commit dfcd762e23c3e2eec6a42d65521d7dc6b81ad166 Author: zhenhui <1276357500@qq.com> Date: Wed Mar 18 15:54:43 2026 +0800 项目初始化 diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..d76ef31 --- /dev/null +++ b/.env-example @@ -0,0 +1,23 @@ +# BuildAdmin Webman 环境配置 +# 复制为 .env 并修改实际值 + +# 应用 +APP_DEBUG = true +APP_DEFAULT_TIMEZONE = Asia/Shanghai + +# 语言 +LANG_DEFAULT_LANG = zh-cn + +# 数据库(config/thinkorm.php) +DATABASE_DRIVER = mysql +DATABASE_TYPE = mysql +DATABASE_HOSTNAME = 127.0.0.1 +DATABASE_DATABASE = dafuweng-buildadmin +DATABASE_USERNAME = dafuweng-buildadmin +DATABASE_PASSWORD = 123456 +DATABASE_HOSTPORT = 3306 +DATABASE_CHARSET = utf8mb4 +DATABASE_PREFIX = + +# 缓存(config/cache.php) +CACHE_DRIVER = file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ebb020 --- /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 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..94ce154 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM php:8.3.22-cli-alpine + +RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" + +RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ + && apk update --no-cache \ + && docker-php-source extract + +# install extensions +RUN docker-php-ext-install pdo pdo_mysql -j$(nproc) pcntl + +# enable opcache and pcntl +RUN docker-php-ext-enable opcache pcntl +RUN docker-php-source delete \ + rm -rf /var/cache/apk/* + +RUN mkdir -p /app +WORKDIR /app \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2c66292 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 walkor and contributors (see https://github.com/walkor/webman/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4031784 --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +
+

webman

+ +基于workerman开发的超高性能PHP框架 + + +

学习

+ + + +
+ +

赞助商

+ +

特别赞助

+ + + + +

铂金赞助

+ + + + +
+ + +
+ +

请作者喝咖啡

+ + + +
+如果您觉得webman对您有所帮助,欢迎捐赠。 + + +
+ + +
+

LICENSE

+The webman is open-sourced software licensed under the MIT. +
+ +
+ + diff --git a/app/admin/controller/Ajax.php b/app/admin/controller/Ajax.php new file mode 100644 index 0000000..fb6db38 --- /dev/null +++ b/app/admin/controller/Ajax.php @@ -0,0 +1,206 @@ +initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('upload')); + $file = $request->file('file'); + if (!$file) { + return $this->error(__('No files were uploaded')); + } + $file = new WebmanUploadedFile($file); + $driver = $request->get('driver', $request->post('driver', 'local')); + $topic = $request->get('topic', $request->post('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) { + return $this->error($e->getMessage()); + } + return $this->success(__('File uploaded successfully'), [ + 'file' => $attachment ?? [] + ]); + } + + public function area(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + return $this->success('', get_area($request)); + } + + public function buildSuffixSvg(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $suffix = $request->get('suffix', $request->post('suffix', 'file')); + $background = $request->get('background', $request->post('background')); + $content = build_suffix_svg((string) $suffix, (string) $background); + return response($content, 200, [ + 'Content-Length' => strlen($content), + 'Content-Type' => 'image/svg+xml' + ]); + } + + public function getDatabaseConnectionList(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $quickSearch = $request->get('quickSearch', ''); + $connections = config('thinkorm.connections', config('database.connections', [])); + $desensitization = []; + foreach ($connections as $key => $connection) { + $connConfig = TableManager::getConnectionConfig($key); + $desensitization[] = [ + 'type' => $connConfig['type'] ?? 'mysql', + 'database' => substr_replace($connConfig['database'] ?? '', '****', 1, strlen($connConfig['database'] ?? '') > 4 ? 2 : 1), + 'key' => $key, + ]; + } + if ($quickSearch) { + $desensitization = array_values(array_filter($desensitization, function ($item) use ($quickSearch) { + return preg_match("/$quickSearch/i", $item['key']); + })); + } + return $this->success('', ['list' => $desensitization]); + } + + public function getTablePk(Request $request, ?string $table = null, ?string $connection = null): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $table = $table ?? $request->get('table', $request->post('table')); + $connection = $connection ?? $request->get('connection', $request->post('connection')); + if (!$table) { + return $this->error(__('Parameter error')); + } + $table = TableManager::tableName($table, true, $connection); + if (!TableManager::phinxAdapter(false, $connection)->hasTable($table)) { + return $this->error(__('Data table does not exist')); + } + $conn = TableManager::getConnection($connection); + $tablePk = Db::connect($conn)->table($table)->getPk(); + return $this->success('', ['pk' => $tablePk]); + } + + public function getTableList(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $quickSearch = $request->get('quickSearch', $request->post('quickSearch', '')); + $connection = $request->get('connection', $request->post('connection')); + $samePrefix = filter_var($request->get('samePrefix', $request->post('samePrefix', true)), FILTER_VALIDATE_BOOLEAN); + $excludeTable = $request->get('excludeTable', $request->post('excludeTable', [])); + $excludeTable = is_array($excludeTable) ? $excludeTable : []; + + $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 = '/^' . preg_quote($dbConfig['prefix'] ?? '', '/') . '/i'; + $outTables = []; + foreach ($tables as $table => $comment) { + if ($samePrefix && !preg_match($pattern, $table)) continue; + $tableNoPrefix = preg_replace($pattern, '', $table); + if (!in_array($tableNoPrefix, $excludeTable)) { + $outTables[] = [ + 'table' => $tableNoPrefix, + 'comment' => $comment, + 'connection' => $connection, + 'prefix' => $dbConfig['prefix'] ?? '', + ]; + } + } + return $this->success('', ['list' => $outTables]); + } + + public function getTableFieldList(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $table = $request->get('table', $request->post('table')); + $clean = filter_var($request->get('clean', $request->post('clean', true)), FILTER_VALIDATE_BOOLEAN); + $connection = $request->get('connection', $request->post('connection')); + if (!$table) { + return $this->error(__('Parameter error')); + } + $conn = TableManager::getConnection($connection); + $tablePk = Db::connect($conn)->name($table)->getPk(); + return $this->success('', [ + 'pk' => $tablePk, + 'fieldList' => TableManager::getTableColumns($table, $clean, $conn), + ]); + } + + public function changeTerminalConfig(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('Change terminal config')); + if (Terminal::changeTerminalConfig()) { + return $this->success(); + } + return $this->error(__('Failed to modify the terminal configuration. Please modify the configuration file manually:%s', ['/config/terminal.php'])); + } + + public function clearCache(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('Clear cache')); + $type = $request->post('type'); + if ($type === 'tp' || $type === 'all') { + clear_config_cache(); + } else { + return $this->error(__('Parameter error')); + } + event_trigger('cacheClearAfter'); + return $this->success(__('Cache cleaned~')); + } + + public function terminal(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + (new Terminal())->exec(); + return $this->success(); + } +} diff --git a/app/admin/controller/Dashboard.php b/app/admin/controller/Dashboard.php new file mode 100644 index 0000000..0c128d7 --- /dev/null +++ b/app/admin/controller/Dashboard.php @@ -0,0 +1,22 @@ +initializeBackend($request); + if ($response !== null) return $response; + + return $this->success('', [ + 'remark' => get_route_remark() + ]); + } +} diff --git a/app/admin/controller/Index.php b/app/admin/controller/Index.php new file mode 100644 index 0000000..da42fc4 --- /dev/null +++ b/app/admin/controller/Index.php @@ -0,0 +1,151 @@ +initializeBackend($request); + if ($response !== null) return $response; + + $adminInfo = $this->auth->getInfo(); + $adminInfo['super'] = $this->auth->isSuperAdmin(); + unset($adminInfo['token'], $adminInfo['refresh_token']); + + $menus = $this->auth->getMenus(); + if (!$menus) { + return $this->error(__('No background menu, please contact super administrator!')); + } + + $apiUrl = config('buildadmin.api_url'); + if (!$apiUrl || $apiUrl === 'https://api.buildadmin.com') { + $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; + $apiUrl = $scheme . '://' . $request->host(); + } + + return $this->success('', [ + 'adminInfo' => $adminInfo, + 'menus' => $menus, + 'siteConfig' => [ + 'siteName' => get_sys_config('site_name'), + 'version' => get_sys_config('version'), + 'apiUrl' => $apiUrl, + 'upload' => keys_to_camel_case(get_upload_config($request), ['max_size', 'save_name', 'allowed_suffixes', 'allowed_mime_types']), + 'cdnUrl' => full_url(), + 'cdnUrlParams' => config('buildadmin.cdn_url_params'), + ], + 'terminal' => [ + 'phpDevelopmentServer' => str_contains($_SERVER['SERVER_SOFTWARE'] ?? '', 'Development Server'), + 'npmPackageManager' => config('terminal.npm_package_manager'), + ] + ]); + } + + public function login(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($this->auth->isLogin()) { + return $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('buildadmin.admin_login_captcha'); + + if ($request->method() === 'POST') { + $username = $request->post('username'); + $password = $request->post('password'); + $keep = $request->post('keep'); + + $rules = [ + 'username' => 'required|string|min:3|max:30', + 'password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/', + ]; + $data = ['username' => $username, 'password' => $password]; + if ($captchaSwitch) { + $rules['captchaId'] = 'required|string'; + $rules['captchaInfo'] = 'required|string'; + $data['captchaId'] = $request->post('captchaId'); + $data['captchaInfo'] = $request->post('captchaInfo'); + } + + try { + Validator::make($data, $rules, [ + 'username.required' => __('Username'), + 'password.required' => __('Password'), + 'password.regex' => __('Please input correct password'), + ])->validate(); + } catch (ValidationException $e) { + return $this->error($e->getMessage()); + } + + if ($captchaSwitch) { + $captchaObj = new ClickCaptcha(); + if (!$captchaObj->check($data['captchaId'], $data['captchaInfo'])) { + return $this->error(__('Captcha error')); + } + } + + AdminLog::instance($request)->setTitle(__('Login')); + + $res = $this->auth->login($username, $password, (bool) $keep); + if ($res === true) { + $userInfo = $this->auth->getInfo(); + $adminId = $this->auth->id; + $keepTime = (int) config('buildadmin.admin_token_keep_time', 86400 * 3); + // 兜底:若 getInfo 未返回 token,在控制器层生成并入库(login 成功时必有 adminId) + if (empty($userInfo['token']) && $adminId) { + $userInfo['token'] = Random::uuid(); + Token::set($userInfo['token'], \app\admin\library\Auth::TOKEN_TYPE, $adminId, $keepTime); + } + if (empty($userInfo['refresh_token']) && $keep && $adminId) { + $userInfo['refresh_token'] = Random::uuid(); + Token::set($userInfo['refresh_token'], \app\admin\library\Auth::TOKEN_TYPE . '-refresh', $adminId, 2592000); + } + return $this->success(__('Login succeeded!'), [ + 'userInfo' => $userInfo + ]); + } + $msg = $this->auth->getError(); + return $this->error($msg ?: __('Incorrect user name or password!')); + } + + return $this->success('', [ + 'captcha' => $captchaSwitch + ]); + } + + public function logout(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + $refreshToken = $request->post('refreshToken', ''); + if ($refreshToken) { + Token::delete((string) $refreshToken); + } + $this->auth->logout(); + return $this->success(); + } + return $this->error(__('Method not allowed'), [], 0, ['statusCode' => 405]); + } +} diff --git a/app/admin/controller/Module.php b/app/admin/controller/Module.php new file mode 100644 index 0000000..a502037 --- /dev/null +++ b/app/admin/controller/Module.php @@ -0,0 +1,147 @@ +initializeBackend($request); + if ($response !== null) return $response; + + return $this->success('', [ + 'installed' => Server::installedList(root_path() . 'modules' . DIRECTORY_SEPARATOR), + 'sysVersion' => config('buildadmin.version'), + 'nuxtVersion' => Server::getNuxtVersion(), + ]); + } + + public function state(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $uid = $request->get('uid', ''); + if (!$uid) { + return $this->error(__('Parameter error')); + } + return $this->success('', [ + 'state' => Manage::instance($uid)->getInstallState() + ]); + } + + public function install(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('Install module')); + $uid = $request->get('uid', $request->post('uid', '')); + $update = filter_var($request->get('update', $request->post('update', false)), FILTER_VALIDATE_BOOLEAN); + if (!$uid) { + return $this->error(__('Parameter error')); + } + $res = []; + try { + $res = Manage::instance($uid)->install($update); + } catch (BaException $e) { + return $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (\Throwable $e) { + return $this->error(__($e->getMessage())); + } + return $this->success('', ['data' => $res]); + } + + public function dependentInstallComplete(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $uid = $request->get('uid', ''); + if (!$uid) { + return $this->error(__('Parameter error')); + } + try { + Manage::instance($uid)->dependentInstallComplete('all'); + } catch (BaException $e) { + return $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (\Throwable $e) { + return $this->error(__($e->getMessage())); + } + return $this->success(); + } + + public function changeState(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('Change module state')); + $uid = $request->post('uid', ''); + $state = filter_var($request->post('state', false), FILTER_VALIDATE_BOOLEAN); + if (!$uid) { + return $this->error(__('Parameter error')); + } + $info = []; + try { + $info = Manage::instance($uid)->changeState($state); + } catch (BaException $e) { + return $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (\Throwable $e) { + return $this->error(__($e->getMessage())); + } + return $this->success('', ['info' => $info]); + } + + public function uninstall(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('Uninstall module')); + $uid = $request->post('uid', ''); + if (!$uid) { + return $this->error(__('Parameter error')); + } + try { + Manage::instance($uid)->uninstall(); + } catch (BaException $e) { + return $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (\Throwable $e) { + return $this->error(__($e->getMessage())); + } + return $this->success(); + } + + public function upload(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('Upload module')); + $file = $request->file('file'); + if (!$file) { + return $this->error(__('Parameter error')); + } + try { + $res = Manage::uploadFromRequest($request); + } catch (BaException $e) { + return $this->error(__($e->getMessage()), $e->getData(), $e->getCode()); + } catch (\Throwable $e) { + return $this->error(__($e->getMessage())); + } + return $this->success('', $res); + } +} diff --git a/app/admin/controller/auth/Admin.php b/app/admin/controller/auth/Admin.php new file mode 100644 index 0000000..2931e19 --- /dev/null +++ b/app/admin/controller/auth/Admin.php @@ -0,0 +1,286 @@ +model = new AdminModel(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') ?? $request->post('select')) { + $selectRes = $this->select($request); + if ($selectRes !== null) return $selectRes; + } + + 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); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + if ($this->modelValidate) { + try { + $rules = [ + 'username' => 'required|string|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/|unique:admin,username', + 'nickname' => 'required|string', + 'password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/', + 'email' => 'email|unique:admin,email', + 'mobile' => 'regex:/^1[3-9]\d{9}$/|unique:admin,mobile', + 'group_arr' => 'required|array', + ]; + $messages = [ + 'username.regex' => __('Please input correct username'), + 'password.regex' => __('Please input correct password'), + ]; + Validator::make($data, $rules, $messages)->validate(); + } catch (ValidationException $e) { + return $this->error($e->getMessage()); + } + } + + $passwd = $data['password'] ?? ''; + $data = $this->excludeFields($data); + $result = false; + if (!empty($data['group_arr'])) { + $authRes = $this->checkGroupAuth($data['group_arr']); + if ($authRes !== null) return $authRes; + } + $this->model->startTrans(); + try { + $result = $this->model->save($data); + if (!empty($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(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Added successfully')); + } + return $this->error(__('No rows were added')); + } + + return $this->error(__('Parameter error')); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->get($pk) ?? $request->post($pk); + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + return $this->error(__('You have no permission')); + } + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + if ($this->modelValidate) { + try { + $rules = [ + 'username' => 'required|string|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/|unique:admin,username,' . $id, + 'nickname' => 'required|string', + 'password' => 'nullable|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/', + 'email' => 'email|unique:admin,email,' . $id, + 'mobile' => 'regex:/^1[3-9]\d{9}$/|unique:admin,mobile,' . $id, + 'group_arr' => 'required|array', + ]; + $messages = [ + 'username.regex' => __('Please input correct username'), + 'password.regex' => __('Please input correct password'), + ]; + Validator::make($data, $rules, $messages)->validate(); + } catch (ValidationException $e) { + return $this->error($e->getMessage()); + } + } + + if ($this->auth->id == $data['id'] && ($data['status'] ?? '') == 'disable') { + return $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 (!empty($data['group_arr'])) { + $checkGroups = []; + $rowGroupArr = $row->group_arr ?? []; + foreach ($data['group_arr'] as $datum) { + if (!in_array($datum, $rowGroupArr)) { + $checkGroups[] = $datum; + } + $groupAccess[] = [ + 'uid' => $id, + 'group_id' => $datum, + ]; + } + $authRes = $this->checkGroupAuth($checkGroups); + if ($authRes !== null) return $authRes; + } + + 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(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Update successful')); + } + return $this->error(__('No rows updated')); + } + + unset($row['salt'], $row['login_failure']); + $row['password'] = ''; + return $this->success('', [ + 'row' => $row + ]); + } + + public function del(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $request->get('ids') ?? $request->post('ids') ?? []; + $ids = is_array($ids) ? $ids : []; + $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(); + return $this->error($e->getMessage()); + } + if ($count) { + return $this->success(__('Deleted successfully')); + } + return $this->error(__('No rows were deleted')); + } + + /** + * 远程下拉(Admin 无自定义,走父类默认列表) + */ + public function select(Request $request): Response + { + return parent::select($request); + } + + private function checkGroupAuth(array $groups): ?Response + { + if ($this->auth->isSuperAdmin()) { + return null; + } + $authGroups = $this->auth->getAllAuthGroups('allAuthAndOthers'); + foreach ($groups as $group) { + if (!in_array($group, $authGroups)) { + return $this->error(__('You have no permission to add an administrator to this group!')); + } + } + return null; + } +} diff --git a/app/admin/controller/auth/AdminLog.php b/app/admin/controller/auth/AdminLog.php new file mode 100644 index 0000000..1bee893 --- /dev/null +++ b/app/admin/controller/auth/AdminLog.php @@ -0,0 +1,62 @@ +model = new AdminLogModel(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') ?? $request->post('select')) { + $selectRes = $this->select($request); + if ($selectRes !== null) return $selectRes; + } + + 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); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 远程下拉(AdminLog 无自定义,走父类默认列表) + */ + public function select(Request $request): Response + { + return parent::select($request); + } +} diff --git a/app/admin/controller/auth/Group.php b/app/admin/controller/auth/Group.php new file mode 100644 index 0000000..26cb0ec --- /dev/null +++ b/app/admin/controller/auth/Group.php @@ -0,0 +1,346 @@ +model = new AdminGroup(); + $this->tree = Tree::instance(); + + $isTree = $request->get('isTree') ?? $request->post('isTree') ?? true; + $initValue = $request->get('initValue') ?? $request->post('initValue') ?? []; + $this->initValue = is_array($initValue) ? array_filter($initValue) : []; + $this->keyword = $request->get('quickSearch') ?? $request->post('quickSearch') ?? ''; + + $this->assembleTree = $isTree && !$this->initValue; + + $this->adminGroups = Db::name('admin_group_access')->where('uid', $this->auth->id)->column('group_id'); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') ?? $request->post('select')) { + return $this->select($request); + } + + return $this->success('', [ + 'list' => $this->getGroups($request), + 'group' => $this->adminGroups, + 'remark' => get_route_remark(), + ]); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $rulesRes = $this->handleRules($data); + if ($rulesRes instanceof Response) return $rulesRes; + + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + try { + $rules = [ + 'name' => 'required|string', + 'rules' => 'required', + ]; + $messages = [ + 'rules.required' => __('Please select rules'), + ]; + Validator::make($data, $rules, $messages)->validate(); + } catch (ValidationException $e) { + throw $e; + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Added successfully')); + } + return $this->error(__('No rows were added')); + } + + return $this->error(__('Parameter error')); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->get($pk) ?? $request->post($pk); + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + $authRes = $this->checkAuth($id); + if ($authRes !== null) return $authRes; + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $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)) { + return $this->error(__('You cannot modify your own management group!')); + } + + $data = $this->excludeFields($data); + $rulesRes = $this->handleRules($data); + if ($rulesRes instanceof Response) return $rulesRes; + + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + try { + $rules = [ + 'name' => 'required|string', + 'rules' => 'required', + ]; + $messages = [ + 'rules.required' => __('Please select rules'), + ]; + Validator::make($data, $rules, $messages)->validate(); + } catch (ValidationException $e) { + throw $e; + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Update successful')); + } + return $this->error(__('No rows updated')); + } + + $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]); + } + } + $rowData = $row->toArray(); + $rowData['rules'] = array_values($rules); + return $this->success('', [ + 'row' => $rowData + ]); + } + + public function del(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $ids = $request->get('ids') ?? $request->post('ids') ?? []; + $ids = is_array($ids) ? $ids : []; + $data = $this->model->where($this->model->getPk(), 'in', $ids)->select(); + foreach ($data as $v) { + $authRes = $this->checkAuth($v->id); + if ($authRes !== null) return $authRes; + } + $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id'); + foreach ($subData as $key => $subDatum) { + if (!in_array($key, $ids)) { + return $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(); + return $this->error($e->getMessage()); + } + if ($count) { + return $this->success(__('Deleted successfully')); + } + return $this->error(__('No rows were deleted')); + } + + public function select(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $data = $this->getGroups($request, [['status', '=', 1]]); + + if ($this->assembleTree) { + $data = $this->tree->assembleTree($this->tree->getTreeArray($data)); + } + return $this->success('', [ + 'options' => $data + ]); + } + + /** + * @return array|Response + */ + private function handleRules(array &$data) + { + if (!empty($data['rules']) && is_array($data['rules'])) { + $superAdmin = true; + $checkedRules = []; + $allRuleIds = AdminRule::column('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)) { + return $this->error(__('Role group has all your rights, please contact the upper administrator to add or do not need to add!')); + } + + if (array_diff($checkedRules, $ownedRuleIds) && !$this->auth->isSuperAdmin()) { + return $this->error(__('The group permission node exceeds the range that can be allocated')); + } + + $data['rules'] = implode(',', $checkedRules); + } + } else { + unset($data['rules']); + } + return $data; + } + + private function getGroups(Request $request, array $where = []): array + { + $pk = $this->model->getPk(); + $initKey = $request->get('initKey') ?? $pk; + + $absoluteAuth = $request->get('absoluteAuth') ?? 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(); + + 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 : __('%first% etc. %count% items', ['%first%' => $rulesFirstTitle, '%count%' => count($rules)]); + } + } + } else { + $datum['rules'] = __('No permission'); + } + } + + return $this->assembleTree ? $this->tree->assembleChild($data) : $data; + } + + private function checkAuth($groupId): ?Response + { + $authGroups = $this->auth->getAllAuthGroups($this->authMethod, []); + if (!$this->auth->isSuperAdmin() && !in_array($groupId, $authGroups)) { + return $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~')); + } + return null; + } +} diff --git a/app/admin/controller/auth/Rule.php b/app/admin/controller/auth/Rule.php new file mode 100644 index 0000000..c87455d --- /dev/null +++ b/app/admin/controller/auth/Rule.php @@ -0,0 +1,303 @@ + 'desc']; + + protected string|array $quickSearchField = 'title'; + + protected ?object $model = null; + + protected Tree $tree; + + protected array $initValue = []; + + protected string $keyword = ''; + + protected bool $assembleTree = true; + + protected bool $modelValidate = false; + + protected function initController(Request $request): ?Response + { + $this->model = new AdminRule(); + $this->tree = Tree::instance(); + $isTree = $request->get('isTree') ?? $request->post('isTree') ?? true; + $initValue = $request->get('initValue') ?? $request->post('initValue') ?? []; + $this->initValue = is_array($initValue) ? array_filter($initValue) : []; + $this->keyword = $request->get('quickSearch') ?? $request->post('quickSearch') ?? ''; + $this->assembleTree = $isTree && !$this->initValue; + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') ?? $request->post('select')) { + return $this->select($request); + } + + return $this->success('', [ + 'list' => $this->getMenus($request), + 'remark' => get_route_remark(), + ]); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $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, (int) $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(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Added successfully')); + } + return $this->error(__('No rows were added')); + } + + return $this->error(__('Parameter error')); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $id = $request->get($this->model->getPk()) ?? $request->post($this->model->getPk()); + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + return $this->error(__('You have no permission')); + } + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $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 && $parent['pid'] == $row['id']) { + $parent->pid = 0; + $parent->save(); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Update successful')); + } + return $this->error(__('No rows updated')); + } + + return $this->success('', [ + 'row' => $row + ]); + } + + public function del(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $ids = $request->get('ids') ?? $request->post('ids') ?? []; + $ids = is_array($ids) ? $ids : []; + + $subData = $this->model->where('pid', 'in', $ids)->column('pid', 'id'); + foreach ($subData as $key => $subDatum) { + if (!in_array($key, $ids)) { + return $this->error(__('Please delete the child element first, or use batch deletion')); + } + } + + return $this->delFromTrait($request); + } + + public function select(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $data = $this->getMenus($request, [['type', 'in', ['menu_dir', 'menu']], ['status', '=', 1]]); + + if ($this->assembleTree) { + $data = $this->tree->assembleTree($this->tree->getTreeArray($data, 'title')); + } + return $this->success('', [ + 'options' => $data + ]); + } + + protected function getMenus(Request $request, array $where = []): array + { + $pk = $this->model->getPk(); + $initKey = $request->get('initKey') ?? $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(); + + 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) { + /** @var AdminGroup $group */ + $rules = explode(',', (string) $group->rules); + if (in_array($pid, $rules) && !in_array($id, $rules)) { + $rules[] = $id; + $group->rules = implode(',', $rules); + $group->save(); + } + } + } + + /** + * 调用 trait 的 del 逻辑(因 Rule 重写了 del,需手动调用 trait) + */ + private function delFromTrait(Request $request): Response + { + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $request->get('ids') ?? $request->post('ids') ?? []; + $ids = is_array($ids) ? $ids : []; + $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(); + return $this->error($e->getMessage()); + } + if ($count) { + return $this->success(__('Deleted successfully')); + } + return $this->error(__('No rows were deleted')); + } +} diff --git a/app/admin/controller/crud/Crud.php b/app/admin/controller/crud/Crud.php new file mode 100644 index 0000000..992cee8 --- /dev/null +++ b/app/admin/controller/crud/Crud.php @@ -0,0 +1,769 @@ +initializeBackend($request); + if ($response !== null) return $response; + + $type = $request->post('type', ''); + $table = $request->post('table', []); + $fields = $request->post('fields', []); + + if (!$table || !$fields || !isset($table['name']) || !$table['name']) { + return $this->error(__('Parameter error')); + } + + $crudLogId = 0; + try { + $crudLogId = Helper::recordCrudStatus([ + 'table' => $table, + 'fields' => $fields, + 'status' => 'start', + ]); + + $tableName = TableManager::tableName($table['name'], false, $table['databaseConnection'] ?? null); + + if ($type == 'create' || ($table['rebuild'] ?? '') == 'Yes') { + TableManager::phinxTable($tableName, [], true, $table['databaseConnection'] ?? null)->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'] ?? false ? 'common' : 'admin', $tableName, 'model', $table['modelFile'] ?? ''); + $validateFile = Helper::parseNameData($table['isCommonModel'] ?? false ? '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']) . '.'; + + $quickSearchField = $table['quickSearchField'] ?? [$tablePk]; + if (!in_array($tablePk, $quickSearchField)) { + $quickSearchField[] = $tablePk; + } + $quickSearchFieldZhCnTitle = []; + + $this->modelData = [ + 'append' => [], 'methods' => [], 'fieldType' => [], 'createTime' => '', 'updateTime' => '', + 'beforeInsertMixins' => [], 'beforeInsert' => '', 'afterInsert' => '', + 'connection' => $table['databaseConnection'] ?? '', 'name' => $tableName, + 'className' => $modelFile['lastName'], 'namespace' => $modelFile['namespace'], + 'relationMethodList' => [], + ]; + $this->controllerData = [ + 'use' => [], 'attr' => [], 'methods' => [], 'filterRule' => '', + 'className' => $controllerFile['lastName'], 'namespace' => $controllerFile['namespace'], + 'tableComment' => $tableComment, 'modelName' => $modelFile['lastName'], + 'modelNamespace' => $modelFile['namespace'], + ]; + $this->indexVueData = [ + 'enableDragSort' => false, 'defaultItems' => [], + 'tableColumn' => [['type' => 'selection', 'align' => 'center', 'operator' => 'false']], + 'dblClickNotEditColumn' => ['undefined'], 'optButtons' => ['edit', 'delete'], + 'defaultOrder' => '', + ]; + $this->formVueData = ['bigDialog' => false, 'formFields' => [], 'formValidatorRules' => [], 'imports' => []]; + $this->langTsData = ['en' => [], 'zh-cn' => []]; + + $fieldsMap = []; + foreach ($fields as $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'], $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'] ?? null); + } + 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(',', $quickSearchField); + $this->langTsData['zh-cn']['quick Search Fields'] = implode('、', $quickSearchFieldZhCnTitle); + $this->controllerData['attr']['quickSearchField'] = $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); + + $this->indexVueData['tablePk'] = $tablePk; + $this->indexVueData['webTranslate'] = $this->webTranslate; + Helper::writeIndexFile($this->indexVueData, $webViewsDir, $controllerFile); + Helper::writeFormFile($this->formVueData, $webViewsDir, $fields, $this->webTranslate); + + Helper::createMenu($webViewsDir, $tableComment); + + Helper::recordCrudStatus(['id' => $crudLogId, 'status' => 'success']); + } catch (BaException $e) { + Helper::recordCrudStatus(['id' => $crudLogId ?: 0, 'status' => 'error']); + return $this->error($e->getMessage()); + } catch (Throwable $e) { + Helper::recordCrudStatus(['id' => $crudLogId ?: 0, 'status' => 'error']); + if (env('app_debug', false)) throw $e; + return $this->error($e->getMessage()); + } + + return $this->success('', ['crudLog' => CrudLog::find($crudLogId)]); + } + + public function logStart(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $id = $request->post('id'); + $type = $request->post('type', ''); + + if ($type == 'Cloud history') { + try { + $client = get_ba_client(); + $response = $client->request('GET', '/api/v6.Crud/info', [ + 'query' => [ + 'id' => $id, + 'server' => 1, + 'ba-user-token' => $request->post('token', ''), + ] + ]); + $content = $response->getBody()->getContents(); + $statusCode = $response->getStatusCode(); + if ($content == '' || stripos($content, '系统发生错误') !== false || $statusCode != 200) { + return $this->error(__('Failed to load cloud data')); + } + $json = json_decode($content, true); + if (json_last_error() != JSON_ERROR_NONE || !is_array($json)) { + return $this->error(__('Failed to load cloud data')); + } + if (($json['code'] ?? 0) != 1) { + return $this->error($json['msg'] ?? __('Failed to load cloud data')); + } + $info = $json['data']['info'] ?? null; + } catch (Throwable $e) { + return $this->error(__('Failed to load cloud data')); + } + } else { + $row = CrudLog::find($id); + $info = $row ? $row->toArray() : null; + } + + if (!$info) { + return $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($request)->setTitle(__('Log start')); + + return $this->success('', [ + 'table' => $info['table'], + 'fields' => $info['fields'], + 'sync' => $info['sync'] ?? 0, + ]); + } + + public function delete(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $id = $request->post('id'); + $row = CrudLog::find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + $info = $row->toArray(); + + $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) { + return $this->error($e->getMessage()); + } + return $this->success(__('Deleted successfully')); + } + + public function getFileData(Request $request): Response + { + try { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $table = $request->get('table'); + $commonModel = $request->get('commonModel', false); + + if (!$table) { + return $this->error(__('Parameter error')); + } + + $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'); + + $adminModelDir = root_path() . 'app' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR; + $commonModelDir = root_path() . 'app' . DIRECTORY_SEPARATOR . 'common' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR; + $adminModelFiles = is_dir($adminModelDir) ? Filesystem::getDirFiles($adminModelDir) : []; + $commonModelFiles = is_dir($commonModelDir) ? Filesystem::getDirFiles($commonModelDir) : []; + $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)) { + $item = Filesystem::fsFit('app/admin/controller/' . $item); + $controllerFiles[$item] = $item; + } + } + + // 路径统一使用正斜杠,便于 UI 展示及跨平台一致(相对于 dafuweng-webman 项目根) + $pathFit = fn(string $p): string => str_replace('\\', '/', $p); + + return $this->success('', [ + 'modelFile' => $pathFit($modelFile['rootFileName']), + 'controllerFile' => $pathFit($controllerFile['rootFileName']), + 'validateFile' => $pathFit($validateFile['rootFileName']), + 'controllerFileList' => array_map($pathFit, $controllerFiles), + 'modelFileList' => array_map($pathFit, $modelFileList), + 'webViewsDir' => $pathFit($webViewsDir['views']), + ]); + } catch (Throwable $e) { + return $this->error($e->getMessage()); + } + } + + public function checkCrudLog(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $table = $request->get('table'); + $connection = $request->get('connection', config('thinkorm.default', config('database.default', 'mysql'))); + + if (!$table) { + return $this->error(__('Parameter error')); + } + + $crudLog = Db::name('crud_log') + ->where('table_name', $table) + ->where('connection', $connection) + ->order('create_time desc') + ->find(); + + $id = ($crudLog && isset($crudLog['status']) && $crudLog['status'] == 'success') ? $crudLog['id'] : 0; + + return $this->success('', ['id' => $id]); + } + + public function parseFieldData(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('Parse field data')); + $type = $request->post('type'); + $table = $request->post('table'); + $connection = TableManager::getConnection($request->post('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) { + return $this->error(__('Record not found')); + } + $adapter = TableManager::phinxAdapter(false, $connection); + $empty = $adapter->hasTable($table) + ? Db::connect($connection)->table($table)->limit(1)->select()->isEmpty() + : true; + + return $this->success('', [ + 'columns' => Helper::parseTableColumns($table, false, $connection), + 'comment' => $tableInfo[0]['TABLE_COMMENT'] ?? '', + 'empty' => $empty, + ]); + } + return $this->error(__('Parameter error')); + } + + public function generateCheck(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + AdminLog::instance($request)->setTitle(__('Generate check')); + $table = $request->post('table'); + $connection = $request->post('connection', ''); + $webViewsDir = $request->post('webViewsDir', ''); + $controllerFile = $request->post('controllerFile', ''); + + if (!$table) { + return $this->error(__('Parameter error')); + } + + try { + $webViewsDir = Helper::parseWebDirNameData($table, 'views', $webViewsDir); + $controllerFile = Helper::parseNameData('admin', $table, 'controller', $controllerFile)['rootFileName']; + } catch (Throwable $e) { + return $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) { + return $this->error('', [ + 'menu' => $menuExist, + 'table' => $tableExist, + 'controller' => $controllerExist, + ], -1); + } + return $this->success(); + } + + public function uploadCompleted(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $syncIds = $request->post('syncIds', []); + $syncIds = is_array($syncIds) ? $syncIds : []; + $cancelSync = $request->post('cancelSync', false); + + $crudLogModel = new CrudLog(); + + if ($cancelSync) { + $logData = $crudLogModel->where('id', 'in', array_keys($syncIds))->select(); + foreach ($logData as $logDatum) { + if (isset($syncIds[$logDatum->id]) && $logDatum->sync == $syncIds[$logDatum->id]) { + $logDatum->sync = 0; + $logDatum->save(); + } + } + return $this->success(); + } + + foreach ($syncIds as $key => $syncId) { + $row = $crudLogModel->find($key); + if ($row) { + $row->sync = $syncId; + $row->save(); + } + } + + return $this->success(); + } + + private function parseJoinData($field, $table): void + { + $dictEn = []; + $dictZhCn = []; + if (empty($field['form']['relation-fields']) || empty($field['form']['remote-table'])) { + return; + } + $columns = Helper::parseTableColumns($field['form']['remote-table'], true, $table['databaseConnection'] ?? null); + $relationFields = explode(',', $field['form']['relation-fields']); + $tableName = TableManager::tableName($field['form']['remote-table'], false, $table['databaseConnection'] ?? null); + $rnPattern = '/(.*)(_ids|_id)$/'; + $relationName = preg_match($rnPattern, $field['name']) + ? parse_name(preg_replace($rnPattern, '$1', $field['name']), 1) + : parse_name($field['name'] . '_table', 1); + + if (empty($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' => [], 'methods' => [], 'fieldType' => [], 'createTime' => '', 'updateTime' => '', + 'beforeInsertMixins' => [], 'beforeInsert' => '', 'afterInsert' => '', + 'connection' => $table['databaseConnection'] ?? '', 'name' => $tableName, + 'className' => $joinModelFile['lastName'], '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' => $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 + { + 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'; + } + if (($field['designType'] ?? '') == 'spk') { + $modelData['beforeInsertMixins']['snowflake'] = Helper::assembleStub('mixins/model/mixins/beforeInsertWithSnowflake', []); + } + $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; + // Webman Request 无 filter 方法,使用 inputFilter 由 Backend trait 在 add/edit 时应用 + $this->controllerData['filterRule'] = "\n" . Helper::tab(2) . '$this->inputFilter = \'clean_xss\';'; + } + if (!empty($table['defaultSortField']) && !empty($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']; + } + } + + 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 (in_array($field['designType'], ['remoteSelect', '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)'; + } + 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'] ?? 0); + } + 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'; + $alias = ''; + if (!str_contains($pk, '.')) { + if (($field['form']['remote-source-config-type'] ?? '') == 'crud' && !empty($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' && !empty($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, string $fieldNamePrefix = '', string $translationPrefix = ''): array + { + $column = [ + 'label' => "t('" . $this->webTranslate . $translationPrefix . $field['name'] . "')", + 'prop' => $fieldNamePrefix . $field['name'] . (($field['designType'] ?? '') == 'city' ? '_text' : ''), + 'align' => 'center', + ]; + 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, string $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; + } +} diff --git a/app/admin/controller/crud/Log.php b/app/admin/controller/crud/Log.php new file mode 100644 index 0000000..d00b640 --- /dev/null +++ b/app/admin/controller/crud/Log.php @@ -0,0 +1,53 @@ +model = new CrudLog(); + + if (!$this->auth->check('crud/crud/index')) { + return $this->error(__('You have no permission'), [], 401); + } + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') || $request->post('select')) { + return $this->select($request); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable ?? [], $this->withJoinType ?? 'LEFT') + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } +} diff --git a/app/admin/controller/mall/Player.php b/app/admin/controller/mall/Player.php new file mode 100644 index 0000000..315567a --- /dev/null +++ b/app/admin/controller/mall/Player.php @@ -0,0 +1,149 @@ +model = new \app\admin\model\mall\Player(); + } + + /** + * 添加(重写以支持密码加密) + */ + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response instanceof Response) { + return $response; + } + + if ($request->method() !== 'POST') { + $this->error(__('Parameter error')); + } + + $data = $request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + $passwd = $data['password'] ?? ''; + if (empty($passwd)) { + $this->error(__('Parameter %s can not be empty', [__('Password')])); + } + + $data = $this->applyInputFilter($data); + $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); + if ($result !== false && $passwd) { + $this->model->resetPassword((int) $this->model->id, $passwd); + } + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + + $result !== false ? $this->success(__('Added successfully')) : $this->error(__('No rows were added')); + } + + /** + * 编辑(重写以支持编辑时密码可选) + */ + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response instanceof Response) { + return $response; + } + + $pk = $this->model->getPk(); + $id = $request->post($pk) ?? $request->get($pk); + $row = $this->model->find($id); + if (!$row) { + $this->error(__('Record not found')); + } + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + $this->error(__('Parameter %s can not be empty', [''])); + } + + if (!empty($data['password'])) { + $this->model->resetPassword((int) $row->id, $data['password']); + } + + $data = $this->applyInputFilter($data); + $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(array_merge($data, [$pk => $row[$pk]])); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + $this->error($e->getMessage()); + } + + return $result !== false ? $this->success(__('Update successful')) : $this->error(__('No rows updated')); + } + + unset($row['password']); + $row['password'] = ''; + $this->success('', ['row' => $row]); + } + + /** + * 若需重写查看、删除等方法,请复制 @see \app\admin\library\traits\Backend 中对应的方法至此进行重写 + */ +} \ 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..8c37c87 --- /dev/null +++ b/app/admin/controller/routine/AdminInfo.php @@ -0,0 +1,91 @@ +auth->setAllowFields($this->authAllowFields); + $this->model = $this->auth->getAdmin(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $info = $this->auth->getInfo(); + return $this->success('', ['info' => $info]); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->post($pk) ?? $request->get($pk); + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + if (!empty($data['avatar'])) { + $row->avatar = $data['avatar']; + if ($row->save()) { + return $this->success(__('Avatar modified successfully!')); + } + } + + if ($this->modelValidate) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + try { + $validate = new $validateClass(); + $validate->scene('info')->check($data); + } catch (\Throwable $e) { + return $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(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Update successful')) : $this->error(__('No rows updated')); + } + + return $this->success('', ['row' => $row]); + } +} diff --git a/app/admin/controller/routine/Attachment.php b/app/admin/controller/routine/Attachment.php new file mode 100644 index 0000000..91c840e --- /dev/null +++ b/app/admin/controller/routine/Attachment.php @@ -0,0 +1,52 @@ + 'desc']; + + protected function initController(Request $request): ?Response + { + $this->model = new AttachmentModel(); + return null; + } + + public function del(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $request->post('ids', $request->get('ids', [])); + $ids = is_array($ids) ? $ids : []; + $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) { + return $this->error(__('%d records and files have been deleted', [$count]) . $e->getMessage()); + } + return $count ? $this->success(__('%d records and files have been deleted', [$count])) : $this->error(__('No rows were deleted')); + } +} diff --git a/app/admin/controller/routine/Config.php b/app/admin/controller/routine/Config.php new file mode 100644 index 0000000..69a42f6 --- /dev/null +++ b/app/admin/controller/routine/Config.php @@ -0,0 +1,169 @@ + 'config/app.php', + 'webAdminBase' => 'web/src/router/static/adminBase.ts', + 'backendEntranceStub' => 'app/admin/library/stubs/backendEntrance.stub', + ]; + + protected function initController(Request $request): ?Response + { + $this->model = new ConfigModel(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $configGroup = get_sys_config('config_group'); + $config = $this->model->order('weigh desc')->select()->toArray(); + + $list = []; + $newConfigGroup = []; + if (is_array($configGroup)) { + foreach ($configGroup as $item) { + $key = $item['key'] ?? $item; + $val = $item['value'] ?? $item; + $list[$key] = ['name' => $key, 'title' => __($val)]; + $newConfigGroup[$key] = $list[$key]['title']; + } + } + foreach ($config as $item) { + $group = $item['group'] ?? ''; + if (isset($newConfigGroup[$group])) { + $item['title'] = __($item['title'] ?? ''); + $list[$group]['list'][] = $item; + } + } + + return $this->success('', [ + 'list' => $list, + 'remark' => get_route_remark(), + 'configGroup' => $newConfigGroup, + 'quickEntrance' => get_sys_config('config_quick_entrance'), + ]); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $all = $this->model->select(); + if ($request->method() === 'POST') { + $this->modelValidate = false; + $data = $request->post(); + if (!$data) { + return $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] + ]; + } + } + + $result = false; + $this->model->startTrans(); + try { + foreach ($configValue as $cv) { + $this->model->where('id', $cv['id'])->update(['value' => $cv['value']]); + } + $this->model->commit(); + $result = true; + } catch (\Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result ? $this->success(__('The current page configuration item was updated successfully')) : $this->error(__('No rows updated')); + } + + return $this->error(__('Parameter error')); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() !== 'POST') { + return $this->error(__('Parameter error')); + } + + $data = $request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + $validate->scene('add')->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (\Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Added successfully')) : $this->error(__('No rows were added')); + } + + public function sendTestMail(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $data = $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'] ?? 465; + $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) { + return $this->error($mail->ErrorInfo ?? ''); + } + return $this->success(__('Test mail sent successfully~')); + } +} diff --git a/app/admin/controller/security/DataRecycle.php b/app/admin/controller/security/DataRecycle.php new file mode 100644 index 0000000..c9e4e2e --- /dev/null +++ b/app/admin/controller/security/DataRecycle.php @@ -0,0 +1,155 @@ +model = new DataRecycleModel(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') || $request->post('select')) { + return $this->select($request); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable ?? [], $this->withJoinType ?? 'LEFT') + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $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) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + $validate->scene('add')->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (\Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Added successfully')) : $this->error(__('No rows were added')); + } + + return $this->success('', [ + 'controllers' => $this->getControllerList(), + ]); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->post($pk) ?? $request->get($pk); + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $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) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + $validate->scene('edit')->check(array_merge($data, [$pk => $row[$pk]])); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (\Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Update successful')) : $this->error(__('No rows updated')); + } + + return $this->success('', [ + 'row' => $row, + 'controllers' => $this->getControllerList(), + ]); + } + + private 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; + } +} diff --git a/app/admin/controller/security/DataRecycleLog.php b/app/admin/controller/security/DataRecycleLog.php new file mode 100644 index 0000000..c4ba41e --- /dev/null +++ b/app/admin/controller/security/DataRecycleLog.php @@ -0,0 +1,119 @@ +model = new DataRecycleLogModel(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') || $request->post('select')) { + return $this->select($request); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + public function restore(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $ids = $request->post('ids', $request->get('ids', [])); + $ids = is_array($ids) ? $ids : []; + $data = $this->model->where('id', 'in', $ids)->select(); + if (!$data) { + return $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(); + return $this->error($e->getMessage()); + } + + return $count ? $this->success(__('Restore successful')) : $this->error(__('No rows were restore')); + } + + public function info(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->get($pk) ?? $request->post($pk); + $row = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->where('data_recycle_log.id', $id) + ->find(); + if (!$row) { + return $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; + + return $this->success('', ['row' => $row]); + } + + protected function jsonToArray(mixed $value = ''): mixed + { + 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; + } +} diff --git a/app/admin/controller/security/SensitiveData.php b/app/admin/controller/security/SensitiveData.php new file mode 100644 index 0000000..db8b112 --- /dev/null +++ b/app/admin/controller/security/SensitiveData.php @@ -0,0 +1,182 @@ +model = new SensitiveDataModel(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') || $request->post('select')) { + return $this->select($request); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $items = $res->items(); + foreach ($items as $item) { + if ($item->data_fields) { + $fields = []; + foreach ($item->data_fields as $key => $field) { + $fields[] = $field ?: $key; + } + $item->data_fields = $fields; + } + } + + return $this->success('', [ + 'list' => $items, + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() !== 'POST') { + return $this->success('', ['controllers' => $this->getControllerList()]); + } + + $data = $request->post(); + if (!$data) { + return $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'])); + + if (is_array($data['fields'] ?? null)) { + $data['data_fields'] = []; + foreach ($data['fields'] as $field) { + $data['data_fields'][$field['name']] = $field['value']; + } + } + + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + $validate->scene('add')->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (\Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Added successfully')) : $this->error(__('No rows were added')); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->get($pk) ?? $request->post($pk); + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + if ($request->method() !== 'POST') { + return $this->success('', [ + 'row' => $row, + 'controllers' => $this->getControllerList(), + ]); + } + + $data = $request->post(); + if (!$data) { + return $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'])); + + if (is_array($data['fields'] ?? null)) { + $data['data_fields'] = []; + foreach ($data['fields'] as $field) { + $data['data_fields'][$field['name']] = $field['value']; + } + } + + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + $validate->scene('edit')->check(array_merge($data, [$pk => $row[$pk]])); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (\Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Update successful')) : $this->error(__('No rows updated')); + } + + private 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; + } +} diff --git a/app/admin/controller/security/SensitiveDataLog.php b/app/admin/controller/security/SensitiveDataLog.php new file mode 100644 index 0000000..50f22b9 --- /dev/null +++ b/app/admin/controller/security/SensitiveDataLog.php @@ -0,0 +1,102 @@ +model = new SensitiveDataLogModel(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') || $request->post('select')) { + return $this->select($request); + } + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $res = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->alias($alias) + ->where($where) + ->order($order) + ->paginate($limit); + + $items = $res->items(); + foreach ($items as $item) { + $item->id_value = $item['primary_key'] . '=' . $item->id_value; + } + + return $this->success('', [ + 'list' => $items, + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + public function info(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->get($pk) ?? $request->post($pk); + $row = $this->model + ->withJoin($this->withJoinTable, $this->withJoinType) + ->where('security_sensitive_data_log.id', $id) + ->find(); + if (!$row) { + return $this->error(__('Record not found')); + } + return $this->success('', ['row' => $row]); + } + + public function rollback(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $ids = $request->post('ids', $request->get('ids', [])); + $ids = is_array($ids) ? $ids : []; + $data = $this->model->where('id', 'in', $ids)->select(); + if (!$data) { + return $this->error(__('Record not found')); + } + + $count = 0; + $this->model->startTrans(); + try { + foreach ($data as $row) { + $conn = Db::connect(TableManager::getConnection($row->connection)); + if ($conn->name($row->data_table)->where($row->primary_key, $row->id_value)->update([$row->data_field => $row->before])) { + $count++; + } + } + $this->model->commit(); + } catch (\Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $count ? $this->success(__('Rollback successful')) : $this->error(__('No rows were rolled back')); + } +} diff --git a/app/admin/controller/user/Group.php b/app/admin/controller/user/Group.php new file mode 100644 index 0000000..af00ee2 --- /dev/null +++ b/app/admin/controller/user/Group.php @@ -0,0 +1,150 @@ +model = new UserGroup(); + return null; + } + + public function select(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + list($where, $alias, $limit, $order) = $this->queryBuilder(); + $data = $this->model + ->alias($alias) + ->where($where) + ->order($order) + ->limit(9999) + ->select() + ->toArray(); + + return $this->success('', [ + 'options' => $data, + ]); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() !== 'POST') { + return $this->error(__('Parameter error')); + } + + $data = $request->post(); + if (!$data) { + return $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) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + $validate->scene('add')->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Added successfully')) : $this->error(__('No rows were added')); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->post($pk) ?? $request->get($pk); + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $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) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + $validate->scene('edit')->check(array_merge($data, [$pk => $row[$pk]])); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Update successful')) : $this->error(__('No rows updated')); + } + + $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]); + } + } + $rowData = $row->toArray(); + $rowData['rules'] = array_values($rules); + return $this->success('', ['row' => $rowData]); + } + + private function handleRules(array $data): array + { + if (isset($data['rules']) && is_array($data['rules']) && $data['rules']) { + $rules = UserRule::select(); + $super = true; + foreach ($rules as $rule) { + if (!in_array($rule['id'], $data['rules'])) { + $super = false; + break; + } + } + $data['rules'] = $super ? '*' : implode(',', $data['rules']); + } else { + unset($data['rules']); + } + return $data; + } +} diff --git a/app/admin/controller/user/MoneyLog.php b/app/admin/controller/user/MoneyLog.php new file mode 100644 index 0000000..c2d628d --- /dev/null +++ b/app/admin/controller/user/MoneyLog.php @@ -0,0 +1,43 @@ +model = new UserMoneyLog(); + return null; + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + return $this->_add(); + } + + $userId = $request->get('userId', $request->post('userId', 0)); + $user = User::where('id', $userId)->find(); + if (!$user) { + return $this->error(__("The user can't find it")); + } + return $this->success('', ['user' => $user]); + } +} diff --git a/app/admin/controller/user/Rule.php b/app/admin/controller/user/Rule.php new file mode 100644 index 0000000..5647fcb --- /dev/null +++ b/app/admin/controller/user/Rule.php @@ -0,0 +1,98 @@ + 'desc']; + protected array|string $quickSearchField = 'title'; + + protected function initController(Request $request): ?Response + { + $this->model = new UserRule(); + $this->tree = Tree::instance(); + $isTree = filter_var($request->get('isTree', $request->post('isTree', true)), FILTER_VALIDATE_BOOLEAN); + $initValue = $request->get('initValue') ?? $request->post('initValue') ?? []; + $this->initValue = is_array($initValue) ? array_filter($initValue) : []; + $this->keyword = $request->get('quickSearch', $request->post('quickSearch', '')); + $this->assembleTree = $isTree && !$this->initValue; + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') || $request->post('select')) { + return $this->select($request); + } + + list($where, , , ) = $this->queryBuilder(); + $list = $this->model->where($where)->order($this->defaultSortField)->select(); + + if ($this->assembleTree) { + $list = $this->tree->assembleChild($list->toArray()); + } else { + $list = $list->toArray(); + } + + return $this->success('', [ + 'list' => $list, + 'remark' => get_route_remark(), + ]); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + return $this->_add(); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + return $this->_edit(); + } + + public function del(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + return $this->_del(); + } + + public function select(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + list($where, , , ) = $this->queryBuilder(); + $list = $this->model->where($where)->order($this->defaultSortField)->select(); + + if ($this->assembleTree) { + $list = $this->tree->assembleChild($list->toArray()); + } else { + $list = $list->toArray(); + } + + return $this->success('', ['list' => $list]); + } +} diff --git a/app/admin/controller/user/ScoreLog.php b/app/admin/controller/user/ScoreLog.php new file mode 100644 index 0000000..f065ad8 --- /dev/null +++ b/app/admin/controller/user/ScoreLog.php @@ -0,0 +1,43 @@ +model = new UserScoreLog(); + return null; + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + return $this->_add(); + } + + $userId = $request->get('userId', $request->post('userId', 0)); + $user = User::where('id', $userId)->find(); + if (!$user) { + return $this->error(__("The user can't find it")); + } + return $this->success('', ['user' => $user]); + } +} diff --git a/app/admin/controller/user/User.php b/app/admin/controller/user/User.php new file mode 100644 index 0000000..37909e8 --- /dev/null +++ b/app/admin/controller/user/User.php @@ -0,0 +1,161 @@ +model = new UserModel(); + return null; + } + + public function index(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->get('select') || $request->post('select')) { + return $this->select($request); + } + + 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); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + public function add(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + if ($request->method() !== 'POST') { + return $this->error(__('Parameter error')); + } + + $data = $request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + $passwd = $data['password'] ?? ''; + $data = $this->excludeFields($data); + + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + if ($this->modelSceneValidate) $validate->scene('add'); + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + if ($passwd) { + $this->model->resetPassword($this->model->id, $passwd); + } + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Added successfully')) : $this->error(__('No rows were added')); + } + + public function edit(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + $pk = $this->model->getPk(); + $id = $request->post($pk) ?? $request->get($pk); + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + return $this->error(__('You have no permission')); + } + + if ($request->method() === 'POST') { + $data = $request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + if (!empty($data['password'])) { + $this->model->resetPassword($row->id, $data['password']); + } + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + $validateClass = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validateClass)) { + $validate = new $validateClass(); + $validate->scene('edit')->check(array_merge($data, [$pk => $row[$pk]])); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + return $result !== false ? $this->success(__('Update successful')) : $this->error(__('No rows updated')); + } + + unset($row['password'], $row['salt']); + $row['password'] = ''; + return $this->success('', ['row' => $row]); + } + + public function select(Request $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + + 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); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + ]); + } +} diff --git a/app/admin/lang/en.php b/app/admin/lang/en.php new file mode 100644 index 0000000..087e8a8 --- /dev/null +++ b/app/admin/lang/en.php @@ -0,0 +1,98 @@ + 'Please login first', + 'No background menu, please contact super administrator!' => '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. There is no need to log in again~', + 'Login succeeded!' => 'Login succeeded!', + 'Incorrect user name or password!' => 'Incorrect username or password!', + 'Login' => 'Login', + 'Logout' => 'Logout', + 'Please input correct password' => 'Please enter the correct password', + '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', + 'Super administrator' => 'Super administrator', + 'No permission' => 'No permission', + '%first% etc. %count% items' => '%first% etc. %count% items', + 'Please select rules' => 'Please select rules', + 'You cannot modify your own management group!' => '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 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~' => '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!' => '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' => 'The group permission node exceeds the range that can be allocated, please refresh and try again~', + '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.', + 'Please use the %s field to sort before operating' => 'Please use the %s field to sort before operating', + 'Topic format error' => 'Upload storage subdirectory format error!', + 'Driver %s not supported' => 'Driver %s not supported', + 'Configuration write failed: %s' => 'Configuration write failed: %s', + 'Token expiration' => 'Token expired, please login again!', + 'Method not allowed' => 'Method not allowed', + 'Variable name' => 'Variable name', + 'type' => 'Type', + 'title' => 'Title', + 'name' => 'Name', + 'user_id' => 'User ID', + 'score' => 'Score', + 'memo' => 'Memo', + 'money' => 'Money', + 'Rollback successful' => 'Rollback successful!', + 'No rows were rolled back' => 'No rows were rolled back', + 'Avatar modified successfully!' => 'Avatar modified successfully!', + 'Failed to load cloud data' => 'Failed to load cloud data', + 'Log start' => 'Log start', + 'Parse field data' => 'Parse field data', + 'Generate check' => 'Generate check', + 'Install module' => 'Install module', + 'Change module state' => 'Change module state', + 'Uninstall module' => 'Uninstall module', + 'Upload module' => 'Upload module', + 'upload' => 'Upload', + 'Data table does not exist' => 'Data table does not exist', + 'Change terminal config' => 'Change terminal config', + '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', + 'Clear cache' => 'Clear cache', + 'The current page configuration item was updated successfully' => 'The current page configuration item was updated 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, receiving this email means that your email service has been configured correctly', + 'Test mail sent successfully~' => 'Test mail sent successfully~', + 'Name' => 'Name', + 'Data Fields' => 'Data Fields', + 'Controller' => 'Controller', + 'Data Table' => 'Data Table', + 'Primary Key' => 'Primary Key', + 'Restore successful' => 'Restore successful!', + 'No rows were restore' => 'No rows were restored', + '%d records and files have been deleted' => '%d records and files have been deleted', + 'Please input correct username' => 'Please enter the correct username', + 'Group Name Arr' => 'Group Name Arr', +]; \ 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..1a80451 --- /dev/null +++ b/app/admin/lang/en/auth/group.php @@ -0,0 +1,13 @@ + 'Group name', + 'Please select rules' => 'Please select rules', + 'Super administrator' => 'Super administrator', + 'No permission' => 'No permission', + 'You cannot modify your own management group!' => '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 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~' => '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!' => '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' => 'The group permission node exceeds the range that can be allocated, please refresh and try again~', + 'Remark lang' => 'For system security, the hierarchical relationship of role groups is for reference only. The actual hierarchy is determined by the number of permission nodes: same permissions = peer, containing and having additional permissions = superior. Peers cannot manage peers; superiors can assign their permission nodes to subordinates. For special cases where an admin needs to become a superior, create a virtual permission node.', +]; 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..1445196 --- /dev/null +++ b/app/admin/lang/zh-cn.php @@ -0,0 +1,117 @@ + '请先登录!', + 'No background menu, please contact super administrator!' => '无后台菜单,请联系超级管理员!', + 'You have already logged in. There is no need to log in again~' => '您已经登录过了,无需重复登录~', + 'Login succeeded!' => '登录成功!', + 'Incorrect user name or password!' => '用户名或密码不正确!', + 'Login' => '登录', + 'Logout' => '注销登录', + 'Please input correct password' => '请输入正确的密码', + '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 + 'Super administrator' => '超级管理员', + 'No permission' => '无权限', + '%first% etc. %count% items' => '%first% 等 %count% 项', + 'Please select rules' => '请选择权限', + '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' => '分组权限节点超出可分配范围,请刷新重试~', + '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' => '登录态过期,请重新登录!', + 'Method not allowed' => '方法不允许', + 'Variable name' => '变量名', + 'type' => '类型', + 'title' => '标题', + 'name' => '名称', + 'user_id' => '用户ID', + 'score' => '积分', + 'memo' => '备注', + 'money' => '金额', + 'Rollback successful' => '回滚成功!', + 'No rows were rolled back' => '未回滚任何行', + 'Avatar modified successfully!' => '头像修改成功!', + 'Failed to load cloud data' => '加载云端数据失败', + 'Log start' => '日志开始', + 'Parse field data' => '解析字段数据', + 'Generate check' => '生成校验', + 'Install module' => '安装模块', + 'Change module state' => '修改模块状态', + 'Uninstall module' => '卸载模块', + 'Upload module' => '上传模块', + 'upload' => '上传', + 'Data table does not exist' => '数据表不存在', + 'Change terminal config' => '修改终端配置', + 'Failed to modify the terminal configuration. Please modify the configuration file manually:%s' => '修改终端配置失败,请手动修改配置文件:%s', + 'Clear cache' => '清除缓存', + 'The current page configuration item was updated successfully' => '当前页配置项更新成功!', + 'This is a test email' => '这是一封测试邮件', + 'Congratulations, receiving this email means that your email service has been configured correctly' => '恭喜,收到此邮件说明您的邮件服务已配置正确', + 'Test mail sent successfully~' => '测试邮件发送成功~', + 'Name' => '名称', + 'Data Fields' => '数据字段', + 'Controller' => '控制器', + 'Data Table' => '数据表', + 'Primary Key' => '主键', + 'Restore successful' => '恢复成功!', + 'No rows were restore' => '未恢复任何行', + '%d records and files have been deleted' => '已删除%d条记录和文件', + 'Please input correct username' => '请输入正确的用户名', + 'Group Name Arr' => '分组名称数组', +]; \ 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..97c8e07 --- /dev/null +++ b/app/admin/library/Auth.php @@ -0,0 +1,369 @@ +setKeepTime((int) config('buildadmin.admin_token_keep_time', 86400 * 3)); + } + + public function __get($name): mixed + { + return $this->model?->$name; + } + + /** + * 初始化(Webman:从 request 获取或创建新实例) + */ + public static function instance(array $options = []): Auth + { + $request = function_exists('request') ? request() : null; + if ($request !== null && isset($request->adminAuth) && $request->adminAuth instanceof Auth) { + return $request->adminAuth; + } + $auth = new static($options); + if ($request !== null) { + $request->adminAuth = $auth; + } + return $auth; + } + + public function init(string $token): bool + { + $tokenData = Token::get($token); + if ($tokenData) { + Token::tokenExpirationCheck($tokenData); + + $userId = (int) $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; + } + + 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; + } + + $adminLoginRetry = config('buildadmin.admin_login_retry'); + if ($adminLoginRetry) { + $lastLoginTime = $this->model->getData('last_login_time'); + if ($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; + } + + if (config('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); + } + if (!$this->loginSuccessful()) { + return false; + } + return true; + } + + public function setRefreshToken(int $keepTime = 0): void + { + $this->refreshToken = Random::uuid(); + Token::set($this->refreshToken, self::TOKEN_TYPE . '-refresh', $this->model->id, $keepTime); + } + + 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 = function_exists('request') && request() ? request()->getRealIp() : ''; + $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; + } + + 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 = function_exists('request') && request() ? request()->getRealIp() : ''; + $this->model->save(); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + } + return $this->reset(); + } + + public function logout(): bool + { + if (!$this->loginEd) { + $this->setError('You are not logged in'); + return false; + } + return $this->reset(); + } + + public function isLogin(): bool + { + return $this->loginEd; + } + + public function getAdmin(): Admin + { + return $this->model; + } + + public function getToken(): string + { + return $this->token; + } + + public function getRefreshToken(): string + { + return $this->refreshToken; + } + + public function getInfo(): array + { + if (!$this->model) { + return []; + } + $info = $this->model->toArray(); + $info = array_intersect_key($info, array_flip($this->getAllowFields())); + // 与 ThinkPHP 一致:token 为主认证令牌,refresh_token 仅 keep=true 时有值 + $token = $this->token; + if (!$token && $this->loginEd) { + $token = Random::uuid(); + Token::set($token, self::TOKEN_TYPE, $this->model->id, $this->keepTime); + $this->token = $token; + } + $info['token'] = $token ?: ''; + $info['refresh_token'] = $this->refreshToken ?: ''; + // last_login_time 与 ThinkPHP 一致返回整数时间戳 + if (isset($info['last_login_time'])) { + $info['last_login_time'] = (int) $info['last_login_time']; + } + return $info; + } + + public function getAllowFields(): array + { + return $this->allowFields; + } + + public function setAllowFields($fields): void + { + $this->allowFields = $fields; + } + + 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); + } + + public function isSuperAdmin(): bool + { + return in_array('*', $this->getRuleIds()); + } + + 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); + } + + 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); + } + } + + public function getGroupAdmins(array $groups): array + { + return Db::name('admin_group_access') + ->where('group_id', 'in', $groups) + ->column('uid'); + } + + 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']); + $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; + } + + public function setError($error): Auth + { + $this->error = $error; + return $this; + } + + 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('buildadmin.admin_token_keep_time', 86400 * 3)); + return true; + } +} diff --git a/app/admin/library/crud/Helper.php b/app/admin/library/crud/Helper.php new file mode 100644 index 0000000..c5f1761 --- /dev/null +++ b/app/admin/library/crud/Helper.php @@ -0,0 +1,928 @@ + [ + 'user' => ['user', 'user'], + 'admin' => ['auth', 'admin'], + 'admin_group' => ['auth', 'group'], + 'attachment' => ['routine', 'attachment'], + 'admin_rule' => ['auth', 'rule'], + ], + 'model' => [], + 'validate' => [], + ]; + + 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], + ]; + + 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'], + ['type' => ['longtext', 'text', 'mediumtext', 'smalltext', 'tinytext', 'bigtext'], 'suffix' => ['content', 'editor'], 'value' => 'editor'], + ['type' => ['varchar'], 'suffix' => ['textarea', 'multiline', 'rows'], 'value' => 'textarea'], + ['suffix' => ['array'], 'value' => 'array'], + ['type' => ['int'], 'suffix' => ['time', 'datetime'], 'value' => 'timestamp'], + ['type' => ['datetime', 'timestamp'], 'value' => 'datetime'], + ['type' => ['date'], 'value' => 'date'], + ['type' => ['year'], 'value' => 'year'], + ['type' => ['time'], 'value' => 'time'], + ['suffix' => ['select', 'list', 'data'], 'value' => 'select'], + ['suffix' => ['selects', 'multi', 'lists'], 'value' => 'selects'], + ['suffix' => ['_id'], 'value' => 'remoteSelect'], + ['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'], + ['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'], + ]; + + protected static array $parseWebDirPresets = [ + 'lang' => [], + 'views' => [ + 'user' => ['user', 'user'], + 'admin' => ['auth', 'admin'], + 'admin_group' => ['auth', 'group'], + 'attachment' => ['routine', 'attachment'], + 'admin_rule' => ['auth', 'rule'], + ], + ]; + + protected static string $createTimeField = 'create_time'; + protected static string $updateTimeField = 'update_time'; + + protected static array $attrType = [ + 'controller' => [ + 'preExcludeFields' => 'array|string', + 'quickSearchField' => 'string|array', + 'withJoinTable' => 'array', + 'defaultSortField' => 'string|array', + 'weighField' => 'string', + ], + ]; + + 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; + } + + 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('thinkorm.default', config('database.default', 'mysql')); + $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; + } + + 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]; + } + + 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'] ?? 'NONE') { + 'EMPTY STRING' => '', + 'NULL' => null, + default => $field['default'] ?? null, + }; + } + + 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; + } + + public static function getPhinxFieldData(array $field): array + { + $conciseType = self::analyseFieldType($field); + $phinxTypeData = self::getPhinxFieldType($conciseType, $field); + $phinxColumnOptions = self::analyseFieldLimit($conciseType, $field); + if ($phinxTypeData['limit'] !== null) { + $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'] ?? false); + $phinxColumnOptions['comment'] = $field['comment'] ?? ''; + $phinxColumnOptions['signed'] = !($field['unsigned'] ?? false); + $phinxColumnOptions['identity'] = $field['autoIncrement'] ?? false; + return ['type' => $phinxTypeData['type'], 'options' => $phinxColumnOptions]; + } + + 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, fn($f) => $f['name'] == $fieldName); + if (!$field) continue; + $phinxFieldData = self::getPhinxFieldData($field); + $phinxFieldData['options']['after'] = $item['after'] == 'FIRST FIELD' ? MysqlAdapter::FIRST : $item['after']; + $table->changeColumn($fieldName, $phinxFieldData['type'], $phinxFieldData['options']); + } + } + $table->update(); + } + } + + public static function handleTableDesign(array $table, array $fields): array + { + $name = TableManager::tableName($table['name'], true, $table['databaseConnection'] ?? null); + $comment = $table['comment'] ?? ''; + $designChange = $table['designChange'] ?? []; + $adapter = TableManager::phinxAdapter(false, $table['databaseConnection'] ?? null); + + $pk = self::searchArray($fields, fn($item) => $item['primaryKey'] ?? false); + $pk = $pk ? $pk['name'] : ''; + + if ($adapter->hasTable($name)) { + if ($designChange) { + $tableManager = TableManager::phinxTable($name, [], false, $table['databaseConnection'] ?? null); + $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']])); + } + $field = self::searchArray($fields, fn($f) => $f['name'] == $item['oldName']); + if ($field) { + $phinxFieldData = self::getPhinxFieldData($field); + $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']])); + } + $field = self::searchArray($fields, fn($f) => $f['name'] == $item['newName']); + if ($field) { + $phinxFieldData = self::getPhinxFieldData($field); + $tableManager->addColumn($item['newName'], $phinxFieldData['type'], $phinxFieldData['options']); + } + } + } + $tableManager->update(); + self::updateFieldOrder($name, $fields, $designChange, $table['databaseConnection'] ?? null); + } + } else { + $tableManager = TableManager::phinxTable($name, [ + 'id' => false, 'comment' => $comment, 'row_format' => 'DYNAMIC', + 'primary_key' => $pk, 'collation' => 'utf8mb4_unicode_ci', + ], false, $table['databaseConnection'] ?? null); + foreach ($fields as $field) { + $phinxFieldData = self::getPhinxFieldData($field); + $tableManager->addColumn($field['name'], $phinxFieldData['type'], $phinxFieldData['options']); + } + $tableManager->create(); + } + return [$pk]; + } + + 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 = root_path() . 'app' . DIRECTORY_SEPARATOR . $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 (isset(self::$parseWebDirPresets[$type]) && 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]); + foreach (['en', 'zh-cn'] 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; + } + + public static function getMenuName(array $webDir): string + { + return ($webDir['path'] ? implode('/', $webDir['path']) . '/' : '') . $webDir['originalLastName']; + } + + public static function getStubFilePath(string $name): string + { + return root_path() . 'app' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR . 'library' . DIRECTORY_SEPARATOR . 'crud' . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . Filesystem::fsFit($name) . '.stub'; + } + + public static function arrayToString(mixed $value): string + { + if (is_array($value)) { + foreach ($value as &$item) { + $item = self::arrayToString($item); + } + return implode(PHP_EOL, $value); + } + if (is_string($value)) return $value; + if (is_bool($value)) return $value ? 'true' : 'false'; + return $value === null ? '' : strval($value); + } + + 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; + } + + public static function escape(array|string $value): string + { + if (is_array($value)) { + $value = json_encode($value, JSON_UNESCAPED_UNICODE); + } + return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8', false); + } + + public static function tab(int $num = 1): string + { + return str_pad('', 4 * $num); + } + + 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'; + + $tableColumn = Db::connect($connection)->query($sql, [$connectionConfig['database'], TableManager::tableName($table, true, $connection)]); + + $columns = []; + 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 && $item['COLUMN_DEFAULT'] === null) { + $defaultType = 'NULL'; + } elseif ($item['COLUMN_DEFAULT'] == '' && in_array($item['DATA_TYPE'], ['varchar', 'char'])) { + $defaultType = 'EMPTY STRING'; + } elseif (!$isNullAble && $item['COLUMN_DEFAULT'] === null) { + $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 + { + } + + 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); + } + + 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'])) { + return "$conciseType({$limit['precision']}, {$limit['scale']})"; + } + if (isset($limit['values'])) { + return "$conciseType(" . implode(',', $limit['values']) . ")"; + } + return "$conciseType({$limit['limit']})"; + } + + 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): string + { + if (stripos($column['COLUMN_NAME'], 'id') !== false && stripos($column['EXTRA'], 'auto_increment') !== false) { + return 'pk'; + } + if ($column['COLUMN_NAME'] == 'weigh') return 'weigh'; + if (in_array($column['COLUMN_NAME'], ['createtime', 'updatetime', 'create_time', 'update_time'])) return 'timestamp'; + + foreach (self::$inputTypeRule as $item) { + $typeBool = !isset($item['type']) || !$item['type'] || in_array($column['DATA_TYPE'], $item['type']); + $suffixBool = !isset($item['suffix']) || !$item['suffix'] || self::isMatchSuffix($column['COLUMN_NAME'], $item['suffix']); + $columnTypeBool = !isset($item['column_type']) || !$item['column_type'] || in_array($column['COLUMN_TYPE'], $item['column_type']); + if ($typeBool && $suffixBool && $columnTypeBool) { + return $item['value']; + } + } + return 'string'; + } + + 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; + } + + 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 ''; + return "\n" . self::tab() . "// 追加属性\n" . self::tab() . "protected \$append = " . self::buildFormatSimpleArray($append) . ";\n"; + } + + public static function buildModelFieldType(array $fieldType): string + { + if (!$fieldType) return ''; + $maxStrLang = 0; + foreach ($fieldType as $key => $item) { + $maxStrLang = max(strlen($key), $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('thinkorm.default', config('database.default', 'mysql'))) { + $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'] ?? []); + + if (isset($modelData['beforeInsertMixins']['snowflake'])) { + $modelData['beforeInsert'] = self::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, ', ') . '])'; + $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 = 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 = isset($field['form']['validatorMsg']) && $field['form']['validatorMsg'] ? ", 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'] ?? ['undefined']); + $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, ',') . " },\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, ',') . ' },'; + } elseif ($item === 'false' || $item === 'true') { + $itemJson = ' ' . $key . ': ' . $item . ','; + } elseif (in_array($key, ['label', 'width', 'buttons'], true) || str_starts_with((string)$item, "t('") || str_starts_with((string)$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; + } + $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((string)$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((string)$item); + $str .= "$quote$item$quote, "; + } + } + return '[' . rtrim($str, ", ") . ']'; + } + + public static function buildDefaultOrder(string $field, string $type): string + { + if ($field && $type) { + $defaultOrderStub = self::getJsonFromArray(['prop' => $field, 'order' => $type]); + 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((string)$item, "t('") || str_starts_with((string)$item, 't("') || $item == '[]' || in_array(gettype($item), ['integer', 'double'])) { + $jsonStr .= $keyStr . $item . ','; + } elseif (isset($item[0]) && $item[0] == '[' && str_ends_with((string)$item, ']')) { + $jsonStr .= $keyStr . $item . ','; + } else { + $quote = self::getQuote((string)$item); + $jsonStr .= $keyStr . "$quote$item$quote,"; + } + } + return $jsonStr ? '{' . rtrim($jsonStr, ',') . ' }' : '{}'; + } + return $arr; + } +} 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..942eab6 --- /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..2f66e89 --- /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 = \support\think\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..82b997f --- /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..d7d21c8 --- /dev/null +++ b/app/admin/library/module/Manage.php @@ -0,0 +1,900 @@ +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); + } else { + $this->uid = ''; + $this->modulesDir = $this->installDir; + } + } + + public function getInstallState(): int + { + 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; + } + + /** + * 从 Webman Request 上传安装(适配 Multipart 上传) + * @return array 模块基本信息 + * @throws Throwable + */ + public static function uploadFromRequest(Request $request): array + { + $file = $request->file('file'); + if (!$file) { + throw new Exception('Parameter error'); + } + $token = $request->post('token', $request->get('token', '')); + if (!$token) { + throw new Exception('Please login to the official website account first'); + } + $uploadDir = root_path() . 'public' . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'upload' . DIRECTORY_SEPARATOR; + if (!is_dir($uploadDir)) { + mkdir($uploadDir, 0755, true); + } + $saveName = 'temp' . DIRECTORY_SEPARATOR . date('YmdHis') . '_' . ($file->getUploadName() ?? 'module.zip'); + $savePath = $uploadDir . $saveName; + $saveDir = dirname($savePath); + if (!is_dir($saveDir)) { + mkdir($saveDir, 0755, true); + } + $file->move($savePath); + $relativePath = 'storage/upload/' . str_replace(DIRECTORY_SEPARATOR, '/', $saveName); + try { + return self::instance('')->doUpload($token, $relativePath); + } finally { + if (is_file($savePath)) { + @unlink($savePath); + } + } + } + + /** + * 下载模块文件 + * @throws Throwable + */ + public function download(): string + { + $req = function_exists('request') ? request() : null; + $token = $req ? ($req->post('token', $req->get('token', ''))) : ''; + $version = $req ? ($req->post('version', $req->get('version', ''))) : ''; + $orderId = $req ? ($req->post('orderId', $req->get('orderId', 0))) : 0; + + if (!$orderId) { + throw new Exception('Order not found'); + } + + $zipFile = Server::download($this->uid, $this->installDir, [ + 'version' => $version, + 'orderId' => $orderId, + 'nuxtVersion' => Server::getNuxtVersion(), + 'sysVersion' => config('buildadmin.version', ''), + 'installed' => Server::getInstalledIds($this->installDir), + 'ba-user-token' => $token, + ]); + + Filesystem::delDir($this->modulesDir); + Filesystem::unzip($zipFile); + @unlink($zipFile); + + $this->checkPackage(); + + $this->setInfo([ + 'state' => self::WAIT_INSTALL, + ]); + + return $zipFile; + } + + /** + * 上传安装(token + 文件相对路径) + * @throws Throwable + */ + public function doUpload(string $token, string $file): array + { + $file = Filesystem::fsFit(root_path() . 'public' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $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; + + @unlink($file); + @unlink($copyTo); + + $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'] ?? '0.0.0'); + 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('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; + } + + /** + * 安装模块 + * @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'); + } + 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(); + } + } + + Server::importSql($this->modulesDir); + + $info = $this->getInfo(); + if ($update) { + $info['update'] = 1; + Server::execEvent($this->uid, 'update'); + } + + $req = function_exists('request') ? request() : null; + $extend = $req ? ($req->post('extend') ?? []) : []; + 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'] ?? 0) != self::DISABLE) { + throw new Exception('Please disable the module first', 0, [ + 'uid' => $this->uid, + ]); + } + + Server::execEvent($this->uid, 'uninstall'); + + Filesystem::delDir($this->modulesDir); + } + + /** + * 修改模块状态 + * @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'] ?? 0, $canDisable)) { + throw new Exception('The current state of the module cannot be set to disabled', 0, [ + 'uid' => $this->uid, + 'state' => $info['state'] ?? 0, + ]); + } + return $this->disable(); + } + + if (($info['state'] ?? 0) != self::DISABLE) { + throw new Exception('The current state of the module cannot be set to enabled', 0, [ + 'uid' => $this->uid, + 'state' => $info['state'] ?? 0, + ]); + } + $this->setInfo([ + 'state' => self::WAIT_INSTALL, + ]); + return $info; + } + + /** + * 启用 + * @throws Throwable + */ + public function enable(string $trigger): void + { + Server::installWebBootstrap($this->uid, $this->modulesDir); + Server::createRuntime($this->modulesDir); + $this->conflictHandle($trigger); + Server::execEvent($this->uid, 'enable'); + $this->dependUpdateHandle(); + } + + /** + * 禁用 + * @throws Throwable + */ + public function disable(): array + { + $req = function_exists('request') ? request() : null; + $update = $req ? filter_var($req->post('update', false), FILTER_VALIDATE_BOOLEAN) : false; + $confirmConflict = $req ? filter_var($req->post('confirmConflict', false), FILTER_VALIDATE_BOOLEAN) : false; + $dependConflictSolution = $req ? ($req->post('dependConflictSolution') ?? []) : []; + + $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); + } + } + + $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())); + + 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->getPathname(), $backupsFile); + } + } + } + + if ($zipDir && is_dir($zipDir)) { + Filesystem::delDir($zipDir); + } + + Server::uninstallWebBootstrap($this->uid); + + $this->setInfo([ + 'state' => self::DISABLE, + ]); + + if ($update) { + throw new Exception('update', -3, [ + 'uid' => $this->uid, + ]); + } + + if (!empty($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 (!in_array($info['state'] ?? 0, [self::WAIT_INSTALL, 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'); + + $req = function_exists('request') ? request() : null; + $extend = $req ? ($req->post('extend') ?? []) : []; + + if ($fileConflict || !self::isEmptyArray($dependConflict)) { + 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; + + $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; + } + $info = $info ?? $this->getInfo(); + if (($info['state'] ?? 0) != 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->getPathname(), $destDirItem); + } + } + if (config('buildadmin.module_pure_install', false)) { + Filesystem::delDir($baseDir); + } + } + return true; + } + + /** + * 依赖升级处理 + * @throws Throwable + */ + public function dependUpdateHandle(): void + { + $info = $this->getInfo(); + if (($info['state'] ?? 0) == 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'] ?? 0) == 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); + } + } + + 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); + } + if ($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)) { + if (!self::isEmptyArray($item)) 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; + } +} diff --git a/app/admin/library/module/Server.php b/app/admin/library/module/Server.php new file mode 100644 index 0000000..6da5fd0 --- /dev/null +++ b/app/admin/library/module/Server.php @@ -0,0 +1,551 @@ +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; + } + + /** + * 获取模块[冲突]文件列表 + */ + 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 = ''; + $prefix = config('thinkorm.connections.mysql.prefix', config('database.connections.mysql.prefix', '')); + 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__', $prefix, $tempLine); + $tempLine = str_ireplace('INSERT INTO ', 'INSERT IGNORE INTO ', $tempLine); + try { + Db::execute($tempLine); + } catch (PDOException) { + // ignore + } + $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; + } + + 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; + } + + /** + * @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); + } + } + } + + 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; + } + + 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]) && isset($filePaths[$key]) && is_file($filePaths[$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); + } + } + } + } + + 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 (!isset($filePaths[$item]) || !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 ?? false) !== false || ($moduleMultiLineMarkStartPos ?? false) !== false) { + file_put_contents($filePaths[$item], $content); + } + } + } + + 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(): mixed + { + $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; + } + + 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('buildadmin.module_pure_install', false), + ])); + } + + 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] ?? []; + } + return $runtimeContentArr; + } +} diff --git a/app/admin/library/traits/Backend.php b/app/admin/library/traits/Backend.php new file mode 100644 index 0000000..5f2fb28 --- /dev/null +++ b/app/admin/library/traits/Backend.php @@ -0,0 +1,307 @@ +preExcludeFields)) { + $this->preExcludeFields = explode(',', (string) $this->preExcludeFields); + } + + $exclude = array_merge( + $this->preExcludeFields, + ['create_time', 'update_time', 'createtime', 'updatetime'] + ); + foreach ($exclude as $field) { + $field = trim($field); + if ($field !== '' && array_key_exists($field, $params)) { + unset($params[$field]); + } + } + return $params; + } + + /** + * 查看(内部实现,由 Backend::index(Request) 调用) + */ + protected function _index(): Response + { + if ($this->request && $this->request->get('select')) { + return $this->select($this->request); + } + + 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); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + 'remark' => get_route_remark(), + ]); + } + + /** + * 递归应用输入过滤(如 clean_xss) + */ + protected function applyInputFilter(array $data): array + { + if (!$this->inputFilter || !function_exists($this->inputFilter)) { + return $data; + } + $filter = $this->inputFilter; + foreach ($data as $k => $v) { + if (is_string($v)) { + $data[$k] = call_user_func($filter, $v); + } elseif (is_array($v)) { + $data[$k] = $this->applyInputFilter($v); + } + } + return $data; + } + + /** + * 添加(内部实现) + */ + protected function _add(): Response + { + if ($this->request && $this->request->method() === 'POST') { + $data = $this->request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->applyInputFilter($data); + $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(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Added successfully')); + } + return $this->error(__('No rows were added')); + } + + return $this->error(__('Parameter error')); + } + + /** + * 编辑(内部实现) + */ + protected function _edit(): Response + { + $pk = $this->model->getPk(); + $id = $this->request ? ($this->request->post($pk) ?? $this->request->get($pk)) : null; + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + return $this->error(__('You have no permission')); + } + + if ($this->request && $this->request->method() === 'POST') { + $data = $this->request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->applyInputFilter($data); + $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(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Update successful')); + } + return $this->error(__('No rows updated')); + } + + return $this->success('', [ + 'row' => $row + ]); + } + + /** + * 删除(内部实现) + */ + protected function _del(): Response + { + $where = []; + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds) { + $where[] = [$this->dataLimitField, 'in', $dataLimitAdminIds]; + } + + $ids = $this->request ? ($this->request->post('ids') ?? $this->request->get('ids') ?? []) : []; + $ids = is_array($ids) ? $ids : []; + $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(); + return $this->error($e->getMessage()); + } + if ($count) { + return $this->success(__('Deleted successfully')); + } + return $this->error(__('No rows were deleted')); + } + + /** + * 排序 - 增量重排法(内部实现) + */ + protected function _sortable(): Response + { + $pk = $this->model->getPk(); + $move = $this->request ? $this->request->post('move') ?? $this->request->get('move') : null; + $target = $this->request ? $this->request->post('target') ?? $this->request->get('target') : null; + $order = $this->request ? ($this->request->post('order') ?? $this->request->get('order')) : null; + $order = $order ?: $this->defaultSortField; + $direction = $this->request ? ($this->request->post('direction') ?? $this->request->get('direction')) : null; + + $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) { + return $this->error(__('Record not found')); + } + + if ($order && is_string($order)) { + $order = explode(',', $order); + $order = [$order[0] => $order[1] ?? 'asc']; + } + if (!is_array($order) || !array_key_exists($this->weighField, $order)) { + return $this->error(__('Please use the %s field to sort before operating', [$this->weighField])); + } + + $order = $this->queryOrderBuilder(); + $weigh = $targetRow[$this->weighField]; + + $updateMethod = $order[$this->weighField] == 'desc' ? ($direction == 'up' ? 'dec' : 'inc') : ($direction == 'up' ? 'inc' : 'dec'); + + $weighRowIds = $this->model + ->where($dataLimitWhere) + ->where($this->weighField, $weigh) + ->order($order) + ->column($pk); + $weighRowsCount = count($weighRowIds); + + $this->model->where($dataLimitWhere) + ->where($this->weighField, $updateMethod == 'dec' ? '<' : '>', $weigh) + ->whereNotIn($pk, [$moveRow->$pk]) + ->$updateMethod($this->weighField, $weighRowsCount) + ->save(); + + if ($direction == 'down') { + $weighRowIds = array_reverse($weighRowIds); + } + + $moveComplete = 0; + $weighRowIdsStr = implode(',', $weighRowIds); + $weighRows = $this->model->where($dataLimitWhere) + ->where($pk, 'in', $weighRowIdsStr) + ->orderRaw("field($pk,$weighRowIdsStr)") + ->select(); + + foreach ($weighRows as $key => $weighRow) { + if ($moveRow[$pk] == $weighRow[$pk]) { + continue; + } + + $rowWeighVal = $updateMethod == 'dec' ? $weighRow[$this->weighField] - $key : $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(); + } + + return $this->success(); + } + + /** + * 加载为 select(远程下拉选择框)数据,子类可覆盖 + */ + protected function _select(): void + { + } +} diff --git a/app/admin/model/Admin.php b/app/admin/model/Admin.php new file mode 100644 index 0000000..4f2399e --- /dev/null +++ b/app/admin/model/Admin.php @@ -0,0 +1,64 @@ +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; + } + + public function resetPassword(int|string $uid, string $newPassword): int + { + return $this->where(['id' => $uid])->update(['password' => hash_password($newPassword), 'salt' => '']); + } +} diff --git a/app/admin/model/AdminGroup.php b/app/admin/model/AdminGroup.php new file mode 100644 index 0000000..9b3dcf3 --- /dev/null +++ b/app/admin/model/AdminGroup.php @@ -0,0 +1,17 @@ +adminLog) && $request->adminLog instanceof self) { + return $request->adminLog; + } + $log = new static(); + if ($request !== null) { + $request->adminLog = $log; + } + return $log; + } + + public function setTitle(string $title): void + { + $this->title = $title; + } + + /** 设置日志内容(BuildAdmin 控制器调用) */ + public function setLogData(string|array $data): void + { + $this->logData = $data; + } + + public function setUrlIgnoreRegex(array|string $regex = []): void + { + $this->urlIgnoreRegex = array_merge($this->urlIgnoreRegex, is_array($regex) ? $regex : [$regex]); + } + + public function setDesensitizationRegex(array|string $regex = []): void + { + $this->desensitizationRegex = array_merge($this->desensitizationRegex, is_array($regex) ? $regex : [$regex]); + } + + 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, (string) $index)) { + $item = '***'; + } elseif (is_array($item)) { + $item = $this->desensitization($item); + } + } + } + return $data; + } + + public function record(string $title = '', string|array|null $data = null, ?Request $request = null): void + { + $request = $request ?? (function_exists('request') ? request() : null); + if (!$request) { + return; + } + + $auth = Auth::instance(); + $adminId = $auth->isLogin() ? $auth->id : 0; + $username = $auth->isLogin() ? $auth->username : ($request->get('username') ?? $request->post('username') ?? __('Unknown')); + + $controllerPath = get_controller_path($request) ?? ''; + $pathParts = explode('/', trim($request->path(), '/')); + $action = $pathParts[array_key_last($pathParts)] ?? ''; + $path = $controllerPath . ($action ? '/' . $action : ''); + + foreach ($this->urlIgnoreRegex as $item) { + if (preg_match($item, $path)) { + return; + } + } + + $data = $data ?: $this->logData; + if (!$data) { + $data = array_merge($request->get(), $request->post()); + } + $data = $this->desensitization($data); + $title = $title ?: $this->title; + if (!$title && class_exists(\app\admin\model\AdminRule::class)) { + $controllerTitle = \app\admin\model\AdminRule::where('name', $controllerPath)->value('title'); + $pathTitle = \app\admin\model\AdminRule::where('name', $path)->value('title'); + $title = $pathTitle ?: __('Unknown') . '(' . $action . ')'; + $title = $controllerTitle ? ($controllerTitle . '-' . $title) : $title; + } + if (!$title) { + $title = __('Unknown'); + } + + $url = $request->url(); + $url = strlen($url) > 1500 ? substr($url, 0, 1500) : $url; + $useragent = $request->header('user-agent', ''); + $useragent = strlen($useragent) > 255 ? substr($useragent, 0, 255) : $useragent; + + self::create([ + 'admin_id' => $adminId, + 'username' => $username, + 'url' => $url, + 'title' => $title, + 'data' => !is_scalar($data) ? json_encode($data, JSON_UNESCAPED_UNICODE) : $data, + 'ip' => $request->getRealIp(), + 'useragent' => $useragent, + ]); + } + + public function admin() + { + return $this->belongsTo(Admin::class); + } +} diff --git a/app/admin/model/AdminRule.php b/app/admin/model/AdminRule.php new file mode 100644 index 0000000..aba24a1 --- /dev/null +++ b/app/admin/model/AdminRule.php @@ -0,0 +1,20 @@ +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 + { + clear_config_cache(); + } + + 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); + } + if ($row['type'] == 'switch') { + return (bool) $value; + } + if ($row['type'] == 'editor') { + return !$value ? '' : htmlspecialchars_decode($value); + } + if (in_array($row['type'], ['city', 'remoteSelects'])) { + if (!$value) return []; + if (!is_array($value)) return explode(',', $value); + return $value; + } + return $value ?: ''; + } + + public function setValueAttr(mixed $value, $row): mixed + { + if (in_array($row['type'], $this->jsonDecodeType)) { + return $value ? json_encode($value) : ''; + } + if ($row['type'] == 'switch') { + return $value ? '1' : '0'; + } + if ($row['type'] == 'time') { + return $value ? date('H:i:s', strtotime($value)) : ''; + } + if ($row['type'] == 'city') { + if ($value && is_array($value)) { + return implode(',', $value); + } + return $value ?: ''; + } + if (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 ?: []; + } + 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 []; + } +} diff --git a/app/admin/model/CrudLog.php b/app/admin/model/CrudLog.php new file mode 100644 index 0000000..5c199e6 --- /dev/null +++ b/app/admin/model/CrudLog.php @@ -0,0 +1,20 @@ + 'array', + 'fields' => 'array', + ]; +} diff --git a/app/admin/model/DataRecycle.php b/app/admin/model/DataRecycle.php new file mode 100644 index 0000000..2ae544f --- /dev/null +++ b/app/admin/model/DataRecycle.php @@ -0,0 +1,14 @@ +belongsTo(DataRecycle::class, 'recycle_id'); + } + + public function admin(): BelongsTo + { + return $this->belongsTo(Admin::class, 'admin_id'); + } +} diff --git a/app/admin/model/SensitiveData.php b/app/admin/model/SensitiveData.php new file mode 100644 index 0000000..28c7761 --- /dev/null +++ b/app/admin/model/SensitiveData.php @@ -0,0 +1,18 @@ + 'array', + ]; +} diff --git a/app/admin/model/SensitiveDataLog.php b/app/admin/model/SensitiveDataLog.php new file mode 100644 index 0000000..c379380 --- /dev/null +++ b/app/admin/model/SensitiveDataLog.php @@ -0,0 +1,26 @@ +belongsTo(SensitiveData::class, 'sensitive_id'); + } + + public function admin(): BelongsTo + { + return $this->belongsTo(Admin::class, 'admin_id'); + } +} diff --git a/app/admin/model/User.php b/app/admin/model/User.php new file mode 100644 index 0000000..bf17d3d --- /dev/null +++ b/app/admin/model/User.php @@ -0,0 +1,45 @@ +belongsTo(UserGroup::class, 'group_id'); + } + + public function resetPassword(int|string $uid, string $newPassword): int + { + return $this->where(['id' => $uid])->update(['password' => hash_password($newPassword), 'salt' => '']); + } +} diff --git a/app/admin/model/UserGroup.php b/app/admin/model/UserGroup.php new file mode 100644 index 0000000..3a10f0a --- /dev/null +++ b/app/admin/model/UserGroup.php @@ -0,0 +1,14 @@ +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((string) $value, '100', 2); + } + + public function setMoneyAttr($value): string + { + return bcmul((string) $value, '100', 2); + } + + public function getBeforeAttr($value): string + { + return bcdiv((string) $value, '100', 2); + } + + public function setBeforeAttr($value): string + { + return bcmul((string) $value, '100', 2); + } + + public function getAfterAttr($value): string + { + return bcdiv((string) $value, '100', 2); + } + + public function setAfterAttr($value): string + { + return bcmul((string) $value, '100', 2); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class, 'user_id'); + } +} diff --git a/app/admin/model/UserRule.php b/app/admin/model/UserRule.php new file mode 100644 index 0000000..64835d1 --- /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; + } +} diff --git a/app/admin/model/UserScoreLog.php b/app/admin/model/UserScoreLog.php new file mode 100644 index 0000000..a9f6438 --- /dev/null +++ b/app/admin/model/UserScoreLog.php @@ -0,0 +1,39 @@ +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'); + } +} diff --git a/app/admin/model/mall/Player.php b/app/admin/model/mall/Player.php new file mode 100644 index 0000000..2a6b6d6 --- /dev/null +++ b/app/admin/model/mall/Player.php @@ -0,0 +1,25 @@ +where(['id' => $id])->update(['password' => hash_password($newPassword)]) !== false; + } +} \ 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..1d33713 --- /dev/null +++ b/app/admin/validate/Admin.php @@ -0,0 +1,58 @@ + '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', + ]; + + protected $message = []; + + protected $field = []; + + protected $scene = [ + 'add' => ['username', 'nickname', 'password', 'email', 'mobile', 'group_arr'], + ]; + + public function sceneInfo(): static + { + return $this->only(['nickname', 'password', 'email', 'mobile']) + ->remove('password', 'require'); + } + + public function sceneEdit(): static + { + 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(); + } +} diff --git a/app/admin/validate/AdminGroup.php b/app/admin/validate/AdminGroup.php new file mode 100644 index 0000000..1145427 --- /dev/null +++ b/app/admin/validate/AdminGroup.php @@ -0,0 +1,37 @@ + 'require', + 'rules' => 'require', + ]; + + 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(); + } +} diff --git a/app/admin/validate/AdminRule.php b/app/admin/validate/AdminRule.php new file mode 100644 index 0000000..9495a88 --- /dev/null +++ b/app/admin/validate/AdminRule.php @@ -0,0 +1,37 @@ + 'require', + 'title' => 'require', + 'name' => 'require|unique:admin_rule', + ]; + + 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(); + } +} diff --git a/app/admin/validate/Config.php b/app/admin/validate/Config.php new file mode 100644 index 0000000..75cbb88 --- /dev/null +++ b/app/admin/validate/Config.php @@ -0,0 +1,32 @@ + 'require|unique:config', + ]; + + protected $message = []; + + protected $field = []; + + protected $scene = [ + 'add' => ['name'], + ]; + + public function __construct() + { + $this->field = [ + 'name' => __('Variable name'), + ]; + parent::__construct(); + } +} diff --git a/app/admin/validate/DataRecycle.php b/app/admin/validate/DataRecycle.php new file mode 100644 index 0000000..32eaa59 --- /dev/null +++ b/app/admin/validate/DataRecycle.php @@ -0,0 +1,39 @@ + 'require', + 'controller' => 'require|unique:security_data_recycle', + 'data_table' => 'require', + 'primary_key' => 'require', + ]; + + 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(); + } +} diff --git a/app/admin/validate/SensitiveData.php b/app/admin/validate/SensitiveData.php new file mode 100644 index 0000000..ff5e2cb --- /dev/null +++ b/app/admin/validate/SensitiveData.php @@ -0,0 +1,41 @@ + 'require', + 'controller' => 'require|unique:security_sensitive_data', + 'data_table' => 'require', + 'primary_key' => 'require', + 'data_fields' => 'require', + ]; + + 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(); + } +} diff --git a/app/admin/validate/UserMoneyLog.php b/app/admin/validate/UserMoneyLog.php new file mode 100644 index 0000000..a46cc51 --- /dev/null +++ b/app/admin/validate/UserMoneyLog.php @@ -0,0 +1,37 @@ + 'require', + 'money' => 'require', + 'memo' => 'require', + ]; + + 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(); + } +} diff --git a/app/admin/validate/UserScoreLog.php b/app/admin/validate/UserScoreLog.php new file mode 100644 index 0000000..66ab985 --- /dev/null +++ b/app/admin/validate/UserScoreLog.php @@ -0,0 +1,37 @@ + 'require', + 'score' => 'require', + 'memo' => 'require', + ]; + + 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(); + } +} diff --git a/app/admin/validate/mall/Player.php b/app/admin/validate/mall/Player.php new file mode 100644 index 0000000..0f170c9 --- /dev/null +++ b/app/admin/validate/mall/Player.php @@ -0,0 +1,31 @@ + [], + 'edit' => [], + ]; + +} diff --git a/app/api/controller/Account.php b/app/api/controller/Account.php new file mode 100644 index 0000000..0c16fbb --- /dev/null +++ b/app/api/controller/Account.php @@ -0,0 +1,269 @@ +initializeFrontend($request); + if ($response !== null) return $response; + + $sevenDays = Date::unixTime('day', -6); + $score = $money = $days = []; + for ($i = 0; $i < 7; $i++) { + $days[$i] = date("Y-m-d", $sevenDays + ($i * 86400)); + $tempToday0 = strtotime($days[$i]); + $tempToday24 = strtotime('+1 day', $tempToday0) - 1; + $score[$i] = UserScoreLog::where('user_id', $this->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((string) $userMoneyTemp, '100', 2); + } + + return $this->success('', [ + 'days' => $days, + 'score' => $score, + 'money' => $money, + ]); + } + + public function profile(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + $model = $this->auth->getUser(); + $data = $request->only(['avatar', 'username', 'nickname', 'gender', 'birthday', 'motto']); + $data['id'] = $this->auth->id; + if (!isset($data['birthday'])) { + $data['birthday'] = null; + } + + try { + Validator::make($data, [ + 'username' => 'required|string|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/', + 'nickname' => 'required|string|regex:/^[\x{4e00}-\x{9fa5}a-zA-Z0-9_-]+$/u', + 'birthday' => 'nullable|date', + ], [ + 'nickname.regex' => __('nicknameChsDash'), + ])->validate(); + } catch (ValidationException $e) { + return $this->error($e->getMessage()); + } + + $existUser = User::where('username', $data['username'])->where('id', '<>', $this->auth->id)->find(); + if ($existUser) { + return $this->error(__('Username') . ' ' . __('already exists')); + } + + $model->startTrans(); + try { + $model->save($data); + $model->commit(); + } catch (\Throwable $e) { + $model->rollback(); + return $this->error($e->getMessage()); + } + + return $this->success(__('Data updated successfully~')); + } + + return $this->success('', [ + 'accountVerificationType' => get_account_verification_type() + ]); + } + + public function verification(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + $captcha = new Captcha(); + $params = $request->only(['type', 'captcha']); + $key = ($params['type'] == 'email' ? $this->auth->email : $this->auth->mobile) . "user_{$params['type']}_verify"; + if ($captcha->check($params['captcha'], $key)) { + $uuid = Random::uuid(); + Token::set($uuid, $params['type'] . '-pass', $this->auth->id, 600); + return $this->success('', [ + 'type' => $params['type'], + 'accountVerificationToken' => $uuid, + ]); + } + return $this->error(__('Please enter the correct verification code')); + } + + public function changeBind(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + $captcha = new Captcha(); + $params = $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)) { + return $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])) { + return $this->error(__('Password error')); + } + + if ($captcha->check($params['captcha'], $params[$params['type']] . "user_change_{$params['type']}")) { + try { + if ($params['type'] == 'email') { + Validator::make($params, ['email' => 'required|email'])->validate(); + if (User::where('email', $params['email'])->find()) { + return $this->error(__('Email') . ' ' . __('already exists')); + } + } else { + Validator::make($params, ['mobile' => 'required|regex:/^1[3-9]\d{9}$/'])->validate(); + if (User::where('mobile', $params['mobile'])->find()) { + return $this->error(__('Mobile') . ' ' . __('already exists')); + } + } + } catch (ValidationException $e) { + return $this->error(__($e->getMessage())); + } + if ($params['type'] == 'email') { + $user->email = $params['email']; + } else { + $user->mobile = $params['mobile']; + } + Token::delete($params['accountVerificationToken']); + $user->save(); + return $this->success(); + } + return $this->error(__('Please enter the correct verification code')); + } + + public function changePassword(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + $model = $this->auth->getUser(); + $params = $request->only(['oldPassword', 'newPassword']); + + if (!verify_password($params['oldPassword'], $model->password, ['salt' => $model->salt])) { + return $this->error(__('Old password error')); + } + + try { + Validator::make( + ['password' => $params['newPassword']], + ['password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/'], + ['password.regex' => __('Please input correct password')] + )->validate(); + } catch (ValidationException $e) { + return $this->error($e->getMessage()); + } + + $model->startTrans(); + try { + $model->resetPassword($this->auth->id, $params['newPassword']); + $model->commit(); + } catch (\Throwable $e) { + $model->rollback(); + return $this->error($e->getMessage()); + } + + $this->auth->logout(); + return $this->success(__('Password has been changed, please login again~')); + } + return $this->error(__('Method not allowed'), [], 0, ['statusCode' => 405]); + } + + public function integral(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + $limit = $request->get('limit', $request->post('limit', 15)); + $res = UserScoreLog::where('user_id', $this->auth->id) + ->order('create_time', 'desc') + ->paginate($limit); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + ]); + } + + public function balance(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + $limit = $request->get('limit', $request->post('limit', 15)); + $res = UserMoneyLog::where('user_id', $this->auth->id) + ->order('create_time', 'desc') + ->paginate($limit); + + return $this->success('', [ + 'list' => $res->items(), + 'total' => $res->total(), + ]); + } + + public function retrievePassword(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + $params = $request->only(['type', 'account', 'captcha', 'password']); + try { + Validator::make($params, [ + 'type' => 'required|in:email,mobile', + 'account' => 'required|string', + 'captcha' => 'required|string', + 'password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/', + ], [ + 'password.regex' => __('Please input correct password'), + ])->validate(); + } catch (ValidationException $e) { + return $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) { + return $this->error(__('Account does not exist~')); + } + + $captchaObj = new Captcha(); + if (!$captchaObj->check($params['captcha'], $params['account'] . 'user_retrieve_pwd')) { + return $this->error(__('Please enter the correct verification code')); + } + + if ($user->resetPassword($user->id, $params['password'])) { + return $this->success(__('Password has been changed~')); + } + return $this->error(__('Failed to modify password, please try again later~')); + } +} diff --git a/app/api/controller/Ajax.php b/app/api/controller/Ajax.php new file mode 100644 index 0000000..c99b8a3 --- /dev/null +++ b/app/api/controller/Ajax.php @@ -0,0 +1,65 @@ +initializeFrontend($request); + if ($response !== null) return $response; + + $file = $request->file('file'); + if (!$file) { + return $this->error(__('No files were uploaded')); + } + $file = new \app\common\library\upload\WebmanUploadedFile($file); + $driver = $request->get('driver', $request->post('driver', 'local')); + $topic = $request->get('topic', $request->post('topic', 'default')); + + try { + $upload = new \app\common\library\Upload(); + $attachment = $upload + ->setFile($file) + ->setDriver($driver) + ->setTopic($topic) + ->upload(null, 0, $this->auth->id); + unset($attachment['create_time'], $attachment['quote']); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + + return $this->success(__('File uploaded successfully'), [ + 'file' => $attachment ?? [] + ]); + } + + public function area(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + return $this->success('', get_area($request)); + } + + public function buildSuffixSvg(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + $suffix = $request->get('suffix', $request->post('suffix', 'file')); + $background = $request->get('background', $request->post('background')); + $content = build_suffix_svg((string) $suffix, (string) $background); + return response($content, 200, [ + 'Content-Length' => strlen($content), + 'Content-Type' => 'image/svg+xml' + ]); + } +} diff --git a/app/api/controller/Common.php b/app/api/controller/Common.php new file mode 100644 index 0000000..6077282 --- /dev/null +++ b/app/api/controller/Common.php @@ -0,0 +1,84 @@ +initializeApi($request); + if ($response !== null) return $response; + + $captchaId = $request->get('id', $request->post('id', '')); + $config = [ + 'codeSet' => '123456789', + 'fontSize' => 22, + 'useCurve' => false, + 'useNoise' => true, + 'length' => 4, + 'bg' => [255, 255, 255], + ]; + $captcha = new Captcha($config); + return $captcha->entry($captchaId); + } + + public function clickCaptcha(Request $request): Response + { + $response = $this->initializeApi($request); + if ($response !== null) return $response; + + $id = $request->get('id', $request->post('id', '')); + $captcha = new ClickCaptcha(); + return $this->success('', $captcha->creat($id)); + } + + public function checkClickCaptcha(Request $request): Response + { + $response = $this->initializeApi($request); + if ($response !== null) return $response; + + $id = $request->post('id', ''); + $info = $request->post('info', ''); + $unset = filter_var($request->post('unset', false), FILTER_VALIDATE_BOOLEAN); + $captcha = new ClickCaptcha(); + if ($captcha->check($id, $info, $unset)) return $this->success(); + return $this->error(); + } + + public function refreshToken(Request $request): Response + { + $response = $this->initializeApi($request); + if ($response !== null) return $response; + + $refreshToken = $request->post('refreshToken', ''); + $refreshToken = Token::get($refreshToken); + + if (!$refreshToken || $refreshToken['expire_time'] < time()) { + return $this->error(__('Login expired, please login again.')); + } + + $newToken = Random::uuid(); + + if ($refreshToken['type'] == AdminAuth::TOKEN_TYPE . '-refresh') { + Token::set($newToken, AdminAuth::TOKEN_TYPE, $refreshToken['user_id'], (int)config('buildadmin.admin_token_keep_time', 259200)); + } + if ($refreshToken['type'] == UserAuth::TOKEN_TYPE . '-refresh') { + Token::set($newToken, UserAuth::TOKEN_TYPE, $refreshToken['user_id'], (int)config('buildadmin.user_token_keep_time', 259200)); + } + + return $this->success('', [ + 'type' => $refreshToken['type'], + 'token' => $newToken + ]); + } +} diff --git a/app/api/controller/Ems.php b/app/api/controller/Ems.php new file mode 100644 index 0000000..53bbc68 --- /dev/null +++ b/app/api/controller/Ems.php @@ -0,0 +1,99 @@ +initializeFrontend($request); + if ($response !== null) return $response; + + $params = $request->post(['email', 'event', 'captchaId', 'captchaInfo']); + $mail = new Email(); + if (!$mail->configured) { + return $this->error(__('Mail sending service unavailable')); + } + + try { + Validator::make($params, [ + 'email' => 'required|email', + 'event' => 'required|string', + 'captchaId' => 'required|string', + 'captchaInfo' => 'required|string', + ], [ + 'email.required' => 'email format error', + 'event.required' => 'Parameter error', + 'captchaId.required' => 'Captcha error', + 'captchaInfo.required' => 'Captcha error', + ])->validate(); + } catch (ValidationException $e) { + return $this->error(__($e->getMessage())); + } + + $captchaObj = new Captcha(); + $clickCaptcha = new ClickCaptcha(); + if (!$clickCaptcha->check($params['captchaId'], $params['captchaInfo'])) { + return $this->error(__('Captcha error')); + } + + $captcha = $captchaObj->getCaptchaData($params['email'] . $params['event']); + if ($captcha && time() - $captcha['create_time'] < 60) { + return $this->error(__('Frequent email sending')); + } + + $userInfo = User::where('email', $params['email'])->find(); + if ($params['event'] == 'user_register' && $userInfo) { + return $this->error(__('Email has been registered, please log in directly')); + } + if ($params['event'] == 'user_change_email' && $userInfo) { + return $this->error(__('The email has been occupied')); + } + if (in_array($params['event'], ['user_retrieve_pwd', 'user_email_verify']) && !$userInfo) { + return $this->error(__('Email not registered')); + } + + if ($params['event'] == 'user_email_verify') { + if (!$this->auth->isLogin()) { + return $this->error(__('Please login first')); + } + if ($this->auth->email != $params['email']) { + return $this->error(__('Please use the account registration email to send the verification code')); + } + $password = $request->post('password'); + if (!verify_password($password, $this->auth->password, ['salt' => $this->auth->salt])) { + return $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) { + return $this->error($mail->ErrorInfo); + } + + return $this->success(__('Mail sent successfully~')); + } +} diff --git a/app/api/controller/Index.php b/app/api/controller/Index.php new file mode 100644 index 0000000..1369d79 --- /dev/null +++ b/app/api/controller/Index.php @@ -0,0 +1,71 @@ +initializeFrontend($request); + if ($response !== null) return $response; + + $menus = []; + if ($this->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 = filter_var($request->get('requiredLogin', false), FILTER_VALIDATE_BOOLEAN); + if ($requiredLogin) { + try { + $token = get_auth_token(['ba', 'user', 'token'], $request); + $this->auth->init($token); + } catch (TokenExpirationException) { + return $this->error(__('Token expiration'), [], 409); + } + return $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); + } + + return $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($request), ['max_size', 'save_name', 'allowed_suffixes', 'allowed_mime_types']), + 'recordNumber' => get_sys_config('record_number'), + 'cdnUrlParams' => config('buildadmin.cdn_url_params'), + ], + 'openMemberCenter' => config('buildadmin.open_member_center'), + 'userInfo' => $this->auth->getUserInfo(), + 'rules' => $rules, + 'menus' => $menus, + ]); + } +} diff --git a/app/api/controller/Install.php b/app/api/controller/Install.php new file mode 100644 index 0000000..f8ff422 --- /dev/null +++ b/app/api/controller/Install.php @@ -0,0 +1,676 @@ + '8.2.0', + 'npm' => '9.8.1', + 'cnpm' => '7.1.0', + 'node' => '20.14.0', + 'yarn' => '1.2.0', + 'pnpm' => '6.32.13', + ]; + + /** + * 安装完成标记 + */ + static string $InstallationCompletionMark = 'install-end'; + + /** + * 命令执行窗口(exec 为 SSE 长连接,不会返回) + * @throws Throwable + */ + public function terminal(Request $request): Response + { + $this->setRequest($request); + if ($this->isInstallComplete()) { + return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName])); + } + + (new Terminal())->exec(false); + return $this->success(); // unreachable: exec() blocks with SSE stream + } + + public function changePackageManager(Request $request): Response + { + $this->setRequest($request); + if ($this->isInstallComplete()) { + return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName])); + } + + $newPackageManager = $request->post('manager', config('terminal.npm_package_manager')); + if (Terminal::changeTerminalConfig()) { + return $this->success('', [ + 'manager' => $newPackageManager + ]); + } + return $this->error(__('Failed to switch package manager. Please modify the configuration file manually:%s', ['config/terminal.php'])); + } + + /** + * 环境基础检查 + */ + public function envBaseCheck(Request $request): Response + { + $this->setRequest($request); + if ($this->isInstallComplete()) { + return $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'] ?? getenv('DATABASE_TYPE'))) { + return $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 = [ + [ + '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 = [ + [ + '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(分别检测目录和文件,便于定位问题) + $configDir = rtrim(config_path(), '/\\'); + $dbConfigFile = $configDir . DIRECTORY_SEPARATOR . self::$dbConfigFileName; + $configDirWritable = Filesystem::pathIsWritable($configDir); + $dbConfigWritable = Filesystem::pathIsWritable($dbConfigFile); + $configIsWritable = $configDirWritable && $dbConfigWritable; + 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 + + return $this->success('', [ + 'php_version' => [ + 'describe' => $phpVersion . " ($phpBit)", + 'state' => $phpVersionCompare && $phpBit == self::X64 ? self::$ok : self::$fail, + 'link' => $phpVersionLink ?? [], + ], + 'config_is_writable' => [ + 'describe' => $configIsWritable + ? self::writableStateDescribe(true) + : (self::writableStateDescribe(false) . ' [' . $configDir . ']'), + '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(Request $request): Response + { + $this->setRequest($request); + if ($this->isInstallComplete()) { + return $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' + ] + ]; + } + + // 包管理器 + $pmVersionLink = []; + $pmVersion = __('nothing'); + $pmVersionCompare = false; + 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[] = [ + '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') { + $pmVersionCompare = true; + } + + // 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' + ] + ]; + } + + return $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(Request $request): Response + { + $this->setRequest($request); + $database = [ + 'hostname' => $request->post('hostname'), + 'username' => $request->post('username'), + 'password' => $request->post('password'), + 'hostport' => $request->post('hostport'), + 'database' => '', + ]; + + $conn = $this->connectDb($database); + if ($conn['code'] == 0) { + return $this->error($conn['msg']); + } + return $this->success('', [ + 'databases' => $conn['databases'] + ]); + } + + /** + * 系统基础配置 + * post请求=开始安装 + */ + public function baseConfig(Request $request): Response + { + $this->setRequest($request); + if ($this->isInstallComplete()) { + return $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()); + $migrateCommand = 'php vendor/bin/phinx migrate'; + if ($request->isGet()) { + return $this->success('', [ + 'rootPath' => $rootPath, + 'executionWebCommand' => $envOk, + 'migrateCommand' => $migrateCommand, + ]); + } + + $connectData = $databaseParam = $request->only(['hostname', 'username', 'password', 'hostport', 'database', 'prefix']); + + // 数据库配置测试 + $connectData['database'] = ''; + $connect = $this->connectDb($connectData, true); + if ($connect['code'] == 0) { + return $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); + } + + // 写入数据库配置文件(thinkorm.php 使用 $env('database.xxx', 'default') 格式) + $dbConfigFile = config_path(self::$dbConfigFileName); + $dbConfigContent = @file_get_contents($dbConfigFile); + if ($dbConfigContent === false || $dbConfigContent === '') { + return $this->error(__('File has no write permission:%s', ['config/' . self::$dbConfigFileName])); + } + $callback = function ($matches) use ($databaseParam) { + $key = $matches[1]; + $value = (string) ($databaseParam[$key] ?? ''); + return "\$env('database.{$key}', '" . addslashes($value) . "')"; + }; + $dbConfigText = preg_replace_callback("/\\\$env\('database\.(hostname|database|username|password|hostport|prefix)',\s*'[^']*'\)/", $callback, $dbConfigContent); + $result = @file_put_contents($dbConfigFile, $dbConfigText); + if (!$result) { + return $this->error(__('File has no write permission:%s', ['config/' . self::$dbConfigFileName])); + } + + // 写入 dafuweng-webman/.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) { + return $this->error(__('File has no write permission:%s', ['/' . $envFile])); + } + } + + // 设置新的Token随机密钥key + $oldTokenKey = config('buildadmin.token.key'); + $newTokenKey = Random::build('alnum', 32); + $buildConfigFile = config_path(self::$buildConfigFileName); + $buildConfigContent = @file_get_contents($buildConfigFile); + if ($buildConfigContent === false || $buildConfigContent === '') { + return $this->error(__('File has no write permission:%s', ['config/' . self::$buildConfigFileName])); + } + $buildConfigContent = preg_replace("/'key'(\s+)=>(\s+)'$oldTokenKey'/", "'key'\$1=>\$2'$newTokenKey'", $buildConfigContent); + $result = @file_put_contents($buildConfigFile, $buildConfigContent); + if (!$result) { + return $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) { + return $this->error(__('File has no write permission:%s', ['public/' . self::$lockFileName])); + } + + return $this->success('', [ + 'rootPath' => $rootPath, + 'executionWebCommand' => $envOk, + 'migrateCommand' => $migrateCommand, + ]); + } + + 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(Request $request): Response + { + $this->setRequest($request); + if ($this->isInstallComplete()) { + return $this->error(__('The system has completed installation. If you need to reinstall, please delete the %s file first', ['public/' . self::$lockFileName])); + } + + $param = $request->only(['type', 'adminname', 'adminpassword', 'sitename']); + if ($param['type'] == 'web') { + $result = @file_put_contents(public_path(self::$lockFileName), self::$InstallationCompletionMark); + if (!$result) { + return $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()); + + // 修改站点名称 + if (class_exists(\app\admin\model\Config::class)) { + \app\admin\model\Config::where('name', 'site_name')->update([ + 'value' => $param['sitename'] + ]); + } + } + return $this->success(); + } + + /** + * 获取命令执行检查的结果 + * @return bool 是否拥有执行命令的条件 + */ + private function commandExecutionCheck(): bool + { + $pm = config('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(Request $request): Response + { + $this->setRequest($request); + return $this->success('', [ + 'webPath' => str_replace('\\', '/', root_path() . 'web') + ]); + } + + public function mvDist(Request $request): Response + { + $this->setRequest($request); + if (!is_file(root_path() . self::$distDir . DIRECTORY_SEPARATOR . 'index.html')) { + return $this->error(__('No built front-end file found, please rebuild manually!')); + } + + if (Terminal::mvDist()) { + return $this->success(); + } + return $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'); + } + + /** + * 数据库连接-获取数据表列表(使用 raw PDO) + * @param array $database hostname, hostport, username, password, database + * @param bool $returnPdo + * @return array + */ + private function connectDb(array $database, bool $returnPdo = false): array + { + $host = $database['hostname'] ?? '127.0.0.1'; + $port = $database['hostport'] ?? '3306'; + $user = $database['username'] ?? ''; + $pass = $database['password'] ?? ''; + $db = $database['database'] ?? ''; + + $dsn = "mysql:host={$host};port={$port};charset=utf8mb4"; + if ($db) { + $dsn .= ";dbname={$db}"; + } + + try { + $pdo = new \PDO($dsn, $user, $pass, [ + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, + ]); + $pdo->query("SELECT 1")->fetchAll(\PDO::FETCH_ASSOC); + } catch (\PDOException $e) { + $errorMsg = mb_convert_encoding($e->getMessage() ?: 'unknown', 'UTF-8', 'UTF-8,GBK,GB2312,BIG5'); + $template = __('Database connection failed:%s'); + return [ + 'code' => 0, + 'msg' => strpos($template, '%s') !== false ? sprintf($template, $errorMsg) : $template . $errorMsg, + ]; + } + + $databases = []; + $databasesExclude = ['information_schema', 'mysql', 'performance_schema', 'sys']; + $stmt = $pdo->query("SHOW DATABASES"); + $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC); + $stmt->closeCursor(); + foreach ($rows as $row) { + $dbName = $row['Database'] ?? $row['database'] ?? ''; + if ($dbName && !in_array($dbName, $databasesExclude)) { + $databases[] = $dbName; + } + } + + return [ + 'code' => 1, + 'msg' => '', + 'databases' => $databases, + 'pdo' => $returnPdo ? $pdo : null, + ]; + } +} diff --git a/app/api/controller/User.php b/app/api/controller/User.php new file mode 100644 index 0000000..8e27665 --- /dev/null +++ b/app/api/controller/User.php @@ -0,0 +1,151 @@ +initializeFrontend($request); + if ($response !== null) return $response; + + $openMemberCenter = config('buildadmin.open_member_center'); + if (!$openMemberCenter) { + return $this->error(__('Member center disabled')); + } + + if ($this->auth->isLogin()) { + return $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('buildadmin.user_login_captcha'); + + if ($request->method() === 'POST') { + $params = $request->post(); + $params = array_merge($params, [ + 'tab' => $params['tab'] ?? '', + 'email' => $params['email'] ?? '', + 'mobile' => $params['mobile'] ?? '', + 'username' => $params['username'] ?? '', + 'password' => $params['password'] ?? '', + 'keep' => $params['keep'] ?? false, + 'captcha' => $params['captcha'] ?? '', + 'captchaId' => $params['captchaId'] ?? '', + 'captchaInfo' => $params['captchaInfo'] ?? '', + 'registerType' => $params['registerType'] ?? '', + ]); + + if (!in_array($params['tab'], ['login', 'register'])) { + return $this->error(__('Unknown operation')); + } + + try { + $rules = $params['tab'] === 'login' ? $this->getLoginRules($userLoginCaptchaSwitch) : $this->getRegisterRules(); + Validator::make($params, $rules[0], $rules[1] ?? [], $rules[2] ?? [])->validate(); + } catch (ValidationException $e) { + return $this->error($e->getMessage()); + } + + if ($params['tab'] === 'login') { + if ($userLoginCaptchaSwitch) { + $captchaObj = new ClickCaptcha(); + if (!$captchaObj->check($params['captchaId'], $params['captchaInfo'])) { + return $this->error(__('Captcha error')); + } + } + $res = $this->auth->login($params['username'], $params['password'], !empty($params['keep'])); + } else { + $captchaObj = new Captcha(); + if (!$captchaObj->check($params['captcha'], $params[$params['registerType']] . 'user_register')) { + return $this->error(__('Please enter the correct verification code')); + } + $res = $this->auth->register($params['username'], $params['password'], $params['mobile'], $params['email']); + } + + if ($res === true) { + return $this->success(__('Login succeeded!'), [ + 'userInfo' => $this->auth->getUserInfo(), + 'routePath' => '/user' + ]); + } + $msg = $this->auth->getError(); + return $this->error($msg ?: __('Check in failed, please try again or contact the website administrator~')); + } + + return $this->success('', [ + 'userLoginCaptchaSwitch' => $userLoginCaptchaSwitch, + 'accountVerificationType' => get_account_verification_type() + ]); + } + + private function getLoginRules(bool $captchaSwitch): array + { + $rules = [ + 'username' => 'required|string', + 'password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/', + ]; + $messages = [ + 'password.regex' => __('Please input correct password'), + ]; + if ($captchaSwitch) { + $rules['captchaId'] = 'required|string'; + $rules['captchaInfo'] = 'required|string'; + } + return [$rules, $messages, []]; + } + + private function getRegisterRules(): array + { + return [ + [ + 'username' => 'required|string|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/|unique:user,username', + 'password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/', + 'registerType' => 'required|in:email,mobile', + 'email' => 'required_if:registerType,email|email|unique:user,email', + 'mobile' => 'required_if:registerType,mobile|regex:/^1[3-9]\d{9}$/|unique:user,mobile', + 'captcha' => 'required|string', + ], + [ + 'username.regex' => __('Please input correct username'), + 'password.regex' => __('Please input correct password'), + ], + [ + 'username' => __('Username'), + 'email' => __('Email'), + 'mobile' => __('Mobile'), + 'password' => __('Password'), + 'captcha' => __('captcha'), + 'registerType' => __('Register type'), + ] + ]; + } + + public function logout(Request $request): Response + { + $response = $this->initializeFrontend($request); + if ($response !== null) return $response; + + if ($request->method() === 'POST') { + $refreshToken = $request->post('refreshToken', ''); + if ($refreshToken) { + Token::delete((string) $refreshToken); + } + $this->auth->logout(); + return $this->success(); + } + return $this->error(__('Method not allowed'), [], 0, ['statusCode' => 405]); + } +} diff --git a/app/api/lang/en.php b/app/api/lang/en.php new file mode 100644 index 0000000..42619df --- /dev/null +++ b/app/api/lang/en.php @@ -0,0 +1,21 @@ + '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!', + // Member center account + 'Data updated successfully~' => 'Data updated successfully~', + 'Password has been changed~' => 'Password has been changed~', + 'Password has been changed, please login again~' => 'Password has been changed, please login again~', + 'already exists' => 'already exists', + 'nicknameChsDash' => 'Usernames can only be Chinese characters, letters, numbers, underscores_ and dashes-.', +]; \ 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..0e01a89 --- /dev/null +++ b/app/api/lang/zh-cn.php @@ -0,0 +1,53 @@ + '%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' => '验证码错误!', + // 会员中心 account + 'Data updated successfully~' => '资料更新成功~', + 'Password has been changed~' => '密码已修改~', + 'Password has been changed, please login again~' => '密码已修改,请重新登录~', + 'already exists' => '已存在', + 'nicknameChsDash' => '用户名只能是汉字、字母、数字和下划线_及破折号-', +]; \ 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/validate/Account.php b/app/api/validate/Account.php new file mode 100644 index 0000000..d6d17ad --- /dev/null +++ b/app/api/validate/Account.php @@ -0,0 +1,46 @@ + '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(); + } +} diff --git a/app/api/validate/User.php b/app/api/validate/User.php new file mode 100644 index 0000000..cad3dfe --- /dev/null +++ b/app/api/validate/User.php @@ -0,0 +1,59 @@ + '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(): static + { + $fields = ['username', 'password']; + + $userLoginCaptchaSwitch = config('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(); + } +} diff --git a/app/common/controller/Api.php b/app/common/controller/Api.php new file mode 100644 index 0000000..998a331 --- /dev/null +++ b/app/common/controller/Api.php @@ -0,0 +1,79 @@ +setRequest($request); + + if ($this->useSystemSettings) { + // 检查数据库连接 + try { + Db::execute('SELECT 1'); + } catch (PDOException $e) { + return $this->error(mb_convert_encoding($e->getMessage(), 'UTF-8', 'UTF-8,GBK,GB2312,BIG5')); + } + + // IP 检查 + $ipCheckResponse = ip_check(null, $request); + if ($ipCheckResponse !== null) { + return $ipCheckResponse; + } + + // 时区设定 + set_timezone(); + } + + // 语言包由 LoadLangPack 中间件加载 + + return null; + } + + /** + * 从 Request 或路由解析控制器路径(如 user/user) + * 优先从 $request->controller 解析,否则从 path 解析 + */ + protected function getControllerPath(WebmanRequest $request): ?string + { + return get_controller_path($request); + } + + /** + * 从 Request 解析应用名(api 或 admin) + */ + protected function getAppFromRequest(WebmanRequest $request): string + { + $path = trim($request->path(), '/'); + $parts = explode('/', $path); + return $parts[0] ?? 'api'; + } +} diff --git a/app/common/controller/Backend.php b/app/common/controller/Backend.php new file mode 100644 index 0000000..6e7c365 --- /dev/null +++ b/app/common/controller/Backend.php @@ -0,0 +1,435 @@ +initializeApi($request); + if ($response !== null) { + return $response; + } + + // 调用子类 initialize(CRUD 生成的控制器在此设置 model) + $this->initialize(); + + $action = $this->getActionFromPath($request->path()); + $needLogin = !action_in_arr($this->noNeedLogin, $action); + $needPermission = !action_in_arr($this->noNeedPermission, $action); + + try { + $this->auth = Auth::instance(); + $token = get_auth_token(['ba', 'token'], $request); + if ($token) { + $this->auth->init($token); + } + } catch (TokenExpirationException) { + if ($needLogin) { + return $this->error(__('Token expiration'), [], 409); + } + } + + if ($needLogin) { + if (!$this->auth->isLogin()) { + return $this->error(__('Please login first'), [ + 'type' => Auth::NEED_LOGIN, + ], 0, ['statusCode' => Auth::LOGIN_RESPONSE_CODE]); + } + if ($needPermission) { + $controllerPath = $this->getControllerPath($request); + $routePath = $controllerPath . '/' . $action; + if (!$this->auth->check($routePath)) { + return $this->error(__('You have no permission'), [], 401); + } + } + } + + event_trigger('backendInit', $this->auth); + + if (method_exists($this, 'initController')) { + $initResp = $this->initController($request); + if ($initResp !== null) { + return $initResp; + } + } + + return null; + } + + /** + * 子类可覆盖,用于初始化 model 等(替代原 initialize) + * @return Response|null 需直接返回时返回 Response,否则 null + */ + protected function initController(WebmanRequest $request): ?Response + { + return null; + } + + public function index(WebmanRequest $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + return $this->_index(); + } + + public function add(WebmanRequest $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + return $this->_add(); + } + + public function edit(WebmanRequest $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + return $this->_edit(); + } + + public function del(WebmanRequest $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + return $this->_del(); + } + + public function sortable(WebmanRequest $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + return $this->_sortable(); + } + + public function select(WebmanRequest $request): Response + { + $response = $this->initializeBackend($request); + if ($response !== null) return $response; + $this->_select(); + return $this->success(); + } + + /** + * 查询参数构建器 + */ + public function queryBuilder(): array + { + if (empty($this->model) || !$this->request) { + return [[], [], 10, []]; + } + $pk = $this->model->getPk(); + $quickSearch = $this->request->get('quickSearch', ''); + $limit = $this->request->get('limit', 10); + $limit = is_numeric($limit) ? intval($limit) : 10; + $search = $this->request->get('search', []); + $search = is_array($search) ? $search : []; + $initKey = $this->request->get('initKey', $pk); + $initValue = $this->request->get('initValue', ''); + $initOperator = $this->request->get('initOperator', 'in'); + + $where = []; + $modelTable = strtolower($this->model->getTable()); + $alias = []; + $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'], strval($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(): array + { + $pk = $this->model->getPk(); + $order = $this->request ? $this->request->get('order') : null; + $order = $order ?: $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)) { + $orderParts = explode(',', $this->orderGuarantee); + $this->orderGuarantee = [$orderParts[0] => $orderParts[1] ?? 'asc']; + } + $orderGuaranteeKey = array_key_first($this->orderGuarantee); + if (!is_array($order) || !array_key_exists($orderGuaranteeKey, $order)) { + $order[$orderGuaranteeKey] = $this->orderGuarantee[$orderGuaranteeKey]; + } + + return $order; + } + + /** + * 数据权限控制 - 获取有权限访问的管理员 IDs + */ + protected function getDataLimitAdminIds(): array + { + if (!$this->dataLimit || !$this->auth || $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); + } + + /** + * 从别名获取原始的逻辑运算符 + */ + protected function getOperatorByAlias(string $operator): string + { + $alias = [ + 'ne' => '<>', + 'eq' => '=', + 'gt' => '>', + 'egt' => '>=', + 'lt' => '<', + 'elt' => '<=', + ]; + return $alias[$operator] ?? $operator; + } + + /** + * 从 path 解析 action + */ + protected function getActionFromPath(string $path): string + { + $parts = explode('/', trim($path, '/')); + return $parts[array_key_last($parts)] ?? ''; + } + + /** + * 从 Request 或路由解析控制器路径(如 auth/admin) + * 优先从 $request->controller(Webman 路由匹配时设置)解析,否则从 path 解析 + */ + protected function getControllerPath(WebmanRequest $request): string + { + return get_controller_path($request); + } +} diff --git a/app/common/controller/Frontend.php b/app/common/controller/Frontend.php new file mode 100644 index 0000000..e29ae8f --- /dev/null +++ b/app/common/controller/Frontend.php @@ -0,0 +1,60 @@ +initializeApi($request); + if ($response !== null) return $response; + + $this->setRequest($request); + $path = trim($request->path(), '/'); + $parts = explode('/', $path); + $action = $parts[array_key_last($parts)] ?? ''; + $needLogin = !action_in_arr($this->noNeedLogin, $action); + + try { + $this->auth = Auth::instance(['request' => $request]); + $token = get_auth_token(['ba', 'user', 'token'], $request); + if ($token) $this->auth->init($token); + } catch (TokenExpirationException) { + if ($needLogin) return $this->error(__('Token expiration'), [], 409); + } + + if ($needLogin) { + if (!$this->auth->isLogin()) { + return $this->error(__('Please login first'), ['type' => Auth::NEED_LOGIN], Auth::LOGIN_RESPONSE_CODE); + } + if (!action_in_arr($this->noNeedPermission, $action)) { + $routePath = get_controller_path($request) . '/' . $action; + if (!$this->auth->check($routePath)) { + return $this->error(__('You have no permission'), [], 401); + } + } + } + + event_trigger('frontendInit', $this->auth); + return null; + } +} diff --git a/app/common/event/Security.php b/app/common/event/Security.php new file mode 100644 index 0000000..122826f --- /dev/null +++ b/app/common/event/Security.php @@ -0,0 +1,154 @@ +getActionFromPath($request->path()); + if (!in_array($action, $this->listenAction)) { + return true; + } + if ($action === 'del' && $request->method() !== 'POST' && $request->method() !== 'DELETE') { + return true; + } + if ($action === 'edit' && $request->method() !== 'POST') { + return true; + } + + if (!class_exists(\app\admin\model\DataRecycle::class) || !class_exists(\app\admin\model\SensitiveData::class)) { + return true; + } + + if ($action === 'del') { + return $this->handleDel($request, $auth); + } + return $this->handleEdit($request, $auth); + } + + protected function getActionFromPath(string $path): string + { + $parts = explode('/', trim($path, '/')); + return $parts[array_key_last($parts)] ?? ''; + } + + protected function handleDel($request, $auth): bool + { + $dataIds = $request->post('ids') ?? $request->get('ids'); + if (!$dataIds) { + return true; + } + try { + $controllerPath = get_controller_path($request) ?? ''; + $recycle = \app\admin\model\DataRecycle::where('status', 1) + ->where('controller_as', $controllerPath) + ->find(); + if (!$recycle) { + return true; + } + $connection = class_exists(\ba\TableManager::class) + ? \ba\TableManager::getConnection($recycle['connection']) + : null; + $db = $connection ? \support\think\Db::connect($connection) : \support\think\Db::connect(); + $recycleData = $db->name($recycle['data_table']) + ->whereIn($recycle['primary_key'], $dataIds) + ->select() + ->toArray(); + $recycleDataArr = []; + $adminId = $auth && $auth->isLogin() ? $auth->id : 0; + foreach ($recycleData as $item) { + $recycleDataArr[] = [ + 'admin_id' => $adminId, + 'recycle_id' => $recycle['id'], + 'data' => json_encode($item, JSON_UNESCAPED_UNICODE), + 'connection' => $recycle['connection'], + 'data_table' => $recycle['data_table'], + 'primary_key' => $recycle['primary_key'], + 'ip' => $request->getRealIp(), + 'useragent' => substr($request->header('user-agent', ''), 0, 255), + ]; + } + if ($recycleDataArr) { + $model = new \app\admin\model\DataRecycleLog(); + $model->saveAll($recycleDataArr); + } + } catch (\Throwable $e) { + \support\Log::warning('[DataSecurity] ' . $e->getMessage()); + } + return true; + } + + protected function handleEdit($request, $auth): bool + { + try { + $controllerPath = get_controller_path($request) ?? ''; + $sensitiveData = \app\admin\model\SensitiveData::where('status', 1) + ->where('controller_as', $controllerPath) + ->find(); + if (!$sensitiveData) { + return true; + } + $sensitiveData = $sensitiveData->toArray(); + $dataId = $request->post($sensitiveData['primary_key']) ?? $request->get($sensitiveData['primary_key']); + $connection = class_exists(\ba\TableManager::class) + ? \ba\TableManager::getConnection($sensitiveData['connection']) + : null; + $db = $connection ? \support\think\Db::connect($connection) : \support\think\Db::connect(); + $editData = $db->name($sensitiveData['data_table']) + ->field(array_keys($sensitiveData['data_fields'])) + ->where($sensitiveData['primary_key'], $dataId) + ->find(); + if (!$editData) { + return true; + } + $newData = $request->post(); + $sensitiveDataLog = []; + foreach ($sensitiveData['data_fields'] as $field => $title) { + if (isset($editData[$field]) && isset($newData[$field]) && $editData[$field] != $newData[$field]) { + $newVal = $newData[$field]; + if (stripos($field, 'password') !== false && $newVal) { + $newVal = '******'; + } + $sensitiveDataLog[] = [ + 'admin_id' => $auth && $auth->isLogin() ? $auth->id : 0, + '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' => $newVal, + 'ip' => $request->getRealIp(), + 'useragent' => substr($request->header('user-agent', ''), 0, 255), + ]; + } + } + if ($sensitiveDataLog) { + $model = new \app\admin\model\SensitiveDataLog(); + $model->saveAll($sensitiveDataLog); + } + } catch (\Throwable $e) { + \support\Log::warning('[DataSecurity] ' . $e->getMessage()); + } + return true; + } +} diff --git a/app/common/facade/Token.php b/app/common/facade/Token.php new file mode 100644 index 0000000..1f2e37c --- /dev/null +++ b/app/common/facade/Token.php @@ -0,0 +1,60 @@ +get($token); + } + + public static function set(string $token, string $type, int $userId, ?int $expire = null): bool + { + return self::getInstance()->set($token, $type, $userId, $expire); + } + + public static function check(string $token, string $type, int $userId): bool + { + return self::getInstance()->check($token, $type, $userId); + } + + public static function delete(string $token): bool + { + return self::getInstance()->delete($token); + } + + public static function clear(string $type, int $userId): bool + { + return self::getInstance()->clear($type, $userId); + } + + public static function tokenExpirationCheck(array $token): void + { + self::getInstance()->tokenExpirationCheck($token); + } +} diff --git a/app/common/library/Auth.php b/app/common/library/Auth.php new file mode 100644 index 0000000..3174717 --- /dev/null +++ b/app/common/library/Auth.php @@ -0,0 +1,356 @@ + 'user_group', + 'auth_group_access' => '', + 'auth_rule' => 'user_rule', + ], $config)); + + $this->setKeepTime((int)config('buildadmin.user_token_keep_time', 86400)); + } + + public function __get($name): mixed + { + return $this->model?->$name; + } + + public static function instance(array $options = []): Auth + { + $request = $options['request'] ?? (function_exists('request') ? request() : null); + unset($options['request']); + if ($request && !isset($request->userAuth)) { + $request->userAuth = new static($options); + } + return $request && isset($request->userAuth) ? $request->userAuth : new static($options); + } + + public function init($token): bool + { + $tokenData = Token::get($token); + if ($tokenData) { + Token::tokenExpirationCheck($tokenData); + $userId = $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; + } + + public function register(string $username, string $password = '', string $mobile = '', string $email = '', int $group = 1, array $extend = []): bool + { + $request = function_exists('request') ? request() : null; + $ip = $request ? $request->getRealIp() : '0.0.0.0'; + + if ($email && !filter_var($email, FILTER_VALIDATE_EMAIL)) { + $this->setError(__('Email')); + return false; + } + if ($username && !preg_match('/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/', $username)) { + $this->setError(__('Username')); + return false; + } + if (User::where('email', $email)->find() && $email) { + $this->setError(__('Email') . ' ' . __('already exists')); + return false; + } + if (User::where('username', $username)->find()) { + $this->setError(__('Username') . ' ' . __('already exists')); + return false; + } + + $nickname = preg_replace_callback('/1[3-9]\d{9}/', fn($m) => substr($m[0], 0, 3) . '****' . substr($m[0], 7), $username); + $time = time(); + $data = [ + 'group_id' => $group, + 'nickname' => $nickname, + 'join_ip' => $ip, + 'join_time' => $time, + 'last_login_ip' => $ip, + 'last_login_time' => $time, + 'status' => 'enable', + ]; + $data = array_merge(compact('username', 'password', 'mobile', 'email'), $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; + } + + public function login(string $username, string $password, bool $keep): bool + { + $accountType = false; + if (preg_match('/^1[3-9]\d{9}$/', $username)) $accountType = 'mobile'; + elseif (filter_var($username, FILTER_VALIDATE_EMAIL)) $accountType = 'email'; + elseif (preg_match('/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/', $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('buildadmin.user_login_retry'); + if ($userLoginRetry && $this->model->last_login_time) { + $lastLoginTs = is_numeric($this->model->last_login_time) ? (int)$this->model->last_login_time : strtotime($this->model->last_login_time); + if ($this->model->login_failure > 0 && $lastLoginTs > 0 && time() - $lastLoginTs >= 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; + } + + if (config('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); + return $this->loginSuccessful(); + } + + public function direct(int $userId): bool + { + $this->model = User::find($userId); + if (!$this->model) return false; + if (config('buildadmin.user_sso')) { + Token::clear(self::TOKEN_TYPE, $this->model->id); + Token::clear(self::TOKEN_TYPE . '-refresh', $this->model->id); + } + return $this->loginSuccessful(); + } + + public function loginSuccessful(): bool + { + if (!$this->model) return false; + $request = function_exists('request') ? request() : null; + $ip = $request ? $request->getRealIp() : '0.0.0.0'; + if (!$this->token) { + $this->token = Random::uuid(); + Token::set($this->token, self::TOKEN_TYPE, $this->model->id, $this->keepTime); + } + $this->model->startTrans(); + try { + $this->model->login_failure = 0; + $this->model->last_login_time = time(); + $this->model->last_login_ip = $ip; + $this->model->save(); + $this->loginEd = true; + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + if ($this->token) { + Token::delete($this->token); + $this->token = ''; + } + $this->setError($e->getMessage()); + return false; + } + return true; + } + + public function loginFailed(): bool + { + if (!$this->model) return false; + $request = function_exists('request') ? request() : null; + $ip = $request ? $request->getRealIp() : '0.0.0.0'; + $this->model->startTrans(); + try { + $this->model->login_failure++; + $this->model->last_login_time = time(); + $this->model->last_login_ip = $ip; + $this->model->save(); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + } + return $this->reset(); + } + + public function logout(): bool + { + if (!$this->loginEd) { + $this->setError('You are not logged in'); + return false; + } + return $this->reset(); + } + + public function isLogin(): bool + { + return $this->loginEd; + } + + public function getUser(): User + { + return $this->model; + } + + public function getToken(): string + { + return $this->token; + } + + public function setRefreshToken(int $keepTime = 0): void + { + $this->refreshToken = Random::uuid(); + Token::set($this->refreshToken, self::TOKEN_TYPE . '-refresh', $this->model->id, $keepTime); + } + + public function getRefreshToken(): string + { + return $this->refreshToken; + } + + 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; + } + + public function getAllowFields(): array + { + return $this->allowFields; + } + + public function setAllowFields($fields): void + { + $this->allowFields = $fields; + } + + 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); + } + + public function isSuperUser(): bool + { + return in_array('*', $this->getRuleIds()); + } + + public function setError(string $error): Auth + { + $this->error = $error; + return $this; + } + + 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('buildadmin.user_token_keep_time', 86400)); + return true; + } +} diff --git a/app/common/library/Email.php b/app/common/library/Email.php new file mode 100644 index 0000000..688eaf0 --- /dev/null +++ b/app/common/library/Email.php @@ -0,0 +1,66 @@ + 'utf-8', + 'debug' => true, + 'lang' => 'zh_cn', + ]; + + public function __construct(array $options = []) + { + $this->options = array_merge($this->options, $options); + + parent::__construct($this->options['debug']); + + $langSet = function_exists('locale') ? locale() : 'zh_CN'; + if ($langSet == 'zh-cn' || $langSet == 'zh_CN' || !$langSet) { + $langSet = 'zh_cn'; + } + $this->options['lang'] = $this->options['lang'] ?: $langSet; + + $langPath = root_path() . 'vendor' . DIRECTORY_SEPARATOR . 'phpmailer' . DIRECTORY_SEPARATOR . 'phpmailer' . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR; + if (is_dir($langPath)) { + $this->setLanguage($this->options['lang'], $langPath); + } + $this->CharSet = $this->options['charset']; + + $sysMailConfig = get_sys_config('', 'mail'); + $this->configured = true; + if (is_array($sysMailConfig)) { + foreach ($sysMailConfig as $item) { + if (!$item) { + $this->configured = false; + break; + } + } + } else { + $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'] ?? 465; + $this->setFrom($sysMailConfig['smtp_sender_mail'] ?? '', $sysMailConfig['smtp_user'] ?? ''); + } + } + + public function setSubject($subject): void + { + $this->Subject = "=?utf-8?B?" . base64_encode($subject) . "?="; + } +} diff --git a/app/common/library/Menu.php b/app/common/library/Menu.php new file mode 100644 index 0000000..85cc396 --- /dev/null +++ b/app/common/library/Menu.php @@ -0,0 +1,133 @@ +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') { + $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); + } + } + } + + 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; + } + + 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; + } + + 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; + } +} diff --git a/app/common/library/Token.php b/app/common/library/Token.php new file mode 100644 index 0000000..766f31d --- /dev/null +++ b/app/common/library/Token.php @@ -0,0 +1,146 @@ +handler !== null) { + return $this->handler; + } + $name = $name ?: $this->getDefaultDriver(); + if ($name === null) { + throw new InvalidArgumentException(sprintf('Unable to resolve NULL driver for [%s].', static::class)); + } + return $this->createDriver($name); + } + + protected function createDriver(string $name): object + { + $type = $this->resolveType($name); + $params = $this->resolveParams($name); + $class = $this->resolveClass($type); + + if (isset($this->instance[$type])) { + return $this->instance[$type]; + } + return new $class(...$params); + } + + protected function getDefaultDriver(): string + { + return $this->getConfig('default'); + } + + protected function getConfig(?string $name = null, mixed $default = null): array|string + { + $config = config('buildadmin.token', []); + if ($name === null) { + return $config; + } + $keys = explode('.', $name); + $val = $config; + foreach ($keys as $k) { + if (!is_array($val) || !array_key_exists($k, $val)) { + return $default; + } + $val = $val[$k]; + } + return $val; + } + + protected function resolveParams(string $name): array + { + $config = $this->getStoreConfig($name); + return [$config]; + } + + protected function resolveClass(string $type): string + { + $class = str_contains($type, '\\') ? $type : $this->namespace . $this->studly($type); + if (class_exists($class)) { + return $class; + } + throw new InvalidArgumentException("Driver [{$type}] not supported."); + } + + protected function getStoreConfig(string $store, ?string $name = null, mixed $default = null): array|string + { + $config = $this->getConfig("stores.{$store}"); + if ($config === null) { + throw new InvalidArgumentException("Store [{$store}] not found."); + } + if ($name === null) { + return $config; + } + $keys = explode('.', $name); + $val = $config; + foreach ($keys as $k) { + if (!is_array($val) || !array_key_exists($k, $val)) { + return $default; + } + $val = $val[$k]; + } + return $val; + } + + protected function resolveType(string $name): string + { + return $this->getStoreConfig($name, 'type', 'Mysql'); + } + + private function studly(string $value): string + { + $value = ucwords(str_replace(['-', '_'], ' ', $value)); + return str_replace(' ', '', $value); + } + + public function set(string $token, string $type, int $userId, ?int $expire = null): bool + { + return $this->getDriver()->set($token, $type, $userId, $expire); + } + + public function get(string $token, bool $expirationException = true): array + { + return $this->getDriver()->get($token); + } + + public function check(string $token, string $type, int $userId, bool $expirationException = true): bool + { + return $this->getDriver()->check($token, $type, $userId); + } + + public function delete(string $token): bool + { + return $this->getDriver()->delete($token); + } + + public function clear(string $type, int $userId): bool + { + return $this->getDriver()->clear($type, $userId); + } + + /** + * 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..fd1df72 --- /dev/null +++ b/app/common/library/Upload.php @@ -0,0 +1,260 @@ + 'local', + 'handler' => [], + 'namespace' => '\\app\\common\\library\\upload\\driver\\', + ]; + protected string $topic = 'default'; + + public function __construct(?WebmanUploadedFile $file = null, array $config = []) + { + $upload = config('upload', []); + $this->config = array_merge($upload, $config); + + if ($file) { + $this->setFile($file); + } + } + + public function setFile(?WebmanUploadedFile $file): self + { + if (empty($file)) { + throw new RuntimeException(__('No files were uploaded')); + } + + $suffix = strtolower($file->extension()); + $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file'; + $this->fileInfo = [ + 'suffix' => $suffix, + 'type' => $file->getMime(), + 'size' => $file->getSize(), + 'name' => $file->getOriginalName(), + 'sha1' => $file->sha1(), + ]; + $this->file = $file; + return $this; + } + + public function setDriver(string $driver): self + { + $this->driver['name'] = $driver; + return $this; + } + + public function getDriver(?string $driver = null, bool $noDriveException = true): Driver|false + { + $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): string|false + { + if ($this->driver['namespace'] || str_contains($driver, '\\')) { + $class = str_contains($driver, '\\') ? $driver : $this->driver['namespace'] . $this->studly($driver); + if (class_exists($class)) { + return $class; + } + } + return false; + } + + protected function studly(string $value): string + { + $value = ucwords(str_replace(['-', '_'], ' ', $value)); + return str_replace(' ', '', $value); + } + + public function setTopic(string $topic): self + { + $this->topic = $topic; + return $this; + } + + 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'])) { + $path = $this->file->getPathname(); + $imgInfo = is_file($path) ? getimagesize($path) : false; + if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) { + throw new RuntimeException(__('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; + } + + public function isImage(): bool + { + return $this->isImage; + } + + public function getSuffix(): string + { + return $this->fileInfo['suffix'] ?? 'file'; + } + + 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)); + } + + public function validates(): void + { + if (empty($this->file)) { + throw new RuntimeException(__('No files have been uploaded or the file size exceeds the upload limit of the server')); + } + + $size = Filesystem::fileUnitToByte($this->config['max_size'] ?? '10M'); + $mime = $this->checkConfig($this->config['allowed_mime_types'] ?? []); + $suffix = $this->checkConfig($this->config['allowed_suffixes'] ?? ''); + + if ($this->fileInfo['size'] > $size) { + throw new RuntimeException(__('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 && !in_array(strtolower($this->fileInfo['suffix']), $suffix)) { + throw new RuntimeException(__('The uploaded file format is not allowed')); + } + + if ($mime && !in_array(strtolower($this->fileInfo['type']), $mime)) { + throw new RuntimeException(__('The uploaded file format is not allowed')); + } + + if (!preg_match('/^[a-zA-Z0-9_-]+$/', $this->topic)) { + throw new RuntimeException(__('Topic format error')); + } + + if (!preg_match('/^[a-zA-Z0-9_-]+$/', $this->driver['name'])) { + throw new RuntimeException(__('Driver %s not supported', [$this->driver['name']])); + } + + if ($this->checkIsImage()) { + $maxW = $this->config['image_max_width'] ?? 0; + $maxH = $this->config['image_max_height'] ?? 0; + if ($maxW && $this->fileInfo['width'] > $maxW) { + throw new RuntimeException(__('The uploaded image file is not a valid image')); + } + if ($maxH && $this->fileInfo['height'] > $maxH) { + throw new RuntimeException(__('The uploaded image file is not a valid image')); + } + } + } + + public function upload(?string $saveName = null, int $adminId = 0, int $userId = 0): array + { + $this->validates(); + + $driver = $this->getDriver(); + if (!$driver) { + throw new RuntimeException(__('Driver %s not supported', [$this->driver['name']])); + } + + $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 + { + $pattern = "/[\s:@#?&\/=',+]+/u"; + $fileName = str_replace(".$suffix", '', $fileName); + $fileName = preg_replace($pattern, '', $fileName); + return mb_substr(htmlspecialchars(strip_tags($fileName)), 0, $length); + } + + protected function checkConfig(mixed $configItem): array + { + if (is_array($configItem)) { + return array_map('strtolower', $configItem); + } + return $configItem ? explode(',', strtolower((string)$configItem)) : []; + } +} diff --git a/app/common/library/token/Driver.php b/app/common/library/token/Driver.php new file mode 100644 index 0000000..21e27e6 --- /dev/null +++ b/app/common/library/token/Driver.php @@ -0,0 +1,66 @@ +handler; + } + + protected function getEncryptedToken(string $token): string + { + $config = config('buildadmin.token'); + return hash_hmac($config['algo'], $token, $config['key']); + } + + protected function getExpiredIn(int $expireTime): int + { + return $expireTime ? max(0, $expireTime - time()) : 365 * 86400; + } +} diff --git a/app/common/library/token/TokenExpirationException.php b/app/common/library/token/TokenExpirationException.php new file mode 100644 index 0000000..9878967 --- /dev/null +++ b/app/common/library/token/TokenExpirationException.php @@ -0,0 +1,27 @@ +data; + } +} diff --git a/app/common/library/token/driver/Mysql.php b/app/common/library/token/driver/Mysql.php new file mode 100644 index 0000000..93b105b --- /dev/null +++ b/app/common/library/token/driver/Mysql.php @@ -0,0 +1,117 @@ +options = array_merge($this->options, $options); + } + + if (!empty($this->options['name'])) { + $this->handler = Db::connect($this->options['name'])->name($this->options['table']); + } else { + $this->handler = Db::name($this->options['table']); + } + } + + public function set(string $token, string $type, int $userId, ?int $expire = null): bool + { + if ($expire === null) { + $expire = $this->options['expire'] ?? 2592000; + } + $expireTime = $expire !== 0 ? time() + $expire : 0; + $encryptedToken = $this->getEncryptedToken($token); + $this->handler->insert([ + 'token' => $encryptedToken, + 'type' => $type, + 'user_id' => $userId, + 'create_time' => time(), + 'expire_time' => $expireTime, + ]); + + // 每隔 48 小时清理一次过期 Token + $time = time(); + $lastCacheCleanupTime = $this->getLastCacheCleanupTime(); + if (!$lastCacheCleanupTime || $lastCacheCleanupTime < $time - 172800) { + $this->setLastCacheCleanupTime($time); + $this->handler->where('expire_time', '<', time())->where('expire_time', '>', 0)->delete(); + } + return true; + } + + public function get(string $token): array + { + $data = $this->handler->where('token', $this->getEncryptedToken($token))->find(); + if (!$data) { + return []; + } + + $data['token'] = $token; + $data['expires_in'] = $this->getExpiredIn($data['expire_time'] ?? 0); + return $data; + } + + 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; + } + + public function delete(string $token): bool + { + $this->handler->where('token', $this->getEncryptedToken($token))->delete(); + return true; + } + + public function clear(string $type, int $userId): bool + { + $this->handler->where('type', $type)->where('user_id', $userId)->delete(); + return true; + } + + /** + * 使用文件存储 last_cache_cleanup_time(兼容无 cache 插件环境) + */ + private function getLastCacheCleanupTime(): ?int + { + $path = $this->getCleanupTimePath(); + if (!is_file($path)) { + return null; + } + $v = file_get_contents($path); + return $v !== false && $v !== '' ? (int) $v : null; + } + + private function setLastCacheCleanupTime(int $time): void + { + $path = $this->getCleanupTimePath(); + $dir = dirname($path); + if (!is_dir($dir)) { + @mkdir($dir, 0755, true); + } + @file_put_contents($path, (string) $time); + } + + private function getCleanupTimePath(): string + { + $base = defined('RUNTIME_PATH') ? RUNTIME_PATH : (base_path() . DIRECTORY_SEPARATOR . 'runtime'); + return $base . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'token_last_cleanup.txt'; + } +} diff --git a/app/common/library/upload/Driver.php b/app/common/library/upload/Driver.php new file mode 100644 index 0000000..e73c7cc --- /dev/null +++ b/app/common/library/upload/Driver.php @@ -0,0 +1,35 @@ +file->getUploadExtension(); + return $ext && preg_match("/^[a-zA-Z0-9]+$/", $ext) ? $ext : 'file'; + } + + public function getMime(): string + { + return $this->file->getUploadMimeType() ?? ''; + } + + public function getSize(): int + { + $size = $this->file->getSize(); + return $size !== false ? $size : 0; + } + + public function getOriginalName(): string + { + return $this->file->getUploadName() ?? ''; + } + + public function sha1(): string + { + $path = $this->file->getPathname(); + return is_file($path) ? hash_file('sha1', $path) : ''; + } + + public function getPathname(): string + { + return $this->file->getPathname(); + } + + /** + * 移动文件(兼容 ThinkPHP move($dir, $name) 与 Webman move($fullPath)) + */ + public function move(string $directory, ?string $name = null): self + { + $destination = rtrim($directory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ($name ?? basename($this->file->getUploadName())); + $this->file->move($destination); + return $this; + } + + public function getUploadFile(): UploadFile + { + return $this->file; + } +} diff --git a/app/common/library/upload/driver/Local.php b/app/common/library/upload/driver/Local.php new file mode 100644 index 0000000..e1e5dbc --- /dev/null +++ b/app/common/library/upload/driver/Local.php @@ -0,0 +1,105 @@ +options = config('filesystem.disks.public', []); + if (!empty($options)) { + $this->options = array_merge($this->options, $options); + } + } + + public function save(WebmanUploadedFile $file, string $saveName): bool + { + $savePathInfo = pathinfo($saveName); + $saveFullPath = $this->getFullPath($saveName); + $destination = rtrim($saveFullPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $savePathInfo['basename']; + + $saveDir = dirname($destination); + if (!is_dir($saveDir) && !@mkdir($saveDir, 0755, true)) { + throw new RuntimeException(__('Failed to create upload directory')); + } + + $uploadFile = $file->getUploadFile(); + $uploadFile->move($destination); + @chmod($destination, 0666 & ~umask()); + return true; + } + + public function delete(string $saveName): bool + { + $saveFullName = $this->getFullPath($saveName, true); + if ($this->exists($saveFullName)) { + @unlink($saveFullName); + } + Filesystem::delEmptyDir(dirname($saveFullName)); + return true; + } + + public function url(string $saveName, string|bool $domain = true, string $default = ''): string + { + $saveName = $this->clearRootPath($saveName); + $saveName = $saveName ? '/' . ltrim(str_replace('\\', '/', $saveName), '/') : ''; + + if ($domain === true) { + $req = function_exists('request') ? request() : null; + $domain = $req && method_exists($req, 'host') ? '//' . $req->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); + } + + public function exists(string $saveName): bool + { + $saveFullName = $this->getFullPath($saveName, true); + return file_exists($saveFullName); + } + + public function getFullPath(string $saveName, bool $baseName = false): string + { + $savePathInfo = pathinfo($saveName); + $root = $this->getRootPath(); + $dirName = $savePathInfo['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 + { + $root = $this->options['root'] ?? rtrim(base_path(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'public'; + return Filesystem::fsFit($root); + } +} diff --git a/app/common/middleware/AdminLog.php b/app/common/middleware/AdminLog.php new file mode 100644 index 0000000..af96855 --- /dev/null +++ b/app/common/middleware/AdminLog.php @@ -0,0 +1,36 @@ +path(), '/'); + if (str_starts_with($path, 'admin/') && config('buildadmin.auto_write_admin_log', true)) { + $method = $request->method(); + if ($method === 'POST' || $method === 'DELETE') { + try { + AdminLogModel::instance($request)->record(); + } catch (\Throwable $e) { + \support\Log::warning('[AdminLog] ' . $e->getMessage()); + } + } + } + + return $response; + } +} diff --git a/app/common/middleware/AllowCrossDomain.php b/app/common/middleware/AllowCrossDomain.php new file mode 100644 index 0000000..347eb79 --- /dev/null +++ b/app/common/middleware/AllowCrossDomain.php @@ -0,0 +1,94 @@ + 'true', + 'Access-Control-Max-Age' => '1800', + 'Access-Control-Allow-Methods' => '*', + 'Access-Control-Allow-Headers' => '*', + ]; + + /** + * 返回 CORS 预检(OPTIONS)响应,供路由直接调用(Webman 未匹配路由时不走中间件) + */ + public static function optionsResponse(Request $request): Response + { + $header = [ + 'Access-Control-Allow-Credentials' => 'true', + 'Access-Control-Max-Age' => '1800', + 'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, PATCH, OPTIONS', + 'Access-Control-Allow-Headers' => 'Content-Type, Authorization, batoken, ba-user-token, think-lang', + ]; + $origin = $request->header('origin'); + if (is_array($origin)) { + $origin = $origin[0] ?? ''; + } + $origin = is_string($origin) ? trim($origin) : ''; + if ($origin !== '') { + $info = parse_url($origin); + $host = $info['host'] ?? ''; + $corsDomain = array_map('trim', explode(',', config('buildadmin.cors_request_domain', ''))); + $corsDomain[] = $request->host(true); + $allowed = in_array('*', $corsDomain) + || in_array($origin, $corsDomain) + || in_array($host, $corsDomain) + || ($host === 'localhost' || $host === '127.0.0.1'); + if ($allowed) { + $header['Access-Control-Allow-Origin'] = $origin; + } + } + return response('', 204, $header); + } + + public function process(Request $request, callable $handler): Response + { + $path = trim($request->path(), '/'); + if (!str_starts_with($path, 'api/') && !str_starts_with($path, 'admin/')) { + return $handler($request); + } + + $header = $this->header; + + $origin = $request->header('origin'); + if (is_array($origin)) { + $origin = $origin[0] ?? ''; + } + $origin = is_string($origin) ? trim($origin) : ''; + + if ($origin !== '') { + $info = parse_url($origin); + $host = $info['host'] ?? ''; + $corsDomain = array_map('trim', explode(',', config('buildadmin.cors_request_domain', ''))); + $corsDomain[] = $request->host(true); + + $allowed = in_array('*', $corsDomain) + || in_array($origin, $corsDomain) + || in_array($host, $corsDomain) + || ($host === 'localhost' || $host === '127.0.0.1'); + + if ($allowed) { + $header['Access-Control-Allow-Origin'] = $origin; + } + } + + if ($request->method() === 'OPTIONS') { + return response('', 204, $header); + } + + $response = $handler($request); + return $response->withHeaders($header); + } +} diff --git a/app/common/middleware/LoadLangPack.php b/app/common/middleware/LoadLangPack.php new file mode 100644 index 0000000..a51a14f --- /dev/null +++ b/app/common/middleware/LoadLangPack.php @@ -0,0 +1,74 @@ +path(), '/'); + if (str_starts_with($path, 'api/') || str_starts_with($path, 'admin/')) { + $this->loadLang($request); + } + return $handler($request); + } + + protected function loadLang(Request $request): void + { + // 优先从请求头 think-lang 获取前端选择的语言(与前端 axios 发送的 header 对应) + $headerLang = $request->header('think-lang'); + $allowLangList = config('lang.allow_lang_list', ['zh-cn', 'en']); + if ($headerLang && in_array(str_replace('_', '-', strtolower($headerLang)), $allowLangList)) { + $langSet = str_replace('_', '-', strtolower($headerLang)); + } else { + $langSet = config('lang.default_lang', config('translation.locale', 'zh-cn')); + $langSet = str_replace('_', '-', strtolower($langSet)); + } + + // 设置当前请求的翻译语言,使 __() 和 trans() 使用正确的语言 + if (function_exists('locale')) { + locale($langSet); + } + + $path = trim($request->path(), '/'); + $parts = explode('/', $path); + $app = $parts[0] ?? 'api'; + + $appLangDir = base_path() . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . $app . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR; + + if (!class_exists(\support\Translation::class)) { + return; + } + + $translator = \support\Translation::instance(); + + // 1. 加载根级语言包(zh-cn.php / en.php),供 common 翻译使用 + $rootLangFile = $appLangDir . $langSet . '.php'; + if (is_file($rootLangFile)) { + $translator->addResource('phpfile', $rootLangFile, $langSet, 'messages'); + } + + // 2. 加载控制器专用语言包(如 zh-cn/auth/group.php),供 get_route_remark 等使用 + $controllerPath = get_controller_path($request); + if ($controllerPath) { + $controllerPathForFile = str_replace('.', '/', $controllerPath); + $controllerPathForFile = implode('/', array_map(function ($p) { + return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $p)); + }, explode('/', $controllerPathForFile))); + $controllerLangFile = $appLangDir . $langSet . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $controllerPathForFile) . '.php'; + if (is_file($controllerLangFile)) { + $translator->addResource('phpfile', $controllerLangFile, $langSet, $controllerPath); + } + } + } +} diff --git a/app/common/model/Attachment.php b/app/common/model/Attachment.php new file mode 100644 index 0000000..ee61446 --- /dev/null +++ b/app/common/model/Attachment.php @@ -0,0 +1,42 @@ +belongsTo(\app\admin\model\Admin::class, 'admin_id'); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class, 'user_id'); + } +} diff --git a/app/common/model/User.php b/app/common/model/User.php new file mode 100644 index 0000000..f452eca --- /dev/null +++ b/app/common/model/User.php @@ -0,0 +1,40 @@ +where(['id' => $uid])->update(['password' => hash_password($newPassword), 'salt' => '']); + } + + public function getMoneyAttr($value): string + { + return bcdiv((string)$value, '100', 2); + } + + public function setMoneyAttr($value): string + { + return bcmul((string)$value, '100', 2); + } +} diff --git a/app/common/model/UserMoneyLog.php b/app/common/model/UserMoneyLog.php new file mode 100644 index 0000000..da8febf --- /dev/null +++ b/app/common/model/UserMoneyLog.php @@ -0,0 +1,43 @@ + + * { + padding: 0; + margin: 0; + } + iframe { + border: none; + overflow: scroll; + } + + +EOF; + } + + public function view(Request $request) + { + return view('index/view', ['name' => 'webman']); + } + + public function json(Request $request) + { + return json(['code' => 0, 'msg' => 'ok']); + } + +} diff --git a/app/functions.php b/app/functions.php new file mode 100644 index 0000000..89a08a7 --- /dev/null +++ b/app/functions.php @@ -0,0 +1,657 @@ +where('name', $name)->find(); + return $config ? $config['value'] : null; + } + 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']; + } + return $config; + } + return $temp; + } + return config("sys_config.{$name}", null); + } +} + +if (!function_exists('clear_config_cache')) { + /** + * 清理配置缓存(Config 写入后调用) + */ + function clear_config_cache(): void + { + $cachePath = base_path() . DIRECTORY_SEPARATOR . 'runtime' . DIRECTORY_SEPARATOR . 'cache'; + if (!is_dir($cachePath)) { + return; + } + $files = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($cachePath, \RecursiveDirectoryIterator::SKIP_DOTS), + \RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ($files as $file) { + if ($file->isFile()) { + @unlink($file->getRealPath()); + } + } + } +} + +if (!function_exists('ip_check')) { + /** + * IP 检查 + * @param string|null $ip 要检查的 IP,null 时从 request 获取 + * @param \Webman\Http\Request|null $request + * @return Response|null 禁止访问时返回 Response,否则 null + */ + function ip_check(?string $ip = null, $request = null): ?Response + { + if ($ip === null && $request) { + $ip = $request->getRealIp(); + } + if (!$ip) { + return null; + } + $noAccess = get_sys_config('no_access_ip'); + $noAccess = !$noAccess ? [] : array_filter(explode("\n", str_replace("\r\n", "\n", (string) $noAccess))); + if ($noAccess && IpUtils::checkIp($ip, $noAccess)) { + return response(json_encode(['msg' => 'No permission request']), 403, ['Content-Type' => 'application/json']); + } + return null; + } +} + +if (!function_exists('get_auth_token')) { + /** + * 获取鉴权 token + * @param array $names 如 ['ba', 'token'] + * @param \Webman\Http\Request|null $request + */ + function get_auth_token(array $names = ['ba', 'token'], $request = null): string + { + $request = $request ?? (function_exists('request') ? request() : null); + if (!$request) { + return ''; + } + $separators = [ + 'header' => ['', '-'], + 'param' => ['', '-', '_'], + 'server' => ['_'], + ]; + $tokens = []; + foreach ($separators as $source => $sps) { + foreach ($sps as $sp) { + $key = ($source === 'server' ? 'http_' : '') . implode($sp, $names); + if ($source === 'header') { + $val = $request->header($key); + } elseif ($source === 'param') { + $val = $request->get($key) ?? $request->post($key); + } else { + $val = $_SERVER[$key] ?? null; + } + if ($val) { + $tokens[] = $val; + } + } + } + return $tokens[0] ?? ''; + } +} + +if (!function_exists('get_controller_path')) { + /** + * 从 Request 或路由获取控制器路径(等价于 ThinkPHP controllerPath) + * 优先从 $request->controller(Webman 路由匹配时设置)解析,否则从 path 解析 + * @param \Webman\Http\Request|null $request + * @return string|null 如 auth/admin、user/user + */ + function get_controller_path($request = null): ?string + { + $request = $request ?? (function_exists('request') ? request() : null); + if (!$request) { + return null; + } + + // 优先从路由匹配的 controller 解析(Webman 在路由匹配后设置) + $controller = $request->controller ?? null; + if ($controller && is_string($controller)) { + foreach (['app\\admin\\controller\\', 'app\\api\\controller\\'] as $prefix) { + if (str_starts_with($controller, $prefix)) { + $relative = substr($controller, strlen($prefix)); + $parts = explode('\\', $relative); + $path = []; + foreach ($parts as $p) { + $path[] = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $p)); + } + return implode('/', $path); + } + } + } + + // 回退:从 path 解析(如 admin/auth/admin/index -> auth/admin) + $path = trim($request->path(), '/'); + if (!$path) { + return null; + } + $parts = explode('/', $path); + if (count($parts) < 2) { + return $parts[0] ?? null; + } + return implode('/', array_slice($parts, 1, -1)) ?: $parts[1]; + } +} + +if (!function_exists('action_in_arr')) { + /** + * 检测当前方法是否在数组中(用于 noNeedLogin、noNeedPermission) + * @param array $arr + * @param string|null $action 当前 action,null 时从 request path 解析 + */ + function action_in_arr(array $arr, ?string $action = null): bool + { + if (!$arr) { + return false; + } + $arr = array_map('strtolower', $arr); + if (in_array('*', $arr)) { + return true; + } + if ($action === null && function_exists('request')) { + $req = request(); + $path = trim($req->path(), '/'); + $parts = explode('/', $path); + $action = $parts[array_key_last($parts)] ?? ''; + } + return $action ? in_array(strtolower($action), $arr) : false; + } +} + +if (!function_exists('event_trigger')) { + /** + * 触发事件(BuildAdmin 兼容,替代 Event::trigger) + * @param string $event + * @param mixed ...$args + */ + function event_trigger(string $event, mixed ...$args): void + { + $listeners = config("events.listen.{$event}", []); + foreach ($listeners as $listener) { + try { + if (is_string($listener) && class_exists($listener)) { + $instance = new $listener(); + if (method_exists($instance, 'handle')) { + $instance->handle(...$args); + } + } elseif (is_callable($listener)) { + $listener(...$args); + } + } catch (\Throwable $e) { + if (class_exists(\support\Log::class)) { + \support\Log::warning("[event_trigger] {$event}: " . $e->getMessage()); + } + } + } + } +} + +if (!function_exists('set_timezone')) { + /** + * 设置时区 + */ + function set_timezone(?string $timezone = null): void + { + $defaultTimezone = config('app.default_timezone', 'Asia/Shanghai'); + $timezone = $timezone ?? get_sys_config('time_zone'); + if ($timezone && $defaultTimezone !== $timezone) { + date_default_timezone_set($timezone); + } + } +} + +if (!function_exists('encrypt_password')) { + /** + * 加密密码(兼容旧版 md5) + * @deprecated 使用 hash_password 代替 + */ + function encrypt_password(string $password, string $salt = '', string $encrypt = 'md5'): string + { + 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')) { + /** + * 验证密码是否和散列值匹配 + */ + function verify_password(string $password, string $hash, array $extend = []): bool + { + if (str_starts_with($hash, '$') || password_get_info($hash)['algoName'] !== 'unknown') { + return password_verify($password, $hash); + } + return encrypt_password($password, $extend['salt'] ?? '') === $hash; + } +} + +if (!function_exists('full_url')) { + /** + * 获取资源完整 url 地址 + */ + function full_url(string $relativeUrl = '', string|bool $domain = true, string $default = ''): string + { + $cdnUrl = config('buildadmin.cdn_url'); + if (!$cdnUrl && function_exists('request')) { + $req = request(); + $cdnUrl = $req ? '//' . $req->host() : '//localhost'; + } elseif (!$cdnUrl) { + $cdnUrl = '//localhost'; + } + + 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('buildadmin.cdn_url_params'); + if ($domain === $cdnUrl && $cdnUrlParams) { + $separator = str_contains($url, '?') ? '&' : '?'; + $url .= $separator . $cdnUrlParams; + } + + return $url; + } +} + +if (!function_exists('parse_name')) { + /** + * 命名转换(ThinkPHP 兼容) + * @param string $name 名称 + * @param int $type 0=转小写+下划线 1=驼峰 2=首字母大写驼峰 + * @param string $delimiter 分隔符 + */ + function parse_name(string $name, int $type = 0, string $delimiter = '_'): string + { + if ($type === 0) { + return strtolower(preg_replace('/([A-Z])/', $delimiter . '$1', lcfirst($name))); + } + if ($type === 1) { + $name = str_replace($delimiter, ' ', $name); + return lcfirst(str_replace(' ', '', ucwords($name))); + } + if ($type === 2) { + $name = str_replace($delimiter, ' ', $name); + return str_replace(' ', '', ucwords($name)); + } + return $name; + } +} + +if (!function_exists('root_path')) { + /** + * 根路径(BuildAdmin 兼容,等价于 base_path) + * 无参数时返回带尾部分隔符的路径,确保 root_path() . 'app' 拼接正确 + * @param string $path 子路径 + */ + function root_path(string $path = ''): string + { + $base = base_path($path); + if ($path === '' && $base !== '') { + return rtrim($base, DIRECTORY_SEPARATOR . '/') . DIRECTORY_SEPARATOR; + } + return $base; + } +} + +if (!function_exists('app_path')) { + /** + * 应用目录路径(Webman 兼容,用于 CRUD Helper 等) + * @param string $path 子路径 + */ + function app_path(string $path = ''): string + { + $base = rtrim(base_path(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'app'; + return $path ? $base . DIRECTORY_SEPARATOR . ltrim(str_replace('/', DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR) : $base; + } +} + +if (!function_exists('get_controller_list')) { + /** + * 获取控制器文件列表(递归) + * @param string $app 应用名,默认 admin + */ + function get_controller_list(string $app = 'admin'): array + { + $controllerDir = root_path() . 'app' . DIRECTORY_SEPARATOR . $app . DIRECTORY_SEPARATOR . 'controller' . DIRECTORY_SEPARATOR; + return (class_exists(\ba\Filesystem::class) && is_dir($controllerDir)) + ? \ba\Filesystem::getDirFiles($controllerDir) + : []; + } +} + +if (!function_exists('get_route_remark')) { + /** + * 获取当前路由后台菜单规则的备注信息 + * 使用控制器 domain 翻译,以支持不同控制器对同一 key(如 Remark lang)的不同翻译 + */ + function get_route_remark(): string + { + $controllerPath = get_controller_path() ?? ''; + $actionName = ''; + if (function_exists('request')) { + $req = request(); + if ($req) { + $path = trim($req->path(), '/'); + $parts = explode('/', $path); + $actionName = $parts[array_key_last($parts)] ?? ''; + } + } + $path = str_replace('.', '/', $controllerPath); + $names = [$path]; + if ($actionName) { + $names[] = $path . '/' . $actionName; + } + $remark = \support\think\Db::name('admin_rule') + ->where('name', 'in', $names) + ->value('remark'); + $remarkStr = (string) ($remark ?? ''); + if (!$remarkStr) { + return ''; + } + return function_exists('trans') ? trans($remarkStr, [], $controllerPath ?: null) : $remarkStr; + } +} + +if (!function_exists('keys_to_camel_case')) { + 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, '_') : $key; + if (is_array($value)) { + $result[$camelCaseKey] = keys_to_camel_case($value); + } else { + $result[$camelCaseKey] = $value; + } + } + return $result; + } +} + +if (!function_exists('get_upload_config')) { + function get_upload_config($request = null): array + { + event_trigger('uploadConfigInit', null); + $uploadConfig = config('upload', []); + $uploadConfig['max_size'] = \ba\Filesystem::fileUnitToByte($uploadConfig['max_size'] ?? '10M'); + $request = $request ?? (function_exists('request') ? request() : null); + $upload = $request && isset($request->upload) ? $request->upload : null; + if (!$upload) { + $uploadConfig['mode'] = 'local'; + return $uploadConfig; + } + unset($upload['cdn']); + return array_merge($upload, $uploadConfig); + } +} + +if (!function_exists('filter')) { + function filter(string $string): string + { + $string = trim($string); + $string = strip_tags($string); + return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8'); + } +} + +if (!function_exists('clean_xss')) { + function clean_xss(string $string): string + { + if (class_exists(\voku\helper\AntiXSS::class)) { + $antiXss = new \voku\helper\AntiXSS(); + $antiXss->removeEvilAttributes(['style']); + $antiXss->setReplacement('cleanXss'); + return $antiXss->xss_clean($string); + } + return strip_tags($string); + } +} + +if (!function_exists('htmlspecialchars_decode_improve')) { + function htmlspecialchars_decode_improve(string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401): string + { + return htmlspecialchars_decode($string, $flags); + } +} + +if (!function_exists('get_ba_client')) { + /** + * 获取请求 BuildAdmin 开源社区的 Guzzle Client(用于云端 CRUD 历史等) + */ + function get_ba_client(): \GuzzleHttp\Client + { + return new \GuzzleHttp\Client([ + 'base_uri' => config('buildadmin.api_url', 'https://api.buildadmin.com'), + 'timeout' => 30, + 'connect_timeout' => 30, + 'verify' => false, + 'http_errors' => false, + 'headers' => [ + 'X-REQUESTED-WITH' => 'XMLHttpRequest', + 'User-Agent' => 'BuildAdminClient', + ] + ]); + } +} + +if (!function_exists('str_attr_to_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], '.') !== false) { + $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('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('build_suffix_svg')) { + 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_account_verification_type')) { + /** + * 获取可用的账户验证方式 + * @return string[] email=电子邮件,mobile=手机短信验证 + */ + function get_account_verification_type(): array + { + $types = []; + $sysMailConfig = get_sys_config('', 'mail'); + $configured = true; + if (is_array($sysMailConfig)) { + foreach ($sysMailConfig as $item) { + if (!$item) { + $configured = false; + break; + } + } + } else { + $configured = false; + } + if ($configured) { + $types[] = 'email'; + } + if (class_exists(\app\admin\library\module\Server::class)) { + $sms = \app\admin\library\module\Server::getIni(\ba\Filesystem::fsFit(root_path() . 'modules/sms/')); + if ($sms && ($sms['state'] ?? 0) == 1) { + $types[] = 'mobile'; + } + } + return $types; + } +} + +if (!function_exists('get_area')) { + function get_area($request = null): array + { + $request = $request ?? (function_exists('request') ? request() : null); + $province = $request ? $request->get('province', '') : ''; + $city = $request ? $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 \support\think\Db::name('area') + ->where($where) + ->field('id as value,name as label') + ->select() + ->toArray(); + } +} diff --git a/app/middleware/StaticFile.php b/app/middleware/StaticFile.php new file mode 100644 index 0000000..fa8dbf7 --- /dev/null +++ b/app/middleware/StaticFile.php @@ -0,0 +1,42 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace app\middleware; + +use Webman\MiddlewareInterface; +use Webman\Http\Response; +use Webman\Http\Request; + +/** + * Class StaticFile + * @package app\middleware + */ +class StaticFile implements MiddlewareInterface +{ + public function process(Request $request, callable $handler): Response + { + // Access to files beginning with. Is prohibited + if (strpos($request->path(), '/.') !== false) { + return response('

403 forbidden

', 403); + } + /** @var Response $response */ + $response = $handler($request); + // Add cross domain HTTP header + /*$response->withHeaders([ + 'Access-Control-Allow-Origin' => '*', + 'Access-Control-Allow-Credentials' => 'true', + ]);*/ + return $response; + } +} diff --git a/app/model/Test.php b/app/model/Test.php new file mode 100644 index 0000000..92d70e3 --- /dev/null +++ b/app/model/Test.php @@ -0,0 +1,29 @@ +method(); + if (is_string($method) && strtoupper($method) === 'OPTIONS') { + $path = $request->path(); + $path = is_string($path) ? trim($path, '/') : ''; + $isApiOrAdmin = $path !== '' && (str_starts_with($path, 'api') || str_starts_with($path, 'admin')); + if ($isApiOrAdmin) { + $origin = $request->header('origin'); + $origin = is_array($origin) ? ($origin[0] ?? '') : (is_string($origin) ? trim($origin) : ''); + if ($origin === '') { + $origin = '*'; + } + $headers = [ + 'Access-Control-Allow-Origin' => $origin, + 'Access-Control-Allow-Credentials' => 'true', + 'Access-Control-Max-Age' => '1800', + 'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, PATCH, OPTIONS', + 'Access-Control-Allow-Headers' => 'Content-Type, Authorization, batoken, ba-user-token, think-lang', + ]; + $connection->send(new Response(204, $headers, '')); + return; + } + } + parent::onMessage($connection, $request); + } +} \ No newline at end of file diff --git a/app/process/Monitor.php b/app/process/Monitor.php new file mode 100644 index 0000000..3928adc --- /dev/null +++ b/app/process/Monitor.php @@ -0,0 +1,305 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace app\process; + +use FilesystemIterator; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use SplFileInfo; +use Workerman\Timer; +use Workerman\Worker; + +/** + * Class FileMonitor + * @package process + */ +class Monitor +{ + /** + * @var array + */ + protected array $paths = []; + + /** + * @var array + */ + protected array $extensions = []; + + /** + * @var array + */ + protected array $loadedFiles = []; + + /** + * @var int + */ + protected int $ppid = 0; + + /** + * Pause monitor + * @return void + */ + public static function pause(): void + { + file_put_contents(static::lockFile(), time()); + } + + /** + * Resume monitor + * @return void + */ + public static function resume(): void + { + clearstatcache(); + if (is_file(static::lockFile())) { + unlink(static::lockFile()); + } + } + + /** + * Whether monitor is paused + * @return bool + */ + public static function isPaused(): bool + { + clearstatcache(); + return file_exists(static::lockFile()); + } + + /** + * Lock file + * @return string + */ + protected static function lockFile(): string + { + return runtime_path('monitor.lock'); + } + + /** + * FileMonitor constructor. + * @param $monitorDir + * @param $monitorExtensions + * @param array $options + */ + public function __construct($monitorDir, $monitorExtensions, array $options = []) + { + $this->ppid = function_exists('posix_getppid') ? posix_getppid() : 0; + static::resume(); + $this->paths = (array)$monitorDir; + $this->extensions = $monitorExtensions; + foreach (get_included_files() as $index => $file) { + $this->loadedFiles[$file] = $index; + if (strpos($file, 'webman-framework/src/support/App.php')) { + break; + } + } + if (!Worker::getAllWorkers()) { + return; + } + $disableFunctions = explode(',', ini_get('disable_functions')); + if (in_array('exec', $disableFunctions, true)) { + echo "\nMonitor file change turned off because exec() has been disabled by disable_functions setting in " . PHP_CONFIG_FILE_PATH . "/php.ini\n"; + } else { + if ($options['enable_file_monitor'] ?? true) { + Timer::add(1, function () { + $this->checkAllFilesChange(); + }); + } + } + + $memoryLimit = $this->getMemoryLimit($options['memory_limit'] ?? null); + if ($memoryLimit && ($options['enable_memory_monitor'] ?? true)) { + Timer::add(60, [$this, 'checkMemory'], [$memoryLimit]); + } + } + + /** + * @param $monitorDir + * @return bool + */ + public function checkFilesChange($monitorDir): bool + { + static $lastMtime, $tooManyFilesCheck; + if (!$lastMtime) { + $lastMtime = time(); + } + clearstatcache(); + if (!is_dir($monitorDir)) { + if (!is_file($monitorDir)) { + return false; + } + $iterator = [new SplFileInfo($monitorDir)]; + } else { + // recursive traversal directory + $dirIterator = new RecursiveDirectoryIterator($monitorDir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS); + $iterator = new RecursiveIteratorIterator($dirIterator); + } + $count = 0; + foreach ($iterator as $file) { + $count ++; + /** @var SplFileInfo $file */ + if (is_dir($file->getRealPath())) { + continue; + } + // check mtime + if (in_array($file->getExtension(), $this->extensions, true) && $lastMtime < $file->getMTime()) { + $lastMtime = $file->getMTime(); + if (DIRECTORY_SEPARATOR === '/' && isset($this->loadedFiles[$file->getRealPath()])) { + echo "$file updated but cannot be reloaded because only auto-loaded files support reload.\n"; + continue; + } + $var = 0; + exec('"'.PHP_BINARY . '" -l ' . $file, $out, $var); + if ($var) { + continue; + } + // send SIGUSR1 signal to master process for reload + if (DIRECTORY_SEPARATOR === '/') { + if ($masterPid = $this->getMasterPid()) { + echo $file . " updated and reload\n"; + posix_kill($masterPid, SIGUSR1); + } else { + echo "Master process has gone away and can not reload\n"; + } + return true; + } + echo $file . " updated and reload\n"; + return true; + } + } + if (!$tooManyFilesCheck && $count > 1000) { + echo "Monitor: There are too many files ($count files) in $monitorDir which makes file monitoring very slow\n"; + $tooManyFilesCheck = 1; + } + return false; + } + + /** + * @return int + */ + public function getMasterPid(): int + { + if ($this->ppid === 0) { + return 0; + } + if (function_exists('posix_kill') && !posix_kill($this->ppid, 0)) { + echo "Master process has gone away\n"; + return $this->ppid = 0; + } + if (PHP_OS_FAMILY !== 'Linux') { + return $this->ppid; + } + $cmdline = "/proc/$this->ppid/cmdline"; + if (!is_readable($cmdline) || !($content = file_get_contents($cmdline)) || (!str_contains($content, 'WorkerMan') && !str_contains($content, 'php'))) { + // Process not exist + $this->ppid = 0; + } + return $this->ppid; + } + + /** + * @return bool + */ + public function checkAllFilesChange(): bool + { + if (static::isPaused()) { + return false; + } + foreach ($this->paths as $path) { + if ($this->checkFilesChange($path)) { + return true; + } + } + return false; + } + + /** + * @param $memoryLimit + * @return void + */ + public function checkMemory($memoryLimit): void + { + if (static::isPaused() || $memoryLimit <= 0) { + return; + } + $masterPid = $this->getMasterPid(); + if ($masterPid <= 0) { + echo "Master process has gone away\n"; + return; + } + + $childrenFile = "/proc/$masterPid/task/$masterPid/children"; + if (!is_file($childrenFile) || !($children = file_get_contents($childrenFile))) { + return; + } + foreach (explode(' ', $children) as $pid) { + $pid = (int)$pid; + $statusFile = "/proc/$pid/status"; + if (!is_file($statusFile) || !($status = file_get_contents($statusFile))) { + continue; + } + $mem = 0; + if (preg_match('/VmRSS\s*?:\s*?(\d+?)\s*?kB/', $status, $match)) { + $mem = $match[1]; + } + $mem = (int)($mem / 1024); + if ($mem >= $memoryLimit) { + posix_kill($pid, SIGINT); + } + } + } + + /** + * Get memory limit + * @param $memoryLimit + * @return int + */ + protected function getMemoryLimit($memoryLimit): int + { + if ($memoryLimit === 0) { + return 0; + } + $usePhpIni = false; + if (!$memoryLimit) { + $memoryLimit = ini_get('memory_limit'); + $usePhpIni = true; + } + + if ($memoryLimit == -1) { + return 0; + } + $unit = strtolower($memoryLimit[strlen($memoryLimit) - 1]); + $memoryLimit = (int)$memoryLimit; + if ($unit === 'g') { + $memoryLimit = 1024 * $memoryLimit; + } else if ($unit === 'k') { + $memoryLimit = ($memoryLimit / 1024); + } else if ($unit === 'm') { + $memoryLimit = (int)($memoryLimit); + } else if ($unit === 't') { + $memoryLimit = (1024 * 1024 * $memoryLimit); + } else { + $memoryLimit = ($memoryLimit / (1024 * 1024)); + } + if ($memoryLimit < 50) { + $memoryLimit = 50; + } + if ($usePhpIni) { + $memoryLimit = (0.8 * $memoryLimit); + } + return (int)$memoryLimit; + } + +} diff --git a/app/support/BaseController.php b/app/support/BaseController.php new file mode 100644 index 0000000..3309bf4 --- /dev/null +++ b/app/support/BaseController.php @@ -0,0 +1,101 @@ +app->request + * - 子类在方法开头调用 setRequest($request),之后可用 $this->request 访问 + */ +abstract class BaseController +{ + /** + * 当前请求实例(由 setRequest($request) 设置,来源于方法参数 $request,非 think\App) + * @var WebmanRequest|null + */ + protected ?WebmanRequest $request = null; + + /** + * 是否批量验证 + * @var bool + */ + protected bool $batchValidate = false; + + /** + * 初始化 + * @access protected + */ + protected function initialize(): void + { + } + + /** + * 设置当前请求(子类方法开头调用) + * @param WebmanRequest $request + */ + protected function setRequest(WebmanRequest $request): void + { + $this->request = $request; + } + + /** + * 操作成功(封装为返回 Response 的方法,替代原 $this->success() 抛异常) + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 业务状态码(1=成功) + * @param array $header 可含 statusCode 指定 HTTP 状态 + */ + protected function success(string $msg = '', mixed $data = null, int $code = 1, array $header = []): Response + { + return $this->result($msg, $data, $code, $header); + } + + /** + * 操作失败(封装为返回 Response 的方法,替代原 $this->error() 抛异常) + * @param string $msg 提示消息 + * @param mixed $data 返回数据 + * @param int $code 业务状态码(0=失败) + * @param array $header 可含 statusCode 指定 HTTP 状态(如 401、409) + */ + protected function error(string $msg = '', mixed $data = null, int $code = 0, array $header = []): Response + { + return $this->result($msg, $data, $code, $header); + } + + /** + * 返回 API 数据(BuildAdmin 格式:code, msg, time, data) + * 使用 response() 生成 JSON Response + */ + protected function result(string $msg, mixed $data = null, int $code = 0, array $header = []): Response + { + $body = [ + 'code' => $code, + 'msg' => $msg, + 'time' => time(), + 'data' => $data, + ]; + + $statusCode = $header['statusCode'] ?? 200; + unset($header['statusCode']); + + $headers = array_merge(['Content-Type' => 'application/json'], $header); + $options = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES; + if (defined('JSON_INVALID_UTF8_SUBSTITUTE')) { + $options |= JSON_INVALID_UTF8_SUBSTITUTE; + } + $jsonBody = json_encode($body, $options); + if ($jsonBody === false) { + $jsonBody = '{"code":0,"msg":"JSON encode error","time":' . time() . ',"data":[]}'; + } + + return response($jsonBody, $statusCode, $headers); + } +} diff --git a/app/view/index/view.html b/app/view/index/view.html new file mode 100644 index 0000000..67ebb26 --- /dev/null +++ b/app/view/index/view.html @@ -0,0 +1,14 @@ + + + + + + + + webman + + + +hello + + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..1affa36 --- /dev/null +++ b/composer.json @@ -0,0 +1,76 @@ +{ + "name": "workerman/webman", + "type": "project", + "keywords": [ + "high performance", + "http service" + ], + "homepage": "https://www.workerman.net", + "license": "MIT", + "description": "High performance HTTP Service Framework.", + "authors": [ + { + "name": "walkor", + "email": "walkor@workerman.net", + "homepage": "https://www.workerman.net", + "role": "Developer" + } + ], + "support": { + "email": "walkor@workerman.net", + "issues": "https://github.com/walkor/webman/issues", + "forum": "https://wenda.workerman.net/", + "wiki": "https://workerman.net/doc/webman", + "source": "https://github.com/walkor/webman" + }, + "require": { + "php": ">=8.1", + "vlucas/phpdotenv": "^5.6", + "workerman/webman-framework": "^2.1", + "monolog/monolog": "^2.0", + "webman/console": "^2.2", + "webman/database": "^2.1", + "webman/think-orm": "^2.1", + "illuminate/pagination": "^12.53", + "illuminate/events": "^12.53", + "symfony/var-dumper": "^7.4", + "webman/redis": "^2.1", + "webman/validation": "^2.2", + "robmorgan/phinx": "^0.15", + "nelexa/zip": "^4.0.0", + "voku/anti-xss": "^4.1", + "topthink/think-validate": "^3.0" + }, + "suggest": { + "ext-event": "For better performance. " + }, + "autoload": { + "psr-4": { + "": "./", + "app\\": "./app", + "App\\": "./app", + "app\\View\\Components\\": "./app/view/components", + "ba\\": "./extend/ba/", + "modules\\": "./modules/" + } + }, + "scripts": { + "post-package-install": [ + "support\\Plugin::install" + ], + "post-package-update": [ + "support\\Plugin::install" + ], + "pre-package-uninstall": [ + "support\\Plugin::uninstall" + ], + "post-create-project-cmd": [ + "support\\Setup::run" + ], + "setup-webman": [ + "support\\Setup::run" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..f26e358 --- /dev/null +++ b/config/app.php @@ -0,0 +1,26 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use support\Request; + +return [ + 'debug' => true, + 'error_reporting' => E_ALL, + 'default_timezone' => 'Asia/Shanghai', + 'request_class' => Request::class, + 'public_path' => base_path() . DIRECTORY_SEPARATOR . 'public', + 'runtime_path' => base_path(false) . DIRECTORY_SEPARATOR . 'runtime', + 'controller_suffix' => 'Controller', + 'controller_reuse' => false, +]; diff --git a/config/autoload.php b/config/autoload.php new file mode 100644 index 0000000..69a8135 --- /dev/null +++ b/config/autoload.php @@ -0,0 +1,21 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'files' => [ + base_path() . '/app/functions.php', + base_path() . '/support/Request.php', + base_path() . '/support/Response.php', + ] +]; diff --git a/config/bootstrap.php b/config/bootstrap.php new file mode 100644 index 0000000..e983488 --- /dev/null +++ b/config/bootstrap.php @@ -0,0 +1,20 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + support\bootstrap\Session::class, + Webman\ThinkOrm\ThinkOrm::class, + support\bootstrap\ValidateInit::class, + support\bootstrap\ModuleInit::class, +]; diff --git a/config/buildadmin.php b/config/buildadmin.php new file mode 100644 index 0000000..ccb970e --- /dev/null +++ b/config/buildadmin.php @@ -0,0 +1,88 @@ + '*', + // 是否开启会员登录验证码 + '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, + // 自定义字体路径(当项目字体不存在且系统回退失败时可指定,如: C:\Windows\Fonts\simhei.ttf) + 'font_path' => '', + ], + // 代理服务器IP(Request 类将尝试获取这些代理服务器发送过来的真实IP) + 'proxy_server_ip' => [], + // Token 配置 + 'token' => [ + // 默认驱动方式 + 'default' => 'mysql', + // 加密key + 'key' => '5u9HTYBPXId3i6K4S2Q08wWRVFxCENLU', + // 加密方式 + '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', +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..521002f --- /dev/null +++ b/config/cache.php @@ -0,0 +1,37 @@ + $env('cache.driver', 'file'), + + // 缓存连接方式配置 + 'stores' => [ + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => base_path() . DIRECTORY_SEPARATOR . 'runtime' . DIRECTORY_SEPARATOR . 'cache', + // 缓存前缀 + 'prefix' => '', + // 缓存有效期 0表示永久缓存 + 'expire' => 0, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + // 更多的缓存连接 + ], +]; diff --git a/config/container.php b/config/container.php new file mode 100644 index 0000000..106b7b4 --- /dev/null +++ b/config/container.php @@ -0,0 +1,15 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return new Webman\Container; \ No newline at end of file diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..f33ca66 --- /dev/null +++ b/config/database.php @@ -0,0 +1,38 @@ + 'mysql', + 'connections' => [ + 'mysql' => [ + 'driver' => 'mysql', + 'host' => $env('database.hostname', '127.0.0.1'), + 'port' => $env('database.hostport', '3306'), + 'database' => $env('database.database', 'dafuweng-buildadmin'), + 'username' => $env('database.username', 'dafuweng-buildadmin'), + 'password' => $env('database.password', '123456'), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_general_ci', + 'prefix' => '', + 'strict' => true, + 'engine' => null, + 'options' => [ + PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers. + ], + 'pool' => [ + 'max_connections' => 5, + 'min_connections' => 1, + 'wait_timeout' => 3, + 'idle_timeout' => 60, + 'heartbeat_interval' => 50, + ], + ], + ], +]; \ No newline at end of file diff --git a/config/dependence.php b/config/dependence.php new file mode 100644 index 0000000..8e964ed --- /dev/null +++ b/config/dependence.php @@ -0,0 +1,15 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return []; \ No newline at end of file diff --git a/config/events.php b/config/events.php new file mode 100644 index 0000000..7ae06fe --- /dev/null +++ b/config/events.php @@ -0,0 +1,11 @@ + [ + 'backendInit' => [ + \app\common\event\Security::class, // 数据回收、敏感数据记录 + ], + ], +]; diff --git a/config/exception.php b/config/exception.php new file mode 100644 index 0000000..f2aede3 --- /dev/null +++ b/config/exception.php @@ -0,0 +1,17 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + '' => support\exception\Handler::class, +]; \ No newline at end of file diff --git a/config/filesystem.php b/config/filesystem.php new file mode 100644 index 0000000..477981b --- /dev/null +++ b/config/filesystem.php @@ -0,0 +1,20 @@ + env('filesystem.driver', 'local'), + 'disks' => [ + 'local' => [ + 'type' => 'local', + 'root' => rtrim(runtime_path(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'storage', + ], + 'public' => [ + 'type' => 'local', + 'root' => rtrim(base_path(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'public', + 'url' => '/storage', + 'visibility' => 'public', + ], + ], +]; diff --git a/config/lang.php b/config/lang.php new file mode 100644 index 0000000..4a22961 --- /dev/null +++ b/config/lang.php @@ -0,0 +1,8 @@ + env('LANG_DEFAULT_LANG', 'zh-cn'), + 'allow_lang_list' => ['zh-cn', 'en'], +]; diff --git a/config/log.php b/config/log.php new file mode 100644 index 0000000..7f05de5 --- /dev/null +++ b/config/log.php @@ -0,0 +1,32 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'default' => [ + 'handlers' => [ + [ + 'class' => Monolog\Handler\RotatingFileHandler::class, + 'constructor' => [ + runtime_path() . '/logs/webman.log', + 7, //$maxFiles + Monolog\Logger::DEBUG, + ], + 'formatter' => [ + 'class' => Monolog\Formatter\LineFormatter::class, + 'constructor' => [null, 'Y-m-d H:i:s', true], + ], + ] + ], + ], +]; diff --git a/config/middleware.php b/config/middleware.php new file mode 100644 index 0000000..8e75768 --- /dev/null +++ b/config/middleware.php @@ -0,0 +1,26 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +/** + * 中间件配置 + * '' 为全局中间件,按顺序执行 + * 原 ThinkPHP api/admin 中间件迁移至此 + */ +return [ + '' => [ + \app\common\middleware\AllowCrossDomain::class, + \app\common\middleware\LoadLangPack::class, + \app\common\middleware\AdminLog::class, + ], +]; \ No newline at end of file diff --git a/config/plugin/webman/console/app.php b/config/plugin/webman/console/app.php new file mode 100644 index 0000000..d7bf968 --- /dev/null +++ b/config/plugin/webman/console/app.php @@ -0,0 +1,28 @@ + true, + + 'build_dir' => BASE_PATH . DIRECTORY_SEPARATOR . 'build', + + 'phar_filename' => 'webman.phar', + + 'phar_format' => Phar::PHAR, // Phar archive format: Phar::PHAR, Phar::TAR, Phar::ZIP + + 'phar_compression' => Phar::NONE, // Compression method for Phar archive: Phar::NONE, Phar::GZ, Phar::BZ2 + + 'bin_filename' => 'webman.bin', + + 'signature_algorithm'=> Phar::SHA256, //set the signature algorithm for a phar and apply it. The signature algorithm must be one of Phar::MD5, Phar::SHA1, Phar::SHA256, Phar::SHA512, or Phar::OPENSSL. + + 'private_key_file' => '', // The file path for certificate or OpenSSL private key file. + + 'exclude_pattern' => '#^(?!.*(composer.json|/.github/|/.idea/|/.git/|/.setting/|/runtime/|/vendor-bin/|/build/|/vendor/webman/admin/))(.*)$#', + + 'exclude_files' => [ + '.env', 'LICENSE', 'composer.json', 'composer.lock', 'start.php', 'webman.phar', 'webman.bin' + ], + + 'custom_ini' => ' +memory_limit = 256M + ', +]; diff --git a/config/plugin/webman/validation/app.php b/config/plugin/webman/validation/app.php new file mode 100644 index 0000000..64c2382 --- /dev/null +++ b/config/plugin/webman/validation/app.php @@ -0,0 +1,8 @@ + true, + 'exception' => ValidationException::class, +]; \ No newline at end of file diff --git a/config/plugin/webman/validation/command.php b/config/plugin/webman/validation/command.php new file mode 100644 index 0000000..643c36f --- /dev/null +++ b/config/plugin/webman/validation/command.php @@ -0,0 +1,7 @@ + [ + Middleware::class, + ], +]; \ No newline at end of file diff --git a/config/process.php b/config/process.php new file mode 100644 index 0000000..892dc82 --- /dev/null +++ b/config/process.php @@ -0,0 +1,62 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use support\Log; +use support\Request; +use app\process\Http; + +global $argv; + +return [ + 'webman' => [ + 'handler' => Http::class, + 'listen' => 'http://0.0.0.0:8787', + 'count' => cpu_count() * 4, + 'user' => '', + 'group' => '', + 'reusePort' => false, + 'eventLoop' => '', + 'context' => [], + 'constructor' => [ + 'requestClass' => Request::class, + 'logger' => Log::channel('default'), + 'appPath' => app_path(), + 'publicPath' => public_path() + ] + ], + // File update detection and automatic reload + 'monitor' => [ + 'handler' => app\process\Monitor::class, + 'reloadable' => false, + 'constructor' => [ + // Monitor these directories + 'monitorDir' => array_merge([ + app_path(), + config_path(), + base_path() . '/process', + base_path() . '/support', + base_path() . '/resource', + base_path() . '/.env', + ], glob(base_path() . '/plugin/*/app'), glob(base_path() . '/plugin/*/config'), glob(base_path() . '/plugin/*/api')), + // Files with these suffixes will be monitored + 'monitorExtensions' => [ + 'php', 'html', 'htm', 'env' + ], + 'options' => [ + 'enable_file_monitor' => !in_array('-d', $argv) && DIRECTORY_SEPARATOR === '/', + 'enable_memory_monitor' => DIRECTORY_SEPARATOR === '/', + ] + ] + ] +]; diff --git a/config/redis.php b/config/redis.php new file mode 100644 index 0000000..84896c3 --- /dev/null +++ b/config/redis.php @@ -0,0 +1,29 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'default' => [ + 'password' => '', + 'host' => '127.0.0.1', + 'port' => 6379, + 'database' => 0, + 'pool' => [ + 'max_connections' => 5, + 'min_connections' => 1, + 'wait_timeout' => 3, + 'idle_timeout' => 60, + 'heartbeat_interval' => 50, + ], + ] +]; diff --git a/config/route.php b/config/route.php new file mode 100644 index 0000000..ea1a5f3 --- /dev/null +++ b/config/route.php @@ -0,0 +1,272 @@ + '/install/']); + } + if (is_file(public_path('index.html'))) { + return new Response(302, ['Location' => '/index.html']); + } + return new Response(404, [], 'Not Found'); +}); +Route::get('/index.html', function () use ($installLockFile, $installCompleteMark, $installPageFile) { + $needRedirect = is_file($installPageFile) + && (!is_file($installLockFile) || @file_get_contents($installLockFile) !== $installCompleteMark); + if ($needRedirect) { + return new Response(302, ['Location' => '/install/']); + } + $file = public_path('index.html'); + return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Not Found'); +}); + +// ==================== 安装向导(静态页) ==================== +// /install、/install/、/install/index 均返回 public/install/index.html +Route::get('/install', function () { + $file = public_path('install/index.html'); + return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found'); +}); +Route::get('/install/', function () { + $file = public_path('install/index.html'); + return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found'); +}); +Route::get('/install/index', function () { + $file = public_path('install/index.html'); + return is_file($file) ? (new Response())->file($file) : new Response(404, [], 'Install page not found'); +}); + +// ==================== API 路由 ==================== + +// api/index +Route::get('/api/index/index', [\app\api\controller\Index::class, 'index']); + +// api/user(GET 获取配置,POST 登录/注册) +Route::add(['GET', 'POST'], '/api/user/checkIn', [\app\api\controller\User::class, 'checkIn']); +Route::post('/api/user/logout', [\app\api\controller\User::class, 'logout']); + +// api/install(安装流程多为 POST) +Route::add(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'], '/api/install/terminal', [\app\api\controller\Install::class, 'terminal']); +Route::post('/api/install/changePackageManager', [\app\api\controller\Install::class, 'changePackageManager']); +Route::get('/api/install/envBaseCheck', [\app\api\controller\Install::class, 'envBaseCheck']); +Route::add(['GET', 'POST'], '/api/install/envNpmCheck', [\app\api\controller\Install::class, 'envNpmCheck']); +Route::post('/api/install/testDatabase', [\app\api\controller\Install::class, 'testDatabase']); +Route::add(['GET', 'POST'], '/api/install/baseConfig', [\app\api\controller\Install::class, 'baseConfig']); +Route::post('/api/install/commandExecComplete', [\app\api\controller\Install::class, 'commandExecComplete']); +Route::post('/api/install/manualInstall', [\app\api\controller\Install::class, 'manualInstall']); +Route::post('/api/install/mvDist', [\app\api\controller\Install::class, 'mvDist']); + +// api/common +Route::get('/api/common/captcha', [\app\api\controller\Common::class, 'captcha']); +Route::get('/api/common/clickCaptcha', [\app\api\controller\Common::class, 'clickCaptcha']); +Route::post('/api/common/checkClickCaptcha', [\app\api\controller\Common::class, 'checkClickCaptcha']); +Route::post('/api/common/refreshToken', [\app\api\controller\Common::class, 'refreshToken']); + +// api/ajax +Route::post('/api/ajax/upload', [\app\api\controller\Ajax::class, 'upload']); +Route::get('/api/ajax/area', [\app\api\controller\Ajax::class, 'area']); +Route::get('/api/ajax/buildSuffixSvg', [\app\api\controller\Ajax::class, 'buildSuffixSvg']); + +// api/account +Route::get('/api/account/overview', [\app\api\controller\Account::class, 'overview']); +Route::add(['GET', 'POST'], '/api/account/profile', [\app\api\controller\Account::class, 'profile']); +Route::get('/api/account/verification', [\app\api\controller\Account::class, 'verification']); +Route::post('/api/account/changeBind', [\app\api\controller\Account::class, 'changeBind']); +Route::add(['GET', 'POST'], '/api/account/changePassword', [\app\api\controller\Account::class, 'changePassword']); +Route::get('/api/account/integral', [\app\api\controller\Account::class, 'integral']); +Route::get('/api/account/balance', [\app\api\controller\Account::class, 'balance']); +Route::post('/api/account/retrievePassword', [\app\api\controller\Account::class, 'retrievePassword']); + +// api/ems +Route::post('/api/ems/send', [\app\api\controller\Ems::class, 'send']); + +// ==================== Admin 路由 ==================== +// Admin 多为 JSON API,前端可能用 GET 传参查列表、POST 提交表单,使用 any 确保兼容 + +// admin/index(小写) +Route::get('/admin/index/index', [\app\admin\controller\Index::class, 'index']); +Route::get('/admin/index/login', [\app\admin\controller\Index::class, 'login']); +Route::post('/admin/index/login', [\app\admin\controller\Index::class, 'login']); +Route::post('/admin/index/logout', [\app\admin\controller\Index::class, 'logout']); + +// 兼容前端请求 /admin/Index/*(首字母大写) +Route::get('/admin/Index/index', [\app\admin\controller\Index::class, 'index']); +Route::get('/admin/Index/login', [\app\admin\controller\Index::class, 'login']); +Route::post('/admin/Index/login', [\app\admin\controller\Index::class, 'login']); +Route::post('/admin/Index/logout', [\app\admin\controller\Index::class, 'logout']); + +// admin/dashboard +Route::get('/admin/dashboard/index', [\app\admin\controller\Dashboard::class, 'index']); +// 兼容前端请求 /admin/Dashboard/* +Route::get('/admin/Dashboard/index', [\app\admin\controller\Dashboard::class, 'index']); + +// admin/module +Route::get('/admin/module/index', [\app\admin\controller\Module::class, 'index']); +Route::get('/admin/module/state', [\app\admin\controller\Module::class, 'state']); +Route::post('/admin/module/install', [\app\admin\controller\Module::class, 'install']); +Route::post('/admin/module/dependentInstallComplete', [\app\admin\controller\Module::class, 'dependentInstallComplete']); +Route::post('/admin/module/changeState', [\app\admin\controller\Module::class, 'changeState']); +Route::post('/admin/module/uninstall', [\app\admin\controller\Module::class, 'uninstall']); +Route::post('/admin/module/upload', [\app\admin\controller\Module::class, 'upload']); + +// admin/ajax +Route::post('/admin/ajax/upload', [\app\admin\controller\Ajax::class, 'upload']); +Route::get('/admin/ajax/area', [\app\admin\controller\Ajax::class, 'area']); +Route::get('/admin/ajax/buildSuffixSvg', [\app\admin\controller\Ajax::class, 'buildSuffixSvg']); +Route::get('/admin/ajax/getDatabaseConnectionList', [\app\admin\controller\Ajax::class, 'getDatabaseConnectionList']); +Route::get('/admin/ajax/getTablePk', [\app\admin\controller\Ajax::class, 'getTablePk']); +Route::get('/admin/ajax/getTableList', [\app\admin\controller\Ajax::class, 'getTableList']); +Route::get('/admin/ajax/getTableFieldList', [\app\admin\controller\Ajax::class, 'getTableFieldList']); +Route::post('/admin/ajax/changeTerminalConfig', [\app\admin\controller\Ajax::class, 'changeTerminalConfig']); +Route::post('/admin/ajax/clearCache', [\app\admin\controller\Ajax::class, 'clearCache']); +Route::add(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'], '/admin/ajax/terminal', [\app\admin\controller\Ajax::class, 'terminal']); + +// admin/auth/admin +Route::get('/admin/auth/admin/index', [\app\admin\controller\auth\Admin::class, 'index']); +Route::post('/admin/auth/admin/add', [\app\admin\controller\auth\Admin::class, 'add']); +Route::post('/admin/auth/admin/edit', [\app\admin\controller\auth\Admin::class, 'edit']); +Route::post('/admin/auth/admin/del', [\app\admin\controller\auth\Admin::class, 'del']); + +// admin/auth/group +Route::get('/admin/auth/group/index', [\app\admin\controller\auth\Group::class, 'index']); +Route::post('/admin/auth/group/add', [\app\admin\controller\auth\Group::class, 'add']); +Route::post('/admin/auth/group/edit', [\app\admin\controller\auth\Group::class, 'edit']); +Route::post('/admin/auth/group/del', [\app\admin\controller\auth\Group::class, 'del']); +Route::get('/admin/auth/group/select', [\app\admin\controller\auth\Group::class, 'select']); + +// admin/auth/rule +Route::get('/admin/auth/rule/index', [\app\admin\controller\auth\Rule::class, 'index']); +Route::post('/admin/auth/rule/add', [\app\admin\controller\auth\Rule::class, 'add']); +Route::post('/admin/auth/rule/edit', [\app\admin\controller\auth\Rule::class, 'edit']); +Route::post('/admin/auth/rule/del', [\app\admin\controller\auth\Rule::class, 'del']); +Route::get('/admin/auth/rule/select', [\app\admin\controller\auth\Rule::class, 'select']); + +// admin/auth/adminLog +Route::get('/admin/auth/adminLog/index', [\app\admin\controller\auth\AdminLog::class, 'index']); + +// admin/user/user +Route::get('/admin/user/user/index', [\app\admin\controller\user\User::class, 'index']); +Route::post('/admin/user/user/add', [\app\admin\controller\user\User::class, 'add']); +Route::post('/admin/user/user/edit', [\app\admin\controller\user\User::class, 'edit']); +Route::get('/admin/user/user/select', [\app\admin\controller\user\User::class, 'select']); + +// admin/user/group +Route::post('/admin/user/group/add', [\app\admin\controller\user\Group::class, 'add']); +Route::post('/admin/user/group/edit', [\app\admin\controller\user\Group::class, 'edit']); + +// admin/user/rule +Route::get('/admin/user/rule/index', [\app\admin\controller\user\Rule::class, 'index']); +Route::post('/admin/user/rule/add', [\app\admin\controller\user\Rule::class, 'add']); +Route::post('/admin/user/rule/edit', [\app\admin\controller\user\Rule::class, 'edit']); +Route::post('/admin/user/rule/del', [\app\admin\controller\user\Rule::class, 'del']); +Route::get('/admin/user/rule/select', [\app\admin\controller\user\Rule::class, 'select']); + +// admin/user/scoreLog +Route::post('/admin/user/scoreLog/add', [\app\admin\controller\user\ScoreLog::class, 'add']); + +// admin/user/moneyLog +Route::post('/admin/user/moneyLog/add', [\app\admin\controller\user\MoneyLog::class, 'add']); + +// admin/routine/config +Route::get('/admin/routine/config/index', [\app\admin\controller\routine\Config::class, 'index']); +Route::post('/admin/routine/config/edit', [\app\admin\controller\routine\Config::class, 'edit']); +Route::post('/admin/routine/config/add', [\app\admin\controller\routine\Config::class, 'add']); +Route::post('/admin/routine/config/sendTestMail', [\app\admin\controller\routine\Config::class, 'sendTestMail']); + +// admin/routine/adminInfo +Route::get('/admin/routine/adminInfo/index', [\app\admin\controller\routine\AdminInfo::class, 'index']); +Route::post('/admin/routine/adminInfo/edit', [\app\admin\controller\routine\AdminInfo::class, 'edit']); + +// admin/routine/attachment +Route::post('/admin/routine/attachment/del', [\app\admin\controller\routine\Attachment::class, 'del']); + +// admin/crud/crud +Route::post('/admin/crud/crud/generate', [\app\admin\controller\crud\Crud::class, 'generate']); +Route::post('/admin/crud/crud/logStart', [\app\admin\controller\crud\Crud::class, 'logStart']); +Route::post('/admin/crud/crud/delete', [\app\admin\controller\crud\Crud::class, 'delete']); +Route::get('/admin/crud/crud/getFileData', [\app\admin\controller\crud\Crud::class, 'getFileData']); +// 兼容 ThinkPHP 风格 URL:/admin/crud.Crud/getFileData +Route::get('/admin/crud.Crud/getFileData', [\app\admin\controller\crud\Crud::class, 'getFileData']); +Route::get('/admin/crud/crud/checkCrudLog', [\app\admin\controller\crud\Crud::class, 'checkCrudLog']); +Route::post('/admin/crud/crud/parseFieldData', [\app\admin\controller\crud\Crud::class, 'parseFieldData']); +Route::post('/admin/crud/crud/generateCheck', [\app\admin\controller\crud\Crud::class, 'generateCheck']); +Route::post('/admin/crud/crud/uploadCompleted', [\app\admin\controller\crud\Crud::class, 'uploadCompleted']); + +// admin/crud/log +Route::get('/admin/crud/log/index', [\app\admin\controller\crud\Log::class, 'index']); + +// admin/security/sensitiveData +Route::get('/admin/security/sensitiveData/index', [\app\admin\controller\security\SensitiveData::class, 'index']); +Route::add(['GET', 'POST'], '/admin/security/sensitiveData/add', [\app\admin\controller\security\SensitiveData::class, 'add']); +Route::add(['GET', 'POST'], '/admin/security/sensitiveData/edit', [\app\admin\controller\security\SensitiveData::class, 'edit']); +Route::post('/admin/security/sensitiveData/del', [\app\admin\controller\security\SensitiveData::class, 'del']); + +// admin/security/sensitiveDataLog +Route::get('/admin/security/sensitiveDataLog/index', [\app\admin\controller\security\SensitiveDataLog::class, 'index']); +Route::get('/admin/security/sensitiveDataLog/info', [\app\admin\controller\security\SensitiveDataLog::class, 'info']); +Route::post('/admin/security/sensitiveDataLog/rollback', [\app\admin\controller\security\SensitiveDataLog::class, 'rollback']); + +// admin/security/dataRecycle +Route::get('/admin/security/dataRecycle/index', [\app\admin\controller\security\DataRecycle::class, 'index']); +Route::add(['GET', 'POST'], '/admin/security/dataRecycle/add', [\app\admin\controller\security\DataRecycle::class, 'add']); +Route::add(['GET', 'POST'], '/admin/security/dataRecycle/edit', [\app\admin\controller\security\DataRecycle::class, 'edit']); +Route::post('/admin/security/dataRecycle/del', [\app\admin\controller\security\DataRecycle::class, 'del']); + +// admin/security/dataRecycleLog +Route::get('/admin/security/dataRecycleLog/index', [\app\admin\controller\security\DataRecycleLog::class, 'index']); +Route::post('/admin/security/dataRecycleLog/restore', [\app\admin\controller\security\DataRecycleLog::class, 'restore']); +Route::get('/admin/security/dataRecycleLog/info', [\app\admin\controller\security\DataRecycleLog::class, 'info']); + +// ==================== 兼容 ThinkPHP 风格 URL(module.Controller/action) ==================== +// 前端使用 /admin/user.Rule/index 格式,需转换为控制器调用 +Route::add( + ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'], + '/admin/{controllerPart:[a-zA-Z]+\\.[a-zA-Z0-9]+}/{action}', + function (\Webman\Http\Request $request, string $controllerPart, string $action) { + $pos = strpos($controllerPart, '.'); + if ($pos === false) { + return new Response(404, ['Content-Type' => 'application/json'], json_encode(['code' => 404, 'msg' => '404 Not Found', 'data' => []], JSON_UNESCAPED_UNICODE)); + } + $module = substr($controllerPart, 0, $pos); + $controller = substr($controllerPart, $pos + 1); + $class = '\\app\\admin\\controller\\' . strtolower($module) . '\\' . $controller; + if (!class_exists($class)) { + return new Response(404, ['Content-Type' => 'application/json'], json_encode(['code' => 404, 'msg' => '404 Not Found', 'data' => []], JSON_UNESCAPED_UNICODE)); + } + if (!method_exists($class, $action)) { + return new Response(404, ['Content-Type' => 'application/json'], json_encode(['code' => 404, 'msg' => '404 Not Found', 'data' => []], JSON_UNESCAPED_UNICODE)); + } + // 设置 controller 供 get_controller_path、权限校验等使用 + $request->controller = $class; + try { + $instance = new $class(); + return $instance->$action($request); + } catch (\Throwable $e) { + return new Response(500, ['Content-Type' => 'application/json'], json_encode([ + 'code' => 0, + 'msg' => $e->getMessage(), + 'time' => time(), + 'data' => null, + ], JSON_UNESCAPED_UNICODE)); + } + } +); + +// ==================== CORS 预检(OPTIONS) ==================== +// 放在最后注册;显式加上前端会请求的路径,再加固通配 +Route::add('OPTIONS', '/api/index/index', [\app\common\middleware\AllowCrossDomain::class, 'optionsResponse']); +Route::add('OPTIONS', '/api/{path:.+}', [\app\common\middleware\AllowCrossDomain::class, 'optionsResponse']); +Route::add('OPTIONS', '/admin/{path:.+}', [\app\common\middleware\AllowCrossDomain::class, 'optionsResponse']); \ No newline at end of file diff --git a/config/server.php b/config/server.php new file mode 100644 index 0000000..054d01f --- /dev/null +++ b/config/server.php @@ -0,0 +1,23 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +return [ + 'event_loop' => '', + 'stop_timeout' => 2, + 'pid_file' => runtime_path() . '/webman.pid', + 'status_file' => runtime_path() . '/webman.status', + 'stdout_file' => runtime_path() . '/logs/stdout.log', + 'log_file' => runtime_path() . '/logs/workerman.log', + 'max_package_size' => 10 * 1024 * 1024 +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..043f8c4 --- /dev/null +++ b/config/session.php @@ -0,0 +1,65 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use Webman\Session\FileSessionHandler; +use Webman\Session\RedisSessionHandler; +use Webman\Session\RedisClusterSessionHandler; + +return [ + + 'type' => 'file', // or redis or redis_cluster + + 'handler' => FileSessionHandler::class, + + 'config' => [ + 'file' => [ + 'save_path' => runtime_path() . '/sessions', + ], + 'redis' => [ + 'host' => '127.0.0.1', + 'port' => 6379, + 'auth' => '', + 'timeout' => 2, + 'database' => '', + 'prefix' => 'redis_session_', + ], + 'redis_cluster' => [ + 'host' => ['127.0.0.1:7000', '127.0.0.1:7001', '127.0.0.1:7001'], + 'timeout' => 2, + 'auth' => '', + 'prefix' => 'redis_session_', + ] + ], + + 'session_name' => 'PHPSID', + + 'auto_update_timestamp' => false, + + 'lifetime' => 7*24*60*60, + + 'cookie_lifetime' => 365*24*60*60, + + 'cookie_path' => '/', + + 'domain' => '', + + 'http_only' => true, + + 'secure' => false, + + 'same_site' => '', + + 'gc_probability' => [1, 1000], + +]; diff --git a/config/static.php b/config/static.php new file mode 100644 index 0000000..6313679 --- /dev/null +++ b/config/static.php @@ -0,0 +1,23 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +/** + * Static file settings + */ +return [ + 'enable' => true, + 'middleware' => [ // Static file Middleware + //app\middleware\StaticFile::class, + ], +]; \ No newline at end of file diff --git a/config/terminal.php b/config/terminal.php new file mode 100644 index 0000000..feba899 --- /dev/null +++ b/config/terminal.php @@ -0,0 +1,83 @@ + 'pnpm', + 'commands' => [ + 'migrate' => [ + 'run' => [ + 'cwd' => '', + 'command' => 'php vendor/bin/phinx migrate', + 'notes' => 'Start the database migration' + ], + 'rollback' => ['cwd' => '', 'command' => 'php vendor/bin/phinx rollback'], + 'breakpoint' => ['cwd' => '', 'command' => 'php vendor/bin/phinx 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-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'], + ], + '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-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'], + ], + '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' + ], + '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/thinkorm.php b/config/thinkorm.php new file mode 100644 index 0000000..bc6ef1b --- /dev/null +++ b/config/thinkorm.php @@ -0,0 +1,95 @@ + $env('database.driver', 'mysql'), + + // 自定义时间查询规则 + 'time_query_rule' => [], + + // 自动写入时间戳字段 + '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.php / .env 一致) + 'database' => $env('database.database', 'dafuweng-buildadmin-webman'), + // 用户名(与 .env DATABASE_USERNAME 一致,默认勿用 root 以免与本机 MySQL 不符) + 'username' => $env('database.username', 'dafuweng-buildadmin-webman'), + // 密码(与 .env DATABASE_PASSWORD 一致) + 'password' => $env('database.password', '123456'), + // 端口 + 'hostport' => $env('database.hostport', '3306'), + // 数据库连接参数(MYSQL_ATTR_USE_BUFFERED_QUERY 避免 "Cannot execute queries while other unbuffered queries are active") + 'params' => [ + \PDO::ATTR_TIMEOUT => 3, + \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, + ], + // 数据库编码默认采用 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, + + // 连接池配置(Webman 常驻内存模式必需) + 'pool' => [ + 'max_connections' => 5, + 'min_connections' => 1, + 'wait_timeout' => 3, + 'idle_timeout' => 60, + 'heartbeat_interval' => 50, + ], + ], + ], + + // 自定义分页类 + 'paginator' => '', + + // 迁移表名(TableManager/Phinx 使用) + 'migration_table' => 'migrations', +]; diff --git a/config/translation.php b/config/translation.php new file mode 100644 index 0000000..e5fa4b8 --- /dev/null +++ b/config/translation.php @@ -0,0 +1,29 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +/** + * Multilingual configuration + */ +return [ + // Default language + 'locale' => 'zh_CN', + // Fallback language + 'fallback_locale' => ['zh_CN', 'en'], + // Folder where language files are stored(含 BuildAdmin app 语言包) + 'path' => [ + base_path() . '/resource/translations', + base_path() . '/app/api/lang', + base_path() . '/app/admin/lang', + ], +]; \ No newline at end of file diff --git a/config/upload.php b/config/upload.php new file mode 100644 index 0000000..1998175 --- /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' => [], +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..e3a7b85 --- /dev/null +++ b/config/view.php @@ -0,0 +1,22 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use support\view\Raw; +use support\view\Twig; +use support\view\Blade; +use support\view\ThinkPHP; + +return [ + 'handler' => Raw::class +]; diff --git a/database/migrations/20230620180908_install.php b/database/migrations/20230620180908_install.php new file mode 100644 index 0000000..0441455 --- /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..d46d809 --- /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..4415a9d --- /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..017a063 --- /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..3cdb117 --- /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..08a8777 --- /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..47e4a39 --- /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/20250318120000_mall_player.php b/database/migrations/20250318120000_mall_player.php new file mode 100644 index 0000000..522f7aa --- /dev/null +++ b/database/migrations/20250318120000_mall_player.php @@ -0,0 +1,30 @@ +hasTable('mall_player')) { + $table = $this->table('mall_player', [ + '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' => 50, 'default' => '', 'comment' => '用户名', 'null' => false]) + ->addColumn('password', 'string', ['limit' => 255, 'default' => '', 'comment' => '密码', 'null' => false]) + ->addColumn('score', 'integer', ['signed' => false, 'default' => 0, 'comment' => '积分', 'null' => false]) + ->addColumn('create_time', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '创建时间']) + ->addColumn('update_time', 'biginteger', ['signed' => false, 'null' => true, 'default' => null, 'comment' => '修改时间']) + ->addIndex(['username']) + ->create(); + } + } +} diff --git a/database/migrations/20250412134127_version222.php b/database/migrations/20250412134127_version222.php new file mode 100644 index 0000000..ed76ae3 --- /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/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..352871e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +version: "3" +services: + webman: + build: . + container_name: docker-webman + restart: unless-stopped + volumes: + - "./:/app" + ports: + - "8787:8787" + command: ["php", "start.php", "start" ] \ No newline at end of file diff --git a/docs/CRUD生成逻辑说明.md b/docs/CRUD生成逻辑说明.md new file mode 100644 index 0000000..9566826 --- /dev/null +++ b/docs/CRUD生成逻辑说明.md @@ -0,0 +1,165 @@ +# CRUD 代码生成逻辑说明 + +参考 ThinkPHP8 与 Webman 实现,说明各配置项含义及生成流程。 + +--- + +## 一、配置项说明 + +### 1. 生成代码的相对路径(generateRelativePath) + +**作用**:作为路径前缀,用于快速组合生成位置。支持多级目录,如 `crud/test` 会生成到 `crud/test` 子目录。 + +**逻辑**: +- 输入值会替换 `/` 为 `\` 后作为 `table` 参与路径计算 +- 与表名等价:`test` 和 `crud/test` 都会触发 `getFileData` 获取默认路径 +- 为空时,需先填写**数据表名**,由表名驱动路径计算 + +**示例**: +- `test` → 控制器 `app/admin/controller/Test.php`,视图 `web/src/views/backend/test/` +- `crud/test` → 控制器 `app/admin/controller/crud/Test.php`,视图 `web/src/views/backend/crud/test/` + +--- + +### 2. 生成的控制器位置(controllerFile) + +**作用**:控制器文件的相对路径,如 `app/admin/controller/crud/Test.php`。 + +**逻辑**: +- 由 `Helper::parseNameData('admin', $tableName, 'controller', $table['controllerFile'])` 计算 +- 为空时:按表名解析,如 `test` → `app/admin/controller/Test.php` +- 有值时:按自定义路径解析,会去掉 `app/admin/controller` 前缀后按剩余部分生成 + +**Webman 适配**:与 ThinkPHP 相同,目录为 `app/admin/controller/`。 + +--- + +### 3. 生成的数据模型位置(modelFile) + +**作用**:模型文件的相对路径,如 `app/admin/model/crud/Test.php` 或 `app/common/model/Test.php`。 + +**逻辑**: +- 由 `Helper::parseNameData($app, $tableName, 'model', $table['modelFile'])` 计算 +- `$app` 由「公共模型」决定:勾选为 `common`,否则为 `admin` +- 为空时按表名解析 + +**Webman 适配**:与 ThinkPHP 相同,目录为 `app/admin/model/` 或 `app/common/model/`。 + +--- + +### 4. 生成的验证器位置(validateFile) + +**作用**:验证器文件的相对路径,如 `app/admin/validate/crud/Test.php`。 + +**逻辑**: +- 由 `Helper::parseNameData($app, $tableName, 'validate', $table['validateFile'])` 计算 +- 与模型使用相同的 `$app`(公共模型或 admin) + +**Webman 适配**:与 ThinkPHP 相同,目录为 `app/admin/validate/` 或 `app/common/validate/`。 + +--- + +### 5. WEB 端视图目录(webViewsDir) + +**作用**:前端 Vue 视图目录,如 `web/src/views/backend/test`。 + +**逻辑**: +- 由 `Helper::parseWebDirNameData($tableName, 'views', $table['webViewsDir'])` 计算 +- 生成 `index.vue`、`popupForm.vue` 及对应语言包 +- 为空时按表名解析,如 `test` → `web/src/views/backend/test` + +**Webman 适配**:与 ThinkPHP 相同,目录为 `web/src/views/backend/`。 + +--- + +### 6. 数据库连接配置标识(databaseConnection) + +**作用**:选择使用的数据库连接,对应 `config/thinkorm.php` 中 `connections` 的 key。 + +**逻辑**: +- ThinkPHP:`config('database.connections')` +- Webman:`config('thinkorm.connections')`,Ajax 的 `getDatabaseConnectionList` 已适配 +- 留空使用默认连接:`config('thinkorm.default', 'mysql')` + +**Webman 适配**:已从 `database.php` 迁移到 `thinkorm.php`,无需额外修改。 + +--- + +## 二、自动填充流程 + +当**数据表名**或**生成代码的相对路径**变化时: + +1. 前端调用 `getFileData(table, commonModel)` +2. 后端 `Crud::getFileData` 根据表名和是否公共模型计算默认路径 +3. 返回并填充: + - `modelFile` + - `controllerFile` + - `validateFile` + - `webViewsDir` + +**若这些字段为空**,可能原因: +- **从零新建**:需先输入数据表名(如 `test`),输入后会自动调用 `getFileData` 填充(输入过程中 400ms 防抖触发,无需失焦) +- 表名格式需符合 `^[a-z_][a-z0-9_]*$`(小写字母、数字、下划线) +- 「高级配置」默认展开,可直接看到控制器/模型/验证器/视图路径 +- `getFileData` 接口异常(可检查网络或后端日志) +- `getFileData` 已加入 `noNeedLogin`,无需登录即可获取路径(便于设计页加载) + +--- + +## 三、generate 生成流程 + +``` +1. 接收 table、fields 等参数 +2. 表设计:handleTableDesign(创建/更新表结构) +3. 路径解析: + - modelFile = parseNameData(admin|common, tableName, 'model', table.modelFile) + - validateFile = parseNameData(...) + - controllerFile = parseNameData('admin', tableName, 'controller', table.controllerFile) + - webViewsDir = parseWebDirNameData(tableName, 'views', table.webViewsDir) +4. 遍历字段,生成: + - 模型(Model) + - 控制器(Controller) + - 验证器(Validate) + - index.vue、popupForm.vue + - 语言包(zh-cn、en) +5. 创建菜单(AdminRule) +``` + +--- + +## 四、Webman 与 ThinkPHP 差异 + +| 项目 | ThinkPHP | Webman | +|--------------|------------------------|----------------------------------| +| 数据库配置 | `config/database.php` | `config/thinkorm.php` | +| 默认连接 | `config('database.default')` | `config('thinkorm.default')` | +| 根路径 | `root_path()` | `root_path()`(同,指向 dafuweng-webman 项目根) | +| 控制器初始化 | `initialize()` 自动调用 | 在 `initializeBackend` 中调用 `$this->initialize()` | +| XSS 过滤 | `$request->filter('clean_xss')` | `$inputFilter = 'clean_xss'`,由 Backend trait 在 add/edit 时应用 | + +--- + +## 五、路径解析规则(Helper) + +### parseNameData($app, $table, $type, $value) + +- `$value` 为空:按 `$table` 解析,下划线 `_` 拆分为目录,末段大驼峰为类名 +- `$value` 有值:按自定义路径解析,会去掉 `app/$app/$type` 前缀 +- 预设:`admin`→`auth/admin`,`admin_rule`→`auth/rule` 等 + +**示例(表名 `xxx_yyy_zzz`,均相对于 dafuweng-webman 项目根):** + +| 配置项 | 默认值 | 公共模型时 | +|------------------|------------------------------------------|----------------------------------------| +| 生成代码的相对位置 | `xxx_yyy_zzz` | - | +| 控制器 | `app/admin/controller/xxx/yyy/Zzz.php` | - | +| 模型 | `app/admin/model/xxx/yyy/Zzz.php` | `app/common/model/xxx/yyy/Zzz.php` | +| 验证器 | `app/admin/validate/xxx/yyy/Zzz.php` | `app/common/validate/xxx/yyy/Zzz.php` | +| WEB端视图目录 | `web/src/views/backend/xxx/yyy/zzz` | - | + +**规则:** 表名 `xxx_yyy_zzz` → 前段 `xxx`、`yyy` 为子目录(小写),末段 `zzz` 转为 `Zzz.php`(大驼峰);视图目录保持全小写。 + +### parseWebDirNameData($table, $type, $value) + +- `$type='views'`:生成 `web/src/views/backend/{path}/{name}`,如 `xxx_yyy_zzz` → `web/src/views/backend/xxx/yyy/zzz` +- `$type='lang'`:生成 `web/src/lang/backend/{lang}/{path}/{name}` diff --git a/docs/nginx.conf.example b/docs/nginx.conf.example new file mode 100644 index 0000000..47833c2 --- /dev/null +++ b/docs/nginx.conf.example @@ -0,0 +1,40 @@ +# BuildAdmin Webman - Nginx 反向代理示例 +# 将 server_name 和 root 改为实际值后,放入 nginx 的 conf.d 或 sites-available + +upstream webman { + server 127.0.0.1:8787; + keepalive 10240; +} + +server { + server_name 你的域名; + listen 80; + access_log off; + root /path/to/dafuweng-webman/public; + + location / { + try_files $uri $uri/ @proxy; + } + + location @proxy { + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://webman; + } + + location ~ \.php$ { + return 404; + } + + location ~ ^/\.well-known/ { + allow all; + } + + location ~ /\. { + return 404; + } +} diff --git a/extend/ba/Auth.php b/extend/ba/Auth.php new file mode 100644 index 0000000..6fdd077 --- /dev/null +++ b/extend/ba/Auth.php @@ -0,0 +1,178 @@ + 'admin_group', + 'auth_group_access' => 'admin_group_access', + 'auth_rule' => 'admin_rule', + ]; + + protected array $children = []; + + public function __construct(array $config = []) + { + $this->config = array_merge($this->config, $config); + } + + public function __get($name): mixed + { + return $this->config[$name] ?? null; + } + + 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]); + } + + 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; + } + + 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); + $name = str_contains($name, ',') ? explode(',', $name) : [$name]; + } + $list = []; + $requestParams = []; + if ($mode === 'url' && function_exists('request')) { + $req = request(); + $requestParams = $req ? array_merge($req->get(), $req->post()) : []; + $requestParams = json_decode(strtolower(json_encode($requestParams, JSON_UNESCAPED_UNICODE)), true) ?? []; + } + + foreach ($ruleList as $rule) { + $query = preg_replace('/^.+\?/U', '', $rule); + if ($mode === 'url' && $query !== $rule) { + parse_str($query, $param); + $intersect = array_intersect_assoc($requestParams, $param); + $rule = preg_replace('/\?.*$/U', '', $rule); + if (in_array($rule, $name) && $intersect == $param) { + $list[] = $rule; + } + } elseif (in_array($rule, $name)) { + $list[] = $rule; + } + } + if ($relation === 'or' && !empty($list)) { + return true; + } + $diff = array_diff($name, $list); + if ($relation === 'and' && empty($diff)) { + return true; + } + + return false; + } + + 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); + } + + public function getOriginAuthRules(int $uid): array + { + $ids = $this->getRuleIds($uid); + if (empty($ids)) { + return []; + } + + $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; + } + + public function getRuleIds(int $uid): array + { + $groups = $this->getGroups($uid); + $ids = []; + foreach ($groups as $g) { + $ids = array_merge($ids, explode(',', trim($g['rules'] ?? '', ','))); + } + return array_unique($ids); + } + + 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; + } +} diff --git a/extend/ba/Captcha.php b/extend/ba/Captcha.php new file mode 100644 index 0000000..ff69a17 --- /dev/null +++ b/extend/ba/Captcha.php @@ -0,0 +1,313 @@ + 'BuildAdmin', + 'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY', + 'expire' => 600, + 'useZh' => false, + 'zhSet' => '们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借', + 'useImgBg' => false, + 'fontSize' => 25, + 'useCurve' => true, + 'useNoise' => true, + 'imageH' => 0, + 'imageW' => 0, + 'length' => 4, + 'fontTtf' => '', + 'bg' => [243, 251, 254], + 'reset' => true, + ]; + + private $image = null; + private bool|int|null $color = null; + + public function __construct(array $config = []) + { + $this->config = array_merge($this->config, $config); + + Db::name('captcha') + ->where('expire_time', '<', time()) + ->delete(); + } + + public function __get(string $name): mixed + { + return $this->config[$name]; + } + + public function __set(string $name, mixed $value): void + { + if (isset($this->config[$name])) { + $this->config[$name] = $value; + } + } + + public function __isset(string $name): bool + { + return isset($this->config[$name]); + } + + 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; + } + + 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; + } + + 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(); + $this->imageW || $this->imageW = $this->length * $this->fontSize * 1.5 + $this->length * $this->fontSize / 2; + $this->imageH || $this->imageH = $this->fontSize * 2.5; + $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-Type' => 'image/png', 'Content-Length' => strlen($content)]); + } + + private function writeText(string $captcha = ''): array|string + { + $code = []; + $codeNX = 0; + 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; + } + + private function writeCurve(): void + { + $py = 0; + + $A = mt_rand(1, $this->imageH / 2); + $b = mt_rand(-$this->imageH / 4, $this->imageH / 4); + $f = mt_rand(-$this->imageH / 4, $this->imageH / 4); + $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; + $i = (int)($this->fontSize / 5); + while ($i > 0) { + imagesetpixel($this->image, $px + $i, $py + $i, (int)$this->color); + $i--; + } + } + } + + $A = mt_rand(1, $this->imageH / 2); + $f = mt_rand(-$this->imageH / 4, $this->imageH / 4); + $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; + $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); + $bgImage = @imagecreatefromjpeg($gb); + @imagecopyresampled($this->image, $bgImage, 0, 0, 0, 0, $this->imageW, $this->imageH, $width, $height); + } + + 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); + } + + 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); + } +} diff --git a/extend/ba/ClickCaptcha.php b/extend/ba/ClickCaptcha.php new file mode 100644 index 0000000..541d0f4 --- /dev/null +++ b/extend/ba/ClickCaptcha.php @@ -0,0 +1,373 @@ + '飞机', + 'apple' => '苹果', + 'banana' => '香蕉', + 'bell' => '铃铛', + 'bicycle' => '自行车', + 'bird' => '小鸟', + 'bomb' => '炸弹', + 'butterfly' => '蝴蝶', + 'candy' => '糖果', + 'crab' => '螃蟹', + 'cup' => '杯子', + 'dolphin' => '海豚', + 'fire' => '火', + 'guitar' => '吉他', + 'hexagon' => '六角形', + 'pear' => '梨', + 'rocket' => '火箭', + 'sailboat' => '帆船', + 'snowflake' => '雪花', + 'wolf head' => '狼头', + ]; + + private array $config = [ + 'alpha' => 36, + 'zhSet' => '们以我到他会作时要动国产的是工就年阶义发成部民可出能方进在和有大这主中为来分生对于学级地用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所起政好十战无农使前等反体合斗路图把结第里正新开论之物从当两些还天资事队点育重其思与间内去因件利相由压员气业代全组数果期导平各基或月然如应形想制心样都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极已根共直团统式转别造切九你取西持总料连任志观调么山程百报更见必真保热委手改管处己将修支识象先老光专什六型具示复安带每东增则完风回南劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单坚据速防史拉世设达尔场织历花求传断况采精金界品判参层止边清至万确究书术状须离再目海权且青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿胜细影济白格效置推空配叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非亚磨族段算适讲按值美态易彪服早班麦削信排台声该击素张密害侯何树肥继右属市严径螺检左页抗苏显苦英快称坏移巴材省黑武培著河帝仅针怎植京助升王眼她抓苗副杂普谈围食源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功友限项余倒卷创律雨让骨远帮初皮播优占圈伟季训控激找叫云互跟粮粒母练塞钢顶策双留误础阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺版烈零室轻倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送侧润盖挥距触星松送获兴独官混纪依未突架宽冬章偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞哪旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶念兰映沟乙吗儒汽磷艰晶埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀摆贡呈劲财仪沉炼麻祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜脂庄擦险赞钟摇典柄辩竹谷乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼峰零柴簧午跳居尚秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑冰柬嘴啥饭塑寄赵喊垫丹渡耳虎笔稀昆浪萨茶滴浅拥覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷忽闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳塘燥泡袋朗喂铝软渠颗惯贸综墙趋彼届墨碍启逆卸航衣孙龄岭休借', + ]; + + public function __construct(array $config = []) + { + $clickConfig = config('buildadmin.click_captcha', []); + $this->config = array_merge($clickConfig, $this->config, $config); + + Db::name('captcha')->where('expire_time', '<', time())->delete(); + } + + /** 将 public 下的相对路径转为绝对路径(public_path 无尾部分隔符时也能正确拼接) */ + private function path(string $relativePath): string + { + return Filesystem::fsFit(rtrim(public_path(), '/\\') . DIRECTORY_SEPARATOR . ltrim($relativePath, '/\\')); + } + + /** + * 获取可用的字体路径,优先使用项目字体,不存在时回退到系统字体或配置中的 font_path + */ + protected function getFontPath(): string + { + $customFont = $this->config['font_path'] ?? config('buildadmin.click_captcha.font_path', ''); + if (!empty($customFont)) { + $fullPath = Filesystem::fsFit($customFont); + if (is_file($fullPath)) { + return $fullPath; + } + } + foreach ($this->fontPaths as $path) { + $fullPath = $this->path($path); + if (is_file($fullPath)) { + return $fullPath; + } + } + foreach ($this->getFontFallbacks() as $path) { + $fullPath = Filesystem::fsFit($path); + if (is_file($fullPath)) { + return $fullPath; + } + } + throw new \RuntimeException( + '点选验证码需要中文字体文件。请将 SourceHanSansCN-Normal.ttf 放入 public/static/fonts/zhttfs/ 目录,' . + '或在 config/buildadmin.php 的 click_captcha.font_path 中指定系统字体路径(如 Windows: C:\\Windows\\Fonts\\simhei.ttf)' + ); + } + + /** 当无背景图时创建简易纯色背景(300x150) */ + private function createFallbackBg(): string + { + $w = 300; + $h = 150; + $img = imagecreatetruecolor($w, $h); + imagefill($img, 0, 0, imagecolorallocate($img, 245, 245, 245)); + $dir = runtime_path('captcha'); + if (!is_dir($dir)) { + mkdir($dir, 0755, true); + } + $path = $dir . DIRECTORY_SEPARATOR . 'fallback_bg_' . uniqid() . '.png'; + imagepng($img, $path); + imagedestroy($img); + return $path; + } + + /** 获取存在的背景图路径列表 */ + private function getAvailableBgPaths(): array + { + $available = []; + foreach ($this->bgPaths as $p) { + if (is_file($this->path($p))) { + $available[] = $p; + } + } + return $available; + } + + /** 获取存在的图标名列表(文件存在的才加入) */ + private function getAvailableIcons(): array + { + $available = []; + foreach (array_keys($this->iconDict) as $name) { + $iconPath = $this->path('static/images/captcha/click/icons/' . $name . '.png'); + if (is_file($iconPath)) { + $available[] = $name; + } + } + return $available; + } + + public function creat(string $id): array + { + $availableBgs = $this->getAvailableBgPaths(); + $imagePath = !empty($availableBgs) + ? $this->path($availableBgs[mt_rand(0, count($availableBgs) - 1)]) + : $this->createFallbackBg(); + $fontPath = $this->getFontPath(); + $randPoints = $this->randPoints($this->config['length'] + $this->config['confuse_length']); + + $lang = config('translation.locale', config('lang.default_lang', 'zh-cn')); + $isZhCn = str_starts_with(strtolower(str_replace('_', '-', (string)$lang)), 'zh-cn'); + + foreach ($randPoints as $v) { + $tmp['size'] = rand(15, 30); + if (isset($this->iconDict[$v])) { + $iconPath = $this->path('static/images/captcha/click/icons/' . $v . '.png'); + if (!is_file($iconPath)) { + $fontArea = imagettfbbox($tmp['size'], 0, $fontPath, $this->iconDict[$v]); + $textWidth = $fontArea[2] - $fontArea[0]; + $textHeight = $fontArea[1] - $fontArea[7]; + $tmp['icon'] = false; + $tmp['text'] = $isZhCn ? $this->iconDict[$v] : $v; + $tmp['width'] = $textWidth; + $tmp['height'] = $textHeight; + } else { + $tmp['icon'] = true; + $tmp['name'] = $v; + $tmp['text'] = $isZhCn ? "<{$this->iconDict[$v]}>" : "<$v>"; + $iconInfo = getimagesize($iconPath); + $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: + imagegif($image); + $content = ob_get_clean(); + break; + case 2: + imagejpeg($image); + $content = ob_get_clean(); + break; + case 3: + 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'], + ]; + } + + 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; + } + } + + protected function iconCover($bgImg, $iconImgData): void + { + $iconImage = imagecreatefrompng($this->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']); + } + + 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'])) { + $availableIcons = $this->getAvailableIcons(); + if (!empty($availableIcons)) { + shuffle($availableIcons); + $icon = array_slice($availableIcons, 0, $length); + $arr = array_merge($arr, $icon); + } + } + + shuffle($arr); + $result = array_slice($arr, 0, $length); + if (empty($result)) { + for ($i = 0; $i < $length; $i++) { + $result[] = mb_substr($this->config['zhSet'], mt_rand(0, mb_strlen($this->config['zhSet'], 'utf-8') - 1), 1, 'utf-8'); + } + } + return $result; + } + + 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; + } + + 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; + } +} diff --git a/extend/ba/Date.php b/extend/ba/Date.php new file mode 100644 index 0000000..cdbd74f --- /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)); + } +} diff --git a/extend/ba/Depends.php b/extend/ba/Depends.php new file mode 100644 index 0000000..c8e172c --- /dev/null +++ b/extend/ba/Depends.php @@ -0,0 +1,211 @@ +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); + } +} diff --git a/extend/ba/Exception.php b/extend/ba/Exception.php new file mode 100644 index 0000000..3597f51 --- /dev/null +++ b/extend/ba/Exception.php @@ -0,0 +1,23 @@ +error(__($e->getMessage()), $e->getData(), $e->getCode()); + */ +class Exception extends \Exception +{ + protected array $data = []; + + public function __construct(string $message = '', int $code = 0, array $data = [], ?\Throwable $previous = null) + { + $this->data = $data; + parent::__construct($message, $code, $previous); + } + + public function getData(): array + { + return $this->data; + } +} 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..e751011 --- /dev/null +++ b/extend/ba/Random.php @@ -0,0 +1,48 @@ + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', + 'alnum' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', + 'numeric' => '0123456789', + 'noZero' => '123456789', + default => '', + }; + return substr(str_shuffle(str_repeat($pool, (int) ceil($len / strlen($pool)))), 0, $len); + case 'unique': + case 'md5': + return md5(uniqid((string) mt_rand())); + case 'encrypt': + case 'sha1': + return sha1(uniqid((string) mt_rand(), true)); + } + return ''; + } +} diff --git a/extend/ba/TableManager.php b/extend/ba/TableManager.php new file mode 100644 index 0000000..8d6ca81 --- /dev/null +++ b/extend/ba/TableManager.php @@ -0,0 +1,183 @@ +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 + { + $connectionConfig = self::getConnectionConfig($connection); + $pattern = '/^' . preg_quote($connectionConfig['prefix'], '/') . '/i'; + return ($fullName ? $connectionConfig['prefix'] : '') . preg_replace($pattern, '', $table); + } + + /** + * 数据表列表 + * @param ?string $connection 连接配置标识 + * @throws Exception + */ + public static function getTableList(?string $connection = null): array + { + $tableList = []; + $config = self::getConnectionConfig($connection); + $connName = self::getConnection($connection); + $tables = Db::connect($connName)->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); + $connName = self::getConnection($connection); + + $sql = "SELECT * FROM `information_schema`.`columns` " + . "WHERE TABLE_SCHEMA = ? AND table_name = ? " + . "ORDER BY ORDINAL_POSITION"; + $columnList = Db::connect($connName)->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('thinkorm.connections', [])) > 1; + } + + /** + * 获取数据库连接配置标识 + * @param ?string $source + * @return string 连接配置标识 + */ + public static function getConnection(?string $source = null): string + { + if (!$source || $source === 'default') { + return config('thinkorm.default', 'mysql'); + } + return $source; + } + + /** + * 获取某个数据库连接的配置数组 + * @param ?string $connection 连接配置标识 + * @throws Exception + */ + public static function getConnectionConfig(?string $connection = null): array + { + $connName = self::getConnection($connection); + $connection = config("thinkorm.connections.{$connName}"); + if (!is_array($connection)) { + throw new Exception('Database connection configuration error'); + } + + // 分布式 + if (($connection['deploy'] ?? 0) == 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); + $connName = self::getConnection($connection); + $db = Db::connect($connName); + + $db->query('SELECT 1'); + + $table = config('thinkorm.migration_table', 'migrations'); + return [ + 'adapter' => $config['type'], + 'connection' => $db->getPdo(), + 'name' => $config['database'], + 'table_prefix' => $config['prefix'], + 'migration_table' => $config['prefix'] . $table, + ]; + } +} diff --git a/extend/ba/Terminal.php b/extend/ba/Terminal.php new file mode 100644 index 0000000..32bac53 --- /dev/null +++ b/extend/ba/Terminal.php @@ -0,0 +1,421 @@ +connection、config() + */ +class Terminal +{ + protected static ?Terminal $instance = null; + protected string $commandKey = ''; + protected array $descriptorsPec = []; + protected $process = false; + protected array $pipes = []; + protected int $procStatusMark = 0; + protected array $procStatusData = []; + protected string $uuid = ''; + protected string $extend = ''; + protected string $outputFile = ''; + protected string $outputContent = ''; + protected static string $distDir = 'web' . DIRECTORY_SEPARATOR . 'dist'; + + 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() + { + $request = request(); + $this->uuid = $request ? $request->param('uuid', '') : ''; + $this->extend = $request ? $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']]; + } + + public static function getCommand(string $key): bool|array + { + if (!$key) { + return false; + } + + $commands = config('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 { + $cwd = $command['cwd'] ?? ''; + $root = rtrim(root_path(), DIRECTORY_SEPARATOR . '/'); + $command['cwd'] = $root . DIRECTORY_SEPARATOR . ltrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $cwd), DIRECTORY_SEPARATOR . '/'); + } + + $request = request(); + if ($request && 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']); + if (DIRECTORY_SEPARATOR === '\\') { + $command['command'] = 'cmd /c "cd /d ' . str_replace('"', '""', $command['cwd']) . ' && ' . $command['command'] . '"'; + $command['cwd'] = root_path(); + } + return $command; + } + + public function exec(bool $authentication = true): void + { + $this->sendHeader(); + + while (ob_get_level()) { + ob_end_clean(); + } + if (!ob_get_level()) ob_start(); + + $request = request(); + $this->commandKey = $request ? $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); + + $procEnv = $this->getProcEnv(); + $this->process = proc_open($command['command'], $this->descriptorsPec, $this->pipes, $command['cwd'], $procEnv); + if (!is_resource($this->process)) { + $this->execError('Failed to execute', true); + } + if (isset($this->pipes[0])) { + fclose($this->pipes[0]); + unset($this->pipes[0]); + } + $lastHeartbeat = time(); + $heartbeatInterval = 15; + 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 (strlen(trim($newOutput)) > 0) { + $this->output($newOutput); + $this->outputContent = $contents; + $lastHeartbeat = time(); + } + } + + if ($this->procStatusMark === 1 && (time() - $lastHeartbeat) >= $heartbeatInterval) { + $this->sendHeartbeat(); + $lastHeartbeat = time(); + } + + 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'); + } + + protected function getProcEnv(): ?array + { + $env = getenv(); + if (!is_array($env)) { + return null; + } + $env['CI'] = '1'; + $env['FORCE_COLOR'] = '0'; + return $env; + } + + 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; + } + } + + 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(); + } + } + + 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); + } + } + + public function outputFlag(string $flag): void + { + $this->output($this->flag[$flag], false); + } + + protected function sendHeartbeat(): void + { + $request = request(); + $connection = $request && isset($request->connection) ? $request->connection : null; + if ($connection) { + $connection->send(new ServerSentEvents(['' => 'keepalive'])); + } + @ob_flush(); + } + + public function outputCallback($data): void + { + } + + 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 && class_exists(\app\admin\library\module\Manage::class)) { + [$type, $value] = explode(':', $this->extend); + if ($type == 'module-install' && $value) { + \app\admin\library\module\Manage::instance($value)->dependentInstallComplete('npm'); + } + } elseif ($commandPKey == 'composer' && $this->extend && class_exists(\app\admin\library\module\Manage::class)) { + [$type, $value] = explode(':', $this->extend); + if ($type == 'module-install' && $value) { + \app\admin\library\module\Manage::instance($value)->dependentInstallComplete('composer'); + } + } elseif ($commandPKey == 'nuxt-install' && $this->extend && class_exists(\app\admin\library\module\Manage::class)) { + [$type, $value] = explode(':', $this->extend); + if ($type == 'module-install' && $value) { + \app\admin\library\module\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 = '/\x1b\[(.*?)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 TerminalBreakException(); + } + + 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 + { + $request = request(); + $oldPackageManager = config('terminal.npm_package_manager'); + $newPackageManager = $request ? $request->post('manager', $config['manager'] ?? $oldPackageManager) : $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 + { + $request = request(); + $connection = $request && isset($request->connection) ? $request->connection : null; + if ($connection) { + $connection->send(new ServerSentEvents(['event' => 'message', 'data' => $data])); + } else { + echo 'data: ' . $data . "\n\n"; + } + } + + public function sendHeader(): void + { + $request = request(); + $headers = array_merge($request->allowCrossDomainHeaders ?? [], [ + 'X-Accel-Buffering' => 'no', + 'Content-Type' => 'text/event-stream', + 'Cache-Control' => 'no-cache', + ]); + + $connection = $request && isset($request->connection) ? $request->connection : null; + if ($connection) { + $connection->send(new WorkermanResponse(200, $headers, "\r\n")); + } else { + foreach ($headers as $name => $val) { + header($name . (!is_null($val) ? ':' . $val : '')); + } + } + } +} diff --git a/extend/ba/TerminalBreakException.php b/extend/ba/TerminalBreakException.php new file mode 100644 index 0000000..39018a7 --- /dev/null +++ b/extend/ba/TerminalBreakException.php @@ -0,0 +1,10 @@ +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; + } +} diff --git a/extend/ba/Version.php b/extend/ba/Version.php new file mode 100644 index 0000000..d94c108 --- /dev/null +++ b/extend/ba/Version.php @@ -0,0 +1,128 @@ + $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 ''; + } +} diff --git a/phinx-bootstrap.php b/phinx-bootstrap.php new file mode 100644 index 0000000..d9c25b6 --- /dev/null +++ b/phinx-bootstrap.php @@ -0,0 +1,49 @@ +load(); + } else { + Dotenv\Dotenv::createMutable($baseDir)->load(); + } +} + +if (!function_exists('env')) { + function env(string $key, mixed $default = null): mixed + { + $value = $_ENV[$key] ?? getenv($key); + if ($value !== false && $value !== null) { + return $value; + } + if (strpos($key, '.') !== false) { + $parts = explode('.', $key); + $upper = strtoupper(implode('_', $parts)); + $value = $_ENV[$upper] ?? getenv($upper); + if ($value !== false && $value !== null) { + return $value; + } + } + return $default; + } +} + +require $baseDir . '/vendor/workerman/webman-framework/src/support/helpers.php'; +require $baseDir . '/app/functions.php'; + +Webman\Config::load($baseDir . '/config', ['route', 'middleware', 'process', 'server', 'static']); +$thinkorm = config('thinkorm', []); +if (!empty($thinkorm)) { + support\think\Db::setConfig($thinkorm); +} diff --git a/phinx.php b/phinx.php new file mode 100644 index 0000000..b4cf22a --- /dev/null +++ b/phinx.php @@ -0,0 +1,63 @@ +load(); + } else { + Dotenv\Dotenv::createMutable($baseDir)->load(); + } +} + +if (!function_exists('env')) { + function env(string $key, mixed $default = null): mixed + { + $value = $_ENV[$key] ?? getenv($key); + if ($value !== false && $value !== null) { + return $value; + } + if (strpos($key, '.') !== false) { + $parts = explode('.', $key); + $upper = strtoupper(implode('_', $parts)); + $value = $_ENV[$upper] ?? getenv($upper); + if ($value !== false && $value !== null) { + return $value; + } + } + return $default; + } +} + +$thinkorm = require $baseDir . '/config/thinkorm.php'; +$conn = $thinkorm['connections'][$thinkorm['default'] ?? 'mysql'] ?? []; +$prefix = $conn['prefix'] ?? ''; + +return [ + 'paths' => [ + 'migrations' => $baseDir . '/database/migrations', + 'seeds' => $baseDir . '/database/seeds', + 'bootstrap' => $baseDir . '/phinx-bootstrap.php', + ], + 'environments' => [ + 'default_migration_table' => $prefix . 'phinxlog', + 'default_environment' => 'prod', + 'prod' => [ + 'adapter' => 'mysql', + 'host' => $conn['hostname'] ?? '127.0.0.1', + 'name' => $conn['database'] ?? '', + 'user' => $conn['username'] ?? 'root', + 'pass' => $conn['password'] ?? '', + 'port' => $conn['hostport'] ?? 3306, + 'charset' => $conn['charset'] ?? 'utf8mb4', + 'table_prefix' => $prefix, + ], + ], +]; diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..b9f722e Binary files /dev/null and b/public/favicon.ico differ 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..c7c0c01 --- /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 vendor/bin/phinx migrate",-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/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..d337465 --- /dev/null +++ b/runtime/.gitignore @@ -0,0 +1,4 @@ +* +!logs +!views +!.gitignore diff --git a/runtime/logs/.gitignore b/runtime/logs/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/runtime/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/runtime/views/.gitignore b/runtime/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/runtime/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/start.php b/start.php new file mode 100644 index 0000000..41ad7ef --- /dev/null +++ b/start.php @@ -0,0 +1,5 @@ +#!/usr/bin/env php + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace support; + +/** + * Class Request + * @package support + */ +class Request extends \Webman\Http\Request +{ + /** @var callable|null 参数过滤器,用于兼容 ThinkPHP 的 filter() */ + protected $filter = null; + + /** + * 获取请求路径(兼容 ThinkPHP:去除 index.php 前缀,使 /index.php/api/xxx 等价于 /api/xxx) + */ + public function path(): string + { + $path = parent::path(); + if (str_starts_with($path, '/index.php')) { + $path = substr($path, 10) ?: '/'; + } + return $path; + } + + /** + * 获取请求参数(兼容 ThinkPHP param,合并 get/post,post 优先) + * @param string|null $name 参数名,null 返回全部 + * @param mixed $default 默认值 + * @return mixed + */ + public function param(?string $name = null, $default = null) + { + $data = $this->post() + $this->get(); + if ($name === null) { + return $this->applyFilter($data); + } + if (!array_key_exists($name, $data)) { + return $default; + } + return $this->applyFilter($data[$name]); + } + + /** + * 设置参数过滤器(兼容 ThinkPHP filter) + * @param string $filter 过滤器名,如 'clean_xss'、'trim' + * @return $this + */ + public function filter(string $filter) + { + if ($filter === 'clean_xss' && function_exists('clean_xss')) { + $this->filter = 'clean_xss'; + } elseif ($filter === 'trim') { + $this->filter = 'trim'; + } else { + $this->filter = null; + } + return $this; + } + + /** + * 对值应用已设置的过滤器 + */ + protected function applyFilter($value) + { + if ($this->filter === null) { + return $value; + } + if (is_array($value)) { + foreach ($value as $k => $v) { + $value[$k] = $this->applyFilter($v); + } + return $value; + } + if (is_string($value) && $this->filter === 'clean_xss') { + return clean_xss($value); + } + if (is_string($value) && $this->filter === 'trim') { + return trim($value); + } + return $value; + } +} \ No newline at end of file diff --git a/support/Response.php b/support/Response.php new file mode 100644 index 0000000..9bc4e1e --- /dev/null +++ b/support/Response.php @@ -0,0 +1,24 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +namespace support; + +/** + * Class Response + * @package support + */ +class Response extends \Webman\Http\Response +{ + +} \ No newline at end of file diff --git a/support/Setup.php b/support/Setup.php new file mode 100644 index 0000000..99320e8 --- /dev/null +++ b/support/Setup.php @@ -0,0 +1,1558 @@ + \DateTimeZone::ASIA, + 'Europe' => \DateTimeZone::EUROPE, + 'America' => \DateTimeZone::AMERICA, + 'Africa' => \DateTimeZone::AFRICA, + 'Australia' => \DateTimeZone::AUSTRALIA, + 'Pacific' => \DateTimeZone::PACIFIC, + 'Atlantic' => \DateTimeZone::ATLANTIC, + 'Indian' => \DateTimeZone::INDIAN, + 'Antarctica' => \DateTimeZone::ANTARCTICA, + 'Arctic' => \DateTimeZone::ARCTIC, + 'UTC' => \DateTimeZone::UTC, + ]; + + // --- Locale => default timezone --- + + private const LOCALE_DEFAULT_TIMEZONES = [ + 'zh_CN' => 'Asia/Shanghai', + 'zh_TW' => 'Asia/Taipei', + 'en' => 'UTC', + 'ja' => 'Asia/Tokyo', + 'ko' => 'Asia/Seoul', + 'fr' => 'Europe/Paris', + 'de' => 'Europe/Berlin', + 'es' => 'Europe/Madrid', + 'pt_BR' => 'America/Sao_Paulo', + 'ru' => 'Europe/Moscow', + 'vi' => 'Asia/Ho_Chi_Minh', + 'tr' => 'Europe/Istanbul', + 'id' => 'Asia/Jakarta', + 'th' => 'Asia/Bangkok', + ]; + + // --- Locale options (localized display names) --- + + private const LOCALE_LABELS = [ + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'en' => 'English', + 'ja' => '日本語', + 'ko' => '한국어', + 'fr' => 'Français', + 'de' => 'Deutsch', + 'es' => 'Español', + 'pt_BR' => 'Português (Brasil)', + 'ru' => 'Русский', + 'vi' => 'Tiếng Việt', + 'tr' => 'Türkçe', + 'id' => 'Bahasa Indonesia', + 'th' => 'ไทย', + ]; + + // --- Multilingual messages (%s = placeholder) --- + + private const MESSAGES = [ + 'zh_CN' => [ + 'remove_package_question' => '发现以下已安装组件本次未选择,是否将其卸载 ?%s', + 'removing_package' => '- 准备移除组件 %s', + 'removing' => '卸载:', + 'error_remove' => '卸载组件出错,请手动执行:composer remove %s', + 'done_remove' => '已卸载组件。', + 'skip' => '非交互模式,跳过安装向导。', + 'default_choice' => ' (默认 %s)', + 'timezone_prompt' => '时区 (默认 %s,输入可联想补全): ', + 'timezone_title' => '时区设置 (默认 %s)', + 'timezone_help' => '输入关键字Tab自动补全,可↑↓下选择:', + 'timezone_region' => '选择时区区域', + 'timezone_city' => '选择时区', + 'timezone_invalid' => '无效的时区,已使用默认值 %s', + 'timezone_input_prompt' => '输入时区或关键字:', + 'timezone_pick_prompt' => '请输入数字编号或关键字:', + 'timezone_no_match' => '未找到匹配的时区,请重试。', + 'timezone_invalid_index' => '无效的编号,请重新输入。', + 'yes' => '是', + 'no' => '否', + 'adding_package' => '- 添加依赖 %s', + 'console_question' => '安装命令行组件 webman/console', + 'db_question' => '数据库组件', + 'db_none' => '不安装', + 'db_invalid' => '请输入有效选项', + 'redis_question' => '安装 Redis 组件 webman/redis', + 'events_note' => ' (Redis 依赖 illuminate/events,已自动包含)', + 'validation_question' => '安装验证器组件 webman/validation', + 'template_question' => '模板引擎', + 'template_none' => '不安装', + 'no_components' => '未选择额外组件。', + 'installing' => '即将安装:', + 'running' => '执行:', + 'error_install' => '安装可选组件时出错,请手动执行:composer require %s', + 'done' => '可选组件安装完成。', + 'summary_locale' => '语言:%s', + 'summary_timezone' => '时区:%s', + ], + 'zh_TW' => [ + 'skip' => '非交互模式,跳過安裝嚮導。', + 'default_choice' => ' (預設 %s)', + 'timezone_prompt' => '時區 (預設 %s,輸入可聯想補全): ', + 'timezone_title' => '時區設定 (預設 %s)', + 'timezone_help' => '輸入關鍵字Tab自動補全,可↑↓上下選擇:', + 'timezone_region' => '選擇時區區域', + 'timezone_city' => '選擇時區', + 'timezone_invalid' => '無效的時區,已使用預設值 %s', + 'timezone_input_prompt' => '輸入時區或關鍵字:', + 'timezone_pick_prompt' => '請輸入數字編號或關鍵字:', + 'timezone_no_match' => '未找到匹配的時區,請重試。', + 'timezone_invalid_index' => '無效的編號,請重新輸入。', + 'yes' => '是', + 'no' => '否', + 'adding_package' => '- 新增依賴 %s', + 'console_question' => '安裝命令列組件 webman/console', + 'db_question' => '資料庫組件', + 'db_none' => '不安裝', + 'db_invalid' => '請輸入有效選項', + 'redis_question' => '安裝 Redis 組件 webman/redis', + 'events_note' => ' (Redis 依賴 illuminate/events,已自動包含)', + 'validation_question' => '安裝驗證器組件 webman/validation', + 'template_question' => '模板引擎', + 'template_none' => '不安裝', + 'no_components' => '未選擇額外組件。', + 'installing' => '即將安裝:', + 'running' => '執行:', + 'error_install' => '安裝可選組件時出錯,請手動執行:composer require %s', + 'done' => '可選組件安裝完成。', + 'summary_locale' => '語言:%s', + 'summary_timezone' => '時區:%s', + ], + 'en' => [ + 'skip' => 'Non-interactive mode, skipping setup wizard.', + 'default_choice' => ' (default %s)', + 'timezone_prompt' => 'Timezone (default=%s, type to autocomplete): ', + 'timezone_title' => 'Timezone (default=%s)', + 'timezone_help' => 'Type keyword then press Tab to autocomplete, use ↑↓ to choose:', + 'timezone_region' => 'Select timezone region', + 'timezone_city' => 'Select timezone', + 'timezone_invalid' => 'Invalid timezone, using default %s', + 'timezone_input_prompt' => 'Enter timezone or keyword:', + 'timezone_pick_prompt' => 'Enter number or keyword:', + 'timezone_no_match' => 'No matching timezone found, please try again.', + 'timezone_invalid_index' => 'Invalid number, please try again.', + 'yes' => 'yes', + 'no' => 'no', + 'adding_package' => '- Adding package %s', + 'console_question' => 'Install console component webman/console', + 'db_question' => 'Database component', + 'db_none' => 'None', + 'db_invalid' => 'Please enter a valid option', + 'redis_question' => 'Install Redis component webman/redis', + 'events_note' => ' (Redis requires illuminate/events, automatically included)', + 'validation_question' => 'Install validator component webman/validation', + 'template_question' => 'Template engine', + 'template_none' => 'None', + 'no_components' => 'No optional components selected.', + 'installing' => 'Installing:', + 'running' => 'Running:', + 'error_install' => 'Failed to install. Try manually: composer require %s', + 'done' => 'Optional components installed.', + 'summary_locale' => 'Language: %s', + 'summary_timezone' => 'Timezone: %s', + ], + 'ja' => [ + 'skip' => '非対話モードのため、セットアップウィザードをスキップします。', + 'default_choice' => ' (デフォルト %s)', + 'timezone_prompt' => 'タイムゾーン (デフォルト=%s、入力で補完): ', + 'timezone_title' => 'タイムゾーン (デフォルト=%s)', + 'timezone_help' => 'キーワード入力→Tabで補完、↑↓で選択:', + 'timezone_region' => 'タイムゾーンの地域を選択', + 'timezone_city' => 'タイムゾーンを選択', + 'timezone_invalid' => '無効なタイムゾーンです。デフォルト %s を使用します', + 'timezone_input_prompt' => 'タイムゾーンまたはキーワードを入力:', + 'timezone_pick_prompt' => '番号またはキーワードを入力:', + 'timezone_no_match' => '一致するタイムゾーンが見つかりません。再試行してください。', + 'timezone_invalid_index' => '無効な番号です。もう一度入力してください。', + 'yes' => 'はい', + 'no' => 'いいえ', + 'adding_package' => '- パッケージを追加 %s', + 'console_question' => 'コンソールコンポーネント webman/console をインストール', + 'db_question' => 'データベースコンポーネント', + 'db_none' => 'インストールしない', + 'db_invalid' => '有効なオプションを入力してください', + 'redis_question' => 'Redis コンポーネント webman/redis をインストール', + 'events_note' => ' (Redis は illuminate/events が必要です。自動的に含まれます)', + 'validation_question' => 'バリデーションコンポーネント webman/validation をインストール', + 'template_question' => 'テンプレートエンジン', + 'template_none' => 'インストールしない', + 'no_components' => 'オプションコンポーネントが選択されていません。', + 'installing' => 'インストール中:', + 'running' => '実行中:', + 'error_install' => 'インストールに失敗しました。手動で実行してください:composer require %s', + 'done' => 'オプションコンポーネントのインストールが完了しました。', + 'summary_locale' => '言語:%s', + 'summary_timezone' => 'タイムゾーン:%s', + ], + 'ko' => [ + 'skip' => '비대화형 모드입니다. 설치 마법사를 건너뜁니다.', + 'default_choice' => ' (기본값 %s)', + 'timezone_prompt' => '시간대 (기본값=%s, 입력하여 자동완성): ', + 'timezone_title' => '시간대 (기본값=%s)', + 'timezone_help' => '키워드 입력 후 Tab 자동완성, ↑↓로 선택:', + 'timezone_region' => '시간대 지역 선택', + 'timezone_city' => '시간대 선택', + 'timezone_invalid' => '잘못된 시간대입니다. 기본값 %s 을(를) 사용합니다', + 'timezone_input_prompt' => '시간대 또는 키워드 입력:', + 'timezone_pick_prompt' => '번호 또는 키워드 입력:', + 'timezone_no_match' => '일치하는 시간대를 찾을 수 없습니다. 다시 시도하세요.', + 'timezone_invalid_index' => '잘못된 번호입니다. 다시 입력하세요.', + 'yes' => '예', + 'no' => '아니오', + 'adding_package' => '- 패키지 추가 %s', + 'console_question' => '콘솔 컴포넌트 webman/console 설치', + 'db_question' => '데이터베이스 컴포넌트', + 'db_none' => '설치 안 함', + 'db_invalid' => '유효한 옵션을 입력하세요', + 'redis_question' => 'Redis 컴포넌트 webman/redis 설치', + 'events_note' => ' (Redis는 illuminate/events가 필요합니다. 자동으로 포함됩니다)', + 'validation_question' => '검증 컴포넌트 webman/validation 설치', + 'template_question' => '템플릿 엔진', + 'template_none' => '설치 안 함', + 'no_components' => '선택된 추가 컴포넌트가 없습니다.', + 'installing' => '설치 예정:', + 'running' => '실행 중:', + 'error_install' => '설치에 실패했습니다. 수동으로 실행하세요: composer require %s', + 'done' => '선택 컴포넌트 설치가 완료되었습니다.', + 'summary_locale' => '언어: %s', + 'summary_timezone' => '시간대: %s', + ], + 'fr' => [ + 'skip' => 'Mode non interactif, assistant d\'installation ignoré.', + 'default_choice' => ' (défaut %s)', + 'timezone_prompt' => 'Fuseau horaire (défaut=%s, tapez pour compléter) : ', + 'timezone_title' => 'Fuseau horaire (défaut=%s)', + 'timezone_help' => 'Tapez un mot-clé, Tab pour compléter, ↑↓ pour choisir :', + 'timezone_region' => 'Sélectionnez la région du fuseau horaire', + 'timezone_city' => 'Sélectionnez le fuseau horaire', + 'timezone_invalid' => 'Fuseau horaire invalide, utilisation de %s par défaut', + 'timezone_input_prompt' => 'Entrez un fuseau horaire ou un mot-clé :', + 'timezone_pick_prompt' => 'Entrez un numéro ou un mot-clé :', + 'timezone_no_match' => 'Aucun fuseau horaire correspondant, veuillez réessayer.', + 'timezone_invalid_index' => 'Numéro invalide, veuillez réessayer.', + 'yes' => 'oui', + 'no' => 'non', + 'adding_package' => '- Ajout du paquet %s', + 'console_question' => 'Installer le composant console webman/console', + 'db_question' => 'Composant base de données', + 'db_none' => 'Aucun', + 'db_invalid' => 'Veuillez entrer une option valide', + 'redis_question' => 'Installer le composant Redis webman/redis', + 'events_note' => ' (Redis nécessite illuminate/events, inclus automatiquement)', + 'validation_question' => 'Installer le composant de validation webman/validation', + 'template_question' => 'Moteur de templates', + 'template_none' => 'Aucun', + 'no_components' => 'Aucun composant optionnel sélectionné.', + 'installing' => 'Installation en cours :', + 'running' => 'Exécution :', + 'error_install' => 'Échec de l\'installation. Essayez manuellement : composer require %s', + 'done' => 'Composants optionnels installés.', + 'summary_locale' => 'Langue : %s', + 'summary_timezone' => 'Fuseau horaire : %s', + ], + 'de' => [ + 'skip' => 'Nicht-interaktiver Modus, Einrichtungsassistent übersprungen.', + 'default_choice' => ' (Standard %s)', + 'timezone_prompt' => 'Zeitzone (Standard=%s, Eingabe zur Vervollständigung): ', + 'timezone_title' => 'Zeitzone (Standard=%s)', + 'timezone_help' => 'Stichwort tippen, Tab ergänzt, ↑↓ auswählen:', + 'timezone_region' => 'Zeitzone Region auswählen', + 'timezone_city' => 'Zeitzone auswählen', + 'timezone_invalid' => 'Ungültige Zeitzone, Standardwert %s wird verwendet', + 'timezone_input_prompt' => 'Zeitzone oder Stichwort eingeben:', + 'timezone_pick_prompt' => 'Nummer oder Stichwort eingeben:', + 'timezone_no_match' => 'Keine passende Zeitzone gefunden, bitte erneut versuchen.', + 'timezone_invalid_index' => 'Ungültige Nummer, bitte erneut eingeben.', + 'yes' => 'ja', + 'no' => 'nein', + 'adding_package' => '- Paket hinzufügen %s', + 'console_question' => 'Konsolen-Komponente webman/console installieren', + 'db_question' => 'Datenbank-Komponente', + 'db_none' => 'Keine', + 'db_invalid' => 'Bitte geben Sie eine gültige Option ein', + 'redis_question' => 'Redis-Komponente webman/redis installieren', + 'events_note' => ' (Redis benötigt illuminate/events, automatisch eingeschlossen)', + 'validation_question' => 'Validierungs-Komponente webman/validation installieren', + 'template_question' => 'Template-Engine', + 'template_none' => 'Keine', + 'no_components' => 'Keine optionalen Komponenten ausgewählt.', + 'installing' => 'Installation:', + 'running' => 'Ausführung:', + 'error_install' => 'Installation fehlgeschlagen. Manuell ausführen: composer require %s', + 'done' => 'Optionale Komponenten installiert.', + 'summary_locale' => 'Sprache: %s', + 'summary_timezone' => 'Zeitzone: %s', + ], + 'es' => [ + 'skip' => 'Modo no interactivo, asistente de instalación omitido.', + 'default_choice' => ' (predeterminado %s)', + 'timezone_prompt' => 'Zona horaria (predeterminado=%s, escriba para autocompletar): ', + 'timezone_title' => 'Zona horaria (predeterminado=%s)', + 'timezone_help' => 'Escriba una palabra clave, Tab autocompleta, use ↑↓ para elegir:', + 'timezone_region' => 'Seleccione la región de zona horaria', + 'timezone_city' => 'Seleccione la zona horaria', + 'timezone_invalid' => 'Zona horaria inválida, usando valor predeterminado %s', + 'timezone_input_prompt' => 'Ingrese zona horaria o palabra clave:', + 'timezone_pick_prompt' => 'Ingrese número o palabra clave:', + 'timezone_no_match' => 'No se encontró zona horaria coincidente, intente de nuevo.', + 'timezone_invalid_index' => 'Número inválido, intente de nuevo.', + 'yes' => 'sí', + 'no' => 'no', + 'adding_package' => '- Agregando paquete %s', + 'console_question' => 'Instalar componente de consola webman/console', + 'db_question' => 'Componente de base de datos', + 'db_none' => 'Ninguno', + 'db_invalid' => 'Por favor ingrese una opción válida', + 'redis_question' => 'Instalar componente Redis webman/redis', + 'events_note' => ' (Redis requiere illuminate/events, incluido automáticamente)', + 'validation_question' => 'Instalar componente de validación webman/validation', + 'template_question' => 'Motor de plantillas', + 'template_none' => 'Ninguno', + 'no_components' => 'No se seleccionaron componentes opcionales.', + 'installing' => 'Instalando:', + 'running' => 'Ejecutando:', + 'error_install' => 'Error en la instalación. Intente manualmente: composer require %s', + 'done' => 'Componentes opcionales instalados.', + 'summary_locale' => 'Idioma: %s', + 'summary_timezone' => 'Zona horaria: %s', + ], + 'pt_BR' => [ + 'skip' => 'Modo não interativo, assistente de instalação ignorado.', + 'default_choice' => ' (padrão %s)', + 'timezone_prompt' => 'Fuso horário (padrão=%s, digite para autocompletar): ', + 'timezone_title' => 'Fuso horário (padrão=%s)', + 'timezone_help' => 'Digite uma palavra-chave, Tab autocompleta, use ↑↓ para escolher:', + 'timezone_region' => 'Selecione a região do fuso horário', + 'timezone_city' => 'Selecione o fuso horário', + 'timezone_invalid' => 'Fuso horário inválido, usando padrão %s', + 'timezone_input_prompt' => 'Digite fuso horário ou palavra-chave:', + 'timezone_pick_prompt' => 'Digite número ou palavra-chave:', + 'timezone_no_match' => 'Nenhum fuso horário encontrado, tente novamente.', + 'timezone_invalid_index' => 'Número inválido, tente novamente.', + 'yes' => 'sim', + 'no' => 'não', + 'adding_package' => '- Adicionando pacote %s', + 'console_question' => 'Instalar componente de console webman/console', + 'db_question' => 'Componente de banco de dados', + 'db_none' => 'Nenhum', + 'db_invalid' => 'Por favor, digite uma opção válida', + 'redis_question' => 'Instalar componente Redis webman/redis', + 'events_note' => ' (Redis requer illuminate/events, incluído automaticamente)', + 'validation_question' => 'Instalar componente de validação webman/validation', + 'template_question' => 'Motor de templates', + 'template_none' => 'Nenhum', + 'no_components' => 'Nenhum componente opcional selecionado.', + 'installing' => 'Instalando:', + 'running' => 'Executando:', + 'error_install' => 'Falha na instalação. Tente manualmente: composer require %s', + 'done' => 'Componentes opcionais instalados.', + 'summary_locale' => 'Idioma: %s', + 'summary_timezone' => 'Fuso horário: %s', + ], + 'ru' => [ + 'skip' => 'Неинтерактивный режим, мастер установки пропущен.', + 'default_choice' => ' (по умолчанию %s)', + 'timezone_prompt' => 'Часовой пояс (по умолчанию=%s, введите для автодополнения): ', + 'timezone_title' => 'Часовой пояс (по умолчанию=%s)', + 'timezone_help' => 'Введите ключевое слово, Tab для автодополнения, ↑↓ для выбора:', + 'timezone_region' => 'Выберите регион часового пояса', + 'timezone_city' => 'Выберите часовой пояс', + 'timezone_invalid' => 'Неверный часовой пояс, используется значение по умолчанию %s', + 'timezone_input_prompt' => 'Введите часовой пояс или ключевое слово:', + 'timezone_pick_prompt' => 'Введите номер или ключевое слово:', + 'timezone_no_match' => 'Совпадающий часовой пояс не найден, попробуйте снова.', + 'timezone_invalid_index' => 'Неверный номер, попробуйте снова.', + 'yes' => 'да', + 'no' => 'нет', + 'adding_package' => '- Добавление пакета %s', + 'console_question' => 'Установить консольный компонент webman/console', + 'db_question' => 'Компонент базы данных', + 'db_none' => 'Не устанавливать', + 'db_invalid' => 'Пожалуйста, введите допустимый вариант', + 'redis_question' => 'Установить компонент Redis webman/redis', + 'events_note' => ' (Redis требует illuminate/events, автоматически включён)', + 'validation_question' => 'Установить компонент валидации webman/validation', + 'template_question' => 'Шаблонизатор', + 'template_none' => 'Не устанавливать', + 'no_components' => 'Дополнительные компоненты не выбраны.', + 'installing' => 'Установка:', + 'running' => 'Выполнение:', + 'error_install' => 'Ошибка установки. Выполните вручную: composer require %s', + 'done' => 'Дополнительные компоненты установлены.', + 'summary_locale' => 'Язык: %s', + 'summary_timezone' => 'Часовой пояс: %s', + ], + 'vi' => [ + 'skip' => 'Chế độ không tương tác, bỏ qua trình hướng dẫn cài đặt.', + 'default_choice' => ' (mặc định %s)', + 'timezone_prompt' => 'Múi giờ (mặc định=%s, nhập để tự động hoàn thành): ', + 'timezone_title' => 'Múi giờ (mặc định=%s)', + 'timezone_help' => 'Nhập từ khóa, Tab để tự hoàn thành, dùng ↑↓ để chọn:', + 'timezone_region' => 'Chọn khu vực múi giờ', + 'timezone_city' => 'Chọn múi giờ', + 'timezone_invalid' => 'Múi giờ không hợp lệ, sử dụng mặc định %s', + 'timezone_input_prompt' => 'Nhập múi giờ hoặc từ khóa:', + 'timezone_pick_prompt' => 'Nhập số thứ tự hoặc từ khóa:', + 'timezone_no_match' => 'Không tìm thấy múi giờ phù hợp, vui lòng thử lại.', + 'timezone_invalid_index' => 'Số không hợp lệ, vui lòng thử lại.', + 'yes' => 'có', + 'no' => 'không', + 'adding_package' => '- Thêm gói %s', + 'console_question' => 'Cài đặt thành phần console webman/console', + 'db_question' => 'Thành phần cơ sở dữ liệu', + 'db_none' => 'Không cài đặt', + 'db_invalid' => 'Vui lòng nhập tùy chọn hợp lệ', + 'redis_question' => 'Cài đặt thành phần Redis webman/redis', + 'events_note' => ' (Redis cần illuminate/events, đã tự động bao gồm)', + 'validation_question' => 'Cài đặt thành phần xác thực webman/validation', + 'template_question' => 'Công cụ mẫu', + 'template_none' => 'Không cài đặt', + 'no_components' => 'Không có thành phần tùy chọn nào được chọn.', + 'installing' => 'Đang cài đặt:', + 'running' => 'Đang thực thi:', + 'error_install' => 'Cài đặt thất bại. Thử thủ công: composer require %s', + 'done' => 'Các thành phần tùy chọn đã được cài đặt.', + 'summary_locale' => 'Ngôn ngữ: %s', + 'summary_timezone' => 'Múi giờ: %s', + ], + 'tr' => [ + 'skip' => 'Etkileşimsiz mod, kurulum sihirbazı atlanıyor.', + 'default_choice' => ' (varsayılan %s)', + 'timezone_prompt' => 'Saat dilimi (varsayılan=%s, otomatik tamamlama için yazın): ', + 'timezone_title' => 'Saat dilimi (varsayılan=%s)', + 'timezone_help' => 'Anahtar kelime yazın, Tab tamamlar, ↑↓ ile seçin:', + 'timezone_region' => 'Saat dilimi bölgesini seçin', + 'timezone_city' => 'Saat dilimini seçin', + 'timezone_invalid' => 'Geçersiz saat dilimi, varsayılan %s kullanılıyor', + 'timezone_input_prompt' => 'Saat dilimi veya anahtar kelime girin:', + 'timezone_pick_prompt' => 'Numara veya anahtar kelime girin:', + 'timezone_no_match' => 'Eşleşen saat dilimi bulunamadı, tekrar deneyin.', + 'timezone_invalid_index' => 'Geçersiz numara, tekrar deneyin.', + 'yes' => 'evet', + 'no' => 'hayır', + 'adding_package' => '- Paket ekleniyor %s', + 'console_question' => 'Konsol bileşeni webman/console yüklensin mi', + 'db_question' => 'Veritabanı bileşeni', + 'db_none' => 'Yok', + 'db_invalid' => 'Lütfen geçerli bir seçenek girin', + 'redis_question' => 'Redis bileşeni webman/redis yüklensin mi', + 'events_note' => ' (Redis, illuminate/events gerektirir, otomatik olarak dahil edildi)', + 'validation_question' => 'Doğrulama bileşeni webman/validation yüklensin mi', + 'template_question' => 'Şablon motoru', + 'template_none' => 'Yok', + 'no_components' => 'İsteğe bağlı bileşen seçilmedi.', + 'installing' => 'Yükleniyor:', + 'running' => 'Çalıştırılıyor:', + 'error_install' => 'Yükleme başarısız. Manuel olarak deneyin: composer require %s', + 'done' => 'İsteğe bağlı bileşenler yüklendi.', + 'summary_locale' => 'Dil: %s', + 'summary_timezone' => 'Saat dilimi: %s', + ], + 'id' => [ + 'skip' => 'Mode non-interaktif, melewati wizard instalasi.', + 'default_choice' => ' (default %s)', + 'timezone_prompt' => 'Zona waktu (default=%s, ketik untuk melengkapi): ', + 'timezone_title' => 'Zona waktu (default=%s)', + 'timezone_help' => 'Ketik kata kunci, Tab untuk melengkapi, gunakan ↑↓ untuk memilih:', + 'timezone_region' => 'Pilih wilayah zona waktu', + 'timezone_city' => 'Pilih zona waktu', + 'timezone_invalid' => 'Zona waktu tidak valid, menggunakan default %s', + 'timezone_input_prompt' => 'Masukkan zona waktu atau kata kunci:', + 'timezone_pick_prompt' => 'Masukkan nomor atau kata kunci:', + 'timezone_no_match' => 'Zona waktu tidak ditemukan, silakan coba lagi.', + 'timezone_invalid_index' => 'Nomor tidak valid, silakan coba lagi.', + 'yes' => 'ya', + 'no' => 'tidak', + 'adding_package' => '- Menambahkan paket %s', + 'console_question' => 'Instal komponen konsol webman/console', + 'db_question' => 'Komponen database', + 'db_none' => 'Tidak ada', + 'db_invalid' => 'Silakan masukkan opsi yang valid', + 'redis_question' => 'Instal komponen Redis webman/redis', + 'events_note' => ' (Redis memerlukan illuminate/events, otomatis disertakan)', + 'validation_question' => 'Instal komponen validasi webman/validation', + 'template_question' => 'Mesin template', + 'template_none' => 'Tidak ada', + 'no_components' => 'Tidak ada komponen opsional yang dipilih.', + 'installing' => 'Menginstal:', + 'running' => 'Menjalankan:', + 'error_install' => 'Instalasi gagal. Coba manual: composer require %s', + 'done' => 'Komponen opsional terinstal.', + 'summary_locale' => 'Bahasa: %s', + 'summary_timezone' => 'Zona waktu: %s', + ], + 'th' => [ + 'skip' => 'โหมดไม่โต้ตอบ ข้ามตัวช่วยติดตั้ง', + 'default_choice' => ' (ค่าเริ่มต้น %s)', + 'timezone_prompt' => 'เขตเวลา (ค่าเริ่มต้น=%s พิมพ์เพื่อเติมอัตโนมัติ): ', + 'timezone_title' => 'เขตเวลา (ค่าเริ่มต้น=%s)', + 'timezone_help' => 'พิมพ์คีย์เวิร์ดแล้วกด Tab เพื่อเติมอัตโนมัติ ใช้ ↑↓ เพื่อเลือก:', + 'timezone_region' => 'เลือกภูมิภาคเขตเวลา', + 'timezone_city' => 'เลือกเขตเวลา', + 'timezone_invalid' => 'เขตเวลาไม่ถูกต้อง ใช้ค่าเริ่มต้น %s', + 'timezone_input_prompt' => 'ป้อนเขตเวลาหรือคำค้น:', + 'timezone_pick_prompt' => 'ป้อนหมายเลขหรือคำค้น:', + 'timezone_no_match' => 'ไม่พบเขตเวลาที่ตรงกัน กรุณาลองอีกครั้ง', + 'timezone_invalid_index' => 'หมายเลขไม่ถูกต้อง กรุณาลองอีกครั้ง', + 'yes' => 'ใช่', + 'no' => 'ไม่', + 'adding_package' => '- เพิ่มแพ็กเกจ %s', + 'console_question' => 'ติดตั้งคอมโพเนนต์คอนโซล webman/console', + 'db_question' => 'คอมโพเนนต์ฐานข้อมูล', + 'db_none' => 'ไม่ติดตั้ง', + 'db_invalid' => 'กรุณาป้อนตัวเลือกที่ถูกต้อง', + 'redis_question' => 'ติดตั้งคอมโพเนนต์ Redis webman/redis', + 'events_note' => ' (Redis ต้องการ illuminate/events รวมไว้โดยอัตโนมัติ)', + 'validation_question' => 'ติดตั้งคอมโพเนนต์ตรวจสอบ webman/validation', + 'template_question' => 'เทมเพลตเอนจิน', + 'template_none' => 'ไม่ติดตั้ง', + 'no_components' => 'ไม่ได้เลือกคอมโพเนนต์เสริม', + 'installing' => 'กำลังติดตั้ง:', + 'running' => 'กำลังดำเนินการ:', + 'error_install' => 'ติดตั้งล้มเหลว ลองด้วยตนเอง: composer require %s', + 'done' => 'คอมโพเนนต์เสริมติดตั้งเรียบร้อยแล้ว', + 'summary_locale' => 'ภาษา: %s', + 'summary_timezone' => 'เขตเวลา: %s', + ], + ]; + + // --- Interrupt message (Ctrl+C) --- + + private const INTERRUPTED_MESSAGES = [ + 'zh_CN' => '安装中断,可运行 composer setup-webman 可重新设置。', + 'zh_TW' => '安裝中斷,可運行 composer setup-webman 重新設置。', + 'en' => 'Setup interrupted. Run "composer setup-webman" to restart setup.', + 'ja' => 'セットアップが中断されました。composer setup-webman を実行して再設定できます。', + 'ko' => '설치가 중단되었습니다. composer setup-webman 을 실행하여 다시 설정할 수 있습니다.', + 'fr' => 'Installation interrompue. Exécutez « composer setup-webman » pour recommencer.', + 'de' => 'Einrichtung abgebrochen. Führen Sie "composer setup-webman" aus, um neu zu starten.', + 'es' => 'Instalación interrumpida. Ejecute "composer setup-webman" para reiniciar.', + 'pt_BR' => 'Instalação interrompida. Execute "composer setup-webman" para reiniciar.', + 'ru' => 'Установка прервана. Выполните «composer setup-webman» для повторной настройки.', + 'vi' => 'Cài đặt bị gián đoạn. Chạy "composer setup-webman" để cài đặt lại.', + 'tr' => 'Kurulum kesildi. Yeniden kurmak için "composer setup-webman" komutunu çalıştırın.', + 'id' => 'Instalasi terganggu. Jalankan "composer setup-webman" untuk mengatur ulang.', + 'th' => 'การติดตั้งถูกขัดจังหวะ เรียกใช้ "composer setup-webman" เพื่อตั้งค่าใหม่', + ]; + + // --- Signal handling state --- + + /** @var string|null Saved stty mode for terminal restoration on interrupt */ + private static ?string $sttyMode = null; + + /** @var string Current locale for interrupt message */ + private static string $interruptLocale = 'en'; + + // ═══════════════════════════════════════════════════════════════ + // Entry + // ═══════════════════════════════════════════════════════════════ + + public static function run(Event $event): void + { + $io = $event->getIO(); + + // Non-interactive mode: use English for skip message + if (!$io->isInteractive()) { + $io->write('' . self::MESSAGES['en']['skip'] . ''); + return; + } + + try { + self::doRun($event, $io); + } catch (\Throwable $e) { + $io->writeError(''); + $io->writeError('Setup wizard error: ' . $e->getMessage() . ''); + $io->writeError('Run "composer setup-webman" to retry.'); + } + } + + private static function doRun(Event $event, IOInterface $io): void + { + $io->write(''); + + // Register Ctrl+C handler + self::registerInterruptHandler(); + + // Banner title (must be before locale selection) + self::renderTitle(); + + // 1. Locale selection + $locale = self::askLocale($io); + self::$interruptLocale = $locale; + $defaultTimezone = self::LOCALE_DEFAULT_TIMEZONES[$locale] ?? 'UTC'; + $msg = fn(string $key, string ...$args): string => + empty($args) ? self::MESSAGES[$locale][$key] : sprintf(self::MESSAGES[$locale][$key], ...$args); + + // Write locale config (update when not default) + if ($locale !== 'zh_CN') { + self::updateConfig($event, 'config/translation.php', "'locale'", $locale); + } + + $io->write(''); + $io->write(''); + + // 2. Timezone selection (default by locale) + $timezone = self::askTimezone($io, $msg, $defaultTimezone); + if ($timezone !== 'Asia/Shanghai') { + self::updateConfig($event, 'config/app.php', "'default_timezone'", $timezone); + } + + // 3. Optional components + $packages = self::askComponents($io, $msg); + + // 4. Remove unselected components + $removePackages = self::askRemoveComponents($event, $packages, $io, $msg); + + // 5. Summary + $io->write(''); + $io->write('─────────────────────────────────────'); + $io->write('' . $msg('summary_locale', self::LOCALE_LABELS[$locale]) . ''); + $io->write('' . $msg('summary_timezone', $timezone) . ''); + + // Remove unselected packages first to avoid dependency conflicts + if ($removePackages !== []) { + $io->write(''); + $io->write('' . $msg('removing') . ''); + + $secondaryPackages = [ + self::PACKAGE_ILLUMINATE_EVENTS, + self::PACKAGE_ILLUMINATE_PAGINATION, + self::PACKAGE_SYMFONY_VAR_DUMPER, + ]; + $displayRemovePackages = array_diff($removePackages, $secondaryPackages); + foreach ($displayRemovePackages as $pkg) { + $io->write(' - ' . $pkg); + } + $io->write(''); + self::runComposerRemove($removePackages, $io, $msg); + } + + // Then install selected packages + if ($packages !== []) { + $io->write(''); + $io->write('' . $msg('installing') . ' ' . implode(', ', $packages)); + $io->write(''); + self::runComposerRequire($packages, $io, $msg); + } elseif ($removePackages === []) { + $io->write('' . $msg('no_components') . ''); + } + } + + private static function renderTitle(): void + { + $output = new ConsoleOutput(); + $terminalWidth = (new Terminal())->getWidth(); + if ($terminalWidth <= 0) { + $terminalWidth = 80; + } + + $text = ' ' . self::SETUP_TITLE . ' '; + $minBoxWidth = 44; + $maxBoxWidth = min($terminalWidth, 96); + $boxWidth = min($maxBoxWidth, max($minBoxWidth, mb_strwidth($text) + 10)); + + $innerWidth = $boxWidth - 2; + $textWidth = mb_strwidth($text); + $pad = max(0, $innerWidth - $textWidth); + $left = intdiv($pad, 2); + $right = $pad - $left; + $line2 = '│' . str_repeat(' ', $left) . $text . str_repeat(' ', $right) . '│'; + $line1 = '┌' . str_repeat('─', $innerWidth) . '┐'; + $line3 = '└' . str_repeat('─', $innerWidth) . '┘'; + + $output->writeln(''); + $output->writeln('' . $line1 . ''); + $output->writeln('' . $line2 . ''); + $output->writeln('' . $line3 . ''); + $output->writeln(''); + } + + // ═══════════════════════════════════════════════════════════════ + // Signal handling (Ctrl+C) + // ═══════════════════════════════════════════════════════════════ + + /** + * Register Ctrl+C (SIGINT) handler to show a friendly message on interrupt. + * Gracefully skipped when the required extensions are unavailable. + */ + private static function registerInterruptHandler(): void + { + // Unix/Linux/Mac: pcntl extension with async signals for immediate delivery + /*if (function_exists('pcntl_async_signals') && function_exists('pcntl_signal')) { + pcntl_async_signals(true); + pcntl_signal(\SIGINT, [self::class, 'handleInterrupt']); + return; + }*/ + + // Windows: sapi ctrl handler (PHP >= 7.4) + if (function_exists('sapi_windows_set_ctrl_handler')) { + sapi_windows_set_ctrl_handler(static function (int $event) { + if ($event === \PHP_WINDOWS_EVENT_CTRL_C) { + self::handleInterrupt(); + } + }); + } + } + + /** + * Handle Ctrl+C: restore terminal, show tip, then exit. + */ + private static function handleInterrupt(): void + { + // Restore terminal if in raw mode + if (self::$sttyMode !== null && function_exists('shell_exec')) { + @shell_exec('stty ' . self::$sttyMode); + self::$sttyMode = null; + } + + $output = new ConsoleOutput(); + $output->writeln(''); + $output->writeln('' . (self::INTERRUPTED_MESSAGES[self::$interruptLocale] ?? self::INTERRUPTED_MESSAGES['en']) . ''); + exit(1); + } + + // ═══════════════════════════════════════════════════════════════ + // Interactive Menu System + // ═══════════════════════════════════════════════════════════════ + + /** + * Check if terminal supports interactive features (arrow keys, ANSI colors). + */ + private static function supportsInteractive(): bool + { + return function_exists('shell_exec') && Terminal::hasSttyAvailable(); + } + + /** + * Display a selection menu with arrow key navigation (if supported) or text input fallback. + * + * @param IOInterface $io Composer IO + * @param string $title Menu title + * @param array $items Indexed array of ['tag' => string, 'label' => string] + * @param int $default Default selected index (0-based) + * @return int Selected index + */ + private static function selectMenu(IOInterface $io, string $title, array $items, int $default = 0): int + { + // Append localized "default" hint to avoid ambiguity + // (Template should contain a single %s placeholder for the default tag.) + $defaultHintTemplate = null; + if (isset(self::MESSAGES[self::$interruptLocale]['default_choice'])) { + $defaultHintTemplate = self::MESSAGES[self::$interruptLocale]['default_choice']; + } + + $defaultTag = $items[$default]['tag'] ?? ''; + if ($defaultHintTemplate && $defaultTag !== '') { + $title .= sprintf($defaultHintTemplate, $defaultTag); + } elseif ($defaultTag !== '') { + // Fallback for early menus (e.g. locale selection) before locale is chosen. + $title .= sprintf(' (default %s)', $defaultTag); + } + + if (self::supportsInteractive()) { + return self::arrowKeySelect($title, $items, $default); + } + + return self::fallbackSelect($io, $title, $items, $default); + } + + /** + * Display a yes/no confirmation as a selection menu. + * + * @param IOInterface $io Composer IO + * @param string $title Menu title + * @param bool $default Default value (true = yes) + * @return bool User's choice + */ + private static function confirmMenu(IOInterface $io, string $title, bool $default = true): bool + { + $locale = self::$interruptLocale; + $yes = self::MESSAGES[$locale]['yes'] ?? self::MESSAGES['en']['yes'] ?? 'yes'; + $no = self::MESSAGES[$locale]['no'] ?? self::MESSAGES['en']['no'] ?? 'no'; + $items = $default + ? [['tag' => 'Y', 'label' => $yes], ['tag' => 'n', 'label' => $no]] + : [['tag' => 'y', 'label' => $yes], ['tag' => 'N', 'label' => $no]]; + $defaultIndex = $default ? 0 : 1; + + return self::selectMenu($io, $title, $items, $defaultIndex) === 0; + } + + /** + * Interactive select with arrow key navigation, manual input and ANSI reverse-video highlighting. + * Input area and option list highlighting are bidirectionally linked. + * Requires stty (Unix-like terminals). + */ + private static function arrowKeySelect(string $title, array $items, int $default): int + { + $output = new ConsoleOutput(); + $count = count($items); + $selected = $default; + + $maxTagWidth = max(array_map(fn(array $item) => mb_strlen($item['tag']), $items)); + $defaultTag = $items[$default]['tag']; + $input = $defaultTag; + + // Print title and initial options + $output->writeln(''); + $output->writeln('' . $title . ''); + self::drawMenuItems($output, $items, $selected, $maxTagWidth); + $output->write('> ' . $input); + + // Enter raw mode + self::$sttyMode = shell_exec('stty -g'); + shell_exec('stty -icanon -echo'); + + try { + while (!feof(STDIN)) { + $c = fread(STDIN, 1); + + if (false === $c || '' === $c) { + break; + } + + // ── Backspace ── + if ("\177" === $c || "\010" === $c) { + if ('' !== $input) { + $input = mb_substr($input, 0, -1); + } + $selected = self::findItemByTag($items, $input); + $output->write("\033[{$count}A"); + self::drawMenuItems($output, $items, $selected, $maxTagWidth); + $output->write("\033[2K\r> " . $input); + continue; + } + + // ── Escape sequences (arrow keys) ── + if ("\033" === $c) { + $seq = fread(STDIN, 2); + if (isset($seq[1])) { + $changed = false; + if ('A' === $seq[1]) { // Up + $selected = ($selected <= 0 ? $count : $selected) - 1; + $changed = true; + } elseif ('B' === $seq[1]) { // Down + $selected = ($selected + 1) % $count; + $changed = true; + } + if ($changed) { + // Sync input with selected item's tag + $input = $items[$selected]['tag']; + $output->write("\033[{$count}A"); + self::drawMenuItems($output, $items, $selected, $maxTagWidth); + $output->write("\033[2K\r> " . $input); + } + } + continue; + } + + // ── Enter: confirm selection ── + if ("\n" === $c || "\r" === $c) { + if ($selected < 0) { + $selected = $default; + } + $output->write("\033[2K\r> " . $items[$selected]['tag'] . ' ' . $items[$selected]['label'] . ''); + $output->writeln(''); + break; + } + + // ── Ignore other control characters ── + if (ord($c) < 32) { + continue; + } + + // ── Printable character (with UTF-8 multi-byte support) ── + if ("\x80" <= $c) { + $extra = ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3]; + $c .= fread(STDIN, $extra[$c & "\xF0"] ?? 0); + } + $input .= $c; + $selected = self::findItemByTag($items, $input); + $output->write("\033[{$count}A"); + self::drawMenuItems($output, $items, $selected, $maxTagWidth); + $output->write("\033[2K\r> " . $input); + } + } finally { + if (self::$sttyMode !== null) { + shell_exec('stty ' . self::$sttyMode); + self::$sttyMode = null; + } + } + + return $selected < 0 ? $default : $selected; + } + + /** + * Fallback select for terminals without stty support. Uses plain text input. + */ + private static function fallbackSelect(IOInterface $io, string $title, array $items, int $default): int + { + $maxTagWidth = max(array_map(fn(array $item) => mb_strlen($item['tag']), $items)); + $defaultTag = $items[$default]['tag']; + + $io->write(''); + $io->write('' . $title . ''); + foreach ($items as $item) { + $tag = str_pad($item['tag'], $maxTagWidth); + $io->write(" [$tag] " . $item['label']); + } + + while (true) { + $io->write('> ', false); + $line = fgets(STDIN); + if ($line === false) { + return $default; + } + $answer = trim($line); + + if ($answer === '') { + $io->write('> ' . $items[$default]['tag'] . ' ' . $items[$default]['label'] . ''); + return $default; + } + + // Match by tag (case-insensitive) + foreach ($items as $i => $item) { + if (strcasecmp($item['tag'], $answer) === 0) { + $io->write('> ' . $items[$i]['tag'] . ' ' . $items[$i]['label'] . ''); + return $i; + } + } + } + } + + /** + * Render menu items with optional ANSI reverse-video highlighting for the selected item. + * When $selected is -1, no item is highlighted. + */ + private static function drawMenuItems(ConsoleOutput $output, array $items, int $selected, int $maxTagWidth): void + { + foreach ($items as $i => $item) { + $tag = str_pad($item['tag'], $maxTagWidth); + $line = " [$tag] " . $item['label']; + if ($i === $selected) { + $output->writeln("\033[2K\r\033[7m" . $line . "\033[0m"); + } else { + $output->writeln("\033[2K\r" . $line); + } + } + } + + /** + * Find item index by tag (case-insensitive exact match). + * Returns -1 if no match found or input is empty. + */ + private static function findItemByTag(array $items, string $input): int + { + if ($input === '') { + return -1; + } + foreach ($items as $i => $item) { + if (strcasecmp($item['tag'], $input) === 0) { + return $i; + } + } + return -1; + } + + // ═══════════════════════════════════════════════════════════════ + // Locale selection + // ═══════════════════════════════════════════════════════════════ + + private static function askLocale(IOInterface $io): string + { + $locales = array_keys(self::LOCALE_LABELS); + $items = []; + foreach ($locales as $i => $code) { + $items[] = ['tag' => (string) $i, 'label' => self::LOCALE_LABELS[$code] . " ($code)"]; + } + + $selected = self::selectMenu( + $io, + '语言 / Language / 言語 / 언어', + $items, + 0 + ); + + return $locales[$selected]; + } + + // ═══════════════════════════════════════════════════════════════ + // Timezone selection + // ═══════════════════════════════════════════════════════════════ + + private static function askTimezone(IOInterface $io, callable $msg, string $default): string + { + if (self::supportsInteractive()) { + return self::askTimezoneAutocomplete($msg, $default); + } + + return self::askTimezoneSelect($io, $msg, $default); + } + + /** + * Option A: when stty is available, custom character-by-character autocomplete + * (case-insensitive, substring match). Interaction: type to filter, hint on right; + * ↑↓ change candidate, Tab accept, Enter confirm; empty input = use default. + */ + private static function askTimezoneAutocomplete(callable $msg, string $default): string + { + $allTimezones = \DateTimeZone::listIdentifiers(); + $output = new ConsoleOutput(); + $cursor = new Cursor($output); + + $output->writeln(''); + $output->writeln('' . $msg('timezone_title', $default) . ''); + $output->writeln($msg('timezone_help')); + $output->write('> '); + + self::$sttyMode = shell_exec('stty -g'); + shell_exec('stty -icanon -echo'); + + // Auto-fill default timezone in the input area; user can edit it directly. + $input = $default; + $output->write($input); + + $ofs = 0; + $matches = self::filterTimezones($allTimezones, $input); + if (!empty($matches)) { + $hint = $matches[$ofs % count($matches)]; + // Avoid duplicating hint when input already fully matches the only candidate. + if (!(count($matches) === 1 && $hint === $input)) { + $cursor->clearLineAfter(); + $cursor->savePosition(); + $output->write(' ' . $hint . ''); + if (count($matches) > 1) { + $output->write(' (' . count($matches) . ' matches, ↑↓)'); + } + $cursor->restorePosition(); + } + } + + try { + while (!feof(STDIN)) { + $c = fread(STDIN, 1); + + if (false === $c || '' === $c) { + break; + } + + // ── Backspace ── + if ("\177" === $c || "\010" === $c) { + if ('' !== $input) { + $lastChar = mb_substr($input, -1); + $input = mb_substr($input, 0, -1); + $cursor->moveLeft(max(1, mb_strwidth($lastChar))); + } + $ofs = 0; + + // ── Escape sequences (arrows) ── + } elseif ("\033" === $c) { + $seq = fread(STDIN, 2); + if (isset($seq[1]) && !empty($matches)) { + if ('A' === $seq[1]) { + $ofs = ($ofs - 1 + count($matches)) % count($matches); + } elseif ('B' === $seq[1]) { + $ofs = ($ofs + 1) % count($matches); + } + } + + // ── Tab: accept current match ── + } elseif ("\t" === $c) { + if (isset($matches[$ofs])) { + self::replaceInput($output, $cursor, $input, $matches[$ofs]); + $input = $matches[$ofs]; + $matches = []; + } + $cursor->clearLineAfter(); + continue; + + // ── Enter: confirm ── + } elseif ("\n" === $c || "\r" === $c) { + if (isset($matches[$ofs])) { + self::replaceInput($output, $cursor, $input, $matches[$ofs]); + $input = $matches[$ofs]; + } + if ($input === '') { + $input = $default; + } + // Re-render user input with style + $cursor->moveToColumn(1); + $cursor->clearLine(); + $output->write('> ' . $input . ''); + $output->writeln(''); + break; + + // ── Other control chars: ignore ── + } elseif (ord($c) < 32) { + continue; + + // ── Printable character ── + } else { + if ("\x80" <= $c) { + $extra = ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3]; + $c .= fread(STDIN, $extra[$c & "\xF0"] ?? 0); + } + $output->write($c); + $input .= $c; + $ofs = 0; + } + + // Update match list + $matches = self::filterTimezones($allTimezones, $input); + + // Show autocomplete hint + $cursor->clearLineAfter(); + if (!empty($matches)) { + $hint = $matches[$ofs % count($matches)]; + $cursor->savePosition(); + $output->write(' ' . $hint . ''); + if (count($matches) > 1) { + $output->write(' (' . count($matches) . ' matches, ↑↓)'); + } + $cursor->restorePosition(); + } + } + } finally { + if (self::$sttyMode !== null) { + shell_exec('stty ' . self::$sttyMode); + self::$sttyMode = null; + } + } + + $result = '' === $input ? $default : $input; + + if (!in_array($result, $allTimezones, true)) { + $output->writeln('' . $msg('timezone_invalid', $default) . ''); + return $default; + } + + return $result; + } + + /** + * Clear current input and replace with new text. + */ + private static function replaceInput(ConsoleOutput $output, Cursor $cursor, string $oldInput, string $newInput): void + { + if ('' !== $oldInput) { + $cursor->moveLeft(mb_strwidth($oldInput)); + } + $cursor->clearLineAfter(); + $output->write($newInput); + } + + /** + * Case-insensitive substring match for timezones. + */ + private static function filterTimezones(array $timezones, string $input): array + { + if ('' === $input) { + return []; + } + $lower = mb_strtolower($input); + return array_values(array_filter( + $timezones, + fn(string $tz) => str_contains(mb_strtolower($tz), $lower) + )); + } + + /** + * Find an exact timezone match (case-insensitive). + * Returns the correctly-cased system timezone name, or null if not found. + */ + private static function findExactTimezone(array $allTimezones, string $input): ?string + { + $lower = mb_strtolower($input); + foreach ($allTimezones as $tz) { + if (mb_strtolower($tz) === $lower) { + return $tz; + } + } + return null; + } + + /** + * Search timezones by keyword (substring) and similarity. + * Returns combined results: substring matches first, then similarity matches (>=50%). + * + * @param string[] $allTimezones All valid timezone identifiers + * @param string $keyword User input to search for + * @param int $limit Maximum number of results + * @return string[] Matched timezone identifiers + */ + private static function searchTimezones(array $allTimezones, string $keyword, int $limit = 15): array + { + // 1. Substring matches (higher priority) + $substringMatches = self::filterTimezones($allTimezones, $keyword); + if (count($substringMatches) >= $limit) { + return array_slice($substringMatches, 0, $limit); + } + + // 2. Similarity matches for remaining slots (normalized: strip _ and /) + $substringSet = array_flip($substringMatches); + $normalizedKeyword = str_replace(['_', '/'], ' ', mb_strtolower($keyword)); + $similarityMatches = []; + + foreach ($allTimezones as $tz) { + if (isset($substringSet[$tz])) { + continue; + } + $parts = explode('/', $tz); + $city = str_replace('_', ' ', mb_strtolower(end($parts))); + $normalizedTz = str_replace(['_', '/'], ' ', mb_strtolower($tz)); + + similar_text($normalizedKeyword, $city, $cityPercent); + similar_text($normalizedKeyword, $normalizedTz, $fullPercent); + + $bestPercent = max($cityPercent, $fullPercent); + if ($bestPercent >= 50.0) { + $similarityMatches[] = ['tz' => $tz, 'score' => $bestPercent]; + } + } + + usort($similarityMatches, fn(array $a, array $b) => $b['score'] <=> $a['score']); + + $results = $substringMatches; + foreach ($similarityMatches as $item) { + $results[] = $item['tz']; + if (count($results) >= $limit) { + break; + } + } + + return $results; + } + + /** + * Option B: when stty is not available (e.g. Windows), keyword search with numbered list. + * Flow: enter timezone/keyword → exact match uses it directly; otherwise show + * numbered results (substring + similarity) → pick by number or refine keyword. + */ + private static function askTimezoneSelect(IOInterface $io, callable $msg, string $default): string + { + $allTimezones = \DateTimeZone::listIdentifiers(); + + $io->write(''); + $io->write('' . $msg('timezone_title', $default) . ''); + $io->write($msg('timezone_input_prompt')); + + /** @var string[]|null Currently displayed search result list */ + $currentList = null; + + while (true) { + $io->write('> ', false); + $line = fgets(STDIN); + if ($line === false) { + return $default; + } + $answer = trim($line); + + // Empty input → use default + if ($answer === '') { + $io->write('> ' . $default . ''); + return $default; + } + + // If a numbered list is displayed and input is a pure number + if ($currentList !== null && ctype_digit($answer)) { + $idx = (int) $answer; + if (isset($currentList[$idx])) { + $io->write('> ' . $currentList[$idx] . ''); + return $currentList[$idx]; + } + $io->write('' . $msg('timezone_invalid_index') . ''); + continue; + } + + // Exact case-insensitive match → return the correctly-cased system value + $exact = self::findExactTimezone($allTimezones, $answer); + if ($exact !== null) { + $io->write('> ' . $exact . ''); + return $exact; + } + + // Keyword + similarity search + $results = self::searchTimezones($allTimezones, $answer); + + if (empty($results)) { + $io->write('' . $msg('timezone_no_match') . ''); + $currentList = null; + continue; + } + + // Single result → use it directly + if (count($results) === 1) { + $io->write('> ' . $results[0] . ''); + return $results[0]; + } + + // Display numbered list + $currentList = $results; + $padWidth = strlen((string) (count($results) - 1)); + foreach ($results as $i => $tz) { + $io->write(' [' . str_pad((string) $i, $padWidth) . '] ' . $tz); + } + $io->write($msg('timezone_pick_prompt')); + } + } + + // ═══════════════════════════════════════════════════════════════ + // Optional component selection + // ═══════════════════════════════════════════════════════════════ + + private static function askComponents(IOInterface $io, callable $msg): array + { + $packages = []; + $addPackage = static function (string $package) use (&$packages, $io, $msg): void { + if (in_array($package, $packages, true)) { + return; + } + $packages[] = $package; + $io->write($msg('adding_package', '' . $package . '')); + }; + + // Console (default: yes) + if (self::confirmMenu($io, $msg('console_question'), true)) { + $addPackage(self::PACKAGE_CONSOLE); + } + + // Database + $dbItems = [ + ['tag' => '0', 'label' => $msg('db_none')], + ['tag' => '1', 'label' => 'webman/database'], + ['tag' => '2', 'label' => 'webman/think-orm'], + ['tag' => '3', 'label' => 'webman/database && webman/think-orm'], + ]; + $dbChoice = self::selectMenu($io, $msg('db_question'), $dbItems, 0); + if ($dbChoice === 1) { + $addPackage(self::PACKAGE_DATABASE); + } elseif ($dbChoice === 2) { + $addPackage(self::PACKAGE_THINK_ORM); + } elseif ($dbChoice === 3) { + $addPackage(self::PACKAGE_DATABASE); + $addPackage(self::PACKAGE_THINK_ORM); + } + + // If webman/database is selected, add required dependencies automatically + if (in_array(self::PACKAGE_DATABASE, $packages, true)) { + $addPackage(self::PACKAGE_ILLUMINATE_PAGINATION); + $addPackage(self::PACKAGE_ILLUMINATE_EVENTS); + $addPackage(self::PACKAGE_SYMFONY_VAR_DUMPER); + } + + // Redis (default: no) + if (self::confirmMenu($io, $msg('redis_question'), false)) { + $addPackage(self::PACKAGE_REDIS); + $addPackage(self::PACKAGE_ILLUMINATE_EVENTS); + } + + // Validation (default: no) + if (self::confirmMenu($io, $msg('validation_question'), false)) { + $addPackage(self::PACKAGE_VALIDATION); + } + + // Template engine + $tplItems = [ + ['tag' => '0', 'label' => $msg('template_none')], + ['tag' => '1', 'label' => 'webman/blade'], + ['tag' => '2', 'label' => 'twig/twig'], + ['tag' => '3', 'label' => 'topthink/think-template'], + ]; + $tplChoice = self::selectMenu($io, $msg('template_question'), $tplItems, 0); + if ($tplChoice === 1) { + $addPackage(self::PACKAGE_BLADE); + } elseif ($tplChoice === 2) { + $addPackage(self::PACKAGE_TWIG); + } elseif ($tplChoice === 3) { + $addPackage(self::PACKAGE_THINK_TEMPLATE); + } + + return $packages; + } + + // ═══════════════════════════════════════════════════════════════ + // Config file update + // ═══════════════════════════════════════════════════════════════ + + /** + * Update a config value like 'key' => 'old_value' in the given file. + */ + private static function updateConfig(Event $event, string $relativePath, string $key, string $newValue): void + { + $root = dirname($event->getComposer()->getConfig()->get('vendor-dir')); + $file = $root . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relativePath); + if (!is_readable($file)) { + return; + } + $content = file_get_contents($file); + if ($content === false) { + return; + } + $pattern = '/' . preg_quote($key, '/') . "\s*=>\s*'[^']*'/"; + $replacement = $key . " => '" . $newValue . "'"; + $newContent = preg_replace($pattern, $replacement, $content); + if ($newContent !== null && $newContent !== $content) { + file_put_contents($file, $newContent); + } + } + + // ═══════════════════════════════════════════════════════════════ + // Composer require + // ═══════════════════════════════════════════════════════════════ + + private static function runComposerRequire(array $packages, IOInterface $io, callable $msg): void + { + $io->write('' . $msg('running') . ' composer require ' . implode(' ', $packages)); + $io->write(''); + + $code = self::runComposerCommand('require', $packages); + + if ($code !== 0) { + $io->writeError('' . $msg('error_install', implode(' ', $packages)) . ''); + } else { + $io->write('' . $msg('done') . ''); + } + } + + private static function askRemoveComponents(Event $event, array $selectedPackages, IOInterface $io, callable $msg): array + { + $requires = $event->getComposer()->getPackage()->getRequires(); + $allOptionalPackages = [ + self::PACKAGE_CONSOLE, + self::PACKAGE_DATABASE, + self::PACKAGE_THINK_ORM, + self::PACKAGE_REDIS, + self::PACKAGE_ILLUMINATE_EVENTS, + self::PACKAGE_ILLUMINATE_PAGINATION, + self::PACKAGE_SYMFONY_VAR_DUMPER, + self::PACKAGE_VALIDATION, + self::PACKAGE_BLADE, + self::PACKAGE_TWIG, + self::PACKAGE_THINK_TEMPLATE, + ]; + + $secondaryPackages = [ + self::PACKAGE_ILLUMINATE_EVENTS, + self::PACKAGE_ILLUMINATE_PAGINATION, + self::PACKAGE_SYMFONY_VAR_DUMPER, + ]; + + $installedOptionalPackages = []; + foreach ($allOptionalPackages as $pkg) { + if (isset($requires[$pkg])) { + $installedOptionalPackages[] = $pkg; + } + } + + $allPackagesToRemove = array_diff($installedOptionalPackages, $selectedPackages); + + if (count($allPackagesToRemove) === 0) { + return []; + } + + $displayPackagesToRemove = array_diff($allPackagesToRemove, $secondaryPackages); + + if (count($displayPackagesToRemove) === 0) { + return $allPackagesToRemove; + } + + $pkgListStr = ""; + foreach ($displayPackagesToRemove as $pkg) { + $pkgListStr .= "\n - {$pkg}"; + } + $pkgListStr .= "\n"; + + $title = '' . $msg('remove_package_question', '') . '' . $pkgListStr; + if (self::confirmMenu($io, $title, false)) { + return $allPackagesToRemove; + } + + return []; + } + + private static function runComposerRemove(array $packages, IOInterface $io, callable $msg): void + { + $io->write('' . $msg('running') . ' composer remove ' . implode(' ', $packages)); + $io->write(''); + + $code = self::runComposerCommand('remove', $packages); + + if ($code !== 0) { + $io->writeError('' . $msg('error_remove', implode(' ', $packages)) . ''); + } else { + $io->write('' . $msg('done_remove') . ''); + } + } + + /** + * Run a Composer command (require/remove) in-process via Composer's Application API. + * No shell execution functions needed — works even when passthru/exec/shell_exec are disabled. + */ + private static function runComposerCommand(string $command, array $packages): int + { + try { + // Already inside a user-initiated Composer session — suppress duplicate root/superuser warnings + $_SERVER['COMPOSER_ALLOW_SUPERUSER'] = '1'; + if (function_exists('putenv')) { + putenv('COMPOSER_ALLOW_SUPERUSER=1'); + } + + $application = new ComposerApplication(); + $application->setAutoExit(false); + + return $application->run( + new ArrayInput([ + 'command' => $command, + 'packages' => $packages, + '--no-interaction' => true, + '--update-with-all-dependencies' => true, + ]), + new ConsoleOutput() + ); + } catch (\Throwable) { + return 1; + } + } +} diff --git a/support/bootstrap.php b/support/bootstrap.php new file mode 100644 index 0000000..d913def --- /dev/null +++ b/support/bootstrap.php @@ -0,0 +1,139 @@ + + * @copyright walkor + * @link http://www.workerman.net/ + * @license http://www.opensource.org/licenses/mit-license.php MIT License + */ + +use Dotenv\Dotenv; +use support\Log; +use Webman\Bootstrap; +use Webman\Config; +use Webman\Middleware; +use Webman\Route; +use Webman\Util; +use Workerman\Events\Select; +use Workerman\Worker; + +$worker = $worker ?? null; + +if (empty(Worker::$eventLoopClass)) { + Worker::$eventLoopClass = Select::class; +} + +set_error_handler(function ($level, $message, $file = '', $line = 0) { + if (error_reporting() & $level) { + throw new ErrorException($message, 0, $level, $file, $line); + } +}); + +if ($worker) { + register_shutdown_function(function ($startTime) { + if (time() - $startTime <= 0.1) { + sleep(1); + } + }, time()); +} + +if (class_exists('Dotenv\Dotenv') && file_exists(base_path(false) . '/.env')) { + if (method_exists('Dotenv\Dotenv', 'createUnsafeMutable')) { + Dotenv::createUnsafeMutable(base_path(false))->load(); + } else { + Dotenv::createMutable(base_path(false))->load(); + } +} + +Config::clear(); +support\App::loadAllConfig(['route']); +if ($timezone = config('app.default_timezone')) { + date_default_timezone_set($timezone); +} + +foreach (config('autoload.files', []) as $file) { + include_once $file; +} +foreach (config('plugin', []) as $firm => $projects) { + foreach ($projects as $name => $project) { + if (!is_array($project)) { + continue; + } + foreach ($project['autoload']['files'] ?? [] as $file) { + include_once $file; + } + } + foreach ($projects['autoload']['files'] ?? [] as $file) { + include_once $file; + } +} + +Middleware::load(config('middleware', [])); +foreach (config('plugin', []) as $firm => $projects) { + foreach ($projects as $name => $project) { + if (!is_array($project) || $name === 'static') { + continue; + } + Middleware::load($project['middleware'] ?? []); + } + Middleware::load($projects['middleware'] ?? [], $firm); + if ($staticMiddlewares = config("plugin.$firm.static.middleware")) { + Middleware::load(['__static__' => $staticMiddlewares], $firm); + } +} +Middleware::load(['__static__' => config('static.middleware', [])]); + +foreach (config('bootstrap', []) as $className) { + if (!class_exists($className)) { + $log = "Warning: Class $className setting in config/bootstrap.php not found\r\n"; + echo $log; + Log::error($log); + continue; + } + /** @var Bootstrap $className */ + $className::start($worker); +} + +foreach (config('plugin', []) as $firm => $projects) { + foreach ($projects as $name => $project) { + if (!is_array($project)) { + continue; + } + foreach ($project['bootstrap'] ?? [] as $className) { + if (!class_exists($className)) { + $log = "Warning: Class $className setting in config/plugin/$firm/$name/bootstrap.php not found\r\n"; + echo $log; + Log::error($log); + continue; + } + /** @var Bootstrap $className */ + $className::start($worker); + } + } + foreach ($projects['bootstrap'] ?? [] as $className) { + /** @var string $className */ + if (!class_exists($className)) { + $log = "Warning: Class $className setting in plugin/$firm/config/bootstrap.php not found\r\n"; + echo $log; + Log::error($log); + continue; + } + /** @var Bootstrap $className */ + $className::start($worker); + } +} + +$directory = base_path() . '/plugin'; +$paths = [config_path()]; +foreach (Util::scanDir($directory) as $path) { + if (is_dir($path = "$path/config")) { + $paths[] = $path; + } +} +Route::load($paths); + diff --git a/support/bootstrap/ModuleInit.php b/support/bootstrap/ModuleInit.php new file mode 100644 index 0000000..3b41a93 --- /dev/null +++ b/support/bootstrap/ModuleInit.php @@ -0,0 +1,96 @@ +AppInit(); + } catch (\Throwable $e) { + // 模块 AppInit 异常不阻断启动,仅记录 + if (class_exists(\support\Log::class)) { + \support\Log::warning('[ModuleInit] ' . $uid . ': ' . $e->getMessage()); + } + } + } + } + } + + /** + * 获取已安装模块列表(与 Server::installedList 逻辑一致) + */ + protected static function installedList(string $dir): array + { + $installedDir = @scandir($dir); + if ($installedDir === false) { + return []; + } + $installedList = []; + foreach ($installedDir as $item) { + if ($item === '.' || $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; + } + + /** + * 读取模块 info.ini + */ + protected static function getIni(string $dir): array + { + $infoFile = $dir . 'info.ini'; + if (!is_file($infoFile)) { + return []; + } + $info = @parse_ini_file($infoFile, true, INI_SCANNER_TYPED); + return is_array($info) ? $info : []; + } + + /** + * 获取模块 Event 类命名空间(与 Server::getClass 逻辑一致) + */ + protected static function getModuleEventClass(string $uid): ?string + { + $name = function_exists('parse_name') ? parse_name($uid) : str_replace('-', '_', $uid); + $class = function_exists('parse_name') ? parse_name($name, 1) : ucfirst(str_replace('_', '', ucwords($name, '_'))); + $namespace = '\\modules\\' . $name . '\\' . $class; + return class_exists($namespace) ? $namespace : null; + } +} diff --git a/support/bootstrap/ValidateInit.php b/support/bootstrap/ValidateInit.php new file mode 100644 index 0000000..a756a5b --- /dev/null +++ b/support/bootstrap/ValidateInit.php @@ -0,0 +1,22 @@ +setDb(Db::connect()); + }); + } +} 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..73f4d6c --- /dev/null +++ b/web/.env.development @@ -0,0 +1,8 @@ +# 本地环境 +ENV = 'development' + +# base路径 +VITE_BASE_PATH = './' + +# 本地环境接口地址 - 用空字符串走同源,由 vite 代理到 8787,避免 CORS +VITE_AXIOS_BASE_URL = '' 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/mall/player.ts b/web/src/lang/backend/en/mall/player.ts new file mode 100644 index 0000000..c84f935 --- /dev/null +++ b/web/src/lang/backend/en/mall/player.ts @@ -0,0 +1,9 @@ +export default { + id: 'id', + username: 'username', + password: 'password', + create_time: 'create_time', + update_time: 'update_time', + score: 'score', + quickSearchFields: 'id', +} 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/mall/player.ts b/web/src/lang/backend/zh-cn/mall/player.ts new file mode 100644 index 0000000..ed43906 --- /dev/null +++ b/web/src/lang/backend/zh-cn/mall/player.ts @@ -0,0 +1,9 @@ +export default { + id: 'ID', + username: '用户名', + password: '密码', + create_time: '创建时间', + update_time: '修改时间', + score: '积分', + quickSearchFields: 'ID', +} 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..a5f79d7 --- /dev/null +++ b/web/src/layouts/backend/index.vue @@ -0,0 +1,120 @@ + + + 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..19d6fa6 --- /dev/null +++ b/web/src/utils/axios.ts @@ -0,0 +1,383 @@ +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和语言(确保每次请求使用当前语言,后端据此返回对应语言的 remark 等) + 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 + ;(config.headers as anyObj)['think-lang'] = useConfig().lang.defaultLang + } + + 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..6a35bde --- /dev/null +++ b/web/src/views/backend/crud/design.vue @@ -0,0 +1,2094 @@ + + + + + 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..5dbd260 --- /dev/null +++ b/web/src/views/backend/login.vue @@ -0,0 +1,293 @@ + + + + + diff --git a/web/src/views/backend/mall/player/index.vue b/web/src/views/backend/mall/player/index.vue new file mode 100644 index 0000000..5502f2b --- /dev/null +++ b/web/src/views/backend/mall/player/index.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/web/src/views/backend/mall/player/popupForm.vue b/web/src/views/backend/mall/player/popupForm.vue new file mode 100644 index 0000000..dd829c7 --- /dev/null +++ b/web/src/views/backend/mall/player/popupForm.vue @@ -0,0 +1,109 @@ + + + + + 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..cc763fe --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,55 @@ +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', + // 开发时把 /api、/admin 代理到 webman,避免跨域 + proxy: { + '/api': { target: 'http://localhost:8787', changeOrigin: true }, + '/admin': { target: 'http://localhost:8787', changeOrigin: true }, + }, + }, + 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 diff --git a/webman b/webman new file mode 100644 index 0000000..3f55062 --- /dev/null +++ b/webman @@ -0,0 +1,71 @@ +#!/usr/bin/env php +load(); + } else { + Dotenv::createMutable(run_path())->load(); + } +} + +$appConfig = require $appConfigFile; +if ($timezone = $appConfig['default_timezone'] ?? '') { + date_default_timezone_set($timezone); +} + +if ($errorReporting = $appConfig['error_reporting'] ?? '') { + error_reporting($errorReporting); +} + +if (!in_array($argv[1] ?? '', ['start', 'restart', 'stop', 'status', 'reload', 'connections'])) { + require_once __DIR__ . '/support/bootstrap.php'; +} else { + if (class_exists('Support\App')) { + Support\App::loadAllConfig(['route']); + } else { + Config::reload(config_path(), ['route', 'container']); + } +} + +$cli = new Command(); +$cli->setName('webman cli'); +$cli->installInternalCommands(); +if (is_dir($command_path = Util::guessPath(app_path(), '/command', true))) { + $cli->installCommands($command_path); +} + +foreach (config('plugin', []) as $firm => $projects) { + if (isset($projects['app'])) { + foreach (['', '/app'] as $app) { + if ($command_str = Util::guessPath(base_path() . "/plugin/$firm{$app}", 'command')) { + $command_path = base_path() . "/plugin/$firm{$app}/$command_str"; + $cli->installCommands($command_path, "plugin\\$firm" . str_replace('/', '\\', $app) . "\\$command_str"); + } + } + } + foreach ($projects as $name => $project) { + if (!is_array($project)) { + continue; + } + $project['command'] ??= []; + array_walk($project['command'], [$cli, 'createCommandInstance']); + } +} + +$cli->run(); diff --git a/windows.bat b/windows.bat new file mode 100644 index 0000000..f07ce53 --- /dev/null +++ b/windows.bat @@ -0,0 +1,3 @@ +CHCP 65001 +php windows.php +pause \ No newline at end of file diff --git a/windows.php b/windows.php new file mode 100644 index 0000000..f37a72c --- /dev/null +++ b/windows.php @@ -0,0 +1,136 @@ +load(); + } else { + Dotenv::createMutable(base_path())->load(); + } +} + +App::loadAllConfig(['route']); + +$errorReporting = config('app.error_reporting'); +if (isset($errorReporting)) { + error_reporting($errorReporting); +} + +$runtimeProcessPath = runtime_path() . DIRECTORY_SEPARATOR . '/windows'; +$paths = [ + $runtimeProcessPath, + runtime_path('logs'), + runtime_path('views') +]; +foreach ($paths as $path) { + if (!is_dir($path)) { + mkdir($path, 0777, true); + } +} + +$processFiles = []; +if (config('server.listen')) { + $processFiles[] = __DIR__ . DIRECTORY_SEPARATOR . 'start.php'; +} +foreach (config('process', []) as $processName => $config) { + $processFiles[] = write_process_file($runtimeProcessPath, $processName, ''); +} + +foreach (config('plugin', []) as $firm => $projects) { + foreach ($projects as $name => $project) { + if (!is_array($project)) { + continue; + } + foreach ($project['process'] ?? [] as $processName => $config) { + $processFiles[] = write_process_file($runtimeProcessPath, $processName, "$firm.$name"); + } + } + foreach ($projects['process'] ?? [] as $processName => $config) { + $processFiles[] = write_process_file($runtimeProcessPath, $processName, $firm); + } +} + +function write_process_file($runtimeProcessPath, $processName, $firm): string +{ + $processParam = $firm ? "plugin.$firm.$processName" : $processName; + $configParam = $firm ? "config('plugin.$firm.process')['$processName']" : "config('process')['$processName']"; + $fileContent = << true]); + if (!$resource) { + exit("Can not execute $cmd\r\n"); + } + return $resource; +} + +$resource = popen_processes($processFiles); +echo "\r\n"; +while (1) { + sleep(1); + if (!empty($monitor) && $monitor->checkAllFilesChange()) { + $status = proc_get_status($resource); + $pid = $status['pid']; + shell_exec("taskkill /F /T /PID $pid"); + proc_close($resource); + $resource = popen_processes($processFiles); + } +}