commit 9ed4c1bc584f7b1725061d35afeafd1647c414fa Author: Zhenhui <1276357500@qq.com> Date: Fri Mar 6 00:29:28 2026 +0800 项目初始化 diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..8f18cf0 --- /dev/null +++ b/.env-example @@ -0,0 +1,7 @@ +APP_DEBUG = true + +[APP] +DEFAULT_TIMEZONE = Asia/Shanghai + +[LANG] +default_lang = zh-cn diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a8822b5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +* text=auto eol=lf + +# Windows +*.bat text eol=crlf \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6eda196 --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# 通过 Git 部署项目至线上时建议删除的忽略规则 +/vendor +/modules +/public/*.lock +/public/index.html +/public/assets + +# 通过 Git 部署项目至线上时可以考虑删除的忽略规则 +/public/storage/* +composer.lock +pnpm-lock.yaml +package-lock.json +yarn.lock + +# common +/nbproject +/runtime/* +/install +node_modules +dist +dist-ssr +.DS_Store +/.env +Desktop.ini + +# Log files +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +!/web/.vscode + +# Other +*.css.map +*.local +!.gitkeep +.svn \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3d91beb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,986 @@ +### [BuildAdmin 更新日志](https://gitee.com/wonderful-code/buildadmin) + +🔥🔥基于 Vue3.x + ThinkPHP8 + TypeScript + Vite + Pinia + Element Plus 等流行技术栈的后台管理系统,支持常驻内存运行、可视化CRUD代码生成、自带WEB终端、自适应多端、同时提供Web、WebNuxt、Server端、内置全局数据回收站和字段级数据修改保护、自动注册路由、无限子级权限管理等,无需授权即可免费商用,希望能帮助大家实现快速开发。 + +## v2.3.6-Release +### 新增 +- 添加菜单规则时可快速生成下级权限节点(一键同时提交查看、编辑、添加、删除等权限节点) +- 增加公共搜索渲染为时间选择器和时间范围选择器的支持 +- 时间日期类字段的公共搜索可按需渲染为单时间、单日期、时间日期,并支持等于、大小比较、范围查询等多种操作符 +- CRUD增加自定义公共搜索输入组件属性的支持 +- CRUD增加远程下拉字段的公共搜索渲染方式的自定义功能 + +### 重构/优化/修复 +- 优化统计图表样式 +- 完善表格列的 TS 类型定义 +- CRUD设计器中的默认排序字段的设定逻辑优化 +- 优化已安装模块详情弹窗中的按钮样式 +- 优化CRUD设计页面部分输入框的提示文案 +- 优化CRUD字段名称重复/命名规则错误时,提示信息的显示时机 +- 使用新的官网接口地址以避免可能的本地 hosts 配置影响 +- 修复本地自建模块的显示问题 +- 修复CRUD设计器中对字段先改名再删除时提示找不到字段的问题 +- 修复后台窗口大小改变重新布局时,可能丢失状态/自动重新布局的问题 +- 修复在部分手机上后台菜单可能滑不到最底部的问题 +- 修复常驻内存模式下不能连续安装模块的问题 +- 修复访问CRUD云记录时可能提示请登录的问题 + +## v2.3.5-Release +### 新增 +- 在后台模块详情弹窗中显示模块文档的链接 +- 新增设定表格 getData 请求时的筛选条件的方法 + +### 重构/优化/修复 +- 优化表格行按钮的样式细节 +- 优化公共搜索数据的类型定义 +- 优化表格顶部按钮的样式细节 +- 优化模块详情弹窗中模块预览轮播图的样式细节 +- 完善部分方法形参的类型声明 (#52) +- 完善表格管家类内部事件相关细节及类型定义 +- 会员余额和积分管理表格刷新时同时刷新当前会员的账户信息 +- 修改公共搜索显示动画为折叠展开,使得动画更平滑 !195 +- 在设置和获取公共搜索表单数据前确定数据已经初始化 +- 优化公共搜索初始化逻辑、优化 getData 筛选条件设定 +- 修复格式化时间日期字符串时可能异常的问题 !192 +- 修复开发环境中 prettier 命令的参数未严格限制可能导致命令注入的问题 +- 修复第一个表格行按钮是确认按钮时存在视觉偏移的问题 !191 +- 修复弃用自带公共搜索组件后远程下拉仍然会发起初始化请求的问题 !187 +- 自定义 `voku/portable-utf8` 和 `voku/anti-xss` 依赖的仓库 URL 以兼容至 `PHP 8.4` + +## v2.3.4-Beta +### 新增 +- 表格行按钮的扩展属性支持以自定义函数定义 +- 新增表格按钮的 `loading` 属性控制函数 +- 后台安装模块时支持选择安装版本(**授权过期订单可继续安装授权过期之前发布的模块版本**) + +### 重构/优化/修复 +- 优化远程下拉组件的分页器 +- 优化上传组件的图片预览弹窗 +- 可视化CRUD:优化生成的控制器中的 `index` 方法内 `visible` 操作的代码 +- 可视化CRUD:生成的表单组件中无验证规则时不导入 `buildValidatorData` 函数 +- 可视化CRUD:存在富文本编辑器时增加表单 `dialog` 的宽度 +- 余额管理和积分管理内的会员信息加载增加防抖 +- 新注册会员未设密码时无需生成随机密码 +- 优化导入部分自定义组件时的单词大小写问题 +- 优化表格行按钮和其图标的默认样式 +- 替换已废弃的 frameborder 属性 +- 同步暗黑模式下 `--el-border-color` 和 `--ba-border-color` 的 CSS 变量值 +- 修复暗黑模式下控制台页面休息片刻按钮的样式问题 +- 修复会员 id 可能被修改的问题 +- 修复会员余额管理部分字段筛选无效的问题 +- 修复后台管理员的最后登录时间显示错误的问题 +- 修复时间格式化工具函数错误的将 0 改为了当前时间 +- 修复后台附件管理删除确认按钮 title 属性的 TS 类型错误 +- 修复菜单规则管理中 Iframe 的 URL 可能被转义的问题 + +## v2.3.3-Release +### 修复 +- 修复卸载模块的 WebBootstrap 时可能报错的问题(即模块卸载可能报错) +- 修复后台菜单规则管理可能意外要求链接URL字段必填的问题 + +## v2.3.2-Release +### 新增 +- 增加预设表格单元格渲染器内部的组件的任意属性自定义功能 +- 表格公共搜索中的范围输入框的 `placeholder` 支持以数组类型定义不同值 +- 允许模块向 `modules` 目录写入文件,即操作其他模块,而不是局限于系统本身 +- 模块系统增加 `nuxt` 工程的 模块启动引导代码 插入支持 +- 对外导出前后台各种布局下顶栏的高度数据 + +### 重构/优化/修复 +- 模板引用升级为 `vue 3.5` 新增的 `useTemplateRef` +- 缓存后台菜单规则管理中数据行的展开折叠等状态以便更好的对菜单进行管理 +- 为 `baTable.getIndex` 和 `baTable.requestEdit` 方法增加更适宜的别名 +- 使用更易读的方式定义表格管家类的钩子 +- 修复后台标签页的退出全屏按钮不能点击的问题 +- 修复刷新页面后菜单栏滚动条不能自动滚动到激活菜单所在位置的问题 +- 优化模块列表页面样式 +- 优化 `baTableApi` 类细节 +- 优化 `TableColumn` 类型定义 +- 优化 `baTable` 注释和类型定义注释 +- 优化后台菜单规则管理的验证规则和细节 +- 优化右击菜单组件和图标选择器的事件监听 +- 优化生成 `tableRenderer.d.ts` 文件的逻辑和其内容 + +## v2.3.1-Release + +### 安全更新 +- 升级 `axios` 以避免 `CVE-2025-27152` 带来的影响([axios请求可能通过绝对URL遭受SSRF和凭证泄露漏洞](https://www.cve.org/CVERecord?id=CVE-2025-27152)) +- `BuildAdmin` 后台 `系统配置控制器` 内意外的设置了 `查看` 方法为免登录,可能导致 `配置信息泄露`,建议你立即进行更新或手动修复,[本安全更新详细文档](https://doc.buildadmin.com/guide/other/incompatibleUpdate/v231.html)。 + +### 优化 +- 统一和调高系统级 `z-index` 配置值 + +## v2.3.0-Release +### 新增 +- 使用更安全的密码 `hash` 算法 +- 可视化 CRUD:新增可选的历史记录云备份功能,可跨设备使用 CRUD 设计 +- 可视化 CRUD:代码生成完毕后,自动调用 `prettier` 格式化前端代码 +- 增加 `cdn_url_params` 内容分发网络 `URL` 参数配置 !177 +- 点选验证码组件支持自定义 `API` 的 `BaseURL` + +### 重构/优化/修复 +- 更新 `vite` 和 `vue-i18n` +- 优化多个数据表的结构 +- 优化部分状态商店的数据填充方法 +- 跨域 `methods` 和 `headers` 默认允许所有 +- 可视化 CRUD:优化空表和删表重建的提示信息 +- 可视化 CRUD:优化数字系列验证规则的注释和显示标题 +- 可视化 CRUD:修复解析表时 `float` 类型字段不设长度可能报错的问题 +- WEB 终端:为可执行命令增加 `notes` 配置项,可于执行前对命令进行一次注释 +- 为部分输入框添加 `placeholder` 以更好的融入整个表单 +- 修改 `user` 模型中 `group` 关联方法的名称以避免方法名称冲突 +- 修复同一文件多次上传可能重复保存的问题 +- 修复附件表 `name` 字段长度可能不够的问题 +- 修复 `createAxios` 取消重复请求的配置项大小写错误 +- 修复上传组件 `showFileList=false` 时可能报错的问题 +- 修复验证码类传递自定义随机字符串时可能验证失败的问题 +- 其他细节 + +## v2.2.1-Release + +### 重构/优化/修复 +- 添加 `pnpm.onlyBuiltDependencies` 以避免编译时报错 +- 修复微信 `PC` 版的截图无法上传的问题 (#50) +- 修复登录失败重试次数超限,隔天后仅能重试一次的问题 +- 修复后台角色组管理中非超管不显示已禁用分组的问题 (#43) +- 修复添加敏感字段和数据回收规则时可能报错的问题 +- 优化WEB终端交互式命令的检测和中断 +- 优化公共权限类的会员注册方法 +- 优化清理 `XSS` 的方案(不过滤富文本的 `style` 属性同时确保内容 `xss` 安全) +- 优化刷新 `token` 接口的逻辑 +- 优化后台角色组管理 +- 前端响应内容中增加 `API` 调试引导 +- 不再使用新版 `el-pagination` 组件中已经废弃的 `small` 属性 (#49) +- 切换 `switch` 单元格的状态时更新表格原始数据 !172 + +## v2.2.0-Release + +- 本版本包含一些不兼容更新,请在升级时查阅 [v2.2.0不兼容更新文档](https://doc.buildadmin.com/guide/other/incompatibleUpdate/v220.html) + +### 新增 +- 升级前后端依赖(`tp8.1` + `vue3.5` + `element plus2.9` 等) +- 可视化CRUD:生成前检查是否已有同名菜单并提示 +- 可视化CRUD:生成远程下拉时支持可视化的自定义数据源 + +### 重构/优化/修复 +- 优化 `element.scss` 细节 +- 优化 `getDirFiles` 获取文件时支持不限后缀 +- 优化后台菜单唯一标识的生成规则 +- 优化公共搜索对嵌套关联预载入字段的支持 +- 提交表单时不再自动过滤值 `null` 的字段 +- 将权重字段自动赋值的条件由值为 `0` 改为值为 `null` +- 多种输入框对应的数据表字段设计允许 `null` 以提供更好的兼容 +- 全局配置 `value-on-clear` 以避免 `el-select` 等组件清空输入时值为 `undefined` +- 优化时间选择器、远程下拉选择器、城市选择器、颜色选择器 +- 单元格 `tag` 渲染器值为 `null` 和 `undefined` 时不渲染 +- 后台会员、管理员表单禁止浏览器密码的自动填充 +- 公共搜索时过滤 `length` 为 `0` 的数组数据 +- 可视化CRUD:勾选生成为公共模型时,同时将验证器设为公共验证器 +- 可视化CRUD:字段名称重复检查移至修改前而不只是在修改后再统一检查 +- 可视化CRUD:优化字段名称重复时自动重命名的逻辑 +- 可视化CRUD:生成的 `number` 类型输入框绑定值不再需要修饰符 +- 可视化CRUD:优化 `float` 和 `time` 类型字段的值为 `null` 时的处理 +- 可视化CRUD:修复多层级菜单情况下,生成的上级菜单有可能错误的问题 +- 修复以 `ASC` 规则排序时,拖拽排序可能无效的问题 +- 修复 `unixTime` 方法可能报错 `Invalid date` 的问题 +- 修复模糊搜索关联字段时可能报错的问题 +- 修复 `number` 类型输入框无法输入 `0.0` 的问题 +- 修复对 `getArrayKey` 的返回值判断不严格的问题 +- 修复关联表列的 `default` 和 `formatter` 定义无效的问题 +- 修复 `number` 输入框值为 `null` 会自动被转为 `0` 的问题 +- 修复格式化 `Unix` 时间戳时不支持未来时的问题 +- 不再需要 `ext-calendar` +- 其他细节 + +## v2.1.3-Release +### 新增 +- 后台控制器基类增加有序保证属性 +- 存在热更新脏文件时,于后台顶栏显示需要重启 `Vite` 热更新服务的警告按钮 + +### 重构/优化/修复 +- 表格拖拽排序由直接替换改为增量重排法 +- 优化点选验证码组件的渲染与销毁 +- 优化会员中心菜单点击时的处理函数逻辑 +- 优化前台顶栏菜单被点击时无需激活的菜单项的处理 +- 优化终端弹窗样式 +- 优化小屏下的菜单抽屉 +- 优化顶栏子级菜单的激活逻辑 +- 优化系统配置项 `buildadmin.api_url` 的注释 +- 优化 `CRUD` 无意义默认值的清理逻辑 +- 优化 `CRUD` 浮点数类型字段的模型获取器生成 +- 去除开发环境下跨域代理示例 +- 前端的会员中心开关状态默认开启 +- 会员前台菜单的路由路径支持 `query` +- 后台删除操作不再必需为 `Delete` 请求、统一输入变量接受方式 +- 完善 `Request` 类的真实 `IP` 获取支持(可避免 `Nuxt` 工程服务端渲染时获取不到客户端真实 `IP`) +- 修改 `request` 类全局过滤规则的设置时机 +- 修复单元格 `tag` 渲染器值为 `0` 时不渲染的问题 +- 修复控制器代码中未写入自定义的权重字段名称的问题 +- 修复会员的分组无所有权限时上传文件会提示无权限的问题 +- 修复模块安装过程中可能提示网络请求超时的问题 +- 其他细节 + +## v2.1.2-Release +### 新增 +- 增加前台会员登录验证码开关配置项 +- `BaInput` 和 `FormItem` 组件增加插槽支持 +- 可视化CRUD将字段默认值区分为多个类型进行设定 +- 可视化CRUD修改字段的生成类型时,询问是否重置为新类型的预设属性 +- 终端设置窗口内增加修改 `NPM` 和 `Composer` 源的功能 + +### 重构/优化/修复 +- 升级 `think-orm` +- 提高 `node` 版本要求 +- 优化根标签和头像样式 +- 优化通用搜索表单重置逻辑 +- 优化前台会员登录注册接口 +- 优化开发服务环境检测,去除开发服务端口配置功能 +- 优化输入组件类型对应的数据表字段设计方案 +- 后台菜单的路由路径支持 `query` +- `baTable` 的通用搜索初始化相关逻辑解耦 +- 删除 `countup.js` 依赖,使用 `useTransition` 代替 +- 设置通用搜索数据时对时间日期的识别优化 +- 表格列的 `renderFormatter` 替换为 `formatter` +- 单元格渲染器拆分为独立组件并改用易于扩展的方式加载 +- 使用 `v-memo` 指令缓存表格中的按钮组以提高表格性能 +- 会员管理控制器的 `select` 方法过滤敏感字段 +- 附件选择器关闭通过 `query` 自动触发通用搜索的功能 +- 升级 `pinia`、`eslint`、`vue-tsc` 等多个前端依赖 +- 使用 `qrcode.vue` 替代 `vue-qr` 以确保不存在已弃用的子依赖 +- 安装程序增加对 `pdo_mysql` 的检测 +- 修复控制台页面部分图表超出容器的问题 +- 修复上传文件时入库文件路径使用了错误的斜杠造成图片可能无法显示的问题 +- 修复在多数据库场景中远程下拉组件的 `pk` 属性可能错误的问题 +- 修复系统配置中部分输入组件可能报警告的问题 +- 其他细节 + +## v2.1.1-Release +### 新增 +- 上传类重构为多驱动模式,同时云存储模块将为系统安装服务端上传云存储的驱动 + +### 重构/优化/修复 +- 限定`think-orm`版本以修复该依赖新版本带来的问题 +- 修复上传组件的文件上传状态可能错误的问题 +- 修复自定义后台入口后`WEB`终端命令执行失败的问题 +- 修复`v-drag`指令对`el-dialog`使用时会意外抖动的问题 +- 修复会员的权限不是所有时,修改邮箱提示没有权限的问题 +- 修复一处类型定义中的注释书写错误 !163 +- 优化`full_url`函数的参数类型 +- 当表格公共搜索字段渲染为`tag`且操作为`in`时,支持多选 !162 +- 上传组件禁用状态相关优化 +- 调高部分全局通知消息的`zIndex` +- 使用更合理的方案处理`OPTIONS`请求 + +## v2.1.0-Release +### 新增 +- 升级所有前端依赖 +- 增加`Writeable`工具类型,可将只读属性转为可写 +- 增加`vue-tsc`依赖和`typecheck`命令 +- 模块上传安装时对模块版本是否兼容当前系统版本进行检查 + +### 重构/优化/修复 +- 修复`FormItem`组件属性失去了响应性的问题 +- 修复`switch`组件使用了`activeValue`属性时无法工作的问题 +- 修复连续安装模块时终端命令可能执行失败的问题 +- 修复拥有所有权限的分组可能无法默认选中权限节点的问题 +- 基于`Element plus`新版本优化远程下拉组件(分页样式、逻辑等) +- 基于`Element plus`新版本优化文件上传组件(钩子等) +- 基于`Element plus`新版本优化`FormItem`组件 +- 优化`FormItem`的`props.tip`和`props.blockHelp`样式 +- 优化`FormItem`组件的类型定义 +- 合并`FormItem`的`props`本身和`props.attr`,可查阅[此提交](https://gitee.com/wonderful-code/buildadmin/commit/10527ebb760a10b329130e3194a6bbc929a52737) +- 合并`baInput`组件的`props.attr`和`props.data`,可查阅[此提交](https://gitee.com/wonderful-code/buildadmin/commit/10527ebb760a10b329130e3194a6bbc929a52737) +- 优化表格的`props`继承的类型的定义 +- 优化富文本编辑器的默认宽度 +- 优化可视化`CRUD`生成的模型的`onBeforeInsert`方法返回值类型定义 +- 优化可视化`CRUD`生成的`FormItem`组件的属性代码 +- 优化`debounce`的使用,无必要不使用全局`debounce` +- 去除菜单权限规则类的静态变量缓存以更好的兼容常驻内存运行 +- 使用`PSR-12`编码风格规范格式化和检查所有`PHP`代码 +- `Vite`热更新控制的相关功能整理为函数 +- 其他细节 + +## v2.0.10-Release +### 新增 +- 单复选框支持按钮模式 +- 公共搜索增加渲染类名方便单独定位某字段 +- 图片上传达到限制数时隐藏上传框的配置项 +- 增加`AttachmentInsert`事件,开发者或模块可于附件入库后对新的附件做一些额外的操作 + +### 重构/优化/修复 +- 优化文件上传,文件移动操作优先于文件数据入库 +- 优化管理员管理和菜单规则管理的控制器代码 +- 修复选择数据表、选择数据表字段接口非默认数据库返回空数据的问题 +- 修复第一个菜单为 Iframe 时不能自动跳转的 BUG +- 修复由于`Gitee Pages`停止服务造成的文档站无法访问 +- 修复可视化`CRUD`远程下拉选择数据表时不能关键词搜索的问题 +- 修复右击菜单组件的菜单面板可能超出屏幕的问题 + +## v2.0.9-Release +### 新增 +- 增加动态修改后台顶部`Tab`标题的方法 +- 增加关闭掉全部或者指定`Tab`的方法 +- 新增`refs`状态商店,全局提供了:引用(指向)一些对象(组件)的句柄 +- 常驻内存支持,享受比传统框架快上数十倍的性能提升,目前[Workerman模块](https://modules.buildadmin.com/workerman)可提供框架的常驻内存HTTP服务 + +### 重构/优化/修复 +- 优化内置滚动条样式 +- 使用鼠标滚轮快速操作顶栏横向滚动条的支持(单双栏布局模式下) +- 在操作日志中管理登录失败时任然尽可能记录输入的管理员名称 +- 内置开发服务(php think run)总是禁用输出压缩 +- 自定义后台入口时,由禁止后台应用访问改为添加应用映射 +- 优化Token门面类的类型定义、鉴权相关解耦、细节优化 +- 上传文件时对文件名中不利于传输的字符进行过滤 +- 修复WEB终端开始执行命令时可能刷新页面的问题 +- 修复清理缓存操作的日志标题错误的问题 + +## v2.0.8-Beta +### 新增 +- [Workerman模块](https://modules.buildadmin.com/workerman)上线(系统内置的`API`已完成常驻内存运行的兼容) +- 增加一个获取用户鉴权`token`的公共函数 +- WEB终端:对交互式命令进行提示并终止执行 + +### 重构/优化/修复 +- 修复收集异常数据时可能出现循环引用导致难以排查的问题 +- 公共函数`full_url`默认域名不再携带协议,由浏览器自动识别或手动指定 +- 文件上传类兼容常驻内存模式运行 +- 权限和权限规则类兼容常驻内存运行 +- WEB终端:兼容常驻内存运行 +- WEB终端:命令执行完毕后再输出退出码和状态信息 +- 跨域中间件:使用更合适的办法设置跨域响应头 + +## v2.0.7-Release +### 重构/优化/修复 +- 优化前台首页在短屏下的样式 +- 可视化CRUD:多数据库支持兼容历史生成记录 +- 为前台登录页增加滚动条以兼容小屏设备 + +## v2.0.6-Release +### 新增 +- 自定义后台入口支持 +- CRUD、数据回收、敏感数据监控的多数据库支持 + +### 重构/优化/修复 +- 修复编辑时`unique`验证问题 +- 添加`symfony/http-foundation`依赖 +- 修复非超管对于新增的子级菜单规则可能显示异常的问题 +- 修复保存系统配置时可能刷新页面的问题 +- 选择数据表、选择数据源接口增加快速搜索支持 +- 优化`git`对模块文件的忽略规则 +- 更换已经失效的`npm`源 +- 优化后台规则管理细节 +- 安装器优化 + +## v2.0.5-Release +### 新增 +- 更新所有前端依赖`Vite5+ElementPlus2.4` +- 模块更新`composer.json`中的`config`字段实现 + +### 重构/优化/修复 +- 优化前台页脚样式 +- 优化路由动态注册 +- 优化获取第一个菜单的函数 +- 优化通用搜索按钮样式 !142 +- 优化系统配置数据模型 +- 优化可视化`CRUD`设计器的样式 +- 后台会员管理中的会员分组设为必填 +- 默认不再内置`easywechat`依赖,添加`guzzlehttp`依赖(受益于模块可以调整`composer.json`的`config`) +- 系统配置中的快捷配置入口使用路由`name`而不再是路由`path` +- 语言包按需加载映射表中的后台入口路径由字面量改为变量 +- 管理员登录接口返回的路由路径使用的字面量改为变量 +- `eslint`和`prettier`与`ESM`的兼容 +- 修复系统配置变量值为`0`时可能无法回显的问题 +- 修复可视化`CRUD`富文本字段默认值为`null`时表单打不开的问题 +- 修复设置浏览器标题的函数可能失败的问题 +- 修复初次打开前端时页面标题不完整的问题 +- 修复双栏模式子级菜单跳转异常的问题 close #I7ZECR +- 其他细节 + +## v2.0.4-Release +### 新增 +- 增加静态路由目录,自动加载其中所有文件并注册 +- 表格快速搜索关键词可通过类实例访问 +- 模块上传安装时对系统版本、模块互斥和依赖关系进行检测 +- 模块纯净模式安装(移动模块文件到系统而不是复制) +- 模块可以通过上传安装来完成升级 +- 自定义远程下拉初始值操作符号支持 + +### 重构/优化/修复 +- 可视化CRUD:生成的菜单默认开启缓存 +- 可视化CRUD:高级配置中显示的字段信息优化 +- 可视化CRUD:非新建设计时,总是显示表设计变更预览的按钮 +- 可视化CRUD:优化字段临时数据备份机制、优化字段重复检测 +- 终端不再使用单独的控制器 +- 终端优化命令执行日志缓冲区清理逻辑 +- 终端执行`composer`相关命令时,关闭交互询问 +- 表单弹窗在小屏设备上的样式优化 +- 优化创建`zip`的方法 +- 表格数据刷新优化 +- 日志数据入库时的编码兼容性优化 +- 基础静态路由路径使用的字面量改为变量 +- 生成代码的`import`语句整理 +- 去掉管理员登录成功时的通知提醒信息 +- 优化模块上传安装时的提示信息 +- WEB端环境变量加载优化 +- 升级`topthink/think-migration`依赖 +- 去除已经失效的`travis.yml`文件 +- 删除`web`目录内多余的`README.md`文件 +- 修复表格自动识别筛选条件功能中,`query`改变不能触发重新筛选的问题 +- 修复`nuxt工程`新增依赖时没有备份`package.json`的问题 + +## v2.0.3-Release +### 新增 +- 前台菜单支持无限层级嵌套 +- 独立出表格内部组件自动调用的鉴权方法,便于开发者重写 +- 前端公共函数`auth`可以通过传递菜单规则的 name 鉴权 +- 删除 web 端中多余的默认头像文件 +- 会员中心增加可选的 query 指定会员登录成功后自动跳转的URL +- 上传类增加一个`setTopic`方法 + +### 重构/优化/修复 +- 优化控制台菜单规则(增加了查看权限节点) +- 公共函数`get_table_list`默认不再去除表注释中的:后缀`表`字 +- 管理员管理中的分组字样改为角色组 +- 角色组管理增加权限说明的备注 +- 取消前台用户头像必填 +- 重置公共搜索表单时,自动刷新表格 +- 内置的后台功能中默认ID字段搜索时不再使用模糊查询 +- 不再需要清理`css charset`,所以删除多余代码 +- 去除多余的 htmlspecialchars 参数(富文本入库可能被多次转义) +- 修复顶栏菜单在非激活菜单右击关闭全部标签会清空标签页的问题 +- 修复头像保存时可能丢失的问题,优化头像URL出入库逻辑 +- 修复用户默认的头像URL可能被入库的问题 +- 修复上传组件图片拖拽排序在添加时无效的问题 +- 修复文件名为中文时可能上传失败的问题 +- 可视化CRUD:修复生成单选框组件时报错的问题 + +## v2.0.2-Release +### 新增 +- 上传图片组和文件组时支持拖拽排序 +- 增加管理员和会员的登录态保持时间配置项 +- 新增清理`XSS`代码的公共函数 + +### 重构/优化/修复 +- 从服务端限制`WEB终端`仅限超管执行命令 +- 表格公共搜索操作符不再使用不利于传输的符号形式 +- 为`a`标签添加`rel="noopener noreferrer"` +- 优化请求输入变量的默认过滤规则 +- 可视化CRUD:存在富文本组件时,默认对`XSS`代码进行清理 +- 可视化CRUD:远程下拉参数预填弹窗增加滚动条,避免小屏显示异常 +- 可视化CRUD:富文本字段默认值改为`empty string` +- 可视化CRUD:修复`php8.1`下从数据表开始可能报错的问题 +- 修复远程下拉脱焦后会有个多余的请求的问题 +- 修复远程下拉组件`row`事件可能失效的问题 +- 修复会员登录态过期后不会触发重新登录的问题 +- 修复小屏设备中后台最后一个菜单可能显示不全的问题 +- 修复顶栏会员中心菜单的下拉项无法显示的问题 + +## v2.0.1-Release +### 新增 +- 全局提供 mainScrollbarRef 以实现子组件操作滚动条 + +### 重构/优化/修复 +- 前端初始化请求和会员中心初始化请求合并为一个 +- 顶栏菜单在手机端的显示和交互优化 +- 优化会员中心个人资料页面小屏自适应 +- 会员余额和会员积分模型添加悲观锁 +- 删除 user 表中可能造成意外错误的唯一索引 +- 添加页面按钮时,隐藏链接地址的输入框 +- 远程下拉组件内部 select 属性绑定 +- 提交表单时操作方法名首字母小写 +- 修复安装模块时可能报异常的问题 +- 修复 symfony/var-dumper 依赖被锁定为 4.* +- 修复顶栏宽度在侧边栏折叠开启操作后宽度不正确 +- 修复模块安装、卸载等操作时管理员日志中标题为未知的问题 +- 修复管理员登录页不能响应暗黑模式开关的问题 +- 修复后台侧边菜单在小屏设备可能意外被隐藏的问题 +- 修复不能同时存在两个地区选择器的问题 +- 修复 el-table 原有属性失效的问题 +- 可视化CRUD:修复远程下拉多选字段后缀不为 _ids 时会生成重复方法的问题 +- 可视化CRUD:修复 enum 默认值为 0 时报错的问题 +- 可视化CRUD:修复生成的前端代码中对象 key 以数字开头时报错的问题 +- 可视化CRUD:修复编辑关联字段时可能不会更新表字段的问题 +- 可视化CRUD:MySQL text 和 blob 类型不能有默认值 + +## v2.0.0-Release +此版本有一些不兼容更新,建议在更新前参考:[v2.0.0不兼容更新](https://doc.buildadmin.com/guide/other/incompatibleUpdate/v200.html) +### 新增 +- 升级到`tp8.0.0`,升级所有后端依赖 +- 升级到`vue3.3`,升级所有前端依赖 +- 上传文件使用部分文件名作为前缀以便识别 +- 多富文本编辑器共存支持 +- 模糊搜索关键词可以含有百分号 +- 表格,单元格和公共搜索自定义渲染支持`slot`方式 +- 表格头组件增加多个插槽 +- 使用`Phinx`管理项目数据表,增加数据表管理类 +- 增加访问和操作文件系统的类 +- 可视化CRUD,修改设计且数据表内有数据时,不再删表重建,而是根据设计调整表结构 +- 可视化CRUD,单表多次关联支持、远程下拉字段名自动根据表名生成 +- 可视化CRUD,修复生成的远程下拉`pk`属性可能错误的问题 +- 可视化CRUD,实时的字段命名规则检查、字段名称重复检查 +- 可视化CRUD,增加当前不在开发环境提醒 +- 可视化CRUD,选择的表有成功生成的记录则建议从历史记录开始 +- 其他细节 + +### 优化/修复 +- 安装器优化 +- 公共语言翻译`key`全面大写开头 +- 内置`font-awesome` +- `WEB`终端执行日志显示样式优化,且输出支持换行 +- 完善前端端类型定义 +- 部分公共函数归纳为类 +- `array`输入组件可以设置数组项的标题 +- 可视化CRUD,修复远程下拉多选字段的公共搜索失效的问题 +- 云存储初始化时机优化 +- 修改菜单规则默认图标 +- 上传组件默认值为`null`时的处理 +- 修复后台基类 del 方法的数据权限失效的问题 +- 编程式删除系统配置分组时,该分组无配置项再删除 +- 同类函数参数命名统一、字段命名规则统一、参数命名规则统一 +- 默认折叠所有会员菜单规则 +- 优化点选验证码汉字集 +- 优化命令执行失败时的提示信息 +- 去除不必要的 controllerUrls +- `timeFormat`函数归类到公共文件中 +- `menu_rule`表名改为`admin_rule`,因为会员规则表名为`user_rule` +- 修复远程下拉组件在无数据时无提醒的问题 +- 修复热更新后鉴权按钮消失的问题 +- 其他细节 + +## v1.1.7-Release +### 新增 +- 升级点选验证码 +- 增加数据表命名规则的检查 +- 增加模块安装时对`Nuxt`工程的版本检测 + +### 重构/修复 +- 优化将字符串属性列表转为数组的函数 +- 为模块安装请求设置更长的请求超时时间 +- 修改高级配置文字颜色 +- 优化输入组件逻辑 +- `nuxt`模块改用标签进行筛选 +- 系统配置中配置分组不存在时不显示该配置项 +- 修复鼠标在时间选择组件上页面无法滚动的问题 !125 +- 修复下拉面板滚动到视窗外隐藏时可能抛出错误的问题 !124 +- 其他细节 + +## v1.1.6-Release +### 新增 +- 上传组件增加实时上传进度的显示 +- 上传组件增加强制上传到本地的`props` +- 上传文件方法增加`AxiosRequestConfig`参数 +- 增加`remoteSelects`类型输入框 +- 后台会员规则管理增加顶栏会员菜单下拉项类型 + +### 修复/重构 +- 后台关闭`tab`,自动返回到上一个`tab`时不带`query`的问题 +- 后台菜单规则管理中的组件路径字段自动转换分隔符号 +- 会员规则无组件的不注册到菜单项 +- 优化系统配置逻辑 +- 优化可视化CRUD拖拽交互 +- 因`web-nuxt`提高`API`节流阈值 +- 限定`pinia`版本号 +- 前台初始化请求防抖 +- 优化会员中心跳转到第一个菜单的逻辑 +- 前台动态路由注册时可根据`name`从已注册路由分析父级路由 +- 不再额外向`element`安装器传递`i18n`选项 +- 优化前台动态菜单样式 +- 前台`link`类型的顶栏菜单打开失败的问题 +- 添加表单默认值赋值改为深拷贝 +- 优化鉴权指令 +- 优化输入组件用于代码提示的类型定义 +- 修复上传组件`onChange`重复触发的问题 +- 修复查询条件 [NOT] NULL 报错的问题 +- 修复系统配置的远程下拉多选值不能正常选中的问题 + +## v1.1.5-Release +### 新增 +- 全面使用`文字点选验证码`,配合服务端二次验证,为您的重要资源保驾护航 +- 增加前台普通路由、顶部导航栏、权限节点的可视化管理 +- 远程下拉增加获取被选中项完整对象的事件 +- `可视化CRUD`常用字段增加`雪花ID`类型 +- `可视化CRUD`生成公共模型代码的支持 +- `可视化CRUD`增加快速设定代码相对位置的功能 +- `可视化CRUD`根据字段字典自动重新生成字段的数据类型,避免部分情况需要手动拼接的问题 +- `可视化CRUD`的字段设计数据导出以便开发者使用 +- `baTableApi`当操作不存在时,创建自定义操作 +- 增加创建表单项数据的组件 +- 前端增加身份证号验证器 +- 增加快速搜索前置插槽 +- 增加将字符串属性列表转为数组的公共函数 +- 增加通过`Git`部署项目至线上时的忽略规则建议 +- 增加备用的`font-awesome CDN`和完善注释 + +### 修复/重构 +- 更新所有前端依赖 +- 优化类型定义 +- 不再加载`lang/pages`中的语言包 +- 优化系统配置保存时的代码逻辑 +- 从数据表开始时不读取表前缀错误的数据表 +- 远程下拉菜单超出视窗时自动隐藏 +- 修复会员分组管理回车保存会刷新页面的问题 +- 菜单折叠后菜单图标垂直对齐 +- 公共搜索查询操作符 FIND_IN_SET 支持传递数组 +- 将渲染为 tags 的字段的默认搜索操作符设定为 FIND_IN_SET +- 禁止管理员添加拥有自己全部权限的分组 +- 上传函数请求超时时间修改为无限制避免超时 +- CRUD下拉框默认的字段数据类型由`tinyint`改为`enum` +- 修复单元格自定义渲染时,改变 data 不重新渲染的问题 +- 修复`Tree类`子节点组装方法漏传`pk`的问题 +- 修复CRUD远程下拉的公共搜索无数据的问题 +- 修复CRUD从数据表加载的字段默认值为null,却被识别为空字符串的问题 +- 修复CRUD数字输入组件的默认值无法通过验证的问题 +- 修复CRUD中支持多选的表单元素名称错误的问题 +- 修复CRUD富文本字段生成失败的问题 +- 修复会员管理建立模型验证后密码验证不通过的问题 +- 修复php8.1+mysql8.0兼容性问题 +- 修复一处 php8.2 不兼容 +- 修复公共搜索未传递值时任然拼装查询条件的问题 +- 其他细节优化 + +## v1.1.4-Release +### 新增 +- 模块安装增加依赖模块检测 +- 新的依赖管理类 +- 通过模块市场为`WebNuxt工程`安装模块的实现 + +## v1.1.3-Release +### 新增 +- `WebNuxt`工程发布,可通过模块市场安装,亦可直接访问[代码仓库](https://gitee.com/wonderful-code/build-admin-nuxt) +- 增加可选的管理员和会员单点登录功能 +- 增加直接登录会员账号的方法 +- 新增双栏布局效果,顶部栏加左侧栏同时存在 +- 确保无需登录的接口不会抛出token过期的异常 +- 增加表格普通侧边按钮类型 +- 增加根据当前路由路径快捷获取语言翻译的函数 +- 后台模块管理增加我的模块按钮 + +### 修复/重构 +- 远程下拉增加信息提示框 +- 文件上传失败则不在上传列表显示 +- 调整composer依赖 +- 可视化CRUD生成的语言包代码按需加载实现 +- 优化数据行拖拽排序的逻辑 +- 优化数据行侧边按钮的类型定义 +- 模块封面图片开启懒加载 +- 修改管理员日志的data字段类型为longtext +- 修复添加窗口中存在富文本字段时可能无法关闭的问题 +- 修复管理员无权限时跳回首页或被注销的问题 +- 修复表格行侧边 confirmButton 按钮 disabled 无效的问题 +- 修复从历史记录开始时,远程下拉参数无法选择的问题 +- 修复菜单规则只添加为菜单时无法打开的问题 +- 修复从数据表开始时字段分析可能出错的问题 +- 修复行侧边按钮 disabledTip 属性无效的问题 +- 修复前台iframe菜单无法打开的问题 +- 修复远程下拉监听值为`null、undefined`时报错的问题 +- 修复后台因为管理员模型登录时间获取器导致登录判断报错问题 + +## v1.1.2-Release +- 此版本有一些不兼容更新,建议在更新前参考:[v1.1.2不兼容更新](https://doc.buildadmin.com/guide/other/incompatibleUpdate/v112.html) +- 页面组件与页面语言包全部**按需加载**,大幅减少首屏加载大小 +- 更新系统前端的所有可更新依赖到最新稳定版本 +- 可视化CRUD增加字段名称检查 +- 禁止管理员自己删除自己 +- `isAdminApp`方法支持传递`path`进行判断 +- `mixins`代码移入到新建的组件内统一管理 +- 修复可视化CRUD生成的代码中`-1`没有加引号的问题 +- 修复后台单栏布局只有一个菜单时菜单不显示的问题 +- 修复模块发布新版本不能减少旧版本模块文件的问题 +- 修复模块更新脚本因未加载而不能执行的问题 + +## v1.1.1-Release +### 新增 +- 增加前台会员中心埋点(配合模块为会员中心增加功能) +- 编程式添加会员菜单规则支持 + +### 优化 +- 默认关闭监听SQL +- 服务端返回302时自动删除前端的用户token +- 系统配置保存时只效验和提交当前页的表单数据 +- 优化用户信息显示 +- 优化`getTableFieldList`接口 +- 统一接口响应数据`key`的命名规范 +- 默认不再允许上传pdf格式的文件 +- `Token::check`方法增加过期不抛出异常时的逻辑 + +### 修复/重构 +- 修复模块下载安装时解压目录名可能错误的问题 +- 文件后缀名大写时无法上传的问题 +- 修复关联表名带下划线生成的代码出错 +- 修复上传组件一处类型检查错误 +- 会员中心的用户名默认不再禁止修改 +- 会员修改绑定信息时账户验证通过的token在使用后立即删除 +- 自定义排序字段,模型onAfterInsert方法生成错误 +- 修复生成三级以上的菜单规则时,无法为非超管分配权限的问题 +- 修复可视化CRUD删除字段时可能出现报错的问题 +- 去除多余的会员菜单规则 +- 模块市场中与官网相关的URL修改 +- 修复预览图片宽高较大时超出对话框的问题 +- 修复公共搜索只有一个输入框时会触发表单的默认行为的问题 +- 其他细节 + +## v1.1.0-Release +### 新增 +- **可视化CRUD新增多种快捷组件,并修复已知问题** +- 模块可以在启用和禁用脚本内备份配置数据和运行文件 +- 模块支持向main.ts和App.vue添加代码 +- 新增会员修改绑定信息(手机号、邮箱)支持 +- 文件图片上传增加隐藏附件选择器的选项 +- 远程下拉组件增加 label 格式化函数的属性 +- 增加颜色选择器(baInput) +- 完善上传组件的onChange等事件 + +### 优化 +- 优化后台登录页面自适应效果 +- 优化首页和会员中心菜单样式 +- 优化终端警告信息显示效果 +- 优化账户名验证错误时的提示消息 +- 详情弹窗可以点击弹窗外部进行关闭 +- 禁止管理员向自己的角色组添加其他管理员 +- 其他细节... + +### 修复/重构 +- 修复后台编辑弹窗缩放后显示异常的问题 +- 修复在第一个tab右击菜单中关闭全部tab时报错的问题 #10 +- 修复远程下拉可能出现已聚焦却无选项的问题 +- 修复添加管理员和会员时可能出现表单验证信息的问题 +- 修复模块管理中会员登录态过期后不自动注销的问题 +- 修复系统配置中的数字输入框编辑可能无法保存的问题 +- 修复系统配置中的上传组件从附件选择器中选择附件保存无效的问题 +- 增加vue-qr依赖 +- 增加忽略Desktop.ini + +## v1.0.9-Release +- **新增可视化CRUD** +- 去除原命令行CRUD代码生成功能(已打包为模块,按需下载) +- 添加表单颜色选择器和表格内的颜色渲染方式 +- 侧边按钮增加 disabled 判定方法和按钮额外属性 +- 增加获取数据表字段的辅助函数 +- 增加获取一个目录所有文件的辅助函数 +- 后台手机端自适应优化 +- 公共搜索输入框可一键清空 +- 远程下拉默认值优化 +- 优化版本类/扩展类 +- 优化树状表格 +- `DELETE`请求的body改为query以兼容域名CNAME解析 +- 在main.ts导入display.css而不是分散导入 +- 修复url带参跳转时表格可能报错的问题 +- 修复只添加为路由的菜单规则不能刷新的问题 +- 修复验权时可能出现错误的问题 +- 修复Linux下删除空文件夹可能失败的问题 +- 修复自建模块处于未安装状态时显示异常的问题 +- 会员切换登录注册时重置表单项 !70 +- 会员切换到注册表单时清理用户名 +- 管理员分组的上级分组禁止为自身 +- 模块管理用户信息弹窗数据更新 +- 本地模块更新日志显示异常的问题 + +## v1.0.8-Release +- **ThinkPHP发布6.1.0版本安全更新**,修正了序列化漏洞问题和优化多语言判断机制。 +- 去除`lodash`依赖改用`lodash-es`(后者同时为`Element plus`的依赖,与框架更契合,包体积更小) +- 修复跨域代理示例的规则错误的问题 +- 合并打包css文件、增加分包配置示例 +- 完善工具函数注释、优化相关代码 +- 模块详情展示效果优化 + +PS: 框架对`TP`的版本限定为`^6.0.0`,针对tp本次安全更新,git包的开发者可以直接`composer update`,若没更新到`v6.1.0`请更换`composer`源,`BuildAdmin`发新版本主要是为了更新完整包和资源包。 + +## v1.0.7-Release +- 富文本编辑器通过模块市场按需安装(框架不再内置),以方便选择不同的编辑器 +- **增加附件资源库** +- 前台用户登录状态检测优化 +- 事件监听优化 +- 附件管理优化 +- 单元格图片预览弹窗可以通过点击遮罩层关闭 +- 自定义表格页码相关优化 +- 搜索事件Data的类型定义优化 +- 修复特殊类型文件上传时可能被限制的问题 +- 优化敏感数据修改监听的逻辑 +- 修复 typescript-eslint 依赖可能安装失败的问题 +- 优化表单密码验证规则 + +## v1.0.6-Release +- Table组件增加多个插槽位,提供`el-table-column`支持 +- 增加WEB端文件上传扩展文件 +- 增加文件上传前的类型与大小检查 +- 增加文件单位转字节的函数 +- 增加系统配置管理类 +- 新增以编程的方式删除依赖的功能 +- 新增模块安装时对互斥模块的检测 +- 增加多个系统预置事件定义 +- 增加发送邮件接口 +- 增加发送短信接口 +- 增加手机验证账户验证方式 +- 增加responseType json 以外类型的处理逻辑 +- 增加编程式添加系统配置中的快捷配置入口的方法 +- 增加清理浏览器缓存的快捷按钮 +- 升级element-plus版本到2.2.17 +- 优化表单验证 +- 优化表格的单元格渲染 +- 优化多处类型定义 +- 优化后端数据库字段读取函数 +- 优化数据管理中数据表和控制器列表的加载 +- 优化控制台页面暗黑模式下的文字颜色 +- 优化模块安装时对互斥模块的检测 +- 优化上传组件 +- WEB端语言包文件无限层级读取 +- 表格顶部菜单按钮图标在暗黑模式时的样式优化 +- 禁用模块时可以选择保留一些由模块添加的依赖项 +- 模块状态不为已安装时不定义AppInit事件 +- 资源完整路径处理时加入上传文件cdnurl的判断 +- Table组件不再使用事件巴士监听相关事件 +- 删除文件不存在的附件记录前额外检查是否是本地存储 +- 附件管理删除记录时同时删除文件,并提供友好提示信息 +- 去除Table组件的action事件 +- 去除TableHeader组件的action事件 +- 输入组件帮助信息显示效果优化 +- 修复对表格第三次排序时(取消排序时)失效的问题 +- 修复部分后台功能缓存设置不生效的问题 +- 修复多选远程下拉选择一次面板就收缩和无右侧箭头的问题 +- 修复菜单规则管理中图标选择器在窗口关闭后残留的问题 +- 修复图标选择器选取图标后无法再次显示的问题 +- 模块安装器去除等待热更新步骤 +- 修复预设表格页码或单页加载数量无效的问题 +- 修复主动添加的系统配置不能删除的问题、格式化代码 +- 修复模块依赖冲突检测可能异常的问题 +- 修复安装云存储模块后,本地上传模块时被上传到云存储的问题 +- 修复用户修改头像时顶栏和侧栏的头像图片可能404的问题 +- 修复模块依赖冲突时,模块的启用脚本不执行的问题 +- 修复模块安装完成后异常的显示了`模块已安装`的错误弹窗 +- 管理员管理和会员管理接口中的敏感信息剔除 +- 移除多余的IE相关判断 +- 其他优化... + +## v1.0.5-Release Preview +- 新增**模块市场**,一键安装某个功能、单页或是纯前端技术栈的学习案例项目等等,随时随地为系统添砖加瓦,系统能够自动维护`package.json`和`composer.json`并通过内置终端自动完成模块所需依赖的安装。 +- 新增前后台**暗黑模式**支持 +- 安装器不再要求数据表前缀必填、安装验证逻辑优化 +- 终端原`popen`实现改为`proc_open` +- 重新实现图片文件上传组件 +- 单元格渲染为 tags 时支持effect、size等属性 +- url的点击事件增加当前行数据的参数 +- 为管理员管理功能开启数据限制 +- 后台Iframe相关多个细节完善 +- 生成代码文件中的缩进改为空格而不是tab +- 访问后端接口时,不再必须通过index.php入口文件 +- 放行所有options请求 +- 修复顶部菜单columnDisplay和comSearch同时不存在时,仍然会残留一个div边框的问题 +- 修复菜单规则管理中无法直接开关规则的问题 +- 修复单选远程下拉清理输入框值后无法再读取全部远程数据的问题 +- 修复axios封装在showCodeMessage=false时请求无后续处理的问题 +- 修复表字段名称为length时CRUD生成语言包报错 +- 修复删除菜单规则时未同时删除子级菜单的问题 +- 修复角色组的资料可被越权修改的问题 +- 修复触发到API请求节流时报错为跨域的问题 +- 修复表格顶部下拉菜单复选框和按钮组占位 +- 修复已上传文件丢失后,无法再次上传的问题 +- 修复有默认值的情况多文件同时上传时文件列表错乱的问题 +- 修复隐藏菜单情况刷新页面再展开菜单会导致顶部tab异常的问题 +- 修复后台菜单折叠状态刷新后丢失的问题 +- 修复管理员昵称过长时首次登录昵称被换行的问题 +- 修复登录页面管理员头像位置自适应异常的问题 +- 其他细节... + +## v1.0.3-Release +- 完善英文语言包 +- 公共搜索增加远程下拉组件支持 +- 增加数据权限控制支持:不同管理员只可以查看有权数据行 的权限控制功能 +- 自动识别表主键并添加到生成的模型属性 +- 后台终端按钮只为超级管理员显示 +- 关联表指定远程select下拉字段 +- 增加表格快速搜索字段是否存在的检测 +- 增加以type为后缀的enum等类型字段可被生成为单选框 +- 站点系统配置缓存支持 +- 增加会员中心开关 +- 会员注册时通过API获取可用的验证方式、会员注册验证邮件实现 +- 完善会员规则管理 +- 表格公共搜索->对开关组件状态的搜索优化 +- 公共搜索显示状态可通过baTable实例控制 +- 验证码类支持到php8.1 +- 去除file_list后缀的字段生成为多文件上传组件(与下拉组件后缀存在冲突) +- 优化角色组权限分配 +- 优化默认管理员分组拥有的权限节点 +- 数据回收和敏感数据规则中,不再使用带前缀的表全名 +- 安装器`npm install`失败自动重试一次 +- 安装器增加检测当前端口是否是8000 +- 安装器完成页面增加重新安装按钮 (只清理缓存,不会删除install.lock) +- 修复敏感数据规则管理中删除敏感字段时的显示异常问题 +- 修复表格时间字段未提供值时显示为当前时间的问题 +- 修复管理员个人资料表单中的签名无法被重置的问题 +- 修复后端默认应用不存在的问题 +- 修复字段类型为char(1)时,生成的单选框无字典数据 +- 修复数据表主键不为ID时编辑表单无法保存、表格无法排序等问题 +- 修复顶栏标签全屏时,取消全屏的按钮会遮挡表格顶部操作按钮的问题 +- 修复前后台路由规则名称重复时可能导致错误跳转问题 +- 修复手机号验证正则无法识别部分已知号码的问题 +- 修复系统配置中的禁止访问IP和时区配置项无效的问题 +- 修复系统配置中富文本编辑器层级过高和无法编辑的问题 +- 修复系统配置中时间和城市类型的输入组件无法正常录入值的问题 +- 修复数据表没有注释时不生成菜单规则的问题 +- 修复表格右侧无buttons,且要初始化排序时会报错的问题 +- 修复单元格渲染为tag时值为0等无法显示的问题 +- 修复images字段名称后缀不能生成为图片上传组件的问题 +- 修复管理员日志权限控制不完善的问题 +- 修复管理员可通过后台使自己部分权限丢失的问题 +- 修复管理员分组被禁用后还可以被远程select选择的问题 +- 修复删除管理员时没有同时删除管理员的分组数据的问题 +- 修复远程下拉搜索结果无法选中的问题、同时优化下拉选项面板显示逻辑 +- 修复菜单规则和会员分组被禁用后在远程select中依然可以选择的问题 +- 修复重复安装系统时.env-example被多次写入数据库资料的问题 +- 修复数据安全监听中表不存在时的日志记录异常 +- 其他细节优化 + +## v1.0.2-Release +- **增加前台会员中心** +- 安装器增加NPM源自动设置选项 +- CRUD:增加tinyint(1)类型的字段在符合条件下自动生成为单选框 +- baInput:单选/复选框/下拉框默认值传递数字支持 +- baInput:优化年份选择器 +- baInput:文件上传组件增加预览响应 +- web端布局(layouts)内的目录结构调整 +- 增加跨域代理配置示例,提供给有需要的小伙伴(感谢@ttdms) +- 增加邮件发送类、增加phpMailer依赖、系统邮件配置增加测试邮件发送功能 +- 后台右侧菜单增加清理缓存按钮 +- 会员余额以分为单位保存到数据库,并在模型层做转换处理 +- 附件管理增加上传会员字段 +- 优化富文本编辑器滚动条样式、通用弹窗表单增加圆角 +- 更新wangeditor依赖版本到5.1.1 +- 增加会员资料的状态商店、优化后台登录状态判断逻辑 +- 表格开关类型字段的公共搜索使用下拉框渲染 +- 重构了站点首页 +- 更新font-awesome的资源地址到国内CDN +- 去除build:online命令,使用build代替 +- 修复关闭管理员登录验证码后,登录任然报错验证码不存在的问题 +- 修复富文本编辑器上传文件时提示未配置上传URL的问题 +- 修复表格中的tag和url在无值时任然显示组件的问题 +- 修复侧边菜单栏的非激活菜单项的图标颜色不符合直觉的问题 +- 修复CRUD生成的代码在添加数据时权重字段无效的问题 +- 修复部分日志记录没有标题的问题 +- 修复已在后台或会员中心再跳转到模块首页时会卡在loading页面的问题 +- 修复系统配置编辑时提示变量名不能为空的问题 +- 修复后台表格右侧字段下拉没有高度限定的问题、修复一处样式缺失 +- 修复管理员注销时偶尔需要权限的问题 +- 修复默认的数据回收规则配置不完整的问题 +- 修复表格顶部的批量操作按钮在未选择数据时依然可点击的问题 +- 修复表格内tag在公共搜索中被渲染为下拉框的问题 +- 修复管理员登录页面编译后可能存在的username未定义报错 + +## v1.0.1-Release +- 增加终端配置功能 +- 终端增加是否运行于安装服务下的检测 +- FormItem增加额外的块级输入提示选项 +- 优化管理分组权限节点选择时的样式 +- 语言包整理 +- 额外暴露i18n实例,实现在非setup中使用语言翻译 +- 新增站点配置状态store +- 修复bug、完善README + +## v1.0.0-beta +**公共测试版本** +- 内置WEB终端 +- 一键CRUD +- Pinia +- 可视化配置+动态加载路由 +- 细粒度权限控制 +- 数据修改保护、数据全局回收 +- ... \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..21c42cd --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 妙码生花 + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d5d6c89 --- /dev/null +++ b/README.md @@ -0,0 +1,148 @@ +
+
+ +

BuildAdmin

+

使用流行技术栈快速创建商业级后台管理系统

+ 官网 | + 演示 | + 社区 | + 文档 | + 加群 | + 视频介绍 | + Gitee仓库 | + GitHub仓库 +
+
+

+ + vue + + + vue + + + element plus + + + typescript + + + vite + + + vite + + + license + +

+ +
+
+ +
+
+ +### 介绍 +🌈 基于 Vue3.x + ThinkPHP8 + TypeScript + Vite + Pinia + Element Plus 等流行技术栈的后台管理系统,支持常驻内存运行、可视化 CRUD 代码生成、自带 WEB 终端、自适应多端、同时提供 Web、WebNuxt、Server 端,内置全局数据回收站和字段级数据修改保护、自动注册路由、无限子级权限管理等,无需授权即可免费商用,希望能帮助大家实现快速开发。 + +✨ 关于 `Star` 的小小期待 ✨ + +~~文档和演示站的「入场券」是点亮 Star~~ 哈哈哈,开个玩笑,实际上**您不需要任何「门槛」即可访问源码、文档和演示站**,在您丝滑体验文档与强大功能的同时,我们有个温暖的请求 —— 若 `BuildAdmin` 让您眼前一亮,请为我们点亮一颗 `Star`,这将是一次开发者间最浪漫的「确认过眼神」,亦可助我们向本应「自由开放」的开源界证明:优秀的项目我会发自内心的点亮 Star ~(而不是像某些同类产品哪样,将 Star 作为文档或演示站的「强制交换」条件) + +### 主要特性 +**🚀 CRUD 代码生成:** +图形化拖拽生成后台增删改查代码,自动创建数据表;大气且实用的表格,多达 24 种表单组件支持,行拖拽排序,受权限控制的编辑和删除等等,并支持关联表,可为您节省大量开发时间。 + +**💥 内置 WEB 终端:** +在后台管理系统领域,我们率先将终端深度集成于系统的 `本地开发环境` 中,它能实现很多理想中的功能,比如:虽然是基于 Vue3 的系统,但在安装时并不需要手动的执行 `npm install` 命令;CRUD 代码生成完毕后,自动调用 `prettier` 格式化代码等。本终端设计上能够调用环境变量中的任意命令,天花板极高,后续将为您提供更多方便、快捷的服务。 + +**👍 流行且稳定的技术栈:** +除了基于 `ThinkPHP8` 前后端分离架构外,我们的 `Vue3` 使用了 `setup、useTemplateRef` 等,状态管理使用 `Pinia`,并使用了 `TypeScript、Vite` 等可以为你的知识面添砖加瓦的技术栈。使用流行技术栈自然代表本框架兼容相关(Vue3+TP8+PHP8.x)生态,生态系统内数不清的库、包、组件,能够使您的开发事半功倍。 + +**🎨 模块市场:** +一键安装数据导入导出、短信发送、支付、云存储、富文本编辑器,甚至 CMS、商城、社区、纯前端技术栈的学习案例项目等,随时随地为系统添砖加瓦,系统能够自动维护 `package.json` 和 `composer.json` 并通过内置终端自动完成模块所需依赖的安装。 + +**🔀 前后端分离:** +项目的 `web` 文件夹内包含: `干净`(不含后端代码)、`完整`(所有前端代码文件均在此内)的前端代码文件,代码和部署均可前后分离,对前端开发者友好,作为纯前端开发者,您可以将 BAdmin 当做学习与资源的社群,本系统可为您准备好案例和模板等所需要的环境,而您只需专注于学习或工作,不需要会任何后端代码!(邀您:[和我们一起](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=paVQA1dlpsVNHTla-ZAts6e4pPK4va9R&authKey=Eto0dq9DOuYldJPl6URFAXXHlG2AFQtPUBxNHEByEiuSg9OraxMniXIaWFt46OKi&noverify=0&group_code=1039646575) ) + +**⚡️ 常驻内存:** +系统内置的功能均可常驻内存运行,享受比传统框架快上数十倍的性能提升!目前 [Workerman 模块](https://modules.buildadmin.com/workerman) 可提供框架的常驻内存 `HTTP` 服务,同时该模块还提供了开箱即用的 `WebSocket` 服务。 + +**🚚 按需加载:** +前端的页面组件和语言包均是在使用到它们时,才从网络异步加载,服务端则是基于 `TP8` 和 `PSR` 规范,天生拥有真正的按需加载能力,所以,您无需考虑 `我并不需要多语言、我并不需要某个后台功能` 这类的问题,不需要不使用或隐藏即可。 + +**🌴 数据回收与反悔:** +内置全局数据回收站,并且提供字段级数据修改记录和修改对比,随时回滚和还原,安全且无感。 + +**✨ 高颜值:** +提供三种布局模式,其中默认布局使用无边框设计风格,它并没有强行填满屏幕的每一个缝然后使用边框线进行分隔,所有的功能版块,都像是悬浮在屏幕上的,同时又将屏幕空间及其合理的利用了。 + +**🔐 权限验证:** +可视化的管理权限,然后根据权限动态的注册路由、菜单、页面、按钮(权限节点)、支持无限父子级权限分组、前后端搭配鉴权,自由分派页面和按钮权限。 + +**📝 未来可期:** +我们正在持续维护系统,并着手开发更多基础设施模块,按需一键安装,甚至提供开箱即用的各行业完整应用。 + +**🧱 一举多得:** +后台自适应 PC、平板、手机 等多种场景的支持,轻松应对各种需求。 + +**💖 其他杂项:** +角色组/管理员/管理员日志、 会员/会员组/会员余额、积分日志、系统配置/控制台/附件管理/个人资料管理等等、更多特性等你探索... + +### 安装使用 +💫 我们提供了完善的文档,对于熟悉 `ThinkPHP` 和 `Vue` 的用户,请使用大佬版:[快速上手](https://doc.buildadmin.com/guide/install/start.html) ,对于新人朋友,我们额外准备了各个操作系统的从零开始套餐:[Windows从零到一](https://doc.buildadmin.com/guide/install/windows.html) | [Linux从零到一](https://doc.buildadmin.com/guide/install/linux-bt.html) | [MacBook安装引导](https://doc.buildadmin.com/guide/install/macBook.html) + +### 联系我们 +- [演示站](https://demo.buildadmin.com) 账户:`admin`,密码:`123456`(演示站数据无法修改,请下载源码安装体验全部功能) +- [问答社区:ask.buildadmin.com](https://ask.buildadmin.com) +- [官方网站:uni.buildadmin.com](https://uni.buildadmin.com) +- [文档:doc.buildadmin.com](https://doc.buildadmin.com/) +- 加群:[687903819(>960/1000)](https://jq.qq.com/?_wv=1027&k=QwtXa14c)、[751852082(>1990/2000)](https://jq.qq.com/?_wv=1027&k=c8a7iSk8)、[1039646575](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=paVQA1dlpsVNHTla-ZAts6e4pPK4va9R&authKey=Eto0dq9DOuYldJPl6URFAXXHlG2AFQtPUBxNHEByEiuSg9OraxMniXIaWFt46OKi&noverify=0&group_code=1039646575) +- [Gitee仓库](https://gitee.com/wonderful-code/buildadmin)、[GitHub仓库](https://github.com/build-admin/BuildAdmin) +- [备用文档:docs.buildadmin.net](https://docs.buildadmin.net/) +- [官方邮箱 hi@buildadmin.com](mailto:hi@buildadmin.com) + +### 项目预览 +| | | +|---------------------|---------------------| +|![登录](https://doc.buildadmin.com/images/readme/login.gif)|![控制台](https://doc.buildadmin.com/images/readme/dashboard.png)| +|![布局配置](https://doc.buildadmin.com/images/readme/layout.png)|![表格](https://doc.buildadmin.com/images/readme/admin.png)| +|![表单](https://doc.buildadmin.com/images/readme/user.png)|![系统配置](https://doc.buildadmin.com/images/readme/config.png)| +|![数据回收规则](https://doc.buildadmin.com/images/readme/data-recycle.png)|![数据回收日志](https://doc.buildadmin.com/images/readme/data-recycle-log.png)| +|![敏感数据](https://doc.buildadmin.com/images/readme/sensitive-data.png)|![菜单](https://doc.buildadmin.com/images/readme/menu.png)| +|![单栏布局](https://doc.buildadmin.com/images/readme/layout-3.png)|![经典布局](https://doc.buildadmin.com/images/readme/layout-2.png)| + +### 特别鸣谢 +💕 感谢巨人提供肩膀,排名不分先后 +- [Thinkphp](http://www.thinkphp.cn/) +- [FastAdmin](https://gitee.com/karson/fastadmin) +- [Vue](https://github.com/vuejs/core) +- [vue-next-admin](https://gitee.com/lyt-top/vue-next-admin) +- [Element Plus](https://github.com/element-plus/element-plus) +- [TypeScript](https://github.com/microsoft/TypeScript) +- [vue-router](https://github.com/vuejs/vue-router-next) +- [vite](https://github.com/vitejs/vite) +- [Pinia](https://github.com/vuejs/pinia) +- [Axios](https://github.com/axios/axios) +- [nprogress](https://github.com/rstacruz/nprogress) +- [screenfull](https://github.com/sindresorhus/screenfull.js) +- [mitt](https://github.com/developit/mitt) +- [sass](https://github.com/sass/sass) +- [echarts](https://github.com/apache/echarts) +- [vueuse](https://github.com/vueuse/vueuse) +- [lodash](https://github.com/lodash/lodash) +- [eslint](https://github.com/eslint/eslint) +- [prettier](https://github.com/prettier/prettier) +- [Sortable](https://github.com/SortableJS/Sortable) +- [v-code-diff](https://github.com/Shimada666/v-code-diff) +- [clicaptcha](https://github.com/hooray/clicaptcha) +- [phinx](https://github.com/cakephp/phinx) +- [jetbrains](https://www.jetbrains.com/) + +### 版权信息 +🔐 BuildAdmin 遵循 `Apache2.0` 开源协议发布,提供无需授权的免费使用。\ +本项目包含的第三方源码和二进制文件之版权信息另行标注。 + +### 支持项目 +💕 无需捐赠,如果觉得项目不错,或者已经在使用了,希望你可以去 [Github](https://github.com/build-admin/BuildAdmin) 或者 [Gitee](https://gitee.com/wonderful-code/buildadmin) 帮我们点个 ⭐ Star,这将是对我们极大的鼓励与支持。 diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/app/AppService.php b/app/AppService.php new file mode 100644 index 0000000..6346741 --- /dev/null +++ b/app/AppService.php @@ -0,0 +1,22 @@ +request = $this->app->request; + $this->request->controllerPath = str_replace('.', '/', $this->request->controller(true)); + + // 控制器初始化 + $this->initialize(); + } + + /** + * 初始化 + * @access protected + */ + protected function initialize(): void + { + } + + /** + * 验证数据 + * @access protected + * @param array $data 数据 + * @param array|string $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array|string|true + * @throws ValidateException + */ + protected function validate(array $data, array|string $validate, array $message = [], bool $batch = false): bool|array|string + { + if (is_array($validate)) { + $v = new Validate(); + $v->rule($validate); + } else { + if (strpos($validate, '.')) { + // 支持场景 + [$validate, $scene] = explode('.', $validate); + } + $class = str_contains($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); + $v = new $class(); + if (!empty($scene)) { + $v->scene($scene); + } + } + + $v->message($message); + + // 是否批量验证 + if ($batch || $this->batchValidate) { + $v->batch(); + } + + return $v->failException()->check($data); + } + +} diff --git a/app/ExceptionHandle.php b/app/ExceptionHandle.php new file mode 100644 index 0000000..b7f87e5 --- /dev/null +++ b/app/ExceptionHandle.php @@ -0,0 +1,119 @@ +app->isDebug()) { + // 调试模式,获取详细的错误信息 + $traces = []; + $nextException = $exception; + do { + $traces[] = [ + 'name' => $nextException::class, + 'file' => $nextException->getFile(), + 'line' => $nextException->getLine(), + 'code' => $this->getCode($nextException), + 'message' => $this->getMessage($nextException), + 'trace' => $nextException->getTrace(), + 'source' => $this->getSourceCode($nextException), + ]; + } while ($nextException = $nextException->getPrevious()); + + // 循环引用检测并直接置空 traces(比起循环引用导致的报错,置空后开发者能得到更多真实的错误信息) + if ($this->app->request->isJson()) { + $json = json_encode($traces, JSON_UNESCAPED_UNICODE); + if (false === $json && in_array(json_last_error(), [JSON_ERROR_DEPTH, JSON_ERROR_RECURSION])) { + $traces = []; + } + } + + $data = [ + 'code' => $this->getCode($exception), + 'message' => $this->getMessage($exception), + 'traces' => $traces, + 'datas' => $this->getExtendData($exception), + 'tables' => [ + 'GET Data' => $this->app->request->get(), + 'POST Data' => $this->app->request->post(), + 'Files' => $this->app->request->file(), + 'Cookies' => $this->app->request->cookie(), + 'Session' => $this->app->exists('session') ? $this->app->session->all() : [], + 'Server/Request Data' => $this->app->request->server(), + ], + ]; + } else { + // 部署模式仅显示 Code 和 Message + $data = [ + 'code' => $this->getCode($exception), + 'message' => $this->getMessage($exception), + ]; + + if (!$this->app->config->get('app.show_error_msg')) { + // 不显示详细错误信息 + $data['message'] = $this->app->config->get('app.error_message'); + } + } + + return $data; + } +} diff --git a/app/Request.php b/app/Request.php new file mode 100644 index 0000000..0c6df49 --- /dev/null +++ b/app/Request.php @@ -0,0 +1,26 @@ +proxyServerIp = $proxyServerIp; + } + } +} diff --git a/app/admin/common.php b/app/admin/common.php new file mode 100644 index 0000000..35b57da --- /dev/null +++ b/app/admin/common.php @@ -0,0 +1,34 @@ + config('buildadmin.api_url'), + 'timeout' => 30, + 'connect_timeout' => 30, + 'verify' => false, + 'http_errors' => false, + 'headers' => [ + 'X-REQUESTED-WITH' => 'XMLHttpRequest', + 'Referer' => dirname(request()->root(true)), + 'User-Agent' => 'BuildAdminClient', + ] + ]); + } +} \ No newline at end of file diff --git a/app/admin/controller/Ajax.php b/app/admin/controller/Ajax.php new file mode 100644 index 0000000..b344736 --- /dev/null +++ b/app/admin/controller/Ajax.php @@ -0,0 +1,217 @@ +setTitle(__('upload')); + $file = $this->request->file('file'); + $driver = $this->request->param('driver', 'local'); + $topic = $this->request->param('topic', 'default'); + try { + $upload = new Upload(); + $attachment = $upload + ->setFile($file) + ->setDriver($driver) + ->setTopic($topic) + ->upload(null, $this->auth->id); + unset($attachment['create_time'], $attachment['quote']); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + $this->success(__('File uploaded successfully'), [ + 'file' => $attachment ?? [] + ]); + } + + /** + * 获取省市区数据 + * @throws Throwable + */ + public function area(): void + { + $this->success('', get_area()); + } + + public function buildSuffixSvg(): Response + { + $suffix = $this->request->param('suffix', 'file'); + $background = $this->request->param('background'); + $content = build_suffix_svg((string)$suffix, (string)$background); + return response($content, 200, ['Content-Length' => strlen($content)])->contentType('image/svg+xml'); + } + + /** + * 获取已脱敏的数据库连接配置列表 + * @throws Throwable + */ + public function getDatabaseConnectionList(): void + { + $quickSearch = $this->request->get("quickSearch/s", ''); + $connections = config('database.connections'); + $desensitization = []; + foreach ($connections as $key => $connection) { + $connection = TableManager::getConnectionConfig($key); + $desensitization[] = [ + 'type' => $connection['type'], + 'database' => substr_replace($connection['database'], '****', 1, strlen($connection['database']) > 4 ? 2 : 1), + 'key' => $key, + ]; + } + + if ($quickSearch) { + $desensitization = array_filter($desensitization, function ($item) use ($quickSearch) { + return preg_match("/$quickSearch/i", $item['key']); + }); + $desensitization = array_values($desensitization); + } + + $this->success('', [ + 'list' => $desensitization, + ]); + } + + /** + * 获取表主键字段 + * @param ?string $table + * @param ?string $connection + * @throws Throwable + */ + public function getTablePk(?string $table = null, ?string $connection = null): void + { + if (!$table) { + $this->error(__('Parameter error')); + } + + $table = TableManager::tableName($table, true, $connection); + if (!TableManager::phinxAdapter(false, $connection)->hasTable($table)) { + $this->error(__('Data table does not exist')); + } + + $tablePk = Db::connect(TableManager::getConnection($connection)) + ->table($table) + ->getPk(); + $this->success('', ['pk' => $tablePk]); + } + + /** + * 获取数据表列表 + * @throws Throwable + */ + public function getTableList(): void + { + $quickSearch = $this->request->get("quickSearch/s", ''); + $connection = $this->request->request('connection');// 数据库连接配置标识 + $samePrefix = $this->request->request('samePrefix/b', true);// 是否仅返回项目数据表(前缀同项目一致的) + $excludeTable = $this->request->request('excludeTable/a', []);// 要排除的数据表数组(表名无需带前缀) + + $outTables = []; + $dbConfig = TableManager::getConnectionConfig($connection); + $tables = TableManager::getTableList($connection); + + if ($quickSearch) { + $tables = array_filter($tables, function ($comment) use ($quickSearch) { + return preg_match("/$quickSearch/i", $comment); + }); + } + + $pattern = '/^' . $dbConfig['prefix'] . '/i'; + foreach ($tables as $table => $comment) { + if ($samePrefix && !preg_match($pattern, $table)) continue; + + $table = preg_replace($pattern, '', $table); + if (!in_array($table, $excludeTable)) { + $outTables[] = [ + 'table' => $table, + 'comment' => $comment, + 'connection' => $connection, + 'prefix' => $dbConfig['prefix'], + ]; + } + } + + $this->success('', [ + 'list' => $outTables, + ]); + } + + /** + * 获取数据表字段列表 + * @throws Throwable + */ + public function getTableFieldList(): void + { + $table = $this->request->param('table'); + $clean = $this->request->param('clean', true); + $connection = $this->request->request('connection'); + if (!$table) { + $this->error(__('Parameter error')); + } + + $connection = TableManager::getConnection($connection); + $tablePk = Db::connect($connection)->name($table)->getPk(); + $this->success('', [ + 'pk' => $tablePk, + 'fieldList' => TableManager::getTableColumns($table, $clean, $connection), + ]); + } + + public function changeTerminalConfig(): void + { + AdminLog::instance()->setTitle(__('Change terminal config')); + if (Terminal::changeTerminalConfig()) { + $this->success(); + } else { + $this->error(__('Failed to modify the terminal configuration. Please modify the configuration file manually:%s', ['/config/buildadmin.php'])); + } + } + + public function clearCache(): void + { + AdminLog::instance()->setTitle(__('Clear cache')); + $type = $this->request->post('type'); + if ($type == 'tp' || $type == 'all') { + Cache::clear(); + } else { + $this->error(__('Parameter error')); + } + Event::trigger('cacheClearAfter', $this->app); + $this->success(__('Cache cleaned~')); + } + + /** + * 终端 + * @throws Throwable + */ + public function terminal(): void + { + (new Terminal())->exec(); + } +} \ No newline at end of file diff --git a/app/admin/controller/Dashboard.php b/app/admin/controller/Dashboard.php new file mode 100644 index 0000000..1aed884 --- /dev/null +++ b/app/admin/controller/Dashboard.php @@ -0,0 +1,20 @@ +success('', [ + 'remark' => get_route_remark() + ]); + } +} \ No newline at end of file diff --git a/app/admin/controller/Index.php b/app/admin/controller/Index.php new file mode 100644 index 0000000..45427eb --- /dev/null +++ b/app/admin/controller/Index.php @@ -0,0 +1,133 @@ +auth->getInfo(); + $adminInfo['super'] = $this->auth->isSuperAdmin(); + unset($adminInfo['token'], $adminInfo['refresh_token']); + + $menus = $this->auth->getMenus(); + if (!$menus) { + $this->error(__('No background menu, please contact super administrator!')); + } + $this->success('', [ + 'adminInfo' => $adminInfo, + 'menus' => $menus, + 'siteConfig' => [ + 'siteName' => get_sys_config('site_name'), + 'version' => get_sys_config('version'), + 'apiUrl' => Config::get('buildadmin.api_url'), + 'upload' => keys_to_camel_case(get_upload_config(), ['max_size', 'save_name', 'allowed_suffixes', 'allowed_mime_types']), + 'cdnUrl' => full_url(), + 'cdnUrlParams' => Config::get('buildadmin.cdn_url_params'), + ], + 'terminal' => [ + 'phpDevelopmentServer' => str_contains($_SERVER['SERVER_SOFTWARE'], 'Development Server'), + 'npmPackageManager' => Config::get('terminal.npm_package_manager'), + ] + ]); + } + + /** + * 管理员登录 + * @return void + * @throws Throwable + */ + public function login(): void + { + // 检查登录态 + if ($this->auth->isLogin()) { + $this->success(__('You have already logged in. There is no need to log in again~'), [ + 'type' => $this->auth::LOGGED_IN + ], $this->auth::LOGIN_RESPONSE_CODE); + } + + $captchaSwitch = Config::get('buildadmin.admin_login_captcha'); + + // 检查提交 + if ($this->request->isPost()) { + $username = $this->request->post('username'); + $password = $this->request->post('password'); + $keep = $this->request->post('keep'); + + $rule = [ + 'username|' . __('Username') => 'require|length:3,30', + 'password|' . __('Password') => 'require|regex:^(?!.*[&<>"\'\n\r]).{6,32}$', + ]; + $data = [ + 'username' => $username, + 'password' => $password, + ]; + if ($captchaSwitch) { + $rule['captchaId|' . __('CaptchaId')] = 'require'; + $rule['captchaInfo|' . __('Captcha')] = 'require'; + + $data['captchaId'] = $this->request->post('captchaId'); + $data['captchaInfo'] = $this->request->post('captchaInfo'); + } + $validate = Validate::rule($rule); + if (!$validate->check($data)) { + $this->error($validate->getError()); + } + + if ($captchaSwitch) { + $captchaObj = new ClickCaptcha(); + if (!$captchaObj->check($data['captchaId'], $data['captchaInfo'])) { + $this->error(__('Captcha error')); + } + } + + AdminLog::instance()->setTitle(__('Login')); + + $res = $this->auth->login($username, $password, (bool)$keep); + if ($res === true) { + $this->success(__('Login succeeded!'), [ + 'userInfo' => $this->auth->getInfo() + ]); + } else { + $msg = $this->auth->getError(); + $msg = $msg ?: __('Incorrect user name or password!'); + $this->error($msg); + } + } + + $this->success('', [ + 'captcha' => $captchaSwitch + ]); + } + + /** + * 管理员注销 + * @return void + */ + public function logout(): void + { + if ($this->request->isPost()) { + $refreshToken = $this->request->post('refreshToken', ''); + if ($refreshToken) Token::delete((string)$refreshToken); + $this->auth->logout(); + $this->success(); + } + } +} diff --git a/app/admin/controller/Module.php b/app/admin/controller/Module.php new file mode 100644 index 0000000..0f3a30e --- /dev/null +++ b/app/admin/controller/Module.php @@ -0,0 +1,137 @@ +success('', [ + 'installed' => Server::installedList(root_path() . 'modules' . DIRECTORY_SEPARATOR), + 'sysVersion' => Config::get('buildadmin.version'), + 'nuxtVersion' => Server::getNuxtVersion(), + ]); + } + + public function state(): void + { + $uid = $this->request->get("uid/s", ''); + if (!$uid) { + $this->error(__('Parameter error')); + } + $this->success('', [ + 'state' => Manage::instance($uid)->getInstallState() + ]); + } + + public function install(): void + { + AdminLog::instance()->setTitle(__('Install module')); + $uid = $this->request->param("uid/s", ''); + $update = $this->request->param("update/b", false); + if (!$uid) { + $this->error(__('Parameter error')); + } + $res = []; + try { + $res = Manage::instance($uid)->install($update); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success('', [ + 'data' => $res, + ]); + } + + public function dependentInstallComplete(): void + { + $uid = $this->request->get("uid/s", ''); + if (!$uid) { + $this->error(__('Parameter error')); + } + try { + Manage::instance($uid)->dependentInstallComplete('all'); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success(); + } + + public function changeState(): void + { + AdminLog::instance()->setTitle(__('Change module state')); + $uid = $this->request->post("uid/s", ''); + $state = $this->request->post("state/b", false); + if (!$uid) { + $this->error(__('Parameter error')); + } + $info = []; + try { + $info = Manage::instance($uid)->changeState($state); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success('', [ + 'info' => $info, + ]); + } + + public function uninstall(): void + { + AdminLog::instance()->setTitle(__('Unload module')); + $uid = $this->request->get("uid/s", ''); + if (!$uid) { + $this->error(__('Parameter error')); + } + try { + Manage::instance($uid)->uninstall(); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success(); + } + + public function upload(): void + { + AdminLog::instance()->setTitle(__('Upload install module')); + $file = $this->request->get("file/s", ''); + $token = $this->request->get("token/s", ''); + if (!$file) $this->error(__('Parameter error')); + if (!$token) $this->error(__('Please login to the official website account first')); + + $info = []; + try { + $info = Manage::instance()->upload($token, $file); + } catch (Exception $e) { + $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (Throwable $e) { + $this->error(__($e->getMessage())); + } + $this->success('', [ + 'info' => $info + ]); + } +} \ No newline at end of file diff --git a/app/admin/controller/auth/Admin.php b/app/admin/controller/auth/Admin.php new file mode 100644 index 0000000..c8f820e --- /dev/null +++ b/app/admin/controller/auth/Admin.php @@ -0,0 +1,261 @@ +model = new AdminModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withoutField('login_failure,password,salt') + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + if ($this->modelValidate) { + try { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + $validate = new $validate(); + $validate->scene('add')->check($data); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + } + + $passwd = $data['password']; // 密码将被排除不直接入库 + $data = $this->excludeFields($data); + $result = false; + if ($data['group_arr']) $this->checkGroupAuth($data['group_arr']); + $this->model->startTrans(); + try { + $result = $this->model->save($data); + if ($data['group_arr']) { + $groupAccess = []; + foreach ($data['group_arr'] as $datum) { + $groupAccess[] = [ + 'uid' => $this->model->id, + 'group_id' => $datum, + ]; + } + Db::name('admin_group_access')->insertAll($groupAccess); + } + $this->model->commit(); + + if (!empty($passwd)) { + $this->model->resetPassword($this->model->id, $passwd); + } + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + $this->error(__('You have no permission')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + if ($this->modelValidate) { + try { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + $validate = new $validate(); + $validate->scene('edit')->check($data); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + } + + if ($this->auth->id == $data['id'] && $data['status'] == 'disable') { + $this->error(__('Please use another administrator account to disable the current account!')); + } + + if (!empty($data['password'])) { + $this->model->resetPassword($row->id, $data['password']); + } + + $groupAccess = []; + if ($data['group_arr']) { + $checkGroups = []; + foreach ($data['group_arr'] as $datum) { + if (!in_array($datum, $row->group_arr)) { + $checkGroups[] = $datum; + } + $groupAccess[] = [ + 'uid' => $id, + 'group_id' => $datum, + ]; + } + $this->checkGroupAuth($checkGroups); + } + + Db::name('admin_group_access') + ->where('uid', $id) + ->delete(); + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + $result = $row->save($data); + if ($groupAccess) Db::name('admin_group_access')->insertAll($groupAccess); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + unset($row['salt'], $row['login_failure']); + $row['password'] = ''; + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $this->request->param('ids/a', []); + $where[] = [$this->model->getPk(), 'in', $ids]; + $data = $this->model->where($where)->select(); + + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $v) { + if ($v->id != $this->auth->id) { + $count += $v->delete(); + Db::name('admin_group_access') + ->where('uid', $v['id']) + ->delete(); + } + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($count) { + $this->success(__('Deleted successfully')); + } else { + $this->error(__('No rows were deleted')); + } + } + + /** + * 检查分组权限 + * @throws Throwable + */ + private function checkGroupAuth(array $groups): void + { + if ($this->auth->isSuperAdmin()) { + return; + } + $authGroups = $this->auth->getAllAuthGroups('allAuthAndOthers'); + foreach ($groups as $group) { + if (!in_array($group, $authGroups)) { + $this->error(__('You have no permission to add an administrator to this group!')); + } + } + } +} \ No newline at end of file diff --git a/app/admin/controller/auth/AdminLog.php b/app/admin/controller/auth/AdminLog.php new file mode 100644 index 0000000..ace3b80 --- /dev/null +++ b/app/admin/controller/auth/AdminLog.php @@ -0,0 +1,54 @@ +model = new AdminLogModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + if (!$this->auth->isSuperAdmin()) { + $where[] = ['admin_id', '=', $this->auth->id]; + } + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } +} \ No newline at end of file diff --git a/app/admin/controller/auth/Group.php b/app/admin/controller/auth/Group.php new file mode 100644 index 0000000..9b3f4ab --- /dev/null +++ b/app/admin/controller/auth/Group.php @@ -0,0 +1,379 @@ +model = new AdminGroup(); + $this->tree = Tree::instance(); + + $isTree = $this->request->param('isTree', true); + $this->initValue = $this->request->get("initValue/a", []); + $this->initValue = array_filter($this->initValue); + $this->keyword = $this->request->request("quickSearch", ''); + + // 有初始化值时不组装树状(初始化出来的值更好看) + $this->assembleTree = $isTree && !$this->initValue; + + $this->adminGroups = Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'); + } + + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + $this->success('', [ + 'list' => $this->getGroups(), + 'group' => $this->adminGroups, + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data = $this->handleRules($data); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + $validate->scene('add')->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $this->checkAuth($id); + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $adminGroup = Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'); + if (in_array($data['id'], $adminGroup)) { + $this->error(__('You cannot modify your own management group!')); + } + + $data = $this->excludeFields($data); + $data = $this->handleRules($data); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + $validate->scene('edit')->check($data); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + // 读取所有pid,全部从节点数组移除,父级选择状态由子级决定 + $pidArr = AdminRule::field('pid') + ->distinct() + ->where('id', 'in', $row->rules) + ->select() + ->toArray(); + $rules = $row->rules ? explode(',', $row->rules) : []; + foreach ($pidArr as $item) { + $ruKey = array_search($item['pid'], $rules); + if ($ruKey !== false) { + unset($rules[$ruKey]); + } + } + $row->rules = array_values($rules); + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $ids = $this->request->param('ids/a', []); + $data = $this->model->where($this->model->getPk(), 'in', $ids)->select(); + foreach ($data as $v) { + $this->checkAuth($v->id); + } + $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id'); + foreach ($subData as $key => $subDatum) { + if (!in_array($key, $ids)) { + $this->error(__('Please delete the child element first, or use batch deletion')); + } + } + + $adminGroup = Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'); + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $v) { + if (!in_array($v['id'], $adminGroup)) { + $count += $v->delete(); + } + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($count) { + $this->success(__('Deleted successfully')); + } else { + $this->error(__('No rows were deleted')); + } + } + + /** + * 远程下拉 + * @return void + * @throws Throwable + */ + public function select(): void + { + $data = $this->getGroups([['status', '=', 1]]); + + if ($this->assembleTree) { + $data = $this->tree->assembleTree($this->tree->getTreeArray($data)); + } + $this->success('', [ + 'options' => $data + ]); + } + + /** + * 权限节点入库前处理 + * @throws Throwable + */ + private function handleRules(array &$data): array + { + if (!empty($data['rules']) && is_array($data['rules'])) { + $superAdmin = true; + $checkedRules = []; + $allRuleIds = AdminRule::column('id'); + + // 遍历检查权限ID是否存在(以免传递了可预测的未来权限ID号) + foreach ($data['rules'] as $postRuleId) { + if (in_array($postRuleId, $allRuleIds)) { + $checkedRules[] = $postRuleId; + } + } + + // 正在建立超管级分组? + foreach ($allRuleIds as $ruleId) { + if (!in_array($ruleId, $checkedRules)) { + $superAdmin = false; + } + } + + if ($superAdmin && $this->auth->isSuperAdmin()) { + // 允许超管建立超管级分组 + $data['rules'] = '*'; + } else { + // 当前管理员所拥有的权限节点 + $ownedRuleIds = $this->auth->getRuleIds(); + + // 禁止添加`拥有自己全部权限`的分组 + if (!array_diff($ownedRuleIds, $checkedRules)) { + $this->error(__('Role group has all your rights, please contact the upper administrator to add or do not need to add!')); + } + + // 检查分组权限是否超出了自己的权限(超管的 $ownedRuleIds 为 ['*'],不便且可以不做此项检查) + if (array_diff($checkedRules, $ownedRuleIds) && !$this->auth->isSuperAdmin()) { + $this->error(__('The group permission node exceeds the range that can be allocated')); + } + + $data['rules'] = implode(',', $checkedRules); + } + } else { + unset($data['rules']); + } + return $data; + } + + /** + * 获取分组 + * @param array $where + * @return array + * @throws Throwable + */ + private function getGroups(array $where = []): array + { + $pk = $this->model->getPk(); + $initKey = $this->request->get("initKey/s", $pk); + + // 下拉选择时只获取:拥有所有权限并且有额外权限的分组 + $absoluteAuth = $this->request->get('absoluteAuth/b', false); + + if ($this->keyword) { + $keyword = explode(' ', $this->keyword); + foreach ($keyword as $item) { + $where[] = [$this->quickSearchField, 'like', '%' . $item . '%']; + } + } + + if ($this->initValue) { + $where[] = [$initKey, 'in', $this->initValue]; + } + + if (!$this->auth->isSuperAdmin()) { + $authGroups = $this->auth->getAllAuthGroups($this->authMethod, $where); + if (!$absoluteAuth) $authGroups = array_merge($this->adminGroups, $authGroups); + $where[] = ['id', 'in', $authGroups]; + } + $data = $this->model->where($where)->select()->toArray(); + + // 获取第一个权限的名称供列表显示-s + foreach ($data as &$datum) { + if ($datum['rules']) { + if ($datum['rules'] == '*') { + $datum['rules'] = __('Super administrator'); + } else { + $rules = explode(',', $datum['rules']); + if ($rules) { + $rulesFirstTitle = AdminRule::where('id', $rules[0])->value('title'); + $datum['rules'] = count($rules) == 1 ? $rulesFirstTitle : $rulesFirstTitle . '等 ' . count($rules) . ' 项'; + } + } + } else { + $datum['rules'] = __('No permission'); + } + } + // 获取第一个权限的名称供列表显示-e + + // 如果要求树状,此处先组装好 children + return $this->assembleTree ? $this->tree->assembleChild($data) : $data; + } + + /** + * 检查权限 + * @param $groupId + * @return void + * @throws Throwable + */ + private function checkAuth($groupId): void + { + $authGroups = $this->auth->getAllAuthGroups($this->authMethod, []); + if (!$this->auth->isSuperAdmin() && !in_array($groupId, $authGroups)) { + $this->error(__($this->authMethod == 'allAuth' ? 'You need to have all permissions of this group to operate this group~' : 'You need to have all the permissions of the group and have additional permissions before you can operate the group~')); + } + } + +} \ No newline at end of file diff --git a/app/admin/controller/auth/Rule.php b/app/admin/controller/auth/Rule.php new file mode 100644 index 0000000..0279170 --- /dev/null +++ b/app/admin/controller/auth/Rule.php @@ -0,0 +1,307 @@ + 'desc']; + + protected string|array $quickSearchField = 'title'; + + /** + * @var object + * @phpstan-var AdminRule + */ + protected object $model; + + /** + * @var Tree + */ + protected Tree $tree; + + /** + * 远程select初始化传值 + * @var array + */ + protected array $initValue; + + /** + * 搜索关键词 + * @var string + */ + protected string $keyword; + + /** + * 是否组装Tree + * @var bool + */ + protected bool $assembleTree; + + /** + * 开启模型验证 + * @var bool + */ + protected bool $modelValidate = false; + + public function initialize(): void + { + parent::initialize(); + + // 防止 URL 中的特殊符号被默认的 filter 函数转义 + $this->request->filter('clean_xss'); + + $this->model = new AdminRule(); + $this->tree = Tree::instance(); + $isTree = $this->request->param('isTree', true); + $this->initValue = $this->request->get('initValue/a', []); + $this->initValue = array_filter($this->initValue); + $this->keyword = $this->request->request('quickSearch', ''); + $this->assembleTree = $isTree && !$this->initValue; // 有初始化值时不组装树状(初始化出来的值更好看) + } + + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + $this->success('', [ + 'list' => $this->getMenus(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $data[$this->dataLimitField] = $this->auth->id; + } + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + + // 检查有那些分组可以拥有新增菜单的权限 + if (!empty($data['pid'])) { + $this->autoAssignPermission($this->model->id, $data['pid']); + } + + // 创建子级权限节点 + if ($data['type'] == 'menu' && !empty($data['buttons'])) { + $newButtons = []; + foreach ($data['buttons'] as $button) { + foreach (Helper::$menuChildren as $menuChild) { + if ($menuChild['name'] == '/' . $button) { + $menuChild['name'] = $data['name'] . $menuChild['name']; + $newButtons[] = $menuChild; + } + } + } + if (!empty($newButtons)) { + // 创建子级权限节点 + Menu::create($newButtons, $this->model->id, 'ignore'); + + // 检查有那些分组可以拥有新增的子级权限 + $children = AdminRule::where('pid', $this->model->id)->select(); + foreach ($children as $child) { + $this->autoAssignPermission($child['id'], $this->model->id); + } + } + } + + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $id = $this->request->param($this->model->getPk()); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + $this->error(__('You have no permission')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + if (isset($data['pid']) && $data['pid'] > 0) { + // 满足意图并消除副作用 + $parent = $this->model->where('id', $data['pid'])->find(); + if ($parent['pid'] == $row['id']) { + $parent->pid = 0; + $parent->save(); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $ids = $this->request->param('ids/a', []); + + // 子级元素检查 + $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id'); + foreach ($subData as $key => $subDatum) { + if (!in_array($key, $ids)) { + $this->error(__('Please delete the child element first, or use batch deletion')); + } + } + + parent::del(); + } + + /** + * 重写select方法 + * @throws Throwable + */ + public function select(): void + { + $data = $this->getMenus([['type', 'in', ['menu_dir', 'menu']], ['status', '=', 1]]); + + if ($this->assembleTree) { + $data = $this->tree->assembleTree($this->tree->getTreeArray($data, 'title')); + } + $this->success('', [ + 'options' => $data + ]); + } + + /** + * 获取菜单列表 + * @throws Throwable + */ + protected function getMenus($where = []): array + { + $pk = $this->model->getPk(); + $initKey = $this->request->get("initKey/s", $pk); + + $ids = $this->auth->getRuleIds(); + + // 如果没有 * 则只获取用户拥有的规则 + if (!in_array('*', $ids)) { + $where[] = ['id', 'in', $ids]; + } + + if ($this->keyword) { + $keyword = explode(' ', $this->keyword); + foreach ($keyword as $item) { + $where[] = [$this->quickSearchField, 'like', '%' . $item . '%']; + } + } + + if ($this->initValue) { + $where[] = [$initKey, 'in', $this->initValue]; + } + + // 读取用户组所有权限规则 + $rules = $this->model + ->where($where) + ->order($this->queryOrderBuilder()) + ->select() + ->toArray(); + + // 如果要求树状,此处先组装好 children + return $this->assembleTree ? $this->tree->assembleChild($rules) : $rules; + } + + /** + * 检查所有非超管的分组是否应该拥有某个权限 + */ + private function autoAssignPermission(int $id, int $pid): void + { + $groups = AdminGroup::where('rules', '<>', '*')->select(); + foreach ($groups as $group) { + $rules = explode(',', $group->rules); + if (in_array($pid, $rules) && !in_array($id, $rules)) { + $rules[] = $id; + $group->rules = implode(',', $rules); + $group->save(); + } + } + } +} \ No newline at end of file diff --git a/app/admin/controller/crud/Crud.php b/app/admin/controller/crud/Crud.php new file mode 100644 index 0000000..02a148f --- /dev/null +++ b/app/admin/controller/crud/Crud.php @@ -0,0 +1,1002 @@ +request->post('type', ''); + $table = $this->request->post('table', []); + $fields = $this->request->post('fields', [], 'clean_xss,htmlspecialchars_decode_improve'); + + if (!$table || !$fields || !isset($table['name']) || !$table['name']) { + $this->error(__('Parameter error')); + } + + try { + // 记录日志 + $crudLogId = Helper::recordCrudStatus([ + 'table' => $table, + 'fields' => $fields, + 'status' => 'start', + ]); + + // 表名称 + $tableName = TableManager::tableName($table['name'], false, $table['databaseConnection']); + + if ($type == 'create' || $table['rebuild'] == 'Yes') { + // 数据表存在则删除 + TableManager::phinxTable($tableName, [], true, $table['databaseConnection'])->drop()->save(); + } + + // 处理表设计 + [$tablePk] = Helper::handleTableDesign($table, $fields); + + // 表注释 + $tableComment = mb_substr($table['comment'], -1) == '表' ? mb_substr($table['comment'], 0, -1) . '管理' : $table['comment']; + + // 生成文件信息解析 + $modelFile = Helper::parseNameData($table['isCommonModel'] ? 'common' : 'admin', $tableName, 'model', $table['modelFile']); + $validateFile = Helper::parseNameData($table['isCommonModel'] ? 'common' : 'admin', $tableName, 'validate', $table['validateFile']); + $controllerFile = Helper::parseNameData('admin', $tableName, 'controller', $table['controllerFile']); + $webViewsDir = Helper::parseWebDirNameData($tableName, 'views', $table['webViewsDir']); + $webLangDir = Helper::parseWebDirNameData($tableName, 'lang', $table['webViewsDir']); + + // 语言翻译前缀 + $this->webTranslate = implode('.', $webLangDir['lang']) . '.'; + + // 快速搜索字段 + if (!in_array($tablePk, $table['quickSearchField'])) { + $table['quickSearchField'][] = $tablePk; + } + $quickSearchFieldZhCnTitle = []; + + // 模型数据 + $this->modelData['append'] = []; + $this->modelData['methods'] = []; + $this->modelData['fieldType'] = []; + $this->modelData['createTime'] = ''; + $this->modelData['updateTime'] = ''; + $this->modelData['beforeInsertMixins'] = []; + $this->modelData['beforeInsert'] = ''; + $this->modelData['afterInsert'] = ''; + $this->modelData['connection'] = $table['databaseConnection']; + $this->modelData['name'] = $tableName; + $this->modelData['className'] = $modelFile['lastName']; + $this->modelData['namespace'] = $modelFile['namespace']; + $this->modelData['relationMethodList'] = []; + + // 控制器数据 + $this->controllerData['use'] = []; + $this->controllerData['attr'] = []; + $this->controllerData['methods'] = []; + $this->controllerData['filterRule'] = ''; + $this->controllerData['className'] = $controllerFile['lastName']; + $this->controllerData['namespace'] = $controllerFile['namespace']; + $this->controllerData['tableComment'] = $tableComment; + $this->controllerData['modelName'] = $modelFile['lastName']; + $this->controllerData['modelNamespace'] = $modelFile['namespace']; + + // index.vue数据 + $this->indexVueData['enableDragSort'] = false; + $this->indexVueData['defaultItems'] = []; + $this->indexVueData['tableColumn'] = [ + [ + 'type' => 'selection', + 'align' => 'center', + 'operator' => 'false', + ], + ]; + $this->indexVueData['dblClickNotEditColumn'] = ['undefined']; + $this->indexVueData['optButtons'] = ['edit', 'delete']; + $this->indexVueData['defaultOrder'] = ''; + + // form.vue数据 + $this->formVueData['bigDialog'] = false; + $this->formVueData['formFields'] = []; + $this->formVueData['formValidatorRules'] = []; + $this->formVueData['imports'] = []; + + // 语言包数据 + $this->langTsData = [ + 'en' => [], + 'zh-cn' => [], + ]; + + // 简化的字段数据 + $fieldsMap = []; + + foreach ($fields as $key => $field) { + + $fieldsMap[$field['name']] = $field['designType']; + + // 分析字段 + Helper::analyseField($field); + + Helper::getDictData($this->langTsData['en'], $field, 'en'); + Helper::getDictData($this->langTsData['zh-cn'], $field, 'zh-cn'); + + // 快速搜索字段 + if (in_array($field['name'], $table['quickSearchField'])) { + $quickSearchFieldZhCnTitle[] = $this->langTsData['zh-cn'][$field['name']] ?? $field['name']; + } + + // 不允许双击编辑的字段 + if ($field['designType'] == 'switch') { + $this->indexVueData['dblClickNotEditColumn'][] = $field['name']; + } + + // 列字典数据 + $columnDict = $this->getColumnDict($field); + + // 表单项 + if (in_array($field['name'], $table['formFields'])) { + $this->formVueData['formFields'][] = $this->getFormField($field, $columnDict, $table['databaseConnection']); + } + + // 表格列 + if (in_array($field['name'], $table['columnFields'])) { + $this->indexVueData['tableColumn'][] = $this->getTableColumn($field, $columnDict); + } + + // 关联表数据解析 + if (in_array($field['designType'], ['remoteSelect', 'remoteSelects'])) { + $this->parseJoinData($field, $table); + } + + // 模型方法 + $this->parseModelMethods($field, $this->modelData); + + // 控制器/模型等文件的一些杂项属性解析 + $this->parseSundryData($field, $table); + + if (!in_array($field['name'], $table['formFields'])) { + $this->controllerData['attr']['preExcludeFields'][] = $field['name']; + } + } + + // 快速搜索提示 + $this->langTsData['en']['quick Search Fields'] = implode(',', $table['quickSearchField']); + $this->langTsData['zh-cn']['quick Search Fields'] = implode('、', $quickSearchFieldZhCnTitle); + $this->controllerData['attr']['quickSearchField'] = $table['quickSearchField']; + + // 开启字段排序 + $weighKey = array_search('weigh', $fieldsMap); + if ($weighKey !== false) { + $this->indexVueData['enableDragSort'] = true; + $this->modelData['afterInsert'] = Helper::assembleStub('mixins/model/afterInsert', [ + 'field' => $weighKey + ]); + } + + // 表格的操作列 + $this->indexVueData['tableColumn'][] = [ + 'label' => "t('Operate')", + 'align' => 'center', + 'width' => $this->indexVueData['enableDragSort'] ? 140 : 100, + 'render' => 'buttons', + 'buttons' => 'optButtons', + 'operator' => 'false', + ]; + if ($this->indexVueData['enableDragSort']) { + array_unshift($this->indexVueData['optButtons'], 'weigh-sort'); + } + + // 写入语言包代码 + Helper::writeWebLangFile($this->langTsData, $webLangDir); + + // 写入模型代码 + Helper::writeModelFile($tablePk, $fieldsMap, $this->modelData, $modelFile); + + // 写入控制器代码 + Helper::writeControllerFile($this->controllerData, $controllerFile); + + // 写入验证器代码 + $validateContent = Helper::assembleStub('mixins/validate/validate', [ + 'namespace' => $validateFile['namespace'], + 'className' => $validateFile['lastName'], + ]); + Helper::writeFile($validateFile['parseFile'], $validateContent); + + // 写入index.vue代码 + $this->indexVueData['tablePk'] = $tablePk; + $this->indexVueData['webTranslate'] = $this->webTranslate; + Helper::writeIndexFile($this->indexVueData, $webViewsDir, $controllerFile); + + // 写入form.vue代码 + Helper::writeFormFile($this->formVueData, $webViewsDir, $fields, $this->webTranslate); + + // 生成菜单 + Helper::createMenu($webViewsDir, $tableComment); + + Helper::recordCrudStatus([ + 'id' => $crudLogId, + 'status' => 'success', + ]); + } catch (Exception $e) { + Helper::recordCrudStatus([ + 'id' => $crudLogId ?? 0, + 'status' => 'error', + ]); + $this->error($e->getMessage()); + } catch (Throwable $e) { + Helper::recordCrudStatus([ + 'id' => $crudLogId ?? 0, + 'status' => 'error', + ]); + if (env('app_debug', false)) throw $e; + $this->error($e->getMessage()); + } + + $this->success('', [ + 'crudLog' => CrudLog::find($crudLogId), + ]); + } + + /** + * 从log开始 + * @throws Throwable + */ + public function logStart(): void + { + $id = $this->request->post('id'); + $type = $this->request->post('type', ''); + + if ($type == 'Cloud history') { + // 云端 历史记录 + $client = get_ba_client(); + $response = $client->request('GET', '/api/v6.Crud/info', [ + 'query' => [ + 'id' => $id, + 'server' => 1, + 'ba-user-token' => $this->request->post('token', ''), + ] + ]); + $body = $response->getBody(); + $statusCode = $response->getStatusCode(); + $content = $body->getContents(); + if ($content == '' || stripos($content, '系统发生错误') !== false || $statusCode != 200) { + $this->error(__('Failed to load cloud data')); + } + $json = json_decode($content, true); + if (json_last_error() != JSON_ERROR_NONE) { + $this->error(__('Failed to load cloud data')); + } + if (is_array($json)) { + if ($json['code'] != 1) { + $this->error($json['msg']); + } + + $info = $json['data']['info']; + } + } else { + // 本地记录 + $info = CrudLog::find($id)->toArray(); + } + + if (!isset($info) || !$info) { + $this->error(__('Record not found')); + } + + // 数据表是否有数据 + $connection = TableManager::getConnection($info['table']['databaseConnection'] ?? ''); + $tableName = TableManager::tableName($info['table']['name'], false, $connection); + $adapter = TableManager::phinxAdapter(true, $connection); + if ($adapter->hasTable($tableName)) { + $info['table']['empty'] = Db::connect($connection) + ->name($tableName) + ->limit(1) + ->select() + ->isEmpty(); + } else { + $info['table']['empty'] = true; + } + + AdminLog::instance()->setTitle(__('Log start')); + + $this->success('', [ + 'table' => $info['table'], + 'fields' => $info['fields'], + 'sync' => $info['sync'], + ]); + } + + /** + * 删除CRUD记录和生成的文件 + * @throws Throwable + */ + public function delete(): void + { + $id = $this->request->post('id'); + $info = CrudLog::find($id)->toArray(); + if (!$info) { + $this->error(__('Record not found')); + } + $webLangDir = Helper::parseWebDirNameData($info['table']['name'], 'lang', $info['table']['webViewsDir']); + $files = [ + $webLangDir['en'] . '.ts', + $webLangDir['zh-cn'] . '.ts', + $info['table']['webViewsDir'] . '/' . 'index.vue', + $info['table']['webViewsDir'] . '/' . 'popupForm.vue', + $info['table']['controllerFile'], + $info['table']['modelFile'], + $info['table']['validateFile'], + ]; + try { + foreach ($files as &$file) { + $file = Filesystem::fsFit(root_path() . $file); + if (file_exists($file)) { + unlink($file); + } + Filesystem::delEmptyDir(dirname($file)); + } + + // 删除菜单 + Menu::delete(Helper::getMenuName($webLangDir), true); + + Helper::recordCrudStatus([ + 'id' => $id, + 'status' => 'delete', + ]); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + $this->success(__('Deleted successfully')); + } + + /** + * 获取文件路径数据 + * @throws Throwable + */ + public function getFileData(): void + { + $table = $this->request->get('table'); + $commonModel = $this->request->get('commonModel/b'); + + if (!$table) { + $this->error(__('Parameter error')); + } + + try { + $modelFile = Helper::parseNameData($commonModel ? 'common' : 'admin', $table, 'model'); + $validateFile = Helper::parseNameData($commonModel ? 'common' : 'admin', $table, 'validate'); + $controllerFile = Helper::parseNameData('admin', $table, 'controller'); + $webViewsDir = Helper::parseWebDirNameData($table, 'views'); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + // 模型和控制器文件和文件列表 + $adminModelFiles = Filesystem::getDirFiles(root_path() . 'app' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR); + $commonModelFiles = Filesystem::getDirFiles(root_path() . 'app' . DIRECTORY_SEPARATOR . 'common' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR); + $adminControllerFiles = get_controller_list(); + + $modelFileList = []; + $controllerFiles = []; + foreach ($adminModelFiles as $item) { + $item = Filesystem::fsFit('app/admin/model/' . $item); + $modelFileList[$item] = $item; + } + foreach ($commonModelFiles as $item) { + $item = Filesystem::fsFit('app/common/model/' . $item); + $modelFileList[$item] = $item; + } + + $outExcludeController = [ + 'Addon.php', + 'Ajax.php', + 'Dashboard.php', + 'Index.php', + 'Module.php', + 'Terminal.php', + 'routine/AdminInfo.php', + 'routine/Config.php', + ]; + foreach ($adminControllerFiles as $item) { + if (in_array($item, $outExcludeController)) { + continue; + } + $item = Filesystem::fsFit('app/admin/controller/' . $item); + $controllerFiles[$item] = $item; + } + + $this->success('', [ + 'modelFile' => $modelFile['rootFileName'], + 'controllerFile' => $controllerFile['rootFileName'], + 'validateFile' => $validateFile['rootFileName'], + 'controllerFileList' => $controllerFiles, + 'modelFileList' => $modelFileList, + 'webViewsDir' => $webViewsDir['views'], + ]); + } + + /** + * 检查是否已有CRUD记录 + * @throws Throwable + */ + public function checkCrudLog(): void + { + $table = $this->request->get('table'); + $connection = $this->request->get('connection'); + $connection = $connection ?: config('database.default'); + + $crudLog = Db::name('crud_log') + ->where('table_name', $table) + ->where('connection', $connection) + ->order('create_time desc') + ->find(); + $this->success('', [ + 'id' => ($crudLog && $crudLog['status'] == 'success') ? $crudLog['id'] : 0, + ]); + } + + /** + * 解析字段数据 + * @throws Throwable + */ + public function parseFieldData(): void + { + AdminLog::instance()->setTitle(__('Parse field data')); + $type = $this->request->post('type'); + $table = $this->request->post('table'); + $connection = $this->request->post('connection'); + $connection = TableManager::getConnection($connection); + + $table = TableManager::tableName($table, true, $connection); + $connectionConfig = TableManager::getConnectionConfig($connection); + + if ($type == 'db') { + $sql = 'SELECT * FROM `information_schema`.`tables` ' + . 'WHERE TABLE_SCHEMA = ? AND table_name = ?'; + $tableInfo = Db::connect($connection)->query($sql, [$connectionConfig['database'], $table]); + if (!$tableInfo) { + $this->error(__('Record not found')); + } + + // 数据表是否有数据 + $adapter = TableManager::phinxAdapter(false, $connection); + if ($adapter->hasTable($table)) { + $empty = Db::connect($connection) + ->table($table) + ->limit(1) + ->select() + ->isEmpty(); + } else { + $empty = true; + } + + $this->success('', [ + 'columns' => Helper::parseTableColumns($table, false, $connection), + 'comment' => $tableInfo[0]['TABLE_COMMENT'] ?? '', + 'empty' => $empty, + ]); + } + } + + /** + * 生成前检查 + * @throws Throwable + */ + public function generateCheck(): void + { + $table = $this->request->post('table'); + $connection = $this->request->post('connection'); + $webViewsDir = $this->request->post('webViewsDir', ''); + $controllerFile = $this->request->post('controllerFile', ''); + + if (!$table) { + $this->error(__('Parameter error')); + } + + AdminLog::instance()->setTitle(__('Generate check')); + + try { + $webViewsDir = Helper::parseWebDirNameData($table, 'views', $webViewsDir); + $controllerFile = Helper::parseNameData('admin', $table, 'controller', $controllerFile)['rootFileName']; + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + // 数据表是否存在 + $tableList = TableManager::getTableList($connection); + $tableExist = array_key_exists(TableManager::tableName($table, true, $connection), $tableList); + + // 控制器是否存在 + $controllerExist = file_exists(root_path() . $controllerFile); + + // 菜单规则是否存在 + $menuName = Helper::getMenuName($webViewsDir); + $menuExist = AdminRule::where('name', $menuName)->value('id'); + + if ($controllerExist || $tableExist || $menuExist) { + $this->error('', [ + 'menu' => $menuExist, + 'table' => $tableExist, + 'controller' => $controllerExist, + ], -1); + } + $this->success(); + } + + /** + * CRUD 设计记录上传成功标记 + * @throws Throwable + */ + public function uploadCompleted(): void + { + $syncIds = $this->request->post('syncIds/a', []); + $cancelSync = $this->request->post('cancelSync/b', false); + $crudLogModel = new CrudLog(); + + if ($cancelSync) { + $logData = $crudLogModel->where('id', 'in', array_keys($syncIds))->select(); + foreach ($logData as $logDatum) { + if ($logDatum->sync == $syncIds[$logDatum->id]) { + $logDatum->sync = 0; + $logDatum->save(); + } + } + $this->success(); + } + + $saveData = []; + foreach ($syncIds as $key => $syncId) { + $saveData[] = [ + 'id' => $key, + 'sync' => $syncId, + ]; + } + $crudLogModel->saveAll($saveData); + $this->success(); + } + + /** + * 关联表数据解析 + * @param $field + * @param $table + * @throws Throwable + */ + private function parseJoinData($field, $table): void + { + $dictEn = []; + $dictZhCn = []; + + if ($field['form']['relation-fields'] && $field['form']['remote-table']) { + $columns = Helper::parseTableColumns($field['form']['remote-table'], true, $table['databaseConnection']); + $relationFields = explode(',', $field['form']['relation-fields']); + $tableName = TableManager::tableName($field['form']['remote-table'], false, $table['databaseConnection']); + $rnPattern = '/(.*)(_ids|_id)$/'; + if (preg_match($rnPattern, $field['name'])) { + $relationName = parse_name(preg_replace($rnPattern, '$1', $field['name']), 1, false); + } else { + $relationName = parse_name($field['name'] . '_table', 1, false); + } + + // 建立关联模型代码文件 + if (!$field['form']['remote-model'] || !file_exists(root_path() . $field['form']['remote-model'])) { + $joinModelFile = Helper::parseNameData('admin', $tableName, 'model', $field['form']['remote-model']); + if (!file_exists(root_path() . $joinModelFile['rootFileName'])) { + $joinModelData['append'] = []; + $joinModelData['methods'] = []; + $joinModelData['fieldType'] = []; + $joinModelData['createTime'] = ''; + $joinModelData['updateTime'] = ''; + $joinModelData['beforeInsertMixins'] = []; + $joinModelData['beforeInsert'] = ''; + $joinModelData['afterInsert'] = ''; + $joinModelData['connection'] = $table['databaseConnection']; + $joinModelData['name'] = $tableName; + $joinModelData['className'] = $joinModelFile['lastName']; + $joinModelData['namespace'] = $joinModelFile['namespace']; + $joinTablePk = 'id'; + $joinFieldsMap = []; + foreach ($columns as $column) { + $joinFieldsMap[$column['name']] = $column['designType']; + $this->parseModelMethods($column, $joinModelData); + if ($column['primaryKey']) $joinTablePk = $column['name']; + } + $weighKey = array_search('weigh', $joinFieldsMap); + if ($weighKey !== false) { + $joinModelData['afterInsert'] = Helper::assembleStub('mixins/model/afterInsert', [ + 'field' => $joinFieldsMap[$weighKey] + ]); + } + Helper::writeModelFile($joinTablePk, $joinFieldsMap, $joinModelData, $joinModelFile); + } + $field['form']['remote-model'] = $joinModelFile['rootFileName']; + } + + if ($field['designType'] == 'remoteSelect') { + // 关联预载入方法 + $this->controllerData['attr']['withJoinTable'][$relationName] = $relationName; + + // 模型方法代码 + $relationData = [ + 'relationMethod' => $relationName, + 'relationMode' => 'belongsTo', + 'relationPrimaryKey' => $field['form']['remote-pk'] ?? 'id', + 'relationForeignKey' => $field['name'], + 'relationClassName' => str_replace(['.php', '/'], ['', '\\'], '\\' . $field['form']['remote-model']) . "::class", + ]; + $this->modelData['relationMethodList'][$relationName] = Helper::assembleStub('mixins/model/belongsTo', $relationData); + + // 查询时显示的字段 + if ($relationFields) { + $this->controllerData['relationVisibleFieldList'][$relationData['relationMethod']] = $relationFields; + } + } elseif ($field['designType'] == 'remoteSelects') { + $this->modelData['append'][] = $relationName; + $this->modelData['methods'][] = Helper::assembleStub('mixins/model/getters/remoteSelectLabels', [ + 'field' => parse_name($relationName, 1), + 'className' => str_replace(['.php', '/'], ['', '\\'], '\\' . $field['form']['remote-model']), + 'primaryKey' => $field['form']['remote-pk'] ?? 'id', + 'foreignKey' => $field['name'], + 'labelFieldName' => $field['form']['remote-field'] ?? 'name', + ]); + } + + foreach ($relationFields as $relationField) { + if (!array_key_exists($relationField, $columns)) continue; + $relationFieldPrefix = $relationName . '.'; + $relationFieldLangPrefix = strtolower($relationName) . '__'; + Helper::getDictData($dictEn, $columns[$relationField], 'en', $relationFieldLangPrefix); + Helper::getDictData($dictZhCn, $columns[$relationField], 'zh-cn', $relationFieldLangPrefix); + + // 不允许双击编辑的字段 + if ($columns[$relationField]['designType'] == 'switch') { + $this->indexVueData['dblClickNotEditColumn'][] = $field['name']; + } + + // 列字典数据 + $columnDict = $this->getColumnDict($columns[$relationField], $relationFieldLangPrefix); + + // 表格列 + $columns[$relationField]['designType'] = $field['designType']; + $columns[$relationField]['form'] = $field['form'] + $columns[$relationField]['form']; + $columns[$relationField]['table'] = $field['table'] + $columns[$relationField]['table']; + + // 公共搜索渲染为远程下拉时,远程下拉组件的必填属性 + $remoteAttr = [ + 'pk' => $this->getRemoteSelectPk($field), + 'field' => $field['form']['remote-field'] ?? 'name', + 'remoteUrl' => $this->getRemoteSelectUrl($field), + ]; + + if ($columns[$relationField]['table']['comSearchRender'] == 'remoteSelect') { + // 生成为已关闭公共搜索的表格列 + $renderColumn = $columns[$relationField]; + $renderColumn['table']['operator'] = 'false'; + unset($renderColumn['table']['comSearchRender']); + $this->indexVueData['tableColumn'][] = $this->getTableColumn($renderColumn, $columnDict, $relationFieldPrefix, $relationFieldLangPrefix); + + // 额外生成一个公共搜索渲染为远程下拉的列,关闭表格列表显示 + $columns[$relationField]['table']['show'] = 'false'; + $columns[$relationField]['table']['label'] = "t('" . $this->webTranslate . $relationFieldLangPrefix . $columns[$relationField]['name'] . "')"; + $columns[$relationField]['name'] = $field['name']; + + // 标记多选 + if ($field['designType'] == 'remoteSelects') { + $remoteAttr['multiple'] = 'true'; + } + + $columnData = $this->getTableColumn($columns[$relationField], $columnDict, '', $relationFieldLangPrefix); + $columnData['comSearchInputAttr'] = array_merge($remoteAttr, $columnData['comSearchInputAttr'] ?? []); + } else { + $columnData = $this->getTableColumn($columns[$relationField], $columnDict, $relationFieldPrefix, $relationFieldLangPrefix); + } + $this->indexVueData['tableColumn'][] = $columnData; + } + } + $this->langTsData['en'] = array_merge($this->langTsData['en'], $dictEn); + $this->langTsData['zh-cn'] = array_merge($this->langTsData['zh-cn'], $dictZhCn); + } + + /** + * 解析模型方法(设置器、获取器等) + */ + private function parseModelMethods($field, &$modelData): void + { + // fieldType + if ($field['designType'] == 'array') { + $modelData['fieldType'][$field['name']] = 'json'; + } elseif (!in_array($field['name'], ['create_time', 'update_time', 'updatetime', 'createtime']) && $field['designType'] == 'datetime' && (in_array($field['type'], ['int', 'bigint']))) { + $modelData['fieldType'][$field['name']] = 'timestamp:Y-m-d H:i:s'; + } + + // beforeInsertMixins + if ($field['designType'] == 'spk') { + $modelData['beforeInsertMixins']['snowflake'] = Helper::assembleStub('mixins/model/mixins/beforeInsertWithSnowflake', []); + } + + // methods + $fieldName = parse_name($field['name'], 1); + if (in_array($field['designType'], $this->dtStringToArray)) { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/stringToArray', [ + 'field' => $fieldName + ]); + $modelData['methods'][] = Helper::assembleStub('mixins/model/setters/arrayToString', [ + 'field' => $fieldName + ]); + } elseif ($field['designType'] == 'array') { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/jsonDecode', [ + 'field' => $fieldName + ]); + } elseif ($field['designType'] == 'time') { + $modelData['methods'][] = Helper::assembleStub('mixins/model/setters/time', [ + 'field' => $fieldName + ]); + } elseif ($field['designType'] == 'editor') { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/htmlDecode', [ + 'field' => $fieldName + ]); + } elseif ($field['designType'] == 'spk') { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/string', [ + 'field' => $fieldName + ]); + } elseif (in_array($field['type'], ['float', 'decimal', 'double'])) { + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/float', [ + 'field' => $fieldName + ]); + } + + if ($field['designType'] == 'city') { + $modelData['append'][] = $field['name'] . '_text'; + $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/cityNames', [ + 'field' => $fieldName . 'Text', + 'originalFieldName' => $field['name'], + ]); + } + } + + /** + * 控制器/模型等文件的一些杂项属性解析 + */ + private function parseSundryData($field, $table): void + { + if ($field['designType'] == 'editor') { + $this->formVueData['bigDialog'] = true; // 加宽 dialog + $this->controllerData['filterRule'] = "\n" . Helper::tab(2) . '$this->request->filter(\'clean_xss\');'; // 修改变量过滤规则 + } + + // 默认排序字段 + if ($table['defaultSortField'] && $table['defaultSortType']) { + $defaultSortField = "{$table['defaultSortField']},{$table['defaultSortType']}"; + if ($defaultSortField == 'id,desc') { + $this->controllerData['attr']['defaultSortField'] = ''; + } else { + $this->controllerData['attr']['defaultSortField'] = $defaultSortField; + $this->indexVueData['defaultOrder'] = Helper::buildDefaultOrder($table['defaultSortField'], $table['defaultSortType']); + } + } + + // 自定义了权重字段名称 + if ($field['originalDesignType'] == 'weigh' && $field['name'] != 'weigh') { + $this->controllerData['attr']['weighField'] = $field['name']; + } + } + + /** + * 组装前台表单的数据 + * @throws Throwable + */ + private function getFormField($field, $columnDict, ?string $dbConnection = null): array + { + // 表单项属性 + $formField = [ + ':label' => 't(\'' . $this->webTranslate . $field['name'] . '\')', + 'type' => $field['designType'], + 'v-model' => 'baTable.form.items!.' . $field['name'], + 'prop' => $field['name'], + ]; + + // 不同输入框的属性处理 + if ($columnDict || in_array($field['designType'], ['radio', 'checkbox', 'select', 'selects'])) { + $formField[':input-attr']['content'] = $columnDict; + } elseif ($field['designType'] == 'textarea') { + $formField[':input-attr']['rows'] = (int)($field['form']['rows'] ?? 3); + $formField['@keyup.enter.stop'] = ''; + $formField['@keyup.ctrl.enter'] = 'baTable.onSubmit(formRef)'; + } elseif ($field['designType'] == 'remoteSelect' || $field['designType'] == 'remoteSelects') { + $formField[':input-attr']['pk'] = $this->getRemoteSelectPk($field); + $formField[':input-attr']['field'] = $field['form']['remote-field'] ?? 'name'; + $formField[':input-attr']['remoteUrl'] = $this->getRemoteSelectUrl($field); + } elseif ($field['designType'] == 'number') { + $formField[':input-attr']['step'] = (int)($field['form']['step'] ?? 1); + } elseif ($field['designType'] == 'icon') { + $formField[':input-attr']['placement'] = 'top'; + } elseif ($field['designType'] == 'editor') { + $formField['@keyup.enter.stop'] = ''; + $formField['@keyup.ctrl.enter'] = 'baTable.onSubmit(formRef)'; + } + + // placeholder + if (!in_array($field['designType'], ['image', 'images', 'file', 'files', 'switch'])) { + if (in_array($field['designType'], ['radio', 'checkbox', 'datetime', 'year', 'date', 'time', 'select', 'selects', 'remoteSelect', 'remoteSelects', 'city', 'icon'])) { + $formField[':placeholder'] = "t('Please select field', { field: t('" . $this->webTranslate . $field['name'] . "') })"; + } else { + $formField[':placeholder'] = "t('Please input field', { field: t('" . $this->webTranslate . $field['name'] . "') })"; + } + } + + // 默认值 + if ($field['defaultType'] == 'INPUT') { + $this->indexVueData['defaultItems'][$field['name']] = $field['default']; + } + + // 部分生成类型的默认值需要额外处理 + if ($field['designType'] == 'editor') { + $this->indexVueData['defaultItems'][$field['name']] = ($field['defaultType'] == 'INPUT' && $field['default']) ? $field['default'] : ''; + } elseif ($field['designType'] == 'array') { + $this->indexVueData['defaultItems'][$field['name']] = "[]"; + } elseif ($field['defaultType'] == 'INPUT' && in_array($field['designType'], $this->dtStringToArray) && str_contains($field['default'], ',')) { + $this->indexVueData['defaultItems'][$field['name']] = Helper::buildSimpleArray(explode(',', $field['default'])); + } elseif ($field['defaultType'] == 'INPUT' && in_array($field['designType'], ['number', 'float'])) { + $this->indexVueData['defaultItems'][$field['name']] = (float)$field['default']; + } + + // 无意义的默认值 + if (isset($field['default']) && in_array($field['designType'], ['switch', 'number', 'float', 'remoteSelect']) && $field['default'] == 0) { + unset($this->indexVueData['defaultItems'][$field['name']]); + } + + return $formField; + } + + private function getRemoteSelectPk($field): string + { + $pk = $field['form']['remote-pk'] ?? 'id'; + if (!str_contains($pk, '.')) { + if ($field['form']['remote-source-config-type'] == 'crud' && $field['form']['remote-model']) { + $alias = parse_name(basename(str_replace('\\', '/', $field['form']['remote-model']), '.php')); + } else { + $alias = $field['form']['remote-primary-table-alias'] ?? ''; + } + } + return !empty($alias) ? "$alias.$pk" : $pk; + } + + private function getRemoteSelectUrl($field): string + { + if ($field['form']['remote-source-config-type'] == 'crud' && $field['form']['remote-controller']) { + $pathArr = []; + $controller = explode(DIRECTORY_SEPARATOR, $field['form']['remote-controller']); + $controller = str_replace('.php', '', $controller); + $redundantDir = [ + 'app' => 0, + 'admin' => 1, + 'controller' => 2, + ]; + foreach ($controller as $key => $item) { + if (!array_key_exists($item, $redundantDir) || $key !== $redundantDir[$item]) { + $pathArr[] = $item; + } + } + $url = count($pathArr) > 1 ? implode('.', $pathArr) : $pathArr[0]; + return '/admin/' . $url . '/index'; + } + return $field['form']['remote-url']; + } + + private function getTableColumn($field, $columnDict, $fieldNamePrefix = '', $translationPrefix = ''): array + { + $column = [ + 'label' => "t('" . $this->webTranslate . $translationPrefix . $field['name'] . "')", + 'prop' => $fieldNamePrefix . $field['name'] . ($field['designType'] == 'city' ? '_text' : ''), + 'align' => 'center', + ]; + + // 模糊搜索增加一个placeholder + if (isset($field['table']['operator']) && $field['table']['operator'] == 'LIKE') { + $column['operatorPlaceholder'] = "t('Fuzzy query')"; + } + + // 合并前端预设的字段表格属性 + if (!empty($field['table'])) { + $column = array_merge($column, $field['table']); + $column['comSearchInputAttr'] = str_attr_to_array($column['comSearchInputAttr'] ?? ''); + } + + // 需要值替换的渲染类型 + $columnReplaceValue = ['tag', 'tags', 'switch']; + if (!in_array($field['designType'], ['remoteSelect', 'remoteSelects']) && ($columnDict || (isset($field['table']['render']) && in_array($field['table']['render'], $columnReplaceValue)))) { + $column['replaceValue'] = $columnDict; + } + + if (isset($column['render']) && $column['render'] == 'none') { + unset($column['render']); + } + return $column; + } + + private function getColumnDict($column, $translationPrefix = ''): array + { + $dict = []; + // 确保字典中无翻译也可以识别到该值 + if (in_array($column['type'], ['enum', 'set'])) { + $dataType = str_replace(' ', '', $column['dataType']); + $columnData = substr($dataType, stripos($dataType, '(') + 1, -1); + $columnData = explode(',', str_replace(["'", '"'], '', $columnData)); + foreach ($columnData as $columnDatum) { + $dict[$columnDatum] = $column['name'] . ' ' . $columnDatum; + } + } + $dictData = []; + Helper::getDictData($dictData, $column, 'zh-cn', $translationPrefix); + if ($dictData) { + unset($dictData[$translationPrefix . $column['name']]); + foreach ($dictData as $key => $item) { + $keyName = str_replace($translationPrefix . $column['name'] . ' ', '', $key); + $dict[$keyName] = "t('" . $this->webTranslate . $key . "')"; + } + } + return $dict; + } +} \ No newline at end of file diff --git a/app/admin/controller/crud/Log.php b/app/admin/controller/crud/Log.php new file mode 100644 index 0000000..59624fa --- /dev/null +++ b/app/admin/controller/crud/Log.php @@ -0,0 +1,37 @@ +model = new CrudLog(); + + if (!$this->auth->check('crud/crud/index')) { + $this->error(__('You have no permission'), [], 401); + } + } + +} \ No newline at end of file diff --git a/app/admin/controller/routine/AdminInfo.php b/app/admin/controller/routine/AdminInfo.php new file mode 100644 index 0000000..945e5e3 --- /dev/null +++ b/app/admin/controller/routine/AdminInfo.php @@ -0,0 +1,90 @@ +auth->setAllowFields($this->authAllowFields); + $this->model = $this->auth->getAdmin(); + } + + public function index(): void + { + $info = $this->auth->getInfo(); + $this->success('', [ + 'info' => $info + ]); + } + + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + if (!empty($data['avatar'])) { + $row->avatar = $data['avatar']; + if ($row->save()) { + $this->success(__('Avatar modified successfully!')); + } + } + + // 数据验证 + if ($this->modelValidate) { + try { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + $validate = new $validate(); + $validate->scene('info')->check($data); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + } + + if (!empty($data['password'])) { + $this->model->resetPassword($this->auth->id, $data['password']); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + } +} \ No newline at end of file diff --git a/app/admin/controller/routine/Attachment.php b/app/admin/controller/routine/Attachment.php new file mode 100644 index 0000000..776a115 --- /dev/null +++ b/app/admin/controller/routine/Attachment.php @@ -0,0 +1,59 @@ +model = new AttachmentModel(); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $this->request->param('ids/a', []); + $where[] = [$this->model->getPk(), 'in', $ids]; + $data = $this->model->where($where)->select(); + + $count = 0; + try { + foreach ($data as $v) { + $count += $v->delete(); + } + } catch (Throwable $e) { + $this->error(__('%d records and files have been deleted', [$count]) . $e->getMessage()); + } + if ($count) { + $this->success(__('%d records and files have been deleted', [$count])); + } else { + $this->error(__('No rows were deleted')); + } + } +} \ No newline at end of file diff --git a/app/admin/controller/routine/Config.php b/app/admin/controller/routine/Config.php new file mode 100644 index 0000000..64db402 --- /dev/null +++ b/app/admin/controller/routine/Config.php @@ -0,0 +1,246 @@ + 'config/app.php', + 'webAdminBase' => 'web/src/router/static/adminBase.ts', + 'backendEntranceStub' => 'app/admin/library/stubs/backendEntrance.stub', + ]; + + public function initialize(): void + { + parent::initialize(); + $this->model = new ConfigModel(); + } + + public function index(): void + { + $configGroup = get_sys_config('config_group'); + $config = $this->model->order('weigh desc')->select()->toArray(); + + $list = []; + $newConfigGroup = []; + foreach ($configGroup as $item) { + $list[$item['key']]['name'] = $item['key']; + $list[$item['key']]['title'] = __($item['value']); + $newConfigGroup[$item['key']] = $list[$item['key']]['title']; + } + foreach ($config as $item) { + if (array_key_exists($item['group'], $newConfigGroup)) { + $item['title'] = __($item['title']); + $list[$item['group']]['list'][] = $item; + } + } + + $this->success('', [ + 'list' => $list, + 'remark' => get_route_remark(), + 'configGroup' => $newConfigGroup ?? [], + 'quickEntrance' => get_sys_config('config_quick_entrance'), + ]); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $all = $this->model->select(); + foreach ($all as $item) { + if ($item['type'] == 'editor') { + $this->request->filter('clean_xss'); + break; + } + } + if ($this->request->isPost()) { + $this->modelValidate = false; + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + + $configValue = []; + foreach ($all as $item) { + if (array_key_exists($item->name, $data)) { + $configValue[] = [ + 'id' => $item->id, + 'type' => $item->getData('type'), + 'value' => $data[$item->name] + ]; + + // 自定义后台入口 + if ($item->name == 'backend_entrance') { + $backendEntrance = get_sys_config('backend_entrance'); + if ($backendEntrance == $data[$item->name]) continue; + + if (!preg_match("/^\/[a-zA-Z0-9]+$/", $data[$item->name])) { + $this->error(__('Backend entrance rule')); + } + + // 修改 adminBaseRoutePath + $adminBaseFilePath = Filesystem::fsFit(root_path() . $this->filePath['webAdminBase']); + $adminBaseContent = @file_get_contents($adminBaseFilePath); + if (!$adminBaseContent) $this->error(__('Configuration write failed: %s', [$this->filePath['webAdminBase']])); + + $adminBaseContent = str_replace("export const adminBaseRoutePath = '$backendEntrance'", "export const adminBaseRoutePath = '{$data[$item->name]}'", $adminBaseContent); + $result = @file_put_contents($adminBaseFilePath, $adminBaseContent); + if (!$result) $this->error(__('Configuration write failed: %s', [$this->filePath['webAdminBase']])); + + // 去除后台入口开头的斜杠 + $oldBackendEntrance = ltrim($backendEntrance, '/'); + $newBackendEntrance = ltrim($data[$item->name], '/'); + + // 设置应用别名映射 + $appMap = config('app.app_map'); + $adminMapKey = array_search('admin', $appMap); + if ($adminMapKey !== false) { + unset($appMap[$adminMapKey]); + } + if ($newBackendEntrance != 'admin') { + $appMap[$newBackendEntrance] = 'admin'; + } + $appConfigFilePath = Filesystem::fsFit(root_path() . $this->filePath['appConfig']); + $appConfigContent = @file_get_contents($appConfigFilePath); + if (!$appConfigContent) $this->error(__('Configuration write failed: %s', [$this->filePath['appConfig']])); + + $appMapStr = ''; + foreach ($appMap as $newAppName => $oldAppName) { + $appMapStr .= "'$newAppName' => '$oldAppName', "; + } + $appMapStr = rtrim($appMapStr, ', '); + $appMapStr = "[$appMapStr]"; + + $appConfigContent = preg_replace("/'app_map'(\s+)=>(\s+)(.*)\/\/ 域名/s", "'app_map'\$1=>\$2$appMapStr,\n // 域名", $appConfigContent); + $result = @file_put_contents($appConfigFilePath, $appConfigContent); + if (!$result) $this->error(__('Configuration write failed: %s', [$this->filePath['appConfig']])); + + // 建立API入口文件 + $oldBackendEntranceFile = Filesystem::fsFit(public_path() . $oldBackendEntrance . '.php'); + $newBackendEntranceFile = Filesystem::fsFit(public_path() . $newBackendEntrance . '.php'); + if (file_exists($oldBackendEntranceFile)) @unlink($oldBackendEntranceFile); + + if ($newBackendEntrance != 'admin') { + $backendEntranceStub = @file_get_contents(Filesystem::fsFit(root_path() . $this->filePath['backendEntranceStub'])); + if (!$backendEntranceStub) $this->error(__('Configuration write failed: %s', [$this->filePath['backendEntranceStub']])); + + $result = @file_put_contents($newBackendEntranceFile, $backendEntranceStub); + if (!$result) $this->error(__('Configuration write failed: %s', [$newBackendEntranceFile])); + } + } + } + } + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + $result = $this->model->saveAll($configValue); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('The current page configuration item was updated successfully')); + } else { + $this->error(__('No rows updated')); + } + + } + } + + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 发送邮件测试 + * @throws Throwable + */ + public function sendTestMail(): void + { + $data = $this->request->post(); + $mail = new Email(); + try { + $mail->Host = $data['smtp_server']; + $mail->SMTPAuth = true; + $mail->Username = $data['smtp_user']; + $mail->Password = $data['smtp_pass']; + $mail->SMTPSecure = $data['smtp_verification'] == 'SSL' ? PHPMailer::ENCRYPTION_SMTPS : PHPMailer::ENCRYPTION_STARTTLS; + $mail->Port = $data['smtp_port']; + + $mail->setFrom($data['smtp_sender_mail'], $data['smtp_user']); + + $mail->isSMTP(); + $mail->addAddress($data['testMail']); + $mail->isHTML(); + $mail->setSubject(__('This is a test email') . '-' . get_sys_config('site_name')); + $mail->Body = __('Congratulations, receiving this email means that your email service has been configured correctly'); + $mail->send(); + } catch (PHPMailerException) { + $this->error($mail->ErrorInfo); + } + $this->success(__('Test mail sent successfully~')); + } +} \ No newline at end of file diff --git a/app/admin/controller/security/DataRecycle.php b/app/admin/controller/security/DataRecycle.php new file mode 100644 index 0000000..33201c5 --- /dev/null +++ b/app/admin/controller/security/DataRecycle.php @@ -0,0 +1,150 @@ +model = new DataRecycleModel(); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data['controller_as'] = str_ireplace('.php', '', $data['controller'] ?? ''); + $data['controller_as'] = strtolower(str_ireplace(['\\', '.'], '/', $data['controller_as'])); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + // 放在add方法内,就不需要额外添加权限节点了 + $this->success('', [ + 'controllers' => $this->getControllerList(), + ]); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data['controller_as'] = str_ireplace('.php', '', $data['controller'] ?? ''); + $data['controller_as'] = strtolower(str_ireplace(['\\', '.'], '/', $data['controller_as'])); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + $this->success('', [ + 'row' => $row + ]); + } + + protected function getControllerList(): array + { + $outExcludeController = [ + 'Addon.php', + 'Ajax.php', + 'Module.php', + 'Terminal.php', + 'Dashboard.php', + 'Index.php', + 'routine/AdminInfo.php', + 'user/MoneyLog.php', + 'user/ScoreLog.php', + ]; + $outControllers = []; + $controllers = get_controller_list(); + foreach ($controllers as $key => $controller) { + if (!in_array($controller, $outExcludeController)) { + $outControllers[$key] = $controller; + } + } + return $outControllers; + } +} \ No newline at end of file diff --git a/app/admin/controller/security/DataRecycleLog.php b/app/admin/controller/security/DataRecycleLog.php new file mode 100644 index 0000000..68907d8 --- /dev/null +++ b/app/admin/controller/security/DataRecycleLog.php @@ -0,0 +1,106 @@ +model = new DataRecycleLogModel(); + } + + /** + * 还原 + * @throws Throwable + */ + public function restore(): void + { + $ids = $this->request->param('ids/a', []); + $data = $this->model->where('id', 'in', $ids)->select(); + if (!$data) { + $this->error(__('Record not found')); + } + + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $row) { + $recycleData = json_decode($row['data'], true); + if (is_array($recycleData) && Db::connect(TableManager::getConnection($row->connection))->name($row->data_table)->insert($recycleData)) { + $row->delete(); + $count++; + } + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + + if ($count) { + $this->success(); + } else { + $this->error(__('No rows were restore')); + } + } + + /** + * 详情 + * @throws Throwable + */ + public function info(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->where('data_recycle_log.id', $id) + ->find(); + if (!$row) { + $this->error(__('Record not found')); + } + $data = $this->jsonToArray($row['data']); + if (is_array($data)) { + foreach ($data as $key => $item) { + $data[$key] = $this->jsonToArray($item); + } + } + $row['data'] = $data; + + $this->success('', [ + 'row' => $row + ]); + } + + protected function jsonToArray($value = '') + { + if (!is_string($value)) { + return $value; + } + $data = json_decode($value, true); + if (($data && is_object($data)) || (is_array($data) && !empty($data))) { + return $data; + } + return $value; + } +} \ No newline at end of file diff --git a/app/admin/controller/security/SensitiveData.php b/app/admin/controller/security/SensitiveData.php new file mode 100644 index 0000000..555889e --- /dev/null +++ b/app/admin/controller/security/SensitiveData.php @@ -0,0 +1,204 @@ +model = new SensitiveDataModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + foreach ($res->items() as $item) { + if ($item->data_fields) { + $fields = []; + foreach ($item->data_fields as $key => $field) { + $fields[] = $field ?: $key; + } + $item->data_fields = $fields; + } + } + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加重写 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data['controller_as'] = str_ireplace('.php', '', $data['controller'] ?? ''); + $data['controller_as'] = strtolower(str_ireplace(['\\', '.'], '/', $data['controller_as'])); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + + if (is_array($data['fields'])) { + $data['data_fields'] = []; + foreach ($data['fields'] as $field) { + $data['data_fields'][$field['name']] = $field['value']; + } + } + + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + // 放在add方法内,就不需要额外添加权限节点了 + $this->success('', [ + 'controllers' => $this->getControllerList(), + ]); + } + + /** + * 编辑重写 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data['controller_as'] = str_ireplace('.php', '', $data['controller'] ?? ''); + $data['controller_as'] = strtolower(str_ireplace(['\\', '.'], '/', $data['controller_as'])); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + + if (is_array($data['fields'])) { + $data['data_fields'] = []; + foreach ($data['fields'] as $field) { + $data['data_fields'][$field['name']] = $field['value']; + } + } + + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + $this->success('', [ + 'row' => $row, + 'controllers' => $this->getControllerList(), + ]); + } + + protected function getControllerList(): array + { + $outExcludeController = [ + 'Addon.php', + 'Ajax.php', + 'Dashboard.php', + 'Index.php', + 'Module.php', + 'Terminal.php', + 'auth/AdminLog.php', + 'routine/AdminInfo.php', + 'routine/Config.php', + 'user/MoneyLog.php', + 'user/ScoreLog.php', + ]; + $outControllers = []; + $controllers = get_controller_list(); + foreach ($controllers as $key => $controller) { + if (!in_array($controller, $outExcludeController)) { + $outControllers[$key] = $controller; + } + } + return $outControllers; + } +} \ No newline at end of file diff --git a/app/admin/controller/security/SensitiveDataLog.php b/app/admin/controller/security/SensitiveDataLog.php new file mode 100644 index 0000000..dc41595 --- /dev/null +++ b/app/admin/controller/security/SensitiveDataLog.php @@ -0,0 +1,117 @@ +model = new SensitiveDataLogModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + foreach ($res->items() as $item) { + $item->id_value = $item['primary_key'] . '=' . $item->id_value; + } + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 详情 + * @throws Throwable + */ + public function info(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->where('sensitive_data_log.id', $id) + ->find(); + if (!$row) { + $this->error(__('Record not found')); + } + + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 回滚 + * @throws Throwable + */ + public function rollback(): void + { + $ids = $this->request->param('ids/a', []); + $data = $this->model->where('id', 'in', $ids)->select(); + if (!$data) { + $this->error(__('Record not found')); + } + + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $row) { + if (Db::connect(TableManager::getConnection($row->connection))->name($row->data_table)->where($row->primary_key, $row->id_value)->update([ + $row->data_field => $row->before + ])) { + $row->delete(); + $count++; + } + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + + if ($count) { + $this->success(); + } else { + $this->error(__('No rows were rollback')); + } + } +} \ No newline at end of file diff --git a/app/admin/controller/user/Group.php b/app/admin/controller/user/Group.php new file mode 100644 index 0000000..8ca7996 --- /dev/null +++ b/app/admin/controller/user/Group.php @@ -0,0 +1,163 @@ +model = new UserGroup(); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data = $this->handleRules($data); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + $validate->scene('add')->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $data = $this->handleRules($data); + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + $validate->scene('edit')->check($data); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + // 读取所有pid,全部从节点数组移除,父级选择状态由子级决定 + $pidArr = UserRule::field('pid') + ->distinct(true) + ->where('id', 'in', $row->rules) + ->select() + ->toArray(); + $rules = $row->rules ? explode(',', $row->rules) : []; + foreach ($pidArr as $item) { + $ruKey = array_search($item['pid'], $rules); + if ($ruKey !== false) { + unset($rules[$ruKey]); + } + } + $row->rules = array_values($rules); + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 权限规则入库前处理 + * @param array $data 接受到的数据 + * @return array + * @throws Throwable + */ + private function handleRules(array &$data): array + { + if (is_array($data['rules']) && $data['rules']) { + $rules = UserRule::select(); + $super = true; + foreach ($rules as $rule) { + if (!in_array($rule['id'], $data['rules'])) { + $super = false; + } + } + + if ($super) { + $data['rules'] = '*'; + } else { + $data['rules'] = implode(',', $data['rules']); + } + } else { + unset($data['rules']); + } + return $data; + } +} \ No newline at end of file diff --git a/app/admin/controller/user/MoneyLog.php b/app/admin/controller/user/MoneyLog.php new file mode 100644 index 0000000..20f86f1 --- /dev/null +++ b/app/admin/controller/user/MoneyLog.php @@ -0,0 +1,50 @@ +model = new UserMoneyLog(); + } + + /** + * 添加 + * @param int $userId + * @throws Throwable + */ + public function add(int $userId = 0): void + { + if ($this->request->isPost()) { + parent::add(); + } + + $user = User::where('id', $userId)->find(); + if (!$user) { + $this->error(__("The user can't find it")); + } + $this->success('', [ + 'user' => $user + ]); + } +} \ No newline at end of file diff --git a/app/admin/controller/user/Rule.php b/app/admin/controller/user/Rule.php new file mode 100644 index 0000000..8b22011 --- /dev/null +++ b/app/admin/controller/user/Rule.php @@ -0,0 +1,260 @@ + 'desc']; + + protected string|array $quickSearchField = 'title'; + + /** + * 远程select初始化传值 + * @var array + */ + protected array $initValue; + + /** + * 是否组装Tree + * @var bool + */ + protected bool $assembleTree; + + /** + * 搜索关键词 + * @var string + */ + protected string $keyword; + + public function initialize(): void + { + parent::initialize(); + + // 防止 URL 中的特殊符号被默认的 filter 函数转义 + $this->request->filter('clean_xss'); + + $this->model = new UserRule(); + $this->tree = Tree::instance(); + $isTree = $this->request->param('isTree', true); + $this->initValue = $this->request->get("initValue/a", []); + $this->initValue = array_filter($this->initValue); + $this->keyword = $this->request->request('quickSearch', ''); + $this->assembleTree = $isTree && !$this->initValue; // 有初始化值时不组装树状(初始化出来的值更好看) + } + + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + $this->success('', [ + 'list' => $this->getRules(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $data[$this->dataLimitField] = $this->auth->id; + } + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + + if (!empty($data['pid'])) { + $groups = UserGroup::where('rules', '<>', '*')->select(); + foreach ($groups as $group) { + $rules = explode(',', $group->rules); + if (in_array($data['pid'], $rules) && !in_array($this->model->id, $rules)) { + $rules[] = $this->model->id; + $group->rules = implode(',', $rules); + $group->save(); + } + } + } + + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $id = $this->request->param($this->model->getPk()); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + $this->error(__('You have no permission')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $validate->check($data); + } + } + if (isset($data['pid']) && $data['pid'] > 0) { + // 满足意图并消除副作用 + $parent = $this->model->where('id', $data['pid'])->find(); + if ($parent['pid'] == $row['id']) { + $parent->pid = 0; + $parent->save(); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + + } + + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $ids = $this->request->param('ids/a', []); + + // 子级元素检查 + $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id'); + foreach ($subData as $key => $subDatum) { + if (!in_array($key, $ids)) { + $this->error(__('Please delete the child element first, or use batch deletion')); + } + } + + parent::del(); + } + + /** + * 远程下拉 + * @throws Throwable + */ + public function select(): void + { + $data = $this->getRules([['status', '=', 1]]); + + if ($this->assembleTree) { + $data = $this->tree->assembleTree($this->tree->getTreeArray($data, 'title')); + } + $this->success('', [ + 'options' => $data + ]); + } + + /** + * 获取菜单规则 + * @throws Throwable + */ + private function getRules(array $where = []): array + { + $pk = $this->model->getPk(); + $initKey = $this->request->get("initKey/s", $pk); + + if ($this->keyword) { + $keyword = explode(' ', $this->keyword); + foreach ($keyword as $item) { + $where[] = [$this->quickSearchField, 'like', '%' . $item . '%']; + } + } + + if ($this->initValue) { + $where[] = [$initKey, 'in', $this->initValue]; + } + + $data = $this->model + ->where($where) + ->order($this->queryOrderBuilder()) + ->select() + ->toArray(); + + return $this->assembleTree ? $this->tree->assembleChild($data) : $data; + } + +} \ No newline at end of file diff --git a/app/admin/controller/user/ScoreLog.php b/app/admin/controller/user/ScoreLog.php new file mode 100644 index 0000000..d8f98db --- /dev/null +++ b/app/admin/controller/user/ScoreLog.php @@ -0,0 +1,50 @@ +model = new UserScoreLog(); + } + + /** + * 添加 + * @param int $userId + * @throws Throwable + */ + public function add(int $userId = 0): void + { + if ($this->request->isPost()) { + parent::add(); + } + + $user = User::where('id', $userId)->find(); + if (!$user) { + $this->error(__("The user can't find it")); + } + $this->success('', [ + 'user' => $user + ]); + } +} \ No newline at end of file diff --git a/app/admin/controller/user/User.php b/app/admin/controller/user/User.php new file mode 100644 index 0000000..04b3929 --- /dev/null +++ b/app/admin/controller/user/User.php @@ -0,0 +1,156 @@ +model = new UserModel(); + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withoutField('password,salt') + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + * @throws Throwable + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $result = false; + $passwd = $data['password']; // 密码将被排除不直接入库 + $data = $this->excludeFields($data); + + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + + if (!empty($passwd)) { + $this->model->resetPassword($this->model->id, $passwd); + } + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($this->request->isPost()) { + $password = $this->request->post('password', ''); + if ($password) { + $this->model->resetPassword($id, $password); + } + parent::edit(); + } + + unset($row->salt); + $row->password = ''; + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 重写select + * @throws Throwable + */ + public function select(): void + { + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withoutField('password,salt') + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + foreach ($res as $re) { + $re->nickname_text = $re->username . '(ID:' . $re->id . ')'; + } + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } +} \ No newline at end of file diff --git a/app/admin/event.php b/app/admin/event.php new file mode 100644 index 0000000..8e86bde --- /dev/null +++ b/app/admin/event.php @@ -0,0 +1,16 @@ + [ + ], + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [], + 'LogLevel' => [], + 'LogWrite' => [], + 'backendInit' => [app\common\event\Security::class], + ], + 'subscribe' => [ + ], +]; \ No newline at end of file diff --git a/app/admin/lang/en.php b/app/admin/lang/en.php new file mode 100644 index 0000000..b16526f --- /dev/null +++ b/app/admin/lang/en.php @@ -0,0 +1,38 @@ + 'Please login first', + 'You have no permission' => 'You have no permission to operate', + 'Username' => 'Username', + 'Password' => 'Password', + 'Nickname' => 'Nickname', + 'Email' => 'Email', + 'Mobile' => 'Mobile Number', + 'Captcha' => 'Captcha', + 'CaptchaId' => 'Captcha Id', + 'Please enter the correct verification code' => 'Please enter the correct Captcha!', + 'Captcha error' => 'Captcha error!', + 'Parameter %s can not be empty' => 'Parameter %s can not be empty', + 'Record not found' => 'Record not found', + 'No rows were added' => 'No rows were added', + 'No rows were deleted' => 'No rows were deleted', + 'No rows updated' => 'No rows updated', + 'Update successful' => 'Update successful!', + 'Added successfully' => 'Added successfully!', + 'Deleted successfully' => 'Deleted successfully!', + 'Parameter error' => 'Parameter error!', + 'File uploaded successfully' => 'File uploaded successfully', + 'No files were uploaded' => 'No files were uploaded', + 'The uploaded file format is not allowed' => 'The uploaded file format is no allowance.', + 'The uploaded image file is not a valid image' => 'The uploaded image file is not a valid image', + 'The uploaded file is too large (%sMiB), Maximum file size:%sMiB' => 'The uploaded file is too large (%sMiB), maximum file size:%sMiB', + 'No files have been uploaded or the file size exceeds the upload limit of the server' => 'No files have been uploaded or the file size exceeds the server upload limit.', + 'Unknown' => 'Unknown', + 'Account not exist' => 'Account does not exist', + 'Account disabled' => 'Account is disabled', + 'Token login failed' => 'Token login failed', + 'Username is incorrect' => 'Incorrect username', + 'Please try again after 1 day' => 'The number of login failures exceeds the limit, please try again after 24 hours', + 'Password is incorrect' => 'Wrong password', + 'You are not logged in' => 'You are not logged in', + 'Cache cleaned~' => 'The cache has been cleaned up, please refresh the page.', +]; \ No newline at end of file diff --git a/app/admin/lang/en/ajax.php b/app/admin/lang/en/ajax.php new file mode 100644 index 0000000..e2cf328 --- /dev/null +++ b/app/admin/lang/en/ajax.php @@ -0,0 +1,9 @@ + 'Failed to switch package manager, please modify the configuration file manually:%s', + 'Failed to modify the terminal configuration. Please modify the configuration file manually:%s' => 'Failed to modify the terminal configuration, please modify the configuration file manually:%s', + 'upload' => 'Upload files', + 'Change terminal config' => 'Modify terminal configuration', + 'Clear cache' => 'Clear cache', + 'Data table does not exist' => 'Data table does not exist', +]; \ No newline at end of file diff --git a/app/admin/lang/en/auth/admin.php b/app/admin/lang/en/auth/admin.php new file mode 100644 index 0000000..b1a3073 --- /dev/null +++ b/app/admin/lang/en/auth/admin.php @@ -0,0 +1,5 @@ + 'Administrator Grouping ', + 'Please use another administrator account to disable the current account!' => 'Disable the current account, please use another administrator account!', +]; \ No newline at end of file diff --git a/app/admin/lang/en/auth/group.php b/app/admin/lang/en/auth/group.php new file mode 100644 index 0000000..19aa20f --- /dev/null +++ b/app/admin/lang/en/auth/group.php @@ -0,0 +1,6 @@ + 'Super administrator', + 'No permission' => 'No permission', + 'You cannot modify your own management group!' => 'You cannot modify your own management group!', +]; diff --git a/app/admin/lang/en/auth/menu.php b/app/admin/lang/en/auth/menu.php new file mode 100644 index 0000000..94d9d4c --- /dev/null +++ b/app/admin/lang/en/auth/menu.php @@ -0,0 +1,6 @@ + 'Rule type', + 'title' => 'Rule title', + 'name' => 'Rule name', +]; \ No newline at end of file diff --git a/app/admin/lang/en/crud/crud.php b/app/admin/lang/en/crud/crud.php new file mode 100644 index 0000000..522c32c --- /dev/null +++ b/app/admin/lang/en/crud/crud.php @@ -0,0 +1,7 @@ + 'Field %s failed to be renamed because the field does not exist in the data table', + 'del-field fail not exist' => 'Failed to delete field %s because the field does not exist in the data table', + 'change-field-attr fail not exist' => 'Description Failed to modify the properties of field %s because the field does not exist in the data table', + 'add-field fail exist' => 'Failed to add field %s because the field already exists in the data table', +]; \ No newline at end of file diff --git a/app/admin/lang/en/dashboard.php b/app/admin/lang/en/dashboard.php new file mode 100644 index 0000000..57b0f72 --- /dev/null +++ b/app/admin/lang/en/dashboard.php @@ -0,0 +1,4 @@ + "Open source equals mutual assistance, and needs everyone's support. There are many ways to support it, such as using, recommending, writing tutorials, protecting the ecology, contributing code, answering questions, sharing experiences, donation, sponsorship and so on. Welcome to join us!", +]; \ No newline at end of file diff --git a/app/admin/lang/en/index.php b/app/admin/lang/en/index.php new file mode 100644 index 0000000..e7fb229 --- /dev/null +++ b/app/admin/lang/en/index.php @@ -0,0 +1,9 @@ + 'No background menu, please contact the super administrator!', + 'You have already logged in. There is no need to log in again~' => 'You have already logged in, no need to log in again.', + 'Login succeeded!' => 'Login successful!', + 'Incorrect user name or password!' => 'Incorrect username or password!', + 'Login' => 'Login', + 'Logout' => 'Logout', +]; \ No newline at end of file diff --git a/app/admin/lang/en/routine/admininfo.php b/app/admin/lang/en/routine/admininfo.php new file mode 100644 index 0000000..924bf10 --- /dev/null +++ b/app/admin/lang/en/routine/admininfo.php @@ -0,0 +1,6 @@ + 'Please enter the correct username', + 'Please input correct password' => 'Please enter the correct password', + 'Avatar modified successfully!' => 'Profile picture modified successfully!', +]; \ No newline at end of file diff --git a/app/admin/lang/en/routine/attachment.php b/app/admin/lang/en/routine/attachment.php new file mode 100644 index 0000000..6761720 --- /dev/null +++ b/app/admin/lang/en/routine/attachment.php @@ -0,0 +1,5 @@ + '%d records and files have been deleted', + 'remark_text' => 'When the same file is uploaded multiple times, only one copy will be saved to the disk and an attachment record will be added; Deleting an attachment record will automatically delete the corresponding file!', +]; \ No newline at end of file diff --git a/app/admin/lang/en/routine/config.php b/app/admin/lang/en/routine/config.php new file mode 100644 index 0000000..6707b30 --- /dev/null +++ b/app/admin/lang/en/routine/config.php @@ -0,0 +1,23 @@ + 'Basic configuration', + 'Mail' => 'Mail configuration', + 'Config group' => 'Configure grouping', + 'Site Name' => 'Site name', + 'Config Quick entrance' => 'Quick configuration entrance', + 'Record number' => 'Record Number', + 'Version number' => 'Version Number', + 'time zone' => 'Time zone', + 'No access ip' => 'No access IP', + 'smtp server' => 'SMTP server', + 'smtp port' => 'SMTP port', + 'smtp user' => 'SMTP username', + 'smtp pass' => 'SMTP password', + 'smtp verification' => 'SMTP verification mode', + 'smtp sender mail' => 'SMTP sender mailbox', + 'Variable name' => 'variable name', + 'Test mail sent successfully~' => 'Test message sent successfully', + 'This is a test email' => 'This is a test email', + 'Congratulations, receiving this email means that your email service has been configured correctly' => "Congratulations, when you receive this email, it means that your mail service is configures correctly. This is the email subject, you can use HtmlL! in the main body.", + 'Backend entrance rule' => 'The background entry must start with / and contain only numbers and letters.', +]; \ No newline at end of file diff --git a/app/admin/lang/en/security/datarecycle.php b/app/admin/lang/en/security/datarecycle.php new file mode 100644 index 0000000..e1491ee --- /dev/null +++ b/app/admin/lang/en/security/datarecycle.php @@ -0,0 +1,7 @@ + 'Rule Name', + 'Controller' => 'Controller', + 'Data Table' => 'Corresponding data table', + 'Primary Key' => 'Data table primary key', +]; \ No newline at end of file diff --git a/app/admin/lang/en/security/datarecyclelog.php b/app/admin/lang/en/security/datarecyclelog.php new file mode 100644 index 0000000..5baf49c --- /dev/null +++ b/app/admin/lang/en/security/datarecyclelog.php @@ -0,0 +1,4 @@ + 'No records have been restored', +]; \ No newline at end of file diff --git a/app/admin/lang/en/security/sensitivedata.php b/app/admin/lang/en/security/sensitivedata.php new file mode 100644 index 0000000..4cb11da --- /dev/null +++ b/app/admin/lang/en/security/sensitivedata.php @@ -0,0 +1,8 @@ + 'Rule name', + 'Controller' => 'Controller', + 'Data Table' => 'Corresponding data table', + 'Primary Key' => 'Data table primary key', + 'Data Fields' => 'Sensitive data fields', +]; \ No newline at end of file diff --git a/app/admin/lang/en/security/sensitivedatalog.php b/app/admin/lang/en/security/sensitivedatalog.php new file mode 100644 index 0000000..53f3e10 --- /dev/null +++ b/app/admin/lang/en/security/sensitivedatalog.php @@ -0,0 +1,4 @@ + 'No records have been roll-back', +]; \ No newline at end of file diff --git a/app/admin/lang/en/user/moneylog.php b/app/admin/lang/en/user/moneylog.php new file mode 100644 index 0000000..d7d23a9 --- /dev/null +++ b/app/admin/lang/en/user/moneylog.php @@ -0,0 +1,8 @@ + 'User', + 'money' => 'Change amount', + 'memo' => 'Change Notes', + "The user can't find it" => "User does not exist", + 'Change note cannot be blank' => 'Change Notes cannot be empty', +]; \ No newline at end of file diff --git a/app/admin/lang/en/user/scorelog.php b/app/admin/lang/en/user/scorelog.php new file mode 100644 index 0000000..aed6a51 --- /dev/null +++ b/app/admin/lang/en/user/scorelog.php @@ -0,0 +1,8 @@ + 'User', + 'score' => 'Change points', + 'memo' => 'Change Notes', + "The user can't find it" => 'User does not exist', + 'Change note cannot be blank' => 'Change notes cannot be empty', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn.php b/app/admin/lang/zh-cn.php new file mode 100644 index 0000000..72b49d5 --- /dev/null +++ b/app/admin/lang/zh-cn.php @@ -0,0 +1,62 @@ + '请先登录!', + 'You have no permission' => '没有权限操作!', + 'Username' => '用户名', + 'Password' => '密码', + 'Nickname' => '昵称', + 'Email' => '邮箱', + 'Mobile' => '手机号', + 'Captcha' => '验证码', + 'CaptchaId' => '验证码ID', + 'Please enter the correct verification code' => '请输入正确的验证码!', + 'Captcha error' => '验证码错误!', + 'Parameter %s can not be empty' => '参数%s不能为空', + 'Record not found' => '记录未找到', + 'No rows were added' => '未添加任何行', + 'No rows were deleted' => '未删除任何行', + 'No rows updated' => '未更新任何行', + 'Update successful' => '更新成功!', + 'Added successfully' => '添加成功!', + 'Deleted successfully' => '删除成功!', + 'Parameter error' => '参数错误!', + 'Please use the %s field to sort before operating' => '请使用 %s 字段排序后再操作', + 'File uploaded successfully' => '文件上传成功!', + 'No files were uploaded' => '没有文件被上传', + 'The uploaded file format is not allowed' => '上传的文件格式未被允许', + 'The uploaded image file is not a valid image' => '上传的图片文件不是有效的图像', + 'The uploaded file is too large (%sMiB), Maximum file size:%sMiB' => '上传的文件太大(%sM),最大文件大小:%sM', + 'No files have been uploaded or the file size exceeds the upload limit of the server' => '没有文件被上传或文件大小超出服务器上传限制!', + 'Topic format error' => '上传存储子目录格式错误!', + 'Driver %s not supported' => '不支持的驱动:%s', + 'Unknown' => '未知', + // 权限类语言包-s + 'Account not exist' => '帐户不存在', + 'Account disabled' => '帐户已禁用', + 'Token login failed' => '令牌登录失败', + 'Username is incorrect' => '用户名不正确', + 'Please try again after 1 day' => '登录失败次数超限,请在1天后再试', + 'Password is incorrect' => '密码不正确', + 'You are not logged in' => '你没有登录', + // 权限类语言包-e + // 时间格式化-s + '%d second%s ago' => '%d秒前', + '%d minute%s ago' => '%d分钟前', + '%d hour%s ago' => '%d小时前', + '%d day%s ago' => '%d天前', + '%d week%s ago' => '%d周前', + '%d month%s ago' => '%d月前', + '%d year%s ago' => '%d年前', + '%d second%s after' => '%d秒后', + '%d minute%s after' => '%d分钟后', + '%d hour%s after' => '%d小时后', + '%d day%s after' => '%d天后', + '%d week%s after' => '%d周后', + '%d month%s after' => '%d月后', + '%d year%s after' => '%d年后', + // 时间格式化-e + 'Cache cleaned~' => '缓存已清理,请刷新后台~', + 'Please delete the child element first, or use batch deletion' => '请首先删除子元素,或使用批量删除!', + 'Configuration write failed: %s' => '配置写入失败:%s', + 'Token expiration' => '登录态过期,请重新登录!', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/ajax.php b/app/admin/lang/zh-cn/ajax.php new file mode 100644 index 0000000..2994d4c --- /dev/null +++ b/app/admin/lang/zh-cn/ajax.php @@ -0,0 +1,12 @@ + '开始进行数据库迁移', + 'Start formatting the web project code' => '开始格式化前端代码(失败无影响,代码编辑器内按需的手动格式化即可)', + 'Start installing the composer dependencies' => '开始安装服务端依赖', + 'Start executing the build command of the web project' => '开始执行 web 工程的 build 命令,成功后会自动将构建产物移动至 根目录/public 目录下', + 'Failed to modify the terminal configuration. Please modify the configuration file manually:%s' => '修改终端配置失败,请手动修改配置文件:%s', + 'upload' => '上传文件', + 'Change terminal config' => '修改终端配置', + 'Clear cache' => '清理缓存', + 'Data table does not exist' => '数据表不存在~', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/auth/admin.php b/app/admin/lang/zh-cn/auth/admin.php new file mode 100644 index 0000000..efa0622 --- /dev/null +++ b/app/admin/lang/zh-cn/auth/admin.php @@ -0,0 +1,6 @@ + '管理员分组', + 'Please use another administrator account to disable the current account!' => '请使用另外的管理员账户禁用当前账户!', + 'You have no permission to add an administrator to this group!' => '您没有权限向此分组添加管理员!', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/auth/group.php b/app/admin/lang/zh-cn/auth/group.php new file mode 100644 index 0000000..1b5db16 --- /dev/null +++ b/app/admin/lang/zh-cn/auth/group.php @@ -0,0 +1,13 @@ + '组别名称', + 'Please select rules' => '请选择权限', + 'Super administrator' => '超级管理员', + 'No permission' => '无权限', + 'You cannot modify your own management group!' => '不能修改自己所在的管理组!', + 'You need to have all permissions of this group to operate this group~' => '您需要拥有该分组的所有权限才可以操作该分组~', + 'You need to have all the permissions of the group and have additional permissions before you can operate the group~' => '您需要拥有该分组的所有权限且还有额外权限时,才可以操作该分组~', + 'Role group has all your rights, please contact the upper administrator to add or do not need to add!' => '角色组拥有您的全部权限,请联系上级管理员添加或无需添加!', + 'The group permission node exceeds the range that can be allocated' => '分组权限节点超出可分配范围,请刷新重试~', + 'Remark lang' => '为保障系统安全,角色组本身的上下级关系仅供参考,系统的实际上下级划分是根据`权限多寡`来确定的,两位管理员的权限节点:相同被认为是`同级`、包含且有额外权限才被认为是`上级`,同级不可管理同级,上级可为下级分配自己拥有的权限节点;若有特殊情况管理员需转`上级`,可建立一个虚拟权限节点', +]; diff --git a/app/admin/lang/zh-cn/auth/rule.php b/app/admin/lang/zh-cn/auth/rule.php new file mode 100644 index 0000000..4c08979 --- /dev/null +++ b/app/admin/lang/zh-cn/auth/rule.php @@ -0,0 +1,6 @@ + '规则类型', + 'title' => '规则标题', + 'name' => '规则名称', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/crud/crud.php b/app/admin/lang/zh-cn/crud/crud.php new file mode 100644 index 0000000..36ca330 --- /dev/null +++ b/app/admin/lang/zh-cn/crud/crud.php @@ -0,0 +1,11 @@ + 'CRUD代码生成-解析字段数据', + 'Log start' => 'CRUD代码生成-从历史记录开始', + 'Generate check' => 'CRUD代码生成-生成前预检', + 'change-field-name fail not exist' => '字段 %s 改名失败,数据表内不存在该字段', + 'del-field fail not exist' => '字段 %s 删除失败,数据表内不存在该字段', + 'change-field-attr fail not exist' => '修改字段 %s 的属性失败,数据表内不存在该字段', + 'add-field fail exist' => '添加字段 %s 失败,数据表内已经存在该字段', + 'Failed to load cloud data' => '加载云端数据失败,请稍后重试!', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/dashboard.php b/app/admin/lang/zh-cn/dashboard.php new file mode 100644 index 0000000..e4eaff2 --- /dev/null +++ b/app/admin/lang/zh-cn/dashboard.php @@ -0,0 +1,4 @@ + '开源等于互助;开源需要大家一起来支持,支持的方式有很多种,比如使用、推荐、写教程、保护生态、贡献代码、回答问题、分享经验、打赏赞助等;欢迎您加入我们!', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/index.php b/app/admin/lang/zh-cn/index.php new file mode 100644 index 0000000..b896075 --- /dev/null +++ b/app/admin/lang/zh-cn/index.php @@ -0,0 +1,9 @@ + '无后台菜单,请联系超级管理员!', + 'You have already logged in. There is no need to log in again~' => '您已经登录过了,无需重复登录~', + 'Login succeeded!' => '登录成功!', + 'Incorrect user name or password!' => '用户名或密码不正确!', + 'Login' => '登录', + 'Logout' => '注销登录', +]; diff --git a/app/admin/lang/zh-cn/module.php b/app/admin/lang/zh-cn/module.php new file mode 100644 index 0000000..d63d099 --- /dev/null +++ b/app/admin/lang/zh-cn/module.php @@ -0,0 +1,29 @@ + '订单找不到啦!', + 'Module already exists' => '模块已存在!', + 'package download failed' => '包下载失败!', + 'package check failed' => '包检查失败!', + 'No permission to write temporary files' => '没有权限写入临时文件!', + 'Zip file not found' => '找不到压缩包文件', + 'Unable to open the zip file' => '无法打开压缩包文件', + 'Unable to extract ZIP file' => '无法提取ZIP文件', + 'Unable to package zip file' => '无法打包zip文件', + 'Basic configuration of the Module is incomplete' => '模块基础配置不完整', + 'Module package file does not exist' => '模块包文件不存在', + 'Module file conflicts' => '模块文件存在冲突,请手动处理!', + 'Configuration file has no write permission' => '配置文件无写入权限', + 'The current state of the module cannot be set to disabled' => '模块当前状态无法设定为禁用', + 'The current state of the module cannot be set to enabled' => '模块当前状态无法设定为启用', + 'Module file updated' => '模块文件有更新', + 'Please disable the module first' => '请先禁用模块', + 'Please disable the module before updating' => '更新前请先禁用模块', + 'The directory required by the module is occupied' => '模块所需目录已被占用', + 'Install module' => '安装模块', + 'Unload module' => '卸载模块', + 'Update module' => '更新模块', + 'Change module state' => '改变模块状态', + 'Upload install module' => '上传安装模块', + 'Please login to the official website account first' => '请先使用BuildAdmin官网账户登录到模块市场~', + 'composer config %s conflict' => 'composer 配置项 %s 存在冲突', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/routine/admininfo.php b/app/admin/lang/zh-cn/routine/admininfo.php new file mode 100644 index 0000000..1f2612c --- /dev/null +++ b/app/admin/lang/zh-cn/routine/admininfo.php @@ -0,0 +1,6 @@ + '请输入正确的用户名', + 'Please input correct password' => '请输入正确的密码', + 'Avatar modified successfully!' => '头像修改成功!', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/routine/attachment.php b/app/admin/lang/zh-cn/routine/attachment.php new file mode 100644 index 0000000..22ee5a0 --- /dev/null +++ b/app/admin/lang/zh-cn/routine/attachment.php @@ -0,0 +1,5 @@ + '同一文件被多次上传时,只会保存一份至磁盘和增加一条附件记录;删除附件记录,将自动删除对应文件!', + '%d records and files have been deleted' => '删除了%d条记录和文件', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/routine/config.php b/app/admin/lang/zh-cn/routine/config.php new file mode 100644 index 0000000..22657d0 --- /dev/null +++ b/app/admin/lang/zh-cn/routine/config.php @@ -0,0 +1,25 @@ + '基础配置', + 'Mail' => '邮件配置', + 'Config group' => '配置分组', + 'Site Name' => '站点名称', + 'Backend entrance' => '自定义后台入口', + 'Config Quick entrance' => '快捷配置入口', + 'Record number' => '备案号', + 'Version number' => '版本号', + 'time zone' => '时区', + 'No access ip' => '禁止访问IP', + 'smtp server' => 'SMTP 服务器', + 'smtp port' => 'SMTP 端口', + 'smtp user' => 'SMTP 用户名', + 'smtp pass' => 'SMTP 密码', + 'smtp verification' => 'SMTP 验证方式', + 'smtp sender mail' => 'SMTP 发件人邮箱', + 'Variable name' => '变量名', + 'Test mail sent successfully~' => '测试邮件发送成功~', + 'This is a test email' => '这是一封测试邮件', + 'Congratulations, receiving this email means that your email service has been configured correctly' => '恭喜您,收到此邮件代表您的邮件服务已配置正确;这是邮件主体 在主体中可以使用Html!', + 'The current page configuration item was updated successfully' => '当前页配置项更新成功!', + 'Backend entrance rule' => '后台入口请以 / 开头,且只包含数字和字母。', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/security/datarecycle.php b/app/admin/lang/zh-cn/security/datarecycle.php new file mode 100644 index 0000000..7b21cfb --- /dev/null +++ b/app/admin/lang/zh-cn/security/datarecycle.php @@ -0,0 +1,8 @@ + '规则名称', + 'Controller' => '控制器', + 'Data Table' => '对应数据表', + 'Primary Key' => '数据表主键', + 'Remark lang' => '在此定义需要回收的数据,实现数据自动统一回收', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/security/datarecyclelog.php b/app/admin/lang/zh-cn/security/datarecyclelog.php new file mode 100644 index 0000000..4b8d0b2 --- /dev/null +++ b/app/admin/lang/zh-cn/security/datarecyclelog.php @@ -0,0 +1,4 @@ + '没有记录被还原', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/security/sensitivedata.php b/app/admin/lang/zh-cn/security/sensitivedata.php new file mode 100644 index 0000000..9367d1c --- /dev/null +++ b/app/admin/lang/zh-cn/security/sensitivedata.php @@ -0,0 +1,9 @@ + '规则名称', + 'Controller' => '控制器', + 'Data Table' => '对应数据表', + 'Primary Key' => '数据表主键', + 'Data Fields' => '敏感数据字段', + 'Remark lang' => '在此定义需要保护的敏感字段,随后系统将自动监听该字段的修改操作,并提供了敏感字段的修改回滚功能', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/security/sensitivedatalog.php b/app/admin/lang/zh-cn/security/sensitivedatalog.php new file mode 100644 index 0000000..7e62651 --- /dev/null +++ b/app/admin/lang/zh-cn/security/sensitivedatalog.php @@ -0,0 +1,4 @@ + '没有记录被回滚', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/user/moneylog.php b/app/admin/lang/zh-cn/user/moneylog.php new file mode 100644 index 0000000..da8d81d --- /dev/null +++ b/app/admin/lang/zh-cn/user/moneylog.php @@ -0,0 +1,8 @@ + '用户', + 'money' => '变更金额', + 'memo' => '变更备注', + "The user can't find it" => '用户找不到啦', + 'Change note cannot be blank' => '变更备注不能为空', +]; \ No newline at end of file diff --git a/app/admin/lang/zh-cn/user/scorelog.php b/app/admin/lang/zh-cn/user/scorelog.php new file mode 100644 index 0000000..7822169 --- /dev/null +++ b/app/admin/lang/zh-cn/user/scorelog.php @@ -0,0 +1,8 @@ + '用户', + 'score' => '变更积分', + 'memo' => '变更备注', + "The user can't find it" => '用户找不到啦', + 'Change note cannot be blank' => '变更备注不能为空', +]; \ No newline at end of file diff --git a/app/admin/library/Auth.php b/app/admin/library/Auth.php new file mode 100644 index 0000000..297581c --- /dev/null +++ b/app/admin/library/Auth.php @@ -0,0 +1,525 @@ +setKeepTime((int)Config::get('buildadmin.admin_token_keep_time')); + } + + /** + * 魔术方法-管理员信息字段 + * @param $name + * @return mixed 字段信息 + */ + public function __get($name): mixed + { + return $this->model?->$name; + } + + /** + * 初始化 + * @access public + * @param array $options 传递到 /ba/Auth 的配置信息 + * @return Auth + */ + public static function instance(array $options = []): Auth + { + $request = request(); + if (!isset($request->adminAuth)) { + $request->adminAuth = new static($options); + } + return $request->adminAuth; + } + + /** + * 根据Token初始化管理员登录态 + * @param string $token + * @return bool + * @throws Throwable + */ + public function init(string $token): bool + { + $tokenData = Token::get($token); + if ($tokenData) { + + /** + * 过期检查,过期则抛出 @see TokenExpirationException + */ + Token::tokenExpirationCheck($tokenData); + + $userId = intval($tokenData['user_id']); + if ($tokenData['type'] == self::TOKEN_TYPE && $userId > 0) { + $this->model = Admin::where('id', $userId)->find(); + if (!$this->model) { + $this->setError('Account not exist'); + return false; + } + if ($this->model['status'] != 'enable') { + $this->setError('Account disabled'); + return false; + } + $this->token = $token; + $this->loginSuccessful(); + return true; + } + } + $this->setError('Token login failed'); + $this->reset(); + return false; + } + + /** + * 管理员登录 + * @param string $username 用户名 + * @param string $password 密码 + * @param bool $keep 是否保持登录 + * @return bool + * @throws Throwable + */ + public function login(string $username, string $password, bool $keep = false): bool + { + $this->model = Admin::where('username', $username)->find(); + if (!$this->model) { + $this->setError('Username is incorrect'); + return false; + } + if ($this->model->status == 'disable') { + $this->setError('Account disabled'); + return false; + } + + // 登录失败重试检查 + $lastLoginTime = $this->model->getData('last_login_time'); + $adminLoginRetry = Config::get('buildadmin.admin_login_retry'); + if ($adminLoginRetry && $lastLoginTime) { + // 重置失败次数 + if ($this->model->login_failure > 0 && time() - $lastLoginTime >= 86400) { + $this->model->login_failure = 0; + $this->model->save(); + + // 重获模型实例,避免单实例多次更新 + $this->model = Admin::where('username', $username)->find(); + } + + if ($this->model->login_failure >= $adminLoginRetry) { + $this->setError('Please try again after 1 day'); + return false; + } + } + + // 密码检查 + if (!verify_password($password, $this->model->password, ['salt' => $this->model->salt])) { + $this->loginFailed(); + $this->setError('Password is incorrect'); + return false; + } + + // 清理 token + if (Config::get('buildadmin.admin_sso')) { + Token::clear(self::TOKEN_TYPE, $this->model->id); + Token::clear(self::TOKEN_TYPE . '-refresh', $this->model->id); + } + + if ($keep) { + $this->setRefreshToken($this->refreshTokenKeepTime); + } + $this->loginSuccessful(); + return true; + } + + /** + * 设置刷新Token + * @param int $keepTime + */ + public function setRefreshToken(int $keepTime = 0): void + { + $this->refreshToken = Random::uuid(); + Token::set($this->refreshToken, self::TOKEN_TYPE . '-refresh', $this->model->id, $keepTime); + } + + /** + * 管理员登录成功 + * @return bool + */ + public function loginSuccessful(): bool + { + if (!$this->model) return false; + $this->model->startTrans(); + try { + $this->model->login_failure = 0; + $this->model->last_login_time = time(); + $this->model->last_login_ip = request()->ip(); + $this->model->save(); + $this->loginEd = true; + + if (!$this->token) { + $this->token = Random::uuid(); + Token::set($this->token, self::TOKEN_TYPE, $this->model->id, $this->keepTime); + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->setError($e->getMessage()); + return false; + } + return true; + } + + /** + * 管理员登录失败 + * @return bool + */ + public function loginFailed(): bool + { + if (!$this->model) return false; + $this->model->startTrans(); + try { + $this->model->login_failure++; + $this->model->last_login_time = time(); + $this->model->last_login_ip = request()->ip(); + $this->model->save(); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->setError($e->getMessage()); + return false; + } + return $this->reset(); + } + + /** + * 退出登录 + * @return bool + */ + public function logout(): bool + { + if (!$this->loginEd) { + $this->setError('You are not logged in'); + return false; + } + return $this->reset(); + } + + /** + * 是否登录 + * @return bool + */ + public function isLogin(): bool + { + return $this->loginEd; + } + + /** + * 获取管理员模型 + * @return Admin + */ + public function getAdmin(): Admin + { + return $this->model; + } + + /** + * 获取管理员Token + * @return string + */ + public function getToken(): string + { + return $this->token; + } + + /** + * 获取管理员刷新Token + * @return string + */ + public function getRefreshToken(): string + { + return $this->refreshToken; + } + + /** + * 获取管理员信息 - 只输出允许输出的字段 + * @return array + */ + public function getInfo(): array + { + if (!$this->model) return []; + $info = $this->model->toArray(); + $info = array_intersect_key($info, array_flip($this->getAllowFields())); + $info['token'] = $this->getToken(); + $info['refresh_token'] = $this->getRefreshToken(); + return $info; + } + + /** + * 获取允许输出字段 + * @return array + */ + public function getAllowFields(): array + { + return $this->allowFields; + } + + /** + * 设置允许输出字段 + * @param $fields + * @return void + */ + public function setAllowFields($fields): void + { + $this->allowFields = $fields; + } + + /** + * 设置Token有效期 + * @param int $keepTime + * @return void + */ + public function setKeepTime(int $keepTime = 0): void + { + $this->keepTime = $keepTime; + } + + public function check(string $name, int $uid = 0, string $relation = 'or', string $mode = 'url'): bool + { + return parent::check($name, $uid ?: $this->id, $relation, $mode); + } + + public function getGroups(int $uid = 0): array + { + return parent::getGroups($uid ?: $this->id); + } + + public function getRuleList(int $uid = 0): array + { + return parent::getRuleList($uid ?: $this->id); + } + + public function getRuleIds(int $uid = 0): array + { + return parent::getRuleIds($uid ?: $this->id); + } + + public function getMenus(int $uid = 0): array + { + return parent::getMenus($uid ?: $this->id); + } + + /** + * 是否是超级管理员 + * @throws Throwable + */ + public function isSuperAdmin(): bool + { + return in_array('*', $this->getRuleIds()); + } + + /** + * 获取管理员所在分组的所有子级分组 + * @return array + * @throws Throwable + */ + public function getAdminChildGroups(): array + { + $groupIds = Db::name('admin_group_access') + ->where('uid', $this->id) + ->select(); + $children = []; + foreach ($groupIds as $group) { + $this->getGroupChildGroups($group['group_id'], $children); + } + return array_unique($children); + } + + /** + * 获取一个分组下的子分组 + * @param int $groupId 分组ID + * @param array $children 存放子分组的变量 + * @return void + * @throws Throwable + */ + public function getGroupChildGroups(int $groupId, array &$children): void + { + $childrenTemp = AdminGroup::where('pid', $groupId) + ->where('status', 1) + ->select(); + foreach ($childrenTemp as $item) { + $children[] = $item['id']; + $this->getGroupChildGroups($item['id'], $children); + } + } + + /** + * 获取分组内的管理员 + * @param array $groups + * @return array 管理员数组 + */ + public function getGroupAdmins(array $groups): array + { + return Db::name('admin_group_access') + ->where('group_id', 'in', $groups) + ->column('uid'); + } + + /** + * 获取拥有 `所有权限` 的分组 + * @param string $dataLimit 数据权限 + * @param array $groupQueryWhere 分组查询条件(默认查询启用的分组:[['status','=',1]]) + * @return array 分组数组 + * @throws Throwable + */ + public function getAllAuthGroups(string $dataLimit, array $groupQueryWhere = [['status', '=', 1]]): array + { + // 当前管理员拥有的权限 + $rules = $this->getRuleIds(); + $allAuthGroups = []; + $groups = AdminGroup::where($groupQueryWhere)->select(); + foreach ($groups as $group) { + if ($group['rules'] == '*') { + continue; + } + $groupRules = explode(',', $group['rules']); + + // 及时break, array_diff 等没有 in_array 快 + $all = true; + foreach ($groupRules as $groupRule) { + if (!in_array($groupRule, $rules)) { + $all = false; + break; + } + } + if ($all) { + if ($dataLimit == 'allAuth' || ($dataLimit == 'allAuthAndOthers' && array_diff($rules, $groupRules))) { + $allAuthGroups[] = $group['id']; + } + } + } + return $allAuthGroups; + } + + /** + * 设置错误消息 + * @param $error + * @return Auth + */ + public function setError($error): Auth + { + $this->error = $error; + return $this; + } + + /** + * 获取错误消息 + * @return string + */ + public function getError(): string + { + return $this->error ? __($this->error) : ''; + } + + /** + * 属性重置(注销、登录失败、重新初始化等将单例数据销毁) + */ + protected function reset(bool $deleteToken = true): bool + { + if ($deleteToken && $this->token) { + Token::delete($this->token); + } + + $this->token = ''; + $this->loginEd = false; + $this->model = null; + $this->refreshToken = ''; + $this->setError(''); + $this->setKeepTime((int)Config::get('buildadmin.admin_token_keep_time')); + return true; + } +} \ No newline at end of file diff --git a/app/admin/library/crud/Helper.php b/app/admin/library/crud/Helper.php new file mode 100644 index 0000000..e0e75c7 --- /dev/null +++ b/app/admin/library/crud/Helper.php @@ -0,0 +1,1299 @@ + [ + 'user' => ['user', 'user'], + 'admin' => ['auth', 'admin'], + 'admin_group' => ['auth', 'group'], + 'attachment' => ['routine', 'attachment'], + 'admin_rule' => ['auth', 'rule'], + ], + 'model' => [], + 'validate' => [], + ]; + + /** + * 子级菜单数组(权限节点) + * @var array + */ + public static array $menuChildren = [ + ['type' => 'button', 'title' => '查看', 'name' => '/index', 'status' => 1], + ['type' => 'button', 'title' => '添加', 'name' => '/add', 'status' => 1], + ['type' => 'button', 'title' => '编辑', 'name' => '/edit', 'status' => 1], + ['type' => 'button', 'title' => '删除', 'name' => '/del', 'status' => 1], + ['type' => 'button', 'title' => '快速排序', 'name' => '/sortable', 'status' => 1], + ]; + + /** + * 输入框类型的识别规则 + * @var array + */ + protected static array $inputTypeRule = [ + // 开关组件 + [ + 'type' => ['tinyint', 'int', 'enum'], + 'suffix' => ['switch', 'toggle'], + 'value' => 'switch', + ], + [ + 'column_type' => ['tinyint(1)', 'char(1)', 'tinyint(1) unsigned'], + 'suffix' => ['switch', 'toggle'], + 'value' => 'switch', + ], + // 富文本-识别规则和textarea重合,优先识别为富文本 + [ + 'type' => ['longtext', 'text', 'mediumtext', 'smalltext', 'tinytext', 'bigtext'], + 'suffix' => ['content', 'editor'], + 'value' => 'editor', + ], + // textarea + [ + 'type' => ['varchar'], + 'suffix' => ['textarea', 'multiline', 'rows'], + 'value' => 'textarea', + ], + // Array + [ + 'suffix' => ['array'], + 'value' => 'array', + ], + // 时间选择器-字段类型为int同时以['time', 'datetime']结尾 + [ + 'type' => ['int'], + 'suffix' => ['time', 'datetime'], + 'value' => 'timestamp', + ], + [ + 'type' => ['datetime', 'timestamp'], + 'value' => 'datetime', + ], + [ + 'type' => ['date'], + 'value' => 'date', + ], + [ + 'type' => ['year'], + 'value' => 'year', + ], + [ + 'type' => ['time'], + 'value' => 'time', + ], + // 单选select + [ + 'suffix' => ['select', 'list', 'data'], + 'value' => 'select', + ], + // 多选select + [ + 'suffix' => ['selects', 'multi', 'lists'], + 'value' => 'selects', + ], + // 远程select + [ + 'suffix' => ['_id'], + 'value' => 'remoteSelect', + ], + // 远程selects + [ + 'suffix' => ['_ids'], + 'value' => 'remoteSelects', + ], + // 城市选择器 + [ + 'suffix' => ['city'], + 'value' => 'city', + ], + // 单图上传 + [ + 'suffix' => ['image', 'avatar'], + 'value' => 'image', + ], + // 多图上传 + [ + 'suffix' => ['images', 'avatars'], + 'value' => 'images', + ], + // 文件上传 + [ + 'suffix' => ['file'], + 'value' => 'file', + ], + // 多文件上传 + [ + 'suffix' => ['files'], + 'value' => 'files', + ], + // icon选择器 + [ + 'suffix' => ['icon'], + 'value' => 'icon', + ], + // 单选框 + [ + 'column_type' => ['tinyint(1)', 'char(1)', 'tinyint(1) unsigned'], + 'suffix' => ['status', 'state', 'type'], + 'value' => 'radio', + ], + // 数字输入框 + [ + 'suffix' => ['number', 'int', 'num'], + 'value' => 'number', + ], + [ + 'type' => ['bigint', 'int', 'mediumint', 'smallint', 'tinyint', 'decimal', 'double', 'float'], + 'value' => 'number', + ], + // 富文本-低权重 + [ + 'type' => ['longtext', 'text', 'mediumtext', 'smalltext', 'tinytext', 'bigtext'], + 'value' => 'textarea', + ], + // 单选框-低权重 + [ + 'type' => ['enum'], + 'value' => 'radio', + ], + // 多选框 + [ + 'type' => ['set'], + 'value' => 'checkbox', + ], + // 颜色选择器 + [ + 'suffix' => ['color'], + 'value' => 'color', + ], + ]; + + /** + * 预设WEB端文件位置 + * @var array + */ + protected static array $parseWebDirPresets = [ + 'lang' => [], + 'views' => [ + 'user' => ['user', 'user'], + 'admin' => ['auth', 'admin'], + 'admin_group' => ['auth', 'group'], + 'attachment' => ['routine', 'attachment'], + 'admin_rule' => ['auth', 'rule'], + ], + ]; + + /** + * 添加时间字段 + * @var string + */ + protected static string $createTimeField = 'create_time'; + + /** + * 更新时间字段 + * @var string + */ + protected static string $updateTimeField = 'update_time'; + + /** + * 属性的类型对照表 + * @var array + */ + protected static array $attrType = [ + 'controller' => [ + 'preExcludeFields' => 'array|string', + 'quickSearchField' => 'string|array', + 'withJoinTable' => 'array', + 'defaultSortField' => 'string|array', + 'weighField' => 'string', + ], + ]; + + /** + * 获取字段字典数据 + * @param array $dict 存储字典数据的变量 + * @param array $field 字段数据 + * @param string $lang 语言 + * @param string $translationPrefix 翻译前缀 + */ + public static function getDictData(array &$dict, array $field, string $lang, string $translationPrefix = ''): array + { + if (!$field['comment']) return []; + $comment = str_replace([',', ':'], [',', ':'], $field['comment']); + if (stripos($comment, ':') !== false && stripos($comment, ',') && stripos($comment, '=') !== false) { + [$fieldTitle, $item] = explode(':', $comment); + $dict[$translationPrefix . $field['name']] = $lang == 'en' ? $field['name'] : $fieldTitle; + foreach (explode(',', $item) as $v) { + $valArr = explode('=', $v); + if (count($valArr) == 2) { + [$key, $value] = $valArr; + $dict[$translationPrefix . $field['name'] . ' ' . $key] = $lang == 'en' ? $field['name'] . ' ' . $key : $value; + } + } + } else { + $dict[$translationPrefix . $field['name']] = $lang == 'en' ? $field['name'] : $comment; + } + return $dict; + } + + /** + * 记录CRUD状态 + * @param array $data CRUD记录数据 + * @return int 记录ID + */ + public static function recordCrudStatus(array $data): int + { + if (isset($data['id'])) { + CrudLog::where('id', $data['id']) + ->update([ + 'status' => $data['status'], + ]); + return $data['id']; + } + + $connection = $data['table']['databaseConnection'] ?: config('database.default'); + $log = CrudLog::create([ + 'table_name' => $data['table']['name'], + 'comment' => $data['table']['comment'], + 'table' => $data['table'], + 'fields' => $data['fields'], + 'connection' => $connection, + 'status' => $data['status'], + ]); + return $log->id; + } + + /** + * 获取 Phinx 的字段类型数据 + * @param string $type 字段类型 + * @param array $field 字段数据 + * @return array + */ + public static function getPhinxFieldType(string $type, array $field): array + { + if ($type == 'tinyint') { + if ( + (isset($field['dataType']) && $field['dataType'] == 'tinyint(1)') || + ($field['default'] == '1' && $field['defaultType'] == 'INPUT') + ) { + $type = 'boolean'; + } + } + $phinxFieldTypeMap = [ + // 数字 + 'tinyint' => ['type' => AdapterInterface::PHINX_TYPE_INTEGER, 'limit' => MysqlAdapter::INT_TINY], + 'smallint' => ['type' => AdapterInterface::PHINX_TYPE_INTEGER, 'limit' => MysqlAdapter::INT_SMALL], + 'mediumint' => ['type' => AdapterInterface::PHINX_TYPE_INTEGER, 'limit' => MysqlAdapter::INT_MEDIUM], + 'int' => ['type' => AdapterInterface::PHINX_TYPE_INTEGER, 'limit' => null], + 'bigint' => ['type' => AdapterInterface::PHINX_TYPE_BIG_INTEGER, 'limit' => null], + 'boolean' => ['type' => AdapterInterface::PHINX_TYPE_BOOLEAN, 'limit' => null], + // 文本 + 'varchar' => ['type' => AdapterInterface::PHINX_TYPE_STRING, 'limit' => null], + 'tinytext' => ['type' => AdapterInterface::PHINX_TYPE_TEXT, 'limit' => MysqlAdapter::TEXT_TINY], + 'mediumtext' => ['type' => AdapterInterface::PHINX_TYPE_TEXT, 'limit' => MysqlAdapter::TEXT_MEDIUM], + 'longtext' => ['type' => AdapterInterface::PHINX_TYPE_TEXT, 'limit' => MysqlAdapter::TEXT_LONG], + 'tinyblob' => ['type' => AdapterInterface::PHINX_TYPE_BLOB, 'limit' => MysqlAdapter::BLOB_TINY], + 'mediumblob' => ['type' => AdapterInterface::PHINX_TYPE_BLOB, 'limit' => MysqlAdapter::BLOB_MEDIUM], + 'longblob' => ['type' => AdapterInterface::PHINX_TYPE_BLOB, 'limit' => MysqlAdapter::BLOB_LONG], + ]; + return array_key_exists($type, $phinxFieldTypeMap) ? $phinxFieldTypeMap[$type] : ['type' => $type, 'limit' => null]; + } + + /** + * 分析字段limit和精度 + * @param string $type 字段类型 + * @param array $field 字段数据 + * @return array ['limit' => 10, 'precision' => null, 'scale' => null] + */ + public static function analyseFieldLimit(string $type, array $field): array + { + $fieldType = [ + 'decimal' => ['decimal', 'double', 'float'], + 'values' => ['enum', 'set'], + ]; + + $dataTypeLimit = self::dataTypeLimit($field['dataType'] ?? ''); + if (in_array($type, $fieldType['decimal'])) { + if ($dataTypeLimit) { + return ['precision' => $dataTypeLimit[0], 'scale' => $dataTypeLimit[1] ?? 0]; + } + $scale = isset($field['precision']) ? intval($field['precision']) : 0; + return ['precision' => $field['length'] ?? 10, 'scale' => $scale]; + } elseif (in_array($type, $fieldType['values'])) { + foreach ($dataTypeLimit as &$item) { + $item = str_replace(['"', "'"], '', $item); + } + return ['values' => $dataTypeLimit]; + } elseif ($dataTypeLimit && $dataTypeLimit[0]) { + return ['limit' => $dataTypeLimit[0]]; + } elseif (isset($field['length'])) { + return ['limit' => $field['length']]; + } + return []; + } + + public static function dataTypeLimit(string $dataType): array + { + preg_match("/\((.*?)\)/", $dataType, $matches); + if (isset($matches[1]) && $matches[1]) { + return explode(',', trim($matches[1], ',')); + } + return []; + } + + public static function analyseFieldDefault(array $field): mixed + { + return match ($field['defaultType']) { + 'EMPTY STRING' => '', + 'NULL' => null, + default => $field['default'], + }; + } + + public static function searchArray($fields, callable $myFunction): array|bool + { + foreach ($fields as $key => $field) { + if (call_user_func($myFunction, $field, $key)) { + return $field; + } + } + return false; + } + + /** + * 获取 Phinx 格式的字段数据 + * @param array $field + * @return array + */ + public static function getPhinxFieldData(array $field): array + { + $conciseType = self::analyseFieldType($field); + $phinxTypeData = self::getPhinxFieldType($conciseType, $field); + + $phinxColumnOptions = self::analyseFieldLimit($conciseType, $field); + if (!is_null($phinxTypeData['limit'])) { + $phinxColumnOptions['limit'] = $phinxTypeData['limit']; + } + + // 无默认值字段 + $noDefaultValueFields = [ + 'text', 'blob', 'geometry', 'geometrycollection', 'json', 'linestring', 'longblob', 'longtext', 'mediumblob', + 'mediumtext', 'multilinestring', 'multipoint', 'multipolygon', 'point', 'polygon', 'tinyblob', + ]; + if ($field['defaultType'] != 'NONE' && !in_array($conciseType, $noDefaultValueFields)) { + $phinxColumnOptions['default'] = self::analyseFieldDefault($field); + } + + $phinxColumnOptions['null'] = (bool)$field['null']; + $phinxColumnOptions['comment'] = $field['comment']; + $phinxColumnOptions['signed'] = !$field['unsigned']; + $phinxColumnOptions['identity'] = $field['autoIncrement']; + return [ + 'type' => $phinxTypeData['type'], + 'options' => $phinxColumnOptions, + ]; + } + + /** + * 表字段排序 + * @param string $tableName 表名 + * @param array $fields 字段数据 + * @param array $designChange 前端字段改变数据 + * @param ?string $connection 数据库连接标识 + * @return void + * @throws Throwable + */ + public static function updateFieldOrder(string $tableName, array $fields, array $designChange, ?string $connection = null): void + { + if ($designChange) { + $table = TableManager::phinxTable($tableName, [], false, $connection); + foreach ($designChange as $item) { + if (!$item['sync']) continue; + + if (!empty($item['after'])) { + + $fieldName = in_array($item['type'], ['add-field', 'change-field-name']) ? $item['newName'] : $item['oldName']; + + $field = self::searchArray($fields, function ($field) use ($fieldName) { + return $field['name'] == $fieldName; + }); + + $phinxFieldData = self::getPhinxFieldData($field); + + // 字段顺序调整 + if ($item['after'] == 'FIRST FIELD') { + $phinxFieldData['options']['after'] = MysqlAdapter::FIRST; + } else { + $phinxFieldData['options']['after'] = $item['after']; + } + $table->changeColumn($fieldName, $phinxFieldData['type'], $phinxFieldData['options']); + } + } + $table->update(); + } + } + + /** + * 表设计处理 + * @param array $table 表数据 + * @param array $fields 字段数据 + * @return array + * @throws Throwable + */ + public static function handleTableDesign(array $table, array $fields): array + { + $name = TableManager::tableName($table['name'], true, $table['databaseConnection']); + $comment = $table['comment'] ?? ''; + $designChange = $table['designChange'] ?? []; + $adapter = TableManager::phinxAdapter(false, $table['databaseConnection']); + + $pk = self::searchArray($fields, function ($item) { + return $item['primaryKey']; + }); + $pk = $pk ? $pk['name'] : ''; + + if ($adapter->hasTable($name)) { + // 更新表 + if ($designChange) { + $tableManager = TableManager::phinxTable($name, [], false, $table['databaseConnection']); + $tableManager->changeComment($comment)->update(); + + // 改名和删除操作优先 + $priorityOpt = false; + foreach ($designChange as $item) { + + if (!$item['sync']) continue; + + if (in_array($item['type'], ['change-field-name', 'del-field']) && !$tableManager->hasColumn($item['oldName'])) { + // 字段不存在 + throw new BaException(__($item['type'] . ' fail not exist', [$item['oldName']])); + } + + if ($item['type'] == 'change-field-name') { + $priorityOpt = true; + $tableManager->renameColumn($item['oldName'], $item['newName']); + } elseif ($item['type'] == 'del-field') { + $priorityOpt = true; + $tableManager->removeColumn($item['oldName']); + } + } + + // 保存需要优先执行的操作,避免先改名再改属性时找不到字段 + if ($priorityOpt) { + $tableManager->update(); + } + + // 修改字段属性和添加字段操作 + foreach ($designChange as $item) { + + if (!$item['sync']) continue; + + if ($item['type'] == 'change-field-attr') { + + if (!$tableManager->hasColumn($item['oldName'])) { + // 字段不存在 + throw new BaException(__($item['type'] . ' fail not exist', [$item['oldName']])); + } + + $phinxFieldData = self::getPhinxFieldData(self::searchArray($fields, function ($field) use ($item) { + return $field['name'] == $item['oldName']; + })); + $tableManager->changeColumn($item['oldName'], $phinxFieldData['type'], $phinxFieldData['options']); + } elseif ($item['type'] == 'add-field') { + + if ($tableManager->hasColumn($item['newName'])) { + // 字段已经存在 + throw new BaException(__($item['type'] . ' fail exist', [$item['newName']])); + } + + $phinxFieldData = self::getPhinxFieldData(self::searchArray($fields, function ($field) use ($item) { + return $field['name'] == $item['newName']; + })); + $tableManager->addColumn($item['newName'], $phinxFieldData['type'], $phinxFieldData['options']); + } + } + $tableManager->update(); + + // 表更新结构完成再处理字段排序 + self::updateFieldOrder($name, $fields, $designChange, $table['databaseConnection']); + } + } else { + // 创建表 + $tableManager = TableManager::phinxTable($name, [ + 'id' => false, + 'comment' => $comment, + 'row_format' => 'DYNAMIC', + 'primary_key' => $pk, + 'collation' => 'utf8mb4_unicode_ci', + ], false, $table['databaseConnection']); + foreach ($fields as $field) { + $phinxFieldData = self::getPhinxFieldData($field); + $tableManager->addColumn($field['name'], $phinxFieldData['type'], $phinxFieldData['options']); + } + $tableManager->create(); + } + + return [$pk]; + } + + /** + * 解析文件数据 + * @throws Throwable + */ + public static function parseNameData($app, $table, $type, $value = ''): array + { + $pathArr = []; + if ($value) { + $value = str_replace('.php', '', $value); + $value = str_replace(['.', '/', '\\', '_'], '/', $value); + $pathArrTemp = explode('/', $value); + $redundantDir = [ + 'app' => 0, + $app => 1, + $type => 2, + ]; + foreach ($pathArrTemp as $key => $item) { + if (!array_key_exists($item, $redundantDir) || $key !== $redundantDir[$item]) { + $pathArr[] = $item; + } + } + } elseif (isset(self::$parseNamePresets[$type]) && array_key_exists($table, self::$parseNamePresets[$type])) { + $pathArr = self::$parseNamePresets[$type][$table]; + } else { + $table = str_replace(['.', '/', '\\', '_'], '/', $table); + $pathArr = explode('/', $table); + } + $originalLastName = array_pop($pathArr); + $pathArr = array_map('strtolower', $pathArr); + $lastName = ucfirst($originalLastName); + + // 类名不能为内部关键字 + if (in_array(strtolower($originalLastName), self::$reservedKeywords)) { + throw new Exception('Unable to use internal variable:' . $lastName); + } + + $appDir = app()->getBasePath() . $app . DIRECTORY_SEPARATOR; + $namespace = "app\\$app\\$type" . ($pathArr ? '\\' . implode('\\', $pathArr) : ''); + $parseFile = $appDir . $type . DIRECTORY_SEPARATOR . ($pathArr ? implode(DIRECTORY_SEPARATOR, $pathArr) . DIRECTORY_SEPARATOR : '') . $lastName . '.php'; + $rootFileName = $namespace . "/$lastName" . '.php'; + + return [ + 'lastName' => $lastName, + 'originalLastName' => $originalLastName, + 'path' => $pathArr, + 'namespace' => $namespace, + 'parseFile' => Filesystem::fsFit($parseFile), + 'rootFileName' => Filesystem::fsFit($rootFileName), + ]; + } + + public static function parseWebDirNameData($table, $type, $value = ''): array + { + $pathArr = []; + if ($value) { + $value = str_replace(['.', '/', '\\', '_'], '/', $value); + $pathArrTemp = explode('/', $value); + $redundantDir = [ + 'web' => 0, + 'src' => 1, + 'views' => 2, + 'lang' => 2, + 'backend' => 3, + 'pages' => 3, + 'en' => 4, + 'zh-cn' => 4, + ]; + foreach ($pathArrTemp as $key => $item) { + if (!array_key_exists($item, $redundantDir) || $key !== $redundantDir[$item]) { + $pathArr[] = $item; + } + } + } elseif (array_key_exists($table, self::$parseWebDirPresets[$type])) { + $pathArr = self::$parseWebDirPresets[$type][$table]; + } else { + $table = str_replace(['.', '/', '\\', '_'], '/', $table); + $pathArr = explode('/', $table); + } + $originalLastName = array_pop($pathArr); + $pathArr = array_map('strtolower', $pathArr); + $lastName = lcfirst($originalLastName); + + $webDir['path'] = $pathArr; + $webDir['lastName'] = $lastName; + $webDir['originalLastName'] = $originalLastName; + if ($type == 'views') { + $webDir['views'] = "web/src/views/backend" . ($pathArr ? '/' . implode('/', $pathArr) : '') . "/$lastName"; + } elseif ($type == 'lang') { + $webDir['lang'] = array_merge($pathArr, [$lastName]); + $langDir = ['en', 'zh-cn']; + foreach ($langDir as $item) { + $webDir[$item] = "web/src/lang/backend/$item" . ($pathArr ? '/' . implode('/', $pathArr) : '') . "/$lastName"; + } + } + foreach ($webDir as &$item) { + if (is_string($item)) $item = Filesystem::fsFit($item); + } + return $webDir; + } + + /** + * 获取菜单name、path + * @param array $webDir + * @return string + */ + public static function getMenuName(array $webDir): string + { + return ($webDir['path'] ? implode('/', $webDir['path']) . '/' : '') . $webDir['originalLastName']; + } + + /** + * 获取基础模板文件路径 + * @param string $name + * @return string + */ + public static function getStubFilePath(string $name): string + { + return app_path() . DIRECTORY_SEPARATOR . 'library' . DIRECTORY_SEPARATOR . 'crud' . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . Filesystem::fsFit($name) . '.stub'; + } + + /** + * 多维数组转字符串 + */ + public static function arrayToString(array|string $value): string + { + if (!is_array($value)) { + return $value; + } + foreach ($value as &$item) { + $item = self::arrayToString($item); + } + return implode(PHP_EOL, $value); + } + + /** + * 组装模板 + * @param string $name + * @param array $data + * @param bool $escape + * @return string + */ + public static function assembleStub(string $name, array $data, bool $escape = false): string + { + foreach ($data as &$datum) { + $datum = self::arrayToString($datum); + } + $search = $replace = []; + foreach ($data as $k => $v) { + $search[] = "{%$k%}"; + $replace[] = $v; + } + $stubPath = self::getStubFilePath($name); + $stubContent = file_get_contents($stubPath); + $content = str_replace($search, $replace, $stubContent); + return $escape ? self::escape($content) : $content; + } + + /** + * 获取转义编码后的值 + * @param array|string $value + * @return string + */ + public static function escape(array|string $value): string + { + if (is_array($value)) { + $value = json_encode($value, JSON_UNESCAPED_UNICODE); + } + return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false); + } + + public static function tab(int $num = 1): string + { + return str_pad('', 4 * $num); + } + + /** + * 根据数据表解析字段数据 + * @throws Throwable + */ + public static function parseTableColumns(string $table, bool $analyseField = false, ?string $connection = null): array + { + $connection = TableManager::getConnection($connection); + $connectionConfig = TableManager::getConnectionConfig($connection); + + // 从数据库中获取表字段信息 + $sql = 'SELECT * FROM `information_schema`.`columns` ' + . 'WHERE TABLE_SCHEMA = ? AND table_name = ? ' + . 'ORDER BY ORDINAL_POSITION'; + + $columns = []; + $tableColumn = Db::connect($connection)->query($sql, [$connectionConfig['database'], TableManager::tableName($table, true, $connection)]); + + foreach ($tableColumn as $item) { + $isNullAble = $item['IS_NULLABLE'] == 'YES'; + if (str_contains($item['COLUMN_TYPE'], '(')) { + $dataType = substr_replace($item['COLUMN_TYPE'], '', stripos($item['COLUMN_TYPE'], ')') + 1); + } else { + $dataType = str_replace(' unsigned', '', $item['COLUMN_TYPE']); + } + + // 默认值和默认值类型分析 + $default = ''; + if ($isNullAble && is_null($item['COLUMN_DEFAULT'])) { + $defaultType = 'NULL'; + } elseif ($item['COLUMN_DEFAULT'] == '' && in_array($item['DATA_TYPE'], ['varchar', 'char'])) { + $defaultType = 'EMPTY STRING'; + } elseif (!$isNullAble && is_null($item['COLUMN_DEFAULT'])) { + $defaultType = 'NONE'; + } else { + $defaultType = 'INPUT'; + $default = $item['COLUMN_DEFAULT']; + } + + $column = [ + 'name' => $item['COLUMN_NAME'], + 'type' => $item['DATA_TYPE'], + 'dataType' => $dataType, + 'default' => $default, + 'defaultType' => $defaultType, + 'null' => $isNullAble, + 'primaryKey' => $item['COLUMN_KEY'] == 'PRI', + 'unsigned' => (bool)stripos($item['COLUMN_TYPE'], 'unsigned'), + 'autoIncrement' => stripos($item['EXTRA'], 'auto_increment') !== false, + 'comment' => $item['COLUMN_COMMENT'], + 'designType' => self::getTableColumnsDataType($item), + 'table' => [], + 'form' => [], + ]; + if ($analyseField) { + self::analyseField($column); + } else { + self::handleTableColumn($column); + } + $columns[$item['COLUMN_NAME']] = $column; + } + return $columns; + } + + /** + * 解析到的表字段的额外处理 + */ + public static function handleTableColumn(&$column): void + { + // 预留 + } + + /** + * 分析字段数据类型 + * @param array $field 字段数据 + * @return string 字段类型 + */ + public static function analyseFieldType(array $field): string + { + $dataType = (isset($field['dataType']) && $field['dataType']) ? $field['dataType'] : $field['type']; + if (stripos($dataType, '(') !== false) { + $typeName = explode('(', $dataType); + return trim($typeName[0]); + } + return trim($dataType); + } + + /** + * 分析字段的完整数据类型定义 + * @param array $field 字段数据 + * @return string + */ + public static function analyseFieldDataType(array $field): string + { + if (!empty($field['dataType'])) return $field['dataType']; + + $conciseType = self::analyseFieldType($field); + $limit = self::analyseFieldLimit($conciseType, $field); + + if (isset($limit['precision'])) { + $dataType = "$conciseType({$limit['precision']}, {$limit['scale']})"; + } elseif (isset($limit['values'])) { + $values = implode(',', $limit['values']); + $dataType = "$conciseType($values)"; + } else { + $dataType = "$conciseType({$limit['limit']})"; + } + return $dataType; + } + + /** + * 分析字段 + */ + public static function analyseField(&$field): void + { + $field['type'] = self::analyseFieldType($field); + $field['originalDesignType'] = $field['designType']; + + // 表单项类型转换对照表 + $designTypeComparison = [ + 'pk' => 'string', + 'weigh' => 'number', + 'timestamp' => 'datetime', + 'float' => 'number', + ]; + if (array_key_exists($field['designType'], $designTypeComparison)) { + $field['designType'] = $designTypeComparison[$field['designType']]; + } + + // 是否开启了多选 + $supportMultipleComparison = ['select', 'image', 'file', 'remoteSelect']; + if (in_array($field['designType'], $supportMultipleComparison)) { + $multiKey = $field['designType'] == 'remoteSelect' ? 'select-multi' : $field['designType'] . '-multi'; + if (isset($field['form'][$multiKey]) && $field['form'][$multiKey]) { + $field['designType'] = $field['designType'] . 's'; + } + } + } + + public static function getTableColumnsDataType($column) + { + if (stripos($column['COLUMN_NAME'], 'id') !== false && stripos($column['EXTRA'], 'auto_increment') !== false) { + return 'pk'; + } elseif ($column['COLUMN_NAME'] == 'weigh') { + return 'weigh'; + } elseif (in_array($column['COLUMN_NAME'], ['createtime', 'updatetime', 'create_time', 'update_time'])) { + return 'timestamp'; + } + foreach (self::$inputTypeRule as $item) { + $typeBool = true; + $suffixBool = true; + $columnTypeBool = true; + if (isset($item['type']) && $item['type'] && !in_array($column['DATA_TYPE'], $item['type'])) { + $typeBool = false; + } + if (isset($item['suffix']) && $item['suffix']) { + $suffixBool = self::isMatchSuffix($column['COLUMN_NAME'], $item['suffix']); + } + if (isset($item['column_type']) && $item['column_type'] && !in_array($column['COLUMN_TYPE'], $item['column_type'])) { + $columnTypeBool = false; + } + if ($typeBool && $suffixBool && $columnTypeBool) { + return $item['value']; + } + } + return 'string'; + } + + /** + * 判断是否符合指定后缀 + * + * @param string $field 字段名称 + * @param string|array $suffixArr 后缀 + * @return bool + */ + protected static function isMatchSuffix(string $field, string|array $suffixArr): bool + { + $suffixArr = is_array($suffixArr) ? $suffixArr : explode(',', $suffixArr); + foreach ($suffixArr as $v) { + if (preg_match("/$v$/i", $field)) { + return true; + } + } + return false; + } + + /** + * 创建菜单 + * @throws Throwable + */ + public static function createMenu($webViewsDir, $tableComment): void + { + $menuName = self::getMenuName($webViewsDir); + if (AdminRule::where('name', $menuName)->value('id')) { + return; + } + + // 组装权限节点数据 + $menuChildren = self::$menuChildren; + foreach ($menuChildren as &$item) { + $item['name'] = $menuName . $item['name']; + } + + // 组件路径 + $componentPath = str_replace(['\\', 'web/src'], ['/', '/src'], $webViewsDir['views'] . '/' . 'index.vue'); + + // 菜单数组 + $menus = [ + 'type' => 'menu', + 'title' => $tableComment ?: $webViewsDir['originalLastName'], + 'name' => $menuName, + 'path' => $menuName, + 'menu_type' => 'tab', + 'keepalive' => 1, + 'component' => $componentPath, + 'children' => $menuChildren, + ]; + $paths = array_reverse($webViewsDir['path']); + foreach ($paths as $path) { + $menus = [ + 'type' => 'menu_dir', + 'title' => $path, + 'name' => $path, + 'path' => $path, + 'children' => [$menus], + ]; + } + + // 创建菜单 + Menu::create([$menus], 0, 'ignore'); + } + + public static function writeWebLangFile($langData, $webLangDir): void + { + foreach ($langData as $lang => $langDatum) { + $langTsContent = ''; + foreach ($langDatum as $key => $item) { + $quote = self::getQuote($item); + $keyStr = self::formatObjectKey($key); + $langTsContent .= self::tab() . $keyStr . ": $quote$item$quote,\n"; + } + $langTsContent = "export default {\n" . $langTsContent . "}\n"; + self::writeFile(root_path() . $webLangDir[$lang] . '.ts', $langTsContent); + } + } + + public static function writeFile($path, $content): bool|int + { + $path = Filesystem::fsFit($path); + if (!is_dir(dirname($path))) { + mkdir(dirname($path), 0755, true); + } + return file_put_contents($path, $content); + } + + public static function buildModelAppend($append): string + { + if (!$append) return ''; + $append = self::buildFormatSimpleArray($append); + return "\n" . self::tab() . "// 追加属性" . "\n" . self::tab() . "protected \$append = $append;\n"; + } + + public static function buildModelFieldType(array $fieldType): string + { + if (!$fieldType) return ''; + $maxStrLang = 0; + foreach ($fieldType as $key => $item) { + $strLang = strlen($key); + $maxStrLang = max($strLang, $maxStrLang); + } + + $str = ''; + foreach ($fieldType as $key => $item) { + $str .= self::tab(2) . "'$key'" . str_pad('=>', ($maxStrLang - strlen($key) + 3), ' ', STR_PAD_LEFT) . " '$item',\n"; + } + return "\n" . self::tab() . "// 字段类型转换" . "\n" . self::tab() . "protected \$type = [\n" . rtrim($str, "\n") . "\n" . self::tab() . "];\n"; + } + + public static function writeModelFile(string $tablePk, array $fieldsMap, array $modelData, array $modelFile): void + { + if ($modelData['connection'] && $modelData['connection'] != config('database.default')) { + $modelData['connection'] = "\n" . self::tab() . "// 数据库连接配置标识\n" . self::tab() . 'protected $connection = ' . "'{$modelData['connection']}';\n"; + } else { + $modelData['connection'] = ''; + } + + $modelData['pk'] = $tablePk == 'id' ? '' : "\n" . self::tab() . "// 表主键\n" . self::tab() . 'protected $pk = ' . "'$tablePk';\n"; + $modelData['autoWriteTimestamp'] = array_key_exists(self::$createTimeField, $fieldsMap) || array_key_exists(self::$updateTimeField, $fieldsMap) ? 'true' : 'false'; + if ($modelData['autoWriteTimestamp'] == 'true') { + $modelData['createTime'] = array_key_exists(self::$createTimeField, $fieldsMap) ? '' : "\n" . self::tab() . "protected \$createTime = false;"; + $modelData['updateTime'] = array_key_exists(self::$updateTimeField, $fieldsMap) ? '' : "\n" . self::tab() . "protected \$updateTime = false;"; + } + $modelMethodList = isset($modelData['relationMethodList']) ? array_merge($modelData['methods'], $modelData['relationMethodList']) : $modelData['methods']; + $modelData['methods'] = $modelMethodList ? "\n" . implode("\n", $modelMethodList) : ''; + $modelData['append'] = self::buildModelAppend($modelData['append']); + $modelData['fieldType'] = self::buildModelFieldType($modelData['fieldType']); + + // 生成雪花ID? + if (isset($modelData['beforeInsertMixins']['snowflake'])) { + // beforeInsert 组装 + $modelData['beforeInsert'] = Helper::assembleStub('mixins/model/beforeInsert', [ + 'setSnowFlakeIdCode' => $modelData['beforeInsertMixins']['snowflake'] + ]); + } + if ($modelData['afterInsert'] && $modelData['beforeInsert']) { + $modelData['afterInsert'] = "\n" . $modelData['afterInsert']; + } + + $modelFileContent = self::assembleStub('mixins/model/model', $modelData); + self::writeFile($modelFile['parseFile'], $modelFileContent); + } + + public static function writeControllerFile(array $controllerData, array $controllerFile): void + { + if (isset($controllerData['relationVisibleFieldList']) && $controllerData['relationVisibleFieldList']) { + $relationVisibleFields = '->visible(['; + foreach ($controllerData['relationVisibleFieldList'] as $cKey => $controllerDatum) { + $relationVisibleFields .= "'$cKey' => ['" . implode("', '", $controllerDatum) . "'], "; + } + $relationVisibleFields = rtrim($relationVisibleFields, ', '); + $relationVisibleFields .= '])'; + // 重写index + $controllerData['methods']['index'] = self::assembleStub('mixins/controller/index', [ + 'relationVisibleFields' => $relationVisibleFields + ]); + $controllerData['use']['Throwable'] = "\nuse Throwable;"; + unset($controllerData['relationVisibleFieldList']); + } + $controllerAttr = ''; + foreach ($controllerData['attr'] as $key => $item) { + $attrType = ''; + if (array_key_exists($key, self::$attrType['controller'])) { + $attrType = self::$attrType['controller'][$key]; + } + if (is_array($item)) { + $controllerAttr .= "\n" . self::tab() . "protected $attrType \$$key = ['" . implode("', '", $item) . "'];\n"; + } elseif ($item) { + $controllerAttr .= "\n" . self::tab() . "protected $attrType \$$key = '$item';\n"; + } + } + $controllerData['attr'] = $controllerAttr; + $controllerData['initialize'] = self::assembleStub('mixins/controller/initialize', [ + 'modelNamespace' => $controllerData['modelNamespace'], + 'modelName' => $controllerData['modelName'], + 'filterRule' => $controllerData['filterRule'], + ]); + $contentFileContent = self::assembleStub('mixins/controller/controller', $controllerData); + self::writeFile($controllerFile['parseFile'], $contentFileContent); + } + + public static function writeFormFile($formVueData, $webViewsDir, $fields, $webTranslate): void + { + $fieldHtml = "\n"; + $formVueData['bigDialog'] = $formVueData['bigDialog'] ? "\n" . self::tab(2) . 'width="70%"' : ''; + foreach ($formVueData['formFields'] as $field) { + $fieldHtml .= self::tab(5) . " $attr) { + if (is_array($attr)) { + $fieldHtml .= ' ' . $key . '="' . self::getJsonFromArray($attr) . '"'; + } else { + $fieldHtml .= ' ' . $key . '="' . $attr . '"'; + } + } + $fieldHtml .= " />\n"; + } + $formVueData['formFields'] = rtrim($fieldHtml, "\n"); + + // 表单验证规则 + foreach ($fields as $field) { + if (isset($field['form']['validator'])) { + foreach ($field['form']['validator'] as $item) { + $message = ''; + if (isset($field['form']['validatorMsg']) && $field['form']['validatorMsg']) { + $message = ", message: '{$field['form']['validatorMsg']}'"; + } + $formVueData['formValidatorRules'][$field['name']][] = "buildValidatorData({ name: '$item', title: t('$webTranslate{$field['name']}')$message })"; + } + } + } + + if ($formVueData['formValidatorRules']) { + $formVueData['imports'][] = "import { buildValidatorData } from '/@/utils/validate'"; + } + + $formVueData['importExpand'] = self::buildImportExpand($formVueData['imports']); + $formVueData['formItemRules'] = self::buildFormValidatorRules($formVueData['formValidatorRules']); + $formVueContent = self::assembleStub('html/form', $formVueData); + self::writeFile(root_path() . $webViewsDir['views'] . '/' . 'popupForm.vue', $formVueContent); + } + + public static function buildImportExpand(array $imports): string + { + $importExpand = ''; + foreach ($imports as $import) { + $importExpand .= "\n$import"; + } + return $importExpand; + } + + public static function buildFormValidatorRules(array $formValidatorRules): string + { + $rulesHtml = ""; + foreach ($formValidatorRules as $key => $formItemRule) { + $rulesArrHtml = ''; + foreach ($formItemRule as $item) { + $rulesArrHtml .= $item . ', '; + } + $rulesHtml .= self::tab() . $key . ': [' . rtrim($rulesArrHtml, ', ') . "],\n"; + } + return $rulesHtml ? "\n" . $rulesHtml : ''; + } + + public static function writeIndexFile($indexVueData, $webViewsDir, $controllerFile): void + { + $indexVueData['optButtons'] = self::buildSimpleArray($indexVueData['optButtons']); + $indexVueData['defaultItems'] = self::getJsonFromArray($indexVueData['defaultItems']); + $indexVueData['tableColumn'] = self::buildTableColumn($indexVueData['tableColumn']); + $indexVueData['dblClickNotEditColumn'] = self::buildSimpleArray($indexVueData['dblClickNotEditColumn']); + $controllerFile['path'][] = $controllerFile['originalLastName']; + $indexVueData['controllerUrl'] = '\'/admin/' . ($controllerFile['path'] ? implode('.', $controllerFile['path']) : '') . '/\''; + $indexVueData['componentName'] = ($webViewsDir['path'] ? implode('/', $webViewsDir['path']) . '/' : '') . $webViewsDir['originalLastName']; + $indexVueContent = self::assembleStub('html/index', $indexVueData); + self::writeFile(root_path() . $webViewsDir['views'] . '/' . 'index.vue', $indexVueContent); + } + + public static function buildTableColumn($tableColumnList): string + { + $columnJson = ''; + $emptyUnset = ['comSearchInputAttr', 'replaceValue', 'custom']; + foreach ($tableColumnList as $column) { + + foreach ($emptyUnset as $unsetKey) { + if (empty($column[$unsetKey])) { + unset($column[$unsetKey]); + } + } + + $columnJson .= self::tab(3) . '{'; + foreach ($column as $key => $item) { + $columnJson .= self::buildTableColumnKey($key, $item); + } + $columnJson = rtrim($columnJson, ','); + $columnJson .= ' }' . ",\n"; + } + return rtrim($columnJson, "\n"); + } + + public static function buildTableColumnKey($key, $item): string + { + $key = self::formatObjectKey($key); + if (is_array($item)) { + $itemJson = ' ' . $key . ': {'; + foreach ($item as $ik => $iItem) { + $itemJson .= self::buildTableColumnKey($ik, $iItem); + } + $itemJson = rtrim($itemJson, ','); + $itemJson .= ' },'; + } elseif ($item === 'false' || $item === 'true') { + $itemJson = ' ' . $key . ': ' . $item . ','; + } elseif (in_array($key, ['label', 'width', 'buttons'], true) || str_starts_with($item, "t('") || str_starts_with($item, "t(\"")) { + $itemJson = ' ' . $key . ': ' . $item . ','; + } else { + $itemJson = ' ' . $key . ': \'' . $item . '\','; + } + return $itemJson; + } + + public static function formatObjectKey(string $keyName): string + { + if (preg_match("/^[a-zA-Z_][a-zA-Z0-9_]+$/", $keyName)) { + return $keyName; + } else { + $quote = self::getQuote($keyName); + return "$quote$keyName$quote"; + } + } + + public static function getQuote(string $value): string + { + return stripos($value, "'") === false ? "'" : '"'; + } + + public static function buildFormatSimpleArray($arr, int $tab = 2): string + { + if (!$arr) return '[]'; + $str = '[' . PHP_EOL; + foreach ($arr as $item) { + if ($item == 'undefined' || $item == 'false' || is_numeric($item)) { + $str .= self::tab($tab) . $item . ',' . PHP_EOL; + } else { + $quote = self::getQuote($item); + $str .= self::tab($tab) . "$quote$item$quote," . PHP_EOL; + } + } + return $str . self::tab($tab - 1) . ']'; + } + + public static function buildSimpleArray($arr): string + { + if (!$arr) return '[]'; + $str = ''; + foreach ($arr as $item) { + if ($item == 'undefined' || $item == 'false' || is_numeric($item)) { + $str .= $item . ', '; + } else { + $quote = self::getQuote($item); + $str .= "$quote$item$quote, "; + } + } + return '[' . rtrim($str, ", ") . ']'; + } + + public static function buildDefaultOrder(string $field, string $type): string + { + if ($field && $type) { + $defaultOrderStub = [ + 'prop' => $field, + 'order' => $type, + ]; + $defaultOrderStub = self::getJsonFromArray($defaultOrderStub); + if ($defaultOrderStub) { + return "\n" . self::tab(2) . "defaultOrder: " . $defaultOrderStub . ','; + } + } + return ''; + } + + public static function getJsonFromArray($arr) + { + if (is_array($arr)) { + $jsonStr = ''; + foreach ($arr as $key => $item) { + $keyStr = ' ' . self::formatObjectKey($key) . ': '; + if (is_array($item)) { + $jsonStr .= $keyStr . self::getJsonFromArray($item) . ','; + } elseif ($item === 'false' || $item === 'true') { + $jsonStr .= $keyStr . ($item === 'false' ? 'false' : 'true') . ','; + } elseif ($item === null) { + $jsonStr .= $keyStr . 'null,'; + } elseif (str_starts_with($item, "t('") || str_starts_with($item, "t(\"") || $item == '[]' || in_array(gettype($item), ['integer', 'double'])) { + $jsonStr .= $keyStr . $item . ','; + } elseif (isset($item[0]) && $item[0] == '[' && str_ends_with($item, ']')) { + $jsonStr .= $keyStr . $item . ','; + } else { + $quote = self::getQuote($item); + $jsonStr .= $keyStr . "$quote$item$quote,"; + } + } + return $jsonStr ? '{' . rtrim($jsonStr, ',') . ' }' : '{}'; + } else { + return $arr; + } + } + +} \ No newline at end of file diff --git a/app/admin/library/crud/stubs/html/form.stub b/app/admin/library/crud/stubs/html/form.stub new file mode 100644 index 0000000..bbf7b8e --- /dev/null +++ b/app/admin/library/crud/stubs/html/form.stub @@ -0,0 +1,63 @@ + + + + + diff --git a/app/admin/library/crud/stubs/html/index.stub b/app/admin/library/crud/stubs/html/index.stub new file mode 100644 index 0000000..53ad5fe --- /dev/null +++ b/app/admin/library/crud/stubs/html/index.stub @@ -0,0 +1,69 @@ + + + + + diff --git a/app/admin/library/crud/stubs/mixins/controller/controller.stub b/app/admin/library/crud/stubs/mixins/controller/controller.stub new file mode 100644 index 0000000..7a5213f --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/controller/controller.stub @@ -0,0 +1,24 @@ +request->param('select')) { + $this->select(); + } + + /** + * 1. withJoin 不可使用 alias 方法设置表别名,别名将自动使用关联模型名称(小写下划线命名规则) + * 2. 以下的别名设置了主表别名,同时便于拼接查询参数等 + * 3. paginate 数据集可使用链式操作 each(function($item, $key) {}) 遍历处理 + */ + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + {%relationVisibleFields%} + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/controller/initialize.stub b/app/admin/library/crud/stubs/mixins/controller/initialize.stub new file mode 100644 index 0000000..d8888f9 --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/controller/initialize.stub @@ -0,0 +1,6 @@ + + public function initialize(): void + { + parent::initialize(); + $this->model = new \{%modelNamespace%}\{%modelName%}();{%filterRule%} + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/afterInsert.stub b/app/admin/library/crud/stubs/mixins/model/afterInsert.stub new file mode 100644 index 0000000..58d0763 --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/afterInsert.stub @@ -0,0 +1,12 @@ + + protected static function onAfterInsert($model): void + { + if (is_null($model->{%field%})) { + $pk = $model->getPk(); + if (strlen($model[$pk]) >= 19) { + $model->where($pk, $model[$pk])->update(['{%field%}' => $model->count()]); + } else { + $model->where($pk, $model[$pk])->update(['{%field%}' => $model[$pk]]); + } + } + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/beforeInsert.stub b/app/admin/library/crud/stubs/mixins/model/beforeInsert.stub new file mode 100644 index 0000000..6eebf2d --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/beforeInsert.stub @@ -0,0 +1,5 @@ + + protected static function onBeforeInsert($model): void + { +{%setSnowFlakeIdCode%} + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/belongsTo.stub b/app/admin/library/crud/stubs/mixins/model/belongsTo.stub new file mode 100644 index 0000000..995118d --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/belongsTo.stub @@ -0,0 +1,5 @@ + + public function {%relationMethod%}(): \think\model\relation\BelongsTo + { + return $this->{%relationMode%}({%relationClassName%}, '{%relationForeignKey%}', '{%relationPrimaryKey%}'); + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/getters/cityNames.stub b/app/admin/library/crud/stubs/mixins/model/getters/cityNames.stub new file mode 100644 index 0000000..191d63c --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/getters/cityNames.stub @@ -0,0 +1,7 @@ + + public function get{%field%}Attr($value, $row): string + { + if ($row['{%originalFieldName%}'] === '' || $row['{%originalFieldName%}'] === null) return ''; + $cityNames = \think\facade\Db::name('area')->whereIn('id', $row['{%originalFieldName%}'])->column('name'); + return $cityNames ? implode(',', $cityNames) : ''; + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/getters/float.stub b/app/admin/library/crud/stubs/mixins/model/getters/float.stub new file mode 100644 index 0000000..482115c --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/getters/float.stub @@ -0,0 +1,5 @@ + + public function get{%field%}Attr($value): ?float + { + return is_null($value) ? null : (float)$value; + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/getters/htmlDecode.stub b/app/admin/library/crud/stubs/mixins/model/getters/htmlDecode.stub new file mode 100644 index 0000000..47ea946 --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/getters/htmlDecode.stub @@ -0,0 +1,5 @@ + + public function get{%field%}Attr($value): string + { + return !$value ? '' : htmlspecialchars_decode($value); + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/getters/jsonDecode.stub b/app/admin/library/crud/stubs/mixins/model/getters/jsonDecode.stub new file mode 100644 index 0000000..6ae96a7 --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/getters/jsonDecode.stub @@ -0,0 +1,5 @@ + + public function get{%field%}Attr($value): array + { + return !$value ? [] : json_decode($value, true); + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/getters/remoteSelectLabels.stub b/app/admin/library/crud/stubs/mixins/model/getters/remoteSelectLabels.stub new file mode 100644 index 0000000..2767dd8 --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/getters/remoteSelectLabels.stub @@ -0,0 +1,7 @@ + + public function get{%field%}Attr($value, $row): array + { + return [ + '{%labelFieldName%}' => {%className%}::whereIn('{%primaryKey%}', $row['{%foreignKey%}'])->column('{%labelFieldName%}'), + ]; + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/getters/string.stub b/app/admin/library/crud/stubs/mixins/model/getters/string.stub new file mode 100644 index 0000000..1622c4b --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/getters/string.stub @@ -0,0 +1,5 @@ + + public function get{%field%}Attr($value): string + { + return (string)$value; + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/getters/stringToArray.stub b/app/admin/library/crud/stubs/mixins/model/getters/stringToArray.stub new file mode 100644 index 0000000..43f7543 --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/getters/stringToArray.stub @@ -0,0 +1,9 @@ + + public function get{%field%}Attr($value): array + { + if ($value === '' || $value === null) return []; + if (!is_array($value)) { + return explode(',', $value); + } + return $value; + } \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/mixins/beforeInsertWithSnowflake.stub b/app/admin/library/crud/stubs/mixins/model/mixins/beforeInsertWithSnowflake.stub new file mode 100644 index 0000000..4904e08 --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/mixins/beforeInsertWithSnowflake.stub @@ -0,0 +1,2 @@ + $pk = $model->getPk(); + $model->$pk = \app\common\library\SnowFlake::generateParticle(); \ No newline at end of file diff --git a/app/admin/library/crud/stubs/mixins/model/model.stub b/app/admin/library/crud/stubs/mixins/model/model.stub new file mode 100644 index 0000000..cd77f11 --- /dev/null +++ b/app/admin/library/crud/stubs/mixins/model/model.stub @@ -0,0 +1,18 @@ + [], + 'edit' => [], + ]; + +} diff --git a/app/admin/library/module/Manage.php b/app/admin/library/module/Manage.php new file mode 100644 index 0000000..2f524cc --- /dev/null +++ b/app/admin/library/module/Manage.php @@ -0,0 +1,971 @@ +setModuleUid($uid); + } + + public function __construct(string $uid) + { + $this->installDir = root_path() . 'modules' . DIRECTORY_SEPARATOR; + $this->backupsDir = $this->installDir . 'backups' . DIRECTORY_SEPARATOR; + if (!is_dir($this->installDir)) { + mkdir($this->installDir, 0755, true); + } + if (!is_dir($this->backupsDir)) { + mkdir($this->backupsDir, 0755, true); + } + + if ($uid) { + $this->setModuleUid($uid); + } + } + + public function getInstallState() + { + if (!is_dir($this->modulesDir)) { + return self::UNINSTALLED; + } + $info = $this->getInfo(); + if ($info && isset($info['state'])) { + return $info['state']; + } + + // 目录已存在,但非正常的模块 + return Filesystem::dirIsEmpty($this->modulesDir) ? self::UNINSTALLED : self::DIRECTORY_OCCUPIED; + } + + /** + * 下载模块文件 + * @return string 已下载文件路径 + * @throws Throwable + */ + public function download(): string + { + $token = request()->param("token/s"); + $version = request()->param('version/s'); + $orderId = request()->param("orderId/d"); + + if (!$orderId) { + throw new Exception('Order not found'); + } + + // 下载 - 系统版本号要求、已安装模块的互斥和依赖检测 + $zipFile = Server::download($this->uid, $this->installDir, [ + 'version' => $version, + 'orderId' => $orderId, + 'nuxtVersion' => Server::getNuxtVersion(), + 'sysVersion' => Config::get('buildadmin.version'), + 'installed' => Server::getInstalledIds($this->installDir), + 'ba-user-token' => $token, + ]); + + // 删除旧版本代码 + Filesystem::delDir($this->modulesDir); + + // 解压 + Filesystem::unzip($zipFile); + + // 删除下载的zip + @unlink($zipFile); + + // 检查是否完整 + $this->checkPackage(); + + // 设置为待安装状态 + $this->setInfo([ + 'state' => self::WAIT_INSTALL, + ]); + + return $zipFile; + } + + /** + * 上传安装 + * @param string $file 已经上传完成的文件 + * @return array 模块的基本信息 + * @throws Throwable + */ + public function upload(string $token, string $file): array + { + $file = Filesystem::fsFit(root_path() . 'public' . $file); + if (!is_file($file)) { + // 包未找到 + throw new Exception('Zip file not found'); + } + + $copyTo = $this->installDir . 'uploadTemp' . date('YmdHis') . '.zip'; + copy($file, $copyTo); + + // 解压 + $copyToDir = Filesystem::unzip($copyTo); + $copyToDir .= DIRECTORY_SEPARATOR; + + // 删除zip + @unlink($file); + @unlink($copyTo); + + // 读取ini + $info = Server::getIni($copyToDir); + if (empty($info['uid'])) { + Filesystem::delDir($copyToDir); + // 基本配置不完整 + throw new Exception('Basic configuration of the Module is incomplete'); + } + + $this->setModuleUid($info['uid']); + + $upgrade = false; + if (is_dir($this->modulesDir)) { + $oldInfo = $this->getInfo(); + if ($oldInfo && !empty($oldInfo['uid'])) { + $versions = explode('.', $oldInfo['version']); + if (isset($versions[2])) { + $versions[2]++; + } + $nextVersion = implode('.', $versions); + $upgrade = Version::compare($nextVersion, $info['version']); + if ($upgrade) { + // 检查模块是否已禁用 + if (!in_array($oldInfo['state'], [self::UNINSTALLED, self::WAIT_INSTALL, self::DISABLE])) { + Filesystem::delDir($copyToDir); + throw new Exception('Please disable the module before updating'); + } + } else { + Filesystem::delDir($copyToDir); + // 模块已经存在 + throw new Exception('Module already exists'); + } + } + + if (!Filesystem::dirIsEmpty($this->modulesDir) && !$upgrade) { + Filesystem::delDir($copyToDir); + // 模块目录被占 + throw new Exception('The directory required by the module is occupied'); + } + } + + // 安装预检 - 系统版本号要求、已安装模块的互斥和依赖检测 + try { + Server::installPreCheck([ + 'uid' => $info['uid'], + 'version' => $info['version'], + 'sysVersion' => Config::get('buildadmin.version'), + 'nuxtVersion' => Server::getNuxtVersion(), + 'moduleVersion' => $info['version'], + 'ba-user-token' => $token, + 'installed' => Server::getInstalledIds($this->installDir), + 'server' => 1, + ]); + } catch (Throwable $e) { + Filesystem::delDir($copyToDir); + throw $e; + } + + $newInfo = ['state' => self::WAIT_INSTALL]; + if ($upgrade) { + $info['update'] = 1; + + // 清理旧版本代码 + Filesystem::delDir($this->modulesDir); + } + + // 放置新模块 + rename($copyToDir, $this->modulesDir); + + // 检查新包是否完整 + $this->checkPackage(); + + // 设置为待安装状态 + $this->setInfo($newInfo); + + return $info; + } + + /** + * 安装模块 + * @return array 模块基本信息 + * @throws Throwable + */ + public function install(bool $update): array + { + $state = $this->getInstallState(); + + if ($update) { + if (!in_array($state, [self::UNINSTALLED, self::WAIT_INSTALL, self::DISABLE])) { + throw new Exception('Please disable the module before updating'); + } + + /** + * self::WAIT_INSTALL=待安装 + * 即本地上传文件进行升级的安装流程,文件上传成功后将被标记为待安装,免去此处的下载 + */ + if ($state == self::UNINSTALLED || $state != self::WAIT_INSTALL) { + $this->download(); + } + } else { + if ($state == self::INSTALLED || $state == self::DIRECTORY_OCCUPIED || $state == self::DISABLE) { + throw new Exception('Module already exists'); + } + + if ($state == self::UNINSTALLED) { + $this->download(); + } + } + + // 导入sql + Server::importSql($this->modulesDir); + + // 如果是更新,先执行更新脚本 + $info = $this->getInfo(); + if ($update) { + $info['update'] = 1; + Server::execEvent($this->uid, 'update'); + } + + // 执行安装脚本 - 排除冲突处理时会重复提交至此的请求 + $extend = request()->post('extend/a', []); + if (!isset($extend['conflictHandle'])) { + Server::execEvent($this->uid, 'install'); + } + + // 启用插件 + $this->enable('install'); + + return $info; + } + + /** + * 卸载 + * @throws Throwable + */ + public function uninstall(): void + { + $info = $this->getInfo(); + if ($info['state'] != self::DISABLE) { + throw new Exception('Please disable the module first', 0, [ + 'uid' => $this->uid, + ]); + } + + // 执行卸载脚本 + Server::execEvent($this->uid, 'uninstall'); + + Filesystem::delDir($this->modulesDir); + } + + /** + * 修改模块状态 + * @param bool $state 新状态 + * @return array 模块基本信息 + * @throws Throwable + */ + public function changeState(bool $state): array + { + $info = $this->getInfo(); + if (!$state) { + $canDisable = [ + self::INSTALLED, + self::CONFLICT_PENDING, + self::DEPENDENT_WAIT_INSTALL, + ]; + if (!in_array($info['state'], $canDisable)) { + throw new Exception('The current state of the module cannot be set to disabled', 0, [ + 'uid' => $this->uid, + 'state' => $info['state'], + ]); + } + return $this->disable(); + } + + if ($info['state'] != self::DISABLE) { + throw new Exception('The current state of the module cannot be set to enabled', 0, [ + 'uid' => $this->uid, + 'state' => $info['state'], + ]); + } + $this->setInfo([ + 'state' => self::WAIT_INSTALL, + ]); + return $info; + } + + /** + * 启用 + * @param string $trigger 触发启用的标志,比如:install=安装 + * @throws Throwable + */ + public function enable(string $trigger): void + { + // 安装 WebBootstrap + Server::installWebBootstrap($this->uid, $this->modulesDir); + + // 建立 .runtime + Server::createRuntime($this->modulesDir); + + // 冲突检查 + $this->conflictHandle($trigger); + + // 执行启用脚本 + Server::execEvent($this->uid, 'enable'); + + $this->dependUpdateHandle(); + } + + /** + * 禁用 + * @return array 模块基本信息 + * @throws Throwable + */ + public function disable(): array + { + $update = request()->post("update/b", false); + $confirmConflict = request()->post("confirmConflict/b", false); + $dependConflictSolution = request()->post("dependConflictSolution/a", []); + + $info = $this->getInfo(); + $zipFile = $this->backupsDir . $this->uid . '-install.zip'; + $zipDir = false; + if (is_file($zipFile)) { + try { + $zipDir = $this->backupsDir . $this->uid . '-install' . DIRECTORY_SEPARATOR; + Filesystem::unzip($zipFile, $zipDir); + } catch (Exception) { + // skip + } + } + + $conflictFile = Server::getFileList($this->modulesDir, true); + $dependConflict = $this->disableDependCheck(); + if (($conflictFile || !self::isEmptyArray($dependConflict)) && !$confirmConflict) { + $dependConflictTemp = []; + foreach ($dependConflict as $env => $item) { + foreach ($item as $depend => $v) { + $dependConflictTemp[] = [ + 'env' => $env, + 'depend' => $depend, + 'dependTitle' => $depend . ' ' . $v, + 'solution' => 'delete', + ]; + } + } + throw new Exception('Module file updated', -1, [ + 'uid' => $this->uid, + 'conflictFile' => $conflictFile, + 'dependConflict' => $dependConflictTemp, + ]); + } + + // 执行禁用脚本 + Server::execEvent($this->uid, 'disable', ['update' => $update]); + + // 是否需要备份依赖? + $delNpmDepend = false; + $delNuxtNpmDepend = false; + $delComposerDepend = false; + foreach ($dependConflictSolution as $env => $depends) { + if (!$depends) continue; + if ($env == 'require' || $env == 'require-dev') { + $delComposerDepend = true; + } elseif ($env == 'dependencies' || $env == 'devDependencies') { + $delNpmDepend = true; + } elseif ($env == 'nuxtDependencies' || $env == 'nuxtDevDependencies') { + $delNuxtNpmDepend = true; + } + } + + // 备份 + $dependJsonFiles = [ + 'composer' => 'composer.json', + 'webPackage' => 'web' . DIRECTORY_SEPARATOR . 'package.json', + 'webNuxtPackage' => 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json', + ]; + $dependWaitInstall = []; + if ($delComposerDepend) { + $conflictFile[] = $dependJsonFiles['composer']; + $dependWaitInstall[] = [ + 'pm' => false, + 'command' => 'composer.update', + 'type' => 'composer_dependent_wait_install', + ]; + } + if ($delNpmDepend) { + $conflictFile[] = $dependJsonFiles['webPackage']; + $dependWaitInstall[] = [ + 'pm' => true, + 'command' => 'web-install', + 'type' => 'npm_dependent_wait_install', + ]; + } + if ($delNuxtNpmDepend) { + $conflictFile[] = $dependJsonFiles['webNuxtPackage']; + $dependWaitInstall[] = [ + 'pm' => true, + 'command' => 'nuxt-install', + 'type' => 'nuxt_npm_dependent_wait_install', + ]; + } + if ($conflictFile) { + // 如果是模块自带文件需要备份,加上模块目录前缀 + $overwriteDir = Server::getOverwriteDir(); + foreach ($conflictFile as $key => $item) { + $paths = explode(DIRECTORY_SEPARATOR, $item); + if (in_array($paths[0], $overwriteDir) || in_array($item, $dependJsonFiles)) { + $conflictFile[$key] = $item; + } else { + $conflictFile[$key] = Filesystem::fsFit(str_replace(root_path(), '', $this->modulesDir . $item)); + } + if (!is_file(root_path() . $conflictFile[$key])) { + unset($conflictFile[$key]); + } + } + $backupsZip = $this->backupsDir . $this->uid . '-disable-' . date('YmdHis') . '.zip'; + Filesystem::zip($conflictFile, $backupsZip); + } + + // 删除依赖 + $serverDepend = new Depends(root_path() . 'composer.json', 'composer'); + $webDep = new Depends(root_path() . 'web' . DIRECTORY_SEPARATOR . 'package.json'); + $webNuxtDep = new Depends(root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json'); + foreach ($dependConflictSolution as $env => $depends) { + if (!$depends) continue; + $dev = !(stripos($env, 'dev') === false); + if ($env == 'require' || $env == 'require-dev') { + $serverDepend->removeDepends($depends, $dev); + } elseif ($env == 'dependencies' || $env == 'devDependencies') { + $webDep->removeDepends($depends, $dev); + } elseif ($env == 'nuxtDependencies' || $env == 'nuxtDevDependencies') { + $webNuxtDep->removeDepends($depends, $dev); + } + } + + // 删除 composer.json 中的 config + $composerConfig = Server::getConfig($this->modulesDir, 'composerConfig'); + if ($composerConfig) { + $serverDepend->removeComposerConfig($composerConfig); + } + + // 配置了不删除的文件 + $protectedFiles = Server::getConfig($this->modulesDir, 'protectedFiles'); + foreach ($protectedFiles as &$protectedFile) { + $protectedFile = Filesystem::fsFit(root_path() . $protectedFile); + } + // 模块文件列表 + $moduleFile = Server::getFileList($this->modulesDir); + + // 删除模块文件 + foreach ($moduleFile as &$file) { + // 纯净模式下,模块文件将被删除,此处直接检查模块目录中是否有该文件并恢复(不检查是否开启纯净模式,因为开关可能被调整) + $moduleFilePath = Filesystem::fsFit($this->modulesDir . $file); + $file = Filesystem::fsFit(root_path() . $file); + if (!file_exists($file)) continue; + if (!file_exists($moduleFilePath)) { + if (!is_dir(dirname($moduleFilePath))) { + mkdir(dirname($moduleFilePath), 0755, true); + } + copy($file, $moduleFilePath); + } + + if (in_array($file, $protectedFiles)) { + continue; + } + if (file_exists($file)) { + unlink($file); + } + Filesystem::delEmptyDir(dirname($file)); + } + + // 恢复备份文件 + if ($zipDir) { + $unrecoverableFiles = [ + Filesystem::fsFit(root_path() . 'composer.json'), + Filesystem::fsFit(root_path() . 'web/package.json'), + Filesystem::fsFit(root_path() . 'web-nuxt/package.json'), + ]; + foreach ( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($zipDir, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST + ) as $item + ) { + $backupsFile = Filesystem::fsFit(root_path() . str_replace($zipDir, '', $item->getPathname())); + + // 在模块包中,同时不在 $protectedFiles 列表的文件不恢复,这些文件可能是模块升级时备份的 + if (in_array($backupsFile, $moduleFile) && !in_array($backupsFile, $protectedFiles)) { + continue; + } + + if ($item->isDir()) { + if (!is_dir($backupsFile)) { + mkdir($backupsFile, 0755, true); + } + } elseif (!in_array($backupsFile, $unrecoverableFiles)) { + copy($item, $backupsFile); + } + } + } + + // 删除解压后的备份文件 + Filesystem::delDir($zipDir); + + // 卸载 WebBootstrap + Server::uninstallWebBootstrap($this->uid); + + $this->setInfo([ + 'state' => self::DISABLE, + ]); + + if ($update) { + throw new Exception('update', -3, [ + 'uid' => $this->uid, + ]); + } + + if ($dependWaitInstall) { + throw new Exception('dependent wait install', -2, [ + 'uid' => $this->uid, + 'wait_install' => $dependWaitInstall, + ]); + } + return $info; + } + + /** + * 处理依赖和文件冲突,并完成与前端的冲突处理交互 + * @throws Throwable + */ + public function conflictHandle(string $trigger): bool + { + $info = $this->getInfo(); + if ($info['state'] != self::WAIT_INSTALL && $info['state'] != self::CONFLICT_PENDING) { + return false; + } + $fileConflict = Server::getFileList($this->modulesDir, true);// 文件冲突 + $dependConflict = Server::dependConflictCheck($this->modulesDir);// 依赖冲突 + $installFiles = Server::getFileList($this->modulesDir);// 待安装文件 + $depends = Server::getDepend($this->modulesDir);// 待安装依赖 + + $coverFiles = [];// 要覆盖的文件-备份 + $discardFiles = [];// 抛弃的文件-复制时不覆盖 + $serverDep = new Depends(root_path() . 'composer.json', 'composer'); + $webDep = new Depends(root_path() . 'web' . DIRECTORY_SEPARATOR . 'package.json'); + $webNuxtDep = new Depends(root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json'); + if ($fileConflict || !self::isEmptyArray($dependConflict)) { + $extend = request()->post('extend/a', []); + if (!$extend) { + // 发现冲突->手动处理->转换为方便前端使用的格式 + $fileConflictTemp = []; + foreach ($fileConflict as $key => $item) { + $fileConflictTemp[$key] = [ + 'newFile' => $this->uid . DIRECTORY_SEPARATOR . $item, + 'oldFile' => $item, + 'solution' => 'cover', + ]; + } + $dependConflictTemp = []; + foreach ($dependConflict as $env => $item) { + $dev = !(stripos($env, 'dev') === false); + foreach ($item as $depend => $v) { + $oldDepend = ''; + if (in_array($env, ['require', 'require-dev'])) { + $oldDepend = $depend . ' ' . $serverDep->hasDepend($depend, $dev); + } elseif (in_array($env, ['dependencies', 'devDependencies'])) { + $oldDepend = $depend . ' ' . $webDep->hasDepend($depend, $dev); + } elseif (in_array($env, ['nuxtDependencies', 'nuxtDevDependencies'])) { + $oldDepend = $depend . ' ' . $webNuxtDep->hasDepend($depend, $dev); + } + $dependConflictTemp[] = [ + 'env' => $env, + 'newDepend' => $depend . ' ' . $v, + 'oldDepend' => $oldDepend, + 'depend' => $depend, + 'solution' => 'cover', + ]; + } + } + $this->setInfo([ + 'state' => self::CONFLICT_PENDING, + ]); + throw new Exception('Module file conflicts', -1, [ + 'fileConflict' => $fileConflictTemp, + 'dependConflict' => $dependConflictTemp, + 'uid' => $this->uid, + 'state' => self::CONFLICT_PENDING, + ]); + } + + // 处理冲突 + if ($fileConflict && isset($extend['fileConflict'])) { + foreach ($installFiles as $ikey => $installFile) { + if (isset($extend['fileConflict'][$installFile])) { + if ($extend['fileConflict'][$installFile] == 'discard') { + $discardFiles[] = $installFile; + unset($installFiles[$ikey]); + } else { + $coverFiles[] = $installFile; + } + } + } + } + if (!self::isEmptyArray($dependConflict) && isset($extend['dependConflict'])) { + foreach ($depends as $fKey => $fItem) { + foreach ($fItem as $cKey => $cItem) { + if (isset($extend['dependConflict'][$fKey][$cKey])) { + if ($extend['dependConflict'][$fKey][$cKey] == 'discard') { + unset($depends[$fKey][$cKey]); + } + } + } + } + } + } + + // 如果有依赖更新,增加要备份的文件 + if ($depends) { + foreach ($depends as $key => $item) { + if (!$item) { + continue; + } + if ($key == 'require' || $key == 'require-dev') { + $coverFiles[] = 'composer.json'; + continue; + } + if ($key == 'dependencies' || $key == 'devDependencies') { + $coverFiles[] = 'web' . DIRECTORY_SEPARATOR . 'package.json'; + } + if ($key == 'nuxtDependencies' || $key == 'nuxtDevDependencies') { + $coverFiles[] = 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json'; + } + } + } + + // 备份将被覆盖的文件 + if ($coverFiles) { + $backupsZip = $trigger == 'install' ? $this->backupsDir . $this->uid . '-install.zip' : $this->backupsDir . $this->uid . '-cover-' . date('YmdHis') . '.zip'; + Filesystem::zip($coverFiles, $backupsZip); + } + + if ($depends) { + $npm = false; + $composer = false; + $nuxtNpm = false; + + // composer config 更新 + $composerConfig = Server::getConfig($this->modulesDir, 'composerConfig'); + if ($composerConfig) { + $serverDep->setComposerConfig($composerConfig); + } + + foreach ($depends as $key => $item) { + if (!$item) { + continue; + } + if ($key == 'require') { + $composer = true; + $serverDep->addDepends($item, false, true); + } elseif ($key == 'require-dev') { + $composer = true; + $serverDep->addDepends($item, true, true); + } elseif ($key == 'dependencies') { + $npm = true; + $webDep->addDepends($item, false, true); + } elseif ($key == 'devDependencies') { + $npm = true; + $webDep->addDepends($item, true, true); + } elseif ($key == 'nuxtDependencies') { + $nuxtNpm = true; + $webNuxtDep->addDepends($item, false, true); + } elseif ($key == 'nuxtDevDependencies') { + $nuxtNpm = true; + $webNuxtDep->addDepends($item, true, true); + } + } + if ($npm) { + $info['npm_dependent_wait_install'] = 1; + $info['state'] = self::DEPENDENT_WAIT_INSTALL; + } + if ($composer) { + $info['composer_dependent_wait_install'] = 1; + $info['state'] = self::DEPENDENT_WAIT_INSTALL; + } + if ($nuxtNpm) { + $info['nuxt_npm_dependent_wait_install'] = 1; + $info['state'] = self::DEPENDENT_WAIT_INSTALL; + } + if ($info['state'] != self::DEPENDENT_WAIT_INSTALL) { + // 无冲突 + $this->setInfo([ + 'state' => self::INSTALLED, + ]); + } else { + $this->setInfo([], $info); + } + } else { + // 无冲突 + $this->setInfo([ + 'state' => self::INSTALLED, + ]); + } + + // 复制文件 + $overwriteDir = Server::getOverwriteDir(); + foreach ($overwriteDir as $dirItem) { + $baseDir = $this->modulesDir . $dirItem; + $destDir = root_path() . $dirItem; + if (!is_dir($baseDir)) { + continue; + } + foreach ( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($baseDir, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST + ) as $item + ) { + $destDirItem = Filesystem::fsFit($destDir . DIRECTORY_SEPARATOR . str_replace($baseDir, '', $item->getPathname())); + if ($item->isDir()) { + Filesystem::mkdir($destDirItem); + } elseif (!in_array(str_replace(root_path(), '', $destDirItem), $discardFiles)) { + Filesystem::mkdir(dirname($destDirItem)); + copy($item, $destDirItem); + } + } + // 纯净模式 + if (Config::get('buildadmin.module_pure_install')) { + Filesystem::delDir($baseDir); + } + } + return true; + } + + /** + * 依赖升级处理 + * @throws Throwable + */ + public function dependUpdateHandle(): void + { + $info = $this->getInfo(); + if ($info['state'] == self::DEPENDENT_WAIT_INSTALL) { + $waitInstall = []; + if (isset($info['composer_dependent_wait_install'])) { + $waitInstall[] = 'composer_dependent_wait_install'; + } + if (isset($info['npm_dependent_wait_install'])) { + $waitInstall[] = 'npm_dependent_wait_install'; + } + if (isset($info['nuxt_npm_dependent_wait_install'])) { + $waitInstall[] = 'nuxt_npm_dependent_wait_install'; + } + if ($waitInstall) { + throw new Exception('dependent wait install', -2, [ + 'uid' => $this->uid, + 'state' => self::DEPENDENT_WAIT_INSTALL, + 'wait_install' => $waitInstall, + ]); + } else { + $this->setInfo([ + 'state' => self::INSTALLED, + ]); + } + } + } + + /** + * 依赖安装完成标记 + * @throws Throwable + */ + public function dependentInstallComplete(string $type): void + { + $info = $this->getInfo(); + if ($info['state'] == self::DEPENDENT_WAIT_INSTALL) { + if ($type == 'npm') { + unset($info['npm_dependent_wait_install']); + } + if ($type == 'nuxt_npm') { + unset($info['nuxt_npm_dependent_wait_install']); + } + if ($type == 'composer') { + unset($info['composer_dependent_wait_install']); + } + if ($type == 'all') { + unset($info['npm_dependent_wait_install'], $info['composer_dependent_wait_install'], $info['nuxt_npm_dependent_wait_install']); + } + if (!isset($info['npm_dependent_wait_install']) && !isset($info['composer_dependent_wait_install']) && !isset($info['nuxt_npm_dependent_wait_install'])) { + $info['state'] = self::INSTALLED; + } + $this->setInfo([], $info); + } + } + + /** + * 禁用依赖检查 + * @throws Throwable + */ + public function disableDependCheck(): array + { + // 读取模块所有依赖 + $depend = Server::getDepend($this->modulesDir); + if (!$depend) { + return []; + } + + // 读取所有依赖中,系统上已经安装的依赖 + $serverDep = new Depends(root_path() . 'composer.json', 'composer'); + $webDep = new Depends(root_path() . 'web' . DIRECTORY_SEPARATOR . 'package.json'); + $webNuxtDep = new Depends(root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json'); + foreach ($depend as $key => $depends) { + $dev = !(stripos($key, 'dev') === false); + if ($key == 'require' || $key == 'require-dev') { + foreach ($depends as $dependKey => $dependItem) { + if (!$serverDep->hasDepend($dependKey, $dev)) { + unset($depends[$dependKey]); + } + } + $depend[$key] = $depends; + } elseif ($key == 'dependencies' || $key == 'devDependencies') { + foreach ($depends as $dependKey => $dependItem) { + if (!$webDep->hasDepend($dependKey, $dev)) { + unset($depends[$dependKey]); + } + } + $depend[$key] = $depends; + } elseif ($key == 'nuxtDependencies' || $key == 'nuxtDevDependencies') { + foreach ($depends as $dependKey => $dependItem) { + if (!$webNuxtDep->hasDepend($dependKey, $dev)) { + unset($depends[$dependKey]); + } + } + $depend[$key] = $depends; + } + } + return $depend; + } + + /** + * 检查包是否完整 + * @throws Throwable + */ + public function checkPackage(): bool + { + if (!is_dir($this->modulesDir)) { + throw new Exception('Module package file does not exist'); + } + $info = $this->getInfo(); + $infoKeys = ['uid', 'title', 'intro', 'author', 'version', 'state']; + foreach ($infoKeys as $value) { + if (!array_key_exists($value, $info)) { + Filesystem::delDir($this->modulesDir); + throw new Exception('Basic configuration of the Module is incomplete'); + } + } + return true; + } + + /** + * 获取模块基本信息 + */ + public function getInfo(): array + { + return Server::getIni($this->modulesDir); + } + + /** + * 设置模块基本信息 + * @throws Throwable + */ + public function setInfo(array $kv = [], array $arr = []): bool + { + if ($kv) { + $info = $this->getInfo(); + foreach ($kv as $k => $v) { + $info[$k] = $v; + } + return Server::setIni($this->modulesDir, $info); + } elseif ($arr) { + return Server::setIni($this->modulesDir, $arr); + } + throw new Exception('Parameter error'); + } + + + /** + * 检查多维数组是否全部为空 + */ + public static function isEmptyArray($arr): bool + { + foreach ($arr as $item) { + if (is_array($item)) { + $empty = self::isEmptyArray($item); + if (!$empty) return false; + } elseif ($item) { + return false; + } + } + return true; + } + + public function setModuleUid(string $uid): static + { + $this->uid = $uid; + $this->modulesDir = $this->installDir . $uid . DIRECTORY_SEPARATOR; + return $this; + } +} \ No newline at end of file diff --git a/app/admin/library/module/Server.php b/app/admin/library/module/Server.php new file mode 100644 index 0000000..d8e7106 --- /dev/null +++ b/app/admin/library/module/Server.php @@ -0,0 +1,590 @@ +get(self::$apiBaseUrl . 'download', ['query' => array_merge(['uid' => $uid, 'server' => 1], $extend)]); + $body = $response->getBody(); + $content = $body->getContents(); + if ($content == '' || stripos($content, '系统发生错误') !== false) { + throw new Exception('package download failed', 0); + } + if (str_starts_with($content, '{')) { + $json = (array)json_decode($content, true); + throw new Exception($json['msg'], $json['code'], $json['data'] ?? []); + } + } catch (TransferException $e) { + throw new Exception('package download failed', 0, ['msg' => $e->getMessage()]); + } + + if ($write = fopen($tmpFile, 'w')) { + fwrite($write, $content); + fclose($write); + return $tmpFile; + } + throw new Exception("No permission to write temporary files"); + } + + /** + * 安装预检 + * @throws Throwable + */ + public static function installPreCheck(array $query = []): bool + { + try { + $client = get_ba_client(); + $response = $client->get(self::$apiBaseUrl . 'preCheck', ['query' => $query]); + $body = $response->getBody(); + $statusCode = $response->getStatusCode(); + $content = $body->getContents(); + if ($content == '' || stripos($content, '系统发生错误') !== false || $statusCode != 200) { + return true; + } + if (str_starts_with($content, '{')) { + $json = json_decode($content, true); + if ($json && $json['code'] == 0) { + throw new Exception($json['msg'], $json['code'], $json['data'] ?? []); + } + } + } catch (TransferException $e) { + throw new Exception('package check failed', 0, ['msg' => $e->getMessage()]); + } + return true; + } + + public static function getConfig(string $dir, $key = ''): array + { + $configFile = $dir . 'config.json'; + if (!is_dir($dir) || !is_file($configFile)) { + return []; + } + $configContent = @file_get_contents($configFile); + $configContent = json_decode($configContent, true); + if (!$configContent) { + return []; + } + if ($key) { + return $configContent[$key] ?? []; + } + return $configContent; + } + + public static function getDepend(string $dir, string $key = ''): array + { + if ($key) { + return self::getConfig($dir, $key); + } + $configContent = self::getConfig($dir); + $dependKey = ['require', 'require-dev', 'dependencies', 'devDependencies', 'nuxtDependencies', 'nuxtDevDependencies']; + $dependArray = []; + foreach ($dependKey as $item) { + if (array_key_exists($item, $configContent) && $configContent[$item]) { + $dependArray[$item] = $configContent[$item]; + } + } + return $dependArray; + } + + /** + * 依赖冲突检查 + * @throws Throwable + */ + public static function dependConflictCheck(string $dir): array + { + $depend = self::getDepend($dir); + $serverDep = new Depends(root_path() . 'composer.json', 'composer'); + $webDep = new Depends(root_path() . 'web' . DIRECTORY_SEPARATOR . 'package.json'); + $webNuxtDep = new Depends(root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR . 'package.json'); + $sysDepend = [ + 'require' => $serverDep->getDepends(), + 'require-dev' => $serverDep->getDepends(true), + 'dependencies' => $webDep->getDepends(), + 'devDependencies' => $webDep->getDepends(true), + 'nuxtDependencies' => $webNuxtDep->getDepends(), + 'nuxtDevDependencies' => $webNuxtDep->getDepends(true), + ]; + + $conflict = []; + foreach ($depend as $key => $item) { + $conflict[$key] = array_uintersect_assoc($item, $sysDepend[$key], function ($a, $b) { + return $a == $b ? -1 : 0; + }); + } + return $conflict; + } + + /** + * 获取模块[冲突]文件列表 + * @param string $dir 模块目录 + * @param bool $onlyConflict 是否只获取冲突文件 + */ + public static function getFileList(string $dir, bool $onlyConflict = false): array + { + if (!is_dir($dir)) { + return []; + } + + $fileList = []; + $overwriteDir = self::getOverwriteDir(); + $moduleFileList = self::getRuntime($dir, 'files'); + + if ($moduleFileList) { + // 有冲突的文件 + if ($onlyConflict) { + // 排除的文件 + $excludeFile = [ + 'info.ini' + ]; + foreach ($moduleFileList as $file) { + // 如果是要安装到项目的文件,从项目根目录开始,如果不是,从模块根目录开始 + $path = Filesystem::fsFit(str_replace($dir, '', $file['path'])); + $paths = explode(DIRECTORY_SEPARATOR, $path); + $overwriteFile = in_array($paths[0], $overwriteDir) ? root_path() . $path : $dir . $path; + if (is_file($overwriteFile) && !in_array($path, $excludeFile) && (filesize($overwriteFile) != $file['size'] || md5_file($overwriteFile) != $file['md5'])) { + $fileList[] = $path; + } + } + } else { + // 要安装的文件 + foreach ($overwriteDir as $item) { + $baseDir = $dir . $item; + foreach ($moduleFileList as $file) { + if (!str_starts_with($file['path'], $baseDir)) continue; + $fileList[] = Filesystem::fsFit(str_replace($dir, '', $file['path'])); + } + } + } + return $fileList; + } + + foreach ($overwriteDir as $item) { + $baseDir = $dir . $item; + if (!is_dir($baseDir)) { + continue; + } + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($baseDir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ($files as $file) { + if ($file->isFile()) { + $filePath = $file->getPathName(); + $path = str_replace($dir, '', $filePath); + $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path); + + if ($onlyConflict) { + $overwriteFile = root_path() . $path; + if (is_file($overwriteFile) && (filesize($overwriteFile) != filesize($filePath) || md5_file($overwriteFile) != md5_file($filePath))) { + $fileList[] = $path; + } + } else { + $fileList[] = $path; + } + } + } + } + return $fileList; + } + + public static function getOverwriteDir(): array + { + return [ + 'app', + 'config', + 'database', + 'extend', + 'modules', + 'public', + 'vendor', + 'web', + 'web-nuxt', + ]; + } + + public static function importSql(string $dir): bool + { + $sqlFile = $dir . 'install.sql'; + $tempLine = ''; + if (is_file($sqlFile)) { + $lines = file($sqlFile); + foreach ($lines as $line) { + if (str_starts_with($line, '--') || $line == '' || str_starts_with($line, '/*')) { + continue; + } + + $tempLine .= $line; + if (str_ends_with(trim($line), ';')) { + $tempLine = str_ireplace('__PREFIX__', Config::get('database.connections.mysql.prefix'), $tempLine); + $tempLine = str_ireplace('INSERT INTO ', 'INSERT IGNORE INTO ', $tempLine); + try { + Db::execute($tempLine); + } catch (PDOException) { + // $e->getMessage(); + } + $tempLine = ''; + } + } + } + return true; + } + + public static function installedList(string $dir): array + { + if (!is_dir($dir)) { + return []; + } + $installedDir = scandir($dir); + $installedList = []; + foreach ($installedDir as $item) { + if ($item === '.' or $item === '..' || is_file($dir . $item)) { + continue; + } + $tempDir = $dir . $item . DIRECTORY_SEPARATOR; + if (!is_dir($tempDir)) { + continue; + } + $info = self::getIni($tempDir); + if (!isset($info['uid'])) { + continue; + } + $installedList[] = $info; + } + return $installedList; + } + + public static function getInstalledIds(string $dir): array + { + $installedIds = []; + $installed = self::installedList($dir); + foreach ($installed as $item) { + $installedIds[] = $item['uid']; + } + return $installedIds; + } + + /** + * 获取模块ini + * @param string $dir 模块目录路径 + */ + public static function getIni(string $dir): array + { + $infoFile = $dir . 'info.ini'; + $info = []; + if (is_file($infoFile)) { + $info = parse_ini_file($infoFile, true, INI_SCANNER_TYPED) ?: []; + if (!$info) return []; + } + return $info; + } + + /** + * 设置模块ini + * @param string $dir 模块目录路径 + * @param array $arr 新的ini数据 + * @return bool + * @throws Throwable + */ + public static function setIni(string $dir, array $arr): bool + { + $infoFile = $dir . 'info.ini'; + $ini = []; + foreach ($arr as $key => $val) { + if (is_array($val)) { + $ini[] = "[$key]"; + foreach ($val as $ikey => $ival) { + $ini[] = "$ikey = $ival"; + } + } else { + $ini[] = "$key = $val"; + } + } + if (!file_put_contents($infoFile, implode("\n", $ini) . "\n", LOCK_EX)) { + throw new Exception("Configuration file has no write permission"); + } + return true; + } + + public static function getClass(string $uid, string $type = 'event', ?string $class = null): string + { + $name = parse_name($uid); + if (!is_null($class) && strpos($class, '.')) { + $class = explode('.', $class); + $class[count($class) - 1] = parse_name(end($class), 1); + $class = implode('\\', $class); + } else { + $class = parse_name(is_null($class) ? $name : $class, 1); + } + $namespace = match ($type) { + 'controller' => '\\modules\\' . $name . '\\controller\\' . $class, + default => '\\modules\\' . $name . '\\' . $class, + }; + return class_exists($namespace) ? $namespace : ''; + } + + public static function execEvent(string $uid, string $event, array $params = []): void + { + $eventClass = self::getClass($uid); + if (class_exists($eventClass)) { + $handle = new $eventClass(); + if (method_exists($eventClass, $event)) { + $handle->$event($params); + } + } + } + + /** + * 分析 WebBootstrap 代码 + */ + public static function analysisWebBootstrap(string $uid, string $dir): array + { + $bootstrapFile = $dir . 'webBootstrap.stub'; + if (!file_exists($bootstrapFile)) return []; + $bootstrapContent = file_get_contents($bootstrapFile); + $pregArr = [ + 'mainTsImport' => '/#main.ts import code start#([\s\S]*?)#main.ts import code end#/i', + 'mainTsStart' => '/#main.ts start code start#([\s\S]*?)#main.ts start code end#/i', + 'appVueImport' => '/#App.vue import code start#([\s\S]*?)#App.vue import code end#/i', + 'appVueOnMounted' => '/#App.vue onMounted code start#([\s\S]*?)#App.vue onMounted code end#/i', + 'nuxtAppVueImport' => '/#web-nuxt\/app.vue import code start#([\s\S]*?)#web-nuxt\/app.vue import code end#/i', + 'nuxtAppVueStart' => '/#web-nuxt\/app.vue start code start#([\s\S]*?)#web-nuxt\/app.vue start code end#/i', + ]; + $codeStrArr = []; + foreach ($pregArr as $key => $item) { + preg_match($item, $bootstrapContent, $matches); + if (isset($matches[1]) && $matches[1]) { + $mainImportCodeArr = array_filter(preg_split('/\r\n|\r|\n/', $matches[1])); + if ($mainImportCodeArr) { + $codeStrArr[$key] = "\n"; + if (count($mainImportCodeArr) == 1) { + foreach ($mainImportCodeArr as $codeItem) { + $codeStrArr[$key] .= $codeItem . self::buildMarkStr('module-line-mark', $uid, $key); + } + } else { + $codeStrArr[$key] .= self::buildMarkStr('module-multi-line-mark-start', $uid, $key); + foreach ($mainImportCodeArr as $codeItem) { + $codeStrArr[$key] .= $codeItem . "\n"; + } + $codeStrArr[$key] .= self::buildMarkStr('module-multi-line-mark-end', $uid, $key); + } + } + } + unset($matches); + } + + return $codeStrArr; + } + + /** + * 安装 WebBootstrap + */ + public static function installWebBootstrap(string $uid, string $dir): void + { + $bootstrapCode = self::analysisWebBootstrap($uid, $dir); + if (!$bootstrapCode) { + return; + } + + $webPath = root_path() . 'web' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR; + $webNuxtPath = root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR; + $filePaths = [ + 'mainTsImport' => $webPath . 'main.ts', + 'mainTsStart' => $webPath . 'main.ts', + 'appVueImport' => $webPath . 'App.vue', + 'appVueOnMounted' => $webPath . 'App.vue', + 'nuxtAppVueImport' => $webNuxtPath . 'app.vue', + 'nuxtAppVueStart' => $webNuxtPath . 'app.vue', + ]; + + $marks = [ + 'mainTsImport' => self::buildMarkStr('import-root-mark'), + 'mainTsStart' => self::buildMarkStr('start-root-mark'), + 'appVueImport' => self::buildMarkStr('import-root-mark'), + 'appVueOnMounted' => self::buildMarkStr('onMounted-root-mark'), + 'nuxtAppVueImport' => self::buildMarkStr('import-root-mark'), + 'nuxtAppVueStart' => self::buildMarkStr('start-root-mark'), + ]; + + foreach ($bootstrapCode as $key => $item) { + if ($item && isset($marks[$key])) { + $content = file_get_contents($filePaths[$key]); + $markPos = stripos($content, $marks[$key]); + if ($markPos && strripos($content, self::buildMarkStr('module-line-mark', $uid, $key)) === false && strripos($content, self::buildMarkStr('module-multi-line-mark-start', $uid, $key)) === false) { + $content = substr_replace($content, $item, $markPos + strlen($marks[$key]), 0); + file_put_contents($filePaths[$key], $content); + } + } + } + } + + /** + * 卸载 WebBootstrap + */ + public static function uninstallWebBootstrap(string $uid): void + { + $webPath = root_path() . 'web' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR; + $webNuxtPath = root_path() . 'web-nuxt' . DIRECTORY_SEPARATOR; + $filePaths = [ + 'mainTsImport' => $webPath . 'main.ts', + 'mainTsStart' => $webPath . 'main.ts', + 'appVueImport' => $webPath . 'App.vue', + 'appVueOnMounted' => $webPath . 'App.vue', + 'nuxtAppVueImport' => $webNuxtPath . 'app.vue', + 'nuxtAppVueStart' => $webNuxtPath . 'app.vue', + ]; + + $marksKey = [ + 'mainTsImport', + 'mainTsStart', + 'appVueImport', + 'appVueOnMounted', + 'nuxtAppVueImport', + 'nuxtAppVueStart', + ]; + + foreach ($marksKey as $item) { + if (!is_file($filePaths[$item])) { + continue; + } + $content = file_get_contents($filePaths[$item]); + $moduleLineMark = self::buildMarkStr('module-line-mark', $uid, $item); + $moduleMultiLineMarkStart = self::buildMarkStr('module-multi-line-mark-start', $uid, $item); + $moduleMultiLineMarkEnd = self::buildMarkStr('module-multi-line-mark-end', $uid, $item); + + // 寻找标记,找到则将其中内容删除 + $moduleLineMarkPos = strripos($content, $moduleLineMark); + if ($moduleLineMarkPos !== false) { + $delStartTemp = explode($moduleLineMark, $content); + $delStartPos = strripos(rtrim($delStartTemp[0], "\n"), "\n"); + $delEndPos = stripos($content, "\n", $moduleLineMarkPos); + $content = substr_replace($content, '', $delStartPos, $delEndPos - $delStartPos); + } + + $moduleMultiLineMarkStartPos = stripos($content, $moduleMultiLineMarkStart); + if ($moduleMultiLineMarkStartPos !== false) { + $moduleMultiLineMarkStartPos--; + $moduleMultiLineMarkEndPos = stripos($content, $moduleMultiLineMarkEnd); + $delLang = ($moduleMultiLineMarkEndPos + strlen($moduleMultiLineMarkEnd)) - $moduleMultiLineMarkStartPos; + $content = substr_replace($content, '', $moduleMultiLineMarkStartPos, $delLang); + } + + if ($moduleLineMarkPos || $moduleMultiLineMarkStartPos) { + file_put_contents($filePaths[$item], $content); + } + } + } + + /** + * 构建 WebBootstrap 需要的各种标记字符串 + * @param string $type + * @param string $uid 模块UID + * @param string $extend 扩展数据 + * @return string + */ + public static function buildMarkStr(string $type, string $uid = '', string $extend = ''): string + { + $nonTabKeys = ['mti', 'avi', 'navi', 'navs']; + $extend = match ($extend) { + 'mainTsImport' => 'mti', + 'mainTsStart' => 'mts', + 'appVueImport' => 'avi', + 'appVueOnMounted' => 'avo', + 'nuxtAppVueImport' => 'navi', + 'nuxtAppVueStart' => 'navs', + default => '', + }; + return match ($type) { + 'import-root-mark' => '// modules import mark, Please do not remove.', + 'start-root-mark' => '// modules start mark, Please do not remove.', + 'onMounted-root-mark' => '// Modules onMounted mark, Please do not remove.', + 'module-line-mark' => ' // Code from module \'' . $uid . "'" . ($extend ? "($extend)" : ''), + 'module-multi-line-mark-start' => (in_array($extend, $nonTabKeys) ? '' : Helper::tab()) . "// Code from module '$uid' start" . ($extend ? "($extend)" : '') . "\n", + 'module-multi-line-mark-end' => (in_array($extend, $nonTabKeys) ? '' : Helper::tab()) . "// Code from module '$uid' end", + default => '', + }; + } + + public static function getNuxtVersion() + { + $nuxtPackageJsonPath = Filesystem::fsFit(root_path() . 'web-nuxt/package.json'); + if (is_file($nuxtPackageJsonPath)) { + $nuxtPackageJson = file_get_contents($nuxtPackageJsonPath); + $nuxtPackageJson = json_decode($nuxtPackageJson, true); + if ($nuxtPackageJson && isset($nuxtPackageJson['version'])) { + return $nuxtPackageJson['version']; + } + } + return false; + } + + /** + * 创建 .runtime + */ + public static function createRuntime(string $dir): void + { + $runtimeFilePath = $dir . '.runtime'; + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::LEAVES_ONLY + ); + $filePaths = []; + foreach ($files as $file) { + if (!$file->isDir()) { + $pathName = $file->getPathName(); + if ($pathName == $runtimeFilePath) continue; + $filePaths[] = [ + 'path' => Filesystem::fsFit($pathName), + 'size' => filesize($pathName), + 'md5' => md5_file($pathName), + ]; + } + } + + file_put_contents($runtimeFilePath, json_encode([ + 'files' => $filePaths, + 'pure' => Config::get('buildadmin.module_pure_install'), + ])); + } + + /** + * 读取 .runtime + */ + public static function getRuntime(string $dir, string $key = ''): mixed + { + $runtimeFilePath = $dir . '.runtime'; + $runtimeContent = @file_get_contents($runtimeFilePath); + $runtimeContentArr = json_decode($runtimeContent, true); + if (!$runtimeContentArr) return []; + + if ($key) { + return $runtimeContentArr[$key] ?? []; + } else { + return $runtimeContentArr; + } + } +} diff --git a/app/admin/library/stubs/backendEntrance.stub b/app/admin/library/stubs/backendEntrance.stub new file mode 100644 index 0000000..7b4b74a --- /dev/null +++ b/app/admin/library/stubs/backendEntrance.stub @@ -0,0 +1,24 @@ + +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +namespace think; + +require __DIR__ . '/../vendor/autoload.php'; + +// 执行HTTP应用并响应 +$http = (new App())->http; + +$response = $http->name('admin')->run(); + +$response->send(); + +$http->end($response); diff --git a/app/admin/library/traits/Backend.php b/app/admin/library/traits/Backend.php new file mode 100644 index 0000000..06c6fbb --- /dev/null +++ b/app/admin/library/traits/Backend.php @@ -0,0 +1,301 @@ +preExcludeFields)) { + $this->preExcludeFields = explode(',', (string)$this->preExcludeFields); + } + + foreach ($this->preExcludeFields as $field) { + if (array_key_exists($field, $params)) { + unset($params[$field]); + } + } + return $params; + } + + /** + * 查看 + * @throws Throwable + */ + public function index(): void + { + if ($this->request->param('select')) { + $this->select(); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->field($this->indexField) + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 添加 + */ + public function add(): void + { + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $data[$this->dataLimitField] = $this->auth->id; + } + + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Added successfully')); + } else { + $this->error(__('No rows were added')); + } + } + + $this->error(__('Parameter error')); + } + + /** + * 编辑 + * @throws Throwable + */ + public function edit(): void + { + $pk = $this->model->getPk(); + $id = $this->request->param($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + $this->error(__('You have no permission')); + } + + if ($this->request->isPost()) { + $data = $this->request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + // 模型验证 + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) $validate->scene('edit'); + $data[$pk] = $row[$pk]; + $validate->check($data); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($result !== false) { + $this->success(__('Update successful')); + } else { + $this->error(__('No rows updated')); + } + } + + $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除 + * @throws Throwable + */ + public function del(): void + { + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $this->request->param('ids/a', []); + $where[] = [$this->model->getPk(), 'in', $ids]; + $data = $this->model->where($where)->select(); + + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $v) { + $count += $v->delete(); + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + if ($count) { + $this->success(__('Deleted successfully')); + } else { + $this->error(__('No rows were deleted')); + } + } + + /** + * 排序 - 增量重排法 + * @throws Throwable + */ + public function sortable(): void + { + $pk = $this->model->getPk(); + $move = $this->request->param('move'); + $target = $this->request->param('target'); + $order = $this->request->param("order/s") ?: $this->defaultSortField; + $direction = $this->request->param('direction'); + + $dataLimitWhere = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $dataLimitWhere[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $moveRow = $this->model->where($dataLimitWhere)->find($move); + $targetRow = $this->model->where($dataLimitWhere)->find($target); + + if ($move == $target || !$moveRow || !$targetRow || !$direction) { + $this->error(__('Record not found')); + } + + // 当前是否以权重字段排序(只检查当前排序和默认排序字段,不检查有序保证字段) + if ($order && is_string($order)) { + $order = explode(',', $order); + $order = [$order[0] => $order[1] ?? 'asc']; + } + if (!array_key_exists($this->weighField, $order)) { + $this->error(__('Please use the %s field to sort before operating', [$this->weighField])); + } + + // 开始增量重排 + $order = $this->queryOrderBuilder(); + $weigh = $targetRow[$this->weighField]; + + // 波及行的权重值向上增加还是向下减少 + if ($order[$this->weighField] == 'desc') { + $updateMethod = $direction == 'up' ? 'dec' : 'inc'; + } else { + $updateMethod = $direction == 'up' ? 'inc' : 'dec'; + } + + // 与目标行权重相同的行 + $weighRowIds = $this->model + ->where($dataLimitWhere) + ->where($this->weighField, $weigh) + ->order($order) + ->column($pk); + $weighRowsCount = count($weighRowIds); + + // 单个 SQL 查询中完成大于目标权重行的修改 + $this->model->where($dataLimitWhere) + ->where($this->weighField, $updateMethod == 'dec' ? '<' : '>', $weigh) + ->whereNotIn($pk, [$moveRow->$pk]) + ->$updateMethod($this->weighField, $weighRowsCount) + ->save(); + + // 遍历与目标行权重相同的行,每出现一行权重值将额外 +1,保证权重相同行的顺序位置不变 + if ($direction == 'down') { + $weighRowIds = array_reverse($weighRowIds); + } + + $moveComplete = 0; + $weighRowIds = implode(',', $weighRowIds); + $weighRows = $this->model->where($dataLimitWhere) + ->where($pk, 'in', $weighRowIds) + ->orderRaw("field($pk,$weighRowIds)") + ->select(); + + // 权重相等行 + foreach ($weighRows as $key => $weighRow) { + // 跳过当前拖动行(相等权重数据之间的拖动时,被拖动行会出现在 $weighRows 内) + if ($moveRow[$pk] == $weighRow[$pk]) { + continue; + } + + if ($updateMethod == 'dec') { + $rowWeighVal = $weighRow[$this->weighField] - $key; + } else { + $rowWeighVal = $weighRow[$this->weighField] + $key; + } + + // 找到了目标行 + if ($weighRow[$pk] == $targetRow[$pk]) { + $moveComplete = 1; + $moveRow[$this->weighField] = $rowWeighVal; + $moveRow->save(); + } + + $rowWeighVal = $updateMethod == 'dec' ? $rowWeighVal - $moveComplete : $rowWeighVal + $moveComplete; + $weighRow[$this->weighField] = $rowWeighVal; + $weighRow->save(); + } + + $this->success(); + } + + /** + * 加载为select(远程下拉选择框)数据,默认还是走$this->index()方法 + * 必要时请在对应控制器类中重写 + */ + public function select(): void + { + + } +} \ No newline at end of file diff --git a/app/admin/middleware.php b/app/admin/middleware.php new file mode 100644 index 0000000..b89787e --- /dev/null +++ b/app/admin/middleware.php @@ -0,0 +1,6 @@ +where('uid', $row['id']) + ->column('group_id'); + } + + public function getGroupNameArrAttr($value, $row): array + { + $groupAccess = Db::name('admin_group_access') + ->where('uid', $row['id']) + ->column('group_id'); + return AdminGroup::whereIn('id', $groupAccess)->column('name'); + } + + public function getAvatarAttr($value): string + { + return full_url($value, false, config('buildadmin.default_avatar')); + } + + public function setAvatarAttr($value): string + { + return $value == full_url('', false, config('buildadmin.default_avatar')) ? '' : $value; + } + + /** + * 重置用户密码 + * @param int|string $uid 管理员ID + * @param string $newPassword 新密码 + * @return int|Admin + */ + public function resetPassword(int|string $uid, string $newPassword): int|Admin + { + return $this->where(['id' => $uid])->update(['password' => hash_password($newPassword), 'salt' => '']); + } +} \ No newline at end of file diff --git a/app/admin/model/AdminGroup.php b/app/admin/model/AdminGroup.php new file mode 100644 index 0000000..15818b8 --- /dev/null +++ b/app/admin/model/AdminGroup.php @@ -0,0 +1,13 @@ +adminLog)) { + $request->adminLog = new static(); + } + return $request->adminLog; + } + + /** + * 设置标题 + * @param string $title + */ + public function setTitle(string $title): void + { + $this->title = $title; + } + + /** + * 设置日志内容 + * @param string|array $data + */ + public function setData(string|array $data): void + { + $this->data = $data; + } + + /** + * 设置忽略的链接正则列表 + * @param array|string $regex + */ + public function setUrlIgnoreRegex(array|string $regex = []): void + { + $regex = is_array($regex) ? $regex : [$regex]; + $this->urlIgnoreRegex = array_merge($this->urlIgnoreRegex, $regex); + } + + /** + * 设置需要进行数据脱敏的正则列表 + * @param array|string $regex + */ + public function setDesensitizationRegex(array|string $regex = []): void + { + $regex = is_array($regex) ? $regex : [$regex]; + $this->desensitizationRegex = array_merge($this->desensitizationRegex, $regex); + } + + /** + * 数据脱敏(只数组,根据数组 key 脱敏) + * @param array|string $data + * @return array|string + */ + protected function desensitization(array|string $data): array|string + { + if (!is_array($data) || !$this->desensitizationRegex) { + return $data; + } + foreach ($data as $index => &$item) { + foreach ($this->desensitizationRegex as $reg) { + if (preg_match($reg, $index)) { + $item = "***"; + } elseif (is_array($item)) { + $item = $this->desensitization($item); + } + } + } + return $data; + } + + /** + * 写入日志 + * @param string $title + * @param string|array|null $data + * @throws Throwable + */ + public function record(string $title = '', string|array|null $data = null): void + { + $auth = Auth::instance(); + $adminId = $auth->isLogin() ? $auth->id : 0; + $username = $auth->isLogin() ? $auth->username : request()->param('username', __('Unknown')); + + $controller = str_replace('.', '/', request()->controller(true)); + $action = request()->action(true); + $path = $controller . '/' . $action; + if ($this->urlIgnoreRegex) { + foreach ($this->urlIgnoreRegex as $item) { + if (preg_match($item, $path)) { + return; + } + } + } + $data = $data ?: $this->data; + if (!$data) { + $data = request()->param('', null, 'trim,strip_tags,htmlspecialchars'); + } + $data = $this->desensitization($data); + $title = $title ?: $this->title; + if (!$title) { + $controllerTitle = AdminRule::where('name', $controller)->value('title'); + $title = AdminRule::where('name', $path)->value('title'); + $title = $title ?: __('Unknown') . '(' . $action . ')'; + $title = $controllerTitle ? ($controllerTitle . '-' . $title) : $title; + } + self::create([ + 'admin_id' => $adminId, + 'username' => $username, + 'url' => substr(request()->url(), 0, 1500), + 'title' => $title, + 'data' => !is_scalar($data) ? json_encode($data) : $data, + 'ip' => request()->ip(), + 'useragent' => substr(request()->server('HTTP_USER_AGENT'), 0, 255), + ]); + } + + public function admin(): BelongsTo + { + return $this->belongsTo(Admin::class); + } +} \ No newline at end of file diff --git a/app/admin/model/AdminRule.php b/app/admin/model/AdminRule.php new file mode 100644 index 0000000..62c9fc4 --- /dev/null +++ b/app/admin/model/AdminRule.php @@ -0,0 +1,21 @@ +getData('type'), $model->needContent)) { + $model->content = null; + } else { + $model->content = json_encode(str_attr_to_array($model->getData('content'))); + } + if (is_array($model->rule)) { + $model->rule = implode(',', $model->rule); + } + if ($model->getData('extend') || $model->getData('inputExtend')) { + $extend = str_attr_to_array($model->getData('extend')); + $inputExtend = str_attr_to_array($model->getData('inputExtend')); + if ($inputExtend) $extend['baInputExtend'] = $inputExtend; + if ($extend) $model->extend = json_encode($extend); + } + $model->allow_del = 1; + } + + /** + * 写入后 + */ + public static function onAfterWrite(): void + { + // 清理配置缓存 + Cache::tag(self::$cacheTag)->clear(); + } + + public function getValueAttr($value, $row) + { + if (!isset($row['type']) || $value == '0') return $value; + if (in_array($row['type'], $this->jsonDecodeType)) { + return empty($value) ? [] : json_decode($value, true); + } elseif ($row['type'] == 'switch') { + return (bool)$value; + } elseif ($row['type'] == 'editor') { + return !$value ? '' : htmlspecialchars_decode($value); + } elseif (in_array($row['type'], ['city', 'remoteSelects'])) { + if (!$value) return []; + if (!is_array($value)) return explode(',', $value); + return $value; + } else { + return $value ?: ''; + } + } + + public function setValueAttr(mixed $value, $row): mixed + { + if (in_array($row['type'], $this->jsonDecodeType)) { + return $value ? json_encode($value) : ''; + } elseif ($row['type'] == 'switch') { + return $value ? '1' : '0'; + } elseif ($row['type'] == 'time') { + return $value ? date('H:i:s', strtotime($value)) : ''; + } elseif ($row['type'] == 'city') { + if ($value && is_array($value)) { + return implode(',', $value); + } + return $value ?: ''; + } elseif (is_array($value)) { + return implode(',', $value); + } + + return $value; + } + + public function getContentAttr($value, $row) + { + if (!isset($row['type'])) return ''; + if (in_array($row['type'], $this->needContent)) { + $arr = json_decode($value, true); + return $arr ?: []; + } else { + return ''; + } + } + + public function getExtendAttr($value) + { + if ($value) { + $arr = json_decode($value, true); + if ($arr) { + unset($arr['baInputExtend']); + return $arr; + } + } + return []; + } + + public function getInputExtendAttr($value, $row) + { + if ($row && $row['extend']) { + $arr = json_decode($row['extend'], true); + if ($arr && isset($arr['baInputExtend'])) { + return $arr['baInputExtend']; + } + } + return []; + } +} \ No newline at end of file diff --git a/app/admin/model/CrudLog.php b/app/admin/model/CrudLog.php new file mode 100644 index 0000000..ac18233 --- /dev/null +++ b/app/admin/model/CrudLog.php @@ -0,0 +1,24 @@ + 'array', + 'fields' => 'array', + ]; + +} \ No newline at end of file diff --git a/app/admin/model/DataRecycle.php b/app/admin/model/DataRecycle.php new file mode 100644 index 0000000..4770890 --- /dev/null +++ b/app/admin/model/DataRecycle.php @@ -0,0 +1,15 @@ +belongsTo(DataRecycle::class, 'recycle_id'); + } + + public function admin(): BelongsTo + { + return $this->belongsTo(Admin::class, 'admin_id'); + } +} \ No newline at end of file diff --git a/app/admin/model/SensitiveData.php b/app/admin/model/SensitiveData.php new file mode 100644 index 0000000..5bf6aeb --- /dev/null +++ b/app/admin/model/SensitiveData.php @@ -0,0 +1,19 @@ + 'array', + ]; +} \ No newline at end of file diff --git a/app/admin/model/SensitiveDataLog.php b/app/admin/model/SensitiveDataLog.php new file mode 100644 index 0000000..e6d4ecf --- /dev/null +++ b/app/admin/model/SensitiveDataLog.php @@ -0,0 +1,27 @@ +belongsTo(SensitiveData::class, 'sensitive_id'); + } + + public function admin(): BelongsTo + { + return $this->belongsTo(Admin::class, 'admin_id'); + } +} \ No newline at end of file diff --git a/app/admin/model/User.php b/app/admin/model/User.php new file mode 100644 index 0000000..6a4846d --- /dev/null +++ b/app/admin/model/User.php @@ -0,0 +1,52 @@ +belongsTo(UserGroup::class, 'group_id'); + } + + /** + * 重置用户密码 + * @param int|string $uid 用户ID + * @param string $newPassword 新密码 + * @return int|User + */ + public function resetPassword(int|string $uid, string $newPassword): int|User + { + return $this->where(['id' => $uid])->update(['password' => hash_password($newPassword), 'salt' => '']); + } +} \ No newline at end of file diff --git a/app/admin/model/UserGroup.php b/app/admin/model/UserGroup.php new file mode 100644 index 0000000..27f4168 --- /dev/null +++ b/app/admin/model/UserGroup.php @@ -0,0 +1,13 @@ +user_id)->lock(true)->find(); + if (!$user) { + throw new Exception("The user can't find it"); + } + if (!$model->memo) { + throw new Exception("Change note cannot be blank"); + } + $model->before = $user->money; + + $user->money += $model->money; + $user->save(); + + $model->after = $user->money; + } + + public static function onBeforeDelete(): bool + { + return false; + } + + public function getMoneyAttr($value): string + { + return bcdiv($value, 100, 2); + } + + public function setMoneyAttr($value): string + { + return bcmul($value, 100, 2); + } + + public function getBeforeAttr($value): string + { + return bcdiv($value, 100, 2); + } + + public function setBeforeAttr($value): string + { + return bcmul($value, 100, 2); + } + + public function getAfterAttr($value): string + { + return bcdiv($value, 100, 2); + } + + public function setAfterAttr($value): string + { + return bcmul($value, 100, 2); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class, 'user_id'); + } +} \ No newline at end of file diff --git a/app/admin/model/UserRule.php b/app/admin/model/UserRule.php new file mode 100644 index 0000000..798c4ec --- /dev/null +++ b/app/admin/model/UserRule.php @@ -0,0 +1,26 @@ +getPk(); + $model->where($pk, $model[$pk])->update(['weigh' => $model[$pk]]); + } + + public function setComponentAttr($value) + { + if ($value) $value = str_replace('\\', '/', $value); + return $value; + } +} \ No newline at end of file diff --git a/app/admin/model/UserScoreLog.php b/app/admin/model/UserScoreLog.php new file mode 100644 index 0000000..770bcf4 --- /dev/null +++ b/app/admin/model/UserScoreLog.php @@ -0,0 +1,50 @@ +user_id)->lock(true)->find(); + if (!$user) { + throw new Exception("The user can't find it"); + } + if (!$model->memo) { + throw new Exception("Change note cannot be blank"); + } + $model->before = $user->score; + + $user->score += $model->score; + $user->save(); + + $model->after = $user->score; + } + + public static function onBeforeDelete(): bool + { + return false; + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class, 'user_id'); + } +} \ No newline at end of file diff --git a/app/admin/validate/Admin.php b/app/admin/validate/Admin.php new file mode 100644 index 0000000..6bd2e29 --- /dev/null +++ b/app/admin/validate/Admin.php @@ -0,0 +1,73 @@ + 'require|regex:^[a-zA-Z][a-zA-Z0-9_]{2,15}$|unique:admin', + 'nickname' => 'require', + 'password' => 'require|regex:^(?!.*[&<>"\'\n\r]).{6,32}$', + 'email' => 'email|unique:admin', + 'mobile' => 'mobile|unique:admin', + 'group_arr' => 'require|array', + ]; + + /** + * 验证提示信息 + * @var array + */ + protected $message = []; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => ['username', 'nickname', 'password', 'email', 'mobile', 'group_arr'], + ]; + + /** + * 验证场景-前台自己修改自己资料 + */ + public function sceneInfo(): Admin + { + return $this->only(['nickname', 'password', 'email', 'mobile']) + ->remove('password', 'require'); + } + + /** + * 验证场景-编辑资料 + */ + public function sceneEdit(): Admin + { + return $this->only(['username', 'nickname', 'password', 'email', 'mobile', 'group_arr']) + ->remove('password', 'require'); + } + + public function __construct() + { + $this->field = [ + 'username' => __('Username'), + 'nickname' => __('Nickname'), + 'password' => __('Password'), + 'email' => __('Email'), + 'mobile' => __('Mobile'), + 'group_arr' => __('Group Name Arr'), + ]; + $this->message = array_merge($this->message, [ + 'username.regex' => __('Please input correct username'), + 'password.regex' => __('Please input correct password') + ]); + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/admin/validate/AdminGroup.php b/app/admin/validate/AdminGroup.php new file mode 100644 index 0000000..936ec2e --- /dev/null +++ b/app/admin/validate/AdminGroup.php @@ -0,0 +1,46 @@ + 'require', + 'rules' => 'require', + ]; + + /** + * 验证提示信息 + * @var array + */ + protected $message = []; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => ['name', 'rules'], + 'edit' => ['name', 'rules'], + ]; + + public function __construct() + { + $this->field = [ + 'name' => __('name'), + ]; + $this->message = [ + 'rules' => __('Please select rules'), + ]; + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/admin/validate/AdminRule.php b/app/admin/validate/AdminRule.php new file mode 100644 index 0000000..5abd477 --- /dev/null +++ b/app/admin/validate/AdminRule.php @@ -0,0 +1,46 @@ + 'require', + 'title' => 'require', + 'name' => 'require|unique:admin_rule', + ]; + + /** + * 验证提示信息 + * @var array + */ + protected $message = []; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => ['type', 'title', 'name'], + 'edit' => ['type', 'title', 'name'], + ]; + + public function __construct() + { + $this->field = [ + 'type' => __('type'), + 'title' => __('title'), + 'name' => __('name'), + ]; + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/admin/validate/Config.php b/app/admin/validate/Config.php new file mode 100644 index 0000000..63bb00c --- /dev/null +++ b/app/admin/validate/Config.php @@ -0,0 +1,41 @@ + 'require|unique:config', + ]; + + /** + * 验证提示信息 + * @var array + */ + protected $message = []; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => ['name'], + ]; + + public function __construct() + { + $this->field = [ + 'name' => __('Variable name'), + ]; + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/admin/validate/DataRecycle.php b/app/admin/validate/DataRecycle.php new file mode 100644 index 0000000..822285f --- /dev/null +++ b/app/admin/validate/DataRecycle.php @@ -0,0 +1,48 @@ + 'require', + 'controller' => 'require|unique:security_data_recycle', + 'data_table' => 'require', + 'primary_key' => 'require', + ]; + + /** + * 验证提示信息 + * @var array + */ + protected $message = []; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => ['name', 'controller', 'data_table', 'primary_key'], + 'edit' => ['name', 'controller', 'data_table', 'primary_key'], + ]; + + public function __construct() + { + $this->field = [ + 'name' => __('Name'), + 'controller' => __('Controller'), + 'data_table' => __('Data Table'), + 'primary_key' => __('Primary Key'), + ]; + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/admin/validate/SensitiveData.php b/app/admin/validate/SensitiveData.php new file mode 100644 index 0000000..10bf627 --- /dev/null +++ b/app/admin/validate/SensitiveData.php @@ -0,0 +1,50 @@ + 'require', + 'controller' => 'require|unique:security_sensitive_data', + 'data_table' => 'require', + 'primary_key' => 'require', + 'data_fields' => 'require', + ]; + + /** + * 验证提示信息 + * @var array + */ + protected $message = []; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => ['name', 'data_fields', 'controller', 'data_table', 'primary_key'], + 'edit' => ['name', 'data_fields', 'controller', 'data_table', 'primary_key'], + ]; + + public function __construct() + { + $this->field = [ + 'name' => __('Name'), + 'data_fields' => __('Data Fields'), + 'controller' => __('Controller'), + 'data_table' => __('Data Table'), + 'primary_key' => __('Primary Key'), + ]; + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/admin/validate/UserMoneyLog.php b/app/admin/validate/UserMoneyLog.php new file mode 100644 index 0000000..76bc080 --- /dev/null +++ b/app/admin/validate/UserMoneyLog.php @@ -0,0 +1,46 @@ + 'require', + 'money' => 'require', + 'memo' => 'require', + ]; + + /** + * 验证提示信息 + * @var array + */ + protected $message = []; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => ['user_id', 'money', 'memo'], + 'edit' => ['user_id', 'money', 'memo'], + ]; + + public function __construct() + { + $this->field = [ + 'user_id' => __('user_id'), + 'money' => __('money'), + 'memo' => __('memo'), + ]; + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/admin/validate/UserScoreLog.php b/app/admin/validate/UserScoreLog.php new file mode 100644 index 0000000..678d87a --- /dev/null +++ b/app/admin/validate/UserScoreLog.php @@ -0,0 +1,46 @@ + 'require', + 'score' => 'require', + 'memo' => 'require', + ]; + + /** + * 验证提示信息 + * @var array + */ + protected $message = []; + + /** + * 字段描述 + */ + protected $field = [ + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'add' => ['user_id', 'score', 'memo'], + 'edit' => ['user_id', 'score', 'memo'], + ]; + + public function __construct() + { + $this->field = [ + 'user_id' => __('user_id'), + 'score' => __('score'), + 'memo' => __('memo'), + ]; + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/api/common.php b/app/api/common.php new file mode 100644 index 0000000..de848d5 --- /dev/null +++ b/app/api/common.php @@ -0,0 +1,38 @@ +auth->id) + ->where('create_time', 'BETWEEN', $tempToday0 . ',' . $tempToday24) + ->sum('score'); + + $userMoneyTemp = UserMoneyLog::where('user_id', $this->auth->id) + ->where('create_time', 'BETWEEN', $tempToday0 . ',' . $tempToday24) + ->sum('money'); + $money[$i] = bcdiv($userMoneyTemp, 100, 2); + } + + $this->success('', [ + 'days' => $days, + 'score' => $score, + 'money' => $money, + ]); + } + + /** + * 会员资料 + * @throws Throwable + */ + public function profile(): void + { + if ($this->request->isPost()) { + $model = $this->auth->getUser(); + $data = $this->request->only(['avatar', 'username', 'nickname', 'gender', 'birthday', 'motto']); + + $data['id'] = $this->auth->id; + if (!isset($data['birthday'])) { + $data['birthday'] = null; + } + + try { + $validate = new AccountValidate(); + $validate->scene('edit')->check($data); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + $model->startTrans(); + try { + $model->save($data); + $model->commit(); + } catch (Throwable $e) { + $model->rollback(); + $this->error($e->getMessage()); + } + + $this->success(__('Data updated successfully~')); + } + + $this->success('', [ + 'accountVerificationType' => get_account_verification_type() + ]); + } + + /** + * 通过手机号或邮箱验证账户 + * 此处检查的验证码是通过 api/Ems或api/Sms发送的 + * 验证成功后,向前端返回一个 email-pass Token或着 mobile-pass Token + * 在 changBind 方法中,通过 pass Token来确定用户已经通过了账户验证(用户未绑定邮箱/手机时通过账户密码验证) + * @throws Throwable + */ + public function verification(): void + { + $captcha = new Captcha(); + $params = $this->request->only(['type', 'captcha']); + if ($captcha->check($params['captcha'], ($params['type'] == 'email' ? $this->auth->email : $this->auth->mobile) . "user_{$params['type']}_verify")) { + $uuid = Random::uuid(); + Token::set($uuid, $params['type'] . '-pass', $this->auth->id, 600); + $this->success('', [ + 'type' => $params['type'], + 'accountVerificationToken' => $uuid, + ]); + } + $this->error(__('Please enter the correct verification code')); + } + + /** + * 修改绑定信息(手机号、邮箱) + * 通过 pass Token来确定用户已经通过了账户验证,也就是以上的 verification 方法,同时用户未绑定邮箱/手机时通过账户密码验证 + * @throws Throwable + */ + public function changeBind(): void + { + $captcha = new Captcha(); + $params = $this->request->only(['type', 'captcha', 'email', 'mobile', 'accountVerificationToken', 'password']); + $user = $this->auth->getUser(); + + if ($user[$params['type']]) { + if (!Token::check($params['accountVerificationToken'], $params['type'] . '-pass', $user->id)) { + $this->error(__('You need to verify your account before modifying the binding information')); + } + } elseif (!isset($params['password']) || !verify_password($params['password'], $user->password, ['salt' => $user->salt])) { + $this->error(__('Password error')); + } + + // 检查验证码 + if ($captcha->check($params['captcha'], $params[$params['type']] . "user_change_{$params['type']}")) { + if ($params['type'] == 'email') { + $validate = Validate::rule(['email' => 'require|email|unique:user'])->message([ + 'email.require' => 'email format error', + 'email.email' => 'email format error', + 'email.unique' => 'email is occupied', + ]); + if (!$validate->check(['email' => $params['email']])) { + $this->error(__($validate->getError())); + } + $user->email = $params['email']; + } elseif ($params['type'] == 'mobile') { + $validate = Validate::rule(['mobile' => 'require|mobile|unique:user'])->message([ + 'mobile.require' => 'mobile format error', + 'mobile.mobile' => 'mobile format error', + 'mobile.unique' => 'mobile is occupied', + ]); + if (!$validate->check(['mobile' => $params['mobile']])) { + $this->error(__($validate->getError())); + } + $user->mobile = $params['mobile']; + } + Token::delete($params['accountVerificationToken']); + $user->save(); + $this->success(); + } + $this->error(__('Please enter the correct verification code')); + } + + public function changePassword(): void + { + if ($this->request->isPost()) { + $model = $this->auth->getUser(); + $params = $this->request->only(['oldPassword', 'newPassword']); + + if (!verify_password($params['oldPassword'], $model->password, ['salt' => $model->salt])) { + $this->error(__('Old password error')); + } + + $model->startTrans(); + try { + $validate = new AccountValidate(); + $validate->scene('changePassword')->check(['password' => $params['newPassword']]); + $model->resetPassword($this->auth->id, $params['newPassword']); + $model->commit(); + } catch (Throwable $e) { + $model->rollback(); + $this->error($e->getMessage()); + } + + $this->auth->logout(); + $this->success(__('Password has been changed, please login again~')); + } + } + + /** + * 积分日志 + * @throws Throwable + */ + public function integral(): void + { + $limit = $this->request->request('limit'); + $integralModel = new UserScoreLog(); + $res = $integralModel->where('user_id', $this->auth->id) + ->order('create_time desc') + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + ]); + } + + /** + * 余额日志 + * @throws Throwable + */ + public function balance(): void + { + $limit = $this->request->request('limit'); + $moneyModel = new UserMoneyLog(); + $res = $moneyModel->where('user_id', $this->auth->id) + ->order('create_time desc') + ->paginate($limit); + + $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + ]); + } + + /** + * 找回密码 + * @throws Throwable + */ + public function retrievePassword(): void + { + $params = $this->request->only(['type', 'account', 'captcha', 'password']); + try { + $validate = new AccountValidate(); + $validate->scene('retrievePassword')->check($params); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + if ($params['type'] == 'email') { + $user = User::where('email', $params['account'])->find(); + } else { + $user = User::where('mobile', $params['account'])->find(); + } + if (!$user) { + $this->error(__('Account does not exist~')); + } + + $captchaObj = new Captcha(); + if (!$captchaObj->check($params['captcha'], $params['account'] . 'user_retrieve_pwd')) { + $this->error(__('Please enter the correct verification code')); + } + + if ($user->resetPassword($user->id, $params['password'])) { + $this->success(__('Password has been changed~')); + } else { + $this->error(__('Failed to modify password, please try again later~')); + } + } +} \ No newline at end of file diff --git a/app/api/controller/Ajax.php b/app/api/controller/Ajax.php new file mode 100644 index 0000000..e7f2a6a --- /dev/null +++ b/app/api/controller/Ajax.php @@ -0,0 +1,59 @@ +request->file('file'); + $driver = $this->request->param('driver', 'local'); + $topic = $this->request->param('topic', 'default'); + try { + $upload = new Upload(); + $attachment = $upload + ->setFile($file) + ->setDriver($driver) + ->setTopic($topic) + ->upload(null, 0, $this->auth->id); + unset($attachment['create_time'], $attachment['quote']); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + $this->success(__('File uploaded successfully'), [ + 'file' => $attachment ?? [] + ]); + } + + /** + * 省份地区数据 + * @throws Throwable + */ + public function area(): void + { + $this->success('', get_area()); + } + + public function buildSuffixSvg(): Response + { + $suffix = $this->request->param('suffix', 'file'); + $background = $this->request->param('background'); + $content = build_suffix_svg((string)$suffix, (string)$background); + return response($content, 200, ['Content-Length' => strlen($content)])->contentType('image/svg+xml'); + } +} \ No newline at end of file diff --git a/app/api/controller/Common.php b/app/api/controller/Common.php new file mode 100644 index 0000000..cc28882 --- /dev/null +++ b/app/api/controller/Common.php @@ -0,0 +1,92 @@ +request->request('id'); + $config = array( + 'codeSet' => '123456789', // 验证码字符集合 + 'fontSize' => 22, // 验证码字体大小(px) + 'useCurve' => false, // 是否画混淆曲线 + 'useNoise' => true, // 是否添加杂点 + 'length' => 4, // 验证码位数 + 'bg' => array(255, 255, 255), // 背景颜色 + ); + + $captcha = new Captcha($config); + return $captcha->entry($captchaId); + } + + /** + * 点选验证码 + */ + public function clickCaptcha(): void + { + $id = $this->request->request('id/s'); + $captcha = new ClickCaptcha(); + $this->success('', $captcha->creat($id)); + } + + /** + * 点选验证码检查 + * @throws Throwable + */ + public function checkClickCaptcha(): void + { + $id = $this->request->post('id/s'); + $info = $this->request->post('info/s'); + $unset = $this->request->post('unset/b', false); + $captcha = new ClickCaptcha(); + if ($captcha->check($id, $info, $unset)) $this->success(); + $this->error(); + } + + /** + * 刷新 token + * 无需主动删除原 token,由 token 驱动自行实现过期 token 清理,可避免并发场景下无法获取到过期 token 数据 + */ + public function refreshToken(): void + { + $refreshToken = $this->request->post('refreshToken'); + $refreshToken = Token::get($refreshToken); + + if (!$refreshToken || $refreshToken['expire_time'] < time()) { + $this->error(__('Login expired, please login again.')); + } + + $newToken = Random::uuid(); + + // 管理员token刷新 + if ($refreshToken['type'] == AdminAuth::TOKEN_TYPE . '-refresh') { + Token::set($newToken, AdminAuth::TOKEN_TYPE, $refreshToken['user_id'], (int)Config::get('buildadmin.admin_token_keep_time')); + } + + // 会员token刷新 + if ($refreshToken['type'] == UserAuth::TOKEN_TYPE . '-refresh') { + Token::set($newToken, UserAuth::TOKEN_TYPE, $refreshToken['user_id'], (int)Config::get('buildadmin.user_token_keep_time')); + } + + $this->success('', [ + 'type' => $refreshToken['type'], + 'token' => $newToken + ]); + } +} \ No newline at end of file diff --git a/app/api/controller/Ems.php b/app/api/controller/Ems.php new file mode 100644 index 0000000..e02b4f5 --- /dev/null +++ b/app/api/controller/Ems.php @@ -0,0 +1,108 @@ +request->post(['email', 'event', 'captchaId', 'captchaInfo']); + $mail = new Email(); + if (!$mail->configured) { + $this->error(__('Mail sending service unavailable')); + } + + $validate = Validate::rule([ + 'email' => 'require|email', + 'event' => 'require', + 'captchaId' => 'require', + 'captchaInfo' => 'require' + ])->message([ + 'email' => 'email format error', + 'event' => 'Parameter error', + 'captchaId' => 'Captcha error', + 'captchaInfo' => 'Captcha error' + ]); + if (!$validate->check($params)) { + $this->error(__($validate->getError())); + } + + // 检查验证码 + $captchaObj = new Captcha(); + $clickCaptcha = new ClickCaptcha(); + if (!$clickCaptcha->check($params['captchaId'], $params['captchaInfo'])) { + $this->error(__('Captcha error')); + } + + // 检查频繁发送 + $captcha = $captchaObj->getCaptchaData($params['email'] . $params['event']); + if ($captcha && time() - $captcha['create_time'] < 60) { + $this->error(__('Frequent email sending')); + } + + // 检查邮箱 + $userInfo = User::where('email', $params['email'])->find(); + if ($params['event'] == 'user_register' && $userInfo) { + $this->error(__('Email has been registered, please log in directly')); + } elseif ($params['event'] == 'user_change_email' && $userInfo) { + $this->error(__('The email has been occupied')); + } elseif (in_array($params['event'], ['user_retrieve_pwd', 'user_email_verify']) && !$userInfo) { + $this->error(__('Email not registered')); + } + + // 通过邮箱验证账户 + if ($params['event'] == 'user_email_verify') { + if (!$this->auth->isLogin()) { + $this->error(__('Please login first')); + } + if ($this->auth->email != $params['email']) { + $this->error(__('Please use the account registration email to send the verification code')); + } + // 验证账户密码 + $password = $this->request->post('password'); + if (!verify_password($password, $this->auth->password, ['salt' => $this->auth->salt])) { + $this->error(__('Password error')); + } + } + + // 生成一个验证码 + $code = $captchaObj->create($params['email'] . $params['event']); + $subject = __($params['event']) . '-' . get_sys_config('site_name'); + $body = __('Your verification code is: %s', [$code]); + + try { + $mail->isSMTP(); + $mail->addAddress($params['email']); + $mail->isHTML(); + $mail->setSubject($subject); + $mail->Body = $body; + $mail->send(); + } catch (PHPMailerException) { + $this->error($mail->ErrorInfo); + } + + $this->success(__('Mail sent successfully~')); + } +} \ No newline at end of file diff --git a/app/api/controller/Index.php b/app/api/controller/Index.php new file mode 100644 index 0000000..427d9b2 --- /dev/null +++ b/app/api/controller/Index.php @@ -0,0 +1,84 @@ +auth->isLogin()) { + $rules = []; + $userMenus = $this->auth->getMenus(); + + // 首页加载的规则,验权,但过滤掉会员中心菜单 + foreach ($userMenus as $item) { + if ($item['type'] == 'menu_dir') { + $menus[] = $item; + } elseif ($item['type'] != 'menu') { + $rules[] = $item; + } + } + $rules = array_values($rules); + } else { + // 若是从前台会员中心内发出的请求,要求必须登录,否则会员中心异常 + $requiredLogin = $this->request->get('requiredLogin/b', false); + if ($requiredLogin) { + + // 触发可能的 token 过期异常 + try { + $token = get_auth_token(['ba', 'user', 'token']); + $this->auth->init($token); + } catch (TokenExpirationException) { + $this->error(__('Token expiration'), [], 409); + } + + $this->error(__('Please login first'), [ + 'type' => $this->auth::NEED_LOGIN + ], $this->auth::LOGIN_RESPONSE_CODE); + } + + $rules = Db::name('user_rule') + ->where('status', 1) + ->where('no_login_valid', 1) + ->where('type', 'in', ['route', 'nav', 'button']) + ->order('weigh', 'desc') + ->select() + ->toArray(); + $rules = Tree::instance()->assembleChild($rules); + } + + $this->success('', [ + 'site' => [ + 'siteName' => get_sys_config('site_name'), + 'version' => get_sys_config('version'), + 'cdnUrl' => full_url(), + 'upload' => keys_to_camel_case(get_upload_config(), ['max_size', 'save_name', 'allowed_suffixes', 'allowed_mime_types']), + 'recordNumber' => get_sys_config('record_number'), + 'cdnUrlParams' => Config::get('buildadmin.cdn_url_params'), + ], + 'openMemberCenter' => Config::get('buildadmin.open_member_center'), + 'userInfo' => $this->auth->getUserInfo(), + 'rules' => $rules, + 'menus' => $menus, + ]); + } +} \ No newline at end of file diff --git a/app/api/controller/Install.php b/app/api/controller/Install.php new file mode 100644 index 0000000..9100230 --- /dev/null +++ b/app/api/controller/Install.php @@ -0,0 +1,671 @@ + '8.2.0', + 'npm' => '9.8.1', + 'cnpm' => '7.1.0', + 'node' => '20.14.0', + 'yarn' => '1.2.0', + 'pnpm' => '6.32.13', + ]; + + /** + * 安装完成标记 + * 配置完成则建立lock文件 + * 执行命令成功执行再写入标记到lock文件 + * 实现命令执行失败,重载页面可重新执行 + */ + static string $InstallationCompletionMark = 'install-end'; + + + /** + * 构造方法 + * @param App $app + */ + public function __construct(App $app) + { + parent::__construct($app); + } + + /** + * 命令执行窗口 + * @throws Throwable + */ + public function terminal(): void + { + if ($this->isInstallComplete()) { + return; + } + + (new Terminal())->exec(false); + } + + public function changePackageManager(): void + { + if ($this->isInstallComplete()) { + return; + } + + $newPackageManager = request()->post('manager', Config::get('terminal.npm_package_manager')); + if (Terminal::changeTerminalConfig()) { + $this->success('', [ + 'manager' => $newPackageManager + ]); + } else { + $this->error(__('Failed to switch package manager. Please modify the configuration file manually:%s', ['根目录/config/buildadmin.php'])); + } + } + + /** + * 环境基础检查 + */ + public function envBaseCheck(): void + { + if ($this->isInstallComplete()) { + $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName]), []); + } + if (env('database.type')) { + $this->error(__('The .env file with database configuration was detected. Please clean up and try again!')); + } + + // php版本-start + $phpVersion = phpversion(); + $phpBit = PHP_INT_SIZE == 8 ? self::X64 : self::X86; + $phpVersionCompare = Version::compare(self::$needDependentVersion['php'], $phpVersion); + if (!$phpVersionCompare) { + $phpVersionLink = [ + [ + // 需要PHP版本 + 'name' => __('need') . ' >= ' . self::$needDependentVersion['php'], + 'type' => 'text' + ], + [ + // 如何解决 + 'name' => __('How to solve?'), + 'title' => __('Click to see how to solve it'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/preparePHP.html' + ] + ]; + } elseif ($phpBit != self::X64) { + $phpVersionLink = [ + [ + // 需要 64 位 PHP + 'name' => __('need') . ' x64 PHP', + 'type' => 'text' + ], + [ + // 如何解决 + 'name' => __('How to solve?'), + 'title' => __('Click to see how to solve it'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/preparePHP.html' + ] + ]; + } + // php版本-end + + // 配置文件-start + $dbConfigFile = config_path() . self::$dbConfigFileName; + $configIsWritable = Filesystem::pathIsWritable(config_path()) && Filesystem::pathIsWritable($dbConfigFile); + if (!$configIsWritable) { + $configIsWritableLink = [ + [ + // 查看原因 + 'name' => __('View reason'), + 'title' => __('Click to view the reason'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/dirNoPermission.html' + ] + ]; + } + // 配置文件-end + + // public-start + $publicIsWritable = Filesystem::pathIsWritable(public_path()); + if (!$publicIsWritable) { + $publicIsWritableLink = [ + [ + 'name' => __('View reason'), + 'title' => __('Click to view the reason'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/dirNoPermission.html' + ] + ]; + } + // public-end + + // PDO-start + $phpPdo = extension_loaded("PDO") && extension_loaded('pdo_mysql'); + if (!$phpPdo) { + $phpPdoLink = [ + [ + 'name' => __('PDO extensions need to be installed'), + 'type' => 'text' + ], + [ + 'name' => __('How to solve?'), + 'title' => __('Click to see how to solve it'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/missingExtension.html' + ] + ]; + } + // PDO-end + + // GD2和freeType-start + $phpGd2 = extension_loaded('gd') && function_exists('imagettftext'); + if (!$phpGd2) { + $phpGd2Link = [ + [ + 'name' => __('The gd extension and freeType library need to be installed'), + 'type' => 'text' + ], + [ + 'name' => __('How to solve?'), + 'title' => __('Click to see how to solve it'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/gdFail.html' + ] + ]; + } + // GD2和freeType-end + + // proc_open + $phpProc = function_exists('proc_open') && function_exists('proc_close') && function_exists('proc_get_status'); + if (!$phpProc) { + $phpProcLink = [ + [ + 'name' => __('View reason'), + 'title' => __('proc_open or proc_close functions in PHP Ini is disabled'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/disablement.html' + ], + [ + 'name' => __('How to modify'), + 'title' => __('Click to view how to modify'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/disablement.html' + ], + [ + 'name' => __('Security assurance?'), + 'title' => __('Using the installation service correctly will not cause any potential security problems. Click to view the details'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/senior.html' + ], + ]; + } + // proc_open-end + + $this->success('', [ + 'php_version' => [ + 'describe' => $phpVersion . " ($phpBit)", + 'state' => $phpVersionCompare && $phpBit == self::X64 ? self::$ok : self::$fail, + 'link' => $phpVersionLink ?? [], + ], + 'config_is_writable' => [ + 'describe' => self::writableStateDescribe($configIsWritable), + 'state' => $configIsWritable ? self::$ok : self::$fail, + 'link' => $configIsWritableLink ?? [] + ], + 'public_is_writable' => [ + 'describe' => self::writableStateDescribe($publicIsWritable), + 'state' => $publicIsWritable ? self::$ok : self::$fail, + 'link' => $publicIsWritableLink ?? [] + ], + 'php_pdo' => [ + 'describe' => $phpPdo ? __('already installed') : __('Not installed'), + 'state' => $phpPdo ? self::$ok : self::$fail, + 'link' => $phpPdoLink ?? [] + ], + 'php_gd2' => [ + 'describe' => $phpGd2 ? __('already installed') : __('Not installed'), + 'state' => $phpGd2 ? self::$ok : self::$fail, + 'link' => $phpGd2Link ?? [] + ], + 'php_proc' => [ + 'describe' => $phpProc ? __('Allow execution') : __('disabled'), + 'state' => $phpProc ? self::$ok : self::$warn, + 'link' => $phpProcLink ?? [] + ], + ]); + } + + /** + * npm环境检查 + */ + public function envNpmCheck(): void + { + if ($this->isInstallComplete()) { + $this->error('', [], 2); + } + + $packageManager = request()->post('manager', 'none'); + + // npm + $npmVersion = Version::getVersion('npm'); + $npmVersionCompare = Version::compare(self::$needDependentVersion['npm'], $npmVersion); + if (!$npmVersionCompare || !$npmVersion) { + $npmVersionLink = [ + [ + // 需要版本 + 'name' => __('need') . ' >= ' . self::$needDependentVersion['npm'], + 'type' => 'text' + ], + [ + // 如何解决 + 'name' => __('How to solve?'), + 'title' => __('Click to see how to solve it'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/prepareNpm.html' + ] + ]; + } + + // 包管理器 + if (in_array($packageManager, ['npm', 'cnpm', 'pnpm', 'yarn'])) { + $pmVersion = Version::getVersion($packageManager); + $pmVersionCompare = Version::compare(self::$needDependentVersion[$packageManager], $pmVersion); + + if (!$pmVersion) { + // 安装 + $pmVersionLink[] = [ + // 需要版本 + 'name' => __('need') . ' >= ' . self::$needDependentVersion[$packageManager], + 'type' => 'text' + ]; + if ($npmVersionCompare) { + $pmVersionLink[] = [ + // 点击安装 + 'name' => __('Click Install %s', [$packageManager]), + 'title' => '', + 'type' => 'install-package-manager' + ]; + } else { + $pmVersionLink[] = [ + // 请先安装npm + 'name' => __('Please install NPM first'), + 'type' => 'text' + ]; + } + } elseif (!$pmVersionCompare) { + // 版本不足 + $pmVersionLink[] = [ + // 需要版本 + 'name' => __('need') . ' >= ' . self::$needDependentVersion[$packageManager], + 'type' => 'text' + ]; + $pmVersionLink[] = [ + // 请升级 + 'name' => __('Please upgrade %s version', [$packageManager]), + 'type' => 'text' + ]; + } + } elseif ($packageManager == 'ni') { + $pmVersion = __('nothing'); + $pmVersionCompare = true; + } else { + $pmVersion = __('nothing'); + $pmVersionCompare = false; + } + + // nodejs + $nodejsVersion = Version::getVersion('node'); + $nodejsVersionCompare = Version::compare(self::$needDependentVersion['node'], $nodejsVersion); + if (!$nodejsVersionCompare || !$nodejsVersion) { + $nodejsVersionLink = [ + [ + // 需要版本 + 'name' => __('need') . ' >= ' . self::$needDependentVersion['node'], + 'type' => 'text' + ], + [ + // 如何解决 + 'name' => __('How to solve?'), + 'title' => __('Click to see how to solve it'), + 'type' => 'faq', + 'url' => 'https://doc.buildadmin.com/guide/install/prepareNodeJs.html' + ] + ]; + } + + $this->success('', [ + 'npm_version' => [ + 'describe' => $npmVersion ?: __('Acquisition failed'), + 'state' => $npmVersionCompare ? self::$ok : self::$warn, + 'link' => $npmVersionLink ?? [], + ], + 'nodejs_version' => [ + 'describe' => $nodejsVersion ?: __('Acquisition failed'), + 'state' => $nodejsVersionCompare ? self::$ok : self::$warn, + 'link' => $nodejsVersionLink ?? [] + ], + 'npm_package_manager' => [ + 'describe' => $pmVersion ?: __('Acquisition failed'), + 'state' => $pmVersionCompare ? self::$ok : self::$warn, + 'link' => $pmVersionLink ?? [], + ] + ]); + } + + /** + * 测试数据库连接 + */ + public function testDatabase(): void + { + $database = [ + 'hostname' => $this->request->post('hostname'), + 'username' => $this->request->post('username'), + 'password' => $this->request->post('password'), + 'hostport' => $this->request->post('hostport'), + 'database' => '', + ]; + + $conn = $this->connectDb($database); + if ($conn['code'] == 0) { + $this->error($conn['msg']); + } else { + $this->success('', [ + 'databases' => $conn['databases'] + ]); + } + } + + /** + * 系统基础配置 + * post请求=开始安装 + */ + public function baseConfig(): void + { + if ($this->isInstallComplete()) { + $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName])); + } + + $envOk = $this->commandExecutionCheck(); + $rootPath = str_replace('\\', '/', root_path()); + if ($this->request->isGet()) { + $this->success('', [ + 'rootPath' => $rootPath, + 'executionWebCommand' => $envOk + ]); + } + + $connectData = $databaseParam = $this->request->only(['hostname', 'username', 'password', 'hostport', 'database', 'prefix']); + + // 数据库配置测试 + $connectData['database'] = ''; + $connect = $this->connectDb($connectData, true); + if ($connect['code'] == 0) { + $this->error($connect['msg']); + } + + // 建立数据库 + if (!in_array($databaseParam['database'], $connect['databases'])) { + $sql = "CREATE DATABASE IF NOT EXISTS `{$databaseParam['database']}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"; + $connect['pdo']->exec($sql); + } + + // 写入数据库配置文件 + $dbConfigFile = config_path() . self::$dbConfigFileName; + $dbConfigContent = @file_get_contents($dbConfigFile); + $callback = function ($matches) use ($databaseParam) { + $value = $databaseParam[$matches[1]] ?? ''; + return "'$matches[1]'$matches[2]=>$matches[3]env('database.$matches[1]', '$value'),"; + }; + $dbConfigText = preg_replace_callback("/'(hostname|database|username|password|hostport|prefix)'(\s+)=>(\s+)env\('database\.(.*)',\s+'(.*)'\),/", $callback, $dbConfigContent); + $result = @file_put_contents($dbConfigFile, $dbConfigText); + if (!$result) { + $this->error(__('File has no write permission:%s', ['config/' . self::$dbConfigFileName])); + } + + // 写入.env-example文件 + $envFile = root_path() . '.env-example'; + $envFileContent = @file_get_contents($envFile); + if ($envFileContent) { + $databasePos = stripos($envFileContent, '[DATABASE]'); + if ($databasePos !== false) { + // 清理已有数据库配置 + $envFileContent = substr($envFileContent, 0, $databasePos); + } + $envFileContent .= "\n" . '[DATABASE]' . "\n"; + $envFileContent .= 'TYPE = mysql' . "\n"; + $envFileContent .= 'HOSTNAME = ' . $databaseParam['hostname'] . "\n"; + $envFileContent .= 'DATABASE = ' . $databaseParam['database'] . "\n"; + $envFileContent .= 'USERNAME = ' . $databaseParam['username'] . "\n"; + $envFileContent .= 'PASSWORD = ' . $databaseParam['password'] . "\n"; + $envFileContent .= 'HOSTPORT = ' . $databaseParam['hostport'] . "\n"; + $envFileContent .= 'PREFIX = ' . $databaseParam['prefix'] . "\n"; + $envFileContent .= 'CHARSET = utf8mb4' . "\n"; + $envFileContent .= 'DEBUG = true' . "\n"; + $result = @file_put_contents($envFile, $envFileContent); + if (!$result) { + $this->error(__('File has no write permission:%s', ['/' . $envFile])); + } + } + + // 设置新的Token随机密钥key + $oldTokenKey = Config::get('buildadmin.token.key'); + $newTokenKey = Random::build('alnum', 32); + $buildConfigFile = config_path() . self::$buildConfigFileName; + $buildConfigContent = @file_get_contents($buildConfigFile); + $buildConfigContent = preg_replace("/'key'(\s+)=>(\s+)'$oldTokenKey'/", "'key'\$1=>\$2'$newTokenKey'", $buildConfigContent); + $result = @file_put_contents($buildConfigFile, $buildConfigContent); + if (!$result) { + $this->error(__('File has no write permission:%s', ['config/' . self::$buildConfigFileName])); + } + + // 建立安装锁文件 + $result = @file_put_contents(public_path() . self::$lockFileName, date('Y-m-d H:i:s')); + if (!$result) { + $this->error(__('File has no write permission:%s', ['public/' . self::$lockFileName])); + } + + $this->success('', [ + 'rootPath' => $rootPath, + 'executionWebCommand' => $envOk + ]); + } + + protected function isInstallComplete(): bool + { + if (is_file(public_path() . self::$lockFileName)) { + $contents = @file_get_contents(public_path() . self::$lockFileName); + if ($contents == self::$InstallationCompletionMark) { + return true; + } + } + return false; + } + + /** + * 标记命令执行完毕 + * @throws Throwable + */ + public function commandExecComplete(): void + { + if ($this->isInstallComplete()) { + $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName])); + } + + $param = $this->request->only(['type', 'adminname', 'adminpassword', 'sitename']); + if ($param['type'] == 'web') { + $result = @file_put_contents(public_path() . self::$lockFileName, self::$InstallationCompletionMark); + if (!$result) { + $this->error(__('File has no write permission:%s', ['public/' . self::$lockFileName])); + } + } else { + // 管理员配置入库 + $adminModel = new AdminModel(); + $defaultAdmin = $adminModel->where('username', 'admin')->find(); + $defaultAdmin->username = $param['adminname']; + $defaultAdmin->nickname = ucfirst($param['adminname']); + $defaultAdmin->save(); + + if (isset($param['adminpassword']) && $param['adminpassword']) { + $adminModel->resetPassword($defaultAdmin->id, $param['adminpassword']); + } + + // 默认用户密码修改 + $user = new UserModel(); + $user->resetPassword(1, Random::build()); + + // 修改站点名称 + \app\admin\model\Config::where('name', 'site_name')->update([ + 'value' => $param['sitename'] + ]); + } + $this->success(); + } + + /** + * 获取命令执行检查的结果 + * @return bool 是否拥有执行命令的条件 + */ + private function commandExecutionCheck(): bool + { + $pm = Config::get('terminal.npm_package_manager'); + if ($pm == 'none') { + return false; + } + $check['phpPopen'] = function_exists('proc_open') && function_exists('proc_close'); + $check['npmVersionCompare'] = Version::compare(self::$needDependentVersion['npm'], Version::getVersion('npm')); + $check['pmVersionCompare'] = Version::compare(self::$needDependentVersion[$pm], Version::getVersion($pm)); + $check['nodejsVersionCompare'] = Version::compare(self::$needDependentVersion['node'], Version::getVersion('node')); + + $envOk = true; + foreach ($check as $value) { + if (!$value) { + $envOk = false; + break; + } + } + return $envOk; + } + + /** + * 安装指引 + */ + public function manualInstall(): void + { + $this->success('', [ + 'webPath' => str_replace('\\', '/', root_path() . 'web') + ]); + } + + public function mvDist(): void + { + if (!is_file(root_path() . self::$distDir . DIRECTORY_SEPARATOR . 'index.html')) { + $this->error(__('No built front-end file found, please rebuild manually!')); + } + + if (Terminal::mvDist()) { + $this->success(); + } else { + $this->error(__('Failed to move the front-end file, please move it manually!')); + } + } + + /** + * 目录是否可写 + * @param $writable + * @return string + */ + private static function writableStateDescribe($writable): string + { + return $writable ? __('Writable') : __('No write permission'); + } + + /** + * 数据库连接-获取数据表列表 + * @param array $database + * @param bool $returnPdo + * @return array + */ + private function connectDb(array $database, bool $returnPdo = false): array + { + try { + $dbConfig = Config::get('database'); + $dbConfig['connections']['mysql'] = array_merge($dbConfig['connections']['mysql'], $database); + Config::set(['connections' => $dbConfig['connections']], 'database'); + + $connect = Db::connect('mysql'); + $connect->execute("SELECT 1"); + } catch (PDOException $e) { + $errorMsg = $e->getMessage(); + return [ + 'code' => 0, + 'msg' => __('Database connection failed:%s', [mb_convert_encoding($errorMsg ?: 'unknown', 'UTF-8', 'UTF-8,GBK,GB2312,BIG5')]) + ]; + } + + $databases = []; + // 不需要的数据表 + $databasesExclude = ['information_schema', 'mysql', 'performance_schema', 'sys']; + $res = $connect->query("SHOW DATABASES"); + foreach ($res as $row) { + if (!in_array($row['Database'], $databasesExclude)) { + $databases[] = $row['Database']; + } + } + + return [ + 'code' => 1, + 'msg' => '', + 'databases' => $databases, + 'pdo' => $returnPdo ? $connect->getPdo() : '', + ]; + } +} diff --git a/app/api/controller/User.php b/app/api/controller/User.php new file mode 100644 index 0000000..9b38826 --- /dev/null +++ b/app/api/controller/User.php @@ -0,0 +1,100 @@ +error(__('Member center disabled')); + } + + // 检查登录态 + if ($this->auth->isLogin()) { + $this->success(__('You have already logged in. There is no need to log in again~'), [ + 'type' => $this->auth::LOGGED_IN + ], $this->auth::LOGIN_RESPONSE_CODE); + } + + $userLoginCaptchaSwitch = Config::get('buildadmin.user_login_captcha'); + + if ($this->request->isPost()) { + $params = $this->request->post(['tab', 'email', 'mobile', 'username', 'password', 'keep', 'captcha', 'captchaId', 'captchaInfo', 'registerType']); + + // 提前检查 tab ,然后将以 tab 值作为数据验证场景 + if (!in_array($params['tab'] ?? '', ['login', 'register'])) { + $this->error(__('Unknown operation')); + } + + $validate = new UserValidate(); + try { + $validate->scene($params['tab'])->check($params); + } catch (Throwable $e) { + $this->error($e->getMessage()); + } + + if ($params['tab'] == 'login') { + if ($userLoginCaptchaSwitch) { + $captchaObj = new ClickCaptcha(); + if (!$captchaObj->check($params['captchaId'], $params['captchaInfo'])) { + $this->error(__('Captcha error')); + } + } + $res = $this->auth->login($params['username'], $params['password'], !empty($params['keep'])); + } elseif ($params['tab'] == 'register') { + $captchaObj = new Captcha(); + if (!$captchaObj->check($params['captcha'], $params[$params['registerType']] . 'user_register')) { + $this->error(__('Please enter the correct verification code')); + } + $res = $this->auth->register($params['username'], $params['password'], $params['mobile'], $params['email']); + } + + if (isset($res) && $res === true) { + $this->success(__('Login succeeded!'), [ + 'userInfo' => $this->auth->getUserInfo(), + 'routePath' => '/user' + ]); + } else { + $msg = $this->auth->getError(); + $msg = $msg ?: __('Check in failed, please try again or contact the website administrator~'); + $this->error($msg); + } + } + + $this->success('', [ + 'userLoginCaptchaSwitch' => $userLoginCaptchaSwitch, + 'accountVerificationType' => get_account_verification_type() + ]); + } + + public function logout(): void + { + if ($this->request->isPost()) { + $refreshToken = $this->request->post('refreshToken', ''); + if ($refreshToken) Token::delete((string)$refreshToken); + $this->auth->logout(); + $this->success(); + } + } +} \ No newline at end of file diff --git a/app/api/lang/en.php b/app/api/lang/en.php new file mode 100644 index 0000000..df16d44 --- /dev/null +++ b/app/api/lang/en.php @@ -0,0 +1,15 @@ + 'Login expired, please login again.', + 'Account not exist' => 'Account does not exist', + 'Account disabled' => 'Account is disabled', + 'Token login failed' => 'Token login failed', + 'Please try again after 1 day' => 'The number of failed login attempts has exceeded the limit, please try again after 24 hours.', + 'Password is incorrect' => 'Incorrect password', + 'You are not logged in' => 'You are not logged in.', + 'Unknown operation' => 'Unknown operation', + 'No action available, please contact the administrator~' => 'There is no action available, please contact the administrator~', + 'Please login first' => 'Please login first!', + 'You have no permission' => 'No permission to operate!', + 'Captcha error' => 'Captcha error!', +]; \ No newline at end of file diff --git a/app/api/lang/en/account.php b/app/api/lang/en/account.php new file mode 100644 index 0000000..3968db2 --- /dev/null +++ b/app/api/lang/en/account.php @@ -0,0 +1,16 @@ + 'Nickname', + 'birthday' => 'Birthday', + 'captcha' => 'Captcha', + 'Old password error' => 'Old password error', + 'Data updated successfully~' => 'Data updated successfully', + 'Please input correct password' => 'Please enter the correct password', + 'nicknameChsDash' => 'Usernames can only be Chinese characters, letters, numbers, underscores_ and dashes-.', + 'Password has been changed~' => 'Password has been changed~', + 'Password has been changed, please login again~' => 'Password has been changed, please login again~', + 'Account does not exist~' => 'Account does not exist', + 'Failed to modify password, please try again later~' => 'Failed to modify password, please try again later~', + 'Please enter the correct verification code' => 'Please enter the correct Captcha', + '%s has been registered' => '%s has been registered, please login directly.', +]; \ No newline at end of file diff --git a/app/api/lang/en/ems.php b/app/api/lang/en/ems.php new file mode 100644 index 0000000..46c7fb3 --- /dev/null +++ b/app/api/lang/en/ems.php @@ -0,0 +1,16 @@ + 'email format error', + 'user_register' => 'Member registration verification', + 'user_retrieve_pwd' => 'Retrieve password verification', + 'user_change_email' => 'Modify mailbox validation', + 'user_email_verify' => 'Member Email Verification', + 'Your verification code is: %s' => 'Your Captcha is: %s,valid for 10 minutes~', + 'Mail sent successfully~' => 'Mail sent successfully', + 'Account does not exist~' => 'Account does not exist', + 'Mail sending service unavailable' => 'The mail sending service is not working, please contact the webmaster to configure it.', + 'Frequent email sending' => 'Frequent email sending', + 'Email has been registered, please log in directly' => 'Email has been registered, please log in directly~', + 'The email has been occupied' => 'The email has been occupied', + 'Email not registered' => 'Email not registered', +]; \ No newline at end of file diff --git a/app/api/lang/en/install.php b/app/api/lang/en/install.php new file mode 100644 index 0000000..0175147 --- /dev/null +++ b/app/api/lang/en/install.php @@ -0,0 +1,44 @@ + 'Install the controller', + 'need' => 'Need', + 'Click to see how to solve it' => 'Click to see how to solve.', + 'Please check the config directory permissions' => 'Please check the Config directory permissions', + 'Please check the public directory permissions' => 'Please check the Public directory permissions', + 'open' => 'Open', + 'close' => 'Close', + 'The installation can continue, and some operations need to be completed manually' => 'You can continue to install, and some operations need to be completed manually ', + 'Allow execution' => 'Allow execution', + 'disabled' => 'Disabled', + 'Allow operation' => 'Allow operation', + 'Acquisition failed' => 'Access failed', + 'Click Install %s' => 'Click Install %s', + 'Writable' => 'Writable', + 'No write permission' => 'No write permissions', + 'already installed' => 'Installed', + 'Not installed' => 'Not installed', + 'File has no write permission:%s' => 'File has no write permission:%s', + 'The system has completed installation. If you need to reinstall, please delete the %s file first' => 'The system has been installed, if you need to reinstall, please delete the %s file first.', + 'Database connection failed:%s' => 'Database connection failure:%s', + 'Failed to install SQL execution:%s' => 'Installation SQL execution failed:%s', + 'unknown' => 'Unknown', + 'Database does not exist' => 'Database does not exist!', + 'No built front-end file found, please rebuild manually!' => 'No built front-end file found, please rebuild manually.', + 'Failed to move the front-end file, please move it manually!' => 'Failed to move the front-end file, please move manually!', + 'How to solve?' => 'How to solve?', + 'View reason' => 'View reasons', + 'Click to view the reason' => 'Click to see the reason', + 'PDO extensions need to be installed' => 'pdo_mysql extensions need to be installed.', + 'proc_open or proc_close functions in PHP Ini is disabled' => 'proc_open and proc_close functions in PHP.Ini is disabled.', + 'How to modify' => 'How to modify?', + 'Click to view how to modify' => 'Click to see how to modify.', + 'Security assurance?' => 'Security assurance?', + 'Using the installation service correctly will not cause any potential security problems. Click to view the details' => 'The correct use of the installation service will not cause any potential security issues. Click to view the details.', + 'Please install NPM first' => 'Please install NPM first.', + 'Installation error:%s' => 'Installation error:%s', + 'Failed to switch package manager. Please modify the configuration file manually:%s' => 'Package manager switch failed, please modify the configuration file manually:%s.', + 'Please upgrade %s version' => 'Please upgrade the %s version', + 'nothing' => 'Nothing', + 'The gd extension and freeType library need to be installed' => 'The gd2 extension and freeType library need to be installed', + 'The .env file with database configuration was detected. Please clean up and try again!' => 'The .env file with database configuration was detected. Please clean up and try again!', +]; \ No newline at end of file diff --git a/app/api/lang/en/user.php b/app/api/lang/en/user.php new file mode 100644 index 0000000..d857baf --- /dev/null +++ b/app/api/lang/en/user.php @@ -0,0 +1,13 @@ + 'Captcha', + 'captchaId' => 'Captcha ID', + 'Please input correct username' => 'Please enter the correct username.', + 'Please input correct password' => 'Please enter the correct password.', + 'Registration parameter error' => 'Wrong registration parameter', + 'Login succeeded!' => 'Login succeeded!', + 'Please enter the correct verification code' => 'Please enter the correct Captcha.', + 'You have already logged in. There is no need to log in again~' => 'You have already logged in, no need to log in again.', + 'Check in failed, please try again or contact the website administrator~' => 'Check in failed,please try again or contact the webmaster.', + 'Member center disabled' => 'The member centre has been disabled, please contact the webmaster to turn it on.', +]; \ No newline at end of file diff --git a/app/api/lang/zh-cn.php b/app/api/lang/zh-cn.php new file mode 100644 index 0000000..a125c99 --- /dev/null +++ b/app/api/lang/zh-cn.php @@ -0,0 +1,47 @@ + '%d秒前', + '%d minute%s ago' => '%d分钟前', + '%d hour%s ago' => '%d小时前', + '%d day%s ago' => '%d天前', + '%d week%s ago' => '%d周前', + '%d month%s ago' => '%d月前', + '%d year%s ago' => '%d年前', + '%d second%s after' => '%d秒后', + '%d minute%s after' => '%d分钟后', + '%d hour%s after' => '%d小时后', + '%d day%s after' => '%d天后', + '%d week%s after' => '%d周后', + '%d month%s after' => '%d月后', + '%d year%s after' => '%d年后', + // 时间格式化-e + // 文件上传-s + 'File uploaded successfully' => '文件上传成功!', + 'No files were uploaded' => '没有文件被上传', + 'The uploaded file format is not allowed' => '上传的文件格式未被允许', + 'The uploaded image file is not a valid image' => '上传的图片文件不是有效的图像', + 'The uploaded file is too large (%sMiB), Maximum file size:%sMiB' => '上传的文件太大(%sM),最大文件大小:%sM', + 'No files have been uploaded or the file size exceeds the upload limit of the server' => '没有文件被上传或文件大小超出服务器上传限制!', + 'Topic format error' => '上传存储子目录格式错误!', + 'Driver %s not supported' => '不支持的驱动:%s', + // 文件上传-e + 'Username' => '用户名', + 'Email' => '邮箱', + 'Mobile' => '手机号', + 'Password' => '密码', + 'Login expired, please login again.' => '登录过期,请重新登录。', + 'Account not exist' => '帐户不存在', + 'Account disabled' => '帐户已禁用', + 'Token login failed' => '令牌登录失败', + 'Please try again after 1 day' => '登录失败次数超限,请在1天后再试', + 'Password is incorrect' => '密码不正确', + 'You are not logged in' => '你没有登录', + 'Unknown operation' => '未知操作', + 'No action available, please contact the administrator~' => '没有可用操作,请联系管理员~', + 'Please login first' => '请先登录!', + 'You have no permission' => '没有权限操作!', + 'Parameter error' => '参数错误!', + 'Token expiration' => '登录态过期,请重新登录!', + 'Captcha error' => '验证码错误!', +]; \ No newline at end of file diff --git a/app/api/lang/zh-cn/account.php b/app/api/lang/zh-cn/account.php new file mode 100644 index 0000000..4f8be69 --- /dev/null +++ b/app/api/lang/zh-cn/account.php @@ -0,0 +1,22 @@ + '昵称', + 'birthday' => '生日', + 'captcha' => '验证码', + 'Old password error' => '旧密码错误', + 'Data updated successfully~' => '资料更新成功~', + 'Please input correct password' => '请输入正确的密码', + 'nicknameChsDash' => '用户名只能是汉字、字母、数字和下划线_及破折号-', + 'Password has been changed~' => '密码已修改~', + 'Password has been changed, please login again~' => '密码已修改,请重新登录~', + 'Account does not exist~' => '账户不存在~', + 'Failed to modify password, please try again later~' => '修改密码失败,请稍后重试~', + 'Please enter the correct verification code' => '请输入正确的验证码!', + '%s has been registered' => '%s已被注册,请直接登录~', + 'email format error' => '电子邮箱格式错误!', + 'mobile format error' => '手机号格式错误!', + 'You need to verify your account before modifying the binding information' => '您需要先通过账户验证才能修改绑定信息!', + 'Password error' => '密码错误!', + 'email is occupied' => '电子邮箱地址已被占用!', + 'mobile is occupied' => '手机号已被占用!', +]; \ No newline at end of file diff --git a/app/api/lang/zh-cn/ems.php b/app/api/lang/zh-cn/ems.php new file mode 100644 index 0000000..e75a328 --- /dev/null +++ b/app/api/lang/zh-cn/ems.php @@ -0,0 +1,18 @@ + '电子邮箱格式错误', + 'user_register' => '会员注册验证', + 'user_change_email' => '修改邮箱验证', + 'user_retrieve_pwd' => '找回密码验证', + 'user_email_verify' => '会员身份验证', + 'Your verification code is: %s' => '您的验证码是:%s,十分钟内有效~', + 'Mail sent successfully~' => '邮件发送成功~', + 'Account does not exist~' => '账户不存在~', + 'Mail sending service unavailable' => '邮件发送服务不可用,请联系网站管理员进行配置~', + 'Frequent email sending' => '频繁发送电子邮件', + 'Email has been registered, please log in directly' => '电子邮箱已注册,请直接登录~', + 'The email has been occupied' => '电子邮箱已被占用!', + 'Email not registered' => '电子邮箱未注册', + 'Please use the account registration email to send the verification code' => '请使用账户注册邮箱发送验证码!', + 'Password error' => '密码错误!', +]; \ No newline at end of file diff --git a/app/api/lang/zh-cn/install.php b/app/api/lang/zh-cn/install.php new file mode 100644 index 0000000..18117ea --- /dev/null +++ b/app/api/lang/zh-cn/install.php @@ -0,0 +1,44 @@ + '安装控制器', + 'need' => '需要', + 'Click to see how to solve it' => '点击查看如何解决', + 'Please check the config directory permissions' => '请检查 config 目录权限', + 'Please check the public directory permissions' => '请检查 public 目录权限', + 'open' => '开启', + 'close' => '关闭', + 'The installation can continue, and some operations need to be completed manually' => '可以继续安装,部分操作需手动完成', + 'Allow execution' => '允许执行', + 'disabled' => '已禁用', + 'Allow operation' => '允许操作', + 'Acquisition failed' => '获取失败', + 'Click Install %s' => '点击安装%s', + 'Writable' => '可写', + 'No write permission' => '无写权限', + 'already installed' => '已安装', + 'Not installed' => '未安装', + 'File has no write permission:%s' => '文件无写入权限:%s', + 'The system has completed installation. If you need to reinstall, please delete the %s file first' => '系统已完成安装。如果需要重新安装,请先删除 %s 文件', + 'Database connection failed:%s' => '数据库连接失败:%s', + 'Failed to install SQL execution:%s' => '安装SQL执行失败:%s', + 'unknown' => '未知', + 'Database does not exist' => '数据库不存在!', + 'No built front-end file found, please rebuild manually!' => '没有找到构建好的前端文件,请手动重新构建!', + 'Failed to move the front-end file, please move it manually!' => '移动前端文件失败,请手动移动!', + 'How to solve?' => '如何解决?', + 'View reason' => '查看原因', + 'Click to view the reason' => '点击查看原因', + 'PDO extensions need to be installed' => '需要安装 pdo_mysql 扩展', + 'proc_open or proc_close functions in PHP Ini is disabled' => 'proc_open和proc_close函数在php.ini中被禁用掉了', + 'How to modify' => '如何修改', + 'Click to view how to modify' => '点击查看如何修改', + 'Security assurance?' => '安全保证?', + 'Using the installation service correctly will not cause any potential security problems. Click to view the details' => '安装服务使用正确不会造成任何潜在安全问题,点击查看详情', + 'Please install NPM first' => '请先安装npm', + 'Installation error:%s' => '安装出错:%s', + 'Failed to switch package manager. Please modify the configuration file manually:%s' => '包管理器切换失败,请手动修改配置文件:%s', + 'Please upgrade %s version' => '请升级%s版本', + 'nothing' => '无', + 'The gd extension and freeType library need to be installed' => '需要gd2扩展和freeType库', + 'The .env file with database configuration was detected. Please clean up and try again!' => '检测到带有数据库配置的 .env 文件。请清理后再试一次!', +]; \ No newline at end of file diff --git a/app/api/lang/zh-cn/user.php b/app/api/lang/zh-cn/user.php new file mode 100644 index 0000000..3bb8591 --- /dev/null +++ b/app/api/lang/zh-cn/user.php @@ -0,0 +1,14 @@ + '验证码', + 'captchaId' => '验证码标识', + 'Register type' => '注册类型', + 'Please input correct username' => '请输入正确的用户名', + 'Please input correct password' => '请输入正确的密码', + 'Registration parameter error' => '注册参数错误', + 'Login succeeded!' => '登录成功', + 'Please enter the correct verification code' => '请输入正确的验证码', + 'You have already logged in. There is no need to log in again~' => '您已经登录过了,无需重复登录~', + 'Check in failed, please try again or contact the website administrator~' => '签入失败,请重试或联系网站管理员~', + 'Member center disabled' => '会员中心已禁用,请联系网站管理员开启。', +]; \ No newline at end of file diff --git a/app/api/middleware.php b/app/api/middleware.php new file mode 100644 index 0000000..8b6c89a --- /dev/null +++ b/app/api/middleware.php @@ -0,0 +1,5 @@ + 'require|regex:^[a-zA-Z][a-zA-Z0-9_]{2,15}$|unique:user', + 'nickname' => 'require|chsDash', + 'birthday' => 'date', + 'email' => 'require|email|unique:user', + 'mobile' => 'require|mobile|unique:user', + 'password' => 'require|regex:^(?!.*[&<>"\'\n\r]).{6,32}$', + 'account' => 'require', + 'captcha' => 'require', + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'edit' => ['username', 'nickname', 'birthday'], + 'changePassword' => ['password'], + 'retrievePassword' => ['account', 'captcha', 'password'], + ]; + + public function __construct() + { + $this->field = [ + 'username' => __('Username'), + 'email' => __('Email'), + 'mobile' => __('Mobile'), + 'password' => __('Password'), + 'nickname' => __('nickname'), + 'birthday' => __('birthday'), + ]; + $this->message = array_merge($this->message, [ + 'nickname.chsDash' => __('nicknameChsDash'), + 'password.regex' => __('Please input correct password') + ]); + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/api/validate/User.php b/app/api/validate/User.php new file mode 100644 index 0000000..4182945 --- /dev/null +++ b/app/api/validate/User.php @@ -0,0 +1,67 @@ + 'require|regex:^[a-zA-Z][a-zA-Z0-9_]{2,15}$|unique:user', + 'password' => 'require|regex:^(?!.*[&<>"\'\n\r]).{6,32}$', + 'registerType' => 'require|in:email,mobile', + 'email' => 'email|unique:user|requireIf:registerType,email', + 'mobile' => 'mobile|unique:user|requireIf:registerType,mobile', + // 注册邮箱或手机验证码 + 'captcha' => 'require', + // 登录点选验证码 + 'captchaId' => 'require', + 'captchaInfo' => 'require', + ]; + + /** + * 验证场景 + */ + protected $scene = [ + 'register' => ['username', 'password', 'registerType', 'email', 'mobile', 'captcha'], + ]; + + /** + * 登录验证场景 + */ + public function sceneLogin(): User + { + $fields = ['username', 'password']; + + // 根据系统配置的登录验证码开关调整验证场景的字段 + $userLoginCaptchaSwitch = Config::get('buildadmin.user_login_captcha'); + if ($userLoginCaptchaSwitch) { + $fields[] = 'captchaId'; + $fields[] = 'captchaInfo'; + } + + return $this->only($fields)->remove('username', ['regex', 'unique']); + } + + public function __construct() + { + $this->field = [ + 'username' => __('Username'), + 'email' => __('Email'), + 'mobile' => __('Mobile'), + 'password' => __('Password'), + 'captcha' => __('captcha'), + 'captchaId' => __('captchaId'), + 'captchaInfo' => __('captcha'), + 'registerType' => __('Register type'), + ]; + $this->message = array_merge($this->message, [ + 'username.regex' => __('Please input correct username'), + 'password.regex' => __('Please input correct password') + ]); + parent::__construct(); + } +} \ No newline at end of file diff --git a/app/common.php b/app/common.php new file mode 100644 index 0000000..f4e3b21 --- /dev/null +++ b/app/common.php @@ -0,0 +1,508 @@ +removeEvilAttributes(['style']); + + // 检查到 xss 代码之后使用 cleanXss 替换它 + $antiXss->setReplacement('cleanXss'); + + return $antiXss->xss_clean($string); + } +} + +if (!function_exists('htmlspecialchars_decode_improve')) { + /** + * html解码增强 + * 被 filter函数 内的 htmlspecialchars 编码的字符串,需要用此函数才能完全解码 + * @param string $string + * @param int $flags + * @return string + */ + function htmlspecialchars_decode_improve(string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401): string + { + return htmlspecialchars_decode($string, $flags); + } +} + +if (!function_exists('get_sys_config')) { + + /** + * 获取站点的系统配置,不传递参数则获取所有配置项 + * @param string $name 变量名 + * @param string $group 变量分组,传递此参数来获取某个分组的所有配置项 + * @param bool $concise 是否开启简洁模式,简洁模式下,获取多项配置时只返回配置的键值对 + * @return mixed + * @throws Throwable + */ + function get_sys_config(string $name = '', string $group = '', bool $concise = true): mixed + { + if ($name) { + // 直接使用->value('value')不能使用到模型的类型格式化 + $config = configModel::cache($name, null, configModel::$cacheTag)->where('name', $name)->find(); + if ($config) $config = $config['value']; + } else { + if ($group) { + $temp = configModel::cache('group' . $group, null, configModel::$cacheTag)->where('group', $group)->select()->toArray(); + } else { + $temp = configModel::cache('sys_config_all', null, configModel::$cacheTag)->order('weigh desc')->select()->toArray(); + } + if ($concise) { + $config = []; + foreach ($temp as $item) { + $config[$item['name']] = $item['value']; + } + } else { + $config = $temp; + } + } + return $config; + } +} + +if (!function_exists('get_route_remark')) { + + /** + * 获取当前路由后台菜单规则的备注信息 + * @return string + */ + function get_route_remark(): string + { + $controllerName = request()->controller(true); + $actionName = request()->action(true); + $path = str_replace('.', '/', $controllerName); + + $remark = Db::name('admin_rule') + ->where('name', $path) + ->whereOr('name', $path . '/' . $actionName) + ->value('remark'); + return __((string)$remark); + } +} + +if (!function_exists('full_url')) { + + /** + * 获取资源完整url地址;若安装了云存储或 config/buildadmin.php 配置了CdnUrl,则自动使用对应的CdnUrl + * @param string $relativeUrl 资源相对地址 不传入则获取域名 + * @param string|bool $domain 是否携带域名 或者直接传入域名 + * @param string $default 默认值 + * @return string + */ + function full_url(string $relativeUrl = '', string|bool $domain = true, string $default = ''): string + { + // 存储/上传资料配置 + Event::trigger('uploadConfigInit', App::getInstance()); + + $cdnUrl = Config::get('buildadmin.cdn_url'); + if (!$cdnUrl) { + $cdnUrl = request()->upload['cdn'] ?? '//' . request()->host(); + } + + if ($domain === true) { + $domain = $cdnUrl; + } elseif ($domain === false) { + $domain = ''; + } + + $relativeUrl = $relativeUrl ?: $default; + if (!$relativeUrl) return $domain; + + $regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i"; + if (preg_match('/^http(s)?:\/\//', $relativeUrl) || preg_match($regex, $relativeUrl) || $domain === false) { + return $relativeUrl; + } + + $url = $domain . $relativeUrl; + $cdnUrlParams = Config::get('buildadmin.cdn_url_params'); + if ($domain === $cdnUrl && $cdnUrlParams) { + $separator = str_contains($url, '?') ? '&' : '?'; + $url .= $separator . $cdnUrlParams; + } + + return $url; + } +} + +if (!function_exists('encrypt_password')) { + + /** + * 加密密码 + * @deprecated 使用 hash_password 代替 + */ + function encrypt_password($password, $salt = '', $encrypt = 'md5') + { + return $encrypt($encrypt($password) . $salt); + } +} + +if (!function_exists('hash_password')) { + + /** + * 创建密码散列(hash) + */ + function hash_password(string $password): string + { + return password_hash($password, PASSWORD_DEFAULT); + } +} + +if (!function_exists('verify_password')) { + + /** + * 验证密码是否和散列值匹配 + * @param string $password 密码 + * @param string $hash 散列值 + * @param array $extend 扩展数据 + */ + function verify_password(string $password, string $hash, array $extend = []): bool + { + // 第一个表达式直接检查是否为 password_hash 函数创建的 hash 的典型格式,即:$algo$cost$salt.hash + if (str_starts_with($hash, '$') || password_get_info($hash)['algoName'] != 'unknown') { + return password_verify($password, $hash); + } else { + // 兼容旧版 md5 加密的密码 + return encrypt_password($password, $extend['salt'] ?? '') === $hash; + } + } +} + +if (!function_exists('str_attr_to_array')) { + + /** + * 将字符串属性列表转为数组 + * @param string $attr 属性,一行一个,无需引号,比如:class=input-class + * @return array + */ + function str_attr_to_array(string $attr): array + { + if (!$attr) return []; + $attr = explode("\n", trim(str_replace("\r\n", "\n", $attr))); + $attrTemp = []; + foreach ($attr as $item) { + $item = explode('=', $item); + if (isset($item[0]) && isset($item[1])) { + $attrVal = $item[1]; + if ($item[1] === 'false' || $item[1] === 'true') { + $attrVal = !($item[1] === 'false'); + } elseif (is_numeric($item[1])) { + $attrVal = (float)$item[1]; + } + if (strpos($item[0], '.')) { + $attrKey = explode('.', $item[0]); + if (isset($attrKey[0]) && isset($attrKey[1])) { + $attrTemp[$attrKey[0]][$attrKey[1]] = $attrVal; + continue; + } + } + $attrTemp[$item[0]] = $attrVal; + } + } + return $attrTemp; + } +} + +if (!function_exists('action_in_arr')) { + + /** + * 检测一个方法是否在传递的数组内 + * @param array $arr + * @return bool + */ + function action_in_arr(array $arr = []): bool + { + $arr = is_array($arr) ? $arr : explode(',', $arr); + if (!$arr) { + return false; + } + $arr = array_map('strtolower', $arr); + if (in_array(strtolower(request()->action()), $arr) || in_array('*', $arr)) { + return true; + } + return false; + } +} + +if (!function_exists('build_suffix_svg')) { + + /** + * 构建文件后缀的svg图片 + * @param string $suffix 文件后缀 + * @param ?string $background 背景颜色,如:rgb(255,255,255) + * @return string + */ + function build_suffix_svg(string $suffix = 'file', ?string $background = null): string + { + $suffix = mb_substr(strtoupper($suffix), 0, 4); + $total = unpack('L', hash('adler32', $suffix, true))[1]; + $hue = $total % 360; + [$r, $g, $b] = hsv2rgb($hue / 360, 0.3, 0.9); + + $background = $background ?: "rgb($r,$g,$b)"; + + return ' + + + + + + ' . $suffix . ' + '; + } +} + +if (!function_exists('get_area')) { + + /** + * 获取省份地区数据 + * @throws Throwable + */ + function get_area(): array + { + $province = request()->get('province', ''); + $city = request()->get('city', ''); + $where = ['pid' => 0, 'level' => 1]; + if ($province !== '') { + $where['pid'] = $province; + $where['level'] = 2; + if ($city !== '') { + $where['pid'] = $city; + $where['level'] = 3; + } + } + return Db::name('area') + ->where($where) + ->field('id as value,name as label') + ->select() + ->toArray(); + } +} + +if (!function_exists('hsv2rgb')) { + function hsv2rgb($h, $s, $v): array + { + $r = $g = $b = 0; + + $i = floor($h * 6); + $f = $h * 6 - $i; + $p = $v * (1 - $s); + $q = $v * (1 - $f * $s); + $t = $v * (1 - (1 - $f) * $s); + + switch ($i % 6) { + case 0: + $r = $v; + $g = $t; + $b = $p; + break; + case 1: + $r = $q; + $g = $v; + $b = $p; + break; + case 2: + $r = $p; + $g = $v; + $b = $t; + break; + case 3: + $r = $p; + $g = $q; + $b = $v; + break; + case 4: + $r = $t; + $g = $p; + $b = $v; + break; + case 5: + $r = $v; + $g = $p; + $b = $q; + break; + } + + return [ + floor($r * 255), + floor($g * 255), + floor($b * 255) + ]; + } +} + +if (!function_exists('ip_check')) { + + /** + * IP检查 + * @throws Throwable + */ + function ip_check($ip = null): void + { + $ip = is_null($ip) ? request()->ip() : $ip; + $noAccess = get_sys_config('no_access_ip'); + $noAccess = !$noAccess ? [] : array_filter(explode("\n", str_replace("\r\n", "\n", $noAccess))); + if ($noAccess && IpUtils::checkIp($ip, $noAccess)) { + $response = Response::create(['msg' => 'No permission request'], 'json', 403); + throw new HttpResponseException($response); + } + } +} + +if (!function_exists('set_timezone')) { + + /** + * 设置时区 + * @throws Throwable + */ + function set_timezone($timezone = null): void + { + $defaultTimezone = Config::get('app.default_timezone'); + $timezone = is_null($timezone) ? get_sys_config('time_zone') : $timezone; + if ($timezone && $defaultTimezone != $timezone) { + Config::set([ + 'app.default_timezone' => $timezone + ]); + date_default_timezone_set($timezone); + } + } +} + +if (!function_exists('get_upload_config')) { + + /** + * 获取上传配置 + * @return array + */ + function get_upload_config(): array + { + // 存储/上传资料配置 + Event::trigger('uploadConfigInit', App::getInstance()); + + $uploadConfig = Config::get('upload'); + $uploadConfig['max_size'] = Filesystem::fileUnitToByte($uploadConfig['max_size']); + + $upload = request()->upload; + if (!$upload) { + $uploadConfig['mode'] = 'local'; + return $uploadConfig; + } + unset($upload['cdn']); + return array_merge($upload, $uploadConfig); + } +} + +if (!function_exists('get_auth_token')) { + + /** + * 获取鉴权 token + * @param array $names + * @return string + */ + function get_auth_token(array $names = ['ba', 'token']): string + { + $separators = [ + 'header' => ['', '-'], // batoken、ba-token【ba_token 不在 header 的接受列表内因为兼容性不高,改用 http_ba_token】 + 'param' => ['', '-', '_'], // batoken、ba-token、ba_token + 'server' => ['_'], // http_ba_token + ]; + + $tokens = []; + $request = request(); + foreach ($separators as $fun => $sps) { + foreach ($sps as $sp) { + $tokens[] = $request->$fun(($fun == 'server' ? 'http_' : '') . implode($sp, $names)); + } + } + $tokens = array_filter($tokens); + return array_values($tokens)[0] ?? ''; + } +} + +if (!function_exists('keys_to_camel_case')) { + + /** + * 将数组 key 的命名方式转换为小写驼峰 + * @param array $array 被转换的数组 + * @param array $keys 要转换的 key,默认所有 + * @return array + */ + function keys_to_camel_case(array $array, array $keys = []): array + { + $result = []; + foreach ($array as $key => $value) { + // 将键名转换为驼峰命名 + $camelCaseKey = $keys && in_array($key, $keys) ? parse_name($key, 1, false) : $key; + + if (is_array($value)) { + // 如果值是数组,递归转换 + $result[$camelCaseKey] = keys_to_camel_case($value); + } else { + $result[$camelCaseKey] = $value; + } + } + return $result; + } +} diff --git a/app/common/controller/Api.php b/app/common/controller/Api.php new file mode 100644 index 0000000..7c6abd0 --- /dev/null +++ b/app/common/controller/Api.php @@ -0,0 +1,117 @@ +useSystemSettings) { + // 检查数据库连接 + try { + Db::execute("SELECT 1"); + } catch (PDOException $e) { + $this->error(mb_convert_encoding($e->getMessage(), 'UTF-8', 'UTF-8,GBK,GB2312,BIG5')); + } + + ip_check(); // ip检查 + set_timezone(); // 时区设定 + } + + parent::initialize(); + + // 加载控制器语言包 + $langSet = $this->app->lang->getLangSet(); + $this->app->lang->load([ + app_path() . 'lang' . DIRECTORY_SEPARATOR . $langSet . DIRECTORY_SEPARATOR . (str_replace('/', DIRECTORY_SEPARATOR, $this->app->request->controllerPath)) . '.php' + ]); + } + + /** + * 操作成功 + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 错误码 + * @param string|null $type 输出类型 + * @param array $header 发送的 header 信息 + * @param array $options Response 输出参数 + */ + protected function success(string $msg = '', mixed $data = null, int $code = 1, ?string $type = null, array $header = [], array $options = []): void + { + $this->result($msg, $data, $code, $type, $header, $options); + } + + /** + * 操作失败 + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 错误码 + * @param string|null $type 输出类型 + * @param array $header 发送的 header 信息 + * @param array $options Response 输出参数 + */ + protected function error(string $msg = '', mixed $data = null, int $code = 0, ?string $type = null, array $header = [], array $options = []): void + { + $this->result($msg, $data, $code, $type, $header, $options); + } + + /** + * 返回 API 数据 + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 错误码 + * @param string|null $type 输出类型 + * @param array $header 发送的 header 信息 + * @param array $options Response 输出参数 + */ + public function result(string $msg, mixed $data = null, int $code = 0, ?string $type = null, array $header = [], array $options = []) + { + $result = [ + 'code' => $code, + 'msg' => $msg, + 'time' => $this->request->server('REQUEST_TIME'), + 'data' => $data, + ]; + + $type = $type ?: $this->responseType; + $code = $header['statusCode'] ?? 200; + + $response = Response::create($result, $type, $code)->header($header)->options($options); + throw new HttpResponseException($response); + } + +} diff --git a/app/common/controller/Backend.php b/app/common/controller/Backend.php new file mode 100644 index 0000000..8e1a266 --- /dev/null +++ b/app/common/controller/Backend.php @@ -0,0 +1,383 @@ + 'desc'] + */ + protected string|array $defaultSortField = []; + + /** + * 有序保证 + * 查询数据时总是需要指定 ORDER BY 子句,否则 MySQL 不保证排序,即先查到哪行就输出哪行且不保证多次查询中的输出顺序 + * 将以下配置作为数据有序保证(用于无排序字段时、默认排序字段相同时继续保持数据有序),不设置将自动使用 pk 字段 + * @var string|array id,desc 或 ['id' => 'desc'](有更方便的格式,此处为了保持和 $defaultSortField 属性的配置格式一致) + */ + protected string|array $orderGuarantee = []; + + /** + * 快速搜索字段 + * @var string|array + */ + protected string|array $quickSearchField = 'id'; + + /** + * 是否开启模型验证 + * @var bool + */ + protected bool $modelValidate = true; + + /** + * 是否开启模型场景验证 + * @var bool + */ + protected bool $modelSceneValidate = false; + + /** + * 关联查询方法名,方法应定义在模型中 + * @var array + */ + protected array $withJoinTable = []; + + /** + * 关联查询JOIN方式 + * @var string + */ + protected string $withJoinType = 'LEFT'; + + /** + * 开启数据限制 + * false=关闭 + * personal=仅限个人 + * allAuth=拥有某管理员所有的权限时 + * allAuthAndOthers=拥有某管理员所有的权限并且还有其他权限时 + * parent=上级分组中的管理员可查 + * 指定分组中的管理员可查,比如 $dataLimit = 2; + * 启用请确保数据表内存在 admin_id 字段,可以查询/编辑数据的管理员为admin_id对应的管理员+数据限制所表示的管理员们 + * @var bool|string|int + */ + protected bool|string|int $dataLimit = false; + + /** + * 数据限制字段 + * @var string + */ + protected string $dataLimitField = 'admin_id'; + + /** + * 数据限制开启时自动填充字段值为当前管理员id + * @var bool + */ + protected bool $dataLimitFieldAutoFill = true; + + /** + * 查看请求返回的主表字段控制 + * @var string|array + */ + protected string|array $indexField = ['*']; + + /** + * 引入traits + * traits内实现了index、add、edit等方法 + */ + use \app\admin\library\traits\Backend; + + /** + * 初始化 + * @throws Throwable + */ + public function initialize(): void + { + parent::initialize(); + + $needLogin = !action_in_arr($this->noNeedLogin); + + try { + + // 初始化管理员鉴权实例 + $this->auth = Auth::instance(); + $token = get_auth_token(); + if ($token) $this->auth->init($token); + + } catch (TokenExpirationException) { + if ($needLogin) { + $this->error(__('Token expiration'), [], 409); + } + } + + if ($needLogin) { + if (!$this->auth->isLogin()) { + $this->error(__('Please login first'), [ + 'type' => $this->auth::NEED_LOGIN + ], $this->auth::LOGIN_RESPONSE_CODE); + } + if (!action_in_arr($this->noNeedPermission)) { + $routePath = ($this->app->request->controllerPath ?? '') . '/' . $this->request->action(true); + if (!$this->auth->check($routePath)) { + $this->error(__('You have no permission'), [], 401); + } + } + } + + // 管理员验权和登录标签位 + Event::trigger('backendInit', $this->auth); + } + + /** + * 查询参数构建器 + * @throws Throwable + */ + public function queryBuilder(): array + { + if (empty($this->model)) { + return []; + } + $pk = $this->model->getPk(); + $quickSearch = $this->request->get("quickSearch/s", ''); + $limit = $this->request->get("limit/d", 10); + $search = $this->request->get("search/a", []); + $initKey = $this->request->get("initKey/s", $pk); + $initValue = $this->request->get("initValue", ''); + $initOperator = $this->request->get("initOperator/s", 'in'); + + $where = []; + $modelTable = strtolower($this->model->getTable()); + $alias[$modelTable] = parse_name(basename(str_replace('\\', '/', get_class($this->model)))); + $mainTableAlias = $alias[$modelTable] . '.'; + + // 快速搜索 + if ($quickSearch) { + $quickSearchArr = is_array($this->quickSearchField) ? $this->quickSearchField : explode(',', $this->quickSearchField); + foreach ($quickSearchArr as $k => $v) { + $quickSearchArr[$k] = str_contains($v, '.') ? $v : $mainTableAlias . $v; + } + $where[] = [implode("|", $quickSearchArr), "LIKE", '%' . str_replace('%', '\%', $quickSearch) . '%']; + } + if ($initValue) { + $where[] = [$initKey, $initOperator, $initValue]; + $limit = 999999; + } + + // 通用搜索组装 + foreach ($search as $field) { + if (!is_array($field) || !isset($field['operator']) || !isset($field['field']) || !isset($field['val'])) { + continue; + } + + $field['operator'] = $this->getOperatorByAlias($field['operator']); + + // 查询关联表字段,转换表别名(驼峰转小写下划线) + if (str_contains($field['field'], '.')) { + $fieldNameParts = explode('.', $field['field']); + $fieldNamePartsLastKey = array_key_last($fieldNameParts); + + // 忽略最后一个元素(字段名) + foreach ($fieldNameParts as $fieldNamePartsKey => $fieldNamePart) { + if ($fieldNamePartsKey !== $fieldNamePartsLastKey) { + $fieldNameParts[$fieldNamePartsKey] = parse_name($fieldNamePart); + } + } + + $fieldName = implode('.', $fieldNameParts); + } else { + $fieldName = $mainTableAlias . $field['field']; + } + + // 日期时间 + if (isset($field['render']) && $field['render'] == 'datetime') { + if ($field['operator'] == 'RANGE') { + $datetimeArr = explode(',', $field['val']); + if (!isset($datetimeArr[1])) { + continue; + } + $datetimeArr = array_filter(array_map("strtotime", $datetimeArr)); + $where[] = [$fieldName, str_replace('RANGE', 'BETWEEN', $field['operator']), $datetimeArr]; + continue; + } + $where[] = [$fieldName, '=', strtotime($field['val'])]; + continue; + } + + // 范围查询 + if ($field['operator'] == 'RANGE' || $field['operator'] == 'NOT RANGE') { + $arr = explode(',', $field['val']); + // 重新确定操作符 + if (!isset($arr[0]) || $arr[0] === '') { + $operator = $field['operator'] == 'RANGE' ? '<=' : '>'; + $arr = $arr[1]; + } elseif (!isset($arr[1]) || $arr[1] === '') { + $operator = $field['operator'] == 'RANGE' ? '>=' : '<'; + $arr = $arr[0]; + } else { + $operator = str_replace('RANGE', 'BETWEEN', $field['operator']); + } + $where[] = [$fieldName, $operator, $arr]; + continue; + } + + switch ($field['operator']) { + case '=': + case '<>': + $where[] = [$fieldName, $field['operator'], (string)$field['val']]; + break; + case 'LIKE': + case 'NOT LIKE': + $where[] = [$fieldName, $field['operator'], '%' . str_replace('%', '\%', $field['val']) . '%']; + break; + case '>': + case '>=': + case '<': + case '<=': + $where[] = [$fieldName, $field['operator'], intval($field['val'])]; + break; + case 'FIND_IN_SET': + if (is_array($field['val'])) { + foreach ($field['val'] as $val) { + $where[] = [$fieldName, 'find in set', $val]; + } + } else { + $where[] = [$fieldName, 'find in set', $field['val']]; + } + break; + case 'IN': + case 'NOT IN': + $where[] = [$fieldName, $field['operator'], is_array($field['val']) ? $field['val'] : explode(',', $field['val'])]; + break; + case 'NULL': + case 'NOT NULL': + $where[] = [$fieldName, strtolower($field['operator']), '']; + break; + } + } + + // 数据权限 + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$mainTableAlias . $this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + return [$where, $alias, $limit, $this->queryOrderBuilder()]; + } + + /** + * 查询的排序参数构建器 + */ + public function queryOrderBuilder() + { + $pk = $this->model->getPk(); + $order = $this->request->get("order/s") ?: $this->defaultSortField; + + if ($order && is_string($order)) { + $order = explode(',', $order); + $order = [$order[0] => $order[1] ?? 'asc']; + } + if (!$this->orderGuarantee) { + $this->orderGuarantee = [$pk => 'desc']; + } elseif (is_string($this->orderGuarantee)) { + $this->orderGuarantee = explode(',', $this->orderGuarantee); + $this->orderGuarantee = [$this->orderGuarantee[0] => $this->orderGuarantee[1] ?? 'asc']; + } + $orderGuaranteeKey = array_key_first($this->orderGuarantee); + if (!array_key_exists($orderGuaranteeKey, $order)) { + $order[$orderGuaranteeKey] = $this->orderGuarantee[$orderGuaranteeKey]; + } + + return $order; + } + + /** + * 数据权限控制-获取有权限访问的管理员Ids + * @throws Throwable + */ + protected function getDataLimitAdminIds(): array + { + if (!$this->dataLimit || $this->auth->isSuperAdmin()) { + return []; + } + $adminIds = []; + if ($this->dataLimit == 'parent') { + // 取得当前管理员的下级分组们 + $parentGroups = $this->auth->getAdminChildGroups(); + if ($parentGroups) { + // 取得分组内的所有管理员 + $adminIds = $this->auth->getGroupAdmins($parentGroups); + } + } elseif (is_numeric($this->dataLimit) && $this->dataLimit > 0) { + // 在组内,可查看所有,不在组内,可查看自己的 + $adminIds = $this->auth->getGroupAdmins([$this->dataLimit]); + return in_array($this->auth->id, $adminIds) ? [] : [$this->auth->id]; + } elseif ($this->dataLimit == 'allAuth' || $this->dataLimit == 'allAuthAndOthers') { + // 取得拥有他所有权限的分组 + $allAuthGroups = $this->auth->getAllAuthGroups($this->dataLimit); + // 取得分组内的所有管理员 + $adminIds = $this->auth->getGroupAdmins($allAuthGroups); + } + $adminIds[] = $this->auth->id; + return array_unique($adminIds); + } + + /** + * 从别名获取原始的逻辑运算符 + * @param string $operator 逻辑运算符别名 + * @return string 原始的逻辑运算符,无别名则原样返回 + */ + protected function getOperatorByAlias(string $operator): string + { + $alias = [ + 'ne' => '<>', + 'eq' => '=', + 'gt' => '>', + 'egt' => '>=', + 'lt' => '<', + 'elt' => '<=', + ]; + + return $alias[$operator] ?? $operator; + } +} \ No newline at end of file diff --git a/app/common/controller/Frontend.php b/app/common/controller/Frontend.php new file mode 100644 index 0000000..909d1ae --- /dev/null +++ b/app/common/controller/Frontend.php @@ -0,0 +1,73 @@ +noNeedLogin); + + try { + + // 初始化会员鉴权实例 + $this->auth = Auth::instance(); + $token = get_auth_token(['ba', 'user', 'token']); + if ($token) $this->auth->init($token); + + } catch (TokenExpirationException) { + if ($needLogin) { + $this->error(__('Token expiration'), [], 409); + } + } + + if ($needLogin) { + if (!$this->auth->isLogin()) { + $this->error(__('Please login first'), [ + 'type' => $this->auth::NEED_LOGIN + ], $this->auth::LOGIN_RESPONSE_CODE); + } + if (!action_in_arr($this->noNeedPermission)) { + $routePath = ($this->app->request->controllerPath ?? '') . '/' . $this->request->action(true); + if (!$this->auth->check($routePath)) { + $this->error(__('You have no permission'), [], 401); + } + } + } + + // 会员验权和登录标签位 + Event::trigger('frontendInit', $this->auth); + } +} \ No newline at end of file diff --git a/app/common/event/Security.php b/app/common/event/Security.php new file mode 100644 index 0000000..712d643 --- /dev/null +++ b/app/common/event/Security.php @@ -0,0 +1,139 @@ +action(true); + if (!in_array($action, $this->listenAction) || (!$request->isPost() && !$request->isDelete())) { + return true; + } + + if ($action == 'del') { + $dataIds = $request->param('ids'); + try { + $recycle = DataRecycle::where('status', 1) + ->where('controller_as', $request->controllerPath) + ->find(); + if (!$recycle) { + return true; + } + + $recycleData = Db::connect(TableManager::getConnection($recycle['connection'])) + ->name($recycle['data_table']) + ->whereIn($recycle['primary_key'], $dataIds) + ->select() + ->toArray(); + $recycleDataArr = []; + $auth = Auth::instance(); + $adminId = $auth->isLogin() ? $auth->id : 0; + foreach ($recycleData as $recycleDatum) { + $recycleDataArr[] = [ + 'admin_id' => $adminId, + 'recycle_id' => $recycle['id'], + 'data' => json_encode($recycleDatum, JSON_UNESCAPED_UNICODE), + 'connection' => $recycle['connection'], + 'data_table' => $recycle['data_table'], + 'primary_key' => $recycle['primary_key'], + 'ip' => $request->ip(), + 'useragent' => substr($request->server('HTTP_USER_AGENT'), 0, 255), + ]; + } + if (!$recycleDataArr) { + return true; + } + + // saveAll 方法自带事务 + $dataRecycleLogModel = new DataRecycleLog(); + if (!$dataRecycleLogModel->saveAll($recycleDataArr)) { + Log::record('[ DataSecurity ] Failed to recycle data:' . var_export($recycleDataArr, true), 'warning'); + } + } catch (Throwable $e) { + Log::record('[ DataSecurity ]' . $e->getMessage(), 'warning'); + } + return true; + } + + try { + $sensitiveData = SensitiveData::where('status', 1) + ->where('controller_as', $request->controllerPath) + ->find(); + if (!$sensitiveData) { + return true; + } + + $sensitiveData = $sensitiveData->toArray(); + $dataId = $request->param($sensitiveData['primary_key']); + $editData = Db::connect(TableManager::getConnection($sensitiveData['connection'])) + ->name($sensitiveData['data_table']) + ->field(array_keys($sensitiveData['data_fields'])) + ->where($sensitiveData['primary_key'], $dataId) + ->find(); + if (!$editData) { + return true; + } + + $auth = Auth::instance(); + $adminId = $auth->isLogin() ? $auth->id : 0; + $newData = $request->post(); + foreach ($sensitiveData['data_fields'] as $field => $title) { + if (isset($editData[$field]) && isset($newData[$field]) && $editData[$field] != $newData[$field]) { + + /* + * 其他跳过规则可添加至此处 + * 1. 如果字段名中包含 password,修改值为空则忽略,修改值不为空,则密码记录为 ****** + */ + if (stripos('password', $field) !== false) { + if (!$newData[$field]) { + continue; + } else { + $newData[$field] = "******"; + } + } + + $sensitiveDataLog[] = [ + 'admin_id' => $adminId, + 'sensitive_id' => $sensitiveData['id'], + 'connection' => $sensitiveData['connection'], + 'data_table' => $sensitiveData['data_table'], + 'primary_key' => $sensitiveData['primary_key'], + 'data_field' => $field, + 'data_comment' => $title, + 'id_value' => $dataId, + 'before' => $editData[$field], + 'after' => $newData[$field], + 'ip' => $request->ip(), + 'useragent' => substr($request->server('HTTP_USER_AGENT'), 0, 255), + ]; + } + } + + if (!isset($sensitiveDataLog) || !$sensitiveDataLog) { + return true; + } + + $sensitiveDataLogModel = new SensitiveDataLog(); + if (!$sensitiveDataLogModel->saveAll($sensitiveDataLog)) { + Log::record('[ DataSecurity ] Sensitive data recording failed:' . var_export($sensitiveDataLog, true), 'warning'); + } + } catch (Throwable $e) { + Log::record('[ DataSecurity ]' . $e->getMessage(), 'warning'); + } + return true; + } +} \ No newline at end of file diff --git a/app/common/facade/Token.php b/app/common/facade/Token.php new file mode 100644 index 0000000..bfa0a57 --- /dev/null +++ b/app/common/facade/Token.php @@ -0,0 +1,24 @@ + 'user_group', // 用户组数据表名 + 'auth_group_access' => '', // 用户-用户组关系表(关系字段) + 'auth_rule' => 'user_rule', // 权限规则表 + ], $config)); + + $this->setKeepTime((int)Config::get('buildadmin.user_token_keep_time')); + } + + /** + * 魔术方法-会员信息字段 + * @param $name + * @return mixed 字段信息 + */ + public function __get($name): mixed + { + return $this->model?->$name; + } + + /** + * 初始化 + * @access public + * @param array $options 传递给 /ba/Auth 的参数 + * @return Auth + */ + public static function instance(array $options = []): Auth + { + $request = request(); + if (!isset($request->userAuth)) { + $request->userAuth = new static($options); + } + return $request->userAuth; + } + + /** + * 根据Token初始化会员登录态 + * @param $token + * @return bool + * @throws Throwable + */ + public function init($token): bool + { + $tokenData = Token::get($token); + if ($tokenData) { + + /** + * 过期检查,过期则抛出 @see TokenExpirationException + */ + Token::tokenExpirationCheck($tokenData); + + $userId = intval($tokenData['user_id']); + if ($tokenData['type'] == self::TOKEN_TYPE && $userId > 0) { + $this->model = User::where('id', $userId)->find(); + if (!$this->model) { + $this->setError('Account not exist'); + return false; + } + if ($this->model->status != 'enable') { + $this->setError('Account disabled'); + return false; + } + $this->token = $token; + $this->loginSuccessful(); + return true; + } + } + + $this->setError('Token login failed'); + $this->reset(); + return false; + } + + /** + * 会员注册,可使用关键词参数方式调用:$auth->register('u18888888888', email: 'test@qq.com') + * @param string $username + * @param string $password + * @param string $mobile + * @param string $email + * @param int $group 会员分组 ID 号 + * @param array $extend 扩展数据,如 ['status' => 'disable'] + * @return bool + */ + public function register(string $username, string $password = '', string $mobile = '', string $email = '', int $group = 1, array $extend = []): bool + { + $validate = Validate::rule([ + 'email|' . __('Email') => 'email|unique:user', + 'mobile|' . __('Mobile') => 'mobile|unique:user', + 'username|' . __('Username') => 'require|regex:^[a-zA-Z][a-zA-Z0-9_]{2,15}$|unique:user', + 'password|' . __('Password') => 'regex:^(?!.*[&<>"\'\n\r]).{6,32}$', + ]); + $params = [ + 'username' => $username, + 'password' => $password, + 'mobile' => $mobile, + 'email' => $email, + ]; + if (!$validate->check($params)) { + $this->setError($validate->getError()); + return false; + } + + // 用户昵称 + $nickname = preg_replace_callback('/1[3-9]\d{9}/', function ($matches) { + // 对 username 中出现的所有手机号进行脱敏处理 + $mobile = $matches[0]; + return substr($mobile, 0, 3) . '****' . substr($mobile, 7); + }, $username); + + $ip = request()->ip(); + $time = time(); + $data = [ + 'group_id' => $group, + 'nickname' => $nickname, + 'join_ip' => $ip, + 'join_time' => $time, + 'last_login_ip' => $ip, + 'last_login_time' => $time, + 'status' => 'enable', // 状态:enable=启用,disable=禁用,使用 string 存储可以自定义其他状态 + ]; + $data = array_merge($params, $data); + $data = array_merge($data, $extend); + + Db::startTrans(); + try { + $this->model = User::create($data); + $this->token = Random::uuid(); + Token::set($this->token, self::TOKEN_TYPE, $this->model->id, $this->keepTime); + Db::commit(); + + if ($password) { + $this->model->resetPassword($this->model->id, $password); + } + + Event::trigger('userRegisterSuccess', $this->model); + } catch (Throwable $e) { + $this->setError($e->getMessage()); + Db::rollback(); + return false; + } + return true; + } + + /** + * 会员登录 + * @param string $username 用户名 + * @param string $password 密码 + * @param bool $keep 是否保持登录 + * @return bool + * @throws Throwable + */ + public function login(string $username, string $password, bool $keep): bool + { + // 判断账户类型 + $accountType = false; + $validate = Validate::rule([ + 'mobile' => 'mobile', + 'email' => 'email', + 'username' => 'regex:^[a-zA-Z][a-zA-Z0-9_]{2,15}$', + ]); + if ($validate->check(['mobile' => $username])) $accountType = 'mobile'; + if ($validate->check(['email' => $username])) $accountType = 'email'; + if ($validate->check(['username' => $username])) $accountType = 'username'; + if (!$accountType) { + $this->setError('Account not exist'); + return false; + } + + $this->model = User::where($accountType, $username)->find(); + if (!$this->model) { + $this->setError('Account not exist'); + return false; + } + if ($this->model->status == 'disable') { + $this->setError('Account disabled'); + return false; + } + + // 登录失败重试检查 + $userLoginRetry = Config::get('buildadmin.user_login_retry'); + if ($userLoginRetry && $this->model->last_login_time) { + // 重置失败次数 + if ($this->model->login_failure > 0 && time() - $this->model->last_login_time >= 86400) { + $this->model->login_failure = 0; + $this->model->save(); + + // 重获模型实例,避免单实例多次更新 + $this->model = User::where($accountType, $username)->find(); + } + + if ($this->model->login_failure >= $userLoginRetry) { + $this->setError('Please try again after 1 day'); + return false; + } + } + + // 密码检查 + if (!verify_password($password, $this->model->password, ['salt' => $this->model->salt])) { + $this->loginFailed(); + $this->setError('Password is incorrect'); + return false; + } + + // 清理 token + if (Config::get('buildadmin.user_sso')) { + Token::clear(self::TOKEN_TYPE, $this->model->id); + Token::clear(self::TOKEN_TYPE . '-refresh', $this->model->id); + } + + if ($keep) { + $this->setRefreshToken($this->refreshTokenKeepTime); + } + $this->loginSuccessful(); + return true; + } + + /** + * 直接登录会员账号 + * @param int $userId 用户ID + * @return bool + * @throws Throwable + */ + public function direct(int $userId): bool + { + $this->model = User::find($userId); + if (!$this->model) return false; + if (Config::get('buildadmin.user_sso')) { + Token::clear(self::TOKEN_TYPE, $this->model->id); + Token::clear(self::TOKEN_TYPE . '-refresh', $this->model->id); + } + return $this->loginSuccessful(); + } + + /** + * 检查旧密码是否正确 + * @param $password + * @return bool + * @deprecated 请使用 verify_password 公共函数代替 + */ + public function checkPassword($password): bool + { + return verify_password($password, $this->model->password, ['salt' => $this->model->salt]); + } + + /** + * 登录成功 + * @return bool + */ + public function loginSuccessful(): bool + { + if (!$this->model) { + return false; + } + $this->model->startTrans(); + try { + $this->model->login_failure = 0; + $this->model->last_login_time = time(); + $this->model->last_login_ip = request()->ip(); + $this->model->save(); + $this->loginEd = true; + + if (!$this->token) { + $this->token = Random::uuid(); + Token::set($this->token, self::TOKEN_TYPE, $this->model->id, $this->keepTime); + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->setError($e->getMessage()); + return false; + } + return true; + } + + /** + * 登录失败 + * @return bool + */ + public function loginFailed(): bool + { + if (!$this->model) return false; + $this->model->startTrans(); + try { + $this->model->login_failure++; + $this->model->last_login_time = time(); + $this->model->last_login_ip = request()->ip(); + $this->model->save(); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->setError($e->getMessage()); + return false; + } + return $this->reset(); + } + + /** + * 退出登录 + * @return bool + */ + public function logout(): bool + { + if (!$this->loginEd) { + $this->setError('You are not logged in'); + return false; + } + return $this->reset(); + } + + /** + * 是否登录 + * @return bool + */ + public function isLogin(): bool + { + return $this->loginEd; + } + + /** + * 获取会员模型 + * @return User + */ + public function getUser(): User + { + return $this->model; + } + + /** + * 获取会员Token + * @return string + */ + public function getToken(): string + { + return $this->token; + } + + /** + * 设置刷新Token + * @param int $keepTime + * @return void + */ + public function setRefreshToken(int $keepTime = 0): void + { + $this->refreshToken = Random::uuid(); + Token::set($this->refreshToken, self::TOKEN_TYPE . '-refresh', $this->model->id, $keepTime); + } + + /** + * 获取会员刷新Token + * @return string + */ + public function getRefreshToken(): string + { + return $this->refreshToken; + } + + /** + * 获取会员信息 - 只输出允许输出的字段 + * @return array + */ + public function getUserInfo(): array + { + if (!$this->model) return []; + $info = $this->model->toArray(); + $info = array_intersect_key($info, array_flip($this->getAllowFields())); + $info['token'] = $this->getToken(); + $info['refresh_token'] = $this->getRefreshToken(); + return $info; + } + + /** + * 获取允许输出字段 + * @return array + */ + public function getAllowFields(): array + { + return $this->allowFields; + } + + /** + * 设置允许输出字段 + * @param $fields + * @return void + */ + public function setAllowFields($fields): void + { + $this->allowFields = $fields; + } + + /** + * 设置Token有效期 + * @param int $keepTime + * @return void + */ + public function setKeepTime(int $keepTime = 0): void + { + $this->keepTime = $keepTime; + } + + public function check(string $name, int $uid = 0, string $relation = 'or', string $mode = 'url'): bool + { + return parent::check($name, $uid ?: $this->id, $relation, $mode); + } + + public function getRuleList(int $uid = 0): array + { + return parent::getRuleList($uid ?: $this->id); + } + + public function getRuleIds(int $uid = 0): array + { + return parent::getRuleIds($uid ?: $this->id); + } + + public function getMenus(int $uid = 0): array + { + return parent::getMenus($uid ?: $this->id); + } + + /** + * 是否是拥有所有权限的会员 + * @return bool + * @throws Throwable + */ + public function isSuperUser(): bool + { + return in_array('*', $this->getRuleIds()); + } + + /** + * 设置错误消息 + * @param string $error + * @return Auth + */ + public function setError(string $error): Auth + { + $this->error = $error; + return $this; + } + + /** + * 获取错误消息 + * @return string + */ + public function getError(): string + { + return $this->error ? __($this->error) : ''; + } + + /** + * 属性重置(注销、登录失败、重新初始化等将单例数据销毁) + */ + protected function reset(bool $deleteToken = true): bool + { + if ($deleteToken && $this->token) { + Token::delete($this->token); + } + + $this->token = ''; + $this->loginEd = false; + $this->model = null; + $this->refreshToken = ''; + $this->setError(''); + $this->setKeepTime((int)Config::get('buildadmin.user_token_keep_time')); + return true; + } +} \ No newline at end of file diff --git a/app/common/library/Email.php b/app/common/library/Email.php new file mode 100644 index 0000000..4852564 --- /dev/null +++ b/app/common/library/Email.php @@ -0,0 +1,71 @@ + 'utf-8', //编码格式 + 'debug' => true, //调式模式 + 'lang' => 'zh_cn', + ]; + + /** + * 构造函数 + * @param array $options + * @throws Throwable + */ + public function __construct(array $options = []) + { + $this->options = array_merge($this->options, $options); + + parent::__construct($this->options['debug']); + $langSet = Lang::getLangSet(); + if ($langSet == 'zh-cn' || !$langSet) $langSet = 'zh_cn'; + $this->options['lang'] = $this->options['lang'] ?: $langSet; + + $this->setLanguage($this->options['lang'], root_path() . 'vendor' . DIRECTORY_SEPARATOR . 'phpmailer' . DIRECTORY_SEPARATOR . 'phpmailer' . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR); + $this->CharSet = $this->options['charset']; + + $sysMailConfig = get_sys_config('', 'mail'); + $this->configured = true; + foreach ($sysMailConfig as $item) { + if (!$item) { + $this->configured = false; + } + } + if ($this->configured) { + $this->Host = $sysMailConfig['smtp_server']; + $this->SMTPAuth = true; + $this->Username = $sysMailConfig['smtp_user']; + $this->Password = $sysMailConfig['smtp_pass']; + $this->SMTPSecure = $sysMailConfig['smtp_verification'] == 'SSL' ? self::ENCRYPTION_SMTPS : self::ENCRYPTION_STARTTLS; + $this->Port = $sysMailConfig['smtp_port']; + + $this->setFrom($sysMailConfig['smtp_sender_mail'], $sysMailConfig['smtp_user']); + } + } + + public function setSubject($subject): void + { + $this->Subject = "=?utf-8?B?" . base64_encode($subject) . "?="; + } +} \ No newline at end of file diff --git a/app/common/library/Menu.php b/app/common/library/Menu.php new file mode 100644 index 0000000..1c22a3b --- /dev/null +++ b/app/common/library/Menu.php @@ -0,0 +1,156 @@ +where((is_numeric($parent) ? 'id' : 'name'), $parent)->find(); + if ($parentRule) { + $pid = $parentRule['id']; + } + foreach ($menu as $item) { + if (!self::requiredAttrCheck($item)) { + continue; + } + + // 属性 + $item['status'] = 1; + if (!isset($item['pid'])) { + $item['pid'] = $pid; + } + + $sameOldMenu = $model->where('name', $item['name'])->find(); + if ($sameOldMenu) { + // 存在相同名称的菜单规则 + if ($mode == 'cover') { + $sameOldMenu->save($item); + } elseif ($mode == 'rename') { + $count = $model->where('name', $item['name'])->count(); + $item['name'] = $item['name'] . '-CONFLICT-' . $count; + $item['path'] = $item['path'] . '-CONFLICT-' . $count; + $item['title'] = $item['title'] . '-CONFLICT-' . $count; + $sameOldMenu = $model->create($item); + } elseif ($mode == 'ignore') { + // 忽略同名菜单时,当前 pid 下没有同名菜单,则创建同名新菜单,以保证所有新增菜单的上下级结构 + $sameOldMenu = $model + ->where('name', $item['name']) + ->where('pid', $item['pid']) + ->find(); + + if (!$sameOldMenu) { + $sameOldMenu = $model->create($item); + } + } + } else { + $sameOldMenu = $model->create($item); + } + if (!empty($item['children'])) { + self::create($item['children'], $sameOldMenu['id'], $mode, $position); + } + } + } + + /** + * 删菜单 + * @param string|int $id 规则name或id + * @param bool $recursion 是否递归删除子级菜单、是否删除自身,是否删除上级空菜单 + * @param string $position 位置:backend=后台,frontend=前台 + * @return bool + * @throws Throwable + */ + public static function delete(string|int $id, bool $recursion = false, string $position = 'backend'): bool + { + if (!$id) { + return true; + } + $model = $position == 'backend' ? new AdminRule() : new UserRule(); + $menuRule = $model->where((is_numeric($id) ? 'id' : 'name'), $id)->find(); + if (!$menuRule) { + return true; + } + + $children = $model->where('pid', $menuRule['id'])->select()->toArray(); + if ($recursion && $children) { + foreach ($children as $child) { + self::delete($child['id'], true, $position); + } + } + + if (!$children || $recursion) { + $menuRule->delete(); + self::delete($menuRule->pid, false, $position); + } + return true; + } + + /** + * 启用菜单 + * @param string|int $id 规则name或id + * @param string $position 位置:backend=后台,frontend=前台 + * @return bool + * @throws Throwable + */ + public static function enable(string|int $id, string $position = 'backend'): bool + { + $model = $position == 'backend' ? new AdminRule() : new UserRule(); + $menuRule = $model->where((is_numeric($id) ? 'id' : 'name'), $id)->find(); + if (!$menuRule) { + return false; + } + $menuRule->status = 1; + $menuRule->save(); + return true; + } + + /** + * 禁用菜单 + * @param string|int $id 规则name或id + * @param string $position 位置:backend=后台,frontend=前台 + * @return bool + * @throws Throwable + */ + public static function disable(string|int $id, string $position = 'backend'): bool + { + $model = $position == 'backend' ? new AdminRule() : new UserRule(); + $menuRule = $model->where((is_numeric($id) ? 'id' : 'name'), $id)->find(); + if (!$menuRule) { + return false; + } + $menuRule->status = 0; + $menuRule->save(); + return true; + } + + public static function requiredAttrCheck($menu): bool + { + $attrs = ['type', 'title', 'name']; + foreach ($attrs as $attr) { + if (!array_key_exists($attr, $menu)) { + return false; + } + if (!$menu[$attr]) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/app/common/library/SnowFlake.php b/app/common/library/SnowFlake.php new file mode 100644 index 0000000..0d9307b --- /dev/null +++ b/app/common/library/SnowFlake.php @@ -0,0 +1,87 @@ +handler)) { + return $this->handler; + } + $name = $name ?: $this->getDefaultDriver(); + + if (is_null($name)) { + throw new InvalidArgumentException( + sprintf( + 'Unable to resolve NULL driver for [%s].', + static::class + ) + ); + } + + return $this->createDriver($name); + } + + /** + * 创建驱动句柄 + * @param string $name + * @return object + */ + protected function createDriver(string $name): object + { + $type = $this->resolveType($name); + + $method = 'create' . Str::studly($type) . 'Driver'; + + $params = $this->resolveParams($name); + + if (method_exists($this, $method)) { + return $this->$method(...$params); + } + + $class = $this->resolveClass($type); + + if (isset($this->instance[$type])) { + return $this->instance[$type]; + } + + return new $class(...$params); + } + + /** + * 默认驱动 + * @return string + */ + protected function getDefaultDriver(): string + { + return $this->getConfig('default'); + } + + /** + * 获取驱动配置 + * @param string|null $name 要获取的配置项,不传递获取完整token配置 + * @param mixed $default + * @return array|string + */ + protected function getConfig(?string $name = null, $default = null): array|string + { + if (!is_null($name)) { + return Config::get('buildadmin.token.' . $name, $default); + } + + return Config::get('buildadmin.token'); + } + + /** + * 获取驱动配置参数 + * @param $name + * @return array + */ + protected function resolveParams($name): array + { + $config = $this->getStoreConfig($name); + return [$config]; + } + + /** + * 获取驱动类 + * @param string $type + * @return string + */ + protected function resolveClass(string $type): string + { + if ($this->namespace || str_contains($type, '\\')) { + $class = str_contains($type, '\\') ? $type : $this->namespace . Str::studly($type); + + if (class_exists($class)) { + return $class; + } + } + + throw new InvalidArgumentException("Driver [$type] not supported."); + } + + /** + * 获取驱动配置 + * @param string $store + * @param string|null $name + * @param mixed $default + * @return array|string + */ + protected function getStoreConfig(string $store, ?string $name = null, $default = null): array|string + { + if ($config = $this->getConfig("stores.$store")) { + return Arr::get($config, $name, $default); + } + + throw new InvalidArgumentException("Store [$store] not found."); + } + + /** + * 获取驱动类型 + * @param string $name + * @return string + */ + protected function resolveType(string $name): string + { + return $this->getStoreConfig($name, 'type', 'Mysql'); + } + + /** + * 设置token + * @param string $token + * @param string $type + * @param int $user_id + * @param int|null $expire + * @return bool + */ + public function set(string $token, string $type, int $user_id, ?int $expire = null): bool + { + return $this->getDriver()->set($token, $type, $user_id, $expire); + } + + /** + * 获取token + * @param string $token + * @param bool $expirationException + * @return array + */ + public function get(string $token, bool $expirationException = true): array + { + return $this->getDriver()->get($token, $expirationException); + } + + /** + * 检查token + * @param string $token + * @param string $type + * @param int $user_id + * @param bool $expirationException + * @return bool + */ + public function check(string $token, string $type, int $user_id, bool $expirationException = true): bool + { + return $this->getDriver()->check($token, $type, $user_id, $expirationException); + } + + /** + * 删除token + * @param string $token + * @return bool + */ + public function delete(string $token): bool + { + return $this->getDriver()->delete($token); + } + + /** + * 清理指定用户token + * @param string $type + * @param int $user_id + * @return bool + */ + public function clear(string $type, int $user_id): bool + { + return $this->getDriver()->clear($type, $user_id); + } + + /** + * Token过期检查 + * @throws TokenExpirationException + */ + public function tokenExpirationCheck(array $token): void + { + if (isset($token['expire_time']) && $token['expire_time'] <= time()) { + throw new TokenExpirationException(); + } + } +} diff --git a/app/common/library/Upload.php b/app/common/library/Upload.php new file mode 100644 index 0000000..312ae34 --- /dev/null +++ b/app/common/library/Upload.php @@ -0,0 +1,341 @@ + 'local', // 默认驱动:local=本地 + 'handler' => [], // 驱动句柄 + 'namespace' => '\\app\\common\\library\\upload\\driver\\', // 驱动类的命名空间 + ]; + + /** + * 存储子目录 + */ + protected string $topic = 'default'; + + /** + * 构造方法 + * @param ?UploadedFile $file 上传的文件 + * @param array $config 配置 + * @throws Throwable + */ + public function __construct(?UploadedFile $file = null, array $config = []) + { + $upload = Config::get('upload'); + $this->config = array_merge($upload, $config); + + if ($file) { + $this->setFile($file); + } + } + + /** + * 设置上传文件 + * @param ?UploadedFile $file + * @return Upload + * @throws Throwable + */ + public function setFile(?UploadedFile $file): Upload + { + if (empty($file)) { + throw new Exception(__('No files were uploaded')); + } + + $suffix = strtolower($file->extension()); + $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file'; + $fileInfo['suffix'] = $suffix; + $fileInfo['type'] = $file->getMime(); + $fileInfo['size'] = $file->getSize(); + $fileInfo['name'] = $file->getOriginalName(); + $fileInfo['sha1'] = $file->sha1(); + + $this->file = $file; + $this->fileInfo = $fileInfo; + return $this; + } + + /** + * 设置上传驱动 + */ + public function setDriver(string $driver): Upload + { + $this->driver['name'] = $driver; + return $this; + } + + /** + * 获取上传驱动句柄 + * @param ?string $driver 驱动名称 + * @param bool $noDriveException 找不到驱动是否抛出异常 + * @return bool|Driver + */ + public function getDriver(?string $driver = null, bool $noDriveException = true): bool|Driver + { + if (is_null($driver)) { + $driver = $this->driver['name']; + } + if (!isset($this->driver['handler'][$driver])) { + $class = $this->resolveDriverClass($driver); + if ($class) { + $this->driver['handler'][$driver] = new $class(); + } elseif ($noDriveException) { + throw new InvalidArgumentException(__('Driver %s not supported', [$driver])); + } + } + return $this->driver['handler'][$driver] ?? false; + } + + /** + * 获取驱动类 + */ + protected function resolveDriverClass(string $driver): bool|string + { + if ($this->driver['namespace'] || str_contains($driver, '\\')) { + $class = str_contains($driver, '\\') ? $driver : $this->driver['namespace'] . Str::studly($driver); + if (class_exists($class)) { + return $class; + } + } + return false; + } + + /** + * 设置存储子目录 + */ + public function setTopic(string $topic): Upload + { + $this->topic = $topic; + return $this; + } + + /** + * 检查是否是图片并设置好相关属性 + * @return bool + * @throws Throwable + */ + protected function checkIsImage(): bool + { + if (in_array($this->fileInfo['type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']) || in_array($this->fileInfo['suffix'], ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'])) { + $imgInfo = getimagesize($this->file->getPathname()); + if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) { + throw new Exception(__('The uploaded image file is not a valid image')); + } + $this->fileInfo['width'] = $imgInfo[0]; + $this->fileInfo['height'] = $imgInfo[1]; + $this->isImage = true; + return true; + } + return false; + } + + /** + * 上传的文件是否为图片 + * @return bool + */ + public function isImage(): bool + { + return $this->isImage; + } + + /** + * 获取文件后缀 + * @return string + */ + public function getSuffix(): string + { + return $this->fileInfo['suffix'] ?: 'file'; + } + + /** + * 获取文件保存路径和名称 + * @param ?string $saveName + * @param ?string $filename + * @param ?string $sha1 + * @return string + */ + public function getSaveName(?string $saveName = null, ?string $filename = null, ?string $sha1 = null): string + { + if ($filename) { + $suffix = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file'; + } else { + $suffix = $this->fileInfo['suffix']; + } + $filename = $filename ?: $this->fileInfo['name']; + $sha1 = $sha1 ?: $this->fileInfo['sha1']; + $replaceArr = [ + '{topic}' => $this->topic, + '{year}' => date("Y"), + '{mon}' => date("m"), + '{day}' => date("d"), + '{hour}' => date("H"), + '{min}' => date("i"), + '{sec}' => date("s"), + '{random}' => Random::build(), + '{random32}' => Random::build('alnum', 32), + '{fileName}' => $this->getFileNameSubstr($filename, $suffix), + '{suffix}' => $suffix, + '{.suffix}' => $suffix ? '.' . $suffix : '', + '{fileSha1}' => $sha1, + ]; + $saveName = $saveName ?: $this->config['save_name']; + return Filesystem::fsFit(str_replace(array_keys($replaceArr), array_values($replaceArr), $saveName)); + } + + /** + * 验证文件是否符合上传配置要求 + * @throws Throwable + */ + public function validates(): void + { + if (empty($this->file)) { + throw new Exception(__('No files have been uploaded or the file size exceeds the upload limit of the server')); + } + + $size = Filesystem::fileUnitToByte($this->config['max_size']); + $mime = $this->checkConfig($this->config['allowed_mime_types']); + $suffix = $this->checkConfig($this->config['allowed_suffixes']); + + // 文件大小 + $fileValidateRule = ValidateRule::fileSize($size, __('The uploaded file is too large (%sMiB), Maximum file size:%sMiB', [ + round($this->fileInfo['size'] / pow(1024, 2), 2), + round($size / pow(1024, 2), 2) + ])); + + // 文件后缀 + if ($suffix) { + $fileValidateRule->fileExt($suffix, __('The uploaded file format is not allowed')); + } + // 文件 MIME 类型 + if ($mime) { + $fileValidateRule->fileMime($mime, __('The uploaded file format is not allowed')); + } + + // 图片文件利用tp内置规则做一些额外检查 + if ($this->checkIsImage()) { + $fileValidateRule->image("{$this->fileInfo['width']},{$this->fileInfo['height']}", __('The uploaded image file is not a valid image')); + } + + Validate::failException() + ->rule([ + 'file' => $fileValidateRule, + 'topic' => ValidateRule::is('alphaDash', __('Topic format error')), + 'driver' => ValidateRule::is('alphaDash', __('Driver %s not supported', [$this->driver['name']])), + ]) + ->check([ + 'file' => $this->file, + 'topic' => $this->topic, + 'driver' => $this->driver['name'], + ]); + } + + /** + * 上传文件 + * @param ?string $saveName + * @param int $adminId + * @param int $userId + * @return array + * @throws Throwable + */ + public function upload(?string $saveName = null, int $adminId = 0, int $userId = 0): array + { + $this->validates(); + + $driver = $this->getDriver(); + $saveName = $saveName ?: $this->getSaveName(); + $params = [ + 'topic' => $this->topic, + 'admin_id' => $adminId, + 'user_id' => $userId, + 'url' => $driver->url($saveName, false), + 'width' => $this->fileInfo['width'] ?? 0, + 'height' => $this->fileInfo['height'] ?? 0, + 'name' => $this->getFileNameSubstr($this->fileInfo['name'], $this->fileInfo['suffix'], 100) . ".{$this->fileInfo['suffix']}", + 'size' => $this->fileInfo['size'], + 'mimetype' => $this->fileInfo['type'], + 'storage' => $this->driver['name'], + 'sha1' => $this->fileInfo['sha1'] + ]; + + // 附件数据入库 - 不依赖模型新增前事件,确保入库前文件已经移动完成 + $attachment = Attachment::where('sha1', $params['sha1']) + ->where('topic', $params['topic']) + ->where('storage', $params['storage']) + ->find(); + if ($attachment && $driver->exists($attachment->url)) { + $attachment->quote++; + $attachment->last_upload_time = time(); + } else { + $driver->save($this->file, $saveName); + $attachment = new Attachment(); + $attachment->data(array_filter($params)); + } + $attachment->save(); + return $attachment->toArray(); + } + + /** + * 获取文件名称字符串的子串 + */ + public function getFileNameSubstr(string $fileName, string $suffix, int $length = 15): string + { + // 对 $fileName 中不利于传输的字符串进行过滤 + $pattern = "/[\s:@#?&\/=',+]+/u"; + $fileName = str_replace(".$suffix", '', $fileName); + $fileName = preg_replace($pattern, '', $fileName); + return mb_substr(htmlspecialchars(strip_tags($fileName)), 0, $length); + } + + /** + * 检查配置项,将 string 类型的配置转换为 array,并且将所有字母转换为小写 + */ + protected function checkConfig($configItem): array + { + if (is_array($configItem)) { + return array_map('strtolower', $configItem); + } else { + return explode(',', strtolower($configItem)); + } + } +} diff --git a/app/common/library/token/Driver.php b/app/common/library/token/Driver.php new file mode 100644 index 0000000..85ce40f --- /dev/null +++ b/app/common/library/token/Driver.php @@ -0,0 +1,92 @@ +handler; + } + + /** + * @param string $token + * @return string + */ + protected function getEncryptedToken(string $token): string + { + $config = Config::get('buildadmin.token'); + return hash_hmac($config['algo'], $token, $config['key']); + } + + /** + * @param int $expireTime + * @return int + */ + protected function getExpiredIn(int $expireTime): int + { + return $expireTime ? max(0, $expireTime - time()) : 365 * 86400; + } +} \ No newline at end of file diff --git a/app/common/library/token/TokenExpirationException.php b/app/common/library/token/TokenExpirationException.php new file mode 100644 index 0000000..ce91e6d --- /dev/null +++ b/app/common/library/token/TokenExpirationException.php @@ -0,0 +1,16 @@ +options = array_merge($this->options, $options); + } + + if ($this->options['name']) { + $this->handler = Db::connect($this->options['name'])->name($this->options['table']); + } else { + $this->handler = Db::name($this->options['table']); + } + } + + /** + * @throws Throwable + */ + public function set(string $token, string $type, int $userId, ?int $expire = null): bool + { + if (is_null($expire)) { + $expire = $this->options['expire']; + } + $expireTime = $expire !== 0 ? time() + $expire : 0; + $token = $this->getEncryptedToken($token); + $this->handler->insert([ + 'token' => $token, + 'type' => $type, + 'user_id' => $userId, + 'create_time' => time(), + 'expire_time' => $expireTime, + ]); + + // 每隔48小时清理一次过期Token + $time = time(); + $lastCacheCleanupTime = Cache::get('last_cache_cleanup_time'); + if (!$lastCacheCleanupTime || $lastCacheCleanupTime < $time - 172800) { + Cache::set('last_cache_cleanup_time', $time); + $this->handler->where('expire_time', '<', time())->where('expire_time', '>', 0)->delete(); + } + return true; + } + + /** + * @throws Throwable + */ + public function get(string $token): array + { + $data = $this->handler->where('token', $this->getEncryptedToken($token))->find(); + if (!$data) { + return []; + } + + $data['token'] = $token; // 返回未加密的token给客户端使用 + $data['expires_in'] = $this->getExpiredIn($data['expire_time'] ?? 0); // 返回剩余有效时间 + return $data; + } + + /** + * @throws Throwable + */ + public function check(string $token, string $type, int $userId): bool + { + $data = $this->get($token); + if (!$data || ($data['expire_time'] && $data['expire_time'] <= time())) return false; + return $data['type'] == $type && $data['user_id'] == $userId; + } + + /** + * @throws Throwable + */ + public function delete(string $token): bool + { + $this->handler->where('token', $this->getEncryptedToken($token))->delete(); + return true; + } + + /** + * @throws Throwable + */ + public function clear(string $type, int $userId): bool + { + $this->handler->where('type', $type)->where('user_id', $userId)->delete(); + return true; + } +} \ No newline at end of file diff --git a/app/common/library/token/driver/Redis.php b/app/common/library/token/driver/Redis.php new file mode 100644 index 0000000..fa9ea89 --- /dev/null +++ b/app/common/library/token/driver/Redis.php @@ -0,0 +1,146 @@ +options = array_merge($this->options, $options); + } + $this->handler = new \Redis(); + if ($this->options['persistent']) { + $this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']); + } else { + $this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']); + } + + if ('' != $this->options['password']) { + $this->handler->auth($this->options['password']); + } + + if (false !== $this->options['select']) { + $this->handler->select($this->options['select']); + } + } + + /** + * @throws Throwable + */ + public function set(string $token, string $type, int $userId, ?int $expire = null): bool + { + if (is_null($expire)) { + $expire = $this->options['expire']; + } + $expireTime = $expire !== 0 ? time() + $expire : 0; + $token = $this->getEncryptedToken($token); + $tokenInfo = [ + 'token' => $token, + 'type' => $type, + 'user_id' => $userId, + 'create_time' => time(), + 'expire_time' => $expireTime, + ]; + $tokenInfo = json_encode($tokenInfo, JSON_UNESCAPED_UNICODE); + if ($expire) { + $expire += $this->expiredHold; + $result = $this->handler->setex($token, $expire, $tokenInfo); + } else { + $result = $this->handler->set($token, $tokenInfo); + } + $this->handler->sAdd($this->getUserKey($type, $userId), $token); + return $result; + } + + /** + * @throws Throwable + */ + public function get(string $token): array + { + $key = $this->getEncryptedToken($token); + $data = $this->handler->get($key); + if (is_null($data) || false === $data) { + return []; + } + $data = json_decode($data, true); + + $data['token'] = $token; // 返回未加密的token给客户端使用 + $data['expires_in'] = $this->getExpiredIn($data['expire_time'] ?? 0); // 过期时间 + return $data; + } + + /** + * @throws Throwable + */ + public function check(string $token, string $type, int $userId): bool + { + $data = $this->get($token); + if (!$data || ($data['expire_time'] && $data['expire_time'] <= time())) return false; + return $data['type'] == $type && $data['user_id'] == $userId; + } + + /** + * @throws Throwable + */ + public function delete(string $token): bool + { + $data = $this->get($token); + if ($data) { + $key = $this->getEncryptedToken($token); + $this->handler->del($key); + $this->handler->sRem($this->getUserKey($data['type'], $data['user_id']), $key); + } + return true; + } + + /** + * @throws Throwable + */ + public function clear(string $type, int $userId): bool + { + $userKey = $this->getUserKey($type, $userId); + $keys = $this->handler->sMembers($userKey); + $this->handler->del($userKey); + $this->handler->del($keys); + return true; + } + + /** + * 获取会员的key + * @param $type + * @param $userId + * @return string + */ + protected function getUserKey($type, $userId): string + { + return $this->options['prefix'] . $type . '-' . $userId; + } +} \ No newline at end of file diff --git a/app/common/library/upload/Driver.php b/app/common/library/upload/Driver.php new file mode 100644 index 0000000..f0a8a3e --- /dev/null +++ b/app/common/library/upload/Driver.php @@ -0,0 +1,47 @@ +options = Config::get('filesystem.disks.public'); + if (!empty($options)) { + $this->options = array_merge($this->options, $options); + } + } + + /** + * 保存文件 + * @param UploadedFile $file + * @param string $saveName + * @return bool + */ + public function save(UploadedFile $file, string $saveName): bool + { + $savePathInfo = pathinfo($saveName); + $saveFullPath = $this->getFullPath($saveName); + + // cgi 直接 move + if (request()->isCgi()) { + $file->move($saveFullPath, $savePathInfo['basename']); + return true; + } + + set_error_handler(function ($type, $msg) use (&$error) { + $error = $msg; + }); + + // 建立文件夹 + if (!is_dir($saveFullPath) && !mkdir($saveFullPath, 0755, true)) { + restore_error_handler(); + throw new FileException(sprintf('Unable to create the "%s" directory (%s)', $saveFullPath, strip_tags($error))); + } + + // cli 使用 rename + $saveName = $this->getFullPath($saveName, true); + if (!rename($file->getPathname(), $saveName)) { + restore_error_handler(); + throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $file->getPathname(), $saveName, strip_tags($error))); + } + + restore_error_handler(); + @chmod($saveName, 0666 & ~umask()); + return true; + } + + /** + * 删除文件 + * @param string $saveName + * @return bool + */ + public function delete(string $saveName): bool + { + $saveFullName = $this->getFullPath($saveName, true); + if ($this->exists($saveFullName)) { + @unlink($saveFullName); + } + Filesystem::delEmptyDir(dirname($saveFullName)); + return true; + } + + /** + * 获取资源 URL 地址 + * @param string $saveName 资源保存名称 + * @param string|bool $domain 是否携带域名 或者直接传入域名 + * @param string $default 默认值 + * @return string + */ + public function url(string $saveName, string|bool $domain = true, string $default = ''): string + { + $saveName = $this->clearRootPath($saveName); + + if ($domain === true) { + $domain = '//' . request()->host(); + } elseif ($domain === false) { + $domain = ''; + } + + $saveName = $saveName ?: $default; + if (!$saveName) return $domain; + + $regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i"; + if (preg_match('/^http(s)?:\/\//', $saveName) || preg_match($regex, $saveName) || $domain === false) { + return $saveName; + } + return str_replace('\\', '/', $domain . $saveName); + } + + /** + * 文件是否存在 + * @param string $saveName + * @return bool + */ + public function exists(string $saveName): bool + { + $saveFullName = $this->getFullPath($saveName, true); + return file_exists($saveFullName); + } + + /** + * 获取文件的完整存储路径 + * @param string $saveName + * @param bool $baseName 是否包含文件名 + * @return string + */ + public function getFullPath(string $saveName, bool $baseName = false): string + { + $savePathInfo = pathinfo($saveName); + $root = $this->getRootPath(); + $dirName = $savePathInfo['dirname'] . '/'; + + // 以 root 路径开始时单独返回,避免重复调用此方法时造成 $dirName 的错误拼接 + if (str_starts_with($saveName, $root)) { + return Filesystem::fsFit($baseName || !isset($savePathInfo['extension']) ? $saveName : $dirName); + } + + return Filesystem::fsFit($root . $dirName . ($baseName ? $savePathInfo['basename'] : '')); + } + + public function clearRootPath(string $saveName): string + { + return str_replace($this->getRootPath(), '', Filesystem::fsFit($saveName)); + } + + public function getRootPath(): string + { + return Filesystem::fsFit(str_replace($this->options['url'], '', $this->options['root'])); + } +} \ No newline at end of file diff --git a/app/common/middleware/AdminLog.php b/app/common/middleware/AdminLog.php new file mode 100644 index 0000000..2525460 --- /dev/null +++ b/app/common/middleware/AdminLog.php @@ -0,0 +1,24 @@ +isPost() || $request->isDelete()) && Config::get('buildadmin.auto_write_admin_log')) { + AdminLogModel::instance()->record(); + } + return $response; + } +} \ No newline at end of file diff --git a/app/common/middleware/AllowCrossDomain.php b/app/common/middleware/AllowCrossDomain.php new file mode 100644 index 0000000..9fa0401 --- /dev/null +++ b/app/common/middleware/AllowCrossDomain.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\common\middleware; + +use Closure; +use think\Request; +use think\Response; +use think\facade\Config; + +/** + * 跨域请求支持 + * 安全起见,只支持了配置中的域名 + */ +class AllowCrossDomain +{ + protected array $header = [ + 'Access-Control-Allow-Credentials' => 'true', + 'Access-Control-Max-Age' => 1800, + 'Access-Control-Allow-Methods' => '*', + 'Access-Control-Allow-Headers' => '*', + ]; + + /** + * 跨域请求检测 + * @access public + * @param Request $request + * @param Closure $next + * @param array|null $header + * @return Response + */ + public function handle(Request $request, Closure $next, ?array $header = []): Response + { + $header = !empty($header) ? array_merge($this->header, $header) : $this->header; + + $origin = $request->header('origin'); + if ($origin && !isset($header['Access-Control-Allow-Origin'])) { + $info = parse_url($origin); + + // 获取跨域配置 + $corsDomain = explode(',', Config::get('buildadmin.cors_request_domain')); + $corsDomain[] = $request->host(true); + + if (in_array("*", $corsDomain) || in_array($origin, $corsDomain) || (isset($info['host']) && in_array($info['host'], $corsDomain))) { + $header['Access-Control-Allow-Origin'] = $origin; + } + } + + if ($request->isOptions()) { + return response('', 204, $header); + } + + $request->allowCrossDomainHeaders = $header; + + return $next($request)->header($header); + } +} diff --git a/app/common/model/Attachment.php b/app/common/model/Attachment.php new file mode 100644 index 0000000..cc8a461 --- /dev/null +++ b/app/common/model/Attachment.php @@ -0,0 +1,115 @@ +getDriver($row['storage'], false); + return $driver ? $driver->url($row['url']) : full_url($row['url']); + } + + /** + * 新增前 + * @throws Throwable + */ + protected static function onBeforeInsert($model): bool + { + $repeat = $model->where([ + ['sha1', '=', $model->sha1], + ['topic', '=', $model->topic], + ['storage', '=', $model->storage], + ])->find(); + if ($repeat) { + $driver = self::$upload->getDriver($repeat->storage, false); + if ($driver && !$driver->exists($repeat->url)) { + $repeat->delete(); + return true; + } else { + $repeat->quote++; + $repeat->last_upload_time = time(); + $repeat->save(); + return false; + } + } + return true; + } + + /** + * 新增后 + */ + protected static function onAfterInsert($model): void + { + Event::trigger('AttachmentInsert', $model); + + if (!$model->last_upload_time) { + $model->quote = 1; + $model->last_upload_time = time(); + $model->save(); + } + } + + /** + * 删除后 + */ + protected static function onAfterDelete($model): void + { + Event::trigger('AttachmentDel', $model); + + $driver = self::$upload->getDriver($model->storage, false); + if ($driver && $driver->exists($model->url)) { + $driver->delete($model->url); + } + } + + public function admin(): BelongsTo + { + return $this->belongsTo(Admin::class); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} \ No newline at end of file diff --git a/app/common/model/Config.php b/app/common/model/Config.php new file mode 100644 index 0000000..a9a8682 --- /dev/null +++ b/app/common/model/Config.php @@ -0,0 +1,83 @@ +find()) return false; + return self::removeArrayItem('config_group', $key); + } + + /** + * 添加系统快捷配置入口 + * @throws Throwable + */ + public static function addQuickEntrance(string $key, string $value): bool + { + return self::addArrayItem('config_quick_entrance', $key, $value); + } + + /** + * 删除系统快捷配置入口 + * @throws Throwable + */ + public static function removeQuickEntrance(string $key): bool + { + return self::removeArrayItem('config_quick_entrance', $key); + } + + /** + * 为Array类型的配置项添加元素 + * @throws Throwable + */ + public static function addArrayItem(string $name, string $key, string $value): bool + { + $configRow = adminConfigModel::where('name', $name)->find(); + foreach ($configRow->value as $item) { + if ($item['key'] == $key) { + return false; + } + } + $configRow->value = array_merge($configRow->value, [['key' => $key, 'value' => $value]]); + $configRow->save(); + return true; + } + + /** + * 删除Array类型配置项的一个元素 + * @throws Throwable + */ + public static function removeArrayItem(string $name, string $key): bool + { + $configRow = adminConfigModel::where('name', $name)->find(); + $configRowValue = $configRow->value; + foreach ($configRowValue as $iKey => $item) { + if ($item['key'] == $key) { + unset($configRowValue[$iKey]); + } + } + $configRow->value = $configRowValue; + $configRow->save(); + return true; + } + +} \ No newline at end of file diff --git a/app/common/model/User.php b/app/common/model/User.php new file mode 100644 index 0000000..09d7f28 --- /dev/null +++ b/app/common/model/User.php @@ -0,0 +1,51 @@ +where(['id' => $uid])->update(['password' => hash_password($newPassword), 'salt' => '']); + } + + public function getMoneyAttr($value): string + { + return bcdiv($value, 100, 2); + } + + /** + * 用户的余额是不可以直接进行修改的,请通过 UserMoneyLog 模型插入记录来实现自动修改余额 + * 此处定义上 money 的修改器仅为防止直接对余额的修改造成数据错乱 + */ + public function setMoneyAttr($value): string + { + return bcmul($value, 100, 2); + } +} \ No newline at end of file diff --git a/app/common/model/UserMoneyLog.php b/app/common/model/UserMoneyLog.php new file mode 100644 index 0000000..c465e71 --- /dev/null +++ b/app/common/model/UserMoneyLog.php @@ -0,0 +1,41 @@ +moduleAppInit(); + } + + public function moduleAppInit(): void + { + $installed = Server::installedList(root_path() . 'modules' . DIRECTORY_SEPARATOR); + foreach ($installed as $item) { + if ($item['state'] != 1) { + continue; + } + $moduleClass = Server::getClass($item['uid']); + if (class_exists($moduleClass)) { + if (method_exists($moduleClass, 'AppInit')) { + Event::listen('AppInit', function () use ($moduleClass) { + $handle = new $moduleClass(); + $handle->AppInit(); + }); + } + } + } + } +} \ No newline at end of file diff --git a/app/event.php b/app/event.php new file mode 100644 index 0000000..95717d8 --- /dev/null +++ b/app/event.php @@ -0,0 +1,17 @@ + [ + ], + + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [], + 'LogLevel' => [], + 'LogWrite' => [], + ], + + 'subscribe' => [ + ], +]; diff --git a/app/middleware.php b/app/middleware.php new file mode 100644 index 0000000..456f05b --- /dev/null +++ b/app/middleware.php @@ -0,0 +1,11 @@ + Request::class, + 'think\exception\Handle' => ExceptionHandle::class, +]; diff --git a/app/service.php b/app/service.php new file mode 100644 index 0000000..7280ac7 --- /dev/null +++ b/app/service.php @@ -0,0 +1,11 @@ +=8.2.0", + "topthink/framework": "8.1.4", + "topthink/think-orm": "3.0.33", + "topthink/think-multi-app": "1.1.1", + "topthink/think-throttle": "2.0.2", + "topthink/think-migration": "3.1.1", + "symfony/http-foundation": "^7.3|v8.0", + "phpmailer/phpmailer": "^6.8", + "guzzlehttp/guzzle": "^7.8.1", + "build-admin/anti-xss": "dev-master", + "voku/portable-utf8": "dev-master", + "nelexa/zip": "^4.0.0", + "ext-bcmath": "*", + "ext-iconv": "*", + "ext-json": "*", + "ext-gd": "*" + }, + "require-dev": { + "symfony/var-dumper": "^5.4", + "topthink/think-trace": "^1.0" + }, + "autoload": { + "psr-4": { + "app\\": "app", + "modules\\": "modules" + }, + "psr-0": { + "": "extend/" + } + }, + "config": { + "preferred-install": "dist" + }, + "scripts": { + "post-autoload-dump": [ + "@php think service:discover", + "@php think vendor:publish" + ] + } +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..148f45b --- /dev/null +++ b/config/app.php @@ -0,0 +1,32 @@ + env('app.host', ''), + // 应用的命名空间 + 'app_namespace' => '', + // 是否启用路由 + 'with_route' => true, + // 默认应用 + 'default_app' => 'api', + // 默认时区 + 'default_timezone' => 'Asia/Shanghai', + + // 应用映射(自动多应用模式有效) + 'app_map' => [], + // 域名绑定(自动多应用模式有效) + 'domain_bind' => [], + // 禁止URL访问的应用列表(自动多应用模式有效) + 'deny_app_list' => ['common'], + + // 异常页面的模板文件 + 'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl', + + // 错误显示信息,非调试模式有效 + 'error_message' => '页面错误!请稍后再试~', + // 显示错误信息 + 'show_error_msg' => false, +]; diff --git a/config/buildadmin.php b/config/buildadmin.php new file mode 100644 index 0000000..b1167fc --- /dev/null +++ b/config/buildadmin.php @@ -0,0 +1,86 @@ + 'localhost,127.0.0.1', + // 是否开启会员登录验证码 + 'user_login_captcha' => true, + // 是否开启管理员登录验证码 + 'admin_login_captcha' => true, + // 会员登录失败可重试次数,false则无限 + 'user_login_retry' => 10, + // 管理员登录失败可重试次数,false则无限 + 'admin_login_retry' => 10, + // 开启管理员单处登录它处失效 + 'admin_sso' => false, + // 开启会员单处登录它处失效 + 'user_sso' => false, + // 会员登录态保持时间(非刷新token,3天) + 'user_token_keep_time' => 60 * 60 * 24 * 3, + // 管理员登录态保持时间(非刷新token,3天) + 'admin_token_keep_time' => 60 * 60 * 24 * 3, + // 开启前台会员中心 + 'open_member_center' => true, + // 模块纯净安装(安装时移动模块文件而不是复制) + 'module_pure_install' => true, + // 点选验证码配置 + 'click_captcha' => [ + // 模式:text=文字,icon=图标(若只有icon则适用于国际化站点) + 'mode' => ['text', 'icon'], + // 长度 + 'length' => 2, + // 混淆点长度 + 'confuse_length' => 2, + ], + // 代理服务器IP(\think\Request 类将尝试获取这些代理服务器发送过来的真实IP) + 'proxy_server_ip' => [], + // Token 配置 + 'token' => [ + // 默认驱动方式 + 'default' => 'mysql', + // 加密key + 'key' => 'tcbDgmqLVzuAdNH39o0QnhOisvSCFZ7I', + // 加密方式 + 'algo' => 'ripemd160', + // 驱动 + 'stores' => [ + 'mysql' => [ + 'type' => 'Mysql', + // 留空表示使用默认的 Mysql 数据库,也可以填写其他数据库连接配置的`name` + 'name' => '', + // 存储token的表名 + 'table' => 'token', + // 默认 token 有效时间 + 'expire' => 2592000, + ], + 'redis' => [ + 'type' => 'Redis', + 'host' => '127.0.0.1', + 'port' => 6379, + 'password' => '', + // Db索引,非 0 以避免数据被意外清理 + 'select' => 1, + 'timeout' => 0, + // 默认 token 有效时间 + 'expire' => 2592000, + 'persistent' => false, + 'prefix' => 'tk:', + ], + ] + ], + // 自动写入管理员操作日志 + 'auto_write_admin_log' => true, + // 缺省头像图片路径 + 'default_avatar' => '/static/images/avatar.png', + // 内容分发网络URL,末尾不带`/` + 'cdn_url' => '', + // 内容分发网络URL参数,将自动添加 `?`,之后拼接到 cdn_url 的结尾(例如 `imageMogr2/format/heif`) + 'cdn_url_params' => '', + // 版本号 + 'version' => 'v2.3.6', + // 中心接口地址(用于请求模块市场的数据等用途) + 'api_url' => 'https://api.buildadmin.com', +]; \ No newline at end of file diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..a8d69d2 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,29 @@ + env('cache.driver', 'file'), + + // 缓存连接方式配置 + 'stores' => [ + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => '', + // 缓存前缀 + 'prefix' => '', + // 缓存有效期 0表示永久缓存 + 'expire' => 0, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + // 更多的缓存连接 + ], +]; diff --git a/config/console.php b/config/console.php new file mode 100644 index 0000000..3368757 --- /dev/null +++ b/config/console.php @@ -0,0 +1,8 @@ + [], +]; diff --git a/config/cookie.php b/config/cookie.php new file mode 100644 index 0000000..d3b3aab --- /dev/null +++ b/config/cookie.php @@ -0,0 +1,20 @@ + 0, + // cookie 保存路径 + 'path' => '/', + // cookie 有效域名 + 'domain' => '', + // cookie 启用安全传输 + 'secure' => false, + // httponly设置 + 'httponly' => false, + // 是否使用 setcookie + 'setcookie' => true, + // samesite 设置,支持 'strict' 'lax' + 'samesite' => '', +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..96d77e9 --- /dev/null +++ b/config/database.php @@ -0,0 +1,63 @@ + env('database.driver', 'mysql'), + + // 自定义时间查询规则 + 'time_query_rule' => [], + + // 自动写入时间戳字段 + // true为自动识别类型 false关闭 + // 字符串则明确指定时间字段类型 支持 int timestamp datetime date + 'auto_timestamp' => true, + + // 时间字段取出后的默认时间格式 + 'datetime_format' => false, + + // 时间字段配置 配置格式:create_time,update_time + 'datetime_field' => '', + + // 数据库连接配置信息 + 'connections' => [ + 'mysql' => [ + // 数据库类型 + 'type' => env('database.type', 'mysql'), + // 服务器地址 + 'hostname' => env('database.hostname', '127.0.0.1'), + // 数据库名 + 'database' => env('database.database', 'buildadmin_com'), + // 用户名 + 'username' => env('database.username', 'root'), + // 密码 + 'password' => env('database.password', 'admin888'), + // 端口 + 'hostport' => env('database.hostport', '3306'), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8mb4 + 'charset' => env('database.charset', 'utf8mb4'), + // 数据库表前缀 + 'prefix' => env('database.prefix', ''), + + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => true, + // 监听SQL + 'trigger_sql' => env('app_debug', false), + // 开启字段缓存 + 'fields_cache' => false, + ], + + // 更多的数据库配置信息 + ], +]; diff --git a/config/filesystem.php b/config/filesystem.php new file mode 100644 index 0000000..965297e --- /dev/null +++ b/config/filesystem.php @@ -0,0 +1,24 @@ + env('filesystem.driver', 'local'), + // 磁盘列表 + 'disks' => [ + 'local' => [ + 'type' => 'local', + 'root' => app()->getRuntimePath() . 'storage', + ], + 'public' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage', + // 可见性 + 'visibility' => 'public', + ], + // 更多的磁盘配置信息 + ], +]; diff --git a/config/lang.php b/config/lang.php new file mode 100644 index 0000000..497718a --- /dev/null +++ b/config/lang.php @@ -0,0 +1,27 @@ + env('lang.default_lang', 'zh-cn'), + // 允许的语言列表 + 'allow_lang_list' => ['zh-cn', 'en'], + // 多语言自动侦测变量名 + 'detect_var' => 'lang', + // 是否使用Cookie记录-开启后 ob_flush() 等操作会报错 + 'use_cookie' => false, + // 多语言cookie变量 + 'cookie_var' => 'think_lang', + // 多语言header变量 + 'header_var' => 'think-lang', + // 扩展语言包 + 'extend_list' => [], + // Accept-Language转义为对应语言包名称 + 'accept_language' => [ + 'zh-hans-cn' => 'zh-cn', + ], + // 是否支持语言分组 + 'allow_group' => false, +]; diff --git a/config/log.php b/config/log.php new file mode 100644 index 0000000..ea24ff9 --- /dev/null +++ b/config/log.php @@ -0,0 +1,45 @@ + env('log.channel', 'file'), + // 日志记录级别 + 'level' => [], + // 日志类型记录的通道 ['error'=>'email',...] + 'type_channel' => [], + // 关闭全局日志写入 + 'close' => false, + // 全局日志处理 支持闭包 + 'processor' => null, + + // 日志通道列表 + 'channels' => [ + 'file' => [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => '', + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => false, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ], + // 其它日志通道配置 + ], + +]; diff --git a/config/middleware.php b/config/middleware.php new file mode 100644 index 0000000..7e1972f --- /dev/null +++ b/config/middleware.php @@ -0,0 +1,8 @@ + [], + // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行 + 'priority' => [], +]; diff --git a/config/route.php b/config/route.php new file mode 100644 index 0000000..2f4cd12 --- /dev/null +++ b/config/route.php @@ -0,0 +1,45 @@ + '/', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + // URL普通方式参数 用于自动生成 + 'url_common_param' => true, + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => false, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => false, + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache_key' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 默认JSONP格式返回的处理方法 + 'default_jsonp_handler' => 'jsonpReturn', + // 默认JSONP处理方法 + 'var_jsonp_handler' => 'callback', +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..c1ef6e1 --- /dev/null +++ b/config/session.php @@ -0,0 +1,19 @@ + 'PHPSESSID', + // SESSION_ID的提交变量,解决flash上传跨域 + 'var_session_id' => '', + // 驱动方式 支持file cache + 'type' => 'file', + // 存储连接标识 当type使用cache的时候有效 + 'store' => null, + // 过期时间 + 'expire' => 1440, + // 前缀 + 'prefix' => '', +]; diff --git a/config/terminal.php b/config/terminal.php new file mode 100644 index 0000000..006142e --- /dev/null +++ b/config/terminal.php @@ -0,0 +1,169 @@ +param('extend') 取值,以 ~~ 分割多个参数后使用 sprintf 函数替换进完整的命令字符串 +// | 3. 命令主体千万不能使用 %s %f 等占位符,参数使用占位符时,系统将自动使用 escapeshellarg 对参数值进行转义来防止命令注入攻击 +// +---------------------------------------------------------------------- + +return [ + // npm包管理器 + 'npm_package_manager' => 'pnpm', + // 允许执行的命令 + 'commands' => [ + // 数据库迁移命令 + 'migrate' => [ + 'run' => [ + 'cwd' => '', + 'command' => 'php think migrate:run', + 'notes' => 'Start the database migration' + ], + 'rollback' => 'php think migrate:rollback', + 'breakpoint' => 'php think migrate:breakpoint', + ], + // 安装包管理器的命令 + 'install' => [ + 'cnpm' => 'npm install cnpm -g --registry=https://registry.npmmirror.com', + 'yarn' => 'npm install -g yarn', + 'pnpm' => 'npm install -g pnpm', + 'ni' => 'npm install -g @antfu/ni', + ], + // 查看版本的命令 + 'version' => [ + 'npm' => 'npm -v', + 'cnpm' => 'cnpm -v', + 'yarn' => 'yarn -v', + 'pnpm' => 'pnpm -v', + 'node' => 'node -v', + ], + // 测试命令 + 'test' => [ + 'npm' => [ + 'cwd' => 'public/npm-install-test', + 'command' => 'npm install', + ], + 'cnpm' => [ + 'cwd' => 'public/npm-install-test', + 'command' => 'cnpm install', + ], + 'yarn' => [ + 'cwd' => 'public/npm-install-test', + 'command' => 'yarn install', + ], + 'pnpm' => [ + 'cwd' => 'public/npm-install-test', + 'command' => 'pnpm install', + ], + 'ni' => [ + 'cwd' => 'public/npm-install-test', + 'command' => 'ni install', + ], + ], + // 安装 WEB 依赖包 + 'web-install' => [ + 'npm' => [ + 'cwd' => 'web', + 'command' => 'npm install', + ], + 'cnpm' => [ + 'cwd' => 'web', + 'command' => 'cnpm install', + ], + 'yarn' => [ + 'cwd' => 'web', + 'command' => 'yarn install', + ], + 'pnpm' => [ + 'cwd' => 'web', + 'command' => 'pnpm install', + ], + 'ni' => [ + 'cwd' => 'web', + 'command' => 'ni install', + ], + ], + // 安装 Web-Nuxt 依赖包 + 'nuxt-install' => [ + 'npm' => [ + 'cwd' => 'web-nuxt', + 'command' => 'npm install', + ], + 'cnpm' => [ + 'cwd' => 'web-nuxt', + 'command' => 'cnpm install', + ], + 'yarn' => [ + 'cwd' => 'web-nuxt', + 'command' => 'yarn install', + ], + 'pnpm' => [ + 'cwd' => 'web-nuxt', + 'command' => 'pnpm install', + ], + 'ni' => [ + 'cwd' => 'web-nuxt', + 'command' => 'ni install', + ], + ], + // 构建 WEB 端 + 'web-build' => [ + 'npm' => [ + 'cwd' => 'web', + 'command' => 'npm run build', + 'notes' => 'Start executing the build command of the web project', + ], + 'cnpm' => [ + 'cwd' => 'web', + 'command' => 'cnpm run build', + 'notes' => 'Start executing the build command of the web project', + ], + 'yarn' => [ + 'cwd' => 'web', + 'command' => 'yarn run build', + 'notes' => 'Start executing the build command of the web project', + ], + 'pnpm' => [ + 'cwd' => 'web', + 'command' => 'pnpm run build', + 'notes' => 'Start executing the build command of the web project', + ], + 'ni' => [ + 'cwd' => 'web', + 'command' => 'nr build', + 'notes' => 'Start executing the build command of the web project', + ], + ], + // 设置 NPM 源 + 'set-npm-registry' => [ + 'npm' => 'npm config set registry https://registry.npmjs.org/ && npm config get registry', + 'taobao' => 'npm config set registry https://registry.npmmirror.com/ && npm config get registry', + 'tencent' => 'npm config set registry https://mirrors.cloud.tencent.com/npm/ && npm config get registry' + ], + // 设置 composer 源 + 'set-composer-registry' => [ + 'composer' => 'composer config --unset repos.packagist', + 'aliyun' => 'composer config -g repos.packagist composer https://mirrors.aliyun.com/composer/', + 'tencent' => 'composer config -g repos.packagist composer https://mirrors.cloud.tencent.com/composer/', + 'huawei' => 'composer config -g repos.packagist composer https://mirrors.huaweicloud.com/repository/php/', + 'kkame' => 'composer config -g repos.packagist composer https://packagist.kr', + ], + 'npx' => [ + 'prettier' => [ + 'cwd' => 'web', + 'command' => 'npx prettier --write %s', + 'notes' => 'Start formatting the web project code', + ], + ], + 'composer' => [ + 'update' => [ + 'cwd' => '', + 'command' => 'composer update --no-interaction', + 'notes' => 'Start installing the composer dependencies' + ] + ], + 'ping' => [ + 'baidu' => 'ping baidu.com', + 'localhost' => 'ping 127.0.0.1 -n 6', + ] + ], +]; diff --git a/config/throttle.php b/config/throttle.php new file mode 100644 index 0000000..fc004f3 --- /dev/null +++ b/config/throttle.php @@ -0,0 +1,42 @@ + 'throttle_', + // 缓存的键,true 表示使用来源ip + 'key' => true, + // 要被限制的请求类型, eg: GET POST PUT DELETE HEAD 等 + 'visit_method' => ['GET', 'HEAD'], + // 设置访问频率,例如 '10/m' 指的是允许每分钟请求10次;'10/60'指允许每60秒请求10次。值 null 表示不限制, eg: null 10/m 20/h 300/d 200/300 + 'visit_rate' => '120/m', + /* + * 设置节流算法,组件提供了四种算法: + * - CounterFixed :计数固定窗口 + * - CounterSlider: 滑动窗口 + * - TokenBucket : 令牌桶算法 + * - LeakyBucket : 漏桶限流算法 + */ + 'driver_name' => CounterFixed::class, + // 响应体中设置速率限制的头部信息,含义见:https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting + 'visit_enable_show_rate_limit' => true, + // 访问受限时返回的响应 + 'visit_fail_response' => function (Throttle $throttle, Request $request, int $wait_seconds) { + return Response::create([ + 'code' => 0, + 'msg' => 'Please do not request frequently. Try again in ' . $wait_seconds . ' seconds.', + ], 'json')->header([ + 'Access-Control-Allow-Credentials' => 'true', + 'Access-Control-Max-Age' => 0, + 'Access-Control-Allow-Methods' => '*', + 'Access-Control-Allow-Headers' => '*', + 'Access-Control-Allow-Origin' => '*', + ]); + }, +]; diff --git a/config/trace.php b/config/trace.php new file mode 100644 index 0000000..fad2392 --- /dev/null +++ b/config/trace.php @@ -0,0 +1,10 @@ + 'Html', + // 读取的日志通道名 + 'channel' => '', +]; diff --git a/config/upload.php b/config/upload.php new file mode 100644 index 0000000..8b5e216 --- /dev/null +++ b/config/upload.php @@ -0,0 +1,21 @@ + '10mb', + // 文件保存格式化方法:topic=存储子目录,fileName=文件名前15个字符 + 'save_name' => '/storage/{topic}/{year}{mon}{day}/{fileName}{fileSha1}{.suffix}', + + /** + * 上传文件的后缀和 MIME类型 白名单 + * 0. 永远使用最少配置 + * 1. 此处不支持通配符 + * 2. 千万不要允许 php,php5,.htaccess,.user.ini 等可执行或配置文件 + * 3. 允许 pdf,ppt,docx 等可能含有脚本的文件时,请先从服务器配置此类文件直接下载而不是预览 + */ + 'allowed_suffixes' => 'jpg,png,bmp,jpeg,gif,webp,zip,rar,wav,mp4,mp3', + 'allowed_mime_types' => [], +]; \ No newline at end of file diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..01259a0 --- /dev/null +++ b/config/view.php @@ -0,0 +1,25 @@ + 'Think', + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view', + // 模板后缀 + 'view_suffix' => 'html', + // 模板文件名分隔符 + 'view_depr' => DIRECTORY_SEPARATOR, + // 模板引擎普通标签开始标记 + 'tpl_begin' => '{', + // 模板引擎普通标签结束标记 + 'tpl_end' => '}', + // 标签库标签开始标记 + 'taglib_begin' => '{', + // 标签库标签结束标记 + 'taglib_end' => '}', +]; diff --git a/database/migrations/20230620180908_install.php b/database/migrations/20230620180908_install.php new file mode 100644 index 0000000..2884854 --- /dev/null +++ b/database/migrations/20230620180908_install.php @@ -0,0 +1,575 @@ +admin(); + $this->adminGroup(); + $this->adminGroupAccess(); + $this->adminLog(); + $this->area(); + $this->attachment(); + $this->captcha(); + $this->config(); + $this->menuRule(); + $this->securityDataRecycle(); + $this->securityDataRecycleLog(); + $this->securitySensitiveData(); + $this->securitySensitiveDataLog(); + $this->testBuild(); + $this->token(); + $this->user(); + $this->userGroup(); + $this->userMoneyLog(); + $this->userRule(); + $this->userScoreLog(); + $this->crudLog(); + } + + public function admin(): void + { + if (!$this->hasTable('admin')) { + $table = $this->table('admin', [ + 'id' => false, + 'comment' => '管理员表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('username', 'string', ['limit' => 20, 'default' => '', 'comment' => '用户名', 'null' => false]) + ->addColumn('nickname', 'string', ['limit' => 50, 'default' => '', 'comment' => '昵称', 'null' => false]) + ->addColumn('avatar', 'string', ['limit' => 255, 'default' => '', 'comment' => '头像', 'null' => false]) + ->addColumn('email', 'string', ['limit' => 50, 'default' => '', 'comment' => '邮箱', 'null' => false]) + ->addColumn('mobile', 'string', ['limit' => 11, 'default' => '', 'comment' => '手机', 'null' => false]) + ->addColumn('loginfailure', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '登录失败次数', 'null' => false]) + ->addColumn('lastlogintime', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '上次登录时间']) + ->addColumn('lastloginip', 'string', ['limit' => 50, 'default' => '', 'comment' => '上次登录IP', 'null' => false]) + ->addColumn('password', 'string', ['limit' => 32, 'default' => '', 'comment' => '密码', 'null' => false]) + ->addColumn('salt', 'string', ['limit' => 30, 'default' => '', 'comment' => '密码盐', 'null' => false]) + ->addColumn('motto', 'string', ['limit' => 255, 'default' => '', 'comment' => '签名', 'null' => false]) + ->addColumn('status', 'enum', ['values' => '0,1', 'default' => '1', 'comment' => '状态:0=禁用,1=启用', 'null' => false]) + ->addColumn('createtime', 'integer', ['limit' => 10, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('updatetime', 'integer', ['limit' => 10, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->addIndex(['username'], [ + 'unique' => true, + ]) + ->create(); + } + } + + public function adminGroup(): void + { + if (!$this->hasTable('admin_group')) { + $table = $this->table('admin_group', [ + 'id' => false, + 'comment' => '管理分组表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('pid', 'integer', ['comment' => '上级分组', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('name', 'string', ['limit' => 100, 'default' => '', 'comment' => '组名', 'null' => false]) + ->addColumn('rules', 'text', ['null' => true, 'default' => null, 'comment' => '权限规则ID']) + ->addColumn('status', 'enum', ['values' => '0,1', 'default' => '1', 'comment' => '状态:0=禁用,1=启用', 'null' => false]) + ->addColumn('updatetime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function adminGroupAccess(): void + { + if (!$this->hasTable('admin_group_access')) { + $table = $this->table('admin_group_access', [ + 'id' => false, + 'comment' => '管理分组映射表', + 'row_format' => 'DYNAMIC', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('uid', 'integer', ['comment' => '管理员ID', 'signed' => false, 'null' => false]) + ->addColumn('group_id', 'integer', ['comment' => '分组ID', 'signed' => false, 'null' => false]) + ->addIndex(['uid'], [ + 'type' => 'BTREE', + ]) + ->addIndex(['group_id'], [ + 'type' => 'BTREE', + ]) + ->create(); + } + } + + public function adminLog(): void + { + if (!$this->hasTable('admin_log')) { + $table = $this->table('admin_log', [ + 'id' => false, + 'comment' => '管理员日志表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('admin_id', 'integer', ['comment' => '管理员ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('username', 'string', ['limit' => 20, 'default' => '', 'comment' => '管理员用户名', 'null' => false]) + ->addColumn('url', 'string', ['limit' => 1500, 'default' => '', 'comment' => '操作Url', 'null' => false]) + ->addColumn('title', 'string', ['limit' => 100, 'default' => '', 'comment' => '日志标题', 'null' => false]) + ->addColumn('data', 'text', ['limit' => MysqlAdapter::TEXT_LONG, 'null' => true, 'default' => null, 'comment' => '请求数据']) + ->addColumn('ip', 'string', ['limit' => 50, 'default' => '', 'comment' => 'IP', 'null' => false]) + ->addColumn('useragent', 'string', ['limit' => 255, 'default' => '', 'comment' => 'User-Agent', 'null' => false]) + ->addColumn('createtime', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function area(): void + { + if (!$this->hasTable('area')) { + $table = $this->table('area', [ + 'id' => false, + 'comment' => '省份地区表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('pid', 'integer', ['comment' => '父id', 'null' => true, 'default' => null, 'signed' => false]) + ->addColumn('shortname', 'string', ['limit' => 100, 'null' => true, 'default' => null, 'comment' => '简称']) + ->addColumn('name', 'string', ['limit' => 100, 'null' => true, 'default' => null, 'comment' => '名称']) + ->addColumn('mergename', 'string', ['limit' => 255, 'null' => true, 'default' => null, 'comment' => '全称']) + ->addColumn('level', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'null' => true, 'default' => null, 'comment' => '层级:1=省,2=市,3=区/县']) + ->addColumn('pinyin', 'string', ['limit' => 100, 'null' => true, 'default' => null, 'comment' => '拼音']) + ->addColumn('code', 'string', ['limit' => 100, 'null' => true, 'default' => null, 'comment' => '长途区号']) + ->addColumn('zip', 'string', ['limit' => 100, 'null' => true, 'default' => null, 'comment' => '邮编']) + ->addColumn('first', 'string', ['limit' => 50, 'null' => true, 'default' => null, 'comment' => '首字母']) + ->addColumn('lng', 'string', ['limit' => 50, 'null' => true, 'default' => null, 'comment' => '经度']) + ->addColumn('lat', 'string', ['limit' => 50, 'null' => true, 'default' => null, 'comment' => '纬度']) + ->addIndex(['pid'], [ + 'type' => 'BTREE', + ]) + ->create(); + } + } + + public function attachment(): void + { + if (!$this->hasTable('attachment')) { + $table = $this->table('attachment', [ + 'id' => false, + 'comment' => '附件表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('topic', 'string', ['limit' => 20, 'default' => '', 'comment' => '细目', 'null' => false]) + ->addColumn('admin_id', 'integer', ['comment' => '上传管理员ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('user_id', 'integer', ['comment' => '上传用户ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('url', 'string', ['limit' => 255, 'default' => '', 'comment' => '物理路径', 'null' => false]) + ->addColumn('width', 'integer', ['comment' => '宽度', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('height', 'integer', ['comment' => '高度', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('name', 'string', ['limit' => 100, 'default' => '', 'comment' => '原始名称', 'null' => false]) + ->addColumn('size', 'integer', ['comment' => '大小', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('mimetype', 'string', ['limit' => 100, 'default' => '', 'comment' => 'mime类型', 'null' => false]) + ->addColumn('quote', 'integer', ['comment' => '上传(引用)次数', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('storage', 'string', ['limit' => 50, 'default' => '', 'comment' => '存储方式', 'null' => false]) + ->addColumn('sha1', 'string', ['limit' => 40, 'default' => '', 'comment' => 'sha1编码', 'null' => false]) + ->addColumn('createtime', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->addColumn('lastuploadtime', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '最后上传时间']) + ->create(); + } + } + + public function captcha(): void + { + if (!$this->hasTable('captcha')) { + $table = $this->table('captcha', [ + 'id' => false, + 'comment' => '验证码表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'key', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('key', 'string', ['limit' => 32, 'default' => '', 'comment' => '验证码Key', 'null' => false]) + ->addColumn('code', 'string', ['limit' => 32, 'default' => '', 'comment' => '验证码(加密后)', 'null' => false]) + ->addColumn('captcha', 'text', ['limit' => MysqlAdapter::TEXT_LONG, 'null' => true, 'default' => null, 'comment' => '验证码数据']) + ->addColumn('createtime', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->addColumn('expiretime', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '过期时间']) + ->create(); + } + } + + public function config(): void + { + if (!$this->hasTable('config')) { + $table = $this->table('config', [ + 'id' => false, + 'comment' => '系统配置', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('name', 'string', ['limit' => 30, 'default' => '', 'comment' => '变量名', 'null' => false]) + ->addColumn('group', 'string', ['limit' => 30, 'default' => '', 'comment' => '分组', 'null' => false]) + ->addColumn('title', 'string', ['limit' => 50, 'default' => '', 'comment' => '变量标题', 'null' => false]) + ->addColumn('tip', 'string', ['limit' => 100, 'default' => '', 'comment' => '变量描述', 'null' => false]) + ->addColumn('type', 'string', ['limit' => 30, 'default' => '', 'comment' => '变量输入组件类型', 'null' => false]) + ->addColumn('value', 'text', ['limit' => MysqlAdapter::TEXT_LONG, 'null' => true, 'default' => null, 'comment' => '变量值']) + ->addColumn('content', 'text', ['limit' => MysqlAdapter::TEXT_LONG, 'null' => true, 'default' => null, 'comment' => '字典数据']) + ->addColumn('rule', 'string', ['limit' => 100, 'default' => '', 'comment' => '验证规则', 'null' => false]) + ->addColumn('extend', 'string', ['limit' => 255, 'default' => '', 'comment' => '扩展属性', 'null' => false]) + ->addColumn('allow_del', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '允许删除:0=否,1=是', 'null' => false]) + ->addColumn('weigh', 'integer', ['comment' => '权重', 'default' => 0, 'null' => false]) + ->addIndex(['name'], [ + 'unique' => true, + ]) + ->create(); + } + } + + public function menuRule(): void + { + if (!$this->hasTable('menu_rule') && !$this->hasTable('admin_rule')) { + $table = $this->table('menu_rule', [ + 'id' => false, + 'comment' => '菜单和权限规则表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('pid', 'integer', ['comment' => '上级菜单', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('type', 'enum', ['values' => 'menu_dir,menu,button', 'default' => 'menu', 'comment' => '类型:menu_dir=菜单目录,menu=菜单项,button=页面按钮', 'null' => false]) + ->addColumn('title', 'string', ['limit' => 50, 'default' => '', 'comment' => '标题', 'null' => false]) + ->addColumn('name', 'string', ['limit' => 50, 'default' => '', 'comment' => '规则名称', 'null' => false]) + ->addColumn('path', 'string', ['limit' => 100, 'default' => '', 'comment' => '路由路径', 'null' => false]) + ->addColumn('icon', 'string', ['limit' => 50, 'default' => '', 'comment' => '图标', 'null' => false]) + ->addColumn('menu_type', 'enum', ['values' => 'tab,link,iframe', 'null' => true, 'default' => null, 'comment' => '菜单类型:tab=选项卡,link=链接,iframe=Iframe']) + ->addColumn('url', 'string', ['limit' => 255, 'default' => '', 'comment' => 'Url', 'null' => false]) + ->addColumn('component', 'string', ['limit' => 100, 'default' => '', 'comment' => '组件路径', 'null' => false]) + ->addColumn('keepalive', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '缓存:0=关闭,1=开启', 'null' => false]) + ->addColumn('extend', 'enum', ['values' => 'none,add_rules_only,add_menu_only', 'default' => 'none', 'comment' => '扩展属性:none=无,add_rules_only=只添加为路由,add_menu_only=只添加为菜单', 'null' => false]) + ->addColumn('remark', 'string', ['limit' => 255, 'default' => '', 'comment' => '备注', 'null' => false]) + ->addColumn('weigh', 'integer', ['comment' => '权重', 'default' => 0, 'null' => false]) + ->addColumn('status', 'enum', ['values' => '0,1', 'default' => '1', 'comment' => '状态:0=禁用,1=启用', 'null' => false]) + ->addColumn('updatetime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->addIndex(['pid'], [ + 'type' => 'BTREE', + ]) + ->create(); + } + } + + public function securityDataRecycle(): void + { + if (!$this->hasTable('security_data_recycle')) { + $table = $this->table('security_data_recycle', [ + 'id' => false, + 'comment' => '回收规则表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('name', 'string', ['limit' => 50, 'default' => '', 'comment' => '规则名称', 'null' => false]) + ->addColumn('controller', 'string', ['limit' => 100, 'default' => '', 'comment' => '控制器', 'null' => false]) + ->addColumn('controller_as', 'string', ['limit' => 100, 'default' => '', 'comment' => '控制器别名', 'null' => false]) + ->addColumn('data_table', 'string', ['limit' => 100, 'default' => '', 'comment' => '对应数据表', 'null' => false]) + ->addColumn('primary_key', 'string', ['limit' => 50, 'default' => '', 'comment' => '数据表主键', 'null' => false]) + ->addColumn('status', 'enum', ['values' => '0,1', 'default' => '1', 'comment' => '状态:0=禁用,1=启用', 'null' => false]) + ->addColumn('updatetime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function securityDataRecycleLog(): void + { + if (!$this->hasTable('security_data_recycle_log')) { + $table = $this->table('security_data_recycle_log', [ + 'id' => false, + 'comment' => '数据回收记录表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('admin_id', 'integer', ['comment' => '操作管理员', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('recycle_id', 'integer', ['comment' => '回收规则ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('data', 'text', ['null' => true, 'default' => null, 'comment' => '回收的数据']) + ->addColumn('data_table', 'string', ['limit' => 100, 'default' => '', 'comment' => '数据表', 'null' => false]) + ->addColumn('primary_key', 'string', ['limit' => 50, 'default' => '', 'comment' => '数据表主键', 'null' => false]) + ->addColumn('is_restore', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '是否已还原:0=否,1=是', 'null' => false]) + ->addColumn('ip', 'string', ['limit' => 50, 'default' => '', 'comment' => '操作者IP', 'null' => false]) + ->addColumn('useragent', 'string', ['limit' => 255, 'default' => '', 'comment' => 'User-Agent', 'null' => false]) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function securitySensitiveData(): void + { + if (!$this->hasTable('security_sensitive_data')) { + $table = $this->table('security_sensitive_data', [ + 'id' => false, + 'comment' => '敏感数据规则表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('name', 'string', ['limit' => 50, 'default' => '', 'comment' => '规则名称', 'null' => false]) + ->addColumn('controller', 'string', ['limit' => 100, 'default' => '', 'comment' => '控制器', 'null' => false]) + ->addColumn('controller_as', 'string', ['limit' => 100, 'default' => '', 'comment' => '控制器别名', 'null' => false]) + ->addColumn('data_table', 'string', ['limit' => 100, 'default' => '', 'comment' => '对应数据表', 'null' => false]) + ->addColumn('primary_key', 'string', ['limit' => 50, 'default' => '', 'comment' => '数据表主键', 'null' => false]) + ->addColumn('data_fields', 'text', ['null' => true, 'default' => null, 'comment' => '敏感数据字段']) + ->addColumn('status', 'enum', ['values' => '0,1', 'default' => '1', 'comment' => '状态:0=禁用,1=启用', 'null' => false]) + ->addColumn('updatetime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function securitySensitiveDataLog(): void + { + if (!$this->hasTable('security_sensitive_data_log')) { + $table = $this->table('security_sensitive_data_log', [ + 'id' => false, + 'comment' => '敏感数据修改记录', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('admin_id', 'integer', ['comment' => '操作管理员', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('sensitive_id', 'integer', ['comment' => '敏感数据规则ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('data_table', 'string', ['limit' => 100, 'default' => '', 'comment' => '数据表', 'null' => false]) + ->addColumn('primary_key', 'string', ['limit' => 50, 'default' => '', 'comment' => '数据表主键', 'null' => false]) + ->addColumn('data_field', 'string', ['limit' => 50, 'default' => '', 'comment' => '被修改字段', 'null' => false]) + ->addColumn('data_comment', 'string', ['limit' => 50, 'default' => '', 'comment' => '被修改项', 'null' => false]) + ->addColumn('id_value', 'integer', ['comment' => '被修改项主键值', 'default' => 0, 'null' => false]) + ->addColumn('before', 'text', ['null' => true, 'default' => null, 'comment' => '修改前']) + ->addColumn('after', 'text', ['null' => true, 'default' => null, 'comment' => '修改后']) + ->addColumn('ip', 'string', ['limit' => 50, 'default' => '', 'comment' => '操作者IP', 'null' => false]) + ->addColumn('useragent', 'string', ['limit' => 255, 'default' => '', 'comment' => 'User-Agent', 'null' => false]) + ->addColumn('is_rollback', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '是否已回滚:0=否,1=是', 'null' => false]) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function testBuild(): void + { + if (!$this->hasTable('test_build')) { + $table = $this->table('test_build', [ + 'id' => false, + 'comment' => '知识库表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('title', 'string', ['limit' => 100, 'default' => '', 'comment' => '标题', 'null' => false]) + ->addColumn('keyword_rows', 'string', ['limit' => 100, 'default' => '', 'comment' => '关键词', 'null' => false]) + ->addColumn('content', 'text', ['null' => true, 'default' => null, 'comment' => '内容']) + ->addColumn('views', 'integer', ['comment' => '浏览量', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('likes', 'integer', ['comment' => '有帮助数', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('dislikes', 'integer', ['comment' => '无帮助数', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('note_textarea', 'string', ['limit' => 100, 'default' => '', 'comment' => '备注', 'null' => false]) + ->addColumn('status', 'enum', ['values' => '0,1', 'default' => '1', 'comment' => '状态:0=隐藏,1=正常', 'null' => false]) + ->addColumn('weigh', 'integer', ['comment' => '权重', 'default' => 0, 'null' => false]) + ->addColumn('update_time', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('create_time', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function token(): void + { + if (!$this->hasTable('token')) { + $table = $this->table('token', [ + 'id' => false, + 'comment' => '用户Token表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'token', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('token', 'string', ['limit' => 50, 'default' => '', 'comment' => 'Token', 'null' => false]) + ->addColumn('type', 'string', ['limit' => 15, 'default' => '', 'comment' => '类型', 'null' => false]) + ->addColumn('user_id', 'integer', ['comment' => '用户ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->addColumn('expiretime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '过期时间']) + ->create(); + } + } + + public function user(): void + { + if (!$this->hasTable('user')) { + $table = $this->table('user', [ + 'id' => false, + 'comment' => '会员表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('group_id', 'integer', ['comment' => '分组ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('username', 'string', ['limit' => 32, 'default' => '', 'comment' => '用户名', 'null' => false]) + ->addColumn('nickname', 'string', ['limit' => 50, 'default' => '', 'comment' => '昵称', 'null' => false]) + ->addColumn('email', 'string', ['limit' => 50, 'default' => '', 'comment' => '邮箱', 'null' => false]) + ->addColumn('mobile', 'string', ['limit' => 11, 'default' => '', 'comment' => '手机', 'null' => false]) + ->addColumn('avatar', 'string', ['limit' => 255, 'default' => '', 'comment' => '头像', 'null' => false]) + ->addColumn('gender', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '性别:0=未知,1=男,2=女', 'null' => false]) + ->addColumn('birthday', 'date', ['null' => true, 'default' => null, 'comment' => '生日']) + ->addColumn('money', 'integer', ['comment' => '余额', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('score', 'integer', ['comment' => '积分', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('lastlogintime', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '上次登录时间']) + ->addColumn('lastloginip', 'string', ['limit' => 50, 'default' => '', 'comment' => '上次登录IP', 'null' => false]) + ->addColumn('loginfailure', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '登录失败次数', 'null' => false]) + ->addColumn('joinip', 'string', ['limit' => 50, 'default' => '', 'comment' => '加入IP', 'null' => false]) + ->addColumn('jointime', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '加入时间']) + ->addColumn('motto', 'string', ['limit' => 255, 'default' => '', 'comment' => '签名', 'null' => false]) + ->addColumn('password', 'string', ['limit' => 32, 'default' => '', 'comment' => '密码', 'null' => false]) + ->addColumn('salt', 'string', ['limit' => 30, 'default' => '', 'comment' => '密码盐', 'null' => false]) + ->addColumn('status', 'string', ['limit' => 30, 'default' => '', 'comment' => '状态', 'null' => false]) + ->addColumn('updatetime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->addIndex(['username'], [ + 'unique' => true, + ]) + ->addIndex(['email'], [ + 'unique' => true, + ]) + ->addIndex(['mobile'], [ + 'unique' => true, + ]) + ->create(); + } + } + + public function userGroup(): void + { + if (!$this->hasTable('user_group')) { + $table = $this->table('user_group', [ + 'id' => false, + 'comment' => '会员组表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('name', 'string', ['limit' => 50, 'default' => '', 'comment' => '组名', 'null' => false]) + ->addColumn('rules', 'text', ['null' => true, 'default' => null, 'comment' => '权限节点']) + ->addColumn('status', 'enum', ['values' => '0,1', 'default' => '1', 'comment' => '状态:0=禁用,1=启用', 'null' => false]) + ->addColumn('updatetime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function userMoneyLog(): void + { + if (!$this->hasTable('user_money_log')) { + $table = $this->table('user_money_log', [ + 'id' => false, + 'comment' => '会员余额变动表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('user_id', 'integer', ['comment' => '会员ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('money', 'integer', ['comment' => '变更余额', 'default' => 0, 'null' => false]) + ->addColumn('before', 'integer', ['comment' => '变更前余额', 'default' => 0, 'null' => false]) + ->addColumn('after', 'integer', ['comment' => '变更后余额', 'default' => 0, 'null' => false]) + ->addColumn('memo', 'string', ['limit' => 255, 'default' => '', 'comment' => '备注', 'null' => false]) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function userRule(): void + { + if (!$this->hasTable('user_rule')) { + $table = $this->table('user_rule', [ + 'id' => false, + 'comment' => '会员菜单权限规则表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('pid', 'integer', ['comment' => '上级菜单', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('type', 'enum', ['values' => 'route,menu_dir,menu,nav_user_menu,nav,button', 'default' => 'menu', 'comment' => '类型:route=路由,menu_dir=菜单目录,menu=菜单项,nav_user_menu=顶栏会员菜单下拉项,nav=顶栏菜单项,button=页面按钮', 'null' => false]) + ->addColumn('title', 'string', ['limit' => 50, 'default' => '', 'comment' => '标题', 'null' => false]) + ->addColumn('name', 'string', ['limit' => 50, 'default' => '', 'comment' => '规则名称', 'null' => false]) + ->addColumn('path', 'string', ['limit' => 100, 'default' => '', 'comment' => '路由路径', 'null' => false]) + ->addColumn('icon', 'string', ['limit' => 50, 'default' => '', 'comment' => '图标', 'null' => false]) + ->addColumn('menu_type', 'enum', ['values' => 'tab,link,iframe', 'default' => 'tab', 'comment' => '菜单类型:tab=选项卡,link=链接,iframe=Iframe', 'null' => false]) + ->addColumn('url', 'string', ['limit' => 255, 'default' => '', 'comment' => 'Url', 'null' => false]) + ->addColumn('component', 'string', ['limit' => 100, 'default' => '', 'comment' => '组件路径', 'null' => false]) + ->addColumn('no_login_valid', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '未登录有效:0=否,1=是', 'null' => false]) + ->addColumn('extend', 'enum', ['values' => 'none,add_rules_only,add_menu_only', 'default' => 'none', 'comment' => '扩展属性:none=无,add_rules_only=只添加为路由,add_menu_only=只添加为菜单', 'null' => false]) + ->addColumn('remark', 'string', ['limit' => 255, 'default' => '', 'comment' => '备注', 'null' => false]) + ->addColumn('weigh', 'integer', ['comment' => '权重', 'default' => 0, 'null' => false]) + ->addColumn('status', 'enum', ['values' => '0,1', 'default' => '1', 'comment' => '状态:0=禁用,1=启用', 'null' => false]) + ->addColumn('updatetime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->addIndex(['pid'], [ + 'type' => 'BTREE', + ]) + ->create(); + } + } + + public function userScoreLog(): void + { + if (!$this->hasTable('user_score_log')) { + $table = $this->table('user_score_log', [ + 'id' => false, + 'comment' => '会员积分变动表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('user_id', 'integer', ['comment' => '会员ID', 'default' => 0, 'signed' => false, 'null' => false]) + ->addColumn('score', 'integer', ['comment' => '变更积分', 'default' => 0, 'null' => false]) + ->addColumn('before', 'integer', ['comment' => '变更前积分', 'default' => 0, 'null' => false]) + ->addColumn('after', 'integer', ['comment' => '变更后积分', 'default' => 0, 'null' => false]) + ->addColumn('memo', 'string', ['limit' => 255, 'default' => '', 'comment' => '备注', 'null' => false]) + ->addColumn('createtime', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } + + public function crudLog(): void + { + if (!$this->hasTable('crud_log')) { + $table = $this->table('crud_log', [ + 'id' => false, + 'comment' => 'CRUD记录表', + 'row_format' => 'DYNAMIC', + 'primary_key' => 'id', + 'collation' => 'utf8mb4_unicode_ci', + ]); + $table->addColumn('id', 'integer', ['comment' => 'ID', 'signed' => false, 'identity' => true, 'null' => false]) + ->addColumn('table_name', 'string', ['limit' => 200, 'default' => '', 'comment' => '数据表名', 'null' => false]) + ->addColumn('table', 'text', ['null' => true, 'default' => null, 'comment' => '数据表数据']) + ->addColumn('fields', 'text', ['null' => true, 'default' => null, 'comment' => '字段数据']) + ->addColumn('status', 'enum', ['values' => 'delete,success,error,start', 'default' => 'start', 'comment' => '状态:delete=已删除,success=成功,error=失败,start=生成中', 'null' => false]) + ->addColumn('create_time', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->create(); + } + } +} diff --git a/database/migrations/20230620180916_install_data.php b/database/migrations/20230620180916_install_data.php new file mode 100644 index 0000000..61e3f6f --- /dev/null +++ b/database/migrations/20230620180916_install_data.php @@ -0,0 +1,1418 @@ +nowTime = time(); + $this->admin(); + $this->adminGroup(); + $this->adminGroupAccess(); + $this->config(); + $this->menuRule(); + $this->securityDataRecycle(); + $this->securitySensitiveData(); + $this->user(); + $this->userGroup(); + $this->userRule(); + } + + public function admin(): void + { + $table = $this->table('admin'); + $rows = [ + [ + 'id' => 1, + 'username' => 'admin', + 'nickname' => 'Admin', + 'email' => 'admin@buildadmin.com', + 'mobile' => '18888888888', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ] + ]; + $exist = Db::name('admin')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function adminGroup(): void + { + $table = $this->table('admin_group'); + $rows = [ + [ + 'id' => 1, + 'pid' => 0, + 'name' => '超级管理组', + 'rules' => '*', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 2, + 'pid' => 1, + 'name' => '一级管理员', + 'rules' => '1,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,77,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 3, + 'pid' => 2, + 'name' => '二级管理员', + 'rules' => '21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 4, + 'pid' => 3, + 'name' => '三级管理员', + 'rules' => '55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + ]; + $exist = Db::name('admin_group')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function adminGroupAccess(): void + { + $table = $this->table('admin_group_access'); + $rows = [ + [ + 'uid' => 1, + 'group_id' => 1, + ] + ]; + $exist = Db::name('admin_group_access')->where('uid', 1)->value('uid'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function config(): void + { + $table = $this->table('config'); + $rows = [ + [ + 'id' => 1, + 'name' => 'config_group', + 'group' => 'basics', + 'title' => 'Config group', + 'type' => 'array', + 'value' => '[{"key":"basics","value":"Basics"},{"key":"mail","value":"Mail"},{"key":"config_quick_entrance","value":"Config Quick entrance"}]', + 'rule' => 'required', + 'weigh' => -1, + ], + [ + 'id' => 2, + 'name' => 'site_name', + 'group' => 'basics', + 'title' => 'Site Name', + 'tip' => '', + 'type' => 'string', + 'value' => '站点名称', + 'rule' => 'required', + 'weigh' => 99, + ], + [ + 'id' => 3, + 'name' => 'record_number', + 'group' => 'basics', + 'title' => 'Record number', + 'tip' => '域名备案号', + 'type' => 'string', + 'value' => '渝ICP备8888888号-1', + ], + [ + 'id' => 4, + 'name' => 'version', + 'group' => 'basics', + 'title' => 'Version number', + 'tip' => '系统版本号', + 'type' => 'string', + 'value' => 'v1.0.0', + 'rule' => 'required', + ], + [ + 'id' => 5, + 'name' => 'time_zone', + 'group' => 'basics', + 'title' => 'time zone', + 'type' => 'string', + 'value' => 'Asia/Shanghai', + 'rule' => 'required', + ], + [ + 'id' => 6, + 'name' => 'no_access_ip', + 'group' => 'basics', + 'title' => 'No access ip', + 'tip' => '禁止访问站点的ip列表,一行一个', + 'type' => 'textarea', + ], + [ + 'id' => 7, + 'name' => 'smtp_server', + 'group' => 'mail', + 'title' => 'smtp server', + 'type' => 'string', + 'value' => 'smtp.qq.com', + 'weigh' => 9, + ], + [ + 'id' => 8, + 'name' => 'smtp_port', + 'group' => 'mail', + 'title' => 'smtp port', + 'type' => 'string', + 'value' => '465', + 'weigh' => 8, + ], + [ + 'id' => 9, + 'name' => 'smtp_user', + 'group' => 'mail', + 'title' => 'smtp user', + 'type' => 'string', + 'weigh' => 7, + ], + [ + 'id' => 10, + 'name' => 'smtp_pass', + 'group' => 'mail', + 'title' => 'smtp pass', + 'type' => 'string', + 'weigh' => 6, + ], + [ + 'id' => 11, + 'name' => 'smtp_verification', + 'group' => 'mail', + 'title' => 'smtp verification', + 'type' => 'select', + 'value' => 'SSL', + 'content' => '{"SSL":"SSL","TLS":"TLS"}', + 'weigh' => 5, + ], + [ + 'id' => 12, + 'name' => 'smtp_sender_mail', + 'group' => 'mail', + 'title' => 'smtp sender mail', + 'type' => 'string', + 'rule' => 'email', + 'weigh' => 4, + ], + [ + 'id' => 13, + 'name' => 'config_quick_entrance', + 'group' => 'config_quick_entrance', + 'title' => 'Config Quick entrance', + 'type' => 'array', + 'value' => '[{"key":"数据回收规则配置","value":"/admin/security/dataRecycle"},{"key":"敏感数据规则配置","value":"/admin/security/sensitiveData"}]', + ], + ]; + $exist = Db::name('config')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function menuRule(): void + { + if (!$this->hasTable('menu_rule')) return; + $table = $this->table('menu_rule'); + $rows = [ + [ + 'id' => '1', + 'type' => 'menu', + 'title' => '控制台', + 'name' => 'dashboard/dashboard', + 'path' => 'dashboard', + 'icon' => 'fa fa-dashboard', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/dashboard.vue', + 'keepalive' => '1', + 'remark' => 'Remark lang', + 'weigh' => '999', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '2', + 'type' => 'menu_dir', + 'title' => '权限管理', + 'name' => 'auth', + 'path' => 'auth', + 'icon' => 'fa fa-group', + 'weigh' => '100', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '3', + 'pid' => '2', + 'type' => 'menu', + 'title' => '角色组管理', + 'name' => 'auth/group', + 'path' => 'auth/group', + 'icon' => 'fa fa-group', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/auth/group/index.vue', + 'keepalive' => '1', + 'weigh' => '99', + 'remark' => 'Remark lang', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '4', + 'pid' => '3', + 'type' => 'button', + 'title' => '查看', + 'name' => 'auth/group/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '5', + 'pid' => '3', + 'type' => 'button', + 'title' => '添加', + 'name' => 'auth/group/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '6', + 'pid' => '3', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'auth/group/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '7', + 'pid' => '3', + 'type' => 'button', + 'title' => '删除', + 'name' => 'auth/group/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '8', + 'pid' => '2', + 'type' => 'menu', + 'title' => '管理员管理', + 'name' => 'auth/admin', + 'path' => 'auth/admin', + 'icon' => 'el-icon-UserFilled', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/auth/admin/index.vue', + 'keepalive' => '1', + 'weigh' => '98', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '9', + 'pid' => '8', + 'type' => 'button', + 'title' => '查看', + 'name' => 'auth/admin/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '10', + 'pid' => '8', + 'type' => 'button', + 'title' => '添加', + 'name' => 'auth/admin/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '11', + 'pid' => '8', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'auth/admin/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '12', + 'pid' => '8', + 'type' => 'button', + 'title' => '删除', + 'name' => 'auth/admin/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '13', + 'pid' => '2', + 'type' => 'menu', + 'title' => '菜单规则管理', + 'name' => 'auth/menu', + 'path' => 'auth/menu', + 'icon' => 'el-icon-Grid', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/auth/menu/index.vue', + 'keepalive' => '1', + 'weigh' => '97', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '14', + 'pid' => '13', + 'type' => 'button', + 'title' => '查看', + 'name' => 'auth/menu/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '15', + 'pid' => '13', + 'type' => 'button', + 'title' => '添加', + 'name' => 'auth/menu/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '16', + 'pid' => '13', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'auth/menu/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '17', + 'pid' => '13', + 'type' => 'button', + 'title' => '删除', + 'name' => 'auth/menu/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '18', + 'pid' => '13', + 'type' => 'button', + 'title' => '快速排序', + 'name' => 'auth/menu/sortable', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '19', + 'pid' => '2', + 'type' => 'menu', + 'title' => '管理员日志管理', + 'name' => 'auth/adminLog', + 'path' => 'auth/adminLog', + 'icon' => 'el-icon-List', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/auth/adminLog/index.vue', + 'keepalive' => '1', + 'weigh' => '96', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '20', + 'pid' => '19', + 'type' => 'button', + 'title' => '查看', + 'name' => 'auth/adminLog/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '21', + 'type' => 'menu_dir', + 'title' => '会员管理', + 'name' => 'user', + 'path' => 'user', + 'icon' => 'fa fa-drivers-license', + 'weigh' => '95', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '22', + 'pid' => '21', + 'type' => 'menu', + 'title' => '会员管理', + 'name' => 'user/user', + 'path' => 'user/user', + 'icon' => 'fa fa-user', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/user/user/index.vue', + 'keepalive' => '1', + 'weigh' => '94', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '23', + 'pid' => '22', + 'type' => 'button', + 'title' => '查看', + 'name' => 'user/user/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '24', + 'pid' => '22', + 'type' => 'button', + 'title' => '添加', + 'name' => 'user/user/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '25', + 'pid' => '22', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'user/user/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '26', + 'pid' => '22', + 'type' => 'button', + 'title' => '删除', + 'name' => 'user/user/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '27', + 'pid' => '21', + 'type' => 'menu', + 'title' => '会员分组管理', + 'name' => 'user/group', + 'path' => 'user/group', + 'icon' => 'fa fa-group', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/user/group/index.vue', + 'keepalive' => '1', + 'weigh' => '93', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '28', + 'pid' => '27', + 'type' => 'button', + 'title' => '查看', + 'name' => 'user/group/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '29', + 'pid' => '27', + 'type' => 'button', + 'title' => '添加', + 'name' => 'user/group/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '30', + 'pid' => '27', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'user/group/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '31', + 'pid' => '27', + 'type' => 'button', + 'title' => '删除', + 'name' => 'user/group/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '32', + 'pid' => '21', + 'type' => 'menu', + 'title' => '会员规则管理', + 'name' => 'user/rule', + 'path' => 'user/rule', + 'icon' => 'fa fa-th-list', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/user/rule/index.vue', + 'keepalive' => '1', + 'weigh' => '92', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '33', + 'pid' => '32', + 'type' => 'button', + 'title' => '查看', + 'name' => 'user/rule/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '34', + 'pid' => '32', + 'type' => 'button', + 'title' => '添加', + 'name' => 'user/rule/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '35', + 'pid' => '32', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'user/rule/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '36', + 'pid' => '32', + 'type' => 'button', + 'title' => '删除', + 'name' => 'user/rule/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '37', + 'pid' => '32', + 'type' => 'button', + 'title' => '快速排序', + 'name' => 'user/rule/sortable', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '38', + 'pid' => '21', + 'type' => 'menu', + 'title' => '会员余额管理', + 'name' => 'user/moneyLog', + 'path' => 'user/moneyLog', + 'icon' => 'el-icon-Money', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/user/moneyLog/index.vue', + 'keepalive' => '1', + 'weigh' => '91', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '39', + 'pid' => '38', + 'type' => 'button', + 'title' => '查看', + 'name' => 'user/moneyLog/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '40', + 'pid' => '38', + 'type' => 'button', + 'title' => '添加', + 'name' => 'user/moneyLog/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '41', + 'pid' => '21', + 'type' => 'menu', + 'title' => '会员积分管理', + 'name' => 'user/scoreLog', + 'path' => 'user/scoreLog', + 'icon' => 'el-icon-Discount', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/user/scoreLog/index.vue', + 'keepalive' => '1', + 'weigh' => '90', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '42', + 'pid' => '41', + 'type' => 'button', + 'title' => '查看', + 'name' => 'user/scoreLog/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '43', + 'pid' => '41', + 'type' => 'button', + 'title' => '添加', + 'name' => 'user/scoreLog/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '44', + 'type' => 'menu_dir', + 'title' => '常规管理', + 'name' => 'routine', + 'path' => 'routine', + 'icon' => 'fa fa-cogs', + 'weigh' => '89', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '45', + 'pid' => '44', + 'type' => 'menu', + 'title' => '系统配置', + 'name' => 'routine/config', + 'path' => 'routine/config', + 'icon' => 'el-icon-Tools', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/routine/config/index.vue', + 'keepalive' => '1', + 'weigh' => '88', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '46', + 'pid' => '45', + 'type' => 'button', + 'title' => '查看', + 'name' => 'routine/config/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '47', + 'pid' => '45', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'routine/config/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '48', + 'pid' => '44', + 'type' => 'menu', + 'title' => '附件管理', + 'name' => 'routine/attachment', + 'path' => 'routine/attachment', + 'icon' => 'fa fa-folder', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/routine/attachment/index.vue', + 'keepalive' => '1', + 'remark' => 'Remark lang', + 'weigh' => '87', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '49', + 'pid' => '48', + 'type' => 'button', + 'title' => '查看', + 'name' => 'routine/attachment/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '50', + 'pid' => '48', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'routine/attachment/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '51', + 'pid' => '48', + 'type' => 'button', + 'title' => '删除', + 'name' => 'routine/attachment/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '52', + 'pid' => '44', + 'type' => 'menu', + 'title' => '个人资料', + 'name' => 'routine/adminInfo', + 'path' => 'routine/adminInfo', + 'icon' => 'fa fa-user', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/routine/adminInfo.vue', + 'keepalive' => '1', + 'weigh' => '86', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '53', + 'pid' => '52', + 'type' => 'button', + 'title' => '查看', + 'name' => 'routine/adminInfo/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '54', + 'pid' => '52', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'routine/adminInfo/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '55', + 'type' => 'menu_dir', + 'title' => '数据安全管理', + 'name' => 'security', + 'path' => 'security', + 'icon' => 'fa fa-shield', + 'weigh' => '85', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '56', + 'pid' => '55', + 'type' => 'menu', + 'title' => '数据回收站', + 'name' => 'security/dataRecycleLog', + 'path' => 'security/dataRecycleLog', + 'icon' => 'fa fa-database', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/security/dataRecycleLog/index.vue', + 'keepalive' => '1', + 'weigh' => '84', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '57', + 'pid' => '56', + 'type' => 'button', + 'title' => '查看', + 'name' => 'security/dataRecycleLog/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '58', + 'pid' => '56', + 'type' => 'button', + 'title' => '删除', + 'name' => 'security/dataRecycleLog/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '59', + 'pid' => '56', + 'type' => 'button', + 'title' => '还原', + 'name' => 'security/dataRecycleLog/restore', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '60', + 'pid' => '56', + 'type' => 'button', + 'title' => '查看详情', + 'name' => 'security/dataRecycleLog/info', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '61', + 'pid' => '55', + 'type' => 'menu', + 'title' => '敏感数据修改记录', + 'name' => 'security/sensitiveDataLog', + 'path' => 'security/sensitiveDataLog', + 'icon' => 'fa fa-expeditedssl', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/security/sensitiveDataLog/index.vue', + 'keepalive' => '1', + 'weigh' => '83', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '62', + 'pid' => '61', + 'type' => 'button', + 'title' => '查看', + 'name' => 'security/sensitiveDataLog/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '63', + 'pid' => '61', + 'type' => 'button', + 'title' => '删除', + 'name' => 'security/sensitiveDataLog/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '64', + 'pid' => '61', + 'type' => 'button', + 'title' => '回滚', + 'name' => 'security/sensitiveDataLog/rollback', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '65', + 'pid' => '61', + 'type' => 'button', + 'title' => '查看详情', + 'name' => 'security/sensitiveDataLog/info', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '66', + 'pid' => '55', + 'type' => 'menu', + 'title' => '数据回收规则管理', + 'name' => 'security/dataRecycle', + 'path' => 'security/dataRecycle', + 'icon' => 'fa fa-database', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/security/dataRecycle/index.vue', + 'keepalive' => '1', + 'remark' => 'Remark lang', + 'weigh' => '82', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '67', + 'pid' => '66', + 'type' => 'button', + 'title' => '查看', + 'name' => 'security/dataRecycle/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '68', + 'pid' => '66', + 'type' => 'button', + 'title' => '添加', + 'name' => 'security/dataRecycle/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '69', + 'pid' => '66', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'security/dataRecycle/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '70', + 'pid' => '66', + 'type' => 'button', + 'title' => '删除', + 'name' => 'security/dataRecycle/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '71', + 'pid' => '55', + 'type' => 'menu', + 'title' => '敏感字段规则管理', + 'name' => 'security/sensitiveData', + 'path' => 'security/sensitiveData', + 'icon' => 'fa fa-expeditedssl', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/security/sensitiveData/index.vue', + 'keepalive' => '1', + 'remark' => 'Remark lang', + 'weigh' => '81', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '72', + 'pid' => '71', + 'type' => 'button', + 'title' => '查看', + 'name' => 'security/sensitiveData/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '73', + 'pid' => '71', + 'type' => 'button', + 'title' => '添加', + 'name' => 'security/sensitiveData/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '74', + 'pid' => '71', + 'type' => 'button', + 'title' => '编辑', + 'name' => 'security/sensitiveData/edit', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '75', + 'pid' => '71', + 'type' => 'button', + 'title' => '删除', + 'name' => 'security/sensitiveData/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '76', + 'type' => 'menu', + 'title' => 'BuildAdmin', + 'name' => 'buildadmin/buildadmin', + 'path' => 'buildadmin', + 'icon' => 'local-logo', + 'menu_type' => 'link', + 'url' => 'https://doc.buildadmin.com', + 'status' => '0', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '77', + 'pid' => '45', + 'type' => 'button', + 'title' => '添加', + 'name' => 'routine/config/add', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '78', + 'type' => 'menu', + 'title' => '模块市场', + 'name' => 'moduleStore/moduleStore', + 'path' => 'moduleStore', + 'icon' => 'el-icon-GoodsFilled', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/module/index.vue', + 'keepalive' => '1', + 'weigh' => '86', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '79', + 'pid' => '78', + 'type' => 'button', + 'title' => '查看', + 'name' => 'moduleStore/moduleStore/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '80', + 'pid' => '78', + 'type' => 'button', + 'title' => '安装', + 'name' => 'moduleStore/moduleStore/install', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '81', + 'pid' => '78', + 'type' => 'button', + 'title' => '调整状态', + 'name' => 'moduleStore/moduleStore/changeState', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '82', + 'pid' => '78', + 'type' => 'button', + 'title' => '卸载', + 'name' => 'moduleStore/moduleStore/uninstall', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '83', + 'pid' => '78', + 'type' => 'button', + 'title' => '更新', + 'name' => 'moduleStore/moduleStore/update', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '84', + 'type' => 'menu', + 'title' => 'CRUD代码生成', + 'name' => 'crud/crud', + 'path' => 'crud/crud', + 'icon' => 'fa fa-code', + 'menu_type' => 'tab', + 'component' => '/src/views/backend/crud/index.vue', + 'keepalive' => '1', + 'weigh' => '80', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '85', + 'pid' => '84', + 'type' => 'button', + 'title' => '查看', + 'name' => 'crud/crud/index', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '86', + 'pid' => '84', + 'type' => 'button', + 'title' => '生成', + 'name' => 'crud/crud/generate', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '87', + 'pid' => '84', + 'type' => 'button', + 'title' => '删除', + 'name' => 'crud/crud/delete', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => '88', + 'pid' => '45', + 'type' => 'button', + 'title' => '删除', + 'name' => 'routine/config/del', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + ]; + $exist = Db::name('menu_rule')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function securityDataRecycle(): void + { + $table = $this->table('security_data_recycle'); + $rows = [ + [ + 'id' => 1, + 'name' => '管理员', + 'controller' => 'auth/Admin.php', + 'controller_as' => 'auth/admin', + 'data_table' => 'admin', + 'primary_key' => 'id', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 2, + 'name' => '管理员日志', + 'controller' => 'auth/AdminLog.php', + 'controller_as' => 'auth/adminlog', + 'data_table' => 'admin_log', + 'primary_key' => 'id', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 3, + 'name' => '菜单规则', + 'controller' => 'auth/Menu.php', + 'controller_as' => 'auth/menu', + 'data_table' => 'menu_rule', + 'primary_key' => 'id', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 4, + 'name' => '系统配置项', + 'controller' => 'routine/Config.php', + 'controller_as' => 'routine/config', + 'data_table' => 'config', + 'primary_key' => 'id', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 5, + 'name' => '会员', + 'controller' => 'user/User.php', + 'controller_as' => 'user/user', + 'data_table' => 'user', + 'primary_key' => 'id', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 6, + 'name' => '数据回收规则', + 'controller' => 'security/DataRecycle.php', + 'controller_as' => 'security/datarecycle', + 'data_table' => 'security_data_recycle', + 'primary_key' => 'id', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + ]; + $exist = Db::name('security_data_recycle')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function securitySensitiveData(): void + { + $table = $this->table('security_sensitive_data'); + $rows = [ + [ + 'id' => 1, + 'name' => '管理员数据', + 'controller' => 'auth/Admin.php', + 'controller_as' => 'auth/admin', + 'data_table' => 'admin', + 'primary_key' => 'id', + 'data_fields' => '{"username":"用户名","mobile":"手机","password":"密码","status":"状态"}', + 'status' => '1', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 2, + 'name' => '会员数据', + 'controller' => 'user/User.php', + 'controller_as' => 'user/user', + 'data_table' => 'user', + 'primary_key' => 'id', + 'data_fields' => '{"username":"用户名","mobile":"手机号","password":"密码","status":"状态","email":"邮箱地址"}', + 'status' => '1', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 3, + 'name' => '管理员权限', + 'controller' => 'auth/Group.php', + 'controller_as' => 'auth/group', + 'data_table' => 'admin_group', + 'primary_key' => 'id', + 'data_fields' => '{"rules":"权限规则ID"}', + 'status' => '1', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + ]; + $exist = Db::name('security_sensitive_data')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function user(): void + { + $table = $this->table('user'); + $rows = [ + [ + 'id' => 1, + 'group_id' => 1, + 'username' => 'user', + 'nickname' => 'User', + 'email' => '18888888888@qq.com', + 'mobile' => '18888888888', + 'gender' => '2', + 'birthday' => date('Y-m-d'), + 'status' => 'enable', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ] + ]; + $exist = Db::name('user')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function userGroup(): void + { + $table = $this->table('user_group'); + $rows = [ + [ + 'id' => 1, + 'name' => '默认分组', + 'rules' => '*', + 'status' => '1', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ] + ]; + $exist = Db::name('user_group')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } + + public function userRule(): void + { + $table = $this->table('user_rule'); + $rows = [ + [ + 'id' => 1, + 'pid' => 0, + 'type' => 'menu_dir', + 'title' => '我的账户', + 'name' => 'account', + 'path' => 'account', + 'icon' => 'fa fa-user-circle', + 'menu_type' => 'tab', + 'weigh' => '98', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 2, + 'pid' => 1, + 'type' => 'menu', + 'title' => '账户概览', + 'name' => 'account/overview', + 'path' => 'account/overview', + 'icon' => 'fa fa-home', + 'menu_type' => 'tab', + 'component' => '/src/views/frontend/user/account/overview.vue', + 'weigh' => '99', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 3, + 'pid' => 1, + 'type' => 'menu', + 'title' => '个人资料', + 'name' => 'account/profile', + 'path' => 'account/profile', + 'icon' => 'fa fa-user-circle-o', + 'menu_type' => 'tab', + 'component' => '/src/views/frontend/user/account/profile.vue', + 'weigh' => '98', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 4, + 'pid' => 1, + 'type' => 'menu', + 'title' => '修改密码', + 'name' => 'account/changePassword', + 'path' => 'account/changePassword', + 'icon' => 'fa fa-shield', + 'menu_type' => 'tab', + 'component' => '/src/views/frontend/user/account/changePassword.vue', + 'weigh' => '97', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 5, + 'pid' => 1, + 'type' => 'menu', + 'title' => '积分记录', + 'name' => 'account/integral', + 'path' => 'account/integral', + 'icon' => 'fa fa-tag', + 'menu_type' => 'tab', + 'component' => '/src/views/frontend/user/account/integral.vue', + 'weigh' => '96', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ], + [ + 'id' => 6, + 'pid' => 1, + 'type' => 'menu', + 'title' => '余额记录', + 'name' => 'account/balance', + 'path' => 'account/balance', + 'icon' => 'fa fa-money', + 'menu_type' => 'tab', + 'component' => '/src/views/frontend/user/account/balance.vue', + 'weigh' => '95', + 'updatetime' => $this->nowTime, + 'createtime' => $this->nowTime, + ] + ]; + $exist = Db::name('user_rule')->where('id', 1)->value('id'); + if (!$exist) { + $table->insert($rows)->saveData(); + } + } +} diff --git a/database/migrations/20230622221507_version200.php b/database/migrations/20230622221507_version200.php new file mode 100644 index 0000000..ecab8d1 --- /dev/null +++ b/database/migrations/20230622221507_version200.php @@ -0,0 +1,179 @@ +table('admin'); + if ($admin->hasColumn('loginfailure')) { + // 字段改名 + $admin->renameColumn('loginfailure', 'login_failure') + ->renameColumn('lastlogintime', 'last_login_time') + ->renameColumn('lastloginip', 'last_login_ip') + ->renameColumn('updatetime', 'update_time') + ->renameColumn('createtime', 'create_time') + ->changeColumn('update_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->changeColumn('create_time', 'biginteger', ['after' => 'update_time', 'limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $adminGroup = $this->table('admin_group'); + if ($adminGroup->hasColumn('updatetime')) { + $adminGroup->renameColumn('updatetime', 'update_time') + ->renameColumn('createtime', 'create_time') + ->changeColumn('update_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $adminLog = $this->table('admin_log'); + if ($adminLog->hasColumn('createtime')) { + $adminLog->renameColumn('createtime', 'create_time') + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->changeColumn('data', 'text', ['limit' => MysqlAdapter::TEXT_LONG, 'null' => true, 'default' => null, 'comment' => '请求数据']) + ->save(); + } + + $attachment = $this->table('attachment'); + if ($attachment->hasColumn('createtime')) { + $attachment->renameColumn('createtime', 'create_time') + ->renameColumn('lastuploadtime', 'last_upload_time') + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->changeColumn('last_upload_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '最后上传时间']) + ->save(); + } + + $captcha = $this->table('captcha'); + if ($captcha->hasColumn('createtime')) { + $captcha->renameColumn('createtime', 'create_time') + ->renameColumn('expiretime', 'expire_time') + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->changeColumn('expire_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '过期时间']) + ->changeColumn('captcha', 'text', ['limit' => MysqlAdapter::TEXT_REGULAR, 'null' => true, 'default' => null, 'comment' => '验证码数据']) + ->save(); + } + + if ($this->hasTable('menu_rule')) { + $menuRule = $this->table('menu_rule'); + if ($menuRule->hasColumn('updatetime') && $this->hasTable('menu_rule')) { + $menuRule->renameColumn('updatetime', 'update_time') + ->renameColumn('createtime', 'create_time') + ->changeColumn('update_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + $menuRule->rename('admin_rule')->save(); + Db::name('admin_rule') + ->where('name', 'auth/menu') + ->update([ + 'name' => 'auth/rule', + 'path' => 'auth/rule', + 'component' => '/src/views/backend/auth/rule/index.vue', + ]); + Db::name('admin_rule')->where('name', 'auth/menu/index')->update(['name' => 'auth/rule/index']); + Db::name('admin_rule')->where('name', 'auth/menu/add')->update(['name' => 'auth/rule/add']); + Db::name('admin_rule')->where('name', 'auth/menu/edit')->update(['name' => 'auth/rule/edit']); + Db::name('admin_rule')->where('name', 'auth/menu/del')->update(['name' => 'auth/rule/del']); + Db::name('admin_rule')->where('name', 'auth/menu/sortable')->update(['name' => 'auth/rule/sortable']); + Db::name('admin_rule')->whereIn('name', [ + 'dashboard/dashboard', + 'routine/attachment', + ])->update(['remark' => 'Remark lang']); + } + } + + $securityDataRecycle = $this->table('security_data_recycle'); + if ($securityDataRecycle->hasColumn('updatetime')) { + $securityDataRecycle->renameColumn('updatetime', 'update_time') + ->renameColumn('createtime', 'create_time') + ->changeColumn('update_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $securityDataRecycleLog = $this->table('security_data_recycle_log'); + if ($securityDataRecycleLog->hasColumn('createtime')) { + $securityDataRecycleLog->renameColumn('createtime', 'create_time') + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $securitySensitiveData = $this->table('security_sensitive_data'); + if ($securitySensitiveData->hasColumn('updatetime')) { + $securitySensitiveData->renameColumn('updatetime', 'update_time') + ->renameColumn('createtime', 'create_time') + ->changeColumn('update_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $securitySensitiveDataLog = $this->table('security_sensitive_data_log'); + if ($securitySensitiveDataLog->hasColumn('createtime')) { + $securitySensitiveDataLog->renameColumn('createtime', 'create_time') + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $token = $this->table('token'); + if ($token->hasColumn('createtime')) { + $token->renameColumn('createtime', 'create_time') + ->renameColumn('expiretime', 'expire_time') + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->changeColumn('expire_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '过期时间']) + ->save(); + } + + $userGroup = $this->table('user_group'); + if ($userGroup->hasColumn('createtime')) { + $userGroup->renameColumn('updatetime', 'update_time') + ->renameColumn('createtime', 'create_time') + ->changeColumn('update_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $userMoneyLog = $this->table('user_money_log'); + if ($userMoneyLog->hasColumn('createtime')) { + $userMoneyLog->renameColumn('createtime', 'create_time') + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $userRule = $this->table('user_rule'); + if ($userRule->hasColumn('createtime')) { + $userRule->renameColumn('updatetime', 'update_time') + ->renameColumn('createtime', 'create_time') + ->changeColumn('update_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->changeColumn('type', 'enum', ['values' => 'route,menu_dir,menu,nav_user_menu,nav,button', 'default' => 'menu', 'comment' => '类型:route=路由,menu_dir=菜单目录,menu=菜单项,nav_user_menu=顶栏会员菜单下拉项,nav=顶栏菜单项,button=页面按钮', 'null' => false]); + if (!$userRule->hasColumn('no_login_valid')) { + $userRule->addColumn('no_login_valid', 'integer', ['signed' => false, 'limit' => MysqlAdapter::INT_TINY, 'default' => 0, 'comment' => '未登录有效:0=否,1=是']); + } + $userRule->save(); + } + + $userScoreLog = $this->table('user_score_log'); + if ($userScoreLog->hasColumn('createtime')) { + $userScoreLog->renameColumn('createtime', 'create_time') + ->changeColumn('create_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + + $user = $this->table('user'); + if ($user->hasColumn('loginfailure')) { + $user->renameColumn('lastlogintime', 'last_login_time') + ->renameColumn('lastloginip', 'last_login_ip') + ->renameColumn('loginfailure', 'login_failure') + ->renameColumn('joinip', 'join_ip') + ->renameColumn('jointime', 'join_time') + ->renameColumn('updatetime', 'update_time') + ->renameColumn('createtime', 'create_time') + ->changeColumn('update_time', 'biginteger', ['limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '更新时间']) + ->changeColumn('create_time', 'biginteger', ['after' => 'update_time', 'limit' => 16, 'signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->save(); + } + } +} diff --git a/database/migrations/20230719211338_version201.php b/database/migrations/20230719211338_version201.php new file mode 100644 index 0000000..d780d79 --- /dev/null +++ b/database/migrations/20230719211338_version201.php @@ -0,0 +1,16 @@ +table('user'); + if ($user->hasIndex('email')) { + $user->removeIndexByName('email') + ->removeIndexByName('mobile') + ->update(); + } + } +} diff --git a/database/migrations/20230905060702_version202.php b/database/migrations/20230905060702_version202.php new file mode 100644 index 0000000..226f6a9 --- /dev/null +++ b/database/migrations/20230905060702_version202.php @@ -0,0 +1,68 @@ +where('name', 'dashboard/dashboard') + ->lock(true) + ->value('id'); + if ($dashboardId) { + // 修改name + Db::name('admin_rule') + ->where('name', 'dashboard/dashboard') + ->update([ + 'name' => 'dashboard', + ]); + + // 增加一个查看的权限节点 + $dashboardIndexId = Db::name('admin_rule')->insertGetId([ + 'pid' => $dashboardId, + 'type' => 'button', + 'title' => '查看', + 'name' => 'dashboard/index', + 'update_time' => time(), + 'create_time' => time(), + ]); + + // 原本有控制台权限的管理员,给予新增的查看权限 + $group = Db::name('admin_group') + ->where('rules', 'find in set', $dashboardId) + ->select(); + foreach ($group as $item) { + + $newRules = trim($item['rules'], ','); + $newRules = $newRules . ',' . $dashboardIndexId; + + Db::name('admin_group') + ->where('id', $item['id']) + ->update([ + 'rules' => $newRules + ]); + } + } + + // 修改name + Db::name('admin_rule') + ->where('name', 'buildadmin/buildadmin') + ->update([ + 'name' => 'buildadmin', + ]); + + Db::commit(); + } catch (Throwable $e) { + Db::rollback(); + throw $e; + } + } +} diff --git a/database/migrations/20231112093414_version205.php b/database/migrations/20231112093414_version205.php new file mode 100644 index 0000000..6cf80e5 --- /dev/null +++ b/database/migrations/20231112093414_version205.php @@ -0,0 +1,24 @@ +find(); + $value = $configQuickEntrance->value; + foreach ($value as &$item) { + if (str_starts_with($item['value'], '/admin/')) { + $pathData = Db::name('admin_rule')->where('path', substr($item['value'], 7))->find(); + if ($pathData) { + $item['value'] = $pathData['name']; + } + } + } + $configQuickEntrance->value = $value; + $configQuickEntrance->save(); + } +} diff --git a/database/migrations/20231229043002_version206.php b/database/migrations/20231229043002_version206.php new file mode 100644 index 0000000..d36f141 --- /dev/null +++ b/database/migrations/20231229043002_version206.php @@ -0,0 +1,60 @@ +where('name', 'backend_entrance')->value('id'); + if (!$exist) { + $rows = [ + [ + 'name' => 'backend_entrance', + 'group' => 'basics', + 'title' => 'Backend entrance', + 'type' => 'string', + 'value' => '/admin', + 'rule' => 'required', + 'weigh' => 1, + ], + ]; + $table = $this->table('config'); + $table->insert($rows)->saveData(); + } + + $crudLog = $this->table('crud_log'); + if (!$crudLog->hasColumn('connection')) { + $crudLog->addColumn('connection', 'string', ['limit' => 100, 'default' => '', 'comment' => '数据库连接配置标识', 'null' => false, 'after' => 'status']); + $crudLog->save(); + } + + $securityDataRecycle = $this->table('security_data_recycle'); + if (!$securityDataRecycle->hasColumn('connection')) { + $securityDataRecycle->addColumn('connection', 'string', ['limit' => 100, 'default' => '', 'comment' => '数据库连接配置标识', 'null' => false, 'after' => 'data_table']); + $securityDataRecycle->save(); + } + + $securityDataRecycleLog = $this->table('security_data_recycle_log'); + if (!$securityDataRecycleLog->hasColumn('connection')) { + $securityDataRecycleLog->addColumn('connection', 'string', ['limit' => 100, 'default' => '', 'comment' => '数据库连接配置标识', 'null' => false, 'after' => 'data_table']); + $securityDataRecycleLog->save(); + } + + $securitySensitiveData = $this->table('security_sensitive_data'); + if (!$securitySensitiveData->hasColumn('connection')) { + $securitySensitiveData->addColumn('connection', 'string', ['limit' => 100, 'default' => '', 'comment' => '数据库连接配置标识', 'null' => false, 'after' => 'data_table']); + $securitySensitiveData->save(); + } + + $securitySensitiveDataLog = $this->table('security_sensitive_data_log'); + if (!$securitySensitiveDataLog->hasColumn('connection')) { + $securitySensitiveDataLog->addColumn('connection', 'string', ['limit' => 100, 'default' => '', 'comment' => '数据库连接配置标识', 'null' => false, 'after' => 'data_table']); + $securitySensitiveDataLog->save(); + } + } +} diff --git a/database/migrations/20250412134127_version222.php b/database/migrations/20250412134127_version222.php new file mode 100644 index 0000000..60ace92 --- /dev/null +++ b/database/migrations/20250412134127_version222.php @@ -0,0 +1,80 @@ +table('attachment'); + $attachment->changeColumn('name', 'string', ['limit' => 120, 'default' => '', 'comment' => '原始名称', 'null' => false])->save(); + + /** + * 用户表 + * 1. status 注释优化 + * 2. password 增加长度至 password_hash 建议值 + * 3. salt 注释中标记废弃待删除 + */ + $user = $this->table('user'); + $user->changeColumn('status', 'string', ['limit' => 30, 'default' => '', 'comment' => '状态:enable=启用,disable=禁用', 'null' => false]) + ->changeColumn('password', 'string', ['limit' => 255, 'default' => '', 'comment' => '密码', 'null' => false]) + ->changeColumn('salt', 'string', ['limit' => 30, 'default' => '', 'comment' => '密码盐(废弃待删)', 'null' => false]) + ->save(); + + /** + * 管理员表 + * 1. status 改为字符串存储 + * 2. 其他和以上用户表的改动相同 + */ + $admin = $this->table('admin'); + $admin->changeColumn('status', 'string', ['limit' => 30, 'default' => '', 'comment' => '状态:enable=启用,disable=禁用', 'null' => false]) + ->changeColumn('password', 'string', ['limit' => 255, 'default' => '', 'comment' => '密码', 'null' => false]) + ->changeColumn('salt', 'string', ['limit' => 30, 'default' => '', 'comment' => '密码盐(废弃待删)', 'null' => false]) + ->save(); + + Db::name('admin')->where('status', '0')->update(['status' => 'disable']); + Db::name('admin')->where('status', '1')->update(['status' => 'enable']); + + /** + * CRUD 历史记录表 + */ + $crudLog = $this->table('crud_log'); + if (!$crudLog->hasColumn('comment')) { + $crudLog + ->addColumn('comment', 'string', ['limit' => 255, 'default' => '', 'comment' => '注释', 'null' => false, 'after' => 'table_name']) + ->addColumn('sync', 'integer', ['default' => 0, 'signed' => false, 'comment' => '同步记录', 'null' => false, 'after' => 'fields']) + ->save(); + + $logs = CrudLog::select(); + foreach ($logs as $log) { + if ($log->table['comment']) { + $log->comment = $log->table['comment']; + $log->save(); + } + } + } + + /** + * 多个数据表的 status 字段类型修改为更合理的类型 + */ + $tables = ['admin_group', 'admin_rule', 'user_group', 'user_rule', 'security_data_recycle', 'security_sensitive_data', 'test_build']; + foreach ($tables as $table) { + if ($this->hasTable($table)) { + $mTable = $this->table($table); + $mTable->changeColumn('status', 'boolean', ['default' => 1, 'signed' => false, 'comment' => '状态:0=禁用,1=启用', 'null' => false])->save(); + + // 原状态值兼容至新类型 + Db::name($table)->where('status', 1)->update(['status' => 0]); + Db::name($table)->where('status', 2)->update(['status' => 1]); + } + } + } +} diff --git a/extend/ba/Auth.php b/extend/ba/Auth.php new file mode 100644 index 0000000..b1fdb65 --- /dev/null +++ b/extend/ba/Auth.php @@ -0,0 +1,241 @@ + 'admin_group', // 用户组数据表名 + 'auth_group_access' => 'admin_group_access', // 用户-用户组关系表 + 'auth_rule' => 'admin_rule', // 权限规则表 + ]; + + /** + * 子菜单规则数组 + * @var array + */ + protected array $children = []; + + /** + * 构造方法 + * @param array $config + */ + public function __construct(array $config = []) + { + $this->config = array_merge($this->config, $config); + } + + /** + * 魔术方法-获取当前配置 + * @param $name + * @return mixed + */ + public function __get($name): mixed + { + return $this->config[$name]; + } + + /** + * 获取菜单规则列表 + * @access public + * @param int $uid 用户ID + * @return array + * @throws Throwable + */ + public function getMenus(int $uid): array + { + $this->children = []; + $originAuthRules = $this->getOriginAuthRules($uid); + foreach ($originAuthRules as $rule) { + $this->children[$rule['pid']][] = $rule; + } + + // 没有根菜单规则 + if (!isset($this->children[0])) return []; + + return $this->getChildren($this->children[0]); + } + + /** + * 获取传递的菜单规则的子规则 + * @param array $rules 菜单规则 + * @return array + */ + private function getChildren(array $rules): array + { + foreach ($rules as $key => $rule) { + if (array_key_exists($rule['id'], $this->children)) { + $rules[$key]['children'] = $this->getChildren($this->children[$rule['id']]); + } + } + return $rules; + } + + /** + * 检查是否有某权限 + * @param string $name 菜单规则的 name,可以传递两个,以','号隔开 + * @param int $uid 用户ID + * @param string $relation 如果出现两个 name,是两个都通过(and)还是一个通过即可(or) + * @param string $mode 如果不使用 url 则菜单规则name匹配到即通过 + * @return bool + * @throws Throwable + */ + public function check(string $name, int $uid, string $relation = 'or', string $mode = 'url'): bool + { + // 获取用户需要验证的所有有效规则列表 + $ruleList = $this->getRuleList($uid); + if (in_array('*', $ruleList)) { + return true; + } + + if ($name) { + $name = strtolower($name); + if (str_contains($name, ',')) { + $name = explode(',', $name); + } else { + $name = [$name]; + } + } + $list = []; //保存验证通过的规则名 + if ('url' == $mode) { + $REQUEST = json_decode(strtolower(json_encode(request()->param(), JSON_UNESCAPED_UNICODE)), true); + } + foreach ($ruleList as $rule) { + $query = preg_replace('/^.+\?/U', '', $rule); + if ('url' == $mode && $query != $rule) { + parse_str($query, $param); //解析规则中的param + $intersect = array_intersect_assoc($REQUEST, $param); + $rule = preg_replace('/\?.*$/U', '', $rule); + if (in_array($rule, $name) && $intersect == $param) { + // 如果节点相符且url参数满足 + $list[] = $rule; + } + } elseif (in_array($rule, $name)) { + $list[] = $rule; + } + } + if ('or' == $relation && !empty($list)) { + return true; + } + $diff = array_diff($name, $list); + if ('and' == $relation && empty($diff)) { + return true; + } + + return false; + } + + /** + * 获得权限规则列表 + * @param int $uid 用户id + * @return array + * @throws Throwable + */ + public function getRuleList(int $uid): array + { + // 读取用户规则节点 + $ids = $this->getRuleIds($uid); + if (empty($ids)) return []; + + $originAuthRules = $this->getOriginAuthRules($uid); + + // 用户规则 + $rules = []; + if (in_array('*', $ids)) { + $rules[] = "*"; + } + foreach ($originAuthRules as $rule) { + $rules[$rule['id']] = strtolower($rule['name']); + } + return array_unique($rules); + } + + /** + * 获得权限规则原始数据 + * @param int $uid 用户id + * @return array + * @throws Throwable + */ + public function getOriginAuthRules(int $uid): array + { + $ids = $this->getRuleIds($uid); + if (empty($ids)) return []; + + $where = []; + $where[] = ['status', '=', '1']; + // 如果没有 * 则只获取用户拥有的规则 + if (!in_array('*', $ids)) { + $where[] = ['id', 'in', $ids]; + } + $rules = Db::name($this->config['auth_rule']) + ->withoutField(['remark', 'status', 'weigh', 'update_time', 'create_time']) + ->where($where) + ->order('weigh desc,id asc') + ->select() + ->toArray(); + foreach ($rules as $key => $rule) { + if (!empty($rule['keepalive'])) { + $rules[$key]['keepalive'] = $rule['name']; + } + } + + return $rules; + } + + /** + * 获取权限规则ids + * @param int $uid + * @return array + * @throws Throwable + */ + public function getRuleIds(int $uid): array + { + // 用户的组别和规则ID + $groups = $this->getGroups($uid); + $ids = []; + foreach ($groups as $g) { + $ids = array_merge($ids, explode(',', trim($g['rules'], ','))); + } + return array_unique($ids); + } + + /** + * 获取用户所有分组和对应权限规则 + * @param int $uid + * @return array + * @throws Throwable + */ + public function getGroups(int $uid): array + { + $dbName = $this->config['auth_group_access'] ?: 'user'; + if ($this->config['auth_group_access']) { + $userGroups = Db::name($dbName) + ->alias('aga') + ->join($this->config['auth_group'] . ' ag', 'aga.group_id = ag.id', 'LEFT') + ->field('aga.uid,aga.group_id,ag.id,ag.pid,ag.name,ag.rules') + ->where("aga.uid='$uid' and ag.status='1'") + ->select() + ->toArray(); + } else { + $userGroups = Db::name($dbName) + ->alias('u') + ->join($this->config['auth_group'] . ' ag', 'u.group_id = ag.id', 'LEFT') + ->field('u.id as uid,u.group_id,ag.id,ag.name,ag.rules') + ->where("u.id='$uid' and ag.status='1'") + ->select() + ->toArray(); + } + + return $userGroups; + } +} \ No newline at end of file diff --git a/extend/ba/Captcha.php b/extend/ba/Captcha.php new file mode 100644 index 0000000..ed05c83 --- /dev/null +++ b/extend/ba/Captcha.php @@ -0,0 +1,441 @@ + +// +---------------------------------------------------------------------- +// | 妙码生花在 2022-2-26 进行修订,通过Mysql保存验证码而不是Session以更好的支持API访问 +// | 使用Cache不能清理过期验证码,且一旦执行清理缓存操作,验证码将失效 +// +---------------------------------------------------------------------- + +namespace ba; + +use GdImage; +use Throwable; +use think\Response; +use think\facade\Db; + +/** + * 验证码类(图形验证码、继续流程验证码) + * @property string $seKey 验证码加密密钥 + * @property string $codeSet 验证码字符集合 + * @property int $expire 验证码过期时间(s) + * @property bool $useZh 使用中文验证码 + * @property string $zhSet 中文验证码字符串 + * @property bool $useImgBg 使用背景图片 + * @property int $fontSize 验证码字体大小(px) + * @property bool $useCurve 是否画混淆曲线 + * @property bool $useNoise 是否添加杂点 + * @property int $imageH 验证码图片高度 + * @property int $imageW 验证码图片宽度 + * @property int $length 验证码位数 + * @property string $fontTtf 验证码字体,不设置随机获取 + * @property array $bg 背景颜色 + * @property bool $reset 验证成功后是否重置 + */ +class Captcha +{ + protected array $config = [ + // 验证码加密密钥 + 'seKey' => 'BuildAdmin', + // 验证码字符集合 + 'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY', + // 验证码过期时间(s) + 'expire' => 600, + // 使用中文验证码 + 'useZh' => false, + // 中文验证码字符串 + 'zhSet' => '们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借', + // 使用背景图片 + 'useImgBg' => false, + // 验证码字体大小(px) + 'fontSize' => 25, + // 是否画混淆曲线 + 'useCurve' => true, + // 是否添加杂点 + 'useNoise' => true, + // 验证码图片高度 + 'imageH' => 0, + // 验证码图片宽度 + 'imageW' => 0, + // 验证码位数 + 'length' => 4, + // 验证码字体,不设置随机获取 + 'fontTtf' => '', + // 背景颜色 + 'bg' => [243, 251, 254], + // 验证成功后是否重置 + 'reset' => true, + ]; + + /** + * 验证码图片实例 + * @var GdImage|resource|null + */ + private $image = null; + + /** + * 验证码字体颜色 + * @var bool|int|null + */ + private bool|int|null $color = null; + + /** + * 架构方法 设置参数 + * @param array $config 配置参数 + * @throws Throwable + */ + public function __construct(array $config = []) + { + $this->config = array_merge($this->config, $config); + + // 清理过期的验证码 + Db::name('captcha') + ->where('expire_time', '<', time()) + ->delete(); + } + + /** + * 使用 $this->name 获取配置 + * @param string $name 配置名称 + * @return mixed 配置值 + */ + public function __get(string $name): mixed + { + return $this->config[$name]; + } + + /** + * 设置验证码配置 + * @param string $name 配置名称 + * @param mixed $value 配置值 + * @return void + */ + public function __set(string $name, mixed $value): void + { + if (isset($this->config[$name])) { + $this->config[$name] = $value; + } + } + + /** + * 检查配置 + * @param string $name 配置名称 + * @return bool + */ + public function __isset(string $name): bool + { + return isset($this->config[$name]); + } + + /** + * 验证验证码是否正确 + * @param string $code 用户验证码 + * @param string $id 验证码标识 + * @return bool 用户验证码是否正确 + * @throws Throwable + */ + public function check(string $code, string $id): bool + { + $key = $this->authCode($this->seKey, $id); + $seCode = Db::name('captcha')->where('key', $key)->find(); + + // 验证码为空 + if (empty($code) || empty($seCode)) { + return false; + } + + // 验证码过期 + if (time() > $seCode['expire_time']) { + Db::name('captcha')->where('key', $key)->delete(); + return false; + } + + if ($this->authCode(strtoupper($code), $id) == $seCode['code']) { + $this->reset && Db::name('captcha')->where('key', $key)->delete(); + return true; + } + + return false; + } + + /** + * 创建一个逻辑验证码可供后续验证(非图形) + * @param string $id 验证码标识 + * @param string|bool $captcha 验证码,不传递则自动生成 + * @return string 生成的验证码,发送出去或做它用... + * @throws Throwable + */ + public function create(string $id, string|bool $captcha = false): string + { + $nowTime = time(); + $key = $this->authCode($this->seKey, $id); + $captchaTemp = Db::name('captcha')->where('key', $key)->find(); + if ($captchaTemp) { + // 重复的为同一标识创建验证码 + Db::name('captcha')->where('key', $key)->delete(); + } + $captcha = $this->generate($captcha); + $code = $this->authCode($captcha, $id); + Db::name('captcha') + ->insert([ + 'key' => $key, + 'code' => $code, + 'captcha' => $captcha, + 'create_time' => $nowTime, + 'expire_time' => $nowTime + $this->expire + ]); + return $captcha; + } + + /** + * 获取验证码数据 + * @param string $id 验证码标识 + * @return array + * @throws Throwable + */ + public function getCaptchaData(string $id): array + { + $key = $this->authCode($this->seKey, $id); + $seCode = Db::name('captcha')->where('key', $key)->find(); + return $seCode ?: []; + } + + /** + * 输出图形验证码并把验证码的值保存的Mysql中 + * @param string $id 要生成验证码的标识 + * @return Response + * @throws Throwable + */ + public function entry(string $id): Response + { + $nowTime = time(); + // 图片宽(px) + $this->imageW || $this->imageW = $this->length * $this->fontSize * 1.5 + $this->length * $this->fontSize / 2; + // 图片高(px) + $this->imageH || $this->imageH = $this->fontSize * 2.5; + // 建立一幅 $this->imageW x $this->imageH 的图像 + $this->image = imagecreate($this->imageW, $this->imageH); + // 设置背景 + imagecolorallocate($this->image, $this->bg[0], $this->bg[1], $this->bg[2]); + + // 验证码字体随机颜色 + $this->color = imagecolorallocate($this->image, mt_rand(1, 150), mt_rand(1, 150), mt_rand(1, 150)); + // 验证码使用随机字体 + $ttfPath = public_path() . 'static' . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR . ($this->useZh ? 'zhttfs' : 'ttfs') . DIRECTORY_SEPARATOR; + + if (empty($this->fontTtf)) { + $dir = dir($ttfPath); + $ttfFiles = []; + while (false !== ($file = $dir->read())) { + if ('.' != $file[0] && str_ends_with($file, '.ttf')) { + $ttfFiles[] = $file; + } + } + $dir->close(); + $this->fontTtf = $ttfFiles[array_rand($ttfFiles)]; + } + $this->fontTtf = $ttfPath . $this->fontTtf; + + if ($this->useImgBg) { + $this->background(); + } + + if ($this->useNoise) { + // 绘杂点 + $this->writeNoise(); + } + if ($this->useCurve) { + // 绘干扰线 + $this->writeCurve(); + } + + $key = $this->authCode($this->seKey, $id); + $captcha = Db::name('captcha')->where('key', $key)->find(); + + // 绘验证码 + if ($captcha && $nowTime <= $captcha['expire_time']) { + $this->writeText($captcha['captcha']); + } else { + $captcha = $this->writeText(); + + // 保存验证码 + $code = $this->authCode(strtoupper(implode('', $captcha)), $id); + Db::name('captcha')->insert([ + 'key' => $key, + 'code' => $code, + 'captcha' => strtoupper(implode('', $captcha)), + 'create_time' => $nowTime, + 'expire_time' => $nowTime + $this->expire + ]); + } + + ob_start(); + // 输出图像 + imagepng($this->image); + $content = ob_get_clean(); + + return response($content, 200, ['Content-Length' => strlen($content)])->contentType('image/png'); + } + + /** + * 绘验证码 + * @param string $captcha 验证码 + * @return array|string 验证码 + */ + private function writeText(string $captcha = ''): array|string + { + $code = []; // 验证码 + $codeNX = 0; // 验证码第N个字符的左边距 + if ($this->useZh) { + // 中文验证码 + for ($i = 0; $i < $this->length; $i++) { + $code[$i] = $captcha ? $captcha[$i] : iconv_substr($this->zhSet, floor(mt_rand(0, mb_strlen($this->zhSet, 'utf-8') - 1)), 1, 'utf-8'); + imagettftext($this->image, $this->fontSize, mt_rand(-40, 40), $this->fontSize * ($i + 1) * 1.5, $this->fontSize + mt_rand(10, 20), (int)$this->color, $this->fontTtf, $code[$i]); + } + } else { + for ($i = 0; $i < $this->length; $i++) { + $code[$i] = $captcha ? $captcha[$i] : $this->codeSet[mt_rand(0, strlen($this->codeSet) - 1)]; + $codeNX += mt_rand((int)($this->fontSize * 1.2), (int)($this->fontSize * 1.6)); + imagettftext($this->image, $this->fontSize, mt_rand(-40, 40), $codeNX, (int)($this->fontSize * 1.6), (int)$this->color, $this->fontTtf, $code[$i]); + } + } + return $captcha ?: $code; + } + + /** + * 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数) + * 正弦型函数解析式:y=Asin(ωx+φ)+b + * 各常数值对函数图像的影响: + * A:决定峰值(即纵向拉伸压缩的倍数) + * b:表示波形在Y轴的位置关系或纵向移动距离(上加下减) + * φ:决定波形与X轴位置关系或横向移动距离(左加右减) + * ω:决定周期(最小正周期T=2π/∣ω∣) + */ + private function writeCurve(): void + { + $py = 0; + + // 曲线前部分 + $A = mt_rand(1, $this->imageH / 2); // 振幅 + $b = mt_rand(-$this->imageH / 4, $this->imageH / 4); // Y轴方向偏移量 + $f = mt_rand(-$this->imageH / 4, $this->imageH / 4); // X轴方向偏移量 + $T = mt_rand($this->imageH, $this->imageW * 2); // 周期 + $w = (2 * M_PI) / $T; + + $px1 = 0; // 曲线横坐标起始位置 + $px2 = mt_rand($this->imageW / 2, $this->imageW * 0.8); // 曲线横坐标结束位置 + + for ($px = $px1; $px <= $px2; $px = $px + 1) { + if (0 != $w) { + $py = $A * sin($w * $px + $f) + $b + $this->imageH / 2; // y = Asin(ωx+φ) + b + $i = (int)($this->fontSize / 5); + while ($i > 0) { + imagesetpixel($this->image, $px + $i, $py + $i, (int)$this->color); // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出(不用这while循环)性能要好很多 + $i--; + } + } + } + + // 曲线后部分 + $A = mt_rand(1, $this->imageH / 2); // 振幅 + $f = mt_rand(-$this->imageH / 4, $this->imageH / 4); // X轴方向偏移量 + $T = mt_rand($this->imageH, $this->imageW * 2); // 周期 + $w = (2 * M_PI) / $T; + $b = $py - $A * sin($w * $px + $f) - $this->imageH / 2; + $px1 = $px2; + $px2 = $this->imageW; + + for ($px = $px1; $px <= $px2; $px = $px + 1) { + if (0 != $w) { + $py = $A * sin($w * $px + $f) + $b + $this->imageH / 2; // y = Asin(ωx+φ) + b + $i = (int)($this->fontSize / 5); + while ($i > 0) { + imagesetpixel($this->image, $px + $i, $py + $i, (int)$this->color); + $i--; + } + } + } + } + + /** + * 绘杂点,往图片上写不同颜色的字母或数字 + */ + private function writeNoise(): void + { + $codeSet = '2345678abcdefhijkmnpqrstuvwxyz'; + for ($i = 0; $i < 10; $i++) { + //杂点颜色 + $noiseColor = imagecolorallocate($this->image, mt_rand(150, 225), mt_rand(150, 225), mt_rand(150, 225)); + for ($j = 0; $j < 5; $j++) { + // 绘制 + imagestring($this->image, 5, mt_rand(-10, $this->imageW), mt_rand(-10, $this->imageH), $codeSet[mt_rand(0, 29)], $noiseColor); + } + } + } + + /** + * 绘制背景图片 + * + * 注:如果验证码输出图片比较大,将占用比较多的系统资源 + */ + private function background(): void + { + $path = Filesystem::fsFit(public_path() . 'static/images/captcha/image/'); + $dir = dir($path); + + $bgs = []; + while (false !== ($file = $dir->read())) { + if ('.' != $file[0] && str_ends_with($file, '.jpg')) { + $bgs[] = $path . $file; + } + } + $dir->close(); + + $gb = $bgs[array_rand($bgs)]; + + list($width, $height) = @getimagesize($gb); + // Resample + $bgImage = @imagecreatefromjpeg($gb); + @imagecopyresampled($this->image, $bgImage, 0, 0, 0, 0, $this->imageW, $this->imageH, $width, $height); + } + + + /** + * 加密验证码 + * @param string $str 验证码字符串 + * @param string $id 验证码标识 + */ + private function authCode(string $str, string $id): string + { + $key = substr(md5($this->seKey), 5, 8); + $str = substr(md5($str), 8, 10); + return md5($key . $str . $id); + } + + /** + * 生成验证码随机字符 + * @param bool|string $captcha + * @return string + */ + private function generate(bool|string $captcha = false): string + { + $code = []; // 验证码 + if ($this->useZh) { + // 中文验证码 + for ($i = 0; $i < $this->length; $i++) { + $code[$i] = $captcha ? $captcha[$i] : iconv_substr($this->zhSet, floor(mt_rand(0, mb_strlen($this->zhSet, 'utf-8') - 1)), 1, 'utf-8'); + } + } else { + for ($i = 0; $i < $this->length; $i++) { + $code[$i] = $captcha ? $captcha[$i] : $this->codeSet[mt_rand(0, strlen($this->codeSet) - 1)]; + } + } + $captcha = $captcha ?: implode('', $code); + return strtoupper($captcha); + } +} \ No newline at end of file diff --git a/extend/ba/ClickCaptcha.php b/extend/ba/ClickCaptcha.php new file mode 100644 index 0000000..7330fd7 --- /dev/null +++ b/extend/ba/ClickCaptcha.php @@ -0,0 +1,335 @@ + '飞机', + 'apple' => '苹果', + 'banana' => '香蕉', + 'bell' => '铃铛', + 'bicycle' => '自行车', + 'bird' => '小鸟', + 'bomb' => '炸弹', + 'butterfly' => '蝴蝶', + 'candy' => '糖果', + 'crab' => '螃蟹', + 'cup' => '杯子', + 'dolphin' => '海豚', + 'fire' => '火', + 'guitar' => '吉他', + 'hexagon' => '六角形', + 'pear' => '梨', + 'rocket' => '火箭', + 'sailboat' => '帆船', + 'snowflake' => '雪花', + 'wolf head' => '狼头', + ]; + + /** + * 配置 + * @var array + */ + private array $config = [ + // 透明度 + 'alpha' => 36, + // 中文字符集 + 'zhSet' => '们以我到他会作时要动国产的是工就年阶义发成部民可出能方进在和有大这主中为来分生对于学级地用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所起政好十战无农使前等反体合斗路图把结第里正新开论之物从当两些还天资事队点育重其思与间内去因件利相由压员气业代全组数果期导平各基或月然如应形想制心样都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极已根共直团统式转别造切九你取西持总料连任志观调么山程百报更见必真保热委手改管处己将修支识象先老光专什六型具示复安带每东增则完风回南劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单坚据速防史拉世设达尔场织历花求传断况采精金界品判参层止边清至万确究书术状须离再目海权且青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿胜细影济白格效置推空配叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非亚磨族段算适讲按值美态易彪服早班麦削信排台声该击素张密害侯何树肥继右属市严径螺检左页抗苏显苦英快称坏移巴材省黑武培著河帝仅针怎植京助升王眼她抓苗副杂普谈围食源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功友限项余倒卷创律雨让骨远帮初皮播优占圈伟季训控激找叫云互跟粮粒母练塞钢顶策双留误础阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺版烈零室轻倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送侧润盖挥距触星松送获兴独官混纪依未突架宽冬章偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞哪旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶念兰映沟乙吗儒汽磷艰晶埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀摆贡呈劲财仪沉炼麻祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜脂庄擦险赞钟摇典柄辩竹谷乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼峰零柴簧午跳居尚秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑冰柬嘴啥饭塑寄赵喊垫丹渡耳虎笔稀昆浪萨茶滴浅拥覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷忽闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳塘燥泡袋朗喂铝软渠颗惯贸综墙趋彼届墨碍启逆卸航衣孙龄岭休借', + ]; + + /** + * 构造方法 + * @param array $config 点击验证码配置 + * @throws Throwable + */ + public function __construct(array $config = []) + { + $clickConfig = Config::get('buildadmin.click_captcha'); + $this->config = array_merge($clickConfig, $this->config, $config); + + // 清理过期的验证码 + Db::name('captcha')->where('expire_time', '<', time())->delete(); + } + + /** + * 创建图形验证码 + * @param string $id 验证码ID,开发者自定义 + * @return array 返回验证码图片的base64编码和验证码文字信息 + */ + public function creat(string $id): array + { + $imagePath = Filesystem::fsFit(public_path() . $this->bgPaths[mt_rand(0, count($this->bgPaths) - 1)]); + $fontPath = Filesystem::fsFit(public_path() . $this->fontPaths[mt_rand(0, count($this->fontPaths) - 1)]); + $randPoints = $this->randPoints($this->config['length'] + $this->config['confuse_length']); + + $lang = Lang::getLangSet(); + + foreach ($randPoints as $v) { + $tmp['size'] = rand(15, 30); + if (isset($this->iconDict[$v])) { + // 图标 + $tmp['icon'] = true; + $tmp['name'] = $v; + $tmp['text'] = $lang == 'zh-cn' ? "<{$this->iconDict[$v]}>" : "<$v>"; + $iconInfo = getimagesize(Filesystem::fsFit(public_path() . 'static/images/captcha/click/icons/' . $v . '.png')); + $tmp['width'] = $iconInfo[0]; + $tmp['height'] = $iconInfo[1]; + } else { + // 字符串文本框宽度和长度 + $fontArea = imagettfbbox($tmp['size'], 0, $fontPath, $v); + $textWidth = $fontArea[2] - $fontArea[0]; + $textHeight = $fontArea[1] - $fontArea[7]; + $tmp['icon'] = false; + $tmp['text'] = $v; + $tmp['width'] = $textWidth; + $tmp['height'] = $textHeight; + } + $textArr['text'][] = $tmp; + } + // 图片宽高和类型 + $imageInfo = getimagesize($imagePath); + $textArr['width'] = $imageInfo[0]; + $textArr['height'] = $imageInfo[1]; + // 随机生成验证点位置 + foreach ($textArr['text'] as &$v) { + list($x, $y) = $this->randPosition($textArr['text'], $textArr['width'], $textArr['height'], $v['width'], $v['height'], $v['icon']); + $v['x'] = $x; + $v['y'] = $y; + $text[] = $v['text']; + } + unset($v); + // 创建图片的实例 + $image = imagecreatefromstring(file_get_contents($imagePath)); + foreach ($textArr['text'] as $v) { + if ($v['icon']) { + $this->iconCover($image, $v); + } else { + //字体颜色 + $color = imagecolorallocatealpha($image, 239, 239, 234, 127 - intval($this->config['alpha'] * (127 / 100))); + // 绘画文字 + imagettftext($image, $v['size'], 0, $v['x'], $v['y'], $color, $fontPath, $v['text']); + } + } + $nowTime = time(); + $textArr['text'] = array_splice($textArr['text'], 0, $this->config['length']); + $text = array_splice($text, 0, $this->config['length']); + Db::name('captcha') + ->replace() + ->insert([ + 'key' => md5($id), + 'code' => md5(implode(',', $text)), + 'captcha' => json_encode($textArr, JSON_UNESCAPED_UNICODE), + 'create_time' => $nowTime, + 'expire_time' => $nowTime + $this->expire + ]); + + // 输出图片 + while (ob_get_level()) { + ob_end_clean(); + } + if (!ob_get_level()) ob_start(); + switch ($imageInfo[2]) { + case 1:// GIF + imagegif($image); + $content = ob_get_clean(); + break; + case 2:// JPG + imagejpeg($image); + $content = ob_get_clean(); + break; + case 3:// PNG + imagepng($image); + $content = ob_get_clean(); + break; + default: + $content = ''; + break; + } + return [ + 'id' => $id, + 'text' => $text, + 'base64' => 'data:' . $imageInfo['mime'] . ';base64,' . base64_encode($content), + 'width' => $textArr['width'], + 'height' => $textArr['height'], + ]; + } + + /** + * 检查验证码 + * @param string $id 开发者自定义的验证码ID + * @param string $info 验证信息 + * @param bool $unset 验证成功是否删除验证码 + * @return bool + * @throws Throwable + */ + public function check(string $id, string $info, bool $unset = true): bool + { + $key = md5($id); + $captcha = Db::name('captcha')->where('key', $key)->find(); + if ($captcha) { + // 验证码过期 + if (time() > $captcha['expire_time']) { + Db::name('captcha')->where('key', $key)->delete(); + return false; + } + $textArr = json_decode($captcha['captcha'], true); + list($xy, $w, $h) = explode(';', $info); + $xyArr = explode('-', $xy); + $xPro = $w / $textArr['width'];// 宽度比例 + $yPro = $h / $textArr['height'];// 高度比例 + foreach ($xyArr as $k => $v) { + $xy = explode(',', $v); + $x = $xy[0]; + $y = $xy[1]; + if ($x / $xPro < $textArr['text'][$k]['x'] || $x / $xPro > $textArr['text'][$k]['x'] + $textArr['text'][$k]['width']) { + return false; + } + $phStart = $textArr['text'][$k]['icon'] ? $textArr['text'][$k]['y'] : $textArr['text'][$k]['y'] - $textArr['text'][$k]['height']; + $phEnd = $textArr['text'][$k]['icon'] ? $textArr['text'][$k]['y'] + $textArr['text'][$k]['height'] : $textArr['text'][$k]['y']; + if ($y / $yPro < $phStart || $y / $yPro > $phEnd) { + return false; + } + } + if ($unset) Db::name('captcha')->where('key', $key)->delete(); + return true; + } else { + return false; + } + } + + /** + * 绘制Icon + */ + protected function iconCover($bgImg, $iconImgData): void + { + $iconImage = imagecreatefrompng(Filesystem::fsFit(public_path() . 'static/images/captcha/click/icons/' . $iconImgData['name'] . '.png')); + $trueColorImage = imagecreatetruecolor($iconImgData['width'], $iconImgData['height']); + imagecopy($trueColorImage, $bgImg, 0, 0, $iconImgData['x'], $iconImgData['y'], $iconImgData['width'], $iconImgData['height']); + imagecopy($trueColorImage, $iconImage, 0, 0, 0, 0, $iconImgData['width'], $iconImgData['height']); + imagecopymerge($bgImg, $trueColorImage, $iconImgData['x'], $iconImgData['y'], 0, 0, $iconImgData['width'], $iconImgData['height'], $this->config['alpha']); + } + + /** + * 随机生成验证点元素 + * @param int $length + * @return array + */ + public function randPoints(int $length = 4): array + { + $arr = []; + // 文字 + if (in_array('text', $this->config['mode'])) { + for ($i = 0; $i < $length; $i++) { + $arr[] = mb_substr($this->config['zhSet'], mt_rand(0, mb_strlen($this->config['zhSet'], 'utf-8') - 1), 1, 'utf-8'); + } + } + + // 图标 + if (in_array('icon', $this->config['mode'])) { + $icon = array_keys($this->iconDict); + shuffle($icon); + $icon = array_slice($icon, 0, $length); + $arr = array_merge($arr, $icon); + } + + shuffle($arr); + return array_slice($arr, 0, $length); + } + + /** + * 随机生成位置布局 + * @param array $textArr 点位数据 + * @param int $imgW 图片宽度 + * @param int $imgH 图片高度 + * @param int $fontW 文字宽度 + * @param int $fontH 文字高度 + * @param bool $isIcon 是否是图标 + * @return array + */ + private function randPosition(array $textArr, int $imgW, int $imgH, int $fontW, int $fontH, bool $isIcon): array + { + $x = rand(0, $imgW - $fontW); + $y = rand($fontH, $imgH - $fontH); + // 碰撞验证 + if (!$this->checkPosition($textArr, $x, $y, $fontW, $fontH, $isIcon)) { + $position = $this->randPosition($textArr, $imgW, $imgH, $fontW, $fontH, $isIcon); + } else { + $position = [$x, $y]; + } + return $position; + } + + /** + * 碰撞验证 + * @param array $textArr 验证点数据 + * @param int $x x轴位置 + * @param int $y y轴位置 + * @param int $w 验证点宽度 + * @param int $h 验证点高度 + * @param bool $isIcon 是否是图标 + * @return bool + */ + public function checkPosition(array $textArr, int $x, int $y, int $w, int $h, bool $isIcon): bool + { + $flag = true; + foreach ($textArr as $v) { + if (isset($v['x']) && isset($v['y'])) { + $flagX = false; + $flagY = false; + $historyPw = $v['x'] + $v['width']; + if (($x + $w) < $v['x'] || $x > $historyPw) { + $flagX = true; + } + + $currentPhStart = $isIcon ? $y : $y - $h; + $currentPhEnd = $isIcon ? $y + $v['height'] : $y; + $historyPhStart = $v['icon'] ? $v['y'] : ($v['y'] - $v['height']); + $historyPhEnd = $v['icon'] ? ($v['y'] + $v['height']) : $v['y']; + if ($currentPhEnd < $historyPhStart || $currentPhStart > $historyPhEnd) { + $flagY = true; + } + if (!$flagX && !$flagY) { + $flag = false; + } + } + } + return $flag; + } +} \ No newline at end of file diff --git a/extend/ba/Date.php b/extend/ba/Date.php new file mode 100644 index 0000000..9c168e2 --- /dev/null +++ b/extend/ba/Date.php @@ -0,0 +1,195 @@ +. + * @param string $remote timezone that to find the offset of + * @param string|null $local timezone used as the baseline + * @param string|int|null $now UNIX timestamp or date string + * @return int + * @throws Throwable + * @example $seconds = self::offset('America/Chicago', 'GMT'); + */ + public static function offset(string $remote, ?string $local = null, string|int|null $now = null): int + { + if ($local === null) { + // Use the default timezone + $local = date_default_timezone_get(); + } + if (is_int($now)) { + // Convert the timestamp into a string + $now = date(DateTimeInterface::RFC2822, $now); + } + // Create timezone objects + $zone_remote = new DateTimeZone($remote); + $zone_local = new DateTimeZone($local); + // Create date objects from timezones + $time_remote = new DateTime($now, $zone_remote); + $time_local = new DateTime($now, $zone_local); + // Find the offset + return $zone_remote->getOffset($time_remote) - $zone_local->getOffset($time_local); + } + + /** + * 计算两个时间戳之间相差的时间 + * + * $span = self::span(60, 182, 'minutes,seconds'); // array('minutes' => 2, 'seconds' => 2) + * $span = self::span(60, 182, 'minutes'); // 2 + * + * @param int $remote timestamp to find the span of + * @param int|null $local timestamp to use as the baseline + * @param string $output formatting string + * @return bool|array|string associative list of all outputs requested|when only a single output is requested + * @from https://github.com/kohana/ohanzee-helpers/blob/master/src/Date.php + */ + public static function span(int $remote, ?int $local = null, string $output = 'years,months,weeks,days,hours,minutes,seconds'): bool|array|string + { + // Normalize output + $output = trim(strtolower($output)); + if (!$output) { + // Invalid output + return false; + } + // Array with the output formats + $output = preg_split('/[^a-z]+/', $output); + // Convert the list of outputs to an associative array + $output = array_combine($output, array_fill(0, count($output), 0)); + // Make the output values into keys + extract(array_flip($output), EXTR_SKIP); + if ($local === null) { + // Calculate the span from the current time + $local = time(); + } + // Calculate timespan (seconds) + $timespan = abs($remote - $local); + if (isset($output['years'])) { + $timespan -= self::YEAR * ($output['years'] = (int)floor($timespan / self::YEAR)); + } + if (isset($output['months'])) { + $timespan -= self::MONTH * ($output['months'] = (int)floor($timespan / self::MONTH)); + } + if (isset($output['weeks'])) { + $timespan -= self::WEEK * ($output['weeks'] = (int)floor($timespan / self::WEEK)); + } + if (isset($output['days'])) { + $timespan -= self::DAY * ($output['days'] = (int)floor($timespan / self::DAY)); + } + if (isset($output['hours'])) { + $timespan -= self::HOUR * ($output['hours'] = (int)floor($timespan / self::HOUR)); + } + if (isset($output['minutes'])) { + $timespan -= self::MINUTE * ($output['minutes'] = (int)floor($timespan / self::MINUTE)); + } + // Seconds ago, 1 + if (isset($output['seconds'])) { + $output['seconds'] = $timespan; + } + if (count($output) === 1) { + // Only a single output was requested, return it + return array_pop($output); + } + // Return array + return $output; + } + + /** + * 格式化 UNIX 时间戳为人易读的字符串 + * + * @param int $remote Unix 时间戳 + * @param ?int $local 本地时间戳 + * @return string 格式化的日期字符串 + */ + public static function human(int $remote, ?int $local = null): string + { + $timeDiff = (is_null($local) ? time() : $local) - $remote; + $tense = $timeDiff < 0 ? 'after' : 'ago'; + $timeDiff = abs($timeDiff); + $chunks = [ + [60 * 60 * 24 * 365, 'year'], + [60 * 60 * 24 * 30, 'month'], + [60 * 60 * 24 * 7, 'week'], + [60 * 60 * 24, 'day'], + [60 * 60, 'hour'], + [60, 'minute'], + [1, 'second'], + ]; + + $count = 0; + $name = ''; + for ($i = 0, $j = count($chunks); $i < $j; $i++) { + $seconds = $chunks[$i][0]; + $name = $chunks[$i][1]; + if (($count = floor($timeDiff / $seconds)) != 0) { + break; + } + } + return __("%d $name%s $tense", [$count, $count > 1 ? 's' : '']); + } + + /** + * 获取一个基于时间偏移的Unix时间戳 + * + * @param string $type 时间类型,默认为day,可选minute,hour,day,week,month,quarter,year + * @param int $offset 时间偏移量 默认为0,正数表示当前type之后,负数表示当前type之前 + * @param string $position 时间的开始或结束,默认为begin,可选前(begin,start,first,front),end + * @param int|null $year 基准年,默认为null,即以当前年为基准 + * @param int|null $month 基准月,默认为null,即以当前月为基准 + * @param int|null $day 基准天,默认为null,即以当前天为基准 + * @param int|null $hour 基准小时,默认为null,即以当前年小时基准 + * @param int|null $minute 基准分钟,默认为null,即以当前分钟为基准 + * @return int 处理后的Unix时间戳 + */ + public static function unixTime(string $type = 'day', int $offset = 0, string $position = 'begin', ?int $year = null, ?int $month = null, ?int $day = null, ?int $hour = null, ?int $minute = null): int + { + $year = is_null($year) ? date('Y') : $year; + $month = is_null($month) ? date('m') : $month; + $day = is_null($day) ? date('d') : $day; + $hour = is_null($hour) ? date('H') : $hour; + $minute = is_null($minute) ? date('i') : $minute; + $position = in_array($position, ['begin', 'start', 'first', 'front']); + + return match ($type) { + 'minute' => $position ? mktime($hour, $minute + $offset, 0, $month, $day, $year) : mktime($hour, $minute + $offset, 59, $month, $day, $year), + 'hour' => $position ? mktime($hour + $offset, 0, 0, $month, $day, $year) : mktime($hour + $offset, 59, 59, $month, $day, $year), + 'day' => $position ? mktime(0, 0, 0, $month, $day + $offset, $year) : mktime(23, 59, 59, $month, $day + $offset, $year), + // 使用固定的 this week monday 而不是 $offset weeks monday 的语法才能确保准确性 + 'week' => $position ? strtotime('this week monday', mktime(0, 0, 0, $month, $day + ($offset * 7), $year)) : strtotime('this week sunday 23:59:59', mktime(0, 0, 0, $month, $day + ($offset * 7), $year)), + 'month' => $position ? mktime(0, 0, 0, $month + $offset, 1, $year) : mktime(23, 59, 59, $month + $offset, self::daysInMonth($month + $offset, $year), $year), + 'quarter' => $position ? + mktime(0, 0, 0, 1 + ((ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) - 1) * 3, 1, $year) : + mktime(23, 59, 59, (ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) * 3, self::daysInMonth((ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) * 3, $year), $year), + 'year' => $position ? mktime(0, 0, 0, 1, 1, $year + $offset) : mktime(23, 59, 59, 12, 31, $year + $offset), + default => mktime($hour, $minute, 0, $month, $day, $year), + }; + } + + /** + * 获取给定月份的天数 (28 到 31) + */ + public static function daysInMonth(int $month, ?int $year = null): int + { + return (int)date('t', mktime(0, 0, 0, $month, 1, $year)); + } +} \ No newline at end of file diff --git a/extend/ba/Depends.php b/extend/ba/Depends.php new file mode 100644 index 0000000..9bd078e --- /dev/null +++ b/extend/ba/Depends.php @@ -0,0 +1,212 @@ +json)) { + throw new Exception($this->json . ' file does not exist!'); + } + if ($this->jsonContent && !$realTime) return $this->jsonContent; + $content = @file_get_contents($this->json); + $this->jsonContent = json_decode($content, true); + if (!$this->jsonContent) { + throw new Exception($this->json . ' file read failure!'); + } + return $this->jsonContent; + } + + /** + * 设置 json 文件内容 + * @param array $content + * @throws Throwable + */ + public function setContent(array $content = []): void + { + if (!$content) $content = $this->jsonContent; + if (!isset($content['name'])) { + throw new Exception('Depend content file content is incomplete'); + } + $content = json_encode($content, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); + $result = @file_put_contents($this->json, $content . PHP_EOL); + if (!$result) { + throw new Exception('File has no write permission:' . $this->json); + } + } + + /** + * 获取依赖项 + * @param bool $devEnv 是否是获取开发环境依赖 + * @return array + * @throws Throwable + */ + public function getDepends(bool $devEnv = false): array + { + try { + $content = $this->getContent(); + } catch (Throwable) { + return []; + } + + if ($this->type == 'npm') { + return $devEnv ? $content['devDependencies'] : $content['dependencies']; + } else { + return $devEnv ? $content['require-dev'] : $content['require']; + } + } + + /** + * 是否存在某个依赖 + * @param string $name 依赖名称 + * @param bool $devEnv 是否是获取开发环境依赖 + * @return bool|string false或者依赖版本号 + * @throws Throwable + */ + public function hasDepend(string $name, bool $devEnv = false): bool|string + { + $depends = $this->getDepends($devEnv); + return $depends[$name] ?? false; + } + + /** + * 添加依赖 + * @param array $depends 要添加的依赖数组["xxx" => ">=7.1.0",] + * @param bool $devEnv 是否添加为开发环境依赖 + * @param bool $cover 覆盖模式 + * @return void + * @throws Throwable + */ + public function addDepends(array $depends, bool $devEnv = false, bool $cover = false): void + { + $content = $this->getContent(true); + $dKey = $devEnv ? ($this->type == 'npm' ? 'devDependencies' : 'require-dev') : ($this->type == 'npm' ? 'dependencies' : 'require'); + if (!$cover) { + foreach ($depends as $key => $item) { + if (isset($content[$dKey][$key])) { + throw new Exception($key . ' depend already exists!'); + } + } + } + $content[$dKey] = array_merge($content[$dKey], $depends); + $this->setContent($content); + } + + /** + * 删除依赖 + * @param array $depends 要删除的依赖数组["php", "w7corp/easyWechat"] + * @param bool $devEnv 是否为开发环境删除依赖 + * @return void + * @throws Throwable + */ + public function removeDepends(array $depends, bool $devEnv = false): void + { + $content = $this->getContent(true); + $dKey = $devEnv ? ($this->type == 'npm' ? 'devDependencies' : 'require-dev') : ($this->type == 'npm' ? 'dependencies' : 'require'); + foreach ($depends as $item) { + if (isset($content[$dKey][$item])) { + unset($content[$dKey][$item]); + } + } + $this->setContent($content); + } + + /** + * 获取 composer.json 的 config 字段 + */ + public function getComposerConfig(): array + { + try { + $content = $this->getContent(); + } catch (Throwable) { + return []; + } + return $content['config']; + } + + /** + * 设置 composer.json 的 config 字段 + * @throws Throwable + */ + public function setComposerConfig(array $config, bool $cover = true): void + { + $content = $this->getContent(true); + + // 配置冲突检查 + if (!$cover) { + foreach ($config as $key => $item) { + if (is_array($item)) { + foreach ($item as $configKey => $configItem) { + if (isset($content['config'][$key][$configKey]) && $content['config'][$key][$configKey] != $configItem) { + throw new Exception(__('composer config %s conflict', [$configKey])); + } + } + } elseif (isset($content['config'][$key]) && $content['config'][$key] != $item) { + throw new Exception(__('composer config %s conflict', [$key])); + } + } + } + + foreach ($config as $key => $item) { + if (is_array($item)) { + foreach ($item as $configKey => $configItem) { + $content['config'][$key][$configKey] = $configItem; + } + } else { + $content['config'][$key] = $item; + } + } + $this->setContent($content); + } + + /** + * 删除 composer 配置项 + * @throws Throwable + */ + public function removeComposerConfig(array $config): void + { + if (!$config) return; + $content = $this->getContent(true); + foreach ($config as $key => $item) { + if (isset($content['config'][$key])) { + if (is_array($item)) { + foreach ($item as $configKey => $configItem) { + if (isset($content['config'][$key][$configKey])) unset($content['config'][$key][$configKey]); + } + + // 没有子级配置项了 + if (!$content['config'][$key]) { + unset($content['config'][$key]); + } + } else { + unset($content['config'][$key]); + } + } + } + $this->setContent($content); + } +} \ No newline at end of file diff --git a/extend/ba/Exception.php b/extend/ba/Exception.php new file mode 100644 index 0000000..ce2edce --- /dev/null +++ b/extend/ba/Exception.php @@ -0,0 +1,17 @@ +error(__($e->getMessage()), $e->getData(), $e->getCode()); + */ +class Exception extends E +{ + public function __construct(protected $message, protected $code = 0, protected $data = []) + { + parent::__construct($message, $code); + } +} \ No newline at end of file diff --git a/extend/ba/Filesystem.php b/extend/ba/Filesystem.php new file mode 100644 index 0000000..1f4c988 --- /dev/null +++ b/extend/ba/Filesystem.php @@ -0,0 +1,248 @@ +isDir()) { + self::delDir($fileInfo->getRealPath()); + } else { + @unlink($fileInfo->getRealPath()); + } + } + if ($delSelf) { + @rmdir($dir); + } + return true; + } + + /** + * 删除一个路径下的所有相对空文件夹(删除此路径中的所有空文件夹) + * @param string $path 相对于根目录的文件夹路径 如`c:BuildAdmin/a/b/` + * @return void + */ + public static function delEmptyDir(string $path): void + { + $path = str_replace(root_path(), '', rtrim(self::fsFit($path), DIRECTORY_SEPARATOR)); + $path = array_filter(explode(DIRECTORY_SEPARATOR, $path)); + for ($i = count($path) - 1; $i >= 0; $i--) { + $dirPath = root_path() . implode(DIRECTORY_SEPARATOR, $path); + if (!is_dir($dirPath)) { + unset($path[$i]); + continue; + } + if (self::dirIsEmpty($dirPath)) { + self::delDir($dirPath); + unset($path[$i]); + } else { + break; + } + } + } + + /** + * 检查目录/文件是否可写 + * @param $path + * @return bool + */ + public static function pathIsWritable($path): bool + { + if (DIRECTORY_SEPARATOR == '/' && !@ini_get('safe_mode')) { + return is_writable($path); + } + + if (is_dir($path)) { + $path = rtrim($path, '/') . '/' . md5(mt_rand(1, 100) . mt_rand(1, 100)); + if (($fp = @fopen($path, 'ab')) === false) { + return false; + } + + fclose($fp); + @chmod($path, 0777); + @unlink($path); + + return true; + } elseif (!is_file($path) || ($fp = @fopen($path, 'ab')) === false) { + return false; + } + + fclose($fp); + return true; + } + + /** + * 路径分隔符根据当前系统分隔符适配 + * @param string $path 路径 + * @return string 转换后的路径 + */ + public static function fsFit(string $path): string + { + return str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path); + } + + /** + * 解压Zip + * @param string $file ZIP文件路径 + * @param string $dir 解压路径 + * @return string 解压后的路径 + * @throws Throwable + */ + public static function unzip(string $file, string $dir = ''): string + { + if (!file_exists($file)) { + throw new Exception("Zip file not found"); + } + + $zip = new ZipFile(); + try { + $zip->openFile($file); + } catch (Throwable $e) { + $zip->close(); + throw new Exception('Unable to open the zip file', 0, ['msg' => $e->getMessage()]); + } + + $dir = $dir ?: substr($file, 0, strripos($file, '.zip')); + if (!is_dir($dir)) { + @mkdir($dir, 0755); + } + + try { + $zip->extractTo($dir); + } catch (Throwable $e) { + throw new Exception('Unable to extract ZIP file', 0, ['msg' => $e->getMessage()]); + } finally { + $zip->close(); + } + return $dir; + } + + /** + * 创建ZIP + * @param array $files 文件路径列表 + * @param string $fileName ZIP文件名称 + * @return bool + * @throws Throwable + */ + public static function zip(array $files, string $fileName): bool + { + $zip = new ZipFile(); + try { + foreach ($files as $v) { + if (is_array($v) && isset($v['file']) && isset($v['name'])) { + $zip->addFile(root_path() . str_replace(root_path(), '', Filesystem::fsFit($v['file'])), $v['name']); + } else { + $saveFile = str_replace(root_path(), '', Filesystem::fsFit($v)); + $zip->addFile(root_path() . $saveFile, $saveFile); + } + } + $zip->saveAsFile($fileName); + } catch (Throwable $e) { + throw new Exception('Unable to package zip file', 0, ['msg' => $e->getMessage(), 'file' => $fileName]); + } finally { + $zip->close(); + } + if (file_exists($fileName)) { + return true; + } else { + return false; + } + } + + /** + * 递归创建目录 + * @param string $dir 目录路径 + * @return bool + */ + public static function mkdir(string $dir): bool + { + if (!is_dir($dir)) { + return mkdir($dir, 0755, true); + } + return false; + } + + /** + * 获取一个目录内的文件列表 + * @param string $dir 目录路径 + * @param array $suffix 要获取的文件列表的后缀 + * @return array + */ + public static function getDirFiles(string $dir, array $suffix = []): array + { + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::LEAVES_ONLY + ); + + $fileList = []; + foreach ($files as $file) { + if ($file->isDir()) { + continue; + } + if (!empty($suffix) && !in_array($file->getExtension(), $suffix)) { + continue; + } + $filePath = $file->getRealPath(); + $name = str_replace($dir, '', $filePath); + $name = str_replace(DIRECTORY_SEPARATOR, "/", $name); + $fileList[$name] = $name; + } + return $fileList; + } + + /** + * 将一个文件单位转为字节 + * @param string $unit 将b、kb、m、mb、g、gb的单位转为 byte + * @return int byte + */ + public static function fileUnitToByte(string $unit): int + { + preg_match('/([0-9.]+)(\w+)/', $unit, $matches); + if (!$matches) { + return 0; + } + $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3]; + return (int)($matches[1] * pow(1024, $typeDict[strtolower($matches[2])] ?? 0)); + } +} diff --git a/extend/ba/Random.php b/extend/ba/Random.php new file mode 100644 index 0000000..4199ba1 --- /dev/null +++ b/extend/ba/Random.php @@ -0,0 +1,54 @@ + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', + 'alnum' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', + 'numeric' => '0123456789', + 'noZero' => '123456789', + default => '', + }; + return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len); + case 'unique': + case 'md5': + return md5(uniqid(mt_rand())); + case 'encrypt': + case 'sha1': + return sha1(uniqid(mt_rand(), true)); + } + return ''; + } + +} \ No newline at end of file diff --git a/extend/ba/TableManager.php b/extend/ba/TableManager.php new file mode 100644 index 0000000..a649eb9 --- /dev/null +++ b/extend/ba/TableManager.php @@ -0,0 +1,186 @@ +getAdapter($config['adapter'], $config); + if ($prefixWrapper) return $factory->getWrapper('prefix', $adapter); + return $adapter; + } + + /** + * 数据表名 + * @param string $table 表名,带不带前缀均可 + * @param bool $fullName 是否返回带前缀的表名 + * @param ?string $connection 连接配置标识 + * @return string 表名 + * @throws Exception + */ + public static function tableName(string $table, bool $fullName = true, ?string $connection = null): string + { + $connection = self::getConnectionConfig($connection); + $pattern = '/^' . $connection['prefix'] . '/i'; + return ($fullName ? $connection['prefix'] : '') . (preg_replace($pattern, '', $table)); + } + + /** + * 数据表列表 + * @param ?string $connection 连接配置标识 + * @throws Exception + */ + public static function getTableList(?string $connection = null): array + { + $tableList = []; + $config = self::getConnectionConfig($connection); + $connection = self::getConnection($connection); + $tables = Db::connect($connection)->query("SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema.TABLES WHERE table_schema = ? ", [$config['database']]); + foreach ($tables as $row) { + $tableList[$row['TABLE_NAME']] = $row['TABLE_NAME'] . ($row['TABLE_COMMENT'] ? ' - ' . $row['TABLE_COMMENT'] : ''); + } + return $tableList; + } + + /** + * 获取数据表所有列 + * @param string $table 数据表名 + * @param bool $onlyCleanComment 只要干净的字段注释信息 + * @param ?string $connection 连接配置标识 + * @throws Throwable + */ + public static function getTableColumns(string $table, bool $onlyCleanComment = false, ?string $connection = null): array + { + if (!$table) return []; + + $table = self::tableName($table, true, $connection); + $config = self::getConnectionConfig($connection); + $connection = self::getConnection($connection); + + // 从数据库中获取表字段信息 + // Phinx 目前无法正确获取到列注释信息,故使用 sql + $sql = "SELECT * FROM `information_schema`.`columns` " + . "WHERE TABLE_SCHEMA = ? AND table_name = ? " + . "ORDER BY ORDINAL_POSITION"; + $columnList = Db::connect($connection)->query($sql, [$config['database'], $table]); + + $fieldList = []; + foreach ($columnList as $item) { + if ($onlyCleanComment) { + $fieldList[$item['COLUMN_NAME']] = ''; + if ($item['COLUMN_COMMENT']) { + $comment = explode(':', $item['COLUMN_COMMENT']); + $fieldList[$item['COLUMN_NAME']] = $comment[0]; + } + continue; + } + $fieldList[$item['COLUMN_NAME']] = $item; + } + return $fieldList; + } + + /** + * 系统是否存在多个数据库连接配置 + */ + public static function isMultiDatabase(): bool + { + return count(Config::get("database.connections")) > 1; + } + + /** + * 获取数据库连接配置标识 + * @param ?string $source + * @return string 连接配置标识 + */ + public static function getConnection(?string $source = null): string + { + if (!$source || $source === 'default') { + return Config::get('database.default'); + } + return $source; + } + + /** + * 获取某个数据库连接的配置数组 + * @param ?string $connection 连接配置标识 + * @throws Exception + */ + public static function getConnectionConfig(?string $connection = null): array + { + $connection = self::getConnection($connection); + $connection = config("database.connections.$connection"); + if (!is_array($connection)) { + throw new Exception('Database connection configuration error'); + } + + // 分布式 + if ($connection['deploy'] == 1) { + $keys = ['type', 'hostname', 'database', 'username', 'password', 'hostport', 'charset', 'prefix']; + foreach ($connection as $key => $item) { + if (in_array($key, $keys)) { + $connection[$key] = is_array($item) ? $item[0] : explode(',', $item)[0]; + } + } + } + return $connection; + } + + /** + * 获取 Phinx 适配器需要的数据库配置 + * @param ?string $connection 连接配置标识 + * @return array + * @throws Throwable + */ + protected static function getPhinxDbConfig(?string $connection = null): array + { + $config = self::getConnectionConfig($connection); + $connection = self::getConnection($connection); + $db = Db::connect($connection); + + // 数据库为懒连接,执行 sql 命令为 $db 实例连接数据库 + $db->query('SELECT 1'); + + $table = Config::get('database.migration_table', 'migrations'); + return [ + 'adapter' => $config['type'], + 'connection' => $db->getPdo(), + 'name' => $config['database'], + 'table_prefix' => $config['prefix'], + 'migration_table' => $config['prefix'] . $table, + ]; + } +} \ No newline at end of file diff --git a/extend/ba/Terminal.php b/extend/ba/Terminal.php new file mode 100644 index 0000000..3e063ae --- /dev/null +++ b/extend/ba/Terminal.php @@ -0,0 +1,510 @@ + +// +---------------------------------------------------------------------- + +namespace ba; + +use Throwable; +use think\Response; +use think\facade\Config; +use app\admin\library\Auth; +use app\admin\library\module\Manage; +use think\exception\HttpResponseException; +use app\common\library\token\TokenExpirationException; + +class Terminal +{ + /** + * @var ?Terminal 对象实例 + */ + protected static ?Terminal $instance = null; + + /** + * @var string 当前执行的命令 $command 的 key + */ + protected string $commandKey = ''; + + /** + * @var array proc_open 的参数 + */ + protected array $descriptorsPec = []; + + /** + * @var resource|bool proc_open 返回的 resource + */ + protected $process = false; + + /** + * @var array proc_open 的管道 + */ + protected array $pipes = []; + + /** + * @var int proc执行状态:0=未执行,1=执行中,2=执行完毕 + */ + protected int $procStatusMark = 0; + + /** + * @var array proc执行状态数据 + */ + protected array $procStatusData = []; + + /** + * @var string 命令在前台的uuid + */ + protected string $uuid = ''; + + /** + * @var string 扩展信息 + */ + protected string $extend = ''; + + /** + * @var string 命令执行输出文件 + */ + protected string $outputFile = ''; + + /** + * @var string 命令执行实时输出内容 + */ + protected string $outputContent = ''; + + /** + * @var string 自动构建的前端文件的 outDir(相对于根目录) + */ + protected static string $distDir = 'web' . DIRECTORY_SEPARATOR . 'dist'; + + /** + * @var array 状态标识 + */ + protected array $flag = [ + // 连接成功 + 'link-success' => 'command-link-success', + // 执行成功 + 'exec-success' => 'command-exec-success', + // 执行完成 + 'exec-completed' => 'command-exec-completed', + // 执行出错 + 'exec-error' => 'command-exec-error', + ]; + + /** + * 初始化 + */ + public static function instance(): Terminal + { + if (is_null(self::$instance)) { + self::$instance = new static(); + } + return self::$instance; + } + + /** + * 构造函数 + */ + public function __construct() + { + $this->uuid = request()->param('uuid', ''); + $this->extend = request()->param('extend', ''); + + // 初始化日志文件 + $outputDir = root_path() . 'runtime' . DIRECTORY_SEPARATOR . 'terminal'; + $this->outputFile = $outputDir . DIRECTORY_SEPARATOR . 'exec.log'; + if (!is_dir($outputDir)) { + mkdir($outputDir, 0755, true); + } + file_put_contents($this->outputFile, ''); + + /** + * 命令执行结果输出到文件而不是管道 + * 因为输出到管道时有延迟,而文件虽然需要频繁读取和对比内容,但是输出实时的 + */ + $this->descriptorsPec = [0 => ['pipe', 'r'], 1 => ['file', $this->outputFile, 'w'], 2 => ['file', $this->outputFile, 'w']]; + } + + /** + * 获取命令 + * @param string $key 命令key + * @return array|bool + */ + public static function getCommand(string $key): bool|array + { + if (!$key) { + return false; + } + + $commands = Config::get('terminal.commands'); + if (stripos($key, '.')) { + $key = explode('.', $key); + if (!array_key_exists($key[0], $commands) || !is_array($commands[$key[0]]) || !array_key_exists($key[1], $commands[$key[0]])) { + return false; + } + $command = $commands[$key[0]][$key[1]]; + } else { + if (!array_key_exists($key, $commands)) { + return false; + } + $command = $commands[$key]; + } + if (!is_array($command)) { + $command = [ + 'cwd' => root_path(), + 'command' => $command, + ]; + } else { + $command['cwd'] = root_path() . $command['cwd']; + } + + if (str_contains($command['command'], '%')) { + $args = request()->param('extend', ''); + $args = explode('~~', $args); + $args = array_map('escapeshellarg', $args); + + array_unshift($args, $command['command']); + $command['command'] = call_user_func_array('sprintf', $args); + } + + $command['cwd'] = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $command['cwd']); + return $command; + } + + /** + * 执行命令 + * @param bool $authentication 是否鉴权 + * @throws Throwable + */ + public function exec(bool $authentication = true): void + { + $this->sendHeader(); + + while (ob_get_level()) { + ob_end_clean(); + } + if (!ob_get_level()) ob_start(); + + $this->commandKey = request()->param('command'); + + $command = self::getCommand($this->commandKey); + if (!$command) { + $this->execError('The command was not allowed to be executed', true); + } + + if ($authentication) { + try { + $token = get_auth_token(); + $auth = Auth::instance(); + $auth->init($token); + + if (!$auth->isLogin() || !$auth->isSuperAdmin()) { + $this->execError("You are not super administrator or not logged in", true); + } + } catch (TokenExpirationException) { + $this->execError(__('Token expiration')); + } + } + + $this->beforeExecution(); + $this->outputFlag('link-success'); + + if (!empty($command['notes'])) { + $this->output('> ' . __($command['notes']), false); + } + $this->output('> ' . $command['command'], false); + + $this->process = proc_open($command['command'], $this->descriptorsPec, $this->pipes, $command['cwd']); + if (!is_resource($this->process)) { + $this->execError('Failed to execute', true); + } + while ($this->getProcStatus()) { + $contents = file_get_contents($this->outputFile); + if (strlen($contents) && $this->outputContent != $contents) { + $newOutput = str_replace($this->outputContent, '', $contents); + $this->checkOutput($contents, $newOutput); + if (preg_match('/\r\n|\r|\n/', $newOutput)) { + $this->output($newOutput); + $this->outputContent = $contents; + } + } + + // 输出执行状态信息 + if ($this->procStatusMark === 2) { + $this->output('exitCode: ' . $this->procStatusData['exitcode']); + if ($this->procStatusData['exitcode'] === 0) { + if ($this->successCallback()) { + $this->outputFlag('exec-success'); + } else { + $this->output('Error: Command execution succeeded, but callback execution failed'); + $this->outputFlag('exec-error'); + } + } else { + $this->outputFlag('exec-error'); + } + } + + usleep(500000); + } + foreach ($this->pipes as $pipe) { + fclose($pipe); + } + proc_close($this->process); + $this->outputFlag('exec-completed'); + } + + /** + * 获取执行状态 + * @throws Throwable + */ + public function getProcStatus(): bool + { + $this->procStatusData = proc_get_status($this->process); + if ($this->procStatusData['running']) { + $this->procStatusMark = 1; + return true; + } elseif ($this->procStatusMark === 1) { + $this->procStatusMark = 2; + return true; + } else { + return false; + } + } + + /** + * 输出 EventSource 数据 + * @param string $data + * @param bool $callback + */ + public function output(string $data, bool $callback = true): void + { + $data = self::outputFilter($data); + $data = [ + 'data' => $data, + 'uuid' => $this->uuid, + 'extend' => $this->extend, + 'key' => $this->commandKey, + ]; + $data = json_encode($data, JSON_UNESCAPED_UNICODE); + if ($data) { + $this->finalOutput($data); + if ($callback) $this->outputCallback($data); + @ob_flush();// 刷新浏览器缓冲区 + } + } + + + /** + * 检查输出 + * @param string $outputs 全部输出内容 + * @param string $rowOutput 当前输出内容(行) + */ + public function checkOutput(string $outputs, string $rowOutput): void + { + if (str_contains($rowOutput, '(Y/n)')) { + $this->execError('Interactive output detected, please manually execute the command to confirm the situation.', true); + } + } + + /** + * 输出状态标记 + * @param string $flag + */ + public function outputFlag(string $flag): void + { + $this->output($this->flag[$flag], false); + } + + /** + * 输出后回调 + */ + public function outputCallback($data): void + { + + } + + /** + * 成功后回调 + * @return bool + * @throws Throwable + */ + public function successCallback(): bool + { + if (stripos($this->commandKey, '.')) { + $commandKeyArr = explode('.', $this->commandKey); + $commandPKey = $commandKeyArr[0] ?? ''; + } else { + $commandPKey = $this->commandKey; + } + + if ($commandPKey == 'web-build') { + if (!self::mvDist()) { + $this->output('Build succeeded, but move file failed. Please operate manually.'); + return false; + } + } elseif ($commandPKey == 'web-install' && $this->extend) { + [$type, $value] = explode(':', $this->extend); + if ($type == 'module-install' && $value) { + Manage::instance($value)->dependentInstallComplete('npm'); + } + } elseif ($commandPKey == 'composer' && $this->extend) { + [$type, $value] = explode(':', $this->extend); + if ($type == 'module-install' && $value) { + Manage::instance($value)->dependentInstallComplete('composer'); + } + } elseif ($commandPKey == 'nuxt-install' && $this->extend) { + [$type, $value] = explode(':', $this->extend); + if ($type == 'module-install' && $value) { + Manage::instance($value)->dependentInstallComplete('nuxt_npm'); + } + } + return true; + } + + /** + * 执行前埋点 + */ + public function beforeExecution(): void + { + if ($this->commandKey == 'test.pnpm') { + @unlink(root_path() . 'public' . DIRECTORY_SEPARATOR . 'npm-install-test' . DIRECTORY_SEPARATOR . 'pnpm-lock.yaml'); + } elseif ($this->commandKey == 'web-install.pnpm') { + @unlink(root_path() . 'web' . DIRECTORY_SEPARATOR . 'pnpm-lock.yaml'); + } + } + + /** + * 输出过滤 + */ + public static function outputFilter($str): string + { + $str = trim($str); + $preg = '/\[(.*?)m/i'; + $str = preg_replace($preg, '', $str); + $str = str_replace(["\r\n", "\r", "\n"], "\n", $str); + return mb_convert_encoding($str, 'UTF-8', 'UTF-8,GBK,GB2312,BIG5'); + } + + /** + * 执行错误 + */ + public function execError($error, $break = false): void + { + $this->output('Error:' . $error); + $this->outputFlag('exec-error'); + if ($break) $this->break(); + } + + /** + * 退出执行 + */ + public function break(): void + { + throw new HttpResponseException(Response::create()->contentType('text/event-stream')); + } + + /** + * 执行一个命令并以字符串的方式返回执行输出 + * 代替 exec 使用,这样就只需要解除 proc_open 的函数禁用了 + * @param $commandKey + * @return string|bool + */ + public static function getOutputFromProc($commandKey): bool|string + { + if (!function_exists('proc_open') || !function_exists('proc_close')) { + return false; + } + $command = self::getCommand($commandKey); + if (!$command) { + return false; + } + $descriptorsPec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; + $process = proc_open($command['command'], $descriptorsPec, $pipes, null, null); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + $info .= stream_get_contents($pipes[2]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + return self::outputFilter($info); + } + return ''; + } + + public static function mvDist(): bool + { + $distPath = root_path() . self::$distDir . DIRECTORY_SEPARATOR; + $indexHtmlPath = $distPath . 'index.html'; + $assetsPath = $distPath . 'assets'; + if (!file_exists($indexHtmlPath) || !file_exists($assetsPath)) { + return false; + } + + $toIndexHtmlPath = root_path() . 'public' . DIRECTORY_SEPARATOR . 'index.html'; + $toAssetsPath = root_path() . 'public' . DIRECTORY_SEPARATOR . 'assets'; + @unlink($toIndexHtmlPath); + Filesystem::delDir($toAssetsPath); + + if (rename($indexHtmlPath, $toIndexHtmlPath) && rename($assetsPath, $toAssetsPath)) { + Filesystem::delDir($distPath); + return true; + } else { + return false; + } + } + + public static function changeTerminalConfig($config = []): bool + { + // 不保存在数据库中,因为切换包管理器时,数据库资料可能还未配置 + $oldPackageManager = Config::get('terminal.npm_package_manager'); + $newPackageManager = request()->post('manager', $config['manager'] ?? $oldPackageManager); + + if ($oldPackageManager == $newPackageManager) { + return true; + } + + $buildConfigFile = config_path() . 'terminal.php'; + $buildConfigContent = @file_get_contents($buildConfigFile); + $buildConfigContent = preg_replace("/'npm_package_manager'(\s+)=>(\s+)'$oldPackageManager'/", "'npm_package_manager'\$1=>\$2'$newPackageManager'", $buildConfigContent); + $result = @file_put_contents($buildConfigFile, $buildConfigContent); + return (bool)$result; + } + + /** + * 最终输出 + */ + public function finalOutput(string $data): void + { + $app = app(); + if (!empty($app->worker) && !empty($app->connection)) { + $app->connection->send(new \Workerman\Protocols\Http\ServerSentEvents(['event' => 'message', 'data' => $data])); + } else { + echo 'data: ' . $data . "\n\n"; + } + } + + /** + * 发送响应头 + */ + public function sendHeader(): void + { + $headers = array_merge(request()->allowCrossDomainHeaders ?? [], [ + 'X-Accel-Buffering' => 'no', + 'Content-Type' => 'text/event-stream', + 'Cache-Control' => 'no-cache', + ]); + + $app = app(); + if (!empty($app->worker) && !empty($app->connection)) { + $app->connection->send(new \Workerman\Protocols\Http\Response(200, $headers, "\r\n")); + } else { + foreach ($headers as $name => $val) { + header($name . (!is_null($val) ? ':' . $val : '')); + } + } + } +} \ No newline at end of file diff --git a/extend/ba/Tree.php b/extend/ba/Tree.php new file mode 100644 index 0000000..8eac879 --- /dev/null +++ b/extend/ba/Tree.php @@ -0,0 +1,145 @@ +assembleChild()方法组装 + * @param array $arr 要改为树状的数组 + * @param string $field '树枝'字段 + * @param int $level 递归数组层次,无需手动维护 + * @param bool $superiorEnd 递归上一级树枝是否结束,无需手动维护 + * @return array + */ + public static function getTreeArray(array $arr, string $field = 'name', int $level = 0, bool $superiorEnd = false): array + { + $level++; + $number = 1; + $total = count($arr); + foreach ($arr as $key => $item) { + $prefix = ($number == $total) ? self::$icon[2] : self::$icon[1]; + if ($level == 2) { + $arr[$key][$field] = str_pad('', 4) . $prefix . $item[$field]; + } elseif ($level >= 3) { + $arr[$key][$field] = str_pad('', 4) . ($superiorEnd ? '' : self::$icon[0]) . str_pad('', ($level - 2) * 4) . $prefix . $item[$field]; + } + + if (isset($item['children']) && $item['children']) { + $arr[$key]['children'] = self::getTreeArray($item['children'], $field, $level, $number == $total); + } + $number++; + } + return $arr; + } + + /** + * 递归合并树状数组(根据children多维变二维方便渲染) + * @param array $data 要合并的数组 ['id' => 1, 'pid' => 0, 'title' => '标题1', 'children' => ['id' => 2, 'pid' => 1, 'title' => ' └标题1-1']] + * @return array [['id' => 1, 'pid' => 0, 'title' => '标题1'], ['id' => 2, 'pid' => 1, 'title' => ' └标题1-1']] + */ + public static function assembleTree(array $data): array + { + $arr = []; + foreach ($data as $v) { + $children = $v['children'] ?? []; + unset($v['children']); + $arr[] = $v; + if ($children) { + $arr = array_merge($arr, self::assembleTree($children)); + } + } + return $arr; + } + + /** + * 递归的根据指定字段组装 children 数组 + * @param array $data 数据源 例如:[['id' => 1, 'pid' => 0, title => '标题1'], ['id' => 2, 'pid' => 1, title => '标题1-1']] + * @param string $pid 存储上级id的字段 + * @param string $pk 主键字段 + * @return array ['id' => 1, 'pid' => 0, 'title' => '标题1', 'children' => ['id' => 2, 'pid' => 1, 'title' => '标题1-1']] + */ + public function assembleChild(array $data, string $pid = 'pid', string $pk = 'id'): array + { + if (!$data) return []; + + $pks = []; + $topLevelData = []; // 顶级数据 + $this->children = []; // 置空子级数据 + foreach ($data as $item) { + $pks[] = $item[$pk]; + + // 以pid组成children + $this->children[$item[$pid]][] = $item; + } + // 上级不存在的就是顶级,只获取它们的 children + foreach ($data as $item) { + if (!in_array($item[$pid], $pks)) { + $topLevelData[] = $item; + } + } + + if (count($this->children) > 0) { + foreach ($topLevelData as $key => $item) { + $topLevelData[$key]['children'] = $this->getChildren($this->children[$item[$pk]] ?? [], $pk); + } + return $topLevelData; + } else { + return $data; + } + } + + /** + * 获取 children 数组 + * 辅助 assembleChild 组装 children + * @param array $data + * @param string $pk + * @return array + */ + protected function getChildren(array $data, string $pk = 'id'): array + { + if (!$data) return []; + foreach ($data as $key => $item) { + if (array_key_exists($item[$pk], $this->children)) { + $data[$key]['children'] = $this->getChildren($this->children[$item[$pk]], $pk); + } + } + return $data; + } +} \ No newline at end of file diff --git a/extend/ba/Version.php b/extend/ba/Version.php new file mode 100644 index 0000000..8a29bc3 --- /dev/null +++ b/extend/ba/Version.php @@ -0,0 +1,133 @@ + $v2[$i]) { + return false; + } + if ($v1[$i] < $v2[$i]) { + return true; + } + } + if (count($v1) != count($v2)) { + return !(count($v1) > count($v2)); + } + return false; + } + + /** + * 是否是一个数字版本号 + * @param $version + * @return bool + */ + public static function checkDigitalVersion($version): bool + { + if (!$version) { + return false; + } + if (strtolower($version[0]) == 'v') { + $version = substr($version, 1); + } + + $rule1 = '/\.{2,10}/'; // 是否有两个的`.` + $rule2 = '/^\d+(\.\d+){0,10}$/'; + if (!preg_match($rule1, (string)$version)) { + return !!preg_match($rule2, (string)$version); + } + return false; + } + + /** + * @return string + */ + public static function getCnpmVersion(): string + { + $execOut = Terminal::getOutputFromProc('version.cnpm'); + if ($execOut) { + $preg = '/cnpm@(.+?) \(/is'; + preg_match($preg, $execOut, $result); + return $result[1] ?? ''; + } else { + return ''; + } + } + + /** + * 获取依赖版本号 + * @param string $name 支持:npm、cnpm、yarn、pnpm、node + * @return string + */ + public static function getVersion(string $name): string + { + if ($name == 'cnpm') { + return self::getCnpmVersion(); + } elseif (in_array($name, ['npm', 'yarn', 'pnpm', 'node'])) { + $execOut = Terminal::getOutputFromProc('version.' . $name); + if ($execOut) { + if (strripos($execOut, 'npm WARN') !== false) { + $preg = '/\d+(\.\d+){0,2}/'; + preg_match($preg, $execOut, $matches); + if (isset($matches[0]) && self::checkDigitalVersion($matches[0])) { + return $matches[0]; + } + } + $execOut = preg_split('/\r\n|\r|\n/', $execOut); + // 检测两行,第一行可能会是个警告消息 + for ($i = 0; $i < 2; $i++) { + if (isset($execOut[$i]) && self::checkDigitalVersion($execOut[$i])) { + return $execOut[$i]; + } + } + } else { + return ''; + } + } + return ''; + } +} \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..df30868 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..403b65f --- /dev/null +++ b/public/index.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +namespace think; + +$server = isset($_REQUEST['server']) || isset($_SERVER['HTTP_SERVER']) || substr($_SERVER['REQUEST_URI'], 1, 9) == 'index.php' || $_SERVER['REQUEST_METHOD'] == 'OPTIONS'; +if (!$server) { + /* + * 用户访问前端 + * 不在tp加载后判断,为了安全的使用 exit()(常驻内存运行时不走本文件) + */ + $rootPath = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR; + + // 安装检测-s + if (!is_file($rootPath . 'install.lock') && is_file($rootPath . 'install' . DIRECTORY_SEPARATOR . 'index.html')) { + header("location:" . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR); + exit(); + } + // 安装检测-e + + // 检测是否已编译前端(如果存在 index.html,则访问)-s + if (is_file($rootPath . 'index.html')) { + header("location:" . DIRECTORY_SEPARATOR . 'index.html'); + exit(); + } + // 检测是否已编译前端-e +} + +require __DIR__ . '/../vendor/autoload.php'; + +// 执行HTTP应用并响应 +$http = (new App())->http; + +$response = $http->run(); + +$response->send(); + +$http->end($response); diff --git a/public/install/assets/index.css b/public/install/assets/index.css new file mode 100644 index 0000000..05ae6b0 --- /dev/null +++ b/public/install/assets/index.css @@ -0,0 +1 @@ +.command[data-v-c55edab5]{font-size:var(--el-font-size-large);font-weight:700;margin-left:10px}.exec-message[data-v-c55edab5]{color:#fff;font-size:12px;line-height:16px;padding:6px;background-color:#424251;margin-top:10px;min-height:30px;max-height:200px;overflow:auto}.exec-message[data-v-c55edab5]::-webkit-scrollbar{width:5px;height:5px}.exec-message[data-v-c55edab5]::-webkit-scrollbar-thumb{background:#c8c9cc;border-radius:4px;box-shadow:none;-webkit-box-shadow:none}.exec-message[data-v-c55edab5]::-webkit-scrollbar-track{background:#f5f5f5}.exec-message[data-v-c55edab5]:hover::-webkit-scrollbar-thumb:hover{background:#909399}@supports not (selector(::-webkit-scrollbar)){.exec-message[data-v-c55edab5]{scrollbar-width:thin;scrollbar-color:#c8c9cc #eaeaea}}.toggle-message-display[data-v-c55edab5]{padding-top:10px;font-size:13px;color:var(--color-secondary);display:flex;align-items:center;justify-content:center;cursor:pointer}.task-opt[data-v-c55edab5]{display:none;float:right}.task-item.task-status-0:hover .task-opt[data-v-c55edab5],.task-item.task-status-3:hover .task-opt[data-v-c55edab5],.task-item.task-status-4:hover .task-opt[data-v-c55edab5],.task-item.task-status-5:hover .task-opt[data-v-c55edab5]{display:inline}.block-on-failure-tag[data-v-c55edab5]{margin-left:10px}.terminal-menu-item[data-v-c55edab5]{margin-bottom:10px}.ba-terminal-dialog{width:42%!important}@media screen and (max-width: 768px){.ba-terminal-dialog{width:80%!important}}@media screen and (max-width: 540px){.ba-terminal-dialog{width:94%!important}}.lang[data-v-631c568f]{position:fixed;top:10px;right:10px;width:86px}.lang:hover .lang-list[data-v-631c568f],.lang .lang-list:hover .lang-list[data-v-631c568f]{display:block}.lang img[data-v-631c568f]{display:block;margin:0 auto;width:30px;height:30px}.lang .lang-list[data-v-631c568f]{display:none;margin-top:5px;background-color:#fff;position:relative;border-radius:4px;transition:all .5s ease}.lang .lang-list .lang-list-arrow[data-v-631c568f]{top:-4px;width:10px;height:10px;position:absolute;left:38px}.lang .lang-list .lang-list-arrow[data-v-631c568f]:before{border-bottom-color:transparent!important;border-right-color:transparent!important;border-top-left-radius:2px;border:1px solid #fff;background:#fff;right:0;position:absolute;width:10px;height:10px;z-index:-1;content:" ";transform:rotate(45deg);box-sizing:border-box}.lang .lang-list .lang-item[data-v-631c568f]{cursor:pointer;padding:10px 15px;border-bottom:1px solid #ebeef5}.lang .lang-list .lang-item[data-v-631c568f]:hover{background-color:#f5f5f5}.lang .lang-list .lang-item[data-v-631c568f]:last-child{border:none}.logo-box[data-v-631c568f]{margin-top:10px}.logo-box .logo[data-v-631c568f]{display:block;margin:0 auto;width:110px;height:110px}.logo-box .title[data-v-631c568f]{display:block;text-align:center;font-size:28px;color:#606266}.container[data-v-e96f3865]{margin-top:20px}.container .table-title[data-v-e96f3865]{display:block;text-align:center;font-size:20px;color:#303133}.container .table[data-v-e96f3865]{max-width:560px;padding:20px;margin:10px auto}.container .global-warning[data-v-e96f3865]{margin-bottom:10px}.container .table-item[data-v-e96f3865]{color:#303133;display:flex;align-items:center;justify-content:space-between;background-color:#fff;padding:13px 15px;margin-bottom:2px;border-radius:5px;transition:all .2s ease}.container .table-item[data-v-e96f3865]:hover{background-color:#fcfcfc}.container .table-item .table-label[data-v-e96f3865]{font-size:15px}.container .table-item .label-need[data-v-e96f3865]{font-size:12px;color:#f56c6c;cursor:pointer;padding:0 4px}.container .table-item .label-need.faq[data-v-e96f3865],.container .table-item .label-need.install-cnpm[data-v-e96f3865]{color:#3f6ad8}.container .table-item .label-need.faq[data-v-e96f3865]:hover,.container .table-item .label-need.install-cnpm[data-v-e96f3865]:hover{text-decoration:underline}.container .table-item .label-need.text[data-v-e96f3865]{cursor:text}.container .table-item.error[data-v-e96f3865]{background-color:#f56c6c;color:#fff}.container .table-item.success[data-v-e96f3865]{background-color:#67c23a;color:#fff}.container .table-value[data-v-e96f3865]{font-size:13px;display:flex;align-items:center}.container .data-state[data-v-e96f3865]{width:20px;height:20px;-webkit-user-select:none;user-select:none;margin-left:5px}.check-done[data-v-e96f3865]{font-size:14px;margin-top:20px;text-align:right}.check-done.ok[data-v-e96f3865]{color:#67c23a}.check-done.fail[data-v-e96f3865]{color:#f56c6c}.button[data-v-e96f3865]{padding:15px;text-align:center;font-size:16px;background-color:#409eff;border-radius:5px;color:#fff;margin-top:20px;opacity:.4;cursor:pointer;transition:all .2s ease}.button.pass[data-v-e96f3865]{opacity:1}.start-install[data-v-e96f3865]{margin-left:10px}.w100[data-v-e96f3865]{width:100%}.start-from[data-v-e96f3865] .el-input__inner{line-height:29px}.block-help[data-v-e96f3865]{font-size:13px;color:#606266;padding-top:5px;line-height:15px}.phinx-fail-box[data-v-efc9ce06]{display:block;padding:15px;margin:15px auto;background-color:#fff;border-radius:4px}.phinx-fail-box .content-item[data-v-efc9ce06]{line-height:1.3;border-radius:4px;padding:10px;background-color:#f5f5f5;word-break:break-all;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;margin:15px 0}.phinx-fail-box .content-item .command[data-v-efc9ce06]{line-height:2;font-weight:700}.phinx-fail-box .content-item .block-help[data-v-efc9ce06]{display:inline-block;line-height:2;font-size:13px;color:#909399}.phinx-fail-box .content-item .text[data-v-efc9ce06]{padding:6px 0;font-size:14px}.phinx-fail-box .content-item .output-box[data-v-efc9ce06]{position:relative;border-radius:5px;box-shadow:#0005 0 2px 2px;padding:5px;font-size:13px;background-color:#282c34}.phinx-fail-box .content-item .output[data-v-efc9ce06]{color:#a9b7c6}.phinx-fail-box .content-item .mt10[data-v-efc9ce06]{margin-top:10px}.phinx-fail-footer-button[data-v-efc9ce06]{width:100%;display:flex;align-items:center;justify-content:center}.container[data-v-efc9ce06]{margin-top:10px}.container .table-title[data-v-efc9ce06]{display:block;text-align:center;font-size:20px;color:#303133}.container .table[data-v-efc9ce06]{max-width:560px;padding:20px;margin:0 auto}.container .table .table-item-br[data-v-efc9ce06]{height:20px}.container .table .table-item[data-v-efc9ce06]:focus-within{border:2px solid #4e73df}.container .table .table-item:focus-within .table-input[data-v-efc9ce06]{color:#303133}.container .table .table-column[data-v-efc9ce06]{padding:12px;border-radius:3px;border:2px solid #fff;transition:all .3s ease}.container .table .table-error[data-v-efc9ce06]{display:flex;align-items:center;justify-content:center;margin-bottom:10px;background-color:#f56c6c;color:#fff}.container .table .table-item[data-v-efc9ce06]{display:flex;align-items:center;margin-bottom:2px;background-color:#fff;color:#909399}.container .table .table-item .table-label[data-v-efc9ce06]{flex:1;font-size:15px;margin-bottom:0}.container .table .table-item .table-label .block-help[data-v-efc9ce06]{display:block;width:100%;color:#909399;font-size:13px;line-height:16px;padding:0 11px}.container .footer-buttons[data-v-efc9ce06]{margin-top:20px;width:100%;display:flex;align-items:center;justify-content:center}.container .footer-buttons .button[data-v-efc9ce06]{width:50%;height:42px}.container .connecting-prompt[data-v-efc9ce06]{position:fixed;top:60px;right:100px;font-size:14px;margin-top:20px;text-align:right;color:#606266}.container[data-v-efc9ce06] .el-input__wrapper,.container[data-v-efc9ce06] .el-input__wrapper.is-focus,.container[data-v-efc9ce06] .el-form-item.is-error .el-input__wrapper{box-shadow:none}.container[data-v-efc9ce06] .el-form-item__error{left:11px;margin-top:-6px}.container[data-v-efc9ce06] .el-input__inner{line-height:29px}.install-tips-box[data-v-efc9ce06]{padding:0 20px}.install-tips-box .install-tips-close[data-v-efc9ce06]{position:absolute;width:22px;height:22px;top:-11px;right:-11px;border:1px solid #d50600;border-radius:50%}.install-tips-box .install-tips[data-v-efc9ce06]{position:relative;padding:10px;background-color:#ffcdcd;color:#d50600;max-width:570px;margin:20px auto 0;border-radius:4px;font-size:14px}.install-tips-box .install-tips .install-tips-title[data-v-efc9ce06],.install-tips-box .install-tips .install-tips-item[data-v-efc9ce06]{text-indent:1em;background-color:#ffe5e5;padding:8px;border-radius:4px;margin-bottom:5px}.install-tips-box .install-tips .install-tips-item[data-v-efc9ce06]:last-child{margin-bottom:0}.install-tips-box .change-route[data-v-efc9ce06]{cursor:pointer;color:#3f6ad8}.container[data-v-e1e72612]{margin-top:20px;padding:20px}.container .table-title[data-v-e1e72612]{display:block;text-align:center;font-size:20px;color:#67c23a}.container .text-warning[data-v-e1e72612]{max-width:500px;margin:20px auto}.container .done-box[data-v-e1e72612]{display:block;max-width:500px;margin:20px auto;background-color:#ffcdcd;padding:20px;border-radius:6px;text-align:center;color:#d9534f;font-size:15px}.container .done-box .reload-tips[data-v-e1e72612]{font-size:13px;color:#909399}.container .done-box .reload-tips .reload[data-v-e1e72612]{cursor:pointer;color:#409eff}.container .admin-url[data-v-e1e72612]{background-color:#fcfcfc;font-size:16px;text-align:center;padding:5px;border-radius:4px;margin:10px 0;cursor:pointer;word-wrap:break-word;white-space:normal;word-break:break-all}.container .admin-url[data-v-e1e72612]:hover{text-decoration:underline}.container .done-button[data-v-e1e72612]{display:flex;justify-content:space-around;max-width:500px;margin:0 auto}.container .done-button button[data-v-e1e72612]{width:130px}.container[data-v-292784ff]{padding:20px}.container .title[data-v-292784ff]{display:block;text-align:center;font-size:20px;color:#303133}.container .reload-tips[data-v-292784ff]{padding:10px 0;text-align:center;font-size:14px;color:#909399}.container .reload-tips .reload[data-v-292784ff]{cursor:pointer;color:#409eff}.container .content[data-v-292784ff]{display:block;max-width:560px;padding:15px;margin:15px auto;background-color:#fff;border-radius:4px;font-size:15px}.container .content .content-item[data-v-292784ff]{line-height:1.3;border-radius:4px;padding:10px;background-color:#f5f5f5;word-break:break-all;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;margin:15px 0}.container .content .content-item .command[data-v-292784ff]{line-height:2;font-weight:700}.container .content .content-item .block-help[data-v-292784ff]{display:inline-block;line-height:2;font-size:13px;color:#303133}.container .content .content-item .block-help.link[data-v-292784ff]{color:#3f6ad8;cursor:pointer}.container .content .content-item .min-help[data-v-292784ff]{color:#909399;font-size:12px}.container .content .content-item .size-15[data-v-292784ff]{font-size:15px}.container .content .content-item .step-box[data-v-292784ff]{padding-bottom:10px}.container .content .content-item .step-box .step[data-v-292784ff]{font-size:14px;line-height:1.5}.container .content .content-item[data-v-292784ff]:last-child{margin-bottom:0}[data-v-292784ff] .text-bold{font-weight:700;padding:0 2px}.loading[data-v-292784ff]{font-size:13px;color:#909399;text-align:right}*{margin:0;padding:0;box-sizing:border-box;outline:none!important}html,body,#app{margin:0;padding:0;width:100%;height:100%;font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,SimSun,sans-serif;font-weight:400;-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent;background-color:#f5f5f5;font-size:14px;overflow-y:auto;position:relative}.slide-bottom-enter-active,.slide-bottom-leave-active{will-change:transform;transition:all .6s ease}.slide-bottom-enter-from{opacity:0;transform:translateY(-30px)}.slide-bottom-leave-to{opacity:0;transform:translateY(30px)}.ba-terminal{position:fixed;right:40px;bottom:200px;height:40px;width:40px;-webkit-user-select:none;user-select:none;border-radius:50%;cursor:pointer;animation:pulse 2s infinite}.terminal-logo{height:38px;width:38px}@-webkit-keyframes pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(13,130,255,.4)}70%{-webkit-box-shadow:0 0 0 10px rgba(13,130,255,0)}to{-webkit-box-shadow:0 0 0 0 rgba(13,130,255,0)}}@keyframes pulse{0%{-moz-box-shadow:0 0 0 0 rgba(13,130,255,.4);box-shadow:0 0 #0d82ff66}70%{-moz-box-shadow:0 0 0 10px rgba(13,130,255,0);box-shadow:0 0 0 10px #0d82ff00}to{-moz-box-shadow:0 0 0 0 rgba(13,130,255,0);box-shadow:0 0 #0d82ff00}}:root{--el-color-white:#ffffff;--el-color-black:#000000;--el-color-primary-rgb:64,158,255;--el-color-success-rgb:103,194,58;--el-color-warning-rgb:230,162,60;--el-color-danger-rgb:245,108,108;--el-color-error-rgb:245,108,108;--el-color-info-rgb:144,147,153;--el-font-size-extra-large:20px;--el-font-size-large:18px;--el-font-size-medium:16px;--el-font-size-base:14px;--el-font-size-small:13px;--el-font-size-extra-small:12px;--el-font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;--el-font-weight-primary:500;--el-font-line-height-primary:24px;--el-index-normal:1;--el-index-top:1000;--el-index-popper:2000;--el-border-radius-base:4px;--el-border-radius-small:2px;--el-border-radius-round:20px;--el-border-radius-circle:100%;--el-transition-duration:.3s;--el-transition-duration-fast:.2s;--el-transition-function-ease-in-out-bezier:cubic-bezier(.645,.045,.355,1);--el-transition-function-fast-bezier:cubic-bezier(.23,1,.32,1);--el-transition-all:all var(--el-transition-duration) var(--el-transition-function-ease-in-out-bezier);--el-transition-fade:opacity var(--el-transition-duration) var(--el-transition-function-fast-bezier);--el-transition-md-fade:transform var(--el-transition-duration) var(--el-transition-function-fast-bezier),opacity var(--el-transition-duration) var(--el-transition-function-fast-bezier);--el-transition-fade-linear:opacity var(--el-transition-duration-fast) linear;--el-transition-border:border-color var(--el-transition-duration-fast) var(--el-transition-function-ease-in-out-bezier);--el-transition-box-shadow:box-shadow var(--el-transition-duration-fast) var(--el-transition-function-ease-in-out-bezier);--el-transition-color:color var(--el-transition-duration-fast) var(--el-transition-function-ease-in-out-bezier);--el-component-size-large:40px;--el-component-size:32px;--el-component-size-small:24px;color-scheme:light;--el-color-primary:#409eff;--el-color-primary-light-3:#79bbff;--el-color-primary-light-5:#a0cfff;--el-color-primary-light-7:#c6e2ff;--el-color-primary-light-8:#d9ecff;--el-color-primary-light-9:#ecf5ff;--el-color-primary-dark-2:#337ecc;--el-color-success:#67c23a;--el-color-success-light-3:#95d475;--el-color-success-light-5:#b3e19d;--el-color-success-light-7:#d1edc4;--el-color-success-light-8:#e1f3d8;--el-color-success-light-9:#f0f9eb;--el-color-success-dark-2:#529b2e;--el-color-warning:#e6a23c;--el-color-warning-light-3:#eebe77;--el-color-warning-light-5:#f3d19e;--el-color-warning-light-7:#f8e3c5;--el-color-warning-light-8:#faecd8;--el-color-warning-light-9:#fdf6ec;--el-color-warning-dark-2:#b88230;--el-color-danger:#f56c6c;--el-color-danger-light-3:#f89898;--el-color-danger-light-5:#fab6b6;--el-color-danger-light-7:#fcd3d3;--el-color-danger-light-8:#fde2e2;--el-color-danger-light-9:#fef0f0;--el-color-danger-dark-2:#c45656;--el-color-error:#f56c6c;--el-color-error-light-3:#f89898;--el-color-error-light-5:#fab6b6;--el-color-error-light-7:#fcd3d3;--el-color-error-light-8:#fde2e2;--el-color-error-light-9:#fef0f0;--el-color-error-dark-2:#c45656;--el-color-info:#909399;--el-color-info-light-3:#b1b3b8;--el-color-info-light-5:#c8c9cc;--el-color-info-light-7:#dedfe0;--el-color-info-light-8:#e9e9eb;--el-color-info-light-9:#f4f4f5;--el-color-info-dark-2:#73767a;--el-bg-color:#ffffff;--el-bg-color-page:#f2f3f5;--el-bg-color-overlay:#ffffff;--el-text-color-primary:#303133;--el-text-color-regular:#606266;--el-text-color-secondary:#909399;--el-text-color-placeholder:#a8abb2;--el-text-color-disabled:#c0c4cc;--el-border-color:#dcdfe6;--el-border-color-light:#e4e7ed;--el-border-color-lighter:#ebeef5;--el-border-color-extra-light:#f2f6fc;--el-border-color-dark:#d4d7de;--el-border-color-darker:#cdd0d6;--el-fill-color:#f0f2f5;--el-fill-color-light:#f5f7fa;--el-fill-color-lighter:#fafafa;--el-fill-color-extra-light:#fafcff;--el-fill-color-dark:#ebedf0;--el-fill-color-darker:#e6e8eb;--el-fill-color-blank:#ffffff;--el-box-shadow:0px 12px 32px 4px rgba(0,0,0,.04),0px 8px 20px rgba(0,0,0,.08);--el-box-shadow-light:0px 0px 12px rgba(0,0,0,.12);--el-box-shadow-lighter:0px 0px 6px rgba(0,0,0,.12);--el-box-shadow-dark:0px 16px 48px 16px rgba(0,0,0,.08),0px 12px 32px rgba(0,0,0,.12),0px 8px 16px -8px rgba(0,0,0,.16);--el-disabled-bg-color:var(--el-fill-color-light);--el-disabled-text-color:var(--el-text-color-placeholder);--el-disabled-border-color:var(--el-border-color-light);--el-overlay-color:rgba(0,0,0,.8);--el-overlay-color-light:rgba(0,0,0,.7);--el-overlay-color-lighter:rgba(0,0,0,.5);--el-mask-color:rgba(255,255,255,.9);--el-mask-color-extra-light:rgba(255,255,255,.3);--el-border-width:1px;--el-border-style:solid;--el-border-color-hover:var(--el-text-color-disabled);--el-border:var(--el-border-width) var(--el-border-style) var(--el-border-color);--el-svg-monochrome-grey:var(--el-border-color)}.fade-in-linear-enter-active,.fade-in-linear-leave-active{transition:var(--el-transition-fade-linear)}.fade-in-linear-enter-from,.fade-in-linear-leave-to{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{transition:var(--el-transition-fade-linear)}.el-fade-in-linear-enter-from,.el-fade-in-linear-leave-to{opacity:0}.el-fade-in-enter-active,.el-fade-in-leave-active{transition:all var(--el-transition-duration) cubic-bezier(.55,0,.1,1)}.el-fade-in-enter-from,.el-fade-in-leave-active{opacity:0}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{transition:all var(--el-transition-duration) cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter-from,.el-zoom-in-center-leave-active{opacity:0;transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;transform:scaleY(1);transform-origin:center top;transition:var(--el-transition-md-fade)}.el-zoom-in-top-enter-active[data-popper-placement^=top],.el-zoom-in-top-leave-active[data-popper-placement^=top]{transform-origin:center bottom}.el-zoom-in-top-enter-from,.el-zoom-in-top-leave-active{opacity:0;transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;transform:scaleY(1);transform-origin:center bottom;transition:var(--el-transition-md-fade)}.el-zoom-in-bottom-enter-from,.el-zoom-in-bottom-leave-active{opacity:0;transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;transform:scale(1);transform-origin:top left;transition:var(--el-transition-md-fade)}.el-zoom-in-left-enter-from,.el-zoom-in-left-leave-active{opacity:0;transform:scale(.45)}.collapse-transition{transition:var(--el-transition-duration) height ease-in-out,var(--el-transition-duration) padding-top ease-in-out,var(--el-transition-duration) padding-bottom ease-in-out}.el-collapse-transition-enter-active,.el-collapse-transition-leave-active{transition:var(--el-transition-duration) max-height ease-in-out,var(--el-transition-duration) padding-top ease-in-out,var(--el-transition-duration) padding-bottom ease-in-out}.horizontal-collapse-transition{transition:var(--el-transition-duration) width ease-in-out,var(--el-transition-duration) padding-left ease-in-out,var(--el-transition-duration) padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{transition:all 1s}.el-list-enter-from,.el-list-leave-to{opacity:0;transform:translateY(-30px)}.el-list-leave-active{position:absolute!important}.el-opacity-transition{transition:opacity var(--el-transition-duration) cubic-bezier(.55,0,.1,1)}.el-icon-loading{animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@keyframes rotating{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.el-icon{--color:inherit;align-items:center;display:inline-flex;height:1em;justify-content:center;line-height:1em;position:relative;width:1em;fill:currentColor;color:var(--color);font-size:inherit}.el-icon.is-loading{animation:rotating 2s linear infinite}.el-icon svg{height:1em;width:1em}.el-affix--fixed{position:fixed}.el-alert{--el-alert-padding:8px 16px;--el-alert-border-radius-base:var(--el-border-radius-base);--el-alert-title-font-size:14px;--el-alert-title-with-description-font-size:16px;--el-alert-description-font-size:14px;--el-alert-close-font-size:16px;--el-alert-close-customed-font-size:14px;--el-alert-icon-size:16px;--el-alert-icon-large-size:28px;align-items:center;background-color:var(--el-color-white);border-radius:var(--el-alert-border-radius-base);box-sizing:border-box;display:flex;margin:0;opacity:1;overflow:hidden;padding:var(--el-alert-padding);position:relative;transition:opacity var(--el-transition-duration-fast);width:100%}.el-alert.is-light .el-alert__close-btn{color:var(--el-text-color-placeholder)}.el-alert.is-dark .el-alert__close-btn,.el-alert.is-dark .el-alert__description{color:var(--el-color-white)}.el-alert.is-center{justify-content:center}.el-alert--success{--el-alert-bg-color:var(--el-color-success-light-9)}.el-alert--success.is-light{background-color:var(--el-alert-bg-color)}.el-alert--success.is-light,.el-alert--success.is-light .el-alert__description{color:var(--el-color-success)}.el-alert--success.is-dark{background-color:var(--el-color-success);color:var(--el-color-white)}.el-alert--info{--el-alert-bg-color:var(--el-color-info-light-9)}.el-alert--info.is-light{background-color:var(--el-alert-bg-color)}.el-alert--info.is-light,.el-alert--info.is-light .el-alert__description{color:var(--el-color-info)}.el-alert--info.is-dark{background-color:var(--el-color-info);color:var(--el-color-white)}.el-alert--warning{--el-alert-bg-color:var(--el-color-warning-light-9)}.el-alert--warning.is-light{background-color:var(--el-alert-bg-color)}.el-alert--warning.is-light,.el-alert--warning.is-light .el-alert__description{color:var(--el-color-warning)}.el-alert--warning.is-dark{background-color:var(--el-color-warning);color:var(--el-color-white)}.el-alert--error{--el-alert-bg-color:var(--el-color-error-light-9)}.el-alert--error.is-light{background-color:var(--el-alert-bg-color)}.el-alert--error.is-light,.el-alert--error.is-light .el-alert__description{color:var(--el-color-error)}.el-alert--error.is-dark{background-color:var(--el-color-error);color:var(--el-color-white)}.el-alert__content{display:flex;flex-direction:column;gap:4px}.el-alert .el-alert__icon{font-size:var(--el-alert-icon-size);margin-right:8px;width:var(--el-alert-icon-size)}.el-alert .el-alert__icon.is-big{font-size:var(--el-alert-icon-large-size);margin-right:12px;width:var(--el-alert-icon-large-size)}.el-alert__title{font-size:var(--el-alert-title-font-size);line-height:24px}.el-alert__title.with-description{font-size:var(--el-alert-title-with-description-font-size)}.el-alert .el-alert__description{font-size:var(--el-alert-description-font-size);margin:0}.el-alert .el-alert__close-btn{cursor:pointer;font-size:var(--el-alert-close-font-size);opacity:1;position:absolute;right:16px;top:12px}.el-alert .el-alert__close-btn.is-customed{font-size:var(--el-alert-close-customed-font-size);font-style:normal;line-height:24px;top:8px}.el-alert-fade-enter-from,.el-alert-fade-leave-active{opacity:0}.el-aside{box-sizing:border-box;flex-shrink:0;overflow:auto;width:var(--el-aside-width,300px)}.el-autocomplete{--el-input-text-color:var(--el-text-color-regular);--el-input-border:var(--el-border);--el-input-hover-border:var(--el-border-color-hover);--el-input-focus-border:var(--el-color-primary);--el-input-transparent-border:0 0 0 1px transparent inset;--el-input-border-color:var(--el-border-color);--el-input-border-radius:var(--el-border-radius-base);--el-input-bg-color:var(--el-fill-color-blank);--el-input-icon-color:var(--el-text-color-placeholder);--el-input-placeholder-color:var(--el-text-color-placeholder);--el-input-hover-border-color:var(--el-border-color-hover);--el-input-clear-hover-color:var(--el-text-color-secondary);--el-input-focus-border-color:var(--el-color-primary);--el-input-width:100%;display:inline-block;position:relative;width:var(--el-input-width)}.el-autocomplete__popper.el-popper{background:var(--el-bg-color-overlay);box-shadow:var(--el-box-shadow-light)}.el-autocomplete__popper.el-popper,.el-autocomplete__popper.el-popper .el-popper__arrow:before{border:1px solid var(--el-border-color-light)}.el-autocomplete__popper.el-popper[data-popper-placement^=top] .el-popper__arrow:before{border-left-color:transparent;border-top-color:transparent}.el-autocomplete__popper.el-popper[data-popper-placement^=bottom] .el-popper__arrow:before{border-bottom-color:transparent;border-right-color:transparent}.el-autocomplete__popper.el-popper[data-popper-placement^=left] .el-popper__arrow:before{border-bottom-color:transparent;border-left-color:transparent}.el-autocomplete__popper.el-popper[data-popper-placement^=right] .el-popper__arrow:before{border-right-color:transparent;border-top-color:transparent}.el-autocomplete-suggestion{border-radius:var(--el-border-radius-base);box-sizing:border-box}.el-autocomplete-suggestion__wrap{box-sizing:border-box;max-height:280px;padding:10px 0}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{color:var(--el-text-color-regular);cursor:pointer;font-size:var(--el-font-size-base);line-height:34px;list-style:none;margin:0;overflow:hidden;padding:0 20px;text-align:left;text-overflow:ellipsis;white-space:nowrap}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:var(--el-fill-color-light)}.el-autocomplete-suggestion li.divider{border-top:1px solid var(--el-color-black);margin-top:6px}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{color:var(--el-text-color-secondary);font-size:20px;height:100px;line-height:100px;text-align:center}.el-autocomplete-suggestion.is-loading li:after{content:"";display:inline-block;height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:var(--el-bg-color-overlay)}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-avatar{--el-avatar-text-color:var(--el-color-white);--el-avatar-bg-color:var(--el-text-color-disabled);--el-avatar-text-size:14px;--el-avatar-icon-size:18px;--el-avatar-border-radius:var(--el-border-radius-base);--el-avatar-size-large:56px;--el-avatar-size-small:24px;--el-avatar-size:40px;align-items:center;background:var(--el-avatar-bg-color);box-sizing:border-box;color:var(--el-avatar-text-color);display:inline-flex;font-size:var(--el-avatar-text-size);height:var(--el-avatar-size);justify-content:center;overflow:hidden;text-align:center;width:var(--el-avatar-size)}.el-avatar>img{display:block;height:100%;width:100%}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:var(--el-avatar-border-radius)}.el-avatar--icon{font-size:var(--el-avatar-icon-size)}.el-avatar--small{--el-avatar-size:24px}.el-avatar--large{--el-avatar-size:56px}.el-backtop{--el-backtop-bg-color:var(--el-bg-color-overlay);--el-backtop-text-color:var(--el-color-primary);--el-backtop-hover-bg-color:var(--el-border-color-extra-light);align-items:center;background-color:var(--el-backtop-bg-color);border-radius:50%;box-shadow:var(--el-box-shadow-lighter);color:var(--el-backtop-text-color);cursor:pointer;display:flex;font-size:20px;height:40px;justify-content:center;position:fixed;width:40px;z-index:5}.el-backtop:hover{background-color:var(--el-backtop-hover-bg-color)}.el-backtop__icon{font-size:20px}.el-badge{--el-badge-bg-color:var(--el-color-danger);--el-badge-radius:10px;--el-badge-font-size:12px;--el-badge-padding:6px;--el-badge-size:18px;display:inline-block;position:relative;vertical-align:middle;width:-moz-fit-content;width:fit-content}.el-badge__content{align-items:center;background-color:var(--el-badge-bg-color);border:1px solid var(--el-bg-color);border-radius:var(--el-badge-radius);color:var(--el-color-white);display:inline-flex;font-size:var(--el-badge-font-size);height:var(--el-badge-size);justify-content:center;padding:0 var(--el-badge-padding);white-space:nowrap}.el-badge__content.is-fixed{position:absolute;right:calc(1px + var(--el-badge-size)/2);top:0;transform:translateY(-50%) translate(100%);z-index:var(--el-index-normal)}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{border-radius:50%;height:8px;padding:0;right:0;width:8px}.el-badge__content--primary{background-color:var(--el-color-primary)}.el-badge__content--success{background-color:var(--el-color-success)}.el-badge__content--warning{background-color:var(--el-color-warning)}.el-badge__content--info{background-color:var(--el-color-info)}.el-badge__content--danger{background-color:var(--el-color-danger)}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb:after,.el-breadcrumb:before{content:"";display:table}.el-breadcrumb:after{clear:both}.el-breadcrumb__separator{color:var(--el-text-color-placeholder);font-weight:700;margin:0 9px}.el-breadcrumb__separator.el-icon{font-weight:400;margin:0 6px}.el-breadcrumb__separator.el-icon svg{vertical-align:middle}.el-breadcrumb__item{align-items:center;display:inline-flex;float:left}.el-breadcrumb__inner{color:var(--el-text-color-regular)}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{color:var(--el-text-color-primary);font-weight:700;text-decoration:none;transition:var(--el-transition-color)}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:var(--el-color-primary);cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{color:var(--el-text-color-regular);cursor:text;font-weight:400}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group:after,.el-button-group:before{content:"";display:table}.el-button-group:after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.el-button-group>.el-button:last-child{border-bottom-left-radius:0;border-top-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-bottom-left-radius:var(--el-border-radius-base);border-bottom-right-radius:var(--el-border-radius-base);border-top-left-radius:var(--el-border-radius-base);border-top-right-radius:var(--el-border-radius-base)}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:var(--el-border-radius-round)}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-button.is-active,.el-button-group>.el-button:active,.el-button-group>.el-button:focus,.el-button-group>.el-button:hover{z-index:1}.el-button-group>.el-dropdown>.el-button{border-bottom-left-radius:0;border-left-color:var(--el-button-divide-border-color);border-top-left-radius:0}.el-button-group .el-button--primary:first-child{border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--primary:last-child{border-left-color:var(--el-button-divide-border-color)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:var(--el-button-divide-border-color);border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--success:first-child{border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--success:last-child{border-left-color:var(--el-button-divide-border-color)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:var(--el-button-divide-border-color);border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--warning:first-child{border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--warning:last-child{border-left-color:var(--el-button-divide-border-color)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:var(--el-button-divide-border-color);border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--danger:first-child{border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--danger:last-child{border-left-color:var(--el-button-divide-border-color)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:var(--el-button-divide-border-color);border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--info:first-child{border-right-color:var(--el-button-divide-border-color)}.el-button-group .el-button--info:last-child{border-left-color:var(--el-button-divide-border-color)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:var(--el-button-divide-border-color);border-right-color:var(--el-button-divide-border-color)}.el-button{--el-button-font-weight:var(--el-font-weight-primary);--el-button-border-color:var(--el-border-color);--el-button-bg-color:var(--el-fill-color-blank);--el-button-text-color:var(--el-text-color-regular);--el-button-disabled-text-color:var(--el-disabled-text-color);--el-button-disabled-bg-color:var(--el-fill-color-blank);--el-button-disabled-border-color:var(--el-border-color-light);--el-button-divide-border-color:rgba(255,255,255,.5);--el-button-hover-text-color:var(--el-color-primary);--el-button-hover-bg-color:var(--el-color-primary-light-9);--el-button-hover-border-color:var(--el-color-primary-light-7);--el-button-active-text-color:var(--el-button-hover-text-color);--el-button-active-border-color:var(--el-color-primary);--el-button-active-bg-color:var(--el-button-hover-bg-color);--el-button-outline-color:var(--el-color-primary-light-5);--el-button-hover-link-text-color:var(--el-color-info);--el-button-active-color:var(--el-text-color-primary);align-items:center;-webkit-appearance:none;background-color:var(--el-button-bg-color);border:var(--el-border);border-color:var(--el-button-border-color);box-sizing:border-box;color:var(--el-button-text-color);cursor:pointer;display:inline-flex;font-weight:var(--el-button-font-weight);height:32px;justify-content:center;line-height:1;outline:none;text-align:center;transition:.1s;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;white-space:nowrap}.el-button:hover{background-color:var(--el-button-hover-bg-color);border-color:var(--el-button-hover-border-color);color:var(--el-button-hover-text-color);outline:none}.el-button:active{background-color:var(--el-button-active-bg-color);border-color:var(--el-button-active-border-color);color:var(--el-button-active-text-color);outline:none}.el-button:focus-visible{outline:2px solid var(--el-button-outline-color);outline-offset:1px;transition:outline-offset 0s,outline 0s}.el-button>span{align-items:center;display:inline-flex}.el-button+.el-button{margin-left:12px}.el-button{border-radius:var(--el-border-radius-base);font-size:var(--el-font-size-base)}.el-button,.el-button.is-round{padding:8px 15px}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon]+span{margin-left:6px}.el-button [class*=el-icon] svg{vertical-align:bottom}.el-button.is-plain{--el-button-hover-text-color:var(--el-color-primary);--el-button-hover-bg-color:var(--el-fill-color-blank);--el-button-hover-border-color:var(--el-color-primary)}.el-button.is-active{background-color:var(--el-button-active-bg-color);border-color:var(--el-button-active-border-color);color:var(--el-button-active-text-color);outline:none}.el-button.is-disabled,.el-button.is-disabled:hover{background-color:var(--el-button-disabled-bg-color);background-image:none;border-color:var(--el-button-disabled-border-color);color:var(--el-button-disabled-text-color);cursor:not-allowed}.el-button.is-loading{pointer-events:none;position:relative}.el-button.is-loading:before{background-color:var(--el-mask-color-extra-light);border-radius:inherit;bottom:-1px;content:"";left:-1px;pointer-events:none;position:absolute;right:-1px;top:-1px;z-index:1}.el-button.is-round{border-radius:var(--el-border-radius-round)}.el-button.is-circle{border-radius:50%;padding:8px;width:32px}.el-button.is-text{background-color:transparent;border:0 solid transparent;color:var(--el-button-text-color)}.el-button.is-text.is-disabled{background-color:transparent!important;color:var(--el-button-disabled-text-color)}.el-button.is-text:not(.is-disabled):hover{background-color:var(--el-fill-color-light)}.el-button.is-text:not(.is-disabled):focus-visible{outline:2px solid var(--el-button-outline-color);outline-offset:1px;transition:outline-offset 0s,outline 0s}.el-button.is-text:not(.is-disabled):active{background-color:var(--el-fill-color)}.el-button.is-text:not(.is-disabled).is-has-bg{background-color:var(--el-fill-color-light)}.el-button.is-text:not(.is-disabled).is-has-bg:hover{background-color:var(--el-fill-color)}.el-button.is-text:not(.is-disabled).is-has-bg:active{background-color:var(--el-fill-color-dark)}.el-button__text--expand{letter-spacing:.3em;margin-right:-.3em}.el-button.is-link{background:transparent;border-color:transparent;color:var(--el-button-text-color);height:auto;padding:2px}.el-button.is-link:hover{color:var(--el-button-hover-link-text-color)}.el-button.is-link.is-disabled{background-color:transparent!important;border-color:transparent!important;color:var(--el-button-disabled-text-color)}.el-button.is-link:not(.is-disabled):active,.el-button.is-link:not(.is-disabled):hover{background-color:transparent;border-color:transparent}.el-button.is-link:not(.is-disabled):active{color:var(--el-button-active-color)}.el-button--text{background:transparent;border-color:transparent;color:var(--el-color-primary);padding-left:0;padding-right:0}.el-button--text.is-disabled{background-color:transparent!important;border-color:transparent!important;color:var(--el-button-disabled-text-color)}.el-button--text:not(.is-disabled):hover{background-color:transparent;border-color:transparent;color:var(--el-color-primary-light-3)}.el-button--text:not(.is-disabled):active{background-color:transparent;border-color:transparent;color:var(--el-color-primary-dark-2)}.el-button__link--expand{letter-spacing:.3em;margin-right:-.3em}.el-button--primary{--el-button-text-color:var(--el-color-white);--el-button-bg-color:var(--el-color-primary);--el-button-border-color:var(--el-color-primary);--el-button-outline-color:var(--el-color-primary-light-5);--el-button-active-color:var(--el-color-primary-dark-2);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-link-text-color:var(--el-color-primary-light-5);--el-button-hover-bg-color:var(--el-color-primary-light-3);--el-button-hover-border-color:var(--el-color-primary-light-3);--el-button-active-bg-color:var(--el-color-primary-dark-2);--el-button-active-border-color:var(--el-color-primary-dark-2);--el-button-disabled-text-color:var(--el-color-white);--el-button-disabled-bg-color:var(--el-color-primary-light-5);--el-button-disabled-border-color:var(--el-color-primary-light-5)}.el-button--primary.is-link,.el-button--primary.is-plain,.el-button--primary.is-text{--el-button-text-color:var(--el-color-primary);--el-button-bg-color:var(--el-color-primary-light-9);--el-button-border-color:var(--el-color-primary-light-5);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-bg-color:var(--el-color-primary);--el-button-hover-border-color:var(--el-color-primary);--el-button-active-text-color:var(--el-color-white)}.el-button--primary.is-link.is-disabled,.el-button--primary.is-link.is-disabled:active,.el-button--primary.is-link.is-disabled:focus,.el-button--primary.is-link.is-disabled:hover,.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover,.el-button--primary.is-text.is-disabled,.el-button--primary.is-text.is-disabled:active,.el-button--primary.is-text.is-disabled:focus,.el-button--primary.is-text.is-disabled:hover{background-color:var(--el-color-primary-light-9);border-color:var(--el-color-primary-light-8);color:var(--el-color-primary-light-5)}.el-button--success{--el-button-text-color:var(--el-color-white);--el-button-bg-color:var(--el-color-success);--el-button-border-color:var(--el-color-success);--el-button-outline-color:var(--el-color-success-light-5);--el-button-active-color:var(--el-color-success-dark-2);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-link-text-color:var(--el-color-success-light-5);--el-button-hover-bg-color:var(--el-color-success-light-3);--el-button-hover-border-color:var(--el-color-success-light-3);--el-button-active-bg-color:var(--el-color-success-dark-2);--el-button-active-border-color:var(--el-color-success-dark-2);--el-button-disabled-text-color:var(--el-color-white);--el-button-disabled-bg-color:var(--el-color-success-light-5);--el-button-disabled-border-color:var(--el-color-success-light-5)}.el-button--success.is-link,.el-button--success.is-plain,.el-button--success.is-text{--el-button-text-color:var(--el-color-success);--el-button-bg-color:var(--el-color-success-light-9);--el-button-border-color:var(--el-color-success-light-5);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-bg-color:var(--el-color-success);--el-button-hover-border-color:var(--el-color-success);--el-button-active-text-color:var(--el-color-white)}.el-button--success.is-link.is-disabled,.el-button--success.is-link.is-disabled:active,.el-button--success.is-link.is-disabled:focus,.el-button--success.is-link.is-disabled:hover,.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover,.el-button--success.is-text.is-disabled,.el-button--success.is-text.is-disabled:active,.el-button--success.is-text.is-disabled:focus,.el-button--success.is-text.is-disabled:hover{background-color:var(--el-color-success-light-9);border-color:var(--el-color-success-light-8);color:var(--el-color-success-light-5)}.el-button--warning{--el-button-text-color:var(--el-color-white);--el-button-bg-color:var(--el-color-warning);--el-button-border-color:var(--el-color-warning);--el-button-outline-color:var(--el-color-warning-light-5);--el-button-active-color:var(--el-color-warning-dark-2);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-link-text-color:var(--el-color-warning-light-5);--el-button-hover-bg-color:var(--el-color-warning-light-3);--el-button-hover-border-color:var(--el-color-warning-light-3);--el-button-active-bg-color:var(--el-color-warning-dark-2);--el-button-active-border-color:var(--el-color-warning-dark-2);--el-button-disabled-text-color:var(--el-color-white);--el-button-disabled-bg-color:var(--el-color-warning-light-5);--el-button-disabled-border-color:var(--el-color-warning-light-5)}.el-button--warning.is-link,.el-button--warning.is-plain,.el-button--warning.is-text{--el-button-text-color:var(--el-color-warning);--el-button-bg-color:var(--el-color-warning-light-9);--el-button-border-color:var(--el-color-warning-light-5);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-bg-color:var(--el-color-warning);--el-button-hover-border-color:var(--el-color-warning);--el-button-active-text-color:var(--el-color-white)}.el-button--warning.is-link.is-disabled,.el-button--warning.is-link.is-disabled:active,.el-button--warning.is-link.is-disabled:focus,.el-button--warning.is-link.is-disabled:hover,.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover,.el-button--warning.is-text.is-disabled,.el-button--warning.is-text.is-disabled:active,.el-button--warning.is-text.is-disabled:focus,.el-button--warning.is-text.is-disabled:hover{background-color:var(--el-color-warning-light-9);border-color:var(--el-color-warning-light-8);color:var(--el-color-warning-light-5)}.el-button--danger{--el-button-text-color:var(--el-color-white);--el-button-bg-color:var(--el-color-danger);--el-button-border-color:var(--el-color-danger);--el-button-outline-color:var(--el-color-danger-light-5);--el-button-active-color:var(--el-color-danger-dark-2);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-link-text-color:var(--el-color-danger-light-5);--el-button-hover-bg-color:var(--el-color-danger-light-3);--el-button-hover-border-color:var(--el-color-danger-light-3);--el-button-active-bg-color:var(--el-color-danger-dark-2);--el-button-active-border-color:var(--el-color-danger-dark-2);--el-button-disabled-text-color:var(--el-color-white);--el-button-disabled-bg-color:var(--el-color-danger-light-5);--el-button-disabled-border-color:var(--el-color-danger-light-5)}.el-button--danger.is-link,.el-button--danger.is-plain,.el-button--danger.is-text{--el-button-text-color:var(--el-color-danger);--el-button-bg-color:var(--el-color-danger-light-9);--el-button-border-color:var(--el-color-danger-light-5);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-bg-color:var(--el-color-danger);--el-button-hover-border-color:var(--el-color-danger);--el-button-active-text-color:var(--el-color-white)}.el-button--danger.is-link.is-disabled,.el-button--danger.is-link.is-disabled:active,.el-button--danger.is-link.is-disabled:focus,.el-button--danger.is-link.is-disabled:hover,.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover,.el-button--danger.is-text.is-disabled,.el-button--danger.is-text.is-disabled:active,.el-button--danger.is-text.is-disabled:focus,.el-button--danger.is-text.is-disabled:hover{background-color:var(--el-color-danger-light-9);border-color:var(--el-color-danger-light-8);color:var(--el-color-danger-light-5)}.el-button--info{--el-button-text-color:var(--el-color-white);--el-button-bg-color:var(--el-color-info);--el-button-border-color:var(--el-color-info);--el-button-outline-color:var(--el-color-info-light-5);--el-button-active-color:var(--el-color-info-dark-2);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-link-text-color:var(--el-color-info-light-5);--el-button-hover-bg-color:var(--el-color-info-light-3);--el-button-hover-border-color:var(--el-color-info-light-3);--el-button-active-bg-color:var(--el-color-info-dark-2);--el-button-active-border-color:var(--el-color-info-dark-2);--el-button-disabled-text-color:var(--el-color-white);--el-button-disabled-bg-color:var(--el-color-info-light-5);--el-button-disabled-border-color:var(--el-color-info-light-5)}.el-button--info.is-link,.el-button--info.is-plain,.el-button--info.is-text{--el-button-text-color:var(--el-color-info);--el-button-bg-color:var(--el-color-info-light-9);--el-button-border-color:var(--el-color-info-light-5);--el-button-hover-text-color:var(--el-color-white);--el-button-hover-bg-color:var(--el-color-info);--el-button-hover-border-color:var(--el-color-info);--el-button-active-text-color:var(--el-color-white)}.el-button--info.is-link.is-disabled,.el-button--info.is-link.is-disabled:active,.el-button--info.is-link.is-disabled:focus,.el-button--info.is-link.is-disabled:hover,.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover,.el-button--info.is-text.is-disabled,.el-button--info.is-text.is-disabled:active,.el-button--info.is-text.is-disabled:focus,.el-button--info.is-text.is-disabled:hover{background-color:var(--el-color-info-light-9);border-color:var(--el-color-info-light-8);color:var(--el-color-info-light-5)}.el-button--large{--el-button-size:40px;height:var(--el-button-size)}.el-button--large [class*=el-icon]+span{margin-left:8px}.el-button--large{border-radius:var(--el-border-radius-base);font-size:var(--el-font-size-base);padding:12px 19px}.el-button--large.is-round{padding:12px 19px}.el-button--large.is-circle{padding:12px;width:var(--el-button-size)}.el-button--small{--el-button-size:24px;height:var(--el-button-size)}.el-button--small [class*=el-icon]+span{margin-left:4px}.el-button--small{border-radius:calc(var(--el-border-radius-base) - 1px);font-size:12px;padding:5px 11px}.el-button--small.is-round{padding:5px 11px}.el-button--small.is-circle{padding:5px;width:var(--el-button-size)}.el-calendar{--el-calendar-border:var(--el-table-border,1px solid var(--el-border-color-lighter));--el-calendar-header-border-bottom:var(--el-calendar-border);--el-calendar-selected-bg-color:var(--el-color-primary-light-9);--el-calendar-cell-width:85px;background-color:var(--el-fill-color-blank)}.el-calendar__header{border-bottom:var(--el-calendar-header-border-bottom);display:flex;justify-content:space-between;padding:12px 20px}.el-calendar__title{align-self:center;color:var(--el-text-color)}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{color:var(--el-text-color-regular);font-weight:400;padding:12px 0}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:var(--el-text-color-placeholder)}.el-calendar-table td{border-bottom:var(--el-calendar-border);border-right:var(--el-calendar-border);transition:background-color var(--el-transition-duration-fast) ease;vertical-align:top}.el-calendar-table td.is-selected{background-color:var(--el-calendar-selected-bg-color)}.el-calendar-table td.is-today{color:var(--el-color-primary)}.el-calendar-table tr:first-child td{border-top:var(--el-calendar-border)}.el-calendar-table tr td:first-child{border-left:var(--el-calendar-border)}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{box-sizing:border-box;height:var(--el-calendar-cell-width);padding:8px}.el-calendar-table .el-calendar-day:hover{background-color:var(--el-calendar-selected-bg-color);cursor:pointer}.el-card{--el-card-border-color:var(--el-border-color-light);--el-card-border-radius:4px;--el-card-padding:20px;--el-card-bg-color:var(--el-fill-color-blank);background-color:var(--el-card-bg-color);border:1px solid var(--el-card-border-color);border-radius:var(--el-card-border-radius);color:var(--el-text-color-primary);overflow:hidden;transition:var(--el-transition-duration)}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{box-shadow:var(--el-box-shadow-light)}.el-card__header{border-bottom:1px solid var(--el-card-border-color);box-sizing:border-box;padding:calc(var(--el-card-padding) - 2px) var(--el-card-padding)}.el-card__body{padding:var(--el-card-padding)}.el-card__footer{border-top:1px solid var(--el-card-border-color);box-sizing:border-box;padding:calc(var(--el-card-padding) - 2px) var(--el-card-padding)}.el-carousel__item{display:inline-block;height:100%;left:0;overflow:hidden;position:absolute;top:0;width:100%}.el-carousel__item,.el-carousel__item.is-active{z-index:calc(var(--el-index-normal) - 1)}.el-carousel__item--card,.el-carousel__item.is-animating{transition:transform .4s ease-in-out}.el-carousel__item--card{width:50%}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:var(--el-index-normal)}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:calc(var(--el-index-normal) + 1)}.el-carousel__item--card-vertical{height:50%;width:100%}.el-carousel__mask{background-color:var(--el-color-white);height:100%;left:0;opacity:.24;position:absolute;top:0;transition:var(--el-transition-duration-fast);width:100%}.el-carousel{--el-carousel-arrow-font-size:12px;--el-carousel-arrow-size:36px;--el-carousel-arrow-background:rgba(31,45,61,.11);--el-carousel-arrow-hover-background:rgba(31,45,61,.23);--el-carousel-indicator-width:30px;--el-carousel-indicator-height:2px;--el-carousel-indicator-padding-horizontal:4px;--el-carousel-indicator-padding-vertical:12px;--el-carousel-indicator-out-color:var(--el-border-color-hover);position:relative}.el-carousel--horizontal,.el-carousel--vertical{overflow:hidden}.el-carousel__container{height:300px;position:relative}.el-carousel__arrow{align-items:center;background-color:var(--el-carousel-arrow-background);border:none;border-radius:50%;color:#fff;cursor:pointer;display:inline-flex;font-size:var(--el-carousel-arrow-font-size);height:var(--el-carousel-arrow-size);justify-content:center;margin:0;outline:none;padding:0;position:absolute;text-align:center;top:50%;transform:translateY(-50%);transition:var(--el-transition-duration);width:var(--el-carousel-arrow-size);z-index:10}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:var(--el-carousel-arrow-hover-background)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{list-style:none;margin:0;padding:0;position:absolute;z-index:calc(var(--el-index-normal) + 1)}.el-carousel__indicators--horizontal{bottom:0;left:50%;transform:translate(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:calc(var(--el-carousel-indicator-height) + var(--el-carousel-indicator-padding-vertical)*2);position:static;text-align:center;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:var(--el-carousel-indicator-out-color);opacity:.24}.el-carousel__indicators--right{right:0}.el-carousel__indicators--labels{left:0;right:0;text-align:center;transform:none}.el-carousel__indicators--labels .el-carousel__button{color:#000;font-size:12px;height:auto;padding:2px 18px;width:auto}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:var(--el-carousel-indicator-padding-vertical) var(--el-carousel-indicator-padding-horizontal)}.el-carousel__indicator--vertical{padding:var(--el-carousel-indicator-padding-horizontal) var(--el-carousel-indicator-padding-vertical)}.el-carousel__indicator--vertical .el-carousel__button{height:calc(var(--el-carousel-indicator-width)/2);width:var(--el-carousel-indicator-height)}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{background-color:#fff;border:none;cursor:pointer;display:block;height:var(--el-carousel-indicator-height);margin:0;opacity:.48;outline:none;padding:0;transition:var(--el-transition-duration);width:var(--el-carousel-indicator-width)}.carousel-arrow-left-enter-from,.carousel-arrow-left-leave-active{opacity:0;transform:translateY(-50%) translate(-10px)}.carousel-arrow-right-enter-from,.carousel-arrow-right-leave-active{opacity:0;transform:translateY(-50%) translate(10px)}.el-transitioning{filter:url(#elCarouselHorizontal)}.el-transitioning-vertical{filter:url(#elCarouselVertical)}.el-cascader-panel{--el-cascader-menu-text-color:var(--el-text-color-regular);--el-cascader-menu-selected-text-color:var(--el-color-primary);--el-cascader-menu-fill:var(--el-bg-color-overlay);--el-cascader-menu-font-size:var(--el-font-size-base);--el-cascader-menu-radius:var(--el-border-radius-base);--el-cascader-menu-border:solid 1px var(--el-border-color-light);--el-cascader-menu-shadow:var(--el-box-shadow-light);--el-cascader-node-background-hover:var(--el-fill-color-light);--el-cascader-node-color-disabled:var(--el-text-color-placeholder);--el-cascader-color-empty:var(--el-text-color-placeholder);--el-cascader-tag-background:var(--el-fill-color);border-radius:var(--el-cascader-menu-radius);display:flex;font-size:var(--el-cascader-menu-font-size)}.el-cascader-panel.is-bordered{border:var(--el-cascader-menu-border);border-radius:var(--el-cascader-menu-radius)}.el-cascader-menu{border-right:var(--el-cascader-menu-border);box-sizing:border-box;color:var(--el-cascader-menu-text-color);min-width:180px}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu:last-child .el-cascader-node{padding-right:20px}.el-cascader-menu__wrap.el-scrollbar__wrap{height:204px}.el-cascader-menu__list{box-sizing:border-box;list-style:none;margin:0;min-height:100%;padding:6px 0;position:relative}.el-cascader-menu__hover-zone{height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%}.el-cascader-menu__empty-text{align-items:center;color:var(--el-cascader-color-empty);display:flex;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.el-cascader-menu__empty-text .is-loading{margin-right:2px}.el-cascader-node{align-items:center;display:flex;height:34px;line-height:34px;outline:none;padding:0 30px 0 20px;position:relative}.el-cascader-node.is-selectable.in-active-path{color:var(--el-cascader-menu-text-color)}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:var(--el-cascader-menu-selected-text-color);font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:var(--el-cascader-node-background-hover)}.el-cascader-node.is-disabled{color:var(--el-cascader-node-color-disabled);cursor:not-allowed}.el-cascader-node__prefix{left:10px;position:absolute}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{flex:1;overflow:hidden;padding:0 8px;text-align:left;text-overflow:ellipsis;white-space:nowrap}.el-cascader-node>.el-checkbox,.el-cascader-node>.el-radio{margin-right:0}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-cascader{--el-cascader-menu-text-color:var(--el-text-color-regular);--el-cascader-menu-selected-text-color:var(--el-color-primary);--el-cascader-menu-fill:var(--el-bg-color-overlay);--el-cascader-menu-font-size:var(--el-font-size-base);--el-cascader-menu-radius:var(--el-border-radius-base);--el-cascader-menu-border:solid 1px var(--el-border-color-light);--el-cascader-menu-shadow:var(--el-box-shadow-light);--el-cascader-node-background-hover:var(--el-fill-color-light);--el-cascader-node-color-disabled:var(--el-text-color-placeholder);--el-cascader-color-empty:var(--el-text-color-placeholder);--el-cascader-tag-background:var(--el-fill-color);display:inline-block;font-size:var(--el-font-size-base);line-height:32px;outline:none;position:relative;vertical-align:middle}.el-cascader:not(.is-disabled):hover .el-input__wrapper{box-shadow:0 0 0 1px var(--el-input-hover-border-color) inset;cursor:pointer}.el-cascader .el-input{cursor:pointer;display:flex}.el-cascader .el-input .el-input__inner{cursor:pointer;text-overflow:ellipsis}.el-cascader .el-input .el-input__suffix-inner .el-icon{height:calc(100% - 2px)}.el-cascader .el-input .el-input__suffix-inner .el-icon svg{vertical-align:middle}.el-cascader .el-input .icon-arrow-down{font-size:14px;transition:transform var(--el-transition-duration)}.el-cascader .el-input .icon-arrow-down.is-reverse{transform:rotate(180deg)}.el-cascader .el-input .icon-circle-close:hover{color:var(--el-input-clear-hover-color,var(--el-text-color-secondary))}.el-cascader .el-input.is-focus .el-input__wrapper{box-shadow:0 0 0 1px var(--el-input-focus-border-color,var(--el-color-primary)) inset}.el-cascader--large{font-size:14px;line-height:40px}.el-cascader--small{font-size:12px;line-height:24px}.el-cascader.is-disabled .el-cascader__label{color:var(--el-disabled-text-color);z-index:calc(var(--el-index-normal) + 1)}.el-cascader__dropdown{--el-cascader-menu-text-color:var(--el-text-color-regular);--el-cascader-menu-selected-text-color:var(--el-color-primary);--el-cascader-menu-fill:var(--el-bg-color-overlay);--el-cascader-menu-font-size:var(--el-font-size-base);--el-cascader-menu-radius:var(--el-border-radius-base);--el-cascader-menu-border:solid 1px var(--el-border-color-light);--el-cascader-menu-shadow:var(--el-box-shadow-light);--el-cascader-node-background-hover:var(--el-fill-color-light);--el-cascader-node-color-disabled:var(--el-text-color-placeholder);--el-cascader-color-empty:var(--el-text-color-placeholder);--el-cascader-tag-background:var(--el-fill-color);border-radius:var(--el-cascader-menu-radius);font-size:var(--el-cascader-menu-font-size)}.el-cascader__dropdown.el-popper{background:var(--el-cascader-menu-fill)}.el-cascader__dropdown.el-popper,.el-cascader__dropdown.el-popper .el-popper__arrow:before{border:var(--el-cascader-menu-border)}.el-cascader__dropdown.el-popper[data-popper-placement^=top] .el-popper__arrow:before{border-left-color:transparent;border-top-color:transparent}.el-cascader__dropdown.el-popper[data-popper-placement^=bottom] .el-popper__arrow:before{border-bottom-color:transparent;border-right-color:transparent}.el-cascader__dropdown.el-popper[data-popper-placement^=left] .el-popper__arrow:before{border-bottom-color:transparent;border-left-color:transparent}.el-cascader__dropdown.el-popper[data-popper-placement^=right] .el-popper__arrow:before{border-right-color:transparent;border-top-color:transparent}.el-cascader__dropdown.el-popper{box-shadow:var(--el-cascader-menu-shadow)}.el-cascader__tags{box-sizing:border-box;display:flex;flex-wrap:wrap;left:0;line-height:normal;position:absolute;right:30px;text-align:left;top:50%;transform:translateY(-50%)}.el-cascader__tags .el-tag{align-items:center;background:var(--el-cascader-tag-background);display:inline-flex;margin:2px 0 2px 6px;max-width:100%;text-overflow:ellipsis}.el-cascader__tags .el-tag.el-tag--dark,.el-cascader__tags .el-tag.el-tag--plain{background-color:var(--el-tag-bg-color)}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag:not(.is-hit).el-tag--dark,.el-cascader__tags .el-tag:not(.is-hit).el-tag--plain{border-color:var(--el-tag-border-color)}.el-cascader__tags .el-tag>span{flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{background-color:var(--el-text-color-placeholder);color:var(--el-color-white);flex:none}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:var(--el-text-color-secondary)}.el-cascader__tags.is-validate{right:55px}.el-cascader__collapse-tags{white-space:normal;z-index:var(--el-index-normal)}.el-cascader__collapse-tags .el-tag{align-items:center;background:var(--el-fill-color);display:inline-flex;margin:2px 0 2px 6px;max-width:100%;text-overflow:ellipsis}.el-cascader__collapse-tags .el-tag.el-tag--dark,.el-cascader__collapse-tags .el-tag.el-tag--plain{background-color:var(--el-tag-bg-color)}.el-cascader__collapse-tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__collapse-tags .el-tag:not(.is-hit).el-tag--dark,.el-cascader__collapse-tags .el-tag:not(.is-hit).el-tag--plain{border-color:var(--el-tag-border-color)}.el-cascader__collapse-tags .el-tag>span{flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__collapse-tags .el-tag .el-icon-close{background-color:var(--el-text-color-placeholder);color:var(--el-color-white);flex:none}.el-cascader__collapse-tags .el-tag .el-icon-close:hover{background-color:var(--el-text-color-secondary)}.el-cascader__suggestion-panel{border-radius:var(--el-cascader-menu-radius)}.el-cascader__suggestion-list{color:var(--el-cascader-menu-text-color);font-size:var(--el-font-size-base);margin:0;max-height:204px;padding:6px 0;text-align:center}.el-cascader__suggestion-item{align-items:center;cursor:pointer;display:flex;height:34px;justify-content:space-between;outline:none;padding:0 15px;text-align:left}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:var(--el-cascader-node-background-hover)}.el-cascader__suggestion-item.is-checked{color:var(--el-cascader-menu-selected-text-color);font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{color:var(--el-cascader-color-empty);margin:10px 0}.el-cascader__search-input{background:transparent;border:none;box-sizing:border-box;color:var(--el-cascader-menu-text-color);flex:1;height:24px;margin:2px 0 2px 11px;min-width:60px;outline:none;padding:0}.el-cascader__search-input::-moz-placeholder{color:transparent}.el-cascader__search-input::placeholder{color:transparent}.el-check-tag{background-color:var(--el-color-info-light-9);border-radius:var(--el-border-radius-base);color:var(--el-color-info);cursor:pointer;display:inline-block;font-size:var(--el-font-size-base);font-weight:700;line-height:var(--el-font-size-base);padding:7px 15px;transition:var(--el-transition-all)}.el-check-tag:hover{background-color:var(--el-color-info-light-7)}.el-check-tag.is-checked.el-check-tag--primary{background-color:var(--el-color-primary-light-8);color:var(--el-color-primary)}.el-check-tag.is-checked.el-check-tag--primary:hover{background-color:var(--el-color-primary-light-7)}.el-check-tag.is-checked.el-check-tag--success{background-color:var(--el-color-success-light-8);color:var(--el-color-success)}.el-check-tag.is-checked.el-check-tag--success:hover{background-color:var(--el-color-success-light-7)}.el-check-tag.is-checked.el-check-tag--warning{background-color:var(--el-color-warning-light-8);color:var(--el-color-warning)}.el-check-tag.is-checked.el-check-tag--warning:hover{background-color:var(--el-color-warning-light-7)}.el-check-tag.is-checked.el-check-tag--danger{background-color:var(--el-color-danger-light-8);color:var(--el-color-danger)}.el-check-tag.is-checked.el-check-tag--danger:hover{background-color:var(--el-color-danger-light-7)}.el-check-tag.is-checked.el-check-tag--error{background-color:var(--el-color-error-light-8);color:var(--el-color-error)}.el-check-tag.is-checked.el-check-tag--error:hover{background-color:var(--el-color-error-light-7)}.el-check-tag.is-checked.el-check-tag--info{background-color:var(--el-color-info-light-8);color:var(--el-color-info)}.el-check-tag.is-checked.el-check-tag--info:hover{background-color:var(--el-color-info-light-7)}.el-checkbox-button{--el-checkbox-button-checked-bg-color:var(--el-color-primary);--el-checkbox-button-checked-text-color:var(--el-color-white);--el-checkbox-button-checked-border-color:var(--el-color-primary);display:inline-block;position:relative}.el-checkbox-button__inner{-webkit-appearance:none;background:var(--el-button-bg-color,var(--el-fill-color-blank));border:var(--el-border);border-left-color:transparent;border-radius:0;box-sizing:border-box;color:var(--el-button-text-color,var(--el-text-color-regular));cursor:pointer;display:inline-block;font-size:var(--el-font-size-base);font-weight:var(--el-checkbox-font-weight);line-height:1;margin:0;outline:none;padding:8px 15px;position:relative;text-align:center;transition:var(--el-transition-all);-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;white-space:nowrap}.el-checkbox-button__inner.is-round{padding:8px 15px}.el-checkbox-button__inner:hover{color:var(--el-color-primary)}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{margin:0;opacity:0;outline:none;position:absolute;z-index:-1}.el-checkbox-button.is-checked .el-checkbox-button__inner{background-color:var(--el-checkbox-button-checked-bg-color);border-color:var(--el-checkbox-button-checked-border-color);box-shadow:-1px 0 0 0 var(--el-color-primary-light-7);color:var(--el-checkbox-button-checked-text-color)}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:var(--el-checkbox-button-checked-border-color)}.el-checkbox-button.is-disabled .el-checkbox-button__inner{background-color:var(--el-button-disabled-bg-color,var(--el-fill-color-blank));background-image:none;border-color:var(--el-button-disabled-border-color,var(--el-border-color-light));box-shadow:none;color:var(--el-disabled-text-color);cursor:not-allowed}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:var(--el-button-disabled-border-color,var(--el-border-color-light))}.el-checkbox-button:first-child .el-checkbox-button__inner{border-bottom-left-radius:var(--el-border-radius-base);border-left:var(--el-border);border-top-left-radius:var(--el-border-radius-base);box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:var(--el-checkbox-button-checked-border-color)}.el-checkbox-button:last-child .el-checkbox-button__inner{border-bottom-right-radius:var(--el-border-radius-base);border-top-right-radius:var(--el-border-radius-base)}.el-checkbox-button--large .el-checkbox-button__inner{border-radius:0;font-size:var(--el-font-size-base);padding:12px 19px}.el-checkbox-button--large .el-checkbox-button__inner.is-round{padding:12px 19px}.el-checkbox-button--small .el-checkbox-button__inner{border-radius:0;font-size:12px;padding:5px 11px}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:5px 11px}.el-checkbox-group{font-size:0;line-height:0}.el-checkbox{--el-checkbox-font-size:14px;--el-checkbox-font-weight:var(--el-font-weight-primary);--el-checkbox-text-color:var(--el-text-color-regular);--el-checkbox-input-height:14px;--el-checkbox-input-width:14px;--el-checkbox-border-radius:var(--el-border-radius-small);--el-checkbox-bg-color:var(--el-fill-color-blank);--el-checkbox-input-border:var(--el-border);--el-checkbox-disabled-border-color:var(--el-border-color);--el-checkbox-disabled-input-fill:var(--el-fill-color-light);--el-checkbox-disabled-icon-color:var(--el-text-color-placeholder);--el-checkbox-disabled-checked-input-fill:var(--el-border-color-extra-light);--el-checkbox-disabled-checked-input-border-color:var(--el-border-color);--el-checkbox-disabled-checked-icon-color:var(--el-text-color-placeholder);--el-checkbox-checked-text-color:var(--el-color-primary);--el-checkbox-checked-input-border-color:var(--el-color-primary);--el-checkbox-checked-bg-color:var(--el-color-primary);--el-checkbox-checked-icon-color:var(--el-color-white);--el-checkbox-input-border-color-hover:var(--el-color-primary);align-items:center;color:var(--el-checkbox-text-color);cursor:pointer;display:inline-flex;font-size:var(--el-font-size-base);font-weight:var(--el-checkbox-font-weight);height:var(--el-checkbox-height,32px);margin-right:30px;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.el-checkbox.is-disabled{cursor:not-allowed}.el-checkbox.is-bordered{border:var(--el-border);border-radius:var(--el-border-radius-base);box-sizing:border-box;padding:0 15px 0 9px}.el-checkbox.is-bordered.is-checked{border-color:var(--el-color-primary)}.el-checkbox.is-bordered.is-disabled{border-color:var(--el-border-color-lighter)}.el-checkbox.is-bordered.el-checkbox--large{border-radius:var(--el-border-radius-base);padding:0 19px 0 11px}.el-checkbox.is-bordered.el-checkbox--large .el-checkbox__label{font-size:var(--el-font-size-base)}.el-checkbox.is-bordered.el-checkbox--large .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{border-radius:calc(var(--el-border-radius-base) - 1px);padding:0 11px 0 7px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox input:focus-visible+.el-checkbox__inner{border-radius:var(--el-checkbox-border-radius);outline:2px solid var(--el-checkbox-input-border-color-hover);outline-offset:1px}.el-checkbox__input{cursor:pointer;display:inline-flex;outline:none;position:relative;white-space:nowrap}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:var(--el-checkbox-disabled-input-fill);border-color:var(--el-checkbox-disabled-border-color);cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner:after{border-color:var(--el-checkbox-disabled-icon-color);cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:var(--el-checkbox-disabled-checked-input-fill);border-color:var(--el-checkbox-disabled-checked-input-border-color)}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner:after{border-color:var(--el-checkbox-disabled-checked-icon-color)}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:var(--el-checkbox-disabled-checked-input-fill);border-color:var(--el-checkbox-disabled-checked-input-border-color)}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner:before{background-color:var(--el-checkbox-disabled-checked-icon-color);border-color:var(--el-checkbox-disabled-checked-icon-color)}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:var(--el-disabled-text-color);cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner{background-color:var(--el-checkbox-checked-bg-color);border-color:var(--el-checkbox-checked-input-border-color)}.el-checkbox__input.is-checked .el-checkbox__inner:after{border-color:var(--el-checkbox-checked-icon-color);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:var(--el-checkbox-checked-text-color)}.el-checkbox__input.is-focus:not(.is-checked) .el-checkbox__original:not(:focus-visible){border-color:var(--el-checkbox-input-border-color-hover)}.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:var(--el-checkbox-checked-bg-color);border-color:var(--el-checkbox-checked-input-border-color)}.el-checkbox__input.is-indeterminate .el-checkbox__inner:before{background-color:var(--el-checkbox-checked-icon-color);content:"";display:block;height:2px;left:0;position:absolute;right:0;top:5px;transform:scale(.5)}.el-checkbox__input.is-indeterminate .el-checkbox__inner:after{display:none}.el-checkbox__inner{background-color:var(--el-checkbox-bg-color);border:var(--el-checkbox-input-border);border-radius:var(--el-checkbox-border-radius);box-sizing:border-box;display:inline-block;height:var(--el-checkbox-input-height);position:relative;transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46),outline .25s cubic-bezier(.71,-.46,.29,1.46);width:var(--el-checkbox-input-width);z-index:var(--el-index-normal)}.el-checkbox__inner:hover{border-color:var(--el-checkbox-input-border-color-hover)}.el-checkbox__inner:after{border:1px solid transparent;border-left:0;border-top:0;box-sizing:content-box;content:"";height:7px;left:4px;position:absolute;top:1px;transform:rotate(45deg) scaleY(0);transform-origin:center;transition:transform .15s ease-in .05s;width:3px}.el-checkbox__original{height:0;margin:0;opacity:0;outline:none;position:absolute;width:0;z-index:-1}.el-checkbox__label{display:inline-block;font-size:var(--el-checkbox-font-size);line-height:1;padding-left:8px}.el-checkbox.el-checkbox--large{height:40px}.el-checkbox.el-checkbox--large .el-checkbox__label{font-size:14px}.el-checkbox.el-checkbox--large .el-checkbox__inner{height:14px;width:14px}.el-checkbox.el-checkbox--small{height:24px}.el-checkbox.el-checkbox--small .el-checkbox__label{font-size:12px}.el-checkbox.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.el-checkbox--small .el-checkbox__input.is-indeterminate .el-checkbox__inner:before{top:4px}.el-checkbox.el-checkbox--small .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox:last-of-type{margin-right:0}[class*=el-col-]{box-sizing:border-box}[class*=el-col-].is-guttered{display:block;min-height:1px}.el-col-0{flex:0 0 0%;max-width:0}.el-col-0,.el-col-0.is-guttered{display:none}.el-col-offset-0{margin-left:0}.el-col-pull-0{position:relative;right:0}.el-col-push-0{left:0;position:relative}.el-col-1{flex:0 0 4.1666666667%;max-width:4.1666666667%}.el-col-1,.el-col-1.is-guttered{display:block}.el-col-offset-1{margin-left:4.1666666667%}.el-col-pull-1{position:relative;right:4.1666666667%}.el-col-push-1{left:4.1666666667%;position:relative}.el-col-2{flex:0 0 8.3333333333%;max-width:8.3333333333%}.el-col-2,.el-col-2.is-guttered{display:block}.el-col-offset-2{margin-left:8.3333333333%}.el-col-pull-2{position:relative;right:8.3333333333%}.el-col-push-2{left:8.3333333333%;position:relative}.el-col-3{flex:0 0 12.5%;max-width:12.5%}.el-col-3,.el-col-3.is-guttered{display:block}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{position:relative;right:12.5%}.el-col-push-3{left:12.5%;position:relative}.el-col-4{flex:0 0 16.6666666667%;max-width:16.6666666667%}.el-col-4,.el-col-4.is-guttered{display:block}.el-col-offset-4{margin-left:16.6666666667%}.el-col-pull-4{position:relative;right:16.6666666667%}.el-col-push-4{left:16.6666666667%;position:relative}.el-col-5{flex:0 0 20.8333333333%;max-width:20.8333333333%}.el-col-5,.el-col-5.is-guttered{display:block}.el-col-offset-5{margin-left:20.8333333333%}.el-col-pull-5{position:relative;right:20.8333333333%}.el-col-push-5{left:20.8333333333%;position:relative}.el-col-6{flex:0 0 25%;max-width:25%}.el-col-6,.el-col-6.is-guttered{display:block}.el-col-offset-6{margin-left:25%}.el-col-pull-6{position:relative;right:25%}.el-col-push-6{left:25%;position:relative}.el-col-7{flex:0 0 29.1666666667%;max-width:29.1666666667%}.el-col-7,.el-col-7.is-guttered{display:block}.el-col-offset-7{margin-left:29.1666666667%}.el-col-pull-7{position:relative;right:29.1666666667%}.el-col-push-7{left:29.1666666667%;position:relative}.el-col-8{flex:0 0 33.3333333333%;max-width:33.3333333333%}.el-col-8,.el-col-8.is-guttered{display:block}.el-col-offset-8{margin-left:33.3333333333%}.el-col-pull-8{position:relative;right:33.3333333333%}.el-col-push-8{left:33.3333333333%;position:relative}.el-col-9{flex:0 0 37.5%;max-width:37.5%}.el-col-9,.el-col-9.is-guttered{display:block}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{position:relative;right:37.5%}.el-col-push-9{left:37.5%;position:relative}.el-col-10{flex:0 0 41.6666666667%;max-width:41.6666666667%}.el-col-10,.el-col-10.is-guttered{display:block}.el-col-offset-10{margin-left:41.6666666667%}.el-col-pull-10{position:relative;right:41.6666666667%}.el-col-push-10{left:41.6666666667%;position:relative}.el-col-11{flex:0 0 45.8333333333%;max-width:45.8333333333%}.el-col-11,.el-col-11.is-guttered{display:block}.el-col-offset-11{margin-left:45.8333333333%}.el-col-pull-11{position:relative;right:45.8333333333%}.el-col-push-11{left:45.8333333333%;position:relative}.el-col-12{flex:0 0 50%;max-width:50%}.el-col-12,.el-col-12.is-guttered{display:block}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%;position:relative}.el-col-13{flex:0 0 54.1666666667%;max-width:54.1666666667%}.el-col-13,.el-col-13.is-guttered{display:block}.el-col-offset-13{margin-left:54.1666666667%}.el-col-pull-13{position:relative;right:54.1666666667%}.el-col-push-13{left:54.1666666667%;position:relative}.el-col-14{flex:0 0 58.3333333333%;max-width:58.3333333333%}.el-col-14,.el-col-14.is-guttered{display:block}.el-col-offset-14{margin-left:58.3333333333%}.el-col-pull-14{position:relative;right:58.3333333333%}.el-col-push-14{left:58.3333333333%;position:relative}.el-col-15{flex:0 0 62.5%;max-width:62.5%}.el-col-15,.el-col-15.is-guttered{display:block}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{position:relative;right:62.5%}.el-col-push-15{left:62.5%;position:relative}.el-col-16{flex:0 0 66.6666666667%;max-width:66.6666666667%}.el-col-16,.el-col-16.is-guttered{display:block}.el-col-offset-16{margin-left:66.6666666667%}.el-col-pull-16{position:relative;right:66.6666666667%}.el-col-push-16{left:66.6666666667%;position:relative}.el-col-17{flex:0 0 70.8333333333%;max-width:70.8333333333%}.el-col-17,.el-col-17.is-guttered{display:block}.el-col-offset-17{margin-left:70.8333333333%}.el-col-pull-17{position:relative;right:70.8333333333%}.el-col-push-17{left:70.8333333333%;position:relative}.el-col-18{flex:0 0 75%;max-width:75%}.el-col-18,.el-col-18.is-guttered{display:block}.el-col-offset-18{margin-left:75%}.el-col-pull-18{position:relative;right:75%}.el-col-push-18{left:75%;position:relative}.el-col-19{flex:0 0 79.1666666667%;max-width:79.1666666667%}.el-col-19,.el-col-19.is-guttered{display:block}.el-col-offset-19{margin-left:79.1666666667%}.el-col-pull-19{position:relative;right:79.1666666667%}.el-col-push-19{left:79.1666666667%;position:relative}.el-col-20{flex:0 0 83.3333333333%;max-width:83.3333333333%}.el-col-20,.el-col-20.is-guttered{display:block}.el-col-offset-20{margin-left:83.3333333333%}.el-col-pull-20{position:relative;right:83.3333333333%}.el-col-push-20{left:83.3333333333%;position:relative}.el-col-21{flex:0 0 87.5%;max-width:87.5%}.el-col-21,.el-col-21.is-guttered{display:block}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{position:relative;right:87.5%}.el-col-push-21{left:87.5%;position:relative}.el-col-22{flex:0 0 91.6666666667%;max-width:91.6666666667%}.el-col-22,.el-col-22.is-guttered{display:block}.el-col-offset-22{margin-left:91.6666666667%}.el-col-pull-22{position:relative;right:91.6666666667%}.el-col-push-22{left:91.6666666667%;position:relative}.el-col-23{flex:0 0 95.8333333333%;max-width:95.8333333333%}.el-col-23,.el-col-23.is-guttered{display:block}.el-col-offset-23{margin-left:95.8333333333%}.el-col-pull-23{position:relative;right:95.8333333333%}.el-col-push-23{left:95.8333333333%;position:relative}.el-col-24{flex:0 0 100%;max-width:100%}.el-col-24,.el-col-24.is-guttered{display:block}.el-col-offset-24{margin-left:100%}.el-col-pull-24{position:relative;right:100%}.el-col-push-24{left:100%;position:relative}@media only screen and (max-width:767px){.el-col-xs-0{display:none;flex:0 0 0%;max-width:0}.el-col-xs-0.is-guttered{display:none}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{left:0;position:relative}.el-col-xs-1{flex:0 0 4.1666666667%;max-width:4.1666666667%}.el-col-xs-1,.el-col-xs-1.is-guttered{display:block}.el-col-xs-offset-1{margin-left:4.1666666667%}.el-col-xs-pull-1{position:relative;right:4.1666666667%}.el-col-xs-push-1{left:4.1666666667%;position:relative}.el-col-xs-2{flex:0 0 8.3333333333%;max-width:8.3333333333%}.el-col-xs-2,.el-col-xs-2.is-guttered{display:block}.el-col-xs-offset-2{margin-left:8.3333333333%}.el-col-xs-pull-2{position:relative;right:8.3333333333%}.el-col-xs-push-2{left:8.3333333333%;position:relative}.el-col-xs-3{flex:0 0 12.5%;max-width:12.5%}.el-col-xs-3,.el-col-xs-3.is-guttered{display:block}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{left:12.5%;position:relative}.el-col-xs-4{flex:0 0 16.6666666667%;max-width:16.6666666667%}.el-col-xs-4,.el-col-xs-4.is-guttered{display:block}.el-col-xs-offset-4{margin-left:16.6666666667%}.el-col-xs-pull-4{position:relative;right:16.6666666667%}.el-col-xs-push-4{left:16.6666666667%;position:relative}.el-col-xs-5{flex:0 0 20.8333333333%;max-width:20.8333333333%}.el-col-xs-5,.el-col-xs-5.is-guttered{display:block}.el-col-xs-offset-5{margin-left:20.8333333333%}.el-col-xs-pull-5{position:relative;right:20.8333333333%}.el-col-xs-push-5{left:20.8333333333%;position:relative}.el-col-xs-6{flex:0 0 25%;max-width:25%}.el-col-xs-6,.el-col-xs-6.is-guttered{display:block}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{left:25%;position:relative}.el-col-xs-7{flex:0 0 29.1666666667%;max-width:29.1666666667%}.el-col-xs-7,.el-col-xs-7.is-guttered{display:block}.el-col-xs-offset-7{margin-left:29.1666666667%}.el-col-xs-pull-7{position:relative;right:29.1666666667%}.el-col-xs-push-7{left:29.1666666667%;position:relative}.el-col-xs-8{flex:0 0 33.3333333333%;max-width:33.3333333333%}.el-col-xs-8,.el-col-xs-8.is-guttered{display:block}.el-col-xs-offset-8{margin-left:33.3333333333%}.el-col-xs-pull-8{position:relative;right:33.3333333333%}.el-col-xs-push-8{left:33.3333333333%;position:relative}.el-col-xs-9{flex:0 0 37.5%;max-width:37.5%}.el-col-xs-9,.el-col-xs-9.is-guttered{display:block}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{left:37.5%;position:relative}.el-col-xs-10{display:block;flex:0 0 41.6666666667%;max-width:41.6666666667%}.el-col-xs-10.is-guttered{display:block}.el-col-xs-offset-10{margin-left:41.6666666667%}.el-col-xs-pull-10{position:relative;right:41.6666666667%}.el-col-xs-push-10{left:41.6666666667%;position:relative}.el-col-xs-11{display:block;flex:0 0 45.8333333333%;max-width:45.8333333333%}.el-col-xs-11.is-guttered{display:block}.el-col-xs-offset-11{margin-left:45.8333333333%}.el-col-xs-pull-11{position:relative;right:45.8333333333%}.el-col-xs-push-11{left:45.8333333333%;position:relative}.el-col-xs-12{display:block;flex:0 0 50%;max-width:50%}.el-col-xs-12.is-guttered{display:block}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{left:50%;position:relative}.el-col-xs-13{display:block;flex:0 0 54.1666666667%;max-width:54.1666666667%}.el-col-xs-13.is-guttered{display:block}.el-col-xs-offset-13{margin-left:54.1666666667%}.el-col-xs-pull-13{position:relative;right:54.1666666667%}.el-col-xs-push-13{left:54.1666666667%;position:relative}.el-col-xs-14{display:block;flex:0 0 58.3333333333%;max-width:58.3333333333%}.el-col-xs-14.is-guttered{display:block}.el-col-xs-offset-14{margin-left:58.3333333333%}.el-col-xs-pull-14{position:relative;right:58.3333333333%}.el-col-xs-push-14{left:58.3333333333%;position:relative}.el-col-xs-15{display:block;flex:0 0 62.5%;max-width:62.5%}.el-col-xs-15.is-guttered{display:block}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{left:62.5%;position:relative}.el-col-xs-16{display:block;flex:0 0 66.6666666667%;max-width:66.6666666667%}.el-col-xs-16.is-guttered{display:block}.el-col-xs-offset-16{margin-left:66.6666666667%}.el-col-xs-pull-16{position:relative;right:66.6666666667%}.el-col-xs-push-16{left:66.6666666667%;position:relative}.el-col-xs-17{display:block;flex:0 0 70.8333333333%;max-width:70.8333333333%}.el-col-xs-17.is-guttered{display:block}.el-col-xs-offset-17{margin-left:70.8333333333%}.el-col-xs-pull-17{position:relative;right:70.8333333333%}.el-col-xs-push-17{left:70.8333333333%;position:relative}.el-col-xs-18{display:block;flex:0 0 75%;max-width:75%}.el-col-xs-18.is-guttered{display:block}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{left:75%;position:relative}.el-col-xs-19{display:block;flex:0 0 79.1666666667%;max-width:79.1666666667%}.el-col-xs-19.is-guttered{display:block}.el-col-xs-offset-19{margin-left:79.1666666667%}.el-col-xs-pull-19{position:relative;right:79.1666666667%}.el-col-xs-push-19{left:79.1666666667%;position:relative}.el-col-xs-20{display:block;flex:0 0 83.3333333333%;max-width:83.3333333333%}.el-col-xs-20.is-guttered{display:block}.el-col-xs-offset-20{margin-left:83.3333333333%}.el-col-xs-pull-20{position:relative;right:83.3333333333%}.el-col-xs-push-20{left:83.3333333333%;position:relative}.el-col-xs-21{display:block;flex:0 0 87.5%;max-width:87.5%}.el-col-xs-21.is-guttered{display:block}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{left:87.5%;position:relative}.el-col-xs-22{display:block;flex:0 0 91.6666666667%;max-width:91.6666666667%}.el-col-xs-22.is-guttered{display:block}.el-col-xs-offset-22{margin-left:91.6666666667%}.el-col-xs-pull-22{position:relative;right:91.6666666667%}.el-col-xs-push-22{left:91.6666666667%;position:relative}.el-col-xs-23{display:block;flex:0 0 95.8333333333%;max-width:95.8333333333%}.el-col-xs-23.is-guttered{display:block}.el-col-xs-offset-23{margin-left:95.8333333333%}.el-col-xs-pull-23{position:relative;right:95.8333333333%}.el-col-xs-push-23{left:95.8333333333%;position:relative}.el-col-xs-24{display:block;flex:0 0 100%;max-width:100%}.el-col-xs-24.is-guttered{display:block}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{left:100%;position:relative}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;flex:0 0 0%;max-width:0}.el-col-sm-0.is-guttered{display:none}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{left:0;position:relative}.el-col-sm-1{flex:0 0 4.1666666667%;max-width:4.1666666667%}.el-col-sm-1,.el-col-sm-1.is-guttered{display:block}.el-col-sm-offset-1{margin-left:4.1666666667%}.el-col-sm-pull-1{position:relative;right:4.1666666667%}.el-col-sm-push-1{left:4.1666666667%;position:relative}.el-col-sm-2{flex:0 0 8.3333333333%;max-width:8.3333333333%}.el-col-sm-2,.el-col-sm-2.is-guttered{display:block}.el-col-sm-offset-2{margin-left:8.3333333333%}.el-col-sm-pull-2{position:relative;right:8.3333333333%}.el-col-sm-push-2{left:8.3333333333%;position:relative}.el-col-sm-3{flex:0 0 12.5%;max-width:12.5%}.el-col-sm-3,.el-col-sm-3.is-guttered{display:block}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{left:12.5%;position:relative}.el-col-sm-4{flex:0 0 16.6666666667%;max-width:16.6666666667%}.el-col-sm-4,.el-col-sm-4.is-guttered{display:block}.el-col-sm-offset-4{margin-left:16.6666666667%}.el-col-sm-pull-4{position:relative;right:16.6666666667%}.el-col-sm-push-4{left:16.6666666667%;position:relative}.el-col-sm-5{flex:0 0 20.8333333333%;max-width:20.8333333333%}.el-col-sm-5,.el-col-sm-5.is-guttered{display:block}.el-col-sm-offset-5{margin-left:20.8333333333%}.el-col-sm-pull-5{position:relative;right:20.8333333333%}.el-col-sm-push-5{left:20.8333333333%;position:relative}.el-col-sm-6{flex:0 0 25%;max-width:25%}.el-col-sm-6,.el-col-sm-6.is-guttered{display:block}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{left:25%;position:relative}.el-col-sm-7{flex:0 0 29.1666666667%;max-width:29.1666666667%}.el-col-sm-7,.el-col-sm-7.is-guttered{display:block}.el-col-sm-offset-7{margin-left:29.1666666667%}.el-col-sm-pull-7{position:relative;right:29.1666666667%}.el-col-sm-push-7{left:29.1666666667%;position:relative}.el-col-sm-8{flex:0 0 33.3333333333%;max-width:33.3333333333%}.el-col-sm-8,.el-col-sm-8.is-guttered{display:block}.el-col-sm-offset-8{margin-left:33.3333333333%}.el-col-sm-pull-8{position:relative;right:33.3333333333%}.el-col-sm-push-8{left:33.3333333333%;position:relative}.el-col-sm-9{flex:0 0 37.5%;max-width:37.5%}.el-col-sm-9,.el-col-sm-9.is-guttered{display:block}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{left:37.5%;position:relative}.el-col-sm-10{display:block;flex:0 0 41.6666666667%;max-width:41.6666666667%}.el-col-sm-10.is-guttered{display:block}.el-col-sm-offset-10{margin-left:41.6666666667%}.el-col-sm-pull-10{position:relative;right:41.6666666667%}.el-col-sm-push-10{left:41.6666666667%;position:relative}.el-col-sm-11{display:block;flex:0 0 45.8333333333%;max-width:45.8333333333%}.el-col-sm-11.is-guttered{display:block}.el-col-sm-offset-11{margin-left:45.8333333333%}.el-col-sm-pull-11{position:relative;right:45.8333333333%}.el-col-sm-push-11{left:45.8333333333%;position:relative}.el-col-sm-12{display:block;flex:0 0 50%;max-width:50%}.el-col-sm-12.is-guttered{display:block}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{left:50%;position:relative}.el-col-sm-13{display:block;flex:0 0 54.1666666667%;max-width:54.1666666667%}.el-col-sm-13.is-guttered{display:block}.el-col-sm-offset-13{margin-left:54.1666666667%}.el-col-sm-pull-13{position:relative;right:54.1666666667%}.el-col-sm-push-13{left:54.1666666667%;position:relative}.el-col-sm-14{display:block;flex:0 0 58.3333333333%;max-width:58.3333333333%}.el-col-sm-14.is-guttered{display:block}.el-col-sm-offset-14{margin-left:58.3333333333%}.el-col-sm-pull-14{position:relative;right:58.3333333333%}.el-col-sm-push-14{left:58.3333333333%;position:relative}.el-col-sm-15{display:block;flex:0 0 62.5%;max-width:62.5%}.el-col-sm-15.is-guttered{display:block}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{left:62.5%;position:relative}.el-col-sm-16{display:block;flex:0 0 66.6666666667%;max-width:66.6666666667%}.el-col-sm-16.is-guttered{display:block}.el-col-sm-offset-16{margin-left:66.6666666667%}.el-col-sm-pull-16{position:relative;right:66.6666666667%}.el-col-sm-push-16{left:66.6666666667%;position:relative}.el-col-sm-17{display:block;flex:0 0 70.8333333333%;max-width:70.8333333333%}.el-col-sm-17.is-guttered{display:block}.el-col-sm-offset-17{margin-left:70.8333333333%}.el-col-sm-pull-17{position:relative;right:70.8333333333%}.el-col-sm-push-17{left:70.8333333333%;position:relative}.el-col-sm-18{display:block;flex:0 0 75%;max-width:75%}.el-col-sm-18.is-guttered{display:block}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{left:75%;position:relative}.el-col-sm-19{display:block;flex:0 0 79.1666666667%;max-width:79.1666666667%}.el-col-sm-19.is-guttered{display:block}.el-col-sm-offset-19{margin-left:79.1666666667%}.el-col-sm-pull-19{position:relative;right:79.1666666667%}.el-col-sm-push-19{left:79.1666666667%;position:relative}.el-col-sm-20{display:block;flex:0 0 83.3333333333%;max-width:83.3333333333%}.el-col-sm-20.is-guttered{display:block}.el-col-sm-offset-20{margin-left:83.3333333333%}.el-col-sm-pull-20{position:relative;right:83.3333333333%}.el-col-sm-push-20{left:83.3333333333%;position:relative}.el-col-sm-21{display:block;flex:0 0 87.5%;max-width:87.5%}.el-col-sm-21.is-guttered{display:block}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{left:87.5%;position:relative}.el-col-sm-22{display:block;flex:0 0 91.6666666667%;max-width:91.6666666667%}.el-col-sm-22.is-guttered{display:block}.el-col-sm-offset-22{margin-left:91.6666666667%}.el-col-sm-pull-22{position:relative;right:91.6666666667%}.el-col-sm-push-22{left:91.6666666667%;position:relative}.el-col-sm-23{display:block;flex:0 0 95.8333333333%;max-width:95.8333333333%}.el-col-sm-23.is-guttered{display:block}.el-col-sm-offset-23{margin-left:95.8333333333%}.el-col-sm-pull-23{position:relative;right:95.8333333333%}.el-col-sm-push-23{left:95.8333333333%;position:relative}.el-col-sm-24{display:block;flex:0 0 100%;max-width:100%}.el-col-sm-24.is-guttered{display:block}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{left:100%;position:relative}}@media only screen and (min-width:992px){.el-col-md-0{display:none;flex:0 0 0%;max-width:0}.el-col-md-0.is-guttered{display:none}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{left:0;position:relative}.el-col-md-1{flex:0 0 4.1666666667%;max-width:4.1666666667%}.el-col-md-1,.el-col-md-1.is-guttered{display:block}.el-col-md-offset-1{margin-left:4.1666666667%}.el-col-md-pull-1{position:relative;right:4.1666666667%}.el-col-md-push-1{left:4.1666666667%;position:relative}.el-col-md-2{flex:0 0 8.3333333333%;max-width:8.3333333333%}.el-col-md-2,.el-col-md-2.is-guttered{display:block}.el-col-md-offset-2{margin-left:8.3333333333%}.el-col-md-pull-2{position:relative;right:8.3333333333%}.el-col-md-push-2{left:8.3333333333%;position:relative}.el-col-md-3{flex:0 0 12.5%;max-width:12.5%}.el-col-md-3,.el-col-md-3.is-guttered{display:block}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{left:12.5%;position:relative}.el-col-md-4{flex:0 0 16.6666666667%;max-width:16.6666666667%}.el-col-md-4,.el-col-md-4.is-guttered{display:block}.el-col-md-offset-4{margin-left:16.6666666667%}.el-col-md-pull-4{position:relative;right:16.6666666667%}.el-col-md-push-4{left:16.6666666667%;position:relative}.el-col-md-5{flex:0 0 20.8333333333%;max-width:20.8333333333%}.el-col-md-5,.el-col-md-5.is-guttered{display:block}.el-col-md-offset-5{margin-left:20.8333333333%}.el-col-md-pull-5{position:relative;right:20.8333333333%}.el-col-md-push-5{left:20.8333333333%;position:relative}.el-col-md-6{flex:0 0 25%;max-width:25%}.el-col-md-6,.el-col-md-6.is-guttered{display:block}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{left:25%;position:relative}.el-col-md-7{flex:0 0 29.1666666667%;max-width:29.1666666667%}.el-col-md-7,.el-col-md-7.is-guttered{display:block}.el-col-md-offset-7{margin-left:29.1666666667%}.el-col-md-pull-7{position:relative;right:29.1666666667%}.el-col-md-push-7{left:29.1666666667%;position:relative}.el-col-md-8{flex:0 0 33.3333333333%;max-width:33.3333333333%}.el-col-md-8,.el-col-md-8.is-guttered{display:block}.el-col-md-offset-8{margin-left:33.3333333333%}.el-col-md-pull-8{position:relative;right:33.3333333333%}.el-col-md-push-8{left:33.3333333333%;position:relative}.el-col-md-9{flex:0 0 37.5%;max-width:37.5%}.el-col-md-9,.el-col-md-9.is-guttered{display:block}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{left:37.5%;position:relative}.el-col-md-10{display:block;flex:0 0 41.6666666667%;max-width:41.6666666667%}.el-col-md-10.is-guttered{display:block}.el-col-md-offset-10{margin-left:41.6666666667%}.el-col-md-pull-10{position:relative;right:41.6666666667%}.el-col-md-push-10{left:41.6666666667%;position:relative}.el-col-md-11{display:block;flex:0 0 45.8333333333%;max-width:45.8333333333%}.el-col-md-11.is-guttered{display:block}.el-col-md-offset-11{margin-left:45.8333333333%}.el-col-md-pull-11{position:relative;right:45.8333333333%}.el-col-md-push-11{left:45.8333333333%;position:relative}.el-col-md-12{display:block;flex:0 0 50%;max-width:50%}.el-col-md-12.is-guttered{display:block}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{left:50%;position:relative}.el-col-md-13{display:block;flex:0 0 54.1666666667%;max-width:54.1666666667%}.el-col-md-13.is-guttered{display:block}.el-col-md-offset-13{margin-left:54.1666666667%}.el-col-md-pull-13{position:relative;right:54.1666666667%}.el-col-md-push-13{left:54.1666666667%;position:relative}.el-col-md-14{display:block;flex:0 0 58.3333333333%;max-width:58.3333333333%}.el-col-md-14.is-guttered{display:block}.el-col-md-offset-14{margin-left:58.3333333333%}.el-col-md-pull-14{position:relative;right:58.3333333333%}.el-col-md-push-14{left:58.3333333333%;position:relative}.el-col-md-15{display:block;flex:0 0 62.5%;max-width:62.5%}.el-col-md-15.is-guttered{display:block}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{left:62.5%;position:relative}.el-col-md-16{display:block;flex:0 0 66.6666666667%;max-width:66.6666666667%}.el-col-md-16.is-guttered{display:block}.el-col-md-offset-16{margin-left:66.6666666667%}.el-col-md-pull-16{position:relative;right:66.6666666667%}.el-col-md-push-16{left:66.6666666667%;position:relative}.el-col-md-17{display:block;flex:0 0 70.8333333333%;max-width:70.8333333333%}.el-col-md-17.is-guttered{display:block}.el-col-md-offset-17{margin-left:70.8333333333%}.el-col-md-pull-17{position:relative;right:70.8333333333%}.el-col-md-push-17{left:70.8333333333%;position:relative}.el-col-md-18{display:block;flex:0 0 75%;max-width:75%}.el-col-md-18.is-guttered{display:block}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{left:75%;position:relative}.el-col-md-19{display:block;flex:0 0 79.1666666667%;max-width:79.1666666667%}.el-col-md-19.is-guttered{display:block}.el-col-md-offset-19{margin-left:79.1666666667%}.el-col-md-pull-19{position:relative;right:79.1666666667%}.el-col-md-push-19{left:79.1666666667%;position:relative}.el-col-md-20{display:block;flex:0 0 83.3333333333%;max-width:83.3333333333%}.el-col-md-20.is-guttered{display:block}.el-col-md-offset-20{margin-left:83.3333333333%}.el-col-md-pull-20{position:relative;right:83.3333333333%}.el-col-md-push-20{left:83.3333333333%;position:relative}.el-col-md-21{display:block;flex:0 0 87.5%;max-width:87.5%}.el-col-md-21.is-guttered{display:block}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{left:87.5%;position:relative}.el-col-md-22{display:block;flex:0 0 91.6666666667%;max-width:91.6666666667%}.el-col-md-22.is-guttered{display:block}.el-col-md-offset-22{margin-left:91.6666666667%}.el-col-md-pull-22{position:relative;right:91.6666666667%}.el-col-md-push-22{left:91.6666666667%;position:relative}.el-col-md-23{display:block;flex:0 0 95.8333333333%;max-width:95.8333333333%}.el-col-md-23.is-guttered{display:block}.el-col-md-offset-23{margin-left:95.8333333333%}.el-col-md-pull-23{position:relative;right:95.8333333333%}.el-col-md-push-23{left:95.8333333333%;position:relative}.el-col-md-24{display:block;flex:0 0 100%;max-width:100%}.el-col-md-24.is-guttered{display:block}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{left:100%;position:relative}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;flex:0 0 0%;max-width:0}.el-col-lg-0.is-guttered{display:none}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{left:0;position:relative}.el-col-lg-1{flex:0 0 4.1666666667%;max-width:4.1666666667%}.el-col-lg-1,.el-col-lg-1.is-guttered{display:block}.el-col-lg-offset-1{margin-left:4.1666666667%}.el-col-lg-pull-1{position:relative;right:4.1666666667%}.el-col-lg-push-1{left:4.1666666667%;position:relative}.el-col-lg-2{flex:0 0 8.3333333333%;max-width:8.3333333333%}.el-col-lg-2,.el-col-lg-2.is-guttered{display:block}.el-col-lg-offset-2{margin-left:8.3333333333%}.el-col-lg-pull-2{position:relative;right:8.3333333333%}.el-col-lg-push-2{left:8.3333333333%;position:relative}.el-col-lg-3{flex:0 0 12.5%;max-width:12.5%}.el-col-lg-3,.el-col-lg-3.is-guttered{display:block}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{left:12.5%;position:relative}.el-col-lg-4{flex:0 0 16.6666666667%;max-width:16.6666666667%}.el-col-lg-4,.el-col-lg-4.is-guttered{display:block}.el-col-lg-offset-4{margin-left:16.6666666667%}.el-col-lg-pull-4{position:relative;right:16.6666666667%}.el-col-lg-push-4{left:16.6666666667%;position:relative}.el-col-lg-5{flex:0 0 20.8333333333%;max-width:20.8333333333%}.el-col-lg-5,.el-col-lg-5.is-guttered{display:block}.el-col-lg-offset-5{margin-left:20.8333333333%}.el-col-lg-pull-5{position:relative;right:20.8333333333%}.el-col-lg-push-5{left:20.8333333333%;position:relative}.el-col-lg-6{flex:0 0 25%;max-width:25%}.el-col-lg-6,.el-col-lg-6.is-guttered{display:block}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{left:25%;position:relative}.el-col-lg-7{flex:0 0 29.1666666667%;max-width:29.1666666667%}.el-col-lg-7,.el-col-lg-7.is-guttered{display:block}.el-col-lg-offset-7{margin-left:29.1666666667%}.el-col-lg-pull-7{position:relative;right:29.1666666667%}.el-col-lg-push-7{left:29.1666666667%;position:relative}.el-col-lg-8{flex:0 0 33.3333333333%;max-width:33.3333333333%}.el-col-lg-8,.el-col-lg-8.is-guttered{display:block}.el-col-lg-offset-8{margin-left:33.3333333333%}.el-col-lg-pull-8{position:relative;right:33.3333333333%}.el-col-lg-push-8{left:33.3333333333%;position:relative}.el-col-lg-9{flex:0 0 37.5%;max-width:37.5%}.el-col-lg-9,.el-col-lg-9.is-guttered{display:block}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{left:37.5%;position:relative}.el-col-lg-10{display:block;flex:0 0 41.6666666667%;max-width:41.6666666667%}.el-col-lg-10.is-guttered{display:block}.el-col-lg-offset-10{margin-left:41.6666666667%}.el-col-lg-pull-10{position:relative;right:41.6666666667%}.el-col-lg-push-10{left:41.6666666667%;position:relative}.el-col-lg-11{display:block;flex:0 0 45.8333333333%;max-width:45.8333333333%}.el-col-lg-11.is-guttered{display:block}.el-col-lg-offset-11{margin-left:45.8333333333%}.el-col-lg-pull-11{position:relative;right:45.8333333333%}.el-col-lg-push-11{left:45.8333333333%;position:relative}.el-col-lg-12{display:block;flex:0 0 50%;max-width:50%}.el-col-lg-12.is-guttered{display:block}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{left:50%;position:relative}.el-col-lg-13{display:block;flex:0 0 54.1666666667%;max-width:54.1666666667%}.el-col-lg-13.is-guttered{display:block}.el-col-lg-offset-13{margin-left:54.1666666667%}.el-col-lg-pull-13{position:relative;right:54.1666666667%}.el-col-lg-push-13{left:54.1666666667%;position:relative}.el-col-lg-14{display:block;flex:0 0 58.3333333333%;max-width:58.3333333333%}.el-col-lg-14.is-guttered{display:block}.el-col-lg-offset-14{margin-left:58.3333333333%}.el-col-lg-pull-14{position:relative;right:58.3333333333%}.el-col-lg-push-14{left:58.3333333333%;position:relative}.el-col-lg-15{display:block;flex:0 0 62.5%;max-width:62.5%}.el-col-lg-15.is-guttered{display:block}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{left:62.5%;position:relative}.el-col-lg-16{display:block;flex:0 0 66.6666666667%;max-width:66.6666666667%}.el-col-lg-16.is-guttered{display:block}.el-col-lg-offset-16{margin-left:66.6666666667%}.el-col-lg-pull-16{position:relative;right:66.6666666667%}.el-col-lg-push-16{left:66.6666666667%;position:relative}.el-col-lg-17{display:block;flex:0 0 70.8333333333%;max-width:70.8333333333%}.el-col-lg-17.is-guttered{display:block}.el-col-lg-offset-17{margin-left:70.8333333333%}.el-col-lg-pull-17{position:relative;right:70.8333333333%}.el-col-lg-push-17{left:70.8333333333%;position:relative}.el-col-lg-18{display:block;flex:0 0 75%;max-width:75%}.el-col-lg-18.is-guttered{display:block}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{left:75%;position:relative}.el-col-lg-19{display:block;flex:0 0 79.1666666667%;max-width:79.1666666667%}.el-col-lg-19.is-guttered{display:block}.el-col-lg-offset-19{margin-left:79.1666666667%}.el-col-lg-pull-19{position:relative;right:79.1666666667%}.el-col-lg-push-19{left:79.1666666667%;position:relative}.el-col-lg-20{display:block;flex:0 0 83.3333333333%;max-width:83.3333333333%}.el-col-lg-20.is-guttered{display:block}.el-col-lg-offset-20{margin-left:83.3333333333%}.el-col-lg-pull-20{position:relative;right:83.3333333333%}.el-col-lg-push-20{left:83.3333333333%;position:relative}.el-col-lg-21{display:block;flex:0 0 87.5%;max-width:87.5%}.el-col-lg-21.is-guttered{display:block}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{left:87.5%;position:relative}.el-col-lg-22{display:block;flex:0 0 91.6666666667%;max-width:91.6666666667%}.el-col-lg-22.is-guttered{display:block}.el-col-lg-offset-22{margin-left:91.6666666667%}.el-col-lg-pull-22{position:relative;right:91.6666666667%}.el-col-lg-push-22{left:91.6666666667%;position:relative}.el-col-lg-23{display:block;flex:0 0 95.8333333333%;max-width:95.8333333333%}.el-col-lg-23.is-guttered{display:block}.el-col-lg-offset-23{margin-left:95.8333333333%}.el-col-lg-pull-23{position:relative;right:95.8333333333%}.el-col-lg-push-23{left:95.8333333333%;position:relative}.el-col-lg-24{display:block;flex:0 0 100%;max-width:100%}.el-col-lg-24.is-guttered{display:block}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{left:100%;position:relative}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;flex:0 0 0%;max-width:0}.el-col-xl-0.is-guttered{display:none}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{left:0;position:relative}.el-col-xl-1{flex:0 0 4.1666666667%;max-width:4.1666666667%}.el-col-xl-1,.el-col-xl-1.is-guttered{display:block}.el-col-xl-offset-1{margin-left:4.1666666667%}.el-col-xl-pull-1{position:relative;right:4.1666666667%}.el-col-xl-push-1{left:4.1666666667%;position:relative}.el-col-xl-2{flex:0 0 8.3333333333%;max-width:8.3333333333%}.el-col-xl-2,.el-col-xl-2.is-guttered{display:block}.el-col-xl-offset-2{margin-left:8.3333333333%}.el-col-xl-pull-2{position:relative;right:8.3333333333%}.el-col-xl-push-2{left:8.3333333333%;position:relative}.el-col-xl-3{flex:0 0 12.5%;max-width:12.5%}.el-col-xl-3,.el-col-xl-3.is-guttered{display:block}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{left:12.5%;position:relative}.el-col-xl-4{flex:0 0 16.6666666667%;max-width:16.6666666667%}.el-col-xl-4,.el-col-xl-4.is-guttered{display:block}.el-col-xl-offset-4{margin-left:16.6666666667%}.el-col-xl-pull-4{position:relative;right:16.6666666667%}.el-col-xl-push-4{left:16.6666666667%;position:relative}.el-col-xl-5{flex:0 0 20.8333333333%;max-width:20.8333333333%}.el-col-xl-5,.el-col-xl-5.is-guttered{display:block}.el-col-xl-offset-5{margin-left:20.8333333333%}.el-col-xl-pull-5{position:relative;right:20.8333333333%}.el-col-xl-push-5{left:20.8333333333%;position:relative}.el-col-xl-6{flex:0 0 25%;max-width:25%}.el-col-xl-6,.el-col-xl-6.is-guttered{display:block}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{left:25%;position:relative}.el-col-xl-7{flex:0 0 29.1666666667%;max-width:29.1666666667%}.el-col-xl-7,.el-col-xl-7.is-guttered{display:block}.el-col-xl-offset-7{margin-left:29.1666666667%}.el-col-xl-pull-7{position:relative;right:29.1666666667%}.el-col-xl-push-7{left:29.1666666667%;position:relative}.el-col-xl-8{flex:0 0 33.3333333333%;max-width:33.3333333333%}.el-col-xl-8,.el-col-xl-8.is-guttered{display:block}.el-col-xl-offset-8{margin-left:33.3333333333%}.el-col-xl-pull-8{position:relative;right:33.3333333333%}.el-col-xl-push-8{left:33.3333333333%;position:relative}.el-col-xl-9{flex:0 0 37.5%;max-width:37.5%}.el-col-xl-9,.el-col-xl-9.is-guttered{display:block}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{left:37.5%;position:relative}.el-col-xl-10{display:block;flex:0 0 41.6666666667%;max-width:41.6666666667%}.el-col-xl-10.is-guttered{display:block}.el-col-xl-offset-10{margin-left:41.6666666667%}.el-col-xl-pull-10{position:relative;right:41.6666666667%}.el-col-xl-push-10{left:41.6666666667%;position:relative}.el-col-xl-11{display:block;flex:0 0 45.8333333333%;max-width:45.8333333333%}.el-col-xl-11.is-guttered{display:block}.el-col-xl-offset-11{margin-left:45.8333333333%}.el-col-xl-pull-11{position:relative;right:45.8333333333%}.el-col-xl-push-11{left:45.8333333333%;position:relative}.el-col-xl-12{display:block;flex:0 0 50%;max-width:50%}.el-col-xl-12.is-guttered{display:block}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{left:50%;position:relative}.el-col-xl-13{display:block;flex:0 0 54.1666666667%;max-width:54.1666666667%}.el-col-xl-13.is-guttered{display:block}.el-col-xl-offset-13{margin-left:54.1666666667%}.el-col-xl-pull-13{position:relative;right:54.1666666667%}.el-col-xl-push-13{left:54.1666666667%;position:relative}.el-col-xl-14{display:block;flex:0 0 58.3333333333%;max-width:58.3333333333%}.el-col-xl-14.is-guttered{display:block}.el-col-xl-offset-14{margin-left:58.3333333333%}.el-col-xl-pull-14{position:relative;right:58.3333333333%}.el-col-xl-push-14{left:58.3333333333%;position:relative}.el-col-xl-15{display:block;flex:0 0 62.5%;max-width:62.5%}.el-col-xl-15.is-guttered{display:block}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{left:62.5%;position:relative}.el-col-xl-16{display:block;flex:0 0 66.6666666667%;max-width:66.6666666667%}.el-col-xl-16.is-guttered{display:block}.el-col-xl-offset-16{margin-left:66.6666666667%}.el-col-xl-pull-16{position:relative;right:66.6666666667%}.el-col-xl-push-16{left:66.6666666667%;position:relative}.el-col-xl-17{display:block;flex:0 0 70.8333333333%;max-width:70.8333333333%}.el-col-xl-17.is-guttered{display:block}.el-col-xl-offset-17{margin-left:70.8333333333%}.el-col-xl-pull-17{position:relative;right:70.8333333333%}.el-col-xl-push-17{left:70.8333333333%;position:relative}.el-col-xl-18{display:block;flex:0 0 75%;max-width:75%}.el-col-xl-18.is-guttered{display:block}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{left:75%;position:relative}.el-col-xl-19{display:block;flex:0 0 79.1666666667%;max-width:79.1666666667%}.el-col-xl-19.is-guttered{display:block}.el-col-xl-offset-19{margin-left:79.1666666667%}.el-col-xl-pull-19{position:relative;right:79.1666666667%}.el-col-xl-push-19{left:79.1666666667%;position:relative}.el-col-xl-20{display:block;flex:0 0 83.3333333333%;max-width:83.3333333333%}.el-col-xl-20.is-guttered{display:block}.el-col-xl-offset-20{margin-left:83.3333333333%}.el-col-xl-pull-20{position:relative;right:83.3333333333%}.el-col-xl-push-20{left:83.3333333333%;position:relative}.el-col-xl-21{display:block;flex:0 0 87.5%;max-width:87.5%}.el-col-xl-21.is-guttered{display:block}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{left:87.5%;position:relative}.el-col-xl-22{display:block;flex:0 0 91.6666666667%;max-width:91.6666666667%}.el-col-xl-22.is-guttered{display:block}.el-col-xl-offset-22{margin-left:91.6666666667%}.el-col-xl-pull-22{position:relative;right:91.6666666667%}.el-col-xl-push-22{left:91.6666666667%;position:relative}.el-col-xl-23{display:block;flex:0 0 95.8333333333%;max-width:95.8333333333%}.el-col-xl-23.is-guttered{display:block}.el-col-xl-offset-23{margin-left:95.8333333333%}.el-col-xl-pull-23{position:relative;right:95.8333333333%}.el-col-xl-push-23{left:95.8333333333%;position:relative}.el-col-xl-24{display:block;flex:0 0 100%;max-width:100%}.el-col-xl-24.is-guttered{display:block}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{left:100%;position:relative}}.el-collapse{--el-collapse-border-color:var(--el-border-color-lighter);--el-collapse-header-height:48px;--el-collapse-header-bg-color:var(--el-fill-color-blank);--el-collapse-header-text-color:var(--el-text-color-primary);--el-collapse-header-font-size:13px;--el-collapse-content-bg-color:var(--el-fill-color-blank);--el-collapse-content-font-size:13px;--el-collapse-content-text-color:var(--el-text-color-primary);border-bottom:1px solid var(--el-collapse-border-color);border-top:1px solid var(--el-collapse-border-color)}.el-collapse-item.is-disabled .el-collapse-item__header{color:var(--el-text-color-disabled);cursor:not-allowed}.el-collapse-item__header{align-items:center;background-color:var(--el-collapse-header-bg-color);border:none;border-bottom:1px solid var(--el-collapse-border-color);color:var(--el-collapse-header-text-color);cursor:pointer;display:flex;font-size:var(--el-collapse-header-font-size);font-weight:500;height:var(--el-collapse-header-height);line-height:var(--el-collapse-header-height);outline:none;padding:0;transition:border-bottom-color var(--el-transition-duration);width:100%}.el-collapse-item__arrow{font-weight:300;margin:0 8px 0 auto;transition:transform var(--el-transition-duration)}.el-collapse-item__arrow.is-active{transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:var(--el-color-primary)}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{background-color:var(--el-collapse-content-bg-color);border-bottom:1px solid var(--el-collapse-border-color);box-sizing:border-box;overflow:hidden;will-change:height}.el-collapse-item__content{color:var(--el-collapse-content-text-color);font-size:var(--el-collapse-content-font-size);line-height:1.7692307692;padding-bottom:25px}.el-collapse-item:last-child{margin-bottom:-1px}.el-color-predefine{display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:flex;flex:1;flex-wrap:wrap}.el-color-predefine__color-selector{border-radius:4px;cursor:pointer;height:20px;margin:0 0 8px 8px;width:20px}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{box-shadow:0 0 3px 2px var(--el-color-primary)}.el-color-predefine__color-selector>div{border-radius:3px;display:flex;height:100%}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{background-color:red;box-sizing:border-box;float:right;height:12px;padding:0 2px;position:relative;width:280px}.el-color-hue-slider__bar{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red);height:100%;position:relative}.el-color-hue-slider__thumb{background:#fff;border:1px solid var(--el-border-color-lighter);border-radius:1px;box-shadow:0 0 2px #0009;box-sizing:border-box;cursor:pointer;height:100%;left:0;position:absolute;top:0;width:4px;z-index:1}.el-color-hue-slider.is-vertical{height:180px;padding:2px 0;width:12px}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:linear-gradient(180deg,red 0,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{height:4px;left:0;top:0;width:100%}.el-color-svpanel{height:180px;position:relative;width:280px}.el-color-svpanel__black,.el-color-svpanel__white{bottom:0;left:0;position:absolute;right:0;top:0}.el-color-svpanel__white{background:linear-gradient(90deg,#fff,#fff0)}.el-color-svpanel__black{background:linear-gradient(0deg,#000,#0000)}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{border-radius:50%;box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px #0000004d,0 0 1px 2px #0006;cursor:head;height:4px;transform:translate(-2px,-2px);width:4px}.el-color-alpha-slider{background-image:linear-gradient(45deg,var(--el-color-picker-alpha-bg-a) 25%,var(--el-color-picker-alpha-bg-b) 25%),linear-gradient(135deg,var(--el-color-picker-alpha-bg-a) 25%,var(--el-color-picker-alpha-bg-b) 25%),linear-gradient(45deg,var(--el-color-picker-alpha-bg-b) 75%,var(--el-color-picker-alpha-bg-a) 75%),linear-gradient(135deg,var(--el-color-picker-alpha-bg-b) 75%,var(--el-color-picker-alpha-bg-a) 75%);background-position:0 0,6px 0,6px -6px,0 6px;background-size:12px 12px;box-sizing:border-box;height:12px;position:relative;width:280px}.el-color-alpha-slider__bar{background:linear-gradient(to right,rgba(255,255,255,0) 0,var(--el-bg-color) 100%);height:100%;position:relative}.el-color-alpha-slider__thumb{background:#fff;border:1px solid var(--el-border-color-lighter);border-radius:1px;box-shadow:0 0 2px #0009;box-sizing:border-box;cursor:pointer;height:100%;left:0;position:absolute;top:0;width:4px;z-index:1}.el-color-alpha-slider.is-vertical{height:180px;width:20px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:linear-gradient(180deg,#fff0 0,#fff)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{height:4px;left:0;top:0;width:100%}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper:after{clear:both;content:"";display:table}.el-color-dropdown__btns{margin-top:12px;text-align:right}.el-color-dropdown__value{color:#000;float:left;font-size:12px;line-height:26px;width:160px}.el-color-picker{display:inline-block;line-height:normal;outline:none;position:relative}.el-color-picker:hover:not(.is-disabled,.is-focused) .el-color-picker__trigger{border-color:var(--el-border-color-hover)}.el-color-picker:focus-visible:not(.is-disabled) .el-color-picker__trigger{outline:2px solid var(--el-color-primary);outline-offset:1px}.el-color-picker.is-focused .el-color-picker__trigger{border-color:var(--el-color-primary)}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--large{height:40px}.el-color-picker--large .el-color-picker__trigger{height:40px;width:40px}.el-color-picker--large .el-color-picker__mask{height:38px;width:38px}.el-color-picker--small{height:24px}.el-color-picker--small .el-color-picker__trigger{height:24px;width:24px}.el-color-picker--small .el-color-picker__mask{height:22px;width:22px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{transform:scale(.8)}.el-color-picker__mask{background-color:#ffffffb3;border-radius:4px;cursor:not-allowed;height:30px;left:1px;position:absolute;top:1px;width:30px;z-index:1}.el-color-picker__trigger{align-items:center;border:1px solid var(--el-border-color);border-radius:4px;box-sizing:border-box;cursor:pointer;display:inline-flex;font-size:0;height:32px;justify-content:center;padding:4px;position:relative;width:32px}.el-color-picker__color{border:1px solid var(--el-text-color-secondary);border-radius:var(--el-border-radius-small);box-sizing:border-box;display:block;height:100%;position:relative;text-align:center;width:100%}.el-color-picker__color.is-alpha{background-image:linear-gradient(45deg,var(--el-color-picker-alpha-bg-a) 25%,var(--el-color-picker-alpha-bg-b) 25%),linear-gradient(135deg,var(--el-color-picker-alpha-bg-a) 25%,var(--el-color-picker-alpha-bg-b) 25%),linear-gradient(45deg,var(--el-color-picker-alpha-bg-b) 75%,var(--el-color-picker-alpha-bg-a) 75%),linear-gradient(135deg,var(--el-color-picker-alpha-bg-b) 75%,var(--el-color-picker-alpha-bg-a) 75%);background-position:0 0,6px 0,6px -6px,0 6px;background-size:12px 12px}.el-color-picker__color-inner{align-items:center;display:inline-flex;height:100%;justify-content:center;width:100%}.el-color-picker .el-color-picker__empty{color:var(--el-text-color-secondary);font-size:12px}.el-color-picker .el-color-picker__icon{align-items:center;color:#fff;display:inline-flex;font-size:12px;justify-content:center}.el-color-picker__panel{background-color:#fff;border-radius:var(--el-border-radius-base);box-shadow:var(--el-box-shadow-light);box-sizing:content-box;padding:6px;position:absolute;z-index:10}.el-color-picker__panel.el-popper{border:1px solid var(--el-border-color-lighter)}.el-color-picker,.el-color-picker__panel{--el-color-picker-alpha-bg-a:#ccc;--el-color-picker-alpha-bg-b:transparent}.dark .el-color-picker,.dark .el-color-picker__panel{--el-color-picker-alpha-bg-a:#333333}.el-container{box-sizing:border-box;display:flex;flex:1;flex-basis:auto;flex-direction:row;min-width:0}.el-container.is-vertical{flex-direction:column}.el-date-table{font-size:12px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover .el-date-table-cell{background-color:var(--el-datepicker-inrange-bg-color)}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:var(--el-datepicker-text-color)}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child .el-date-table-cell{border-bottom-left-radius:15px;border-top-left-radius:15px;margin-left:5px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child .el-date-table-cell{border-bottom-right-radius:15px;border-top-right-radius:15px;margin-right:5px}.el-date-table.is-week-mode .el-date-table__row.current .el-date-table-cell{background-color:var(--el-datepicker-inrange-bg-color)}.el-date-table td{box-sizing:border-box;cursor:pointer;height:30px;padding:4px 0;position:relative;text-align:center;width:32px}.el-date-table td .el-date-table-cell{box-sizing:border-box;height:30px;padding:3px 0}.el-date-table td .el-date-table-cell .el-date-table-cell__text{border-radius:50%;display:block;height:24px;left:50%;line-height:24px;margin:0 auto;position:absolute;transform:translate(-50%);width:24px}.el-date-table td.next-month,.el-date-table td.prev-month{color:var(--el-datepicker-off-text-color)}.el-date-table td.today{position:relative}.el-date-table td.today .el-date-table-cell__text{color:var(--el-color-primary);font-weight:700}.el-date-table td.today.end-date .el-date-table-cell__text,.el-date-table td.today.start-date .el-date-table-cell__text{color:#fff}.el-date-table td.available:hover{color:var(--el-datepicker-hover-text-color)}.el-date-table td.in-range .el-date-table-cell{background-color:var(--el-datepicker-inrange-bg-color)}.el-date-table td.in-range .el-date-table-cell:hover{background-color:var(--el-datepicker-inrange-hover-bg-color)}.el-date-table td.current:not(.disabled) .el-date-table-cell__text{background-color:var(--el-datepicker-active-color);color:#fff}.el-date-table td.current:not(.disabled):focus-visible .el-date-table-cell__text{outline:2px solid var(--el-datepicker-active-color);outline-offset:1px}.el-date-table td.end-date .el-date-table-cell,.el-date-table td.start-date .el-date-table-cell{color:#fff}.el-date-table td.end-date .el-date-table-cell__text,.el-date-table td.start-date .el-date-table-cell__text{background-color:var(--el-datepicker-active-color)}.el-date-table td.start-date .el-date-table-cell{border-bottom-left-radius:15px;border-top-left-radius:15px;margin-left:5px}.el-date-table td.end-date .el-date-table-cell{border-bottom-right-radius:15px;border-top-right-radius:15px;margin-right:5px}.el-date-table td.disabled .el-date-table-cell{background-color:var(--el-fill-color-light);color:var(--el-text-color-placeholder);cursor:not-allowed;opacity:1}.el-date-table td.selected .el-date-table-cell{border-radius:15px;margin-left:5px;margin-right:5px}.el-date-table td.selected .el-date-table-cell__text{background-color:var(--el-datepicker-active-color);border-radius:15px;color:#fff}.el-date-table td.week{color:var(--el-datepicker-header-text-color);font-size:80%}.el-date-table td:focus{outline:none}.el-date-table th{border-bottom:1px solid var(--el-border-color-lighter);color:var(--el-datepicker-header-text-color);font-weight:400;padding:5px}.el-month-table{border-collapse:collapse;font-size:12px;margin:-1px}.el-month-table td{cursor:pointer;padding:8px 0;position:relative;text-align:center;width:68px}.el-month-table td div{box-sizing:border-box;height:48px;padding:6px 0}.el-month-table td.today .cell{color:var(--el-color-primary);font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#fff}.el-month-table td.disabled .cell{background-color:var(--el-fill-color-light);cursor:not-allowed}.el-month-table td.disabled .cell,.el-month-table td.disabled .cell:hover{color:var(--el-text-color-placeholder)}.el-month-table td .cell{border-radius:18px;color:var(--el-datepicker-text-color);display:block;height:36px;left:50%;line-height:36px;margin:0 auto;position:absolute;transform:translate(-50%);width:54px}.el-month-table td .cell:hover{color:var(--el-datepicker-hover-text-color)}.el-month-table td.in-range div{background-color:var(--el-datepicker-inrange-bg-color)}.el-month-table td.in-range div:hover{background-color:var(--el-datepicker-inrange-hover-bg-color)}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#fff}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{background-color:var(--el-datepicker-active-color);color:#fff}.el-month-table td.start-date div{border-bottom-left-radius:24px;border-top-left-radius:24px;margin-left:3px}.el-month-table td.end-date div{border-bottom-right-radius:24px;border-top-right-radius:24px;margin-right:3px}.el-month-table td.current:not(.disabled) div{border-radius:24px;margin-left:3px;margin-right:3px}.el-month-table td.current:not(.disabled) .cell{background-color:var(--el-datepicker-active-color);color:#fff}.el-month-table td:focus-visible{outline:none}.el-month-table td:focus-visible .cell{outline:2px solid var(--el-datepicker-active-color);outline-offset:1px}.el-year-table{border-collapse:collapse;font-size:12px;margin:-1px}.el-year-table .el-icon{color:var(--el-datepicker-icon-color)}.el-year-table td{cursor:pointer;padding:8px 0;position:relative;text-align:center;width:68px}.el-year-table td div{box-sizing:border-box;height:48px;padding:6px 0}.el-year-table td.today .cell{color:var(--el-color-primary);font-weight:700}.el-year-table td.disabled .cell{background-color:var(--el-fill-color-light);cursor:not-allowed}.el-year-table td.disabled .cell,.el-year-table td.disabled .cell:hover{color:var(--el-text-color-placeholder)}.el-year-table td .cell{border-radius:18px;color:var(--el-datepicker-text-color);display:block;height:36px;left:50%;line-height:36px;margin:0 auto;position:absolute;transform:translate(-50%);width:54px}.el-year-table td .cell:hover{color:var(--el-datepicker-hover-text-color)}.el-year-table td.current:not(.disabled) div{border-radius:24px;margin-left:3px;margin-right:3px}.el-year-table td.current:not(.disabled) .cell{background-color:var(--el-datepicker-active-color);color:#fff}.el-year-table td:focus-visible{outline:none}.el-year-table td:focus-visible .cell{outline:2px solid var(--el-datepicker-active-color);outline-offset:1px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{display:inline-block;max-height:192px;overflow:auto;position:relative;vertical-align:top;width:50%}.el-time-spinner__wrapper.el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__wrapper.is-arrow{box-sizing:border-box;overflow:hidden;text-align:center}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.is-disabled):not(.is-active){background:var(--el-fill-color-light);cursor:default}.el-time-spinner__arrow{color:var(--el-text-color-secondary);cursor:pointer;font-size:12px;height:30px;left:0;line-height:30px;position:absolute;text-align:center;width:100%;z-index:var(--el-index-normal)}.el-time-spinner__arrow:hover{color:var(--el-color-primary)}.el-time-spinner__arrow.arrow-up{top:10px}.el-time-spinner__arrow.arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__list{list-style:none;margin:0}.el-time-spinner__list:after,.el-time-spinner__list:before{content:"";display:block;height:80px;width:100%}.el-time-spinner__item{color:var(--el-text-color-regular);font-size:12px;height:32px;line-height:32px}.el-time-spinner__item:hover:not(.is-disabled):not(.is-active){background:var(--el-fill-color-light);cursor:pointer}.el-time-spinner__item.is-active:not(.is-disabled){color:var(--el-text-color-primary);font-weight:700}.el-time-spinner__item.is-disabled{color:var(--el-text-color-placeholder);cursor:not-allowed}.el-picker__popper{--el-datepicker-border-color:var(--el-disabled-border-color)}.el-picker__popper.el-popper{background:var(--el-bg-color-overlay);box-shadow:var(--el-box-shadow-light)}.el-picker__popper.el-popper,.el-picker__popper.el-popper .el-popper__arrow:before{border:1px solid var(--el-datepicker-border-color)}.el-picker__popper.el-popper[data-popper-placement^=top] .el-popper__arrow:before{border-left-color:transparent;border-top-color:transparent}.el-picker__popper.el-popper[data-popper-placement^=bottom] .el-popper__arrow:before{border-bottom-color:transparent;border-right-color:transparent}.el-picker__popper.el-popper[data-popper-placement^=left] .el-popper__arrow:before{border-bottom-color:transparent;border-left-color:transparent}.el-picker__popper.el-popper[data-popper-placement^=right] .el-popper__arrow:before{border-right-color:transparent;border-top-color:transparent}.el-date-editor{--el-date-editor-width:220px;--el-date-editor-monthrange-width:300px;--el-date-editor-daterange-width:350px;--el-date-editor-datetimerange-width:400px;--el-input-text-color:var(--el-text-color-regular);--el-input-border:var(--el-border);--el-input-hover-border:var(--el-border-color-hover);--el-input-focus-border:var(--el-color-primary);--el-input-transparent-border:0 0 0 1px transparent inset;--el-input-border-color:var(--el-border-color);--el-input-border-radius:var(--el-border-radius-base);--el-input-bg-color:var(--el-fill-color-blank);--el-input-icon-color:var(--el-text-color-placeholder);--el-input-placeholder-color:var(--el-text-color-placeholder);--el-input-hover-border-color:var(--el-border-color-hover);--el-input-clear-hover-color:var(--el-text-color-secondary);--el-input-focus-border-color:var(--el-color-primary);--el-input-width:100%;position:relative;text-align:left;vertical-align:middle}.el-date-editor.el-input__wrapper{box-shadow:0 0 0 1px var(--el-input-border-color,var(--el-border-color)) inset}.el-date-editor.el-input__wrapper:hover{box-shadow:0 0 0 1px var(--el-input-hover-border-color) inset}.el-date-editor.el-input,.el-date-editor.el-input__wrapper{height:var(--el-input-height,var(--el-component-size));width:var(--el-date-editor-width)}.el-date-editor--monthrange{--el-date-editor-width:var(--el-date-editor-monthrange-width)}.el-date-editor--daterange,.el-date-editor--timerange{--el-date-editor-width:var(--el-date-editor-daterange-width)}.el-date-editor--datetimerange{--el-date-editor-width:var(--el-date-editor-datetimerange-width)}.el-date-editor--dates .el-input__wrapper{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .clear-icon,.el-date-editor .close-icon{cursor:pointer}.el-date-editor .clear-icon:hover{color:var(--el-text-color-secondary)}.el-date-editor .el-range__icon{color:var(--el-text-color-placeholder);float:left;font-size:14px;height:inherit}.el-date-editor .el-range__icon svg{vertical-align:middle}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:none;color:var(--el-text-color-regular);display:inline-block;font-size:var(--el-font-size-base);height:30px;line-height:30px;margin:0;outline:none;padding:0;text-align:center;width:39%}.el-date-editor .el-range-input::-moz-placeholder{color:var(--el-text-color-placeholder)}.el-date-editor .el-range-input::placeholder{color:var(--el-text-color-placeholder)}.el-date-editor .el-range-separator{align-items:center;color:var(--el-text-color-primary);display:inline-flex;flex:1;font-size:14px;height:100%;justify-content:center;margin:0;overflow-wrap:break-word;padding:0 5px}.el-date-editor .el-range__close-icon{color:var(--el-text-color-placeholder);cursor:pointer;font-size:14px;height:inherit;width:unset}.el-date-editor .el-range__close-icon:hover{color:var(--el-text-color-secondary)}.el-date-editor .el-range__close-icon svg{vertical-align:middle}.el-date-editor .el-range__close-icon--hidden{opacity:0;visibility:hidden}.el-range-editor.el-input__wrapper{align-items:center;display:inline-flex;padding:0 10px}.el-range-editor.is-active,.el-range-editor.is-active:hover{box-shadow:0 0 0 1px var(--el-input-focus-border-color) inset}.el-range-editor--large{line-height:var(--el-component-size-large)}.el-range-editor--large.el-input__wrapper{height:var(--el-component-size-large)}.el-range-editor--large .el-range-separator{font-size:14px;line-height:40px}.el-range-editor--large .el-range-input{font-size:14px;height:38px;line-height:38px}.el-range-editor--small{line-height:var(--el-component-size-small)}.el-range-editor--small.el-input__wrapper{height:var(--el-component-size-small)}.el-range-editor--small .el-range-separator{font-size:12px;line-height:24px}.el-range-editor--small .el-range-input{font-size:12px;height:22px;line-height:22px}.el-range-editor.is-disabled{background-color:var(--el-disabled-bg-color);color:var(--el-disabled-text-color);cursor:not-allowed}.el-range-editor.is-disabled,.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:var(--el-disabled-border-color)}.el-range-editor.is-disabled input{background-color:var(--el-disabled-bg-color);color:var(--el-disabled-text-color);cursor:not-allowed}.el-range-editor.is-disabled input::-moz-placeholder{color:var(--el-text-color-placeholder)}.el-range-editor.is-disabled input::placeholder{color:var(--el-text-color-placeholder)}.el-range-editor.is-disabled .el-range-separator{color:var(--el-disabled-text-color)}.el-picker-panel{background:var(--el-bg-color-overlay);border-radius:var(--el-border-radius-base);color:var(--el-text-color-regular);line-height:30px}.el-picker-panel .el-time-panel{background-color:var(--el-bg-color-overlay);border:1px solid var(--el-datepicker-border-color);box-shadow:var(--el-box-shadow-light);margin:5px 0}.el-picker-panel__body-wrapper:after,.el-picker-panel__body:after{clear:both;content:"";display:table}.el-picker-panel__content{margin:15px;position:relative}.el-picker-panel__footer{background-color:var(--el-bg-color-overlay);border-top:1px solid var(--el-datepicker-inner-border-color);font-size:0;padding:4px 12px;position:relative;text-align:right}.el-picker-panel__shortcut{background-color:transparent;border:0;color:var(--el-datepicker-text-color);cursor:pointer;display:block;font-size:14px;line-height:28px;outline:none;padding-left:12px;text-align:left;width:100%}.el-picker-panel__shortcut:hover{color:var(--el-datepicker-hover-text-color)}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:var(--el-datepicker-active-color)}.el-picker-panel__btn{background-color:transparent;border:1px solid var(--el-fill-color-darker);border-radius:2px;color:var(--el-text-color-primary);cursor:pointer;font-size:12px;line-height:24px;outline:none;padding:0 20px}.el-picker-panel__btn[disabled]{color:var(--el-text-color-disabled);cursor:not-allowed}.el-picker-panel__icon-btn{background:transparent;border:0;color:var(--el-datepicker-icon-color);cursor:pointer;font-size:12px;margin-top:8px;outline:none}.el-picker-panel__icon-btn:hover{color:var(--el-datepicker-hover-text-color)}.el-picker-panel__icon-btn:focus-visible{color:var(--el-datepicker-hover-text-color)}.el-picker-panel__icon-btn.is-disabled{color:var(--el-text-color-disabled)}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__icon-btn .el-icon{cursor:pointer;font-size:inherit}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{background-color:var(--el-bg-color-overlay);border-right:1px solid var(--el-datepicker-inner-border-color);bottom:0;box-sizing:border-box;overflow:auto;padding-top:6px;position:absolute;top:0;width:110px}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-date-picker{--el-datepicker-text-color:var(--el-text-color-regular);--el-datepicker-off-text-color:var(--el-text-color-placeholder);--el-datepicker-header-text-color:var(--el-text-color-regular);--el-datepicker-icon-color:var(--el-text-color-primary);--el-datepicker-border-color:var(--el-disabled-border-color);--el-datepicker-inner-border-color:var(--el-border-color-light);--el-datepicker-inrange-bg-color:var(--el-border-color-extra-light);--el-datepicker-inrange-hover-bg-color:var(--el-border-color-extra-light);--el-datepicker-active-color:var(--el-color-primary);--el-datepicker-hover-text-color:var(--el-color-primary);width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{display:table-cell;padding:0 5px;position:relative}.el-date-picker__time-header{border-bottom:1px solid var(--el-datepicker-inner-border-color);box-sizing:border-box;display:table;font-size:12px;padding:8px 5px 5px;position:relative;width:100%}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{border-bottom:1px solid var(--el-border-color-lighter);margin-bottom:0;padding-bottom:12px}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{color:var(--el-text-color-regular);cursor:pointer;font-size:16px;font-weight:500;line-height:22px;padding:0 5px;text-align:center}.el-date-picker__header-label:hover{color:var(--el-datepicker-hover-text-color)}.el-date-picker__header-label:focus-visible{color:var(--el-datepicker-hover-text-color);outline:none}.el-date-picker__header-label.active{color:var(--el-datepicker-active-color)}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{cursor:pointer;float:left;line-height:30px;margin-left:10px}.el-date-picker .el-time-panel{position:absolute}.el-date-range-picker{--el-datepicker-text-color:var(--el-text-color-regular);--el-datepicker-off-text-color:var(--el-text-color-placeholder);--el-datepicker-header-text-color:var(--el-text-color-regular);--el-datepicker-icon-color:var(--el-text-color-primary);--el-datepicker-border-color:var(--el-disabled-border-color);--el-datepicker-inner-border-color:var(--el-border-color-light);--el-datepicker-inrange-bg-color:var(--el-border-color-extra-light);--el-datepicker-inrange-hover-bg-color:var(--el-border-color-extra-light);--el-datepicker-active-color:var(--el-color-primary);--el-datepicker-hover-text-color:var(--el-color-primary);width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{height:28px;position:relative;text-align:center}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{box-sizing:border-box;float:left;margin:0;padding:16px;width:50%}.el-date-range-picker__content.is-left{border-right:1px solid var(--el-datepicker-inner-border-color)}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{border-bottom:1px solid var(--el-datepicker-inner-border-color);box-sizing:border-box;display:table;font-size:12px;padding:8px 5px 5px;position:relative;width:100%}.el-date-range-picker__time-header>.el-icon-arrow-right{color:var(--el-datepicker-icon-color);display:table-cell;font-size:20px;vertical-align:middle}.el-date-range-picker__time-picker-wrap{display:table-cell;padding:0 5px;position:relative}.el-date-range-picker__time-picker-wrap .el-picker-panel{background:#fff;position:absolute;right:0;top:13px;z-index:1}.el-date-range-picker__time-picker-wrap .el-time-panel{position:absolute}.el-time-range-picker{overflow:visible;width:354px}.el-time-range-picker__content{padding:10px;position:relative;text-align:center;z-index:1}.el-time-range-picker__cell{box-sizing:border-box;display:inline-block;margin:0;padding:4px 7px 7px;width:50%}.el-time-range-picker__header{font-size:14px;margin-bottom:5px;text-align:center}.el-time-range-picker__body{border:1px solid var(--el-datepicker-border-color);border-radius:2px}.el-time-panel{border-radius:2px;box-sizing:content-box;left:0;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:180px;z-index:var(--el-index-top)}.el-time-panel__content{font-size:0;overflow:hidden;position:relative}.el-time-panel__content:after,.el-time-panel__content:before{box-sizing:border-box;content:"";height:32px;left:0;margin-top:-16px;padding-top:6px;position:absolute;right:0;text-align:left;top:50%;z-index:-1}.el-time-panel__content:after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content:before{border-bottom:1px solid var(--el-border-color-light);border-top:1px solid var(--el-border-color-light);margin-left:12%;margin-right:12%;padding-left:50%}.el-time-panel__content.has-seconds:after{left:66.6666666667%}.el-time-panel__content.has-seconds:before{padding-left:33.3333333333%}.el-time-panel__footer{border-top:1px solid var(--el-timepicker-inner-border-color,var(--el-border-color-light));box-sizing:border-box;height:36px;line-height:25px;padding:4px;text-align:right}.el-time-panel__btn{background-color:transparent;border:none;color:var(--el-text-color-primary);cursor:pointer;font-size:12px;line-height:28px;margin:0 5px;outline:none;padding:0 5px}.el-time-panel__btn.confirm{color:var(--el-timepicker-active-color,var(--el-color-primary));font-weight:800}.el-descriptions{--el-descriptions-table-border:1px solid var(--el-border-color-lighter);--el-descriptions-item-bordered-label-background:var(--el-fill-color-light);box-sizing:border-box;color:var(--el-text-color-primary);font-size:var(--el-font-size-base)}.el-descriptions__header{align-items:center;display:flex;justify-content:space-between;margin-bottom:16px}.el-descriptions__title{color:var(--el-text-color-primary);font-size:16px;font-weight:700}.el-descriptions__body{background-color:var(--el-fill-color-blank)}.el-descriptions__body .el-descriptions__table{border-collapse:collapse;width:100%}.el-descriptions__body .el-descriptions__table .el-descriptions__cell{box-sizing:border-box;font-size:14px;font-weight:400;line-height:23px;text-align:left}.el-descriptions__body .el-descriptions__table .el-descriptions__cell.is-left{text-align:left}.el-descriptions__body .el-descriptions__table .el-descriptions__cell.is-center{text-align:center}.el-descriptions__body .el-descriptions__table .el-descriptions__cell.is-right{text-align:right}.el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell{border:var(--el-descriptions-table-border);padding:8px 11px}.el-descriptions__body .el-descriptions__table:not(.is-bordered) .el-descriptions__cell{padding-bottom:12px}.el-descriptions--large{font-size:14px}.el-descriptions--large .el-descriptions__header{margin-bottom:20px}.el-descriptions--large .el-descriptions__header .el-descriptions__title{font-size:16px}.el-descriptions--large .el-descriptions__body .el-descriptions__table .el-descriptions__cell{font-size:14px}.el-descriptions--large .el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell{padding:12px 15px}.el-descriptions--large .el-descriptions__body .el-descriptions__table:not(.is-bordered) .el-descriptions__cell{padding-bottom:16px}.el-descriptions--small{font-size:12px}.el-descriptions--small .el-descriptions__header{margin-bottom:12px}.el-descriptions--small .el-descriptions__header .el-descriptions__title{font-size:14px}.el-descriptions--small .el-descriptions__body .el-descriptions__table .el-descriptions__cell{font-size:12px}.el-descriptions--small .el-descriptions__body .el-descriptions__table.is-bordered .el-descriptions__cell{padding:4px 7px}.el-descriptions--small .el-descriptions__body .el-descriptions__table:not(.is-bordered) .el-descriptions__cell{padding-bottom:8px}.el-descriptions__label.el-descriptions__cell.is-bordered-label{background:var(--el-descriptions-item-bordered-label-background);color:var(--el-text-color-regular);font-weight:700}.el-descriptions__label:not(.is-bordered-label){color:var(--el-text-color-primary);margin-right:16px}.el-descriptions__label.el-descriptions__cell:not(.is-bordered-label).is-vertical-label{padding-bottom:6px}.el-descriptions__content.el-descriptions__cell.is-bordered-content{color:var(--el-text-color-primary)}.el-descriptions__content:not(.is-bordered-label){color:var(--el-text-color-regular)}.el-descriptions--large .el-descriptions__label:not(.is-bordered-label){margin-right:16px}.el-descriptions--large .el-descriptions__label.el-descriptions__cell:not(.is-bordered-label).is-vertical-label{padding-bottom:8px}.el-descriptions--small .el-descriptions__label:not(.is-bordered-label){margin-right:12px}.el-descriptions--small .el-descriptions__label.el-descriptions__cell:not(.is-bordered-label).is-vertical-label{padding-bottom:4px}:root{--el-popup-modal-bg-color:var(--el-color-black);--el-popup-modal-opacity:.5}.v-modal-enter{animation:v-modal-in var(--el-transition-duration-fast) ease}.v-modal-leave{animation:v-modal-out var(--el-transition-duration-fast) ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{to{opacity:0}}.v-modal{background:var(--el-popup-modal-bg-color);height:100%;left:0;opacity:var(--el-popup-modal-opacity);position:fixed;top:0;width:100%}.el-popup-parent--hidden{overflow:hidden}.el-dialog{--el-dialog-width:50%;--el-dialog-margin-top:15vh;--el-dialog-bg-color:var(--el-bg-color);--el-dialog-box-shadow:var(--el-box-shadow);--el-dialog-title-font-size:var(--el-font-size-large);--el-dialog-content-font-size:14px;--el-dialog-font-line-height:var(--el-font-line-height-primary);--el-dialog-padding-primary:16px;--el-dialog-border-radius:var(--el-border-radius-small);background:var(--el-dialog-bg-color);border-radius:var(--el-dialog-border-radius);box-shadow:var(--el-dialog-box-shadow);box-sizing:border-box;margin:var(--el-dialog-margin-top,15vh) auto 50px;overflow-wrap:break-word;padding:var(--el-dialog-padding-primary);position:relative;width:var(--el-dialog-width,50%)}.el-dialog:focus{outline:none!important}.el-dialog.is-align-center{margin:auto}.el-dialog.is-fullscreen{--el-dialog-width:100%;--el-dialog-margin-top:0;height:100%;margin-bottom:0;overflow:auto}.el-dialog__wrapper{bottom:0;left:0;margin:0;overflow:auto;position:fixed;right:0;top:0}.el-dialog.is-draggable .el-dialog__header{cursor:move;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-dialog__header{padding-bottom:var(--el-dialog-padding-primary)}.el-dialog__header.show-close{padding-right:calc(var(--el-dialog-padding-primary) + var(--el-message-close-size, 16px))}.el-dialog__headerbtn{background:transparent;border:none;cursor:pointer;font-size:var(--el-message-close-size,16px);height:48px;outline:none;padding:0;position:absolute;right:0;top:0;width:48px}.el-dialog__headerbtn .el-dialog__close{color:var(--el-color-info);font-size:inherit}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:var(--el-color-primary)}.el-dialog__title{color:var(--el-text-color-primary);font-size:var(--el-dialog-title-font-size);line-height:var(--el-dialog-font-line-height)}.el-dialog__body{color:var(--el-text-color-regular);font-size:var(--el-dialog-content-font-size)}.el-dialog__footer{box-sizing:border-box;padding-top:var(--el-dialog-padding-primary);text-align:right}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial}.el-dialog--center .el-dialog__footer{text-align:inherit}.el-overlay-dialog{bottom:0;left:0;overflow:auto;position:fixed;right:0;top:0}.dialog-fade-enter-active{animation:modal-fade-in var(--el-transition-duration)}.dialog-fade-enter-active .el-overlay-dialog{animation:dialog-fade-in var(--el-transition-duration)}.dialog-fade-leave-active{animation:modal-fade-out var(--el-transition-duration)}.dialog-fade-leave-active .el-overlay-dialog{animation:dialog-fade-out var(--el-transition-duration)}@keyframes dialog-fade-in{0%{opacity:0;transform:translate3d(0,-20px,0)}to{opacity:1;transform:translateZ(0)}}@keyframes dialog-fade-out{0%{opacity:1;transform:translateZ(0)}to{opacity:0;transform:translate3d(0,-20px,0)}}@keyframes modal-fade-in{0%{opacity:0}to{opacity:1}}@keyframes modal-fade-out{0%{opacity:1}to{opacity:0}}.el-divider{position:relative}.el-divider--horizontal{border-top:1px var(--el-border-color) var(--el-border-style);display:block;height:1px;margin:24px 0;width:100%}.el-divider--vertical{border-left:1px var(--el-border-color) var(--el-border-style);display:inline-block;height:1em;margin:0 8px;position:relative;vertical-align:middle;width:1px}.el-divider__text{background-color:var(--el-bg-color);color:var(--el-text-color-primary);font-size:14px;font-weight:500;padding:0 20px;position:absolute}.el-divider__text.is-left{left:20px;transform:translateY(-50%)}.el-divider__text.is-center{left:50%;transform:translate(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;transform:translateY(-50%)}.el-drawer{--el-drawer-bg-color:var(--el-dialog-bg-color,var(--el-bg-color));--el-drawer-padding-primary:var(--el-dialog-padding-primary,20px);background-color:var(--el-drawer-bg-color);box-shadow:var(--el-box-shadow-dark);box-sizing:border-box;display:flex;flex-direction:column;overflow:hidden;position:absolute;transition:all var(--el-transition-duration)}.el-drawer .btt,.el-drawer .ltr,.el-drawer .rtl,.el-drawer .ttb{transform:translate(0)}.el-drawer__sr-focus:focus{outline:none!important}.el-drawer__header{align-items:center;color:#72767b;display:flex;margin-bottom:32px;padding:var(--el-drawer-padding-primary);padding-bottom:0}.el-drawer__header>:first-child{flex:1}.el-drawer__title{flex:1;font-size:16px;line-height:inherit;margin:0}.el-drawer__footer{padding:var(--el-drawer-padding-primary);padding-top:10px;text-align:right}.el-drawer__close-btn{background-color:transparent;border:none;color:inherit;cursor:pointer;display:inline-flex;font-size:var(--el-font-size-extra-large);outline:none}.el-drawer__close-btn:focus i,.el-drawer__close-btn:hover i{color:var(--el-color-primary)}.el-drawer__body{flex:1;overflow:auto;padding:var(--el-drawer-padding-primary)}.el-drawer__body>*{box-sizing:border-box}.el-drawer.ltr,.el-drawer.rtl{bottom:0;height:100%;top:0}.el-drawer.btt,.el-drawer.ttb{left:0;right:0;width:100%}.el-drawer.ltr{left:0}.el-drawer.rtl{right:0}.el-drawer.ttb{top:0}.el-drawer.btt{bottom:0}.el-drawer-fade-enter-active,.el-drawer-fade-leave-active{transition:all var(--el-transition-duration)}.el-drawer-fade-enter-active,.el-drawer-fade-enter-from,.el-drawer-fade-enter-to,.el-drawer-fade-leave-active,.el-drawer-fade-leave-from,.el-drawer-fade-leave-to{overflow:hidden!important}.el-drawer-fade-enter-from,.el-drawer-fade-leave-to{opacity:0}.el-drawer-fade-enter-to,.el-drawer-fade-leave-from{opacity:1}.el-drawer-fade-enter-from .rtl,.el-drawer-fade-leave-to .rtl{transform:translate(100%)}.el-drawer-fade-enter-from .ltr,.el-drawer-fade-leave-to .ltr{transform:translate(-100%)}.el-drawer-fade-enter-from .ttb,.el-drawer-fade-leave-to .ttb{transform:translateY(-100%)}.el-drawer-fade-enter-from .btt,.el-drawer-fade-leave-to .btt{transform:translateY(100%)}.el-dropdown{--el-dropdown-menu-box-shadow:var(--el-box-shadow-light);--el-dropdown-menuItem-hover-fill:var(--el-color-primary-light-9);--el-dropdown-menuItem-hover-color:var(--el-color-primary);--el-dropdown-menu-index:10;color:var(--el-text-color-regular);display:inline-flex;font-size:var(--el-font-size-base);line-height:1;position:relative;vertical-align:top}.el-dropdown.is-disabled{color:var(--el-text-color-placeholder);cursor:not-allowed}.el-dropdown__popper{--el-dropdown-menu-box-shadow:var(--el-box-shadow-light);--el-dropdown-menuItem-hover-fill:var(--el-color-primary-light-9);--el-dropdown-menuItem-hover-color:var(--el-color-primary);--el-dropdown-menu-index:10}.el-dropdown__popper.el-popper{background:var(--el-bg-color-overlay);box-shadow:var(--el-dropdown-menu-box-shadow)}.el-dropdown__popper.el-popper,.el-dropdown__popper.el-popper .el-popper__arrow:before{border:1px solid var(--el-border-color-light)}.el-dropdown__popper.el-popper[data-popper-placement^=top] .el-popper__arrow:before{border-left-color:transparent;border-top-color:transparent}.el-dropdown__popper.el-popper[data-popper-placement^=bottom] .el-popper__arrow:before{border-bottom-color:transparent;border-right-color:transparent}.el-dropdown__popper.el-popper[data-popper-placement^=left] .el-popper__arrow:before{border-bottom-color:transparent;border-left-color:transparent}.el-dropdown__popper.el-popper[data-popper-placement^=right] .el-popper__arrow:before{border-right-color:transparent;border-top-color:transparent}.el-dropdown__popper .el-dropdown-menu{border:none}.el-dropdown__popper .el-dropdown__popper-selfdefine{outline:none}.el-dropdown__popper .el-scrollbar__bar{z-index:calc(var(--el-dropdown-menu-index) + 1)}.el-dropdown__popper .el-dropdown__list{box-sizing:border-box;list-style:none;margin:0;padding:0}.el-dropdown .el-dropdown__caret-button{align-items:center;border-left:none;display:inline-flex;justify-content:center;padding-left:0;padding-right:0;width:32px}.el-dropdown .el-dropdown__caret-button>span{display:inline-flex}.el-dropdown .el-dropdown__caret-button:before{background:var(--el-overlay-color-lighter);bottom:-1px;content:"";display:block;left:0;position:absolute;top:-1px;width:1px}.el-dropdown .el-dropdown__caret-button.el-button:before{background:var(--el-border-color);opacity:.5}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{font-size:inherit;padding-left:0}.el-dropdown .el-dropdown-selfdefine{outline:none}.el-dropdown--large .el-dropdown__caret-button{width:40px}.el-dropdown--small .el-dropdown__caret-button{width:24px}.el-dropdown-menu{background-color:var(--el-bg-color-overlay);border:none;border-radius:var(--el-border-radius-base);box-shadow:none;left:0;list-style:none;margin:0;padding:5px 0;position:relative;top:0;z-index:var(--el-dropdown-menu-index)}.el-dropdown-menu__item{align-items:center;color:var(--el-text-color-regular);cursor:pointer;display:flex;font-size:var(--el-font-size-base);line-height:22px;list-style:none;margin:0;outline:none;padding:5px 16px;white-space:nowrap}.el-dropdown-menu__item:not(.is-disabled):focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:var(--el-dropdown-menuItem-hover-fill);color:var(--el-dropdown-menuItem-hover-color)}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{border-top:1px solid var(--el-border-color-lighter);margin:6px 0}.el-dropdown-menu__item.is-disabled{color:var(--el-text-color-disabled);cursor:not-allowed}.el-dropdown-menu--large{padding:7px 0}.el-dropdown-menu--large .el-dropdown-menu__item{font-size:14px;line-height:22px;padding:7px 20px}.el-dropdown-menu--large .el-dropdown-menu__item--divided{margin:8px 0}.el-dropdown-menu--small{padding:3px 0}.el-dropdown-menu--small .el-dropdown-menu__item{font-size:12px;line-height:20px;padding:2px 12px}.el-dropdown-menu--small .el-dropdown-menu__item--divided{margin:4px 0}.el-empty{--el-empty-padding:40px 0;--el-empty-image-width:160px;--el-empty-description-margin-top:20px;--el-empty-bottom-margin-top:20px;--el-empty-fill-color-0:var(--el-color-white);--el-empty-fill-color-1:#fcfcfd;--el-empty-fill-color-2:#f8f9fb;--el-empty-fill-color-3:#f7f8fc;--el-empty-fill-color-4:#eeeff3;--el-empty-fill-color-5:#edeef2;--el-empty-fill-color-6:#e9ebef;--el-empty-fill-color-7:#e5e7e9;--el-empty-fill-color-8:#e0e3e9;--el-empty-fill-color-9:#d5d7de;align-items:center;box-sizing:border-box;display:flex;flex-direction:column;justify-content:center;padding:var(--el-empty-padding);text-align:center}.el-empty__image{width:var(--el-empty-image-width)}.el-empty__image img{height:100%;-o-object-fit:contain;object-fit:contain;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:top;width:100%}.el-empty__image svg{color:var(--el-svg-monochrome-grey);fill:currentColor;height:100%;vertical-align:top;width:100%}.el-empty__description{margin-top:var(--el-empty-description-margin-top)}.el-empty__description p{color:var(--el-text-color-secondary);font-size:var(--el-font-size-base);margin:0}.el-empty__bottom{margin-top:var(--el-empty-bottom-margin-top)}.el-footer{--el-footer-padding:0 20px;--el-footer-height:60px;box-sizing:border-box;flex-shrink:0;height:var(--el-footer-height);padding:var(--el-footer-padding)}.el-form{--el-form-label-font-size:var(--el-font-size-base);--el-form-inline-content-width:220px}.el-form--inline .el-form-item{display:inline-flex;margin-right:32px;vertical-align:middle}.el-form--inline.el-form--label-top{display:flex;flex-wrap:wrap}.el-form--inline.el-form--label-top .el-form-item{display:block}.el-form-item{display:flex;--font-size:14px;margin-bottom:18px}.el-form-item .el-form-item{margin-bottom:0}.el-form-item .el-input__validateIcon{display:none}.el-form-item--large{--font-size:14px;--el-form-label-font-size:var(--font-size);margin-bottom:22px}.el-form-item--large .el-form-item__label{height:40px;line-height:40px}.el-form-item--large .el-form-item__content{line-height:40px}.el-form-item--large .el-form-item__error{padding-top:4px}.el-form-item--default{--font-size:14px;--el-form-label-font-size:var(--font-size);margin-bottom:18px}.el-form-item--default .el-form-item__label{height:32px;line-height:32px}.el-form-item--default .el-form-item__content{line-height:32px}.el-form-item--default .el-form-item__error{padding-top:2px}.el-form-item--small{--font-size:12px;--el-form-label-font-size:var(--font-size);margin-bottom:18px}.el-form-item--small .el-form-item__label{height:24px;line-height:24px}.el-form-item--small .el-form-item__content{line-height:24px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--label-left .el-form-item__label{justify-content:flex-start}.el-form-item--label-top{display:block}.el-form-item--label-top .el-form-item__label{display:block;height:auto;line-height:22px;margin-bottom:8px;text-align:left}.el-form-item__label-wrap{display:flex}.el-form-item__label{align-items:flex-start;box-sizing:border-box;color:var(--el-text-color-regular);display:inline-flex;flex:0 0 auto;font-size:var(--el-form-label-font-size);height:32px;justify-content:flex-end;line-height:32px;padding:0 12px 0 0}.el-form-item__content{align-items:center;display:flex;flex:1;flex-wrap:wrap;font-size:var(--font-size);line-height:32px;min-width:0;position:relative}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:var(--el-color-danger);font-size:12px;left:0;line-height:1;padding-top:2px;position:absolute;top:100%}.el-form-item__error--inline{display:inline-block;left:auto;margin-left:10px;position:relative;top:auto}.el-form-item.is-required:not(.is-no-asterisk).asterisk-left>.el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk).asterisk-left>.el-form-item__label:before{color:var(--el-color-danger);content:"*";margin-right:4px}.el-form-item.is-required:not(.is-no-asterisk).asterisk-right>.el-form-item__label-wrap>.el-form-item__label:after,.el-form-item.is-required:not(.is-no-asterisk).asterisk-right>.el-form-item__label:after{color:var(--el-color-danger);content:"*";margin-left:4px}.el-form-item.is-error .el-input__wrapper,.el-form-item.is-error .el-input__wrapper.is-focus,.el-form-item.is-error .el-input__wrapper:focus,.el-form-item.is-error .el-input__wrapper:hover,.el-form-item.is-error .el-select__wrapper,.el-form-item.is-error .el-select__wrapper.is-focus,.el-form-item.is-error .el-select__wrapper:focus,.el-form-item.is-error .el-select__wrapper:hover,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner.is-focus,.el-form-item.is-error .el-textarea__inner:focus,.el-form-item.is-error .el-textarea__inner:hover{box-shadow:0 0 0 1px var(--el-color-danger) inset}.el-form-item.is-error .el-input-group__append .el-input__wrapper,.el-form-item.is-error .el-input-group__prepend .el-input__wrapper{box-shadow:inset 0 0 0 1px transparent}.el-form-item.is-error .el-input-group__append .el-input__validateIcon,.el-form-item.is-error .el-input-group__prepend .el-input__validateIcon{display:none}.el-form-item.is-error .el-input__validateIcon{color:var(--el-color-danger)}.el-form-item--feedback .el-input__validateIcon{display:inline-flex}.el-header{--el-header-padding:0 20px;--el-header-height:60px;box-sizing:border-box;flex-shrink:0;height:var(--el-header-height);padding:var(--el-header-padding)}.el-image-viewer__wrapper{bottom:0;left:0;position:fixed;right:0;top:0}.el-image-viewer__btn{align-items:center;border-radius:50%;box-sizing:border-box;cursor:pointer;display:flex;justify-content:center;opacity:.8;position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:1}.el-image-viewer__btn .el-icon{cursor:pointer;font-size:inherit}.el-image-viewer__close{font-size:40px;height:40px;right:40px;top:40px;width:40px}.el-image-viewer__canvas{align-items:center;display:flex;height:100%;justify-content:center;position:static;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.el-image-viewer__actions{background-color:var(--el-text-color-regular);border-color:#fff;border-radius:22px;bottom:30px;height:44px;left:50%;padding:0 23px;transform:translate(-50%);width:282px}.el-image-viewer__actions__inner{align-items:center;color:#fff;cursor:default;display:flex;font-size:23px;height:100%;justify-content:space-around;width:100%}.el-image-viewer__prev{left:40px}.el-image-viewer__next,.el-image-viewer__prev{background-color:var(--el-text-color-regular);border-color:#fff;color:#fff;font-size:24px;height:44px;top:50%;transform:translateY(-50%);width:44px}.el-image-viewer__next{right:40px;text-indent:2px}.el-image-viewer__close{background-color:var(--el-text-color-regular);border-color:#fff;color:#fff;font-size:24px;height:44px;width:44px}.el-image-viewer__mask{background:#000;height:100%;left:0;opacity:.5;position:absolute;top:0;width:100%}.viewer-fade-enter-active{animation:viewer-fade-in var(--el-transition-duration)}.viewer-fade-leave-active{animation:viewer-fade-out var(--el-transition-duration)}@keyframes viewer-fade-in{0%{opacity:0;transform:translate3d(0,-20px,0)}to{opacity:1;transform:translateZ(0)}}@keyframes viewer-fade-out{0%{opacity:1;transform:translateZ(0)}to{opacity:0;transform:translate3d(0,-20px,0)}}.el-image__error,.el-image__inner,.el-image__placeholder,.el-image__wrapper{height:100%;width:100%}.el-image{display:inline-block;overflow:hidden;position:relative}.el-image__inner{opacity:1;vertical-align:top}.el-image__inner.is-loading{opacity:0}.el-image__wrapper{left:0;position:absolute;top:0}.el-image__error,.el-image__placeholder{background:var(--el-fill-color-light)}.el-image__error{align-items:center;color:var(--el-text-color-placeholder);display:flex;font-size:14px;justify-content:center;vertical-align:middle}.el-image__preview{cursor:pointer}.el-textarea{--el-input-text-color:var(--el-text-color-regular);--el-input-border:var(--el-border);--el-input-hover-border:var(--el-border-color-hover);--el-input-focus-border:var(--el-color-primary);--el-input-transparent-border:0 0 0 1px transparent inset;--el-input-border-color:var(--el-border-color);--el-input-border-radius:var(--el-border-radius-base);--el-input-bg-color:var(--el-fill-color-blank);--el-input-icon-color:var(--el-text-color-placeholder);--el-input-placeholder-color:var(--el-text-color-placeholder);--el-input-hover-border-color:var(--el-border-color-hover);--el-input-clear-hover-color:var(--el-text-color-secondary);--el-input-focus-border-color:var(--el-color-primary);--el-input-width:100%;display:inline-block;font-size:var(--el-font-size-base);position:relative;vertical-align:bottom;width:100%}.el-textarea__inner{-webkit-appearance:none;background-color:var(--el-input-bg-color,var(--el-fill-color-blank));background-image:none;border:none;border-radius:var(--el-input-border-radius,var(--el-border-radius-base));box-shadow:0 0 0 1px var(--el-input-border-color,var(--el-border-color)) inset;box-sizing:border-box;color:var(--el-input-text-color,var(--el-text-color-regular));display:block;font-family:inherit;font-size:inherit;line-height:1.5;padding:5px 11px;position:relative;resize:vertical;transition:var(--el-transition-box-shadow);width:100%}.el-textarea__inner::-moz-placeholder{color:var(--el-input-placeholder-color,var(--el-text-color-placeholder))}.el-textarea__inner::placeholder{color:var(--el-input-placeholder-color,var(--el-text-color-placeholder))}.el-textarea__inner:hover{box-shadow:0 0 0 1px var(--el-input-hover-border-color) inset}.el-textarea__inner:focus{box-shadow:0 0 0 1px var(--el-input-focus-border-color) inset;outline:none}.el-textarea .el-input__count{background:var(--el-fill-color-blank);bottom:5px;color:var(--el-color-info);font-size:12px;line-height:14px;position:absolute;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:var(--el-disabled-bg-color);box-shadow:0 0 0 1px var(--el-disabled-border-color) inset;color:var(--el-disabled-text-color);cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-moz-placeholder{color:var(--el-text-color-placeholder)}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:var(--el-text-color-placeholder)}.el-textarea.is-exceed .el-textarea__inner{box-shadow:0 0 0 1px var(--el-color-danger) inset}.el-textarea.is-exceed .el-input__count{color:var(--el-color-danger)}.el-input{--el-input-text-color:var(--el-text-color-regular);--el-input-border:var(--el-border);--el-input-hover-border:var(--el-border-color-hover);--el-input-focus-border:var(--el-color-primary);--el-input-transparent-border:0 0 0 1px transparent inset;--el-input-border-color:var(--el-border-color);--el-input-border-radius:var(--el-border-radius-base);--el-input-bg-color:var(--el-fill-color-blank);--el-input-icon-color:var(--el-text-color-placeholder);--el-input-placeholder-color:var(--el-text-color-placeholder);--el-input-hover-border-color:var(--el-border-color-hover);--el-input-clear-hover-color:var(--el-text-color-secondary);--el-input-focus-border-color:var(--el-color-primary);--el-input-width:100%;--el-input-height:var(--el-component-size);box-sizing:border-box;display:inline-flex;font-size:var(--el-font-size-base);line-height:var(--el-input-height);position:relative;vertical-align:middle;width:var(--el-input-width)}.el-input::-webkit-scrollbar{width:6px;z-index:11}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{background:var(--el-text-color-disabled);border-radius:5px;width:6px}.el-input::-webkit-scrollbar-corner,.el-input::-webkit-scrollbar-track{background:var(--el-fill-color-blank)}.el-input::-webkit-scrollbar-track-piece{background:var(--el-fill-color-blank);width:6px}.el-input .el-input__clear,.el-input .el-input__password{color:var(--el-input-icon-color);cursor:pointer;font-size:14px}.el-input .el-input__clear:hover,.el-input .el-input__password:hover{color:var(--el-input-clear-hover-color)}.el-input .el-input__count{align-items:center;color:var(--el-color-info);display:inline-flex;font-size:12px;height:100%}.el-input .el-input__count .el-input__count-inner{background:var(--el-fill-color-blank);display:inline-block;line-height:normal;padding-left:8px}.el-input__wrapper{align-items:center;background-color:var(--el-input-bg-color,var(--el-fill-color-blank));background-image:none;border-radius:var(--el-input-border-radius,var(--el-border-radius-base));box-shadow:0 0 0 1px var(--el-input-border-color,var(--el-border-color)) inset;cursor:text;display:inline-flex;flex-grow:1;justify-content:center;padding:1px 11px;transform:translateZ(0);transition:var(--el-transition-box-shadow)}.el-input__wrapper:hover{box-shadow:0 0 0 1px var(--el-input-hover-border-color) inset}.el-input__wrapper.is-focus{box-shadow:0 0 0 1px var(--el-input-focus-border-color) inset}.el-input__inner{--el-input-inner-height:calc(var(--el-input-height, 32px) - 2px);-webkit-appearance:none;background:none;border:none;box-sizing:border-box;color:var(--el-input-text-color,var(--el-text-color-regular));flex-grow:1;font-size:inherit;height:var(--el-input-inner-height);line-height:var(--el-input-inner-height);outline:none;padding:0;width:100%}.el-input__inner:focus{outline:none}.el-input__inner::-moz-placeholder{color:var(--el-input-placeholder-color,var(--el-text-color-placeholder))}.el-input__inner::placeholder{color:var(--el-input-placeholder-color,var(--el-text-color-placeholder))}.el-input__inner[type=password]::-ms-reveal{display:none}.el-input__inner[type=number]{line-height:1}.el-input__prefix{color:var(--el-input-icon-color,var(--el-text-color-placeholder));display:inline-flex;flex-shrink:0;flex-wrap:nowrap;height:100%;pointer-events:none;text-align:center;transition:all var(--el-transition-duration);white-space:nowrap}.el-input__prefix-inner{align-items:center;display:inline-flex;justify-content:center;pointer-events:all}.el-input__prefix-inner>:last-child{margin-right:8px}.el-input__prefix-inner>:first-child,.el-input__prefix-inner>:first-child.el-input__icon{margin-left:0}.el-input__suffix{color:var(--el-input-icon-color,var(--el-text-color-placeholder));display:inline-flex;flex-shrink:0;flex-wrap:nowrap;height:100%;pointer-events:none;text-align:center;transition:all var(--el-transition-duration);white-space:nowrap}.el-input__suffix-inner{align-items:center;display:inline-flex;justify-content:center;pointer-events:all}.el-input__suffix-inner>:first-child{margin-left:8px}.el-input .el-input__icon{align-items:center;display:flex;height:inherit;justify-content:center;line-height:inherit;margin-left:8px;transition:all var(--el-transition-duration)}.el-input__validateIcon{pointer-events:none}.el-input.is-active .el-input__wrapper{box-shadow:0 0 0 1px var(--el-input-focus-color, ) inset}.el-input.is-disabled{cursor:not-allowed}.el-input.is-disabled .el-input__wrapper{background-color:var(--el-disabled-bg-color);box-shadow:0 0 0 1px var(--el-disabled-border-color) inset}.el-input.is-disabled .el-input__inner{color:var(--el-disabled-text-color);-webkit-text-fill-color:var(--el-disabled-text-color);cursor:not-allowed}.el-input.is-disabled .el-input__inner::-moz-placeholder{color:var(--el-text-color-placeholder)}.el-input.is-disabled .el-input__inner::placeholder{color:var(--el-text-color-placeholder)}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input.is-exceed .el-input__wrapper{box-shadow:0 0 0 1px var(--el-color-danger) inset}.el-input.is-exceed .el-input__suffix .el-input__count{color:var(--el-color-danger)}.el-input--large{--el-input-height:var(--el-component-size-large);font-size:14px}.el-input--large .el-input__wrapper{padding:1px 15px}.el-input--large .el-input__inner{--el-input-inner-height:calc(var(--el-input-height, 40px) - 2px)}.el-input--small{--el-input-height:var(--el-component-size-small);font-size:12px}.el-input--small .el-input__wrapper{padding:1px 7px}.el-input--small .el-input__inner{--el-input-inner-height:calc(var(--el-input-height, 24px) - 2px)}.el-input-group{align-items:stretch;display:inline-flex;width:100%}.el-input-group__append,.el-input-group__prepend{align-items:center;background-color:var(--el-fill-color-light);border-radius:var(--el-input-border-radius);color:var(--el-color-info);display:inline-flex;justify-content:center;min-height:100%;padding:0 20px;position:relative;white-space:nowrap}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:none}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:0 -20px}.el-input-group__append button.el-button,.el-input-group__append button.el-button:hover,.el-input-group__append div.el-select .el-select__wrapper,.el-input-group__append div.el-select:hover .el-select__wrapper,.el-input-group__prepend button.el-button,.el-input-group__prepend button.el-button:hover,.el-input-group__prepend div.el-select .el-select__wrapper,.el-input-group__prepend div.el-select:hover .el-select__wrapper{background-color:transparent;border-color:transparent;color:inherit}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-bottom-right-radius:0;border-right:0;border-top-right-radius:0;box-shadow:1px 0 0 0 var(--el-input-border-color) inset,0 1px 0 0 var(--el-input-border-color) inset,0 -1px 0 0 var(--el-input-border-color) inset}.el-input-group__append{border-left:0;box-shadow:0 1px 0 0 var(--el-input-border-color) inset,0 -1px 0 0 var(--el-input-border-color) inset,-1px 0 0 0 var(--el-input-border-color) inset}.el-input-group--prepend>.el-input__wrapper,.el-input-group__append{border-bottom-left-radius:0;border-top-left-radius:0}.el-input-group--prepend .el-input-group__prepend .el-select .el-select__wrapper{border-bottom-right-radius:0;border-top-right-radius:0;box-shadow:1px 0 0 0 var(--el-input-border-color) inset,0 1px 0 0 var(--el-input-border-color) inset,0 -1px 0 0 var(--el-input-border-color) inset}.el-input-group--append>.el-input__wrapper{border-bottom-right-radius:0;border-top-right-radius:0}.el-input-group--append .el-input-group__append .el-select .el-select__wrapper{border-bottom-left-radius:0;border-top-left-radius:0;box-shadow:0 1px 0 0 var(--el-input-border-color) inset,0 -1px 0 0 var(--el-input-border-color) inset,-1px 0 0 0 var(--el-input-border-color) inset}.el-input-hidden{display:none!important}.el-input-number{display:inline-flex;line-height:30px;position:relative;width:150px}.el-input-number .el-input__wrapper{padding-left:42px;padding-right:42px}.el-input-number .el-input__inner{-webkit-appearance:none;-moz-appearance:textfield;line-height:1;text-align:center}.el-input-number .el-input__inner::-webkit-inner-spin-button,.el-input-number .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-input-number__decrease,.el-input-number__increase{align-items:center;background:var(--el-fill-color-light);bottom:1px;color:var(--el-text-color-regular);cursor:pointer;display:flex;font-size:13px;height:auto;justify-content:center;position:absolute;top:1px;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:32px;z-index:1}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:var(--el-color-primary)}.el-input-number__decrease:hover~.el-input:not(.is-disabled) .el-input__wrapper,.el-input-number__increase:hover~.el-input:not(.is-disabled) .el-input__wrapper{box-shadow:0 0 0 1px var(--el-input-focus-border-color,var(--el-color-primary)) inset}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:var(--el-disabled-text-color);cursor:not-allowed}.el-input-number__increase{border-left:var(--el-border);border-radius:0 var(--el-border-radius-base) var(--el-border-radius-base) 0;right:1px}.el-input-number__decrease{border-radius:var(--el-border-radius-base) 0 0 var(--el-border-radius-base);border-right:var(--el-border);left:1px}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:var(--el-disabled-border-color);color:var(--el-disabled-border-color)}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:var(--el-disabled-border-color);cursor:not-allowed}.el-input-number--large{line-height:38px;width:180px}.el-input-number--large .el-input-number__decrease,.el-input-number--large .el-input-number__increase{font-size:14px;width:40px}.el-input-number--large .el-input--large .el-input__wrapper{padding-left:47px;padding-right:47px}.el-input-number--small{line-height:22px;width:120px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{font-size:12px;width:24px}.el-input-number--small .el-input--small .el-input__wrapper{padding-left:31px;padding-right:31px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{transform:scale(.9)}.el-input-number.is-without-controls .el-input__wrapper{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__wrapper{padding-left:15px;padding-right:42px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{--el-input-number-controls-height:15px;height:var(--el-input-number-controls-height);line-height:var(--el-input-number-controls-height)}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-bottom:var(--el-border);border-radius:0 var(--el-border-radius-base) 0 0;bottom:auto;left:auto}.el-input-number.is-controls-right .el-input-number__decrease{border-left:var(--el-border);border-radius:0 0 var(--el-border-radius-base) 0;border-right:none;left:auto;right:1px;top:auto}.el-input-number.is-controls-right[class*=large] [class*=decrease],.el-input-number.is-controls-right[class*=large] [class*=increase]{--el-input-number-controls-height:19px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{--el-input-number-controls-height:11px}.el-link{--el-link-font-size:var(--el-font-size-base);--el-link-font-weight:var(--el-font-weight-primary);--el-link-text-color:var(--el-text-color-regular);--el-link-hover-text-color:var(--el-color-primary);--el-link-disabled-text-color:var(--el-text-color-placeholder);align-items:center;color:var(--el-link-text-color);cursor:pointer;display:inline-flex;flex-direction:row;font-size:var(--el-link-font-size);font-weight:var(--el-link-font-weight);justify-content:center;outline:none;padding:0;position:relative;text-decoration:none;vertical-align:middle}.el-link:hover{color:var(--el-link-hover-text-color)}.el-link.is-underline:hover:after{border-bottom:1px solid var(--el-link-hover-text-color);bottom:0;content:"";height:0;left:0;position:absolute;right:0}.el-link.is-disabled{color:var(--el-link-disabled-text-color);cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default:after{border-color:var(--el-link-hover-text-color)}.el-link__inner{align-items:center;display:inline-flex;justify-content:center}.el-link.el-link--primary{--el-link-text-color:var(--el-color-primary);--el-link-hover-text-color:var(--el-color-primary-light-3);--el-link-disabled-text-color:var(--el-color-primary-light-5)}.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:var(--el-link-text-color)}.el-link.el-link--success{--el-link-text-color:var(--el-color-success);--el-link-hover-text-color:var(--el-color-success-light-3);--el-link-disabled-text-color:var(--el-color-success-light-5)}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:var(--el-link-text-color)}.el-link.el-link--warning{--el-link-text-color:var(--el-color-warning);--el-link-hover-text-color:var(--el-color-warning-light-3);--el-link-disabled-text-color:var(--el-color-warning-light-5)}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:var(--el-link-text-color)}.el-link.el-link--danger{--el-link-text-color:var(--el-color-danger);--el-link-hover-text-color:var(--el-color-danger-light-3);--el-link-disabled-text-color:var(--el-color-danger-light-5)}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:var(--el-link-text-color)}.el-link.el-link--error{--el-link-text-color:var(--el-color-error);--el-link-hover-text-color:var(--el-color-error-light-3);--el-link-disabled-text-color:var(--el-color-error-light-5)}.el-link.el-link--error.is-underline:hover:after,.el-link.el-link--error:after{border-color:var(--el-link-text-color)}.el-link.el-link--info{--el-link-text-color:var(--el-color-info);--el-link-hover-text-color:var(--el-color-info-light-3);--el-link-disabled-text-color:var(--el-color-info-light-5)}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:var(--el-link-text-color)}:root{--el-loading-spinner-size:42px;--el-loading-fullscreen-spinner-size:50px}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{background-color:var(--el-mask-color);bottom:0;left:0;margin:0;position:absolute;right:0;top:0;transition:opacity var(--el-transition-duration);z-index:2000}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:calc((0px - var(--el-loading-fullscreen-spinner-size))/2)}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:var(--el-loading-fullscreen-spinner-size);width:var(--el-loading-fullscreen-spinner-size)}.el-loading-spinner{margin-top:calc((0px - var(--el-loading-spinner-size))/2);position:absolute;text-align:center;top:50%;width:100%}.el-loading-spinner .el-loading-text{color:var(--el-color-primary);font-size:14px;margin:3px 0}.el-loading-spinner .circular{animation:loading-rotate 2s linear infinite;display:inline;height:var(--el-loading-spinner-size);width:var(--el-loading-spinner-size)}.el-loading-spinner .path{animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:var(--el-color-primary);stroke-linecap:round}.el-loading-spinner i{color:var(--el-color-primary)}.el-loading-fade-enter-from,.el-loading-fade-leave-to{opacity:0}@keyframes loading-rotate{to{transform:rotate(1turn)}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-main{--el-main-padding:20px;box-sizing:border-box;display:block;flex:1;flex-basis:auto;overflow:auto;padding:var(--el-main-padding)}:root{--el-menu-active-color:var(--el-color-primary);--el-menu-text-color:var(--el-text-color-primary);--el-menu-hover-text-color:var(--el-color-primary);--el-menu-bg-color:var(--el-fill-color-blank);--el-menu-hover-bg-color:var(--el-color-primary-light-9);--el-menu-item-height:56px;--el-menu-sub-item-height:calc(var(--el-menu-item-height) - 6px);--el-menu-horizontal-height:60px;--el-menu-horizontal-sub-item-height:36px;--el-menu-item-font-size:var(--el-font-size-base);--el-menu-item-hover-fill:var(--el-color-primary-light-9);--el-menu-border-color:var(--el-border-color);--el-menu-base-level-padding:20px;--el-menu-level-padding:20px;--el-menu-icon-width:24px}.el-menu{background-color:var(--el-menu-bg-color);border-right:1px solid var(--el-menu-border-color);box-sizing:border-box;list-style:none;margin:0;padding-left:0;position:relative}.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-menu-item,.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-menu-item-group__title,.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title{padding-left:calc(var(--el-menu-base-level-padding) + var(--el-menu-level)*var(--el-menu-level-padding));white-space:nowrap}.el-menu:not(.el-menu--collapse) .el-sub-menu__title{padding-right:calc(var(--el-menu-base-level-padding) + var(--el-menu-icon-width))}.el-menu--horizontal{border-right:none;display:flex;flex-wrap:nowrap;height:var(--el-menu-horizontal-height)}.el-menu--horizontal.el-menu--popup-container{height:unset}.el-menu--horizontal.el-menu{border-bottom:1px solid var(--el-menu-border-color)}.el-menu--horizontal>.el-menu-item{align-items:center;border-bottom:2px solid transparent;color:var(--el-menu-text-color);display:inline-flex;height:100%;justify-content:center;margin:0}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-sub-menu:focus,.el-menu--horizontal>.el-sub-menu:hover{outline:none}.el-menu--horizontal>.el-sub-menu:hover .el-sub-menu__title{color:var(--el-menu-hover-text-color)}.el-menu--horizontal>.el-sub-menu.is-active .el-sub-menu__title{border-bottom:2px solid var(--el-menu-active-color);color:var(--el-menu-active-color)}.el-menu--horizontal>.el-sub-menu .el-sub-menu__title{border-bottom:2px solid transparent;color:var(--el-menu-text-color);height:100%}.el-menu--horizontal>.el-sub-menu .el-sub-menu__title:hover{background-color:var(--el-menu-bg-color)}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-sub-menu__title{align-items:center;background-color:var(--el-menu-bg-color);color:var(--el-menu-text-color);display:flex;height:var(--el-menu-horizontal-sub-item-height);line-height:var(--el-menu-horizontal-sub-item-height);padding:0 10px}.el-menu--horizontal .el-menu .el-sub-menu__title{padding-right:40px}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-sub-menu.is-active>.el-sub-menu__title{color:var(--el-menu-active-color)}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{background-color:var(--el-menu-hover-bg-color);color:var(--el-menu-hover-text-color);outline:none}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid var(--el-menu-active-color);color:var(--el-menu-active-color)!important}.el-menu--collapse{width:calc(var(--el-menu-icon-width) + var(--el-menu-base-level-padding)*2)}.el-menu--collapse>.el-menu-item [class^=el-icon],.el-menu--collapse>.el-menu-item-group>ul>.el-sub-menu>.el-sub-menu__title [class^=el-icon],.el-menu--collapse>.el-sub-menu>.el-sub-menu__title [class^=el-icon]{margin:0;text-align:center;vertical-align:middle;width:var(--el-menu-icon-width)}.el-menu--collapse>.el-menu-item .el-sub-menu__icon-arrow,.el-menu--collapse>.el-menu-item-group>ul>.el-sub-menu>.el-sub-menu__title .el-sub-menu__icon-arrow,.el-menu--collapse>.el-sub-menu>.el-sub-menu__title .el-sub-menu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item-group>ul>.el-sub-menu>.el-sub-menu__title>span,.el-menu--collapse>.el-menu-item>span,.el-menu--collapse>.el-sub-menu>.el-sub-menu__title>span{display:inline-block;height:0;overflow:hidden;visibility:hidden;width:0}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-menu .el-sub-menu{min-width:200px}.el-menu--collapse .el-sub-menu.is-active .el-sub-menu__title{color:var(--el-menu-active-color)}.el-menu--popup{border:none;border-radius:var(--el-border-radius-small);box-shadow:var(--el-box-shadow-light);min-width:200px;padding:5px 0;z-index:100}.el-menu .el-icon{flex-shrink:0}.el-menu-item{align-items:center;box-sizing:border-box;color:var(--el-menu-text-color);cursor:pointer;display:flex;font-size:var(--el-menu-item-font-size);height:var(--el-menu-item-height);line-height:var(--el-menu-item-height);list-style:none;padding:0 var(--el-menu-base-level-padding);position:relative;transition:border-color var(--el-transition-duration),background-color var(--el-transition-duration),color var(--el-transition-duration);white-space:nowrap}.el-menu-item *{vertical-align:bottom}.el-menu-item i{color:inherit}.el-menu-item:focus,.el-menu-item:hover{outline:none}.el-menu-item:hover{background-color:var(--el-menu-hover-bg-color)}.el-menu-item.is-disabled{background:none!important;cursor:not-allowed;opacity:.25}.el-menu-item [class^=el-icon]{font-size:18px;margin-right:5px;text-align:center;vertical-align:middle;width:var(--el-menu-icon-width)}.el-menu-item.is-active{color:var(--el-menu-active-color)}.el-menu-item.is-active i{color:inherit}.el-menu-item .el-menu-tooltip__trigger{align-items:center;box-sizing:border-box;display:inline-flex;height:100%;left:0;padding:0 var(--el-menu-base-level-padding);position:absolute;top:0;width:100%}.el-sub-menu{list-style:none;margin:0;padding-left:0}.el-sub-menu__title{align-items:center;box-sizing:border-box;color:var(--el-menu-text-color);cursor:pointer;display:flex;font-size:var(--el-menu-item-font-size);height:var(--el-menu-item-height);line-height:var(--el-menu-item-height);list-style:none;padding:0 var(--el-menu-base-level-padding);position:relative;transition:border-color var(--el-transition-duration),background-color var(--el-transition-duration),color var(--el-transition-duration);white-space:nowrap}.el-sub-menu__title *{vertical-align:bottom}.el-sub-menu__title i{color:inherit}.el-sub-menu__title:focus,.el-sub-menu__title:hover{outline:none}.el-sub-menu__title.is-disabled{background:none!important;cursor:not-allowed;opacity:.25}.el-sub-menu__title:hover{background-color:var(--el-menu-hover-bg-color)}.el-sub-menu .el-menu{border:none}.el-sub-menu .el-menu-item{height:var(--el-menu-sub-item-height);line-height:var(--el-menu-sub-item-height)}.el-sub-menu__hide-arrow .el-sub-menu__icon-arrow{display:none!important}.el-sub-menu.is-active .el-sub-menu__title{border-bottom-color:var(--el-menu-active-color)}.el-sub-menu.is-disabled .el-menu-item,.el-sub-menu.is-disabled .el-sub-menu__title{background:none!important;cursor:not-allowed;opacity:.25}.el-sub-menu .el-icon{font-size:18px;margin-right:5px;text-align:center;vertical-align:middle;width:var(--el-menu-icon-width)}.el-sub-menu .el-icon.el-sub-menu__icon-more{margin-right:0!important}.el-sub-menu .el-sub-menu__icon-arrow{font-size:12px;margin-right:0;margin-top:-6px;position:absolute;right:var(--el-menu-base-level-padding);top:50%;transition:transform var(--el-transition-duration);width:inherit}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{color:var(--el-text-color-secondary);font-size:12px;line-height:normal;padding:7px 0 7px var(--el-menu-base-level-padding)}.horizontal-collapse-transition .el-sub-menu__title .el-sub-menu__icon-arrow{opacity:0;transition:var(--el-transition-duration-fast)}.el-message-box{--el-messagebox-title-color:var(--el-text-color-primary);--el-messagebox-width:420px;--el-messagebox-border-radius:4px;--el-messagebox-box-shadow:var(--el-box-shadow);--el-messagebox-font-size:var(--el-font-size-large);--el-messagebox-content-font-size:var(--el-font-size-base);--el-messagebox-content-color:var(--el-text-color-regular);--el-messagebox-error-font-size:12px;--el-messagebox-padding-primary:12px;--el-messagebox-font-line-height:var(--el-font-line-height-primary);backface-visibility:hidden;background-color:var(--el-bg-color);border-radius:var(--el-messagebox-border-radius);box-shadow:var(--el-messagebox-box-shadow);box-sizing:border-box;display:inline-block;font-size:var(--el-messagebox-font-size);max-width:var(--el-messagebox-width);overflow:hidden;overflow-wrap:break-word;padding:var(--el-messagebox-padding-primary);position:relative;text-align:left;vertical-align:middle;width:100%}.el-message-box:focus{outline:none!important}.el-overlay.is-message-box .el-overlay-message-box{bottom:0;left:0;overflow:auto;padding:16px;position:fixed;right:0;text-align:center;top:0}.el-overlay.is-message-box .el-overlay-message-box:after{content:"";display:inline-block;height:100%;vertical-align:middle;width:0}.el-message-box.is-draggable .el-message-box__header{cursor:move;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-message-box__header{padding-bottom:var(--el-messagebox-padding-primary)}.el-message-box__header.show-close{padding-right:calc(var(--el-messagebox-padding-primary) + var(--el-message-close-size, 16px))}.el-message-box__title{color:var(--el-messagebox-title-color);font-size:var(--el-messagebox-font-size);line-height:var(--el-messagebox-font-line-height)}.el-message-box__headerbtn{background:transparent;border:none;cursor:pointer;font-size:var(--el-message-close-size,16px);height:40px;outline:none;padding:0;position:absolute;right:0;top:0;width:40px}.el-message-box__headerbtn .el-message-box__close{color:var(--el-color-info);font-size:inherit}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:var(--el-color-primary)}.el-message-box__content{color:var(--el-messagebox-content-color);font-size:var(--el-messagebox-content-font-size)}.el-message-box__container{align-items:center;display:flex;gap:12px}.el-message-box__input{padding-top:12px}.el-message-box__input div.invalid>input,.el-message-box__input div.invalid>input:focus{border-color:var(--el-color-error)}.el-message-box__status{font-size:24px}.el-message-box__status.el-message-box-icon--success{--el-messagebox-color:var(--el-color-success);color:var(--el-messagebox-color)}.el-message-box__status.el-message-box-icon--info{--el-messagebox-color:var(--el-color-info);color:var(--el-messagebox-color)}.el-message-box__status.el-message-box-icon--warning{--el-messagebox-color:var(--el-color-warning);color:var(--el-messagebox-color)}.el-message-box__status.el-message-box-icon--error{--el-messagebox-color:var(--el-color-error);color:var(--el-messagebox-color)}.el-message-box__message{margin:0}.el-message-box__message p{line-height:var(--el-messagebox-font-line-height);margin:0}.el-message-box__errormsg{color:var(--el-color-error);font-size:var(--el-messagebox-error-font-size);line-height:var(--el-messagebox-font-line-height)}.el-message-box__btns{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-end;padding-top:var(--el-messagebox-padding-primary)}.el-message-box--center .el-message-box__title{align-items:center;display:flex;gap:6px;justify-content:center}.el-message-box--center .el-message-box__status{font-size:inherit}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__container{justify-content:center}.fade-in-linear-enter-active .el-overlay-message-box{animation:msgbox-fade-in var(--el-transition-duration)}.fade-in-linear-leave-active .el-overlay-message-box{animation:msgbox-fade-in var(--el-transition-duration) reverse}@keyframes msgbox-fade-in{0%{opacity:0;transform:translate3d(0,-20px,0)}to{opacity:1;transform:translateZ(0)}}.el-message{--el-message-bg-color:var(--el-color-info-light-9);--el-message-border-color:var(--el-border-color-lighter);--el-message-padding:11px 15px;--el-message-close-size:16px;--el-message-close-icon-color:var(--el-text-color-placeholder);--el-message-close-hover-color:var(--el-text-color-secondary);align-items:center;background-color:var(--el-message-bg-color);border-color:var(--el-message-border-color);border-radius:var(--el-border-radius-base);border-style:var(--el-border-style);border-width:var(--el-border-width);box-sizing:border-box;display:flex;gap:8px;left:50%;max-width:calc(100% - 32px);padding:var(--el-message-padding);position:fixed;top:20px;transform:translate(-50%);transition:opacity var(--el-transition-duration),transform .4s,top .4s;width:-moz-fit-content;width:fit-content}.el-message.is-center{justify-content:center}.el-message.is-plain{background-color:var(--el-bg-color-overlay);border-color:var(--el-bg-color-overlay);box-shadow:var(--el-box-shadow-light)}.el-message p{margin:0}.el-message--success{--el-message-bg-color:var(--el-color-success-light-9);--el-message-border-color:var(--el-color-success-light-8);--el-message-text-color:var(--el-color-success)}.el-message--success .el-message__content{color:var(--el-message-text-color);overflow-wrap:break-word}.el-message .el-message-icon--success{color:var(--el-message-text-color)}.el-message--info{--el-message-bg-color:var(--el-color-info-light-9);--el-message-border-color:var(--el-color-info-light-8);--el-message-text-color:var(--el-color-info)}.el-message--info .el-message__content{color:var(--el-message-text-color);overflow-wrap:break-word}.el-message .el-message-icon--info{color:var(--el-message-text-color)}.el-message--warning{--el-message-bg-color:var(--el-color-warning-light-9);--el-message-border-color:var(--el-color-warning-light-8);--el-message-text-color:var(--el-color-warning)}.el-message--warning .el-message__content{color:var(--el-message-text-color);overflow-wrap:break-word}.el-message .el-message-icon--warning{color:var(--el-message-text-color)}.el-message--error{--el-message-bg-color:var(--el-color-error-light-9);--el-message-border-color:var(--el-color-error-light-8);--el-message-text-color:var(--el-color-error)}.el-message--error .el-message__content{color:var(--el-message-text-color);overflow-wrap:break-word}.el-message .el-message-icon--error{color:var(--el-message-text-color)}.el-message .el-message__badge{position:absolute;right:-8px;top:-8px}.el-message__content{font-size:14px;line-height:1;padding:0}.el-message__content:focus{outline-width:0}.el-message .el-message__closeBtn{color:var(--el-message-close-icon-color);cursor:pointer;font-size:var(--el-message-close-size)}.el-message .el-message__closeBtn:focus{outline-width:0}.el-message .el-message__closeBtn:hover{color:var(--el-message-close-hover-color)}.el-message-fade-enter-from,.el-message-fade-leave-to{opacity:0;transform:translate(-50%,-100%)}.el-notification{--el-notification-width:330px;--el-notification-padding:14px 26px 14px 13px;--el-notification-radius:8px;--el-notification-shadow:var(--el-box-shadow-light);--el-notification-border-color:var(--el-border-color-lighter);--el-notification-icon-size:24px;--el-notification-close-font-size:var(--el-message-close-size,16px);--el-notification-group-margin-left:13px;--el-notification-group-margin-right:8px;--el-notification-content-font-size:var(--el-font-size-base);--el-notification-content-color:var(--el-text-color-regular);--el-notification-title-font-size:16px;--el-notification-title-color:var(--el-text-color-primary);--el-notification-close-color:var(--el-text-color-secondary);--el-notification-close-hover-color:var(--el-text-color-regular);background-color:var(--el-bg-color-overlay);border:1px solid var(--el-notification-border-color);border-radius:var(--el-notification-radius);box-shadow:var(--el-notification-shadow);box-sizing:border-box;display:flex;overflow:hidden;overflow-wrap:break-word;padding:var(--el-notification-padding);position:fixed;transition:opacity var(--el-transition-duration),transform var(--el-transition-duration),left var(--el-transition-duration),right var(--el-transition-duration),top .4s,bottom var(--el-transition-duration);width:var(--el-notification-width);z-index:9999}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:var(--el-notification-group-margin-left);margin-right:var(--el-notification-group-margin-right)}.el-notification__title{color:var(--el-notification-title-color);font-size:var(--el-notification-title-font-size);font-weight:700;line-height:var(--el-notification-icon-size);margin:0}.el-notification__content{color:var(--el-notification-content-color);font-size:var(--el-notification-content-font-size);line-height:24px;margin:6px 0 0}.el-notification__content p{margin:0}.el-notification .el-notification__icon{font-size:var(--el-notification-icon-size);height:var(--el-notification-icon-size);width:var(--el-notification-icon-size)}.el-notification .el-notification__closeBtn{color:var(--el-notification-close-color);cursor:pointer;font-size:var(--el-notification-close-font-size);position:absolute;right:15px;top:18px}.el-notification .el-notification__closeBtn:hover{color:var(--el-notification-close-hover-color)}.el-notification .el-notification--success{--el-notification-icon-color:var(--el-color-success);color:var(--el-notification-icon-color)}.el-notification .el-notification--info{--el-notification-icon-color:var(--el-color-info);color:var(--el-notification-icon-color)}.el-notification .el-notification--warning{--el-notification-icon-color:var(--el-color-warning);color:var(--el-notification-icon-color)}.el-notification .el-notification--error{--el-notification-icon-color:var(--el-color-error);color:var(--el-notification-icon-color)}.el-notification-fade-enter-from.right{right:0;transform:translate(100%)}.el-notification-fade-enter-from.left{left:0;transform:translate(-100%)}.el-notification-fade-leave-to{opacity:0}.el-overlay{background-color:var(--el-overlay-color-lighter);bottom:0;height:100%;left:0;overflow:auto;position:fixed;right:0;top:0;z-index:2000}.el-overlay .el-overlay-root{height:0}.el-page-header.is-contentful .el-page-header__main{border-top:1px solid var(--el-border-color-light);margin-top:16px}.el-page-header__header{align-items:center;display:flex;justify-content:space-between;line-height:24px}.el-page-header__left{align-items:center;display:flex;margin-right:40px;position:relative}.el-page-header__back{align-items:center;cursor:pointer;display:flex}.el-page-header__left .el-divider--vertical{margin:0 16px}.el-page-header__icon{align-items:center;display:flex;font-size:16px;margin-right:10px}.el-page-header__icon .el-icon{font-size:inherit}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{color:var(--el-text-color-primary);font-size:18px}.el-page-header__breadcrumb{margin-bottom:16px}.el-pagination{--el-pagination-font-size:14px;--el-pagination-bg-color:var(--el-fill-color-blank);--el-pagination-text-color:var(--el-text-color-primary);--el-pagination-border-radius:2px;--el-pagination-button-color:var(--el-text-color-primary);--el-pagination-button-width:32px;--el-pagination-button-height:32px;--el-pagination-button-disabled-color:var(--el-text-color-placeholder);--el-pagination-button-disabled-bg-color:var(--el-fill-color-blank);--el-pagination-button-bg-color:var(--el-fill-color);--el-pagination-hover-color:var(--el-color-primary);--el-pagination-font-size-small:12px;--el-pagination-button-width-small:24px;--el-pagination-button-height-small:24px;--el-pagination-button-width-large:40px;--el-pagination-button-height-large:40px;--el-pagination-item-gap:16px;align-items:center;color:var(--el-pagination-text-color);display:flex;font-size:var(--el-pagination-font-size);font-weight:400;white-space:nowrap}.el-pagination .el-input__inner{-moz-appearance:textfield;text-align:center}.el-pagination .el-select{width:128px}.el-pagination button{align-items:center;background:var(--el-pagination-bg-color);border:none;border-radius:var(--el-pagination-border-radius);box-sizing:border-box;color:var(--el-pagination-button-color);cursor:pointer;display:flex;font-size:var(--el-pagination-font-size);height:var(--el-pagination-button-height);justify-content:center;line-height:var(--el-pagination-button-height);min-width:var(--el-pagination-button-width);padding:0 4px;text-align:center}.el-pagination button *{pointer-events:none}.el-pagination button:focus{outline:none}.el-pagination button.is-active,.el-pagination button:hover{color:var(--el-pagination-hover-color)}.el-pagination button.is-active{cursor:default;font-weight:700}.el-pagination button.is-active.is-disabled{color:var(--el-text-color-secondary);font-weight:700}.el-pagination button.is-disabled,.el-pagination button:disabled{background-color:var(--el-pagination-button-disabled-bg-color);color:var(--el-pagination-button-disabled-color);cursor:not-allowed}.el-pagination button:focus-visible{outline:1px solid var(--el-pagination-hover-color);outline-offset:-1px}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700;width:inherit}.el-pagination>.is-first{margin-left:0!important}.el-pagination>.is-last{margin-right:0!important}.el-pagination .btn-prev{margin-left:var(--el-pagination-item-gap)}.el-pagination__sizes,.el-pagination__total{color:var(--el-text-color-regular);font-weight:400;margin-left:var(--el-pagination-item-gap)}.el-pagination__total[disabled=true]{color:var(--el-text-color-placeholder)}.el-pagination__jump{align-items:center;color:var(--el-text-color-regular);display:flex;font-weight:400;margin-left:var(--el-pagination-item-gap)}.el-pagination__jump[disabled=true]{color:var(--el-text-color-placeholder)}.el-pagination__goto{margin-right:8px}.el-pagination__editor{box-sizing:border-box;text-align:center}.el-pagination__editor.el-input{width:56px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination__classifier{margin-left:8px}.el-pagination__rightwrapper{align-items:center;display:flex;flex:1;justify-content:flex-end}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{background-color:var(--el-pagination-button-bg-color);margin:0 4px}.el-pagination.is-background .btn-next.is-active,.el-pagination.is-background .btn-prev.is-active,.el-pagination.is-background .el-pager li.is-active{background-color:var(--el-color-primary);color:var(--el-color-white)}.el-pagination.is-background .btn-next.is-disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.is-disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.is-disabled,.el-pagination.is-background .el-pager li:disabled{background-color:var(--el-disabled-bg-color);color:var(--el-text-color-placeholder)}.el-pagination.is-background .btn-next.is-disabled.is-active,.el-pagination.is-background .btn-next:disabled.is-active,.el-pagination.is-background .btn-prev.is-disabled.is-active,.el-pagination.is-background .btn-prev:disabled.is-active,.el-pagination.is-background .el-pager li.is-disabled.is-active,.el-pagination.is-background .el-pager li:disabled.is-active{background-color:var(--el-fill-color-dark);color:var(--el-text-color-secondary)}.el-pagination.is-background .btn-prev{margin-left:var(--el-pagination-item-gap)}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li{font-size:var(--el-pagination-font-size-small);height:var(--el-pagination-button-height-small);line-height:var(--el-pagination-button-height-small);min-width:var(--el-pagination-button-width-small)}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){font-size:var(--el-pagination-font-size-small)}.el-pagination--small .el-select{width:100px}.el-pagination--large .btn-next,.el-pagination--large .btn-prev,.el-pagination--large .el-pager li{height:var(--el-pagination-button-height-large);line-height:var(--el-pagination-button-height-large);min-width:var(--el-pagination-button-width-large)}.el-pagination--large .el-select .el-input{width:160px}.el-pager{font-size:0;list-style:none;margin:0;padding:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-pager,.el-pager li{align-items:center;display:flex}.el-pager li{background:var(--el-pagination-bg-color);border:none;border-radius:var(--el-pagination-border-radius);box-sizing:border-box;color:var(--el-pagination-button-color);cursor:pointer;font-size:var(--el-pagination-font-size);height:var(--el-pagination-button-height);justify-content:center;line-height:var(--el-pagination-button-height);min-width:var(--el-pagination-button-width);padding:0 4px;text-align:center}.el-pager li *{pointer-events:none}.el-pager li:focus{outline:none}.el-pager li.is-active,.el-pager li:hover{color:var(--el-pagination-hover-color)}.el-pager li.is-active{cursor:default;font-weight:700}.el-pager li.is-active.is-disabled{color:var(--el-text-color-secondary);font-weight:700}.el-pager li.is-disabled,.el-pager li:disabled{background-color:var(--el-pagination-button-disabled-bg-color);color:var(--el-pagination-button-disabled-color);cursor:not-allowed}.el-pager li:focus-visible{outline:1px solid var(--el-pagination-hover-color);outline-offset:-1px}.el-popconfirm__main{align-items:center;display:flex}.el-popconfirm__icon{margin-right:5px}.el-popconfirm__action{margin-top:8px;text-align:right}.el-popover{--el-popover-bg-color:var(--el-bg-color-overlay);--el-popover-font-size:var(--el-font-size-base);--el-popover-border-color:var(--el-border-color-lighter);--el-popover-padding:12px;--el-popover-padding-large:18px 20px;--el-popover-title-font-size:16px;--el-popover-title-text-color:var(--el-text-color-primary);--el-popover-border-radius:4px}.el-popover.el-popper{background:var(--el-popover-bg-color);border:1px solid var(--el-popover-border-color);border-radius:var(--el-popover-border-radius);box-shadow:var(--el-box-shadow-light);box-sizing:border-box;color:var(--el-text-color-regular);font-size:var(--el-popover-font-size);line-height:1.4;min-width:150px;overflow-wrap:break-word;padding:var(--el-popover-padding);z-index:var(--el-index-popper)}.el-popover.el-popper--plain{padding:var(--el-popover-padding-large)}.el-popover__title{color:var(--el-popover-title-text-color);font-size:var(--el-popover-title-font-size);line-height:1;margin-bottom:12px}.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing){outline-width:0}.el-popover.el-popper.is-dark{--el-popover-bg-color:var(--el-text-color-primary);--el-popover-border-color:var(--el-text-color-primary);--el-popover-title-text-color:var(--el-bg-color);color:var(--el-bg-color)}.el-popover.el-popper:focus,.el-popover.el-popper:focus:active{outline-width:0}.el-progress{align-items:center;display:flex;line-height:1;position:relative}.el-progress__text{color:var(--el-text-color-regular);font-size:14px;line-height:1;margin-left:5px;min-width:50px}.el-progress__text i{display:block;vertical-align:middle}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{left:0;margin:0;position:absolute;text-align:center;top:50%;transform:translateY(-50%);width:100%}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{display:inline-block;vertical-align:middle}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{display:block;margin-right:0;padding-right:0}.el-progress--text-inside .el-progress-bar{margin-right:0;padding-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:var(--el-color-success)}.el-progress.is-success .el-progress__text{color:var(--el-color-success)}.el-progress.is-warning .el-progress-bar__inner{background-color:var(--el-color-warning)}.el-progress.is-warning .el-progress__text{color:var(--el-color-warning)}.el-progress.is-exception .el-progress-bar__inner{background-color:var(--el-color-danger)}.el-progress.is-exception .el-progress__text{color:var(--el-color-danger)}.el-progress-bar{box-sizing:border-box;flex-grow:1}.el-progress-bar__outer{background-color:var(--el-border-color-lighter);border-radius:100px;height:6px;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{background-color:var(--el-color-primary);border-radius:100px;height:100%;left:0;line-height:1;position:absolute;text-align:right;top:0;transition:width .6s ease;white-space:nowrap}.el-progress-bar__inner:after{content:"";display:inline-block;height:100%;vertical-align:middle}.el-progress-bar__inner--indeterminate{animation:indeterminate 3s infinite;transform:translateZ(0)}.el-progress-bar__inner--striped{background-image:linear-gradient(45deg,rgba(0,0,0,.1) 25%,transparent 0,transparent 50%,rgba(0,0,0,.1) 0,rgba(0,0,0,.1) 75%,transparent 0,transparent);background-size:1.25em 1.25em}.el-progress-bar__inner--striped.el-progress-bar__inner--striped-flow{animation:striped-flow 3s linear infinite}.el-progress-bar__innerText{color:#fff;display:inline-block;font-size:12px;margin:0 5px;vertical-align:middle}@keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}@keyframes indeterminate{0%{left:-100%}to{left:100%}}@keyframes striped-flow{0%{background-position:-100%}to{background-position:100%}}.el-radio-button{--el-radio-button-checked-bg-color:var(--el-color-primary);--el-radio-button-checked-text-color:var(--el-color-white);--el-radio-button-checked-border-color:var(--el-color-primary);--el-radio-button-disabled-checked-fill:var(--el-border-color-extra-light)}.el-radio-button,.el-radio-button__inner{display:inline-block;outline:none;position:relative}.el-radio-button__inner{-webkit-appearance:none;background:var(--el-button-bg-color,var(--el-fill-color-blank));border:var(--el-border);border-left:0;border-radius:0;box-sizing:border-box;color:var(--el-button-text-color,var(--el-text-color-regular));cursor:pointer;font-size:var(--el-font-size-base);font-weight:var(--el-button-font-weight,var(--el-font-weight-primary));line-height:1;margin:0;padding:8px 15px;text-align:center;transition:var(--el-transition-all);-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;white-space:nowrap}.el-radio-button__inner.is-round{padding:8px 15px}.el-radio-button__inner:hover{color:var(--el-color-primary)}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:var(--el-border);border-radius:var(--el-border-radius-base) 0 0 var(--el-border-radius-base);box-shadow:none!important}.el-radio-button.is-active .el-radio-button__original-radio:not(:disabled)+.el-radio-button__inner{background-color:var(--el-radio-button-checked-bg-color,var(--el-color-primary));border-color:var(--el-radio-button-checked-border-color,var(--el-color-primary));box-shadow:-1px 0 0 0 var(--el-radio-button-checked-border-color,var(--el-color-primary));color:var(--el-radio-button-checked-text-color,var(--el-color-white))}.el-radio-button__original-radio{opacity:0;outline:none;position:absolute;z-index:-1}.el-radio-button__original-radio:focus-visible+.el-radio-button__inner{border-left:var(--el-border);border-left-color:var(--el-radio-button-checked-border-color,var(--el-color-primary));border-radius:var(--el-border-radius-base);box-shadow:none;outline:2px solid var(--el-radio-button-checked-border-color);outline-offset:1px;z-index:2}.el-radio-button__original-radio:disabled+.el-radio-button__inner{background-color:var(--el-button-disabled-bg-color,var(--el-fill-color-blank));background-image:none;border-color:var(--el-button-disabled-border-color,var(--el-border-color-light));box-shadow:none;color:var(--el-disabled-text-color);cursor:not-allowed}.el-radio-button__original-radio:disabled:checked+.el-radio-button__inner{background-color:var(--el-radio-button-disabled-checked-fill)}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 var(--el-border-radius-base) var(--el-border-radius-base) 0}.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:var(--el-border-radius-base)}.el-radio-button--large .el-radio-button__inner{border-radius:0;font-size:var(--el-font-size-base);padding:12px 19px}.el-radio-button--large .el-radio-button__inner.is-round{padding:12px 19px}.el-radio-button--small .el-radio-button__inner{border-radius:0;font-size:12px;padding:5px 11px}.el-radio-button--small .el-radio-button__inner.is-round{padding:5px 11px}.el-radio-group{align-items:center;display:inline-flex;flex-wrap:wrap;font-size:0}.el-radio{--el-radio-font-size:var(--el-font-size-base);--el-radio-text-color:var(--el-text-color-regular);--el-radio-font-weight:var(--el-font-weight-primary);--el-radio-input-height:14px;--el-radio-input-width:14px;--el-radio-input-border-radius:var(--el-border-radius-circle);--el-radio-input-bg-color:var(--el-fill-color-blank);--el-radio-input-border:var(--el-border);--el-radio-input-border-color:var(--el-border-color);--el-radio-input-border-color-hover:var(--el-color-primary);align-items:center;color:var(--el-radio-text-color);cursor:pointer;display:inline-flex;font-size:var(--el-font-size-base);font-weight:var(--el-radio-font-weight);height:32px;margin-right:32px;outline:none;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.el-radio.el-radio--large{height:40px}.el-radio.el-radio--small{height:24px}.el-radio.is-bordered{border:var(--el-border);border-radius:var(--el-border-radius-base);box-sizing:border-box;padding:0 15px 0 9px}.el-radio.is-bordered.is-checked{border-color:var(--el-color-primary)}.el-radio.is-bordered.is-disabled{border-color:var(--el-border-color-lighter);cursor:not-allowed}.el-radio.is-bordered.el-radio--large{border-radius:var(--el-border-radius-base);padding:0 19px 0 11px}.el-radio.is-bordered.el-radio--large .el-radio__label{font-size:var(--el-font-size-base)}.el-radio.is-bordered.el-radio--large .el-radio__inner{height:14px;width:14px}.el-radio.is-bordered.el-radio--small{border-radius:var(--el-border-radius-base);padding:0 11px 0 7px}.el-radio.is-bordered.el-radio--small .el-radio__label{font-size:12px}.el-radio.is-bordered.el-radio--small .el-radio__inner{height:12px;width:12px}.el-radio:last-child{margin-right:0}.el-radio__input{cursor:pointer;display:inline-flex;outline:none;position:relative;vertical-align:middle;white-space:nowrap}.el-radio__input.is-disabled .el-radio__inner{border-color:var(--el-disabled-border-color)}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled .el-radio__inner:after{background-color:var(--el-disabled-bg-color);cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:var(--el-disabled-bg-color);border-color:var(--el-disabled-border-color)}.el-radio__input.is-disabled.is-checked .el-radio__inner:after{background-color:var(--el-text-color-placeholder)}.el-radio__input.is-disabled+span.el-radio__label{color:var(--el-text-color-placeholder);cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{background:var(--el-color-primary);border-color:var(--el-color-primary)}.el-radio__input.is-checked .el-radio__inner:after{transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:var(--el-color-primary)}.el-radio__input.is-focus .el-radio__inner{border-color:var(--el-radio-input-border-color-hover)}.el-radio__inner{background-color:var(--el-radio-input-bg-color);border:var(--el-radio-input-border);border-radius:var(--el-radio-input-border-radius);box-sizing:border-box;cursor:pointer;display:inline-block;height:var(--el-radio-input-height);position:relative;width:var(--el-radio-input-width)}.el-radio__inner:hover{border-color:var(--el-radio-input-border-color-hover)}.el-radio__inner:after{background-color:var(--el-color-white);border-radius:var(--el-radio-input-border-radius);content:"";height:4px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:transform .15s ease-in;width:4px}.el-radio__original{bottom:0;left:0;margin:0;opacity:0;outline:none;position:absolute;right:0;top:0;z-index:-1}.el-radio__original:focus-visible+.el-radio__inner{border-radius:var(--el-radio-input-border-radius);outline:2px solid var(--el-radio-input-border-color-hover);outline-offset:1px}.el-radio:focus:not(:focus-visible):not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{box-shadow:0 0 2px 2px var(--el-radio-input-border-color-hover)}.el-radio__label{font-size:var(--el-radio-font-size);padding-left:8px}.el-radio.el-radio--large .el-radio__label{font-size:14px}.el-radio.el-radio--large .el-radio__inner{height:14px;width:14px}.el-radio.el-radio--small .el-radio__label{font-size:12px}.el-radio.el-radio--small .el-radio__inner{height:12px;width:12px}.el-rate{--el-rate-height:20px;--el-rate-font-size:var(--el-font-size-base);--el-rate-icon-size:18px;--el-rate-icon-margin:6px;--el-rate-void-color:var(--el-border-color-darker);--el-rate-fill-color:#f7ba2a;--el-rate-disabled-void-color:var(--el-fill-color);--el-rate-text-color:var(--el-text-color-primary);align-items:center;display:inline-flex;height:32px}.el-rate:active,.el-rate:focus{outline:none}.el-rate__item{color:var(--el-rate-void-color);cursor:pointer;display:inline-block;font-size:0;line-height:normal;position:relative;vertical-align:middle}.el-rate .el-rate__icon{display:inline-block;font-size:var(--el-rate-icon-size);margin-right:var(--el-rate-icon-margin);position:relative;transition:var(--el-transition-duration)}.el-rate .el-rate__icon.hover{transform:scale(1.15)}.el-rate .el-rate__icon .path2{left:0;position:absolute;top:0}.el-rate .el-rate__icon.is-active{color:var(--el-rate-fill-color)}.el-rate__decimal{color:var(--el-rate-fill-color);display:inline-block;overflow:hidden}.el-rate__decimal,.el-rate__decimal--box{left:0;position:absolute;top:0}.el-rate__text{color:var(--el-rate-text-color);font-size:var(--el-rate-font-size);vertical-align:middle}.el-rate--large{height:40px}.el-rate--small{height:24px}.el-rate--small .el-rate__icon{font-size:14px}.el-rate.is-disabled .el-rate__item{color:var(--el-rate-disabled-void-color);cursor:auto}.el-result{--el-result-padding:40px 30px;--el-result-icon-font-size:64px;--el-result-title-font-size:20px;--el-result-title-margin-top:20px;--el-result-subtitle-margin-top:10px;--el-result-extra-margin-top:30px;align-items:center;box-sizing:border-box;display:flex;flex-direction:column;justify-content:center;padding:var(--el-result-padding);text-align:center}.el-result__icon svg{height:var(--el-result-icon-font-size);width:var(--el-result-icon-font-size)}.el-result__title{margin-top:var(--el-result-title-margin-top)}.el-result__title p{color:var(--el-text-color-primary);font-size:var(--el-result-title-font-size);line-height:1.3;margin:0}.el-result__subtitle{margin-top:var(--el-result-subtitle-margin-top)}.el-result__subtitle p{color:var(--el-text-color-regular);font-size:var(--el-font-size-base);line-height:1.3;margin:0}.el-result__extra{margin-top:var(--el-result-extra-margin-top)}.el-result .icon-primary{--el-result-color:var(--el-color-primary);color:var(--el-result-color)}.el-result .icon-success{--el-result-color:var(--el-color-success);color:var(--el-result-color)}.el-result .icon-warning{--el-result-color:var(--el-color-warning);color:var(--el-result-color)}.el-result .icon-danger{--el-result-color:var(--el-color-danger);color:var(--el-result-color)}.el-result .icon-error{--el-result-color:var(--el-color-error);color:var(--el-result-color)}.el-result .icon-info{--el-result-color:var(--el-color-info);color:var(--el-result-color)}.el-row{box-sizing:border-box;display:flex;flex-wrap:wrap;position:relative}.el-row.is-justify-center{justify-content:center}.el-row.is-justify-end{justify-content:flex-end}.el-row.is-justify-space-between{justify-content:space-between}.el-row.is-justify-space-around{justify-content:space-around}.el-row.is-justify-space-evenly{justify-content:space-evenly}.el-row.is-align-top{align-items:flex-start}.el-row.is-align-middle{align-items:center}.el-row.is-align-bottom{align-items:flex-end}.el-scrollbar{--el-scrollbar-opacity:.3;--el-scrollbar-bg-color:var(--el-text-color-secondary);--el-scrollbar-hover-opacity:.5;--el-scrollbar-hover-bg-color:var(--el-text-color-secondary);height:100%;overflow:hidden;position:relative}.el-scrollbar__wrap{height:100%;overflow:auto}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{display:none}.el-scrollbar__thumb{background-color:var(--el-scrollbar-bg-color,var(--el-text-color-secondary));border-radius:inherit;cursor:pointer;display:block;height:0;opacity:var(--el-scrollbar-opacity,.3);position:relative;transition:var(--el-transition-duration) background-color;width:0}.el-scrollbar__thumb:hover{background-color:var(--el-scrollbar-hover-bg-color,var(--el-text-color-secondary));opacity:var(--el-scrollbar-hover-opacity,.5)}.el-scrollbar__bar{border-radius:4px;bottom:2px;position:absolute;right:2px;z-index:1}.el-scrollbar__bar.is-vertical{top:2px;width:6px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-scrollbar-fade-enter-active{transition:opacity .34s ease-out}.el-scrollbar-fade-leave-active{transition:opacity .12s ease-out}.el-scrollbar-fade-enter-from,.el-scrollbar-fade-leave-active{opacity:0}.el-select-dropdown{border-radius:var(--el-border-radius-base);box-sizing:border-box;z-index:calc(var(--el-index-top) + 1)}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty,.el-select-dropdown__loading{color:var(--el-text-color-secondary);font-size:var(--el-select-font-size);margin:0;padding:10px 0;text-align:center}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{box-sizing:border-box;list-style:none;margin:0;padding:6px 0}.el-select-dropdown__list.el-vl__window{margin:6px 0;padding:0}.el-select-dropdown__header{border-bottom:1px solid var(--el-border-color-light);padding:10px}.el-select-dropdown__footer{border-top:1px solid var(--el-border-color-light);padding:10px}.el-select-dropdown__item{box-sizing:border-box;color:var(--el-text-color-regular);cursor:pointer;font-size:var(--el-font-size-base);height:34px;line-height:34px;overflow:hidden;padding:0 32px 0 20px;position:relative;text-overflow:ellipsis;white-space:nowrap}.el-select-dropdown__item.is-hovering{background-color:var(--el-fill-color-light)}.el-select-dropdown__item.is-selected{color:var(--el-color-primary);font-weight:700}.el-select-dropdown__item.is-disabled{background-color:unset;color:var(--el-text-color-placeholder);cursor:not-allowed}.el-select-dropdown.is-multiple .el-select-dropdown__item.is-selected:after{background-color:var(--el-color-primary);background-position:50%;background-repeat:no-repeat;border-right:none;border-top:none;content:"";height:12px;mask:url("data:image/svg+xml;utf8,%3Csvg class='icon' width='200' height='200' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='currentColor' d='M406.656 706.944L195.84 496.256a32 32 0 10-45.248 45.248l256 256 512-512a32 32 0 00-45.248-45.248L406.592 706.944z'%3E%3C/path%3E%3C/svg%3E") no-repeat;mask-size:100% 100%;-webkit-mask:url("data:image/svg+xml;utf8,%3Csvg class='icon' width='200' height='200' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='currentColor' d='M406.656 706.944L195.84 496.256a32 32 0 10-45.248 45.248l256 256 512-512a32 32 0 00-45.248-45.248L406.592 706.944z'%3E%3C/path%3E%3C/svg%3E") no-repeat;-webkit-mask-size:100% 100%;position:absolute;right:20px;top:50%;transform:translateY(-50%);width:12px}.el-select-dropdown.is-multiple .el-select-dropdown__item.is-disabled:after{background-color:var(--el-text-color-placeholder)}.el-select-group{margin:0;padding:0}.el-select-group__wrap{list-style:none;margin:0;padding:0;position:relative}.el-select-group__title{color:var(--el-color-info);font-size:12px;line-height:34px;padding-left:20px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{--el-select-border-color-hover:var(--el-border-color-hover);--el-select-disabled-color:var(--el-disabled-text-color);--el-select-disabled-border:var(--el-disabled-border-color);--el-select-font-size:var(--el-font-size-base);--el-select-close-hover-color:var(--el-text-color-secondary);--el-select-input-color:var(--el-text-color-placeholder);--el-select-multiple-input-color:var(--el-text-color-regular);--el-select-input-focus-border-color:var(--el-color-primary);--el-select-input-font-size:14px;--el-select-width:100%;display:inline-block;position:relative;vertical-align:middle;width:var(--el-select-width)}.el-select__wrapper{align-items:center;background-color:var(--el-fill-color-blank);border-radius:var(--el-border-radius-base);box-shadow:0 0 0 1px var(--el-border-color) inset;box-sizing:border-box;cursor:pointer;display:flex;font-size:14px;gap:6px;line-height:24px;min-height:32px;padding:4px 12px;position:relative;text-align:left;transition:var(--el-transition-duration)}.el-select__wrapper:hover{box-shadow:0 0 0 1px var(--el-text-color) inset}.el-select__wrapper.is-filterable{cursor:text}.el-select__wrapper.is-focused{box-shadow:0 0 0 1px var(--el-color-primary) inset}.el-select__wrapper.is-hovering:not(.is-focused){box-shadow:0 0 0 1px var(--el-border-color-hover) inset}.el-select__wrapper.is-disabled{background-color:var(--el-fill-color-light);color:var(--el-text-color-placeholder);cursor:not-allowed}.el-select__wrapper.is-disabled,.el-select__wrapper.is-disabled:hover{box-shadow:0 0 0 1px var(--el-select-disabled-border) inset}.el-select__wrapper.is-disabled.is-focus{box-shadow:0 0 0 1px var(--el-input-focus-border-color) inset}.el-select__wrapper.is-disabled .el-select__selected-item{color:var(--el-select-disabled-color)}.el-select__wrapper.is-disabled .el-select__caret,.el-select__wrapper.is-disabled .el-tag{cursor:not-allowed}.el-select__prefix,.el-select__suffix{align-items:center;color:var(--el-input-icon-color,var(--el-text-color-placeholder));display:flex;flex-shrink:0;gap:6px}.el-select__caret{color:var(--el-select-input-color);cursor:pointer;font-size:var(--el-select-input-font-size);transform:rotate(0);transition:var(--el-transition-duration)}.el-select__caret.is-reverse{transform:rotate(180deg)}.el-select__selection{align-items:center;display:flex;flex:1;flex-wrap:wrap;gap:6px;min-width:0;position:relative}.el-select__selection.is-near{margin-left:-8px}.el-select__selection .el-tag{border-color:transparent;cursor:pointer}.el-select__selection .el-tag.el-tag--plain{border-color:var(--el-tag-border-color)}.el-select__selection .el-tag .el-tag__content{min-width:0}.el-select__selected-item{display:flex;flex-wrap:wrap;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-select__tags-text{line-height:normal}.el-select__placeholder,.el-select__tags-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.el-select__placeholder{color:var(--el-input-text-color,var(--el-text-color-regular));position:absolute;top:50%;transform:translateY(-50%);width:100%}.el-select__placeholder.is-transparent{color:var(--el-text-color-placeholder);-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-select__popper.el-popper{background:var(--el-bg-color-overlay);box-shadow:var(--el-box-shadow-light)}.el-select__popper.el-popper,.el-select__popper.el-popper .el-popper__arrow:before{border:1px solid var(--el-border-color-light)}.el-select__popper.el-popper[data-popper-placement^=top] .el-popper__arrow:before{border-left-color:transparent;border-top-color:transparent}.el-select__popper.el-popper[data-popper-placement^=bottom] .el-popper__arrow:before{border-bottom-color:transparent;border-right-color:transparent}.el-select__popper.el-popper[data-popper-placement^=left] .el-popper__arrow:before{border-bottom-color:transparent;border-left-color:transparent}.el-select__popper.el-popper[data-popper-placement^=right] .el-popper__arrow:before{border-right-color:transparent;border-top-color:transparent}.el-select__input-wrapper{max-width:100%}.el-select__input-wrapper.is-hidden{opacity:0;position:absolute}.el-select__input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:none;color:var(--el-select-multiple-input-color);font-family:inherit;font-size:inherit;height:24px;max-width:100%;outline:none;padding:0}.el-select__input.is-disabled{cursor:not-allowed}.el-select__input-calculator{left:0;max-width:100%;overflow:hidden;position:absolute;top:0;visibility:hidden;white-space:pre}.el-select--large .el-select__wrapper{font-size:14px;gap:6px;line-height:24px;min-height:40px;padding:8px 16px}.el-select--large .el-select__selection{gap:6px}.el-select--large .el-select__selection.is-near{margin-left:-8px}.el-select--large .el-select__prefix,.el-select--large .el-select__suffix{gap:6px}.el-select--large .el-select__input{height:24px}.el-select--small .el-select__wrapper{font-size:12px;gap:4px;line-height:20px;min-height:24px;padding:2px 8px}.el-select--small .el-select__selection{gap:4px}.el-select--small .el-select__selection.is-near{margin-left:-6px}.el-select--small .el-select__prefix,.el-select--small .el-select__suffix{gap:4px}.el-select--small .el-select__input{height:20px}.el-skeleton{--el-skeleton-circle-size:var(--el-avatar-size)}.el-skeleton__item{background:var(--el-skeleton-color);border-radius:var(--el-border-radius-base);display:inline-block;height:16px;width:100%}.el-skeleton__circle{border-radius:50%;height:var(--el-skeleton-circle-size);line-height:var(--el-skeleton-circle-size);width:var(--el-skeleton-circle-size)}.el-skeleton__button{border-radius:4px;height:40px;width:64px}.el-skeleton__p{width:100%}.el-skeleton__p.is-last{width:61%}.el-skeleton__p.is-first{width:33%}.el-skeleton__text{height:var(--el-font-size-small);width:100%}.el-skeleton__caption{height:var(--el-font-size-extra-small)}.el-skeleton__h1{height:var(--el-font-size-extra-large)}.el-skeleton__h3{height:var(--el-font-size-large)}.el-skeleton__h5{height:var(--el-font-size-medium)}.el-skeleton__image{align-items:center;border-radius:0;display:flex;justify-content:center;width:unset}.el-skeleton__image svg{color:var(--el-svg-monochrome-grey);fill:currentColor;height:22%;width:22%}.el-skeleton{--el-skeleton-color:var(--el-fill-color);--el-skeleton-to-color:var(--el-fill-color-darker)}@keyframes el-skeleton-loading{0%{background-position:100% 50%}to{background-position:0 50%}}.el-skeleton{width:100%}.el-skeleton__first-line,.el-skeleton__paragraph{background:var(--el-skeleton-color);height:16px;margin-top:16px}.el-skeleton.is-animated .el-skeleton__item{animation:el-skeleton-loading 1.4s ease infinite;background:linear-gradient(90deg,var(--el-skeleton-color) 25%,var(--el-skeleton-to-color) 37%,var(--el-skeleton-color) 63%);background-size:400% 100%}.el-slider{--el-slider-main-bg-color:var(--el-color-primary);--el-slider-runway-bg-color:var(--el-border-color-light);--el-slider-stop-bg-color:var(--el-color-white);--el-slider-disabled-color:var(--el-text-color-placeholder);--el-slider-border-radius:3px;--el-slider-height:6px;--el-slider-button-size:20px;--el-slider-button-wrapper-size:36px;--el-slider-button-wrapper-offset:-15px;align-items:center;display:flex;height:32px;width:100%}.el-slider__runway{background-color:var(--el-slider-runway-bg-color);border-radius:var(--el-slider-border-radius);cursor:pointer;flex:1;height:var(--el-slider-height);position:relative}.el-slider__runway.show-input{margin-right:30px;width:auto}.el-slider__runway.is-disabled{cursor:default}.el-slider__runway.is-disabled .el-slider__bar{background-color:var(--el-slider-disabled-color)}.el-slider__runway.is-disabled .el-slider__button{border-color:var(--el-slider-disabled-color)}.el-slider__runway.is-disabled .el-slider__button-wrapper.dragging,.el-slider__runway.is-disabled .el-slider__button-wrapper.hover,.el-slider__runway.is-disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.is-disabled .el-slider__button.dragging,.el-slider__runway.is-disabled .el-slider__button.hover,.el-slider__runway.is-disabled .el-slider__button:hover{transform:scale(1)}.el-slider__runway.is-disabled .el-slider__button.dragging,.el-slider__runway.is-disabled .el-slider__button.hover,.el-slider__runway.is-disabled .el-slider__button:hover{cursor:not-allowed}.el-slider__input{flex-shrink:0;width:130px}.el-slider__bar{background-color:var(--el-slider-main-bg-color);border-bottom-left-radius:var(--el-slider-border-radius);border-top-left-radius:var(--el-slider-border-radius);height:var(--el-slider-height);position:absolute}.el-slider__button-wrapper{background-color:transparent;height:var(--el-slider-button-wrapper-size);line-height:normal;outline:none;position:absolute;text-align:center;top:var(--el-slider-button-wrapper-offset);transform:translate(-50%);-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--el-slider-button-wrapper-size);z-index:1}.el-slider__button-wrapper:after{content:"";display:inline-block;height:100%;vertical-align:middle}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:grab}.el-slider__button-wrapper.dragging{cursor:grabbing}.el-slider__button{background-color:var(--el-color-white);border:2px solid var(--el-slider-main-bg-color);border-radius:50%;box-sizing:border-box;display:inline-block;height:var(--el-slider-button-size);transition:var(--el-transition-duration-fast);-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;width:var(--el-slider-button-size)}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:grab}.el-slider__button.dragging{cursor:grabbing}.el-slider__stop{background-color:var(--el-slider-stop-bg-color);border-radius:var(--el-border-radius-circle);height:var(--el-slider-height);position:absolute;transform:translate(-50%);width:var(--el-slider-height)}.el-slider__marks{height:100%;left:12px;top:0;width:18px}.el-slider__marks-text{color:var(--el-color-info);font-size:14px;margin-top:15px;position:absolute;transform:translate(-50%);white-space:pre}.el-slider.is-vertical{display:inline-flex;flex:0;height:100%;position:relative;width:auto}.el-slider.is-vertical .el-slider__runway{height:100%;margin:0 16px;width:var(--el-slider-height)}.el-slider.is-vertical .el-slider__bar{border-radius:0 0 3px 3px;height:auto;width:var(--el-slider-height)}.el-slider.is-vertical .el-slider__button-wrapper{left:var(--el-slider-button-wrapper-offset);top:auto;transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{transform:translateY(50%)}.el-slider.is-vertical .el-slider__marks-text{left:15px;margin-top:0;transform:translateY(50%)}.el-slider--large{height:40px}.el-slider--small{height:24px}.el-space{display:inline-flex;vertical-align:top}.el-space__item{display:flex;flex-wrap:wrap}.el-space__item>*{flex:1}.el-space--vertical{flex-direction:column}.el-time-spinner{white-space:nowrap;width:100%}.el-spinner{display:inline-block;vertical-align:middle}.el-spinner-inner{animation:rotate 2s linear infinite;height:50px;width:50px}.el-spinner-inner .path{stroke:var(--el-border-color-lighter);stroke-linecap:round;animation:dash 1.5s ease-in-out infinite}@keyframes rotate{to{transform:rotate(1turn)}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-step{flex-shrink:1;position:relative}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{flex-basis:auto!important;flex-grow:0;flex-shrink:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{border-color:var(--el-text-color-primary);color:var(--el-text-color-primary)}.el-step__head.is-wait{border-color:var(--el-text-color-placeholder);color:var(--el-text-color-placeholder)}.el-step__head.is-success{border-color:var(--el-color-success);color:var(--el-color-success)}.el-step__head.is-error{border-color:var(--el-color-danger);color:var(--el-color-danger)}.el-step__head.is-finish{border-color:var(--el-color-primary);color:var(--el-color-primary)}.el-step__icon{align-items:center;background:var(--el-bg-color);box-sizing:border-box;display:inline-flex;font-size:14px;height:24px;justify-content:center;position:relative;transition:.15s ease-out;width:24px;z-index:1}.el-step__icon.is-text{border:2px solid;border-color:inherit;border-radius:50%}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{color:inherit;display:inline-block;font-weight:700;line-height:1;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{transform:translateY(1px)}.el-step__line{background-color:var(--el-text-color-placeholder);border-color:inherit;position:absolute}.el-step__line-inner{border:1px solid;border-color:inherit;box-sizing:border-box;display:block;height:0;transition:.15s ease-out;width:0}.el-step__main{text-align:left;white-space:normal}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{color:var(--el-text-color-primary);font-weight:700}.el-step__title.is-wait{color:var(--el-text-color-placeholder)}.el-step__title.is-success{color:var(--el-color-success)}.el-step__title.is-error{color:var(--el-color-danger)}.el-step__title.is-finish{color:var(--el-color-primary)}.el-step__description{font-size:12px;font-weight:400;line-height:20px;margin-top:-5px;padding-right:10%}.el-step__description.is-process{color:var(--el-text-color-primary)}.el-step__description.is-wait{color:var(--el-text-color-placeholder)}.el-step__description.is-success{color:var(--el-color-success)}.el-step__description.is-error{color:var(--el-color-danger)}.el-step__description.is-finish{color:var(--el-color-primary)}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;left:0;right:0;top:11px}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{flex-grow:1;padding-left:10px}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{bottom:0;left:11px;top:0;width:2px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{align-items:center;display:flex}.el-step.is-simple .el-step__head{font-size:0;padding-right:10px;width:auto}.el-step.is-simple .el-step__icon{background:transparent;font-size:12px;height:16px;width:16px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{align-items:stretch;display:flex;flex-grow:1;position:relative}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;overflow-wrap:break-word}.el-step.is-simple .el-step__arrow{align-items:center;display:flex;flex-grow:1;justify-content:center}.el-step.is-simple .el-step__arrow:after,.el-step.is-simple .el-step__arrow:before{background:var(--el-text-color-placeholder);content:"";display:inline-block;height:15px;position:absolute;width:1px}.el-step.is-simple .el-step__arrow:before{transform:rotate(-45deg) translateY(-4px);transform-origin:0 0}.el-step.is-simple .el-step__arrow:after{transform:rotate(45deg) translateY(4px);transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-steps{display:flex}.el-steps--simple{background:var(--el-fill-color-light);border-radius:4px;padding:13px 8%}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{flex-flow:column;height:100%}.el-switch{--el-switch-on-color:var(--el-color-primary);--el-switch-off-color:var(--el-border-color);align-items:center;display:inline-flex;font-size:14px;height:32px;line-height:20px;position:relative;vertical-align:middle}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{color:var(--el-text-color-primary);cursor:pointer;display:inline-block;font-size:14px;font-weight:500;height:20px;transition:var(--el-transition-duration-fast);vertical-align:middle}.el-switch__label.is-active{color:var(--el-color-primary)}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{display:inline-block;font-size:14px;line-height:1}.el-switch__label .el-icon{height:inherit}.el-switch__label .el-icon svg{vertical-align:middle}.el-switch__input{height:0;margin:0;opacity:0;position:absolute;width:0}.el-switch__input:focus-visible~.el-switch__core{outline:2px solid var(--el-switch-on-color);outline-offset:1px}.el-switch__core{align-items:center;background:var(--el-switch-off-color);border:1px solid var(--el-switch-border-color,var(--el-switch-off-color));border-radius:10px;box-sizing:border-box;cursor:pointer;display:inline-flex;height:20px;min-width:40px;outline:none;position:relative;transition:border-color var(--el-transition-duration),background-color var(--el-transition-duration)}.el-switch__core .el-switch__inner{align-items:center;display:flex;height:16px;justify-content:center;overflow:hidden;padding:0 4px 0 18px;transition:all var(--el-transition-duration);width:100%}.el-switch__core .el-switch__inner .is-icon,.el-switch__core .el-switch__inner .is-text{color:var(--el-color-white);font-size:12px;overflow:hidden;text-overflow:ellipsis;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.el-switch__core .el-switch__action{align-items:center;background-color:var(--el-color-white);border-radius:var(--el-border-radius-circle);color:var(--el-switch-off-color);display:flex;height:16px;justify-content:center;left:1px;position:absolute;transition:all var(--el-transition-duration);width:16px}.el-switch.is-checked .el-switch__core{background-color:var(--el-switch-on-color);border-color:var(--el-switch-border-color,var(--el-switch-on-color))}.el-switch.is-checked .el-switch__core .el-switch__action{color:var(--el-switch-on-color);left:calc(100% - 17px)}.el-switch.is-checked .el-switch__core .el-switch__inner{padding:0 18px 0 4px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter-from,.el-switch .label-fade-leave-active{opacity:0}.el-switch--large{font-size:14px;height:40px;line-height:24px}.el-switch--large .el-switch__label{font-size:14px;height:24px}.el-switch--large .el-switch__label *{font-size:14px}.el-switch--large .el-switch__core{border-radius:12px;height:24px;min-width:50px}.el-switch--large .el-switch__core .el-switch__inner{height:20px;padding:0 6px 0 22px}.el-switch--large .el-switch__core .el-switch__action{height:20px;width:20px}.el-switch--large.is-checked .el-switch__core .el-switch__action{left:calc(100% - 21px)}.el-switch--large.is-checked .el-switch__core .el-switch__inner{padding:0 22px 0 6px}.el-switch--small{font-size:12px;height:24px;line-height:16px}.el-switch--small .el-switch__label{font-size:12px;height:16px}.el-switch--small .el-switch__label *{font-size:12px}.el-switch--small .el-switch__core{border-radius:8px;height:16px;min-width:30px}.el-switch--small .el-switch__core .el-switch__inner{height:12px;padding:0 2px 0 14px}.el-switch--small .el-switch__core .el-switch__action{height:12px;width:12px}.el-switch--small.is-checked .el-switch__core .el-switch__action{left:calc(100% - 13px)}.el-switch--small.is-checked .el-switch__core .el-switch__inner{padding:0 14px 0 2px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{background-color:#fff;border:1px solid var(--el-border-color-lighter);border-radius:2px;box-shadow:var(--el-box-shadow-light);box-sizing:border-box}.el-table-filter__list{list-style:none;margin:0;min-width:100px;padding:5px 0}.el-table-filter__list-item{cursor:pointer;font-size:var(--el-font-size-base);line-height:36px;padding:0 10px}.el-table-filter__list-item:hover{background-color:var(--el-color-primary-light-9);color:var(--el-color-primary)}.el-table-filter__list-item.is-active{background-color:var(--el-color-primary);color:#fff}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid var(--el-border-color-lighter);padding:8px}.el-table-filter__bottom button{background:transparent;border:none;color:var(--el-text-color-regular);cursor:pointer;font-size:var(--el-font-size-small);padding:0 3px}.el-table-filter__bottom button:hover{color:var(--el-color-primary)}.el-table-filter__bottom button:focus{outline:none}.el-table-filter__bottom button.is-disabled{color:var(--el-disabled-text-color);cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{align-items:center;display:flex;height:unset;margin-bottom:12px;margin-left:5px;margin-right:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-table{--el-table-border-color:var(--el-border-color-lighter);--el-table-border:1px solid var(--el-table-border-color);--el-table-text-color:var(--el-text-color-regular);--el-table-header-text-color:var(--el-text-color-secondary);--el-table-row-hover-bg-color:var(--el-fill-color-light);--el-table-current-row-bg-color:var(--el-color-primary-light-9);--el-table-header-bg-color:var(--el-bg-color);--el-table-fixed-box-shadow:var(--el-box-shadow-light);--el-table-bg-color:var(--el-fill-color-blank);--el-table-tr-bg-color:var(--el-bg-color);--el-table-expanded-cell-bg-color:var(--el-fill-color-blank);--el-table-fixed-left-column:inset 10px 0 10px -10px rgba(0,0,0,.15);--el-table-fixed-right-column:inset -10px 0 10px -10px rgba(0,0,0,.15);--el-table-index:var(--el-index-normal);background-color:var(--el-table-bg-color);box-sizing:border-box;color:var(--el-table-text-color);font-size:14px;height:-moz-fit-content;height:fit-content;max-width:100%;overflow:hidden;position:relative;width:100%}.el-table__inner-wrapper{display:flex;flex-direction:column;height:100%;position:relative}.el-table__inner-wrapper:before{bottom:0;height:1px;left:0}.el-table tbody:focus-visible{outline:none}.el-table.has-footer.el-table--fluid-height tr:last-child td.el-table__cell,.el-table.has-footer.el-table--scrollable-y tr:last-child td.el-table__cell{border-bottom-color:transparent}.el-table__empty-block{align-items:center;display:flex;justify-content:center;left:0;min-height:60px;position:sticky;text-align:center;width:100%}.el-table__empty-text{color:var(--el-text-color-secondary);line-height:60px;width:50%}.el-table__expand-column .cell{padding:0;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-table__expand-icon{color:var(--el-text-color-regular);cursor:pointer;font-size:12px;height:20px;position:relative;transition:transform var(--el-transition-duration-fast) ease-in-out}.el-table__expand-icon--expanded{transform:rotate(90deg)}.el-table__expand-icon>.el-icon{font-size:12px}.el-table__expanded-cell{background-color:var(--el-table-expanded-cell-bg-color)}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table__append-wrapper{overflow:hidden}.el-table--fit{border-bottom:0;border-right:0}.el-table--fit .el-table__cell.gutter{border-right-width:1px}.el-table--fit .el-table__inner-wrapper:before{width:100%}.el-table thead{color:var(--el-table-header-text-color)}.el-table thead th{font-weight:600}.el-table thead.is-group th.el-table__cell{background:var(--el-fill-color-light)}.el-table .el-table__cell{box-sizing:border-box;min-width:0;padding:8px 0;position:relative;text-align:left;text-overflow:ellipsis;vertical-align:middle;z-index:var(--el-table-index)}.el-table .el-table__cell.is-center{text-align:center}.el-table .el-table__cell.is-right{text-align:right}.el-table .el-table__cell.gutter{border-bottom-width:0;border-right-width:0;padding:0;width:15px}.el-table .el-table__cell.is-hidden>*{visibility:hidden}.el-table .cell{box-sizing:border-box;line-height:23px;overflow:hidden;overflow-wrap:break-word;padding:0 12px;text-overflow:ellipsis;white-space:normal}.el-table .cell.el-tooltip{min-width:50px;white-space:nowrap}.el-table--large{font-size:var(--el-font-size-base)}.el-table--large .el-table__cell{padding:12px 0}.el-table--large .cell{padding:0 16px}.el-table--default{font-size:14px}.el-table--default .el-table__cell{padding:8px 0}.el-table--default .cell{padding:0 12px}.el-table--small{font-size:12px}.el-table--small .el-table__cell{padding:4px 0}.el-table--small .cell{padding:0 8px}.el-table tr{background-color:var(--el-table-tr-bg-color)}.el-table tr input[type=checkbox]{margin:0}.el-table td.el-table__cell,.el-table th.el-table__cell.is-leaf{border-bottom:var(--el-table-border)}.el-table th.el-table__cell.is-sortable{cursor:pointer}.el-table th.el-table__cell{background-color:var(--el-table-header-bg-color)}.el-table th.el-table__cell>.cell.highlight{color:var(--el-color-primary)}.el-table th.el-table__cell.required>div:before{background:#ff4d51;border-radius:50%;content:"";display:inline-block;height:8px;margin-right:5px;vertical-align:middle;width:8px}.el-table td.el-table__cell div{box-sizing:border-box}.el-table td.el-table__cell.gutter{width:0}.el-table--border .el-table__inner-wrapper:after,.el-table--border:after,.el-table--border:before,.el-table__inner-wrapper:before{background-color:var(--el-table-border-color);content:"";position:absolute;z-index:calc(var(--el-table-index) + 2)}.el-table--border .el-table__inner-wrapper:after{height:1px;left:0;top:0;width:100%;z-index:calc(var(--el-table-index) + 2)}.el-table--border:before{height:100%;left:0;top:-1px;width:1px}.el-table--border:after{height:100%;right:0;top:-1px;width:1px}.el-table--border .el-table__inner-wrapper{border-bottom:none;border-right:none}.el-table--border .el-table__footer-wrapper{flex-shrink:0;position:relative}.el-table--border .el-table__cell{border-right:var(--el-table-border)}.el-table--border th.el-table__cell.gutter:last-of-type{border-bottom:var(--el-table-border);border-bottom-width:1px}.el-table--border th.el-table__cell{border-bottom:var(--el-table-border)}.el-table--hidden{visibility:hidden}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__body-wrapper tr td.el-table-fixed-column--left,.el-table__body-wrapper tr td.el-table-fixed-column--right,.el-table__body-wrapper tr th.el-table-fixed-column--left,.el-table__body-wrapper tr th.el-table-fixed-column--right,.el-table__footer-wrapper tr td.el-table-fixed-column--left,.el-table__footer-wrapper tr td.el-table-fixed-column--right,.el-table__footer-wrapper tr th.el-table-fixed-column--left,.el-table__footer-wrapper tr th.el-table-fixed-column--right,.el-table__header-wrapper tr td.el-table-fixed-column--left,.el-table__header-wrapper tr td.el-table-fixed-column--right,.el-table__header-wrapper tr th.el-table-fixed-column--left,.el-table__header-wrapper tr th.el-table-fixed-column--right{background:inherit;position:sticky!important;z-index:calc(var(--el-table-index) + 1)}.el-table__body-wrapper tr td.el-table-fixed-column--left.is-first-column:before,.el-table__body-wrapper tr td.el-table-fixed-column--left.is-last-column:before,.el-table__body-wrapper tr td.el-table-fixed-column--right.is-first-column:before,.el-table__body-wrapper tr td.el-table-fixed-column--right.is-last-column:before,.el-table__body-wrapper tr th.el-table-fixed-column--left.is-first-column:before,.el-table__body-wrapper tr th.el-table-fixed-column--left.is-last-column:before,.el-table__body-wrapper tr th.el-table-fixed-column--right.is-first-column:before,.el-table__body-wrapper tr th.el-table-fixed-column--right.is-last-column:before,.el-table__footer-wrapper tr td.el-table-fixed-column--left.is-first-column:before,.el-table__footer-wrapper tr td.el-table-fixed-column--left.is-last-column:before,.el-table__footer-wrapper tr td.el-table-fixed-column--right.is-first-column:before,.el-table__footer-wrapper tr td.el-table-fixed-column--right.is-last-column:before,.el-table__footer-wrapper tr th.el-table-fixed-column--left.is-first-column:before,.el-table__footer-wrapper tr th.el-table-fixed-column--left.is-last-column:before,.el-table__footer-wrapper tr th.el-table-fixed-column--right.is-first-column:before,.el-table__footer-wrapper tr th.el-table-fixed-column--right.is-last-column:before,.el-table__header-wrapper tr td.el-table-fixed-column--left.is-first-column:before,.el-table__header-wrapper tr td.el-table-fixed-column--left.is-last-column:before,.el-table__header-wrapper tr td.el-table-fixed-column--right.is-first-column:before,.el-table__header-wrapper tr td.el-table-fixed-column--right.is-last-column:before,.el-table__header-wrapper tr th.el-table-fixed-column--left.is-first-column:before,.el-table__header-wrapper tr th.el-table-fixed-column--left.is-last-column:before,.el-table__header-wrapper tr th.el-table-fixed-column--right.is-first-column:before,.el-table__header-wrapper tr th.el-table-fixed-column--right.is-last-column:before{bottom:-1px;box-shadow:none;content:"";overflow-x:hidden;overflow-y:hidden;pointer-events:none;position:absolute;top:0;touch-action:none;width:10px}.el-table__body-wrapper tr td.el-table-fixed-column--left.is-first-column:before,.el-table__body-wrapper tr td.el-table-fixed-column--right.is-first-column:before,.el-table__body-wrapper tr th.el-table-fixed-column--left.is-first-column:before,.el-table__body-wrapper tr th.el-table-fixed-column--right.is-first-column:before,.el-table__footer-wrapper tr td.el-table-fixed-column--left.is-first-column:before,.el-table__footer-wrapper tr td.el-table-fixed-column--right.is-first-column:before,.el-table__footer-wrapper tr th.el-table-fixed-column--left.is-first-column:before,.el-table__footer-wrapper tr th.el-table-fixed-column--right.is-first-column:before,.el-table__header-wrapper tr td.el-table-fixed-column--left.is-first-column:before,.el-table__header-wrapper tr td.el-table-fixed-column--right.is-first-column:before,.el-table__header-wrapper tr th.el-table-fixed-column--left.is-first-column:before,.el-table__header-wrapper tr th.el-table-fixed-column--right.is-first-column:before{left:-10px}.el-table__body-wrapper tr td.el-table-fixed-column--left.is-last-column:before,.el-table__body-wrapper tr td.el-table-fixed-column--right.is-last-column:before,.el-table__body-wrapper tr th.el-table-fixed-column--left.is-last-column:before,.el-table__body-wrapper tr th.el-table-fixed-column--right.is-last-column:before,.el-table__footer-wrapper tr td.el-table-fixed-column--left.is-last-column:before,.el-table__footer-wrapper tr td.el-table-fixed-column--right.is-last-column:before,.el-table__footer-wrapper tr th.el-table-fixed-column--left.is-last-column:before,.el-table__footer-wrapper tr th.el-table-fixed-column--right.is-last-column:before,.el-table__header-wrapper tr td.el-table-fixed-column--left.is-last-column:before,.el-table__header-wrapper tr td.el-table-fixed-column--right.is-last-column:before,.el-table__header-wrapper tr th.el-table-fixed-column--left.is-last-column:before,.el-table__header-wrapper tr th.el-table-fixed-column--right.is-last-column:before{box-shadow:none;right:-10px}.el-table__body-wrapper tr td.el-table__fixed-right-patch,.el-table__body-wrapper tr th.el-table__fixed-right-patch,.el-table__footer-wrapper tr td.el-table__fixed-right-patch,.el-table__footer-wrapper tr th.el-table__fixed-right-patch,.el-table__header-wrapper tr td.el-table__fixed-right-patch,.el-table__header-wrapper tr th.el-table__fixed-right-patch{background:#fff;position:sticky!important;right:0;z-index:calc(var(--el-table-index) + 1)}.el-table__header-wrapper{flex-shrink:0}.el-table__header-wrapper tr th.el-table-fixed-column--left,.el-table__header-wrapper tr th.el-table-fixed-column--right{background-color:var(--el-table-header-bg-color)}.el-table__body,.el-table__footer,.el-table__header{border-collapse:separate;table-layout:fixed}.el-table__header-wrapper{overflow:hidden}.el-table__header-wrapper tbody td.el-table__cell{background-color:var(--el-table-row-hover-bg-color);color:var(--el-table-text-color)}.el-table__footer-wrapper{flex-shrink:0;overflow:hidden}.el-table__footer-wrapper tfoot td.el-table__cell{background-color:var(--el-table-row-hover-bg-color);color:var(--el-table-text-color)}.el-table__body-wrapper .el-table-column--selection>.cell,.el-table__header-wrapper .el-table-column--selection>.cell{align-items:center;display:inline-flex;height:23px}.el-table__body-wrapper .el-table-column--selection .el-checkbox,.el-table__header-wrapper .el-table-column--selection .el-checkbox{height:unset}.el-table.is-scrolling-left .el-table-fixed-column--right.is-first-column:before{box-shadow:var(--el-table-fixed-right-column)}.el-table.is-scrolling-left.el-table--border .el-table-fixed-column--left.is-last-column.el-table__cell{border-right:var(--el-table-border)}.el-table.is-scrolling-left th.el-table-fixed-column--left{background-color:var(--el-table-header-bg-color)}.el-table.is-scrolling-right .el-table-fixed-column--left.is-last-column:before{box-shadow:var(--el-table-fixed-left-column)}.el-table.is-scrolling-right .el-table-fixed-column--left.is-last-column.el-table__cell{border-right:none}.el-table.is-scrolling-right th.el-table-fixed-column--right{background-color:var(--el-table-header-bg-color)}.el-table.is-scrolling-middle .el-table-fixed-column--left.is-last-column.el-table__cell{border-right:none}.el-table.is-scrolling-middle .el-table-fixed-column--right.is-first-column:before{box-shadow:var(--el-table-fixed-right-column)}.el-table.is-scrolling-middle .el-table-fixed-column--left.is-last-column:before{box-shadow:var(--el-table-fixed-left-column)}.el-table.is-scrolling-none .el-table-fixed-column--left.is-first-column:before,.el-table.is-scrolling-none .el-table-fixed-column--left.is-last-column:before,.el-table.is-scrolling-none .el-table-fixed-column--right.is-first-column:before,.el-table.is-scrolling-none .el-table-fixed-column--right.is-last-column:before{box-shadow:none}.el-table.is-scrolling-none th.el-table-fixed-column--left,.el-table.is-scrolling-none th.el-table-fixed-column--right{background-color:var(--el-table-header-bg-color)}.el-table__body-wrapper{flex:1;overflow:hidden;position:relative}.el-table__body-wrapper .el-scrollbar__bar{z-index:calc(var(--el-table-index) + 2)}.el-table .caret-wrapper{align-items:center;cursor:pointer;display:inline-flex;flex-direction:column;height:14px;overflow:initial;position:relative;vertical-align:middle;width:24px}.el-table .sort-caret{border:5px solid transparent;height:0;left:7px;position:absolute;width:0}.el-table .sort-caret.ascending{border-bottom-color:var(--el-text-color-placeholder);top:-5px}.el-table .sort-caret.descending{border-top-color:var(--el-text-color-placeholder);bottom:-3px}.el-table .ascending .sort-caret.ascending{border-bottom-color:var(--el-color-primary)}.el-table .descending .sort-caret.descending{border-top-color:var(--el-color-primary)}.el-table .hidden-columns{position:absolute;visibility:hidden;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell{background:var(--el-fill-color-lighter)}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td.el-table__cell{background-color:var(--el-table-current-row-bg-color)}.el-table__body tr.hover-row.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped>td.el-table__cell,.el-table__body tr.hover-row>td.el-table__cell,.el-table__body tr>td.hover-cell{background-color:var(--el-table-row-hover-bg-color)}.el-table__body tr.current-row>td.el-table__cell{background-color:var(--el-table-current-row-bg-color)}.el-table.el-table--scrollable-y .el-table__body-header{position:sticky;top:0;z-index:calc(var(--el-table-index) + 2)}.el-table.el-table--scrollable-y .el-table__body-footer{bottom:0;position:sticky;z-index:calc(var(--el-table-index) + 2)}.el-table__column-resize-proxy{border-left:var(--el-table-border);bottom:0;left:200px;position:absolute;top:0;width:0;z-index:calc(var(--el-table-index) + 9)}.el-table__column-filter-trigger{cursor:pointer;display:inline-block}.el-table__column-filter-trigger i{color:var(--el-color-info);font-size:14px;vertical-align:middle}.el-table__border-left-patch{height:100%;top:0;width:1px}.el-table__border-bottom-patch,.el-table__border-left-patch{background-color:var(--el-table-border-color);left:0;position:absolute;z-index:calc(var(--el-table-index) + 2)}.el-table__border-bottom-patch{height:1px}.el-table__border-right-patch{background-color:var(--el-table-border-color);height:100%;position:absolute;top:0;width:1px;z-index:calc(var(--el-table-index) + 2)}.el-table--enable-row-transition .el-table__body td.el-table__cell{transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell{background-color:var(--el-table-row-hover-bg-color)}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;height:12px;line-height:12px;margin-right:8px;text-align:center;width:12px}.el-table .el-table.el-table--border .el-table__cell{border-right:var(--el-table-border)}.el-table:not(.el-table--border) .el-table__cell{border-right:none}.el-table:not(.el-table--border)>.el-table__inner-wrapper:after{content:none}.el-table-v2{--el-table-border-color:var(--el-border-color-lighter);--el-table-border:1px solid var(--el-table-border-color);--el-table-text-color:var(--el-text-color-regular);--el-table-header-text-color:var(--el-text-color-secondary);--el-table-row-hover-bg-color:var(--el-fill-color-light);--el-table-current-row-bg-color:var(--el-color-primary-light-9);--el-table-header-bg-color:var(--el-bg-color);--el-table-fixed-box-shadow:var(--el-box-shadow-light);--el-table-bg-color:var(--el-fill-color-blank);--el-table-tr-bg-color:var(--el-bg-color);--el-table-expanded-cell-bg-color:var(--el-fill-color-blank);--el-table-fixed-left-column:inset 10px 0 10px -10px rgba(0,0,0,.15);--el-table-fixed-right-column:inset -10px 0 10px -10px rgba(0,0,0,.15);--el-table-index:var(--el-index-normal);font-size:14px}.el-table-v2 *{box-sizing:border-box}.el-table-v2__root{position:relative}.el-table-v2__root:hover .el-table-v2__main .el-virtual-scrollbar{opacity:1}.el-table-v2__main{background-color:var(--el-bg-color);display:flex;flex-direction:column-reverse;left:0;overflow:hidden;position:absolute;top:0}.el-table-v2__main .el-vl__horizontal,.el-table-v2__main .el-vl__vertical{z-index:2}.el-table-v2__left{background-color:var(--el-bg-color);box-shadow:2px 0 4px #0000000f;display:flex;flex-direction:column-reverse;left:0;overflow:hidden;position:absolute;top:0}.el-table-v2__left .el-virtual-scrollbar{opacity:0}.el-table-v2__left .el-vl__horizontal,.el-table-v2__left .el-vl__vertical{z-index:-1}.el-table-v2__right{background-color:var(--el-bg-color);box-shadow:-2px 0 4px #0000000f;display:flex;flex-direction:column-reverse;overflow:hidden;position:absolute;right:0;top:0}.el-table-v2__right .el-virtual-scrollbar{opacity:0}.el-table-v2__right .el-vl__horizontal,.el-table-v2__right .el-vl__vertical{z-index:-1}.el-table-v2__header-row,.el-table-v2__row{padding-inline-end:var(--el-table-scrollbar-size)}.el-table-v2__header-wrapper{overflow:hidden}.el-table-v2__header{overflow:hidden;position:relative}.el-table-v2__footer{bottom:0;overflow:hidden;right:0}.el-table-v2__empty,.el-table-v2__footer,.el-table-v2__overlay{left:0;position:absolute}.el-table-v2__overlay{bottom:0;right:0;top:0;z-index:9999}.el-table-v2__header-row{border-bottom:var(--el-table-border);display:flex}.el-table-v2__header-cell{align-items:center;background-color:var(--el-table-header-bg-color);color:var(--el-table-header-text-color);display:flex;font-weight:700;height:100%;overflow:hidden;padding:0 8px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-table-v2__header-cell.is-align-center{justify-content:center;text-align:center}.el-table-v2__header-cell.is-align-right{justify-content:flex-end;text-align:right}.el-table-v2__header-cell.is-sortable{cursor:pointer}.el-table-v2__header-cell:hover .el-icon{display:block}.el-table-v2__sort-icon{display:none;opacity:.6;transition:opacity,display var(--el-transition-duration)}.el-table-v2__sort-icon.is-sorting{display:block;opacity:1}.el-table-v2__row{align-items:center;border-bottom:var(--el-table-border);display:flex;transition:background-color var(--el-transition-duration)}.el-table-v2__row.is-hovered,.el-table-v2__row:hover{background-color:var(--el-table-row-hover-bg-color)}.el-table-v2__row-cell{align-items:center;display:flex;height:100%;overflow:hidden;padding:0 8px}.el-table-v2__row-cell.is-align-center{justify-content:center;text-align:center}.el-table-v2__row-cell.is-align-right{justify-content:flex-end;text-align:right}.el-table-v2__expand-icon{cursor:pointer;margin:0 4px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-table-v2__expand-icon svg{transition:transform var(--el-transition-duration)}.el-table-v2__expand-icon.is-expanded svg{transform:rotate(90deg)}.el-table-v2:not(.is-dynamic) .el-table-v2__cell-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.el-table-v2.is-dynamic .el-table-v2__row{align-items:stretch;overflow:hidden}.el-table-v2.is-dynamic .el-table-v2__row .el-table-v2__row-cell{overflow-wrap:break-word}.el-tabs{--el-tabs-header-height:40px}.el-tabs__header{align-items:center;display:flex;justify-content:space-between;margin:0 0 15px;padding:0;position:relative}.el-tabs__header-vertical{flex-direction:column}.el-tabs__active-bar{background-color:var(--el-color-primary);bottom:0;height:2px;left:0;list-style:none;position:absolute;transition:width var(--el-transition-duration) var(--el-transition-function-ease-in-out-bezier),transform var(--el-transition-duration) var(--el-transition-function-ease-in-out-bezier);z-index:1}.el-tabs__new-tab{align-items:center;border:1px solid var(--el-border-color);border-radius:3px;color:var(--el-text-color-primary);cursor:pointer;display:flex;font-size:12px;height:20px;justify-content:center;line-height:20px;margin:10px 0 10px 10px;text-align:center;transition:all .15s;width:20px}.el-tabs__new-tab .is-icon-plus{height:inherit;transform:scale(.8);width:inherit}.el-tabs__new-tab .is-icon-plus svg{vertical-align:middle}.el-tabs__new-tab:hover{color:var(--el-color-primary)}.el-tabs__new-tab-vertical{margin-left:0}.el-tabs__nav-wrap{flex:1 auto;margin-bottom:-1px;overflow:hidden;position:relative}.el-tabs__nav-wrap:after{background-color:var(--el-border-color-light);bottom:0;content:"";height:2px;left:0;position:absolute;width:100%;z-index:var(--el-index-normal)}.el-tabs__nav-wrap.is-scrollable{box-sizing:border-box;padding:0 20px}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{color:var(--el-text-color-secondary);cursor:pointer;font-size:12px;line-height:44px;position:absolute;text-align:center;width:20px}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{display:flex;float:left;position:relative;transition:transform var(--el-transition-duration);white-space:nowrap;z-index:calc(var(--el-index-normal) + 1)}.el-tabs__nav.is-stretch{display:flex;min-width:100%}.el-tabs__nav.is-stretch>*{flex:1;text-align:center}.el-tabs__item{align-items:center;box-sizing:border-box;color:var(--el-text-color-primary);display:flex;font-size:var(--el-font-size-base);font-weight:500;height:var(--el-tabs-header-height);justify-content:center;list-style:none;padding:0 20px;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:none}.el-tabs__item:focus-visible{border-radius:3px;box-shadow:0 0 2px 2px var(--el-color-primary) inset}.el-tabs__item .is-icon-close{border-radius:50%;margin-left:5px;text-align:center;transition:all var(--el-transition-duration) var(--el-transition-function-ease-in-out-bezier)}.el-tabs__item .is-icon-close:before{display:inline-block;transform:scale(.9)}.el-tabs__item .is-icon-close:hover{background-color:var(--el-text-color-placeholder);color:#fff}.el-tabs__item.is-active,.el-tabs__item:hover{color:var(--el-color-primary)}.el-tabs__item:hover{cursor:pointer}.el-tabs__item.is-disabled{color:var(--el-disabled-text-color);cursor:not-allowed}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid var(--el-border-color-light);height:var(--el-tabs-header-height)}.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap:after{content:none}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid var(--el-border-color-light);border-bottom:none;border-radius:4px 4px 0 0;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .is-icon-close{font-size:12px;height:14px;overflow:hidden;position:relative;right:-2px;transform-origin:100% 50%;width:0}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid var(--el-border-color-light);transition:color var(--el-transition-duration) var(--el-transition-function-ease-in-out-bezier),padding var(--el-transition-duration) var(--el-transition-function-ease-in-out-bezier)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .is-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:var(--el-bg-color)}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .is-icon-close{width:14px}.el-tabs--border-card{background:var(--el-bg-color-overlay);border:1px solid var(--el-border-color)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:var(--el-fill-color-light);border-bottom:1px solid var(--el-border-color-light);margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap:after{content:none}.el-tabs--border-card>.el-tabs__header .el-tabs__item{border:1px solid transparent;color:var(--el-text-color-secondary);margin-top:-1px;transition:all var(--el-transition-duration) var(--el-transition-function-ease-in-out-bezier)}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{background-color:var(--el-bg-color-overlay);border-left-color:var(--el-border-color);border-right-color:var(--el-border-color);color:var(--el-color-primary)}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:var(--el-color-primary)}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:var(--el-disabled-text-color)}.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2):not(.is-active).is-closable:hover,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2):not(.is-active).is-closable:hover,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2):not(.is-active).is-closable:hover,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2):not(.is-active).is-closable:hover,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2):not(.is-active).is-closable:hover,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2):not(.is-active).is-closable:hover,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2):not(.is-active).is-closable:hover,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2):not(.is-active).is-closable:hover{padding-left:13px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child:not(.is-active).is-closable:hover,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child:not(.is-active).is-closable:hover,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child:not(.is-active).is-closable:hover,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child:not(.is-active).is-closable:hover,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child:not(.is-active).is-closable:hover,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child:not(.is-active).is-closable:hover,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child:not(.is-active).is-closable:hover,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child:not(.is-active).is-closable:hover{padding-right:13px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid var(--el-border-color)}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-bottom:0;margin-top:-1px}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{bottom:auto;height:auto;top:0;width:2px}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{cursor:pointer;height:30px;line-height:30px;text-align:center;width:100%}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{transform:rotate(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{bottom:0;right:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left:after,.el-tabs--left .el-tabs__nav-wrap.is-right:after,.el-tabs--right .el-tabs__nav-wrap.is-left:after,.el-tabs--right .el-tabs__nav-wrap.is-right:after{bottom:auto;height:100%;top:0;width:2px}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{flex-direction:column}.el-tabs--left .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-left{justify-content:flex-end}.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-right{justify-content:flex-start}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left:after{left:auto;right:0}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left{display:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-bottom:none;border-left:none;border-right:1px solid var(--el-border-color-light);border-top:1px solid var(--el-border-color-light);text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid var(--el-border-color-light);border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid var(--el-border-color-light);border-bottom:none;border-left:none;border-right:1px solid #fff}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-bottom:1px solid var(--el-border-color-light);border-radius:4px 0 0 4px;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid var(--el-border-color)}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:rgb(209,219,229) transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right:after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid var(--el-border-color-light)}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid var(--el-border-color-light);border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid var(--el-border-color-light);border-bottom:none;border-left:1px solid #fff;border-right:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-bottom:1px solid var(--el-border-color-light);border-left:none;border-radius:0 4px 4px 0}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid var(--el-border-color)}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:rgb(209,219,229) transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{animation:slideInRight-enter var(--el-transition-duration)}.slideInRight-leave{animation:slideInRight-leave var(--el-transition-duration);left:0;position:absolute;right:0}.slideInLeft-enter{animation:slideInLeft-enter var(--el-transition-duration)}.slideInLeft-leave{animation:slideInLeft-leave var(--el-transition-duration);left:0;position:absolute;right:0}@keyframes slideInRight-enter{0%{opacity:0;transform:translate(100%);transform-origin:0 0}to{opacity:1;transform:translate(0);transform-origin:0 0}}@keyframes slideInRight-leave{0%{opacity:1;transform:translate(0);transform-origin:0 0}to{opacity:0;transform:translate(100%);transform-origin:0 0}}@keyframes slideInLeft-enter{0%{opacity:0;transform:translate(-100%);transform-origin:0 0}to{opacity:1;transform:translate(0);transform-origin:0 0}}@keyframes slideInLeft-leave{0%{opacity:1;transform:translate(0);transform-origin:0 0}to{opacity:0;transform:translate(-100%);transform-origin:0 0}}.el-tag{--el-tag-font-size:12px;--el-tag-border-radius:4px;--el-tag-border-radius-rounded:9999px;align-items:center;background-color:var(--el-tag-bg-color);border-color:var(--el-tag-border-color);border-radius:var(--el-tag-border-radius);border-style:solid;border-width:1px;box-sizing:border-box;color:var(--el-tag-text-color);display:inline-flex;font-size:var(--el-tag-font-size);height:24px;justify-content:center;line-height:1;padding:0 9px;vertical-align:middle;white-space:nowrap;--el-icon-size:14px}.el-tag,.el-tag.el-tag--primary{--el-tag-bg-color:var(--el-color-primary-light-9);--el-tag-border-color:var(--el-color-primary-light-8);--el-tag-hover-color:var(--el-color-primary)}.el-tag.el-tag--success{--el-tag-bg-color:var(--el-color-success-light-9);--el-tag-border-color:var(--el-color-success-light-8);--el-tag-hover-color:var(--el-color-success)}.el-tag.el-tag--warning{--el-tag-bg-color:var(--el-color-warning-light-9);--el-tag-border-color:var(--el-color-warning-light-8);--el-tag-hover-color:var(--el-color-warning)}.el-tag.el-tag--danger{--el-tag-bg-color:var(--el-color-danger-light-9);--el-tag-border-color:var(--el-color-danger-light-8);--el-tag-hover-color:var(--el-color-danger)}.el-tag.el-tag--error{--el-tag-bg-color:var(--el-color-error-light-9);--el-tag-border-color:var(--el-color-error-light-8);--el-tag-hover-color:var(--el-color-error)}.el-tag.el-tag--info{--el-tag-bg-color:var(--el-color-info-light-9);--el-tag-border-color:var(--el-color-info-light-8);--el-tag-hover-color:var(--el-color-info)}.el-tag.is-hit{border-color:var(--el-color-primary)}.el-tag.is-round{border-radius:var(--el-tag-border-radius-rounded)}.el-tag .el-tag__close{color:var(--el-tag-text-color);flex-shrink:0}.el-tag .el-tag__close:hover{background-color:var(--el-tag-hover-color);color:var(--el-color-white)}.el-tag.el-tag--primary{--el-tag-text-color:var(--el-color-primary)}.el-tag.el-tag--success{--el-tag-text-color:var(--el-color-success)}.el-tag.el-tag--warning{--el-tag-text-color:var(--el-color-warning)}.el-tag.el-tag--danger{--el-tag-text-color:var(--el-color-danger)}.el-tag.el-tag--error{--el-tag-text-color:var(--el-color-error)}.el-tag.el-tag--info{--el-tag-text-color:var(--el-color-info)}.el-tag .el-icon{border-radius:50%;cursor:pointer;font-size:calc(var(--el-icon-size) - 2px);height:var(--el-icon-size);width:var(--el-icon-size)}.el-tag .el-tag__close{margin-left:6px}.el-tag--dark{--el-tag-text-color:var(--el-color-white)}.el-tag--dark,.el-tag--dark.el-tag--primary{--el-tag-bg-color:var(--el-color-primary);--el-tag-border-color:var(--el-color-primary);--el-tag-hover-color:var(--el-color-primary-light-3)}.el-tag--dark.el-tag--success{--el-tag-bg-color:var(--el-color-success);--el-tag-border-color:var(--el-color-success);--el-tag-hover-color:var(--el-color-success-light-3)}.el-tag--dark.el-tag--warning{--el-tag-bg-color:var(--el-color-warning);--el-tag-border-color:var(--el-color-warning);--el-tag-hover-color:var(--el-color-warning-light-3)}.el-tag--dark.el-tag--danger{--el-tag-bg-color:var(--el-color-danger);--el-tag-border-color:var(--el-color-danger);--el-tag-hover-color:var(--el-color-danger-light-3)}.el-tag--dark.el-tag--error{--el-tag-bg-color:var(--el-color-error);--el-tag-border-color:var(--el-color-error);--el-tag-hover-color:var(--el-color-error-light-3)}.el-tag--dark.el-tag--info{--el-tag-bg-color:var(--el-color-info);--el-tag-border-color:var(--el-color-info);--el-tag-hover-color:var(--el-color-info-light-3)}.el-tag--dark.el-tag--danger,.el-tag--dark.el-tag--error,.el-tag--dark.el-tag--info,.el-tag--dark.el-tag--primary,.el-tag--dark.el-tag--success,.el-tag--dark.el-tag--warning{--el-tag-text-color:var(--el-color-white)}.el-tag--plain,.el-tag--plain.el-tag--primary{--el-tag-bg-color:var(--el-fill-color-blank);--el-tag-border-color:var(--el-color-primary-light-5);--el-tag-hover-color:var(--el-color-primary)}.el-tag--plain.el-tag--success{--el-tag-bg-color:var(--el-fill-color-blank);--el-tag-border-color:var(--el-color-success-light-5);--el-tag-hover-color:var(--el-color-success)}.el-tag--plain.el-tag--warning{--el-tag-bg-color:var(--el-fill-color-blank);--el-tag-border-color:var(--el-color-warning-light-5);--el-tag-hover-color:var(--el-color-warning)}.el-tag--plain.el-tag--danger{--el-tag-bg-color:var(--el-fill-color-blank);--el-tag-border-color:var(--el-color-danger-light-5);--el-tag-hover-color:var(--el-color-danger)}.el-tag--plain.el-tag--error{--el-tag-bg-color:var(--el-fill-color-blank);--el-tag-border-color:var(--el-color-error-light-5);--el-tag-hover-color:var(--el-color-error)}.el-tag--plain.el-tag--info{--el-tag-bg-color:var(--el-fill-color-blank);--el-tag-border-color:var(--el-color-info-light-5);--el-tag-hover-color:var(--el-color-info)}.el-tag.is-closable{padding-right:5px}.el-tag--large{height:32px;padding:0 11px;--el-icon-size:16px}.el-tag--large .el-tag__close{margin-left:8px}.el-tag--large.is-closable{padding-right:7px}.el-tag--small{height:20px;padding:0 7px;--el-icon-size:12px}.el-tag--small .el-tag__close{margin-left:4px}.el-tag--small.is-closable{padding-right:3px}.el-tag--small .el-icon-close{transform:scale(.8)}.el-tag.el-tag--primary.is-hit{border-color:var(--el-color-primary)}.el-tag.el-tag--success.is-hit{border-color:var(--el-color-success)}.el-tag.el-tag--warning.is-hit{border-color:var(--el-color-warning)}.el-tag.el-tag--danger.is-hit{border-color:var(--el-color-danger)}.el-tag.el-tag--error.is-hit{border-color:var(--el-color-error)}.el-tag.el-tag--info.is-hit{border-color:var(--el-color-info)}.el-text{--el-text-font-size:var(--el-font-size-base);--el-text-color:var(--el-text-color-regular);align-self:center;color:var(--el-text-color);font-size:var(--el-text-font-size);margin:0;overflow-wrap:break-word;padding:0}.el-text.is-truncated{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.el-text.is-line-clamp{display:-webkit-inline-box;-webkit-box-orient:vertical;overflow:hidden}.el-text--large{--el-text-font-size:var(--el-font-size-medium)}.el-text--default{--el-text-font-size:var(--el-font-size-base)}.el-text--small{--el-text-font-size:var(--el-font-size-extra-small)}.el-text.el-text--primary{--el-text-color:var(--el-color-primary)}.el-text.el-text--success{--el-text-color:var(--el-color-success)}.el-text.el-text--warning{--el-text-color:var(--el-color-warning)}.el-text.el-text--danger{--el-text-color:var(--el-color-danger)}.el-text.el-text--error{--el-text-color:var(--el-color-error)}.el-text.el-text--info{--el-text-color:var(--el-color-info)}.el-text>.el-icon{vertical-align:-2px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{margin:0;max-height:200px}.time-select-item{font-size:14px;line-height:20px;padding:8px 10px}.time-select-item.disabled{color:var(--el-datepicker-border-color);cursor:not-allowed}.time-select-item:hover{background-color:var(--el-fill-color-light);cursor:pointer;font-weight:700}.time-select .time-select-item.selected:not(.disabled){color:var(--el-color-primary);font-weight:700}.el-timeline-item{padding-bottom:20px;position:relative}.el-timeline-item__wrapper{padding-left:28px;position:relative;top:-3px}.el-timeline-item__tail{border-left:2px solid var(--el-timeline-node-color);height:100%;left:4px;position:absolute}.el-timeline-item .el-timeline-item__icon{color:var(--el-color-white);font-size:var(--el-font-size-small)}.el-timeline-item__node{align-items:center;background-color:var(--el-timeline-node-color);border-color:var(--el-timeline-node-color);border-radius:50%;box-sizing:border-box;display:flex;justify-content:center;position:absolute}.el-timeline-item__node--normal{height:var(--el-timeline-node-size-normal);left:-1px;width:var(--el-timeline-node-size-normal)}.el-timeline-item__node--large{height:var(--el-timeline-node-size-large);left:-2px;width:var(--el-timeline-node-size-large)}.el-timeline-item__node.is-hollow{background:var(--el-color-white);border-style:solid;border-width:2px}.el-timeline-item__node--primary{background-color:var(--el-color-primary);border-color:var(--el-color-primary)}.el-timeline-item__node--success{background-color:var(--el-color-success);border-color:var(--el-color-success)}.el-timeline-item__node--warning{background-color:var(--el-color-warning);border-color:var(--el-color-warning)}.el-timeline-item__node--danger{background-color:var(--el-color-danger);border-color:var(--el-color-danger)}.el-timeline-item__node--info{background-color:var(--el-color-info);border-color:var(--el-color-info)}.el-timeline-item__dot{align-items:center;display:flex;justify-content:center;position:absolute}.el-timeline-item__content{color:var(--el-text-color-primary)}.el-timeline-item__timestamp{color:var(--el-text-color-secondary);font-size:var(--el-font-size-small);line-height:1}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-timeline{--el-timeline-node-size-normal:12px;--el-timeline-node-size-large:14px;--el-timeline-node-color:var(--el-border-color-light);font-size:var(--el-font-size-base);list-style:none;margin:0}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline .el-timeline-item__center{align-items:center;display:flex}.el-timeline .el-timeline-item__center .el-timeline-item__wrapper{width:100%}.el-timeline .el-timeline-item__center .el-timeline-item__tail{top:0}.el-timeline .el-timeline-item__center:first-child .el-timeline-item__tail{height:calc(50% + 10px);top:calc(50% - 10px)}.el-timeline .el-timeline-item__center:last-child .el-timeline-item__tail{display:block;height:calc(50% - 10px)}.el-tooltip-v2__content{--el-tooltip-v2-padding:5px 10px;--el-tooltip-v2-border-radius:4px;--el-tooltip-v2-border-color:var(--el-border-color);background-color:var(--el-color-white);border:1px solid var(--el-border-color);border-radius:var(--el-tooltip-v2-border-radius);color:var(--el-color-black);padding:var(--el-tooltip-v2-padding)}.el-tooltip-v2__arrow{color:var(--el-color-white);height:var(--el-tooltip-v2-arrow-height);left:var(--el-tooltip-v2-arrow-x);pointer-events:none;position:absolute;top:var(--el-tooltip-v2-arrow-y);width:var(--el-tooltip-v2-arrow-width)}.el-tooltip-v2__arrow:after,.el-tooltip-v2__arrow:before{border:var(--el-tooltip-v2-arrow-border-width) solid transparent;content:"";height:0;position:absolute;width:0}.el-tooltip-v2__content[data-side^=top] .el-tooltip-v2__arrow{bottom:0}.el-tooltip-v2__content[data-side^=top] .el-tooltip-v2__arrow:before{border-bottom:0;border-top-color:var(--el-color-white);border-top-width:var(--el-tooltip-v2-arrow-border-width);top:calc(100% - 1px)}.el-tooltip-v2__content[data-side^=top] .el-tooltip-v2__arrow:after{border-bottom:0;border-top-color:var(--el-border-color);border-top-width:var(--el-tooltip-v2-arrow-border-width);top:100%;z-index:-1}.el-tooltip-v2__content[data-side^=bottom] .el-tooltip-v2__arrow{top:0}.el-tooltip-v2__content[data-side^=bottom] .el-tooltip-v2__arrow:before{border-bottom-color:var(--el-color-white);border-bottom-width:var(--el-tooltip-v2-arrow-border-width);border-top:0;bottom:calc(100% - 1px)}.el-tooltip-v2__content[data-side^=bottom] .el-tooltip-v2__arrow:after{border-bottom-color:var(--el-border-color);border-bottom-width:var(--el-tooltip-v2-arrow-border-width);border-top:0;bottom:100%;z-index:-1}.el-tooltip-v2__content[data-side^=left] .el-tooltip-v2__arrow{right:0}.el-tooltip-v2__content[data-side^=left] .el-tooltip-v2__arrow:before{border-left-color:var(--el-color-white);border-left-width:var(--el-tooltip-v2-arrow-border-width);border-right:0;left:calc(100% - 1px)}.el-tooltip-v2__content[data-side^=left] .el-tooltip-v2__arrow:after{border-left-color:var(--el-border-color);border-left-width:var(--el-tooltip-v2-arrow-border-width);border-right:0;left:100%;z-index:-1}.el-tooltip-v2__content[data-side^=right] .el-tooltip-v2__arrow{left:0}.el-tooltip-v2__content[data-side^=right] .el-tooltip-v2__arrow:before{border-left:0;border-right-color:var(--el-color-white);border-right-width:var(--el-tooltip-v2-arrow-border-width);right:calc(100% - 1px)}.el-tooltip-v2__content[data-side^=right] .el-tooltip-v2__arrow:after{border-left:0;border-right-color:var(--el-border-color);border-right-width:var(--el-tooltip-v2-arrow-border-width);right:100%;z-index:-1}.el-tooltip-v2__content.is-dark{--el-tooltip-v2-border-color:transparent;color:var(--el-color-white)}.el-tooltip-v2__content.is-dark,.el-tooltip-v2__content.is-dark .el-tooltip-v2__arrow{background-color:var(--el-color-black);border-color:transparent}.el-transfer{--el-transfer-border-color:var(--el-border-color-lighter);--el-transfer-border-radius:var(--el-border-radius-base);--el-transfer-panel-width:200px;--el-transfer-panel-header-height:40px;--el-transfer-panel-header-bg-color:var(--el-fill-color-light);--el-transfer-panel-footer-height:40px;--el-transfer-panel-body-height:278px;--el-transfer-item-height:30px;--el-transfer-filter-height:32px;font-size:var(--el-font-size-base)}.el-transfer__buttons{display:inline-block;padding:0 30px;vertical-align:middle}.el-transfer__button{vertical-align:top}.el-transfer__button:nth-child(2){margin:0 0 0 10px}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer__button .el-icon+span{margin-left:0}.el-transfer-panel{background:var(--el-bg-color-overlay);box-sizing:border-box;display:inline-block;max-height:100%;overflow:hidden;position:relative;text-align:left;vertical-align:middle;width:var(--el-transfer-panel-width)}.el-transfer-panel__body{border-bottom:1px solid var(--el-transfer-border-color);border-bottom-left-radius:var(--el-transfer-border-radius);border-bottom-right-radius:var(--el-transfer-border-radius);border-left:1px solid var(--el-transfer-border-color);border-right:1px solid var(--el-transfer-border-color);height:var(--el-transfer-panel-body-height);overflow:hidden}.el-transfer-panel__body.is-with-footer{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.el-transfer-panel__list{box-sizing:border-box;height:var(--el-transfer-panel-body-height);list-style:none;margin:0;overflow:auto;padding:6px 0}.el-transfer-panel__list.is-filterable{height:calc(100% - var(--el-transfer-filter-height) - 30px);padding-top:0}.el-transfer-panel__item{display:block!important;height:var(--el-transfer-item-height);line-height:var(--el-transfer-item-height);padding-left:15px}.el-transfer-panel__item+.el-transfer-panel__item{margin-left:0}.el-transfer-panel__item.el-checkbox{color:var(--el-text-color-regular)}.el-transfer-panel__item:hover{color:var(--el-color-primary)}.el-transfer-panel__item.el-checkbox .el-checkbox__label{box-sizing:border-box;display:block;line-height:var(--el-transfer-item-height);overflow:hidden;padding-left:22px;text-overflow:ellipsis;white-space:nowrap;width:100%}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{box-sizing:border-box;padding:15px;text-align:center}.el-transfer-panel__filter .el-input__inner{border-radius:calc(var(--el-transfer-filter-height)/2);box-sizing:border-box;display:inline-block;font-size:12px;height:var(--el-transfer-filter-height);width:100%}.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-transfer-panel .el-transfer-panel__header{align-items:center;background:var(--el-transfer-panel-header-bg-color);border:1px solid var(--el-transfer-border-color);border-top-left-radius:var(--el-transfer-border-radius);border-top-right-radius:var(--el-transfer-border-radius);box-sizing:border-box;color:var(--el-color-black);display:flex;height:var(--el-transfer-panel-header-height);margin:0;padding-left:15px}.el-transfer-panel .el-transfer-panel__header .el-checkbox{align-items:center;display:flex;position:relative;width:100%}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{color:var(--el-text-color-primary);font-size:16px;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{color:var(--el-text-color-secondary);font-size:12px;font-weight:400;position:absolute;right:15px;top:50%;transform:translate3d(0,-50%,0)}.el-transfer-panel .el-transfer-panel__footer{background:var(--el-bg-color-overlay);border:1px solid var(--el-transfer-border-color);border-bottom-left-radius:var(--el-transfer-border-radius);border-bottom-right-radius:var(--el-transfer-border-radius);height:var(--el-transfer-panel-footer-height);margin:0;padding:0}.el-transfer-panel .el-transfer-panel__footer:after{content:"";display:inline-block;height:100%;vertical-align:middle}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{color:var(--el-text-color-regular);padding-left:20px}.el-transfer-panel .el-transfer-panel__empty{color:var(--el-text-color-secondary);height:var(--el-transfer-item-height);line-height:var(--el-transfer-item-height);margin:0;padding:6px 15px 0;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{border-radius:3px;height:14px;width:14px}.el-transfer-panel .el-checkbox__inner:after{height:6px;left:4px;width:3px}.el-tree{--el-tree-node-content-height:26px;--el-tree-node-hover-bg-color:var(--el-fill-color-light);--el-tree-text-color:var(--el-text-color-regular);--el-tree-expand-icon-color:var(--el-text-color-placeholder);background:var(--el-fill-color-blank);color:var(--el-tree-text-color);cursor:default;font-size:var(--el-font-size-base);position:relative}.el-tree__empty-block{height:100%;min-height:60px;position:relative;text-align:center;width:100%}.el-tree__empty-text{color:var(--el-text-color-secondary);font-size:var(--el-font-size-base);left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.el-tree__drop-indicator{background-color:var(--el-color-primary);height:1px;left:0;position:absolute;right:0}.el-tree-node{outline:none;white-space:nowrap}.el-tree-node:focus>.el-tree-node__content{background-color:var(--el-tree-node-hover-bg-color)}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:var(--el-color-primary);color:#fff}.el-tree-node__content{--el-checkbox-height:var(--el-tree-node-content-height);align-items:center;cursor:pointer;display:flex;height:var(--el-tree-node-content-height)}.el-tree-node__content>.el-tree-node__expand-icon{box-sizing:content-box;padding:6px}.el-tree-node__content>label.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:var(--el-tree-node-hover-bg-color)}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{color:var(--el-tree-expand-icon-color);cursor:pointer;font-size:12px;transform:rotate(0);transition:transform var(--el-transition-duration) ease-in-out}.el-tree-node__expand-icon.expanded{transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default;visibility:hidden}.el-tree-node__expand-icon.is-hidden{visibility:hidden}.el-tree-node__loading-icon{color:var(--el-tree-expand-icon-color);font-size:var(--el-font-size-base);margin-right:8px}.el-tree-node>.el-tree-node__children{background-color:transparent;overflow:hidden}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:var(--el-color-primary-light-9)}.el-tree-select{--el-tree-node-content-height:26px;--el-tree-node-hover-bg-color:var(--el-fill-color-light);--el-tree-text-color:var(--el-text-color-regular);--el-tree-expand-icon-color:var(--el-text-color-placeholder)}.el-tree-select__popper .el-tree-node__expand-icon{margin-left:8px}.el-tree-select__popper .el-tree-node.is-checked>.el-tree-node__content .el-select-dropdown__item.selected:after{content:none}.el-tree-select__popper .el-select-dropdown__list>.el-select-dropdown__item{padding-left:32px}.el-tree-select__popper .el-select-dropdown__item{background:transparent!important;flex:1;height:20px;line-height:20px;padding-left:0}.el-upload{--el-upload-dragger-padding-horizontal:40px;--el-upload-dragger-padding-vertical:10px;align-items:center;cursor:pointer;display:inline-flex;justify-content:center;outline:none}.el-upload__input{display:none}.el-upload__tip{color:var(--el-text-color-regular);font-size:12px;margin-top:7px}.el-upload iframe{filter:alpha(opacity=0);left:0;opacity:0;position:absolute;top:0;z-index:-1}.el-upload--picture-card{--el-upload-picture-card-size:148px;align-items:center;background-color:var(--el-fill-color-lighter);border:1px dashed var(--el-border-color-darker);border-radius:6px;box-sizing:border-box;cursor:pointer;display:inline-flex;height:var(--el-upload-picture-card-size);justify-content:center;vertical-align:top;width:var(--el-upload-picture-card-size)}.el-upload--picture-card>i{color:var(--el-text-color-secondary);font-size:28px}.el-upload--picture-card:hover{border-color:var(--el-color-primary);color:var(--el-color-primary)}.el-upload.is-drag{display:block}.el-upload:focus{color:var(--el-color-primary)}.el-upload:focus,.el-upload:focus .el-upload-dragger{border-color:var(--el-color-primary)}.el-upload-dragger{background-color:var(--el-fill-color-blank);border:1px dashed var(--el-border-color);border-radius:6px;box-sizing:border-box;cursor:pointer;overflow:hidden;padding:var(--el-upload-dragger-padding-horizontal) var(--el-upload-dragger-padding-vertical);position:relative;text-align:center}.el-upload-dragger .el-icon--upload{color:var(--el-text-color-placeholder);font-size:67px;line-height:50px;margin-bottom:16px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:var(--el-border);margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:var(--el-text-color-regular);font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:var(--el-color-primary);font-style:normal}.el-upload-dragger:hover{border-color:var(--el-color-primary)}.el-upload-dragger.is-dragover{background-color:var(--el-color-primary-light-9);border:2px dashed var(--el-color-primary);padding:calc(var(--el-upload-dragger-padding-horizontal) - 1px) calc(var(--el-upload-dragger-padding-vertical) - 1px)}.el-upload-list{list-style:none;margin:10px 0 0;padding:0;position:relative}.el-upload-list__item{border-radius:4px;box-sizing:border-box;color:var(--el-text-color-regular);font-size:14px;margin-bottom:5px;position:relative;transition:all .5s cubic-bezier(.55,0,.1,1);width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item .el-icon--upload-success{color:var(--el-color-success)}.el-upload-list__item .el-icon--close{color:var(--el-text-color-regular);cursor:pointer;display:none;opacity:.75;position:absolute;right:5px;top:50%;transform:translateY(-50%);transition:opacity var(--el-transition-duration)}.el-upload-list__item .el-icon--close:hover{color:var(--el-color-primary);opacity:1}.el-upload-list__item .el-icon--close-tip{color:var(--el-color-primary);cursor:pointer;display:none;font-size:12px;font-style:normal;opacity:1;position:absolute;right:5px;top:1px}.el-upload-list__item:hover{background-color:var(--el-fill-color-light)}.el-upload-list__item:hover .el-icon--close{display:inline-flex}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item .el-upload-list__item-info{display:inline-flex;flex-direction:column;justify-content:center;margin-left:4px;width:calc(100% - 30px)}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:inline-flex}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:var(--el-color-primary);cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon--close-tip{display:inline-block}.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}.el-upload-list__item.is-success:active .el-icon--close-tip,.el-upload-list__item.is-success:not(.focusing):focus .el-icon--close-tip{display:none}.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label{display:none;opacity:0}.el-upload-list__item-name{align-items:center;color:var(--el-text-color-regular);display:inline-flex;font-size:var(--el-font-size-base);padding:0 4px;text-align:center;transition:color var(--el-transition-duration)}.el-upload-list__item-name .el-icon{color:var(--el-text-color-secondary);margin-right:6px}.el-upload-list__item-file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.el-upload-list__item-status-label{align-items:center;display:none;height:100%;justify-content:center;line-height:inherit;position:absolute;right:5px;top:0;transition:opacity var(--el-transition-duration)}.el-upload-list__item-delete{color:var(--el-text-color-regular);display:none;font-size:12px;position:absolute;right:10px;top:0}.el-upload-list__item-delete:hover{color:var(--el-color-primary)}.el-upload-list--picture-card{--el-upload-list-picture-card-size:148px;display:inline-flex;flex-wrap:wrap;margin:0}.el-upload-list--picture-card .el-upload-list__item{background-color:var(--el-fill-color-blank);border:1px solid var(--el-border-color);border-radius:6px;box-sizing:border-box;display:inline-flex;height:var(--el-upload-list-picture-card-size);margin:0 8px 8px 0;overflow:hidden;padding:0;width:var(--el-upload-list-picture-card-size)}.el-upload-list--picture-card .el-upload-list__item .el-icon--check,.el-upload-list--picture-card .el-upload-list__item .el-icon--circle-check{color:#fff}.el-upload-list--picture-card .el-upload-list__item .el-icon--close{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:block;opacity:0}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{height:100%;-o-object-fit:contain;object-fit:contain;width:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{background:var(--el-color-success);height:24px;right:-15px;text-align:center;top:-6px;transform:rotate(45deg);width:40px}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{align-items:center;background-color:var(--el-overlay-color-lighter);color:#fff;cursor:default;display:inline-flex;font-size:20px;height:100%;justify-content:center;left:0;opacity:0;position:absolute;top:0;transition:opacity var(--el-transition-duration);width:100%}.el-upload-list--picture-card .el-upload-list__item-actions span{cursor:pointer;display:none}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:16px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{color:inherit;font-size:inherit;position:static}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-flex}.el-upload-list--picture-card .el-progress{bottom:auto;left:50%;top:50%;transform:translate(-50%,-50%);width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{align-items:center;background-color:var(--el-fill-color-blank);border:1px solid var(--el-border-color);border-radius:6px;box-sizing:border-box;display:flex;margin-top:10px;overflow:hidden;padding:10px;z-index:0}.el-upload-list--picture .el-upload-list__item .el-icon--check,.el-upload-list--picture .el-upload-list__item .el-icon--circle-check{color:#fff}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{display:inline-flex;opacity:0}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item .el-icon--close{top:5px;transform:translateY(0)}.el-upload-list--picture .el-upload-list__item-thumbnail{align-items:center;background-color:var(--el-color-white);display:inline-flex;height:70px;justify-content:center;-o-object-fit:contain;object-fit:contain;position:relative;width:70px;z-index:1}.el-upload-list--picture .el-upload-list__item-status-label{background:var(--el-color-success);height:26px;position:absolute;right:-17px;text-align:center;top:-7px;transform:rotate(45deg);width:46px}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{cursor:default;height:100%;left:0;overflow:hidden;position:absolute;top:0;width:100%;z-index:10}.el-upload-cover:after{content:"";display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;height:100%;width:100%}.el-upload-cover__label{background:var(--el-color-success);height:24px;right:-15px;text-align:center;top:-6px;transform:rotate(45deg);width:40px}.el-upload-cover__label i{color:#fff;font-size:12px;margin-top:11px;transform:rotate(-45deg)}.el-upload-cover__progress{display:inline-block;position:static;vertical-align:middle;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{height:100%;left:0;position:absolute;top:0;width:100%}.el-upload-cover__interact{background-color:var(--el-overlay-color-light);bottom:0;height:100%;left:0;position:absolute;text-align:center;width:100%}.el-upload-cover__interact .btn{color:#fff;cursor:pointer;display:inline-block;font-size:14px;margin-top:60px;transition:var(--el-transition-md-fade);vertical-align:middle}.el-upload-cover__interact .btn i{margin-top:0}.el-upload-cover__interact .btn span{opacity:0;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#fff;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{background-color:#fff;bottom:0;color:var(--el-text-color-primary);font-size:14px;font-weight:400;height:36px;left:0;line-height:36px;margin:0;overflow:hidden;padding:0 10px;position:absolute;text-align:left;text-overflow:ellipsis;white-space:nowrap;width:100%}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-vl__wrapper{position:relative}.el-vl__wrapper.always-on .el-virtual-scrollbar,.el-vl__wrapper:hover .el-virtual-scrollbar{opacity:1}.el-vl__window{scrollbar-width:none}.el-vl__window::-webkit-scrollbar{display:none}.el-virtual-scrollbar{opacity:0;transition:opacity .34s ease-out}.el-virtual-scrollbar.always-on{opacity:1}.el-vg__wrapper{position:relative}.el-popper{--el-popper-border-radius:var(--el-popover-border-radius,4px);border-radius:var(--el-popper-border-radius);font-size:12px;line-height:20px;min-width:10px;overflow-wrap:break-word;padding:5px 11px;position:absolute;visibility:visible;z-index:2000}.el-popper.is-dark{color:var(--el-bg-color)}.el-popper.is-dark,.el-popper.is-dark .el-popper__arrow:before{background:var(--el-text-color-primary);border:1px solid var(--el-text-color-primary)}.el-popper.is-dark .el-popper__arrow:before{right:0}.el-popper.is-light,.el-popper.is-light .el-popper__arrow:before{background:var(--el-bg-color-overlay);border:1px solid var(--el-border-color-light)}.el-popper.is-light .el-popper__arrow:before{right:0}.el-popper.is-pure{padding:0}.el-popper__arrow,.el-popper__arrow:before{height:10px;position:absolute;width:10px;z-index:-1}.el-popper__arrow:before{background:var(--el-text-color-primary);box-sizing:border-box;content:" ";transform:rotate(45deg)}.el-popper[data-popper-placement^=top]>.el-popper__arrow{bottom:-5px}.el-popper[data-popper-placement^=top]>.el-popper__arrow:before{border-bottom-right-radius:2px}.el-popper[data-popper-placement^=bottom]>.el-popper__arrow{top:-5px}.el-popper[data-popper-placement^=bottom]>.el-popper__arrow:before{border-top-left-radius:2px}.el-popper[data-popper-placement^=left]>.el-popper__arrow{right:-5px}.el-popper[data-popper-placement^=left]>.el-popper__arrow:before{border-top-right-radius:2px}.el-popper[data-popper-placement^=right]>.el-popper__arrow{left:-5px}.el-popper[data-popper-placement^=right]>.el-popper__arrow:before{border-bottom-left-radius:2px}.el-popper[data-popper-placement^=top] .el-popper__arrow:before{border-left-color:transparent!important;border-top-color:transparent!important}.el-popper[data-popper-placement^=bottom] .el-popper__arrow:before{border-bottom-color:transparent!important;border-right-color:transparent!important}.el-popper[data-popper-placement^=left] .el-popper__arrow:before{border-bottom-color:transparent!important;border-left-color:transparent!important}.el-popper[data-popper-placement^=right] .el-popper__arrow:before{border-right-color:transparent!important;border-top-color:transparent!important}.el-statistic{--el-statistic-title-font-weight:400;--el-statistic-title-font-size:var(--el-font-size-extra-small);--el-statistic-title-color:var(--el-text-color-regular);--el-statistic-content-font-weight:400;--el-statistic-content-font-size:var(--el-font-size-extra-large);--el-statistic-content-color:var(--el-text-color-primary)}.el-statistic__head{color:var(--el-statistic-title-color);font-size:var(--el-statistic-title-font-size);font-weight:var(--el-statistic-title-font-weight);line-height:20px;margin-bottom:4px}.el-statistic__content{color:var(--el-statistic-content-color);font-size:var(--el-statistic-content-font-size);font-weight:var(--el-statistic-content-font-weight)}.el-statistic__value{display:inline-block}.el-statistic__prefix{display:inline-block;margin-right:4px}.el-statistic__suffix{display:inline-block;margin-left:4px}.el-tour{--el-tour-width:520px;--el-tour-padding-primary:12px;--el-tour-font-line-height:var(--el-font-line-height-primary);--el-tour-title-font-size:16px;--el-tour-title-text-color:var(--el-text-color-primary);--el-tour-title-font-weight:400;--el-tour-close-color:var(--el-color-info);--el-tour-font-size:14px;--el-tour-color:var(--el-text-color-primary);--el-tour-bg-color:var(--el-bg-color);--el-tour-border-radius:4px}.el-tour__hollow{transition:all var(--el-transition-duration) ease}.el-tour__content{border-radius:var(--el-tour-border-radius);box-shadow:var(--el-box-shadow-light);outline:none;overflow-wrap:break-word;padding:var(--el-tour-padding-primary);width:var(--el-tour-width)}.el-tour__arrow,.el-tour__content{background:var(--el-tour-bg-color);box-sizing:border-box}.el-tour__arrow{height:10px;pointer-events:none;position:absolute;transform:rotate(45deg);width:10px}.el-tour__content[data-side^=top] .el-tour__arrow{border-left-color:transparent;border-top-color:transparent}.el-tour__content[data-side^=bottom] .el-tour__arrow{border-bottom-color:transparent;border-right-color:transparent}.el-tour__content[data-side^=left] .el-tour__arrow{border-bottom-color:transparent;border-left-color:transparent}.el-tour__content[data-side^=right] .el-tour__arrow{border-right-color:transparent;border-top-color:transparent}.el-tour__content[data-side^=top] .el-tour__arrow{bottom:-5px}.el-tour__content[data-side^=bottom] .el-tour__arrow{top:-5px}.el-tour__content[data-side^=left] .el-tour__arrow{right:-5px}.el-tour__content[data-side^=right] .el-tour__arrow{left:-5px}.el-tour__closebtn{background:transparent;border:none;cursor:pointer;font-size:var(--el-message-close-size,16px);height:40px;outline:none;padding:0;position:absolute;right:0;top:0;width:40px}.el-tour__closebtn .el-tour__close{color:var(--el-tour-close-color);font-size:inherit}.el-tour__closebtn:focus .el-tour__close,.el-tour__closebtn:hover .el-tour__close{color:var(--el-color-primary)}.el-tour__header{padding-bottom:var(--el-tour-padding-primary)}.el-tour__header.show-close{padding-right:calc(var(--el-tour-padding-primary) + var(--el-message-close-size, 16px))}.el-tour__title{color:var(--el-tour-title-text-color);font-size:var(--el-tour-title-font-size);font-weight:var(--el-tour-title-font-weight);line-height:var(--el-tour-font-line-height)}.el-tour__body{color:var(--el-tour-text-color);font-size:var(--el-tour-font-size)}.el-tour__body img,.el-tour__body video{max-width:100%}.el-tour__footer{box-sizing:border-box;display:flex;justify-content:space-between;padding-top:var(--el-tour-padding-primary)}.el-tour__content .el-tour-indicators{display:inline-block;flex:1}.el-tour__content .el-tour-indicator{background:var(--el-color-info-light-9);border-radius:50%;display:inline-block;height:6px;margin-right:6px;width:6px}.el-tour__content .el-tour-indicator.is-active{background:var(--el-color-primary)}.el-tour.el-tour--primary{--el-tour-title-text-color:#fff;--el-tour-text-color:#fff;--el-tour-bg-color:var(--el-color-primary);--el-tour-close-color:#fff}.el-tour.el-tour--primary .el-tour__closebtn:focus .el-tour__close,.el-tour.el-tour--primary .el-tour__closebtn:hover .el-tour__close{color:var(--el-tour-title-text-color)}.el-tour.el-tour--primary .el-button--default{background:#fff;border-color:var(--el-color-primary);color:var(--el-color-primary)}.el-tour.el-tour--primary .el-button--primary{border-color:#fff}.el-tour.el-tour--primary .el-tour-indicator{background:#ffffff26}.el-tour.el-tour--primary .el-tour-indicator.is-active{background:#fff}.el-tour-parent--hidden{overflow:hidden}.el-anchor{--el-anchor-bg-color:var(--el-bg-color);--el-anchor-padding-indent:14px;--el-anchor-line-height:22px;--el-anchor-font-size:12px;--el-anchor-color:var(--el-text-color-secondary);--el-anchor-active-color:var(--el-color-primary);--el-anchor-marker-bg-color:var(--el-color-primary);background-color:var(--el-anchor-bg-color);position:relative}.el-anchor__marker{background-color:var(--el-anchor-marker-bg-color);border-radius:4px;opacity:0;position:absolute;z-index:0}.el-anchor.el-anchor--vertical .el-anchor__marker{height:14px;left:0;top:8px;transition:top .25s ease-in-out,opacity .25s;width:4px}.el-anchor.el-anchor--vertical .el-anchor__list{padding-left:var(--el-anchor-padding-indent)}.el-anchor.el-anchor--vertical.el-anchor--underline:before{background-color:#0505050f;content:"";height:100%;left:0;position:absolute;width:2px}.el-anchor.el-anchor--vertical.el-anchor--underline .el-anchor__marker{border-radius:unset;width:2px}.el-anchor.el-anchor--horizontal .el-anchor__marker{bottom:0;height:2px;transition:left .25s ease-in-out,opacity .25s,width .25s;width:20px}.el-anchor.el-anchor--horizontal .el-anchor__list{display:flex;padding-bottom:4px}.el-anchor.el-anchor--horizontal .el-anchor__list .el-anchor__item{padding-left:16px}.el-anchor.el-anchor--horizontal .el-anchor__list .el-anchor__item:first-child{padding-left:0}.el-anchor.el-anchor--horizontal.el-anchor--underline:before{background-color:#0505050f;bottom:0;content:"";height:2px;position:absolute;width:100%}.el-anchor.el-anchor--horizontal.el-anchor--underline .el-anchor__marker{border-radius:unset;height:2px}.el-anchor__item{display:flex;flex-direction:column;overflow:hidden}.el-anchor__link{cursor:pointer;font-size:var(--el-anchor-font-size);line-height:var(--el-anchor-line-height);max-width:100%;outline:none;overflow:hidden;padding:4px 0;text-decoration:none;text-overflow:ellipsis;transition:color var(--el-transition-duration);white-space:nowrap}.el-anchor__link,.el-anchor__link:focus,.el-anchor__link:hover{color:var(--el-anchor-color)}.el-anchor__link.is-active{color:var(--el-anchor-active-color)}.el-anchor .el-anchor__list .el-anchor__item a{display:inline-block}.el-segmented{--el-segmented-color:var(--el-text-color-regular);--el-segmented-bg-color:var(--el-fill-color-light);--el-segmented-padding:2px;--el-segmented-item-selected-color:var(--el-color-white);--el-segmented-item-selected-bg-color:var(--el-color-primary);--el-segmented-item-selected-disabled-bg-color:var(--el-color-primary-light-5);--el-segmented-item-hover-color:var(--el-text-color-primary);--el-segmented-item-hover-bg-color:var(--el-fill-color-dark);--el-segmented-item-active-bg-color:var(--el-fill-color-darker);--el-segmented-item-disabled-color:var(--el-text-color-placeholder);align-items:stretch;background:var(--el-segmented-bg-color);border-radius:var(--el-border-radius-base);box-sizing:border-box;color:var(--el-segmented-color);display:inline-flex;font-size:14px;min-height:32px;padding:var(--el-segmented-padding)}.el-segmented__group{align-items:stretch;display:flex;position:relative;width:100%}.el-segmented__item-selected{background:var(--el-segmented-item-selected-bg-color);border-radius:calc(var(--el-border-radius-base) - 2px);height:100%;left:0;pointer-events:none;position:absolute;top:0;transition:all .3s;width:10px}.el-segmented__item-selected.is-disabled{background:var(--el-segmented-item-selected-disabled-bg-color)}.el-segmented__item-selected.is-focus-visible:before{border-radius:inherit;content:"";top:0;right:0;bottom:0;left:0;outline:2px solid var(--el-segmented-item-selected-bg-color);outline-offset:1px;position:absolute}.el-segmented__item{align-items:center;border-radius:calc(var(--el-border-radius-base) - 2px);cursor:pointer;display:flex;flex:1;padding:0 11px}.el-segmented__item:not(.is-disabled):not(.is-selected):hover{background:var(--el-segmented-item-hover-bg-color);color:var(--el-segmented-item-hover-color)}.el-segmented__item:not(.is-disabled):not(.is-selected):active{background:var(--el-segmented-item-active-bg-color)}.el-segmented__item.is-selected,.el-segmented__item.is-selected.is-disabled{color:var(--el-segmented-item-selected-color)}.el-segmented__item.is-disabled{color:var(--el-segmented-item-disabled-color);cursor:not-allowed}.el-segmented__item-input{height:0;margin:0;opacity:0;pointer-events:none;position:absolute;width:0}.el-segmented__item-label{flex:1;line-height:normal;overflow:hidden;text-align:center;text-overflow:ellipsis;transition:color .3s;white-space:nowrap;z-index:1}.el-segmented.is-block{display:flex}.el-segmented.is-block .el-segmented__item{min-width:0}.el-segmented--large{border-radius:var(--el-border-radius-base);font-size:16px;min-height:40px}.el-segmented--large .el-segmented__item,.el-segmented--large .el-segmented__item-selected{border-radius:calc(var(--el-border-radius-base) - 2px)}.el-segmented--large .el-segmented__item{padding:0 11px}.el-segmented--small{border-radius:calc(var(--el-border-radius-base) - 1px);font-size:14px;min-height:24px}.el-segmented--small .el-segmented__item,.el-segmented--small .el-segmented__item-selected{border-radius:calc(var(--el-border-radius-base) - 3px)}.el-segmented--small .el-segmented__item{padding:0 7px} diff --git a/public/install/assets/index.js b/public/install/assets/index.js new file mode 100644 index 0000000..fac1d87 --- /dev/null +++ b/public/install/assets/index.js @@ -0,0 +1,73 @@ +var _$=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var nue=_$((go,bo)=>{(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))o(r);new MutationObserver(r=>{for(const a of r)if(a.type==="childList")for(const l of a.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&o(l)}).observe(document,{childList:!0,subtree:!0});function n(r){const a={};return r.integrity&&(a.integrity=r.integrity),r.referrerPolicy&&(a.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?a.credentials="include":r.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function o(r){if(r.ep)return;r.ep=!0;const a=n(r);fetch(r.href,a)}})();function xd(e,t){const n=Object.create(null),o=e.split(",");for(let r=0;r!!n[r]}const Zt={},rs=[],Bt=()=>{},C$=()=>!1,S$=/^on[^a-z]/,yu=e=>S$.test(e),Lm=e=>e.startsWith("onUpdate:"),an=Object.assign,xm=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},k$=Object.prototype.hasOwnProperty,Tt=(e,t)=>k$.call(e,t),Pe=Array.isArray,as=e=>js(e)==="[object Map]",Il=e=>js(e)==="[object Set]",hl=e=>js(e)==="[object Date]",E$=e=>js(e)==="[object RegExp]",Xe=e=>typeof e=="function",nt=e=>typeof e=="string",zi=e=>typeof e=="symbol",dt=e=>e!==null&&typeof e=="object",vs=e=>dt(e)&&Xe(e.then)&&Xe(e.catch),gw=Object.prototype.toString,js=e=>gw.call(e),Tc=e=>js(e).slice(8,-1),nd=e=>js(e)==="[object Object]",Dm=e=>nt(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,$i=xd(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Dd=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},T$=/-(\w)/g,jn=Dd(e=>e.replace(T$,(t,n)=>n?n.toUpperCase():"")),$$=/\B([A-Z])/g,mo=Dd(e=>e.replace($$,"-$1").toLowerCase()),Ws=Dd(e=>e.charAt(0).toUpperCase()+e.slice(1)),ls=Dd(e=>e?`on${Ws(e)}`:""),gs=(e,t)=>!Object.is(e,t),ss=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},rd=e=>{const t=parseFloat(e);return isNaN(t)?e:t},ad=e=>{const t=nt(e)?Number(e):NaN;return isNaN(t)?e:t};let db;const Hp=()=>db||(db=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}),O$="Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console",N$=xd(O$);function je(e){if(Pe(e)){const t={};for(let n=0;n{if(n){const o=n.split(M$);o.length>1&&(t[o[0].trim()]=o[1].trim())}}),t}function N(e){let t="";if(nt(e))t=e;else if(Pe(e))for(let n=0;nEa(n,t))}const le=e=>nt(e)?e:e==null?"":Pe(e)||dt(e)&&(e.toString===gw||!Xe(e.toString))?JSON.stringify(e,yw,2):String(e),yw=(e,t)=>t&&t.__v_isRef?yw(e,t.value):as(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((n,[o,r])=>(n[`${o} =>`]=r,n),{})}:Il(t)?{[`Set(${t.size})`]:[...t.values()]}:dt(t)&&!Pe(t)&&!nd(t)?String(t):t;let po;class Fm{constructor(t=!1){this.detached=t,this._active=!0,this.effects=[],this.cleanups=[],this.parent=po,!t&&po&&(this.index=(po.scopes||(po.scopes=[])).push(this)-1)}get active(){return this._active}run(t){if(this._active){const n=po;try{return po=this,t()}finally{po=n}}}on(){po=this}off(){po=this.parent}stop(t){if(this._active){let n,o;for(n=0,o=this.effects.length;n{const t=new Set(e);return t.w=0,t.n=0,t},_w=e=>(e.w&Ta)>0,Cw=e=>(e.n&Ta)>0,D$=({deps:e})=>{if(e.length)for(let t=0;t{const{deps:t}=e;if(t.length){let n=0;for(let o=0;o{(f==="length"||f>=u)&&s.push(c)})}else switch(n!==void 0&&s.push(l.get(n)),t){case"add":Pe(e)?Dm(n)&&s.push(l.get("length")):(s.push(l.get(al)),as(e)&&s.push(l.get(jp)));break;case"delete":Pe(e)||(s.push(l.get(al)),as(e)&&s.push(l.get(jp)));break;case"set":as(e)&&s.push(l.get(al));break}if(s.length===1)s[0]&&Wp(s[0]);else{const u=[];for(const c of s)c&&u.push(...c);Wp(Bm(u))}}function Wp(e,t){const n=Pe(e)?e:[...e];for(const o of n)o.computed&&pb(o);for(const o of n)o.computed||pb(o)}function pb(e,t){(e!==Go||e.allowRecurse)&&(e.scheduler?e.scheduler():e.run())}function H$(e,t){var n;return(n=ld.get(e))==null?void 0:n.get(t)}const z$=xd("__proto__,__v_isRef,__isVue"),Ew=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(zi)),j$=zd(),W$=zd(!1,!0),K$=zd(!0),U$=zd(!0,!0),hb=q$();function q$(){const e={};return["includes","indexOf","lastIndexOf"].forEach(t=>{e[t]=function(...n){const o=Mt(this);for(let a=0,l=this.length;a{e[t]=function(...n){Ks();const o=Mt(this)[t].apply(this,n);return Us(),o}}),e}function Y$(e){const t=Mt(this);return uo(t,"has",e),t.hasOwnProperty(e)}function zd(e=!1,t=!1){return function(o,r,a){if(r==="__v_isReactive")return!e;if(r==="__v_isReadonly")return e;if(r==="__v_isShallow")return t;if(r==="__v_raw"&&a===(e?t?Aw:Mw:t?Iw:Nw).get(o))return o;const l=Pe(o);if(!e){if(l&&Tt(hb,r))return Reflect.get(hb,r,a);if(r==="hasOwnProperty")return Y$}const s=Reflect.get(o,r,a);return(zi(r)?Ew.has(r):z$(r))||(e||uo(o,"get",r),t)?s:xt(s)?l&&Dm(r)?s:s.value:dt(s)?e?Ml(s):Et(s):s}}const G$=Tw(),X$=Tw(!0);function Tw(e=!1){return function(n,o,r,a){let l=n[o];if(ml(l)&&xt(l)&&!xt(r))return!1;if(!e&&(!ji(r)&&!ml(r)&&(l=Mt(l),r=Mt(r)),!Pe(n)&&xt(l)&&!xt(r)))return l.value=r,!0;const s=Pe(n)&&Dm(o)?Number(o)e,jd=e=>Reflect.getPrototypeOf(e);function Gu(e,t,n=!1,o=!1){e=e.__v_raw;const r=Mt(e),a=Mt(t);n||(t!==a&&uo(r,"get",t),uo(r,"get",a));const{has:l}=jd(r),s=o?Vm:n?jm:Wi;if(l.call(r,t))return s(e.get(t));if(l.call(r,a))return s(e.get(a));e!==r&&e.get(t)}function Xu(e,t=!1){const n=this.__v_raw,o=Mt(n),r=Mt(e);return t||(e!==r&&uo(o,"has",e),uo(o,"has",r)),e===r?n.has(e):n.has(e)||n.has(r)}function Ju(e,t=!1){return e=e.__v_raw,!t&&uo(Mt(e),"iterate",al),Reflect.get(e,"size",e)}function mb(e){e=Mt(e);const t=Mt(this);return jd(t).has.call(t,e)||(t.add(e),Kr(t,"add",e,e)),this}function vb(e,t){t=Mt(t);const n=Mt(this),{has:o,get:r}=jd(n);let a=o.call(n,e);a||(e=Mt(e),a=o.call(n,e));const l=r.call(n,e);return n.set(e,t),a?gs(t,l)&&Kr(n,"set",e,t):Kr(n,"add",e,t),this}function gb(e){const t=Mt(this),{has:n,get:o}=jd(t);let r=n.call(t,e);r||(e=Mt(e),r=n.call(t,e)),o&&o.call(t,e);const a=t.delete(e);return r&&Kr(t,"delete",e,void 0),a}function bb(){const e=Mt(this),t=e.size!==0,n=e.clear();return t&&Kr(e,"clear",void 0,void 0),n}function Zu(e,t){return function(o,r){const a=this,l=a.__v_raw,s=Mt(l),u=t?Vm:e?jm:Wi;return!e&&uo(s,"iterate",al),l.forEach((c,f)=>o.call(r,u(c),u(f),a))}}function Qu(e,t,n){return function(...o){const r=this.__v_raw,a=Mt(r),l=as(a),s=e==="entries"||e===Symbol.iterator&&l,u=e==="keys"&&l,c=r[e](...o),f=n?Vm:t?jm:Wi;return!t&&uo(a,"iterate",u?jp:al),{next(){const{value:d,done:p}=c.next();return p?{value:d,done:p}:{value:s?[f(d[0]),f(d[1])]:f(d),done:p}},[Symbol.iterator](){return this}}}}function aa(e){return function(...t){return e==="delete"?!1:this}}function nO(){const e={get(a){return Gu(this,a)},get size(){return Ju(this)},has:Xu,add:mb,set:vb,delete:gb,clear:bb,forEach:Zu(!1,!1)},t={get(a){return Gu(this,a,!1,!0)},get size(){return Ju(this)},has:Xu,add:mb,set:vb,delete:gb,clear:bb,forEach:Zu(!1,!0)},n={get(a){return Gu(this,a,!0)},get size(){return Ju(this,!0)},has(a){return Xu.call(this,a,!0)},add:aa("add"),set:aa("set"),delete:aa("delete"),clear:aa("clear"),forEach:Zu(!0,!1)},o={get(a){return Gu(this,a,!0,!0)},get size(){return Ju(this,!0)},has(a){return Xu.call(this,a,!0)},add:aa("add"),set:aa("set"),delete:aa("delete"),clear:aa("clear"),forEach:Zu(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach(a=>{e[a]=Qu(a,!1,!1),n[a]=Qu(a,!0,!1),t[a]=Qu(a,!1,!0),o[a]=Qu(a,!0,!0)}),[e,n,t,o]}const[oO,rO,aO,lO]=nO();function Wd(e,t){const n=t?e?lO:aO:e?rO:oO;return(o,r,a)=>r==="__v_isReactive"?!e:r==="__v_isReadonly"?e:r==="__v_raw"?o:Reflect.get(Tt(n,r)&&r in o?n:o,r,a)}const sO={get:Wd(!1,!1)},iO={get:Wd(!1,!0)},uO={get:Wd(!0,!1)},cO={get:Wd(!0,!0)},Nw=new WeakMap,Iw=new WeakMap,Mw=new WeakMap,Aw=new WeakMap;function dO(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function fO(e){return e.__v_skip||!Object.isExtensible(e)?0:dO(Tc(e))}function Et(e){return ml(e)?e:Kd(e,!1,$w,sO,Nw)}function Hm(e){return Kd(e,!1,eO,iO,Iw)}function Ml(e){return Kd(e,!0,Ow,uO,Mw)}function pO(e){return Kd(e,!0,tO,cO,Aw)}function Kd(e,t,n,o,r){if(!dt(e)||e.__v_raw&&!(t&&e.__v_isReactive))return e;const a=r.get(e);if(a)return a;const l=fO(e);if(l===0)return e;const s=new Proxy(e,l===2?o:n);return r.set(e,s),s}function jr(e){return ml(e)?jr(e.__v_raw):!!(e&&e.__v_isReactive)}function ml(e){return!!(e&&e.__v_isReadonly)}function ji(e){return!!(e&&e.__v_isShallow)}function zm(e){return jr(e)||ml(e)}function Mt(e){const t=e&&e.__v_raw;return t?Mt(t):e}function Po(e){return od(e,"__v_skip",!0),e}const Wi=e=>dt(e)?Et(e):e,jm=e=>dt(e)?Ml(e):e;function Wm(e){wa&&Go&&(e=Mt(e),kw(e.dep||(e.dep=Bm())))}function Ud(e,t){e=Mt(e);const n=e.dep;n&&Wp(n)}function xt(e){return!!(e&&e.__v_isRef===!0)}function R(e){return Pw(e,!1)}function Ut(e){return Pw(e,!0)}function Pw(e,t){return xt(e)?e:new hO(e,t)}class hO{constructor(t,n){this.__v_isShallow=n,this.dep=void 0,this.__v_isRef=!0,this._rawValue=n?t:Mt(t),this._value=n?t:Wi(t)}get value(){return Wm(this),this._value}set value(t){const n=this.__v_isShallow||ji(t)||ml(t);t=n?t:Mt(t),gs(t,this._rawValue)&&(this._rawValue=t,this._value=n?t:Wi(t),Ud(this))}}function mO(e){Ud(e)}function i(e){return xt(e)?e.value:e}function vO(e){return Xe(e)?e():i(e)}const gO={get:(e,t,n)=>i(Reflect.get(e,t,n)),set:(e,t,n,o)=>{const r=e[t];return xt(r)&&!xt(n)?(r.value=n,!0):Reflect.set(e,t,n,o)}};function Km(e){return jr(e)?e:new Proxy(e,gO)}class bO{constructor(t){this.dep=void 0,this.__v_isRef=!0;const{get:n,set:o}=t(()=>Wm(this),()=>Ud(this));this._get=n,this._set=o}get value(){return this._get()}set value(t){this._set(t)}}function Rw(e){return new bO(e)}function Cn(e){const t=Pe(e)?new Array(e.length):{};for(const n in e)t[n]=Lw(e,n);return t}class yO{constructor(t,n,o){this._object=t,this._key=n,this._defaultValue=o,this.__v_isRef=!0}get value(){const t=this._object[this._key];return t===void 0?this._defaultValue:t}set value(t){this._object[this._key]=t}get dep(){return H$(Mt(this._object),this._key)}}class wO{constructor(t){this._getter=t,this.__v_isRef=!0,this.__v_isReadonly=!0}get value(){return this._getter()}}function Lt(e,t,n){return xt(e)?e:Xe(e)?new wO(e):dt(e)&&arguments.length>1?Lw(e,t,n):R(e)}function Lw(e,t,n){const o=e[t];return xt(o)?o:new yO(e,t,n)}class _O{constructor(t,n,o,r){this._setter=n,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this._dirty=!0,this.effect=new wu(t,()=>{this._dirty||(this._dirty=!0,Ud(this))}),this.effect.computed=this,this.effect.active=this._cacheable=!r,this.__v_isReadonly=o}get value(){const t=Mt(this);return Wm(t),(t._dirty||!t._cacheable)&&(t._dirty=!1,t._value=t.effect.run()),t._value}set value(t){this._setter(t)}}function CO(e,t,n=!1){let o,r;const a=Xe(e);return a?(o=e,r=Bt):(o=e.get,r=e.set),new _O(o,r,a||!r,n)}function xw(e,...t){}function SO(e,t){}function Wr(e,t,n,o){let r;try{r=o?e(...o):e()}catch(a){Al(a,t,n)}return r}function yo(e,t,n,o){if(Xe(e)){const a=Wr(e,t,n,o);return a&&vs(a)&&a.catch(l=>{Al(l,t,n)}),a}const r=[];for(let a=0;a>>1;Ui(Hn[o])hr&&Hn.splice(t,1)}function qm(e){Pe(e)?is.push(...e):(!Br||!Br.includes(e,e.allowRecurse?qa+1:qa))&&is.push(e),Fw()}function yb(e,t=Ki?hr+1:0){for(;tUi(n)-Ui(o)),qa=0;qae.id==null?1/0:e.id,$O=(e,t)=>{const n=Ui(e)-Ui(t);if(n===0){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function Bw(e){Kp=!1,Ki=!0,Hn.sort($O);try{for(hr=0;hrXl.emit(r,...a)),ec=[]):typeof window<"u"&&window.HTMLElement&&!((o=(n=window.navigator)==null?void 0:n.userAgent)!=null&&o.includes("jsdom"))?((t.__VUE_DEVTOOLS_HOOK_REPLAY__=t.__VUE_DEVTOOLS_HOOK_REPLAY__||[]).push(a=>{Vw(a,t)}),setTimeout(()=>{Xl||(t.__VUE_DEVTOOLS_HOOK_REPLAY__=null,ec=[])},3e3)):ec=[]}function OO(e,t,...n){if(e.isUnmounted)return;const o=e.vnode.props||Zt;let r=n;const a=t.startsWith("update:"),l=a&&t.slice(7);if(l&&l in o){const f=`${l==="modelValue"?"model":l}Modifiers`,{number:d,trim:p}=o[f]||Zt;p&&(r=n.map(m=>nt(m)?m.trim():m)),d&&(r=n.map(rd))}let s,u=o[s=ls(t)]||o[s=ls(jn(t))];!u&&a&&(u=o[s=ls(mo(t))]),u&&yo(u,e,6,r);const c=o[s+"Once"];if(c){if(!e.emitted)e.emitted={};else if(e.emitted[s])return;e.emitted[s]=!0,yo(c,e,6,r)}}function Hw(e,t,n=!1){const o=t.emitsCache,r=o.get(e);if(r!==void 0)return r;const a=e.emits;let l={},s=!1;if(!Xe(e)){const u=c=>{const f=Hw(c,t,!0);f&&(s=!0,an(l,f))};!n&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}return!a&&!s?(dt(e)&&o.set(e,null),null):(Pe(a)?a.forEach(u=>l[u]=null):an(l,a),dt(e)&&o.set(e,l),l)}function Yd(e,t){return!e||!yu(t)?!1:(t=t.slice(2).replace(/Once$/,""),Tt(e,t[0].toLowerCase()+t.slice(1))||Tt(e,mo(t))||Tt(e,t))}let In=null,Gd=null;function qi(e){const t=In;return In=e,Gd=e&&e.type.__scopeId||null,t}function Xd(e){Gd=e}function Jd(){Gd=null}const NO=e=>X;function X(e,t=In,n){if(!t||e._n)return e;const o=(...r)=>{o._d&&Zp(-1);const a=qi(t);let l;try{l=e(...r)}finally{qi(a),o._d&&Zp(1)}return l};return o._n=!0,o._c=!0,o._d=!0,o}function $c(e){const{type:t,vnode:n,proxy:o,withProxy:r,props:a,propsOptions:[l],slots:s,attrs:u,emit:c,render:f,renderCache:d,data:p,setupState:m,ctx:v,inheritAttrs:h}=e;let C,g;const y=qi(e);try{if(n.shapeFlag&4){const b=r||o;C=ho(f.call(b,b,d,a,m,p,v)),g=u}else{const b=t;C=ho(b.length>1?b(a,{attrs:u,slots:s,emit:c}):b(a,null)),g=t.props?u:MO(u)}}catch(b){Ii.length=0,Al(b,e,1),C=K(En)}let _=C;if(g&&h!==!1){const b=Object.keys(g),{shapeFlag:w}=_;b.length&&w&7&&(l&&b.some(Lm)&&(g=AO(g,l)),_=Qo(_,g))}return n.dirs&&(_=Qo(_),_.dirs=_.dirs?_.dirs.concat(n.dirs):n.dirs),n.transition&&(_.transition=n.transition),C=_,qi(y),C}function IO(e){let t;for(let n=0;n{let t;for(const n in e)(n==="class"||n==="style"||yu(n))&&((t||(t={}))[n]=e[n]);return t},AO=(e,t)=>{const n={};for(const o in e)(!Lm(o)||!(o.slice(9)in t))&&(n[o]=e[o]);return n};function PO(e,t,n){const{props:o,children:r,component:a}=e,{props:l,children:s,patchFlag:u}=t,c=a.emitsOptions;if(t.dirs||t.transition)return!0;if(n&&u>=0){if(u&1024)return!0;if(u&16)return o?wb(o,l,c):!!l;if(u&8){const f=t.dynamicProps;for(let d=0;de.__isSuspense,RO={name:"Suspense",__isSuspense:!0,process(e,t,n,o,r,a,l,s,u,c){e==null?xO(t,n,o,r,a,l,s,u,c):DO(e,t,n,o,r,l,s,u,c)},hydrate:FO,create:Gm,normalize:BO},LO=RO;function Yi(e,t){const n=e.props&&e.props[t];Xe(n)&&n()}function xO(e,t,n,o,r,a,l,s,u){const{p:c,o:{createElement:f}}=u,d=f("div"),p=e.suspense=Gm(e,r,o,t,d,n,a,l,s,u);c(null,p.pendingBranch=e.ssContent,d,null,o,p,a,l),p.deps>0?(Yi(e,"onPending"),Yi(e,"onFallback"),c(null,e.ssFallback,t,n,o,null,a,l),us(p,e.ssFallback)):p.resolve(!1,!0)}function DO(e,t,n,o,r,a,l,s,{p:u,um:c,o:{createElement:f}}){const d=t.suspense=e.suspense;d.vnode=t,t.el=e.el;const p=t.ssContent,m=t.ssFallback,{activeBranch:v,pendingBranch:h,isInFallback:C,isHydrating:g}=d;if(h)d.pendingBranch=p,Xo(p,h)?(u(h,p,d.hiddenContainer,null,r,d,a,l,s),d.deps<=0?d.resolve():C&&(u(v,m,n,o,r,null,a,l,s),us(d,m))):(d.pendingId++,g?(d.isHydrating=!1,d.activeBranch=h):c(h,r,d),d.deps=0,d.effects.length=0,d.hiddenContainer=f("div"),C?(u(null,p,d.hiddenContainer,null,r,d,a,l,s),d.deps<=0?d.resolve():(u(v,m,n,o,r,null,a,l,s),us(d,m))):v&&Xo(p,v)?(u(v,p,n,o,r,d,a,l,s),d.resolve(!0)):(u(null,p,d.hiddenContainer,null,r,d,a,l,s),d.deps<=0&&d.resolve()));else if(v&&Xo(p,v))u(v,p,n,o,r,d,a,l,s),us(d,p);else if(Yi(t,"onPending"),d.pendingBranch=p,d.pendingId++,u(null,p,d.hiddenContainer,null,r,d,a,l,s),d.deps<=0)d.resolve();else{const{timeout:y,pendingId:_}=d;y>0?setTimeout(()=>{d.pendingId===_&&d.fallback(m)},y):y===0&&d.fallback(m)}}function Gm(e,t,n,o,r,a,l,s,u,c,f=!1){const{p:d,m:p,um:m,n:v,o:{parentNode:h,remove:C}}=c;let g;const y=VO(e);y&&t!=null&&t.pendingBranch&&(g=t.pendingId,t.deps++);const _=e.props?ad(e.props.timeout):void 0,b={vnode:e,parent:t,parentComponent:n,isSVG:l,container:o,hiddenContainer:r,anchor:a,deps:0,pendingId:0,timeout:typeof _=="number"?_:-1,activeBranch:null,pendingBranch:null,isInFallback:!0,isHydrating:f,isUnmounted:!1,effects:[],resolve(w=!1,S=!1){const{vnode:E,activeBranch:$,pendingBranch:O,pendingId:A,effects:M,parentComponent:D,container:U}=b;if(b.isHydrating)b.isHydrating=!1;else if(!w){const L=$&&O.transition&&O.transition.mode==="out-in";L&&($.transition.afterLeave=()=>{A===b.pendingId&&p(O,U,P,0)});let{anchor:P}=b;$&&(P=v($),m($,D,b,!0)),L||p(O,U,P,0)}us(b,O),b.pendingBranch=null,b.isInFallback=!1;let j=b.parent,W=!1;for(;j;){if(j.pendingBranch){j.effects.push(...M),W=!0;break}j=j.parent}W||qm(M),b.effects=[],y&&t&&t.pendingBranch&&g===t.pendingId&&(t.deps--,t.deps===0&&!S&&t.resolve()),Yi(E,"onResolve")},fallback(w){if(!b.pendingBranch)return;const{vnode:S,activeBranch:E,parentComponent:$,container:O,isSVG:A}=b;Yi(S,"onFallback");const M=v(E),D=()=>{b.isInFallback&&(d(null,w,O,M,$,null,A,s,u),us(b,w))},U=w.transition&&w.transition.mode==="out-in";U&&(E.transition.afterLeave=D),b.isInFallback=!0,m(E,$,null,!0),U||D()},move(w,S,E){b.activeBranch&&p(b.activeBranch,w,S,E),b.container=w},next(){return b.activeBranch&&v(b.activeBranch)},registerDep(w,S){const E=!!b.pendingBranch;E&&b.deps++;const $=w.vnode.el;w.asyncDep.catch(O=>{Al(O,w,0)}).then(O=>{if(w.isUnmounted||b.isUnmounted||b.pendingId!==w.suspenseId)return;w.asyncResolved=!0;const{vnode:A}=w;Qp(w,O,!1),$&&(A.el=$);const M=!$&&w.subTree.el;S(w,A,h($||w.subTree.el),$?null:v(w.subTree),b,l,u),M&&C(M),Ym(w,A.el),E&&--b.deps===0&&b.resolve()})},unmount(w,S){b.isUnmounted=!0,b.activeBranch&&m(b.activeBranch,n,w,S),b.pendingBranch&&m(b.pendingBranch,n,w,S)}};return b}function FO(e,t,n,o,r,a,l,s,u){const c=t.suspense=Gm(t,o,n,e.parentNode,document.createElement("div"),null,r,a,l,s,!0),f=u(e,c.pendingBranch=t.ssContent,n,c,a,l);return c.deps===0&&c.resolve(!1,!0),f}function BO(e){const{shapeFlag:t,children:n}=e,o=t&32;e.ssContent=_b(o?n.default:n),e.ssFallback=o?_b(n.fallback):K(En)}function _b(e){let t;if(Xe(e)){const n=gl&&e._c;n&&(e._d=!1,T()),e=e(),n&&(e._d=!0,t=ao,m_())}return Pe(e)&&(e=IO(e)),e=ho(e),t&&!e.dynamicChildren&&(e.dynamicChildren=t.filter(n=>n!==e)),e}function jw(e,t){t&&t.pendingBranch?Pe(e)?t.effects.push(...e):t.effects.push(e):qm(e)}function us(e,t){e.activeBranch=t;const{vnode:n,parentComponent:o}=e,r=n.el=t.el;o&&o.subTree===n&&(o.vnode.el=r,Ym(o,r))}function VO(e){var t;return((t=e.props)==null?void 0:t.suspensible)!=null&&e.props.suspensible!==!1}function Mn(e,t){return _u(e,null,t)}function Ww(e,t){return _u(e,null,{flush:"post"})}function HO(e,t){return _u(e,null,{flush:"sync"})}const tc={};function ve(e,t,n){return _u(e,t,n)}function _u(e,t,{immediate:n,deep:o,flush:r,onTrack:a,onTrigger:l}=Zt){var s;const u=Vd()===((s=bn)==null?void 0:s.scope)?bn:null;let c,f=!1,d=!1;if(xt(e)?(c=()=>e.value,f=ji(e)):jr(e)?(c=()=>e,o=!0):Pe(e)?(d=!0,f=e.some(b=>jr(b)||ji(b)),c=()=>e.map(b=>{if(xt(b))return b.value;if(jr(b))return Ja(b);if(Xe(b))return Wr(b,u,2)})):Xe(e)?t?c=()=>Wr(e,u,2):c=()=>{if(!(u&&u.isUnmounted))return p&&p(),yo(e,u,3,[m])}:c=Bt,t&&o){const b=c;c=()=>Ja(b())}let p,m=b=>{p=y.onStop=()=>{Wr(b,u,4)}},v;if(ys)if(m=Bt,t?n&&yo(t,u,3,[c(),d?[]:void 0,m]):c(),r==="sync"){const b=k_();v=b.__watcherHandles||(b.__watcherHandles=[])}else return Bt;let h=d?new Array(e.length).fill(tc):tc;const C=()=>{if(y.active)if(t){const b=y.run();(o||f||(d?b.some((w,S)=>gs(w,h[S])):gs(b,h)))&&(p&&p(),yo(t,u,3,[b,h===tc?void 0:d&&h[0]===tc?[]:h,m]),h=b)}else y.run()};C.allowRecurse=!!t;let g;r==="sync"?g=C:r==="post"?g=()=>Pn(C,u&&u.suspense):(C.pre=!0,u&&(C.id=u.uid),g=()=>qd(C));const y=new wu(c,g);t?n?C():h=y.run():r==="post"?Pn(y.run.bind(y),u&&u.suspense):y.run();const _=()=>{y.stop(),u&&u.scope&&xm(u.scope.effects,y)};return v&&v.push(_),_}function zO(e,t,n){const o=this.proxy,r=nt(e)?e.includes(".")?Kw(o,e):()=>o[e]:e.bind(o,o);let a;Xe(t)?a=t:(a=t.handler,n=t);const l=bn;$a(this);const s=_u(r,a.bind(o),n);return l?$a(l):_a(),s}function Kw(e,t){const n=t.split(".");return()=>{let o=e;for(let r=0;r{Ja(n,t)});else if(nd(e))for(const n in e)Ja(e[n],t);return e}function tt(e,t){const n=In;if(n===null)return e;const o=tf(n)||n.proxy,r=e.dirs||(e.dirs=[]);for(let a=0;a{e.isMounted=!0}),zt(()=>{e.isUnmounting=!0}),e}const Eo=[Function,Array],Jm={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:Eo,onEnter:Eo,onAfterEnter:Eo,onEnterCancelled:Eo,onBeforeLeave:Eo,onLeave:Eo,onAfterLeave:Eo,onLeaveCancelled:Eo,onBeforeAppear:Eo,onAppear:Eo,onAfterAppear:Eo,onAppearCancelled:Eo},jO={name:"BaseTransition",props:Jm,setup(e,{slots:t}){const n=lt(),o=Xm();let r;return()=>{const a=t.default&&Zd(t.default(),!0);if(!a||!a.length)return;let l=a[0];if(a.length>1){for(const h of a)if(h.type!==En){l=h;break}}const s=Mt(e),{mode:u}=s;if(o.isLeaving)return Jf(l);const c=Cb(l);if(!c)return Jf(l);const f=bs(c,s,o,n);vl(c,f);const d=n.subTree,p=d&&Cb(d);let m=!1;const{getTransitionKey:v}=c.type;if(v){const h=v();r===void 0?r=h:h!==r&&(r=h,m=!0)}if(p&&p.type!==En&&(!Xo(c,p)||m)){const h=bs(p,s,o,n);if(vl(p,h),u==="out-in")return o.isLeaving=!0,h.afterLeave=()=>{o.isLeaving=!1,n.update.active!==!1&&n.update()},Jf(l);u==="in-out"&&c.type!==En&&(h.delayLeave=(C,g,y)=>{const _=qw(o,p);_[String(p.key)]=p,C._leaveCb=()=>{g(),C._leaveCb=void 0,delete f.delayedLeave},f.delayedLeave=y})}return l}}},Uw=jO;function qw(e,t){const{leavingVNodes:n}=e;let o=n.get(t.type);return o||(o=Object.create(null),n.set(t.type,o)),o}function bs(e,t,n,o){const{appear:r,mode:a,persisted:l=!1,onBeforeEnter:s,onEnter:u,onAfterEnter:c,onEnterCancelled:f,onBeforeLeave:d,onLeave:p,onAfterLeave:m,onLeaveCancelled:v,onBeforeAppear:h,onAppear:C,onAfterAppear:g,onAppearCancelled:y}=t,_=String(e.key),b=qw(n,e),w=($,O)=>{$&&yo($,o,9,O)},S=($,O)=>{const A=O[1];w($,O),Pe($)?$.every(M=>M.length<=1)&&A():$.length<=1&&A()},E={mode:a,persisted:l,beforeEnter($){let O=s;if(!n.isMounted)if(r)O=h||s;else return;$._leaveCb&&$._leaveCb(!0);const A=b[_];A&&Xo(e,A)&&A.el._leaveCb&&A.el._leaveCb(),w(O,[$])},enter($){let O=u,A=c,M=f;if(!n.isMounted)if(r)O=C||u,A=g||c,M=y||f;else return;let D=!1;const U=$._enterCb=j=>{D||(D=!0,j?w(M,[$]):w(A,[$]),E.delayedLeave&&E.delayedLeave(),$._enterCb=void 0)};O?S(O,[$,U]):U()},leave($,O){const A=String(e.key);if($._enterCb&&$._enterCb(!0),n.isUnmounting)return O();w(d,[$]);let M=!1;const D=$._leaveCb=U=>{M||(M=!0,O(),U?w(v,[$]):w(m,[$]),$._leaveCb=void 0,b[A]===e&&delete b[A])};b[A]=e,p?S(p,[$,D]):D()},clone($){return bs($,t,n,o)}};return E}function Jf(e){if(Cu(e))return e=Qo(e),e.children=null,e}function Cb(e){return Cu(e)?e.children?e.children[0]:void 0:e}function vl(e,t){e.shapeFlag&6&&e.component?vl(e.component.subTree,t):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Zd(e,t=!1,n){let o=[],r=0;for(let a=0;a1)for(let a=0;a!!e.type.__asyncLoader;function WO(e){Xe(e)&&(e={loader:e});const{loader:t,loadingComponent:n,errorComponent:o,delay:r=200,timeout:a,suspensible:l=!0,onError:s}=e;let u=null,c,f=0;const d=()=>(f++,u=null,p()),p=()=>{let m;return u||(m=u=t().catch(v=>{if(v=v instanceof Error?v:new Error(String(v)),s)return new Promise((h,C)=>{s(v,()=>h(d()),()=>C(v),f+1)});throw v}).then(v=>m!==u&&u?u:(v&&(v.__esModule||v[Symbol.toStringTag]==="Module")&&(v=v.default),c=v,v)))};return Y({name:"AsyncComponentWrapper",__asyncLoader:p,get __asyncResolved(){return c},setup(){const m=bn;if(c)return()=>Zf(c,m);const v=y=>{u=null,Al(y,m,13,!o)};if(l&&m.suspense||ys)return p().then(y=>()=>Zf(y,m)).catch(y=>(v(y),()=>o?K(o,{error:y}):null));const h=R(!1),C=R(),g=R(!!r);return r&&setTimeout(()=>{g.value=!1},r),a!=null&&setTimeout(()=>{if(!h.value&&!C.value){const y=new Error(`Async component timed out after ${a}ms.`);v(y),C.value=y}},a),p().then(()=>{h.value=!0,m.parent&&Cu(m.parent.vnode)&&qd(m.parent.update)}).catch(y=>{v(y),C.value=y}),()=>{if(h.value&&c)return Zf(c,m);if(C.value&&o)return K(o,{error:C.value});if(n&&!g.value)return K(n)}}})}function Zf(e,t){const{ref:n,props:o,children:r,ce:a}=t.vnode,l=K(e,o,r);return l.ref=n,l.ce=a,delete t.vnode.ce,l}const Cu=e=>e.type.__isKeepAlive,KO={name:"KeepAlive",__isKeepAlive:!0,props:{include:[String,RegExp,Array],exclude:[String,RegExp,Array],max:[String,Number]},setup(e,{slots:t}){const n=lt(),o=n.ctx;if(!o.renderer)return()=>{const y=t.default&&t.default();return y&&y.length===1?y[0]:y};const r=new Map,a=new Set;let l=null;const s=n.suspense,{renderer:{p:u,m:c,um:f,o:{createElement:d}}}=o,p=d("div");o.activate=(y,_,b,w,S)=>{const E=y.component;c(y,_,b,0,s),u(E.vnode,y,_,b,E,s,w,y.slotScopeIds,S),Pn(()=>{E.isDeactivated=!1,E.a&&ss(E.a);const $=y.props&&y.props.onVnodeMounted;$&&ro($,E.parent,y)},s)},o.deactivate=y=>{const _=y.component;c(y,p,null,1,s),Pn(()=>{_.da&&ss(_.da);const b=y.props&&y.props.onVnodeUnmounted;b&&ro(b,_.parent,y),_.isDeactivated=!0},s)};function m(y){Qf(y),f(y,n,s,!0)}function v(y){r.forEach((_,b)=>{const w=th(_.type);w&&(!y||!y(w))&&h(b)})}function h(y){const _=r.get(y);!l||!Xo(_,l)?m(_):l&&Qf(l),r.delete(y),a.delete(y)}ve(()=>[e.include,e.exclude],([y,_])=>{y&&v(b=>Ci(y,b)),_&&v(b=>!Ci(_,b))},{flush:"post",deep:!0});let C=null;const g=()=>{C!=null&&r.set(C,ep(n.subTree))};return at(g),ar(g),zt(()=>{r.forEach(y=>{const{subTree:_,suspense:b}=n,w=ep(_);if(y.type===w.type&&y.key===w.key){Qf(w);const S=w.component.da;S&&Pn(S,b);return}m(y)})}),()=>{if(C=null,!t.default)return null;const y=t.default(),_=y[0];if(y.length>1)return l=null,y;if(!Wt(_)||!(_.shapeFlag&4)&&!(_.shapeFlag&128))return l=null,_;let b=ep(_);const w=b.type,S=th(ll(b)?b.type.__asyncResolved||{}:w),{include:E,exclude:$,max:O}=e;if(E&&(!S||!Ci(E,S))||$&&S&&Ci($,S))return l=b,_;const A=b.key==null?w:b.key,M=r.get(A);return b.el&&(b=Qo(b),_.shapeFlag&128&&(_.ssContent=b)),C=A,M?(b.el=M.el,b.component=M.component,b.transition&&vl(b,b.transition),b.shapeFlag|=512,a.delete(A),a.add(A)):(a.add(A),O&&a.size>parseInt(O,10)&&h(a.values().next().value)),b.shapeFlag|=256,l=b,zw(_.type)?_:b}}},UO=KO;function Ci(e,t){return Pe(e)?e.some(n=>Ci(n,t)):nt(e)?e.split(",").includes(t):E$(e)?e.test(t):!1}function Zm(e,t){Yw(e,"a",t)}function Qm(e,t){Yw(e,"da",t)}function Yw(e,t,n=bn){const o=e.__wdc||(e.__wdc=()=>{let r=n;for(;r;){if(r.isDeactivated)return;r=r.parent}return e()});if(Qd(t,o,n),n){let r=n.parent;for(;r&&r.parent;)Cu(r.parent.vnode)&&qO(o,t,n,r),r=r.parent}}function qO(e,t,n,o){const r=Qd(t,e,o,!0);lr(()=>{xm(o[t],r)},n)}function Qf(e){e.shapeFlag&=-257,e.shapeFlag&=-513}function ep(e){return e.shapeFlag&128?e.ssContent:e}function Qd(e,t,n=bn,o=!1){if(n){const r=n[e]||(n[e]=[]),a=t.__weh||(t.__weh=(...l)=>{if(n.isUnmounted)return;Ks(),$a(n);const s=yo(t,n,e,l);return _a(),Us(),s});return o?r.unshift(a):r.push(a),a}}const Xr=e=>(t,n=bn)=>(!ys||e==="sp")&&Qd(e,(...o)=>t(...o),n),Su=Xr("bm"),at=Xr("m"),ev=Xr("bu"),ar=Xr("u"),zt=Xr("bum"),lr=Xr("um"),Gw=Xr("sp"),Xw=Xr("rtg"),Jw=Xr("rtc");function Zw(e,t=bn){Qd("ec",e,t)}const tv="components",YO="directives";function qe(e,t){return nv(tv,e,!0,t)||e}const Qw=Symbol.for("v-ndc");function pt(e){return nt(e)?nv(tv,e,!1)||e:e||Qw}function qs(e){return nv(YO,e)}function nv(e,t,n=!0,o=!1){const r=In||bn;if(r){const a=r.type;if(e===tv){const s=th(a,!1);if(s&&(s===t||s===jn(t)||s===Ws(jn(t))))return a}const l=Sb(r[e]||a[e],t)||Sb(r.appContext[e],t);return!l&&o?a:l}}function Sb(e,t){return e&&(e[t]||e[jn(t)]||e[Ws(jn(t))])}function bt(e,t,n,o){let r;const a=n&&n[o];if(Pe(e)||nt(e)){r=new Array(e.length);for(let l=0,s=e.length;lt(l,s,void 0,a&&a[s]));else{const l=Object.keys(e);r=new Array(l.length);for(let s=0,u=l.length;s{const a=o.fn(...r);return a&&(a.key=o.key),a}:o.fn)}return e}function ie(e,t,n={},o,r){if(In.isCE||In.parent&&ll(In.parent)&&In.parent.isCE)return t!=="default"&&(n.name=t),K("slot",n,o&&o());let a=e[t];a&&a._c&&(a._d=!1),T();const l=a&&e_(a(n)),s=re(Ve,{key:n.key||l&&l.key||`_${t}`},l||(o?o():[]),l&&e._===1?64:-2);return!r&&s.scopeId&&(s.slotScopeIds=[s.scopeId+"-s"]),a&&a._c&&(a._d=!0),s}function e_(e){return e.some(t=>Wt(t)?!(t.type===En||t.type===Ve&&!e_(t.children)):!0)?e:null}function t_(e,t){const n={};for(const o in e)n[t&&/[A-Z]/.test(o)?`on:${o}`:ls(o)]=e[o];return n}const Up=e=>e?y_(e)?tf(e)||e.proxy:Up(e.parent):null,Oi=an(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Up(e.parent),$root:e=>Up(e.root),$emit:e=>e.emit,$options:e=>ov(e),$forceUpdate:e=>e.f||(e.f=()=>qd(e.update)),$nextTick:e=>e.n||(e.n=We.bind(e.proxy)),$watch:e=>zO.bind(e)}),tp=(e,t)=>e!==Zt&&!e.__isScriptSetup&&Tt(e,t),qp={get({_:e},t){const{ctx:n,setupState:o,data:r,props:a,accessCache:l,type:s,appContext:u}=e;let c;if(t[0]!=="$"){const m=l[t];if(m!==void 0)switch(m){case 1:return o[t];case 2:return r[t];case 4:return n[t];case 3:return a[t]}else{if(tp(o,t))return l[t]=1,o[t];if(r!==Zt&&Tt(r,t))return l[t]=2,r[t];if((c=e.propsOptions[0])&&Tt(c,t))return l[t]=3,a[t];if(n!==Zt&&Tt(n,t))return l[t]=4,n[t];Yp&&(l[t]=0)}}const f=Oi[t];let d,p;if(f)return t==="$attrs"&&uo(e,"get",t),f(e);if((d=s.__cssModules)&&(d=d[t]))return d;if(n!==Zt&&Tt(n,t))return l[t]=4,n[t];if(p=u.config.globalProperties,Tt(p,t))return p[t]},set({_:e},t,n){const{data:o,setupState:r,ctx:a}=e;return tp(r,t)?(r[t]=n,!0):o!==Zt&&Tt(o,t)?(o[t]=n,!0):Tt(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(a[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:o,appContext:r,propsOptions:a}},l){let s;return!!n[l]||e!==Zt&&Tt(e,l)||tp(t,l)||(s=a[0])&&Tt(s,l)||Tt(o,l)||Tt(Oi,l)||Tt(r.config.globalProperties,l)},defineProperty(e,t,n){return n.get!=null?e._.accessCache[t]=0:Tt(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}},GO=an({},qp,{get(e,t){if(t!==Symbol.unscopables)return qp.get(e,t,e)},has(e,t){return t[0]!=="_"&&!N$(t)}});function XO(){return null}function JO(){return null}function ZO(e){}function QO(e){}function eN(){return null}function tN(){}function nN(e,t){return null}function Sn(){return n_().slots}function xa(){return n_().attrs}function oN(e,t,n){const o=lt();if(n&&n.local){const r=R(e[t]);return ve(()=>e[t],a=>r.value=a),ve(r,a=>{a!==e[t]&&o.emit(`update:${t}`,a)}),r}else return{__v_isRef:!0,get value(){return e[t]},set value(r){o.emit(`update:${t}`,r)}}}function n_(){const e=lt();return e.setupContext||(e.setupContext=C_(e))}function Gi(e){return Pe(e)?e.reduce((t,n)=>(t[n]=null,t),{}):e}function rN(e,t){const n=Gi(e);for(const o in t){if(o.startsWith("__skip"))continue;let r=n[o];r?Pe(r)||Xe(r)?r=n[o]={type:r,default:t[o]}:r.default=t[o]:r===null&&(r=n[o]={default:t[o]}),r&&t[`__skip_${o}`]&&(r.skipFactory=!0)}return n}function aN(e,t){return!e||!t?e||t:Pe(e)&&Pe(t)?e.concat(t):an({},Gi(e),Gi(t))}function lN(e,t){const n={};for(const o in e)t.includes(o)||Object.defineProperty(n,o,{enumerable:!0,get:()=>e[o]});return n}function sN(e){const t=lt();let n=e();return _a(),vs(n)&&(n=n.catch(o=>{throw $a(t),o})),[n,()=>$a(t)]}let Yp=!0;function iN(e){const t=ov(e),n=e.proxy,o=e.ctx;Yp=!1,t.beforeCreate&&kb(t.beforeCreate,e,"bc");const{data:r,computed:a,methods:l,watch:s,provide:u,inject:c,created:f,beforeMount:d,mounted:p,beforeUpdate:m,updated:v,activated:h,deactivated:C,beforeDestroy:g,beforeUnmount:y,destroyed:_,unmounted:b,render:w,renderTracked:S,renderTriggered:E,errorCaptured:$,serverPrefetch:O,expose:A,inheritAttrs:M,components:D,directives:U,filters:j}=t;if(c&&uN(c,o,null),l)for(const P in l){const x=l[P];Xe(x)&&(o[P]=x.bind(n))}if(r){const P=r.call(n,n);dt(P)&&(e.data=Et(P))}if(Yp=!0,a)for(const P in a){const x=a[P],I=Xe(x)?x.bind(n,n):Xe(x.get)?x.get.bind(n,n):Bt,H=!Xe(x)&&Xe(x.set)?x.set.bind(n):Bt,G=k({get:I,set:H});Object.defineProperty(o,P,{enumerable:!0,configurable:!0,get:()=>G.value,set:J=>G.value=J})}if(s)for(const P in s)o_(s[P],o,n,P);if(u){const P=Xe(u)?u.call(n):u;Reflect.ownKeys(P).forEach(x=>{yt(x,P[x])})}f&&kb(f,e,"c");function L(P,x){Pe(x)?x.forEach(I=>P(I.bind(n))):x&&P(x.bind(n))}if(L(Su,d),L(at,p),L(ev,m),L(ar,v),L(Zm,h),L(Qm,C),L(Zw,$),L(Jw,S),L(Xw,E),L(zt,y),L(lr,b),L(Gw,O),Pe(A))if(A.length){const P=e.exposed||(e.exposed={});A.forEach(x=>{Object.defineProperty(P,x,{get:()=>n[x],set:I=>n[x]=I})})}else e.exposed||(e.exposed={});w&&e.render===Bt&&(e.render=w),M!=null&&(e.inheritAttrs=M),D&&(e.components=D),U&&(e.directives=U)}function uN(e,t,n=Bt){Pe(e)&&(e=Gp(e));for(const o in e){const r=e[o];let a;dt(r)?"default"in r?a=De(r.from||o,r.default,!0):a=De(r.from||o):a=De(r),xt(a)?Object.defineProperty(t,o,{enumerable:!0,configurable:!0,get:()=>a.value,set:l=>a.value=l}):t[o]=a}}function kb(e,t,n){yo(Pe(e)?e.map(o=>o.bind(t.proxy)):e.bind(t.proxy),t,n)}function o_(e,t,n,o){const r=o.includes(".")?Kw(n,o):()=>n[o];if(nt(e)){const a=t[e];Xe(a)&&ve(r,a)}else if(Xe(e))ve(r,e.bind(n));else if(dt(e))if(Pe(e))e.forEach(a=>o_(a,t,n,o));else{const a=Xe(e.handler)?e.handler.bind(n):t[e.handler];Xe(a)&&ve(r,a,e)}}function ov(e){const t=e.type,{mixins:n,extends:o}=t,{mixins:r,optionsCache:a,config:{optionMergeStrategies:l}}=e.appContext,s=a.get(t);let u;return s?u=s:!r.length&&!n&&!o?u=t:(u={},r.length&&r.forEach(c=>id(u,c,l,!0)),id(u,t,l)),dt(t)&&a.set(t,u),u}function id(e,t,n,o=!1){const{mixins:r,extends:a}=t;a&&id(e,a,n,!0),r&&r.forEach(l=>id(e,l,n,!0));for(const l in t)if(!(o&&l==="expose")){const s=cN[l]||n&&n[l];e[l]=s?s(e[l],t[l]):t[l]}return e}const cN={data:Eb,props:Tb,emits:Tb,methods:Si,computed:Si,beforeCreate:Gn,created:Gn,beforeMount:Gn,mounted:Gn,beforeUpdate:Gn,updated:Gn,beforeDestroy:Gn,beforeUnmount:Gn,destroyed:Gn,unmounted:Gn,activated:Gn,deactivated:Gn,errorCaptured:Gn,serverPrefetch:Gn,components:Si,directives:Si,watch:fN,provide:Eb,inject:dN};function Eb(e,t){return t?e?function(){return an(Xe(e)?e.call(this,this):e,Xe(t)?t.call(this,this):t)}:t:e}function dN(e,t){return Si(Gp(e),Gp(t))}function Gp(e){if(Pe(e)){const t={};for(let n=0;n1)return n&&Xe(t)?t.call(o&&o.proxy):t}}function a_(){return!!(bn||In||Xi)}function mN(e,t,n,o=!1){const r={},a={};od(a,ef,1),e.propsDefaults=Object.create(null),l_(e,t,r,a);for(const l in e.propsOptions[0])l in r||(r[l]=void 0);n?e.props=o?r:Hm(r):e.type.props?e.props=r:e.props=a,e.attrs=a}function vN(e,t,n,o){const{props:r,attrs:a,vnode:{patchFlag:l}}=e,s=Mt(r),[u]=e.propsOptions;let c=!1;if((o||l>0)&&!(l&16)){if(l&8){const f=e.vnode.dynamicProps;for(let d=0;d{u=!0;const[p,m]=s_(d,t,!0);an(l,p),m&&s.push(...m)};!n&&t.mixins.length&&t.mixins.forEach(f),e.extends&&f(e.extends),e.mixins&&e.mixins.forEach(f)}if(!a&&!u)return dt(e)&&o.set(e,rs),rs;if(Pe(a))for(let f=0;f-1,m[1]=h<0||v-1||Tt(m,"default"))&&s.push(d)}}}const c=[l,s];return dt(e)&&o.set(e,c),c}function $b(e){return e[0]!=="$"}function Ob(e){const t=e&&e.toString().match(/^\s*(function|class) (\w+)/);return t?t[2]:e===null?"null":""}function Nb(e,t){return Ob(e)===Ob(t)}function Ib(e,t){return Pe(t)?t.findIndex(n=>Nb(n,e)):Xe(t)&&Nb(t,e)?0:-1}const i_=e=>e[0]==="_"||e==="$stable",rv=e=>Pe(e)?e.map(ho):[ho(e)],gN=(e,t,n)=>{if(t._n)return t;const o=X((...r)=>rv(t(...r)),n);return o._c=!1,o},u_=(e,t,n)=>{const o=e._ctx;for(const r in e){if(i_(r))continue;const a=e[r];if(Xe(a))t[r]=gN(r,a,o);else if(a!=null){const l=rv(a);t[r]=()=>l}}},c_=(e,t)=>{const n=rv(t);e.slots.default=()=>n},bN=(e,t)=>{if(e.vnode.shapeFlag&32){const n=t._;n?(e.slots=Mt(t),od(t,"_",n)):u_(t,e.slots={})}else e.slots={},t&&c_(e,t);od(e.slots,ef,1)},yN=(e,t,n)=>{const{vnode:o,slots:r}=e;let a=!0,l=Zt;if(o.shapeFlag&32){const s=t._;s?n&&s===1?a=!1:(an(r,t),!n&&s===1&&delete r._):(a=!t.$stable,u_(t,r)),l=t}else t&&(c_(e,t),l={default:1});if(a)for(const s in r)!i_(s)&&!(s in l)&&delete r[s]};function ud(e,t,n,o,r=!1){if(Pe(e)){e.forEach((p,m)=>ud(p,t&&(Pe(t)?t[m]:t),n,o,r));return}if(ll(o)&&!r)return;const a=o.shapeFlag&4?tf(o.component)||o.component.proxy:o.el,l=r?null:a,{i:s,r:u}=e,c=t&&t.r,f=s.refs===Zt?s.refs={}:s.refs,d=s.setupState;if(c!=null&&c!==u&&(nt(c)?(f[c]=null,Tt(d,c)&&(d[c]=null)):xt(c)&&(c.value=null)),Xe(u))Wr(u,s,12,[l,f]);else{const p=nt(u),m=xt(u);if(p||m){const v=()=>{if(e.f){const h=p?Tt(d,u)?d[u]:f[u]:u.value;r?Pe(h)&&xm(h,a):Pe(h)?h.includes(a)||h.push(a):p?(f[u]=[a],Tt(d,u)&&(d[u]=f[u])):(u.value=[a],e.k&&(f[e.k]=u.value))}else p?(f[u]=l,Tt(d,u)&&(d[u]=l)):m&&(u.value=l,e.k&&(f[e.k]=l))};l?(v.id=-1,Pn(v,n)):v()}}}let la=!1;const nc=e=>/svg/.test(e.namespaceURI)&&e.tagName!=="foreignObject",oc=e=>e.nodeType===8;function wN(e){const{mt:t,p:n,o:{patchProp:o,createText:r,nextSibling:a,parentNode:l,remove:s,insert:u,createComment:c}}=e,f=(g,y)=>{if(!y.hasChildNodes()){n(null,g,y),sd(),y._vnode=g;return}la=!1,d(y.firstChild,g,null,null,null),sd(),y._vnode=g,la&&console.error("Hydration completed but contains mismatches.")},d=(g,y,_,b,w,S=!1)=>{const E=oc(g)&&g.data==="[",$=()=>h(g,y,_,b,w,E),{type:O,ref:A,shapeFlag:M,patchFlag:D}=y;let U=g.nodeType;y.el=g,D===-2&&(S=!1,y.dynamicChildren=null);let j=null;switch(O){case Ur:U!==3?y.children===""?(u(y.el=r(""),l(g),g),j=g):j=$():(g.data!==y.children&&(la=!0,g.data=y.children),j=a(g));break;case En:U!==8||E?j=$():j=a(g);break;case sl:if(E&&(g=a(g),U=g.nodeType),U===1||U===3){j=g;const W=!y.children.length;for(let L=0;L{S=S||!!y.dynamicChildren;const{type:E,props:$,patchFlag:O,shapeFlag:A,dirs:M}=y,D=E==="input"&&M||E==="option";if(D||O!==-1){if(M&&pr(y,null,_,"created"),$)if(D||!S||O&48)for(const j in $)(D&&j.endsWith("value")||yu(j)&&!$i(j))&&o(g,j,null,$[j],!1,void 0,_);else $.onClick&&o(g,"onClick",null,$.onClick,!1,void 0,_);let U;if((U=$&&$.onVnodeBeforeMount)&&ro(U,_,y),M&&pr(y,null,_,"beforeMount"),((U=$&&$.onVnodeMounted)||M)&&jw(()=>{U&&ro(U,_,y),M&&pr(y,null,_,"mounted")},b),A&16&&!($&&($.innerHTML||$.textContent))){let j=m(g.firstChild,y,g,_,b,w,S);for(;j;){la=!0;const W=j;j=j.nextSibling,s(W)}}else A&8&&g.textContent!==y.children&&(la=!0,g.textContent=y.children)}return g.nextSibling},m=(g,y,_,b,w,S,E)=>{E=E||!!y.dynamicChildren;const $=y.children,O=$.length;for(let A=0;A{const{slotScopeIds:E}=y;E&&(w=w?w.concat(E):E);const $=l(g),O=m(a(g),y,$,_,b,w,S);return O&&oc(O)&&O.data==="]"?a(y.anchor=O):(la=!0,u(y.anchor=c("]"),$,O),O)},h=(g,y,_,b,w,S)=>{if(la=!0,y.el=null,S){const O=C(g);for(;;){const A=a(g);if(A&&A!==O)s(A);else break}}const E=a(g),$=l(g);return s(g),n(null,y,$,E,_,b,nc($),w),E},C=g=>{let y=0;for(;g;)if(g=a(g),g&&oc(g)&&(g.data==="["&&y++,g.data==="]")){if(y===0)return a(g);y--}return g};return[f,d]}const Pn=jw;function d_(e){return p_(e)}function f_(e){return p_(e,wN)}function p_(e,t){const n=Hp();n.__VUE__=!0;const{insert:o,remove:r,patchProp:a,createElement:l,createText:s,createComment:u,setText:c,setElementText:f,parentNode:d,nextSibling:p,setScopeId:m=Bt,insertStaticContent:v}=e,h=(q,B,z,Z=null,ue=null,se=null,me=!1,_e=null,$e=!!B.dynamicChildren)=>{if(q===B)return;q&&!Xo(q,B)&&(Z=ke(q),J(q,ue,se,!0),q=null),B.patchFlag===-2&&($e=!1,B.dynamicChildren=null);const{type:Ce,ref:ce,shapeFlag:de}=B;switch(Ce){case Ur:C(q,B,z,Z);break;case En:g(q,B,z,Z);break;case sl:q==null&&y(B,z,Z,me);break;case Ve:D(q,B,z,Z,ue,se,me,_e,$e);break;default:de&1?w(q,B,z,Z,ue,se,me,_e,$e):de&6?U(q,B,z,Z,ue,se,me,_e,$e):(de&64||de&128)&&Ce.process(q,B,z,Z,ue,se,me,_e,$e,Oe)}ce!=null&&ue&&ud(ce,q&&q.ref,se,B||q,!B)},C=(q,B,z,Z)=>{if(q==null)o(B.el=s(B.children),z,Z);else{const ue=B.el=q.el;B.children!==q.children&&c(ue,B.children)}},g=(q,B,z,Z)=>{q==null?o(B.el=u(B.children||""),z,Z):B.el=q.el},y=(q,B,z,Z)=>{[q.el,q.anchor]=v(q.children,B,z,Z,q.el,q.anchor)},_=({el:q,anchor:B},z,Z)=>{let ue;for(;q&&q!==B;)ue=p(q),o(q,z,Z),q=ue;o(B,z,Z)},b=({el:q,anchor:B})=>{let z;for(;q&&q!==B;)z=p(q),r(q),q=z;r(B)},w=(q,B,z,Z,ue,se,me,_e,$e)=>{me=me||B.type==="svg",q==null?S(B,z,Z,ue,se,me,_e,$e):O(q,B,ue,se,me,_e,$e)},S=(q,B,z,Z,ue,se,me,_e)=>{let $e,Ce;const{type:ce,props:de,shapeFlag:xe,transition:he,dirs:He}=q;if($e=q.el=l(q.type,se,de&&de.is,de),xe&8?f($e,q.children):xe&16&&$(q.children,$e,null,Z,ue,se&&ce!=="foreignObject",me,_e),He&&pr(q,null,Z,"created"),E($e,q,q.scopeId,me,Z),de){for(const rt in de)rt!=="value"&&!$i(rt)&&a($e,rt,null,de[rt],se,q.children,Z,ue,oe);"value"in de&&a($e,"value",null,de.value),(Ce=de.onVnodeBeforeMount)&&ro(Ce,Z,q)}He&&pr(q,null,Z,"beforeMount");const et=(!ue||ue&&!ue.pendingBranch)&&he&&!he.persisted;et&&he.beforeEnter($e),o($e,B,z),((Ce=de&&de.onVnodeMounted)||et||He)&&Pn(()=>{Ce&&ro(Ce,Z,q),et&&he.enter($e),He&&pr(q,null,Z,"mounted")},ue)},E=(q,B,z,Z,ue)=>{if(z&&m(q,z),Z)for(let se=0;se{for(let Ce=$e;Ce{const _e=B.el=q.el;let{patchFlag:$e,dynamicChildren:Ce,dirs:ce}=B;$e|=q.patchFlag&16;const de=q.props||Zt,xe=B.props||Zt;let he;z&&Ha(z,!1),(he=xe.onVnodeBeforeUpdate)&&ro(he,z,B,q),ce&&pr(B,q,z,"beforeUpdate"),z&&Ha(z,!0);const He=ue&&B.type!=="foreignObject";if(Ce?A(q.dynamicChildren,Ce,_e,z,Z,He,se):me||x(q,B,_e,null,z,Z,He,se,!1),$e>0){if($e&16)M(_e,B,de,xe,z,Z,ue);else if($e&2&&de.class!==xe.class&&a(_e,"class",null,xe.class,ue),$e&4&&a(_e,"style",de.style,xe.style,ue),$e&8){const et=B.dynamicProps;for(let rt=0;rt{he&&ro(he,z,B,q),ce&&pr(B,q,z,"updated")},Z)},A=(q,B,z,Z,ue,se,me)=>{for(let _e=0;_e{if(z!==Z){if(z!==Zt)for(const _e in z)!$i(_e)&&!(_e in Z)&&a(q,_e,z[_e],null,me,B.children,ue,se,oe);for(const _e in Z){if($i(_e))continue;const $e=Z[_e],Ce=z[_e];$e!==Ce&&_e!=="value"&&a(q,_e,Ce,$e,me,B.children,ue,se,oe)}"value"in Z&&a(q,"value",z.value,Z.value)}},D=(q,B,z,Z,ue,se,me,_e,$e)=>{const Ce=B.el=q?q.el:s(""),ce=B.anchor=q?q.anchor:s("");let{patchFlag:de,dynamicChildren:xe,slotScopeIds:he}=B;he&&(_e=_e?_e.concat(he):he),q==null?(o(Ce,z,Z),o(ce,z,Z),$(B.children,z,ce,ue,se,me,_e,$e)):de>0&&de&64&&xe&&q.dynamicChildren?(A(q.dynamicChildren,xe,z,ue,se,me,_e),(B.key!=null||ue&&B===ue.subTree)&&av(q,B,!0)):x(q,B,z,ce,ue,se,me,_e,$e)},U=(q,B,z,Z,ue,se,me,_e,$e)=>{B.slotScopeIds=_e,q==null?B.shapeFlag&512?ue.ctx.activate(B,z,Z,me,$e):j(B,z,Z,ue,se,me,$e):W(q,B,$e)},j=(q,B,z,Z,ue,se,me)=>{const _e=q.component=b_(q,Z,ue);if(Cu(q)&&(_e.ctx.renderer=Oe),w_(_e),_e.asyncDep){if(ue&&ue.registerDep(_e,L),!q.el){const $e=_e.subTree=K(En);g(null,$e,B,z)}return}L(_e,q,B,z,ue,se,me)},W=(q,B,z)=>{const Z=B.component=q.component;if(PO(q,B,z))if(Z.asyncDep&&!Z.asyncResolved){P(Z,B,z);return}else Z.next=B,TO(Z.update),Z.update();else B.el=q.el,Z.vnode=B},L=(q,B,z,Z,ue,se,me)=>{const _e=()=>{if(q.isMounted){let{next:ce,bu:de,u:xe,parent:he,vnode:He}=q,et=ce,rt;Ha(q,!1),ce?(ce.el=He.el,P(q,ce,me)):ce=He,de&&ss(de),(rt=ce.props&&ce.props.onVnodeBeforeUpdate)&&ro(rt,he,ce,He),Ha(q,!0);const wt=$c(q),Ze=q.subTree;q.subTree=wt,h(Ze,wt,d(Ze.el),ke(Ze),q,ue,se),ce.el=wt.el,et===null&&Ym(q,wt.el),xe&&Pn(xe,ue),(rt=ce.props&&ce.props.onVnodeUpdated)&&Pn(()=>ro(rt,he,ce,He),ue)}else{let ce;const{el:de,props:xe}=B,{bm:he,m:He,parent:et}=q,rt=ll(B);if(Ha(q,!1),he&&ss(he),!rt&&(ce=xe&&xe.onVnodeBeforeMount)&&ro(ce,et,B),Ha(q,!0),de&&ge){const wt=()=>{q.subTree=$c(q),ge(de,q.subTree,q,ue,null)};rt?B.type.__asyncLoader().then(()=>!q.isUnmounted&&wt()):wt()}else{const wt=q.subTree=$c(q);h(null,wt,z,Z,q,ue,se),B.el=wt.el}if(He&&Pn(He,ue),!rt&&(ce=xe&&xe.onVnodeMounted)){const wt=B;Pn(()=>ro(ce,et,wt),ue)}(B.shapeFlag&256||et&&ll(et.vnode)&&et.vnode.shapeFlag&256)&&q.a&&Pn(q.a,ue),q.isMounted=!0,B=z=Z=null}},$e=q.effect=new wu(_e,()=>qd(Ce),q.scope),Ce=q.update=()=>$e.run();Ce.id=q.uid,Ha(q,!0),Ce()},P=(q,B,z)=>{B.component=q;const Z=q.vnode.props;q.vnode=B,q.next=null,vN(q,B.props,Z,z),yN(q,B.children,z),Ks(),yb(),Us()},x=(q,B,z,Z,ue,se,me,_e,$e=!1)=>{const Ce=q&&q.children,ce=q?q.shapeFlag:0,de=B.children,{patchFlag:xe,shapeFlag:he}=B;if(xe>0){if(xe&128){H(Ce,de,z,Z,ue,se,me,_e,$e);return}else if(xe&256){I(Ce,de,z,Z,ue,se,me,_e,$e);return}}he&8?(ce&16&&oe(Ce,ue,se),de!==Ce&&f(z,de)):ce&16?he&16?H(Ce,de,z,Z,ue,se,me,_e,$e):oe(Ce,ue,se,!0):(ce&8&&f(z,""),he&16&&$(de,z,Z,ue,se,me,_e,$e))},I=(q,B,z,Z,ue,se,me,_e,$e)=>{q=q||rs,B=B||rs;const Ce=q.length,ce=B.length,de=Math.min(Ce,ce);let xe;for(xe=0;xece?oe(q,ue,se,!0,!1,de):$(B,z,Z,ue,se,me,_e,$e,de)},H=(q,B,z,Z,ue,se,me,_e,$e)=>{let Ce=0;const ce=B.length;let de=q.length-1,xe=ce-1;for(;Ce<=de&&Ce<=xe;){const he=q[Ce],He=B[Ce]=$e?va(B[Ce]):ho(B[Ce]);if(Xo(he,He))h(he,He,z,null,ue,se,me,_e,$e);else break;Ce++}for(;Ce<=de&&Ce<=xe;){const he=q[de],He=B[xe]=$e?va(B[xe]):ho(B[xe]);if(Xo(he,He))h(he,He,z,null,ue,se,me,_e,$e);else break;de--,xe--}if(Ce>de){if(Ce<=xe){const he=xe+1,He=hexe)for(;Ce<=de;)J(q[Ce],ue,se,!0),Ce++;else{const he=Ce,He=Ce,et=new Map;for(Ce=He;Ce<=xe;Ce++){const be=B[Ce]=$e?va(B[Ce]):ho(B[Ce]);be.key!=null&&et.set(be.key,Ce)}let rt,wt=0;const Ze=xe-He+1;let st=!1,Ee=0;const ye=new Array(Ze);for(Ce=0;Ce=Ze){J(be,ue,se,!0);continue}let Fe;if(be.key!=null)Fe=et.get(be.key);else for(rt=He;rt<=xe;rt++)if(ye[rt-He]===0&&Xo(be,B[rt])){Fe=rt;break}Fe===void 0?J(be,ue,se,!0):(ye[Fe-He]=Ce+1,Fe>=Ee?Ee=Fe:st=!0,h(be,B[Fe],z,null,ue,se,me,_e,$e),wt++)}const ne=st?_N(ye):rs;for(rt=ne.length-1,Ce=Ze-1;Ce>=0;Ce--){const be=He+Ce,Fe=B[be],vt=be+1{const{el:se,type:me,transition:_e,children:$e,shapeFlag:Ce}=q;if(Ce&6){G(q.component.subTree,B,z,Z);return}if(Ce&128){q.suspense.move(B,z,Z);return}if(Ce&64){me.move(q,B,z,Oe);return}if(me===Ve){o(se,B,z);for(let de=0;de<$e.length;de++)G($e[de],B,z,Z);o(q.anchor,B,z);return}if(me===sl){_(q,B,z);return}if(Z!==2&&Ce&1&&_e)if(Z===0)_e.beforeEnter(se),o(se,B,z),Pn(()=>_e.enter(se),ue);else{const{leave:de,delayLeave:xe,afterLeave:he}=_e,He=()=>o(se,B,z),et=()=>{de(se,()=>{He(),he&&he()})};xe?xe(se,He,et):et()}else o(se,B,z)},J=(q,B,z,Z=!1,ue=!1)=>{const{type:se,props:me,ref:_e,children:$e,dynamicChildren:Ce,shapeFlag:ce,patchFlag:de,dirs:xe}=q;if(_e!=null&&ud(_e,null,z,q,!0),ce&256){B.ctx.deactivate(q);return}const he=ce&1&&xe,He=!ll(q);let et;if(He&&(et=me&&me.onVnodeBeforeUnmount)&&ro(et,B,q),ce&6)Te(q.component,z,Z);else{if(ce&128){q.suspense.unmount(z,Z);return}he&&pr(q,null,B,"beforeUnmount"),ce&64?q.type.remove(q,B,z,ue,Oe,Z):Ce&&(se!==Ve||de>0&&de&64)?oe(Ce,B,z,!1,!0):(se===Ve&&de&384||!ue&&ce&16)&&oe($e,B,z),Z&&ee(q)}(He&&(et=me&&me.onVnodeUnmounted)||he)&&Pn(()=>{et&&ro(et,B,q),he&&pr(q,null,B,"unmounted")},z)},ee=q=>{const{type:B,el:z,anchor:Z,transition:ue}=q;if(B===Ve){fe(z,Z);return}if(B===sl){b(q);return}const se=()=>{r(z),ue&&!ue.persisted&&ue.afterLeave&&ue.afterLeave()};if(q.shapeFlag&1&&ue&&!ue.persisted){const{leave:me,delayLeave:_e}=ue,$e=()=>me(z,se);_e?_e(q.el,se,$e):$e()}else se()},fe=(q,B)=>{let z;for(;q!==B;)z=p(q),r(q),q=z;r(B)},Te=(q,B,z)=>{const{bum:Z,scope:ue,update:se,subTree:me,um:_e}=q;Z&&ss(Z),ue.stop(),se&&(se.active=!1,J(me,q,B,z)),_e&&Pn(_e,B),Pn(()=>{q.isUnmounted=!0},B),B&&B.pendingBranch&&!B.isUnmounted&&q.asyncDep&&!q.asyncResolved&&q.suspenseId===B.pendingId&&(B.deps--,B.deps===0&&B.resolve())},oe=(q,B,z,Z=!1,ue=!1,se=0)=>{for(let me=se;meq.shapeFlag&6?ke(q.component.subTree):q.shapeFlag&128?q.suspense.next():p(q.anchor||q.el),ae=(q,B,z)=>{q==null?B._vnode&&J(B._vnode,null,null,!0):h(B._vnode||null,q,B,null,null,null,z),yb(),sd(),B._vnode=q},Oe={p:h,um:J,m:G,r:ee,mt:j,mc:$,pc:x,pbc:A,n:ke,o:e};let we,ge;return t&&([we,ge]=t(Oe)),{render:ae,hydrate:we,createApp:hN(ae,we)}}function Ha({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function av(e,t,n=!1){const o=e.children,r=t.children;if(Pe(o)&&Pe(r))for(let a=0;a>1,e[n[s]]0&&(t[o]=n[a-1]),n[a]=o)}}for(a=n.length,l=n[a-1];a-- >0;)n[a]=l,l=t[l];return n}const CN=e=>e.__isTeleport,Ni=e=>e&&(e.disabled||e.disabled===""),Mb=e=>typeof SVGElement<"u"&&e instanceof SVGElement,Jp=(e,t)=>{const n=e&&e.to;return nt(n)?t?t(n):null:n},SN={__isTeleport:!0,process(e,t,n,o,r,a,l,s,u,c){const{mc:f,pc:d,pbc:p,o:{insert:m,querySelector:v,createText:h,createComment:C}}=c,g=Ni(t.props);let{shapeFlag:y,children:_,dynamicChildren:b}=t;if(e==null){const w=t.el=h(""),S=t.anchor=h("");m(w,n,o),m(S,n,o);const E=t.target=Jp(t.props,v),$=t.targetAnchor=h("");E&&(m($,E),l=l||Mb(E));const O=(A,M)=>{y&16&&f(_,A,M,r,a,l,s,u)};g?O(n,S):E&&O(E,$)}else{t.el=e.el;const w=t.anchor=e.anchor,S=t.target=e.target,E=t.targetAnchor=e.targetAnchor,$=Ni(e.props),O=$?n:S,A=$?w:E;if(l=l||Mb(S),b?(p(e.dynamicChildren,b,O,r,a,l,s),av(e,t,!0)):u||d(e,t,O,A,r,a,l,s,!1),g)$||rc(t,n,w,c,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){const M=t.target=Jp(t.props,v);M&&rc(t,M,null,c,0)}else $&&rc(t,S,E,c,1)}h_(t)},remove(e,t,n,o,{um:r,o:{remove:a}},l){const{shapeFlag:s,children:u,anchor:c,targetAnchor:f,target:d,props:p}=e;if(d&&a(f),(l||!Ni(p))&&(a(c),s&16))for(let m=0;m0?ao||rs:null,m_(),gl>0&&ao&&ao.push(e),e}function V(e,t,n,o,r,a){return v_(F(e,t,n,o,r,a,!0))}function re(e,t,n,o,r){return v_(K(e,t,n,o,r,!0))}function Wt(e){return e?e.__v_isVNode===!0:!1}function Xo(e,t){return e.type===t.type&&e.key===t.key}function EN(e){}const ef="__vInternal",g_=({key:e})=>e??null,Oc=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?nt(e)||xt(e)||Xe(e)?{i:In,r:e,k:t,f:!!n}:e:null);function F(e,t=null,n=null,o=0,r=null,a=e===Ve?0:1,l=!1,s=!1){const u={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&g_(t),ref:t&&Oc(t),scopeId:Gd,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:a,patchFlag:o,dynamicProps:r,dynamicChildren:null,appContext:null,ctx:In};return s?(lv(u,n),a&128&&e.normalize(u)):n&&(u.shapeFlag|=nt(n)?8:16),gl>0&&!l&&ao&&(u.patchFlag>0||a&6)&&u.patchFlag!==32&&ao.push(u),u}const K=TN;function TN(e,t=null,n=null,o=0,r=null,a=!1){if((!e||e===Qw)&&(e=En),Wt(e)){const s=Qo(e,t,!0);return n&&lv(s,n),gl>0&&!a&&ao&&(s.shapeFlag&6?ao[ao.indexOf(e)]=s:ao.push(s)),s.patchFlag|=-2,s}if(RN(e)&&(e=e.__vccOpts),t){t=bl(t);let{class:s,style:u}=t;s&&!nt(s)&&(t.class=N(s)),dt(u)&&(zm(u)&&!Pe(u)&&(u=an({},u)),t.style=je(u))}const l=nt(e)?1:zw(e)?128:CN(e)?64:dt(e)?4:Xe(e)?2:0;return F(e,t,n,o,r,l,a,!0)}function bl(e){return e?zm(e)||ef in e?an({},e):e:null}function Qo(e,t,n=!1){const{props:o,ref:r,patchFlag:a,children:l}=e,s=t?mt(o||{},t):o;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:s,key:s&&g_(s),ref:t&&t.ref?n&&r?Pe(r)?r.concat(Oc(t)):[r,Oc(t)]:Oc(t):r,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:l,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Ve?a===-1?16:a|16:a,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Qo(e.ssContent),ssFallback:e.ssFallback&&Qo(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Ge(e=" ",t=0){return K(Ur,null,e,t)}function $N(e,t){const n=K(sl,null,e);return n.staticCount=t,n}function te(e="",t=!1){return t?(T(),re(En,null,e)):K(En,null,e)}function ho(e){return e==null||typeof e=="boolean"?K(En):Pe(e)?K(Ve,null,e.slice()):typeof e=="object"?va(e):K(Ur,null,String(e))}function va(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Qo(e)}function lv(e,t){let n=0;const{shapeFlag:o}=e;if(t==null)t=null;else if(Pe(t))n=16;else if(typeof t=="object")if(o&65){const r=t.default;r&&(r._c&&(r._d=!1),lv(e,r()),r._c&&(r._d=!0));return}else{n=32;const r=t._;!r&&!(ef in t)?t._ctx=In:r===3&&In&&(In.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else Xe(t)?(t={default:t,_ctx:In},n=32):(t=String(t),o&64?(n=16,t=[Ge(t)]):n=8);e.children=t,e.shapeFlag|=n}function mt(...e){const t={};for(let n=0;nbn||In;let sv,jl,Ab="__VUE_INSTANCE_SETTERS__";(jl=Hp()[Ab])||(jl=Hp()[Ab]=[]),jl.push(e=>bn=e),sv=e=>{jl.length>1?jl.forEach(t=>t(e)):jl[0](e)};const $a=e=>{sv(e),e.scope.on()},_a=()=>{bn&&bn.scope.off(),sv(null)};function y_(e){return e.vnode.shapeFlag&4}let ys=!1;function w_(e,t=!1){ys=t;const{props:n,children:o}=e.vnode,r=y_(e);mN(e,n,r,t),bN(e,o);const a=r?IN(e,t):void 0;return ys=!1,a}function IN(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=Po(new Proxy(e.ctx,qp));const{setup:o}=n;if(o){const r=e.setupContext=o.length>1?C_(e):null;$a(e),Ks();const a=Wr(o,e,0,[e.props,r]);if(Us(),_a(),vs(a)){if(a.then(_a,_a),t)return a.then(l=>{Qp(e,l,t)}).catch(l=>{Al(l,e,0)});e.asyncDep=a}else Qp(e,a,t)}else __(e,t)}function Qp(e,t,n){Xe(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:dt(t)&&(e.setupState=Km(t)),__(e,n)}let cd,eh;function MN(e){cd=e,eh=t=>{t.render._rc&&(t.withProxy=new Proxy(t.ctx,GO))}}const AN=()=>!cd;function __(e,t,n){const o=e.type;if(!e.render){if(!t&&cd&&!o.render){const r=o.template||ov(e).template;if(r){const{isCustomElement:a,compilerOptions:l}=e.appContext.config,{delimiters:s,compilerOptions:u}=o,c=an(an({isCustomElement:a,delimiters:s},l),u);o.render=cd(r,c)}}e.render=o.render||Bt,eh&&eh(e)}$a(e),Ks(),iN(e),Us(),_a()}function PN(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return uo(e,"get","$attrs"),t[n]}}))}function C_(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return PN(e)},slots:e.slots,emit:e.emit,expose:t}}function tf(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(Km(Po(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in Oi)return Oi[n](e)},has(t,n){return n in t||n in Oi}}))}function th(e,t=!0){return Xe(e)?e.displayName||e.name:e.name||t&&e.__name}function RN(e){return Xe(e)&&"__vccOpts"in e}const k=(e,t)=>CO(e,t,ys);function Ke(e,t,n){const o=arguments.length;return o===2?dt(t)&&!Pe(t)?Wt(t)?K(e,null,[t]):K(e,t):K(e,null,t):(o>3?n=Array.prototype.slice.call(arguments,2):o===3&&Wt(n)&&(n=[n]),K(e,t,n))}const S_=Symbol.for("v-scx"),k_=()=>De(S_);function LN(){}function xN(e,t,n,o){const r=n[o];if(r&&E_(r,e))return r;const a=t();return a.memo=e.slice(),n[o]=a}function E_(e,t){const n=e.memo;if(n.length!=t.length)return!1;for(let o=0;o0&&ao&&ao.push(e),!0}const T_="3.3.4",DN={createComponentInstance:b_,setupComponent:w_,renderComponentRoot:$c,setCurrentRenderingInstance:qi,isVNode:Wt,normalizeVNode:ho},FN=DN,BN=null,VN=null,HN="http://www.w3.org/2000/svg",Ya=typeof document<"u"?document:null,Pb=Ya&&Ya.createElement("template"),zN={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,o)=>{const r=t?Ya.createElementNS(HN,e):Ya.createElement(e,n?{is:n}:void 0);return e==="select"&&o&&o.multiple!=null&&r.setAttribute("multiple",o.multiple),r},createText:e=>Ya.createTextNode(e),createComment:e=>Ya.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Ya.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,o,r,a){const l=n?n.previousSibling:t.lastChild;if(r&&(r===a||r.nextSibling))for(;t.insertBefore(r.cloneNode(!0),n),!(r===a||!(r=r.nextSibling)););else{Pb.innerHTML=o?`${e}`:e;const s=Pb.content;if(o){const u=s.firstChild;for(;u.firstChild;)s.appendChild(u.firstChild);s.removeChild(u)}t.insertBefore(s,n)}return[l?l.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}};function jN(e,t,n){const o=e._vtc;o&&(t=(t?[t,...o]:[...o]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}function WN(e,t,n){const o=e.style,r=nt(n);if(n&&!r){if(t&&!nt(t))for(const a in t)n[a]==null&&nh(o,a,"");for(const a in n)nh(o,a,n[a])}else{const a=o.display;r?t!==n&&(o.cssText=n):t&&e.removeAttribute("style"),"_vod"in e&&(o.display=a)}}const Rb=/\s*!important$/;function nh(e,t,n){if(Pe(n))n.forEach(o=>nh(e,t,o));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const o=KN(e,t);Rb.test(n)?e.setProperty(mo(o),n.replace(Rb,""),"important"):e[o]=n}}const Lb=["Webkit","Moz","ms"],np={};function KN(e,t){const n=np[t];if(n)return n;let o=jn(t);if(o!=="filter"&&o in e)return np[t]=o;o=Ws(o);for(let r=0;rop||(JN.then(()=>op=0),op=Date.now());function QN(e,t){const n=o=>{if(!o._vts)o._vts=Date.now();else if(o._vts<=n.attached)return;yo(eI(o,n.value),t,5,[o])};return n.value=e,n.attached=ZN(),n}function eI(e,t){if(Pe(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(o=>r=>!r._stopped&&o&&o(r))}else return t}const Fb=/^on[a-z]/,tI=(e,t,n,o,r=!1,a,l,s,u)=>{t==="class"?jN(e,o,r):t==="style"?WN(e,n,o):yu(t)?Lm(t)||GN(e,t,n,o,l):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):nI(e,t,o,r))?qN(e,t,o,a,l,s,u):(t==="true-value"?e._trueValue=o:t==="false-value"&&(e._falseValue=o),UN(e,t,o,r))};function nI(e,t,n,o){return o?!!(t==="innerHTML"||t==="textContent"||t in e&&Fb.test(t)&&Xe(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Fb.test(t)&&nt(n)?!1:t in e}function $_(e,t){const n=Y(e);class o extends nf{constructor(a){super(n,a,t)}}return o.def=n,o}const oI=e=>$_(e,z_),rI=typeof HTMLElement<"u"?HTMLElement:class{};class nf extends rI{constructor(t,n={},o){super(),this._def=t,this._props=n,this._instance=null,this._connected=!1,this._resolved=!1,this._numberProps=null,this.shadowRoot&&o?o(this._createVNode(),this.shadowRoot):(this.attachShadow({mode:"open"}),this._def.__asyncLoader||this._resolveProps(this._def))}connectedCallback(){this._connected=!0,this._instance||(this._resolved?this._update():this._resolveDef())}disconnectedCallback(){this._connected=!1,We(()=>{this._connected||(er(null,this.shadowRoot),this._instance=null)})}_resolveDef(){this._resolved=!0;for(let o=0;o{for(const r of o)this._setAttr(r.attributeName)}).observe(this,{attributes:!0});const t=(o,r=!1)=>{const{props:a,styles:l}=o;let s;if(a&&!Pe(a))for(const u in a){const c=a[u];(c===Number||c&&c.type===Number)&&(u in this._props&&(this._props[u]=ad(this._props[u])),(s||(s=Object.create(null)))[jn(u)]=!0)}this._numberProps=s,r&&this._resolveProps(o),this._applyStyles(l),this._update()},n=this._def.__asyncLoader;n?n().then(o=>t(o,!0)):t(this._def)}_resolveProps(t){const{props:n}=t,o=Pe(n)?n:Object.keys(n||{});for(const r of Object.keys(this))r[0]!=="_"&&o.includes(r)&&this._setProp(r,this[r],!0,!1);for(const r of o.map(jn))Object.defineProperty(this,r,{get(){return this._getProp(r)},set(a){this._setProp(r,a)}})}_setAttr(t){let n=this.getAttribute(t);const o=jn(t);this._numberProps&&this._numberProps[o]&&(n=ad(n)),this._setProp(o,n,!1)}_getProp(t){return this._props[t]}_setProp(t,n,o=!0,r=!0){n!==this._props[t]&&(this._props[t]=n,r&&this._instance&&this._update(),o&&(n===!0?this.setAttribute(mo(t),""):typeof n=="string"||typeof n=="number"?this.setAttribute(mo(t),n+""):n||this.removeAttribute(mo(t))))}_update(){er(this._createVNode(),this.shadowRoot)}_createVNode(){const t=K(this._def,an({},this._props));return this._instance||(t.ce=n=>{this._instance=n,n.isCE=!0;const o=(a,l)=>{this.dispatchEvent(new CustomEvent(a,{detail:l}))};n.emit=(a,...l)=>{o(a,l),mo(a)!==a&&o(mo(a),l)};let r=this;for(;r=r&&(r.parentNode||r.host);)if(r instanceof nf){n.parent=r._instance,n.provides=r._instance.provides;break}}),t}_applyStyles(t){t&&t.forEach(n=>{const o=document.createElement("style");o.textContent=n,this.shadowRoot.appendChild(o)})}}function aI(e="$style"){{const t=lt();if(!t)return Zt;const n=t.type.__cssModules;if(!n)return Zt;const o=n[e];return o||Zt}}function lI(e){const t=lt();if(!t)return;const n=t.ut=(r=e(t.proxy))=>{Array.from(document.querySelectorAll(`[data-v-owner="${t.uid}"]`)).forEach(a=>rh(a,r))},o=()=>{const r=e(t.proxy);oh(t.subTree,r),n(r)};Ww(o),at(()=>{const r=new MutationObserver(o);r.observe(t.subTree.el.parentNode,{childList:!0}),lr(()=>r.disconnect())})}function oh(e,t){if(e.shapeFlag&128){const n=e.suspense;e=n.activeBranch,n.pendingBranch&&!n.isHydrating&&n.effects.push(()=>{oh(n.activeBranch,t)})}for(;e.component;)e=e.component.subTree;if(e.shapeFlag&1&&e.el)rh(e.el,t);else if(e.type===Ve)e.children.forEach(n=>oh(n,t));else if(e.type===sl){let{el:n,anchor:o}=e;for(;n&&(rh(n,t),n!==o);)n=n.nextSibling}}function rh(e,t){if(e.nodeType===1){const n=e.style;for(const o in t)n.setProperty(`--${o}`,t[o])}}const sa="transition",di="animation",fn=(e,{slots:t})=>Ke(Uw,N_(e),t);fn.displayName="Transition";const O_={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},sI=fn.props=an({},Jm,O_),za=(e,t=[])=>{Pe(e)?e.forEach(n=>n(...t)):e&&e(...t)},Bb=e=>e?Pe(e)?e.some(t=>t.length>1):e.length>1:!1;function N_(e){const t={};for(const D in e)D in O_||(t[D]=e[D]);if(e.css===!1)return t;const{name:n="v",type:o,duration:r,enterFromClass:a=`${n}-enter-from`,enterActiveClass:l=`${n}-enter-active`,enterToClass:s=`${n}-enter-to`,appearFromClass:u=a,appearActiveClass:c=l,appearToClass:f=s,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:m=`${n}-leave-to`}=e,v=iI(r),h=v&&v[0],C=v&&v[1],{onBeforeEnter:g,onEnter:y,onEnterCancelled:_,onLeave:b,onLeaveCancelled:w,onBeforeAppear:S=g,onAppear:E=y,onAppearCancelled:$=_}=t,O=(D,U,j)=>{da(D,U?f:s),da(D,U?c:l),j&&j()},A=(D,U)=>{D._isLeaving=!1,da(D,d),da(D,m),da(D,p),U&&U()},M=D=>(U,j)=>{const W=D?E:y,L=()=>O(U,D,j);za(W,[U,L]),Vb(()=>{da(U,D?u:a),Fr(U,D?f:s),Bb(W)||Hb(U,o,h,L)})};return an(t,{onBeforeEnter(D){za(g,[D]),Fr(D,a),Fr(D,l)},onBeforeAppear(D){za(S,[D]),Fr(D,u),Fr(D,c)},onEnter:M(!1),onAppear:M(!0),onLeave(D,U){D._isLeaving=!0;const j=()=>A(D,U);Fr(D,d),M_(),Fr(D,p),Vb(()=>{D._isLeaving&&(da(D,d),Fr(D,m),Bb(b)||Hb(D,o,C,j))}),za(b,[D,j])},onEnterCancelled(D){O(D,!1),za(_,[D])},onAppearCancelled(D){O(D,!0),za($,[D])},onLeaveCancelled(D){A(D),za(w,[D])}})}function iI(e){if(e==null)return null;if(dt(e))return[rp(e.enter),rp(e.leave)];{const t=rp(e);return[t,t]}}function rp(e){return ad(e)}function Fr(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e._vtc||(e._vtc=new Set)).add(t)}function da(e,t){t.split(/\s+/).forEach(o=>o&&e.classList.remove(o));const{_vtc:n}=e;n&&(n.delete(t),n.size||(e._vtc=void 0))}function Vb(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let uI=0;function Hb(e,t,n,o){const r=e._endId=++uI,a=()=>{r===e._endId&&o()};if(n)return setTimeout(a,n);const{type:l,timeout:s,propCount:u}=I_(e,t);if(!l)return o();const c=l+"end";let f=0;const d=()=>{e.removeEventListener(c,p),a()},p=m=>{m.target===e&&++f>=u&&d()};setTimeout(()=>{f(n[v]||"").split(", "),r=o(`${sa}Delay`),a=o(`${sa}Duration`),l=zb(r,a),s=o(`${di}Delay`),u=o(`${di}Duration`),c=zb(s,u);let f=null,d=0,p=0;t===sa?l>0&&(f=sa,d=l,p=a.length):t===di?c>0&&(f=di,d=c,p=u.length):(d=Math.max(l,c),f=d>0?l>c?sa:di:null,p=f?f===sa?a.length:u.length:0);const m=f===sa&&/\b(transform|all)(,|$)/.test(o(`${sa}Property`).toString());return{type:f,timeout:d,propCount:p,hasTransform:m}}function zb(e,t){for(;e.lengthjb(n)+jb(e[o])))}function jb(e){return Number(e.slice(0,-1).replace(",","."))*1e3}function M_(){return document.body.offsetHeight}const A_=new WeakMap,P_=new WeakMap,R_={name:"TransitionGroup",props:an({},sI,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=lt(),o=Xm();let r,a;return ar(()=>{if(!r.length)return;const l=e.moveClass||`${e.name||"v"}-move`;if(!hI(r[0].el,n.vnode.el,l))return;r.forEach(dI),r.forEach(fI);const s=r.filter(pI);M_(),s.forEach(u=>{const c=u.el,f=c.style;Fr(c,l),f.transform=f.webkitTransform=f.transitionDuration="";const d=c._moveCb=p=>{p&&p.target!==c||(!p||/transform$/.test(p.propertyName))&&(c.removeEventListener("transitionend",d),c._moveCb=null,da(c,l))};c.addEventListener("transitionend",d)})}),()=>{const l=Mt(e),s=N_(l);let u=l.tag||Ve;r=a,a=t.default?Zd(t.default()):[];for(let c=0;cdelete e.mode;R_.props;const ku=R_;function dI(e){const t=e.el;t._moveCb&&t._moveCb(),t._enterCb&&t._enterCb()}function fI(e){P_.set(e,e.el.getBoundingClientRect())}function pI(e){const t=A_.get(e),n=P_.get(e),o=t.left-n.left,r=t.top-n.top;if(o||r){const a=e.el.style;return a.transform=a.webkitTransform=`translate(${o}px,${r}px)`,a.transitionDuration="0s",e}}function hI(e,t,n){const o=e.cloneNode();e._vtc&&e._vtc.forEach(l=>{l.split(/\s+/).forEach(s=>s&&o.classList.remove(s))}),n.split(/\s+/).forEach(l=>l&&o.classList.add(l)),o.style.display="none";const r=t.nodeType===1?t:t.parentNode;r.appendChild(o);const{hasTransform:a}=I_(o);return r.removeChild(o),a}const Oa=e=>{const t=e.props["onUpdate:modelValue"]||!1;return Pe(t)?n=>ss(t,n):t};function mI(e){e.target.composing=!0}function Wb(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const yl={created(e,{modifiers:{lazy:t,trim:n,number:o}},r){e._assign=Oa(r);const a=o||r.props&&r.props.type==="number";Hr(e,t?"change":"input",l=>{if(l.target.composing)return;let s=e.value;n&&(s=s.trim()),a&&(s=rd(s)),e._assign(s)}),n&&Hr(e,"change",()=>{e.value=e.value.trim()}),t||(Hr(e,"compositionstart",mI),Hr(e,"compositionend",Wb),Hr(e,"change",Wb))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:o,number:r}},a){if(e._assign=Oa(a),e.composing||document.activeElement===e&&e.type!=="range"&&(n||o&&e.value.trim()===t||(r||e.type==="number")&&rd(e.value)===t))return;const l=t??"";e.value!==l&&(e.value=l)}},wl={deep:!0,created(e,t,n){e._assign=Oa(n),Hr(e,"change",()=>{const o=e._modelValue,r=ws(e),a=e.checked,l=e._assign;if(Pe(o)){const s=Fd(o,r),u=s!==-1;if(a&&!u)l(o.concat(r));else if(!a&&u){const c=[...o];c.splice(s,1),l(c)}}else if(Il(o)){const s=new Set(o);a?s.add(r):s.delete(r),l(s)}else l(x_(e,a))})},mounted:Kb,beforeUpdate(e,t,n){e._assign=Oa(n),Kb(e,t,n)}};function Kb(e,{value:t,oldValue:n},o){e._modelValue=t,Pe(t)?e.checked=Fd(t,o.props.value)>-1:Il(t)?e.checked=t.has(o.props.value):t!==n&&(e.checked=Ea(t,x_(e,!0)))}const Eu={created(e,{value:t},n){e.checked=Ea(t,n.props.value),e._assign=Oa(n),Hr(e,"change",()=>{e._assign(ws(e))})},beforeUpdate(e,{value:t,oldValue:n},o){e._assign=Oa(o),t!==n&&(e.checked=Ea(t,o.props.value))}},L_={deep:!0,created(e,{value:t,modifiers:{number:n}},o){const r=Il(t);Hr(e,"change",()=>{const a=Array.prototype.filter.call(e.options,l=>l.selected).map(l=>n?rd(ws(l)):ws(l));e._assign(e.multiple?r?new Set(a):a:a[0])}),e._assign=Oa(o)},mounted(e,{value:t}){Ub(e,t)},beforeUpdate(e,t,n){e._assign=Oa(n)},updated(e,{value:t}){Ub(e,t)}};function Ub(e,t){const n=e.multiple;if(!(n&&!Pe(t)&&!Il(t))){for(let o=0,r=e.options.length;o-1:a.selected=t.has(l);else if(Ea(ws(a),t)){e.selectedIndex!==o&&(e.selectedIndex=o);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function ws(e){return"_value"in e?e._value:e.value}function x_(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const D_={created(e,t,n){ac(e,t,n,null,"created")},mounted(e,t,n){ac(e,t,n,null,"mounted")},beforeUpdate(e,t,n,o){ac(e,t,n,o,"beforeUpdate")},updated(e,t,n,o){ac(e,t,n,o,"updated")}};function F_(e,t){switch(e){case"SELECT":return L_;case"TEXTAREA":return yl;default:switch(t){case"checkbox":return wl;case"radio":return Eu;default:return yl}}}function ac(e,t,n,o,r){const l=F_(e.tagName,n.props&&n.props.type)[r];l&&l(e,t,n,o)}function vI(){yl.getSSRProps=({value:e})=>({value:e}),Eu.getSSRProps=({value:e},t)=>{if(t.props&&Ea(t.props.value,e))return{checked:!0}},wl.getSSRProps=({value:e},t)=>{if(Pe(e)){if(t.props&&Fd(e,t.props.value)>-1)return{checked:!0}}else if(Il(e)){if(t.props&&e.has(t.props.value))return{checked:!0}}else if(e)return{checked:!0}},D_.getSSRProps=(e,t)=>{if(typeof t.type!="string")return;const n=F_(t.type.toUpperCase(),t.props&&t.props.type);if(n.getSSRProps)return n.getSSRProps(e,t)}}const gI=["ctrl","shift","alt","meta"],bI={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>gI.some(n=>e[`${n}Key`]&&!t.includes(n))},Qe=(e,t)=>(n,...o)=>{for(let r=0;rn=>{if(!("key"in n))return;const o=mo(n.key);if(t.some(r=>r===o||yI[r]===o))return e(n)},kt={beforeMount(e,{value:t},{transition:n}){e._vod=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):fi(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:o}){!t!=!n&&(o?t?(o.beforeEnter(e),fi(e,!0),o.enter(e)):o.leave(e,()=>{fi(e,!1)}):fi(e,t))},beforeUnmount(e,{value:t}){fi(e,t)}};function fi(e,t){e.style.display=t?e._vod:"none"}function wI(){kt.getSSRProps=({value:e})=>{if(!e)return{style:{display:"none"}}}}const B_=an({patchProp:tI},zN);let Mi,qb=!1;function V_(){return Mi||(Mi=d_(B_))}function H_(){return Mi=qb?Mi:f_(B_),qb=!0,Mi}const er=(...e)=>{V_().render(...e)},z_=(...e)=>{H_().hydrate(...e)},iv=(...e)=>{const t=V_().createApp(...e),{mount:n}=t;return t.mount=o=>{const r=j_(o);if(!r)return;const a=t._component;!Xe(a)&&!a.render&&!a.template&&(a.template=r.innerHTML),r.innerHTML="";const l=n(r,!1,r instanceof SVGElement);return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),l},t},_I=(...e)=>{const t=H_().createApp(...e),{mount:n}=t;return t.mount=o=>{const r=j_(o);if(r)return n(r,!0,r instanceof SVGElement)},t};function j_(e){return nt(e)?document.querySelector(e):e}let Yb=!1;const CI=()=>{Yb||(Yb=!0,vI(),wI())},SI=()=>{},kI=Object.freeze(Object.defineProperty({__proto__:null,BaseTransition:Uw,BaseTransitionPropsValidators:Jm,Comment:En,EffectScope:Fm,Fragment:Ve,KeepAlive:UO,ReactiveEffect:wu,Static:sl,Suspense:LO,Teleport:Pl,Text:Ur,Transition:fn,TransitionGroup:ku,VueElement:nf,assertNumber:SO,callWithAsyncErrorHandling:yo,callWithErrorHandling:Wr,camelize:jn,capitalize:Ws,cloneVNode:Qo,compatUtils:VN,compile:SI,computed:k,createApp:iv,createBlock:re,createCommentVNode:te,createElementBlock:V,createElementVNode:F,createHydrationRenderer:f_,createPropsRestProxy:lN,createRenderer:d_,createSSRApp:_I,createSlots:Sr,createStaticVNode:$N,createTextVNode:Ge,createVNode:K,customRef:Rw,defineAsyncComponent:WO,defineComponent:Y,defineCustomElement:$_,defineEmits:JO,defineExpose:ZO,defineModel:tN,defineOptions:QO,defineProps:XO,defineSSRCustomElement:oI,defineSlots:eN,get devtools(){return Xl},effect:B$,effectScope:Bd,getCurrentInstance:lt,getCurrentScope:Vd,getTransitionRawChildren:Zd,guardReactiveProps:bl,h:Ke,handleError:Al,hasInjectionContext:a_,hydrate:z_,initCustomFormatter:LN,initDirectivesForSSR:CI,inject:De,isMemoSame:E_,isProxy:zm,isReactive:jr,isReadonly:ml,isRef:xt,isRuntimeOnly:AN,isShallow:ji,isVNode:Wt,markRaw:Po,mergeDefaults:rN,mergeModels:aN,mergeProps:mt,nextTick:We,normalizeClass:N,normalizeProps:vr,normalizeStyle:je,onActivated:Zm,onBeforeMount:Su,onBeforeUnmount:zt,onBeforeUpdate:ev,onDeactivated:Qm,onErrorCaptured:Zw,onMounted:at,onRenderTracked:Jw,onRenderTriggered:Xw,onScopeDispose:Hd,onServerPrefetch:Gw,onUnmounted:lr,onUpdated:ar,openBlock:T,popScopeId:Jd,provide:yt,proxyRefs:Km,pushScopeId:Xd,queuePostFlushCb:qm,reactive:Et,readonly:Ml,ref:R,registerRuntimeCompiler:MN,render:er,renderList:bt,renderSlot:ie,resolveComponent:qe,resolveDirective:qs,resolveDynamicComponent:pt,resolveFilter:BN,resolveTransitionHooks:bs,setBlockTracking:Zp,setDevtoolsHook:Vw,setTransitionHooks:vl,shallowReactive:Hm,shallowReadonly:pO,shallowRef:Ut,ssrContextKey:S_,ssrUtils:FN,stop:V$,toDisplayString:le,toHandlerKey:ls,toHandlers:t_,toRaw:Mt,toRef:Lt,toRefs:Cn,toValue:vO,transformVNodeArgs:EN,triggerRef:mO,unref:i,useAttrs:xa,useCssModule:aI,useCssVars:lI,useModel:oN,useSSRContext:k_,useSlots:Sn,useTransitionState:Xm,vModelCheckbox:wl,vModelDynamic:D_,vModelRadio:Eu,vModelSelect:L_,vModelText:yl,vShow:kt,version:T_,warn:xw,watch:ve,watchEffect:Mn,watchPostEffect:Ww,watchSyncEffect:HO,withAsyncContext:sN,withCtx:X,withDefaults:nN,withDirectives:tt,withKeys:Pt,withMemo:xN,withModifiers:Qe,withScopeId:NO},Symbol.toStringTag,{value:"Module"}));var EI=!1;/*! + * pinia v2.1.4 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */let W_;const of=e=>W_=e,K_=Symbol();function ah(e){return e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"&&typeof e.toJSON!="function"}var Ai;(function(e){e.direct="direct",e.patchObject="patch object",e.patchFunction="patch function"})(Ai||(Ai={}));function TI(){const e=Bd(!0),t=e.run(()=>R({}));let n=[],o=[];const r=Po({install(a){of(r),r._a=a,a.provide(K_,r),a.config.globalProperties.$pinia=r,o.forEach(l=>n.push(l)),o=[]},use(a){return!this._a&&!EI?o.push(a):n.push(a),this},_p:n,_a:null,_e:e,_s:new Map,state:t});return r}const U_=()=>{};function Gb(e,t,n,o=U_){e.push(t);const r=()=>{const a=e.indexOf(t);a>-1&&(e.splice(a,1),o())};return!n&&Vd()&&Hd(r),r}function Wl(e,...t){e.slice().forEach(n=>{n(...t)})}const $I=e=>e();function lh(e,t){e instanceof Map&&t instanceof Map&&t.forEach((n,o)=>e.set(o,n)),e instanceof Set&&t instanceof Set&&t.forEach(e.add,e);for(const n in t){if(!t.hasOwnProperty(n))continue;const o=t[n],r=e[n];ah(r)&&ah(o)&&e.hasOwnProperty(n)&&!xt(o)&&!jr(o)?e[n]=lh(r,o):e[n]=o}return e}const OI=Symbol();function NI(e){return!ah(e)||!e.hasOwnProperty(OI)}const{assign:fa}=Object;function II(e){return!!(xt(e)&&e.effect)}function MI(e,t,n,o){const{state:r,actions:a,getters:l}=t,s=n.state.value[e];let u;function c(){s||(n.state.value[e]=r?r():{});const f=Cn(n.state.value[e]);return fa(f,a,Object.keys(l||{}).reduce((d,p)=>(d[p]=Po(k(()=>{of(n);const m=n._s.get(e);return l[p].call(m,m)})),d),{}))}return u=q_(e,c,t,n,o,!0),u}function q_(e,t,n={},o,r,a){let l;const s=fa({actions:{}},n),u={deep:!0};let c,f,d=[],p=[],m;const v=o.state.value[e];!a&&!v&&(o.state.value[e]={}),R({});let h;function C($){let O;c=f=!1,typeof $=="function"?($(o.state.value[e]),O={type:Ai.patchFunction,storeId:e,events:m}):(lh(o.state.value[e],$),O={type:Ai.patchObject,payload:$,storeId:e,events:m});const A=h=Symbol();We().then(()=>{h===A&&(c=!0)}),f=!0,Wl(d,O,o.state.value[e])}const g=a?function(){const{state:O}=n,A=O?O():{};this.$patch(M=>{fa(M,A)})}:U_;function y(){l.stop(),d=[],p=[],o._s.delete(e)}function _($,O){return function(){of(o);const A=Array.from(arguments),M=[],D=[];function U(L){M.push(L)}function j(L){D.push(L)}Wl(p,{args:A,name:$,store:w,after:U,onError:j});let W;try{W=O.apply(this&&this.$id===e?this:w,A)}catch(L){throw Wl(D,L),L}return W instanceof Promise?W.then(L=>(Wl(M,L),L)).catch(L=>(Wl(D,L),Promise.reject(L))):(Wl(M,W),W)}}const b={_p:o,$id:e,$onAction:Gb.bind(null,p),$patch:C,$reset:g,$subscribe($,O={}){const A=Gb(d,$,O.detached,()=>M()),M=l.run(()=>ve(()=>o.state.value[e],D=>{(O.flush==="sync"?f:c)&&$({storeId:e,type:Ai.direct,events:m},D)},fa({},u,O)));return A},$dispose:y},w=Et(b);o._s.set(e,w);const S=o._a&&o._a.runWithContext||$I,E=o._e.run(()=>(l=Bd(),S(()=>l.run(t))));for(const $ in E){const O=E[$];if(xt(O)&&!II(O)||jr(O))a||(v&&NI(O)&&(xt(O)?O.value=v[$]:lh(O,v[$])),o.state.value[e][$]=O);else if(typeof O=="function"){const A=_($,O);E[$]=A,s.actions[$]=O}}return fa(w,E),fa(Mt(w),E),Object.defineProperty(w,"$state",{get:()=>o.state.value[e],set:$=>{C(O=>{fa(O,$)})}}),o._p.forEach($=>{fa(w,l.run(()=>$({store:w,app:o._a,pinia:o,options:s})))}),v&&a&&n.hydrate&&n.hydrate(w.$state,v),c=!0,f=!0,w}function Y_(e,t,n){let o,r;const a=typeof t=="function";typeof e=="string"?(o=e,r=a?n:t):(r=e,o=e.id);function l(s,u){const c=a_();return s=s||(c?De(K_,null):null),s&&of(s),s=W_,s._s.has(o)||(a?q_(o,t,r,s):MI(o,r,s)),s._s.get(o)}return l.$id=o,l}const AI="storeCommon",PI="storeTerminal",RI=(e=null,t="yyyy-mm-dd hh:MM:ss")=>{if(e=="none")return"无";e||(e=Number(new Date)),e.toString().length===10&&(e=+e*1e3);const n=new Date(e);let o;const r={"y+":n.getFullYear().toString(),"m+":(n.getMonth()+1).toString(),"d+":n.getDate().toString(),"h+":n.getHours().toString(),"M+":n.getMinutes().toString(),"s+":n.getSeconds().toString()};for(const a in r)o=new RegExp("("+a+")").exec(t),o&&(t=t.replace(o[1],o[1].length==1?r[a]:xI(r[a],o[1].length,"0")));return t},sh=[];for(let e=0;e<=15;e++)sh[e]=e.toString(16);function LI(){let e="";for(let t=1;t<=36;t++)t===9||t===14||t===19||t===24?e+="-":t===15?e+=4:t===20?e+=sh[Math.random()*4|8]:e+=sh[Math.random()*16|0];return e}const xI=(e,t,n=" ")=>{if(e.length>=t)return e;const o=t-e.length;let r=Math.ceil(o/n.length);for(;r>>=1;)n+=n,r===1&&(n+=n);return n.slice(0,o)+e},DI='a[href],button:not([disabled]),button:not([hidden]),:not([tabindex="-1"]),input:not([disabled]),input:not([type="hidden"]),select:not([disabled]),textarea:not([disabled])',FI=e=>getComputedStyle(e).position==="fixed"?!1:e.offsetParent!==null,Xb=e=>Array.from(e.querySelectorAll(DI)).filter(t=>BI(t)&&FI(t)),BI=e=>{if(e.tabIndex>0||e.tabIndex===0&&e.getAttribute("tabIndex")!==null)return!0;if(e.disabled)return!1;switch(e.nodeName){case"A":return!!e.href&&e.rel!=="ignore";case"INPUT":return!(e.type==="hidden"||e.type==="file");case"BUTTON":case"SELECT":case"TEXTAREA":return!0;default:return!1}},Nc=function(e,t,...n){let o;t.includes("mouse")||t.includes("click")?o="MouseEvents":t.includes("key")?o="KeyboardEvent":o="HTMLEvents";const r=document.createEvent(o);return r.initEvent(t,...n),e.dispatchEvent(r),e},G_=e=>!e.getAttribute("aria-owns"),X_=(e,t,n)=>{const{parentNode:o}=e;if(!o)return null;const r=o.querySelectorAll(n),a=Array.prototype.indexOf.call(r,e);return r[a+t]||null},Ic=e=>{e&&(e.focus(),!G_(e)&&e.click())},on=(e,t,{checkForDefaultPrevented:n=!0}={})=>r=>{const a=e==null?void 0:e(r);if(n===!1||!a)return t==null?void 0:t(r)},Jb=e=>t=>t.pointerType==="mouse"?e(t):void 0;var VI=Object.defineProperty,HI=Object.defineProperties,zI=Object.getOwnPropertyDescriptors,Zb=Object.getOwnPropertySymbols,jI=Object.prototype.hasOwnProperty,WI=Object.prototype.propertyIsEnumerable,Qb=(e,t,n)=>t in e?VI(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,KI=(e,t)=>{for(var n in t||(t={}))jI.call(t,n)&&Qb(e,n,t[n]);if(Zb)for(var n of Zb(t))WI.call(t,n)&&Qb(e,n,t[n]);return e},UI=(e,t)=>HI(e,zI(t));function ey(e,t){var n;const o=Ut();return Mn(()=>{o.value=e()},UI(KI({},t),{flush:(n=void 0)!=null?n:"sync"})),Ml(o)}var ty;const Ct=typeof window<"u",qI=e=>typeof e<"u",ih=e=>typeof e=="function",YI=e=>typeof e=="string",_s=()=>{},uh=Ct&&((ty=window==null?void 0:window.navigator)==null?void 0:ty.userAgent)&&/iP(ad|hone|od)/.test(window.navigator.userAgent);function Na(e){return typeof e=="function"?e():i(e)}function J_(e,t){function n(...o){return new Promise((r,a)=>{Promise.resolve(e(()=>t.apply(this,o),{fn:t,thisArg:this,args:o})).then(r).catch(a)})}return n}function GI(e,t={}){let n,o,r=_s;const a=s=>{clearTimeout(s),r(),r=_s};return s=>{const u=Na(e),c=Na(t.maxWait);return n&&a(n),u<=0||c!==void 0&&c<=0?(o&&(a(o),o=null),Promise.resolve(s())):new Promise((f,d)=>{r=t.rejectOnCancel?d:f,c&&!o&&(o=setTimeout(()=>{n&&a(n),o=null,f(s())},c)),n=setTimeout(()=>{o&&a(o),o=null,f(s())},u)})}}function XI(e,t=!0,n=!0,o=!1){let r=0,a,l=!0,s=_s,u;const c=()=>{a&&(clearTimeout(a),a=void 0,s(),s=_s)};return d=>{const p=Na(e),m=Date.now()-r,v=()=>u=d();return c(),p<=0?(r=Date.now(),v()):(m>p&&(n||!l)?(r=Date.now(),v()):t&&(u=new Promise((h,C)=>{s=o?C:h,a=setTimeout(()=>{r=Date.now(),l=!0,h(v()),c()},Math.max(0,p-m))})),!n&&!a&&(a=setTimeout(()=>l=!0,p)),l=!1,u)}}function JI(e){return e}function ZI(e,t){let n,o,r;const a=R(!0),l=()=>{a.value=!0,r()};ve(e,l,{flush:"sync"});const s=ih(t)?t:t.get,u=ih(t)?void 0:t.set,c=Rw((f,d)=>(o=f,r=d,{get(){return a.value&&(n=s(),a.value=!1),o(),n},set(p){u==null||u(p)}}));return Object.isExtensible(c)&&(c.trigger=l),c}function Tu(e){return Vd()?(Hd(e),!0):!1}function QI(e,t=200,n={}){return J_(GI(t,n),e)}function eM(e,t=200,n={}){const o=R(e.value),r=QI(()=>{o.value=e.value},t,n);return ve(e,()=>r()),o}function Z_(e,t=200,n=!1,o=!0,r=!1){return J_(XI(t,n,o,r),e)}function uv(e,t=!0){lt()?at(e):t?e():We(e)}function _l(e,t,n={}){const{immediate:o=!0}=n,r=R(!1);let a=null;function l(){a&&(clearTimeout(a),a=null)}function s(){r.value=!1,l()}function u(...c){l(),r.value=!0,a=setTimeout(()=>{r.value=!1,a=null,e(...c)},Na(t))}return o&&(r.value=!0,Ct&&u()),Tu(s),{isPending:Ml(r),start:u,stop:s}}function lo(e){var t;const n=Na(e);return(t=n==null?void 0:n.$el)!=null?t:n}const Da=Ct?window:void 0,tM=Ct?window.document:void 0;function qt(...e){let t,n,o,r;if(YI(e[0])||Array.isArray(e[0])?([n,o,r]=e,t=Da):[t,n,o,r]=e,!t)return _s;Array.isArray(n)||(n=[n]),Array.isArray(o)||(o=[o]);const a=[],l=()=>{a.forEach(f=>f()),a.length=0},s=(f,d,p,m)=>(f.addEventListener(d,p,m),()=>f.removeEventListener(d,p,m)),u=ve(()=>[lo(t),Na(r)],([f,d])=>{l(),f&&a.push(...n.flatMap(p=>o.map(m=>s(f,p,m,d))))},{immediate:!0,flush:"post"}),c=()=>{u(),l()};return Tu(c),c}let ny=!1;function cv(e,t,n={}){const{window:o=Da,ignore:r=[],capture:a=!0,detectIframe:l=!1}=n;if(!o)return;uh&&!ny&&(ny=!0,Array.from(o.document.body.children).forEach(p=>p.addEventListener("click",_s)));let s=!0;const u=p=>r.some(m=>{if(typeof m=="string")return Array.from(o.document.querySelectorAll(m)).some(v=>v===p.target||p.composedPath().includes(v));{const v=lo(m);return v&&(p.target===v||p.composedPath().includes(v))}}),f=[qt(o,"click",p=>{const m=lo(e);if(!(!m||m===p.target||p.composedPath().includes(m))){if(p.detail===0&&(s=!u(p)),!s){s=!0;return}t(p)}},{passive:!0,capture:a}),qt(o,"pointerdown",p=>{const m=lo(e);m&&(s=!p.composedPath().includes(m)&&!u(p))},{passive:!0}),l&&qt(o,"blur",p=>{var m;const v=lo(e);((m=o.document.activeElement)==null?void 0:m.tagName)==="IFRAME"&&!(v!=null&&v.contains(o.document.activeElement))&&t(p)})].filter(Boolean);return()=>f.forEach(p=>p())}function nM(e={}){var t;const{window:n=Da}=e,o=(t=e.document)!=null?t:n==null?void 0:n.document,r=ZI(()=>null,()=>o==null?void 0:o.activeElement);return n&&(qt(n,"blur",a=>{a.relatedTarget===null&&r.trigger()},!0),qt(n,"focus",r.trigger,!0)),r}function Q_(e,t=!1){const n=R(),o=()=>n.value=!!e();return o(),uv(o,t),n}function oM(e){return JSON.parse(JSON.stringify(e))}const oy=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},ry="__vueuse_ssr_handlers__";oy[ry]=oy[ry]||{};function rM(e,t,{window:n=Da,initialValue:o=""}={}){const r=R(o),a=k(()=>{var l;return lo(t)||((l=n==null?void 0:n.document)==null?void 0:l.documentElement)});return ve([a,()=>Na(e)],([l,s])=>{var u;if(l&&n){const c=(u=n.getComputedStyle(l).getPropertyValue(s))==null?void 0:u.trim();r.value=c||o}},{immediate:!0}),ve(r,l=>{var s;(s=a.value)!=null&&s.style&&a.value.style.setProperty(Na(e),l)}),r}function aM({document:e=tM}={}){if(!e)return R("visible");const t=R(e.visibilityState);return qt(e,"visibilitychange",()=>{t.value=e.visibilityState}),t}var ay=Object.getOwnPropertySymbols,lM=Object.prototype.hasOwnProperty,sM=Object.prototype.propertyIsEnumerable,iM=(e,t)=>{var n={};for(var o in e)lM.call(e,o)&&t.indexOf(o)<0&&(n[o]=e[o]);if(e!=null&&ay)for(var o of ay(e))t.indexOf(o)<0&&sM.call(e,o)&&(n[o]=e[o]);return n};function Qt(e,t,n={}){const o=n,{window:r=Da}=o,a=iM(o,["window"]);let l;const s=Q_(()=>r&&"ResizeObserver"in r),u=()=>{l&&(l.disconnect(),l=void 0)},c=ve(()=>lo(e),d=>{u(),s.value&&r&&d&&(l=new ResizeObserver(t),l.observe(d,a))},{immediate:!0,flush:"post"}),f=()=>{u(),c()};return Tu(f),{isSupported:s,stop:f}}function ly(e,t={}){const{reset:n=!0,windowResize:o=!0,windowScroll:r=!0,immediate:a=!0}=t,l=R(0),s=R(0),u=R(0),c=R(0),f=R(0),d=R(0),p=R(0),m=R(0);function v(){const h=lo(e);if(!h){n&&(l.value=0,s.value=0,u.value=0,c.value=0,f.value=0,d.value=0,p.value=0,m.value=0);return}const C=h.getBoundingClientRect();l.value=C.height,s.value=C.bottom,u.value=C.left,c.value=C.right,f.value=C.top,d.value=C.width,p.value=C.x,m.value=C.y}return Qt(e,v),ve(()=>lo(e),h=>!h&&v()),r&&qt("scroll",v,{capture:!0,passive:!0}),o&&qt("resize",v,{passive:!0}),uv(()=>{a&&v()}),{height:l,bottom:s,left:u,right:c,top:f,width:d,x:p,y:m,update:v}}var sy=Object.getOwnPropertySymbols,uM=Object.prototype.hasOwnProperty,cM=Object.prototype.propertyIsEnumerable,dM=(e,t)=>{var n={};for(var o in e)uM.call(e,o)&&t.indexOf(o)<0&&(n[o]=e[o]);if(e!=null&&sy)for(var o of sy(e))t.indexOf(o)<0&&cM.call(e,o)&&(n[o]=e[o]);return n};function eC(e,t,n={}){const o=n,{window:r=Da}=o,a=dM(o,["window"]);let l;const s=Q_(()=>r&&"MutationObserver"in r),u=()=>{l&&(l.disconnect(),l=void 0)},c=ve(()=>lo(e),d=>{u(),s.value&&r&&d&&(l=new MutationObserver(t),l.observe(d,a))},{immediate:!0}),f=()=>{u(),c()};return Tu(f),{isSupported:s,stop:f}}var iy;(function(e){e.UP="UP",e.RIGHT="RIGHT",e.DOWN="DOWN",e.LEFT="LEFT",e.NONE="NONE"})(iy||(iy={}));var fM=Object.defineProperty,uy=Object.getOwnPropertySymbols,pM=Object.prototype.hasOwnProperty,hM=Object.prototype.propertyIsEnumerable,cy=(e,t,n)=>t in e?fM(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,mM=(e,t)=>{for(var n in t||(t={}))pM.call(t,n)&&cy(e,n,t[n]);if(uy)for(var n of uy(t))hM.call(t,n)&&cy(e,n,t[n]);return e};const vM={easeInSine:[.12,0,.39,0],easeOutSine:[.61,1,.88,1],easeInOutSine:[.37,0,.63,1],easeInQuad:[.11,0,.5,0],easeOutQuad:[.5,1,.89,1],easeInOutQuad:[.45,0,.55,1],easeInCubic:[.32,0,.67,0],easeOutCubic:[.33,1,.68,1],easeInOutCubic:[.65,0,.35,1],easeInQuart:[.5,0,.75,0],easeOutQuart:[.25,1,.5,1],easeInOutQuart:[.76,0,.24,1],easeInQuint:[.64,0,.78,0],easeOutQuint:[.22,1,.36,1],easeInOutQuint:[.83,0,.17,1],easeInExpo:[.7,0,.84,0],easeOutExpo:[.16,1,.3,1],easeInOutExpo:[.87,0,.13,1],easeInCirc:[.55,0,1,.45],easeOutCirc:[0,.55,.45,1],easeInOutCirc:[.85,0,.15,1],easeInBack:[.36,0,.66,-.56],easeOutBack:[.34,1.56,.64,1],easeInOutBack:[.68,-.6,.32,1.6]};mM({linear:JI},vM);function tC(e,t,n,o={}){var r,a,l;const{clone:s=!1,passive:u=!1,eventName:c,deep:f=!1,defaultValue:d}=o,p=lt(),m=n||(p==null?void 0:p.emit)||((r=p==null?void 0:p.$emit)==null?void 0:r.bind(p))||((l=(a=p==null?void 0:p.proxy)==null?void 0:a.$emit)==null?void 0:l.bind(p==null?void 0:p.proxy));let v=c;t||(t="modelValue"),v=c||v||`update:${t.toString()}`;const h=g=>s?ih(s)?s(g):oM(g):g,C=()=>qI(e[t])?h(e[t]):d;if(u){const g=C(),y=R(g);return ve(()=>e[t],_=>y.value=h(_)),ve(y,_=>{(_!==e[t]||f)&&m(v,_)},{deep:f}),y}else return k({get(){return C()},set(g){m(v,g)}})}function gM({window:e=Da}={}){if(!e)return R(!1);const t=R(e.document.hasFocus());return qt(e,"blur",()=>{t.value=!1}),qt(e,"focus",()=>{t.value=!0}),t}function bM(e={}){const{window:t=Da,initialWidth:n=1/0,initialHeight:o=1/0,listenOrientation:r=!0,includeScrollbar:a=!0}=e,l=R(n),s=R(o),u=()=>{t&&(a?(l.value=t.innerWidth,s.value=t.innerHeight):(l.value=t.document.documentElement.clientWidth,s.value=t.document.documentElement.clientHeight))};return u(),uv(u),qt("resize",u,{passive:!0}),r&&qt("orientationchange",u,{passive:!0}),{width:l,height:s}}const nC=()=>Ct&&/firefox/i.test(window.navigator.userAgent),yM=(e,t)=>{if(!Ct||!e||!t)return!1;const n=e.getBoundingClientRect();let o;return t instanceof Element?o=t.getBoundingClientRect():o={top:0,right:window.innerWidth,bottom:window.innerHeight,left:0},n.topo.top&&n.right>o.left&&n.left{let t=0,n=e;for(;n;)t+=n.offsetTop,n=n.offsetParent;return t},ch=(e,t)=>Math.abs(dy(e)-dy(t)),dv=e=>{let t,n;return e.type==="touchend"?(n=e.changedTouches[0].clientY,t=e.changedTouches[0].clientX):e.type.startsWith("touch")?(n=e.touches[0].clientY,t=e.touches[0].clientX):(n=e.clientY,t=e.clientX),{clientX:t,clientY:n}};function wM(e,t,n,o){const r=n-t;return e/=o/2,e<1?r/2*e*e*e+t:r/2*((e-=2)*e*e+2)+t}var oC=typeof global=="object"&&global&&global.Object===Object&&global,_M=typeof self=="object"&&self&&self.Object===Object&&self,sr=oC||_M||Function("return this")(),Do=sr.Symbol,rC=Object.prototype,CM=rC.hasOwnProperty,SM=rC.toString,pi=Do?Do.toStringTag:void 0;function kM(e){var t=CM.call(e,pi),n=e[pi];try{e[pi]=void 0;var o=!0}catch{}var r=SM.call(e);return o&&(t?e[pi]=n:delete e[pi]),r}var EM=Object.prototype,TM=EM.toString;function $M(e){return TM.call(e)}var OM="[object Null]",NM="[object Undefined]",fy=Do?Do.toStringTag:void 0;function Rl(e){return e==null?e===void 0?NM:OM:fy&&fy in Object(e)?kM(e):$M(e)}function kr(e){return e!=null&&typeof e=="object"}var IM="[object Symbol]";function rf(e){return typeof e=="symbol"||kr(e)&&Rl(e)==IM}function fv(e,t){for(var n=-1,o=e==null?0:e.length,r=Array(o);++n0){if(++t>=aA)return arguments[0]}else t=0;return e.apply(void 0,arguments)}}function uA(e){return function(){return e}}var dd=function(){try{var e=xl(Object,"defineProperty");return e({},"",{}),e}catch{}}(),cA=dd?function(e,t){return dd(e,"toString",{configurable:!0,enumerable:!1,value:uA(t),writable:!0})}:pv,sC=iA(cA);function dA(e,t){for(var n=-1,o=e==null?0:e.length;++n-1}var vA=9007199254740991,gA=/^(?:0|[1-9]\d*)$/;function af(e,t){var n=typeof e;return t=t??vA,!!t&&(n=="number"||n!="symbol"&&gA.test(e))&&e>-1&&e%1==0&&e-1&&e%1==0&&e<=wA}function Gs(e){return e!=null&&gv(e.length)&&!hv(e)}function _A(e,t,n){if(!eo(n))return!1;var o=typeof t;return(o=="number"?Gs(n)&&af(t,n.length):o=="string"&&t in n)?$u(n[t],e):!1}function CA(e){return cC(function(t,n){var o=-1,r=n.length,a=r>1?n[r-1]:void 0,l=r>2?n[2]:void 0;for(a=e.length>3&&typeof a=="function"?(r--,a):void 0,l&&_A(n[0],n[1],l)&&(a=r<3?void 0:a,r=1),t=Object(t);++o-1}function AP(e,t){var n=this.__data__,o=lf(n,e);return o<0?(++this.size,n.push([e,t])):n[o][1]=t,this}function Jr(e){var t=-1,n=e==null?0:e.length;for(this.clear();++t0&&n(s)?t>1?Iu(s,t-1,n,o,r):Cv(r,s):o||(r[r.length]=s)}return r}function vC(e){var t=e==null?0:e.length;return t?Iu(e,1):[]}function gC(e){return sC(uC(e,void 0,vC),e+"")}var Sv=mC(Object.getPrototypeOf,Object),YP="[object Object]",GP=Function.prototype,XP=Object.prototype,bC=GP.toString,JP=XP.hasOwnProperty,ZP=bC.call(Object);function yC(e){if(!kr(e)||Rl(e)!=YP)return!1;var t=Sv(e);if(t===null)return!0;var n=JP.call(t,"constructor")&&t.constructor;return typeof n=="function"&&n instanceof n&&bC.call(n)==ZP}function QP(e,t,n){var o=-1,r=e.length;t<0&&(t=-t>r?0:r+t),n=n>r?r:n,n<0&&(n+=r),r=t>n?0:n-t>>>0,t>>>=0;for(var a=Array(r);++os))return!1;var c=a.get(e),f=a.get(t);if(c&&f)return c==t&&f==e;var d=-1,p=!0,m=n&RL?new tu:void 0;for(a.set(e,t),a.set(t,e);++d=t||E<0||d&&$>=a}function g(){var S=ip();if(C(S))return y(S);s=setTimeout(g,h(S))}function y(S){return s=void 0,p&&o?m(S):(o=r=void 0,l)}function _(){s!==void 0&&clearTimeout(s),c=0,o=u=r=s=void 0}function b(){return s===void 0?l:y(ip())}function w(){var S=ip(),E=C(S);if(o=arguments,r=this,u=S,E){if(s===void 0)return v(u);if(d)return clearTimeout(s),s=setTimeout(g,t),m(u)}return s===void 0&&(s=setTimeout(g,t)),l}return w.cancel=_,w.flush=b,w}function mh(e,t,n){(n!==void 0&&!$u(e[t],n)||n===void 0&&!(t in e))&&mv(e,t,n)}function FC(e){return kr(e)&&Gs(e)}function vh(e,t){if(!(t==="constructor"&&typeof e[t]=="function")&&t!="__proto__")return e[t]}function Sx(e){return Ys(e,Nu(e))}function kx(e,t,n,o,r,a,l){var s=vh(e,n),u=vh(t,n),c=l.get(u);if(c){mh(e,n,c);return}var f=a?a(s,u,n+"",e,t,l):void 0,d=f===void 0;if(d){var p=Qn(u),m=!p&&Zi(u),v=!p&&!m&&wv(u);f=u,p||m||v?Qn(s)?f=s:FC(s)?f=lC(s):m?(d=!1,f=_C(u,!0)):v?(d=!1,f=TC(u,!0)):f=[]:yC(u)||Ji(u)?(f=s,Ji(s)?f=Sx(s):(!eo(s)||hv(s))&&(f=$C(u))):d=!1}d&&(l.set(u,f),r(f,u,o,a,l),l.delete(u)),mh(e,n,f)}function BC(e,t,n,o,r){e!==t&&DC(t,function(a,l){if(r||(r=new Zo),eo(a))kx(e,t,l,n,BC,o,r);else{var s=o?o(vh(e,l),a,l+"",e,t,r):void 0;s===void 0&&(s=a),mh(e,l,s)}},Nu)}function Ex(e){var t=e==null?0:e.length;return t?e[t-1]:void 0}function VC(e,t,n){var o=e==null?0:e.length;if(!o)return-1;var r=o-1;return iC(e,xC(t),r,!0)}function Tx(e,t){var n=-1,o=Gs(e)?Array(e.length):[];return yx(e,function(r,a,l){o[++n]=t(r,a,l)}),o}function $x(e,t){var n=Qn(e)?fv:Tx;return n(e,xC(t))}function Ox(e,t){return Iu($x(e,t),1)}var Nx=1/0;function Ix(e){var t=e==null?0:e.length;return t?Iu(e,Nx):[]}function hd(e){for(var t=-1,n=e==null?0:e.length,o={};++t1),a}),Ys(e,EC(e),n),o&&(n=ds(n,Lx|xx|Dx,Rx));for(var r=t.length;r--;)Px(n,t[r]);return n});function zC(e,t,n,o){if(!eo(e))return e;t=Xs(t,e);for(var r=-1,a=t.length,l=a-1,s=e;s!=null&&++r=Kx){var c=Wx(e);if(c)return Tv(c);l=!1,r=MC,u=new tu}else u=s;e:for(;++oe===void 0,dn=e=>typeof e=="boolean",Je=e=>typeof e=="number",Io=e=>!e&&e!==0||Pe(e)&&e.length===0||dt(e)&&!Object.keys(e).length,Fo=e=>typeof Element>"u"?!1:e instanceof Element,Sl=e=>Tn(e),qx=e=>nt(e)?!Number.isNaN(Number(e)):!1,ff=e=>e===window,Ma=e=>Ct?window.requestAnimationFrame(e):setTimeout(e,16),kl=e=>Ct?window.cancelAnimationFrame(e):clearTimeout(e),$v=(e="")=>e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&").replace(/-/g,"\\x2d"),mr=e=>Ws(e),Ss=e=>Object.keys(e),Yx=e=>Object.entries(e),Mc=(e,t,n)=>({get value(){return un(e,t,n)},set value(o){Hx(e,t,o)}});class Gx extends Error{constructor(t){super(t),this.name="ElementPlusError"}}function vn(e,t){throw new Gx(`[${e}] ${t}`)}const jC=(e="")=>e.split(" ").filter(t=>!!t.trim()),wo=(e,t)=>{if(!e||!t)return!1;if(t.includes(" "))throw new Error("className should not contain space.");return e.classList.contains(t)},Mo=(e,t)=>{!e||!t.trim()||e.classList.add(...jC(t))},Kn=(e,t)=>{!e||!t.trim()||e.classList.remove(...jC(t))},ga=(e,t)=>{var n;if(!Ct||!e||!t)return"";let o=jn(t);o==="float"&&(o="cssFloat");try{const r=e.style[o];if(r)return r;const a=(n=document.defaultView)==null?void 0:n.getComputedStyle(e,"");return a?a[o]:""}catch{return e.style[o]}};function rn(e,t="px"){if(!e)return"";if(Je(e)||qx(e))return`${e}${t}`;if(nt(e))return e}const Xx=(e,t)=>{if(!Ct)return!1;const n={undefined:"overflow",true:"overflow-y",false:"overflow-x"}[String(t)],o=ga(e,n);return["scroll","auto","overlay"].some(r=>o.includes(r))},Ov=(e,t)=>{if(!Ct)return;let n=e;for(;n;){if([window,document,document.documentElement].includes(n))return window;if(Xx(n,t))return n;n=n.parentNode}return n};let sc;const WC=e=>{var t;if(!Ct)return 0;if(sc!==void 0)return sc;const n=document.createElement("div");n.className=`${e}-scrollbar__wrap`,n.style.visibility="hidden",n.style.width="100px",n.style.position="absolute",n.style.top="-9999px",document.body.appendChild(n);const o=n.offsetWidth;n.style.overflow="scroll";const r=document.createElement("div");r.style.width="100%",n.appendChild(r);const a=r.offsetWidth;return(t=n.parentNode)==null||t.removeChild(n),sc=o-a,sc};function KC(e,t){if(!Ct)return;if(!t){e.scrollTop=0;return}const n=[];let o=t.offsetParent;for(;o!==null&&e!==o&&e.contains(o);)n.push(o),o=o.offsetParent;const r=t.offsetTop+n.reduce((u,c)=>u+c.offsetTop,0),a=r+t.offsetHeight,l=e.scrollTop,s=l+e.clientHeight;rs&&(e.scrollTop=a-e.clientHeight)}function Jx(e,t,n,o,r){const a=Date.now();let l;const s=()=>{const c=Date.now()-a,f=wM(c>o?o:c,t,n,o);ff(e)?e.scrollTo(window.pageXOffset,f):e.scrollTop=f,c{l&&kl(l)}}const jy=(e,t)=>ff(t)?e.ownerDocument.documentElement:t,Wy=e=>ff(e)?window.scrollY:e.scrollTop,ic=e=>{if(!Ct||e==="")return null;if(nt(e))try{return document.querySelector(e)}catch{return null}return e};/*! Element Plus Icons Vue v2.3.1 */var Zx=Y({name:"ArrowDown",__name:"arrow-down",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M831.872 340.864 512 652.672 192.128 340.864a30.592 30.592 0 0 0-42.752 0 29.12 29.12 0 0 0 0 41.6L489.664 714.24a32 32 0 0 0 44.672 0l340.288-331.712a29.12 29.12 0 0 0 0-41.728 30.592 30.592 0 0 0-42.752 0z"})]))}}),Nr=Zx,Qx=Y({name:"ArrowLeft",__name:"arrow-left",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M609.408 149.376 277.76 489.6a32 32 0 0 0 0 44.672l331.648 340.352a29.12 29.12 0 0 0 41.728 0 30.592 30.592 0 0 0 0-42.752L339.264 511.936l311.872-319.872a30.592 30.592 0 0 0 0-42.688 29.12 29.12 0 0 0-41.728 0z"})]))}}),Aa=Qx,e4=Y({name:"ArrowRight",__name:"arrow-right",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M340.864 149.312a30.592 30.592 0 0 0 0 42.752L652.736 512 340.864 831.872a30.592 30.592 0 0 0 0 42.752 29.12 29.12 0 0 0 41.728 0L714.24 534.336a32 32 0 0 0 0-44.672L382.592 149.376a29.12 29.12 0 0 0-41.728 0z"})]))}}),Jn=e4,t4=Y({name:"ArrowUp",__name:"arrow-up",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"m488.832 344.32-339.84 356.672a32 32 0 0 0 0 44.16l.384.384a29.44 29.44 0 0 0 42.688 0l320-335.872 319.872 335.872a29.44 29.44 0 0 0 42.688 0l.384-.384a32 32 0 0 0 0-44.16L535.168 344.32a32 32 0 0 0-46.336 0"})]))}}),pf=t4,n4=Y({name:"Back",__name:"back",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M224 480h640a32 32 0 1 1 0 64H224a32 32 0 0 1 0-64"}),F("path",{fill:"currentColor",d:"m237.248 512 265.408 265.344a32 32 0 0 1-45.312 45.312l-288-288a32 32 0 0 1 0-45.312l288-288a32 32 0 1 1 45.312 45.312z"})]))}}),o4=n4,r4=Y({name:"Calendar",__name:"calendar",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M128 384v512h768V192H768v32a32 32 0 1 1-64 0v-32H320v32a32 32 0 0 1-64 0v-32H128v128h768v64zm192-256h384V96a32 32 0 1 1 64 0v32h160a32 32 0 0 1 32 32v768a32 32 0 0 1-32 32H96a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h160V96a32 32 0 0 1 64 0zm-32 384h64a32 32 0 0 1 0 64h-64a32 32 0 0 1 0-64m0 192h64a32 32 0 1 1 0 64h-64a32 32 0 1 1 0-64m192-192h64a32 32 0 0 1 0 64h-64a32 32 0 0 1 0-64m0 192h64a32 32 0 1 1 0 64h-64a32 32 0 1 1 0-64m192-192h64a32 32 0 1 1 0 64h-64a32 32 0 1 1 0-64m0 192h64a32 32 0 1 1 0 64h-64a32 32 0 1 1 0-64"})]))}}),a4=r4,l4=Y({name:"CaretRight",__name:"caret-right",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M384 192v640l384-320.064z"})]))}}),UC=l4,s4=Y({name:"CaretTop",__name:"caret-top",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 320 192 704h639.936z"})]))}}),i4=s4,u4=Y({name:"Check",__name:"check",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M406.656 706.944 195.84 496.256a32 32 0 1 0-45.248 45.248l256 256 512-512a32 32 0 0 0-45.248-45.248L406.592 706.944z"})]))}}),Mu=u4,c4=Y({name:"CircleCheckFilled",__name:"circle-check-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896m-55.808 536.384-99.52-99.584a38.4 38.4 0 1 0-54.336 54.336l126.72 126.72a38.272 38.272 0 0 0 54.336 0l262.4-262.464a38.4 38.4 0 1 0-54.272-54.336z"})]))}}),d4=c4,f4=Y({name:"CircleCheck",__name:"circle-check",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768m0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896"}),F("path",{fill:"currentColor",d:"M745.344 361.344a32 32 0 0 1 45.312 45.312l-288 288a32 32 0 0 1-45.312 0l-160-160a32 32 0 1 1 45.312-45.312L480 626.752l265.344-265.408z"})]))}}),Nv=f4,p4=Y({name:"CircleCloseFilled",__name:"circle-close-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896m0 393.664L407.936 353.6a38.4 38.4 0 1 0-54.336 54.336L457.664 512 353.6 616.064a38.4 38.4 0 1 0 54.336 54.336L512 566.336 616.064 670.4a38.4 38.4 0 1 0 54.336-54.336L566.336 512 670.4 407.936a38.4 38.4 0 1 0-54.336-54.336z"})]))}}),Iv=p4,h4=Y({name:"CircleClose",__name:"circle-close",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"m466.752 512-90.496-90.496a32 32 0 0 1 45.248-45.248L512 466.752l90.496-90.496a32 32 0 1 1 45.248 45.248L557.248 512l90.496 90.496a32 32 0 1 1-45.248 45.248L512 557.248l-90.496 90.496a32 32 0 0 1-45.248-45.248z"}),F("path",{fill:"currentColor",d:"M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768m0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896"})]))}}),Fa=h4,m4=Y({name:"Clock",__name:"clock",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768m0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896"}),F("path",{fill:"currentColor",d:"M480 256a32 32 0 0 1 32 32v256a32 32 0 0 1-64 0V288a32 32 0 0 1 32-32"}),F("path",{fill:"currentColor",d:"M480 512h256q32 0 32 32t-32 32H480q-32 0-32-32t32-32"})]))}}),qC=m4,v4=Y({name:"Close",__name:"close",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M764.288 214.592 512 466.88 259.712 214.592a31.936 31.936 0 0 0-45.12 45.12L466.752 512 214.528 764.224a31.936 31.936 0 1 0 45.12 45.184L512 557.184l252.288 252.288a31.936 31.936 0 0 0 45.12-45.12L557.12 512.064l252.288-252.352a31.936 31.936 0 1 0-45.12-45.184z"})]))}}),tr=v4,g4=Y({name:"DArrowLeft",__name:"d-arrow-left",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M529.408 149.376a29.12 29.12 0 0 1 41.728 0 30.592 30.592 0 0 1 0 42.688L259.264 511.936l311.872 319.936a30.592 30.592 0 0 1-.512 43.264 29.12 29.12 0 0 1-41.216-.512L197.76 534.272a32 32 0 0 1 0-44.672l331.648-340.224zm256 0a29.12 29.12 0 0 1 41.728 0 30.592 30.592 0 0 1 0 42.688L515.264 511.936l311.872 319.936a30.592 30.592 0 0 1-.512 43.264 29.12 29.12 0 0 1-41.216-.512L453.76 534.272a32 32 0 0 1 0-44.672l331.648-340.224z"})]))}}),ks=g4,b4=Y({name:"DArrowRight",__name:"d-arrow-right",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M452.864 149.312a29.12 29.12 0 0 1 41.728.064L826.24 489.664a32 32 0 0 1 0 44.672L494.592 874.624a29.12 29.12 0 0 1-41.728 0 30.592 30.592 0 0 1 0-42.752L764.736 512 452.864 192a30.592 30.592 0 0 1 0-42.688m-256 0a29.12 29.12 0 0 1 41.728.064L570.24 489.664a32 32 0 0 1 0 44.672L238.592 874.624a29.12 29.12 0 0 1-41.728 0 30.592 30.592 0 0 1 0-42.752L508.736 512 196.864 192a30.592 30.592 0 0 1 0-42.688z"})]))}}),Es=b4,y4=Y({name:"Delete",__name:"delete",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M160 256H96a32 32 0 0 1 0-64h256V95.936a32 32 0 0 1 32-32h256a32 32 0 0 1 32 32V192h256a32 32 0 1 1 0 64h-64v672a32 32 0 0 1-32 32H192a32 32 0 0 1-32-32zm448-64v-64H416v64zM224 896h576V256H224zm192-128a32 32 0 0 1-32-32V416a32 32 0 0 1 64 0v320a32 32 0 0 1-32 32m192 0a32 32 0 0 1-32-32V416a32 32 0 0 1 64 0v320a32 32 0 0 1-32 32"})]))}}),YC=y4,w4=Y({name:"Document",__name:"document",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M832 384H576V128H192v768h640zm-26.496-64L640 154.496V320zM160 64h480l256 256v608a32 32 0 0 1-32 32H160a32 32 0 0 1-32-32V96a32 32 0 0 1 32-32m160 448h384v64H320zm0-192h160v64H320zm0 384h384v64H320z"})]))}}),_4=w4,C4=Y({name:"FullScreen",__name:"full-screen",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"m160 96.064 192 .192a32 32 0 0 1 0 64l-192-.192V352a32 32 0 0 1-64 0V96h64zm0 831.872V928H96V672a32 32 0 1 1 64 0v191.936l192-.192a32 32 0 1 1 0 64zM864 96.064V96h64v256a32 32 0 1 1-64 0V160.064l-192 .192a32 32 0 1 1 0-64l192-.192zm0 831.872-192-.192a32 32 0 0 1 0-64l192 .192V672a32 32 0 1 1 64 0v256h-64z"})]))}}),S4=C4,k4=Y({name:"Hide",__name:"hide",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M876.8 156.8c0-9.6-3.2-16-9.6-22.4-6.4-6.4-12.8-9.6-22.4-9.6-9.6 0-16 3.2-22.4 9.6L736 220.8c-64-32-137.6-51.2-224-60.8-160 16-288 73.6-377.6 176C44.8 438.4 0 496 0 512s48 73.6 134.4 176c22.4 25.6 44.8 48 73.6 67.2l-86.4 89.6c-6.4 6.4-9.6 12.8-9.6 22.4 0 9.6 3.2 16 9.6 22.4 6.4 6.4 12.8 9.6 22.4 9.6 9.6 0 16-3.2 22.4-9.6l704-710.4c3.2-6.4 6.4-12.8 6.4-22.4Zm-646.4 528c-76.8-70.4-128-128-153.6-172.8 28.8-48 80-105.6 153.6-172.8C304 272 400 230.4 512 224c64 3.2 124.8 19.2 176 44.8l-54.4 54.4C598.4 300.8 560 288 512 288c-64 0-115.2 22.4-160 64s-64 96-64 160c0 48 12.8 89.6 35.2 124.8L256 707.2c-9.6-6.4-19.2-16-25.6-22.4Zm140.8-96c-12.8-22.4-19.2-48-19.2-76.8 0-44.8 16-83.2 48-112 32-28.8 67.2-48 112-48 28.8 0 54.4 6.4 73.6 19.2zM889.599 336c-12.8-16-28.8-28.8-41.6-41.6l-48 48c73.6 67.2 124.8 124.8 150.4 169.6-28.8 48-80 105.6-153.6 172.8-73.6 67.2-172.8 108.8-284.8 115.2-51.2-3.2-99.2-12.8-140.8-28.8l-48 48c57.6 22.4 118.4 38.4 188.8 44.8 160-16 288-73.6 377.6-176C979.199 585.6 1024 528 1024 512s-48.001-73.6-134.401-176Z"}),F("path",{fill:"currentColor",d:"M511.998 672c-12.8 0-25.6-3.2-38.4-6.4l-51.2 51.2c28.8 12.8 57.6 19.2 89.6 19.2 64 0 115.2-22.4 160-64 41.6-41.6 64-96 64-160 0-32-6.4-64-19.2-89.6l-51.2 51.2c3.2 12.8 6.4 25.6 6.4 38.4 0 44.8-16 83.2-48 112-32 28.8-67.2 48-112 48Z"})]))}}),E4=k4,T4=Y({name:"InfoFilled",__name:"info-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 64a448 448 0 1 1 0 896.064A448 448 0 0 1 512 64m67.2 275.072c33.28 0 60.288-23.104 60.288-57.344s-27.072-57.344-60.288-57.344c-33.28 0-60.16 23.104-60.16 57.344s26.88 57.344 60.16 57.344M590.912 699.2c0-6.848 2.368-24.64 1.024-34.752l-52.608 60.544c-10.88 11.456-24.512 19.392-30.912 17.28a12.992 12.992 0 0 1-8.256-14.72l87.68-276.992c7.168-35.136-12.544-67.2-54.336-71.296-44.096 0-108.992 44.736-148.48 101.504 0 6.784-1.28 23.68.064 33.792l52.544-60.608c10.88-11.328 23.552-19.328 29.952-17.152a12.8 12.8 0 0 1 7.808 16.128L388.48 728.576c-10.048 32.256 8.96 63.872 55.04 71.04 67.84 0 107.904-43.648 147.456-100.416z"})]))}}),Mv=T4,$4=Y({name:"Loading",__name:"loading",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32m0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32m448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32m-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32M195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0m-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"})]))}}),Er=$4,O4=Y({name:"Minus",__name:"minus",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M128 544h768a32 32 0 1 0 0-64H128a32 32 0 0 0 0 64"})]))}}),N4=O4,I4=Y({name:"MoreFilled",__name:"more-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M176 416a112 112 0 1 1 0 224 112 112 0 0 1 0-224m336 0a112 112 0 1 1 0 224 112 112 0 0 1 0-224m336 0a112 112 0 1 1 0 224 112 112 0 0 1 0-224"})]))}}),Ky=I4,M4=Y({name:"More",__name:"more",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M176 416a112 112 0 1 0 0 224 112 112 0 0 0 0-224m0 64a48 48 0 1 1 0 96 48 48 0 0 1 0-96m336-64a112 112 0 1 1 0 224 112 112 0 0 1 0-224m0 64a48 48 0 1 0 0 96 48 48 0 0 0 0-96m336-64a112 112 0 1 1 0 224 112 112 0 0 1 0-224m0 64a48 48 0 1 0 0 96 48 48 0 0 0 0-96"})]))}}),A4=M4,P4=Y({name:"PictureFilled",__name:"picture-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M96 896a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h832a32 32 0 0 1 32 32v704a32 32 0 0 1-32 32zm315.52-228.48-68.928-68.928a32 32 0 0 0-45.248 0L128 768.064h778.688l-242.112-290.56a32 32 0 0 0-49.216 0L458.752 665.408a32 32 0 0 1-47.232 2.112M256 384a96 96 0 1 0 192.064-.064A96 96 0 0 0 256 384"})]))}}),R4=P4,L4=Y({name:"Plus",__name:"plus",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M480 480V128a32 32 0 0 1 64 0v352h352a32 32 0 1 1 0 64H544v352a32 32 0 1 1-64 0V544H128a32 32 0 0 1 0-64z"})]))}}),GC=L4,x4=Y({name:"Promotion",__name:"promotion",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"m64 448 832-320-128 704-446.08-243.328L832 192 242.816 545.472zm256 512V657.024L512 768z"})]))}}),D4=x4,F4=Y({name:"QuestionFilled",__name:"question-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896m23.744 191.488c-52.096 0-92.928 14.784-123.2 44.352-30.976 29.568-45.76 70.4-45.76 122.496h80.256c0-29.568 5.632-52.8 17.6-68.992 13.376-19.712 35.2-28.864 66.176-28.864 23.936 0 42.944 6.336 56.32 19.712 12.672 13.376 19.712 31.68 19.712 54.912 0 17.6-6.336 34.496-19.008 49.984l-8.448 9.856c-45.76 40.832-73.216 70.4-82.368 89.408-9.856 19.008-14.08 42.24-14.08 68.992v9.856h80.96v-9.856c0-16.896 3.52-31.68 10.56-45.76 6.336-12.672 15.488-24.64 28.16-35.2 33.792-29.568 54.208-48.576 60.544-55.616 16.896-22.528 26.048-51.392 26.048-86.592 0-42.944-14.08-76.736-42.24-101.376-28.16-25.344-65.472-37.312-111.232-37.312zm-12.672 406.208a54.272 54.272 0 0 0-38.72 14.784 49.408 49.408 0 0 0-15.488 38.016c0 15.488 4.928 28.16 15.488 38.016A54.848 54.848 0 0 0 523.072 768c15.488 0 28.16-4.928 38.72-14.784a51.52 51.52 0 0 0 16.192-38.72 51.968 51.968 0 0 0-15.488-38.016 55.936 55.936 0 0 0-39.424-14.784z"})]))}}),B4=F4,V4=Y({name:"RefreshLeft",__name:"refresh-left",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M289.088 296.704h92.992a32 32 0 0 1 0 64H232.96a32 32 0 0 1-32-32V179.712a32 32 0 0 1 64 0v50.56a384 384 0 0 1 643.84 282.88 384 384 0 0 1-383.936 384 384 384 0 0 1-384-384h64a320 320 0 1 0 640 0 320 320 0 0 0-555.712-216.448z"})]))}}),H4=V4,z4=Y({name:"RefreshRight",__name:"refresh-right",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M784.512 230.272v-50.56a32 32 0 1 1 64 0v149.056a32 32 0 0 1-32 32H667.52a32 32 0 1 1 0-64h92.992A320 320 0 1 0 524.8 833.152a320 320 0 0 0 320-320h64a384 384 0 0 1-384 384 384 384 0 0 1-384-384 384 384 0 0 1 643.712-282.88z"})]))}}),XC=z4,j4=Y({name:"ScaleToOriginal",__name:"scale-to-original",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M813.176 180.706a60.235 60.235 0 0 1 60.236 60.235v481.883a60.235 60.235 0 0 1-60.236 60.235H210.824a60.235 60.235 0 0 1-60.236-60.235V240.94a60.235 60.235 0 0 1 60.236-60.235h602.352zm0-60.235H210.824A120.47 120.47 0 0 0 90.353 240.94v481.883a120.47 120.47 0 0 0 120.47 120.47h602.353a120.47 120.47 0 0 0 120.471-120.47V240.94a120.47 120.47 0 0 0-120.47-120.47zm-120.47 180.705a30.118 30.118 0 0 0-30.118 30.118v301.177a30.118 30.118 0 0 0 60.236 0V331.294a30.118 30.118 0 0 0-30.118-30.118zm-361.412 0a30.118 30.118 0 0 0-30.118 30.118v301.177a30.118 30.118 0 1 0 60.236 0V331.294a30.118 30.118 0 0 0-30.118-30.118M512 361.412a30.118 30.118 0 0 0-30.118 30.117v30.118a30.118 30.118 0 0 0 60.236 0V391.53A30.118 30.118 0 0 0 512 361.412M512 512a30.118 30.118 0 0 0-30.118 30.118v30.117a30.118 30.118 0 0 0 60.236 0v-30.117A30.118 30.118 0 0 0 512 512"})]))}}),W4=j4,K4=Y({name:"Search",__name:"search",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"m795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704"})]))}}),U4=K4,q4=Y({name:"SortDown",__name:"sort-down",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M576 96v709.568L333.312 562.816A32 32 0 1 0 288 608l297.408 297.344A32 32 0 0 0 640 882.688V96a32 32 0 0 0-64 0"})]))}}),Y4=q4,G4=Y({name:"SortUp",__name:"sort-up",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M384 141.248V928a32 32 0 1 0 64 0V218.56l242.688 242.688A32 32 0 1 0 736 416L438.592 118.656A32 32 0 0 0 384 141.248"})]))}}),X4=G4,J4=Y({name:"StarFilled",__name:"star-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M283.84 867.84 512 747.776l228.16 119.936a6.4 6.4 0 0 0 9.28-6.72l-43.52-254.08 184.512-179.904a6.4 6.4 0 0 0-3.52-10.88l-255.104-37.12L517.76 147.904a6.4 6.4 0 0 0-11.52 0L392.192 379.072l-255.104 37.12a6.4 6.4 0 0 0-3.52 10.88L318.08 606.976l-43.584 254.08a6.4 6.4 0 0 0 9.28 6.72z"})]))}}),uc=J4,Z4=Y({name:"Star",__name:"star",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"m512 747.84 228.16 119.936a6.4 6.4 0 0 0 9.28-6.72l-43.52-254.08 184.512-179.904a6.4 6.4 0 0 0-3.52-10.88l-255.104-37.12L517.76 147.904a6.4 6.4 0 0 0-11.52 0L392.192 379.072l-255.104 37.12a6.4 6.4 0 0 0-3.52 10.88L318.08 606.976l-43.584 254.08a6.4 6.4 0 0 0 9.28 6.72zM313.6 924.48a70.4 70.4 0 0 1-102.144-74.24l37.888-220.928L88.96 472.96A70.4 70.4 0 0 1 128 352.896l221.76-32.256 99.2-200.96a70.4 70.4 0 0 1 126.208 0l99.2 200.96 221.824 32.256a70.4 70.4 0 0 1 39.04 120.064L774.72 629.376l37.888 220.928a70.4 70.4 0 0 1-102.144 74.24L512 820.096l-198.4 104.32z"})]))}}),Q4=Z4,e3=Y({name:"SuccessFilled",__name:"success-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896m-55.808 536.384-99.52-99.584a38.4 38.4 0 1 0-54.336 54.336l126.72 126.72a38.272 38.272 0 0 0 54.336 0l262.4-262.464a38.4 38.4 0 1 0-54.272-54.336z"})]))}}),JC=e3,t3=Y({name:"View",__name:"view",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 160c320 0 512 352 512 352S832 864 512 864 0 512 0 512s192-352 512-352m0 64c-225.28 0-384.128 208.064-436.8 288 52.608 79.872 211.456 288 436.8 288 225.28 0 384.128-208.064 436.8-288-52.608-79.872-211.456-288-436.8-288zm0 64a224 224 0 1 1 0 448 224 224 0 0 1 0-448m0 64a160.192 160.192 0 0 0-160 160c0 88.192 71.744 160 160 160s160-71.808 160-160-71.744-160-160-160"})]))}}),n3=t3,o3=Y({name:"WarningFilled",__name:"warning-filled",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896m0 192a58.432 58.432 0 0 0-58.24 63.744l23.36 256.384a35.072 35.072 0 0 0 69.76 0l23.296-256.384A58.432 58.432 0 0 0 512 256m0 512a51.2 51.2 0 1 0 0-102.4 51.2 51.2 0 0 0 0 102.4"})]))}}),hf=o3,r3=Y({name:"ZoomIn",__name:"zoom-in",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"m795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704m-32-384v-96a32 32 0 0 1 64 0v96h96a32 32 0 0 1 0 64h-96v96a32 32 0 0 1-64 0v-96h-96a32 32 0 0 1 0-64z"})]))}}),ZC=r3,a3=Y({name:"ZoomOut",__name:"zoom-out",setup(e){return(t,n)=>(T(),V("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 1024 1024"},[F("path",{fill:"currentColor",d:"m795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704M352 448h256a32 32 0 0 1 0 64H352a32 32 0 0 1 0-64"})]))}}),l3=a3;const QC="__epPropKey",Q=e=>e,s3=e=>dt(e)&&!!e[QC],ir=(e,t)=>{if(!dt(e)||s3(e))return e;const{values:n,required:o,default:r,type:a,validator:l}=e,u={type:a,required:!!o,validator:n||l?c=>{let f=!1,d=[];if(n&&(d=Array.from(n),Tt(e,"default")&&d.push(r),f||(f=d.includes(c))),l&&(f||(f=l(c))),!f&&d.length>0){const p=[...new Set(d)].map(m=>JSON.stringify(m)).join(", ");xw(`Invalid prop: validation failed${t?` for prop "${t}"`:""}. Expected one of [${p}], got value ${JSON.stringify(c)}.`)}return f}:void 0,[QC]:!0};return Tt(e,"default")&&(u.default=r),u},Ne=e=>hd(Object.entries(e).map(([t,n])=>[t,ir(n,t)])),Dt=Q([String,Object,Function]),Av={Close:tr},Pv={Close:tr,SuccessFilled:JC,InfoFilled:Mv,WarningFilled:hf,CircleCloseFilled:Iv},Pa={success:JC,warning:hf,error:Iv,info:Mv},Rv={validating:Er,success:Nv,error:Fa},ut=(e,t)=>{if(e.install=n=>{for(const o of[e,...Object.values(t??{})])n.component(o.name,o)},t)for(const[n,o]of Object.entries(t))e[n]=o;return e},eS=(e,t)=>(e.install=n=>{e._context=n._context,n.config.globalProperties[t]=e},e),i3=(e,t)=>(e.install=n=>{n.directive(t,e)},e),tn=e=>(e.install=Bt,e),mf=(...e)=>t=>{e.forEach(n=>{Xe(n)?n(t):n.value=t})},Ue={tab:"Tab",enter:"Enter",space:"Space",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",esc:"Escape",delete:"Delete",backspace:"Backspace",numpadEnter:"NumpadEnter",pageUp:"PageUp",pageDown:"PageDown",home:"Home",end:"End"},u3=["year","years","month","months","date","dates","week","datetime","datetimerange","daterange","monthrange"],cp=["sun","mon","tue","wed","thu","fri","sat"],ft="update:modelValue",Yt="change",Zn="input",Uy=Symbol("INSTALLED_KEY"),Ir=["","default","small","large"],tS=e=>["",...Ir].includes(e);var Oo=(e=>(e[e.TEXT=1]="TEXT",e[e.CLASS=2]="CLASS",e[e.STYLE=4]="STYLE",e[e.PROPS=8]="PROPS",e[e.FULL_PROPS=16]="FULL_PROPS",e[e.HYDRATE_EVENTS=32]="HYDRATE_EVENTS",e[e.STABLE_FRAGMENT=64]="STABLE_FRAGMENT",e[e.KEYED_FRAGMENT=128]="KEYED_FRAGMENT",e[e.UNKEYED_FRAGMENT=256]="UNKEYED_FRAGMENT",e[e.NEED_PATCH=512]="NEED_PATCH",e[e.DYNAMIC_SLOTS=1024]="DYNAMIC_SLOTS",e[e.HOISTED=-1]="HOISTED",e[e.BAIL=-2]="BAIL",e))(Oo||{});function gh(e){return Wt(e)&&e.type===Ve}function c3(e){return Wt(e)&&e.type===En}function d3(e){return Wt(e)&&!gh(e)&&!c3(e)}const f3=e=>{if(!Wt(e))return{};const t=e.props||{},n=(Wt(e.type)?e.type.props:void 0)||{},o={};return Object.keys(n).forEach(r=>{Tt(n[r],"default")&&(o[r]=n[r].default)}),Object.keys(t).forEach(r=>{o[jn(r)]=t[r]}),o},p3=e=>{if(!Pe(e)||e.length>1)throw new Error("expect to receive a single Vue element child");return e[0]},Ca=e=>{const t=Pe(e)?e:[e],n=[];return t.forEach(o=>{var r;Pe(o)?n.push(...Ca(o)):Wt(o)&&Pe(o.children)?n.push(...Ca(o.children)):(n.push(o),Wt(o)&&((r=o.component)!=null&&r.subTree)&&n.push(...Ca(o.component.subTree)))}),n},qy=e=>[...new Set(e)],Vn=e=>!e&&e!==0?[]:Array.isArray(e)?e:[e],Lv=e=>/([\uAC00-\uD7AF\u3130-\u318F])+/gi.test(e),en=e=>e;function h3(e){let t=0;const n=(...o)=>{t&&kl(t),t=Ma(()=>{e(...o),t=0})};return n.cancel=()=>{kl(t),t=0},n}const m3=["class","style"],v3=/^on[A-Z]/,xv=(e={})=>{const{excludeListeners:t=!1,excludeKeys:n}=e,o=k(()=>((n==null?void 0:n.value)||[]).concat(m3)),r=lt();return k(r?()=>{var a;return hd(Object.entries((a=r.proxy)==null?void 0:a.$attrs).filter(([l])=>!o.value.includes(l)&&!(t&&v3.test(l))))}:()=>({}))},wn=({from:e,replacement:t,scope:n,version:o,ref:r,type:a="API"},l)=>{ve(()=>i(l),s=>{},{immediate:!0})},nS=(e,t,n,o)=>{let r={offsetX:0,offsetY:0};const a=u=>{const c=u.clientX,f=u.clientY,{offsetX:d,offsetY:p}=r,m=e.value.getBoundingClientRect(),v=m.left,h=m.top,C=m.width,g=m.height,y=document.documentElement.clientWidth,_=document.documentElement.clientHeight,b=-v+d,w=-h+p,S=y-v-C+d,E=_-h-g+p,$=A=>{let M=d+A.clientX-c,D=p+A.clientY-f;o!=null&&o.value||(M=Math.min(Math.max(M,b),S),D=Math.min(Math.max(D,w),E)),r={offsetX:M,offsetY:D},e.value&&(e.value.style.transform=`translate(${rn(M)}, ${rn(D)})`)},O=()=>{document.removeEventListener("mousemove",$),document.removeEventListener("mouseup",O)};document.addEventListener("mousemove",$),document.addEventListener("mouseup",O)},l=()=>{t.value&&e.value&&t.value.addEventListener("mousedown",a)},s=()=>{t.value&&e.value&&t.value.removeEventListener("mousedown",a)};at(()=>{Mn(()=>{n.value?l():s()})}),zt(()=>{s()})};var oS={name:"en",el:{breadcrumb:{label:"Breadcrumb"},colorpicker:{confirm:"OK",clear:"Clear",defaultLabel:"color picker",description:"current color is {color}. press enter to select a new color."},datepicker:{now:"Now",today:"Today",cancel:"Cancel",clear:"Clear",confirm:"OK",dateTablePrompt:"Use the arrow keys and enter to select the day of the month",monthTablePrompt:"Use the arrow keys and enter to select the month",yearTablePrompt:"Use the arrow keys and enter to select the year",selectedDate:"Selected date",selectDate:"Select date",selectTime:"Select time",startDate:"Start Date",startTime:"Start Time",endDate:"End Date",endTime:"End Time",prevYear:"Previous Year",nextYear:"Next Year",prevMonth:"Previous Month",nextMonth:"Next Month",year:"",month1:"January",month2:"February",month3:"March",month4:"April",month5:"May",month6:"June",month7:"July",month8:"August",month9:"September",month10:"October",month11:"November",month12:"December",week:"week",weeks:{sun:"Sun",mon:"Mon",tue:"Tue",wed:"Wed",thu:"Thu",fri:"Fri",sat:"Sat"},weeksFull:{sun:"Sunday",mon:"Monday",tue:"Tuesday",wed:"Wednesday",thu:"Thursday",fri:"Friday",sat:"Saturday"},months:{jan:"Jan",feb:"Feb",mar:"Mar",apr:"Apr",may:"May",jun:"Jun",jul:"Jul",aug:"Aug",sep:"Sep",oct:"Oct",nov:"Nov",dec:"Dec"}},inputNumber:{decrease:"decrease number",increase:"increase number"},select:{loading:"Loading",noMatch:"No matching data",noData:"No data",placeholder:"Select"},dropdown:{toggleDropdown:"Toggle Dropdown"},cascader:{noMatch:"No matching data",loading:"Loading",placeholder:"Select",noData:"No data"},pagination:{goto:"Go to",pagesize:"/page",total:"Total {total}",pageClassifier:"",page:"Page",prev:"Go to previous page",next:"Go to next page",currentPage:"page {pager}",prevPages:"Previous {pager} pages",nextPages:"Next {pager} pages",deprecationWarning:"Deprecated usages detected, please refer to the el-pagination documentation for more details"},dialog:{close:"Close this dialog"},drawer:{close:"Close this dialog"},messagebox:{title:"Message",confirm:"OK",cancel:"Cancel",error:"Illegal input",close:"Close this dialog"},upload:{deleteTip:"press delete to remove",delete:"Delete",preview:"Preview",continue:"Continue"},slider:{defaultLabel:"slider between {min} and {max}",defaultRangeStartLabel:"pick start value",defaultRangeEndLabel:"pick end value"},table:{emptyText:"No Data",confirmFilter:"Confirm",resetFilter:"Reset",clearFilter:"All",sumText:"Sum"},tour:{next:"Next",previous:"Previous",finish:"Finish"},tree:{emptyText:"No Data"},transfer:{noMatch:"No matching data",noData:"No data",titles:["List 1","List 2"],filterPlaceholder:"Enter keyword",noCheckedFormat:"{total} items",hasCheckedFormat:"{checked}/{total} checked"},image:{error:"FAILED"},pageHeader:{title:"Back"},popconfirm:{confirmButtonText:"Yes",cancelButtonText:"No"},carousel:{leftArrow:"Carousel arrow left",rightArrow:"Carousel arrow right",indicator:"Carousel switch to index {index}"}}};const g3=e=>(t,n)=>b3(t,n,i(e)),b3=(e,t,n)=>un(n,e,e).replace(/\{(\w+)\}/g,(o,r)=>{var a;return`${(a=t==null?void 0:t[r])!=null?a:`{${r}}`}`}),y3=e=>{const t=k(()=>i(e).name),n=xt(e)?e:R(e);return{lang:t,locale:n,t:g3(e)}},rS=Symbol("localeContextKey"),$t=e=>{const t=e||De(rS,R());return y3(k(()=>t.value||oS))},Ri="el",w3="is-",ja=(e,t,n,o,r)=>{let a=`${e}-${t}`;return n&&(a+=`-${n}`),o&&(a+=`__${o}`),r&&(a+=`--${r}`),a},aS=Symbol("namespaceContextKey"),Dv=e=>{const t=e||(lt()?De(aS,R(Ri)):R(Ri));return k(()=>i(t)||Ri)},Se=(e,t)=>{const n=Dv(t);return{namespace:n,b:(h="")=>ja(n.value,e,h,"",""),e:h=>h?ja(n.value,e,"",h,""):"",m:h=>h?ja(n.value,e,"","",h):"",be:(h,C)=>h&&C?ja(n.value,e,h,C,""):"",em:(h,C)=>h&&C?ja(n.value,e,"",h,C):"",bm:(h,C)=>h&&C?ja(n.value,e,h,"",C):"",bem:(h,C,g)=>h&&C&&g?ja(n.value,e,h,C,g):"",is:(h,...C)=>{const g=C.length>=1?C[0]:!0;return h&&g?`${w3}${h}`:""},cssVar:h=>{const C={};for(const g in h)h[g]&&(C[`--${n.value}-${g}`]=h[g]);return C},cssVarName:h=>`--${n.value}-${h}`,cssVarBlock:h=>{const C={};for(const g in h)h[g]&&(C[`--${n.value}-${e}-${g}`]=h[g]);return C},cssVarBlockName:h=>`--${n.value}-${e}-${h}`}},Fv=(e,t={})=>{xt(e)||vn("[useLockscreen]","You need to pass a ref param to this function");const n=t.ns||Se("popup"),o=k(()=>n.bm("parent","hidden"));if(!Ct||wo(document.body,o.value))return;let r=0,a=!1,l="0";const s=()=>{setTimeout(()=>{Kn(document==null?void 0:document.body,o.value),a&&document&&(document.body.style.width=l)},200)};ve(e,u=>{if(!u){s();return}a=!wo(document.body,o.value),a&&(l=document.body.style.width),r=WC(n.namespace.value);const c=document.documentElement.clientHeight0&&(c||f==="scroll")&&a&&(document.body.style.width=`calc(100% - ${r}px)`),Mo(document.body,o.value)}),Hd(()=>s())},_3=ir({type:Q(Boolean),default:null}),C3=ir({type:Q(Function)}),lS=e=>{const t=`update:${e}`,n=`onUpdate:${e}`,o=[t],r={[e]:_3,[n]:C3};return{useModelToggle:({indicator:l,toggleReason:s,shouldHideWhenRouteChanges:u,shouldProceed:c,onShow:f,onHide:d})=>{const p=lt(),{emit:m}=p,v=p.props,h=k(()=>Xe(v[n])),C=k(()=>v[e]===null),g=E=>{l.value!==!0&&(l.value=!0,s&&(s.value=E),Xe(f)&&f(E))},y=E=>{l.value!==!1&&(l.value=!1,s&&(s.value=E),Xe(d)&&d(E))},_=E=>{if(v.disabled===!0||Xe(c)&&!c())return;const $=h.value&&Ct;$&&m(t,!0),(C.value||!$)&&g(E)},b=E=>{if(v.disabled===!0||!Ct)return;const $=h.value&&Ct;$&&m(t,!1),(C.value||!$)&&y(E)},w=E=>{dn(E)&&(v.disabled&&E?h.value&&m(t,!1):l.value!==E&&(E?g():y()))},S=()=>{l.value?b():_()};return ve(()=>v[e],w),u&&p.appContext.config.globalProperties.$route!==void 0&&ve(()=>({...p.proxy.$route}),()=>{u.value&&l.value&&b()}),at(()=>{w(v[e])}),{hide:b,show:_,toggle:S,hasUpdateHandler:h}},useModelToggleProps:r,useModelToggleEmits:o}};lS("modelValue");const sS=e=>{const t=lt();return k(()=>{var n,o;return(o=(n=t==null?void 0:t.proxy)==null?void 0:n.$props)==null?void 0:o[e]})};var so="top",Bo="bottom",Vo="right",io="left",Bv="auto",Au=[so,Bo,Vo,io],Ts="start",nu="end",S3="clippingParents",iS="viewport",hi="popper",k3="reference",Yy=Au.reduce(function(e,t){return e.concat([t+"-"+Ts,t+"-"+nu])},[]),Dl=[].concat(Au,[Bv]).reduce(function(e,t){return e.concat([t,t+"-"+Ts,t+"-"+nu])},[]),E3="beforeRead",T3="read",$3="afterRead",O3="beforeMain",N3="main",I3="afterMain",M3="beforeWrite",A3="write",P3="afterWrite",R3=[E3,T3,$3,O3,N3,I3,M3,A3,P3];function Tr(e){return e?(e.nodeName||"").toLowerCase():null}function ur(e){if(e==null)return window;if(e.toString()!=="[object Window]"){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function $s(e){var t=ur(e).Element;return e instanceof t||e instanceof Element}function Ro(e){var t=ur(e).HTMLElement;return e instanceof t||e instanceof HTMLElement}function Vv(e){if(typeof ShadowRoot>"u")return!1;var t=ur(e).ShadowRoot;return e instanceof t||e instanceof ShadowRoot}function L3(e){var t=e.state;Object.keys(t.elements).forEach(function(n){var o=t.styles[n]||{},r=t.attributes[n]||{},a=t.elements[n];!Ro(a)||!Tr(a)||(Object.assign(a.style,o),Object.keys(r).forEach(function(l){var s=r[l];s===!1?a.removeAttribute(l):a.setAttribute(l,s===!0?"":s)}))})}function x3(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach(function(o){var r=t.elements[o],a=t.attributes[o]||{},l=Object.keys(t.styles.hasOwnProperty(o)?t.styles[o]:n[o]),s=l.reduce(function(u,c){return u[c]="",u},{});!Ro(r)||!Tr(r)||(Object.assign(r.style,s),Object.keys(a).forEach(function(u){r.removeAttribute(u)}))})}}var uS={name:"applyStyles",enabled:!0,phase:"write",fn:L3,effect:x3,requires:["computeStyles"]};function _r(e){return e.split("-")[0]}var ul=Math.max,md=Math.min,Os=Math.round;function Ns(e,t){t===void 0&&(t=!1);var n=e.getBoundingClientRect(),o=1,r=1;if(Ro(e)&&t){var a=e.offsetHeight,l=e.offsetWidth;l>0&&(o=Os(n.width)/l||1),a>0&&(r=Os(n.height)/a||1)}return{width:n.width/o,height:n.height/r,top:n.top/r,right:n.right/o,bottom:n.bottom/r,left:n.left/o,x:n.left/o,y:n.top/r}}function Hv(e){var t=Ns(e),n=e.offsetWidth,o=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-o)<=1&&(o=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:o}}function cS(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&Vv(n)){var o=t;do{if(o&&e.isSameNode(o))return!0;o=o.parentNode||o.host}while(o)}return!1}function qr(e){return ur(e).getComputedStyle(e)}function D3(e){return["table","td","th"].indexOf(Tr(e))>=0}function Ba(e){return(($s(e)?e.ownerDocument:e.document)||window.document).documentElement}function vf(e){return Tr(e)==="html"?e:e.assignedSlot||e.parentNode||(Vv(e)?e.host:null)||Ba(e)}function Gy(e){return!Ro(e)||qr(e).position==="fixed"?null:e.offsetParent}function F3(e){var t=navigator.userAgent.toLowerCase().indexOf("firefox")!==-1,n=navigator.userAgent.indexOf("Trident")!==-1;if(n&&Ro(e)){var o=qr(e);if(o.position==="fixed")return null}var r=vf(e);for(Vv(r)&&(r=r.host);Ro(r)&&["html","body"].indexOf(Tr(r))<0;){var a=qr(r);if(a.transform!=="none"||a.perspective!=="none"||a.contain==="paint"||["transform","perspective"].indexOf(a.willChange)!==-1||t&&a.willChange==="filter"||t&&a.filter&&a.filter!=="none")return r;r=r.parentNode}return null}function Pu(e){for(var t=ur(e),n=Gy(e);n&&D3(n)&&qr(n).position==="static";)n=Gy(n);return n&&(Tr(n)==="html"||Tr(n)==="body"&&qr(n).position==="static")?t:n||F3(e)||t}function zv(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function Li(e,t,n){return ul(e,md(t,n))}function B3(e,t,n){var o=Li(e,t,n);return o>n?n:o}function dS(){return{top:0,right:0,bottom:0,left:0}}function fS(e){return Object.assign({},dS(),e)}function pS(e,t){return t.reduce(function(n,o){return n[o]=e,n},{})}var V3=function(e,t){return e=typeof e=="function"?e(Object.assign({},t.rects,{placement:t.placement})):e,fS(typeof e!="number"?e:pS(e,Au))};function H3(e){var t,n=e.state,o=e.name,r=e.options,a=n.elements.arrow,l=n.modifiersData.popperOffsets,s=_r(n.placement),u=zv(s),c=[io,Vo].indexOf(s)>=0,f=c?"height":"width";if(!(!a||!l)){var d=V3(r.padding,n),p=Hv(a),m=u==="y"?so:io,v=u==="y"?Bo:Vo,h=n.rects.reference[f]+n.rects.reference[u]-l[u]-n.rects.popper[f],C=l[u]-n.rects.reference[u],g=Pu(a),y=g?u==="y"?g.clientHeight||0:g.clientWidth||0:0,_=h/2-C/2,b=d[m],w=y-p[f]-d[v],S=y/2-p[f]/2+_,E=Li(b,S,w),$=u;n.modifiersData[o]=(t={},t[$]=E,t.centerOffset=E-S,t)}}function z3(e){var t=e.state,n=e.options,o=n.element,r=o===void 0?"[data-popper-arrow]":o;r!=null&&(typeof r=="string"&&(r=t.elements.popper.querySelector(r),!r)||!cS(t.elements.popper,r)||(t.elements.arrow=r))}var j3={name:"arrow",enabled:!0,phase:"main",fn:H3,effect:z3,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Is(e){return e.split("-")[1]}var W3={top:"auto",right:"auto",bottom:"auto",left:"auto"};function K3(e){var t=e.x,n=e.y,o=window,r=o.devicePixelRatio||1;return{x:Os(t*r)/r||0,y:Os(n*r)/r||0}}function Xy(e){var t,n=e.popper,o=e.popperRect,r=e.placement,a=e.variation,l=e.offsets,s=e.position,u=e.gpuAcceleration,c=e.adaptive,f=e.roundOffsets,d=e.isFixed,p=l.x,m=p===void 0?0:p,v=l.y,h=v===void 0?0:v,C=typeof f=="function"?f({x:m,y:h}):{x:m,y:h};m=C.x,h=C.y;var g=l.hasOwnProperty("x"),y=l.hasOwnProperty("y"),_=io,b=so,w=window;if(c){var S=Pu(n),E="clientHeight",$="clientWidth";if(S===ur(n)&&(S=Ba(n),qr(S).position!=="static"&&s==="absolute"&&(E="scrollHeight",$="scrollWidth")),S=S,r===so||(r===io||r===Vo)&&a===nu){b=Bo;var O=d&&S===w&&w.visualViewport?w.visualViewport.height:S[E];h-=O-o.height,h*=u?1:-1}if(r===io||(r===so||r===Bo)&&a===nu){_=Vo;var A=d&&S===w&&w.visualViewport?w.visualViewport.width:S[$];m-=A-o.width,m*=u?1:-1}}var M=Object.assign({position:s},c&&W3),D=f===!0?K3({x:m,y:h}):{x:m,y:h};if(m=D.x,h=D.y,u){var U;return Object.assign({},M,(U={},U[b]=y?"0":"",U[_]=g?"0":"",U.transform=(w.devicePixelRatio||1)<=1?"translate("+m+"px, "+h+"px)":"translate3d("+m+"px, "+h+"px, 0)",U))}return Object.assign({},M,(t={},t[b]=y?h+"px":"",t[_]=g?m+"px":"",t.transform="",t))}function U3(e){var t=e.state,n=e.options,o=n.gpuAcceleration,r=o===void 0?!0:o,a=n.adaptive,l=a===void 0?!0:a,s=n.roundOffsets,u=s===void 0?!0:s,c={placement:_r(t.placement),variation:Is(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:r,isFixed:t.options.strategy==="fixed"};t.modifiersData.popperOffsets!=null&&(t.styles.popper=Object.assign({},t.styles.popper,Xy(Object.assign({},c,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:l,roundOffsets:u})))),t.modifiersData.arrow!=null&&(t.styles.arrow=Object.assign({},t.styles.arrow,Xy(Object.assign({},c,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:u})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})}var hS={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:U3,data:{}},cc={passive:!0};function q3(e){var t=e.state,n=e.instance,o=e.options,r=o.scroll,a=r===void 0?!0:r,l=o.resize,s=l===void 0?!0:l,u=ur(t.elements.popper),c=[].concat(t.scrollParents.reference,t.scrollParents.popper);return a&&c.forEach(function(f){f.addEventListener("scroll",n.update,cc)}),s&&u.addEventListener("resize",n.update,cc),function(){a&&c.forEach(function(f){f.removeEventListener("scroll",n.update,cc)}),s&&u.removeEventListener("resize",n.update,cc)}}var mS={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:q3,data:{}},Y3={left:"right",right:"left",bottom:"top",top:"bottom"};function Ac(e){return e.replace(/left|right|bottom|top/g,function(t){return Y3[t]})}var G3={start:"end",end:"start"};function Jy(e){return e.replace(/start|end/g,function(t){return G3[t]})}function jv(e){var t=ur(e),n=t.pageXOffset,o=t.pageYOffset;return{scrollLeft:n,scrollTop:o}}function Wv(e){return Ns(Ba(e)).left+jv(e).scrollLeft}function X3(e){var t=ur(e),n=Ba(e),o=t.visualViewport,r=n.clientWidth,a=n.clientHeight,l=0,s=0;return o&&(r=o.width,a=o.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(l=o.offsetLeft,s=o.offsetTop)),{width:r,height:a,x:l+Wv(e),y:s}}function J3(e){var t,n=Ba(e),o=jv(e),r=(t=e.ownerDocument)==null?void 0:t.body,a=ul(n.scrollWidth,n.clientWidth,r?r.scrollWidth:0,r?r.clientWidth:0),l=ul(n.scrollHeight,n.clientHeight,r?r.scrollHeight:0,r?r.clientHeight:0),s=-o.scrollLeft+Wv(e),u=-o.scrollTop;return qr(r||n).direction==="rtl"&&(s+=ul(n.clientWidth,r?r.clientWidth:0)-a),{width:a,height:l,x:s,y:u}}function Kv(e){var t=qr(e),n=t.overflow,o=t.overflowX,r=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+r+o)}function vS(e){return["html","body","#document"].indexOf(Tr(e))>=0?e.ownerDocument.body:Ro(e)&&Kv(e)?e:vS(vf(e))}function xi(e,t){var n;t===void 0&&(t=[]);var o=vS(e),r=o===((n=e.ownerDocument)==null?void 0:n.body),a=ur(o),l=r?[a].concat(a.visualViewport||[],Kv(o)?o:[]):o,s=t.concat(l);return r?s:s.concat(xi(vf(l)))}function bh(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function Z3(e){var t=Ns(e);return t.top=t.top+e.clientTop,t.left=t.left+e.clientLeft,t.bottom=t.top+e.clientHeight,t.right=t.left+e.clientWidth,t.width=e.clientWidth,t.height=e.clientHeight,t.x=t.left,t.y=t.top,t}function Zy(e,t){return t===iS?bh(X3(e)):$s(t)?Z3(t):bh(J3(Ba(e)))}function Q3(e){var t=xi(vf(e)),n=["absolute","fixed"].indexOf(qr(e).position)>=0,o=n&&Ro(e)?Pu(e):e;return $s(o)?t.filter(function(r){return $s(r)&&cS(r,o)&&Tr(r)!=="body"}):[]}function eD(e,t,n){var o=t==="clippingParents"?Q3(e):[].concat(t),r=[].concat(o,[n]),a=r[0],l=r.reduce(function(s,u){var c=Zy(e,u);return s.top=ul(c.top,s.top),s.right=md(c.right,s.right),s.bottom=md(c.bottom,s.bottom),s.left=ul(c.left,s.left),s},Zy(e,a));return l.width=l.right-l.left,l.height=l.bottom-l.top,l.x=l.left,l.y=l.top,l}function gS(e){var t=e.reference,n=e.element,o=e.placement,r=o?_r(o):null,a=o?Is(o):null,l=t.x+t.width/2-n.width/2,s=t.y+t.height/2-n.height/2,u;switch(r){case so:u={x:l,y:t.y-n.height};break;case Bo:u={x:l,y:t.y+t.height};break;case Vo:u={x:t.x+t.width,y:s};break;case io:u={x:t.x-n.width,y:s};break;default:u={x:t.x,y:t.y}}var c=r?zv(r):null;if(c!=null){var f=c==="y"?"height":"width";switch(a){case Ts:u[c]=u[c]-(t[f]/2-n[f]/2);break;case nu:u[c]=u[c]+(t[f]/2-n[f]/2);break}}return u}function ou(e,t){t===void 0&&(t={});var n=t,o=n.placement,r=o===void 0?e.placement:o,a=n.boundary,l=a===void 0?S3:a,s=n.rootBoundary,u=s===void 0?iS:s,c=n.elementContext,f=c===void 0?hi:c,d=n.altBoundary,p=d===void 0?!1:d,m=n.padding,v=m===void 0?0:m,h=fS(typeof v!="number"?v:pS(v,Au)),C=f===hi?k3:hi,g=e.rects.popper,y=e.elements[p?C:f],_=eD($s(y)?y:y.contextElement||Ba(e.elements.popper),l,u),b=Ns(e.elements.reference),w=gS({reference:b,element:g,strategy:"absolute",placement:r}),S=bh(Object.assign({},g,w)),E=f===hi?S:b,$={top:_.top-E.top+h.top,bottom:E.bottom-_.bottom+h.bottom,left:_.left-E.left+h.left,right:E.right-_.right+h.right},O=e.modifiersData.offset;if(f===hi&&O){var A=O[r];Object.keys($).forEach(function(M){var D=[Vo,Bo].indexOf(M)>=0?1:-1,U=[so,Bo].indexOf(M)>=0?"y":"x";$[M]+=A[U]*D})}return $}function tD(e,t){t===void 0&&(t={});var n=t,o=n.placement,r=n.boundary,a=n.rootBoundary,l=n.padding,s=n.flipVariations,u=n.allowedAutoPlacements,c=u===void 0?Dl:u,f=Is(o),d=f?s?Yy:Yy.filter(function(v){return Is(v)===f}):Au,p=d.filter(function(v){return c.indexOf(v)>=0});p.length===0&&(p=d);var m=p.reduce(function(v,h){return v[h]=ou(e,{placement:h,boundary:r,rootBoundary:a,padding:l})[_r(h)],v},{});return Object.keys(m).sort(function(v,h){return m[v]-m[h]})}function nD(e){if(_r(e)===Bv)return[];var t=Ac(e);return[Jy(e),t,Jy(t)]}function oD(e){var t=e.state,n=e.options,o=e.name;if(!t.modifiersData[o]._skip){for(var r=n.mainAxis,a=r===void 0?!0:r,l=n.altAxis,s=l===void 0?!0:l,u=n.fallbackPlacements,c=n.padding,f=n.boundary,d=n.rootBoundary,p=n.altBoundary,m=n.flipVariations,v=m===void 0?!0:m,h=n.allowedAutoPlacements,C=t.options.placement,g=_r(C),y=g===C,_=u||(y||!v?[Ac(C)]:nD(C)),b=[C].concat(_).reduce(function(fe,Te){return fe.concat(_r(Te)===Bv?tD(t,{placement:Te,boundary:f,rootBoundary:d,padding:c,flipVariations:v,allowedAutoPlacements:h}):Te)},[]),w=t.rects.reference,S=t.rects.popper,E=new Map,$=!0,O=b[0],A=0;A=0,W=j?"width":"height",L=ou(t,{placement:M,boundary:f,rootBoundary:d,altBoundary:p,padding:c}),P=j?U?Vo:io:U?Bo:so;w[W]>S[W]&&(P=Ac(P));var x=Ac(P),I=[];if(a&&I.push(L[D]<=0),s&&I.push(L[P]<=0,L[x]<=0),I.every(function(fe){return fe})){O=M,$=!1;break}E.set(M,I)}if($)for(var H=v?3:1,G=function(fe){var Te=b.find(function(oe){var ke=E.get(oe);if(ke)return ke.slice(0,fe).every(function(ae){return ae})});if(Te)return O=Te,"break"},J=H;J>0;J--){var ee=G(J);if(ee==="break")break}t.placement!==O&&(t.modifiersData[o]._skip=!0,t.placement=O,t.reset=!0)}}var rD={name:"flip",enabled:!0,phase:"main",fn:oD,requiresIfExists:["offset"],data:{_skip:!1}};function Qy(e,t,n){return n===void 0&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function e0(e){return[so,Vo,Bo,io].some(function(t){return e[t]>=0})}function aD(e){var t=e.state,n=e.name,o=t.rects.reference,r=t.rects.popper,a=t.modifiersData.preventOverflow,l=ou(t,{elementContext:"reference"}),s=ou(t,{altBoundary:!0}),u=Qy(l,o),c=Qy(s,r,a),f=e0(u),d=e0(c);t.modifiersData[n]={referenceClippingOffsets:u,popperEscapeOffsets:c,isReferenceHidden:f,hasPopperEscaped:d},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":f,"data-popper-escaped":d})}var lD={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:aD};function sD(e,t,n){var o=_r(e),r=[io,so].indexOf(o)>=0?-1:1,a=typeof n=="function"?n(Object.assign({},t,{placement:e})):n,l=a[0],s=a[1];return l=l||0,s=(s||0)*r,[io,Vo].indexOf(o)>=0?{x:s,y:l}:{x:l,y:s}}function iD(e){var t=e.state,n=e.options,o=e.name,r=n.offset,a=r===void 0?[0,0]:r,l=Dl.reduce(function(f,d){return f[d]=sD(d,t.rects,a),f},{}),s=l[t.placement],u=s.x,c=s.y;t.modifiersData.popperOffsets!=null&&(t.modifiersData.popperOffsets.x+=u,t.modifiersData.popperOffsets.y+=c),t.modifiersData[o]=l}var uD={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:iD};function cD(e){var t=e.state,n=e.name;t.modifiersData[n]=gS({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})}var bS={name:"popperOffsets",enabled:!0,phase:"read",fn:cD,data:{}};function dD(e){return e==="x"?"y":"x"}function fD(e){var t=e.state,n=e.options,o=e.name,r=n.mainAxis,a=r===void 0?!0:r,l=n.altAxis,s=l===void 0?!1:l,u=n.boundary,c=n.rootBoundary,f=n.altBoundary,d=n.padding,p=n.tether,m=p===void 0?!0:p,v=n.tetherOffset,h=v===void 0?0:v,C=ou(t,{boundary:u,rootBoundary:c,padding:d,altBoundary:f}),g=_r(t.placement),y=Is(t.placement),_=!y,b=zv(g),w=dD(b),S=t.modifiersData.popperOffsets,E=t.rects.reference,$=t.rects.popper,O=typeof h=="function"?h(Object.assign({},t.rects,{placement:t.placement})):h,A=typeof O=="number"?{mainAxis:O,altAxis:O}:Object.assign({mainAxis:0,altAxis:0},O),M=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,D={x:0,y:0};if(S){if(a){var U,j=b==="y"?so:io,W=b==="y"?Bo:Vo,L=b==="y"?"height":"width",P=S[b],x=P+C[j],I=P-C[W],H=m?-$[L]/2:0,G=y===Ts?E[L]:$[L],J=y===Ts?-$[L]:-E[L],ee=t.elements.arrow,fe=m&&ee?Hv(ee):{width:0,height:0},Te=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:dS(),oe=Te[j],ke=Te[W],ae=Li(0,E[L],fe[L]),Oe=_?E[L]/2-H-ae-oe-A.mainAxis:G-ae-oe-A.mainAxis,we=_?-E[L]/2+H+ae+ke+A.mainAxis:J+ae+ke+A.mainAxis,ge=t.elements.arrow&&Pu(t.elements.arrow),q=ge?b==="y"?ge.clientTop||0:ge.clientLeft||0:0,B=(U=M==null?void 0:M[b])!=null?U:0,z=P+Oe-B-q,Z=P+we-B,ue=Li(m?md(x,z):x,P,m?ul(I,Z):I);S[b]=ue,D[b]=ue-P}if(s){var se,me=b==="x"?so:io,_e=b==="x"?Bo:Vo,$e=S[w],Ce=w==="y"?"height":"width",ce=$e+C[me],de=$e-C[_e],xe=[so,io].indexOf(g)!==-1,he=(se=M==null?void 0:M[w])!=null?se:0,He=xe?ce:$e-E[Ce]-$[Ce]-he+A.altAxis,et=xe?$e+E[Ce]+$[Ce]-he-A.altAxis:de,rt=m&&xe?B3(He,$e,et):Li(m?He:ce,$e,m?et:de);S[w]=rt,D[w]=rt-$e}t.modifiersData[o]=D}}var pD={name:"preventOverflow",enabled:!0,phase:"main",fn:fD,requiresIfExists:["offset"]};function hD(e){return{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}}function mD(e){return e===ur(e)||!Ro(e)?jv(e):hD(e)}function vD(e){var t=e.getBoundingClientRect(),n=Os(t.width)/e.offsetWidth||1,o=Os(t.height)/e.offsetHeight||1;return n!==1||o!==1}function gD(e,t,n){n===void 0&&(n=!1);var o=Ro(t),r=Ro(t)&&vD(t),a=Ba(t),l=Ns(e,r),s={scrollLeft:0,scrollTop:0},u={x:0,y:0};return(o||!o&&!n)&&((Tr(t)!=="body"||Kv(a))&&(s=mD(t)),Ro(t)?(u=Ns(t,!0),u.x+=t.clientLeft,u.y+=t.clientTop):a&&(u.x=Wv(a))),{x:l.left+s.scrollLeft-u.x,y:l.top+s.scrollTop-u.y,width:l.width,height:l.height}}function bD(e){var t=new Map,n=new Set,o=[];e.forEach(function(a){t.set(a.name,a)});function r(a){n.add(a.name);var l=[].concat(a.requires||[],a.requiresIfExists||[]);l.forEach(function(s){if(!n.has(s)){var u=t.get(s);u&&r(u)}}),o.push(a)}return e.forEach(function(a){n.has(a.name)||r(a)}),o}function yD(e){var t=bD(e);return R3.reduce(function(n,o){return n.concat(t.filter(function(r){return r.phase===o}))},[])}function wD(e){var t;return function(){return t||(t=new Promise(function(n){Promise.resolve().then(function(){t=void 0,n(e())})})),t}}function _D(e){var t=e.reduce(function(n,o){var r=n[o.name];return n[o.name]=r?Object.assign({},r,o,{options:Object.assign({},r.options,o.options),data:Object.assign({},r.data,o.data)}):o,n},{});return Object.keys(t).map(function(n){return t[n]})}var t0={placement:"bottom",modifiers:[],strategy:"absolute"};function n0(){for(var e=arguments.length,t=new Array(e),n=0;n{const o={name:"updateState",enabled:!0,phase:"write",fn:({state:u})=>{const c=TD(u);Object.assign(l.value,c)},requires:["computeStyles"]},r=k(()=>{const{onFirstUpdate:u,placement:c,strategy:f,modifiers:d}=i(n);return{onFirstUpdate:u,placement:c||"bottom",strategy:f||"absolute",modifiers:[...d||[],o,{name:"applyStyles",enabled:!1}]}}),a=Ut(),l=R({styles:{popper:{position:i(r).strategy,left:"0",top:"0"},arrow:{position:"absolute"}},attributes:{}}),s=()=>{a.value&&(a.value.destroy(),a.value=void 0)};return ve(r,u=>{const c=i(a);c&&c.setOptions(u)},{deep:!0}),ve([e,t],([u,c])=>{s(),!(!u||!c)&&(a.value=kD(u,c,i(r)))}),zt(()=>{s()}),{state:k(()=>{var u;return{...((u=i(a))==null?void 0:u.state)||{}}}),styles:k(()=>i(l).styles),attributes:k(()=>i(l).attributes),update:()=>{var u;return(u=i(a))==null?void 0:u.update()},forceUpdate:()=>{var u;return(u=i(a))==null?void 0:u.forceUpdate()},instanceRef:k(()=>i(a))}};function TD(e){const t=Object.keys(e.elements),n=hd(t.map(r=>[r,e.styles[r]||{}])),o=hd(t.map(r=>[r,e.attributes[r]]));return{styles:n,attributes:o}}const qv=e=>{if(!e)return{onClick:Bt,onMousedown:Bt,onMouseup:Bt};let t=!1,n=!1;return{onClick:l=>{t&&n&&e(l),t=n=!1},onMousedown:l=>{t=l.target===l.currentTarget},onMouseup:l=>{n=l.target===l.currentTarget}}},$D=(e,t=0)=>{if(t===0)return e;const n=R(!1);let o=0;const r=()=>{o&&clearTimeout(o),o=window.setTimeout(()=>{n.value=e.value},t)};return at(r),ve(()=>e.value,a=>{a?r():n.value=a}),n};function o0(){let e;const t=(o,r)=>{n(),e=window.setTimeout(o,r)},n=()=>window.clearTimeout(e);return Tu(()=>n()),{registerTimeout:t,cancelTimeout:n}}const r0={prefix:Math.floor(Math.random()*1e4),current:0},OD=Symbol("elIdInjection"),Yv=()=>lt()?De(OD,r0):r0,xn=e=>{const t=Yv(),n=Dv();return k(()=>i(e)||`${n.value}-id-${t.prefix}-${t.current++}`)};let Jl=[];const a0=e=>{const t=e;t.key===Ue.esc&&Jl.forEach(n=>n(t))},ND=e=>{at(()=>{Jl.length===0&&document.addEventListener("keydown",a0),Ct&&Jl.push(e)}),zt(()=>{Jl=Jl.filter(t=>t!==e),Jl.length===0&&Ct&&document.removeEventListener("keydown",a0)})};let l0;const yS=()=>{const e=Dv(),t=Yv(),n=k(()=>`${e.value}-popper-container-${t.prefix}`),o=k(()=>`#${n.value}`);return{id:n,selector:o}},ID=e=>{const t=document.createElement("div");return t.id=e,document.body.appendChild(t),t},MD=()=>{const{id:e,selector:t}=yS();return Su(()=>{Ct&&!l0&&!document.body.querySelector(t.value)&&(l0=ID(e.value))}),{id:e,selector:t}},AD=Ne({showAfter:{type:Number,default:0},hideAfter:{type:Number,default:200},autoClose:{type:Number,default:0}}),PD=({showAfter:e,hideAfter:t,autoClose:n,open:o,close:r})=>{const{registerTimeout:a}=o0(),{registerTimeout:l,cancelTimeout:s}=o0();return{onOpen:f=>{a(()=>{o(f);const d=i(n);Je(d)&&d>0&&l(()=>{r(f)},d)},i(e))},onClose:f=>{s(),a(()=>{r(f)},i(t))}}},wS=Symbol("elForwardRef"),RD=e=>{yt(wS,{setForwardRef:n=>{e.value=n}})},LD=e=>({mounted(t){e(t)},updated(t){e(t)},unmounted(){e(null)}}),s0={current:0},i0=R(0),_S=2e3,u0=Symbol("elZIndexContextKey"),CS=Symbol("zIndexContextKey"),Zs=e=>{const t=lt()?De(u0,s0):s0,n=e||(lt()?De(CS,void 0):void 0),o=k(()=>{const l=i(n);return Je(l)?l:_S}),r=k(()=>o.value+i0.value),a=()=>(t.current++,i0.value=t.current,r.value);return!Ct&&De(u0),{initialZIndex:o,currentZIndex:r,nextZIndex:a}},Ms=Math.min,cl=Math.max,vd=Math.round,dc=Math.floor,Ra=e=>({x:e,y:e}),xD={left:"right",right:"left",bottom:"top",top:"bottom"},DD={start:"end",end:"start"};function yh(e,t,n){return cl(e,Ms(t,n))}function Ru(e,t){return typeof e=="function"?e(t):e}function El(e){return e.split("-")[0]}function Lu(e){return e.split("-")[1]}function SS(e){return e==="x"?"y":"x"}function Gv(e){return e==="y"?"height":"width"}function As(e){return["top","bottom"].includes(El(e))?"y":"x"}function Xv(e){return SS(As(e))}function FD(e,t,n){n===void 0&&(n=!1);const o=Lu(e),r=Xv(e),a=Gv(r);let l=r==="x"?o===(n?"end":"start")?"right":"left":o==="start"?"bottom":"top";return t.reference[a]>t.floating[a]&&(l=gd(l)),[l,gd(l)]}function BD(e){const t=gd(e);return[wh(e),t,wh(t)]}function wh(e){return e.replace(/start|end/g,t=>DD[t])}function VD(e,t,n){const o=["left","right"],r=["right","left"],a=["top","bottom"],l=["bottom","top"];switch(e){case"top":case"bottom":return n?t?r:o:t?o:r;case"left":case"right":return t?a:l;default:return[]}}function HD(e,t,n,o){const r=Lu(e);let a=VD(El(e),n==="start",o);return r&&(a=a.map(l=>l+"-"+r),t&&(a=a.concat(a.map(wh)))),a}function gd(e){return e.replace(/left|right|bottom|top/g,t=>xD[t])}function zD(e){return{top:0,right:0,bottom:0,left:0,...e}}function kS(e){return typeof e!="number"?zD(e):{top:e,right:e,bottom:e,left:e}}function bd(e){const{x:t,y:n,width:o,height:r}=e;return{width:o,height:r,top:n,left:t,right:t+o,bottom:n+r,x:t,y:n}}function c0(e,t,n){let{reference:o,floating:r}=e;const a=As(t),l=Xv(t),s=Gv(l),u=El(t),c=a==="y",f=o.x+o.width/2-r.width/2,d=o.y+o.height/2-r.height/2,p=o[s]/2-r[s]/2;let m;switch(u){case"top":m={x:f,y:o.y-r.height};break;case"bottom":m={x:f,y:o.y+o.height};break;case"right":m={x:o.x+o.width,y:d};break;case"left":m={x:o.x-r.width,y:d};break;default:m={x:o.x,y:o.y}}switch(Lu(t)){case"start":m[l]-=p*(n&&c?-1:1);break;case"end":m[l]+=p*(n&&c?-1:1);break}return m}const jD=async(e,t,n)=>{const{placement:o="bottom",strategy:r="absolute",middleware:a=[],platform:l}=n,s=a.filter(Boolean),u=await(l.isRTL==null?void 0:l.isRTL(t));let c=await l.getElementRects({reference:e,floating:t,strategy:r}),{x:f,y:d}=c0(c,o,u),p=o,m={},v=0;for(let h=0;h({name:"arrow",options:e,async fn(t){const{x:n,y:o,placement:r,rects:a,platform:l,elements:s,middlewareData:u}=t,{element:c,padding:f=0}=Ru(e,t)||{};if(c==null)return{};const d=kS(f),p={x:n,y:o},m=Xv(r),v=Gv(m),h=await l.getDimensions(c),C=m==="y",g=C?"top":"left",y=C?"bottom":"right",_=C?"clientHeight":"clientWidth",b=a.reference[v]+a.reference[m]-p[m]-a.floating[v],w=p[m]-a.reference[m],S=await(l.getOffsetParent==null?void 0:l.getOffsetParent(c));let E=S?S[_]:0;(!E||!await(l.isElement==null?void 0:l.isElement(S)))&&(E=s.floating[_]||a.floating[v]);const $=b/2-w/2,O=E/2-h[v]/2-1,A=Ms(d[g],O),M=Ms(d[y],O),D=A,U=E-h[v]-M,j=E/2-h[v]/2+$,W=yh(D,j,U),L=!u.arrow&&Lu(r)!=null&&j!==W&&a.reference[v]/2-(jj<=0)){var M,D;const j=(((M=a.flip)==null?void 0:M.index)||0)+1,W=E[j];if(W)return{data:{index:j,overflows:A},reset:{placement:W}};let L=(D=A.filter(P=>P.overflows[0]<=0).sort((P,x)=>P.overflows[1]-x.overflows[1])[0])==null?void 0:D.placement;if(!L)switch(m){case"bestFit":{var U;const P=(U=A.filter(x=>{if(S){const I=As(x.placement);return I===y||I==="y"}return!0}).map(x=>[x.placement,x.overflows.filter(I=>I>0).reduce((I,H)=>I+H,0)]).sort((x,I)=>x[1]-I[1])[0])==null?void 0:U[0];P&&(L=P);break}case"initialPlacement":L=s;break}if(r!==L)return{reset:{placement:L}}}return{}}}};async function UD(e,t){const{placement:n,platform:o,elements:r}=e,a=await(o.isRTL==null?void 0:o.isRTL(r.floating)),l=El(n),s=Lu(n),u=As(n)==="y",c=["left","top"].includes(l)?-1:1,f=a&&u?-1:1,d=Ru(t,e);let{mainAxis:p,crossAxis:m,alignmentAxis:v}=typeof d=="number"?{mainAxis:d,crossAxis:0,alignmentAxis:null}:{mainAxis:0,crossAxis:0,alignmentAxis:null,...d};return s&&typeof v=="number"&&(m=s==="end"?v*-1:v),u?{x:m*f,y:p*c}:{x:p*c,y:m*f}}const qD=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(t){var n,o;const{x:r,y:a,placement:l,middlewareData:s}=t,u=await UD(t,e);return l===((n=s.offset)==null?void 0:n.placement)&&(o=s.arrow)!=null&&o.alignmentOffset?{}:{x:r+u.x,y:a+u.y,data:{...u,placement:l}}}}},YD=function(e){return e===void 0&&(e={}),{name:"shift",options:e,async fn(t){const{x:n,y:o,placement:r}=t,{mainAxis:a=!0,crossAxis:l=!1,limiter:s={fn:C=>{let{x:g,y}=C;return{x:g,y}}},...u}=Ru(e,t),c={x:n,y:o},f=await Jv(t,u),d=As(El(r)),p=SS(d);let m=c[p],v=c[d];if(a){const C=p==="y"?"top":"left",g=p==="y"?"bottom":"right",y=m+f[C],_=m-f[g];m=yh(y,m,_)}if(l){const C=d==="y"?"top":"left",g=d==="y"?"bottom":"right",y=v+f[C],_=v-f[g];v=yh(y,v,_)}const h=s.fn({...t,[p]:m,[d]:v});return{...h,data:{x:h.x-n,y:h.y-o}}}}};function Qs(e){return ES(e)?(e.nodeName||"").toLowerCase():"#document"}function _o(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function Qr(e){var t;return(t=(ES(e)?e.ownerDocument:e.document)||window.document)==null?void 0:t.documentElement}function ES(e){return e instanceof Node||e instanceof _o(e).Node}function nr(e){return e instanceof Element||e instanceof _o(e).Element}function $r(e){return e instanceof HTMLElement||e instanceof _o(e).HTMLElement}function d0(e){return typeof ShadowRoot>"u"?!1:e instanceof ShadowRoot||e instanceof _o(e).ShadowRoot}function xu(e){const{overflow:t,overflowX:n,overflowY:o,display:r}=or(e);return/auto|scroll|overlay|hidden|clip/.test(t+o+n)&&!["inline","contents"].includes(r)}function GD(e){return["table","td","th"].includes(Qs(e))}function gf(e){return[":popover-open",":modal"].some(t=>{try{return e.matches(t)}catch{return!1}})}function Zv(e){const t=Qv(),n=nr(e)?or(e):e;return n.transform!=="none"||n.perspective!=="none"||(n.containerType?n.containerType!=="normal":!1)||!t&&(n.backdropFilter?n.backdropFilter!=="none":!1)||!t&&(n.filter?n.filter!=="none":!1)||["transform","perspective","filter"].some(o=>(n.willChange||"").includes(o))||["paint","layout","strict","content"].some(o=>(n.contain||"").includes(o))}function XD(e){let t=La(e);for(;$r(t)&&!Ps(t);){if(Zv(t))return t;if(gf(t))return null;t=La(t)}return null}function Qv(){return typeof CSS>"u"||!CSS.supports?!1:CSS.supports("-webkit-backdrop-filter","none")}function Ps(e){return["html","body","#document"].includes(Qs(e))}function or(e){return _o(e).getComputedStyle(e)}function bf(e){return nr(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function La(e){if(Qs(e)==="html")return e;const t=e.assignedSlot||e.parentNode||d0(e)&&e.host||Qr(e);return d0(t)?t.host:t}function TS(e){const t=La(e);return Ps(t)?e.ownerDocument?e.ownerDocument.body:e.body:$r(t)&&xu(t)?t:TS(t)}function ru(e,t,n){var o;t===void 0&&(t=[]),n===void 0&&(n=!0);const r=TS(e),a=r===((o=e.ownerDocument)==null?void 0:o.body),l=_o(r);if(a){const s=_h(l);return t.concat(l,l.visualViewport||[],xu(r)?r:[],s&&n?ru(s):[])}return t.concat(r,ru(r,[],n))}function _h(e){return e.parent&&Object.getPrototypeOf(e.parent)?e.frameElement:null}function $S(e){const t=or(e);let n=parseFloat(t.width)||0,o=parseFloat(t.height)||0;const r=$r(e),a=r?e.offsetWidth:n,l=r?e.offsetHeight:o,s=vd(n)!==a||vd(o)!==l;return s&&(n=a,o=l),{width:n,height:o,$:s}}function eg(e){return nr(e)?e:e.contextElement}function fs(e){const t=eg(e);if(!$r(t))return Ra(1);const n=t.getBoundingClientRect(),{width:o,height:r,$:a}=$S(t);let l=(a?vd(n.width):n.width)/o,s=(a?vd(n.height):n.height)/r;return(!l||!Number.isFinite(l))&&(l=1),(!s||!Number.isFinite(s))&&(s=1),{x:l,y:s}}const JD=Ra(0);function OS(e){const t=_o(e);return!Qv()||!t.visualViewport?JD:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function ZD(e,t,n){return t===void 0&&(t=!1),!n||t&&n!==_o(e)?!1:t}function Tl(e,t,n,o){t===void 0&&(t=!1),n===void 0&&(n=!1);const r=e.getBoundingClientRect(),a=eg(e);let l=Ra(1);t&&(o?nr(o)&&(l=fs(o)):l=fs(e));const s=ZD(a,n,o)?OS(a):Ra(0);let u=(r.left+s.x)/l.x,c=(r.top+s.y)/l.y,f=r.width/l.x,d=r.height/l.y;if(a){const p=_o(a),m=o&&nr(o)?_o(o):o;let v=p,h=_h(v);for(;h&&o&&m!==v;){const C=fs(h),g=h.getBoundingClientRect(),y=or(h),_=g.left+(h.clientLeft+parseFloat(y.paddingLeft))*C.x,b=g.top+(h.clientTop+parseFloat(y.paddingTop))*C.y;u*=C.x,c*=C.y,f*=C.x,d*=C.y,u+=_,c+=b,v=_o(h),h=_h(v)}}return bd({width:f,height:d,x:u,y:c})}function QD(e){let{elements:t,rect:n,offsetParent:o,strategy:r}=e;const a=r==="fixed",l=Qr(o),s=t?gf(t.floating):!1;if(o===l||s&&a)return n;let u={scrollLeft:0,scrollTop:0},c=Ra(1);const f=Ra(0),d=$r(o);if((d||!d&&!a)&&((Qs(o)!=="body"||xu(l))&&(u=bf(o)),$r(o))){const p=Tl(o);c=fs(o),f.x=p.x+o.clientLeft,f.y=p.y+o.clientTop}return{width:n.width*c.x,height:n.height*c.y,x:n.x*c.x-u.scrollLeft*c.x+f.x,y:n.y*c.y-u.scrollTop*c.y+f.y}}function e8(e){return Array.from(e.getClientRects())}function NS(e){return Tl(Qr(e)).left+bf(e).scrollLeft}function t8(e){const t=Qr(e),n=bf(e),o=e.ownerDocument.body,r=cl(t.scrollWidth,t.clientWidth,o.scrollWidth,o.clientWidth),a=cl(t.scrollHeight,t.clientHeight,o.scrollHeight,o.clientHeight);let l=-n.scrollLeft+NS(e);const s=-n.scrollTop;return or(o).direction==="rtl"&&(l+=cl(t.clientWidth,o.clientWidth)-r),{width:r,height:a,x:l,y:s}}function n8(e,t){const n=_o(e),o=Qr(e),r=n.visualViewport;let a=o.clientWidth,l=o.clientHeight,s=0,u=0;if(r){a=r.width,l=r.height;const c=Qv();(!c||c&&t==="fixed")&&(s=r.offsetLeft,u=r.offsetTop)}return{width:a,height:l,x:s,y:u}}function o8(e,t){const n=Tl(e,!0,t==="fixed"),o=n.top+e.clientTop,r=n.left+e.clientLeft,a=$r(e)?fs(e):Ra(1),l=e.clientWidth*a.x,s=e.clientHeight*a.y,u=r*a.x,c=o*a.y;return{width:l,height:s,x:u,y:c}}function f0(e,t,n){let o;if(t==="viewport")o=n8(e,n);else if(t==="document")o=t8(Qr(e));else if(nr(t))o=o8(t,n);else{const r=OS(e);o={...t,x:t.x-r.x,y:t.y-r.y}}return bd(o)}function IS(e,t){const n=La(e);return n===t||!nr(n)||Ps(n)?!1:or(n).position==="fixed"||IS(n,t)}function r8(e,t){const n=t.get(e);if(n)return n;let o=ru(e,[],!1).filter(s=>nr(s)&&Qs(s)!=="body"),r=null;const a=or(e).position==="fixed";let l=a?La(e):e;for(;nr(l)&&!Ps(l);){const s=or(l),u=Zv(l);!u&&s.position==="fixed"&&(r=null),(a?!u&&!r:!u&&s.position==="static"&&!!r&&["absolute","fixed"].includes(r.position)||xu(l)&&!u&&IS(e,l))?o=o.filter(f=>f!==l):r=s,l=La(l)}return t.set(e,o),o}function a8(e){let{element:t,boundary:n,rootBoundary:o,strategy:r}=e;const l=[...n==="clippingAncestors"?gf(t)?[]:r8(t,this._c):[].concat(n),o],s=l[0],u=l.reduce((c,f)=>{const d=f0(t,f,r);return c.top=cl(d.top,c.top),c.right=Ms(d.right,c.right),c.bottom=Ms(d.bottom,c.bottom),c.left=cl(d.left,c.left),c},f0(t,s,r));return{width:u.right-u.left,height:u.bottom-u.top,x:u.left,y:u.top}}function l8(e){const{width:t,height:n}=$S(e);return{width:t,height:n}}function s8(e,t,n){const o=$r(t),r=Qr(t),a=n==="fixed",l=Tl(e,!0,a,t);let s={scrollLeft:0,scrollTop:0};const u=Ra(0);if(o||!o&&!a)if((Qs(t)!=="body"||xu(r))&&(s=bf(t)),o){const d=Tl(t,!0,a,t);u.x=d.x+t.clientLeft,u.y=d.y+t.clientTop}else r&&(u.x=NS(r));const c=l.left+s.scrollLeft-u.x,f=l.top+s.scrollTop-u.y;return{x:c,y:f,width:l.width,height:l.height}}function dp(e){return or(e).position==="static"}function p0(e,t){return!$r(e)||or(e).position==="fixed"?null:t?t(e):e.offsetParent}function MS(e,t){const n=_o(e);if(gf(e))return n;if(!$r(e)){let r=La(e);for(;r&&!Ps(r);){if(nr(r)&&!dp(r))return r;r=La(r)}return n}let o=p0(e,t);for(;o&&GD(o)&&dp(o);)o=p0(o,t);return o&&Ps(o)&&dp(o)&&!Zv(o)?n:o||XD(e)||n}const i8=async function(e){const t=this.getOffsetParent||MS,n=this.getDimensions,o=await n(e.floating);return{reference:s8(e.reference,await t(e.floating),e.strategy),floating:{x:0,y:0,width:o.width,height:o.height}}};function u8(e){return or(e).direction==="rtl"}const c8={convertOffsetParentRelativeRectToViewportRelativeRect:QD,getDocumentElement:Qr,getClippingRect:a8,getOffsetParent:MS,getElementRects:i8,getClientRects:e8,getDimensions:l8,getScale:fs,isElement:nr,isRTL:u8};function d8(e,t){let n=null,o;const r=Qr(e);function a(){var s;clearTimeout(o),(s=n)==null||s.disconnect(),n=null}function l(s,u){s===void 0&&(s=!1),u===void 0&&(u=1),a();const{left:c,top:f,width:d,height:p}=e.getBoundingClientRect();if(s||t(),!d||!p)return;const m=dc(f),v=dc(r.clientWidth-(c+d)),h=dc(r.clientHeight-(f+p)),C=dc(c),y={rootMargin:-m+"px "+-v+"px "+-h+"px "+-C+"px",threshold:cl(0,Ms(1,u))||1};let _=!0;function b(w){const S=w[0].intersectionRatio;if(S!==u){if(!_)return l();S?l(!1,S):o=setTimeout(()=>{l(!1,1e-7)},1e3)}_=!1}try{n=new IntersectionObserver(b,{...y,root:r.ownerDocument})}catch{n=new IntersectionObserver(b,y)}n.observe(e)}return l(!0),a}function f8(e,t,n,o){o===void 0&&(o={});const{ancestorScroll:r=!0,ancestorResize:a=!0,elementResize:l=typeof ResizeObserver=="function",layoutShift:s=typeof IntersectionObserver=="function",animationFrame:u=!1}=o,c=eg(e),f=r||a?[...c?ru(c):[],...ru(t)]:[];f.forEach(g=>{r&&g.addEventListener("scroll",n,{passive:!0}),a&&g.addEventListener("resize",n)});const d=c&&s?d8(c,n):null;let p=-1,m=null;l&&(m=new ResizeObserver(g=>{let[y]=g;y&&y.target===c&&m&&(m.unobserve(t),cancelAnimationFrame(p),p=requestAnimationFrame(()=>{var _;(_=m)==null||_.observe(t)})),n()}),c&&!u&&m.observe(c),m.observe(t));let v,h=u?Tl(e):null;u&&C();function C(){const g=Tl(e);h&&(g.x!==h.x||g.y!==h.y||g.width!==h.width||g.height!==h.height)&&n(),h=g,v=requestAnimationFrame(C)}return n(),()=>{var g;f.forEach(y=>{r&&y.removeEventListener("scroll",n),a&&y.removeEventListener("resize",n)}),d==null||d(),(g=m)==null||g.disconnect(),m=null,u&&cancelAnimationFrame(v)}}const p8=Jv,AS=qD,h8=YD,m8=KD,PS=WD,RS=(e,t,n)=>{const o=new Map,r={platform:c8,...n},a={...r.platform,_c:o};return jD(e,t,{...r,platform:a})};Ne({});const v8=e=>{if(!Ct)return;if(!e)return e;const t=lo(e);return t||(xt(e)?t:e)},g8=({middleware:e,placement:t,strategy:n})=>{const o=R(),r=R(),a=R(),l=R(),s=R({}),u={x:a,y:l,placement:t,strategy:n,middlewareData:s},c=async()=>{if(!Ct)return;const f=v8(o),d=lo(r);if(!f||!d)return;const p=await RS(f,d,{placement:i(t),strategy:i(n),middleware:i(e)});Ss(u).forEach(m=>{u[m].value=p[m]})};return at(()=>{Mn(()=>{c()})}),{...u,update:c,referenceRef:o,contentRef:r}},b8=({arrowRef:e,padding:t})=>({name:"arrow",options:{element:e,padding:t},fn(n){const o=i(e);return o?PS({element:o,padding:t}).fn(n):{}}});function y8(e){const t=R();function n(){if(e.value==null)return;const{selectionStart:r,selectionEnd:a,value:l}=e.value;if(r==null||a==null)return;const s=l.slice(0,Math.max(0,r)),u=l.slice(Math.max(0,a));t.value={selectionStart:r,selectionEnd:a,value:l,beforeTxt:s,afterTxt:u}}function o(){if(e.value==null||t.value==null)return;const{value:r}=e.value,{beforeTxt:a,afterTxt:l,selectionStart:s}=t.value;if(a==null||l==null||s==null)return;let u=r.length;if(r.endsWith(l))u=r.length-l.length;else if(r.startsWith(a))u=a.length;else{const c=a[s-1],f=r.indexOf(c,s-1);f!==-1&&(u=f+1)}e.value.setSelectionRange(u,u)}return[n,o]}const w8=(e,t,n)=>Ca(e.subTree).filter(a=>{var l;return Wt(a)&&((l=a.type)==null?void 0:l.name)===t&&!!a.component}).map(a=>a.component.uid).map(a=>n[a]).filter(a=>!!a),tg=(e,t)=>{const n={},o=Ut([]);return{children:o,addChild:l=>{n[l.uid]=l,o.value=w8(e,t,n)},removeChild:l=>{delete n[l],o.value=o.value.filter(s=>s.uid!==l)}}},gn=ir({type:String,values:Ir,required:!1}),LS=Symbol("size"),xS=()=>{const e=De(LS,{});return k(()=>i(e.size)||"")};function yf(e,{afterFocus:t,beforeBlur:n,afterBlur:o}={}){const r=lt(),{emit:a}=r,l=Ut(),s=R(!1),u=d=>{s.value||(s.value=!0,a("focus",d),t==null||t())},c=d=>{var p;Xe(n)&&n(d)||d.relatedTarget&&((p=l.value)!=null&&p.contains(d.relatedTarget))||(s.value=!1,a("blur",d),o==null||o())},f=()=>{var d;(d=e.value)==null||d.focus()};return ve(l,d=>{d&&d.setAttribute("tabindex","-1")}),qt(l,"click",f),{wrapperRef:l,isFocused:s,handleFocus:u,handleBlur:c}}const DS=Symbol("emptyValuesContextKey"),_8=["",void 0,null],C8=void 0,ei=Ne({emptyValues:Array,valueOnClear:{type:[String,Number,Boolean,Function],default:void 0,validator:e=>Xe(e)?!e():!e}}),wf=(e,t)=>{const n=lt()?De(DS,R({})):R({}),o=k(()=>e.emptyValues||n.value.emptyValues||_8),r=k(()=>Xe(e.valueOnClear)?e.valueOnClear():e.valueOnClear!==void 0?e.valueOnClear:Xe(n.value.valueOnClear)?n.value.valueOnClear():n.value.valueOnClear!==void 0?n.value.valueOnClear:t!==void 0?t:C8),a=l=>o.value.includes(l);return o.value.includes(r.value),{emptyValues:o,valueOnClear:r,isEmptyValue:a}},S8=Ne({ariaLabel:String,ariaOrientation:{type:String,values:["horizontal","vertical","undefined"]},ariaControls:String}),An=e=>gr(S8,e),FS=Symbol(),yd=R();function _f(e,t=void 0){const n=lt()?De(FS,yd):yd;return e?k(()=>{var o,r;return(r=(o=n.value)==null?void 0:o[e])!=null?r:t}):n}function Cf(e,t){const n=_f(),o=Se(e,k(()=>{var s;return((s=n.value)==null?void 0:s.namespace)||Ri})),r=$t(k(()=>{var s;return(s=n.value)==null?void 0:s.locale})),a=Zs(k(()=>{var s;return((s=n.value)==null?void 0:s.zIndex)||_S})),l=k(()=>{var s;return i(t)||((s=n.value)==null?void 0:s.size)||""});return ng(k(()=>i(n)||{})),{ns:o,locale:r,zIndex:a,size:l}}const ng=(e,t,n=!1)=>{var o;const r=!!lt(),a=r?_f():void 0,l=(o=t==null?void 0:t.provide)!=null?o:r?yt:void 0;if(!l)return;const s=k(()=>{const u=i(e);return a!=null&&a.value?k8(a.value,u):u});return l(FS,s),l(rS,k(()=>s.value.locale)),l(aS,k(()=>s.value.namespace)),l(CS,k(()=>s.value.zIndex)),l(LS,{size:k(()=>s.value.size||"")}),l(DS,k(()=>({emptyValues:s.value.emptyValues,valueOnClear:s.value.valueOnClear}))),(n||!yd.value)&&(yd.value=s.value),s},k8=(e,t)=>{const n=[...new Set([...Ss(e),...Ss(t)])],o={};for(const r of n)o[r]=t[r]!==void 0?t[r]:e[r];return o},E8=Ne({a11y:{type:Boolean,default:!0},locale:{type:Q(Object)},size:gn,button:{type:Q(Object)},experimentalFeatures:{type:Q(Object)},keyboardNavigation:{type:Boolean,default:!0},message:{type:Q(Object)},zIndex:Number,namespace:{type:String,default:"el"},...ei}),Ch={},T8=Y({name:"ElConfigProvider",props:E8,setup(e,{slots:t}){ve(()=>e.message,o=>{Object.assign(Ch,o??{})},{immediate:!0,deep:!0});const n=ng(e);return()=>ie(t,"default",{config:n==null?void 0:n.value})}}),$8=ut(T8),O8="2.7.8",N8=(e=[])=>({version:O8,install:(n,o)=>{n[Uy]||(n[Uy]=!0,e.forEach(r=>n.use(r)),o&&ng(o,n,!0))}}),I8=Ne({zIndex:{type:Q([Number,String]),default:100},target:{type:String,default:""},offset:{type:Number,default:0},position:{type:String,values:["top","bottom"],default:"top"}}),M8={scroll:({scrollTop:e,fixed:t})=>Je(e)&&dn(t),[Yt]:e=>dn(e)};var Ie=(e,t)=>{const n=e.__vccOpts||e;for(const[o,r]of t)n[o]=r;return n};const BS="ElAffix",A8=Y({name:BS}),P8=Y({...A8,props:I8,emits:M8,setup(e,{expose:t,emit:n}){const o=e,r=Se("affix"),a=Ut(),l=Ut(),s=Ut(),{height:u}=bM(),{height:c,width:f,top:d,bottom:p,update:m}=ly(l,{windowScroll:!1}),v=ly(a),h=R(!1),C=R(0),g=R(0),y=k(()=>({height:h.value?`${c.value}px`:"",width:h.value?`${f.value}px`:""})),_=k(()=>{if(!h.value)return{};const S=o.offset?rn(o.offset):0;return{height:`${c.value}px`,width:`${f.value}px`,top:o.position==="top"?S:"",bottom:o.position==="bottom"?S:"",transform:g.value?`translateY(${g.value}px)`:"",zIndex:o.zIndex}}),b=()=>{if(s.value)if(C.value=s.value instanceof Window?document.documentElement.scrollTop:s.value.scrollTop||0,o.position==="top")if(o.target){const S=v.bottom.value-o.offset-c.value;h.value=o.offset>d.value&&v.bottom.value>0,g.value=S<0?S:0}else h.value=o.offset>d.value;else if(o.target){const S=u.value-v.top.value-o.offset-c.value;h.value=u.value-o.offsetv.top.value,g.value=S<0?-S:0}else h.value=u.value-o.offset{m(),n("scroll",{scrollTop:C.value,fixed:h.value})};return ve(h,S=>n("change",S)),at(()=>{var S;o.target?(a.value=(S=document.querySelector(o.target))!=null?S:void 0,a.value||vn(BS,`Target does not exist: ${o.target}`)):a.value=document.documentElement,s.value=Ov(l.value,!0),m()}),qt(s,"scroll",w),Mn(b),t({update:b,updateRoot:m}),(S,E)=>(T(),V("div",{ref_key:"root",ref:l,class:N(i(r).b()),style:je(i(y))},[F("div",{class:N({[i(r).m("fixed")]:h.value}),style:je(i(_))},[ie(S.$slots,"default")],6)],6))}});var R8=Ie(P8,[["__file","affix.vue"]]);const L8=ut(R8),x8=Ne({size:{type:Q([Number,String])},color:{type:String}}),D8=Y({name:"ElIcon",inheritAttrs:!1}),F8=Y({...D8,props:x8,setup(e){const t=e,n=Se("icon"),o=k(()=>{const{size:r,color:a}=t;return!r&&!a?{}:{fontSize:pn(r)?void 0:rn(r),"--color":a}});return(r,a)=>(T(),V("i",mt({class:i(n).b(),style:i(o)},r.$attrs),[ie(r.$slots,"default")],16))}});var B8=Ie(F8,[["__file","icon.vue"]]);const ze=ut(B8),V8=["light","dark"],H8=Ne({title:{type:String,default:""},description:{type:String,default:""},type:{type:String,values:Ss(Pa),default:"info"},closable:{type:Boolean,default:!0},closeText:{type:String,default:""},showIcon:Boolean,center:Boolean,effect:{type:String,values:V8,default:"light"}}),z8={close:e=>e instanceof MouseEvent},j8=Y({name:"ElAlert"}),W8=Y({...j8,props:H8,emits:z8,setup(e,{emit:t}){const n=e,{Close:o}=Pv,r=Sn(),a=Se("alert"),l=R(!0),s=k(()=>Pa[n.type]),u=k(()=>[a.e("icon"),{[a.is("big")]:!!n.description||!!r.default}]),c=k(()=>({"with-description":n.description||r.default})),f=d=>{l.value=!1,t("close",d)};return(d,p)=>(T(),re(fn,{name:i(a).b("fade"),persisted:""},{default:X(()=>[tt(F("div",{class:N([i(a).b(),i(a).m(d.type),i(a).is("center",d.center),i(a).is(d.effect)]),role:"alert"},[d.showIcon&&i(s)?(T(),re(i(ze),{key:0,class:N(i(u))},{default:X(()=>[(T(),re(pt(i(s))))]),_:1},8,["class"])):te("v-if",!0),F("div",{class:N(i(a).e("content"))},[d.title||d.$slots.title?(T(),V("span",{key:0,class:N([i(a).e("title"),i(c)])},[ie(d.$slots,"title",{},()=>[Ge(le(d.title),1)])],2)):te("v-if",!0),d.$slots.default||d.description?(T(),V("p",{key:1,class:N(i(a).e("description"))},[ie(d.$slots,"default",{},()=>[Ge(le(d.description),1)])],2)):te("v-if",!0),d.closable?(T(),V(Ve,{key:2},[d.closeText?(T(),V("div",{key:0,class:N([i(a).e("close-btn"),i(a).is("customed")]),onClick:f},le(d.closeText),3)):(T(),re(i(ze),{key:1,class:N(i(a).e("close-btn")),onClick:f},{default:X(()=>[K(i(o))]),_:1},8,["class"]))],64)):te("v-if",!0)],2)],2),[[kt,l.value]])]),_:3},8,["name"]))}});var K8=Ie(W8,[["__file","alert.vue"]]);const U8=ut(K8),Fl=Symbol("formContextKey"),Or=Symbol("formItemContextKey"),hn=(e,t={})=>{const n=R(void 0),o=t.prop?n:sS("size"),r=t.global?n:xS(),a=t.form?{size:void 0}:De(Fl,void 0),l=t.formItem?{size:void 0}:De(Or,void 0);return k(()=>o.value||i(e)||(l==null?void 0:l.size)||(a==null?void 0:a.size)||r.value||"")},to=e=>{const t=sS("disabled"),n=De(Fl,void 0);return k(()=>t.value||i(e)||(n==null?void 0:n.disabled)||!1)},qn=()=>{const e=De(Fl,void 0),t=De(Or,void 0);return{form:e,formItem:t}},cr=(e,{formItemContext:t,disableIdGeneration:n,disableIdManagement:o})=>{n||(n=R(!1)),o||(o=R(!1));const r=R();let a;const l=k(()=>{var s;return!!(!(e.label||e.ariaLabel)&&t&&t.inputIds&&((s=t.inputIds)==null?void 0:s.length)<=1)});return at(()=>{a=ve([Lt(e,"id"),n],([s,u])=>{const c=s??(u?void 0:xn().value);c!==r.value&&(t!=null&&t.removeInputId&&(r.value&&t.removeInputId(r.value),!(o!=null&&o.value)&&!u&&c&&t.addInputId(c)),r.value=c)},{immediate:!0})}),lr(()=>{a&&a(),t!=null&&t.removeInputId&&r.value&&t.removeInputId(r.value)}),{isLabeledByFormItem:l,inputId:r}},q8=Ne({size:{type:String,values:Ir},disabled:Boolean}),Y8=Ne({...q8,model:Object,rules:{type:Q(Object)},labelPosition:{type:String,values:["left","right","top"],default:"right"},requireAsteriskPosition:{type:String,values:["left","right"],default:"left"},labelWidth:{type:[String,Number],default:""},labelSuffix:{type:String,default:""},inline:Boolean,inlineMessage:Boolean,statusIcon:Boolean,showMessage:{type:Boolean,default:!0},validateOnRuleChange:{type:Boolean,default:!0},hideRequiredAsterisk:Boolean,scrollToError:Boolean,scrollIntoViewOptions:{type:[Object,Boolean]}}),G8={validate:(e,t,n)=>(Pe(e)||nt(e))&&dn(t)&&nt(n)};function X8(){const e=R([]),t=k(()=>{if(!e.value.length)return"0";const a=Math.max(...e.value);return a?`${a}px`:""});function n(a){const l=e.value.indexOf(a);return l===-1&&t.value,l}function o(a,l){if(a&&l){const s=n(l);e.value.splice(s,1,a)}else a&&e.value.push(a)}function r(a){const l=n(a);l>-1&&e.value.splice(l,1)}return{autoLabelWidth:t,registerLabelWidth:o,deregisterLabelWidth:r}}const fc=(e,t)=>{const n=Ia(t);return n.length>0?e.filter(o=>o.prop&&n.includes(o.prop)):e},J8="ElForm",Z8=Y({name:J8}),Q8=Y({...Z8,props:Y8,emits:G8,setup(e,{expose:t,emit:n}){const o=e,r=[],a=hn(),l=Se("form"),s=k(()=>{const{labelPosition:_,inline:b}=o;return[l.b(),l.m(a.value||"default"),{[l.m(`label-${_}`)]:_,[l.m("inline")]:b}]}),u=_=>r.find(b=>b.prop===_),c=_=>{r.push(_)},f=_=>{_.prop&&r.splice(r.indexOf(_),1)},d=(_=[])=>{o.model&&fc(r,_).forEach(b=>b.resetField())},p=(_=[])=>{fc(r,_).forEach(b=>b.clearValidate())},m=k(()=>!!o.model),v=_=>{if(r.length===0)return[];const b=fc(r,_);return b.length?b:[]},h=async _=>g(void 0,_),C=async(_=[])=>{if(!m.value)return!1;const b=v(_);if(b.length===0)return!0;let w={};for(const S of b)try{await S.validate("")}catch(E){w={...w,...E}}return Object.keys(w).length===0?!0:Promise.reject(w)},g=async(_=[],b)=>{const w=!Xe(b);try{const S=await C(_);return S===!0&&await(b==null?void 0:b(S)),S}catch(S){if(S instanceof Error)throw S;const E=S;return o.scrollToError&&y(Object.keys(E)[0]),await(b==null?void 0:b(!1,E)),w&&Promise.reject(E)}},y=_=>{var b;const w=fc(r,_)[0];w&&((b=w.$el)==null||b.scrollIntoView(o.scrollIntoViewOptions))};return ve(()=>o.rules,()=>{o.validateOnRuleChange&&h().catch(_=>void 0)},{deep:!0}),yt(Fl,Et({...Cn(o),emit:n,resetFields:d,clearValidate:p,validateField:g,getField:u,addField:c,removeField:f,...X8()})),t({validate:h,validateField:g,resetFields:d,clearValidate:p,scrollToField:y,fields:r}),(_,b)=>(T(),V("form",{class:N(i(s))},[ie(_.$slots,"default")],2))}});var eF=Ie(Q8,[["__file","form.vue"]]);function Za(){return Za=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function Pc(e,t,n){return nF()?Pc=Reflect.construct.bind():Pc=function(r,a,l){var s=[null];s.push.apply(s,a);var u=Function.bind.apply(r,s),c=new u;return l&&au(c,l.prototype),c},Pc.apply(null,arguments)}function oF(e){return Function.toString.call(e).indexOf("[native code]")!==-1}function kh(e){var t=typeof Map=="function"?new Map:void 0;return kh=function(o){if(o===null||!oF(o))return o;if(typeof o!="function")throw new TypeError("Super expression must either be null or a function");if(typeof t<"u"){if(t.has(o))return t.get(o);t.set(o,r)}function r(){return Pc(o,arguments,Sh(this).constructor)}return r.prototype=Object.create(o.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),au(r,o)},kh(e)}var rF=/%[sdj%]/g,aF=function(){};function Eh(e){if(!e||!e.length)return null;var t={};return e.forEach(function(n){var o=n.field;t[o]=t[o]||[],t[o].push(n)}),t}function vo(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o=a)return s;switch(s){case"%s":return String(n[r++]);case"%d":return Number(n[r++]);case"%j":try{return JSON.stringify(n[r++])}catch{return"[Circular]"}break;default:return s}});return l}return e}function lF(e){return e==="string"||e==="url"||e==="hex"||e==="email"||e==="date"||e==="pattern"}function On(e,t){return!!(e==null||t==="array"&&Array.isArray(e)&&!e.length||lF(t)&&typeof e=="string"&&!e)}function sF(e,t,n){var o=[],r=0,a=e.length;function l(s){o.push.apply(o,s||[]),r++,r===a&&n(o)}e.forEach(function(s){t(s,l)})}function h0(e,t,n){var o=0,r=e.length;function a(l){if(l&&l.length){n(l);return}var s=o;o=o+1,s()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+\.)+[a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}))$/,hex:/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i},ki={integer:function(t){return ki.number(t)&&parseInt(t,10)===t},float:function(t){return ki.number(t)&&!ki.integer(t)},array:function(t){return Array.isArray(t)},regexp:function(t){if(t instanceof RegExp)return!0;try{return!!new RegExp(t)}catch{return!1}},date:function(t){return typeof t.getTime=="function"&&typeof t.getMonth=="function"&&typeof t.getYear=="function"&&!isNaN(t.getTime())},number:function(t){return isNaN(t)?!1:typeof t=="number"},object:function(t){return typeof t=="object"&&!ki.array(t)},method:function(t){return typeof t=="function"},email:function(t){return typeof t=="string"&&t.length<=320&&!!t.match(b0.email)},url:function(t){return typeof t=="string"&&t.length<=2048&&!!t.match(pF())},hex:function(t){return typeof t=="string"&&!!t.match(b0.hex)}},hF=function(t,n,o,r,a){if(t.required&&n===void 0){VS(t,n,o,r,a);return}var l=["integer","float","array","regexp","object","method","email","number","date","url","hex"],s=t.type;l.indexOf(s)>-1?ki[s](n)||r.push(vo(a.messages.types[s],t.fullField,t.type)):s&&typeof n!==t.type&&r.push(vo(a.messages.types[s],t.fullField,t.type))},mF=function(t,n,o,r,a){var l=typeof t.len=="number",s=typeof t.min=="number",u=typeof t.max=="number",c=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,f=n,d=null,p=typeof n=="number",m=typeof n=="string",v=Array.isArray(n);if(p?d="number":m?d="string":v&&(d="array"),!d)return!1;v&&(f=n.length),m&&(f=n.replace(c,"_").length),l?f!==t.len&&r.push(vo(a.messages[d].len,t.fullField,t.len)):s&&!u&&ft.max?r.push(vo(a.messages[d].max,t.fullField,t.max)):s&&u&&(ft.max)&&r.push(vo(a.messages[d].range,t.fullField,t.min,t.max))},Kl="enum",vF=function(t,n,o,r,a){t[Kl]=Array.isArray(t[Kl])?t[Kl]:[],t[Kl].indexOf(n)===-1&&r.push(vo(a.messages[Kl],t.fullField,t[Kl].join(", ")))},gF=function(t,n,o,r,a){if(t.pattern){if(t.pattern instanceof RegExp)t.pattern.lastIndex=0,t.pattern.test(n)||r.push(vo(a.messages.pattern.mismatch,t.fullField,n,t.pattern));else if(typeof t.pattern=="string"){var l=new RegExp(t.pattern);l.test(n)||r.push(vo(a.messages.pattern.mismatch,t.fullField,n,t.pattern))}}},Vt={required:VS,whitespace:fF,type:hF,range:mF,enum:vF,pattern:gF},bF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n,"string")&&!t.required)return o();Vt.required(t,n,r,l,a,"string"),On(n,"string")||(Vt.type(t,n,r,l,a),Vt.range(t,n,r,l,a),Vt.pattern(t,n,r,l,a),t.whitespace===!0&&Vt.whitespace(t,n,r,l,a))}o(l)},yF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n)&&!t.required)return o();Vt.required(t,n,r,l,a),n!==void 0&&Vt.type(t,n,r,l,a)}o(l)},wF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(n===""&&(n=void 0),On(n)&&!t.required)return o();Vt.required(t,n,r,l,a),n!==void 0&&(Vt.type(t,n,r,l,a),Vt.range(t,n,r,l,a))}o(l)},_F=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n)&&!t.required)return o();Vt.required(t,n,r,l,a),n!==void 0&&Vt.type(t,n,r,l,a)}o(l)},CF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n)&&!t.required)return o();Vt.required(t,n,r,l,a),On(n)||Vt.type(t,n,r,l,a)}o(l)},SF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n)&&!t.required)return o();Vt.required(t,n,r,l,a),n!==void 0&&(Vt.type(t,n,r,l,a),Vt.range(t,n,r,l,a))}o(l)},kF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n)&&!t.required)return o();Vt.required(t,n,r,l,a),n!==void 0&&(Vt.type(t,n,r,l,a),Vt.range(t,n,r,l,a))}o(l)},EF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(n==null&&!t.required)return o();Vt.required(t,n,r,l,a,"array"),n!=null&&(Vt.type(t,n,r,l,a),Vt.range(t,n,r,l,a))}o(l)},TF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n)&&!t.required)return o();Vt.required(t,n,r,l,a),n!==void 0&&Vt.type(t,n,r,l,a)}o(l)},$F="enum",OF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n)&&!t.required)return o();Vt.required(t,n,r,l,a),n!==void 0&&Vt[$F](t,n,r,l,a)}o(l)},NF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n,"string")&&!t.required)return o();Vt.required(t,n,r,l,a),On(n,"string")||Vt.pattern(t,n,r,l,a)}o(l)},IF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n,"date")&&!t.required)return o();if(Vt.required(t,n,r,l,a),!On(n,"date")){var u;n instanceof Date?u=n:u=new Date(n),Vt.type(t,u,r,l,a),u&&Vt.range(t,u.getTime(),r,l,a)}}o(l)},MF=function(t,n,o,r,a){var l=[],s=Array.isArray(n)?"array":typeof n;Vt.required(t,n,r,l,a,s),o(l)},fp=function(t,n,o,r,a){var l=t.type,s=[],u=t.required||!t.required&&r.hasOwnProperty(t.field);if(u){if(On(n,l)&&!t.required)return o();Vt.required(t,n,r,s,a,l),On(n,l)||Vt.type(t,n,r,s,a)}o(s)},AF=function(t,n,o,r,a){var l=[],s=t.required||!t.required&&r.hasOwnProperty(t.field);if(s){if(On(n)&&!t.required)return o();Vt.required(t,n,r,l,a)}o(l)},Di={string:bF,method:yF,number:wF,boolean:_F,regexp:CF,integer:SF,float:kF,array:EF,object:TF,enum:OF,pattern:NF,date:IF,url:fp,hex:fp,email:fp,required:MF,any:AF};function Th(){return{default:"Validation error on field %s",required:"%s is required",enum:"%s must be one of %s",whitespace:"%s cannot be empty",date:{format:"%s date %s is invalid for format %s",parse:"%s date could not be parsed, %s is invalid ",invalid:"%s date %s is invalid"},types:{string:"%s is not a %s",method:"%s is not a %s (function)",array:"%s is not an %s",object:"%s is not an %s",number:"%s is not a %s",date:"%s is not a %s",boolean:"%s is not a %s",integer:"%s is not an %s",float:"%s is not a %s",regexp:"%s is not a valid %s",email:"%s is not a valid %s",url:"%s is not a valid %s",hex:"%s is not a valid %s"},string:{len:"%s must be exactly %s characters",min:"%s must be at least %s characters",max:"%s cannot be longer than %s characters",range:"%s must be between %s and %s characters"},number:{len:"%s must equal %s",min:"%s cannot be less than %s",max:"%s cannot be greater than %s",range:"%s must be between %s and %s"},array:{len:"%s must be exactly %s in length",min:"%s cannot be less than %s in length",max:"%s cannot be greater than %s in length",range:"%s must be between %s and %s in length"},pattern:{mismatch:"%s value %s does not match pattern %s"},clone:function(){var t=JSON.parse(JSON.stringify(this));return t.clone=this.clone,t}}}var $h=Th(),Du=function(){function e(n){this.rules=null,this._messages=$h,this.define(n)}var t=e.prototype;return t.define=function(o){var r=this;if(!o)throw new Error("Cannot configure a schema with no rules");if(typeof o!="object"||Array.isArray(o))throw new Error("Rules must be an object");this.rules={},Object.keys(o).forEach(function(a){var l=o[a];r.rules[a]=Array.isArray(l)?l:[l]})},t.messages=function(o){return o&&(this._messages=g0(Th(),o)),this._messages},t.validate=function(o,r,a){var l=this;r===void 0&&(r={}),a===void 0&&(a=function(){});var s=o,u=r,c=a;if(typeof u=="function"&&(c=u,u={}),!this.rules||Object.keys(this.rules).length===0)return c&&c(null,s),Promise.resolve(s);function f(h){var C=[],g={};function y(b){if(Array.isArray(b)){var w;C=(w=C).concat.apply(w,b)}else C.push(b)}for(var _=0;_");const r=Se("form"),a=R(),l=R(0),s=()=>{var f;if((f=a.value)!=null&&f.firstElementChild){const d=window.getComputedStyle(a.value.firstElementChild).width;return Math.ceil(Number.parseFloat(d))}else return 0},u=(f="update")=>{We(()=>{t.default&&e.isAutoWidth&&(f==="update"?l.value=s():f==="remove"&&(n==null||n.deregisterLabelWidth(l.value)))})},c=()=>u("update");return at(()=>{c()}),zt(()=>{u("remove")}),ar(()=>c()),ve(l,(f,d)=>{e.updateAll&&(n==null||n.registerLabelWidth(f,d))}),Qt(k(()=>{var f,d;return(d=(f=a.value)==null?void 0:f.firstElementChild)!=null?d:null}),c),()=>{var f,d;if(!t)return null;const{isAutoWidth:p}=e;if(p){const m=n==null?void 0:n.autoLabelWidth,v=o==null?void 0:o.hasLabel,h={};if(v&&m&&m!=="auto"){const C=Math.max(0,Number.parseInt(m,10)-l.value),y=(o.labelPosition||n.labelPosition)==="left"?"marginRight":"marginLeft";C&&(h[y]=`${C}px`)}return K("div",{ref:a,class:[r.be("item","label-wrap")],style:h},[(f=t.default)==null?void 0:f.call(t)])}else return K(Ve,{ref:a},[(d=t.default)==null?void 0:d.call(t)])}}});const xF=["role","aria-labelledby"],DF=Y({name:"ElFormItem"}),FF=Y({...DF,props:RF,setup(e,{expose:t}){const n=e,o=Sn(),r=De(Fl,void 0),a=De(Or,void 0),l=hn(void 0,{formItem:!1}),s=Se("form-item"),u=xn().value,c=R([]),f=R(""),d=eM(f,100),p=R(""),m=R();let v,h=!1;const C=k(()=>n.labelPosition||(r==null?void 0:r.labelPosition)),g=k(()=>{if(C.value==="top")return{};const ae=rn(n.labelWidth||(r==null?void 0:r.labelWidth)||"");return ae?{width:ae}:{}}),y=k(()=>{if(C.value==="top"||r!=null&&r.inline)return{};if(!n.label&&!n.labelWidth&&A)return{};const ae=rn(n.labelWidth||(r==null?void 0:r.labelWidth)||"");return!n.label&&!o.label?{marginLeft:ae}:{}}),_=k(()=>[s.b(),s.m(l.value),s.is("error",f.value==="error"),s.is("validating",f.value==="validating"),s.is("success",f.value==="success"),s.is("required",W.value||n.required),s.is("no-asterisk",r==null?void 0:r.hideRequiredAsterisk),(r==null?void 0:r.requireAsteriskPosition)==="right"?"asterisk-right":"asterisk-left",{[s.m("feedback")]:r==null?void 0:r.statusIcon,[s.m(`label-${C.value}`)]:C.value}]),b=k(()=>dn(n.inlineMessage)?n.inlineMessage:(r==null?void 0:r.inlineMessage)||!1),w=k(()=>[s.e("error"),{[s.em("error","inline")]:b.value}]),S=k(()=>n.prop?nt(n.prop)?n.prop:n.prop.join("."):""),E=k(()=>!!(n.label||o.label)),$=k(()=>n.for||(c.value.length===1?c.value[0]:void 0)),O=k(()=>!$.value&&E.value),A=!!a,M=k(()=>{const ae=r==null?void 0:r.model;if(!(!ae||!n.prop))return Mc(ae,n.prop).value}),D=k(()=>{const{required:ae}=n,Oe=[];n.rules&&Oe.push(...Ia(n.rules));const we=r==null?void 0:r.rules;if(we&&n.prop){const ge=Mc(we,n.prop).value;ge&&Oe.push(...Ia(ge))}if(ae!==void 0){const ge=Oe.map((q,B)=>[q,B]).filter(([q])=>Object.keys(q).includes("required"));if(ge.length>0)for(const[q,B]of ge)q.required!==ae&&(Oe[B]={...q,required:ae});else Oe.push({required:ae})}return Oe}),U=k(()=>D.value.length>0),j=ae=>D.value.filter(we=>!we.trigger||!ae?!0:Array.isArray(we.trigger)?we.trigger.includes(ae):we.trigger===ae).map(({trigger:we,...ge})=>ge),W=k(()=>D.value.some(ae=>ae.required)),L=k(()=>{var ae;return d.value==="error"&&n.showMessage&&((ae=r==null?void 0:r.showMessage)!=null?ae:!0)}),P=k(()=>`${n.label||""}${(r==null?void 0:r.labelSuffix)||""}`),x=ae=>{f.value=ae},I=ae=>{var Oe,we;const{errors:ge,fields:q}=ae;(!ge||!q)&&console.error(ae),x("error"),p.value=ge?(we=(Oe=ge==null?void 0:ge[0])==null?void 0:Oe.message)!=null?we:`${n.prop} is required`:"",r==null||r.emit("validate",n.prop,!1,p.value)},H=()=>{x("success"),r==null||r.emit("validate",n.prop,!0,"")},G=async ae=>{const Oe=S.value;return new Du({[Oe]:ae}).validate({[Oe]:M.value},{firstFields:!0}).then(()=>(H(),!0)).catch(ge=>(I(ge),Promise.reject(ge)))},J=async(ae,Oe)=>{if(h||!n.prop)return!1;const we=Xe(Oe);if(!U.value)return Oe==null||Oe(!1),!1;const ge=j(ae);return ge.length===0?(Oe==null||Oe(!0),!0):(x("validating"),G(ge).then(()=>(Oe==null||Oe(!0),!0)).catch(q=>{const{fields:B}=q;return Oe==null||Oe(!1,B),we?!1:Promise.reject(B)}))},ee=()=>{x(""),p.value="",h=!1},fe=async()=>{const ae=r==null?void 0:r.model;if(!ae||!n.prop)return;const Oe=Mc(ae,n.prop);h=!0,Oe.value=Fy(v),await We(),ee(),h=!1},Te=ae=>{c.value.includes(ae)||c.value.push(ae)},oe=ae=>{c.value=c.value.filter(Oe=>Oe!==ae)};ve(()=>n.error,ae=>{p.value=ae||"",x(ae?"error":"")},{immediate:!0}),ve(()=>n.validateStatus,ae=>x(ae||""));const ke=Et({...Cn(n),$el:m,size:l,validateState:f,labelId:u,inputIds:c,isGroup:O,hasLabel:E,fieldValue:M,addInputId:Te,removeInputId:oe,resetField:fe,clearValidate:ee,validate:J});return yt(Or,ke),at(()=>{n.prop&&(r==null||r.addField(ke),v=Fy(M.value))}),zt(()=>{r==null||r.removeField(ke)}),t({size:l,validateMessage:p,validateState:f,validate:J,clearValidate:ee,resetField:fe}),(ae,Oe)=>{var we;return T(),V("div",{ref_key:"formItemRef",ref:m,class:N(i(_)),role:i(O)?"group":void 0,"aria-labelledby":i(O)?i(u):void 0},[K(i(LF),{"is-auto-width":i(g).width==="auto","update-all":((we=i(r))==null?void 0:we.labelWidth)==="auto"},{default:X(()=>[i(E)?(T(),re(pt(i($)?"label":"div"),{key:0,id:i(u),for:i($),class:N(i(s).e("label")),style:je(i(g))},{default:X(()=>[ie(ae.$slots,"label",{label:i(P)},()=>[Ge(le(i(P)),1)])]),_:3},8,["id","for","class","style"])):te("v-if",!0)]),_:3},8,["is-auto-width","update-all"]),F("div",{class:N(i(s).e("content")),style:je(i(y))},[ie(ae.$slots,"default"),K(ku,{name:`${i(s).namespace.value}-zoom-in-top`},{default:X(()=>[i(L)?ie(ae.$slots,"error",{key:0,error:p.value},()=>[F("div",{class:N(i(w))},le(p.value),3)]):te("v-if",!0)]),_:3},8,["name"])],6)],10,xF)}}});var HS=Ie(FF,[["__file","form-item.vue"]]);const zS=ut(eF,{FormItem:HS}),BF=tn(HS);let Uo;const VF=` + height:0 !important; + visibility:hidden !important; + ${nC()?"":"overflow:hidden !important;"} + position:absolute !important; + z-index:-1000 !important; + top:0 !important; + right:0 !important; +`,HF=["letter-spacing","line-height","padding-top","padding-bottom","font-family","font-weight","font-size","text-rendering","text-transform","width","text-indent","padding-left","padding-right","border-width","box-sizing"];function zF(e){const t=window.getComputedStyle(e),n=t.getPropertyValue("box-sizing"),o=Number.parseFloat(t.getPropertyValue("padding-bottom"))+Number.parseFloat(t.getPropertyValue("padding-top")),r=Number.parseFloat(t.getPropertyValue("border-bottom-width"))+Number.parseFloat(t.getPropertyValue("border-top-width"));return{contextStyle:HF.map(l=>`${l}:${t.getPropertyValue(l)}`).join(";"),paddingSize:o,borderSize:r,boxSizing:n}}function w0(e,t=1,n){var o;Uo||(Uo=document.createElement("textarea"),document.body.appendChild(Uo));const{paddingSize:r,borderSize:a,boxSizing:l,contextStyle:s}=zF(e);Uo.setAttribute("style",`${s};${VF}`),Uo.value=e.value||e.placeholder||"";let u=Uo.scrollHeight;const c={};l==="border-box"?u=u+a:l==="content-box"&&(u=u-r),Uo.value="";const f=Uo.scrollHeight-r;if(Je(t)){let d=f*t;l==="border-box"&&(d=d+r+a),u=Math.max(d,u),c.minHeight=`${d}px`}if(Je(n)){let d=f*n;l==="border-box"&&(d=d+r+a),u=Math.min(d,u)}return c.height=`${u}px`,(o=Uo.parentNode)==null||o.removeChild(Uo),Uo=void 0,c}const jF=Ne({id:{type:String,default:void 0},size:gn,disabled:Boolean,modelValue:{type:Q([String,Number,Object]),default:""},maxlength:{type:[String,Number]},minlength:{type:[String,Number]},type:{type:String,default:"text"},resize:{type:String,values:["none","both","horizontal","vertical"]},autosize:{type:Q([Boolean,Object]),default:!1},autocomplete:{type:String,default:"off"},formatter:{type:Function},parser:{type:Function},placeholder:{type:String},form:{type:String},readonly:Boolean,clearable:Boolean,showPassword:Boolean,showWordLimit:Boolean,suffixIcon:{type:Dt},prefixIcon:{type:Dt},containerRole:{type:String,default:void 0},label:{type:String,default:void 0},tabindex:{type:[String,Number],default:0},validateEvent:{type:Boolean,default:!0},inputStyle:{type:Q([Object,Array,String]),default:()=>en({})},autofocus:Boolean,rows:{type:Number,default:2},...An(["ariaLabel"])}),WF={[ft]:e=>nt(e),input:e=>nt(e),change:e=>nt(e),focus:e=>e instanceof FocusEvent,blur:e=>e instanceof FocusEvent,clear:()=>!0,mouseleave:e=>e instanceof MouseEvent,mouseenter:e=>e instanceof MouseEvent,keydown:e=>e instanceof Event,compositionstart:e=>e instanceof CompositionEvent,compositionupdate:e=>e instanceof CompositionEvent,compositionend:e=>e instanceof CompositionEvent},KF=["role"],UF=["id","minlength","maxlength","type","disabled","readonly","autocomplete","tabindex","aria-label","placeholder","form","autofocus"],qF=["id","minlength","maxlength","tabindex","disabled","readonly","autocomplete","aria-label","placeholder","form","autofocus","rows"],YF=Y({name:"ElInput",inheritAttrs:!1}),GF=Y({...YF,props:jF,emits:WF,setup(e,{expose:t,emit:n}){const o=e,r=xa(),a=Sn(),l=k(()=>{const he={};return o.containerRole==="combobox"&&(he["aria-haspopup"]=r["aria-haspopup"],he["aria-owns"]=r["aria-owns"],he["aria-expanded"]=r["aria-expanded"]),he}),s=k(()=>[o.type==="textarea"?C.b():h.b(),h.m(m.value),h.is("disabled",v.value),h.is("exceed",fe.value),{[h.b("group")]:a.prepend||a.append,[h.m("prefix")]:a.prefix||o.prefixIcon,[h.m("suffix")]:a.suffix||o.suffixIcon||o.clearable||o.showPassword,[h.bm("suffix","password-clear")]:H.value&&G.value,[h.b("hidden")]:o.type==="hidden"},r.class]),u=k(()=>[h.e("wrapper"),h.is("focus",A.value)]),c=xv({excludeKeys:k(()=>Object.keys(l.value))}),{form:f,formItem:d}=qn(),{inputId:p}=cr(o,{formItemContext:d}),m=hn(),v=to(),h=Se("input"),C=Se("textarea"),g=Ut(),y=Ut(),_=R(!1),b=R(!1),w=R(!1),S=R(),E=Ut(o.inputStyle),$=k(()=>g.value||y.value),{wrapperRef:O,isFocused:A,handleFocus:M,handleBlur:D}=yf($,{afterBlur(){var he;o.validateEvent&&((he=d==null?void 0:d.validate)==null||he.call(d,"blur").catch(He=>void 0))}}),U=k(()=>{var he;return(he=f==null?void 0:f.statusIcon)!=null?he:!1}),j=k(()=>(d==null?void 0:d.validateState)||""),W=k(()=>j.value&&Rv[j.value]),L=k(()=>w.value?n3:E4),P=k(()=>[r.style]),x=k(()=>[o.inputStyle,E.value,{resize:o.resize}]),I=k(()=>Tn(o.modelValue)?"":String(o.modelValue)),H=k(()=>o.clearable&&!v.value&&!o.readonly&&!!I.value&&(A.value||_.value)),G=k(()=>o.showPassword&&!v.value&&!o.readonly&&!!I.value&&(!!I.value||A.value)),J=k(()=>o.showWordLimit&&!!o.maxlength&&(o.type==="text"||o.type==="textarea")&&!v.value&&!o.readonly&&!o.showPassword),ee=k(()=>I.value.length),fe=k(()=>!!J.value&&ee.value>Number(o.maxlength)),Te=k(()=>!!a.suffix||!!o.suffixIcon||H.value||o.showPassword||J.value||!!j.value&&U.value),[oe,ke]=y8(g);Qt(y,he=>{if(we(),!J.value||o.resize!=="both")return;const He=he[0],{width:et}=He.contentRect;S.value={right:`calc(100% - ${et+15+6}px)`}});const ae=()=>{const{type:he,autosize:He}=o;if(!(!Ct||he!=="textarea"||!y.value))if(He){const et=dt(He)?He.minRows:void 0,rt=dt(He)?He.maxRows:void 0,wt=w0(y.value,et,rt);E.value={overflowY:"hidden",...wt},We(()=>{y.value.offsetHeight,E.value=wt})}else E.value={minHeight:w0(y.value).minHeight}},we=(he=>{let He=!1;return()=>{var et;if(He||!o.autosize)return;((et=y.value)==null?void 0:et.offsetParent)===null||(he(),He=!0)}})(ae),ge=()=>{const he=$.value,He=o.formatter?o.formatter(I.value):I.value;!he||he.value===He||(he.value=He)},q=async he=>{oe();let{value:He}=he.target;if(o.formatter&&(He=o.parser?o.parser(He):He),!b.value){if(He===I.value){ge();return}n(ft,He),n("input",He),await We(),ge(),ke()}},B=he=>{n("change",he.target.value)},z=he=>{n("compositionstart",he),b.value=!0},Z=he=>{var He;n("compositionupdate",he);const et=(He=he.target)==null?void 0:He.value,rt=et[et.length-1]||"";b.value=!Lv(rt)},ue=he=>{n("compositionend",he),b.value&&(b.value=!1,q(he))},se=()=>{w.value=!w.value,me()},me=async()=>{var he;await We(),(he=$.value)==null||he.focus()},_e=()=>{var he;return(he=$.value)==null?void 0:he.blur()},$e=he=>{_.value=!1,n("mouseleave",he)},Ce=he=>{_.value=!0,n("mouseenter",he)},ce=he=>{n("keydown",he)},de=()=>{var he;(he=$.value)==null||he.select()},xe=()=>{n(ft,""),n("change",""),n("clear"),n("input","")};return ve(()=>o.modelValue,()=>{var he;We(()=>ae()),o.validateEvent&&((he=d==null?void 0:d.validate)==null||he.call(d,"change").catch(He=>void 0))}),ve(I,()=>ge()),ve(()=>o.type,async()=>{await We(),ge(),ae()}),at(()=>{!o.formatter&&o.parser,ge(),We(ae)}),wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-input",ref:"https://element-plus.org/en-US/component/input.html"},k(()=>!!o.label)),t({input:g,textarea:y,ref:$,textareaStyle:x,autosize:Lt(o,"autosize"),focus:me,blur:_e,select:de,clear:xe,resizeTextarea:ae}),(he,He)=>(T(),V("div",mt(i(l),{class:[i(s),{[i(h).bm("group","append")]:he.$slots.append,[i(h).bm("group","prepend")]:he.$slots.prepend}],style:i(P),role:he.containerRole,onMouseenter:Ce,onMouseleave:$e}),[te(" input "),he.type!=="textarea"?(T(),V(Ve,{key:0},[te(" prepend slot "),he.$slots.prepend?(T(),V("div",{key:0,class:N(i(h).be("group","prepend"))},[ie(he.$slots,"prepend")],2)):te("v-if",!0),F("div",{ref_key:"wrapperRef",ref:O,class:N(i(u))},[te(" prefix slot "),he.$slots.prefix||he.prefixIcon?(T(),V("span",{key:0,class:N(i(h).e("prefix"))},[F("span",{class:N(i(h).e("prefix-inner"))},[ie(he.$slots,"prefix"),he.prefixIcon?(T(),re(i(ze),{key:0,class:N(i(h).e("icon"))},{default:X(()=>[(T(),re(pt(he.prefixIcon)))]),_:1},8,["class"])):te("v-if",!0)],2)],2)):te("v-if",!0),F("input",mt({id:i(p),ref_key:"input",ref:g,class:i(h).e("inner")},i(c),{minlength:he.minlength,maxlength:he.maxlength,type:he.showPassword?w.value?"text":"password":he.type,disabled:i(v),readonly:he.readonly,autocomplete:he.autocomplete,tabindex:he.tabindex,"aria-label":he.label||he.ariaLabel,placeholder:he.placeholder,style:he.inputStyle,form:he.form,autofocus:he.autofocus,onCompositionstart:z,onCompositionupdate:Z,onCompositionend:ue,onInput:q,onFocus:He[0]||(He[0]=(...et)=>i(M)&&i(M)(...et)),onBlur:He[1]||(He[1]=(...et)=>i(D)&&i(D)(...et)),onChange:B,onKeydown:ce}),null,16,UF),te(" suffix slot "),i(Te)?(T(),V("span",{key:1,class:N(i(h).e("suffix"))},[F("span",{class:N(i(h).e("suffix-inner"))},[!i(H)||!i(G)||!i(J)?(T(),V(Ve,{key:0},[ie(he.$slots,"suffix"),he.suffixIcon?(T(),re(i(ze),{key:0,class:N(i(h).e("icon"))},{default:X(()=>[(T(),re(pt(he.suffixIcon)))]),_:1},8,["class"])):te("v-if",!0)],64)):te("v-if",!0),i(H)?(T(),re(i(ze),{key:1,class:N([i(h).e("icon"),i(h).e("clear")]),onMousedown:Qe(i(Bt),["prevent"]),onClick:xe},{default:X(()=>[K(i(Fa))]),_:1},8,["class","onMousedown"])):te("v-if",!0),i(G)?(T(),re(i(ze),{key:2,class:N([i(h).e("icon"),i(h).e("password")]),onClick:se},{default:X(()=>[(T(),re(pt(i(L))))]),_:1},8,["class"])):te("v-if",!0),i(J)?(T(),V("span",{key:3,class:N(i(h).e("count"))},[F("span",{class:N(i(h).e("count-inner"))},le(i(ee))+" / "+le(he.maxlength),3)],2)):te("v-if",!0),i(j)&&i(W)&&i(U)?(T(),re(i(ze),{key:4,class:N([i(h).e("icon"),i(h).e("validateIcon"),i(h).is("loading",i(j)==="validating")])},{default:X(()=>[(T(),re(pt(i(W))))]),_:1},8,["class"])):te("v-if",!0)],2)],2)):te("v-if",!0)],2),te(" append slot "),he.$slots.append?(T(),V("div",{key:1,class:N(i(h).be("group","append"))},[ie(he.$slots,"append")],2)):te("v-if",!0)],64)):(T(),V(Ve,{key:1},[te(" textarea "),F("textarea",mt({id:i(p),ref_key:"textarea",ref:y,class:[i(C).e("inner"),i(h).is("focus",i(A))]},i(c),{minlength:he.minlength,maxlength:he.maxlength,tabindex:he.tabindex,disabled:i(v),readonly:he.readonly,autocomplete:he.autocomplete,style:i(x),"aria-label":he.label||he.ariaLabel,placeholder:he.placeholder,form:he.form,autofocus:he.autofocus,rows:he.rows,onCompositionstart:z,onCompositionupdate:Z,onCompositionend:ue,onInput:q,onFocus:He[2]||(He[2]=(...et)=>i(M)&&i(M)(...et)),onBlur:He[3]||(He[3]=(...et)=>i(D)&&i(D)(...et)),onChange:B,onKeydown:ce}),null,16,qF),i(J)?(T(),V("span",{key:0,style:je(S.value),class:N(i(h).e("count"))},le(i(ee))+" / "+le(he.maxlength),7)):te("v-if",!0)],64))],16,KF))}});var XF=Ie(GF,[["__file","input.vue"]]);const zn=ut(XF),Ul=4,jS={vertical:{offset:"offsetHeight",scroll:"scrollTop",scrollSize:"scrollHeight",size:"height",key:"vertical",axis:"Y",client:"clientY",direction:"top"},horizontal:{offset:"offsetWidth",scroll:"scrollLeft",scrollSize:"scrollWidth",size:"width",key:"horizontal",axis:"X",client:"clientX",direction:"left"}},JF=({move:e,size:t,bar:n})=>({[n.size]:t,transform:`translate${n.axis}(${e}%)`}),og=Symbol("scrollbarContextKey"),ZF=Ne({vertical:Boolean,size:String,move:Number,ratio:{type:Number,required:!0},always:Boolean}),QF="Thumb",e6=Y({__name:"thumb",props:ZF,setup(e){const t=e,n=De(og),o=Se("scrollbar");n||vn(QF,"can not inject scrollbar context");const r=R(),a=R(),l=R({}),s=R(!1);let u=!1,c=!1,f=Ct?document.onselectstart:null;const d=k(()=>jS[t.vertical?"vertical":"horizontal"]),p=k(()=>JF({size:t.size,move:t.move,bar:d.value})),m=k(()=>r.value[d.value.offset]**2/n.wrapElement[d.value.scrollSize]/t.ratio/a.value[d.value.offset]),v=S=>{var E;if(S.stopPropagation(),S.ctrlKey||[1,2].includes(S.button))return;(E=window.getSelection())==null||E.removeAllRanges(),C(S);const $=S.currentTarget;$&&(l.value[d.value.axis]=$[d.value.offset]-(S[d.value.client]-$.getBoundingClientRect()[d.value.direction]))},h=S=>{if(!a.value||!r.value||!n.wrapElement)return;const E=Math.abs(S.target.getBoundingClientRect()[d.value.direction]-S[d.value.client]),$=a.value[d.value.offset]/2,O=(E-$)*100*m.value/r.value[d.value.offset];n.wrapElement[d.value.scroll]=O*n.wrapElement[d.value.scrollSize]/100},C=S=>{S.stopImmediatePropagation(),u=!0,document.addEventListener("mousemove",g),document.addEventListener("mouseup",y),f=document.onselectstart,document.onselectstart=()=>!1},g=S=>{if(!r.value||!a.value||u===!1)return;const E=l.value[d.value.axis];if(!E)return;const $=(r.value.getBoundingClientRect()[d.value.direction]-S[d.value.client])*-1,O=a.value[d.value.offset]-E,A=($-O)*100*m.value/r.value[d.value.offset];n.wrapElement[d.value.scroll]=A*n.wrapElement[d.value.scrollSize]/100},y=()=>{u=!1,l.value[d.value.axis]=0,document.removeEventListener("mousemove",g),document.removeEventListener("mouseup",y),w(),c&&(s.value=!1)},_=()=>{c=!1,s.value=!!t.size},b=()=>{c=!0,s.value=u};zt(()=>{w(),document.removeEventListener("mouseup",y)});const w=()=>{document.onselectstart!==f&&(document.onselectstart=f)};return qt(Lt(n,"scrollbarElement"),"mousemove",_),qt(Lt(n,"scrollbarElement"),"mouseleave",b),(S,E)=>(T(),re(fn,{name:i(o).b("fade"),persisted:""},{default:X(()=>[tt(F("div",{ref_key:"instance",ref:r,class:N([i(o).e("bar"),i(o).is(i(d).key)]),onMousedown:h},[F("div",{ref_key:"thumb",ref:a,class:N(i(o).e("thumb")),style:je(i(p)),onMousedown:v},null,38)],34),[[kt,S.always||s.value]])]),_:1},8,["name"]))}});var _0=Ie(e6,[["__file","thumb.vue"]]);const t6=Ne({always:{type:Boolean,default:!0},minSize:{type:Number,required:!0}}),n6=Y({__name:"bar",props:t6,setup(e,{expose:t}){const n=e,o=De(og),r=R(0),a=R(0),l=R(""),s=R(""),u=R(1),c=R(1);return t({handleScroll:p=>{if(p){const m=p.offsetHeight-Ul,v=p.offsetWidth-Ul;a.value=p.scrollTop*100/m*u.value,r.value=p.scrollLeft*100/v*c.value}},update:()=>{const p=o==null?void 0:o.wrapElement;if(!p)return;const m=p.offsetHeight-Ul,v=p.offsetWidth-Ul,h=m**2/p.scrollHeight,C=v**2/p.scrollWidth,g=Math.max(h,n.minSize),y=Math.max(C,n.minSize);u.value=h/(m-h)/(g/(m-g)),c.value=C/(v-C)/(y/(v-y)),s.value=g+Ul(T(),V(Ve,null,[K(_0,{move:r.value,ratio:c.value,size:l.value,always:p.always},null,8,["move","ratio","size","always"]),K(_0,{move:a.value,ratio:u.value,size:s.value,vertical:"",always:p.always},null,8,["move","ratio","size","always"])],64))}});var o6=Ie(n6,[["__file","bar.vue"]]);const r6=Ne({height:{type:[String,Number],default:""},maxHeight:{type:[String,Number],default:""},native:{type:Boolean,default:!1},wrapStyle:{type:Q([String,Object,Array]),default:""},wrapClass:{type:[String,Array],default:""},viewClass:{type:[String,Array],default:""},viewStyle:{type:[String,Array,Object],default:""},noresize:Boolean,tag:{type:String,default:"div"},always:Boolean,minSize:{type:Number,default:20},id:String,role:String,...An(["ariaLabel","ariaOrientation"])}),a6={scroll:({scrollTop:e,scrollLeft:t})=>[e,t].every(Je)},l6="ElScrollbar",s6=Y({name:l6}),i6=Y({...s6,props:r6,emits:a6,setup(e,{expose:t,emit:n}){const o=e,r=Se("scrollbar");let a,l;const s=R(),u=R(),c=R(),f=R(),d=k(()=>{const _={};return o.height&&(_.height=rn(o.height)),o.maxHeight&&(_.maxHeight=rn(o.maxHeight)),[o.wrapStyle,_]}),p=k(()=>[o.wrapClass,r.e("wrap"),{[r.em("wrap","hidden-default")]:!o.native}]),m=k(()=>[r.e("view"),o.viewClass]),v=()=>{var _;u.value&&((_=f.value)==null||_.handleScroll(u.value),n("scroll",{scrollTop:u.value.scrollTop,scrollLeft:u.value.scrollLeft}))};function h(_,b){dt(_)?u.value.scrollTo(_):Je(_)&&Je(b)&&u.value.scrollTo(_,b)}const C=_=>{Je(_)&&(u.value.scrollTop=_)},g=_=>{Je(_)&&(u.value.scrollLeft=_)},y=()=>{var _;(_=f.value)==null||_.update()};return ve(()=>o.noresize,_=>{_?(a==null||a(),l==null||l()):({stop:a}=Qt(c,y),l=qt("resize",y))},{immediate:!0}),ve(()=>[o.maxHeight,o.height],()=>{o.native||We(()=>{var _;y(),u.value&&((_=f.value)==null||_.handleScroll(u.value))})}),yt(og,Et({scrollbarElement:s,wrapElement:u})),at(()=>{o.native||We(()=>{y()})}),ar(()=>y()),t({wrapRef:u,update:y,scrollTo:h,setScrollTop:C,setScrollLeft:g,handleScroll:v}),(_,b)=>(T(),V("div",{ref_key:"scrollbarRef",ref:s,class:N(i(r).b())},[F("div",{ref_key:"wrapRef",ref:u,class:N(i(p)),style:je(i(d)),onScroll:v},[(T(),re(pt(_.tag),{id:_.id,ref_key:"resizeRef",ref:c,class:N(i(m)),style:je(_.viewStyle),role:_.role,"aria-label":_.ariaLabel,"aria-orientation":_.ariaOrientation},{default:X(()=>[ie(_.$slots,"default")]),_:3},8,["id","class","style","role","aria-label","aria-orientation"]))],38),_.native?te("v-if",!0):(T(),re(o6,{key:0,ref_key:"barRef",ref:f,always:_.always,"min-size":_.minSize},null,8,["always","min-size"]))],2))}});var u6=Ie(i6,[["__file","scrollbar.vue"]]);const ea=ut(u6),rg=Symbol("popper"),WS=Symbol("popperContent"),c6=["dialog","grid","group","listbox","menu","navigation","tooltip","tree"],KS=Ne({role:{type:String,values:c6,default:"tooltip"}}),d6=Y({name:"ElPopper",inheritAttrs:!1}),f6=Y({...d6,props:KS,setup(e,{expose:t}){const n=e,o=R(),r=R(),a=R(),l=R(),s=k(()=>n.role),u={triggerRef:o,popperInstanceRef:r,contentRef:a,referenceRef:l,role:s};return t(u),yt(rg,u),(c,f)=>ie(c.$slots,"default")}});var p6=Ie(f6,[["__file","popper.vue"]]);const US=Ne({arrowOffset:{type:Number,default:5}}),h6=Y({name:"ElPopperArrow",inheritAttrs:!1}),m6=Y({...h6,props:US,setup(e,{expose:t}){const n=e,o=Se("popper"),{arrowOffset:r,arrowRef:a,arrowStyle:l}=De(WS,void 0);return ve(()=>n.arrowOffset,s=>{r.value=s}),zt(()=>{a.value=void 0}),t({arrowRef:a}),(s,u)=>(T(),V("span",{ref_key:"arrowRef",ref:a,class:N(i(o).e("arrow")),style:je(i(l)),"data-popper-arrow":""},null,6))}});var v6=Ie(m6,[["__file","arrow.vue"]]);const g6="ElOnlyChild",qS=Y({name:g6,setup(e,{slots:t,attrs:n}){var o;const r=De(wS),a=LD((o=r==null?void 0:r.setForwardRef)!=null?o:Bt);return()=>{var l;const s=(l=t.default)==null?void 0:l.call(t,n);if(!s||s.length>1)return null;const u=YS(s);return u?tt(Qo(u,n),[[a]]):null}}});function YS(e){if(!e)return null;const t=e;for(const n of t){if(dt(n))switch(n.type){case En:continue;case Ur:case"svg":return C0(n);case Ve:return YS(n.children);default:return n}return C0(n)}return null}function C0(e){const t=Se("only-child");return K("span",{class:t.e("content")},[e])}const GS=Ne({virtualRef:{type:Q(Object)},virtualTriggering:Boolean,onMouseenter:{type:Q(Function)},onMouseleave:{type:Q(Function)},onClick:{type:Q(Function)},onKeydown:{type:Q(Function)},onFocus:{type:Q(Function)},onBlur:{type:Q(Function)},onContextmenu:{type:Q(Function)},id:String,open:Boolean}),b6=Y({name:"ElPopperTrigger",inheritAttrs:!1}),y6=Y({...b6,props:GS,setup(e,{expose:t}){const n=e,{role:o,triggerRef:r}=De(rg,void 0);RD(r);const a=k(()=>s.value?n.id:void 0),l=k(()=>{if(o&&o.value==="tooltip")return n.open&&n.id?n.id:void 0}),s=k(()=>{if(o&&o.value!=="tooltip")return o.value}),u=k(()=>s.value?`${n.open}`:void 0);let c;return at(()=>{ve(()=>n.virtualRef,f=>{f&&(r.value=lo(f))},{immediate:!0}),ve(r,(f,d)=>{c==null||c(),c=void 0,Fo(f)&&(["onMouseenter","onMouseleave","onClick","onKeydown","onFocus","onBlur","onContextmenu"].forEach(p=>{var m;const v=n[p];v&&(f.addEventListener(p.slice(2).toLowerCase(),v),(m=d==null?void 0:d.removeEventListener)==null||m.call(d,p.slice(2).toLowerCase(),v))}),c=ve([a,l,s,u],p=>{["aria-controls","aria-describedby","aria-haspopup","aria-expanded"].forEach((m,v)=>{Tn(p[v])?f.removeAttribute(m):f.setAttribute(m,p[v])})},{immediate:!0})),Fo(d)&&["aria-controls","aria-describedby","aria-haspopup","aria-expanded"].forEach(p=>d.removeAttribute(p))},{immediate:!0})}),zt(()=>{c==null||c(),c=void 0}),t({triggerRef:r}),(f,d)=>f.virtualTriggering?te("v-if",!0):(T(),re(i(qS),mt({key:0},f.$attrs,{"aria-controls":i(a),"aria-describedby":i(l),"aria-expanded":i(u),"aria-haspopup":i(s)}),{default:X(()=>[ie(f.$slots,"default")]),_:3},16,["aria-controls","aria-describedby","aria-expanded","aria-haspopup"]))}});var w6=Ie(y6,[["__file","trigger.vue"]]);const pp="focus-trap.focus-after-trapped",hp="focus-trap.focus-after-released",_6="focus-trap.focusout-prevented",S0={cancelable:!0,bubbles:!1},C6={cancelable:!0,bubbles:!1},k0="focusAfterTrapped",E0="focusAfterReleased",ag=Symbol("elFocusTrap"),lg=R(),Sf=R(0),sg=R(0);let hc=0;const XS=e=>{const t=[],n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,{acceptNode:o=>{const r=o.tagName==="INPUT"&&o.type==="hidden";return o.disabled||o.hidden||r?NodeFilter.FILTER_SKIP:o.tabIndex>=0||o===document.activeElement?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});for(;n.nextNode();)t.push(n.currentNode);return t},T0=(e,t)=>{for(const n of e)if(!S6(n,t))return n},S6=(e,t)=>{if(getComputedStyle(e).visibility==="hidden")return!0;for(;e;){if(t&&e===t)return!1;if(getComputedStyle(e).display==="none")return!0;e=e.parentElement}return!1},k6=e=>{const t=XS(e),n=T0(t,e),o=T0(t.reverse(),e);return[n,o]},E6=e=>e instanceof HTMLInputElement&&"select"in e,pa=(e,t)=>{if(e&&e.focus){const n=document.activeElement;e.focus({preventScroll:!0}),sg.value=window.performance.now(),e!==n&&E6(e)&&t&&e.select()}};function $0(e,t){const n=[...e],o=e.indexOf(t);return o!==-1&&n.splice(o,1),n}const T6=()=>{let e=[];return{push:o=>{const r=e[0];r&&o!==r&&r.pause(),e=$0(e,o),e.unshift(o)},remove:o=>{var r,a;e=$0(e,o),(a=(r=e[0])==null?void 0:r.resume)==null||a.call(r)}}},$6=(e,t=!1)=>{const n=document.activeElement;for(const o of e)if(pa(o,t),document.activeElement!==n)return},O0=T6(),O6=()=>Sf.value>sg.value,mc=()=>{lg.value="pointer",Sf.value=window.performance.now()},N0=()=>{lg.value="keyboard",Sf.value=window.performance.now()},N6=()=>(at(()=>{hc===0&&(document.addEventListener("mousedown",mc),document.addEventListener("touchstart",mc),document.addEventListener("keydown",N0)),hc++}),zt(()=>{hc--,hc<=0&&(document.removeEventListener("mousedown",mc),document.removeEventListener("touchstart",mc),document.removeEventListener("keydown",N0))}),{focusReason:lg,lastUserFocusTimestamp:Sf,lastAutomatedFocusTimestamp:sg}),vc=e=>new CustomEvent(_6,{...C6,detail:e}),I6=Y({name:"ElFocusTrap",inheritAttrs:!1,props:{loop:Boolean,trapped:Boolean,focusTrapEl:Object,focusStartEl:{type:[Object,String],default:"first"}},emits:[k0,E0,"focusin","focusout","focusout-prevented","release-requested"],setup(e,{emit:t}){const n=R();let o,r;const{focusReason:a}=N6();ND(v=>{e.trapped&&!l.paused&&t("release-requested",v)});const l={paused:!1,pause(){this.paused=!0},resume(){this.paused=!1}},s=v=>{if(!e.loop&&!e.trapped||l.paused)return;const{key:h,altKey:C,ctrlKey:g,metaKey:y,currentTarget:_,shiftKey:b}=v,{loop:w}=e,S=h===Ue.tab&&!C&&!g&&!y,E=document.activeElement;if(S&&E){const $=_,[O,A]=k6($);if(O&&A){if(!b&&E===A){const D=vc({focusReason:a.value});t("focusout-prevented",D),D.defaultPrevented||(v.preventDefault(),w&&pa(O,!0))}else if(b&&[O,$].includes(E)){const D=vc({focusReason:a.value});t("focusout-prevented",D),D.defaultPrevented||(v.preventDefault(),w&&pa(A,!0))}}else if(E===$){const D=vc({focusReason:a.value});t("focusout-prevented",D),D.defaultPrevented||v.preventDefault()}}};yt(ag,{focusTrapRef:n,onKeydown:s}),ve(()=>e.focusTrapEl,v=>{v&&(n.value=v)},{immediate:!0}),ve([n],([v],[h])=>{v&&(v.addEventListener("keydown",s),v.addEventListener("focusin",f),v.addEventListener("focusout",d)),h&&(h.removeEventListener("keydown",s),h.removeEventListener("focusin",f),h.removeEventListener("focusout",d))});const u=v=>{t(k0,v)},c=v=>t(E0,v),f=v=>{const h=i(n);if(!h)return;const C=v.target,g=v.relatedTarget,y=C&&h.contains(C);e.trapped||g&&h.contains(g)||(o=g),y&&t("focusin",v),!l.paused&&e.trapped&&(y?r=C:pa(r,!0))},d=v=>{const h=i(n);if(!(l.paused||!h))if(e.trapped){const C=v.relatedTarget;!Tn(C)&&!h.contains(C)&&setTimeout(()=>{if(!l.paused&&e.trapped){const g=vc({focusReason:a.value});t("focusout-prevented",g),g.defaultPrevented||pa(r,!0)}},0)}else{const C=v.target;C&&h.contains(C)||t("focusout",v)}};async function p(){await We();const v=i(n);if(v){O0.push(l);const h=v.contains(document.activeElement)?o:document.activeElement;if(o=h,!v.contains(h)){const g=new Event(pp,S0);v.addEventListener(pp,u),v.dispatchEvent(g),g.defaultPrevented||We(()=>{let y=e.focusStartEl;nt(y)||(pa(y),document.activeElement!==y&&(y="first")),y==="first"&&$6(XS(v),!0),(document.activeElement===h||y==="container")&&pa(v)})}}}function m(){const v=i(n);if(v){v.removeEventListener(pp,u);const h=new CustomEvent(hp,{...S0,detail:{focusReason:a.value}});v.addEventListener(hp,c),v.dispatchEvent(h),!h.defaultPrevented&&(a.value=="keyboard"||!O6()||v.contains(document.activeElement))&&pa(o??document.body),v.removeEventListener(hp,c),O0.remove(l)}}return at(()=>{e.trapped&&p(),ve(()=>e.trapped,v=>{v?p():m()})}),zt(()=>{e.trapped&&m()}),{onKeydown:s}}});function M6(e,t,n,o,r,a){return ie(e.$slots,"default",{handleKeydown:e.onKeydown})}var Fu=Ie(I6,[["render",M6],["__file","focus-trap.vue"]]);const A6=["fixed","absolute"],P6=Ne({boundariesPadding:{type:Number,default:0},fallbackPlacements:{type:Q(Array),default:void 0},gpuAcceleration:{type:Boolean,default:!0},offset:{type:Number,default:12},placement:{type:String,values:Dl,default:"bottom"},popperOptions:{type:Q(Object),default:()=>({})},strategy:{type:String,values:A6,default:"absolute"}}),JS=Ne({...P6,id:String,style:{type:Q([String,Array,Object])},className:{type:Q([String,Array,Object])},effect:{type:Q(String),default:"dark"},visible:Boolean,enterable:{type:Boolean,default:!0},pure:Boolean,focusOnShow:{type:Boolean,default:!1},trapping:{type:Boolean,default:!1},popperClass:{type:Q([String,Array,Object])},popperStyle:{type:Q([String,Array,Object])},referenceEl:{type:Q(Object)},triggerTargetEl:{type:Q(Object)},stopPopperMouseEvent:{type:Boolean,default:!0},virtualTriggering:Boolean,zIndex:Number,...An(["ariaLabel"])}),R6={mouseenter:e=>e instanceof MouseEvent,mouseleave:e=>e instanceof MouseEvent,focus:()=>!0,blur:()=>!0,close:()=>!0},L6=(e,t=[])=>{const{placement:n,strategy:o,popperOptions:r}=e,a={placement:n,strategy:o,...r,modifiers:[...D6(e),...t]};return F6(a,r==null?void 0:r.modifiers),a},x6=e=>{if(Ct)return lo(e)};function D6(e){const{offset:t,gpuAcceleration:n,fallbackPlacements:o}=e;return[{name:"offset",options:{offset:[0,t??12]}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5,fallbackPlacements:o}},{name:"computeStyles",options:{gpuAcceleration:n}}]}function F6(e,t){t&&(e.modifiers=[...e.modifiers,...t??[]])}const B6=0,V6=e=>{const{popperInstanceRef:t,contentRef:n,triggerRef:o,role:r}=De(rg,void 0),a=R(),l=R(),s=k(()=>({name:"eventListeners",enabled:!!e.visible})),u=k(()=>{var g;const y=i(a),_=(g=i(l))!=null?g:B6;return{name:"arrow",enabled:!HC(y),options:{element:y,padding:_}}}),c=k(()=>({onFirstUpdate:()=>{v()},...L6(e,[i(u),i(s)])})),f=k(()=>x6(e.referenceEl)||i(o)),{attributes:d,state:p,styles:m,update:v,forceUpdate:h,instanceRef:C}=ED(f,n,c);return ve(C,g=>t.value=g),at(()=>{ve(()=>{var g;return(g=i(f))==null?void 0:g.getBoundingClientRect()},()=>{v()})}),{attributes:d,arrowRef:a,contentRef:n,instanceRef:C,state:p,styles:m,role:r,forceUpdate:h,update:v}},H6=(e,{attributes:t,styles:n,role:o})=>{const{nextZIndex:r}=Zs(),a=Se("popper"),l=k(()=>i(t).popper),s=R(Je(e.zIndex)?e.zIndex:r()),u=k(()=>[a.b(),a.is("pure",e.pure),a.is(e.effect),e.popperClass]),c=k(()=>[{zIndex:i(s)},i(n).popper,e.popperStyle||{}]),f=k(()=>o.value==="dialog"?"false":void 0),d=k(()=>i(n).arrow||{});return{ariaModal:f,arrowStyle:d,contentAttrs:l,contentClass:u,contentStyle:c,contentZIndex:s,updateZIndex:()=>{s.value=Je(e.zIndex)?e.zIndex:r()}}},z6=(e,t)=>{const n=R(!1),o=R();return{focusStartRef:o,trapped:n,onFocusAfterReleased:c=>{var f;((f=c.detail)==null?void 0:f.focusReason)!=="pointer"&&(o.value="first",t("blur"))},onFocusAfterTrapped:()=>{t("focus")},onFocusInTrap:c=>{e.visible&&!n.value&&(c.target&&(o.value=c.target),n.value=!0)},onFocusoutPrevented:c=>{e.trapping||(c.detail.focusReason==="pointer"&&c.preventDefault(),n.value=!1)},onReleaseRequested:()=>{n.value=!1,t("close")}}},j6=Y({name:"ElPopperContent"}),W6=Y({...j6,props:JS,emits:R6,setup(e,{expose:t,emit:n}){const o=e,{focusStartRef:r,trapped:a,onFocusAfterReleased:l,onFocusAfterTrapped:s,onFocusInTrap:u,onFocusoutPrevented:c,onReleaseRequested:f}=z6(o,n),{attributes:d,arrowRef:p,contentRef:m,styles:v,instanceRef:h,role:C,update:g}=V6(o),{ariaModal:y,arrowStyle:_,contentAttrs:b,contentClass:w,contentStyle:S,updateZIndex:E}=H6(o,{styles:v,attributes:d,role:C}),$=De(Or,void 0),O=R();yt(WS,{arrowStyle:_,arrowRef:p,arrowOffset:O}),$&&yt(Or,{...$,addInputId:Bt,removeInputId:Bt});let A;const M=(U=!0)=>{g(),U&&E()},D=()=>{M(!1),o.visible&&o.focusOnShow?a.value=!0:o.visible===!1&&(a.value=!1)};return at(()=>{ve(()=>o.triggerTargetEl,(U,j)=>{A==null||A(),A=void 0;const W=i(U||m.value),L=i(j||m.value);Fo(W)&&(A=ve([C,()=>o.ariaLabel,y,()=>o.id],P=>{["role","aria-label","aria-modal","id"].forEach((x,I)=>{Tn(P[I])?W.removeAttribute(x):W.setAttribute(x,P[I])})},{immediate:!0})),L!==W&&Fo(L)&&["role","aria-label","aria-modal","id"].forEach(P=>{L.removeAttribute(P)})},{immediate:!0}),ve(()=>o.visible,D,{immediate:!0})}),zt(()=>{A==null||A(),A=void 0}),t({popperContentRef:m,popperInstanceRef:h,updatePopper:M,contentStyle:S}),(U,j)=>(T(),V("div",mt({ref_key:"contentRef",ref:m},i(b),{style:i(S),class:i(w),tabindex:"-1",onMouseenter:j[0]||(j[0]=W=>U.$emit("mouseenter",W)),onMouseleave:j[1]||(j[1]=W=>U.$emit("mouseleave",W))}),[K(i(Fu),{trapped:i(a),"trap-on-focus-in":!0,"focus-trap-el":i(m),"focus-start-el":i(r),onFocusAfterTrapped:i(s),onFocusAfterReleased:i(l),onFocusin:i(u),onFocusoutPrevented:i(c),onReleaseRequested:i(f)},{default:X(()=>[ie(U.$slots,"default")]),_:3},8,["trapped","focus-trap-el","focus-start-el","onFocusAfterTrapped","onFocusAfterReleased","onFocusin","onFocusoutPrevented","onReleaseRequested"])],16))}});var K6=Ie(W6,[["__file","content.vue"]]);const ZS=ut(p6),kf=Symbol("elTooltip"),kn=Ne({...AD,...JS,appendTo:{type:Q([String,Object])},content:{type:String,default:""},rawContent:Boolean,persistent:Boolean,visible:{type:Q(Boolean),default:null},transition:String,teleported:{type:Boolean,default:!0},disabled:Boolean,...An(["ariaLabel"])}),lu=Ne({...GS,disabled:Boolean,trigger:{type:Q([String,Array]),default:"hover"},triggerKeys:{type:Q(Array),default:()=>[Ue.enter,Ue.space]}}),{useModelToggleProps:U6,useModelToggleEmits:q6,useModelToggle:Y6}=lS("visible"),G6=Ne({...KS,...U6,...kn,...lu,...US,showArrow:{type:Boolean,default:!0}}),X6=[...q6,"before-show","before-hide","show","hide","open","close"],J6=(e,t)=>Pe(e)?e.includes(t):e===t,ql=(e,t,n)=>o=>{J6(i(e),t)&&n(o)},Z6=Y({name:"ElTooltipTrigger"}),Q6=Y({...Z6,props:lu,setup(e,{expose:t}){const n=e,o=Se("tooltip"),{controlled:r,id:a,open:l,onOpen:s,onClose:u,onToggle:c}=De(kf,void 0),f=R(null),d=()=>{if(i(r)||n.disabled)return!0},p=Lt(n,"trigger"),m=on(d,ql(p,"hover",s)),v=on(d,ql(p,"hover",u)),h=on(d,ql(p,"click",b=>{b.button===0&&c(b)})),C=on(d,ql(p,"focus",s)),g=on(d,ql(p,"focus",u)),y=on(d,ql(p,"contextmenu",b=>{b.preventDefault(),c(b)})),_=on(d,b=>{const{code:w}=b;n.triggerKeys.includes(w)&&(b.preventDefault(),c(b))});return t({triggerRef:f}),(b,w)=>(T(),re(i(w6),{id:i(a),"virtual-ref":b.virtualRef,open:i(l),"virtual-triggering":b.virtualTriggering,class:N(i(o).e("trigger")),onBlur:i(g),onClick:i(h),onContextmenu:i(y),onFocus:i(C),onMouseenter:i(m),onMouseleave:i(v),onKeydown:i(_)},{default:X(()=>[ie(b.$slots,"default")]),_:3},8,["id","virtual-ref","open","virtual-triggering","class","onBlur","onClick","onContextmenu","onFocus","onMouseenter","onMouseleave","onKeydown"]))}});var eB=Ie(Q6,[["__file","trigger.vue"]]);const tB=Y({name:"ElTooltipContent",inheritAttrs:!1}),nB=Y({...tB,props:kn,setup(e,{expose:t}){const n=e,{selector:o}=yS(),r=Se("tooltip"),a=R(null),l=R(!1),{controlled:s,id:u,open:c,trigger:f,onClose:d,onOpen:p,onShow:m,onHide:v,onBeforeShow:h,onBeforeHide:C}=De(kf,void 0),g=k(()=>n.transition||`${r.namespace.value}-fade-in-linear`),y=k(()=>n.persistent);zt(()=>{l.value=!0});const _=k(()=>i(y)?!0:i(c)),b=k(()=>n.disabled?!1:i(c)),w=k(()=>n.appendTo||o.value),S=k(()=>{var P;return(P=n.style)!=null?P:{}}),E=k(()=>!i(c)),$=()=>{v()},O=()=>{if(i(s))return!0},A=on(O,()=>{n.enterable&&i(f)==="hover"&&p()}),M=on(O,()=>{i(f)==="hover"&&d()}),D=()=>{var P,x;(x=(P=a.value)==null?void 0:P.updatePopper)==null||x.call(P),h==null||h()},U=()=>{C==null||C()},j=()=>{m(),L=cv(k(()=>{var P;return(P=a.value)==null?void 0:P.popperContentRef}),()=>{if(i(s))return;i(f)!=="hover"&&d()})},W=()=>{n.virtualTriggering||d()};let L;return ve(()=>i(c),P=>{P||L==null||L()},{flush:"post"}),ve(()=>n.content,()=>{var P,x;(x=(P=a.value)==null?void 0:P.updatePopper)==null||x.call(P)}),t({contentRef:a}),(P,x)=>(T(),re(Pl,{disabled:!P.teleported,to:i(w)},[K(fn,{name:i(g),onAfterLeave:$,onBeforeEnter:D,onAfterEnter:j,onBeforeLeave:U},{default:X(()=>[i(_)?tt((T(),re(i(K6),mt({key:0,id:i(u),ref_key:"contentRef",ref:a},P.$attrs,{"aria-label":P.ariaLabel,"aria-hidden":i(E),"boundaries-padding":P.boundariesPadding,"fallback-placements":P.fallbackPlacements,"gpu-acceleration":P.gpuAcceleration,offset:P.offset,placement:P.placement,"popper-options":P.popperOptions,strategy:P.strategy,effect:P.effect,enterable:P.enterable,pure:P.pure,"popper-class":P.popperClass,"popper-style":[P.popperStyle,i(S)],"reference-el":P.referenceEl,"trigger-target-el":P.triggerTargetEl,visible:i(b),"z-index":P.zIndex,onMouseenter:i(A),onMouseleave:i(M),onBlur:W,onClose:i(d)}),{default:X(()=>[l.value?te("v-if",!0):ie(P.$slots,"default",{key:0})]),_:3},16,["id","aria-label","aria-hidden","boundaries-padding","fallback-placements","gpu-acceleration","offset","placement","popper-options","strategy","effect","enterable","pure","popper-class","popper-style","reference-el","trigger-target-el","visible","z-index","onMouseenter","onMouseleave","onClose"])),[[kt,i(b)]]):te("v-if",!0)]),_:3},8,["name"])],8,["disabled","to"]))}});var oB=Ie(nB,[["__file","content.vue"]]);const rB=["innerHTML"],aB={key:1},lB=Y({name:"ElTooltip"}),sB=Y({...lB,props:G6,emits:X6,setup(e,{expose:t,emit:n}){const o=e;MD();const r=xn(),a=R(),l=R(),s=()=>{var g;const y=i(a);y&&((g=y.popperInstanceRef)==null||g.update())},u=R(!1),c=R(),{show:f,hide:d,hasUpdateHandler:p}=Y6({indicator:u,toggleReason:c}),{onOpen:m,onClose:v}=PD({showAfter:Lt(o,"showAfter"),hideAfter:Lt(o,"hideAfter"),autoClose:Lt(o,"autoClose"),open:f,close:d}),h=k(()=>dn(o.visible)&&!p.value);yt(kf,{controlled:h,id:r,open:Ml(u),trigger:Lt(o,"trigger"),onOpen:g=>{m(g)},onClose:g=>{v(g)},onToggle:g=>{i(u)?v(g):m(g)},onShow:()=>{n("show",c.value)},onHide:()=>{n("hide",c.value)},onBeforeShow:()=>{n("before-show",c.value)},onBeforeHide:()=>{n("before-hide",c.value)},updatePopper:s}),ve(()=>o.disabled,g=>{g&&u.value&&(u.value=!1)});const C=g=>{var y,_;const b=(_=(y=l.value)==null?void 0:y.contentRef)==null?void 0:_.popperContentRef,w=(g==null?void 0:g.relatedTarget)||document.activeElement;return b&&b.contains(w)};return Qm(()=>u.value&&d()),t({popperRef:a,contentRef:l,isFocusInsideContent:C,updatePopper:s,onOpen:m,onClose:v,hide:d}),(g,y)=>(T(),re(i(ZS),{ref_key:"popperRef",ref:a,role:g.role},{default:X(()=>[K(eB,{disabled:g.disabled,trigger:g.trigger,"trigger-keys":g.triggerKeys,"virtual-ref":g.virtualRef,"virtual-triggering":g.virtualTriggering},{default:X(()=>[g.$slots.default?ie(g.$slots,"default",{key:0}):te("v-if",!0)]),_:3},8,["disabled","trigger","trigger-keys","virtual-ref","virtual-triggering"]),K(oB,{ref_key:"contentRef",ref:l,"aria-label":g.ariaLabel,"boundaries-padding":g.boundariesPadding,content:g.content,disabled:g.disabled,effect:g.effect,enterable:g.enterable,"fallback-placements":g.fallbackPlacements,"hide-after":g.hideAfter,"gpu-acceleration":g.gpuAcceleration,offset:g.offset,persistent:g.persistent,"popper-class":g.popperClass,"popper-style":g.popperStyle,placement:g.placement,"popper-options":g.popperOptions,pure:g.pure,"raw-content":g.rawContent,"reference-el":g.referenceEl,"trigger-target-el":g.triggerTargetEl,"show-after":g.showAfter,strategy:g.strategy,teleported:g.teleported,transition:g.transition,"virtual-triggering":g.virtualTriggering,"z-index":g.zIndex,"append-to":g.appendTo},{default:X(()=>[ie(g.$slots,"content",{},()=>[g.rawContent?(T(),V("span",{key:0,innerHTML:g.content},null,8,rB)):(T(),V("span",aB,le(g.content),1))]),g.showArrow?(T(),re(i(v6),{key:0,"arrow-offset":g.arrowOffset},null,8,["arrow-offset"])):te("v-if",!0)]),_:3},8,["aria-label","boundaries-padding","content","disabled","effect","enterable","fallback-placements","hide-after","gpu-acceleration","offset","persistent","popper-class","popper-style","placement","popper-options","pure","raw-content","reference-el","trigger-target-el","show-after","strategy","teleported","transition","virtual-triggering","z-index","append-to"])]),_:3},8,["role"]))}});var iB=Ie(sB,[["__file","tooltip.vue"]]);const Un=ut(iB),uB=Ne({valueKey:{type:String,default:"value"},modelValue:{type:[String,Number],default:""},debounce:{type:Number,default:300},placement:{type:Q(String),values:["top","top-start","top-end","bottom","bottom-start","bottom-end"],default:"bottom-start"},fetchSuggestions:{type:Q([Function,Array]),default:Bt},popperClass:{type:String,default:""},triggerOnFocus:{type:Boolean,default:!0},selectWhenUnmatched:{type:Boolean,default:!1},hideLoading:{type:Boolean,default:!1},teleported:kn.teleported,highlightFirstItem:{type:Boolean,default:!1},fitInputWidth:{type:Boolean,default:!1},clearable:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},name:String,...An(["ariaLabel"])}),cB={[ft]:e=>nt(e),[Zn]:e=>nt(e),[Yt]:e=>nt(e),focus:e=>e instanceof FocusEvent,blur:e=>e instanceof FocusEvent,clear:()=>!0,select:e=>dt(e)},dB=["aria-expanded","aria-owns"],fB={key:0},pB=["id","aria-selected","onClick"],QS="ElAutocomplete",hB=Y({name:QS,inheritAttrs:!1}),mB=Y({...hB,props:uB,emits:cB,setup(e,{expose:t,emit:n}){const o=e,r=xv(),a=xa(),l=to(),s=Se("autocomplete"),u=R(),c=R(),f=R(),d=R();let p=!1,m=!1;const v=R([]),h=R(-1),C=R(""),g=R(!1),y=R(!1),_=R(!1),b=xn(),w=k(()=>a.style),S=k(()=>(v.value.length>0||_.value)&&g.value),E=k(()=>!o.hideLoading&&_.value),$=k(()=>u.value?Array.from(u.value.$el.querySelectorAll("input")):[]),O=()=>{S.value&&(C.value=`${u.value.$el.offsetWidth}px`)},A=()=>{h.value=-1},D=co(async oe=>{if(y.value)return;const ke=ae=>{_.value=!1,!y.value&&(Pe(ae)?(v.value=ae,h.value=o.highlightFirstItem?0:-1):vn(QS,"autocomplete suggestions must be an array"))};if(_.value=!0,Pe(o.fetchSuggestions))ke(o.fetchSuggestions);else{const ae=await o.fetchSuggestions(oe,ke);Pe(ae)&&ke(ae)}},o.debounce),U=oe=>{const ke=!!oe;if(n(Zn,oe),n(ft,oe),y.value=!1,g.value||(g.value=ke),!o.triggerOnFocus&&!oe){y.value=!0,v.value=[];return}D(oe)},j=oe=>{var ke;l.value||(((ke=oe.target)==null?void 0:ke.tagName)!=="INPUT"||$.value.includes(document.activeElement))&&(g.value=!0)},W=oe=>{n(Yt,oe)},L=oe=>{m?m=!1:(g.value=!0,n("focus",oe),o.triggerOnFocus&&!p&&D(String(o.modelValue)))},P=oe=>{setTimeout(()=>{var ke;if((ke=f.value)!=null&&ke.isFocusInsideContent()){m=!0;return}g.value&&G(),n("blur",oe)})},x=()=>{g.value=!1,n(ft,""),n("clear")},I=async()=>{S.value&&h.value>=0&&h.value{S.value&&(oe.preventDefault(),oe.stopPropagation(),G())},G=()=>{g.value=!1},J=()=>{var oe;(oe=u.value)==null||oe.focus()},ee=()=>{var oe;(oe=u.value)==null||oe.blur()},fe=async oe=>{n(Zn,oe[o.valueKey]),n(ft,oe[o.valueKey]),n("select",oe),v.value=[],h.value=-1},Te=oe=>{if(!S.value||_.value)return;if(oe<0){h.value=-1;return}oe>=v.value.length&&(oe=v.value.length-1);const ke=c.value.querySelector(`.${s.be("suggestion","wrap")}`),Oe=ke.querySelectorAll(`.${s.be("suggestion","list")} li`)[oe],we=ke.scrollTop,{offsetTop:ge,scrollHeight:q}=Oe;ge+q>we+ke.clientHeight&&(ke.scrollTop+=q),ge{S.value&&G()}),at(()=>{u.value.ref.setAttribute("role","textbox"),u.value.ref.setAttribute("aria-autocomplete","list"),u.value.ref.setAttribute("aria-controls","id"),u.value.ref.setAttribute("aria-activedescendant",`${b.value}-item-${h.value}`),p=u.value.ref.hasAttribute("readonly")}),t({highlightedIndex:h,activated:g,loading:_,inputRef:u,popperRef:f,suggestions:v,handleSelect:fe,handleKeyEnter:I,focus:J,blur:ee,close:G,highlight:Te}),(oe,ke)=>(T(),re(i(Un),{ref_key:"popperRef",ref:f,visible:i(S),placement:oe.placement,"fallback-placements":["bottom-start","top-start"],"popper-class":[i(s).e("popper"),oe.popperClass],teleported:oe.teleported,"gpu-acceleration":!1,pure:"","manual-mode":"",effect:"light",trigger:"click",transition:`${i(s).namespace.value}-zoom-in-top`,persistent:"",role:"listbox",onBeforeShow:O,onHide:A},{content:X(()=>[F("div",{ref_key:"regionRef",ref:c,class:N([i(s).b("suggestion"),i(s).is("loading",i(E))]),style:je({[oe.fitInputWidth?"width":"minWidth"]:C.value,outline:"none"}),role:"region"},[K(i(ea),{id:i(b),tag:"ul","wrap-class":i(s).be("suggestion","wrap"),"view-class":i(s).be("suggestion","list"),role:"listbox"},{default:X(()=>[i(E)?(T(),V("li",fB,[ie(oe.$slots,"loading",{},()=>[K(i(ze),{class:N(i(s).is("loading"))},{default:X(()=>[K(i(Er))]),_:1},8,["class"])])])):(T(!0),V(Ve,{key:1},bt(v.value,(ae,Oe)=>(T(),V("li",{id:`${i(b)}-item-${Oe}`,key:Oe,class:N({highlighted:h.value===Oe}),role:"option","aria-selected":h.value===Oe,onClick:we=>fe(ae)},[ie(oe.$slots,"default",{item:ae},()=>[Ge(le(ae[oe.valueKey]),1)])],10,pB))),128))]),_:3},8,["id","wrap-class","view-class"])],6)]),default:X(()=>[F("div",{ref_key:"listboxRef",ref:d,class:N([i(s).b(),oe.$attrs.class]),style:je(i(w)),role:"combobox","aria-haspopup":"listbox","aria-expanded":i(S),"aria-owns":i(b)},[K(i(zn),mt({ref_key:"inputRef",ref:u},i(r),{clearable:oe.clearable,disabled:i(l),name:oe.name,"model-value":oe.modelValue,"aria-label":oe.ariaLabel,onInput:U,onChange:W,onFocus:L,onBlur:P,onClear:x,onKeydown:[ke[0]||(ke[0]=Pt(Qe(ae=>Te(h.value-1),["prevent"]),["up"])),ke[1]||(ke[1]=Pt(Qe(ae=>Te(h.value+1),["prevent"]),["down"])),Pt(I,["enter"]),Pt(G,["tab"]),Pt(H,["esc"])],onMousedown:j}),Sr({_:2},[oe.$slots.prepend?{name:"prepend",fn:X(()=>[ie(oe.$slots,"prepend")])}:void 0,oe.$slots.append?{name:"append",fn:X(()=>[ie(oe.$slots,"append")])}:void 0,oe.$slots.prefix?{name:"prefix",fn:X(()=>[ie(oe.$slots,"prefix")])}:void 0,oe.$slots.suffix?{name:"suffix",fn:X(()=>[ie(oe.$slots,"suffix")])}:void 0]),1040,["clearable","disabled","name","model-value","aria-label","onKeydown"])],14,dB)]),_:3},8,["visible","placement","popper-class","teleported","transition"]))}});var vB=Ie(mB,[["__file","autocomplete.vue"]]);const gB=ut(vB),bB=Ne({size:{type:[Number,String],values:Ir,default:"",validator:e=>Je(e)},shape:{type:String,values:["circle","square"],default:"circle"},icon:{type:Dt},src:{type:String,default:""},alt:String,srcSet:String,fit:{type:Q(String),default:"cover"}}),yB={error:e=>e instanceof Event},wB=["src","alt","srcset"],_B=Y({name:"ElAvatar"}),CB=Y({..._B,props:bB,emits:yB,setup(e,{emit:t}){const n=e,o=Se("avatar"),r=R(!1),a=k(()=>{const{size:c,icon:f,shape:d}=n,p=[o.b()];return nt(c)&&p.push(o.m(c)),f&&p.push(o.m("icon")),d&&p.push(o.m(d)),p}),l=k(()=>{const{size:c}=n;return Je(c)?o.cssVarBlock({size:rn(c)||""}):void 0}),s=k(()=>({objectFit:n.fit}));ve(()=>n.src,()=>r.value=!1);function u(c){r.value=!0,t("error",c)}return(c,f)=>(T(),V("span",{class:N(i(a)),style:je(i(l))},[(c.src||c.srcSet)&&!r.value?(T(),V("img",{key:0,src:c.src,alt:c.alt,srcset:c.srcSet,style:je(i(s)),onError:u},null,44,wB)):c.icon?(T(),re(i(ze),{key:1},{default:X(()=>[(T(),re(pt(c.icon)))]),_:1})):ie(c.$slots,"default",{key:2})],6))}});var SB=Ie(CB,[["__file","avatar.vue"]]);const kB=ut(SB),EB={visibilityHeight:{type:Number,default:200},target:{type:String,default:""},right:{type:Number,default:40},bottom:{type:Number,default:40}},TB={click:e=>e instanceof MouseEvent},$B=(e,t,n)=>{const o=Ut(),r=Ut(),a=R(!1),l=()=>{o.value&&(a.value=o.value.scrollTop>=e.visibilityHeight)},s=c=>{var f;(f=o.value)==null||f.scrollTo({top:0,behavior:"smooth"}),t("click",c)},u=Z_(l,300,!0);return qt(r,"scroll",u),at(()=>{var c;r.value=document,o.value=document.documentElement,e.target&&(o.value=(c=document.querySelector(e.target))!=null?c:void 0,o.value||vn(n,`target does not exist: ${e.target}`),r.value=o.value),l()}),{visible:a,handleClick:s}},ek="ElBacktop",OB=Y({name:ek}),NB=Y({...OB,props:EB,emits:TB,setup(e,{emit:t}){const n=e,o=Se("backtop"),{handleClick:r,visible:a}=$B(n,t,ek),l=k(()=>({right:`${n.right}px`,bottom:`${n.bottom}px`}));return(s,u)=>(T(),re(fn,{name:`${i(o).namespace.value}-fade-in`},{default:X(()=>[i(a)?(T(),V("div",{key:0,style:je(i(l)),class:N(i(o).b()),onClick:u[0]||(u[0]=Qe((...c)=>i(r)&&i(r)(...c),["stop"]))},[ie(s.$slots,"default",{},()=>[K(i(ze),{class:N(i(o).e("icon"))},{default:X(()=>[K(i(i4))]),_:1},8,["class"])])],6)):te("v-if",!0)]),_:3},8,["name"]))}});var IB=Ie(NB,[["__file","backtop.vue"]]);const MB=ut(IB),AB=Ne({value:{type:[String,Number],default:""},max:{type:Number,default:99},isDot:Boolean,hidden:Boolean,type:{type:String,values:["primary","success","warning","info","danger"],default:"danger"},showZero:{type:Boolean,default:!0},color:String,dotStyle:{type:Q([String,Object,Array])},badgeStyle:{type:Q([String,Object,Array])},offset:{type:Q(Array),default:[0,0]},dotClass:{type:String},badgeClass:{type:String}}),PB=["textContent"],RB=Y({name:"ElBadge"}),LB=Y({...RB,props:AB,setup(e,{expose:t}){const n=e,o=Se("badge"),r=k(()=>n.isDot?"":Je(n.value)&&Je(n.max)?n.max{var l,s,u,c,f,d;return[{backgroundColor:n.color,marginRight:rn(-((s=(l=n.offset)==null?void 0:l[0])!=null?s:0)),marginTop:rn((c=(u=n.offset)==null?void 0:u[1])!=null?c:0)},(f=n.dotStyle)!=null?f:{},(d=n.badgeStyle)!=null?d:{}]});return wn({from:"dot-style",replacement:"badge-style",version:"2.8.0",scope:"el-badge",ref:"https://element-plus.org/en-US/component/badge.html"},k(()=>!!n.dotStyle)),wn({from:"dot-class",replacement:"badge-class",version:"2.8.0",scope:"el-badge",ref:"https://element-plus.org/en-US/component/badge.html"},k(()=>!!n.dotClass)),t({content:r}),(l,s)=>(T(),V("div",{class:N(i(o).b())},[ie(l.$slots,"default"),K(fn,{name:`${i(o).namespace.value}-zoom-in-center`,persisted:""},{default:X(()=>[tt(F("sup",{class:N([i(o).e("content"),i(o).em("content",l.type),i(o).is("fixed",!!l.$slots.default),i(o).is("dot",l.isDot),l.dotClass,l.badgeClass]),style:je(i(a)),textContent:le(i(r))},null,14,PB),[[kt,!l.hidden&&(i(r)||l.isDot)]])]),_:1},8,["name"])],2))}});var xB=Ie(LB,[["__file","badge.vue"]]);const tk=ut(xB),nk=Symbol("breadcrumbKey"),DB=Ne({separator:{type:String,default:"/"},separatorIcon:{type:Dt}}),FB=["aria-label"],BB=Y({name:"ElBreadcrumb"}),VB=Y({...BB,props:DB,setup(e){const t=e,{t:n}=$t(),o=Se("breadcrumb"),r=R();return yt(nk,t),at(()=>{const a=r.value.querySelectorAll(`.${o.e("item")}`);a.length&&a[a.length-1].setAttribute("aria-current","page")}),(a,l)=>(T(),V("div",{ref_key:"breadcrumb",ref:r,class:N(i(o).b()),"aria-label":i(n)("el.breadcrumb.label"),role:"navigation"},[ie(a.$slots,"default")],10,FB))}});var HB=Ie(VB,[["__file","breadcrumb.vue"]]);const zB=Ne({to:{type:Q([String,Object]),default:""},replace:Boolean}),jB=Y({name:"ElBreadcrumbItem"}),WB=Y({...jB,props:zB,setup(e){const t=e,n=lt(),o=De(nk,void 0),r=Se("breadcrumb"),a=n.appContext.config.globalProperties.$router,l=R(),s=()=>{!t.to||!a||(t.replace?a.replace(t.to):a.push(t.to))};return(u,c)=>{var f,d;return T(),V("span",{class:N(i(r).e("item"))},[F("span",{ref_key:"link",ref:l,class:N([i(r).e("inner"),i(r).is("link",!!u.to)]),role:"link",onClick:s},[ie(u.$slots,"default")],2),(f=i(o))!=null&&f.separatorIcon?(T(),re(i(ze),{key:0,class:N(i(r).e("separator"))},{default:X(()=>[(T(),re(pt(i(o).separatorIcon)))]),_:1},8,["class"])):(T(),V("span",{key:1,class:N(i(r).e("separator")),role:"presentation"},le((d=i(o))==null?void 0:d.separator),3))],2)}}});var ok=Ie(WB,[["__file","breadcrumb-item.vue"]]);const KB=ut(HB,{BreadcrumbItem:ok}),UB=tn(ok),rk=Symbol("buttonGroupContextKey"),qB=(e,t)=>{wn({from:"type.text",replacement:"link",version:"3.0.0",scope:"props",ref:"https://element-plus.org/en-US/component/button.html#button-attributes"},k(()=>e.type==="text"));const n=De(rk,void 0),o=_f("button"),{form:r}=qn(),a=hn(k(()=>n==null?void 0:n.size)),l=to(),s=R(),u=Sn(),c=k(()=>e.type||(n==null?void 0:n.type)||""),f=k(()=>{var v,h,C;return(C=(h=e.autoInsertSpace)!=null?h:(v=o.value)==null?void 0:v.autoInsertSpace)!=null?C:!1}),d=k(()=>e.tag==="button"?{ariaDisabled:l.value||e.loading,disabled:l.value||e.loading,autofocus:e.autofocus,type:e.nativeType}:{}),p=k(()=>{var v;const h=(v=u.default)==null?void 0:v.call(u);if(f.value&&(h==null?void 0:h.length)===1){const C=h[0];if((C==null?void 0:C.type)===Ur){const g=C.children;return new RegExp("^\\p{Unified_Ideograph}{2}$","u").test(g.trim())}}return!1});return{_disabled:l,_size:a,_type:c,_ref:s,_props:d,shouldAddSpace:p,handleClick:v=>{e.nativeType==="reset"&&(r==null||r.resetFields()),t("click",v)}}},Oh=["default","primary","success","warning","info","danger","text",""],YB=["button","submit","reset"],Nh=Ne({size:gn,disabled:Boolean,type:{type:String,values:Oh,default:""},icon:{type:Dt},nativeType:{type:String,values:YB,default:"button"},loading:Boolean,loadingIcon:{type:Dt,default:()=>Er},plain:Boolean,text:Boolean,link:Boolean,bg:Boolean,autofocus:Boolean,round:Boolean,circle:Boolean,color:String,dark:Boolean,autoInsertSpace:{type:Boolean,default:void 0},tag:{type:Q([String,Object]),default:"button"}}),GB={click:e=>e instanceof MouseEvent};function Ln(e,t){XB(e)&&(e="100%");var n=JB(e);return e=t===360?e:Math.min(t,Math.max(0,parseFloat(e))),n&&(e=parseInt(String(e*t),10)/100),Math.abs(e-t)<1e-6?1:(t===360?e=(e<0?e%t+t:e%t)/parseFloat(String(t)):e=e%t/parseFloat(String(t)),e)}function gc(e){return Math.min(1,Math.max(0,e))}function XB(e){return typeof e=="string"&&e.indexOf(".")!==-1&&parseFloat(e)===1}function JB(e){return typeof e=="string"&&e.indexOf("%")!==-1}function ak(e){return e=parseFloat(e),(isNaN(e)||e<0||e>1)&&(e=1),e}function bc(e){return e<=1?"".concat(Number(e)*100,"%"):e}function Qa(e){return e.length===1?"0"+e:String(e)}function ZB(e,t,n){return{r:Ln(e,255)*255,g:Ln(t,255)*255,b:Ln(n,255)*255}}function I0(e,t,n){e=Ln(e,255),t=Ln(t,255),n=Ln(n,255);var o=Math.max(e,t,n),r=Math.min(e,t,n),a=0,l=0,s=(o+r)/2;if(o===r)l=0,a=0;else{var u=o-r;switch(l=s>.5?u/(2-o-r):u/(o+r),o){case e:a=(t-n)/u+(t1&&(n-=1),n<1/6?e+(t-e)*(6*n):n<1/2?t:n<2/3?e+(t-e)*(2/3-n)*6:e}function QB(e,t,n){var o,r,a;if(e=Ln(e,360),t=Ln(t,100),n=Ln(n,100),t===0)r=n,a=n,o=n;else{var l=n<.5?n*(1+t):n+t-n*t,s=2*n-l;o=mp(s,l,e+1/3),r=mp(s,l,e),a=mp(s,l,e-1/3)}return{r:o*255,g:r*255,b:a*255}}function M0(e,t,n){e=Ln(e,255),t=Ln(t,255),n=Ln(n,255);var o=Math.max(e,t,n),r=Math.min(e,t,n),a=0,l=o,s=o-r,u=o===0?0:s/o;if(o===r)a=0;else{switch(o){case e:a=(t-n)/s+(t>16,g:(e&65280)>>8,b:e&255}}var Ih={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",goldenrod:"#daa520",gold:"#ffd700",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavenderblush:"#fff0f5",lavender:"#e6e6fa",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};function rV(e){var t={r:0,g:0,b:0},n=1,o=null,r=null,a=null,l=!1,s=!1;return typeof e=="string"&&(e=sV(e)),typeof e=="object"&&(xr(e.r)&&xr(e.g)&&xr(e.b)?(t=ZB(e.r,e.g,e.b),l=!0,s=String(e.r).substr(-1)==="%"?"prgb":"rgb"):xr(e.h)&&xr(e.s)&&xr(e.v)?(o=bc(e.s),r=bc(e.v),t=eV(e.h,o,r),l=!0,s="hsv"):xr(e.h)&&xr(e.s)&&xr(e.l)&&(o=bc(e.s),a=bc(e.l),t=QB(e.h,o,a),l=!0,s="hsl"),Object.prototype.hasOwnProperty.call(e,"a")&&(n=e.a)),n=ak(n),{ok:l,format:e.format||s,r:Math.min(255,Math.max(t.r,0)),g:Math.min(255,Math.max(t.g,0)),b:Math.min(255,Math.max(t.b,0)),a:n}}var aV="[-\\+]?\\d+%?",lV="[-\\+]?\\d*\\.\\d+%?",ba="(?:".concat(lV,")|(?:").concat(aV,")"),vp="[\\s|\\(]+(".concat(ba,")[,|\\s]+(").concat(ba,")[,|\\s]+(").concat(ba,")\\s*\\)?"),gp="[\\s|\\(]+(".concat(ba,")[,|\\s]+(").concat(ba,")[,|\\s]+(").concat(ba,")[,|\\s]+(").concat(ba,")\\s*\\)?"),qo={CSS_UNIT:new RegExp(ba),rgb:new RegExp("rgb"+vp),rgba:new RegExp("rgba"+gp),hsl:new RegExp("hsl"+vp),hsla:new RegExp("hsla"+gp),hsv:new RegExp("hsv"+vp),hsva:new RegExp("hsva"+gp),hex3:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex4:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex8:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/};function sV(e){if(e=e.trim().toLowerCase(),e.length===0)return!1;var t=!1;if(Ih[e])e=Ih[e],t=!0;else if(e==="transparent")return{r:0,g:0,b:0,a:0,format:"name"};var n=qo.rgb.exec(e);return n?{r:n[1],g:n[2],b:n[3]}:(n=qo.rgba.exec(e),n?{r:n[1],g:n[2],b:n[3],a:n[4]}:(n=qo.hsl.exec(e),n?{h:n[1],s:n[2],l:n[3]}:(n=qo.hsla.exec(e),n?{h:n[1],s:n[2],l:n[3],a:n[4]}:(n=qo.hsv.exec(e),n?{h:n[1],s:n[2],v:n[3]}:(n=qo.hsva.exec(e),n?{h:n[1],s:n[2],v:n[3],a:n[4]}:(n=qo.hex8.exec(e),n?{r:fo(n[1]),g:fo(n[2]),b:fo(n[3]),a:P0(n[4]),format:t?"name":"hex8"}:(n=qo.hex6.exec(e),n?{r:fo(n[1]),g:fo(n[2]),b:fo(n[3]),format:t?"name":"hex"}:(n=qo.hex4.exec(e),n?{r:fo(n[1]+n[1]),g:fo(n[2]+n[2]),b:fo(n[3]+n[3]),a:P0(n[4]+n[4]),format:t?"name":"hex8"}:(n=qo.hex3.exec(e),n?{r:fo(n[1]+n[1]),g:fo(n[2]+n[2]),b:fo(n[3]+n[3]),format:t?"name":"hex"}:!1)))))))))}function xr(e){return!!qo.CSS_UNIT.exec(String(e))}var lk=function(){function e(t,n){t===void 0&&(t=""),n===void 0&&(n={});var o;if(t instanceof e)return t;typeof t=="number"&&(t=oV(t)),this.originalInput=t;var r=rV(t);this.originalInput=t,this.r=r.r,this.g=r.g,this.b=r.b,this.a=r.a,this.roundA=Math.round(100*this.a)/100,this.format=(o=n.format)!==null&&o!==void 0?o:r.format,this.gradientType=n.gradientType,this.r<1&&(this.r=Math.round(this.r)),this.g<1&&(this.g=Math.round(this.g)),this.b<1&&(this.b=Math.round(this.b)),this.isValid=r.ok}return e.prototype.isDark=function(){return this.getBrightness()<128},e.prototype.isLight=function(){return!this.isDark()},e.prototype.getBrightness=function(){var t=this.toRgb();return(t.r*299+t.g*587+t.b*114)/1e3},e.prototype.getLuminance=function(){var t=this.toRgb(),n,o,r,a=t.r/255,l=t.g/255,s=t.b/255;return a<=.03928?n=a/12.92:n=Math.pow((a+.055)/1.055,2.4),l<=.03928?o=l/12.92:o=Math.pow((l+.055)/1.055,2.4),s<=.03928?r=s/12.92:r=Math.pow((s+.055)/1.055,2.4),.2126*n+.7152*o+.0722*r},e.prototype.getAlpha=function(){return this.a},e.prototype.setAlpha=function(t){return this.a=ak(t),this.roundA=Math.round(100*this.a)/100,this},e.prototype.isMonochrome=function(){var t=this.toHsl().s;return t===0},e.prototype.toHsv=function(){var t=M0(this.r,this.g,this.b);return{h:t.h*360,s:t.s,v:t.v,a:this.a}},e.prototype.toHsvString=function(){var t=M0(this.r,this.g,this.b),n=Math.round(t.h*360),o=Math.round(t.s*100),r=Math.round(t.v*100);return this.a===1?"hsv(".concat(n,", ").concat(o,"%, ").concat(r,"%)"):"hsva(".concat(n,", ").concat(o,"%, ").concat(r,"%, ").concat(this.roundA,")")},e.prototype.toHsl=function(){var t=I0(this.r,this.g,this.b);return{h:t.h*360,s:t.s,l:t.l,a:this.a}},e.prototype.toHslString=function(){var t=I0(this.r,this.g,this.b),n=Math.round(t.h*360),o=Math.round(t.s*100),r=Math.round(t.l*100);return this.a===1?"hsl(".concat(n,", ").concat(o,"%, ").concat(r,"%)"):"hsla(".concat(n,", ").concat(o,"%, ").concat(r,"%, ").concat(this.roundA,")")},e.prototype.toHex=function(t){return t===void 0&&(t=!1),A0(this.r,this.g,this.b,t)},e.prototype.toHexString=function(t){return t===void 0&&(t=!1),"#"+this.toHex(t)},e.prototype.toHex8=function(t){return t===void 0&&(t=!1),tV(this.r,this.g,this.b,this.a,t)},e.prototype.toHex8String=function(t){return t===void 0&&(t=!1),"#"+this.toHex8(t)},e.prototype.toHexShortString=function(t){return t===void 0&&(t=!1),this.a===1?this.toHexString(t):this.toHex8String(t)},e.prototype.toRgb=function(){return{r:Math.round(this.r),g:Math.round(this.g),b:Math.round(this.b),a:this.a}},e.prototype.toRgbString=function(){var t=Math.round(this.r),n=Math.round(this.g),o=Math.round(this.b);return this.a===1?"rgb(".concat(t,", ").concat(n,", ").concat(o,")"):"rgba(".concat(t,", ").concat(n,", ").concat(o,", ").concat(this.roundA,")")},e.prototype.toPercentageRgb=function(){var t=function(n){return"".concat(Math.round(Ln(n,255)*100),"%")};return{r:t(this.r),g:t(this.g),b:t(this.b),a:this.a}},e.prototype.toPercentageRgbString=function(){var t=function(n){return Math.round(Ln(n,255)*100)};return this.a===1?"rgb(".concat(t(this.r),"%, ").concat(t(this.g),"%, ").concat(t(this.b),"%)"):"rgba(".concat(t(this.r),"%, ").concat(t(this.g),"%, ").concat(t(this.b),"%, ").concat(this.roundA,")")},e.prototype.toName=function(){if(this.a===0)return"transparent";if(this.a<1)return!1;for(var t="#"+A0(this.r,this.g,this.b,!1),n=0,o=Object.entries(Ih);n=0,a=!n&&r&&(t.startsWith("hex")||t==="name");return a?t==="name"&&this.a===0?this.toName():this.toRgbString():(t==="rgb"&&(o=this.toRgbString()),t==="prgb"&&(o=this.toPercentageRgbString()),(t==="hex"||t==="hex6")&&(o=this.toHexString()),t==="hex3"&&(o=this.toHexString(!0)),t==="hex4"&&(o=this.toHex8String(!0)),t==="hex8"&&(o=this.toHex8String()),t==="name"&&(o=this.toName()),t==="hsl"&&(o=this.toHslString()),t==="hsv"&&(o=this.toHsvString()),o||this.toHexString())},e.prototype.toNumber=function(){return(Math.round(this.r)<<16)+(Math.round(this.g)<<8)+Math.round(this.b)},e.prototype.clone=function(){return new e(this.toString())},e.prototype.lighten=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.l+=t/100,n.l=gc(n.l),new e(n)},e.prototype.brighten=function(t){t===void 0&&(t=10);var n=this.toRgb();return n.r=Math.max(0,Math.min(255,n.r-Math.round(255*-(t/100)))),n.g=Math.max(0,Math.min(255,n.g-Math.round(255*-(t/100)))),n.b=Math.max(0,Math.min(255,n.b-Math.round(255*-(t/100)))),new e(n)},e.prototype.darken=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.l-=t/100,n.l=gc(n.l),new e(n)},e.prototype.tint=function(t){return t===void 0&&(t=10),this.mix("white",t)},e.prototype.shade=function(t){return t===void 0&&(t=10),this.mix("black",t)},e.prototype.desaturate=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.s-=t/100,n.s=gc(n.s),new e(n)},e.prototype.saturate=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.s+=t/100,n.s=gc(n.s),new e(n)},e.prototype.greyscale=function(){return this.desaturate(100)},e.prototype.spin=function(t){var n=this.toHsl(),o=(n.h+t)%360;return n.h=o<0?360+o:o,new e(n)},e.prototype.mix=function(t,n){n===void 0&&(n=50);var o=this.toRgb(),r=new e(t).toRgb(),a=n/100,l={r:(r.r-o.r)*a+o.r,g:(r.g-o.g)*a+o.g,b:(r.b-o.b)*a+o.b,a:(r.a-o.a)*a+o.a};return new e(l)},e.prototype.analogous=function(t,n){t===void 0&&(t=6),n===void 0&&(n=30);var o=this.toHsl(),r=360/n,a=[this];for(o.h=(o.h-(r*t>>1)+720)%360;--t;)o.h=(o.h+r)%360,a.push(new e(o));return a},e.prototype.complement=function(){var t=this.toHsl();return t.h=(t.h+180)%360,new e(t)},e.prototype.monochromatic=function(t){t===void 0&&(t=6);for(var n=this.toHsv(),o=n.h,r=n.s,a=n.v,l=[],s=1/t;t--;)l.push(new e({h:o,s:r,v:a})),a=(a+s)%1;return l},e.prototype.splitcomplement=function(){var t=this.toHsl(),n=t.h;return[this,new e({h:(n+72)%360,s:t.s,l:t.l}),new e({h:(n+216)%360,s:t.s,l:t.l})]},e.prototype.onBackground=function(t){var n=this.toRgb(),o=new e(t).toRgb(),r=n.a+o.a*(1-n.a);return new e({r:(n.r*n.a+o.r*o.a*(1-n.a))/r,g:(n.g*n.a+o.g*o.a*(1-n.a))/r,b:(n.b*n.a+o.b*o.a*(1-n.a))/r,a:r})},e.prototype.triad=function(){return this.polyad(3)},e.prototype.tetrad=function(){return this.polyad(4)},e.prototype.polyad=function(t){for(var n=this.toHsl(),o=n.h,r=[this],a=360/t,l=1;l{let o={},r=e.color;if(r){const a=r.match(/var\((.*?)\)/);a&&(r=window.getComputedStyle(window.document.documentElement).getPropertyValue(a[1]));const l=new lk(r),s=e.dark?l.tint(20).toString():ia(l,20);if(e.plain)o=n.cssVarBlock({"bg-color":e.dark?ia(l,90):l.tint(90).toString(),"text-color":r,"border-color":e.dark?ia(l,50):l.tint(50).toString(),"hover-text-color":`var(${n.cssVarName("color-white")})`,"hover-bg-color":r,"hover-border-color":r,"active-bg-color":s,"active-text-color":`var(${n.cssVarName("color-white")})`,"active-border-color":s}),t.value&&(o[n.cssVarBlockName("disabled-bg-color")]=e.dark?ia(l,90):l.tint(90).toString(),o[n.cssVarBlockName("disabled-text-color")]=e.dark?ia(l,50):l.tint(50).toString(),o[n.cssVarBlockName("disabled-border-color")]=e.dark?ia(l,80):l.tint(80).toString());else{const u=e.dark?ia(l,30):l.tint(30).toString(),c=l.isDark()?`var(${n.cssVarName("color-white")})`:`var(${n.cssVarName("color-black")})`;if(o=n.cssVarBlock({"bg-color":r,"text-color":c,"border-color":r,"hover-bg-color":u,"hover-text-color":c,"hover-border-color":u,"active-bg-color":s,"active-border-color":s}),t.value){const f=e.dark?ia(l,50):l.tint(50).toString();o[n.cssVarBlockName("disabled-bg-color")]=f,o[n.cssVarBlockName("disabled-text-color")]=e.dark?"rgba(255, 255, 255, 0.5)":`var(${n.cssVarName("color-white")})`,o[n.cssVarBlockName("disabled-border-color")]=f}}}return o})}const uV=Y({name:"ElButton"}),cV=Y({...uV,props:Nh,emits:GB,setup(e,{expose:t,emit:n}){const o=e,r=iV(o),a=Se("button"),{_ref:l,_size:s,_type:u,_disabled:c,_props:f,shouldAddSpace:d,handleClick:p}=qB(o,n),m=k(()=>[a.b(),a.m(u.value),a.m(s.value),a.is("disabled",c.value),a.is("loading",o.loading),a.is("plain",o.plain),a.is("round",o.round),a.is("circle",o.circle),a.is("text",o.text),a.is("link",o.link),a.is("has-bg",o.bg)]);return t({ref:l,size:s,type:u,disabled:c,shouldAddSpace:d}),(v,h)=>(T(),re(pt(v.tag),mt({ref_key:"_ref",ref:l},i(f),{class:i(m),style:i(r),onClick:i(p)}),{default:X(()=>[v.loading?(T(),V(Ve,{key:0},[v.$slots.loading?ie(v.$slots,"loading",{key:0}):(T(),re(i(ze),{key:1,class:N(i(a).is("loading"))},{default:X(()=>[(T(),re(pt(v.loadingIcon)))]),_:1},8,["class"]))],64)):v.icon||v.$slots.icon?(T(),re(i(ze),{key:1},{default:X(()=>[v.icon?(T(),re(pt(v.icon),{key:0})):ie(v.$slots,"icon",{key:1})]),_:3})):te("v-if",!0),v.$slots.default?(T(),V("span",{key:2,class:N({[i(a).em("text","expand")]:i(d)})},[ie(v.$slots,"default")],2)):te("v-if",!0)]),_:3},16,["class","style","onClick"]))}});var dV=Ie(cV,[["__file","button.vue"]]);const fV={size:Nh.size,type:Nh.type},pV=Y({name:"ElButtonGroup"}),hV=Y({...pV,props:fV,setup(e){const t=e;yt(rk,Et({size:Lt(t,"size"),type:Lt(t,"type")}));const n=Se("button");return(o,r)=>(T(),V("div",{class:N(i(n).b("group"))},[ie(o.$slots,"default")],2))}});var sk=Ie(hV,[["__file","button-group.vue"]]);const $n=ut(dV,{ButtonGroup:sk}),ik=tn(sk);var rr=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ta(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function mV(e){if(e.__esModule)return e;var t=e.default;if(typeof t=="function"){var n=function o(){return this instanceof o?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(o){var r=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(n,o,r.get?r:{enumerable:!0,get:function(){return e[o]}})}),n}var uk={exports:{}};(function(e,t){(function(n,o){e.exports=o()})(rr,function(){var n=1e3,o=6e4,r=36e5,a="millisecond",l="second",s="minute",u="hour",c="day",f="week",d="month",p="quarter",m="year",v="date",h="Invalid Date",C=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,g=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,y={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(j){var W=["th","st","nd","rd"],L=j%100;return"["+j+(W[(L-20)%10]||W[L]||W[0])+"]"}},_=function(j,W,L){var P=String(j);return!P||P.length>=W?j:""+Array(W+1-P.length).join(L)+j},b={s:_,z:function(j){var W=-j.utcOffset(),L=Math.abs(W),P=Math.floor(L/60),x=L%60;return(W<=0?"+":"-")+_(P,2,"0")+":"+_(x,2,"0")},m:function j(W,L){if(W.date()1)return j(H[0])}else{var G=W.name;S[G]=W,x=G}return!P&&x&&(w=x),x||!P&&w},A=function(j,W){if($(j))return j.clone();var L=typeof W=="object"?W:{};return L.date=j,L.args=arguments,new D(L)},M=b;M.l=O,M.i=$,M.w=function(j,W){return A(j,{locale:W.$L,utc:W.$u,x:W.$x,$offset:W.$offset})};var D=function(){function j(L){this.$L=O(L.locale,null,!0),this.parse(L),this.$x=this.$x||L.x||{},this[E]=!0}var W=j.prototype;return W.parse=function(L){this.$d=function(P){var x=P.date,I=P.utc;if(x===null)return new Date(NaN);if(M.u(x))return new Date;if(x instanceof Date)return new Date(x);if(typeof x=="string"&&!/Z$/i.test(x)){var H=x.match(C);if(H){var G=H[2]-1||0,J=(H[7]||"0").substring(0,3);return I?new Date(Date.UTC(H[1],G,H[3]||1,H[4]||0,H[5]||0,H[6]||0,J)):new Date(H[1],G,H[3]||1,H[4]||0,H[5]||0,H[6]||0,J)}}return new Date(x)}(L),this.init()},W.init=function(){var L=this.$d;this.$y=L.getFullYear(),this.$M=L.getMonth(),this.$D=L.getDate(),this.$W=L.getDay(),this.$H=L.getHours(),this.$m=L.getMinutes(),this.$s=L.getSeconds(),this.$ms=L.getMilliseconds()},W.$utils=function(){return M},W.isValid=function(){return this.$d.toString()!==h},W.isSame=function(L,P){var x=A(L);return this.startOf(P)<=x&&x<=this.endOf(P)},W.isAfter=function(L,P){return A(L)68?1900:2e3)},f=function(C){return function(g){this[C]=+g}},d=[/[+-]\d\d:?(\d\d)?|Z/,function(C){(this.zone||(this.zone={})).offset=function(g){if(!g||g==="Z")return 0;var y=g.match(/([+-]|\d\d)/g),_=60*y[1]+(+y[2]||0);return _===0?0:y[0]==="+"?-_:_}(C)}],p=function(C){var g=u[C];return g&&(g.indexOf?g:g.s.concat(g.f))},m=function(C,g){var y,_=u.meridiem;if(_){for(var b=1;b<=24;b+=1)if(C.indexOf(_(b,0,g))>-1){y=b>12;break}}else y=C===(g?"pm":"PM");return y},v={A:[s,function(C){this.afternoon=m(C,!1)}],a:[s,function(C){this.afternoon=m(C,!0)}],Q:[r,function(C){this.month=3*(C-1)+1}],S:[r,function(C){this.milliseconds=100*+C}],SS:[a,function(C){this.milliseconds=10*+C}],SSS:[/\d{3}/,function(C){this.milliseconds=+C}],s:[l,f("seconds")],ss:[l,f("seconds")],m:[l,f("minutes")],mm:[l,f("minutes")],H:[l,f("hours")],h:[l,f("hours")],HH:[l,f("hours")],hh:[l,f("hours")],D:[l,f("day")],DD:[a,f("day")],Do:[s,function(C){var g=u.ordinal,y=C.match(/\d+/);if(this.day=y[0],g)for(var _=1;_<=31;_+=1)g(_).replace(/\[|\]/g,"")===C&&(this.day=_)}],w:[l,f("week")],ww:[a,f("week")],M:[l,f("month")],MM:[a,f("month")],MMM:[s,function(C){var g=p("months"),y=(p("monthsShort")||g.map(function(_){return _.slice(0,3)})).indexOf(C)+1;if(y<1)throw new Error;this.month=y%12||y}],MMMM:[s,function(C){var g=p("months").indexOf(C)+1;if(g<1)throw new Error;this.month=g%12||g}],Y:[/[+-]?\d+/,f("year")],YY:[a,function(C){this.year=c(C)}],YYYY:[/\d{4}/,f("year")],Z:d,ZZ:d};function h(C){var g,y;g=C,y=u&&u.formats;for(var _=(C=g.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,function(A,M,D){var U=D&&D.toUpperCase();return M||y[D]||n[D]||y[U].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,function(j,W,L){return W||L.slice(1)})})).match(o),b=_.length,w=0;w-1)return new Date((x==="X"?1e3:1)*P);var G=h(x)(P),J=G.year,ee=G.month,fe=G.day,Te=G.hours,oe=G.minutes,ke=G.seconds,ae=G.milliseconds,Oe=G.zone,we=G.week,ge=new Date,q=fe||(J||ee?1:ge.getDate()),B=J||ge.getFullYear(),z=0;J&&!ee||(z=ee>0?ee-1:ge.getMonth());var Z,ue=Te||0,se=oe||0,me=ke||0,_e=ae||0;return Oe?new Date(Date.UTC(B,z,q,ue,se,me,_e+60*Oe.offset*1e3)):I?new Date(Date.UTC(B,z,q,ue,se,me,_e)):(Z=new Date(B,z,q,ue,se,me,_e),we&&(Z=H(Z).week(we).toDate()),Z)}catch{return new Date("")}}(S,O,E,y),this.init(),U&&U!==!0&&(this.$L=this.locale(U).$L),D&&S!=this.format(O)&&(this.$d=new Date("")),u={}}else if(O instanceof Array)for(var j=O.length,W=1;W<=j;W+=1){$[1]=O[W-1];var L=y.apply(this,$);if(L.isValid()){this.$d=L.$d,this.$L=L.$L,this.init();break}W===j&&(this.$d=new Date(""))}else b.call(this,w)}}})})(ck);var gV=ck.exports;const ig=ta(gV),R0=["hours","minutes","seconds"],Mh="HH:mm:ss",Zl="YYYY-MM-DD",bV={date:Zl,dates:Zl,week:"gggg[w]ww",year:"YYYY",years:"YYYY",month:"YYYY-MM",months:"YYYY-MM",datetime:`${Zl} ${Mh}`,monthrange:"YYYY-MM",daterange:Zl,datetimerange:`${Zl} ${Mh}`},bp=(e,t)=>[e>0?e-1:void 0,e,eArray.from(Array.from({length:e}).keys()),dk=e=>e.replace(/\W?m{1,2}|\W?ZZ/g,"").replace(/\W?h{1,2}|\W?s{1,3}|\W?a/gi,"").trim(),fk=e=>e.replace(/\W?D{1,2}|\W?Do|\W?d{1,4}|\W?M{1,4}|\W?Y{2,4}/g,"").trim(),L0=function(e,t){const n=hl(e),o=hl(t);return n&&o?e.getTime()===t.getTime():!n&&!o?e===t:!1},x0=function(e,t){const n=Pe(e),o=Pe(t);return n&&o?e.length!==t.length?!1:e.every((r,a)=>L0(r,t[a])):!n&&!o?L0(e,t):!1},D0=function(e,t,n){const o=Io(t)||t==="x"?ct(e).locale(n):ct(e,t).locale(n);return o.isValid()?o:void 0},F0=function(e,t,n){return Io(t)?e:t==="x"?+e:ct(e).locale(n).format(t)},yp=(e,t)=>{var n;const o=[],r=t==null?void 0:t();for(let a=0;a({})},modelValue:{type:Q([Date,Array,String,Number]),default:""},rangeSeparator:{type:String,default:"-"},startPlaceholder:String,endPlaceholder:String,defaultValue:{type:Q([Date,Array])},defaultTime:{type:Q([Date,Array])},isRange:Boolean,...pk,disabledDate:{type:Function},cellClassName:{type:Function},shortcuts:{type:Array,default:()=>[]},arrowControl:Boolean,label:{type:String,default:void 0},tabindex:{type:Q([String,Number]),default:0},validateEvent:{type:Boolean,default:!0},unlinkPanels:Boolean,...ei,...An(["ariaLabel"])}),yV=["id","name","placeholder","value","disabled","readonly"],wV=["id","name","placeholder","value","disabled","readonly"],_V=Y({name:"Picker"}),CV=Y({..._V,props:ug,emits:["update:modelValue","change","focus","blur","clear","calendar-change","panel-change","visible-change","keydown"],setup(e,{expose:t,emit:n}){const o=e,r=xa(),{lang:a}=$t(),l=Se("date"),s=Se("input"),u=Se("range"),{form:c,formItem:f}=qn(),d=De("ElPopperOptions",{}),{valueOnClear:p}=wf(o,null),m=R(),v=R(),h=R(!1),C=R(!1),g=R(null);let y=!1,_=!1;const b=k(()=>[l.b("editor"),l.bm("editor",o.type),s.e("wrapper"),l.is("disabled",ee.value),l.is("active",h.value),u.b("editor"),$e?u.bm("editor",$e.value):"",r.class]),w=k(()=>[s.e("icon"),u.e("close-icon"),q.value?"":u.e("close-icon--hidden")]);ve(h,pe=>{pe?We(()=>{pe&&(g.value=o.modelValue)}):(de.value=null,We(()=>{S(o.modelValue)}))});const S=(pe,Ye)=>{(Ye||!x0(pe,g.value))&&(n("change",pe),o.validateEvent&&(f==null||f.validate("change").catch(_t=>void 0)))},E=pe=>{if(!x0(o.modelValue,pe)){let Ye;Pe(pe)?Ye=pe.map(_t=>F0(_t,o.valueFormat,a.value)):pe&&(Ye=F0(pe,o.valueFormat,a.value)),n("update:modelValue",pe&&Ye,a.value)}},$=pe=>{n("keydown",pe)},O=k(()=>{if(v.value){const pe=_e.value?v.value:v.value.$el;return Array.from(pe.querySelectorAll("input"))}return[]}),A=(pe,Ye,_t)=>{const Kt=O.value;Kt.length&&(!_t||_t==="min"?(Kt[0].setSelectionRange(pe,Ye),Kt[0].focus()):_t==="max"&&(Kt[1].setSelectionRange(pe,Ye),Kt[1].focus()))},M=()=>{I(!0,!0),We(()=>{_=!1})},D=(pe="",Ye=!1)=>{Ye||(_=!0),h.value=Ye;let _t;Pe(pe)?_t=pe.map(Kt=>Kt.toDate()):_t=pe&&pe.toDate(),de.value=null,E(_t)},U=()=>{C.value=!0},j=()=>{n("visible-change",!0)},W=pe=>{(pe==null?void 0:pe.key)===Ue.esc&&I(!0,!0)},L=()=>{C.value=!1,h.value=!1,_=!1,n("visible-change",!1)},P=()=>{h.value=!0},x=()=>{h.value=!1},I=(pe=!0,Ye=!1)=>{_=Ye;const[_t,Kt]=i(O);let Jt=_t;!pe&&_e.value&&(Jt=Kt),Jt&&Jt.focus()},H=pe=>{o.readonly||ee.value||h.value||_||(h.value=!0,n("focus",pe))};let G;const J=pe=>{const Ye=async()=>{setTimeout(()=>{var _t;G===Ye&&(!((_t=m.value)!=null&&_t.isFocusInsideContent()&&!y)&&O.value.filter(Kt=>Kt.contains(document.activeElement)).length===0&&(xe(),h.value=!1,n("blur",pe),o.validateEvent&&(f==null||f.validate("blur").catch(Kt=>void 0))),y=!1)},0)};G=Ye,Ye()},ee=k(()=>o.disabled||(c==null?void 0:c.disabled)),fe=k(()=>{let pe;if(z.value?ne.value.getDefaultValue&&(pe=ne.value.getDefaultValue()):Pe(o.modelValue)?pe=o.modelValue.map(Ye=>D0(Ye,o.valueFormat,a.value)):pe=D0(o.modelValue,o.valueFormat,a.value),ne.value.getRangeAvailableTime){const Ye=ne.value.getRangeAvailableTime(pe);Wn(Ye,pe)||(pe=Ye,E(Pe(pe)?pe.map(_t=>_t.toDate()):pe.toDate()))}return Pe(pe)&&pe.some(Ye=>!Ye)&&(pe=[]),pe}),Te=k(()=>{if(!ne.value.panelReady)return"";const pe=He(fe.value);return Pe(de.value)?[de.value[0]||pe&&pe[0]||"",de.value[1]||pe&&pe[1]||""]:de.value!==null?de.value:!ke.value&&z.value||!h.value&&z.value?"":pe?ae.value||Oe.value||we.value?pe.join(", "):pe:""}),oe=k(()=>o.type.includes("time")),ke=k(()=>o.type.startsWith("time")),ae=k(()=>o.type==="dates"),Oe=k(()=>o.type==="months"),we=k(()=>o.type==="years"),ge=k(()=>o.prefixIcon||(oe.value?qC:a4)),q=R(!1),B=pe=>{o.readonly||ee.value||(q.value&&(pe.stopPropagation(),M(),E(p.value),S(p.value,!0),q.value=!1,h.value=!1,ne.value.handleClear&&ne.value.handleClear()),n("clear"))},z=k(()=>{const{modelValue:pe}=o;return!pe||Pe(pe)&&!pe.filter(Boolean).length}),Z=async pe=>{var Ye;o.readonly||ee.value||(((Ye=pe.target)==null?void 0:Ye.tagName)!=="INPUT"||O.value.includes(document.activeElement))&&(h.value=!0)},ue=()=>{o.readonly||ee.value||!z.value&&o.clearable&&(q.value=!0)},se=()=>{q.value=!1},me=pe=>{var Ye;o.readonly||ee.value||(((Ye=pe.touches[0].target)==null?void 0:Ye.tagName)!=="INPUT"||O.value.includes(document.activeElement))&&(h.value=!0)},_e=k(()=>o.type.includes("range")),$e=hn(),Ce=k(()=>{var pe,Ye;return(Ye=(pe=i(m))==null?void 0:pe.popperRef)==null?void 0:Ye.contentRef}),ce=k(()=>{var pe;return i(_e)?i(v):(pe=i(v))==null?void 0:pe.$el});cv(ce,pe=>{const Ye=i(Ce),_t=i(ce);Ye&&(pe.target===Ye||pe.composedPath().includes(Ye))||pe.target===_t||pe.composedPath().includes(_t)||(h.value=!1)});const de=R(null),xe=()=>{if(de.value){const pe=he(Te.value);pe&&et(pe)&&(E(Pe(pe)?pe.map(Ye=>Ye.toDate()):pe.toDate()),de.value=null)}de.value===""&&(E(p.value),S(p.value),de.value=null)},he=pe=>pe?ne.value.parseUserInput(pe):null,He=pe=>pe?ne.value.formatToString(pe):null,et=pe=>ne.value.isValidValue(pe),rt=async pe=>{if(o.readonly||ee.value)return;const{code:Ye}=pe;if($(pe),Ye===Ue.esc){h.value===!0&&(h.value=!1,pe.preventDefault(),pe.stopPropagation());return}if(Ye===Ue.down&&(ne.value.handleFocusPicker&&(pe.preventDefault(),pe.stopPropagation()),h.value===!1&&(h.value=!0,await We()),ne.value.handleFocusPicker)){ne.value.handleFocusPicker();return}if(Ye===Ue.tab){y=!0;return}if(Ye===Ue.enter||Ye===Ue.numpadEnter){(de.value===null||de.value===""||et(he(Te.value)))&&(xe(),h.value=!1),pe.stopPropagation();return}if(de.value){pe.stopPropagation();return}ne.value.handleKeydownInput&&ne.value.handleKeydownInput(pe)},wt=pe=>{de.value=pe,h.value||(h.value=!0)},Ze=pe=>{const Ye=pe.target;de.value?de.value=[Ye.value,de.value[1]]:de.value=[Ye.value,null]},st=pe=>{const Ye=pe.target;de.value?de.value=[de.value[0],Ye.value]:de.value=[null,Ye.value]},Ee=()=>{var pe;const Ye=de.value,_t=he(Ye&&Ye[0]),Kt=i(fe);if(_t&&_t.isValid()){de.value=[He(_t),((pe=Te.value)==null?void 0:pe[1])||null];const Jt=[_t,Kt&&(Kt[1]||null)];et(Jt)&&(E(Jt),de.value=null)}},ye=()=>{var pe;const Ye=i(de),_t=he(Ye&&Ye[1]),Kt=i(fe);if(_t&&_t.isValid()){de.value=[((pe=i(Te))==null?void 0:pe[0])||null,He(_t)];const Jt=[Kt&&Kt[0],_t];et(Jt)&&(E(Jt),de.value=null)}},ne=R({}),be=pe=>{ne.value[pe[0]]=pe[1],ne.value.panelReady=!0},Fe=pe=>{n("calendar-change",pe)},vt=(pe,Ye,_t)=>{n("panel-change",pe,Ye,_t)};return yt("EP_PICKER_BASE",{props:o}),wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-time-picker",ref:"https://element-plus.org/en-US/component/time-picker.html"},k(()=>!!o.label)),t({focus:I,handleFocusInput:H,handleBlurInput:J,handleOpen:P,handleClose:x,onPick:D}),(pe,Ye)=>(T(),re(i(Un),mt({ref_key:"refPopper",ref:m,visible:h.value,effect:"light",pure:"",trigger:"click"},pe.$attrs,{role:"dialog",teleported:"",transition:`${i(l).namespace.value}-zoom-in-top`,"popper-class":[`${i(l).namespace.value}-picker__popper`,pe.popperClass],"popper-options":i(d),"fallback-placements":["bottom","top","right","left"],"gpu-acceleration":!1,"stop-popper-mouse-event":!1,"hide-after":0,persistent:"",onBeforeShow:U,onShow:j,onHide:L}),{default:X(()=>[i(_e)?(T(),V("div",{key:1,ref_key:"inputRef",ref:v,class:N(i(b)),style:je(pe.$attrs.style),onClick:H,onMouseenter:ue,onMouseleave:se,onTouchstartPassive:me,onKeydown:rt},[i(ge)?(T(),re(i(ze),{key:0,class:N([i(s).e("icon"),i(u).e("icon")]),onMousedown:Qe(Z,["prevent"]),onTouchstartPassive:me},{default:X(()=>[(T(),re(pt(i(ge))))]),_:1},8,["class","onMousedown"])):te("v-if",!0),F("input",{id:pe.id&&pe.id[0],autocomplete:"off",name:pe.name&&pe.name[0],placeholder:pe.startPlaceholder,value:i(Te)&&i(Te)[0],disabled:i(ee),readonly:!pe.editable||pe.readonly,class:N(i(u).b("input")),onMousedown:Z,onInput:Ze,onChange:Ee,onFocus:H,onBlur:J},null,42,yV),ie(pe.$slots,"range-separator",{},()=>[F("span",{class:N(i(u).b("separator"))},le(pe.rangeSeparator),3)]),F("input",{id:pe.id&&pe.id[1],autocomplete:"off",name:pe.name&&pe.name[1],placeholder:pe.endPlaceholder,value:i(Te)&&i(Te)[1],disabled:i(ee),readonly:!pe.editable||pe.readonly,class:N(i(u).b("input")),onMousedown:Z,onFocus:H,onBlur:J,onInput:st,onChange:ye},null,42,wV),pe.clearIcon?(T(),re(i(ze),{key:1,class:N(i(w)),onClick:B},{default:X(()=>[(T(),re(pt(pe.clearIcon)))]),_:1},8,["class"])):te("v-if",!0)],38)):(T(),re(i(zn),{key:0,id:pe.id,ref_key:"inputRef",ref:v,"container-role":"combobox","model-value":i(Te),name:pe.name,size:i($e),disabled:i(ee),placeholder:pe.placeholder,class:N([i(l).b("editor"),i(l).bm("editor",pe.type),pe.$attrs.class]),style:je(pe.$attrs.style),readonly:!pe.editable||pe.readonly||i(ae)||i(Oe)||i(we)||pe.type==="week","aria-label":pe.label||pe.ariaLabel,tabindex:pe.tabindex,"validate-event":!1,onInput:wt,onFocus:H,onBlur:J,onKeydown:rt,onChange:xe,onMousedown:Z,onMouseenter:ue,onMouseleave:se,onTouchstartPassive:me,onClick:Ye[0]||(Ye[0]=Qe(()=>{},["stop"]))},{prefix:X(()=>[i(ge)?(T(),re(i(ze),{key:0,class:N(i(s).e("icon")),onMousedown:Qe(Z,["prevent"]),onTouchstartPassive:me},{default:X(()=>[(T(),re(pt(i(ge))))]),_:1},8,["class","onMousedown"])):te("v-if",!0)]),suffix:X(()=>[q.value&&pe.clearIcon?(T(),re(i(ze),{key:0,class:N(`${i(s).e("icon")} clear-icon`),onClick:Qe(B,["stop"])},{default:X(()=>[(T(),re(pt(pe.clearIcon)))]),_:1},8,["class","onClick"])):te("v-if",!0)]),_:1},8,["id","model-value","name","size","disabled","placeholder","class","style","readonly","aria-label","tabindex","onKeydown"]))]),content:X(()=>[ie(pe.$slots,"default",{visible:h.value,actualVisible:C.value,parsedValue:i(fe),format:pe.format,dateFormat:pe.dateFormat,timeFormat:pe.timeFormat,unlinkPanels:pe.unlinkPanels,type:pe.type,defaultValue:pe.defaultValue,onPick:D,onSelectRange:A,onSetPickerOption:be,onCalendarChange:Fe,onPanelChange:vt,onKeydown:W,onMousedown:Ye[1]||(Ye[1]=Qe(()=>{},["stop"]))})]),_:3},16,["visible","transition","popper-class","popper-options"]))}});var mk=Ie(CV,[["__file","picker.vue"]]);const SV=Ne({...hk,datetimeRole:String,parsedValue:{type:Q(Object)}}),vk=({getAvailableHours:e,getAvailableMinutes:t,getAvailableSeconds:n})=>{const o=(l,s,u,c)=>{const f={hour:e,minute:t,second:n};let d=l;return["hour","minute","second"].forEach(p=>{if(f[p]){let m;const v=f[p];switch(p){case"minute":{m=v(d.hour(),s,c);break}case"second":{m=v(d.hour(),d.minute(),s,c);break}default:{m=v(s,c);break}}if(m!=null&&m.length&&!m.includes(d[p]())){const h=u?0:m.length-1;d=d[p](m[h])}}}),d},r={};return{timePickerOptions:r,getAvailableTime:o,onSetOption:([l,s])=>{r[l]=s}}},wp=e=>{const t=(o,r)=>o||r,n=o=>o!==!0;return e.map(t).filter(n)},gk=(e,t,n)=>({getHoursList:(l,s)=>yp(24,e&&(()=>e==null?void 0:e(l,s))),getMinutesList:(l,s,u)=>yp(60,t&&(()=>t==null?void 0:t(l,s,u))),getSecondsList:(l,s,u,c)=>yp(60,n&&(()=>n==null?void 0:n(l,s,u,c)))}),bk=(e,t,n)=>{const{getHoursList:o,getMinutesList:r,getSecondsList:a}=gk(e,t,n);return{getAvailableHours:(c,f)=>wp(o(c,f)),getAvailableMinutes:(c,f,d)=>wp(r(c,f,d)),getAvailableSeconds:(c,f,d,p)=>wp(a(c,f,d,p))}},yk=e=>{const t=R(e.parsedValue);return ve(()=>e.visible,n=>{n||(t.value=e.parsedValue)}),t},ha=new Map;let B0;Ct&&(document.addEventListener("mousedown",e=>B0=e),document.addEventListener("mouseup",e=>{for(const t of ha.values())for(const{documentHandler:n}of t)n(e,B0)}));function V0(e,t){let n=[];return Array.isArray(t.arg)?n=t.arg:Fo(t.arg)&&n.push(t.arg),function(o,r){const a=t.instance.popperRef,l=o.target,s=r==null?void 0:r.target,u=!t||!t.instance,c=!l||!s,f=e.contains(l)||e.contains(s),d=e===l,p=n.length&&n.some(v=>v==null?void 0:v.contains(l))||n.length&&n.includes(s),m=a&&(a.contains(l)||a.contains(s));u||c||f||d||p||m||t.value(o,r)}}const Yr={beforeMount(e,t){ha.has(e)||ha.set(e,[]),ha.get(e).push({documentHandler:V0(e,t),bindingFn:t.value})},updated(e,t){ha.has(e)||ha.set(e,[]);const n=ha.get(e),o=n.findIndex(a=>a.bindingFn===t.oldValue),r={documentHandler:V0(e,t),bindingFn:t.value};o>=0?n.splice(o,1,r):n.push(r)},unmounted(e){ha.delete(e)}},kV=100,EV=600,wd={beforeMount(e,t){const n=t.value,{interval:o=kV,delay:r=EV}=Xe(n)?{}:n;let a,l;const s=()=>Xe(n)?n():n.handler(),u=()=>{l&&(clearTimeout(l),l=void 0),a&&(clearInterval(a),a=void 0)};e.addEventListener("mousedown",c=>{c.button===0&&(u(),s(),document.addEventListener("mouseup",()=>u(),{once:!0}),l=setTimeout(()=>{a=setInterval(()=>{s()},o)},r))})}},Ah="_trap-focus-children",el=[],H0=e=>{if(el.length===0)return;const t=el[el.length-1][Ah];if(t.length>0&&e.code===Ue.tab){if(t.length===1){e.preventDefault(),document.activeElement!==t[0]&&t[0].focus();return}const n=e.shiftKey,o=e.target===t[0],r=e.target===t[t.length-1];o&&n&&(e.preventDefault(),t[t.length-1].focus()),r&&!n&&(e.preventDefault(),t[0].focus())}},TV={beforeMount(e){e[Ah]=Xb(e),el.push(e),el.length<=1&&document.addEventListener("keydown",H0)},updated(e){We(()=>{e[Ah]=Xb(e)})},unmounted(){el.shift(),el.length===0&&document.removeEventListener("keydown",H0)}};var z0=!1,Ga,Ph,Rh,Rc,Lc,wk,xc,Lh,xh,Dh,_k,Fh,Bh,Ck,Sk;function no(){if(!z0){z0=!0;var e=navigator.userAgent,t=/(?:MSIE.(\d+\.\d+))|(?:(?:Firefox|GranParadiso|Iceweasel).(\d+\.\d+))|(?:Opera(?:.+Version.|.)(\d+\.\d+))|(?:AppleWebKit.(\d+(?:\.\d+)?))|(?:Trident\/\d+\.\d+.*rv:(\d+\.\d+))/.exec(e),n=/(Mac OS X)|(Windows)|(Linux)/.exec(e);if(Fh=/\b(iPhone|iP[ao]d)/.exec(e),Bh=/\b(iP[ao]d)/.exec(e),Dh=/Android/i.exec(e),Ck=/FBAN\/\w+;/i.exec(e),Sk=/Mobile/i.exec(e),_k=!!/Win64/.exec(e),t){Ga=t[1]?parseFloat(t[1]):t[5]?parseFloat(t[5]):NaN,Ga&&document&&document.documentMode&&(Ga=document.documentMode);var o=/(?:Trident\/(\d+.\d+))/.exec(e);wk=o?parseFloat(o[1])+4:Ga,Ph=t[2]?parseFloat(t[2]):NaN,Rh=t[3]?parseFloat(t[3]):NaN,Rc=t[4]?parseFloat(t[4]):NaN,Rc?(t=/(?:Chrome\/(\d+\.\d+))/.exec(e),Lc=t&&t[1]?parseFloat(t[1]):NaN):Lc=NaN}else Ga=Ph=Rh=Lc=Rc=NaN;if(n){if(n[1]){var r=/(?:Mac OS X (\d+(?:[._]\d+)?))/.exec(e);xc=r?parseFloat(r[1].replace("_",".")):!0}else xc=!1;Lh=!!n[2],xh=!!n[3]}else xc=Lh=xh=!1}}var Vh={ie:function(){return no()||Ga},ieCompatibilityMode:function(){return no()||wk>Ga},ie64:function(){return Vh.ie()&&_k},firefox:function(){return no()||Ph},opera:function(){return no()||Rh},webkit:function(){return no()||Rc},safari:function(){return Vh.webkit()},chrome:function(){return no()||Lc},windows:function(){return no()||Lh},osx:function(){return no()||xc},linux:function(){return no()||xh},iphone:function(){return no()||Fh},mobile:function(){return no()||Fh||Bh||Dh||Sk},nativeApp:function(){return no()||Ck},android:function(){return no()||Dh},ipad:function(){return no()||Bh}},$V=Vh,yc=!!(typeof window<"u"&&window.document&&window.document.createElement),OV={canUseDOM:yc,canUseWorkers:typeof Worker<"u",canUseEventListeners:yc&&!!(window.addEventListener||window.attachEvent),canUseViewport:yc&&!!window.screen,isInWorker:!yc},kk=OV,Ek;kk.canUseDOM&&(Ek=document.implementation&&document.implementation.hasFeature&&document.implementation.hasFeature("","")!==!0);function NV(e,t){if(!kk.canUseDOM||t&&!("addEventListener"in document))return!1;var n="on"+e,o=n in document;if(!o){var r=document.createElement("div");r.setAttribute(n,"return;"),o=typeof r[n]=="function"}return!o&&Ek&&e==="wheel"&&(o=document.implementation.hasFeature("Events.wheel","3.0")),o}var IV=NV,j0=10,W0=40,K0=800;function Tk(e){var t=0,n=0,o=0,r=0;return"detail"in e&&(n=e.detail),"wheelDelta"in e&&(n=-e.wheelDelta/120),"wheelDeltaY"in e&&(n=-e.wheelDeltaY/120),"wheelDeltaX"in e&&(t=-e.wheelDeltaX/120),"axis"in e&&e.axis===e.HORIZONTAL_AXIS&&(t=n,n=0),o=t*j0,r=n*j0,"deltaY"in e&&(r=e.deltaY),"deltaX"in e&&(o=e.deltaX),(o||r)&&e.deltaMode&&(e.deltaMode==1?(o*=W0,r*=W0):(o*=K0,r*=K0)),o&&!t&&(t=o<1?-1:1),r&&!n&&(n=r<1?-1:1),{spinX:t,spinY:n,pixelX:o,pixelY:r}}Tk.getEventType=function(){return $V.firefox()?"DOMMouseScroll":IV("wheel")?"wheel":"mousewheel"};var MV=Tk;/** +* Checks if an event is supported in the current execution environment. +* +* NOTE: This will not work correctly for non-generic events such as `change`, +* `reset`, `load`, `error`, and `select`. +* +* Borrows from Modernizr. +* +* @param {string} eventNameSuffix Event name, e.g. "click". +* @param {?boolean} capture Check if the capture phase is supported. +* @return {boolean} True if the event is supported. +* @internal +* @license Modernizr 3.0.0pre (Custom Build) | MIT +*/const AV=function(e,t){if(e&&e.addEventListener){const n=function(o){const r=MV(o);t&&Reflect.apply(t,this,[o,r])};e.addEventListener("wheel",n,{passive:!0})}},PV={beforeMount(e,t){AV(e,t.value)}},RV=Ne({role:{type:String,required:!0},spinnerDate:{type:Q(Object),required:!0},showSeconds:{type:Boolean,default:!0},arrowControl:Boolean,amPmMode:{type:Q(String),default:""},...pk}),LV=["onClick"],xV=["onMouseenter"],DV=Y({__name:"basic-time-spinner",props:RV,emits:["change","select-range","set-option"],setup(e,{emit:t}){const n=e,o=Se("time"),{getHoursList:r,getMinutesList:a,getSecondsList:l}=gk(n.disabledHours,n.disabledMinutes,n.disabledSeconds);let s=!1;const u=R(),c=R(),f=R(),d=R(),p={hours:c,minutes:f,seconds:d},m=k(()=>n.showSeconds?R0:R0.slice(0,2)),v=k(()=>{const{spinnerDate:I}=n,H=I.hour(),G=I.minute(),J=I.second();return{hours:H,minutes:G,seconds:J}}),h=k(()=>{const{hours:I,minutes:H}=i(v);return{hours:r(n.role),minutes:a(I,n.role),seconds:l(I,H,n.role)}}),C=k(()=>{const{hours:I,minutes:H,seconds:G}=i(v);return{hours:bp(I,23),minutes:bp(H,59),seconds:bp(G,59)}}),g=co(I=>{s=!1,b(I)},200),y=I=>{if(!!!n.amPmMode)return"";const G=n.amPmMode==="A";let J=I<12?" am":" pm";return G&&(J=J.toUpperCase()),J},_=I=>{let H;switch(I){case"hours":H=[0,2];break;case"minutes":H=[3,5];break;case"seconds":H=[6,8];break}const[G,J]=H;t("select-range",G,J),u.value=I},b=I=>{E(I,i(v)[I])},w=()=>{b("hours"),b("minutes"),b("seconds")},S=I=>I.querySelector(`.${o.namespace.value}-scrollbar__wrap`),E=(I,H)=>{if(n.arrowControl)return;const G=i(p[I]);G&&G.$el&&(S(G.$el).scrollTop=Math.max(0,H*$(I)))},$=I=>{const H=i(p[I]),G=H==null?void 0:H.$el.querySelector("li");return G&&Number.parseFloat(ga(G,"height"))||0},O=()=>{M(1)},A=()=>{M(-1)},M=I=>{u.value||_("hours");const H=u.value,G=i(v)[H],J=u.value==="hours"?24:60,ee=D(H,G,I,J);U(H,ee),E(H,ee),We(()=>_(H))},D=(I,H,G,J)=>{let ee=(H+G+J)%J;const fe=i(h)[I];for(;fe[ee]&&ee!==H;)ee=(ee+G+J)%J;return ee},U=(I,H)=>{if(i(h)[I][H])return;const{hours:ee,minutes:fe,seconds:Te}=i(v);let oe;switch(I){case"hours":oe=n.spinnerDate.hour(H).minute(fe).second(Te);break;case"minutes":oe=n.spinnerDate.hour(ee).minute(H).second(Te);break;case"seconds":oe=n.spinnerDate.hour(ee).minute(fe).second(H);break}t("change",oe)},j=(I,{value:H,disabled:G})=>{G||(U(I,H),_(I),E(I,H))},W=I=>{s=!0,g(I);const H=Math.min(Math.round((S(i(p[I]).$el).scrollTop-(L(I)*.5-10)/$(I)+3)/$(I)),I==="hours"?23:59);U(I,H)},L=I=>i(p[I]).$el.offsetHeight,P=()=>{const I=H=>{const G=i(p[H]);G&&G.$el&&(S(G.$el).onscroll=()=>{W(H)})};I("hours"),I("minutes"),I("seconds")};at(()=>{We(()=>{!n.arrowControl&&P(),w(),n.role==="start"&&_("hours")})});const x=(I,H)=>{p[H].value=I};return t("set-option",[`${n.role}_scrollDown`,M]),t("set-option",[`${n.role}_emitSelectRange`,_]),ve(()=>n.spinnerDate,()=>{s||w()}),(I,H)=>(T(),V("div",{class:N([i(o).b("spinner"),{"has-seconds":I.showSeconds}])},[I.arrowControl?te("v-if",!0):(T(!0),V(Ve,{key:0},bt(i(m),G=>(T(),re(i(ea),{key:G,ref_for:!0,ref:J=>x(J,G),class:N(i(o).be("spinner","wrapper")),"wrap-style":"max-height: inherit;","view-class":i(o).be("spinner","list"),noresize:"",tag:"ul",onMouseenter:J=>_(G),onMousemove:J=>b(G)},{default:X(()=>[(T(!0),V(Ve,null,bt(i(h)[G],(J,ee)=>(T(),V("li",{key:ee,class:N([i(o).be("spinner","item"),i(o).is("active",ee===i(v)[G]),i(o).is("disabled",J)]),onClick:fe=>j(G,{value:ee,disabled:J})},[G==="hours"?(T(),V(Ve,{key:0},[Ge(le(("0"+(I.amPmMode?ee%12||12:ee)).slice(-2))+le(y(ee)),1)],64)):(T(),V(Ve,{key:1},[Ge(le(("0"+ee).slice(-2)),1)],64))],10,LV))),128))]),_:2},1032,["class","view-class","onMouseenter","onMousemove"]))),128)),I.arrowControl?(T(!0),V(Ve,{key:1},bt(i(m),G=>(T(),V("div",{key:G,class:N([i(o).be("spinner","wrapper"),i(o).is("arrow")]),onMouseenter:J=>_(G)},[tt((T(),re(i(ze),{class:N(["arrow-up",i(o).be("spinner","arrow")])},{default:X(()=>[K(i(pf))]),_:1},8,["class"])),[[i(wd),A]]),tt((T(),re(i(ze),{class:N(["arrow-down",i(o).be("spinner","arrow")])},{default:X(()=>[K(i(Nr))]),_:1},8,["class"])),[[i(wd),O]]),F("ul",{class:N(i(o).be("spinner","list"))},[(T(!0),V(Ve,null,bt(i(C)[G],(J,ee)=>(T(),V("li",{key:ee,class:N([i(o).be("spinner","item"),i(o).is("active",J===i(v)[G]),i(o).is("disabled",i(h)[G][J])])},[typeof J=="number"?(T(),V(Ve,{key:0},[G==="hours"?(T(),V(Ve,{key:0},[Ge(le(("0"+(I.amPmMode?J%12||12:J)).slice(-2))+le(y(J)),1)],64)):(T(),V(Ve,{key:1},[Ge(le(("0"+J).slice(-2)),1)],64))],64)):te("v-if",!0)],2))),128))],2)],42,xV))),128)):te("v-if",!0)],2))}});var Hh=Ie(DV,[["__file","basic-time-spinner.vue"]]);const FV=Y({__name:"panel-time-pick",props:SV,emits:["pick","select-range","set-picker-option"],setup(e,{emit:t}){const n=e,o=De("EP_PICKER_BASE"),{arrowControl:r,disabledHours:a,disabledMinutes:l,disabledSeconds:s,defaultValue:u}=o.props,{getAvailableHours:c,getAvailableMinutes:f,getAvailableSeconds:d}=bk(a,l,s),p=Se("time"),{t:m,lang:v}=$t(),h=R([0,2]),C=yk(n),g=k(()=>pn(n.actualVisible)?`${p.namespace.value}-zoom-in-top`:""),y=k(()=>n.format.includes("ss")),_=k(()=>n.format.includes("A")?"A":n.format.includes("a")?"a":""),b=x=>{const I=ct(x).locale(v.value),H=j(I);return I.isSame(H)},w=()=>{t("pick",C.value,!1)},S=(x=!1,I=!1)=>{I||t("pick",n.parsedValue,x)},E=x=>{if(!n.visible)return;const I=j(x).millisecond(0);t("pick",I,!0)},$=(x,I)=>{t("select-range",x,I),h.value=[x,I]},O=x=>{const I=[0,3].concat(y.value?[6]:[]),H=["hours","minutes"].concat(y.value?["seconds"]:[]),J=(I.indexOf(h.value[0])+x+I.length)%I.length;M.start_emitSelectRange(H[J])},A=x=>{const I=x.code,{left:H,right:G,up:J,down:ee}=Ue;if([H,G].includes(I)){O(I===H?-1:1),x.preventDefault();return}if([J,ee].includes(I)){const fe=I===J?-1:1;M.start_scrollDown(fe),x.preventDefault();return}},{timePickerOptions:M,onSetOption:D,getAvailableTime:U}=vk({getAvailableHours:c,getAvailableMinutes:f,getAvailableSeconds:d}),j=x=>U(x,n.datetimeRole||"",!0),W=x=>x?ct(x,n.format).locale(v.value):null,L=x=>x?x.format(n.format):null,P=()=>ct(u).locale(v.value);return t("set-picker-option",["isValidValue",b]),t("set-picker-option",["formatToString",L]),t("set-picker-option",["parseUserInput",W]),t("set-picker-option",["handleKeydownInput",A]),t("set-picker-option",["getRangeAvailableTime",j]),t("set-picker-option",["getDefaultValue",P]),(x,I)=>(T(),re(fn,{name:i(g)},{default:X(()=>[x.actualVisible||x.visible?(T(),V("div",{key:0,class:N(i(p).b("panel"))},[F("div",{class:N([i(p).be("panel","content"),{"has-seconds":i(y)}])},[K(Hh,{ref:"spinner",role:x.datetimeRole||"start","arrow-control":i(r),"show-seconds":i(y),"am-pm-mode":i(_),"spinner-date":x.parsedValue,"disabled-hours":i(a),"disabled-minutes":i(l),"disabled-seconds":i(s),onChange:E,onSetOption:i(D),onSelectRange:$},null,8,["role","arrow-control","show-seconds","am-pm-mode","spinner-date","disabled-hours","disabled-minutes","disabled-seconds","onSetOption"])],2),F("div",{class:N(i(p).be("panel","footer"))},[F("button",{type:"button",class:N([i(p).be("panel","btn"),"cancel"]),onClick:w},le(i(m)("el.datepicker.cancel")),3),F("button",{type:"button",class:N([i(p).be("panel","btn"),"confirm"]),onClick:I[0]||(I[0]=H=>S())},le(i(m)("el.datepicker.confirm")),3)],2)],2)):te("v-if",!0)]),_:1},8,["name"]))}});var _d=Ie(FV,[["__file","panel-time-pick.vue"]]);const BV=Ne({...hk,parsedValue:{type:Q(Array)}}),VV=["disabled"],HV=Y({__name:"panel-time-range",props:BV,emits:["pick","select-range","set-picker-option"],setup(e,{emit:t}){const n=e,o=(ge,q)=>{const B=[];for(let z=ge;z<=q;z++)B.push(z);return B},{t:r,lang:a}=$t(),l=Se("time"),s=Se("picker"),u=De("EP_PICKER_BASE"),{arrowControl:c,disabledHours:f,disabledMinutes:d,disabledSeconds:p,defaultValue:m}=u.props,v=k(()=>[l.be("range-picker","body"),l.be("panel","content"),l.is("arrow",c),b.value?"has-seconds":""]),h=k(()=>[l.be("range-picker","body"),l.be("panel","content"),l.is("arrow",c),b.value?"has-seconds":""]),C=k(()=>n.parsedValue[0]),g=k(()=>n.parsedValue[1]),y=yk(n),_=()=>{t("pick",y.value,!1)},b=k(()=>n.format.includes("ss")),w=k(()=>n.format.includes("A")?"A":n.format.includes("a")?"a":""),S=(ge=!1)=>{t("pick",[C.value,g.value],ge)},E=ge=>{A(ge.millisecond(0),g.value)},$=ge=>{A(C.value,ge.millisecond(0))},O=ge=>{const q=ge.map(z=>ct(z).locale(a.value)),B=G(q);return q[0].isSame(B[0])&&q[1].isSame(B[1])},A=(ge,q)=>{t("pick",[ge,q],!0)},M=k(()=>C.value>g.value),D=R([0,2]),U=(ge,q)=>{t("select-range",ge,q,"min"),D.value=[ge,q]},j=k(()=>b.value?11:8),W=(ge,q)=>{t("select-range",ge,q,"max");const B=i(j);D.value=[ge+B,q+B]},L=ge=>{const q=b.value?[0,3,6,11,14,17]:[0,3,8,11],B=["hours","minutes"].concat(b.value?["seconds"]:[]),Z=(q.indexOf(D.value[0])+ge+q.length)%q.length,ue=q.length/2;Z{const q=ge.code,{left:B,right:z,up:Z,down:ue}=Ue;if([B,z].includes(q)){L(q===B?-1:1),ge.preventDefault();return}if([Z,ue].includes(q)){const se=q===Z?-1:1,me=D.value[0]{const B=f?f(ge):[],z=ge==="start",ue=(q||(z?g.value:C.value)).hour(),se=z?o(ue+1,23):o(0,ue-1);return up(B,se)},I=(ge,q,B)=>{const z=d?d(ge,q):[],Z=q==="start",ue=B||(Z?g.value:C.value),se=ue.hour();if(ge!==se)return z;const me=ue.minute(),_e=Z?o(me+1,59):o(0,me-1);return up(z,_e)},H=(ge,q,B,z)=>{const Z=p?p(ge,q,B):[],ue=B==="start",se=z||(ue?g.value:C.value),me=se.hour(),_e=se.minute();if(ge!==me||q!==_e)return Z;const $e=se.second(),Ce=ue?o($e+1,59):o(0,$e-1);return up(Z,Ce)},G=([ge,q])=>[oe(ge,"start",!0,q),oe(q,"end",!1,ge)],{getAvailableHours:J,getAvailableMinutes:ee,getAvailableSeconds:fe}=bk(x,I,H),{timePickerOptions:Te,getAvailableTime:oe,onSetOption:ke}=vk({getAvailableHours:J,getAvailableMinutes:ee,getAvailableSeconds:fe}),ae=ge=>ge?Pe(ge)?ge.map(q=>ct(q,n.format).locale(a.value)):ct(ge,n.format).locale(a.value):null,Oe=ge=>ge?Pe(ge)?ge.map(q=>q.format(n.format)):ge.format(n.format):null,we=()=>{if(Pe(m))return m.map(q=>ct(q).locale(a.value));const ge=ct(m).locale(a.value);return[ge,ge.add(60,"m")]};return t("set-picker-option",["formatToString",Oe]),t("set-picker-option",["parseUserInput",ae]),t("set-picker-option",["isValidValue",O]),t("set-picker-option",["handleKeydownInput",P]),t("set-picker-option",["getDefaultValue",we]),t("set-picker-option",["getRangeAvailableTime",G]),(ge,q)=>ge.actualVisible?(T(),V("div",{key:0,class:N([i(l).b("range-picker"),i(s).b("panel")])},[F("div",{class:N(i(l).be("range-picker","content"))},[F("div",{class:N(i(l).be("range-picker","cell"))},[F("div",{class:N(i(l).be("range-picker","header"))},le(i(r)("el.datepicker.startTime")),3),F("div",{class:N(i(v))},[K(Hh,{ref:"minSpinner",role:"start","show-seconds":i(b),"am-pm-mode":i(w),"arrow-control":i(c),"spinner-date":i(C),"disabled-hours":x,"disabled-minutes":I,"disabled-seconds":H,onChange:E,onSetOption:i(ke),onSelectRange:U},null,8,["show-seconds","am-pm-mode","arrow-control","spinner-date","onSetOption"])],2)],2),F("div",{class:N(i(l).be("range-picker","cell"))},[F("div",{class:N(i(l).be("range-picker","header"))},le(i(r)("el.datepicker.endTime")),3),F("div",{class:N(i(h))},[K(Hh,{ref:"maxSpinner",role:"end","show-seconds":i(b),"am-pm-mode":i(w),"arrow-control":i(c),"spinner-date":i(g),"disabled-hours":x,"disabled-minutes":I,"disabled-seconds":H,onChange:$,onSetOption:i(ke),onSelectRange:W},null,8,["show-seconds","am-pm-mode","arrow-control","spinner-date","onSetOption"])],2)],2)],2),F("div",{class:N(i(l).be("panel","footer"))},[F("button",{type:"button",class:N([i(l).be("panel","btn"),"cancel"]),onClick:q[0]||(q[0]=B=>_())},le(i(r)("el.datepicker.cancel")),3),F("button",{type:"button",class:N([i(l).be("panel","btn"),"confirm"]),disabled:i(M),onClick:q[1]||(q[1]=B=>S())},le(i(r)("el.datepicker.confirm")),11,VV)],2)],2)):te("v-if",!0)}});var zV=Ie(HV,[["__file","panel-time-range.vue"]]);ct.extend(ig);var jV=Y({name:"ElTimePicker",install:null,props:{...ug,isRange:{type:Boolean,default:!1}},emits:["update:modelValue"],setup(e,t){const n=R(),[o,r]=e.isRange?["timerange",zV]:["time",_d],a=l=>t.emit("update:modelValue",l);return yt("ElPopperOptions",e.popperOptions),t.expose({focus:l=>{var s;(s=n.value)==null||s.handleFocusInput(l)},blur:l=>{var s;(s=n.value)==null||s.handleBlurInput(l)},handleOpen:()=>{var l;(l=n.value)==null||l.handleOpen()},handleClose:()=>{var l;(l=n.value)==null||l.handleClose()}}),()=>{var l;const s=(l=e.format)!=null?l:Mh;return K(mk,mt(e,{ref:n,type:o,format:s,"onUpdate:modelValue":a}),{default:u=>K(r,u,null)})}}});const Dc=jV;Dc.install=e=>{e.component(Dc.name,Dc)};const WV=Dc,KV=(e,t)=>{const n=e.subtract(1,"month").endOf("month").date();return Sa(t).map((o,r)=>n-(t-r-1))},UV=e=>{const t=e.daysInMonth();return Sa(t).map((n,o)=>o+1)},qV=e=>Sa(e.length/7).map(t=>{const n=t*7;return e.slice(n,n+7)}),YV=Ne({selectedDay:{type:Q(Object)},range:{type:Q(Array)},date:{type:Q(Object),required:!0},hideHeader:{type:Boolean}}),GV={pick:e=>dt(e)};var $k={exports:{}};(function(e,t){(function(n,o){e.exports=o()})(rr,function(){return function(n,o,r){var a=o.prototype,l=function(d){return d&&(d.indexOf?d:d.s)},s=function(d,p,m,v,h){var C=d.name?d:d.$locale(),g=l(C[p]),y=l(C[m]),_=g||y.map(function(w){return w.slice(0,v)});if(!h)return _;var b=C.weekStart;return _.map(function(w,S){return _[(S+(b||0))%7]})},u=function(){return r.Ls[r.locale()]},c=function(d,p){return d.formats[p]||function(m){return m.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,function(v,h,C){return h||C.slice(1)})}(d.formats[p.toUpperCase()])},f=function(){var d=this;return{months:function(p){return p?p.format("MMMM"):s(d,"months")},monthsShort:function(p){return p?p.format("MMM"):s(d,"monthsShort","months",3)},firstDayOfWeek:function(){return d.$locale().weekStart||0},weekdays:function(p){return p?p.format("dddd"):s(d,"weekdays")},weekdaysMin:function(p){return p?p.format("dd"):s(d,"weekdaysMin","weekdays",2)},weekdaysShort:function(p){return p?p.format("ddd"):s(d,"weekdaysShort","weekdays",3)},longDateFormat:function(p){return c(d.$locale(),p)},meridiem:this.$locale().meridiem,ordinal:this.$locale().ordinal}};a.localeData=function(){return f.bind(this)()},r.localeData=function(){var d=u();return{firstDayOfWeek:function(){return d.weekStart||0},weekdays:function(){return r.weekdays()},weekdaysShort:function(){return r.weekdaysShort()},weekdaysMin:function(){return r.weekdaysMin()},months:function(){return r.months()},monthsShort:function(){return r.monthsShort()},longDateFormat:function(p){return c(d,p)},meridiem:d.meridiem,ordinal:d.ordinal}},r.months=function(){return s(u(),"months")},r.monthsShort=function(){return s(u(),"monthsShort","months",3)},r.weekdays=function(d){return s(u(),"weekdays",null,null,d)},r.weekdaysShort=function(d){return s(u(),"weekdaysShort","weekdays",3,d)},r.weekdaysMin=function(d){return s(u(),"weekdaysMin","weekdays",2,d)}}})})($k);var XV=$k.exports;const Ok=ta(XV),JV=(e,t)=>{ct.extend(Ok);const n=ct.localeData().firstDayOfWeek(),{t:o,lang:r}=$t(),a=ct().locale(r.value),l=k(()=>!!e.range&&!!e.range.length),s=k(()=>{let p=[];if(l.value){const[m,v]=e.range,h=Sa(v.date()-m.date()+1).map(y=>({text:m.date()+y,type:"current"}));let C=h.length%7;C=C===0?0:7-C;const g=Sa(C).map((y,_)=>({text:_+1,type:"next"}));p=h.concat(g)}else{const m=e.date.startOf("month").day(),v=KV(e.date,(m-n+7)%7).map(y=>({text:y,type:"prev"})),h=UV(e.date).map(y=>({text:y,type:"current"}));p=[...v,...h];const C=7-(p.length%7||7),g=Sa(C).map((y,_)=>({text:_+1,type:"next"}));p=p.concat(g)}return qV(p)}),u=k(()=>{const p=n;return p===0?cp.map(m=>o(`el.datepicker.weeks.${m}`)):cp.slice(p).concat(cp.slice(0,p)).map(m=>o(`el.datepicker.weeks.${m}`))}),c=(p,m)=>{switch(m){case"prev":return e.date.startOf("month").subtract(1,"month").date(p);case"next":return e.date.startOf("month").add(1,"month").date(p);case"current":return e.date.date(p)}};return{now:a,isInRange:l,rows:s,weekDays:u,getFormattedDate:c,handlePickDay:({text:p,type:m})=>{const v=c(p,m);t("pick",v)},getSlotData:({text:p,type:m})=>{const v=c(p,m);return{isSelected:v.isSame(e.selectedDay),type:`${m}-month`,day:v.format("YYYY-MM-DD"),date:v.toDate()}}}},ZV={key:0},QV=["onClick"],e5=Y({name:"DateTable"}),t5=Y({...e5,props:YV,emits:GV,setup(e,{expose:t,emit:n}){const o=e,{isInRange:r,now:a,rows:l,weekDays:s,getFormattedDate:u,handlePickDay:c,getSlotData:f}=JV(o,n),d=Se("calendar-table"),p=Se("calendar-day"),m=({text:v,type:h})=>{const C=[h];if(h==="current"){const g=u(v,h);g.isSame(o.selectedDay,"day")&&C.push(p.is("selected")),g.isSame(a,"day")&&C.push(p.is("today"))}return C};return t({getFormattedDate:u}),(v,h)=>(T(),V("table",{class:N([i(d).b(),i(d).is("range",i(r))]),cellspacing:"0",cellpadding:"0"},[v.hideHeader?te("v-if",!0):(T(),V("thead",ZV,[(T(!0),V(Ve,null,bt(i(s),C=>(T(),V("th",{key:C},le(C),1))),128))])),F("tbody",null,[(T(!0),V(Ve,null,bt(i(l),(C,g)=>(T(),V("tr",{key:g,class:N({[i(d).e("row")]:!0,[i(d).em("row","hide-border")]:g===0&&v.hideHeader})},[(T(!0),V(Ve,null,bt(C,(y,_)=>(T(),V("td",{key:_,class:N(m(y)),onClick:b=>i(c)(y)},[F("div",{class:N(i(p).b())},[ie(v.$slots,"date-cell",{data:i(f)(y)},()=>[F("span",null,le(y.text),1)])],2)],10,QV))),128))],2))),128))])],2))}});var U0=Ie(t5,[["__file","date-table.vue"]]);const n5=(e,t)=>{const n=e.endOf("month"),o=t.startOf("month"),a=n.isSame(o,"week")?o.add(1,"week"):o;return[[e,n],[a.startOf("week"),t]]},o5=(e,t)=>{const n=e.endOf("month"),o=e.add(1,"month").startOf("month"),r=n.isSame(o,"week")?o.add(1,"week"):o,a=r.endOf("month"),l=t.startOf("month"),s=a.isSame(l,"week")?l.add(1,"week"):l;return[[e,n],[r.startOf("week"),a],[s.startOf("week"),t]]},r5=(e,t,n)=>{const{lang:o}=$t(),r=R(),a=ct().locale(o.value),l=k({get(){return e.modelValue?u.value:r.value},set(C){if(!C)return;r.value=C;const g=C.toDate();t(Zn,g),t(ft,g)}}),s=k(()=>{if(!e.range)return[];const C=e.range.map(_=>ct(_).locale(o.value)),[g,y]=C;return g.isAfter(y)?[]:g.isSame(y,"month")?m(g,y):g.add(1,"month").month()!==y.month()?[]:m(g,y)}),u=k(()=>e.modelValue?ct(e.modelValue).locale(o.value):l.value||(s.value.length?s.value[0][0]:a)),c=k(()=>u.value.subtract(1,"month").date(1)),f=k(()=>u.value.add(1,"month").date(1)),d=k(()=>u.value.subtract(1,"year").date(1)),p=k(()=>u.value.add(1,"year").date(1)),m=(C,g)=>{const y=C.startOf("week"),_=g.endOf("week"),b=y.get("month"),w=_.get("month");return b===w?[[y,_]]:(b+1)%12===w?n5(y,_):b+2===w||(b+1)%11===w?o5(y,_):[]},v=C=>{l.value=C};return{calculateValidatedDateRange:m,date:u,realSelectedDay:l,pickDay:v,selectDate:C=>{const y={"prev-month":c.value,"next-month":f.value,"prev-year":d.value,"next-year":p.value,today:a}[C];y.isSame(u.value,"day")||v(y)},validatedRange:s}},a5=e=>Pe(e)&&e.length===2&&e.every(t=>hl(t)),l5=Ne({modelValue:{type:Date},range:{type:Q(Array),validator:a5}}),s5={[ft]:e=>hl(e),[Zn]:e=>hl(e)},i5="ElCalendar",u5=Y({name:i5}),c5=Y({...u5,props:l5,emits:s5,setup(e,{expose:t,emit:n}){const o=e,r=Se("calendar"),{calculateValidatedDateRange:a,date:l,pickDay:s,realSelectedDay:u,selectDate:c,validatedRange:f}=r5(o,n),{t:d}=$t(),p=k(()=>{const m=`el.datepicker.month${l.value.format("M")}`;return`${l.value.year()} ${d("el.datepicker.year")} ${d(m)}`});return t({selectedDay:u,pickDay:s,selectDate:c,calculateValidatedDateRange:a}),(m,v)=>(T(),V("div",{class:N(i(r).b())},[F("div",{class:N(i(r).e("header"))},[ie(m.$slots,"header",{date:i(p)},()=>[F("div",{class:N(i(r).e("title"))},le(i(p)),3),i(f).length===0?(T(),V("div",{key:0,class:N(i(r).e("button-group"))},[K(i(ik),null,{default:X(()=>[K(i($n),{size:"small",onClick:v[0]||(v[0]=h=>i(c)("prev-month"))},{default:X(()=>[Ge(le(i(d)("el.datepicker.prevMonth")),1)]),_:1}),K(i($n),{size:"small",onClick:v[1]||(v[1]=h=>i(c)("today"))},{default:X(()=>[Ge(le(i(d)("el.datepicker.today")),1)]),_:1}),K(i($n),{size:"small",onClick:v[2]||(v[2]=h=>i(c)("next-month"))},{default:X(()=>[Ge(le(i(d)("el.datepicker.nextMonth")),1)]),_:1})]),_:1})],2)):te("v-if",!0)])],2),i(f).length===0?(T(),V("div",{key:0,class:N(i(r).e("body"))},[K(U0,{date:i(l),"selected-day":i(u),onPick:i(s)},Sr({_:2},[m.$slots["date-cell"]?{name:"date-cell",fn:X(h=>[ie(m.$slots,"date-cell",vr(bl(h)))])}:void 0]),1032,["date","selected-day","onPick"])],2)):(T(),V("div",{key:1,class:N(i(r).e("body"))},[(T(!0),V(Ve,null,bt(i(f),(h,C)=>(T(),re(U0,{key:C,date:h[0],"selected-day":i(u),range:h,"hide-header":C!==0,onPick:i(s)},Sr({_:2},[m.$slots["date-cell"]?{name:"date-cell",fn:X(g=>[ie(m.$slots,"date-cell",vr(bl(g)))])}:void 0]),1032,["date","selected-day","range","hide-header","onPick"]))),128))],2))],2))}});var d5=Ie(c5,[["__file","calendar.vue"]]);const f5=ut(d5),p5=Ne({header:{type:String,default:""},footer:{type:String,default:""},bodyStyle:{type:Q([String,Object,Array]),default:""},bodyClass:String,shadow:{type:String,values:["always","hover","never"],default:"always"}}),h5=Y({name:"ElCard"}),m5=Y({...h5,props:p5,setup(e){const t=Se("card");return(n,o)=>(T(),V("div",{class:N([i(t).b(),i(t).is(`${n.shadow}-shadow`)])},[n.$slots.header||n.header?(T(),V("div",{key:0,class:N(i(t).e("header"))},[ie(n.$slots,"header",{},()=>[Ge(le(n.header),1)])],2)):te("v-if",!0),F("div",{class:N([i(t).e("body"),n.bodyClass]),style:je(n.bodyStyle)},[ie(n.$slots,"default")],6),n.$slots.footer||n.footer?(T(),V("div",{key:1,class:N(i(t).e("footer"))},[ie(n.$slots,"footer",{},()=>[Ge(le(n.footer),1)])],2)):te("v-if",!0)],2))}});var v5=Ie(m5,[["__file","card.vue"]]);const g5=ut(v5),b5=Ne({initialIndex:{type:Number,default:0},height:{type:String,default:""},trigger:{type:String,values:["hover","click"],default:"hover"},autoplay:{type:Boolean,default:!0},interval:{type:Number,default:3e3},indicatorPosition:{type:String,values:["","none","outside"],default:""},arrow:{type:String,values:["always","hover","never"],default:"hover"},type:{type:String,values:["","card"],default:""},cardScale:{type:Number,default:.83},loop:{type:Boolean,default:!0},direction:{type:String,values:["horizontal","vertical"],default:"horizontal"},pauseOnHover:{type:Boolean,default:!0},motionBlur:Boolean}),y5={change:(e,t)=>[e,t].every(Je)},Nk=Symbol("carouselContextKey"),q0=300,w5=(e,t,n)=>{const{children:o,addChild:r,removeChild:a}=tg(lt(),"ElCarouselItem"),l=Sn(),s=R(-1),u=R(null),c=R(!1),f=R(),d=R(0),p=R(!0),m=R(!0),v=R(!1),h=k(()=>e.arrow!=="never"&&!i(y)),C=k(()=>o.value.some(oe=>oe.props.label.toString().length>0)),g=k(()=>e.type==="card"),y=k(()=>e.direction==="vertical"),_=k(()=>e.height!=="auto"?{height:e.height}:{height:`${d.value}px`,overflow:"hidden"}),b=il(oe=>{A(oe)},q0,{trailing:!0}),w=il(oe=>{I(oe)},q0),S=oe=>p.value?s.value<=1?oe<=1:oe>1:!0;function E(){u.value&&(clearInterval(u.value),u.value=null)}function $(){e.interval<=0||!e.autoplay||u.value||(u.value=setInterval(()=>O(),e.interval))}const O=()=>{m.value||(v.value=!0),m.value=!1,s.valuewe.props.name===oe);Oe.length>0&&(oe=o.value.indexOf(Oe[0]))}if(oe=Number(oe),Number.isNaN(oe)||oe!==Math.floor(oe))return;const ke=o.value.length,ae=s.value;oe<0?s.value=e.loop?ke-1:0:oe>=ke?s.value=e.loop?0:ke-1:s.value=oe,ae===s.value&&M(ae),J()}function M(oe){o.value.forEach((ke,ae)=>{ke.translateItem(ae,s.value,oe)})}function D(oe,ke){var ae,Oe,we,ge;const q=i(o),B=q.length;if(B===0||!oe.states.inStage)return!1;const z=ke+1,Z=ke-1,ue=B-1,se=q[ue].states.active,me=q[0].states.active,_e=(Oe=(ae=q[z])==null?void 0:ae.states)==null?void 0:Oe.active,$e=(ge=(we=q[Z])==null?void 0:we.states)==null?void 0:ge.active;return ke===ue&&me||_e?"left":ke===0&&se||$e?"right":!1}function U(){c.value=!0,e.pauseOnHover&&E()}function j(){c.value=!1,$()}function W(){v.value=!1}function L(oe){i(y)||o.value.forEach((ke,ae)=>{oe===D(ke,ae)&&(ke.states.hover=!0)})}function P(){i(y)||o.value.forEach(oe=>{oe.states.hover=!1})}function x(oe){oe!==s.value&&(m.value||(v.value=!0)),s.value=oe}function I(oe){e.trigger==="hover"&&oe!==s.value&&(s.value=oe,m.value||(v.value=!0))}function H(){A(s.value-1)}function G(){A(s.value+1)}function J(){E(),e.pauseOnHover||$()}function ee(oe){e.height==="auto"&&(d.value=oe)}function fe(){var oe;const ke=(oe=l.default)==null?void 0:oe.call(l);if(!ke)return null;const ae=Ca(ke),Oe="ElCarouselItem",we=ae.filter(ge=>Wt(ge)&&ge.type.name===Oe);return(we==null?void 0:we.length)===2&&e.loop&&!g.value?(p.value=!0,we):(p.value=!1,null)}ve(()=>s.value,(oe,ke)=>{M(ke),p.value&&(oe=oe%2,ke=ke%2),ke>-1&&t("change",oe,ke)}),ve(()=>e.autoplay,oe=>{oe?$():E()}),ve(()=>e.loop,()=>{A(s.value)}),ve(()=>e.interval,()=>{J()});const Te=Ut();return at(()=>{ve(()=>o.value,()=>{o.value.length>0&&A(e.initialIndex)},{immediate:!0}),Te.value=Qt(f.value,()=>{M()}),$()}),zt(()=>{E(),f.value&&Te.value&&Te.value.stop()}),yt(Nk,{root:f,isCardType:g,isVertical:y,items:o,loop:e.loop,cardScale:e.cardScale,addItem:r,removeItem:a,setActiveItem:A,setContainerHeight:ee}),{root:f,activeIndex:s,arrowDisplay:h,hasLabel:C,hover:c,isCardType:g,isTransitioning:v,items:o,isVertical:y,containerStyle:_,isItemsTwoLength:p,handleButtonEnter:L,handleTransitionEnd:W,handleButtonLeave:P,handleIndicatorClick:x,handleMouseEnter:U,handleMouseLeave:j,setActiveItem:A,prev:H,next:G,PlaceholderItem:fe,isTwoLengthShow:S,throttledArrowClick:b,throttledIndicatorHover:w}},_5=["aria-label"],C5=["aria-label"],S5=["onMouseenter","onClick"],k5=["aria-label"],E5={key:0},T5={key:3,xmlns:"http://www.w3.org/2000/svg",version:"1.1",style:{display:"none"}},$5=F("defs",null,[F("filter",{id:"elCarouselHorizontal"},[F("feGaussianBlur",{in:"SourceGraphic",stdDeviation:"12,0"})]),F("filter",{id:"elCarouselVertical"},[F("feGaussianBlur",{in:"SourceGraphic",stdDeviation:"0,10"})])],-1),O5=[$5],N5="ElCarousel",I5=Y({name:N5}),M5=Y({...I5,props:b5,emits:y5,setup(e,{expose:t,emit:n}){const o=e,{root:r,activeIndex:a,arrowDisplay:l,hasLabel:s,hover:u,isCardType:c,items:f,isVertical:d,containerStyle:p,handleButtonEnter:m,handleButtonLeave:v,isTransitioning:h,handleIndicatorClick:C,handleMouseEnter:g,handleMouseLeave:y,handleTransitionEnd:_,setActiveItem:b,prev:w,next:S,PlaceholderItem:E,isTwoLengthShow:$,throttledArrowClick:O,throttledIndicatorHover:A}=w5(o,n),M=Se("carousel"),{t:D}=$t(),U=k(()=>{const L=[M.b(),M.m(o.direction)];return i(c)&&L.push(M.m("card")),L}),j=k(()=>{const L=[M.e("container")];return o.motionBlur&&i(h)&&L.push(i(d)?`${M.namespace.value}-transitioning-vertical`:`${M.namespace.value}-transitioning`),L}),W=k(()=>{const L=[M.e("indicators"),M.em("indicators",o.direction)];return i(s)&&L.push(M.em("indicators","labels")),o.indicatorPosition==="outside"&&L.push(M.em("indicators","outside")),i(d)&&L.push(M.em("indicators","right")),L});return t({activeIndex:a,setActiveItem:b,prev:w,next:S}),(L,P)=>(T(),V("div",{ref_key:"root",ref:r,class:N(i(U)),onMouseenter:P[7]||(P[7]=Qe((...x)=>i(g)&&i(g)(...x),["stop"])),onMouseleave:P[8]||(P[8]=Qe((...x)=>i(y)&&i(y)(...x),["stop"]))},[i(l)?(T(),re(fn,{key:0,name:"carousel-arrow-left",persisted:""},{default:X(()=>[tt(F("button",{type:"button",class:N([i(M).e("arrow"),i(M).em("arrow","left")]),"aria-label":i(D)("el.carousel.leftArrow"),onMouseenter:P[0]||(P[0]=x=>i(m)("left")),onMouseleave:P[1]||(P[1]=(...x)=>i(v)&&i(v)(...x)),onClick:P[2]||(P[2]=Qe(x=>i(O)(i(a)-1),["stop"]))},[K(i(ze),null,{default:X(()=>[K(i(Aa))]),_:1})],42,_5),[[kt,(L.arrow==="always"||i(u))&&(o.loop||i(a)>0)]])]),_:1})):te("v-if",!0),i(l)?(T(),re(fn,{key:1,name:"carousel-arrow-right",persisted:""},{default:X(()=>[tt(F("button",{type:"button",class:N([i(M).e("arrow"),i(M).em("arrow","right")]),"aria-label":i(D)("el.carousel.rightArrow"),onMouseenter:P[3]||(P[3]=x=>i(m)("right")),onMouseleave:P[4]||(P[4]=(...x)=>i(v)&&i(v)(...x)),onClick:P[5]||(P[5]=Qe(x=>i(O)(i(a)+1),["stop"]))},[K(i(ze),null,{default:X(()=>[K(i(Jn))]),_:1})],42,C5),[[kt,(L.arrow==="always"||i(u))&&(o.loop||i(a)i(_)&&i(_)(...x))},[K(i(E)),ie(L.$slots,"default")],38),L.indicatorPosition!=="none"?(T(),V("ul",{key:2,class:N(i(W))},[(T(!0),V(Ve,null,bt(i(f),(x,I)=>tt((T(),V("li",{key:I,class:N([i(M).e("indicator"),i(M).em("indicator",L.direction),i(M).is("active",I===i(a))]),onMouseenter:H=>i(A)(I),onClick:Qe(H=>i(C)(I),["stop"])},[F("button",{class:N(i(M).e("button")),"aria-label":i(D)("el.carousel.indicator",{index:I+1})},[i(s)?(T(),V("span",E5,le(x.props.label),1)):te("v-if",!0)],10,k5)],42,S5)),[[kt,i($)(I)]])),128))],2)):te("v-if",!0),o.motionBlur?(T(),V("svg",T5,O5)):te("v-if",!0)],34))}});var A5=Ie(M5,[["__file","carousel.vue"]]);const P5=Ne({name:{type:String,default:""},label:{type:[String,Number],default:""}}),R5=(e,t)=>{const n=De(Nk),o=lt(),r=R(),a=R(!1),l=R(0),s=R(1),u=R(!1),c=R(!1),f=R(!1),d=R(!1),{isCardType:p,isVertical:m,cardScale:v}=n;function h(b,w,S){const E=S-1,$=w-1,O=w+1,A=S/2;return w===0&&b===E?-1:w===E&&b===0?S:b<$&&w-b>=A?S+1:b>O&&b-w>=A?-2:b}function C(b,w){var S,E;const $=i(m)?((S=n.root.value)==null?void 0:S.offsetHeight)||0:((E=n.root.value)==null?void 0:E.offsetWidth)||0;return f.value?$*((2-v)*(b-w)+1)/4:b{var E;const $=i(p),O=(E=n.items.value.length)!=null?E:Number.NaN,A=b===w;!$&&!pn(S)&&(d.value=A||b===S),!A&&O>2&&n.loop&&(b=h(b,w,O));const M=i(m);u.value=A,$?(f.value=Math.round(Math.abs(b-w))<=1,l.value=C(b,w),s.value=i(u)?1:v):l.value=g(b,w,M),c.value=!0,A&&r.value&&n.setContainerHeight(r.value.offsetHeight)};function _(){if(n&&i(p)){const b=n.items.value.findIndex(({uid:w})=>w===o.uid);n.setActiveItem(b)}}return at(()=>{n.addItem({props:e,states:Et({hover:a,translate:l,scale:s,active:u,ready:c,inStage:f,animating:d}),uid:o.uid,translateItem:y})}),lr(()=>{n.removeItem(o.uid)}),{carouselItemRef:r,active:u,animating:d,hover:a,inStage:f,isVertical:m,translate:l,isCardType:p,scale:s,ready:c,handleItemClick:_}},L5=Y({name:"ElCarouselItem"}),x5=Y({...L5,props:P5,setup(e){const t=e,n=Se("carousel"),{carouselItemRef:o,active:r,animating:a,hover:l,inStage:s,isVertical:u,translate:c,isCardType:f,scale:d,ready:p,handleItemClick:m}=R5(t),v=k(()=>[n.e("item"),n.is("active",r.value),n.is("in-stage",s.value),n.is("hover",l.value),n.is("animating",a.value),{[n.em("item","card")]:f.value,[n.em("item","card-vertical")]:f.value&&u.value}]),h=k(()=>{const g=`${`translate${i(u)?"Y":"X"}`}(${i(c)}px)`,y=`scale(${i(d)})`;return{transform:[g,y].join(" ")}});return(C,g)=>tt((T(),V("div",{ref_key:"carouselItemRef",ref:o,class:N(i(v)),style:je(i(h)),onClick:g[0]||(g[0]=(...y)=>i(m)&&i(m)(...y))},[i(f)?tt((T(),V("div",{key:0,class:N(i(n).e("mask"))},null,2)),[[kt,!i(r)]]):te("v-if",!0),ie(C.$slots,"default")],6)),[[kt,i(p)]])}});var Ik=Ie(x5,[["__file","carousel-item.vue"]]);const D5=ut(A5,{CarouselItem:Ik}),F5=tn(Ik),Mk={modelValue:{type:[Number,String,Boolean],default:void 0},label:{type:[String,Boolean,Number,Object],default:void 0},value:{type:[String,Boolean,Number,Object],default:void 0},indeterminate:Boolean,disabled:Boolean,checked:Boolean,name:{type:String,default:void 0},trueValue:{type:[String,Number],default:void 0},falseValue:{type:[String,Number],default:void 0},trueLabel:{type:[String,Number],default:void 0},falseLabel:{type:[String,Number],default:void 0},id:{type:String,default:void 0},controls:{type:String,default:void 0},border:Boolean,size:gn,tabindex:[String,Number],validateEvent:{type:Boolean,default:!0},...An(["ariaControls"])},Ak={[ft]:e=>nt(e)||Je(e)||dn(e),change:e=>nt(e)||Je(e)||dn(e)},ti=Symbol("checkboxGroupContextKey"),B5=({model:e,isChecked:t})=>{const n=De(ti,void 0),o=k(()=>{var a,l;const s=(a=n==null?void 0:n.max)==null?void 0:a.value,u=(l=n==null?void 0:n.min)==null?void 0:l.value;return!pn(s)&&e.value.length>=s&&!t.value||!pn(u)&&e.value.length<=u&&t.value});return{isDisabled:to(k(()=>(n==null?void 0:n.disabled.value)||o.value)),isLimitDisabled:o}},V5=(e,{model:t,isLimitExceeded:n,hasOwnLabel:o,isDisabled:r,isLabeledByFormItem:a})=>{const l=De(ti,void 0),{formItem:s}=qn(),{emit:u}=lt();function c(v){var h,C,g,y;return[!0,e.trueValue,e.trueLabel].includes(v)?(C=(h=e.trueValue)!=null?h:e.trueLabel)!=null?C:!0:(y=(g=e.falseValue)!=null?g:e.falseLabel)!=null?y:!1}function f(v,h){u("change",c(v),h)}function d(v){if(n.value)return;const h=v.target;u("change",c(h.checked),v)}async function p(v){n.value||!o.value&&!r.value&&a.value&&(v.composedPath().some(g=>g.tagName==="LABEL")||(t.value=c([!1,e.falseValue,e.falseLabel].includes(t.value)),await We(),f(t.value,v)))}const m=k(()=>(l==null?void 0:l.validateEvent)||e.validateEvent);return ve(()=>e.modelValue,()=>{m.value&&(s==null||s.validate("change").catch(v=>void 0))}),{handleChange:d,onClickRoot:p}},H5=e=>{const t=R(!1),{emit:n}=lt(),o=De(ti,void 0),r=k(()=>pn(o)===!1),a=R(!1),l=k({get(){var s,u;return r.value?(s=o==null?void 0:o.modelValue)==null?void 0:s.value:(u=e.modelValue)!=null?u:t.value},set(s){var u,c;r.value&&Pe(s)?(a.value=((u=o==null?void 0:o.max)==null?void 0:u.value)!==void 0&&s.length>(o==null?void 0:o.max.value)&&s.length>l.value.length,a.value===!1&&((c=o==null?void 0:o.changeEvent)==null||c.call(o,s))):(n(ft,s),t.value=s)}});return{model:l,isGroup:r,isLimitExceeded:a}},z5=(e,t,{model:n})=>{const o=De(ti,void 0),r=R(!1),a=k(()=>Sl(e.value)?e.label:e.value),l=k(()=>{const f=n.value;return dn(f)?f:Pe(f)?dt(a.value)?f.map(Mt).some(d=>Wn(d,a.value)):f.map(Mt).includes(a.value):f!=null?f===e.trueValue||f===e.trueLabel:!!f}),s=hn(k(()=>{var f;return(f=o==null?void 0:o.size)==null?void 0:f.value}),{prop:!0}),u=hn(k(()=>{var f;return(f=o==null?void 0:o.size)==null?void 0:f.value})),c=k(()=>!!t.default||!Sl(a.value));return{checkboxButtonSize:s,isChecked:l,isFocused:r,checkboxSize:u,hasOwnLabel:c,actualValue:a}},Pk=(e,t)=>{const{formItem:n}=qn(),{model:o,isGroup:r,isLimitExceeded:a}=H5(e),{isFocused:l,isChecked:s,checkboxButtonSize:u,checkboxSize:c,hasOwnLabel:f,actualValue:d}=z5(e,t,{model:o}),{isDisabled:p}=B5({model:o,isChecked:s}),{inputId:m,isLabeledByFormItem:v}=cr(e,{formItemContext:n,disableIdGeneration:f,disableIdManagement:r}),{handleChange:h,onClickRoot:C}=V5(e,{model:o,isLimitExceeded:a,hasOwnLabel:f,isDisabled:p,isLabeledByFormItem:v});return(()=>{function y(){var _,b;Pe(o.value)&&!o.value.includes(d.value)?o.value.push(d.value):o.value=(b=(_=e.trueValue)!=null?_:e.trueLabel)!=null?b:!0}e.checked&&y()})(),wn({from:"controls",replacement:"aria-controls",version:"2.8.0",scope:"el-checkbox",ref:"https://element-plus.org/en-US/component/checkbox.html"},k(()=>!!e.controls)),wn({from:"label act as value",replacement:"value",version:"3.0.0",scope:"el-checkbox",ref:"https://element-plus.org/en-US/component/checkbox.html"},k(()=>r.value&&Sl(e.value))),wn({from:"true-label",replacement:"true-value",version:"3.0.0",scope:"el-checkbox",ref:"https://element-plus.org/en-US/component/checkbox.html"},k(()=>!!e.trueLabel)),wn({from:"false-label",replacement:"false-value",version:"3.0.0",scope:"el-checkbox",ref:"https://element-plus.org/en-US/component/checkbox.html"},k(()=>!!e.falseLabel)),{inputId:m,isLabeledByFormItem:v,isChecked:s,isDisabled:p,isFocused:l,checkboxButtonSize:u,checkboxSize:c,hasOwnLabel:f,model:o,actualValue:d,handleChange:h,onClickRoot:C}},j5=["id","indeterminate","name","tabindex","disabled","true-value","false-value"],W5=["id","indeterminate","disabled","value","name","tabindex"],K5=Y({name:"ElCheckbox"}),U5=Y({...K5,props:Mk,emits:Ak,setup(e){const t=e,n=Sn(),{inputId:o,isLabeledByFormItem:r,isChecked:a,isDisabled:l,isFocused:s,checkboxSize:u,hasOwnLabel:c,model:f,actualValue:d,handleChange:p,onClickRoot:m}=Pk(t,n),v=Se("checkbox"),h=k(()=>[v.b(),v.m(u.value),v.is("disabled",l.value),v.is("bordered",t.border),v.is("checked",a.value)]),C=k(()=>[v.e("input"),v.is("disabled",l.value),v.is("checked",a.value),v.is("indeterminate",t.indeterminate),v.is("focus",s.value)]);return(g,y)=>(T(),re(pt(!i(c)&&i(r)?"span":"label"),{class:N(i(h)),"aria-controls":g.indeterminate?g.controls||g.ariaControls:null,onClick:i(m)},{default:X(()=>{var _,b;return[F("span",{class:N(i(C))},[g.trueValue||g.falseValue||g.trueLabel||g.falseLabel?tt((T(),V("input",{key:0,id:i(o),"onUpdate:modelValue":y[0]||(y[0]=w=>xt(f)?f.value=w:null),class:N(i(v).e("original")),type:"checkbox",indeterminate:g.indeterminate,name:g.name,tabindex:g.tabindex,disabled:i(l),"true-value":(_=g.trueValue)!=null?_:g.trueLabel,"false-value":(b=g.falseValue)!=null?b:g.falseLabel,onChange:y[1]||(y[1]=(...w)=>i(p)&&i(p)(...w)),onFocus:y[2]||(y[2]=w=>s.value=!0),onBlur:y[3]||(y[3]=w=>s.value=!1),onClick:y[4]||(y[4]=Qe(()=>{},["stop"]))},null,42,j5)),[[wl,i(f)]]):tt((T(),V("input",{key:1,id:i(o),"onUpdate:modelValue":y[5]||(y[5]=w=>xt(f)?f.value=w:null),class:N(i(v).e("original")),type:"checkbox",indeterminate:g.indeterminate,disabled:i(l),value:i(d),name:g.name,tabindex:g.tabindex,onChange:y[6]||(y[6]=(...w)=>i(p)&&i(p)(...w)),onFocus:y[7]||(y[7]=w=>s.value=!0),onBlur:y[8]||(y[8]=w=>s.value=!1),onClick:y[9]||(y[9]=Qe(()=>{},["stop"]))},null,42,W5)),[[wl,i(f)]]),F("span",{class:N(i(v).e("inner"))},null,2)],2),i(c)?(T(),V("span",{key:0,class:N(i(v).e("label"))},[ie(g.$slots,"default"),g.$slots.default?te("v-if",!0):(T(),V(Ve,{key:0},[Ge(le(g.label),1)],64))],2)):te("v-if",!0)]}),_:3},8,["class","aria-controls","onClick"]))}});var q5=Ie(U5,[["__file","checkbox.vue"]]);const Y5=["name","tabindex","disabled","true-value","false-value"],G5=["name","tabindex","disabled","value"],X5=Y({name:"ElCheckboxButton"}),J5=Y({...X5,props:Mk,emits:Ak,setup(e){const t=e,n=Sn(),{isFocused:o,isChecked:r,isDisabled:a,checkboxButtonSize:l,model:s,actualValue:u,handleChange:c}=Pk(t,n),f=De(ti,void 0),d=Se("checkbox"),p=k(()=>{var v,h,C,g;const y=(h=(v=f==null?void 0:f.fill)==null?void 0:v.value)!=null?h:"";return{backgroundColor:y,borderColor:y,color:(g=(C=f==null?void 0:f.textColor)==null?void 0:C.value)!=null?g:"",boxShadow:y?`-1px 0 0 0 ${y}`:void 0}}),m=k(()=>[d.b("button"),d.bm("button",l.value),d.is("disabled",a.value),d.is("checked",r.value),d.is("focus",o.value)]);return(v,h)=>{var C,g;return T(),V("label",{class:N(i(m))},[v.trueValue||v.falseValue||v.trueLabel||v.falseLabel?tt((T(),V("input",{key:0,"onUpdate:modelValue":h[0]||(h[0]=y=>xt(s)?s.value=y:null),class:N(i(d).be("button","original")),type:"checkbox",name:v.name,tabindex:v.tabindex,disabled:i(a),"true-value":(C=v.trueValue)!=null?C:v.trueLabel,"false-value":(g=v.falseValue)!=null?g:v.falseLabel,onChange:h[1]||(h[1]=(...y)=>i(c)&&i(c)(...y)),onFocus:h[2]||(h[2]=y=>o.value=!0),onBlur:h[3]||(h[3]=y=>o.value=!1),onClick:h[4]||(h[4]=Qe(()=>{},["stop"]))},null,42,Y5)),[[wl,i(s)]]):tt((T(),V("input",{key:1,"onUpdate:modelValue":h[5]||(h[5]=y=>xt(s)?s.value=y:null),class:N(i(d).be("button","original")),type:"checkbox",name:v.name,tabindex:v.tabindex,disabled:i(a),value:i(u),onChange:h[6]||(h[6]=(...y)=>i(c)&&i(c)(...y)),onFocus:h[7]||(h[7]=y=>o.value=!0),onBlur:h[8]||(h[8]=y=>o.value=!1),onClick:h[9]||(h[9]=Qe(()=>{},["stop"]))},null,42,G5)),[[wl,i(s)]]),v.$slots.default||v.label?(T(),V("span",{key:2,class:N(i(d).be("button","inner")),style:je(i(r)?i(p):void 0)},[ie(v.$slots,"default",{},()=>[Ge(le(v.label),1)])],6)):te("v-if",!0)],2)}}});var Rk=Ie(J5,[["__file","checkbox-button.vue"]]);const Z5=Ne({modelValue:{type:Q(Array),default:()=>[]},disabled:Boolean,min:Number,max:Number,size:gn,label:String,fill:String,textColor:String,tag:{type:String,default:"div"},validateEvent:{type:Boolean,default:!0},...An(["ariaLabel"])}),Q5={[ft]:e=>Pe(e),change:e=>Pe(e)},eH=Y({name:"ElCheckboxGroup"}),tH=Y({...eH,props:Z5,emits:Q5,setup(e,{emit:t}){const n=e,o=Se("checkbox"),{formItem:r}=qn(),{inputId:a,isLabeledByFormItem:l}=cr(n,{formItemContext:r}),s=async c=>{t(ft,c),await We(),t("change",c)},u=k({get(){return n.modelValue},set(c){s(c)}});return yt(ti,{...gr(Cn(n),["size","min","max","disabled","validateEvent","fill","textColor"]),modelValue:u,changeEvent:s}),wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-checkbox-group",ref:"https://element-plus.org/en-US/component/checkbox.html"},k(()=>!!n.label)),ve(()=>n.modelValue,()=>{n.validateEvent&&(r==null||r.validate("change").catch(c=>void 0))}),(c,f)=>{var d;return T(),re(pt(c.tag),{id:i(a),class:N(i(o).b("group")),role:"group","aria-label":i(l)?void 0:c.label||c.ariaLabel||"checkbox-group","aria-labelledby":i(l)?(d=i(r))==null?void 0:d.labelId:void 0},{default:X(()=>[ie(c.$slots,"default")]),_:3},8,["id","class","aria-label","aria-labelledby"])}}});var Lk=Ie(tH,[["__file","checkbox-group.vue"]]);const Ho=ut(q5,{CheckboxButton:Rk,CheckboxGroup:Lk}),nH=tn(Rk),xk=tn(Lk),Dk=Ne({modelValue:{type:[String,Number,Boolean],default:void 0},size:gn,disabled:Boolean,label:{type:[String,Number,Boolean],default:void 0},value:{type:[String,Number,Boolean],default:void 0},name:{type:String,default:void 0}}),oH=Ne({...Dk,border:Boolean}),Fk={[ft]:e=>nt(e)||Je(e)||dn(e),[Yt]:e=>nt(e)||Je(e)||dn(e)},Bk=Symbol("radioGroupKey"),Vk=(e,t)=>{const n=R(),o=De(Bk,void 0),r=k(()=>!!o),a=k(()=>Sl(e.value)?e.label:e.value),l=k({get(){return r.value?o.modelValue:e.modelValue},set(d){r.value?o.changeEvent(d):t&&t(ft,d),n.value.checked=e.modelValue===a.value}}),s=hn(k(()=>o==null?void 0:o.size)),u=to(k(()=>o==null?void 0:o.disabled)),c=R(!1),f=k(()=>u.value||r.value&&l.value!==a.value?-1:0);return wn({from:"label act as value",replacement:"value",version:"3.0.0",scope:"el-radio",ref:"https://element-plus.org/en-US/component/radio.html"},k(()=>r.value&&Sl(e.value))),{radioRef:n,isGroup:r,radioGroup:o,focus:c,size:s,disabled:u,tabIndex:f,modelValue:l,actualValue:a}},rH=["value","name","disabled"],aH=Y({name:"ElRadio"}),lH=Y({...aH,props:oH,emits:Fk,setup(e,{emit:t}){const n=e,o=Se("radio"),{radioRef:r,radioGroup:a,focus:l,size:s,disabled:u,modelValue:c,actualValue:f}=Vk(n,t);function d(){We(()=>t("change",c.value))}return(p,m)=>{var v;return T(),V("label",{class:N([i(o).b(),i(o).is("disabled",i(u)),i(o).is("focus",i(l)),i(o).is("bordered",p.border),i(o).is("checked",i(c)===i(f)),i(o).m(i(s))])},[F("span",{class:N([i(o).e("input"),i(o).is("disabled",i(u)),i(o).is("checked",i(c)===i(f))])},[tt(F("input",{ref_key:"radioRef",ref:r,"onUpdate:modelValue":m[0]||(m[0]=h=>xt(c)?c.value=h:null),class:N(i(o).e("original")),value:i(f),name:p.name||((v=i(a))==null?void 0:v.name),disabled:i(u),type:"radio",onFocus:m[1]||(m[1]=h=>l.value=!0),onBlur:m[2]||(m[2]=h=>l.value=!1),onChange:d,onClick:m[3]||(m[3]=Qe(()=>{},["stop"]))},null,42,rH),[[Eu,i(c)]]),F("span",{class:N(i(o).e("inner"))},null,2)],2),F("span",{class:N(i(o).e("label")),onKeydown:m[4]||(m[4]=Qe(()=>{},["stop"]))},[ie(p.$slots,"default",{},()=>[Ge(le(p.label),1)])],34)],2)}}});var sH=Ie(lH,[["__file","radio.vue"]]);const iH=Ne({...Dk}),uH=["value","name","disabled"],cH=Y({name:"ElRadioButton"}),dH=Y({...cH,props:iH,setup(e){const t=e,n=Se("radio"),{radioRef:o,focus:r,size:a,disabled:l,modelValue:s,radioGroup:u,actualValue:c}=Vk(t),f=k(()=>({backgroundColor:(u==null?void 0:u.fill)||"",borderColor:(u==null?void 0:u.fill)||"",boxShadow:u!=null&&u.fill?`-1px 0 0 0 ${u.fill}`:"",color:(u==null?void 0:u.textColor)||""}));return(d,p)=>{var m;return T(),V("label",{class:N([i(n).b("button"),i(n).is("active",i(s)===i(c)),i(n).is("disabled",i(l)),i(n).is("focus",i(r)),i(n).bm("button",i(a))])},[tt(F("input",{ref_key:"radioRef",ref:o,"onUpdate:modelValue":p[0]||(p[0]=v=>xt(s)?s.value=v:null),class:N(i(n).be("button","original-radio")),value:i(c),type:"radio",name:d.name||((m=i(u))==null?void 0:m.name),disabled:i(l),onFocus:p[1]||(p[1]=v=>r.value=!0),onBlur:p[2]||(p[2]=v=>r.value=!1),onClick:p[3]||(p[3]=Qe(()=>{},["stop"]))},null,42,uH),[[Eu,i(s)]]),F("span",{class:N(i(n).be("button","inner")),style:je(i(s)===i(c)?i(f):{}),onKeydown:p[4]||(p[4]=Qe(()=>{},["stop"]))},[ie(d.$slots,"default",{},()=>[Ge(le(d.label),1)])],38)],2)}}});var Hk=Ie(dH,[["__file","radio-button.vue"]]);const fH=Ne({id:{type:String,default:void 0},size:gn,disabled:Boolean,modelValue:{type:[String,Number,Boolean],default:void 0},fill:{type:String,default:""},label:{type:String,default:void 0},textColor:{type:String,default:""},name:{type:String,default:void 0},validateEvent:{type:Boolean,default:!0},...An(["ariaLabel"])}),pH=Fk,hH=["id","aria-label","aria-labelledby"],mH=Y({name:"ElRadioGroup"}),vH=Y({...mH,props:fH,emits:pH,setup(e,{emit:t}){const n=e,o=Se("radio"),r=xn(),a=R(),{formItem:l}=qn(),{inputId:s,isLabeledByFormItem:u}=cr(n,{formItemContext:l}),c=d=>{t(ft,d),We(()=>t("change",d))};at(()=>{const d=a.value.querySelectorAll("[type=radio]"),p=d[0];!Array.from(d).some(m=>m.checked)&&p&&(p.tabIndex=0)});const f=k(()=>n.name||r.value);return yt(Bk,Et({...Cn(n),changeEvent:c,name:f})),ve(()=>n.modelValue,()=>{n.validateEvent&&(l==null||l.validate("change").catch(d=>void 0))}),wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-radio-group",ref:"https://element-plus.org/en-US/component/radio.html"},k(()=>!!n.label)),(d,p)=>(T(),V("div",{id:i(s),ref_key:"radioGroupRef",ref:a,class:N(i(o).b("group")),role:"radiogroup","aria-label":i(u)?void 0:d.label||d.ariaLabel||"radio-group","aria-labelledby":i(u)?i(l).labelId:void 0},[ie(d.$slots,"default")],10,hH))}});var zk=Ie(vH,[["__file","radio-group.vue"]]);const jk=ut(sH,{RadioButton:Hk,RadioGroup:zk}),gH=tn(zk),bH=tn(Hk);var yH=Y({name:"NodeContent",setup(){return{ns:Se("cascader-node")}},render(){const{ns:e}=this,{node:t,panel:n}=this.$parent,{data:o,label:r}=t,{renderLabelFn:a}=n;return Ke("span",{class:e.e("label")},a?a({node:t,data:o}):r)}});const cg=Symbol(),wH=Y({name:"ElCascaderNode",components:{ElCheckbox:Ho,ElRadio:jk,NodeContent:yH,ElIcon:ze,Check:Mu,Loading:Er,ArrowRight:Jn},props:{node:{type:Object,required:!0},menuId:String},emits:["expand"],setup(e,{emit:t}){const n=De(cg),o=Se("cascader-node"),r=k(()=>n.isHoverMenu),a=k(()=>n.config.multiple),l=k(()=>n.config.checkStrictly),s=k(()=>{var S;return(S=n.checkedNodes[0])==null?void 0:S.uid}),u=k(()=>e.node.isDisabled),c=k(()=>e.node.isLeaf),f=k(()=>l.value&&!c.value||!u.value),d=k(()=>m(n.expandingNode)),p=k(()=>l.value&&n.checkedNodes.some(m)),m=S=>{var E;const{level:$,uid:O}=e.node;return((E=S==null?void 0:S.pathNodes[$-1])==null?void 0:E.uid)===O},v=()=>{d.value||n.expandNode(e.node)},h=S=>{const{node:E}=e;S!==E.checked&&n.handleCheckChange(E,S)},C=()=>{n.lazyLoad(e.node,()=>{c.value||v()})},g=S=>{r.value&&(y(),!c.value&&t("expand",S))},y=()=>{const{node:S}=e;!f.value||S.loading||(S.loaded?v():C())},_=()=>{r.value&&!c.value||(c.value&&!u.value&&!l.value&&!a.value?w(!0):y())},b=S=>{l.value?(h(S),e.node.loaded&&v()):w(S)},w=S=>{e.node.loaded?(h(S),!l.value&&v()):C()};return{panel:n,isHoverMenu:r,multiple:a,checkStrictly:l,checkedNodeId:s,isDisabled:u,isLeaf:c,expandable:f,inExpandingPath:d,inCheckedPath:p,ns:o,handleHoverExpand:g,handleExpand:y,handleClick:_,handleCheck:w,handleSelectCheck:b}}}),_H=["id","aria-haspopup","aria-owns","aria-expanded","tabindex"],CH=F("span",null,null,-1);function SH(e,t,n,o,r,a){const l=qe("el-checkbox"),s=qe("el-radio"),u=qe("check"),c=qe("el-icon"),f=qe("node-content"),d=qe("loading"),p=qe("arrow-right");return T(),V("li",{id:`${e.menuId}-${e.node.uid}`,role:"menuitem","aria-haspopup":!e.isLeaf,"aria-owns":e.isLeaf?null:e.menuId,"aria-expanded":e.inExpandingPath,tabindex:e.expandable?-1:void 0,class:N([e.ns.b(),e.ns.is("selectable",e.checkStrictly),e.ns.is("active",e.node.checked),e.ns.is("disabled",!e.expandable),e.inExpandingPath&&"in-active-path",e.inCheckedPath&&"in-checked-path"]),onMouseenter:t[2]||(t[2]=(...m)=>e.handleHoverExpand&&e.handleHoverExpand(...m)),onFocus:t[3]||(t[3]=(...m)=>e.handleHoverExpand&&e.handleHoverExpand(...m)),onClick:t[4]||(t[4]=(...m)=>e.handleClick&&e.handleClick(...m))},[te(" prefix "),e.multiple?(T(),re(l,{key:0,"model-value":e.node.checked,indeterminate:e.node.indeterminate,disabled:e.isDisabled,onClick:t[0]||(t[0]=Qe(()=>{},["stop"])),"onUpdate:modelValue":e.handleSelectCheck},null,8,["model-value","indeterminate","disabled","onUpdate:modelValue"])):e.checkStrictly?(T(),re(s,{key:1,"model-value":e.checkedNodeId,label:e.node.uid,disabled:e.isDisabled,"onUpdate:modelValue":e.handleSelectCheck,onClick:t[1]||(t[1]=Qe(()=>{},["stop"]))},{default:X(()=>[te(` + Add an empty element to avoid render label, + do not use empty fragment here for https://github.com/vuejs/vue-next/pull/2485 + `),CH]),_:1},8,["model-value","label","disabled","onUpdate:modelValue"])):e.isLeaf&&e.node.checked?(T(),re(c,{key:2,class:N(e.ns.e("prefix"))},{default:X(()=>[K(u)]),_:1},8,["class"])):te("v-if",!0),te(" content "),K(f),te(" postfix "),e.isLeaf?te("v-if",!0):(T(),V(Ve,{key:3},[e.node.loading?(T(),re(c,{key:0,class:N([e.ns.is("loading"),e.ns.e("postfix")])},{default:X(()=>[K(d)]),_:1},8,["class"])):(T(),re(c,{key:1,class:N(["arrow-right",e.ns.e("postfix")])},{default:X(()=>[K(p)]),_:1},8,["class"]))],64))],42,_H)}var kH=Ie(wH,[["render",SH],["__file","node.vue"]]);const EH=Y({name:"ElCascaderMenu",components:{Loading:Er,ElIcon:ze,ElScrollbar:ea,ElCascaderNode:kH},props:{nodes:{type:Array,required:!0},index:{type:Number,required:!0}},setup(e){const t=lt(),n=Se("cascader-menu"),{t:o}=$t(),r=xn();let a=null,l=null;const s=De(cg),u=R(null),c=k(()=>!e.nodes.length),f=k(()=>!s.initialLoaded),d=k(()=>`${r.value}-${e.index}`),p=C=>{a=C.target},m=C=>{if(!(!s.isHoverMenu||!a||!u.value))if(a.contains(C.target)){v();const g=t.vnode.el,{left:y}=g.getBoundingClientRect(),{offsetWidth:_,offsetHeight:b}=g,w=C.clientX-y,S=a.offsetTop,E=S+a.offsetHeight;u.value.innerHTML=` + + + `}else l||(l=window.setTimeout(h,s.config.hoverThreshold))},v=()=>{l&&(clearTimeout(l),l=null)},h=()=>{u.value&&(u.value.innerHTML="",v())};return{ns:n,panel:s,hoverZone:u,isEmpty:c,isLoading:f,menuId:d,t:o,handleExpand:p,handleMouseMove:m,clearHoverZone:h}}});function TH(e,t,n,o,r,a){const l=qe("el-cascader-node"),s=qe("loading"),u=qe("el-icon"),c=qe("el-scrollbar");return T(),re(c,{key:e.menuId,tag:"ul",role:"menu",class:N(e.ns.b()),"wrap-class":e.ns.e("wrap"),"view-class":[e.ns.e("list"),e.ns.is("empty",e.isEmpty)],onMousemove:e.handleMouseMove,onMouseleave:e.clearHoverZone},{default:X(()=>{var f;return[(T(!0),V(Ve,null,bt(e.nodes,d=>(T(),re(l,{key:d.uid,node:d,"menu-id":e.menuId,onExpand:e.handleExpand},null,8,["node","menu-id","onExpand"]))),128)),e.isLoading?(T(),V("div",{key:0,class:N(e.ns.e("empty-text"))},[K(u,{size:"14",class:N(e.ns.is("loading"))},{default:X(()=>[K(s)]),_:1},8,["class"]),Ge(" "+le(e.t("el.cascader.loading")),1)],2)):e.isEmpty?(T(),V("div",{key:1,class:N(e.ns.e("empty-text"))},le(e.t("el.cascader.noData")),3)):(f=e.panel)!=null&&f.isHoverMenu?(T(),V("svg",{key:2,ref:"hoverZone",class:N(e.ns.e("hover-zone"))},null,2)):te("v-if",!0)]}),_:1},8,["class","wrap-class","view-class","onMousemove","onMouseleave"])}var $H=Ie(EH,[["render",TH],["__file","menu.vue"]]);let OH=0;const NH=e=>{const t=[e];let{parent:n}=e;for(;n;)t.unshift(n),n=n.parent;return t};let zh=class jh{constructor(t,n,o,r=!1){this.data=t,this.config=n,this.parent=o,this.root=r,this.uid=OH++,this.checked=!1,this.indeterminate=!1,this.loading=!1;const{value:a,label:l,children:s}=n,u=t[s],c=NH(this);this.level=r?0:o?o.level+1:1,this.value=t[a],this.label=t[l],this.pathNodes=c,this.pathValues=c.map(f=>f.value),this.pathLabels=c.map(f=>f.label),this.childrenData=u,this.children=(u||[]).map(f=>new jh(f,n,this)),this.loaded=!n.lazy||this.isLeaf||!Io(u)}get isDisabled(){const{data:t,parent:n,config:o}=this,{disabled:r,checkStrictly:a}=o;return(Xe(r)?r(t,this):!!t[r])||!a&&(n==null?void 0:n.isDisabled)}get isLeaf(){const{data:t,config:n,childrenData:o,loaded:r}=this,{lazy:a,leaf:l}=n,s=Xe(l)?l(t,this):t[l];return pn(s)?a&&!r?!1:!(Array.isArray(o)&&o.length):!!s}get valueByOption(){return this.config.emitPath?this.pathValues:this.value}appendChild(t){const{childrenData:n,children:o}=this,r=new jh(t,this.config,this);return Array.isArray(n)?n.push(t):this.childrenData=[t],o.push(r),r}calcText(t,n){const o=t?this.pathLabels.join(n):this.label;return this.text=o,o}broadcast(t,...n){const o=`onParent${mr(t)}`;this.children.forEach(r=>{r&&(r.broadcast(t,...n),r[o]&&r[o](...n))})}emit(t,...n){const{parent:o}=this,r=`onChild${mr(t)}`;o&&(o[r]&&o[r](...n),o.emit(t,...n))}onParentCheck(t){this.isDisabled||this.setCheckState(t)}onChildCheck(){const{children:t}=this,n=t.filter(r=>!r.isDisabled),o=n.length?n.every(r=>r.checked):!1;this.setCheckState(o)}setCheckState(t){const n=this.children.length,o=this.children.reduce((r,a)=>{const l=a.checked?1:a.indeterminate?.5:0;return r+l},0);this.checked=this.loaded&&this.children.filter(r=>!r.isDisabled).every(r=>r.loaded&&r.checked)&&t,this.indeterminate=this.loaded&&o!==n&&o>0}doCheck(t){if(this.checked===t)return;const{checkStrictly:n,multiple:o}=this.config;n||!o?this.checked=t:(this.broadcast("check",t),this.setCheckState(t),this.emit("check"))}};const Wh=(e,t)=>e.reduce((n,o)=>(o.isLeaf?n.push(o):(!t&&n.push(o),n=n.concat(Wh(o.children,t))),n),[]);class Y0{constructor(t,n){this.config=n;const o=(t||[]).map(r=>new zh(r,this.config));this.nodes=o,this.allNodes=Wh(o,!1),this.leafNodes=Wh(o,!0)}getNodes(){return this.nodes}getFlattedNodes(t){return t?this.leafNodes:this.allNodes}appendNode(t,n){const o=n?n.appendChild(t):new zh(t,this.config);n||this.nodes.push(o),this.allNodes.push(o),o.isLeaf&&this.leafNodes.push(o)}appendNodes(t,n){t.forEach(o=>this.appendNode(o,n))}getNodeByValue(t,n=!1){return!t&&t!==0?null:this.getFlattedNodes(n).find(r=>Wn(r.value,t)||Wn(r.pathValues,t))||null}getSameNode(t){return t&&this.getFlattedNodes(!1).find(({value:o,level:r})=>Wn(t.value,o)&&t.level===r)||null}}const Wk=Ne({modelValue:{type:Q([Number,String,Array])},options:{type:Q(Array),default:()=>[]},props:{type:Q(Object),default:()=>({})}}),IH={expandTrigger:"click",multiple:!1,checkStrictly:!1,emitPath:!0,lazy:!1,lazyLoad:Bt,value:"value",label:"label",children:"children",leaf:"leaf",disabled:"disabled",hoverThreshold:500},MH=e=>k(()=>({...IH,...e.props})),G0=e=>{if(!e)return 0;const t=e.id.split("-");return Number(t[t.length-2])},AH=e=>{if(!e)return;const t=e.querySelector("input");t?t.click():G_(e)&&e.click()},PH=(e,t)=>{const n=t.slice(0),o=n.map(a=>a.uid),r=e.reduce((a,l)=>{const s=o.indexOf(l.uid);return s>-1&&(a.push(l),n.splice(s,1),o.splice(s,1)),a},[]);return r.push(...n),r},RH=Y({name:"ElCascaderPanel",components:{ElCascaderMenu:$H},props:{...Wk,border:{type:Boolean,default:!0},renderLabel:Function},emits:[ft,Yt,"close","expand-change"],setup(e,{emit:t,slots:n}){let o=!1;const r=Se("cascader"),a=MH(e);let l=null;const s=R(!0),u=R([]),c=R(null),f=R([]),d=R(null),p=R([]),m=k(()=>a.value.expandTrigger==="hover"),v=k(()=>e.renderLabel||n.default),h=()=>{const{options:D}=e,U=a.value;o=!1,l=new Y0(D,U),f.value=[l.getNodes()],U.lazy&&Io(e.options)?(s.value=!1,C(void 0,j=>{j&&(l=new Y0(j,U),f.value=[l.getNodes()]),s.value=!0,$(!1,!0)})):$(!1,!0)},C=(D,U)=>{const j=a.value;D=D||new zh({},j,void 0,!0),D.loading=!0;const W=L=>{const P=D,x=P.root?null:P;L&&(l==null||l.appendNodes(L,x)),P.loading=!1,P.loaded=!0,P.childrenData=P.childrenData||[],U&&U(L)};j.lazyLoad(D,W)},g=(D,U)=>{var j;const{level:W}=D,L=f.value.slice(0,W);let P;D.isLeaf?P=D.pathNodes[W-2]:(P=D,L.push(D.children)),((j=d.value)==null?void 0:j.uid)!==(P==null?void 0:P.uid)&&(d.value=D,f.value=L,!U&&t("expand-change",(D==null?void 0:D.pathValues)||[]))},y=(D,U,j=!0)=>{const{checkStrictly:W,multiple:L}=a.value,P=p.value[0];o=!0,!L&&(P==null||P.doCheck(!1)),D.doCheck(U),E(),j&&!L&&!W&&t("close"),!j&&!L&&!W&&_(D)},_=D=>{D&&(D=D.parent,_(D),D&&g(D))},b=D=>l==null?void 0:l.getFlattedNodes(D),w=D=>{var U;return(U=b(D))==null?void 0:U.filter(j=>j.checked!==!1)},S=()=>{p.value.forEach(D=>D.doCheck(!1)),E(),f.value=f.value.slice(0,1),d.value=null,t("expand-change",[])},E=()=>{var D;const{checkStrictly:U,multiple:j}=a.value,W=p.value,L=w(!U),P=PH(W,L),x=P.map(I=>I.valueByOption);p.value=P,c.value=j?x:(D=x[0])!=null?D:null},$=(D=!1,U=!1)=>{const{modelValue:j}=e,{lazy:W,multiple:L,checkStrictly:P}=a.value,x=!P;if(!(!s.value||o||!U&&Wn(j,c.value)))if(W&&!D){const H=qy(Ix(Vn(j))).map(G=>l==null?void 0:l.getNodeByValue(G)).filter(G=>!!G&&!G.loaded&&!G.loading);H.length?H.forEach(G=>{C(G,()=>$(!1,U))}):$(!0,U)}else{const I=L?Vn(j):[j],H=qy(I.map(G=>l==null?void 0:l.getNodeByValue(G,x)));O(H,U),c.value=pd(j)}},O=(D,U=!0)=>{const{checkStrictly:j}=a.value,W=p.value,L=D.filter(I=>!!I&&(j||I.isLeaf)),P=l==null?void 0:l.getSameNode(d.value),x=U&&P||L[0];x?x.pathNodes.forEach(I=>g(I,!0)):d.value=null,W.forEach(I=>I.doCheck(!1)),Et(L).forEach(I=>I.doCheck(!0)),p.value=L,We(A)},A=()=>{Ct&&u.value.forEach(D=>{const U=D==null?void 0:D.$el;if(U){const j=U.querySelector(`.${r.namespace.value}-scrollbar__wrap`),W=U.querySelector(`.${r.b("node")}.${r.is("active")}`)||U.querySelector(`.${r.b("node")}.in-active-path`);KC(j,W)}})},M=D=>{const U=D.target,{code:j}=D;switch(j){case Ue.up:case Ue.down:{D.preventDefault();const W=j===Ue.up?-1:1;Ic(X_(U,W,`.${r.b("node")}[tabindex="-1"]`));break}case Ue.left:{D.preventDefault();const W=u.value[G0(U)-1],L=W==null?void 0:W.$el.querySelector(`.${r.b("node")}[aria-expanded="true"]`);Ic(L);break}case Ue.right:{D.preventDefault();const W=u.value[G0(U)+1],L=W==null?void 0:W.$el.querySelector(`.${r.b("node")}[tabindex="-1"]`);Ic(L);break}case Ue.enter:AH(U);break}};return yt(cg,Et({config:a,expandingNode:d,checkedNodes:p,isHoverMenu:m,initialLoaded:s,renderLabelFn:v,lazyLoad:C,expandNode:g,handleCheckChange:y})),ve([a,()=>e.options],h,{deep:!0,immediate:!0}),ve(()=>e.modelValue,()=>{o=!1,$()},{deep:!0}),ve(()=>c.value,D=>{Wn(D,e.modelValue)||(t(ft,D),t(Yt,D))}),ev(()=>u.value=[]),at(()=>!Io(e.modelValue)&&$()),{ns:r,menuList:u,menus:f,checkedNodes:p,handleKeyDown:M,handleCheckChange:y,getFlattedNodes:b,getCheckedNodes:w,clearCheckedNodes:S,calculateCheckedValue:E,scrollToExpandingNode:A}}});function LH(e,t,n,o,r,a){const l=qe("el-cascader-menu");return T(),V("div",{class:N([e.ns.b("panel"),e.ns.is("bordered",e.border)]),onKeydown:t[0]||(t[0]=(...s)=>e.handleKeyDown&&e.handleKeyDown(...s))},[(T(!0),V(Ve,null,bt(e.menus,(s,u)=>(T(),re(l,{key:u,ref_for:!0,ref:c=>e.menuList[u]=c,index:u,nodes:[...s]},null,8,["index","nodes"]))),128))],34)}var Fc=Ie(RH,[["render",LH],["__file","index.vue"]]);Fc.install=e=>{e.component(Fc.name,Fc)};const Kk=Fc,xH=Kk,$l=Ne({type:{type:String,values:["primary","success","info","warning","danger"],default:"primary"},closable:Boolean,disableTransitions:Boolean,hit:Boolean,color:String,size:{type:String,values:Ir},effect:{type:String,values:["dark","light","plain"],default:"light"},round:Boolean}),DH={close:e=>e instanceof MouseEvent,click:e=>e instanceof MouseEvent},FH=Y({name:"ElTag"}),BH=Y({...FH,props:$l,emits:DH,setup(e,{emit:t}){const n=e,o=hn(),r=Se("tag"),a=k(()=>{const{type:u,hit:c,effect:f,closable:d,round:p}=n;return[r.b(),r.is("closable",d),r.m(u||"primary"),r.m(o.value),r.m(f),r.is("hit",c),r.is("round",p)]}),l=u=>{t("close",u)},s=u=>{t("click",u)};return(u,c)=>u.disableTransitions?(T(),V("span",{key:0,class:N(i(a)),style:je({backgroundColor:u.color}),onClick:s},[F("span",{class:N(i(r).e("content"))},[ie(u.$slots,"default")],2),u.closable?(T(),re(i(ze),{key:0,class:N(i(r).e("close")),onClick:Qe(l,["stop"])},{default:X(()=>[K(i(tr))]),_:1},8,["class","onClick"])):te("v-if",!0)],6)):(T(),re(fn,{key:1,name:`${i(r).namespace.value}-zoom-in-center`,appear:""},{default:X(()=>[F("span",{class:N(i(a)),style:je({backgroundColor:u.color}),onClick:s},[F("span",{class:N(i(r).e("content"))},[ie(u.$slots,"default")],2),u.closable?(T(),re(i(ze),{key:0,class:N(i(r).e("close")),onClick:Qe(l,["stop"])},{default:X(()=>[K(i(tr))]),_:1},8,["class","onClick"])):te("v-if",!0)],6)]),_:3},8,["name"]))}});var VH=Ie(BH,[["__file","tag.vue"]]);const su=ut(VH),HH=Ne({...Wk,size:gn,placeholder:String,disabled:Boolean,clearable:Boolean,filterable:Boolean,filterMethod:{type:Q(Function),default:(e,t)=>e.text.includes(t)},separator:{type:String,default:" / "},showAllLevels:{type:Boolean,default:!0},collapseTags:Boolean,maxCollapseTags:{type:Number,default:1},collapseTagsTooltip:{type:Boolean,default:!1},debounce:{type:Number,default:300},beforeFilter:{type:Q(Function),default:()=>!0},popperClass:{type:String,default:""},teleported:kn.teleported,tagType:{...$l.type,default:"info"},tagEffect:{...$l.effect,default:"light"},validateEvent:{type:Boolean,default:!0},persistent:{type:Boolean,default:!0},...ei}),zH={[ft]:e=>!0,[Yt]:e=>!0,focus:e=>e instanceof FocusEvent,blur:e=>e instanceof FocusEvent,clear:()=>!0,visibleChange:e=>dn(e),expandChange:e=>!!e,removeTag:e=>!!e},jH={key:0},WH=["placeholder","onKeydown"],KH=["onClick"],UH="ElCascader",qH=Y({name:UH}),YH=Y({...qH,props:HH,emits:zH,setup(e,{expose:t,emit:n}){const o=e,r={modifiers:[{name:"arrowPosition",enabled:!0,phase:"main",fn:({state:ne})=>{const{modifiersData:be,placement:Fe}=ne;["right","left","bottom","top"].includes(Fe)||(be.arrow.x=35)},requires:["arrow"]}]},a=xa();let l=0,s=0;const u=Se("cascader"),c=Se("input"),{t:f}=$t(),{form:d,formItem:p}=qn(),{valueOnClear:m}=wf(o),v=R(null),h=R(null),C=R(null),g=R(null),y=R(null),_=R(!1),b=R(!1),w=R(!1),S=R(!1),E=R(""),$=R(""),O=R([]),A=R([]),M=R([]),D=R(!1),U=k(()=>a.style),j=k(()=>o.disabled||(d==null?void 0:d.disabled)),W=k(()=>o.placeholder||f("el.cascader.placeholder")),L=k(()=>$.value||O.value.length>0||D.value?"":W.value),P=hn(),x=k(()=>["small"].includes(P.value)?"small":"default"),I=k(()=>!!o.props.multiple),H=k(()=>!o.filterable||I.value),G=k(()=>I.value?$.value:E.value),J=k(()=>{var ne;return((ne=g.value)==null?void 0:ne.checkedNodes)||[]}),ee=k(()=>!o.clearable||j.value||w.value||!b.value?!1:!!J.value.length),fe=k(()=>{const{showAllLevels:ne,separator:be}=o,Fe=J.value;return Fe.length?I.value?"":Fe[0].calcText(ne,be):""}),Te=k(()=>(p==null?void 0:p.validateState)||""),oe=k({get(){return pd(o.modelValue)},set(ne){const be=ne??m.value;n(ft,be),n(Yt,be),o.validateEvent&&(p==null||p.validate("change").catch(Fe=>void 0))}}),ke=k(()=>[u.b(),u.m(P.value),u.is("disabled",j.value),a.class]),ae=k(()=>[c.e("icon"),"icon-arrow-down",u.is("reverse",_.value)]),Oe=k(()=>u.is("focus",_.value||S.value)),we=k(()=>{var ne,be;return(be=(ne=v.value)==null?void 0:ne.popperRef)==null?void 0:be.contentRef}),ge=ne=>{var be,Fe,vt;j.value||(ne=ne??!_.value,ne!==_.value&&(_.value=ne,(Fe=(be=h.value)==null?void 0:be.input)==null||Fe.setAttribute("aria-expanded",`${ne}`),ne?(q(),We((vt=g.value)==null?void 0:vt.scrollToExpandingNode)):o.filterable&&he(),n("visibleChange",ne)))},q=()=>{We(()=>{var ne;(ne=v.value)==null||ne.updatePopper()})},B=()=>{w.value=!1},z=ne=>{const{showAllLevels:be,separator:Fe}=o;return{node:ne,key:ne.uid,text:ne.calcText(be,Fe),hitState:!1,closable:!j.value&&!ne.isDisabled,isCollapseTag:!1}},Z=ne=>{var be;const Fe=ne.node;Fe.doCheck(!1),(be=g.value)==null||be.calculateCheckedValue(),n("removeTag",Fe.valueByOption)},ue=()=>{if(!I.value)return;const ne=J.value,be=[],Fe=[];if(ne.forEach(vt=>Fe.push(z(vt))),A.value=Fe,ne.length){ne.slice(0,o.maxCollapseTags).forEach(Ye=>be.push(z(Ye)));const vt=ne.slice(o.maxCollapseTags),pe=vt.length;pe&&(o.collapseTags?be.push({key:-1,text:`+ ${pe}`,closable:!1,isCollapseTag:!0}):vt.forEach(Ye=>be.push(z(Ye))))}O.value=be},se=()=>{var ne,be;const{filterMethod:Fe,showAllLevels:vt,separator:pe}=o,Ye=(be=(ne=g.value)==null?void 0:ne.getFlattedNodes(!o.props.checkStrictly))==null?void 0:be.filter(_t=>_t.isDisabled?!1:(_t.calcText(vt,pe),Fe(_t,G.value)));I.value&&(O.value.forEach(_t=>{_t.hitState=!1}),A.value.forEach(_t=>{_t.hitState=!1})),w.value=!0,M.value=Ye,q()},me=()=>{var ne;let be;w.value&&y.value?be=y.value.$el.querySelector(`.${u.e("suggestion-item")}`):be=(ne=g.value)==null?void 0:ne.$el.querySelector(`.${u.b("node")}[tabindex="-1"]`),be&&(be.focus(),!w.value&&be.click())},_e=()=>{var ne,be;const Fe=(ne=h.value)==null?void 0:ne.input,vt=C.value,pe=(be=y.value)==null?void 0:be.$el;if(!(!Ct||!Fe)){if(pe){const Ye=pe.querySelector(`.${u.e("suggestion-list")}`);Ye.style.minWidth=`${Fe.offsetWidth}px`}if(vt){const{offsetHeight:Ye}=vt,_t=O.value.length>0?`${Math.max(Ye+6,l)}px`:`${l}px`;Fe.style.height=_t,q()}}},$e=ne=>{var be;return(be=g.value)==null?void 0:be.getCheckedNodes(ne)},Ce=ne=>{q(),n("expandChange",ne)},ce=ne=>{var be;const Fe=(be=ne.target)==null?void 0:be.value;if(ne.type==="compositionend")D.value=!1,We(()=>Ee(Fe));else{const vt=Fe[Fe.length-1]||"";D.value=!Lv(vt)}},de=ne=>{if(!D.value)switch(ne.code){case Ue.enter:ge();break;case Ue.down:ge(!0),We(me),ne.preventDefault();break;case Ue.esc:_.value===!0&&(ne.preventDefault(),ne.stopPropagation(),ge(!1));break;case Ue.tab:ge(!1);break}},xe=()=>{var ne;(ne=g.value)==null||ne.clearCheckedNodes(),!_.value&&o.filterable&&he(),ge(!1),n("clear")},he=()=>{const{value:ne}=fe;E.value=ne,$.value=ne},He=ne=>{var be,Fe;const{checked:vt}=ne;I.value?(be=g.value)==null||be.handleCheckChange(ne,!vt,!1):(!vt&&((Fe=g.value)==null||Fe.handleCheckChange(ne,!0,!1)),ge(!1))},et=ne=>{const be=ne.target,{code:Fe}=ne;switch(Fe){case Ue.up:case Ue.down:{const vt=Fe===Ue.up?-1:1;Ic(X_(be,vt,`.${u.e("suggestion-item")}[tabindex="-1"]`));break}case Ue.enter:be.click();break}},rt=()=>{const ne=O.value,be=ne[ne.length-1];s=$.value?0:s+1,!(!be||!s||o.collapseTags&&ne.length>1)&&(be.hitState?Z(be):be.hitState=!0)},wt=ne=>{const be=ne.target,Fe=u.e("search-input");be.className===Fe&&(S.value=!0),n("focus",ne)},Ze=ne=>{S.value=!1,n("blur",ne)},st=co(()=>{const{value:ne}=G;if(!ne)return;const be=o.beforeFilter(ne);vs(be)?be.then(se).catch(()=>{}):be!==!1?se():B()},o.debounce),Ee=(ne,be)=>{!_.value&&ge(!0),!(be!=null&&be.isComposing)&&(ne?st():B())},ye=ne=>Number.parseFloat(rM(c.cssVarName("input-height"),ne).value)-2;return ve(w,q),ve([J,j,()=>o.collapseTags],ue),ve(O,()=>{We(()=>_e())}),ve(P,async()=>{await We();const ne=h.value.input;l=ye(ne)||l,_e()}),ve(fe,he,{immediate:!0}),at(()=>{const ne=h.value.input,be=ye(ne);l=ne.offsetHeight||be,Qt(ne,_e)}),t({getCheckedNodes:$e,cascaderPanelRef:g,togglePopperVisible:ge,contentRef:we}),(ne,be)=>(T(),re(i(Un),{ref_key:"tooltipRef",ref:v,visible:_.value,teleported:ne.teleported,"popper-class":[i(u).e("dropdown"),ne.popperClass],"popper-options":r,"fallback-placements":["bottom-start","bottom","top-start","top","right","left"],"stop-popper-mouse-event":!1,"gpu-acceleration":!1,placement:"bottom-start",transition:`${i(u).namespace.value}-zoom-in-top`,effect:"light",pure:"",persistent:ne.persistent,onHide:B},{default:X(()=>[tt((T(),V("div",{class:N(i(ke)),style:je(i(U)),onClick:be[5]||(be[5]=()=>ge(i(H)?void 0:!0)),onKeydown:de,onMouseenter:be[6]||(be[6]=Fe=>b.value=!0),onMouseleave:be[7]||(be[7]=Fe=>b.value=!1)},[K(i(zn),{ref_key:"input",ref:h,modelValue:E.value,"onUpdate:modelValue":be[1]||(be[1]=Fe=>E.value=Fe),placeholder:i(L),readonly:i(H),disabled:i(j),"validate-event":!1,size:i(P),class:N(i(Oe)),tabindex:i(I)&&ne.filterable&&!i(j)?-1:void 0,onCompositionstart:ce,onCompositionupdate:ce,onCompositionend:ce,onFocus:wt,onBlur:Ze,onInput:Ee},{suffix:X(()=>[i(ee)?(T(),re(i(ze),{key:"clear",class:N([i(c).e("icon"),"icon-circle-close"]),onClick:Qe(xe,["stop"])},{default:X(()=>[K(i(Fa))]),_:1},8,["class","onClick"])):(T(),re(i(ze),{key:"arrow-down",class:N(i(ae)),onClick:be[0]||(be[0]=Qe(Fe=>ge(),["stop"]))},{default:X(()=>[K(i(Nr))]),_:1},8,["class"]))]),_:1},8,["modelValue","placeholder","readonly","disabled","size","class","tabindex"]),i(I)?(T(),V("div",{key:0,ref_key:"tagWrapper",ref:C,class:N([i(u).e("tags"),i(u).is("validate",!!i(Te))])},[(T(!0),V(Ve,null,bt(O.value,Fe=>(T(),re(i(su),{key:Fe.key,type:ne.tagType,size:i(x),effect:ne.tagEffect,hit:Fe.hitState,closable:Fe.closable,"disable-transitions":"",onClose:vt=>Z(Fe)},{default:X(()=>[Fe.isCollapseTag===!1?(T(),V("span",jH,le(Fe.text),1)):(T(),re(i(Un),{key:1,disabled:_.value||!ne.collapseTagsTooltip,"fallback-placements":["bottom","top","right","left"],placement:"bottom",effect:"light"},{default:X(()=>[F("span",null,le(Fe.text),1)]),content:X(()=>[F("div",{class:N(i(u).e("collapse-tags"))},[(T(!0),V(Ve,null,bt(A.value.slice(ne.maxCollapseTags),(vt,pe)=>(T(),V("div",{key:pe,class:N(i(u).e("collapse-tag"))},[(T(),re(i(su),{key:vt.key,class:"in-tooltip",type:ne.tagType,size:i(x),effect:ne.tagEffect,hit:vt.hitState,closable:vt.closable,"disable-transitions":"",onClose:Ye=>Z(vt)},{default:X(()=>[F("span",null,le(vt.text),1)]),_:2},1032,["type","size","effect","hit","closable","onClose"]))],2))),128))],2)]),_:2},1032,["disabled"]))]),_:2},1032,["type","size","effect","hit","closable","onClose"]))),128)),ne.filterable&&!i(j)?tt((T(),V("input",{key:0,"onUpdate:modelValue":be[2]||(be[2]=Fe=>$.value=Fe),type:"text",class:N(i(u).e("search-input")),placeholder:i(fe)?"":i(W),onInput:be[3]||(be[3]=Fe=>Ee($.value,Fe)),onClick:be[4]||(be[4]=Qe(Fe=>ge(!0),["stop"])),onKeydown:Pt(rt,["delete"]),onCompositionstart:ce,onCompositionupdate:ce,onCompositionend:ce,onFocus:wt,onBlur:Ze},null,42,WH)),[[yl,$.value]]):te("v-if",!0)],2)):te("v-if",!0)],38)),[[i(Yr),()=>ge(!1),i(we)]])]),content:X(()=>[tt(K(i(Kk),{ref_key:"cascaderPanelRef",ref:g,modelValue:i(oe),"onUpdate:modelValue":be[8]||(be[8]=Fe=>xt(oe)?oe.value=Fe:null),options:ne.options,props:o.props,border:!1,"render-label":ne.$slots.default,onExpandChange:Ce,onClose:be[9]||(be[9]=Fe=>ne.$nextTick(()=>ge(!1)))},null,8,["modelValue","options","props","render-label"]),[[kt,!w.value]]),ne.filterable?tt((T(),re(i(ea),{key:0,ref_key:"suggestionPanel",ref:y,tag:"ul",class:N(i(u).e("suggestion-panel")),"view-class":i(u).e("suggestion-list"),onKeydown:et},{default:X(()=>[M.value.length?(T(!0),V(Ve,{key:0},bt(M.value,Fe=>(T(),V("li",{key:Fe.uid,class:N([i(u).e("suggestion-item"),i(u).is("checked",Fe.checked)]),tabindex:-1,onClick:vt=>He(Fe)},[F("span",null,le(Fe.text),1),Fe.checked?(T(),re(i(ze),{key:0},{default:X(()=>[K(i(Mu))]),_:1})):te("v-if",!0)],10,KH))),128)):ie(ne.$slots,"empty",{key:1},()=>[F("li",{class:N(i(u).e("empty-text"))},le(i(f)("el.cascader.noMatch")),3)])]),_:3},8,["class","view-class"])),[[kt,w.value]]):te("v-if",!0)]),_:3},8,["visible","teleported","popper-class","transition","persistent"]))}});var Bc=Ie(YH,[["__file","cascader.vue"]]);Bc.install=e=>{e.component(Bc.name,Bc)};const GH=Bc,XH=GH,JH=Ne({checked:Boolean,type:{type:String,values:["primary","success","info","warning","danger"],default:"primary"}}),ZH={"update:checked":e=>dn(e),[Yt]:e=>dn(e)},QH=Y({name:"ElCheckTag"}),ez=Y({...QH,props:JH,emits:ZH,setup(e,{emit:t}){const n=e,o=Se("check-tag"),r=k(()=>[o.b(),o.is("checked",n.checked),o.m(n.type||"primary")]),a=()=>{const l=!n.checked;t(Yt,l),t("update:checked",l)};return(l,s)=>(T(),V("span",{class:N(i(r)),onClick:a},[ie(l.$slots,"default")],2))}});var tz=Ie(ez,[["__file","check-tag.vue"]]);const nz=ut(tz),Uk=Symbol("rowContextKey"),oz=["start","center","end","space-around","space-between","space-evenly"],rz=["top","middle","bottom"],az=Ne({tag:{type:String,default:"div"},gutter:{type:Number,default:0},justify:{type:String,values:oz,default:"start"},align:{type:String,values:rz}}),lz=Y({name:"ElRow"}),sz=Y({...lz,props:az,setup(e){const t=e,n=Se("row"),o=k(()=>t.gutter);yt(Uk,{gutter:o});const r=k(()=>{const l={};return t.gutter&&(l.marginRight=l.marginLeft=`-${t.gutter/2}px`),l}),a=k(()=>[n.b(),n.is(`justify-${t.justify}`,t.justify!=="start"),n.is(`align-${t.align}`,!!t.align)]);return(l,s)=>(T(),re(pt(l.tag),{class:N(i(a)),style:je(i(r))},{default:X(()=>[ie(l.$slots,"default")]),_:3},8,["class","style"]))}});var iz=Ie(sz,[["__file","row.vue"]]);const uz=ut(iz),cz=Ne({tag:{type:String,default:"div"},span:{type:Number,default:24},offset:{type:Number,default:0},pull:{type:Number,default:0},push:{type:Number,default:0},xs:{type:Q([Number,Object]),default:()=>en({})},sm:{type:Q([Number,Object]),default:()=>en({})},md:{type:Q([Number,Object]),default:()=>en({})},lg:{type:Q([Number,Object]),default:()=>en({})},xl:{type:Q([Number,Object]),default:()=>en({})}}),dz=Y({name:"ElCol"}),fz=Y({...dz,props:cz,setup(e){const t=e,{gutter:n}=De(Uk,{gutter:k(()=>0)}),o=Se("col"),r=k(()=>{const l={};return n.value&&(l.paddingLeft=l.paddingRight=`${n.value/2}px`),l}),a=k(()=>{const l=[];return["span","offset","pull","push"].forEach(c=>{const f=t[c];Je(f)&&(c==="span"?l.push(o.b(`${t[c]}`)):f>0&&l.push(o.b(`${c}-${t[c]}`)))}),["xs","sm","md","lg","xl"].forEach(c=>{Je(t[c])?l.push(o.b(`${c}-${t[c]}`)):dt(t[c])&&Object.entries(t[c]).forEach(([f,d])=>{l.push(f!=="span"?o.b(`${c}-${f}-${d}`):o.b(`${c}-${d}`))})}),n.value&&l.push(o.is("guttered")),[o.b(),l]});return(l,s)=>(T(),re(pt(l.tag),{class:N(i(a)),style:je(i(r))},{default:X(()=>[ie(l.$slots,"default")]),_:3},8,["class","style"]))}});var pz=Ie(fz,[["__file","col.vue"]]);const hz=ut(pz),X0=e=>Je(e)||nt(e)||Pe(e),mz=Ne({accordion:Boolean,modelValue:{type:Q([Array,String,Number]),default:()=>en([])}}),vz={[ft]:X0,[Yt]:X0},qk=Symbol("collapseContextKey"),gz=(e,t)=>{const n=R(Ia(e.modelValue)),o=a=>{n.value=a;const l=e.accordion?n.value[0]:n.value;t(ft,l),t(Yt,l)},r=a=>{if(e.accordion)o([n.value[0]===a?"":a]);else{const l=[...n.value],s=l.indexOf(a);s>-1?l.splice(s,1):l.push(a),o(l)}};return ve(()=>e.modelValue,()=>n.value=Ia(e.modelValue),{deep:!0}),yt(qk,{activeNames:n,handleItemClick:r}),{activeNames:n,setActiveNames:o}},bz=()=>{const e=Se("collapse");return{rootKls:k(()=>e.b())}},yz=Y({name:"ElCollapse"}),wz=Y({...yz,props:mz,emits:vz,setup(e,{expose:t,emit:n}){const o=e,{activeNames:r,setActiveNames:a}=gz(o,n),{rootKls:l}=bz();return t({activeNames:r,setActiveNames:a}),(s,u)=>(T(),V("div",{class:N(i(l))},[ie(s.$slots,"default")],2))}});var _z=Ie(wz,[["__file","collapse.vue"]]);const Cz=Y({name:"ElCollapseTransition"}),Sz=Y({...Cz,setup(e){const t=Se("collapse-transition"),n=r=>{r.style.maxHeight="",r.style.overflow=r.dataset.oldOverflow,r.style.paddingTop=r.dataset.oldPaddingTop,r.style.paddingBottom=r.dataset.oldPaddingBottom},o={beforeEnter(r){r.dataset||(r.dataset={}),r.dataset.oldPaddingTop=r.style.paddingTop,r.dataset.oldPaddingBottom=r.style.paddingBottom,r.style.height&&(r.dataset.elExistsHeight=r.style.height),r.style.maxHeight=0,r.style.paddingTop=0,r.style.paddingBottom=0},enter(r){requestAnimationFrame(()=>{r.dataset.oldOverflow=r.style.overflow,r.dataset.elExistsHeight?r.style.maxHeight=r.dataset.elExistsHeight:r.scrollHeight!==0?r.style.maxHeight=`${r.scrollHeight}px`:r.style.maxHeight=0,r.style.paddingTop=r.dataset.oldPaddingTop,r.style.paddingBottom=r.dataset.oldPaddingBottom,r.style.overflow="hidden"})},afterEnter(r){r.style.maxHeight="",r.style.overflow=r.dataset.oldOverflow},enterCancelled(r){n(r)},beforeLeave(r){r.dataset||(r.dataset={}),r.dataset.oldPaddingTop=r.style.paddingTop,r.dataset.oldPaddingBottom=r.style.paddingBottom,r.dataset.oldOverflow=r.style.overflow,r.style.maxHeight=`${r.scrollHeight}px`,r.style.overflow="hidden"},leave(r){r.scrollHeight!==0&&(r.style.maxHeight=0,r.style.paddingTop=0,r.style.paddingBottom=0)},afterLeave(r){n(r)},leaveCancelled(r){n(r)}};return(r,a)=>(T(),re(fn,mt({name:i(t).b()},t_(o)),{default:X(()=>[ie(r.$slots,"default")]),_:3},16,["name"]))}});var Vc=Ie(Sz,[["__file","collapse-transition.vue"]]);Vc.install=e=>{e.component(Vc.name,Vc)};const Ef=Vc,kz=Ef,Ez=Ne({title:{type:String,default:""},name:{type:Q([String,Number]),default:void 0},disabled:Boolean}),Tz=e=>{const t=De(qk),{namespace:n}=Se("collapse"),o=R(!1),r=R(!1),a=Yv(),l=k(()=>a.current++),s=k(()=>{var p;return(p=e.name)!=null?p:`${n.value}-id-${a.prefix}-${i(l)}`}),u=k(()=>t==null?void 0:t.activeNames.value.includes(i(s)));return{focusing:o,id:l,isActive:u,handleFocus:()=>{setTimeout(()=>{r.value?r.value=!1:o.value=!0},50)},handleHeaderClick:()=>{e.disabled||(t==null||t.handleItemClick(i(s)),o.value=!1,r.value=!0)},handleEnterClick:()=>{t==null||t.handleItemClick(i(s))}}},$z=(e,{focusing:t,isActive:n,id:o})=>{const r=Se("collapse"),a=k(()=>[r.b("item"),r.is("active",i(n)),r.is("disabled",e.disabled)]),l=k(()=>[r.be("item","header"),r.is("active",i(n)),{focusing:i(t)&&!e.disabled}]),s=k(()=>[r.be("item","arrow"),r.is("active",i(n))]),u=k(()=>r.be("item","wrap")),c=k(()=>r.be("item","content")),f=k(()=>r.b(`content-${i(o)}`)),d=k(()=>r.b(`head-${i(o)}`));return{arrowKls:s,headKls:l,rootKls:a,itemWrapperKls:u,itemContentKls:c,scopedContentId:f,scopedHeadId:d}},Oz=["id","aria-expanded","aria-controls","aria-describedby","tabindex"],Nz=["id","aria-hidden","aria-labelledby"],Iz=Y({name:"ElCollapseItem"}),Mz=Y({...Iz,props:Ez,setup(e,{expose:t}){const n=e,{focusing:o,id:r,isActive:a,handleFocus:l,handleHeaderClick:s,handleEnterClick:u}=Tz(n),{arrowKls:c,headKls:f,rootKls:d,itemWrapperKls:p,itemContentKls:m,scopedContentId:v,scopedHeadId:h}=$z(n,{focusing:o,isActive:a,id:r});return t({isActive:a}),(C,g)=>(T(),V("div",{class:N(i(d))},[F("button",{id:i(h),class:N(i(f)),"aria-expanded":i(a),"aria-controls":i(v),"aria-describedby":i(v),tabindex:C.disabled?-1:0,type:"button",onClick:g[0]||(g[0]=(...y)=>i(s)&&i(s)(...y)),onKeydown:g[1]||(g[1]=Pt(Qe((...y)=>i(u)&&i(u)(...y),["stop","prevent"]),["space","enter"])),onFocus:g[2]||(g[2]=(...y)=>i(l)&&i(l)(...y)),onBlur:g[3]||(g[3]=y=>o.value=!1)},[ie(C.$slots,"title",{},()=>[Ge(le(C.title),1)]),K(i(ze),{class:N(i(c))},{default:X(()=>[K(i(Jn))]),_:1},8,["class"])],42,Oz),K(i(Ef),null,{default:X(()=>[tt(F("div",{id:i(v),role:"region",class:N(i(p)),"aria-hidden":!i(a),"aria-labelledby":i(h)},[F("div",{class:N(i(m))},[ie(C.$slots,"default")],2)],10,Nz),[[kt,i(a)]])]),_:3})],2))}});var Yk=Ie(Mz,[["__file","collapse-item.vue"]]);const Az=ut(_z,{CollapseItem:Yk}),Pz=tn(Yk),Rz=Ne({color:{type:Q(Object),required:!0},vertical:{type:Boolean,default:!1}});let _p=!1;function iu(e,t){if(!Ct)return;const n=function(a){var l;(l=t.drag)==null||l.call(t,a)},o=function(a){var l;document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",o),document.removeEventListener("touchmove",n),document.removeEventListener("touchend",o),document.onselectstart=null,document.ondragstart=null,_p=!1,(l=t.end)==null||l.call(t,a)},r=function(a){var l;_p||(a.preventDefault(),document.onselectstart=()=>!1,document.ondragstart=()=>!1,document.addEventListener("mousemove",n),document.addEventListener("mouseup",o),document.addEventListener("touchmove",n),document.addEventListener("touchend",o),_p=!0,(l=t.start)==null||l.call(t,a))};e.addEventListener("mousedown",r),e.addEventListener("touchstart",r)}const Lz=e=>{const t=lt(),n=Ut(),o=Ut();function r(l){l.target!==n.value&&a(l)}function a(l){if(!o.value||!n.value)return;const u=t.vnode.el.getBoundingClientRect(),{clientX:c,clientY:f}=dv(l);if(e.vertical){let d=f-u.top;d=Math.max(n.value.offsetHeight/2,d),d=Math.min(d,u.height-n.value.offsetHeight/2),e.color.set("alpha",Math.round((d-n.value.offsetHeight/2)/(u.height-n.value.offsetHeight)*100))}else{let d=c-u.left;d=Math.max(n.value.offsetWidth/2,d),d=Math.min(d,u.width-n.value.offsetWidth/2),e.color.set("alpha",Math.round((d-n.value.offsetWidth/2)/(u.width-n.value.offsetWidth)*100))}}return{thumb:n,bar:o,handleDrag:a,handleClick:r}},xz=(e,{bar:t,thumb:n,handleDrag:o})=>{const r=lt(),a=Se("color-alpha-slider"),l=R(0),s=R(0),u=R();function c(){if(!n.value||e.vertical)return 0;const y=r.vnode.el,_=e.color.get("alpha");return y?Math.round(_*(y.offsetWidth-n.value.offsetWidth/2)/100):0}function f(){if(!n.value)return 0;const y=r.vnode.el;if(!e.vertical)return 0;const _=e.color.get("alpha");return y?Math.round(_*(y.offsetHeight-n.value.offsetHeight/2)/100):0}function d(){if(e.color&&e.color.value){const{r:y,g:_,b}=e.color.toRgb();return`linear-gradient(to right, rgba(${y}, ${_}, ${b}, 0) 0%, rgba(${y}, ${_}, ${b}, 1) 100%)`}return""}function p(){l.value=c(),s.value=f(),u.value=d()}at(()=>{if(!t.value||!n.value)return;const y={drag:_=>{o(_)},end:_=>{o(_)}};iu(t.value,y),iu(n.value,y),p()}),ve(()=>e.color.get("alpha"),()=>p()),ve(()=>e.color.value,()=>p());const m=k(()=>[a.b(),a.is("vertical",e.vertical)]),v=k(()=>a.e("bar")),h=k(()=>a.e("thumb")),C=k(()=>({background:u.value})),g=k(()=>({left:rn(l.value),top:rn(s.value)}));return{rootKls:m,barKls:v,barStyle:C,thumbKls:h,thumbStyle:g,update:p}},Dz="ElColorAlphaSlider",Fz=Y({name:Dz}),Bz=Y({...Fz,props:Rz,setup(e,{expose:t}){const n=e,{bar:o,thumb:r,handleDrag:a,handleClick:l}=Lz(n),{rootKls:s,barKls:u,barStyle:c,thumbKls:f,thumbStyle:d,update:p}=xz(n,{bar:o,thumb:r,handleDrag:a});return t({update:p,bar:o,thumb:r}),(m,v)=>(T(),V("div",{class:N(i(s))},[F("div",{ref_key:"bar",ref:o,class:N(i(u)),style:je(i(c)),onClick:v[0]||(v[0]=(...h)=>i(l)&&i(l)(...h))},null,6),F("div",{ref_key:"thumb",ref:r,class:N(i(f)),style:je(i(d))},null,6)],2))}});var Vz=Ie(Bz,[["__file","alpha-slider.vue"]]);const Hz=Y({name:"ElColorHueSlider",props:{color:{type:Object,required:!0},vertical:Boolean},setup(e){const t=Se("color-hue-slider"),n=lt(),o=R(),r=R(),a=R(0),l=R(0),s=k(()=>e.color.get("hue"));ve(()=>s.value,()=>{p()});function u(m){m.target!==o.value&&c(m)}function c(m){if(!r.value||!o.value)return;const h=n.vnode.el.getBoundingClientRect(),{clientX:C,clientY:g}=dv(m);let y;if(e.vertical){let _=g-h.top;_=Math.min(_,h.height-o.value.offsetHeight/2),_=Math.max(o.value.offsetHeight/2,_),y=Math.round((_-o.value.offsetHeight/2)/(h.height-o.value.offsetHeight)*360)}else{let _=C-h.left;_=Math.min(_,h.width-o.value.offsetWidth/2),_=Math.max(o.value.offsetWidth/2,_),y=Math.round((_-o.value.offsetWidth/2)/(h.width-o.value.offsetWidth)*360)}e.color.set("hue",y)}function f(){if(!o.value)return 0;const m=n.vnode.el;if(e.vertical)return 0;const v=e.color.get("hue");return m?Math.round(v*(m.offsetWidth-o.value.offsetWidth/2)/360):0}function d(){if(!o.value)return 0;const m=n.vnode.el;if(!e.vertical)return 0;const v=e.color.get("hue");return m?Math.round(v*(m.offsetHeight-o.value.offsetHeight/2)/360):0}function p(){a.value=f(),l.value=d()}return at(()=>{if(!r.value||!o.value)return;const m={drag:v=>{c(v)},end:v=>{c(v)}};iu(r.value,m),iu(o.value,m),p()}),{bar:r,thumb:o,thumbLeft:a,thumbTop:l,hueValue:s,handleClick:u,update:p,ns:t}}});function zz(e,t,n,o,r,a){return T(),V("div",{class:N([e.ns.b(),e.ns.is("vertical",e.vertical)])},[F("div",{ref:"bar",class:N(e.ns.e("bar")),onClick:t[0]||(t[0]=(...l)=>e.handleClick&&e.handleClick(...l))},null,2),F("div",{ref:"thumb",class:N(e.ns.e("thumb")),style:je({left:e.thumbLeft+"px",top:e.thumbTop+"px"})},null,6)],2)}var jz=Ie(Hz,[["render",zz],["__file","hue-slider.vue"]]);const Wz=Ne({modelValue:String,id:String,showAlpha:Boolean,colorFormat:String,disabled:Boolean,size:gn,popperClass:{type:String,default:""},label:{type:String,default:void 0},tabindex:{type:[String,Number],default:0},teleported:kn.teleported,predefine:{type:Q(Array)},validateEvent:{type:Boolean,default:!0},...An(["ariaLabel"])}),Kz={[ft]:e=>nt(e)||Tn(e),[Yt]:e=>nt(e)||Tn(e),activeChange:e=>nt(e)||Tn(e),focus:e=>e instanceof FocusEvent,blur:e=>e instanceof FocusEvent},Gk=Symbol("colorPickerContextKey"),J0=function(e,t,n){return[e,t*n/((e=(2-t)*n)<1?e:2-e)||0,e/2]},Uz=function(e){return typeof e=="string"&&e.includes(".")&&Number.parseFloat(e)===1},qz=function(e){return typeof e=="string"&&e.includes("%")},ps=function(e,t){Uz(e)&&(e="100%");const n=qz(e);return e=Math.min(t,Math.max(0,Number.parseFloat(`${e}`))),n&&(e=Number.parseInt(`${e*t}`,10)/100),Math.abs(e-t)<1e-6?1:e%t/Number.parseFloat(t)},Z0={10:"A",11:"B",12:"C",13:"D",14:"E",15:"F"},Hc=e=>{e=Math.min(Math.round(e),255);const t=Math.floor(e/16),n=e%16;return`${Z0[t]||t}${Z0[n]||n}`},Q0=function({r:e,g:t,b:n}){return Number.isNaN(+e)||Number.isNaN(+t)||Number.isNaN(+n)?"":`#${Hc(e)}${Hc(t)}${Hc(n)}`},Cp={A:10,B:11,C:12,D:13,E:14,F:15},Wa=function(e){return e.length===2?(Cp[e[0].toUpperCase()]||+e[0])*16+(Cp[e[1].toUpperCase()]||+e[1]):Cp[e[1].toUpperCase()]||+e[1]},Yz=function(e,t,n){t=t/100,n=n/100;let o=t;const r=Math.max(n,.01);n*=2,t*=n<=1?n:2-n,o*=r<=1?r:2-r;const a=(n+t)/2,l=n===0?2*o/(r+o):2*t/(n+t);return{h:e,s:l*100,v:a*100}},e1=(e,t,n)=>{e=ps(e,255),t=ps(t,255),n=ps(n,255);const o=Math.max(e,t,n),r=Math.min(e,t,n);let a;const l=o,s=o-r,u=o===0?0:s/o;if(o===r)a=0;else{switch(o){case e:{a=(t-n)/s+(t{this._hue=Math.max(0,Math.min(360,o)),this._saturation=Math.max(0,Math.min(100,r)),this._value=Math.max(0,Math.min(100,a)),this.doOnChange()};if(t.includes("hsl")){const o=t.replace(/hsla|hsl|\(|\)/gm,"").split(/\s|,/g).filter(r=>r!=="").map((r,a)=>a>2?Number.parseFloat(r):Number.parseInt(r,10));if(o.length===4?this._alpha=Number.parseFloat(o[3])*100:o.length===3&&(this._alpha=100),o.length>=3){const{h:r,s:a,v:l}=Yz(o[0],o[1],o[2]);n(r,a,l)}}else if(t.includes("hsv")){const o=t.replace(/hsva|hsv|\(|\)/gm,"").split(/\s|,/g).filter(r=>r!=="").map((r,a)=>a>2?Number.parseFloat(r):Number.parseInt(r,10));o.length===4?this._alpha=Number.parseFloat(o[3])*100:o.length===3&&(this._alpha=100),o.length>=3&&n(o[0],o[1],o[2])}else if(t.includes("rgb")){const o=t.replace(/rgba|rgb|\(|\)/gm,"").split(/\s|,/g).filter(r=>r!=="").map((r,a)=>a>2?Number.parseFloat(r):Number.parseInt(r,10));if(o.length===4?this._alpha=Number.parseFloat(o[3])*100:o.length===3&&(this._alpha=100),o.length>=3){const{h:r,s:a,v:l}=e1(o[0],o[1],o[2]);n(r,a,l)}}else if(t.includes("#")){const o=t.replace("#","").trim();if(!/^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$|^[0-9a-fA-F]{8}$/.test(o))return;let r,a,l;o.length===3?(r=Wa(o[0]+o[0]),a=Wa(o[1]+o[1]),l=Wa(o[2]+o[2])):(o.length===6||o.length===8)&&(r=Wa(o.slice(0,2)),a=Wa(o.slice(2,4)),l=Wa(o.slice(4,6))),o.length===8?this._alpha=Wa(o.slice(6))/255*100:(o.length===3||o.length===6)&&(this._alpha=100);const{h:s,s:u,v:c}=e1(r,a,l);n(s,u,c)}}compare(t){return Math.abs(t._hue-this._hue)<2&&Math.abs(t._saturation-this._saturation)<1&&Math.abs(t._value-this._value)<1&&Math.abs(t._alpha-this._alpha)<1}doOnChange(){const{_hue:t,_saturation:n,_value:o,_alpha:r,format:a}=this;if(this.enableAlpha)switch(a){case"hsl":{const l=J0(t,n/100,o/100);this.value=`hsla(${t}, ${Math.round(l[1]*100)}%, ${Math.round(l[2]*100)}%, ${this.get("alpha")/100})`;break}case"hsv":{this.value=`hsva(${t}, ${Math.round(n)}%, ${Math.round(o)}%, ${this.get("alpha")/100})`;break}case"hex":{this.value=`${Q0(mi(t,n,o))}${Hc(r*255/100)}`;break}default:{const{r:l,g:s,b:u}=mi(t,n,o);this.value=`rgba(${l}, ${s}, ${u}, ${this.get("alpha")/100})`}}else switch(a){case"hsl":{const l=J0(t,n/100,o/100);this.value=`hsl(${t}, ${Math.round(l[1]*100)}%, ${Math.round(l[2]*100)}%)`;break}case"hsv":{this.value=`hsv(${t}, ${Math.round(n)}%, ${Math.round(o)}%)`;break}case"rgb":{const{r:l,g:s,b:u}=mi(t,n,o);this.value=`rgb(${l}, ${s}, ${u})`;break}default:this.value=Q0(mi(t,n,o))}}}const Gz=Y({props:{colors:{type:Array,required:!0},color:{type:Object,required:!0},enableAlpha:{type:Boolean,required:!0}},setup(e){const t=Se("color-predefine"),{currentColor:n}=De(Gk),o=R(a(e.colors,e.color));ve(()=>n.value,l=>{const s=new Fi;s.fromString(l),o.value.forEach(u=>{u.selected=s.compare(u)})}),Mn(()=>{o.value=a(e.colors,e.color)});function r(l){e.color.fromString(e.colors[l])}function a(l,s){return l.map(u=>{const c=new Fi;return c.enableAlpha=e.enableAlpha,c.format="rgba",c.fromString(u),c.selected=c.value===s.value,c})}return{rgbaColors:o,handleSelect:r,ns:t}}}),Xz=["onClick"];function Jz(e,t,n,o,r,a){return T(),V("div",{class:N(e.ns.b())},[F("div",{class:N(e.ns.e("colors"))},[(T(!0),V(Ve,null,bt(e.rgbaColors,(l,s)=>(T(),V("div",{key:e.colors[s],class:N([e.ns.e("color-selector"),e.ns.is("alpha",l._alpha<100),{selected:l.selected}]),onClick:u=>e.handleSelect(s)},[F("div",{style:je({backgroundColor:l.value})},null,4)],10,Xz))),128))],2)],2)}var Zz=Ie(Gz,[["render",Jz],["__file","predefine.vue"]]);const Qz=Y({name:"ElSlPanel",props:{color:{type:Object,required:!0}},setup(e){const t=Se("color-svpanel"),n=lt(),o=R(0),r=R(0),a=R("hsl(0, 100%, 50%)"),l=k(()=>{const c=e.color.get("hue"),f=e.color.get("value");return{hue:c,value:f}});function s(){const c=e.color.get("saturation"),f=e.color.get("value"),d=n.vnode.el,{clientWidth:p,clientHeight:m}=d;r.value=c*p/100,o.value=(100-f)*m/100,a.value=`hsl(${e.color.get("hue")}, 100%, 50%)`}function u(c){const d=n.vnode.el.getBoundingClientRect(),{clientX:p,clientY:m}=dv(c);let v=p-d.left,h=m-d.top;v=Math.max(0,v),v=Math.min(v,d.width),h=Math.max(0,h),h=Math.min(h,d.height),r.value=v,o.value=h,e.color.set({saturation:v/d.width*100,value:100-h/d.height*100})}return ve(()=>l.value,()=>{s()}),at(()=>{iu(n.vnode.el,{drag:c=>{u(c)},end:c=>{u(c)}}),s()}),{cursorTop:o,cursorLeft:r,background:a,colorValue:l,handleDrag:u,update:s,ns:t}}}),ej=F("div",null,null,-1),tj=[ej];function nj(e,t,n,o,r,a){return T(),V("div",{class:N(e.ns.b()),style:je({backgroundColor:e.background})},[F("div",{class:N(e.ns.e("white"))},null,2),F("div",{class:N(e.ns.e("black"))},null,2),F("div",{class:N(e.ns.e("cursor")),style:je({top:e.cursorTop+"px",left:e.cursorLeft+"px"})},tj,6)],6)}var oj=Ie(Qz,[["render",nj],["__file","sv-panel.vue"]]);const rj=["onKeydown"],aj=["id","aria-label","aria-labelledby","aria-description","aria-disabled","tabindex"],lj=Y({name:"ElColorPicker"}),sj=Y({...lj,props:Wz,emits:Kz,setup(e,{expose:t,emit:n}){const o=e,{t:r}=$t(),a=Se("color"),{formItem:l}=qn(),s=hn(),u=to(),{inputId:c,isLabeledByFormItem:f}=cr(o,{formItemContext:l}),d=R(),p=R(),m=R(),v=R(),h=R(),C=R(),{isFocused:g,handleFocus:y,handleBlur:_}=yf(h,{beforeBlur(we){var ge;return(ge=v.value)==null?void 0:ge.isFocusInsideContent(we)},afterBlur(){L(!1),H()}}),b=we=>{if(u.value)return Oe();y(we)};let w=!0;const S=Et(new Fi({enableAlpha:o.showAlpha,format:o.colorFormat||"",value:o.modelValue})),E=R(!1),$=R(!1),O=R(""),A=k(()=>!o.modelValue&&!$.value?"transparent":W(S,o.showAlpha)),M=k(()=>!o.modelValue&&!$.value?"":S.value),D=k(()=>f.value?void 0:o.label||o.ariaLabel||r("el.colorpicker.defaultLabel"));wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-color-picker",ref:"https://element-plus.org/en-US/component/color-picker.html"},k(()=>!!o.label));const U=k(()=>f.value?l==null?void 0:l.labelId:void 0),j=k(()=>[a.b("picker"),a.is("disabled",u.value),a.bm("picker",s.value),a.is("focused",g.value)]);function W(we,ge){if(!(we instanceof Fi))throw new TypeError("color should be instance of _color Class");const{r:q,g:B,b:z}=we.toRgb();return ge?`rgba(${q}, ${B}, ${z}, ${we.get("alpha")/100})`:`rgb(${q}, ${B}, ${z})`}function L(we){E.value=we}const P=co(L,100,{leading:!0});function x(){u.value||L(!0)}function I(){P(!1),H()}function H(){We(()=>{o.modelValue?S.fromString(o.modelValue):(S.value="",We(()=>{$.value=!1}))})}function G(){u.value||P(!E.value)}function J(){S.fromString(O.value)}function ee(){const we=S.value;n(ft,we),n("change",we),o.validateEvent&&(l==null||l.validate("change").catch(ge=>void 0)),P(!1),We(()=>{const ge=new Fi({enableAlpha:o.showAlpha,format:o.colorFormat||"",value:o.modelValue});S.compare(ge)||H()})}function fe(){P(!1),n(ft,null),n("change",null),o.modelValue!==null&&o.validateEvent&&(l==null||l.validate("change").catch(we=>void 0)),H()}function Te(we){if(E.value&&(I(),g.value)){const ge=new FocusEvent("focus",we);_(ge)}}function oe(we){we.preventDefault(),we.stopPropagation(),L(!1),H()}function ke(we){switch(we.code){case Ue.enter:case Ue.space:we.preventDefault(),we.stopPropagation(),x(),C.value.focus();break;case Ue.esc:oe(we);break}}function ae(){h.value.focus()}function Oe(){h.value.blur()}return at(()=>{o.modelValue&&(O.value=M.value)}),ve(()=>o.modelValue,we=>{we?we&&we!==S.value&&(w=!1,S.fromString(we)):$.value=!1}),ve(()=>M.value,we=>{O.value=we,w&&n("activeChange",we),w=!0}),ve(()=>S.value,()=>{!o.modelValue&&!$.value&&($.value=!0)}),ve(()=>E.value,()=>{We(()=>{var we,ge,q;(we=d.value)==null||we.update(),(ge=p.value)==null||ge.update(),(q=m.value)==null||q.update()})}),yt(Gk,{currentColor:M}),t({color:S,show:x,hide:I,focus:ae,blur:Oe}),(we,ge)=>(T(),re(i(Un),{ref_key:"popper",ref:v,visible:E.value,"show-arrow":!1,"fallback-placements":["bottom","top","right","left"],offset:0,"gpu-acceleration":!1,"popper-class":[i(a).be("picker","panel"),i(a).b("dropdown"),we.popperClass],"stop-popper-mouse-event":!1,effect:"light",trigger:"click",teleported:we.teleported,transition:`${i(a).namespace.value}-zoom-in-top`,persistent:"",onHide:ge[2]||(ge[2]=q=>L(!1))},{content:X(()=>[tt((T(),V("div",{onKeydown:Pt(oe,["esc"])},[F("div",{class:N(i(a).be("dropdown","main-wrapper"))},[K(jz,{ref_key:"hue",ref:d,class:"hue-slider",color:i(S),vertical:""},null,8,["color"]),K(oj,{ref_key:"sv",ref:p,color:i(S)},null,8,["color"])],2),we.showAlpha?(T(),re(Vz,{key:0,ref_key:"alpha",ref:m,color:i(S)},null,8,["color"])):te("v-if",!0),we.predefine?(T(),re(Zz,{key:1,ref:"predefine","enable-alpha":we.showAlpha,color:i(S),colors:we.predefine},null,8,["enable-alpha","color","colors"])):te("v-if",!0),F("div",{class:N(i(a).be("dropdown","btns"))},[F("span",{class:N(i(a).be("dropdown","value"))},[K(i(zn),{ref_key:"inputRef",ref:C,modelValue:O.value,"onUpdate:modelValue":ge[0]||(ge[0]=q=>O.value=q),"validate-event":!1,size:"small",onKeyup:Pt(J,["enter"]),onBlur:J},null,8,["modelValue","onKeyup"])],2),K(i($n),{class:N(i(a).be("dropdown","link-btn")),text:"",size:"small",onClick:fe},{default:X(()=>[Ge(le(i(r)("el.colorpicker.clear")),1)]),_:1},8,["class"]),K(i($n),{plain:"",size:"small",class:N(i(a).be("dropdown","btn")),onClick:ee},{default:X(()=>[Ge(le(i(r)("el.colorpicker.confirm")),1)]),_:1},8,["class"])],2)],40,rj)),[[i(Yr),Te]])]),default:X(()=>[F("div",mt({id:i(c),ref_key:"triggerRef",ref:h},we.$attrs,{class:i(j),role:"button","aria-label":i(D),"aria-labelledby":i(U),"aria-description":i(r)("el.colorpicker.description",{color:we.modelValue||""}),"aria-disabled":i(u),tabindex:i(u)?-1:we.tabindex,onKeydown:ke,onFocus:b,onBlur:ge[1]||(ge[1]=(...q)=>i(_)&&i(_)(...q))}),[i(u)?(T(),V("div",{key:0,class:N(i(a).be("picker","mask"))},null,2)):te("v-if",!0),F("div",{class:N(i(a).be("picker","trigger")),onClick:G},[F("span",{class:N([i(a).be("picker","color"),i(a).is("alpha",we.showAlpha)])},[F("span",{class:N(i(a).be("picker","color-inner")),style:je({backgroundColor:i(A)})},[tt(K(i(ze),{class:N([i(a).be("picker","icon"),i(a).is("icon-arrow-down")])},{default:X(()=>[K(i(Nr))]),_:1},8,["class"]),[[kt,we.modelValue||$.value]]),tt(K(i(ze),{class:N([i(a).be("picker","empty"),i(a).is("icon-close")])},{default:X(()=>[K(i(tr))]),_:1},8,["class"]),[[kt,!we.modelValue&&!$.value]])],6)],2)],2)],16,aj)]),_:1},8,["visible","popper-class","teleported","transition"]))}});var ij=Ie(sj,[["__file","color-picker.vue"]]);const uj=ut(ij),cj=Y({name:"ElContainer"}),dj=Y({...cj,props:{direction:{type:String}},setup(e){const t=e,n=Sn(),o=Se("container"),r=k(()=>t.direction==="vertical"?!0:t.direction==="horizontal"?!1:n&&n.default?n.default().some(l=>{const s=l.type.name;return s==="ElHeader"||s==="ElFooter"}):!1);return(a,l)=>(T(),V("section",{class:N([i(o).b(),i(o).is("vertical",i(r))])},[ie(a.$slots,"default")],2))}});var fj=Ie(dj,[["__file","container.vue"]]);const pj=Y({name:"ElAside"}),hj=Y({...pj,props:{width:{type:String,default:null}},setup(e){const t=e,n=Se("aside"),o=k(()=>t.width?n.cssVarBlock({width:t.width}):{});return(r,a)=>(T(),V("aside",{class:N(i(n).b()),style:je(i(o))},[ie(r.$slots,"default")],6))}});var Xk=Ie(hj,[["__file","aside.vue"]]);const mj=Y({name:"ElFooter"}),vj=Y({...mj,props:{height:{type:String,default:null}},setup(e){const t=e,n=Se("footer"),o=k(()=>t.height?n.cssVarBlock({height:t.height}):{});return(r,a)=>(T(),V("footer",{class:N(i(n).b()),style:je(i(o))},[ie(r.$slots,"default")],6))}});var Jk=Ie(vj,[["__file","footer.vue"]]);const gj=Y({name:"ElHeader"}),bj=Y({...gj,props:{height:{type:String,default:null}},setup(e){const t=e,n=Se("header"),o=k(()=>t.height?n.cssVarBlock({height:t.height}):{});return(r,a)=>(T(),V("header",{class:N(i(n).b()),style:je(i(o))},[ie(r.$slots,"default")],6))}});var Zk=Ie(bj,[["__file","header.vue"]]);const yj=Y({name:"ElMain"}),wj=Y({...yj,setup(e){const t=Se("main");return(n,o)=>(T(),V("main",{class:N(i(t).b())},[ie(n.$slots,"default")],2))}});var Qk=Ie(wj,[["__file","main.vue"]]);const _j=ut(fj,{Aside:Xk,Footer:Jk,Header:Zk,Main:Qk}),Cj=tn(Xk),Sj=tn(Jk),kj=tn(Zk),Ej=tn(Qk);var eE={exports:{}};(function(e,t){(function(n,o){e.exports=o()})(rr,function(){return function(n,o){var r=o.prototype,a=r.format;r.format=function(l){var s=this,u=this.$locale();if(!this.isValid())return a.bind(this)(l);var c=this.$utils(),f=(l||"YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g,function(d){switch(d){case"Q":return Math.ceil((s.$M+1)/3);case"Do":return u.ordinal(s.$D);case"gggg":return s.weekYear();case"GGGG":return s.isoWeekYear();case"wo":return u.ordinal(s.week(),"W");case"w":case"ww":return c.s(s.week(),d==="w"?1:2,"0");case"W":case"WW":return c.s(s.isoWeek(),d==="W"?1:2,"0");case"k":case"kk":return c.s(String(s.$H===0?24:s.$H),d==="k"?1:2,"0");case"X":return Math.floor(s.$d.getTime()/1e3);case"x":return s.$d.getTime();case"z":return"["+s.offsetName()+"]";case"zzz":return"["+s.offsetName("long")+"]";default:return d}});return a.bind(this)(f)}}})})(eE);var Tj=eE.exports;const $j=ta(Tj);var tE={exports:{}};(function(e,t){(function(n,o){e.exports=o()})(rr,function(){var n="week",o="year";return function(r,a,l){var s=a.prototype;s.week=function(u){if(u===void 0&&(u=null),u!==null)return this.add(7*(u-this.week()),"day");var c=this.$locale().yearStart||1;if(this.month()===11&&this.date()>25){var f=l(this).startOf(o).add(1,o).date(c),d=l(this).endOf(n);if(f.isBefore(d))return 1}var p=l(this).startOf(o).date(c).startOf(n).subtract(1,"millisecond"),m=this.diff(p,n,!0);return m<0?l(this).startOf("week").week():Math.ceil(m)},s.weeks=function(u){return u===void 0&&(u=null),this.week(u)}}})})(tE);var Oj=tE.exports;const Nj=ta(Oj);var nE={exports:{}};(function(e,t){(function(n,o){e.exports=o()})(rr,function(){return function(n,o){o.prototype.weekYear=function(){var r=this.month(),a=this.week(),l=this.year();return a===1&&r===11?l+1:r===0&&a>=52?l-1:l}}})})(nE);var Ij=nE.exports;const Mj=ta(Ij);var oE={exports:{}};(function(e,t){(function(n,o){e.exports=o()})(rr,function(){return function(n,o,r){o.prototype.dayOfYear=function(a){var l=Math.round((r(this).startOf("day")-r(this).startOf("year"))/864e5)+1;return a==null?l:this.add(a-l,"day")}}})})(oE);var Aj=oE.exports;const Pj=ta(Aj);var rE={exports:{}};(function(e,t){(function(n,o){e.exports=o()})(rr,function(){return function(n,o){o.prototype.isSameOrAfter=function(r,a){return this.isSame(r,a)||this.isAfter(r,a)}}})})(rE);var Rj=rE.exports;const Lj=ta(Rj);var aE={exports:{}};(function(e,t){(function(n,o){e.exports=o()})(rr,function(){return function(n,o){o.prototype.isSameOrBefore=function(r,a){return this.isSame(r,a)||this.isBefore(r,a)}}})})(aE);var xj=aE.exports;const Dj=ta(xj),dg=Symbol(),Fj=Ne({...ug,type:{type:Q(String),default:"date"}}),Bj=["date","dates","year","years","month","months","week","range"],fg=Ne({disabledDate:{type:Q(Function)},date:{type:Q(Object),required:!0},minDate:{type:Q(Object)},maxDate:{type:Q(Object)},parsedValue:{type:Q([Object,Array])},rangeState:{type:Q(Object),default:()=>({endDate:null,selecting:!1})}}),lE=Ne({type:{type:Q(String),required:!0,values:u3},dateFormat:String,timeFormat:String}),sE=Ne({unlinkPanels:Boolean,parsedValue:{type:Q(Array)}}),pg=e=>({type:String,values:Bj,default:e}),Vj=Ne({...lE,parsedValue:{type:Q([Object,Array])},visible:{type:Boolean},format:{type:String,default:""}}),Hj=Ne({...fg,cellClassName:{type:Q(Function)},showWeekNumber:Boolean,selectionMode:pg("date")}),zj=["changerange","pick","select"],Kh=e=>{if(!Pe(e))return!1;const[t,n]=e;return ct.isDayjs(t)&&ct.isDayjs(n)&&t.isSameOrBefore(n)},iE=(e,{lang:t,unit:n,unlinkPanels:o})=>{let r;if(Pe(e)){let[a,l]=e.map(s=>ct(s).locale(t));return o||(l=a.add(1,n)),[a,l]}else e?r=ct(e):r=ct();return r=r.locale(t),[r,r.add(1,n)]},jj=(e,t,{columnIndexOffset:n,startDate:o,nextEndDate:r,now:a,unit:l,relativeDateGetter:s,setCellMetadata:u,setRowMetadata:c})=>{for(let f=0;f["normal","today"].includes(e),Wj=(e,t)=>{const{lang:n}=$t(),o=R(),r=R(),a=R(),l=R(),s=R([[],[],[],[],[],[]]);let u=!1;const c=e.date.$locale().weekStart||7,f=e.date.locale("en").localeData().weekdaysShort().map(I=>I.toLowerCase()),d=k(()=>c>3?7-c:-c),p=k(()=>{const I=e.date.startOf("month");return I.subtract(I.day()||7,"day")}),m=k(()=>f.concat(f).slice(c,c+7)),v=k(()=>vC(i(b)).some(I=>I.isCurrent)),h=k(()=>{const I=e.date.startOf("month"),H=I.day()||7,G=I.daysInMonth(),J=I.subtract(1,"month").daysInMonth();return{startOfMonthDay:H,dateCountOfMonth:G,dateCountOfLastMonth:J}}),C=k(()=>e.selectionMode==="dates"?Vn(e.parsedValue):[]),g=(I,{count:H,rowIndex:G,columnIndex:J})=>{const{startOfMonthDay:ee,dateCountOfMonth:fe,dateCountOfLastMonth:Te}=i(h),oe=i(d);if(G>=0&&G<=1){const ke=ee+oe<0?7+ee+oe:ee+oe;if(J+G*7>=ke)return I.text=H,!0;I.text=Te-(ke-J%7)+1+G*7,I.type="prev-month"}else return H<=fe?I.text=H:(I.text=H-fe,I.type="next-month"),!0;return!1},y=(I,{columnIndex:H,rowIndex:G},J)=>{const{disabledDate:ee,cellClassName:fe}=e,Te=i(C),oe=g(I,{count:J,rowIndex:G,columnIndex:H}),ke=I.dayjs.toDate();return I.selected=Te.find(ae=>ae.isSame(I.dayjs,"day")),I.isSelected=!!I.selected,I.isCurrent=S(I),I.disabled=ee==null?void 0:ee(ke),I.customClass=fe==null?void 0:fe(ke),oe},_=I=>{if(e.selectionMode==="week"){const[H,G]=e.showWeekNumber?[1,7]:[0,6],J=x(I[H+1]);I[H].inRange=J,I[H].start=J,I[G].inRange=J,I[G].end=J}},b=k(()=>{const{minDate:I,maxDate:H,rangeState:G,showWeekNumber:J}=e,ee=i(d),fe=i(s),Te="day";let oe=1;if(J)for(let ke=0;ke<6;ke++)fe[ke][0]||(fe[ke][0]={type:"week",text:i(p).add(ke*7+1,Te).week()});return jj({row:6,column:7},fe,{startDate:I,columnIndexOffset:J?1:0,nextEndDate:G.endDate||H||G.selecting&&I||null,now:ct().locale(i(n)).startOf(Te),unit:Te,relativeDateGetter:ke=>i(p).add(ke-ee,Te),setCellMetadata:(...ke)=>{y(...ke,oe)&&(oe+=1)},setRowMetadata:_}),fe});ve(()=>e.date,async()=>{var I;(I=i(o))!=null&&I.contains(document.activeElement)&&(await We(),await w())});const w=async()=>{var I;return(I=i(r))==null?void 0:I.focus()},S=I=>e.selectionMode==="date"&&Uh(I.type)&&E(I,e.parsedValue),E=(I,H)=>H?ct(H).locale(i(n)).isSame(e.date.date(Number(I.text)),"day"):!1,$=(I,H)=>{const G=I*7+(H-(e.showWeekNumber?1:0))-i(d);return i(p).add(G,"day")},O=I=>{var H;if(!e.rangeState.selecting)return;let G=I.target;if(G.tagName==="SPAN"&&(G=(H=G.parentNode)==null?void 0:H.parentNode),G.tagName==="DIV"&&(G=G.parentNode),G.tagName!=="TD")return;const J=G.parentNode.rowIndex-1,ee=G.cellIndex;i(b)[J][ee].disabled||(J!==i(a)||ee!==i(l))&&(a.value=J,l.value=ee,t("changerange",{selecting:!0,endDate:$(J,ee)}))},A=I=>!i(v)&&(I==null?void 0:I.text)===1&&I.type==="normal"||I.isCurrent,M=I=>{u||i(v)||e.selectionMode!=="date"||P(I,!0)},D=I=>{I.target.closest("td")&&(u=!0)},U=I=>{I.target.closest("td")&&(u=!1)},j=I=>{!e.rangeState.selecting||!e.minDate?(t("pick",{minDate:I,maxDate:null}),t("select",!0)):(I>=e.minDate?t("pick",{minDate:e.minDate,maxDate:I}):t("pick",{minDate:I,maxDate:e.minDate}),t("select",!1))},W=I=>{const H=I.week(),G=`${I.year()}w${H}`;t("pick",{year:I.year(),week:H,value:G,date:I.startOf("week")})},L=(I,H)=>{const G=H?Vn(e.parsedValue).filter(J=>(J==null?void 0:J.valueOf())!==I.valueOf()):Vn(e.parsedValue).concat([I]);t("pick",G)},P=(I,H=!1)=>{const G=I.target.closest("td");if(!G)return;const J=G.parentNode.rowIndex-1,ee=G.cellIndex,fe=i(b)[J][ee];if(fe.disabled||fe.type==="week")return;const Te=$(J,ee);switch(e.selectionMode){case"range":{j(Te);break}case"date":{t("pick",Te,H);break}case"week":{W(Te);break}case"dates":{L(Te,!!fe.selected);break}}},x=I=>{if(e.selectionMode!=="week")return!1;let H=e.date.startOf("day");if(I.type==="prev-month"&&(H=H.subtract(1,"month")),I.type==="next-month"&&(H=H.add(1,"month")),H=H.date(Number.parseInt(I.text,10)),e.parsedValue&&!Array.isArray(e.parsedValue)){const G=(e.parsedValue.day()-c+7)%7-1;return e.parsedValue.subtract(G,"day").isSame(H,"day")}return!1};return{WEEKS:m,rows:b,tbodyRef:o,currentCellRef:r,focus:w,isCurrent:S,isWeekActive:x,isSelectedCell:A,handlePickDate:P,handleMouseUp:U,handleMouseDown:D,handleMouseMove:O,handleFocus:M}},Kj=(e,{isCurrent:t,isWeekActive:n})=>{const o=Se("date-table"),{t:r}=$t(),a=k(()=>[o.b(),{"is-week-mode":e.selectionMode==="week"}]),l=k(()=>r("el.datepicker.dateTablePrompt")),s=k(()=>r("el.datepicker.week"));return{tableKls:a,tableLabel:l,weekLabel:s,getCellClasses:f=>{const d=[];return Uh(f.type)&&!f.disabled?(d.push("available"),f.type==="today"&&d.push("today")):d.push(f.type),t(f)&&d.push("current"),f.inRange&&(Uh(f.type)||e.selectionMode==="week")&&(d.push("in-range"),f.start&&d.push("start-date"),f.end&&d.push("end-date")),f.disabled&&d.push("disabled"),f.selected&&d.push("selected"),f.customClass&&d.push(f.customClass),d.join(" ")},getRowKls:f=>[o.e("row"),{current:n(f)}],t:r}},Uj=Ne({cell:{type:Q(Object)}});var qj=Y({name:"ElDatePickerCell",props:Uj,setup(e){const t=Se("date-table-cell"),{slots:n}=De(dg);return()=>{const{cell:o}=e;return ie(n,"default",{...o},()=>[K("div",{class:t.b()},[K("span",{class:t.e("text")},[o==null?void 0:o.text])])])}}});const Yj=["aria-label"],Gj={key:0,scope:"col"},Xj=["aria-label"],Jj=["aria-current","aria-selected","tabindex"],Zj=Y({__name:"basic-date-table",props:Hj,emits:zj,setup(e,{expose:t,emit:n}){const o=e,{WEEKS:r,rows:a,tbodyRef:l,currentCellRef:s,focus:u,isCurrent:c,isWeekActive:f,isSelectedCell:d,handlePickDate:p,handleMouseUp:m,handleMouseDown:v,handleMouseMove:h,handleFocus:C}=Wj(o,n),{tableLabel:g,tableKls:y,weekLabel:_,getCellClasses:b,getRowKls:w,t:S}=Kj(o,{isCurrent:c,isWeekActive:f});return t({focus:u}),(E,$)=>(T(),V("table",{"aria-label":i(g),class:N(i(y)),cellspacing:"0",cellpadding:"0",role:"grid",onClick:$[1]||($[1]=(...O)=>i(p)&&i(p)(...O)),onMousemove:$[2]||($[2]=(...O)=>i(h)&&i(h)(...O)),onMousedown:$[3]||($[3]=Qe((...O)=>i(v)&&i(v)(...O),["prevent"])),onMouseup:$[4]||($[4]=(...O)=>i(m)&&i(m)(...O))},[F("tbody",{ref_key:"tbodyRef",ref:l},[F("tr",null,[E.showWeekNumber?(T(),V("th",Gj,le(i(_)),1)):te("v-if",!0),(T(!0),V(Ve,null,bt(i(r),(O,A)=>(T(),V("th",{key:A,"aria-label":i(S)("el.datepicker.weeksFull."+O),scope:"col"},le(i(S)("el.datepicker.weeks."+O)),9,Xj))),128))]),(T(!0),V(Ve,null,bt(i(a),(O,A)=>(T(),V("tr",{key:A,class:N(i(w)(O[1]))},[(T(!0),V(Ve,null,bt(O,(M,D)=>(T(),V("td",{key:`${A}.${D}`,ref_for:!0,ref:U=>i(d)(M)&&(s.value=U),class:N(i(b)(M)),"aria-current":M.isCurrent?"date":void 0,"aria-selected":M.isCurrent,tabindex:i(d)(M)?0:-1,onFocus:$[0]||($[0]=(...U)=>i(C)&&i(C)(...U))},[K(i(qj),{cell:M},null,8,["cell"])],42,Jj))),128))],2))),128))],512)],42,Yj))}});var qh=Ie(Zj,[["__file","basic-date-table.vue"]]);const Qj=Ne({...fg,selectionMode:pg("month")}),eW=["aria-label"],tW=["aria-selected","aria-label","tabindex","onKeydown"],nW={class:"cell"},oW=Y({__name:"basic-month-table",props:Qj,emits:["changerange","pick","select"],setup(e,{expose:t,emit:n}){const o=e,r=(b,w,S)=>{const E=ct().locale(S).startOf("month").month(w).year(b),$=E.daysInMonth();return Sa($).map(O=>E.add(O,"day").toDate())},a=Se("month-table"),{t:l,lang:s}=$t(),u=R(),c=R(),f=R(o.date.locale("en").localeData().monthsShort().map(b=>b.toLowerCase())),d=R([[],[],[]]),p=R(),m=R(),v=k(()=>{var b,w;const S=d.value,E=ct().locale(s.value).startOf("month");for(let $=0;$<3;$++){const O=S[$];for(let A=0;A<4;A++){const M=O[A]||(O[A]={row:$,column:A,type:"normal",inRange:!1,start:!1,end:!1,text:-1,disabled:!1});M.type="normal";const D=$*4+A,U=o.date.startOf("year").month(D),j=o.rangeState.endDate||o.maxDate||o.rangeState.selecting&&o.minDate||null;M.inRange=!!(o.minDate&&U.isSameOrAfter(o.minDate,"month")&&j&&U.isSameOrBefore(j,"month"))||!!(o.minDate&&U.isSameOrBefore(o.minDate,"month")&&j&&U.isSameOrAfter(j,"month")),(b=o.minDate)!=null&&b.isSameOrAfter(j)?(M.start=!!(j&&U.isSame(j,"month")),M.end=o.minDate&&U.isSame(o.minDate,"month")):(M.start=!!(o.minDate&&U.isSame(o.minDate,"month")),M.end=!!(j&&U.isSame(j,"month"))),E.isSame(U)&&(M.type="today"),M.text=D,M.disabled=((w=o.disabledDate)==null?void 0:w.call(o,U.toDate()))||!1}}return S}),h=()=>{var b;(b=c.value)==null||b.focus()},C=b=>{const w={},S=o.date.year(),E=new Date,$=b.text;return w.disabled=o.disabledDate?r(S,$,s.value).every(o.disabledDate):!1,w.current=Vn(o.parsedValue).findIndex(O=>ct.isDayjs(O)&&O.year()===S&&O.month()===$)>=0,w.today=E.getFullYear()===S&&E.getMonth()===$,b.inRange&&(w["in-range"]=!0,b.start&&(w["start-date"]=!0),b.end&&(w["end-date"]=!0)),w},g=b=>{const w=o.date.year(),S=b.text;return Vn(o.date).findIndex(E=>E.year()===w&&E.month()===S)>=0},y=b=>{var w;if(!o.rangeState.selecting)return;let S=b.target;if(S.tagName==="SPAN"&&(S=(w=S.parentNode)==null?void 0:w.parentNode),S.tagName==="DIV"&&(S=S.parentNode),S.tagName!=="TD")return;const E=S.parentNode.rowIndex,$=S.cellIndex;v.value[E][$].disabled||(E!==p.value||$!==m.value)&&(p.value=E,m.value=$,n("changerange",{selecting:!0,endDate:o.date.startOf("year").month(E*4+$)}))},_=b=>{var w;const S=(w=b.target)==null?void 0:w.closest("td");if((S==null?void 0:S.tagName)!=="TD"||wo(S,"disabled"))return;const E=S.cellIndex,O=S.parentNode.rowIndex*4+E,A=o.date.startOf("year").month(O);if(o.selectionMode==="months"){if(b.type==="keydown"){n("pick",Vn(o.parsedValue),!1);return}const M=o.date.startOf("month").month(O),D=wo(S,"current")?Vn(o.parsedValue).filter(U=>Number(U)!==Number(M)):Vn(o.parsedValue).concat([ct(M)]);n("pick",D)}else o.selectionMode==="range"?o.rangeState.selecting?(o.minDate&&A>=o.minDate?n("pick",{minDate:o.minDate,maxDate:A}):n("pick",{minDate:A,maxDate:o.minDate}),n("select",!1)):(n("pick",{minDate:A,maxDate:null}),n("select",!0)):n("pick",O)};return ve(()=>o.date,async()=>{var b,w;(b=u.value)!=null&&b.contains(document.activeElement)&&(await We(),(w=c.value)==null||w.focus())}),t({focus:h}),(b,w)=>(T(),V("table",{role:"grid","aria-label":i(l)("el.datepicker.monthTablePrompt"),class:N(i(a).b()),onClick:_,onMousemove:y},[F("tbody",{ref_key:"tbodyRef",ref:u},[(T(!0),V(Ve,null,bt(i(v),(S,E)=>(T(),V("tr",{key:E},[(T(!0),V(Ve,null,bt(S,($,O)=>(T(),V("td",{key:O,ref_for:!0,ref:A=>g($)&&(c.value=A),class:N(C($)),"aria-selected":`${g($)}`,"aria-label":i(l)(`el.datepicker.month${+$.text+1}`),tabindex:g($)?0:-1,onKeydown:[Pt(Qe(_,["prevent","stop"]),["space"]),Pt(Qe(_,["prevent","stop"]),["enter"])]},[F("div",null,[F("span",nW,le(i(l)("el.datepicker.months."+f.value[$.text])),1)])],42,tW))),128))]))),128))],512)],42,eW))}});var Yh=Ie(oW,[["__file","basic-month-table.vue"]]);const{date:rW,disabledDate:aW,parsedValue:lW}=fg,sW=Ne({date:rW,disabledDate:aW,parsedValue:lW,selectionMode:pg("year")}),iW=["aria-label"],uW=["aria-selected","tabindex","onKeydown"],cW={class:"cell"},dW={key:1},fW=Y({__name:"basic-year-table",props:sW,emits:["pick"],setup(e,{expose:t,emit:n}){const o=e,r=(h,C)=>{const g=ct(String(h)).locale(C).startOf("year"),_=g.endOf("year").dayOfYear();return Sa(_).map(b=>g.add(b,"day").toDate())},a=Se("year-table"),{t:l,lang:s}=$t(),u=R(),c=R(),f=k(()=>Math.floor(o.date.year()/10)*10),d=()=>{var h;(h=c.value)==null||h.focus()},p=h=>{const C={},g=ct().locale(s.value);return C.disabled=o.disabledDate?r(h,s.value).every(o.disabledDate):!1,C.current=Vn(o.parsedValue).findIndex(y=>y.year()===h)>=0,C.today=g.year()===h,C},m=h=>h===f.value&&o.date.year()f.value+9||Vn(o.date).findIndex(C=>C.year()===h)>=0||Vn(o.parsedValue).findIndex(C=>(C==null?void 0:C.year())===h)>=0,v=h=>{const g=h.target.closest("td");if(g&&g.textContent){if(wo(g,"disabled"))return;const y=g.textContent||g.innerText;if(o.selectionMode==="years"){if(h.type==="keydown"){n("pick",Vn(o.parsedValue),!1);return}const _=wo(g,"current")?Vn(o.parsedValue).filter(b=>(b==null?void 0:b.year())!==Number(y)):Vn(o.parsedValue).concat([ct(y)]);n("pick",_)}else n("pick",Number(y))}};return ve(()=>o.date,async()=>{var h,C;(h=u.value)!=null&&h.contains(document.activeElement)&&(await We(),(C=c.value)==null||C.focus())}),t({focus:d}),(h,C)=>(T(),V("table",{role:"grid","aria-label":i(l)("el.datepicker.yearTablePrompt"),class:N(i(a).b()),onClick:v},[F("tbody",{ref_key:"tbodyRef",ref:u},[(T(),V(Ve,null,bt(3,(g,y)=>F("tr",{key:y},[(T(),V(Ve,null,bt(4,(_,b)=>(T(),V(Ve,{key:y+"_"+b},[y*4+b<10?(T(),V("td",{key:0,ref_for:!0,ref:w=>m(i(f)+y*4+b)&&(c.value=w),class:N(["available",p(i(f)+y*4+b)]),"aria-selected":`${m(i(f)+y*4+b)}`,tabindex:m(i(f)+y*4+b)?0:-1,onKeydown:[Pt(Qe(v,["prevent","stop"]),["space"]),Pt(Qe(v,["prevent","stop"]),["enter"])]},[F("div",null,[F("span",cW,le(i(f)+y*4+b),1)])],42,uW)):(T(),V("td",dW))],64))),64))])),64))],512)],10,iW))}});var pW=Ie(fW,[["__file","basic-year-table.vue"]]);const hW=["onClick"],mW=["aria-label"],vW=["aria-label"],gW=["aria-label"],bW=["aria-label"],yW=Y({__name:"panel-date-pick",props:Vj,emits:["pick","set-picker-option","panel-change"],setup(e,{emit:t}){const n=e,o=(Ee,ye,ne)=>!0,r=Se("picker-panel"),a=Se("date-picker"),l=xa(),s=Sn(),{t:u,lang:c}=$t(),f=De("EP_PICKER_BASE"),d=De(kf),{shortcuts:p,disabledDate:m,cellClassName:v,defaultTime:h}=f.props,C=Lt(f.props,"defaultValue"),g=R(),y=R(ct().locale(c.value)),_=R(!1);let b=!1;const w=k(()=>ct(h).locale(c.value)),S=k(()=>y.value.month()),E=k(()=>y.value.year()),$=R([]),O=R(null),A=R(null),M=Ee=>$.value.length>0?o(Ee,$.value,n.format||"HH:mm:ss"):!0,D=Ee=>h&&!Z.value&&!_.value&&!b?w.value.year(Ee.year()).month(Ee.month()).date(Ee.date()):ke.value?Ee.millisecond(0):Ee.startOf("day"),U=(Ee,...ye)=>{if(!Ee)t("pick",Ee,...ye);else if(Pe(Ee)){const ne=Ee.map(D);t("pick",ne,...ye)}else t("pick",D(Ee),...ye);O.value=null,A.value=null,_.value=!1,b=!1},j=async(Ee,ye)=>{if(H.value==="date"){Ee=Ee;let ne=n.parsedValue?n.parsedValue.year(Ee.year()).month(Ee.month()).date(Ee.date()):Ee;M(ne)||(ne=$.value[0][0].year(Ee.year()).month(Ee.month()).date(Ee.date())),y.value=ne,U(ne,ke.value||ye),n.type==="datetime"&&(await We(),rt())}else H.value==="week"?U(Ee.date):H.value==="dates"&&U(Ee,!0)},W=Ee=>{const ye=Ee?"add":"subtract";y.value=y.value[ye](1,"month"),st("month")},L=Ee=>{const ye=y.value,ne=Ee?"add":"subtract";y.value=P.value==="year"?ye[ne](10,"year"):ye[ne](1,"year"),st("year")},P=R("date"),x=k(()=>{const Ee=u("el.datepicker.year");if(P.value==="year"){const ye=Math.floor(E.value/10)*10;return Ee?`${ye} ${Ee} - ${ye+9} ${Ee}`:`${ye} - ${ye+9}`}return`${E.value} ${Ee}`}),I=Ee=>{const ye=Xe(Ee.value)?Ee.value():Ee.value;if(ye){b=!0,U(ct(ye).locale(c.value));return}Ee.onClick&&Ee.onClick({attrs:l,slots:s,emit:t})},H=k(()=>{const{type:Ee}=n;return["week","month","months","year","years","dates"].includes(Ee)?Ee:"date"}),G=k(()=>H.value==="dates"||H.value==="months"||H.value==="years"),J=k(()=>H.value==="date"?P.value:H.value),ee=k(()=>!!p.length),fe=async(Ee,ye)=>{H.value==="month"?(y.value=y.value.startOf("month").month(Ee),U(y.value,!1)):H.value==="months"?U(Ee,ye??!0):(y.value=y.value.startOf("month").month(Ee),P.value="date",["month","year","date","week"].includes(H.value)&&(U(y.value,!0),await We(),rt())),st("month")},Te=async(Ee,ye)=>{H.value==="year"?(y.value=y.value.startOf("year").year(Ee),U(y.value,!1)):H.value==="years"?U(Ee,ye??!0):(y.value=y.value.year(Ee),P.value="month",["month","year","date","week"].includes(H.value)&&(U(y.value,!0),await We(),rt())),st("year")},oe=async Ee=>{P.value=Ee,await We(),rt()},ke=k(()=>n.type==="datetime"||n.type==="datetimerange"),ae=k(()=>{const Ee=ke.value||H.value==="dates",ye=H.value==="years",ne=H.value==="months",be=P.value==="date",Fe=P.value==="year",vt=P.value==="month";return Ee&&be||ye&&Fe||ne&&vt}),Oe=k(()=>m?n.parsedValue?Pe(n.parsedValue)?m(n.parsedValue[0].toDate()):m(n.parsedValue.toDate()):!0:!1),we=()=>{if(G.value)U(n.parsedValue);else{let Ee=n.parsedValue;if(!Ee){const ye=ct(h).locale(c.value),ne=et();Ee=ye.year(ne.year()).month(ne.month()).date(ne.date())}y.value=Ee,U(Ee)}},ge=k(()=>m?m(ct().locale(c.value).toDate()):!1),q=()=>{const ye=ct().locale(c.value).toDate();_.value=!0,(!m||!m(ye))&&M(ye)&&(y.value=ct().locale(c.value),U(y.value))},B=k(()=>n.timeFormat||fk(n.format)),z=k(()=>n.dateFormat||dk(n.format)),Z=k(()=>{if(A.value)return A.value;if(!(!n.parsedValue&&!C.value))return(n.parsedValue||y.value).format(B.value)}),ue=k(()=>{if(O.value)return O.value;if(!(!n.parsedValue&&!C.value))return(n.parsedValue||y.value).format(z.value)}),se=R(!1),me=()=>{se.value=!0},_e=()=>{se.value=!1},$e=Ee=>({hour:Ee.hour(),minute:Ee.minute(),second:Ee.second(),year:Ee.year(),month:Ee.month(),date:Ee.date()}),Ce=(Ee,ye,ne)=>{const{hour:be,minute:Fe,second:vt}=$e(Ee),pe=n.parsedValue?n.parsedValue.hour(be).minute(Fe).second(vt):Ee;y.value=pe,U(y.value,!0),ne||(se.value=ye)},ce=Ee=>{const ye=ct(Ee,B.value).locale(c.value);if(ye.isValid()&&M(ye)){const{year:ne,month:be,date:Fe}=$e(y.value);y.value=ye.year(ne).month(be).date(Fe),A.value=null,se.value=!1,U(y.value,!0)}},de=Ee=>{const ye=ct(Ee,z.value).locale(c.value);if(ye.isValid()){if(m&&m(ye.toDate()))return;const{hour:ne,minute:be,second:Fe}=$e(y.value);y.value=ye.hour(ne).minute(be).second(Fe),O.value=null,U(y.value,!0)}},xe=Ee=>ct.isDayjs(Ee)&&Ee.isValid()&&(m?!m(Ee.toDate()):!0),he=Ee=>Pe(Ee)?Ee.map(ye=>ye.format(n.format)):Ee.format(n.format),He=Ee=>ct(Ee,n.format).locale(c.value),et=()=>{const Ee=ct(C.value).locale(c.value);if(!C.value){const ye=w.value;return ct().hour(ye.hour()).minute(ye.minute()).second(ye.second()).locale(c.value)}return Ee},rt=async()=>{var Ee;["week","month","year","date"].includes(H.value)&&((Ee=g.value)==null||Ee.focus(),H.value==="week"&&Ze(Ue.down))},wt=Ee=>{const{code:ye}=Ee;[Ue.up,Ue.down,Ue.left,Ue.right,Ue.home,Ue.end,Ue.pageUp,Ue.pageDown].includes(ye)&&(Ze(ye),Ee.stopPropagation(),Ee.preventDefault()),[Ue.enter,Ue.space,Ue.numpadEnter].includes(ye)&&O.value===null&&A.value===null&&(Ee.preventDefault(),U(y.value,!1))},Ze=Ee=>{var ye;const{up:ne,down:be,left:Fe,right:vt,home:pe,end:Ye,pageUp:_t,pageDown:Kt}=Ue,Jt={year:{[ne]:-4,[be]:4,[Fe]:-1,[vt]:1,offset:(At,Fn)=>At.setFullYear(At.getFullYear()+Fn)},month:{[ne]:-4,[be]:4,[Fe]:-1,[vt]:1,offset:(At,Fn)=>At.setMonth(At.getMonth()+Fn)},week:{[ne]:-1,[be]:1,[Fe]:-1,[vt]:1,offset:(At,Fn)=>At.setDate(At.getDate()+Fn*7)},date:{[ne]:-7,[be]:7,[Fe]:-1,[vt]:1,[pe]:At=>-At.getDay(),[Ye]:At=>-At.getDay()+6,[_t]:At=>-new Date(At.getFullYear(),At.getMonth(),0).getDate(),[Kt]:At=>new Date(At.getFullYear(),At.getMonth()+1,0).getDate(),offset:(At,Fn)=>At.setDate(At.getDate()+Fn)}},Ht=y.value.toDate();for(;Math.abs(y.value.diff(Ht,"year",!0))<1;){const At=Jt[J.value];if(!At)return;if(At.offset(Ht,Xe(At[Ee])?At[Ee](Ht):(ye=At[Ee])!=null?ye:0),m&&m(Ht))break;const Fn=ct(Ht).locale(c.value);y.value=Fn,t("pick",Fn,!0);break}},st=Ee=>{t("panel-change",y.value.toDate(),Ee,P.value)};return ve(()=>H.value,Ee=>{if(["month","year"].includes(Ee)){P.value=Ee;return}else if(Ee==="years"){P.value="year";return}else if(Ee==="months"){P.value="month";return}P.value="date"},{immediate:!0}),ve(()=>P.value,()=>{d==null||d.updatePopper()}),ve(()=>C.value,Ee=>{Ee&&(y.value=et())},{immediate:!0}),ve(()=>n.parsedValue,Ee=>{if(Ee){if(G.value||Array.isArray(Ee))return;y.value=Ee}else y.value=et()},{immediate:!0}),t("set-picker-option",["isValidValue",xe]),t("set-picker-option",["formatToString",he]),t("set-picker-option",["parseUserInput",He]),t("set-picker-option",["handleFocusPicker",rt]),(Ee,ye)=>(T(),V("div",{class:N([i(r).b(),i(a).b(),{"has-sidebar":Ee.$slots.sidebar||i(ee),"has-time":i(ke)}])},[F("div",{class:N(i(r).e("body-wrapper"))},[ie(Ee.$slots,"sidebar",{class:N(i(r).e("sidebar"))}),i(ee)?(T(),V("div",{key:0,class:N(i(r).e("sidebar"))},[(T(!0),V(Ve,null,bt(i(p),(ne,be)=>(T(),V("button",{key:be,type:"button",class:N(i(r).e("shortcut")),onClick:Fe=>I(ne)},le(ne.text),11,hW))),128))],2)):te("v-if",!0),F("div",{class:N(i(r).e("body"))},[i(ke)?(T(),V("div",{key:0,class:N(i(a).e("time-header"))},[F("span",{class:N(i(a).e("editor-wrap"))},[K(i(zn),{placeholder:i(u)("el.datepicker.selectDate"),"model-value":i(ue),size:"small","validate-event":!1,onInput:ye[0]||(ye[0]=ne=>O.value=ne),onChange:de},null,8,["placeholder","model-value"])],2),tt((T(),V("span",{class:N(i(a).e("editor-wrap"))},[K(i(zn),{placeholder:i(u)("el.datepicker.selectTime"),"model-value":i(Z),size:"small","validate-event":!1,onFocus:me,onInput:ye[1]||(ye[1]=ne=>A.value=ne),onChange:ce},null,8,["placeholder","model-value"]),K(i(_d),{visible:se.value,format:i(B),"parsed-value":y.value,onPick:Ce},null,8,["visible","format","parsed-value"])],2)),[[i(Yr),_e]])],2)):te("v-if",!0),tt(F("div",{class:N([i(a).e("header"),(P.value==="year"||P.value==="month")&&i(a).e("header--bordered")])},[F("span",{class:N(i(a).e("prev-btn"))},[F("button",{type:"button","aria-label":i(u)("el.datepicker.prevYear"),class:N(["d-arrow-left",i(r).e("icon-btn")]),onClick:ye[2]||(ye[2]=ne=>L(!1))},[K(i(ze),null,{default:X(()=>[K(i(ks))]),_:1})],10,mW),tt(F("button",{type:"button","aria-label":i(u)("el.datepicker.prevMonth"),class:N([i(r).e("icon-btn"),"arrow-left"]),onClick:ye[3]||(ye[3]=ne=>W(!1))},[K(i(ze),null,{default:X(()=>[K(i(Aa))]),_:1})],10,vW),[[kt,P.value==="date"]])],2),F("span",{role:"button",class:N(i(a).e("header-label")),"aria-live":"polite",tabindex:"0",onKeydown:ye[4]||(ye[4]=Pt(ne=>oe("year"),["enter"])),onClick:ye[5]||(ye[5]=ne=>oe("year"))},le(i(x)),35),tt(F("span",{role:"button","aria-live":"polite",tabindex:"0",class:N([i(a).e("header-label"),{active:P.value==="month"}]),onKeydown:ye[6]||(ye[6]=Pt(ne=>oe("month"),["enter"])),onClick:ye[7]||(ye[7]=ne=>oe("month"))},le(i(u)(`el.datepicker.month${i(S)+1}`)),35),[[kt,P.value==="date"]]),F("span",{class:N(i(a).e("next-btn"))},[tt(F("button",{type:"button","aria-label":i(u)("el.datepicker.nextMonth"),class:N([i(r).e("icon-btn"),"arrow-right"]),onClick:ye[8]||(ye[8]=ne=>W(!0))},[K(i(ze),null,{default:X(()=>[K(i(Jn))]),_:1})],10,gW),[[kt,P.value==="date"]]),F("button",{type:"button","aria-label":i(u)("el.datepicker.nextYear"),class:N([i(r).e("icon-btn"),"d-arrow-right"]),onClick:ye[9]||(ye[9]=ne=>L(!0))},[K(i(ze),null,{default:X(()=>[K(i(Es))]),_:1})],10,bW)],2)],2),[[kt,P.value!=="time"]]),F("div",{class:N(i(r).e("content")),onKeydown:wt},[P.value==="date"?(T(),re(qh,{key:0,ref_key:"currentViewRef",ref:g,"selection-mode":i(H),date:y.value,"parsed-value":Ee.parsedValue,"disabled-date":i(m),"cell-class-name":i(v),onPick:j},null,8,["selection-mode","date","parsed-value","disabled-date","cell-class-name"])):te("v-if",!0),P.value==="year"?(T(),re(pW,{key:1,ref_key:"currentViewRef",ref:g,"selection-mode":i(H),date:y.value,"disabled-date":i(m),"parsed-value":Ee.parsedValue,onPick:Te},null,8,["selection-mode","date","disabled-date","parsed-value"])):te("v-if",!0),P.value==="month"?(T(),re(Yh,{key:2,ref_key:"currentViewRef",ref:g,"selection-mode":i(H),date:y.value,"parsed-value":Ee.parsedValue,"disabled-date":i(m),onPick:fe},null,8,["selection-mode","date","parsed-value","disabled-date"])):te("v-if",!0)],34)],2)],2),tt(F("div",{class:N(i(r).e("footer"))},[tt(K(i($n),{text:"",size:"small",class:N(i(r).e("link-btn")),disabled:i(ge),onClick:q},{default:X(()=>[Ge(le(i(u)("el.datepicker.now")),1)]),_:1},8,["class","disabled"]),[[kt,!i(G)]]),K(i($n),{plain:"",size:"small",class:N(i(r).e("link-btn")),disabled:i(Oe),onClick:we},{default:X(()=>[Ge(le(i(u)("el.datepicker.confirm")),1)]),_:1},8,["class","disabled"])],2),[[kt,i(ae)]])],2))}});var wW=Ie(yW,[["__file","panel-date-pick.vue"]]);const _W=Ne({...lE,...sE}),CW=e=>{const{emit:t}=lt(),n=xa(),o=Sn();return a=>{const l=Xe(a.value)?a.value():a.value;if(l){t("pick",[ct(l[0]).locale(e.value),ct(l[1]).locale(e.value)]);return}a.onClick&&a.onClick({attrs:n,slots:o,emit:t})}},uE=(e,{defaultValue:t,leftDate:n,rightDate:o,unit:r,onParsedValueChanged:a})=>{const{emit:l}=lt(),{pickerNs:s}=De(dg),u=Se("date-range-picker"),{t:c,lang:f}=$t(),d=CW(f),p=R(),m=R(),v=R({endDate:null,selecting:!1}),h=_=>{v.value=_},C=(_=!1)=>{const b=i(p),w=i(m);Kh([b,w])&&l("pick",[b,w],_)},g=_=>{v.value.selecting=_,_||(v.value.endDate=null)},y=()=>{const[_,b]=iE(i(t),{lang:i(f),unit:r,unlinkPanels:e.unlinkPanels});p.value=void 0,m.value=void 0,n.value=_,o.value=b};return ve(t,_=>{_&&y()},{immediate:!0}),ve(()=>e.parsedValue,_=>{if(Pe(_)&&_.length===2){const[b,w]=_;p.value=b,n.value=b,m.value=w,a(i(p),i(m))}else y()},{immediate:!0}),{minDate:p,maxDate:m,rangeState:v,lang:f,ppNs:s,drpNs:u,handleChangeRange:h,handleRangeConfirm:C,handleShortcutClick:d,onSelect:g,t:c}},SW=["onClick"],kW=["aria-label"],EW=["aria-label"],TW=["disabled","aria-label"],$W=["disabled","aria-label"],OW=["disabled","aria-label"],NW=["disabled","aria-label"],IW=["aria-label"],MW=["aria-label"],wc="month",AW=Y({__name:"panel-date-range",props:_W,emits:["pick","set-picker-option","calendar-change","panel-change"],setup(e,{emit:t}){const n=e,o=De("EP_PICKER_BASE"),{disabledDate:r,cellClassName:a,defaultTime:l,clearable:s}=o.props,u=Lt(o.props,"format"),c=Lt(o.props,"shortcuts"),f=Lt(o.props,"defaultValue"),{lang:d}=$t(),p=R(ct().locale(d.value)),m=R(ct().locale(d.value).add(1,wc)),{minDate:v,maxDate:h,rangeState:C,ppNs:g,drpNs:y,handleChangeRange:_,handleRangeConfirm:b,handleShortcutClick:w,onSelect:S,t:E}=uE(n,{defaultValue:f,leftDate:p,rightDate:m,unit:wc,onParsedValueChanged:Ee}),$=R({min:null,max:null}),O=R({min:null,max:null}),A=k(()=>`${p.value.year()} ${E("el.datepicker.year")} ${E(`el.datepicker.month${p.value.month()+1}`)}`),M=k(()=>`${m.value.year()} ${E("el.datepicker.year")} ${E(`el.datepicker.month${m.value.month()+1}`)}`),D=k(()=>p.value.year()),U=k(()=>p.value.month()),j=k(()=>m.value.year()),W=k(()=>m.value.month()),L=k(()=>!!c.value.length),P=k(()=>$.value.min!==null?$.value.min:v.value?v.value.format(J.value):""),x=k(()=>$.value.max!==null?$.value.max:h.value||v.value?(h.value||v.value).format(J.value):""),I=k(()=>O.value.min!==null?O.value.min:v.value?v.value.format(G.value):""),H=k(()=>O.value.max!==null?O.value.max:h.value||v.value?(h.value||v.value).format(G.value):""),G=k(()=>n.timeFormat||fk(u.value)),J=k(()=>n.dateFormat||dk(u.value)),ee=ye=>Kh(ye)&&(r?!r(ye[0].toDate())&&!r(ye[1].toDate()):!0),fe=()=>{p.value=p.value.subtract(1,"year"),n.unlinkPanels||(m.value=p.value.add(1,"month")),q("year")},Te=()=>{p.value=p.value.subtract(1,"month"),n.unlinkPanels||(m.value=p.value.add(1,"month")),q("month")},oe=()=>{n.unlinkPanels?m.value=m.value.add(1,"year"):(p.value=p.value.add(1,"year"),m.value=p.value.add(1,"month")),q("year")},ke=()=>{n.unlinkPanels?m.value=m.value.add(1,"month"):(p.value=p.value.add(1,"month"),m.value=p.value.add(1,"month")),q("month")},ae=()=>{p.value=p.value.add(1,"year"),q("year")},Oe=()=>{p.value=p.value.add(1,"month"),q("month")},we=()=>{m.value=m.value.subtract(1,"year"),q("year")},ge=()=>{m.value=m.value.subtract(1,"month"),q("month")},q=ye=>{t("panel-change",[p.value.toDate(),m.value.toDate()],ye)},B=k(()=>{const ye=(U.value+1)%12,ne=U.value+1>=12?1:0;return n.unlinkPanels&&new Date(D.value+ne,ye)n.unlinkPanels&&j.value*12+W.value-(D.value*12+U.value+1)>=12),Z=k(()=>!(v.value&&h.value&&!C.value.selecting&&Kh([v.value,h.value]))),ue=k(()=>n.type==="datetime"||n.type==="datetimerange"),se=(ye,ne)=>{if(ye)return l?ct(l[ne]||l).locale(d.value).year(ye.year()).month(ye.month()).date(ye.date()):ye},me=(ye,ne=!0)=>{const be=ye.minDate,Fe=ye.maxDate,vt=se(be,0),pe=se(Fe,1);h.value===pe&&v.value===vt||(t("calendar-change",[be.toDate(),Fe&&Fe.toDate()]),h.value=pe,v.value=vt,!(!ne||ue.value)&&b())},_e=R(!1),$e=R(!1),Ce=()=>{_e.value=!1},ce=()=>{$e.value=!1},de=(ye,ne)=>{$.value[ne]=ye;const be=ct(ye,J.value).locale(d.value);if(be.isValid()){if(r&&r(be.toDate()))return;ne==="min"?(p.value=be,v.value=(v.value||p.value).year(be.year()).month(be.month()).date(be.date()),!n.unlinkPanels&&(!h.value||h.value.isBefore(v.value))&&(m.value=be.add(1,"month"),h.value=v.value.add(1,"month"))):(m.value=be,h.value=(h.value||m.value).year(be.year()).month(be.month()).date(be.date()),!n.unlinkPanels&&(!v.value||v.value.isAfter(h.value))&&(p.value=be.subtract(1,"month"),v.value=h.value.subtract(1,"month")))}},xe=(ye,ne)=>{$.value[ne]=null},he=(ye,ne)=>{O.value[ne]=ye;const be=ct(ye,G.value).locale(d.value);be.isValid()&&(ne==="min"?(_e.value=!0,v.value=(v.value||p.value).hour(be.hour()).minute(be.minute()).second(be.second())):($e.value=!0,h.value=(h.value||m.value).hour(be.hour()).minute(be.minute()).second(be.second()),m.value=h.value))},He=(ye,ne)=>{O.value[ne]=null,ne==="min"?(p.value=v.value,_e.value=!1,(!h.value||h.value.isBefore(v.value))&&(h.value=v.value)):(m.value=h.value,$e.value=!1,h.value&&h.value.isBefore(v.value)&&(v.value=h.value))},et=(ye,ne,be)=>{O.value.min||(ye&&(p.value=ye,v.value=(v.value||p.value).hour(ye.hour()).minute(ye.minute()).second(ye.second())),be||(_e.value=ne),(!h.value||h.value.isBefore(v.value))&&(h.value=v.value,m.value=ye))},rt=(ye,ne,be)=>{O.value.max||(ye&&(m.value=ye,h.value=(h.value||m.value).hour(ye.hour()).minute(ye.minute()).second(ye.second())),be||($e.value=ne),h.value&&h.value.isBefore(v.value)&&(v.value=h.value))},wt=()=>{p.value=iE(i(f),{lang:i(d),unit:"month",unlinkPanels:n.unlinkPanels})[0],m.value=p.value.add(1,"month"),h.value=void 0,v.value=void 0,t("pick",null)},Ze=ye=>Pe(ye)?ye.map(ne=>ne.format(u.value)):ye.format(u.value),st=ye=>Pe(ye)?ye.map(ne=>ct(ne,u.value).locale(d.value)):ct(ye,u.value).locale(d.value);function Ee(ye,ne){if(n.unlinkPanels&&ne){const be=(ye==null?void 0:ye.year())||0,Fe=(ye==null?void 0:ye.month())||0,vt=ne.year(),pe=ne.month();m.value=be===vt&&Fe===pe?ne.add(1,wc):ne}else m.value=p.value.add(1,wc),ne&&(m.value=m.value.hour(ne.hour()).minute(ne.minute()).second(ne.second()))}return t("set-picker-option",["isValidValue",ee]),t("set-picker-option",["parseUserInput",st]),t("set-picker-option",["formatToString",Ze]),t("set-picker-option",["handleClear",wt]),(ye,ne)=>(T(),V("div",{class:N([i(g).b(),i(y).b(),{"has-sidebar":ye.$slots.sidebar||i(L),"has-time":i(ue)}])},[F("div",{class:N(i(g).e("body-wrapper"))},[ie(ye.$slots,"sidebar",{class:N(i(g).e("sidebar"))}),i(L)?(T(),V("div",{key:0,class:N(i(g).e("sidebar"))},[(T(!0),V(Ve,null,bt(i(c),(be,Fe)=>(T(),V("button",{key:Fe,type:"button",class:N(i(g).e("shortcut")),onClick:vt=>i(w)(be)},le(be.text),11,SW))),128))],2)):te("v-if",!0),F("div",{class:N(i(g).e("body"))},[i(ue)?(T(),V("div",{key:0,class:N(i(y).e("time-header"))},[F("span",{class:N(i(y).e("editors-wrap"))},[F("span",{class:N(i(y).e("time-picker-wrap"))},[K(i(zn),{size:"small",disabled:i(C).selecting,placeholder:i(E)("el.datepicker.startDate"),class:N(i(y).e("editor")),"model-value":i(P),"validate-event":!1,onInput:ne[0]||(ne[0]=be=>de(be,"min")),onChange:ne[1]||(ne[1]=be=>xe(be,"min"))},null,8,["disabled","placeholder","class","model-value"])],2),tt((T(),V("span",{class:N(i(y).e("time-picker-wrap"))},[K(i(zn),{size:"small",class:N(i(y).e("editor")),disabled:i(C).selecting,placeholder:i(E)("el.datepicker.startTime"),"model-value":i(I),"validate-event":!1,onFocus:ne[2]||(ne[2]=be=>_e.value=!0),onInput:ne[3]||(ne[3]=be=>he(be,"min")),onChange:ne[4]||(ne[4]=be=>He(be,"min"))},null,8,["class","disabled","placeholder","model-value"]),K(i(_d),{visible:_e.value,format:i(G),"datetime-role":"start","parsed-value":p.value,onPick:et},null,8,["visible","format","parsed-value"])],2)),[[i(Yr),Ce]])],2),F("span",null,[K(i(ze),null,{default:X(()=>[K(i(Jn))]),_:1})]),F("span",{class:N([i(y).e("editors-wrap"),"is-right"])},[F("span",{class:N(i(y).e("time-picker-wrap"))},[K(i(zn),{size:"small",class:N(i(y).e("editor")),disabled:i(C).selecting,placeholder:i(E)("el.datepicker.endDate"),"model-value":i(x),readonly:!i(v),"validate-event":!1,onInput:ne[5]||(ne[5]=be=>de(be,"max")),onChange:ne[6]||(ne[6]=be=>xe(be,"max"))},null,8,["class","disabled","placeholder","model-value","readonly"])],2),tt((T(),V("span",{class:N(i(y).e("time-picker-wrap"))},[K(i(zn),{size:"small",class:N(i(y).e("editor")),disabled:i(C).selecting,placeholder:i(E)("el.datepicker.endTime"),"model-value":i(H),readonly:!i(v),"validate-event":!1,onFocus:ne[7]||(ne[7]=be=>i(v)&&($e.value=!0)),onInput:ne[8]||(ne[8]=be=>he(be,"max")),onChange:ne[9]||(ne[9]=be=>He(be,"max"))},null,8,["class","disabled","placeholder","model-value","readonly"]),K(i(_d),{"datetime-role":"end",visible:$e.value,format:i(G),"parsed-value":m.value,onPick:rt},null,8,["visible","format","parsed-value"])],2)),[[i(Yr),ce]])],2)],2)):te("v-if",!0),F("div",{class:N([[i(g).e("content"),i(y).e("content")],"is-left"])},[F("div",{class:N(i(y).e("header"))},[F("button",{type:"button",class:N([i(g).e("icon-btn"),"d-arrow-left"]),"aria-label":i(E)("el.datepicker.prevYear"),onClick:fe},[K(i(ze),null,{default:X(()=>[K(i(ks))]),_:1})],10,kW),F("button",{type:"button",class:N([i(g).e("icon-btn"),"arrow-left"]),"aria-label":i(E)("el.datepicker.prevMonth"),onClick:Te},[K(i(ze),null,{default:X(()=>[K(i(Aa))]),_:1})],10,EW),ye.unlinkPanels?(T(),V("button",{key:0,type:"button",disabled:!i(z),class:N([[i(g).e("icon-btn"),{"is-disabled":!i(z)}],"d-arrow-right"]),"aria-label":i(E)("el.datepicker.nextYear"),onClick:ae},[K(i(ze),null,{default:X(()=>[K(i(Es))]),_:1})],10,TW)):te("v-if",!0),ye.unlinkPanels?(T(),V("button",{key:1,type:"button",disabled:!i(B),class:N([[i(g).e("icon-btn"),{"is-disabled":!i(B)}],"arrow-right"]),"aria-label":i(E)("el.datepicker.nextMonth"),onClick:Oe},[K(i(ze),null,{default:X(()=>[K(i(Jn))]),_:1})],10,$W)):te("v-if",!0),F("div",null,le(i(A)),1)],2),K(qh,{"selection-mode":"range",date:p.value,"min-date":i(v),"max-date":i(h),"range-state":i(C),"disabled-date":i(r),"cell-class-name":i(a),onChangerange:i(_),onPick:me,onSelect:i(S)},null,8,["date","min-date","max-date","range-state","disabled-date","cell-class-name","onChangerange","onSelect"])],2),F("div",{class:N([[i(g).e("content"),i(y).e("content")],"is-right"])},[F("div",{class:N(i(y).e("header"))},[ye.unlinkPanels?(T(),V("button",{key:0,type:"button",disabled:!i(z),class:N([[i(g).e("icon-btn"),{"is-disabled":!i(z)}],"d-arrow-left"]),"aria-label":i(E)("el.datepicker.prevYear"),onClick:we},[K(i(ze),null,{default:X(()=>[K(i(ks))]),_:1})],10,OW)):te("v-if",!0),ye.unlinkPanels?(T(),V("button",{key:1,type:"button",disabled:!i(B),class:N([[i(g).e("icon-btn"),{"is-disabled":!i(B)}],"arrow-left"]),"aria-label":i(E)("el.datepicker.prevMonth"),onClick:ge},[K(i(ze),null,{default:X(()=>[K(i(Aa))]),_:1})],10,NW)):te("v-if",!0),F("button",{type:"button","aria-label":i(E)("el.datepicker.nextYear"),class:N([i(g).e("icon-btn"),"d-arrow-right"]),onClick:oe},[K(i(ze),null,{default:X(()=>[K(i(Es))]),_:1})],10,IW),F("button",{type:"button",class:N([i(g).e("icon-btn"),"arrow-right"]),"aria-label":i(E)("el.datepicker.nextMonth"),onClick:ke},[K(i(ze),null,{default:X(()=>[K(i(Jn))]),_:1})],10,MW),F("div",null,le(i(M)),1)],2),K(qh,{"selection-mode":"range",date:m.value,"min-date":i(v),"max-date":i(h),"range-state":i(C),"disabled-date":i(r),"cell-class-name":i(a),onChangerange:i(_),onPick:me,onSelect:i(S)},null,8,["date","min-date","max-date","range-state","disabled-date","cell-class-name","onChangerange","onSelect"])],2)],2)],2),i(ue)?(T(),V("div",{key:0,class:N(i(g).e("footer"))},[i(s)?(T(),re(i($n),{key:0,text:"",size:"small",class:N(i(g).e("link-btn")),onClick:wt},{default:X(()=>[Ge(le(i(E)("el.datepicker.clear")),1)]),_:1},8,["class"])):te("v-if",!0),K(i($n),{plain:"",size:"small",class:N(i(g).e("link-btn")),disabled:i(Z),onClick:ne[10]||(ne[10]=be=>i(b)(!1))},{default:X(()=>[Ge(le(i(E)("el.datepicker.confirm")),1)]),_:1},8,["class","disabled"])],2)):te("v-if",!0)],2))}});var PW=Ie(AW,[["__file","panel-date-range.vue"]]);const RW=Ne({...sE}),LW=["pick","set-picker-option","calendar-change"],xW=({unlinkPanels:e,leftDate:t,rightDate:n})=>{const{t:o}=$t(),r=()=>{t.value=t.value.subtract(1,"year"),e.value||(n.value=n.value.subtract(1,"year"))},a=()=>{e.value||(t.value=t.value.add(1,"year")),n.value=n.value.add(1,"year")},l=()=>{t.value=t.value.add(1,"year")},s=()=>{n.value=n.value.subtract(1,"year")},u=k(()=>`${t.value.year()} ${o("el.datepicker.year")}`),c=k(()=>`${n.value.year()} ${o("el.datepicker.year")}`),f=k(()=>t.value.year()),d=k(()=>n.value.year()===t.value.year()?t.value.year()+1:n.value.year());return{leftPrevYear:r,rightNextYear:a,leftNextYear:l,rightPrevYear:s,leftLabel:u,rightLabel:c,leftYear:f,rightYear:d}},DW=["onClick"],FW=["disabled"],BW=["disabled"],_c="year",VW=Y({name:"DatePickerMonthRange"}),HW=Y({...VW,props:RW,emits:LW,setup(e,{emit:t}){const n=e,{lang:o}=$t(),r=De("EP_PICKER_BASE"),{shortcuts:a,disabledDate:l}=r.props,s=Lt(r.props,"format"),u=Lt(r.props,"defaultValue"),c=R(ct().locale(o.value)),f=R(ct().locale(o.value).add(1,_c)),{minDate:d,maxDate:p,rangeState:m,ppNs:v,drpNs:h,handleChangeRange:C,handleRangeConfirm:g,handleShortcutClick:y,onSelect:_}=uE(n,{defaultValue:u,leftDate:c,rightDate:f,unit:_c,onParsedValueChanged:L}),b=k(()=>!!a.length),{leftPrevYear:w,rightNextYear:S,leftNextYear:E,rightPrevYear:$,leftLabel:O,rightLabel:A,leftYear:M,rightYear:D}=xW({unlinkPanels:Lt(n,"unlinkPanels"),leftDate:c,rightDate:f}),U=k(()=>n.unlinkPanels&&D.value>M.value+1),j=(P,x=!0)=>{const I=P.minDate,H=P.maxDate;p.value===H&&d.value===I||(t("calendar-change",[I.toDate(),H&&H.toDate()]),p.value=H,d.value=I,x&&g())},W=P=>P.map(x=>x.format(s.value));function L(P,x){if(n.unlinkPanels&&x){const I=(P==null?void 0:P.year())||0,H=x.year();f.value=I===H?x.add(1,_c):x}else f.value=c.value.add(1,_c)}return t("set-picker-option",["formatToString",W]),(P,x)=>(T(),V("div",{class:N([i(v).b(),i(h).b(),{"has-sidebar":!!P.$slots.sidebar||i(b)}])},[F("div",{class:N(i(v).e("body-wrapper"))},[ie(P.$slots,"sidebar",{class:N(i(v).e("sidebar"))}),i(b)?(T(),V("div",{key:0,class:N(i(v).e("sidebar"))},[(T(!0),V(Ve,null,bt(i(a),(I,H)=>(T(),V("button",{key:H,type:"button",class:N(i(v).e("shortcut")),onClick:G=>i(y)(I)},le(I.text),11,DW))),128))],2)):te("v-if",!0),F("div",{class:N(i(v).e("body"))},[F("div",{class:N([[i(v).e("content"),i(h).e("content")],"is-left"])},[F("div",{class:N(i(h).e("header"))},[F("button",{type:"button",class:N([i(v).e("icon-btn"),"d-arrow-left"]),onClick:x[0]||(x[0]=(...I)=>i(w)&&i(w)(...I))},[K(i(ze),null,{default:X(()=>[K(i(ks))]),_:1})],2),P.unlinkPanels?(T(),V("button",{key:0,type:"button",disabled:!i(U),class:N([[i(v).e("icon-btn"),{[i(v).is("disabled")]:!i(U)}],"d-arrow-right"]),onClick:x[1]||(x[1]=(...I)=>i(E)&&i(E)(...I))},[K(i(ze),null,{default:X(()=>[K(i(Es))]),_:1})],10,FW)):te("v-if",!0),F("div",null,le(i(O)),1)],2),K(Yh,{"selection-mode":"range",date:c.value,"min-date":i(d),"max-date":i(p),"range-state":i(m),"disabled-date":i(l),onChangerange:i(C),onPick:j,onSelect:i(_)},null,8,["date","min-date","max-date","range-state","disabled-date","onChangerange","onSelect"])],2),F("div",{class:N([[i(v).e("content"),i(h).e("content")],"is-right"])},[F("div",{class:N(i(h).e("header"))},[P.unlinkPanels?(T(),V("button",{key:0,type:"button",disabled:!i(U),class:N([[i(v).e("icon-btn"),{"is-disabled":!i(U)}],"d-arrow-left"]),onClick:x[2]||(x[2]=(...I)=>i($)&&i($)(...I))},[K(i(ze),null,{default:X(()=>[K(i(ks))]),_:1})],10,BW)):te("v-if",!0),F("button",{type:"button",class:N([i(v).e("icon-btn"),"d-arrow-right"]),onClick:x[3]||(x[3]=(...I)=>i(S)&&i(S)(...I))},[K(i(ze),null,{default:X(()=>[K(i(Es))]),_:1})],2),F("div",null,le(i(A)),1)],2),K(Yh,{"selection-mode":"range",date:f.value,"min-date":i(d),"max-date":i(p),"range-state":i(m),"disabled-date":i(l),onChangerange:i(C),onPick:j,onSelect:i(_)},null,8,["date","min-date","max-date","range-state","disabled-date","onChangerange","onSelect"])],2)],2)],2)],2))}});var zW=Ie(HW,[["__file","panel-month-range.vue"]]);const jW=function(e){switch(e){case"daterange":case"datetimerange":return PW;case"monthrange":return zW;default:return wW}};ct.extend(Ok);ct.extend($j);ct.extend(ig);ct.extend(Nj);ct.extend(Mj);ct.extend(Pj);ct.extend(Lj);ct.extend(Dj);var WW=Y({name:"ElDatePicker",install:null,props:Fj,emits:["update:modelValue"],setup(e,{expose:t,emit:n,slots:o}){const r=Se("picker-panel");yt("ElPopperOptions",Et(Lt(e,"popperOptions"))),yt(dg,{slots:o,pickerNs:r});const a=R();t({focus:(u=!0)=>{var c;(c=a.value)==null||c.focus(u)},handleOpen:()=>{var u;(u=a.value)==null||u.handleOpen()},handleClose:()=>{var u;(u=a.value)==null||u.handleClose()}});const s=u=>{n("update:modelValue",u)};return()=>{var u;const c=(u=e.format)!=null?u:bV[e.type]||Zl,f=jW(e.type);return K(mk,mt(e,{format:c,type:e.type,ref:a,"onUpdate:modelValue":s}),{default:d=>K(f,d,null),"range-separator":o["range-separator"]})}}});const zc=WW;zc.install=e=>{e.component(zc.name,zc)};const KW=zc,hg=Symbol("elDescriptions");var vi=Y({name:"ElDescriptionsCell",props:{cell:{type:Object},tag:{type:String,default:"td"},type:{type:String}},setup(){return{descriptions:De(hg,{})}},render(){var e,t,n,o,r,a,l;const s=f3(this.cell),u=(((e=this.cell)==null?void 0:e.dirs)||[]).map(w=>{const{dir:S,arg:E,modifiers:$,value:O}=w;return[S,O,E,$]}),{border:c,direction:f}=this.descriptions,d=f==="vertical",p=((o=(n=(t=this.cell)==null?void 0:t.children)==null?void 0:n.label)==null?void 0:o.call(n))||s.label,m=(l=(a=(r=this.cell)==null?void 0:r.children)==null?void 0:a.default)==null?void 0:l.call(a),v=s.span,h=s.align?`is-${s.align}`:"",C=s.labelAlign?`is-${s.labelAlign}`:h,g=s.className,y=s.labelClassName,_={width:rn(s.width),minWidth:rn(s.minWidth)},b=Se("descriptions");switch(this.type){case"label":return tt(Ke(this.tag,{style:_,class:[b.e("cell"),b.e("label"),b.is("bordered-label",c),b.is("vertical-label",d),C,y],colSpan:d?v:1},p),u);case"content":return tt(Ke(this.tag,{style:_,class:[b.e("cell"),b.e("content"),b.is("bordered-content",c),b.is("vertical-content",d),h,g],colSpan:d?v:v*2-1},m),u);default:return tt(Ke("td",{style:_,class:[b.e("cell"),h],colSpan:v},[Tn(p)?void 0:Ke("span",{class:[b.e("label"),y]},p),Ke("span",{class:[b.e("content"),g]},m)]),u)}}});const UW=Ne({row:{type:Q(Array),default:()=>[]}}),qW={key:1},YW=Y({name:"ElDescriptionsRow"}),GW=Y({...YW,props:UW,setup(e){const t=De(hg,{});return(n,o)=>i(t).direction==="vertical"?(T(),V(Ve,{key:0},[F("tr",null,[(T(!0),V(Ve,null,bt(n.row,(r,a)=>(T(),re(i(vi),{key:`tr1-${a}`,cell:r,tag:"th",type:"label"},null,8,["cell"]))),128))]),F("tr",null,[(T(!0),V(Ve,null,bt(n.row,(r,a)=>(T(),re(i(vi),{key:`tr2-${a}`,cell:r,tag:"td",type:"content"},null,8,["cell"]))),128))])],64)):(T(),V("tr",qW,[(T(!0),V(Ve,null,bt(n.row,(r,a)=>(T(),V(Ve,{key:`tr3-${a}`},[i(t).border?(T(),V(Ve,{key:0},[K(i(vi),{cell:r,tag:"td",type:"label"},null,8,["cell"]),K(i(vi),{cell:r,tag:"td",type:"content"},null,8,["cell"])],64)):(T(),re(i(vi),{key:1,cell:r,tag:"td",type:"both"},null,8,["cell"]))],64))),128))]))}});var XW=Ie(GW,[["__file","descriptions-row.vue"]]);const JW=Ne({border:Boolean,column:{type:Number,default:3},direction:{type:String,values:["horizontal","vertical"],default:"horizontal"},size:gn,title:{type:String,default:""},extra:{type:String,default:""}}),ZW=Y({name:"ElDescriptions"}),QW=Y({...ZW,props:JW,setup(e){const t=e,n=Se("descriptions"),o=hn(),r=Sn();yt(hg,t);const a=k(()=>[n.b(),n.m(o.value)]),l=(u,c,f,d=!1)=>(u.props||(u.props={}),c>f&&(u.props.span=f),d&&(u.props.span=c),u),s=()=>{if(!r.default)return[];const u=Ca(r.default()).filter(m=>{var v;return((v=m==null?void 0:m.type)==null?void 0:v.name)==="ElDescriptionsItem"}),c=[];let f=[],d=t.column,p=0;return u.forEach((m,v)=>{var h;const C=((h=m.props)==null?void 0:h.span)||1;if(vd?d:C),v===u.length-1){const g=t.column-p%t.column;f.push(l(m,g,d,!0)),c.push(f);return}C(T(),V("div",{class:N(i(a))},[u.title||u.extra||u.$slots.title||u.$slots.extra?(T(),V("div",{key:0,class:N(i(n).e("header"))},[F("div",{class:N(i(n).e("title"))},[ie(u.$slots,"title",{},()=>[Ge(le(u.title),1)])],2),F("div",{class:N(i(n).e("extra"))},[ie(u.$slots,"extra",{},()=>[Ge(le(u.extra),1)])],2)],2)):te("v-if",!0),F("div",{class:N(i(n).e("body"))},[F("table",{class:N([i(n).e("table"),i(n).is("bordered",u.border)])},[F("tbody",null,[(T(!0),V(Ve,null,bt(s(),(f,d)=>(T(),re(XW,{key:d,row:f},null,8,["row"]))),128))])],2)],2)],2))}});var eK=Ie(QW,[["__file","description.vue"]]);const tK=Ne({label:{type:String,default:""},span:{type:Number,default:1},width:{type:[String,Number],default:""},minWidth:{type:[String,Number],default:""},align:{type:String,default:"left"},labelAlign:{type:String,default:""},className:{type:String,default:""},labelClassName:{type:String,default:""}}),cE=Y({name:"ElDescriptionsItem",props:tK}),nK=ut(eK,{DescriptionsItem:cE}),oK=tn(cE),rK=Ne({mask:{type:Boolean,default:!0},customMaskEvent:Boolean,overlayClass:{type:Q([String,Array,Object])},zIndex:{type:Q([String,Number])}}),aK={click:e=>e instanceof MouseEvent},lK="overlay";var sK=Y({name:"ElOverlay",props:rK,emits:aK,setup(e,{slots:t,emit:n}){const o=Se(lK),r=u=>{n("click",u)},{onClick:a,onMousedown:l,onMouseup:s}=qv(e.customMaskEvent?void 0:r);return()=>e.mask?K("div",{class:[o.b(),e.overlayClass],style:{zIndex:e.zIndex},onClick:a,onMousedown:l,onMouseup:s},[ie(t,"default")],Oo.STYLE|Oo.CLASS|Oo.PROPS,["onClick","onMouseup","onMousedown"]):Ke("div",{class:e.overlayClass,style:{zIndex:e.zIndex,position:"fixed",top:"0px",right:"0px",bottom:"0px",left:"0px"}},[ie(t,"default")])}});const mg=sK,dE=Symbol("dialogInjectionKey"),fE=Ne({center:Boolean,alignCenter:Boolean,closeIcon:{type:Dt},draggable:Boolean,overflow:Boolean,fullscreen:Boolean,showClose:{type:Boolean,default:!0},title:{type:String,default:""},ariaLevel:{type:String,default:"2"}}),iK={close:()=>!0},uK=["aria-level"],cK=["aria-label"],dK=["id"],fK=Y({name:"ElDialogContent"}),pK=Y({...fK,props:fE,emits:iK,setup(e){const t=e,{t:n}=$t(),{Close:o}=Av,{dialogRef:r,headerRef:a,bodyId:l,ns:s,style:u}=De(dE),{focusTrapRef:c}=De(ag),f=k(()=>[s.b(),s.is("fullscreen",t.fullscreen),s.is("draggable",t.draggable),s.is("align-center",t.alignCenter),{[s.m("center")]:t.center}]),d=mf(c,r),p=k(()=>t.draggable),m=k(()=>t.overflow);return nS(r,a,p,m),(v,h)=>(T(),V("div",{ref:i(d),class:N(i(f)),style:je(i(u)),tabindex:"-1"},[F("header",{ref_key:"headerRef",ref:a,class:N([i(s).e("header"),{"show-close":v.showClose}])},[ie(v.$slots,"header",{},()=>[F("span",{role:"heading","aria-level":v.ariaLevel,class:N(i(s).e("title"))},le(v.title),11,uK)]),v.showClose?(T(),V("button",{key:0,"aria-label":i(n)("el.dialog.close"),class:N(i(s).e("headerbtn")),type:"button",onClick:h[0]||(h[0]=C=>v.$emit("close"))},[K(i(ze),{class:N(i(s).e("close"))},{default:X(()=>[(T(),re(pt(v.closeIcon||i(o))))]),_:1},8,["class"])],10,cK)):te("v-if",!0)],2),F("div",{id:i(l),class:N(i(s).e("body"))},[ie(v.$slots,"default")],10,dK),v.$slots.footer?(T(),V("footer",{key:0,class:N(i(s).e("footer"))},[ie(v.$slots,"footer")],2)):te("v-if",!0)],6))}});var hK=Ie(pK,[["__file","dialog-content.vue"]]);const pE=Ne({...fE,appendToBody:Boolean,appendTo:{type:Q(String),default:"body"},beforeClose:{type:Q(Function)},destroyOnClose:Boolean,closeOnClickModal:{type:Boolean,default:!0},closeOnPressEscape:{type:Boolean,default:!0},lockScroll:{type:Boolean,default:!0},modal:{type:Boolean,default:!0},openDelay:{type:Number,default:0},closeDelay:{type:Number,default:0},top:{type:String},modelValue:Boolean,modalClass:String,width:{type:[String,Number]},zIndex:{type:Number},trapFocus:Boolean,headerAriaLevel:{type:String,default:"2"}}),hE={open:()=>!0,opened:()=>!0,close:()=>!0,closed:()=>!0,[ft]:e=>dn(e),openAutoFocus:()=>!0,closeAutoFocus:()=>!0},mE=(e,t)=>{var n;const r=lt().emit,{nextZIndex:a}=Zs();let l="";const s=xn(),u=xn(),c=R(!1),f=R(!1),d=R(!1),p=R((n=e.zIndex)!=null?n:a());let m,v;const h=_f("namespace",Ri),C=k(()=>{const W={},L=`--${h.value}-dialog`;return e.fullscreen||(e.top&&(W[`${L}-margin-top`]=e.top),e.width&&(W[`${L}-width`]=rn(e.width))),W}),g=k(()=>e.alignCenter?{display:"flex"}:{});function y(){r("opened")}function _(){r("closed"),r(ft,!1),e.destroyOnClose&&(d.value=!1)}function b(){r("close")}function w(){v==null||v(),m==null||m(),e.openDelay&&e.openDelay>0?{stop:m}=_l(()=>O(),e.openDelay):O()}function S(){m==null||m(),v==null||v(),e.closeDelay&&e.closeDelay>0?{stop:v}=_l(()=>A(),e.closeDelay):A()}function E(){function W(L){L||(f.value=!0,c.value=!1)}e.beforeClose?e.beforeClose(W):S()}function $(){e.closeOnClickModal&&E()}function O(){Ct&&(c.value=!0)}function A(){c.value=!1}function M(){r("openAutoFocus")}function D(){r("closeAutoFocus")}function U(W){var L;((L=W.detail)==null?void 0:L.focusReason)==="pointer"&&W.preventDefault()}e.lockScroll&&Fv(c);function j(){e.closeOnPressEscape&&E()}return ve(()=>e.modelValue,W=>{W?(f.value=!1,w(),d.value=!0,p.value=HC(e.zIndex)?a():p.value++,We(()=>{r("open"),t.value&&(t.value.scrollTop=0)})):c.value&&S()}),ve(()=>e.fullscreen,W=>{t.value&&(W?(l=t.value.style.transform,t.value.style.transform=""):t.value.style.transform=l)}),at(()=>{e.modelValue&&(c.value=!0,d.value=!0,w())}),{afterEnter:y,afterLeave:_,beforeLeave:b,handleClose:E,onModalClick:$,close:S,doClose:A,onOpenAutoFocus:M,onCloseAutoFocus:D,onCloseRequested:j,onFocusoutPrevented:U,titleId:s,bodyId:u,closed:f,style:C,overlayDialogStyle:g,rendered:d,visible:c,zIndex:p}},mK=["aria-label","aria-labelledby","aria-describedby"],vK=Y({name:"ElDialog",inheritAttrs:!1}),gK=Y({...vK,props:pE,emits:hE,setup(e,{expose:t}){const n=e,o=Sn();wn({scope:"el-dialog",from:"the title slot",replacement:"the header slot",version:"3.0.0",ref:"https://element-plus.org/en-US/component/dialog.html#slots"},k(()=>!!o.title));const r=Se("dialog"),a=R(),l=R(),s=R(),{visible:u,titleId:c,bodyId:f,style:d,overlayDialogStyle:p,rendered:m,zIndex:v,afterEnter:h,afterLeave:C,beforeLeave:g,handleClose:y,onModalClick:_,onOpenAutoFocus:b,onCloseAutoFocus:w,onCloseRequested:S,onFocusoutPrevented:E}=mE(n,a);yt(dE,{dialogRef:a,headerRef:l,bodyId:f,ns:r,rendered:m,style:d});const $=qv(_),O=k(()=>n.draggable&&!n.fullscreen);return t({visible:u,dialogContentRef:s}),(A,M)=>(T(),re(Pl,{to:A.appendTo,disabled:A.appendTo!=="body"?!1:!A.appendToBody},[K(fn,{name:"dialog-fade",onAfterEnter:i(h),onAfterLeave:i(C),onBeforeLeave:i(g),persisted:""},{default:X(()=>[tt(K(i(mg),{"custom-mask-event":"",mask:A.modal,"overlay-class":A.modalClass,"z-index":i(v)},{default:X(()=>[F("div",{role:"dialog","aria-modal":"true","aria-label":A.title||void 0,"aria-labelledby":A.title?void 0:i(c),"aria-describedby":i(f),class:N(`${i(r).namespace.value}-overlay-dialog`),style:je(i(p)),onClick:M[0]||(M[0]=(...D)=>i($).onClick&&i($).onClick(...D)),onMousedown:M[1]||(M[1]=(...D)=>i($).onMousedown&&i($).onMousedown(...D)),onMouseup:M[2]||(M[2]=(...D)=>i($).onMouseup&&i($).onMouseup(...D))},[K(i(Fu),{loop:"",trapped:i(u),"focus-start-el":"container",onFocusAfterTrapped:i(b),onFocusAfterReleased:i(w),onFocusoutPrevented:i(E),onReleaseRequested:i(S)},{default:X(()=>[i(m)?(T(),re(hK,mt({key:0,ref_key:"dialogContentRef",ref:s},A.$attrs,{center:A.center,"align-center":A.alignCenter,"close-icon":A.closeIcon,draggable:i(O),overflow:A.overflow,fullscreen:A.fullscreen,"show-close":A.showClose,title:A.title,"aria-level":A.headerAriaLevel,onClose:i(y)}),Sr({header:X(()=>[A.$slots.title?ie(A.$slots,"title",{key:1}):ie(A.$slots,"header",{key:0,close:i(y),titleId:i(c),titleClass:i(r).e("title")})]),default:X(()=>[ie(A.$slots,"default")]),_:2},[A.$slots.footer?{name:"footer",fn:X(()=>[ie(A.$slots,"footer")])}:void 0]),1040,["center","align-center","close-icon","draggable","overflow","fullscreen","show-close","title","aria-level","onClose"])):te("v-if",!0)]),_:3},8,["trapped","onFocusAfterTrapped","onFocusAfterReleased","onFocusoutPrevented","onReleaseRequested"])],46,mK)]),_:3},8,["mask","overlay-class","z-index"]),[[kt,i(u)]])]),_:3},8,["onAfterEnter","onAfterLeave","onBeforeLeave"])],8,["to","disabled"]))}});var bK=Ie(gK,[["__file","dialog.vue"]]);const yK=ut(bK),wK=Ne({direction:{type:String,values:["horizontal","vertical"],default:"horizontal"},contentPosition:{type:String,values:["left","center","right"],default:"center"},borderStyle:{type:Q(String),default:"solid"}}),_K=Y({name:"ElDivider"}),CK=Y({..._K,props:wK,setup(e){const t=e,n=Se("divider"),o=k(()=>n.cssVar({"border-style":t.borderStyle}));return(r,a)=>(T(),V("div",{class:N([i(n).b(),i(n).m(r.direction)]),style:je(i(o)),role:"separator"},[r.$slots.default&&r.direction!=="vertical"?(T(),V("div",{key:0,class:N([i(n).e("text"),i(n).is(r.contentPosition)])},[ie(r.$slots,"default")],2)):te("v-if",!0)],6))}});var SK=Ie(CK,[["__file","divider.vue"]]);const vE=ut(SK),kK=Ne({...pE,direction:{type:String,default:"rtl",values:["ltr","rtl","ttb","btt"]},size:{type:[String,Number],default:"30%"},withHeader:{type:Boolean,default:!0},modalFade:{type:Boolean,default:!0},headerAriaLevel:{type:String,default:"2"}}),EK=hE,TK=["aria-label","aria-labelledby","aria-describedby"],$K=["id","aria-level"],OK=["aria-label"],NK=["id"],IK=Y({name:"ElDrawer",inheritAttrs:!1}),MK=Y({...IK,props:kK,emits:EK,setup(e,{expose:t}){const n=e,o=Sn();wn({scope:"el-drawer",from:"the title slot",replacement:"the header slot",version:"3.0.0",ref:"https://element-plus.org/en-US/component/drawer.html#slots"},k(()=>!!o.title));const r=R(),a=R(),l=Se("drawer"),{t:s}=$t(),{afterEnter:u,afterLeave:c,beforeLeave:f,visible:d,rendered:p,titleId:m,bodyId:v,zIndex:h,onModalClick:C,onOpenAutoFocus:g,onCloseAutoFocus:y,onFocusoutPrevented:_,onCloseRequested:b,handleClose:w}=mE(n,r),S=k(()=>n.direction==="rtl"||n.direction==="ltr"),E=k(()=>rn(n.size));return t({handleClose:w,afterEnter:u,afterLeave:c}),($,O)=>(T(),re(Pl,{to:"body",disabled:!$.appendToBody},[K(fn,{name:i(l).b("fade"),onAfterEnter:i(u),onAfterLeave:i(c),onBeforeLeave:i(f),persisted:""},{default:X(()=>[tt(K(i(mg),{mask:$.modal,"overlay-class":$.modalClass,"z-index":i(h),onClick:i(C)},{default:X(()=>[K(i(Fu),{loop:"",trapped:i(d),"focus-trap-el":r.value,"focus-start-el":a.value,onFocusAfterTrapped:i(g),onFocusAfterReleased:i(y),onFocusoutPrevented:i(_),onReleaseRequested:i(b)},{default:X(()=>[F("div",mt({ref_key:"drawerRef",ref:r,"aria-modal":"true","aria-label":$.title||void 0,"aria-labelledby":$.title?void 0:i(m),"aria-describedby":i(v)},$.$attrs,{class:[i(l).b(),$.direction,i(d)&&"open"],style:i(S)?"width: "+i(E):"height: "+i(E),role:"dialog",onClick:O[1]||(O[1]=Qe(()=>{},["stop"]))}),[F("span",{ref_key:"focusStartRef",ref:a,class:N(i(l).e("sr-focus")),tabindex:"-1"},null,2),$.withHeader?(T(),V("header",{key:0,class:N(i(l).e("header"))},[$.$slots.title?ie($.$slots,"title",{key:1},()=>[te(" DEPRECATED SLOT ")]):ie($.$slots,"header",{key:0,close:i(w),titleId:i(m),titleClass:i(l).e("title")},()=>[$.$slots.title?te("v-if",!0):(T(),V("span",{key:0,id:i(m),role:"heading","aria-level":$.headerAriaLevel,class:N(i(l).e("title"))},le($.title),11,$K))]),$.showClose?(T(),V("button",{key:2,"aria-label":i(s)("el.drawer.close"),class:N(i(l).e("close-btn")),type:"button",onClick:O[0]||(O[0]=(...A)=>i(w)&&i(w)(...A))},[K(i(ze),{class:N(i(l).e("close"))},{default:X(()=>[K(i(tr))]),_:1},8,["class"])],10,OK)):te("v-if",!0)],2)):te("v-if",!0),i(p)?(T(),V("div",{key:1,id:i(v),class:N(i(l).e("body"))},[ie($.$slots,"default")],10,NK)):te("v-if",!0),$.$slots.footer?(T(),V("div",{key:2,class:N(i(l).e("footer"))},[ie($.$slots,"footer")],2)):te("v-if",!0)],16,TK)]),_:3},8,["trapped","focus-trap-el","focus-start-el","onFocusAfterTrapped","onFocusAfterReleased","onFocusoutPrevented","onReleaseRequested"])]),_:3},8,["mask","overlay-class","z-index","onClick"]),[[kt,i(d)]])]),_:3},8,["name","onAfterEnter","onAfterLeave","onBeforeLeave"])],8,["disabled"]))}});var AK=Ie(MK,[["__file","drawer.vue"]]);const PK=ut(AK),RK=Y({inheritAttrs:!1});function LK(e,t,n,o,r,a){return ie(e.$slots,"default")}var xK=Ie(RK,[["render",LK],["__file","collection.vue"]]);const DK=Y({name:"ElCollectionItem",inheritAttrs:!1});function FK(e,t,n,o,r,a){return ie(e.$slots,"default")}var BK=Ie(DK,[["render",FK],["__file","collection-item.vue"]]);const gE="data-el-collection-item",bE=e=>{const t=`El${e}Collection`,n=`${t}Item`,o=Symbol(t),r=Symbol(n),a={...xK,name:t,setup(){const s=R(null),u=new Map;yt(o,{itemMap:u,getItems:()=>{const f=i(s);if(!f)return[];const d=Array.from(f.querySelectorAll(`[${gE}]`));return[...u.values()].sort((m,v)=>d.indexOf(m.ref)-d.indexOf(v.ref))},collectionRef:s})}},l={...BK,name:n,setup(s,{attrs:u}){const c=R(null),f=De(o,void 0);yt(r,{collectionItemRef:c}),at(()=>{const d=i(c);d&&f.itemMap.set(d,{ref:d,...u})}),zt(()=>{const d=i(c);f.itemMap.delete(d)})}};return{COLLECTION_INJECTION_KEY:o,COLLECTION_ITEM_INJECTION_KEY:r,ElCollection:a,ElCollectionItem:l}},VK=Ne({style:{type:Q([String,Array,Object])},currentTabId:{type:Q(String)},defaultCurrentTabId:String,loop:Boolean,dir:{type:String,values:["ltr","rtl"],default:"ltr"},orientation:{type:Q(String)},onBlur:Function,onFocus:Function,onMousedown:Function}),{ElCollection:HK,ElCollectionItem:zK,COLLECTION_INJECTION_KEY:vg,COLLECTION_ITEM_INJECTION_KEY:jK}=bE("RovingFocusGroup"),gg=Symbol("elRovingFocusGroup"),yE=Symbol("elRovingFocusGroupItem"),WK={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"},KK=(e,t)=>e,UK=(e,t,n)=>{const o=KK(e.key);return WK[o]},qK=(e,t)=>e.map((n,o)=>e[(o+t)%e.length]),bg=e=>{const{activeElement:t}=document;for(const n of e)if(n===t||(n.focus(),t!==document.activeElement))return},t1="currentTabIdChange",n1="rovingFocusGroup.entryFocus",YK={bubbles:!1,cancelable:!0},GK=Y({name:"ElRovingFocusGroupImpl",inheritAttrs:!1,props:VK,emits:[t1,"entryFocus"],setup(e,{emit:t}){var n;const o=R((n=e.currentTabId||e.defaultCurrentTabId)!=null?n:null),r=R(!1),a=R(!1),l=R(null),{getItems:s}=De(vg,void 0),u=k(()=>[{outline:"none"},e.style]),c=h=>{t(t1,h)},f=()=>{r.value=!0},d=on(h=>{var C;(C=e.onMousedown)==null||C.call(e,h)},()=>{a.value=!0}),p=on(h=>{var C;(C=e.onFocus)==null||C.call(e,h)},h=>{const C=!i(a),{target:g,currentTarget:y}=h;if(g===y&&C&&!i(r)){const _=new Event(n1,YK);if(y==null||y.dispatchEvent(_),!_.defaultPrevented){const b=s().filter(O=>O.focusable),w=b.find(O=>O.active),S=b.find(O=>O.id===i(o)),$=[w,S,...b].filter(Boolean).map(O=>O.ref);bg($)}}a.value=!1}),m=on(h=>{var C;(C=e.onBlur)==null||C.call(e,h)},()=>{r.value=!1}),v=(...h)=>{t("entryFocus",...h)};yt(gg,{currentTabbedId:Ml(o),loop:Lt(e,"loop"),tabIndex:k(()=>i(r)?-1:0),rovingFocusGroupRef:l,rovingFocusGroupRootStyle:u,orientation:Lt(e,"orientation"),dir:Lt(e,"dir"),onItemFocus:c,onItemShiftTab:f,onBlur:m,onFocus:p,onMousedown:d}),ve(()=>e.currentTabId,h=>{o.value=h??null}),qt(l,n1,v)}});function XK(e,t,n,o,r,a){return ie(e.$slots,"default")}var JK=Ie(GK,[["render",XK],["__file","roving-focus-group-impl.vue"]]);const ZK=Y({name:"ElRovingFocusGroup",components:{ElFocusGroupCollection:HK,ElRovingFocusGroupImpl:JK}});function QK(e,t,n,o,r,a){const l=qe("el-roving-focus-group-impl"),s=qe("el-focus-group-collection");return T(),re(s,null,{default:X(()=>[K(l,vr(bl(e.$attrs)),{default:X(()=>[ie(e.$slots,"default")]),_:3},16)]),_:3})}var e9=Ie(ZK,[["render",QK],["__file","roving-focus-group.vue"]]);const t9=Y({components:{ElRovingFocusCollectionItem:zK},props:{focusable:{type:Boolean,default:!0},active:{type:Boolean,default:!1}},emits:["mousedown","focus","keydown"],setup(e,{emit:t}){const{currentTabbedId:n,loop:o,onItemFocus:r,onItemShiftTab:a}=De(gg,void 0),{getItems:l}=De(vg,void 0),s=xn(),u=R(null),c=on(m=>{t("mousedown",m)},m=>{e.focusable?r(i(s)):m.preventDefault()}),f=on(m=>{t("focus",m)},()=>{r(i(s))}),d=on(m=>{t("keydown",m)},m=>{const{key:v,shiftKey:h,target:C,currentTarget:g}=m;if(v===Ue.tab&&h){a();return}if(C!==g)return;const y=UK(m);if(y){m.preventDefault();let b=l().filter(w=>w.focusable).map(w=>w.ref);switch(y){case"last":{b.reverse();break}case"prev":case"next":{y==="prev"&&b.reverse();const w=b.indexOf(g);b=o.value?qK(b,w+1):b.slice(w+1);break}}We(()=>{bg(b)})}}),p=k(()=>n.value===i(s));return yt(yE,{rovingFocusGroupItemRef:u,tabIndex:k(()=>i(p)?0:-1),handleMousedown:c,handleFocus:f,handleKeydown:d}),{id:s,handleKeydown:d,handleFocus:f,handleMousedown:c}}});function n9(e,t,n,o,r,a){const l=qe("el-roving-focus-collection-item");return T(),re(l,{id:e.id,focusable:e.focusable,active:e.active},{default:X(()=>[ie(e.$slots,"default")]),_:3},8,["id","focusable","active"])}var o9=Ie(t9,[["render",n9],["__file","roving-focus-item.vue"]]);const jc=Ne({trigger:lu.trigger,effect:{...kn.effect,default:"light"},type:{type:Q(String)},placement:{type:Q(String),default:"bottom"},popperOptions:{type:Q(Object),default:()=>({})},id:String,size:{type:String,default:""},splitButton:Boolean,hideOnClick:{type:Boolean,default:!0},loop:{type:Boolean,default:!0},showTimeout:{type:Number,default:150},hideTimeout:{type:Number,default:150},tabindex:{type:Q([Number,String]),default:0},maxHeight:{type:Q([Number,String]),default:""},popperClass:{type:String,default:""},disabled:Boolean,role:{type:String,default:"menu"},buttonProps:{type:Q(Object)},teleported:kn.teleported}),wE=Ne({command:{type:[Object,String,Number],default:()=>({})},disabled:Boolean,divided:Boolean,textValue:String,icon:{type:Dt}}),r9=Ne({onKeydown:{type:Q(Function)}}),a9=[Ue.down,Ue.pageDown,Ue.home],_E=[Ue.up,Ue.pageUp,Ue.end],l9=[...a9,..._E],{ElCollection:s9,ElCollectionItem:i9,COLLECTION_INJECTION_KEY:u9,COLLECTION_ITEM_INJECTION_KEY:c9}=bE("Dropdown"),Tf=Symbol("elDropdown"),{ButtonGroup:d9}=$n,f9=Y({name:"ElDropdown",components:{ElButton:$n,ElButtonGroup:d9,ElScrollbar:ea,ElDropdownCollection:s9,ElTooltip:Un,ElRovingFocusGroup:e9,ElOnlyChild:qS,ElIcon:ze,ArrowDown:Nr},props:jc,emits:["visible-change","click","command"],setup(e,{emit:t}){const n=lt(),o=Se("dropdown"),{t:r}=$t(),a=R(),l=R(),s=R(null),u=R(null),c=R(null),f=R(null),d=R(!1),p=[Ue.enter,Ue.space,Ue.down],m=k(()=>({maxHeight:rn(e.maxHeight)})),v=k(()=>[o.m(w.value)]),h=k(()=>Ia(e.trigger)),C=xn().value,g=k(()=>e.id||C);ve([a,h],([P,x],[I])=>{var H,G,J;(H=I==null?void 0:I.$el)!=null&&H.removeEventListener&&I.$el.removeEventListener("pointerenter",E),(G=P==null?void 0:P.$el)!=null&&G.removeEventListener&&P.$el.removeEventListener("pointerenter",E),(J=P==null?void 0:P.$el)!=null&&J.addEventListener&&x.includes("hover")&&P.$el.addEventListener("pointerenter",E)},{immediate:!0}),zt(()=>{var P,x;(x=(P=a.value)==null?void 0:P.$el)!=null&&x.removeEventListener&&a.value.$el.removeEventListener("pointerenter",E)});function y(){_()}function _(){var P;(P=s.value)==null||P.onClose()}function b(){var P;(P=s.value)==null||P.onOpen()}const w=hn();function S(...P){t("command",...P)}function E(){var P,x;(x=(P=a.value)==null?void 0:P.$el)==null||x.focus()}function $(){}function O(){const P=i(u);h.value.includes("hover")&&(P==null||P.focus()),f.value=null}function A(P){f.value=P}function M(P){d.value||(P.preventDefault(),P.stopImmediatePropagation())}function D(){t("visible-change",!0)}function U(P){(P==null?void 0:P.type)==="keydown"&&u.value.focus()}function j(){t("visible-change",!1)}return yt(Tf,{contentRef:u,role:k(()=>e.role),triggerId:g,isUsingKeyboard:d,onItemEnter:$,onItemLeave:O}),yt("elDropdown",{instance:n,dropdownSize:w,handleClick:y,commandHandler:S,trigger:Lt(e,"trigger"),hideOnClick:Lt(e,"hideOnClick")}),{t:r,ns:o,scrollbar:c,wrapStyle:m,dropdownTriggerKls:v,dropdownSize:w,triggerId:g,triggerKeys:p,currentTabId:f,handleCurrentTabIdChange:A,handlerMainButtonClick:P=>{t("click",P)},handleEntryFocus:M,handleClose:_,handleOpen:b,handleBeforeShowTooltip:D,handleShowTooltip:U,handleBeforeHideTooltip:j,onFocusAfterTrapped:P=>{var x,I;P.preventDefault(),(I=(x=u.value)==null?void 0:x.focus)==null||I.call(x,{preventScroll:!0})},popperRef:s,contentRef:u,triggeringElementRef:a,referenceElementRef:l}}});function p9(e,t,n,o,r,a){var l;const s=qe("el-dropdown-collection"),u=qe("el-roving-focus-group"),c=qe("el-scrollbar"),f=qe("el-only-child"),d=qe("el-tooltip"),p=qe("el-button"),m=qe("arrow-down"),v=qe("el-icon"),h=qe("el-button-group");return T(),V("div",{class:N([e.ns.b(),e.ns.is("disabled",e.disabled)])},[K(d,{ref:"popperRef",role:e.role,effect:e.effect,"fallback-placements":["bottom","top"],"popper-options":e.popperOptions,"gpu-acceleration":!1,"hide-after":e.trigger==="hover"?e.hideTimeout:0,"manual-mode":!0,placement:e.placement,"popper-class":[e.ns.e("popper"),e.popperClass],"reference-element":(l=e.referenceElementRef)==null?void 0:l.$el,trigger:e.trigger,"trigger-keys":e.triggerKeys,"trigger-target-el":e.contentRef,"show-after":e.trigger==="hover"?e.showTimeout:0,"stop-popper-mouse-event":!1,"virtual-ref":e.triggeringElementRef,"virtual-triggering":e.splitButton,disabled:e.disabled,transition:`${e.ns.namespace.value}-zoom-in-top`,teleported:e.teleported,pure:"",persistent:"",onBeforeShow:e.handleBeforeShowTooltip,onShow:e.handleShowTooltip,onBeforeHide:e.handleBeforeHideTooltip},Sr({content:X(()=>[K(c,{ref:"scrollbar","wrap-style":e.wrapStyle,tag:"div","view-class":e.ns.e("list")},{default:X(()=>[K(u,{loop:e.loop,"current-tab-id":e.currentTabId,orientation:"horizontal",onCurrentTabIdChange:e.handleCurrentTabIdChange,onEntryFocus:e.handleEntryFocus},{default:X(()=>[K(s,null,{default:X(()=>[ie(e.$slots,"dropdown")]),_:3})]),_:3},8,["loop","current-tab-id","onCurrentTabIdChange","onEntryFocus"])]),_:3},8,["wrap-style","view-class"])]),_:2},[e.splitButton?void 0:{name:"default",fn:X(()=>[K(f,{id:e.triggerId,ref:"triggeringElementRef",role:"button",tabindex:e.tabindex},{default:X(()=>[ie(e.$slots,"default")]),_:3},8,["id","tabindex"])])}]),1032,["role","effect","popper-options","hide-after","placement","popper-class","reference-element","trigger","trigger-keys","trigger-target-el","show-after","virtual-ref","virtual-triggering","disabled","transition","teleported","onBeforeShow","onShow","onBeforeHide"]),e.splitButton?(T(),re(h,{key:0},{default:X(()=>[K(p,mt({ref:"referenceElementRef"},e.buttonProps,{size:e.dropdownSize,type:e.type,disabled:e.disabled,tabindex:e.tabindex,onClick:e.handlerMainButtonClick}),{default:X(()=>[ie(e.$slots,"default")]),_:3},16,["size","type","disabled","tabindex","onClick"]),K(p,mt({id:e.triggerId,ref:"triggeringElementRef"},e.buttonProps,{role:"button",size:e.dropdownSize,type:e.type,class:e.ns.e("caret-button"),disabled:e.disabled,tabindex:e.tabindex,"aria-label":e.t("el.dropdown.toggleDropdown")}),{default:X(()=>[K(v,{class:N(e.ns.e("icon"))},{default:X(()=>[K(m)]),_:1},8,["class"])]),_:1},16,["id","size","type","class","disabled","tabindex","aria-label"])]),_:3})):te("v-if",!0)],2)}var h9=Ie(f9,[["render",p9],["__file","dropdown.vue"]]);const m9=Y({name:"DropdownItemImpl",components:{ElIcon:ze},props:wE,emits:["pointermove","pointerleave","click","clickimpl"],setup(e,{emit:t}){const n=Se("dropdown"),{role:o}=De(Tf,void 0),{collectionItemRef:r}=De(c9,void 0),{collectionItemRef:a}=De(jK,void 0),{rovingFocusGroupItemRef:l,tabIndex:s,handleFocus:u,handleKeydown:c,handleMousedown:f}=De(yE,void 0),d=mf(r,a,l),p=k(()=>o.value==="menu"?"menuitem":o.value==="navigation"?"link":"button"),m=on(v=>{const{code:h}=v;if(h===Ue.enter||h===Ue.space)return v.preventDefault(),v.stopImmediatePropagation(),t("clickimpl",v),!0},c);return{ns:n,itemRef:d,dataset:{[gE]:""},role:p,tabIndex:s,handleFocus:u,handleKeydown:m,handleMousedown:f}}}),v9=["aria-disabled","tabindex","role"];function g9(e,t,n,o,r,a){const l=qe("el-icon");return T(),V(Ve,null,[e.divided?(T(),V("li",mt({key:0,role:"separator",class:e.ns.bem("menu","item","divided")},e.$attrs),null,16)):te("v-if",!0),F("li",mt({ref:e.itemRef},{...e.dataset,...e.$attrs},{"aria-disabled":e.disabled,class:[e.ns.be("menu","item"),e.ns.is("disabled",e.disabled)],tabindex:e.tabIndex,role:e.role,onClick:t[0]||(t[0]=s=>e.$emit("clickimpl",s)),onFocus:t[1]||(t[1]=(...s)=>e.handleFocus&&e.handleFocus(...s)),onKeydown:t[2]||(t[2]=Qe((...s)=>e.handleKeydown&&e.handleKeydown(...s),["self"])),onMousedown:t[3]||(t[3]=(...s)=>e.handleMousedown&&e.handleMousedown(...s)),onPointermove:t[4]||(t[4]=s=>e.$emit("pointermove",s)),onPointerleave:t[5]||(t[5]=s=>e.$emit("pointerleave",s))}),[e.icon?(T(),re(l,{key:0},{default:X(()=>[(T(),re(pt(e.icon)))]),_:1})):te("v-if",!0),ie(e.$slots,"default")],16,v9)],64)}var b9=Ie(m9,[["render",g9],["__file","dropdown-item-impl.vue"]]);const CE=()=>{const e=De("elDropdown",{}),t=k(()=>e==null?void 0:e.dropdownSize);return{elDropdown:e,_elDropdownSize:t}},y9=Y({name:"ElDropdownItem",components:{ElDropdownCollectionItem:i9,ElRovingFocusItem:o9,ElDropdownItemImpl:b9},inheritAttrs:!1,props:wE,emits:["pointermove","pointerleave","click"],setup(e,{emit:t,attrs:n}){const{elDropdown:o}=CE(),r=lt(),a=R(null),l=k(()=>{var m,v;return(v=(m=i(a))==null?void 0:m.textContent)!=null?v:""}),{onItemEnter:s,onItemLeave:u}=De(Tf,void 0),c=on(m=>(t("pointermove",m),m.defaultPrevented),Jb(m=>{if(e.disabled){u(m);return}const v=m.currentTarget;v===document.activeElement||v.contains(document.activeElement)||(s(m),m.defaultPrevented||v==null||v.focus())})),f=on(m=>(t("pointerleave",m),m.defaultPrevented),Jb(m=>{u(m)})),d=on(m=>{if(!e.disabled)return t("click",m),m.type!=="keydown"&&m.defaultPrevented},m=>{var v,h,C;if(e.disabled){m.stopImmediatePropagation();return}(v=o==null?void 0:o.hideOnClick)!=null&&v.value&&((h=o.handleClick)==null||h.call(o)),(C=o.commandHandler)==null||C.call(o,e.command,r,m)}),p=k(()=>({...e,...n}));return{handleClick:d,handlePointerMove:c,handlePointerLeave:f,textContent:l,propsAndAttrs:p}}});function w9(e,t,n,o,r,a){var l;const s=qe("el-dropdown-item-impl"),u=qe("el-roving-focus-item"),c=qe("el-dropdown-collection-item");return T(),re(c,{disabled:e.disabled,"text-value":(l=e.textValue)!=null?l:e.textContent},{default:X(()=>[K(u,{focusable:!e.disabled},{default:X(()=>[K(s,mt(e.propsAndAttrs,{onPointerleave:e.handlePointerLeave,onPointermove:e.handlePointerMove,onClickimpl:e.handleClick}),{default:X(()=>[ie(e.$slots,"default")]),_:3},16,["onPointerleave","onPointermove","onClickimpl"])]),_:3},8,["focusable"])]),_:3},8,["disabled","text-value"])}var SE=Ie(y9,[["render",w9],["__file","dropdown-item.vue"]]);const _9=Y({name:"ElDropdownMenu",props:r9,setup(e){const t=Se("dropdown"),{_elDropdownSize:n}=CE(),o=n.value,{focusTrapRef:r,onKeydown:a}=De(ag,void 0),{contentRef:l,role:s,triggerId:u}=De(Tf,void 0),{collectionRef:c,getItems:f}=De(u9,void 0),{rovingFocusGroupRef:d,rovingFocusGroupRootStyle:p,tabIndex:m,onBlur:v,onFocus:h,onMousedown:C}=De(gg,void 0),{collectionRef:g}=De(vg,void 0),y=k(()=>[t.b("menu"),t.bm("menu",o==null?void 0:o.value)]),_=mf(l,c,r,d,g),b=on(S=>{var E;(E=e.onKeydown)==null||E.call(e,S)},S=>{const{currentTarget:E,code:$,target:O}=S;if(E.contains(O),Ue.tab===$&&S.stopImmediatePropagation(),S.preventDefault(),O!==i(l)||!l9.includes($))return;const M=f().filter(D=>!D.disabled).map(D=>D.ref);_E.includes($)&&M.reverse(),bg(M)});return{size:o,rovingFocusGroupRootStyle:p,tabIndex:m,dropdownKls:y,role:s,triggerId:u,dropdownListWrapperRef:_,handleKeydown:S=>{b(S),a(S)},onBlur:v,onFocus:h,onMousedown:C}}}),C9=["role","aria-labelledby"];function S9(e,t,n,o,r,a){return T(),V("ul",{ref:e.dropdownListWrapperRef,class:N(e.dropdownKls),style:je(e.rovingFocusGroupRootStyle),tabindex:-1,role:e.role,"aria-labelledby":e.triggerId,onBlur:t[0]||(t[0]=(...l)=>e.onBlur&&e.onBlur(...l)),onFocus:t[1]||(t[1]=(...l)=>e.onFocus&&e.onFocus(...l)),onKeydown:t[2]||(t[2]=Qe((...l)=>e.handleKeydown&&e.handleKeydown(...l),["self"])),onMousedown:t[3]||(t[3]=Qe((...l)=>e.onMousedown&&e.onMousedown(...l),["self"]))},[ie(e.$slots,"default")],46,C9)}var kE=Ie(_9,[["render",S9],["__file","dropdown-menu.vue"]]);const k9=ut(h9,{DropdownItem:SE,DropdownMenu:kE}),E9=tn(SE),T9=tn(kE),$9={viewBox:"0 0 79 86",version:"1.1",xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"},O9=["id"],N9=["stop-color"],I9=["stop-color"],M9=["id"],A9=["stop-color"],P9=["stop-color"],R9=["id"],L9={id:"Illustrations",stroke:"none","stroke-width":"1",fill:"none","fill-rule":"evenodd"},x9={id:"B-type",transform:"translate(-1268.000000, -535.000000)"},D9={id:"Group-2",transform:"translate(1268.000000, 535.000000)"},F9=["fill"],B9=["fill"],V9={id:"Group-Copy",transform:"translate(34.500000, 31.500000) scale(-1, 1) rotate(-25.000000) translate(-34.500000, -31.500000) translate(7.000000, 10.000000)"},H9=["fill"],z9=["fill"],j9=["fill"],W9=["fill"],K9=["fill"],U9={id:"Rectangle-Copy-17",transform:"translate(53.000000, 45.000000)"},q9=["fill","xlink:href"],Y9=["fill","mask"],G9=["fill"],X9=Y({name:"ImgEmpty"}),J9=Y({...X9,setup(e){const t=Se("empty"),n=xn();return(o,r)=>(T(),V("svg",$9,[F("defs",null,[F("linearGradient",{id:`linearGradient-1-${i(n)}`,x1:"38.8503086%",y1:"0%",x2:"61.1496914%",y2:"100%"},[F("stop",{"stop-color":`var(${i(t).cssVarBlockName("fill-color-1")})`,offset:"0%"},null,8,N9),F("stop",{"stop-color":`var(${i(t).cssVarBlockName("fill-color-4")})`,offset:"100%"},null,8,I9)],8,O9),F("linearGradient",{id:`linearGradient-2-${i(n)}`,x1:"0%",y1:"9.5%",x2:"100%",y2:"90.5%"},[F("stop",{"stop-color":`var(${i(t).cssVarBlockName("fill-color-1")})`,offset:"0%"},null,8,A9),F("stop",{"stop-color":`var(${i(t).cssVarBlockName("fill-color-6")})`,offset:"100%"},null,8,P9)],8,M9),F("rect",{id:`path-3-${i(n)}`,x:"0",y:"0",width:"17",height:"36"},null,8,R9)]),F("g",L9,[F("g",x9,[F("g",D9,[F("path",{id:"Oval-Copy-2",d:"M39.5,86 C61.3152476,86 79,83.9106622 79,81.3333333 C79,78.7560045 57.3152476,78 35.5,78 C13.6847524,78 0,78.7560045 0,81.3333333 C0,83.9106622 17.6847524,86 39.5,86 Z",fill:`var(${i(t).cssVarBlockName("fill-color-3")})`},null,8,F9),F("polygon",{id:"Rectangle-Copy-14",fill:`var(${i(t).cssVarBlockName("fill-color-7")})`,transform:"translate(27.500000, 51.500000) scale(1, -1) translate(-27.500000, -51.500000) ",points:"13 58 53 58 42 45 2 45"},null,8,B9),F("g",V9,[F("polygon",{id:"Rectangle-Copy-10",fill:`var(${i(t).cssVarBlockName("fill-color-7")})`,transform:"translate(11.500000, 5.000000) scale(1, -1) translate(-11.500000, -5.000000) ",points:"2.84078316e-14 3 18 3 23 7 5 7"},null,8,H9),F("polygon",{id:"Rectangle-Copy-11",fill:`var(${i(t).cssVarBlockName("fill-color-5")})`,points:"-3.69149156e-15 7 38 7 38 43 -3.69149156e-15 43"},null,8,z9),F("rect",{id:"Rectangle-Copy-12",fill:`url(#linearGradient-1-${i(n)})`,transform:"translate(46.500000, 25.000000) scale(-1, 1) translate(-46.500000, -25.000000) ",x:"38",y:"7",width:"17",height:"36"},null,8,j9),F("polygon",{id:"Rectangle-Copy-13",fill:`var(${i(t).cssVarBlockName("fill-color-2")})`,transform:"translate(39.500000, 3.500000) scale(-1, 1) translate(-39.500000, -3.500000) ",points:"24 7 41 7 55 -3.63806207e-12 38 -3.63806207e-12"},null,8,W9)]),F("rect",{id:"Rectangle-Copy-15",fill:`url(#linearGradient-2-${i(n)})`,x:"13",y:"45",width:"40",height:"36"},null,8,K9),F("g",U9,[F("use",{id:"Mask",fill:`var(${i(t).cssVarBlockName("fill-color-8")})`,transform:"translate(8.500000, 18.000000) scale(-1, 1) translate(-8.500000, -18.000000) ","xlink:href":`#path-3-${i(n)}`},null,8,q9),F("polygon",{id:"Rectangle-Copy",fill:`var(${i(t).cssVarBlockName("fill-color-9")})`,mask:`url(#mask-4-${i(n)})`,transform:"translate(12.000000, 9.000000) scale(-1, 1) translate(-12.000000, -9.000000) ",points:"7 0 24 0 20 18 7 16.5"},null,8,Y9)]),F("polygon",{id:"Rectangle-Copy-18",fill:`var(${i(t).cssVarBlockName("fill-color-2")})`,transform:"translate(66.000000, 51.500000) scale(-1, 1) translate(-66.000000, -51.500000) ",points:"62 45 79 45 70 58 53 58"},null,8,G9)])])])]))}});var Z9=Ie(J9,[["__file","img-empty.vue"]]);const Q9=Ne({image:{type:String,default:""},imageSize:Number,description:{type:String,default:""}}),eU=["src"],tU={key:1},nU=Y({name:"ElEmpty"}),oU=Y({...nU,props:Q9,setup(e){const t=e,{t:n}=$t(),o=Se("empty"),r=k(()=>t.description||n("el.table.emptyText")),a=k(()=>({width:rn(t.imageSize)}));return(l,s)=>(T(),V("div",{class:N(i(o).b())},[F("div",{class:N(i(o).e("image")),style:je(i(a))},[l.image?(T(),V("img",{key:0,src:l.image,ondragstart:"return false"},null,8,eU)):ie(l.$slots,"image",{key:1},()=>[K(Z9)])],6),F("div",{class:N(i(o).e("description"))},[l.$slots.description?ie(l.$slots,"description",{key:0}):(T(),V("p",tU,le(i(r)),1))],2),l.$slots.default?(T(),V("div",{key:0,class:N(i(o).e("bottom"))},[ie(l.$slots,"default")],2)):te("v-if",!0)],2))}});var rU=Ie(oU,[["__file","empty.vue"]]);const EE=ut(rU),aU=Ne({urlList:{type:Q(Array),default:()=>en([])},zIndex:{type:Number},initialIndex:{type:Number,default:0},infinite:{type:Boolean,default:!0},hideOnClickModal:Boolean,teleported:Boolean,closeOnPressEscape:{type:Boolean,default:!0},zoomRate:{type:Number,default:1.2},minScale:{type:Number,default:.2},maxScale:{type:Number,default:7},crossorigin:{type:Q(String)}}),lU={close:()=>!0,switch:e=>Je(e),rotate:e=>Je(e)},sU=["src","crossorigin"],iU=Y({name:"ElImageViewer"}),uU=Y({...iU,props:aU,emits:lU,setup(e,{expose:t,emit:n}){var o;const r=e,a={CONTAIN:{name:"contain",icon:Po(S4)},ORIGINAL:{name:"original",icon:Po(W4)}},{t:l}=$t(),s=Se("image-viewer"),{nextZIndex:u}=Zs(),c=R(),f=R([]),d=Bd(),p=R(!0),m=R(r.initialIndex),v=Ut(a.CONTAIN),h=R({scale:1,deg:0,offsetX:0,offsetY:0,enableTransition:!1}),C=R((o=r.zIndex)!=null?o:u()),g=k(()=>{const{urlList:H}=r;return H.length<=1}),y=k(()=>m.value===0),_=k(()=>m.value===r.urlList.length-1),b=k(()=>r.urlList[m.value]),w=k(()=>[s.e("btn"),s.e("prev"),s.is("disabled",!r.infinite&&y.value)]),S=k(()=>[s.e("btn"),s.e("next"),s.is("disabled",!r.infinite&&_.value)]),E=k(()=>{const{scale:H,deg:G,offsetX:J,offsetY:ee,enableTransition:fe}=h.value;let Te=J/H,oe=ee/H;switch(G%360){case 90:case-270:[Te,oe]=[oe,-Te];break;case 180:case-180:[Te,oe]=[-Te,-oe];break;case 270:case-90:[Te,oe]=[-oe,Te];break}const ke={transform:`scale(${H}) rotate(${G}deg) translate(${Te}px, ${oe}px)`,transition:fe?"transform .3s":""};return v.value.name===a.CONTAIN.name&&(ke.maxWidth=ke.maxHeight="100%"),ke});function $(){A(),n("close")}function O(){const H=il(J=>{switch(J.code){case Ue.esc:r.closeOnPressEscape&&$();break;case Ue.space:W();break;case Ue.left:P();break;case Ue.up:I("zoomIn");break;case Ue.right:x();break;case Ue.down:I("zoomOut");break}}),G=il(J=>{const ee=J.deltaY||J.deltaX;I(ee<0?"zoomIn":"zoomOut",{zoomRate:r.zoomRate,enableTransition:!1})});d.run(()=>{qt(document,"keydown",H),qt(document,"wheel",G)})}function A(){d.stop()}function M(){p.value=!1}function D(H){p.value=!1,H.target.alt=l("el.image.error")}function U(H){if(p.value||H.button!==0||!c.value)return;h.value.enableTransition=!1;const{offsetX:G,offsetY:J}=h.value,ee=H.pageX,fe=H.pageY,Te=il(ke=>{h.value={...h.value,offsetX:G+ke.pageX-ee,offsetY:J+ke.pageY-fe}}),oe=qt(document,"mousemove",Te);qt(document,"mouseup",()=>{oe()}),H.preventDefault()}function j(){h.value={scale:1,deg:0,offsetX:0,offsetY:0,enableTransition:!1}}function W(){if(p.value)return;const H=Ss(a),G=Object.values(a),J=v.value.name,fe=(G.findIndex(Te=>Te.name===J)+1)%H.length;v.value=a[H[fe]],j()}function L(H){const G=r.urlList.length;m.value=(H+G)%G}function P(){y.value&&!r.infinite||L(m.value-1)}function x(){_.value&&!r.infinite||L(m.value+1)}function I(H,G={}){if(p.value)return;const{minScale:J,maxScale:ee}=r,{zoomRate:fe,rotateDeg:Te,enableTransition:oe}={zoomRate:r.zoomRate,rotateDeg:90,enableTransition:!0,...G};switch(H){case"zoomOut":h.value.scale>J&&(h.value.scale=Number.parseFloat((h.value.scale/fe).toFixed(3)));break;case"zoomIn":h.value.scale{We(()=>{const H=f.value[0];H!=null&&H.complete||(p.value=!0)})}),ve(m,H=>{j(),n("switch",H)}),at(()=>{var H,G;O(),(G=(H=c.value)==null?void 0:H.focus)==null||G.call(H)}),t({setActiveItem:L}),(H,G)=>(T(),re(Pl,{to:"body",disabled:!H.teleported},[K(fn,{name:"viewer-fade",appear:""},{default:X(()=>[F("div",{ref_key:"wrapper",ref:c,tabindex:-1,class:N(i(s).e("wrapper")),style:je({zIndex:C.value})},[F("div",{class:N(i(s).e("mask")),onClick:G[0]||(G[0]=Qe(J=>H.hideOnClickModal&&$(),["self"]))},null,2),te(" CLOSE "),F("span",{class:N([i(s).e("btn"),i(s).e("close")]),onClick:$},[K(i(ze),null,{default:X(()=>[K(i(tr))]),_:1})],2),te(" ARROW "),i(g)?te("v-if",!0):(T(),V(Ve,{key:0},[F("span",{class:N(i(w)),onClick:P},[K(i(ze),null,{default:X(()=>[K(i(Aa))]),_:1})],2),F("span",{class:N(i(S)),onClick:x},[K(i(ze),null,{default:X(()=>[K(i(Jn))]),_:1})],2)],64)),te(" ACTIONS "),F("div",{class:N([i(s).e("btn"),i(s).e("actions")])},[F("div",{class:N(i(s).e("actions__inner"))},[K(i(ze),{onClick:G[1]||(G[1]=J=>I("zoomOut"))},{default:X(()=>[K(i(l3))]),_:1}),K(i(ze),{onClick:G[2]||(G[2]=J=>I("zoomIn"))},{default:X(()=>[K(i(ZC))]),_:1}),F("i",{class:N(i(s).e("actions__divider"))},null,2),K(i(ze),{onClick:W},{default:X(()=>[(T(),re(pt(i(v).icon)))]),_:1}),F("i",{class:N(i(s).e("actions__divider"))},null,2),K(i(ze),{onClick:G[3]||(G[3]=J=>I("anticlockwise"))},{default:X(()=>[K(i(H4))]),_:1}),K(i(ze),{onClick:G[4]||(G[4]=J=>I("clockwise"))},{default:X(()=>[K(i(XC))]),_:1})],2)],2),te(" CANVAS "),F("div",{class:N(i(s).e("canvas"))},[(T(!0),V(Ve,null,bt(H.urlList,(J,ee)=>tt((T(),V("img",{ref_for:!0,ref:fe=>f.value[ee]=fe,key:J,src:J,style:je(i(E)),class:N(i(s).e("img")),crossorigin:H.crossorigin,onLoad:M,onError:D,onMousedown:U},null,46,sU)),[[kt,ee===m.value]])),128))],2),ie(H.$slots,"default")],6)]),_:3})],8,["disabled"]))}});var cU=Ie(uU,[["__file","image-viewer.vue"]]);const TE=ut(cU),dU=Ne({hideOnClickModal:Boolean,src:{type:String,default:""},fit:{type:String,values:["","contain","cover","fill","none","scale-down"],default:""},loading:{type:String,values:["eager","lazy"]},lazy:Boolean,scrollContainer:{type:Q([String,Object])},previewSrcList:{type:Q(Array),default:()=>en([])},previewTeleported:Boolean,zIndex:{type:Number},initialIndex:{type:Number,default:0},infinite:{type:Boolean,default:!0},closeOnPressEscape:{type:Boolean,default:!0},zoomRate:{type:Number,default:1.2},minScale:{type:Number,default:.2},maxScale:{type:Number,default:7},crossorigin:{type:Q(String)}}),fU={load:e=>e instanceof Event,error:e=>e instanceof Event,switch:e=>Je(e),close:()=>!0,show:()=>!0},pU=["src","loading","crossorigin"],hU={key:0},mU=Y({name:"ElImage",inheritAttrs:!1}),vU=Y({...mU,props:dU,emits:fU,setup(e,{emit:t}){const n=e;let o="";const{t:r}=$t(),a=Se("image"),l=xa(),s=xv(),u=R(),c=R(!1),f=R(!0),d=R(!1),p=R(),m=R(),v=Ct&&"loading"in HTMLImageElement.prototype;let h,C;const g=k(()=>[a.e("inner"),b.value&&a.e("preview"),f.value&&a.is("loading")]),y=k(()=>l.style),_=k(()=>{const{fit:x}=n;return Ct&&x?{objectFit:x}:{}}),b=k(()=>{const{previewSrcList:x}=n;return Array.isArray(x)&&x.length>0}),w=k(()=>{const{previewSrcList:x,initialIndex:I}=n;let H=I;return I>x.length-1&&(H=0),H}),S=k(()=>n.loading==="eager"?!1:!v&&n.loading==="lazy"||n.lazy),E=()=>{Ct&&(f.value=!0,c.value=!1,u.value=n.src)};function $(x){f.value=!1,c.value=!1,t("load",x)}function O(x){f.value=!1,c.value=!0,t("error",x)}function A(){yM(p.value,m.value)&&(E(),U())}const M=Z_(A,200,!0);async function D(){var x;if(!Ct)return;await We();const{scrollContainer:I}=n;Fo(I)?m.value=I:nt(I)&&I!==""?m.value=(x=document.querySelector(I))!=null?x:void 0:p.value&&(m.value=Ov(p.value)),m.value&&(h=qt(m,"scroll",M),setTimeout(()=>A(),100))}function U(){!Ct||!m.value||!M||(h==null||h(),m.value=void 0)}function j(x){if(x.ctrlKey){if(x.deltaY<0)return x.preventDefault(),!1;if(x.deltaY>0)return x.preventDefault(),!1}}function W(){b.value&&(C=qt("wheel",j,{passive:!1}),o=document.body.style.overflow,document.body.style.overflow="hidden",d.value=!0,t("show"))}function L(){C==null||C(),document.body.style.overflow=o,d.value=!1,t("close")}function P(x){t("switch",x)}return ve(()=>n.src,()=>{S.value?(f.value=!0,c.value=!1,U(),D()):E()}),at(()=>{S.value?D():E()}),(x,I)=>(T(),V("div",{ref_key:"container",ref:p,class:N([i(a).b(),x.$attrs.class]),style:je(i(y))},[c.value?ie(x.$slots,"error",{key:0},()=>[F("div",{class:N(i(a).e("error"))},le(i(r)("el.image.error")),3)]):(T(),V(Ve,{key:1},[u.value!==void 0?(T(),V("img",mt({key:0},i(s),{src:u.value,loading:x.loading,style:i(_),class:i(g),crossorigin:x.crossorigin,onClick:W,onLoad:$,onError:O}),null,16,pU)):te("v-if",!0),f.value?(T(),V("div",{key:1,class:N(i(a).e("wrapper"))},[ie(x.$slots,"placeholder",{},()=>[F("div",{class:N(i(a).e("placeholder"))},null,2)])],2)):te("v-if",!0)],64)),i(b)?(T(),V(Ve,{key:2},[d.value?(T(),re(i(TE),{key:0,"z-index":x.zIndex,"initial-index":i(w),infinite:x.infinite,"zoom-rate":x.zoomRate,"min-scale":x.minScale,"max-scale":x.maxScale,"url-list":x.previewSrcList,crossorigin:x.crossorigin,"hide-on-click-modal":x.hideOnClickModal,teleported:x.previewTeleported,"close-on-press-escape":x.closeOnPressEscape,onClose:L,onSwitch:P},{default:X(()=>[x.$slots.viewer?(T(),V("div",hU,[ie(x.$slots,"viewer")])):te("v-if",!0)]),_:3},8,["z-index","initial-index","infinite","zoom-rate","min-scale","max-scale","url-list","crossorigin","hide-on-click-modal","teleported","close-on-press-escape"])):te("v-if",!0)],64)):te("v-if",!0)],6))}});var gU=Ie(vU,[["__file","image.vue"]]);const bU=ut(gU),yU=Ne({id:{type:String,default:void 0},step:{type:Number,default:1},stepStrictly:Boolean,max:{type:Number,default:Number.POSITIVE_INFINITY},min:{type:Number,default:Number.NEGATIVE_INFINITY},modelValue:Number,readonly:Boolean,disabled:Boolean,size:gn,controls:{type:Boolean,default:!0},controlsPosition:{type:String,default:"",values:["","right"]},valueOnClear:{type:[String,Number,null],validator:e=>e===null||Je(e)||["min","max"].includes(e),default:null},name:String,label:String,placeholder:String,precision:{type:Number,validator:e=>e>=0&&e===Number.parseInt(`${e}`,10)},validateEvent:{type:Boolean,default:!0},...An(["ariaLabel"])}),wU={[Yt]:(e,t)=>t!==e,blur:e=>e instanceof FocusEvent,focus:e=>e instanceof FocusEvent,[Zn]:e=>Je(e)||Tn(e),[ft]:e=>Je(e)||Tn(e)},_U=["aria-label","onKeydown"],CU=["aria-label","onKeydown"],SU=Y({name:"ElInputNumber"}),kU=Y({...SU,props:yU,emits:wU,setup(e,{expose:t,emit:n}){const o=e,{t:r}=$t(),a=Se("input-number"),l=R(),s=Et({currentValue:o.modelValue,userInput:null}),{formItem:u}=qn(),c=k(()=>Je(o.modelValue)&&o.modelValue<=o.min),f=k(()=>Je(o.modelValue)&&o.modelValue>=o.max),d=k(()=>{const W=g(o.step);return pn(o.precision)?Math.max(g(o.modelValue),W):(W>o.precision,o.precision)}),p=k(()=>o.controls&&o.controlsPosition==="right"),m=hn(),v=to(),h=k(()=>{if(s.userInput!==null)return s.userInput;let W=s.currentValue;if(Tn(W))return"";if(Je(W)){if(Number.isNaN(W))return"";pn(o.precision)||(W=W.toFixed(o.precision))}return W}),C=(W,L)=>{if(pn(L)&&(L=d.value),L===0)return Math.round(W);let P=String(W);const x=P.indexOf(".");if(x===-1||!P.replace(".","").split("")[x+L])return W;const G=P.length;return P.charAt(G-1)==="5"&&(P=`${P.slice(0,Math.max(0,G-1))}6`),Number.parseFloat(Number(P).toFixed(L))},g=W=>{if(Tn(W))return 0;const L=W.toString(),P=L.indexOf(".");let x=0;return P!==-1&&(x=L.length-P-1),x},y=(W,L=1)=>Je(W)?C(W+o.step*L):s.currentValue,_=()=>{if(o.readonly||v.value||f.value)return;const W=Number(h.value)||0,L=y(W);S(L),n(Zn,s.currentValue),U()},b=()=>{if(o.readonly||v.value||c.value)return;const W=Number(h.value)||0,L=y(W,-1);S(L),n(Zn,s.currentValue),U()},w=(W,L)=>{const{max:P,min:x,step:I,precision:H,stepStrictly:G,valueOnClear:J}=o;PP||eeP?P:x,L&&n(ft,ee)),ee},S=(W,L=!0)=>{var P;const x=s.currentValue,I=w(W);if(!L){n(ft,I);return}x===I&&W||(s.userInput=null,n(ft,I),x!==I&&n(Yt,I,x),o.validateEvent&&((P=u==null?void 0:u.validate)==null||P.call(u,"change").catch(H=>void 0)),s.currentValue=I)},E=W=>{s.userInput=W;const L=W===""?null:Number(W);n(Zn,L),S(L,!1)},$=W=>{const L=W!==""?Number(W):"";(Je(L)&&!Number.isNaN(L)||W==="")&&S(L),U(),s.userInput=null},O=()=>{var W,L;(L=(W=l.value)==null?void 0:W.focus)==null||L.call(W)},A=()=>{var W,L;(L=(W=l.value)==null?void 0:W.blur)==null||L.call(W)},M=W=>{n("focus",W)},D=W=>{var L;s.userInput=null,n("blur",W),o.validateEvent&&((L=u==null?void 0:u.validate)==null||L.call(u,"blur").catch(P=>void 0))},U=()=>{s.currentValue!==o.modelValue&&(s.currentValue=o.modelValue)},j=W=>{document.activeElement===W.target&&W.preventDefault()};return ve(()=>o.modelValue,(W,L)=>{const P=w(W,!0);s.userInput===null&&P!==L&&(s.currentValue=P)},{immediate:!0}),at(()=>{var W;const{min:L,max:P,modelValue:x}=o,I=(W=l.value)==null?void 0:W.input;if(I.setAttribute("role","spinbutton"),Number.isFinite(P)?I.setAttribute("aria-valuemax",String(P)):I.removeAttribute("aria-valuemax"),Number.isFinite(L)?I.setAttribute("aria-valuemin",String(L)):I.removeAttribute("aria-valuemin"),I.setAttribute("aria-valuenow",s.currentValue||s.currentValue===0?String(s.currentValue):""),I.setAttribute("aria-disabled",String(v.value)),!Je(x)&&x!=null){let H=Number(x);Number.isNaN(H)&&(H=null),n(ft,H)}I.addEventListener("wheel",j,{passive:!1})}),ar(()=>{var W,L;const P=(W=l.value)==null?void 0:W.input;P==null||P.setAttribute("aria-valuenow",`${(L=s.currentValue)!=null?L:""}`)}),wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-input-number",ref:"https://element-plus.org/en-US/component/input-number.html"},k(()=>!!o.label)),t({focus:O,blur:A}),(W,L)=>(T(),V("div",{class:N([i(a).b(),i(a).m(i(m)),i(a).is("disabled",i(v)),i(a).is("without-controls",!W.controls),i(a).is("controls-right",i(p))]),onDragstart:L[0]||(L[0]=Qe(()=>{},["prevent"]))},[W.controls?tt((T(),V("span",{key:0,role:"button","aria-label":i(r)("el.inputNumber.decrease"),class:N([i(a).e("decrease"),i(a).is("disabled",i(c))]),onKeydown:Pt(b,["enter"])},[ie(W.$slots,"decrease-icon",{},()=>[K(i(ze),null,{default:X(()=>[i(p)?(T(),re(i(Nr),{key:0})):(T(),re(i(N4),{key:1}))]),_:1})])],42,_U)),[[i(wd),b]]):te("v-if",!0),W.controls?tt((T(),V("span",{key:1,role:"button","aria-label":i(r)("el.inputNumber.increase"),class:N([i(a).e("increase"),i(a).is("disabled",i(f))]),onKeydown:Pt(_,["enter"])},[ie(W.$slots,"increase-icon",{},()=>[K(i(ze),null,{default:X(()=>[i(p)?(T(),re(i(pf),{key:0})):(T(),re(i(GC),{key:1}))]),_:1})])],42,CU)),[[i(wd),_]]):te("v-if",!0),K(i(zn),{id:W.id,ref_key:"input",ref:l,type:"number",step:W.step,"model-value":i(h),placeholder:W.placeholder,readonly:W.readonly,disabled:i(v),size:i(m),max:W.max,min:W.min,name:W.name,"aria-label":W.label||W.ariaLabel,"validate-event":!1,onKeydown:[Pt(Qe(_,["prevent"]),["up"]),Pt(Qe(b,["prevent"]),["down"])],onBlur:D,onFocus:M,onInput:E,onChange:$},null,8,["id","step","model-value","placeholder","readonly","disabled","size","max","min","name","aria-label","onKeydown"])],34))}});var EU=Ie(kU,[["__file","input-number.vue"]]);const $E=ut(EU),TU=Ne({type:{type:String,values:["primary","success","warning","info","danger","default"],default:"default"},underline:{type:Boolean,default:!0},disabled:Boolean,href:{type:String,default:""},target:{type:String,default:"_self"},icon:{type:Dt}}),$U={click:e=>e instanceof MouseEvent},OU=["href","target"],NU=Y({name:"ElLink"}),IU=Y({...NU,props:TU,emits:$U,setup(e,{emit:t}){const n=e,o=Se("link"),r=k(()=>[o.b(),o.m(n.type),o.is("disabled",n.disabled),o.is("underline",n.underline&&!n.disabled)]);function a(l){n.disabled||t("click",l)}return(l,s)=>(T(),V("a",{class:N(i(r)),href:l.disabled||!l.href?void 0:l.href,target:l.disabled||!l.href?void 0:l.target,onClick:a},[l.icon?(T(),re(i(ze),{key:0},{default:X(()=>[(T(),re(pt(l.icon)))]),_:1})):te("v-if",!0),l.$slots.default?(T(),V("span",{key:1,class:N(i(o).e("inner"))},[ie(l.$slots,"default")],2)):te("v-if",!0),l.$slots.icon?ie(l.$slots,"icon",{key:2}):te("v-if",!0)],10,OU))}});var MU=Ie(IU,[["__file","link.vue"]]);const AU=ut(MU);let PU=class{constructor(t,n){this.parent=t,this.domNode=n,this.subIndex=0,this.subIndex=0,this.init()}init(){this.subMenuItems=this.domNode.querySelectorAll("li"),this.addListeners()}gotoSubIndex(t){t===this.subMenuItems.length?t=0:t<0&&(t=this.subMenuItems.length-1),this.subMenuItems[t].focus(),this.subIndex=t}addListeners(){const t=this.parent.domNode;Array.prototype.forEach.call(this.subMenuItems,n=>{n.addEventListener("keydown",o=>{let r=!1;switch(o.code){case Ue.down:{this.gotoSubIndex(this.subIndex+1),r=!0;break}case Ue.up:{this.gotoSubIndex(this.subIndex-1),r=!0;break}case Ue.tab:{Nc(t,"mouseleave");break}case Ue.enter:case Ue.space:{r=!0,o.currentTarget.click();break}}return r&&(o.preventDefault(),o.stopPropagation()),!1})})}},RU=class{constructor(t,n){this.domNode=t,this.submenu=null,this.submenu=null,this.init(n)}init(t){this.domNode.setAttribute("tabindex","0");const n=this.domNode.querySelector(`.${t}-menu`);n&&(this.submenu=new PU(this,n)),this.addListeners()}addListeners(){this.domNode.addEventListener("keydown",t=>{let n=!1;switch(t.code){case Ue.down:{Nc(t.currentTarget,"mouseenter"),this.submenu&&this.submenu.gotoSubIndex(0),n=!0;break}case Ue.up:{Nc(t.currentTarget,"mouseenter"),this.submenu&&this.submenu.gotoSubIndex(this.submenu.subMenuItems.length-1),n=!0;break}case Ue.tab:{Nc(t.currentTarget,"mouseleave");break}case Ue.enter:case Ue.space:{n=!0,t.currentTarget.click();break}}n&&t.preventDefault()})}},LU=class{constructor(t,n){this.domNode=t,this.init(n)}init(t){const n=this.domNode.childNodes;Array.from(n).forEach(o=>{o.nodeType===1&&new RU(o,t)})}};const xU=Y({name:"ElMenuCollapseTransition",setup(){const e=Se("menu");return{listeners:{onBeforeEnter:n=>n.style.opacity="0.2",onEnter(n,o){Mo(n,`${e.namespace.value}-opacity-transition`),n.style.opacity="1",o()},onAfterEnter(n){Kn(n,`${e.namespace.value}-opacity-transition`),n.style.opacity=""},onBeforeLeave(n){n.dataset||(n.dataset={}),wo(n,e.m("collapse"))?(Kn(n,e.m("collapse")),n.dataset.oldOverflow=n.style.overflow,n.dataset.scrollWidth=n.clientWidth.toString(),Mo(n,e.m("collapse"))):(Mo(n,e.m("collapse")),n.dataset.oldOverflow=n.style.overflow,n.dataset.scrollWidth=n.clientWidth.toString(),Kn(n,e.m("collapse"))),n.style.width=`${n.scrollWidth}px`,n.style.overflow="hidden"},onLeave(n){Mo(n,"horizontal-collapse-transition"),n.style.width=`${n.dataset.scrollWidth}px`}}}}});function DU(e,t,n,o,r,a){return T(),re(fn,mt({mode:"out-in"},e.listeners),{default:X(()=>[ie(e.$slots,"default")]),_:3},16)}var FU=Ie(xU,[["render",DU],["__file","menu-collapse-transition.vue"]]);function OE(e,t){const n=k(()=>{let r=e.parent;const a=[t.value];for(;r.type.name!=="ElMenu";)r.props.index&&a.unshift(r.props.index),r=r.parent;return a});return{parentMenu:k(()=>{let r=e.parent;for(;r&&!["ElMenu","ElSubMenu"].includes(r.type.name);)r=r.parent;return r}),indexPath:n}}function BU(e){return k(()=>{const n=e.backgroundColor;return n?new lk(n).shade(20).toString():""})}const NE=(e,t)=>{const n=Se("menu");return k(()=>n.cssVarBlock({"text-color":e.textColor||"","hover-text-color":e.textColor||"","bg-color":e.backgroundColor||"","hover-bg-color":BU(e).value||"","active-color":e.activeTextColor||"",level:`${t}`}))},VU=Ne({index:{type:String,required:!0},showTimeout:Number,hideTimeout:Number,popperClass:String,disabled:Boolean,teleported:{type:Boolean,default:void 0},popperOffset:Number,expandCloseIcon:{type:Dt},expandOpenIcon:{type:Dt},collapseCloseIcon:{type:Dt},collapseOpenIcon:{type:Dt}}),Sp="ElSubMenu";var yg=Y({name:Sp,props:VU,setup(e,{slots:t,expose:n}){const o=lt(),{indexPath:r,parentMenu:a}=OE(o,k(()=>e.index)),l=Se("menu"),s=Se("sub-menu"),u=De("rootMenu");u||vn(Sp,"can not inject root menu");const c=De(`subMenu:${a.value.uid}`);c||vn(Sp,"can not inject sub menu");const f=R({}),d=R({});let p;const m=R(!1),v=R(),h=R(null),C=k(()=>$.value==="horizontal"&&y.value?"bottom-start":"right-start"),g=k(()=>$.value==="horizontal"&&y.value||$.value==="vertical"&&!u.props.collapse?e.expandCloseIcon&&e.expandOpenIcon?S.value?e.expandOpenIcon:e.expandCloseIcon:Nr:e.collapseCloseIcon&&e.collapseOpenIcon?S.value?e.collapseOpenIcon:e.collapseCloseIcon:Jn),y=k(()=>c.level===0),_=k(()=>{const H=e.teleported;return H===void 0?y.value:H}),b=k(()=>u.props.collapse?`${l.namespace.value}-zoom-in-left`:`${l.namespace.value}-zoom-in-top`),w=k(()=>$.value==="horizontal"&&y.value?["bottom-start","bottom-end","top-start","top-end","right-start","left-start"]:["right-start","right","right-end","left-start","bottom-start","bottom-end","top-start","top-end"]),S=k(()=>u.openedMenus.includes(e.index)),E=k(()=>{let H=!1;return Object.values(f.value).forEach(G=>{G.active&&(H=!0)}),Object.values(d.value).forEach(G=>{G.active&&(H=!0)}),H}),$=k(()=>u.props.mode),O=Et({index:e.index,indexPath:r,active:E}),A=NE(u.props,c.level+1),M=k(()=>{var H;return(H=e.popperOffset)!=null?H:u.props.popperOffset}),D=k(()=>{var H;return(H=e.popperClass)!=null?H:u.props.popperClass}),U=k(()=>{var H;return(H=e.showTimeout)!=null?H:u.props.showTimeout}),j=k(()=>{var H;return(H=e.hideTimeout)!=null?H:u.props.hideTimeout}),W=()=>{var H,G,J;return(J=(G=(H=h.value)==null?void 0:H.popperRef)==null?void 0:G.popperInstanceRef)==null?void 0:J.destroy()},L=H=>{H||W()},P=()=>{u.props.menuTrigger==="hover"&&u.props.mode==="horizontal"||u.props.collapse&&u.props.mode==="vertical"||e.disabled||u.handleSubMenuClick({index:e.index,indexPath:r.value,active:E.value})},x=(H,G=U.value)=>{var J;if(H.type!=="focus"){if(u.props.menuTrigger==="click"&&u.props.mode==="horizontal"||!u.props.collapse&&u.props.mode==="vertical"||e.disabled){c.mouseInChild.value=!0;return}c.mouseInChild.value=!0,p==null||p(),{stop:p}=_l(()=>{u.openMenu(e.index,r.value)},G),_.value&&((J=a.value.vnode.el)==null||J.dispatchEvent(new MouseEvent("mouseenter")))}},I=(H=!1)=>{var G;if(u.props.menuTrigger==="click"&&u.props.mode==="horizontal"||!u.props.collapse&&u.props.mode==="vertical"){c.mouseInChild.value=!1;return}p==null||p(),c.mouseInChild.value=!1,{stop:p}=_l(()=>!m.value&&u.closeMenu(e.index,r.value),j.value),_.value&&H&&((G=c.handleMouseleave)==null||G.call(c,!0))};ve(()=>u.props.collapse,H=>L(!!H));{const H=J=>{d.value[J.index]=J},G=J=>{delete d.value[J.index]};yt(`subMenu:${o.uid}`,{addSubMenu:H,removeSubMenu:G,handleMouseleave:I,mouseInChild:m,level:c.level+1})}return n({opened:S}),at(()=>{u.addSubMenu(O),c.addSubMenu(O)}),zt(()=>{c.removeSubMenu(O),u.removeSubMenu(O)}),()=>{var H;const G=[(H=t.title)==null?void 0:H.call(t),Ke(ze,{class:s.e("icon-arrow"),style:{transform:S.value?e.expandCloseIcon&&e.expandOpenIcon||e.collapseCloseIcon&&e.collapseOpenIcon&&u.props.collapse?"none":"rotateZ(180deg)":"none"}},{default:()=>nt(g.value)?Ke(o.appContext.components[g.value]):Ke(g.value)})],J=u.isMenuPopup?Ke(Un,{ref:h,visible:S.value,effect:"light",pure:!0,offset:M.value,showArrow:!1,persistent:!0,popperClass:D.value,placement:C.value,teleported:_.value,fallbackPlacements:w.value,transition:b.value,gpuAcceleration:!1},{content:()=>{var ee;return Ke("div",{class:[l.m($.value),l.m("popup-container"),D.value],onMouseenter:fe=>x(fe,100),onMouseleave:()=>I(!0),onFocus:fe=>x(fe,100)},[Ke("ul",{class:[l.b(),l.m("popup"),l.m(`popup-${C.value}`)],style:A.value},[(ee=t.default)==null?void 0:ee.call(t)])])},default:()=>Ke("div",{class:s.e("title"),onClick:P},G)}):Ke(Ve,{},[Ke("div",{class:s.e("title"),ref:v,onClick:P},G),Ke(Ef,{},{default:()=>{var ee;return tt(Ke("ul",{role:"menu",class:[l.b(),l.m("inline")],style:A.value},[(ee=t.default)==null?void 0:ee.call(t)]),[[kt,S.value]])}})]);return Ke("li",{class:[s.b(),s.is("active",E.value),s.is("opened",S.value),s.is("disabled",e.disabled)],role:"menuitem",ariaHaspopup:!0,ariaExpanded:S.value,onMouseenter:x,onMouseleave:()=>I(),onFocus:x},[J])}}});const HU=Ne({mode:{type:String,values:["horizontal","vertical"],default:"vertical"},defaultActive:{type:String,default:""},defaultOpeneds:{type:Q(Array),default:()=>en([])},uniqueOpened:Boolean,router:Boolean,menuTrigger:{type:String,values:["hover","click"],default:"hover"},collapse:Boolean,backgroundColor:String,textColor:String,activeTextColor:String,closeOnClickOutside:Boolean,collapseTransition:{type:Boolean,default:!0},ellipsis:{type:Boolean,default:!0},popperOffset:{type:Number,default:6},ellipsisIcon:{type:Dt,default:()=>A4},popperEffect:{type:String,values:["dark","light"],default:"dark"},popperClass:String,showTimeout:{type:Number,default:300},hideTimeout:{type:Number,default:300}}),kp=e=>Array.isArray(e)&&e.every(t=>nt(t)),zU={close:(e,t)=>nt(e)&&kp(t),open:(e,t)=>nt(e)&&kp(t),select:(e,t,n,o)=>nt(e)&&kp(t)&&dt(n)&&(o===void 0||o instanceof Promise)};var jU=Y({name:"ElMenu",props:HU,emits:zU,setup(e,{emit:t,slots:n,expose:o}){const r=lt(),a=r.appContext.config.globalProperties.$router,l=R(),s=Se("menu"),u=Se("sub-menu"),c=R(-1),f=R(e.defaultOpeneds&&!e.collapse?e.defaultOpeneds.slice(0):[]),d=R(e.defaultActive),p=R({}),m=R({}),v=k(()=>e.mode==="horizontal"||e.mode==="vertical"&&e.collapse),h=()=>{const j=d.value&&p.value[d.value];if(!j||e.mode==="horizontal"||e.collapse)return;j.indexPath.forEach(L=>{const P=m.value[L];P&&C(L,P.indexPath)})},C=(j,W)=>{f.value.includes(j)||(e.uniqueOpened&&(f.value=f.value.filter(L=>W.includes(L))),f.value.push(j),t("open",j,W))},g=j=>{const W=f.value.indexOf(j);W!==-1&&f.value.splice(W,1)},y=(j,W)=>{g(j),t("close",j,W)},_=({index:j,indexPath:W})=>{f.value.includes(j)?y(j,W):C(j,W)},b=j=>{(e.mode==="horizontal"||e.collapse)&&(f.value=[]);const{index:W,indexPath:L}=j;if(!(Tn(W)||Tn(L)))if(e.router&&a){const P=j.route||W,x=a.push(P).then(I=>(I||(d.value=W),I));t("select",W,L,{index:W,indexPath:L,route:P},x)}else d.value=W,t("select",W,L,{index:W,indexPath:L})},w=j=>{const W=p.value,L=W[j]||d.value&&W[d.value]||W[e.defaultActive];L?d.value=L.index:d.value=j},S=j=>{const W=getComputedStyle(j),L=Number.parseInt(W.marginLeft,10),P=Number.parseInt(W.marginRight,10);return j.offsetWidth+L+P||0},E=()=>{var j,W;if(!l.value)return-1;const L=Array.from((W=(j=l.value)==null?void 0:j.childNodes)!=null?W:[]).filter(fe=>fe.nodeName!=="#comment"&&(fe.nodeName!=="#text"||fe.nodeValue)),P=64,x=getComputedStyle(l.value),I=Number.parseInt(x.paddingLeft,10),H=Number.parseInt(x.paddingRight,10),G=l.value.clientWidth-I-H;let J=0,ee=0;return L.forEach((fe,Te)=>{J+=S(fe),J<=G-P&&(ee=Te+1)}),ee===L.length?-1:ee},$=j=>m.value[j].indexPath,O=(j,W=33.34)=>{let L;return()=>{L&&clearTimeout(L),L=setTimeout(()=>{j()},W)}};let A=!0;const M=()=>{if(c.value===E())return;const j=()=>{c.value=-1,We(()=>{c.value=E()})};A?j():O(j)(),A=!1};ve(()=>e.defaultActive,j=>{p.value[j]||(d.value=""),w(j)}),ve(()=>e.collapse,j=>{j&&(f.value=[])}),ve(p.value,h);let D;Mn(()=>{e.mode==="horizontal"&&e.ellipsis?D=Qt(l,M).stop:D==null||D()});const U=R(!1);{const j=x=>{m.value[x.index]=x},W=x=>{delete m.value[x.index]};yt("rootMenu",Et({props:e,openedMenus:f,items:p,subMenus:m,activeIndex:d,isMenuPopup:v,addMenuItem:x=>{p.value[x.index]=x},removeMenuItem:x=>{delete p.value[x.index]},addSubMenu:j,removeSubMenu:W,openMenu:C,closeMenu:y,handleMenuItemClick:b,handleSubMenuClick:_})),yt(`subMenu:${r.uid}`,{addSubMenu:j,removeSubMenu:W,mouseInChild:U,level:0})}return at(()=>{e.mode==="horizontal"&&new LU(r.vnode.el,s.namespace.value)}),o({open:W=>{const{indexPath:L}=m.value[W];L.forEach(P=>C(P,L))},close:g,handleResize:M}),()=>{var j,W;let L=(W=(j=n.default)==null?void 0:j.call(n))!=null?W:[];const P=[];if(e.mode==="horizontal"&&l.value){const G=Ca(L),J=c.value===-1?G:G.slice(0,c.value),ee=c.value===-1?[]:G.slice(c.value);ee!=null&&ee.length&&e.ellipsis&&(L=J,P.push(Ke(yg,{index:"sub-menu-more",class:u.e("hide-arrow"),popperOffset:e.popperOffset},{title:()=>Ke(ze,{class:u.e("icon-more")},{default:()=>Ke(e.ellipsisIcon)}),default:()=>ee})))}const x=NE(e,0),I=e.closeOnClickOutside?[[Yr,()=>{f.value.length&&(U.value||(f.value.forEach(G=>t("close",G,$(G))),f.value=[]))}]]:[],H=tt(Ke("ul",{key:String(e.collapse),role:"menubar",ref:l,style:x.value,class:{[s.b()]:!0,[s.m(e.mode)]:!0,[s.m("collapse")]:e.collapse}},[...L,...P]),I);return e.collapseTransition&&e.mode==="vertical"?Ke(FU,()=>H):H}}});const WU=Ne({index:{type:Q([String,null]),default:null},route:{type:Q([String,Object])},disabled:Boolean}),KU={click:e=>nt(e.index)&&Array.isArray(e.indexPath)},Ep="ElMenuItem",UU=Y({name:Ep,components:{ElTooltip:Un},props:WU,emits:KU,setup(e,{emit:t}){const n=lt(),o=De("rootMenu"),r=Se("menu"),a=Se("menu-item");o||vn(Ep,"can not inject root menu");const{parentMenu:l,indexPath:s}=OE(n,Lt(e,"index")),u=De(`subMenu:${l.value.uid}`);u||vn(Ep,"can not inject sub menu");const c=k(()=>e.index===o.activeIndex),f=Et({index:e.index,indexPath:s,active:c}),d=()=>{e.disabled||(o.handleMenuItemClick({index:e.index,indexPath:s.value,route:e.route}),t("click",f))};return at(()=>{u.addSubMenu(f),o.addMenuItem(f)}),zt(()=>{u.removeSubMenu(f),o.removeMenuItem(f)}),{parentMenu:l,rootMenu:o,active:c,nsMenu:r,nsMenuItem:a,handleClick:d}}});function qU(e,t,n,o,r,a){const l=qe("el-tooltip");return T(),V("li",{class:N([e.nsMenuItem.b(),e.nsMenuItem.is("active",e.active),e.nsMenuItem.is("disabled",e.disabled)]),role:"menuitem",tabindex:"-1",onClick:t[0]||(t[0]=(...s)=>e.handleClick&&e.handleClick(...s))},[e.parentMenu.type.name==="ElMenu"&&e.rootMenu.props.collapse&&e.$slots.title?(T(),re(l,{key:0,effect:e.rootMenu.props.popperEffect,placement:"right","fallback-placements":["left"],persistent:""},{content:X(()=>[ie(e.$slots,"title")]),default:X(()=>[F("div",{class:N(e.nsMenu.be("tooltip","trigger"))},[ie(e.$slots,"default")],2)]),_:3},8,["effect"])):(T(),V(Ve,{key:1},[ie(e.$slots,"default"),ie(e.$slots,"title")],64))],2)}var IE=Ie(UU,[["render",qU],["__file","menu-item.vue"]]);const YU={title:String},GU="ElMenuItemGroup",XU=Y({name:GU,props:YU,setup(){return{ns:Se("menu-item-group")}}});function JU(e,t,n,o,r,a){return T(),V("li",{class:N(e.ns.b())},[F("div",{class:N(e.ns.e("title"))},[e.$slots.title?ie(e.$slots,"title",{key:1}):(T(),V(Ve,{key:0},[Ge(le(e.title),1)],64))],2),F("ul",null,[ie(e.$slots,"default")])],2)}var ME=Ie(XU,[["render",JU],["__file","menu-item-group.vue"]]);const ZU=ut(jU,{MenuItem:IE,MenuItemGroup:ME,SubMenu:yg}),QU=tn(IE),e7=tn(ME),t7=tn(yg),n7=Ne({icon:{type:Dt,default:()=>o4},title:String,content:{type:String,default:""}}),o7={back:()=>!0},r7=["aria-label"],a7=Y({name:"ElPageHeader"}),l7=Y({...a7,props:n7,emits:o7,setup(e,{emit:t}){const n=Sn(),{t:o}=$t(),r=Se("page-header"),a=k(()=>[r.b(),{[r.m("has-breadcrumb")]:!!n.breadcrumb,[r.m("has-extra")]:!!n.extra,[r.is("contentful")]:!!n.default}]);function l(){t("back")}return(s,u)=>(T(),V("div",{class:N(i(a))},[s.$slots.breadcrumb?(T(),V("div",{key:0,class:N(i(r).e("breadcrumb"))},[ie(s.$slots,"breadcrumb")],2)):te("v-if",!0),F("div",{class:N(i(r).e("header"))},[F("div",{class:N(i(r).e("left"))},[F("div",{class:N(i(r).e("back")),role:"button",tabindex:"0",onClick:l},[s.icon||s.$slots.icon?(T(),V("div",{key:0,"aria-label":s.title||i(o)("el.pageHeader.title"),class:N(i(r).e("icon"))},[ie(s.$slots,"icon",{},()=>[s.icon?(T(),re(i(ze),{key:0},{default:X(()=>[(T(),re(pt(s.icon)))]),_:1})):te("v-if",!0)])],10,r7)):te("v-if",!0),F("div",{class:N(i(r).e("title"))},[ie(s.$slots,"title",{},()=>[Ge(le(s.title||i(o)("el.pageHeader.title")),1)])],2)],2),K(i(vE),{direction:"vertical"}),F("div",{class:N(i(r).e("content"))},[ie(s.$slots,"content",{},()=>[Ge(le(s.content),1)])],2)],2),s.$slots.extra?(T(),V("div",{key:0,class:N(i(r).e("extra"))},[ie(s.$slots,"extra")],2)):te("v-if",!0)],2),s.$slots.default?(T(),V("div",{key:1,class:N(i(r).e("main"))},[ie(s.$slots,"default")],2)):te("v-if",!0)],2))}});var s7=Ie(l7,[["__file","page-header.vue"]]);const i7=ut(s7),AE=Symbol("elPaginationKey"),u7=Ne({disabled:Boolean,currentPage:{type:Number,default:1},prevText:{type:String},prevIcon:{type:Dt}}),c7={click:e=>e instanceof MouseEvent},d7=["disabled","aria-label","aria-disabled"],f7={key:0},p7=Y({name:"ElPaginationPrev"}),h7=Y({...p7,props:u7,emits:c7,setup(e){const t=e,{t:n}=$t(),o=k(()=>t.disabled||t.currentPage<=1);return(r,a)=>(T(),V("button",{type:"button",class:"btn-prev",disabled:i(o),"aria-label":r.prevText||i(n)("el.pagination.prev"),"aria-disabled":i(o),onClick:a[0]||(a[0]=l=>r.$emit("click",l))},[r.prevText?(T(),V("span",f7,le(r.prevText),1)):(T(),re(i(ze),{key:1},{default:X(()=>[(T(),re(pt(r.prevIcon)))]),_:1}))],8,d7))}});var m7=Ie(h7,[["__file","prev.vue"]]);const v7=Ne({disabled:Boolean,currentPage:{type:Number,default:1},pageCount:{type:Number,default:50},nextText:{type:String},nextIcon:{type:Dt}}),g7=["disabled","aria-label","aria-disabled"],b7={key:0},y7=Y({name:"ElPaginationNext"}),w7=Y({...y7,props:v7,emits:["click"],setup(e){const t=e,{t:n}=$t(),o=k(()=>t.disabled||t.currentPage===t.pageCount||t.pageCount===0);return(r,a)=>(T(),V("button",{type:"button",class:"btn-next",disabled:i(o),"aria-label":r.nextText||i(n)("el.pagination.next"),"aria-disabled":i(o),onClick:a[0]||(a[0]=l=>r.$emit("click",l))},[r.nextText?(T(),V("span",b7,le(r.nextText),1)):(T(),re(i(ze),{key:1},{default:X(()=>[(T(),re(pt(r.nextIcon)))]),_:1}))],8,g7))}});var _7=Ie(w7,[["__file","next.vue"]]);const PE=Symbol("ElSelectGroup"),ni=Symbol("ElSelect");function C7(e,t){const n=De(ni),o=De(PE,{disabled:!1}),r=k(()=>n.props.multiple?f(n.props.modelValue,e.value):f([n.props.modelValue],e.value)),a=k(()=>{if(n.props.multiple){const m=n.props.modelValue||[];return!r.value&&m.length>=n.props.multipleLimit&&n.props.multipleLimit>0}else return!1}),l=k(()=>e.label||(dt(e.value)?"":e.value)),s=k(()=>e.value||e.label||""),u=k(()=>e.disabled||t.groupDisabled||a.value),c=lt(),f=(m=[],v)=>{if(dt(e.value)){const h=n.props.valueKey;return m&&m.some(C=>Mt(un(C,h))===un(v,h))}else return m&&m.includes(v)},d=()=>{!e.disabled&&!o.disabled&&(n.states.hoveringIndex=n.optionsArray.indexOf(c.proxy))},p=m=>{const v=new RegExp($v(m),"i");t.visible=v.test(l.value)||e.created};return ve(()=>l.value,()=>{!e.created&&!n.props.remote&&n.setSelected()}),ve(()=>e.value,(m,v)=>{const{remote:h,valueKey:C}=n.props;if(Wn(m,v)||(n.onOptionDestroy(v,c.proxy),n.onOptionCreate(c.proxy)),!e.created&&!h){if(C&&dt(m)&&dt(v)&&m[C]===v[C])return;n.setSelected()}}),ve(()=>o.disabled,()=>{t.groupDisabled=o.disabled},{immediate:!0}),{select:n,currentLabel:l,currentValue:s,itemSelected:r,isDisabled:u,hoverItem:d,updateOption:p}}const S7=Y({name:"ElOption",componentName:"ElOption",props:{value:{required:!0,type:[String,Number,Boolean,Object]},label:[String,Number],created:Boolean,disabled:Boolean},setup(e){const t=Se("select"),n=xn(),o=k(()=>[t.be("dropdown","item"),t.is("disabled",i(s)),t.is("selected",i(l)),t.is("hovering",i(p))]),r=Et({index:-1,groupDisabled:!1,visible:!0,hover:!1}),{currentLabel:a,itemSelected:l,isDisabled:s,select:u,hoverItem:c,updateOption:f}=C7(e,r),{visible:d,hover:p}=Cn(r),m=lt().proxy;u.onOptionCreate(m),zt(()=>{const h=m.value,{selected:C}=u.states,y=(u.props.multiple?C:[C]).some(_=>_.value===m.value);We(()=>{u.states.cachedOptions.get(h)===m&&!y&&u.states.cachedOptions.delete(h)}),u.onOptionDestroy(h,m)});function v(){e.disabled!==!0&&r.groupDisabled!==!0&&u.handleOptionSelect(m)}return{ns:t,id:n,containerKls:o,currentLabel:a,itemSelected:l,isDisabled:s,select:u,hoverItem:c,updateOption:f,visible:d,hover:p,selectOptionClick:v,states:r}}}),k7=["id","aria-disabled","aria-selected"];function E7(e,t,n,o,r,a){return tt((T(),V("li",{id:e.id,class:N(e.containerKls),role:"option","aria-disabled":e.isDisabled||void 0,"aria-selected":e.itemSelected,onMouseenter:t[0]||(t[0]=(...l)=>e.hoverItem&&e.hoverItem(...l)),onClick:t[1]||(t[1]=Qe((...l)=>e.selectOptionClick&&e.selectOptionClick(...l),["stop"]))},[ie(e.$slots,"default",{},()=>[F("span",null,le(e.currentLabel),1)])],42,k7)),[[kt,e.visible]])}var wg=Ie(S7,[["render",E7],["__file","option.vue"]]);const T7=Y({name:"ElSelectDropdown",componentName:"ElSelectDropdown",setup(){const e=De(ni),t=Se("select"),n=k(()=>e.props.popperClass),o=k(()=>e.props.multiple),r=k(()=>e.props.fitInputWidth),a=R("");function l(){var s;a.value=`${(s=e.selectRef)==null?void 0:s.offsetWidth}px`}return at(()=>{l(),Qt(e.selectRef,l)}),{ns:t,minWidth:a,popperClass:n,isMultiple:o,isFitInputWidth:r}}});function $7(e,t,n,o,r,a){return T(),V("div",{class:N([e.ns.b("dropdown"),e.ns.is("multiple",e.isMultiple),e.popperClass]),style:je({[e.isFitInputWidth?"width":"minWidth"]:e.minWidth})},[e.$slots.header?(T(),V("div",{key:0,class:N(e.ns.be("dropdown","header"))},[ie(e.$slots,"header")],2)):te("v-if",!0),ie(e.$slots,"default"),e.$slots.footer?(T(),V("div",{key:1,class:N(e.ns.be("dropdown","footer"))},[ie(e.$slots,"footer")],2)):te("v-if",!0)],6)}var O7=Ie(T7,[["render",$7],["__file","select-dropdown.vue"]]);function RE(e){const t=R(!1);return{handleCompositionStart:()=>{t.value=!0},handleCompositionUpdate:a=>{const l=a.target.value,s=l[l.length-1]||"";t.value=!Lv(s)},handleCompositionEnd:a=>{t.value&&(t.value=!1,Xe(e)&&e(a))}}}const N7=11,I7=(e,t)=>{const{t:n}=$t(),o=xn(),r=Se("select"),a=Se("input"),l=Et({inputValue:"",options:new Map,cachedOptions:new Map,disabledOptions:new Map,optionValues:[],selected:e.multiple?[]:{},selectionWidth:0,calculatorWidth:0,collapseItemWidth:0,selectedLabel:"",hoveringIndex:-1,previousQuery:null,inputHovering:!1,menuVisibleOnFocus:!1,isBeforeHide:!1}),s=R(null),u=R(null),c=R(null),f=R(null),d=R(null),p=R(null),m=R(null),v=R(null),h=R(null),C=R(null),g=R(null),y=R(null),{wrapperRef:_,isFocused:b,handleFocus:w,handleBlur:S}=yf(d,{afterFocus(){e.automaticDropdown&&!E.value&&(E.value=!0,l.menuVisibleOnFocus=!0)},beforeBlur(Le){var ot,Gt;return((ot=c.value)==null?void 0:ot.isFocusInsideContent(Le))||((Gt=f.value)==null?void 0:Gt.isFocusInsideContent(Le))},afterBlur(){E.value=!1,l.menuVisibleOnFocus=!1}}),E=R(!1),$=R(),{form:O,formItem:A}=qn(),{inputId:M}=cr(e,{formItemContext:A}),{valueOnClear:D,isEmptyValue:U}=wf(e),j=k(()=>e.disabled||(O==null?void 0:O.disabled)),W=k(()=>e.multiple?Pe(e.modelValue)&&e.modelValue.length>0:!U(e.modelValue)),L=k(()=>e.clearable&&!j.value&&l.inputHovering&&W.value),P=k(()=>e.remote&&e.filterable&&!e.remoteShowSuffix?"":e.suffixIcon),x=k(()=>r.is("reverse",P.value&&E.value)),I=k(()=>(A==null?void 0:A.validateState)||""),H=k(()=>Rv[I.value]),G=k(()=>e.remote?300:0),J=k(()=>e.loading?e.loadingText||n("el.select.loading"):e.remote&&!l.inputValue&&l.options.size===0?!1:e.filterable&&l.inputValue&&l.options.size>0&&ee.value===0?e.noMatchText||n("el.select.noMatch"):l.options.size===0?e.noDataText||n("el.select.noData"):null),ee=k(()=>fe.value.filter(Le=>Le.visible).length),fe=k(()=>{const Le=Array.from(l.options.values()),ot=[];return l.optionValues.forEach(Gt=>{const ln=Le.findIndex(Wo=>Wo.value===Gt);ln>-1&&ot.push(Le[ln])}),ot.length>=Le.length?ot:Le}),Te=k(()=>Array.from(l.cachedOptions.values())),oe=k(()=>{const Le=fe.value.filter(ot=>!ot.created).some(ot=>ot.currentLabel===l.inputValue);return e.filterable&&e.allowCreate&&l.inputValue!==""&&!Le}),ke=()=>{e.filterable&&Xe(e.filterMethod)||e.filterable&&e.remote&&Xe(e.remoteMethod)||fe.value.forEach(Le=>{var ot;(ot=Le.updateOption)==null||ot.call(Le,l.inputValue)})},ae=hn(),Oe=k(()=>["small"].includes(ae.value)?"small":"default"),we=k({get(){return E.value&&J.value!==!1},set(Le){E.value=Le}}),ge=k(()=>Pe(e.modelValue)?e.modelValue.length===0&&!l.inputValue:e.filterable?!l.inputValue:!0),q=k(()=>{var Le;const ot=(Le=e.placeholder)!=null?Le:n("el.select.placeholder");return e.multiple||!W.value?ot:l.selectedLabel}),B=k(()=>uh?null:"mouseenter");ve(()=>e.modelValue,(Le,ot)=>{e.multiple&&e.filterable&&!e.reserveKeyword&&(l.inputValue="",z("")),ue(),!Wn(Le,ot)&&e.validateEvent&&(A==null||A.validate("change").catch(Gt=>void 0))},{flush:"post",deep:!0}),ve(()=>E.value,Le=>{Le?z(l.inputValue):(l.inputValue="",l.previousQuery=null,l.isBeforeHide=!0),t("visible-change",Le)}),ve(()=>l.options.entries(),()=>{var Le;if(!Ct)return;const ot=((Le=s.value)==null?void 0:Le.querySelectorAll("input"))||[];(!e.filterable&&!e.defaultFirstOption&&!pn(e.modelValue)||!Array.from(ot).includes(document.activeElement))&&ue(),e.defaultFirstOption&&(e.filterable||e.remote)&&ee.value&&Z()},{flush:"post"}),ve(()=>l.hoveringIndex,Le=>{Je(Le)&&Le>-1?$.value=fe.value[Le]||{}:$.value={},fe.value.forEach(ot=>{ot.hover=$.value===ot})}),Mn(()=>{l.isBeforeHide||ke()});const z=Le=>{l.previousQuery!==Le&&(l.previousQuery=Le,e.filterable&&Xe(e.filterMethod)?e.filterMethod(Le):e.filterable&&e.remote&&Xe(e.remoteMethod)&&e.remoteMethod(Le),e.defaultFirstOption&&(e.filterable||e.remote)&&ee.value?We(Z):We(me))},Z=()=>{const Le=fe.value.filter(ln=>ln.visible&&!ln.disabled&&!ln.states.groupDisabled),ot=Le.find(ln=>ln.created),Gt=Le[0];l.hoveringIndex=ye(fe.value,ot||Gt)},ue=()=>{if(e.multiple)l.selectedLabel="";else{const ot=se(e.modelValue);l.selectedLabel=ot.currentLabel,l.selected=ot;return}const Le=[];Pe(e.modelValue)&&e.modelValue.forEach(ot=>{Le.push(se(ot))}),l.selected=Le},se=Le=>{let ot;const Gt=Tc(Le).toLowerCase()==="object",ln=Tc(Le).toLowerCase()==="null",Wo=Tc(Le).toLowerCase()==="undefined";for(let Ko=l.cachedOptions.size-1;Ko>=0;Ko--){const So=Te.value[Ko];if(Gt?un(So.value,e.valueKey)===un(Le,e.valueKey):So.value===Le){ot={value:Le,currentLabel:So.currentLabel,get isDisabled(){return So.isDisabled}};break}}if(ot)return ot;const ra=Gt?Le.label:!ln&&!Wo?Le:"";return{value:Le,currentLabel:ra}},me=()=>{e.multiple?l.hoveringIndex=fe.value.findIndex(Le=>l.selected.some(ot=>oa(ot)===oa(Le))):l.hoveringIndex=fe.value.findIndex(Le=>oa(Le)===oa(l.selected))},_e=()=>{l.selectionWidth=u.value.getBoundingClientRect().width},$e=()=>{l.calculatorWidth=p.value.getBoundingClientRect().width},Ce=()=>{l.collapseItemWidth=g.value.getBoundingClientRect().width},ce=()=>{var Le,ot;(ot=(Le=c.value)==null?void 0:Le.updatePopper)==null||ot.call(Le)},de=()=>{var Le,ot;(ot=(Le=f.value)==null?void 0:Le.updatePopper)==null||ot.call(Le)},xe=()=>{l.inputValue.length>0&&!E.value&&(E.value=!0),z(l.inputValue)},he=Le=>{if(l.inputValue=Le.target.value,e.remote)He();else return xe()},He=co(()=>{xe()},G.value),et=Le=>{Wn(e.modelValue,Le)||t(Yt,Le)},rt=Le=>VC(Le,ot=>!l.disabledOptions.has(ot)),wt=Le=>{if(e.multiple&&Le.code!==Ue.delete&&Le.target.value.length<=0){const ot=e.modelValue.slice(),Gt=rt(ot);if(Gt<0)return;const ln=ot[Gt];ot.splice(Gt,1),t(ft,ot),et(ot),t("remove-tag",ln)}},Ze=(Le,ot)=>{const Gt=l.selected.indexOf(ot);if(Gt>-1&&!j.value){const ln=e.modelValue.slice();ln.splice(Gt,1),t(ft,ln),et(ln),t("remove-tag",ot.value)}Le.stopPropagation(),Jt()},st=Le=>{Le.stopPropagation();const ot=e.multiple?[]:D.value;if(e.multiple)for(const Gt of l.selected)Gt.isDisabled&&ot.push(Gt.value);t(ft,ot),et(ot),l.hoveringIndex=-1,E.value=!1,t("clear"),Jt()},Ee=Le=>{if(e.multiple){const ot=(e.modelValue||[]).slice(),Gt=ye(ot,Le.value);Gt>-1?ot.splice(Gt,1):(e.multipleLimit<=0||ot.length{ne(Le)})},ye=(Le=[],ot)=>{if(!dt(ot))return Le.indexOf(ot);const Gt=e.valueKey;let ln=-1;return Le.some((Wo,ra)=>Mt(un(Wo,Gt))===un(ot,Gt)?(ln=ra,!0):!1),ln},ne=Le=>{var ot,Gt,ln,Wo,ra;const Hl=Pe(Le)?Le[0]:Le;let Ko=null;if(Hl!=null&&Hl.value){const So=fe.value.filter(zl=>zl.value===Hl.value);So.length>0&&(Ko=So[0].$el)}if(c.value&&Ko){const So=(Wo=(ln=(Gt=(ot=c.value)==null?void 0:ot.popperRef)==null?void 0:Gt.contentRef)==null?void 0:ln.querySelector)==null?void 0:Wo.call(ln,`.${r.be("dropdown","wrap")}`);So&&KC(So,Ko)}(ra=y.value)==null||ra.handleScroll()},be=Le=>{l.options.set(Le.value,Le),l.cachedOptions.set(Le.value,Le),Le.disabled&&l.disabledOptions.set(Le.value,Le)},Fe=(Le,ot)=>{l.options.get(Le)===ot&&l.options.delete(Le)},{handleCompositionStart:vt,handleCompositionUpdate:pe,handleCompositionEnd:Ye}=RE(Le=>he(Le)),_t=k(()=>{var Le,ot;return(ot=(Le=c.value)==null?void 0:Le.popperRef)==null?void 0:ot.contentRef}),Kt=()=>{l.isBeforeHide=!1,We(()=>ne(l.selected))},Jt=()=>{var Le;(Le=d.value)==null||Le.focus()},Ht=()=>{Fn()},At=Le=>{st(Le)},Fn=Le=>{if(E.value=!1,b.value){const ot=new FocusEvent("focus",Le);We(()=>S(ot))}},Ku=()=>{l.inputValue.length>0?l.inputValue="":E.value=!1},Uu=()=>{j.value||(uh&&(l.inputHovering=!0),l.menuVisibleOnFocus?l.menuVisibleOnFocus=!1:E.value=!E.value)},ci=()=>{E.value?fe.value[l.hoveringIndex]&&Ee(fe.value[l.hoveringIndex]):Uu()},oa=Le=>dt(Le.value)?un(Le.value,e.valueKey):Le.value,qu=k(()=>fe.value.filter(Le=>Le.visible).every(Le=>Le.disabled)),Uf=k(()=>e.multiple?e.collapseTags?l.selected.slice(0,e.maxCollapseTags):l.selected:[]),Vl=k(()=>e.multiple?e.collapseTags?l.selected.slice(e.maxCollapseTags):[]:[]),Yu=Le=>{if(!E.value){E.value=!0;return}if(!(l.options.size===0||ee.value===0)&&!qu.value){Le==="next"?(l.hoveringIndex++,l.hoveringIndex===l.options.size&&(l.hoveringIndex=0)):Le==="prev"&&(l.hoveringIndex--,l.hoveringIndex<0&&(l.hoveringIndex=l.options.size-1));const ot=fe.value[l.hoveringIndex];(ot.disabled===!0||ot.states.groupDisabled===!0||!ot.visible)&&Yu(Le),We(()=>ne($.value))}},qf=()=>{if(!u.value)return 0;const Le=window.getComputedStyle(u.value);return Number.parseFloat(Le.gap||"6px")},Yf=k(()=>{const Le=qf();return{maxWidth:`${g.value&&e.maxCollapseTags===1?l.selectionWidth-l.collapseItemWidth-Le:l.selectionWidth}px`}}),Gf=k(()=>({maxWidth:`${l.selectionWidth}px`})),Xf=k(()=>({width:`${Math.max(l.calculatorWidth,N7)}px`}));return e.multiple&&!Pe(e.modelValue)&&t(ft,[]),!e.multiple&&Pe(e.modelValue)&&t(ft,""),Qt(u,_e),Qt(p,$e),Qt(h,ce),Qt(_,ce),Qt(C,de),Qt(g,Ce),at(()=>{ue()}),{inputId:M,contentId:o,nsSelect:r,nsInput:a,states:l,isFocused:b,expanded:E,optionsArray:fe,hoverOption:$,selectSize:ae,filteredOptionsCount:ee,resetCalculatorWidth:$e,updateTooltip:ce,updateTagTooltip:de,debouncedOnInputChange:He,onInput:he,deletePrevTag:wt,deleteTag:Ze,deleteSelected:st,handleOptionSelect:Ee,scrollToOption:ne,hasModelValue:W,shouldShowPlaceholder:ge,currentPlaceholder:q,mouseEnterEventName:B,showClose:L,iconComponent:P,iconReverse:x,validateState:I,validateIcon:H,showNewOption:oe,updateOptions:ke,collapseTagSize:Oe,setSelected:ue,selectDisabled:j,emptyText:J,handleCompositionStart:vt,handleCompositionUpdate:pe,handleCompositionEnd:Ye,onOptionCreate:be,onOptionDestroy:Fe,handleMenuEnter:Kt,handleFocus:w,focus:Jt,blur:Ht,handleBlur:S,handleClearClick:At,handleClickOutside:Fn,handleEsc:Ku,toggleMenu:Uu,selectOption:ci,getValueKey:oa,navigateOptions:Yu,dropdownMenuVisible:we,showTagList:Uf,collapseTagList:Vl,tagStyle:Yf,collapseTagStyle:Gf,inputStyle:Xf,popperRef:_t,inputRef:d,tooltipRef:c,tagTooltipRef:f,calculatorRef:p,prefixRef:m,suffixRef:v,selectRef:s,wrapperRef:_,selectionRef:u,scrollbarRef:y,menuRef:h,tagMenuRef:C,collapseItemRef:g}};var M7=Y({name:"ElOptions",setup(e,{slots:t}){const n=De(ni);let o=[];return()=>{var r,a;const l=(r=t.default)==null?void 0:r.call(t),s=[];function u(c){Pe(c)&&c.forEach(f=>{var d,p,m,v;const h=(d=(f==null?void 0:f.type)||{})==null?void 0:d.name;h==="ElOptionGroup"?u(!nt(f.children)&&!Pe(f.children)&&Xe((p=f.children)==null?void 0:p.default)?(m=f.children)==null?void 0:m.default():f.children):h==="ElOption"?s.push((v=f.props)==null?void 0:v.value):Pe(f.children)&&u(f.children)})}return l.length&&u((a=l[0])==null?void 0:a.children),Wn(s,o)||(o=s,n&&(n.states.optionValues=s)),l}}});const A7=Ne({name:String,id:String,modelValue:{type:[Array,String,Number,Boolean,Object],default:void 0},autocomplete:{type:String,default:"off"},automaticDropdown:Boolean,size:gn,effect:{type:Q(String),default:"light"},disabled:Boolean,clearable:Boolean,filterable:Boolean,allowCreate:Boolean,loading:Boolean,popperClass:{type:String,default:""},popperOptions:{type:Q(Object),default:()=>({})},remote:Boolean,loadingText:String,noMatchText:String,noDataText:String,remoteMethod:Function,filterMethod:Function,multiple:Boolean,multipleLimit:{type:Number,default:0},placeholder:{type:String},defaultFirstOption:Boolean,reserveKeyword:{type:Boolean,default:!0},valueKey:{type:String,default:"value"},collapseTags:Boolean,collapseTagsTooltip:Boolean,maxCollapseTags:{type:Number,default:1},teleported:kn.teleported,persistent:{type:Boolean,default:!0},clearIcon:{type:Dt,default:Fa},fitInputWidth:Boolean,suffixIcon:{type:Dt,default:Nr},tagType:{...$l.type,default:"info"},tagEffect:{...$l.effect,default:"light"},validateEvent:{type:Boolean,default:!0},remoteShowSuffix:Boolean,placement:{type:Q(String),values:Dl,default:"bottom-start"},fallbackPlacements:{type:Q(Array),default:["bottom-start","top-start","right","left"]},...ei,...An(["ariaLabel"])}),o1="ElSelect",P7=Y({name:o1,componentName:o1,components:{ElInput:zn,ElSelectMenu:O7,ElOption:wg,ElOptions:M7,ElTag:su,ElScrollbar:ea,ElTooltip:Un,ElIcon:ze},directives:{ClickOutside:Yr},props:A7,emits:[ft,Yt,"remove-tag","clear","visible-change","focus","blur"],setup(e,{emit:t}){const n=I7(e,t);return yt(ni,Et({props:e,states:n.states,optionsArray:n.optionsArray,handleOptionSelect:n.handleOptionSelect,onOptionCreate:n.onOptionCreate,onOptionDestroy:n.onOptionDestroy,selectRef:n.selectRef,setSelected:n.setSelected})),{...n}}}),R7=["id","name","disabled","autocomplete","readonly","aria-activedescendant","aria-controls","aria-expanded","aria-label"],L7=["textContent"],x7={key:1};function D7(e,t,n,o,r,a){const l=qe("el-tag"),s=qe("el-tooltip"),u=qe("el-icon"),c=qe("el-option"),f=qe("el-options"),d=qe("el-scrollbar"),p=qe("el-select-menu"),m=qs("click-outside");return tt((T(),V("div",{ref:"selectRef",class:N([e.nsSelect.b(),e.nsSelect.m(e.selectSize)]),[ls(e.mouseEnterEventName)]:t[16]||(t[16]=v=>e.states.inputHovering=!0),onMouseleave:t[17]||(t[17]=v=>e.states.inputHovering=!1),onClick:t[18]||(t[18]=Qe((...v)=>e.toggleMenu&&e.toggleMenu(...v),["prevent","stop"]))},[K(s,{ref:"tooltipRef",visible:e.dropdownMenuVisible,placement:e.placement,teleported:e.teleported,"popper-class":[e.nsSelect.e("popper"),e.popperClass],"popper-options":e.popperOptions,"fallback-placements":e.fallbackPlacements,effect:e.effect,pure:"",trigger:"click",transition:`${e.nsSelect.namespace.value}-zoom-in-top`,"stop-popper-mouse-event":!1,"gpu-acceleration":!1,persistent:e.persistent,onBeforeShow:e.handleMenuEnter,onHide:t[15]||(t[15]=v=>e.states.isBeforeHide=!1)},{default:X(()=>{var v;return[F("div",{ref:"wrapperRef",class:N([e.nsSelect.e("wrapper"),e.nsSelect.is("focused",e.isFocused),e.nsSelect.is("hovering",e.states.inputHovering),e.nsSelect.is("filterable",e.filterable),e.nsSelect.is("disabled",e.selectDisabled)])},[e.$slots.prefix?(T(),V("div",{key:0,ref:"prefixRef",class:N(e.nsSelect.e("prefix"))},[ie(e.$slots,"prefix")],2)):te("v-if",!0),F("div",{ref:"selectionRef",class:N([e.nsSelect.e("selection"),e.nsSelect.is("near",e.multiple&&!e.$slots.prefix&&!!e.states.selected.length)])},[e.multiple?ie(e.$slots,"tag",{key:0},()=>[(T(!0),V(Ve,null,bt(e.showTagList,h=>(T(),V("div",{key:e.getValueKey(h),class:N(e.nsSelect.e("selected-item"))},[K(l,{closable:!e.selectDisabled&&!h.isDisabled,size:e.collapseTagSize,type:e.tagType,effect:e.tagEffect,"disable-transitions":"",style:je(e.tagStyle),onClose:C=>e.deleteTag(C,h)},{default:X(()=>[F("span",{class:N(e.nsSelect.e("tags-text"))},[ie(e.$slots,"label",{label:h.currentLabel,value:h.value},()=>[Ge(le(h.currentLabel),1)])],2)]),_:2},1032,["closable","size","type","effect","style","onClose"])],2))),128)),e.collapseTags&&e.states.selected.length>e.maxCollapseTags?(T(),re(s,{key:0,ref:"tagTooltipRef",disabled:e.dropdownMenuVisible||!e.collapseTagsTooltip,"fallback-placements":["bottom","top","right","left"],effect:e.effect,placement:"bottom",teleported:e.teleported},{default:X(()=>[F("div",{ref:"collapseItemRef",class:N(e.nsSelect.e("selected-item"))},[K(l,{closable:!1,size:e.collapseTagSize,type:e.tagType,effect:e.tagEffect,"disable-transitions":"",style:je(e.collapseTagStyle)},{default:X(()=>[F("span",{class:N(e.nsSelect.e("tags-text"))}," + "+le(e.states.selected.length-e.maxCollapseTags),3)]),_:1},8,["size","type","effect","style"])],2)]),content:X(()=>[F("div",{ref:"tagMenuRef",class:N(e.nsSelect.e("selection"))},[(T(!0),V(Ve,null,bt(e.collapseTagList,h=>(T(),V("div",{key:e.getValueKey(h),class:N(e.nsSelect.e("selected-item"))},[K(l,{class:"in-tooltip",closable:!e.selectDisabled&&!h.isDisabled,size:e.collapseTagSize,type:e.tagType,effect:e.tagEffect,"disable-transitions":"",onClose:C=>e.deleteTag(C,h)},{default:X(()=>[F("span",{class:N(e.nsSelect.e("tags-text"))},[ie(e.$slots,"label",{label:h.currentLabel,value:h.value},()=>[Ge(le(h.currentLabel),1)])],2)]),_:2},1032,["closable","size","type","effect","onClose"])],2))),128))],2)]),_:3},8,["disabled","effect","teleported"])):te("v-if",!0)]):te("v-if",!0),e.selectDisabled?te("v-if",!0):(T(),V("div",{key:1,class:N([e.nsSelect.e("selected-item"),e.nsSelect.e("input-wrapper"),e.nsSelect.is("hidden",!e.filterable)])},[tt(F("input",{id:e.inputId,ref:"inputRef","onUpdate:modelValue":t[0]||(t[0]=h=>e.states.inputValue=h),type:"text",name:e.name,class:N([e.nsSelect.e("input"),e.nsSelect.is(e.selectSize)]),disabled:e.selectDisabled,autocomplete:e.autocomplete,style:je(e.inputStyle),role:"combobox",readonly:!e.filterable,spellcheck:"false","aria-activedescendant":((v=e.hoverOption)==null?void 0:v.id)||"","aria-controls":e.contentId,"aria-expanded":e.dropdownMenuVisible,"aria-label":e.ariaLabel,"aria-autocomplete":"none","aria-haspopup":"listbox",onFocus:t[1]||(t[1]=(...h)=>e.handleFocus&&e.handleFocus(...h)),onBlur:t[2]||(t[2]=(...h)=>e.handleBlur&&e.handleBlur(...h)),onKeydown:[t[3]||(t[3]=Pt(Qe(h=>e.navigateOptions("next"),["stop","prevent"]),["down"])),t[4]||(t[4]=Pt(Qe(h=>e.navigateOptions("prev"),["stop","prevent"]),["up"])),t[5]||(t[5]=Pt(Qe((...h)=>e.handleEsc&&e.handleEsc(...h),["stop","prevent"]),["esc"])),t[6]||(t[6]=Pt(Qe((...h)=>e.selectOption&&e.selectOption(...h),["stop","prevent"]),["enter"])),t[7]||(t[7]=Pt(Qe((...h)=>e.deletePrevTag&&e.deletePrevTag(...h),["stop"]),["delete"]))],onCompositionstart:t[8]||(t[8]=(...h)=>e.handleCompositionStart&&e.handleCompositionStart(...h)),onCompositionupdate:t[9]||(t[9]=(...h)=>e.handleCompositionUpdate&&e.handleCompositionUpdate(...h)),onCompositionend:t[10]||(t[10]=(...h)=>e.handleCompositionEnd&&e.handleCompositionEnd(...h)),onInput:t[11]||(t[11]=(...h)=>e.onInput&&e.onInput(...h)),onClick:t[12]||(t[12]=Qe((...h)=>e.toggleMenu&&e.toggleMenu(...h),["stop"]))},null,46,R7),[[yl,e.states.inputValue]]),e.filterable?(T(),V("span",{key:0,ref:"calculatorRef","aria-hidden":"true",class:N(e.nsSelect.e("input-calculator")),textContent:le(e.states.inputValue)},null,10,L7)):te("v-if",!0)],2)),e.shouldShowPlaceholder?(T(),V("div",{key:2,class:N([e.nsSelect.e("selected-item"),e.nsSelect.e("placeholder"),e.nsSelect.is("transparent",!e.hasModelValue||e.expanded&&!e.states.inputValue)])},[e.hasModelValue?ie(e.$slots,"label",{key:0,label:e.currentPlaceholder,value:e.modelValue},()=>[F("span",null,le(e.currentPlaceholder),1)]):(T(),V("span",x7,le(e.currentPlaceholder),1))],2)):te("v-if",!0)],2),F("div",{ref:"suffixRef",class:N(e.nsSelect.e("suffix"))},[e.iconComponent&&!e.showClose?(T(),re(u,{key:0,class:N([e.nsSelect.e("caret"),e.nsSelect.e("icon"),e.iconReverse])},{default:X(()=>[(T(),re(pt(e.iconComponent)))]),_:1},8,["class"])):te("v-if",!0),e.showClose&&e.clearIcon?(T(),re(u,{key:1,class:N([e.nsSelect.e("caret"),e.nsSelect.e("icon")]),onClick:e.handleClearClick},{default:X(()=>[(T(),re(pt(e.clearIcon)))]),_:1},8,["class","onClick"])):te("v-if",!0),e.validateState&&e.validateIcon?(T(),re(u,{key:2,class:N([e.nsInput.e("icon"),e.nsInput.e("validateIcon")])},{default:X(()=>[(T(),re(pt(e.validateIcon)))]),_:1},8,["class"])):te("v-if",!0)],2)],2)]}),content:X(()=>[K(p,{ref:"menuRef"},{default:X(()=>[e.$slots.header?(T(),V("div",{key:0,class:N(e.nsSelect.be("dropdown","header")),onClick:t[13]||(t[13]=Qe(()=>{},["stop"]))},[ie(e.$slots,"header")],2)):te("v-if",!0),tt(K(d,{id:e.contentId,ref:"scrollbarRef",tag:"ul","wrap-class":e.nsSelect.be("dropdown","wrap"),"view-class":e.nsSelect.be("dropdown","list"),class:N([e.nsSelect.is("empty",e.filteredOptionsCount===0)]),role:"listbox","aria-label":e.ariaLabel,"aria-orientation":"vertical"},{default:X(()=>[e.showNewOption?(T(),re(c,{key:0,value:e.states.inputValue,created:!0},null,8,["value"])):te("v-if",!0),K(f,null,{default:X(()=>[ie(e.$slots,"default")]),_:3})]),_:3},8,["id","wrap-class","view-class","class","aria-label"]),[[kt,e.states.options.size>0&&!e.loading]]),e.$slots.loading&&e.loading?(T(),V("div",{key:1,class:N(e.nsSelect.be("dropdown","loading"))},[ie(e.$slots,"loading")],2)):e.loading||e.filteredOptionsCount===0?(T(),V("div",{key:2,class:N(e.nsSelect.be("dropdown","empty"))},[ie(e.$slots,"empty",{},()=>[F("span",null,le(e.emptyText),1)])],2)):te("v-if",!0),e.$slots.footer?(T(),V("div",{key:3,class:N(e.nsSelect.be("dropdown","footer")),onClick:t[14]||(t[14]=Qe(()=>{},["stop"]))},[ie(e.$slots,"footer")],2)):te("v-if",!0)]),_:3},512)]),_:3},8,["visible","placement","teleported","popper-class","popper-options","fallback-placements","effect","transition","persistent","onBeforeShow"])],16)),[[m,e.handleClickOutside,e.popperRef]])}var F7=Ie(P7,[["render",D7],["__file","select.vue"]]);const B7=Y({name:"ElOptionGroup",componentName:"ElOptionGroup",props:{label:String,disabled:Boolean},setup(e){const t=Se("select"),n=R(null),o=lt(),r=R([]);yt(PE,Et({...Cn(e)}));const a=k(()=>r.value.some(c=>c.visible===!0)),l=c=>{var f,d;return((f=c.type)==null?void 0:f.name)==="ElOption"&&!!((d=c.component)!=null&&d.proxy)},s=c=>{const f=Ia(c),d=[];return f.forEach(p=>{var m,v;l(p)?d.push(p.component.proxy):(m=p.children)!=null&&m.length?d.push(...s(p.children)):(v=p.component)!=null&&v.subTree&&d.push(...s(p.component.subTree))}),d},u=()=>{r.value=s(o.subTree)};return at(()=>{u()}),eC(n,u,{attributes:!0,subtree:!0,childList:!0}),{groupRef:n,visible:a,ns:t}}});function V7(e,t,n,o,r,a){return tt((T(),V("ul",{ref:"groupRef",class:N(e.ns.be("group","wrap"))},[F("li",{class:N(e.ns.be("group","title"))},le(e.label),3),F("li",null,[F("ul",{class:N(e.ns.b("group"))},[ie(e.$slots,"default")],2)])],2)),[[kt,e.visible]])}var LE=Ie(B7,[["render",V7],["__file","option-group.vue"]]);const Ol=ut(F7,{Option:wg,OptionGroup:LE}),Cd=tn(wg),H7=tn(LE),_g=()=>De(AE,{}),z7=Ne({pageSize:{type:Number,required:!0},pageSizes:{type:Q(Array),default:()=>en([10,20,30,40,50,100])},popperClass:{type:String},disabled:Boolean,teleported:Boolean,size:{type:String,values:Ir}}),j7=Y({name:"ElPaginationSizes"}),W7=Y({...j7,props:z7,emits:["page-size-change"],setup(e,{emit:t}){const n=e,{t:o}=$t(),r=Se("pagination"),a=_g(),l=R(n.pageSize);ve(()=>n.pageSizes,(c,f)=>{if(!Wn(c,f)&&Array.isArray(c)){const d=c.includes(n.pageSize)?n.pageSize:n.pageSizes[0];t("page-size-change",d)}}),ve(()=>n.pageSize,c=>{l.value=c});const s=k(()=>n.pageSizes);function u(c){var f;c!==l.value&&(l.value=c,(f=a.handleSizeChange)==null||f.call(a,Number(c)))}return(c,f)=>(T(),V("span",{class:N(i(r).e("sizes"))},[K(i(Ol),{"model-value":l.value,disabled:c.disabled,"popper-class":c.popperClass,size:c.size,teleported:c.teleported,"validate-event":!1,onChange:u},{default:X(()=>[(T(!0),V(Ve,null,bt(i(s),d=>(T(),re(i(Cd),{key:d,value:d,label:d+i(o)("el.pagination.pagesize")},null,8,["value","label"]))),128))]),_:1},8,["model-value","disabled","popper-class","size","teleported"])],2))}});var K7=Ie(W7,[["__file","sizes.vue"]]);const U7=Ne({size:{type:String,values:Ir}}),q7=["disabled"],Y7=Y({name:"ElPaginationJumper"}),G7=Y({...Y7,props:U7,setup(e){const{t}=$t(),n=Se("pagination"),{pageCount:o,disabled:r,currentPage:a,changeEvent:l}=_g(),s=R(),u=k(()=>{var d;return(d=s.value)!=null?d:a==null?void 0:a.value});function c(d){s.value=d?+d:""}function f(d){d=Math.trunc(+d),l==null||l(d),s.value=void 0}return(d,p)=>(T(),V("span",{class:N(i(n).e("jump")),disabled:i(r)},[F("span",{class:N([i(n).e("goto")])},le(i(t)("el.pagination.goto")),3),K(i(zn),{size:d.size,class:N([i(n).e("editor"),i(n).is("in-pagination")]),min:1,max:i(o),disabled:i(r),"model-value":i(u),"validate-event":!1,"aria-label":i(t)("el.pagination.page"),type:"number","onUpdate:modelValue":c,onChange:f},null,8,["size","class","max","disabled","model-value","aria-label"]),F("span",{class:N([i(n).e("classifier")])},le(i(t)("el.pagination.pageClassifier")),3)],10,q7))}});var X7=Ie(G7,[["__file","jumper.vue"]]);const J7=Ne({total:{type:Number,default:1e3}}),Z7=["disabled"],Q7=Y({name:"ElPaginationTotal"}),eq=Y({...Q7,props:J7,setup(e){const{t}=$t(),n=Se("pagination"),{disabled:o}=_g();return(r,a)=>(T(),V("span",{class:N(i(n).e("total")),disabled:i(o)},le(i(t)("el.pagination.total",{total:r.total})),11,Z7))}});var tq=Ie(eq,[["__file","total.vue"]]);const nq=Ne({currentPage:{type:Number,default:1},pageCount:{type:Number,required:!0},pagerCount:{type:Number,default:7},disabled:Boolean}),oq=["onKeyup"],rq=["aria-current","aria-label","tabindex"],aq=["tabindex","aria-label"],lq=["aria-current","aria-label","tabindex"],sq=["tabindex","aria-label"],iq=["aria-current","aria-label","tabindex"],uq=Y({name:"ElPaginationPager"}),cq=Y({...uq,props:nq,emits:["change"],setup(e,{emit:t}){const n=e,o=Se("pager"),r=Se("icon"),{t:a}=$t(),l=R(!1),s=R(!1),u=R(!1),c=R(!1),f=R(!1),d=R(!1),p=k(()=>{const b=n.pagerCount,w=(b-1)/2,S=Number(n.currentPage),E=Number(n.pageCount);let $=!1,O=!1;E>b&&(S>b-w&&($=!0),S["more","btn-quickprev",r.b(),o.is("disabled",n.disabled)]),v=k(()=>["more","btn-quicknext",r.b(),o.is("disabled",n.disabled)]),h=k(()=>n.disabled?-1:0);Mn(()=>{const b=(n.pagerCount-1)/2;l.value=!1,s.value=!1,n.pageCount>n.pagerCount&&(n.currentPage>n.pagerCount-b&&(l.value=!0),n.currentPageE&&(S=E)),S!==$&&t("change",S)}return(b,w)=>(T(),V("ul",{class:N(i(o).b()),onClick:_,onKeyup:Pt(y,["enter"])},[b.pageCount>0?(T(),V("li",{key:0,class:N([[i(o).is("active",b.currentPage===1),i(o).is("disabled",b.disabled)],"number"]),"aria-current":b.currentPage===1,"aria-label":i(a)("el.pagination.currentPage",{pager:1}),tabindex:i(h)}," 1 ",10,rq)):te("v-if",!0),l.value?(T(),V("li",{key:1,class:N(i(m)),tabindex:i(h),"aria-label":i(a)("el.pagination.prevPages",{pager:b.pagerCount-2}),onMouseenter:w[0]||(w[0]=S=>C(!0)),onMouseleave:w[1]||(w[1]=S=>u.value=!1),onFocus:w[2]||(w[2]=S=>g(!0)),onBlur:w[3]||(w[3]=S=>f.value=!1)},[(u.value||f.value)&&!b.disabled?(T(),re(i(ks),{key:0})):(T(),re(i(Ky),{key:1}))],42,aq)):te("v-if",!0),(T(!0),V(Ve,null,bt(i(p),S=>(T(),V("li",{key:S,class:N([[i(o).is("active",b.currentPage===S),i(o).is("disabled",b.disabled)],"number"]),"aria-current":b.currentPage===S,"aria-label":i(a)("el.pagination.currentPage",{pager:S}),tabindex:i(h)},le(S),11,lq))),128)),s.value?(T(),V("li",{key:2,class:N(i(v)),tabindex:i(h),"aria-label":i(a)("el.pagination.nextPages",{pager:b.pagerCount-2}),onMouseenter:w[4]||(w[4]=S=>C()),onMouseleave:w[5]||(w[5]=S=>c.value=!1),onFocus:w[6]||(w[6]=S=>g()),onBlur:w[7]||(w[7]=S=>d.value=!1)},[(c.value||d.value)&&!b.disabled?(T(),re(i(Es),{key:0})):(T(),re(i(Ky),{key:1}))],42,sq)):te("v-if",!0),b.pageCount>1?(T(),V("li",{key:3,class:N([[i(o).is("active",b.currentPage===b.pageCount),i(o).is("disabled",b.disabled)],"number"]),"aria-current":b.currentPage===b.pageCount,"aria-label":i(a)("el.pagination.currentPage",{pager:b.pageCount}),tabindex:i(h)},le(b.pageCount),11,iq)):te("v-if",!0)],42,oq))}});var dq=Ie(cq,[["__file","pager.vue"]]);const Yn=e=>typeof e!="number",fq=Ne({pageSize:Number,defaultPageSize:Number,total:Number,pageCount:Number,pagerCount:{type:Number,validator:e=>Je(e)&&Math.trunc(e)===e&&e>4&&e<22&&e%2===1,default:7},currentPage:Number,defaultCurrentPage:Number,layout:{type:String,default:["prev","pager","next","jumper","->","total"].join(", ")},pageSizes:{type:Q(Array),default:()=>en([10,20,30,40,50,100])},popperClass:{type:String,default:""},prevText:{type:String,default:""},prevIcon:{type:Dt,default:()=>Aa},nextText:{type:String,default:""},nextIcon:{type:Dt,default:()=>Jn},teleported:{type:Boolean,default:!0},small:Boolean,size:gn,background:Boolean,disabled:Boolean,hideOnSinglePage:Boolean}),pq={"update:current-page":e=>Je(e),"update:page-size":e=>Je(e),"size-change":e=>Je(e),change:(e,t)=>Je(e)&&Je(t),"current-change":e=>Je(e),"prev-click":e=>Je(e),"next-click":e=>Je(e)},r1="ElPagination";var hq=Y({name:r1,props:fq,emits:pq,setup(e,{emit:t,slots:n}){const{t:o}=$t(),r=Se("pagination"),a=lt().vnode.props||{},l=k(()=>{var b;return e.small?"small":(b=e.size)!=null?b:xS().value});wn({from:"small",replacement:"size",version:"3.0.0",scope:"el-pagination",ref:"https://element-plus.org/zh-CN/component/pagination.html"},k(()=>!!e.small));const s="onUpdate:currentPage"in a||"onUpdate:current-page"in a||"onCurrentChange"in a,u="onUpdate:pageSize"in a||"onUpdate:page-size"in a||"onSizeChange"in a,c=k(()=>{if(Yn(e.total)&&Yn(e.pageCount)||!Yn(e.currentPage)&&!s)return!1;if(e.layout.includes("sizes")){if(Yn(e.pageCount)){if(!Yn(e.total)&&!Yn(e.pageSize)&&!u)return!1}else if(!u)return!1}return!0}),f=R(Yn(e.defaultPageSize)?10:e.defaultPageSize),d=R(Yn(e.defaultCurrentPage)?1:e.defaultCurrentPage),p=k({get(){return Yn(e.pageSize)?f.value:e.pageSize},set(b){Yn(e.pageSize)&&(f.value=b),u&&(t("update:page-size",b),t("size-change",b))}}),m=k(()=>{let b=0;return Yn(e.pageCount)?Yn(e.total)||(b=Math.max(1,Math.ceil(e.total/p.value))):b=e.pageCount,b}),v=k({get(){return Yn(e.currentPage)?d.value:e.currentPage},set(b){let w=b;b<1?w=1:b>m.value&&(w=m.value),Yn(e.currentPage)&&(d.value=w),s&&(t("update:current-page",w),t("current-change",w))}});ve(m,b=>{v.value>b&&(v.value=b)}),ve([v,p],b=>{t("change",...b)},{flush:"post"});function h(b){v.value=b}function C(b){p.value=b;const w=m.value;v.value>w&&(v.value=w)}function g(){e.disabled||(v.value-=1,t("prev-click",v.value))}function y(){e.disabled||(v.value+=1,t("next-click",v.value))}function _(b,w){b&&(b.props||(b.props={}),b.props.class=[b.props.class,w].join(" "))}return yt(AE,{pageCount:m,disabled:k(()=>e.disabled),currentPage:v,changeEvent:h,handleSizeChange:C}),()=>{var b,w;if(!c.value)return o("el.pagination.deprecationWarning"),null;if(!e.layout||e.hideOnSinglePage&&m.value<=1)return null;const S=[],E=[],$=Ke("div",{class:r.e("rightwrapper")},E),O={prev:Ke(m7,{disabled:e.disabled,currentPage:v.value,prevText:e.prevText,prevIcon:e.prevIcon,onClick:g}),jumper:Ke(X7,{size:l.value}),pager:Ke(dq,{currentPage:v.value,pageCount:m.value,pagerCount:e.pagerCount,onChange:h,disabled:e.disabled}),next:Ke(_7,{disabled:e.disabled,currentPage:v.value,pageCount:m.value,nextText:e.nextText,nextIcon:e.nextIcon,onClick:y}),sizes:Ke(K7,{pageSize:p.value,pageSizes:e.pageSizes,popperClass:e.popperClass,disabled:e.disabled,teleported:e.teleported,size:l.value}),slot:(w=(b=n==null?void 0:n.default)==null?void 0:b.call(n))!=null?w:null,total:Ke(tq,{total:Yn(e.total)?0:e.total})},A=e.layout.split(",").map(D=>D.trim());let M=!1;return A.forEach(D=>{if(D==="->"){M=!0;return}M?E.push(O[D]):S.push(O[D])}),_(S[0],r.is("first")),_(S[S.length-1],r.is("last")),M&&E.length>0&&(_(E[0],r.is("first")),_(E[E.length-1],r.is("last")),S.push($)),Ke("div",{class:[r.b(),r.is("background",e.background),r.m(l.value)]},S)}}});const mq=ut(hq),vq=Ne({title:String,confirmButtonText:String,cancelButtonText:String,confirmButtonType:{type:String,values:Oh,default:"primary"},cancelButtonType:{type:String,values:Oh,default:"text"},icon:{type:Dt,default:()=>B4},iconColor:{type:String,default:"#f90"},hideIcon:{type:Boolean,default:!1},hideAfter:{type:Number,default:200},teleported:kn.teleported,persistent:kn.persistent,width:{type:[String,Number],default:150}}),gq={confirm:e=>e instanceof MouseEvent,cancel:e=>e instanceof MouseEvent},bq=Y({name:"ElPopconfirm"}),yq=Y({...bq,props:vq,emits:gq,setup(e,{emit:t}){const n=e,{t:o}=$t(),r=Se("popconfirm"),a=R(),l=()=>{var p,m;(m=(p=a.value)==null?void 0:p.onClose)==null||m.call(p)},s=k(()=>({width:rn(n.width)})),u=p=>{t("confirm",p),l()},c=p=>{t("cancel",p),l()},f=k(()=>n.confirmButtonText||o("el.popconfirm.confirmButtonText")),d=k(()=>n.cancelButtonText||o("el.popconfirm.cancelButtonText"));return(p,m)=>(T(),re(i(Un),mt({ref_key:"tooltipRef",ref:a,trigger:"click",effect:"light"},p.$attrs,{"popper-class":`${i(r).namespace.value}-popover`,"popper-style":i(s),teleported:p.teleported,"fallback-placements":["bottom","top","right","left"],"hide-after":p.hideAfter,persistent:p.persistent}),{content:X(()=>[F("div",{class:N(i(r).b())},[F("div",{class:N(i(r).e("main"))},[!p.hideIcon&&p.icon?(T(),re(i(ze),{key:0,class:N(i(r).e("icon")),style:je({color:p.iconColor})},{default:X(()=>[(T(),re(pt(p.icon)))]),_:1},8,["class","style"])):te("v-if",!0),Ge(" "+le(p.title),1)],2),F("div",{class:N(i(r).e("action"))},[K(i($n),{size:"small",type:p.cancelButtonType==="text"?"":p.cancelButtonType,text:p.cancelButtonType==="text",onClick:c},{default:X(()=>[Ge(le(i(d)),1)]),_:1},8,["type","text"]),K(i($n),{size:"small",type:p.confirmButtonType==="text"?"":p.confirmButtonType,text:p.confirmButtonType==="text",onClick:u},{default:X(()=>[Ge(le(i(f)),1)]),_:1},8,["type","text"])],2)],2)]),default:X(()=>[p.$slots.reference?ie(p.$slots,"reference",{key:0}):te("v-if",!0)]),_:3},16,["popper-class","popper-style","teleported","hide-after","persistent"]))}});var wq=Ie(yq,[["__file","popconfirm.vue"]]);const _q=ut(wq),Cq=Ne({trigger:lu.trigger,placement:jc.placement,disabled:lu.disabled,visible:kn.visible,transition:kn.transition,popperOptions:jc.popperOptions,tabindex:jc.tabindex,content:kn.content,popperStyle:kn.popperStyle,popperClass:kn.popperClass,enterable:{...kn.enterable,default:!0},effect:{...kn.effect,default:"light"},teleported:kn.teleported,title:String,width:{type:[String,Number],default:150},offset:{type:Number,default:void 0},showAfter:{type:Number,default:0},hideAfter:{type:Number,default:200},autoClose:{type:Number,default:0},showArrow:{type:Boolean,default:!0},persistent:{type:Boolean,default:!0},"onUpdate:visible":{type:Function}}),Sq={"update:visible":e=>dn(e),"before-enter":()=>!0,"before-leave":()=>!0,"after-enter":()=>!0,"after-leave":()=>!0},kq="onUpdate:visible",Eq=Y({name:"ElPopover"}),Tq=Y({...Eq,props:Cq,emits:Sq,setup(e,{expose:t,emit:n}){const o=e,r=k(()=>o[kq]),a=Se("popover"),l=R(),s=k(()=>{var C;return(C=i(l))==null?void 0:C.popperRef}),u=k(()=>[{width:rn(o.width)},o.popperStyle]),c=k(()=>[a.b(),o.popperClass,{[a.m("plain")]:!!o.content}]),f=k(()=>o.transition===`${a.namespace.value}-fade-in-linear`),d=()=>{var C;(C=l.value)==null||C.hide()},p=()=>{n("before-enter")},m=()=>{n("before-leave")},v=()=>{n("after-enter")},h=()=>{n("update:visible",!1),n("after-leave")};return t({popperRef:s,hide:d}),(C,g)=>(T(),re(i(Un),mt({ref_key:"tooltipRef",ref:l},C.$attrs,{trigger:C.trigger,placement:C.placement,disabled:C.disabled,visible:C.visible,transition:C.transition,"popper-options":C.popperOptions,tabindex:C.tabindex,content:C.content,offset:C.offset,"show-after":C.showAfter,"hide-after":C.hideAfter,"auto-close":C.autoClose,"show-arrow":C.showArrow,"aria-label":C.title,effect:C.effect,enterable:C.enterable,"popper-class":i(c),"popper-style":i(u),teleported:C.teleported,persistent:C.persistent,"gpu-acceleration":i(f),"onUpdate:visible":i(r),onBeforeShow:p,onBeforeHide:m,onShow:v,onHide:h}),{content:X(()=>[C.title?(T(),V("div",{key:0,class:N(i(a).e("title")),role:"title"},le(C.title),3)):te("v-if",!0),ie(C.$slots,"default",{},()=>[Ge(le(C.content),1)])]),default:X(()=>[C.$slots.reference?ie(C.$slots,"reference",{key:0}):te("v-if",!0)]),_:3},16,["trigger","placement","disabled","visible","transition","popper-options","tabindex","content","offset","show-after","hide-after","auto-close","show-arrow","aria-label","effect","enterable","popper-class","popper-style","teleported","persistent","gpu-acceleration","onUpdate:visible"]))}});var $q=Ie(Tq,[["__file","popover.vue"]]);const a1=(e,t)=>{const n=t.arg||t.value,o=n==null?void 0:n.popperRef;o&&(o.triggerRef=e)};var Oq={mounted(e,t){a1(e,t)},updated(e,t){a1(e,t)}};const Nq="popover",xE=i3(Oq,Nq),Iq=ut($q,{directive:xE}),Mq=Ne({type:{type:String,default:"line",values:["line","circle","dashboard"]},percentage:{type:Number,default:0,validator:e=>e>=0&&e<=100},status:{type:String,default:"",values:["","success","exception","warning"]},indeterminate:Boolean,duration:{type:Number,default:3},strokeWidth:{type:Number,default:6},strokeLinecap:{type:Q(String),default:"round"},textInside:Boolean,width:{type:Number,default:126},showText:{type:Boolean,default:!0},color:{type:Q([String,Array,Function]),default:""},striped:Boolean,stripedFlow:Boolean,format:{type:Q(Function),default:e=>`${e}%`}}),Aq=["aria-valuenow"],Pq={viewBox:"0 0 100 100"},Rq=["d","stroke","stroke-linecap","stroke-width"],Lq=["d","stroke","opacity","stroke-linecap","stroke-width"],xq={key:0},Dq=Y({name:"ElProgress"}),Fq=Y({...Dq,props:Mq,setup(e){const t=e,n={success:"#13ce66",exception:"#ff4949",warning:"#e6a23c",default:"#20a0ff"},o=Se("progress"),r=k(()=>{const _={width:`${t.percentage}%`,animationDuration:`${t.duration}s`},b=y(t.percentage);return b.includes("gradient")?_.background=b:_.backgroundColor=b,_}),a=k(()=>(t.strokeWidth/t.width*100).toFixed(1)),l=k(()=>["circle","dashboard"].includes(t.type)?Number.parseInt(`${50-Number.parseFloat(a.value)/2}`,10):0),s=k(()=>{const _=l.value,b=t.type==="dashboard";return` + M 50 50 + m 0 ${b?"":"-"}${_} + a ${_} ${_} 0 1 1 0 ${b?"-":""}${_*2} + a ${_} ${_} 0 1 1 0 ${b?"":"-"}${_*2} + `}),u=k(()=>2*Math.PI*l.value),c=k(()=>t.type==="dashboard"?.75:1),f=k(()=>`${-1*u.value*(1-c.value)/2}px`),d=k(()=>({strokeDasharray:`${u.value*c.value}px, ${u.value}px`,strokeDashoffset:f.value})),p=k(()=>({strokeDasharray:`${u.value*c.value*(t.percentage/100)}px, ${u.value}px`,strokeDashoffset:f.value,transition:"stroke-dasharray 0.6s ease 0s, stroke 0.6s ease, opacity ease 0.6s"})),m=k(()=>{let _;return t.color?_=y(t.percentage):_=n[t.status]||n.default,_}),v=k(()=>t.status==="warning"?hf:t.type==="line"?t.status==="success"?Nv:Fa:t.status==="success"?Mu:tr),h=k(()=>t.type==="line"?12+t.strokeWidth*.4:t.width*.111111+2),C=k(()=>t.format(t.percentage));function g(_){const b=100/_.length;return _.map((S,E)=>nt(S)?{color:S,percentage:(E+1)*b}:S).sort((S,E)=>S.percentage-E.percentage)}const y=_=>{var b;const{color:w}=t;if(Xe(w))return w(_);if(nt(w))return w;{const S=g(w);for(const E of S)if(E.percentage>_)return E.color;return(b=S[S.length-1])==null?void 0:b.color}};return(_,b)=>(T(),V("div",{class:N([i(o).b(),i(o).m(_.type),i(o).is(_.status),{[i(o).m("without-text")]:!_.showText,[i(o).m("text-inside")]:_.textInside}]),role:"progressbar","aria-valuenow":_.percentage,"aria-valuemin":"0","aria-valuemax":"100"},[_.type==="line"?(T(),V("div",{key:0,class:N(i(o).b("bar"))},[F("div",{class:N(i(o).be("bar","outer")),style:je({height:`${_.strokeWidth}px`})},[F("div",{class:N([i(o).be("bar","inner"),{[i(o).bem("bar","inner","indeterminate")]:_.indeterminate},{[i(o).bem("bar","inner","striped")]:_.striped},{[i(o).bem("bar","inner","striped-flow")]:_.stripedFlow}]),style:je(i(r))},[(_.showText||_.$slots.default)&&_.textInside?(T(),V("div",{key:0,class:N(i(o).be("bar","innerText"))},[ie(_.$slots,"default",{percentage:_.percentage},()=>[F("span",null,le(i(C)),1)])],2)):te("v-if",!0)],6)],6)],2)):(T(),V("div",{key:1,class:N(i(o).b("circle")),style:je({height:`${_.width}px`,width:`${_.width}px`})},[(T(),V("svg",Pq,[F("path",{class:N(i(o).be("circle","track")),d:i(s),stroke:`var(${i(o).cssVarName("fill-color-light")}, #e5e9f2)`,"stroke-linecap":_.strokeLinecap,"stroke-width":i(a),fill:"none",style:je(i(d))},null,14,Rq),F("path",{class:N(i(o).be("circle","path")),d:i(s),stroke:i(m),fill:"none",opacity:_.percentage?1:0,"stroke-linecap":_.strokeLinecap,"stroke-width":i(a),style:je(i(p))},null,14,Lq)]))],6)),(_.showText||_.$slots.default)&&!_.textInside?(T(),V("div",{key:2,class:N(i(o).e("text")),style:je({fontSize:`${i(h)}px`})},[ie(_.$slots,"default",{percentage:_.percentage},()=>[_.status?(T(),re(i(ze),{key:1},{default:X(()=>[(T(),re(pt(i(v))))]),_:1})):(T(),V("span",xq,le(i(C)),1))])],6)):te("v-if",!0)],10,Aq))}});var Bq=Ie(Fq,[["__file","progress.vue"]]);const DE=ut(Bq),Vq=Ne({modelValue:{type:Number,default:0},id:{type:String,default:void 0},lowThreshold:{type:Number,default:2},highThreshold:{type:Number,default:4},max:{type:Number,default:5},colors:{type:Q([Array,Object]),default:()=>en(["","",""])},voidColor:{type:String,default:""},disabledVoidColor:{type:String,default:""},icons:{type:Q([Array,Object]),default:()=>[uc,uc,uc]},voidIcon:{type:Dt,default:()=>Q4},disabledVoidIcon:{type:Dt,default:()=>uc},disabled:Boolean,allowHalf:Boolean,showText:Boolean,showScore:Boolean,textColor:{type:String,default:""},texts:{type:Q(Array),default:()=>en(["Extremely bad","Disappointed","Fair","Satisfied","Surprise"])},scoreTemplate:{type:String,default:"{value}"},size:gn,label:{type:String,default:void 0},clearable:Boolean,...An(["ariaLabel"])}),Hq={[Yt]:e=>Je(e),[ft]:e=>Je(e)},zq=["id","aria-label","aria-labelledby","aria-valuenow","aria-valuetext","aria-valuemax"],jq=["onMousemove","onClick"],Wq=Y({name:"ElRate"}),Kq=Y({...Wq,props:Vq,emits:Hq,setup(e,{expose:t,emit:n}){const o=e;function r(L,P){const x=G=>dt(G),I=Object.keys(P).map(G=>+G).filter(G=>{const J=P[G];return(x(J)?J.excluded:!1)?LG-J),H=P[I[0]];return x(H)&&H.value||H}const a=De(Fl,void 0),l=De(Or,void 0),s=hn(),u=Se("rate"),{inputId:c,isLabeledByFormItem:f}=cr(o,{formItemContext:l}),d=R(o.modelValue),p=R(-1),m=R(!0),v=k(()=>[u.b(),u.m(s.value)]),h=k(()=>o.disabled||(a==null?void 0:a.disabled)),C=k(()=>u.cssVarBlock({"void-color":o.voidColor,"disabled-void-color":o.disabledVoidColor,"fill-color":b.value})),g=k(()=>{let L="";return o.showScore?L=o.scoreTemplate.replace(/\{\s*value\s*\}/,h.value?`${o.modelValue}`:`${d.value}`):o.showText&&(L=o.texts[Math.ceil(d.value)-1]),L}),y=k(()=>o.modelValue*100-Math.floor(o.modelValue)*100),_=k(()=>Pe(o.colors)?{[o.lowThreshold]:o.colors[0],[o.highThreshold]:{value:o.colors[1],excluded:!0},[o.max]:o.colors[2]}:o.colors),b=k(()=>{const L=r(d.value,_.value);return dt(L)?"":L}),w=k(()=>{let L="";return h.value?L=`${y.value}%`:o.allowHalf&&(L="50%"),{color:b.value,width:L}}),S=k(()=>{let L=Pe(o.icons)?[...o.icons]:{...o.icons};return L=Po(L),Pe(L)?{[o.lowThreshold]:L[0],[o.highThreshold]:{value:L[1],excluded:!0},[o.max]:L[2]}:L}),E=k(()=>r(o.modelValue,S.value)),$=k(()=>h.value?nt(o.disabledVoidIcon)?o.disabledVoidIcon:Po(o.disabledVoidIcon):nt(o.voidIcon)?o.voidIcon:Po(o.voidIcon)),O=k(()=>r(d.value,S.value));function A(L){const P=h.value&&y.value>0&&L-1o.modelValue,x=o.allowHalf&&m.value&&L-.5<=d.value&&L>d.value;return P||x}function M(L){o.clearable&&L===o.modelValue&&(L=0),n(ft,L),o.modelValue!==L&&n("change",L)}function D(L){h.value||(o.allowHalf&&m.value?M(d.value):M(L))}function U(L){if(h.value)return;let P=d.value;const x=L.code;return x===Ue.up||x===Ue.right?(o.allowHalf?P+=.5:P+=1,L.stopPropagation(),L.preventDefault()):(x===Ue.left||x===Ue.down)&&(o.allowHalf?P-=.5:P-=1,L.stopPropagation(),L.preventDefault()),P=P<0?0:P,P=P>o.max?o.max:P,n(ft,P),n("change",P),P}function j(L,P){if(!h.value){if(o.allowHalf&&P){let x=P.target;wo(x,u.e("item"))&&(x=x.querySelector(`.${u.e("icon")}`)),(x.clientWidth===0||wo(x,u.e("decimal")))&&(x=x.parentNode),m.value=P.offsetX*2<=x.clientWidth,d.value=m.value?L-.5:L}else d.value=L;p.value=L}}function W(){h.value||(o.allowHalf&&(m.value=o.modelValue!==Math.floor(o.modelValue)),d.value=o.modelValue,p.value=-1)}return ve(()=>o.modelValue,L=>{d.value=L,m.value=o.modelValue!==Math.floor(o.modelValue)}),o.modelValue||n(ft,0),wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-rate",ref:"https://element-plus.org/en-US/component/rate.html"},k(()=>!!o.label)),t({setCurrentValue:j,resetCurrentValue:W}),(L,P)=>{var x;return T(),V("div",{id:i(c),class:N([i(v),i(u).is("disabled",i(h))]),role:"slider","aria-label":i(f)?void 0:L.label||L.ariaLabel||"rating","aria-labelledby":i(f)?(x=i(l))==null?void 0:x.labelId:void 0,"aria-valuenow":d.value,"aria-valuetext":i(g)||void 0,"aria-valuemin":"0","aria-valuemax":L.max,tabindex:"0",style:je(i(C)),onKeydown:U},[(T(!0),V(Ve,null,bt(L.max,(I,H)=>(T(),V("span",{key:H,class:N(i(u).e("item")),onMousemove:G=>j(I,G),onMouseleave:W,onClick:G=>D(I)},[K(i(ze),{class:N([i(u).e("icon"),{hover:p.value===I},i(u).is("active",I<=d.value)])},{default:X(()=>[A(I)?te("v-if",!0):(T(),V(Ve,{key:0},[tt((T(),re(pt(i(O)),null,null,512)),[[kt,I<=d.value]]),tt((T(),re(pt(i($)),null,null,512)),[[kt,!(I<=d.value)]])],64)),A(I)?(T(),V(Ve,{key:1},[(T(),re(pt(i($)),{class:N([i(u).em("decimal","box")])},null,8,["class"])),K(i(ze),{style:je(i(w)),class:N([i(u).e("icon"),i(u).e("decimal")])},{default:X(()=>[(T(),re(pt(i(E))))]),_:1},8,["style","class"])],64)):te("v-if",!0)]),_:2},1032,["class"])],42,jq))),128)),L.showText||L.showScore?(T(),V("span",{key:0,class:N(i(u).e("text")),style:je({color:L.textColor})},le(i(g)),7)):te("v-if",!0)],46,zq)}}});var Uq=Ie(Kq,[["__file","rate.vue"]]);const qq=ut(Uq),ts={success:"icon-success",warning:"icon-warning",error:"icon-error",info:"icon-info"},l1={[ts.success]:d4,[ts.warning]:hf,[ts.error]:Iv,[ts.info]:Mv},Yq=Ne({title:{type:String,default:""},subTitle:{type:String,default:""},icon:{type:String,values:["success","warning","info","error"],default:"info"}}),Gq=Y({name:"ElResult"}),Xq=Y({...Gq,props:Yq,setup(e){const t=e,n=Se("result"),o=k(()=>{const r=t.icon,a=r&&ts[r]?ts[r]:"icon-info",l=l1[a]||l1["icon-info"];return{class:a,component:l}});return(r,a)=>(T(),V("div",{class:N(i(n).b())},[F("div",{class:N(i(n).e("icon"))},[ie(r.$slots,"icon",{},()=>[i(o).component?(T(),re(pt(i(o).component),{key:0,class:N(i(o).class)},null,8,["class"])):te("v-if",!0)])],2),r.title||r.$slots.title?(T(),V("div",{key:0,class:N(i(n).e("title"))},[ie(r.$slots,"title",{},()=>[F("p",null,le(r.title),1)])],2)):te("v-if",!0),r.subTitle||r.$slots["sub-title"]?(T(),V("div",{key:1,class:N(i(n).e("subtitle"))},[ie(r.$slots,"sub-title",{},()=>[F("p",null,le(r.subTitle),1)])],2)):te("v-if",!0),r.$slots.extra?(T(),V("div",{key:2,class:N(i(n).e("extra"))},[ie(r.$slots,"extra")],2)):te("v-if",!0)],2))}});var Jq=Ie(Xq,[["__file","result.vue"]]);const Zq=ut(Jq);var s1=Number.isNaN||function(t){return typeof t=="number"&&t!==t};function Qq(e,t){return!!(e===t||s1(e)&&s1(t))}function eY(e,t){if(e.length!==t.length)return!1;for(var n=0;n{const t=lt().proxy.$props;return k(()=>{const n=(o,r,a)=>({});return t.perfMode?uf(n):tY(n)})},Gh=50,Sd="itemRendered",kd="scroll",ns="forward",Ed="backward",Ao="auto",$f="smart",uu="start",br="center",cu="end",Rs="horizontal",Cg="vertical",nY="ltr",hs="rtl",du="negative",Sg="positive-ascending",kg="positive-descending",oY={[Rs]:"left",[Cg]:"top"},rY=20,aY={[Rs]:"deltaX",[Cg]:"deltaY"},lY=({atEndEdge:e,atStartEdge:t,layout:n},o)=>{let r,a=0;const l=u=>u<0&&t.value||u>0&&e.value;return{hasReachedEdge:l,onWheel:u=>{kl(r);const c=u[aY[n.value]];l(a)&&l(a+c)||(a+=c,nC()||u.preventDefault(),r=Ma(()=>{o(a),a=0}))}}},Xh=ir({type:Q([Number,Function]),required:!0}),Jh=ir({type:Number}),Zh=ir({type:Number,default:2}),sY=ir({type:String,values:["ltr","rtl"],default:"ltr"}),Qh=ir({type:Number,default:0}),Td=ir({type:Number,required:!0}),BE=ir({type:String,values:["horizontal","vertical"],default:Cg}),VE=Ne({className:{type:String,default:""},containerElement:{type:Q([String,Object]),default:"div"},data:{type:Q(Array),default:()=>en([])},direction:sY,height:{type:[String,Number],required:!0},innerElement:{type:[String,Object],default:"div"},style:{type:Q([Object,String,Array])},useIsScrolling:{type:Boolean,default:!1},width:{type:[Number,String],required:!1},perfMode:{type:Boolean,default:!0},scrollbarAlwaysOn:{type:Boolean,default:!1}}),HE=Ne({cache:Zh,estimatedItemSize:Jh,layout:BE,initScrollOffset:Qh,total:Td,itemSize:Xh,...VE}),em={type:Number,default:6},zE={type:Number,default:0},jE={type:Number,default:2},dl=Ne({columnCache:Zh,columnWidth:Xh,estimatedColumnWidth:Jh,estimatedRowHeight:Jh,initScrollLeft:Qh,initScrollTop:Qh,itemKey:{type:Q(Function),default:({columnIndex:e,rowIndex:t})=>`${t}:${e}`},rowCache:Zh,rowHeight:Xh,totalColumn:Td,totalRow:Td,hScrollbarSize:em,vScrollbarSize:em,scrollbarStartGap:zE,scrollbarEndGap:jE,role:String,...VE}),WE=Ne({alwaysOn:Boolean,class:String,layout:BE,total:Td,ratio:{type:Number,required:!0},clientSize:{type:Number,required:!0},scrollFrom:{type:Number,required:!0},scrollbarSize:em,startGap:zE,endGap:jE,visible:Boolean}),tl=(e,t)=>ee===nY||e===hs||e===Rs,i1=e=>e===hs;let Yl=null;function $d(e=!1){if(Yl===null||e){const t=document.createElement("div"),n=t.style;n.width="50px",n.height="50px",n.overflow="scroll",n.direction="rtl";const o=document.createElement("div"),r=o.style;return r.width="100px",r.height="100px",t.appendChild(o),document.body.appendChild(t),t.scrollLeft>0?Yl=kg:(t.scrollLeft=1,t.scrollLeft===0?Yl=du:Yl=Sg),document.body.removeChild(t),Yl}return Yl}function iY({move:e,size:t,bar:n},o){const r={},a=`translate${n.axis}(${e}px)`;return r[n.size]=t,r.transform=a,r.msTransform=a,r.webkitTransform=a,o==="horizontal"?r.height="100%":r.width="100%",r}const tm=Y({name:"ElVirtualScrollBar",props:WE,emits:["scroll","start-move","stop-move"],setup(e,{emit:t}){const n=k(()=>e.startGap+e.endGap),o=Se("virtual-scrollbar"),r=Se("scrollbar"),a=R(),l=R();let s=null,u=null;const c=Et({isDragging:!1,traveled:0}),f=k(()=>jS[e.layout]),d=k(()=>e.clientSize-i(n)),p=k(()=>({position:"absolute",width:`${Rs===e.layout?d.value:e.scrollbarSize}px`,height:`${Rs===e.layout?e.scrollbarSize:d.value}px`,[oY[e.layout]]:"2px",right:"2px",bottom:"2px",borderRadius:"4px"})),m=k(()=>{const S=e.ratio,E=e.clientSize;if(S>=100)return Number.POSITIVE_INFINITY;if(S>=50)return S*E/100;const $=E/3;return Math.floor(Math.min(Math.max(S*E,rY),$))}),v=k(()=>{if(!Number.isFinite(m.value))return{display:"none"};const S=`${m.value}px`;return iY({bar:f.value,size:S,move:c.traveled},e.layout)}),h=k(()=>Math.floor(e.clientSize-m.value-i(n))),C=()=>{window.addEventListener("mousemove",b),window.addEventListener("mouseup",_);const S=i(l);S&&(u=document.onselectstart,document.onselectstart=()=>!1,S.addEventListener("touchmove",b),S.addEventListener("touchend",_))},g=()=>{window.removeEventListener("mousemove",b),window.removeEventListener("mouseup",_),document.onselectstart=u,u=null;const S=i(l);S&&(S.removeEventListener("touchmove",b),S.removeEventListener("touchend",_))},y=S=>{S.stopImmediatePropagation(),!(S.ctrlKey||[1,2].includes(S.button))&&(c.isDragging=!0,c[f.value.axis]=S.currentTarget[f.value.offset]-(S[f.value.client]-S.currentTarget.getBoundingClientRect()[f.value.direction]),t("start-move"),C())},_=()=>{c.isDragging=!1,c[f.value.axis]=0,t("stop-move"),g()},b=S=>{const{isDragging:E}=c;if(!E||!l.value||!a.value)return;const $=c[f.value.axis];if(!$)return;kl(s);const O=(a.value.getBoundingClientRect()[f.value.direction]-S[f.value.client])*-1,A=l.value[f.value.offset]-$,M=O-A;s=Ma(()=>{c.traveled=Math.max(e.startGap,Math.min(M,h.value)),t("scroll",M,h.value)})},w=S=>{const E=Math.abs(S.target.getBoundingClientRect()[f.value.direction]-S[f.value.client]),$=l.value[f.value.offset]/2,O=E-$;c.traveled=Math.max(0,Math.min(O,h.value)),t("scroll",O,h.value)};return ve(()=>e.scrollFrom,S=>{c.isDragging||(c.traveled=Math.ceil(S*h.value))}),zt(()=>{g()}),()=>Ke("div",{role:"presentation",ref:a,class:[o.b(),e.class,(e.alwaysOn||c.isDragging)&&"always-on"],style:p.value,onMousedown:Qe(w,["stop","prevent"]),onTouchstartPrevent:y},Ke("div",{ref:l,class:r.e("thumb"),style:v.value,onMousedown:y},[]))}}),KE=({name:e,getOffset:t,getItemSize:n,getItemOffset:o,getEstimatedTotalSize:r,getStartIndexForOffset:a,getStopIndexForStartIndex:l,initCache:s,clearCache:u,validateProps:c})=>Y({name:e??"ElVirtualList",props:HE,emits:[Sd,kd],setup(f,{emit:d,expose:p}){c(f);const m=lt(),v=Se("vl"),h=R(s(f,m)),C=FE(),g=R(),y=R(),_=R(),b=R({isScrolling:!1,scrollDir:"forward",scrollOffset:Je(f.initScrollOffset)?f.initScrollOffset:0,updateRequested:!1,isScrollbarDragging:!1,scrollbarAlwaysOn:f.scrollbarAlwaysOn}),w=k(()=>{const{total:ee,cache:fe}=f,{isScrolling:Te,scrollDir:oe,scrollOffset:ke}=i(b);if(ee===0)return[0,0,0,0];const ae=a(f,ke,i(h)),Oe=l(f,ae,ke,i(h)),we=!Te||oe===Ed?Math.max(1,fe):1,ge=!Te||oe===ns?Math.max(1,fe):1;return[Math.max(0,ae-we),Math.max(0,Math.min(ee-1,Oe+ge)),ae,Oe]}),S=k(()=>r(f,i(h))),E=k(()=>fu(f.layout)),$=k(()=>[{position:"relative",[`overflow-${E.value?"x":"y"}`]:"scroll",WebkitOverflowScrolling:"touch",willChange:"transform"},{direction:f.direction,height:Je(f.height)?`${f.height}px`:f.height,width:Je(f.width)?`${f.width}px`:f.width},f.style]),O=k(()=>{const ee=i(S),fe=i(E);return{height:fe?"100%":`${ee}px`,pointerEvents:i(b).isScrolling?"none":void 0,width:fe?`${ee}px`:"100%"}}),A=k(()=>E.value?f.width:f.height),{onWheel:M}=lY({atStartEdge:k(()=>b.value.scrollOffset<=0),atEndEdge:k(()=>b.value.scrollOffset>=S.value),layout:k(()=>f.layout)},ee=>{var fe,Te;(Te=(fe=_.value).onMouseUp)==null||Te.call(fe),P(Math.min(b.value.scrollOffset+ee,S.value-A.value))}),D=()=>{const{total:ee}=f;if(ee>0){const[ke,ae,Oe,we]=i(w);d(Sd,ke,ae,Oe,we)}const{scrollDir:fe,scrollOffset:Te,updateRequested:oe}=i(b);d(kd,fe,Te,oe)},U=ee=>{const{clientHeight:fe,scrollHeight:Te,scrollTop:oe}=ee.currentTarget,ke=i(b);if(ke.scrollOffset===oe)return;const ae=Math.max(0,Math.min(oe,Te-fe));b.value={...ke,isScrolling:!0,scrollDir:tl(ke.scrollOffset,ae),scrollOffset:ae,updateRequested:!1},We(H)},j=ee=>{const{clientWidth:fe,scrollLeft:Te,scrollWidth:oe}=ee.currentTarget,ke=i(b);if(ke.scrollOffset===Te)return;const{direction:ae}=f;let Oe=Te;if(ae===hs)switch($d()){case du:{Oe=-Te;break}case kg:{Oe=oe-fe-Te;break}}Oe=Math.max(0,Math.min(Oe,oe-fe)),b.value={...ke,isScrolling:!0,scrollDir:tl(ke.scrollOffset,Oe),scrollOffset:Oe,updateRequested:!1},We(H)},W=ee=>{i(E)?j(ee):U(ee),D()},L=(ee,fe)=>{const Te=(S.value-A.value)/fe*ee;P(Math.min(S.value-A.value,Te))},P=ee=>{ee=Math.max(ee,0),ee!==i(b).scrollOffset&&(b.value={...i(b),scrollOffset:ee,scrollDir:tl(i(b).scrollOffset,ee),updateRequested:!0},We(H))},x=(ee,fe=Ao)=>{const{scrollOffset:Te}=i(b);ee=Math.max(0,Math.min(ee,f.total-1)),P(t(f,ee,fe,Te,i(h)))},I=ee=>{const{direction:fe,itemSize:Te,layout:oe}=f,ke=C.value(u&&Te,u&&oe,u&&fe);let ae;if(Tt(ke,String(ee)))ae=ke[ee];else{const Oe=o(f,ee,i(h)),we=n(f,ee,i(h)),ge=i(E),q=fe===hs,B=ge?Oe:0;ke[ee]=ae={position:"absolute",left:q?void 0:`${B}px`,right:q?`${B}px`:void 0,top:ge?0:`${Oe}px`,height:ge?"100%":`${we}px`,width:ge?`${we}px`:"100%"}}return ae},H=()=>{b.value.isScrolling=!1,We(()=>{C.value(-1,null,null)})},G=()=>{const ee=g.value;ee&&(ee.scrollTop=0)};at(()=>{if(!Ct)return;const{initScrollOffset:ee}=f,fe=i(g);Je(ee)&&fe&&(i(E)?fe.scrollLeft=ee:fe.scrollTop=ee),D()}),ar(()=>{const{direction:ee,layout:fe}=f,{scrollOffset:Te,updateRequested:oe}=i(b),ke=i(g);if(oe&&ke)if(fe===Rs)if(ee===hs)switch($d()){case du:{ke.scrollLeft=-Te;break}case Sg:{ke.scrollLeft=Te;break}default:{const{clientWidth:ae,scrollWidth:Oe}=ke;ke.scrollLeft=Oe-ae-Te;break}}else ke.scrollLeft=Te;else ke.scrollTop=Te}),Zm(()=>{i(g).scrollTop=i(b).scrollOffset});const J={ns:v,clientSize:A,estimatedTotalSize:S,windowStyle:$,windowRef:g,innerRef:y,innerStyle:O,itemsToRender:w,scrollbarRef:_,states:b,getItemStyle:I,onScroll:W,onScrollbarScroll:L,onWheel:M,scrollTo:P,scrollToItem:x,resetScrollTop:G};return p({windowRef:g,innerRef:y,getItemStyleCache:C,scrollTo:P,scrollToItem:x,resetScrollTop:G,states:b}),J},render(f){var d;const{$slots:p,className:m,clientSize:v,containerElement:h,data:C,getItemStyle:g,innerElement:y,itemsToRender:_,innerStyle:b,layout:w,total:S,onScroll:E,onScrollbarScroll:$,onWheel:O,states:A,useIsScrolling:M,windowStyle:D,ns:U}=f,[j,W]=_,L=pt(h),P=pt(y),x=[];if(S>0)for(let J=j;J<=W;J++)x.push((d=p.default)==null?void 0:d.call(p,{data:C,key:J,index:J,isScrolling:M?A.isScrolling:void 0,style:g(J)}));const I=[Ke(P,{style:b,ref:"innerRef"},nt(P)?x:{default:()=>x})],H=Ke(tm,{ref:"scrollbarRef",clientSize:v,layout:w,onScroll:$,ratio:v*100/this.estimatedTotalSize,scrollFrom:A.scrollOffset/(this.estimatedTotalSize-v),total:S}),G=Ke(L,{class:[U.e("window"),m],style:D,onScroll:E,onWheel:O,ref:"windowRef",key:0},nt(L)?[I]:{default:()=>[I]});return Ke("div",{key:0,class:[U.e("wrapper"),A.scrollbarAlwaysOn?"always-on":""]},[G,H])}}),UE=KE({name:"ElFixedSizeList",getItemOffset:({itemSize:e},t)=>t*e,getItemSize:({itemSize:e})=>e,getEstimatedTotalSize:({total:e,itemSize:t})=>t*e,getOffset:({height:e,total:t,itemSize:n,layout:o,width:r},a,l,s)=>{const u=fu(o)?r:e,c=Math.max(0,t*n-u),f=Math.min(c,a*n),d=Math.max(0,(a+1)*n-u);switch(l===$f&&(s>=d-u&&s<=f+u?l=Ao:l=br),l){case uu:return f;case cu:return d;case br:{const p=Math.round(d+(f-d)/2);return pc+Math.floor(u/2)?c:p}case Ao:default:return s>=d&&s<=f?s:sMath.max(0,Math.min(e-1,Math.floor(n/t))),getStopIndexForStartIndex:({height:e,total:t,itemSize:n,layout:o,width:r},a,l)=>{const s=a*n,u=fu(o)?r:e,c=Math.ceil((u+l-s)/n);return Math.max(0,Math.min(t-1,a+c-1))},initCache(){},clearCache:!0,validateProps(){}}),os=(e,t,n)=>{const{itemSize:o}=e,{items:r,lastVisitedIndex:a}=n;if(t>a){let l=0;if(a>=0){const s=r[a];l=s.offset+s.size}for(let s=a+1;s<=t;s++){const u=o(s);r[s]={offset:l,size:u},l+=u}n.lastVisitedIndex=t}return r[t]},uY=(e,t,n)=>{const{items:o,lastVisitedIndex:r}=t;return(r>0?o[r].offset:0)>=n?qE(e,t,0,r,n):cY(e,t,Math.max(0,r),n)},qE=(e,t,n,o,r)=>{for(;n<=o;){const a=n+Math.floor((o-n)/2),l=os(e,a,t).offset;if(l===r)return a;lr&&(o=a-1)}return Math.max(0,n-1)},cY=(e,t,n,o)=>{const{total:r}=e;let a=1;for(;n{let r=0;if(o>=e&&(o=e-1),o>=0){const s=t[o];r=s.offset+s.size}const l=(e-o-1)*n;return r+l},dY=KE({name:"ElDynamicSizeList",getItemOffset:(e,t,n)=>os(e,t,n).offset,getItemSize:(e,t,{items:n})=>n[t].size,getEstimatedTotalSize:u1,getOffset:(e,t,n,o,r)=>{const{height:a,layout:l,width:s}=e,u=fu(l)?s:a,c=os(e,t,r),f=u1(e,r),d=Math.max(0,Math.min(f-u,c.offset)),p=Math.max(0,c.offset-u+c.size);switch(n===$f&&(o>=p-u&&o<=d+u?n=Ao:n=br),n){case uu:return d;case cu:return p;case br:return Math.round(p+(d-p)/2);case Ao:default:return o>=p&&o<=d?o:ouY(e,n,t),getStopIndexForStartIndex:(e,t,n,o)=>{const{height:r,total:a,layout:l,width:s}=e,u=fu(l)?s:r,c=os(e,t,o),f=n+u;let d=c.offset+c.size,p=t;for(;p{var a,l;n.lastVisitedIndex=Math.min(n.lastVisitedIndex,o-1),(a=t.exposed)==null||a.getItemStyleCache(-1),r&&((l=t.proxy)==null||l.$forceUpdate())},n},clearCache:!1,validateProps:({itemSize:e})=>{}}),fY=({atXEndEdge:e,atXStartEdge:t,atYEndEdge:n,atYStartEdge:o},r)=>{let a=null,l=0,s=0;const u=(f,d)=>{const p=f<=0&&t.value||f>=0&&e.value,m=d<=0&&o.value||d>=0&&n.value;return p&&m};return{hasReachedEdge:u,onWheel:f=>{kl(a);let d=f.deltaX,p=f.deltaY;Math.abs(d)>Math.abs(p)?p=0:d=0,f.shiftKey&&p!==0&&(d=p,p=0),!(u(l,s)&&u(l+d,s+p))&&(l+=d,s+=p,f.preventDefault(),a=Ma(()=>{r(l,s),l=0,s=0}))}}},YE=({name:e,clearCache:t,getColumnPosition:n,getColumnStartIndexForOffset:o,getColumnStopIndexForStartIndex:r,getEstimatedTotalHeight:a,getEstimatedTotalWidth:l,getColumnOffset:s,getRowOffset:u,getRowPosition:c,getRowStartIndexForOffset:f,getRowStopIndexForStartIndex:d,initCache:p,injectToInstance:m,validateProps:v})=>Y({name:e??"ElVirtualList",props:dl,emits:[Sd,kd],setup(h,{emit:C,expose:g,slots:y}){const _=Se("vl");v(h);const b=lt(),w=R(p(h,b));m==null||m(b,w);const S=R(),E=R(),$=R(),O=R(null),A=R({isScrolling:!1,scrollLeft:Je(h.initScrollLeft)?h.initScrollLeft:0,scrollTop:Je(h.initScrollTop)?h.initScrollTop:0,updateRequested:!1,xAxisScrollDir:ns,yAxisScrollDir:ns}),M=FE(),D=k(()=>Number.parseInt(`${h.height}`,10)),U=k(()=>Number.parseInt(`${h.width}`,10)),j=k(()=>{const{totalColumn:se,totalRow:me,columnCache:_e}=h,{isScrolling:$e,xAxisScrollDir:Ce,scrollLeft:ce}=i(A);if(se===0||me===0)return[0,0,0,0];const de=o(h,ce,i(w)),xe=r(h,de,ce,i(w)),he=!$e||Ce===Ed?Math.max(1,_e):1,He=!$e||Ce===ns?Math.max(1,_e):1;return[Math.max(0,de-he),Math.max(0,Math.min(se-1,xe+He)),de,xe]}),W=k(()=>{const{totalColumn:se,totalRow:me,rowCache:_e}=h,{isScrolling:$e,yAxisScrollDir:Ce,scrollTop:ce}=i(A);if(se===0||me===0)return[0,0,0,0];const de=f(h,ce,i(w)),xe=d(h,de,ce,i(w)),he=!$e||Ce===Ed?Math.max(1,_e):1,He=!$e||Ce===ns?Math.max(1,_e):1;return[Math.max(0,de-he),Math.max(0,Math.min(me-1,xe+He)),de,xe]}),L=k(()=>a(h,i(w))),P=k(()=>l(h,i(w))),x=k(()=>{var se;return[{position:"relative",overflow:"hidden",WebkitOverflowScrolling:"touch",willChange:"transform"},{direction:h.direction,height:Je(h.height)?`${h.height}px`:h.height,width:Je(h.width)?`${h.width}px`:h.width},(se=h.style)!=null?se:{}]}),I=k(()=>{const se=`${i(P)}px`;return{height:`${i(L)}px`,pointerEvents:i(A).isScrolling?"none":void 0,width:se}}),H=()=>{const{totalColumn:se,totalRow:me}=h;if(se>0&&me>0){const[xe,he,He,et]=i(j),[rt,wt,Ze,st]=i(W);C(Sd,{columnCacheStart:xe,columnCacheEnd:he,rowCacheStart:rt,rowCacheEnd:wt,columnVisibleStart:He,columnVisibleEnd:et,rowVisibleStart:Ze,rowVisibleEnd:st})}const{scrollLeft:_e,scrollTop:$e,updateRequested:Ce,xAxisScrollDir:ce,yAxisScrollDir:de}=i(A);C(kd,{xAxisScrollDir:ce,scrollLeft:_e,yAxisScrollDir:de,scrollTop:$e,updateRequested:Ce})},G=se=>{const{clientHeight:me,clientWidth:_e,scrollHeight:$e,scrollLeft:Ce,scrollTop:ce,scrollWidth:de}=se.currentTarget,xe=i(A);if(xe.scrollTop===ce&&xe.scrollLeft===Ce)return;let he=Ce;if(i1(h.direction))switch($d()){case du:he=-Ce;break;case kg:he=de-_e-Ce;break}A.value={...xe,isScrolling:!0,scrollLeft:he,scrollTop:Math.max(0,Math.min(ce,$e-me)),updateRequested:!0,xAxisScrollDir:tl(xe.scrollLeft,he),yAxisScrollDir:tl(xe.scrollTop,ce)},We(()=>ae()),Oe(),H()},J=(se,me)=>{const _e=i(D),$e=(L.value-_e)/me*se;Te({scrollTop:Math.min(L.value-_e,$e)})},ee=(se,me)=>{const _e=i(U),$e=(P.value-_e)/me*se;Te({scrollLeft:Math.min(P.value-_e,$e)})},{onWheel:fe}=fY({atXStartEdge:k(()=>A.value.scrollLeft<=0),atXEndEdge:k(()=>A.value.scrollLeft>=P.value-i(U)),atYStartEdge:k(()=>A.value.scrollTop<=0),atYEndEdge:k(()=>A.value.scrollTop>=L.value-i(D))},(se,me)=>{var _e,$e,Ce,ce;($e=(_e=E.value)==null?void 0:_e.onMouseUp)==null||$e.call(_e),(ce=(Ce=$.value)==null?void 0:Ce.onMouseUp)==null||ce.call(Ce);const de=i(U),xe=i(D);Te({scrollLeft:Math.min(A.value.scrollLeft+se,P.value-de),scrollTop:Math.min(A.value.scrollTop+me,L.value-xe)})}),Te=({scrollLeft:se=A.value.scrollLeft,scrollTop:me=A.value.scrollTop})=>{se=Math.max(se,0),me=Math.max(me,0);const _e=i(A);me===_e.scrollTop&&se===_e.scrollLeft||(A.value={..._e,xAxisScrollDir:tl(_e.scrollLeft,se),yAxisScrollDir:tl(_e.scrollTop,me),scrollLeft:se,scrollTop:me,updateRequested:!0},We(()=>ae()),Oe(),H())},oe=(se=0,me=0,_e=Ao)=>{const $e=i(A);me=Math.max(0,Math.min(me,h.totalColumn-1)),se=Math.max(0,Math.min(se,h.totalRow-1));const Ce=WC(_.namespace.value),ce=i(w),de=a(h,ce),xe=l(h,ce);Te({scrollLeft:s(h,me,_e,$e.scrollLeft,ce,xe>h.width?Ce:0),scrollTop:u(h,se,_e,$e.scrollTop,ce,de>h.height?Ce:0)})},ke=(se,me)=>{const{columnWidth:_e,direction:$e,rowHeight:Ce}=h,ce=M.value(t&&_e,t&&Ce,t&&$e),de=`${se},${me}`;if(Tt(ce,de))return ce[de];{const[,xe]=n(h,me,i(w)),he=i(w),He=i1($e),[et,rt]=c(h,se,he),[wt]=n(h,me,he);return ce[de]={position:"absolute",left:He?void 0:`${xe}px`,right:He?`${xe}px`:void 0,top:`${rt}px`,height:`${et}px`,width:`${wt}px`},ce[de]}},ae=()=>{A.value.isScrolling=!1,We(()=>{M.value(-1,null,null)})};at(()=>{if(!Ct)return;const{initScrollLeft:se,initScrollTop:me}=h,_e=i(S);_e&&(Je(se)&&(_e.scrollLeft=se),Je(me)&&(_e.scrollTop=me)),H()});const Oe=()=>{const{direction:se}=h,{scrollLeft:me,scrollTop:_e,updateRequested:$e}=i(A),Ce=i(S);if($e&&Ce){if(se===hs)switch($d()){case du:{Ce.scrollLeft=-me;break}case Sg:{Ce.scrollLeft=me;break}default:{const{clientWidth:ce,scrollWidth:de}=Ce;Ce.scrollLeft=de-ce-me;break}}else Ce.scrollLeft=Math.max(0,me);Ce.scrollTop=Math.max(0,_e)}},{resetAfterColumnIndex:we,resetAfterRowIndex:ge,resetAfter:q}=b.proxy;g({windowRef:S,innerRef:O,getItemStyleCache:M,scrollTo:Te,scrollToItem:oe,states:A,resetAfterColumnIndex:we,resetAfterRowIndex:ge,resetAfter:q});const B=()=>{const{scrollbarAlwaysOn:se,scrollbarStartGap:me,scrollbarEndGap:_e,totalColumn:$e,totalRow:Ce}=h,ce=i(U),de=i(D),xe=i(P),he=i(L),{scrollLeft:He,scrollTop:et}=i(A),rt=Ke(tm,{ref:E,alwaysOn:se,startGap:me,endGap:_e,class:_.e("horizontal"),clientSize:ce,layout:"horizontal",onScroll:ee,ratio:ce*100/xe,scrollFrom:He/(xe-ce),total:Ce,visible:!0}),wt=Ke(tm,{ref:$,alwaysOn:se,startGap:me,endGap:_e,class:_.e("vertical"),clientSize:de,layout:"vertical",onScroll:J,ratio:de*100/he,scrollFrom:et/(he-de),total:$e,visible:!0});return{horizontalScrollbar:rt,verticalScrollbar:wt}},z=()=>{var se;const[me,_e]=i(j),[$e,Ce]=i(W),{data:ce,totalColumn:de,totalRow:xe,useIsScrolling:he,itemKey:He}=h,et=[];if(xe>0&&de>0)for(let rt=$e;rt<=Ce;rt++)for(let wt=me;wt<=_e;wt++)et.push((se=y.default)==null?void 0:se.call(y,{columnIndex:wt,data:ce,key:He({columnIndex:wt,data:ce,rowIndex:rt}),isScrolling:he?i(A).isScrolling:void 0,style:ke(rt,wt),rowIndex:rt}));return et},Z=()=>{const se=pt(h.innerElement),me=z();return[Ke(se,{style:i(I),ref:O},nt(se)?me:{default:()=>me})]};return()=>{const se=pt(h.containerElement),{horizontalScrollbar:me,verticalScrollbar:_e}=B(),$e=Z();return Ke("div",{key:0,class:_.e("wrapper"),role:h.role},[Ke(se,{class:h.className,style:i(x),onScroll:G,onWheel:fe,ref:S},nt(se)?$e:{default:()=>$e}),me,_e])}}}),pY=YE({name:"ElFixedSizeGrid",getColumnPosition:({columnWidth:e},t)=>[e,t*e],getRowPosition:({rowHeight:e},t)=>[e,t*e],getEstimatedTotalHeight:({totalRow:e,rowHeight:t})=>t*e,getEstimatedTotalWidth:({totalColumn:e,columnWidth:t})=>t*e,getColumnOffset:({totalColumn:e,columnWidth:t,width:n},o,r,a,l,s)=>{n=Number(n);const u=Math.max(0,e*t-n),c=Math.min(u,o*t),f=Math.max(0,o*t-n+s+t);switch(r==="smart"&&(a>=f-n&&a<=c+n?r=Ao:r=br),r){case uu:return c;case cu:return f;case br:{const d=Math.round(f+(c-f)/2);return du+Math.floor(n/2)?u:d}case Ao:default:return a>=f&&a<=c?a:f>c||a{t=Number(t);const u=Math.max(0,n*e-t),c=Math.min(u,o*e),f=Math.max(0,o*e-t+s+e);switch(r===$f&&(a>=f-t&&a<=c+t?r=Ao:r=br),r){case uu:return c;case cu:return f;case br:{const d=Math.round(f+(c-f)/2);return du+Math.floor(t/2)?u:d}case Ao:default:return a>=f&&a<=c?a:f>c||aMath.max(0,Math.min(t-1,Math.floor(n/e))),getColumnStopIndexForStartIndex:({columnWidth:e,totalColumn:t,width:n},o,r)=>{const a=o*e,l=Math.ceil((n+r-a)/e);return Math.max(0,Math.min(t-1,o+l-1))},getRowStartIndexForOffset:({rowHeight:e,totalRow:t},n)=>Math.max(0,Math.min(t-1,Math.floor(n/e))),getRowStopIndexForStartIndex:({rowHeight:e,totalRow:t,height:n},o,r)=>{const a=o*e,l=Math.ceil((n+r-a)/e);return Math.max(0,Math.min(t-1,o+l-1))},initCache:()=>{},clearCache:!0,validateProps:({columnWidth:e,rowHeight:t})=>{}}),{max:Od,min:GE,floor:XE}=Math,hY={column:"columnWidth",row:"rowHeight"},nm={column:"lastVisitedColumnIndex",row:"lastVisitedRowIndex"},Vr=(e,t,n,o)=>{const[r,a,l]=[n[o],e[hY[o]],n[nm[o]]];if(t>l){let s=0;if(l>=0){const u=r[l];s=u.offset+u.size}for(let u=l+1;u<=t;u++){const c=a(u);r[u]={offset:s,size:c},s+=c}n[nm[o]]=t}return r[t]},JE=(e,t,n,o,r,a)=>{for(;n<=o;){const l=n+XE((o-n)/2),s=Vr(e,l,t,a).offset;if(s===r)return l;s{const a=r==="column"?e.totalColumn:e.totalRow;let l=1;for(;n{const[r,a]=[t[o],t[nm[o]]];return(a>0?r[a].offset:0)>=n?JE(e,t,0,a,n,o):mY(e,t,Od(0,a),n,o)},ZE=({totalRow:e},{estimatedRowHeight:t,lastVisitedRowIndex:n,row:o})=>{let r=0;if(n>=e&&(n=e-1),n>=0){const s=o[n];r=s.offset+s.size}const l=(e-n-1)*t;return r+l},QE=({totalColumn:e},{column:t,estimatedColumnWidth:n,lastVisitedColumnIndex:o})=>{let r=0;if(o>e&&(o=e-1),o>=0){const s=t[o];r=s.offset+s.size}const l=(e-o-1)*n;return r+l},vY={column:QE,row:ZE},d1=(e,t,n,o,r,a,l)=>{const[s,u]=[a==="row"?e.height:e.width,vY[a]],c=Vr(e,t,r,a),f=u(e,r),d=Od(0,GE(f-s,c.offset)),p=Od(0,c.offset-s+l+c.size);switch(n===$f&&(o>=p-s&&o<=d+s?n=Ao:n=br),n){case uu:return d;case cu:return p;case br:return Math.round(p+(d-p)/2);case Ao:default:return o>=p&&o<=d?o:p>d||o{const o=Vr(e,t,n,"column");return[o.size,o.offset]},getRowPosition:(e,t,n)=>{const o=Vr(e,t,n,"row");return[o.size,o.offset]},getColumnOffset:(e,t,n,o,r,a)=>d1(e,t,n,o,r,"column",a),getRowOffset:(e,t,n,o,r,a)=>d1(e,t,n,o,r,"row",a),getColumnStartIndexForOffset:(e,t,n)=>c1(e,n,t,"column"),getColumnStopIndexForStartIndex:(e,t,n,o)=>{const r=Vr(e,t,o,"column"),a=n+e.width;let l=r.offset+r.size,s=t;for(;sc1(e,n,t,"row"),getRowStopIndexForStartIndex:(e,t,n,o)=>{const{totalRow:r,height:a}=e,l=Vr(e,t,o,"row"),s=n+a;let u=l.size+l.offset,c=t;for(;c{const n=({columnIndex:a,rowIndex:l},s)=>{var u,c;s=pn(s)?!0:s,Je(a)&&(t.value.lastVisitedColumnIndex=Math.min(t.value.lastVisitedColumnIndex,a-1)),Je(l)&&(t.value.lastVisitedRowIndex=Math.min(t.value.lastVisitedRowIndex,l-1)),(u=e.exposed)==null||u.getItemStyleCache.value(-1,null,null),s&&((c=e.proxy)==null||c.$forceUpdate())},o=(a,l)=>{n({columnIndex:a},l)},r=(a,l)=>{n({rowIndex:a},l)};Object.assign(e.proxy,{resetAfterColumnIndex:o,resetAfterRowIndex:r,resetAfter:n})},initCache:({estimatedColumnWidth:e=Gh,estimatedRowHeight:t=Gh})=>({column:{},estimatedColumnWidth:e,estimatedRowHeight:t,lastVisitedColumnIndex:-1,lastVisitedRowIndex:-1,row:{}}),clearCache:!1,validateProps:({columnWidth:e,rowHeight:t})=>{}}),bY=Y({props:{item:{type:Object,required:!0},style:Object,height:Number},setup(){return{ns:Se("select")}}});function yY(e,t,n,o,r,a){return T(),V("div",{class:N(e.ns.be("group","title")),style:je([e.style,{lineHeight:`${e.height}px`}])},le(e.item.label),7)}var wY=Ie(bY,[["render",yY],["__file","group-item.vue"]]);function _Y(e,{emit:t}){return{hoverItem:()=>{e.disabled||t("hover",e.index)},selectOptionClick:()=>{e.disabled||t("select",e.item,e.index)}}}const e2={label:"label",value:"value",disabled:"disabled",options:"options"};function Of(e){const t=k(()=>({...e2,...e.props}));return{aliasProps:t,getLabel:l=>un(l,t.value.label),getValue:l=>un(l,t.value.value),getDisabled:l=>un(l,t.value.disabled),getOptions:l=>un(l,t.value.options)}}const CY=Ne({allowCreate:Boolean,autocomplete:{type:Q(String),default:"none"},automaticDropdown:Boolean,clearable:Boolean,clearIcon:{type:Dt,default:Fa},effect:{type:Q(String),default:"light"},collapseTags:Boolean,collapseTagsTooltip:Boolean,maxCollapseTags:{type:Number,default:1},defaultFirstOption:Boolean,disabled:Boolean,estimatedOptionHeight:{type:Number,default:void 0},filterable:Boolean,filterMethod:Function,height:{type:Number,default:274},itemHeight:{type:Number,default:34},id:String,loading:Boolean,loadingText:String,modelValue:{type:Q([Array,String,Number,Boolean,Object])},multiple:Boolean,multipleLimit:{type:Number,default:0},name:String,noDataText:String,noMatchText:String,remoteMethod:Function,reserveKeyword:{type:Boolean,default:!0},options:{type:Q(Array),required:!0},placeholder:{type:String},teleported:kn.teleported,persistent:{type:Boolean,default:!0},popperClass:{type:String,default:""},popperOptions:{type:Q(Object),default:()=>({})},remote:Boolean,size:gn,props:{type:Q(Object),default:()=>e2},valueKey:{type:String,default:"value"},scrollbarAlwaysOn:Boolean,validateEvent:{type:Boolean,default:!0},placement:{type:Q(String),values:Dl,default:"bottom-start"},fallbackPlacements:{type:Q(Array),default:["bottom-start","top-start","right","left"]},tagType:{...$l.type,default:"info"},tagEffect:{...$l.effect,default:"light"},...ei,...An(["ariaLabel"])}),SY=Ne({data:Array,disabled:Boolean,hovering:Boolean,item:{type:Q(Object),required:!0},index:Number,style:Object,selected:Boolean,created:Boolean}),Eg=Symbol("ElSelectV2Injection"),kY=Y({props:SY,emits:["select","hover"],setup(e,{emit:t}){const n=De(Eg),o=Se("select"),{hoverItem:r,selectOptionClick:a}=_Y(e,{emit:t}),{getLabel:l}=Of(n.props);return{ns:o,hoverItem:r,selectOptionClick:a,getLabel:l}}}),EY=["aria-selected"];function TY(e,t,n,o,r,a){return T(),V("li",{"aria-selected":e.selected,style:je(e.style),class:N([e.ns.be("dropdown","item"),e.ns.is("selected",e.selected),e.ns.is("disabled",e.disabled),e.ns.is("created",e.created),e.ns.is("hovering",e.hovering)]),onMouseenter:t[0]||(t[0]=(...l)=>e.hoverItem&&e.hoverItem(...l)),onClick:t[1]||(t[1]=Qe((...l)=>e.selectOptionClick&&e.selectOptionClick(...l),["stop"]))},[ie(e.$slots,"default",{item:e.item,index:e.index,disabled:e.disabled},()=>[F("span",null,le(e.getLabel(e.item)),1)])],46,EY)}var $Y=Ie(kY,[["render",TY],["__file","option-item.vue"]]),OY=Y({name:"ElSelectDropdown",props:{loading:Boolean,data:{type:Array,required:!0},hoveringIndex:Number,width:Number},setup(e,{slots:t,expose:n}){const o=De(Eg),r=Se("select"),{getLabel:a,getValue:l,getDisabled:s}=Of(o.props),u=R([]),c=R(),f=k(()=>e.data.length);ve(()=>f.value,()=>{var M,D;(D=(M=o.tooltipRef.value).updatePopper)==null||D.call(M)});const d=k(()=>pn(o.props.estimatedOptionHeight)),p=k(()=>d.value?{itemSize:o.props.itemHeight}:{estimatedSize:o.props.estimatedOptionHeight,itemSize:M=>u.value[M]}),m=(M=[],D)=>{const{props:{valueKey:U}}=o;return dt(D)?M&&M.some(j=>Mt(un(j,U))===un(D,U)):M.includes(D)},v=(M,D)=>{if(dt(D)){const{valueKey:U}=o.props;return un(M,U)===un(D,U)}else return M===D},h=(M,D)=>o.props.multiple?m(M,l(D)):v(M,l(D)),C=(M,D)=>{const{disabled:U,multiple:j,multipleLimit:W}=o.props;return U||!D&&(j?W>0&&M.length>=W:!1)},g=M=>e.hoveringIndex===M;n({listRef:c,isSized:d,isItemDisabled:C,isItemHovering:g,isItemSelected:h,scrollToItem:M=>{const D=c.value;D&&D.scrollToItem(M)},resetScrollTop:()=>{const M=c.value;M&&M.resetScrollTop()}});const b=M=>{const{index:D,data:U,style:j}=M,W=i(d),{itemSize:L,estimatedSize:P}=i(p),{modelValue:x}=o.props,{onSelect:I,onHover:H}=o,G=U[D];if(G.type==="Group")return K(wY,{item:G,style:j,height:W?L:P},null);const J=h(x,G),ee=C(x,J),fe=g(D);return K($Y,mt(M,{selected:J,disabled:s(G)||ee,created:!!G.created,hovering:fe,item:G,onSelect:I,onHover:H}),{default:Te=>{var oe;return((oe=t.default)==null?void 0:oe.call(t,Te))||K("span",null,[a(G)])}})},{onKeyboardNavigate:w,onKeyboardSelect:S}=o,E=()=>{w("forward")},$=()=>{w("backward")},O=()=>{o.expanded=!1},A=M=>{const{code:D}=M,{tab:U,esc:j,down:W,up:L,enter:P}=Ue;switch(D!==U&&(M.preventDefault(),M.stopPropagation()),D){case U:case j:{O();break}case W:{E();break}case L:{$();break}case P:{S();break}}};return()=>{var M,D,U,j;const{data:W,width:L}=e,{height:P,multiple:x,scrollbarAlwaysOn:I}=o.props,H=i(d)?UE:dY;return K("div",{class:[r.b("dropdown"),r.is("multiple",x)],style:{width:`${L}px`}},[(M=t.header)==null?void 0:M.call(t),((D=t.loading)==null?void 0:D.call(t))||((U=t.empty)==null?void 0:U.call(t))||K(H,mt({ref:c},i(p),{className:r.be("dropdown","list"),scrollbarAlwaysOn:I,data:W,height:P,width:L,total:W.length,onKeydown:A}),{default:G=>K(b,G,null)}),(j=t.footer)==null?void 0:j.call(t)])}}});function NY(e,t){const{aliasProps:n,getLabel:o,getValue:r}=Of(e),a=R(0),l=R(null),s=k(()=>e.allowCreate&&e.filterable);function u(m){const v=h=>o(h)===m;return e.options&&e.options.some(v)||t.createdOptions.some(v)}function c(m){s.value&&(e.multiple&&m.created?a.value++:l.value=m)}function f(m){if(s.value)if(m&&m.length>0){if(u(m))return;const v={[n.value.value]:m,[n.value.label]:m,created:!0,[n.value.disabled]:!1};t.createdOptions.length>=a.value?t.createdOptions[a.value]=v:t.createdOptions.push(v)}else if(e.multiple)t.createdOptions.length=a.value;else{const v=l.value;t.createdOptions.length=0,v&&v.created&&t.createdOptions.push(v)}}function d(m){if(!s.value||!m||!m.created||m.created&&e.reserveKeyword&&t.inputValue===o(m))return;const v=t.createdOptions.findIndex(h=>r(h)===r(m));~v&&(t.createdOptions.splice(v,1),a.value--)}function p(){s.value&&(t.createdOptions.length=0,a.value=0)}return{createNewOption:f,removeNewOption:d,selectNewOption:c,clearAllNewOption:p}}const IY=11,MY=(e,t)=>{const{t:n}=$t(),o=Se("select"),r=Se("input"),{form:a,formItem:l}=qn(),{inputId:s}=cr(e,{formItemContext:l}),{aliasProps:u,getLabel:c,getValue:f,getDisabled:d,getOptions:p}=Of(e),{valueOnClear:m,isEmptyValue:v}=wf(e),h=Et({inputValue:"",cachedOptions:[],createdOptions:[],hoveringIndex:-1,inputHovering:!1,selectionWidth:0,calculatorWidth:0,collapseItemWidth:0,previousQuery:null,previousValue:void 0,selectedLabel:"",menuVisibleOnFocus:!1,isBeforeHide:!1}),C=R(-1),g=R(null),y=R(null),_=R(null),b=R(null),w=R(null),S=R(null),E=R(null),$=R(null),O=R(null),A=R(null),M=R(null),{wrapperRef:D,isFocused:U,handleFocus:j,handleBlur:W}=yf(w,{afterFocus(){e.automaticDropdown&&!x.value&&(x.value=!0,h.menuVisibleOnFocus=!0)},beforeBlur(Re){var it,St;return((it=_.value)==null?void 0:it.isFocusInsideContent(Re))||((St=b.value)==null?void 0:St.isFocusInsideContent(Re))},afterBlur(){x.value=!1,h.menuVisibleOnFocus=!1}}),L=R([]),P=R([]),x=R(!1),I=k(()=>e.disabled||(a==null?void 0:a.disabled)),H=k(()=>{const Re=P.value.length*e.itemHeight;return Re>e.height?e.height:Re}),G=k(()=>e.multiple?Pe(e.modelValue)&&e.modelValue.length>0:!v(e.modelValue)),J=k(()=>e.clearable&&!I.value&&h.inputHovering&&G.value),ee=k(()=>e.remote&&e.filterable?"":Nr),fe=k(()=>ee.value&&o.is("reverse",x.value)),Te=k(()=>(l==null?void 0:l.validateState)||""),oe=k(()=>Rv[Te.value]),ke=k(()=>e.remote?300:0),ae=k(()=>e.loading?e.loadingText||n("el.select.loading"):e.remote&&!h.inputValue&&L.value.length===0?!1:e.filterable&&h.inputValue&&L.value.length>0&&P.value.length===0?e.noMatchText||n("el.select.noMatch"):L.value.length===0?e.noDataText||n("el.select.noData"):null),Oe=Re=>{const it=St=>{if(e.filterable&&Xe(e.filterMethod)||e.filterable&&e.remote&&Xe(e.remoteMethod))return!0;const Ft=new RegExp($v(Re),"i");return Re?Ft.test(c(St)||""):!0};return e.loading?[]:[...h.createdOptions,...e.options].reduce((St,Ft)=>{const ko=p(Ft);if(Pe(ko)){const Lr=ko.filter(it);Lr.length>0&&St.push({label:c(Ft),type:"Group"},...Lr)}else(e.remote||it(Ft))&&St.push(Ft);return St},[])},we=()=>{L.value=Oe(""),P.value=Oe(h.inputValue)},ge=k(()=>{const Re=new Map;return L.value.forEach((it,St)=>{Re.set(Ht(f(it)),{option:it,index:St})}),Re}),q=k(()=>{const Re=new Map;return P.value.forEach((it,St)=>{Re.set(Ht(f(it)),{option:it,index:St})}),Re}),B=k(()=>P.value.every(Re=>d(Re))),z=hn(),Z=k(()=>z.value==="small"?"small":"default"),ue=()=>{var Re;C.value=((Re=g.value)==null?void 0:Re.offsetWidth)||200},se=()=>{if(!y.value)return 0;const Re=window.getComputedStyle(y.value);return Number.parseFloat(Re.gap||"6px")},me=k(()=>{const Re=se();return{maxWidth:`${M.value&&e.maxCollapseTags===1?h.selectionWidth-h.collapseItemWidth-Re:h.selectionWidth}px`}}),_e=k(()=>({maxWidth:`${h.selectionWidth}px`})),$e=k(()=>({width:`${Math.max(h.calculatorWidth,IY)}px`})),Ce=k(()=>Pe(e.modelValue)?e.modelValue.length===0&&!h.inputValue:e.filterable?!h.inputValue:!0),ce=k(()=>{var Re;const it=(Re=e.placeholder)!=null?Re:n("el.select.placeholder");return e.multiple||!G.value?it:h.selectedLabel}),de=k(()=>{var Re,it;return(it=(Re=_.value)==null?void 0:Re.popperRef)==null?void 0:it.contentRef}),xe=k(()=>{if(e.multiple){const Re=e.modelValue.length;if(e.modelValue.length>0&&q.value.has(e.modelValue[Re-1])){const{index:it}=q.value.get(e.modelValue[Re-1]);return it}}else if(e.modelValue&&q.value.has(e.modelValue)){const{index:Re}=q.value.get(e.modelValue);return Re}return-1}),he=k({get(){return x.value&&ae.value!==!1},set(Re){x.value=Re}}),He=k(()=>e.multiple?e.collapseTags?h.cachedOptions.slice(0,e.maxCollapseTags):h.cachedOptions:[]),et=k(()=>e.multiple?e.collapseTags?h.cachedOptions.slice(e.maxCollapseTags):[]:[]),{createNewOption:rt,removeNewOption:wt,selectNewOption:Ze,clearAllNewOption:st}=NY(e,h),{handleCompositionStart:Ee,handleCompositionUpdate:ye,handleCompositionEnd:ne}=RE(Re=>Wo(Re)),be=()=>{I.value||(h.menuVisibleOnFocus?h.menuVisibleOnFocus=!1:x.value=!x.value)},Fe=()=>{h.inputValue.length>0&&!x.value&&(x.value=!0),rt(h.inputValue),pe(h.inputValue)},vt=co(Fe,ke.value),pe=Re=>{h.previousQuery!==Re&&(h.previousQuery=Re,e.filterable&&Xe(e.filterMethod)?e.filterMethod(Re):e.filterable&&e.remote&&Xe(e.remoteMethod)&&e.remoteMethod(Re),e.defaultFirstOption&&(e.filterable||e.remote)&&P.value.length?We(Ye):We(ln))},Ye=()=>{const Re=P.value.filter(Ft=>!Ft.disabled&&Ft.type!=="Group"),it=Re.find(Ft=>Ft.created),St=Re[0];h.hoveringIndex=Jt(P.value,it||St)},_t=Re=>{Wn(e.modelValue,Re)||t(Yt,Re)},Kt=Re=>{t(ft,Re),_t(Re),h.previousValue=e.multiple?String(Re):Re},Jt=(Re=[],it)=>{if(!dt(it))return Re.indexOf(it);const St=e.valueKey;let Ft=-1;return Re.some((ko,Lr)=>un(ko,St)===un(it,St)?(Ft=Lr,!0):!1),Ft},Ht=Re=>dt(Re)?un(Re,e.valueKey):Re,At=()=>{ue()},Fn=()=>{h.selectionWidth=y.value.getBoundingClientRect().width},Ku=()=>{h.calculatorWidth=S.value.getBoundingClientRect().width},Uu=()=>{h.collapseItemWidth=M.value.getBoundingClientRect().width},ci=()=>{var Re,it;(it=(Re=_.value)==null?void 0:Re.updatePopper)==null||it.call(Re)},oa=()=>{var Re,it;(it=(Re=b.value)==null?void 0:Re.updatePopper)==null||it.call(Re)},qu=Re=>{if(e.multiple){let it=e.modelValue.slice();const St=Jt(it,f(Re));St>-1?(it=[...it.slice(0,St),...it.slice(St+1)],h.cachedOptions.splice(St,1),wt(Re)):(e.multipleLimit<=0||it.length{let St=e.modelValue.slice();const Ft=Jt(St,f(it));Ft>-1&&!I.value&&(St=[...e.modelValue.slice(0,Ft),...e.modelValue.slice(Ft+1)],h.cachedOptions.splice(Ft,1),Kt(St),t("remove-tag",f(it)),wt(it)),Re.stopPropagation(),Vl()},Vl=()=>{var Re;(Re=w.value)==null||Re.focus()},Yu=()=>{var Re;(Re=w.value)==null||Re.blur()},qf=()=>{h.inputValue.length>0?h.inputValue="":x.value=!1},Yf=Re=>VC(Re,it=>!h.cachedOptions.some(St=>f(St)===it&&d(St))),Gf=Re=>{if(e.multiple&&Re.code!==Ue.delete&&h.inputValue.length===0){Re.preventDefault();const it=e.modelValue.slice(),St=Yf(it);if(St<0)return;const Ft=it[St];it.splice(St,1);const ko=h.cachedOptions[St];h.cachedOptions.splice(St,1),wt(ko),Kt(it),t("remove-tag",Ft)}},Xf=()=>{let Re;Pe(e.modelValue)?Re=[]:Re=m.value,e.multiple?h.cachedOptions=[]:h.selectedLabel="",x.value=!1,Kt(Re),t("clear"),st(),Vl()},Le=(Re,it=void 0)=>{const St=P.value;if(!["forward","backward"].includes(Re)||I.value||St.length<=0||B.value)return;if(!x.value)return be();it===void 0&&(it=h.hoveringIndex);let Ft=-1;Re==="forward"?(Ft=it+1,Ft>=St.length&&(Ft=0)):Re==="backward"&&(Ft=it-1,(Ft<0||Ft>=St.length)&&(Ft=St.length-1));const ko=St[Ft];if(d(ko)||ko.type==="Group")return Le(Re,Ft);h.hoveringIndex=Ft,Ko(Ft)},ot=()=>{if(x.value)~h.hoveringIndex&&P.value[h.hoveringIndex]&&qu(P.value[h.hoveringIndex]);else return be()},Gt=Re=>{h.hoveringIndex=Re},ln=()=>{e.multiple?h.hoveringIndex=P.value.findIndex(Re=>e.modelValue.some(it=>Ht(it)===Ht(Re))):h.hoveringIndex=P.value.findIndex(Re=>Ht(Re)===Ht(e.modelValue))},Wo=Re=>{if(h.inputValue=Re.target.value,e.remote)vt();else return Fe()},ra=Re=>{if(x.value=!1,U.value){const it=new FocusEvent("focus",Re);W(it)}},Hl=()=>(h.isBeforeHide=!1,We(()=>{~xe.value&&Ko(h.hoveringIndex)})),Ko=Re=>{O.value.scrollToItem(Re)},So=Re=>{const it=Ht(Re);if(ge.value.has(it)){const{option:St}=ge.value.get(it);return St}return{[u.value.value]:Re,[u.value.label]:Re}},zl=()=>{if(e.multiple)if(e.modelValue.length>0){h.cachedOptions.length=0,h.previousValue=e.modelValue.toString();for(const Re of e.modelValue){const it=So(Re);h.cachedOptions.push(it)}}else h.cachedOptions=[],h.previousValue=void 0;else if(G.value){h.previousValue=e.modelValue;const Re=P.value,it=Re.findIndex(St=>Ht(f(St))===Ht(e.modelValue));~it?h.selectedLabel=c(Re[it]):h.selectedLabel=Ht(e.modelValue)}else h.selectedLabel="",h.previousValue=void 0;st(),ue()};return ve(x,Re=>{Re?pe(""):(h.inputValue="",h.previousQuery=null,h.isBeforeHide=!0,rt("")),t("visible-change",Re)}),ve(()=>e.modelValue,(Re,it)=>{var St;(!Re||e.multiple&&Re.toString()!==h.previousValue||!e.multiple&&Ht(Re)!==Ht(h.previousValue))&&zl(),!Wn(Re,it)&&e.validateEvent&&((St=l==null?void 0:l.validate)==null||St.call(l,"change").catch(Ft=>void 0))},{deep:!0}),ve(()=>e.options,()=>{const Re=w.value;(!Re||Re&&document.activeElement!==Re)&&zl()},{deep:!0,flush:"post"}),ve(()=>P.value,()=>O.value&&We(O.value.resetScrollTop)),Mn(()=>{h.isBeforeHide||we()}),Mn(()=>{const{valueKey:Re,options:it}=e,St=new Map;for(const Ft of it){const ko=f(Ft);let Lr=ko;if(dt(Lr)&&(Lr=un(ko,Re)),St.get(Lr))break;St.set(Lr,!0)}}),at(()=>{zl()}),Qt(g,At),Qt(y,Fn),Qt(S,Ku),Qt(O,ci),Qt(D,ci),Qt(A,oa),Qt(M,Uu),{inputId:s,collapseTagSize:Z,currentPlaceholder:ce,expanded:x,emptyText:ae,popupHeight:H,debounce:ke,allOptions:L,filteredOptions:P,iconComponent:ee,iconReverse:fe,tagStyle:me,collapseTagStyle:_e,inputStyle:$e,popperSize:C,dropdownMenuVisible:he,hasModelValue:G,shouldShowPlaceholder:Ce,selectDisabled:I,selectSize:z,showClearBtn:J,states:h,isFocused:U,nsSelect:o,nsInput:r,calculatorRef:S,inputRef:w,menuRef:O,tagMenuRef:A,tooltipRef:_,tagTooltipRef:b,selectRef:g,wrapperRef:D,selectionRef:y,prefixRef:E,suffixRef:$,collapseItemRef:M,popperRef:de,validateState:Te,validateIcon:oe,showTagList:He,collapseTagList:et,debouncedOnInputChange:vt,deleteTag:Uf,getLabel:c,getValue:f,getDisabled:d,getValueKey:Ht,handleBlur:W,handleClear:Xf,handleClickOutside:ra,handleDel:Gf,handleEsc:qf,handleFocus:j,focus:Vl,blur:Yu,handleMenuEnter:Hl,handleResize:At,resetSelectionWidth:Fn,resetCalculatorWidth:Ku,updateTooltip:ci,updateTagTooltip:oa,updateOptions:we,toggleMenu:be,scrollTo:Ko,onInput:Wo,onKeyboardNavigate:Le,onKeyboardSelect:ot,onSelect:qu,onHover:Gt,handleCompositionStart:Ee,handleCompositionEnd:ne,handleCompositionUpdate:ye}},AY=Y({name:"ElSelectV2",components:{ElSelectMenu:OY,ElTag:su,ElTooltip:Un,ElIcon:ze},directives:{ClickOutside:Yr},props:CY,emits:[ft,Yt,"remove-tag","clear","visible-change","focus","blur"],setup(e,{emit:t}){const n=k(()=>{const{modelValue:r,multiple:a}=e,l=a?[]:void 0;return Pe(r)?a?r:l:a?l:r}),o=MY(Et({...Cn(e),modelValue:n}),t);return yt(Eg,{props:Et({...Cn(e),height:o.popupHeight,modelValue:n}),tooltipRef:o.tooltipRef,onSelect:o.onSelect,onHover:o.onHover,onKeyboardNavigate:o.onKeyboardNavigate,onKeyboardSelect:o.onKeyboardSelect}),{...o,modelValue:n}}}),PY=["id","autocomplete","aria-expanded","aria-label","disabled","readonly","name"],RY=["textContent"],LY={key:1};function xY(e,t,n,o,r,a){const l=qe("el-tag"),s=qe("el-tooltip"),u=qe("el-icon"),c=qe("el-select-menu"),f=qs("click-outside");return tt((T(),V("div",{ref:"selectRef",class:N([e.nsSelect.b(),e.nsSelect.m(e.selectSize)]),onMouseenter:t[15]||(t[15]=d=>e.states.inputHovering=!0),onMouseleave:t[16]||(t[16]=d=>e.states.inputHovering=!1)},[K(s,{ref:"tooltipRef",visible:e.dropdownMenuVisible,teleported:e.teleported,"popper-class":[e.nsSelect.e("popper"),e.popperClass],"gpu-acceleration":!1,"stop-popper-mouse-event":!1,"popper-options":e.popperOptions,"fallback-placements":e.fallbackPlacements,effect:e.effect,placement:e.placement,pure:"",transition:`${e.nsSelect.namespace.value}-zoom-in-top`,trigger:"click",persistent:e.persistent,onBeforeShow:e.handleMenuEnter,onHide:t[14]||(t[14]=d=>e.states.isBeforeHide=!1)},{default:X(()=>[F("div",{ref:"wrapperRef",class:N([e.nsSelect.e("wrapper"),e.nsSelect.is("focused",e.isFocused),e.nsSelect.is("hovering",e.states.inputHovering),e.nsSelect.is("filterable",e.filterable),e.nsSelect.is("disabled",e.selectDisabled)]),onClick:t[13]||(t[13]=Qe((...d)=>e.toggleMenu&&e.toggleMenu(...d),["prevent","stop"]))},[e.$slots.prefix?(T(),V("div",{key:0,ref:"prefixRef",class:N(e.nsSelect.e("prefix"))},[ie(e.$slots,"prefix")],2)):te("v-if",!0),F("div",{ref:"selectionRef",class:N([e.nsSelect.e("selection"),e.nsSelect.is("near",e.multiple&&!e.$slots.prefix&&!!e.modelValue.length)])},[e.multiple?ie(e.$slots,"tag",{key:0},()=>[(T(!0),V(Ve,null,bt(e.showTagList,d=>(T(),V("div",{key:e.getValueKey(e.getValue(d)),class:N(e.nsSelect.e("selected-item"))},[K(l,{closable:!e.selectDisabled&&!e.getDisabled(d),size:e.collapseTagSize,type:e.tagType,effect:e.tagEffect,"disable-transitions":"",style:je(e.tagStyle),onClose:p=>e.deleteTag(p,d)},{default:X(()=>[F("span",{class:N(e.nsSelect.e("tags-text"))},[ie(e.$slots,"label",{label:e.getLabel(d),value:e.getValue(d)},()=>[Ge(le(e.getLabel(d)),1)])],2)]),_:2},1032,["closable","size","type","effect","style","onClose"])],2))),128)),e.collapseTags&&e.modelValue.length>e.maxCollapseTags?(T(),re(s,{key:0,ref:"tagTooltipRef",disabled:e.dropdownMenuVisible||!e.collapseTagsTooltip,"fallback-placements":["bottom","top","right","left"],effect:e.effect,placement:"bottom",teleported:e.teleported},{default:X(()=>[F("div",{ref:"collapseItemRef",class:N(e.nsSelect.e("selected-item"))},[K(l,{closable:!1,size:e.collapseTagSize,type:e.tagType,effect:e.tagEffect,style:je(e.collapseTagStyle),"disable-transitions":""},{default:X(()=>[F("span",{class:N(e.nsSelect.e("tags-text"))}," + "+le(e.modelValue.length-e.maxCollapseTags),3)]),_:1},8,["size","type","effect","style"])],2)]),content:X(()=>[F("div",{ref:"tagMenuRef",class:N(e.nsSelect.e("selection"))},[(T(!0),V(Ve,null,bt(e.collapseTagList,d=>(T(),V("div",{key:e.getValueKey(e.getValue(d)),class:N(e.nsSelect.e("selected-item"))},[K(l,{class:"in-tooltip",closable:!e.selectDisabled&&!e.getDisabled(d),size:e.collapseTagSize,type:e.tagType,effect:e.tagEffect,"disable-transitions":"",onClose:p=>e.deleteTag(p,d)},{default:X(()=>[F("span",{class:N(e.nsSelect.e("tags-text"))},[ie(e.$slots,"label",{label:e.getLabel(d),value:e.getValue(d)},()=>[Ge(le(e.getLabel(d)),1)])],2)]),_:2},1032,["closable","size","type","effect","onClose"])],2))),128))],2)]),_:3},8,["disabled","effect","teleported"])):te("v-if",!0)]):te("v-if",!0),e.selectDisabled?te("v-if",!0):(T(),V("div",{key:1,class:N([e.nsSelect.e("selected-item"),e.nsSelect.e("input-wrapper"),e.nsSelect.is("hidden",!e.filterable)])},[tt(F("input",{id:e.inputId,ref:"inputRef","onUpdate:modelValue":t[0]||(t[0]=d=>e.states.inputValue=d),style:je(e.inputStyle),autocomplete:e.autocomplete,"aria-autocomplete":"list","aria-haspopup":"listbox",autocapitalize:"off","aria-expanded":e.expanded,"aria-label":e.ariaLabel,class:N([e.nsSelect.e("input"),e.nsSelect.is(e.selectSize)]),disabled:e.selectDisabled,role:"combobox",readonly:!e.filterable,spellcheck:"false",type:"text",name:e.name,onFocus:t[1]||(t[1]=(...d)=>e.handleFocus&&e.handleFocus(...d)),onBlur:t[2]||(t[2]=(...d)=>e.handleBlur&&e.handleBlur(...d)),onInput:t[3]||(t[3]=(...d)=>e.onInput&&e.onInput(...d)),onCompositionstart:t[4]||(t[4]=(...d)=>e.handleCompositionStart&&e.handleCompositionStart(...d)),onCompositionupdate:t[5]||(t[5]=(...d)=>e.handleCompositionUpdate&&e.handleCompositionUpdate(...d)),onCompositionend:t[6]||(t[6]=(...d)=>e.handleCompositionEnd&&e.handleCompositionEnd(...d)),onKeydown:[t[7]||(t[7]=Pt(Qe(d=>e.onKeyboardNavigate("backward"),["stop","prevent"]),["up"])),t[8]||(t[8]=Pt(Qe(d=>e.onKeyboardNavigate("forward"),["stop","prevent"]),["down"])),t[9]||(t[9]=Pt(Qe((...d)=>e.onKeyboardSelect&&e.onKeyboardSelect(...d),["stop","prevent"]),["enter"])),t[10]||(t[10]=Pt(Qe((...d)=>e.handleEsc&&e.handleEsc(...d),["stop","prevent"]),["esc"])),t[11]||(t[11]=Pt(Qe((...d)=>e.handleDel&&e.handleDel(...d),["stop"]),["delete"]))],onClick:t[12]||(t[12]=Qe((...d)=>e.toggleMenu&&e.toggleMenu(...d),["stop"]))},null,46,PY),[[yl,e.states.inputValue]]),e.filterable?(T(),V("span",{key:0,ref:"calculatorRef","aria-hidden":"true",class:N(e.nsSelect.e("input-calculator")),textContent:le(e.states.inputValue)},null,10,RY)):te("v-if",!0)],2)),e.shouldShowPlaceholder?(T(),V("div",{key:2,class:N([e.nsSelect.e("selected-item"),e.nsSelect.e("placeholder"),e.nsSelect.is("transparent",!e.hasModelValue||e.expanded&&!e.states.inputValue)])},[e.hasModelValue?ie(e.$slots,"label",{key:0,label:e.currentPlaceholder,value:e.modelValue},()=>[F("span",null,le(e.currentPlaceholder),1)]):(T(),V("span",LY,le(e.currentPlaceholder),1))],2)):te("v-if",!0)],2),F("div",{ref:"suffixRef",class:N(e.nsSelect.e("suffix"))},[e.iconComponent?tt((T(),re(u,{key:0,class:N([e.nsSelect.e("caret"),e.nsInput.e("icon"),e.iconReverse])},{default:X(()=>[(T(),re(pt(e.iconComponent)))]),_:1},8,["class"])),[[kt,!e.showClearBtn]]):te("v-if",!0),e.showClearBtn&&e.clearIcon?(T(),re(u,{key:1,class:N([e.nsSelect.e("caret"),e.nsInput.e("icon")]),onClick:Qe(e.handleClear,["prevent","stop"])},{default:X(()=>[(T(),re(pt(e.clearIcon)))]),_:1},8,["class","onClick"])):te("v-if",!0),e.validateState&&e.validateIcon?(T(),re(u,{key:2,class:N([e.nsInput.e("icon"),e.nsInput.e("validateIcon")])},{default:X(()=>[(T(),re(pt(e.validateIcon)))]),_:1},8,["class"])):te("v-if",!0)],2)],2)]),content:X(()=>[K(c,{ref:"menuRef",data:e.filteredOptions,width:e.popperSize,"hovering-index":e.states.hoveringIndex,"scrollbar-always-on":e.scrollbarAlwaysOn},Sr({default:X(d=>[ie(e.$slots,"default",vr(bl(d)))]),_:2},[e.$slots.header?{name:"header",fn:X(()=>[F("div",{class:N(e.nsSelect.be("dropdown","header"))},[ie(e.$slots,"header")],2)])}:void 0,e.$slots.loading&&e.loading?{name:"loading",fn:X(()=>[F("div",{class:N(e.nsSelect.be("dropdown","loading"))},[ie(e.$slots,"loading")],2)])}:e.loading||e.filteredOptions.length===0?{name:"empty",fn:X(()=>[F("div",{class:N(e.nsSelect.be("dropdown","empty"))},[ie(e.$slots,"empty",{},()=>[F("span",null,le(e.emptyText),1)])],2)])}:void 0,e.$slots.footer?{name:"footer",fn:X(()=>[F("div",{class:N(e.nsSelect.be("dropdown","footer"))},[ie(e.$slots,"footer")],2)])}:void 0]),1032,["data","width","hovering-index","scrollbar-always-on"])]),_:3},8,["visible","teleported","popper-class","popper-options","fallback-placements","effect","placement","transition","persistent","onBeforeShow"])],34)),[[f,e.handleClickOutside,e.popperRef]])}var Wc=Ie(AY,[["render",xY],["__file","select.vue"]]);Wc.install=e=>{e.component(Wc.name,Wc)};const DY=Wc,FY=DY,BY=Ne({animated:{type:Boolean,default:!1},count:{type:Number,default:1},rows:{type:Number,default:3},loading:{type:Boolean,default:!0},throttle:{type:Number}}),VY=Ne({variant:{type:String,values:["circle","rect","h1","h3","text","caption","p","image","button"],default:"text"}}),HY=Y({name:"ElSkeletonItem"}),zY=Y({...HY,props:VY,setup(e){const t=Se("skeleton");return(n,o)=>(T(),V("div",{class:N([i(t).e("item"),i(t).e(n.variant)])},[n.variant==="image"?(T(),re(i(R4),{key:0})):te("v-if",!0)],2))}});var Nd=Ie(zY,[["__file","skeleton-item.vue"]]);const jY=Y({name:"ElSkeleton"}),WY=Y({...jY,props:BY,setup(e,{expose:t}){const n=e,o=Se("skeleton"),r=$D(Lt(n,"loading"),n.throttle);return t({uiLoading:r}),(a,l)=>i(r)?(T(),V("div",mt({key:0,class:[i(o).b(),i(o).is("animated",a.animated)]},a.$attrs),[(T(!0),V(Ve,null,bt(a.count,s=>(T(),V(Ve,{key:s},[a.loading?ie(a.$slots,"template",{key:s},()=>[K(Nd,{class:N(i(o).is("first")),variant:"p"},null,8,["class"]),(T(!0),V(Ve,null,bt(a.rows,u=>(T(),re(Nd,{key:u,class:N([i(o).e("paragraph"),i(o).is("last",u===a.rows&&a.rows>1)]),variant:"p"},null,8,["class"]))),128))]):te("v-if",!0)],64))),128))],16)):ie(a.$slots,"default",vr(mt({key:1},a.$attrs)))}});var KY=Ie(WY,[["__file","skeleton.vue"]]);const UY=ut(KY,{SkeletonItem:Nd}),qY=tn(Nd),t2=Symbol("sliderContextKey"),YY=Ne({modelValue:{type:Q([Number,Array]),default:0},id:{type:String,default:void 0},min:{type:Number,default:0},max:{type:Number,default:100},step:{type:Number,default:1},showInput:Boolean,showInputControls:{type:Boolean,default:!0},size:gn,inputSize:gn,showStops:Boolean,showTooltip:{type:Boolean,default:!0},formatTooltip:{type:Q(Function),default:void 0},disabled:Boolean,range:Boolean,vertical:Boolean,height:String,debounce:{type:Number,default:300},label:{type:String,default:void 0},rangeStartLabel:{type:String,default:void 0},rangeEndLabel:{type:String,default:void 0},formatValueText:{type:Q(Function),default:void 0},tooltipClass:{type:String,default:void 0},placement:{type:String,values:Dl,default:"top"},marks:{type:Q(Object)},validateEvent:{type:Boolean,default:!0},...An(["ariaLabel"])}),Tp=e=>Je(e)||Pe(e)&&e.every(Je),GY={[ft]:Tp,[Zn]:Tp,[Yt]:Tp},XY=(e,t,n)=>{const o=R();return at(async()=>{e.range?(Array.isArray(e.modelValue)?(t.firstValue=Math.max(e.min,e.modelValue[0]),t.secondValue=Math.min(e.max,e.modelValue[1])):(t.firstValue=e.min,t.secondValue=e.max),t.oldValue=[t.firstValue,t.secondValue]):(typeof e.modelValue!="number"||Number.isNaN(e.modelValue)?t.firstValue=e.min:t.firstValue=Math.min(e.max,Math.max(e.min,e.modelValue)),t.oldValue=t.firstValue),qt(window,"resize",n),await We(),n()}),{sliderWrapper:o}},JY=e=>k(()=>e.marks?Object.keys(e.marks).map(Number.parseFloat).sort((n,o)=>n-o).filter(n=>n<=e.max&&n>=e.min).map(n=>({point:n,position:(n-e.min)*100/(e.max-e.min),mark:e.marks[n]})):[]),ZY=(e,t,n)=>{const{form:o,formItem:r}=qn(),a=Ut(),l=R(),s=R(),u={firstButton:l,secondButton:s},c=k(()=>e.disabled||(o==null?void 0:o.disabled)||!1),f=k(()=>Math.min(t.firstValue,t.secondValue)),d=k(()=>Math.max(t.firstValue,t.secondValue)),p=k(()=>e.range?`${100*(d.value-f.value)/(e.max-e.min)}%`:`${100*(t.firstValue-e.min)/(e.max-e.min)}%`),m=k(()=>e.range?`${100*(f.value-e.min)/(e.max-e.min)}%`:"0%"),v=k(()=>e.vertical?{height:e.height}:{}),h=k(()=>e.vertical?{height:p.value,bottom:m.value}:{width:p.value,left:m.value}),C=()=>{a.value&&(t.sliderSize=a.value[`client${e.vertical?"Height":"Width"}`])},g=M=>{const D=e.min+M*(e.max-e.min)/100;if(!e.range)return l;let U;return Math.abs(f.value-D)t.secondValue?"firstButton":"secondButton",u[U]},y=M=>{const D=g(M);return D.value.setPosition(M),D},_=M=>{t.firstValue=M,w(e.range?[f.value,d.value]:M)},b=M=>{t.secondValue=M,e.range&&w([f.value,d.value])},w=M=>{n(ft,M),n(Zn,M)},S=async()=>{await We(),n(Yt,e.range?[f.value,d.value]:e.modelValue)},E=M=>{var D,U,j,W,L,P;if(c.value||t.dragging)return;C();let x=0;if(e.vertical){const I=(j=(U=(D=M.touches)==null?void 0:D.item(0))==null?void 0:U.clientY)!=null?j:M.clientY;x=(a.value.getBoundingClientRect().bottom-I)/t.sliderSize*100}else{const I=(P=(L=(W=M.touches)==null?void 0:W.item(0))==null?void 0:L.clientX)!=null?P:M.clientX,H=a.value.getBoundingClientRect().left;x=(I-H)/t.sliderSize*100}if(!(x<0||x>100))return y(x)};return{elFormItem:r,slider:a,firstButton:l,secondButton:s,sliderDisabled:c,minValue:f,maxValue:d,runwayStyle:v,barStyle:h,resetSize:C,setPosition:y,emitChange:S,onSliderWrapperPrevent:M=>{var D,U;((D=u.firstButton.value)!=null&&D.dragging||(U=u.secondButton.value)!=null&&U.dragging)&&M.preventDefault()},onSliderClick:M=>{E(M)&&S()},onSliderDown:async M=>{const D=E(M);D&&(await We(),D.value.onButtonDown(M))},setFirstValue:_,setSecondValue:b}},{left:QY,down:eG,right:tG,up:nG,home:oG,end:rG,pageUp:aG,pageDown:lG}=Ue,sG=(e,t,n)=>{const o=R(),r=R(!1),a=k(()=>t.value instanceof Function),l=k(()=>a.value&&t.value(e.modelValue)||e.modelValue),s=co(()=>{n.value&&(r.value=!0)},50),u=co(()=>{n.value&&(r.value=!1)},50);return{tooltip:o,tooltipVisible:r,formatValue:l,displayTooltip:s,hideTooltip:u}},iG=(e,t,n)=>{const{disabled:o,min:r,max:a,step:l,showTooltip:s,precision:u,sliderSize:c,formatTooltip:f,emitChange:d,resetSize:p,updateDragging:m}=De(t2),{tooltip:v,tooltipVisible:h,formatValue:C,displayTooltip:g,hideTooltip:y}=sG(e,f,s),_=R(),b=k(()=>`${(e.modelValue-r.value)/(a.value-r.value)*100}%`),w=k(()=>e.vertical?{bottom:b.value}:{left:b.value}),S=()=>{t.hovering=!0,g()},E=()=>{t.hovering=!1,t.dragging||y()},$=J=>{o.value||(J.preventDefault(),x(J),window.addEventListener("mousemove",I),window.addEventListener("touchmove",I),window.addEventListener("mouseup",H),window.addEventListener("touchend",H),window.addEventListener("contextmenu",H),_.value.focus())},O=J=>{o.value||(t.newPosition=Number.parseFloat(b.value)+J/(a.value-r.value)*100,G(t.newPosition),d())},A=()=>{O(-l.value)},M=()=>{O(l.value)},D=()=>{O(-l.value*4)},U=()=>{O(l.value*4)},j=()=>{o.value||(G(0),d())},W=()=>{o.value||(G(100),d())},L=J=>{let ee=!0;[QY,eG].includes(J.key)?A():[tG,nG].includes(J.key)?M():J.key===oG?j():J.key===rG?W():J.key===lG?D():J.key===aG?U():ee=!1,ee&&J.preventDefault()},P=J=>{let ee,fe;return J.type.startsWith("touch")?(fe=J.touches[0].clientY,ee=J.touches[0].clientX):(fe=J.clientY,ee=J.clientX),{clientX:ee,clientY:fe}},x=J=>{t.dragging=!0,t.isClick=!0;const{clientX:ee,clientY:fe}=P(J);e.vertical?t.startY=fe:t.startX=ee,t.startPosition=Number.parseFloat(b.value),t.newPosition=t.startPosition},I=J=>{if(t.dragging){t.isClick=!1,g(),p();let ee;const{clientX:fe,clientY:Te}=P(J);e.vertical?(t.currentY=Te,ee=(t.startY-t.currentY)/c.value*100):(t.currentX=fe,ee=(t.currentX-t.startX)/c.value*100),t.newPosition=t.startPosition+ee,G(t.newPosition)}},H=()=>{t.dragging&&(setTimeout(()=>{t.dragging=!1,t.hovering||y(),t.isClick||G(t.newPosition),d()},0),window.removeEventListener("mousemove",I),window.removeEventListener("touchmove",I),window.removeEventListener("mouseup",H),window.removeEventListener("touchend",H),window.removeEventListener("contextmenu",H))},G=async J=>{if(J===null||Number.isNaN(+J))return;J<0?J=0:J>100&&(J=100);const ee=100/((a.value-r.value)/l.value);let Te=Math.round(J/ee)*ee*(a.value-r.value)*.01+r.value;Te=Number.parseFloat(Te.toFixed(u.value)),Te!==e.modelValue&&n(ft,Te),!t.dragging&&e.modelValue!==t.oldValue&&(t.oldValue=e.modelValue),await We(),t.dragging&&g(),v.value.updatePopper()};return ve(()=>t.dragging,J=>{m(J)}),{disabled:o,button:_,tooltip:v,tooltipVisible:h,showTooltip:s,wrapperStyle:w,formatValue:C,handleMouseEnter:S,handleMouseLeave:E,onButtonDown:$,onKeyDown:L,setPosition:G}},uG=(e,t,n,o)=>({stops:k(()=>{if(!e.showStops||e.min>e.max)return[];if(e.step===0)return[];const l=(e.max-e.min)/e.step,s=100*e.step/(e.max-e.min),u=Array.from({length:l-1}).map((c,f)=>(f+1)*s);return e.range?u.filter(c=>c<100*(n.value-e.min)/(e.max-e.min)||c>100*(o.value-e.min)/(e.max-e.min)):u.filter(c=>c>100*(t.firstValue-e.min)/(e.max-e.min))}),getStopStyle:l=>e.vertical?{bottom:`${l}%`}:{left:`${l}%`}}),cG=(e,t,n,o,r,a)=>{const l=c=>{r(ft,c),r(Zn,c)},s=()=>e.range?![n.value,o.value].every((c,f)=>c===t.oldValue[f]):e.modelValue!==t.oldValue,u=()=>{var c,f;e.min>e.max&&vn("Slider","min should not be greater than max.");const d=e.modelValue;e.range&&Array.isArray(d)?d[1]e.max?l([e.max,e.max]):d[0]e.max?l([d[0],e.max]):(t.firstValue=d[0],t.secondValue=d[1],s()&&(e.validateEvent&&((c=a==null?void 0:a.validate)==null||c.call(a,"change").catch(p=>void 0)),t.oldValue=d.slice())):!e.range&&typeof d=="number"&&!Number.isNaN(d)&&(de.max?l(e.max):(t.firstValue=d,s()&&(e.validateEvent&&((f=a==null?void 0:a.validate)==null||f.call(a,"change").catch(p=>void 0)),t.oldValue=d)))};u(),ve(()=>t.dragging,c=>{c||u()}),ve(()=>e.modelValue,(c,f)=>{t.dragging||Array.isArray(c)&&Array.isArray(f)&&c.every((d,p)=>d===f[p])&&t.firstValue===c[0]&&t.secondValue===c[1]||u()},{deep:!0}),ve(()=>[e.min,e.max],()=>{u()})},dG=Ne({modelValue:{type:Number,default:0},vertical:Boolean,tooltipClass:String,placement:{type:String,values:Dl,default:"top"}}),fG={[ft]:e=>Je(e)},pG=["tabindex"],hG=Y({name:"ElSliderButton"}),mG=Y({...hG,props:dG,emits:fG,setup(e,{expose:t,emit:n}){const o=e,r=Se("slider"),a=Et({hovering:!1,dragging:!1,isClick:!1,startX:0,currentX:0,startY:0,currentY:0,startPosition:0,newPosition:0,oldValue:o.modelValue}),{disabled:l,button:s,tooltip:u,showTooltip:c,tooltipVisible:f,wrapperStyle:d,formatValue:p,handleMouseEnter:m,handleMouseLeave:v,onButtonDown:h,onKeyDown:C,setPosition:g}=iG(o,a,n),{hovering:y,dragging:_}=Cn(a);return t({onButtonDown:h,onKeyDown:C,setPosition:g,hovering:y,dragging:_}),(b,w)=>(T(),V("div",{ref_key:"button",ref:s,class:N([i(r).e("button-wrapper"),{hover:i(y),dragging:i(_)}]),style:je(i(d)),tabindex:i(l)?-1:0,onMouseenter:w[0]||(w[0]=(...S)=>i(m)&&i(m)(...S)),onMouseleave:w[1]||(w[1]=(...S)=>i(v)&&i(v)(...S)),onMousedown:w[2]||(w[2]=(...S)=>i(h)&&i(h)(...S)),onTouchstart:w[3]||(w[3]=(...S)=>i(h)&&i(h)(...S)),onFocus:w[4]||(w[4]=(...S)=>i(m)&&i(m)(...S)),onBlur:w[5]||(w[5]=(...S)=>i(v)&&i(v)(...S)),onKeydown:w[6]||(w[6]=(...S)=>i(C)&&i(C)(...S))},[K(i(Un),{ref_key:"tooltip",ref:u,visible:i(f),placement:b.placement,"fallback-placements":["top","bottom","right","left"],"stop-popper-mouse-event":!1,"popper-class":b.tooltipClass,disabled:!i(c),persistent:""},{content:X(()=>[F("span",null,le(i(p)),1)]),default:X(()=>[F("div",{class:N([i(r).e("button"),{hover:i(y),dragging:i(_)}])},null,2)]),_:1},8,["visible","placement","popper-class","disabled"])],46,pG))}});var f1=Ie(mG,[["__file","button.vue"]]);const vG=Ne({mark:{type:Q([String,Object]),default:void 0}});var gG=Y({name:"ElSliderMarker",props:vG,setup(e){const t=Se("slider"),n=k(()=>nt(e.mark)?e.mark:e.mark.label),o=k(()=>nt(e.mark)?void 0:e.mark.style);return()=>Ke("div",{class:t.e("marks-text"),style:o.value},n.value)}});const bG=["id","role","aria-label","aria-labelledby"],yG={key:1},wG=Y({name:"ElSlider"}),_G=Y({...wG,props:YY,emits:GY,setup(e,{expose:t,emit:n}){const o=e,r=Se("slider"),{t:a}=$t(),l=Et({firstValue:0,secondValue:0,oldValue:0,dragging:!1,sliderSize:1}),{elFormItem:s,slider:u,firstButton:c,secondButton:f,sliderDisabled:d,minValue:p,maxValue:m,runwayStyle:v,barStyle:h,resetSize:C,emitChange:g,onSliderWrapperPrevent:y,onSliderClick:_,onSliderDown:b,setFirstValue:w,setSecondValue:S}=ZY(o,l,n),{stops:E,getStopStyle:$}=uG(o,l,p,m),{inputId:O,isLabeledByFormItem:A}=cr(o,{formItemContext:s}),M=hn(),D=k(()=>o.inputSize||M.value),U=k(()=>o.label||o.ariaLabel||a("el.slider.defaultLabel",{min:o.min,max:o.max})),j=k(()=>o.range?o.rangeStartLabel||a("el.slider.defaultRangeStartLabel"):U.value),W=k(()=>o.formatValueText?o.formatValueText(J.value):`${J.value}`),L=k(()=>o.rangeEndLabel||a("el.slider.defaultRangeEndLabel")),P=k(()=>o.formatValueText?o.formatValueText(ee.value):`${ee.value}`),x=k(()=>[r.b(),r.m(M.value),r.is("vertical",o.vertical),{[r.m("with-input")]:o.showInput}]),I=JY(o);cG(o,l,p,m,n,s);const H=k(()=>{const oe=[o.min,o.max,o.step].map(ke=>{const ae=`${ke}`.split(".")[1];return ae?ae.length:0});return Math.max.apply(null,oe)}),{sliderWrapper:G}=XY(o,l,C),{firstValue:J,secondValue:ee,sliderSize:fe}=Cn(l),Te=oe=>{l.dragging=oe};return yt(t2,{...Cn(o),sliderSize:fe,disabled:d,precision:H,emitChange:g,resetSize:C,updateDragging:Te}),wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-slider",ref:"https://element-plus.org/en-US/component/slider.html"},k(()=>!!o.label)),t({onSliderClick:_}),(oe,ke)=>{var ae,Oe;return T(),V("div",{id:oe.range?i(O):void 0,ref_key:"sliderWrapper",ref:G,class:N(i(x)),role:oe.range?"group":void 0,"aria-label":oe.range&&!i(A)?i(U):void 0,"aria-labelledby":oe.range&&i(A)?(ae=i(s))==null?void 0:ae.labelId:void 0,onTouchstart:ke[2]||(ke[2]=(...we)=>i(y)&&i(y)(...we)),onTouchmove:ke[3]||(ke[3]=(...we)=>i(y)&&i(y)(...we))},[F("div",{ref_key:"slider",ref:u,class:N([i(r).e("runway"),{"show-input":oe.showInput&&!oe.range},i(r).is("disabled",i(d))]),style:je(i(v)),onMousedown:ke[0]||(ke[0]=(...we)=>i(b)&&i(b)(...we)),onTouchstart:ke[1]||(ke[1]=(...we)=>i(b)&&i(b)(...we))},[F("div",{class:N(i(r).e("bar")),style:je(i(h))},null,6),K(f1,{id:oe.range?void 0:i(O),ref_key:"firstButton",ref:c,"model-value":i(J),vertical:oe.vertical,"tooltip-class":oe.tooltipClass,placement:oe.placement,role:"slider","aria-label":oe.range||!i(A)?i(j):void 0,"aria-labelledby":!oe.range&&i(A)?(Oe=i(s))==null?void 0:Oe.labelId:void 0,"aria-valuemin":oe.min,"aria-valuemax":oe.range?i(ee):oe.max,"aria-valuenow":i(J),"aria-valuetext":i(W),"aria-orientation":oe.vertical?"vertical":"horizontal","aria-disabled":i(d),"onUpdate:modelValue":i(w)},null,8,["id","model-value","vertical","tooltip-class","placement","aria-label","aria-labelledby","aria-valuemin","aria-valuemax","aria-valuenow","aria-valuetext","aria-orientation","aria-disabled","onUpdate:modelValue"]),oe.range?(T(),re(f1,{key:0,ref_key:"secondButton",ref:f,"model-value":i(ee),vertical:oe.vertical,"tooltip-class":oe.tooltipClass,placement:oe.placement,role:"slider","aria-label":i(L),"aria-valuemin":i(J),"aria-valuemax":oe.max,"aria-valuenow":i(ee),"aria-valuetext":i(P),"aria-orientation":oe.vertical?"vertical":"horizontal","aria-disabled":i(d),"onUpdate:modelValue":i(S)},null,8,["model-value","vertical","tooltip-class","placement","aria-label","aria-valuemin","aria-valuemax","aria-valuenow","aria-valuetext","aria-orientation","aria-disabled","onUpdate:modelValue"])):te("v-if",!0),oe.showStops?(T(),V("div",yG,[(T(!0),V(Ve,null,bt(i(E),(we,ge)=>(T(),V("div",{key:ge,class:N(i(r).e("stop")),style:je(i($)(we))},null,6))),128))])):te("v-if",!0),i(I).length>0?(T(),V(Ve,{key:2},[F("div",null,[(T(!0),V(Ve,null,bt(i(I),(we,ge)=>(T(),V("div",{key:ge,style:je(i($)(we.position)),class:N([i(r).e("stop"),i(r).e("marks-stop")])},null,6))),128))]),F("div",{class:N(i(r).e("marks"))},[(T(!0),V(Ve,null,bt(i(I),(we,ge)=>(T(),re(i(gG),{key:ge,mark:we.mark,style:je(i($)(we.position))},null,8,["mark","style"]))),128))],2)],64)):te("v-if",!0)],38),oe.showInput&&!oe.range?(T(),re(i($E),{key:0,ref:"input","model-value":i(J),class:N(i(r).e("input")),step:oe.step,disabled:i(d),controls:oe.showInputControls,min:oe.min,max:oe.max,debounce:oe.debounce,size:i(D),"onUpdate:modelValue":i(w),onChange:i(g)},null,8,["model-value","class","step","disabled","controls","min","max","debounce","size","onUpdate:modelValue","onChange"])):te("v-if",!0)],42,bG)}}});var CG=Ie(_G,[["__file","slider.vue"]]);const SG=ut(CG),kG=Ne({prefixCls:{type:String}}),p1=Y({name:"ElSpaceItem",props:kG,setup(e,{slots:t}){const n=Se("space"),o=k(()=>`${e.prefixCls||n.b()}__item`);return()=>Ke("div",{class:o.value},ie(t,"default"))}}),h1={small:8,default:12,large:16};function EG(e){const t=Se("space"),n=k(()=>[t.b(),t.m(e.direction),e.class]),o=R(0),r=R(0),a=k(()=>{const s=e.wrap||e.fill?{flexWrap:"wrap"}:{},u={alignItems:e.alignment},c={rowGap:`${r.value}px`,columnGap:`${o.value}px`};return[s,u,c,e.style]}),l=k(()=>e.fill?{flexGrow:1,minWidth:`${e.fillRatio}%`}:{});return Mn(()=>{const{size:s="small",wrap:u,direction:c,fill:f}=e;if(Pe(s)){const[d=0,p=0]=s;o.value=d,r.value=p}else{let d;Je(s)?d=s:d=h1[s||"small"]||h1.small,(u||f)&&c==="horizontal"?o.value=r.value=d:c==="horizontal"?(o.value=d,r.value=0):(r.value=d,o.value=0)}}),{classes:n,containerStyle:a,itemStyle:l}}const TG=Ne({direction:{type:String,values:["horizontal","vertical"],default:"horizontal"},class:{type:Q([String,Object,Array]),default:""},style:{type:Q([String,Array,Object]),default:""},alignment:{type:Q(String),default:"center"},prefixCls:{type:String},spacer:{type:Q([Object,String,Number,Array]),default:null,validator:e=>Wt(e)||Je(e)||nt(e)},wrap:Boolean,fill:Boolean,fillRatio:{type:Number,default:100},size:{type:[String,Array,Number],values:Ir,validator:e=>Je(e)||Pe(e)&&e.length===2&&e.every(Je)}}),$G=Y({name:"ElSpace",props:TG,setup(e,{slots:t}){const{classes:n,containerStyle:o,itemStyle:r}=EG(e);function a(l,s="",u=[]){const{prefixCls:c}=e;return l.forEach((f,d)=>{gh(f)?Pe(f.children)&&f.children.forEach((p,m)=>{gh(p)&&Pe(p.children)?a(p.children,`${s+m}-`,u):u.push(K(p1,{style:r.value,prefixCls:c,key:`nested-${s+m}`},{default:()=>[p]},Oo.PROPS|Oo.STYLE,["style","prefixCls"]))}):d3(f)&&u.push(K(p1,{style:r.value,prefixCls:c,key:`LoopKey${s+d}`},{default:()=>[f]},Oo.PROPS|Oo.STYLE,["style","prefixCls"]))}),u}return()=>{var l;const{spacer:s,direction:u}=e,c=ie(t,"default",{key:0},()=>[]);if(((l=c.children)!=null?l:[]).length===0)return null;if(Pe(c.children)){let f=a(c.children);if(s){const d=f.length-1;f=f.reduce((p,m,v)=>{const h=[...p,m];return v!==d&&h.push(K("span",{style:[r.value,u==="vertical"?"width: 100%":null],key:v},[Wt(s)?s:Ge(s,Oo.TEXT)],Oo.STYLE)),h},[])}return K("div",{class:n.value,style:o.value},f,Oo.STYLE|Oo.CLASS)}return c.children}}}),OG=ut($G),NG=Ne({decimalSeparator:{type:String,default:"."},groupSeparator:{type:String,default:","},precision:{type:Number,default:0},formatter:Function,value:{type:Q([Number,Object]),default:0},prefix:String,suffix:String,title:String,valueStyle:{type:Q([String,Object,Array])}}),IG=Y({name:"ElStatistic"}),MG=Y({...IG,props:NG,setup(e,{expose:t}){const n=e,o=Se("statistic"),r=k(()=>{const{value:a,formatter:l,precision:s,decimalSeparator:u,groupSeparator:c}=n;if(Xe(l))return l(a);if(!Je(a))return a;let[f,d=""]=String(a).split(".");return d=d.padEnd(s,"0").slice(0,s>0?s:0),f=f.replace(/\B(?=(\d{3})+(?!\d))/g,c),[f,d].join(d?u:"")});return t({displayValue:r}),(a,l)=>(T(),V("div",{class:N(i(o).b())},[a.$slots.title||a.title?(T(),V("div",{key:0,class:N(i(o).e("head"))},[ie(a.$slots,"title",{},()=>[Ge(le(a.title),1)])],2)):te("v-if",!0),F("div",{class:N(i(o).e("content"))},[a.$slots.prefix||a.prefix?(T(),V("div",{key:0,class:N(i(o).e("prefix"))},[ie(a.$slots,"prefix",{},()=>[F("span",null,le(a.prefix),1)])],2)):te("v-if",!0),F("span",{class:N(i(o).e("number")),style:je(a.valueStyle)},le(i(r)),7),a.$slots.suffix||a.suffix?(T(),V("div",{key:1,class:N(i(o).e("suffix"))},[ie(a.$slots,"suffix",{},()=>[F("span",null,le(a.suffix),1)])],2)):te("v-if",!0)],2)],2))}});var AG=Ie(MG,[["__file","statistic.vue"]]);const n2=ut(AG),PG=Ne({format:{type:String,default:"HH:mm:ss"},prefix:String,suffix:String,title:String,value:{type:Q([Number,Object]),default:0},valueStyle:{type:Q([String,Object,Array])}}),RG={finish:()=>!0,[Yt]:e=>Je(e)},LG=[["Y",1e3*60*60*24*365],["M",1e3*60*60*24*30],["D",1e3*60*60*24],["H",1e3*60*60],["m",1e3*60],["s",1e3],["S",1]],m1=e=>Je(e)?new Date(e).getTime():e.valueOf(),v1=(e,t)=>{let n=e;const o=/\[([^\]]*)]/g;return LG.reduce((a,[l,s])=>{const u=new RegExp(`${l}+(?![^\\[\\]]*\\])`,"g");if(u.test(a)){const c=Math.floor(n/s);return n-=c*s,a.replace(u,f=>String(c).padStart(f.length,"0"))}return a},t).replace(o,"$1")},xG=Y({name:"ElCountdown"}),DG=Y({...xG,props:PG,emits:RG,setup(e,{expose:t,emit:n}){const o=e;let r;const a=R(0),l=k(()=>v1(a.value,o.format)),s=f=>v1(f,o.format),u=()=>{r&&(kl(r),r=void 0)},c=()=>{const f=m1(o.value),d=()=>{let p=f-Date.now();n("change",p),p<=0?(p=0,u(),n("finish")):r=Ma(d),a.value=p};r=Ma(d)};return at(()=>{a.value=m1(o.value)-Date.now(),ve(()=>[o.value,o.format],()=>{u(),c()},{immediate:!0})}),zt(()=>{u()}),t({displayValue:l}),(f,d)=>(T(),re(i(n2),{value:a.value,title:f.title,prefix:f.prefix,suffix:f.suffix,"value-style":f.valueStyle,formatter:s},Sr({_:2},[bt(f.$slots,(p,m)=>({name:m,fn:X(()=>[ie(f.$slots,m)])}))]),1032,["value","title","prefix","suffix","value-style"]))}});var FG=Ie(DG,[["__file","countdown.vue"]]);const BG=ut(FG),VG=Ne({space:{type:[Number,String],default:""},active:{type:Number,default:0},direction:{type:String,default:"horizontal",values:["horizontal","vertical"]},alignCenter:{type:Boolean},simple:{type:Boolean},finishStatus:{type:String,values:["wait","process","finish","error","success"],default:"finish"},processStatus:{type:String,values:["wait","process","finish","error","success"],default:"process"}}),HG={[Yt]:(e,t)=>[e,t].every(Je)},zG=Y({name:"ElSteps"}),jG=Y({...zG,props:VG,emits:HG,setup(e,{emit:t}){const n=e,o=Se("steps"),{children:r,addChild:a,removeChild:l}=tg(lt(),"ElStep");return ve(r,()=>{r.value.forEach((s,u)=>{s.setIndex(u)})}),yt("ElSteps",{props:n,steps:r,addStep:a,removeStep:l}),ve(()=>n.active,(s,u)=>{t(Yt,s,u)}),(s,u)=>(T(),V("div",{class:N([i(o).b(),i(o).m(s.simple?"simple":s.direction)])},[ie(s.$slots,"default")],2))}});var WG=Ie(jG,[["__file","steps.vue"]]);const KG=Ne({title:{type:String,default:""},icon:{type:Dt},description:{type:String,default:""},status:{type:String,values:["","wait","process","finish","error","success"],default:""}}),UG=Y({name:"ElStep"}),qG=Y({...UG,props:KG,setup(e){const t=e,n=Se("step"),o=R(-1),r=R({}),a=R(""),l=De("ElSteps"),s=lt();at(()=>{ve([()=>l.props.active,()=>l.props.processStatus,()=>l.props.finishStatus],([S])=>{b(S)},{immediate:!0})}),zt(()=>{l.removeStep(w.uid)});const u=k(()=>t.status||a.value),c=k(()=>{const S=l.steps.value[o.value-1];return S?S.currentStatus:"wait"}),f=k(()=>l.props.alignCenter),d=k(()=>l.props.direction==="vertical"),p=k(()=>l.props.simple),m=k(()=>l.steps.value.length),v=k(()=>{var S;return((S=l.steps.value[m.value-1])==null?void 0:S.uid)===(s==null?void 0:s.uid)}),h=k(()=>p.value?"":l.props.space),C=k(()=>[n.b(),n.is(p.value?"simple":l.props.direction),n.is("flex",v.value&&!h.value&&!f.value),n.is("center",f.value&&!d.value&&!p.value)]),g=k(()=>{const S={flexBasis:Je(h.value)?`${h.value}px`:h.value?h.value:`${100/(m.value-(f.value?0:1))}%`};return d.value||v.value&&(S.maxWidth=`${100/m.value}%`),S}),y=S=>{o.value=S},_=S=>{const E=S==="wait",$={transitionDelay:`${E?"-":""}${150*o.value}ms`},O=S===l.props.processStatus||E?0:100;$.borderWidth=O&&!p.value?"1px":0,$[l.props.direction==="vertical"?"height":"width"]=`${O}%`,r.value=$},b=S=>{S>o.value?a.value=l.props.finishStatus:S===o.value&&c.value!=="error"?a.value=l.props.processStatus:a.value="wait";const E=l.steps.value[o.value-1];E&&E.calcProgress(a.value)},w=Et({uid:s.uid,currentStatus:u,setIndex:y,calcProgress:_});return l.addStep(w),(S,E)=>(T(),V("div",{style:je(i(g)),class:N(i(C))},[te(" icon & line "),F("div",{class:N([i(n).e("head"),i(n).is(i(u))])},[i(p)?te("v-if",!0):(T(),V("div",{key:0,class:N(i(n).e("line"))},[F("i",{class:N(i(n).e("line-inner")),style:je(r.value)},null,6)],2)),F("div",{class:N([i(n).e("icon"),i(n).is(S.icon||S.$slots.icon?"icon":"text")])},[ie(S.$slots,"icon",{},()=>[S.icon?(T(),re(i(ze),{key:0,class:N(i(n).e("icon-inner"))},{default:X(()=>[(T(),re(pt(S.icon)))]),_:1},8,["class"])):i(u)==="success"?(T(),re(i(ze),{key:1,class:N([i(n).e("icon-inner"),i(n).is("status")])},{default:X(()=>[K(i(Mu))]),_:1},8,["class"])):i(u)==="error"?(T(),re(i(ze),{key:2,class:N([i(n).e("icon-inner"),i(n).is("status")])},{default:X(()=>[K(i(tr))]),_:1},8,["class"])):i(p)?te("v-if",!0):(T(),V("div",{key:3,class:N(i(n).e("icon-inner"))},le(o.value+1),3))])],2)],2),te(" title & description "),F("div",{class:N(i(n).e("main"))},[F("div",{class:N([i(n).e("title"),i(n).is(i(u))])},[ie(S.$slots,"title",{},()=>[Ge(le(S.title),1)])],2),i(p)?(T(),V("div",{key:0,class:N(i(n).e("arrow"))},null,2)):(T(),V("div",{key:1,class:N([i(n).e("description"),i(n).is(i(u))])},[ie(S.$slots,"description",{},()=>[Ge(le(S.description),1)])],2))],2)],6))}});var o2=Ie(qG,[["__file","item.vue"]]);const YG=ut(WG,{Step:o2}),GG=tn(o2),XG=Ne({modelValue:{type:[Boolean,String,Number],default:!1},disabled:Boolean,loading:Boolean,size:{type:String,validator:tS},width:{type:[String,Number],default:""},inlinePrompt:Boolean,inactiveActionIcon:{type:Dt},activeActionIcon:{type:Dt},activeIcon:{type:Dt},inactiveIcon:{type:Dt},activeText:{type:String,default:""},inactiveText:{type:String,default:""},activeValue:{type:[Boolean,String,Number],default:!0},inactiveValue:{type:[Boolean,String,Number],default:!1},name:{type:String,default:""},validateEvent:{type:Boolean,default:!0},beforeChange:{type:Q(Function)},id:String,tabindex:{type:[String,Number]},label:{type:String,default:void 0},...An(["ariaLabel"])}),JG={[ft]:e=>dn(e)||nt(e)||Je(e),[Yt]:e=>dn(e)||nt(e)||Je(e),[Zn]:e=>dn(e)||nt(e)||Je(e)},ZG=["onClick"],QG=["id","aria-checked","aria-disabled","aria-label","name","true-value","false-value","disabled","tabindex","onKeydown"],eX=["aria-hidden"],tX=["aria-hidden"],nX=["aria-hidden"],r2="ElSwitch",oX=Y({name:r2}),rX=Y({...oX,props:XG,emits:JG,setup(e,{expose:t,emit:n}){const o=e,{formItem:r}=qn(),a=hn(),l=Se("switch"),{inputId:s}=cr(o,{formItemContext:r}),u=to(k(()=>o.loading)),c=R(o.modelValue!==!1),f=R(),d=R(),p=k(()=>[l.b(),l.m(a.value),l.is("disabled",u.value),l.is("checked",g.value)]),m=k(()=>[l.e("label"),l.em("label","left"),l.is("active",!g.value)]),v=k(()=>[l.e("label"),l.em("label","right"),l.is("active",g.value)]),h=k(()=>({width:rn(o.width)}));ve(()=>o.modelValue,()=>{c.value=!0});const C=k(()=>c.value?o.modelValue:!1),g=k(()=>C.value===o.activeValue);[o.activeValue,o.inactiveValue].includes(C.value)||(n(ft,o.inactiveValue),n(Yt,o.inactiveValue),n(Zn,o.inactiveValue)),ve(g,w=>{var S;f.value.checked=w,o.validateEvent&&((S=r==null?void 0:r.validate)==null||S.call(r,"change").catch(E=>void 0))});const y=()=>{const w=g.value?o.inactiveValue:o.activeValue;n(ft,w),n(Yt,w),n(Zn,w),We(()=>{f.value.checked=g.value})},_=()=>{if(u.value)return;const{beforeChange:w}=o;if(!w){y();return}const S=w();[vs(S),dn(S)].includes(!0)||vn(r2,"beforeChange must return type `Promise` or `boolean`"),vs(S)?S.then($=>{$&&y()}).catch($=>{}):S&&y()},b=()=>{var w,S;(S=(w=f.value)==null?void 0:w.focus)==null||S.call(w)};return at(()=>{f.value.checked=g.value}),wn({from:"label",replacement:"aria-label",version:"2.8.0",scope:"el-switch",ref:"https://element-plus.org/en-US/component/switch.html"},k(()=>!!o.label)),t({focus:b,checked:g}),(w,S)=>(T(),V("div",{class:N(i(p)),onClick:Qe(_,["prevent"])},[F("input",{id:i(s),ref_key:"input",ref:f,class:N(i(l).e("input")),type:"checkbox",role:"switch","aria-checked":i(g),"aria-disabled":i(u),"aria-label":w.label||w.ariaLabel,name:w.name,"true-value":w.activeValue,"false-value":w.inactiveValue,disabled:i(u),tabindex:w.tabindex,onChange:y,onKeydown:Pt(_,["enter"])},null,42,QG),!w.inlinePrompt&&(w.inactiveIcon||w.inactiveText)?(T(),V("span",{key:0,class:N(i(m))},[w.inactiveIcon?(T(),re(i(ze),{key:0},{default:X(()=>[(T(),re(pt(w.inactiveIcon)))]),_:1})):te("v-if",!0),!w.inactiveIcon&&w.inactiveText?(T(),V("span",{key:1,"aria-hidden":i(g)},le(w.inactiveText),9,eX)):te("v-if",!0)],2)):te("v-if",!0),F("span",{ref_key:"core",ref:d,class:N(i(l).e("core")),style:je(i(h))},[w.inlinePrompt?(T(),V("div",{key:0,class:N(i(l).e("inner"))},[w.activeIcon||w.inactiveIcon?(T(),re(i(ze),{key:0,class:N(i(l).is("icon"))},{default:X(()=>[(T(),re(pt(i(g)?w.activeIcon:w.inactiveIcon)))]),_:1},8,["class"])):w.activeText||w.inactiveText?(T(),V("span",{key:1,class:N(i(l).is("text")),"aria-hidden":!i(g)},le(i(g)?w.activeText:w.inactiveText),11,tX)):te("v-if",!0)],2)):te("v-if",!0),F("div",{class:N(i(l).e("action"))},[w.loading?(T(),re(i(ze),{key:0,class:N(i(l).is("loading"))},{default:X(()=>[K(i(Er))]),_:1},8,["class"])):i(g)?ie(w.$slots,"active-action",{key:1},()=>[w.activeActionIcon?(T(),re(i(ze),{key:0},{default:X(()=>[(T(),re(pt(w.activeActionIcon)))]),_:1})):te("v-if",!0)]):i(g)?te("v-if",!0):ie(w.$slots,"inactive-action",{key:2},()=>[w.inactiveActionIcon?(T(),re(i(ze),{key:0},{default:X(()=>[(T(),re(pt(w.inactiveActionIcon)))]),_:1})):te("v-if",!0)])],2)],6),!w.inlinePrompt&&(w.activeIcon||w.activeText)?(T(),V("span",{key:1,class:N(i(v))},[w.activeIcon?(T(),re(i(ze),{key:0},{default:X(()=>[(T(),re(pt(w.activeIcon)))]),_:1})):te("v-if",!0),!w.activeIcon&&w.activeText?(T(),V("span",{key:1,"aria-hidden":!i(g)},le(w.activeText),9,nX)):te("v-if",!0)],2)):te("v-if",!0)],10,ZG))}});var aX=Ie(rX,[["__file","switch.vue"]]);const lX=ut(aX),$p=function(e){var t;return(t=e.target)==null?void 0:t.closest("td")},sX=function(e,t,n,o,r){if(!t&&!o&&(!r||Array.isArray(r)&&!r.length))return e;typeof n=="string"?n=n==="descending"?-1:1:n=n&&n<0?-1:1;const a=o?null:function(s,u){return r?(Array.isArray(r)||(r=[r]),r.map(c=>typeof c=="string"?un(s,c):c(s,u,e))):(t!=="$key"&&dt(s)&&"$value"in s&&(s=s.$value),[dt(s)?un(s,t):s])},l=function(s,u){if(o)return o(s.value,u.value);for(let c=0,f=s.key.length;cu.key[c])return 1}return 0};return e.map((s,u)=>({value:s,index:u,key:a?a(s,u):null})).sort((s,u)=>{let c=l(s,u);return c||(c=s.index-u.index),c*+n}).map(s=>s.value)},a2=function(e,t){let n=null;return e.columns.forEach(o=>{o.id===t&&(n=o)}),n},iX=function(e,t){let n=null;for(let o=0;o{if(!e)throw new Error("Row is required when get row identity");if(typeof t=="string"){if(!t.includes("."))return`${e[t]}`;const n=t.split(".");let o=e;for(const r of n)o=o[r];return`${o}`}else if(typeof t=="function")return t.call(null,e)},nl=function(e,t){const n={};return(e||[]).forEach((o,r)=>{n[Rn(o,t)]={row:o,index:r}}),n};function uX(e,t){const n={};let o;for(o in e)n[o]=e[o];for(o in t)if(Tt(t,o)){const r=t[o];typeof r<"u"&&(n[o]=r)}return n}function Tg(e){return e===""||e!==void 0&&(e=Number.parseInt(e,10),Number.isNaN(e)&&(e="")),e}function l2(e){return e===""||e!==void 0&&(e=Tg(e),Number.isNaN(e)&&(e=80)),e}function cX(e){return typeof e=="number"?e:typeof e=="string"?/^\d+(?:px)?$/.test(e)?Number.parseInt(e,10):e:null}function dX(...e){return e.length===0?t=>t:e.length===1?e[0]:e.reduce((t,n)=>(...o)=>t(n(...o)))}function Bi(e,t,n){let o=!1;const r=e.indexOf(t),a=r!==-1,l=s=>{s==="add"?e.push(t):e.splice(r,1),o=!0,Pe(t.children)&&t.children.forEach(u=>{Bi(e,u,n??!a)})};return dn(n)?n&&!a?l("add"):!n&&a&&l("remove"):l(a?"remove":"add"),o}function fX(e,t,n="children",o="hasChildren"){const r=l=>!(Array.isArray(l)&&l.length);function a(l,s,u){t(l,s,u),s.forEach(c=>{if(c[o]){t(c,null,u+1);return}const f=c[n];r(f)||a(c,f,u+1)})}e.forEach(l=>{if(l[o]){t(l,null,0);return}const s=l[n];r(s)||a(l,s,0)})}let To=null;function pX(e,t,n,o){if((To==null?void 0:To.trigger)===n)return;To==null||To();const r=o==null?void 0:o.refs.tableWrapper,a=r==null?void 0:r.dataset.prefix,l={strategy:"fixed",...e.popperOptions},s=K(Un,{content:t,virtualTriggering:!0,virtualRef:n,appendTo:r,placement:"top",transition:"none",offset:0,hideAfter:0,...e,popperOptions:l,onHide:()=>{To==null||To()}});s.appContext={...o.appContext,...o};const u=document.createElement("div");er(s,u),s.component.exposed.onOpen();const c=r==null?void 0:r.querySelector(`.${a}-scrollbar__wrap`);To=()=>{er(null,u),c==null||c.removeEventListener("scroll",To),To=null},To.trigger=n,c==null||c.addEventListener("scroll",To)}function s2(e){return e.children?Ox(e.children,s2):[e]}function b1(e,t){return e+t.colSpan}const i2=(e,t,n,o)=>{let r=0,a=e;const l=n.states.columns.value;if(o){const u=s2(o[e]);r=l.slice(0,l.indexOf(u[0])).reduce(b1,0),a=r+u.reduce(b1,0)-1}else r=e;let s;switch(t){case"left":a=l.length-n.states.rightFixedLeafColumnsLength.value&&(s="right");break;default:a=l.length-n.states.rightFixedLeafColumnsLength.value&&(s="right")}return s?{direction:s,start:r,after:a}:{}},$g=(e,t,n,o,r,a=0)=>{const l=[],{direction:s,start:u,after:c}=i2(t,n,o,r);if(s){const f=s==="left";l.push(`${e}-fixed-column--${s}`),f&&c+a===o.states.fixedLeafColumnsLength.value-1?l.push("is-last-column"):!f&&u-a===o.states.columns.value.length-o.states.rightFixedLeafColumnsLength.value&&l.push("is-first-column")}return l};function y1(e,t){return e+(t.realWidth===null||Number.isNaN(t.realWidth)?Number(t.width):t.realWidth)}const Og=(e,t,n,o)=>{const{direction:r,start:a=0,after:l=0}=i2(e,t,n,o);if(!r)return;const s={},u=r==="left",c=n.states.columns.value;return u?s.left=c.slice(0,a).reduce(y1,0):s.right=c.slice(l+1).reverse().reduce(y1,0),s},Ls=(e,t)=>{e&&(Number.isNaN(e[t])||(e[t]=`${e[t]}px`))};function hX(e){const t=lt(),n=R(!1),o=R([]);return{updateExpandRows:()=>{const u=e.data.value||[],c=e.rowKey.value;if(n.value)o.value=u.slice();else if(c){const f=nl(o.value,c);o.value=u.reduce((d,p)=>{const m=Rn(p,c);return f[m]&&d.push(p),d},[])}else o.value=[]},toggleRowExpansion:(u,c)=>{Bi(o.value,u,c)&&t.emit("expand-change",u,o.value.slice())},setExpandRowKeys:u=>{t.store.assertRowKey();const c=e.data.value||[],f=e.rowKey.value,d=nl(c,f);o.value=u.reduce((p,m)=>{const v=d[m];return v&&p.push(v.row),p},[])},isRowExpanded:u=>{const c=e.rowKey.value;return c?!!nl(o.value,c)[Rn(u,c)]:o.value.includes(u)},states:{expandRows:o,defaultExpandAll:n}}}function mX(e){const t=lt(),n=R(null),o=R(null),r=c=>{t.store.assertRowKey(),n.value=c,l(c)},a=()=>{n.value=null},l=c=>{const{data:f,rowKey:d}=e;let p=null;d.value&&(p=(i(f)||[]).find(m=>Rn(m,d.value)===c)),o.value=p,t.emit("current-change",o.value,null)};return{setCurrentRowKey:r,restoreCurrentRowKey:a,setCurrentRowByKey:l,updateCurrentRow:c=>{const f=o.value;if(c&&c!==f){o.value=c,t.emit("current-change",o.value,f);return}!c&&f&&(o.value=null,t.emit("current-change",null,f))},updateCurrentRowData:()=>{const c=e.rowKey.value,f=e.data.value||[],d=o.value;if(!f.includes(d)&&d){if(c){const p=Rn(d,c);l(p)}else o.value=null;o.value===null&&t.emit("current-change",null,d)}else n.value&&(l(n.value),a())},states:{_currentRowKey:n,currentRow:o}}}function vX(e){const t=R([]),n=R({}),o=R(16),r=R(!1),a=R({}),l=R("hasChildren"),s=R("children"),u=lt(),c=k(()=>{if(!e.rowKey.value)return{};const g=e.data.value||[];return d(g)}),f=k(()=>{const g=e.rowKey.value,y=Object.keys(a.value),_={};return y.length&&y.forEach(b=>{if(a.value[b].length){const w={children:[]};a.value[b].forEach(S=>{const E=Rn(S,g);w.children.push(E),S[l.value]&&!_[E]&&(_[E]={children:[]})}),_[b]=w}}),_}),d=g=>{const y=e.rowKey.value,_={};return fX(g,(b,w,S)=>{const E=Rn(b,y);Array.isArray(w)?_[E]={children:w.map($=>Rn($,y)),level:S}:r.value&&(_[E]={children:[],lazy:!0,level:S})},s.value,l.value),_},p=(g=!1,y=(_=>(_=u.store)==null?void 0:_.states.defaultExpandAll.value)())=>{var _;const b=c.value,w=f.value,S=Object.keys(b),E={};if(S.length){const $=i(n),O=[],A=(D,U)=>{if(g)return t.value?y||t.value.includes(U):!!(y||D!=null&&D.expanded);{const j=y||t.value&&t.value.includes(U);return!!(D!=null&&D.expanded||j)}};S.forEach(D=>{const U=$[D],j={...b[D]};if(j.expanded=A(U,D),j.lazy){const{loaded:W=!1,loading:L=!1}=U||{};j.loaded=!!W,j.loading=!!L,O.push(D)}E[D]=j});const M=Object.keys(w);r.value&&M.length&&O.length&&M.forEach(D=>{const U=$[D],j=w[D].children;if(O.includes(D)){if(E[D].children.length!==0)throw new Error("[ElTable]children must be an empty array.");E[D].children=j}else{const{loaded:W=!1,loading:L=!1}=U||{};E[D]={lazy:!0,loaded:!!W,loading:!!L,expanded:A(U,D),children:j,level:""}}})}n.value=E,(_=u.store)==null||_.updateTableScrollY()};ve(()=>t.value,()=>{p(!0)}),ve(()=>c.value,()=>{p()}),ve(()=>f.value,()=>{p()});const m=g=>{t.value=g,p()},v=(g,y)=>{u.store.assertRowKey();const _=e.rowKey.value,b=Rn(g,_),w=b&&n.value[b];if(b&&w&&"expanded"in w){const S=w.expanded;y=typeof y>"u"?!w.expanded:y,n.value[b].expanded=y,S!==y&&u.emit("expand-change",g,y),u.store.updateTableScrollY()}},h=g=>{u.store.assertRowKey();const y=e.rowKey.value,_=Rn(g,y),b=n.value[_];r.value&&b&&"loaded"in b&&!b.loaded?C(g,_,b):v(g,void 0)},C=(g,y,_)=>{const{load:b}=u.props;b&&!n.value[y].loaded&&(n.value[y].loading=!0,b(g,_,w=>{if(!Array.isArray(w))throw new TypeError("[ElTable] data must be an array");n.value[y].loading=!1,n.value[y].loaded=!0,n.value[y].expanded=!0,w.length&&(a.value[y]=w),u.emit("expand-change",g,!0)}))};return{loadData:C,loadOrToggle:h,toggleTreeExpansion:v,updateTreeExpandKeys:m,updateTreeData:p,normalize:d,states:{expandRowKeys:t,treeData:n,indent:o,lazy:r,lazyTreeNodeMap:a,lazyColumnIdentifier:l,childrenColumnName:s}}}const gX=(e,t)=>{const n=t.sortingColumn;return!n||typeof n.sortable=="string"?e:sX(e,t.sortProp,t.sortOrder,n.sortMethod,n.sortBy)},Kc=e=>{const t=[];return e.forEach(n=>{n.children&&n.children.length>0?t.push.apply(t,Kc(n.children)):t.push(n)}),t};function bX(){var e;const t=lt(),{size:n}=Cn((e=t.proxy)==null?void 0:e.$props),o=R(null),r=R([]),a=R([]),l=R(!1),s=R([]),u=R([]),c=R([]),f=R([]),d=R([]),p=R([]),m=R([]),v=R([]),h=[],C=R(0),g=R(0),y=R(0),_=R(!1),b=R([]),w=R(!1),S=R(!1),E=R(null),$=R({}),O=R(null),A=R(null),M=R(null),D=R(null),U=R(null);ve(r,()=>t.state&&P(!1),{deep:!0});const j=()=>{if(!o.value)throw new Error("[ElTable] prop row-key is required")},W=Ze=>{var st;(st=Ze.children)==null||st.forEach(Ee=>{Ee.fixed=Ze.fixed,W(Ee)})},L=()=>{s.value.forEach(ne=>{W(ne)}),f.value=s.value.filter(ne=>ne.fixed===!0||ne.fixed==="left"),d.value=s.value.filter(ne=>ne.fixed==="right"),f.value.length>0&&s.value[0]&&s.value[0].type==="selection"&&!s.value[0].fixed&&(s.value[0].fixed=!0,f.value.unshift(s.value[0]));const Ze=s.value.filter(ne=>!ne.fixed);u.value=[].concat(f.value).concat(Ze).concat(d.value);const st=Kc(Ze),Ee=Kc(f.value),ye=Kc(d.value);C.value=st.length,g.value=Ee.length,y.value=ye.length,c.value=[].concat(Ee).concat(st).concat(ye),l.value=f.value.length>0||d.value.length>0},P=(Ze,st=!1)=>{Ze&&L(),st?t.state.doLayout():t.state.debouncedUpdateLayout()},x=Ze=>b.value.includes(Ze),I=()=>{_.value=!1;const Ze=b.value;b.value=[],Ze.length&&t.emit("selection-change",[])},H=()=>{let Ze;if(o.value){Ze=[];const st=nl(b.value,o.value),Ee=nl(r.value,o.value);for(const ye in st)Tt(st,ye)&&!Ee[ye]&&Ze.push(st[ye].row)}else Ze=b.value.filter(st=>!r.value.includes(st));if(Ze.length){const st=b.value.filter(Ee=>!Ze.includes(Ee));b.value=st,t.emit("selection-change",st.slice())}},G=()=>(b.value||[]).slice(),J=(Ze,st=void 0,Ee=!0)=>{if(Bi(b.value,Ze,st)){const ne=(b.value||[]).slice();Ee&&t.emit("select",ne,Ze),t.emit("selection-change",ne)}},ee=()=>{var Ze,st;const Ee=S.value?!_.value:!(_.value||b.value.length);_.value=Ee;let ye=!1,ne=0;const be=(st=(Ze=t==null?void 0:t.store)==null?void 0:Ze.states)==null?void 0:st.rowKey.value;r.value.forEach((Fe,vt)=>{const pe=vt+ne;E.value?E.value.call(null,Fe,pe)&&Bi(b.value,Fe,Ee)&&(ye=!0):Bi(b.value,Fe,Ee)&&(ye=!0),ne+=oe(Rn(Fe,be))}),ye&&t.emit("selection-change",b.value?b.value.slice():[]),t.emit("select-all",(b.value||[]).slice())},fe=()=>{const Ze=nl(b.value,o.value);r.value.forEach(st=>{const Ee=Rn(st,o.value),ye=Ze[Ee];ye&&(b.value[ye.index]=st)})},Te=()=>{var Ze,st,Ee;if(((Ze=r.value)==null?void 0:Ze.length)===0){_.value=!1;return}let ye;o.value&&(ye=nl(b.value,o.value));const ne=function(pe){return ye?!!ye[Rn(pe,o.value)]:b.value.includes(pe)};let be=!0,Fe=0,vt=0;for(let pe=0,Ye=(r.value||[]).length;pe{var st;if(!t||!t.store)return 0;const{treeData:Ee}=t.store.states;let ye=0;const ne=(st=Ee.value[Ze])==null?void 0:st.children;return ne&&(ye+=ne.length,ne.forEach(be=>{ye+=oe(be)})),ye},ke=(Ze,st)=>{Array.isArray(Ze)||(Ze=[Ze]);const Ee={};return Ze.forEach(ye=>{$.value[ye.id]=st,Ee[ye.columnKey||ye.id]=st}),Ee},ae=(Ze,st,Ee)=>{A.value&&A.value!==Ze&&(A.value.order=null),A.value=Ze,M.value=st,D.value=Ee},Oe=()=>{let Ze=i(a);Object.keys($.value).forEach(st=>{const Ee=$.value[st];if(!Ee||Ee.length===0)return;const ye=a2({columns:c.value},st);ye&&ye.filterMethod&&(Ze=Ze.filter(ne=>Ee.some(be=>ye.filterMethod.call(null,be,ne,ye))))}),O.value=Ze},we=()=>{r.value=gX(O.value,{sortingColumn:A.value,sortProp:M.value,sortOrder:D.value})},ge=(Ze=void 0)=>{Ze&&Ze.filter||Oe(),we()},q=Ze=>{const{tableHeaderRef:st}=t.refs;if(!st)return;const Ee=Object.assign({},st.filterPanels),ye=Object.keys(Ee);if(ye.length)if(typeof Ze=="string"&&(Ze=[Ze]),Array.isArray(Ze)){const ne=Ze.map(be=>iX({columns:c.value},be));ye.forEach(be=>{const Fe=ne.find(vt=>vt.id===be);Fe&&(Fe.filteredValue=[])}),t.store.commit("filterChange",{column:ne,values:[],silent:!0,multi:!0})}else ye.forEach(ne=>{const be=c.value.find(Fe=>Fe.id===ne);be&&(be.filteredValue=[])}),$.value={},t.store.commit("filterChange",{column:{},values:[],silent:!0})},B=()=>{A.value&&(ae(null,null,null),t.store.commit("changeSortCondition",{silent:!0}))},{setExpandRowKeys:z,toggleRowExpansion:Z,updateExpandRows:ue,states:se,isRowExpanded:me}=hX({data:r,rowKey:o}),{updateTreeExpandKeys:_e,toggleTreeExpansion:$e,updateTreeData:Ce,loadOrToggle:ce,states:de}=vX({data:r,rowKey:o}),{updateCurrentRowData:xe,updateCurrentRow:he,setCurrentRowKey:He,states:et}=mX({data:r,rowKey:o});return{assertRowKey:j,updateColumns:L,scheduleLayout:P,isSelected:x,clearSelection:I,cleanSelection:H,getSelectionRows:G,toggleRowSelection:J,_toggleAllSelection:ee,toggleAllSelection:null,updateSelectionByRowKey:fe,updateAllSelected:Te,updateFilters:ke,updateCurrentRow:he,updateSort:ae,execFilter:Oe,execSort:we,execQuery:ge,clearFilter:q,clearSort:B,toggleRowExpansion:Z,setExpandRowKeysAdapter:Ze=>{z(Ze),_e(Ze)},setCurrentRowKey:He,toggleRowExpansionAdapter:(Ze,st)=>{c.value.some(({type:ye})=>ye==="expand")?Z(Ze,st):$e(Ze,st)},isRowExpanded:me,updateExpandRows:ue,updateCurrentRowData:xe,loadOrToggle:ce,updateTreeData:Ce,states:{tableSize:n,rowKey:o,data:r,_data:a,isComplex:l,_columns:s,originColumns:u,columns:c,fixedColumns:f,rightFixedColumns:d,leafColumns:p,fixedLeafColumns:m,rightFixedLeafColumns:v,updateOrderFns:h,leafColumnsLength:C,fixedLeafColumnsLength:g,rightFixedLeafColumnsLength:y,isAllSelected:_,selection:b,reserveSelection:w,selectOnIndeterminate:S,selectable:E,filters:$,filteredData:O,sortingColumn:A,sortProp:M,sortOrder:D,hoverRow:U,...se,...de,...et}}}function om(e,t){return e.map(n=>{var o;return n.id===t.id?t:((o=n.children)!=null&&o.length&&(n.children=om(n.children,t)),n)})}function rm(e){e.forEach(t=>{var n,o;t.no=(n=t.getColumnIndex)==null?void 0:n.call(t),(o=t.children)!=null&&o.length&&rm(t.children)}),e.sort((t,n)=>t.no-n.no)}function yX(){const e=lt(),t=bX();return{ns:Se("table"),...t,mutations:{setData(l,s){const u=i(l._data)!==s;l.data.value=s,l._data.value=s,e.store.execQuery(),e.store.updateCurrentRowData(),e.store.updateExpandRows(),e.store.updateTreeData(e.store.states.defaultExpandAll.value),i(l.reserveSelection)?(e.store.assertRowKey(),e.store.updateSelectionByRowKey()):u?e.store.clearSelection():e.store.cleanSelection(),e.store.updateAllSelected(),e.$ready&&e.store.scheduleLayout()},insertColumn(l,s,u,c){const f=i(l._columns);let d=[];u?(u&&!u.children&&(u.children=[]),u.children.push(s),d=om(f,u)):(f.push(s),d=f),rm(d),l._columns.value=d,l.updateOrderFns.push(c),s.type==="selection"&&(l.selectable.value=s.selectable,l.reserveSelection.value=s.reserveSelection),e.$ready&&(e.store.updateColumns(),e.store.scheduleLayout())},updateColumnOrder(l,s){var u;((u=s.getColumnIndex)==null?void 0:u.call(s))!==s.no&&(rm(l._columns.value),e.$ready&&e.store.updateColumns())},removeColumn(l,s,u,c){const f=i(l._columns)||[];if(u)u.children.splice(u.children.findIndex(p=>p.id===s.id),1),We(()=>{var p;((p=u.children)==null?void 0:p.length)===0&&delete u.children}),l._columns.value=om(f,u);else{const p=f.indexOf(s);p>-1&&(f.splice(p,1),l._columns.value=f)}const d=l.updateOrderFns.indexOf(c);d>-1&&l.updateOrderFns.splice(d,1),e.$ready&&(e.store.updateColumns(),e.store.scheduleLayout())},sort(l,s){const{prop:u,order:c,init:f}=s;if(u){const d=i(l.columns).find(p=>p.property===u);d&&(d.order=c,e.store.updateSort(d,u,c),e.store.commit("changeSortCondition",{init:f}))}},changeSortCondition(l,s){const{sortingColumn:u,sortProp:c,sortOrder:f}=l,d=i(u),p=i(c),m=i(f);m===null&&(l.sortingColumn.value=null,l.sortProp.value=null);const v={filter:!0};e.store.execQuery(v),(!s||!(s.silent||s.init))&&e.emit("sort-change",{column:d,prop:p,order:m}),e.store.updateTableScrollY()},filterChange(l,s){const{column:u,values:c,silent:f}=s,d=e.store.updateFilters(u,c);e.store.execQuery(),f||e.emit("filter-change",d),e.store.updateTableScrollY()},toggleAllSelection(){e.store.toggleAllSelection()},rowSelectedChanged(l,s){e.store.toggleRowSelection(s),e.store.updateAllSelected()},setHoverRow(l,s){l.hoverRow.value=s},setCurrentRow(l,s){e.store.updateCurrentRow(s)}},commit:function(l,...s){const u=e.store.mutations;if(u[l])u[l].apply(e,[e.store.states].concat(s));else throw new Error(`Action not found: ${l}`)},updateTableScrollY:function(){We(()=>e.layout.updateScrollY.apply(e.layout))}}}const Vi={rowKey:"rowKey",defaultExpandAll:"defaultExpandAll",selectOnIndeterminate:"selectOnIndeterminate",indent:"indent",lazy:"lazy",data:"data","treeProps.hasChildren":{key:"lazyColumnIdentifier",default:"hasChildren"},"treeProps.children":{key:"childrenColumnName",default:"children"}};function wX(e,t){if(!e)throw new Error("Table is required.");const n=yX();return n.toggleAllSelection=co(n._toggleAllSelection,10),Object.keys(Vi).forEach(o=>{u2(c2(t,o),o,n)}),_X(n,t),n}function _X(e,t){Object.keys(Vi).forEach(n=>{ve(()=>c2(t,n),o=>{u2(o,n,e)})})}function u2(e,t,n){let o=e,r=Vi[t];typeof Vi[t]=="object"&&(r=r.key,o=o||Vi[t].default),n.states[r].value=o}function c2(e,t){if(t.includes(".")){const n=t.split(".");let o=e;return n.forEach(r=>{o=o[r]}),o}else return e[t]}class CX{constructor(t){this.observers=[],this.table=null,this.store=null,this.columns=[],this.fit=!0,this.showHeader=!0,this.height=R(null),this.scrollX=R(!1),this.scrollY=R(!1),this.bodyWidth=R(null),this.fixedWidth=R(null),this.rightFixedWidth=R(null),this.gutterWidth=0;for(const n in t)Tt(t,n)&&(xt(this[n])?this[n].value=t[n]:this[n]=t[n]);if(!this.table)throw new Error("Table is required for Table Layout");if(!this.store)throw new Error("Store is required for Table Layout")}updateScrollY(){if(this.height.value===null)return!1;const n=this.table.refs.scrollBarRef;if(this.table.vnode.el&&(n!=null&&n.wrapRef)){let o=!0;const r=this.scrollY.value;return o=n.wrapRef.scrollHeight>n.wrapRef.clientHeight,this.scrollY.value=o,r!==o}return!1}setHeight(t,n="height"){if(!Ct)return;const o=this.table.vnode.el;if(t=cX(t),this.height.value=Number(t),!o&&(t||t===0))return We(()=>this.setHeight(t,n));typeof t=="number"?(o.style[n]=`${t}px`,this.updateElsHeight()):typeof t=="string"&&(o.style[n]=t,this.updateElsHeight())}setMaxHeight(t){this.setHeight(t,"max-height")}getFlattenColumns(){const t=[];return this.table.store.states.columns.value.forEach(o=>{o.isColumnGroup?t.push.apply(t,o.columns):t.push(o)}),t}updateElsHeight(){this.updateScrollY(),this.notifyObservers("scrollable")}headerDisplayNone(t){if(!t)return!0;let n=t;for(;n.tagName!=="DIV";){if(getComputedStyle(n).display==="none")return!0;n=n.parentElement}return!1}updateColumnsWidth(){if(!Ct)return;const t=this.fit,n=this.table.vnode.el.clientWidth;let o=0;const r=this.getFlattenColumns(),a=r.filter(u=>typeof u.width!="number");if(r.forEach(u=>{typeof u.width=="number"&&u.realWidth&&(u.realWidth=null)}),a.length>0&&t){if(r.forEach(u=>{o+=Number(u.width||u.minWidth||80)}),o<=n){this.scrollX.value=!1;const u=n-o;if(a.length===1)a[0].realWidth=Number(a[0].minWidth||80)+u;else{const c=a.reduce((p,m)=>p+Number(m.minWidth||80),0),f=u/c;let d=0;a.forEach((p,m)=>{if(m===0)return;const v=Math.floor(Number(p.minWidth||80)*f);d+=v,p.realWidth=Number(p.minWidth||80)+v}),a[0].realWidth=Number(a[0].minWidth||80)+u-d}}else this.scrollX.value=!0,a.forEach(u=>{u.realWidth=Number(u.minWidth)});this.bodyWidth.value=Math.max(o,n),this.table.state.resizeState.value.width=this.bodyWidth.value}else r.forEach(u=>{!u.width&&!u.minWidth?u.realWidth=80:u.realWidth=Number(u.width||u.minWidth),o+=u.realWidth}),this.scrollX.value=o>n,this.bodyWidth.value=o;const l=this.store.states.fixedColumns.value;if(l.length>0){let u=0;l.forEach(c=>{u+=Number(c.realWidth||c.width)}),this.fixedWidth.value=u}const s=this.store.states.rightFixedColumns.value;if(s.length>0){let u=0;s.forEach(c=>{u+=Number(c.realWidth||c.width)}),this.rightFixedWidth.value=u}this.notifyObservers("columns")}addObserver(t){this.observers.push(t)}removeObserver(t){const n=this.observers.indexOf(t);n!==-1&&this.observers.splice(n,1)}notifyObservers(t){this.observers.forEach(o=>{var r,a;switch(t){case"columns":(r=o.state)==null||r.onColumnsChange(this);break;case"scrollable":(a=o.state)==null||a.onScrollableChange(this);break;default:throw new Error(`Table Layout don't have event ${t}.`)}})}}const{CheckboxGroup:SX}=Ho,kX=Y({name:"ElTableFilterPanel",components:{ElCheckbox:Ho,ElCheckboxGroup:SX,ElScrollbar:ea,ElTooltip:Un,ElIcon:ze,ArrowDown:Nr,ArrowUp:pf},directives:{ClickOutside:Yr},props:{placement:{type:String,default:"bottom-start"},store:{type:Object},column:{type:Object},upDataColumn:{type:Function}},setup(e){const t=lt(),{t:n}=$t(),o=Se("table-filter"),r=t==null?void 0:t.parent;r.filterPanels.value[e.column.id]||(r.filterPanels.value[e.column.id]=t);const a=R(!1),l=R(null),s=k(()=>e.column&&e.column.filters),u=k(()=>e.column.filterClassName?`${o.b()} ${e.column.filterClassName}`:o.b()),c=k({get:()=>{var w;return(((w=e.column)==null?void 0:w.filteredValue)||[])[0]},set:w=>{f.value&&(typeof w<"u"&&w!==null?f.value.splice(0,1,w):f.value.splice(0,1))}}),f=k({get(){return e.column?e.column.filteredValue||[]:[]},set(w){e.column&&e.upDataColumn("filteredValue",w)}}),d=k(()=>e.column?e.column.filterMultiple:!0),p=w=>w.value===c.value,m=()=>{a.value=!1},v=w=>{w.stopPropagation(),a.value=!a.value},h=()=>{a.value=!1},C=()=>{_(f.value),m()},g=()=>{f.value=[],_(f.value),m()},y=w=>{c.value=w,_(typeof w<"u"&&w!==null?f.value:[]),m()},_=w=>{e.store.commit("filterChange",{column:e.column,values:w}),e.store.updateAllSelected()};ve(a,w=>{e.column&&e.upDataColumn("filterOpened",w)},{immediate:!0});const b=k(()=>{var w,S;return(S=(w=l.value)==null?void 0:w.popperRef)==null?void 0:S.contentRef});return{tooltipVisible:a,multiple:d,filterClassName:u,filteredValue:f,filterValue:c,filters:s,handleConfirm:C,handleReset:g,handleSelect:y,isActive:p,t:n,ns:o,showFilterPanel:v,hideFilterPanel:h,popperPaneRef:b,tooltip:l}}}),EX={key:0},TX=["disabled"],$X=["label","onClick"];function OX(e,t,n,o,r,a){const l=qe("el-checkbox"),s=qe("el-checkbox-group"),u=qe("el-scrollbar"),c=qe("arrow-up"),f=qe("arrow-down"),d=qe("el-icon"),p=qe("el-tooltip"),m=qs("click-outside");return T(),re(p,{ref:"tooltip",visible:e.tooltipVisible,offset:0,placement:e.placement,"show-arrow":!1,"stop-popper-mouse-event":!1,teleported:"",effect:"light",pure:"","popper-class":e.filterClassName,persistent:""},{content:X(()=>[e.multiple?(T(),V("div",EX,[F("div",{class:N(e.ns.e("content"))},[K(u,{"wrap-class":e.ns.e("wrap")},{default:X(()=>[K(s,{modelValue:e.filteredValue,"onUpdate:modelValue":t[0]||(t[0]=v=>e.filteredValue=v),class:N(e.ns.e("checkbox-group"))},{default:X(()=>[(T(!0),V(Ve,null,bt(e.filters,v=>(T(),re(l,{key:v.value,value:v.value},{default:X(()=>[Ge(le(v.text),1)]),_:2},1032,["value"]))),128))]),_:1},8,["modelValue","class"])]),_:1},8,["wrap-class"])],2),F("div",{class:N(e.ns.e("bottom"))},[F("button",{class:N({[e.ns.is("disabled")]:e.filteredValue.length===0}),disabled:e.filteredValue.length===0,type:"button",onClick:t[1]||(t[1]=(...v)=>e.handleConfirm&&e.handleConfirm(...v))},le(e.t("el.table.confirmFilter")),11,TX),F("button",{type:"button",onClick:t[2]||(t[2]=(...v)=>e.handleReset&&e.handleReset(...v))},le(e.t("el.table.resetFilter")),1)],2)])):(T(),V("ul",{key:1,class:N(e.ns.e("list"))},[F("li",{class:N([e.ns.e("list-item"),{[e.ns.is("active")]:e.filterValue===void 0||e.filterValue===null}]),onClick:t[3]||(t[3]=v=>e.handleSelect(null))},le(e.t("el.table.clearFilter")),3),(T(!0),V(Ve,null,bt(e.filters,v=>(T(),V("li",{key:v.value,class:N([e.ns.e("list-item"),e.ns.is("active",e.isActive(v))]),label:v.value,onClick:h=>e.handleSelect(v.value)},le(v.text),11,$X))),128))],2))]),default:X(()=>[tt((T(),V("span",{class:N([`${e.ns.namespace.value}-table__column-filter-trigger`,`${e.ns.namespace.value}-none-outline`]),onClick:t[4]||(t[4]=(...v)=>e.showFilterPanel&&e.showFilterPanel(...v))},[K(d,null,{default:X(()=>[ie(e.$slots,"filter-icon",{},()=>[e.column.filterOpened?(T(),re(c,{key:0})):(T(),re(f,{key:1}))])]),_:3})],2)),[[m,e.hideFilterPanel,e.popperPaneRef]])]),_:3},8,["visible","placement","popper-class"])}var NX=Ie(kX,[["render",OX],["__file","filter-panel.vue"]]);function d2(e){const t=lt();Su(()=>{n.value.addObserver(t)}),at(()=>{o(n.value),r(n.value)}),ar(()=>{o(n.value),r(n.value)}),lr(()=>{n.value.removeObserver(t)});const n=k(()=>{const a=e.layout;if(!a)throw new Error("Can not find table layout.");return a}),o=a=>{var l;const s=((l=e.vnode.el)==null?void 0:l.querySelectorAll("colgroup > col"))||[];if(!s.length)return;const u=a.getFlattenColumns(),c={};u.forEach(f=>{c[f.id]=f});for(let f=0,d=s.length;f{var l,s;const u=((l=e.vnode.el)==null?void 0:l.querySelectorAll("colgroup > col[name=gutter]"))||[];for(let f=0,d=u.length;f{h.stopPropagation()},a=(h,C)=>{!C.filters&&C.sortable?v(h,C,!1):C.filterable&&!C.sortable&&r(h),o==null||o.emit("header-click",C,h)},l=(h,C)=>{o==null||o.emit("header-contextmenu",C,h)},s=R(null),u=R(!1),c=R({}),f=(h,C)=>{if(Ct&&!(C.children&&C.children.length>0)&&s.value&&e.border){u.value=!0;const g=o;t("set-drag-visible",!0);const _=(g==null?void 0:g.vnode.el).getBoundingClientRect().left,b=n.vnode.el.querySelector(`th.${C.id}`),w=b.getBoundingClientRect(),S=w.left-_+30;Mo(b,"noclick"),c.value={startMouseLeft:h.clientX,startLeft:w.right-_,startColumnLeft:w.left-_,tableLeft:_};const E=g==null?void 0:g.refs.resizeProxy;E.style.left=`${c.value.startLeft}px`,document.onselectstart=function(){return!1},document.ondragstart=function(){return!1};const $=A=>{const M=A.clientX-c.value.startMouseLeft,D=c.value.startLeft+M;E.style.left=`${Math.max(S,D)}px`},O=()=>{if(u.value){const{startColumnLeft:A,startLeft:M}=c.value,U=Number.parseInt(E.style.left,10)-A;C.width=C.realWidth=U,g==null||g.emit("header-dragend",C.width,M-A,C,h),requestAnimationFrame(()=>{e.store.scheduleLayout(!1,!0)}),document.body.style.cursor="",u.value=!1,s.value=null,c.value={},t("set-drag-visible",!1)}document.removeEventListener("mousemove",$),document.removeEventListener("mouseup",O),document.onselectstart=null,document.ondragstart=null,setTimeout(()=>{Kn(b,"noclick")},0)};document.addEventListener("mousemove",$),document.addEventListener("mouseup",O)}},d=(h,C)=>{if(C.children&&C.children.length>0)return;const g=h.target;if(!Fo(g))return;const y=g==null?void 0:g.closest("th");if(!(!C||!C.resizable)&&!u.value&&e.border){const _=y.getBoundingClientRect(),b=document.body.style;_.width>12&&_.right-h.pageX<8?(b.cursor="col-resize",wo(y,"is-sortable")&&(y.style.cursor="col-resize"),s.value=C):u.value||(b.cursor="",wo(y,"is-sortable")&&(y.style.cursor="pointer"),s.value=null)}},p=()=>{Ct&&(document.body.style.cursor="")},m=({order:h,sortOrders:C})=>{if(h==="")return C[0];const g=C.indexOf(h||null);return C[g>C.length-2?0:g+1]},v=(h,C,g)=>{var y;h.stopPropagation();const _=C.order===g?null:g||m(C),b=(y=h.target)==null?void 0:y.closest("th");if(b&&wo(b,"noclick")){Kn(b,"noclick");return}if(!C.sortable)return;const w=e.store.states;let S=w.sortProp.value,E;const $=w.sortingColumn.value;($!==C||$===C&&$.order===null)&&($&&($.order=null),w.sortingColumn.value=C,S=C.property),_?E=C.order=_:E=C.order=null,w.sortProp.value=S,w.sortOrder.value=E,o==null||o.store.commit("changeSortCondition")};return{handleHeaderClick:a,handleHeaderContextMenu:l,handleMouseDown:f,handleMouseMove:d,handleMouseOut:p,handleSortClick:v,handleFilterClick:r}}function MX(e){const t=De(Mr),n=Se("table");return{getHeaderRowStyle:s=>{const u=t==null?void 0:t.props.headerRowStyle;return typeof u=="function"?u.call(null,{rowIndex:s}):u},getHeaderRowClass:s=>{const u=[],c=t==null?void 0:t.props.headerRowClassName;return typeof c=="string"?u.push(c):typeof c=="function"&&u.push(c.call(null,{rowIndex:s})),u.join(" ")},getHeaderCellStyle:(s,u,c,f)=>{var d;let p=(d=t==null?void 0:t.props.headerCellStyle)!=null?d:{};typeof p=="function"&&(p=p.call(null,{rowIndex:s,columnIndex:u,row:c,column:f}));const m=Og(u,f.fixed,e.store,c);return Ls(m,"left"),Ls(m,"right"),Object.assign({},p,m)},getHeaderCellClass:(s,u,c,f)=>{const d=$g(n.b(),u,f.fixed,e.store,c),p=[f.id,f.order,f.headerAlign,f.className,f.labelClassName,...d];f.children||p.push("is-leaf"),f.sortable&&p.push("is-sortable");const m=t==null?void 0:t.props.headerCellClassName;return typeof m=="string"?p.push(m):typeof m=="function"&&p.push(m.call(null,{rowIndex:s,columnIndex:u,row:c,column:f})),p.push(n.e("cell")),p.filter(v=>!!v).join(" ")}}}const f2=e=>{const t=[];return e.forEach(n=>{n.children?(t.push(n),t.push.apply(t,f2(n.children))):t.push(n)}),t},p2=e=>{let t=1;const n=(a,l)=>{if(l&&(a.level=l.level+1,t{n(u,a),s+=u.colSpan}),a.colSpan=s}else a.colSpan=1};e.forEach(a=>{a.level=1,n(a,void 0)});const o=[];for(let a=0;a{a.children?(a.rowSpan=1,a.children.forEach(l=>l.isSubColumn=!0)):a.rowSpan=t-a.level+1,o[a.level-1].push(a)}),o};function AX(e){const t=De(Mr),n=k(()=>p2(e.store.states.originColumns.value));return{isGroup:k(()=>{const a=n.value.length>1;return a&&t&&(t.state.isGroup.value=!0),a}),toggleAllSelection:a=>{a.stopPropagation(),t==null||t.store.commit("toggleAllSelection")},columnRows:n}}var PX=Y({name:"ElTableHeader",components:{ElCheckbox:Ho},props:{fixed:{type:String,default:""},store:{required:!0,type:Object},border:Boolean,defaultSort:{type:Object,default:()=>({prop:"",order:""})}},setup(e,{emit:t}){const n=lt(),o=De(Mr),r=Se("table"),a=R({}),{onColumnsChange:l,onScrollableChange:s}=d2(o);at(async()=>{await We(),await We();const{prop:S,order:E}=e.defaultSort;o==null||o.store.commit("sort",{prop:S,order:E,init:!0})});const{handleHeaderClick:u,handleHeaderContextMenu:c,handleMouseDown:f,handleMouseMove:d,handleMouseOut:p,handleSortClick:m,handleFilterClick:v}=IX(e,t),{getHeaderRowStyle:h,getHeaderRowClass:C,getHeaderCellStyle:g,getHeaderCellClass:y}=MX(e),{isGroup:_,toggleAllSelection:b,columnRows:w}=AX(e);return n.state={onColumnsChange:l,onScrollableChange:s},n.filterPanels=a,{ns:r,filterPanels:a,onColumnsChange:l,onScrollableChange:s,columnRows:w,getHeaderRowClass:C,getHeaderRowStyle:h,getHeaderCellClass:y,getHeaderCellStyle:g,handleHeaderClick:u,handleHeaderContextMenu:c,handleMouseDown:f,handleMouseMove:d,handleMouseOut:p,handleSortClick:m,handleFilterClick:v,isGroup:_,toggleAllSelection:b}},render(){const{ns:e,isGroup:t,columnRows:n,getHeaderCellStyle:o,getHeaderCellClass:r,getHeaderRowClass:a,getHeaderRowStyle:l,handleHeaderClick:s,handleHeaderContextMenu:u,handleMouseDown:c,handleMouseMove:f,handleSortClick:d,handleMouseOut:p,store:m,$parent:v}=this;let h=1;return Ke("thead",{class:{[e.is("group")]:t}},n.map((C,g)=>Ke("tr",{class:a(g),key:g,style:l(g)},C.map((y,_)=>(y.rowSpan>h&&(h=y.rowSpan),Ke("th",{class:r(g,_,C,y),colspan:y.colSpan,key:`${y.id}-thead`,rowspan:y.rowSpan,style:o(g,_,C,y),onClick:b=>{b.currentTarget.classList.contains("noclick")||s(b,y)},onContextmenu:b=>u(b,y),onMousedown:b=>c(b,y),onMousemove:b=>f(b,y),onMouseout:p},[Ke("div",{class:["cell",y.filteredValue&&y.filteredValue.length>0?"highlight":""]},[y.renderHeader?y.renderHeader({column:y,$index:_,store:m,_self:v}):y.label,y.sortable&&Ke("span",{onClick:b=>d(b,y),class:"caret-wrapper"},[Ke("i",{onClick:b=>d(b,y,"ascending"),class:"sort-caret ascending"}),Ke("i",{onClick:b=>d(b,y,"descending"),class:"sort-caret descending"})]),y.filterable&&Ke(NX,{store:m,placement:y.filterPlacement||"bottom-start",column:y,upDataColumn:(b,w)=>{y[b]=w}},{"filter-icon":()=>y.renderFilterIcon?y.renderFilterIcon({filterOpened:y.filterOpened}):null})])]))))))}});function Op(e,t,n=.01){return e-t>n}function RX(e){const t=De(Mr),n=R(""),o=R(Ke("div")),r=(v,h,C)=>{var g;const y=t,_=$p(v);let b;const w=(g=y==null?void 0:y.vnode.el)==null?void 0:g.dataset.prefix;_&&(b=g1({columns:e.store.states.columns.value},_,w),b&&(y==null||y.emit(`cell-${C}`,h,b,_,v))),y==null||y.emit(`row-${C}`,h,b,v)},a=(v,h)=>{r(v,h,"dblclick")},l=(v,h)=>{e.store.commit("setCurrentRow",h),r(v,h,"click")},s=(v,h)=>{r(v,h,"contextmenu")},u=co(v=>{e.store.commit("setHoverRow",v)},30),c=co(()=>{e.store.commit("setHoverRow",null)},30),f=v=>{const h=window.getComputedStyle(v,null),C=Number.parseInt(h.paddingLeft,10)||0,g=Number.parseInt(h.paddingRight,10)||0,y=Number.parseInt(h.paddingTop,10)||0,_=Number.parseInt(h.paddingBottom,10)||0;return{left:C,right:g,top:y,bottom:_}},d=(v,h,C)=>{let g=h.target.parentNode;for(;v>1&&(g=g==null?void 0:g.nextSibling,!(!g||g.nodeName!=="TR"));)C(g,"hover-row hover-fixed-row"),v--};return{handleDoubleClick:a,handleClick:l,handleContextMenu:s,handleMouseEnter:u,handleMouseLeave:c,handleCellMouseEnter:(v,h,C)=>{var g;const y=t,_=$p(v),b=(g=y==null?void 0:y.vnode.el)==null?void 0:g.dataset.prefix;if(_){const I=g1({columns:e.store.states.columns.value},_,b);_.rowSpan>1&&d(_.rowSpan,v,Mo);const H=y.hoverState={cell:_,column:I,row:h};y==null||y.emit("cell-mouse-enter",H.row,H.column,H.cell,v)}if(!C)return;const w=v.target.querySelector(".cell");if(!(wo(w,`${b}-tooltip`)&&w.childNodes.length))return;const S=document.createRange();S.setStart(w,0),S.setEnd(w,w.childNodes.length);let{width:E,height:$}=S.getBoundingClientRect();const O=E-Math.floor(E),{width:A,height:M}=w.getBoundingClientRect();O<.001&&(E=Math.floor(E)),$-Math.floor($)<.001&&($=Math.floor($));const{top:U,left:j,right:W,bottom:L}=f(w),P=j+W,x=U+L;(Op(E+P,A)||Op($+x,M)||Op(w.scrollWidth,A))&&pX(C,_.innerText||_.textContent,_,y)},handleCellMouseLeave:v=>{const h=$p(v);if(!h)return;h.rowSpan>1&&d(h.rowSpan,v,Kn);const C=t==null?void 0:t.hoverState;t==null||t.emit("cell-mouse-leave",C==null?void 0:C.row,C==null?void 0:C.column,C==null?void 0:C.cell,v)},tooltipContent:n,tooltipTrigger:o}}function LX(e){const t=De(Mr),n=Se("table");return{getRowStyle:(c,f)=>{const d=t==null?void 0:t.props.rowStyle;return typeof d=="function"?d.call(null,{row:c,rowIndex:f}):d||null},getRowClass:(c,f)=>{const d=[n.e("row")];t!=null&&t.props.highlightCurrentRow&&c===e.store.states.currentRow.value&&d.push("current-row"),e.stripe&&f%2===1&&d.push(n.em("row","striped"));const p=t==null?void 0:t.props.rowClassName;return typeof p=="string"?d.push(p):typeof p=="function"&&d.push(p.call(null,{row:c,rowIndex:f})),d},getCellStyle:(c,f,d,p)=>{const m=t==null?void 0:t.props.cellStyle;let v=m??{};typeof m=="function"&&(v=m.call(null,{rowIndex:c,columnIndex:f,row:d,column:p}));const h=Og(f,e==null?void 0:e.fixed,e.store);return Ls(h,"left"),Ls(h,"right"),Object.assign({},v,h)},getCellClass:(c,f,d,p,m)=>{const v=$g(n.b(),f,e==null?void 0:e.fixed,e.store,void 0,m),h=[p.id,p.align,p.className,...v],C=t==null?void 0:t.props.cellClassName;return typeof C=="string"?h.push(C):typeof C=="function"&&h.push(C.call(null,{rowIndex:c,columnIndex:f,row:d,column:p})),h.push(n.e("cell")),h.filter(g=>!!g).join(" ")},getSpan:(c,f,d,p)=>{let m=1,v=1;const h=t==null?void 0:t.props.spanMethod;if(typeof h=="function"){const C=h({row:c,column:f,rowIndex:d,columnIndex:p});Array.isArray(C)?(m=C[0],v=C[1]):typeof C=="object"&&(m=C.rowspan,v=C.colspan)}return{rowspan:m,colspan:v}},getColspanRealWidth:(c,f,d)=>{if(f<1)return c[d].realWidth;const p=c.map(({realWidth:m,width:v})=>m||v).slice(d,d+f);return Number(p.reduce((m,v)=>Number(m)+Number(v),-1))}}}function xX(e){const t=De(Mr),n=Se("table"),{handleDoubleClick:o,handleClick:r,handleContextMenu:a,handleMouseEnter:l,handleMouseLeave:s,handleCellMouseEnter:u,handleCellMouseLeave:c,tooltipContent:f,tooltipTrigger:d}=RX(e),{getRowStyle:p,getRowClass:m,getCellStyle:v,getCellClass:h,getSpan:C,getColspanRealWidth:g}=LX(e),y=k(()=>e.store.states.columns.value.findIndex(({type:E})=>E==="default")),_=(E,$)=>{const O=t.props.rowKey;return O?Rn(E,O):$},b=(E,$,O,A=!1)=>{const{tooltipEffect:M,tooltipOptions:D,store:U}=e,{indent:j,columns:W}=U.states,L=m(E,$);let P=!0;return O&&(L.push(n.em("row",`level-${O.level}`)),P=O.display),Ke("tr",{style:[P?null:{display:"none"},p(E,$)],class:L,key:_(E,$),onDblclick:I=>o(I,E),onClick:I=>r(I,E),onContextmenu:I=>a(I,E),onMouseenter:()=>l($),onMouseleave:s},W.value.map((I,H)=>{const{rowspan:G,colspan:J}=C(E,I,$,H);if(!G||!J)return null;const ee=Object.assign({},I);ee.realWidth=g(W.value,J,H);const fe={store:e.store,_self:e.context||t,column:ee,row:E,$index:$,cellIndex:H,expanded:A};H===y.value&&O&&(fe.treeNode={indent:O.level*j.value,level:O.level},typeof O.expanded=="boolean"&&(fe.treeNode.expanded=O.expanded,"loading"in O&&(fe.treeNode.loading=O.loading),"noLazyChildren"in O&&(fe.treeNode.noLazyChildren=O.noLazyChildren)));const Te=`${_(E,$)},${H}`,oe=ee.columnKey||ee.rawColumnKey||"",ke=w(H,I,fe),ae=I.showOverflowTooltip&&Ax({effect:M},D,I.showOverflowTooltip);return Ke("td",{style:v($,H,E,I),class:h($,H,E,I,J-1),key:`${oe}${Te}`,rowspan:G,colspan:J,onMouseenter:Oe=>u(Oe,E,ae),onMouseleave:c},[ke])}))},w=(E,$,O)=>$.renderCell(O);return{wrappedRowRender:(E,$)=>{const O=e.store,{isRowExpanded:A,assertRowKey:M}=O,{treeData:D,lazyTreeNodeMap:U,childrenColumnName:j,rowKey:W}=O.states,L=O.states.columns.value;if(L.some(({type:x})=>x==="expand")){const x=A(E),I=b(E,$,void 0,x),H=t.renderExpanded;return x?H?[[I,Ke("tr",{key:`expanded-row__${I.key}`},[Ke("td",{colspan:L.length,class:`${n.e("cell")} ${n.e("expanded-cell")}`},[H({row:E,$index:$,store:O,expanded:x})])])]]:(console.error("[Element Error]renderExpanded is required."),I):[[I]]}else if(Object.keys(D.value).length){M();const x=Rn(E,W.value);let I=D.value[x],H=null;I&&(H={expanded:I.expanded,level:I.level,display:!0},typeof I.lazy=="boolean"&&(typeof I.loaded=="boolean"&&I.loaded&&(H.noLazyChildren=!(I.children&&I.children.length)),H.loading=I.loading));const G=[b(E,$,H)];if(I){let J=0;const ee=(Te,oe)=>{Te&&Te.length&&oe&&Te.forEach(ke=>{const ae={display:oe.display&&oe.expanded,level:oe.level+1,expanded:!1,noLazyChildren:!1,loading:!1},Oe=Rn(ke,W.value);if(Oe==null)throw new Error("For nested data item, row-key is required.");if(I={...D.value[Oe]},I&&(ae.expanded=I.expanded,I.level=I.level||ae.level,I.display=!!(I.expanded&&ae.display),typeof I.lazy=="boolean"&&(typeof I.loaded=="boolean"&&I.loaded&&(ae.noLazyChildren=!(I.children&&I.children.length)),ae.loading=I.loading)),J++,G.push(b(ke,$+J,ae)),I){const we=U.value[Oe]||ke[j.value];ee(we,I)}})};I.display=!0;const fe=U.value[x]||E[j.value];ee(fe,I)}return G}else return b(E,$,void 0)},tooltipContent:f,tooltipTrigger:d}}const DX={store:{required:!0,type:Object},stripe:Boolean,tooltipEffect:String,tooltipOptions:{type:Object},context:{default:()=>({}),type:Object},rowClassName:[String,Function],rowStyle:[Object,Function],fixed:{type:String,default:""},highlight:Boolean};var FX=Y({name:"ElTableBody",props:DX,setup(e){const t=lt(),n=De(Mr),o=Se("table"),{wrappedRowRender:r,tooltipContent:a,tooltipTrigger:l}=xX(e),{onColumnsChange:s,onScrollableChange:u}=d2(n),c=[];return ve(e.store.states.hoverRow,(f,d)=>{var p;const m=t==null?void 0:t.vnode.el,v=Array.from((m==null?void 0:m.children)||[]).filter(g=>g==null?void 0:g.classList.contains(`${o.e("row")}`));let h=f;const C=(p=v[h])==null?void 0:p.childNodes;if(C!=null&&C.length){let g=0;Array.from(C).reduce((_,b,w)=>{var S,E;return((S=C[w])==null?void 0:S.colSpan)>1&&(g=(E=C[w])==null?void 0:E.colSpan),b.nodeName!=="TD"&&g===0&&_.push(w),g>0&&g--,_},[]).forEach(_=>{var b;for(h=f;h>0;){const w=(b=v[h-1])==null?void 0:b.childNodes;if(w[_]&&w[_].nodeName==="TD"&&w[_].rowSpan>1){Mo(w[_],"hover-cell"),c.push(w[_]);break}h--}})}else c.forEach(g=>Kn(g,"hover-cell")),c.length=0;!e.store.states.isComplex.value||!Ct||Ma(()=>{const g=v[d],y=v[f];g&&!g.classList.contains("hover-fixed-row")&&Kn(g,"hover-row"),y&&Mo(y,"hover-row")})}),lr(()=>{var f;(f=To)==null||f()}),{ns:o,onColumnsChange:s,onScrollableChange:u,wrappedRowRender:r,tooltipContent:a,tooltipTrigger:l}},render(){const{wrappedRowRender:e,store:t}=this,n=t.states.data.value||[];return Ke("tbody",{tabIndex:-1},[n.reduce((o,r)=>o.concat(e(r,o.length)),[])])}});function BX(){const e=De(Mr),t=e==null?void 0:e.store,n=k(()=>t.states.fixedLeafColumnsLength.value),o=k(()=>t.states.rightFixedColumns.value.length),r=k(()=>t.states.columns.value.length),a=k(()=>t.states.fixedColumns.value.length),l=k(()=>t.states.rightFixedColumns.value.length);return{leftFixedLeafCount:n,rightFixedLeafCount:o,columnsCount:r,leftFixedCount:a,rightFixedCount:l,columns:t.states.columns}}function VX(e){const{columns:t}=BX(),n=Se("table");return{getCellClasses:(a,l)=>{const s=a[l],u=[n.e("cell"),s.id,s.align,s.labelClassName,...$g(n.b(),l,s.fixed,e.store)];return s.className&&u.push(s.className),s.children||u.push(n.is("leaf")),u},getCellStyles:(a,l)=>{const s=Og(l,a.fixed,e.store);return Ls(s,"left"),Ls(s,"right"),s},columns:t}}var HX=Y({name:"ElTableFooter",props:{fixed:{type:String,default:""},store:{required:!0,type:Object},summaryMethod:Function,sumText:String,border:Boolean,defaultSort:{type:Object,default:()=>({prop:"",order:""})}},setup(e){const{getCellClasses:t,getCellStyles:n,columns:o}=VX(e);return{ns:Se("table"),getCellClasses:t,getCellStyles:n,columns:o}},render(){const{columns:e,getCellStyles:t,getCellClasses:n,summaryMethod:o,sumText:r}=this,a=this.store.states.data.value;let l=[];return o?l=o({columns:e,data:a}):e.forEach((s,u)=>{if(u===0){l[u]=r;return}const c=a.map(m=>Number(m[s.property])),f=[];let d=!0;c.forEach(m=>{if(!Number.isNaN(+m)){d=!1;const v=`${m}`.split(".")[1];f.push(v?v.length:0)}});const p=Math.max.apply(null,f);d?l[u]="":l[u]=c.reduce((m,v)=>{const h=Number(v);return Number.isNaN(+h)?m:Number.parseFloat((m+v).toFixed(Math.min(p,20)))},0)}),Ke(Ke("tfoot",[Ke("tr",{},[...e.map((s,u)=>Ke("td",{key:u,colspan:s.colSpan,rowspan:s.rowSpan,class:n(e,u),style:t(s,u)},[Ke("div",{class:["cell",s.labelClassName]},[l[u]])]))])]))}});function zX(e){return{setCurrentRow:f=>{e.commit("setCurrentRow",f)},getSelectionRows:()=>e.getSelectionRows(),toggleRowSelection:(f,d)=>{e.toggleRowSelection(f,d,!1),e.updateAllSelected()},clearSelection:()=>{e.clearSelection()},clearFilter:f=>{e.clearFilter(f)},toggleAllSelection:()=>{e.commit("toggleAllSelection")},toggleRowExpansion:(f,d)=>{e.toggleRowExpansionAdapter(f,d)},clearSort:()=>{e.clearSort()},sort:(f,d)=>{e.commit("sort",{prop:f,order:d})}}}function jX(e,t,n,o){const r=R(!1),a=R(null),l=R(!1),s=I=>{l.value=I},u=R({width:null,height:null,headerHeight:null}),c=R(!1),f={display:"inline-block",verticalAlign:"middle"},d=R(),p=R(0),m=R(0),v=R(0),h=R(0),C=R(0);Mn(()=>{t.setHeight(e.height)}),Mn(()=>{t.setMaxHeight(e.maxHeight)}),ve(()=>[e.currentRowKey,n.states.rowKey],([I,H])=>{!i(H)||!i(I)||n.setCurrentRowKey(`${I}`)},{immediate:!0}),ve(()=>e.data,I=>{o.store.commit("setData",I)},{immediate:!0,deep:!0}),Mn(()=>{e.expandRowKeys&&n.setExpandRowKeysAdapter(e.expandRowKeys)});const g=()=>{o.store.commit("setHoverRow",null),o.hoverState&&(o.hoverState=null)},y=(I,H)=>{const{pixelX:G,pixelY:J}=H;Math.abs(G)>=Math.abs(J)&&(o.refs.bodyWrapper.scrollLeft+=H.pixelX/5)},_=k(()=>e.height||e.maxHeight||n.states.fixedColumns.value.length>0||n.states.rightFixedColumns.value.length>0),b=k(()=>({width:t.bodyWidth.value?`${t.bodyWidth.value}px`:""})),w=()=>{_.value&&t.updateElsHeight(),t.updateColumnsWidth(),requestAnimationFrame(O)};at(async()=>{await We(),n.updateColumns(),A(),requestAnimationFrame(w);const I=o.vnode.el,H=o.refs.headerWrapper;e.flexible&&I&&I.parentElement&&(I.parentElement.style.minWidth="0"),u.value={width:d.value=I.offsetWidth,height:I.offsetHeight,headerHeight:e.showHeader&&H?H.offsetHeight:null},n.states.columns.value.forEach(G=>{G.filteredValue&&G.filteredValue.length&&o.store.commit("filterChange",{column:G,values:G.filteredValue,silent:!0})}),o.$ready=!0});const S=(I,H)=>{if(!I)return;const G=Array.from(I.classList).filter(J=>!J.startsWith("is-scrolling-"));G.push(t.scrollX.value?H:"is-scrolling-none"),I.className=G.join(" ")},E=I=>{const{tableWrapper:H}=o.refs;S(H,I)},$=I=>{const{tableWrapper:H}=o.refs;return!!(H&&H.classList.contains(I))},O=function(){if(!o.refs.scrollBarRef)return;if(!t.scrollX.value){const oe="is-scrolling-none";$(oe)||E(oe);return}const I=o.refs.scrollBarRef.wrapRef;if(!I)return;const{scrollLeft:H,offsetWidth:G,scrollWidth:J}=I,{headerWrapper:ee,footerWrapper:fe}=o.refs;ee&&(ee.scrollLeft=H),fe&&(fe.scrollLeft=H);const Te=J-G-1;H>=Te?E("is-scrolling-right"):E(H===0?"is-scrolling-left":"is-scrolling-middle")},A=()=>{o.refs.scrollBarRef&&(o.refs.scrollBarRef.wrapRef&&qt(o.refs.scrollBarRef.wrapRef,"scroll",O,{passive:!0}),e.fit?Qt(o.vnode.el,M):qt(window,"resize",M),Qt(o.refs.bodyWrapper,()=>{var I,H;M(),(H=(I=o.refs)==null?void 0:I.scrollBarRef)==null||H.update()}))},M=()=>{var I,H,G,J;const ee=o.vnode.el;if(!o.$ready||!ee)return;let fe=!1;const{width:Te,height:oe,headerHeight:ke}=u.value,ae=d.value=ee.offsetWidth;Te!==ae&&(fe=!0);const Oe=ee.offsetHeight;(e.height||_.value)&&oe!==Oe&&(fe=!0);const we=e.tableLayout==="fixed"?o.refs.headerWrapper:(I=o.refs.tableHeaderRef)==null?void 0:I.$el;e.showHeader&&(we==null?void 0:we.offsetHeight)!==ke&&(fe=!0),p.value=((H=o.refs.tableWrapper)==null?void 0:H.scrollHeight)||0,v.value=(we==null?void 0:we.scrollHeight)||0,h.value=((G=o.refs.footerWrapper)==null?void 0:G.offsetHeight)||0,C.value=((J=o.refs.appendWrapper)==null?void 0:J.offsetHeight)||0,m.value=p.value-v.value-h.value-C.value,fe&&(u.value={width:ae,height:Oe,headerHeight:e.showHeader&&(we==null?void 0:we.offsetHeight)||0},w())},D=hn(),U=k(()=>{const{bodyWidth:I,scrollY:H,gutterWidth:G}=t;return I.value?`${I.value-(H.value?G:0)}px`:""}),j=k(()=>e.maxHeight?"fixed":e.tableLayout),W=k(()=>{if(e.data&&e.data.length)return null;let I="100%";e.height&&m.value&&(I=`${m.value}px`);const H=d.value;return{width:H?`${H}px`:"",height:I}}),L=k(()=>e.height?{height:Number.isNaN(Number(e.height))?e.height:`${e.height}px`}:e.maxHeight?{maxHeight:Number.isNaN(Number(e.maxHeight))?e.maxHeight:`${e.maxHeight}px`}:{}),P=k(()=>e.height?{height:"100%"}:e.maxHeight?Number.isNaN(Number(e.maxHeight))?{maxHeight:`calc(${e.maxHeight} - ${v.value+h.value}px)`}:{maxHeight:`${e.maxHeight-v.value-h.value}px`}:{});return{isHidden:r,renderExpanded:a,setDragVisible:s,isGroup:c,handleMouseLeave:g,handleHeaderFooterMousewheel:y,tableSize:D,emptyBlockStyle:W,handleFixedMousewheel:(I,H)=>{const G=o.refs.bodyWrapper;if(Math.abs(H.spinY)>0){const J=G.scrollTop;H.pixelY<0&&J!==0&&I.preventDefault(),H.pixelY>0&&G.scrollHeight-G.clientHeight>J&&I.preventDefault(),G.scrollTop+=Math.ceil(H.pixelY/5)}else G.scrollLeft+=Math.ceil(H.pixelX/5)},resizeProxyVisible:l,bodyWidth:U,resizeState:u,doLayout:w,tableBodyStyles:b,tableLayout:j,scrollbarViewStyle:f,tableInnerStyle:L,scrollbarStyle:P}}function WX(e){const t=R(),n=()=>{const r=e.vnode.el.querySelector(".hidden-columns"),a={childList:!0,subtree:!0},l=e.store.states.updateOrderFns;t.value=new MutationObserver(()=>{l.forEach(s=>s())}),t.value.observe(r,a)};at(()=>{n()}),lr(()=>{var o;(o=t.value)==null||o.disconnect()})}var KX={data:{type:Array,default:()=>[]},size:gn,width:[String,Number],height:[String,Number],maxHeight:[String,Number],fit:{type:Boolean,default:!0},stripe:Boolean,border:Boolean,rowKey:[String,Function],showHeader:{type:Boolean,default:!0},showSummary:Boolean,sumText:String,summaryMethod:Function,rowClassName:[String,Function],rowStyle:[Object,Function],cellClassName:[String,Function],cellStyle:[Object,Function],headerRowClassName:[String,Function],headerRowStyle:[Object,Function],headerCellClassName:[String,Function],headerCellStyle:[Object,Function],highlightCurrentRow:Boolean,currentRowKey:[String,Number],emptyText:String,expandRowKeys:Array,defaultExpandAll:Boolean,defaultSort:Object,tooltipEffect:String,tooltipOptions:Object,spanMethod:Function,selectOnIndeterminate:{type:Boolean,default:!0},indent:{type:Number,default:16},treeProps:{type:Object,default:()=>({hasChildren:"hasChildren",children:"children"})},lazy:Boolean,load:Function,style:{type:Object,default:()=>({})},className:{type:String,default:""},tableLayout:{type:String,default:"fixed"},scrollbarAlwaysOn:Boolean,flexible:Boolean,showOverflowTooltip:[Boolean,Object]};function h2(e){const t=e.tableLayout==="auto";let n=e.columns||[];t&&n.every(r=>r.width===void 0)&&(n=[]);const o=r=>{const a={key:`${e.tableLayout}_${r.id}`,style:{},name:void 0};return t?a.style={width:`${r.width}px`}:a.name=r.id,a};return Ke("colgroup",{},n.map(r=>Ke("col",o(r))))}h2.props=["columns","tableLayout"];const UX=()=>{const e=R(),t=(a,l)=>{const s=e.value;s&&s.scrollTo(a,l)},n=(a,l)=>{const s=e.value;s&&Je(l)&&["Top","Left"].includes(a)&&s[`setScroll${a}`](l)};return{scrollBarRef:e,scrollTo:t,setScrollTop:a=>n("Top",a),setScrollLeft:a=>n("Left",a)}};let qX=1;const YX=Y({name:"ElTable",directives:{Mousewheel:PV},components:{TableHeader:PX,TableBody:FX,TableFooter:HX,ElScrollbar:ea,hColgroup:h2},props:KX,emits:["select","select-all","selection-change","cell-mouse-enter","cell-mouse-leave","cell-contextmenu","cell-click","cell-dblclick","row-click","row-contextmenu","row-dblclick","header-click","header-contextmenu","sort-change","filter-change","current-change","header-dragend","expand-change"],setup(e){const{t}=$t(),n=Se("table"),o=lt();yt(Mr,o);const r=wX(o,e);o.store=r;const a=new CX({store:o.store,table:o,fit:e.fit,showHeader:e.showHeader});o.layout=a;const l=k(()=>(r.states.data.value||[]).length===0),{setCurrentRow:s,getSelectionRows:u,toggleRowSelection:c,clearSelection:f,clearFilter:d,toggleAllSelection:p,toggleRowExpansion:m,clearSort:v,sort:h}=zX(r),{isHidden:C,renderExpanded:g,setDragVisible:y,isGroup:_,handleMouseLeave:b,handleHeaderFooterMousewheel:w,tableSize:S,emptyBlockStyle:E,handleFixedMousewheel:$,resizeProxyVisible:O,bodyWidth:A,resizeState:M,doLayout:D,tableBodyStyles:U,tableLayout:j,scrollbarViewStyle:W,tableInnerStyle:L,scrollbarStyle:P}=jX(e,a,r,o),{scrollBarRef:x,scrollTo:I,setScrollLeft:H,setScrollTop:G}=UX(),J=co(D,50),ee=`${n.namespace.value}-table_${qX++}`;o.tableId=ee,o.state={isGroup:_,resizeState:M,doLayout:D,debouncedUpdateLayout:J};const fe=k(()=>e.sumText||t("el.table.sumText")),Te=k(()=>e.emptyText||t("el.table.emptyText")),oe=k(()=>p2(r.states.originColumns.value)[0]);return WX(o),{ns:n,layout:a,store:r,columns:oe,handleHeaderFooterMousewheel:w,handleMouseLeave:b,tableId:ee,tableSize:S,isHidden:C,isEmpty:l,renderExpanded:g,resizeProxyVisible:O,resizeState:M,isGroup:_,bodyWidth:A,tableBodyStyles:U,emptyBlockStyle:E,debouncedUpdateLayout:J,handleFixedMousewheel:$,setCurrentRow:s,getSelectionRows:u,toggleRowSelection:c,clearSelection:f,clearFilter:d,toggleAllSelection:p,toggleRowExpansion:m,clearSort:v,doLayout:D,sort:h,t,setDragVisible:y,context:o,computedSumText:fe,computedEmptyText:Te,tableLayout:j,scrollbarViewStyle:W,tableInnerStyle:L,scrollbarStyle:P,scrollBarRef:x,scrollTo:I,setScrollLeft:H,setScrollTop:G}}}),GX=["data-prefix"],XX={ref:"hiddenColumns",class:"hidden-columns"};function JX(e,t,n,o,r,a){const l=qe("hColgroup"),s=qe("table-header"),u=qe("table-body"),c=qe("table-footer"),f=qe("el-scrollbar"),d=qs("mousewheel");return T(),V("div",{ref:"tableWrapper",class:N([{[e.ns.m("fit")]:e.fit,[e.ns.m("striped")]:e.stripe,[e.ns.m("border")]:e.border||e.isGroup,[e.ns.m("hidden")]:e.isHidden,[e.ns.m("group")]:e.isGroup,[e.ns.m("fluid-height")]:e.maxHeight,[e.ns.m("scrollable-x")]:e.layout.scrollX.value,[e.ns.m("scrollable-y")]:e.layout.scrollY.value,[e.ns.m("enable-row-hover")]:!e.store.states.isComplex.value,[e.ns.m("enable-row-transition")]:(e.store.states.data.value||[]).length!==0&&(e.store.states.data.value||[]).length<100,"has-footer":e.showSummary},e.ns.m(e.tableSize),e.className,e.ns.b(),e.ns.m(`layout-${e.tableLayout}`)]),style:je(e.style),"data-prefix":e.ns.namespace.value,onMouseleave:t[0]||(t[0]=(...p)=>e.handleMouseLeave&&e.handleMouseLeave(...p))},[F("div",{class:N(e.ns.e("inner-wrapper")),style:je(e.tableInnerStyle)},[F("div",XX,[ie(e.$slots,"default")],512),e.showHeader&&e.tableLayout==="fixed"?tt((T(),V("div",{key:0,ref:"headerWrapper",class:N(e.ns.e("header-wrapper"))},[F("table",{ref:"tableHeader",class:N(e.ns.e("header")),style:je(e.tableBodyStyles),border:"0",cellpadding:"0",cellspacing:"0"},[K(l,{columns:e.store.states.columns.value,"table-layout":e.tableLayout},null,8,["columns","table-layout"]),K(s,{ref:"tableHeaderRef",border:e.border,"default-sort":e.defaultSort,store:e.store,onSetDragVisible:e.setDragVisible},null,8,["border","default-sort","store","onSetDragVisible"])],6)],2)),[[d,e.handleHeaderFooterMousewheel]]):te("v-if",!0),F("div",{ref:"bodyWrapper",class:N(e.ns.e("body-wrapper"))},[K(f,{ref:"scrollBarRef","view-style":e.scrollbarViewStyle,"wrap-style":e.scrollbarStyle,always:e.scrollbarAlwaysOn},{default:X(()=>[F("table",{ref:"tableBody",class:N(e.ns.e("body")),cellspacing:"0",cellpadding:"0",border:"0",style:je({width:e.bodyWidth,tableLayout:e.tableLayout})},[K(l,{columns:e.store.states.columns.value,"table-layout":e.tableLayout},null,8,["columns","table-layout"]),e.showHeader&&e.tableLayout==="auto"?(T(),re(s,{key:0,ref:"tableHeaderRef",class:N(e.ns.e("body-header")),border:e.border,"default-sort":e.defaultSort,store:e.store,onSetDragVisible:e.setDragVisible},null,8,["class","border","default-sort","store","onSetDragVisible"])):te("v-if",!0),K(u,{context:e.context,highlight:e.highlightCurrentRow,"row-class-name":e.rowClassName,"tooltip-effect":e.tooltipEffect,"tooltip-options":e.tooltipOptions,"row-style":e.rowStyle,store:e.store,stripe:e.stripe},null,8,["context","highlight","row-class-name","tooltip-effect","tooltip-options","row-style","store","stripe"]),e.showSummary&&e.tableLayout==="auto"?(T(),re(c,{key:1,class:N(e.ns.e("body-footer")),border:e.border,"default-sort":e.defaultSort,store:e.store,"sum-text":e.computedSumText,"summary-method":e.summaryMethod},null,8,["class","border","default-sort","store","sum-text","summary-method"])):te("v-if",!0)],6),e.isEmpty?(T(),V("div",{key:0,ref:"emptyBlock",style:je(e.emptyBlockStyle),class:N(e.ns.e("empty-block"))},[F("span",{class:N(e.ns.e("empty-text"))},[ie(e.$slots,"empty",{},()=>[Ge(le(e.computedEmptyText),1)])],2)],6)):te("v-if",!0),e.$slots.append?(T(),V("div",{key:1,ref:"appendWrapper",class:N(e.ns.e("append-wrapper"))},[ie(e.$slots,"append")],2)):te("v-if",!0)]),_:3},8,["view-style","wrap-style","always"])],2),e.showSummary&&e.tableLayout==="fixed"?tt((T(),V("div",{key:1,ref:"footerWrapper",class:N(e.ns.e("footer-wrapper"))},[F("table",{class:N(e.ns.e("footer")),cellspacing:"0",cellpadding:"0",border:"0",style:je(e.tableBodyStyles)},[K(l,{columns:e.store.states.columns.value,"table-layout":e.tableLayout},null,8,["columns","table-layout"]),K(c,{border:e.border,"default-sort":e.defaultSort,store:e.store,"sum-text":e.computedSumText,"summary-method":e.summaryMethod},null,8,["border","default-sort","store","sum-text","summary-method"])],6)],2)),[[kt,!e.isEmpty],[d,e.handleHeaderFooterMousewheel]]):te("v-if",!0),e.border||e.isGroup?(T(),V("div",{key:2,class:N(e.ns.e("border-left-patch"))},null,2)):te("v-if",!0)],6),tt(F("div",{ref:"resizeProxy",class:N(e.ns.e("column-resize-proxy"))},null,2),[[kt,e.resizeProxyVisible]])],46,GX)}var ZX=Ie(YX,[["render",JX],["__file","table.vue"]]);const QX={selection:"table-column--selection",expand:"table__expand-column"},eJ={default:{order:""},selection:{width:48,minWidth:48,realWidth:48,order:""},expand:{width:48,minWidth:48,realWidth:48,order:""},index:{width:48,minWidth:48,realWidth:48,order:""}},tJ=e=>QX[e]||"",nJ={selection:{renderHeader({store:e,column:t}){function n(){return e.states.data.value&&e.states.data.value.length===0}return Ke(Ho,{disabled:n(),size:e.states.tableSize.value,indeterminate:e.states.selection.value.length>0&&!e.states.isAllSelected.value,"onUpdate:modelValue":e.toggleAllSelection,modelValue:e.states.isAllSelected.value,ariaLabel:t.label})},renderCell({row:e,column:t,store:n,$index:o}){return Ke(Ho,{disabled:t.selectable?!t.selectable.call(null,e,o):!1,size:n.states.tableSize.value,onChange:()=>{n.commit("rowSelectedChanged",e)},onClick:r=>r.stopPropagation(),modelValue:n.isSelected(e),ariaLabel:t.label})},sortable:!1,resizable:!1},index:{renderHeader({column:e}){return e.label||"#"},renderCell({column:e,$index:t}){let n=t+1;const o=e.index;return typeof o=="number"?n=t+o:typeof o=="function"&&(n=o(t)),Ke("div",{},[n])},sortable:!1},expand:{renderHeader({column:e}){return e.label||""},renderCell({row:e,store:t,expanded:n}){const{ns:o}=t,r=[o.e("expand-icon")];return n&&r.push(o.em("expand-icon","expanded")),Ke("div",{class:r,onClick:function(l){l.stopPropagation(),t.toggleRowExpansion(e)}},{default:()=>[Ke(ze,null,{default:()=>[Ke(Jn)]})]})},sortable:!1,resizable:!1}};function oJ({row:e,column:t,$index:n}){var o;const r=t.property,a=r&&Mc(e,r).value;return t&&t.formatter?t.formatter(e,t,a,n):((o=a==null?void 0:a.toString)==null?void 0:o.call(a))||""}function rJ({row:e,treeNode:t,store:n},o=!1){const{ns:r}=n;if(!t)return o?[Ke("span",{class:r.e("placeholder")})]:null;const a=[],l=function(s){s.stopPropagation(),!t.loading&&n.loadOrToggle(e)};if(t.indent&&a.push(Ke("span",{class:r.e("indent"),style:{"padding-left":`${t.indent}px`}})),typeof t.expanded=="boolean"&&!t.noLazyChildren){const s=[r.e("expand-icon"),t.expanded?r.em("expand-icon","expanded"):""];let u=Jn;t.loading&&(u=Er),a.push(Ke("div",{class:s,onClick:l},{default:()=>[Ke(ze,{class:{[r.is("loading")]:t.loading}},{default:()=>[Ke(u)]})]}))}else a.push(Ke("span",{class:r.e("placeholder")}));return a}function w1(e,t){return e.reduce((n,o)=>(n[o]=o,n),t)}function aJ(e,t){const n=lt();return{registerComplexWatchers:()=>{const a=["fixed"],l={realWidth:"width",realMinWidth:"minWidth"},s=w1(a,l);Object.keys(s).forEach(u=>{const c=l[u];Tt(t,c)&&ve(()=>t[c],f=>{let d=f;c==="width"&&u==="realWidth"&&(d=Tg(f)),c==="minWidth"&&u==="realMinWidth"&&(d=l2(f)),n.columnConfig.value[c]=d,n.columnConfig.value[u]=d;const p=c==="fixed";e.value.store.scheduleLayout(p)})})},registerNormalWatchers:()=>{const a=["label","filters","filterMultiple","filteredValue","sortable","index","formatter","className","labelClassName","filterClassName","showOverflowTooltip"],l={property:"prop",align:"realAlign",headerAlign:"realHeaderAlign"},s=w1(a,l);Object.keys(s).forEach(u=>{const c=l[u];Tt(t,c)&&ve(()=>t[c],f=>{n.columnConfig.value[u]=f})})}}}function lJ(e,t,n){const o=lt(),r=R(""),a=R(!1),l=R(),s=R(),u=Se("table");Mn(()=>{l.value=e.align?`is-${e.align}`:null,l.value}),Mn(()=>{s.value=e.headerAlign?`is-${e.headerAlign}`:l.value,s.value});const c=k(()=>{let b=o.vnode.vParent||o.parent;for(;b&&!b.tableId&&!b.columnId;)b=b.vnode.vParent||b.parent;return b}),f=k(()=>{const{store:b}=o.parent;if(!b)return!1;const{treeData:w}=b.states,S=w.value;return S&&Object.keys(S).length>0}),d=R(Tg(e.width)),p=R(l2(e.minWidth)),m=b=>(d.value&&(b.width=d.value),p.value&&(b.minWidth=p.value),!d.value&&p.value&&(b.width=void 0),b.minWidth||(b.minWidth=80),b.realWidth=Number(b.width===void 0?b.minWidth:b.width),b),v=b=>{const w=b.type,S=nJ[w]||{};Object.keys(S).forEach($=>{const O=S[$];$!=="className"&&O!==void 0&&(b[$]=O)});const E=tJ(w);if(E){const $=`${i(u.namespace)}-${E}`;b.className=b.className?`${b.className} ${$}`:$}return b},h=b=>{Array.isArray(b)?b.forEach(S=>w(S)):w(b);function w(S){var E;((E=S==null?void 0:S.type)==null?void 0:E.name)==="ElTableColumn"&&(S.vParent=o)}};return{columnId:r,realAlign:l,isSubColumn:a,realHeaderAlign:s,columnOrTableParent:c,setColumnWidth:m,setColumnForcedProps:v,setColumnRenders:b=>{e.renderHeader||b.type!=="selection"&&(b.renderHeader=S=>(o.columnConfig.value.label,ie(t,"header",S,()=>[b.label]))),t["filter-icon"]&&(b.renderFilterIcon=S=>ie(t,"filter-icon",S));let w=b.renderCell;return b.type==="expand"?(b.renderCell=S=>Ke("div",{class:"cell"},[w(S)]),n.value.renderExpanded=S=>t.default?t.default(S):t.default):(w=w||oJ,b.renderCell=S=>{let E=null;if(t.default){const U=t.default(S);E=U.some(j=>j.type!==En)?U:w(S)}else E=w(S);const{columns:$}=n.value.store.states,O=$.value.findIndex(U=>U.type==="default"),A=f.value&&S.cellIndex===O,M=rJ(S,A),D={class:"cell",style:{}};return b.showOverflowTooltip&&(D.class=`${D.class} ${i(u.namespace)}-tooltip`,D.style={width:`${(S.column.realWidth||Number(S.column.width))-1}px`}),h(E),Ke("div",D,[M,E])}),b},getPropsData:(...b)=>b.reduce((w,S)=>(Array.isArray(S)&&S.forEach(E=>{w[E]=e[E]}),w),{}),getColumnElIndex:(b,w)=>Array.prototype.indexOf.call(b,w),updateColumnOrder:()=>{n.value.store.commit("updateColumnOrder",o.columnConfig.value)}}}var sJ={type:{type:String,default:"default"},label:String,className:String,labelClassName:String,property:String,prop:String,width:{type:[String,Number],default:""},minWidth:{type:[String,Number],default:""},renderHeader:Function,sortable:{type:[Boolean,String],default:!1},sortMethod:Function,sortBy:[String,Function,Array],resizable:{type:Boolean,default:!0},columnKey:String,align:String,headerAlign:String,showOverflowTooltip:{type:[Boolean,Object],default:void 0},fixed:[Boolean,String],formatter:Function,selectable:Function,reserveSelection:Boolean,filterMethod:Function,filteredValue:Array,filters:Array,filterPlacement:String,filterMultiple:{type:Boolean,default:!0},filterClassName:String,index:[Number,Function],sortOrders:{type:Array,default:()=>["ascending","descending",null],validator:e=>e.every(t=>["ascending","descending",null].includes(t))}};let iJ=1;var m2=Y({name:"ElTableColumn",components:{ElCheckbox:Ho},props:sJ,setup(e,{slots:t}){const n=lt(),o=R({}),r=k(()=>{let _=n.parent;for(;_&&!_.tableId;)_=_.parent;return _}),{registerNormalWatchers:a,registerComplexWatchers:l}=aJ(r,e),{columnId:s,isSubColumn:u,realHeaderAlign:c,columnOrTableParent:f,setColumnWidth:d,setColumnForcedProps:p,setColumnRenders:m,getPropsData:v,getColumnElIndex:h,realAlign:C,updateColumnOrder:g}=lJ(e,t,r),y=f.value;s.value=`${y.tableId||y.columnId}_column_${iJ++}`,Su(()=>{u.value=r.value!==y;const _=e.type||"default",b=e.sortable===""?!0:e.sortable,w=pn(e.showOverflowTooltip)?y.props.showOverflowTooltip:e.showOverflowTooltip,S={...eJ[_],id:s.value,type:_,property:e.prop||e.property,align:C,headerAlign:c,showOverflowTooltip:w,filterable:e.filters||e.filterMethod,filteredValue:[],filterPlacement:"",filterClassName:"",isColumnGroup:!1,isSubColumn:!1,filterOpened:!1,sortable:b,index:e.index,rawColumnKey:n.vnode.key};let M=v(["columnKey","label","className","labelClassName","type","renderHeader","formatter","fixed","resizable"],["sortMethod","sortBy","sortOrders"],["selectable","reserveSelection"],["filterMethod","filters","filterMultiple","filterOpened","filteredValue","filterPlacement","filterClassName"]);M=uX(S,M),M=dX(m,d,p)(M),o.value=M,a(),l()}),at(()=>{var _;const b=f.value,w=u.value?b.vnode.el.children:(_=b.refs.hiddenColumns)==null?void 0:_.children,S=()=>h(w||[],n.vnode.el);o.value.getColumnIndex=S,S()>-1&&r.value.store.commit("insertColumn",o.value,u.value?b.columnConfig.value:null,g)}),zt(()=>{o.value.getColumnIndex()>-1&&r.value.store.commit("removeColumn",o.value,u.value?y.columnConfig.value:null,g)}),n.columnId=s.value,n.columnConfig=o},render(){var e,t,n;try{const o=(t=(e=this.$slots).default)==null?void 0:t.call(e,{row:{},column:{},$index:-1}),r=[];if(Array.isArray(o))for(const l of o)((n=l.type)==null?void 0:n.name)==="ElTableColumn"||l.shapeFlag&2?r.push(l):l.type===Ve&&Array.isArray(l.children)&&l.children.forEach(s=>{(s==null?void 0:s.patchFlag)!==1024&&!nt(s==null?void 0:s.children)&&r.push(s)});return Ke("div",r)}catch{return Ke("div",[])}}});const uJ=ut(ZX,{TableColumn:m2}),cJ=tn(m2);var pu=(e=>(e.ASC="asc",e.DESC="desc",e))(pu||{}),hu=(e=>(e.CENTER="center",e.RIGHT="right",e))(hu||{}),v2=(e=>(e.LEFT="left",e.RIGHT="right",e))(v2||{});const am={asc:"desc",desc:"asc"},mu=Symbol("placeholder"),dJ=(e,t,n)=>{var o;const r={flexGrow:0,flexShrink:0,...n?{}:{flexGrow:e.flexGrow||0,flexShrink:e.flexShrink||1}};n||(r.flexShrink=1);const a={...(o=e.style)!=null?o:{},...r,flexBasis:"auto",width:e.width};return t||(e.maxWidth&&(a.maxWidth=e.maxWidth),e.minWidth&&(a.minWidth=e.minWidth)),a};function fJ(e,t,n){const o=k(()=>i(t).filter(h=>!h.hidden)),r=k(()=>i(o).filter(h=>h.fixed==="left"||h.fixed===!0)),a=k(()=>i(o).filter(h=>h.fixed==="right")),l=k(()=>i(o).filter(h=>!h.fixed)),s=k(()=>{const h=[];return i(r).forEach(C=>{h.push({...C,placeholderSign:mu})}),i(l).forEach(C=>{h.push(C)}),i(a).forEach(C=>{h.push({...C,placeholderSign:mu})}),h}),u=k(()=>i(r).length||i(a).length),c=k(()=>i(t).reduce((C,g)=>(C[g.key]=dJ(g,i(n),e.fixed),C),{})),f=k(()=>i(o).reduce((h,C)=>h+C.width,0)),d=h=>i(t).find(C=>C.key===h),p=h=>i(c)[h],m=(h,C)=>{h.width=C};function v(h){var C;const{key:g}=h.currentTarget.dataset;if(!g)return;const{sortState:y,sortBy:_}=e;let b=pu.ASC;dt(y)?b=am[y[g]]:b=am[_.order],(C=e.onColumnSort)==null||C.call(e,{column:d(g),key:g,order:b})}return{columns:t,columnsStyles:c,columnsTotalWidth:f,fixedColumnsOnLeft:r,fixedColumnsOnRight:a,hasFixedColumns:u,mainColumns:s,normalColumns:l,visibleColumns:o,getColumn:d,getColumnStyle:p,updateColumnWidth:m,onColumnSorted:v}}const pJ=(e,{mainTableRef:t,leftTableRef:n,rightTableRef:o,onMaybeEndReached:r})=>{const a=R({scrollLeft:0,scrollTop:0});function l(m){var v,h,C;const{scrollTop:g}=m;(v=t.value)==null||v.scrollTo(m),(h=n.value)==null||h.scrollToTop(g),(C=o.value)==null||C.scrollToTop(g)}function s(m){a.value=m,l(m)}function u(m){a.value.scrollTop=m,l(i(a))}function c(m){var v,h;a.value.scrollLeft=m,(h=(v=t.value)==null?void 0:v.scrollTo)==null||h.call(v,i(a))}function f(m){var v;s(m),(v=e.onScroll)==null||v.call(e,m)}function d({scrollTop:m}){const{scrollTop:v}=i(a);m!==v&&u(m)}function p(m,v="auto"){var h;(h=t.value)==null||h.scrollToRow(m,v)}return ve(()=>i(a).scrollTop,(m,v)=>{m>v&&r()}),{scrollPos:a,scrollTo:s,scrollToLeft:c,scrollToTop:u,scrollToRow:p,onScroll:f,onVerticalScroll:d}},hJ=(e,{mainTableRef:t,leftTableRef:n,rightTableRef:o,tableInstance:r,ns:a,isScrolling:l})=>{const s=lt(),{emit:u}=s,c=Ut(!1),f=R(e.defaultExpandedRowKeys||[]),d=R(-1),p=Ut(null),m=R({}),v=R({}),h=Ut({}),C=Ut({}),g=Ut({}),y=k(()=>Je(e.estimatedRowHeight));function _(A){var M;(M=e.onRowsRendered)==null||M.call(e,A),A.rowCacheEnd>i(d)&&(d.value=A.rowCacheEnd)}function b({hovered:A,rowKey:M}){if(l.value)return;r.vnode.el.querySelectorAll(`[rowkey="${String(M)}"]`).forEach(j=>{A?j.classList.add(a.is("hovered")):j.classList.remove(a.is("hovered"))})}function w({expanded:A,rowData:M,rowIndex:D,rowKey:U}){var j,W;const L=[...i(f)],P=L.indexOf(U);A?P===-1&&L.push(U):P>-1&&L.splice(P,1),f.value=L,u("update:expandedRowKeys",L),(j=e.onRowExpand)==null||j.call(e,{expanded:A,rowData:M,rowIndex:D,rowKey:U}),(W=e.onExpandedRowsChange)==null||W.call(e,L)}const S=co(()=>{var A,M,D,U;c.value=!0,m.value={...i(m),...i(v)},E(i(p),!1),v.value={},p.value=null,(A=t.value)==null||A.forceUpdate(),(M=n.value)==null||M.forceUpdate(),(D=o.value)==null||D.forceUpdate(),(U=s.proxy)==null||U.$forceUpdate(),c.value=!1},0);function E(A,M=!1){i(y)&&[t,n,o].forEach(D=>{const U=i(D);U&&U.resetAfterRowIndex(A,M)})}function $(A,M,D){const U=i(p);(U===null||U>D)&&(p.value=D),v.value[A]=M}function O({rowKey:A,height:M,rowIndex:D},U){U?U===v2.RIGHT?g.value[A]=M:h.value[A]=M:C.value[A]=M;const j=Math.max(...[h,g,C].map(W=>W.value[A]||0));i(m)[A]!==j&&($(A,j,D),S())}return{expandedRowKeys:f,lastRenderedRowIndex:d,isDynamic:y,isResetting:c,rowHeights:m,resetAfterIndex:E,onRowExpanded:w,onRowHovered:b,onRowsRendered:_,onRowHeightChange:O}},mJ=(e,{expandedRowKeys:t,lastRenderedRowIndex:n,resetAfterIndex:o})=>{const r=R({}),a=k(()=>{const s={},{data:u,rowKey:c}=e,f=i(t);if(!f||!f.length)return u;const d=[],p=new Set;f.forEach(v=>p.add(v));let m=u.slice();for(m.forEach(v=>s[v[c]]=0);m.length>0;){const v=m.shift();d.push(v),p.has(v[c])&&Array.isArray(v.children)&&v.children.length>0&&(m=[...v.children,...m],v.children.forEach(h=>s[h[c]]=s[v[c]]+1))}return r.value=s,d}),l=k(()=>{const{data:s,expandColumnKey:u}=e;return u?i(a):s});return ve(l,(s,u)=>{s!==u&&(n.value=-1,o(0,!0))}),{data:l,depthMap:r}},vJ=(e,t)=>e+t,Uc=e=>Pe(e)?e.reduce(vJ,0):e,Nl=(e,t,n={})=>Xe(e)?e(t):e??n,ya=e=>(["width","maxWidth","minWidth","height"].forEach(t=>{e[t]=rn(e[t])}),e),g2=e=>Wt(e)?t=>Ke(e,t):e,gJ=(e,{columnsTotalWidth:t,data:n,fixedColumnsOnLeft:o,fixedColumnsOnRight:r})=>{const a=k(()=>{const{fixed:_,width:b,vScrollbarSize:w}=e,S=b-w;return _?Math.max(Math.round(i(t)),S):S}),l=k(()=>i(a)+e.vScrollbarSize),s=k(()=>{const{height:_=0,maxHeight:b=0,footerHeight:w,hScrollbarSize:S}=e;if(b>0){const E=i(v),$=i(u),A=i(m)+E+$+S;return Math.min(A,b-w)}return _-w}),u=k(()=>{const{rowHeight:_,estimatedRowHeight:b}=e,w=i(n);return Je(b)?w.length*b:w.length*_}),c=k(()=>{const{maxHeight:_}=e,b=i(s);if(Je(_)&&_>0)return b;const w=i(u)+i(m)+i(v);return Math.min(b,w)}),f=_=>_.width,d=k(()=>Uc(i(o).map(f))),p=k(()=>Uc(i(r).map(f))),m=k(()=>Uc(e.headerHeight)),v=k(()=>{var _;return(((_=e.fixedData)==null?void 0:_.length)||0)*e.rowHeight}),h=k(()=>i(s)-i(m)-i(v)),C=k(()=>{const{style:_={},height:b,width:w}=e;return ya({..._,height:b,width:w})}),g=k(()=>ya({height:e.footerHeight})),y=k(()=>({top:rn(i(m)),bottom:rn(e.footerHeight),width:rn(e.width)}));return{bodyWidth:a,fixedTableHeight:c,mainTableHeight:s,leftTableWidth:d,rightTableWidth:p,headerWidth:l,rowsHeight:u,windowHeight:h,footerHeight:g,emptyStyle:y,rootStyle:C,headerHeight:m}},bJ=e=>{const t=R(),n=R(0),o=R(0);let r;return at(()=>{r=Qt(t,([a])=>{const{width:l,height:s}=a.contentRect,{paddingLeft:u,paddingRight:c,paddingTop:f,paddingBottom:d}=getComputedStyle(a.target),p=Number.parseInt(u)||0,m=Number.parseInt(c)||0,v=Number.parseInt(f)||0,h=Number.parseInt(d)||0;n.value=l-p-m,o.value=s-v-h}).stop}),zt(()=>{r==null||r()}),ve([n,o],([a,l])=>{var s;(s=e.onResize)==null||s.call(e,{width:a,height:l})}),{sizer:t,width:n,height:o}};function yJ(e){const t=R(),n=R(),o=R(),{columns:r,columnsStyles:a,columnsTotalWidth:l,fixedColumnsOnLeft:s,fixedColumnsOnRight:u,hasFixedColumns:c,mainColumns:f,onColumnSorted:d}=fJ(e,Lt(e,"columns"),Lt(e,"fixed")),{scrollTo:p,scrollToLeft:m,scrollToTop:v,scrollToRow:h,onScroll:C,onVerticalScroll:g,scrollPos:y}=pJ(e,{mainTableRef:t,leftTableRef:n,rightTableRef:o,onMaybeEndReached:B}),_=Se("table-v2"),b=lt(),w=Ut(!1),{expandedRowKeys:S,lastRenderedRowIndex:E,isDynamic:$,isResetting:O,rowHeights:A,resetAfterIndex:M,onRowExpanded:D,onRowHeightChange:U,onRowHovered:j,onRowsRendered:W}=hJ(e,{mainTableRef:t,leftTableRef:n,rightTableRef:o,tableInstance:b,ns:_,isScrolling:w}),{data:L,depthMap:P}=mJ(e,{expandedRowKeys:S,lastRenderedRowIndex:E,resetAfterIndex:M}),{bodyWidth:x,fixedTableHeight:I,mainTableHeight:H,leftTableWidth:G,rightTableWidth:J,headerWidth:ee,rowsHeight:fe,windowHeight:Te,footerHeight:oe,emptyStyle:ke,rootStyle:ae,headerHeight:Oe}=gJ(e,{columnsTotalWidth:l,data:L,fixedColumnsOnLeft:s,fixedColumnsOnRight:u}),we=R(),ge=k(()=>{const z=i(L).length===0;return Pe(e.fixedData)?e.fixedData.length===0&&z:z});function q(z){const{estimatedRowHeight:Z,rowHeight:ue,rowKey:se}=e;return Z?i(A)[i(L)[z][se]]||Z:ue}function B(){const{onEndReached:z}=e;if(!z)return;const{scrollTop:Z}=i(y),ue=i(fe),se=i(Te),me=ue-(Z+se)+e.hScrollbarSize;i(E)>=0&&ue===Z+i(H)-i(Oe)&&z(me)}return ve(()=>e.expandedRowKeys,z=>S.value=z,{deep:!0}),{columns:r,containerRef:we,mainTableRef:t,leftTableRef:n,rightTableRef:o,isDynamic:$,isResetting:O,isScrolling:w,hasFixedColumns:c,columnsStyles:a,columnsTotalWidth:l,data:L,expandedRowKeys:S,depthMap:P,fixedColumnsOnLeft:s,fixedColumnsOnRight:u,mainColumns:f,bodyWidth:x,emptyStyle:ke,rootStyle:ae,headerWidth:ee,footerHeight:oe,mainTableHeight:H,fixedTableHeight:I,leftTableWidth:G,rightTableWidth:J,showEmpty:ge,getRowHeight:q,onColumnSorted:d,onRowHovered:j,onRowExpanded:D,onRowsRendered:W,onRowHeightChange:U,scrollTo:p,scrollToLeft:m,scrollToTop:v,scrollToRow:h,onScroll:C,onVerticalScroll:g}}const Ng=Symbol("tableV2"),b2=String,Bu={type:Q(Array),required:!0},Ig={type:Q(Array)},y2={...Ig,required:!0},wJ=String,_1={type:Q(Array),default:()=>en([])},Xa={type:Number,required:!0},w2={type:Q([String,Number,Symbol]),default:"id"},C1={type:Q(Object)},ol=Ne({class:String,columns:Bu,columnsStyles:{type:Q(Object),required:!0},depth:Number,expandColumnKey:wJ,estimatedRowHeight:{...dl.estimatedRowHeight,default:void 0},isScrolling:Boolean,onRowExpand:{type:Q(Function)},onRowHover:{type:Q(Function)},onRowHeightChange:{type:Q(Function)},rowData:{type:Q(Object),required:!0},rowEventHandlers:{type:Q(Object)},rowIndex:{type:Number,required:!0},rowKey:w2,style:{type:Q(Object)}}),Np={type:Number,required:!0},Mg=Ne({class:String,columns:Bu,fixedHeaderData:{type:Q(Array)},headerData:{type:Q(Array),required:!0},headerHeight:{type:Q([Number,Array]),default:50},rowWidth:Np,rowHeight:{type:Number,default:50},height:Np,width:Np}),qc=Ne({columns:Bu,data:y2,fixedData:Ig,estimatedRowHeight:ol.estimatedRowHeight,width:Xa,height:Xa,headerWidth:Xa,headerHeight:Mg.headerHeight,bodyWidth:Xa,rowHeight:Xa,cache:HE.cache,useIsScrolling:Boolean,scrollbarAlwaysOn:dl.scrollbarAlwaysOn,scrollbarStartGap:dl.scrollbarStartGap,scrollbarEndGap:dl.scrollbarEndGap,class:b2,style:C1,containerStyle:C1,getRowHeight:{type:Q(Function),required:!0},rowKey:ol.rowKey,onRowsRendered:{type:Q(Function)},onScroll:{type:Q(Function)}}),_J=Ne({cache:qc.cache,estimatedRowHeight:ol.estimatedRowHeight,rowKey:w2,headerClass:{type:Q([String,Function])},headerProps:{type:Q([Object,Function])},headerCellProps:{type:Q([Object,Function])},headerHeight:Mg.headerHeight,footerHeight:{type:Number,default:0},rowClass:{type:Q([String,Function])},rowProps:{type:Q([Object,Function])},rowHeight:{type:Number,default:50},cellProps:{type:Q([Object,Function])},columns:Bu,data:y2,dataGetter:{type:Q(Function)},fixedData:Ig,expandColumnKey:ol.expandColumnKey,expandedRowKeys:_1,defaultExpandedRowKeys:_1,class:b2,fixed:Boolean,style:{type:Q(Object)},width:Xa,height:Xa,maxHeight:Number,useIsScrolling:Boolean,indentSize:{type:Number,default:12},iconSize:{type:Number,default:12},hScrollbarSize:dl.hScrollbarSize,vScrollbarSize:dl.vScrollbarSize,scrollbarAlwaysOn:WE.alwaysOn,sortBy:{type:Q(Object),default:()=>({})},sortState:{type:Q(Object),default:void 0},onColumnSort:{type:Q(Function)},onExpandedRowsChange:{type:Q(Function)},onEndReached:{type:Q(Function)},onRowExpand:ol.onRowExpand,onScroll:qc.onScroll,onRowsRendered:qc.onRowsRendered,rowEventHandlers:ol.rowEventHandlers}),Ag=(e,{slots:t})=>{var n;const{cellData:o,style:r}=e,a=((n=o==null?void 0:o.toString)==null?void 0:n.call(o))||"",l=ie(t,"default",e,()=>[a]);return K("div",{class:e.class,title:a,style:r},[l])};Ag.displayName="ElTableV2Cell";Ag.inheritAttrs=!1;const Pg=(e,{slots:t})=>ie(t,"default",e,()=>{var n,o;return[K("div",{class:e.class,title:(n=e.column)==null?void 0:n.title},[(o=e.column)==null?void 0:o.title])]});Pg.displayName="ElTableV2HeaderCell";Pg.inheritAttrs=!1;const CJ=Ne({class:String,columns:Bu,columnsStyles:{type:Q(Object),required:!0},headerIndex:Number,style:{type:Q(Object)}}),SJ=Y({name:"ElTableV2HeaderRow",props:CJ,setup(e,{slots:t}){return()=>{const{columns:n,columnsStyles:o,headerIndex:r,style:a}=e;let l=n.map((s,u)=>t.cell({columns:n,column:s,columnIndex:u,headerIndex:r,style:o[s.key]}));return t.header&&(l=t.header({cells:l.map(s=>Pe(s)&&s.length===1?s[0]:s),columns:n,headerIndex:r})),K("div",{class:e.class,style:a,role:"row"},[l])}}}),kJ="ElTableV2Header",EJ=Y({name:kJ,props:Mg,setup(e,{slots:t,expose:n}){const o=Se("table-v2"),r=R(),a=k(()=>ya({width:e.width,height:e.height})),l=k(()=>ya({width:e.rowWidth,height:e.height})),s=k(()=>Ia(i(e.headerHeight))),u=d=>{const p=i(r);We(()=>{p!=null&&p.scroll&&p.scroll({left:d})})},c=()=>{const d=o.e("fixed-header-row"),{columns:p,fixedHeaderData:m,rowHeight:v}=e;return m==null?void 0:m.map((h,C)=>{var g;const y=ya({height:v,width:"100%"});return(g=t.fixed)==null?void 0:g.call(t,{class:d,columns:p,rowData:h,rowIndex:-(C+1),style:y})})},f=()=>{const d=o.e("dynamic-header-row"),{columns:p}=e;return i(s).map((m,v)=>{var h;const C=ya({width:"100%",height:m});return(h=t.dynamic)==null?void 0:h.call(t,{class:d,columns:p,headerIndex:v,style:C})})};return n({scrollToLeft:u}),()=>{if(!(e.height<=0))return K("div",{ref:r,class:e.class,style:i(a),role:"rowgroup"},[K("div",{style:i(l),class:o.e("header")},[f(),c()])])}}}),TJ=e=>{const{isScrolling:t}=De(Ng),n=R(!1),o=R(),r=k(()=>Je(e.estimatedRowHeight)&&e.rowIndex>=0),a=(u=!1)=>{const c=i(o);if(!c)return;const{columns:f,onRowHeightChange:d,rowKey:p,rowIndex:m,style:v}=e,{height:h}=c.getBoundingClientRect();n.value=!0,We(()=>{if(u||h!==Number.parseInt(v.height)){const C=f[0],g=(C==null?void 0:C.placeholderSign)===mu;d==null||d({rowKey:p,height:h,rowIndex:m},C&&!g&&C.fixed)}})},l=k(()=>{const{rowData:u,rowIndex:c,rowKey:f,onRowHover:d}=e,p=e.rowEventHandlers||{},m={};return Object.entries(p).forEach(([v,h])=>{Xe(h)&&(m[v]=C=>{h({event:C,rowData:u,rowIndex:c,rowKey:f})})}),d&&[{name:"onMouseleave",hovered:!1},{name:"onMouseenter",hovered:!0}].forEach(({name:v,hovered:h})=>{const C=m[v];m[v]=g=>{d({event:g,hovered:h,rowData:u,rowIndex:c,rowKey:f}),C==null||C(g)}}),m}),s=u=>{const{onRowExpand:c,rowData:f,rowIndex:d,rowKey:p}=e;c==null||c({expanded:u,rowData:f,rowIndex:d,rowKey:p})};return at(()=>{i(r)&&a(!0)}),{isScrolling:t,measurable:r,measured:n,rowRef:o,eventHandlers:l,onExpand:s}},$J="ElTableV2TableRow",OJ=Y({name:$J,props:ol,setup(e,{expose:t,slots:n,attrs:o}){const{eventHandlers:r,isScrolling:a,measurable:l,measured:s,rowRef:u,onExpand:c}=TJ(e);return t({onExpand:c}),()=>{const{columns:f,columnsStyles:d,expandColumnKey:p,depth:m,rowData:v,rowIndex:h,style:C}=e;let g=f.map((y,_)=>{const b=Pe(v.children)&&v.children.length>0&&y.key===p;return n.cell({column:y,columns:f,columnIndex:_,depth:m,style:d[y.key],rowData:v,rowIndex:h,isScrolling:i(a),expandIconProps:b?{rowData:v,rowIndex:h,onExpand:c}:void 0})});if(n.row&&(g=n.row({cells:g.map(y=>Pe(y)&&y.length===1?y[0]:y),style:C,columns:f,depth:m,rowData:v,rowIndex:h,isScrolling:i(a)})),i(l)){const{height:y,..._}=C||{},b=i(s);return K("div",mt({ref:u,class:e.class,style:b?C:_,role:"row"},o,i(r)),[g])}return K("div",mt(o,{ref:u,class:e.class,style:C,role:"row"},i(r)),[g])}}}),NJ=e=>{const{sortOrder:t}=e;return K(ze,{size:14,class:e.class},{default:()=>[t===pu.ASC?K(X4,null,null):K(Y4,null,null)]})},IJ=e=>{const{expanded:t,expandable:n,onExpand:o,style:r,size:a}=e,l={onClick:n?()=>o(!t):void 0,class:e.class};return K(ze,mt(l,{size:a,style:r}),{default:()=>[K(Jn,null,null)]})},MJ="ElTableV2Grid",AJ=e=>{const t=R(),n=R(),o=k(()=>{const{data:h,rowHeight:C,estimatedRowHeight:g}=e;if(!g)return h.length*C}),r=k(()=>{const{fixedData:h,rowHeight:C}=e;return((h==null?void 0:h.length)||0)*C}),a=k(()=>Uc(e.headerHeight)),l=k(()=>{const{height:h}=e;return Math.max(0,h-i(a)-i(r))}),s=k(()=>i(a)+i(r)>0),u=({data:h,rowIndex:C})=>h[C][e.rowKey];function c({rowCacheStart:h,rowCacheEnd:C,rowVisibleStart:g,rowVisibleEnd:y}){var _;(_=e.onRowsRendered)==null||_.call(e,{rowCacheStart:h,rowCacheEnd:C,rowVisibleStart:g,rowVisibleEnd:y})}function f(h,C){var g;(g=n.value)==null||g.resetAfterRowIndex(h,C)}function d(h,C){const g=i(t),y=i(n);dt(h)?(g==null||g.scrollToLeft(h.scrollLeft),y==null||y.scrollTo(h)):(g==null||g.scrollToLeft(h),y==null||y.scrollTo({scrollLeft:h,scrollTop:C}))}function p(h){var C;(C=i(n))==null||C.scrollTo({scrollTop:h})}function m(h,C){var g;(g=i(n))==null||g.scrollToItem(h,1,C)}function v(){var h,C;(h=i(n))==null||h.$forceUpdate(),(C=i(t))==null||C.$forceUpdate()}return{bodyRef:n,forceUpdate:v,fixedRowHeight:r,gridHeight:l,hasHeader:s,headerHeight:a,headerRef:t,totalHeight:o,itemKey:u,onItemRendered:c,resetAfterRowIndex:f,scrollTo:d,scrollToTop:p,scrollToRow:m}},Rg=Y({name:MJ,props:qc,setup(e,{slots:t,expose:n}){const{ns:o}=De(Ng),{bodyRef:r,fixedRowHeight:a,gridHeight:l,hasHeader:s,headerRef:u,headerHeight:c,totalHeight:f,forceUpdate:d,itemKey:p,onItemRendered:m,resetAfterRowIndex:v,scrollTo:h,scrollToTop:C,scrollToRow:g}=AJ(e);n({forceUpdate:d,totalHeight:f,scrollTo:h,scrollToTop:C,scrollToRow:g,resetAfterRowIndex:v});const y=()=>e.bodyWidth;return()=>{const{cache:_,columns:b,data:w,fixedData:S,useIsScrolling:E,scrollbarAlwaysOn:$,scrollbarEndGap:O,scrollbarStartGap:A,style:M,rowHeight:D,bodyWidth:U,estimatedRowHeight:j,headerWidth:W,height:L,width:P,getRowHeight:x,onScroll:I}=e,H=Je(j),G=H?gY:pY,J=i(c);return K("div",{role:"table",class:[o.e("table"),e.class],style:M},[K(G,{ref:r,data:w,useIsScrolling:E,itemKey:p,columnCache:0,columnWidth:H?y:U,totalColumn:1,totalRow:w.length,rowCache:_,rowHeight:H?x:D,width:P,height:i(l),class:o.e("body"),role:"rowgroup",scrollbarStartGap:A,scrollbarEndGap:O,scrollbarAlwaysOn:$,onScroll:I,onItemRendered:m,perfMode:!1},{default:ee=>{var fe;const Te=w[ee.rowIndex];return(fe=t.row)==null?void 0:fe.call(t,{...ee,columns:b,rowData:Te})}}),i(s)&&K(EJ,{ref:u,class:o.e("header-wrapper"),columns:b,headerData:w,headerHeight:e.headerHeight,fixedHeaderData:S,rowWidth:W,rowHeight:D,width:P,height:Math.min(J+i(a),L)},{dynamic:t.header,fixed:t.row})])}}});function PJ(e){return typeof e=="function"||Object.prototype.toString.call(e)==="[object Object]"&&!Wt(e)}const RJ=(e,{slots:t})=>{const{mainTableRef:n,...o}=e;return K(Rg,mt({ref:n},o),PJ(t)?t:{default:()=>[t]})};function LJ(e){return typeof e=="function"||Object.prototype.toString.call(e)==="[object Object]"&&!Wt(e)}const xJ=(e,{slots:t})=>{if(!e.columns.length)return;const{leftTableRef:n,...o}=e;return K(Rg,mt({ref:n},o),LJ(t)?t:{default:()=>[t]})};function DJ(e){return typeof e=="function"||Object.prototype.toString.call(e)==="[object Object]"&&!Wt(e)}const FJ=(e,{slots:t})=>{if(!e.columns.length)return;const{rightTableRef:n,...o}=e;return K(Rg,mt({ref:n},o),DJ(t)?t:{default:()=>[t]})};function BJ(e){return typeof e=="function"||Object.prototype.toString.call(e)==="[object Object]"&&!Wt(e)}const VJ=(e,{slots:t})=>{const{columns:n,columnsStyles:o,depthMap:r,expandColumnKey:a,expandedRowKeys:l,estimatedRowHeight:s,hasFixedColumns:u,rowData:c,rowIndex:f,style:d,isScrolling:p,rowProps:m,rowClass:v,rowKey:h,rowEventHandlers:C,ns:g,onRowHovered:y,onRowExpanded:_}=e,b=Nl(v,{columns:n,rowData:c,rowIndex:f},""),w=Nl(m,{columns:n,rowData:c,rowIndex:f}),S=c[h],E=r[S]||0,$=!!a,O=f<0,A=[g.e("row"),b,{[g.e(`row-depth-${E}`)]:$&&f>=0,[g.is("expanded")]:$&&l.includes(S),[g.is("fixed")]:!E&&O,[g.is("customized")]:!!t.row}],M=u?y:void 0,D={...w,columns:n,columnsStyles:o,class:A,depth:E,expandColumnKey:a,estimatedRowHeight:O?void 0:s,isScrolling:p,rowIndex:f,rowData:c,rowKey:S,rowEventHandlers:C,style:d};return K(OJ,mt(D,{onRowExpand:_,onMouseenter:W=>{M==null||M({hovered:!0,rowKey:S,event:W,rowData:c,rowIndex:f})},onMouseleave:W=>{M==null||M({hovered:!1,rowKey:S,event:W,rowData:c,rowIndex:f})},rowkey:S}),BJ(t)?t:{default:()=>[t]})},lm=({columns:e,column:t,columnIndex:n,depth:o,expandIconProps:r,isScrolling:a,rowData:l,rowIndex:s,style:u,expandedRowKeys:c,ns:f,cellProps:d,expandColumnKey:p,indentSize:m,iconSize:v,rowKey:h},{slots:C})=>{const g=ya(u);if(t.placeholderSign===mu)return K("div",{class:f.em("row-cell","placeholder"),style:g},null);const{cellRenderer:y,dataKey:_,dataGetter:b}=t,w=Xe(b)?b({columns:e,column:t,columnIndex:n,rowData:l,rowIndex:s}):un(l,_??""),S=Nl(d,{cellData:w,columns:e,column:t,columnIndex:n,rowIndex:s,rowData:l}),E={class:f.e("cell-text"),columns:e,column:t,columnIndex:n,cellData:w,isScrolling:a,rowData:l,rowIndex:s},$=g2(y),O=$?$(E):ie(C,"default",E,()=>[K(Ag,E,null)]),A=[f.e("row-cell"),t.class,t.align===hu.CENTER&&f.is("align-center"),t.align===hu.RIGHT&&f.is("align-right")],M=s>=0&&p&&t.key===p,D=s>=0&&c.includes(l[h]);let U;const j=`margin-inline-start: ${o*m}px;`;return M&&(dt(r)?U=K(IJ,mt(r,{class:[f.e("expand-icon"),f.is("expanded",D)],size:v,expanded:D,style:j,expandable:!0}),null):U=K("div",{style:[j,`width: ${v}px; height: ${v}px;`].join(" ")},null)),K("div",mt({class:A,style:g},S,{role:"cell"}),[U,O])};lm.inheritAttrs=!1;function HJ(e){return typeof e=="function"||Object.prototype.toString.call(e)==="[object Object]"&&!Wt(e)}const zJ=({columns:e,columnsStyles:t,headerIndex:n,style:o,headerClass:r,headerProps:a,ns:l},{slots:s})=>{const u={columns:e,headerIndex:n},c=[l.e("header-row"),Nl(r,u,""),{[l.is("customized")]:!!s.header}],f={...Nl(a,u),columnsStyles:t,class:c,columns:e,headerIndex:n,style:o};return K(SJ,f,HJ(s)?s:{default:()=>[s]})},S1=(e,{slots:t})=>{const{column:n,ns:o,style:r,onColumnSorted:a}=e,l=ya(r);if(n.placeholderSign===mu)return K("div",{class:o.em("header-row-cell","placeholder"),style:l},null);const{headerCellRenderer:s,headerClass:u,sortable:c}=n,f={...e,class:o.e("header-cell-text")},d=g2(s),p=d?d(f):ie(t,"default",f,()=>[K(Pg,f,null)]),{sortBy:m,sortState:v,headerCellProps:h}=e;let C,g;if(v){const b=v[n.key];C=!!am[b],g=C?b:pu.ASC}else C=n.key===m.key,g=C?m.order:pu.ASC;const y=[o.e("header-cell"),Nl(u,e,""),n.align===hu.CENTER&&o.is("align-center"),n.align===hu.RIGHT&&o.is("align-right"),c&&o.is("sortable")],_={...Nl(h,e),onClick:n.sortable?a:void 0,class:y,style:l,"data-key":n.key};return K("div",mt(_,{role:"columnheader"}),[p,c&&K(NJ,{class:[o.e("sort-icon"),C&&o.is("sorting")],sortOrder:g},null)])},_2=(e,{slots:t})=>{var n;return K("div",{class:e.class,style:e.style},[(n=t.default)==null?void 0:n.call(t)])};_2.displayName="ElTableV2Footer";const C2=(e,{slots:t})=>{const n=ie(t,"default",{},()=>[K(EE,null,null)]);return K("div",{class:e.class,style:e.style},[n])};C2.displayName="ElTableV2Empty";const S2=(e,{slots:t})=>{var n;return K("div",{class:e.class,style:e.style},[(n=t.default)==null?void 0:n.call(t)])};S2.displayName="ElTableV2Overlay";function gi(e){return typeof e=="function"||Object.prototype.toString.call(e)==="[object Object]"&&!Wt(e)}const jJ="ElTableV2",WJ=Y({name:jJ,props:_J,setup(e,{slots:t,expose:n}){const o=Se("table-v2"),{columnsStyles:r,fixedColumnsOnLeft:a,fixedColumnsOnRight:l,mainColumns:s,mainTableHeight:u,fixedTableHeight:c,leftTableWidth:f,rightTableWidth:d,data:p,depthMap:m,expandedRowKeys:v,hasFixedColumns:h,mainTableRef:C,leftTableRef:g,rightTableRef:y,isDynamic:_,isResetting:b,isScrolling:w,bodyWidth:S,emptyStyle:E,rootStyle:$,headerWidth:O,footerHeight:A,showEmpty:M,scrollTo:D,scrollToLeft:U,scrollToTop:j,scrollToRow:W,getRowHeight:L,onColumnSorted:P,onRowHeightChange:x,onRowHovered:I,onRowExpanded:H,onRowsRendered:G,onScroll:J,onVerticalScroll:ee}=yJ(e);return n({scrollTo:D,scrollToLeft:U,scrollToTop:j,scrollToRow:W}),yt(Ng,{ns:o,isResetting:b,isScrolling:w}),()=>{const{cache:fe,cellProps:Te,estimatedRowHeight:oe,expandColumnKey:ke,fixedData:ae,headerHeight:Oe,headerClass:we,headerProps:ge,headerCellProps:q,sortBy:B,sortState:z,rowHeight:Z,rowClass:ue,rowEventHandlers:se,rowKey:me,rowProps:_e,scrollbarAlwaysOn:$e,indentSize:Ce,iconSize:ce,useIsScrolling:de,vScrollbarSize:xe,width:he}=e,He=i(p),et={cache:fe,class:o.e("main"),columns:i(s),data:He,fixedData:ae,estimatedRowHeight:oe,bodyWidth:i(S)+xe,headerHeight:Oe,headerWidth:i(O),height:i(u),mainTableRef:C,rowKey:me,rowHeight:Z,scrollbarAlwaysOn:$e,scrollbarStartGap:2,scrollbarEndGap:xe,useIsScrolling:de,width:he,getRowHeight:L,onRowsRendered:G,onScroll:J},rt=i(f),wt=i(c),Ze={cache:fe,class:o.e("left"),columns:i(a),data:He,estimatedRowHeight:oe,leftTableRef:g,rowHeight:Z,bodyWidth:rt,headerWidth:rt,headerHeight:Oe,height:wt,rowKey:me,scrollbarAlwaysOn:$e,scrollbarStartGap:2,scrollbarEndGap:xe,useIsScrolling:de,width:rt,getRowHeight:L,onScroll:ee},Ee=i(d)+xe,ye={cache:fe,class:o.e("right"),columns:i(l),data:He,estimatedRowHeight:oe,rightTableRef:y,rowHeight:Z,bodyWidth:Ee,headerWidth:Ee,headerHeight:Oe,height:wt,rowKey:me,scrollbarAlwaysOn:$e,scrollbarStartGap:2,scrollbarEndGap:xe,width:Ee,style:`--${i(o.namespace)}-table-scrollbar-size: ${xe}px`,useIsScrolling:de,getRowHeight:L,onScroll:ee},ne=i(r),be={ns:o,depthMap:i(m),columnsStyles:ne,expandColumnKey:ke,expandedRowKeys:i(v),estimatedRowHeight:oe,hasFixedColumns:i(h),rowProps:_e,rowClass:ue,rowKey:me,rowEventHandlers:se,onRowHovered:I,onRowExpanded:H,onRowHeightChange:x},Fe={cellProps:Te,expandColumnKey:ke,indentSize:Ce,iconSize:ce,rowKey:me,expandedRowKeys:i(v),ns:o},vt={ns:o,headerClass:we,headerProps:ge,columnsStyles:ne},pe={ns:o,sortBy:B,sortState:z,headerCellProps:q,onColumnSorted:P},Ye={row:Jt=>K(VJ,mt(Jt,be),{row:t.row,cell:Ht=>{let At;return t.cell?K(lm,mt(Ht,Fe,{style:ne[Ht.column.key]}),gi(At=t.cell(Ht))?At:{default:()=>[At]}):K(lm,mt(Ht,Fe,{style:ne[Ht.column.key]}),null)}}),header:Jt=>K(zJ,mt(Jt,vt),{header:t.header,cell:Ht=>{let At;return t["header-cell"]?K(S1,mt(Ht,pe,{style:ne[Ht.column.key]}),gi(At=t["header-cell"](Ht))?At:{default:()=>[At]}):K(S1,mt(Ht,pe,{style:ne[Ht.column.key]}),null)}})},_t=[e.class,o.b(),o.e("root"),{[o.is("dynamic")]:i(_)}],Kt={class:o.e("footer"),style:i(A)};return K("div",{class:_t,style:i($)},[K(RJ,et,gi(Ye)?Ye:{default:()=>[Ye]}),K(xJ,Ze,gi(Ye)?Ye:{default:()=>[Ye]}),K(FJ,ye,gi(Ye)?Ye:{default:()=>[Ye]}),t.footer&&K(_2,Kt,{default:t.footer}),i(M)&&K(C2,{class:o.e("empty"),style:i(E)},{default:t.empty}),t.overlay&&K(S2,{class:o.e("overlay")},{default:t.overlay})])}}}),KJ=Ne({disableWidth:Boolean,disableHeight:Boolean,onResize:{type:Q(Function)}}),UJ=Y({name:"ElAutoResizer",props:KJ,setup(e,{slots:t}){const n=Se("auto-resizer"),{height:o,width:r,sizer:a}=bJ(e),l={width:"100%",height:"100%"};return()=>{var s;return K("div",{ref:a,class:n.b(),style:l},[(s=t.default)==null?void 0:s.call(t,{height:o.value,width:r.value})])}}}),qJ=ut(WJ),YJ=ut(UJ),Nf=Symbol("tabsRootContextKey"),GJ=Ne({tabs:{type:Q(Array),default:()=>en([])}}),k2="ElTabBar",XJ=Y({name:k2}),JJ=Y({...XJ,props:GJ,setup(e,{expose:t}){const n=e,o=lt(),r=De(Nf);r||vn(k2,"");const a=Se("tabs"),l=R(),s=R(),u=()=>{let f=0,d=0;const p=["top","bottom"].includes(r.props.tabPosition)?"width":"height",m=p==="width"?"x":"y",v=m==="x"?"left":"top";return n.tabs.every(h=>{var C,g;const y=(g=(C=o.parent)==null?void 0:C.refs)==null?void 0:g[`tab-${h.uid}`];if(!y)return!1;if(!h.active)return!0;f=y[`offset${mr(v)}`],d=y[`client${mr(p)}`];const _=window.getComputedStyle(y);return p==="width"&&(d-=Number.parseFloat(_.paddingLeft)+Number.parseFloat(_.paddingRight),f+=Number.parseFloat(_.paddingLeft)),!1}),{[p]:`${d}px`,transform:`translate${mr(m)}(${f}px)`}},c=()=>s.value=u();return ve(()=>n.tabs,async()=>{await We(),c()},{immediate:!0}),Qt(l,()=>c()),t({ref:l,update:c}),(f,d)=>(T(),V("div",{ref_key:"barRef",ref:l,class:N([i(a).e("active-bar"),i(a).is(i(r).props.tabPosition)]),style:je(s.value)},null,6))}});var ZJ=Ie(JJ,[["__file","tab-bar.vue"]]);const QJ=Ne({panes:{type:Q(Array),default:()=>en([])},currentName:{type:[String,Number],default:""},editable:Boolean,type:{type:String,values:["card","border-card",""],default:""},stretch:Boolean}),eZ={tabClick:(e,t,n)=>n instanceof Event,tabRemove:(e,t)=>t instanceof Event},k1="ElTabNav",tZ=Y({name:k1,props:QJ,emits:eZ,setup(e,{expose:t,emit:n}){const o=lt(),r=De(Nf);r||vn(k1,"");const a=Se("tabs"),l=aM(),s=gM(),u=R(),c=R(),f=R(),d=R(),p=R(!1),m=R(0),v=R(!1),h=R(!0),C=k(()=>["top","bottom"].includes(r.props.tabPosition)?"width":"height"),g=k(()=>({transform:`translate${C.value==="width"?"X":"Y"}(-${m.value}px)`})),y=()=>{if(!u.value)return;const O=u.value[`offset${mr(C.value)}`],A=m.value;if(!A)return;const M=A>O?A-O:0;m.value=M},_=()=>{if(!u.value||!c.value)return;const O=c.value[`offset${mr(C.value)}`],A=u.value[`offset${mr(C.value)}`],M=m.value;if(O-M<=A)return;const D=O-M>A*2?M+A:O-A;m.value=D},b=async()=>{const O=c.value;if(!p.value||!f.value||!u.value||!O)return;await We();const A=f.value.querySelector(".is-active");if(!A)return;const M=u.value,D=["top","bottom"].includes(r.props.tabPosition),U=A.getBoundingClientRect(),j=M.getBoundingClientRect(),W=D?O.offsetWidth-j.width:O.offsetHeight-j.height,L=m.value;let P=L;D?(U.leftj.right&&(P=L+U.right-j.right)):(U.topj.bottom&&(P=L+(U.bottom-j.bottom))),P=Math.max(P,0),m.value=Math.min(P,W)},w=()=>{var O;if(!c.value||!u.value)return;e.stretch&&((O=d.value)==null||O.update());const A=c.value[`offset${mr(C.value)}`],M=u.value[`offset${mr(C.value)}`],D=m.value;M0&&(m.value=0))},S=O=>{const A=O.code,{up:M,down:D,left:U,right:j}=Ue;if(![M,D,U,j].includes(A))return;const W=Array.from(O.currentTarget.querySelectorAll("[role=tab]:not(.is-disabled)")),L=W.indexOf(O.target);let P;A===U||A===M?L===0?P=W.length-1:P=L-1:L{h.value&&(v.value=!0)},$=()=>v.value=!1;return ve(l,O=>{O==="hidden"?h.value=!1:O==="visible"&&setTimeout(()=>h.value=!0,50)}),ve(s,O=>{O?setTimeout(()=>h.value=!0,50):h.value=!1}),Qt(f,w),at(()=>setTimeout(()=>b(),0)),ar(()=>w()),t({scrollToActiveTab:b,removeFocus:$}),ve(()=>e.panes,()=>o.update(),{flush:"post",deep:!0}),()=>{const O=p.value?[K("span",{class:[a.e("nav-prev"),a.is("disabled",!p.value.prev)],onClick:y},[K(ze,null,{default:()=>[K(Aa,null,null)]})]),K("span",{class:[a.e("nav-next"),a.is("disabled",!p.value.next)],onClick:_},[K(ze,null,{default:()=>[K(Jn,null,null)]})])]:null,A=e.panes.map((M,D)=>{var U,j,W,L;const P=M.uid,x=M.props.disabled,I=(j=(U=M.props.name)!=null?U:M.index)!=null?j:`${D}`,H=!x&&(M.isClosable||e.editable);M.index=`${D}`;const G=H?K(ze,{class:"is-icon-close",onClick:fe=>n("tabRemove",M,fe)},{default:()=>[K(tr,null,null)]}):null,J=((L=(W=M.slots).label)==null?void 0:L.call(W))||M.props.label,ee=!x&&M.active?0:-1;return K("div",{ref:`tab-${P}`,class:[a.e("item"),a.is(r.props.tabPosition),a.is("active",M.active),a.is("disabled",x),a.is("closable",H),a.is("focus",v.value)],id:`tab-${I}`,key:`tab-${P}`,"aria-controls":`pane-${I}`,role:"tab","aria-selected":M.active,tabindex:ee,onFocus:()=>E(),onBlur:()=>$(),onClick:fe=>{$(),n("tabClick",M,I,fe)},onKeydown:fe=>{H&&(fe.code===Ue.delete||fe.code===Ue.backspace)&&n("tabRemove",M,fe)}},[J,G])});return K("div",{ref:f,class:[a.e("nav-wrap"),a.is("scrollable",!!p.value),a.is(r.props.tabPosition)]},[O,K("div",{class:a.e("nav-scroll"),ref:u},[K("div",{class:[a.e("nav"),a.is(r.props.tabPosition),a.is("stretch",e.stretch&&["top","bottom"].includes(r.props.tabPosition))],ref:c,style:g.value,role:"tablist",onKeydown:S},[e.type?null:K(ZJ,{ref:d,tabs:[...e.panes]},null),A])])])}}}),nZ=Ne({type:{type:String,values:["card","border-card",""],default:""},closable:Boolean,addable:Boolean,modelValue:{type:[String,Number]},editable:Boolean,tabPosition:{type:String,values:["top","right","bottom","left"],default:"top"},beforeLeave:{type:Q(Function),default:()=>!0},stretch:Boolean}),Ip=e=>nt(e)||Je(e),oZ={[ft]:e=>Ip(e),tabClick:(e,t)=>t instanceof Event,tabChange:e=>Ip(e),edit:(e,t)=>["remove","add"].includes(t),tabRemove:e=>Ip(e),tabAdd:()=>!0},rZ=Y({name:"ElTabs",props:nZ,emits:oZ,setup(e,{emit:t,slots:n,expose:o}){var r;const a=Se("tabs"),l=k(()=>["left","right"].includes(e.tabPosition)),{children:s,addChild:u,removeChild:c}=tg(lt(),"ElTabPane"),f=R(),d=R((r=e.modelValue)!=null?r:"0"),p=async(C,g=!1)=>{var y,_,b;if(!(d.value===C||pn(C)))try{await((y=e.beforeLeave)==null?void 0:y.call(e,C,d.value))!==!1&&(d.value=C,g&&(t(ft,C),t("tabChange",C)),(b=(_=f.value)==null?void 0:_.removeFocus)==null||b.call(_))}catch{}},m=(C,g,y)=>{C.props.disabled||(p(g,!0),t("tabClick",C,y))},v=(C,g)=>{C.props.disabled||pn(C.props.name)||(g.stopPropagation(),t("edit",C.props.name,"remove"),t("tabRemove",C.props.name))},h=()=>{t("edit",void 0,"add"),t("tabAdd")};return ve(()=>e.modelValue,C=>p(C)),ve(d,async()=>{var C;await We(),(C=f.value)==null||C.scrollToActiveTab()}),yt(Nf,{props:e,currentName:d,registerPane:u,unregisterPane:c}),o({currentName:d}),()=>{const C=n["add-icon"],g=e.editable||e.addable?K("div",{class:[a.e("new-tab"),l.value&&a.e("new-tab-vertical")],tabindex:"0",onClick:h,onKeydown:b=>{b.code===Ue.enter&&h()}},[C?ie(n,"add-icon"):K(ze,{class:a.is("icon-plus")},{default:()=>[K(GC,null,null)]})]):null,y=K("div",{class:[a.e("header"),l.value&&a.e("header-vertical"),a.is(e.tabPosition)]},[K(tZ,{ref:f,currentName:d.value,editable:e.editable,type:e.type,panes:s.value,stretch:e.stretch,onTabClick:m,onTabRemove:v},null),g]),_=K("div",{class:a.e("content")},[ie(n,"default")]);return K("div",{class:[a.b(),a.m(e.tabPosition),{[a.m("card")]:e.type==="card",[a.m("border-card")]:e.type==="border-card"}]},[...e.tabPosition!=="bottom"?[y,_]:[_,y]])}}}),aZ=Ne({label:{type:String,default:""},name:{type:[String,Number]},closable:Boolean,disabled:Boolean,lazy:Boolean}),lZ=["id","aria-hidden","aria-labelledby"],E2="ElTabPane",sZ=Y({name:E2}),iZ=Y({...sZ,props:aZ,setup(e){const t=e,n=lt(),o=Sn(),r=De(Nf);r||vn(E2,"usage: ");const a=Se("tab-pane"),l=R(),s=k(()=>t.closable||r.props.closable),u=ey(()=>{var m;return r.currentName.value===((m=t.name)!=null?m:l.value)}),c=R(u.value),f=k(()=>{var m;return(m=t.name)!=null?m:l.value}),d=ey(()=>!t.lazy||c.value||u.value);ve(u,m=>{m&&(c.value=!0)});const p=Et({uid:n.uid,slots:o,props:t,paneName:f,active:u,index:l,isClosable:s});return at(()=>{r.registerPane(p)}),lr(()=>{r.unregisterPane(p.uid)}),(m,v)=>i(d)?tt((T(),V("div",{key:0,id:`pane-${i(f)}`,class:N(i(a).b()),role:"tabpanel","aria-hidden":!i(u),"aria-labelledby":`tab-${i(f)}`},[ie(m.$slots,"default")],10,lZ)),[[kt,i(u)]]):te("v-if",!0)}});var T2=Ie(iZ,[["__file","tab-pane.vue"]]);const uZ=ut(rZ,{TabPane:T2}),cZ=tn(T2),dZ=Ne({type:{type:String,values:["primary","success","info","warning","danger",""],default:""},size:{type:String,values:Ir,default:""},truncated:Boolean,lineClamp:{type:[String,Number]},tag:{type:String,default:"span"}}),fZ=Y({name:"ElText"}),pZ=Y({...fZ,props:dZ,setup(e){const t=e,n=hn(),o=Se("text"),r=k(()=>[o.b(),o.m(t.type),o.m(n.value),o.is("truncated",t.truncated),o.is("line-clamp",!pn(t.lineClamp))]);return(a,l)=>(T(),re(pt(a.tag),{class:N(i(r)),style:je({"-webkit-line-clamp":a.lineClamp})},{default:X(()=>[ie(a.$slots,"default")]),_:3},8,["class","style"]))}});var hZ=Ie(pZ,[["__file","text.vue"]]);const mZ=ut(hZ),vZ=Ne({format:{type:String,default:"HH:mm"},modelValue:String,disabled:Boolean,editable:{type:Boolean,default:!0},effect:{type:Q(String),default:"light"},clearable:{type:Boolean,default:!0},size:gn,placeholder:String,start:{type:String,default:"09:00"},end:{type:String,default:"18:00"},step:{type:String,default:"00:30"},minTime:String,maxTime:String,name:String,prefixIcon:{type:Q([String,Object]),default:()=>qC},clearIcon:{type:Q([String,Object]),default:()=>Fa},...ei}),zr=e=>{const t=(e||"").split(":");if(t.length>=2){let n=Number.parseInt(t[0],10);const o=Number.parseInt(t[1],10),r=e.toUpperCase();return r.includes("AM")&&n===12?n=0:r.includes("PM")&&n!==12&&(n+=12),{hours:n,minutes:o}}return null},Mp=(e,t)=>{const n=zr(e);if(!n)return-1;const o=zr(t);if(!o)return-1;const r=n.minutes+n.hours*60,a=o.minutes+o.hours*60;return r===a?0:r>a?1:-1},E1=e=>`${e}`.padStart(2,"0"),Ql=e=>`${E1(e.hours)}:${E1(e.minutes)}`,gZ=(e,t)=>{const n=zr(e);if(!n)return"";const o=zr(t);if(!o)return"";const r={hours:n.hours,minutes:n.minutes};return r.minutes+=o.minutes,r.hours+=o.hours,r.hours+=Math.floor(r.minutes/60),r.minutes=r.minutes%60,Ql(r)},bZ=Y({name:"ElTimeSelect"}),yZ=Y({...bZ,props:vZ,emits:["change","blur","focus","clear","update:modelValue"],setup(e,{expose:t}){const n=e;ct.extend(ig);const{Option:o}=Ol,r=Se("input"),a=R(),l=to(),{lang:s}=$t(),u=k(()=>n.modelValue),c=k(()=>{const g=zr(n.start);return g?Ql(g):null}),f=k(()=>{const g=zr(n.end);return g?Ql(g):null}),d=k(()=>{const g=zr(n.step);return g?Ql(g):null}),p=k(()=>{const g=zr(n.minTime||"");return g?Ql(g):null}),m=k(()=>{const g=zr(n.maxTime||"");return g?Ql(g):null}),v=k(()=>{const g=[];if(n.start&&n.end&&n.step){let y=c.value,_;for(;y&&f.value&&Mp(y,f.value)<=0;)_=ct(y,"HH:mm").locale(s.value).format(n.format),g.push({value:_,disabled:Mp(y,p.value||"-1:-1")<=0||Mp(y,m.value||"100:100")>=0}),y=gZ(y,d.value)}return g});return t({blur:()=>{var g,y;(y=(g=a.value)==null?void 0:g.blur)==null||y.call(g)},focus:()=>{var g,y;(y=(g=a.value)==null?void 0:g.focus)==null||y.call(g)}}),(g,y)=>(T(),re(i(Ol),{ref_key:"select",ref:a,"model-value":i(u),disabled:i(l),clearable:g.clearable,"clear-icon":g.clearIcon,size:g.size,effect:g.effect,placeholder:g.placeholder,"default-first-option":"",filterable:g.editable,"empty-values":g.emptyValues,"value-on-clear":g.valueOnClear,"onUpdate:modelValue":y[0]||(y[0]=_=>g.$emit("update:modelValue",_)),onChange:y[1]||(y[1]=_=>g.$emit("change",_)),onBlur:y[2]||(y[2]=_=>g.$emit("blur",_)),onFocus:y[3]||(y[3]=_=>g.$emit("focus",_)),onClear:y[4]||(y[4]=()=>g.$emit("clear"))},{prefix:X(()=>[g.prefixIcon?(T(),re(i(ze),{key:0,class:N(i(r).e("prefix-icon"))},{default:X(()=>[(T(),re(pt(g.prefixIcon)))]),_:1},8,["class"])):te("v-if",!0)]),default:X(()=>[(T(!0),V(Ve,null,bt(i(v),_=>(T(),re(i(o),{key:_.value,label:_.value,value:_.value,disabled:_.disabled},null,8,["label","value","disabled"]))),128))]),_:1},8,["model-value","disabled","clearable","clear-icon","size","effect","placeholder","filterable","empty-values","value-on-clear"]))}});var wZ=Ie(yZ,[["__file","time-select.vue"]]);const _Z=ut(wZ),CZ=Y({name:"ElTimeline",setup(e,{slots:t}){const n=Se("timeline");return yt("timeline",t),()=>Ke("ul",{class:[n.b()]},[ie(t,"default")])}}),SZ=Ne({timestamp:{type:String,default:""},hideTimestamp:Boolean,center:Boolean,placement:{type:String,values:["top","bottom"],default:"bottom"},type:{type:String,values:["primary","success","warning","danger","info"],default:""},color:{type:String,default:""},size:{type:String,values:["normal","large"],default:"normal"},icon:{type:Dt},hollow:Boolean}),kZ=Y({name:"ElTimelineItem"}),EZ=Y({...kZ,props:SZ,setup(e){const t=e,n=Se("timeline-item"),o=k(()=>[n.e("node"),n.em("node",t.size||""),n.em("node",t.type||""),n.is("hollow",t.hollow)]);return(r,a)=>(T(),V("li",{class:N([i(n).b(),{[i(n).e("center")]:r.center}])},[F("div",{class:N(i(n).e("tail"))},null,2),r.$slots.dot?te("v-if",!0):(T(),V("div",{key:0,class:N(i(o)),style:je({backgroundColor:r.color})},[r.icon?(T(),re(i(ze),{key:0,class:N(i(n).e("icon"))},{default:X(()=>[(T(),re(pt(r.icon)))]),_:1},8,["class"])):te("v-if",!0)],6)),r.$slots.dot?(T(),V("div",{key:1,class:N(i(n).e("dot"))},[ie(r.$slots,"dot")],2)):te("v-if",!0),F("div",{class:N(i(n).e("wrapper"))},[!r.hideTimestamp&&r.placement==="top"?(T(),V("div",{key:0,class:N([i(n).e("timestamp"),i(n).is("top")])},le(r.timestamp),3)):te("v-if",!0),F("div",{class:N(i(n).e("content"))},[ie(r.$slots,"default")],2),!r.hideTimestamp&&r.placement==="bottom"?(T(),V("div",{key:1,class:N([i(n).e("timestamp"),i(n).is("bottom")])},le(r.timestamp),3)):te("v-if",!0)],2)],2))}});var $2=Ie(EZ,[["__file","timeline-item.vue"]]);const TZ=ut(CZ,{TimelineItem:$2}),$Z=tn($2),O2=Ne({nowrap:Boolean});var N2=(e=>(e.top="top",e.bottom="bottom",e.left="left",e.right="right",e))(N2||{});const OZ=Object.values(N2),Lg=Ne({width:{type:Number,default:10},height:{type:Number,default:10},style:{type:Q(Object),default:null}}),NZ=Ne({side:{type:Q(String),values:OZ,required:!0}}),IZ=["absolute","fixed"],MZ=["top-start","top-end","top","bottom-start","bottom-end","bottom","left-start","left-end","left","right-start","right-end","right"],xg=Ne({arrowPadding:{type:Q(Number),default:5},effect:{type:Q(String),default:"light"},contentClass:String,placement:{type:Q(String),values:MZ,default:"bottom"},reference:{type:Q(Object),default:null},offset:{type:Number,default:8},strategy:{type:Q(String),values:IZ,default:"absolute"},showArrow:Boolean,...An(["ariaLabel"])}),Dg=Ne({delayDuration:{type:Number,default:300},defaultOpen:Boolean,open:{type:Boolean,default:void 0},onOpenChange:{type:Q(Function)},"onUpdate:open":{type:Q(Function)}}),Gl={type:Q(Function)},Fg=Ne({onBlur:Gl,onClick:Gl,onFocus:Gl,onMouseDown:Gl,onMouseEnter:Gl,onMouseLeave:Gl}),AZ=Ne({...Dg,...Lg,...Fg,...xg,alwaysOn:Boolean,fullTransition:Boolean,transitionProps:{type:Q(Object),default:null},teleported:Boolean,to:{type:Q(String),default:"body"}}),If=Symbol("tooltipV2"),I2=Symbol("tooltipV2Content"),Ap="tooltip_v2.open",PZ=Y({name:"ElTooltipV2Root"}),RZ=Y({...PZ,props:Dg,setup(e,{expose:t}){const n=e,o=R(n.defaultOpen),r=R(null),a=k({get:()=>Sl(n.open)?o.value:n.open,set:C=>{var g;o.value=C,(g=n["onUpdate:open"])==null||g.call(n,C)}}),l=k(()=>Je(n.delayDuration)&&n.delayDuration>0),{start:s,stop:u}=_l(()=>{a.value=!0},k(()=>n.delayDuration),{immediate:!1}),c=Se("tooltip-v2"),f=xn(),d=()=>{u(),a.value=!0},p=()=>{i(l)?s():d()},m=d,v=()=>{u(),a.value=!1};return ve(a,C=>{var g;C&&(document.dispatchEvent(new CustomEvent(Ap)),m()),(g=n.onOpenChange)==null||g.call(n,C)}),at(()=>{document.addEventListener(Ap,v)}),zt(()=>{u(),document.removeEventListener(Ap,v)}),yt(If,{contentId:f,triggerRef:r,ns:c,onClose:v,onDelayOpen:p,onOpen:m}),t({onOpen:m,onClose:v}),(C,g)=>ie(C.$slots,"default",{open:i(a)})}});var LZ=Ie(RZ,[["__file","root.vue"]]);const xZ=Y({name:"ElTooltipV2Arrow"}),DZ=Y({...xZ,props:{...Lg,...NZ},setup(e){const t=e,{ns:n}=De(If),{arrowRef:o}=De(I2),r=k(()=>{const{style:a,width:l,height:s}=t,u=n.namespace.value;return{[`--${u}-tooltip-v2-arrow-width`]:`${l}px`,[`--${u}-tooltip-v2-arrow-height`]:`${s}px`,[`--${u}-tooltip-v2-arrow-border-width`]:`${l/2}px`,[`--${u}-tooltip-v2-arrow-cover-width`]:l/2-1,...a||{}}});return(a,l)=>(T(),V("span",{ref_key:"arrowRef",ref:o,style:je(i(r)),class:N(i(n).e("arrow"))},null,6))}});var T1=Ie(DZ,[["__file","arrow.vue"]]);const FZ=Ne({style:{type:Q([String,Object,Array]),default:()=>({})}}),BZ=Y({name:"ElVisuallyHidden"}),VZ=Y({...BZ,props:FZ,setup(e){const t=e,n=k(()=>[t.style,{position:"absolute",border:0,width:1,height:1,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",wordWrap:"normal"}]);return(o,r)=>(T(),V("span",mt(o.$attrs,{style:i(n)}),[ie(o.$slots,"default")],16))}});var HZ=Ie(VZ,[["__file","visual-hidden.vue"]]);const zZ=["data-side"],jZ=Y({name:"ElTooltipV2Content"}),WZ=Y({...jZ,props:{...xg,...O2},setup(e){const t=e,{triggerRef:n,contentId:o}=De(If),r=R(t.placement),a=R(t.strategy),l=R(null),{referenceRef:s,contentRef:u,middlewareData:c,x:f,y:d,update:p}=g8({placement:r,strategy:a,middleware:k(()=>{const _=[AS(t.offset)];return t.showArrow&&_.push(b8({arrowRef:l})),_})}),m=Zs().nextZIndex(),v=Se("tooltip-v2"),h=k(()=>r.value.split("-")[0]),C=k(()=>({position:i(a),top:`${i(d)||0}px`,left:`${i(f)||0}px`,zIndex:m})),g=k(()=>{if(!t.showArrow)return{};const{arrow:_}=i(c);return{[`--${v.namespace.value}-tooltip-v2-arrow-x`]:`${_==null?void 0:_.x}px`||"",[`--${v.namespace.value}-tooltip-v2-arrow-y`]:`${_==null?void 0:_.y}px`||""}}),y=k(()=>[v.e("content"),v.is("dark",t.effect==="dark"),v.is(i(a)),t.contentClass]);return ve(l,()=>p()),ve(()=>t.placement,_=>r.value=_),at(()=>{ve(()=>t.reference||n.value,_=>{s.value=_||void 0},{immediate:!0})}),yt(I2,{arrowRef:l}),(_,b)=>(T(),V("div",{ref_key:"contentRef",ref:u,style:je(i(C)),"data-tooltip-v2-root":""},[_.nowrap?te("v-if",!0):(T(),V("div",{key:0,"data-side":i(h),class:N(i(y))},[ie(_.$slots,"default",{contentStyle:i(C),contentClass:i(y)}),K(i(HZ),{id:i(o),role:"tooltip"},{default:X(()=>[_.ariaLabel?(T(),V(Ve,{key:0},[Ge(le(_.ariaLabel),1)],64)):ie(_.$slots,"default",{key:1})]),_:3},8,["id"]),ie(_.$slots,"arrow",{style:je(i(g)),side:i(h)})],10,zZ))],4))}});var $1=Ie(WZ,[["__file","content.vue"]]);const KZ=Ne({setRef:{type:Q(Function),required:!0},onlyChild:Boolean});var UZ=Y({props:KZ,setup(e,{slots:t}){const n=R(),o=mf(n,r=>{r?e.setRef(r.nextElementSibling):e.setRef(null)});return()=>{var r;const[a]=((r=t.default)==null?void 0:r.call(t))||[],l=e.onlyChild?p3(a.children):a.children;return K(Ve,{ref:o},[l])}}});const qZ=Y({name:"ElTooltipV2Trigger"}),YZ=Y({...qZ,props:{...O2,...Fg},setup(e){const t=e,{onClose:n,onOpen:o,onDelayOpen:r,triggerRef:a,contentId:l}=De(If);let s=!1;const u=y=>{a.value=y},c=()=>{s=!1},f=on(t.onMouseEnter,r),d=on(t.onMouseLeave,n),p=on(t.onMouseDown,()=>{n(),s=!0,document.addEventListener("mouseup",c,{once:!0})}),m=on(t.onFocus,()=>{s||o()}),v=on(t.onBlur,n),h=on(t.onClick,y=>{y.detail===0&&n()}),C={blur:v,click:h,focus:m,mousedown:p,mouseenter:f,mouseleave:d},g=(y,_,b)=>{y&&Object.entries(_).forEach(([w,S])=>{y[b](w,S)})};return ve(a,(y,_)=>{g(y,C,"addEventListener"),g(_,C,"removeEventListener"),y&&y.setAttribute("aria-describedby",l.value)}),zt(()=>{g(a.value,C,"removeEventListener"),document.removeEventListener("mouseup",c)}),(y,_)=>y.nowrap?(T(),re(i(UZ),{key:0,"set-ref":u,"only-child":""},{default:X(()=>[ie(y.$slots,"default")]),_:3})):(T(),V("button",mt({key:1,ref_key:"triggerRef",ref:a},y.$attrs),[ie(y.$slots,"default")],16))}});var GZ=Ie(YZ,[["__file","trigger.vue"]]);const XZ=Y({name:"ElTooltipV2"}),JZ=Y({...XZ,props:AZ,setup(e){const n=Cn(e),o=Et(gr(n,Object.keys(Lg))),r=Et(gr(n,Object.keys(xg))),a=Et(gr(n,Object.keys(Dg))),l=Et(gr(n,Object.keys(Fg)));return(s,u)=>(T(),re(LZ,vr(bl(a)),{default:X(({open:c})=>[K(GZ,mt(l,{nowrap:""}),{default:X(()=>[ie(s.$slots,"trigger")]),_:3},16),(T(),re(Pl,{to:s.to,disabled:!s.teleported},[s.fullTransition?(T(),re(fn,vr(mt({key:0},s.transitionProps)),{default:X(()=>[s.alwaysOn||c?(T(),re($1,vr(mt({key:0},r)),{arrow:X(({style:f,side:d})=>[s.showArrow?(T(),re(T1,mt({key:0},o,{style:f,side:d}),null,16,["style","side"])):te("v-if",!0)]),default:X(()=>[ie(s.$slots,"default")]),_:3},16)):te("v-if",!0)]),_:2},1040)):(T(),V(Ve,{key:1},[s.alwaysOn||c?(T(),re($1,vr(mt({key:0},r)),{arrow:X(({style:f,side:d})=>[s.showArrow?(T(),re(T1,mt({key:0},o,{style:f,side:d}),null,16,["style","side"])):te("v-if",!0)]),default:X(()=>[ie(s.$slots,"default")]),_:3},16)):te("v-if",!0)],64))],8,["to","disabled"]))]),_:3},16))}});var ZZ=Ie(JZ,[["__file","tooltip.vue"]]);const QZ=ut(ZZ),M2="left-check-change",A2="right-check-change",es=Ne({data:{type:Q(Array),default:()=>[]},titles:{type:Q(Array),default:()=>[]},buttonTexts:{type:Q(Array),default:()=>[]},filterPlaceholder:String,filterMethod:{type:Q(Function)},leftDefaultChecked:{type:Q(Array),default:()=>[]},rightDefaultChecked:{type:Q(Array),default:()=>[]},renderContent:{type:Q(Function)},modelValue:{type:Q(Array),default:()=>[]},format:{type:Q(Object),default:()=>({})},filterable:Boolean,props:{type:Q(Object),default:()=>en({label:"label",key:"key",disabled:"disabled"})},targetOrder:{type:String,values:["original","push","unshift"],default:"original"},validateEvent:{type:Boolean,default:!0}}),sm=(e,t)=>[e,t].every(Pe)||Pe(e)&&Tn(t),eQ={[Yt]:(e,t,n)=>[e,n].every(Pe)&&["left","right"].includes(t),[ft]:e=>Pe(e),[M2]:sm,[A2]:sm},im="checked-change",tQ=Ne({data:es.data,optionRender:{type:Q(Function)},placeholder:String,title:String,filterable:Boolean,format:es.format,filterMethod:es.filterMethod,defaultChecked:es.leftDefaultChecked,props:es.props}),nQ={[im]:sm},Vu=e=>{const t={label:"label",key:"key",disabled:"disabled"};return k(()=>({...t,...e.props}))},oQ=(e,t,n)=>{const o=Vu(e),r=k(()=>e.data.filter(f=>Xe(e.filterMethod)?e.filterMethod(t.query,f):String(f[o.value.label]||f[o.value.key]).toLowerCase().includes(t.query.toLowerCase()))),a=k(()=>r.value.filter(f=>!f[o.value.disabled])),l=k(()=>{const f=t.checked.length,d=e.data.length,{noChecked:p,hasChecked:m}=e.format;return p&&m?f>0?m.replace(/\${checked}/g,f.toString()).replace(/\${total}/g,d.toString()):p.replace(/\${total}/g,d.toString()):`${f}/${d}`}),s=k(()=>{const f=t.checked.length;return f>0&&f{const f=a.value.map(d=>d[o.value.key]);t.allChecked=f.length>0&&f.every(d=>t.checked.includes(d))},c=f=>{t.checked=f?a.value.map(d=>d[o.value.key]):[]};return ve(()=>t.checked,(f,d)=>{if(u(),t.checkChangeByUser){const p=f.concat(d).filter(m=>!f.includes(m)||!d.includes(m));n(im,f,p)}else n(im,f),t.checkChangeByUser=!0}),ve(a,()=>{u()}),ve(()=>e.data,()=>{const f=[],d=r.value.map(p=>p[o.value.key]);t.checked.forEach(p=>{d.includes(p)&&f.push(p)}),t.checkChangeByUser=!1,t.checked=f}),ve(()=>e.defaultChecked,(f,d)=>{if(d&&f.length===d.length&&f.every(v=>d.includes(v)))return;const p=[],m=a.value.map(v=>v[o.value.key]);f.forEach(v=>{m.includes(v)&&p.push(v)}),t.checkChangeByUser=!1,t.checked=p},{immediate:!0}),{filteredData:r,checkableData:a,checkedSummary:l,isIndeterminate:s,updateAllChecked:u,handleAllCheckedChange:c}},rQ=(e,t)=>({onSourceCheckedChange:(r,a)=>{e.leftChecked=r,a&&t(M2,r,a)},onTargetCheckedChange:(r,a)=>{e.rightChecked=r,a&&t(A2,r,a)}}),aQ=e=>{const t=Vu(e),n=k(()=>e.data.reduce((a,l)=>(a[l[t.value.key]]=l)&&a,{})),o=k(()=>e.data.filter(a=>!e.modelValue.includes(a[t.value.key]))),r=k(()=>e.targetOrder==="original"?e.data.filter(a=>e.modelValue.includes(a[t.value.key])):e.modelValue.reduce((a,l)=>{const s=n.value[l];return s&&a.push(s),a},[]));return{sourceData:o,targetData:r}},lQ=(e,t,n)=>{const o=Vu(e),r=(s,u,c)=>{n(ft,s),n(Yt,s,u,c)};return{addToLeft:()=>{const s=e.modelValue.slice();t.rightChecked.forEach(u=>{const c=s.indexOf(u);c>-1&&s.splice(c,1)}),r(s,"left",t.rightChecked)},addToRight:()=>{let s=e.modelValue.slice();const u=e.data.filter(c=>{const f=c[o.value.key];return t.leftChecked.includes(f)&&!e.modelValue.includes(f)}).map(c=>c[o.value.key]);s=e.targetOrder==="unshift"?u.concat(s):s.concat(u),e.targetOrder==="original"&&(s=e.data.filter(c=>s.includes(c[o.value.key])).map(c=>c[o.value.key])),r(s,"right",t.leftChecked)}}},sQ=Y({name:"ElTransferPanel"}),iQ=Y({...sQ,props:tQ,emits:nQ,setup(e,{expose:t,emit:n}){const o=e,r=Sn(),a=({option:_})=>_,{t:l}=$t(),s=Se("transfer"),u=Et({checked:[],allChecked:!1,query:"",checkChangeByUser:!0}),c=Vu(o),{filteredData:f,checkedSummary:d,isIndeterminate:p,handleAllCheckedChange:m}=oQ(o,u,n),v=k(()=>!Io(u.query)&&Io(f.value)),h=k(()=>!Io(r.default()[0].children)),{checked:C,allChecked:g,query:y}=Cn(u);return t({query:y}),(_,b)=>(T(),V("div",{class:N(i(s).b("panel"))},[F("p",{class:N(i(s).be("panel","header"))},[K(i(Ho),{modelValue:i(g),"onUpdate:modelValue":b[0]||(b[0]=w=>xt(g)?g.value=w:null),indeterminate:i(p),"validate-event":!1,onChange:i(m)},{default:X(()=>[Ge(le(_.title)+" ",1),F("span",null,le(i(d)),1)]),_:1},8,["modelValue","indeterminate","onChange"])],2),F("div",{class:N([i(s).be("panel","body"),i(s).is("with-footer",i(h))])},[_.filterable?(T(),re(i(zn),{key:0,modelValue:i(y),"onUpdate:modelValue":b[1]||(b[1]=w=>xt(y)?y.value=w:null),class:N(i(s).be("panel","filter")),size:"default",placeholder:_.placeholder,"prefix-icon":i(U4),clearable:"","validate-event":!1},null,8,["modelValue","class","placeholder","prefix-icon"])):te("v-if",!0),tt(K(i(xk),{modelValue:i(C),"onUpdate:modelValue":b[2]||(b[2]=w=>xt(C)?C.value=w:null),"validate-event":!1,class:N([i(s).is("filterable",_.filterable),i(s).be("panel","list")])},{default:X(()=>[(T(!0),V(Ve,null,bt(i(f),w=>(T(),re(i(Ho),{key:w[i(c).key],class:N(i(s).be("panel","item")),value:w[i(c).key],disabled:w[i(c).disabled],"validate-event":!1},{default:X(()=>{var S;return[K(a,{option:(S=_.optionRender)==null?void 0:S.call(_,w)},null,8,["option"])]}),_:2},1032,["class","value","disabled"]))),128))]),_:1},8,["modelValue","class"]),[[kt,!i(v)&&!i(Io)(_.data)]]),tt(F("p",{class:N(i(s).be("panel","empty"))},le(i(v)?i(l)("el.transfer.noMatch"):i(l)("el.transfer.noData")),3),[[kt,i(v)||i(Io)(_.data)]])],2),i(h)?(T(),V("p",{key:0,class:N(i(s).be("panel","footer"))},[ie(_.$slots,"default")],2)):te("v-if",!0)],2))}});var O1=Ie(iQ,[["__file","transfer-panel.vue"]]);const uQ={key:0},cQ={key:0},dQ=Y({name:"ElTransfer"}),fQ=Y({...dQ,props:es,emits:eQ,setup(e,{expose:t,emit:n}){const o=e,r=Sn(),{t:a}=$t(),l=Se("transfer"),{formItem:s}=qn(),u=Et({leftChecked:[],rightChecked:[]}),c=Vu(o),{sourceData:f,targetData:d}=aQ(o),{onSourceCheckedChange:p,onTargetCheckedChange:m}=rQ(u,n),{addToLeft:v,addToRight:h}=lQ(o,u,n),C=R(),g=R(),y=$=>{switch($){case"left":C.value.query="";break;case"right":g.value.query="";break}},_=k(()=>o.buttonTexts.length===2),b=k(()=>o.titles[0]||a("el.transfer.titles.0")),w=k(()=>o.titles[1]||a("el.transfer.titles.1")),S=k(()=>o.filterPlaceholder||a("el.transfer.filterPlaceholder"));ve(()=>o.modelValue,()=>{var $;o.validateEvent&&(($=s==null?void 0:s.validate)==null||$.call(s,"change").catch(O=>void 0))});const E=k(()=>$=>o.renderContent?o.renderContent(Ke,$):r.default?r.default({option:$}):Ke("span",$[c.value.label]||$[c.value.key]));return t({clearQuery:y,leftPanel:C,rightPanel:g}),($,O)=>(T(),V("div",{class:N(i(l).b())},[K(O1,{ref_key:"leftPanel",ref:C,data:i(f),"option-render":i(E),placeholder:i(S),title:i(b),filterable:$.filterable,format:$.format,"filter-method":$.filterMethod,"default-checked":$.leftDefaultChecked,props:o.props,onCheckedChange:i(p)},{default:X(()=>[ie($.$slots,"left-footer")]),_:3},8,["data","option-render","placeholder","title","filterable","format","filter-method","default-checked","props","onCheckedChange"]),F("div",{class:N(i(l).e("buttons"))},[K(i($n),{type:"primary",class:N([i(l).e("button"),i(l).is("with-texts",i(_))]),disabled:i(Io)(u.rightChecked),onClick:i(v)},{default:X(()=>[K(i(ze),null,{default:X(()=>[K(i(Aa))]),_:1}),i(pn)($.buttonTexts[0])?te("v-if",!0):(T(),V("span",uQ,le($.buttonTexts[0]),1))]),_:1},8,["class","disabled","onClick"]),K(i($n),{type:"primary",class:N([i(l).e("button"),i(l).is("with-texts",i(_))]),disabled:i(Io)(u.leftChecked),onClick:i(h)},{default:X(()=>[i(pn)($.buttonTexts[1])?te("v-if",!0):(T(),V("span",cQ,le($.buttonTexts[1]),1)),K(i(ze),null,{default:X(()=>[K(i(Jn))]),_:1})]),_:1},8,["class","disabled","onClick"])],2),K(O1,{ref_key:"rightPanel",ref:g,data:i(d),"option-render":i(E),placeholder:i(S),filterable:$.filterable,format:$.format,"filter-method":$.filterMethod,title:i(w),"default-checked":$.rightDefaultChecked,props:o.props,onCheckedChange:i(m)},{default:X(()=>[ie($.$slots,"right-footer")]),_:3},8,["data","option-render","placeholder","filterable","format","filter-method","title","default-checked","props","onCheckedChange"])],2))}});var pQ=Ie(fQ,[["__file","transfer.vue"]]);const hQ=ut(pQ),ms="$treeNodeId",N1=function(e,t){!t||t[ms]||Object.defineProperty(t,ms,{value:e.id,enumerable:!1,configurable:!1,writable:!1})},Bg=function(e,t){return e?t[e]:t[ms]},um=(e,t,n)=>{const o=e.value.currentNode;n();const r=e.value.currentNode;o!==r&&t("current-change",r?r.data:null,r)},cm=e=>{let t=!0,n=!0,o=!0;for(let r=0,a=e.length;r"u"){const a=o[t];return a===void 0?"":a}};let mQ=0,dm=class Yc{constructor(t){this.id=mQ++,this.text=null,this.checked=!1,this.indeterminate=!1,this.data=null,this.expanded=!1,this.parent=null,this.visible=!0,this.isCurrent=!1,this.canFocus=!1;for(const n in t)Tt(t,n)&&(this[n]=t[n]);this.level=0,this.loaded=!1,this.childNodes=[],this.loading=!1,this.parent&&(this.level=this.parent.level+1)}initialize(){const t=this.store;if(!t)throw new Error("[Node]store is required!");t.registerNode(this);const n=t.props;if(n&&typeof n.isLeaf<"u"){const a=Cc(this,"isLeaf");typeof a=="boolean"&&(this.isLeafByUser=a)}if(t.lazy!==!0&&this.data?(this.setData(this.data),t.defaultExpandAll&&(this.expanded=!0,this.canFocus=!0)):this.level>0&&t.lazy&&t.defaultExpandAll&&this.expand(),Array.isArray(this.data)||N1(this,this.data),!this.data)return;const o=t.defaultExpandedKeys,r=t.key;r&&o&&o.includes(this.key)&&this.expand(null,t.autoExpandParent),r&&t.currentNodeKey!==void 0&&this.key===t.currentNodeKey&&(t.currentNode=this,t.currentNode.isCurrent=!0),t.lazy&&t._initDefaultCheckedNode(this),this.updateLeafState(),this.parent&&(this.level===1||this.parent.expanded===!0)&&(this.canFocus=!0)}setData(t){Array.isArray(t)||N1(this,t),this.data=t,this.childNodes=[];let n;this.level===0&&Array.isArray(this.data)?n=this.data:n=Cc(this,"children")||[];for(let o=0,r=n.length;o-1)return t.childNodes[n+1]}return null}get previousSibling(){const t=this.parent;if(t){const n=t.childNodes.indexOf(this);if(n>-1)return n>0?t.childNodes[n-1]:null}return null}contains(t,n=!0){return(this.childNodes||[]).some(o=>o===t||n&&o.contains(t))}remove(){const t=this.parent;t&&t.removeChild(this)}insertChild(t,n,o){if(!t)throw new Error("InsertChild error: child is required.");if(!(t instanceof Yc)){if(!o){const r=this.getChildren(!0);r.includes(t.data)||(typeof n>"u"||n<0?r.push(t.data):r.splice(n,0,t.data))}Object.assign(t,{parent:this,store:this.store}),t=Et(new Yc(t)),t instanceof Yc&&t.initialize()}t.level=this.level+1,typeof n>"u"||n<0?this.childNodes.push(t):this.childNodes.splice(n,0,t),this.updateLeafState()}insertBefore(t,n){let o;n&&(o=this.childNodes.indexOf(n)),this.insertChild(t,o)}insertAfter(t,n){let o;n&&(o=this.childNodes.indexOf(n),o!==-1&&(o+=1)),this.insertChild(t,o)}removeChild(t){const n=this.getChildren()||[],o=n.indexOf(t.data);o>-1&&n.splice(o,1);const r=this.childNodes.indexOf(t);r>-1&&(this.store&&this.store.deregisterNode(t),t.parent=null,this.childNodes.splice(r,1)),this.updateLeafState()}removeChildByData(t){let n=null;for(let o=0;o{if(n){let r=this.parent;for(;r.level>0;)r.expanded=!0,r=r.parent}this.expanded=!0,t&&t(),this.childNodes.forEach(r=>{r.canFocus=!0})};this.shouldLoadData()?this.loadData(r=>{Array.isArray(r)&&(this.checked?this.setChecked(!0,!0):this.store.checkStrictly||Ei(this),o())}):o()}doCreateChildren(t,n={}){t.forEach(o=>{this.insertChild(Object.assign({data:o},n),void 0,!0)})}collapse(){this.expanded=!1,this.childNodes.forEach(t=>{t.canFocus=!1})}shouldLoadData(){return this.store.lazy===!0&&this.store.load&&!this.loaded}updateLeafState(){if(this.store.lazy===!0&&this.loaded!==!0&&typeof this.isLeafByUser<"u"){this.isLeaf=this.isLeafByUser;return}const t=this.childNodes;if(!this.store.lazy||this.store.lazy===!0&&this.loaded===!0){this.isLeaf=!t||t.length===0;return}this.isLeaf=!1}setChecked(t,n,o,r){if(this.indeterminate=t==="half",this.checked=t===!0,this.store.checkStrictly)return;if(!(this.shouldLoadData()&&!this.store.checkDescendants)){const{all:l,allWithoutDisable:s}=cm(this.childNodes);!this.isLeaf&&!l&&s&&(this.checked=!1,t=!1);const u=()=>{if(n){const c=this.childNodes;for(let p=0,m=c.length;p{u(),Ei(this)},{checked:t!==!1});return}else u()}const a=this.parent;!a||a.level===0||o||Ei(a)}getChildren(t=!1){if(this.level===0)return this.data;const n=this.data;if(!n)return null;const o=this.store.props;let r="children";return o&&(r=o.children||"children"),n[r]===void 0&&(n[r]=null),t&&!n[r]&&(n[r]=[]),n[r]}updateChildren(){const t=this.getChildren()||[],n=this.childNodes.map(a=>a.data),o={},r=[];t.forEach((a,l)=>{const s=a[ms];!!s&&n.findIndex(c=>c[ms]===s)>=0?o[s]={index:l,data:a}:r.push({index:l,data:a})}),this.store.lazy||n.forEach(a=>{o[a[ms]]||this.removeChildByData(a)}),r.forEach(({index:a,data:l})=>{this.insertChild({data:l},a)}),this.updateLeafState()}loadData(t,n={}){if(this.store.lazy===!0&&this.store.load&&!this.loaded&&(!this.loading||Object.keys(n).length)){this.loading=!0;const o=a=>{this.childNodes=[],this.doCreateChildren(a,n),this.loaded=!0,this.loading=!1,this.updateLeafState(),t&&t.call(this,a)},r=()=>{this.loading=!1};this.store.load(this,o,r)}else t&&t.call(this)}eachNode(t){const n=[this];for(;n.length;){const o=n.shift();n.unshift(...o.childNodes),t(o)}}reInitChecked(){this.store.checkStrictly||Ei(this)}};class vQ{constructor(t){this.currentNode=null,this.currentNodeKey=null;for(const n in t)Tt(t,n)&&(this[n]=t[n]);this.nodesMap={}}initialize(){if(this.root=new dm({data:this.data,store:this}),this.root.initialize(),this.lazy&&this.load){const t=this.load;t(this.root,n=>{this.root.doCreateChildren(n),this._initDefaultCheckedNodes()})}else this._initDefaultCheckedNodes()}filter(t){const n=this.filterNodeMethod,o=this.lazy,r=function(a){const l=a.root?a.root.childNodes:a.childNodes;if(l.forEach(s=>{s.visible=n.call(s,t,s.data,s),r(s)}),!a.visible&&l.length){let s=!0;s=!l.some(u=>u.visible),a.root?a.root.visible=s===!1:a.visible=s===!1}t&&a.visible&&!a.isLeaf&&(!o||a.loaded)&&a.expand()};r(this)}setData(t){t!==this.root.data?(this.root.setData(t),this._initDefaultCheckedNodes()):this.root.updateChildren()}getNode(t){if(t instanceof dm)return t;const n=dt(t)?Bg(this.key,t):t;return this.nodesMap[n]||null}insertBefore(t,n){const o=this.getNode(n);o.parent.insertBefore({data:t},o)}insertAfter(t,n){const o=this.getNode(n);o.parent.insertAfter({data:t},o)}remove(t){const n=this.getNode(t);n&&n.parent&&(n===this.currentNode&&(this.currentNode=null),n.parent.removeChild(n))}append(t,n){const o=Sl(n)?this.root:this.getNode(n);o&&o.insertChild({data:t})}_initDefaultCheckedNodes(){const t=this.defaultCheckedKeys||[],n=this.nodesMap;t.forEach(o=>{const r=n[o];r&&r.setChecked(!0,!this.checkStrictly)})}_initDefaultCheckedNode(t){(this.defaultCheckedKeys||[]).includes(t.key)&&t.setChecked(!0,!this.checkStrictly)}setDefaultCheckedKey(t){t!==this.defaultCheckedKeys&&(this.defaultCheckedKeys=t,this._initDefaultCheckedNodes())}registerNode(t){const n=this.key;!t||!t.data||(n?t.key!==void 0&&(this.nodesMap[t.key]=t):this.nodesMap[t.id]=t)}deregisterNode(t){!this.key||!t||!t.data||(t.childNodes.forEach(o=>{this.deregisterNode(o)}),delete this.nodesMap[t.key])}getCheckedNodes(t=!1,n=!1){const o=[],r=function(a){(a.root?a.root.childNodes:a.childNodes).forEach(s=>{(s.checked||n&&s.indeterminate)&&(!t||t&&s.isLeaf)&&o.push(s.data),r(s)})};return r(this),o}getCheckedKeys(t=!1){return this.getCheckedNodes(t).map(n=>(n||{})[this.key])}getHalfCheckedNodes(){const t=[],n=function(o){(o.root?o.root.childNodes:o.childNodes).forEach(a=>{a.indeterminate&&t.push(a.data),n(a)})};return n(this),t}getHalfCheckedKeys(){return this.getHalfCheckedNodes().map(t=>(t||{})[this.key])}_getAllNodes(){const t=[],n=this.nodesMap;for(const o in n)Tt(n,o)&&t.push(n[o]);return t}updateChildren(t,n){const o=this.nodesMap[t];if(!o)return;const r=o.childNodes;for(let a=r.length-1;a>=0;a--){const l=r[a];this.remove(l.data)}for(let a=0,l=n.length;au.level-c.level),a=Object.create(null),l=Object.keys(o);r.forEach(u=>u.setChecked(!1,!1));const s=u=>{u.childNodes.forEach(c=>{var f;a[c.data[t]]=!0,(f=c.childNodes)!=null&&f.length&&s(c)})};for(let u=0,c=r.length;u{C.isLeaf||C.setChecked(!1,!1),m(C)})};m(f)}}}setCheckedNodes(t,n=!1){const o=this.key,r={};t.forEach(a=>{r[(a||{})[o]]=!0}),this._setCheckedKeys(o,n,r)}setCheckedKeys(t,n=!1){this.defaultCheckedKeys=t;const o=this.key,r={};t.forEach(a=>{r[a]=!0}),this._setCheckedKeys(o,n,r)}setDefaultExpandedKeys(t){t=t||[],this.defaultExpandedKeys=t,t.forEach(n=>{const o=this.getNode(n);o&&o.expand(null,this.autoExpandParent)})}setChecked(t,n,o){const r=this.getNode(t);r&&r.setChecked(!!n,o)}getCurrentNode(){return this.currentNode}setCurrentNode(t){const n=this.currentNode;n&&(n.isCurrent=!1),this.currentNode=t,this.currentNode.isCurrent=!0}setUserCurrentNode(t,n=!0){const o=t[this.key],r=this.nodesMap[o];this.setCurrentNode(r),n&&this.currentNode.level>1&&this.currentNode.parent.expand(null,!0)}setCurrentNodeKey(t,n=!0){if(t==null){this.currentNode&&(this.currentNode.isCurrent=!1),this.currentNode=null;return}const o=this.getNode(t);o&&(this.setCurrentNode(o),n&&this.currentNode.level>1&&this.currentNode.parent.expand(null,!0))}}const gQ=Y({name:"ElTreeNodeContent",props:{node:{type:Object,required:!0},renderContent:Function},setup(e){const t=Se("tree"),n=De("NodeInstance"),o=De("RootTree");return()=>{const r=e.node,{data:a,store:l}=r;return e.renderContent?e.renderContent(Ke,{_self:n,node:r,data:a,store:l}):ie(o.ctx.slots,"default",{node:r,data:a},()=>[Ke("span",{class:t.be("node","label")},[r.label])])}}});var bQ=Ie(gQ,[["__file","tree-node-content.vue"]]);function P2(e){const t=De("TreeNodeMap",null),n={treeNodeExpand:o=>{e.node!==o&&e.node.collapse()},children:[]};return t&&t.children.push(n),yt("TreeNodeMap",n),{broadcastExpanded:o=>{if(e.accordion)for(const r of n.children)r.treeNodeExpand(o)}}}const R2=Symbol("dragEvents");function yQ({props:e,ctx:t,el$:n,dropIndicator$:o,store:r}){const a=Se("tree"),l=R({showDropIndicator:!1,draggingNode:null,dropNode:null,allowDrop:!0,dropType:null});return yt(R2,{treeNodeDragStart:({event:f,treeNode:d})=>{if(typeof e.allowDrag=="function"&&!e.allowDrag(d.node))return f.preventDefault(),!1;f.dataTransfer.effectAllowed="move";try{f.dataTransfer.setData("text/plain","")}catch{}l.value.draggingNode=d,t.emit("node-drag-start",d.node,f)},treeNodeDragOver:({event:f,treeNode:d})=>{const p=d,m=l.value.dropNode;m&&m.node.id!==p.node.id&&Kn(m.$el,a.is("drop-inner"));const v=l.value.draggingNode;if(!v||!p)return;let h=!0,C=!0,g=!0,y=!0;typeof e.allowDrop=="function"&&(h=e.allowDrop(v.node,p.node,"prev"),y=C=e.allowDrop(v.node,p.node,"inner"),g=e.allowDrop(v.node,p.node,"next")),f.dataTransfer.dropEffect=C||h||g?"move":"none",(h||C||g)&&(m==null?void 0:m.node.id)!==p.node.id&&(m&&t.emit("node-drag-leave",v.node,m.node,f),t.emit("node-drag-enter",v.node,p.node,f)),h||C||g?l.value.dropNode=p:l.value.dropNode=null,p.node.nextSibling===v.node&&(g=!1),p.node.previousSibling===v.node&&(h=!1),p.node.contains(v.node,!1)&&(C=!1),(v.node===p.node||v.node.contains(p.node))&&(h=!1,C=!1,g=!1);const _=p.$el.querySelector(`.${a.be("node","content")}`).getBoundingClientRect(),b=n.value.getBoundingClientRect();let w;const S=h?C?.25:g?.45:1:-1,E=g?C?.75:h?.55:0:1;let $=-9999;const O=f.clientY-_.top;O<_.height*S?w="before":O>_.height*E?w="after":C?w="inner":w="none";const A=p.$el.querySelector(`.${a.be("node","expand-icon")}`).getBoundingClientRect(),M=o.value;w==="before"?$=A.top-b.top:w==="after"&&($=A.bottom-b.top),M.style.top=`${$}px`,M.style.left=`${A.right-b.left}px`,w==="inner"?Mo(p.$el,a.is("drop-inner")):Kn(p.$el,a.is("drop-inner")),l.value.showDropIndicator=w==="before"||w==="after",l.value.allowDrop=l.value.showDropIndicator||y,l.value.dropType=w,t.emit("node-drag-over",v.node,p.node,f)},treeNodeDragEnd:f=>{const{draggingNode:d,dropType:p,dropNode:m}=l.value;if(f.preventDefault(),f.dataTransfer.dropEffect="move",d&&m){const v={data:d.node.data};p!=="none"&&d.node.remove(),p==="before"?m.node.parent.insertBefore(v,m.node):p==="after"?m.node.parent.insertAfter(v,m.node):p==="inner"&&m.node.insertChild(v),p!=="none"&&(r.value.registerNode(v),r.value.key&&d.node.eachNode(h=>{var C;(C=r.value.nodesMap[h.data[r.value.key]])==null||C.setChecked(h.checked,!r.value.checkStrictly)})),Kn(m.$el,a.is("drop-inner")),t.emit("node-drag-end",d.node,m.node,p,f),p!=="none"&&t.emit("node-drop",d.node,m.node,p,f)}d&&!m&&t.emit("node-drag-end",d.node,null,p,f),l.value.showDropIndicator=!1,l.value.draggingNode=null,l.value.dropNode=null,l.value.allowDrop=!0}}),{dragState:l}}const wQ=Y({name:"ElTreeNode",components:{ElCollapseTransition:Ef,ElCheckbox:Ho,NodeContent:bQ,ElIcon:ze,Loading:Er},props:{node:{type:dm,default:()=>({})},props:{type:Object,default:()=>({})},accordion:Boolean,renderContent:Function,renderAfterExpand:Boolean,showCheckbox:{type:Boolean,default:!1}},emits:["node-expand"],setup(e,t){const n=Se("tree"),{broadcastExpanded:o}=P2(e),r=De("RootTree"),a=R(!1),l=R(!1),s=R(null),u=R(null),c=R(null),f=De(R2),d=lt();yt("NodeInstance",d),e.node.expanded&&(a.value=!0,l.value=!0);const p=r.props.props.children||"children";ve(()=>{const O=e.node.data[p];return O&&[...O]},()=>{e.node.updateChildren()}),ve(()=>e.node.indeterminate,O=>{h(e.node.checked,O)}),ve(()=>e.node.checked,O=>{h(O,e.node.indeterminate)}),ve(()=>e.node.childNodes.length,()=>e.node.reInitChecked()),ve(()=>e.node.expanded,O=>{We(()=>a.value=O),O&&(l.value=!0)});const m=O=>Bg(r.props.nodeKey,O.data),v=O=>{const A=e.props.class;if(!A)return{};let M;if(Xe(A)){const{data:D}=O;M=A(D,O)}else M=A;return nt(M)?{[M]:!0}:M},h=(O,A)=>{(s.value!==O||u.value!==A)&&r.ctx.emit("check-change",e.node.data,O,A),s.value=O,u.value=A},C=O=>{um(r.store,r.ctx.emit,()=>r.store.value.setCurrentNode(e.node)),r.currentNode.value=e.node,r.props.expandOnClickNode&&y(),r.props.checkOnClickNode&&!e.node.disabled&&_(null,{target:{checked:!e.node.checked}}),r.ctx.emit("node-click",e.node.data,e.node,d,O)},g=O=>{r.instance.vnode.props.onNodeContextmenu&&(O.stopPropagation(),O.preventDefault()),r.ctx.emit("node-contextmenu",O,e.node.data,e.node,d)},y=()=>{e.node.isLeaf||(a.value?(r.ctx.emit("node-collapse",e.node.data,e.node,d),e.node.collapse()):(e.node.expand(),t.emit("node-expand",e.node.data,e.node,d)))},_=(O,A)=>{e.node.setChecked(A.target.checked,!r.props.checkStrictly),We(()=>{const M=r.store.value;r.ctx.emit("check",e.node.data,{checkedNodes:M.getCheckedNodes(),checkedKeys:M.getCheckedKeys(),halfCheckedNodes:M.getHalfCheckedNodes(),halfCheckedKeys:M.getHalfCheckedKeys()})})};return{ns:n,node$:c,tree:r,expanded:a,childNodeRendered:l,oldChecked:s,oldIndeterminate:u,getNodeKey:m,getNodeClass:v,handleSelectChange:h,handleClick:C,handleContextMenu:g,handleExpandIconClick:y,handleCheckChange:_,handleChildNodeExpand:(O,A,M)=>{o(A),r.ctx.emit("node-expand",O,A,M)},handleDragStart:O=>{r.props.draggable&&f.treeNodeDragStart({event:O,treeNode:e})},handleDragOver:O=>{O.preventDefault(),r.props.draggable&&f.treeNodeDragOver({event:O,treeNode:{$el:c.value,node:e.node}})},handleDrop:O=>{O.preventDefault()},handleDragEnd:O=>{r.props.draggable&&f.treeNodeDragEnd(O)},CaretRight:UC}}}),_Q=["aria-expanded","aria-disabled","aria-checked","draggable","data-key"],CQ=["aria-expanded"];function SQ(e,t,n,o,r,a){const l=qe("el-icon"),s=qe("el-checkbox"),u=qe("loading"),c=qe("node-content"),f=qe("el-tree-node"),d=qe("el-collapse-transition");return tt((T(),V("div",{ref:"node$",class:N([e.ns.b("node"),e.ns.is("expanded",e.expanded),e.ns.is("current",e.node.isCurrent),e.ns.is("hidden",!e.node.visible),e.ns.is("focusable",!e.node.disabled),e.ns.is("checked",!e.node.disabled&&e.node.checked),e.getNodeClass(e.node)]),role:"treeitem",tabindex:"-1","aria-expanded":e.expanded,"aria-disabled":e.node.disabled,"aria-checked":e.node.checked,draggable:e.tree.props.draggable,"data-key":e.getNodeKey(e.node),onClick:t[1]||(t[1]=Qe((...p)=>e.handleClick&&e.handleClick(...p),["stop"])),onContextmenu:t[2]||(t[2]=(...p)=>e.handleContextMenu&&e.handleContextMenu(...p)),onDragstart:t[3]||(t[3]=Qe((...p)=>e.handleDragStart&&e.handleDragStart(...p),["stop"])),onDragover:t[4]||(t[4]=Qe((...p)=>e.handleDragOver&&e.handleDragOver(...p),["stop"])),onDragend:t[5]||(t[5]=Qe((...p)=>e.handleDragEnd&&e.handleDragEnd(...p),["stop"])),onDrop:t[6]||(t[6]=Qe((...p)=>e.handleDrop&&e.handleDrop(...p),["stop"]))},[F("div",{class:N(e.ns.be("node","content")),style:je({paddingLeft:(e.node.level-1)*e.tree.props.indent+"px"})},[e.tree.props.icon||e.CaretRight?(T(),re(l,{key:0,class:N([e.ns.be("node","expand-icon"),e.ns.is("leaf",e.node.isLeaf),{expanded:!e.node.isLeaf&&e.expanded}]),onClick:Qe(e.handleExpandIconClick,["stop"])},{default:X(()=>[(T(),re(pt(e.tree.props.icon||e.CaretRight)))]),_:1},8,["class","onClick"])):te("v-if",!0),e.showCheckbox?(T(),re(s,{key:1,"model-value":e.node.checked,indeterminate:e.node.indeterminate,disabled:!!e.node.disabled,onClick:t[0]||(t[0]=Qe(()=>{},["stop"])),onChange:e.handleCheckChange},null,8,["model-value","indeterminate","disabled","onChange"])):te("v-if",!0),e.node.loading?(T(),re(l,{key:2,class:N([e.ns.be("node","loading-icon"),e.ns.is("loading")])},{default:X(()=>[K(u)]),_:1},8,["class"])):te("v-if",!0),K(c,{node:e.node,"render-content":e.renderContent},null,8,["node","render-content"])],6),K(d,null,{default:X(()=>[!e.renderAfterExpand||e.childNodeRendered?tt((T(),V("div",{key:0,class:N(e.ns.be("node","children")),role:"group","aria-expanded":e.expanded},[(T(!0),V(Ve,null,bt(e.node.childNodes,p=>(T(),re(f,{key:e.getNodeKey(p),"render-content":e.renderContent,"render-after-expand":e.renderAfterExpand,"show-checkbox":e.showCheckbox,node:p,accordion:e.accordion,props:e.props,onNodeExpand:e.handleChildNodeExpand},null,8,["render-content","render-after-expand","show-checkbox","node","accordion","props","onNodeExpand"]))),128))],10,CQ)),[[kt,e.expanded]]):te("v-if",!0)]),_:1})],42,_Q)),[[kt,e.node.visible]])}var kQ=Ie(wQ,[["render",SQ],["__file","tree-node.vue"]]);function EQ({el$:e},t){const n=Se("tree"),o=Ut([]),r=Ut([]);at(()=>{l()}),ar(()=>{o.value=Array.from(e.value.querySelectorAll("[role=treeitem]")),r.value=Array.from(e.value.querySelectorAll("input[type=checkbox]"))}),ve(r,s=>{s.forEach(u=>{u.setAttribute("tabindex","-1")})}),qt(e,"keydown",s=>{const u=s.target;if(!u.className.includes(n.b("node")))return;const c=s.code;o.value=Array.from(e.value.querySelectorAll(`.${n.is("focusable")}[role=treeitem]`));const f=o.value.indexOf(u);let d;if([Ue.up,Ue.down].includes(c)){if(s.preventDefault(),c===Ue.up){d=f===-1?0:f!==0?f-1:o.value.length-1;const m=d;for(;!t.value.getNode(o.value[d].dataset.key).canFocus;){if(d--,d===m){d=-1;break}d<0&&(d=o.value.length-1)}}else{d=f===-1?0:f=o.value.length&&(d=0)}}d!==-1&&o.value[d].focus()}[Ue.left,Ue.right].includes(c)&&(s.preventDefault(),u.click());const p=u.querySelector('[type="checkbox"]');[Ue.enter,Ue.space].includes(c)&&p&&(s.preventDefault(),p.click())});const l=()=>{var s;o.value=Array.from(e.value.querySelectorAll(`.${n.is("focusable")}[role=treeitem]`)),r.value=Array.from(e.value.querySelectorAll("input[type=checkbox]"));const u=e.value.querySelectorAll(`.${n.is("checked")}[role=treeitem]`);if(u.length){u[0].setAttribute("tabindex","0");return}(s=o.value[0])==null||s.setAttribute("tabindex","0")}}const TQ=Y({name:"ElTree",components:{ElTreeNode:kQ},props:{data:{type:Array,default:()=>[]},emptyText:{type:String},renderAfterExpand:{type:Boolean,default:!0},nodeKey:String,checkStrictly:Boolean,defaultExpandAll:Boolean,expandOnClickNode:{type:Boolean,default:!0},checkOnClickNode:Boolean,checkDescendants:{type:Boolean,default:!1},autoExpandParent:{type:Boolean,default:!0},defaultCheckedKeys:Array,defaultExpandedKeys:Array,currentNodeKey:[String,Number],renderContent:Function,showCheckbox:{type:Boolean,default:!1},draggable:{type:Boolean,default:!1},allowDrag:Function,allowDrop:Function,props:{type:Object,default:()=>({children:"children",label:"label",disabled:"disabled"})},lazy:{type:Boolean,default:!1},highlightCurrent:Boolean,load:Function,filterNodeMethod:Function,accordion:Boolean,indent:{type:Number,default:18},icon:{type:Dt}},emits:["check-change","current-change","node-click","node-contextmenu","node-collapse","node-expand","check","node-drag-start","node-drag-end","node-drop","node-drag-leave","node-drag-enter","node-drag-over"],setup(e,t){const{t:n}=$t(),o=Se("tree"),r=De(ni,null),a=R(new vQ({key:e.nodeKey,data:e.data,lazy:e.lazy,props:e.props,load:e.load,currentNodeKey:e.currentNodeKey,checkStrictly:e.checkStrictly,checkDescendants:e.checkDescendants,defaultCheckedKeys:e.defaultCheckedKeys,defaultExpandedKeys:e.defaultExpandedKeys,autoExpandParent:e.autoExpandParent,defaultExpandAll:e.defaultExpandAll,filterNodeMethod:e.filterNodeMethod}));a.value.initialize();const l=R(a.value.root),s=R(null),u=R(null),c=R(null),{broadcastExpanded:f}=P2(e),{dragState:d}=yQ({props:e,ctx:t,el$:u,dropIndicator$:c,store:a});EQ({el$:u},a);const p=k(()=>{const{childNodes:x}=l.value,I=r?r.hasFilteredOptions!==0:!1;return(!x||x.length===0||x.every(({visible:H})=>!H))&&!I});ve(()=>e.currentNodeKey,x=>{a.value.setCurrentNodeKey(x)}),ve(()=>e.defaultCheckedKeys,x=>{a.value.setDefaultCheckedKey(x)}),ve(()=>e.defaultExpandedKeys,x=>{a.value.setDefaultExpandedKeys(x)}),ve(()=>e.data,x=>{a.value.setData(x)},{deep:!0}),ve(()=>e.checkStrictly,x=>{a.value.checkStrictly=x});const m=x=>{if(!e.filterNodeMethod)throw new Error("[Tree] filterNodeMethod is required when filter");a.value.filter(x)},v=x=>Bg(e.nodeKey,x.data),h=x=>{if(!e.nodeKey)throw new Error("[Tree] nodeKey is required in getNodePath");const I=a.value.getNode(x);if(!I)return[];const H=[I.data];let G=I.parent;for(;G&&G!==l.value;)H.push(G.data),G=G.parent;return H.reverse()},C=(x,I)=>a.value.getCheckedNodes(x,I),g=x=>a.value.getCheckedKeys(x),y=()=>{const x=a.value.getCurrentNode();return x?x.data:null},_=()=>{if(!e.nodeKey)throw new Error("[Tree] nodeKey is required in getCurrentKey");const x=y();return x?x[e.nodeKey]:null},b=(x,I)=>{if(!e.nodeKey)throw new Error("[Tree] nodeKey is required in setCheckedNodes");a.value.setCheckedNodes(x,I)},w=(x,I)=>{if(!e.nodeKey)throw new Error("[Tree] nodeKey is required in setCheckedKeys");a.value.setCheckedKeys(x,I)},S=(x,I,H)=>{a.value.setChecked(x,I,H)},E=()=>a.value.getHalfCheckedNodes(),$=()=>a.value.getHalfCheckedKeys(),O=(x,I=!0)=>{if(!e.nodeKey)throw new Error("[Tree] nodeKey is required in setCurrentNode");um(a,t.emit,()=>{f(x),a.value.setUserCurrentNode(x,I)})},A=(x,I=!0)=>{if(!e.nodeKey)throw new Error("[Tree] nodeKey is required in setCurrentKey");um(a,t.emit,()=>{f(),a.value.setCurrentNodeKey(x,I)})},M=x=>a.value.getNode(x),D=x=>{a.value.remove(x)},U=(x,I)=>{a.value.append(x,I)},j=(x,I)=>{a.value.insertBefore(x,I)},W=(x,I)=>{a.value.insertAfter(x,I)},L=(x,I,H)=>{f(I),t.emit("node-expand",x,I,H)},P=(x,I)=>{if(!e.nodeKey)throw new Error("[Tree] nodeKey is required in updateKeyChild");a.value.updateChildren(x,I)};return yt("RootTree",{ctx:t,props:e,store:a,root:l,currentNode:s,instance:lt()}),yt(Or,void 0),{ns:o,store:a,root:l,currentNode:s,dragState:d,el$:u,dropIndicator$:c,isEmpty:p,filter:m,getNodeKey:v,getNodePath:h,getCheckedNodes:C,getCheckedKeys:g,getCurrentNode:y,getCurrentKey:_,setCheckedNodes:b,setCheckedKeys:w,setChecked:S,getHalfCheckedNodes:E,getHalfCheckedKeys:$,setCurrentNode:O,setCurrentKey:A,t:n,getNode:M,remove:D,append:U,insertBefore:j,insertAfter:W,handleNodeExpand:L,updateKeyChildren:P}}});function $Q(e,t,n,o,r,a){const l=qe("el-tree-node");return T(),V("div",{ref:"el$",class:N([e.ns.b(),e.ns.is("dragging",!!e.dragState.draggingNode),e.ns.is("drop-not-allow",!e.dragState.allowDrop),e.ns.is("drop-inner",e.dragState.dropType==="inner"),{[e.ns.m("highlight-current")]:e.highlightCurrent}]),role:"tree"},[(T(!0),V(Ve,null,bt(e.root.childNodes,s=>(T(),re(l,{key:e.getNodeKey(s),node:s,props:e.props,accordion:e.accordion,"render-after-expand":e.renderAfterExpand,"show-checkbox":e.showCheckbox,"render-content":e.renderContent,onNodeExpand:e.handleNodeExpand},null,8,["node","props","accordion","render-after-expand","show-checkbox","render-content","onNodeExpand"]))),128)),e.isEmpty?(T(),V("div",{key:0,class:N(e.ns.e("empty-block"))},[ie(e.$slots,"empty",{},()=>{var s;return[F("span",{class:N(e.ns.e("empty-text"))},le((s=e.emptyText)!=null?s:e.t("el.tree.emptyText")),3)]})],2)):te("v-if",!0),tt(F("div",{ref:"dropIndicator$",class:N(e.ns.e("drop-indicator"))},null,2),[[kt,e.dragState.showDropIndicator]])],2)}var Gc=Ie(TQ,[["render",$Q],["__file","tree.vue"]]);Gc.install=e=>{e.component(Gc.name,Gc)};const Id=Gc,OQ=Id,NQ=(e,{attrs:t,emit:n},{select:o,tree:r,key:a})=>{const l=Se("tree-select");return ve(()=>e.data,()=>{e.filterable&&We(()=>{var u,c;(c=r.value)==null||c.filter((u=o.value)==null?void 0:u.states.inputValue)})},{flush:"post"}),{...gr(Cn(e),Object.keys(Ol.props)),...t,"onUpdate:modelValue":u=>n(ft,u),valueKey:a,popperClass:k(()=>{const u=[l.e("popper")];return e.popperClass&&u.push(e.popperClass),u.join(" ")}),filterMethod:(u="")=>{var c;e.filterMethod?e.filterMethod(u):e.remoteMethod?e.remoteMethod(u):(c=r.value)==null||c.filter(u)}}},IQ=Y({extends:Cd,setup(e,t){const n=Cd.setup(e,t);delete n.selectOptionClick;const o=lt().proxy;return We(()=>{n.select.states.cachedOptions.get(o.value)||n.select.onOptionCreate(o)}),ve(()=>t.attrs.visible,r=>{n.states.visible=r},{immediate:!0}),n},methods:{selectOptionClick(){this.$el.parentElement.click()}}});function fm(e){return e||e===0}function Vg(e){return Array.isArray(e)&&e.length}function bi(e){return Array.isArray(e)?e:fm(e)?[e]:[]}function Xc(e,t,n,o,r){for(let a=0;a{ve(()=>e.modelValue,()=>{e.showCheckbox&&We(()=>{const d=a.value;d&&!Wn(d.getCheckedKeys(),bi(e.modelValue))&&d.setCheckedKeys(bi(e.modelValue))})},{immediate:!0,deep:!0});const s=k(()=>({value:l.value,label:"label",children:"children",disabled:"disabled",isLeaf:"isLeaf",...e.props})),u=(d,p)=>{var m;const v=s.value[d];return Xe(v)?v(p,(m=a.value)==null?void 0:m.getNode(u("value",p))):p[v]},c=bi(e.modelValue).map(d=>Xc(e.data||[],p=>u("value",p)===d,p=>u("children",p),(p,m,v,h)=>h&&u("value",h))).filter(d=>fm(d)),f=k(()=>{if(!e.renderAfterExpand&&!e.lazy)return[];const d=[];return pm(e.data.concat(e.cacheData),p=>{const m=u("value",p);d.push({value:m,currentLabel:u("label",p),isDisabled:u("disabled",p)})},p=>u("children",p)),d});return{...gr(Cn(e),Object.keys(Id.props)),...t,nodeKey:l,expandOnClickNode:k(()=>!e.checkStrictly&&e.expandOnClickNode),defaultExpandedKeys:k(()=>e.defaultExpandedKeys?e.defaultExpandedKeys.concat(c):c),renderContent:(d,{node:p,data:m,store:v})=>d(IQ,{value:u("value",m),label:u("label",m),disabled:u("disabled",m),visible:p.visible},e.renderContent?()=>e.renderContent(d,{node:p,data:m,store:v}):n.default?()=>n.default({node:p,data:m,store:v}):void 0),filterNodeMethod:(d,p,m)=>e.filterNodeMethod?e.filterNodeMethod(d,p,m):d?new RegExp($v(d),"i").test(u("label",p)||""):!0,onNodeClick:(d,p,m)=>{var v,h,C,g;if((v=t.onNodeClick)==null||v.call(t,d,p,m),!(e.showCheckbox&&e.checkOnClickNode)){if(!e.showCheckbox&&(e.checkStrictly||p.isLeaf)){if(!u("disabled",d)){const y=(h=r.value)==null?void 0:h.states.options.get(u("value",d));(C=r.value)==null||C.handleOptionSelect(y)}}else e.expandOnClickNode&&m.proxy.handleExpandIconClick();(g=r.value)==null||g.focus()}},onCheck:(d,p)=>{var m;if(!e.showCheckbox)return;const v=u("value",d),h={};pm([a.value.store.root],_=>h[_.key]=_,_=>_.childNodes);const C=p.checkedKeys,g=e.multiple?bi(e.modelValue).filter(_=>!(_ in h)&&!C.includes(_)):[],y=g.concat(C);if(e.checkStrictly)o(ft,e.multiple?y:y.includes(v)?v:void 0);else if(e.multiple)o(ft,g.concat(a.value.getCheckedKeys(!0)));else{const _=Xc([d],S=>!Vg(u("children",S))&&!u("disabled",S),S=>u("children",S)),b=_?u("value",_):void 0,w=fm(e.modelValue)&&!!Xc([d],S=>u("value",S)===e.modelValue,S=>u("children",S));o(ft,b===e.modelValue||w?void 0:b)}We(()=>{var _;const b=bi(e.modelValue);a.value.setCheckedKeys(b),(_=t.onCheck)==null||_.call(t,d,{checkedKeys:a.value.getCheckedKeys(),checkedNodes:a.value.getCheckedNodes(),halfCheckedKeys:a.value.getHalfCheckedKeys(),halfCheckedNodes:a.value.getHalfCheckedNodes()})}),(m=r.value)==null||m.focus()},cacheOptions:f}};var AQ=Y({props:{data:{type:Array,default:()=>[]}},setup(e){const t=De(ni);return ve(()=>e.data,()=>{var n;e.data.forEach(r=>{t.states.cachedOptions.has(r.value)||t.states.cachedOptions.set(r.value,r)});const o=((n=t.selectRef)==null?void 0:n.querySelectorAll("input"))||[];Ct&&!Array.from(o).includes(document.activeElement)&&t.setSelected()},{flush:"post",immediate:!0}),()=>{}}});const PQ=Y({name:"ElTreeSelect",inheritAttrs:!1,props:{...Ol.props,...Id.props,cacheData:{type:Array,default:()=>[]}},setup(e,t){const{slots:n,expose:o}=t,r=R(),a=R(),l=k(()=>e.nodeKey||e.valueKey||"value"),s=NQ(e,t,{select:r,tree:a,key:l}),{cacheOptions:u,...c}=MQ(e,t,{select:r,tree:a,key:l}),f=Et({});return o(f),at(()=>{Object.assign(f,{...gr(a.value,["filter","updateKeyChildren","getCheckedNodes","setCheckedNodes","getCheckedKeys","setCheckedKeys","setChecked","getHalfCheckedNodes","getHalfCheckedKeys","getCurrentKey","getCurrentNode","setCurrentKey","setCurrentNode","getNode","remove","append","insertBefore","insertAfter"]),...gr(r.value,["focus","blur"])})}),()=>Ke(Ol,Et({...s,ref:d=>r.value=d}),{...n,default:()=>[Ke(AQ,{data:u.value}),Ke(Id,Et({...c,ref:d=>a.value=d}))]})}});var Jc=Ie(PQ,[["__file","tree-select.vue"]]);Jc.install=e=>{e.component(Jc.name,Jc)};const RQ=Jc,LQ=RQ,Hg=Symbol(),xQ={key:-1,level:-1,data:{}};var Ti=(e=>(e.KEY="id",e.LABEL="label",e.CHILDREN="children",e.DISABLED="disabled",e))(Ti||{}),hm=(e=>(e.ADD="add",e.DELETE="delete",e))(hm||{});const L2={type:Number,default:26},DQ=Ne({data:{type:Q(Array),default:()=>en([])},emptyText:{type:String},height:{type:Number,default:200},props:{type:Q(Object),default:()=>en({children:"children",label:"label",disabled:"disabled",value:"id"})},highlightCurrent:{type:Boolean,default:!1},showCheckbox:{type:Boolean,default:!1},defaultCheckedKeys:{type:Q(Array),default:()=>en([])},checkStrictly:{type:Boolean,default:!1},defaultExpandedKeys:{type:Q(Array),default:()=>en([])},indent:{type:Number,default:16},itemSize:L2,icon:{type:Dt},expandOnClickNode:{type:Boolean,default:!0},checkOnClickNode:{type:Boolean,default:!1},currentNodeKey:{type:Q([String,Number])},accordion:{type:Boolean,default:!1},filterMethod:{type:Q(Function)},perfMode:{type:Boolean,default:!0}}),FQ=Ne({node:{type:Q(Object),default:()=>en(xQ)},expanded:{type:Boolean,default:!1},checked:{type:Boolean,default:!1},indeterminate:{type:Boolean,default:!1},showCheckbox:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},current:{type:Boolean,default:!1},hiddenExpandIcon:{type:Boolean,default:!1},itemSize:L2}),BQ=Ne({node:{type:Q(Object),required:!0}}),x2="node-click",D2="node-expand",F2="node-collapse",B2="current-change",V2="check",H2="check-change",z2="node-contextmenu",VQ={[x2]:(e,t,n)=>e&&t&&n,[D2]:(e,t)=>e&&t,[F2]:(e,t)=>e&&t,[B2]:(e,t)=>e&&t,[V2]:(e,t)=>e&&t,[H2]:(e,t)=>e&&typeof t=="boolean",[z2]:(e,t,n)=>e&&t&&n},HQ={click:(e,t)=>!!(e&&t),toggle:e=>!!e,check:(e,t)=>e&&typeof t=="boolean"};function zQ(e,t){const n=R(new Set),o=R(new Set),{emit:r}=lt();ve([()=>t.value,()=>e.defaultCheckedKeys],()=>We(()=>{y(e.defaultCheckedKeys)}),{immediate:!0});const a=()=>{if(!t.value||!e.showCheckbox||e.checkStrictly)return;const{levelTreeNodeMap:_,maxLevel:b}=t.value,w=n.value,S=new Set;for(let E=b-1;E>=1;--E){const $=_.get(E);$&&$.forEach(O=>{const A=O.children;if(A){let M=!0,D=!1;for(const U of A){const j=U.key;if(w.has(j))D=!0;else if(S.has(j)){M=!1,D=!0;break}else M=!1}M?w.add(O.key):D?(S.add(O.key),w.delete(O.key)):(w.delete(O.key),S.delete(O.key))}})}o.value=S},l=_=>n.value.has(_.key),s=_=>o.value.has(_.key),u=(_,b,w=!0)=>{const S=n.value,E=($,O)=>{S[O?hm.ADD:hm.DELETE]($.key);const A=$.children;!e.checkStrictly&&A&&A.forEach(M=>{M.disabled||E(M,O)})};E(_,b),a(),w&&c(_,b)},c=(_,b)=>{const{checkedNodes:w,checkedKeys:S}=v(),{halfCheckedNodes:E,halfCheckedKeys:$}=h();r(V2,_.data,{checkedKeys:S,checkedNodes:w,halfCheckedKeys:$,halfCheckedNodes:E}),r(H2,_.data,b)};function f(_=!1){return v(_).checkedKeys}function d(_=!1){return v(_).checkedNodes}function p(){return h().halfCheckedKeys}function m(){return h().halfCheckedNodes}function v(_=!1){const b=[],w=[];if(t!=null&&t.value&&e.showCheckbox){const{treeNodeMap:S}=t.value;n.value.forEach(E=>{const $=S.get(E);$&&(!_||_&&$.isLeaf)&&(w.push(E),b.push($.data))})}return{checkedKeys:w,checkedNodes:b}}function h(){const _=[],b=[];if(t!=null&&t.value&&e.showCheckbox){const{treeNodeMap:w}=t.value;o.value.forEach(S=>{const E=w.get(S);E&&(b.push(S),_.push(E.data))})}return{halfCheckedNodes:_,halfCheckedKeys:b}}function C(_){n.value.clear(),o.value.clear(),We(()=>{y(_)})}function g(_,b){if(t!=null&&t.value&&e.showCheckbox){const w=t.value.treeNodeMap.get(_);w&&u(w,b,!1)}}function y(_){if(t!=null&&t.value){const{treeNodeMap:b}=t.value;if(e.showCheckbox&&b&&_)for(const w of _){const S=b.get(w);S&&!l(S)&&u(S,!0,!1)}}}return{updateCheckedKeys:a,toggleCheckbox:u,isChecked:l,isIndeterminate:s,getCheckedKeys:f,getCheckedNodes:d,getHalfCheckedKeys:p,getHalfCheckedNodes:m,setChecked:g,setCheckedKeys:C}}function jQ(e,t){const n=R(new Set([])),o=R(new Set([])),r=k(()=>Xe(e.filterMethod));function a(s){var u;if(!r.value)return;const c=new Set,f=o.value,d=n.value,p=[],m=((u=t.value)==null?void 0:u.treeNodes)||[],v=e.filterMethod;d.clear();function h(C){C.forEach(g=>{p.push(g),v!=null&&v(s,g.data)?p.forEach(_=>{c.add(_.key)}):g.isLeaf&&d.add(g.key);const y=g.children;if(y&&h(y),!g.isLeaf){if(!c.has(g.key))d.add(g.key);else if(y){let _=!0;for(const b of y)if(!d.has(b.key)){_=!1;break}_?f.add(g.key):f.delete(g.key)}}p.pop()})}return h(m),c}function l(s){return o.value.has(s.key)}return{hiddenExpandIconKeySet:o,hiddenNodeKeySet:n,doFilter:a,isForceHiddenExpandIcon:l}}function WQ(e,t){const n=R(new Set(e.defaultExpandedKeys)),o=R(),r=Ut();ve(()=>e.currentNodeKey,ae=>{o.value=ae},{immediate:!0}),ve(()=>e.data,ae=>{oe(ae)},{immediate:!0});const{isIndeterminate:a,isChecked:l,toggleCheckbox:s,getCheckedKeys:u,getCheckedNodes:c,getHalfCheckedKeys:f,getHalfCheckedNodes:d,setChecked:p,setCheckedKeys:m}=zQ(e,r),{doFilter:v,hiddenNodeKeySet:h,isForceHiddenExpandIcon:C}=jQ(e,r),g=k(()=>{var ae;return((ae=e.props)==null?void 0:ae.value)||Ti.KEY}),y=k(()=>{var ae;return((ae=e.props)==null?void 0:ae.children)||Ti.CHILDREN}),_=k(()=>{var ae;return((ae=e.props)==null?void 0:ae.disabled)||Ti.DISABLED}),b=k(()=>{var ae;return((ae=e.props)==null?void 0:ae.label)||Ti.LABEL}),w=k(()=>{const ae=n.value,Oe=h.value,we=[],ge=r.value&&r.value.treeNodes||[];function q(){const B=[];for(let z=ge.length-1;z>=0;--z)B.push(ge[z]);for(;B.length;){const z=B.pop();if(z&&(Oe.has(z.key)||we.push(z),ae.has(z.key))){const Z=z.children;if(Z){const ue=Z.length;for(let se=ue-1;se>=0;--se)B.push(Z[se])}}}}return q(),we}),S=k(()=>w.value.length>0);function E(ae){const Oe=new Map,we=new Map;let ge=1;function q(z,Z=1,ue=void 0){var se;const me=[];for(const _e of z){const $e=A(_e),Ce={level:Z,key:$e,data:_e};Ce.label=D(_e),Ce.parent=ue;const ce=O(_e);Ce.disabled=M(_e),Ce.isLeaf=!ce||ce.length===0,ce&&ce.length&&(Ce.children=q(ce,Z+1,Ce)),me.push(Ce),Oe.set($e,Ce),we.has(Z)||we.set(Z,[]),(se=we.get(Z))==null||se.push(Ce)}return Z>ge&&(ge=Z),me}const B=q(ae);return{treeNodeMap:Oe,levelTreeNodeMap:we,maxLevel:ge,treeNodes:B}}function $(ae){const Oe=v(ae);Oe&&(n.value=Oe)}function O(ae){return ae[y.value]}function A(ae){return ae?ae[g.value]:""}function M(ae){return ae[_.value]}function D(ae){return ae[b.value]}function U(ae){n.value.has(ae.key)?I(ae):x(ae)}function j(ae){n.value=new Set(ae)}function W(ae,Oe){t(x2,ae.data,ae,Oe),L(ae),e.expandOnClickNode&&U(ae),e.showCheckbox&&e.checkOnClickNode&&!ae.disabled&&s(ae,!l(ae),!0)}function L(ae){J(ae)||(o.value=ae.key,t(B2,ae.data,ae))}function P(ae,Oe){s(ae,Oe)}function x(ae){const Oe=n.value;if(r.value&&e.accordion){const{treeNodeMap:we}=r.value;Oe.forEach(ge=>{const q=we.get(ge);ae&&ae.level===(q==null?void 0:q.level)&&Oe.delete(ge)})}Oe.add(ae.key),t(D2,ae.data,ae)}function I(ae){n.value.delete(ae.key),t(F2,ae.data,ae)}function H(ae){return n.value.has(ae.key)}function G(ae){return!!ae.disabled}function J(ae){const Oe=o.value;return Oe!==void 0&&Oe===ae.key}function ee(){var ae,Oe;if(o.value)return(Oe=(ae=r.value)==null?void 0:ae.treeNodeMap.get(o.value))==null?void 0:Oe.data}function fe(){return o.value}function Te(ae){o.value=ae}function oe(ae){We(()=>r.value=E(ae))}function ke(ae){var Oe;const we=dt(ae)?A(ae):ae;return(Oe=r.value)==null?void 0:Oe.treeNodeMap.get(we)}return{tree:r,flattenTree:w,isNotEmpty:S,getKey:A,getChildren:O,toggleExpand:U,toggleCheckbox:s,isExpanded:H,isChecked:l,isIndeterminate:a,isDisabled:G,isCurrent:J,isForceHiddenExpandIcon:C,handleNodeClick:W,handleNodeCheck:P,getCurrentNode:ee,getCurrentKey:fe,setCurrentKey:Te,getCheckedKeys:u,getCheckedNodes:c,getHalfCheckedKeys:f,getHalfCheckedNodes:d,setChecked:p,setCheckedKeys:m,filter:$,setData:oe,getNode:ke,expandNode:x,collapseNode:I,setExpandedKeys:j}}var KQ=Y({name:"ElTreeNodeContent",props:BQ,setup(e){const t=De(Hg),n=Se("tree");return()=>{const o=e.node,{data:r}=o;return t!=null&&t.ctx.slots.default?t.ctx.slots.default({node:o,data:r}):Ke("span",{class:n.be("node","label")},[o==null?void 0:o.label])}}});const UQ=["aria-expanded","aria-disabled","aria-checked","data-key","onClick"],qQ=Y({name:"ElTreeNode"}),YQ=Y({...qQ,props:FQ,emits:HQ,setup(e,{emit:t}){const n=e,o=De(Hg),r=Se("tree"),a=k(()=>{var d;return(d=o==null?void 0:o.props.indent)!=null?d:16}),l=k(()=>{var d;return(d=o==null?void 0:o.props.icon)!=null?d:UC}),s=d=>{t("click",n.node,d)},u=()=>{t("toggle",n.node)},c=d=>{t("check",n.node,d)},f=d=>{var p,m,v,h;(v=(m=(p=o==null?void 0:o.instance)==null?void 0:p.vnode)==null?void 0:m.props)!=null&&v.onNodeContextmenu&&(d.stopPropagation(),d.preventDefault()),o==null||o.ctx.emit(z2,d,(h=n.node)==null?void 0:h.data,n.node)};return(d,p)=>{var m,v,h;return T(),V("div",{ref:"node$",class:N([i(r).b("node"),i(r).is("expanded",d.expanded),i(r).is("current",d.current),i(r).is("focusable",!d.disabled),i(r).is("checked",!d.disabled&&d.checked)]),role:"treeitem",tabindex:"-1","aria-expanded":d.expanded,"aria-disabled":d.disabled,"aria-checked":d.checked,"data-key":(m=d.node)==null?void 0:m.key,onClick:Qe(s,["stop"]),onContextmenu:f},[F("div",{class:N(i(r).be("node","content")),style:je({paddingLeft:`${(d.node.level-1)*i(a)}px`,height:d.itemSize+"px"})},[i(l)?(T(),re(i(ze),{key:0,class:N([i(r).is("leaf",!!((v=d.node)!=null&&v.isLeaf)),i(r).is("hidden",d.hiddenExpandIcon),{expanded:!((h=d.node)!=null&&h.isLeaf)&&d.expanded},i(r).be("node","expand-icon")]),onClick:Qe(u,["stop"])},{default:X(()=>[(T(),re(pt(i(l))))]),_:1},8,["class","onClick"])):te("v-if",!0),d.showCheckbox?(T(),re(i(Ho),{key:1,"model-value":d.checked,indeterminate:d.indeterminate,disabled:d.disabled,onChange:c,onClick:p[0]||(p[0]=Qe(()=>{},["stop"]))},null,8,["model-value","indeterminate","disabled"])):te("v-if",!0),K(i(KQ),{node:d.node},null,8,["node"])],6)],42,UQ)}}});var GQ=Ie(YQ,[["__file","tree-node.vue"]]);const XQ=Y({name:"ElTreeV2"}),JQ=Y({...XQ,props:DQ,emits:VQ,setup(e,{expose:t,emit:n}){const o=e,r=Sn(),a=k(()=>o.itemSize);yt(Hg,{ctx:{emit:n,slots:r},props:o,instance:lt()}),yt(Or,void 0);const{t:l}=$t(),s=Se("tree"),{flattenTree:u,isNotEmpty:c,toggleExpand:f,isExpanded:d,isIndeterminate:p,isChecked:m,isDisabled:v,isCurrent:h,isForceHiddenExpandIcon:C,handleNodeClick:g,handleNodeCheck:y,toggleCheckbox:_,getCurrentNode:b,getCurrentKey:w,setCurrentKey:S,getCheckedKeys:E,getCheckedNodes:$,getHalfCheckedKeys:O,getHalfCheckedNodes:A,setChecked:M,setCheckedKeys:D,filter:U,setData:j,getNode:W,expandNode:L,collapseNode:P,setExpandedKeys:x}=WQ(o,n);return t({toggleCheckbox:_,getCurrentNode:b,getCurrentKey:w,setCurrentKey:S,getCheckedKeys:E,getCheckedNodes:$,getHalfCheckedKeys:O,getHalfCheckedNodes:A,setChecked:M,setCheckedKeys:D,filter:U,setData:j,getNode:W,expandNode:L,collapseNode:P,setExpandedKeys:x}),(I,H)=>{var G;return T(),V("div",{class:N([i(s).b(),{[i(s).m("highlight-current")]:I.highlightCurrent}]),role:"tree"},[i(c)?(T(),re(i(UE),{key:0,"class-name":i(s).b("virtual-list"),data:i(u),total:i(u).length,height:I.height,"item-size":i(a),"perf-mode":I.perfMode},{default:X(({data:J,index:ee,style:fe})=>[(T(),re(GQ,{key:J[ee].key,style:je(fe),node:J[ee],expanded:i(d)(J[ee]),"show-checkbox":I.showCheckbox,checked:i(m)(J[ee]),indeterminate:i(p)(J[ee]),"item-size":i(a),disabled:i(v)(J[ee]),current:i(h)(J[ee]),"hidden-expand-icon":i(C)(J[ee]),onClick:i(g),onToggle:i(f),onCheck:i(y)},null,8,["style","node","expanded","show-checkbox","checked","indeterminate","item-size","disabled","current","hidden-expand-icon","onClick","onToggle","onCheck"]))]),_:1},8,["class-name","data","total","height","item-size","perf-mode"])):(T(),V("div",{key:1,class:N(i(s).e("empty-block"))},[F("span",{class:N(i(s).e("empty-text"))},le((G=I.emptyText)!=null?G:i(l)("el.tree.emptyText")),3)],2))],2)}}});var ZQ=Ie(JQ,[["__file","tree.vue"]]);const QQ=ut(ZQ),j2=Symbol("uploadContextKey"),eee="ElUpload";class tee extends Error{constructor(t,n,o,r){super(t),this.name="UploadAjaxError",this.status=n,this.method=o,this.url=r}}function I1(e,t,n){let o;return n.response?o=`${n.response.error||n.response}`:n.responseText?o=`${n.responseText}`:o=`fail to ${t.method} ${e} ${n.status}`,new tee(o,n.status,t.method,e)}function nee(e){const t=e.responseText||e.response;if(!t)return t;try{return JSON.parse(t)}catch{return t}}const oee=e=>{typeof XMLHttpRequest>"u"&&vn(eee,"XMLHttpRequest is undefined");const t=new XMLHttpRequest,n=e.action;t.upload&&t.upload.addEventListener("progress",a=>{const l=a;l.percent=a.total>0?a.loaded/a.total*100:0,e.onProgress(l)});const o=new FormData;if(e.data)for(const[a,l]of Object.entries(e.data))Pe(l)&&l.length?o.append(a,...l):o.append(a,l);o.append(e.filename,e.file,e.file.name),t.addEventListener("error",()=>{e.onError(I1(n,e,t))}),t.addEventListener("load",()=>{if(t.status<200||t.status>=300)return e.onError(I1(n,e,t));e.onSuccess(nee(t))}),t.open(e.method,n,!0),e.withCredentials&&"withCredentials"in t&&(t.withCredentials=!0);const r=e.headers||{};if(r instanceof Headers)r.forEach((a,l)=>t.setRequestHeader(l,a));else for(const[a,l]of Object.entries(r))Tn(l)||t.setRequestHeader(a,String(l));return t.send(o),t},W2=["text","picture","picture-card"];let ree=1;const mm=()=>Date.now()+ree++,K2=Ne({action:{type:String,default:"#"},headers:{type:Q(Object)},method:{type:String,default:"post"},data:{type:Q([Object,Function,Promise]),default:()=>en({})},multiple:Boolean,name:{type:String,default:"file"},drag:Boolean,withCredentials:Boolean,showFileList:{type:Boolean,default:!0},accept:{type:String,default:""},fileList:{type:Q(Array),default:()=>en([])},autoUpload:{type:Boolean,default:!0},listType:{type:String,values:W2,default:"text"},httpRequest:{type:Q(Function),default:oee},disabled:Boolean,limit:Number}),aee=Ne({...K2,beforeUpload:{type:Q(Function),default:Bt},beforeRemove:{type:Q(Function)},onRemove:{type:Q(Function),default:Bt},onChange:{type:Q(Function),default:Bt},onPreview:{type:Q(Function),default:Bt},onSuccess:{type:Q(Function),default:Bt},onProgress:{type:Q(Function),default:Bt},onError:{type:Q(Function),default:Bt},onExceed:{type:Q(Function),default:Bt},crossorigin:{type:Q(String)}}),lee=Ne({files:{type:Q(Array),default:()=>en([])},disabled:{type:Boolean,default:!1},handlePreview:{type:Q(Function),default:Bt},listType:{type:String,values:W2,default:"text"},crossorigin:{type:Q(String)}}),see={remove:e=>!!e},iee=["onKeydown"],uee=["src","crossorigin"],cee=["onClick"],dee=["title"],fee=["onClick"],pee=["onClick"],hee=Y({name:"ElUploadList"}),mee=Y({...hee,props:lee,emits:see,setup(e,{emit:t}){const n=e,{t:o}=$t(),r=Se("upload"),a=Se("icon"),l=Se("list"),s=to(),u=R(!1),c=k(()=>[r.b("list"),r.bm("list",n.listType),r.is("disabled",n.disabled)]),f=d=>{t("remove",d)};return(d,p)=>(T(),re(ku,{tag:"ul",class:N(i(c)),name:i(l).b()},{default:X(()=>[(T(!0),V(Ve,null,bt(d.files,m=>(T(),V("li",{key:m.uid||m.name,class:N([i(r).be("list","item"),i(r).is(m.status),{focusing:u.value}]),tabindex:"0",onKeydown:Pt(v=>!i(s)&&f(m),["delete"]),onFocus:p[0]||(p[0]=v=>u.value=!0),onBlur:p[1]||(p[1]=v=>u.value=!1),onClick:p[2]||(p[2]=v=>u.value=!1)},[ie(d.$slots,"default",{file:m},()=>[d.listType==="picture"||m.status!=="uploading"&&d.listType==="picture-card"?(T(),V("img",{key:0,class:N(i(r).be("list","item-thumbnail")),src:m.url,crossorigin:d.crossorigin,alt:""},null,10,uee)):te("v-if",!0),m.status==="uploading"||d.listType!=="picture-card"?(T(),V("div",{key:1,class:N(i(r).be("list","item-info"))},[F("a",{class:N(i(r).be("list","item-name")),onClick:Qe(v=>d.handlePreview(m),["prevent"])},[K(i(ze),{class:N(i(a).m("document"))},{default:X(()=>[K(i(_4))]),_:1},8,["class"]),F("span",{class:N(i(r).be("list","item-file-name")),title:m.name},le(m.name),11,dee)],10,cee),m.status==="uploading"?(T(),re(i(DE),{key:0,type:d.listType==="picture-card"?"circle":"line","stroke-width":d.listType==="picture-card"?6:2,percentage:Number(m.percentage),style:je(d.listType==="picture-card"?"":"margin-top: 0.5rem")},null,8,["type","stroke-width","percentage","style"])):te("v-if",!0)],2)):te("v-if",!0),F("label",{class:N(i(r).be("list","item-status-label"))},[d.listType==="text"?(T(),re(i(ze),{key:0,class:N([i(a).m("upload-success"),i(a).m("circle-check")])},{default:X(()=>[K(i(Nv))]),_:1},8,["class"])):["picture-card","picture"].includes(d.listType)?(T(),re(i(ze),{key:1,class:N([i(a).m("upload-success"),i(a).m("check")])},{default:X(()=>[K(i(Mu))]),_:1},8,["class"])):te("v-if",!0)],2),i(s)?te("v-if",!0):(T(),re(i(ze),{key:2,class:N(i(a).m("close")),onClick:v=>f(m)},{default:X(()=>[K(i(tr))]),_:2},1032,["class","onClick"])),te(" Due to close btn only appears when li gets focused disappears after li gets blurred, thus keyboard navigation can never reach close btn"),te(" This is a bug which needs to be fixed "),te(" TODO: Fix the incorrect navigation interaction "),i(s)?te("v-if",!0):(T(),V("i",{key:3,class:N(i(a).m("close-tip"))},le(i(o)("el.upload.deleteTip")),3)),d.listType==="picture-card"?(T(),V("span",{key:4,class:N(i(r).be("list","item-actions"))},[F("span",{class:N(i(r).be("list","item-preview")),onClick:v=>d.handlePreview(m)},[K(i(ze),{class:N(i(a).m("zoom-in"))},{default:X(()=>[K(i(ZC))]),_:1},8,["class"])],10,fee),i(s)?te("v-if",!0):(T(),V("span",{key:0,class:N(i(r).be("list","item-delete")),onClick:v=>f(m)},[K(i(ze),{class:N(i(a).m("delete"))},{default:X(()=>[K(i(YC))]),_:1},8,["class"])],10,pee))],2)):te("v-if",!0)])],42,iee))),128)),ie(d.$slots,"append")]),_:3},8,["class","name"]))}});var M1=Ie(mee,[["__file","upload-list.vue"]]);const vee=Ne({disabled:{type:Boolean,default:!1}}),gee={file:e=>Pe(e)},bee=["onDrop","onDragover"],U2="ElUploadDrag",yee=Y({name:U2}),wee=Y({...yee,props:vee,emits:gee,setup(e,{emit:t}){De(j2)||vn(U2,"usage: ");const o=Se("upload"),r=R(!1),a=to(),l=u=>{if(a.value)return;r.value=!1,u.stopPropagation();const c=Array.from(u.dataTransfer.files);t("file",c)},s=()=>{a.value||(r.value=!0)};return(u,c)=>(T(),V("div",{class:N([i(o).b("dragger"),i(o).is("dragover",r.value)]),onDrop:Qe(l,["prevent"]),onDragover:Qe(s,["prevent"]),onDragleave:c[0]||(c[0]=Qe(f=>r.value=!1,["prevent"]))},[ie(u.$slots,"default")],42,bee))}});var _ee=Ie(wee,[["__file","upload-dragger.vue"]]);const Cee=Ne({...K2,beforeUpload:{type:Q(Function),default:Bt},onRemove:{type:Q(Function),default:Bt},onStart:{type:Q(Function),default:Bt},onSuccess:{type:Q(Function),default:Bt},onProgress:{type:Q(Function),default:Bt},onError:{type:Q(Function),default:Bt},onExceed:{type:Q(Function),default:Bt}}),See=["onKeydown"],kee=["name","multiple","accept"],Eee=Y({name:"ElUploadContent",inheritAttrs:!1}),Tee=Y({...Eee,props:Cee,setup(e,{expose:t}){const n=e,o=Se("upload"),r=to(),a=Ut({}),l=Ut(),s=h=>{if(h.length===0)return;const{autoUpload:C,limit:g,fileList:y,multiple:_,onStart:b,onExceed:w}=n;if(g&&y.length+h.length>g){w(h,y);return}_||(h=h.slice(0,1));for(const S of h){const E=S;E.uid=mm(),b(E),C&&u(E)}},u=async h=>{if(l.value.value="",!n.beforeUpload)return f(h);let C,g={};try{const _=n.data,b=n.beforeUpload(h);g=nd(n.data)?pd(n.data):n.data,C=await b,nd(n.data)&&Wn(_,g)&&(g=pd(n.data))}catch{C=!1}if(C===!1){n.onRemove(h);return}let y=h;C instanceof Blob&&(C instanceof File?y=C:y=new File([C],h.name,{type:h.type})),f(Object.assign(y,{uid:h.uid}),g)},c=async(h,C)=>Xe(h)?h(C):h,f=async(h,C)=>{const{headers:g,data:y,method:_,withCredentials:b,name:w,action:S,onProgress:E,onSuccess:$,onError:O,httpRequest:A}=n;try{C=await c(C??y,h)}catch{n.onRemove(h);return}const{uid:M}=h,D={headers:g||{},withCredentials:b,file:h,data:C,method:_,filename:w,action:S,onProgress:j=>{E(j,h)},onSuccess:j=>{$(j,h),delete a.value[M]},onError:j=>{O(j,h),delete a.value[M]}},U=A(D);a.value[M]=U,U instanceof Promise&&U.then(D.onSuccess,D.onError)},d=h=>{const C=h.target.files;C&&s(Array.from(C))},p=()=>{r.value||(l.value.value="",l.value.click())},m=()=>{p()};return t({abort:h=>{Yx(a.value).filter(h?([g])=>String(h.uid)===g:()=>!0).forEach(([g,y])=>{y instanceof XMLHttpRequest&&y.abort(),delete a.value[g]})},upload:u}),(h,C)=>(T(),V("div",{class:N([i(o).b(),i(o).m(h.listType),i(o).is("drag",h.drag)]),tabindex:"0",onClick:p,onKeydown:Pt(Qe(m,["self"]),["enter","space"])},[h.drag?(T(),re(_ee,{key:0,disabled:i(r),onFile:s},{default:X(()=>[ie(h.$slots,"default")]),_:3},8,["disabled"])):ie(h.$slots,"default",{key:1}),F("input",{ref_key:"inputRef",ref:l,class:N(i(o).e("input")),name:h.name,multiple:h.multiple,accept:h.accept,type:"file",onChange:d,onClick:C[0]||(C[0]=Qe(()=>{},["stop"]))},null,42,kee)],42,See))}});var A1=Ie(Tee,[["__file","upload-content.vue"]]);const P1="ElUpload",R1=e=>{var t;(t=e.url)!=null&&t.startsWith("blob:")&&URL.revokeObjectURL(e.url)},$ee=(e,t)=>{const n=tC(e,"fileList",void 0,{passive:!0}),o=p=>n.value.find(m=>m.uid===p.uid);function r(p){var m;(m=t.value)==null||m.abort(p)}function a(p=["ready","uploading","success","fail"]){n.value=n.value.filter(m=>!p.includes(m.status))}const l=(p,m)=>{const v=o(m);v&&(console.error(p),v.status="fail",n.value.splice(n.value.indexOf(v),1),e.onError(p,v,n.value),e.onChange(v,n.value))},s=(p,m)=>{const v=o(m);v&&(e.onProgress(p,v,n.value),v.status="uploading",v.percentage=Math.round(p.percent))},u=(p,m)=>{const v=o(m);v&&(v.status="success",v.response=p,e.onSuccess(p,v,n.value),e.onChange(v,n.value))},c=p=>{Tn(p.uid)&&(p.uid=mm());const m={name:p.name,percentage:0,status:"ready",size:p.size,raw:p,uid:p.uid};if(e.listType==="picture-card"||e.listType==="picture")try{m.url=URL.createObjectURL(p)}catch(v){v.message,e.onError(v,m,n.value)}n.value=[...n.value,m],e.onChange(m,n.value)},f=async p=>{const m=p instanceof File?o(p):p;m||vn(P1,"file to be removed not found");const v=h=>{r(h);const C=n.value;C.splice(C.indexOf(h),1),e.onRemove(h,C),R1(h)};e.beforeRemove?await e.beforeRemove(m,n.value)!==!1&&v(m):v(m)};function d(){n.value.filter(({status:p})=>p==="ready").forEach(({raw:p})=>{var m;return p&&((m=t.value)==null?void 0:m.upload(p))})}return ve(()=>e.listType,p=>{p!=="picture-card"&&p!=="picture"||(n.value=n.value.map(m=>{const{raw:v,url:h}=m;if(!h&&v)try{m.url=URL.createObjectURL(v)}catch(C){e.onError(C,m,n.value)}return m}))}),ve(n,p=>{for(const m of p)m.uid||(m.uid=mm()),m.status||(m.status="success")},{immediate:!0,deep:!0}),{uploadFiles:n,abort:r,clearFiles:a,handleError:l,handleProgress:s,handleStart:c,handleSuccess:u,handleRemove:f,submit:d,revokeFileObjectURL:R1}},Oee=Y({name:"ElUpload"}),Nee=Y({...Oee,props:aee,setup(e,{expose:t}){const n=e,o=to(),r=Ut(),{abort:a,submit:l,clearFiles:s,uploadFiles:u,handleStart:c,handleError:f,handleRemove:d,handleSuccess:p,handleProgress:m,revokeFileObjectURL:v}=$ee(n,r),h=k(()=>n.listType==="picture-card"),C=k(()=>({...n,fileList:u.value,onStart:c,onProgress:m,onSuccess:p,onError:f,onRemove:d}));return zt(()=>{u.value.forEach(v)}),yt(j2,{accept:Lt(n,"accept")}),t({abort:a,submit:l,clearFiles:s,handleStart:c,handleRemove:d}),(g,y)=>(T(),V("div",null,[i(h)&&g.showFileList?(T(),re(M1,{key:0,disabled:i(o),"list-type":g.listType,files:i(u),crossorigin:g.crossorigin,"handle-preview":g.onPreview,onRemove:i(d)},Sr({append:X(()=>[K(A1,mt({ref_key:"uploadRef",ref:r},i(C)),{default:X(()=>[g.$slots.trigger?ie(g.$slots,"trigger",{key:0}):te("v-if",!0),!g.$slots.trigger&&g.$slots.default?ie(g.$slots,"default",{key:1}):te("v-if",!0)]),_:3},16)]),_:2},[g.$slots.file?{name:"default",fn:X(({file:_})=>[ie(g.$slots,"file",{file:_})])}:void 0]),1032,["disabled","list-type","files","crossorigin","handle-preview","onRemove"])):te("v-if",!0),!i(h)||i(h)&&!g.showFileList?(T(),re(A1,mt({key:1,ref_key:"uploadRef",ref:r},i(C)),{default:X(()=>[g.$slots.trigger?ie(g.$slots,"trigger",{key:0}):te("v-if",!0),!g.$slots.trigger&&g.$slots.default?ie(g.$slots,"default",{key:1}):te("v-if",!0)]),_:3},16)):te("v-if",!0),g.$slots.trigger?ie(g.$slots,"default",{key:2}):te("v-if",!0),ie(g.$slots,"tip"),!i(h)&&g.showFileList?(T(),re(M1,{key:3,disabled:i(o),"list-type":g.listType,files:i(u),crossorigin:g.crossorigin,"handle-preview":g.onPreview,onRemove:i(d)},Sr({_:2},[g.$slots.file?{name:"default",fn:X(({file:_})=>[ie(g.$slots,"file",{file:_})])}:void 0]),1032,["disabled","list-type","files","crossorigin","handle-preview","onRemove"])):te("v-if",!0)]))}});var Iee=Ie(Nee,[["__file","upload.vue"]]);const Mee=ut(Iee),Aee=Ne({zIndex:{type:Number,default:9},rotate:{type:Number,default:-22},width:Number,height:Number,image:String,content:{type:Q([String,Array]),default:"Element Plus"},font:{type:Q(Object)},gap:{type:Q(Array),default:()=>[100,100]},offset:{type:Q(Array)}});function Pee(e){return e.replace(/([A-Z])/g,"-$1").toLowerCase()}function Ree(e){return Object.keys(e).map(t=>`${Pee(t)}: ${e[t]};`).join(" ")}function Lee(){return window.devicePixelRatio||1}const xee=(e,t)=>{let n=!1;return e.removedNodes.length&&t&&(n=Array.from(e.removedNodes).includes(t)),e.type==="attributes"&&e.target===t&&(n=!0),n},q2=3;function Pp(e,t,n=1){const o=document.createElement("canvas"),r=o.getContext("2d"),a=e*n,l=t*n;return o.setAttribute("width",`${a}px`),o.setAttribute("height",`${l}px`),r.save(),[r,o,a,l]}function Dee(){function e(t,n,o,r,a,l,s,u){const[c,f,d,p]=Pp(r,a,o);if(t instanceof HTMLImageElement)c.drawImage(t,0,0,d,p);else{const{color:G,fontSize:J,fontStyle:ee,fontWeight:fe,fontFamily:Te,textAlign:oe,textBaseline:ke}=l,ae=Number(J)*o;c.font=`${ee} normal ${fe} ${ae}px/${a}px ${Te}`,c.fillStyle=G,c.textAlign=oe,c.textBaseline=ke;const Oe=Array.isArray(t)?t:[t];Oe==null||Oe.forEach((we,ge)=>{c.fillText(we??"",d/2,ge*(ae+q2*o))})}const m=Math.PI/180*Number(n),v=Math.max(r,a),[h,C,g]=Pp(v,v,o);h.translate(g/2,g/2),h.rotate(m),d>0&&p>0&&h.drawImage(f,-d/2,-p/2);function y(G,J){const ee=G*Math.cos(m)-J*Math.sin(m),fe=G*Math.sin(m)+J*Math.cos(m);return[ee,fe]}let _=0,b=0,w=0,S=0;const E=d/2,$=p/2;[[0-E,0-$],[0+E,0-$],[0+E,0+$],[0-E,0+$]].forEach(([G,J])=>{const[ee,fe]=y(G,J);_=Math.min(_,ee),b=Math.max(b,ee),w=Math.min(w,fe),S=Math.max(S,fe)});const A=_+g/2,M=w+g/2,D=b-_,U=S-w,j=s*o,W=u*o,L=(D+j)*2,P=U+W,[x,I]=Pp(L,P);function H(G=0,J=0){x.drawImage(C,A,M,D,U,G,J,D,U)}return H(),H(D+j,-U/2-W/2),H(D+j,+U/2+W/2),[I.toDataURL(),L/o,P/o]}return e}const Fee=Y({name:"ElWatermark"}),Bee=Y({...Fee,props:Aee,setup(e){const t=e,n={position:"relative"},o=k(()=>{var A,M;return(M=(A=t.font)==null?void 0:A.color)!=null?M:"rgba(0,0,0,.15)"}),r=k(()=>{var A,M;return(M=(A=t.font)==null?void 0:A.fontSize)!=null?M:16}),a=k(()=>{var A,M;return(M=(A=t.font)==null?void 0:A.fontWeight)!=null?M:"normal"}),l=k(()=>{var A,M;return(M=(A=t.font)==null?void 0:A.fontStyle)!=null?M:"normal"}),s=k(()=>{var A,M;return(M=(A=t.font)==null?void 0:A.fontFamily)!=null?M:"sans-serif"}),u=k(()=>{var A,M;return(M=(A=t.font)==null?void 0:A.textAlign)!=null?M:"center"}),c=k(()=>{var A,M;return(M=(A=t.font)==null?void 0:A.textBaseline)!=null?M:"hanging"}),f=k(()=>t.gap[0]),d=k(()=>t.gap[1]),p=k(()=>f.value/2),m=k(()=>d.value/2),v=k(()=>{var A,M;return(M=(A=t.offset)==null?void 0:A[0])!=null?M:p.value}),h=k(()=>{var A,M;return(M=(A=t.offset)==null?void 0:A[1])!=null?M:m.value}),C=()=>{const A={zIndex:t.zIndex,position:"absolute",left:0,top:0,width:"100%",height:"100%",pointerEvents:"none",backgroundRepeat:"repeat"};let M=v.value-p.value,D=h.value-m.value;return M>0&&(A.left=`${M}px`,A.width=`calc(100% - ${M}px)`,M=0),D>0&&(A.top=`${D}px`,A.height=`calc(100% - ${D}px)`,D=0),A.backgroundPosition=`${M}px ${D}px`,A},g=Ut(null),y=Ut(),_=R(!1),b=()=>{y.value&&(y.value.remove(),y.value=void 0)},w=(A,M)=>{var D;g.value&&y.value&&(_.value=!0,y.value.setAttribute("style",Ree({...C(),backgroundImage:`url('${A}')`,backgroundSize:`${Math.floor(M)}px`})),(D=g.value)==null||D.append(y.value),setTimeout(()=>{_.value=!1}))},S=A=>{let M=120,D=64;const U=t.image,j=t.content,W=t.width,L=t.height;if(!U&&A.measureText){A.font=`${Number(r.value)}px ${s.value}`;const P=Array.isArray(j)?j:[j],x=P.map(I=>{const H=A.measureText(I);return[H.width,H.fontBoundingBoxAscent!==void 0?H.fontBoundingBoxAscent+H.fontBoundingBoxDescent:H.actualBoundingBoxAscent+H.actualBoundingBoxDescent]});M=Math.ceil(Math.max(...x.map(I=>I[0]))),D=Math.ceil(Math.max(...x.map(I=>I[1])))*P.length+(P.length-1)*q2}return[W??M,L??D]},E=Dee(),$=()=>{const M=document.createElement("canvas").getContext("2d"),D=t.image,U=t.content,j=t.rotate;if(M){y.value||(y.value=document.createElement("div"));const W=Lee(),[L,P]=S(M),x=I=>{const[H,G]=E(I||"",j,W,L,P,{color:o.value,fontSize:r.value,fontStyle:l.value,fontWeight:a.value,fontFamily:s.value,textAlign:u.value,textBaseline:c.value},f.value,d.value);w(H,G)};if(D){const I=new Image;I.onload=()=>{x(I)},I.onerror=()=>{x(U)},I.crossOrigin="anonymous",I.referrerPolicy="no-referrer",I.src=D}else x(U)}};return at(()=>{$()}),ve(()=>t,()=>{$()},{deep:!0,flush:"post"}),zt(()=>{b()}),eC(g,A=>{_.value||A.forEach(M=>{xee(M,y.value)&&(b(),$())})},{attributes:!0,subtree:!0,childList:!0}),(A,M)=>(T(),V("div",{ref_key:"containerRef",ref:g,style:je([n])},[ie(A.$slots,"default")],4))}});var Vee=Ie(Bee,[["__file","watermark.vue"]]);const Hee=ut(Vee),zee=Ne({zIndex:{type:Number,default:1001},visible:Boolean,fill:{type:String,default:"rgba(0,0,0,0.5)"},pos:{type:Q(Object)},targetAreaClickable:{type:Boolean,default:!0}}),jee=(e,t,n,o,r)=>{const a=R(null),l=()=>{let d;return nt(e.value)?d=document.querySelector(e.value):Xe(e.value)?d=e.value():d=e.value,d},s=()=>{const d=l();if(!d||!t.value){a.value=null;return}!Wee(d)&&t.value&&d.scrollIntoView(r.value);const{left:p,top:m,width:v,height:h}=d.getBoundingClientRect();a.value={left:p,top:m,width:v,height:h,radius:0}};at(()=>{ve([t,e],()=>{s()},{immediate:!0}),window.addEventListener("resize",s)}),zt(()=>{window.removeEventListener("resize",s)});const u=d=>{var p;return(p=Pe(n.value.offset)?n.value.offset[d]:n.value.offset)!=null?p:6},c=k(()=>{var d;if(!a.value)return a.value;const p=u(0),m=u(1),v=((d=n.value)==null?void 0:d.radius)||2;return{left:a.value.left-p,top:a.value.top-m,width:a.value.width+p*2,height:a.value.height+m*2,radius:v}}),f=k(()=>{const d=l();return!o.value||!d||!window.DOMRect?d||void 0:{getBoundingClientRect(){var p,m,v,h;return window.DOMRect.fromRect({width:((p=c.value)==null?void 0:p.width)||0,height:((m=c.value)==null?void 0:m.height)||0,x:((v=c.value)==null?void 0:v.left)||0,y:((h=c.value)==null?void 0:h.top)||0})}}});return{mergedPosInfo:c,triggerTarget:f}},Mf=Symbol("ElTour");function Wee(e){const t=window.innerWidth||document.documentElement.clientWidth,n=window.innerHeight||document.documentElement.clientHeight,{top:o,right:r,bottom:a,left:l}=e.getBoundingClientRect();return o>=0&&l>=0&&r<=t&&a<=n}const Kee=(e,t,n,o,r,a,l,s)=>{const u=R(),c=R(),f=R({}),d={x:u,y:c,placement:o,strategy:r,middlewareData:f},p=k(()=>{const g=[AS(i(a)),m8(),h8(),Uee()];return i(s)&&i(n)&&g.push(PS({element:i(n)})),g}),m=async()=>{if(!Ct)return;const g=i(e),y=i(t);if(!g||!y)return;const _=await RS(g,y,{placement:i(o),strategy:i(r),middleware:i(p)});Ss(d).forEach(b=>{d[b].value=_[b]})},v=k(()=>{if(!i(e))return{position:"fixed",top:"50%",left:"50%",transform:"translate3d(-50%, -50%, 0)",maxWidth:"100vw",zIndex:i(l)};const{overflow:g}=i(f);return{position:i(r),zIndex:i(l),top:i(c)!=null?`${i(c)}px`:"",left:i(u)!=null?`${i(u)}px`:"",maxWidth:g!=null&&g.maxWidth?`${g==null?void 0:g.maxWidth}px`:""}}),h=k(()=>{if(!i(s))return{};const{arrow:g}=i(f);return{left:(g==null?void 0:g.x)!=null?`${g==null?void 0:g.x}px`:"",top:(g==null?void 0:g.y)!=null?`${g==null?void 0:g.y}px`:""}});let C;return at(()=>{const g=i(e),y=i(t);g&&y&&(C=f8(g,y,m)),Mn(()=>{m()})}),zt(()=>{C&&C()}),{update:m,contentStyle:v,arrowStyle:h}},Uee=()=>({name:"overflow",async fn(e){const t=await p8(e);let n=0;return t.left>0&&(n=t.left),t.right>0&&(n=t.right),{data:{maxWidth:e.rects.floating.width-n}}}}),qee={style:{width:"100%",height:"100%"}},Yee=["d"],Gee=Y({name:"ElTourMask",inheritAttrs:!1}),Xee=Y({...Gee,props:zee,setup(e){const t=e,{ns:n}=De(Mf),o=k(()=>{var s,u;return(u=(s=t.pos)==null?void 0:s.radius)!=null?u:2}),r=k(()=>{const s=o.value,u=`a${s},${s} 0 0 1`;return{topRight:`${u} ${s},${s}`,bottomRight:`${u} ${-s},${s}`,bottomLeft:`${u} ${-s},${-s}`,topLeft:`${u} ${s},${-s}`}}),a=k(()=>{const s=window.innerWidth,u=window.innerHeight,c=r.value,f=`M${s},0 L0,0 L0,${u} L${s},${u} L${s},0 Z`,d=o.value;return t.pos?`${f} M${t.pos.left+d},${t.pos.top} h${t.pos.width-d*2} ${c.topRight} v${t.pos.height-d*2} ${c.bottomRight} h${-t.pos.width+d*2} ${c.bottomLeft} v${-t.pos.height+d*2} ${c.topLeft} z`:f}),l=k(()=>({fill:t.fill,pointerEvents:"auto",cursor:"auto"}));return Fv(Lt(t,"visible"),{ns:n}),(s,u)=>s.visible?(T(),V("div",mt({key:0,class:i(n).e("mask"),style:{position:"fixed",left:0,right:0,top:0,bottom:0,zIndex:s.zIndex,pointerEvents:s.pos&&s.targetAreaClickable?"none":"auto"}},s.$attrs),[(T(),V("svg",qee,[F("path",{class:N(i(n).e("hollow")),style:je(i(l)),d:i(a)},null,14,Yee)]))],16)):te("v-if",!0)}});var Jee=Ie(Xee,[["__file","mask.vue"]]);const Zee=["absolute","fixed"],Qee=["top-start","top-end","top","bottom-start","bottom-end","bottom","left-start","left-end","left","right-start","right-end","right"],zg=Ne({placement:{type:Q(String),values:Qee,default:"bottom"},reference:{type:Q(Object),default:null},strategy:{type:Q(String),values:Zee,default:"absolute"},offset:{type:Number,default:10},showArrow:Boolean,zIndex:{type:Number,default:2001}}),ete={close:()=>!0},tte=["data-side"],nte=Y({name:"ElTourContent"}),ote=Y({...nte,props:zg,emits:ete,setup(e,{emit:t}){const n=e,o=R(n.placement),r=R(n.strategy),a=R(null),l=R(null);ve(()=>n.placement,()=>{o.value=n.placement});const{contentStyle:s,arrowStyle:u}=Kee(Lt(n,"reference"),a,l,o,r,Lt(n,"offset"),Lt(n,"zIndex"),Lt(n,"showArrow")),c=k(()=>o.value.split("-")[0]),{ns:f}=De(Mf),d=()=>{t("close")},p=m=>{m.detail.focusReason==="pointer"&&m.preventDefault()};return(m,v)=>(T(),V("div",{ref_key:"contentRef",ref:a,style:je(i(s)),class:N(i(f).e("content")),"data-side":i(c),tabindex:"-1"},[K(i(Fu),{loop:"",trapped:"","focus-start-el":"container","focus-trap-el":a.value||void 0,onReleaseRequested:d,onFocusoutPrevented:p},{default:X(()=>[ie(m.$slots,"default")]),_:3},8,["focus-trap-el"]),m.showArrow?(T(),V("span",{key:0,ref_key:"arrowRef",ref:l,style:je(i(u)),class:N(i(f).e("arrow"))},null,6)):te("v-if",!0)],14,tte))}});var rte=Ie(ote,[["__file","content.vue"]]),ate=Y({name:"ElTourSteps",props:{current:{type:Number,default:0}},emits:["update-total"],setup(e,{slots:t,emit:n}){let o=0;return()=>{var r,a;const l=(r=t.default)==null?void 0:r.call(t),s=[];let u=0;function c(f){Pe(f)&&f.forEach(d=>{var p;((p=(d==null?void 0:d.type)||{})==null?void 0:p.name)==="ElTourStep"&&(s.push(d),u+=1)})}return l.length&&c(Ca((a=l[0])==null?void 0:a.children)),o!==u&&(o=u,n("update-total",u)),s.length?s[e.current]:null}}});const lte=Ne({modelValue:Boolean,current:{type:Number,default:0},showArrow:{type:Boolean,default:!0},showClose:{type:Boolean,default:!0},closeIcon:{type:Dt},placement:zg.placement,contentStyle:{type:Q([Object])},mask:{type:Q([Boolean,Object]),default:!0},gap:{type:Q(Object),default:()=>({offset:6,radius:2})},zIndex:{type:Number},scrollIntoViewOptions:{type:Q([Boolean,Object]),default:()=>({block:"center"})},type:{type:Q(String)},appendTo:{type:Q([String,Object]),default:"body"},closeOnPressEscape:{type:Boolean,default:!0},targetAreaClickable:{type:Boolean,default:!0}}),ste={[ft]:e=>dn(e),"update:current":e=>Je(e),close:e=>Je(e),finish:()=>!0,change:e=>Je(e)},ite=Y({name:"ElTour"}),ute=Y({...ite,props:lte,emits:ste,setup(e,{emit:t}){const n=e,o=Se("tour"),r=R(0),a=R(),l=tC(n,"current",t,{passive:!0}),s=k(()=>{var O;return(O=a.value)==null?void 0:O.target}),u=k(()=>[o.b(),C.value==="primary"?o.m("primary"):""]),c=k(()=>{var O;return((O=a.value)==null?void 0:O.placement)||n.placement}),f=k(()=>{var O,A;return(A=(O=a.value)==null?void 0:O.contentStyle)!=null?A:n.contentStyle}),d=k(()=>{var O,A;return(A=(O=a.value)==null?void 0:O.mask)!=null?A:n.mask}),p=k(()=>!!d.value&&n.modelValue),m=k(()=>dn(d.value)?void 0:d.value),v=k(()=>{var O,A;return!!s.value&&((A=(O=a.value)==null?void 0:O.showArrow)!=null?A:n.showArrow)}),h=k(()=>{var O,A;return(A=(O=a.value)==null?void 0:O.scrollIntoViewOptions)!=null?A:n.scrollIntoViewOptions}),C=k(()=>{var O,A;return(A=(O=a.value)==null?void 0:O.type)!=null?A:n.type}),{nextZIndex:g}=Zs(),y=g(),_=k(()=>{var O;return(O=n.zIndex)!=null?O:y}),{mergedPosInfo:b,triggerTarget:w}=jee(s,Lt(n,"modelValue"),Lt(n,"gap"),d,h);ve(()=>n.modelValue,O=>{O||(l.value=0)});const S=()=>{n.closeOnPressEscape&&(t("update:modelValue",!1),t("close",l.value))},E=O=>{r.value=O},$=Sn();return yt(Mf,{currentStep:a,current:l,total:r,showClose:Lt(n,"showClose"),closeIcon:Lt(n,"closeIcon"),mergedType:C,ns:o,slots:$,updateModelValue(O){t("update:modelValue",O)},onClose(){t("close",l.value)},onFinish(){t("finish")},onChange(){t("change",l.value)}}),(O,A)=>{var M,D;return T(),V(Ve,null,[(T(),re(Pl,{to:O.appendTo},[F("div",mt({class:i(u)},O.$attrs),[K(Jee,{visible:i(p),fill:(M=i(m))==null?void 0:M.color,style:je((D=i(m))==null?void 0:D.style),pos:i(b),"z-index":i(_),"target-area-clickable":O.targetAreaClickable},null,8,["visible","fill","style","pos","z-index","target-area-clickable"]),O.modelValue?(T(),re(rte,{key:i(l),reference:i(w),placement:i(c),"show-arrow":i(v),"z-index":i(_),style:je(i(f)),onClose:S},{default:X(()=>[K(i(ate),{current:i(l),onUpdateTotal:E},{default:X(()=>[ie(O.$slots,"default")]),_:3},8,["current"])]),_:3},8,["reference","placement","show-arrow","z-index","style"])):te("v-if",!0)],16)],8,["to"])),te(" just for IDE "),te("v-if",!0)],64)}}});var cte=Ie(ute,[["__file","tour.vue"]]);const dte=Ne({target:{type:Q([String,Object,Function])},title:String,description:String,showClose:{type:Boolean,default:void 0},closeIcon:{type:Dt},showArrow:{type:Boolean,default:void 0},placement:zg.placement,mask:{type:Q([Boolean,Object]),default:void 0},contentStyle:{type:Q([Object])},prevButtonProps:{type:Q(Object)},nextButtonProps:{type:Q(Object)},scrollIntoViewOptions:{type:Q([Boolean,Object]),default:void 0},type:{type:Q(String)}}),fte={close:()=>!0},pte=Y({name:"ElTourStep"}),hte=Y({...pte,props:dte,emits:fte,setup(e,{emit:t}){const n=e,{Close:o}=Av,{t:r}=$t(),{currentStep:a,current:l,total:s,showClose:u,closeIcon:c,mergedType:f,ns:d,slots:p,updateModelValue:m,onClose:v,onFinish:h,onChange:C}=De(Mf);ve(n,$=>{a.value=$},{immediate:!0});const g=k(()=>{var $;return($=n.showClose)!=null?$:u.value}),y=k(()=>{var $,O;return(O=($=n.closeIcon)!=null?$:c.value)!=null?O:o}),_=$=>{if($)return Fx($,["children","onClick"])},b=()=>{var $,O;l.value-=1,($=n.prevButtonProps)!=null&&$.onClick&&((O=n.prevButtonProps)==null||O.onClick()),C()},w=()=>{var $;l.value>=s.value-1?S():l.value+=1,($=n.nextButtonProps)!=null&&$.onClick&&n.nextButtonProps.onClick(),C()},S=()=>{E(),h()},E=()=>{m(!1),v(),t("close")};return($,O)=>(T(),V(Ve,null,[i(g)?(T(),V("button",{key:0,"aria-label":"Close",class:N(i(d).e("closebtn")),type:"button",onClick:E},[K(i(ze),{class:N(i(d).e("close"))},{default:X(()=>[(T(),re(pt(i(y))))]),_:1},8,["class"])],2)):te("v-if",!0),F("header",{class:N([i(d).e("header"),{"show-close":i(u)}])},[ie($.$slots,"header",{},()=>[F("span",{role:"heading",class:N(i(d).e("title"))},le($.title),3)])],2),F("div",{class:N(i(d).e("body"))},[ie($.$slots,"default",{},()=>[F("span",null,le($.description),1)])],2),F("footer",{class:N(i(d).e("footer"))},[F("div",{class:N(i(d).b("indicators"))},[i(p).indicators?(T(),re(pt(i(p).indicators),{key:0,current:i(l),total:i(s)},null,8,["current","total"])):(T(!0),V(Ve,{key:1},bt(i(s),(A,M)=>(T(),V("span",{key:A,class:N([i(d).b("indicator"),M===i(l)?"is-active":""])},null,2))),128))],2),F("div",{class:N(i(d).b("buttons"))},[i(l)>0?(T(),re(i($n),mt({key:0,size:"small",type:i(f)},_($.prevButtonProps),{onClick:b}),{default:X(()=>{var A,M;return[Ge(le((M=(A=$.prevButtonProps)==null?void 0:A.children)!=null?M:i(r)("el.tour.previous")),1)]}),_:1},16,["type"])):te("v-if",!0),i(l)<=i(s)-1?(T(),re(i($n),mt({key:1,size:"small",type:i(f)==="primary"?"default":"primary"},_($.nextButtonProps),{onClick:w}),{default:X(()=>{var A,M;return[Ge(le((M=(A=$.nextButtonProps)==null?void 0:A.children)!=null?M:i(l)===i(s)-1?i(r)("el.tour.finish"):i(r)("el.tour.next")),1)]}),_:1},16,["type"])):te("v-if",!0)],2)],2)],64))}});var Y2=Ie(hte,[["__file","step.vue"]]);const mte=ut(cte,{TourStep:Y2}),vte=tn(Y2),gte=Ne({container:{type:Q([String,Object])},offset:{type:Number,default:0},bound:{type:Number,default:15},duration:{type:Number,default:300},marker:{type:Boolean,default:!0},type:{type:Q(String),default:"default"},direction:{type:Q(String),default:"vertical"}}),bte={change:e=>nt(e),click:(e,t)=>e instanceof MouseEvent&&(nt(t)||pn(t))},G2=Symbol("anchor"),yte=Y({name:"ElAnchor"}),wte=Y({...yte,props:gte,emits:bte,setup(e,{expose:t,emit:n}){const o=e,r=R(""),a=R(null),l=R(null),s=R(),u={};let c=!1,f=0;const d=Se("anchor"),p=k(()=>[d.b(),o.type==="underline"?d.m("underline"):"",d.m(o.direction)]),m=$=>{u[$.href]=$.el},v=$=>{delete u[$]},h=$=>{r.value!==$&&(r.value=$,n("change",$))};let C=null;const g=$=>{if(!s.value)return;const O=ic($);if(!O)return;C&&C(),c=!0;const A=jy(O,s.value),M=ch(O,A),D=A.scrollHeight-A.clientHeight,U=Math.min(M-o.offset,D);C=Jx(s.value,f,U,o.duration,()=>{setTimeout(()=>{c=!1},20)})},y=$=>{$&&(h($),g($))},_=($,O)=>{n("click",$,O),y(O)},b=h3(()=>{s.value&&(f=Wy(s.value));const $=w();c||pn($)||h($)}),w=()=>{if(!s.value)return;const $=Wy(s.value),O=[];for(const A of Object.keys(u)){const M=ic(A);if(!M)continue;const D=jy(M,s.value),U=ch(M,D);O.push({top:U-o.offset-o.bound,href:A})}O.sort((A,M)=>A.top-M.top);for(let A=0;A$))return M.href}},S=()=>{const $=ic(o.container);!$||ff($)?s.value=window:s.value=$};qt(s,"scroll",b);const E=k(()=>{if(!a.value||!l.value||!r.value)return{};const $=u[r.value];if(!$)return{};const O=a.value.getBoundingClientRect(),A=l.value.getBoundingClientRect(),M=$.getBoundingClientRect();return o.direction==="horizontal"?{left:`${M.left-O.left}px`,width:`${M.width}px`,opacity:1}:{top:`${M.top-O.top+(M.height-A.height)/2}px`,opacity:1}});return at(()=>{S();const $=decodeURIComponent(window.location.hash);ic($)?y($):b()}),ve(()=>o.container,()=>{S()}),yt(G2,{ns:d,direction:o.direction,currentAnchor:r,addLink:m,removeLink:v,handleClick:_}),t({scrollTo:y}),($,O)=>(T(),V("div",{ref_key:"anchorRef",ref:a,class:N(i(p))},[$.marker?(T(),V("div",{key:0,ref_key:"markerRef",ref:l,class:N(i(d).e("marker")),style:je(i(E))},null,6)):te("v-if",!0),F("div",{class:N(i(d).e("list"))},[ie($.$slots,"default")],2)],2))}});var _te=Ie(wte,[["__file","anchor.vue"]]);const Cte=Ne({title:String,href:String}),Ste=["href"],kte=Y({name:"ElAnchorLink"}),Ete=Y({...kte,props:Cte,setup(e){const t=e,n=R(null),{ns:o,direction:r,currentAnchor:a,addLink:l,removeLink:s,handleClick:u}=De(G2),c=k(()=>[o.e("link"),o.is("active",a.value===t.href)]),f=d=>{u(d,t.href)};return ve(()=>t.href,(d,p)=>{We(()=>{p&&s(p),d&&l({href:d,el:n.value})})}),at(()=>{const{href:d}=t;d&&l({href:d,el:n.value})}),zt(()=>{const{href:d}=t;d&&s(d)}),(d,p)=>(T(),V("div",{class:N(i(o).e("item"))},[F("a",{ref_key:"linkRef",ref:n,class:N(i(c)),href:d.href,onClick:f},[ie(d.$slots,"default",{},()=>[Ge(le(d.title),1)])],10,Ste),d.$slots["sub-link"]&&i(r)==="vertical"?(T(),V("div",{key:0,class:N(i(o).e("list"))},[ie(d.$slots,"sub-link")],2)):te("v-if",!0)],2))}});var X2=Ie(Ete,[["__file","anchor-link.vue"]]);const Tte=ut(_te,{AnchorLink:X2}),$te=tn(X2),Ote=Ne({options:{type:Q(Array),default:()=>[]},modelValue:{type:[String,Number,Boolean],default:void 0},block:Boolean,size:gn,disabled:Boolean,validateEvent:{type:Boolean,default:!0},id:String,name:String,...An(["ariaLabel"])}),Nte={[ft]:e=>nt(e)||Je(e)||dn(e),[Yt]:e=>nt(e)||Je(e)||dn(e)},Ite=["id","aria-label","aria-labelledby"],Mte=["name","disabled","checked","onChange"],Ate=Y({name:"ElSegmented"}),Pte=Y({...Ate,props:Ote,emits:Nte,setup(e,{emit:t}){const n=e,o=Se("segmented"),r=xn(),a=hn(),l=to(),{formItem:s}=qn(),{inputId:u,isLabeledByFormItem:c}=cr(n,{formItemContext:s}),f=R(null),d=nM(),p=Et({isInit:!1,width:0,translateX:0,disabled:!1,focusVisible:!1}),m=O=>{const A=v(O);t(ft,A),t(Yt,A)},v=O=>dt(O)?O.value:O,h=O=>dt(O)?O.label:O,C=O=>!!(l.value||dt(O)&&O.disabled),g=O=>n.modelValue===v(O),y=O=>n.options.find(A=>v(A)===O),_=O=>[o.e("item"),o.is("selected",g(O)),o.is("disabled",C(O))],b=()=>{if(!f.value)return;const O=f.value.querySelector(".is-selected"),A=f.value.querySelector(".is-selected input");if(!O||!A){p.width=0,p.translateX=0,p.disabled=!1,p.focusVisible=!1;return}const M=O.getBoundingClientRect();p.isInit=!0,p.width=M.width,p.translateX=O.offsetLeft,p.disabled=C(y(n.modelValue));try{p.focusVisible=A.matches(":focus-visible")}catch{}},w=k(()=>[o.b(),o.m(a.value),o.is("block",n.block)]),S=k(()=>({width:`${p.width}px`,transform:`translateX(${p.translateX}px)`,display:p.isInit?"block":"none"})),E=k(()=>[o.e("item-selected"),o.is("disabled",p.disabled),o.is("focus-visible",p.focusVisible)]),$=k(()=>n.name||r.value);return Qt(f,b),ve(d,b),ve(()=>n.modelValue,()=>{var O;b(),n.validateEvent&&((O=s==null?void 0:s.validate)==null||O.call(s,"change").catch(A=>void 0))},{flush:"post"}),(O,A)=>(T(),V("div",{id:i(u),ref_key:"segmentedRef",ref:f,class:N(i(w)),role:"radiogroup","aria-label":i(c)?void 0:O.ariaLabel||"segmented","aria-labelledby":i(c)?i(s).labelId:void 0},[F("div",{class:N(i(o).e("group"))},[F("div",{style:je(i(S)),class:N(i(E))},null,6),(T(!0),V(Ve,null,bt(O.options,(M,D)=>(T(),V("label",{key:D,class:N(_(M))},[F("input",{class:N(i(o).e("item-input")),type:"radio",name:i($),disabled:C(M),checked:g(M),onChange:U=>m(M)},null,42,Mte),F("div",{class:N(i(o).e("item-label"))},[ie(O.$slots,"default",{item:M},()=>[Ge(le(h(M)),1)])],2)],2))),128))],2)],10,Ite))}});var Rte=Ie(Pte,[["__file","segmented.vue"]]);const Lte=ut(Rte);var xte=[L8,U8,gB,YJ,kB,MB,tk,KB,UB,$n,ik,f5,g5,D5,F5,XH,xH,nz,Ho,nH,xk,hz,Az,Pz,kz,uj,$8,_j,Cj,Sj,kj,Ej,KW,nK,oK,yK,vE,PK,k9,E9,T9,EE,zS,BF,ze,bU,TE,zn,$E,AU,ZU,QU,e7,t7,i7,mq,_q,Iq,ZS,DE,jk,bH,gH,qq,Zq,uz,ea,Ol,Cd,H7,FY,UY,qY,SG,OG,n2,BG,YG,GG,lX,uJ,cJ,qJ,uZ,cZ,su,mZ,WV,_Z,TZ,$Z,Un,QZ,hQ,OQ,LQ,QQ,Mee,Hee,mte,vte,Tte,$te,Lte];const No="ElInfiniteScroll",Dte=50,Fte=200,Bte=0,Vte={delay:{type:Number,default:Fte},distance:{type:Number,default:Bte},disabled:{type:Boolean,default:!1},immediate:{type:Boolean,default:!0}},jg=(e,t)=>Object.entries(Vte).reduce((n,[o,r])=>{var a,l;const{type:s,default:u}=r,c=e.getAttribute(`infinite-scroll-${o}`);let f=(l=(a=t[c])!=null?a:c)!=null?l:u;return f=f==="false"?!1:f,f=s(f),n[o]=Number.isNaN(f)?u:f,n},{}),J2=e=>{const{observer:t}=e[No];t&&(t.disconnect(),delete e[No].observer)},Hte=(e,t)=>{const{container:n,containerEl:o,instance:r,observer:a,lastScrollTop:l}=e[No],{disabled:s,distance:u}=jg(e,r),{clientHeight:c,scrollHeight:f,scrollTop:d}=o,p=d-l;if(e[No].lastScrollTop=d,a||s||p<0)return;let m=!1;if(n===e)m=f-(c+d)<=u;else{const{clientTop:v,scrollHeight:h}=e,C=ch(e,o);m=d+c>=C+v+h-u}m&&t.call(r)};function Rp(e,t){const{containerEl:n,instance:o}=e[No],{disabled:r}=jg(e,o);r||n.clientHeight===0||(n.scrollHeight<=n.clientHeight?t.call(o):J2(e))}const zte={async mounted(e,t){const{instance:n,value:o}=t;Xe(o)||vn(No,"'v-infinite-scroll' binding value must be a function"),await We();const{delay:r,immediate:a}=jg(e,n),l=Ov(e,!0),s=l===window?document.documentElement:l,u=il(Hte.bind(null,e,o),r);if(l){if(e[No]={instance:n,container:l,containerEl:s,delay:r,cb:o,onScroll:u,lastScrollTop:s.scrollTop},a){const c=new MutationObserver(il(Rp.bind(null,e,o),Dte));e[No].observer=c,c.observe(e,{childList:!0,subtree:!0}),Rp(e,o)}l.addEventListener("scroll",u)}},unmounted(e){if(!e[No])return;const{container:t,onScroll:n}=e[No];t==null||t.removeEventListener("scroll",n),J2(e)},async updated(e){if(!e[No])await We();else{const{containerEl:t,cb:n,observer:o}=e[No];t.clientHeight&&o&&Rp(e,n)}}},vm=zte;vm.install=e=>{e.directive("InfiniteScroll",vm)};const jte=vm;function Wte(e){let t;const n=R(!1),o=Et({...e,originalPosition:"",originalOverflow:"",visible:!1});function r(p){o.text=p}function a(){const p=o.parent,m=d.ns;if(!p.vLoadingAddClassList){let v=p.getAttribute("loading-number");v=Number.parseInt(v)-1,v?p.setAttribute("loading-number",v.toString()):(Kn(p,m.bm("parent","relative")),p.removeAttribute("loading-number")),Kn(p,m.bm("parent","hidden"))}l(),f.unmount()}function l(){var p,m;(m=(p=d.$el)==null?void 0:p.parentNode)==null||m.removeChild(d.$el)}function s(){var p;e.beforeClose&&!e.beforeClose()||(n.value=!0,clearTimeout(t),t=window.setTimeout(u,400),o.visible=!1,(p=e.closed)==null||p.call(e))}function u(){if(!n.value)return;const p=o.parent;n.value=!1,p.vLoadingAddClassList=void 0,a()}const c=Y({name:"ElLoading",setup(p,{expose:m}){const{ns:v,zIndex:h}=Cf("loading");return m({ns:v,zIndex:h}),()=>{const C=o.spinner||o.svg,g=Ke("svg",{class:"circular",viewBox:o.svgViewBox?o.svgViewBox:"0 0 50 50",...C?{innerHTML:C}:{}},[Ke("circle",{class:"path",cx:"25",cy:"25",r:"20",fill:"none"})]),y=o.text?Ke("p",{class:v.b("text")},[o.text]):void 0;return Ke(fn,{name:v.b("fade"),onAfterLeave:u},{default:X(()=>[tt(K("div",{style:{backgroundColor:o.background||""},class:[v.b("mask"),o.customClass,o.fullscreen?"is-fullscreen":""]},[Ke("div",{class:v.b("spinner")},[g,y])]),[[kt,o.visible]])])})}}}),f=iv(c),d=f.mount(document.createElement("div"));return{...Cn(o),setText:r,removeElLoadingChild:l,close:s,handleAfterLeave:u,vm:d,get $el(){return d.$el}}}let Sc;const gm=function(e={}){if(!Ct)return;const t=Kte(e);if(t.fullscreen&&Sc)return Sc;const n=Wte({...t,closed:()=>{var r;(r=t.closed)==null||r.call(t),t.fullscreen&&(Sc=void 0)}});Ute(t,t.parent,n),L1(t,t.parent,n),t.parent.vLoadingAddClassList=()=>L1(t,t.parent,n);let o=t.parent.getAttribute("loading-number");return o?o=`${Number.parseInt(o)+1}`:o="1",t.parent.setAttribute("loading-number",o),t.parent.appendChild(n.$el),We(()=>n.visible.value=t.visible),t.fullscreen&&(Sc=n),n},Kte=e=>{var t,n,o,r;let a;return nt(e.target)?a=(t=document.querySelector(e.target))!=null?t:document.body:a=e.target||document.body,{parent:a===document.body||e.body?document.body:a,background:e.background||"",svg:e.svg||"",svgViewBox:e.svgViewBox||"",spinner:e.spinner||!1,text:e.text||"",fullscreen:a===document.body&&((n=e.fullscreen)!=null?n:!0),lock:(o=e.lock)!=null?o:!1,customClass:e.customClass||"",visible:(r=e.visible)!=null?r:!0,beforeClose:e.beforeClose,closed:e.closed,target:a}},Ute=async(e,t,n)=>{const{nextZIndex:o}=n.vm.zIndex||n.vm._.exposed.zIndex,r={};if(e.fullscreen)n.originalPosition.value=ga(document.body,"position"),n.originalOverflow.value=ga(document.body,"overflow"),r.zIndex=o();else if(e.parent===document.body){n.originalPosition.value=ga(document.body,"position"),await We();for(const a of["top","left"]){const l=a==="top"?"scrollTop":"scrollLeft";r[a]=`${e.target.getBoundingClientRect()[a]+document.body[l]+document.documentElement[l]-Number.parseInt(ga(document.body,`margin-${a}`),10)}px`}for(const a of["height","width"])r[a]=`${e.target.getBoundingClientRect()[a]}px`}else n.originalPosition.value=ga(t,"position");for(const[a,l]of Object.entries(r))n.$el.style[a]=l},L1=(e,t,n)=>{const o=n.vm.ns||n.vm._.exposed.ns;["absolute","fixed","sticky"].includes(n.originalPosition.value)?Kn(t,o.bm("parent","relative")):Mo(t,o.bm("parent","relative")),e.fullscreen&&e.lock?Mo(t,o.bm("parent","hidden")):Kn(t,o.bm("parent","hidden"))},Zc=Symbol("ElLoading"),x1=(e,t)=>{var n,o,r,a;const l=t.instance,s=p=>dt(t.value)?t.value[p]:void 0,u=p=>{const m=nt(p)&&(l==null?void 0:l[p])||p;return m&&R(m)},c=p=>u(s(p)||e.getAttribute(`element-loading-${mo(p)}`)),f=(n=s("fullscreen"))!=null?n:t.modifiers.fullscreen,d={text:c("text"),svg:c("svg"),svgViewBox:c("svgViewBox"),spinner:c("spinner"),background:c("background"),customClass:c("customClass"),fullscreen:f,target:(o=s("target"))!=null?o:f?void 0:e,body:(r=s("body"))!=null?r:t.modifiers.body,lock:(a=s("lock"))!=null?a:t.modifiers.lock};e[Zc]={options:d,instance:gm(d)}},qte=(e,t)=>{for(const n of Object.keys(t))xt(t[n])&&(t[n].value=e[n])},D1={mounted(e,t){t.value&&x1(e,t)},updated(e,t){const n=e[Zc];t.oldValue!==t.value&&(t.value&&!t.oldValue?x1(e,t):t.value&&t.oldValue?dt(t.value)&&qte(t.value,n.options):n==null||n.instance.close())},unmounted(e){var t;(t=e[Zc])==null||t.instance.close(),e[Zc]=null}},Yte={install(e){e.directive("loading",D1),e.config.globalProperties.$loading=gm},directive:D1,service:gm},Z2=["success","info","warning","error"],Bn=en({customClass:"",center:!1,dangerouslyUseHTMLString:!1,duration:3e3,icon:void 0,id:"",message:"",onClose:void 0,showClose:!1,type:"info",plain:!1,offset:16,zIndex:0,grouping:!1,repeatNum:1,appendTo:Ct?document.body:void 0}),Gte=Ne({customClass:{type:String,default:Bn.customClass},center:{type:Boolean,default:Bn.center},dangerouslyUseHTMLString:{type:Boolean,default:Bn.dangerouslyUseHTMLString},duration:{type:Number,default:Bn.duration},icon:{type:Dt,default:Bn.icon},id:{type:String,default:Bn.id},message:{type:Q([String,Object,Function]),default:Bn.message},onClose:{type:Q(Function),default:Bn.onClose},showClose:{type:Boolean,default:Bn.showClose},type:{type:String,values:Z2,default:Bn.type},plain:{type:Boolean,default:Bn.plain},offset:{type:Number,default:Bn.offset},zIndex:{type:Number,default:Bn.zIndex},grouping:{type:Boolean,default:Bn.grouping},repeatNum:{type:Number,default:Bn.repeatNum}}),Xte={destroy:()=>!0},Jo=Hm([]),Jte=e=>{const t=Jo.findIndex(r=>r.id===e),n=Jo[t];let o;return t>0&&(o=Jo[t-1]),{current:n,prev:o}},Zte=e=>{const{prev:t}=Jte(e);return t?t.vm.exposed.bottom.value:0},Qte=(e,t)=>Jo.findIndex(o=>o.id===e)>0?16:t,ene=["id"],tne=["innerHTML"],nne=Y({name:"ElMessage"}),one=Y({...nne,props:Gte,emits:Xte,setup(e,{expose:t}){const n=e,{Close:o}=Pv,{ns:r,zIndex:a}=Cf("message"),{currentZIndex:l,nextZIndex:s}=a,u=R(),c=R(!1),f=R(0);let d;const p=k(()=>n.type?n.type==="error"?"danger":n.type:"info"),m=k(()=>{const E=n.type;return{[r.bm("icon",E)]:E&&Pa[E]}}),v=k(()=>n.icon||Pa[n.type]||""),h=k(()=>Zte(n.id)),C=k(()=>Qte(n.id,n.offset)+h.value),g=k(()=>f.value+C.value),y=k(()=>({top:`${C.value}px`,zIndex:l.value}));function _(){n.duration!==0&&({stop:d}=_l(()=>{w()},n.duration))}function b(){d==null||d()}function w(){c.value=!1}function S({code:E}){E===Ue.esc&&w()}return at(()=>{_(),s(),c.value=!0}),ve(()=>n.repeatNum,()=>{b(),_()}),qt(document,"keydown",S),Qt(u,()=>{f.value=u.value.getBoundingClientRect().height}),t({visible:c,bottom:g,close:w}),(E,$)=>(T(),re(fn,{name:i(r).b("fade"),onBeforeLeave:E.onClose,onAfterLeave:$[0]||($[0]=O=>E.$emit("destroy")),persisted:""},{default:X(()=>[tt(F("div",{id:E.id,ref_key:"messageRef",ref:u,class:N([i(r).b(),{[i(r).m(E.type)]:E.type},i(r).is("center",E.center),i(r).is("closable",E.showClose),i(r).is("plain",E.plain),E.customClass]),style:je(i(y)),role:"alert",onMouseenter:b,onMouseleave:_},[E.repeatNum>1?(T(),re(i(tk),{key:0,value:E.repeatNum,type:i(p),class:N(i(r).e("badge"))},null,8,["value","type","class"])):te("v-if",!0),i(v)?(T(),re(i(ze),{key:1,class:N([i(r).e("icon"),i(m)])},{default:X(()=>[(T(),re(pt(i(v))))]),_:1},8,["class"])):te("v-if",!0),ie(E.$slots,"default",{},()=>[E.dangerouslyUseHTMLString?(T(),V(Ve,{key:1},[te(" Caution here, message could've been compromised, never use user's input as message "),F("p",{class:N(i(r).e("content")),innerHTML:E.message},null,10,tne)],2112)):(T(),V("p",{key:0,class:N(i(r).e("content"))},le(E.message),3))]),E.showClose?(T(),re(i(ze),{key:2,class:N(i(r).e("closeBtn")),onClick:Qe(w,["stop"])},{default:X(()=>[K(i(o))]),_:1},8,["class","onClick"])):te("v-if",!0)],46,ene),[[kt,c.value]])]),_:3},8,["name","onBeforeLeave"]))}});var rne=Ie(one,[["__file","message.vue"]]);let ane=1;const Q2=e=>{const t=!e||nt(e)||Wt(e)||Xe(e)?{message:e}:e,n={...Bn,...t};if(!n.appendTo)n.appendTo=document.body;else if(nt(n.appendTo)){let o=document.querySelector(n.appendTo);Fo(o)||(o=document.body),n.appendTo=o}return n},lne=e=>{const t=Jo.indexOf(e);if(t===-1)return;Jo.splice(t,1);const{handler:n}=e;n.close()},sne=({appendTo:e,...t},n)=>{const o=`message_${ane++}`,r=t.onClose,a=document.createElement("div"),l={...t,id:o,onClose:()=>{r==null||r(),lne(f)},onDestroy:()=>{er(null,a)}},s=K(rne,l,Xe(l.message)||Wt(l.message)?{default:Xe(l.message)?l.message:()=>l.message}:null);s.appContext=n||xs._context,er(s,a),e.appendChild(a.firstElementChild);const u=s.component,f={id:o,vnode:s,vm:u,handler:{close:()=>{u.exposed.visible.value=!1}},props:s.component.props};return f},xs=(e={},t)=>{if(!Ct)return{close:()=>{}};if(Je(Ch.max)&&Jo.length>=Ch.max)return{close:()=>{}};const n=Q2(e);if(n.grouping&&Jo.length){const r=Jo.find(({vnode:a})=>{var l;return((l=a.props)==null?void 0:l.message)===n.message});if(r)return r.props.repeatNum+=1,r.props.type=n.type,r.handler}const o=sne(n,t);return Jo.push(o),o.handler};Z2.forEach(e=>{xs[e]=(t={},n)=>{const o=Q2(t);return xs({...o,type:e},n)}});function ine(e){for(const t of Jo)(!e||e===t.props.type)&&t.handler.close()}xs.closeAll=ine;xs._context=null;const Cr=eS(xs,"$message"),une=Y({name:"ElMessageBox",directives:{TrapFocus:TV},components:{ElButton:$n,ElFocusTrap:Fu,ElInput:zn,ElOverlay:mg,ElIcon:ze,...Pv},inheritAttrs:!1,props:{buttonSize:{type:String,validator:tS},modal:{type:Boolean,default:!0},lockScroll:{type:Boolean,default:!0},showClose:{type:Boolean,default:!0},closeOnClickModal:{type:Boolean,default:!0},closeOnPressEscape:{type:Boolean,default:!0},closeOnHashChange:{type:Boolean,default:!0},center:Boolean,draggable:Boolean,overflow:Boolean,roundButton:{default:!1,type:Boolean},container:{type:String,default:"body"},boxType:{type:String,default:""}},emits:["vanish","action"],setup(e,{emit:t}){const{locale:n,zIndex:o,ns:r,size:a}=Cf("message-box",k(()=>e.buttonSize)),{t:l}=n,{nextZIndex:s}=o,u=R(!1),c=Et({autofocus:!0,beforeClose:null,callback:null,cancelButtonText:"",cancelButtonClass:"",confirmButtonText:"",confirmButtonClass:"",customClass:"",customStyle:{},dangerouslyUseHTMLString:!1,distinguishCancelAndClose:!1,icon:"",inputPattern:null,inputPlaceholder:"",inputType:"text",inputValue:null,inputValidator:null,inputErrorMessage:"",message:null,modalFade:!0,modalClass:"",showCancelButton:!1,showConfirmButton:!0,type:"",title:void 0,showInput:!1,action:"",confirmButtonLoading:!1,cancelButtonLoading:!1,confirmButtonLoadingIcon:Po(Er),cancelButtonLoadingIcon:Po(Er),confirmButtonDisabled:!1,editorErrorMessage:"",validateError:!1,zIndex:s()}),f=k(()=>{const L=c.type;return{[r.bm("icon",L)]:L&&Pa[L]}}),d=xn(),p=xn(),m=k(()=>c.icon||Pa[c.type]||""),v=k(()=>!!c.message),h=R(),C=R(),g=R(),y=R(),_=R(),b=k(()=>c.confirmButtonClass);ve(()=>c.inputValue,async L=>{await We(),e.boxType==="prompt"&&L!==null&&D()},{immediate:!0}),ve(()=>u.value,L=>{var P,x;L&&(e.boxType!=="prompt"&&(c.autofocus?g.value=(x=(P=_.value)==null?void 0:P.$el)!=null?x:h.value:g.value=h.value),c.zIndex=s()),e.boxType==="prompt"&&(L?We().then(()=>{var I;y.value&&y.value.$el&&(c.autofocus?g.value=(I=U())!=null?I:h.value:g.value=h.value)}):(c.editorErrorMessage="",c.validateError=!1))});const w=k(()=>e.draggable),S=k(()=>e.overflow);nS(h,C,w,S),at(async()=>{await We(),e.closeOnHashChange&&window.addEventListener("hashchange",E)}),zt(()=>{e.closeOnHashChange&&window.removeEventListener("hashchange",E)});function E(){u.value&&(u.value=!1,We(()=>{c.action&&t("action",c.action)}))}const $=()=>{e.closeOnClickModal&&M(c.distinguishCancelAndClose?"close":"cancel")},O=qv($),A=L=>{if(c.inputType!=="textarea")return L.preventDefault(),M("confirm")},M=L=>{var P;e.boxType==="prompt"&&L==="confirm"&&!D()||(c.action=L,c.beforeClose?(P=c.beforeClose)==null||P.call(c,L,c,E):E())},D=()=>{if(e.boxType==="prompt"){const L=c.inputPattern;if(L&&!L.test(c.inputValue||""))return c.editorErrorMessage=c.inputErrorMessage||l("el.messagebox.error"),c.validateError=!0,!1;const P=c.inputValidator;if(typeof P=="function"){const x=P(c.inputValue);if(x===!1)return c.editorErrorMessage=c.inputErrorMessage||l("el.messagebox.error"),c.validateError=!0,!1;if(typeof x=="string")return c.editorErrorMessage=x,c.validateError=!0,!1}}return c.editorErrorMessage="",c.validateError=!1,!0},U=()=>{const L=y.value.$refs;return L.input||L.textarea},j=()=>{M("close")},W=()=>{e.closeOnPressEscape&&j()};return e.lockScroll&&Fv(u),{...Cn(c),ns:r,overlayEvent:O,visible:u,hasMessage:v,typeClass:f,contentId:d,inputId:p,btnSize:a,iconComponent:m,confirmButtonClasses:b,rootRef:h,focusStartRef:g,headerRef:C,inputRef:y,confirmRef:_,doClose:E,handleClose:j,onCloseRequested:W,handleWrapperClick:$,handleInputEnter:A,handleAction:M,t:l}}}),cne=["aria-label","aria-describedby"],dne=["aria-label"],fne=["id"];function pne(e,t,n,o,r,a){const l=qe("el-icon"),s=qe("close"),u=qe("el-input"),c=qe("el-button"),f=qe("el-focus-trap"),d=qe("el-overlay");return T(),re(fn,{name:"fade-in-linear",onAfterLeave:t[11]||(t[11]=p=>e.$emit("vanish")),persisted:""},{default:X(()=>[tt(K(d,{"z-index":e.zIndex,"overlay-class":[e.ns.is("message-box"),e.modalClass],mask:e.modal},{default:X(()=>[F("div",{role:"dialog","aria-label":e.title,"aria-modal":"true","aria-describedby":e.showInput?void 0:e.contentId,class:N(`${e.ns.namespace.value}-overlay-message-box`),onClick:t[8]||(t[8]=(...p)=>e.overlayEvent.onClick&&e.overlayEvent.onClick(...p)),onMousedown:t[9]||(t[9]=(...p)=>e.overlayEvent.onMousedown&&e.overlayEvent.onMousedown(...p)),onMouseup:t[10]||(t[10]=(...p)=>e.overlayEvent.onMouseup&&e.overlayEvent.onMouseup(...p))},[K(f,{loop:"",trapped:e.visible,"focus-trap-el":e.rootRef,"focus-start-el":e.focusStartRef,onReleaseRequested:e.onCloseRequested},{default:X(()=>[F("div",{ref:"rootRef",class:N([e.ns.b(),e.customClass,e.ns.is("draggable",e.draggable),{[e.ns.m("center")]:e.center}]),style:je(e.customStyle),tabindex:"-1",onClick:t[7]||(t[7]=Qe(()=>{},["stop"]))},[e.title!==null&&e.title!==void 0?(T(),V("div",{key:0,ref:"headerRef",class:N([e.ns.e("header"),{"show-close":e.showClose}])},[F("div",{class:N(e.ns.e("title"))},[e.iconComponent&&e.center?(T(),re(l,{key:0,class:N([e.ns.e("status"),e.typeClass])},{default:X(()=>[(T(),re(pt(e.iconComponent)))]),_:1},8,["class"])):te("v-if",!0),F("span",null,le(e.title),1)],2),e.showClose?(T(),V("button",{key:0,type:"button",class:N(e.ns.e("headerbtn")),"aria-label":e.t("el.messagebox.close"),onClick:t[0]||(t[0]=p=>e.handleAction(e.distinguishCancelAndClose?"close":"cancel")),onKeydown:t[1]||(t[1]=Pt(Qe(p=>e.handleAction(e.distinguishCancelAndClose?"close":"cancel"),["prevent"]),["enter"]))},[K(l,{class:N(e.ns.e("close"))},{default:X(()=>[K(s)]),_:1},8,["class"])],42,dne)):te("v-if",!0)],2)):te("v-if",!0),F("div",{id:e.contentId,class:N(e.ns.e("content"))},[F("div",{class:N(e.ns.e("container"))},[e.iconComponent&&!e.center&&e.hasMessage?(T(),re(l,{key:0,class:N([e.ns.e("status"),e.typeClass])},{default:X(()=>[(T(),re(pt(e.iconComponent)))]),_:1},8,["class"])):te("v-if",!0),e.hasMessage?(T(),V("div",{key:1,class:N(e.ns.e("message"))},[ie(e.$slots,"default",{},()=>[e.dangerouslyUseHTMLString?(T(),re(pt(e.showInput?"label":"p"),{key:1,for:e.showInput?e.inputId:void 0,innerHTML:e.message},null,8,["for","innerHTML"])):(T(),re(pt(e.showInput?"label":"p"),{key:0,for:e.showInput?e.inputId:void 0},{default:X(()=>[Ge(le(e.dangerouslyUseHTMLString?"":e.message),1)]),_:1},8,["for"]))])],2)):te("v-if",!0)],2),tt(F("div",{class:N(e.ns.e("input"))},[K(u,{id:e.inputId,ref:"inputRef",modelValue:e.inputValue,"onUpdate:modelValue":t[2]||(t[2]=p=>e.inputValue=p),type:e.inputType,placeholder:e.inputPlaceholder,"aria-invalid":e.validateError,class:N({invalid:e.validateError}),onKeydown:Pt(e.handleInputEnter,["enter"])},null,8,["id","modelValue","type","placeholder","aria-invalid","class","onKeydown"]),F("div",{class:N(e.ns.e("errormsg")),style:je({visibility:e.editorErrorMessage?"visible":"hidden"})},le(e.editorErrorMessage),7)],2),[[kt,e.showInput]])],10,fne),F("div",{class:N(e.ns.e("btns"))},[e.showCancelButton?(T(),re(c,{key:0,loading:e.cancelButtonLoading,"loading-icon":e.cancelButtonLoadingIcon,class:N([e.cancelButtonClass]),round:e.roundButton,size:e.btnSize,onClick:t[3]||(t[3]=p=>e.handleAction("cancel")),onKeydown:t[4]||(t[4]=Pt(Qe(p=>e.handleAction("cancel"),["prevent"]),["enter"]))},{default:X(()=>[Ge(le(e.cancelButtonText||e.t("el.messagebox.cancel")),1)]),_:1},8,["loading","loading-icon","class","round","size"])):te("v-if",!0),tt(K(c,{ref:"confirmRef",type:"primary",loading:e.confirmButtonLoading,"loading-icon":e.confirmButtonLoadingIcon,class:N([e.confirmButtonClasses]),round:e.roundButton,disabled:e.confirmButtonDisabled,size:e.btnSize,onClick:t[5]||(t[5]=p=>e.handleAction("confirm")),onKeydown:t[6]||(t[6]=Pt(Qe(p=>e.handleAction("confirm"),["prevent"]),["enter"]))},{default:X(()=>[Ge(le(e.confirmButtonText||e.t("el.messagebox.confirm")),1)]),_:1},8,["loading","loading-icon","class","round","disabled","size"]),[[kt,e.showConfirmButton]])],2)],6)]),_:3},8,["trapped","focus-trap-el","focus-start-el","onReleaseRequested"])],42,cne)]),_:3},8,["z-index","overlay-class","mask"]),[[kt,e.visible]])]),_:3})}var hne=Ie(une,[["render",pne],["__file","index.vue"]]);const vu=new Map,mne=e=>{let t=document.body;return e.appendTo&&(nt(e.appendTo)&&(t=document.querySelector(e.appendTo)),Fo(e.appendTo)&&(t=e.appendTo),Fo(t)||(t=document.body)),t},vne=(e,t,n=null)=>{const o=K(hne,e,Xe(e.message)||Wt(e.message)?{default:Xe(e.message)?e.message:()=>e.message}:null);return o.appContext=n,er(o,t),mne(e).appendChild(t.firstElementChild),o.component},gne=()=>document.createElement("div"),bne=(e,t)=>{const n=gne();e.onVanish=()=>{er(null,n),vu.delete(r)},e.onAction=a=>{const l=vu.get(r);let s;e.showInput?s={value:r.inputValue,action:a}:s=a,e.callback?e.callback(s,o.proxy):a==="cancel"||a==="close"?e.distinguishCancelAndClose&&a!=="cancel"?l.reject("close"):l.reject("cancel"):l.resolve(s)};const o=vne(e,n,t),r=o.proxy;for(const a in e)Tt(e,a)&&!Tt(r.$props,a)&&(r[a]=e[a]);return r.visible=!0,r};function oi(e,t=null){if(!Ct)return Promise.reject();let n;return nt(e)||Wt(e)?e={message:e}:n=e.callback,new Promise((o,r)=>{const a=bne(e,t??oi._context);vu.set(a,{options:e,callback:n,resolve:o,reject:r})})}const yne=["alert","confirm","prompt"],wne={alert:{closeOnPressEscape:!1,closeOnClickModal:!1},confirm:{showCancelButton:!0},prompt:{showCancelButton:!0,showInput:!0}};yne.forEach(e=>{oi[e]=_ne(e)});function _ne(e){return(t,n,o,r)=>{let a="";return dt(n)?(o=n,a=""):pn(n)?a="":a=n,oi(Object.assign({title:a,message:t,type:"",...wne[e]},o,{boxType:e}),r)}}oi.close=()=>{vu.forEach((e,t)=>{t.doClose()}),vu.clear()};oi._context=null;const ma=oi;ma.install=e=>{ma._context=e._context,e.config.globalProperties.$msgbox=ma,e.config.globalProperties.$messageBox=ma,e.config.globalProperties.$alert=ma.alert,e.config.globalProperties.$confirm=ma.confirm,e.config.globalProperties.$prompt=ma.prompt};const bm=ma,eT=["success","info","warning","error"],Cne=Ne({customClass:{type:String,default:""},dangerouslyUseHTMLString:Boolean,duration:{type:Number,default:4500},icon:{type:Dt},id:{type:String,default:""},message:{type:Q([String,Object]),default:""},offset:{type:Number,default:0},onClick:{type:Q(Function),default:()=>{}},onClose:{type:Q(Function),required:!0},position:{type:String,values:["top-right","top-left","bottom-right","bottom-left"],default:"top-right"},showClose:{type:Boolean,default:!0},title:{type:String,default:""},type:{type:String,values:[...eT,""],default:""},zIndex:Number}),Sne={destroy:()=>!0},kne=["id"],Ene=["textContent"],Tne={key:0},$ne=["innerHTML"],One=Y({name:"ElNotification"}),Nne=Y({...One,props:Cne,emits:Sne,setup(e,{expose:t}){const n=e,{ns:o,zIndex:r}=Cf("notification"),{nextZIndex:a,currentZIndex:l}=r,{Close:s}=Av,u=R(!1);let c;const f=k(()=>{const _=n.type;return _&&Pa[n.type]?o.m(_):""}),d=k(()=>n.type&&Pa[n.type]||n.icon),p=k(()=>n.position.endsWith("right")?"right":"left"),m=k(()=>n.position.startsWith("top")?"top":"bottom"),v=k(()=>{var _;return{[m.value]:`${n.offset}px`,zIndex:(_=n.zIndex)!=null?_:l.value}});function h(){n.duration>0&&({stop:c}=_l(()=>{u.value&&g()},n.duration))}function C(){c==null||c()}function g(){u.value=!1}function y({code:_}){_===Ue.delete||_===Ue.backspace?C():_===Ue.esc?u.value&&g():h()}return at(()=>{h(),a(),u.value=!0}),qt(document,"keydown",y),t({visible:u,close:g}),(_,b)=>(T(),re(fn,{name:i(o).b("fade"),onBeforeLeave:_.onClose,onAfterLeave:b[1]||(b[1]=w=>_.$emit("destroy")),persisted:""},{default:X(()=>[tt(F("div",{id:_.id,class:N([i(o).b(),_.customClass,i(p)]),style:je(i(v)),role:"alert",onMouseenter:C,onMouseleave:h,onClick:b[0]||(b[0]=(...w)=>_.onClick&&_.onClick(...w))},[i(d)?(T(),re(i(ze),{key:0,class:N([i(o).e("icon"),i(f)])},{default:X(()=>[(T(),re(pt(i(d))))]),_:1},8,["class"])):te("v-if",!0),F("div",{class:N(i(o).e("group"))},[F("h2",{class:N(i(o).e("title")),textContent:le(_.title)},null,10,Ene),tt(F("div",{class:N(i(o).e("content")),style:je(_.title?void 0:{margin:0})},[ie(_.$slots,"default",{},()=>[_.dangerouslyUseHTMLString?(T(),V(Ve,{key:1},[te(" Caution here, message could've been compromised, never use user's input as message "),F("p",{innerHTML:_.message},null,8,$ne)],2112)):(T(),V("p",Tne,le(_.message),1))])],6),[[kt,_.message]]),_.showClose?(T(),re(i(ze),{key:0,class:N(i(o).e("closeBtn")),onClick:Qe(g,["stop"])},{default:X(()=>[K(i(s))]),_:1},8,["class","onClick"])):te("v-if",!0)],2)],46,kne),[[kt,u.value]])]),_:3},8,["name","onBeforeLeave"]))}});var Ine=Ie(Nne,[["__file","notification.vue"]]);const Md={"top-left":[],"top-right":[],"bottom-left":[],"bottom-right":[]},ym=16;let Mne=1;const Ds=function(e={},t=null){if(!Ct)return{close:()=>{}};(typeof e=="string"||Wt(e))&&(e={message:e});const n=e.position||"top-right";let o=e.offset||0;Md[n].forEach(({vm:f})=>{var d;o+=(((d=f.el)==null?void 0:d.offsetHeight)||0)+ym}),o+=ym;const r=`notification_${Mne++}`,a=e.onClose,l={...e,offset:o,id:r,onClose:()=>{Ane(r,n,a)}};let s=document.body;Fo(e.appendTo)?s=e.appendTo:nt(e.appendTo)&&(s=document.querySelector(e.appendTo)),Fo(s)||(s=document.body);const u=document.createElement("div"),c=K(Ine,l,Wt(l.message)?{default:()=>l.message}:null);return c.appContext=t??Ds._context,c.props.onDestroy=()=>{er(null,u)},er(c,u),Md[n].push({vm:c}),s.appendChild(u.firstElementChild),{close:()=>{c.component.exposed.visible.value=!1}}};eT.forEach(e=>{Ds[e]=(t={})=>((typeof t=="string"||Wt(t))&&(t={message:t}),Ds({...t,type:e}))});function Ane(e,t,n){const o=Md[t],r=o.findIndex(({vm:c})=>{var f;return((f=c.component)==null?void 0:f.props.id)===e});if(r===-1)return;const{vm:a}=o[r];if(!a)return;n==null||n(a);const l=a.el.offsetHeight,s=t.split("-")[0];o.splice(r,1);const u=o.length;if(!(u<1))for(let c=r;c{t.component.exposed.visible.value=!1})}Ds.closeAll=Pne;Ds._context=null;const Rne=eS(Ds,"$notify");var Lne=[jte,Yte,Cr,bm,Rne,xE],xne=N8([...xte,...Lne]);function tT(e,t){return function(){return e.apply(t,arguments)}}const{toString:Dne}=Object.prototype,{getPrototypeOf:Wg}=Object,Af=(e=>t=>{const n=Dne.call(t);return e[n]||(e[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),Ar=e=>(e=e.toLowerCase(),t=>Af(t)===e),Pf=e=>t=>typeof t===e,{isArray:ri}=Array,gu=Pf("undefined");function Fne(e){return e!==null&&!gu(e)&&e.constructor!==null&&!gu(e.constructor)&&Lo(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const nT=Ar("ArrayBuffer");function Bne(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&nT(e.buffer),t}const Vne=Pf("string"),Lo=Pf("function"),oT=Pf("number"),Rf=e=>e!==null&&typeof e=="object",Hne=e=>e===!0||e===!1,Qc=e=>{if(Af(e)!=="object")return!1;const t=Wg(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)},zne=Ar("Date"),jne=Ar("File"),Wne=Ar("Blob"),Kne=Ar("FileList"),Une=e=>Rf(e)&&Lo(e.pipe),qne=e=>{let t;return e&&(typeof FormData=="function"&&e instanceof FormData||Lo(e.append)&&((t=Af(e))==="formdata"||t==="object"&&Lo(e.toString)&&e.toString()==="[object FormData]"))},Yne=Ar("URLSearchParams"),Gne=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function Hu(e,t,{allOwnKeys:n=!1}={}){if(e===null||typeof e>"u")return;let o,r;if(typeof e!="object"&&(e=[e]),ri(e))for(o=0,r=e.length;o0;)if(r=n[o],t===r.toLowerCase())return r;return null}const aT=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global,lT=e=>!gu(e)&&e!==aT;function wm(){const{caseless:e}=lT(this)&&this||{},t={},n=(o,r)=>{const a=e&&rT(t,r)||r;Qc(t[a])&&Qc(o)?t[a]=wm(t[a],o):Qc(o)?t[a]=wm({},o):ri(o)?t[a]=o.slice():t[a]=o};for(let o=0,r=arguments.length;o(Hu(t,(r,a)=>{n&&Lo(r)?e[a]=tT(r,n):e[a]=r},{allOwnKeys:o}),e),Jne=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),Zne=(e,t,n,o)=>{e.prototype=Object.create(t.prototype,o),e.prototype.constructor=e,Object.defineProperty(e,"super",{value:t.prototype}),n&&Object.assign(e.prototype,n)},Qne=(e,t,n,o)=>{let r,a,l;const s={};if(t=t||{},e==null)return t;do{for(r=Object.getOwnPropertyNames(e),a=r.length;a-- >0;)l=r[a],(!o||o(l,e,t))&&!s[l]&&(t[l]=e[l],s[l]=!0);e=n!==!1&&Wg(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},eoe=(e,t,n)=>{e=String(e),(n===void 0||n>e.length)&&(n=e.length),n-=t.length;const o=e.indexOf(t,n);return o!==-1&&o===n},toe=e=>{if(!e)return null;if(ri(e))return e;let t=e.length;if(!oT(t))return null;const n=new Array(t);for(;t-- >0;)n[t]=e[t];return n},noe=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&Wg(Uint8Array)),ooe=(e,t)=>{const o=(e&&e[Symbol.iterator]).call(e);let r;for(;(r=o.next())&&!r.done;){const a=r.value;t.call(e,a[0],a[1])}},roe=(e,t)=>{let n;const o=[];for(;(n=e.exec(t))!==null;)o.push(n);return o},aoe=Ar("HTMLFormElement"),loe=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(n,o,r){return o.toUpperCase()+r}),F1=(({hasOwnProperty:e})=>(t,n)=>e.call(t,n))(Object.prototype),soe=Ar("RegExp"),sT=(e,t)=>{const n=Object.getOwnPropertyDescriptors(e),o={};Hu(n,(r,a)=>{t(r,a,e)!==!1&&(o[a]=r)}),Object.defineProperties(e,o)},ioe=e=>{sT(e,(t,n)=>{if(Lo(e)&&["arguments","caller","callee"].indexOf(n)!==-1)return!1;const o=e[n];if(Lo(o)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")})}})},uoe=(e,t)=>{const n={},o=r=>{r.forEach(a=>{n[a]=!0})};return ri(e)?o(e):o(String(e).split(t)),n},coe=()=>{},doe=(e,t)=>(e=+e,Number.isFinite(e)?e:t),Lp="abcdefghijklmnopqrstuvwxyz",B1="0123456789",iT={DIGIT:B1,ALPHA:Lp,ALPHA_DIGIT:Lp+Lp.toUpperCase()+B1},foe=(e=16,t=iT.ALPHA_DIGIT)=>{let n="";const{length:o}=t;for(;e--;)n+=t[Math.random()*o|0];return n};function poe(e){return!!(e&&Lo(e.append)&&e[Symbol.toStringTag]==="FormData"&&e[Symbol.iterator])}const hoe=e=>{const t=new Array(10),n=(o,r)=>{if(Rf(o)){if(t.indexOf(o)>=0)return;if(!("toJSON"in o)){t[r]=o;const a=ri(o)?[]:{};return Hu(o,(l,s)=>{const u=n(l,r+1);!gu(u)&&(a[s]=u)}),t[r]=void 0,a}}return o};return n(e,0)},moe=Ar("AsyncFunction"),voe=e=>e&&(Rf(e)||Lo(e))&&Lo(e.then)&&Lo(e.catch),Be={isArray:ri,isArrayBuffer:nT,isBuffer:Fne,isFormData:qne,isArrayBufferView:Bne,isString:Vne,isNumber:oT,isBoolean:Hne,isObject:Rf,isPlainObject:Qc,isUndefined:gu,isDate:zne,isFile:jne,isBlob:Wne,isRegExp:soe,isFunction:Lo,isStream:Une,isURLSearchParams:Yne,isTypedArray:noe,isFileList:Kne,forEach:Hu,merge:wm,extend:Xne,trim:Gne,stripBOM:Jne,inherits:Zne,toFlatObject:Qne,kindOf:Af,kindOfTest:Ar,endsWith:eoe,toArray:toe,forEachEntry:ooe,matchAll:roe,isHTMLForm:aoe,hasOwnProperty:F1,hasOwnProp:F1,reduceDescriptors:sT,freezeMethods:ioe,toObjectSet:uoe,toCamelCase:loe,noop:coe,toFiniteNumber:doe,findKey:rT,global:aT,isContextDefined:lT,ALPHABET:iT,generateString:foe,isSpecCompliantForm:poe,toJSONObject:hoe,isAsyncFn:moe,isThenable:voe};function jt(e,t,n,o,r){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack,this.message=e,this.name="AxiosError",t&&(this.code=t),n&&(this.config=n),o&&(this.request=o),r&&(this.response=r)}Be.inherits(jt,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:Be.toJSONObject(this.config),code:this.code,status:this.response&&this.response.status?this.response.status:null}}});const uT=jt.prototype,cT={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED","ERR_NOT_SUPPORT","ERR_INVALID_URL"].forEach(e=>{cT[e]={value:e}});Object.defineProperties(jt,cT);Object.defineProperty(uT,"isAxiosError",{value:!0});jt.from=(e,t,n,o,r,a)=>{const l=Object.create(uT);return Be.toFlatObject(e,l,function(u){return u!==Error.prototype},s=>s!=="isAxiosError"),jt.call(l,e.message,t,n,o,r),l.cause=e,l.name=e.name,a&&Object.assign(l,a),l};const goe=null;function _m(e){return Be.isPlainObject(e)||Be.isArray(e)}function dT(e){return Be.endsWith(e,"[]")?e.slice(0,-2):e}function V1(e,t,n){return e?e.concat(t).map(function(r,a){return r=dT(r),!n&&a?"["+r+"]":r}).join(n?".":""):t}function boe(e){return Be.isArray(e)&&!e.some(_m)}const yoe=Be.toFlatObject(Be,{},null,function(t){return/^is[A-Z]/.test(t)});function Lf(e,t,n){if(!Be.isObject(e))throw new TypeError("target must be an object");t=t||new FormData,n=Be.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(h,C){return!Be.isUndefined(C[h])});const o=n.metaTokens,r=n.visitor||f,a=n.dots,l=n.indexes,u=(n.Blob||typeof Blob<"u"&&Blob)&&Be.isSpecCompliantForm(t);if(!Be.isFunction(r))throw new TypeError("visitor must be a function");function c(v){if(v===null)return"";if(Be.isDate(v))return v.toISOString();if(!u&&Be.isBlob(v))throw new jt("Blob is not supported. Use a Buffer instead.");return Be.isArrayBuffer(v)||Be.isTypedArray(v)?u&&typeof Blob=="function"?new Blob([v]):Buffer.from(v):v}function f(v,h,C){let g=v;if(v&&!C&&typeof v=="object"){if(Be.endsWith(h,"{}"))h=o?h:h.slice(0,-2),v=JSON.stringify(v);else if(Be.isArray(v)&&boe(v)||(Be.isFileList(v)||Be.endsWith(h,"[]"))&&(g=Be.toArray(v)))return h=dT(h),g.forEach(function(_,b){!(Be.isUndefined(_)||_===null)&&t.append(l===!0?V1([h],b,a):l===null?h:h+"[]",c(_))}),!1}return _m(v)?!0:(t.append(V1(C,h,a),c(v)),!1)}const d=[],p=Object.assign(yoe,{defaultVisitor:f,convertValue:c,isVisitable:_m});function m(v,h){if(!Be.isUndefined(v)){if(d.indexOf(v)!==-1)throw Error("Circular reference detected in "+h.join("."));d.push(v),Be.forEach(v,function(g,y){(!(Be.isUndefined(g)||g===null)&&r.call(t,g,Be.isString(y)?y.trim():y,h,p))===!0&&m(g,h?h.concat(y):[y])}),d.pop()}}if(!Be.isObject(e))throw new TypeError("data must be an object");return m(e),t}function H1(e){const t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(e).replace(/[!'()~]|%20|%00/g,function(o){return t[o]})}function Kg(e,t){this._pairs=[],e&&Lf(e,this,t)}const fT=Kg.prototype;fT.append=function(t,n){this._pairs.push([t,n])};fT.toString=function(t){const n=t?function(o){return t.call(this,o,H1)}:H1;return this._pairs.map(function(r){return n(r[0])+"="+n(r[1])},"").join("&")};function woe(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}function pT(e,t,n){if(!t)return e;const o=n&&n.encode||woe,r=n&&n.serialize;let a;if(r?a=r(t,n):a=Be.isURLSearchParams(t)?t.toString():new Kg(t,n).toString(o),a){const l=e.indexOf("#");l!==-1&&(e=e.slice(0,l)),e+=(e.indexOf("?")===-1?"?":"&")+a}return e}class z1{constructor(){this.handlers=[]}use(t,n,o){return this.handlers.push({fulfilled:t,rejected:n,synchronous:o?o.synchronous:!1,runWhen:o?o.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){Be.forEach(this.handlers,function(o){o!==null&&t(o)})}}const hT={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},_oe=typeof URLSearchParams<"u"?URLSearchParams:Kg,Coe=typeof FormData<"u"?FormData:null,Soe=typeof Blob<"u"?Blob:null,koe=(()=>{let e;return typeof navigator<"u"&&((e=navigator.product)==="ReactNative"||e==="NativeScript"||e==="NS")?!1:typeof window<"u"&&typeof document<"u"})(),Eoe=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function",yr={isBrowser:!0,classes:{URLSearchParams:_oe,FormData:Coe,Blob:Soe},isStandardBrowserEnv:koe,isStandardBrowserWebWorkerEnv:Eoe,protocols:["http","https","file","blob","url","data"]};function Toe(e,t){return Lf(e,new yr.classes.URLSearchParams,Object.assign({visitor:function(n,o,r,a){return yr.isNode&&Be.isBuffer(n)?(this.append(o,n.toString("base64")),!1):a.defaultVisitor.apply(this,arguments)}},t))}function $oe(e){return Be.matchAll(/\w+|\[(\w*)]/g,e).map(t=>t[0]==="[]"?"":t[1]||t[0])}function Ooe(e){const t={},n=Object.keys(e);let o;const r=n.length;let a;for(o=0;o=n.length;return l=!l&&Be.isArray(r)?r.length:l,u?(Be.hasOwnProp(r,l)?r[l]=[r[l],o]:r[l]=o,!s):((!r[l]||!Be.isObject(r[l]))&&(r[l]=[]),t(n,o,r[l],a)&&Be.isArray(r[l])&&(r[l]=Ooe(r[l])),!s)}if(Be.isFormData(e)&&Be.isFunction(e.entries)){const n={};return Be.forEachEntry(e,(o,r)=>{t($oe(o),r,n,0)}),n}return null}const Noe={"Content-Type":void 0};function Ioe(e,t,n){if(Be.isString(e))try{return(t||JSON.parse)(e),Be.trim(e)}catch(o){if(o.name!=="SyntaxError")throw o}return(n||JSON.stringify)(e)}const ai={transitional:hT,adapter:["xhr","http"],transformRequest:[function(t,n){const o=n.getContentType()||"",r=o.indexOf("application/json")>-1,a=Be.isObject(t);if(a&&Be.isHTMLForm(t)&&(t=new FormData(t)),Be.isFormData(t))return r&&r?JSON.stringify(mT(t)):t;if(Be.isArrayBuffer(t)||Be.isBuffer(t)||Be.isStream(t)||Be.isFile(t)||Be.isBlob(t))return t;if(Be.isArrayBufferView(t))return t.buffer;if(Be.isURLSearchParams(t))return n.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let s;if(a){if(o.indexOf("application/x-www-form-urlencoded")>-1)return Toe(t,this.formSerializer).toString();if((s=Be.isFileList(t))||o.indexOf("multipart/form-data")>-1){const u=this.env&&this.env.FormData;return Lf(s?{"files[]":t}:t,u&&new u,this.formSerializer)}}return a||r?(n.setContentType("application/json",!1),Ioe(t)):t}],transformResponse:[function(t){const n=this.transitional||ai.transitional,o=n&&n.forcedJSONParsing,r=this.responseType==="json";if(t&&Be.isString(t)&&(o&&!this.responseType||r)){const l=!(n&&n.silentJSONParsing)&&r;try{return JSON.parse(t)}catch(s){if(l)throw s.name==="SyntaxError"?jt.from(s,jt.ERR_BAD_RESPONSE,this,null,this.response):s}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:yr.classes.FormData,Blob:yr.classes.Blob},validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};Be.forEach(["delete","get","head"],function(t){ai.headers[t]={}});Be.forEach(["post","put","patch"],function(t){ai.headers[t]=Be.merge(Noe)});const Moe=Be.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),Aoe=e=>{const t={};let n,o,r;return e&&e.split(` +`).forEach(function(l){r=l.indexOf(":"),n=l.substring(0,r).trim().toLowerCase(),o=l.substring(r+1).trim(),!(!n||t[n]&&Moe[n])&&(n==="set-cookie"?t[n]?t[n].push(o):t[n]=[o]:t[n]=t[n]?t[n]+", "+o:o)}),t},j1=Symbol("internals");function yi(e){return e&&String(e).trim().toLowerCase()}function ed(e){return e===!1||e==null?e:Be.isArray(e)?e.map(ed):String(e)}function Poe(e){const t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let o;for(;o=n.exec(e);)t[o[1]]=o[2];return t}const Roe=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function xp(e,t,n,o,r){if(Be.isFunction(o))return o.call(this,t,n);if(r&&(t=n),!!Be.isString(t)){if(Be.isString(o))return t.indexOf(o)!==-1;if(Be.isRegExp(o))return o.test(t)}}function Loe(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,n,o)=>n.toUpperCase()+o)}function xoe(e,t){const n=Be.toCamelCase(" "+t);["get","set","has"].forEach(o=>{Object.defineProperty(e,o+n,{value:function(r,a,l){return this[o].call(this,t,r,a,l)},configurable:!0})})}class xo{constructor(t){t&&this.set(t)}set(t,n,o){const r=this;function a(s,u,c){const f=yi(u);if(!f)throw new Error("header name must be a non-empty string");const d=Be.findKey(r,f);(!d||r[d]===void 0||c===!0||c===void 0&&r[d]!==!1)&&(r[d||u]=ed(s))}const l=(s,u)=>Be.forEach(s,(c,f)=>a(c,f,u));return Be.isPlainObject(t)||t instanceof this.constructor?l(t,n):Be.isString(t)&&(t=t.trim())&&!Roe(t)?l(Aoe(t),n):t!=null&&a(n,t,o),this}get(t,n){if(t=yi(t),t){const o=Be.findKey(this,t);if(o){const r=this[o];if(!n)return r;if(n===!0)return Poe(r);if(Be.isFunction(n))return n.call(this,r,o);if(Be.isRegExp(n))return n.exec(r);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,n){if(t=yi(t),t){const o=Be.findKey(this,t);return!!(o&&this[o]!==void 0&&(!n||xp(this,this[o],o,n)))}return!1}delete(t,n){const o=this;let r=!1;function a(l){if(l=yi(l),l){const s=Be.findKey(o,l);s&&(!n||xp(o,o[s],s,n))&&(delete o[s],r=!0)}}return Be.isArray(t)?t.forEach(a):a(t),r}clear(t){const n=Object.keys(this);let o=n.length,r=!1;for(;o--;){const a=n[o];(!t||xp(this,this[a],a,t,!0))&&(delete this[a],r=!0)}return r}normalize(t){const n=this,o={};return Be.forEach(this,(r,a)=>{const l=Be.findKey(o,a);if(l){n[l]=ed(r),delete n[a];return}const s=t?Loe(a):String(a).trim();s!==a&&delete n[a],n[s]=ed(r),o[s]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const n=Object.create(null);return Be.forEach(this,(o,r)=>{o!=null&&o!==!1&&(n[r]=t&&Be.isArray(o)?o.join(", "):o)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,n])=>t+": "+n).join(` +`)}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const o=new this(t);return n.forEach(r=>o.set(r)),o}static accessor(t){const o=(this[j1]=this[j1]={accessors:{}}).accessors,r=this.prototype;function a(l){const s=yi(l);o[s]||(xoe(r,l),o[s]=!0)}return Be.isArray(t)?t.forEach(a):a(t),this}}xo.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);Be.freezeMethods(xo.prototype);Be.freezeMethods(xo);function Dp(e,t){const n=this||ai,o=t||n,r=xo.from(o.headers);let a=o.data;return Be.forEach(e,function(s){a=s.call(n,a,r.normalize(),t?t.status:void 0)}),r.normalize(),a}function vT(e){return!!(e&&e.__CANCEL__)}function zu(e,t,n){jt.call(this,e??"canceled",jt.ERR_CANCELED,t,n),this.name="CanceledError"}Be.inherits(zu,jt,{__CANCEL__:!0});function Doe(e,t,n){const o=n.config.validateStatus;!n.status||!o||o(n.status)?e(n):t(new jt("Request failed with status code "+n.status,[jt.ERR_BAD_REQUEST,jt.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n))}const Foe=yr.isStandardBrowserEnv?function(){return{write:function(n,o,r,a,l,s){const u=[];u.push(n+"="+encodeURIComponent(o)),Be.isNumber(r)&&u.push("expires="+new Date(r).toGMTString()),Be.isString(a)&&u.push("path="+a),Be.isString(l)&&u.push("domain="+l),s===!0&&u.push("secure"),document.cookie=u.join("; ")},read:function(n){const o=document.cookie.match(new RegExp("(^|;\\s*)("+n+")=([^;]*)"));return o?decodeURIComponent(o[3]):null},remove:function(n){this.write(n,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}();function Boe(e){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}function Voe(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}function gT(e,t){return e&&!Boe(t)?Voe(e,t):t}const Hoe=yr.isStandardBrowserEnv?function(){const t=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");let o;function r(a){let l=a;return t&&(n.setAttribute("href",l),l=n.href),n.setAttribute("href",l),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:n.pathname.charAt(0)==="/"?n.pathname:"/"+n.pathname}}return o=r(window.location.href),function(l){const s=Be.isString(l)?r(l):l;return s.protocol===o.protocol&&s.host===o.host}}():function(){return function(){return!0}}();function zoe(e){const t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}function joe(e,t){e=e||10;const n=new Array(e),o=new Array(e);let r=0,a=0,l;return t=t!==void 0?t:1e3,function(u){const c=Date.now(),f=o[a];l||(l=c),n[r]=u,o[r]=c;let d=a,p=0;for(;d!==r;)p+=n[d++],d=d%e;if(r=(r+1)%e,r===a&&(a=(a+1)%e),c-l{const a=r.loaded,l=r.lengthComputable?r.total:void 0,s=a-n,u=o(s),c=a<=l;n=a;const f={loaded:a,total:l,progress:l?a/l:void 0,bytes:s,rate:u||void 0,estimated:u&&l&&c?(l-a)/u:void 0,event:r};f[t?"download":"upload"]=!0,e(f)}}const Woe=typeof XMLHttpRequest<"u",Koe=Woe&&function(e){return new Promise(function(n,o){let r=e.data;const a=xo.from(e.headers).normalize(),l=e.responseType;let s;function u(){e.cancelToken&&e.cancelToken.unsubscribe(s),e.signal&&e.signal.removeEventListener("abort",s)}Be.isFormData(r)&&(yr.isStandardBrowserEnv||yr.isStandardBrowserWebWorkerEnv?a.setContentType(!1):a.setContentType("multipart/form-data;",!1));let c=new XMLHttpRequest;if(e.auth){const m=e.auth.username||"",v=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";a.set("Authorization","Basic "+btoa(m+":"+v))}const f=gT(e.baseURL,e.url);c.open(e.method.toUpperCase(),pT(f,e.params,e.paramsSerializer),!0),c.timeout=e.timeout;function d(){if(!c)return;const m=xo.from("getAllResponseHeaders"in c&&c.getAllResponseHeaders()),h={data:!l||l==="text"||l==="json"?c.responseText:c.response,status:c.status,statusText:c.statusText,headers:m,config:e,request:c};Doe(function(g){n(g),u()},function(g){o(g),u()},h),c=null}if("onloadend"in c?c.onloadend=d:c.onreadystatechange=function(){!c||c.readyState!==4||c.status===0&&!(c.responseURL&&c.responseURL.indexOf("file:")===0)||setTimeout(d)},c.onabort=function(){c&&(o(new jt("Request aborted",jt.ECONNABORTED,e,c)),c=null)},c.onerror=function(){o(new jt("Network Error",jt.ERR_NETWORK,e,c)),c=null},c.ontimeout=function(){let v=e.timeout?"timeout of "+e.timeout+"ms exceeded":"timeout exceeded";const h=e.transitional||hT;e.timeoutErrorMessage&&(v=e.timeoutErrorMessage),o(new jt(v,h.clarifyTimeoutError?jt.ETIMEDOUT:jt.ECONNABORTED,e,c)),c=null},yr.isStandardBrowserEnv){const m=(e.withCredentials||Hoe(f))&&e.xsrfCookieName&&Foe.read(e.xsrfCookieName);m&&a.set(e.xsrfHeaderName,m)}r===void 0&&a.setContentType(null),"setRequestHeader"in c&&Be.forEach(a.toJSON(),function(v,h){c.setRequestHeader(h,v)}),Be.isUndefined(e.withCredentials)||(c.withCredentials=!!e.withCredentials),l&&l!=="json"&&(c.responseType=e.responseType),typeof e.onDownloadProgress=="function"&&c.addEventListener("progress",W1(e.onDownloadProgress,!0)),typeof e.onUploadProgress=="function"&&c.upload&&c.upload.addEventListener("progress",W1(e.onUploadProgress)),(e.cancelToken||e.signal)&&(s=m=>{c&&(o(!m||m.type?new zu(null,e,c):m),c.abort(),c=null)},e.cancelToken&&e.cancelToken.subscribe(s),e.signal&&(e.signal.aborted?s():e.signal.addEventListener("abort",s)));const p=zoe(f);if(p&&yr.protocols.indexOf(p)===-1){o(new jt("Unsupported protocol "+p+":",jt.ERR_BAD_REQUEST,e));return}c.send(r||null)})},td={http:goe,xhr:Koe};Be.forEach(td,(e,t)=>{if(e){try{Object.defineProperty(e,"name",{value:t})}catch{}Object.defineProperty(e,"adapterName",{value:t})}});const Uoe={getAdapter:e=>{e=Be.isArray(e)?e:[e];const{length:t}=e;let n,o;for(let r=0;re instanceof xo?e.toJSON():e;function Fs(e,t){t=t||{};const n={};function o(c,f,d){return Be.isPlainObject(c)&&Be.isPlainObject(f)?Be.merge.call({caseless:d},c,f):Be.isPlainObject(f)?Be.merge({},f):Be.isArray(f)?f.slice():f}function r(c,f,d){if(Be.isUndefined(f)){if(!Be.isUndefined(c))return o(void 0,c,d)}else return o(c,f,d)}function a(c,f){if(!Be.isUndefined(f))return o(void 0,f)}function l(c,f){if(Be.isUndefined(f)){if(!Be.isUndefined(c))return o(void 0,c)}else return o(void 0,f)}function s(c,f,d){if(d in t)return o(c,f);if(d in e)return o(void 0,c)}const u={url:a,method:a,data:a,baseURL:l,transformRequest:l,transformResponse:l,paramsSerializer:l,timeout:l,timeoutMessage:l,withCredentials:l,adapter:l,responseType:l,xsrfCookieName:l,xsrfHeaderName:l,onUploadProgress:l,onDownloadProgress:l,decompress:l,maxContentLength:l,maxBodyLength:l,beforeRedirect:l,transport:l,httpAgent:l,httpsAgent:l,cancelToken:l,socketPath:l,responseEncoding:l,validateStatus:s,headers:(c,f)=>r(U1(c),U1(f),!0)};return Be.forEach(Object.keys(Object.assign({},e,t)),function(f){const d=u[f]||r,p=d(e[f],t[f],f);Be.isUndefined(p)&&d!==s||(n[f]=p)}),n}const bT="1.4.0",Ug={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{Ug[e]=function(o){return typeof o===e||"a"+(t<1?"n ":" ")+e}});const q1={};Ug.transitional=function(t,n,o){function r(a,l){return"[Axios v"+bT+"] Transitional option '"+a+"'"+l+(o?". "+o:"")}return(a,l,s)=>{if(t===!1)throw new jt(r(l," has been removed"+(n?" in "+n:"")),jt.ERR_DEPRECATED);return n&&!q1[l]&&(q1[l]=!0,console.warn(r(l," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(a,l,s):!0}};function qoe(e,t,n){if(typeof e!="object")throw new jt("options must be an object",jt.ERR_BAD_OPTION_VALUE);const o=Object.keys(e);let r=o.length;for(;r-- >0;){const a=o[r],l=t[a];if(l){const s=e[a],u=s===void 0||l(s,a,e);if(u!==!0)throw new jt("option "+a+" must be "+u,jt.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new jt("Unknown option "+a,jt.ERR_BAD_OPTION)}}const Cm={assertOptions:qoe,validators:Ug},ua=Cm.validators;let fl=class{constructor(t){this.defaults=t,this.interceptors={request:new z1,response:new z1}}request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=Fs(this.defaults,n);const{transitional:o,paramsSerializer:r,headers:a}=n;o!==void 0&&Cm.assertOptions(o,{silentJSONParsing:ua.transitional(ua.boolean),forcedJSONParsing:ua.transitional(ua.boolean),clarifyTimeoutError:ua.transitional(ua.boolean)},!1),r!=null&&(Be.isFunction(r)?n.paramsSerializer={serialize:r}:Cm.assertOptions(r,{encode:ua.function,serialize:ua.function},!0)),n.method=(n.method||this.defaults.method||"get").toLowerCase();let l;l=a&&Be.merge(a.common,a[n.method]),l&&Be.forEach(["delete","get","head","post","put","patch","common"],v=>{delete a[v]}),n.headers=xo.concat(l,a);const s=[];let u=!0;this.interceptors.request.forEach(function(h){typeof h.runWhen=="function"&&h.runWhen(n)===!1||(u=u&&h.synchronous,s.unshift(h.fulfilled,h.rejected))});const c=[];this.interceptors.response.forEach(function(h){c.push(h.fulfilled,h.rejected)});let f,d=0,p;if(!u){const v=[K1.bind(this),void 0];for(v.unshift.apply(v,s),v.push.apply(v,c),p=v.length,f=Promise.resolve(n);d{if(!o._listeners)return;let a=o._listeners.length;for(;a-- >0;)o._listeners[a](r);o._listeners=null}),this.promise.then=r=>{let a;const l=new Promise(s=>{o.subscribe(s),a=s}).then(r);return l.cancel=function(){o.unsubscribe(a)},l},t(function(a,l,s){o.reason||(o.reason=new zu(a,l,s),n(o.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}static source(){let t;return{token:new qg(function(r){t=r}),cancel:t}}}function Yoe(e){return function(n){return e.apply(null,n)}}function Goe(e){return Be.isObject(e)&&e.isAxiosError===!0}const Sm={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(Sm).forEach(([e,t])=>{Sm[t]=e});function yT(e){const t=new fl(e),n=tT(fl.prototype.request,t);return Be.extend(n,fl.prototype,t,{allOwnKeys:!0}),Be.extend(n,t,null,{allOwnKeys:!0}),n.create=function(r){return yT(Fs(e,r))},n}const Nn=yT(ai);Nn.Axios=fl;Nn.CanceledError=zu;Nn.CancelToken=qg;Nn.isCancel=vT;Nn.VERSION=bT;Nn.toFormData=Lf;Nn.AxiosError=jt;Nn.Cancel=Nn.CanceledError;Nn.all=function(t){return Promise.all(t)};Nn.spread=Yoe;Nn.isAxiosError=Goe;Nn.mergeConfig=Fs;Nn.AxiosHeaders=xo;Nn.formToJSON=e=>mT(Be.isHTMLForm(e)?new FormData(e):e);Nn.HttpStatusCode=Sm;Nn.default=Nn;const Xoe={Terminal:"终端","Command run log":"命令运行日志","No mission yet":"还没有任务...","Test command":"测试命令","Install dependent packages":"安装依赖包",Republish:"重新发布","Clean up task list":"清理任务列表",unknown:"未知","Waiting for execution":"等待执行",Connecting:"连接中...",Executing:"执行中...","Successful execution":"执行成功","Execution failed":"执行失败","Unknown execution result":"执行结果未知","Are you sure you want to republish?":"确认要重新发布吗?","Failure to execute this command will block the execution of the queue":"本命令执行失败会阻断队列执行","Do not refresh the browser":"请勿刷新浏览器"},Joe=Object.freeze(Object.defineProperty({__proto__:null,default:Xoe},Symbol.toStringTag,{value:"Module"})),Zoe={Terminal:"Terminal","Command run log":"Command run log","No mission yet":"No mission yet","Test command":"Test command","Install dependent packages":"Install the dependent packages",Republish:"Republish","Clean up task list":"Clean up the task list",unknown:"Unknown","Waiting for execution":"Waiting for execution",Connecting:"Connecting",Executing:"Executing","Successful execution":"Execution successful","Execution failed":"Execution failed","Unknown execution result":"Unknown execution result","Are you sure you want to republish?":"Are you sure you want to republish?","Failure to execute this command will block the execution of the queue":"Failure to execute this command will block the execution of the queue.","Do not refresh the browser":"Please do not refresh your browser."},Qoe=Object.freeze(Object.defineProperty({__proto__:null,default:Zoe},Symbol.toStringTag,{value:"Module"}));var Pr={},wT={exports:{}},Ot={},_T={exports:{}},jo={},CT={exports:{}},Xt={};/*! + * shared v9.2.2 + * (c) 2022 kazuya kawaguchi + * Released under the MIT License. + */Object.defineProperty(Xt,"__esModule",{value:!0});const ere=typeof window<"u";let tre,nre;const ore=/\{([0-9a-zA-Z]+)\}/g;function rre(e,...t){return t.length===1&&Yg(t[0])&&(t=t[0]),(!t||!t.hasOwnProperty)&&(t={}),e.replace(ore,(n,o)=>t.hasOwnProperty(o)?t[o]:"")}const are=typeof Symbol=="function"&&typeof Symbol.toStringTag=="symbol",lre=e=>are?Symbol(e):e,sre=(e,t,n)=>ST({l:e,k:t,s:n}),ST=e=>JSON.stringify(e).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/\u0027/g,"\\u0027"),ire=e=>typeof e=="number"&&isFinite(e),ure=e=>xf(e)==="[object Date]",cre=e=>xf(e)==="[object RegExp]",dre=e=>Xg(e)&&Object.keys(e).length===0;function fre(e,t){typeof console<"u"&&(console.warn("[intlify] "+e),t&&console.warn(t.stack))}const pre=Object.assign;let Y1;const hre=()=>Y1||(Y1=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof rr<"u"?rr:{});function mre(e){return e.replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}const vre=Object.prototype.hasOwnProperty;function gre(e,t){return vre.call(e,t)}const kT=Array.isArray,km=e=>typeof e=="function",bre=e=>typeof e=="string",yre=e=>typeof e=="boolean",wre=e=>typeof e=="symbol",Yg=e=>e!==null&&typeof e=="object",_re=e=>Yg(e)&&km(e.then)&&km(e.catch),Gg=Object.prototype.toString,xf=e=>Gg.call(e),Xg=e=>xf(e)==="[object Object]",Cre=e=>e==null?"":kT(e)||Xg(e)&&e.toString===Gg?JSON.stringify(e,null,2):String(e),G1=2;function Sre(e,t=0,n=e.length){const o=e.split(/\r?\n/);let r=0;const a=[];for(let l=0;l=t){for(let s=l-G1;s<=l+G1||n>r;s++){if(s<0||s>=o.length)continue;const u=s+1;a.push(`${u}${" ".repeat(3-String(u).length)}| ${o[s]}`);const c=o[s].length;if(s===l){const f=t-(r-c)+1,d=Math.max(1,n>r?c-f:n-t);a.push(" | "+" ".repeat(f)+"^".repeat(d))}else if(s>l){if(n>r){const f=Math.max(Math.min(n-r,c),1);a.push(" | "+"^".repeat(f))}r+=c+1}}break}return a.join(` +`)}function kre(){const e=new Map;return{events:e,on(n,o){const r=e.get(n);r&&r.push(o)||e.set(n,[o])},off(n,o){const r=e.get(n);r&&r.splice(r.indexOf(o)>>>0,1)},emit(n,o){(e.get(n)||[]).slice().map(r=>r(o)),(e.get("*")||[]).slice().map(r=>r(n,o))}}}Xt.assign=pre;Xt.createEmitter=kre;Xt.escapeHtml=mre;Xt.format=rre;Xt.friendlyJSONstringify=ST;Xt.generateCodeFrame=Sre;Xt.generateFormatCacheKey=sre;Xt.getGlobalThis=hre;Xt.hasOwn=gre;Xt.inBrowser=ere;Xt.isArray=kT;Xt.isBoolean=yre;Xt.isDate=ure;Xt.isEmptyObject=dre;Xt.isFunction=km;Xt.isNumber=ire;Xt.isObject=Yg;Xt.isPlainObject=Xg;Xt.isPromise=_re;Xt.isRegExp=cre;Xt.isString=bre;Xt.isSymbol=wre;Xt.makeSymbol=lre;Xt.mark=tre;Xt.measure=nre;Xt.objectToString=Gg;Xt.toDisplayString=Cre;Xt.toTypeString=xf;Xt.warn=fre;CT.exports=Xt;var Jg=CT.exports,Df={},Zg={},Ff={},Qg={},X1="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");Qg.encode=function(e){if(0<=e&&e>1;return t?-n:n}Ff.encode=function(t){var n="",o,r=Ere(t);do o=r&$T,r>>>=eb,r>0&&(o|=OT),n+=ET.encode(o);while(r>0);return n};Ff.decode=function(t,n,o){var r=t.length,a=0,l=0,s,u;do{if(n>=r)throw new Error("Expected more digits in base 64 VLQ value.");if(u=ET.decode(t.charCodeAt(n++)),u===-1)throw new Error("Invalid base64 digit: "+t.charAt(n-1));s=!!(u&OT),u&=$T,a=a+(u<=0;M--)O=$[M],O==="."?$.splice(M,1):O===".."?A++:A>0&&(O===""?($.splice(M+1,A),A=0):($.splice(M,2),A--));return w=$.join("/"),w===""&&(w=E?"/":"."),S?(S.path=w,a(S)):w}e.normalize=l;function s(b,w){b===""&&(b="."),w===""&&(w=".");var S=r(w),E=r(b);if(E&&(b=E.path||"/"),S&&!S.scheme)return E&&(S.scheme=E.scheme),a(S);if(S||w.match(o))return w;if(E&&!E.host&&!E.path)return E.host=w,a(E);var $=w.charAt(0)==="/"?w:l(b.replace(/\/+$/,"")+"/"+w);return E?(E.path=$,a(E)):$}e.join=s,e.isAbsolute=function(b){return b.charAt(0)==="/"||n.test(b)};function u(b,w){b===""&&(b="."),b=b.replace(/\/$/,"");for(var S=0;w.indexOf(b+"/")!==0;){var E=b.lastIndexOf("/");if(E<0||(b=b.slice(0,E),b.match(/^([^\/]+:\/)?\/*$/)))return w;++S}return Array(S+1).join("../")+w.substr(b.length+1)}e.relative=u;var c=function(){var b=Object.create(null);return!("__proto__"in b)}();function f(b){return b}function d(b){return m(b)?"$"+b:b}e.toSetString=c?f:d;function p(b){return m(b)?b.slice(1):b}e.fromSetString=c?f:p;function m(b){if(!b)return!1;var w=b.length;if(w<9||b.charCodeAt(w-1)!==95||b.charCodeAt(w-2)!==95||b.charCodeAt(w-3)!==111||b.charCodeAt(w-4)!==116||b.charCodeAt(w-5)!==111||b.charCodeAt(w-6)!==114||b.charCodeAt(w-7)!==112||b.charCodeAt(w-8)!==95||b.charCodeAt(w-9)!==95)return!1;for(var S=w-10;S>=0;S--)if(b.charCodeAt(S)!==36)return!1;return!0}function v(b,w,S){var E=C(b.source,w.source);return E!==0||(E=b.originalLine-w.originalLine,E!==0)||(E=b.originalColumn-w.originalColumn,E!==0||S)||(E=b.generatedColumn-w.generatedColumn,E!==0)||(E=b.generatedLine-w.generatedLine,E!==0)?E:C(b.name,w.name)}e.compareByOriginalPositions=v;function h(b,w,S){var E=b.generatedLine-w.generatedLine;return E!==0||(E=b.generatedColumn-w.generatedColumn,E!==0||S)||(E=C(b.source,w.source),E!==0)||(E=b.originalLine-w.originalLine,E!==0)||(E=b.originalColumn-w.originalColumn,E!==0)?E:C(b.name,w.name)}e.compareByGeneratedPositionsDeflated=h;function C(b,w){return b===w?0:b===null?1:w===null?-1:b>w?1:-1}function g(b,w){var S=b.generatedLine-w.generatedLine;return S!==0||(S=b.generatedColumn-w.generatedColumn,S!==0)||(S=C(b.source,w.source),S!==0)||(S=b.originalLine-w.originalLine,S!==0)||(S=b.originalColumn-w.originalColumn,S!==0)?S:C(b.name,w.name)}e.compareByGeneratedPositionsInflated=g;function y(b){return JSON.parse(b.replace(/^\)]}'[^\n]*\n/,""))}e.parseSourceMapInput=y;function _(b,w,S){if(w=w||"",b&&(b[b.length-1]!=="/"&&w[0]!=="/"&&(b+="/"),w=b+w),S){var E=r(S);if(!E)throw new Error("sourceMapURL could not be parsed");if(E.path){var $=E.path.lastIndexOf("/");$>=0&&(E.path=E.path.substring(0,$+1))}w=s(a(E),w)}return l(w)}e.computeSourceURL=_})(li);var tb={},nb=li,ob=Object.prototype.hasOwnProperty,pl=typeof Map<"u";function Gr(){this._array=[],this._set=pl?new Map:Object.create(null)}Gr.fromArray=function(t,n){for(var o=new Gr,r=0,a=t.length;r=0)return n}else{var o=nb.toSetString(t);if(ob.call(this._set,o))return this._set[o]}throw new Error('"'+t+'" is not in the set.')};Gr.prototype.at=function(t){if(t>=0&&tn||o==n&&a>=r||IT.compareByGeneratedPositionsInflated(e,t)<=0}function Bf(){this._array=[],this._sorted=!0,this._last={generatedLine:-1,generatedColumn:0}}Bf.prototype.unsortedForEach=function(t,n){this._array.forEach(t,n)};Bf.prototype.add=function(t){$re(this._last,t)?(this._last=t,this._array.push(t)):(this._sorted=!1,this._array.push(t))};Bf.prototype.toArray=function(){return this._sorted||(this._array.sort(IT.compareByGeneratedPositionsInflated),this._sorted=!0),this._array};NT.MappingList=Bf;var wi=Ff,yn=li,Ad=tb.ArraySet,Ore=NT.MappingList;function zo(e){e||(e={}),this._file=yn.getArg(e,"file",null),this._sourceRoot=yn.getArg(e,"sourceRoot",null),this._skipValidation=yn.getArg(e,"skipValidation",!1),this._sources=new Ad,this._names=new Ad,this._mappings=new Ore,this._sourcesContents=null}zo.prototype._version=3;zo.fromSourceMap=function(t){var n=t.sourceRoot,o=new zo({file:t.file,sourceRoot:n});return t.eachMapping(function(r){var a={generated:{line:r.generatedLine,column:r.generatedColumn}};r.source!=null&&(a.source=r.source,n!=null&&(a.source=yn.relative(n,a.source)),a.original={line:r.originalLine,column:r.originalColumn},r.name!=null&&(a.name=r.name)),o.addMapping(a)}),t.sources.forEach(function(r){var a=r;n!==null&&(a=yn.relative(n,r)),o._sources.has(a)||o._sources.add(a);var l=t.sourceContentFor(r);l!=null&&o.setSourceContent(r,l)}),o};zo.prototype.addMapping=function(t){var n=yn.getArg(t,"generated"),o=yn.getArg(t,"original",null),r=yn.getArg(t,"source",null),a=yn.getArg(t,"name",null);this._skipValidation||this._validateMapping(n,o,r,a),r!=null&&(r=String(r),this._sources.has(r)||this._sources.add(r)),a!=null&&(a=String(a),this._names.has(a)||this._names.add(a)),this._mappings.add({generatedLine:n.line,generatedColumn:n.column,originalLine:o!=null&&o.line,originalColumn:o!=null&&o.column,source:r,name:a})};zo.prototype.setSourceContent=function(t,n){var o=t;this._sourceRoot!=null&&(o=yn.relative(this._sourceRoot,o)),n!=null?(this._sourcesContents||(this._sourcesContents=Object.create(null)),this._sourcesContents[yn.toSetString(o)]=n):this._sourcesContents&&(delete this._sourcesContents[yn.toSetString(o)],Object.keys(this._sourcesContents).length===0&&(this._sourcesContents=null))};zo.prototype.applySourceMap=function(t,n,o){var r=n;if(n==null){if(t.file==null)throw new Error(`SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, or the source map's "file" property. Both were omitted.`);r=t.file}var a=this._sourceRoot;a!=null&&(r=yn.relative(a,r));var l=new Ad,s=new Ad;this._mappings.unsortedForEach(function(u){if(u.source===r&&u.originalLine!=null){var c=t.originalPositionFor({line:u.originalLine,column:u.originalColumn});c.source!=null&&(u.source=c.source,o!=null&&(u.source=yn.join(o,u.source)),a!=null&&(u.source=yn.relative(a,u.source)),u.originalLine=c.line,u.originalColumn=c.column,c.name!=null&&(u.name=c.name))}var f=u.source;f!=null&&!l.has(f)&&l.add(f);var d=u.name;d!=null&&!s.has(d)&&s.add(d)},this),this._sources=l,this._names=s,t.sources.forEach(function(u){var c=t.sourceContentFor(u);c!=null&&(o!=null&&(u=yn.join(o,u)),a!=null&&(u=yn.relative(a,u)),this.setSourceContent(u,c))},this)};zo.prototype._validateMapping=function(t,n,o,r){if(n&&typeof n.line!="number"&&typeof n.column!="number")throw new Error("original.line and original.column are not numbers -- you probably meant to omit the original mapping entirely and only map the generated position. If so, pass null for the original mapping instead of an object with empty or null values.");if(!(t&&"line"in t&&"column"in t&&t.line>0&&t.column>=0&&!n&&!o&&!r)){if(t&&"line"in t&&"column"in t&&n&&"line"in n&&"column"in n&&t.line>0&&t.column>=0&&n.line>0&&n.column>=0&&o)return;throw new Error("Invalid mapping: "+JSON.stringify({generated:t,source:o,original:n,name:r}))}};zo.prototype._serializeMappings=function(){for(var t=0,n=1,o=0,r=0,a=0,l=0,s="",u,c,f,d,p=this._mappings.toArray(),m=0,v=p.length;m0){if(!yn.compareByGeneratedPositionsInflated(c,p[m-1]))continue;u+=","}u+=wi.encode(c.generatedColumn-t),t=c.generatedColumn,c.source!=null&&(d=this._sources.indexOf(c.source),u+=wi.encode(d-l),l=d,u+=wi.encode(c.originalLine-1-r),r=c.originalLine-1,u+=wi.encode(c.originalColumn-o),o=c.originalColumn,c.name!=null&&(f=this._names.indexOf(c.name),u+=wi.encode(f-a),a=f)),s+=u}return s};zo.prototype._generateSourcesContent=function(t,n){return t.map(function(o){if(!this._sourcesContents)return null;n!=null&&(o=yn.relative(n,o));var r=yn.toSetString(o);return Object.prototype.hasOwnProperty.call(this._sourcesContents,r)?this._sourcesContents[r]:null},this)};zo.prototype.toJSON=function(){var t={version:this._version,sources:this._sources.toArray(),names:this._names.toArray(),mappings:this._serializeMappings()};return this._file!=null&&(t.file=this._file),this._sourceRoot!=null&&(t.sourceRoot=this._sourceRoot),this._sourcesContents&&(t.sourcesContent=this._generateSourcesContent(t.sources,t.sourceRoot)),t};zo.prototype.toString=function(){return JSON.stringify(this.toJSON())};Zg.SourceMapGenerator=zo;var Vf={},MT={};(function(e){e.GREATEST_LOWER_BOUND=1,e.LEAST_UPPER_BOUND=2;function t(n,o,r,a,l,s){var u=Math.floor((o-n)/2)+n,c=l(r,a[u],!0);return c===0?u:c>0?o-u>1?t(u,o,r,a,l,s):s==e.LEAST_UPPER_BOUND?o1?t(n,u,r,a,l,s):s==e.LEAST_UPPER_BOUND?u:n<0?-1:n}e.search=function(o,r,a,l){if(r.length===0)return-1;var s=t(-1,r.length,o,r,a,l||e.GREATEST_LOWER_BOUND);if(s<0)return-1;for(;s-1>=0&&a(r[s],r[s-1],!0)===0;)--s;return s}})(MT);var AT={};function Bp(e,t,n){var o=e[t];e[t]=e[n],e[n]=o}function Nre(e,t){return Math.round(e+Math.random()*(t-e))}function Em(e,t,n,o){if(n=0){var l=this._originalMappings[a];if(t.column===void 0)for(var s=l.originalLine;l&&l.originalLine===s;)r.push({line:ht.getArg(l,"generatedLine",null),column:ht.getArg(l,"generatedColumn",null),lastColumn:ht.getArg(l,"lastGeneratedColumn",null)}),l=this._originalMappings[++a];else for(var u=l.originalColumn;l&&l.originalLine===n&&l.originalColumn==u;)r.push({line:ht.getArg(l,"generatedLine",null),column:ht.getArg(l,"generatedColumn",null),lastColumn:ht.getArg(l,"lastGeneratedColumn",null)}),l=this._originalMappings[++a]}return r};Vf.SourceMapConsumer=cn;function Dn(e,t){var n=e;typeof e=="string"&&(n=ht.parseSourceMapInput(e));var o=ht.getArg(n,"version"),r=ht.getArg(n,"sources"),a=ht.getArg(n,"names",[]),l=ht.getArg(n,"sourceRoot",null),s=ht.getArg(n,"sourcesContent",null),u=ht.getArg(n,"mappings"),c=ht.getArg(n,"file",null);if(o!=this._version)throw new Error("Unsupported version: "+o);l&&(l=ht.normalize(l)),r=r.map(String).map(ht.normalize).map(function(f){return l&&ht.isAbsolute(l)&&ht.isAbsolute(f)?ht.relative(l,f):f}),this._names=Bs.fromArray(a.map(String),!0),this._sources=Bs.fromArray(r,!0),this._absoluteSources=this._sources.toArray().map(function(f){return ht.computeSourceURL(l,f,t)}),this.sourceRoot=l,this.sourcesContent=s,this._mappings=u,this._sourceMapURL=t,this.file=c}Dn.prototype=Object.create(cn.prototype);Dn.prototype.consumer=cn;Dn.prototype._findSourceIndex=function(e){var t=e;if(this.sourceRoot!=null&&(t=ht.relative(this.sourceRoot,t)),this._sources.has(t))return this._sources.indexOf(t);var n;for(n=0;n1&&(h.source=s+g[1],s+=g[1],h.originalLine=a+g[2],a=h.originalLine,h.originalLine+=1,h.originalColumn=l+g[3],l=h.originalColumn,g.length>4&&(h.name=u+g[4],u+=g[4])),v.push(h),typeof h.originalLine=="number"&&m.push(h)}bu(v,ht.compareByGeneratedPositionsDeflated),this.__generatedMappings=v,bu(m,ht.compareByOriginalPositions),this.__originalMappings=m};Dn.prototype._findMapping=function(t,n,o,r,a,l){if(t[o]<=0)throw new TypeError("Line must be greater than or equal to 1, got "+t[o]);if(t[r]<0)throw new TypeError("Column must be greater than or equal to 0, got "+t[r]);return rb.search(t,n,a,l)};Dn.prototype.computeColumnSpans=function(){for(var t=0;t=0){var r=this._generatedMappings[o];if(r.generatedLine===n.generatedLine){var a=ht.getArg(r,"source",null);a!==null&&(a=this._sources.at(a),a=ht.computeSourceURL(this.sourceRoot,a,this._sourceMapURL));var l=ht.getArg(r,"name",null);return l!==null&&(l=this._names.at(l)),{source:a,line:ht.getArg(r,"originalLine",null),column:ht.getArg(r,"originalColumn",null),name:l}}}return{source:null,line:null,column:null,name:null}};Dn.prototype.hasContentsOfAllSources=function(){return this.sourcesContent?this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some(function(t){return t==null}):!1};Dn.prototype.sourceContentFor=function(t,n){if(!this.sourcesContent)return null;var o=this._findSourceIndex(t);if(o>=0)return this.sourcesContent[o];var r=t;this.sourceRoot!=null&&(r=ht.relative(this.sourceRoot,r));var a;if(this.sourceRoot!=null&&(a=ht.urlParse(this.sourceRoot))){var l=r.replace(/^file:\/\//,"");if(a.scheme=="file"&&this._sources.has(l))return this.sourcesContent[this._sources.indexOf(l)];if((!a.path||a.path=="/")&&this._sources.has("/"+r))return this.sourcesContent[this._sources.indexOf("/"+r)]}if(n)return null;throw new Error('"'+r+'" is not in the SourceMap.')};Dn.prototype.generatedPositionFor=function(t){var n=ht.getArg(t,"source");if(n=this._findSourceIndex(n),n<0)return{line:null,column:null,lastColumn:null};var o={source:n,originalLine:ht.getArg(t,"line"),originalColumn:ht.getArg(t,"column")},r=this._findMapping(o,this._originalMappings,"originalLine","originalColumn",ht.compareByOriginalPositions,ht.getArg(t,"bias",cn.GREATEST_LOWER_BOUND));if(r>=0){var a=this._originalMappings[r];if(a.source===o.source)return{line:ht.getArg(a,"generatedLine",null),column:ht.getArg(a,"generatedColumn",null),lastColumn:ht.getArg(a,"lastGeneratedColumn",null)}}return{line:null,column:null,lastColumn:null}};Vf.BasicSourceMapConsumer=Dn;function dr(e,t){var n=e;typeof e=="string"&&(n=ht.parseSourceMapInput(e));var o=ht.getArg(n,"version"),r=ht.getArg(n,"sections");if(o!=this._version)throw new Error("Unsupported version: "+o);this._sources=new Bs,this._names=new Bs;var a={line:-1,column:0};this._sections=r.map(function(l){if(l.url)throw new Error("Support for url field in sections not implemented.");var s=ht.getArg(l,"offset"),u=ht.getArg(s,"line"),c=ht.getArg(s,"column");if(u=0;n--)this.prepend(t[n]);else if(t[si]||typeof t=="string")this.children.unshift(t);else throw new TypeError("Expected a SourceNode, string, or an array of SourceNodes and strings. Got "+t);return this};Co.prototype.walk=function(t){for(var n,o=0,r=this.children.length;o0){for(n=[],o=0;ot[E]===Dre&&t[E+1]===Xn,s=E=>t[E]===Xn,u=E=>t[E]===Bre,c=E=>t[E]===Fre,f=E=>l(E)||s(E)||u(E)||c(E),d=()=>n,p=()=>o,m=()=>r,v=()=>a,h=E=>l(E)||u(E)||c(E)?Xn:t[E],C=()=>h(n),g=()=>h(n+a);function y(){return a=0,f(n)&&(o++,r=0),l(n)&&n++,n++,r++,t[n]}function _(){return l(n+a)&&a++,a++,t[n+a]}function b(){n=0,o=1,r=1,a=0}function w(E=0){a=E}function S(){const E=n+a;for(;E!==n;)y();a=0}return{index:d,line:p,column:m,peekOffset:v,charAt:h,currentChar:C,currentPeek:g,next:y,peek:_,reset:b,resetPeek:w,skipToPeek:S}}const ca=void 0,J1="'",Hre="tokenizer";function zre(e,t={}){const n=t.location!==!1,o=Vre(e),r=()=>o.index(),a=()=>xT(o.line(),o.column(),o.index()),l=a(),s=r(),u={currentType:14,offset:s,startLoc:l,endLoc:l,lastType:14,lastOffset:s,lastStartLoc:l,lastEndLoc:l,braceNest:0,inLinked:!1,text:""},c=()=>u,{onError:f}=t;function d(B,z,Z,...ue){const se=c();if(z.column+=Z,z.offset+=Z,f){const me=Ld(se.startLoc,z),_e=ab(B,me,{domain:Hre,args:ue});f(_e)}}function p(B,z,Z){B.endLoc=a(),B.currentType=z;const ue={type:z};return n&&(ue.loc=Ld(B.startLoc,B.endLoc)),Z!=null&&(ue.value=Z),ue}const m=B=>p(B,14);function v(B,z){return B.currentChar()===z?(B.next(),z):(d(Nt.EXPECTED_TOKEN,a(),0,z),"")}function h(B){let z="";for(;B.currentPeek()===Dr||B.currentPeek()===Xn;)z+=B.currentPeek(),B.peek();return z}function C(B){const z=h(B);return B.skipToPeek(),z}function g(B){if(B===ca)return!1;const z=B.charCodeAt(0);return z>=97&&z<=122||z>=65&&z<=90||z===95}function y(B){if(B===ca)return!1;const z=B.charCodeAt(0);return z>=48&&z<=57}function _(B,z){const{currentType:Z}=z;if(Z!==2)return!1;h(B);const ue=g(B.currentPeek());return B.resetPeek(),ue}function b(B,z){const{currentType:Z}=z;if(Z!==2)return!1;h(B);const ue=B.currentPeek()==="-"?B.peek():B.currentPeek(),se=y(ue);return B.resetPeek(),se}function w(B,z){const{currentType:Z}=z;if(Z!==2)return!1;h(B);const ue=B.currentPeek()===J1;return B.resetPeek(),ue}function S(B,z){const{currentType:Z}=z;if(Z!==8)return!1;h(B);const ue=B.currentPeek()===".";return B.resetPeek(),ue}function E(B,z){const{currentType:Z}=z;if(Z!==9)return!1;h(B);const ue=g(B.currentPeek());return B.resetPeek(),ue}function $(B,z){const{currentType:Z}=z;if(!(Z===8||Z===12))return!1;h(B);const ue=B.currentPeek()===":";return B.resetPeek(),ue}function O(B,z){const{currentType:Z}=z;if(Z!==10)return!1;const ue=()=>{const me=B.currentPeek();return me==="{"?g(B.peek()):me==="@"||me==="%"||me==="|"||me===":"||me==="."||me===Dr||!me?!1:me===Xn?(B.peek(),ue()):g(me)},se=ue();return B.resetPeek(),se}function A(B){h(B);const z=B.currentPeek()==="|";return B.resetPeek(),z}function M(B){const z=h(B),Z=B.currentPeek()==="%"&&B.peek()==="{";return B.resetPeek(),{isModulo:Z,hasSpace:z.length>0}}function D(B,z=!0){const Z=(se=!1,me="",_e=!1)=>{const $e=B.currentPeek();return $e==="{"?me==="%"?!1:se:$e==="@"||!$e?me==="%"?!0:se:$e==="%"?(B.peek(),Z(se,"%",!0)):$e==="|"?me==="%"||_e?!0:!(me===Dr||me===Xn):$e===Dr?(B.peek(),Z(!0,Dr,_e)):$e===Xn?(B.peek(),Z(!0,Xn,_e)):!0},ue=Z();return z&&B.resetPeek(),ue}function U(B,z){const Z=B.currentChar();return Z===ca?ca:z(Z)?(B.next(),Z):null}function j(B){return U(B,Z=>{const ue=Z.charCodeAt(0);return ue>=97&&ue<=122||ue>=65&&ue<=90||ue>=48&&ue<=57||ue===95||ue===36})}function W(B){return U(B,Z=>{const ue=Z.charCodeAt(0);return ue>=48&&ue<=57})}function L(B){return U(B,Z=>{const ue=Z.charCodeAt(0);return ue>=48&&ue<=57||ue>=65&&ue<=70||ue>=97&&ue<=102})}function P(B){let z="",Z="";for(;z=W(B);)Z+=z;return Z}function x(B){C(B);const z=B.currentChar();return z!=="%"&&d(Nt.EXPECTED_TOKEN,a(),0,z),B.next(),"%"}function I(B){let z="";for(;;){const Z=B.currentChar();if(Z==="{"||Z==="}"||Z==="@"||Z==="|"||!Z)break;if(Z==="%")if(D(B))z+=Z,B.next();else break;else if(Z===Dr||Z===Xn)if(D(B))z+=Z,B.next();else{if(A(B))break;z+=Z,B.next()}else z+=Z,B.next()}return z}function H(B){C(B);let z="",Z="";for(;z=j(B);)Z+=z;return B.currentChar()===ca&&d(Nt.UNTERMINATED_CLOSING_BRACE,a(),0),Z}function G(B){C(B);let z="";return B.currentChar()==="-"?(B.next(),z+=`-${P(B)}`):z+=P(B),B.currentChar()===ca&&d(Nt.UNTERMINATED_CLOSING_BRACE,a(),0),z}function J(B){C(B),v(B,"'");let z="",Z="";const ue=me=>me!==J1&&me!==Xn;for(;z=U(B,ue);)z==="\\"?Z+=ee(B):Z+=z;const se=B.currentChar();return se===Xn||se===ca?(d(Nt.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER,a(),0),se===Xn&&(B.next(),v(B,"'")),Z):(v(B,"'"),Z)}function ee(B){const z=B.currentChar();switch(z){case"\\":case"'":return B.next(),`\\${z}`;case"u":return fe(B,z,4);case"U":return fe(B,z,6);default:return d(Nt.UNKNOWN_ESCAPE_SEQUENCE,a(),0,z),""}}function fe(B,z,Z){v(B,z);let ue="";for(let se=0;sese!=="{"&&se!=="}"&&se!==Dr&&se!==Xn;for(;z=U(B,ue);)Z+=z;return Z}function oe(B){let z="",Z="";for(;z=j(B);)Z+=z;return Z}function ke(B){const z=(Z=!1,ue)=>{const se=B.currentChar();return se==="{"||se==="%"||se==="@"||se==="|"||!se||se===Dr?ue:se===Xn?(ue+=se,B.next(),z(Z,ue)):(ue+=se,B.next(),z(!0,ue))};return z(!1,"")}function ae(B){C(B);const z=v(B,"|");return C(B),z}function Oe(B,z){let Z=null;switch(B.currentChar()){case"{":return z.braceNest>=1&&d(Nt.NOT_ALLOW_NEST_PLACEHOLDER,a(),0),B.next(),Z=p(z,2,"{"),C(B),z.braceNest++,Z;case"}":return z.braceNest>0&&z.currentType===2&&d(Nt.EMPTY_PLACEHOLDER,a(),0),B.next(),Z=p(z,3,"}"),z.braceNest--,z.braceNest>0&&C(B),z.inLinked&&z.braceNest===0&&(z.inLinked=!1),Z;case"@":return z.braceNest>0&&d(Nt.UNTERMINATED_CLOSING_BRACE,a(),0),Z=we(B,z)||m(z),z.braceNest=0,Z;default:let se=!0,me=!0,_e=!0;if(A(B))return z.braceNest>0&&d(Nt.UNTERMINATED_CLOSING_BRACE,a(),0),Z=p(z,1,ae(B)),z.braceNest=0,z.inLinked=!1,Z;if(z.braceNest>0&&(z.currentType===5||z.currentType===6||z.currentType===7))return d(Nt.UNTERMINATED_CLOSING_BRACE,a(),0),z.braceNest=0,ge(B,z);if(se=_(B,z))return Z=p(z,5,H(B)),C(B),Z;if(me=b(B,z))return Z=p(z,6,G(B)),C(B),Z;if(_e=w(B,z))return Z=p(z,7,J(B)),C(B),Z;if(!se&&!me&&!_e)return Z=p(z,13,Te(B)),d(Nt.INVALID_TOKEN_IN_PLACEHOLDER,a(),0,Z.value),C(B),Z;break}return Z}function we(B,z){const{currentType:Z}=z;let ue=null;const se=B.currentChar();switch((Z===8||Z===9||Z===12||Z===10)&&(se===Xn||se===Dr)&&d(Nt.INVALID_LINKED_FORMAT,a(),0),se){case"@":return B.next(),ue=p(z,8,"@"),z.inLinked=!0,ue;case".":return C(B),B.next(),p(z,9,".");case":":return C(B),B.next(),p(z,10,":");default:return A(B)?(ue=p(z,1,ae(B)),z.braceNest=0,z.inLinked=!1,ue):S(B,z)||$(B,z)?(C(B),we(B,z)):E(B,z)?(C(B),p(z,12,oe(B))):O(B,z)?(C(B),se==="{"?Oe(B,z)||ue:p(z,11,ke(B))):(Z===8&&d(Nt.INVALID_LINKED_FORMAT,a(),0),z.braceNest=0,z.inLinked=!1,ge(B,z))}}function ge(B,z){let Z={type:14};if(z.braceNest>0)return Oe(B,z)||m(z);if(z.inLinked)return we(B,z)||m(z);switch(B.currentChar()){case"{":return Oe(B,z)||m(z);case"}":return d(Nt.UNBALANCED_CLOSING_BRACE,a(),0),B.next(),p(z,3,"}");case"@":return we(B,z)||m(z);default:if(A(B))return Z=p(z,1,ae(B)),z.braceNest=0,z.inLinked=!1,Z;const{isModulo:se,hasSpace:me}=M(B);if(se)return me?p(z,0,I(B)):p(z,4,x(B));if(D(B))return p(z,0,I(B));break}return Z}function q(){const{currentType:B,offset:z,startLoc:Z,endLoc:ue}=u;return u.lastType=B,u.lastOffset=z,u.lastStartLoc=Z,u.lastEndLoc=ue,u.offset=r(),u.startLoc=a(),o.currentChar()===ca?p(u,14):ge(o,u)}return{nextToken:q,currentOffset:r,currentPosition:a,context:c}}const DT="parser",jre=/(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;function Wre(e,t,n){switch(e){case"\\\\":return"\\";case"\\'":return"'";default:{const o=parseInt(t||n,16);return o<=55295||o>=57344?String.fromCodePoint(o):"�"}}}function FT(e={}){const t=e.location!==!1,{onError:n}=e;function o(g,y,_,b,...w){const S=g.currentPosition();if(S.offset+=b,S.column+=b,n){const E=Ld(_,S),$=ab(y,E,{domain:DT,args:w});n($)}}function r(g,y,_){const b={type:g,start:y,end:y};return t&&(b.loc={start:_,end:_}),b}function a(g,y,_,b){g.end=y,t&&g.loc&&(g.loc.end=_)}function l(g,y){const _=g.context(),b=r(3,_.offset,_.startLoc);return b.value=y,a(b,g.currentOffset(),g.currentPosition()),b}function s(g,y){const _=g.context(),{lastOffset:b,lastStartLoc:w}=_,S=r(5,b,w);return S.index=parseInt(y,10),g.nextToken(),a(S,g.currentOffset(),g.currentPosition()),S}function u(g,y){const _=g.context(),{lastOffset:b,lastStartLoc:w}=_,S=r(4,b,w);return S.key=y,g.nextToken(),a(S,g.currentOffset(),g.currentPosition()),S}function c(g,y){const _=g.context(),{lastOffset:b,lastStartLoc:w}=_,S=r(9,b,w);return S.value=y.replace(jre,Wre),g.nextToken(),a(S,g.currentOffset(),g.currentPosition()),S}function f(g){const y=g.nextToken(),_=g.context(),{lastOffset:b,lastStartLoc:w}=_,S=r(8,b,w);return y.type!==12?(o(g,Nt.UNEXPECTED_EMPTY_LINKED_MODIFIER,_.lastStartLoc,0),S.value="",a(S,b,w),{nextConsumeToken:y,node:S}):(y.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,_.lastStartLoc,0,fr(y)),S.value=y.value||"",a(S,g.currentOffset(),g.currentPosition()),{node:S})}function d(g,y){const _=g.context(),b=r(7,_.offset,_.startLoc);return b.value=y,a(b,g.currentOffset(),g.currentPosition()),b}function p(g){const y=g.context(),_=r(6,y.offset,y.startLoc);let b=g.nextToken();if(b.type===9){const w=f(g);_.modifier=w.node,b=w.nextConsumeToken||g.nextToken()}switch(b.type!==10&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(b)),b=g.nextToken(),b.type===2&&(b=g.nextToken()),b.type){case 11:b.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(b)),_.key=d(g,b.value||"");break;case 5:b.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(b)),_.key=u(g,b.value||"");break;case 6:b.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(b)),_.key=s(g,b.value||"");break;case 7:b.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(b)),_.key=c(g,b.value||"");break;default:o(g,Nt.UNEXPECTED_EMPTY_LINKED_KEY,y.lastStartLoc,0);const w=g.context(),S=r(7,w.offset,w.startLoc);return S.value="",a(S,w.offset,w.startLoc),_.key=S,a(_,w.offset,w.startLoc),{nextConsumeToken:b,node:_}}return a(_,g.currentOffset(),g.currentPosition()),{node:_}}function m(g){const y=g.context(),_=y.currentType===1?g.currentOffset():y.offset,b=y.currentType===1?y.endLoc:y.startLoc,w=r(2,_,b);w.items=[];let S=null;do{const O=S||g.nextToken();switch(S=null,O.type){case 0:O.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(O)),w.items.push(l(g,O.value||""));break;case 6:O.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(O)),w.items.push(s(g,O.value||""));break;case 5:O.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(O)),w.items.push(u(g,O.value||""));break;case 7:O.value==null&&o(g,Nt.UNEXPECTED_LEXICAL_ANALYSIS,y.lastStartLoc,0,fr(O)),w.items.push(c(g,O.value||""));break;case 8:const A=p(g);w.items.push(A.node),S=A.nextConsumeToken||null;break}}while(y.currentType!==14&&y.currentType!==1);const E=y.currentType===1?y.lastOffset:g.currentOffset(),$=y.currentType===1?y.lastEndLoc:g.currentPosition();return a(w,E,$),w}function v(g,y,_,b){const w=g.context();let S=b.items.length===0;const E=r(1,y,_);E.cases=[],E.cases.push(b);do{const $=m(g);S||(S=$.items.length===0),E.cases.push($)}while(w.currentType!==14);return S&&o(g,Nt.MUST_HAVE_MESSAGES_IN_PLURAL,_,0),a(E,g.currentOffset(),g.currentPosition()),E}function h(g){const y=g.context(),{offset:_,startLoc:b}=y,w=m(g);return y.currentType===14?w:v(g,_,b,w)}function C(g){const y=zre(g,Rd.assign({},e)),_=y.context(),b=r(0,_.offset,_.startLoc);return t&&b.loc&&(b.loc.source=g),b.body=h(y),_.currentType!==14&&o(y,Nt.UNEXPECTED_LEXICAL_ANALYSIS,_.lastStartLoc,0,g[_.offset]||""),a(b,y.currentOffset(),y.currentPosition()),b}return{parse:C}}function fr(e){if(e.type===14)return"EOF";const t=(e.value||"").replace(/\r?\n/gu,"\\n");return t.length>10?t.slice(0,9)+"…":t}function Kre(e,t={}){const n={ast:e,helpers:new Set};return{context:()=>n,helper:a=>(n.helpers.add(a),a)}}function Z1(e,t){for(let n=0;nl;function u(C,g){l.code+=C,l.map&&(g&&g.loc&&g.loc!==LT&&h(g.loc.start,Qre(g)),eae(l,C))}function c(C,g=!0){const y=g?r:"";u(a?y+" ".repeat(C):y)}function f(C=!0){const g=++l.indentLevel;C&&c(g)}function d(C=!0){const g=--l.indentLevel;C&&c(g)}function p(){c(l.indentLevel)}const m=C=>`_${C}`,v=()=>l.needIndent;function h(C,g){l.map.addMapping({name:g,source:l.filename,original:{line:C.line,column:C.column-1},generated:{line:l.line,column:l.column-1}})}return n&&(l.map=new Rre.SourceMapGenerator,l.map.setSourceContent(o,l.source)),{context:s,push:u,indent:f,deindent:d,newline:p,helper:m,needIndent:v}}function Yre(e,t){const{helper:n}=e;e.push(`${n("linked")}(`),Vs(e,t.key),t.modifier?(e.push(", "),Vs(e,t.modifier),e.push(", _type")):e.push(", undefined, _type"),e.push(")")}function Gre(e,t){const{helper:n,needIndent:o}=e;e.push(`${n("normalize")}([`),e.indent(o());const r=t.items.length;for(let a=0;a1){e.push(`${n("plural")}([`),e.indent(o());const r=t.cases.length;for(let a=0;a{const n=Rd.isString(t.mode)?t.mode:"normal",o=Rd.isString(t.filename)?t.filename:"message.intl",r=!!t.sourceMap,a=t.breakLineCode!=null?t.breakLineCode:n==="arrow"?";":` +`,l=t.needIndent?t.needIndent:n!=="arrow",s=e.helpers||[],u=qre(e,{mode:n,filename:o,sourceMap:r,breakLineCode:a,needIndent:l});u.push(n==="normal"?"function __msg__ (ctx) {":"(ctx) => {"),u.indent(l),s.length>0&&(u.push(`const { ${s.map(d=>`${d}: _${d}`).join(", ")} } = ctx`),u.newline()),u.push("return "),Vs(u,e),u.deindent(l),u.push("}");const{code:c,map:f}=u.context();return{ast:e,code:c,map:f?f.toJSON():void 0}};function Qre(e){switch(e.type){case 3:case 9:case 8:case 7:return e.value;case 5:return e.index.toString();case 4:return e.key;default:return}}function eae(e,t,n=t.length){let o=0,r=-1;for(let a=0;a{l===void 0?l=s:l+=s},p[1]=()=>{l!==void 0&&(t.push(l),l=void 0)},p[2]=()=>{p[0](),r++},p[3]=()=>{if(r>0)r--,o=4,p[0]();else{if(r=0,l===void 0||(l=uae(l),l===!1))return!1;p[1]()}};function m(){const v=e[n+1];if(o===5&&v==="'"||o===6&&v==='"')return n++,s="\\"+v,p[0](),!0}for(;o!==null;)if(n++,a=e[n],!(a==="\\"&&m())){if(u=iae(a),d=Va[o],c=d[u]||d.l||8,c===8||(o=c[0],c[1]!==void 0&&(f=p[c[1]],f&&(s=a,f()===!1))))return;if(o===7)return t}}const Q1=new Map;function zT(e,t){return Ae.isObject(e)?e[t]:null}function cae(e,t){if(!Ae.isObject(e))return null;let n=Q1.get(t);if(n||(n=HT(t),n&&Q1.set(t,n)),!n)return null;const o=n.length;let r=e,a=0;for(;ae,fae=e=>"",jT="text",pae=e=>e.length===0?"":e.join(""),hae=Ae.toDisplayString;function ew(e,t){return e=Math.abs(e),t===2?e?e>1?1:0:1:e?Math.min(e,2):0}function mae(e){const t=Ae.isNumber(e.pluralIndex)?e.pluralIndex:-1;return e.named&&(Ae.isNumber(e.named.count)||Ae.isNumber(e.named.n))?Ae.isNumber(e.named.count)?e.named.count:Ae.isNumber(e.named.n)?e.named.n:t:t}function vae(e,t){t.count||(t.count=e),t.n||(t.n=e)}function WT(e={}){const t=e.locale,n=mae(e),o=Ae.isObject(e.pluralRules)&&Ae.isString(t)&&Ae.isFunction(e.pluralRules[t])?e.pluralRules[t]:ew,r=Ae.isObject(e.pluralRules)&&Ae.isString(t)&&Ae.isFunction(e.pluralRules[t])?ew:void 0,a=g=>g[o(n,g.length,r)],l=e.list||[],s=g=>l[g],u=e.named||{};Ae.isNumber(e.pluralIndex)&&vae(n,u);const c=g=>u[g];function f(g){const y=Ae.isFunction(e.messages)?e.messages(g):Ae.isObject(e.messages)?e.messages[g]:!1;return y||(e.parent?e.parent.message(g):fae)}const d=g=>e.modifiers?e.modifiers[g]:dae,p=Ae.isPlainObject(e.processor)&&Ae.isFunction(e.processor.normalize)?e.processor.normalize:pae,m=Ae.isPlainObject(e.processor)&&Ae.isFunction(e.processor.interpolate)?e.processor.interpolate:hae,v=Ae.isPlainObject(e.processor)&&Ae.isString(e.processor.type)?e.processor.type:jT,C={list:s,named:c,plural:a,linked:(g,...y)=>{const[_,b]=y;let w="text",S="";y.length===1?Ae.isObject(_)?(S=_.modifier||S,w=_.type||w):Ae.isString(_)&&(S=_||S):y.length===2&&(Ae.isString(_)&&(S=_||S),Ae.isString(b)&&(w=b||w));let E=f(g)(C);return w==="vnode"&&Ae.isArray(E)&&S&&(E=E[0]),S?d(S)(E,w):E},message:f,type:v,interpolate:m,normalize:p};return C}let zs=null;function gae(e){zs=e}function bae(){return zs}function yae(e,t,n){zs&&zs.emit(VT.IntlifyDevToolsHooks.I18nInit,{timestamp:Date.now(),i18n:e,version:t,meta:n})}const wae=_ae(VT.IntlifyDevToolsHooks.FunctionTranslate);function _ae(e){return t=>zs&&zs.emit(e,t)}const Ka={NOT_FOUND_KEY:1,FALLBACK_TO_TRANSLATE:2,CANNOT_FORMAT_NUMBER:3,FALLBACK_TO_NUMBER_FORMAT:4,CANNOT_FORMAT_DATE:5,FALLBACK_TO_DATE_FORMAT:6,__EXTEND_POINT__:7},Cae={[Ka.NOT_FOUND_KEY]:"Not found '{key}' key in '{locale}' locale messages.",[Ka.FALLBACK_TO_TRANSLATE]:"Fall back to translate '{key}' key with '{target}' locale.",[Ka.CANNOT_FORMAT_NUMBER]:"Cannot format a number value due to not supported Intl.NumberFormat.",[Ka.FALLBACK_TO_NUMBER_FORMAT]:"Fall back to number format '{key}' key with '{target}' locale.",[Ka.CANNOT_FORMAT_DATE]:"Cannot format a date value due to not supported Intl.DateTimeFormat.",[Ka.FALLBACK_TO_DATE_FORMAT]:"Fall back to datetime format '{key}' key with '{target}' locale."};function Sae(e,...t){return Ae.format(Cae[e],...t)}function KT(e,t,n){return[...new Set([n,...Ae.isArray(t)?t:Ae.isObject(t)?Object.keys(t):Ae.isString(t)?[t]:[n]])]}function kae(e,t,n){const o=Ae.isString(n)?n:ib,r=e;r.__localeChainCache||(r.__localeChainCache=new Map);let a=r.__localeChainCache.get(o);if(!a){a=[];let l=[n];for(;Ae.isArray(l);)l=tw(a,l,t);const s=Ae.isArray(t)||!Ae.isPlainObject(t)?t:t.default?t.default:null;l=Ae.isString(s)?[s]:s,Ae.isArray(l)&&tw(a,l,!1),r.__localeChainCache.set(o,a)}return a}function tw(e,t,n){let o=!0;for(let r=0;r`${e.charAt(0).toLocaleUpperCase()}${e.substr(1)}`;function Oae(){return{upper:(e,t)=>t==="text"&&Ae.isString(e)?e.toUpperCase():t==="vnode"&&Ae.isObject(e)&&"__v_isVNode"in e?e.children.toUpperCase():e,lower:(e,t)=>t==="text"&&Ae.isString(e)?e.toLowerCase():t==="vnode"&&Ae.isObject(e)&&"__v_isVNode"in e?e.children.toLowerCase():e,capitalize:(e,t)=>t==="text"&&Ae.isString(e)?nw(e):t==="vnode"&&Ae.isObject(e)&&"__v_isVNode"in e?nw(e.children):e}}let qT;function Nae(e){qT=e}let YT;function Iae(e){YT=e}let GT;function Mae(e){GT=e}let XT=null;const Aae=e=>{XT=e},Pae=()=>XT;let JT=null;const Rae=e=>{JT=e},Lae=()=>JT;let ow=0;function xae(e={}){const t=Ae.isString(e.version)?e.version:UT,n=Ae.isString(e.locale)?e.locale:ib,o=Ae.isArray(e.fallbackLocale)||Ae.isPlainObject(e.fallbackLocale)||Ae.isString(e.fallbackLocale)||e.fallbackLocale===!1?e.fallbackLocale:n,r=Ae.isPlainObject(e.messages)?e.messages:{[n]:{}},a=Ae.isPlainObject(e.datetimeFormats)?e.datetimeFormats:{[n]:{}},l=Ae.isPlainObject(e.numberFormats)?e.numberFormats:{[n]:{}},s=Ae.assign({},e.modifiers||{},Oae()),u=e.pluralRules||{},c=Ae.isFunction(e.missing)?e.missing:null,f=Ae.isBoolean(e.missingWarn)||Ae.isRegExp(e.missingWarn)?e.missingWarn:!0,d=Ae.isBoolean(e.fallbackWarn)||Ae.isRegExp(e.fallbackWarn)?e.fallbackWarn:!0,p=!!e.fallbackFormat,m=!!e.unresolving,v=Ae.isFunction(e.postTranslation)?e.postTranslation:null,h=Ae.isPlainObject(e.processor)?e.processor:null,C=Ae.isBoolean(e.warnHtmlMessage)?e.warnHtmlMessage:!0,g=!!e.escapeParameter,y=Ae.isFunction(e.messageCompiler)?e.messageCompiler:qT,_=Ae.isFunction(e.messageResolver)?e.messageResolver:YT||zT,b=Ae.isFunction(e.localeFallbacker)?e.localeFallbacker:GT||KT,w=Ae.isObject(e.fallbackContext)?e.fallbackContext:void 0,S=Ae.isFunction(e.onWarn)?e.onWarn:Ae.warn,E=e,$=Ae.isObject(E.__datetimeFormatters)?E.__datetimeFormatters:new Map,O=Ae.isObject(E.__numberFormatters)?E.__numberFormatters:new Map,A=Ae.isObject(E.__meta)?E.__meta:{};ow++;const M={version:t,cid:ow,locale:n,fallbackLocale:o,messages:r,modifiers:s,pluralRules:u,missing:c,missingWarn:f,fallbackWarn:d,fallbackFormat:p,unresolving:m,postTranslation:v,processor:h,warnHtmlMessage:C,escapeParameter:g,messageCompiler:y,messageResolver:_,localeFallbacker:b,fallbackContext:w,onWarn:S,__meta:A};return M.datetimeFormats=a,M.numberFormats=l,M.__datetimeFormatters=$,M.__numberFormatters=O,M}function Dae(e,t){return e instanceof RegExp?e.test(t):e}function Fae(e,t){return e instanceof RegExp?e.test(t):e}function zf(e,t,n,o,r){const{missing:a,onWarn:l}=e;if(a!==null){const s=a(e,n,t,r);return Ae.isString(s)?s:t}else return t}function Bae(e,t,n){const o=e;o.__localeChainCache=new Map,e.localeFallbacker(e,n,t)}const Vae=e=>e;let Tm=Object.create(null);function Hae(){Tm=Object.create(null)}function zae(e,t={}){{const o=(t.onCacheKey||Vae)(e),r=Tm[o];if(r)return r;let a=!1;const l=t.onError||Hs.defaultOnError;t.onError=c=>{a=!0,l(c)};const{code:s}=Hs.baseCompile(e,t),u=new Function(`return ${s}`)();return a?u:Tm[o]=u}}let ZT=Hs.CompileErrorCodes.__EXTEND_POINT__;const Vp=()=>++ZT,wr={INVALID_ARGUMENT:ZT,INVALID_DATE_ARGUMENT:Vp(),INVALID_ISO_DATE_ARGUMENT:Vp(),__EXTEND_POINT__:Vp()};function rl(e){return Hs.createCompileError(e,null,void 0)}wr.INVALID_ARGUMENT+"",wr.INVALID_DATE_ARGUMENT+"",wr.INVALID_ISO_DATE_ARGUMENT+"";const rw=()=>"",ka=e=>Ae.isFunction(e);function jae(e,...t){const{fallbackFormat:n,postTranslation:o,unresolving:r,messageCompiler:a,fallbackLocale:l,messages:s}=e,[u,c]=t$(...t),f=Ae.isBoolean(c.missingWarn)?c.missingWarn:e.missingWarn,d=Ae.isBoolean(c.fallbackWarn)?c.fallbackWarn:e.fallbackWarn,p=Ae.isBoolean(c.escapeParameter)?c.escapeParameter:e.escapeParameter,m=!!c.resolvedMessage,v=Ae.isString(c.default)||Ae.isBoolean(c.default)?Ae.isBoolean(c.default)?a?u:()=>u:c.default:n?a?u:()=>u:"",h=n||v!=="",C=Ae.isString(c.locale)?c.locale:e.locale;p&&Wae(c);let[g,y,_]=m?[u,C,s[C]||{}]:QT(e,u,C,l,d,f),b=g,w=u;if(!m&&!(Ae.isString(b)||ka(b))&&h&&(b=v,w=b),!m&&(!(Ae.isString(b)||ka(b))||!Ae.isString(y)))return r?Hf:u;let S=!1;const E=()=>{S=!0},$=ka(b)?b:e$(e,u,y,b,w,E);if(S)return b;const O=qae(e,y,_,c),A=WT(O),M=Kae(e,$,A);return o?o(M,u):M}function Wae(e){Ae.isArray(e.list)?e.list=e.list.map(t=>Ae.isString(t)?Ae.escapeHtml(t):t):Ae.isObject(e.named)&&Object.keys(e.named).forEach(t=>{Ae.isString(e.named[t])&&(e.named[t]=Ae.escapeHtml(e.named[t]))})}function QT(e,t,n,o,r,a){const{messages:l,onWarn:s,messageResolver:u,localeFallbacker:c}=e,f=c(e,o,n);let d={},p,m=null;const v="translate";for(let h=0;ho;return c.locale=n,c.key=t,c}const u=l(o,Uae(e,n,r,o,s,a));return u.locale=n,u.key=t,u.source=o,u}function Kae(e,t,n){return t(n)}function t$(...e){const[t,n,o]=e,r={};if(!Ae.isString(t)&&!Ae.isNumber(t)&&!ka(t))throw rl(wr.INVALID_ARGUMENT);const a=Ae.isNumber(t)?String(t):(ka(t),t);return Ae.isNumber(n)?r.plural=n:Ae.isString(n)?r.default=n:Ae.isPlainObject(n)&&!Ae.isEmptyObject(n)?r.named=n:Ae.isArray(n)&&(r.list=n),Ae.isNumber(o)?r.plural=o:Ae.isString(o)?r.default=o:Ae.isPlainObject(o)&&Ae.assign(r,o),[a,r]}function Uae(e,t,n,o,r,a){return{warnHtmlMessage:r,onError:l=>{throw a&&a(l),l},onCacheKey:l=>Ae.generateFormatCacheKey(t,n,l)}}function qae(e,t,n,o){const{modifiers:r,pluralRules:a,messageResolver:l,fallbackLocale:s,fallbackWarn:u,missingWarn:c,fallbackContext:f}=e,p={locale:t,modifiers:r,pluralRules:a,messages:m=>{let v=l(n,m);if(v==null&&f){const[,,h]=QT(f,m,t,s,u,c);v=l(h,m)}if(Ae.isString(v)){let h=!1;const g=e$(e,m,t,v,m,()=>{h=!0});return h?rw:g}else return ka(v)?v:rw}};return e.processor&&(p.processor=e.processor),o.list&&(p.list=o.list),o.named&&(p.named=o.named),Ae.isNumber(o.plural)&&(p.pluralIndex=o.plural),p}function Yae(e,...t){const{datetimeFormats:n,unresolving:o,fallbackLocale:r,onWarn:a,localeFallbacker:l}=e,{__datetimeFormatters:s}=e,[u,c,f,d]=o$(...t),p=Ae.isBoolean(f.missingWarn)?f.missingWarn:e.missingWarn;Ae.isBoolean(f.fallbackWarn)?f.fallbackWarn:e.fallbackWarn;const m=!!f.part,v=Ae.isString(f.locale)?f.locale:e.locale,h=l(e,r,v);if(!Ae.isString(u)||u==="")return new Intl.DateTimeFormat(v,d).format(c);let C={},g,y=null;const _="datetime format";for(let S=0;S{n$.includes(u)?l[u]=n[u]:a[u]=n[u]}),Ae.isString(o)?a.locale=o:Ae.isPlainObject(o)&&(l=o),Ae.isPlainObject(r)&&(l=r),[a.key||"",s,a,l]}function Gae(e,t,n){const o=e;for(const r in n){const a=`${t}__${r}`;o.__datetimeFormatters.has(a)&&o.__datetimeFormatters.delete(a)}}function Xae(e,...t){const{numberFormats:n,unresolving:o,fallbackLocale:r,onWarn:a,localeFallbacker:l}=e,{__numberFormatters:s}=e,[u,c,f,d]=a$(...t),p=Ae.isBoolean(f.missingWarn)?f.missingWarn:e.missingWarn;Ae.isBoolean(f.fallbackWarn)?f.fallbackWarn:e.fallbackWarn;const m=!!f.part,v=Ae.isString(f.locale)?f.locale:e.locale,h=l(e,r,v);if(!Ae.isString(u)||u==="")return new Intl.NumberFormat(v,d).format(c);let C={},g,y=null;const _="number format";for(let S=0;S{r$.includes(u)?l[u]=n[u]:a[u]=n[u]}),Ae.isString(o)?a.locale=o:Ae.isPlainObject(o)&&(l=o),Ae.isPlainObject(r)&&(l=r),[a.key||"",s,a,l]}function Jae(e,t,n){const o=e;for(const r in n){const a=`${t}__${r}`;o.__numberFormatters.has(a)&&o.__numberFormatters.delete(a)}}Ot.CompileErrorCodes=Hs.CompileErrorCodes;Ot.createCompileError=Hs.createCompileError;Ot.CoreErrorCodes=wr;Ot.CoreWarnCodes=Ka;Ot.DATETIME_FORMAT_OPTIONS_KEYS=n$;Ot.DEFAULT_LOCALE=ib;Ot.DEFAULT_MESSAGE_DATA_TYPE=jT;Ot.MISSING_RESOLVE_VALUE=$ae;Ot.NOT_REOSLVED=Hf;Ot.NUMBER_FORMAT_OPTIONS_KEYS=r$;Ot.VERSION=UT;Ot.clearCompileCache=Hae;Ot.clearDateTimeFormat=Gae;Ot.clearNumberFormat=Jae;Ot.compileToFunction=zae;Ot.createCoreContext=xae;Ot.createCoreError=rl;Ot.createMessageContext=WT;Ot.datetime=Yae;Ot.fallbackWithLocaleChain=kae;Ot.fallbackWithSimple=KT;Ot.getAdditionalMeta=Pae;Ot.getDevToolsHook=bae;Ot.getFallbackContext=Lae;Ot.getWarnMessage=Sae;Ot.handleMissing=zf;Ot.initI18nDevTools=yae;Ot.isMessageFunction=ka;Ot.isTranslateFallbackWarn=Dae;Ot.isTranslateMissingWarn=Fae;Ot.number=Xae;Ot.parse=HT;Ot.parseDateTimeArgs=o$;Ot.parseNumberArgs=a$;Ot.parseTranslateArgs=t$;Ot.registerLocaleFallbacker=Mae;Ot.registerMessageCompiler=Nae;Ot.registerMessageResolver=Iae;Ot.resolveValue=cae;Ot.resolveWithKeyValue=zT;Ot.setAdditionalMeta=Aae;Ot.setDevToolsHook=gae;Ot.setFallbackContext=Rae;Ot.translate=jae;Ot.translateDevTools=wae;Ot.updateFallbackLocale=Bae;wT.exports=Ot;var Zae=wT.exports;const Qae=mV(kI);/*! + * vue-i18n v9.2.2 + * (c) 2022 kazuya kawaguchi + * Released under the MIT License. + */Object.defineProperty(Pr,"__esModule",{value:!0});var It=Zae,Rt=Qae,Me=Jg;const l$="9.2.2";let s$=It.CompileErrorCodes.__EXTEND_POINT__;const oo=()=>++s$,mn={UNEXPECTED_RETURN_TYPE:s$,INVALID_ARGUMENT:oo(),MUST_BE_CALL_SETUP_TOP:oo(),NOT_INSLALLED:oo(),NOT_AVAILABLE_IN_LEGACY_MODE:oo(),REQUIRED_VALUE:oo(),INVALID_VALUE:oo(),CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN:oo(),NOT_INSLALLED_WITH_PROVIDE:oo(),UNEXPECTED_ERROR:oo(),NOT_COMPATIBLE_LEGACY_VUE_I18N:oo(),BRIDGE_SUPPORT_VUE_2_ONLY:oo(),MUST_DEFINE_I18N_OPTION_IN_ALLOW_COMPOSITION:oo(),NOT_AVAILABLE_COMPOSITION_IN_LEGACY:oo(),__EXTEND_POINT__:oo()};function _n(e,...t){return It.createCompileError(e,null,void 0)}const $m=Me.makeSymbol("__transrateVNode"),Om=Me.makeSymbol("__datetimeParts"),Nm=Me.makeSymbol("__numberParts"),i$=Me.makeSymbol("__setPluralRules");Me.makeSymbol("__intlifyMeta");const u$=Me.makeSymbol("__injectWithOption"),ele="__VUE_I18N_BRIDGE__";function Im(e){if(!Me.isObject(e))return e;for(const t in e)if(Me.hasOwn(e,t))if(!t.includes("."))Me.isObject(e[t])&&Im(e[t]);else{const n=t.split("."),o=n.length-1;let r=e;for(let a=0;a{if("locale"in s&&"resource"in s){const{locale:u,resource:c}=s;u?(l[u]=l[u]||{},Hi(c,l[u])):Hi(c,l)}else Me.isString(s)&&Hi(JSON.parse(s),l)}),r==null&&a)for(const s in l)Me.hasOwn(l,s)&&Im(l[s]);return l}const kc=e=>!Me.isObject(e)||Me.isArray(e);function Hi(e,t){if(kc(e)||kc(t))throw _n(mn.INVALID_VALUE);for(const n in e)Me.hasOwn(e,n)&&(kc(e[n])||kc(t[n])?t[n]=e[n]:Hi(e[n],t[n]))}function tle(e){return e.type}function c$(e,t,n){let o=Me.isObject(t.messages)?t.messages:{};"__i18nGlobal"in n&&(o=jf(e.locale.value,{messages:o,__i18n:n.__i18nGlobal}));const r=Object.keys(o);r.length&&r.forEach(a=>{e.mergeLocaleMessage(a,o[a])});{if(Me.isObject(t.datetimeFormats)){const a=Object.keys(t.datetimeFormats);a.length&&a.forEach(l=>{e.mergeDateTimeFormat(l,t.datetimeFormats[l])})}if(Me.isObject(t.numberFormats)){const a=Object.keys(t.numberFormats);a.length&&a.forEach(l=>{e.mergeNumberFormat(l,t.numberFormats[l])})}}}function aw(e){return Rt.createVNode(Rt.Text,null,e,0)}let lw=0;function sw(e){return(t,n,o,r)=>e(n,o,Rt.getCurrentInstance()||void 0,r)}function ub(e={},t){const{__root:n}=e,o=n===void 0;let r=Me.isBoolean(e.inheritLocale)?e.inheritLocale:!0;const a=Rt.ref(n&&r?n.locale.value:Me.isString(e.locale)?e.locale:It.DEFAULT_LOCALE),l=Rt.ref(n&&r?n.fallbackLocale.value:Me.isString(e.fallbackLocale)||Me.isArray(e.fallbackLocale)||Me.isPlainObject(e.fallbackLocale)||e.fallbackLocale===!1?e.fallbackLocale:a.value),s=Rt.ref(jf(a.value,e)),u=Rt.ref(Me.isPlainObject(e.datetimeFormats)?e.datetimeFormats:{[a.value]:{}}),c=Rt.ref(Me.isPlainObject(e.numberFormats)?e.numberFormats:{[a.value]:{}});let f=n?n.missingWarn:Me.isBoolean(e.missingWarn)||Me.isRegExp(e.missingWarn)?e.missingWarn:!0,d=n?n.fallbackWarn:Me.isBoolean(e.fallbackWarn)||Me.isRegExp(e.fallbackWarn)?e.fallbackWarn:!0,p=n?n.fallbackRoot:Me.isBoolean(e.fallbackRoot)?e.fallbackRoot:!0,m=!!e.fallbackFormat,v=Me.isFunction(e.missing)?e.missing:null,h=Me.isFunction(e.missing)?sw(e.missing):null,C=Me.isFunction(e.postTranslation)?e.postTranslation:null,g=n?n.warnHtmlMessage:Me.isBoolean(e.warnHtmlMessage)?e.warnHtmlMessage:!0,y=!!e.escapeParameter;const _=n?n.modifiers:Me.isPlainObject(e.modifiers)?e.modifiers:{};let b=e.pluralRules||n&&n.pluralRules,w;w=(()=>{o&&It.setFallbackContext(null);const ce={version:l$,locale:a.value,fallbackLocale:l.value,messages:s.value,modifiers:_,pluralRules:b,missing:h===null?void 0:h,missingWarn:f,fallbackWarn:d,fallbackFormat:m,unresolving:!0,postTranslation:C===null?void 0:C,warnHtmlMessage:g,escapeParameter:y,messageResolver:e.messageResolver,__meta:{framework:"vue"}};ce.datetimeFormats=u.value,ce.numberFormats=c.value,ce.__datetimeFormatters=Me.isPlainObject(w)?w.__datetimeFormatters:void 0,ce.__numberFormatters=Me.isPlainObject(w)?w.__numberFormatters:void 0;const de=It.createCoreContext(ce);return o&&It.setFallbackContext(de),de})(),It.updateFallbackLocale(w,a.value,l.value);function E(){return[a.value,l.value,s.value,u.value,c.value]}const $=Rt.computed({get:()=>a.value,set:ce=>{a.value=ce,w.locale=a.value}}),O=Rt.computed({get:()=>l.value,set:ce=>{l.value=ce,w.fallbackLocale=l.value,It.updateFallbackLocale(w,a.value,ce)}}),A=Rt.computed(()=>s.value),M=Rt.computed(()=>u.value),D=Rt.computed(()=>c.value);function U(){return Me.isFunction(C)?C:null}function j(ce){C=ce,w.postTranslation=ce}function W(){return v}function L(ce){ce!==null&&(h=sw(ce)),v=ce,w.missing=h}const P=(ce,de,xe,he,He,et)=>{E();let rt;if(rt=ce(w),Me.isNumber(rt)&&rt===It.NOT_REOSLVED){const[wt,Ze]=de();return n&&p?he(n):He(wt)}else{if(et(rt))return rt;throw _n(mn.UNEXPECTED_RETURN_TYPE)}};function x(...ce){return P(de=>Reflect.apply(It.translate,null,[de,...ce]),()=>It.parseTranslateArgs(...ce),"translate",de=>Reflect.apply(de.t,de,[...ce]),de=>de,de=>Me.isString(de))}function I(...ce){const[de,xe,he]=ce;if(he&&!Me.isObject(he))throw _n(mn.INVALID_ARGUMENT);return x(de,xe,Me.assign({resolvedMessage:!0},he||{}))}function H(...ce){return P(de=>Reflect.apply(It.datetime,null,[de,...ce]),()=>It.parseDateTimeArgs(...ce),"datetime format",de=>Reflect.apply(de.d,de,[...ce]),()=>It.MISSING_RESOLVE_VALUE,de=>Me.isString(de))}function G(...ce){return P(de=>Reflect.apply(It.number,null,[de,...ce]),()=>It.parseNumberArgs(...ce),"number format",de=>Reflect.apply(de.n,de,[...ce]),()=>It.MISSING_RESOLVE_VALUE,de=>Me.isString(de))}function J(ce){return ce.map(de=>Me.isString(de)||Me.isNumber(de)||Me.isBoolean(de)?aw(String(de)):de)}const fe={normalize:J,interpolate:ce=>ce,type:"vnode"};function Te(...ce){return P(de=>{let xe;const he=de;try{he.processor=fe,xe=Reflect.apply(It.translate,null,[he,...ce])}finally{he.processor=null}return xe},()=>It.parseTranslateArgs(...ce),"translate",de=>de[$m](...ce),de=>[aw(de)],de=>Me.isArray(de))}function oe(...ce){return P(de=>Reflect.apply(It.number,null,[de,...ce]),()=>It.parseNumberArgs(...ce),"number format",de=>de[Nm](...ce),()=>[],de=>Me.isString(de)||Me.isArray(de))}function ke(...ce){return P(de=>Reflect.apply(It.datetime,null,[de,...ce]),()=>It.parseDateTimeArgs(...ce),"datetime format",de=>de[Om](...ce),()=>[],de=>Me.isString(de)||Me.isArray(de))}function ae(ce){b=ce,w.pluralRules=b}function Oe(ce,de){const xe=Me.isString(de)?de:a.value,he=q(xe);return w.messageResolver(he,ce)!==null}function we(ce){let de=null;const xe=It.fallbackWithLocaleChain(w,l.value,a.value);for(let he=0;he{r&&(a.value=ce,w.locale=ce,It.updateFallbackLocale(w,a.value,l.value))}),Rt.watch(n.fallbackLocale,ce=>{r&&(l.value=ce,w.fallbackLocale=ce,It.updateFallbackLocale(w,a.value,l.value))}));const Ce={id:lw,locale:$,fallbackLocale:O,get inheritLocale(){return r},set inheritLocale(ce){r=ce,ce&&n&&(a.value=n.locale.value,l.value=n.fallbackLocale.value,It.updateFallbackLocale(w,a.value,l.value))},get availableLocales(){return Object.keys(s.value).sort()},messages:A,get modifiers(){return _},get pluralRules(){return b||{}},get isGlobal(){return o},get missingWarn(){return f},set missingWarn(ce){f=ce,w.missingWarn=f},get fallbackWarn(){return d},set fallbackWarn(ce){d=ce,w.fallbackWarn=d},get fallbackRoot(){return p},set fallbackRoot(ce){p=ce},get fallbackFormat(){return m},set fallbackFormat(ce){m=ce,w.fallbackFormat=m},get warnHtmlMessage(){return g},set warnHtmlMessage(ce){g=ce,w.warnHtmlMessage=ce},get escapeParameter(){return y},set escapeParameter(ce){y=ce,w.escapeParameter=ce},t:x,getLocaleMessage:q,setLocaleMessage:B,mergeLocaleMessage:z,getPostTranslationHandler:U,setPostTranslationHandler:j,getMissingHandler:W,setMissingHandler:L,[i$]:ae};return Ce.datetimeFormats=M,Ce.numberFormats=D,Ce.rt=I,Ce.te=Oe,Ce.tm=ge,Ce.d=H,Ce.n=G,Ce.getDateTimeFormat=Z,Ce.setDateTimeFormat=ue,Ce.mergeDateTimeFormat=se,Ce.getNumberFormat=me,Ce.setNumberFormat=_e,Ce.mergeNumberFormat=$e,Ce[u$]=e.__injectWithOption,Ce[$m]=Te,Ce[Om]=ke,Ce[Nm]=oe,Ce}function nle(e){const t=Me.isString(e.locale)?e.locale:It.DEFAULT_LOCALE,n=Me.isString(e.fallbackLocale)||Me.isArray(e.fallbackLocale)||Me.isPlainObject(e.fallbackLocale)||e.fallbackLocale===!1?e.fallbackLocale:t,o=Me.isFunction(e.missing)?e.missing:void 0,r=Me.isBoolean(e.silentTranslationWarn)||Me.isRegExp(e.silentTranslationWarn)?!e.silentTranslationWarn:!0,a=Me.isBoolean(e.silentFallbackWarn)||Me.isRegExp(e.silentFallbackWarn)?!e.silentFallbackWarn:!0,l=Me.isBoolean(e.fallbackRoot)?e.fallbackRoot:!0,s=!!e.formatFallbackMessages,u=Me.isPlainObject(e.modifiers)?e.modifiers:{},c=e.pluralizationRules,f=Me.isFunction(e.postTranslation)?e.postTranslation:void 0,d=Me.isString(e.warnHtmlInMessage)?e.warnHtmlInMessage!=="off":!0,p=!!e.escapeParameterHtml,m=Me.isBoolean(e.sync)?e.sync:!0;let v=e.messages;if(Me.isPlainObject(e.sharedMessages)){const w=e.sharedMessages;v=Object.keys(w).reduce((E,$)=>{const O=E[$]||(E[$]={});return Me.assign(O,w[$]),E},v||{})}const{__i18n:h,__root:C,__injectWithOption:g}=e,y=e.datetimeFormats,_=e.numberFormats,b=e.flatJson;return{locale:t,fallbackLocale:n,messages:v,flatJson:b,datetimeFormats:y,numberFormats:_,missing:o,missingWarn:r,fallbackWarn:a,fallbackRoot:l,fallbackFormat:s,modifiers:u,pluralRules:c,postTranslation:f,warnHtmlMessage:d,escapeParameter:p,messageResolver:e.messageResolver,inheritLocale:m,__i18n:h,__root:C,__injectWithOption:g}}function Mm(e={},t){{const n=ub(nle(e)),o={id:n.id,get locale(){return n.locale.value},set locale(r){n.locale.value=r},get fallbackLocale(){return n.fallbackLocale.value},set fallbackLocale(r){n.fallbackLocale.value=r},get messages(){return n.messages.value},get datetimeFormats(){return n.datetimeFormats.value},get numberFormats(){return n.numberFormats.value},get availableLocales(){return n.availableLocales},get formatter(){return{interpolate(){return[]}}},set formatter(r){},get missing(){return n.getMissingHandler()},set missing(r){n.setMissingHandler(r)},get silentTranslationWarn(){return Me.isBoolean(n.missingWarn)?!n.missingWarn:n.missingWarn},set silentTranslationWarn(r){n.missingWarn=Me.isBoolean(r)?!r:r},get silentFallbackWarn(){return Me.isBoolean(n.fallbackWarn)?!n.fallbackWarn:n.fallbackWarn},set silentFallbackWarn(r){n.fallbackWarn=Me.isBoolean(r)?!r:r},get modifiers(){return n.modifiers},get formatFallbackMessages(){return n.fallbackFormat},set formatFallbackMessages(r){n.fallbackFormat=r},get postTranslation(){return n.getPostTranslationHandler()},set postTranslation(r){n.setPostTranslationHandler(r)},get sync(){return n.inheritLocale},set sync(r){n.inheritLocale=r},get warnHtmlInMessage(){return n.warnHtmlMessage?"warn":"off"},set warnHtmlInMessage(r){n.warnHtmlMessage=r!=="off"},get escapeParameterHtml(){return n.escapeParameter},set escapeParameterHtml(r){n.escapeParameter=r},get preserveDirectiveContent(){return!0},set preserveDirectiveContent(r){},get pluralizationRules(){return n.pluralRules||{}},__composer:n,t(...r){const[a,l,s]=r,u={};let c=null,f=null;if(!Me.isString(a))throw _n(mn.INVALID_ARGUMENT);const d=a;return Me.isString(l)?u.locale=l:Me.isArray(l)?c=l:Me.isPlainObject(l)&&(f=l),Me.isArray(s)?c=s:Me.isPlainObject(s)&&(f=s),Reflect.apply(n.t,n,[d,c||f||{},u])},rt(...r){return Reflect.apply(n.rt,n,[...r])},tc(...r){const[a,l,s]=r,u={plural:1};let c=null,f=null;if(!Me.isString(a))throw _n(mn.INVALID_ARGUMENT);const d=a;return Me.isString(l)?u.locale=l:Me.isNumber(l)?u.plural=l:Me.isArray(l)?c=l:Me.isPlainObject(l)&&(f=l),Me.isString(s)?u.locale=s:Me.isArray(s)?c=s:Me.isPlainObject(s)&&(f=s),Reflect.apply(n.t,n,[d,c||f||{},u])},te(r,a){return n.te(r,a)},tm(r){return n.tm(r)},getLocaleMessage(r){return n.getLocaleMessage(r)},setLocaleMessage(r,a){n.setLocaleMessage(r,a)},mergeLocaleMessage(r,a){n.mergeLocaleMessage(r,a)},d(...r){return Reflect.apply(n.d,n,[...r])},getDateTimeFormat(r){return n.getDateTimeFormat(r)},setDateTimeFormat(r,a){n.setDateTimeFormat(r,a)},mergeDateTimeFormat(r,a){n.mergeDateTimeFormat(r,a)},n(...r){return Reflect.apply(n.n,n,[...r])},getNumberFormat(r){return n.getNumberFormat(r)},setNumberFormat(r,a){n.setNumberFormat(r,a)},mergeNumberFormat(r,a){n.mergeNumberFormat(r,a)},getChoiceIndex(r,a){return-1},__onComponentInstanceCreated(r){const{componentInstanceCreatedListener:a}=e;a&&a(r,o)}};return o}}const cb={tag:{type:[String,Object]},locale:{type:String},scope:{type:String,validator:e=>e==="parent"||e==="global",default:"parent"},i18n:{type:Object}};function ole({slots:e},t){return t.length===1&&t[0]==="default"?(e.default?e.default():[]).reduce((o,r)=>o=[...o,...Me.isArray(r.children)?r.children:[r]],[]):t.reduce((n,o)=>{const r=e[o];return r&&(n[o]=r()),n},{})}function d$(e){return Rt.Fragment}const Am={name:"i18n-t",props:Me.assign({keypath:{type:String,required:!0},plural:{type:[Number,String],validator:e=>Me.isNumber(e)||!isNaN(e)}},cb),setup(e,t){const{slots:n,attrs:o}=t,r=e.i18n||Wf({useScope:e.scope,__useComponent:!0});return()=>{const a=Object.keys(n).filter(d=>d!=="_"),l={};e.locale&&(l.locale=e.locale),e.plural!==void 0&&(l.plural=Me.isString(e.plural)?+e.plural:e.plural);const s=ole(t,a),u=r[$m](e.keypath,s,l),c=Me.assign({},o),f=Me.isString(e.tag)||Me.isObject(e.tag)?e.tag:d$();return Rt.h(f,c,u)}}};function rle(e){return Me.isArray(e)&&!Me.isString(e[0])}function f$(e,t,n,o){const{slots:r,attrs:a}=t;return()=>{const l={part:!0};let s={};e.locale&&(l.locale=e.locale),Me.isString(e.format)?l.key=e.format:Me.isObject(e.format)&&(Me.isString(e.format.key)&&(l.key=e.format.key),s=Object.keys(e.format).reduce((p,m)=>n.includes(m)?Me.assign({},p,{[m]:e.format[m]}):p,{}));const u=o(e.value,l,s);let c=[l.key];Me.isArray(u)?c=u.map((p,m)=>{const v=r[p.type],h=v?v({[p.type]:p.value,index:m,parts:u}):[p.value];return rle(h)&&(h[0].key=`${p.type}-${m}`),h}):Me.isString(u)&&(c=[u]);const f=Me.assign({},a),d=Me.isString(e.tag)||Me.isObject(e.tag)?e.tag:d$();return Rt.h(d,f,c)}}const Pm={name:"i18n-n",props:Me.assign({value:{type:Number,required:!0},format:{type:[String,Object]}},cb),setup(e,t){const n=e.i18n||Wf({useScope:"parent",__useComponent:!0});return f$(e,t,It.NUMBER_FORMAT_OPTIONS_KEYS,(...o)=>n[Nm](...o))}},Rm={name:"i18n-d",props:Me.assign({value:{type:[Number,Date],required:!0},format:{type:[String,Object]}},cb),setup(e,t){const n=e.i18n||Wf({useScope:"parent",__useComponent:!0});return f$(e,t,It.DATETIME_FORMAT_OPTIONS_KEYS,(...o)=>n[Om](...o))}};function ale(e,t){const n=e;if(e.mode==="composition")return n.__getInstance(t)||e.global;{const o=n.__getInstance(t);return o!=null?o.__composer:e.global.__composer}}function p$(e){const t=l=>{const{instance:s,modifiers:u,value:c}=l;if(!s||!s.$)throw _n(mn.UNEXPECTED_ERROR);const f=ale(e,s.$),d=iw(c);return[Reflect.apply(f.t,f,[...uw(d)]),f]};return{created:(l,s)=>{const[u,c]=t(s);Me.inBrowser&&e.global===c&&(l.__i18nWatcher=Rt.watch(c.locale,()=>{s.instance&&s.instance.$forceUpdate()})),l.__composer=c,l.textContent=u},unmounted:l=>{Me.inBrowser&&l.__i18nWatcher&&(l.__i18nWatcher(),l.__i18nWatcher=void 0,delete l.__i18nWatcher),l.__composer&&(l.__composer=void 0,delete l.__composer)},beforeUpdate:(l,{value:s})=>{if(l.__composer){const u=l.__composer,c=iw(s);l.textContent=Reflect.apply(u.t,u,[...uw(c)])}},getSSRProps:l=>{const[s]=t(l);return{textContent:s}}}}function iw(e){if(Me.isString(e))return{path:e};if(Me.isPlainObject(e)){if(!("path"in e))throw _n(mn.REQUIRED_VALUE,"path");return e}else throw _n(mn.INVALID_VALUE)}function uw(e){const{path:t,locale:n,args:o,choice:r,plural:a}=e,l={},s=o||{};return Me.isString(n)&&(l.locale=n),Me.isNumber(r)&&(l.plural=r),Me.isNumber(a)&&(l.plural=a),[t,s,l]}function lle(e,t,...n){const o=Me.isPlainObject(n[0])?n[0]:{},r=!!o.useI18nComponentName;(Me.isBoolean(o.globalInstall)?o.globalInstall:!0)&&(e.component(r?"i18n":Am.name,Am),e.component(Pm.name,Pm),e.component(Rm.name,Rm)),e.directive("t",p$(t))}function sle(e,t,n){return{beforeCreate(){const o=Rt.getCurrentInstance();if(!o)throw _n(mn.UNEXPECTED_ERROR);const r=this.$options;if(r.i18n){const a=r.i18n;r.__i18n&&(a.__i18n=r.__i18n),a.__root=t,this===this.$root?this.$i18n=cw(e,a):(a.__injectWithOption=!0,this.$i18n=Mm(a))}else r.__i18n?this===this.$root?this.$i18n=cw(e,r):this.$i18n=Mm({__i18n:r.__i18n,__injectWithOption:!0,__root:t}):this.$i18n=e;r.__i18nGlobal&&c$(t,r,r),e.__onComponentInstanceCreated(this.$i18n),n.__setInstance(o,this.$i18n),this.$t=(...a)=>this.$i18n.t(...a),this.$rt=(...a)=>this.$i18n.rt(...a),this.$tc=(...a)=>this.$i18n.tc(...a),this.$te=(a,l)=>this.$i18n.te(a,l),this.$d=(...a)=>this.$i18n.d(...a),this.$n=(...a)=>this.$i18n.n(...a),this.$tm=a=>this.$i18n.tm(a)},mounted(){},unmounted(){const o=Rt.getCurrentInstance();if(!o)throw _n(mn.UNEXPECTED_ERROR);delete this.$t,delete this.$rt,delete this.$tc,delete this.$te,delete this.$d,delete this.$n,delete this.$tm,n.__deleteInstance(o),delete this.$i18n}}}function cw(e,t){e.locale=t.locale||e.locale,e.fallbackLocale=t.fallbackLocale||e.fallbackLocale,e.missing=t.missing||e.missing,e.silentTranslationWarn=t.silentTranslationWarn||e.silentFallbackWarn,e.silentFallbackWarn=t.silentFallbackWarn||e.silentFallbackWarn,e.formatFallbackMessages=t.formatFallbackMessages||e.formatFallbackMessages,e.postTranslation=t.postTranslation||e.postTranslation,e.warnHtmlInMessage=t.warnHtmlInMessage||e.warnHtmlInMessage,e.escapeParameterHtml=t.escapeParameterHtml||e.escapeParameterHtml,e.sync=t.sync||e.sync,e.__composer[i$](t.pluralizationRules||e.pluralizationRules);const n=jf(e.locale,{messages:t.messages,__i18n:t.__i18n});return Object.keys(n).forEach(o=>e.mergeLocaleMessage(o,n[o])),t.datetimeFormats&&Object.keys(t.datetimeFormats).forEach(o=>e.mergeDateTimeFormat(o,t.datetimeFormats[o])),t.numberFormats&&Object.keys(t.numberFormats).forEach(o=>e.mergeNumberFormat(o,t.numberFormats[o])),e}const h$=Me.makeSymbol("global-vue-i18n");function ile(e={},t){const n=Me.isBoolean(e.legacy)?e.legacy:!0,o=Me.isBoolean(e.globalInjection)?e.globalInjection:!0,r=n?!!e.allowComposition:!0,a=new Map,[l,s]=cle(e,n),u=Me.makeSymbol("");function c(p){return a.get(p)||null}function f(p,m){a.set(p,m)}function d(p){a.delete(p)}{const p={get mode(){return n?"legacy":"composition"},get allowComposition(){return r},async install(m,...v){m.__VUE_I18N_SYMBOL__=u,m.provide(m.__VUE_I18N_SYMBOL__,p),!n&&o&&yle(m,p.global),lle(m,p,...v),n&&m.mixin(sle(s,s.__composer,p));const h=m.unmount;m.unmount=()=>{p.dispose(),h()}},get global(){return s},dispose(){l.stop()},__instances:a,__getInstance:c,__setInstance:f,__deleteInstance:d};return p}}function Wf(e={}){const t=Rt.getCurrentInstance();if(t==null)throw _n(mn.MUST_BE_CALL_SETUP_TOP);if(!t.isCE&&t.appContext.app!=null&&!t.appContext.app.__VUE_I18N_SYMBOL__)throw _n(mn.NOT_INSLALLED);const n=dle(t),o=ple(n),r=tle(t),a=fle(e,r);if(n.mode==="legacy"&&!e.__useComponent){if(!n.allowComposition)throw _n(mn.NOT_AVAILABLE_IN_LEGACY_MODE);return vle(t,a,o,e)}if(a==="global")return c$(o,e,r),o;if(a==="parent"){let u=hle(n,t,e.__useComponent);return u==null&&(u=o),u}const l=n;let s=l.__getInstance(t);if(s==null){const u=Me.assign({},e);"__i18n"in r&&(u.__i18n=r.__i18n),o&&(u.__root=o),s=ub(u),mle(l,t),l.__setInstance(t,s)}return s}const ule=e=>{if(!(ele in e))throw _n(mn.NOT_COMPATIBLE_LEGACY_VUE_I18N);return e};function cle(e,t,n){const o=Rt.effectScope();{const r=t?o.run(()=>Mm(e)):o.run(()=>ub(e));if(r==null)throw _n(mn.UNEXPECTED_ERROR);return[o,r]}}function dle(e){{const t=Rt.inject(e.isCE?h$:e.appContext.app.__VUE_I18N_SYMBOL__);if(!t)throw _n(e.isCE?mn.NOT_INSLALLED_WITH_PROVIDE:mn.UNEXPECTED_ERROR);return t}}function fle(e,t){return Me.isEmptyObject(e)?"__i18n"in t?"local":"global":e.useScope?e.useScope:"local"}function ple(e){return e.mode==="composition"?e.global:e.global.__composer}function hle(e,t,n=!1){let o=null;const r=t.root;let a=t.parent;for(;a!=null;){const l=e;if(e.mode==="composition")o=l.__getInstance(a);else{const s=l.__getInstance(a);s!=null&&(o=s.__composer,n&&o&&!o[u$]&&(o=null))}if(o!=null||r===a)break;a=a.parent}return o}function mle(e,t,n){Rt.onMounted(()=>{},t),Rt.onUnmounted(()=>{e.__deleteInstance(t)},t)}function vle(e,t,n,o={}){const r=t==="local",a=Rt.shallowRef(null);if(r&&e.proxy&&!(e.proxy.$options.i18n||e.proxy.$options.__i18n))throw _n(mn.MUST_DEFINE_I18N_OPTION_IN_ALLOW_COMPOSITION);const l=Me.isBoolean(o.inheritLocale)?o.inheritLocale:!0,s=Rt.ref(r&&l?n.locale.value:Me.isString(o.locale)?o.locale:It.DEFAULT_LOCALE),u=Rt.ref(r&&l?n.fallbackLocale.value:Me.isString(o.fallbackLocale)||Me.isArray(o.fallbackLocale)||Me.isPlainObject(o.fallbackLocale)||o.fallbackLocale===!1?o.fallbackLocale:s.value),c=Rt.ref(jf(s.value,o)),f=Rt.ref(Me.isPlainObject(o.datetimeFormats)?o.datetimeFormats:{[s.value]:{}}),d=Rt.ref(Me.isPlainObject(o.numberFormats)?o.numberFormats:{[s.value]:{}}),p=r?n.missingWarn:Me.isBoolean(o.missingWarn)||Me.isRegExp(o.missingWarn)?o.missingWarn:!0,m=r?n.fallbackWarn:Me.isBoolean(o.fallbackWarn)||Me.isRegExp(o.fallbackWarn)?o.fallbackWarn:!0,v=r?n.fallbackRoot:Me.isBoolean(o.fallbackRoot)?o.fallbackRoot:!0,h=!!o.fallbackFormat,C=Me.isFunction(o.missing)?o.missing:null,g=Me.isFunction(o.postTranslation)?o.postTranslation:null,y=r?n.warnHtmlMessage:Me.isBoolean(o.warnHtmlMessage)?o.warnHtmlMessage:!0,_=!!o.escapeParameter,b=r?n.modifiers:Me.isPlainObject(o.modifiers)?o.modifiers:{},w=o.pluralRules||r&&n.pluralRules;function S(){return[s.value,u.value,c.value,f.value,d.value]}const E=Rt.computed({get:()=>a.value?a.value.locale.value:s.value,set:z=>{a.value&&(a.value.locale.value=z),s.value=z}}),$=Rt.computed({get:()=>a.value?a.value.fallbackLocale.value:u.value,set:z=>{a.value&&(a.value.fallbackLocale.value=z),u.value=z}}),O=Rt.computed(()=>a.value?a.value.messages.value:c.value),A=Rt.computed(()=>f.value),M=Rt.computed(()=>d.value);function D(){return a.value?a.value.getPostTranslationHandler():g}function U(z){a.value&&a.value.setPostTranslationHandler(z)}function j(){return a.value?a.value.getMissingHandler():C}function W(z){a.value&&a.value.setMissingHandler(z)}function L(z){return S(),z()}function P(...z){return a.value?L(()=>Reflect.apply(a.value.t,null,[...z])):L(()=>"")}function x(...z){return a.value?Reflect.apply(a.value.rt,null,[...z]):""}function I(...z){return a.value?L(()=>Reflect.apply(a.value.d,null,[...z])):L(()=>"")}function H(...z){return a.value?L(()=>Reflect.apply(a.value.n,null,[...z])):L(()=>"")}function G(z){return a.value?a.value.tm(z):{}}function J(z,Z){return a.value?a.value.te(z,Z):!1}function ee(z){return a.value?a.value.getLocaleMessage(z):{}}function fe(z,Z){a.value&&(a.value.setLocaleMessage(z,Z),c.value[z]=Z)}function Te(z,Z){a.value&&a.value.mergeLocaleMessage(z,Z)}function oe(z){return a.value?a.value.getDateTimeFormat(z):{}}function ke(z,Z){a.value&&(a.value.setDateTimeFormat(z,Z),f.value[z]=Z)}function ae(z,Z){a.value&&a.value.mergeDateTimeFormat(z,Z)}function Oe(z){return a.value?a.value.getNumberFormat(z):{}}function we(z,Z){a.value&&(a.value.setNumberFormat(z,Z),d.value[z]=Z)}function ge(z,Z){a.value&&a.value.mergeNumberFormat(z,Z)}const q={get id(){return a.value?a.value.id:-1},locale:E,fallbackLocale:$,messages:O,datetimeFormats:A,numberFormats:M,get inheritLocale(){return a.value?a.value.inheritLocale:l},set inheritLocale(z){a.value&&(a.value.inheritLocale=z)},get availableLocales(){return a.value?a.value.availableLocales:Object.keys(c.value)},get modifiers(){return a.value?a.value.modifiers:b},get pluralRules(){return a.value?a.value.pluralRules:w},get isGlobal(){return a.value?a.value.isGlobal:!1},get missingWarn(){return a.value?a.value.missingWarn:p},set missingWarn(z){a.value&&(a.value.missingWarn=z)},get fallbackWarn(){return a.value?a.value.fallbackWarn:m},set fallbackWarn(z){a.value&&(a.value.missingWarn=z)},get fallbackRoot(){return a.value?a.value.fallbackRoot:v},set fallbackRoot(z){a.value&&(a.value.fallbackRoot=z)},get fallbackFormat(){return a.value?a.value.fallbackFormat:h},set fallbackFormat(z){a.value&&(a.value.fallbackFormat=z)},get warnHtmlMessage(){return a.value?a.value.warnHtmlMessage:y},set warnHtmlMessage(z){a.value&&(a.value.warnHtmlMessage=z)},get escapeParameter(){return a.value?a.value.escapeParameter:_},set escapeParameter(z){a.value&&(a.value.escapeParameter=z)},t:P,getPostTranslationHandler:D,setPostTranslationHandler:U,getMissingHandler:j,setMissingHandler:W,rt:x,d:I,n:H,tm:G,te:J,getLocaleMessage:ee,setLocaleMessage:fe,mergeLocaleMessage:Te,getDateTimeFormat:oe,setDateTimeFormat:ke,mergeDateTimeFormat:ae,getNumberFormat:Oe,setNumberFormat:we,mergeNumberFormat:ge};function B(z){z.locale.value=s.value,z.fallbackLocale.value=u.value,Object.keys(c.value).forEach(Z=>{z.mergeLocaleMessage(Z,c.value[Z])}),Object.keys(f.value).forEach(Z=>{z.mergeDateTimeFormat(Z,f.value[Z])}),Object.keys(d.value).forEach(Z=>{z.mergeNumberFormat(Z,d.value[Z])}),z.escapeParameter=_,z.fallbackFormat=h,z.fallbackRoot=v,z.fallbackWarn=m,z.missingWarn=p,z.warnHtmlMessage=y}return Rt.onBeforeMount(()=>{if(e.proxy==null||e.proxy.$i18n==null)throw _n(mn.NOT_AVAILABLE_COMPOSITION_IN_LEGACY);const z=a.value=e.proxy.$i18n.__composer;t==="global"?(s.value=z.locale.value,u.value=z.fallbackLocale.value,c.value=z.messages.value,f.value=z.datetimeFormats.value,d.value=z.numberFormats.value):r&&B(z)}),q}const gle=["locale","fallbackLocale","availableLocales"],ble=["t","rt","d","n","tm"];function yle(e,t){const n=Object.create(null);gle.forEach(o=>{const r=Object.getOwnPropertyDescriptor(t,o);if(!r)throw _n(mn.UNEXPECTED_ERROR);const a=Rt.isRef(r.value)?{get(){return r.value.value},set(l){r.value.value=l}}:{get(){return r.get&&r.get()}};Object.defineProperty(n,o,a)}),e.config.globalProperties.$i18n=n,ble.forEach(o=>{const r=Object.getOwnPropertyDescriptor(t,o);if(!r||!r.value)throw _n(mn.UNEXPECTED_ERROR);Object.defineProperty(e.config.globalProperties,`$${o}`,r)})}It.registerMessageCompiler(It.compileToFunction);It.registerMessageResolver(It.resolveValue);It.registerLocaleFallbacker(It.fallbackWithLocaleChain);Pr.DatetimeFormat=Rm;Pr.I18nInjectionKey=h$;Pr.NumberFormat=Pm;Pr.Translation=Am;Pr.VERSION=l$;Pr.castToVueI18n=ule;var wle=Pr.createI18n=ile,Bl=Pr.useI18n=Wf;Pr.vTDirective=p$;var _le={name:"zh-cn",el:{breadcrumb:{label:"面包屑"},colorpicker:{confirm:"确定",clear:"清空"},datepicker:{now:"此刻",today:"今天",cancel:"取消",clear:"清空",confirm:"确定",selectDate:"选择日期",selectTime:"选择时间",startDate:"开始日期",startTime:"开始时间",endDate:"结束日期",endTime:"结束时间",prevYear:"前一年",nextYear:"后一年",prevMonth:"上个月",nextMonth:"下个月",year:"年",month1:"1 月",month2:"2 月",month3:"3 月",month4:"4 月",month5:"5 月",month6:"6 月",month7:"7 月",month8:"8 月",month9:"9 月",month10:"10 月",month11:"11 月",month12:"12 月",weeks:{sun:"日",mon:"一",tue:"二",wed:"三",thu:"四",fri:"五",sat:"六"},months:{jan:"一月",feb:"二月",mar:"三月",apr:"四月",may:"五月",jun:"六月",jul:"七月",aug:"八月",sep:"九月",oct:"十月",nov:"十一月",dec:"十二月"}},select:{loading:"加载中",noMatch:"无匹配数据",noData:"无数据",placeholder:"请选择"},cascader:{noMatch:"无匹配数据",loading:"加载中",placeholder:"请选择",noData:"暂无数据"},pagination:{goto:"前往",pagesize:"条/页",total:"共 {total} 条",pageClassifier:"页",page:"页",prev:"上一页",next:"下一页",currentPage:"第 {pager} 页",prevPages:"向前 {pager} 页",nextPages:"向后 {pager} 页",deprecationWarning:"你使用了一些已被废弃的用法,请参考 el-pagination 的官方文档"},messagebox:{title:"提示",confirm:"确定",cancel:"取消",error:"输入的数据不合法!"},upload:{deleteTip:"按 delete 键可删除",delete:"删除",preview:"查看图片",continue:"继续上传"},table:{emptyText:"暂无数据",confirmFilter:"筛选",resetFilter:"重置",clearFilter:"全部",sumText:"合计"},tour:{next:"下一步",previous:"上一步",finish:"结束导览"},tree:{emptyText:"暂无数据"},transfer:{noMatch:"无匹配数据",noData:"无数据",titles:["列表 1","列表 2"],filterPlaceholder:"请输入搜索内容",noCheckedFormat:"共 {total} 项",hasCheckedFormat:"已选 {checked}/{total} 项"},image:{error:"加载失败"},pageHeader:{title:"返回"},popconfirm:{confirmButtonText:"确定",cancelButtonText:"取消"},carousel:{leftArrow:"上一张幻灯片",rightArrow:"下一张幻灯片",indicator:"幻灯片切换至索引 {index}"}}};const Cle={"Install BuildAdmin":"安装 BuildAdmin","Environmental inspection":"环境检查","Checking installation environment":"正在检查安装环境","Current execution to:":"当前执行到:","Step 2 site configuration":"第二步 站点配置","Environmental inspection passed":"环境检查通过","This environmental check failed":"此项环境检查未通过","The environment check failed, but the installation can continue":"环境检查为失败/未确认,但可以继续安装","Basic environment":"基础环境","NPM correlation":"NPM相关","Test npm install":"测试 npm install","Check complete":"检查完成","Congratulations, the installation can continue~":"恭喜,安装可以继续~","Sorry, the necessary installation environment conditions have not been met, please check the above form!":"抱歉,有必要的安装环境条件没有达成,请检查以上表格!","Network Timeout":"网络超时","Network connection error":"网络连接错误","The interface path cannot be found":"接口路径找不到了(404):{url}","unknown error":"未知错误",executing:"",php_version:"PHP 版本",config_is_writable:"配置目录是否可写",public_is_writable:"public 目录是否可写",php_pdo:"PHP pdo_mysql 扩展",php_safe_mode:"PHP安全模式",php_proc:"PHP 程序执行函数(proc)",php_gd2:"PHP gd2 或 freeType",npm_version:"NPM 版本",npm_package_manager:"包管理器",nodejs_version:"node.js 版本",error:"错误",success:"成功","test-npm-install":"测试 npm install","check npm install":"是否测试命令执行?","set-npm-registry":"设置NPM源","Set NPM source":"设置NPM源","Use current source":"使用当前源",recommend:"(推荐)",TaoBao:"淘宝",Tencent:"腾讯","Click to test":"点击进行测试","Can execute":"可以执行","Command execution test failed":"命令执行测试失败","PM is ready!":"npm包管理器已经准备好了!","already installed":"已安装","The installation can continue, and some operations need to be completed manually":"可以继续安装,部分操作需手动完成","Sorry, the automatic installation of package manager failed. Please complete the installation manually!":"抱歉,自动安装包管理器失败,请手动完成安装!","Click to see how to solve it":"点击查看如何解决","How to solve":"如何解决",terminal:"终端",narrow:"缩小",Connecting:"连接中...","No command":"无命令",executed:" 已执行","Waiting for execution":" 等待执行","Connection successful, executing":"连接成功 正在执行 ","Unfinished matters manually":"手动完成未尽事宜","Open terminal (windows PowerShell)":"打开您PC/服务器的终端(Windows PowerShell、cmd等)","Execute command":"执行命令","Execution failed?":"执行失败了?","Move the built file to the specified location of the system":"移动构建好的文件到系统指定位置","Click to try to automatically move the build file":"点击尝试自动移动构建文件","The build output directory is: site":"构建输出目录为:站点","root directory / dist":"根目录/web/dist","You can delete the build output directory directly":"您可以直接删除构建输出目录","Getting full path of root directory / Web":"正在获取 根目录/web 的完整路径","Moving automatically":"正在自动移动...","Please move 1":"请移动构建输出目录中的","Please move 2":"文件夹和","Please move 3":"文件到根目录的","Please move 4":"目录下","During construction, all files in the output directory will be overwritten, so the system is designed to build in the root directory first, and then move to the public directory to prevent other files in the public from being overwritten":"构建时,会覆盖输出目录的所有文件,所以系统设计为先构建,然后移动到public目录,以免public内的其他文件被覆盖掉","Thanks for using buildadmin":"感谢使用 BuildAdmin","Background URL":"后台地址","Access foreground":"访问前台","Access background":"访问后台","Install Tips Title 1":"安装环境检测并没有完全通过,但安装可以继续,只是您后续需要手动进行一些操作,建议您","Install Tips Title 2":",在所有检测通过后再安装,以便您体验到 BuildAdmin 的核心功能之一。","Back to previous page":"回到上一页","If you don't want to open the corresponding permission due to some security factors, please check ":"如果你考虑到一些安全因素而不愿开启相应权限,请查看","how installation services ensure system security":"安装服务如何保障系统安全","If you really can't adjust all the tests to pass, please ":"如果您确实无法将所有检测调整到通过状态,请","click to feed back to us":"点击向我们反馈","continue installation":",并继续安装,安装程序后续将引导您,如何手动完成未尽事宜。","Close the prompt of completing unfinished matters manually":"关闭手动完成未尽事宜提示","Test connection to data server":"测试连接数据服务器...","Install now":"立即安装","Mysql database address":"MySQL 数据库地址","MySQL connection user name":"MySQL 连接用户名","MySQL connection password":"MySQL 连接密码","MySQL connection port number":"MySQL 连接端口号","Mysql database name":"MySQL 数据库名","MySQL data table prefix":"MySQL 数据表前缀","Administrator user name":"管理员用户名","Administrator password":"管理员密码","Duplicate administrator password":"重复管理员密码","Site name":"站点名称","Site configuration":"站点配置","The entered database was not found!":"数据表不存在,安装时将自动建立!","Duplicate passwords do not match":"重复密码不匹配","Command execution failed":"命令执行失败",Installing:"正在安装...","After installation, please complete the unfinished matters manually":"安装完成,请手动完成未尽事宜","Automatically executing the build command on the web side":"正在自动执行 WEB端的 构建命令","Installation complete":"安装完成...","The table prefix can only contain alphanumeric characters and underscores, and starts with a letter":"表前缀只能包含字母数字和下划线,并以字母开头","Manual Install 1":"命令自动执行失败,请手动完成未尽事宜,","Manual Install 2":"{seconds}秒 后自动跳转到操作引导页面...",Retry:"重试",delete:"删除",Confirm:"确认",Cancel:"取消","Request timeout!":"请求超时!","Server internal error!":"服务器内部错误!","The service is temporarily unavailable. Please try again later!":"服务暂时无法访问,请稍后再试!","Abnormal problem, please contact the website administrator!":"异常问题,请联系网站管理员!","You're disconnected!":"您断网了!",Required:"必填","Please enter the correct password":`密码要求6到32位,不能包含 & < > " '`,"It is composed of letters, numbers and underscores, starting with letters (3-15 digits)":"由字母、数字、下划线组成,以字母开头(3-15位)","It is recommended to delete the root directory / public / install folder; This page is only visible on your device.":"建议删除: 根目录/public/install 文件夹;本页仅在您的设备上可见。","Switch package manager":"切换包管理器","Please select package manager":"请选择包管理器","Switch package manager title":"只读WEB终端,可以在CRUD等操作后方便的执行 npm install、npm build 等命令,请在下方选择一个已安装好或您喜欢的的 NPM 包管理器","I want to execute the command manually":"我想手动执行命令",Reminder:"温馨提醒","Ready to start":"准备开始",language:"语言","NPM package manager":"NPM包管理器","The system has a Web terminal. Please select an installed or your favorite NPM package manager":"系统拥有WEB终端,请选择一个已安装好或您喜欢的的NPM包管理器","Start installation":"开始安装","Setup will restart. Are you sure you want to switch package manager?":"将重新开始安装程序,请确定要切换包管理器吗?","None - manual execution":"无-手动执行","Previous step":"上一步","Hide index.html?":"隐藏 index.html?","Sorry, some operations could not be completed automatically You need to manually complete the outstanding matters according to the following guidance":"抱歉,一些操作未能自动完成,需要您根据以下引导手动完成未尽事宜。","Need to reinstall the system?":"需重新安装系统?","Please click on me":"请点击我","Backend login password":"后台登录密码","Port error prompt 1":"当前安装程序站点的端口不是8000,您可能以错误的方式启动了安装服务,请参考","Get started quickly":"快速上手文档","Port error prompt 3":"进行安装。","Table migration failed":"数据表迁移失败","We use Phinx to manage the data table, which can version the data table":"我们使用`Phinx`管理数据表,它可以对数据表进行版本化管理。","Data table automatic migration failed, please manually migrate as follows:":"数据表自动迁移失败了,请按以下方法手动迁移:","If the command fails to be executed, add sudo or press the error message":"若命令执行失败,请尝试加 sudo,或按报错解决即可","Migration check":"迁移检查","When the command is executed successfully, the output is similar to:":"命令执行成功时,输出类似于:","After the command is executed successfully, multiple data tables will be automatically created in the database, and then click below to ":"命令执行成功后,数据库内将自动建立多个数据表,然后请您点击下方的","continue install":"继续安装"},Sle={"Install BuildAdmin":"Install BuildAdmin","Environmental inspection":"Environmental inspection","Checking installation environment":"Checking the installation environment","Current execution to:":"Current execution to:","Step 2 site configuration":"Step 2 site configuration","Environmental inspection passed":"Environmental inspection passed","This environmental check failed":"This environmental inspection was not passed.","The environment check failed, but the installation can continue":"Environment check failed/unconfirmed, but you can continue to install.","Basic environment":"Basic Environment","NPM correlation":"NPM correlation","Test npm install":"Test npm install","Check complete":"Check complete","Congratulations, the installation can continue~":"Congratulations, the installation can continue~","Sorry, the necessary installation environment conditions have not been met, please check the above form!":"Sorry, the necessary installation environmental conditions have not been met, please check the above form!","Network Timeout":"Network timeout","Network connection error":"Network connection error","The interface path cannot be found":"The interface path cannot be found(404):{url}","unknown error":"Unknown error",executing:"",php_version:"PHP Version",config_is_writable:"Is the configuration directory writable?",public_is_writable:"Is the public directory writable?",php_pdo:"PHP pdo_mysql extension",php_safe_mode:"PHP security mode",php_proc:"PHP proc_open and proc_close permission",php_gd2:"PHP gd2 or freeType extensions",npm_version:"NPM Version",npm_package_manager:"NPM package manager",nodejs_version:"node.js Version",error:"error",success:"success","test-npm-install":"Test npm install","check npm install":"Whether to test command execution?","set-npm-registry":"Set NPM source","Set NPM source":"Set NPM source","Use current source":"Use the current source",recommend:"(Recommend)",TaoBao:"TaoBao","Click to test":"Click to test","Can execute":"Can be executed","Command execution test failed":"Command execution test failed","PM is ready!":"The NPM package manager is ready!","already installed":"Already installed","The installation can continue, and some operations need to be completed manually":"You can continue the installation, and some operations need to be completed manually.","Sorry, the automatic installation of package manager failed. Please complete the installation manually!":"Sorry, the automatic installation of the package manager failed. Please complete the installation manually!","Click to see how to solve it":"Click to see how to solve it","How to solve":"How to solve",terminal:"Terminal",narrow:"Narrow",Connecting:"Connecting...","No command":"No command",executed:" Executed","Waiting for execution":" Waiting for execution","Connection successful, executing":"Connection successful, executing ","Unfinished matters manually":"Complete unfinished matters manually","Open terminal (windows PowerShell)":"Open the terminal of your PC/Server (PowerShell, cmd)","Execute command":"Execute the command","Execution failed?":"Failed execution?","Move the built file to the specified location of the system":"Move the built file to the specified location on the system.","Click to try to automatically move the build file":"Click to try to move the build file automatically","The build output directory is: site":"Build the output directory as: site","root directory / dist":"root directory/web/dist","You can delete the build output directory directly":"You can delete the build output directory directly","Getting full path of root directory / Web":"Getting the full path to the root directory/web","Moving automatically":"Moving automatically","Please move 1":"Please move the ","Please move 2":" folder and ","Please move 3":" files from the build output directory to the ","Please move 4":" directory of the root directory.","During construction, all files in the output directory will be overwritten, so the system is designed to build in the root directory first, and then move to the public directory to prevent other files in the public from being overwritten":"When constructing the process, all files in the output directory are overwriting, so the system is designed to build first and then move to the public directory to prevent overwriting other files in the public directory","Thanks for using buildadmin":"Thanks for using BuildAdmin","Background URL":"Background URL","Access foreground":"Access to the foreground","Access background":"Access to the background","Install Tips Title 1":"The installation environment test does not completely passed, but the installation can continue, and you need to do some manual operations to see how to modify it.It is recommended that you go ","Install Tips Title 2":" and install it after all the tests have passed so that you can experience one of the core functions of BuildAdmin.","Back to previous page":"back to previous page","If you don't want to open the corresponding permission due to some security factors, please check ":"If you don't want to open the corresponding permission due to some security factors, please check ","how installation services ensure system security":"how installation services ensure system security","If you really can't adjust all the tests to pass, please ":"If you really can't adjust all the tests to pass, please ","click to feed back to us":"click to feed back to us","continue installation":" and continue the installation. The subsequent installation program will guide you on how to manually complete the outstanding matters.","Close the prompt of completing unfinished matters manually":"Close the prompt of completing unfinished matters manually","Test connection to data server":"Test connection to data server","Install now":"Install now","Mysql database address":"Mysql database address","MySQL connection user name":"MySQL connection username","MySQL connection password":"MySQL connection password","MySQL connection port number":"MySQL connection port number","Mysql database name":"Mysql database name","MySQL data table prefix":"MySQL data table prefix","Administrator user name":"Administrator username","Administrator password":"Administrator password","Duplicate administrator password":"Duplicate administrator password","Site name":"Site Name","Site configuration":"Site Configuration","The entered database was not found!":"The data table does not exist and will be created automatically during installation","Duplicate passwords do not match":"Duplicate passwords mismatch","Command execution failed":"Command execution failed",Installing:"Installing","After installation, please complete the unfinished matters manually":"Installation is complete, please complete the unfinished matters manually.","Automatically executing the build command on the web side":"Automatically executing the build command on the web side","Installation complete":"Installation completed","The table prefix can only contain alphanumeric characters and underscores, and starts with a letter":"The table prefix can only contain alphanumeric characters and underscores, and starts with letters","Manual Install 1":"Failed to execute Command automatically. Please complete the unfinished matters manually.","Manual Install 2":"Automatically jump to the operation boot page after {seconds} seconds...",Retry:"Retry",delete:"Delete",Confirm:"Confirm",Cancel:"Cancel","Request timeout!":"Request timeout!","Server internal error!":"Internal server error!","The service is temporarily unavailable. Please try again later!":"The service is temporarily unavailable. Please try again later!","Abnormal problem, please contact the website administrator!":"Abnormal problem, please contact the website administrator!","You're disconnected!":"You're disconnected!",Required:"Required","Please enter the correct password":`The password requires 6 to 32 bits and cannot contain & < > " '`,"It is composed of letters, numbers and underscores, starting with letters (3-15 digits)":"Composed of letters, numbers and underscores, start with letters (3-15 digits)","It is recommended to delete the root directory / public / install folder; This page is only visible on your device.":"It is recommended to delete the root directory / public / install folder; This page is only visible on your device.","Switch package manager":"Switch package manager","Please select package manager":"Please select the package manager","Switch package manager title":"Read-only Web terminal, you can easily execute NPM install, NPM builds, and other commands after crud and other operations. Please select an installed or your favorite NPM package manager below","I want to execute the command manually":"I want to execute the command manually",Reminder:"Reminder","Ready to start":"Ready to start",language:"Language","NPM package manager":"NPM package manager","The system has a Web terminal. Please select an installed or your favorite NPM package manager":"The system has a Web terminal. Please select an installed or your favorite NPM package manager","Start installation":"Start installation","Setup will restart. Are you sure you want to switch package manager?":"The install will restart. Are you sure you want to switch the package manager?","None - manual execution":"None - manual execution","Previous step":"Previous step","Hide index.html?":"Hide index.html?","Sorry, some operations could not be completed automatically You need to manually complete the outstanding matters according to the following guidance":"Sorry, some operations could not be completed automatically. You need to outstanding matters according to the following guidance manually.","Need to reinstall the system?":"Need to reinstall the system?","Please click on me":"Please click on me","Backend login password":"Backend login password","Port error prompt 1":"The current installation site port is not 8000. You may have started the installation service in the wrong way. Please refer to the","Get started quickly":" Quick Start documentation ","Port error prompt 3":" for installation.","Table migration failed":"Table migration failed","We use Phinx to manage the data table, which can version the data table":"We use 'Phinx' to manage the data table, which can version the data table","Data table automatic migration failed, please manually migrate as follows:":"Data table automatic migration failed, please manually migrate as follows:","If the command fails to be executed, add sudo or press the error message":"If the command fails to be executed, add sudo or press the error message","Migration check":"Migration check","When the command is executed successfully, the output is similar to:":"When the command is executed successfully, the output is similar to:","After the command is executed successfully, multiple data tables will be automatically created in the database, and then click below to ":"After the command is executed successfully, multiple data tables will be automatically created in the database, and then click below to ","continue install":"continue the installation"},dw={"zh-cn":fw(Object.assign({"./pages/zh-cn/terminal.ts":Joe}),"zh-cn"),en:fw(Object.assign({"./pages/en/terminal.ts":Qoe}),"en")},kle={"zh-cn":{...Cle,..._le,...dw["zh-cn"]},en:{...Sle,...oS,...dw.en}},$o=wle({locale:"zh-cn",legacy:!1,fallbackLocale:"en",messages:kle});function fw(e,t){const n={};for(const o in e)if(e[o].default){const r=o.slice(o.lastIndexOf(t)+(t.length+1),o.lastIndexOf("."));if(r.indexOf("/")>0){const a=r.split("/");for(const l in a)typeof n[a[l]]>"u"&&(n[a[l]]=[]);a.length==2?n[a[0]][a[1]]=Ec(e[o].default):a.length==3?n[a[0]][a[1]][a[2]]=Ec(e[o].default):n[r]=Ec(e[o].default)}else n[r]=Ec(e[o].default)}return n}function Ec(e){const t=[];for(const n in e)if(n.indexOf(".")>0){const o=n.split(".");typeof t[o[0]]>"u"?t[o[0]]=[]:t[o[0]][o[1]]=e[n]}else t[n]=e[n];return t}const Ele=window.localStorage.getItem("ba-lang")||"zh-cn",m$=()=>window.location.protocol+"//"+window.location.host,Rr=Nn.create({baseURL:m$(),timeout:1e3*10,headers:{"Content-Type":"application/json","think-lang":Ele}});Rr.interceptors.response.use(e=>e,e=>(Tle(e),Promise.reject(e)));function Tle(e){let t="";if(e&&e.response)switch(e.response.status){case 404:t=$o.global.t("The interface path cannot be found",{url:e.response.config.url});break;case 408:t=$o.global.t("Request timeout!");break;case 500:t=$o.global.t("Server internal error!");break;case 504:t=$o.global.t("The service is temporarily unavailable. Please try again later!");break;default:t=$o.global.t("Abnormal problem, please contact the website administrator!");break}e.message.includes("timeout")&&(t=$o.global.t("Network Timeout")),e.message.includes("Network Error")&&(t=$o.global.t("Network connection error")),e.message.includes("Network")&&(t=window.navigator.onLine?$o.global.t("Abnormal problem, please contact the website administrator!"):$o.global.t("You're disconnected!")),t||(t=$o.global.t("unknown error")),Cr({type:"error",message:t,center:!0})}const na="/index.php",$le=na+"/api/install/envBaseCheck",Ole=na+"/api/install/envNpmCheck",Nle=na+"/api/install/testDatabase",v$=na+"/api/install/baseConfig",Ile=na+"/api/install/commandExecComplete",Mle=na+"/api/install/mvDist",Ale=na+"/api/install/manualInstall",Ple=na+"/api/install/terminal",Rle=na+"/api/install/changePackageManager",Lle=()=>Rr.get($le),xle=()=>{const e=ii();return Rr.post(Ole,{manager:e.state.packageManager})},Dle=e=>Rr.post(Nle,e),Fle=()=>Rr.get(v$),Ble=e=>Rr.post(v$,e),pw=e=>Rr.post(Ile,e).then(t=>{t.data.code!=1&&Cr({type:"error",message:t.data.msg,center:!0})}),Ua=e=>{const t=ii();Rr.post(Rle,{manager:e}).then(n=>{n.data.code==1?t.changePackageManager(n.data.data.manager):n.data.msg&&Cr({type:"error",message:n.data.msg,center:!0})})},Vle=()=>Rr.post(Mle),Hle=()=>Rr.get(Ale),zle=(e,t,n)=>m$()+Ple+"?command="+e+"&uuid="+t+"&extend="+n,gt={Waiting:0,Connecting:1,Executing:2,Success:3,Failed:4,Unknown:5},ju=Y_("common",()=>{const e=Et({step:"check",showStartDialog:!0});function t(o){e.step=o}function n(o){e.showStartDialog=o}return{state:e,setStep:t,toggleStartDialog:n}},{persist:{key:AI}}),ii=Y_("terminal",()=>{const e=Et({show:!1,showDot:!1,taskList:[],packageManager:"pnpm",showPackageManagerDialog:!1});function t(){for(const b in e.taskList)(e.taskList[b].status==gt.Connecting||e.taskList[b].status==gt.Executing)&&(e.taskList[b].status=gt.Unknown)}function n(b=!e.show){e.show=b,b&&o(!1)}function o(b=!e.showDot){e.showDot=b}function r(b=!e.showPackageManagerDialog){n(!b),e.showPackageManagerDialog=b}function a(b){e.packageManager=b}function l(b,w){e.taskList[b]&&(e.taskList[b].status=w,(w==gt.Failed||w==gt.Unknown)&&e.taskList[b].blockOnFailure&&u(b,!0))}function s(b){if(!e.taskList[b]||typeof e.taskList[b].callback!="function")return;const w=e.taskList[b].status;if(w==gt.Failed||w==gt.Unknown)e.taskList[b].callback(gt.Failed,b);else if(w==gt.Success&&(e.taskList[b].callback(gt.Success,b),e.taskList[b].command=="web-build."+e.packageManager)){const S=ju();S.state.step=="manualInstall"&&(n(!1),S.setStep("done"))}}function u(b,w=!e.taskList[b].showMessage){e.taskList[b].showMessage=w}function c(b,w){e.show||o(!0),e.taskList[b].message=e.taskList[b].message.concat(w),We(()=>{_(e.taskList[b].uuid)})}function f(b,w=!0,S="",E=()=>{}){e.show||o(!0),e.taskList=e.taskList.concat({uuid:LI(),createtime:RI(),status:gt.Waiting,command:b,message:[],showMessage:!1,blockOnFailure:w,extend:S,callback:E}),m()}function d(b,w=!0,S="",E=()=>{}){f(b+"."+e.packageManager,w,S,E)}function p(b){e.taskList[b].status!=gt.Connecting&&e.taskList[b].status!=gt.Executing&&e.taskList.splice(b,1),m()}function m(){let b=null;for(const w in e.taskList){if(e.taskList[w].status==gt.Waiting){b=parseInt(w);break}if(e.taskList[w].status==gt.Connecting||e.taskList[w].status==gt.Executing)break;if(e.taskList[w].status!=gt.Success&&(e.taskList[w].status==gt.Failed||e.taskList[w].status==gt.Unknown)){if(e.taskList[w].blockOnFailure)break;continue}}b!==null&&(l(b,gt.Connecting),v(b))}function v(b){window.eventSource=new EventSource(zle(e.taskList[b].command,e.taskList[b].uuid,e.taskList[b].extend)),window.eventSource.onmessage=function(w){const S=JSON.parse(w.data);if(!S||!S.data)return;const E=g(S.uuid);E!==!1&&(S.data=="command-exec-error"?(l(E,gt.Failed),window.eventSource.close(),s(E),m()):S.data=="command-exec-completed"?(window.eventSource.close(),e.taskList[E].status!=gt.Success&&l(E,gt.Failed),s(E),m()):S.data=="command-link-success"?l(E,gt.Executing):S.data=="command-exec-success"?l(E,gt.Success):c(E,S.data))},window.eventSource.onerror=function(){window.eventSource.close();const w=y(b);w!==!1&&(l(w,gt.Failed),s(w))}}function h(b){e.taskList[b].message=[],l(b,gt.Waiting),m()}function C(){e.taskList=e.taskList.filter(b=>b.status!=gt.Success)}function g(b){for(const w in e.taskList)if(e.taskList[w].uuid==b)return parseInt(w);return!1}function y(b){if(e.taskList[b])return b;{let w=-1;for(const S in e.taskList)(e.taskList[S].status==gt.Connecting||e.taskList[S].status==gt.Executing)&&(w=parseInt(S));return w===-1?!1:w}}function _(b){const w=document.querySelector(".exec-message-"+b);w&&w.scrollHeight&&(w.scrollTop=w.scrollHeight)}return{state:e,init:t,toggle:n,toggleDot:o,setTaskStatus:l,setTaskShowMessage:u,addTaskMessage:c,addTask:f,addTaskPM:d,delTask:p,startTask:m,retryTask:h,clearSuccessTask:C,togglePackageManagerDialog:r,changePackageManager:a}},{persist:{key:PI}}),jle={class:"command"},Wle={class:"task-opt"},Kle=["onClick"],Ule={class:"indent-2"},qle={class:"package-manager-dialog-footer"},Yle=Y({__name:"index",setup(e){const{t}=Bl(),n=ii(),o=l=>{let s=t("terminal.unknown"),u="info";switch(l){case gt.Waiting:s=t("terminal.Waiting for execution"),u="info";break;case gt.Connecting:s=t("terminal.Connecting"),u="warning";break;case gt.Executing:s=t("terminal.Executing"),u="warning";break;case gt.Success:s=t("terminal.Successful execution"),u="success";break;case gt.Failed:s=t("terminal.Execution failed"),u="danger";break;case gt.Unknown:s=t("terminal.Unknown execution result"),u="danger";break}return{statusText:s,statusType:u}},r=()=>{bm.confirm(t("terminal.Are you sure you want to republish?"),t("Reminder"),{confirmButtonText:t("Confirm"),cancelButtonText:t("Cancel"),type:"warning"}).then(()=>{n.addTaskPM("web-build")})},a=()=>{bm.confirm(t("Setup will restart. Are you sure you want to switch package manager?"),t("Reminder"),{confirmButtonText:t("Confirm"),cancelButtonText:t("Cancel"),type:"warning"}).then(()=>{window.localStorage.clear(),location.reload()})};return(l,s)=>{const u=qe("el-tag"),c=qe("el-button"),f=qe("el-icon"),d=qe("el-card"),p=qe("el-timeline-item"),m=qe("el-timeline"),v=qe("el-empty"),h=qe("el-button-group"),C=qe("el-dialog"),g=qs("blur");return T(),V(Ve,null,[K(C,mt(l.$attrs,{modelValue:i(n).state.show,"onUpdate:modelValue":s[5]||(s[5]=y=>i(n).state.show=y),title:i(t)("terminal.Terminal")+" - "+i(n).state.packageManager,class:"ba-terminal-dialog","append-to-body":!0,"close-on-click-modal":!1}),{default:X(()=>[i(n).state.taskList.length?(T(),re(m,{key:0},{default:X(()=>[(T(!0),V(Ve,null,bt(i(n).state.taskList,(y,_)=>(T(),re(p,{key:_,class:N(["task-item","task-status-"+y.status]),type:o(y.status).statusType,center:"",timestamp:y.createtime,placement:"top"},{default:X(()=>[K(d,null,{default:X(()=>[F("div",null,[K(u,{type:o(y.status).statusType},{default:X(()=>[Ge(le(o(y.status).statusText),1)]),_:2},1032,["type"]),(y.status==i(gt).Failed||y.status==i(gt).Unknown)&&y.blockOnFailure?(T(),re(u,{key:0,class:"block-on-failure-tag",type:"warning"},{default:X(()=>[Ge(le(i(t)("terminal.Failure to execute this command will block the execution of the queue")),1)]),_:1})):te("",!0),y.status==i(gt).Connecting||y.status==i(gt).Executing?(T(),re(u,{key:1,class:"block-on-failure-tag",type:"danger"},{default:X(()=>[Ge(le(i(t)("terminal.Do not refresh the browser")),1)]),_:1})):te("",!0),F("span",jle,le(y.command),1),F("div",Wle,[y.status==i(gt).Failed||y.status==i(gt).Unknown?tt((T(),re(c,{key:0,title:i(t)("Retry"),size:"small",type:"warning",icon:i(XC),circle:"",onClick:b=>i(n).retryTask(_)},null,8,["title","icon","onClick"])),[[g]]):te("",!0),tt(K(c,{onClick:b=>i(n).delTask(_),title:i(t)("delete"),size:"small",type:"danger",icon:i(YC),circle:""},null,8,["onClick","title","icon"]),[[g]])])]),y.status!=i(gt).Waiting?(T(),V(Ve,{key:0},[y.status!=i(gt).Connecting&&y.status!=i(gt).Executing?(T(),V("div",{key:0,onClick:b=>i(n).setTaskShowMessage(_),class:"toggle-message-display"},[F("span",null,le(i(t)("terminal.Command run log")),1),K(f,{size:"16",color:"#909399"},{default:X(()=>[y.showMessage?(T(),re(i(pf),{key:0})):(T(),re(i(Nr),{key:1}))]),_:2},1024)],8,Kle)):te("",!0),y.status==i(gt).Connecting||y.status==i(gt).Executing||y.status>i(gt).Executing&&y.showMessage?(T(),V("div",{key:1,class:N(["exec-message","exec-message-"+y.uuid])},[(T(!0),V(Ve,null,bt(y.message,(b,w)=>(T(),V("pre",{key:w,class:"message-item"},le(b),1))),128))],2)):te("",!0)],64)):te("",!0)]),_:2},1024)]),_:2},1032,["class","type","timestamp"]))),128))]),_:1})):(T(),re(v,{key:1,"image-size":80,description:i(t)("terminal.No mission yet")},null,8,["description"])),K(h,null,{default:X(()=>[tt((T(),re(c,{class:"terminal-menu-item",onClick:s[0]||(s[0]=y=>i(n).addTaskPM("test",!1))},{default:X(()=>[Ge(le(i(t)("terminal.Test command")),1)]),_:1})),[[g]]),tt((T(),re(c,{class:"terminal-menu-item",onClick:s[1]||(s[1]=y=>i(n).addTaskPM("web-install"))},{default:X(()=>[Ge(le(i(t)("terminal.Install dependent packages")),1)]),_:1})),[[g]]),tt((T(),re(c,{class:"terminal-menu-item",onClick:s[2]||(s[2]=y=>r())},{default:X(()=>[Ge(le(i(t)("terminal.Republish")),1)]),_:1})),[[g]]),tt((T(),re(c,{class:"terminal-menu-item",onClick:s[3]||(s[3]=y=>i(n).addTask("version.npm",!1))},{default:X(()=>[Ge("npm -v")]),_:1})),[[g]]),tt((T(),re(c,{class:"terminal-menu-item",onClick:a},{default:X(()=>[Ge(le(i(t)("Switch package manager")),1)]),_:1})),[[g]]),tt((T(),re(c,{class:"terminal-menu-item",onClick:s[4]||(s[4]=y=>i(n).clearSuccessTask())},{default:X(()=>[Ge(le(i(t)("terminal.Clean up task list")),1)]),_:1})),[[g]])]),_:1})]),_:1},16,["modelValue","title"]),K(C,{onClose:s[12]||(s[12]=y=>i(n).togglePackageManagerDialog(!1)),modelValue:i(n).state.showPackageManagerDialog,"onUpdate:modelValue":s[13]||(s[13]=y=>i(n).state.showPackageManagerDialog=y),class:"ba-terminal-dialog",title:i(t)("Please select package manager"),center:""},{footer:X(()=>[F("div",qle,[K(c,{onClick:s[6]||(s[6]=y=>i(Ua)("npm"))},{default:X(()=>[Ge("npm")]),_:1}),K(c,{onClick:s[7]||(s[7]=y=>i(Ua)("cnpm"))},{default:X(()=>[Ge("cnpm")]),_:1}),K(c,{onClick:s[8]||(s[8]=y=>i(Ua)("pnpm"))},{default:X(()=>[Ge("pnpm")]),_:1}),K(c,{onClick:s[9]||(s[9]=y=>i(Ua)("yarn"))},{default:X(()=>[Ge("yarn")]),_:1}),K(c,{onClick:s[10]||(s[10]=y=>i(Ua)("ni"))},{default:X(()=>[Ge("ni")]),_:1}),K(c,{onClick:s[11]||(s[11]=y=>i(Ua)("none"))},{default:X(()=>[Ge(le(i(t)("I want to execute the command manually")),1)]),_:1})])]),default:X(()=>[F("div",Ule,le(i(t)("Switch package manager title")),1)]),_:1},8,["modelValue","title"])],64)}}}),ui=(e,t)=>{const n=e.__vccOpts||e;for(const[o,r]of t)n[o]=r;return n},Gle=ui(Yle,[["__scopeId","data-v-c55edab5"]]),g$="/install/assets/logo.svg",Xle="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAgMAAADQNkYNAAAACVBMVEUAAADc3eTc3+YFvQraAAAAAnRSTlMA9btEy6sAAAGFSURBVGje7dixbcNAEERR24EBuwSX4CpYimNVoRJYggIF1lTpAr6xPxgo2wkpHMEnUXe7+7LZbDabzWazeVo+/rv4My75Pnjt9XdckpPX3jOteMudF79yHZZ85sGLl9wmSnKAkkyYJCcpyURJ7qQk14GSPEhJbhMlOUCZMEmSk5RkoiR3UAbMa0LMJXxafmy34UOcpPA14ue8i2L4rIbhTQyjFGKUQoxTiFEKMUohRinEOIUYpxDjFGJIUQwphiFFMaQoBhTHkOIYUBwDimNAcQwpjgHFMaA4BhTHgOIYUBwDimNAcQwoggHFMaQ4hhTHkOIYUhxDimNIcczRL+kfzPn9l+w/Zf/C+GvZv/z+F+v/yL5d9JuSb339Bttv435Y9EeSH3z98eqHeF8qeEHSlz1eXPUlnBeKRTnaF71eWvcFvLcJfTPiLU/VWPXtmzeJfSvqDW/fVnvz3o8IfBBRjDv6oYqPbvoBkY+h+mGXj9T6wZ2PB/shpI86N5vNZrPZbDbPyh8nhMFbtczXEQAAAABJRU5ErkJggg==",Jle=Object.freeze(Object.defineProperty({__proto__:null,default:Xle},Symbol.toStringTag,{value:"Module"})),b$="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAgMAAADQNkYNAAAADFBMVEUAAAD2bGz1bGz1bGxNefxdAAAAA3RSTlMAVaoLuSc5AAABi0lEQVRo3u3YwXHCQBBEUeOLy+UgHIJTUCjOBDJzCgqBIDhwQe0APrX/0MVt+ihqVXogdmfmbTKZTCaTyWTysnw+u/i7XPKz8drpvlzyt/Pax7Fa8Z4bL37nsljylQcvnnNdUZINlOS+oiQ7KMmxoiQ3UpLLgpI8SEmuK0qygZLcV5RkByU5VpTkBsoCc0qIOYdPy4/tNnyIHZTwNeLnvIti+KyG4U0MoxRilEKMU4hRCjFKIUYpxDiFGKcQ4xRiSFEMKYYhRTGkKAYUx5DiGFAcA4pjQHEMKY4BxTGgOAYUx4DiGFAcA4pjQHEMKIIBxTGkOIYUx5DiGFIcQ4pjSHHM1i/pH8z5/ZfsP2X/wvhr2b/8/hfr/8i+XfSbkm99/Qbbb+N+WPRHkh98/fHqh3hfKnhB0pc9Xlz1JZwXikU52he9Xlr3Bby3CX0z4i1P1Vj17Zs3iX0r6g1v31Z7896PCHwQUYw7+qGKj276AZGPofphl4/U+sGdjwf7IaSPOieTyWQymUwmr8o/BXYQUa5D7j4AAAAASUVORK5CYII=",Zle=Object.freeze(Object.defineProperty({__proto__:null,default:b$},Symbol.toStringTag,{value:"Module"})),Qle="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAmVBMVEUAAABnwjpmwjlnwjpnwztnwjpnwjpnwjpmwzpowzpnwzlnwTtnwjpnwjpmwjlnwzpnwzpnwjpnwjlnwzpnxDltuTZnwjlnwjpnwzpnwzpnwzpnwjpnwjpnwjpnwjhlwDdixDtnwjpnwzlnwjpnwjlowjpnwjpnwzlnwjpnwjpnwjlmwjpnwjpnwjpnwjpmwTpmwjtnwjlnwjrJKS+EAAAAMnRSTlMA7GidKOfFulROSBng2c5vYVs7Mw8Fv7WqfnX1o0MiEwr61dKwlpOJh3o/LvHKgjYdj7mKH34AAANoSURBVHja7dzpUuJQFATgEwhhR1BAZBdwYRu13//hpqxxSsVziQEh98T+fltSVAHp7nARIiIiIiIiIiIiIiIiIiIiIqJfYdJcIKhH/Y7Y9jTDP9uSWFbBu6bY1ccHg7VYNcInRTFqgh1lsekWO/Ji0ha7ArHoDl9sxKAcvqqLPU9QRGJOB5qlmBNAUW+LNUVoLsSaB2iuxZoWNLOxGBNCM1iJNXhnOsTXobkRaxZ4ZT8u3kDTnYoxZWhqoRjzDFVFrNlAkxNrGtA8iDVDaHpizQU024kYs4JmcyXGtKGyN5QWoOmLNV1o7sWa+4xUqSY0s2cx5goqe1XqFpqWWDNjlfLKY0aqVAmajbkqFWalSgUZqVIRNI9iTVaq1BKambkqVYHKXJWqZqVK1TJyN6eY6SpVlJMbh1P5QRfQBKeuUq1eDcDsfiw/5BKqSzmp6R3eFPo/9B8HaVSpKj7odeQHNM5apfRHvW7L0XrQDOW0cvisODlNlZp35LQi7OhWT7H9IJQTC7ArGssR1qlUKT0RNUI5XCGlKrWCYr6WQ3XTqlJVaOqHZu18OsnE3aprl3KIPjRBW84ggqowkuRKaVapCnRBRZIap1ulltANypJQPeUq1YPutiSJXKc+8g4BHB9XX6CZyznl4dBMktlUz3JWdwCOuyKPUqlS+uvimLfqJPDlrtQjHPryHVt/Rt4/cLhJ8HHhxRGdJRz+HPgFv6Aj6ejD4UH2a7mqVFou4PASc4RCNZL05OBwJ27Tmod3pZpwyItTMfVkomnBYZjsWtqQtJVuoet1kryvPDjTUh5At2hrfw2VF6dVKwF01xPZFQ7wytMjnqsCFOp0N3dcQT1xWYNCme4Wvn8x7qoO3TaMPytVEI+Ec+jm69iLTlV8EjaAmOlu5UmVivEcAXunu2rBw2SiqXaxd7qLvEwmmnZx33SX9zSZaKYL6DZlVwvz9NdNOu7pDip/D3cO4eBzMkky3fmdTL5fN3xPJt+d7vxPJgolUXlbpRJOd7onMeAGHxlJJrHTnZlkEjMxGEomqhz2EUOaeGWhSsVpmUwmjukuI2eMygOLyUSf7iwmE82oYKVKxU931o8e/PdUt5hMNOtGNp6HSPsBb7pmX1dvRvfFGqKlb5MiEREREREREREREREREREREdHv8xfQb5TIVcxdIwAAAABJRU5ErkJggg==",ese=Object.freeze(Object.defineProperty({__proto__:null,default:Qle},Symbol.toStringTag,{value:"Module"})),tse="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAllBMVEUAAADnozzkoDzmojzmojzmojznozrnojzmojvmojvnojznojzmojznojzmojzmojznojznojzmojzmojzmojvnojzmojzmojzmpDvmojzmojzmojzmojzmoTvnojznojvlnjjmoDzmojzmojzmojzmojznojznozzmojznojzmoTvmojzmojznpjnmojzmojzmoDzmojxUQ0wVAAAAMXRSTlMAfz+/onQV5+GHevLRybavqJSObl9YUzcP7cRKRTIoGwYj+tedgWROmWks3LsK9s0fysZrJgAABRZJREFUeNrt3Wdv20AMBmDGQ17y3kveM178/3+uQVAUIWO7PuVO4gV8PhZFgdf2G51oqgGllFJKKaWUUkoppdTv1uvB7xCG8Cu8Ib7BLxDhhwj818APDfBeDz/twHchfrqC58r4Vxm8tljiX5cF+CyH/+TAYzv8Ygz+uuIXVfBWGYk8eGpxQaIyAz/lkFmDl8b4zQR8VMVvRuChPN7RBu/cKnjH0L++r/GuPXhmjA9kwC9VfCALXsnjQwfwyGyIDxUC8Mcan2iCNyZINX3t+wiJTUA/aSfwRBuJ929/sgUvzApIdAFg5GPf90jU7rSmBR7gTZ/eS9cH+UZ3X/xZhb1N4rFeFwb3r/UdEC5gTd8+OH0VByBbE4nsw/NwCUTLPDm053zqe/bJbdTt4k/fD0gMA/jkXd+D4vNRw5UeXeT2nTW9CszOk77zpo//N3ucgkwnJHLwTbTEr+og0haJyuL/8/kuCDR4R6IMd8xD/Golse8tJEK4q4fEBsTpI9WD+xrS+17D13p8xH9ErkSwpi+P8MgGCWErUOcVEqWX/2p4BklY01dzeKyLn0SuRPSXJufBOv8UylFHkxP6FD+IXInooNk9U0lo33nTW4aHgOscZCih6VyhI3IlYnpB4mB8+bzI6Hs9xndrfYF9503PmF14xKw8zkMk9rFu76vp9501vTAjN7/ZL+hbtRXW92kFifzju/jMsxvjSgTpavCtmZeDZEStQHWRGj8PwvsuZuVxfuU/Rg2C3ApyVqA2SAwXJkHgIGYF6sia/gYmQfjIe5he3xt8RGoYZCJkJYI3vWsaBPYy+l7lAxHjIIuhhBWoNyQqR/Mg0BbQ92jIBycxgvCViAUkL4dEOI8VZJd633tIdSBWEFinveI84iPSmEGOlXRXoMpILPtxg0A+1ZXHqMAHJ7GDnNlKxA2StEZiFcQPAr0UV6B2SB3AJAiXS6/vWT4i/VGQ6TKtlYgyUhPDIFw5pb4vivwq9sMggzCdvu+RKM6Mg3DdVPrOm54H8yBcI40V5xMfkVoI0sfkVyLySO1sBIFN4ivOtyKfR1kJEqzoCtQMXGsiUYjsBIFOwitQY6TKYCkI1JPt+4mPSK0FySTa9zZSXXtBoJRg32fvfERqLwj/x1e87w6bPpzCc/z7kee2ifV9gj/dthLS9xoS1bPbF6oBjhzQ9QZyK5EV59nK9QvGbxDCAFxoIVHJgH3tBFYeJ8skfqjU+JTJvjom8baPnX98D5jMhbfpuO9BiETdfFseXhLRvl8DsKuExHLiKgjknfY9c+HjAWdB5nRodum7bPrq5i4I9ByuQG2RaoPDIHzc1HXX9Bo4DTKlo/7qwFXTcew2CB+hvllreoWPSB0HGYzoYWgKdjSQKEaug0DXSd8730akzoNAzkHfB1cksvMEgvSHdFgzsL/KhD1IIAhsrD/S0B/GXdnjwwcwEVTZmMP2gkNhCongzVzbXmUqQ1IaVh9pGFTRtHWOrl7Zs81VJuxCckoWPwv9QorL+LOQtvNor+nDPiRpy/pur+kbSFbdUt/PIySqASRrsrTT97LBiNSNlpVHGqaF1B+rXdApbTFe39euR6Tm07R9vKVFCf/VRC3OI0x8KiPQaQ6m8iiScd+PRRSpGBmvMgnVNF1lEmtn1PQTinWa+99040caoncU7D0y+NZItJf7Pkbhxi8fC4SrwUvaKN5LfV+8ecDv38qilFJKKaWUUkoppZRSSimllFIv+wNEulUVw2/KggAAAABJRU5ErkJggg==",nse=Object.freeze(Object.defineProperty({__proto__:null,default:tse},Symbol.toStringTag,{value:"Module"})),ose="/install/assets/loading.gif",rse="/install/assets/lang.svg",ase=e=>(Xd("data-v-631c568f"),e=e(),Jd(),e),lse={class:"lang"},sse=["src"],ise={class:"lang-list"},use=ase(()=>F("span",{class:"lang-list-arrow"},null,-1)),cse={class:"logo-box"},dse=["src"],fse={class:"title"},pse=Y({__name:"index",setup(e){const{t}=Bl(),n=o=>{window.localStorage.setItem("ba-lang",o),location.reload()};return(o,r)=>(T(),V(Ve,null,[F("div",lse,[F("img",{src:i(rse),alt:"lang icon"},null,8,sse),F("div",ise,[use,F("div",{onClick:r[0]||(r[0]=a=>n("zh-cn")),class:"lang-item"},"中文简体"),F("div",{onClick:r[1]||(r[1]=a=>n("en")),class:"lang-item"},"English")])]),F("div",cse,[F("img",{class:"logo",alt:"Build Admin logo",src:i(g$)},null,8,dse),F("div",fse,le(i(t)("Install BuildAdmin")),1)])],64))}}),Kf=ui(pse,[["__scopeId","data-v-631c568f"]]);var hse={VITE_PORT:"2828",VITE_OPEN:"false",VITE_BASE_PATH:"/install/",BASE_URL:"/install/",MODE:"production",DEV:!1,PROD:!0,SSR:!1};const mse={class:"container"},vse={class:"table-title"},gse={class:"table"},bse={key:0,class:"global-warning"},yse={target:"_blank",href:"https://doc.buildadmin.com/guide/install/start.html"},wse={class:"table-label"},_se=["title","onClick"],Cse={class:"table-value"},Sse=["title","src","alt"],kse={key:1,class:"table-item"},Ese={class:"table-label"},Tse={class:"table-value"},$se=["title","alt"],Ose={class:"block-help"},Nse={class:"start-install"},Ise=Y({__name:"check",setup(e){const{t,locale:n}=Bl(),o=ju(),r=ii(),a=Et({envCheckData:[],stateTitle:{ok:"Environmental inspection passed",fail:"This environmental check failed",warn:"The environment check failed, but the installation can continue"},checkType:{base:"Basic environment",npm:"NPM correlation",npminstall:"Test npm install",done:"Check complete"},checkTypeIndex:"base",checkDone:{ok:"Congratulations, the installation can continue~",fail:"Sorry, the necessary installation environment conditions have not been met, please check the above form!",executing:"executing"},checkDoneIndex:"executing",startForm:{lang:n.value,packageManager:r.state.packageManager,setNpmRegistry:"taobao"},showPortErrorPrompt:!1}),l=Object.assign({"../assets/img/install/close.png":Jle,"../assets/img/install/fail.png":Zle,"../assets/img/install/ok.png":ese,"../assets/img/install/warn.png":nse}),s=w=>{const S=`../assets/img/install/${w}.png`;return l[S].default},u=w=>{window.localStorage.setItem("ba-lang",w),location.reload()},c=()=>{o.state.showStartDialog&&Ua(a.startForm.packageManager),o.toggleStartDialog(!1),Lle().then(w=>{if(w.data.code!=1)return p(w.data.msg);m(),a.envCheckData=w.data.data})},f=w=>{w.type=="faq"?window.open(w.url):w.type=="install-package-manager"?(a.checkDoneIndex="executing",v(),r.toggle(!0),r.addTaskPM("install",!0,"",S=>{r.toggle(!1),y(),S==gt.Failed?p(t("Sorry, the automatic installation of package manager failed. Please complete the installation manually!")):S==gt.Success&&(a.envCheckData=Object.assign({},a.envCheckData,{success:{describe:t("PM is ready!"),state:"ok",link:[]}}),a.envCheckData=Object.assign({},a.envCheckData,{npm_package_manager:{describe:t("already installed"),state:"ok",link:[],pm:r.state.packageManager}}),h())})):w.type=="test-npm-install"&&C()},d=()=>{a.checkDoneIndex=="ok"&&o.setStep("config")},p=w=>{y(),a.checkDoneIndex=="fail"&&(a.checkDoneIndex="executing"),Cr({type:"error",message:w,duration:0,center:!0})},m=()=>{a.checkTypeIndex="npm",xle().then(w=>{if(y(),w.data.code==2)return!1;if(w.data.code!=1)return p(w.data.msg);a.envCheckData=Object.assign({},a.envCheckData,w.data.data),w.data.data.npm_package_manager.state=="ok"&&(v(),h())})},v=()=>{if(a.startForm.setNpmRegistry!="none"){let w=!1;for(const S in r.state.taskList)if(r.state.taskList[S].command=="set-npm-registry."+a.startForm.setNpmRegistry&&r.state.taskList[S].status==gt.Success){w=!0;break}w||r.addTask("set-npm-registry."+a.startForm.setNpmRegistry,!1,"",S=>{if(S==gt.Failed){let E={"set-npm-registry":{describe:t("Command execution failed"),state:"fail",link:[{name:t("How to solve"),title:t("Click to see how to solve it"),type:"faq",url:"https://doc.buildadmin.com/guide/install/setNpmRegistryFail.html"}]}};a.envCheckData=Object.assign({},a.envCheckData,E)}})}},h=()=>{a.envCheckData=Object.assign({},a.envCheckData,{"check npm install":{describe:"",state:"warn",link:[{name:t("Click to test"),title:t("Click to test")+" npm install",type:"test-npm-install"}]}})},C=()=>{a.checkDoneIndex="executing",a.checkTypeIndex="npminstall",g("check npm install"),r.toggle(!0),r.addTaskPM("test",!0,"",w=>{if(y(),r.toggle(!1),w==gt.Failed){let S={"test-npm-install":{describe:t("Command execution test failed"),state:"warn",link:[{name:t("How to solve"),title:t("Click to see how to solve it"),type:"faq",url:"https://doc.buildadmin.com/guide/install/npmInstallFail.html"}]}};a.envCheckData=Object.assign({},a.envCheckData,S)}else if(w==gt.Success){let S={"test-npm-install":{describe:t("Can execute"),state:"ok",link:[]}};a.envCheckData=Object.assign({},a.envCheckData,S)}})},g=w=>{delete a.envCheckData[w]},y=()=>{a.checkTypeIndex="done";let w=["php_version","config_is_writable","public_is_writable","php_pdo","php_gd2"];for(const S in w)if(!a.envCheckData[w[S]]||a.envCheckData[w[S]].state!="ok")return a.checkDoneIndex="fail",!1;return a.checkDoneIndex="ok",!0},_=()=>r.state.packageManager=="none"?t("None - manual execution"):r.state.packageManager,b=()=>{let w=hse.VITE_AXIOS_BASE_URL;return w=w=="getCurrentDomain"||!w?window.location.protocol+"//"+window.location.host:w,new URL(w).port};return at(()=>{o.state.showStartDialog||c(),b()!="8000"&&(a.showPortErrorPrompt=!0)}),(w,S)=>{const E=qe("el-alert"),$=qe("el-option"),O=qe("el-select"),A=qe("el-form-item"),M=qe("el-radio"),D=qe("el-radio-group"),U=qe("el-form"),j=qe("el-icon"),W=qe("el-button"),L=qe("el-dialog");return T(),V("div",null,[K(Kf),F("div",mse,[F("div",vse,le(i(t)("Environmental inspection")),1),F("div",gse,[a.showPortErrorPrompt?(T(),V("div",bse,[K(E,{closable:!1,center:"",type:"error"},{default:X(()=>[Ge(le(i(t)("Port error prompt 1"))+" ",1),F("a",yse,le(i(t)("Get started quickly")),1),Ge(" "+le(i(t)("Port error prompt 3")),1)]),_:1})])):te("",!0),K(ku,{name:"slide-bottom"},{default:X(()=>[(T(!0),V(Ve,null,bt(a.envCheckData,(P,x)=>(T(),V("div",{class:N(["table-item",x]),key:x+P.describe+P.state},[F("div",wse,[Ge(le(x.toString()=="npm_package_manager"?i(t)(x)+" "+_():i(t)(x))+" ",1),P.link&&P.link.length>0?(T(!0),V(Ve,{key:0},bt(P.link,(I,H)=>(T(),V("span",{key:H,title:I.title?I.title:"",onClick:G=>f(I),class:N(["label-need",I.type])},le(I.name),11,_se))),128)):te("",!0)]),F("div",Cse,[Ge(le(P.describe)+" ",1),F("img",{title:i(t)(a.stateTitle[P.state]),class:"data-state",src:s(P.state),alt:P.state},null,8,Sse)])],2))),128))]),_:1}),a.checkTypeIndex!="done"?(T(),V("div",kse,[F("div",Ese,le(i(t)("Checking installation environment")),1),F("div",Tse,[Ge(le(i(t)(a.checkType[a.checkTypeIndex]))+" ",1),F("img",{title:i(t)("Current execution to:")+i(t)(a.checkType[a.checkTypeIndex]),class:"data-state",src:ose,alt:i(t)(a.checkType[a.checkTypeIndex])},null,8,$se)])])):te("",!0),F("div",{class:N(["check-done",a.checkDoneIndex])},le(i(t)(a.checkDone[a.checkDoneIndex])),3),F("div",{class:N(["button",a.checkDoneIndex=="ok"?"pass":""]),onClick:d},le(i(t)("Step 2 site configuration")),3)])]),K(L,{modelValue:i(o).state.showStartDialog,"onUpdate:modelValue":S[3]||(S[3]=P=>i(o).state.showStartDialog=P),"close-on-click-modal":!1,"close-on-press-escape":!1,"show-close":!1,"destroy-on-close":!0,class:"ba-terminal-dialog",title:i(t)("Ready to start"),center:""},{footer:X(()=>[K(W,{onClick:c,type:"primary",size:"large",round:""},{default:X(()=>[K(j,null,{default:X(()=>[K(i(D4))]),_:1}),F("span",Nse,le(i(t)("Start installation")),1)]),_:1})]),default:X(()=>[K(U,{onKeyup:Pt(c,["enter"]),class:"start-from","label-position":"left","label-width":"120px",model:a.startForm},{default:X(()=>[K(A,{label:i(t)("language")},{default:X(()=>[K(O,{onChange:u,class:"w100",modelValue:a.startForm.lang,"onUpdate:modelValue":S[0]||(S[0]=P=>a.startForm.lang=P)},{default:X(()=>[K($,{label:"中文简体",value:"zh-cn"}),K($,{label:"English",value:"en"})]),_:1},8,["modelValue"])]),_:1},8,["label"]),K(A,{label:i(t)("NPM package manager")},{default:X(()=>[K(O,{class:"w100",modelValue:a.startForm.packageManager,"onUpdate:modelValue":S[1]||(S[1]=P=>a.startForm.packageManager=P)},{default:X(()=>[K($,{label:"npm",value:"npm"}),K($,{label:"cnpm",value:"cnpm"}),K($,{label:"pnpm"+i(t)("recommend"),value:"pnpm"},null,8,["label"]),K($,{label:"yarn"+i(t)("recommend"),value:"yarn"},null,8,["label"]),K($,{label:"ni",value:"ni"}),K($,{label:i(t)("I want to execute the command manually"),value:"none"},null,8,["label"])]),_:1},8,["modelValue"]),F("div",Ose,le(i(t)("The system has a Web terminal. Please select an installed or your favorite NPM package manager")),1)]),_:1},8,["label"]),K(A,{label:i(t)("Set NPM source")},{default:X(()=>[K(D,{modelValue:a.startForm.setNpmRegistry,"onUpdate:modelValue":S[2]||(S[2]=P=>a.startForm.setNpmRegistry=P),class:"ml-4"},{default:X(()=>[K(M,{label:i(t)("Use current source"),value:"none",size:"large"},null,8,["label"]),K(M,{label:i(t)("TaoBao"),value:"taobao",size:"large"},null,8,["label"]),K(M,{label:"NPM",value:"npm",size:"large"}),K(M,{label:i(t)("Tencent"),value:"tencent",size:"large"},null,8,["label"])]),_:1},8,["modelValue"])]),_:1},8,["label"])]),_:1},8,["onKeyup","model"])]),_:1},8,["modelValue","title"])])}}}),Mse=ui(Ise,[["__scopeId","data-v-e96f3865"]]),y$=e=>(Xd("data-v-efc9ce06"),e=e(),Jd(),e),Ase={class:"container"},Pse={class:"table-title"},Rse={key:0,class:"install-tips-box"},Lse={class:"install-tips"},xse=["alt"],Dse={class:"install-tips-title"},Fse={class:"install-tips-item"},Bse={class:"install-tips-item"},Vse={class:"change-route",href:"https://gitee.com/wonderful-code/buildadmin/issues",target:"_blank"},Hse={class:"table"},zse={key:0,class:"table-item-br"},jse={key:1,class:"table-column table-item"},Wse={key:0,class:"block-help"},Kse={class:"connecting-prompt"},Use={class:"footer-buttons"},qse={class:"phinx-fail-box"},Yse={class:"title"},Gse={class:"content-item"},Xse={class:"content-item"},Jse={class:"command"},Zse={class:"content-item"},Qse=y$(()=>F("div",{class:"command"},"php think migrate:run",-1)),eie={class:"block-help"},tie={class:"content-item"},nie={class:"text"},oie=y$(()=>F("div",{class:"output-box"},[F("div",{class:"output"},"PS E:\\build-admin> php think migrate:run"),F("div",{class:"output mt10"},"== 20230620180908 Install: migrating"),F("div",{class:"output"},"== 20230620180908 Install: migrated 0.0165s"),F("div",{class:"output mt10"},"== 20230620180916 InstallData: migrating"),F("div",{class:"output"},"== 20230620180916 InstallData: migrated 0.0573s"),F("div",{class:"output mt10"},"All Done. Took 0.0898s")],-1)),rie={class:"block-help mt10"},aie={class:"command"},lie={class:"phinx-fail-footer-button"},sie=Y({__name:"config",setup(e){var t,n={hostname:"",username:"",password:"",hostport:""};const{t:o}=Bl(),r=ju(),a=ii(),l=R(),s=Et({formItem:{hostname:{label:o("Mysql database address"),value:"127.0.0.1",name:"hostname",type:"text"},username:{label:o("MySQL connection user name"),value:"root",name:"username",type:"text"},password:{label:o("MySQL connection password"),value:"",name:"password",type:"password"},hostport:{label:o("MySQL connection port number"),value:"3306",name:"hostport",type:"number"},database:{label:o("Mysql database name"),value:"",name:"database",type:"text",blockHelp:""},prefix:{label:o("MySQL data table prefix"),value:"ba_",name:"prefix",type:"text"},br1:{type:"br"},adminname:{label:o("Administrator user name"),value:"admin",name:"adminname",type:"text"},adminpassword:{label:o("Administrator password"),value:"",name:"adminpassword",type:"password",placeholder:o("Backend login password")},repeatadminpassword:{label:o("Duplicate administrator password"),value:"",name:"repeatadminpassword",type:"password"},br2:{type:"br"},sitename:{label:o("Site name"),value:"BuildAdmin",name:"sitename",type:"text"}},showFormItem:!1,showError:"",baseConfigSubmitState:!1,databaseCheck:"wait",databases:[],showInstallTips:!1,autoJumpSeconds:5,maximumCommandFailures:1,commandFailureCount:0,executionWebCommand:!0,execMigrateFail:!1,execMigrateIdx:0,rootPath:""}),u=async()=>{n={hostname:s.formItem.hostname.value,username:s.formItem.username.value,password:s.formItem.password.value,hostport:s.formItem.hostport.value,database:s.formItem.database.value},n.hostname&&n.username&&n.hostport&&(s.databaseCheck="connecting",await Dle(n).then(y=>{if(y.data.code==1)s.databaseCheck="connect-ok",s.databases=y.data.data.databases,s.formItem.database.value&&c.findDatabase(s.formItem.database.value);else throw s.databaseCheck="wait",s.databases=[],Cr({type:"error",message:y.data.msg,center:!0}),new Error(y.data.msg)}))},c={required:(y,_,b)=>_.value==""||!_.value?b(new Error(_.label+o("Required"))):b(),findDatabase:y=>{s.databaseCheck=="connect-ok"&&(y&&s.databases.indexOf(y)===-1?s.formItem.database.blockHelp=o("The entered database was not found!"):s.formItem.database.blockHelp="")},database:(y,_,b)=>(c.findDatabase(_.value),b()),connect:(y,_,b)=>{let w=!1;for(const S in n)n[S]!=s.formItem[S].value&&(w=!0);return w&&u(),b()},prefix:function(y,_,b){if(_.value){var w=new RegExp(/^[a-zA-Z][a-zA-Z0-9_]*$/i);if(!w.test(_.value))return b(new Error(o("The table prefix can only contain alphanumeric characters and underscores, and starts with a letter")))}return b()},adminname:function(y,_,b){return/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/.test(_.value)?b():b(new Error(o("It is composed of letters, numbers and underscores, starting with letters (3-15 digits)")))},adminpassword:function(y,_,b){return/^(?!.*[&<>"'\n\r]).{6,32}$/.test(_.value)?b():b(new Error(o("Please enter the correct password")))},repeatadminpassword:function(y,_,b){return s.formItem.adminpassword.value&&_.value&&s.formItem.adminpassword.value!=_.value?b(new Error(o("Duplicate passwords do not match"))):b()}},f=Et({hostname:[{validator:c.required,trigger:"blur"}],username:[{validator:c.required,trigger:"blur"}],hostport:[{validator:c.required,trigger:"blur"}],database:[{validator:c.required,trigger:"blur"},{validator:c.database,trigger:"blur"}],prefix:[{validator:c.connect,trigger:"blur"},{validator:c.prefix,trigger:"blur"}],adminname:[{validator:c.required,trigger:"blur"},{validator:c.connect,trigger:"blur"},{validator:c.adminname,trigger:"blur"}],adminpassword:[{validator:c.required,trigger:"blur"},{validator:c.connect,trigger:"blur"},{validator:c.adminpassword,trigger:"blur"}],repeatadminpassword:[{validator:c.required,trigger:"blur"},{validator:c.repeatadminpassword,trigger:"blur"}],sitename:[{validator:c.required,trigger:"blur"}]}),d=y=>{window.open(y)},p=y=>{s.showError=y},m=()=>{a.addTask("migrate.run",!0,"",(y,_)=>{y==gt.Success?v():(s.execMigrateIdx=_,s.execMigrateFail=!0)})},v=()=>{s.execMigrateIdx&&a.delTask(s.execMigrateIdx),setTimeout(()=>{pw({type:"migrate",adminname:s.formItem.adminname.value,adminpassword:s.formItem.adminpassword.value,sitename:s.formItem.sitename.value}).then(()=>{h()})},1500)},h=()=>{if(s.execMigrateFail=!1,!s.executionWebCommand){s.showInstallTips=!1,r.setStep("manualInstall");return}a.toggle(!0),a.addTaskPM("web-install",!0,"",(y,_)=>{y==gt.Success?a.addTaskPM("web-build",!0,"",b=>{s.baseConfigSubmitState=!1,b==gt.Success?(pw({type:"web"}),a.toggle(!1),r.setStep("done")):b==gt.Failed&&g()}):y==gt.Failed&&(s.commandFailureCount{y&&(s.baseConfigSubmitState=!0,u().then(()=>{y.validate(_=>{if(_){let b={};for(const w in s.formItem)b=Object.assign(b,{[w]:s.formItem[w].value});Ble(b).then(w=>{w.data.code==1?(s.rootPath=w.data.data.rootPath,s.executionWebCommand=w.data.data.executionWebCommand,m()):(Cr({type:"error",message:w.data.msg,center:!0}),s.baseConfigSubmitState=!1)}).catch(()=>{s.baseConfigSubmitState=!1})}else s.baseConfigSubmitState=!1})}).catch(()=>{s.baseConfigSubmitState=!1}))};Fle().then(y=>{y.data.code==1?(s.rootPath=y.data.data.rootPath,s.showInstallTips=!y.data.data.executionWebCommand,s.executionWebCommand=y.data.data.executionWebCommand):y.data.code==0?Cr({type:"error",message:y.data.msg,center:!0,duration:0}):s.showInstallTips=!0});const g=()=>{a.toggle(!1),t=setInterval(()=>{s.autoJumpSeconds<=0?(clearInterval(t),r.setStep("manualInstall")):(s.autoJumpSeconds--,p(o("Manual Install 1")+o("Manual Install 2",{seconds:s.autoJumpSeconds})))},1e3)};return at(()=>{s.showFormItem=!0}),lr(()=>{clearInterval(t)}),(y,_)=>{const b=qe("el-input"),w=qe("el-form-item"),S=qe("el-button"),E=qe("el-alert"),$=qe("el-dialog");return T(),V(Ve,null,[F("div",null,[K(Kf),F("div",Ase,[F("div",Pse,le(i(o)("Site configuration")),1),s.showInstallTips?(T(),V("div",Rse,[F("div",Lse,[F("img",{class:"install-tips-close",onClick:_[0]||(_[0]=O=>s.showInstallTips=!1),src:b$,alt:i(o)("Close the prompt of completing unfinished matters manually")},null,8,xse),F("div",Dse,[F("span",null,le(i(o)("Install Tips Title 1")),1),F("span",{class:"change-route",onClick:_[1]||(_[1]=O=>i(r).setStep("check"))},le(i(o)("Back to previous page")),1),F("span",null,le(i(o)("Install Tips Title 2")),1)]),F("div",Fse,[Ge(le(i(o)("If you don't want to open the corresponding permission due to some security factors, please check "))+" ",1),F("span",{onClick:_[2]||(_[2]=O=>d("https://doc.buildadmin.com/guide/install/senior.html")),class:"change-route"},le(i(o)("how installation services ensure system security")),1)]),F("div",Bse,[Ge(le(i(o)("If you really can't adjust all the tests to pass, please "))+" ",1),F("a",Vse,le(i(o)("click to feed back to us")),1),Ge(" "+le(i(o)("continue installation")),1)])])])):te("",!0),F("div",Hse,[K(i(zS),{ref_key:"formRef",ref:l,"label-width":"150px",onKeyup:_[5]||(_[5]=Pt(O=>C(l.value),["enter"])),rules:f,model:s.formItem},{default:X(()=>[K(fn,{name:"slide-bottom"},{default:X(()=>[tt(F("div",{class:"table-column table-error"},le(s.showError),513),[[kt,s.showError]])]),_:1}),K(ku,{name:"slide-bottom"},{default:X(()=>[(T(!0),V(Ve,null,bt(s.formItem,(O,A)=>tt((T(),V("div",{key:A},[O.type=="br"?(T(),V("div",zse)):(T(),V("div",jse,[K(w,{prop:O.name,class:"table-label",label:O.label},{default:X(()=>[K(b,{placeholder:O.placeholder?O.placeholder:"",modelValue:O.value,"onUpdate:modelValue":M=>O.value=M,class:"table-input",type:O.type},null,8,["placeholder","modelValue","onUpdate:modelValue","type"]),O.blockHelp?(T(),V("div",Wse,le(O.blockHelp),1)):te("",!0)]),_:2},1032,["prop","label"])]))])),[[kt,s.showFormItem]])),128))]),_:1}),K(fn,{name:"slide-bottom"},{default:X(()=>[tt(F("div",null,[tt(F("div",Kse,[F("span",null,le(i(o)("Test connection to data server")),1)],512),[[kt,s.databaseCheck=="connecting"]]),F("div",Use,[K(S,{class:"button",onClick:_[3]||(_[3]=O=>i(r).setStep("check"))},{default:X(()=>[Ge(le(i(o)("Previous step")),1)]),_:1}),K(S,{type:"primary",class:"button",onClick:_[4]||(_[4]=O=>C(l.value)),loading:s.baseConfigSubmitState},{default:X(()=>[Ge(le(i(o)("Install now")),1)]),_:1},8,["loading"])])],512),[[kt,s.showFormItem]])]),_:1})]),_:1},8,["rules","model"])])])]),K($,{modelValue:s.execMigrateFail,"onUpdate:modelValue":_[6]||(_[6]=O=>s.execMigrateFail=O),top:"5vh","close-on-click-modal":!1,"close-on-press-escape":!1,"show-close":!1,title:i(o)("Table migration failed")},{default:X(()=>[K(E,{title:i(o)("We use Phinx to manage the data table, which can version the data table"),closable:!1,center:"",type:"info"},null,8,["title"]),F("div",qse,[F("div",Yse,le(i(o)("Data table automatic migration failed, please manually migrate as follows:")),1),F("div",Gse,"1、"+le(i(o)("Open terminal (windows PowerShell)")),1),F("div",Xse,[F("div",null,"2、"+le(i(o)("Execute command")),1),F("div",Jse,"cd "+le(s.rootPath),1)]),F("div",Zse,[F("div",null,"3、"+le(i(o)("Execute command")),1),Qse,F("div",eie,le(i(o)("If the command fails to be executed, add sudo or press the error message")),1)]),F("div",tie,[F("div",null,"4、"+le(i(o)("Migration check")),1),F("div",nie,le(i(o)("When the command is executed successfully, the output is similar to:")),1),oie,F("div",rie,[Ge(le(i(o)("After the command is executed successfully, multiple data tables will be automatically created in the database, and then click below to "))+" ",1),F("span",aie,le(i(o)("continue install")),1)])])]),F("div",lie,[K(S,{type:"primary",onClick:v},{default:X(()=>[Ge(le(i(o)("continue install")),1)]),_:1})])]),_:1},8,["modelValue","title"])],64)}}}),iie=ui(sie,[["__scopeId","data-v-efc9ce06"]]),uie={class:"container"},cie={class:"table-title"},die={class:"done-box"},fie={class:"reload-tips"},pie={class:"text-warning"},hie={class:"done-button"},mie=Y({__name:"done",setup(e){const{t}=Bl(),n=window.location.protocol+"//"+window.location.host,o=Et({hideIndexUrl:"https://doc.buildadmin.com/guide/install/hideIndex.html",indexUrl:n+"/index.html/#/",adminUrl:n+"/index.html/#/admin"}),r=l=>{window.open(l)},a=()=>{window.localStorage.clear(),location.reload()};return(l,s)=>{const u=qe("el-alert"),c=qe("el-button");return T(),V("div",null,[K(Kf),F("div",uie,[F("div",cie,"✨ "+le(i(t)("Thanks for using buildadmin"))+" ✨",1),F("div",die,[F("div",null,le(i(t)("Background URL")),1),F("div",{onClick:s[0]||(s[0]=f=>r(o.adminUrl)),class:"admin-url"},le(o.adminUrl),1),F("div",fie,[Ge(le(i(t)("Need to reinstall the system?")),1),F("span",{class:"reload",onClick:a},le(i(t)("Please click on me")),1)])]),F("div",pie,[K(u,{closable:!1,center:"",title:i(t)("It is recommended to delete the root directory / public / install folder; This page is only visible on your device."),type:"error"},null,8,["title"])]),F("div",hie,[K(c,{onClick:s[1]||(s[1]=f=>r(o.hideIndexUrl)),type:"primary",plain:"",size:"large"},{default:X(()=>[Ge(le(i(t)("Hide index.html?")),1)]),_:1}),K(c,{onClick:s[2]||(s[2]=f=>r(o.indexUrl)),type:"primary",plain:"",size:"large"},{default:X(()=>[Ge(le(i(t)("Access foreground")),1)]),_:1}),K(c,{onClick:s[3]||(s[3]=f=>r(o.adminUrl)),type:"primary",size:"large"},{default:X(()=>[Ge(le(i(t)("Access background")),1)]),_:1})])])])}}}),vie=ui(mie,[["__scopeId","data-v-e1e72612"]]),Wu=e=>(Xd("data-v-292784ff"),e=e(),Jd(),e),gie={class:"container"},bie={class:"title"},yie={class:"content"},wie={class:"content-item"},_ie={class:"content-item"},Cie={class:"command"},Sie={class:"content-item"},kie=Wu(()=>F("div",{class:"command"},"npm install",-1)),Eie={class:"content-item"},Tie=Wu(()=>F("div",{class:"command"},"npm run build",-1)),$ie={class:"content-item"},Oie={class:"step-box"},Nie={class:"step"},Iie={class:"text-bold"},Mie={class:"step"},Aie=Wu(()=>F("span",{class:"text-bold"},"assets",-1)),Pie=Wu(()=>F("span",{class:"text-bold"},"index.html",-1)),Rie=Wu(()=>F("span",{class:"text-bold"},"public",-1)),Lie={class:"step"},xie={class:"min-help"},Die={key:0,class:"loading"},Fie={class:"reload-tips"},Bie=Y({__name:"index",setup(e){const{t}=Bl(),n=ju(),o=Et({showLoading:"",webPath:t("Getting full path of root directory / Web")}),r=s=>{window.open(s)},a=()=>{o.showLoading=t("Moving automatically"),Vle().then(s=>{s.data.code==1?n.setStep("done"):Cr({type:"error",message:s.data.msg,center:!0})}).finally(()=>{o.showLoading=""})};Hle().then(s=>{s.data.code==1?o.webPath=s.data.data.webPath:Cr({type:"error",message:s.data.msg,center:!0})});const l=()=>{window.localStorage.clear(),location.reload()};return(s,u)=>{const c=qe("el-alert");return T(),V("div",gie,[F("div",bie,le(i(t)("Unfinished matters manually")),1),F("div",yie,[K(c,{title:i(t)("Sorry, some operations could not be completed automatically You need to manually complete the outstanding matters according to the following guidance"),type:"error"},null,8,["title"]),F("div",wie,"1、"+le(i(t)("Open terminal (windows PowerShell)")),1),F("div",_ie,[F("div",null,"2、"+le(i(t)("Execute command")),1),F("div",Cie,"cd "+le(o.webPath),1)]),F("div",Sie,[F("div",null,"3、"+le(i(t)("Execute command")),1),kie,F("div",{onClick:u[0]||(u[0]=f=>r("https://doc.buildadmin.com/guide/install/npmInstallFail.html")),class:"block-help link"},le(i(t)("Execution failed?")),1)]),F("div",Eie,[F("div",null,"4、"+le(i(t)("Execute command")),1),Tie,F("div",{onClick:u[1]||(u[1]=f=>r("https://doc.buildadmin.com/guide/install/npmBuildFail.html")),class:"block-help link"},le(i(t)("Execution failed?")),1)]),F("div",$ie,[F("div",null,"5、"+le(i(t)("Move the built file to the specified location of the system")),1),F("div",{onClick:a,class:"block-help link size-15"},le(i(t)("Click to try to automatically move the build file")),1),F("div",Oie,[F("div",Nie,[Ge(" 1. "+le(i(t)("The build output directory is: site")),1),F("span",Iie,le(i(t)("root directory / dist")),1)]),F("div",Mie,[Ge(" 2. "+le(i(t)("Please move 1")),1),Aie,Ge(le(i(t)("Please move 2")),1),Pie,Ge(le(i(t)("Please move 3")),1),Rie,Ge(le(i(t)("Please move 4")),1)]),F("div",Lie,"3. "+le(i(t)("You can delete the build output directory directly")),1)]),F("div",xie,le(i(t)("During construction, all files in the output directory will be overwritten, so the system is designed to build in the root directory first, and then move to the public directory to prevent other files in the public from being overwritten")),1)]),o.showLoading?(T(),V("div",Die,le(o.showLoading),1)):te("",!0)]),F("div",Fie,[Ge(le(i(t)("Need to reinstall the system?")),1),F("span",{class:"reload",onClick:l},le(i(t)("Please click on me")),1)])])}}}),Vie=ui(Bie,[["__scopeId","data-v-292784ff"]]),Hie=Y({__name:"manualInstall",setup(e){return(t,n)=>(T(),V("div",null,[K(Kf),K(Vie)]))}}),zie={class:"ba-terminal"},jie=["src"],Wie=Y({__name:"App",setup(e){const t=ju(),n=ii(),{locale:o,getLocaleMessage:r}=Bl();var a=window.localStorage.getItem("ba-lang")||"zh-cn";o.value=a;const l=r(a);return at(()=>{n.init()}),(s,u)=>{const c=qe("el-badge"),f=qe("el-config-provider");return T(),re(f,{locale:i(l)},{default:X(()=>[i(t).state.step=="check"?(T(),re(Mse,{key:0})):te("",!0),i(t).state.step=="config"?(T(),re(iie,{key:1})):te("",!0),i(t).state.step=="done"?(T(),re(vie,{key:2})):te("",!0),i(t).state.step=="manualInstall"?(T(),re(Hie,{key:3})):te("",!0),K(Gle),F("div",zie,[K(c,{"is-dot":i(n).state.showDot},{default:X(()=>[F("img",{onClick:u[0]||(u[0]=d=>i(n).toggle()),class:"terminal-logo",draggable:"false",src:i(g$),alt:"BuildAdmin Logo"},null,8,jie)]),_:1},8,["is-dot"])])]),_:1},8,["locale"])}}});function Kie(e){Yie(e),qie(e),Uie(e)}function Uie(e){e.directive("blur",{mounted(t){t.addEventListener("focus",()=>{t.blur()})}})}function qie(e){e.directive("zoom",{mounted(t,n){if(!n.value)return!1;We(()=>{const o=document.querySelector(n.value),r=document.createElement("div");r.className="zoom-handle",r.onmouseenter=()=>{r.onmousedown=a=>{const l=a.clientX,s=a.clientY,u=o.offsetWidth,c=o.offsetHeight;document.onmousemove=f=>{f.preventDefault();const d=u+(f.clientX-l)*2,p=c+(f.clientY-s);o.style.width=`${d}px`,o.style.height=`${p}px`},document.onmouseup=function(){document.onmousemove=null,document.onmouseup=null}}},o.appendChild(r)})}})}function Yie(e){e.directive("drag",{mounted(t,n){if(!n.value)return!1;const o=document.querySelector(n.value[0]),r=document.querySelector(n.value[1]);if(!r||!o)return!1;r.onmouseover=()=>r.style.cursor="move";function a(s,u){const c=u==="pc"?s.clientX-r.offsetLeft:s.touches[0].clientX-r.offsetLeft,f=u==="pc"?s.clientY-r.offsetTop:s.touches[0].clientY-r.offsetTop,d=document.body.clientWidth,p=document.body.clientHeight||document.documentElement.clientHeight,m=o.offsetWidth,v=o.offsetHeight,h=o.offsetLeft,C=d-o.offsetLeft-m,g=o.offsetTop,y=p-o.offsetTop-v;let _=getComputedStyle(o).left,b=getComputedStyle(o).top;return _.includes("%")?(_=+document.body.clientWidth*(+_.replace(/\%/g,"")/100),b=+document.body.clientHeight*(+b.replace(/\%/g,"")/100)):(_=+_.replace(/\px/g,""),b=+b.replace(/\px/g,"")),{disX:c,disY:f,minDragDomLeft:h,maxDragDomLeft:C,minDragDomTop:g,maxDragDomTop:y,styL:_,styT:b}}function l(s,u,c){const{disX:f,disY:d,minDragDomLeft:p,maxDragDomLeft:m,minDragDomTop:v,maxDragDomTop:h,styL:C,styT:g}=c;let y=u==="pc"?s.clientX-f:s.touches[0].clientX-f,_=u==="pc"?s.clientY-d:s.touches[0].clientY-d;-y>p?y=-p:y>m&&(y=m),-_>v?_=-v:_>h&&(_=h),o.style.cssText+=`;left:${y+C}px;top:${_+g}px;`}r.onmousedown=s=>{const u=a(s,"pc");document.onmousemove=c=>{l(c,"pc",u)},document.onmouseup=()=>{document.onmousemove=null,document.onmouseup=null}},r.ontouchstart=s=>{const u=a(s,"app");document.ontouchmove=c=>{l(c,"app",u)},document.ontouchend=()=>{document.ontouchmove=null,document.ontouchend=null}}}})}function Gie(e){return typeof e=="object"&&e!==null}function hw(e,t){return e=Gie(e)?e:Object.create(null),new Proxy(e,{get(n,o,r){return o==="key"?Reflect.get(n,o,r):Reflect.get(n,o,r)||Reflect.get(t,o,r)}})}function Xie(e,t){return t.reduce((n,o)=>n==null?void 0:n[o],e)}function Jie(e,t,n){return t.slice(0,-1).reduce((o,r)=>/^(__proto__)$/.test(r)?{}:o[r]=o[r]||{},e)[t[t.length-1]]=n,e}function Zie(e,t){return t.reduce((n,o)=>{const r=o.split(".");return Jie(n,r,Xie(e,r))},{})}function mw(e,{storage:t,serializer:n,key:o,debug:r}){try{const a=t==null?void 0:t.getItem(o);a&&e.$patch(n==null?void 0:n.deserialize(a))}catch(a){r&&console.error(a)}}function vw(e,{storage:t,serializer:n,key:o,paths:r,debug:a}){try{const l=Array.isArray(r)?Zie(e,r):e;t.setItem(o,n.serialize(l))}catch(l){a&&console.error(l)}}function Qie(e={}){return t=>{const{auto:n=!1}=e,{options:{persist:o=n},store:r}=t;if(!o)return;const a=(Array.isArray(o)?o.map(l=>hw(l,e)):[hw(o,e)]).map(({storage:l=localStorage,beforeRestore:s=null,afterRestore:u=null,serializer:c={serialize:JSON.stringify,deserialize:JSON.parse},key:f=r.$id,paths:d=null,debug:p=!1})=>{var m;return{storage:l,beforeRestore:s,afterRestore:u,serializer:c,key:((m=e.key)!=null?m:v=>v)(f),paths:d,debug:p}});r.$persist=()=>{a.forEach(l=>{vw(r.$state,l)})},r.$hydrate=({runHooks:l=!0}={})=>{a.forEach(s=>{const{beforeRestore:u,afterRestore:c}=s;l&&(u==null||u(t)),mw(r,s),l&&(c==null||c(t))})},a.forEach(l=>{const{beforeRestore:s,afterRestore:u}=l;s==null||s(t),mw(r,l),u==null||u(t),r.$subscribe((c,f)=>{vw(f,l)},{detached:!0})})}}var eue=Qie();const w$=TI();w$.use(eue);async function tue(){const e=iv(Wie);e.use(w$),e.use($o),e.use(xne,{i18n:$o.global.t}),Kie(e),e.mount("#app")}tue()});export default nue(); diff --git a/public/install/assets/lang.svg b/public/install/assets/lang.svg new file mode 100644 index 0000000..0d8224c --- /dev/null +++ b/public/install/assets/lang.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/install/assets/loading.gif b/public/install/assets/loading.gif new file mode 100644 index 0000000..ffcb562 Binary files /dev/null and b/public/install/assets/loading.gif differ diff --git a/public/install/assets/logo.svg b/public/install/assets/logo.svg new file mode 100644 index 0000000..da77266 --- /dev/null +++ b/public/install/assets/logo.svg @@ -0,0 +1,102 @@ + + + + diff --git a/public/install/favicon.ico b/public/install/favicon.ico new file mode 100644 index 0000000..df30868 Binary files /dev/null and b/public/install/favicon.ico differ diff --git a/public/install/index.html b/public/install/index.html new file mode 100644 index 0000000..373529a --- /dev/null +++ b/public/install/index.html @@ -0,0 +1,14 @@ + + + + + + + BuildAdmin-安装 + + + + +
+ + diff --git a/public/npm-install-test/package.json b/public/npm-install-test/package.json new file mode 100644 index 0000000..72603fc --- /dev/null +++ b/public/npm-install-test/package.json @@ -0,0 +1,12 @@ +{ + "name": "npm-install-test", + "private": true, + "version": "0.0.1", + "scripts": { + "dev": "vite" + }, + "dependencies": { + "vue": "^3.2.25" + }, + "devDependencies": {} +} diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/public/router.php b/public/router.php new file mode 100644 index 0000000..9c43666 --- /dev/null +++ b/public/router.php @@ -0,0 +1,21 @@ + +// +---------------------------------------------------------------------- +// $Id$ + +@ini_set('zlib.output_compression', 'Off'); + +if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) { + return false; +} else { + $_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php'; + + require __DIR__ . "/index.php"; +} diff --git a/public/static/fonts/ttfs/1.ttf b/public/static/fonts/ttfs/1.ttf new file mode 100644 index 0000000..d4ee155 Binary files /dev/null and b/public/static/fonts/ttfs/1.ttf differ diff --git a/public/static/fonts/ttfs/2.ttf b/public/static/fonts/ttfs/2.ttf new file mode 100644 index 0000000..3a452b6 Binary files /dev/null and b/public/static/fonts/ttfs/2.ttf differ diff --git a/public/static/fonts/ttfs/3.ttf b/public/static/fonts/ttfs/3.ttf new file mode 100644 index 0000000..d07a4d9 Binary files /dev/null and b/public/static/fonts/ttfs/3.ttf differ diff --git a/public/static/fonts/ttfs/4.ttf b/public/static/fonts/ttfs/4.ttf new file mode 100644 index 0000000..54a14ed Binary files /dev/null and b/public/static/fonts/ttfs/4.ttf differ diff --git a/public/static/fonts/ttfs/5.ttf b/public/static/fonts/ttfs/5.ttf new file mode 100644 index 0000000..d672876 Binary files /dev/null and b/public/static/fonts/ttfs/5.ttf differ diff --git a/public/static/fonts/ttfs/6.ttf b/public/static/fonts/ttfs/6.ttf new file mode 100644 index 0000000..7f183e2 Binary files /dev/null and b/public/static/fonts/ttfs/6.ttf differ diff --git a/public/static/fonts/zhttfs/1.ttf b/public/static/fonts/zhttfs/1.ttf new file mode 100644 index 0000000..1c14f7f Binary files /dev/null and b/public/static/fonts/zhttfs/1.ttf differ diff --git a/public/static/fonts/zhttfs/SourceHanSansCN-Normal.ttf b/public/static/fonts/zhttfs/SourceHanSansCN-Normal.ttf new file mode 100644 index 0000000..c6cc488 Binary files /dev/null and b/public/static/fonts/zhttfs/SourceHanSansCN-Normal.ttf differ diff --git a/public/static/images/avatar.png b/public/static/images/avatar.png new file mode 100644 index 0000000..e32edd3 Binary files /dev/null and b/public/static/images/avatar.png differ diff --git a/public/static/images/captcha/click/bgs/1.png b/public/static/images/captcha/click/bgs/1.png new file mode 100644 index 0000000..8ba3b34 Binary files /dev/null and b/public/static/images/captcha/click/bgs/1.png differ diff --git a/public/static/images/captcha/click/bgs/2.png b/public/static/images/captcha/click/bgs/2.png new file mode 100644 index 0000000..5bff3a9 Binary files /dev/null and b/public/static/images/captcha/click/bgs/2.png differ diff --git a/public/static/images/captcha/click/bgs/3.png b/public/static/images/captcha/click/bgs/3.png new file mode 100644 index 0000000..71517d6 Binary files /dev/null and b/public/static/images/captcha/click/bgs/3.png differ diff --git a/public/static/images/captcha/click/icons/aeroplane.png b/public/static/images/captcha/click/icons/aeroplane.png new file mode 100644 index 0000000..7b1c062 Binary files /dev/null and b/public/static/images/captcha/click/icons/aeroplane.png differ diff --git a/public/static/images/captcha/click/icons/apple.png b/public/static/images/captcha/click/icons/apple.png new file mode 100644 index 0000000..4584367 Binary files /dev/null and b/public/static/images/captcha/click/icons/apple.png differ diff --git a/public/static/images/captcha/click/icons/banana.png b/public/static/images/captcha/click/icons/banana.png new file mode 100644 index 0000000..d3f5fb8 Binary files /dev/null and b/public/static/images/captcha/click/icons/banana.png differ diff --git a/public/static/images/captcha/click/icons/bell.png b/public/static/images/captcha/click/icons/bell.png new file mode 100644 index 0000000..8ea07a1 Binary files /dev/null and b/public/static/images/captcha/click/icons/bell.png differ diff --git a/public/static/images/captcha/click/icons/bicycle.png b/public/static/images/captcha/click/icons/bicycle.png new file mode 100644 index 0000000..5ba9e44 Binary files /dev/null and b/public/static/images/captcha/click/icons/bicycle.png differ diff --git a/public/static/images/captcha/click/icons/bird.png b/public/static/images/captcha/click/icons/bird.png new file mode 100644 index 0000000..f8ff493 Binary files /dev/null and b/public/static/images/captcha/click/icons/bird.png differ diff --git a/public/static/images/captcha/click/icons/bomb.png b/public/static/images/captcha/click/icons/bomb.png new file mode 100644 index 0000000..f734e11 Binary files /dev/null and b/public/static/images/captcha/click/icons/bomb.png differ diff --git a/public/static/images/captcha/click/icons/butterfly.png b/public/static/images/captcha/click/icons/butterfly.png new file mode 100644 index 0000000..1e24b61 Binary files /dev/null and b/public/static/images/captcha/click/icons/butterfly.png differ diff --git a/public/static/images/captcha/click/icons/candy.png b/public/static/images/captcha/click/icons/candy.png new file mode 100644 index 0000000..24af81e Binary files /dev/null and b/public/static/images/captcha/click/icons/candy.png differ diff --git a/public/static/images/captcha/click/icons/crab.png b/public/static/images/captcha/click/icons/crab.png new file mode 100644 index 0000000..cef4646 Binary files /dev/null and b/public/static/images/captcha/click/icons/crab.png differ diff --git a/public/static/images/captcha/click/icons/cup.png b/public/static/images/captcha/click/icons/cup.png new file mode 100644 index 0000000..89cedf9 Binary files /dev/null and b/public/static/images/captcha/click/icons/cup.png differ diff --git a/public/static/images/captcha/click/icons/dolphin.png b/public/static/images/captcha/click/icons/dolphin.png new file mode 100644 index 0000000..bd33f18 Binary files /dev/null and b/public/static/images/captcha/click/icons/dolphin.png differ diff --git a/public/static/images/captcha/click/icons/fire.png b/public/static/images/captcha/click/icons/fire.png new file mode 100644 index 0000000..35f9428 Binary files /dev/null and b/public/static/images/captcha/click/icons/fire.png differ diff --git a/public/static/images/captcha/click/icons/guitar.png b/public/static/images/captcha/click/icons/guitar.png new file mode 100644 index 0000000..430ae49 Binary files /dev/null and b/public/static/images/captcha/click/icons/guitar.png differ diff --git a/public/static/images/captcha/click/icons/hexagon.png b/public/static/images/captcha/click/icons/hexagon.png new file mode 100644 index 0000000..cf4d14b Binary files /dev/null and b/public/static/images/captcha/click/icons/hexagon.png differ diff --git a/public/static/images/captcha/click/icons/pear.png b/public/static/images/captcha/click/icons/pear.png new file mode 100644 index 0000000..45d1688 Binary files /dev/null and b/public/static/images/captcha/click/icons/pear.png differ diff --git a/public/static/images/captcha/click/icons/rocket.png b/public/static/images/captcha/click/icons/rocket.png new file mode 100644 index 0000000..60538f5 Binary files /dev/null and b/public/static/images/captcha/click/icons/rocket.png differ diff --git a/public/static/images/captcha/click/icons/sailboat.png b/public/static/images/captcha/click/icons/sailboat.png new file mode 100644 index 0000000..e30a3ce Binary files /dev/null and b/public/static/images/captcha/click/icons/sailboat.png differ diff --git a/public/static/images/captcha/click/icons/snowflake.png b/public/static/images/captcha/click/icons/snowflake.png new file mode 100644 index 0000000..32809ae Binary files /dev/null and b/public/static/images/captcha/click/icons/snowflake.png differ diff --git a/public/static/images/captcha/click/icons/wolf head.png b/public/static/images/captcha/click/icons/wolf head.png new file mode 100644 index 0000000..d72dbf2 Binary files /dev/null and b/public/static/images/captcha/click/icons/wolf head.png differ diff --git a/public/static/images/captcha/image/1.jpg b/public/static/images/captcha/image/1.jpg new file mode 100644 index 0000000..d417136 Binary files /dev/null and b/public/static/images/captcha/image/1.jpg differ diff --git a/public/static/images/captcha/image/2.jpg b/public/static/images/captcha/image/2.jpg new file mode 100644 index 0000000..56640bd Binary files /dev/null and b/public/static/images/captcha/image/2.jpg differ diff --git a/public/static/images/captcha/image/3.jpg b/public/static/images/captcha/image/3.jpg new file mode 100644 index 0000000..83e5bd9 Binary files /dev/null and b/public/static/images/captcha/image/3.jpg differ diff --git a/public/static/images/captcha/image/4.jpg b/public/static/images/captcha/image/4.jpg new file mode 100644 index 0000000..97a3721 Binary files /dev/null and b/public/static/images/captcha/image/4.jpg differ diff --git a/public/static/images/captcha/image/5.jpg b/public/static/images/captcha/image/5.jpg new file mode 100644 index 0000000..220a17a Binary files /dev/null and b/public/static/images/captcha/image/5.jpg differ diff --git a/public/static/images/captcha/image/6.jpg b/public/static/images/captcha/image/6.jpg new file mode 100644 index 0000000..be53ea0 Binary files /dev/null and b/public/static/images/captcha/image/6.jpg differ diff --git a/public/static/images/captcha/image/7.jpg b/public/static/images/captcha/image/7.jpg new file mode 100644 index 0000000..fbf537f Binary files /dev/null and b/public/static/images/captcha/image/7.jpg differ diff --git a/public/static/images/captcha/image/8.jpg b/public/static/images/captcha/image/8.jpg new file mode 100644 index 0000000..e10cf28 Binary files /dev/null and b/public/static/images/captcha/image/8.jpg differ diff --git a/public/static/images/local-module-logo.png b/public/static/images/local-module-logo.png new file mode 100644 index 0000000..99cd9fa Binary files /dev/null and b/public/static/images/local-module-logo.png differ diff --git a/runtime/.gitignore b/runtime/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/runtime/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/think b/think new file mode 100644 index 0000000..2429d22 --- /dev/null +++ b/think @@ -0,0 +1,10 @@ +#!/usr/bin/env php +console->run(); \ No newline at end of file diff --git a/web/.editorconfig b/web/.editorconfig new file mode 100644 index 0000000..5c83fe8 --- /dev/null +++ b/web/.editorconfig @@ -0,0 +1,15 @@ +# https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +indent_style = tab +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/web/.env b/web/.env new file mode 100644 index 0000000..e4dd6b0 --- /dev/null +++ b/web/.env @@ -0,0 +1,5 @@ +# port 端口号 +VITE_PORT = 1818 + +# open 运行 npm run dev 时自动打开浏览器 +VITE_OPEN = false diff --git a/web/.env.development b/web/.env.development new file mode 100644 index 0000000..3a9fa29 --- /dev/null +++ b/web/.env.development @@ -0,0 +1,8 @@ +# 本地环境 +ENV = 'development' + +# base路径 +VITE_BASE_PATH = './' + +# 本地环境接口地址 - 尾部无需带'/' +VITE_AXIOS_BASE_URL = 'http://localhost:8000' diff --git a/web/.env.production b/web/.env.production new file mode 100644 index 0000000..7ef3784 --- /dev/null +++ b/web/.env.production @@ -0,0 +1,11 @@ +# 线上环境 +ENV = 'production' + +# base路径 +VITE_BASE_PATH = '/' + +# 导出路径 +VITE_OUT_DIR = 'dist' + +# 线上环境接口地址 - 'getCurrentDomain:表示获取当前域名' +VITE_AXIOS_BASE_URL = 'getCurrentDomain' diff --git a/web/.npmrc b/web/.npmrc new file mode 100644 index 0000000..49813ee --- /dev/null +++ b/web/.npmrc @@ -0,0 +1,2 @@ +# 若不开启且使用 pnpm 安装依赖后,element-plus 和 vue-i18n(useI18n) 共存时组件的类型定义将丢失 +shamefully-hoist=true diff --git a/web/.prettierrc.js b/web/.prettierrc.js new file mode 100644 index 0000000..0075f36 --- /dev/null +++ b/web/.prettierrc.js @@ -0,0 +1,36 @@ +export default { + printWidth: 150, + // 指定每个缩进级别的空格数 + tabWidth: 4, + // 使用制表符而不是空格缩进行 + useTabs: false, + // 在语句末尾打印分号 + semi: false, + // 使用单引号而不是双引号 + singleQuote: true, + // 更改引用对象属性的时间 可选值"" + quoteProps: 'as-needed', + // 在JSX中使用单引号而不是双引号 + jsxSingleQuote: false, + // 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"",默认none + trailingComma: 'es5', + // 在对象文字中的括号之间打印空格 + bracketSpacing: true, + // 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x + arrowParens: 'always', + // 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码 + rangeStart: 0, + rangeEnd: Infinity, + // 指定要使用的解析器,不需要写文件开头的 @prettier + requirePragma: false, + // 不需要自动在文件开头插入 @prettier + insertPragma: false, + // 使用默认的折行标准 always\never\preserve + proseWrap: 'preserve', + // 指定HTML文件的全局空格敏感度 css\strict\ignore + htmlWhitespaceSensitivity: 'css', + // Vue文件脚本和样式标签缩进 + vueIndentScriptAndStyle: false, + // 换行符使用 lf 结尾是 可选值"" + endOfLine: 'lf', +} diff --git a/web/.vscode/extensions.json b/web/.vscode/extensions.json new file mode 100644 index 0000000..d77da08 --- /dev/null +++ b/web/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["vue.volar", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint"] +} diff --git a/web/.vscode/settings.json b/web/.vscode/settings.json new file mode 100644 index 0000000..dc7a3b8 --- /dev/null +++ b/web/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[vue]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "eslint.validate": ["javascript", "vue", "typescript"] +} diff --git a/web/eslint.config.js b/web/eslint.config.js new file mode 100644 index 0000000..76afbbf --- /dev/null +++ b/web/eslint.config.js @@ -0,0 +1,108 @@ +import js from '@eslint/js' +import eslintConfigPrettier from 'eslint-config-prettier' +import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' +import eslintPluginVue from 'eslint-plugin-vue' +import globals from 'globals' +import ts from 'typescript-eslint' + +export default [ + // 三大基本推荐规则 + js.configs.recommended, + ...ts.configs.recommended, + ...eslintPluginVue.configs['flat/recommended'], + + // 忽略规则 + { + ignores: ['node_modules', 'dist', 'public'], + }, + + // 全局变量 + { + languageOptions: { + globals: { + ...globals.browser, + }, + }, + }, + + // vue + { + files: ['**/*.vue'], + languageOptions: { + parserOptions: { + // ts 解析器 + parser: ts.parser, + // 允许 jsx + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + + // eslint + prettier 的兼容性问题解决规则 + eslintConfigPrettier, + eslintPluginPrettierRecommended, + + // ts + { + files: ['**/*.{ts,tsx,vue}'], + rules: { + 'no-empty': 'off', + 'no-undef': 'off', + 'no-unused-vars': 'off', + 'no-useless-escape': 'off', + 'no-sparse-arrays': 'off', + 'no-prototype-builtins': 'off', + 'no-use-before-define': 'off', + 'no-case-declarations': 'off', + 'no-console': 'off', + 'no-control-regex': 'off', + + 'vue/v-on-event-hyphenation': 'off', + 'vue/custom-event-name-casing': 'off', + 'vue/component-definition-name-casing': 'off', + 'vue/attributes-order': 'off', + 'vue/one-component-per-file': 'off', + 'vue/html-closing-bracket-newline': 'off', + 'vue/max-attributes-per-line': 'off', + 'vue/multiline-html-element-content-newline': 'off', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/attribute-hyphenation': 'off', + 'vue/html-self-closing': 'off', + 'vue/require-default-prop': 'off', + 'vue/no-arrow-functions-in-watch': 'off', + 'vue/no-v-html': 'off', + 'vue/comment-directive': 'off', + 'vue/multi-word-component-names': 'off', + 'vue/require-prop-types': 'off', + 'vue/html-indent': 'off', + + '@typescript-eslint/no-unsafe-function-type': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-unused-expressions': 'off', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + }, + ], + }, + }, + + // prettier 规则 + { + files: ['**/*.{ts,tsx,vue,js}'], + rules: { + 'prettier/prettier': [ + 'warn', // 使用警告而不是错误 + { + endOfLine: 'auto', // eslint 无需检查文件换行符 + }, + ], + }, + }, +] diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..badfa36 --- /dev/null +++ b/web/index.html @@ -0,0 +1,16 @@ + + + + + + + + + + Loading... + + +
+ + + diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..1885725 --- /dev/null +++ b/web/package.json @@ -0,0 +1,63 @@ +{ + "name": "build-admin", + "version": "2.3.6", + "license": "Apache-2.0", + "type": "module", + "scripts": { + "dev": "esno ./src/utils/build.ts && vite --force", + "build": "vite build && esno ./src/utils/build.ts", + "lint": "eslint .", + "lint-fix": "eslint --fix .", + "format": "npx prettier --write .", + "typecheck": "vue-tsc --noEmit" + }, + "dependencies": { + "@element-plus/icons-vue": "2.3.1", + "@vueuse/core": "12.0.0", + "axios": "1.9.0", + "echarts": "5.5.1", + "element-plus": "2.9.1", + "font-awesome": "4.7.0", + "lodash-es": "4.17.21", + "mitt": "3.0.1", + "nprogress": "0.2.0", + "pinia": "2.3.0", + "pinia-plugin-persistedstate": "4.2.0", + "qrcode.vue": "3.6.0", + "screenfull": "6.0.2", + "sortablejs": "1.15.6", + "v-code-diff": "1.13.1", + "vue": "3.5.13", + "vue-i18n": "11.1.3", + "vue-router": "4.5.0" + }, + "devDependencies": { + "@eslint/js": "9.17.0", + "@types/lodash-es": "4.17.12", + "@types/node": "22.10.2", + "@types/nprogress": "0.2.3", + "@types/sortablejs": "1.15.8", + "@vitejs/plugin-vue": "5.2.3", + "async-validator": "4.2.5", + "eslint": "9.17.0", + "eslint-config-prettier": "9.1.0", + "eslint-plugin-prettier": "5.2.1", + "eslint-plugin-vue": "9.32.0", + "esno": "4.8.0", + "globals": "15.14.0", + "prettier": "3.4.2", + "sass": "1.83.0", + "typescript": "5.7.2", + "typescript-eslint": "8.18.1", + "vite": "6.3.5", + "vue-tsc": "2.1.10" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "@parcel/watcher", + "esbuild", + "v-code-diff", + "vue-demi" + ] + } +} diff --git a/web/public/favicon.ico b/web/public/favicon.ico new file mode 100644 index 0000000..df30868 Binary files /dev/null and b/web/public/favicon.ico differ diff --git a/web/src/App.vue b/web/src/App.vue new file mode 100644 index 0000000..af0ca20 --- /dev/null +++ b/web/src/App.vue @@ -0,0 +1,36 @@ + + diff --git a/web/src/api/backend/auth/group.ts b/web/src/api/backend/auth/group.ts new file mode 100644 index 0000000..5612631 --- /dev/null +++ b/web/src/api/backend/auth/group.ts @@ -0,0 +1,8 @@ +import createAxios from '/@/utils/axios' + +export function getAdminRules() { + return createAxios({ + url: '/admin/auth.Rule/index', + method: 'get', + }) +} diff --git a/web/src/api/backend/crud.ts b/web/src/api/backend/crud.ts new file mode 100644 index 0000000..f2ffeb1 --- /dev/null +++ b/web/src/api/backend/crud.ts @@ -0,0 +1,142 @@ +import { useBaAccount } from '/@/stores/baAccount' +import { useSiteConfig } from '/@/stores/siteConfig' +import createAxios from '/@/utils/axios' + +export const url = '/admin/crud.Crud/' + +export function generate(data: anyObj) { + return createAxios( + { + url: url + 'generate', + method: 'post', + data: data, + }, + { + showSuccessMessage: true, + } + ) +} + +export function getFileData(table: string, commonModel = 0) { + return createAxios({ + url: url + 'getFileData', + method: 'get', + params: { + table: table, + commonModel: commonModel, + }, + }) +} + +export function generateCheck(data: anyObj) { + return createAxios( + { + url: url + 'generateCheck', + method: 'post', + data: data, + }, + { + showCodeMessage: false, + } + ) +} + +export function parseFieldData(data: anyObj) { + return createAxios({ + url: url + 'parseFieldData', + method: 'post', + data: data, + }) +} + +export function postLogStart(id: string, type: string) { + const data: anyObj = { + id, + type, + } + + if (type == 'Cloud history') { + const baAccount = useBaAccount() + data['token'] = baAccount.getToken('auth') + } + + return createAxios({ + url: url + 'logStart', + method: 'post', + data: data, + }) +} + +export function postDel(id: number) { + return createAxios({ + url: url + 'delete', + method: 'post', + data: { + id: id, + }, + }) +} + +export function checkCrudLog(table: string, connection: string) { + return createAxios({ + url: url + 'checkCrudLog', + method: 'get', + params: { + table: table, + connection: connection, + }, + }) +} + +export function uploadLog(data: anyObj) { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + '/api/v6.Crud/uploadLog', + data: data, + method: 'post', + }, + { + anotherToken: baAccount.getToken('auth'), + } + ) +} + +export function uploadCompleted(data: anyObj) { + return createAxios({ + url: url + 'uploadCompleted', + data: data, + method: 'post', + }) +} + +export function logs(data: anyObj = {}) { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + '/api/v6.Crud/logs', + data: data, + method: 'post', + }, + { + anotherToken: baAccount.getToken('auth'), + } + ) +} + +export function delLog(data: anyObj = {}) { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + '/api/v6.Crud/del', + data: data, + method: 'post', + }, + { + anotherToken: baAccount.getToken('auth'), + } + ) +} diff --git a/web/src/api/backend/dashboard.ts b/web/src/api/backend/dashboard.ts new file mode 100644 index 0000000..5caef9d --- /dev/null +++ b/web/src/api/backend/dashboard.ts @@ -0,0 +1,10 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/Dashboard/' + +export function index() { + return createAxios({ + url: url + 'index', + method: 'get', + }) +} diff --git a/web/src/api/backend/index.ts b/web/src/api/backend/index.ts new file mode 100644 index 0000000..9573c2c --- /dev/null +++ b/web/src/api/backend/index.ts @@ -0,0 +1,72 @@ +import { useAdminInfo } from '/@/stores/adminInfo' +import { useBaAccount } from '/@/stores/baAccount' +import { useSiteConfig } from '/@/stores/siteConfig' +import createAxios from '/@/utils/axios' + +export const url = '/admin/Index/' + +export function index() { + return createAxios({ + url: url + 'index', + method: 'get', + }) +} + +export function login(method: 'get' | 'post', params: object = {}) { + return createAxios({ + url: url + 'login', + data: params, + method: method, + }) +} + +export function logout() { + const adminInfo = useAdminInfo() + return createAxios({ + url: url + 'logout', + method: 'POST', + data: { + refreshToken: adminInfo.getToken('refresh'), + }, + }) +} + +export function baAccountCheckIn(params: object = {}) { + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + '/api/user/checkIn', + data: params, + method: 'post', + }, + { + showSuccessMessage: true, + } + ) +} + +export function baAccountGetUserInfo() { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + '/api/user/info', + method: 'get', + }, + { + anotherToken: baAccount.getToken('auth'), + } + ) +} + +export function baAccountLogout() { + const siteConfig = useSiteConfig() + const baAccount = useBaAccount() + return createAxios({ + url: siteConfig.apiUrl + '/api/user/logout', + method: 'POST', + data: { + refreshToken: baAccount.getToken('refresh'), + }, + }) +} diff --git a/web/src/api/backend/module.ts b/web/src/api/backend/module.ts new file mode 100644 index 0000000..5fc9930 --- /dev/null +++ b/web/src/api/backend/module.ts @@ -0,0 +1,190 @@ +import { useBaAccount } from '/@/stores/baAccount' +import { useSiteConfig } from '/@/stores/siteConfig' +import createAxios from '/@/utils/axios' + +const storeUrl = '/api/v7.store/' +const moduleControllerUrl = '/admin/module/' + +export function index(params: anyObj = {}) { + return createAxios({ + url: moduleControllerUrl + 'index', + method: 'get', + params: params, + }) +} + +export function modules(params: anyObj = {}) { + const siteConfig = useSiteConfig() + return createAxios({ + url: siteConfig.apiUrl + storeUrl + 'modules', + method: 'get', + params: params, + }) +} + +export function info(params: anyObj) { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + storeUrl + 'info', + method: 'get', + params: params, + }, + { + anotherToken: baAccount.getToken('auth'), + } + ) +} + +export function createOrder(params: object = {}) { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + storeUrl + 'order', + method: 'post', + params: params, + }, + { + anotherToken: baAccount.getToken('auth'), + } + ) +} + +export function payOrder(orderId: number, payType: string) { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + storeUrl + 'pay', + method: 'post', + params: { + order_id: orderId, + pay_type: payType, + }, + }, + { + anotherToken: baAccount.getToken('auth'), + showSuccessMessage: true, + } + ) +} + +export function payCheck(sn: string) { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + '/api/pay/check', + method: 'get', + params: { + sn: sn, + }, + }, + { + anotherToken: baAccount.getToken('auth'), + showCodeMessage: false, + } + ) +} + +/** + * 获取模块的可安装版本列表 + */ +export function preDownload(data: anyObj) { + const baAccount = useBaAccount() + const siteConfig = useSiteConfig() + return createAxios( + { + url: siteConfig.apiUrl + storeUrl + 'preDownload', + method: 'POST', + data, + }, + { + anotherToken: baAccount.getToken('auth'), + } + ) +} + +export function getInstallState(uid: string) { + return createAxios({ + url: moduleControllerUrl + 'state', + method: 'get', + params: { + uid: uid, + }, + }) +} + +export function postInstallModule(uid: string, orderId: number, version: string, update: boolean, extend: anyObj = {}) { + const baAccount = useBaAccount() + return createAxios( + { + url: moduleControllerUrl + 'install', + method: 'POST', + data: { + uid, + update, + version, + orderId, + token: baAccount.getToken('auth'), + extend, + }, + timeout: 3000 * 10, + }, + { + showCodeMessage: false, + } + ) +} + +export function postUninstall(uid: string) { + return createAxios( + { + url: moduleControllerUrl + 'uninstall', + method: 'post', + params: { + uid: uid, + }, + }, + { + showSuccessMessage: true, + } + ) +} + +export function changeState(params: anyObj) { + return createAxios( + { + url: moduleControllerUrl + 'changeState', + method: 'post', + data: params, + }, + { + showCodeMessage: false, + } + ) +} + +export function dependentInstallComplete(uid: string) { + return createAxios({ + url: moduleControllerUrl + 'dependentInstallComplete', + method: 'post', + params: { + uid: uid, + }, + }) +} + +export function upload(file: string) { + const baAccount = useBaAccount() + return createAxios({ + url: moduleControllerUrl + 'upload', + method: 'post', + params: { + file: file, + token: baAccount.getToken('auth'), + }, + }) +} diff --git a/web/src/api/backend/routine/AdminInfo.ts b/web/src/api/backend/routine/AdminInfo.ts new file mode 100644 index 0000000..7f08b07 --- /dev/null +++ b/web/src/api/backend/routine/AdminInfo.ts @@ -0,0 +1,37 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/routine.AdminInfo/' + +export const actionUrl = new Map([ + ['index', url + 'index'], + ['edit', url + 'edit'], + ['log', '/admin/auth.AdminLog/index'], +]) + +export function index() { + return createAxios({ + url: actionUrl.get('index'), + method: 'get', + }) +} + +export function log(filter: anyObj = {}) { + return createAxios({ + url: actionUrl.get('log'), + method: 'get', + params: filter, + }) +} + +export function postData(data: anyObj) { + return createAxios( + { + url: actionUrl.get('edit'), + method: 'post', + data: data, + }, + { + showSuccessMessage: true, + } + ) +} diff --git a/web/src/api/backend/routine/config.ts b/web/src/api/backend/routine/config.ts new file mode 100644 index 0000000..0adf4b7 --- /dev/null +++ b/web/src/api/backend/routine/config.ts @@ -0,0 +1,59 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/routine.Config/' + +export const actionUrl = new Map([ + ['index', url + 'index'], + ['add', url + 'add'], + ['edit', url + 'edit'], + ['del', url + 'del'], + ['sendTestMail', url + 'sendTestMail'], +]) + +export function index() { + return createAxios({ + url: actionUrl.get('index'), + method: 'get', + }) +} + +export function postData(action: string, data: anyObj) { + return createAxios( + { + url: actionUrl.get(action), + method: 'post', + data: data, + }, + { + showSuccessMessage: true, + } + ) +} + +export function del(ids: string[]) { + return createAxios( + { + url: actionUrl.get('del'), + method: 'DELETE', + params: { + ids: ids, + }, + }, + { + showSuccessMessage: true, + } + ) +} + +export function postSendTestMail(data: anyObj, mail: string) { + return createAxios( + { + url: actionUrl.get('sendTestMail'), + method: 'POST', + data: Object.assign({}, data, { testMail: mail }), + }, + { + showSuccessMessage: true, + } + ) +} diff --git a/web/src/api/backend/security/dataRecycle.ts b/web/src/api/backend/security/dataRecycle.ts new file mode 100644 index 0000000..8490e33 --- /dev/null +++ b/web/src/api/backend/security/dataRecycle.ts @@ -0,0 +1,10 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/security.DataRecycle/' + +export function add() { + return createAxios({ + url: url + 'add', + method: 'get', + }) +} diff --git a/web/src/api/backend/security/dataRecycleLog.ts b/web/src/api/backend/security/dataRecycleLog.ts new file mode 100644 index 0000000..3086a52 --- /dev/null +++ b/web/src/api/backend/security/dataRecycleLog.ts @@ -0,0 +1,28 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/security.DataRecycleLog/' + +export function restore(ids: string[]) { + return createAxios( + { + url: url + 'restore', + method: 'POST', + data: { + ids: ids, + }, + }, + { + showSuccessMessage: true, + } + ) +} + +export function info(id: string) { + return createAxios({ + url: url + 'info', + method: 'get', + params: { + id: id, + }, + }) +} diff --git a/web/src/api/backend/security/sensitiveData.ts b/web/src/api/backend/security/sensitiveData.ts new file mode 100644 index 0000000..1aeab91 --- /dev/null +++ b/web/src/api/backend/security/sensitiveData.ts @@ -0,0 +1,10 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/security.SensitiveData/' + +export function add() { + return createAxios({ + url: url + 'add', + method: 'get', + }) +} diff --git a/web/src/api/backend/security/sensitiveDataLog.ts b/web/src/api/backend/security/sensitiveDataLog.ts new file mode 100644 index 0000000..3dfba25 --- /dev/null +++ b/web/src/api/backend/security/sensitiveDataLog.ts @@ -0,0 +1,28 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/security.SensitiveDataLog/' + +export function rollback(ids: string[]) { + return createAxios( + { + url: url + 'rollback', + method: 'POST', + data: { + ids: ids, + }, + }, + { + showSuccessMessage: true, + } + ) +} + +export function info(id: string) { + return createAxios({ + url: url + 'info', + method: 'get', + params: { + id: id, + }, + }) +} diff --git a/web/src/api/backend/user/group.ts b/web/src/api/backend/user/group.ts new file mode 100644 index 0000000..010f231 --- /dev/null +++ b/web/src/api/backend/user/group.ts @@ -0,0 +1,8 @@ +import createAxios from '/@/utils/axios' + +export function getUserRules() { + return createAxios({ + url: '/admin/user.Rule/index', + method: 'get', + }) +} diff --git a/web/src/api/backend/user/moneyLog.ts b/web/src/api/backend/user/moneyLog.ts new file mode 100644 index 0000000..e2078fe --- /dev/null +++ b/web/src/api/backend/user/moneyLog.ts @@ -0,0 +1,13 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/user.MoneyLog/' + +export function add(userId: string) { + return createAxios({ + url: url + 'add', + method: 'get', + params: { + userId: userId, + }, + }) +} diff --git a/web/src/api/backend/user/scoreLog.ts b/web/src/api/backend/user/scoreLog.ts new file mode 100644 index 0000000..9262d2a --- /dev/null +++ b/web/src/api/backend/user/scoreLog.ts @@ -0,0 +1,13 @@ +import createAxios from '/@/utils/axios' + +export const url = '/admin/user.ScoreLog/' + +export function add(userId: string) { + return createAxios({ + url: url + 'add', + method: 'get', + params: { + userId: userId, + }, + }) +} diff --git a/web/src/api/common.ts b/web/src/api/common.ts new file mode 100644 index 0000000..ab650ba --- /dev/null +++ b/web/src/api/common.ts @@ -0,0 +1,378 @@ +import createAxios from '/@/utils/axios' +import { isAdminApp, checkFileMimetype } from '/@/utils/common' +import { getUrl } from '/@/utils/axios' +import { useAdminInfo } from '/@/stores/adminInfo' +import { useUserInfo } from '/@/stores/userInfo' +import { ElNotification, type UploadRawFile } from 'element-plus' +import { useSiteConfig } from '/@/stores/siteConfig' +import { state as uploadExpandState, fileUpload as uploadExpand } from '/@/components/mixins/baUpload' +import type { AxiosRequestConfig } from 'axios' +import { uuid } from '/@/utils/random' +import { i18n } from '../lang' +import { adminBaseRoutePath } from '/@/router/static/adminBase' +import { SYSTEM_ZINDEX } from '/@/stores/constant/common' + +/* + * 公共请求函数和Url定义 + */ + +// Admin模块 +export const adminUploadUrl = '/admin/ajax/upload' +export const adminBuildSuffixSvgUrl = adminBaseRoutePath + '/ajax/buildSuffixSvg' +export const adminAreaUrl = '/admin/ajax/area' +export const getTablePkUrl = '/admin/ajax/getTablePk' +export const getTableListUrl = '/admin/ajax/getTableList' +export const getTableFieldListUrl = '/admin/ajax/getTableFieldList' +export const getDatabaseConnectionListUrl = '/admin/ajax/getDatabaseConnectionList' +export const terminalUrl = adminBaseRoutePath + '/ajax/terminal' +export const changeTerminalConfigUrl = '/admin/ajax/changeTerminalConfig' +export const clearCacheUrl = '/admin/ajax/clearCache' + +// 公共 +export const captchaUrl = '/api/common/captcha' +export const clickCaptchaUrl = '/api/common/clickCaptcha' +export const checkClickCaptchaUrl = '/api/common/checkClickCaptcha' +export const refreshTokenUrl = '/api/common/refreshToken' + +// api模块(前台) +export const apiUploadUrl = '/api/ajax/upload' +export const apiBuildSuffixSvgUrl = '/api/ajax/buildSuffixSvg' +export const apiAreaUrl = '/api/ajax/area' +export const apiSendSms = '/api/Sms/send' +export const apiSendEms = '/api/Ems/send' + +/** + * 上传文件 + */ +export function fileUpload(fd: FormData, params: anyObj = {}, forceLocal = false, config: AxiosRequestConfig = {}): ApiPromise { + let errorMsg = '' + const file = fd.get('file') as UploadRawFile + const siteConfig = useSiteConfig() + + if (!file.name || typeof file.size == 'undefined') { + errorMsg = i18n.global.t('utils.The data of the uploaded file is incomplete!') + } else if (!checkFileMimetype(file.name, file.type)) { + errorMsg = i18n.global.t('utils.The type of uploaded file is not allowed!') + } else if (file.size > siteConfig.upload.maxSize) { + errorMsg = i18n.global.t('utils.The size of the uploaded file exceeds the allowed range!') + } + if (errorMsg) { + return new Promise((resolve, reject) => { + ElNotification({ + type: 'error', + message: errorMsg, + zIndex: SYSTEM_ZINDEX, + }) + reject(errorMsg) + }) + } + + if (!forceLocal && uploadExpandState() == 'enable') { + return uploadExpand(fd, params, config) + } + + return createAxios({ + url: isAdminApp() ? adminUploadUrl : apiUploadUrl, + method: 'POST', + data: fd, + params: params, + timeout: 0, + ...config, + }) +} + +/** + * 生成文件后缀icon的svg图片 + * @param suffix 后缀名 + * @param background 背景色,如:rgb(255,255,255) + */ +export function buildSuffixSvgUrl(suffix: string, background = '') { + const adminInfo = useAdminInfo() + return ( + getUrl() + + (isAdminApp() ? adminBuildSuffixSvgUrl : apiBuildSuffixSvgUrl) + + '?batoken=' + + adminInfo.getToken() + + '&suffix=' + + suffix + + (background ? '&background=' + background : '') + + '&server=1' + ) +} + +/** + * 获取地区数据 + */ +export function getArea(values: number[]) { + const params: { province?: number; city?: number; uuid?: string } = {} + if (values[0]) { + params.province = values[0] + } + if (values[1]) { + params.city = values[1] + } + params.uuid = uuid() + return createAxios({ + url: isAdminApp() ? adminAreaUrl : apiAreaUrl, + method: 'GET', + params: params, + }) +} + +/** + * 发送短信 + */ +export function sendSms(mobile: string, templateCode: string, extend: anyObj = {}) { + return createAxios( + { + url: apiSendSms, + method: 'POST', + data: { + mobile: mobile, + template_code: templateCode, + ...extend, + }, + }, + { + showSuccessMessage: true, + } + ) +} + +/** + * 发送邮件 + */ +export function sendEms(email: string, event: string, extend: anyObj = {}) { + return createAxios( + { + url: apiSendEms, + method: 'POST', + data: { + email: email, + event: event, + ...extend, + }, + }, + { + showSuccessMessage: true, + } + ) +} + +/** + * 缓存清理接口 + */ +export function postClearCache(type: string) { + return createAxios( + { + url: clearCacheUrl, + method: 'POST', + data: { + type: type, + }, + }, + { + showSuccessMessage: true, + } + ) +} + +/** + * 构建命令执行窗口url + */ +export function buildTerminalUrl(commandKey: string, uuid: string, extend: string) { + const adminInfo = useAdminInfo() + return ( + getUrl() + terminalUrl + '?command=' + commandKey + '&uuid=' + uuid + '&extend=' + extend + '&batoken=' + adminInfo.getToken() + '&server=1' + ) +} + +/** + * 请求修改终端配置 + */ +export function postChangeTerminalConfig(data: { manager?: string; port?: string }) { + return createAxios({ + url: changeTerminalConfigUrl, + method: 'POST', + data: data, + }) +} + +/** + * 远程下拉框数据获取 + */ +export function getSelectData(remoteUrl: string, q: string, params: anyObj = {}) { + return createAxios({ + url: remoteUrl, + method: 'get', + params: { + select: true, + quickSearch: q, + ...params, + }, + }) +} + +export function buildCaptchaUrl() { + return getUrl() + captchaUrl + '?server=1' +} + +export function getCaptchaData(id: string, apiBaseURL: string) { + return createAxios({ + url: apiBaseURL + clickCaptchaUrl, + method: 'get', + params: { + id, + }, + }) +} + +export function checkClickCaptcha(id: string, info: string, unset: boolean, apiBaseURL: string) { + return createAxios( + { + url: apiBaseURL + checkClickCaptchaUrl, + method: 'post', + data: { + id, + info, + unset, + }, + }, + { + showCodeMessage: false, + } + ) +} + +export function getTablePk(table: string, connection = '') { + return createAxios({ + url: getTablePkUrl, + method: 'get', + params: { + table: table, + connection: connection, + }, + }) +} + +/** + * 获取数据表的字段 + * @param table 数据表名 + * @param clean 只要干净的字段注释(只要字段标题) + */ +export function getTableFieldList(table: string, clean = true, connection = '') { + return createAxios({ + url: getTableFieldListUrl, + method: 'get', + params: { + table: table, + clean: clean ? 1 : 0, + connection: connection, + }, + }) +} + +export function refreshToken() { + const adminInfo = useAdminInfo() + const userInfo = useUserInfo() + return createAxios({ + url: refreshTokenUrl, + method: 'POST', + data: { + refreshToken: isAdminApp() ? adminInfo.getToken('refresh') : userInfo.getToken('refresh'), + }, + }) +} + +/** + * 快速生成一个控制器的 增、删、改、查、排序 接口的请求方法 + * 本 class 实例通常直接传递给 baTable 使用,开发者可重写本类的方法,亦可直接向 baTable 传递自定义的 API 请求类 + * 表格相关网络请求无需局限于本类,开发者可于 /src/api/ 目录创建自定义的接口请求函数,并于需要的地方导入使用即可 + */ +export class baTableApi { + private controllerUrl + public actionUrl + + constructor(controllerUrl: string) { + this.controllerUrl = controllerUrl + this.actionUrl = new Map([ + ['index', controllerUrl + 'index'], + ['add', controllerUrl + 'add'], + ['edit', controllerUrl + 'edit'], + ['del', controllerUrl + 'del'], + ['sortable', controllerUrl + 'sortable'], + ]) + } + + /** + * 表格查看接口的请求方法 + * @param filter 数据过滤条件 + */ + index(filter: BaTable['filter'] = {}) { + return createAxios({ + url: this.actionUrl.get('index'), + method: 'get', + params: filter, + }) + } + + /** + * 获取被编辑行数据 + * @param params 被编辑行主键等 + */ + edit(params: anyObj) { + return createAxios({ + url: this.actionUrl.get('edit'), + method: 'get', + params, + }) + } + + /** + * 表格删除接口的请求方法 + * @param ids 被删除数据的主键数组 + */ + del(ids: string[]) { + return createAxios( + { + url: this.actionUrl.get('del'), + method: 'DELETE', + params: { + ids, + }, + }, + { + showSuccessMessage: true, + } + ) + } + + /** + * 向指定接口 POST 数据,本方法虽然较为通用,但请不要局限于此,开发者可于 /src/api/ 目录创建自定义的接口请求函数,并于需要的地方导入使用即可 + * @param action 请求的接口,比如 add、edit + * @param data 要 POST 的数据 + */ + postData(action: string, data: anyObj) { + return createAxios( + { + url: this.actionUrl.has(action) ? this.actionUrl.get(action) : this.controllerUrl + action, + method: 'post', + data, + }, + { + showSuccessMessage: true, + } + ) + } + + /** + * 表格行排序接口的请求方法 + */ + sortable(data: anyObj) { + return createAxios({ + url: this.actionUrl.get('sortable'), + method: 'post', + data, + }) + } +} diff --git a/web/src/api/frontend/index.ts b/web/src/api/frontend/index.ts new file mode 100644 index 0000000..051eb67 --- /dev/null +++ b/web/src/api/frontend/index.ts @@ -0,0 +1,56 @@ +import createAxios from '/@/utils/axios' +import { useSiteConfig } from '/@/stores/siteConfig' +import { useMemberCenter } from '/@/stores/memberCenter' +import { debounce, setTitleFromRoute } from '/@/utils/common' +import { handleFrontendRoute } from '/@/utils/router' +import { useUserInfo } from '/@/stores/userInfo' +import router from '/@/router/index' +import { isEmpty } from 'lodash-es' + +export const indexUrl = '/api/index/' + +/** + * 前台初始化请求,获取站点配置信息,动态路由信息等 + * 1. 首次初始化携带了会员token时,一共只初始化一次 + * 2. 首次初始化未带会员token,将在登录后再初始化一次 + */ +export function initialize(callback?: (res: ApiResponse) => void, requiredLogin?: boolean) { + debounce(() => { + if (router.currentRoute.value.meta.initialize === false) return + + const userInfo = useUserInfo() + const siteConfig = useSiteConfig() + if (!userInfo.isLogin() && siteConfig.initialize) return + if (userInfo.isLogin() && siteConfig.userInitialize) return + + const memberCenter = useMemberCenter() + + createAxios({ + url: indexUrl + 'index', + method: 'get', + params: { + requiredLogin: requiredLogin ? 1 : 0, + }, + }).then((res) => { + handleFrontendRoute(res.data.rules, res.data.menus) + siteConfig.dataFill(res.data.site) + memberCenter.setStatus(res.data.openMemberCenter) + + if (!isEmpty(res.data.userInfo)) { + userInfo.dataFill(res.data.userInfo) + + // 请求到会员信息才设置会员中心初始化是成功的 + siteConfig.setUserInitialize(true) + } + + if (!res.data.openMemberCenter) memberCenter.setLayoutMode('Disable') + + siteConfig.setInitialize(true) + + // 根据当前路由重设页面标题 + setTitleFromRoute() + + typeof callback == 'function' && callback(res) + }) + }, 200)() +} diff --git a/web/src/api/frontend/user/index.ts b/web/src/api/frontend/user/index.ts new file mode 100644 index 0000000..069a982 --- /dev/null +++ b/web/src/api/frontend/user/index.ts @@ -0,0 +1,120 @@ +import createAxios from '/@/utils/axios' +import { useUserInfo } from '/@/stores/userInfo' + +export const userUrl = '/api/user/' +export const accountUrl = '/api/account/' + +export function checkIn(method: 'get' | 'post', params: object = {}) { + return createAxios({ + url: userUrl + 'checkIn', + data: params, + method: method, + }) +} + +export function overview() { + return createAxios({ + url: accountUrl + 'overview', + method: 'get', + }) +} + +export function postProfile(params: anyObj) { + return createAxios( + { + url: accountUrl + 'profile', + method: 'POST', + data: params, + }, + { + showSuccessMessage: true, + } + ) +} + +export function getProfile() { + return createAxios({ + url: accountUrl + 'profile', + method: 'get', + }) +} + +export function postVerification(data: anyObj) { + return createAxios({ + url: accountUrl + 'verification', + method: 'post', + data: data, + }) +} + +export function postChangeBind(data: anyObj) { + return createAxios( + { + url: accountUrl + 'changeBind', + method: 'post', + data: data, + }, + { + showSuccessMessage: true, + } + ) +} + +export function changePassword(params: anyObj) { + return createAxios( + { + url: accountUrl + 'changePassword', + method: 'POST', + data: params, + }, + { + showSuccessMessage: true, + } + ) +} + +export function getBalanceLog(page: number, pageSize: number) { + return createAxios({ + url: accountUrl + 'balance', + method: 'GET', + params: { + page: page, + limit: pageSize, + }, + }) +} + +export function getIntegralLog(page: number, pageSize: number) { + return createAxios({ + url: accountUrl + 'integral', + method: 'GET', + params: { + page: page, + limit: pageSize, + }, + }) +} + +export function postLogout() { + const userInfo = useUserInfo() + return createAxios({ + url: userUrl + 'logout', + method: 'POST', + data: { + refreshToken: userInfo.getToken('refresh'), + }, + }) +} + +export function retrievePassword(params: anyObj) { + return createAxios( + { + url: accountUrl + 'retrievePassword', + method: 'POST', + data: params, + }, + { + showSuccessMessage: true, + } + ) +} diff --git a/web/src/assets/bg-dark.jpg b/web/src/assets/bg-dark.jpg new file mode 100644 index 0000000..c88faff Binary files /dev/null and b/web/src/assets/bg-dark.jpg differ diff --git a/web/src/assets/bg.jpg b/web/src/assets/bg.jpg new file mode 100644 index 0000000..ddf4655 Binary files /dev/null and b/web/src/assets/bg.jpg differ diff --git a/web/src/assets/dashboard/coffee.svg b/web/src/assets/dashboard/coffee.svg new file mode 100644 index 0000000..bd88779 --- /dev/null +++ b/web/src/assets/dashboard/coffee.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/dashboard/header-1.svg b/web/src/assets/dashboard/header-1.svg new file mode 100644 index 0000000..f7dc22c --- /dev/null +++ b/web/src/assets/dashboard/header-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/dark.svg b/web/src/assets/icons/dark.svg new file mode 100644 index 0000000..3ef1cf0 --- /dev/null +++ b/web/src/assets/icons/dark.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/web/src/assets/icons/full-screen-cancel.svg b/web/src/assets/icons/full-screen-cancel.svg new file mode 100644 index 0000000..e08e22b --- /dev/null +++ b/web/src/assets/icons/full-screen-cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/lang.svg b/web/src/assets/icons/lang.svg new file mode 100644 index 0000000..8fe9126 --- /dev/null +++ b/web/src/assets/icons/lang.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/icons/light.svg b/web/src/assets/icons/light.svg new file mode 100644 index 0000000..e1cc97c --- /dev/null +++ b/web/src/assets/icons/light.svg @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/web/src/assets/icons/logo.svg b/web/src/assets/icons/logo.svg new file mode 100644 index 0000000..da77266 --- /dev/null +++ b/web/src/assets/icons/logo.svg @@ -0,0 +1,102 @@ + + + + diff --git a/web/src/assets/icons/terminal.svg b/web/src/assets/icons/terminal.svg new file mode 100644 index 0000000..b0edca4 --- /dev/null +++ b/web/src/assets/icons/terminal.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/web/src/assets/index/index-cover.svg b/web/src/assets/index/index-cover.svg new file mode 100644 index 0000000..2abce1c --- /dev/null +++ b/web/src/assets/index/index-cover.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/login-header.png b/web/src/assets/login-header.png new file mode 100644 index 0000000..545b9c0 Binary files /dev/null and b/web/src/assets/login-header.png differ diff --git a/web/src/assets/logo.png b/web/src/assets/logo.png new file mode 100644 index 0000000..c39e983 Binary files /dev/null and b/web/src/assets/logo.png differ diff --git a/web/src/assets/qr.png b/web/src/assets/qr.png new file mode 100644 index 0000000..c55172d Binary files /dev/null and b/web/src/assets/qr.png differ diff --git a/web/src/components/baInput/components/array.vue b/web/src/components/baInput/components/array.vue new file mode 100644 index 0000000..c9f46de --- /dev/null +++ b/web/src/components/baInput/components/array.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/web/src/components/baInput/components/baUpload.vue b/web/src/components/baInput/components/baUpload.vue new file mode 100644 index 0000000..25d86af --- /dev/null +++ b/web/src/components/baInput/components/baUpload.vue @@ -0,0 +1,518 @@ + + + + + diff --git a/web/src/components/baInput/components/editor.vue b/web/src/components/baInput/components/editor.vue new file mode 100644 index 0000000..5d52805 --- /dev/null +++ b/web/src/components/baInput/components/editor.vue @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/web/src/components/baInput/components/iconSelector.vue b/web/src/components/baInput/components/iconSelector.vue new file mode 100644 index 0000000..4c527da --- /dev/null +++ b/web/src/components/baInput/components/iconSelector.vue @@ -0,0 +1,286 @@ + + + + + diff --git a/web/src/components/baInput/components/remoteSelect.vue b/web/src/components/baInput/components/remoteSelect.vue new file mode 100644 index 0000000..ff29b9f --- /dev/null +++ b/web/src/components/baInput/components/remoteSelect.vue @@ -0,0 +1,352 @@ + + + + + diff --git a/web/src/components/baInput/components/selectFile.vue b/web/src/components/baInput/components/selectFile.vue new file mode 100644 index 0000000..c1860f6 --- /dev/null +++ b/web/src/components/baInput/components/selectFile.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/web/src/components/baInput/helper.ts b/web/src/components/baInput/helper.ts new file mode 100644 index 0000000..7ceb029 --- /dev/null +++ b/web/src/components/baInput/helper.ts @@ -0,0 +1,206 @@ +import type { FieldData } from './index' + +export const npuaFalse = () => { + return { + null: false, + primaryKey: false, + unsigned: false, + autoIncrement: false, + } +} + +/** + * 所有 Input 支持的类型对应的数据字段类型等数据(默认/示例设计) + */ +export const fieldData: FieldData = { + string: { + type: 'varchar', + length: 255, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + password: { + type: 'varchar', + length: 32, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + number: { + type: 'int', + length: 10, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + }, + radio: { + type: 'enum', + length: 0, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + }, + checkbox: { + type: 'set', + length: 0, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + }, + switch: { + type: 'tinyint', + length: 1, + precision: 0, + default: '0', + defaultType: 'INPUT', + ...npuaFalse(), + unsigned: true, + }, + textarea: { + type: 'varchar', + length: 255, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + array: { + type: 'varchar', + length: 255, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + datetime: { + type: 'bigint', + length: 16, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + unsigned: true, + }, + year: { + type: 'year', + length: 4, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + }, + date: { + type: 'date', + length: 0, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + }, + time: { + type: 'time', + length: 0, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + }, + select: { + type: 'enum', + length: 0, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + }, + selects: { + type: 'varchar', + length: 255, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + remoteSelect: { + type: 'int', + length: 10, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + unsigned: true, + }, + remoteSelects: { + type: 'varchar', + length: 255, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + editor: { + type: 'text', + length: 0, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + }, + city: { + type: 'varchar', + length: 100, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + image: { + type: 'varchar', + length: 255, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + images: { + type: 'varchar', + length: 1500, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + file: { + type: 'varchar', + length: 255, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + files: { + type: 'varchar', + length: 1500, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + icon: { + type: 'varchar', + length: 50, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, + color: { + type: 'varchar', + length: 50, + precision: 0, + defaultType: 'EMPTY STRING', + ...npuaFalse(), + }, +} + +export const stringToArray = (val: string | string[]) => { + if (typeof val === 'string') { + return val == '' ? [] : val.split(',') + } else { + return val as string[] + } +} diff --git a/web/src/components/baInput/index.ts b/web/src/components/baInput/index.ts new file mode 100644 index 0000000..a46d899 --- /dev/null +++ b/web/src/components/baInput/index.ts @@ -0,0 +1,218 @@ +import type { Component, CSSProperties } from 'vue' + +/** + * 支持的输入框类型 + * 若您正在设计数据表,可以找到 ./helper.ts 文件来参考对应类型的:数据字段设计示例 + */ +export const inputTypes = [ + 'string', + 'password', + 'number', + 'radio', + 'checkbox', + 'switch', + 'textarea', + 'array', + 'datetime', + 'year', + 'date', + 'time', + 'select', + 'selects', + 'remoteSelect', + 'remoteSelects', + 'editor', + 'city', + 'image', + 'images', + 'file', + 'files', + 'icon', + 'color', +] +export type ModelValueTypes = string | number | boolean | object + +export interface InputData { + // 内容,比如radio的选项列表数据,格式为对象或者数组:{ a: '选项1', b: '选项2' } or [{value: '1', label: 2, disabled: false}, {...}] + content?: any + // 需要生成子级元素时,子级元素属性(比如radio) + childrenAttr?: anyObj + // 城市选择器等级,1=省,2=市,3=区 + level?: number +} + +/** + * input可用属性,用于代码提示,渲染不同输入组件时,需要的属性是不一样的 + * https://element-plus.org/zh-CN/component/input.html#input-属性 + */ +export interface InputAttr extends InputData { + id?: string + name?: string + type?: string + placeholder?: string + maxlength?: string | number + minlength?: string | number + showWordLimit?: boolean + clearable?: boolean + showPassword?: boolean + disabled?: boolean + size?: 'large' | 'default' | 'small' + prefixIcon?: string | Component + suffixIcon?: string | Component + rows?: number + border?: boolean + autosize?: boolean | anyObj + autocomplete?: string + readonly?: boolean + max?: string | number + min?: string | number + step?: string | number + resize?: 'none' | 'both' | 'horizontal' | 'vertical' + autofocus?: boolean + form?: string + label?: string + tabindex?: string | number + validateEvent?: boolean + inputStyle?: anyObj + activeValue?: string | number | boolean + inactiveValue?: string | number | boolean + emptyValues?: any[] + valueOnClear?: string | number | boolean | Function + // DateTimePicker属性 + editable?: boolean + startPlaceholder?: string + endPlaceholder?: string + timeArrowControl?: boolean + format?: string + popperClass?: string + rangeSeparator?: string + defaultValue?: Date + defaultTime?: Date | Date[] + valueFormat?: string + unlinkPanels?: boolean + clearIcon?: string | Component + shortcuts?: { text: string; value: Date | Function }[] + disabledDate?: Function + cellClassName?: Function + teleported?: boolean + // select属性 + multiple?: boolean + valueKey?: string + collapseTags?: string + collapseTagsTooltip?: boolean + multipleLimit?: number + effect?: 'dark' | 'light' + filterable?: boolean + allowCreate?: boolean + filterMethod?: Function + remote?: false // 禁止使用远程搜索,如需使用请使用单独封装好的 remoteSelect 组件 + remoteMethod?: false + labelFormatter?: (optionData: anyObj, optionKey: string) => string + noMatchText?: string + noDataText?: string + reserveKeyword?: boolean + defaultFirstOption?: boolean + popperAppendToBody?: boolean + persistent?: boolean + automaticDropdown?: boolean + fitInputWidth?: boolean + tagType?: 'success' | 'info' | 'warning' | 'danger' + params?: anyObj + // 远程select属性 + pk?: string + field?: string + remoteUrl?: string + tooltipParams?: anyObj + escBlur?: boolean + // 图标选择器属性 + showIconName?: boolean + placement?: string + title?: string + // 颜色选择器 + showAlpha?: boolean + colorFormat?: string + predefine?: string[] + // 图片文件上传属性 + action?: string + headers?: anyObj + method?: string + data?: anyObj + withCredentials?: boolean + showFileList?: boolean + drag?: boolean + accept?: string + listType?: string + autoUpload?: boolean + limit?: number + hideSelectFile?: boolean + returnFullUrl?: boolean + forceLocal?: boolean + hideImagePlusOnOverLimit?: boolean + // editor属性 + height?: string + mode?: string + editorStyle?: CSSProperties + style?: CSSProperties + toolbarConfig?: anyObj + editorConfig?: anyObj + editorType?: string + preview?: boolean + language?: string + theme?: 'light' | 'dark' + toolbarsExclude?: string[] + fileForceLocal?: boolean + // array组件属性 + keyTitle?: string + valueTitle?: string + // 返回数据类型 + dataType?: string + // 是否渲染为 button(radio 和 checkbox) + button?: boolean + // 事件 + onPreview?: Function + onRemove?: Function + onSuccess?: Function + onError?: Function + onProgress?: Function + onExceed?: Function + onBeforeUpload?: Function + onBeforeRemove?: Function + onChange?: Function + onInput?: Function + onVisibleChange?: Function + onRemoveTag?: Function + onClear?: Function + onBlur?: Function + onFocus?: Function + onCalendarChange?: Function + onPanelChange?: Function + onActiveChange?: Function + onRow?: Function + [key: string]: any +} + +/** + * Input 支持的类型对应的数据字段设计数据 + */ +export interface FieldData { + [key: string]: { + // 数据类型 + type: string + // 长度 + length: number + // 小数点 + precision: number + // 默认值 + default?: string + // 默认值类型:INPUT=输入,EMPTY STRING=空字符串,NULL=NULL,NONE=无 + defaultType: 'INPUT' | 'EMPTY STRING' | 'NULL' | 'NONE' + // 允许 null + null: boolean + // 主键 + primaryKey: boolean + // 无符号 + unsigned: boolean + // 自动递增 + autoIncrement: boolean + } +} diff --git a/web/src/components/baInput/index.vue b/web/src/components/baInput/index.vue new file mode 100644 index 0000000..cc905f2 --- /dev/null +++ b/web/src/components/baInput/index.vue @@ -0,0 +1,525 @@ + + + diff --git a/web/src/components/clickCaptcha/index.ts b/web/src/components/clickCaptcha/index.ts new file mode 100644 index 0000000..db89488 --- /dev/null +++ b/web/src/components/clickCaptcha/index.ts @@ -0,0 +1,47 @@ +import { createVNode, render } from 'vue' +import ClickCaptchaConstructor from './index.vue' +import { shortUuid } from '/@/utils/random' + +interface ClickCaptchaOptions { + // 验证码弹窗的自定义class + class?: string + // 前端验证成功时立即清理验证码数据,不可再进行二次验证,不开启则 600s 后自动清理数据 + unset?: boolean + // 验证失败的提示信息 + error?: string + // 验证成功的提示信息 + success?: string + // 验证码 API 的基础 URL,默认为当前服务端 URL(VITE_AXIOS_BASE_URL) + apiBaseURL?: string +} + +/** + * 弹出点击验证码 + * @param uuid 开发者自定义的唯一标识 + * @param callback 验证成功的回调,业务接口可通过 captchaInfo 进行二次验证 + * @param options + */ +const clickCaptcha = (uuid: string, callback?: (captchaInfo: string) => void, options: ClickCaptchaOptions = {}) => { + const container = document.createElement('div') + const vnode = createVNode(ClickCaptchaConstructor, { + uuid, + callback, + ...options, + key: shortUuid(), + onDestroy: () => { + render(null, container) + }, + }) + render(vnode, container) + document.body.appendChild(container.firstElementChild!) +} + +/** + * 组件的 props 类型定义 + */ +export interface Props extends ClickCaptchaOptions { + uuid: string + callback?: (captchaInfo: string) => void +} + +export default clickCaptcha diff --git a/web/src/components/clickCaptcha/index.vue b/web/src/components/clickCaptcha/index.vue new file mode 100644 index 0000000..1c8106e --- /dev/null +++ b/web/src/components/clickCaptcha/index.vue @@ -0,0 +1,221 @@ + + + + + diff --git a/web/src/components/contextmenu/index.vue b/web/src/components/contextmenu/index.vue new file mode 100644 index 0000000..48bc758 --- /dev/null +++ b/web/src/components/contextmenu/index.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/web/src/components/contextmenu/interface.ts b/web/src/components/contextmenu/interface.ts new file mode 100644 index 0000000..a17574a --- /dev/null +++ b/web/src/components/contextmenu/interface.ts @@ -0,0 +1,20 @@ +export interface Axis { + x: number + y: number +} + +export interface ContextMenuItem { + name: string + label: string + icon?: string + disabled?: boolean +} + +export interface ContextMenuItemClickEmitArg extends ContextMenuItem { + sourceData?: T +} + +export interface Props { + width?: number + items: ContextMenuItem[] +} diff --git a/web/src/components/formItem/createData.vue b/web/src/components/formItem/createData.vue new file mode 100644 index 0000000..16be18a --- /dev/null +++ b/web/src/components/formItem/createData.vue @@ -0,0 +1,304 @@ + + + + + + + diff --git a/web/src/components/formItem/index.ts b/web/src/components/formItem/index.ts new file mode 100644 index 0000000..c2fa777 --- /dev/null +++ b/web/src/components/formItem/index.ts @@ -0,0 +1,13 @@ +import type { CSSProperties } from 'vue' +import type { FormItemProps, ElTooltipProps } from 'element-plus' + +export interface FormItemAttr extends Partial> { + // 通用属性名称的键入提示 + id?: string + class?: string + style?: CSSProperties + // 块级输入帮助信息 + blockHelp?: string + // 输入提示信息(使用 el-tooltip 渲染) + tip?: string | Partial +} diff --git a/web/src/components/formItem/index.vue b/web/src/components/formItem/index.vue new file mode 100644 index 0000000..12a09e9 --- /dev/null +++ b/web/src/components/formItem/index.vue @@ -0,0 +1,163 @@ + + + diff --git a/web/src/components/icon/index.vue b/web/src/components/icon/index.vue new file mode 100644 index 0000000..d4a65dc --- /dev/null +++ b/web/src/components/icon/index.vue @@ -0,0 +1,41 @@ + diff --git a/web/src/components/icon/svg/index.ts b/web/src/components/icon/svg/index.ts new file mode 100644 index 0000000..0209946 --- /dev/null +++ b/web/src/components/icon/svg/index.ts @@ -0,0 +1,69 @@ +import { readFileSync, readdirSync } from 'fs' + +let idPerfix = '' +const iconNames: string[] = [] +const svgTitle = /+].*?)>/ +const clearHeightWidth = /(width|height)="([^>+].*?)"/g +const hasViewBox = /(viewBox="[^>+].*?")/g +const clearReturn = /(\r)|(\n)/g +// 清理 svg 的 fill +const clearFill = /(fill="[^>+].*?")/g + +function findSvgFile(dir: string): string[] { + const svgRes = [] + const dirents = readdirSync(dir, { + withFileTypes: true, + }) + for (const dirent of dirents) { + iconNames.push(`${idPerfix}-${dirent.name.replace('.svg', '')}`) + if (dirent.isDirectory()) { + svgRes.push(...findSvgFile(dir + dirent.name + '/')) + } else { + const svg = readFileSync(dir + dirent.name) + .toString() + .replace(clearReturn, '') + .replace(clearFill, 'fill=""') + .replace(svgTitle, ($1, $2) => { + let width = 0 + let height = 0 + let content = $2.replace(clearHeightWidth, (s1: string, s2: string, s3: number) => { + if (s2 === 'width') { + width = s3 + } else if (s2 === 'height') { + height = s3 + } + return '' + }) + if (!hasViewBox.test($2)) { + content += `viewBox="0 0 ${width} ${height}"` + } + return `` + }) + .replace('', '') + svgRes.push(svg) + } + } + return svgRes +} + +export const svgBuilder = (path: string, perfix = 'local') => { + if (path === '') return + idPerfix = perfix + const res = findSvgFile(path) + return { + name: 'svg-transform', + transformIndexHtml(html: string) { + return html.replace( + '', + ` + + + ${res.join('')} + + ` + ) + }, + } +} diff --git a/web/src/components/icon/svg/index.vue b/web/src/components/icon/svg/index.vue new file mode 100644 index 0000000..10cf4e3 --- /dev/null +++ b/web/src/components/icon/svg/index.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/web/src/components/mixins/baUpload.ts b/web/src/components/mixins/baUpload.ts new file mode 100644 index 0000000..29b566e --- /dev/null +++ b/web/src/components/mixins/baUpload.ts @@ -0,0 +1,11 @@ +import type { AxiosRequestConfig } from 'axios' + +export const state: () => 'disable' | 'enable' = () => 'disable' + +export function fileUpload(fd: FormData, params: anyObj = {}, config: AxiosRequestConfig = {}): ApiPromise { + // 上传扩展,定义此函数,并将上方的 state 设定为 enable,系统可自动使用此函数进行上传 + return new Promise((resolve, reject) => { + console.log(fd, params, config) + reject('未定义') + }) +} diff --git a/web/src/components/mixins/editor/default.vue b/web/src/components/mixins/editor/default.vue new file mode 100644 index 0000000..a780fce --- /dev/null +++ b/web/src/components/mixins/editor/default.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/web/src/components/mixins/loginFooter.vue b/web/src/components/mixins/loginFooter.vue new file mode 100644 index 0000000..4dcc65f --- /dev/null +++ b/web/src/components/mixins/loginFooter.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/web/src/components/mixins/loginMounted.ts b/web/src/components/mixins/loginMounted.ts new file mode 100644 index 0000000..3635747 --- /dev/null +++ b/web/src/components/mixins/loginMounted.ts @@ -0,0 +1,4 @@ +export default function loginMounted(): Promise { + // 通常用于会员登录页初始化时接受各种回调或收参跳转,返回 true 将终止会员登录页初始化 + return new Promise((resolve) => resolve(false)) +} diff --git a/web/src/components/mixins/userMounted.ts b/web/src/components/mixins/userMounted.ts new file mode 100644 index 0000000..33fcf3d --- /dev/null +++ b/web/src/components/mixins/userMounted.ts @@ -0,0 +1,11 @@ +interface UserMountedRet { + type: 'jump' | 'break' | 'continue' | 'reload' + [key: string]: any +} + +export default function userMounted(): Promise { + // 通常用于会员中心初始化时接受各种回调或收参跳转,返回 true 将终止会员中心初始化 + return new Promise((resolve) => { + resolve({ type: 'continue' }) + }) +} diff --git a/web/src/components/mixins/userProfile.vue b/web/src/components/mixins/userProfile.vue new file mode 100644 index 0000000..811a80e --- /dev/null +++ b/web/src/components/mixins/userProfile.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/web/src/components/table/comSearch/index.vue b/web/src/components/table/comSearch/index.vue new file mode 100644 index 0000000..f291a12 --- /dev/null +++ b/web/src/components/table/comSearch/index.vue @@ -0,0 +1,300 @@ + + + + + diff --git a/web/src/components/table/fieldRender/buttons.vue b/web/src/components/table/fieldRender/buttons.vue new file mode 100644 index 0000000..60f5b72 --- /dev/null +++ b/web/src/components/table/fieldRender/buttons.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/web/src/components/table/fieldRender/color.vue b/web/src/components/table/fieldRender/color.vue new file mode 100644 index 0000000..6ba1f74 --- /dev/null +++ b/web/src/components/table/fieldRender/color.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/web/src/components/table/fieldRender/customRender.vue b/web/src/components/table/fieldRender/customRender.vue new file mode 100644 index 0000000..d9bac39 --- /dev/null +++ b/web/src/components/table/fieldRender/customRender.vue @@ -0,0 +1,28 @@ + + + diff --git a/web/src/components/table/fieldRender/customTemplate.vue b/web/src/components/table/fieldRender/customTemplate.vue new file mode 100644 index 0000000..5d95401 --- /dev/null +++ b/web/src/components/table/fieldRender/customTemplate.vue @@ -0,0 +1,21 @@ + + + diff --git a/web/src/components/table/fieldRender/datetime.vue b/web/src/components/table/fieldRender/datetime.vue new file mode 100644 index 0000000..09dc1a3 --- /dev/null +++ b/web/src/components/table/fieldRender/datetime.vue @@ -0,0 +1,22 @@ + + + diff --git a/web/src/components/table/fieldRender/default.vue b/web/src/components/table/fieldRender/default.vue new file mode 100644 index 0000000..27bfa30 --- /dev/null +++ b/web/src/components/table/fieldRender/default.vue @@ -0,0 +1,5 @@ + diff --git a/web/src/components/table/fieldRender/icon.vue b/web/src/components/table/fieldRender/icon.vue new file mode 100644 index 0000000..e47cdcc --- /dev/null +++ b/web/src/components/table/fieldRender/icon.vue @@ -0,0 +1,25 @@ + + + diff --git a/web/src/components/table/fieldRender/image.vue b/web/src/components/table/fieldRender/image.vue new file mode 100644 index 0000000..1e22e76 --- /dev/null +++ b/web/src/components/table/fieldRender/image.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/web/src/components/table/fieldRender/images.vue b/web/src/components/table/fieldRender/images.vue new file mode 100644 index 0000000..f47ae20 --- /dev/null +++ b/web/src/components/table/fieldRender/images.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/web/src/components/table/fieldRender/switch.vue b/web/src/components/table/fieldRender/switch.vue new file mode 100644 index 0000000..2ca05be --- /dev/null +++ b/web/src/components/table/fieldRender/switch.vue @@ -0,0 +1,52 @@ + + + diff --git a/web/src/components/table/fieldRender/tag.vue b/web/src/components/table/fieldRender/tag.vue new file mode 100644 index 0000000..667c5eb --- /dev/null +++ b/web/src/components/table/fieldRender/tag.vue @@ -0,0 +1,34 @@ + + + diff --git a/web/src/components/table/fieldRender/tags.vue b/web/src/components/table/fieldRender/tags.vue new file mode 100644 index 0000000..0113b0f --- /dev/null +++ b/web/src/components/table/fieldRender/tags.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/web/src/components/table/fieldRender/url.vue b/web/src/components/table/fieldRender/url.vue new file mode 100644 index 0000000..eb2e836 --- /dev/null +++ b/web/src/components/table/fieldRender/url.vue @@ -0,0 +1,39 @@ + + + diff --git a/web/src/components/table/header/index.vue b/web/src/components/table/header/index.vue new file mode 100644 index 0000000..e5ccb4b --- /dev/null +++ b/web/src/components/table/header/index.vue @@ -0,0 +1,243 @@ + + + + + diff --git a/web/src/components/table/index.ts b/web/src/components/table/index.ts new file mode 100644 index 0000000..e1fa2de --- /dev/null +++ b/web/src/components/table/index.ts @@ -0,0 +1,141 @@ +import { TableColumnCtx } from 'element-plus' +import { isUndefined } from 'lodash-es' +import { i18n } from '/@/lang/index' + +/** + * 获取单元格值 + */ +export const getCellValue = (row: TableRow, field: TableColumn, column: TableColumnCtx, index: number) => { + if (!field.prop) return '' + + const prop = field.prop + let cellValue: any = row[prop] + + // 字段 prop 带 . 比如 user.nickname + if (prop.indexOf('.') > -1) { + const fieldNameArr = prop.split('.') + cellValue = row[fieldNameArr[0]] + for (let index = 1; index < fieldNameArr.length; index++) { + cellValue = cellValue ? (cellValue[fieldNameArr[index]] ?? '') : '' + } + } + + // 若无值,尝试取默认值 + if ([undefined, null, ''].includes(cellValue) && field.default !== undefined) { + cellValue = field.default + } + + // 渲染前格式化 + if (field.renderFormatter && typeof field.renderFormatter == 'function') { + cellValue = field.renderFormatter(row, field, cellValue, column, index) + console.warn('baTable.table.column.renderFormatter 即将废弃,请直接使用兼容 el-table 的 baTable.table.column.formatter 代替') + } + if (field.formatter && typeof field.formatter == 'function') { + cellValue = field.formatter(row, column, cellValue, index) + } + + return cellValue +} + +/* + * 默认按钮组 + */ +export const defaultOptButtons = (optButType: DefaultOptButType[] = ['weigh-sort', 'edit', 'delete']): OptButton[] => { + const optButtonsPre: Map = new Map([ + [ + 'weigh-sort', + { + render: 'moveButton', + name: 'weigh-sort', + title: 'Drag sort', + text: '', + type: 'info', + icon: 'fa fa-arrows', + class: 'table-row-weigh-sort', + disabledTip: false, + }, + ], + [ + 'edit', + { + render: 'tipButton', + name: 'edit', + title: 'Edit', + text: '', + type: 'primary', + icon: 'fa fa-pencil', + class: 'table-row-edit', + disabledTip: false, + }, + ], + [ + 'delete', + { + render: 'confirmButton', + name: 'delete', + title: 'Delete', + text: '', + type: 'danger', + icon: 'fa fa-trash', + class: 'table-row-delete', + popconfirm: { + confirmButtonText: i18n.global.t('Delete'), + cancelButtonText: i18n.global.t('Cancel'), + confirmButtonType: 'danger', + title: i18n.global.t('Are you sure to delete the selected record?'), + }, + disabledTip: false, + }, + ], + ]) + + const optButtons: OptButton[] = [] + for (const key in optButType) { + if (optButtonsPre.has(optButType[key])) { + optButtons.push(optButtonsPre.get(optButType[key])!) + } + } + return optButtons +} + +/** + * 将带children的数组降维,然后寻找index所在的行 + */ +export const findIndexRow = (data: TableRow[], findIdx: number, keyIndex: number | TableRow = -1): number | TableRow => { + for (const key in data) { + if (typeof keyIndex == 'number') { + keyIndex++ + } + + if (keyIndex == findIdx) { + return data[key] + } + + if (data[key].children) { + keyIndex = findIndexRow(data[key].children!, findIdx, keyIndex) + if (typeof keyIndex != 'number') { + return keyIndex + } + } + } + + return keyIndex +} + +/** + * 调用一个接受表格上下文数据的任意属性计算函数 + */ +export const invokeTableContextDataFun = ( + fun: TableContextDataFun | undefined, + context: TableContextData, + defaultValue: any = {} +): Partial => { + if (isUndefined(fun)) { + return defaultValue + } else if (typeof fun === 'function') { + return fun(context) + } + return fun +} + +type DefaultOptButType = 'weigh-sort' | 'edit' | 'delete' diff --git a/web/src/components/table/index.vue b/web/src/components/table/index.vue new file mode 100644 index 0000000..869c2b1 --- /dev/null +++ b/web/src/components/table/index.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/web/src/components/terminal/index.vue b/web/src/components/terminal/index.vue new file mode 100644 index 0000000..6096a3c --- /dev/null +++ b/web/src/components/terminal/index.vue @@ -0,0 +1,439 @@ + + + + + diff --git a/web/src/lang/autoload.ts b/web/src/lang/autoload.ts new file mode 100644 index 0000000..af5d708 --- /dev/null +++ b/web/src/lang/autoload.ts @@ -0,0 +1,14 @@ +import { adminBaseRoutePath } from '/@/router/static/adminBase' + +/* + * 语言包按需加载映射表 + * 使用固定字符串 ${lang} 指代当前语言 + * key 为页面 path,value 为语言包文件相对路径,访问时,按需自动加载映射表的语言包,同时加载 path 对应的语言包(若存在) + */ +export default { + '/': ['./frontend/${lang}/index.ts'], + [adminBaseRoutePath + '/moduleStore']: ['./backend/${lang}/module.ts'], + [adminBaseRoutePath + '/user/rule']: ['./backend/${lang}/auth/rule.ts'], + [adminBaseRoutePath + '/user/scoreLog']: ['./backend/${lang}/user/moneyLog.ts'], + [adminBaseRoutePath + '/crud/crud']: ['./backend/${lang}/crud/log.ts', './backend/${lang}/crud/state.ts'], +} diff --git a/web/src/lang/backend/en.ts b/web/src/lang/backend/en.ts new file mode 100644 index 0000000..293704a --- /dev/null +++ b/web/src/lang/backend/en.ts @@ -0,0 +1,102 @@ +/** + * backend common language package + */ +export default { + Balance: 'Balance', + Integral: 'Integral', + Connection: 'connection', + 'Database connection': 'Database connection', + 'Database connection help': 'You can configure multiple database connections in config/database.php and select it here', + layouts: { + 'Layout configuration': 'Layout configuration', + 'Layout mode': 'Layout mode', + default: 'Default', + classic: 'Classic', + 'Single column': 'Single Column', + 'overall situation': 'Global', + 'Background page switching animation': 'Background page switching animation', + 'Please select an animation name': 'Please select an animation name', + sidebar: 'Sidebar', + 'Side menu bar background color': 'Background color of the side menu bar', + 'Side menu text color': 'Side menu text color', + 'Side menu active item background color': 'Background color of the side menu activation item', + 'Side menu active item text color': 'Side menu activation item text color', + 'Show side menu top bar (logo bar)': 'Display the top bar of the side menu (Logo Bar)', + 'Side menu top bar background color': 'Background color of the top bar of the side menu ', + 'Side menu width (when expanded)': 'Width of the side menu (Unfolding)', + 'Side menu default icon': 'Side menu default icon', + 'Side menu horizontal collapse': 'Side menu collapsed horizontally', + 'Side menu accordion': 'Side menu accordion', + 'Top bar': 'Top bar', + 'Top bar background color': 'Top bar background color', + 'Top bar text color': 'Top bar text color', + 'Background color when hovering over the top bar': 'Top bar hover background color', + 'Top bar menu active item background color': 'Background color of the top bar activation item', + 'Top bar menu active item text color': 'Top bar menu activation item text color', + 'Are you sure you want to restore all configurations to the default values?': + 'Are you sure to restore all configurations to the default values?', + 'Restore default': 'Restore default', + Profile: 'Profile', + Logout: 'Logout', + 'Dark mode': 'Dark mode', + 'Exit full screen': 'Exit Full Screen', + 'Full screen is not supported': 'Your browser does not support full screen, please change another browser and try again~', + 'Member center': 'Member center', + 'Member information': 'Member information', + 'Login to the buildadmin': 'Login to the buildadmin', + 'Please enter buildadmin account name or email': 'Please enter buildadmin account name or email', + 'Please enter the buildadmin account password': 'Please enter the buildadmin account password', + Login: 'Login', + Password: 'Password', + Username: 'Username', + Register: 'Register', + }, + terminal: { + Source: 'source', + Terminal: 'Terminal', + 'Command run log': 'Command Run Log', + 'No mission yet': 'There is no task yet', + 'Test command': 'Test command', + 'Install dependent packages': 'Install dependent packages', + Republish: 'Republish', + 'Clean up task list': 'Clean up the task list', + unknown: 'Unknown', + 'Waiting for execution': 'Waiting for execution', + Connecting: 'Connecting', + Executing: 'Executing', + 'Successful execution': 'Executed successfully', + 'Execution failed': 'Failed to execute', + 'Unknown execution result': 'Execution result is unknown', + 'Are you sure you want to republish?': 'Are you sure to republish?', + 'Failure to execute this command will block the execution of the queue': 'Failed to execute this command will block queue execution.', + 'NPM package manager': 'NPM package manager', + 'NPM package manager tip': 'Select an available package manager for the execution of commands such as npm install in the WEB terminal', + 'Clear successful task': 'Clear successful task', + 'Clear successful task tip': 'When you start a new task, automatically clear the list of already successful tasks', + 'Manual execution': 'Manual execution', + 'Do not refresh the browser': 'Do not refresh your browser.', + 'Terminal settings': 'Terminal setup', + 'Back to terminal': 'Back to terminal', + or: 'or', + 'Site domain name': 'Site domain name', + 'The current terminal is not running under the installation service, and some commands may not be executed': + 'The current terminal is not running under the installation service, and some commands may not be executed.', + 'Newly added tasks will never start because they are blocked by failed tasks': + 'Newly added tasks will never start because they are blocked by failed tasks!(Web terminal)', + 'Failed to modify the source command, Please try again manually': 'Failed to modify the source command. Please try again manually.', + }, + vite: { + Later: '稍后', + 'Restart hot update': '重启热更新', + 'Close type terminal': 'WEB Terminal server', + 'Close type crud': 'CRUD server', + 'Close type modules': 'module install server', + 'Close type config': 'system configuration server', + 'Reload hot server title': 'Need to restart Vite hot update service', + 'Reload hot server tips 1': 'To ensure that ', + 'Reload hot server tips 2': + " is not interrupted, the system has temporarily suspended Vite's hot update function. During this period, changes to front-end files will not be updated in real-time and web pages will not be automatically reloaded. It has been detected that there are file updates during the service suspension period, and the hot update service needs to be restarted.", + 'Reload hot server tips 3': + 'The pause of hot updates does not affect the already loaded functions. You can continue to operate and click to restart the hot update service after everything is ready.', + }, +} diff --git a/web/src/lang/backend/en/auth/admin.ts b/web/src/lang/backend/en/auth/admin.ts new file mode 100644 index 0000000..285962a --- /dev/null +++ b/web/src/lang/backend/en/auth/admin.ts @@ -0,0 +1,13 @@ +export default { + username: 'Username', + nickname: 'Nickname', + group: 'Group', + avatar: 'Avatar', + email: 'Email', + mobile: 'Mobile Number', + 'Last login': 'Last login', + Password: 'Password', + 'Please leave blank if not modified': 'Please leave blank if you do not modify.', + 'Personal signature': 'Personal Signature', + 'Administrator login': 'Administrator Login Name', +} diff --git a/web/src/lang/backend/en/auth/adminLog.ts b/web/src/lang/backend/en/auth/adminLog.ts new file mode 100644 index 0000000..a0af627 --- /dev/null +++ b/web/src/lang/backend/en/auth/adminLog.ts @@ -0,0 +1,12 @@ +export default { + admin_id: 'Manage ID', + username: 'Manage Username', + title: 'Title', + data: 'Request Data', + url: 'URL', + ip: 'IP', + useragent: 'UserAgent', + 'Operation administrator': 'Operation administrator', + 'Operator IP': 'Operator IP', + 'Request data': 'Request Data', +} diff --git a/web/src/lang/backend/en/auth/group.ts b/web/src/lang/backend/en/auth/group.ts new file mode 100644 index 0000000..57f8a04 --- /dev/null +++ b/web/src/lang/backend/en/auth/group.ts @@ -0,0 +1,9 @@ +export default { + GroupName: 'Group Name', + 'Group name': 'Group Name', + jurisdiction: 'Permissions', + 'Parent group': 'Superior group', + 'The parent group cannot be the group itself': 'The parent group cannot be the group itself', + 'Manage subordinate role groups here': + 'In managing a subordinate role group (excluding a peer role group), you have all the rights of a subordinate role group and additional rights', +} diff --git a/web/src/lang/backend/en/auth/rule.ts b/web/src/lang/backend/en/auth/rule.ts new file mode 100644 index 0000000..1f9bbd3 --- /dev/null +++ b/web/src/lang/backend/en/auth/rule.ts @@ -0,0 +1,51 @@ +export default { + title: 'Title', + Icon: 'Icon', + name: 'Name', + type: 'Type', + cache: 'Cache', + 'Superior menu rule': 'Superior menu rules', + 'Rule type': 'Rule type', + 'type menu_dir': 'Menu directory', + 'type menu': 'Menu item', + 'type button': 'Page button', + 'Rule title': 'Rule title', + 'Rule name': 'Rule name', + 'Routing path': 'Routing path', + 'Rule Icon': 'Rule Icon', + 'Menu type': 'Menu type', + 'Menu type tab': 'Tab', + 'Menu type link (offsite)': 'Link (off-site)', + 'Link address': 'Link address', + 'Component path': 'Component path', + 'Extended properties': 'Extended properties', + 'Add as route only': 'Add as route only', + 'Add as menu only': 'Add as menu only', + 'Rule comments': 'Rule comments', + 'Rule weight': 'Rule weights', + 'Create Page Button': 'Create Page Button', + 'Create Page Button index': 'index', + 'Create Page Button add': 'add', + 'Create Page Button edit': 'edit', + 'Create Page Button del': 'del', + 'Create Page Button sortable': 'sortable', + 'Create Page Button tips': 'When creating the menu, automatically create the menu page buttons (permission nodes)', + 'Please select the button for automatically creating the desired page': 'Please select the button for automatically creating the desired page', + 'Please enter the weight of menu rule (sort by)': 'Please enter the menu rule weights (sort by)', + 'Please enter the correct URL': 'Please enter the correct URL', + 'The superior menu rule cannot be the rule itself': 'The superior menu rules cannot be rules itself.', + 'It will be registered as the web side routing name and used as the server side API authentication': + 'It will be registered as the routing name of the webside and used as a server-side API authentication at the same time.', + 'Please enter the URL address of the link or iframe': 'Please enter the link or the URL address of iframe.', + 'English name, which does not need to start with `/admin`, such as auth/menu': + 'The English name does not need to start with `/admin`, such as: auth/menu.', + 'Web side component path, please start with /src, such as: /src/views/backend/dashboard': + 'Please start with /src for web side component paths, such as: /src/views/backend/dashboard.vue', + 'The web side routing path (path) does not need to start with `/admin`, such as auth/menu': + 'The web side routing path (Path) does not need to start with `/admin`, such as: auth/menu.', + 'Use in controller `get_ route_ Remark()` function, which can obtain the value of this field for your own use, such as the banner file of the console': + 'Use the `get_route_remark()` function in the controller can get the value of this field for your own use, such as the banner file for the console.', + 'extend Title': + "For example, if 'auth/menu' is only added as a route, then `auth/menu`, `auth/menu/:a` and `auth/menu/:b/:c` can be added only as menus.", + none: 'None', +} diff --git a/web/src/lang/backend/en/crud/crud.ts b/web/src/lang/backend/en/crud/crud.ts new file mode 100644 index 0000000..333ca94 --- /dev/null +++ b/web/src/lang/backend/en/crud/crud.ts @@ -0,0 +1,173 @@ +export default { + show: 'Show in Table Columns', + width: 'Width', + sortable: 'sortable', + operator: 'Search operator', + comSearchRender: 'Common search render', + comSearchInputAttr: 'Common search render input extend properties', + comSearchInputAttrTip: 'Remote pull-down field, no need to fill in the mandatory attributes of the component.', + render: 'table column render', + timeFormat: 'Format', + step: 'Step', + rows: 'Rows', + 'api url': 'api url', + 'api url example': 'For example: /admin/user.User/index', + 'remote-pk': 'value field', + 'remote-field': 'label field', + 'remote-url': 'remote URL', + 'remote-table': 'remote table', + 'remote-controller': 'remote controller', + 'remote-model': 'remote model', + 'remote-primary-table-alias': 'primary table alias', + 'relation-fields': 'relation fields', + 'image-multi': 'Multiple upload', + 'file-multi': 'Multiple upload', + 'select-multi': 'Multiple', + validator: 'validator', + validatorMsg: 'validator error message', + copy: 'Copy', + 'CRUD record': 'CRUD record', + 'Delete Code': 'Delete Code', + 'Start CRUD design with this record?': 'Start CRUD design with this record?', + 'Are you sure to delete the generated CRUD code?': 'Are you sure to delete the generated CRUD code?', + start: 'Start', + create: 'Create', + or: ' or ', + 'New background CRUD from zero': 'New background CRUD from zero', + 'Select Data Table': 'Select data table', + 'Select a designed data table from the database': 'Select a designed data table from the database', + 'Start with previously generated CRUD code': 'Start with previously generated CRUD code', + 'Fast experience': 'Fast experience', + 'Please enter SQL': 'Please enter SQL', + 'Please select a data table': 'Please select a data table', + 'data sheet help': 'The table prefix must be the same as the table prefix configured for the project', + 'data sheet': 'data sheet', + 'table create SQL': 'table creation SQL', + 'Please enter the table creation SQL': 'Please enter the table creation SQL', + 'experience 1 1': 'Prepare the ', + 'experience 1 2': 'development environment', + 'experience 1 3': '(The site port is 1818)', + 'experience 2 1': 'On this page, click to', + 'experience 2 2': 'Select data table', + 'experience 2 3': '(You can select the test_build data table)', + 'experience 3 1': 'Click', + 'experience 3 2': 'Generate CRUD Code', + 'experience 3 3': ', and click ', + 'experience 3 4': 'Continue to Generate', + 'experience 4 1': 'You are not currently in the development environment, ', + 'experience 4 2': 'please set up the development environment', + 'experience 4 3': ', or after generating the code, click on the upper right corner of the terminal to', + 'experience 4 4': 'Republish', + // design + 'Name of the data table': 'Name of the data table', + 'Data Table Notes': 'Data Table Notes', + 'Generate CRUD code': 'Generate CRUD code', + 'give up': 'give up', + 'Table Quick Search Fields': 'Table Quick Search Fields', + 'Table Default Sort Fields': 'Table Default Sort Fields', + 'sort order': 'sort order', + 'sort order asc': 'asc', + 'sort order desc': 'desc', + 'Fields as Table Columns': 'Fields as Table Columns', + 'Fields as form items': 'Fields as form items', + 'The relative path to the generated code': 'The relative path to the generated code', + 'For quick combination code generation location, please fill in the relative path': + 'For quick combination code generation location, please fill in the relative path', + 'Generated Controller Location': 'Generated Controller Location', + 'Generated Data Model Location': 'Generated Data Model Location', + 'Generated Validator Location': 'Generated Validator Location', + 'Common model': 'Common model', + 'WEB end view directory': 'WEB end view directory', + 'Check model class': "Check whether protected $connection = '{connection}'; is configured in the above data model class", + 'There is no connection attribute in model class': 'If no configuration is available, you can configure it manually', + 'Advanced Configuration': 'Advanced Configuration', + 'Common Fields': 'Common Fields', + 'Base Fields': 'Base Fields', + 'Advanced Fields': 'Advanced Fields', + 'Field Name': 'Field Name', + 'field comment': 'field comment', + 'Please select a field from the left first': 'Please select a field from the left first', + Common: 'Common', + 'Generate type': 'generate type', + 'Field comments (CRUD dictionary)': 'Field comments (CRUD dictionary)', + 'Field Properties': 'Field Properties', + 'Field Type': 'Field Type', + length: 'length', + 'decimal point': 'decimal point', + 'Field Defaults': 'Field Defaults', + 'Please input the default value': 'Please input the default value', + 'Auto increment': 'Auto increment', + Unsigned: 'Unsigned', + 'Allow NULL': 'Allow NULL', + 'Field Form Properties': 'Field Form Properties', + 'Field Table Properties': 'Field Table Properties', + 'Remote drop-down association information': 'Remote drop-down association information', + 'Associated Data Table': 'Associated Data Table', + 'Drop down value field': 'Drop down value field', + 'Drop down label field': 'Drop down label field', + 'Please select the value field of the select component': 'Please select the value field of the select component', + 'Please select the label field of the select component': 'Please select the label field of the select component', + 'Fields displayed in the table': 'Fields displayed in the table', + 'Please select the fields displayed in the table': 'Please select the fields displayed in the table', + 'Controller position': 'Controller position', + 'Please select the controller of the data table': 'Please select the controller of the data table', + 'Data Model Location': 'Data Model Location', + 'Data source configuration type': 'Data source configuration type', + 'Fast configuration with generated controllers and models': 'Fast configuration with generated controllers and models', + 'Custom configuration': 'Custom configuration', + 'If the remote interface query involves associated query of multiple tables, enter the alias of the primary data table here': + 'If the remote interface query involves associated query of multiple tables, enter the alias of the primary data table here', + 'Please select the data model location of the data table': 'Please select the data model location of the data table', + 'Confirm CRUD code generation': 'Confirm CRUD code generation', + 'Continue building': 'Continue building', + 'Please enter the data table name!': 'Please enter the data table name!', + 'Please enter the correct table name!': 'Please enter the correct table name!', + 'Use lower case underlined for table names': 'Use lower case underlined for table names', + 'Please design the primary key field!': 'Please design the primary key field!', + 'It is irreversible to give up the design Are you sure you want to give up?': + 'It is irreversible to give up the design. Are you sure you want to give up?', + 'There can only be one primary key field': 'There can only be one primary key field.', + 'Drag the left element here to start designing CRUD': 'Drag the left element here to start designing CRUD', + 'The data table already exists Continuing to generate will automatically delete the original table and create a new one!': + 'The data table already exists Continuing to generate will automatically delete the original table and create a new one!', + 'The controller already exists Continuing to generate will automatically overwrite the existing code!': + 'The controller already exists Continuing to generate will automatically overwrite the existing code!', + 'The menu rule with the same name already exists The menu and permission node will not be created in this generation': + 'The menu rule with the same name already exists The menu and permission node will not be created in this generation', + 'For example: `user table` will be generated into `user management`': 'For example: `user table` will be generated into `user management`', + 'The remote pull-down will request the corresponding controller to obtain data, so it is recommended that you create the CRUD of the associated table': + 'The remote pull-down will request the corresponding controller to obtain data, so it is recommended that you create the CRUD of the associated table', + 'If it is left blank, the model of the associated table will be generated automatically If the table already has a model, it is recommended to select it to avoid repeated generation': + 'If it is left blank, the model of the associated table will be generated automatically If the table already has a model, it is recommended to select it to avoid repeated generation', + 'The field comment will be used as the CRUD dictionary, and will be identified as the field title before the colon, and as the data dictionary after the colon': + 'The field comment will be used as the CRUD dictionary, and will be identified as the field title before the colon, and as the data dictionary after the colon', + 'Field name is invalid It starts with a letter or underscore and cannot contain any character other than letters, digits, or underscores': + 'Field name {field} is invalid. It starts with a letter or underscore and cannot contain any character other than letters, digits, or underscores', + 'The selected table has already generated records You are advised to start with historical records': + 'The selected table has already generated records. You are advised to start with historical records', + 'Start with the historical record': 'Start with the historical record', + 'Add field': 'Add field', + 'Modify field properties': 'Modify field properties', + 'Modify field name': 'Modify field name', + 'Delete field': 'Delete field', + 'Modify field order': 'Modify field order', + 'First field': 'First field', + After: 'after', + 'Table design change': 'Table design change', + 'Data table design changes preview': 'Data table design changes preview', + designChangeTips: 'When unchecked, the change will not be synchronized to the data table (the table structure has been manually modified, etc)', + tableReBuild: 'Delete and rebuild', + tableReBuildBlockHelp: + 'Deleting existing data tables and rebuilding them without adjusting the table structure ensures that CRUD code/records are consistent with the table structure', + Yes: 'Yes', + No: 'No', + 'If the data is abnormal, repeat the previous step': 'If the data is abnormal, repeat the previous step', + 'Field name duplication': 'field name {field} is duplicate', + 'Design remote select tips': + 'The name of the cost field is automatically generated from the table name; Confirm that when the field name user_id is generated, the association method generated by the field name user_id is named user, and the association method generated by the field name developer_done_id is named developerDone. Note that the name prefix of the remote drop-down field is not the same', + 'Vite hot warning': + 'Vite Hot Update service not found, please generate code in the development environment, or click the WEB terminal in the upper right corner to republish', + 'Reset generate type attr': + 'The field generation type has been changed. Do you want to reset the field design to the preset scheme for the new type?', + 'Design efficiency': 'Determine design validity by yourself', +} diff --git a/web/src/lang/backend/en/crud/log.ts b/web/src/lang/backend/en/crud/log.ts new file mode 100644 index 0000000..d2470f3 --- /dev/null +++ b/web/src/lang/backend/en/crud/log.ts @@ -0,0 +1,53 @@ +export default { + id: 'id', + table_name: 'name', + comment: 'comment', + table: 'table', + fields: 'fields', + sync: 'sync', + 'sync no': 'no', + 'sync yes': 'yes', + status: 'status', + delete: 'delete code', + 'status delete': 'status delete', + 'status success': 'status success', + 'status error': 'status error', + 'status start': 'status start', + create_time: 'create_time', + 'quick Search Fields': 'id,table_name,comment', + 'Upload the selected design records to the cloud for cross-device use': 'Upload the selected design records to the cloud for cross-device use', + 'Design records that have been synchronized to the cloud': 'Design records that have been synchronized to the cloud', + 'Cloud record': 'Cloud record', + Settings: 'Settings', + 'Login for backup design': 'Login for backup design', + 'CRUD design record synchronization scheme': 'CRUD design record synchronization scheme', + Manual: 'Manual', + automatic: 'automatic', + 'When automatically synchronizing records, share them to the open source community': + 'When automatically synchronizing records, share them to the open source community', + 'Not to share': 'Not to share', + Share: 'Share', + 'Enabling sharing can automatically earn community points during development': + 'Enabling sharing can automatically earn community points during development', + 'The synchronized CRUD records are automatically resynchronized when they are updated': + 'The synchronized CRUD records are automatically resynchronized when they are updated', + 'Do not resynchronize': 'Do not resynchronize', + 'Automatic resynchronization': 'Automatic resynchronization', + 'No effective design': 'No effective design', + 'Number of fields': 'Number of fields', + 'Upload type': 'Upload type', + Update: 'Update', + 'New added': 'New added', + 'Share to earn points': 'Share to earn points', + 'Share to the open source community': 'Share to the open source community', + 'No design record': 'No design record', + Field: 'Field', + 'Field information': 'Field information', + 'No field': 'No field', + 'Field name': 'Field name', + Note: 'Note', + Type: 'Type', + Load: 'Load', + 'Delete cloud records?': 'Delete cloud records?', + 'You can use the synchronized design records across devices': 'You can use the synchronized design records across devices', +} diff --git a/web/src/lang/backend/en/crud/state.ts b/web/src/lang/backend/en/crud/state.ts new file mode 100644 index 0000000..255f89b --- /dev/null +++ b/web/src/lang/backend/en/crud/state.ts @@ -0,0 +1,21 @@ +export default { + remarks: 'remarks', + 'Primary key': 'Primary key', + 'Primary key (Snowflake ID)': 'Primary key (Snowflake ID)', + 'Disable Search': 'Disable Search', + 'Weight (drag and drop sorting)': 'Weight (drag and drop sorting)', + 'Status:0=Disabled,1=Enabled': 'Status:0=Disabled,1=Enabled', + 'Remote Select (association table)': 'Remote Select (association table)', + 'Remote Select (Multi)': 'Remote Select (Multi)', + 'Radio:opt0=Option1,opt1=Option2': 'Radio:opt0=Option1,opt1=Option2', + 'Checkbox:opt0=Option1,opt1=Option2': 'Checkbox:opt0=Option1,opt1=Option2', + Multi: '(Multi)', + 'Select:opt0=Option1,opt1=Option2': 'Select:opt0=Option1,opt1=Option2', + 'Switch:0=off,1=on': 'Switch:0=off,1=on', + 'Time date (timestamp storage)': 'Time date (timestamp storage)', + 'If left blank, the verifier title attribute will be filled in automatically': + 'If left blank, the verifier title attribute will be filled in automatically', + 'Weight (automatically generate drag sort button)': 'Weight (automatically generate drag sort button)', + 'If it is not input, it will be automatically analyzed by the controller': + 'If it is not input, it will be automatically analyzed by the controller', +} diff --git a/web/src/lang/backend/en/dashboard.ts b/web/src/lang/backend/en/dashboard.ts new file mode 100644 index 0000000..3927977 --- /dev/null +++ b/web/src/lang/backend/en/dashboard.ts @@ -0,0 +1,39 @@ +export default { + 'You have worked today': 'You have worked today: ', + 'Continue to work': 'Keep working', + 'have a bit of rest': 'Take a break', + 'Member registration': 'Member registration', + 'Total number of members': 'Total number of members', + 'Number of installed plug-ins': 'Number of installed plug-ins', + 'Membership growth': 'Membership growth', + 'Annex growth': 'Annex Growth', + 'New member': 'New Member', + 'Joined us': 'Joined us', + 'Member source': 'Member source', + 'Member last name': 'Member last name', + Loading: 'Loading', + Monday: 'Monday', + Tuesday: 'Tuesday', + Wednesday: 'Wednesday', + Thursday: 'Thursday', + Friday: 'Friday', + Saturday: 'Saturday', + Sunday: 'Sunday', + Visits: 'Visits', + 'Registration volume': 'The number of registered users', + picture: 'picture', + file: 'file', + table: 'table', + other: 'other', + 'Compressed package': 'Compressed package', + Baidu: 'Baidu', + 'Direct access': 'Direct access', + 'take a plane': 'Take a plane', + 'Take the high-speed railway': 'Take the high-speed rail', + 'full name': 'Full name', + hour: 'Hour', + minute: 'Minute', + second: 'Second', + day: 'Day', + 'Number of attachments Uploaded': 'Number of attachments upload', +} diff --git a/web/src/lang/backend/en/login.ts b/web/src/lang/backend/en/login.ts new file mode 100644 index 0000000..9d29c63 --- /dev/null +++ b/web/src/lang/backend/en/login.ts @@ -0,0 +1,6 @@ +export default { + 'Please enter an account': 'Please enter your account', + 'Please input a password': 'Please enter your password', + 'Hold session': 'Keep the session', + 'Sign in': 'Sign in', +} diff --git a/web/src/lang/backend/en/module.ts b/web/src/lang/backend/en/module.ts new file mode 100644 index 0000000..00ac529 --- /dev/null +++ b/web/src/lang/backend/en/module.ts @@ -0,0 +1,163 @@ +export default { + 'stateTitle init': 'Module installer initialization...', + 'stateTitle download': 'Downloading module...', + 'stateTitle install': 'Installing module...', + 'stateTitle getInstallableVersion': 'Get installable version...', + 'env require': 'Composer', + 'env require-dev': 'Composer-dev', + 'env dependencies': 'NPM', + 'env devDependencies': 'NPM-dev', + 'env nuxtDependencies': 'Nuxt NPM', + 'env nuxtDevDependencies': 'Nuxt NPM Dev', + // buy + 'Module installation warning': + 'Free download and update within one year after purchase. Virtual products do not support 7-day refund without reason', + 'Order title': 'Order title', + 'Order No': 'Order No.:', + 'Purchase user': 'Purchase user', + 'Order price': 'Order price', + 'Purchased, can be installed directly': 'Purchased, can be installed directly', + 'Understand and agree': 'Understand and agree', + 'Module purchase and use agreement': 'Module purchase and use agreement', + 'Point payment': 'Point payment', + 'Balance payment': 'Balance payment', + 'Wechat payment': 'Wechat payment', + 'Alipay payment': 'Alipay payment', + 'Install now': 'Install now', + payment: 'payment', + 'Confirm order info': 'Confirm order info', + // commonDone + 'Congratulations, module installation is complete': 'Congratulations, module installation is complete.', + 'Module is disabled': 'Module is disabled.', + 'Congratulations, the code of the module is ready': 'Congratulations, the code of the module is ready.', + 'Unknown state': 'Unknown state.', + 'Do not refresh the page!': 'Do not refresh the page!', + 'New adjustment of dependency detected': 'New adjustment of dependency detected', + 'This module adds new dependencies': 'This module adds new dependencies', + 'The built-in terminal of the system is automatically installing these dependencies, please wait~': + 'The built-in terminal of the system is automatically installing these dependencies, please wait~', + 'View progress': 'View progress', + 'Dependency installation completed~': 'Dependency installation completed~', + 'This module does not add new dependencies': 'This module does not add new dependencies.', + 'There is no adjustment for system dependency': 'There is no adjustment for system dependency.', + please: 'please', + 'After installation 1': 'After installation', + 'Manually clean up the system and browser cache': 'Manually clean up the system and browser cache.', + 'After installation 2': 'After installation', + 'Automatically execute reissue command?': 'Automatically execute reissue command?', + 'End of installation': 'End of installation', + 'Dependency installation fail 1': 'The dependency installation failed. Please click the retry button in the ', + 'Dependency installation fail 2': 'terminal', + 'Dependency installation fail 3': 'You can also view the ', + 'Dependency installation fail 4': 'unfinished matters manually', + 'Dependency installation fail 5': 'Until you are', + 'Dependency installation fail 6': 'sure that the dependency is ready', + 'Dependency installation fail 7': ', the module will not work!', + 'Is the command that failed on the WEB terminal executed manually or in other ways successfully?': + 'Is the command that failed on the WEB terminal executed manually or in other ways successfully?', + yes: 'yes', + no: 'no', + // confirmFileConflict + 'Update warning': + 'The following module files have been detected to be updated. When disabled, they will be automatically overwritten. Please pay attention to backup.', + 'File conflict': 'File conflict', + 'Conflict file': 'Conflict file', + 'Dependency conflict': 'Dependency conflict', + 'Confirm to disable the module': 'Confirm to disable the module', + 'The module declares the added dependencies': 'The module declares the added dependencies', + Dependencies: 'Dependencies', + retain: 'Retain', + // goodsInfo + 'detailed information': 'detailed information', + Price: 'Price', + 'Last updated': 'Last updated', + 'Published on': 'Published on:', + 'amount of downloads': 'amount of downloads', + 'Module classification': 'Module classification', + 'Module documentation': 'Module documentation', + 'Developer Homepage': 'Developer Homepage', + 'Click to access': 'Click to access', + 'Module status': 'Module status', + 'View demo': 'View demo', + 'Code scanning Preview': 'Code scanning Preview', + 'Buy now': 'Buy now', + 'continue installation': 'continue installation', + installed: 'installed', + 'to update': 'to update', + uninstall: 'uninstall', + 'Contact developer': 'Contact developer', + 'Other works of developers': 'Other works of developers', + 'There are no more works': 'There are no more works', + 'You need to disable this module before updating Do you want to disable it now?': + 'You need to disable this module before updating. Do you want to disable it now?', + 'Disable and update': 'Disable and update', + 'No module purchase order was found': 'No module purchase order was found. Do you want to purchase the current module now?', + // installConflict + 'new file': 'new file', + 'Existing files': 'Existing files', + 'Treatment scheme': 'Treatment scheme', + 'Backup and overwrite existing files': 'Backup and overwrite existing files', + 'Discard new file': 'Discard new file', + environment: 'environment', + 'New dependency': 'New dependency', + 'Existing dependencies': 'Existing dependencies', + 'Overwrite existing dependencies': 'Overwrite existing dependencies', + 'Do not use new dependencies': 'Do not use new dependencies', + // tableHeader + 'Upload zip package for installation': 'Upload zip package for installation', + 'Upload installation': 'Upload installation', + 'Uploaded / installed modules': 'Uploaded / installed modules', + 'Local module': 'Local module', + 'Publishing module': 'Publishing module', + 'Get points': 'Get points', + 'Search is actually very simple': 'Search is actually very simple', + // tabs + Loading: 'Loading...', + 'No more': 'No more.', + // uploadInstall + 'Local upload warning': + 'Please make sure that the module package file comes from the official channel or the officially certified module author, otherwise the system may be damaged because:', + 'The module can modify and add system files': 'The module can modify and add system files', + 'The module can execute sql commands and codes': 'The module can execute sql commands and codes', + 'The module can install new front and rear dependencies': 'The module can install new front and rear dependencies', + 'Drag the module package file here': 'Drag the module package file here, Or', + 'Click me to upload': 'Click me to upload', + 'Uploaded, installation is about to start, please wait': 'Uploaded, installation is about to start, please wait', + 'Update Log': 'Update Log', + 'No detailed update log': 'No detailed update log', + 'Use WeChat to scan QR code for payment': 'Use WeChat to scan QR code for payment', + 'Use Alipay to scan QR code for payment': 'Use Alipay to scan QR code for payment', + 'dependency-installation-fail-tips': + 'If the command is successfully executed manually, click `Make sure dependency is ready` above to change the module to the installed state', + 'New version': 'New version', + Install: 'Install', + 'Installation cancelled because module already exists!': 'Installation cancelled because module already exists!', + 'Installation cancelled because the directory required by the module is occupied!': + 'Installation cancelled because the directory required by the module is occupied!', + 'Installation complete': 'Installation complete', + 'A conflict is found Please handle it manually': 'A conflict is found. Please handle it manually', + 'Select Version': 'Select install version', + 'Wait for dependent installation': 'Wait for dependent installation', + 'The operation succeeds Please clear the system cache and refresh the browser ~': + 'The operation succeeds. Please clear the system cache and refresh the browser ~', + 'Deal with conflict': 'Deal with conflict', + 'Wait for installation': 'Wait for installation', + 'Conflict pending': 'Conflict pending', + 'Dependency to be installed': 'Dependency to be installed', + 'Restart Vite hot server': 'Restart Vite hot server', + 'Restart Vite hot server tips': + 'Before successfully restarting the service, you can find the button to manually restart the service from the button group on the right side of the top bar.', + 'Manual restart': 'Manual restart', + 'Restart Now': 'Restart Now', + // 选择安装版本 + 'Available system version': 'Available system version', + Description: 'Description', + Version: 'Version', + 'Current installed version': 'Current installed version', + 'Insufficient system version': 'Insufficient system version', + 'Click to install': 'Click to install', + 'Versions released beyond the authorization period': 'Versions released beyond the authorization period', + Renewal: 'Renewal', + 'Order expiration time': + 'The expiration time of the current order authorization is {expiration_time}, and the release time of this version is {create_time}', +} diff --git a/web/src/lang/backend/en/routine/adminInfo.ts b/web/src/lang/backend/en/routine/adminInfo.ts new file mode 100644 index 0000000..0ae2dd1 --- /dev/null +++ b/web/src/lang/backend/en/routine/adminInfo.ts @@ -0,0 +1,14 @@ +export default { + 'Last logged in on': 'Last logged on', + 'user name': 'Username', + 'User nickname': 'User nickname', + 'Please enter a nickname': 'Please enter a nickname', + 'e-mail address': 'E-mail address', + 'phone number': 'Mobile number', + autograph: 'Signature', + 'This guy is lazy and doesn write anything': "This guy is lazy and didn't write anything.", + 'New password': 'New password', + 'Please leave blank if not modified': 'Please leave blank if you do not modify', + 'Save changes': 'Save changes', + 'Operation log': 'Operation log', +} diff --git a/web/src/lang/backend/en/routine/attachment.ts b/web/src/lang/backend/en/routine/attachment.ts new file mode 100644 index 0000000..23606ff --- /dev/null +++ b/web/src/lang/backend/en/routine/attachment.ts @@ -0,0 +1,25 @@ +export default { + 'Upload administrator': 'Upload administrator', + 'Upload user': 'Upload member', + 'Storage mode': 'Storage mode', + 'Physical path': 'Physical path', + 'image width': 'Picture width', + 'Picture height': 'Picture height', + 'file size': 'file size', + 'mime type': 'mime type ', + 'SHA1 code': 'SHA1', + 'The file is saved in the directory, and the file will not be automatically transferred if the record is modified': + 'The file had saved in the directory, and the modification record will not automatically tansfer the file.', + 'File saving path Modifying records will not automatically transfer files': + 'The file had saved in the path, and the modification record will not automatically tansfer the file.', + 'Width of picture file': 'The width of the image file.', + 'Height of picture file': 'The height of the image file.', + 'Original file name': 'Original name of the file', + 'File size (bytes)': 'File size (Bytes)', + 'File MIME type': 'File MIME type', + 'Upload (Reference) times of this file': 'Upload (Reference) times of this file', + 'When the same file is uploaded multiple times, only one attachment record will be saved and added': + 'When the same file is uploaded many times, only one attachment record will be saved and added.', + 'SHA1 encoding of file': 'The SHA1 encoding of file', + 'Files and records will be deleted at the same time Are you sure?': 'Files and records will be deleted at the same time Are you sure?', +} diff --git a/web/src/lang/backend/en/routine/config.ts b/web/src/lang/backend/en/routine/config.ts new file mode 100644 index 0000000..1db001c --- /dev/null +++ b/web/src/lang/backend/en/routine/config.ts @@ -0,0 +1,16 @@ +export default { + 'Are you sure to delete the configuration item?': 'Are you sure to delete the configuration item?', + 'Add configuration item': 'Add configuration item', + 'Quick configuration entry': 'Quick configuration entry', + 'Variable name': 'Variable name', + 'Variable group': 'Variable group', + 'Variable title': 'Variable title', + 'Variable type': 'Variable type', + number: 'Number', + 'Please enter the recipient email address': 'Please enter the recipient email address', + 'Test mail sending': 'Test mail sending', + 'send out': 'send', + 'Please enter the correct email address': 'Please enter the correct email address', + Sending: 'Sending', + 'Please enter the correct mail configuration': 'Please enter the correct mail configuration', +} diff --git a/web/src/lang/backend/en/security/dataRecycle.ts b/web/src/lang/backend/en/security/dataRecycle.ts new file mode 100644 index 0000000..febee4e --- /dev/null +++ b/web/src/lang/backend/en/security/dataRecycle.ts @@ -0,0 +1,11 @@ +export default { + 'Rule name': 'Rule name', + controller: 'Controller', + 'data sheet': 'Data table', + 'Data table primary key': 'Data table primary key', + 'Deleting monitoring': 'Delete monitoring', + 'The rule name helps to identify deleted data later': 'Rule names help to identify deleted data subsequently later.', + 'The data collection mechanism will monitor delete operations under this controller': + 'The data recycle mechanism will monitor the delete operations under this controller.', + 'Corresponding data sheet': 'Corresponding data sheet', +} diff --git a/web/src/lang/backend/en/security/dataRecycleLog.ts b/web/src/lang/backend/en/security/dataRecycleLog.ts new file mode 100644 index 0000000..0de787a --- /dev/null +++ b/web/src/lang/backend/en/security/dataRecycleLog.ts @@ -0,0 +1,17 @@ +export default { + restore: 'Restore', + 'Are you sure to restore the selected records?': 'Are you sure to restore the selected records?', + 'Restore the selected record to the original data table': 'Restore the selected record to the original data table.', + 'Operation administrator': 'Operation administrator', + 'Recycling rule name': 'Recycling rule name', + 'Rule name': 'Rule name', + controller: 'Controller', + 'data sheet': 'Data table', + DeletedData: 'Deleted data', + 'Arbitrary fragment fuzzy query': 'Arbitrary fragment fuzzy query', + 'Click to expand': 'Click to expand', + 'Data table primary key': 'Data table primary key', + 'Operator IP': 'Operator IP', + 'Deleted data': 'Deleted data', + 'Delete time': 'Delete time', +} diff --git a/web/src/lang/backend/en/security/sensitiveData.ts b/web/src/lang/backend/en/security/sensitiveData.ts new file mode 100644 index 0000000..e2c6081 --- /dev/null +++ b/web/src/lang/backend/en/security/sensitiveData.ts @@ -0,0 +1,13 @@ +export default { + 'Rule name': 'Rule name', + controller: 'Controller', + 'data sheet': 'Data table', + 'Data table primary key': 'Data table primary key', + 'Sensitive fields': 'Sensitive fields', + 'Modifying monitoring': 'Modify monitoring', + 'The rule name helps to identify the modified data later': 'Rule names help to identify modified data subsequently later.', + 'The data listening mechanism will monitor the modification operations under this controller': + 'The data monitor mechanism will monitor the modified operation under this controller.', + 'Corresponding data sheet': 'Corresponding data table', + 'Filling in field notes helps you quickly identify fields later': 'Fill in field comments help to identify fields quickly later.', +} diff --git a/web/src/lang/backend/en/security/sensitiveDataLog.ts b/web/src/lang/backend/en/security/sensitiveDataLog.ts new file mode 100644 index 0000000..f5c7167 --- /dev/null +++ b/web/src/lang/backend/en/security/sensitiveDataLog.ts @@ -0,0 +1,18 @@ +export default { + 'Operation administrator': 'Operation administrator', + 'Rule name': 'Rule name', + controller: 'Controller', + 'data sheet': 'Data table', + 'Modify line': 'Modify row', + Modification: 'Modify item', + 'Before modification': 'Before modification', + 'After modification': 'After modification', + 'Modification time': 'Modify time', + 'Are you sure you want to rollback the record?': 'Are you sure to rollback the record?', + 'Rollback the selected record to the original data table': 'Rollback the selected record to the original data table.', + 'Operator IP': 'Operator IP', + 'Data table primary key': 'Data table primary key', + 'Modified item': 'Modified item', + 'Modification comparison': 'Modify the comparison', + RollBACK: 'Rollback', +} diff --git a/web/src/lang/backend/en/user/group.ts b/web/src/lang/backend/en/user/group.ts new file mode 100644 index 0000000..8f6b6cc --- /dev/null +++ b/web/src/lang/backend/en/user/group.ts @@ -0,0 +1,5 @@ +export default { + GroupName: 'Group name', + 'Group name': 'Group name', + jurisdiction: 'Permissions', +} diff --git a/web/src/lang/backend/en/user/moneyLog.ts b/web/src/lang/backend/en/user/moneyLog.ts new file mode 100644 index 0000000..0714c79 --- /dev/null +++ b/web/src/lang/backend/en/user/moneyLog.ts @@ -0,0 +1,16 @@ +export default { + 'User name': 'Username', + 'User nickname': 'User nickname', + balance: 'Balance', + 'User ID': 'User ID', + 'Change balance': 'Change balance', + 'Before change': 'Before the change', + 'After change': 'After the change', + remarks: 'Remark', + 'Current balance': 'Current balance', + 'Change amount': 'Change amount', + 'Please enter the balance change amount': 'Please enter the balance change amount.', + 'Balance after change': 'Balance after change', + 'Please enter change remarks / description': 'Please enter change remarks/description', + User: 'User', +} diff --git a/web/src/lang/backend/en/user/rule.ts b/web/src/lang/backend/en/user/rule.ts new file mode 100644 index 0000000..9d2b92f --- /dev/null +++ b/web/src/lang/backend/en/user/rule.ts @@ -0,0 +1,26 @@ +export default { + 'Normal routing': 'Normal routing', + 'Member center menu contents': 'Member center menu directory ', + 'Member center menu items': 'Member Center menu items', + 'Top bar menu items': 'Top bar menu items', + 'Page button': 'Page button', + 'Top bar user dropdown': 'Top bar user dropdown', + 'Type route tips': 'Automatically register as a front-end route', + 'Type menu_dir tips': 'Automatically register routes and serve as menu directory of member center This item cannot jump', + 'Type menu tips': 'Automatically register routes and serve as menu items in member centers', + 'Type nav tips': 'Routes are automatically registered as menu items in the top bar of the site', + 'Type button tips': 'Automatic registration as a permission node, can be quickly verified by v-auth', + 'Type nav_user_menu tips': 'Automatically register routes and serve as a dropdown menu for top bar members', + 'English name': 'English name', + 'Web side routing path': 'Web side routing path', + no_login_valid: 'no login valid', + 'no_login_valid 0': 'no', + 'no_login_valid 1': 'yes', + 'no_login_valid tips': 'Tourists do not have membership groups Use this option to set whether the current rules are valid for tourists (visible)', + 'For example, if you add account/overview as a route only': + 'Please start with /src for web side component paths, such as: /src/views/frontend/index.vue', + 'Web side component path, please start with /src, such as: /src/views/frontend/index': + "For example, if you add 'account/overview' as a route only, then you can additionally add 'account/overview', 'account/overview/:a' and 'account/overview/:b/:C' as menus only.", + 'Component path tips': + 'This item is mandatory within a WEB project; otherwise, it cannot be accessed. However, when it is used as a menu within a Nuxt project, there is no need to fill in this item', +} diff --git a/web/src/lang/backend/en/user/scoreLog.ts b/web/src/lang/backend/en/user/scoreLog.ts new file mode 100644 index 0000000..54a5ab6 --- /dev/null +++ b/web/src/lang/backend/en/user/scoreLog.ts @@ -0,0 +1,8 @@ +export default { + integral: 'Integral', + 'Change points': 'Change points', + 'Current points': 'Current points', + 'Please enter the change amount of points': 'Please enter the change amount of points', + 'Points after change': 'Points after change', + 'Please enter change remarks / description': 'Please enter change remarks/description', +} diff --git a/web/src/lang/backend/en/user/user.ts b/web/src/lang/backend/en/user/user.ts new file mode 100644 index 0000000..4a51286 --- /dev/null +++ b/web/src/lang/backend/en/user/user.ts @@ -0,0 +1,22 @@ +export default { + 'User name': 'Username', + nickname: 'Nickname', + group: 'Group', + avatar: 'Avatar', + Gender: 'Gender', + male: 'Male', + female: 'Female', + mobile: 'Mobile Number', + 'Last login IP': 'Last login IP', + 'Last login': 'Last login', + email: 'Email', + birthday: 'Birthday', + balance: 'Balance', + 'Adjustment balance': 'Adjust balance', + integral: 'Integral', + 'Adjust integral': 'Adjust integral', + password: 'Password', + 'Please leave blank if not modified': 'Please leave blank if you do not modify', + 'Personal signature': 'Personal signature', + 'Login account': 'Login account name', +} diff --git a/web/src/lang/backend/zh-cn.ts b/web/src/lang/backend/zh-cn.ts new file mode 100644 index 0000000..031c5f3 --- /dev/null +++ b/web/src/lang/backend/zh-cn.ts @@ -0,0 +1,101 @@ +/** + * 后台公共语言包 + * 覆盖风险:请避免使用页面语言包的目录名、文件名作为翻译 key + */ +export default { + Balance: '余额', + Integral: '积分', + Connection: '连接标识', + 'Database connection': '数据库连接配置标识', + 'Database connection help': '您可以在 config/database.php 内配置多个数据库连接,然后在此处选择它,留空将使用默认连接配置', + layouts: { + 'Layout configuration': '布局配置', + 'Layout mode': '布局方式', + default: '默认', + classic: '经典', + 'Single column': '单栏', + 'Double column': '双栏', + 'overall situation': '全局', + 'Background page switching animation': '后台页面切换动画', + 'Please select an animation name': '请选择动画名称', + sidebar: '侧边栏', + 'Side menu bar background color': '侧边菜单栏背景色', + 'Side menu text color': '侧边菜单文字颜色', + 'Side menu active item background color': '侧边菜单激活项背景色', + 'Side menu active item text color': '侧边菜单激活项文字色', + 'Show side menu top bar (logo bar)': '显示侧边菜单顶栏(LOGO栏)', + 'Side menu top bar background color': '侧边菜单顶栏背景色', + 'Side menu width (when expanded)': '侧边菜单宽度(展开时)', + 'Side menu default icon': '侧边菜单默认图标', + 'Side menu horizontal collapse': '侧边菜单水平折叠', + 'Side menu accordion': '侧边菜单手风琴', + 'Top bar': '顶栏', + 'Top bar background color': '顶栏背景色', + 'Top bar text color': '顶栏文字色', + 'Background color when hovering over the top bar': '顶栏悬停时背景色', + 'Top bar menu active item background color': '顶栏菜单激活项背景色', + 'Top bar menu active item text color': '顶栏菜单激活项文字色', + 'Are you sure you want to restore all configurations to the default values?': '确定要恢复全部配置到默认值吗?', + 'Restore default': '恢复默认', + Profile: '个人资料', + Logout: '注销', + 'Dark mode': '暗黑模式', + 'Exit full screen': '退出全屏', + 'Full screen is not supported': '您的浏览器不支持全屏,请更换浏览器再试~', + 'Member center': '会员中心', + 'Member information': '会员信息', + 'Login to the buildadmin': '登录到 BuildAdmin 开源社区', + 'Please enter buildadmin account name or email': '请输入 BuildAdmin 账户名/邮箱/手机号', + 'Please enter the buildadmin account password': '请输入 BuildAdmin 账户密码', + Login: '登录', + Password: '密码', + Username: '用户名', + Register: '没有账户?去注册', + }, + terminal: { + Source: '源', + Terminal: '终端', + 'Command run log': '命令运行日志', + 'No mission yet': '还没有任务...', + 'Test command': '测试命令', + 'Install dependent packages': '安装依赖包', + Republish: '重新发布', + 'Clean up task list': '清理任务列表', + unknown: '未知', + 'Waiting for execution': '等待执行', + Connecting: '连接中...', + Executing: '执行中...', + 'Successful execution': '执行成功', + 'Execution failed': '执行失败', + 'Unknown execution result': '执行结果未知', + 'Are you sure you want to republish?': '确认要重新发布吗?', + 'Failure to execute this command will block the execution of the queue': '本命令执行失败会阻断队列执行', + 'NPM package manager': 'NPM 包管理器', + 'NPM package manager tip': '选择一个可用的包管理器,用于 WEB 终端中 npm install 等命令的执行', + 'Clear successful task': '清理成功任务', + 'Clear successful task tip': '开始一个新任务时,自动清理列表中已经成功的任务', + 'Manual execution': '手动执行', + 'Do not refresh the browser': '请勿刷新浏览器', + 'Terminal settings': '终端设置', + 'Back to terminal': '回到终端', + or: '或', + 'Site domain name': '站点域名', + 'The current terminal is not running under the installation service, and some commands may not be executed': + '当前终端未运行于安装服务下,部分命令可能无法执行。', + 'Newly added tasks will never start because they are blocked by failed tasks': '新添加的任务永远不会开始,因为被失败的任务阻塞!(WEB终端)', + 'Failed to modify the source command, Please try again manually': '修改源的命令执行失败,请手动重试。', + }, + vite: { + Later: '稍后', + 'Restart hot update': '重启热更新', + 'Close type terminal': 'WEB终端执行命令', + 'Close type crud': 'CRUD代码生成服务', + 'Close type modules': '模块安装服务', + 'Close type config': '修改系统配置', + 'Reload hot server title': '需要重启 Vite 热更新服务', + 'Reload hot server tips 1': '为确保', + 'Reload hot server tips 2': + '不被打断,系统暂停了 Vite 的热更新功能,期间前端文件变动将不会实时更新和自动重载网页,现检测到服务暂停期间存在文件更新,需要重启热更新服务。', + 'Reload hot server tips 3': '热更新暂停不影响已经加载好的功能,您可以继续操作,并在一切就绪后再点击重新启动热更新服务。', + }, +} diff --git a/web/src/lang/backend/zh-cn/auth/admin.ts b/web/src/lang/backend/zh-cn/auth/admin.ts new file mode 100644 index 0000000..e5c671f --- /dev/null +++ b/web/src/lang/backend/zh-cn/auth/admin.ts @@ -0,0 +1,13 @@ +export default { + username: '用户名', + nickname: '昵称', + group: '角色组', + avatar: '头像', + email: '电子邮箱', + mobile: '手机号', + 'Last login': '最后登录', + Password: '密码', + 'Please leave blank if not modified': '不修改请留空', + 'Personal signature': '个性签名', + 'Administrator login': '管理员登录名', +} diff --git a/web/src/lang/backend/zh-cn/auth/adminLog.ts b/web/src/lang/backend/zh-cn/auth/adminLog.ts new file mode 100644 index 0000000..ec22a0a --- /dev/null +++ b/web/src/lang/backend/zh-cn/auth/adminLog.ts @@ -0,0 +1,12 @@ +export default { + admin_id: '管理ID', + username: '管理用户名', + title: '标题', + data: '请求数据', + url: 'URL', + ip: 'IP', + useragent: 'UserAgent', + 'Operation administrator': '操作管理员', + 'Operator IP': '操作人IP', + 'Request data': '请求数据', +} diff --git a/web/src/lang/backend/zh-cn/auth/group.ts b/web/src/lang/backend/zh-cn/auth/group.ts new file mode 100644 index 0000000..18f6a82 --- /dev/null +++ b/web/src/lang/backend/zh-cn/auth/group.ts @@ -0,0 +1,8 @@ +export default { + GroupName: '组名', + 'Group name': '组别名称', + jurisdiction: '权限', + 'Parent group': '上级分组', + 'The parent group cannot be the group itself': '上级分组不能是分组本身', + 'Manage subordinate role groups here': '在此管理下级角色组(您拥有下级角色组的所有权限并且拥有额外的权限,不含同级)', +} diff --git a/web/src/lang/backend/zh-cn/auth/rule.ts b/web/src/lang/backend/zh-cn/auth/rule.ts new file mode 100644 index 0000000..dc2fb88 --- /dev/null +++ b/web/src/lang/backend/zh-cn/auth/rule.ts @@ -0,0 +1,49 @@ +export default { + title: '标题', + Icon: '图标', + name: '名称', + type: '类型', + cache: '缓存', + 'Superior menu rule': '上级菜单规则', + 'Rule type': '规则类型', + 'type menu_dir': '菜单目录', + 'type menu': '菜单项', + 'type button': '页面按钮', + 'Rule title': '规则标题', + 'Rule name': '规则名称', + 'Routing path': '路由路径', + 'Rule Icon': '规则图标', + 'Menu type': '菜单类型', + 'Menu type tab': '选项卡', + 'Menu type link (offsite)': '链接(站外)', + 'Link address': '链接地址', + 'Component path': '组件路径', + 'Extended properties': '扩展属性', + 'Add as route only': '只添加为路由', + 'Add as menu only': '只添加为菜单', + 'Rule comments': '规则备注', + 'Rule weight': '规则权重', + 'Create Page Button': '创建页面按钮', + 'Create Page Button index': '查看', + 'Create Page Button add': '添加', + 'Create Page Button edit': '编辑', + 'Create Page Button del': '删除', + 'Create Page Button sortable': '快速排序', + 'Create Page Button tips': '创建菜单的同时,自动创建菜单的页面按钮(权限节点),若需自定义按钮请后续手动添加', + 'Please select the button for automatically creating the desired page': '请选择需要自动创建的页面按钮', + 'Please enter the weight of menu rule (sort by)': '请输入菜单规则权重(排序依据)', + 'Please enter the correct URL': '请输入正确的 URL', + 'The superior menu rule cannot be the rule itself': '上级菜单规则不能是规则本身', + 'It will be registered as the web side routing name and used as the server side API authentication': + '将注册为 WEB 端路由名称,同时作为服务端方法名验权(有此节点权限才能请求对应控制器或方法)', + 'Please enter the URL address of the link or iframe': '请输入链接或 Iframe 的 URL 地址', + 'English name, which does not need to start with `/admin`, such as auth/menu': '英文名称,无需以 `/admin` 开头,如:auth/menu', + 'Web side component path, please start with /src, such as: /src/views/backend/dashboard': + 'WEB 端组件路径,请以 /src 开头,如:/src/views/backend/dashboard.vue', + 'The web side routing path (path) does not need to start with `/admin`, such as auth/menu': + 'vue-router 的 path,无需以 `/admin` 开头,如:auth/menu', + 'Use in controller `get_ route_ Remark()` function, which can obtain the value of this field for your own use, such as the banner file of the console': + '在控制器中使用 `get_route_remark()` 函数,可以获得此字段值自用,比如控制台的 Banner 文案', + 'extend Title': '比如将 `auth/menu` 只添加为路由,那么可以另外将 `auth/menu`、`auth/menu/:a`、`auth/menu/:b/:c` 只添加为菜单', + none: '无', +} diff --git a/web/src/lang/backend/zh-cn/crud/crud.ts b/web/src/lang/backend/zh-cn/crud/crud.ts new file mode 100644 index 0000000..104dbed --- /dev/null +++ b/web/src/lang/backend/zh-cn/crud/crud.ts @@ -0,0 +1,168 @@ +export default { + show: '在表格列中显示', + width: '表格列宽度', + sortable: '字段排序', + operator: '公共搜索操作符', + comSearchRender: '公共搜索输入框渲染方案', + comSearchInputAttr: '公共搜索输入框扩展属性', + comSearchInputAttrTip: '格式如:size=large,一行一个属性,远程下拉的公共搜索也渲染为远程下拉时,此处免填远程下拉组件的必填属性', + render: '渲染方案', + timeFormat: '格式化方式', + step: '步进值', + rows: '行数', + 'api url': '数据接口URL', + 'api url example': '比如: /admin/user.User/index', + 'remote-pk': '远程下拉 value 字段', + 'remote-field': '远程下拉 label 字段', + 'remote-url': '远程下拉数据接口 URL', + 'remote-controller': '关联表的控制器', + 'remote-table': '关联数据表', + 'remote-model': '关联表的模型', + 'remote-primary-table-alias': '主表别名', + 'relation-fields': '关联表显示字段', + 'image-multi': '图片多选上传', + 'file-multi': '文件多选上传', + 'select-multi': '下拉框多选', + validator: '验证规则', + validatorMsg: '验证错误提示', + copy: '复制设计', + 'CRUD record': 'CRUD 记录', + 'Delete Code': '删除代码', + 'Start CRUD design with this record?': '以此记录开始 CRUD 设计?', + 'Are you sure to delete the generated CRUD code?': '确认删除生成的 CRUD 代码?', + start: '开始', + create: '新建', + or: '或', + 'New background CRUD from zero': '从零新建后台 CRUD', + 'Select Data Table': '选择数据表', + 'Select a designed data table from the database': '从数据库中选择一个设计好的数据表', + 'Start with previously generated CRUD code': '从以往生成的 CRUD 代码开始', + 'Fast experience': '快速体验', + 'Please enter SQL': '请输入 SQL', + 'Please select a data table': '请选择数据表', + 'data sheet help': '数据表前缀需要同项目配置的数据表前缀一致', + 'data sheet': '数据表', + 'table create SQL': '建表 SQL', + 'Please enter the table creation SQL': '请输入建表 SQL', + 'experience 1 1': '准备好', + 'experience 1 2': '开发环境', + 'experience 1 3': '(站点端口为:1818)', + 'experience 2 1': '在本页点击', + 'experience 2 2': '选择数据表', + 'experience 2 3': '(可选择 test_build 数据表)', + 'experience 3 1': '点击', + 'experience 3 2': '生成 CRUD 代码', + 'experience 3 3': ',点击', + 'experience 3 4': '继续生成', + 'experience 4 1': '您当前未在开发环境,请 ', + 'experience 4 2': '搭建开发环境', + 'experience 4 3': ',或生成好代码之后点击右上角终端内的', + 'experience 4 4': '重新发布', + // design + 'Name of the data table': '数据表的名称', + 'Data Table Notes': '数据表注释', + 'Generate CRUD code': '生成 CRUD 代码', + 'give up': '放弃', + 'Table Quick Search Fields': '表格快速搜索字段', + 'Table Default Sort Fields': '表格默认排序字段', + 'sort order': '排序方式', + 'sort order asc': 'asc-顺序', + 'sort order desc': 'desc-倒序', + 'Fields as Table Columns': '作为表格列的字段', + 'Fields as form items': '作为表单项的字段', + 'The relative path to the generated code': '生成代码的相对位置', + 'For quick combination code generation location, please fill in the relative path': '快速的组合代码生成位置,请填写相对路径', + 'Generated Controller Location': '生成的控制器位置', + 'Generated Data Model Location': '生成的数据模型位置', + 'Generated Validator Location': '生成的验证器位置', + 'WEB end view directory': 'WEB端视图目录', + 'Check model class': "请检查以上数据模型类中是否已经配置 protected $connection = '{connection}';", + 'There is no connection attribute in model class': '未配置请手动配置。', + 'Common model': '公共模型', + 'Advanced Configuration': '高级配置', + 'Common Fields': '常用字段', + 'Base Fields': '基础字段', + 'Advanced Fields': '高级字段', + 'Field Name': '字段名', + 'field comment': '字段注释', + 'Please select a field from the left first': '请先从左侧选择一个字段', + Common: '常用', + 'Generate type': '生成类型', + 'Field comments (CRUD dictionary)': '字段注释(CRUD 字典)', + 'Field Properties': '字段属性', + 'Field Type': '字段类型', + length: '长度', + 'decimal point': '小数点', + 'Field Defaults': '字段默认值', + 'Please input the default value': '请输入默认值', + 'Auto increment': '自动递增', + Unsigned: '无符号', + 'Allow NULL': '允许 NULL', + 'Field Form Properties': '字段表单属性', + 'Field Table Properties': '字段表格属性', + 'Remote drop-down association information': '远程下拉关联信息', + 'Associated Data Table': '关联数据表', + 'Drop down value field': '下拉 value 字段', + 'Drop down label field': '下拉 label 字段', + 'Please select the value field of the select component': '请选择 select 组件的 value 字段', + 'Please select the label field of the select component': '请选择 select 组件的 label 字段', + 'Fields displayed in the table': '在表格中显示的字段', + 'Please select the fields displayed in the table': '请选择在表格中显示的字段', + 'Controller position': '控制器位置', + 'Please select the controller of the data table': '请选择数据表的控制器', + 'Data Model Location': '数据模型位置', + 'Please select the data model location of the data table': '请选择数据表的数据模型位置', + 'Data source configuration type': '数据源配置类型', + 'Fast configuration with generated controllers and models': '通过已生成好的控制器和模型快速配置', + 'Custom configuration': '自定义配置', + 'If the remote interface query involves associated query of multiple tables, enter the alias of the primary data table here': + '如果远程接口查询数据时涉及多表关联查询,请在此填写主数据表的别名', + 'Confirm CRUD code generation': '确认生成 CRUD 代码', + 'Continue building': '继续生成', + 'Please enter the data table name!': '请输入数据表名!', + 'Please enter the correct table name!': '请输入正确的数据表名!', + 'Use lower case underlined for table names': '请使用小写加下划线作为表名,小写字母开头,可以带有数字', + 'Please design the primary key field!': '请设计主键字段!', + 'It is irreversible to give up the design Are you sure you want to give up?': '放弃设计不可逆,确定要放弃吗?', + 'There can only be one primary key field': '只可以有一个主键字段。', + 'Drag the left element here to start designing CRUD': '拖动左侧元素至此处以开始设计CRUD', + 'The data table already exists Continuing to generate will automatically delete the original table and create a new one!': + '数据表已经存在,继续生成将自动删除原表并建立新的数据表(数据表是空的或您已勾选删表重建)!', + 'The controller already exists Continuing to generate will automatically overwrite the existing code!': + '控制器已经存在,继续生成将自动覆盖已有代码!', + 'The menu rule with the same name already exists The menu and permission node will not be created in this generation': + '同名菜单规则已经存在,本次生成将不会创建菜单和权限节点!', + 'For example: `user table` will be generated into `user management`': '如:会员表(将生成为会员管理)', + 'The remote pull-down will request the corresponding controller to obtain data, so it is recommended that you create the CRUD of the associated table': + '远程下拉将请求该控制器的 index 方法来获取 value 和 label 字段数据,所以请先生成好被关联表的CRUD', + 'If it is left blank, the model of the associated table will be generated automatically If the table already has a model, it is recommended to select it to avoid repeated generation': + '留空则自动生成关联表的模型,若该表已有模型,请选择好以免重复生成', + 'The field comment will be used as the CRUD dictionary, and will be identified as the field title before the colon, and as the data dictionary after the colon': + '字段注释将作为 CRUD 字典,冒号前将识别为字段标题,冒号后识别为数据字典', + 'Field name is invalid It starts with a letter or underscore and cannot contain any character other than letters, digits, or underscores': + '字段名 {field} 不符合规范,请以 字母、_ 开头,不能出现 字母、数字、下划线 以外的字符', + 'The selected table has already generated records You are advised to start with historical records': + '选择的表已有成功生成的记录,建议从历史记录开始~', + 'Start with the historical record': '从历史记录开始', + 'Add field': '添加字段', + 'Modify field properties': '修改字段属性', + 'Modify field name': '修改字段名称', + 'Delete field': '删除字段', + 'Modify field order': '修改字段顺序', + 'First field': '第一个字段', + After: '之后', + 'Table design change': '表设计变更', + 'Data table design changes preview': '数据表设计变更预览', + designChangeTips: '取消勾选后,则该项变动不会尝试同步至数据表(通常用于已经手动修改过表结构等情况)', + tableReBuild: '删表重建', + tableReBuildBlockHelp: '不调整表结构,直接删除已有数据表并重建,此举可以确保CRUD代码/记录与数据表结构一致', + Yes: '是', + No: '否', + 'If the data is abnormal, repeat the previous step': '数据异常,请重做上步操作', + 'Field name duplication': '字段名称 {field} 重复!', + 'Design remote select tips': + '将自动根据表名生成本字段的名称;确认生成时,字段名 user_id 生成的关联方法名为 user,字段名 developer_done_id 生成的关联方法名为 developerDone,请注意远程下拉字段的名称前缀不要重复', + 'Vite hot warning': '未找到 Vite 热更新服务,请在开发环境生成代码,或点击右上角的WEB终端重新发布', + 'Reset generate type attr': '字段生成类型已修改,是否将字段设计重置为新类型预设的方案?', + 'Design efficiency': '自行确定设计有效性', +} diff --git a/web/src/lang/backend/zh-cn/crud/log.ts b/web/src/lang/backend/zh-cn/crud/log.ts new file mode 100644 index 0000000..165af1c --- /dev/null +++ b/web/src/lang/backend/zh-cn/crud/log.ts @@ -0,0 +1,51 @@ +export default { + id: 'ID', + table_name: '数据表名', + comment: '表注释', + table: '数据表数据', + fields: '字段数据', + sync: '是否上传', + 'sync no': '否', + 'sync yes': '是', + status: '状态', + delete: '删除代码', + 'status delete': '代码已删除', + 'status success': '成功', + 'status error': '失败', + 'status start': '生成中', + create_time: '创建时间', + 'quick Search Fields': 'ID、表名、注释', + 'Upload the selected design records to the cloud for cross-device use': '上传选中的设计记录至云端以跨设备使用', + 'Design records that have been synchronized to the cloud': '已同步至云端的设计记录', + 'Cloud record': '云记录', + Settings: '设置', + 'Login for backup design': '登录以备份设计', + 'CRUD design record synchronization scheme': 'CRUD 设计记录同步方案', + Manual: '手动', + automatic: '自动', + 'When automatically synchronizing records, share them to the open source community': '自动同步记录时分享至开源社区', + 'Not to share': '不分享', + Share: '分享', + 'Enabling sharing can automatically earn community points during development': '开启分享可于开发同时自动获取社区积分', + 'The synchronized CRUD records are automatically resynchronized when they are updated': '已同步的 CRUD 记录被更新时自动重新同步', + 'Do not resynchronize': '不重新同步', + 'Automatic resynchronization': '自动重新同步', + 'No effective design': '无有效设计', + 'Number of fields': '字段数', + 'Upload type': '上传类型', + Update: '更新', + 'New added': '新增', + 'Share to earn points': '分享获得积分', + 'Share to the open source community': '分享至开源社区', + 'No design record': '无设计记录', + Field: '字段', + 'Field information': '字段信息', + 'No field': '无字段', + 'Field name': '字段名', + Note: '注释', + Type: '类型', + Load: '载入', + 'Delete cloud records?': '删除云端记录?', + 'You can use the synchronized design records across devices': + '您可以跨设备使用已同步的设计记录;选择手动同步时,系统不会主动收集任何数据,同时系统永远不会同步表内数据', +} diff --git a/web/src/lang/backend/zh-cn/crud/state.ts b/web/src/lang/backend/zh-cn/crud/state.ts new file mode 100644 index 0000000..73351f9 --- /dev/null +++ b/web/src/lang/backend/zh-cn/crud/state.ts @@ -0,0 +1,19 @@ +export default { + remarks: '备注', + 'Primary key': '主键', + 'Primary key (Snowflake ID)': '主键(雪花ID)', + 'Disable Search': '禁用搜索', + 'Weight (drag and drop sorting)': '权重(拖拽排序)', + 'Status:0=Disabled,1=Enabled': '状态:0=禁用,1=启用', + 'Remote Select (association table)': '远程下拉(关联表)', + 'Remote Select (Multi)': '远程下拉(关联多选)', + 'Radio:opt0=Option1,opt1=Option2': '单选框:opt0=选项一,opt1=选项二', + 'Checkbox:opt0=Option1,opt1=Option2': '复选框:opt0=选项一,opt1=选项二', + Multi: '(多选)', + 'Select:opt0=Option1,opt1=Option2': '下拉框:opt0=选项一,opt1=选项二', + 'Switch:0=off,1=on': '开关:0=关,1=开', + 'Time date (timestamp storage)': '时间日期(时间戳存储)', + 'If left blank, the verifier title attribute will be filled in automatically': '留空则自动填写验证器title属性(看不懂请直接填写完整错误消息)', + 'Weight (automatically generate drag sort button)': '权重(自动生成拖拽排序按钮)', + 'If it is not input, it will be automatically analyzed by the controller': '不输入则以控制器自动解析', +} diff --git a/web/src/lang/backend/zh-cn/dashboard.ts b/web/src/lang/backend/zh-cn/dashboard.ts new file mode 100644 index 0000000..009eaa8 --- /dev/null +++ b/web/src/lang/backend/zh-cn/dashboard.ts @@ -0,0 +1,39 @@ +export default { + 'You have worked today': '您今天已工作了', + 'Continue to work': '继续工作', + 'have a bit of rest': '休息片刻', + 'Member registration': '会员注册量', + 'Total number of members': '会员总数', + 'Number of installed plug-ins': '已装插件数', + 'Membership growth': '会员增长情况', + 'Annex growth': '附件增长情况', + 'New member': '刚刚加入的会员', + 'Joined us': '加入了我们', + 'Member source': '会员来源', + 'Member last name': '会员姓氏', + Loading: '加载中...', + Monday: '周一', + Tuesday: '周二', + Wednesday: '周三', + Thursday: '周四', + Friday: '周五', + Saturday: '周六', + Sunday: '周日', + Visits: '访问量', + 'Registration volume': '注册量', + picture: '图片', + file: '文档', + table: '表格', + other: '其它', + 'Compressed package': '压缩包', + Baidu: '百度', + 'Direct access': '直接访问', + 'take a plane': '坐飞机', + 'Take the high-speed railway': '坐高铁', + 'full name': '姓名', + hour: '小时', + minute: '分', + second: '秒', + day: '天', + 'Number of attachments Uploaded': '附件上传量', +} diff --git a/web/src/lang/backend/zh-cn/login.ts b/web/src/lang/backend/zh-cn/login.ts new file mode 100644 index 0000000..bba33b5 --- /dev/null +++ b/web/src/lang/backend/zh-cn/login.ts @@ -0,0 +1,6 @@ +export default { + 'Please enter an account': '请输入账号', + 'Please input a password': '请输入密码', + 'Hold session': '保持会话', + 'Sign in': '登录', +} diff --git a/web/src/lang/backend/zh-cn/module.ts b/web/src/lang/backend/zh-cn/module.ts new file mode 100644 index 0000000..3d45453 --- /dev/null +++ b/web/src/lang/backend/zh-cn/module.ts @@ -0,0 +1,153 @@ +export default { + 'stateTitle init': '模块安装器初始化...', + 'stateTitle download': '正在下载模块...', + 'stateTitle install': '正在安装模块...', + 'stateTitle getInstallableVersion': '正在获取模块版本列表...', + 'env require': '后端依赖(composer)', + 'env require-dev': '后端开发环境依赖(composer)', + 'env dependencies': '前端依赖(NPM)', + 'env devDependencies': '前端开发环境依赖(NPM)', + 'env nuxtDependencies': '前端依赖(Nuxt-NPM)', + 'env nuxtDevDependencies': '前端开发环境依赖(Nuxt-NPM)', + // buy + 'Module installation warning': '购买后一年内可免费下载和更新,虚拟产品不支持7天无理由退款', + 'Order title': '订单标题', + 'Order No': '订单编号', + 'Purchase user': '购买用户', + 'Order price': '订单价格', + 'Purchased, can be installed directly': '已购买,可直接安装', + 'Understand and agree': '理解并同意', + 'Module purchase and use agreement': '模块购买和使用协议', + 'Point payment': '积分支付', + 'Balance payment': '余额支付', + 'Wechat payment': '微信支付', + 'Alipay payment': '支付宝支付', + 'Install now': '立即安装', + payment: '支付', + 'Confirm order info': '确认订单信息', + // commonDone + 'Congratulations, module installation is complete': '恭喜,模块安装已完成。', + 'Module is disabled': '模块已禁用。', + 'Congratulations, the code of the module is ready': '恭喜,模块的代码已经准备好了。', + 'Unknown state': '未知状态。', + 'Do not refresh the page!': '请勿刷新页面!', + 'New adjustment of dependency detected': '检测到依赖项有新的调整', + 'This module adds new dependencies': '本模块添加了新的依赖项', + 'The built-in terminal of the system is automatically installing these dependencies, please wait~': '系统内置终端正在自动安装这些依赖,请稍等~', + 'View progress': '查看进度', + 'Dependency installation completed~': '依赖已安装完成~', + 'This module does not add new dependencies': '本模块没有添加新的依赖项。', + 'There is no adjustment for system dependency': '系统依赖无调整。', + please: '请', + 'After installation 1': '在安装结束后', + 'Manually clean up the system and browser cache': '手动的清理系统和浏览器缓存。', + 'After installation 2': '安装结束后', + 'Automatically execute reissue command?': '自动执行重新发布命令?', + 'End of installation': '安装结束', + 'Dependency installation fail 1': '依赖安装失败,请点击', + 'Dependency installation fail 2': '终端', + 'Dependency installation fail 3': '中的重试按钮,您也可以查看', + 'Dependency installation fail 4': '手动完成未尽事宜', + 'Dependency installation fail 5': '在您', + 'Dependency installation fail 6': '确定依赖已准备好', + 'Dependency installation fail 7': '之前,模块还不能正常使用!', + 'Is the command that failed on the WEB terminal executed manually or in other ways successfully?': + 'WEB终端失败的命令已经手动或以其他方式执行成功?', + yes: '是', + no: '否', + // confirmFileConflict + 'Update warning': '检测到以下的模块文件有更新,禁用时将自动覆盖,请注意备份。', + 'File conflict': '文件冲突', + 'Conflict file': '冲突文件', + 'Dependency conflict': '依赖冲突', + 'Confirm to disable the module': '确认禁用模块', + 'The module declares the added dependencies': '模块声明添加的依赖', + Dependencies: '依赖项', + retain: '保留', + // goodsInfo + 'detailed information': '详细信息', + Price: '价格', + 'Last updated': '最后更新', + 'Published on': '发布时间', + 'amount of downloads': '下载次数', + 'Module classification': '模块分类', + 'Module documentation': '模块文档', + 'Developer Homepage': '开发者主页', + 'Click to access': '点击访问', + 'Module status': '模块状态', + 'View demo': '查看演示', + 'Code scanning Preview': '扫码预览', + 'Buy now': '立即购买', + 'continue installation': '继续安装', + installed: '已安装', + 'to update': '更新', + uninstall: '卸载', + 'Contact developer': '联系开发者', + 'Other works of developers': 'TA的其他作品', + 'There are no more works': '没有更多作品了', + 'You need to disable this module before updating Do you want to disable it now?': '更新前需要先禁用该模块,立即禁用?', + 'Disable and update': '禁用并更新', + 'No module purchase order was found': '没有找到有效的模块购买订单,是否立即购买当前模块?', + // installConflict + 'new file': '新文件', + 'Existing files': '已有文件', + 'Treatment scheme': '处理方案', + 'Backup and overwrite existing files': '备份并覆盖已有文件', + 'Discard new file': '丢弃新文件', + environment: '环境', + 'New dependency': '新依赖', + 'Existing dependencies': '已有依赖', + 'Overwrite existing dependencies': '覆盖已有依赖', + 'Do not use new dependencies': '不使用新依赖', + // tableHeader + 'Upload zip package for installation': '上传ZIP包安装', + 'Upload installation': '上传安装', + 'Uploaded / installed modules': '已上传/安装的模块', + 'Local module': '本地模块', + 'Publishing module': '发布模块', + 'Get points': '获得积分', + 'Search is actually very simple': '搜索其实很简单', + // tabs + Loading: '加载中...', + 'No more': '没有更多了...', + // uploadInstall + 'Local upload warning': '请您务必确认模块包文件来自官方渠道或经由官方认证的模块作者,否则系统可能被破坏,因为:', + 'The module can modify and add system files': '模块可以修改和新增系统文件', + 'The module can execute sql commands and codes': '模块可以执行sql命令和代码', + 'The module can install new front and rear dependencies': '模块可以安装新的前后端依赖', + 'Drag the module package file here': '拖拽模块包文件到此处或', + 'Click me to upload': '点击我上传', + 'Uploaded, installation is about to start, please wait': '已上传,即将开始安装,请稍等', + 'Update Log': '更新日志', + 'No detailed update log': '无详细更新日志', + 'Use WeChat to scan QR code for payment': '使用微信扫描二维码支付', + 'Use Alipay to scan QR code for payment': '使用支付宝扫描二维码支付', + 'dependency-installation-fail-tips': '若手动执行命令成功,可点击以上的 `确定依赖已准备好` 将模块修改为已安装状态。', + 'New version': '有新版本', + Install: '安装', + 'Installation cancelled because module already exists!': '安装取消,因为模块已经存在!', + 'Installation cancelled because the directory required by the module is occupied!': '安装取消,因为模块所需目录被占用!', + 'Installation complete': '安装完成', + 'A conflict is found Please handle it manually': '发现冲突,请手动处理', + 'Select Version': '选择安装版本', + 'Wait for dependent installation': '等待依赖安装', + 'The operation succeeds Please clear the system cache and refresh the browser ~': '操作成功,请清理系统缓存并刷新浏览器~', + 'Deal with conflict': '处理冲突', + 'Wait for installation': '等待安装', + 'Conflict pending': '冲突待处理', + 'Dependency to be installed': '依赖待安装', + 'Restart Vite hot server': '重启热更新服务', + 'Restart Vite hot server tips': '在完成服务重启之前,您还可以随时从顶栏右侧的按钮组中找到手动重启服务的按钮。', + 'Manual restart': '手动重启', + 'Restart Now': '立即重启', + // 选择安装版本 + 'Available system version': '可用系统版本', + Description: '描述', + Version: '版本', + 'Current installed version': '当前安装版本', + 'Insufficient system version': '系统版本不足', + 'Click to install': '点击安装', + 'Versions released beyond the authorization period': '授权期限以外发布的版本', + Renewal: '续费', + 'Order expiration time': '当前订单授权过期时间为 {expiration_time},此版本发布时间为 {create_time}', +} diff --git a/web/src/lang/backend/zh-cn/routine/adminInfo.ts b/web/src/lang/backend/zh-cn/routine/adminInfo.ts new file mode 100644 index 0000000..fec914f --- /dev/null +++ b/web/src/lang/backend/zh-cn/routine/adminInfo.ts @@ -0,0 +1,14 @@ +export default { + 'Last logged in on': '上次登录于', + 'user name': '用户名', + 'User nickname': '用户昵称', + 'Please enter a nickname': '请输入昵称', + 'e-mail address': '邮箱地址', + 'phone number': '手机号码', + autograph: '签名', + 'This guy is lazy and doesn write anything': '这家伙很懒,什么也没写', + 'New password': '新密码', + 'Please leave blank if not modified': '不修改请留空', + 'Save changes': '保存修改', + 'Operation log': '操作日志', +} diff --git a/web/src/lang/backend/zh-cn/routine/attachment.ts b/web/src/lang/backend/zh-cn/routine/attachment.ts new file mode 100644 index 0000000..a33d93a --- /dev/null +++ b/web/src/lang/backend/zh-cn/routine/attachment.ts @@ -0,0 +1,24 @@ +export default { + 'Upload administrator': '上传管理员', + 'Upload user': '上传会员', + 'Storage mode': '存储方式', + 'Physical path': '物理路径', + 'image width': '图片宽度', + 'Picture height': '图片高度', + 'file size': '文件大小', + 'mime type': 'mime类型', + 'SHA1 code': 'sha1', + 'The file is saved in the directory, and the file will not be automatically transferred if the record is modified': + '文件保存目录,修改记录不会自动转移文件', + 'File saving path Modifying records will not automatically transfer files': '文件保存路径,修改记录不会自动转移文件', + 'Width of picture file': '图片文件的宽度', + 'Height of picture file': '图片文件的高度', + 'Original file name': '文件原始名称', + 'File size (bytes)': '文件大小(bytes)', + 'File MIME type': '文件mime类型', + 'Upload (Reference) times of this file': '此文件的上传(引用)次数', + 'When the same file is uploaded multiple times, only one attachment record will be saved and added': + '同一文件被多次上传时,只会保存一份和增加一条附件记录', + 'SHA1 encoding of file': '文件的sha1编码', + 'Files and records will be deleted at the same time Are you sure?': '将同时删除文件和记录,确认吗?', +} diff --git a/web/src/lang/backend/zh-cn/routine/config.ts b/web/src/lang/backend/zh-cn/routine/config.ts new file mode 100644 index 0000000..401a8dd --- /dev/null +++ b/web/src/lang/backend/zh-cn/routine/config.ts @@ -0,0 +1,16 @@ +export default { + 'Are you sure to delete the configuration item?': '确定删除配置项吗?', + 'Add configuration item': '添加配置项', + 'Quick configuration entry': '快捷配置入口', + 'Variable name': '变量名', + 'Variable group': '变量分组', + 'Variable title': '变量标题', + 'Variable type': '变量类型', + number: '数字', + 'Please enter the recipient email address': '请输入接收者邮箱地址', + 'Test mail sending': '测试邮件发送', + 'send out': '发送', + 'Please enter the correct email address': '请输入正确的电子邮箱地址', + Sending: '发送中...', + 'Please enter the correct mail configuration': '请输入正确的邮件配置', +} diff --git a/web/src/lang/backend/zh-cn/security/dataRecycle.ts b/web/src/lang/backend/zh-cn/security/dataRecycle.ts new file mode 100644 index 0000000..736e713 --- /dev/null +++ b/web/src/lang/backend/zh-cn/security/dataRecycle.ts @@ -0,0 +1,10 @@ +export default { + 'Rule name': '规则名称', + controller: '控制器', + 'data sheet': '数据表', + 'Data table primary key': '数据表主键', + 'Deleting monitoring': '删除监控中', + 'The rule name helps to identify deleted data later': '规则名称有助于后续识别被删数据', + 'The data collection mechanism will monitor delete operations under this controller': '数据回收机制将监控此控制器下的删除操作', + 'Corresponding data sheet': '对应数据表', +} diff --git a/web/src/lang/backend/zh-cn/security/dataRecycleLog.ts b/web/src/lang/backend/zh-cn/security/dataRecycleLog.ts new file mode 100644 index 0000000..e6743a5 --- /dev/null +++ b/web/src/lang/backend/zh-cn/security/dataRecycleLog.ts @@ -0,0 +1,17 @@ +export default { + restore: '还原', + 'Are you sure to restore the selected records?': '确定还原选中记录?', + 'Restore the selected record to the original data table': '还原选中记录到原数据表', + 'Operation administrator': '操作管理员', + 'Recycling rule name': '回收规则名称', + 'Rule name': '规则名称', + controller: '控制器', + 'data sheet': '数据表', + DeletedData: '被删数据', + 'Arbitrary fragment fuzzy query': '任意片段模糊查询', + 'Click to expand': '点击展开', + 'Data table primary key': '数据表主键', + 'Operator IP': '操作者IP', + 'Deleted data': '被删除的数据', + 'Delete time': '删除时间', +} diff --git a/web/src/lang/backend/zh-cn/security/sensitiveData.ts b/web/src/lang/backend/zh-cn/security/sensitiveData.ts new file mode 100644 index 0000000..7431a3a --- /dev/null +++ b/web/src/lang/backend/zh-cn/security/sensitiveData.ts @@ -0,0 +1,12 @@ +export default { + 'Rule name': '规则名称', + controller: '控制器', + 'data sheet': '数据表', + 'Data table primary key': '数据表主键', + 'Sensitive fields': '敏感字段', + 'Modifying monitoring': '修改监控中', + 'The rule name helps to identify the modified data later': '规则名称有助于后续识别被修改数据', + 'The data listening mechanism will monitor the modification operations under this controller': '数据监听机制将监控此控制器下的修改操作', + 'Corresponding data sheet': '对应数据表', + 'Filling in field notes helps you quickly identify fields later': '填写字段注释有助于后续快速识别字段', +} diff --git a/web/src/lang/backend/zh-cn/security/sensitiveDataLog.ts b/web/src/lang/backend/zh-cn/security/sensitiveDataLog.ts new file mode 100644 index 0000000..db6913c --- /dev/null +++ b/web/src/lang/backend/zh-cn/security/sensitiveDataLog.ts @@ -0,0 +1,18 @@ +export default { + 'Operation administrator': '操作管理员', + 'Rule name': '规则名称', + controller: '控制器', + 'data sheet': '数据表', + 'Modify line': '修改行', + Modification: '修改项', + 'Before modification': '修改前', + 'After modification': '修改后', + 'Modification time': '修改时间', + 'Are you sure you want to rollback the record?': '确认要回滚记录吗?', + 'Rollback the selected record to the original data table': '回滚选中记录到原数据表', + 'Operator IP': '操作者IP', + 'Data table primary key': '数据表主键', + 'Modified item': '被修改项', + 'Modification comparison': '修改对比', + RollBACK: '回滚', +} diff --git a/web/src/lang/backend/zh-cn/user/group.ts b/web/src/lang/backend/zh-cn/user/group.ts new file mode 100644 index 0000000..170fc8c --- /dev/null +++ b/web/src/lang/backend/zh-cn/user/group.ts @@ -0,0 +1,5 @@ +export default { + GroupName: '组名', + 'Group name': '组别名称', + jurisdiction: '权限', +} diff --git a/web/src/lang/backend/zh-cn/user/moneyLog.ts b/web/src/lang/backend/zh-cn/user/moneyLog.ts new file mode 100644 index 0000000..7f40880 --- /dev/null +++ b/web/src/lang/backend/zh-cn/user/moneyLog.ts @@ -0,0 +1,16 @@ +export default { + 'User name': '用户名', + 'User nickname': '用户昵称', + balance: '余额', + 'User ID': '用户ID', + 'Change balance': '变更余额', + 'Before change': '变更前', + 'After change': '变更后', + remarks: '备注', + 'Current balance': '当前余额', + 'Change amount': '变动数额', + 'Please enter the balance change amount': '请输入余额变更数额', + 'Balance after change': '变更后余额', + 'Please enter change remarks / description': '请输入变更备注/说明', + User: '用户', +} diff --git a/web/src/lang/backend/zh-cn/user/rule.ts b/web/src/lang/backend/zh-cn/user/rule.ts new file mode 100644 index 0000000..d2851ad --- /dev/null +++ b/web/src/lang/backend/zh-cn/user/rule.ts @@ -0,0 +1,24 @@ +export default { + 'Normal routing': '普通路由', + 'Member center menu contents': '会员中心菜单目录', + 'Member center menu items': '会员中心菜单项', + 'Top bar menu items': '顶栏菜单项', + 'Page button': '页面按钮', + 'Top bar user dropdown': '顶栏会员菜单下拉项', + 'Type route tips': '自动注册为前端路由', + 'Type menu_dir tips': '自动注册路由,并作为会员中心的菜单目录,此项本身不可跳转', + 'Type menu tips': '自动注册路由,并作为会员中心的菜单项目', + 'Type nav tips': '自动注册路由,并作为站点顶栏的菜单项目', + 'Type button tips': '自动注册为权限节点,可通过 v-auth 快速验权', + 'Type nav_user_menu tips': '自动注册路由,并作为顶栏会员菜单下拉项', + 'English name': '英文名称', + 'Web side routing path': 'WEB 端路由路径(vue-router 的 path)', + no_login_valid: '未登录有效', + 'no_login_valid 0': '游客无效', + 'no_login_valid 1': '游客有效', + 'no_login_valid tips': '游客没有会员分组,通过本选项设置当前规则是否对游客有效(可见)', + 'For example, if you add account/overview as a route only': 'WEB 端组件路径,请以 /src 开头,如:/src/views/frontend/index.vue', + 'Web side component path, please start with /src, such as: /src/views/frontend/index': + '比如将 `account/overview` 只添加为路由,那么可以另外将 `account/overview`、`account/overview/:a`、`account/overview/:b/:c` 只添加为菜单', + 'Component path tips': '组件路径在 WEB 工程内是必填的,否则无法访问,但作为 Nuxt 工程内的菜单时,无需填写此项,请根据菜单使用场景填写', +} diff --git a/web/src/lang/backend/zh-cn/user/scoreLog.ts b/web/src/lang/backend/zh-cn/user/scoreLog.ts new file mode 100644 index 0000000..d6cbb21 --- /dev/null +++ b/web/src/lang/backend/zh-cn/user/scoreLog.ts @@ -0,0 +1,8 @@ +export default { + integral: '积分', + 'Change points': '变更积分', + 'Current points': '当前积分', + 'Please enter the change amount of points': '请输入积分变更数额', + 'Points after change': '变更后积分', + 'Please enter change remarks / description': '请输入变更备注/说明', +} diff --git a/web/src/lang/backend/zh-cn/user/user.ts b/web/src/lang/backend/zh-cn/user/user.ts new file mode 100644 index 0000000..fc9df85 --- /dev/null +++ b/web/src/lang/backend/zh-cn/user/user.ts @@ -0,0 +1,22 @@ +export default { + 'User name': '用户名', + nickname: '昵称', + group: '分组', + avatar: '头像', + Gender: '性别', + male: '男', + female: '女', + mobile: '手机号', + 'Last login IP': '最后登录IP', + 'Last login': '最后登录', + email: '电子邮箱', + birthday: '生日', + balance: '余额', + 'Adjustment balance': '调整余额', + integral: '积分', + 'Adjust integral': '调整积分', + password: '密码', + 'Please leave blank if not modified': '不修改请留空', + 'Personal signature': '个性签名', + 'Login account': '登录账户名', +} diff --git a/web/src/lang/common/en/401.ts b/web/src/lang/common/en/401.ts new file mode 100644 index 0000000..749859a --- /dev/null +++ b/web/src/lang/common/en/401.ts @@ -0,0 +1,4 @@ +export default { + noPowerTip: + "It's not what you want, but we're serious. I want to tell you in a special way that you don't have permission to access this page or the file is invalid. You can contact the website administrator to solve the problem faster or go back home page to view another page.", +} diff --git a/web/src/lang/common/en/404.ts b/web/src/lang/common/en/404.ts new file mode 100644 index 0000000..1f52a21 --- /dev/null +++ b/web/src/lang/common/en/404.ts @@ -0,0 +1,7 @@ +export default { + 'problems tip': + 'Your website has encountered some problems. The system is optimizing and reporting fault information. We will improve and reduce this situation in the future.', + 'We will automatically return to the previous page when we are finished': 'Auto return to previous page when finished.', + 'Return to home page': 'Back to Home', + 'Back to previous page': 'Back to previous page', +} diff --git a/web/src/lang/common/en/axios.ts b/web/src/lang/common/en/axios.ts new file mode 100644 index 0000000..041b202 --- /dev/null +++ b/web/src/lang/common/en/axios.ts @@ -0,0 +1,20 @@ +export default { + 'Operation successful': 'Operate successful', + 'Automatic cancellation due to duplicate request:': 'Automatic cancellation due to duplicate requests:', + 'Interface redirected!': 'Interface redirected!', + 'Incorrect parameter!': 'Incorrect parameter!', + 'You do not have permission to operate!': 'You have no permission to operate!', + 'Error requesting address:': 'Error requesting address:', + 'Request timed out!': 'Request timeout!', + 'The same data already exists in the system!': 'The same data already exists on the system!', + 'Server internal error!': 'Internal server error!', + 'Service not implemented!': 'Service unrealized!', + 'Gateway error!': 'Gateway error!', + 'Service unavailable!': 'Service unavailable!', + 'The service is temporarily unavailable Please try again later!': 'The service is temporarily unavailable, please try again later!', + 'HTTP version is not supported!': 'HTTP version is not Unsupported!', + 'Abnormal problem, please contact the website administrator!': 'Abnormal problems, please contact the website administrator!', + 'Network request timeout!': 'Network request timeout!', + 'Server exception!': 'Server-side exceptions!', + 'You are disconnected!': 'You are disconnected!', +} diff --git a/web/src/lang/common/en/pagesTitle.ts b/web/src/lang/common/en/pagesTitle.ts new file mode 100644 index 0000000..bc97161 --- /dev/null +++ b/web/src/lang/common/en/pagesTitle.ts @@ -0,0 +1,11 @@ +export default { + home: 'Home', + admin: 'Admin', + adminLogin: 'Login', + notFound: 'Page not found', + noPower: 'No access permission', + noTitle: 'No title', + loading: 'Loading...', + user: 'Member Center', + userLogin: 'Menber Login', +} diff --git a/web/src/lang/common/en/utils.ts b/web/src/lang/common/en/utils.ts new file mode 100644 index 0000000..50c3e19 --- /dev/null +++ b/web/src/lang/common/en/utils.ts @@ -0,0 +1,88 @@ +export default { + 'The moving position is beyond the movable range!': 'The movement position is beyond the removable range!', + 'Navigation failed, the menu type is unrecognized!': 'Navigation failed, menu type not recognized!', + 'Navigation failed, navigation guard intercepted!': 'Navigation failed, Navigation Guard interception!', + 'Navigation failed, it is at the navigation target position!': 'Navigation failed, it is already at the navigation the position!', + 'Navigation failed, invalid route!': 'Navigation failed, invalid route!', + 'No child menu to jump to!': 'No child menu to jump to!', + Loading: 'Loading...', + Reload: 'Reload', + comma: ',', + 'welcome back': 'Welcome back!', + 'Late at night, pay attention to your body!': 'It is late at night. Please tack care of your body!', + 'good morning!': 'Good morning!', + 'Good morning!': 'Good morning!', + 'Good noon!': 'Good noon!', + 'good afternoon': 'Good afternoon.', + 'Good evening': 'Good evening', + 'Hello!': 'Hello!', + open: 'Open', + close: 'Close', + 'Clean up system cache': 'Clean up the system cache', + 'Clean up browser cache': 'Clean up browser cache', + 'Clean up all cache': 'Clean up all cache', + 'The data of the uploaded file is incomplete!': 'The data of the uploaded file is incomplete!', + 'The type of uploaded file is not allowed!': 'The type of uploaded file is not allowed!', + 'The size of the uploaded file exceeds the allowed range!': 'The size of the uploaded file exceeds the allowed range!', + 'Please install editor': 'Please install editor', + // 输入框类型 + mobile: 'Mobile Number', + 'Id number': 'Id Number', + account: 'Account name', + password: 'password', + 'variable name': 'Variable Name', + email: 'Email address', + date: 'Date', + number: 'Number', + float: 'Float', + integer: 'Integer', + time: 'Time', + file: 'File', + array: 'Array', + switch: 'Switch', + year: 'Year', + image: 'Image', + select: 'Select', + string: 'String', + radio: 'Radio', + checkbox: 'checkbox', + 'rich Text': 'Rich Text', + 'multi image': 'Multi image', + textarea: 'Textarea', + 'time date': 'Time Date', + 'remote select': 'Remote Select', + 'city select': 'City select', + 'icon select': 'Icon select', + 'color picker': 'color picker', + color: 'color', + choice: ' Choice', + Icon: 'Icon', + 'Local icon title': 'Local icon:/src/assets/icons Inside.svg', + 'Please select an icon': 'Please select an icon', + 'Ali iconcont Icon': 'Ali Iconfont Icon', + 'Select File': 'Select File', + 'Original name': 'Original name', + 'You can also select': 'You can also select', + items: 'items', + Breakdown: 'Detailed catalogue', + size: 'Size', + type: 'Type', + preview: 'Preview', + 'Upload (Reference) times': 'Upload (Reference) times', + 'Last upload time': 'Last upload time', + 'One attribute per line without quotation marks(formitem)': + 'Extensions to FormItem, One attribute per line, no quotation marks required, such as: class=config-item', + 'Extended properties of Input, one line without quotation marks, such as: size=large': + 'Extended properties of Input, one line without quotation marks, such as: size=large', + 'One line at a time, without quotation marks, for example: key1=value1': 'One per line, no quotation marks required, such as: key1=value1', + Var: 'Var ', + Name: 'Name', + Title: 'Title', + Tip: 'Tip', + Rule: 'Rule', + Extend: 'Extend', + Dict: 'Dict', + ArrayKey: 'Key', + ArrayValue: 'Value', + 'No data': 'No data', +} diff --git a/web/src/lang/common/en/validate.ts b/web/src/lang/common/en/validate.ts new file mode 100644 index 0000000..8a821d7 --- /dev/null +++ b/web/src/lang/common/en/validate.ts @@ -0,0 +1,18 @@ +export default { + 'Captcha loading failed, please click refresh button': 'Captcha loading failed, please click refresh button', + 'The correct area is not clicked, please try again!': 'The correct area is not clicked, please try again!', + 'Verification is successful!': 'Verification is successful!', + 'Please click': 'Please click', + 'Please enter the correct mobile number': 'Please enter the correct mobile number', + 'Please enter the correct account': 'The account requires 3 to 15 characters and contains a-z A-Z 0-9 _', + 'Please enter the correct password': 'The password requires 6 to 32 characters and cannot contains & < > " \'', + 'Please enter the correct name': 'Please enter the correct name', + 'Content cannot be empty': 'The content cannot be blank', + 'Floating point number': ' Floating number', + required: 'Required', + 'editor required': 'editor Required', + 'Please enter the correct ID number': 'Please enter the correct ID number', + number: 'Number (including float and integer)', + integer: 'Integer (excluding float)', + float: 'Float (excluding integer)', +} diff --git a/web/src/lang/common/zh-cn/401.ts b/web/src/lang/common/zh-cn/401.ts new file mode 100644 index 0000000..14c30fb --- /dev/null +++ b/web/src/lang/common/zh-cn/401.ts @@ -0,0 +1,4 @@ +export default { + noPowerTip: + '这不是你想要的,但我们是认真的。我只是想用一种特殊的方式告诉你,你无权访问此页面,或者该文件无效。您可以联系网站管理员以更快地解决问题,或返回网站首页浏览其他页面。', +} diff --git a/web/src/lang/common/zh-cn/404.ts b/web/src/lang/common/zh-cn/404.ts new file mode 100644 index 0000000..2ffe98b --- /dev/null +++ b/web/src/lang/common/zh-cn/404.ts @@ -0,0 +1,6 @@ +export default { + 'problems tip': '你的网页遇到了一些问题,系统正在优化和上报故障信息,我们在未来将改善和减少这种情况的发生.', + 'We will automatically return to the previous page when we are finished': '我们将在完成后自动返回到上一页。', + 'Return to home page': '返回首页', + 'Back to previous page': '返回上一页', +} diff --git a/web/src/lang/common/zh-cn/axios.ts b/web/src/lang/common/zh-cn/axios.ts new file mode 100644 index 0000000..c802afe --- /dev/null +++ b/web/src/lang/common/zh-cn/axios.ts @@ -0,0 +1,20 @@ +export default { + 'Operation successful': '操作成功', + 'Automatic cancellation due to duplicate request:': '因为请求重复被自动取消:', + 'Interface redirected!': '接口重定向了!', + 'Incorrect parameter!': '参数不正确!', + 'You do not have permission to operate!': '您没有权限操作!', + 'Error requesting address:': '请求地址出错:', + 'Request timed out!': '请求超时!', + 'The same data already exists in the system!': '系统已存在相同数据!', + 'Server internal error!': '服务器内部错误!', + 'Service not implemented!': '服务未实现!', + 'Gateway error!': '网关错误!', + 'Service unavailable!': '服务不可用!', + 'The service is temporarily unavailable Please try again later!': '服务暂时无法访问,请稍后再试!', + 'HTTP version is not supported!': 'HTTP版本不受支持!', + 'Abnormal problem, please contact the website administrator!': '异常问题,请联系网站管理员!', + 'Network request timeout!': '网络请求超时!', + 'Server exception!': '服务端异常!', + 'You are disconnected!': '您断网了!', +} diff --git a/web/src/lang/common/zh-cn/pagesTitle.ts b/web/src/lang/common/zh-cn/pagesTitle.ts new file mode 100644 index 0000000..39c5a69 --- /dev/null +++ b/web/src/lang/common/zh-cn/pagesTitle.ts @@ -0,0 +1,11 @@ +export default { + home: '首页', + admin: '后台', + adminLogin: '登录', + notFound: '页面找不到了', + noPower: '无访问权限', + noTitle: '无标题', + loading: 'Loading...', + user: '会员中心', + userLogin: '会员登录', +} diff --git a/web/src/lang/common/zh-cn/utils.ts b/web/src/lang/common/zh-cn/utils.ts new file mode 100644 index 0000000..a3c3f2a --- /dev/null +++ b/web/src/lang/common/zh-cn/utils.ts @@ -0,0 +1,86 @@ +export default { + 'The moving position is beyond the movable range!': '移动位置超出了可移动范围!', + 'Navigation failed, the menu type is unrecognized!': '导航失败,菜单类型无法识别!', + 'Navigation failed, navigation guard intercepted!': '导航失败,导航守卫拦截!', + 'Navigation failed, it is at the navigation target position!': '导航失败,已在导航目标位置!', + 'Navigation failed, invalid route!': '导航失败,路由无效!', + 'No child menu to jump to!': '没有找到可以跳转的子级菜单!', + Loading: '加载中...', + Reload: '重新加载', + comma: ',', + 'welcome back': '欢迎回来!', + 'Late at night, pay attention to your body!': '夜深了,注意身体哦!', + 'good morning!': '早上好!', + 'Good morning!': '上午好!', + 'Good noon!': '中午好!', + 'good afternoon': '下午好!', + 'Good evening': '晚上好!', + 'Hello!': '您好!', + open: '开启', + close: '关闭', + 'Clean up system cache': '清理系统缓存', + 'Clean up browser cache': '清理浏览器缓存', + 'Clean up all cache': '一键清理所有', + 'The data of the uploaded file is incomplete!': '上传文件的资料不完整!', + 'The type of uploaded file is not allowed!': '上传文件的类型不被允许!', + 'The size of the uploaded file exceeds the allowed range!': '上传文件的大小超出允许范围!', + 'Please install editor': '请先于模块市场安装富文本编辑器。', + // 输入框类型 + mobile: '手机号', + 'Id number': '身份证号', + account: '账户名', + password: '密码', + 'variable name': '变量名', + email: '邮箱地址', + date: '日期', + number: '数字', + float: '浮点数', + integer: '整数', + time: '时间', + file: '文件', + array: '数组', + switch: '开关', + year: '年份', + image: '图片', + select: '下拉框', + string: '字符串', + radio: '单选框', + checkbox: '复选框', + 'rich Text': '富文本', + 'multi image': '多图', + textarea: '多行文本框', + 'time date': '时间日期', + 'remote select': '远程下拉', + 'city select': '城市选择', + 'icon select': '图标选择', + 'color picker': '颜色选择器', + color: '颜色', + choice: '选择', + Icon: '图标', + 'Local icon title': '本地图标:/src/assets/icons中的.svg', + 'Please select an icon': '请选择图标', + 'Ali iconcont Icon': '阿里 Iconfont 图标', + 'Select File': '选择文件', + 'Original name': '原始名称', + 'You can also select': '还可以选择', + items: '项', + Breakdown: '细目', + size: '大小', + type: '类型', + preview: '预览', + 'Upload (Reference) times': '上传(引用)次数', + 'Last upload time': '最后上传时间', + 'One attribute per line without quotation marks(formitem)': 'FormItem 的扩展属性,一行一个,无需引号,比如:class=config-item', + 'Extended properties of Input, one line without quotation marks, such as: size=large': 'Input 的扩展属性,一行一个,无需引号,比如:size=large', + 'One line at a time, without quotation marks, for example: key1=value1': '一行一个,无需引号,比如:key1=value1', + Var: '变量', + Name: '名', + Title: '标题', + Tip: '提示信息', + Rule: '验证规则', + Extend: '扩展属性', + Dict: '字典数据', + ArrayKey: '键名', + ArrayValue: '键值', + 'No data': '无数据', +} diff --git a/web/src/lang/common/zh-cn/validate.ts b/web/src/lang/common/zh-cn/validate.ts new file mode 100644 index 0000000..6b8ec16 --- /dev/null +++ b/web/src/lang/common/zh-cn/validate.ts @@ -0,0 +1,18 @@ +export default { + 'Captcha loading failed, please click refresh button': '验证码加载失败,请点击刷新按钮', + 'The correct area is not clicked, please try again!': '未点中正确区域,请重试!', + 'Verification is successful!': '验证成功!', + 'Please click': '请依次点击', + 'Please enter the correct mobile number': '请输入正确的手机号', + 'Please enter the correct account': '要求3到15位,字母开头且只含字母、数字、下划线', + 'Please enter the correct password': '密码要求6到32位,不能包含 & < > " \'', + 'Please enter the correct name': '请输入正确的名称', + 'Content cannot be empty': '内容不能为空', + 'Floating point number': '浮点数', + required: '必填', + 'editor required': '富文本必填', + 'Please enter the correct ID number': '请输入正确的身份证号码', + number: '数字(包括浮点数和整数)', + integer: '整数(不包括浮点数)', + float: '浮点数(不包括整数)', +} diff --git a/web/src/lang/frontend/en.ts b/web/src/lang/frontend/en.ts new file mode 100644 index 0000000..6c24b0b --- /dev/null +++ b/web/src/lang/frontend/en.ts @@ -0,0 +1,12 @@ +/** + * frontend common language package + */ +export default { + Integral: 'Integral', + Balance: 'Balance', + Language: 'Language', + Copyright: 'Copyright', + 'Member Center': 'Member Center', + 'Logout login': 'Logout', + 'Member center disabled': 'The member center has been disabled. Please contact the webmaster to turn it on.', +} diff --git a/web/src/lang/frontend/en/index.ts b/web/src/lang/frontend/en/index.ts new file mode 100644 index 0000000..40c86d3 --- /dev/null +++ b/web/src/lang/frontend/en/index.ts @@ -0,0 +1,3 @@ +export default { + 'Steve Jobs': "Great art don't have to follow the trend, it alone can lead.-- Steve Jobs", +} diff --git a/web/src/lang/frontend/en/user/account/balance.ts b/web/src/lang/frontend/en/user/account/balance.ts new file mode 100644 index 0000000..efe4efd --- /dev/null +++ b/web/src/lang/frontend/en/user/account/balance.ts @@ -0,0 +1,6 @@ +export default { + 'Change time': 'Change time', + 'Current balance': 'Current balance', + 'Balance after change': 'Balance after change', + 'Balance change record': 'Balance change record', +} diff --git a/web/src/lang/frontend/en/user/account/changePassword.ts b/web/src/lang/frontend/en/user/account/changePassword.ts new file mode 100644 index 0000000..8f603f7 --- /dev/null +++ b/web/src/lang/frontend/en/user/account/changePassword.ts @@ -0,0 +1,8 @@ +export default { + 'Change Password': 'Change Password', + 'Old password': 'Old password', + 'New password': 'New password', + 'Confirm new password': 'Confirm new password', + 'Please enter your current password': 'Please enter your current password', + 'The duplicate password does not match the new password': 'The duplicate password does not match the new password', +} diff --git a/web/src/lang/frontend/en/user/account/integral.ts b/web/src/lang/frontend/en/user/account/integral.ts new file mode 100644 index 0000000..4114a61 --- /dev/null +++ b/web/src/lang/frontend/en/user/account/integral.ts @@ -0,0 +1,6 @@ +export default { + 'Change time': 'Change time', + 'Current points': 'Current points', + 'Points after change': 'Points after change', + 'Score change record': 'Score change record', +} diff --git a/web/src/lang/frontend/en/user/account/overview.ts b/web/src/lang/frontend/en/user/account/overview.ts new file mode 100644 index 0000000..373343b --- /dev/null +++ b/web/src/lang/frontend/en/user/account/overview.ts @@ -0,0 +1,11 @@ +export default { + 'Account information': 'Account information', + profile: 'Profile', + 'Filled in': 'Filled in', + 'Not filled in': 'Not filled in', + mobile: 'mobile', + email: 'email', + 'Last login IP': 'Last login IP', + 'Last login': 'Last login', + 'Growth statistics': 'Growth statistics', +} diff --git a/web/src/lang/frontend/en/user/account/profile.ts b/web/src/lang/frontend/en/user/account/profile.ts new file mode 100644 index 0000000..8eea8a8 --- /dev/null +++ b/web/src/lang/frontend/en/user/account/profile.ts @@ -0,0 +1,32 @@ +export default { + profile: 'Profile', + 'Change Password': 'Change Password', + avatar: 'Avatar', + 'User name': 'User name', + 'User nickname': 'User nickname', + mail: 'mail', + email: 'email', + 'Operation via right button': 'Operation via right button', + 'Click Modify': 'Click Modify', + bind: 'bind', + mobile: 'mobile', + Gender: 'Gender', + secrecy: 'secrecy', + male: 'male', + female: 'female', + birthday: 'birthday', + 'Personal signature': 'Personal signature', + 'Account verification': 'Account verification', + 'Account password verification': 'Account password verification', + 'Mail verification': 'Mail verification', + 'SMS verification': 'SMS verification', + password: 'password', + accept: 'accept', + 'next step': 'next step', + 'New email': 'New email', + 'New mobile': 'New mobile', + 'Verification Code': 'Captcha', + send: 'send', + seconds: 'seconds', + nickname: 'nickname', +} diff --git a/web/src/lang/frontend/en/user/login.ts b/web/src/lang/frontend/en/user/login.ts new file mode 100644 index 0000000..98856c1 --- /dev/null +++ b/web/src/lang/frontend/en/user/login.ts @@ -0,0 +1,24 @@ +export default { + reach: ' Reach ', + login: 'Login', + register: 'Register', + 'Via email': 'By email', + 'Via mobile number': 'By mobile number', + 'User name': 'User name', + account: 'Username/Email/Mobile', + password: 'Password', + 'Verification Code': 'Captcha', + mobile: 'mobile', + email: 'email', + send: 'send', + seconds: 'seconds', + 'Remember me': 'Remember me', + 'Forgot your password?': 'Forgot your password?', + 'Back to login': 'Back to login', + 'No account yet? Click Register': 'No account yet? Click Register', + 'Retrieve password': 'Retrieve password', + 'Retrieval method': 'Retrieval method', + 'New password': 'New password', + second: 'second', + 'Account name': 'Account name', +} diff --git a/web/src/lang/frontend/zh-cn.ts b/web/src/lang/frontend/zh-cn.ts new file mode 100644 index 0000000..59db0fd --- /dev/null +++ b/web/src/lang/frontend/zh-cn.ts @@ -0,0 +1,13 @@ +/** + * 前台公共语言包 + * 覆盖风险:请避免使用页面语言包的目录名、文件名作为翻译 key + */ +export default { + Integral: '积分', + Balance: '余额', + Language: '语言', + Copyright: '版权所有', + 'Member Center': '会员中心', + 'Logout login': '注销登录', + 'Member center disabled': '会员中心已禁用,请联系网站管理员开启。', +} diff --git a/web/src/lang/frontend/zh-cn/index.ts b/web/src/lang/frontend/zh-cn/index.ts new file mode 100644 index 0000000..7ba6da1 --- /dev/null +++ b/web/src/lang/frontend/zh-cn/index.ts @@ -0,0 +1,3 @@ +export default { + 'Steve Jobs': '伟大的艺术品不必追随潮流,他本身就能引领潮流。 -- 乔布斯', +} diff --git a/web/src/lang/frontend/zh-cn/user/account/balance.ts b/web/src/lang/frontend/zh-cn/user/account/balance.ts new file mode 100644 index 0000000..bd9dcae --- /dev/null +++ b/web/src/lang/frontend/zh-cn/user/account/balance.ts @@ -0,0 +1,6 @@ +export default { + 'Change time': '变更时间', + 'Current balance': '当前余额', + 'Balance after change': '变更后余额', + 'Balance change record': '余额变更记录', +} diff --git a/web/src/lang/frontend/zh-cn/user/account/changePassword.ts b/web/src/lang/frontend/zh-cn/user/account/changePassword.ts new file mode 100644 index 0000000..862427f --- /dev/null +++ b/web/src/lang/frontend/zh-cn/user/account/changePassword.ts @@ -0,0 +1,8 @@ +export default { + 'Change Password': '修改密码', + 'Old password': '旧密码', + 'New password': '新密码', + 'Confirm new password': '确认新密码', + 'Please enter your current password': '请输入现在的密码', + 'The duplicate password does not match the new password': '重复密码与新密码不相符', +} diff --git a/web/src/lang/frontend/zh-cn/user/account/integral.ts b/web/src/lang/frontend/zh-cn/user/account/integral.ts new file mode 100644 index 0000000..937ae84 --- /dev/null +++ b/web/src/lang/frontend/zh-cn/user/account/integral.ts @@ -0,0 +1,6 @@ +export default { + 'Change time': '变更时间', + 'Current points': '当前积分', + 'Points after change': '变更后积分', + 'Score change record': '积分变更记录', +} diff --git a/web/src/lang/frontend/zh-cn/user/account/overview.ts b/web/src/lang/frontend/zh-cn/user/account/overview.ts new file mode 100644 index 0000000..4802acf --- /dev/null +++ b/web/src/lang/frontend/zh-cn/user/account/overview.ts @@ -0,0 +1,11 @@ +export default { + 'Account information': '账户信息', + profile: '个人资料', + 'Filled in': '已填写', + 'Not filled in': '未填写', + mobile: '手机号', + email: '电子邮箱', + 'Last login IP': '最后登录IP', + 'Last login': '最后登录', + 'Growth statistics': '增长统计', +} diff --git a/web/src/lang/frontend/zh-cn/user/account/profile.ts b/web/src/lang/frontend/zh-cn/user/account/profile.ts new file mode 100644 index 0000000..a8aa187 --- /dev/null +++ b/web/src/lang/frontend/zh-cn/user/account/profile.ts @@ -0,0 +1,32 @@ +export default { + profile: '个人资料', + 'Change Password': '修改密码', + avatar: '头像', + 'User name': '用户名', + 'User nickname': '用户昵称', + mail: '邮箱', + email: '电子邮箱', + 'Operation via right button': '通过右侧按钮操作', + 'Click Modify': '点击修改', + bind: '绑定', + mobile: '手机号', + Gender: '性别', + secrecy: '保密', + male: '男', + female: '女', + birthday: '生日', + 'Personal signature': '个性签名', + 'Account verification': '账户验证', + 'Account password verification': '账户密码验证', + 'Mail verification': '邮件验证', + 'SMS verification': '短信验证', + password: '密码', + accept: '接受', + 'next step': '下一步', + 'New email': '新邮箱', + 'New mobile': '新手机号', + 'Verification Code': '验证码', + send: '发送', + seconds: '秒', + nickname: '昵称', +} diff --git a/web/src/lang/frontend/zh-cn/user/login.ts b/web/src/lang/frontend/zh-cn/user/login.ts new file mode 100644 index 0000000..0ab2e0d --- /dev/null +++ b/web/src/lang/frontend/zh-cn/user/login.ts @@ -0,0 +1,24 @@ +export default { + reach: '到', + login: '登录', + register: '注册', + 'Via email': '通过邮箱', + 'Via mobile number': '通过手机号', + 'User name': '用户名', + account: '用户名/邮箱/手机号', + password: '密码', + 'Verification Code': '验证码', + mobile: '手机号', + email: '电子邮箱', + send: '发送', + seconds: '秒', + 'Remember me': '记住我', + 'Forgot your password?': '忘记密码?', + 'Back to login': '回到登录', + 'No account yet? Click Register': '还没有账户?点击注册', + 'Retrieve password': '找回密码', + 'Retrieval method': '找回方式', + 'New password': '新密码', + second: '确定', + 'Account name': '账户', +} diff --git a/web/src/lang/globs-en.ts b/web/src/lang/globs-en.ts new file mode 100644 index 0000000..ef294d7 --- /dev/null +++ b/web/src/lang/globs-en.ts @@ -0,0 +1,50 @@ +/** + * Global common language package + */ +export default { + Id: 'ID', + State: 'State', + Home: 'Home', + Complete: 'Completed', + Edit: 'Edit', + Add: 'Add', + Info: 'Details', + Delete: 'Delete', + Refresh: 'Refresh', + Operate: 'Operate', + Confirm: 'Confirm', + Cancel: 'Cancel', + Save: 'Save', + Upload: 'Upload', + Retry: 'Retry', + Reminder: 'Reminder', + Disable: 'Disable', + Enable: 'Enable', + Shrink: 'Shrink', + Open: 'Open', + Search: 'Search', + Reset: 'Reset', + To: 'To', + None: 'None', + Unknown: 'Unknown', + Weigh: 'weigh', + 'Drag sort': 'Drag sort', + 'Save and edit next item': 'save and edit next item', + 'Quick search placeholder': 'Fuzzy search by {fields}', + 'Please select field': 'Please select {field}', + 'Please input field': 'Please input {field}', + 'Please enter the correct field': 'Please enter the correct {field}', + 'Update time': 'Update time', + 'Create time': 'Create time', + 'Fuzzy query': 'Fuzzy query', + 'Click select': 'Click select', + 'Edit selected row': 'Edit selected row', + 'Delete selected row': 'Delete selected row', + 'Are you sure to delete the selected record?': 'Are you sure to delete the selected record?', + 'All submenus': 'All submenus', + 'Shrink all': 'Shrinkage all', + 'Expand all': 'Expand all', + 'Expand generic search': 'Expand Universal Search', + 'Link address': 'Link address', + 'No route found to jump~': 'Failed to find a jump route.', +} diff --git a/web/src/lang/globs-zh-cn.ts b/web/src/lang/globs-zh-cn.ts new file mode 100644 index 0000000..e2508dc --- /dev/null +++ b/web/src/lang/globs-zh-cn.ts @@ -0,0 +1,51 @@ +/** + * 全局公共语言包 + * 覆盖风险:请避免使用页面语言包的目录名、文件名作为翻译 key、请使用大写开头避免覆盖 + */ +export default { + Id: 'ID', + State: '状态', + Home: '首页', + Complete: '完成', + Edit: '编辑', + Add: '添加', + Info: '查看详情', + Delete: '删除', + Refresh: '刷新', + Operate: '操作', + Confirm: '确认', + Cancel: '取消', + Save: '保存', + Upload: '上传', + Retry: '重试', + Reminder: '温馨提示', + Disable: '禁用', + Enable: '启用', + Shrink: '收缩', + Open: '展开', + Search: '搜索', + Reset: '重置', + To: '至', + None: '无', + Unknown: '未知', + Weigh: '权重', + 'Drag sort': '拖动以排序', + 'Save and edit next item': '保存并编辑下一项', + 'Quick search placeholder': '通过{fields}模糊搜索', + 'Please select field': '请选择{field}', + 'Please input field': '请输入{field}', + 'Please enter the correct field': '请输入正确的{field}', + 'Update time': '修改时间', + 'Create time': '创建时间', + 'Fuzzy query': '模糊查询', + 'Click select': '点击选择', + 'Edit selected row': '编辑选中行', + 'Delete selected row': '删除选中行', + 'Are you sure to delete the selected record?': '确定删除选中记录?', + 'All submenus': '所有子菜单', + 'Shrink all': '收缩所有', + 'Expand all': '展开所有', + 'Expand generic search': '展开公共搜索', + 'Link address': '链接地址', + 'No route found to jump~': '没有找到可以跳转的路由~', +} diff --git a/web/src/lang/index.ts b/web/src/lang/index.ts new file mode 100644 index 0000000..114bb44 --- /dev/null +++ b/web/src/lang/index.ts @@ -0,0 +1,148 @@ +import type { App } from 'vue' +import { createI18n } from 'vue-i18n' +import type { I18n, Composer } from 'vue-i18n' +import { useConfig } from '/@/stores/config' +import { isEmpty } from 'lodash-es' + +/* + * 默认只引入 element-plus 的中英文语言包 + * 其他语言包请自行在此 import,并添加到 assignLocale 内 + * 动态 import 只支持相对路径,所以无法按需 import element-plus 的语言包 + * 但i18n的 messages 内是按需载入的 + */ +import elementZhcnLocale from 'element-plus/es/locale/lang/zh-cn' +import elementEnLocale from 'element-plus/es/locale/lang/en' + +export let i18n: { + global: Composer +} + +// 准备要合并的语言包 +const assignLocale: anyObj = { + 'zh-cn': [elementZhcnLocale], + en: [elementEnLocale], +} + +export async function loadLang(app: App) { + const config = useConfig() + const locale = config.lang.defaultLang + + // 加载框架全局语言包 + const lang = await import(`./globs-${locale}.ts`) + const message = lang.default ?? {} + + // 按需加载语言包文件的句柄 + if (locale == 'zh-cn') { + window.loadLangHandle = { + ...import.meta.glob('./backend/zh-cn/**/*.ts'), + ...import.meta.glob('./frontend/zh-cn/**/*.ts'), + ...import.meta.glob('./backend/zh-cn.ts'), + ...import.meta.glob('./frontend/zh-cn.ts'), + } + } else { + window.loadLangHandle = { + ...import.meta.glob('./backend/en/**/*.ts'), + ...import.meta.glob('./frontend/en/**/*.ts'), + ...import.meta.glob('./backend/en.ts'), + ...import.meta.glob('./frontend/en.ts'), + } + } + + /* + * 加载页面语言包 import.meta.glob 的路径不能使用变量 import() 在 Vite 中目录名不能使用变量(编译后,文件名可以) + */ + if (locale == 'zh-cn') { + assignLocale[locale].push(getLangFileMessage(import.meta.glob('./common/zh-cn/**/*.ts', { eager: true }), locale)) + } else if (locale == 'en') { + assignLocale[locale].push(getLangFileMessage(import.meta.glob('./common/en/**/*.ts', { eager: true }), locale)) + } + + const messages = { + [locale]: { + ...message, + }, + } + + // 合并语言包(含element-puls、页面语言包) + Object.assign(messages[locale], ...assignLocale[locale]) + + i18n = createI18n({ + locale: locale, + legacy: false, // 组合式api + globalInjection: true, // 挂载$t,$d等到全局 + fallbackLocale: config.lang.fallbackLang, + messages, + }) + + app.use(i18n as I18n) + return i18n +} + +function getLangFileMessage(mList: any, locale: string) { + let msg: anyObj = {} + locale = '/' + locale + for (const path in mList) { + if (mList[path].default) { + // 获取文件名 + const pathName = path.slice(path.lastIndexOf(locale) + (locale.length + 1), path.lastIndexOf('.')) + if (pathName.indexOf('/') > 0) { + msg = handleMsglist(msg, mList[path].default, pathName) + } else { + msg[pathName] = mList[path].default + } + } + } + return msg +} + +export function mergeMessage(message: anyObj, pathName = '') { + if (isEmpty(message)) return + if (!pathName) { + return i18n.global.mergeLocaleMessage(i18n.global.locale.value, message) + } + let msg: anyObj = {} + if (pathName.indexOf('/') > 0) { + msg = handleMsglist(msg, message, pathName) + } else { + msg[pathName] = message + } + i18n.global.mergeLocaleMessage(i18n.global.locale.value, msg) +} + +export function handleMsglist(msg: anyObj, mList: anyObj, pathName: string) { + const pathNameTmp = pathName.split('/') + let obj: anyObj = {} + for (let i = pathNameTmp.length - 1; i >= 0; i--) { + if (i == pathNameTmp.length - 1) { + obj = { + [pathNameTmp[i]]: mList, + } + } else { + obj = { + [pathNameTmp[i]]: obj, + } + } + } + return mergeMsg(msg, obj) +} + +export function mergeMsg(msg: anyObj, obj: anyObj) { + for (const key in obj) { + if (typeof msg[key] == 'undefined') { + msg[key] = obj[key] + } else if (typeof msg[key] == 'object') { + msg[key] = mergeMsg(msg[key], obj[key]) + } + } + return msg +} + +export function editDefaultLang(lang: string): void { + const config = useConfig() + config.setLang(lang) + + /* + * 语言包是按需加载的,比如默认语言为中文,则只在app实例内加载了中文语言包,所以切换语言需要进行 reload + */ + location.reload() +} diff --git a/web/src/layouts/backend/components/aside.vue b/web/src/layouts/backend/components/aside.vue new file mode 100644 index 0000000..b4d43cc --- /dev/null +++ b/web/src/layouts/backend/components/aside.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/web/src/layouts/backend/components/baAccount.vue b/web/src/layouts/backend/components/baAccount.vue new file mode 100644 index 0000000..e48cab8 --- /dev/null +++ b/web/src/layouts/backend/components/baAccount.vue @@ -0,0 +1,259 @@ + + + + + + diff --git a/web/src/layouts/backend/components/closeFullScreen.vue b/web/src/layouts/backend/components/closeFullScreen.vue new file mode 100644 index 0000000..5b90738 --- /dev/null +++ b/web/src/layouts/backend/components/closeFullScreen.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/web/src/layouts/backend/components/config.vue b/web/src/layouts/backend/components/config.vue new file mode 100644 index 0000000..36a4515 --- /dev/null +++ b/web/src/layouts/backend/components/config.vue @@ -0,0 +1,420 @@ + + + + + diff --git a/web/src/layouts/backend/components/header.vue b/web/src/layouts/backend/components/header.vue new file mode 100644 index 0000000..94575d0 --- /dev/null +++ b/web/src/layouts/backend/components/header.vue @@ -0,0 +1,28 @@ + + + + diff --git a/web/src/layouts/backend/components/logo.vue b/web/src/layouts/backend/components/logo.vue new file mode 100644 index 0000000..c03e6b2 --- /dev/null +++ b/web/src/layouts/backend/components/logo.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/web/src/layouts/backend/components/menus/menuHorizontal.vue b/web/src/layouts/backend/components/menus/menuHorizontal.vue new file mode 100644 index 0000000..8665820 --- /dev/null +++ b/web/src/layouts/backend/components/menus/menuHorizontal.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/web/src/layouts/backend/components/menus/menuTree.vue b/web/src/layouts/backend/components/menus/menuTree.vue new file mode 100644 index 0000000..8d3c136 --- /dev/null +++ b/web/src/layouts/backend/components/menus/menuTree.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/web/src/layouts/backend/components/menus/menuVertical.vue b/web/src/layouts/backend/components/menus/menuVertical.vue new file mode 100644 index 0000000..98c9d02 --- /dev/null +++ b/web/src/layouts/backend/components/menus/menuVertical.vue @@ -0,0 +1,81 @@ + + + + diff --git a/web/src/layouts/backend/components/menus/menuVerticalChildren.vue b/web/src/layouts/backend/components/menus/menuVerticalChildren.vue new file mode 100644 index 0000000..c93dc92 --- /dev/null +++ b/web/src/layouts/backend/components/menus/menuVerticalChildren.vue @@ -0,0 +1,99 @@ + + + + diff --git a/web/src/layouts/backend/components/navBar/classic.vue b/web/src/layouts/backend/components/navBar/classic.vue new file mode 100644 index 0000000..e8d8705 --- /dev/null +++ b/web/src/layouts/backend/components/navBar/classic.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/web/src/layouts/backend/components/navBar/default.vue b/web/src/layouts/backend/components/navBar/default.vue new file mode 100644 index 0000000..4a8a2c0 --- /dev/null +++ b/web/src/layouts/backend/components/navBar/default.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/web/src/layouts/backend/components/navBar/double.vue b/web/src/layouts/backend/components/navBar/double.vue new file mode 100644 index 0000000..cc25b5c --- /dev/null +++ b/web/src/layouts/backend/components/navBar/double.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/web/src/layouts/backend/components/navBar/tabs.vue b/web/src/layouts/backend/components/navBar/tabs.vue new file mode 100644 index 0000000..1a7344f --- /dev/null +++ b/web/src/layouts/backend/components/navBar/tabs.vue @@ -0,0 +1,263 @@ + + + + + diff --git a/web/src/layouts/backend/components/navMenus.vue b/web/src/layouts/backend/components/navMenus.vue new file mode 100644 index 0000000..78d5cda --- /dev/null +++ b/web/src/layouts/backend/components/navMenus.vue @@ -0,0 +1,329 @@ + + + + + diff --git a/web/src/layouts/backend/container/classic.vue b/web/src/layouts/backend/container/classic.vue new file mode 100644 index 0000000..e9d2c1a --- /dev/null +++ b/web/src/layouts/backend/container/classic.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/web/src/layouts/backend/container/default.vue b/web/src/layouts/backend/container/default.vue new file mode 100644 index 0000000..e9d2c1a --- /dev/null +++ b/web/src/layouts/backend/container/default.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/web/src/layouts/backend/container/double.vue b/web/src/layouts/backend/container/double.vue new file mode 100644 index 0000000..e9d2c1a --- /dev/null +++ b/web/src/layouts/backend/container/double.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/web/src/layouts/backend/container/streamline.vue b/web/src/layouts/backend/container/streamline.vue new file mode 100644 index 0000000..543db54 --- /dev/null +++ b/web/src/layouts/backend/container/streamline.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/web/src/layouts/backend/index.vue b/web/src/layouts/backend/index.vue new file mode 100644 index 0000000..ac8556d --- /dev/null +++ b/web/src/layouts/backend/index.vue @@ -0,0 +1,116 @@ + + + diff --git a/web/src/layouts/backend/router-view/main.vue b/web/src/layouts/backend/router-view/main.vue new file mode 100644 index 0000000..cc87819 --- /dev/null +++ b/web/src/layouts/backend/router-view/main.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/web/src/layouts/common/components/darkSwitch.vue b/web/src/layouts/common/components/darkSwitch.vue new file mode 100644 index 0000000..5a11dd7 --- /dev/null +++ b/web/src/layouts/common/components/darkSwitch.vue @@ -0,0 +1,77 @@ + + + diff --git a/web/src/layouts/common/components/loading.vue b/web/src/layouts/common/components/loading.vue new file mode 100644 index 0000000..bd9d2c3 --- /dev/null +++ b/web/src/layouts/common/components/loading.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/web/src/layouts/common/router-view/iframe.vue b/web/src/layouts/common/router-view/iframe.vue new file mode 100644 index 0000000..dc26907 --- /dev/null +++ b/web/src/layouts/common/router-view/iframe.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/web/src/layouts/frontend/components/aside.vue b/web/src/layouts/frontend/components/aside.vue new file mode 100644 index 0000000..101156e --- /dev/null +++ b/web/src/layouts/frontend/components/aside.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/web/src/layouts/frontend/components/footer.vue b/web/src/layouts/frontend/components/footer.vue new file mode 100644 index 0000000..38230a5 --- /dev/null +++ b/web/src/layouts/frontend/components/footer.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/web/src/layouts/frontend/components/header.vue b/web/src/layouts/frontend/components/header.vue new file mode 100644 index 0000000..d9e1b66 --- /dev/null +++ b/web/src/layouts/frontend/components/header.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/web/src/layouts/frontend/components/main.vue b/web/src/layouts/frontend/components/main.vue new file mode 100644 index 0000000..5990ab8 --- /dev/null +++ b/web/src/layouts/frontend/components/main.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/web/src/layouts/frontend/components/menu.vue b/web/src/layouts/frontend/components/menu.vue new file mode 100644 index 0000000..919a56c --- /dev/null +++ b/web/src/layouts/frontend/components/menu.vue @@ -0,0 +1,256 @@ + + + + + diff --git a/web/src/layouts/frontend/components/menuSub.vue b/web/src/layouts/frontend/components/menuSub.vue new file mode 100644 index 0000000..c741700 --- /dev/null +++ b/web/src/layouts/frontend/components/menuSub.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/web/src/layouts/frontend/container/default.vue b/web/src/layouts/frontend/container/default.vue new file mode 100644 index 0000000..3b49934 --- /dev/null +++ b/web/src/layouts/frontend/container/default.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/web/src/layouts/frontend/container/disable.vue b/web/src/layouts/frontend/container/disable.vue new file mode 100644 index 0000000..be3122e --- /dev/null +++ b/web/src/layouts/frontend/container/disable.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/web/src/layouts/frontend/user.vue b/web/src/layouts/frontend/user.vue new file mode 100644 index 0000000..076ffc1 --- /dev/null +++ b/web/src/layouts/frontend/user.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/web/src/main.ts b/web/src/main.ts new file mode 100644 index 0000000..57dcc16 --- /dev/null +++ b/web/src/main.ts @@ -0,0 +1,36 @@ +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' +import { loadLang } from '/@/lang/index' +import { registerIcons } from '/@/utils/common' +import ElementPlus from 'element-plus' +import mitt from 'mitt' +import pinia from '/@/stores/index' +import { directives } from '/@/utils/directives' +import 'element-plus/dist/index.css' +import 'element-plus/theme-chalk/display.css' +import 'font-awesome/css/font-awesome.min.css' +import '/@/styles/index.scss' +// modules import mark, Please do not remove. + +async function start() { + const app = createApp(App) + app.use(pinia) + + // 全局语言包加载 + await loadLang(app) + + app.use(router) + app.use(ElementPlus) + + // 全局注册 + directives(app) // 指令 + registerIcons(app) // icons + + app.mount('#app') + + // modules start mark, Please do not remove. + + app.config.globalProperties.eventBus = mitt() +} +start() diff --git a/web/src/router/index.ts b/web/src/router/index.ts new file mode 100644 index 0000000..adbfbc0 --- /dev/null +++ b/web/src/router/index.ts @@ -0,0 +1,81 @@ +import { createRouter, createWebHashHistory } from 'vue-router' +import NProgress from 'nprogress' +import 'nprogress/nprogress.css' +import staticRoutes from '/@/router/static' +import { adminBaseRoutePath } from '/@/router/static/adminBase' +import { loading } from '/@/utils/loading' +import langAutoLoadMap from '/@/lang/autoload' +import { mergeMessage } from '/@/lang/index' +import { useConfig } from '/@/stores/config' +import { isAdminApp } from '/@/utils/common' +import { uniq } from 'lodash-es' + +const router = createRouter({ + history: createWebHashHistory(), + routes: staticRoutes, +}) + +router.beforeEach((to, from, next) => { + NProgress.configure({ showSpinner: false }) + NProgress.start() + if (!window.existLoading) { + loading.show() + window.existLoading = true + } + + // 按需动态加载页面的语言包-start + let loadPath: string[] = [] + const config = useConfig() + if (to.path in langAutoLoadMap) { + loadPath.push(...langAutoLoadMap[to.path as keyof typeof langAutoLoadMap]) + } + let prefix = '' + if (isAdminApp(to.fullPath)) { + prefix = './backend/' + config.lang.defaultLang + + // 去除 path 中的 /admin + const adminPath = to.path.slice(to.path.indexOf(adminBaseRoutePath) + adminBaseRoutePath.length) + if (adminPath) loadPath.push(prefix + adminPath + '.ts') + } else { + prefix = './frontend/' + config.lang.defaultLang + loadPath.push(prefix + to.path + '.ts') + } + + // 根据路由 name 加载的语言包 + if (to.name) { + loadPath.push(prefix + '/' + to.name.toString() + '.ts') + } + + if (!window.loadLangHandle.publicMessageLoaded) window.loadLangHandle.publicMessageLoaded = [] + const publicMessagePath = prefix + '.ts' + if (!window.loadLangHandle.publicMessageLoaded.includes(publicMessagePath)) { + loadPath.push(publicMessagePath) + window.loadLangHandle.publicMessageLoaded.push(publicMessagePath) + } + + // 去重 + loadPath = uniq(loadPath) + + for (const key in loadPath) { + loadPath[key] = loadPath[key].replaceAll('${lang}', config.lang.defaultLang) + if (loadPath[key] in window.loadLangHandle) { + window.loadLangHandle[loadPath[key]]().then((res: { default: anyObj }) => { + const pathName = loadPath[key].slice(loadPath[key].lastIndexOf(prefix) + (prefix.length + 1), loadPath[key].lastIndexOf('.')) + mergeMessage(res.default, pathName) + }) + } + } + // 动态加载语言包-end + + next() +}) + +// 路由加载后 +router.afterEach(() => { + if (window.existLoading) { + loading.hide() + } + NProgress.done() +}) + +export default router diff --git a/web/src/router/static.ts b/web/src/router/static.ts new file mode 100644 index 0000000..e126270 --- /dev/null +++ b/web/src/router/static.ts @@ -0,0 +1,100 @@ +import type { RouteRecordRaw } from 'vue-router' +import { adminBaseRoutePath } from '/@/router/static/adminBase' +import { memberCenterBaseRoutePath } from '/@/router/static/memberCenterBase' + +const pageTitle = (name: string): string => { + return `pagesTitle.${name}` +} + +/* + * 静态路由 + * 自动加载 ./static 目录的所有文件,并 push 到以下数组 + */ +const staticRoutes: Array = [ + { + // 首页 + path: '/', + name: '/', + component: () => import('/@/views/frontend/index.vue'), + meta: { + title: pageTitle('home'), + }, + }, + { + // 管理员登录页 - 不放在 adminBaseRoute.children 因为登录页不需要使用后台的布局 + path: adminBaseRoutePath + '/login', + name: 'adminLogin', + component: () => import('/@/views/backend/login.vue'), + meta: { + title: pageTitle('adminLogin'), + }, + }, + { + // 会员登录页 + path: memberCenterBaseRoutePath + '/login', + name: 'userLogin', + component: () => import('/@/views/frontend/user/login.vue'), + meta: { + title: pageTitle('userLogin'), + }, + }, + { + path: '/:path(.*)*', + redirect: '/404', + }, + { + // 404 + path: '/404', + name: 'notFound', + component: () => import('/@/views/common/error/404.vue'), + meta: { + title: pageTitle('notFound'), // 页面不存在 + }, + }, + { + // 后台找不到页面了-可能是路由未加载上 + path: adminBaseRoutePath + ':path(.*)*', + redirect: (to) => { + return { + name: 'adminMainLoading', + params: { + to: JSON.stringify({ + path: to.path, + query: to.query, + }), + }, + } + }, + }, + { + // 会员中心找不到页面了 + path: memberCenterBaseRoutePath + ':path(.*)*', + redirect: (to) => { + return { + name: 'userMainLoading', + params: { + to: JSON.stringify({ + path: to.path, + query: to.query, + }), + }, + } + }, + }, + { + // 无权限访问 + path: '/401', + name: 'noPower', + component: () => import('/@/views/common/error/401.vue'), + meta: { + title: pageTitle('noPower'), + }, + }, +] + +const staticFiles: Record> = import.meta.glob('./static/*.ts', { eager: true }) +for (const key in staticFiles) { + if (staticFiles[key].default) staticRoutes.push(staticFiles[key].default) +} + +export default staticRoutes diff --git a/web/src/router/static/adminBase.ts b/web/src/router/static/adminBase.ts new file mode 100644 index 0000000..c98e818 --- /dev/null +++ b/web/src/router/static/adminBase.ts @@ -0,0 +1,33 @@ +import type { RouteRecordRaw } from 'vue-router' + +/** + * 后台基础路由路径 + * 您可以随时于后台->系统配置中修改此值,程序可自动完成代码修改,同时建立对应的API入口和禁止admin应用访问 + */ +export const adminBaseRoutePath = '/admin' + +/* + * 后台基础静态路由 + */ +const adminBaseRoute: RouteRecordRaw = { + path: adminBaseRoutePath, + name: 'admin', + component: () => import('/@/layouts/backend/index.vue'), + // 直接重定向到 loading 路由 + redirect: adminBaseRoutePath + '/loading', + meta: { + title: `pagesTitle.admin`, + }, + children: [ + { + path: 'loading/:to?', + name: 'adminMainLoading', + component: () => import('/@/layouts/common/components/loading.vue'), + meta: { + title: `pagesTitle.loading`, + }, + }, + ], +} + +export default adminBaseRoute diff --git a/web/src/router/static/memberCenterBase.ts b/web/src/router/static/memberCenterBase.ts new file mode 100644 index 0000000..38a7265 --- /dev/null +++ b/web/src/router/static/memberCenterBase.ts @@ -0,0 +1,32 @@ +import type { RouteRecordRaw } from 'vue-router' + +/** + * 会员中心基础路由路径 + */ +export const memberCenterBaseRoutePath = '/user' + +/* + * 会员中心基础静态路由 + */ +const memberCenterBaseRoute: RouteRecordRaw = { + path: memberCenterBaseRoutePath, + name: 'user', + component: () => import('/@/layouts/frontend/user.vue'), + // 重定向到 loading 路由 + redirect: memberCenterBaseRoutePath + '/loading', + meta: { + title: `pagesTitle.user`, + }, + children: [ + { + path: 'loading/:to?', + name: 'userMainLoading', + component: () => import('/@/layouts/common/components/loading.vue'), + meta: { + title: `pagesTitle.loading`, + }, + }, + ], +} + +export default memberCenterBaseRoute diff --git a/web/src/stores/adminInfo.ts b/web/src/stores/adminInfo.ts new file mode 100644 index 0000000..65ffd10 --- /dev/null +++ b/web/src/stores/adminInfo.ts @@ -0,0 +1,57 @@ +import { defineStore } from 'pinia' +import { ADMIN_INFO } from '/@/stores/constant/cacheKey' +import type { AdminInfo } from '/@/stores/interface' + +export const useAdminInfo = defineStore('adminInfo', { + state: (): AdminInfo => { + return { + id: 0, + username: '', + nickname: '', + avatar: '', + last_login_time: '', + token: '', + refresh_token: '', + super: false, + } + }, + actions: { + /** + * 状态批量填充 + * @param state 新状态数据 + * @param [exclude=true] 是否排除某些字段(忽略填充),默认值 true 排除 token 和 refresh_token,传递 false 则不排除,还可传递 string[] 指定排除字段列表 + */ + dataFill(state: Partial, exclude: boolean | string[] = true) { + if (exclude === true) { + exclude = ['token', 'refresh_token'] + } else if (exclude === false) { + exclude = [] + } + + if (Array.isArray(exclude)) { + exclude.forEach((item) => { + delete state[item as keyof AdminInfo] + }) + } + + this.$patch(state) + }, + removeToken() { + this.token = '' + this.refresh_token = '' + }, + setToken(token: string, type: 'auth' | 'refresh') { + const field = type == 'auth' ? 'token' : 'refresh_token' + this[field] = token + }, + getToken(type: 'auth' | 'refresh' = 'auth') { + return type === 'auth' ? this.token : this.refresh_token + }, + setSuper(val: boolean) { + this.super = val + }, + }, + persist: { + key: ADMIN_INFO, + }, +}) diff --git a/web/src/stores/baAccount.ts b/web/src/stores/baAccount.ts new file mode 100644 index 0000000..458ff7f --- /dev/null +++ b/web/src/stores/baAccount.ts @@ -0,0 +1,82 @@ +import { defineStore } from 'pinia' +import router from '../router' +import { baAccountLogout } from '/@/api/backend/index' +import { BA_ACCOUNT } from '/@/stores/constant/cacheKey' +import type { UserInfo } from '/@/stores/interface' +import { Local } from '/@/utils/storage' + +export const useBaAccount = defineStore('baAccount', { + state: (): Partial => { + return { + id: 0, + username: '', + nickname: '', + email: '', + mobile: '', + avatar: '', + gender: 0, + birthday: '', + money: 0, + score: 0, + motto: '', + token: '', + refresh_token: '', + } + }, + actions: { + /** + * 状态批量填充 + * @param state 新状态数据 + * @param [exclude=true] 是否排除某些字段(忽略填充),默认值 true 排除 token 和 refresh_token,传递 false 则不排除,还可传递 string[] 指定排除字段列表 + */ + dataFill(state: Partial, exclude: boolean | string[] = true) { + if (exclude === true) { + exclude = ['token', 'refresh_token'] + } else if (exclude === false) { + exclude = [] + } + + if (Array.isArray(exclude)) { + exclude.forEach((item) => { + delete state[item as keyof UserInfo] + }) + } + + this.$patch(state) + }, + removeToken() { + this.token = '' + this.refresh_token = '' + }, + getGenderIcon() { + let icon = { name: 'fa fa-transgender-alt', color: 'var(--el-text-color-secondary)' } + switch (this.gender) { + case 1: + icon = { name: 'fa fa-mars-stroke-v', color: 'var(--el-color-primary)' } + break + case 2: + icon = { name: 'fa fa-mars-stroke', color: 'var(--el-color-danger)' } + break + } + return icon + }, + setToken(token: string, type: 'auth' | 'refresh') { + const field = type == 'auth' ? 'token' : 'refresh_token' + this[field] = token + }, + getToken(type: 'auth' | 'refresh' = 'auth') { + return type === 'auth' ? this.token : this.refresh_token + }, + logout() { + baAccountLogout().then((res) => { + if (res.code == 1) { + Local.remove(BA_ACCOUNT) + router.go(0) + } + }) + }, + }, + persist: { + key: BA_ACCOUNT, + }, +}) diff --git a/web/src/stores/config.ts b/web/src/stores/config.ts new file mode 100644 index 0000000..1894c5f --- /dev/null +++ b/web/src/stores/config.ts @@ -0,0 +1,111 @@ +import { defineStore } from 'pinia' +import { reactive } from 'vue' +import { STORE_CONFIG } from '/@/stores/constant/cacheKey' +import type { Crud, Lang, Layout } from '/@/stores/interface' + +export const useConfig = defineStore( + 'config', + () => { + const layout: Layout = reactive({ + // 全局 + showDrawer: false, + shrink: false, + layoutMode: 'Default', + mainAnimation: 'slide-right', + isDark: false, + + // 侧边栏 + menuBackground: ['#ffffff', '#1d1e1f'], + menuColor: ['#303133', '#CFD3DC'], + menuActiveBackground: ['#ffffff', '#1d1e1f'], + menuActiveColor: ['#409eff', '#3375b9'], + menuTopBarBackground: ['#fcfcfc', '#1d1e1f'], + menuWidth: 260, + menuDefaultIcon: 'fa fa-circle-o', + menuCollapse: false, + menuUniqueOpened: false, + menuShowTopBar: true, + + // 顶栏 + headerBarTabColor: ['#000000', '#CFD3DC'], + headerBarTabActiveBackground: ['#ffffff', '#1d1e1f'], + headerBarTabActiveColor: ['#000000', '#409EFF'], + headerBarBackground: ['#ffffff', '#1d1e1f'], + headerBarHoverBackground: ['#f5f5f5', '#18222c'], + }) + + const lang: Lang = reactive({ + defaultLang: 'zh-cn', + fallbackLang: 'zh-cn', + langArray: [ + { name: 'zh-cn', value: '中文简体' }, + { name: 'en', value: 'English' }, + ], + }) + + const crud: Crud = reactive({ + syncType: 'manual', + syncedUpdate: 'yes', + syncAutoPublic: 'no', + }) + + function menuWidth() { + if (layout.shrink) { + return layout.menuCollapse ? '0px' : layout.menuWidth + 'px' + } + // 菜单是否折叠 + return layout.menuCollapse ? '64px' : layout.menuWidth + 'px' + } + + function setLang(val: string) { + lang.defaultLang = val + } + + function onSetLayoutColor(data = layout.layoutMode) { + // 切换布局时,如果是为默认配色方案,对菜单激活背景色重新赋值 + const tempValue = layout.isDark ? { idx: 1, color: '#1d1e1f', newColor: '#141414' } : { idx: 0, color: '#ffffff', newColor: '#f5f5f5' } + if ( + data == 'Classic' && + layout.headerBarBackground[tempValue.idx] == tempValue.color && + layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.color + ) { + layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.newColor + } else if ( + data == 'Default' && + layout.headerBarBackground[tempValue.idx] == tempValue.color && + layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.newColor + ) { + layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.color + } + } + + function setLayoutMode(data: string) { + layout.layoutMode = data + onSetLayoutColor(data) + } + + const setLayout = (name: keyof Layout, value: any) => { + ;(layout[name] as any) = value + } + + const getColorVal = function (name: keyof Layout): string { + const colors = layout[name] as string[] + if (layout.isDark) { + return colors[1] + } else { + return colors[0] + } + } + + const setCrud = (name: keyof Crud, value: any) => { + ;(crud[name] as any) = value + } + + return { layout, lang, crud, menuWidth, setLang, setLayoutMode, setLayout, getColorVal, onSetLayoutColor, setCrud } + }, + { + persist: { + key: STORE_CONFIG, + }, + } +) diff --git a/web/src/stores/constant/cacheKey.ts b/web/src/stores/constant/cacheKey.ts new file mode 100644 index 0000000..64f2276 --- /dev/null +++ b/web/src/stores/constant/cacheKey.ts @@ -0,0 +1,25 @@ +/** + * 本地缓存Key + */ + +// 管理员资料 +export const ADMIN_INFO = 'adminInfo' + +// WEB端布局配置 +export const STORE_CONFIG = 'storeConfig_v2' +// 后台标签页 +export const STORE_TAB_VIEW_CONFIG = 'storeTabViewConfig' +// 终端 +export const STORE_TERMINAL = 'storeTerminal' + +// 工作时间 +export const WORKING_TIME = 'workingTime' + +// 切换到手机端前的上次布局方式 +export const BEFORE_RESIZE_LAYOUT = 'beforeResizeLayout' + +// 会员资料 +export const USER_INFO = 'userInfo' + +// ba官网用户信息 +export const BA_ACCOUNT = 'ba_account' diff --git a/web/src/stores/constant/common.ts b/web/src/stores/constant/common.ts new file mode 100644 index 0000000..87eccc3 --- /dev/null +++ b/web/src/stores/constant/common.ts @@ -0,0 +1,8 @@ +/** + * 公共常量定义 + */ + +/** + * 系统级 z-index 配置,比如全局通知消息的 z-index(浏览器支持的最大值通常为 2147483647) + */ +export const SYSTEM_ZINDEX = 2147483600 diff --git a/web/src/stores/constant/terminalTaskStatus.ts b/web/src/stores/constant/terminalTaskStatus.ts new file mode 100644 index 0000000..d564597 --- /dev/null +++ b/web/src/stores/constant/terminalTaskStatus.ts @@ -0,0 +1,8 @@ +export const enum taskStatus { + Waiting, + Connecting, + Executing, + Success, + Failed, + Unknown, +} diff --git a/web/src/stores/index.ts b/web/src/stores/index.ts new file mode 100644 index 0000000..e952ed8 --- /dev/null +++ b/web/src/stores/index.ts @@ -0,0 +1,7 @@ +import { createPinia } from 'pinia' +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' + +const pinia = createPinia() +pinia.use(piniaPluginPersistedstate) + +export default pinia diff --git a/web/src/stores/interface/index.ts b/web/src/stores/interface/index.ts new file mode 100644 index 0000000..5307183 --- /dev/null +++ b/web/src/stores/interface/index.ts @@ -0,0 +1,203 @@ +import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router' + +export interface Layout { + /* 全局 - s */ + // 是否显示布局配置抽屉 + showDrawer: boolean + // 是否收缩布局(小屏设备) + shrink: boolean + // 后台布局方式,可选值 + layoutMode: string + // 后台主页面切换动画,可选值 + mainAnimation: string + // 是否暗黑模式 + isDark: boolean + /* 全局 - e */ + + /* 侧边栏 - s */ + // 侧边菜单宽度(展开时),单位px + menuWidth: number + // 侧边菜单项默认图标 + menuDefaultIcon: string + // 是否水平折叠收起菜单 + menuCollapse: boolean + // 是否只保持一个子菜单的展开(手风琴) + menuUniqueOpened: boolean + // 显示菜单栏顶栏(LOGO) + menuShowTopBar: boolean + // 侧边菜单背景色 + menuBackground: string[] + // 侧边菜单文字颜色 + menuColor: string[] + // 侧边菜单激活项背景色 + menuActiveBackground: string[] + // 侧边菜单激活项文字色 + menuActiveColor: string[] + // 侧边菜单顶栏背景色 + menuTopBarBackground: string[] + /* 侧边栏 - e */ + + /* 顶栏 - s */ + // 顶栏文字色 + headerBarTabColor: string[] + // 顶栏背景色 + headerBarBackground: string[] + // 顶栏悬停时背景色 + headerBarHoverBackground: string[] + // 顶栏激活项背景色 + headerBarTabActiveBackground: string[] + // 顶栏激活项文字色 + headerBarTabActiveColor: string[] + /* 顶栏 - e */ +} + +export interface Lang { + // 默认语言,可选值 + defaultLang: string + // 当在默认语言包找不到翻译时,继续在 fallbackLang 语言包内查找翻译 + fallbackLang: string + // 支持的语言列表 + langArray: { name: string; value: string }[] +} + +export interface Crud { + // 日志同步方式 + syncType: 'manual' | 'automatic' + // 已同步记录被更新时,是否自动重新同步 + syncedUpdate: 'no' | 'yes' + // 自动同步时是否分享至开源社区 + syncAutoPublic: 'no' | 'yes' +} + +export interface NavTabs { + // 激活 tab 的 index + activeIndex: number + // 激活的 tab + activeRoute: RouteLocationNormalized | null + // tab 列表 + tabsView: RouteLocationNormalized[] + // 当前 tab 是否全屏 + tabFullScreen: boolean + // 从后台加载到的菜单路由列表 + tabsViewRoutes: RouteRecordRaw[] + // 权限节点 + authNode: Map +} + +export interface MemberCenter { + // 是否开启会员中心 + open: boolean + // 布局模式 + layoutMode: string + // 从后台加载到的菜单 + viewRoutes: RouteRecordRaw[] + // 是否显示一级菜单标题(当有多个一级菜单分组时显示) + showHeadline: boolean + // 权限节点 + authNode: Map + // 收缩布局(小屏设备) + shrink: boolean + // 菜单展开状态(小屏设备) + menuExpand: boolean + // 顶栏会员菜单下拉项 + navUserMenus: RouteRecordRaw[] +} + +export interface AdminInfo { + id: number + username: string + nickname: string + avatar: string + last_login_time: string + token: string + refresh_token: string + // 是否是 superAdmin,用于判定是否显示终端按钮等,不做任何权限判断 + super: boolean +} + +export interface UserInfo { + id: number + username: string + nickname: string + email: string + mobile: string + gender: number + birthday: string + money: number + score: number + avatar: string + last_login_time: string + last_login_ip: string + join_time: string + motto: string + token: string + refresh_token: string +} + +export interface TaskItem { + // 任务唯一标识 + uuid: string + // 创建时间 + createTime: string + // 状态 + status: number + // 命令 + command: string + // 命令执行日志 + message: string[] + // 显示命令执行日志 + showMessage: boolean + // 失败阻断后续命令执行 + blockOnFailure: boolean + // 扩展信息,自动发送到后台 + extend: string + // 执行结果回调 + callback: Function +} + +export interface Terminal { + // 显示终端窗口 + show: boolean + // 在后台终端按钮上显示一个红点 + showDot: boolean + // 任务列表 + taskList: TaskItem[] + // 包管理器 + packageManager: string + // 显示终端设置窗口 + showConfig: boolean + // 开始任务时自动清理已完成任务 + automaticCleanupTask: string + // PHP 开发服务环境 + phpDevelopmentServer: boolean + // NPM 源 + npmRegistry: string + // composer 源 + composerRegistry: string +} + +export interface SiteConfig { + // 站点名称 + siteName: string + // 系统版本号 + version: string + // 内容分发网络URL + cdnUrl: string + // 中心接口地址(用于请求模块市场的数据等用途) + apiUrl: string + // 上传配置 + upload: { + mode: string + [key: string]: any + } + // 顶部导航菜单数据 + headNav: RouteRecordRaw[] + // 备案号 + recordNumber?: string + // 内容分发网络URL的参数,格式如 imageMogr2/format/heif + cdnUrlParams: string + + // 初始化状态 + initialize: boolean + userInitialize: boolean +} diff --git a/web/src/stores/memberCenter.ts b/web/src/stores/memberCenter.ts new file mode 100644 index 0000000..237a66b --- /dev/null +++ b/web/src/stores/memberCenter.ts @@ -0,0 +1,84 @@ +import { defineStore } from 'pinia' +import { reactive } from 'vue' +import type { RouteRecordRaw } from 'vue-router' +import type { MemberCenter } from '/@/stores/interface/index' + +export const useMemberCenter = defineStore('memberCenter', () => { + const state: MemberCenter = reactive({ + open: true, + layoutMode: 'Default', + viewRoutes: [], + showHeadline: false, + authNode: new Map(), + shrink: false, + menuExpand: false, + navUserMenus: [], + }) + + const setNavUserMenus = (menus: RouteRecordRaw[]) => { + state.navUserMenus = menus + } + + const mergeNavUserMenus = (menus: RouteRecordRaw[]) => { + state.navUserMenus = [...state.navUserMenus, ...menus] + } + + const setAuthNode = (key: string, data: string[]) => { + state.authNode.set(key, data) + } + + const mergeAuthNode = (authNode: Map) => { + state.authNode = new Map([...state.authNode, ...authNode]) + } + + const setViewRoutes = (data: RouteRecordRaw[]): void => { + state.viewRoutes = encodeRoutesURI(data) + } + + const setShowHeadline = (show: boolean): void => { + state.showHeadline = show + } + + const setShrink = (shrink: boolean) => { + state.shrink = shrink + } + + const setStatus = (status: boolean) => { + state.open = status + } + + const setLayoutMode = (mode: string) => { + state.layoutMode = mode + } + + const toggleMenuExpand = (expand = !state.menuExpand) => { + state.menuExpand = expand + } + + return { + state, + setNavUserMenus, + mergeNavUserMenus, + setAuthNode, + mergeAuthNode, + setViewRoutes, + setShowHeadline, + setShrink, + setStatus, + setLayoutMode, + toggleMenuExpand, + } +}) + +function encodeRoutesURI(data: RouteRecordRaw[]) { + data.forEach((item) => { + if (item.meta?.menu_type == 'iframe') { + item.path = '/user/iframe/' + encodeURIComponent(item.path) + } + + if (item.children && item.children.length) { + item.children = encodeRoutesURI(item.children) + } + }) + return data +} diff --git a/web/src/stores/navTabs.ts b/web/src/stores/navTabs.ts new file mode 100644 index 0000000..fbcb483 --- /dev/null +++ b/web/src/stores/navTabs.ts @@ -0,0 +1,245 @@ +import { isEmpty } from 'lodash-es' +import { defineStore } from 'pinia' +import { reactive } from 'vue' +import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router' +import { i18n } from '../lang' +import { adminBaseRoutePath } from '/@/router/static/adminBase' +import { STORE_TAB_VIEW_CONFIG } from '/@/stores/constant/cacheKey' +import type { NavTabs } from '/@/stores/interface/index' +import { layoutNavTabsRef } from '/@/stores/refs' + +export const useNavTabs = defineStore( + 'navTabs', + () => { + const state: NavTabs = reactive({ + activeIndex: 0, + activeRoute: null, + tabsView: [], + tabFullScreen: false, + tabsViewRoutes: [], + authNode: new Map(), + }) + + /** + * 通过路由路径关闭tab + * @param fullPath 需要关闭的 tab 的路径 + */ + const closeTabByPath = (fullPath: string) => { + layoutNavTabsRef.value?.closeTabByPath(fullPath) + } + + /** + * 关闭所有tab + * @param menu 需要保留的标签,否则关闭全部标签并打开第一个路由 + */ + const closeAllTab = (menu?: RouteLocationNormalized) => { + layoutNavTabsRef.value?.closeAllTab(menu) + } + + /** + * 修改 tab 标题 + * @param fullPath 需要修改标题的 tab 的路径 + * @param title 新的标题 + */ + const updateTabTitle = (fullPath: string, title: string) => { + layoutNavTabsRef.value?.updateTabTitle(fullPath, title) + } + + /** + * 添加 tab(内部) + * ps: router.push 时可自动完成 tab 添加,无需调用此方法 + */ + function _addTab(route: RouteLocationNormalized) { + const tabView = { ...route, matched: [], meta: { ...route.meta } } + if (!tabView.meta.addtab) return + + // 通过路由寻找菜单的原始数据 + const tabViewRoute = getTabsViewDataByRoute(tabView) + if (tabViewRoute && tabViewRoute.meta) { + tabView.name = tabViewRoute.name + tabView.meta.id = tabViewRoute.meta.id + tabView.meta.title = tabViewRoute.meta.title + } + + for (const key in state.tabsView) { + // 菜单已在 tabs 存在,更新 params 和 query + if (state.tabsView[key].meta.id === tabView.meta.id || state.tabsView[key].fullPath == tabView.fullPath) { + state.tabsView[key].fullPath = tabView.fullPath + state.tabsView[key].params = !isEmpty(tabView.params) ? tabView.params : state.tabsView[key].params + state.tabsView[key].query = !isEmpty(tabView.query) ? tabView.query : state.tabsView[key].query + return + } + } + if (typeof tabView.meta.title == 'string') { + tabView.meta.title = i18n.global.te(tabView.meta.title) ? i18n.global.t(tabView.meta.title) : tabView.meta.title + } + state.tabsView.push(tabView) + } + + /** + * 设置激活 tab(内部) + * ps: router.push 时可自动完成 tab 激活,无需调用此方法 + */ + const _setActiveRoute = (route: RouteLocationNormalized): void => { + const currentRouteIndex: number = state.tabsView.findIndex((item: RouteLocationNormalized) => { + return item.fullPath === route.fullPath + }) + if (currentRouteIndex === -1) return + state.activeRoute = route + state.activeIndex = currentRouteIndex + } + + /** + * 关闭 tab(内部) + * ps: 使用 closeTabByPath 代替 + */ + function _closeTab(route: RouteLocationNormalized) { + state.tabsView.map((v, k) => { + if (v.fullPath == route.fullPath) { + state.tabsView.splice(k, 1) + return + } + }) + } + + /** + * 关闭多个标签(内部) + * ps:使用 closeAllTab 代替 + */ + const _closeTabs = (retainMenu: RouteLocationNormalized | false = false) => { + if (retainMenu) { + state.tabsView = [retainMenu] + } else { + state.tabsView = [] + } + } + + /** + * 更新标签标题(内部) + * ps: 使用 updateTabTitle 代替 + */ + const _updateTabTitle = (fullPath: string, title: string) => { + for (const key in state.tabsView) { + if (state.tabsView[key].fullPath == fullPath) { + state.tabsView[key].meta.title = title + break + } + } + } + + /** + * 设置从后台加载到的菜单路由列表 + */ + const setTabsViewRoutes = (data: RouteRecordRaw[]): void => { + state.tabsViewRoutes = encodeRoutesURI(data) + } + + /** + * 以key设置权限节点 + */ + const setAuthNode = (key: string, data: string[]) => { + state.authNode.set(key, data) + } + + /** + * 覆盖设置权限节点 + */ + const fillAuthNode = (data: Map) => { + state.authNode = data + } + + /** + * 设置当前 tab 是否全屏 + * @param status 全屏状态 + */ + const setFullScreen = (status: boolean): void => { + state.tabFullScreen = status + } + + /** + * 寻找路由在菜单中的数据 + * @param route 路由 + * @param returnType 返回值要求:normal=返回被搜索的路径对应的菜单数据,above=返回被搜索的路径对应的上一级菜单数组 + */ + const getTabsViewDataByRoute = (route: RouteLocationNormalized, returnType: 'normal' | 'above' = 'normal'): RouteRecordRaw | false => { + // 以完整路径寻找 + let found = getTabsViewDataByPath(route.fullPath, state.tabsViewRoutes, returnType) + if (found) { + found.meta!.matched = route.fullPath + return found + } + + // 以路径寻找 + found = getTabsViewDataByPath(route.path, state.tabsViewRoutes, returnType) + if (found) { + found.meta!.matched = route.path + return found + } + + return false + } + + /** + * 递归的寻找路由路径在菜单中的数据 + * @param path 路由路径 + * @param menus 菜单数据(只有 path 代表完整 url,没有 fullPath) + * @param returnType 返回值要求:normal=返回被搜索的路径对应的菜单数据,above=返回被搜索的路径对应的上一级菜单数组 + */ + const getTabsViewDataByPath = (path: string, menus: RouteRecordRaw[], returnType: 'normal' | 'above'): RouteRecordRaw | false => { + for (const key in menus) { + // 找到目标 + if (menus[key].path === path) { + return menus[key] + } + // 从子级继续寻找 + if (menus[key].children && menus[key].children.length) { + const find = getTabsViewDataByPath(path, menus[key].children, returnType) + if (find) { + return returnType == 'above' ? menus[key] : find + } + } + } + return false + } + + return { + state, + closeAllTab, + closeTabByPath, + updateTabTitle, + setTabsViewRoutes, + setAuthNode, + fillAuthNode, + setFullScreen, + getTabsViewDataByPath, + getTabsViewDataByRoute, + _addTab, + _closeTab, + _closeTabs, + _setActiveRoute, + _updateTabTitle, + } + }, + { + persist: { + key: STORE_TAB_VIEW_CONFIG, + pick: ['state.tabFullScreen'], + }, + } +) + +/** + * 对iframe的url进行编码 + */ +function encodeRoutesURI(data: RouteRecordRaw[]) { + data.forEach((item) => { + if (item.meta?.menu_type == 'iframe') { + item.path = adminBaseRoutePath + '/iframe/' + encodeURIComponent(item.path) + } + + if (item.children && item.children.length) { + item.children = encodeRoutesURI(item.children) + } + }) + return data +} diff --git a/web/src/stores/refs.ts b/web/src/stores/refs.ts new file mode 100644 index 0000000..80a169a --- /dev/null +++ b/web/src/stores/refs.ts @@ -0,0 +1,34 @@ +/** + * references + * 全局提供:引用(指向)一些对象(组件)的句柄 + */ +import type { ScrollbarInstance } from 'element-plus' +import type { CSSProperties } from 'vue' +import { computed, ref } from 'vue' +import NavTabs from '/@/layouts/backend/components/navBar/tabs.vue' +import { mainHeight } from '/@/utils/layout' + +/** + * 后台顶栏(tabs)组件ref(仅默认和经典布局) + */ +export const layoutNavTabsRef = ref>() + +/** + * 前后台布局的主体的滚动条组件ref + */ +export const layoutMainScrollbarRef = ref() + +/** + * 前后台布局的主体滚动条的额外样式,包括高度 + */ +export const layoutMainScrollbarStyle = computed(() => mainHeight()) + +/** + * 前后台布局的菜单组件ref + */ +export const layoutMenuRef = ref() + +/** + * 前后台布局的菜单栏滚动条组件ref + */ +export const layoutMenuScrollbarRef = ref() diff --git a/web/src/stores/siteConfig.ts b/web/src/stores/siteConfig.ts new file mode 100644 index 0000000..6829675 --- /dev/null +++ b/web/src/stores/siteConfig.ts @@ -0,0 +1,37 @@ +import { defineStore } from 'pinia' +import type { RouteRecordRaw } from 'vue-router' +import type { SiteConfig } from '/@/stores/interface' + +export const useSiteConfig = defineStore('siteConfig', { + state: (): SiteConfig => { + return { + siteName: '', + version: '', + cdnUrl: '', + apiUrl: '', + upload: { + mode: 'local', + }, + headNav: [], + recordNumber: '', + cdnUrlParams: '', + initialize: false, + userInitialize: false, + } + }, + actions: { + dataFill(state: SiteConfig) { + // 使用 this.$patch(state) 时 headNav 的类型异常,直接赋值 + this.$state = state + }, + setHeadNav(headNav: RouteRecordRaw[]) { + this.headNav = headNav + }, + setInitialize(initialize: boolean) { + this.initialize = initialize + }, + setUserInitialize(userInitialize: boolean) { + this.userInitialize = userInitialize + }, + }, +}) diff --git a/web/src/stores/terminal.ts b/web/src/stores/terminal.ts new file mode 100644 index 0000000..034e5ad --- /dev/null +++ b/web/src/stores/terminal.ts @@ -0,0 +1,292 @@ +import { ElNotification } from 'element-plus' +import { defineStore } from 'pinia' +import { nextTick, reactive } from 'vue' +import { buildTerminalUrl } from '/@/api/common' +import { i18n } from '/@/lang/index' +import { STORE_TERMINAL } from '/@/stores/constant/cacheKey' +import { SYSTEM_ZINDEX } from '/@/stores/constant/common' +import { taskStatus } from '/@/stores/constant/terminalTaskStatus' +import type { Terminal } from '/@/stores/interface/index' +import { timeFormat } from '/@/utils/common' +import { uuid } from '/@/utils/random' +import { closeHotUpdate, openHotUpdate } from '/@/utils/vite' + +export const useTerminal = defineStore( + 'terminal', + () => { + const state: Terminal = reactive({ + show: false, + showDot: false, + taskList: [], + packageManager: 'pnpm', + showConfig: false, + automaticCleanupTask: '1', + phpDevelopmentServer: false, + npmRegistry: 'unknown', + composerRegistry: 'unknown', + }) + + function init() { + for (const key in state.taskList) { + if (state.taskList[key].status == taskStatus.Connecting || state.taskList[key].status == taskStatus.Executing) { + state.taskList[key].status = taskStatus.Unknown + } + } + } + + function toggle(val = !state.show) { + state.show = val + if (val) { + toggleDot(false) + } + } + + function toggleDot(val = !state.showDot) { + state.showDot = val + } + + function toggleConfigDialog(val = !state.showConfig) { + toggle(!val) + state.showConfig = val + } + + function changeRegistry(val: string, type: 'npm' | 'composer') { + state[type == 'npm' ? 'npmRegistry' : 'composerRegistry'] = val + } + + function changePackageManager(val: string) { + state.packageManager = val + } + + function changePHPDevelopmentServer(val: boolean) { + state.phpDevelopmentServer = val + } + + function changeAutomaticCleanupTask(val: '0' | '1') { + state.automaticCleanupTask = val + } + + function setTaskStatus(idx: number, status: number) { + state.taskList[idx].status = status + if ((status == taskStatus.Failed || status == taskStatus.Unknown) && state.taskList[idx].blockOnFailure) { + setTaskShowMessage(idx, true) + } + } + + function taskCompleted(idx: number) { + // 命令执行完毕,重新打开热更新 + openHotUpdate('terminal') + + if (typeof state.taskList[idx].callback != 'function') return + + const status = state.taskList[idx].status + if (status == taskStatus.Failed || status == taskStatus.Unknown) { + state.taskList[idx].callback(taskStatus.Failed) + } else if (status == taskStatus.Success) { + state.taskList[idx].callback(taskStatus.Success) + } + } + + function setTaskShowMessage(idx: number, val = !state.taskList[idx].showMessage) { + state.taskList[idx].showMessage = val + } + + function addTaskMessage(idx: number, message: string) { + if (!state.show) toggleDot(true) + state.taskList[idx].message = state.taskList[idx].message.concat(message) + nextTick(() => { + execMessageScrollbarKeep(state.taskList[idx].uuid) + }) + } + + function addTask(command: string, blockOnFailure = true, extend = '', callback: Function = () => {}) { + if (!state.show) toggleDot(true) + state.taskList = state.taskList.concat({ + uuid: uuid(), + createTime: timeFormat(), + status: taskStatus.Waiting, + command: command, + message: [], + showMessage: false, + blockOnFailure: blockOnFailure, + extend: extend, + callback: callback, + }) + + // 清理任务列表 + if (parseInt(state.automaticCleanupTask) === 1) { + clearSuccessTask() + } + + // 检查是否有已经失败的任务 + if (state.show === false) { + for (const key in state.taskList) { + if (state.taskList[key].status == taskStatus.Failed || state.taskList[key].status == taskStatus.Unknown) { + ElNotification({ + type: 'error', + message: i18n.global.t('terminal.Newly added tasks will never start because they are blocked by failed tasks'), + zIndex: SYSTEM_ZINDEX, + }) + break + } + } + } + + startTask() + } + + function addTaskPM(command: string, blockOnFailure = true, extend = '', callback: Function = () => {}) { + addTask(command + '.' + state.packageManager, blockOnFailure, extend, callback) + } + + function delTask(idx: number) { + if (state.taskList[idx].status != taskStatus.Connecting && state.taskList[idx].status != taskStatus.Executing) { + state.taskList.splice(idx, 1) + } + startTask() + } + + function startTask() { + let taskKey = null + + // 寻找可以开始执行的命令 + for (const key in state.taskList) { + if (state.taskList[key].status == taskStatus.Waiting) { + taskKey = parseInt(key) + break + } + if (state.taskList[key].status == taskStatus.Connecting || state.taskList[key].status == taskStatus.Executing) { + break + } + if (state.taskList[key].status == taskStatus.Success) { + continue + } + if (state.taskList[key].status == taskStatus.Failed || state.taskList[key].status == taskStatus.Unknown) { + if (state.taskList[key].blockOnFailure) { + break + } else { + continue + } + } + } + if (taskKey !== null) { + setTaskStatus(taskKey, taskStatus.Connecting) + startEventSource(taskKey) + } + } + + function startEventSource(taskKey: number) { + // 命令执行期间禁用热更新 + closeHotUpdate('terminal') + + window.eventSource = new EventSource( + buildTerminalUrl(state.taskList[taskKey].command, state.taskList[taskKey].uuid, state.taskList[taskKey].extend) + ) + window.eventSource.onmessage = function (e) { + const data = JSON.parse(e.data) + if (!data || !data.data) { + return + } + + const taskIdx = findTaskIdxFromUuid(data.uuid) + if (taskIdx === false) { + return + } + + if (data.data == 'command-exec-error') { + setTaskStatus(taskIdx, taskStatus.Failed) + window.eventSource.close() + taskCompleted(taskIdx) + startTask() + } else if (data.data == 'command-exec-completed') { + window.eventSource.close() + if (state.taskList[taskIdx].status != taskStatus.Success) { + setTaskStatus(taskIdx, taskStatus.Failed) + } + taskCompleted(taskIdx) + startTask() + } else if (data.data == 'command-link-success') { + setTaskStatus(taskIdx, taskStatus.Executing) + } else if (data.data == 'command-exec-success') { + setTaskStatus(taskIdx, taskStatus.Success) + } else { + addTaskMessage(taskIdx, data.data) + } + } + window.eventSource.onerror = function () { + window.eventSource.close() + const taskIdx = findTaskIdxFromGuess(taskKey) + if (taskIdx === false) return + setTaskStatus(taskIdx, taskStatus.Failed) + taskCompleted(taskIdx) + } + } + + function retryTask(idx: number) { + state.taskList[idx].message = [] + setTaskStatus(idx, taskStatus.Waiting) + startTask() + } + + function clearSuccessTask() { + state.taskList = state.taskList.filter((item) => item.status != taskStatus.Success) + } + + function findTaskIdxFromUuid(uuid: string) { + for (const key in state.taskList) { + if (state.taskList[key].uuid == uuid) { + return parseInt(key) + } + } + return false + } + + function findTaskIdxFromGuess(idx: number) { + if (!state.taskList[idx]) { + let taskKey = -1 + for (const key in state.taskList) { + if (state.taskList[key].status == taskStatus.Connecting || state.taskList[key].status == taskStatus.Executing) { + taskKey = parseInt(key) + } + } + return taskKey === -1 ? false : taskKey + } else { + return idx + } + } + + function execMessageScrollbarKeep(uuid: string) { + const execMessageEl = document.querySelector('.exec-message-' + uuid) as Element + if (execMessageEl && execMessageEl.scrollHeight) { + execMessageEl.scrollTop = execMessageEl.scrollHeight + } + } + + return { + state, + init, + toggle, + toggleDot, + setTaskStatus, + setTaskShowMessage, + addTaskMessage, + addTask, + addTaskPM, + delTask, + startTask, + retryTask, + clearSuccessTask, + toggleConfigDialog, + changeRegistry, + changePackageManager, + changePHPDevelopmentServer, + changeAutomaticCleanupTask, + } + }, + { + persist: { + key: STORE_TERMINAL, + pick: ['state.showDot', 'state.taskList', 'state.automaticCleanupTask', 'state.npmRegistry', 'state.composerRegistry'], + }, + } +) diff --git a/web/src/stores/userInfo.ts b/web/src/stores/userInfo.ts new file mode 100644 index 0000000..23077ad --- /dev/null +++ b/web/src/stores/userInfo.ts @@ -0,0 +1,88 @@ +import { defineStore } from 'pinia' +import router from '../router' +import { postLogout } from '/@/api/frontend/user/index' +import { USER_INFO } from '/@/stores/constant/cacheKey' +import type { UserInfo } from '/@/stores/interface' +import { Local } from '/@/utils/storage' + +export const useUserInfo = defineStore('userInfo', { + state: (): UserInfo => { + return { + id: 0, + username: '', + nickname: '', + email: '', + mobile: '', + avatar: '', + gender: 0, + birthday: '', + money: 0, + score: 0, + last_login_time: '', + last_login_ip: '', + join_time: '', + motto: '', + token: '', + refresh_token: '', + } + }, + actions: { + /** + * 状态批量填充 + * @param state 新状态数据 + * @param [exclude=true] 是否排除某些字段(忽略填充),默认值 true 排除 token 和 refresh_token,传递 false 则不排除,还可传递 string[] 指定排除字段列表 + */ + dataFill(state: Partial, exclude: boolean | string[] = true) { + if (exclude === true) { + exclude = ['token', 'refresh_token'] + } else if (exclude === false) { + exclude = [] + } + + if (Array.isArray(exclude)) { + exclude.forEach((item) => { + delete state[item as keyof UserInfo] + }) + } + + this.$patch(state) + }, + removeToken() { + this.token = '' + this.refresh_token = '' + }, + setToken(token: string, type: 'auth' | 'refresh') { + const field = type == 'auth' ? 'token' : 'refresh_token' + this[field] = token + }, + getToken(type: 'auth' | 'refresh' = 'auth') { + return type === 'auth' ? this.token : this.refresh_token + }, + getGenderIcon() { + let icon = { name: 'fa fa-transgender-alt', color: 'var(--el-text-color-secondary)' } + switch (this.gender) { + case 1: + icon = { name: 'fa fa-mars-stroke-v', color: 'var(--el-color-primary)' } + break + case 2: + icon = { name: 'fa fa-mars-stroke', color: 'var(--el-color-danger)' } + break + } + return icon + }, + logout() { + postLogout().then((res) => { + if (res.code == 1) { + Local.remove(USER_INFO) + router.go(0) + } + }) + }, + isLogin() { + return this.id && this.token + }, + }, + persist: { + key: USER_INFO, + }, +}) diff --git a/web/src/styles/app.scss b/web/src/styles/app.scss new file mode 100644 index 0000000..8d7c7ba --- /dev/null +++ b/web/src/styles/app.scss @@ -0,0 +1,240 @@ +/* 基本样式 */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + outline: none !important; +} + +html, +body, +#app { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + font-family: + Helvetica Neue, + Helvetica, + PingFang SC, + Hiragino Sans GB, + Microsoft YaHei, + SimSun, + sans-serif; + font-weight: 400; + -webkit-font-smoothing: antialiased; + -webkit-tap-highlight-color: transparent; + background-color: var(--ba-bg-color); + color: var(--el-text-color-primary); + font-size: var(--el-font-size-base); +} + +// 阿里 iconfont Symbol引用css +.iconfont-icon { + width: 1em; + height: 1em; + vertical-align: -0.15em; + fill: currentColor; + overflow: hidden; +} + +.w100 { + width: 100% !important; +} +.h100 { + height: 100% !important; +} +.ba-center { + display: flex; + align-items: center; + justify-content: center; +} + +.default-main { + margin: var(--ba-main-space) var(--ba-main-space) 60px var(--ba-main-space); +} +.zoom-handle { + position: absolute; + width: 20px; + height: 20px; + bottom: -10px; + right: -10px; + cursor: se-resize; +} +.block-help { + display: block; + width: 100%; + color: #909399; + font-size: 13px; + line-height: 16px; + padding-top: 5px; +} + +/* 表格顶部菜单-s */ +.table-header { + .table-header-operate .icon { + font-size: 14px !important; + color: var(--el-color-white) !important; + } + .el-button.is-disabled .icon { + color: var(--el-button-disabled-text-color) !important; + } +} +/* 表格顶部菜单-e */ + +/* 鼠标置入浮动效果-s */ +.suspension { + transition: all 0.3s ease; +} +.suspension:hover { + -webkit-transform: translateY(-4px) scale(1.02); + -moz-transform: translateY(-4px) scale(1.02); + -ms-transform: translateY(-4px) scale(1.02); + -o-transform: translateY(-4px) scale(1.02); + transform: translateY(-4px) scale(1.02); + -webkit-box-shadow: 0 14px 24px rgba(0, 0, 0, 0.2); + box-shadow: 0 14px 24px rgba(0, 0, 0, 0.2); + z-index: 2147483600; + border-radius: 6px; +} +/* 鼠标置入浮动效果-e */ + +/* 表格-s */ +.ba-table-box { + border-radius: var(--el-border-radius-round); +} +.ba-table-alert { + background-color: var(--el-fill-color-darker) !important; + border: 1px solid var(--ba-boder-color); + border-bottom: 0; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +/* 表格-e */ + +/* 新增/编辑表单-s */ +.ba-operate-dialog { + overflow: hidden; + border-radius: var(--el-border-radius-base); + padding-bottom: 52px; +} +.ba-operate-dialog .el-dialog__header { + border-bottom: 1px solid var(--ba-bg-color); + .el-dialog__headerbtn { + top: 4px; + } +} +.ba-operate-dialog .el-dialog__body { + height: 58vh; +} +.ba-operate-dialog .el-dialog__footer { + padding: 10px var(--el-dialog-padding-primary); + box-shadow: var(--el-box-shadow); + position: absolute; + width: 100%; + bottom: 0; + left: 0; +} +.ba-operate-form { + padding-top: 20px; +} +/* 新增/编辑表单-e */ + +/* 全局遮罩-s */ +.ba-layout-shade { + position: fixed; + top: 0; + left: 0; + height: 100vh; + width: 100vw; + background-color: rgba(0, 0, 0, 0.5); + z-index: 2147483599; +} +/* 全局遮罩-e */ + +/* 图片上传预览-s */ +.img-preview-dialog .el-dialog__body { + display: flex; + align-items: center; + justify-content: center; + img { + max-width: 100%; + } +} +/* 图片上传预览-e */ + +/* 页面切换动画-s */ +.slide-right-enter-active, +.slide-right-leave-active, +.slide-left-enter-active, +.slide-left-leave-active { + will-change: transform; + transition: all 0.3s ease; +} +// slide-right +.slide-right-enter-from { + opacity: 0; + transform: translateX(-20px); +} +.slide-right-leave-to { + opacity: 0; + transform: translateX(20px); +} +// slide-left +.slide-left-enter-from { + @extend .slide-right-leave-to; +} +.slide-left-leave-to { + @extend .slide-right-enter-from; +} +/* 页面切换动画-e */ + +/* 布局相关-s */ +.frontend-footer-brother { + min-height: calc(100vh - 120px); +} +.user-views { + padding-left: 15px; + .user-views-card { + margin-bottom: 15px; + } +} +.ba-aside-drawer { + .el-drawer__body { + padding: 0; + } +} +/* 布局相关-e */ + +/* 暗黑模式公共样式-s */ +.ba-icon-dark { + color: var(--el-text-color-primary) !important; +} +/* 暗黑模式公共样式-e */ + +/* NProgress-s */ +#nprogress { + .bar, + .spinner { + z-index: 2147483600; + } +} +/* NProgress-e */ + +/* 自适应-s */ +@media screen and (max-width: 768px) { + .xs-hidden { + display: none; + } +} +@media screen and (max-width: 1024px) { + .ba-operate-dialog { + width: 96%; + } +} +@media screen and (max-width: 991px) { + .user-views { + padding: 0; + } +} +/* 自适应-e */ diff --git a/web/src/styles/dark.scss b/web/src/styles/dark.scss new file mode 100644 index 0000000..13814eb --- /dev/null +++ b/web/src/styles/dark.scss @@ -0,0 +1,27 @@ +@use 'sass:map'; +@use 'mixins.scss' as *; +@use 'element-plus/theme-chalk/src/dark/css-vars.scss'; + +// Background +$bg-color: () !default; +$bg-color: map.merge( + ( + '': #141414, + 'overlay': #1d1e1f, + ), + $bg-color +); + +// Border +$border-color: () !default; +$border-color: map.merge( + ( + '': #4c4d4f, + ), + $border-color +); + +html.dark { + @include set-component-css-var('bg-color', $bg-color); + @include set-component-css-var('border-color', $border-color); +} diff --git a/web/src/styles/element.scss b/web/src/styles/element.scss new file mode 100644 index 0000000..f002e97 --- /dev/null +++ b/web/src/styles/element.scss @@ -0,0 +1,87 @@ +.el-menu { + user-select: none; + .el-sub-menu__title:hover { + background-color: var(--el-color-primary-light-9) !important; + } +} + +.el-table { + --el-table-border-color: var(--ba-border-color); +} + +.el-card { + border: none; + .el-card__header { + border-bottom: 1px solid var(--el-border-color-extra-light); + } +} + +.el-divider__text.is-center { + transform: translateX(-50%) translateY(-62%); +} + +/* 修复 Chrome 浏览器输入框内选中字符行高异常的问题开始 <<< */ +.el-input { + .el-input__inner { + line-height: calc(var(--el-input-height, 40px) - 4px); + } +} +/* 修复 Chrome 浏览器输入框内选中字符行高异常的问题结束 >>> */ + +/* 输入框样式统一开始 <<< */ +.el-input-number.is-controls-right { + .el-input__wrapper { + padding-left: 11px; + } + .el-input__inner { + text-align: left; + } +} +.el-textarea__inner { + padding: 5px 11px; +} +.datetime-picker { + height: 32px; + padding-top: 0; + padding-bottom: 0; +} +/* 输入框样式统一结束 >>> */ + +/* dialog 滚动条样式优化开始 <<< */ +.el-overlay-dialog, +.ba-scroll-style { + &::-webkit-scrollbar { + width: 5px; + height: 5px; + } + &::-webkit-scrollbar-thumb { + background: #eaeaea; + border-radius: var(--el-border-radius-base); + box-shadow: none; + -webkit-box-shadow: none; + } + &:hover { + &::-webkit-scrollbar-thumb:hover { + background: #c8c9cc; + } + } +} +@supports not (selector(::-webkit-scrollbar)) { + .el-overlay-dialog, + .ba-scroll-style { + scrollbar-width: thin; + scrollbar-color: #c8c9cc #eaeaea; + } +} +/* dialog 滚动条样式优化结束 >>> */ + +/* 小屏设备 el-radio-group 样式优化开始 <<< */ +.ba-input-item-radio { + margin-bottom: 10px; + .el-radio-group { + .el-radio { + margin-bottom: 8px; + } + } +} +/* 小屏设备 el-radio-group 样式优化结束 >>> */ diff --git a/web/src/styles/index.scss b/web/src/styles/index.scss new file mode 100644 index 0000000..3a300cc --- /dev/null +++ b/web/src/styles/index.scss @@ -0,0 +1,5 @@ +@use '/@/styles/app'; +@use '/@/styles/element'; +@use '/@/styles/var'; +@use '/@/styles/dark'; +@use '/@/styles/markdown'; diff --git a/web/src/styles/loading.scss b/web/src/styles/loading.scss new file mode 100644 index 0000000..5576868 --- /dev/null +++ b/web/src/styles/loading.scss @@ -0,0 +1,54 @@ +.block-loading { + width: 100%; + height: 100%; + position: fixed; + z-index: 2147483600; + background-color: var(--ba-bg-color); +} +.block-loading .block-loading-box { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} +.block-loading .block-loading-box-warp { + width: 80px; + height: 80px; +} +.block-loading .block-loading-box-warp .block-loading-box-item { + width: 33.333333%; + height: 33.333333%; + background: #409eff; + float: left; + animation: block-loading-animation 1.2s infinite ease; + border-radius: 1px; +} +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(7) { + animation-delay: 0s; +} +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(4), +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(8) { + animation-delay: 0.1s; +} +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(1), +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(5), +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(9) { + animation-delay: 0.2s; +} +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(2), +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(6) { + animation-delay: 0.3s; +} +.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(3) { + animation-delay: 0.4s; +} +@keyframes block-loading-animation { + 0%, + 70%, + 100% { + transform: scale3D(1, 1, 1); + } + 35% { + transform: scale3D(0, 0, 1); + } +} diff --git a/web/src/styles/markdown.scss b/web/src/styles/markdown.scss new file mode 100644 index 0000000..68e48fa --- /dev/null +++ b/web/src/styles/markdown.scss @@ -0,0 +1,242 @@ +.ba-markdown { + ::-webkit-scrollbar { + width: 6px; + height: 6px; + } + ::-webkit-scrollbar-corner, + ::-webkit-scrollbar-track { + background-color: var(--el-bg-color-page); + border-radius: 2px; + } + ::-webkit-scrollbar-thumb { + border-radius: 2px; + background-color: var(--el-color-black); + } + ::-webkit-scrollbar-button:vertical { + display: none; + } + ::-webkit-scrollbar-thumb:vertical:hover { + background-color: var(--el-color-black); + } + ::-webkit-scrollbar-thumb:vertical:active { + background-color: var(--el-color-black); + } + h1 { + font-size: var(--el-font-size-large); + text-transform: uppercase; + color: var(--el-color-primary); + } + h1, + h2, + h3, + h4, + h5, + h6 { + position: relative; + word-break: break-all; + } + h1 a, + h2 a, + h3 a, + h4 a, + h5 a, + h6 a, + h1 a:hover, + h2 a:hover, + h3 a:hover, + h4 a:hover, + h5 a:hover, + h6 a:hover { + color: inherit; + } + ol > li { + list-style: decimal; + } + ul > li { + list-style: disc; + } + ol .li-task, + ul .li-task { + list-style-type: none; + } + ol .li-task input, + ul .li-task input { + margin-left: -1.5em; + margin-right: 0.1em; + } + a { + text-decoration: none; + } + pre, + code { + font-family: + source-code-pro, + Menlo, + Monaco, + Consolas, + Courier New, + monospace; + font-size: 14px; + color: #24292f; + } + pre { + margin: 20px 0; + } + pre code { + display: block; + line-height: 1.6; + overflow: auto; + } + pre code .code-block { + display: inline-block; + width: 100%; + overflow: auto; + vertical-align: bottom; + } + hr { + height: 1px; + margin: 10px 0; + border: none; + border-top: 1px solid #eaecef; + } + div[inline] > .figure { + padding-right: 0.5em; + } + div[inline] > .figure img { + padding: 0; + border: none; + } + .figure { + margin: 0 0 1em; + display: inline-flex; + flex-direction: column; + text-align: center; + } + .figure .figcaption { + color: #888; + font-size: 0.875em; + margin-top: 5px; + } + h1, + h2, + h3, + h4, + h5, + h6 { + margin: 1.4em 0 0.8em; + font-weight: 700; + } + a { + color: #2d8cf0; + transition: color 0.3s; + } + a:hover { + color: #73d13d; + } + img { + margin: 0 auto; + max-width: 100%; + box-sizing: border-box; + padding: 5px; + border: 1px solid #e6e6e6; + border-radius: 3px; + } + p { + line-height: 1.6; + margin: 0; + padding: 0.5rem 0; + } + p:empty { + display: none; + } + code { + color: #3594f7; + background-color: #3baafa1a; + display: inline-block; + padding: 0 4px; + border-radius: 2px; + line-height: 22px; + } + blockquote { + margin: 20px 0; + padding: 0.5em 1.2em; + line-height: 2em; + background-color: #ececec; + border-left: 5px solid #35b378; + display: block; + } + blockquote p { + padding: 0; + } + pre { + position: relative; + border-radius: 5px; + box-shadow: #0005 0 2px 2px; + } + pre code { + position: relative; + padding: 1em; + background-color: #282c34; + color: #a9b7c6; + border-radius: 0 0 5px 5px; + } + pre code > * { + line-height: 1.6; + } + pre .copy-button { + color: #999; + position: absolute; + font-size: 12px; + top: 9px; + right: 10px; + cursor: pointer; + } + pre:before { + content: ''; + display: block; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcIAAACCCAYAAADVN8idAAAgAElEQVR4nO2de5QU5Zn/v1VdVX2/zQwMzDCDgCBKOIx4myXLRlnYGDlhzWWDSTxkhXBQo2iS34kmavb3C5qo5+yqqBs5xNG4ZpVskjXk6BrhqAkbdoyXgSUoiqgMzDjAzPS1+lLX3x/TYNU7F6C7untm+vn8Ne/bVdVvP+8777fe2/MABEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQExKu2BtN03SyHGVhxdS61jk+77xWr3dWk9c7Y4okTakThbqAIIa8POcTeF4EAM0w1KxhZtKamhxUtcETinKiN5s92p3Nfngok31vx/HB7mr/FmLisaItMGv2NPfclqnCrKYGoXVqWJxWF+TrAj4u5JE4n+jiRZMzoWmmmlPMTDpjJgdTxuDxhNrX2691HzmuffhBX/7gjj3pD6v9W4iJx9TFwXqxWWrlG6UmforYiIhQb4ZcEcPPBzjJ5eZd4AHA0GGYip7nZSPNJfU44tqAcUI9ZhxTetUepfv4W6mBav+W08FxRUvZ0P3F3jjehHBByM+3RyNLLw6H29vCwQubPJ6ZhY/aS3x0JwD05nKH9yRSXW8kEp2dsfiu/UnZKPG5xCRiQYuHb5/vvfyieZ4lbXO8FzU1uE62vwtLfHQXAPT064f3Hsq++cZ7ud2vHci+uv9IjtofYWP6VfWfEud7F2Gu9wJMEacVsteW+NgOAMAJtQ8Hs2+rB7J7P35h4C8lPtNxaloI2+tDkRUNDSuvqG9YPsfvnY/SRe9M6TwkywdeGRjcuaO///nOgWS8Qt9LjCP+ap6v/m8X+1de3ua78twmaT5KF70zpev9XuXAq3syL+54S97+2nsZan81SMN8v9tzaXApvziwBDOkky9epQrf6RgSxqPKYeOt9O7cn1O7+g/I+TJ/52mpSSG8aXbL51ZNa/zCeX7/QlRO/Eaj811Z3re979h/PvLBkf+qclmICvCtlfUrP78k8JX5LdJCVE78RqPrwBFl3+92p3/56PMDz1e5LEQFaPrClEvFvw4uN2d65qD8wnc6OozDuUPmrtTve5478Wa1ClEzQtgW8bu/1ty8dnXT9DWFrDEFkOcAURIhCiJEQYDL5YLocoEXePDgwPHcKeOZpgnTMGHAhKEZUHUduq5D1TSomgo1r+IM5qE6TcD4Ze/HT//70Z6OPYnqvyURzrHoHK/7a8tCG1ZfHvrHQtaYAsgBkCQXRJGDKLggCIDg4uHiOfCFtsdxQ/9DpsnBNE0YhgndMKHpBjQNUDUdqmpCUXScwX9bl2lyxrZXk08+80pi696PstT+JhnN1zdf7Voe/nwhOaYAGpwJSRTBSQK4ocYH3sXD5eIB3gWe42AU2h9vcjBMEzB06LoBQzcATYepaTAVDYqqgjdPKxUdnAld3xl/4eiW3udK/7Vnx6QXwraI372uteWmVY2NX8ZpxM/r8cDjluCRJEhu0dFyKHkVOUVBLq8gm8ud7vLO7ceO/erxw0ceIUGc2Cw6x+ted2Xk1lVLAqtxGvHzelzwuAV43DzcEu9oOfKKgVzeQC6vIZvTT3d51/bd6W2Pvxh/kARx4tNyy4zV3NLQ3xWSowqg4HGD94jg3SJcDvd/el6FkVdh5FRouTGbVAcAmLuSLx156Og2RwsxBpNaCH98/rnrvz6jeS3GEECf1wuf1wOf112yMc4U0zSRyeaRyeaQyWbHurTzF0d7On7wzvtbK1IwwlHuWdN4w9eXh9ZjDAH0eUX4vTx8XlfF2p9hmshmdchZDZnsmKLY9fTO5JY7nzq2pSIFIxyl5ZvTV3JXRr9YSI4ogJzPA7fXDc4nga9g+zMzCvLZPMzMqIOCIUF8MfabIz/7uOxT9pNSCNfNbP7MrbNn3RYSXFGMIIKiICLg98Lv98LFO/vmfbbohgFZziItZ6Fq6kiXdCY1LfbgBx/d9/jhnj9UunzE2bNuRXTZLV+quyPk46MYQQRFgUfALyLgF+CqbvODrgPpjIa0rELVRpzA70pmjNiDvx68p2NH7OVKl484e6ZfVf8p1zUN63mfK4CRBFBwQQp44fJ7wFe5ARq6AV3OQUlnAW3El7IOyEZa3XZiazl3m04qIVwQ8vPfnzt709K6umUYQQDdbhFBfwB+n8fx73YCOZNDSk4jnx9ZEHcNDr78k4Mf3EVHL8YnC1o8/G3X1N/7Nwt9yzGCALolF0IBAX6fUIXSnR45oyGZ1pBXRuyQuv74v9md923rv52OXoxfWu+cuQFt/ksxggAKkgQh6IXL765CyU6PLuehpWRoijbSxx3YI/+5++7DZZmdmDRC+I3WpiU/nDvnXoHnl7KfSYKAUCg4bgWQRc7kkEymoGjDG4RqGH/YdPDQD37e3bu7CkUjRmHNsujSO6+tv18SuOEzECKHSFAatwLIImc0xFMKVHX4/6iimZ13Pz3wvadeju2qQtGIUZj+2boLhOumbeQEiGBEkBdFSCHfuBVAFl3OQ0lmYKjDBgQdpmaoesfxB3tfGjzg5HdOCiG8f8G8Gwq7QW2dEM8B4VAIoaDfse+qJMmUjFgiOdJHndt6P37qe/vf+2mly0QM5761jRsLu0Fto0COMxEJeRAOTgwBZEmkNMQT+ZF2nHY9+0qq4/Yn+h6pfKkIFstuUJsAGpwJTzgIMeSrUslKQ01mkEukRtpx2mHsiP/Oyd2lE14If31J2wMXR8LtYETQ5/UiGglCcLkc+Z5qoak6YsnUSJtqOt+IJzq/9Pqeb1ejXMQQv7qj5eGLz/N8GowI+rwi6sIiBKEyGxDKhaaZGEzkR9pU0/X6u/k//cM93TdXo1zEEK2bZm3E+d5FYESQ83ngi/gBYWL3f9B0ZOLySJtqOvBOdm/3XR9uduJrJqwQtteHIg9ccP5jBVdoNhGsi4QRDEzMt6DRSKUzGIwn2OzO3lzu8Lfffud68k5TWS6b54s8cP20Jwqu0GwiWB+REAw4u/282qTSKgbiCpvd1dOvH/7OY33XkXeaytIw3+/23dL0w4IrNJsIeqJBuILeKpWsPOipLHKxFJvdwR1X++TNvT8q1TvNhBTCFVPrWh9euOBxL88vt+a7RQnRaAhuaXJ1QifJKyoG40koir1DyhrGzpv37V9Hzr0rw4q2wKyHvjXt5z43Z1uPlkQXGqISJIfPAI4XFMVAf0yBotpHh5m8uWvjo33X7tyTpvZXAaYuDtZ7vtu8CW7+BtsHkgBfXQicNDGn4k+HqWjIDCYBdjNN3vhp7p977irFufeEE8KrpjXM+deFC57igCXWfL/Pg/popGJnsaqFaZoYiMUhM1MFJrD7xn3717zQ13+oSkWrCT53UWjuo7c0PsMDF1nz/T4BDVHPKW8vkxXT5NAfy0HOaGz+mzdu7v3qf72ZPlilotUEjZeEp7hva74XzChQ9HngqQ+f8vYyWeFNE7mBFFSm/+NMbM3e33PH8dcTJ4p57oQSwhVT61q3Llr4DCuCoWAA0XCw2KJMSGKJFJKptC3PBHav37vvqzQyLA8r2gKztnxn+n+wIhgKCqgLT4wdeU4xmMgjmRouhusf6P0ijQzLw9TFwXrPD1ruByuCIS+kSG31f1osjXwqY8vjTGzN/uTI94sZGZYqhBWbA2qvD0UeXrjgcVYEI6FgzYkgAETDQURC9t/NAUseXrjg8fb6UKRKxZq0XDbPF3noW9N+zopgNCTVnAgCQF3YjUhIsuVxnHnR5m9Ne/qyeT5qfw7TMN/v9ny3eRMYEXSHAzUnggAgRANwhwO2PJPDes93mzc1zK/8OZGKCeEDF5z/GLsmGA2HEA4FRrtl0hMOBRANh2x5Xp5f/sAF5z9WpSJNWh64ftoT7JpgNOxGODQ516PPhEhIRJR5CfC5uaX/cv20J6pUpEmL75amH7JrglIkACE8uTYFng1C2AcpwvT/bv4G/8amH1a6LBURwl9f0vaAJVAugKGR4EQ9H+gkoaB/2MiwyeOZ+etL2h6oUpEmHb+6o+VhS6BcAEMjwYl6PtBJwkFh2MiwucE18z/uaH24SkWadLRumrXREigXwJAITtTzgU4ihnzDR4ZTxWmtm2ZtrGQ5yi6E9y+YdwN7TjAUDNT0SJAlHAogFLTZo/3iSLj9/gXzbhjtHuLMuG9t40b2nGA4KNT0SJAlEhIRsr8UXHjJee5P33vdtJuqVabJQvP1zVez5wTFkJ9E0IIQ9sEdtNljLc73LpqxoenqSpWhrEL4jdamJazHGL/PU5NrgqcjGh7mQq59ddP0Nd9obVoy2j3E2KxZFl3Keozx+4Rh04HE0Joh40LuwmuuCK5dsyw6zOUhcWZM/2zdBazHGNHngRShmTAWIRqAaO//1vIrIp+f/tm6Cyrx/WXbNbog5Oe3X7L4VavvULcooXFq3aQ/IlEspmmi78Sg7Zyhahh/+PvX31pGjrrPjgUtHv4//9+MP1l9h0qiC9Oneif9EYliMU0OHx/P2s4ZKprZ+YV/OvppctR99rQ8e8FjnIANpzIkAcHG+kl/RKJYeNNE6ljMds7Q1IwtR645cP3p7h23u0a/P3f2JtaBdjQaIhEcA47jUBexb54Ref4z3587e1OVijRhue2a+ntZB9oNUYlEcAw4zkRD1L5eKAlc+23X1N9bpSJNWFrvnLmh4ED7FL66EIngGBgcB1+dvf/jBF5svXPmhlFucYyyCOG6mc2fKYRSOkVdJDxpPcY4iVsSURcJ2/KW1tUtWzez+TNVKtKEY92K6LJCKKVT1Ecmr8cYJ5EkHvURuxj+zULf8rUrostGuYVgmH5V/afYUEqeaHDSeoxxEk4S4Inals7Wos1/6fSr6j9Vzu8tS89w6+xZt8GyLujzeied79ByEgz44PPafA223zr7nNuqVZ6Jxi1fqrsDlnVBn1ecdL5Dy0kwIMLntTl7vvDWIZsSZ4Drmob1sIgg5/NMOt+h5cQV9IJj1gvF1VPWl/M7HRfCH59/7vpCZPmhL+CAaA0eGC2VKHOkIiQI0R+ff25ZG8Nk4J41jTcUIssDGJruqwuTCJ4tdWG3bQNByMdH717TWPYpqolOyzenryxElgcwFErJR5tjzhpfxG+fRvbzgZZvTl9Zru9zVAjbIn7312c0r4VlNBgOhSZ8KKVqIIgu9rB9+9dnNK9tC0+Q6JxVYNE5XvfXl4fWwzIajIQ8Ez6UUjUQBA4R++7aC69dHtqw6Bwvtb8x4K6MfhHWKdFwcOKHUqoGgmvIdp+wtmDbsuCoEK5rbbkJFhGUBIEOzZdAKOiHJNjWFdrXzWyhs12jsO7KyK2wiKAocnRovgTCQQGiaHuJuLBgY2IEWm6Zsdqa5kWRzguWgBjygRftszmsjZ3CMSFsi/jdqxobv2zNC4VoSrRUQozjgVWNjV+mUeFwFp3jda9aErD9k0SC0miXE2cIa8NVSwKraVQ4MtzS0N/BMhqUSARLhrHh2oKNHccxIfxas31K1O0W2QPiRBH4fV64RVtn1P61oelnwsLXloU2wDIadEsu9oA4UQR+nwC3ZN8489UrwrRWzdB8fbPNC4ogSXDR+2rJuPxuCMxu23J4nHFMCAseZE4R9JMLNacI2t0P4StN06+tUlHGLQUPMqcIBUgEnYK1JWtrAmA9yAi0S9QxBPvy2lrX8shVTn+HI0J40+yWz1nTokCjQSfx+7wQhU/myjmAZ21ey3xrZb1tN5ko8DQadBC/T4AofNJVcJzJ38jYvJZp+sKUS20ZgotGgw7i8rshWDYcmRxczVdPuWiMW84aR4Rw1bTGL8AyLRrw09uQ0zA2bS/YnADw+SWBr8AyLRrw03EJp2FseuGqIZsTAMS/Di6HdW0wQP2f0/B2m67llgY/6+jzS31Ae30ocp7fv9Ca5ychdBzWpuf5/QspgC/wV/N89fNbJFv7C/hpNOg0AWaEPb9FWkgBfIcC7pozPXOseS4/zYY5DWtTfqZnjpMBfEsWwhUNDSvBeJFx8eTKymlcPD/M20zB9jXN3y72rwTjRcZFzc9xXC4M8zazYrF/VbXKM17wXBpcCsaLDE8N0HF4Fz/M20zB9s48v9QHXFHfYPPp6PPS21C58DG71q+or1s+yqU1w+Vtviutab+XOqFy4ffaR4Ws7WsRfnHAFibNTSdLygZrW9b2pVBSr7Eg5Ofn+L3zrXlsZ004B/uSMcfvn78g5K/Znn9Bi4c/t0li2h958SgXXsa25zZJ8xe0eGq2/QEAZkgzrUnOR2dXy8Uw2zK2L4WSGnF7NLIUlmlRr8dDYZbKCMdx8HrswXsLdVCTtM/3Xg7LtKjX46L2V0Z4joPXY58evWyoDmoSNiKC4HGDp/ZXNniOg+CxD7ScikpRkhBeHA7b4r153PQ2VG5YG7N1UEtcNM9jmxrxuGmTTLlhbXwxUwe1hDjfuwiW9UHeQ7uVyw1j47WFOij9uaXc3BYOXmhNeyQSwnLD2pitg1qibY7XdpbI467tWbpKwNp4EVMHNcVc7wXWJO8mISw3w2zM1EHRzy3l5iaP59QcLc8BEjWEssPa2FoHtUZTg+vUb+c4E24KvFt23BJvC8/UbKmDmmOKOO3knwZnwkX9X9lxuUV7eCZLHZRC0T3Hiql1rda0SNHnK4ab+Ydj66IWWNEWmGVNSyJNi1YKye57dFhd1AJTFwfrrWlJpP6vUrC2ZuuiGIoWwjk+7zxYNspYXYAR5YWxdXuhLmqK2dPcc8GEXCIqAxuaqVAXNYXYLLXCen5QohexSuESmXXCobooiaKFsNXrtb0FigI1hErB2pqti1qgZarAtD86NlEpWFuzdVEL8I1SkzXNUf9XMUzR3v7YuiiGooWwyeudYU27KAp9xWBtzdZFLdDUINjeAqkfqhysrZvqxZqbmueniI22DHoRqxyMrYfVRREULYRTJGmKNS2SEFYM1tZsXdQCU8P2RXKB3FpVDNbWUyO8IxsWJhQRwbYuRW7VKscwWzN1UdQzi72xThTqbA8SqCFUCp7x5crWRS1QF+Rtv9nF0xphpWBtHQ3WXvszQy6bw3EXCWHFYG3N1kUxFF17AUEM2R9EHVGl4JmOiK2LWiDg4+ztj4SwYrC2DjJ1UQsYft4eeZynGbGKwdh6WF0U88hib/TynC1sOkcdUcVgbc3WRS3gkZj2R66tKgZra7YuagFOctl8fZFrtcrBW88RYnhdFPXMYm8UeN62h5U6osrB2pqti1pAdLHtzxztUsJhWFsLAldz7Y932ftOg9pfxTCY/o+ti2KgiW1iQmJSx0MQhEMULYSaYajWtGlSx1QpWFuzdVELaJrJtD+akagUrK3ZuqgFDB2GNc1T+6sYPNP/sXVR1DOLvTFrmBlr2jRICCsFa+usYWRGuXTSklOY9kcvYhWDtTVbF7WAqeh5a9qg9lcxDOalg8sb+VEuPWOKFsK0piataYOEsGKwtk5rWnKUSyct6YxJ7a9KsLZOMXVRC/CykbZlGHqVSlKDsLbO6OmRLzxzihbCQVUbtKYNo+TRKXGGsLZm66IWGEwZtt+skxBWDNbWsVTttT8uqcetaV2n/q9SsLZm66IYihbCE4pywppWdXojqhSsrU/k7XVRCxyPa33WtEYdUcVgbX08bvSNcunkJa4NWJMGtb+KMczWTF0UQ9FC2JvNHrWmdRLCisHaujdnr4taoHdA7bamNa1aJak9WFuzdVELGCfUY7YMjfq/isHYelhdFEHRQtidzX5oTavUE1UM1tZsXdQCR45rTPujjqhSsLbuZuqiFjCOKb3WtEn9X8Vgbc3WRTEULYSHMtn3AHSeTKtaze2grhqqYmsInYW6qCk+6MsfBNB1Mq2qtEZYKRhbd304VBc1hdqjdAPoOJk2FRLCSsHYuqNQFyVRtBDuOD5o+3JVISGsFHlVsaXZuqgFduxJ20YhikIjwkrB2pqti1rg+Fsp27qUolL/VylYW7N1UQwleZbpzeUOn/zbMAElT42h3OQYG1vroNbo6ddP/XYTQF6hDQvlJq8YsI4HrXVQc5xQT20S4k0OOvV/ZUfPqzbnBdxx1ZGNWiUJ4Z5EqsuazinKaJcSDqEwNmbroJbYeyj7pjWdy5MQlptc3j4FyNZBTXEw+7Y1aZAQlh3Wxub79joolpKE8I1EotOazuVJCMsNa2O2DmqJN97L7bam2U6acB72ZYOtg1pCPZDdC8s6oZEjISw3jI07CnVQMiUJYWcsvguWDTPZXI5cXZUR0zSRzeWsWZ2FOqhJXjuQfRWWDTPZnE6ursqIYZrI5mzrg12FOqhJPn5h4C/WtJbLU/srJ8aQja2wdVAsJQnh/qRsHJLlA9a8TLZkt2/EKGSyNhHEIVk+sD8p1+x84P4jOeP9XsXW/rJZ2jRTLljbvt+rHNh/JFez7Q8AcFSxrZGaGZoVKxc6qy2M7Uuh5DBMrwwM7rSm2c6acA72JYO1fS3y6p7Mi9a0nKXp0XLB2pa1fS1ivJW2TQ3naSBQNljbmm+mHZuWL1kId/T3Pw/L9Ggmm4VOfkcdRzcMZLJZa1bnjhP9z1erPOOFHW/J22GZHs1kdZCTI+fR9SHbWugq2L6myf05tQvW84SZHLlbKwOGbsDM2AZZHdnXk44tC5UshJ0Dyfi7srzPmifL2dEuJ4okzdj0XVne1zmYLNnZ7ETntfcy8QNHFFv7S2doVOg0aWbK70C3uu+19zI13/76D8h543DukDVPl2lWzGmG2fSj3KH+AxnHht+ORKjf3nfsP2EZFbKdNlE6sixbk52/7Tv2q2qVZbzxu93pX8IyKkzLtHvPadKyfTS4/X9Sv6xWWcYb5q7U72EZFSpp6v+chrFph/7fyd87+XxHhPCRD478l4lPogSrmgo5Q29FTiFnsjb/jiZgPPrBkZeqWKRxxaPPDzxvmpyl/RmQaVToGHJGg6p9Mt1nmpzxr88P1Py0/El6njvxJmfik39QTYcu01qhU+hy3uZomzOh9zzX7+j5VUeEEAB+2fvx09Z0Si45ViJRIJWyBwDf1tv7VJWKMm7Z9mrySWs6mSYhdArWlqytCUDfGX8BllGhlpLHuJo4GxhbdhRs7SiOCeG/H+3pgGV6NJ+nUaETyJks61u085mjvU9WqTjjlmdeSWyFZXo0r+g0KnQAOaMhb/ct2vXMK/Gt1SrPeOXolt7nrGlN0WhU6AC6nIfGODRnbe0EjgnhnoSc337Mvm6VTKacenzNkkzaR9bbjx371Z4E/Yex7P0om9++O73NmhdP0ZmuUmFt+Nvd6Wf2fpSj9jcC5q7kS7CuFSYzY1xNnAmMDTsKNnYcx4QQAB4/fOQRWEaFiqYhSVMERZNIyVDssbc6CzYmRuDxF+MPggnNlEjRqLBYEillWMiljhdjm6tVnvHOkYeO2l7EDFWFSmJYNGoyA4OJNMHa2CkcFcI9CTn/C2aKNJFIQlPpYNfZoqk6komkNavzF0d7Omg0ODp7P8rmn96Z3AKLGMaTOWgaub06WzTNRDxh64S6nt6Z3EKjwbExX4z9BpZRYS6Rouj1xaDpQ7b7hI6CbcuCo0IIAD945/2tSU2LnUwbAGI0RXrWxJIpWI/lJjUt9oN33qe1mdNw51PHtiQzxqn2Z5ocBhN0nOJsGUzkbeGWErIZu/OpY1uqVqAJwpGfffw8ZOPUegZvcsjEaVbsbMnEZVu4JchG+sjPPi7bTmXHhRAAHvzgo/vAeJtJpWmK4ExJpTPDvMgUbEqcAQ/+evAe2LzNqEilSQzPlGRaG+ZF5qHfDNxTrfJMNNRtJ7aC8Tajp+hs4Zmip7LDvMgUbFo2yiKEjx/u+cOuwcGXrXmD8QTyFMX+tOQVFYPxhC1v1+Dgy48f7vlDlYo04ejYEXv5j/syNj+sA3EFCgXuPS15xcBg3D77+cf/ze7s2BF7eZRbCIaPXxj4C/bIf4Z1ijSWgqnQevXpMBUNuZh9ShR75D87FWViNMoihADwk4Mf3KUahq3zjsWSFKZpDEzTRCxmWxeEahh/+MnBD+6qUpEmLPc9O3C7opm2WI39MQWmdbqFsGGaHAZi9l2iimZ23vds/+1VKtKEpfvuw1tMzbC9+WcGk+Cp/xsV3jSRGbT3f6ZmqN13Hy77lHzZhHB/UjY2HTz0A1jPFqoKBmI1755wVAZi8WFnBn908P3baznUUrHsP5Iz7n564HuwTJEqqo7+GJ1tHY3+WA6KfWNb193/NvC9/UdrPNRSkWhPHN8My6gQiobcAO2XGI3cQAqwj5o79I7jD1biu8smhADw8+7e3dt6P34KFjGUMznEEtQYWGKJFOuAoPPZ3t4nn+r+uGYj0JfKUy/Hdj37SqoDFjGUMxoGE7TxkWUwkWcdEHQ9+0qq46lXYjUb+LlUPv794NvGjvjvYBFDNZODFiOvWyxaLA2VWRc0dsR/1/vS4IHR7nGSsgohAHxv/3s/fSOe6IRFDJOpNBJJagwnSSTTSKZs9uh8PZ740237D9IuvRK5/Ym+R15/N/8nWMQwmdIQT9J69UniSRVJ+3nLrtffzf/p9if66MxqiRzd0vsc3snuhUUM86kMtARtHjyJlsggb3cj2cG9ndlbDg8yo1F2IQSAL72+59u9uZwtmnA8maLD9gCSKRlx5nhJby53+Muv7/k/VSrSpOMf7um+uadfZ9qfQoftMXRoPp60rwv29OuH/+Ge7purVKRJR/ddH27mjqt91rx8Ik2H7TF0aD6fsA+KuONq3+EfflRRxw0VEUIA+Pbb71yfNQzbTr5YIlnTI8NEMo2Y/dA8srqx89v737m+SkWatHznsb7rMnnTNs0XS+RremQYT6qIMWcsM3lz13ce67uuSkWatMibe3+EvPFTa54ST9f0yFBLZKDEmf4/b/xU3tzzo0qXpWJC2DmQjN+8b/86E9htzY8nUzW5ZhhLpCGUJnwAAAm3SURBVIaNBE1g981/2b+OAu46z2vvZeIbH+271jQ5W/iWeFKpyTXDwUR+2EjQNLk3Nz7Sdy0F3HWe/gNyPvfPPXdxJmzn4fKJdE2uGWqx9PCRoImtuX/uucvJgLtnSsWEEAB2HB/svnHf/jWsGCZTafQPxmriaIVpmugfjLFrgjCB3Tfu27dmx/HB7ioVbdKzc0+6+8bNvV9lxTCZ0nBiMF8TRytMk8OJAYVdE4Rpcm/esLl39c69aWp/ZeL4W6mB7P09dwwTw1QGSn9tHK3gTRNKf5JdEwRnYmv2/iN3HH8rNVCNchX9n1+KaK2YWtf68MIFj3t5frk13y1KiEZDcEti0c8ezwwdlk9CUexv4lnd2HnzX/avIxGsDCvaArMe+ta0n/vc3FJrviS60BCVIEkVfT+sGHnFwEBMYY9IIJM3d218pO9aEsHKMHVxsN7z3eZNcPM32D6QBPjqQuAkoUolKy+mog2dE2QcC/A545HMv/T831JEkONKe4mtihACQHt9KPLABec/1uTxzATQbv2sLhJGMOAr6fnjjVQ6M8xjDIDO3lzu8Lf3v3M9TYdWlsvm+SL/cv20J5obXDMBXGj9rD4iIRiYXC9jqbSKgfiwsFRdPf364e881ncdTYdWlob5frfvlqYfYoo4DcBa62eeaBCuoLdKJSsPeirLeowBgA7uuNonb+75UanToRNWCE/y60vaHrg4Em4HI4Y+rxfRUBCC6HLke6qFpuqIJVOs71CgcESCdodWl/+4o/XhS85zfxqMGPq8LtSF3RCEiT1dqmkmBhN51ncoUDgiQbtDq0vrplkbcb53ERgx5Hwe+CJ+QJjY/R80HZm4zPoOBQpHJJzaHTrhhRAA7l8w74bVTdPXgBFDAIiGQwgF/Y59VyVJpuRhu0ILdD7b2/sknRMcH9x73bSbrrkiuBaMGHIAImE3wsGJOVWVSCmIJ1SM8J/a9ewrqQ46Jzg+mLGh6Wp+ReTzYMTQ4Ex4wkGIoYk5O6YmR9gVOkSHsSP+OyfPCU4KIQSAb7Q2Lblr7pwfizz/GfYzSRAQCgXg902M6QI5k0UymWaD6gIY8h36o4Pv304eY8YXa5ZFl955bf39ksANexkTRQ6RoAS/b2IIopzREB8eVBfAkO/Qu/9t4HvkMWZ8Mf2zdRcI103byAkQwQgiL4qQQj64/O4qle7s0OU8lBGC6gLoMDVD1TuOP+i0x5hJI4QAsCDk578/d/ampXV1yzDC6NDtFhH0+8etIMqZLFKpDOsv9CSdfxyM7bz34KF/It+h45MFLR7+tmvq7/2bhb7lYEaHAOCWXAgFhHEriHJGQzKtIa+MGAi264//m91537P9t5Pv0PFL650zN6DNfykYMQQAQRIgBP3jVhB1OQ8tJUMbOcpGB/bIfy6XA+1JJYQnWTez+TO3zp51W0hwRTGCIIqCiIDfC7/fCxdf3R1+umEgLWchyzLUkSNRdyY1LfbAhx/9pOOjHnoLnwCsXRFdduuX6u4I+fgoRhBEUeAR8IsI+AS4qryEo+tAOqMgLetQtRH1rSshm7GHfjNwD4VSmhhMv6r+U65rGtbzPlcAIwgiBBekgBcuvwe8q7r9n6Eb0OUclHQWGLn/64BspNVtJ7aWM5TSpBTCk/z4/HPXf31G81qMIIYn8Xm98Hnd8Hk9JRvjTDFNE5lsDplsfqRNMFY6n+7p3XrH2wc7xrqIGJ/cvaZxw7XLQxswghiexOd1we8V4PW6wFeo/RmmiWxWh5wdFkCXpevpncktFFl+YtLyzekruSujXywkhwsihjbVuL1ucD6pYu0PBqBn88hn8yNtgjlJBwCYL8Z+U87I8ieZ1EIIAG0Rv3tda8tNqxobv4wxBBEAvB4PPG4JHkmC5HZ2+3sur0JRFOTyCrK504by6fztsWPbOg4f+emehFx7bksmEYvO8brXXRm5ddWSwGqMIYgA4PW44HEL8Lh5uB0+i5hXDOTyBnJ5DdncmOIHAF2/3Z1+puPF2Oa9H+Wo/U1wWm6ZsZpbGvq7QnJEQQQAweMG7xHBu0W4HO7/9LwKI6/CyKnQxm5SQwK4K/nSkYeObnO0EGMw6YXwJG1hv/trM5rXfqVp+rXckEecMUURGDqgL0oCREGAy+WC6HKB53nwPAeO504ZzzRNmIYJwzBhGAZUXYeu61A1DaqiQVUVnMGiSqcJGNt6e5965mjvkySAk4tF53jdX70ivH715aF/5DiTx2lEERhaUxRFDqLggiAAgouHi+eG2h/HgeOG/odMk4NpDrU/3TCh6QY0DVA1HapqQlH0kXZ+snSZJmdsezX55DOvxLeSAE4+Zmxoutq1PHKVycGFMQQRGNpxKokiOEkAN9T4wLt4uFw8wLvAcyaMQv/HmyYMkwMMHbpuwNANQNNhahpMRYOiquBP73WpgzOh6zvjL1QyasRJakYIrdw0u+Vzq6Y1fuE8v38hzkAQy0znu7K877d9x3716AdHXqpyWYgKcOPK+pWrlgS+Mr9FWogzEMQy03WgW923/X9Sv/zX5wfKPgVFVJ/mq6dcxC0Nfpaf6ZmD0whiBejAR7lD+n8nf9/zXP+bp7+8PNSkEJ6kvT4UWdHQsPKK+rrlc/z++aicKHYekuUDrwwM7txxov958gpTm1w2zxdZsdi/6vI235XnNknzUTlR7Hq/Vznw6p7MizvekreTV5japGG+3+25NLiUXxxYghnSzEJ2uYVxaL/DUeWw+WZ6d/b15K5qOMlmqWkhtLIg5Ofbo5GlF4fD7W3h4IUF121A6eLYCQzFCNyTSHW9kUh0dsbiu+gIBGFlQYuHv2y+9/KL53mWLJrjvajgug0oXRy7gKEYgXsPZd98473c7tcOZF/df4SOQBB2pl9V/ylxvncR5novKLhuA0oXxg5gKEag+X72bfVAdm85d38WCwnhGKyYWtc6x+ed1+r1zmryemdMkaQpdaJQFxDEkJfnfALPiwCgGYaaNYxMWtOSg6o2eCKvnOjNZY92Z7MfHspk3yNn2EQxrGgLzJo9zT23Zaowq6lebJ0a4adFg0Jd0MeFPBLnEwRuqP1ppppTzEwqYyZjKW3weNzo6x1Qu7uPax9+2Jc/uGNP+sNq/xZi4jF1cbBebJZa+UapiZ8iNiIi1JshV8Tw8wFOcrl511D0IUOHweWNPDJ6mkvqccS1AeOEesw4pvSqPUp3tSJCnA2VOjFAEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEAQxzvj/snGtbrdYI/0AAAAASUVORK5CYII=); + height: 32px; + width: 100%; + background-size: 40px; + background-repeat: no-repeat; + background-color: #282c34; + margin-bottom: 0; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + background-position: 10px 10px; + } + + table { + overflow: auto; + border-spacing: 0; + border-collapse: collapse; + margin-bottom: 1em; + } + + table tr th, + table tr td { + word-wrap: break-word; + padding: 8px 14px; + border: 1px solid #e6e6e6; + } + + table tr:nth-child(2n) { + background-color: #fafafa; + } + + table tr:hover { + background-color: #eee; + } + + ol, + ul { + margin: 0.6em 0; + padding-left: 1.6em; + } + + ol li, + ul li { + line-height: 1.6; + margin: 0.5em 0; + } +} diff --git a/web/src/styles/mixins.scss b/web/src/styles/mixins.scss new file mode 100644 index 0000000..ae0d086 --- /dev/null +++ b/web/src/styles/mixins.scss @@ -0,0 +1,30 @@ +@mixin set-css-var-value($name, $value) { + #{joinVarName($name)}: #{$value}; +} + +@function joinVarName($list) { + $name: '--ba'; + @each $item in $list { + @if $item != '' { + $name: $name + '-' + $item; + } + } + @return $name; +} + +@function getCssVarName($args...) { + @return joinVarName($args); +} + +/* + * 通过映射设置所有的CSS变量 + */ +@mixin set-component-css-var($name, $variables) { + @each $attribute, $value in $variables { + @if $attribute == 'default' { + #{getCssVarName($name)}: #{$value}; + } @else { + #{getCssVarName($name, $attribute)}: #{$value}; + } + } +} diff --git a/web/src/styles/var.scss b/web/src/styles/var.scss new file mode 100644 index 0000000..8559562 --- /dev/null +++ b/web/src/styles/var.scss @@ -0,0 +1,32 @@ +@use 'sass:map'; +@use 'mixins' as *; + +// 后台主体窗口左右间距 +$main-space: 16px; +$primary-light: #3f6ad8; + +// --ba-background +$bg-color: () !default; +$bg-color: map.merge( + ( + '': #f5f5f5, + 'overlay': #ffffff, + ), + $bg-color +); + +// --ba-border-color +$border-color: () !default; +$border-color: map.merge( + ( + '': #f6f6f6, + ), + $border-color +); + +:root { + @include set-css-var-value('main-space', $main-space); + @include set-css-var-value('color-primary-light', $primary-light); + @include set-component-css-var('bg-color', $bg-color); + @include set-component-css-var('border-color', $border-color); +} diff --git a/web/src/utils/axios.ts b/web/src/utils/axios.ts new file mode 100644 index 0000000..6b65c07 --- /dev/null +++ b/web/src/utils/axios.ts @@ -0,0 +1,382 @@ +import type { AxiosRequestConfig, Method } from 'axios' +import axios from 'axios' +import { ElLoading, ElNotification, type LoadingOptions } from 'element-plus' +import { refreshToken } from '/@/api/common' +import { i18n } from '/@/lang/index' +import router from '/@/router/index' +import adminBaseRoute from '/@/router/static/adminBase' +import { memberCenterBaseRoutePath } from '/@/router/static/memberCenterBase' +import { useAdminInfo } from '/@/stores/adminInfo' +import { useConfig } from '/@/stores/config' +import { SYSTEM_ZINDEX } from '/@/stores/constant/common' +import { useUserInfo } from '/@/stores/userInfo' +import { isAdminApp } from '/@/utils/common' + +window.requests = [] +window.tokenRefreshing = false +const pendingMap = new Map() +const loadingInstance: LoadingInstance = { + target: null, + count: 0, +} + +/** + * 根据运行环境获取基础请求URL + */ +export const getUrl = (): string => { + const value: string = import.meta.env.VITE_AXIOS_BASE_URL as string + return value == 'getCurrentDomain' ? window.location.protocol + '//' + window.location.host : value +} + +/** + * 根据运行环境获取基础请求URL的端口 + */ +export const getUrlPort = (): string => { + const url = getUrl() + return new URL(url).port +} + +/** + * 创建`Axios` + * 默认开启`reductDataFormat(简洁响应)`,返回类型为`ApiPromise` + * 关闭`reductDataFormat`,返回类型则为`AxiosPromise` + */ +function createAxios>(axiosConfig: AxiosRequestConfig, options: Options = {}, loading: LoadingOptions = {}): T { + const config = useConfig() + const adminInfo = useAdminInfo() + const userInfo = useUserInfo() + + const Axios = axios.create({ + baseURL: getUrl(), + timeout: 1000 * 10, + headers: { + 'think-lang': config.lang.defaultLang, + server: true, + }, + responseType: 'json', + }) + + // 自定义后台入口 + if (adminBaseRoute.path != '/admin' && isAdminApp() && /^\/admin\//.test(axiosConfig.url!)) { + axiosConfig.url = axiosConfig.url!.replace(/^\/admin\//, adminBaseRoute.path + '.php/') + } + + // 合并默认请求选项 + options = Object.assign( + { + cancelDuplicateRequest: true, // 是否开启取消重复请求, 默认为 true + loading: false, // 是否开启loading层效果, 默认为false + reductDataFormat: true, // 是否开启简洁的数据结构响应, 默认为true + showErrorMessage: true, // 是否开启接口错误信息展示,默认为true + showCodeMessage: true, // 是否开启code不为1时的信息提示, 默认为true + showSuccessMessage: false, // 是否开启code为1时的信息提示, 默认为false + anotherToken: '', // 当前请求使用另外的用户token + }, + options + ) + + // 请求拦截 + Axios.interceptors.request.use( + (config) => { + removePending(config) + options.cancelDuplicateRequest && addPending(config) + // 创建loading实例 + if (options.loading) { + loadingInstance.count++ + if (loadingInstance.count === 1) { + loadingInstance.target = ElLoading.service(loading) + } + } + + // 自动携带token + if (config.headers) { + const token = adminInfo.getToken() + if (token) (config.headers as anyObj).batoken = token + const userToken = options.anotherToken || userInfo.getToken() + if (userToken) (config.headers as anyObj)['ba-user-token'] = userToken + } + + return config + }, + (error) => { + return Promise.reject(error) + } + ) + + // 响应拦截 + Axios.interceptors.response.use( + (response) => { + removePending(response.config) + options.loading && closeLoading(options) // 关闭loading + + if (response.config.responseType == 'json') { + if (response.data && response.data.code !== 1) { + if (response.data.code == 409) { + if (!window.tokenRefreshing) { + window.tokenRefreshing = true + return refreshToken() + .then((res) => { + if (res.data.type == 'admin-refresh') { + adminInfo.setToken(res.data.token, 'auth') + response.headers.batoken = `${res.data.token}` + window.requests.forEach((cb) => cb(res.data.token, 'admin-refresh')) + } else if (res.data.type == 'user-refresh') { + userInfo.setToken(res.data.token, 'auth') + response.headers['ba-user-token'] = `${res.data.token}` + window.requests.forEach((cb) => cb(res.data.token, 'user-refresh')) + } + window.requests = [] + return Axios(response.config) + }) + .catch((err) => { + if (isAdminApp()) { + adminInfo.removeToken() + if (router.currentRoute.value.name != 'adminLogin') { + router.push({ name: 'adminLogin' }) + return Promise.reject(err) + } else { + response.headers.batoken = '' + window.requests.forEach((cb) => cb('', 'admin-refresh')) + window.requests = [] + return Axios(response.config) + } + } else { + userInfo.removeToken() + if (router.currentRoute.value.name != 'userLogin') { + router.push({ name: 'userLogin' }) + return Promise.reject(err) + } else { + response.headers['ba-user-token'] = '' + window.requests.forEach((cb) => cb('', 'user-refresh')) + window.requests = [] + return Axios(response.config) + } + } + }) + .finally(() => { + window.tokenRefreshing = false + }) + } else { + return new Promise((resolve) => { + // 用函数形式将 resolve 存入,等待刷新后再执行 + window.requests.push((token: string, type: string) => { + if (type == 'admin-refresh') { + response.headers.batoken = `${token}` + } else { + response.headers['ba-user-token'] = `${token}` + } + resolve(Axios(response.config)) + }) + }) + } + } + if (options.showCodeMessage) { + ElNotification({ + type: 'error', + message: response.data.msg, + zIndex: SYSTEM_ZINDEX, + }) + } + // 自动跳转到路由name或path + if (response.data.code == 302) { + router.push({ path: response.data.data.routePath ?? '', name: response.data.data.routeName ?? '' }) + } + if (response.data.code == 303) { + const isAdminAppFlag = isAdminApp() + let routerPath = isAdminAppFlag ? adminBaseRoute.path : memberCenterBaseRoutePath + + // 需要登录,清理 token,转到登录页 + if (response.data.data.type == 'need login') { + if (isAdminAppFlag) { + adminInfo.removeToken() + } else { + userInfo.removeToken() + } + routerPath += '/login' + } + router.push({ path: routerPath }) + } + // code不等于1, 页面then内的具体逻辑就不执行了 + return Promise.reject(response.data) + } else if (options.showSuccessMessage && response.data && response.data.code == 1) { + ElNotification({ + message: response.data.msg ? response.data.msg : i18n.global.t('axios.Operation successful'), + type: 'success', + zIndex: SYSTEM_ZINDEX, + }) + } + } + + return options.reductDataFormat ? response.data : response + }, + (error) => { + error.config && removePending(error.config) + options.loading && closeLoading(options) // 关闭loading + options.showErrorMessage && httpErrorStatusHandle(error) // 处理错误状态码 + return Promise.reject(error) // 错误继续返回给到具体页面 + } + ) + return Axios(axiosConfig) as T +} + +export default createAxios + +/** + * 处理异常 + * @param {*} error + */ +function httpErrorStatusHandle(error: any) { + // 处理被取消的请求 + if (axios.isCancel(error)) return console.error(i18n.global.t('axios.Automatic cancellation due to duplicate request:') + error.message) + let message = '' + if (error && error.response) { + switch (error.response.status) { + case 302: + message = i18n.global.t('axios.Interface redirected!') + break + case 400: + message = i18n.global.t('axios.Incorrect parameter!') + break + case 401: + message = i18n.global.t('axios.You do not have permission to operate!') + break + case 403: + message = i18n.global.t('axios.You do not have permission to operate!') + break + case 404: + message = i18n.global.t('axios.Error requesting address:') + error.response.config.url + break + case 408: + message = i18n.global.t('axios.Request timed out!') + break + case 409: + message = i18n.global.t('axios.The same data already exists in the system!') + break + case 500: + message = i18n.global.t('axios.Server internal error!') + break + case 501: + message = i18n.global.t('axios.Service not implemented!') + break + case 502: + message = i18n.global.t('axios.Gateway error!') + break + case 503: + message = i18n.global.t('axios.Service unavailable!') + break + case 504: + message = i18n.global.t('axios.The service is temporarily unavailable Please try again later!') + break + case 505: + message = i18n.global.t('axios.HTTP version is not supported!') + break + default: + message = i18n.global.t('axios.Abnormal problem, please contact the website administrator!') + break + } + } + if (error.message.includes('timeout')) message = i18n.global.t('axios.Network request timeout!') + if (error.message.includes('Network')) + message = window.navigator.onLine ? i18n.global.t('axios.Server exception!') : i18n.global.t('axios.You are disconnected!') + + ElNotification({ + type: 'error', + message, + zIndex: SYSTEM_ZINDEX, + }) +} + +/** + * 关闭Loading层实例 + */ +function closeLoading(options: Options) { + if (options.loading && loadingInstance.count > 0) loadingInstance.count-- + if (loadingInstance.count === 0) { + loadingInstance.target.close() + loadingInstance.target = null + } +} + +/** + * 储存每个请求的唯一cancel回调, 以此为标识 + */ +function addPending(config: AxiosRequestConfig) { + const pendingKey = getPendingKey(config) + config.cancelToken = + config.cancelToken || + new axios.CancelToken((cancel) => { + if (!pendingMap.has(pendingKey)) { + pendingMap.set(pendingKey, cancel) + } + }) +} + +/** + * 删除重复的请求 + */ +function removePending(config: AxiosRequestConfig) { + const pendingKey = getPendingKey(config) + if (pendingMap.has(pendingKey)) { + const cancelToken = pendingMap.get(pendingKey) + cancelToken(pendingKey) + pendingMap.delete(pendingKey) + } +} + +/** + * 生成每个请求的唯一key + */ +function getPendingKey(config: AxiosRequestConfig) { + let { data } = config + const { url, method, params, headers } = config + if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象 + return [ + url, + method, + headers && (headers as anyObj).batoken ? (headers as anyObj).batoken : '', + headers && (headers as anyObj)['ba-user-token'] ? (headers as anyObj)['ba-user-token'] : '', + JSON.stringify(params), + JSON.stringify(data), + ].join('&') +} + +/** + * 根据请求方法组装请求数据/参数 + */ +export function requestPayload(method: Method, data: anyObj) { + if (method == 'GET') { + return { + params: data, + } + } else if (method == 'POST') { + return { + data: data, + } + } +} + +interface LoadingInstance { + target: any + count: number +} +interface Options { + // 是否开启取消重复请求, 默认为 true + cancelDuplicateRequest?: boolean + // 是否开启loading层效果, 默认为false + loading?: boolean + // 是否开启简洁的数据结构响应, 默认为true + reductDataFormat?: boolean + // 是否开启接口错误信息展示,默认为true + showErrorMessage?: boolean + // 是否开启code不为1时的信息提示, 默认为true + showCodeMessage?: boolean + // 是否开启code为1时的信息提示, 默认为false + showSuccessMessage?: boolean + // 当前请求使用另外的用户token + anotherToken?: string +} + +/* + * 感谢掘金@橙某人提供的思路和分享 + * 本axios封装详细解释请参考:https://juejin.cn/post/6968630178163458084?share_token=7831c9e0-bea0-469e-8028-b587e13681a8#heading-27 + */ diff --git a/web/src/utils/baTable.ts b/web/src/utils/baTable.ts new file mode 100644 index 0000000..bc76ebc --- /dev/null +++ b/web/src/utils/baTable.ts @@ -0,0 +1,684 @@ +import type { FormInstance, TableColumnCtx } from 'element-plus' +import { ElNotification, dayjs } from 'element-plus' +import { cloneDeep, isArray, isEmpty } from 'lodash-es' +import Sortable from 'sortablejs' +import { reactive } from 'vue' +import { useRoute } from 'vue-router' +import type { baTableApi } from '/@/api/common' +import { findIndexRow } from '/@/components/table' +import { i18n } from '/@/lang/index' +import { auth, getArrayKey } from '/@/utils/common' + +/** + * 表格管家类 + */ +export default class baTable { + /** baTableApi 类的实例,开发者可重写该类 */ + public api: baTableApi + + /** 表格状态,属性对应含义请查阅 BaTable 的类型定义 */ + public table: BaTable = reactive({ + ref: undefined, + pk: 'id', + data: [], + remark: null, + loading: false, + selection: [], + column: [], + total: 0, + filter: {}, + dragSortLimitField: 'pid', + acceptQuery: true, + showComSearch: false, + dblClickNotEditColumn: [undefined], + expandAll: false, + extend: {}, + }) + + /** 表单状态,属性对应含义请查阅 BaTableForm 的类型定义 */ + public form: BaTableForm = reactive({ + ref: undefined, + labelWidth: 160, + operate: '', + operateIds: [], + items: {}, + submitLoading: false, + defaultItems: {}, + loading: false, + extend: {}, + }) + + /** BaTable 前置处理函数列表(前置埋点) */ + public before: BaTableBefore + + /** BaTable 后置处理函数列表(后置埋点) */ + public after: BaTableAfter + + /** 公共搜索数据 */ + public comSearch: ComSearch = reactive({ + form: {}, + fieldData: new Map(), + }) + + constructor(api: baTableApi, table: BaTable, form: BaTableForm = {}, before: BaTableBefore = {}, after: BaTableAfter = {}) { + this.api = api + this.form = Object.assign(this.form, form) + this.table = Object.assign(this.table, table) + this.before = before + this.after = after + } + + /** + * 表格内部鉴权方法 + * 此方法在表头或表行组件内部自动调用,传递权限节点名,如:add、edit + * 若需自定义表格内部鉴权,重写此方法即可 + */ + auth(node: string) { + return auth(node) + } + + /** + * 运行前置函数 + * @param funName 函数名 + * @param args 参数 + */ + runBefore(funName: string, args: any = {}) { + if (this.before && this.before[funName] && typeof this.before[funName] == 'function') { + return this.before[funName]!({ ...args }) === false ? false : true + } + return true + } + + /** + * 运行后置函数 + * @param funName 函数名 + * @param args 参数 + */ + runAfter(funName: string, args: any = {}) { + if (this.after && this.after[funName] && typeof this.after[funName] == 'function') { + return this.after[funName]!({ ...args }) === false ? false : true + } + return true + } + + /** + * 表格数据获取(请求表格对应控制器的查看方法) + * @alias getIndex + */ + getData = () => { + if (this.runBefore('getData') === false) return + if (this.runBefore('getIndex') === false) return + this.table.loading = true + return this.api + .index(this.table.filter) + .then((res) => { + this.table.data = res.data.list + this.table.total = res.data.total + this.table.remark = res.data.remark + this.runAfter('getData', { res }) + this.runAfter('getIndex', { res }) + }) + .catch((err) => { + this.runAfter('getData', { err }) + this.runAfter('getIndex', { err }) + }) + .finally(() => { + this.table.loading = false + }) + } + + /** + * 删除数据 + */ + postDel = (ids: string[]) => { + if (this.runBefore('postDel', { ids }) === false) return + this.api.del(ids).then((res) => { + this.onTableHeaderAction('refresh', { event: 'delete', ids }) + this.runAfter('postDel', { res }) + }) + } + + /** + * 获取被编辑行数据 + * @alias requestEdit + */ + getEditData = (id: string) => { + if (this.runBefore('getEditData', { id }) === false) return + if (this.runBefore('requestEdit', { id }) === false) return + this.form.loading = true + this.form.items = {} + return this.api + .edit({ + [this.table.pk!]: id, + }) + .then((res) => { + this.form.items = res.data.row + this.runAfter('getEditData', { res }) + this.runAfter('requestEdit', { res }) + }) + .catch((err) => { + this.toggleForm() + this.runAfter('getEditData', { err }) + this.runAfter('requestEdit', { err }) + }) + .finally(() => { + this.form.loading = false + }) + } + + /** + * 双击表格 + * @param row 行数据 + * @param column 列上下文数据 + */ + onTableDblclick = (row: TableRow, column: TableColumnCtx) => { + if (!this.table.dblClickNotEditColumn!.includes('all') && !this.table.dblClickNotEditColumn!.includes(column.property)) { + if (this.runBefore('onTableDblclick', { row, column }) === false) return + this.toggleForm('Edit', [row[this.table.pk!]]) + this.runAfter('onTableDblclick', { row, column }) + } + } + + /** + * 打开表单 + * @param operate 操作:Add=添加,Edit=编辑 + * @param operateIds 被操作项的数组:Add=[],Edit=[1,2,...] + */ + toggleForm = (operate = '', operateIds: string[] = []) => { + if (this.runBefore('toggleForm', { operate, operateIds }) === false) return + if (operate == 'Edit') { + if (!operateIds.length) { + return false + } + this.getEditData(operateIds[0]) + } else if (operate == 'Add') { + this.form.items = cloneDeep(this.form.defaultItems) + } + this.form.operate = operate + this.form.operateIds = operateIds + this.runAfter('toggleForm', { operate, operateIds }) + } + + /** + * 提交表单 + * @param formEl 表单组件ref + */ + onSubmit = (formEl?: FormInstance | null) => { + // 当前操作的首字母小写 + const operate = this.form.operate!.replace(this.form.operate![0], this.form.operate![0].toLowerCase()) + + if (this.runBefore('onSubmit', { formEl: formEl, operate: operate, items: this.form.items! }) === false) return + + // 表单验证通过后执行的 api 请求操作 + const submitCallback = () => { + this.form.submitLoading = true + this.api + .postData(operate, this.form.items!) + .then((res) => { + this.onTableHeaderAction('refresh', { event: 'submit', operate, items: this.form.items }) + this.form.operateIds?.shift() + if (this.form.operateIds!.length > 0) { + this.toggleForm('Edit', this.form.operateIds) + } else { + this.toggleForm() + } + this.runAfter('onSubmit', { res }) + }) + .finally(() => { + this.form.submitLoading = false + }) + } + + if (formEl) { + this.form.ref = formEl + formEl.validate((valid: boolean) => { + if (valid) { + submitCallback() + } + }) + } else { + submitCallback() + } + } + + /** + * 获取表格选择项的主键数组 + */ + getSelectionIds() { + const ids: string[] = [] + this.table.selection?.forEach((item) => { + ids.push(item[this.table.pk!]) + }) + return ids + } + + /** + * 表格内的事件统一响应 + * @param event 事件名称,含义请参考其类型定义 + * @param data 携带数据 + */ + onTableAction = (event: BaTableActionEventName, data: anyObj) => { + if (this.runBefore('onTableAction', { event, data }) === false) return + const actionFun = new Map([ + [ + 'selection-change', + () => { + this.table.selection = data as TableRow[] + }, + ], + [ + 'page-size-change', + () => { + this.table.filter!.limit = data.size + this.onTableHeaderAction('refresh', { event: 'page-size-change', ...data }) + }, + ], + [ + 'current-page-change', + () => { + this.table.filter!.page = data.page + this.onTableHeaderAction('refresh', { event: 'current-page-change', ...data }) + }, + ], + [ + 'sort-change', + () => { + let newOrder: string | undefined + if (data.prop && data.order) { + newOrder = data.prop + ',' + data.order + } + if (newOrder != this.table.filter!.order) { + this.table.filter!.order = newOrder + this.onTableHeaderAction('refresh', { event: 'sort-change', ...data }) + } + }, + ], + [ + 'edit', + () => { + this.toggleForm('Edit', [data.row[this.table.pk!]]) + }, + ], + [ + 'delete', + () => { + this.postDel([data.row[this.table.pk!]]) + }, + ], + [ + 'field-change', + () => { + if (data.field && data.field.prop && this.table.data![data.index]) { + this.table.data![data.index][data.field.prop!] = data.value + } + }, + ], + [ + 'com-search', + () => { + // 主动触发公共搜索,采用覆盖模式设定请求筛选数据 + this.setFilterSearchData(this.getComSearchData(), 'cover') + + // 刷新表格 + this.onTableHeaderAction('refresh', { event: 'com-search', data: this.table.filter!.search }) + }, + ], + [ + 'default', + () => { + console.warn('No action defined') + }, + ], + ]) + + const action = actionFun.get(event) || actionFun.get('default') + action!.call(this) + return this.runAfter('onTableAction', { event, data }) + } + + /** + * 表格顶栏按钮事件统一响应 + * @param event 事件名称,含义参考其类型定义 + * @param data 携带数据 + */ + onTableHeaderAction = (event: BaTableHeaderActionEventName, data: anyObj) => { + if (this.runBefore('onTableHeaderAction', { event, data }) === false) return + const actionFun = new Map([ + [ + 'refresh', + () => { + // 刷新表格在大多数情况下无需置空 data,但任需防范表格列组件的 :key 不会被更新的问题,比如关联表的数据列 + this.table.data = [] + this.getData() + }, + ], + [ + 'add', + () => { + this.toggleForm('Add') + }, + ], + [ + 'edit', + () => { + this.toggleForm('Edit', this.getSelectionIds()) + }, + ], + [ + 'delete', + () => { + this.postDel(this.getSelectionIds()) + }, + ], + [ + 'unfold', + () => { + if (!this.table.ref) { + console.warn('Collapse/expand failed because table ref is not defined. Please assign table ref when onMounted') + return + } + this.table.expandAll = data.unfold + this.table.ref.unFoldAll(data.unfold) + }, + ], + [ + 'quick-search', + () => { + this.onTableHeaderAction('refresh', { event: 'quick-search', ...data }) + }, + ], + [ + 'change-show-column', + () => { + const columnKey = getArrayKey(this.table.column, 'prop', data.field) + this.table.column[columnKey].show = data.value + }, + ], + [ + 'default', + () => { + console.warn('No action defined') + }, + ], + ]) + + const action = actionFun.get(event) || actionFun.get('default') + action!.call(this) + return this.runAfter('onTableHeaderAction', { event, data }) + } + + /** + * 初始化默认排序 + * el-table 的 `default-sort` 在自定义排序时无效 + * 此方法只有在表格数据请求结束后执行有效 + */ + initSort = () => { + if (this.table.defaultOrder && this.table.defaultOrder.prop) { + if (!this.table.ref) { + console.warn('Failed to initialize default sorting because table ref is not defined. Please assign table ref when onMounted') + return + } + + const defaultOrder = this.table.defaultOrder.prop + ',' + this.table.defaultOrder.order + if (this.table.filter && this.table.filter.order != defaultOrder) { + this.table.filter.order = defaultOrder + this.table.ref.getRef()?.sort(this.table.defaultOrder.prop, this.table.defaultOrder.order == 'desc' ? 'descending' : 'ascending') + } + } + } + + /** + * 初始化表格拖动排序 + */ + dragSort = () => { + const buttonsKey = getArrayKey(this.table.column, 'render', 'buttons') + if (buttonsKey === false) return + const moveButton = getArrayKey(this.table.column[buttonsKey]?.buttons, 'render', 'moveButton') + if (moveButton === false) return + if (!this.table.ref) { + console.warn('Failed to initialize drag sort because table ref is not defined. Please assign table ref when onMounted') + return + } + + const el = this.table.ref.getRef()?.$el.querySelector('.el-table__body-wrapper .el-table__body tbody') + const disabledTip = this.table.column[buttonsKey].buttons![moveButton].disabledTip + Sortable.create(el, { + animation: 200, + handle: '.table-row-weigh-sort', + ghostClass: 'ba-table-row', + onStart: () => { + this.table.column[buttonsKey].buttons![moveButton].disabledTip = true + }, + onEnd: (evt: Sortable.SortableEvent) => { + this.table.column[buttonsKey].buttons![moveButton].disabledTip = disabledTip + + // 目标位置不变 + if (evt.oldIndex == evt.newIndex || typeof evt.newIndex == 'undefined' || typeof evt.oldIndex == 'undefined') return + + // 找到对应行id + const moveRow = findIndexRow(this.table.data!, evt.oldIndex) as TableRow + const targetRow = findIndexRow(this.table.data!, evt.newIndex) as TableRow + + const eventData = { + move: moveRow[this.table.pk!], + target: targetRow[this.table.pk!], + order: this.table.filter?.order, + direction: evt.newIndex > evt.oldIndex ? 'down' : 'up', + } + + if (this.table.dragSortLimitField && moveRow[this.table.dragSortLimitField] != targetRow[this.table.dragSortLimitField]) { + this.onTableHeaderAction('refresh', { event: 'sort', ...eventData }) + ElNotification({ + type: 'error', + message: i18n.global.t('utils.The moving position is beyond the movable range!'), + }) + return + } + + this.api.sortable(eventData).finally(() => { + this.onTableHeaderAction('refresh', { event: 'sort', ...eventData }) + }) + }, + }) + } + + /** + * 表格初始化 + */ + mount = () => { + if (this.runBefore('mount') === false) return + + // 记录表格的路由路径 + const route = useRoute() + this.table.routePath = route.fullPath + + // 按需初始化公共搜索表单数据和字段Map + if (this.comSearch.fieldData.size === 0) { + this.initComSearch() + } + + if (this.table.acceptQuery && !isEmpty(route.query)) { + // 根据当前 URL 的 query 初始化公共搜索默认值 + this.setComSearchData(route.query) + + // 获取公共搜索数据合并至表格筛选条件 + this.setFilterSearchData(this.getComSearchData(), 'merge') + } + } + + /** + * 公共搜索初始化 + */ + initComSearch = () => { + const form: anyObj = {} + const field = this.table.column + + if (field.length <= 0) return + + for (const key in field) { + // 关闭搜索的字段 + if (field[key].operator === false) continue + + // 取默认操作符号 + if (typeof field[key].operator == 'undefined') { + field[key].operator = 'eq' + } + + // 公共搜索表单字段初始化 + const prop = field[key].prop + if (prop) { + if (field[key].operator == 'RANGE' || field[key].operator == 'NOT RANGE') { + // 范围查询 + form[prop] = '' + form[prop + '-start'] = '' + form[prop + '-end'] = '' + } else if (field[key].operator == 'NULL' || field[key].operator == 'NOT NULL') { + // 复选框 + form[prop] = false + } else { + // 普通文本框 + form[prop] = '' + } + + // 初始化字段的公共搜索数据 + this.comSearch.fieldData.set(prop, { + operator: field[key].operator, + render: field[key].render, + comSearchRender: field[key].comSearchRender, + }) + } + } + + this.comSearch.form = Object.assign(this.comSearch.form, form) + } + + /** + * 设置公共搜索表单数据 + */ + setComSearchData = (query: anyObj) => { + // 必需已经完成公共搜索数据的初始化 + if (this.comSearch.fieldData.size === 0) { + this.initComSearch() + } + + for (const key in this.table.column) { + const prop = this.table.column[key].prop + if (prop && typeof query[prop] !== 'undefined') { + const queryProp = query[prop] ?? '' + if (this.table.column[key].operator == 'RANGE' || this.table.column[key].operator == 'NOT RANGE') { + const range = queryProp.split(',') + if (this.table.column[key].render == 'datetime' || this.table.column[key].comSearchRender == 'date') { + if (range && range.length >= 2) { + const rangeDayJs = [dayjs(range[0]), dayjs(range[1])] + if (rangeDayJs[0].isValid() && rangeDayJs[1].isValid()) { + if (this.table.column[key].comSearchRender == 'date') { + this.comSearch.form[prop] = [rangeDayJs[0].format('YYYY-MM-DD'), rangeDayJs[1].format('YYYY-MM-DD')] + } else { + this.comSearch.form[prop] = [ + rangeDayJs[0].format('YYYY-MM-DD HH:mm:ss'), + rangeDayJs[1].format('YYYY-MM-DD HH:mm:ss'), + ] + } + } + } + } else if (this.table.column[key].comSearchRender == 'time') { + if (range && range.length >= 2) { + this.comSearch.form[prop] = [range[0], range[1]] + } + } else { + this.comSearch.form[prop + '-start'] = range[0] ?? '' + this.comSearch.form[prop + '-end'] = range[1] ?? '' + } + } else if (this.table.column[key].operator == 'NULL' || this.table.column[key].operator == 'NOT NULL') { + this.comSearch.form[prop] = queryProp ? true : false + } else if (this.table.column[key].render == 'datetime' || this.table.column[key].comSearchRender == 'date') { + const propDayJs = dayjs(queryProp) + if (propDayJs.isValid()) { + this.comSearch.form[prop] = propDayJs.format( + this.table.column[key].comSearchRender == 'date' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss' + ) + } + } else { + this.comSearch.form[prop] = queryProp + } + } + } + } + + /** + * 获取公共搜索表单数据 + */ + getComSearchData = () => { + // 必需已经完成公共搜索数据的初始化 + if (this.comSearch.fieldData.size === 0) { + this.initComSearch() + } + + const comSearchData: ComSearchData[] = [] + + for (const key in this.comSearch.form) { + if (!this.comSearch.fieldData.has(key)) continue + + let val = null + const fieldDataTemp = this.comSearch.fieldData.get(key) + if ( + (fieldDataTemp.render == 'datetime' || ['datetime', 'date', 'time'].includes(fieldDataTemp.comSearchRender)) && + (fieldDataTemp.operator == 'RANGE' || fieldDataTemp.operator == 'NOT RANGE') + ) { + if (this.comSearch.form[key] && this.comSearch.form[key].length >= 2) { + // 日期范围 + if (fieldDataTemp.comSearchRender == 'date') { + val = this.comSearch.form[key][0] + ' 00:00:00' + ',' + this.comSearch.form[key][1] + ' 23:59:59' + } else { + // 时间范围、时间日期范围 + val = this.comSearch.form[key][0] + ',' + this.comSearch.form[key][1] + } + } + } else if (fieldDataTemp.operator == 'RANGE' || fieldDataTemp.operator == 'NOT RANGE') { + // 普通的范围筛选,公共搜索初始化时已准备好 start 和 end 字段 + if (!this.comSearch.form[key + '-start'] && !this.comSearch.form[key + '-end']) { + continue + } + val = this.comSearch.form[key + '-start'] + ',' + this.comSearch.form[key + '-end'] + } else if (this.comSearch.form[key]) { + val = this.comSearch.form[key] + } + + if (val === null) continue + if (isArray(val) && !val.length) continue + + comSearchData.push({ + field: key, + val: val, + operator: fieldDataTemp.operator, + render: fieldDataTemp.render, + }) + } + + return comSearchData + } + + /** + * 设置 getData 请求时的过滤条件(搜索数据) + * @param search 新的搜索数据 + * @param mode 模式:cover=覆盖到已有搜索数据,merge=合并到已有搜索数据 + */ + setFilterSearchData = (search: ComSearchData[], mode: 'cover' | 'merge' = 'merge') => { + if (mode == 'cover' || !this.table.filter?.search) { + this.table.filter!.search = search + } else { + const merged = this.table.filter!.search.concat(search) + const fieldMap = new Map() + + merged.forEach((item) => { + fieldMap.set(item.field, item) + }) + + this.table.filter!.search = Array.from(fieldMap.values()) + } + } + + // 方法别名 + getIndex = this.getData + requestEdit = this.getEditData +} diff --git a/web/src/utils/build.ts b/web/src/utils/build.ts new file mode 100644 index 0000000..8370d31 --- /dev/null +++ b/web/src/utils/build.ts @@ -0,0 +1,37 @@ +import { readdirSync, writeFile } from 'fs' +import { trimEnd } from 'lodash-es' + +function getFileNames(dir: string) { + const dirents = readdirSync(dir, { + withFileTypes: true, + }) + const fileNames: string[] = [] + for (const dirent of dirents) { + if (!dirent.isDirectory()) fileNames.push(dirent.name.replace('.vue', '')) + } + return fileNames +} + +/** + * 生成 ./types/tableRenderer.d.ts 文件 + */ +const buildTableRendererType = () => { + let tableRenderer = getFileNames('./src/components/table/fieldRender/') + + // 增加 slot,去除 default + tableRenderer.push('slot') + tableRenderer = tableRenderer.filter((item) => item !== 'default') + + let tableRendererContent = + '/** 可用的表格单元格渲染器,以 ./src/components/table/fieldRender/ 目录中的文件名自动生成 */\ntype TableRenderer =\n | ' + for (const key in tableRenderer) { + tableRendererContent += `'${tableRenderer[key]}'\n | ` + } + tableRendererContent = trimEnd(tableRendererContent, ' | ') + + writeFile('./types/tableRenderer.d.ts', tableRendererContent, 'utf-8', (err) => { + if (err) throw err + }) +} + +buildTableRendererType() diff --git a/web/src/utils/common.ts b/web/src/utils/common.ts new file mode 100644 index 0000000..ad3aaef --- /dev/null +++ b/web/src/utils/common.ts @@ -0,0 +1,404 @@ +import * as elIcons from '@element-plus/icons-vue' +import { useTitle } from '@vueuse/core' +import type { FormInstance } from 'element-plus' +import { isArray, isNull, trim, trimStart } from 'lodash-es' +import type { App } from 'vue' +import { nextTick } from 'vue' +import type { TranslateOptions } from 'vue-i18n' +import { i18n } from '../lang' +import { useSiteConfig } from '../stores/siteConfig' +import { getUrl } from './axios' +import Icon from '/@/components/icon/index.vue' +import router from '/@/router/index' +import { adminBaseRoutePath } from '/@/router/static/adminBase' +import { useMemberCenter } from '/@/stores/memberCenter' +import { useNavTabs } from '/@/stores/navTabs' + +export function registerIcons(app: App) { + /* + * 全局注册 Icon + * 使用方式: + * 详见<待完善> + */ + app.component('Icon', Icon) + + /* + * 全局注册element Plus的icon + */ + const icons = elIcons as any + for (const i in icons) { + app.component(`el-icon-${icons[i].name}`, icons[i]) + } +} + +/** + * 加载网络css文件 + * @param url css资源url + */ +export function loadCss(url: string): void { + const link = document.createElement('link') + link.rel = 'stylesheet' + link.href = url + link.crossOrigin = 'anonymous' + document.getElementsByTagName('head')[0].appendChild(link) +} + +/** + * 加载网络js文件 + * @param url js资源url + */ +export function loadJs(url: string): void { + const link = document.createElement('script') + link.src = url + document.body.appendChild(link) +} + +/** + * 根据路由 meta.title 设置浏览器标题 + */ +export function setTitleFromRoute() { + nextTick(() => { + if (typeof router.currentRoute.value.meta.title != 'string') { + return + } + const webTitle = i18n.global.te(router.currentRoute.value.meta.title) + ? i18n.global.t(router.currentRoute.value.meta.title) + : router.currentRoute.value.meta.title + const title = useTitle() + const siteConfig = useSiteConfig() + title.value = `${webTitle}${siteConfig.siteName ? ' - ' + siteConfig.siteName : ''}` + }) +} + +/** + * 设置浏览器标题 + * @param webTitle 新的标题 + */ +export function setTitle(webTitle: string) { + if (router.currentRoute.value) { + router.currentRoute.value.meta.title = webTitle + } + nextTick(() => { + const title = useTitle() + const siteConfig = useSiteConfig() + title.value = `${webTitle}${siteConfig.siteName ? ' - ' + siteConfig.siteName : ''}` + }) +} + +/** + * 是否是外部链接 + * @param path + */ +export function isExternal(path: string): boolean { + return /^(https?|ftp|mailto|tel):/.test(path) +} + +/** + * 全局防抖 + * 与 _.debounce 不同的是,间隔期间如果再次传递不同的函数,两个函数也只会执行一次 + * @param fn 执行函数 + * @param ms 间隔毫秒数 + */ +export const debounce = (fn: Function, ms: number) => { + return (...args: any[]) => { + if (window.lazy) { + clearTimeout(window.lazy) + } + window.lazy = window.setTimeout(() => { + fn(...args) + }, ms) + } +} + +/** + * 根据pk字段的值从数组中获取key + * @param arr + * @param pk + * @param value + */ +export const getArrayKey = (arr: any, pk: string, value: any): any => { + for (const key in arr) { + if (arr[key][pk] == value) { + return key + } + } + return false +} + +/** + * 表单重置 + * @param formEl + */ +export const onResetForm = (formEl?: FormInstance | null) => { + typeof formEl?.resetFields == 'function' && formEl.resetFields() +} + +/** + * 将数据构建为ElTree的data {label:'', children: []} + * @param data + */ +export const buildJsonToElTreeData = (data: any): ElTreeData[] => { + if (typeof data == 'object') { + const childrens = [] + for (const key in data) { + childrens.push({ + label: key + ': ' + data[key], + children: buildJsonToElTreeData(data[key]), + }) + } + return childrens + } else { + return [] + } +} + +/** + * 是否在后台应用内 + * @param path 不传递则通过当前路由 path 检查 + */ +export const isAdminApp = (path = '') => { + const regex = new RegExp(`^${adminBaseRoutePath}`) + if (path) { + return regex.test(path) + } + if (regex.test(getCurrentRoutePath())) { + return true + } + return false +} + +/** + * 是否为手机设备 + */ +export const isMobile = () => { + return !!navigator.userAgent.match( + /android|webos|ip(hone|ad|od)|opera (mini|mobi|tablet)|iemobile|windows.+(phone|touch)|mobile|fennec|kindle (Fire)|Silk|maemo|blackberry|playbook|bb10\; (touch|kbd)|Symbian(OS)|Ubuntu Touch/i + ) +} + +/** + * 从一个文件路径中获取文件名 + * @param path 文件路径 + */ +export const getFileNameFromPath = (path: string) => { + const paths = path.split('/') + return paths[paths.length - 1] +} + +export function auth(node: string): boolean +export function auth(node: { name: string; subNodeName?: string }): boolean + +/** + * 鉴权 + * 提供 string 将根据当前路由 path 自动拼接和鉴权,还可以提供路由的 name 对象进行鉴权 + * @param node + */ +export function auth(node: string | { name: string; subNodeName?: string }) { + const store = isAdminApp() ? useNavTabs() : useMemberCenter() + if (typeof node === 'string') { + const path = getCurrentRoutePath() + if (store.state.authNode.has(path)) { + const subNodeName = path + (path == '/' ? '' : '/') + node + if (store.state.authNode.get(path)!.some((v: string) => v == subNodeName)) { + return true + } + } + } else { + // 节点列表中没有找到 name + if (!node.name || !store.state.authNode.has(node.name)) return false + + // 无需继续检查子节点或未找到子节点 + if (!node.subNodeName || store.state.authNode.get(node.name)?.includes(node.subNodeName)) return true + } + return false +} + +/** + * 获取资源完整地址 + * @param relativeUrl 资源相对地址 + * @param domain 指定域名 + */ +export const fullUrl = (relativeUrl: string, domain = '') => { + const siteConfig = useSiteConfig() + if (!domain) { + domain = siteConfig.cdnUrl ? siteConfig.cdnUrl : getUrl() + } + if (!relativeUrl) return domain + + const regUrl = new RegExp(/^http(s)?:\/\//) + const regexImg = new RegExp(/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i) + if (!domain || regUrl.test(relativeUrl) || regexImg.test(relativeUrl)) { + return relativeUrl + } + + let url = domain + relativeUrl + if (domain === siteConfig.cdnUrl && siteConfig.cdnUrlParams) { + const separator = url.includes('?') ? '&' : '?' + url += separator + siteConfig.cdnUrlParams + } + return url +} + +/** + * 获取路由 path + */ +export const getCurrentRoutePath = () => { + let path = router.currentRoute.value.path + if (path == '/') path = trimStart(window.location.hash, '#') + if (path.indexOf('?') !== -1) path = path.replace(/\?.*/, '') + return path +} + +/** + * 获取根据当前路由路径动态加载的语言翻译 + * @param key 无需语言路径的翻译key,亦可使用完整路径 + * @param named — 命名插值的值 + * @param options — 其他翻译选项 + * @returns — Translated message + */ +export const __ = (key: string, named?: Record, options?: TranslateOptions) => { + let langPath = '' + const path = getCurrentRoutePath() + if (isAdminApp()) { + langPath = path.slice(path.indexOf(adminBaseRoutePath) + adminBaseRoutePath.length) + langPath = trim(langPath, '/').replaceAll('/', '.') + } else { + langPath = trim(path, '/').replaceAll('/', '.') + } + langPath = langPath ? langPath + '.' + key : key + return i18n.global.te(langPath) + ? i18n.global.t(langPath, named ?? {}, options ? options : {}) + : i18n.global.t(key, named ?? {}, options ? options : {}) +} + +/** + * 文件类型效验,前端根据服务端配置进行初步检查 + * @param fileName 文件名 + * @param fileType 文件 mimeType,不一定存在 + */ +export const checkFileMimetype = (fileName: string, fileType: string) => { + if (!fileName) return false + const siteConfig = useSiteConfig() + const allowedSuffixes = isArray(siteConfig.upload.allowedSuffixes) + ? siteConfig.upload.allowedSuffixes + : siteConfig.upload.allowedSuffixes.toLowerCase().split(',') + + const allowedMimeTypes = isArray(siteConfig.upload.allowedMimeTypes) + ? siteConfig.upload.allowedMimeTypes + : siteConfig.upload.allowedMimeTypes.toLowerCase().split(',') + + const fileSuffix = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase() + if (allowedSuffixes.includes(fileSuffix) || allowedSuffixes.includes('.' + fileSuffix)) { + return true + } + if (fileType && allowedMimeTypes.includes(fileType)) { + return true + } + return false +} + +/** + * 获取一组资源的完整地址 + * @param relativeUrls 资源相对地址 + * @param domain 指定域名 + */ +export const arrayFullUrl = (relativeUrls: string | string[], domain = '') => { + if (typeof relativeUrls === 'string') { + relativeUrls = relativeUrls == '' ? [] : relativeUrls.split(',') + } + for (const key in relativeUrls) { + relativeUrls[key] = fullUrl(relativeUrls[key], domain) + } + return relativeUrls +} + +/** + * 格式化时间戳 + * @param dateTime 时间戳,默认使用当前时间戳 + * @param fmt 格式化方式,默认:yyyy-mm-dd hh:MM:ss + */ +export const timeFormat = (dateTime: string | number | null = null, fmt = 'yyyy-mm-dd hh:MM:ss') => { + if (dateTime == 'none') { + return i18n.global.t('None') + } + + if (isNull(dateTime)) { + dateTime = Number(new Date()) + } + + /** + * 1. 秒级时间戳(10位)需要转换为毫秒级,才能供 Date 对象直接使用 + * 2. yyyy-mm-dd 也是10位,使用 isFinite 进行排除 + */ + if (String(dateTime).length === 10 && isFinite(Number(dateTime))) { + dateTime = +dateTime * 1000 + } + + let date = new Date(dateTime) + if (isNaN(date.getTime())) { + date = new Date(Number(dateTime)) + if (isNaN(date.getTime())) { + return 'Invalid Date' + } + } + + let ret + const opt: anyObj = { + 'y+': date.getFullYear().toString(), // 年 + 'm+': (date.getMonth() + 1).toString(), // 月 + 'd+': date.getDate().toString(), // 日 + 'h+': date.getHours().toString(), // 时 + 'M+': date.getMinutes().toString(), // 分 + 's+': date.getSeconds().toString(), // 秒 + } + for (const k in opt) { + ret = new RegExp('(' + k + ')').exec(fmt) + if (ret) { + fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : padStart(opt[k], ret[1].length, '0')) + } + } + return fmt +} + +/** + * 字符串补位 + */ +const padStart = (str: string, maxLength: number, fillString = ' ') => { + if (str.length >= maxLength) return str + + const fillLength = maxLength - str.length + let times = Math.ceil(fillLength / fillString.length) + while ((times >>= 1)) { + fillString += fillString + if (times === 1) { + fillString += fillString + } + } + return fillString.slice(0, fillLength) + str +} + +/** + * 根据当前时间生成问候语 + */ +export const getGreet = () => { + const now = new Date() + const hour = now.getHours() + let greet = '' + + if (hour < 5) { + greet = i18n.global.t('utils.Late at night, pay attention to your body!') + } else if (hour < 9) { + greet = i18n.global.t('utils.good morning!') + i18n.global.t('utils.welcome back') + } else if (hour < 12) { + greet = i18n.global.t('utils.Good morning!') + i18n.global.t('utils.welcome back') + } else if (hour < 14) { + greet = i18n.global.t('utils.Good noon!') + i18n.global.t('utils.welcome back') + } else if (hour < 18) { + greet = i18n.global.t('utils.good afternoon') + i18n.global.t('utils.welcome back') + } else if (hour < 24) { + greet = i18n.global.t('utils.Good evening') + i18n.global.t('utils.welcome back') + } else { + greet = i18n.global.t('utils.Hello!') + i18n.global.t('utils.welcome back') + } + return greet +} diff --git a/web/src/utils/directives.ts b/web/src/utils/directives.ts new file mode 100644 index 0000000..814ae07 --- /dev/null +++ b/web/src/utils/directives.ts @@ -0,0 +1,224 @@ +import type { App } from 'vue' +import { nextTick } from 'vue' +import horizontalScroll from '/@/utils/horizontalScroll' +import { useEventListener } from '@vueuse/core' +import { isString } from 'lodash-es' +import { auth } from '/@/utils/common' + +export function directives(app: App) { + // 鉴权指令 + authDirective(app) + // 拖动指令 + dragDirective(app) + // 缩放指令 + zoomDirective(app) + // 点击后自动失焦指令 + blurDirective(app) + // 表格横向拖动指令 + tableLateralDragDirective(app) +} + +/** + * 页面按钮鉴权指令 + * @description v-auth="'name'",name可以为:index,add,edit,del,... + */ +function authDirective(app: App) { + app.directive('auth', { + mounted(el, binding) { + if (!binding.value) return false + if (!auth(binding.value)) el.parentNode.removeChild(el) + }, + }) +} + +/** + * 表格横向滚动指令 + * @description v-table-lateral-drag + */ +function tableLateralDragDirective(app: App) { + app.directive('tableLateralDrag', { + created(el) { + new horizontalScroll(el.querySelector('.el-table__body-wrapper .el-scrollbar .el-scrollbar__wrap')) + }, + }) +} + +/** + * 点击后自动失焦指令 + * @description v-blur + */ +function blurDirective(app: App) { + app.directive('blur', { + mounted(el) { + useEventListener(el, 'focus', () => el.blur()) + }, + }) +} + +/** + * el-dialog 的缩放指令 + * 可以传递字符串和数组 + * 当为字符串时,传递dialog的class即可,实际被缩放的元素为'.el-dialog__body' + * 当为数组时,参数一为句柄,参数二为实际被缩放的元素 + * @description v-zoom="'.handle-class-name'" + * @description v-zoom="['.handle-class-name', '.zoom-dom-class-name', 句柄元素高度是否跟随缩放:默认false,句柄元素宽度是否跟随缩放:默认true]" + */ +function zoomDirective(app: App) { + app.directive('zoom', { + mounted(el, binding) { + if (!binding.value) return false + const zoomDomBindData = isString(binding.value) ? [binding.value, '.el-dialog__body', false, true] : binding.value + zoomDomBindData[1] = zoomDomBindData[1] ? zoomDomBindData[1] : '.el-dialog__body' + zoomDomBindData[2] = typeof zoomDomBindData[2] == 'undefined' ? false : zoomDomBindData[2] + zoomDomBindData[3] = typeof zoomDomBindData[3] == 'undefined' ? true : zoomDomBindData[3] + + nextTick(() => { + const zoomDom = document.querySelector(zoomDomBindData[1]) as HTMLElement // 实际被缩放的元素 + const zoomDomBox = document.querySelector(zoomDomBindData[0]) as HTMLElement // 动态添加缩放句柄的元素 + const zoomHandleEl = document.createElement('div') // 缩放句柄 + zoomHandleEl.className = 'zoom-handle' + zoomHandleEl.onmouseenter = () => { + zoomHandleEl.onmousedown = (e: MouseEvent) => { + const x = e.clientX + const y = e.clientY + const zoomDomWidth = zoomDom.offsetWidth + const zoomDomHeight = zoomDom.offsetHeight + const zoomDomBoxWidth = zoomDomBox.offsetWidth + const zoomDomBoxHeight = zoomDomBox.offsetHeight + document.onmousemove = (e: MouseEvent) => { + e.preventDefault() // 移动时禁用默认事件 + const w = zoomDomWidth + (e.clientX - x) * 2 + const h = zoomDomHeight + (e.clientY - y) + + zoomDom.style.width = `${w}px` + zoomDom.style.height = `${h}px` + + if (zoomDomBindData[2]) { + const boxH = zoomDomBoxHeight + (e.clientY - y) + zoomDomBox.style.height = `${boxH}px` + } + if (zoomDomBindData[3]) { + const boxW = zoomDomBoxWidth + (e.clientX - x) * 2 + zoomDomBox.style.width = `${boxW}px` + } + } + + document.onmouseup = function () { + document.onmousemove = null + document.onmouseup = null + } + } + } + + zoomDomBox.appendChild(zoomHandleEl) + }) + }, + }) +} + +/** + * 拖动指令 + * @description v-drag="[domEl,handleEl]" + * @description domEl=被拖动的元素,handleEl=在此元素内可以拖动`dom` + */ +interface downReturn { + [key: string]: number +} +function dragDirective(app: App) { + app.directive('drag', { + mounted(el, binding) { + if (!binding.value) return false + + const dragDom = document.querySelector(binding.value[0]) as HTMLElement + const dragHandle = document.querySelector(binding.value[1]) as HTMLElement + + if (!dragHandle || !dragDom) { + return false + } + + function down(e: MouseEvent | TouchEvent, type: string): downReturn { + // 鼠标按下,记录鼠标位置 + const disX = type === 'pc' ? (e as MouseEvent).clientX : (e as TouchEvent).touches[0].clientX + const disY = type === 'pc' ? (e as MouseEvent).clientY : (e as TouchEvent).touches[0].clientY + + // body宽度 + const screenWidth = document.body.clientWidth + const screenHeight = document.body.clientHeight || document.documentElement.clientHeight + + // 被拖动元素宽度 + const dragDomWidth = dragDom.offsetWidth + // 被拖动元素高度 + const dragDomheight = dragDom.offsetHeight + + // 拖动限位 + const minDragDomLeft = dragDom.offsetLeft + const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth + const minDragDomTop = dragDom.offsetTop + const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight + + // 获取到的值带px 正则匹配替换 + let styL: string | number = getComputedStyle(dragDom).left + let styT: string | number = getComputedStyle(dragDom).top + styL = +styL.replace(/\px/g, '') + styT = +styT.replace(/\px/g, '') + + return { + disX, + disY, + minDragDomLeft, + maxDragDomLeft, + minDragDomTop, + maxDragDomTop, + styL, + styT, + } + } + + function move(e: MouseEvent | TouchEvent, type: string, obj: downReturn) { + const { disX, disY, minDragDomLeft, maxDragDomLeft, minDragDomTop, maxDragDomTop, styL, styT } = obj + + // 通过事件委托,计算移动的距离 + let left = type === 'pc' ? (e as MouseEvent).clientX - disX : (e as TouchEvent).touches[0].clientX - disX + let top = type === 'pc' ? (e as MouseEvent).clientY - disY : (e as TouchEvent).touches[0].clientY - disY + + // 边界处理 + if (-left > minDragDomLeft) { + left = -minDragDomLeft + } else if (left > maxDragDomLeft) { + left = maxDragDomLeft + } + + if (-top > minDragDomTop) { + top = -minDragDomTop + } else if (top > maxDragDomTop) { + top = maxDragDomTop + } + + // 移动当前元素 + dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;` + } + + dragHandle.onmouseover = () => (dragHandle.style.cursor = `move`) + dragHandle.onmousedown = (e) => { + const obj = down(e, 'pc') + document.onmousemove = (e) => { + move(e, 'pc', obj) + } + document.onmouseup = () => { + document.onmousemove = null + document.onmouseup = null + } + } + dragHandle.ontouchstart = (e) => { + const obj = down(e, 'app') + document.ontouchmove = (e) => { + move(e, 'app', obj) + } + document.ontouchend = () => { + document.ontouchmove = null + document.ontouchend = null + } + } + }, + }) +} diff --git a/web/src/utils/horizontalScroll.ts b/web/src/utils/horizontalScroll.ts new file mode 100644 index 0000000..47d6817 --- /dev/null +++ b/web/src/utils/horizontalScroll.ts @@ -0,0 +1,33 @@ +/** + * 横向滚动条 + */ +export default class horizontalScroll { + private el: HTMLElement + + constructor(nativeElement: HTMLElement) { + this.el = nativeElement + this.handleWheelEvent() + } + + handleWheelEvent() { + let wheel = '' + + if ('onmousewheel' in this.el) { + wheel = 'mousewheel' + } else if ('onwheel' in this.el) { + wheel = 'wheel' + } else if ('attachEvent' in window) { + wheel = 'onmousewheel' + } else { + wheel = 'DOMMouseScroll' + } + this.el['addEventListener'](wheel, this.scroll, { passive: true }) + } + + scroll = (event: any) => { + if (this.el.clientWidth >= this.el.scrollWidth) { + return + } + this.el.scrollLeft += event.deltaY ? event.deltaY : event.detail && event.detail !== 0 ? event.detail : -event.wheelDelta + } +} diff --git a/web/src/utils/iconfont.ts b/web/src/utils/iconfont.ts new file mode 100644 index 0000000..ca6a0c5 --- /dev/null +++ b/web/src/utils/iconfont.ts @@ -0,0 +1,170 @@ +import { nextTick } from 'vue' +import { loadCss, loadJs } from './common' +import * as elIcons from '@element-plus/icons-vue' +import { getUrl } from '/@/utils/axios' + +/** + * 动态加载的 css 和 js + */ +const cssUrls: Array = ['//at.alicdn.com/t/font_3135462_5axiswmtpj.css'] +const jsUrls: Array = [] + +/* + * 加载预设的字体图标资源 + */ +export default function init() { + if (cssUrls.length > 0) { + cssUrls.map((v) => { + loadCss(v) + }) + } + + if (jsUrls.length > 0) { + jsUrls.map((v) => { + loadJs(v) + }) + } +} + +/* + * 获取当前页面中从指定域名加载到的样式表内容 + * 样式表未载入前无法获取 + */ +function getStylesFromDomain(domain: string) { + const sheets = [] + const styles: StyleSheetList = document.styleSheets + for (const key in styles) { + if (styles[key].href && (styles[key].href as string).indexOf(domain) > -1) { + sheets.push(styles[key]) + } + } + return sheets +} + +/** + * 获取Vite开发服务/编译后的样式表内容 + * @param devID style 标签的 viteDevId,只开发服务有 + */ +function getStylesFromVite(devId: string) { + const sheets = [] + const styles: StyleSheetList = document.styleSheets + if (import.meta.env.MODE == 'production') { + const url = getUrl() + for (const key in styles) { + if (styles[key].href && styles[key].href?.indexOf(url) === 0) { + sheets.push(styles[key]) + } + } + return sheets + } + for (const key in styles) { + const ownerNode = styles[key].ownerNode as HTMLMapElement + if (ownerNode && ownerNode.dataset?.viteDevId && ownerNode.dataset.viteDevId!.indexOf(devId) > -1) { + sheets.push(styles[key]) + } + } + return sheets +} + +/* + * 获取本地自带的图标 + * /src/assets/icons文件夹内的svg文件 + */ +export function getLocalIconfontNames() { + return new Promise((resolve, reject) => { + nextTick(() => { + let iconfonts: string[] = [] + + const svgEl = document.getElementById('local-icon') + if (svgEl?.dataset.iconName) { + iconfonts = (svgEl?.dataset.iconName as string).split(',') + } + + if (iconfonts.length > 0) { + resolve(iconfonts) + } else { + reject('No Local Icons') + } + }) + }) +} + +/* + * 获取 Awesome-Iconfont 的 name 列表 + */ +export function getAwesomeIconfontNames() { + return new Promise((resolve, reject) => { + nextTick(() => { + const iconfonts = [] + const sheets = getStylesFromVite('font-awesome.min.css') + for (const key in sheets) { + const rules: any = sheets[key].cssRules + for (const k in rules) { + if (!rules[k].selectorText || rules[k].selectorText.indexOf('.fa-') !== 0) { + continue + } + if (/^\.fa-(.*)::before$/g.test(rules[k].selectorText)) { + if (rules[k].selectorText.indexOf(', ') > -1) { + const iconNames = rules[k].selectorText.split(', ') + iconfonts.push(`${iconNames[0].substring(1, iconNames[0].length).replace(/\:\:before/gi, '')}`) + } else { + iconfonts.push(`${rules[k].selectorText.substring(1, rules[k].selectorText.length).replace(/\:\:before/gi, '')}`) + } + } + } + } + + if (iconfonts.length > 0) { + resolve(iconfonts) + } else { + reject('No AwesomeIcon style sheet') + } + }) + }) +} + +/* + * 获取 Iconfont 的 name 列表 + */ +export function getIconfontNames() { + return new Promise((resolve, reject) => { + nextTick(() => { + const iconfonts = [] + const sheets = getStylesFromDomain('at.alicdn.com') + for (const key in sheets) { + const rules: any = sheets[key].cssRules + for (const k in rules) { + if (rules[k].selectorText && /^\.icon-(.*)::before$/g.test(rules[k].selectorText)) { + iconfonts.push(`${rules[k].selectorText.substring(1, rules[k].selectorText.length).replace(/\:\:before/gi, '')}`) + } + } + } + + if (iconfonts.length > 0) { + resolve(iconfonts) + } else { + reject('No Iconfont style sheet') + } + }) + }) +} + +/* + * 获取element plus 自带的图标 + */ +export function getElementPlusIconfontNames() { + return new Promise((resolve, reject) => { + nextTick(() => { + const iconfonts = [] + const icons = elIcons as any + for (const i in icons) { + iconfonts.push(`el-icon-${icons[i].name}`) + } + if (iconfonts.length > 0) { + resolve(iconfonts) + } else { + reject('No ElementPlus Icons') + } + }) + }) +} diff --git a/web/src/utils/layout.ts b/web/src/utils/layout.ts new file mode 100644 index 0000000..26078a9 --- /dev/null +++ b/web/src/utils/layout.ts @@ -0,0 +1,60 @@ +import type { CSSProperties } from 'vue' +import { useConfig } from '/@/stores/config' +import { useMemberCenter } from '/@/stores/memberCenter' +import { useNavTabs } from '/@/stores/navTabs' +import { isAdminApp } from '/@/utils/common' + +/** + * 管理员后台各个布局顶栏高度 + */ +export const adminLayoutHeaderBarHeight = { + Default: 70, + Classic: 50, + Streamline: 60, + Double: 60, +} + +/** + * 前台会员中心各个布局顶栏高度 + */ +export const userLayoutHeaderBarHeight = { + Default: 60, + Disable: 60, +} + +/** + * main高度 + * @param extra main高度额外减去的px数,可以实现隐藏原有的滚动条 + * @returns CSSProperties + */ +export function mainHeight(extra = 0): CSSProperties { + let height = extra + if (isAdminApp()) { + const config = useConfig() + const navTabs = useNavTabs() + if (!navTabs.state.tabFullScreen) { + height += adminLayoutHeaderBarHeight[config.layout.layoutMode as keyof typeof adminLayoutHeaderBarHeight] + } + } else { + const memberCenter = useMemberCenter() + height += userLayoutHeaderBarHeight[memberCenter.state.layoutMode as keyof typeof userLayoutHeaderBarHeight] + } + return { + height: 'calc(100vh - ' + height.toString() + 'px)', + } +} + +/** + * 设置导航栏宽度 + * @returns + */ +export function setNavTabsWidth() { + const navTabs = document.querySelector('.nav-tabs') as HTMLElement + if (!navTabs) { + return + } + const navBar = document.querySelector('.nav-bar') as HTMLElement + const navMenus = document.querySelector('.nav-menus') as HTMLElement + const minWidth = navBar.offsetWidth - (navMenus.offsetWidth + 20) + navTabs.style.width = minWidth.toString() + 'px' +} diff --git a/web/src/utils/loading.ts b/web/src/utils/loading.ts new file mode 100644 index 0000000..937cfa5 --- /dev/null +++ b/web/src/utils/loading.ts @@ -0,0 +1,34 @@ +import { nextTick } from 'vue' +import '/@/styles/loading.scss' + +export const loading = { + show: () => { + const bodys: Element = document.body + const div = document.createElement('div') + div.className = 'block-loading' + div.innerHTML = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+ ` + bodys.insertBefore(div, bodys.childNodes[0]) + }, + hide: () => { + nextTick(() => { + setTimeout(() => { + const el = document.querySelector('.block-loading') + el && el.parentNode?.removeChild(el) + }, 1000) + }) + }, +} diff --git a/web/src/utils/pageBubble.ts b/web/src/utils/pageBubble.ts new file mode 100644 index 0000000..f024753 --- /dev/null +++ b/web/src/utils/pageBubble.ts @@ -0,0 +1,104 @@ +// 页面气泡效果 + +const bubble: { + width: number + height: number + bubbleEl: any + canvas: any + ctx: any + circles: any[] + animate: boolean + requestId: any +} = { + width: 0, + height: 0, + bubbleEl: null, + canvas: null, + ctx: {}, + circles: [], + animate: true, + requestId: null, +} + +export const init = function (): void { + bubble.width = window.innerWidth + bubble.height = window.innerHeight + + bubble.bubbleEl = document.getElementById('bubble') + bubble.bubbleEl.style.height = bubble.height + 'px' + + bubble.canvas = document.getElementById('bubble-canvas') + bubble.canvas.width = bubble.width + bubble.canvas.height = bubble.height + bubble.ctx = bubble.canvas.getContext('2d') + + // create particles + bubble.circles = [] + for (let x = 0; x < bubble.width * 0.5; x++) { + const c = new Circle() + bubble.circles.push(c) + } + animate() + addListeners() +} + +function scrollCheck() { + bubble.animate = document.body.scrollTop > bubble.height ? false : true +} + +function resize() { + bubble.width = window.innerWidth + bubble.height = window.innerHeight + bubble.bubbleEl.style.height = bubble.height + 'px' + bubble.canvas.width = bubble.width + bubble.canvas.height = bubble.height +} + +function animate() { + if (bubble.animate) { + bubble.ctx.clearRect(0, 0, bubble.width, bubble.height) + for (const i in bubble.circles) { + bubble.circles[i].draw() + } + } + bubble.requestId = requestAnimationFrame(animate) +} + +class Circle { + pos: { + x: number + y: number + } + alpha: number + scale: number + velocity: number + draw: () => void + constructor() { + this.pos = { + x: Math.random() * bubble.width, + y: bubble.height + Math.random() * 100, + } + this.alpha = 0.1 + Math.random() * 0.3 + this.scale = 0.1 + Math.random() * 0.3 + this.velocity = Math.random() + this.draw = function () { + this.pos.y -= this.velocity + this.alpha -= 0.0005 + bubble.ctx.beginPath() + bubble.ctx.arc(this.pos.x, this.pos.y, this.scale * 10, 0, 2 * Math.PI, false) + bubble.ctx.fillStyle = 'rgba(255,255,255,' + this.alpha + ')' + bubble.ctx.fill() + } + } +} + +function addListeners() { + window.addEventListener('scroll', scrollCheck) + window.addEventListener('resize', resize) +} + +export function removeListeners() { + window.removeEventListener('scroll', scrollCheck) + window.removeEventListener('resize', resize) + cancelAnimationFrame(bubble.requestId) +} diff --git a/web/src/utils/pageShade.ts b/web/src/utils/pageShade.ts new file mode 100644 index 0000000..98cd5a9 --- /dev/null +++ b/web/src/utils/pageShade.ts @@ -0,0 +1,22 @@ +import { useEventListener } from '@vueuse/core' + +/* + * 显示页面遮罩 + */ +export const showShade = function (className = 'shade', closeCallBack: Function): void { + const containerEl = document.querySelector('.layout-container') as HTMLElement + const shadeDiv = document.createElement('div') + shadeDiv.setAttribute('class', 'ba-layout-shade ' + className) + containerEl.appendChild(shadeDiv) + useEventListener(shadeDiv, 'click', () => closeShade(closeCallBack)) +} + +/* + * 隐藏页面遮罩 + */ +export const closeShade = function (closeCallBack: Function = () => {}): void { + const shadeEl = document.querySelector('.ba-layout-shade') as HTMLElement + shadeEl && shadeEl.remove() + + closeCallBack() +} diff --git a/web/src/utils/random.ts b/web/src/utils/random.ts new file mode 100644 index 0000000..6b2a11d --- /dev/null +++ b/web/src/utils/random.ts @@ -0,0 +1,57 @@ +const hexList: string[] = [] +for (let i = 0; i <= 15; i++) { + hexList[i] = i.toString(16) +} + +/** + * 生成随机数 + * @param min 最小值 + * @param max 最大值 + * @returns 生成的随机数 + */ +export function randomNum(min: number, max: number) { + switch (arguments.length) { + case 1: + return parseInt((Math.random() * min + 1).toString(), 10) + break + case 2: + return parseInt((Math.random() * (max - min + 1) + min).toString(), 10) + break + default: + return 0 + break + } +} + +/** + * 生成全球唯一标识 + * @returns uuid + */ +export function uuid(): string { + let uuid = '' + for (let i = 1; i <= 36; i++) { + if (i === 9 || i === 14 || i === 19 || i === 24) { + uuid += '-' + } else if (i === 15) { + uuid += 4 + } else if (i === 20) { + uuid += hexList[(Math.random() * 4) | 8] + } else { + uuid += hexList[(Math.random() * 16) | 0] + } + } + return uuid +} + +/** + * 生成唯一标识 + * @param prefix 前缀 + * @returns 唯一标识 + */ +export function shortUuid(prefix = ''): string { + const time = Date.now() + const random = Math.floor(Math.random() * 1000000000) + if (!window.unique) window.unique = 0 + window.unique++ + return prefix + '_' + random + window.unique + String(time) +} diff --git a/web/src/utils/router.ts b/web/src/utils/router.ts new file mode 100644 index 0000000..dd6c331 --- /dev/null +++ b/web/src/utils/router.ts @@ -0,0 +1,318 @@ +import { ElNotification } from 'element-plus' +import { compact, isEmpty, reverse } from 'lodash-es' +import type { RouteLocationRaw, RouteRecordRaw } from 'vue-router' +import { isNavigationFailure, NavigationFailureType } from 'vue-router' +import { i18n } from '/@/lang/index' +import router from '/@/router/index' +import adminBaseRoute from '/@/router/static/adminBase' +import memberCenterBaseRoute from '/@/router/static/memberCenterBase' +import { useConfig } from '/@/stores/config' +import { useMemberCenter } from '/@/stores/memberCenter' +import { useNavTabs } from '/@/stores/navTabs' +import { useSiteConfig } from '/@/stores/siteConfig' +import { isAdminApp } from '/@/utils/common' +import { closeShade } from '/@/utils/pageShade' + +/** + * 导航失败有错误消息的路由push + * @param to — 导航位置,同 router.push + */ +export const routePush = async (to: RouteLocationRaw) => { + try { + const failure = await router.push(to) + if (isNavigationFailure(failure, NavigationFailureType.aborted)) { + ElNotification({ + message: i18n.global.t('utils.Navigation failed, navigation guard intercepted!'), + type: 'error', + }) + } else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) { + ElNotification({ + message: i18n.global.t('utils.Navigation failed, it is at the navigation target position!'), + type: 'warning', + }) + } + } catch (error) { + ElNotification({ + message: i18n.global.t('utils.Navigation failed, invalid route!'), + type: 'error', + }) + console.error(error) + } +} + +/** + * 获取第一个菜单 + */ +export const getFirstRoute = (routes: RouteRecordRaw[]): false | RouteRecordRaw => { + const routerPaths: string[] = [] + const routers = router.getRoutes() + routers.forEach((item) => { + if (item.path) routerPaths.push(item.path) + }) + let find: boolean | RouteRecordRaw = false + for (const key in routes) { + if (routes[key].meta?.type == 'menu' && routerPaths.indexOf(routes[key].path) !== -1) { + return routes[key] + } else if (routes[key].children && routes[key].children?.length) { + find = getFirstRoute(routes[key].children!) + if (find) return find + } + } + return find +} + +/** + * 打开侧边菜单 + * @param menu 菜单数据 + */ +export const onClickMenu = (menu: RouteRecordRaw) => { + switch (menu.meta?.menu_type) { + case 'iframe': + case 'tab': + routePush(menu.path) + break + case 'link': + window.open(menu.path, '_blank') + break + + default: + ElNotification({ + message: i18n.global.t('utils.Navigation failed, the menu type is unrecognized!'), + type: 'error', + }) + break + } + + const config = useConfig() + if (config.layout.shrink) { + closeShade(() => { + config.setLayout('menuCollapse', true) + }) + } +} + +/** + * 处理前台的路由 + * @param routes 路由规则 + * @param menus 会员中心菜单路由规则 + */ +export const handleFrontendRoute = (routes: any, menus: any) => { + const siteConfig = useSiteConfig() + const memberCenter = useMemberCenter() + const viewsComponent = import.meta.glob('/src/views/frontend/**/*.vue') + + if (routes.length) { + addRouteAll(viewsComponent, routes, '', true) + memberCenter.mergeAuthNode(handleAuthNode(routes, '/')) + siteConfig.setHeadNav(handleMenuRule(routes, '/', ['nav'])) + memberCenter.mergeNavUserMenus(handleMenuRule(routes, '/', ['nav_user_menu'])) + } + if (menus.length && isEmpty(memberCenter.state.viewRoutes)) { + addRouteAll(viewsComponent, menus, memberCenterBaseRoute.name as string) + const menuMemberCenterBaseRoute = (memberCenterBaseRoute.path as string) + '/' + memberCenter.mergeAuthNode(handleAuthNode(menus, menuMemberCenterBaseRoute)) + + memberCenter.mergeNavUserMenus(handleMenuRule(menus, '/', ['nav_user_menu'])) + memberCenter.setShowHeadline(menus.length > 1) + memberCenter.setViewRoutes(handleMenuRule(menus, menuMemberCenterBaseRoute)) + } +} + +/** + * 处理后台的路由 + */ +export const handleAdminRoute = (routes: any) => { + const viewsComponent = import.meta.glob('/src/views/backend/**/*.vue') + addRouteAll(viewsComponent, routes, adminBaseRoute.name as string) + const menuAdminBaseRoute = (adminBaseRoute.path as string) + '/' + + // 更新stores中的路由菜单数据 + const navTabs = useNavTabs() + navTabs.setTabsViewRoutes(handleMenuRule(routes, menuAdminBaseRoute)) + navTabs.fillAuthNode(handleAuthNode(routes, menuAdminBaseRoute)) +} + +/** + * 获取菜单的paths + */ +export const getMenuPaths = (menus: RouteRecordRaw[]): string[] => { + let menuPaths: string[] = [] + menus.forEach((item) => { + menuPaths.push(item.path) + if (item.children && item.children.length > 0) { + menuPaths = menuPaths.concat(getMenuPaths(item.children)) + } + }) + return menuPaths +} + +/** + * 获取菜单唯一标识 + * @param menu 菜单数据 + * @param prefix 前缀 + */ +export const getMenuKey = (menu: RouteRecordRaw, prefix = '') => { + if (prefix === '') { + prefix = menu.path + } + return `${prefix}-${menu.name as string}-${menu.meta && menu.meta.id ? menu.meta.id : ''}` +} + +/** + * 会员中心和后台的菜单处理 + */ +const handleMenuRule = (routes: any, pathPrefix = '/', type = ['menu', 'menu_dir']) => { + const menuRule: RouteRecordRaw[] = [] + for (const key in routes) { + if (routes[key].extend == 'add_rules_only') { + continue + } + if (!type.includes(routes[key].type)) { + continue + } + if (routes[key].type == 'menu_dir' && routes[key].children && !routes[key].children.length) { + continue + } + if ( + ['route', 'menu', 'nav_user_menu', 'nav'].includes(routes[key].type) && + ((routes[key].menu_type == 'tab' && !routes[key].component) || (['link', 'iframe'].includes(routes[key].menu_type) && !routes[key].url)) + ) { + continue + } + const currentPath = ['link', 'iframe'].includes(routes[key].menu_type) ? routes[key].url : pathPrefix + routes[key].path + let children: RouteRecordRaw[] = [] + if (routes[key].children && routes[key].children.length > 0) { + children = handleMenuRule(routes[key].children, pathPrefix, type) + } + menuRule.push({ + path: currentPath, + name: routes[key].name, + component: routes[key].component, + meta: { + id: routes[key].id, + title: routes[key].title, + icon: routes[key].icon, + keepalive: routes[key].keepalive, + menu_type: routes[key].menu_type, + type: routes[key].type, + }, + children: children, + }) + } + return menuRule +} + +/** + * 处理权限节点 + * @param routes 路由数据 + * @param prefix 节点前缀 + * @returns 组装好的权限节点 + */ +const handleAuthNode = (routes: any, prefix = '/') => { + const authNode: Map = new Map([]) + assembleAuthNode(routes, authNode, prefix, prefix) + return authNode +} +const assembleAuthNode = (routes: any, authNode: Map, prefix = '/', parent = '/') => { + const authNodeTemp = [] + for (const key in routes) { + if (routes[key].type == 'button') authNodeTemp.push(prefix + routes[key].name) + if (routes[key].children && routes[key].children.length > 0) { + assembleAuthNode(routes[key].children, authNode, prefix, prefix + routes[key].name) + } + } + if (authNodeTemp && authNodeTemp.length > 0) { + authNode.set(parent, authNodeTemp) + } +} + +/** + * 动态添加路由-带子路由 + * @param viewsComponent + * @param routes + * @param parentName + * @param analyticRelation 根据 name 从已注册路由分析父级路由 + */ +export const addRouteAll = (viewsComponent: Record, routes: any, parentName: string, analyticRelation = false) => { + for (const idx in routes) { + if (routes[idx].extend == 'add_menu_only') { + continue + } + if ((routes[idx].menu_type == 'tab' && viewsComponent[routes[idx].component]) || routes[idx].menu_type == 'iframe') { + addRouteItem(viewsComponent, routes[idx], parentName, analyticRelation) + } + + if (routes[idx].children && routes[idx].children.length > 0) { + addRouteAll(viewsComponent, routes[idx].children, parentName, analyticRelation) + } + } +} + +/** + * 动态添加路由 + * @param viewsComponent + * @param route + * @param parentName + * @param analyticRelation 根据 name 从已注册路由分析父级路由 + */ +export const addRouteItem = (viewsComponent: Record, route: any, parentName: string, analyticRelation: boolean) => { + let path = '', + component + if (route.menu_type == 'iframe') { + path = (isAdminApp() ? adminBaseRoute.path : memberCenterBaseRoute.path) + '/iframe/' + encodeURIComponent(route.url) + component = () => import('/@/layouts/common/router-view/iframe.vue') + } else { + path = parentName ? route.path : '/' + route.path + component = viewsComponent[route.component] + } + + if (route.menu_type == 'tab' && analyticRelation) { + const parentNames = getParentNames(route.name) + if (parentNames.length) { + for (const key in parentNames) { + if (router.hasRoute(parentNames[key])) { + parentName = parentNames[key] + break + } + } + } + } + + const routeBaseInfo: RouteRecordRaw = { + path: path, + name: route.name, + component: component, + meta: { + title: route.title, + extend: route.extend, + icon: route.icon, + keepalive: route.keepalive, + menu_type: route.menu_type, + type: route.type, + url: route.url, + addtab: true, + }, + } + if (parentName) { + router.addRoute(parentName, routeBaseInfo) + } else { + router.addRoute(routeBaseInfo) + } +} + +/** + * 根据name字符串,获取父级name组合的数组 + * @param name + */ +const getParentNames = (name: string) => { + const names = compact(name.split('/')) + const tempNames = [] + const parentNames = [] + for (const key in names) { + tempNames.push(names[key]) + if (parseInt(key) != names.length - 1) { + parentNames.push(tempNames.join('/')) + } + } + return reverse(parentNames) +} diff --git a/web/src/utils/storage.ts b/web/src/utils/storage.ts new file mode 100644 index 0000000..1b4d3e5 --- /dev/null +++ b/web/src/utils/storage.ts @@ -0,0 +1,45 @@ +/** + * window.localStorage + * @method set 设置 + * @method get 获取 + * @method remove 移除 + * @method clear 移除全部 + */ +export const Local = { + set(key: string, val: any) { + window.localStorage.setItem(key, JSON.stringify(val)) + }, + get(key: string) { + const json: any = window.localStorage.getItem(key) + return JSON.parse(json) + }, + remove(key: string) { + window.localStorage.removeItem(key) + }, + clear() { + window.localStorage.clear() + }, +} + +/** + * window.sessionStorage + * @method set 设置会话缓存 + * @method get 获取会话缓存 + * @method remove 移除会话缓存 + * @method clear 移除全部会话缓存 + */ +export const Session = { + set(key: string, val: any) { + window.sessionStorage.setItem(key, JSON.stringify(val)) + }, + get(key: string) { + const json: any = window.sessionStorage.getItem(key) + return JSON.parse(json) + }, + remove(key: string) { + window.sessionStorage.removeItem(key) + }, + clear() { + window.sessionStorage.clear() + }, +} diff --git a/web/src/utils/useCurrentInstance.ts b/web/src/utils/useCurrentInstance.ts new file mode 100644 index 0000000..c0fc26e --- /dev/null +++ b/web/src/utils/useCurrentInstance.ts @@ -0,0 +1,13 @@ +import { getCurrentInstance } from 'vue' +import type { ComponentInternalInstance } from 'vue' + +export default function useCurrentInstance() { + if (!getCurrentInstance()) { + throw new Error('useCurrentInstance() can only be used inside setup() or functional components!') + } + const { appContext } = getCurrentInstance() as ComponentInternalInstance + const proxy = appContext.config.globalProperties + return { + proxy, + } +} diff --git a/web/src/utils/useDark.ts b/web/src/utils/useDark.ts new file mode 100644 index 0000000..197b720 --- /dev/null +++ b/web/src/utils/useDark.ts @@ -0,0 +1,49 @@ +import { useDark, useToggle } from '@vueuse/core' +import { useConfig } from '/@/stores/config' +import { onMounted, onUnmounted, ref, watch } from 'vue' + +const isDark = useDark({ + onChanged(dark: boolean) { + const config = useConfig() + updateHtmlDarkClass(dark) + config.setLayout('isDark', dark) + config.onSetLayoutColor() + }, +}) + +/** + * 切换暗黑模式 + */ +const toggleDark = useToggle(isDark) + +/** + * 切换当前页面的暗黑模式 + */ +export function togglePageDark(val: boolean) { + const config = useConfig() + const isDark = ref(config.layout.isDark) + onMounted(() => { + if (isDark.value !== val) updateHtmlDarkClass(val) + }) + onUnmounted(() => { + updateHtmlDarkClass(isDark.value) + }) + watch( + () => config.layout.isDark, + (newVal) => { + isDark.value = newVal + if (isDark.value !== val) updateHtmlDarkClass(val) + } + ) +} + +export function updateHtmlDarkClass(val: boolean) { + const htmlEl = document.getElementsByTagName('html')[0] + if (val) { + htmlEl.setAttribute('class', 'dark') + } else { + htmlEl.setAttribute('class', '') + } +} + +export default toggleDark diff --git a/web/src/utils/validate.ts b/web/src/utils/validate.ts new file mode 100644 index 0000000..7a8fa48 --- /dev/null +++ b/web/src/utils/validate.ts @@ -0,0 +1,169 @@ +import type { RuleType } from 'async-validator' +import type { FormItemRule } from 'element-plus' +import { i18n } from '../lang' + +/** + * 手机号码验证 + */ +export function validatorMobile(rule: any, mobile: string | number, callback: Function) { + // 允许空值,若需必填请添加多验证规则 + if (!mobile) { + return callback() + } + if (!/^(1[3-9])\d{9}$/.test(mobile.toString())) { + return callback(new Error(i18n.global.t('validate.Please enter the correct mobile number'))) + } + return callback() +} + +/** + * 身份证号验证 + */ +export function validatorIdNumber(rule: any, idNumber: string | number, callback: Function) { + if (!idNumber) { + return callback() + } + if (!/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(idNumber.toString())) { + return callback(new Error(i18n.global.t('validate.Please enter the correct ID number'))) + } + return callback() +} + +/** + * 账户名验证 + */ +export function validatorAccount(rule: any, val: string, callback: Function) { + if (!val) { + return callback() + } + if (!/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/.test(val)) { + return callback(new Error(i18n.global.t('validate.Please enter the correct account'))) + } + return callback() +} + +/** + * 密码验证 + */ +export function regularPassword(val: string) { + return /^(?!.*[&<>"'\n\r]).{6,32}$/.test(val) +} +export function validatorPassword(rule: any, val: string, callback: Function) { + if (!val) { + return callback() + } + if (!regularPassword(val)) { + return callback(new Error(i18n.global.t('validate.Please enter the correct password'))) + } + return callback() +} + +/** + * 变量名验证 + */ +export function regularVarName(val: string) { + return /^([^\x00-\xff]|[a-zA-Z_$])([^\x00-\xff]|[a-zA-Z0-9_$])*$/.test(val) +} +export function validatorVarName(rule: any, val: string, callback: Function) { + if (!val) { + return callback() + } + if (!regularVarName(val)) { + return callback(new Error(i18n.global.t('validate.Please enter the correct name'))) + } + return callback() +} + +export function validatorEditorRequired(rule: any, val: string, callback: Function) { + if (!val || val == '


') { + return callback(new Error(i18n.global.t('validate.Content cannot be empty'))) + } + return callback() +} + +/** + * 支持的表单验证规则 + */ +export const validatorType = { + required: i18n.global.t('validate.required'), + mobile: i18n.global.t('utils.mobile'), + idNumber: i18n.global.t('utils.Id number'), + account: i18n.global.t('utils.account'), + password: i18n.global.t('utils.password'), + varName: i18n.global.t('utils.variable name'), + editorRequired: i18n.global.t('validate.editor required'), + url: 'URL', + email: i18n.global.t('utils.email'), + date: i18n.global.t('utils.date'), + number: i18n.global.t('validate.number'), // 数字(包括浮点和整数) + integer: i18n.global.t('validate.integer'), // 整数(不包括浮点数) + float: i18n.global.t('validate.float'), // 浮点数(不包括整数) +} + +export interface buildValidatorParams { + // 规则名:required=必填,mobile=手机号,idNumber=身份证号,account=账户,password=密码,varName=变量名,editorRequired=富文本必填,number、integer、float、date、url、email + name: + | 'required' + | 'mobile' + | 'idNumber' + | 'account' + | 'password' + | 'varName' + | 'editorRequired' + | 'number' + | 'integer' + | 'float' + | 'date' + | 'url' + | 'email' + // 自定义验证错误消息 + message?: string + // 验证项的标题,这些验证方式不支持:mobile、account、password、varName、editorRequired + title?: string + // 验证触发方式 + trigger?: 'change' | 'blur' +} + +/** + * 构建表单验证规则 + * @param {buildValidatorParams} paramsObj 参数对象 + */ +export function buildValidatorData({ name, message, title, trigger = 'blur' }: buildValidatorParams): FormItemRule { + // 必填 + if (name == 'required') { + return { + required: true, + message: message ? message : i18n.global.t('Please input field', { field: title }), + trigger: trigger, + } + } + + // 常见类型 + const validatorType = ['number', 'integer', 'float', 'date', 'url', 'email'] + if (validatorType.includes(name)) { + return { + type: name as RuleType, + message: message ? message : i18n.global.t('Please enter the correct field', { field: title }), + trigger: trigger, + } + } + + // 自定义验证方法 + const validatorCustomFun: anyObj = { + mobile: validatorMobile, + idNumber: validatorIdNumber, + account: validatorAccount, + password: validatorPassword, + varName: validatorVarName, + editorRequired: validatorEditorRequired, + } + if (validatorCustomFun[name]) { + return { + required: name == 'editorRequired' ? true : false, + validator: validatorCustomFun[name], + trigger: trigger, + message: message, + } + } + return {} +} diff --git a/web/src/utils/vite.ts b/web/src/utils/vite.ts new file mode 100644 index 0000000..6500262 --- /dev/null +++ b/web/src/utils/vite.ts @@ -0,0 +1,184 @@ +import type { Plugin, ViteDevServer } from 'vite' +import { reactive } from 'vue' + +interface HotUpdateState { + // 热更新状态 + switch: boolean + // 热更新关闭类型:terminal=WEB终端执行命令,crud=CRUD,modules=模块安装服务,config=修改系统配置 + closeType: string + // 是否有脏文件(热更新 switch 为 false,又触发了热更新就会产生脏文件) + dirtyFile: boolean + // 监听是否有脏文件 + listenDirtyFileSwitch: boolean +} + +/** + * 调试模式下的 Vite 热更新相关状态(这些状态均由 Vite 服务器记录并随时同步至客户端) + */ +export const hotUpdateState = reactive({ + switch: true, + closeType: '', + dirtyFile: false, + listenDirtyFileSwitch: true, +}) + +/** + * Vite 相关初始化 + */ +export function init() { + if (import.meta.hot) { + // 监听 Vite 服务器通知热更新相关状态更新 + import.meta.hot.on('custom:change-hot-update-state', (state: Partial) => { + hotUpdateState.switch = state.switch ?? hotUpdateState.switch + hotUpdateState.closeType = state.closeType ?? hotUpdateState.closeType + hotUpdateState.dirtyFile = state.dirtyFile ?? hotUpdateState.dirtyFile + hotUpdateState.listenDirtyFileSwitch = state.listenDirtyFileSwitch ?? hotUpdateState.listenDirtyFileSwitch + }) + + // 保持脏文件监听功能开启(同时可以从服务端同步一次热更新服务的状态数据) + changeListenDirtyFileSwitch(true) + } +} + +/** + * 是否在开发环境 + */ +export function isDev(mode: string): boolean { + return mode === 'development' +} + +/** + * 是否在生产环境 + */ +export function isProd(mode: string | undefined): boolean { + return mode === 'production' +} + +/** + * 调试模式下关闭热更新 + */ +export const closeHotUpdate = (type: string) => { + if (import.meta.hot) { + import.meta.hot.send('custom:close-hot', { type }) + } +} + +/** + * 调试模式下开启热更新 + */ +export const openHotUpdate = (type: string) => { + if (import.meta.hot) { + import.meta.hot.send('custom:open-hot', { type }) + } +} + +/** + * 调试模式下重启服务并刷新网页 + */ +export const reloadServer = (type: string) => { + if (import.meta.hot) { + import.meta.hot.send('custom:reload-server', { type }) + } +} + +/** + * 改变脏文件监听功能的开关 + */ +export const changeListenDirtyFileSwitch = (status: boolean) => { + if (import.meta.hot) { + import.meta.hot.send('custom:change-listen-dirty-file-switch', status) + } +} + +/** + * 自定义热更新/热替换处理的 Vite 插件 + */ +export const customHotUpdate = (): Plugin => { + type Listeners = ((...args: any[]) => void)[] + + let addFunctionBack: Listeners = [] + let unlinkFunctionBack: Listeners = [] + + // 本服务端的热更新状态数据 + const hotUpdateState: HotUpdateState = { + switch: true, + closeType: '', + dirtyFile: false, + listenDirtyFileSwitch: true, + } + + /** + * 同步所有热更新状态数据至客户端 + */ + const syncHotUpdateState = (server: ViteDevServer) => { + server.ws.send('custom:change-hot-update-state', hotUpdateState) + } + + return { + name: 'vite-plugin-custom-hot-update', + apply: 'serve', + configureServer(server) { + // 关闭热更新 + server.ws.on('custom:close-hot', ({ type }) => { + hotUpdateState.switch = false + hotUpdateState.closeType = type + + // 备份文件添加和删除时的函数列表 + addFunctionBack = server.watcher.listeners('add') as Listeners + unlinkFunctionBack = server.watcher.listeners('unlink') as Listeners + + // 关闭文件添加和删除的监听 + server.watcher.removeAllListeners('add') + server.watcher.removeAllListeners('unlink') + + syncHotUpdateState(server) + + // 文件添加时通知客户端新增了脏文件(文件删除无需记录为脏文件) + server.watcher.on('add', () => { + if (hotUpdateState.listenDirtyFileSwitch) { + hotUpdateState.dirtyFile = true + syncHotUpdateState(server) + } + }) + }) + + // 开启热更新 + server.ws.on('custom:open-hot', () => { + hotUpdateState.switch = true + server.watcher.removeAllListeners('add') + server.watcher.removeAllListeners('unlink') + + // 恢复备份的函数列表 + for (const key in addFunctionBack) { + server.watcher.on('add', addFunctionBack[key]) + } + for (const key in unlinkFunctionBack) { + server.watcher.on('unlink', unlinkFunctionBack[key]) + } + + syncHotUpdateState(server) + }) + + // 重启热更新 + server.ws.on('custom:reload-server', () => { + server.restart() + }) + + // 客户端可从本服务端获取热更新服务状态数据 + server.ws.on('custom:get-hot-update-state', () => { + syncHotUpdateState(server) + }) + + // 修改监听脏文件的开关 + server.ws.on('custom:change-listen-dirty-file-switch', (status: boolean) => { + hotUpdateState.listenDirtyFileSwitch = status + syncHotUpdateState(server) + }) + }, + handleHotUpdate() { + if (!hotUpdateState.switch) { + return [] + } + }, + } +} diff --git a/web/src/views/backend/auth/admin/index.vue b/web/src/views/backend/auth/admin/index.vue new file mode 100644 index 0000000..295f068 --- /dev/null +++ b/web/src/views/backend/auth/admin/index.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/web/src/views/backend/auth/admin/popupForm.vue b/web/src/views/backend/auth/admin/popupForm.vue new file mode 100644 index 0000000..cf3e43c --- /dev/null +++ b/web/src/views/backend/auth/admin/popupForm.vue @@ -0,0 +1,198 @@ + + + + + diff --git a/web/src/views/backend/auth/adminLog/index.vue b/web/src/views/backend/auth/adminLog/index.vue new file mode 100644 index 0000000..ee8e697 --- /dev/null +++ b/web/src/views/backend/auth/adminLog/index.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/web/src/views/backend/auth/adminLog/info.vue b/web/src/views/backend/auth/adminLog/info.vue new file mode 100644 index 0000000..cd4dc6f --- /dev/null +++ b/web/src/views/backend/auth/adminLog/info.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/web/src/views/backend/auth/group/index.vue b/web/src/views/backend/auth/group/index.vue new file mode 100644 index 0000000..42d574b --- /dev/null +++ b/web/src/views/backend/auth/group/index.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/web/src/views/backend/auth/group/popupForm.vue b/web/src/views/backend/auth/group/popupForm.vue new file mode 100644 index 0000000..95ebb66 --- /dev/null +++ b/web/src/views/backend/auth/group/popupForm.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/web/src/views/backend/auth/rule/index.vue b/web/src/views/backend/auth/rule/index.vue new file mode 100644 index 0000000..f147310 --- /dev/null +++ b/web/src/views/backend/auth/rule/index.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/web/src/views/backend/auth/rule/popupForm.vue b/web/src/views/backend/auth/rule/popupForm.vue new file mode 100644 index 0000000..4845f82 --- /dev/null +++ b/web/src/views/backend/auth/rule/popupForm.vue @@ -0,0 +1,244 @@ + + + + + diff --git a/web/src/views/backend/crud/design.vue b/web/src/views/backend/crud/design.vue new file mode 100644 index 0000000..ee588b0 --- /dev/null +++ b/web/src/views/backend/crud/design.vue @@ -0,0 +1,2075 @@ + + + + + diff --git a/web/src/views/backend/crud/index.ts b/web/src/views/backend/crud/index.ts new file mode 100644 index 0000000..85559e1 --- /dev/null +++ b/web/src/views/backend/crud/index.ts @@ -0,0 +1,970 @@ +import { reactive } from 'vue' +import { fieldData, npuaFalse } from '/@/components/baInput/helper' +import { i18n } from '/@/lang/index' +import { validatorType } from '/@/utils/validate' + +/** + * 字段修改类型标识 + * 改排序需要在表结构变更完成之后再单独处理所以标识独立 + */ +export type TableDesignChangeType = 'change-field-name' | 'del-field' | 'add-field' | 'change-field-attr' | 'change-field-order' + +export interface TableDesignChange { + type: TableDesignChangeType + // 字段在设计器中的数组 index + index?: number + // 字段旧名称(重命名、修改属性、删除) + oldName: string + // 字段新名称(重命名、添加) + newName: string + // 是否同步到数据表 + sync?: boolean + // 此字段在 after 字段之后,值为`FIRST FIELD`表示它是第一个字段 + after?: string +} + +export const state: { + step: 'Start' | 'Design' + type: string + startData: { + sql: string + table: string + logId: string + logType: string + databaseConnection: string + } +} = reactive({ + step: 'Start', + type: '', + startData: { + sql: '', + table: '', + logId: '', + logType: '', + databaseConnection: '', + }, +}) + +export const changeStep = (type: string) => { + state.type = type + if (type == 'start') { + state.step = 'Start' + for (const key in state.startData) { + state.startData[key as keyof typeof state.startData] = '' + } + } else { + state.step = 'Design' + } +} + +export interface FieldItem { + index?: number + title: string + name: string + type: string + dataType?: string + length: number + precision: number + default?: string + defaultType: 'INPUT' | 'EMPTY STRING' | 'NULL' | 'NONE' + null: boolean + primaryKey: boolean + unsigned: boolean + autoIncrement: boolean + comment: string + designType: string + formBuildExclude?: boolean + tableBuildExclude?: boolean + table: anyObj + form: anyObj + uuid?: string +} + +export const fieldItem: { + common: FieldItem[] + base: FieldItem[] + senior: FieldItem[] +} = { + common: [ + { + title: i18n.global.t('crud.state.Primary key'), + name: 'id', + comment: 'ID', + designType: 'pk', + formBuildExclude: true, + table: {}, + form: {}, + ...fieldData.number, + defaultType: 'NONE', + null: false, + primaryKey: true, + unsigned: true, + autoIncrement: true, + }, + { + title: i18n.global.t('crud.state.Primary key (Snowflake ID)'), + name: 'id', + comment: 'ID', + designType: 'spk', + formBuildExclude: true, + table: {}, + form: {}, + ...fieldData.number, + type: 'bigint', + length: 20, + defaultType: 'NONE', + null: false, + primaryKey: true, + unsigned: true, + }, + { + title: i18n.global.t('State'), + name: 'status', + comment: i18n.global.t('crud.state.Status:0=Disabled,1=Enabled'), + designType: 'switch', + table: {}, + form: {}, + ...fieldData.switch, + default: '1', + defaultType: 'INPUT', + }, + { + title: i18n.global.t('crud.state.remarks'), + name: 'remark', + comment: i18n.global.t('crud.state.remarks'), + designType: 'textarea', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.textarea, + }, + { + title: i18n.global.t('crud.state.Weight (drag and drop sorting)'), + name: 'weigh', + comment: i18n.global.t('Weigh'), + designType: 'weigh', + table: {}, + form: {}, + ...fieldData.number, + }, + { + title: i18n.global.t('Update time'), + name: 'update_time', + comment: i18n.global.t('Update time'), + designType: 'timestamp', + formBuildExclude: true, + table: {}, + form: {}, + ...fieldData.datetime, + }, + { + title: i18n.global.t('Create time'), + name: 'create_time', + comment: i18n.global.t('Create time'), + designType: 'timestamp', + formBuildExclude: true, + table: {}, + form: {}, + ...fieldData.datetime, + }, + { + title: i18n.global.t('crud.state.Remote Select (association table)'), + name: 'remote_select', + comment: i18n.global.t('utils.remote select'), + designType: 'remoteSelect', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.remoteSelect, + }, + ], + base: [ + { + title: i18n.global.t('utils.string'), + name: 'string', + comment: i18n.global.t('utils.string'), + designType: 'string', + table: {}, + form: {}, + ...fieldData.string, + }, + { + title: i18n.global.t('utils.image'), + name: 'image', + comment: i18n.global.t('utils.image'), + designType: 'image', + table: {}, + form: {}, + ...fieldData.image, + }, + { + title: i18n.global.t('utils.file'), + name: 'file', + comment: i18n.global.t('utils.file'), + designType: 'file', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.file, + }, + { + title: i18n.global.t('utils.radio'), + name: 'radio', + dataType: "enum('opt0','opt1')", + comment: i18n.global.t('crud.state.Radio:opt0=Option1,opt1=Option2'), + designType: 'radio', + table: {}, + form: {}, + ...fieldData.radio, + default: 'opt0', + defaultType: 'INPUT', + }, + { + title: i18n.global.t('utils.checkbox'), + name: 'checkbox', + dataType: "set('opt0','opt1')", + comment: i18n.global.t('crud.state.Checkbox:opt0=Option1,opt1=Option2'), + designType: 'checkbox', + table: {}, + form: {}, + ...fieldData.checkbox, + default: 'opt0,opt1', + defaultType: 'INPUT', + }, + { + title: i18n.global.t('utils.select'), + name: 'select', + dataType: "enum('opt0','opt1')", + comment: i18n.global.t('crud.state.Select:opt0=Option1,opt1=Option2'), + designType: 'select', + table: {}, + form: {}, + ...fieldData.select, + default: 'opt0', + defaultType: 'INPUT', + }, + { + title: i18n.global.t('utils.switch'), + name: 'switch', + comment: i18n.global.t('crud.state.Switch:0=off,1=on'), + designType: 'switch', + table: {}, + form: {}, + ...fieldData.switch, + default: '1', + defaultType: 'INPUT', + }, + { + title: i18n.global.t('utils.rich Text'), + name: 'editor', + comment: i18n.global.t('utils.rich Text'), + designType: 'editor', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.editor, + }, + { + title: i18n.global.t('utils.textarea'), + name: 'textarea', + comment: i18n.global.t('utils.textarea'), + designType: 'textarea', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.textarea, + }, + { + title: i18n.global.t('utils.number'), + name: 'number', + comment: i18n.global.t('utils.number'), + designType: 'number', + table: {}, + form: {}, + ...fieldData.number, + }, + { + title: i18n.global.t('utils.float'), + name: 'float', + type: 'decimal', + length: 5, + precision: 2, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + comment: i18n.global.t('utils.float'), + designType: 'float', + table: {}, + form: {}, + }, + { + title: i18n.global.t('utils.password'), + name: 'password', + comment: i18n.global.t('utils.password'), + designType: 'password', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.password, + }, + { + title: i18n.global.t('utils.date'), + name: 'date', + comment: i18n.global.t('utils.date'), + designType: 'date', + table: {}, + form: {}, + ...fieldData.date, + }, + { + title: i18n.global.t('utils.time'), + name: 'time', + comment: i18n.global.t('utils.time'), + designType: 'time', + table: {}, + form: {}, + ...fieldData.time, + }, + { + title: i18n.global.t('utils.time date'), + name: 'datetime', + type: 'datetime', + length: 0, + precision: 0, + defaultType: 'NULL', + ...npuaFalse(), + null: true, + comment: i18n.global.t('utils.time date'), + designType: 'datetime', + table: {}, + form: {}, + }, + { + title: i18n.global.t('utils.year'), + name: 'year', + comment: i18n.global.t('utils.year'), + designType: 'year', + table: {}, + form: {}, + ...fieldData.year, + }, + { + title: i18n.global.t('crud.state.Time date (timestamp storage)'), + name: 'timestamp', + comment: i18n.global.t('utils.time date'), + designType: 'timestamp', + table: {}, + form: {}, + ...fieldData.datetime, + }, + ], + senior: [ + { + title: i18n.global.t('utils.array'), + name: 'array', + comment: i18n.global.t('utils.array'), + designType: 'array', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.array, + }, + { + title: i18n.global.t('utils.city select'), + name: 'city', + comment: i18n.global.t('utils.city select'), + designType: 'city', + table: {}, + form: {}, + ...fieldData.city, + }, + { + title: i18n.global.t('utils.icon select'), + name: 'icon', + comment: i18n.global.t('utils.icon select'), + designType: 'icon', + table: {}, + form: {}, + ...fieldData.icon, + }, + { + title: i18n.global.t('utils.color picker'), + name: 'color', + comment: i18n.global.t('utils.color picker'), + designType: 'color', + table: {}, + form: {}, + ...fieldData.color, + }, + { + title: i18n.global.t('utils.image') + i18n.global.t('crud.state.Multi'), + name: 'images', + comment: i18n.global.t('utils.image'), + designType: 'images', + table: {}, + form: {}, + ...fieldData.images, + }, + { + title: i18n.global.t('utils.file') + i18n.global.t('crud.state.Multi'), + name: 'files', + comment: i18n.global.t('utils.file'), + designType: 'files', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.files, + }, + { + title: i18n.global.t('utils.select') + i18n.global.t('crud.state.Multi'), + name: 'selects', + comment: i18n.global.t('crud.state.Select:opt0=Option1,opt1=Option2'), + designType: 'selects', + table: {}, + form: {}, + ...fieldData.selects, + }, + { + title: i18n.global.t('crud.state.Remote Select (Multi)'), + name: 'remote_select', + comment: i18n.global.t('utils.remote select'), + designType: 'remoteSelects', + tableBuildExclude: true, + table: {}, + form: {}, + ...fieldData.remoteSelects, + }, + ], +} + +const tableBaseAttr = { + render: { + type: 'select', + value: 'none', + options: { + none: i18n.global.t('None'), + icon: 'Icon', + switch: i18n.global.t('utils.switch'), + image: i18n.global.t('utils.image'), + images: i18n.global.t('utils.multi image'), + tag: 'Tag', + tags: 'Tags', + url: 'URL', + datetime: i18n.global.t('utils.time date'), + color: i18n.global.t('utils.color'), + }, + }, + operator: { + type: 'select', + value: 'eq', + options: { + false: i18n.global.t('crud.state.Disable Search'), + eq: 'eq =', + ne: 'ne !=', + gt: 'gt >', + egt: 'egt >=', + lt: 'lt <', + elt: 'elt <=', + LIKE: 'LIKE', + 'NOT LIKE': 'NOT LIKE', + IN: 'IN', + 'NOT IN': 'NOT IN', + RANGE: 'RANGE', + 'NOT RANGE': 'NOT RANGE', + NULL: 'NULL', + 'NOT NULL': 'NOT NULL', + FIND_IN_SET: 'FIND_IN_SET', + }, + }, + comSearchRender: { + type: 'select', + value: 'string', + options: { + string: i18n.global.t('utils.string'), + select: i18n.global.t('utils.select'), + remoteSelect: i18n.global.t('utils.remote select'), + time: i18n.global.t('utils.time') + i18n.global.t('utils.choice'), + date: i18n.global.t('utils.date') + i18n.global.t('utils.choice'), + datetime: i18n.global.t('utils.time date') + i18n.global.t('utils.choice'), + }, + }, + comSearchInputAttr: { + type: 'textarea', + value: '', + placeholder: i18n.global.t('crud.crud.comSearchInputAttrTip'), + attr: { + rows: 3, + }, + }, + sortable: { + type: 'select', + value: 'false', + options: { + false: i18n.global.t('Disable'), + custom: i18n.global.t('Enable'), + }, + }, +} + +const formBaseAttr = { + validator: { + type: 'selects', + value: [], + options: validatorType, + }, + validatorMsg: { + type: 'textarea', + value: '', + placeholder: i18n.global.t('crud.state.If left blank, the verifier title attribute will be filled in automatically'), + attr: { + rows: 3, + }, + }, +} + +export const getTableAttr = (type: keyof typeof tableBaseAttr, val: string) => { + return { + ...tableBaseAttr[type], + value: val, + } +} + +const getFormAttr = (type: keyof typeof formBaseAttr, val: string[]) => { + return { + ...formBaseAttr[type], + value: val, + } +} + +export const designTypes: anyObj = { + pk: { + name: i18n.global.t('crud.state.Primary key'), + table: { + width: { + type: 'number', + value: 70, + }, + operator: getTableAttr('operator', 'RANGE'), + sortable: getTableAttr('sortable', 'custom'), + }, + form: {}, + }, + spk: { + name: i18n.global.t('crud.state.Primary key (Snowflake ID)'), + table: { + width: { + type: 'number', + value: 180, + }, + operator: getTableAttr('operator', 'RANGE'), + sortable: getTableAttr('sortable', 'custom'), + }, + form: {}, + }, + weigh: { + name: i18n.global.t('crud.state.Weight (automatically generate drag sort button)'), + table: { + operator: getTableAttr('operator', 'RANGE'), + sortable: getTableAttr('sortable', 'custom'), + }, + form: formBaseAttr, + }, + timestamp: { + name: i18n.global.t('crud.state.Time date (timestamp storage)'), + table: { + render: getTableAttr('render', 'datetime'), + operator: getTableAttr('operator', 'RANGE'), + comSearchRender: getTableAttr('comSearchRender', 'datetime'), + comSearchInputAttr: getTableAttr('comSearchInputAttr', ''), + sortable: getTableAttr('sortable', 'custom'), + width: { + type: 'number', + value: 160, + }, + timeFormat: { + type: 'string', + value: 'yyyy-mm-dd hh:MM:ss', + }, + }, + form: { + ...formBaseAttr, + validator: getFormAttr('validator', ['date']), + }, + }, + string: { + name: i18n.global.t('utils.string'), + table: { + render: getTableAttr('render', 'none'), + sortable: getTableAttr('sortable', 'false'), + operator: getTableAttr('operator', 'LIKE'), + }, + form: formBaseAttr, + }, + password: { + name: i18n.global.t('utils.password'), + table: { + operator: getTableAttr('operator', 'false'), + }, + form: { + ...formBaseAttr, + validator: getFormAttr('validator', ['password']), + }, + }, + number: { + name: i18n.global.t('utils.number'), + table: { + render: getTableAttr('render', 'none'), + sortable: getTableAttr('sortable', 'false'), + operator: getTableAttr('operator', 'RANGE'), + }, + form: { + ...formBaseAttr, + validator: getFormAttr('validator', ['number']), + step: { + type: 'number', + value: 1, + }, + }, + }, + float: { + name: i18n.global.t('utils.float'), + table: { + render: getTableAttr('render', 'none'), + sortable: getTableAttr('sortable', 'false'), + operator: getTableAttr('operator', 'RANGE'), + }, + form: { + ...formBaseAttr, + validator: getFormAttr('validator', ['float']), + step: { + type: 'number', + value: 1, + }, + }, + }, + radio: { + name: i18n.global.t('utils.radio'), + table: { + operator: getTableAttr('operator', 'eq'), + sortable: getTableAttr('sortable', 'false'), + render: getTableAttr('render', 'tag'), + }, + form: formBaseAttr, + }, + checkbox: { + name: i18n.global.t('utils.checkbox'), + table: { + sortable: getTableAttr('sortable', 'false'), + render: getTableAttr('render', 'tags'), + operator: getTableAttr('operator', 'FIND_IN_SET'), + }, + form: formBaseAttr, + }, + switch: { + name: i18n.global.t('utils.switch'), + table: { + operator: getTableAttr('operator', 'eq'), + sortable: getTableAttr('sortable', 'false'), + render: getTableAttr('render', 'switch'), + }, + form: formBaseAttr, + }, + textarea: { + name: i18n.global.t('utils.textarea'), + table: { + operator: getTableAttr('operator', 'false'), + }, + form: { + ...formBaseAttr, + rows: { + type: 'number', + value: 3, + }, + }, + }, + array: { + name: i18n.global.t('utils.array'), + table: { + operator: getTableAttr('operator', 'false'), + }, + form: formBaseAttr, + }, + datetime: { + name: i18n.global.t('utils.time date') + i18n.global.t('utils.choice'), + table: { + operator: getTableAttr('operator', 'RANGE'), + comSearchRender: getTableAttr('comSearchRender', 'datetime'), + comSearchInputAttr: getTableAttr('comSearchInputAttr', ''), + sortable: getTableAttr('sortable', 'custom'), + width: { + type: 'number', + value: 160, + }, + }, + form: { + ...formBaseAttr, + validator: getFormAttr('validator', ['date']), + }, + }, + year: { + name: i18n.global.t('utils.year') + i18n.global.t('utils.choice'), + table: { + operator: getTableAttr('operator', 'RANGE'), + sortable: getTableAttr('sortable', 'custom'), + }, + form: { + ...formBaseAttr, + validator: getFormAttr('validator', ['date']), + }, + }, + date: { + name: i18n.global.t('utils.date') + i18n.global.t('utils.choice'), + table: { + operator: getTableAttr('operator', 'RANGE'), + comSearchRender: getTableAttr('comSearchRender', 'date'), + comSearchInputAttr: getTableAttr('comSearchInputAttr', ''), + sortable: getTableAttr('sortable', 'custom'), + }, + form: { + ...formBaseAttr, + validator: getFormAttr('validator', ['date']), + }, + }, + time: { + name: i18n.global.t('utils.time') + i18n.global.t('utils.choice'), + table: { + operator: getTableAttr('operator', 'RANGE'), + comSearchRender: getTableAttr('comSearchRender', 'time'), + comSearchInputAttr: getTableAttr('comSearchInputAttr', ''), + sortable: getTableAttr('sortable', 'custom'), + }, + form: formBaseAttr, + }, + select: { + name: i18n.global.t('utils.select'), + table: { + operator: getTableAttr('operator', 'eq'), + sortable: getTableAttr('sortable', 'false'), + render: getTableAttr('render', 'tag'), + }, + form: { + ...formBaseAttr, + 'select-multi': { + type: 'switch', + value: false, + }, + }, + }, + selects: { + name: i18n.global.t('utils.select') + i18n.global.t('crud.state.Multi'), + table: { + sortable: getTableAttr('sortable', 'false'), + render: getTableAttr('render', 'tags'), + operator: getTableAttr('operator', 'FIND_IN_SET'), + }, + form: { + ...formBaseAttr, + 'select-multi': { + type: 'switch', + value: true, + }, + }, + }, + remoteSelect: { + name: i18n.global.t('utils.remote select') + i18n.global.t('utils.choice'), + table: { + render: getTableAttr('render', 'tags'), + operator: getTableAttr('operator', 'LIKE'), + comSearchRender: getTableAttr('comSearchRender', 'string'), + comSearchInputAttr: getTableAttr('comSearchInputAttr', ''), + }, + form: { + ...formBaseAttr, + 'select-multi': { + type: 'switch', + value: false, + }, + 'remote-pk': { + type: 'string', + value: 'id', + }, + 'remote-field': { + type: 'string', + value: 'name', + }, + 'remote-table': { + type: 'string', + value: '', + }, + 'remote-controller': { + type: 'string', + value: '', + }, + 'remote-model': { + type: 'string', + value: '', + }, + 'relation-fields': { + type: 'string', + value: '', + }, + 'remote-url': { + type: 'string', + value: '', + placeholder: i18n.global.t('crud.state.If it is not input, it will be automatically analyzed by the controller'), + }, + 'remote-primary-table-alias': { + type: 'string', + value: '', + }, + 'remote-source-config-type': { + type: 'hidden', + value: '', + }, + }, + }, + remoteSelects: { + name: i18n.global.t('utils.remote select') + i18n.global.t('utils.choice') + i18n.global.t('crud.state.Multi'), + table: { + render: getTableAttr('render', 'tags'), + operator: getTableAttr('operator', 'FIND_IN_SET'), + comSearchRender: getTableAttr('comSearchRender', 'remoteSelect'), + comSearchInputAttr: getTableAttr('comSearchInputAttr', ''), + }, + form: { + ...formBaseAttr, + 'select-multi': { + type: 'switch', + value: true, + }, + 'remote-pk': { + type: 'string', + value: 'id', + }, + 'remote-field': { + type: 'string', + value: 'name', + }, + 'remote-table': { + type: 'string', + value: '', + }, + 'remote-controller': { + type: 'string', + value: '', + }, + 'remote-model': { + type: 'string', + value: '', + }, + 'relation-fields': { + type: 'string', + value: '', + }, + 'remote-url': { + type: 'string', + value: '', + placeholder: i18n.global.t('crud.state.If it is not input, it will be automatically analyzed by the controller'), + }, + 'remote-primary-table-alias': { + type: 'string', + value: '', + }, + 'remote-source-config-type': { + type: 'hidden', + value: '', + }, + }, + }, + editor: { + name: i18n.global.t('utils.rich Text'), + table: { + operator: getTableAttr('operator', 'false'), + }, + form: { + ...formBaseAttr, + validator: getFormAttr('validator', ['editorRequired']), + }, + }, + city: { + name: i18n.global.t('utils.city select'), + table: { + operator: getTableAttr('operator', 'false'), + }, + form: formBaseAttr, + }, + image: { + name: i18n.global.t('utils.image') + i18n.global.t('Upload'), + table: { + render: getTableAttr('render', 'image'), + operator: getTableAttr('operator', 'false'), + }, + form: { + ...formBaseAttr, + 'image-multi': { + type: 'switch', + value: false, + }, + }, + }, + images: { + name: i18n.global.t('utils.image') + i18n.global.t('Upload') + i18n.global.t('crud.state.Multi'), + table: { + render: getTableAttr('render', 'images'), + operator: getTableAttr('operator', 'false'), + }, + form: { + ...formBaseAttr, + 'image-multi': { + type: 'switch', + value: true, + }, + }, + }, + file: { + name: i18n.global.t('utils.file') + i18n.global.t('Upload'), + table: { + render: getTableAttr('render', 'none'), + operator: getTableAttr('operator', 'false'), + }, + form: { + ...formBaseAttr, + 'file-multi': { + type: 'switch', + value: false, + }, + }, + }, + files: { + name: i18n.global.t('utils.file') + i18n.global.t('Upload') + i18n.global.t('crud.state.Multi'), + table: { + render: getTableAttr('render', 'none'), + operator: getTableAttr('operator', 'false'), + }, + form: { + ...formBaseAttr, + 'file-multi': { + type: 'switch', + value: true, + }, + }, + }, + icon: { + name: i18n.global.t('utils.icon select'), + table: { + render: getTableAttr('render', 'icon'), + operator: getTableAttr('operator', 'false'), + }, + form: formBaseAttr, + }, + color: { + name: i18n.global.t('utils.color picker'), + table: { + render: getTableAttr('render', 'color'), + operator: getTableAttr('operator', 'false'), + }, + form: formBaseAttr, + }, +} + +export const tableFieldsKey = ['quickSearchField', 'formFields', 'columnFields'] diff --git a/web/src/views/backend/crud/index.vue b/web/src/views/backend/crud/index.vue new file mode 100644 index 0000000..1c00aae --- /dev/null +++ b/web/src/views/backend/crud/index.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/web/src/views/backend/crud/log.vue b/web/src/views/backend/crud/log.vue new file mode 100644 index 0000000..9d931e6 --- /dev/null +++ b/web/src/views/backend/crud/log.vue @@ -0,0 +1,578 @@ + + + + + diff --git a/web/src/views/backend/crud/start.vue b/web/src/views/backend/crud/start.vue new file mode 100644 index 0000000..c1aa244 --- /dev/null +++ b/web/src/views/backend/crud/start.vue @@ -0,0 +1,319 @@ + + + + + diff --git a/web/src/views/backend/dashboard.vue b/web/src/views/backend/dashboard.vue new file mode 100644 index 0000000..0921c94 --- /dev/null +++ b/web/src/views/backend/dashboard.vue @@ -0,0 +1,826 @@ + + + + + diff --git a/web/src/views/backend/login.vue b/web/src/views/backend/login.vue new file mode 100644 index 0000000..cf07b38 --- /dev/null +++ b/web/src/views/backend/login.vue @@ -0,0 +1,284 @@ + + + + + diff --git a/web/src/views/backend/module/components/buy.vue b/web/src/views/backend/module/components/buy.vue new file mode 100644 index 0000000..7123aeb --- /dev/null +++ b/web/src/views/backend/module/components/buy.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/web/src/views/backend/module/components/commonDialog.vue b/web/src/views/backend/module/components/commonDialog.vue new file mode 100644 index 0000000..f626756 --- /dev/null +++ b/web/src/views/backend/module/components/commonDialog.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/web/src/views/backend/module/components/commonDone.vue b/web/src/views/backend/module/components/commonDone.vue new file mode 100644 index 0000000..a38afaa --- /dev/null +++ b/web/src/views/backend/module/components/commonDone.vue @@ -0,0 +1,288 @@ + + + + + diff --git a/web/src/views/backend/module/components/commonSelectVersion.vue b/web/src/views/backend/module/components/commonSelectVersion.vue new file mode 100644 index 0000000..54fd514 --- /dev/null +++ b/web/src/views/backend/module/components/commonSelectVersion.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/web/src/views/backend/module/components/confirmFileConflict.vue b/web/src/views/backend/module/components/confirmFileConflict.vue new file mode 100644 index 0000000..8f7f26e --- /dev/null +++ b/web/src/views/backend/module/components/confirmFileConflict.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/web/src/views/backend/module/components/goodsInfo.vue b/web/src/views/backend/module/components/goodsInfo.vue new file mode 100644 index 0000000..d483d27 --- /dev/null +++ b/web/src/views/backend/module/components/goodsInfo.vue @@ -0,0 +1,610 @@ + + + + + diff --git a/web/src/views/backend/module/components/installConflict.vue b/web/src/views/backend/module/components/installConflict.vue new file mode 100644 index 0000000..72f8628 --- /dev/null +++ b/web/src/views/backend/module/components/installConflict.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/web/src/views/backend/module/components/pay.vue b/web/src/views/backend/module/components/pay.vue new file mode 100644 index 0000000..9dc386a --- /dev/null +++ b/web/src/views/backend/module/components/pay.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/web/src/views/backend/module/components/tableHeader.vue b/web/src/views/backend/module/components/tableHeader.vue new file mode 100644 index 0000000..8fdc46a --- /dev/null +++ b/web/src/views/backend/module/components/tableHeader.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/web/src/views/backend/module/components/tabs.vue b/web/src/views/backend/module/components/tabs.vue new file mode 100644 index 0000000..bc4694d --- /dev/null +++ b/web/src/views/backend/module/components/tabs.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/web/src/views/backend/module/components/uploadInstall.vue b/web/src/views/backend/module/components/uploadInstall.vue new file mode 100644 index 0000000..67a4513 --- /dev/null +++ b/web/src/views/backend/module/components/uploadInstall.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/web/src/views/backend/module/index.ts b/web/src/views/backend/module/index.ts new file mode 100644 index 0000000..9ff0d07 --- /dev/null +++ b/web/src/views/backend/module/index.ts @@ -0,0 +1,604 @@ +import { ElNotification } from 'element-plus' +import { isArray } from 'lodash-es' +import { state } from './store' +import { moduleInstallState, type moduleState } from './types' +import { + changeState, + createOrder, + getInstallState, + index, + info, + modules, + payCheck, + payOrder, + postInstallModule, + preDownload, +} from '/@/api/backend/module' +import { i18n } from '/@/lang/index' +import router from '/@/router/index' +import { useBaAccount } from '/@/stores/baAccount' +import { SYSTEM_ZINDEX } from '/@/stores/constant/common' +import { taskStatus } from '/@/stores/constant/terminalTaskStatus' +import type { UserInfo } from '/@/stores/interface' +import { useTerminal } from '/@/stores/terminal' +import { fullUrl } from '/@/utils/common' +import { uuid } from '/@/utils/random' +import { changeListenDirtyFileSwitch, closeHotUpdate } from '/@/utils/vite' + +export const loadData = () => { + state.loading.table = true + if (!state.table.indexLoaded) { + loadIndex().then(() => { + getModules() + }) + } else { + getModules() + } +} + +export const onRefreshTableData = () => { + state.table.indexLoaded = false + for (const key in state.table.modulesEbak) { + state.table.modulesEbak[key] = undefined + } + loadData() +} + +const loadIndex = () => { + return index().then((res) => { + state.table.indexLoaded = true + state.sysVersion = res.data.sysVersion + state.nuxtVersion = res.data.nuxtVersion + state.installedModule = res.data.installed + + const installedModuleUids: string[] = [] + const installedModuleVersions: { uid: string; version: string }[] = [] + if (res.data.installed) { + state.installedModule.forEach((item) => { + installedModuleUids.push(item.uid) + installedModuleVersions.push({ + uid: item.uid, + version: item.version, + }) + }) + state.installedModuleUids = installedModuleUids + state.installedModuleVersions = installedModuleVersions + } + }) +} + +const getModules = () => { + if (typeof state.table.modulesEbak[state.table.params.activeTab] != 'undefined') { + state.table.modules[state.table.params.activeTab] = modulesOnlyLocalHandle(state.table.modulesEbak[state.table.params.activeTab]) + state.loading.table = false + return + } + const params: anyObj = {} + for (const key in state.table.params) { + if (state.table.params[key] != '') { + params[key] = state.table.params[key] + } + } + const moduleUids: string[] = [] + params['installed'] = state.installedModuleVersions + params['sysVersion'] = state.sysVersion + modules(params) + .then((res) => { + if (params.activeTab == 'all') { + res.data.rows.forEach((item: anyObj) => { + moduleUids.push(item.uid) + }) + + state.installedModule.forEach((item) => { + if (moduleUids.indexOf(item.uid) === -1) { + if (state.table.params.quickSearch) { + if (item.title.includes(state.table.params.quickSearch)) res.data.rows.push(item) + } else { + res.data.rows.push(item) + } + } + }) + } + + state.table.remark = res.data.remark + state.table.modulesEbak[params.activeTab] = res.data.rows.map((item: anyObj) => { + const idx = state.installedModuleUids.indexOf(item.uid) + if (idx !== -1) { + item.state = state.installedModule[idx].state + item.title = state.installedModule[idx].title + item.version = state.installedModule[idx].version + item.website = state.installedModule[idx].website + item.stateTag = moduleStatus(item.state) + + if (!isArray(item.tags)) item.tags = [] + item.tags.push({ + name: `${i18n.global.t('module.installed')} v${state.installedModule[idx].version}`, + type: 'primary', + }) + } else { + item.state = 0 + } + + if (item.new_version && item.tags) { + item.tags.push({ + name: i18n.global.t('module.New version'), + type: 'danger', + }) + } + + return item + }) + state.table.modules[params.activeTab] = modulesOnlyLocalHandle(state.table.modulesEbak[params.activeTab]) + state.table.category = res.data.category + }) + .finally(() => { + state.loading.table = false + }) +} + +export const showInfo = (uid: string) => { + state.dialog.goodsInfo = true + state.loading.goodsInfo = true + + const localItem = state.installedModule.find((item) => { + return item.uid == uid + }) + + info({ + uid: uid, + localVersion: localItem?.version, + sysVersion: state.sysVersion, + }) + .then((res) => { + if (localItem) { + if (res.data.info.type == 'local') { + res.data.info = localItem + res.data.info.images = [fullUrl('/static/images/local-module-logo.png')] + res.data.info.type = 'local' // 纯本地模块 + } else { + res.data.info.type = 'online' + res.data.info.state = localItem.state + res.data.info.version = localItem.version + } + res.data.info.enable = localItem.state === moduleInstallState.DISABLE ? false : true + } else { + res.data.info.state = 0 + res.data.info.type = 'online' + } + state.goodsInfo = res.data.info + }) + .catch((err) => { + if (loginExpired(err)) { + state.dialog.goodsInfo = false + } + }) + .finally(() => { + state.loading.goodsInfo = false + }) +} + +/** + * 支付订单 + * @param renew 是否是续费订单 + */ +export const onBuy = (renew = false) => { + state.dialog.buy = true + state.loading.buy = true + createOrder({ + goods_id: state.goodsInfo.id, + }) + .then((res) => { + state.loading.buy = false + state.buy.renew = renew + state.buy.info = res.data.info + }) + .catch((err) => { + state.dialog.buy = false + state.loading.buy = false + loginExpired(err) + }) +} + +export const onPay = (payType: 'score' | 'wx' | 'balance' | 'zfb') => { + state.common.payType = payType + state.loading.common = true + payOrder(state.buy.info.id, payType) + .then((res) => { + // 关闭其他弹窗 + state.dialog.buy = false + state.dialog.goodsInfo = false + + if (payType == 'wx' || payType == 'zfb') { + // 显示支付二维码 + state.dialog.pay = true + state.payInfo = res.data + + // 轮询获取支付状态 + const timer = setInterval(() => { + payCheck(state.payInfo.info.sn) + .then(() => { + state.payInfo.pay.status = 'success' + clearInterval(timer) + if (state.buy.renew) { + showInfo(res.data.info.uid) + } else { + onPreInstallModule(res.data.info.uid, res.data.info.id, true) + } + state.dialog.pay = false + }) + .catch(() => {}) + }, 3000) + } else { + if (state.buy.renew) { + showInfo(res.data.info.uid) + } else { + onPreInstallModule(res.data.info.uid, res.data.info.id, true) + } + } + }) + .catch((err) => { + loginExpired(err) + }) + .finally(() => { + state.loading.common = false + }) +} + +export const showCommonLoading = (loadingTitle: moduleState['common']['loadingTitle']) => { + state.common.type = 'loading' + state.common.loadingTitle = loadingTitle + state.common.loadingComponentKey = uuid() +} + +/** + * 模块预安装 + */ +export const onPreInstallModule = (uid: string, id: number, needGetInstallableVersion: boolean, update: boolean = false) => { + state.dialog.common = true + showCommonLoading('init') + state.common.dialogTitle = i18n.global.t('module.Install') + + const nextStep = (moduleState: number) => { + if (needGetInstallableVersion) { + // 获取模块版本列表 + showCommonLoading('getInstallableVersion') + preDownload({ + uid, + orderId: id, + sysVersion: state.sysVersion, + nuxtVersion: state.nuxtVersion, + installed: state.installedModuleUids, + }) + .then((res) => { + state.common.uid = uid + state.common.update = update + state.common.type = 'selectVersion' + state.common.dialogTitle = i18n.global.t('module.Select Version') + state.common.versions = res.data.versions + + // 关闭其他弹窗 + state.dialog.baAccount = false + state.dialog.buy = false + state.dialog.goodsInfo = false + }) + .catch((res) => { + if (loginExpired(res)) return + state.dialog.common = false + }) + } else { + // 立即安装(上传安装、继续安装) + showCommonLoading(moduleState === moduleInstallState.UNINSTALLED ? 'download' : 'install') + execInstall(uid, id, '', update) + + // 关闭其他弹窗 + state.dialog.baAccount = false + state.dialog.buy = false + state.dialog.goodsInfo = false + } + } + + if (update) { + nextStep(moduleInstallState.DISABLE) + } else { + // 获取安装状态 + getInstallState(uid).then((res) => { + if ( + res.data.state === moduleInstallState.INSTALLED || + res.data.state === moduleInstallState.DISABLE || + res.data.state === moduleInstallState.DIRECTORY_OCCUPIED + ) { + ElNotification({ + type: 'error', + message: + res.data.state === moduleInstallState.INSTALLED || res.data.state === moduleInstallState.DISABLE + ? i18n.global.t('module.Installation cancelled because module already exists!') + : i18n.global.t('module.Installation cancelled because the directory required by the module is occupied!'), + }) + state.dialog.common = false + return + } + + nextStep(res.data.state) + }) + } +} + +/** + * 执行安装请求,还包含启用、安装时的冲突处理 + */ +export const execInstall = (uid: string, id: number, version: string = '', update: boolean = false, extend: anyObj = {}) => { + postInstallModule(uid, id, version, update, extend) + .then(() => { + state.common.dialogTitle = i18n.global.t('module.Installation complete') + state.common.moduleState = moduleInstallState.INSTALLED + state.common.type = 'done' + onRefreshTableData() + }) + .catch((res) => { + if (loginExpired(res)) return + if (res.code == -1) { + state.common.uid = res.data.uid + state.common.type = 'installConflict' + state.common.dialogTitle = i18n.global.t('module.A conflict is found Please handle it manually') + state.common.fileConflict = res.data.fileConflict + state.common.dependConflict = res.data.dependConflict + } else if (res.code == -2) { + state.common.type = 'done' + state.common.uid = res.data.uid + state.common.dialogTitle = i18n.global.t('module.Wait for dependent installation') + state.common.moduleState = moduleInstallState.DEPENDENT_WAIT_INSTALL + state.common.waitInstallDepend = res.data.wait_install + state.common.dependInstallState = 'executing' + const terminal = useTerminal() + if (res.data.wait_install.includes('npm_dependent_wait_install')) { + terminal.addTaskPM('web-install', true, 'module-install:' + res.data.uid, (res: number) => { + terminalTaskExecComplete(res, 'npm_dependent_wait_install') + }) + } + if (res.data.wait_install.includes('nuxt_npm_dependent_wait_install')) { + terminal.addTaskPM('nuxt-install', true, 'module-install:' + res.data.uid, (res: number) => { + terminalTaskExecComplete(res, 'nuxt_npm_dependent_wait_install') + }) + } + if (res.data.wait_install.includes('composer_dependent_wait_install')) { + terminal.addTask('composer.update', true, 'module-install:' + res.data.uid, (res: number) => { + terminalTaskExecComplete(res, 'composer_dependent_wait_install') + }) + } + } else if (res.code == 0) { + ElNotification({ + type: 'error', + message: res.msg, + zIndex: SYSTEM_ZINDEX, + }) + state.dialog.common = false + onRefreshTableData() + } + }) + .finally(() => { + state.loading.common = false + }) +} + +const terminalTaskExecComplete = (res: number, type: string) => { + if (res == taskStatus.Success) { + state.common.waitInstallDepend = state.common.waitInstallDepend.filter((depend: string) => { + return depend != type + }) + if (state.common.waitInstallDepend.length == 0) { + state.common.dependInstallState = 'success' + + // 仅在命令全部执行完毕才刷新数据 + if (router.currentRoute.value.name === 'moduleStore/moduleStore') { + onRefreshTableData() + } + } + } else { + const terminal = useTerminal() + terminal.toggle(true) + state.common.dependInstallState = 'fail' + + // 有命令执行失败了,刷新一次数据 + if (router.currentRoute.value.name === 'moduleStore/moduleStore') { + onRefreshTableData() + } + } + + // 连续安装模块的情况中,首个模块的命令执行完毕时,自动启动了热更新 + if (router.currentRoute.value.name === 'moduleStore/moduleStore') { + closeHotUpdate('modules') + } +} + +export const onDisable = (confirmConflict = false) => { + state.loading.common = true + + // 拼装依赖处理方案 + if (confirmConflict) { + const dependConflict: anyObj = {} + for (const key in state.common.disableDependConflict) { + if (state.common.disableDependConflict[key]['solution'] != 'delete') { + continue + } + if (typeof dependConflict[state.common.disableDependConflict[key].env] == 'undefined') { + dependConflict[state.common.disableDependConflict[key].env] = [] + } + dependConflict[state.common.disableDependConflict[key].env].push(state.common.disableDependConflict[key].depend) + } + state.common.disableParams['confirmConflict'] = 1 + state.common.disableParams['dependConflictSolution'] = dependConflict + } + + changeState(state.common.disableParams) + .then(() => { + ElNotification({ + type: 'success', + message: i18n.global.t('module.The operation succeeds Please clear the system cache and refresh the browser ~'), + zIndex: SYSTEM_ZINDEX, + }) + state.dialog.common = false + onRefreshTableData() + }) + .catch((res) => { + if (res.code == -1) { + state.dialog.common = true + state.common.dialogTitle = i18n.global.t('module.Deal with conflict') + state.common.type = 'disableConfirmConflict' + state.common.disableDependConflict = res.data.dependConflict + if (res.data.conflictFile && res.data.conflictFile.length) { + const conflictFile = [] + for (const key in res.data.conflictFile) { + conflictFile.push({ + file: res.data.conflictFile[key], + }) + } + state.common.disableConflictFile = conflictFile + } + } else if (res.code == -2) { + state.dialog.common = true + const commandsData = { + type: 'disable', + commands: res.data.wait_install, + } + state.common.uid = state.goodsInfo.uid + execCommand(commandsData) + } else if (res.code == -3) { + // 更新 + onPreInstallModule(state.goodsInfo.uid, state.goodsInfo.purchased, true, true) + } else { + ElNotification({ + type: 'error', + message: res.msg, + zIndex: SYSTEM_ZINDEX, + }) + if (state.common.disableParams && state.common.disableParams.uid) { + showInfo(state.common.disableParams.uid) + } else { + onRefreshTableData() + } + } + }) + .finally(() => { + state.loading.common = false + }) +} + +export const onEnable = (uid: string) => { + state.loading.common = true + changeState({ + uid: uid, + state: 1, + }) + .then(() => { + state.dialog.common = true + showCommonLoading('init') + state.common.dialogTitle = i18n.global.t('Enable') + + execInstall(uid, 0) + state.dialog.goodsInfo = false + }) + .catch((res) => { + ElNotification({ + type: 'error', + message: res.msg, + zIndex: SYSTEM_ZINDEX, + }) + state.loading.common = false + }) +} + +export const loginExpired = (res: ApiResponse) => { + const baAccount = useBaAccount() + if (res.code == 301 || res.code == 408) { + baAccount.removeToken() + state.dialog.baAccount = true + return true + } + return false +} + +const modulesOnlyLocalHandle = (modules: anyObj) => { + if (!state.table.onlyLocal) return modules + return modules.filter((item: anyObj) => { + return item.installed + }) +} + +export const execCommand = (data: anyObj) => { + if (data.type == 'disable') { + state.dialog.common = true + state.common.type = 'done' + state.common.dialogTitle = i18n.global.t('module.Wait for dependent installation') + state.common.moduleState = moduleInstallState.DISABLE + state.common.dependInstallState = 'executing' + const terminal = useTerminal() + data.commands.forEach((item: anyObj) => { + state.common.waitInstallDepend.push(item.type) + if (item.pm) { + if (item.command == 'web-install') { + changeListenDirtyFileSwitch(false) + } + terminal.addTaskPM(item.command, true, '', (res: number) => { + terminalTaskExecComplete(res, item.type) + if (item.command == 'web-install') { + changeListenDirtyFileSwitch(true) + } + }) + } else { + terminal.addTask(item.command, true, '', (res: number) => { + terminalTaskExecComplete(res, item.type) + }) + } + }) + } +} + +export const specificUserName = (userInfo: Partial) => { + return userInfo.nickname + '(' + (userInfo.email || userInfo.mobile || 'ID:' + userInfo.id) + ')' +} + +export const currency = (price: number, val: number) => { + if (typeof price == 'undefined' || typeof val == 'undefined') { + return '-' + } + if (val == 0) { + return parseInt(price.toString()) + i18n.global.t('Integral') + } else { + return '¥' + price + } +} + +export const moduleStatus = (state: number) => { + switch (state) { + case moduleInstallState.INSTALLED: + return { + type: '', + text: i18n.global.t('module.installed'), + } + case moduleInstallState.WAIT_INSTALL: + return { + type: 'success', + text: i18n.global.t('module.Wait for installation'), + } + case moduleInstallState.CONFLICT_PENDING: + return { + type: 'danger', + text: i18n.global.t('module.Conflict pending'), + } + case moduleInstallState.DEPENDENT_WAIT_INSTALL: + return { + type: 'warning', + text: i18n.global.t('module.Dependency to be installed'), + } + case moduleInstallState.DISABLE: + return { + type: 'warning', + text: i18n.global.t('Disable'), + } + default: + return { + type: 'info', + text: i18n.global.t('Unknown'), + } + } +} diff --git a/web/src/views/backend/module/index.vue b/web/src/views/backend/module/index.vue new file mode 100644 index 0000000..fde6ad7 --- /dev/null +++ b/web/src/views/backend/module/index.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/web/src/views/backend/module/store.ts b/web/src/views/backend/module/store.ts new file mode 100644 index 0000000..4215a92 --- /dev/null +++ b/web/src/views/backend/module/store.ts @@ -0,0 +1,63 @@ +import { reactive } from 'vue' +import { uuid } from '/@/utils/random' +import type { moduleState } from './types' + +export const state = reactive({ + loading: { + buy: false, + table: true, + common: false, + install: false, + goodsInfo: false, + }, + dialog: { + buy: false, + pay: false, + common: false, + goodsInfo: false, + baAccount: false, + }, + table: { + remark: '', + modules: [], + modulesEbak: [], + category: [], + onlyLocal: false, + indexLoaded: false, + params: { + quickSearch: '', + activeTab: 'all', + }, + }, + payInfo: {}, + goodsInfo: {}, + buy: { + info: {}, + renew: false, + agreement: true, + }, + common: { + uid: '', + moduleState: 0, + quickClose: false, + type: 'loading', + dialogTitle: '', + fileConflict: [], + dependConflict: [], + loadingTitle: 'init', + loadingComponentKey: uuid(), + waitInstallDepend: [], + dependInstallState: 'none', + disableConflictFile: [], + disableDependConflict: [], + disableParams: {}, + payType: 'wx', + update: false, + versions: [], + }, + sysVersion: '', + nuxtVersion: '', + installedModule: [], + installedModuleUids: [], + installedModuleVersions: [], +}) diff --git a/web/src/views/backend/module/types.ts b/web/src/views/backend/module/types.ts new file mode 100644 index 0000000..d32a4c1 --- /dev/null +++ b/web/src/views/backend/module/types.ts @@ -0,0 +1,78 @@ +export enum moduleInstallState { + UNINSTALLED, + INSTALLED, + WAIT_INSTALL, + CONFLICT_PENDING, + DEPENDENT_WAIT_INSTALL, + DIRECTORY_OCCUPIED, + DISABLE, +} + +export interface moduleInfo { + uid: string + title: string + version: string + state: number + website: string + stateTag: { + type: string + text: string + } +} + +export interface moduleState { + loading: { + buy: boolean + table: boolean + common: boolean + install: boolean + goodsInfo: boolean + } + dialog: { + buy: boolean + pay: boolean + common: boolean + goodsInfo: boolean + baAccount: boolean + } + table: { + remark: string + modules: anyObj + modulesEbak: anyObj + category: anyObj + onlyLocal: boolean + indexLoaded: boolean + params: anyObj + } + payInfo: anyObj + goodsInfo: anyObj + buy: { + info: anyObj + renew: boolean + agreement: boolean + } + common: { + uid: string + moduleState: number + quickClose: boolean + type: 'loading' | 'installConflict' | 'done' | 'disableConfirmConflict' | 'uploadInstall' | 'selectVersion' + dialogTitle: string + fileConflict: anyObj[] + dependConflict: anyObj[] + loadingTitle: 'init' | 'download' | 'install' | 'getInstallableVersion' + loadingComponentKey: string + waitInstallDepend: string[] + dependInstallState: 'none' | 'executing' | 'success' | 'fail' + disableConflictFile: { file: string }[] + disableDependConflict: anyObj[] + disableParams: anyObj + payType: 'score' | 'wx' | 'balance' | 'zfb' + update: boolean + versions: anyObj[] + } + sysVersion: string + nuxtVersion: string + installedModule: moduleInfo[] + installedModuleUids: string[] + installedModuleVersions: { uid: string; version: string }[] +} diff --git a/web/src/views/backend/routine/adminInfo.vue b/web/src/views/backend/routine/adminInfo.vue new file mode 100644 index 0000000..3d97ece --- /dev/null +++ b/web/src/views/backend/routine/adminInfo.vue @@ -0,0 +1,297 @@ + + + + + diff --git a/web/src/views/backend/routine/attachment/index.ts b/web/src/views/backend/routine/attachment/index.ts new file mode 100644 index 0000000..92e18be --- /dev/null +++ b/web/src/views/backend/routine/attachment/index.ts @@ -0,0 +1,12 @@ +import { buildSuffixSvgUrl } from '/@/api/common' + +/** + * 表格和表单中文件预览图的生成 + */ +export const previewRenderFormatter = (row: TableRow, column: TableColumn, cellValue: string) => { + const imgSuffix = ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'] + if (imgSuffix.includes(cellValue)) { + return row.full_url + } + return buildSuffixSvgUrl(cellValue) +} diff --git a/web/src/views/backend/routine/attachment/index.vue b/web/src/views/backend/routine/attachment/index.vue new file mode 100644 index 0000000..e279069 --- /dev/null +++ b/web/src/views/backend/routine/attachment/index.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/web/src/views/backend/routine/attachment/popupForm.vue b/web/src/views/backend/routine/attachment/popupForm.vue new file mode 100644 index 0000000..6fe3ba6 --- /dev/null +++ b/web/src/views/backend/routine/attachment/popupForm.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/web/src/views/backend/routine/config/add.vue b/web/src/views/backend/routine/config/add.vue new file mode 100644 index 0000000..bef6f21 --- /dev/null +++ b/web/src/views/backend/routine/config/add.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/web/src/views/backend/routine/config/index.vue b/web/src/views/backend/routine/config/index.vue new file mode 100644 index 0000000..f3452f3 --- /dev/null +++ b/web/src/views/backend/routine/config/index.vue @@ -0,0 +1,369 @@ + + + + + diff --git a/web/src/views/backend/security/dataRecycle/index.vue b/web/src/views/backend/security/dataRecycle/index.vue new file mode 100644 index 0000000..6ff57e4 --- /dev/null +++ b/web/src/views/backend/security/dataRecycle/index.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/web/src/views/backend/security/dataRecycle/popupForm.vue b/web/src/views/backend/security/dataRecycle/popupForm.vue new file mode 100644 index 0000000..2f32c24 --- /dev/null +++ b/web/src/views/backend/security/dataRecycle/popupForm.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/web/src/views/backend/security/dataRecycleLog/index.vue b/web/src/views/backend/security/dataRecycleLog/index.vue new file mode 100644 index 0000000..99dd328 --- /dev/null +++ b/web/src/views/backend/security/dataRecycleLog/index.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/web/src/views/backend/security/dataRecycleLog/info.vue b/web/src/views/backend/security/dataRecycleLog/info.vue new file mode 100644 index 0000000..2bfab75 --- /dev/null +++ b/web/src/views/backend/security/dataRecycleLog/info.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/web/src/views/backend/security/sensitiveData/index.ts b/web/src/views/backend/security/sensitiveData/index.ts new file mode 100644 index 0000000..9cab58a --- /dev/null +++ b/web/src/views/backend/security/sensitiveData/index.ts @@ -0,0 +1,113 @@ +import baTableClass from '/@/utils/baTable' +import type { baTableApi } from '/@/api/common' +import { getTableFieldList } from '/@/api/common' +import { add } from '/@/api/backend/security/sensitiveData' +import { uuid } from '/@/utils/random' + +export interface DataFields { + name: string + value: string +} + +export class sensitiveDataClass extends baTableClass { + constructor(api: baTableApi, table: BaTable, form: BaTableForm = {}, before: BaTableBefore = {}, after: BaTableAfter = {}) { + super(api, table, form, before, after) + } + + // 重写编辑 + getEditData = (id: string) => { + this.form.loading = true + this.form.items = {} + return this.api.edit({ id: id }).then((res) => { + const fields: string[] = [] + const dataFields: DataFields[] = [] + for (const key in res.data.row.data_fields) { + fields.push(key) + dataFields.push({ + name: key, + value: res.data.row.data_fields[key] ?? '', + }) + } + + this.form.items!.connection = res.data.row.connection ? res.data.row.connection : '' + this.form.extend!.controllerList = res.data.controllers + + if (res.data.row.data_table) { + this.onTableChange(res.data.row.data_table) + if (this.form.extend!.parentRef) this.form.extend!.parentRef.setDataFields(dataFields) + } + + res.data.row.data_fields = fields + this.form.loading = false + this.form.items = res.data.row + }) + } + + onConnectionChange = () => { + this.form.extend!.fieldList = {} + this.form.extend!.fieldSelect = {} + this.form.extend!.fieldSelectKey = uuid() + + this.form.items!.data_table = '' + this.form.items!.data_fields = [] + if (this.form.extend!.parentRef) this.form.extend!.parentRef.setDataFields([]) + } + + // 数据表改变事件 + onTableChange = (table: string) => { + this.form.extend = Object.assign(this.form.extend!, { + fieldLoading: true, + fieldList: {}, + fieldSelect: {}, + fieldSelectKey: uuid(), + }) + + this.form.items!.data_fields = [] + if (this.form.extend!.parentRef) this.form.extend!.parentRef.setDataFields([]) + + getTableFieldList(table, true, this.form.items!.connection).then((res) => { + this.form.items!.primary_key = res.data.pk + this.form.defaultItems!.primary_key = res.data.pk + + const fieldSelect: anyObj = {} + for (const key in res.data.fieldList) { + fieldSelect[key] = (key ? key + ' - ' : '') + res.data.fieldList[key] + } + + this.form.extend = Object.assign(this.form.extend!, { + fieldLoading: false, + fieldList: res.data.fieldList, + fieldSelect: fieldSelect, + fieldSelectKey: uuid(), + }) + }) + } + + /** + * 重写打开表单方法 + */ + toggleForm = (operate = '', operateIds: string[] = []) => { + if (this.form.ref) { + this.form.ref.resetFields() + } + + if (this.form.extend!.parentRef) this.form.extend!.parentRef.setDataFields([]) + + if (operate == 'Edit') { + if (!operateIds.length) { + return false + } + this.getEditData(operateIds[0]) + } else if (operate == 'Add') { + this.form.loading = true + add().then((res) => { + this.form.extend!.controllerList = res.data.controllers + this.form.items = Object.assign({}, this.form.defaultItems) + this.form.loading = false + }) + } + + this.form.operate = operate + this.form.operateIds = operateIds + } +} diff --git a/web/src/views/backend/security/sensitiveData/index.vue b/web/src/views/backend/security/sensitiveData/index.vue new file mode 100644 index 0000000..ed102ca --- /dev/null +++ b/web/src/views/backend/security/sensitiveData/index.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/web/src/views/backend/security/sensitiveData/popupForm.vue b/web/src/views/backend/security/sensitiveData/popupForm.vue new file mode 100644 index 0000000..82fbd22 --- /dev/null +++ b/web/src/views/backend/security/sensitiveData/popupForm.vue @@ -0,0 +1,229 @@ + + + + + diff --git a/web/src/views/backend/security/sensitiveDataLog/index.vue b/web/src/views/backend/security/sensitiveDataLog/index.vue new file mode 100644 index 0000000..83d3d64 --- /dev/null +++ b/web/src/views/backend/security/sensitiveDataLog/index.vue @@ -0,0 +1,229 @@ + + + + + diff --git a/web/src/views/backend/security/sensitiveDataLog/info.vue b/web/src/views/backend/security/sensitiveDataLog/info.vue new file mode 100644 index 0000000..03e0408 --- /dev/null +++ b/web/src/views/backend/security/sensitiveDataLog/info.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/web/src/views/backend/user/group/index.vue b/web/src/views/backend/user/group/index.vue new file mode 100644 index 0000000..27110de --- /dev/null +++ b/web/src/views/backend/user/group/index.vue @@ -0,0 +1,155 @@ + + + + + diff --git a/web/src/views/backend/user/group/popupForm.vue b/web/src/views/backend/user/group/popupForm.vue new file mode 100644 index 0000000..f60742e --- /dev/null +++ b/web/src/views/backend/user/group/popupForm.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/web/src/views/backend/user/moneyLog/index.vue b/web/src/views/backend/user/moneyLog/index.vue new file mode 100644 index 0000000..b620f7f --- /dev/null +++ b/web/src/views/backend/user/moneyLog/index.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/web/src/views/backend/user/moneyLog/popupForm.vue b/web/src/views/backend/user/moneyLog/popupForm.vue new file mode 100644 index 0000000..50570b4 --- /dev/null +++ b/web/src/views/backend/user/moneyLog/popupForm.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/web/src/views/backend/user/rule/index.vue b/web/src/views/backend/user/rule/index.vue new file mode 100644 index 0000000..f631ff8 --- /dev/null +++ b/web/src/views/backend/user/rule/index.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/web/src/views/backend/user/rule/popupForm.vue b/web/src/views/backend/user/rule/popupForm.vue new file mode 100644 index 0000000..9343f12 --- /dev/null +++ b/web/src/views/backend/user/rule/popupForm.vue @@ -0,0 +1,237 @@ + + + + + diff --git a/web/src/views/backend/user/scoreLog/index.vue b/web/src/views/backend/user/scoreLog/index.vue new file mode 100644 index 0000000..676eaa8 --- /dev/null +++ b/web/src/views/backend/user/scoreLog/index.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/web/src/views/backend/user/scoreLog/popupForm.vue b/web/src/views/backend/user/scoreLog/popupForm.vue new file mode 100644 index 0000000..0f54c04 --- /dev/null +++ b/web/src/views/backend/user/scoreLog/popupForm.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/web/src/views/backend/user/user/index.vue b/web/src/views/backend/user/user/index.vue new file mode 100644 index 0000000..a55b23b --- /dev/null +++ b/web/src/views/backend/user/user/index.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/web/src/views/backend/user/user/popupForm.vue b/web/src/views/backend/user/user/popupForm.vue new file mode 100644 index 0000000..48850fd --- /dev/null +++ b/web/src/views/backend/user/user/popupForm.vue @@ -0,0 +1,238 @@ + + + + + diff --git a/web/src/views/common/error/401.vue b/web/src/views/common/error/401.vue new file mode 100644 index 0000000..625b22e --- /dev/null +++ b/web/src/views/common/error/401.vue @@ -0,0 +1,79 @@ + + + diff --git a/web/src/views/common/error/404.vue b/web/src/views/common/error/404.vue new file mode 100644 index 0000000..7045129 --- /dev/null +++ b/web/src/views/common/error/404.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/web/src/views/frontend/index.vue b/web/src/views/frontend/index.vue new file mode 100644 index 0000000..f32cfe4 --- /dev/null +++ b/web/src/views/frontend/index.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/web/src/views/frontend/user/account/balance.vue b/web/src/views/frontend/user/account/balance.vue new file mode 100644 index 0000000..f3fb1b0 --- /dev/null +++ b/web/src/views/frontend/user/account/balance.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/web/src/views/frontend/user/account/changePassword.vue b/web/src/views/frontend/user/account/changePassword.vue new file mode 100644 index 0000000..4086002 --- /dev/null +++ b/web/src/views/frontend/user/account/changePassword.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/web/src/views/frontend/user/account/integral.vue b/web/src/views/frontend/user/account/integral.vue new file mode 100644 index 0000000..00fcdd4 --- /dev/null +++ b/web/src/views/frontend/user/account/integral.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/web/src/views/frontend/user/account/overview.vue b/web/src/views/frontend/user/account/overview.vue new file mode 100644 index 0000000..5dcf41d --- /dev/null +++ b/web/src/views/frontend/user/account/overview.vue @@ -0,0 +1,299 @@ + + + + + diff --git a/web/src/views/frontend/user/account/profile.vue b/web/src/views/frontend/user/account/profile.vue new file mode 100644 index 0000000..b2e1fa4 --- /dev/null +++ b/web/src/views/frontend/user/account/profile.vue @@ -0,0 +1,533 @@ + + + + + diff --git a/web/src/views/frontend/user/login.vue b/web/src/views/frontend/user/login.vue new file mode 100644 index 0000000..29f891c --- /dev/null +++ b/web/src/views/frontend/user/login.vue @@ -0,0 +1,590 @@ + + + + + diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 0000000..7b52b4a --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "useDefineForClassFields": true, + "moduleResolution": "Bundler", + "strict": true, + "jsx": "preserve", + "sourceMap": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "isolatedModules": true, + "baseUrl": "./", + "allowJs": true, + "skipLibCheck": true, + "paths": { + "/@/*": ["src/*"] + }, + "types": ["vite/client", "element-plus/global"] + }, + "include": ["src/**/*.ts", "src/**/*.vue", "types/**/*.d.ts", "vite.config.ts"] +} diff --git a/web/types/global.d.ts b/web/types/global.d.ts new file mode 100644 index 0000000..85c9e97 --- /dev/null +++ b/web/types/global.d.ts @@ -0,0 +1,30 @@ +interface Window { + existLoading: boolean + lazy: number + unique: number + tokenRefreshing: boolean + requests: Function[] + eventSource: EventSource + loadLangHandle: Record +} + +interface anyObj { + [key: string]: any +} + +interface TableDefaultData { + list: T + remark: string + total: number +} + +interface ApiResponse { + code: number + data: T + msg: string + time: number +} + +type ApiPromise = Promise> + +type Writeable = { -readonly [P in keyof T]: T[P] } diff --git a/web/types/module.d.ts b/web/types/module.d.ts new file mode 100644 index 0000000..88a1545 --- /dev/null +++ b/web/types/module.d.ts @@ -0,0 +1,8 @@ +/// + +declare module '*.vue' { + import { DefineComponent } from 'vue' + // eslint-disable-next-line @typescript-eslint/no-empty-object-type + const component: DefineComponent<{}, {}, any> + export default component +} diff --git a/web/types/table.d.ts b/web/types/table.d.ts new file mode 100644 index 0000000..703aeee --- /dev/null +++ b/web/types/table.d.ts @@ -0,0 +1,519 @@ +import type { + ButtonProps, + ButtonType, + ColProps, + ElTooltipProps, + FormInstance, + ImageProps, + PopconfirmProps, + SwitchProps, + TableColumnCtx, + TagProps, +} from 'element-plus' +import type { Component, ComponentPublicInstance } from 'vue' +import Icon from '/@/components/icon/index.vue' +import Table from '/@/components/table/index.vue' + +declare global { + interface BaTable { + /** + * 表格数据,通过 baTable.getData 获取 + * 刷新数据可使用 baTable.onTableHeaderAction('refresh', { event: 'custom' }) + */ + data?: TableRow[] + + /** + * 表格列定义 + */ + column: TableColumn[] + + /** + * 获取表格数据时的过滤条件(含公共搜索、快速搜索、分页、排序等数据) + * 公共搜索数据可使用 baTable.setComSearchData 和 baTable.getComSearchData 进行管理 + */ + filter?: { + page?: number + limit?: number + order?: string + quickSearch?: string + search?: ComSearchData[] + [key: string]: any + } + + /** + * 不需要双击编辑的字段,type=selection 的列为 undefined + * 禁用全部列的双击编辑,可使用 ['all'] + */ + dblClickNotEditColumn?: (string | undefined)[] + + /** + * 表格扩展数据,随意定义,以便一些自定义数据可以随 baTable 实例传递 + */ + extend?: anyObj + + // 表格 ref,通常在 页面 onMounted 时赋值,可选的 + ref?: InstanceType | null + // 表格对应数据表的主键字段 + pk?: string + // 路由 remark,后台菜单规则备注信息 + remark?: string | null + // 表格加载状态 + loading?: boolean + // 当前选中行 + selection?: TableRow[] + // 数据总量 + total?: number + // 默认排序字段和排序方式 + defaultOrder?: { prop: string; order: string } + // 拖动排序限位字段,例如拖动行 pid=1,那么拖动目的行 pid 也需要为 1 + dragSortLimitField?: string + // 接受 url 的 query 参数并自动触发公共搜索 + acceptQuery?: boolean + // 显示公共搜索 + showComSearch?: boolean + // 是否展开所有子项,树状表格专用属性 + expandAll?: boolean + // 当前表格所在页面的路由 path + routePath?: string + } + + interface BaTableForm { + /** + * 当前表单项数据 + */ + items?: anyObj + + /** + * 当前操作标识:Add=添加,Edit=编辑 + */ + operate?: string + + /** + * 添加表单字段默认值,打开表单时会使用 cloneDeep 赋值给 this.form.items 对象 + */ + defaultItems?: anyObj + + /** + * 表单扩展数据,可随意定义,以便一些自定义数据可以随 baTable 实例传递 + */ + extend?: anyObj + + // 表单 ref,实例化表格时通常无需传递 + ref?: FormInstance | undefined + // 表单项 label 的宽度 + labelWidth?: number + // 被操作数据ID,支持批量编辑:add=[0],edit=[1,2,n] + operateIds?: string[] + // 提交按钮状态 + submitLoading?: boolean + // 表单加载状态 + loading?: boolean + } + + /** + * BaTable 前置处理函数(前置埋点) + */ + interface BaTableBefore { + /** + * 获取表格数据前的钩子(返回 false 可取消原操作) + */ + getData?: () => boolean | void + + /** + * 删除前的钩子(返回 false 可取消原操作) + * @param object.ids 被删除数据的主键集合 + */ + postDel?: ({ ids }: { ids: string[] }) => boolean | void + + /** + * 获取被编辑行数据前的钩子(返回 false 可取消原操作) + * @param object.id 被编辑行主键 + */ + getEditData?: ({ id }: { id: string }) => boolean | void + + /** + * 双击表格具体操作执行前钩子(返回 false 可取消原操作) + * @param object.row 被双击行数据 + * @param object.column 被双击列数据 + */ + onTableDblclick?: ({ row, column }: { row: TableRow; column: TableColumn }) => boolean | void + + /** + * 表单切换前钩子(返回 false 可取消默认行为) + * @param object.operate 当前操作标识:Add=添加,Edit=编辑 + * @param object.operateIds 被操作的行 ID 集合 + */ + toggleForm?: ({ operate, operateIds }: { operate: string; operateIds: string[] }) => boolean | void + + /** + * 表单提交前钩子(返回 false 可取消原操作) + * @param object.formEl 表单组件ref + * @param object.operate 当前操作标识:Add=添加,Edit=编辑 + * @param object.items 表单数据 + */ + onSubmit?: ({ formEl, operate, items }: { formEl?: FormInstance | null; operate: string; items: anyObj }) => boolean | void + + /** + * 表格内事件响应前钩子(返回 false 可取消原操作) + * @param object.event 事件名称 + * @param object.data 事件携带的数据 + */ + onTableAction?: ({ event, data }: { event: BaTableActionEventName; data: anyObj }) => boolean | void + + /** + * 表格顶部菜单事件响应前钩子(返回 false 可取消原操作) + * @param object.event 事件名称 + * @param object.data 事件携带的数据 + */ + onTableHeaderAction?: ({ event, data }: { event: BaTableHeaderActionEventName; data: anyObj }) => boolean | void + + /** + * 表格初始化前钩子 + */ + mount?: () => boolean | void + + /** getData 的别名 */ + getIndex?: () => boolean | void + /** getEditData 的别名 */ + requestEdit?: ({ id }: { id: string }) => boolean | void + + // 可自定义其他钩子 + [key: string]: Function | undefined + } + + /** + * BaTable 后置处理函数(后置埋点) + */ + interface BaTableAfter { + /** + * 请求到表格数据后钩子 + * 此时 baTable.table.data 已赋值 + * @param object.res 请求完整响应 + */ + getData?: ({ res }: { res: ApiResponse }) => void + + /** + * 删除请求后钩子 + * @param object.res 请求完整响应 + */ + postDel?: ({ res }: { res: ApiResponse }) => void + + /** + * 获取到编辑行数据后钩子 + * 此时 baTable.form.items 已赋值 + * @param object.res 请求完整响应 + */ + getEditData?: ({ res }: { res: ApiResponse }) => void + + /** + * 双击单元格操作执行后钩子 + * @param object.row 当前行数据 + * @param object.column 当前列数据 + */ + onTableDblclick?: ({ row, column }: { row: TableRow; column: TableColumn }) => void + + /** + * 表单切换后钩子 + * @param object.operate 当前操作标识:Add=添加,Edit=编辑 + * @param object.operateIds 被操作的 ID 集合 + */ + toggleForm?: ({ operate, operateIds }: { operate: string; operateIds: string[] }) => void + + /** + * 表单提交后钩子 + * @param object.res 请求完整响应 + */ + onSubmit?: ({ res }: { res: ApiResponse }) => void + + /** + * 表格内事件响应后钩子 + * @param object.event 事件名称 + * @param object.data 事件携带的数据 + */ + onTableAction?: ({ event, data }: { event: BaTableActionEventName; data: anyObj }) => void + + /** + * 表格顶部菜单事件响应后钩子 + * @param object.event 事件名称 + * @param object.data 事件携带的数据 + */ + onTableHeaderAction?: ({ event, data }: { event: BaTableHeaderActionEventName; data: anyObj }) => void + + /** getData 的别名 */ + getIndex?: ({ res }: { res: ApiResponse }) => void + /** getEditData 的别名 */ + requestEdit?: ({ res }: { res: ApiResponse }) => void + + // 可自定义其他钩子 + [key: string]: Function | undefined + } + + /** + * baTable 表格内事件名称 + * selection-change=选中项改变,page-size-change=每页数量改变,current-page-change=翻页,sort-change=排序,edit=编辑,delete=删除,field-change=单元格值改变,com-search=公共搜索 + */ + type BaTableActionEventName = + | 'selection-change' + | 'page-size-change' + | 'current-page-change' + | 'sort-change' + | 'edit' + | 'delete' + | 'field-change' + | 'com-search' + + /** + * baTable 表格头部事件名称 + * refresh=刷新,add=添加,edit=编辑,delete=删除,quick-search=快速查询,unfold=折叠/展开,change-show-column=调整列显示状态 + */ + type BaTableHeaderActionEventName = 'refresh' | 'add' | 'edit' | 'delete' | 'quick-search' | 'unfold' | 'change-show-column' + + /** + * 表格公共搜索数据 + */ + interface ComSearch { + /** 表单项数据 */ + form: anyObj + /** 字段搜索配置,搜索操作符(operator)、字段渲染方式(render)等 */ + fieldData: Map + } + + /** + * 表格列 + */ + interface TableColumn extends Partial> { + // 是否于表格显示此列 + show?: boolean + // 渲染器组件名,即 \src\components\table\fieldRender\ 中的组件之一,也可以查看 TableRenderer 类型定义 + render?: TableRenderer + // 值替换数据(字典数据),同时用于单元格渲染时和作为公共搜索下拉框数据,格式如:{ open: '开', close: '关', disable: '已禁用' } + replaceValue?: Record + + // render=slot 时,slot 的名称 + slotName?: string + // render=customRender 时,要渲染的组件或已注册组件名称的字符串 + customRender?: string | Component + // render=customTemplate 时,自定义渲染 html,应谨慎使用:请返回 html 内容,务必确保返回内容是 xss 安全的 + customTemplate?: (row: TableRow, field: TableColumn, value: any, column: TableColumnCtx, index: number) => string + // 渲染前对字段值的预处理函数(对 el-table 的 formatter 扩展) + formatter?: (row: TableRow, column: TableColumnCtx, cellValue: any, index: number) => any + + /** + * 自定义单元格渲染属性(比如单元格渲染器内部的 tag、button 组件的属性,设计上不仅是组件属性,也可以自定义其他渲染相关属性) + * 直接定义对应组件的属性 object,或使用一个函数返回组件属性 object + */ + customRenderAttr?: { + tag?: TableContextDataFun + icon?: TableContextDataFun['$props']> + image?: TableContextDataFun + switch?: TableContextDataFun + tooltip?: TableContextDataFun + [key: string]: any + } + + // render=tag 时,el-tag 组件的 effect + effect?: TagProps['effect'] + // render=tag 时,el-tag 组件的 size + size?: TagProps['size'] + // render=url 时,链接的打开方式 + target?: '_blank' | '_self' + // render=datetime 时,时间日期的格式化方式,字母可以自由组合:y=年,m=月,d=日,h=时,M=分,s=秒,默认:yyyy-mm-dd hh:MM:ss + timeFormat?: string + // render=buttons 时,操作按钮数组 + buttons?: OptButton[] + + /** + * 单元格渲染器需要的其他任意自定义数据 + * 1. render=tag 时,可单独指定每个不同的值 tag 的 type 属性 { open: 'success', close: 'info', disable: 'danger' } + */ + custom?: any + + // 默认值(单元格值为 undefined,null,'' 时取默认值,仅使用了 render 时有效) + default?: any + // 是否允许动态控制字段是否显示,默认为 true + enableColumnDisplayControl?: boolean + // 单元格渲染组件的 key,默认将根据列配置等属性自动生成(此 key 值改变时单元格将自动重新渲染) + getRenderKey?: (row: TableRow, field: TableColumn, column: TableColumnCtx, index: number) => string + + // 公共搜索操作符,默认值为 = ,值为 false 禁用此字段公共搜索,支持的操作符见下类型定义 + operator?: boolean | OperatorStr + // 公共搜索框的 placeholder + operatorPlaceholder?: string | string[] + // 公共搜索渲染方式,render=tag|switch 时公共搜索也会渲染为下拉,数字会渲染为范围筛选,时间渲染为时间选择器等 + comSearchRender?: 'string' | 'remoteSelect' | 'select' | 'time' | 'date' | 'datetime' | 'customRender' | 'slot' + // 公共搜索自定义组件/函数渲染 + comSearchCustomRender?: string | Component + // 公共搜索自定义渲染为 slot 时,slot 的名称 + comSearchSlotName?: string + // 公共搜索自定义渲染时,外层 el-col 的属性(仅 customRender、slot 支持) + comSearchColAttr?: Partial + // 公共搜索是否显示字段的 label + comSearchShowLabel?: boolean + // 公共搜索输入组件的扩展属性 + comSearchInputAttr?: anyObj + // 公共搜索渲染为远程下拉时,远程下拉组件的必要属性 + remote?: { + pk?: string + field?: string + params?: anyObj + multiple?: boolean + remoteUrl: string + } + + // 使用了 render 属性时,渲染前对字段值的预处理方法(即将废弃,请使用兼容 el-table 的 formatter 函数代替) + renderFormatter?: (row: TableRow, field: TableColumn, value: any, column: TableColumnCtx, index: number) => any + // 渲染为 url 时的点击事件(即将废弃,请使用 el-table 的 @cell-click 或单元格自定义渲染代替) + click?: (row: TableRow, field: TableColumn, value: any, column: TableColumnCtx, index: number) => any + } + + /** + * 表格右侧操作按钮 + */ + interface OptButton { + /** + * 渲染方式:tipButton=带tip的按钮,confirmButton=带确认框的按钮,moveButton=移动按钮,basicButton=普通按钮 + */ + render: 'tipButton' | 'confirmButton' | 'moveButton' | 'basicButton' + + /** + * 按钮名称,将作为触发表格内事件(onTableAction)时的事件名 + */ + name: string + + /** + * 鼠标 hover 时的提示 + * 可使用多语言翻译 key,比如 user.group + */ + title?: string + + /** + * 直接在按钮内显示的文字,title 有值时可为空 + * 可使用多语言翻译 key,比如 user.group + */ + text?: string + + /** + * 自定义按钮的点击事件 + * @param row 当前行数据 + * @param field 当前列数据 + */ + click?: (row: TableRow, field: TableColumn) => void + + /** + * 按钮是否显示(请返回布尔值,比如:display: auth('add')) + * @param row 当前行数据 + * @param field 当前列数据 + */ + display?: (row: TableRow, field: TableColumn) => boolean + + /** + * 按钮是否禁用(请返回布尔值) + * @param row 当前行数据 + * @param field 当前列数据 + */ + disabled?: (row: TableRow, field: TableColumn) => boolean + + /** + * 按钮是否正在加载中(请返回布尔值) + * @param row 当前行数据 + * @param field 当前列数据 + */ + loading?: (row: TableRow, field: TableColumn) => boolean + + /** + * 自定义 el-button 的其他属性(格式为属性 object 或一个返回属性 object 的函数) + */ + attr?: TableContextDataFun + + // 按钮 class + class?: string + // 按钮 type + type: ButtonType + // 按钮 icon 的名称 + icon: string + // 确认按钮的气泡确认框的属性(el-popconfirm 的属性,格式为属性 object 或一个返回属性 object 的函数) + popconfirm?: TableContextDataFun + // 是否禁用 title 提示,此值通常由系统动态调整以确保提示的显示效果 + disabledTip?: boolean + } + + /** + * 表格行 + */ + interface TableRow extends anyObj { + children?: TableRow[] + } + + /** + * 表头支持的按钮 + */ + type HeaderOptButton = 'refresh' | 'add' | 'edit' | 'delete' | 'unfold' | 'comSearch' | 'quickSearch' | 'columnDisplay' + + /** + * 公共搜索操作符支持的值 + */ + type OperatorStr = + | 'eq' // 等于,默认值 + | 'ne' // 不等于 + | 'gt' // 大于 + | 'egt' // 大于等于 + | 'lt' // 小于 + | 'elt' // 小于等于 + | 'LIKE' + | 'NOT LIKE' + | 'IN' + | 'NOT IN' + | 'RANGE' // 范围,将生成两个输入框,可以输入最小值和最大值 + | 'NOT RANGE' + | 'NULL' // 是否为NULL,将生成单个复选框 + | 'NOT NULL' + | 'FIND_IN_SET' + // 不推荐使用的,因为部分符号不利于网络传输 + | '=' + | '<>' + | '>' + | '>=' + | '<' + | '<=' + + /** + * 公共搜索事件返回的 Data + */ + interface ComSearchData { + field: string + val: string | string[] | number | number[] + operator: string + render?: string + } + + interface ElTreeData { + label: string + children?: ElTreeData[] + } + + /** + * 表格上下文数据 + */ + interface TableContextData { + row?: TableRow + field?: TableColumn + cellValue?: any + column?: TableColumnCtx + index?: number + } + + /** + * 接受表格上下文数据的任意属性计算函数 + */ + type TableContextDataFun = Partial | ((context: TableContextData) => Partial) + + interface TableRenderPublicInstance extends ComponentPublicInstance { + $attrs: { + renderValue: any + renderRow: TableRow + renderField: TableColumn + renderColumn: TableColumnCtx + renderIndex: number + } + } +} diff --git a/web/types/tableRenderer.d.ts b/web/types/tableRenderer.d.ts new file mode 100644 index 0000000..ab5299a --- /dev/null +++ b/web/types/tableRenderer.d.ts @@ -0,0 +1,15 @@ +/** 可用的表格单元格渲染器,以 ./src/components/table/fieldRender/ 目录中的文件名自动生成 */ +type TableRenderer = + | 'buttons' + | 'color' + | 'customRender' + | 'customTemplate' + | 'datetime' + | 'icon' + | 'image' + | 'images' + | 'switch' + | 'tag' + | 'tags' + | 'url' + | 'slot' diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100644 index 0000000..408d745 --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,50 @@ +import vue from '@vitejs/plugin-vue' +import { resolve } from 'path' +import type { ConfigEnv, UserConfig } from 'vite' +import { loadEnv } from 'vite' +import { svgBuilder } from '/@/components/icon/svg/index' +import { customHotUpdate, isProd } from '/@/utils/vite' + +const pathResolve = (dir: string): any => { + return resolve(__dirname, '.', dir) +} + +// https://vitejs.cn/config/ +const viteConfig = ({ mode }: ConfigEnv): UserConfig => { + const { VITE_PORT, VITE_OPEN, VITE_BASE_PATH, VITE_OUT_DIR } = loadEnv(mode, process.cwd()) + + const alias: Record = { + '/@': pathResolve('./src/'), + assets: pathResolve('./src/assets'), + 'vue-i18n': isProd(mode) ? 'vue-i18n/dist/vue-i18n.cjs.prod.js' : 'vue-i18n/dist/vue-i18n.cjs.js', + } + + return { + plugins: [vue(), svgBuilder('./src/assets/icons/'), customHotUpdate()], + root: process.cwd(), + resolve: { alias }, + base: VITE_BASE_PATH, + server: { + port: parseInt(VITE_PORT), + open: VITE_OPEN != 'false', + }, + build: { + cssCodeSplit: false, + sourcemap: false, + outDir: VITE_OUT_DIR, + emptyOutDir: true, + chunkSizeWarningLimit: 1500, + rollupOptions: { + output: { + manualChunks: { + // 分包配置,配置完成自动按需加载 + vue: ['vue', 'vue-router', 'pinia', 'vue-i18n', 'element-plus'], + echarts: ['echarts'], + }, + }, + }, + }, + } +} + +export default viteConfig