From e97978d0b7b694872441c59f665ab92d8e30ad7f Mon Sep 17 00:00:00 2001 From: "[yxf]" <[1524240689@qq.com]> Date: Fri, 27 Mar 2026 21:37:39 +0800 Subject: [PATCH] Initial commit: cool-admin-vue project --- .cursor/rules/adv-search.mdc | 305 + .cursor/rules/crud.mdc | 1480 +++++ .cursor/rules/form.mdc | 1820 ++++++ .cursor/rules/module.mdc | 464 ++ .cursor/rules/search.mdc | 743 +++ .cursor/rules/table.mdc | 2117 ++++++ .cursor/rules/upsert.mdc | 716 ++ .cursorrules | 74 + .dockerignore | 5 + .editorconfig | 7 + .env | 5 + .gitattributes | 4 + .gitignore | 20 + .hintrc | 16 + .prettierrc.json | 10 + .vscode/config.code-snippets | 15 + .vscode/crud.code-snippets | 100 + .vscode/extensions.json | 3 + .vscode/settings.json | 17 + Dockerfile | 14 + LICENSE | 33 + README.md | 78 + build/cool/eps.d.ts | 1588 +++++ build/cool/eps.json | 1 + env.d.ts | 10 + eslint.config.js | 73 + index.html | 178 + nginx.conf | 72 + package-lock.json | 5618 ++++++++++++++++ package.json | 77 + packages/crud/.gitignore | 23 + packages/crud/.prettierrc | 9 + packages/crud/README.md | 33 + packages/crud/index.d.ts | 811 +++ packages/crud/index.html | 29 + packages/crud/package.json | 38 + packages/crud/pnpm-lock.yaml | 2350 +++++++ packages/crud/src/App.vue | 208 + .../crud/src/components/add-btn/index.tsx | 21 + packages/crud/src/components/adv/btn.tsx | 31 + packages/crud/src/components/adv/search.tsx | 203 + .../src/components/context-menu/index.tsx | 282 + packages/crud/src/components/crud/helper.ts | 287 + packages/crud/src/components/crud/index.tsx | 91 + packages/crud/src/components/dialog/index.tsx | 288 + .../src/components/error-message/index.tsx | 17 + packages/crud/src/components/filter/index.tsx | 23 + packages/crud/src/components/flex1/index.tsx | 11 + .../crud/src/components/form-card/index.tsx | 51 + .../crud/src/components/form-tabs/index.tsx | 145 + .../crud/src/components/form/helper/action.ts | 146 + .../crud/src/components/form/helper/api.ts | 36 + .../crud/src/components/form/helper/index.ts | 85 + .../src/components/form/helper/plugins.ts | 92 + .../crud/src/components/form/helper/tabs.ts | 151 + packages/crud/src/components/form/index.tsx | 683 ++ packages/crud/src/components/index.tsx | 50 + .../src/components/multi-delete-btn/index.tsx | 27 + .../crud/src/components/pagination/index.tsx | 90 + .../crud/src/components/refresh-btn/index.tsx | 23 + packages/crud/src/components/row/index.tsx | 11 + .../crud/src/components/search-key/index.tsx | 178 + .../src/components/search/helper/plugins.ts | 21 + packages/crud/src/components/search/index.tsx | 298 + .../crud/src/components/table/helper/data.ts | 35 + .../src/components/table/helper/header.tsx | 91 + .../src/components/table/helper/height.ts | 99 + .../crud/src/components/table/helper/index.ts | 43 + .../crud/src/components/table/helper/op.ts | 69 + .../src/components/table/helper/plugins.ts | 22 + .../src/components/table/helper/render.tsx | 327 + .../crud/src/components/table/helper/row.ts | 130 + .../src/components/table/helper/selection.ts | 16 + .../crud/src/components/table/helper/sort.ts | 86 + packages/crud/src/components/table/index.tsx | 165 + packages/crud/src/components/upsert/index.tsx | 306 + packages/crud/src/emitter.ts | 27 + packages/crud/src/entry.ts | 30 + packages/crud/src/hooks/crud.ts | 191 + packages/crud/src/hooks/index.ts | 74 + packages/crud/src/index.ts | 1 + packages/crud/src/locale/en.ts | 33 + packages/crud/src/locale/index.ts | 11 + packages/crud/src/locale/ja.ts | 32 + packages/crud/src/locale/zh-cn.ts | 32 + packages/crud/src/locale/zh-tw.ts | 32 + packages/crud/src/main.ts | 28 + packages/crud/src/provide.ts | 129 + packages/crud/src/static/index.scss | 862 +++ packages/crud/src/test/service.ts | 231 + packages/crud/src/utils/form-hook.ts | 149 + packages/crud/src/utils/global.ts | 16 + packages/crud/src/utils/index.ts | 164 + packages/crud/src/utils/mitt.ts | 30 + packages/crud/src/utils/parse.tsx | 52 + packages/crud/src/utils/vnode.tsx | 182 + packages/crud/tsconfig.json | 34 + .../crud/types/components/add-btn/index.d.ts | 2 + packages/crud/types/components/adv/btn.d.ts | 4 + .../crud/types/components/adv/search.d.ts | 42 + .../types/components/context-menu/index.d.ts | 30 + .../crud/types/components/crud/helper.d.ts | 23 + .../crud/types/components/crud/index.d.ts | 19 + .../crud/types/components/dialog/index.d.ts | 86 + .../types/components/error-message/index.d.ts | 6 + .../crud/types/components/filter/index.d.ts | 6 + .../crud/types/components/flex1/index.d.ts | 2 + .../types/components/form-card/index.d.ts | 28 + .../types/components/form-tabs/index.d.ts | 38 + .../types/components/form/helper/action.d.ts | 17 + .../types/components/form/helper/api.d.ts | 3 + .../types/components/form/helper/index.d.ts | 237 + .../types/components/form/helper/plugins.d.ts | 7 + .../types/components/form/helper/tabs.d.ts | 19 + .../crud/types/components/form/index.d.ts | 22 + packages/crud/types/components/index.d.ts | 5 + .../components/multi-delete-btn/index.d.ts | 2 + .../types/components/pagination/index.d.ts | 4 + .../types/components/refresh-btn/index.d.ts | 2 + packages/crud/types/components/row/index.d.ts | 2 + .../types/components/search-key/index.d.ts | 55 + .../components/search/helper/plugins.d.ts | 3 + .../crud/types/components/search/index.d.ts | 66 + .../types/components/table/helper/data.d.ts | 7 + .../types/components/table/helper/header.d.ts | 1 + .../types/components/table/helper/height.d.ts | 7 + .../types/components/table/helper/index.d.ts | 191 + .../types/components/table/helper/op.d.ts | 9 + .../components/table/helper/plugins.d.ts | 3 + .../types/components/table/helper/render.d.ts | 7 + .../types/components/table/helper/row.d.ts | 13 + .../components/table/helper/selection.d.ts | 6 + .../types/components/table/helper/sort.d.ts | 18 + .../crud/types/components/table/index.d.ts | 62 + .../crud/types/components/upsert/index.d.ts | 38 + packages/crud/types/emitter.d.ts | 2 + packages/crud/types/entry.d.ts | 13 + packages/crud/types/hooks/crud.d.ts | 10 + packages/crud/types/hooks/index.d.ts | 16 + packages/crud/types/locale/en.d.ts | 33 + packages/crud/types/locale/index.d.ts | 130 + packages/crud/types/locale/ja.d.ts | 33 + packages/crud/types/locale/zh-cn.d.ts | 33 + packages/crud/types/locale/zh-tw.d.ts | 33 + packages/crud/types/main.d.ts | 0 packages/crud/types/provide.d.ts | 2 + packages/crud/types/test/service.d.ts | 52 + packages/crud/types/utils/form-hook.d.ts | 9 + packages/crud/types/utils/global.d.ts | 7 + packages/crud/types/utils/index.d.ts | 14 + packages/crud/types/utils/mitt.d.ts | 10 + packages/crud/types/utils/parse.d.ts | 5 + packages/crud/types/utils/vnode.d.ts | 14 + packages/crud/vite.config.ts | 49 + packages/crud/yarn.lock | 1790 +++++ packages/vite-plugin/.eslintrc.js | 12 + packages/vite-plugin/.prettierrc | 8 + packages/vite-plugin/client.d.ts | 48 + packages/vite-plugin/dist/base.d.ts | 2 + packages/vite-plugin/dist/config.d.ts | 39 + packages/vite-plugin/dist/ctx/index.d.ts | 2 + packages/vite-plugin/dist/demo.d.ts | 2 + packages/vite-plugin/dist/eps/flatten.d.ts | 7 + packages/vite-plugin/dist/eps/index.d.ts | 18 + packages/vite-plugin/dist/file/index.d.ts | 6 + packages/vite-plugin/dist/index.d.ts | 2 + packages/vite-plugin/dist/index.js | 2505 +++++++ packages/vite-plugin/dist/plugin/index.d.ts | 4 + packages/vite-plugin/dist/proxy/index.d.ts | 4 + packages/vite-plugin/dist/svg/index.d.ts | 4 + packages/vite-plugin/dist/tag/index.d.ts | 4 + packages/vite-plugin/dist/test.d.ts | 1 + packages/vite-plugin/dist/uniapp-x.d.ts | 67 + packages/vite-plugin/dist/uniapp-x/code.d.ts | 2 + packages/vite-plugin/dist/uniapp-x/color.d.ts | 9 + .../vite-plugin/dist/uniapp-x/config.d.ts | 8 + .../vite-plugin/dist/uniapp-x/flatten.d.ts | 7 + packages/vite-plugin/dist/uniapp-x/index.d.ts | 7 + .../vite-plugin/dist/uniapp-x/tailwind.d.ts | 9 + packages/vite-plugin/dist/uniapp-x/utils.d.ts | 28 + packages/vite-plugin/dist/utils/index.d.ts | 18 + packages/vite-plugin/dist/virtual.d.ts | 2 + packages/vite-plugin/package.json | 41 + packages/vite-plugin/rollup.config.js | 21 + packages/vite-plugin/src/base.ts | 68 + packages/vite-plugin/src/config.ts | 61 + packages/vite-plugin/src/ctx/index.ts | 116 + packages/vite-plugin/src/demo.ts | 50 + packages/vite-plugin/src/eps/index.ts | 788 +++ packages/vite-plugin/src/file/index.ts | 40 + packages/vite-plugin/src/index.ts | 77 + packages/vite-plugin/src/plugin/index.ts | 41 + packages/vite-plugin/src/proxy/index.ts | 36 + packages/vite-plugin/src/svg/index.ts | 100 + packages/vite-plugin/src/tag/index.ts | 32 + packages/vite-plugin/src/test.ts | 90 + packages/vite-plugin/src/uniapp-x/code.ts | 206 + packages/vite-plugin/src/uniapp-x/config.ts | 51 + packages/vite-plugin/src/uniapp-x/flatten.ts | 129 + packages/vite-plugin/src/uniapp-x/index.ts | 23 + packages/vite-plugin/src/uniapp-x/tailwind.ts | 441 ++ packages/vite-plugin/src/uniapp-x/utils.ts | 524 ++ packages/vite-plugin/src/utils/index.ts | 174 + packages/vite-plugin/src/virtual.ts | 92 + packages/vite-plugin/tsconfig.json | 16 + packages/vite-plugin/types/index.d.ts | 129 + packages/vite-plugin/yarn.lock | 1771 +++++ pnpm-lock.yaml | 5730 +++++++++++++++++ pnpm-workspace.yaml | 6 + postcss.config.js | 6 + public/favicon.ico | Bin 0 -> 67646 bytes public/logo.png | Bin 0 -> 1403 bytes public/用户导入模版.xlsx | Bin 0 -> 9198 bytes src/App.vue | 8 + src/config/dev.ts | 9 + src/config/index.ts | 62 + src/config/prod.ts | 17 + src/config/proxy.ts | 18 + src/cool/bootstrap/eps.ts | 62 + src/cool/bootstrap/index.ts | 24 + src/cool/bootstrap/module.ts | 126 + src/cool/hooks/browser.ts | 41 + src/cool/hooks/hmr.ts | 32 + src/cool/hooks/index.ts | 58 + src/cool/hooks/mitt.ts | 9 + src/cool/index.ts | 7 + src/cool/index.vue | 39 + src/cool/module/index.ts | 43 + src/cool/router/index.ts | 246 + src/cool/service/base.ts | 86 + src/cool/service/index.ts | 10 + src/cool/service/request.ts | 168 + src/cool/service/stream.ts | 103 + src/cool/types/index.ts | 60 + src/cool/utils/index.ts | 301 + src/cool/utils/loading.ts | 37 + src/cool/utils/storage.ts | 83 + src/main.ts | 14 + src/modules/base/components/avatar/index.tsx | 53 + src/modules/base/components/code/json.vue | 156 + src/modules/base/components/dept/check.vue | 111 + src/modules/base/components/dept/select.vue | 87 + src/modules/base/components/editor/index.tsx | 44 + src/modules/base/components/icon/svg.vue | 41 + src/modules/base/components/image/index.vue | 111 + src/modules/base/components/link/index.vue | 75 + src/modules/base/components/menu/check.vue | 99 + src/modules/base/components/menu/file.vue | 174 + src/modules/base/components/menu/icon.vue | 84 + src/modules/base/components/menu/perms.vue | 95 + src/modules/base/components/menu/select.vue | 86 + src/modules/base/components/num/index.vue | 61 + src/modules/base/config.ts | 101 + src/modules/base/directives/permission.ts | 13 + src/modules/base/index.ts | 9 + src/modules/base/locales/en.json | 143 + src/modules/base/locales/zh-cn.json | 143 + src/modules/base/locales/zh-tw.json | 143 + src/modules/base/pages/error/401.vue | 11 + src/modules/base/pages/error/403.vue | 11 + src/modules/base/pages/error/404.vue | 11 + src/modules/base/pages/error/500.vue | 11 + src/modules/base/pages/error/502.vue | 11 + .../pages/error/components/error-page.vue | 140 + src/modules/base/pages/kefulogin/chat.vue | 912 +++ src/modules/base/pages/kefulogin/index.vue | 343 + .../pages/login/components/pic-captcha.vue | 110 + src/modules/base/pages/login/index.vue | 307 + src/modules/base/pages/login/static/bg.svg | 39 + .../base/pages/main/components/amenu.vue | 151 + .../base/pages/main/components/bmenu.tsx | 153 + .../base/pages/main/components/global.vue | 37 + .../base/pages/main/components/process.vue | 279 + .../base/pages/main/components/route-nav.vue | 87 + .../base/pages/main/components/slider.vue | 188 + .../base/pages/main/components/topbar.vue | 219 + .../base/pages/main/components/views.vue | 99 + src/modules/base/pages/main/index.vue | 132 + src/modules/base/static/css/index.scss | 81 + src/modules/base/static/svg/amount.svg | 1 + src/modules/base/static/svg/back.svg | 17 + src/modules/base/static/svg/close-border.svg | 1 + src/modules/base/static/svg/close.svg | 21 + src/modules/base/static/svg/delete.svg | 1 + src/modules/base/static/svg/edit.svg | 21 + src/modules/base/static/svg/exit.svg | 25 + src/modules/base/static/svg/expand.svg | 1 + src/modules/base/static/svg/export.svg | 1 + src/modules/base/static/svg/fail.svg | 1 + src/modules/base/static/svg/fold.svg | 1 + src/modules/base/static/svg/github.svg | 17 + src/modules/base/static/svg/home.svg | 17 + src/modules/base/static/svg/icon-activity.svg | 1 + src/modules/base/static/svg/icon-amount.svg | 9 + src/modules/base/static/svg/icon-app.svg | 1 + src/modules/base/static/svg/icon-approve.svg | 1 + src/modules/base/static/svg/icon-auth.svg | 1 + src/modules/base/static/svg/icon-ban.svg | 1 + src/modules/base/static/svg/icon-call.svg | 1 + src/modules/base/static/svg/icon-camera.svg | 1 + src/modules/base/static/svg/icon-card.svg | 1 + src/modules/base/static/svg/icon-cart.svg | 1 + src/modules/base/static/svg/icon-common.svg | 1 + .../base/static/svg/icon-component.svg | 17 + src/modules/base/static/svg/icon-count.svg | 1 + src/modules/base/static/svg/icon-crown.svg | 1 + src/modules/base/static/svg/icon-data.svg | 9 + src/modules/base/static/svg/icon-db.svg | 15 + src/modules/base/static/svg/icon-delete.svg | 1 + src/modules/base/static/svg/icon-dept.svg | 9 + src/modules/base/static/svg/icon-design.svg | 12 + src/modules/base/static/svg/icon-device.svg | 9 + src/modules/base/static/svg/icon-dict.svg | 1 + src/modules/base/static/svg/icon-discover.svg | 1 + src/modules/base/static/svg/icon-doc.svg | 1 + src/modules/base/static/svg/icon-download.svg | 1 + src/modules/base/static/svg/icon-emoji.svg | 1 + src/modules/base/static/svg/icon-favor.svg | 1 + src/modules/base/static/svg/icon-file.svg | 1 + src/modules/base/static/svg/icon-folder.svg | 1 + src/modules/base/static/svg/icon-goods.svg | 1 + src/modules/base/static/svg/icon-home.svg | 1 + src/modules/base/static/svg/icon-hot.svg | 1 + src/modules/base/static/svg/icon-info.svg | 1 + src/modules/base/static/svg/icon-iot.svg | 43 + src/modules/base/static/svg/icon-light.svg | 1 + src/modules/base/static/svg/icon-like.svg | 1 + src/modules/base/static/svg/icon-list.svg | 9 + src/modules/base/static/svg/icon-local.svg | 1 + src/modules/base/static/svg/icon-log.svg | 1 + src/modules/base/static/svg/icon-map.svg | 1 + src/modules/base/static/svg/icon-match.svg | 1 + src/modules/base/static/svg/icon-menu.svg | 1 + src/modules/base/static/svg/icon-monitor.svg | 9 + src/modules/base/static/svg/icon-msg.svg | 1 + src/modules/base/static/svg/icon-news.svg | 1 + src/modules/base/static/svg/icon-notice.svg | 1 + src/modules/base/static/svg/icon-params.svg | 9 + src/modules/base/static/svg/icon-phone.svg | 9 + src/modules/base/static/svg/icon-pic.svg | 1 + src/modules/base/static/svg/icon-question.svg | 1 + src/modules/base/static/svg/icon-quick.svg | 1 + src/modules/base/static/svg/icon-rank.svg | 1 + src/modules/base/static/svg/icon-reward.svg | 1 + src/modules/base/static/svg/icon-search.svg | 1 + src/modules/base/static/svg/icon-set.svg | 1 + src/modules/base/static/svg/icon-tag.svg | 1 + src/modules/base/static/svg/icon-task.svg | 1 + src/modules/base/static/svg/icon-time.svg | 1 + src/modules/base/static/svg/icon-tutorial.svg | 1 + src/modules/base/static/svg/icon-unlock.svg | 1 + src/modules/base/static/svg/icon-user.svg | 1 + src/modules/base/static/svg/icon-video.svg | 1 + src/modules/base/static/svg/icon-vip.svg | 1 + src/modules/base/static/svg/icon-warn.svg | 1 + src/modules/base/static/svg/icon-work.svg | 1 + .../base/static/svg/icon-workbench.svg | 1 + src/modules/base/static/svg/image.svg | 17 + src/modules/base/static/svg/import.svg | 1 + src/modules/base/static/svg/left.svg | 1 + src/modules/base/static/svg/my.svg | 21 + src/modules/base/static/svg/order.svg | 1 + src/modules/base/static/svg/play.svg | 1 + src/modules/base/static/svg/plus-border.svg | 1 + src/modules/base/static/svg/plus.svg | 1 + src/modules/base/static/svg/refresh.svg | 21 + src/modules/base/static/svg/right.svg | 1 + src/modules/base/static/svg/screen-full.svg | 17 + src/modules/base/static/svg/screen-normal.svg | 17 + src/modules/base/static/svg/search.svg | 1 + src/modules/base/static/svg/set.svg | 1 + src/modules/base/static/svg/sort.svg | 1 + src/modules/base/static/svg/stats.svg | 1 + src/modules/base/static/svg/success.svg | 1 + src/modules/base/static/svg/team.svg | 1 + src/modules/base/static/svg/trend.svg | 1 + src/modules/base/store/app.ts | 69 + src/modules/base/store/index.ts | 18 + src/modules/base/store/menu.ts | 205 + src/modules/base/store/process.ts | 74 + src/modules/base/store/user.ts | 88 + src/modules/base/types/index.d.ts | 52 + src/modules/base/utils/index.ts | 9 + src/modules/base/utils/permission.ts | 30 + src/modules/base/views/frame.vue | 49 + src/modules/base/views/info.vue | 119 + src/modules/base/views/log.vue | 153 + .../base/views/menu/components/exp.vue | 109 + .../base/views/menu/components/imp.vue | 122 + src/modules/base/views/menu/index.vue | 404 ++ src/modules/base/views/param.vue | 226 + src/modules/base/views/role.vue | 165 + .../base/views/user/components/dept-list.vue | 503 ++ .../base/views/user/components/user-move.vue | 74 + src/modules/base/views/user/index.vue | 342 + src/modules/cs/components/index.vue | 244 + src/modules/cs/components/message.vue | 526 ++ src/modules/cs/components/session.vue | 223 + src/modules/cs/components/tools/emoji.vue | 162 + src/modules/cs/config.ts | 10 + src/modules/cs/hooks/index.ts | 5 + src/modules/cs/hooks/message.ts | 128 + src/modules/cs/hooks/notice.tsx | 68 + src/modules/cs/hooks/session.ts | 97 + src/modules/cs/hooks/socket.ts | 95 + src/modules/cs/hooks/tools.ts | 28 + src/modules/cs/index.ts | 13 + src/modules/cs/static/audio/ding.wav | Bin 0 -> 3534 bytes src/modules/cs/static/emoji/angry-face.png | Bin 0 -> 3669 bytes .../cs/static/emoji/anguished-face.png | Bin 0 -> 3584 bytes .../cs/static/emoji/astonished-face.png | Bin 0 -> 3584 bytes .../cs/static/emoji/confounded-face.png | Bin 0 -> 3683 bytes src/modules/cs/static/emoji/confused-face.png | Bin 0 -> 3670 bytes src/modules/cs/static/emoji/crying-face.png | Bin 0 -> 3824 bytes .../emoji/disappointed-but-relieved-face.png | Bin 0 -> 3709 bytes .../cs/static/emoji/disappointed-face.png | Bin 0 -> 3584 bytes src/modules/cs/static/emoji/dizzy-face.png | Bin 0 -> 3683 bytes src/modules/cs/static/emoji/drooling-face.png | Bin 0 -> 3552 bytes .../cs/static/emoji/expressionless-face.png | Bin 0 -> 3553 bytes .../emoji/face-savouring-delicious-food.png | Bin 0 -> 3701 bytes .../static/emoji/face-screaming-in-fear.png | Bin 0 -> 3672 bytes .../cs/static/emoji/face-throwing-a-kiss.png | Bin 0 -> 3744 bytes .../cs/static/emoji/face-with-cold-sweat.png | Bin 0 -> 3545 bytes .../cs/static/emoji/face-with-cowboy-hat.png | Bin 0 -> 3683 bytes .../face-with-finger-covering-closed-lips.png | Bin 0 -> 3797 bytes .../static/emoji/face-with-head-bandage.png | Bin 0 -> 3586 bytes .../emoji/face-with-look-of-triumph.png | Bin 0 -> 3809 bytes .../static/emoji/face-with-medical-mask.png | Bin 0 -> 3684 bytes .../cs/static/emoji/face-with-monocle.png | Bin 0 -> 3609 bytes .../emoji/face-with-one-eyebrow-raised.png | Bin 0 -> 3483 bytes .../face-with-open-mouth-and-cold-sweat.png | Bin 0 -> 3377 bytes .../emoji/face-with-open-mouth-vomiting.png | Bin 0 -> 4011 bytes .../cs/static/emoji/face-with-open-mouth.png | Bin 0 -> 3667 bytes .../face-with-party-horn-and-party-hat.png | Bin 0 -> 3971 bytes .../static/emoji/face-with-pleading-eyes.png | Bin 0 -> 3498 bytes .../static/emoji/face-with-rolling-eyes.png | Bin 0 -> 3461 bytes ...uck-out-tongue-and-tightly-closed-eyes.png | Bin 0 -> 3622 bytes ...-with-stuck-out-tongue-and-winking-eye.png | Bin 0 -> 3561 bytes .../emoji/face-with-stuck-out-tongue.png | Bin 0 -> 3535 bytes .../cs/static/emoji/face-with-thermometer.png | Bin 0 -> 3560 bytes .../face-with-uneven-eyes-and-wavy-mouth.png | Bin 0 -> 3640 bytes .../cs/static/emoji/face-without-mouth.png | Bin 0 -> 3664 bytes src/modules/cs/static/emoji/fearful-face.png | Bin 0 -> 3366 bytes src/modules/cs/static/emoji/flushed-face.png | Bin 0 -> 3611 bytes src/modules/cs/static/emoji/freezing-face.png | Bin 0 -> 3615 bytes .../emoji/frowning-face-with-open-mouth.png | Bin 0 -> 3666 bytes .../cs/static/emoji/grimacing-face.png | Bin 0 -> 3695 bytes ...-face-with-one-large-and-one-small-eye.png | Bin 0 -> 3719 bytes .../emoji/grinning-face-with-smiling-eyes.png | Bin 0 -> 3677 bytes .../emoji/grinning-face-with-star-eyes.png | Bin 0 -> 3888 bytes src/modules/cs/static/emoji/grinning-face.png | Bin 0 -> 3675 bytes src/modules/cs/static/emoji/hugging-face.png | Bin 0 -> 4061 bytes src/modules/cs/static/emoji/hushed-face.png | Bin 0 -> 3548 bytes src/modules/cs/static/emoji/imp.png | Bin 0 -> 3972 bytes .../emoji/kissing-face-with-closed-eyes.png | Bin 0 -> 3613 bytes .../emoji/kissing-face-with-smiling-eyes.png | Bin 0 -> 3633 bytes src/modules/cs/static/emoji/kissing-face.png | Bin 0 -> 3589 bytes .../cs/static/emoji/loudly-crying-face.png | Bin 0 -> 3671 bytes src/modules/cs/static/emoji/lying-face.png | Bin 0 -> 3755 bytes .../cs/static/emoji/money-mouth-face.png | Bin 0 -> 3680 bytes .../cs/static/emoji/nauseated-face.png | Bin 0 -> 3759 bytes src/modules/cs/static/emoji/nerd-face.png | Bin 0 -> 3673 bytes src/modules/cs/static/emoji/neutral-face.png | Bin 0 -> 3603 bytes .../cs/static/emoji/overheated-face.png | Bin 0 -> 3440 bytes src/modules/cs/static/emoji/pensive-face.png | Bin 0 -> 3672 bytes .../cs/static/emoji/persevering-face.png | Bin 0 -> 3628 bytes src/modules/cs/static/emoji/pouting-face.png | Bin 0 -> 3643 bytes src/modules/cs/static/emoji/relieved-face.png | Bin 0 -> 3716 bytes .../emoji/rolling-on-the-floor-laughing.png | Bin 0 -> 3698 bytes ...rious-face-with-symbols-covering-mouth.png | Bin 0 -> 3580 bytes .../shocked-face-with-exploding-head.png | Bin 0 -> 4401 bytes src/modules/cs/static/emoji/sleeping-face.png | Bin 0 -> 3525 bytes src/modules/cs/static/emoji/sleepy-face.png | Bin 0 -> 3477 bytes .../static/emoji/slightly-frowning-face.png | Bin 0 -> 3675 bytes .../cs/static/emoji/slightly-smiling-face.png | Bin 0 -> 3737 bytes .../static/emoji/smiling-face-with-halo.png | Bin 0 -> 3981 bytes .../smiling-face-with-heart-shaped-eyes.png | Bin 0 -> 3690 bytes .../static/emoji/smiling-face-with-horns.png | Bin 0 -> 3957 bytes ...-face-with-open-mouth-and-smiling-eyes.png | Bin 0 -> 3710 bytes ...ith-open-mouth-and-tightly-closed-eyes.png | Bin 0 -> 3746 bytes .../emoji/smiling-face-with-open-mouth.png | Bin 0 -> 3581 bytes ...h-smiling-eyes-and-hand-covering-mouth.png | Bin 0 -> 3807 bytes ...ace-with-smiling-eyes-and-three-hearts.png | Bin 0 -> 3986 bytes .../emoji/smiling-face-with-smiling-eyes.png | Bin 0 -> 3684 bytes .../emoji/smiling-face-with-sunglasses.png | Bin 0 -> 3633 bytes src/modules/cs/static/emoji/smirking-face.png | Bin 0 -> 3566 bytes src/modules/cs/static/emoji/sneezing-face.png | Bin 0 -> 3686 bytes src/modules/cs/static/emoji/thinking-face.png | Bin 0 -> 3763 bytes src/modules/cs/static/emoji/tired-face.png | Bin 0 -> 3683 bytes .../cs/static/emoji/upside-down-face.png | Bin 0 -> 3688 bytes src/modules/cs/static/emoji/weary-face.png | Bin 0 -> 3726 bytes .../cs/static/emoji/white-frowning-face.png | Bin 0 -> 3590 bytes .../cs/static/emoji/white-smiling-face.png | Bin 0 -> 3576 bytes src/modules/cs/static/emoji/winking-face.png | Bin 0 -> 3742 bytes src/modules/cs/static/emoji/worried-face.png | Bin 0 -> 3655 bytes .../cs/static/emoji/zipper-mouth-face.png | Bin 0 -> 3747 bytes src/modules/cs/types/index.d.ts | 13 + src/modules/cs/utils/index.ts | 52 + src/modules/cs/views/chat.vue | 175 + src/modules/demo/config.ts | 27 + src/modules/demo/directives/color.ts | 5 + src/modules/demo/locales/en.json | 54 + src/modules/demo/locales/zh-cn.json | 54 + src/modules/demo/locales/zh-tw.json | 54 + .../views/crud/components/adv-search/base.vue | 138 + .../crud/components/adv-search/custom.vue | 152 + .../demo/views/crud/components/code.vue | 45 + .../demo/views/crud/components/crud/all.vue | 578 ++ .../demo/views/crud/components/crud/base.vue | 145 + .../demo/views/crud/components/crud/dict.vue | 164 + .../demo/views/crud/components/crud/event.vue | 182 + .../crud/components/crud/select-table.vue | 155 + .../views/crud/components/crud/service.vue | 179 + .../crud/components/crud/user-select.vue | 77 + .../views/crud/components/form/children.vue | 118 + .../crud/components/form/component/index.vue | 124 + .../form/component/select-labels.vue | 42 + .../form/component/select-status.vue | 47 + .../components/form/component/select-work.vue | 63 + .../form/component/select-work2.vue | 42 + .../views/crud/components/form/config.vue | 122 + .../demo/views/crud/components/form/crud.vue | 151 + .../views/crud/components/form/disabled.vue | 64 + .../demo/views/crud/components/form/event.vue | 93 + .../demo/views/crud/components/form/group.vue | 105 + .../views/crud/components/form/hidden.vue | 77 + .../views/crud/components/form/layout.vue | 98 + .../demo/views/crud/components/form/open.vue | 84 + .../views/crud/components/form/options.vue | 172 + .../crud/components/form/plugin/index.vue | 109 + .../views/crud/components/form/plugin/role.ts | 20 + .../views/crud/components/form/required.vue | 94 + .../demo/views/crud/components/form/rules.vue | 123 + .../views/crud/components/form/setFocus.vue | 63 + .../crud/components/other/context-menu.vue | 71 + .../demo/views/crud/components/other/tips.vue | 150 + .../crud/components/other/tsx/index.scss | 28 + .../views/crud/components/other/tsx/index.tsx | 109 + .../views/crud/components/search/base.vue | 147 + .../views/crud/components/search/collapse.vue | 110 + .../views/crud/components/search/custom.vue | 176 + .../views/crud/components/search/layout.vue | 149 + .../views/crud/components/search/plugin.vue | 128 + .../demo/views/crud/components/table/base.vue | 109 + .../views/crud/components/table/children.vue | 95 + .../crud/components/table/column-custom.vue | 108 + .../crud/components/table/component/index.vue | 108 + .../components/table/component/user-info.vue | 34 + .../crud/components/table/context-menu.vue | 191 + .../demo/views/crud/components/table/dict.vue | 156 + .../views/crud/components/table/formatter.vue | 95 + .../views/crud/components/table/hidden.vue | 127 + .../demo/views/crud/components/table/op.vue | 182 + .../crud/components/table/plugin/base.vue | 130 + .../crud/components/table/plugin/row-edit.vue | 124 + .../crud/components/table/plugin/to-tree.vue | 87 + .../views/crud/components/table/search.vue | 137 + .../views/crud/components/table/selection.vue | 109 + .../demo/views/crud/components/table/slot.vue | 97 + .../crud/components/table/span-method.vue | 115 + .../views/crud/components/table/summary.vue | 95 + .../views/crud/components/upsert/base.vue | 133 + .../views/crud/components/upsert/event.vue | 210 + .../crud/components/upsert/hook/index.vue | 200 + .../crud/components/upsert/hook/reg-pca2.ts | 14 + .../views/crud/components/upsert/mode.vue | 146 + src/modules/demo/views/crud/index.vue | 327 + .../views/home/components/category-ratio.vue | 69 + .../views/home/components/count-effect.vue | 89 + .../demo/views/home/components/count-paid.vue | 30 + .../demo/views/home/components/count-user.vue | 58 + .../views/home/components/count-views.vue | 110 + .../demo/views/home/components/hot-goods.vue | 179 + .../demo/views/home/components/tab-chart.vue | 152 + src/modules/demo/views/home/index.vue | 106 + src/modules/demo/views/test/route.vue | 52 + src/modules/dict/config.ts | 16 + src/modules/dict/index.ts | 7 + src/modules/dict/locales/en.json | 16 + src/modules/dict/locales/zh-cn.json | 16 + src/modules/dict/locales/zh-tw.json | 16 + src/modules/dict/store/dict.ts | 65 + src/modules/dict/store/index.ts | 9 + src/modules/dict/types/index.d.ts | 15 + src/modules/dict/utils/index.ts | 31 + src/modules/dict/views/list.vue | 281 + src/modules/helper/components/ai-code/btn.vue | 71 + src/modules/helper/components/ai-code/dev.vue | 76 + src/modules/helper/components/auto-menu.vue | 217 + src/modules/helper/components/auto-perms.vue | 213 + src/modules/helper/config.ts | 30 + src/modules/helper/hooks/index.ts | 2 + src/modules/helper/hooks/menu.ts | 93 + src/modules/helper/hooks/plugin.ts | 120 + src/modules/helper/locales/en.json | 66 + src/modules/helper/locales/zh-cn.json | 66 + src/modules/helper/locales/zh-tw.json | 66 + src/modules/helper/static/index.scss | 119 + src/modules/helper/static/svg/icon-vue.svg | 18 + src/modules/helper/types/index.d.ts | 35 + src/modules/helper/views/ai-code.vue | 246 + src/modules/helper/views/plugins.vue | 1033 +++ src/modules/recycle/locales/en.json | 14 + src/modules/recycle/locales/zh-cn.json | 14 + src/modules/recycle/locales/zh-tw.json | 14 + src/modules/recycle/views/data.vue | 144 + src/modules/space/components/space-inner.vue | 454 ++ src/modules/space/components/space.vue | 172 + src/modules/space/config.ts | 24 + src/modules/space/hooks/index.ts | 19 + src/modules/space/locales/en.json | 20 + src/modules/space/locales/zh-cn.json | 20 + src/modules/space/locales/zh-tw.json | 20 + src/modules/space/views/list.vue | 11 + src/modules/staff/views/list.vue | 195 + src/modules/task/components/logs.vue | 119 + src/modules/task/locales/en.json | 34 + src/modules/task/locales/zh-cn.json | 34 + src/modules/task/locales/zh-tw.json | 34 + src/modules/task/views/list.vue | 499 ++ src/modules/user/components/user-select.vue | 67 + src/modules/user/config.ts | 5 + src/modules/user/locales/en.json | 20 + src/modules/user/locales/zh-cn.json | 20 + src/modules/user/locales/zh-tw.json | 20 + src/modules/user/views/list.vue | 208 + src/plugins/crud/comm/index.ts | 10 + .../crud/components/column-custom/index.vue | 186 + src/plugins/crud/components/date/picker.vue | 184 + src/plugins/crud/components/date/text.vue | 24 + src/plugins/crud/components/dict/index.tsx | 146 + src/plugins/crud/components/number/range.vue | 78 + src/plugins/crud/components/render/index.tsx | 18 + src/plugins/crud/components/select/button.tsx | 32 + src/plugins/crud/components/select/index.scss | 35 + src/plugins/crud/components/select/index.tsx | 275 + src/plugins/crud/components/select/table.vue | 433 ++ src/plugins/crud/components/switch/index.tsx | 130 + src/plugins/crud/components/text/index.tsx | 28 + src/plugins/crud/components/user/select.vue | 385 ++ src/plugins/crud/config.ts | 68 + src/plugins/crud/index.ts | 2 + src/plugins/crud/locales/en.json | 35 + src/plugins/crud/locales/zh-cn.json | 35 + src/plugins/crud/locales/zh-tw.json | 35 + src/plugins/crud/plugins/form/index.ts | 5 + src/plugins/crud/plugins/form/setFocus.ts | 47 + src/plugins/crud/plugins/index.ts | 9 + src/plugins/crud/plugins/search/index.ts | 5 + src/plugins/crud/plugins/search/setAuto.ts | 125 + src/plugins/crud/plugins/table/index.ts | 7 + src/plugins/crud/plugins/table/rowEdit.tsx | 135 + src/plugins/crud/plugins/table/toTree.ts | 116 + src/plugins/dev-tools/components/account.vue | 159 + src/plugins/dev-tools/components/dict.vue | 139 + src/plugins/dev-tools/components/doc.vue | 148 + src/plugins/dev-tools/components/eps.vue | 158 + src/plugins/dev-tools/components/index.vue | 297 + src/plugins/dev-tools/components/proxy.vue | 86 + src/plugins/dev-tools/config.ts | 9 + src/plugins/dev-tools/locales/en.json | 14 + src/plugins/dev-tools/locales/zh-cn.json | 14 + src/plugins/dev-tools/locales/zh-tw.json | 14 + src/plugins/dev-tools/static/cool.png | Bin 0 -> 4427 bytes src/plugins/dev-tools/static/echarts.png | Bin 0 -> 1074 bytes src/plugins/dev-tools/static/element-plus.png | Bin 0 -> 938 bytes src/plugins/dev-tools/static/lodash.png | Bin 0 -> 1765 bytes src/plugins/dev-tools/static/logo.png | Bin 0 -> 1180 bytes src/plugins/dev-tools/static/pinia.png | Bin 0 -> 11675 bytes src/plugins/dev-tools/static/tailwindcss.png | Bin 0 -> 741 bytes src/plugins/dev-tools/static/vite.png | Bin 0 -> 9733 bytes src/plugins/dev-tools/static/vue.png | Bin 0 -> 918 bytes src/plugins/dev-tools/utils/index.ts | 7 + src/plugins/distpicker/components/index.tsx | 52 + src/plugins/distpicker/config.ts | 37 + src/plugins/distpicker/data/pca.json | 5300 +++++++++++++++ src/plugins/distpicker/demo/base.vue | 10 + src/plugins/echarts/config.ts | 20 + .../editor-preview/components/preview.vue | 230 + src/plugins/editor-preview/config.ts | 20 + src/plugins/editor-preview/demo/base.vue | 11 + src/plugins/editor-preview/locales/en.json | 9 + src/plugins/editor-preview/locales/zh-cn.json | 9 + src/plugins/editor-preview/locales/zh-tw.json | 9 + src/plugins/editor-wang/components/wang.vue | 236 + src/plugins/editor-wang/config.ts | 21 + src/plugins/editor-wang/demo/base.vue | 11 + src/plugins/editor-wang/locales/en.json | 3 + src/plugins/editor-wang/locales/zh-cn.json | 3 + src/plugins/editor-wang/locales/zh-tw.json | 3 + src/plugins/element-ui/config.ts | 33 + src/plugins/element-ui/css/index.scss | 126 + src/plugins/excel/components/export-btn.tsx | 209 + src/plugins/excel/components/import-btn.vue | 413 ++ src/plugins/excel/config.ts | 23 + src/plugins/excel/demo/base.vue | 78 + src/plugins/excel/locales/en.json | 17 + src/plugins/excel/locales/zh-cn.json | 17 + src/plugins/excel/locales/zh-tw.json | 17 + src/plugins/excel/utils/index.ts | 226 + src/plugins/github/components/code.vue | 11 + src/plugins/github/config.ts | 9 + src/plugins/i18n/components/switch.vue | 72 + src/plugins/i18n/config.ts | 31 + src/plugins/i18n/index.ts | 16 + src/plugins/i18n/static/svg/lang.svg | 17 + src/plugins/iconfont/config.ts | 21 + src/plugins/iconfont/index.ts | 1 + src/plugins/iconfont/utils/index.ts | 13 + src/plugins/tailwind/config.ts | 14 + src/plugins/tailwind/static/index.css | 3 + src/plugins/theme/components/theme.vue | 201 + src/plugins/theme/config.ts | 75 + src/plugins/theme/hooks/index.ts | 151 + src/plugins/theme/index.ts | 1 + src/plugins/theme/locales/en.json | 16 + src/plugins/theme/locales/zh-cn.json | 16 + src/plugins/theme/locales/zh-tw.json | 16 + src/plugins/theme/static/css/index.scss | 32 + src/plugins/theme/static/svg/dark.svg | 1 + src/plugins/theme/static/svg/light.svg | 1 + src/plugins/theme/static/svg/theme.svg | 12 + src/plugins/theme/types/index.d.ts | 7 + src/plugins/theme/utils/index.ts | 16 + .../upload/components/upload-item/index.vue | 445 ++ .../upload/components/upload-item/viewer.vue | 112 + src/plugins/upload/components/upload.vue | 642 ++ src/plugins/upload/config.ts | 132 + src/plugins/upload/demo/base.vue | 9 + src/plugins/upload/demo/check.vue | 20 + src/plugins/upload/demo/custom.vue | 27 + src/plugins/upload/demo/drag.vue | 11 + src/plugins/upload/demo/file.vue | 9 + src/plugins/upload/demo/multiple.vue | 9 + src/plugins/upload/demo/small.vue | 9 + src/plugins/upload/demo/space.vue | 66 + src/plugins/upload/hooks/index.ts | 191 + src/plugins/upload/index.ts | 2 + src/plugins/upload/locales/en.json | 22 + src/plugins/upload/locales/zh-cn.json | 22 + src/plugins/upload/locales/zh-tw.json | 22 + src/plugins/upload/static/svg/audio.svg | 30 + src/plugins/upload/static/svg/excel.svg | 30 + src/plugins/upload/static/svg/file.svg | 48 + src/plugins/upload/static/svg/image.svg | 30 + src/plugins/upload/static/svg/pdf.svg | 30 + src/plugins/upload/static/svg/ppt.svg | 30 + src/plugins/upload/static/svg/rar.svg | 71 + src/plugins/upload/static/svg/video.svg | 26 + src/plugins/upload/static/svg/word.svg | 30 + src/plugins/upload/types/index.d.ts | 36 + src/plugins/upload/utils/index.ts | 74 + src/plugins/view/components/group.vue | 701 ++ src/plugins/view/components/head.vue | 65 + src/plugins/view/config.ts | 24 + src/plugins/view/demo/group.vue | 19 + src/plugins/view/demo/head.vue | 5 + src/plugins/view/hooks/group.ts | 13 + src/plugins/view/hooks/index.ts | 1 + src/plugins/view/index.ts | 1 + src/plugins/view/locales/en.json | 15 + src/plugins/view/locales/zh-cn.json | 15 + src/plugins/view/locales/zh-tw.json | 15 + src/plugins/view/types/index.d.ts | 69 + src/shims-vue.d.ts | 8 + tailwind.config.js | 4 + tsconfig.json | 45 + vite.config.ts | 108 + 768 files changed, 83991 insertions(+) create mode 100644 .cursor/rules/adv-search.mdc create mode 100644 .cursor/rules/crud.mdc create mode 100644 .cursor/rules/form.mdc create mode 100644 .cursor/rules/module.mdc create mode 100644 .cursor/rules/search.mdc create mode 100644 .cursor/rules/table.mdc create mode 100644 .cursor/rules/upsert.mdc create mode 100644 .cursorrules create mode 100644 .dockerignore create mode 100644 .editorconfig create mode 100644 .env create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .hintrc create mode 100644 .prettierrc.json create mode 100644 .vscode/config.code-snippets create mode 100644 .vscode/crud.code-snippets create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build/cool/eps.d.ts create mode 100644 build/cool/eps.json create mode 100644 env.d.ts create mode 100644 eslint.config.js create mode 100644 index.html create mode 100644 nginx.conf create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 packages/crud/.gitignore create mode 100644 packages/crud/.prettierrc create mode 100644 packages/crud/README.md create mode 100644 packages/crud/index.d.ts create mode 100644 packages/crud/index.html create mode 100644 packages/crud/package.json create mode 100644 packages/crud/pnpm-lock.yaml create mode 100644 packages/crud/src/App.vue create mode 100644 packages/crud/src/components/add-btn/index.tsx create mode 100644 packages/crud/src/components/adv/btn.tsx create mode 100644 packages/crud/src/components/adv/search.tsx create mode 100644 packages/crud/src/components/context-menu/index.tsx create mode 100644 packages/crud/src/components/crud/helper.ts create mode 100644 packages/crud/src/components/crud/index.tsx create mode 100644 packages/crud/src/components/dialog/index.tsx create mode 100644 packages/crud/src/components/error-message/index.tsx create mode 100644 packages/crud/src/components/filter/index.tsx create mode 100644 packages/crud/src/components/flex1/index.tsx create mode 100644 packages/crud/src/components/form-card/index.tsx create mode 100644 packages/crud/src/components/form-tabs/index.tsx create mode 100644 packages/crud/src/components/form/helper/action.ts create mode 100644 packages/crud/src/components/form/helper/api.ts create mode 100644 packages/crud/src/components/form/helper/index.ts create mode 100644 packages/crud/src/components/form/helper/plugins.ts create mode 100644 packages/crud/src/components/form/helper/tabs.ts create mode 100644 packages/crud/src/components/form/index.tsx create mode 100644 packages/crud/src/components/index.tsx create mode 100644 packages/crud/src/components/multi-delete-btn/index.tsx create mode 100644 packages/crud/src/components/pagination/index.tsx create mode 100644 packages/crud/src/components/refresh-btn/index.tsx create mode 100644 packages/crud/src/components/row/index.tsx create mode 100644 packages/crud/src/components/search-key/index.tsx create mode 100644 packages/crud/src/components/search/helper/plugins.ts create mode 100644 packages/crud/src/components/search/index.tsx create mode 100644 packages/crud/src/components/table/helper/data.ts create mode 100644 packages/crud/src/components/table/helper/header.tsx create mode 100644 packages/crud/src/components/table/helper/height.ts create mode 100644 packages/crud/src/components/table/helper/index.ts create mode 100644 packages/crud/src/components/table/helper/op.ts create mode 100644 packages/crud/src/components/table/helper/plugins.ts create mode 100644 packages/crud/src/components/table/helper/render.tsx create mode 100644 packages/crud/src/components/table/helper/row.ts create mode 100644 packages/crud/src/components/table/helper/selection.ts create mode 100644 packages/crud/src/components/table/helper/sort.ts create mode 100644 packages/crud/src/components/table/index.tsx create mode 100644 packages/crud/src/components/upsert/index.tsx create mode 100644 packages/crud/src/emitter.ts create mode 100644 packages/crud/src/entry.ts create mode 100644 packages/crud/src/hooks/crud.ts create mode 100644 packages/crud/src/hooks/index.ts create mode 100644 packages/crud/src/index.ts create mode 100644 packages/crud/src/locale/en.ts create mode 100644 packages/crud/src/locale/index.ts create mode 100644 packages/crud/src/locale/ja.ts create mode 100644 packages/crud/src/locale/zh-cn.ts create mode 100644 packages/crud/src/locale/zh-tw.ts create mode 100644 packages/crud/src/main.ts create mode 100644 packages/crud/src/provide.ts create mode 100644 packages/crud/src/static/index.scss create mode 100644 packages/crud/src/test/service.ts create mode 100644 packages/crud/src/utils/form-hook.ts create mode 100644 packages/crud/src/utils/global.ts create mode 100644 packages/crud/src/utils/index.ts create mode 100644 packages/crud/src/utils/mitt.ts create mode 100644 packages/crud/src/utils/parse.tsx create mode 100644 packages/crud/src/utils/vnode.tsx create mode 100644 packages/crud/tsconfig.json create mode 100644 packages/crud/types/components/add-btn/index.d.ts create mode 100644 packages/crud/types/components/adv/btn.d.ts create mode 100644 packages/crud/types/components/adv/search.d.ts create mode 100644 packages/crud/types/components/context-menu/index.d.ts create mode 100644 packages/crud/types/components/crud/helper.d.ts create mode 100644 packages/crud/types/components/crud/index.d.ts create mode 100644 packages/crud/types/components/dialog/index.d.ts create mode 100644 packages/crud/types/components/error-message/index.d.ts create mode 100644 packages/crud/types/components/filter/index.d.ts create mode 100644 packages/crud/types/components/flex1/index.d.ts create mode 100644 packages/crud/types/components/form-card/index.d.ts create mode 100644 packages/crud/types/components/form-tabs/index.d.ts create mode 100644 packages/crud/types/components/form/helper/action.d.ts create mode 100644 packages/crud/types/components/form/helper/api.d.ts create mode 100644 packages/crud/types/components/form/helper/index.d.ts create mode 100644 packages/crud/types/components/form/helper/plugins.d.ts create mode 100644 packages/crud/types/components/form/helper/tabs.d.ts create mode 100644 packages/crud/types/components/form/index.d.ts create mode 100644 packages/crud/types/components/index.d.ts create mode 100644 packages/crud/types/components/multi-delete-btn/index.d.ts create mode 100644 packages/crud/types/components/pagination/index.d.ts create mode 100644 packages/crud/types/components/refresh-btn/index.d.ts create mode 100644 packages/crud/types/components/row/index.d.ts create mode 100644 packages/crud/types/components/search-key/index.d.ts create mode 100644 packages/crud/types/components/search/helper/plugins.d.ts create mode 100644 packages/crud/types/components/search/index.d.ts create mode 100644 packages/crud/types/components/table/helper/data.d.ts create mode 100644 packages/crud/types/components/table/helper/header.d.ts create mode 100644 packages/crud/types/components/table/helper/height.d.ts create mode 100644 packages/crud/types/components/table/helper/index.d.ts create mode 100644 packages/crud/types/components/table/helper/op.d.ts create mode 100644 packages/crud/types/components/table/helper/plugins.d.ts create mode 100644 packages/crud/types/components/table/helper/render.d.ts create mode 100644 packages/crud/types/components/table/helper/row.d.ts create mode 100644 packages/crud/types/components/table/helper/selection.d.ts create mode 100644 packages/crud/types/components/table/helper/sort.d.ts create mode 100644 packages/crud/types/components/table/index.d.ts create mode 100644 packages/crud/types/components/upsert/index.d.ts create mode 100644 packages/crud/types/emitter.d.ts create mode 100644 packages/crud/types/entry.d.ts create mode 100644 packages/crud/types/hooks/crud.d.ts create mode 100644 packages/crud/types/hooks/index.d.ts create mode 100644 packages/crud/types/locale/en.d.ts create mode 100644 packages/crud/types/locale/index.d.ts create mode 100644 packages/crud/types/locale/ja.d.ts create mode 100644 packages/crud/types/locale/zh-cn.d.ts create mode 100644 packages/crud/types/locale/zh-tw.d.ts create mode 100644 packages/crud/types/main.d.ts create mode 100644 packages/crud/types/provide.d.ts create mode 100644 packages/crud/types/test/service.d.ts create mode 100644 packages/crud/types/utils/form-hook.d.ts create mode 100644 packages/crud/types/utils/global.d.ts create mode 100644 packages/crud/types/utils/index.d.ts create mode 100644 packages/crud/types/utils/mitt.d.ts create mode 100644 packages/crud/types/utils/parse.d.ts create mode 100644 packages/crud/types/utils/vnode.d.ts create mode 100644 packages/crud/vite.config.ts create mode 100644 packages/crud/yarn.lock create mode 100644 packages/vite-plugin/.eslintrc.js create mode 100644 packages/vite-plugin/.prettierrc create mode 100644 packages/vite-plugin/client.d.ts create mode 100644 packages/vite-plugin/dist/base.d.ts create mode 100644 packages/vite-plugin/dist/config.d.ts create mode 100644 packages/vite-plugin/dist/ctx/index.d.ts create mode 100644 packages/vite-plugin/dist/demo.d.ts create mode 100644 packages/vite-plugin/dist/eps/flatten.d.ts create mode 100644 packages/vite-plugin/dist/eps/index.d.ts create mode 100644 packages/vite-plugin/dist/file/index.d.ts create mode 100644 packages/vite-plugin/dist/index.d.ts create mode 100644 packages/vite-plugin/dist/index.js create mode 100644 packages/vite-plugin/dist/plugin/index.d.ts create mode 100644 packages/vite-plugin/dist/proxy/index.d.ts create mode 100644 packages/vite-plugin/dist/svg/index.d.ts create mode 100644 packages/vite-plugin/dist/tag/index.d.ts create mode 100644 packages/vite-plugin/dist/test.d.ts create mode 100644 packages/vite-plugin/dist/uniapp-x.d.ts create mode 100644 packages/vite-plugin/dist/uniapp-x/code.d.ts create mode 100644 packages/vite-plugin/dist/uniapp-x/color.d.ts create mode 100644 packages/vite-plugin/dist/uniapp-x/config.d.ts create mode 100644 packages/vite-plugin/dist/uniapp-x/flatten.d.ts create mode 100644 packages/vite-plugin/dist/uniapp-x/index.d.ts create mode 100644 packages/vite-plugin/dist/uniapp-x/tailwind.d.ts create mode 100644 packages/vite-plugin/dist/uniapp-x/utils.d.ts create mode 100644 packages/vite-plugin/dist/utils/index.d.ts create mode 100644 packages/vite-plugin/dist/virtual.d.ts create mode 100644 packages/vite-plugin/package.json create mode 100644 packages/vite-plugin/rollup.config.js create mode 100644 packages/vite-plugin/src/base.ts create mode 100644 packages/vite-plugin/src/config.ts create mode 100644 packages/vite-plugin/src/ctx/index.ts create mode 100644 packages/vite-plugin/src/demo.ts create mode 100644 packages/vite-plugin/src/eps/index.ts create mode 100644 packages/vite-plugin/src/file/index.ts create mode 100644 packages/vite-plugin/src/index.ts create mode 100644 packages/vite-plugin/src/plugin/index.ts create mode 100644 packages/vite-plugin/src/proxy/index.ts create mode 100644 packages/vite-plugin/src/svg/index.ts create mode 100644 packages/vite-plugin/src/tag/index.ts create mode 100644 packages/vite-plugin/src/test.ts create mode 100644 packages/vite-plugin/src/uniapp-x/code.ts create mode 100644 packages/vite-plugin/src/uniapp-x/config.ts create mode 100644 packages/vite-plugin/src/uniapp-x/flatten.ts create mode 100644 packages/vite-plugin/src/uniapp-x/index.ts create mode 100644 packages/vite-plugin/src/uniapp-x/tailwind.ts create mode 100644 packages/vite-plugin/src/uniapp-x/utils.ts create mode 100644 packages/vite-plugin/src/utils/index.ts create mode 100644 packages/vite-plugin/src/virtual.ts create mode 100644 packages/vite-plugin/tsconfig.json create mode 100644 packages/vite-plugin/types/index.d.ts create mode 100644 packages/vite-plugin/yarn.lock create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml create mode 100644 postcss.config.js create mode 100644 public/favicon.ico create mode 100644 public/logo.png create mode 100644 public/用户导入模版.xlsx create mode 100644 src/App.vue create mode 100644 src/config/dev.ts create mode 100644 src/config/index.ts create mode 100644 src/config/prod.ts create mode 100644 src/config/proxy.ts create mode 100644 src/cool/bootstrap/eps.ts create mode 100644 src/cool/bootstrap/index.ts create mode 100644 src/cool/bootstrap/module.ts create mode 100644 src/cool/hooks/browser.ts create mode 100644 src/cool/hooks/hmr.ts create mode 100644 src/cool/hooks/index.ts create mode 100644 src/cool/hooks/mitt.ts create mode 100644 src/cool/index.ts create mode 100644 src/cool/index.vue create mode 100644 src/cool/module/index.ts create mode 100644 src/cool/router/index.ts create mode 100644 src/cool/service/base.ts create mode 100644 src/cool/service/index.ts create mode 100644 src/cool/service/request.ts create mode 100644 src/cool/service/stream.ts create mode 100644 src/cool/types/index.ts create mode 100644 src/cool/utils/index.ts create mode 100644 src/cool/utils/loading.ts create mode 100644 src/cool/utils/storage.ts create mode 100644 src/main.ts create mode 100644 src/modules/base/components/avatar/index.tsx create mode 100644 src/modules/base/components/code/json.vue create mode 100644 src/modules/base/components/dept/check.vue create mode 100644 src/modules/base/components/dept/select.vue create mode 100644 src/modules/base/components/editor/index.tsx create mode 100644 src/modules/base/components/icon/svg.vue create mode 100644 src/modules/base/components/image/index.vue create mode 100644 src/modules/base/components/link/index.vue create mode 100644 src/modules/base/components/menu/check.vue create mode 100644 src/modules/base/components/menu/file.vue create mode 100644 src/modules/base/components/menu/icon.vue create mode 100644 src/modules/base/components/menu/perms.vue create mode 100644 src/modules/base/components/menu/select.vue create mode 100644 src/modules/base/components/num/index.vue create mode 100644 src/modules/base/config.ts create mode 100644 src/modules/base/directives/permission.ts create mode 100644 src/modules/base/index.ts create mode 100644 src/modules/base/locales/en.json create mode 100644 src/modules/base/locales/zh-cn.json create mode 100644 src/modules/base/locales/zh-tw.json create mode 100644 src/modules/base/pages/error/401.vue create mode 100644 src/modules/base/pages/error/403.vue create mode 100644 src/modules/base/pages/error/404.vue create mode 100644 src/modules/base/pages/error/500.vue create mode 100644 src/modules/base/pages/error/502.vue create mode 100644 src/modules/base/pages/error/components/error-page.vue create mode 100644 src/modules/base/pages/kefulogin/chat.vue create mode 100644 src/modules/base/pages/kefulogin/index.vue create mode 100644 src/modules/base/pages/login/components/pic-captcha.vue create mode 100644 src/modules/base/pages/login/index.vue create mode 100644 src/modules/base/pages/login/static/bg.svg create mode 100644 src/modules/base/pages/main/components/amenu.vue create mode 100644 src/modules/base/pages/main/components/bmenu.tsx create mode 100644 src/modules/base/pages/main/components/global.vue create mode 100644 src/modules/base/pages/main/components/process.vue create mode 100644 src/modules/base/pages/main/components/route-nav.vue create mode 100644 src/modules/base/pages/main/components/slider.vue create mode 100644 src/modules/base/pages/main/components/topbar.vue create mode 100644 src/modules/base/pages/main/components/views.vue create mode 100644 src/modules/base/pages/main/index.vue create mode 100644 src/modules/base/static/css/index.scss create mode 100644 src/modules/base/static/svg/amount.svg create mode 100644 src/modules/base/static/svg/back.svg create mode 100644 src/modules/base/static/svg/close-border.svg create mode 100644 src/modules/base/static/svg/close.svg create mode 100644 src/modules/base/static/svg/delete.svg create mode 100644 src/modules/base/static/svg/edit.svg create mode 100644 src/modules/base/static/svg/exit.svg create mode 100644 src/modules/base/static/svg/expand.svg create mode 100644 src/modules/base/static/svg/export.svg create mode 100644 src/modules/base/static/svg/fail.svg create mode 100644 src/modules/base/static/svg/fold.svg create mode 100644 src/modules/base/static/svg/github.svg create mode 100644 src/modules/base/static/svg/home.svg create mode 100644 src/modules/base/static/svg/icon-activity.svg create mode 100644 src/modules/base/static/svg/icon-amount.svg create mode 100644 src/modules/base/static/svg/icon-app.svg create mode 100644 src/modules/base/static/svg/icon-approve.svg create mode 100644 src/modules/base/static/svg/icon-auth.svg create mode 100644 src/modules/base/static/svg/icon-ban.svg create mode 100644 src/modules/base/static/svg/icon-call.svg create mode 100644 src/modules/base/static/svg/icon-camera.svg create mode 100644 src/modules/base/static/svg/icon-card.svg create mode 100644 src/modules/base/static/svg/icon-cart.svg create mode 100644 src/modules/base/static/svg/icon-common.svg create mode 100644 src/modules/base/static/svg/icon-component.svg create mode 100644 src/modules/base/static/svg/icon-count.svg create mode 100644 src/modules/base/static/svg/icon-crown.svg create mode 100644 src/modules/base/static/svg/icon-data.svg create mode 100644 src/modules/base/static/svg/icon-db.svg create mode 100644 src/modules/base/static/svg/icon-delete.svg create mode 100644 src/modules/base/static/svg/icon-dept.svg create mode 100644 src/modules/base/static/svg/icon-design.svg create mode 100644 src/modules/base/static/svg/icon-device.svg create mode 100644 src/modules/base/static/svg/icon-dict.svg create mode 100644 src/modules/base/static/svg/icon-discover.svg create mode 100644 src/modules/base/static/svg/icon-doc.svg create mode 100644 src/modules/base/static/svg/icon-download.svg create mode 100644 src/modules/base/static/svg/icon-emoji.svg create mode 100644 src/modules/base/static/svg/icon-favor.svg create mode 100644 src/modules/base/static/svg/icon-file.svg create mode 100644 src/modules/base/static/svg/icon-folder.svg create mode 100644 src/modules/base/static/svg/icon-goods.svg create mode 100644 src/modules/base/static/svg/icon-home.svg create mode 100644 src/modules/base/static/svg/icon-hot.svg create mode 100644 src/modules/base/static/svg/icon-info.svg create mode 100644 src/modules/base/static/svg/icon-iot.svg create mode 100644 src/modules/base/static/svg/icon-light.svg create mode 100644 src/modules/base/static/svg/icon-like.svg create mode 100644 src/modules/base/static/svg/icon-list.svg create mode 100644 src/modules/base/static/svg/icon-local.svg create mode 100644 src/modules/base/static/svg/icon-log.svg create mode 100644 src/modules/base/static/svg/icon-map.svg create mode 100644 src/modules/base/static/svg/icon-match.svg create mode 100644 src/modules/base/static/svg/icon-menu.svg create mode 100644 src/modules/base/static/svg/icon-monitor.svg create mode 100644 src/modules/base/static/svg/icon-msg.svg create mode 100644 src/modules/base/static/svg/icon-news.svg create mode 100644 src/modules/base/static/svg/icon-notice.svg create mode 100644 src/modules/base/static/svg/icon-params.svg create mode 100644 src/modules/base/static/svg/icon-phone.svg create mode 100644 src/modules/base/static/svg/icon-pic.svg create mode 100644 src/modules/base/static/svg/icon-question.svg create mode 100644 src/modules/base/static/svg/icon-quick.svg create mode 100644 src/modules/base/static/svg/icon-rank.svg create mode 100644 src/modules/base/static/svg/icon-reward.svg create mode 100644 src/modules/base/static/svg/icon-search.svg create mode 100644 src/modules/base/static/svg/icon-set.svg create mode 100644 src/modules/base/static/svg/icon-tag.svg create mode 100644 src/modules/base/static/svg/icon-task.svg create mode 100644 src/modules/base/static/svg/icon-time.svg create mode 100644 src/modules/base/static/svg/icon-tutorial.svg create mode 100644 src/modules/base/static/svg/icon-unlock.svg create mode 100644 src/modules/base/static/svg/icon-user.svg create mode 100644 src/modules/base/static/svg/icon-video.svg create mode 100644 src/modules/base/static/svg/icon-vip.svg create mode 100644 src/modules/base/static/svg/icon-warn.svg create mode 100644 src/modules/base/static/svg/icon-work.svg create mode 100644 src/modules/base/static/svg/icon-workbench.svg create mode 100644 src/modules/base/static/svg/image.svg create mode 100644 src/modules/base/static/svg/import.svg create mode 100644 src/modules/base/static/svg/left.svg create mode 100644 src/modules/base/static/svg/my.svg create mode 100644 src/modules/base/static/svg/order.svg create mode 100644 src/modules/base/static/svg/play.svg create mode 100644 src/modules/base/static/svg/plus-border.svg create mode 100644 src/modules/base/static/svg/plus.svg create mode 100644 src/modules/base/static/svg/refresh.svg create mode 100644 src/modules/base/static/svg/right.svg create mode 100644 src/modules/base/static/svg/screen-full.svg create mode 100644 src/modules/base/static/svg/screen-normal.svg create mode 100644 src/modules/base/static/svg/search.svg create mode 100644 src/modules/base/static/svg/set.svg create mode 100644 src/modules/base/static/svg/sort.svg create mode 100644 src/modules/base/static/svg/stats.svg create mode 100644 src/modules/base/static/svg/success.svg create mode 100644 src/modules/base/static/svg/team.svg create mode 100644 src/modules/base/static/svg/trend.svg create mode 100644 src/modules/base/store/app.ts create mode 100644 src/modules/base/store/index.ts create mode 100644 src/modules/base/store/menu.ts create mode 100644 src/modules/base/store/process.ts create mode 100644 src/modules/base/store/user.ts create mode 100644 src/modules/base/types/index.d.ts create mode 100644 src/modules/base/utils/index.ts create mode 100644 src/modules/base/utils/permission.ts create mode 100644 src/modules/base/views/frame.vue create mode 100644 src/modules/base/views/info.vue create mode 100644 src/modules/base/views/log.vue create mode 100644 src/modules/base/views/menu/components/exp.vue create mode 100644 src/modules/base/views/menu/components/imp.vue create mode 100644 src/modules/base/views/menu/index.vue create mode 100644 src/modules/base/views/param.vue create mode 100644 src/modules/base/views/role.vue create mode 100644 src/modules/base/views/user/components/dept-list.vue create mode 100644 src/modules/base/views/user/components/user-move.vue create mode 100644 src/modules/base/views/user/index.vue create mode 100644 src/modules/cs/components/index.vue create mode 100644 src/modules/cs/components/message.vue create mode 100644 src/modules/cs/components/session.vue create mode 100644 src/modules/cs/components/tools/emoji.vue create mode 100644 src/modules/cs/config.ts create mode 100644 src/modules/cs/hooks/index.ts create mode 100644 src/modules/cs/hooks/message.ts create mode 100644 src/modules/cs/hooks/notice.tsx create mode 100644 src/modules/cs/hooks/session.ts create mode 100644 src/modules/cs/hooks/socket.ts create mode 100644 src/modules/cs/hooks/tools.ts create mode 100644 src/modules/cs/index.ts create mode 100644 src/modules/cs/static/audio/ding.wav create mode 100644 src/modules/cs/static/emoji/angry-face.png create mode 100644 src/modules/cs/static/emoji/anguished-face.png create mode 100644 src/modules/cs/static/emoji/astonished-face.png create mode 100644 src/modules/cs/static/emoji/confounded-face.png create mode 100644 src/modules/cs/static/emoji/confused-face.png create mode 100644 src/modules/cs/static/emoji/crying-face.png create mode 100644 src/modules/cs/static/emoji/disappointed-but-relieved-face.png create mode 100644 src/modules/cs/static/emoji/disappointed-face.png create mode 100644 src/modules/cs/static/emoji/dizzy-face.png create mode 100644 src/modules/cs/static/emoji/drooling-face.png create mode 100644 src/modules/cs/static/emoji/expressionless-face.png create mode 100644 src/modules/cs/static/emoji/face-savouring-delicious-food.png create mode 100644 src/modules/cs/static/emoji/face-screaming-in-fear.png create mode 100644 src/modules/cs/static/emoji/face-throwing-a-kiss.png create mode 100644 src/modules/cs/static/emoji/face-with-cold-sweat.png create mode 100644 src/modules/cs/static/emoji/face-with-cowboy-hat.png create mode 100644 src/modules/cs/static/emoji/face-with-finger-covering-closed-lips.png create mode 100644 src/modules/cs/static/emoji/face-with-head-bandage.png create mode 100644 src/modules/cs/static/emoji/face-with-look-of-triumph.png create mode 100644 src/modules/cs/static/emoji/face-with-medical-mask.png create mode 100644 src/modules/cs/static/emoji/face-with-monocle.png create mode 100644 src/modules/cs/static/emoji/face-with-one-eyebrow-raised.png create mode 100644 src/modules/cs/static/emoji/face-with-open-mouth-and-cold-sweat.png create mode 100644 src/modules/cs/static/emoji/face-with-open-mouth-vomiting.png create mode 100644 src/modules/cs/static/emoji/face-with-open-mouth.png create mode 100644 src/modules/cs/static/emoji/face-with-party-horn-and-party-hat.png create mode 100644 src/modules/cs/static/emoji/face-with-pleading-eyes.png create mode 100644 src/modules/cs/static/emoji/face-with-rolling-eyes.png create mode 100644 src/modules/cs/static/emoji/face-with-stuck-out-tongue-and-tightly-closed-eyes.png create mode 100644 src/modules/cs/static/emoji/face-with-stuck-out-tongue-and-winking-eye.png create mode 100644 src/modules/cs/static/emoji/face-with-stuck-out-tongue.png create mode 100644 src/modules/cs/static/emoji/face-with-thermometer.png create mode 100644 src/modules/cs/static/emoji/face-with-uneven-eyes-and-wavy-mouth.png create mode 100644 src/modules/cs/static/emoji/face-without-mouth.png create mode 100644 src/modules/cs/static/emoji/fearful-face.png create mode 100644 src/modules/cs/static/emoji/flushed-face.png create mode 100644 src/modules/cs/static/emoji/freezing-face.png create mode 100644 src/modules/cs/static/emoji/frowning-face-with-open-mouth.png create mode 100644 src/modules/cs/static/emoji/grimacing-face.png create mode 100644 src/modules/cs/static/emoji/grinning-face-with-one-large-and-one-small-eye.png create mode 100644 src/modules/cs/static/emoji/grinning-face-with-smiling-eyes.png create mode 100644 src/modules/cs/static/emoji/grinning-face-with-star-eyes.png create mode 100644 src/modules/cs/static/emoji/grinning-face.png create mode 100644 src/modules/cs/static/emoji/hugging-face.png create mode 100644 src/modules/cs/static/emoji/hushed-face.png create mode 100644 src/modules/cs/static/emoji/imp.png create mode 100644 src/modules/cs/static/emoji/kissing-face-with-closed-eyes.png create mode 100644 src/modules/cs/static/emoji/kissing-face-with-smiling-eyes.png create mode 100644 src/modules/cs/static/emoji/kissing-face.png create mode 100644 src/modules/cs/static/emoji/loudly-crying-face.png create mode 100644 src/modules/cs/static/emoji/lying-face.png create mode 100644 src/modules/cs/static/emoji/money-mouth-face.png create mode 100644 src/modules/cs/static/emoji/nauseated-face.png create mode 100644 src/modules/cs/static/emoji/nerd-face.png create mode 100644 src/modules/cs/static/emoji/neutral-face.png create mode 100644 src/modules/cs/static/emoji/overheated-face.png create mode 100644 src/modules/cs/static/emoji/pensive-face.png create mode 100644 src/modules/cs/static/emoji/persevering-face.png create mode 100644 src/modules/cs/static/emoji/pouting-face.png create mode 100644 src/modules/cs/static/emoji/relieved-face.png create mode 100644 src/modules/cs/static/emoji/rolling-on-the-floor-laughing.png create mode 100644 src/modules/cs/static/emoji/serious-face-with-symbols-covering-mouth.png create mode 100644 src/modules/cs/static/emoji/shocked-face-with-exploding-head.png create mode 100644 src/modules/cs/static/emoji/sleeping-face.png create mode 100644 src/modules/cs/static/emoji/sleepy-face.png create mode 100644 src/modules/cs/static/emoji/slightly-frowning-face.png create mode 100644 src/modules/cs/static/emoji/slightly-smiling-face.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-halo.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-heart-shaped-eyes.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-horns.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-open-mouth-and-smiling-eyes.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-open-mouth-and-tightly-closed-eyes.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-open-mouth.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-smiling-eyes-and-hand-covering-mouth.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-smiling-eyes-and-three-hearts.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-smiling-eyes.png create mode 100644 src/modules/cs/static/emoji/smiling-face-with-sunglasses.png create mode 100644 src/modules/cs/static/emoji/smirking-face.png create mode 100644 src/modules/cs/static/emoji/sneezing-face.png create mode 100644 src/modules/cs/static/emoji/thinking-face.png create mode 100644 src/modules/cs/static/emoji/tired-face.png create mode 100644 src/modules/cs/static/emoji/upside-down-face.png create mode 100644 src/modules/cs/static/emoji/weary-face.png create mode 100644 src/modules/cs/static/emoji/white-frowning-face.png create mode 100644 src/modules/cs/static/emoji/white-smiling-face.png create mode 100644 src/modules/cs/static/emoji/winking-face.png create mode 100644 src/modules/cs/static/emoji/worried-face.png create mode 100644 src/modules/cs/static/emoji/zipper-mouth-face.png create mode 100644 src/modules/cs/types/index.d.ts create mode 100644 src/modules/cs/utils/index.ts create mode 100644 src/modules/cs/views/chat.vue create mode 100644 src/modules/demo/config.ts create mode 100644 src/modules/demo/directives/color.ts create mode 100644 src/modules/demo/locales/en.json create mode 100644 src/modules/demo/locales/zh-cn.json create mode 100644 src/modules/demo/locales/zh-tw.json create mode 100644 src/modules/demo/views/crud/components/adv-search/base.vue create mode 100644 src/modules/demo/views/crud/components/adv-search/custom.vue create mode 100644 src/modules/demo/views/crud/components/code.vue create mode 100644 src/modules/demo/views/crud/components/crud/all.vue create mode 100644 src/modules/demo/views/crud/components/crud/base.vue create mode 100644 src/modules/demo/views/crud/components/crud/dict.vue create mode 100644 src/modules/demo/views/crud/components/crud/event.vue create mode 100644 src/modules/demo/views/crud/components/crud/select-table.vue create mode 100644 src/modules/demo/views/crud/components/crud/service.vue create mode 100644 src/modules/demo/views/crud/components/crud/user-select.vue create mode 100644 src/modules/demo/views/crud/components/form/children.vue create mode 100644 src/modules/demo/views/crud/components/form/component/index.vue create mode 100644 src/modules/demo/views/crud/components/form/component/select-labels.vue create mode 100644 src/modules/demo/views/crud/components/form/component/select-status.vue create mode 100644 src/modules/demo/views/crud/components/form/component/select-work.vue create mode 100644 src/modules/demo/views/crud/components/form/component/select-work2.vue create mode 100644 src/modules/demo/views/crud/components/form/config.vue create mode 100644 src/modules/demo/views/crud/components/form/crud.vue create mode 100644 src/modules/demo/views/crud/components/form/disabled.vue create mode 100644 src/modules/demo/views/crud/components/form/event.vue create mode 100644 src/modules/demo/views/crud/components/form/group.vue create mode 100644 src/modules/demo/views/crud/components/form/hidden.vue create mode 100644 src/modules/demo/views/crud/components/form/layout.vue create mode 100644 src/modules/demo/views/crud/components/form/open.vue create mode 100644 src/modules/demo/views/crud/components/form/options.vue create mode 100644 src/modules/demo/views/crud/components/form/plugin/index.vue create mode 100644 src/modules/demo/views/crud/components/form/plugin/role.ts create mode 100644 src/modules/demo/views/crud/components/form/required.vue create mode 100644 src/modules/demo/views/crud/components/form/rules.vue create mode 100644 src/modules/demo/views/crud/components/form/setFocus.vue create mode 100644 src/modules/demo/views/crud/components/other/context-menu.vue create mode 100644 src/modules/demo/views/crud/components/other/tips.vue create mode 100644 src/modules/demo/views/crud/components/other/tsx/index.scss create mode 100644 src/modules/demo/views/crud/components/other/tsx/index.tsx create mode 100644 src/modules/demo/views/crud/components/search/base.vue create mode 100644 src/modules/demo/views/crud/components/search/collapse.vue create mode 100644 src/modules/demo/views/crud/components/search/custom.vue create mode 100644 src/modules/demo/views/crud/components/search/layout.vue create mode 100644 src/modules/demo/views/crud/components/search/plugin.vue create mode 100644 src/modules/demo/views/crud/components/table/base.vue create mode 100644 src/modules/demo/views/crud/components/table/children.vue create mode 100644 src/modules/demo/views/crud/components/table/column-custom.vue create mode 100644 src/modules/demo/views/crud/components/table/component/index.vue create mode 100644 src/modules/demo/views/crud/components/table/component/user-info.vue create mode 100644 src/modules/demo/views/crud/components/table/context-menu.vue create mode 100644 src/modules/demo/views/crud/components/table/dict.vue create mode 100644 src/modules/demo/views/crud/components/table/formatter.vue create mode 100644 src/modules/demo/views/crud/components/table/hidden.vue create mode 100644 src/modules/demo/views/crud/components/table/op.vue create mode 100644 src/modules/demo/views/crud/components/table/plugin/base.vue create mode 100644 src/modules/demo/views/crud/components/table/plugin/row-edit.vue create mode 100644 src/modules/demo/views/crud/components/table/plugin/to-tree.vue create mode 100644 src/modules/demo/views/crud/components/table/search.vue create mode 100644 src/modules/demo/views/crud/components/table/selection.vue create mode 100644 src/modules/demo/views/crud/components/table/slot.vue create mode 100644 src/modules/demo/views/crud/components/table/span-method.vue create mode 100644 src/modules/demo/views/crud/components/table/summary.vue create mode 100644 src/modules/demo/views/crud/components/upsert/base.vue create mode 100644 src/modules/demo/views/crud/components/upsert/event.vue create mode 100644 src/modules/demo/views/crud/components/upsert/hook/index.vue create mode 100644 src/modules/demo/views/crud/components/upsert/hook/reg-pca2.ts create mode 100644 src/modules/demo/views/crud/components/upsert/mode.vue create mode 100644 src/modules/demo/views/crud/index.vue create mode 100644 src/modules/demo/views/home/components/category-ratio.vue create mode 100644 src/modules/demo/views/home/components/count-effect.vue create mode 100644 src/modules/demo/views/home/components/count-paid.vue create mode 100644 src/modules/demo/views/home/components/count-user.vue create mode 100644 src/modules/demo/views/home/components/count-views.vue create mode 100644 src/modules/demo/views/home/components/hot-goods.vue create mode 100644 src/modules/demo/views/home/components/tab-chart.vue create mode 100644 src/modules/demo/views/home/index.vue create mode 100644 src/modules/demo/views/test/route.vue create mode 100644 src/modules/dict/config.ts create mode 100644 src/modules/dict/index.ts create mode 100644 src/modules/dict/locales/en.json create mode 100644 src/modules/dict/locales/zh-cn.json create mode 100644 src/modules/dict/locales/zh-tw.json create mode 100644 src/modules/dict/store/dict.ts create mode 100644 src/modules/dict/store/index.ts create mode 100644 src/modules/dict/types/index.d.ts create mode 100644 src/modules/dict/utils/index.ts create mode 100644 src/modules/dict/views/list.vue create mode 100644 src/modules/helper/components/ai-code/btn.vue create mode 100644 src/modules/helper/components/ai-code/dev.vue create mode 100644 src/modules/helper/components/auto-menu.vue create mode 100644 src/modules/helper/components/auto-perms.vue create mode 100644 src/modules/helper/config.ts create mode 100644 src/modules/helper/hooks/index.ts create mode 100644 src/modules/helper/hooks/menu.ts create mode 100644 src/modules/helper/hooks/plugin.ts create mode 100644 src/modules/helper/locales/en.json create mode 100644 src/modules/helper/locales/zh-cn.json create mode 100644 src/modules/helper/locales/zh-tw.json create mode 100644 src/modules/helper/static/index.scss create mode 100644 src/modules/helper/static/svg/icon-vue.svg create mode 100644 src/modules/helper/types/index.d.ts create mode 100644 src/modules/helper/views/ai-code.vue create mode 100644 src/modules/helper/views/plugins.vue create mode 100644 src/modules/recycle/locales/en.json create mode 100644 src/modules/recycle/locales/zh-cn.json create mode 100644 src/modules/recycle/locales/zh-tw.json create mode 100644 src/modules/recycle/views/data.vue create mode 100644 src/modules/space/components/space-inner.vue create mode 100644 src/modules/space/components/space.vue create mode 100644 src/modules/space/config.ts create mode 100644 src/modules/space/hooks/index.ts create mode 100644 src/modules/space/locales/en.json create mode 100644 src/modules/space/locales/zh-cn.json create mode 100644 src/modules/space/locales/zh-tw.json create mode 100644 src/modules/space/views/list.vue create mode 100644 src/modules/staff/views/list.vue create mode 100644 src/modules/task/components/logs.vue create mode 100644 src/modules/task/locales/en.json create mode 100644 src/modules/task/locales/zh-cn.json create mode 100644 src/modules/task/locales/zh-tw.json create mode 100644 src/modules/task/views/list.vue create mode 100644 src/modules/user/components/user-select.vue create mode 100644 src/modules/user/config.ts create mode 100644 src/modules/user/locales/en.json create mode 100644 src/modules/user/locales/zh-cn.json create mode 100644 src/modules/user/locales/zh-tw.json create mode 100644 src/modules/user/views/list.vue create mode 100644 src/plugins/crud/comm/index.ts create mode 100644 src/plugins/crud/components/column-custom/index.vue create mode 100644 src/plugins/crud/components/date/picker.vue create mode 100644 src/plugins/crud/components/date/text.vue create mode 100644 src/plugins/crud/components/dict/index.tsx create mode 100644 src/plugins/crud/components/number/range.vue create mode 100644 src/plugins/crud/components/render/index.tsx create mode 100644 src/plugins/crud/components/select/button.tsx create mode 100644 src/plugins/crud/components/select/index.scss create mode 100644 src/plugins/crud/components/select/index.tsx create mode 100644 src/plugins/crud/components/select/table.vue create mode 100644 src/plugins/crud/components/switch/index.tsx create mode 100644 src/plugins/crud/components/text/index.tsx create mode 100644 src/plugins/crud/components/user/select.vue create mode 100644 src/plugins/crud/config.ts create mode 100644 src/plugins/crud/index.ts create mode 100644 src/plugins/crud/locales/en.json create mode 100644 src/plugins/crud/locales/zh-cn.json create mode 100644 src/plugins/crud/locales/zh-tw.json create mode 100644 src/plugins/crud/plugins/form/index.ts create mode 100644 src/plugins/crud/plugins/form/setFocus.ts create mode 100644 src/plugins/crud/plugins/index.ts create mode 100644 src/plugins/crud/plugins/search/index.ts create mode 100644 src/plugins/crud/plugins/search/setAuto.ts create mode 100644 src/plugins/crud/plugins/table/index.ts create mode 100644 src/plugins/crud/plugins/table/rowEdit.tsx create mode 100644 src/plugins/crud/plugins/table/toTree.ts create mode 100644 src/plugins/dev-tools/components/account.vue create mode 100644 src/plugins/dev-tools/components/dict.vue create mode 100644 src/plugins/dev-tools/components/doc.vue create mode 100644 src/plugins/dev-tools/components/eps.vue create mode 100644 src/plugins/dev-tools/components/index.vue create mode 100644 src/plugins/dev-tools/components/proxy.vue create mode 100644 src/plugins/dev-tools/config.ts create mode 100644 src/plugins/dev-tools/locales/en.json create mode 100644 src/plugins/dev-tools/locales/zh-cn.json create mode 100644 src/plugins/dev-tools/locales/zh-tw.json create mode 100644 src/plugins/dev-tools/static/cool.png create mode 100644 src/plugins/dev-tools/static/echarts.png create mode 100644 src/plugins/dev-tools/static/element-plus.png create mode 100644 src/plugins/dev-tools/static/lodash.png create mode 100644 src/plugins/dev-tools/static/logo.png create mode 100644 src/plugins/dev-tools/static/pinia.png create mode 100644 src/plugins/dev-tools/static/tailwindcss.png create mode 100644 src/plugins/dev-tools/static/vite.png create mode 100644 src/plugins/dev-tools/static/vue.png create mode 100644 src/plugins/dev-tools/utils/index.ts create mode 100644 src/plugins/distpicker/components/index.tsx create mode 100644 src/plugins/distpicker/config.ts create mode 100644 src/plugins/distpicker/data/pca.json create mode 100644 src/plugins/distpicker/demo/base.vue create mode 100644 src/plugins/echarts/config.ts create mode 100644 src/plugins/editor-preview/components/preview.vue create mode 100644 src/plugins/editor-preview/config.ts create mode 100644 src/plugins/editor-preview/demo/base.vue create mode 100644 src/plugins/editor-preview/locales/en.json create mode 100644 src/plugins/editor-preview/locales/zh-cn.json create mode 100644 src/plugins/editor-preview/locales/zh-tw.json create mode 100644 src/plugins/editor-wang/components/wang.vue create mode 100644 src/plugins/editor-wang/config.ts create mode 100644 src/plugins/editor-wang/demo/base.vue create mode 100644 src/plugins/editor-wang/locales/en.json create mode 100644 src/plugins/editor-wang/locales/zh-cn.json create mode 100644 src/plugins/editor-wang/locales/zh-tw.json create mode 100644 src/plugins/element-ui/config.ts create mode 100644 src/plugins/element-ui/css/index.scss create mode 100644 src/plugins/excel/components/export-btn.tsx create mode 100644 src/plugins/excel/components/import-btn.vue create mode 100644 src/plugins/excel/config.ts create mode 100644 src/plugins/excel/demo/base.vue create mode 100644 src/plugins/excel/locales/en.json create mode 100644 src/plugins/excel/locales/zh-cn.json create mode 100644 src/plugins/excel/locales/zh-tw.json create mode 100644 src/plugins/excel/utils/index.ts create mode 100644 src/plugins/github/components/code.vue create mode 100644 src/plugins/github/config.ts create mode 100644 src/plugins/i18n/components/switch.vue create mode 100644 src/plugins/i18n/config.ts create mode 100644 src/plugins/i18n/index.ts create mode 100644 src/plugins/i18n/static/svg/lang.svg create mode 100644 src/plugins/iconfont/config.ts create mode 100644 src/plugins/iconfont/index.ts create mode 100644 src/plugins/iconfont/utils/index.ts create mode 100644 src/plugins/tailwind/config.ts create mode 100644 src/plugins/tailwind/static/index.css create mode 100644 src/plugins/theme/components/theme.vue create mode 100644 src/plugins/theme/config.ts create mode 100644 src/plugins/theme/hooks/index.ts create mode 100644 src/plugins/theme/index.ts create mode 100644 src/plugins/theme/locales/en.json create mode 100644 src/plugins/theme/locales/zh-cn.json create mode 100644 src/plugins/theme/locales/zh-tw.json create mode 100644 src/plugins/theme/static/css/index.scss create mode 100644 src/plugins/theme/static/svg/dark.svg create mode 100644 src/plugins/theme/static/svg/light.svg create mode 100644 src/plugins/theme/static/svg/theme.svg create mode 100644 src/plugins/theme/types/index.d.ts create mode 100644 src/plugins/theme/utils/index.ts create mode 100644 src/plugins/upload/components/upload-item/index.vue create mode 100644 src/plugins/upload/components/upload-item/viewer.vue create mode 100644 src/plugins/upload/components/upload.vue create mode 100644 src/plugins/upload/config.ts create mode 100644 src/plugins/upload/demo/base.vue create mode 100644 src/plugins/upload/demo/check.vue create mode 100644 src/plugins/upload/demo/custom.vue create mode 100644 src/plugins/upload/demo/drag.vue create mode 100644 src/plugins/upload/demo/file.vue create mode 100644 src/plugins/upload/demo/multiple.vue create mode 100644 src/plugins/upload/demo/small.vue create mode 100644 src/plugins/upload/demo/space.vue create mode 100644 src/plugins/upload/hooks/index.ts create mode 100644 src/plugins/upload/index.ts create mode 100644 src/plugins/upload/locales/en.json create mode 100644 src/plugins/upload/locales/zh-cn.json create mode 100644 src/plugins/upload/locales/zh-tw.json create mode 100644 src/plugins/upload/static/svg/audio.svg create mode 100644 src/plugins/upload/static/svg/excel.svg create mode 100644 src/plugins/upload/static/svg/file.svg create mode 100644 src/plugins/upload/static/svg/image.svg create mode 100644 src/plugins/upload/static/svg/pdf.svg create mode 100644 src/plugins/upload/static/svg/ppt.svg create mode 100644 src/plugins/upload/static/svg/rar.svg create mode 100644 src/plugins/upload/static/svg/video.svg create mode 100644 src/plugins/upload/static/svg/word.svg create mode 100644 src/plugins/upload/types/index.d.ts create mode 100644 src/plugins/upload/utils/index.ts create mode 100644 src/plugins/view/components/group.vue create mode 100644 src/plugins/view/components/head.vue create mode 100644 src/plugins/view/config.ts create mode 100644 src/plugins/view/demo/group.vue create mode 100644 src/plugins/view/demo/head.vue create mode 100644 src/plugins/view/hooks/group.ts create mode 100644 src/plugins/view/hooks/index.ts create mode 100644 src/plugins/view/index.ts create mode 100644 src/plugins/view/locales/en.json create mode 100644 src/plugins/view/locales/zh-cn.json create mode 100644 src/plugins/view/locales/zh-tw.json create mode 100644 src/plugins/view/types/index.d.ts create mode 100644 src/shims-vue.d.ts create mode 100644 tailwind.config.js create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.cursor/rules/adv-search.mdc b/.cursor/rules/adv-search.mdc new file mode 100644 index 0000000..153f4d8 --- /dev/null +++ b/.cursor/rules/adv-search.mdc @@ -0,0 +1,305 @@ +--- +description: cl-adv-search 组件示例 +globs: *.tsx, *.ts, *.vue +--- +## 起步 示例 + +```vue + + + + +``` + +## 自定义 示例 + +```vue + + + + +``` \ No newline at end of file diff --git a/.cursor/rules/crud.mdc b/.cursor/rules/crud.mdc new file mode 100644 index 0000000..c1af823 --- /dev/null +++ b/.cursor/rules/crud.mdc @@ -0,0 +1,1480 @@ +--- +description: cl-crud 组件示例 +globs: *.tsx, *.ts, *.vue +--- +## 完整示例 示例 + +```vue + + + + +``` + +## 起步 示例 + +```vue + + + + +``` + +## 修改文案 / 接口 示例 + +```vue + + + + +``` + +## 事件监听 示例 + +```vue + + + + +``` + +## 选择表格 示例 + +```vue + + + + +``` + +## Service 配置 示例 + +```vue + + + + +``` + +## 选择成员 示例 + +```vue + + + + +``` \ No newline at end of file diff --git a/.cursor/rules/form.mdc b/.cursor/rules/form.mdc new file mode 100644 index 0000000..60ec859 --- /dev/null +++ b/.cursor/rules/form.mdc @@ -0,0 +1,1820 @@ +--- +description: cl-form 组件示例 +globs: *.tsx, *.ts, *.vue +--- +## 层级显示 示例 + +```vue + + + + +``` + +## 组件渲染 示例 + +```vue + + + + +``` + +## select-labels 示例 + +```vue + + + + + +``` + +## select-status 示例 + +```vue + + + + + +``` + +## select-work 示例 + +```vue + + + + + +``` + +## select-work2 示例 + +```vue + + + + + +``` + +## 参数配置 示例 + +```vue + + + + +``` + +## 内嵌CRUD 示例 + +```vue + + + + +``` + +## 组件禁用 示例 + +```vue + + + + +``` + +## 组件事件 示例 + +```vue + + + + +``` + +## 分组显示 示例 + +```vue + + + + +``` + +## 隐藏/显示 示例 + +```vue + + + + +``` + +## 布局 示例 + +```vue + + + + +``` + +## 起步 示例 + +```vue + + + + +``` + +## 选项框配置 示例 + +```vue + + + + +``` + +## 插件的使用 示例 + +```vue + + + + +``` + +## 必填项配置 示例 + +```vue + + + + +``` + +## 添加/删除表单项 示例 + +```vue + + + + + + +``` \ No newline at end of file diff --git a/.cursor/rules/module.mdc b/.cursor/rules/module.mdc new file mode 100644 index 0000000..daa2139 --- /dev/null +++ b/.cursor/rules/module.mdc @@ -0,0 +1,464 @@ +--- +description: module | plugins 模块、插件 +globs: +--- +# 模块/插件开发 + +## 目录结构 + +在 `src/modules` 或 `src/plugins` 下添加一个目录 `demo`: + +```js +demo + ├──pages // 页面路由 + ├──views // 视图路由 + ├──hooks // 常用函数 + ├──components // 常用组件 + ├──directives // 指令 + ├──static // 静态文件目录 + ├──store // 状态管理 + ├──... // 其他自定义文件 + ├──config.ts // 配置文件 + └──index.ts // 入口文件 +``` + +::: warning +约定的目录名称不可修改,但可自行添加或者删除。 +::: + +## pages、views + +1. 页面参与权限控制,所以不主动注册目录下的路由,通过 `菜单列表` 中配置注册。或者在 `config.ts` 中手动配置: + +```js +import { type ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + views: [ + { + path: "/demo", + meta: { + label: "测试", + }, + component: () => import("./views/demo.vue"), + }, + ], + pages: [ + { + path: "/demo2", + meta: { + label: "测试", + }, + component: () => import("./pages/demo.vue"), + }, + ], + }; +}; +``` + +2. 使页面参与路由缓存,配置 `name` 参数 + +:::warning + +`path` 与 `name` 的匹配规则: + +- /demo/t1 = demo-t1 +- /demo/t1-det = demo-t1-det + +::: + +方式 1: + +```html + +``` + +方式 2: + +```html + +``` + +## components + +目录下的组件,全局注册配置方法如下: + +```js +import { ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + components: [ + import("./components/demo.vue"), + import("./components/demo1.vue"), + ], + }; +}; +``` + +## directives + +`directives` 会以目录下的文件名分别注册指令 + +```ts +// demo/directives/test.ts +export default { + created(el, binding) {}, + mounted() {}, + ... +}; +``` + +使用 + +```html +
+``` + +## store + +使用 `pinia` 的推荐写法: + +```ts +import { defineStore } from "pinia"; +import { ref } from "vue"; + +export const useTestStore = defineStore("test", function () { + const count = ref(0); + + function add() { + count.value += 1; + } + + return { + count, + add, + }; +}); +``` + +使用 + +```ts +import { useTestStore } from "/$/demo/store"; + +const test = useTestStore(); + +test.add(); + +console.log(test.count); // 1 +``` + +::: tip +参考 `base` 模块下 `store` 的导出方式 +::: + +## config.ts + +模块的配置,程序运行时会读取该文件。 + +- 全局组件、路由的导入 + +- 事件钩子 + +输入 `module-config` 关键字,`vscode` 中会自动生成: + +```ts +import { ModuleConfig } from "/@/cool"; +import { Vue } from "vue"; + +export default (): ModuleConfig => { + return { + // 是否启用 + enable: true, + + // 插件名称 + label: "插件名称", + + // 插件描述 + description: "插件描述", + + // 作者 + author: "作者", + version: "1.0.0", + updateTime: "2024-02-02", + logo: "", + + // 忽略 + ignore: { + // 忽略进度条的请求 + NProgress: [ + "/base/open/eps", + "/base/comm/person", + "/base/comm/permmenu", + "/base/comm/upload", + "/base/comm/uploadMode", + ], + + // 忽略 token 的路由 + token: ["/login", "/401", "/403", "/404", "/500", "/502"], + }, + + // 排序 + order: 0, + + // 配置参数 + options: { + name: "神仙", + }, + + // 示例页面 + demo: [ + { + name: "基础用法", + component: () => import("..."), + }, + ], + + // 注册全局组件 + components: [], + + // 视图路由 + views: [], + + // 页面路由 + pages: [], + + // 顶部工具栏 + toolbar: { + order: 1, + pc: true, // 是否在 pc 端显示 + h5: true, // 是否在 h5 端显示 + component: import("./components/index.vue"), + }, + + // 注入全局组件 + index: { + component: import("./components/index.vue"), + }, + + // 安装时触发 + install(app: Vue) {}, + + // 加载时触发 + onLoad(events) {}, + }; +}; +``` + +- order 模块加载顺序,值越大越先 + +- options 提供给外部使用的参数配置: + +```ts +import { ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + options: { + // 尺寸 + size: 120, + // 显示文案 + text: "选择文件", + // 限制 + limit: { + // 上传最大数量 + upload: 9, + // 文件空间选择数 + select: 9, + // 上传大小限制 + size: 100, + }, + }, + }; +}; +``` + +获取方式: + +```ts +import { module } from "/@/cool"; + +const config = module.config("模块名"); +``` + +- components 提供全局的组件: + +```ts +import type { ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + components: [import("./components/test.vue")], + }; +}; +``` + +批量导入可以使用 [import.meta.glob](mdc:https:/vitejs.dev/guide/features.html#glob-import) 方法: + +```ts +import { ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + components: Object.values(import.meta.glob("./components/**/*")), + }; +}; +``` + +- views 全局注册的视图路由,存放在 `/` 中的子路由 `children`: + +```ts +import { ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + views: [ + { + path: "/test", + meta: { + label: "测试中心", + }, + component: () => import("./views/test.vue"), + }, + ], + }; +}; +``` + +- pages 全局注册的页面路由: + +```ts +import { ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + pages: [ + { + path: "/test", + meta: { + label: "测试中心", + }, + component: () => import("./views/test.vue"), + }, + ], + }; +}; +``` + +- install 模块安装时触发。用于预先处理: + +```ts +import { ModuleConfig } from "/@/cool"; +import { Vue } from "vue"; + +export default (): ModuleConfig => { + return { + install(app: Vue) { + // 注册组件 + app.component("test", Test); + + // 注册指令 + app.directive("focus", { + created(el, bind) {}, + }); + }, + }; +}; +``` + +- onLoad 模块安装时触发,预先加载数据,如菜单配置、用户信息: + + 1. 使用 `await` 等待加载完成后往下执行 + + 2. 可往下模块导出某个方法和变量,如 `hasToken` 验证是否有登陆 + +```ts +import { ModuleConfig } from "/@/cool"; +import { Vue } from "vue"; + +export default (): ModuleConfig => { + return { + async onLoad() { + const { user, menu } = useStore(); + + if (user.token) { + // 获取用户信息 + user.get(); + // 获取菜单权限 + await menu.get(); + } + + return { + async hasToken(cb: () => Promise | void) { + if (user.token) { + if (cb) await cb(); + } + }, + }; + }, + }; +}; +``` + +其他模块中接收 `hasToken` 方法: + +```ts +import { ModuleConfig } from "/@/cool"; +import { useDict } from "./index"; + +export default (): ModuleConfig => { + return { + onLoad({ hasToken }) { + const { dict } = useDict(); + + hasToken(() => { + dict.refresh(); + }); + }, + }; +}; +``` + +## index.ts + +该模块需要对外开放的变量及方法,方便于别人直接使用: + +```ts +// modules/test/index.ts +import { useStore } from "./store"; + +export function useTest() { + return { + // 导出 pinia + ...useStore(), + + // 自定义方法 + test() {}, + + // 自定义变量 + data: { + description: "数据描述", + }, + }; +} +``` + +导出命名规则 `useBase` `useDemo` `useDict` use + 模块名 + +使用: + +```ts +import { useTest } from "/$/test"; + +const { data, test } = useTest(); +``` diff --git a/.cursor/rules/search.mdc b/.cursor/rules/search.mdc new file mode 100644 index 0000000..5f6f16f --- /dev/null +++ b/.cursor/rules/search.mdc @@ -0,0 +1,743 @@ +--- +description: cl-search 组件示例 +globs: *.tsx, *.ts, *.vue +--- +## 起步 示例 + +```vue + + + + +``` + +## 折叠 示例 + +```vue + + + +x + +``` + +## 自定义 示例 + +```vue + + + + +``` + +## 布局 示例 + +```vue + + + + +``` + +## 使用插件 示例 + +```vue + + + + +``` \ No newline at end of file diff --git a/.cursor/rules/table.mdc b/.cursor/rules/table.mdc new file mode 100644 index 0000000..2443933 --- /dev/null +++ b/.cursor/rules/table.mdc @@ -0,0 +1,2117 @@ +--- +description: cl-table 组件示例 +globs: *.tsx, *.ts, *.vue +--- +## 起步 示例 + +```vue + + + + +``` + +## 多级表头 示例 + +```vue + + + + +``` + +## 自定义列展示 示例 + +```vue + + + + +``` + +## 组件渲染 示例 + +```vue + + + + +``` + +## user-info 示例 + +```vue + + + + + + + +``` + +## 右键菜单 示例 + +```vue + + + + +``` + +## 字典匹配 示例 + +```vue + + + + +``` + +## 数据格式化 示例 + +```vue + + + + +``` + +## 隐藏/显示 示例 + +```vue + + + + +``` + +## 操作栏 示例 + +```vue + + + + +``` + +## 插件的使用 示例 + +```vue + + + + +``` + +## 行编辑 示例 + +```vue + + + + +``` + +## 表头搜索 示例 + +```vue + + + + +``` + +## 多选框数据 示例 + +```vue + + + + +``` + +## 插槽的使用 示例 + +```vue + + + + +``` + +## 合并行或列 示例 + +```vue + + + + +``` + +## 表尾合计行 示例 + +```vue + + + + +``` \ No newline at end of file diff --git a/.cursor/rules/upsert.mdc b/.cursor/rules/upsert.mdc new file mode 100644 index 0000000..1b34574 --- /dev/null +++ b/.cursor/rules/upsert.mdc @@ -0,0 +1,716 @@ +--- +description: cl-upsert 组件示例 +globs: *.tsx, *.ts, *.vue +--- +## 起步 示例 + +```vue + + + + +``` + +## 打开、关闭、提交等事件 示例 + +```vue + + + + +``` + +## Hook的使用 示例 + +```vue + + + + +``` + +## 新增、编辑、详情模式 示例 + +```vue + + + + +``` \ No newline at end of file diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..c0df244 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,74 @@ +# 项目背景 + +- 库:typescript、javaScript、scss、vue、tailwind +- 框架:cool-admin-vue +- 项目版本:8.x + +# 项目目录 + +├── .vscode(代码片段,根据关键字可以快速地生成代码) +├── public(静态资源文件) +├── packages(源码包:@cool-vue/crud、@cool-vue/vite-plugin) +├── build +│ └── cool() +│ │ └── eps.json(Eps 配置文件) +│ │ └── eps.d.ts(Eps 描述文件) +├── src +│ └── cool(核心文件) +│ └── modules(项目模块) +│ │ └── base(基础模块) +│ │ └── demo(示例模块) +│ │ └── dict(字典模块) +│ │ └── helper(辅助模块) +│ │ └── recycle(回收站模块) +│ │ └── space(cl-upload-space 文件空间模块) +│ │ └── task(任务模块) +│ │ └── user(用户模块) +│ └── plugins(项目插件) +│ │ └── crud(cl-crud、@cool-vue/crud) +│ │ └── distpicker(cl-distpicker、省市区选择器) +│ │ └── echarts(图标) +│ │ └── editor-preview(编辑器预览组件) +│ │ └── editor-wange(wang富文本编辑器) +│ │ └── element-ui(element-plus 组件) +│ │ └── excel(excel导入、导出组件) +│ │ └── i18n(多语言) +│ │ └── iconfont(iconfont 图标) +│ │ └── theme(cl-theme 主题组件) +│ │ └── upload(cl-upload 文件上传组件) +│ │ └── view(cl-view-group、cl-view-head 视图组件) +│ └── config +│ │ └── index.ts(默认配置) +│ │ └── dev.ts(开发环境) +│ │ └── prod.ts(生产环境) +│ │ └── proxy.ts(代理配置) +│ └── App.vue(入口文件) +│ └── main.ts(入口文件) +├── package.json(依赖管理,项目信息) +└── ... + +模块、插件目录 +├── modules/plugins +│ └── base(模块名) +│ │ └── components(全局组件) +│ │ └── directives(全局指令) +│ │ └── locales(国际化) +│ │ └── router(路由) +│ │ └── store(状态管理) +│ │ └── utils(工具函数) +│ │ └── views(视图) +│ │ └── config.ts(必须,模块的配置) +│ │ └── index.ts(模块导出) + +# 其它 + +- 文件、组件命名用 - 连接,如:student-info.vue +- service 的描述类型,查看 build/cool/eps.d.ts 描述文件 +- 创建模块、插件代码需要读取.cursor/rules的module.mdc,其它的rules根据需要进行参考 + +# import 引用别名 + +- "/@" 对应 "./src" +- "/$" 对应 "./src/modules" +- "/#" 对应 "./src/plugins" +- "/~" 对应 "./packages" diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d451ff1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..284364f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}] +charset = utf-8 +end_of_line = lf +indent_style = tab +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.env b/.env new file mode 100644 index 0000000..028356d --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +# 应用名称 +VITE_NAME = "COOL-ADMIN" + +# 网络超时请求时间 +VITE_TIMEOUT = 30000 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e41187f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +*.js text eol=lf +*.json text eol=lf +*.ts text eol=lf +*.vue text eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..615a016 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +.DS_Store +node_modules/ +/dist/ +dist-ssr/ + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.project +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw* + +vite.config.ts.timestamp* diff --git a/.hintrc b/.hintrc new file mode 100644 index 0000000..de024c3 --- /dev/null +++ b/.hintrc @@ -0,0 +1,16 @@ +{ + "extends": [ + "development" + ], + "hints": { + "meta-viewport": "off", + "axe/text-alternatives": [ + "default", + { + "document-title": "off" + } + ], + "disown-opener": "off", + "css-prefix-order": "off" + } +} \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..29d7d66 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": true, + "useTabs": true, + "tabWidth": 4, + "printWidth": 100, + "singleQuote": true, + "arrowParens": "avoid", + "trailingComma": "none" +} diff --git a/.vscode/config.code-snippets b/.vscode/config.code-snippets new file mode 100644 index 0000000..6fd0453 --- /dev/null +++ b/.vscode/config.code-snippets @@ -0,0 +1,15 @@ +{ + "module-config": { + "prefix": "module-config", + "scope": "typescript", + "body": [ + "import { type ModuleConfig } from \"/@/cool\";", + "", + "export default (): ModuleConfig => {", + " return {};", + "};", + "" + ], + "description": "module config snippets" + } +} diff --git a/.vscode/crud.code-snippets b/.vscode/crud.code-snippets new file mode 100644 index 0000000..0c4694b --- /dev/null +++ b/.vscode/crud.code-snippets @@ -0,0 +1,100 @@ +{ + "cl-crud": { + "prefix": "cl-crud", + "scope": "vue", + "body": [ + "", + "", + "", + "" + ], + "description": "cl-crud snippets" + }, + "cl-filter": { + "prefix": "cl-filter", + "scope": "html", + "body": [ + "", + " ", + "" + ], + "description": "cl-filter snippets" + }, + "slot-item": { + "prefix": "slot item", + "scope": "html", + "body": ["", ""], + "description": "slot snippets" + }, + "slot-column": { + "prefix": "slot column", + "scope": "html", + "body": ["", ""], + "description": "column slot snippets" + } +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..7355b16 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3e56ecf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,17 @@ +{ + "editor.cursorSmoothCaretAnimation": "on", + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.patterns": { + "tsconfig.json": "tsconfig.*.json, env.d.ts", + "vite.config.*": "jsconfig*, vitest.config.*, cypress.config.*, playwright.config.*", + "package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .prettier*, prettier*, .editorconfig" + }, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit" + }, + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[scss]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..811db32 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM node:lts-alpine +WORKDIR /build +# 设置npm镜像 +RUN npm config set registry https://registry.npmmirror.com +COPY package.json /build/package.json +RUN npm install +COPY ./ /build +RUN npm run build + +FROM nginx +RUN mkdir /app +COPY --from=0 /build/dist /app +COPY --from=0 /build/nginx.conf /etc/nginx/nginx.conf +EXPOSE 80 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b6722d4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,33 @@ +MIT License + +Copyright (c) [2025] [厦门闪酷科技开发有限公司] + +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. + +--- + +MIT 许可证 + +版权所有 (c) [2025] [厦门闪酷科技开发有限公司] + +特此免费授予获得本软件及相关文档文件(“软件”)副本的任何人无限制地处理本软件的权限,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件的副本,并允许软件提供给其的人员这样做,但须符合以下条件: + +上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。 + +本软件按“原样”提供,不提供任何明示或暗示的担保,包括但不限于对适销性、特定用途适用性和非侵权的担保。在任何情况下,作者或版权持有人均不对因软件或软件使用或其他交易而产生的任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权诉讼或其他诉讼中。 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a03692 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# cool-admin [vue3 - ts - vite] + +

+ cool-admin Logo +

+ +

cool-admin 一个很酷的后台权限管理系统,开源免费,模块化、插件化、极速开发 CRUD,方便快速构建迭代后台管理系统, 到文档 进一步了解

+ +

+ GitHub license + GitHub tag + GitHub tag +

+ +## 特性 + +Ai时代,很多老旧的框架已经无法满足现代化的开发需求,Cool-Admin开发了一系列的功能,让开发变得更简单、更快速、更高效。 + +- **Ai编码**:通过微调大模型学习框架特有写法,实现简单功能从Api接口到前端页面的一键生成 +- **流程编排**:通过拖拽编排方式,即可实现类似像智能客服这样的功能 +- **模块化**:代码是模块化的,清晰明了,方便维护 +- **插件化**:插件化的设计,可以通过安装插件的方式扩展如:支付、短信、邮件等功能 + +![](https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/flow.png) + +## 地址 + +- [📌 v7 版本](https://github.com/cool-team-official/cool-admin-vue/tree/7.x) + +- [🌐 码云仓库](https://gitee.com/cool-team-official/cool-admin-vue) + +## 视频教程 + +[官方 B 站视频教程](https://www.bilibili.com/video/BV1j1421R7aB) + +## 演示 + +[https://show.cool-admin.com](https://show.cool-admin.com) + +账户:admin,密码:123456 + +Admin Home + +## 项目后端 + +[https://github.com/cool-team-official/cool-admin-midway](https://github.com/cool-team-official/cool-admin-midway) + +或 + +[https://gitee.com/cool-team-official/cool-admin-midway](https://gitee.com/cool-team-official/cool-admin-midway) + +或 + +[https://gitcode.com/cool_team/cool-admin-midway](https://gitcode.com/cool_team/cool-admin-midway) + +## 微信群 + +Admin Wechat + +## 安装项目依赖 + +推荐使用 `pnpm`: + +```shell +pnpm i +``` + +## 运行应用程序 + +安装过程完成后,运行以下命令启动服务。您可以在浏览器中预览网站 [http://localhost:9000](http://localhost:9000) + +```shell +pnpm dev +``` + +### 低价服务器 + +[阿里云、腾讯云、华为云低价云服务器,不限新老](https://cool-js.com/service/cloud) diff --git a/build/cool/eps.d.ts b/build/cool/eps.d.ts new file mode 100644 index 0000000..fd274fc --- /dev/null +++ b/build/cool/eps.d.ts @@ -0,0 +1,1588 @@ +declare namespace Eps { + interface BaseSysDepartmentEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface BaseSysLogEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface BaseSysMenuEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface BaseSysParamEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface BaseSysRoleEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface BaseSysUserEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface CsChatEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface CsMsgEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface CsSessionEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface DemoGoodsEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface DictInfoEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface DictTypeEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface PluginInfoEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface RecycleDataEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface SpaceInfoEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface SpaceTypeEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface StaffInfoEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface TaskInfoEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface UserAddressEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + interface UserInfoEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + + type json = any; + + interface PagePagination { + size: number; + page: number; + total: number; + [key: string]: any; + } + + interface PageResponse { + pagination: PagePagination; + list: T[]; + [key: string]: any; + } + + interface BaseSysLogPageResponse { + pagination: PagePagination; + list: BaseSysLogEntity[]; + } + + interface BaseSysMenuPageResponse { + pagination: PagePagination; + list: BaseSysMenuEntity[]; + } + + interface BaseSysParamPageResponse { + pagination: PagePagination; + list: BaseSysParamEntity[]; + } + + interface BaseSysRolePageResponse { + pagination: PagePagination; + list: BaseSysRoleEntity[]; + } + + interface BaseSysUserPageResponse { + pagination: PagePagination; + list: BaseSysUserEntity[]; + } + + interface CsChatPageResponse { + pagination: PagePagination; + list: CsChatEntity[]; + } + + interface CsMsgPageResponse { + pagination: PagePagination; + list: CsMsgEntity[]; + } + + interface CsSessionPageResponse { + pagination: PagePagination; + list: CsSessionEntity[]; + } + + interface DemoGoodsPageResponse { + pagination: PagePagination; + list: DemoGoodsEntity[]; + } + + interface DictInfoPageResponse { + pagination: PagePagination; + list: DictInfoEntity[]; + } + + interface DictTypePageResponse { + pagination: PagePagination; + list: DictTypeEntity[]; + } + + interface PluginInfoPageResponse { + pagination: PagePagination; + list: PluginInfoEntity[]; + } + + interface RecycleDataPageResponse { + pagination: PagePagination; + list: RecycleDataEntity[]; + } + + interface SpaceInfoPageResponse { + pagination: PagePagination; + list: SpaceInfoEntity[]; + } + + interface SpaceTypePageResponse { + pagination: PagePagination; + list: SpaceTypeEntity[]; + } + + interface StaffInfoPageResponse { + pagination: PagePagination; + list: StaffInfoEntity[]; + } + + interface TaskInfoPageResponse { + pagination: PagePagination; + list: TaskInfoEntity[]; + } + + interface UserAddressPageResponse { + pagination: PagePagination; + list: UserAddressEntity[]; + } + + interface UserInfoPageResponse { + pagination: PagePagination; + list: UserInfoEntity[]; + } + + interface BaseCoding { + /** + * getModuleTree + */ + getModuleTree(data?: any): Promise; + + /** + * createCode + */ + createCode(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { getModuleTree: string; createCode: string }; + + /** + * 权限状态 + */ + _permission: { getModuleTree: boolean; createCode: boolean }; + + request: Request; + } + + interface BaseComm { + /** + * personUpdate + */ + personUpdate(data?: any): Promise; + + /** + * uploadMode + */ + uploadMode(data?: any): Promise; + + /** + * permmenu + */ + permmenu(data?: any): Promise; + + /** + * program + */ + program(data?: any): Promise; + + /** + * person + */ + person(data?: any): Promise; + + /** + * upload + */ + upload(data?: any): Promise; + + /** + * logout + */ + logout(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + personUpdate: string; + uploadMode: string; + permmenu: string; + program: string; + person: string; + upload: string; + logout: string; + }; + + /** + * 权限状态 + */ + _permission: { + personUpdate: boolean; + uploadMode: boolean; + permmenu: boolean; + program: boolean; + person: boolean; + upload: boolean; + logout: boolean; + }; + + request: Request; + } + + interface BaseOpen { + /** + * refreshToken + */ + refreshToken(data?: any): Promise; + + /** + * captcha + */ + captcha(data?: any): Promise; + + /** + * login + */ + login(data?: any): Promise; + + /** + * html + */ + html(data?: any): Promise; + + /** + * eps + */ + eps(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + refreshToken: string; + captcha: string; + login: string; + html: string; + eps: string; + }; + + /** + * 权限状态 + */ + _permission: { + refreshToken: boolean; + captcha: boolean; + login: boolean; + html: boolean; + eps: boolean; + }; + + request: Request; + } + + interface BaseSysDepartment { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * order + */ + order(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { delete: string; update: string; order: string; list: string; add: string }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + order: boolean; + list: boolean; + add: boolean; + }; + + request: Request; + } + + interface BaseSysLog { + /** + * setKeep + */ + setKeep(data?: any): Promise; + + /** + * getKeep + */ + getKeep(data?: any): Promise; + + /** + * clear + */ + clear(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { setKeep: string; getKeep: string; clear: string; page: string }; + + /** + * 权限状态 + */ + _permission: { setKeep: boolean; getKeep: boolean; clear: boolean; page: boolean }; + + request: Request; + } + + interface BaseSysMenu { + /** + * create + */ + create(data?: any): Promise; + + /** + * export + */ + export(data?: any): Promise; + + /** + * import + */ + import(data?: any): Promise; + + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * parse + */ + parse(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + create: string; + export: string; + import: string; + delete: string; + update: string; + parse: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + create: boolean; + export: boolean; + import: boolean; + delete: boolean; + update: boolean; + parse: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface BaseSysParam { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * html + */ + html(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + html: string; + info: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + html: boolean; + info: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface BaseSysRole { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface BaseSysUser { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * move + */ + move(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + move: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + move: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface CsChat { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface CsMsg { + /** + * unreadCount + */ + unreadCount(data?: any): Promise; + + /** + * read + */ + read(data?: any): Promise; + + /** + * send + */ + send(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { unreadCount: string; read: string; send: string; page: string }; + + /** + * 权限状态 + */ + _permission: { unreadCount: boolean; read: boolean; send: boolean; page: boolean }; + + request: Request; + } + + interface CsSession { + /** + * page + */ + page(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { page: string }; + + /** + * 权限状态 + */ + _permission: { page: boolean }; + + request: Request; + } + + interface DemoGoods { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface DemoTenant { + /** + * noTenant + */ + noTenant(data?: any): Promise; + + /** + * noUse + */ + noUse(data?: any): Promise; + + /** + * use + */ + use(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { noTenant: string; noUse: string; use: string }; + + /** + * 权限状态 + */ + _permission: { noTenant: boolean; noUse: boolean; use: boolean }; + + request: Request; + } + + interface DictInfo { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * types + */ + types(data?: any): Promise; + + /** + * data + */ + data(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + types: string; + data: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + types: boolean; + data: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface DictType { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface PluginInfo { + /** + * install + */ + install(data?: any): Promise; + + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + install: string; + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + install: boolean; + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface RecycleData { + /** + * restore + */ + restore(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { restore: string; info: string; page: string }; + + /** + * 权限状态 + */ + _permission: { restore: boolean; info: boolean; page: boolean }; + + request: Request; + } + + interface SpaceInfo { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface SpaceType { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface StaffInfo { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface StaffLogin { + /** + * login + */ + login(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { login: string }; + + /** + * 权限状态 + */ + _permission: { login: boolean }; + + request: Request; + } + + interface TaskInfo { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * start + */ + start(data?: any): Promise; + + /** + * once + */ + once(data?: any): Promise; + + /** + * stop + */ + stop(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * log + */ + log(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + start: string; + once: string; + stop: string; + info: string; + page: string; + log: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + start: boolean; + once: boolean; + stop: boolean; + info: boolean; + page: boolean; + log: boolean; + add: boolean; + }; + + request: Request; + } + + interface UserAddress { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface UserInfo { + /** + * delete + */ + delete(data?: any): Promise; + + /** + * update + */ + update(data?: any): Promise; + + /** + * info + */ + info(data?: any): Promise; + + /** + * list + */ + list(data?: any): Promise; + + /** + * page + */ + page(data?: any): Promise; + + /** + * add + */ + add(data?: any): Promise; + + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + + request: Request; + } + + interface RequestOptions { + url: string; + method?: "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT"; + data?: any; + params?: any; + headers?: any; + timeout?: number; + [key: string]: any; + } + + type Request = (options: RequestOptions) => Promise; + + type DictKey = "brand" | "occupation"; + + type Service = { + request: Request; + + base: { + coding: BaseCoding; + comm: BaseComm; + open: BaseOpen; + sys: { + department: BaseSysDepartment; + log: BaseSysLog; + menu: BaseSysMenu; + param: BaseSysParam; + role: BaseSysRole; + user: BaseSysUser; + }; + }; + cs: { chat: CsChat; msg: CsMsg; session: CsSession }; + demo: { goods: DemoGoods; tenant: DemoTenant }; + dict: { info: DictInfo; type: DictType }; + plugin: { info: PluginInfo }; + recycle: { data: RecycleData }; + space: { info: SpaceInfo; type: SpaceType }; + staff: { info: StaffInfo; login: StaffLogin }; + task: { info: TaskInfo }; + user: { address: UserAddress; info: UserInfo }; + }; +} diff --git a/build/cool/eps.json b/build/cool/eps.json new file mode 100644 index 0000000..6ca2892 --- /dev/null +++ b/build/cool/eps.json @@ -0,0 +1 @@ +[{"prefix":"/admin/base/coding","name":"","api":[{"method":"get","path":"/getModuleTree"},{"method":"post","path":"/createCode"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/base/comm","name":"","api":[{"method":"post","path":"/personUpdate"},{"method":"get","path":"/uploadMode"},{"method":"get","path":"/permmenu"},{"method":"get","path":"/program"},{"method":"get","path":"/person"},{"method":"post","path":"/upload"},{"method":"post","path":"/logout"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/base/open","name":"","api":[{"method":"get","path":"/refreshToken"},{"method":"get","path":"/captcha"},{"method":"post","path":"/login"},{"method":"get","path":"/html"},{"method":"get","path":"/eps"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/base/sys/department","name":"BaseSysDepartmentEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"post","path":"/order"},{"method":"post","path":"/list"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/base/sys/log","name":"BaseSysLogEntity","api":[{"method":"post","path":"/setKeep"},{"method":"get","path":"/getKeep"},{"method":"post","path":"/clear"},{"method":"post","path":"/page"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[{"propertyName":"name","type":"string","length":"","comment":"姓名","nullable":true,"source":"b.name"},{"propertyName":"action","type":"string","length":"","comment":"行为","nullable":false,"source":"a.action"},{"propertyName":"ip","type":"string","length":"","comment":"ip","nullable":true,"source":"a.ip"}]}},{"prefix":"/admin/base/sys/menu","name":"BaseSysMenuEntity","api":[{"method":"post","path":"/create"},{"method":"post","path":"/export"},{"method":"post","path":"/import"},{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"post","path":"/parse"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/base/sys/param","name":"BaseSysParamEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/html"},{"method":"get","path":"/info"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[{"propertyName":"dataType","type":"number","length":"","comment":"数据类型 0-字符串 1-富文本 2-文件 ","nullable":false,"defaultValue":0,"source":"a.dataType"}],"fieldLike":[],"keyWordLikeFields":[{"propertyName":"name","type":"string","length":"","comment":"名称","nullable":false,"source":"a.name"},{"propertyName":"keyName","type":"string","length":"","comment":"键","nullable":false,"source":"a.keyName"}]}},{"prefix":"/admin/base/sys/role","name":"BaseSysRoleEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[{"propertyName":"name","type":"string","length":"","comment":"名称","nullable":false,"source":"a.name"},{"propertyName":"label","type":"string","length":"50","comment":"角色标签","nullable":true,"source":"a.label"}]}},{"prefix":"/admin/base/sys/user","name":"BaseSysUserEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"post","path":"/move"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/cs/chat","name":"CsChatEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[{"propertyName":"senderId","type":"number","length":"","comment":"发送人ID","nullable":false,"source":"a.senderId"},{"propertyName":"receiverId","type":"number","length":"","comment":"接收人ID","nullable":false,"source":"a.receiverId"}],"fieldLike":[],"keyWordLikeFields":[{"propertyName":"content","type":"text","length":"","comment":"消息内容","nullable":false,"source":"a.content"}]}},{"prefix":"/admin/cs/msg","name":"CsMsgEntity","api":[{"method":"get","path":"/unreadCount"},{"method":"post","path":"/read"},{"method":"post","path":"/send"},{"method":"post","path":"/page"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/cs/session","name":"CsSessionEntity","api":[{"method":"post","path":"/page"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/demo/goods","name":"DemoGoodsEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[{"propertyName":"status","type":"number","length":"","comment":"状态","nullable":false,"defaultValue":1,"dict":["禁用","启用"],"source":"a.status"}],"fieldLike":[{"propertyName":"title","type":"string","length":"50","comment":"标题","nullable":false,"source":"a.title"}],"keyWordLikeFields":[{"propertyName":"description","type":"string","length":"","comment":"描述","nullable":true,"source":"a.description"}]}},{"prefix":"/admin/demo/tenant","name":"DemoGoodsEntity","api":[{"method":"post","path":"/noTenant"},{"method":"post","path":"/noUse"},{"method":"post","path":"/use"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/dict/info","name":"DictInfoEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/types"},{"method":"post","path":"/data"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/dict/type","name":"DictTypeEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/plugin/info","name":"PluginInfoEntity","api":[{"method":"post","path":"/install"},{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/recycle/data","name":"RecycleDataEntity","api":[{"method":"post","path":"/restore"},{"method":"get","path":"/info"},{"method":"post","path":"/page"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[{"propertyName":"userName","type":"string","length":"","comment":"姓名","nullable":true,"source":"b.name"},{"propertyName":"url","type":"string","length":"","comment":"请求的接口","nullable":true,"source":"a.url"}]}},{"prefix":"/admin/space/info","name":"SpaceInfoEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[{"propertyName":"type","type":"string","length":"","comment":"类型","nullable":false,"source":"a.type"},{"propertyName":"classifyId","type":"number","length":"","comment":"分类ID","nullable":true,"source":"a.classifyId"}],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/space/type","name":"SpaceTypeEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/staff/info","name":"StaffInfoEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[{"propertyName":"status","type":"number","length":"","comment":"状态","nullable":false,"defaultValue":1,"dict":["禁用","在线","忙碌","离线"],"source":"a.status"}],"fieldLike":[],"keyWordLikeFields":[{"propertyName":"nickName","type":"string","length":"50","comment":"客服昵称","nullable":true,"source":"a.nickName"},{"propertyName":"account","type":"string","length":"50","comment":"客服账号","nullable":false,"source":"a.account"}]}},{"prefix":"/admin/staff/login","name":"","api":[{"method":"post","path":"/login"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/task/info","name":"TaskInfoEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"post","path":"/start"},{"method":"post","path":"/once"},{"method":"post","path":"/stop"},{"method":"get","path":"/info"},{"method":"post","path":"/page"},{"method":"get","path":"/log"},{"method":"post","path":"/add"}],"search":{"fieldEq":[{"propertyName":"status","type":"number","length":"","comment":"状态 0-停止 1-运行","nullable":false,"defaultValue":1,"source":"a.status"},{"propertyName":"type","type":"number","length":"","comment":"状态 0-系统 1-用户","nullable":false,"defaultValue":0,"source":"a.type"}],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/user/address","name":"UserAddressEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[],"fieldLike":[],"keyWordLikeFields":[]}},{"prefix":"/admin/user/info","name":"UserInfoEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}],"search":{"fieldEq":[{"propertyName":"status","type":"number","length":"","comment":"状态","nullable":false,"defaultValue":1,"dict":["禁用","正常","已注销"],"source":"a.status"},{"propertyName":"gender","type":"number","length":"","comment":"性别","nullable":false,"defaultValue":0,"dict":["未知","男","女"],"source":"a.gender"},{"propertyName":"loginType","type":"number","length":"","comment":"登录方式","nullable":false,"defaultValue":0,"dict":["小程序","公众号","H5"],"source":"a.loginType"}],"fieldLike":[],"keyWordLikeFields":[{"propertyName":"nickName","type":"string","length":"","comment":"昵称","nullable":true,"source":"a.nickName"},{"propertyName":"phone","type":"string","length":"","comment":"手机号","nullable":true,"source":"a.phone"}]}}] \ No newline at end of file diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 0000000..b5a1827 --- /dev/null +++ b/env.d.ts @@ -0,0 +1,10 @@ +/// + +interface ImportMetaEnv { + readonly VITE_NAME: string; + readonly VITE_TIMEOUT: number; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..a361065 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,73 @@ +import pluginVue from 'eslint-plugin-vue'; +import vueTsEslintConfig from '@vue/eslint-config-typescript'; +import prettier from 'eslint-plugin-prettier'; +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'; + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], + }, + + { + name: 'app/files-to-ignore', + ignores: [ + '**/dist/**', + '**/dist-ssr/**', + '**/coverage/**', + '**/packages/**', + '**/build/**', + ], + }, + + ...pluginVue.configs['flat/recommended'], + ...vueTsEslintConfig(), + skipFormatting, + + { + languageOptions: { + parserOptions: { + ecmaVersion: 2020, + ecmaFeatures: { + jsx: true, + }, + }, + }, + rules: { + '@typescript-eslint/ban-ts-ignore': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-empty-object-type': 'off', + 'space-before-function-paren': 'off', + 'no-unused-vars': 'off', + 'no-use-before-define': 'off', + 'no-self-assign': 'off', + 'vue/no-mutating-props': 'off', + 'vue/no-template-shadow': 'off', + 'vue/no-v-html': 'off', + 'vue/component-name-in-template-casing': ['error', 'kebab-case'], + 'vue/component-definition-name-casing': ['error', 'kebab-case'], + '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/multi-word-component-names': 'off', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/attribute-hyphenation': 'off', + 'vue/html-self-closing': 'off', + 'vue/require-default-prop': 'off', + 'vue/v-on-event-hyphenation': 'off', + 'vue/block-lang': 'off', + }, + }, +]; diff --git a/index.html b/index.html new file mode 100644 index 0000000..1148b64 --- /dev/null +++ b/index.html @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+ +
+ + + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..2a02b0a --- /dev/null +++ b/nginx.conf @@ -0,0 +1,72 @@ +user nginx; +worker_processes 1; +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; +events { + worker_connections 1024; +} +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; + sendfile on; + keepalive_timeout 65; + upstream cool { + server midway:8001; + } + + server { + listen 80; + server_name localhost; + location / { + root /app; + index index.html; + try_files $uri $uri/ /index.html; + } + location /api/ { + proxy_pass http://cool/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + + #缓存相关配置 + #proxy_cache cache_one; + #proxy_cache_key $host$request_uri$is_args$args; + #proxy_cache_valid 200 304 301 302 1h; + + #持久化连接相关配置 + proxy_connect_timeout 3000s; + proxy_read_timeout 86400s; + proxy_send_timeout 3000s; + #proxy_http_version 1.1; + #proxy_set_header Upgrade $http_upgrade; + #proxy_set_header Connection "upgrade"; + + add_header X-Cache $upstream_cache_status; + + #expires 12h; + } + + # socket需额外配置 + location /socket { + proxy_pass http://cool/socket; + proxy_connect_timeout 3600s; #配置点1 + proxy_read_timeout 3600s; #配置点2,如果没效,可以考虑这个时间配置长一点 + proxy_send_timeout 3600s; #配置点3 + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + #proxy_bind $remote_addr transparent; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + rewrite /socket/(.*) /$1 break; + proxy_redirect off; + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6148da5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5618 @@ +{ + "name": "cool-admin-vue", + "version": "8.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true + }, + "@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true + }, + "@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + } + }, + "@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true + }, + "@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "requires": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "requires": { + "@babel/types": "^7.27.3" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "requires": { + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + } + }, + "@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==" + }, + "@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==" + }, + "@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true + }, + "@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "requires": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + } + }, + "@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "requires": { + "@babel/types": "^7.29.0" + } + }, + "@babel/plugin-proposal-decorators": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.0.tgz", + "integrity": "sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-decorators": "^7.28.6" + } + }, + "@babel/plugin-syntax-decorators": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.28.6.tgz", + "integrity": "sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.28.6" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.28.6" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.28.6" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.28.6" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + } + }, + "@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==" + }, + "@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + } + }, + "@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + } + }, + "@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "requires": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + } + }, + "@cool-vue/crud": { + "version": "8.0.6", + "requires": { + "@vue/runtime-core": "^3.5.13", + "element-plus": "^2.10.4", + "lodash-es": "^4.17.21", + "vue": "^3.5.13" + }, + "dependencies": { + "@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==" + }, + "@vueuse/core": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.0.0.tgz", + "integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==", + "requires": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "12.0.0", + "@vueuse/shared": "12.0.0", + "vue": "^3.5.13" + } + }, + "dayjs": { + "version": "1.11.20", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==" + }, + "element-plus": { + "version": "2.13.5", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.13.5.tgz", + "integrity": "sha512-dmY24fhSREfZN/PuUt0YZigMso7wWzl+B5o+YKNN15kQIn/0hzamsPU+ebj9SES0IbUqsLX1wkrzYmzU8VrVOQ==", + "requires": { + "@ctrl/tinycolor": "^4.2.0", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.17.20", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "12.0.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.19", + "lodash": "^4.17.23", + "lodash-es": "^4.17.23", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "dependencies": { + "lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==" + } + } + } + } + }, + "@cool-vue/vite-plugin": { + "version": "8.2.2", + "dev": true, + "requires": { + "@vue/compiler-sfc": "^3.5.13", + "axios": "^1.6.8", + "glob": "^10.3.12", + "lodash": "^4.17.21", + "magic-string": "^0.30.17", + "prettier": "^3.4.2", + "svgo": "^3.3.2" + } + }, + "@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==" + }, + "@element-plus/icons-vue": { + "version": "2.3.1" + }, + "@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "dev": true, + "optional": true + }, + "@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.4.3" + } + }, + "@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true + }, + "@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "requires": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true + }, + "@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.15" + } + }, + "@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "requires": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true + }, + "espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "requires": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + } + }, + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + }, + "minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@eslint/js": { + "version": "9.31.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", + "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", + "dev": true + }, + "@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true + }, + "@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "requires": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + } + }, + "@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "requires": { + "@floating-ui/utils": "^0.2.11" + } + }, + "@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "requires": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==" + }, + "@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true + }, + "@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "requires": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true + }, + "@intlify/bundle-utils": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-10.0.1.tgz", + "integrity": "sha512-WkaXfSevtpgtUR4t8K2M6lbR7g03mtOxFeh+vXp5KExvPqS12ppaRj1QxzwRuRI5VUto54A22BjKoBMLyHILWQ==", + "dev": true, + "requires": { + "@intlify/message-compiler": "^11.1.2", + "@intlify/shared": "^11.1.2", + "acorn": "^8.8.2", + "escodegen": "^2.1.0", + "estree-walker": "^2.0.2", + "jsonc-eslint-parser": "^2.3.0", + "mlly": "^1.2.0", + "source-map-js": "^1.0.1", + "yaml-eslint-parser": "^1.2.2" + } + }, + "@intlify/core-base": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.8.tgz", + "integrity": "sha512-FoHslNWSoHjdUBLy35bpm9PV/0LVI/DSv9L6Km6J2ad8r/mm0VaGg06C40FqlE8u2ADcGUM60lyoU7Myo4WNZQ==", + "dev": true, + "requires": { + "@intlify/message-compiler": "10.0.8", + "@intlify/shared": "10.0.8" + }, + "dependencies": { + "@intlify/message-compiler": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.8.tgz", + "integrity": "sha512-DV+sYXIkHVd5yVb2mL7br/NEUwzUoLBsMkV3H0InefWgmYa34NLZUvMCGi5oWX+Hqr2Y2qUxnVrnOWF4aBlgWg==", + "dev": true, + "requires": { + "@intlify/shared": "10.0.8", + "source-map-js": "^1.0.2" + } + }, + "@intlify/shared": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.8.tgz", + "integrity": "sha512-BcmHpb5bQyeVNrptC3UhzpBZB/YHHDoEREOUERrmF2BRxsyOEuRrq+Z96C/D4+2KJb8kuHiouzAei7BXlG0YYw==", + "dev": true + } + } + }, + "@intlify/message-compiler": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.3.0.tgz", + "integrity": "sha512-RAJp3TMsqohg/Wa7bVF3cChRhecSYBLrTCQSj7j0UtWVFLP+6iEJoE2zb7GU5fp+fmG5kCbUdzhmlAUCWXiUJw==", + "dev": true, + "requires": { + "@intlify/shared": "11.3.0", + "source-map-js": "^1.0.2" + } + }, + "@intlify/shared": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.3.0.tgz", + "integrity": "sha512-LC6P/uay7rXL5zZ5+5iRJfLs/iUN8apu9tm8YqQVmW3Uq3X4A0dOFUIDuAmB7gAC29wTHOS3EiN/IosNSz0eNQ==", + "dev": true + }, + "@intlify/unplugin-vue-i18n": { + "version": "6.0.8", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@intlify/bundle-utils": "^10.0.1", + "@intlify/shared": "^11.1.2", + "@intlify/vue-i18n-extensions": "^8.0.0", + "@rollup/pluginutils": "^5.1.0", + "@typescript-eslint/scope-manager": "^8.13.0", + "@typescript-eslint/typescript-estree": "^8.13.0", + "debug": "^4.3.3", + "fast-glob": "^3.2.12", + "js-yaml": "^4.1.0", + "json5": "^2.2.3", + "pathe": "^1.0.0", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2", + "unplugin": "^1.1.0", + "vue": "^3.4" + } + }, + "@intlify/vue-i18n-extensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@intlify/vue-i18n-extensions/-/vue-i18n-extensions-8.0.0.tgz", + "integrity": "sha512-w0+70CvTmuqbskWfzeYhn0IXxllr6mU+IeM2MU0M+j9OW64jkrvqY+pYFWrUnIIC9bEdij3NICruicwd5EgUuQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.24.6", + "@intlify/shared": "^10.0.0", + "@vue/compiler-dom": "^3.2.45", + "vue-i18n": "^10.0.0" + }, + "dependencies": { + "@intlify/shared": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.8.tgz", + "integrity": "sha512-BcmHpb5bQyeVNrptC3UhzpBZB/YHHDoEREOUERrmF2BRxsyOEuRrq+Z96C/D4+2KJb8kuHiouzAei7BXlG0YYw==", + "dev": true + }, + "vue-i18n": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.8.tgz", + "integrity": "sha512-mIjy4utxMz9lMMo6G9vYePv7gUFt4ztOMhY9/4czDJxZ26xPeJ49MAGa9wBAE3XuXbYCrtVPmPxNjej7JJJkZQ==", + "dev": true, + "requires": { + "@intlify/core-base": "10.0.8", + "@intlify/shared": "10.0.8", + "@vue/devtools-api": "^6.5.0" + } + } + } + }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true + }, + "@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "optional": true, + "requires": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6", + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + } + }, + "@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "dev": true, + "optional": true + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, + "@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true + }, + "@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true + }, + "@popperjs/core": { + "version": "npm:@sxzz/popperjs-es@2.11.8", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz", + "integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==" + }, + "@rolldown/pluginutils": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", + "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", + "dev": true + }, + "@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + } + }, + "@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "dev": true, + "optional": true + }, + "@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "dev": true, + "optional": true + }, + "@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "dev": true, + "optional": true + }, + "@rushstack/eslint-patch": { + "version": "1.12.0", + "dev": true + }, + "@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true + }, + "@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true + }, + "@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, + "@transloadit/prettier-bytes": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz", + "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==" + }, + "@tsconfig/node20": { + "version": "20.1.6", + "dev": true + }, + "@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true + }, + "@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "@types/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@types/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==" + }, + "@types/file-saver": { + "version": "2.0.7", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==" + }, + "@types/lodash-es": { + "version": "4.17.12", + "requires": { + "@types/lodash": "*" + } + }, + "@types/mockjs": { + "version": "1.0.10", + "dev": true + }, + "@types/node": { + "version": "20.19.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", + "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", + "dev": true, + "requires": { + "undici-types": "~6.21.0" + } + }, + "@types/nprogress": { + "version": "0.2.3", + "dev": true + }, + "@types/store": { + "version": "2.0.5", + "dev": true + }, + "@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==" + }, + "@typescript-eslint/eslint-plugin": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz", + "integrity": "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/type-utils": "8.57.0", + "@typescript-eslint/utils": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + } + }, + "@typescript-eslint/parser": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz", + "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", + "debug": "^4.4.3" + } + }, + "@typescript-eslint/project-service": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", + "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", + "dev": true, + "requires": { + "@typescript-eslint/tsconfig-utils": "^8.57.0", + "@typescript-eslint/types": "^8.57.0", + "debug": "^4.4.3" + } + }, + "@typescript-eslint/scope-manager": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", + "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0" + } + }, + "@typescript-eslint/tsconfig-utils": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", + "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", + "dev": true + }, + "@typescript-eslint/type-utils": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz", + "integrity": "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/utils": "8.57.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + } + }, + "@typescript-eslint/types": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", + "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", + "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", + "dev": true, + "requires": { + "@typescript-eslint/project-service": "8.57.0", + "@typescript-eslint/tsconfig-utils": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/visitor-keys": "8.57.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "dependencies": { + "balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true + }, + "brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "requires": { + "balanced-match": "^4.0.2" + } + }, + "minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "requires": { + "brace-expansion": "^5.0.2" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz", + "integrity": "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.57.0", + "@typescript-eslint/types": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", + "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.57.0", + "eslint-visitor-keys": "^5.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true + } + } + }, + "@uppy/companion-client": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.2.2.tgz", + "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==", + "requires": { + "@uppy/utils": "^4.1.2", + "namespace-emitter": "^2.0.1" + } + }, + "@uppy/core": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz", + "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==", + "requires": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/store-default": "^2.1.1", + "@uppy/utils": "^4.1.3", + "lodash.throttle": "^4.1.1", + "mime-match": "^1.0.2", + "namespace-emitter": "^2.0.1", + "nanoid": "^3.1.25", + "preact": "^10.5.13" + } + }, + "@uppy/store-default": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.1.1.tgz", + "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==" + }, + "@uppy/utils": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.1.3.tgz", + "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==", + "requires": { + "lodash.throttle": "^4.1.1" + } + }, + "@uppy/xhr-upload": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz", + "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==", + "requires": { + "@uppy/companion-client": "^2.2.2", + "@uppy/utils": "^4.1.2", + "nanoid": "^3.1.25" + } + }, + "@vitejs/plugin-vue": { + "version": "5.2.4", + "dev": true + }, + "@vitejs/plugin-vue-jsx": { + "version": "4.2.0", + "dev": true, + "requires": { + "@babel/core": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.27.1", + "@rolldown/pluginutils": "^1.0.0-beta.9", + "@vue/babel-plugin-jsx": "^1.4.0" + } + }, + "@volar/language-core": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz", + "integrity": "sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==", + "dev": true, + "requires": { + "@volar/source-map": "2.4.15" + } + }, + "@volar/source-map": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.15.tgz", + "integrity": "sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==", + "dev": true + }, + "@volar/typescript": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz", + "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==", + "dev": true, + "requires": { + "@volar/language-core": "2.4.15", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "@vue/babel-helper-vue-transform-on": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", + "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", + "dev": true + }, + "@vue/babel-plugin-jsx": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", + "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@vue/babel-helper-vue-transform-on": "1.5.0", + "@vue/babel-plugin-resolve-type": "1.5.0", + "@vue/shared": "^3.5.18" + } + }, + "@vue/babel-plugin-resolve-type": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", + "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/parser": "^7.28.0", + "@vue/compiler-sfc": "^3.5.18" + } + }, + "@vue/compiler-core": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.18.tgz", + "integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==", + "requires": { + "@babel/parser": "^7.28.0", + "@vue/shared": "3.5.18", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + }, + "dependencies": { + "@vue/shared": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==" + } + } + }, + "@vue/compiler-dom": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz", + "integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==", + "requires": { + "@vue/compiler-core": "3.5.18", + "@vue/shared": "3.5.18" + }, + "dependencies": { + "@vue/shared": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==" + } + } + }, + "@vue/compiler-sfc": { + "version": "3.5.18", + "requires": { + "@babel/parser": "^7.28.0", + "@vue/compiler-core": "3.5.18", + "@vue/compiler-dom": "3.5.18", + "@vue/compiler-ssr": "3.5.18", + "@vue/shared": "3.5.18", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.17", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + }, + "dependencies": { + "@vue/shared": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==" + } + } + }, + "@vue/compiler-ssr": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz", + "integrity": "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==", + "requires": { + "@vue/compiler-dom": "3.5.18", + "@vue/shared": "3.5.18" + }, + "dependencies": { + "@vue/shared": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==" + } + } + }, + "@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" + }, + "@vue/devtools-core": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.7.9.tgz", + "integrity": "sha512-48jrBSwG4GVQRvVeeXn9p9+dlx+ISgasM7SxZZKczseohB0cBz+ITKr4YbLWjmJdy45UHL7UMPlR4Y0CWTRcSQ==", + "dev": true, + "requires": { + "@vue/devtools-kit": "^7.7.9", + "@vue/devtools-shared": "^7.7.9", + "mitt": "^3.0.1", + "nanoid": "^5.1.0", + "pathe": "^2.0.3", + "vite-hot-client": "^2.0.4" + }, + "dependencies": { + "nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "dev": true + }, + "pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true + } + } + }, + "@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "dev": true, + "requires": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "dev": true, + "requires": { + "rfdc": "^1.4.1" + } + }, + "@vue/eslint-config-prettier": { + "version": "10.2.0", + "dev": true, + "requires": { + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.2" + } + }, + "@vue/eslint-config-typescript": { + "version": "14.6.0", + "dev": true, + "requires": { + "@typescript-eslint/utils": "^8.35.1", + "fast-glob": "^3.3.3", + "typescript-eslint": "^8.35.1", + "vue-eslint-parser": "^10.2.0" + } + }, + "@vue/language-core": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.12.tgz", + "integrity": "sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==", + "dev": true, + "requires": { + "@volar/language-core": "2.4.15", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^1.0.3", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + } + }, + "@vue/reactivity": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", + "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "requires": { + "@vue/shared": "3.5.30" + } + }, + "@vue/runtime-core": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", + "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "requires": { + "@vue/reactivity": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "@vue/runtime-dom": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.18.tgz", + "integrity": "sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==", + "requires": { + "@vue/reactivity": "3.5.18", + "@vue/runtime-core": "3.5.18", + "@vue/shared": "3.5.18", + "csstype": "^3.1.3" + }, + "dependencies": { + "@vue/reactivity": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.18.tgz", + "integrity": "sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==", + "requires": { + "@vue/shared": "3.5.18" + } + }, + "@vue/runtime-core": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.18.tgz", + "integrity": "sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==", + "requires": { + "@vue/reactivity": "3.5.18", + "@vue/shared": "3.5.18" + } + }, + "@vue/shared": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==" + } + } + }, + "@vue/server-renderer": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.18.tgz", + "integrity": "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==", + "requires": { + "@vue/compiler-ssr": "3.5.18", + "@vue/shared": "3.5.18" + }, + "dependencies": { + "@vue/shared": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==" + } + } + }, + "@vue/shared": { + "version": "3.5.30", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", + "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==" + }, + "@vue/test-utils": { + "version": "2.4.6", + "dev": true, + "requires": { + "js-beautify": "^1.14.9", + "vue-component-type-helpers": "^2.0.0" + } + }, + "@vue/tsconfig": { + "version": "0.5.1", + "dev": true + }, + "@vueuse/core": { + "version": "12.8.2", + "requires": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "dependencies": { + "@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==" + }, + "@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==" + }, + "@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "requires": { + "vue": "^3.5.13" + } + } + } + }, + "@vueuse/metadata": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.0.0.tgz", + "integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==" + }, + "@vueuse/shared": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.0.0.tgz", + "integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==", + "requires": { + "vue": "^3.5.13" + } + }, + "@wangeditor/basic-modules": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz", + "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==", + "requires": { + "is-url": "^1.2.4" + } + }, + "@wangeditor/code-highlight": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz", + "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==", + "requires": { + "prismjs": "^1.23.0" + } + }, + "@wangeditor/core": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.19.tgz", + "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==", + "requires": { + "@types/event-emitter": "^0.3.3", + "event-emitter": "^0.3.5", + "html-void-elements": "^2.0.0", + "i18next": "^20.4.0", + "scroll-into-view-if-needed": "^2.2.28", + "slate-history": "^0.66.0" + } + }, + "@wangeditor/editor": { + "version": "5.1.23", + "requires": { + "@uppy/core": "^2.1.1", + "@uppy/xhr-upload": "^2.0.3", + "@wangeditor/basic-modules": "^1.1.7", + "@wangeditor/code-highlight": "^1.0.3", + "@wangeditor/core": "^1.1.19", + "@wangeditor/list-module": "^1.0.5", + "@wangeditor/table-module": "^1.1.4", + "@wangeditor/upload-image-module": "^1.0.2", + "@wangeditor/video-module": "^1.1.4", + "dom7": "^3.0.0", + "is-hotkey": "^0.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.foreach": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "lodash.toarray": "^4.4.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "@wangeditor/editor-for-vue": { + "version": "5.1.12" + }, + "@wangeditor/list-module": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.5.tgz", + "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==" + }, + "@wangeditor/table-module": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.4.tgz", + "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==" + }, + "@wangeditor/upload-image-module": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz", + "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==" + }, + "@wangeditor/video-module": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.4.tgz", + "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==" + }, + "abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true + }, + "acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==" + }, + "ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "alien-signals": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz", + "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", + "dev": true + }, + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "dependencies": { + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + } + } + }, + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "autoprefixer": { + "version": "10.4.21", + "dev": true, + "requires": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + } + }, + "axios": { + "version": "1.11.0", + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "baseline-browser-mapping": { + "version": "2.10.7", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.7.tgz", + "integrity": "sha512-1ghYO3HnxGec0TCGBXiDLVns4eCSx4zJpxnHrlqFQajmhfKMQBzUGDdkMK7fUW7PTHTeLf+j87aTuKuuwWzMGw==", + "dev": true + }, + "binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true + }, + "birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "requires": { + "fill-range": "^7.1.1" + } + }, + "browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "requires": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "requires": { + "run-applescript": "^7.0.0" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001778", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001778.tgz", + "integrity": "sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==", + "dev": true + }, + "cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "requires": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "chardet": { + "version": "2.1.0" + }, + "chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "requires": { + "readdirp": "^4.0.1" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "compute-scroll-into-view": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, + "requires": { + "is-what": "^5.2.0" + } + }, + "core-js": { + "version": "3.44.0" + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" + }, + "cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "requires": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + } + }, + "css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "requires": { + "css-tree": "~2.2.0" + }, + "dependencies": { + "css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "requires": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + } + }, + "mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + } + } + }, + "csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" + }, + "d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "requires": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + } + }, + "dayjs": { + "version": "1.11.13" + }, + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, + "debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "requires": { + "ms": "^2.1.3" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "requires": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + } + }, + "default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "optional": true + }, + "didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "dom7": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz", + "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==", + "requires": { + "ssr-window": "^3.0.0-alpha.1" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "echarts": { + "version": "5.6.0", + "requires": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "editorconfig": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", + "dev": true, + "requires": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "^9.0.1", + "semver": "^7.5.3" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.5.313", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.313.tgz", + "integrity": "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==", + "dev": true + }, + "element-plus": { + "version": "2.10.2", + "requires": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "dependencies": { + "@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==" + }, + "@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" + }, + "@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "requires": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + } + }, + "@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==" + }, + "@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "requires": { + "vue-demi": "*" + } + } + } + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "engine.io-client": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", + "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==" + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "error-stack-parser-es": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz", + "integrity": "sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==", + "dev": true + }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, + "es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "requires": { + "d": "^1.0.2", + "ext": "^1.7.0" + } + }, + "esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "source-map": "~0.6.1" + } + }, + "eslint": { + "version": "9.31.0", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.31.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true + }, + "espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "requires": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + }, + "minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true + }, + "eslint-plugin-prettier": { + "version": "5.5.3", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + } + }, + "eslint-plugin-vue": { + "version": "9.33.0", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "vue-eslint-parser": "^9.4.3", + "xml-name-validator": "^4.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + } + } + } + }, + "eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "requires": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + } + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "dev": true, + "requires": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + } + }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "requires": { + "type": "^2.7.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true + }, + "figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "requires": { + "is-unicode-supported": "^2.0.0" + } + }, + "file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "requires": { + "flat-cache": "^4.0.0" + } + }, + "file-saver": { + "version": "2.0.5" + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + } + }, + "flatted": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz", + "integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==" + }, + "foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + } + }, + "form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + } + }, + "frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==" + }, + "fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, + "get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "requires": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + } + }, + "glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true + }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true + }, + "html-void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", + "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==" + }, + "human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true + }, + "i18next": { + "version": "20.6.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.6.1.tgz", + "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==", + "requires": { + "@babel/runtime": "^7.12.0" + } + }, + "ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true + }, + "immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" + }, + "immutable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "dev": true + }, + "import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "requires": { + "hasown": "^2.0.2" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hotkey": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz", + "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==" + }, + "is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "requires": { + "is-docker": "^3.0.0" + }, + "dependencies": { + "is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true + } + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, + "is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true + }, + "is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true + }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, + "is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true + }, + "js-beautify": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "dev": true, + "requires": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + } + }, + "js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonc-eslint-parser": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.2.tgz", + "integrity": "sha512-1e4qoRgnn448pRuMvKGsFFymUCquZV0mpGgOyIKNgD3JVDTsVJyRBGH/Fm0tBb8WsWGgmB1mDe6/yJMQM37DUA==", + "dev": true, + "requires": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "semver": "^7.3.5" + } + }, + "jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" + }, + "lodash-es": { + "version": "4.17.21" + }, + "lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==" + }, + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "marked": { + "version": "14.1.4" + }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, + "mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "dependencies": { + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + } + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz", + "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==", + "requires": { + "wildcard": "^1.1.0" + } + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.2" + } + }, + "minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true + }, + "mitt": { + "version": "3.0.1" + }, + "mlly": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.1.tgz", + "integrity": "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==", + "dev": true, + "requires": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + }, + "dependencies": { + "pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true + } + } + }, + "mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "namespace-emitter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", + "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==" + }, + "nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + }, + "node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true + }, + "nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "requires": { + "abbrev": "^2.0.0" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true + }, + "normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==" + }, + "npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "requires": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } + } + }, + "nprogress": { + "version": "0.2.0" + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, + "pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true + }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, + "pinia": { + "version": "2.3.1", + "requires": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + } + }, + "pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true + }, + "pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "requires": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + }, + "dependencies": { + "pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true + } + } + }, + "postcss": { + "version": "8.5.6", + "requires": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + } + }, + "postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "requires": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + } + }, + "postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.1.1" + } + }, + "postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "preact": { + "version": "10.29.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.0.tgz", + "integrity": "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "3.6.2", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "dev": true, + "requires": { + "parse-ms": "^4.0.0" + } + }, + "prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==" + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "requires": { + "pify": "^2.3.0" + } + }, + "readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "requires": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true + }, + "rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true + }, + "rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "@types/estree": "1.0.8", + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-visualizer": { + "version": "5.14.0", + "dev": true, + "requires": { + "open": "^8.4.0", + "picomatch": "^4.0.2", + "source-map": "^0.7.4", + "yargs": "^17.5.1" + }, + "dependencies": { + "source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true + } + } + }, + "run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "sass": { + "version": "1.81.0", + "dev": true, + "requires": { + "@parcel/watcher": "^2.4.1", + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sax": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", + "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", + "dev": true + }, + "scroll-into-view-if-needed": { + "version": "2.2.31", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz", + "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==", + "requires": { + "compute-scroll-into-view": "^1.0.20" + } + }, + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, + "sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + } + }, + "slate": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz", + "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==", + "requires": { + "immer": "^9.0.6", + "is-plain-object": "^5.0.0", + "tiny-warning": "^1.0.3" + } + }, + "slate-history": { + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.66.0.tgz", + "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==", + "requires": { + "is-plain-object": "^5.0.0" + } + }, + "snabbdom": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.3.tgz", + "integrity": "sha512-W2lHLLw2qR2Vv0DcMmcxXqcfdBaIcoN+y/86SmHv8fn4DazEQSH6KN3TjZcWvwujW56OHiiirsbHWZb4vx/0fg==" + }, + "socket.io-client": { + "version": "4.8.3", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", + "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + } + }, + "sortablejs": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz", + "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true + }, + "ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "requires": { + "frac": "~1.1.2" + } + }, + "ssr-window": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz", + "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==" + }, + "store": { + "version": "2.0.12" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "requires": { + "ansi-regex": "^6.2.2" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + } + } + }, + "strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + } + } + }, + "superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "requires": { + "copy-anything": "^4" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "svgo": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", + "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "dev": true, + "requires": { + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0", + "sax": "^1.5.0" + } + }, + "synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "dev": true, + "requires": { + "@pkgr/core": "^0.2.9" + } + }, + "tailwindcss": { + "version": "3.4.17", + "dev": true, + "requires": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "dependencies": { + "chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + } + } + }, + "terser": { + "version": "5.43.1", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.14.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "requires": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true + }, + "ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true + }, + "ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typescript": { + "version": "5.5.4", + "dev": true + }, + "typescript-eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.0.tgz", + "integrity": "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==", + "dev": true, + "requires": { + "@typescript-eslint/eslint-plugin": "8.57.0", + "@typescript-eslint/parser": "8.57.0", + "@typescript-eslint/typescript-estree": "8.57.0", + "@typescript-eslint/utils": "8.57.0" + } + }, + "ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true + }, + "undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + }, + "unplugin": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz", + "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==", + "dev": true, + "requires": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + } + }, + "update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "requires": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "vite": { + "version": "5.4.19", + "dev": true, + "requires": { + "esbuild": "^0.21.3", + "fsevents": "~2.3.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + } + }, + "vite-hot-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.1.0.tgz", + "integrity": "sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==", + "dev": true + }, + "vite-plugin-compression": { + "version": "0.5.1", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "debug": "^4.3.3", + "fs-extra": "^10.0.0" + } + }, + "vite-plugin-inspect": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-0.8.9.tgz", + "integrity": "sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==", + "dev": true, + "requires": { + "@antfu/utils": "^0.7.10", + "@rollup/pluginutils": "^5.1.3", + "debug": "^4.3.7", + "error-stack-parser-es": "^0.1.5", + "fs-extra": "^11.2.0", + "open": "^10.1.0", + "perfect-debounce": "^1.0.0", + "picocolors": "^1.1.1", + "sirv": "^3.0.0" + }, + "dependencies": { + "define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true + }, + "fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "requires": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + } + } + } + }, + "vite-plugin-vue-devtools": { + "version": "7.7.7", + "dev": true, + "requires": { + "@vue/devtools-core": "^7.7.7", + "@vue/devtools-kit": "^7.7.7", + "@vue/devtools-shared": "^7.7.7", + "execa": "^9.5.2", + "sirv": "^3.0.1", + "vite-plugin-inspect": "0.8.9", + "vite-plugin-vue-inspector": "^5.3.1" + } + }, + "vite-plugin-vue-inspector": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-5.4.0.tgz", + "integrity": "sha512-Iq/024CydcE46FZqWPU4t4lw4uYOdLnFSO1RNxJVt2qY9zxIjmnkBqhHnYaReWM82kmNnaXs7OkfgRrV2GEjyw==", + "dev": true, + "requires": { + "@babel/core": "^7.23.0", + "@babel/plugin-proposal-decorators": "^7.23.0", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.22.15", + "@vue/babel-plugin-jsx": "^1.1.5", + "@vue/compiler-dom": "^3.3.4", + "kolorist": "^1.8.0", + "magic-string": "^0.30.4" + } + }, + "vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true + }, + "vue": { + "version": "3.5.18", + "requires": { + "@vue/compiler-dom": "3.5.18", + "@vue/compiler-sfc": "3.5.18", + "@vue/runtime-dom": "3.5.18", + "@vue/server-renderer": "3.5.18", + "@vue/shared": "3.5.18" + }, + "dependencies": { + "@vue/shared": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==" + } + } + }, + "vue-component-type-helpers": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.12.tgz", + "integrity": "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==", + "dev": true + }, + "vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==" + }, + "vue-echarts": { + "version": "7.0.3", + "requires": { + "vue-demi": "^0.13.11" + }, + "dependencies": { + "vue-demi": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", + "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==" + } + } + }, + "vue-eslint-parser": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.0.tgz", + "integrity": "sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==", + "dev": true, + "requires": { + "debug": "^4.4.0", + "eslint-scope": "^8.2.0 || ^9.0.0", + "eslint-visitor-keys": "^4.2.0 || ^5.0.0", + "espree": "^10.3.0 || ^11.0.0", + "esquery": "^1.6.0", + "semver": "^7.6.3" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true + }, + "espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "requires": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + } + } + } + }, + "vue-i18n": { + "version": "11.1.10", + "requires": { + "@intlify/core-base": "11.1.10", + "@intlify/shared": "11.1.10", + "@vue/devtools-api": "^6.5.0" + }, + "dependencies": { + "@intlify/core-base": { + "version": "11.1.10", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.1.10.tgz", + "integrity": "sha512-JhRb40hD93Vk0BgMgDc/xMIFtdXPHoytzeK6VafBNOj6bb6oUZrGamXkBKecMsmGvDQQaPRGG2zpa25VCw8pyw==", + "requires": { + "@intlify/message-compiler": "11.1.10", + "@intlify/shared": "11.1.10" + } + }, + "@intlify/message-compiler": { + "version": "11.1.10", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.1.10.tgz", + "integrity": "sha512-TABl3c8tSLWbcD+jkQTyBhrnW251dzqW39MPgEUCsd69Ua3ceoimsbIzvkcPzzZvt1QDxNkenMht+5//V3JvLQ==", + "requires": { + "@intlify/shared": "11.1.10", + "source-map-js": "^1.0.2" + } + }, + "@intlify/shared": { + "version": "11.1.10", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.1.10.tgz", + "integrity": "sha512-6ZW/f3Zzjxfa1Wh0tYQI5pLKUtU+SY7l70pEG+0yd0zjcsYcK0EBt6Fz30Dy0tZhEqemziQQy2aNU3GJzyrMUA==" + } + } + }, + "vue-router": { + "version": "4.5.1", + "requires": { + "@vue/devtools-api": "^6.6.4" + } + }, + "vue-tsc": { + "version": "2.2.12", + "dev": true, + "requires": { + "@volar/typescript": "2.4.15", + "@vue/language-core": "2.2.12" + } + }, + "vuedraggable": { + "version": "4.1.0", + "requires": { + "sortablejs": "1.14.0" + } + }, + "webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", + "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==" + }, + "wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==" + }, + "word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==" + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==" + }, + "wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "requires": { + "is-wsl": "^3.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "requires": { + "is-inside-container": "^1.0.0" + } + } + } + }, + "xlsx": { + "version": "0.18.5", + "requires": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + } + }, + "xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true + }, + "yaml-eslint-parser": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.3.2.tgz", + "integrity": "sha512-odxVsHAkZYYglR30aPYRY4nUGJnoJ2y1ww2HDvZALo0BDETv9kWbi16J52eHs+PWRNmF4ub6nZqfVOeesOvntg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.0.0", + "yaml": "^2.0.0" + } + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, + "yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true + }, + "zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "requires": { + "tslib": "2.3.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..94fcbc2 --- /dev/null +++ b/package.json @@ -0,0 +1,77 @@ +{ + "name": "cool-admin-vue", + "version": "8.0.0", + "type": "module", + "scripts": { + "dev": "vite --host", + "build": "vite build", + "build-static": "vite build --mode static", + "build-demo": "vite build --mode demo", + "preview": "vite preview", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix", + "format": "prettier --write src/" + }, + "dependencies": { + "@cool-vue/crud": "^8.0.6", + "@element-plus/icons-vue": "^2.3.1", + "@vueuse/core": "^12.5.0", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^5.1.12", + "axios": "^1.7.9", + "chardet": "^2.0.0", + "core-js": "^3.40.0", + "dayjs": "^1.11.13", + "echarts": "^5.6.0", + "element-plus": "2.10.2", + "file-saver": "^2.0.5", + "lodash-es": "^4.17.21", + "marked": "^14.1.3", + "mitt": "^3.0.1", + "nprogress": "^0.2.0", + "pinia": "^2.3.1", + "socket.io-client": "^4.8.3", + "store": "^2.0.12", + "vue": "^3.5.13", + "vue-echarts": "^7.0.3", + "vue-i18n": "^11.0.1", + "vue-router": "^4.5.0", + "vuedraggable": "^4.1.0", + "xlsx": "^0.18.5" + }, + "devDependencies": { + "@cool-vue/vite-plugin": "^8.2.2", + "@intlify/unplugin-vue-i18n": "^6.0.3", + "@rushstack/eslint-patch": "^1.10.5", + "@tsconfig/node20": "^20.1.4", + "@types/file-saver": "^2.0.7", + "@types/lodash-es": "^4.17.12", + "@types/mockjs": "^1.0.10", + "@types/node": "^20.19.37", + "@types/nprogress": "^0.2.3", + "@types/store": "^2.0.5", + "@vitejs/plugin-vue": "^5.2.1", + "@vitejs/plugin-vue-jsx": "^4.1.1", + "@vue/compiler-sfc": "^3.5.13", + "@vue/eslint-config-prettier": "^10.2.0", + "@vue/eslint-config-typescript": "^14.3.0", + "@vue/runtime-core": "^3.5.30", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.5.1", + "autoprefixer": "^10.4.20", + "eslint": "^9.19.0", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-vue": "^9.32.0", + "postcss": "^8.5.1", + "prettier": "^3.4.2", + "rollup-plugin-visualizer": "^5.14.0", + "sass": "1.81.0", + "tailwindcss": "^3.4.17", + "terser": "^5.36.0", + "typescript": "~5.5.4", + "vite": "^5.4.14", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-vue-devtools": "^7.7.1", + "vue-tsc": "^2.2.0" + } +} diff --git a/packages/crud/.gitignore b/packages/crud/.gitignore new file mode 100644 index 0000000..403adbc --- /dev/null +++ b/packages/crud/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist + + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/packages/crud/.prettierrc b/packages/crud/.prettierrc new file mode 100644 index 0000000..b82b0c6 --- /dev/null +++ b/packages/crud/.prettierrc @@ -0,0 +1,9 @@ +{ + "tabWidth": 4, + "useTabs": true, + "semi": true, + "jsxBracketSameLine": true, + "singleQuote": false, + "printWidth": 100, + "trailingComma": "none" +} diff --git a/packages/crud/README.md b/packages/crud/README.md new file mode 100644 index 0000000..9500cde --- /dev/null +++ b/packages/crud/README.md @@ -0,0 +1,33 @@ +# 介绍 + +**cool-admin for vue**是基于[Vue.js](https://v3.cn.vuejs.org)开发。 + +[cool-admin 官方文档](https://cool-js.com/) + +尝试 `cool-admin` 最简单的方法就是查看文档及运行示例。 + + + +[Ai极速编码 🔥 在线体验](https://show.cool-admin.com/helper/ai-code) + + + +## 代码仓库 + +**cool-admin for vue** 是开源免费的,遵循[MIT](https://baike.baidu.com/item/MIT/10772952)开源协议,意味着您无需支付任何费用,也无需授权,即可将它应用到您的产品中。 + +开源免费,并不意味着您可以将 cool-admin 应用到非法的领域,比如涉及赌博,暴力等方面。如因此产生纠纷等法律问题,`cool-admin`不承担任何责任。 + +[https://github.com/cool-team-official/cool-admin-vue](https://github.com/cool-team-official/cool-admin-vue) + +```shell +git clone https://github.com/cool-team-official/cool-admin-vue.git +``` + +## 技术选型 + +- [Vue.js](https://v3.cn.vuejs.org),基础框架; +- [VueRouter](https://router.vuejs.org),Vue.js 官方路由; +- [Pinia](https://pinia.vuejs.org),轻量级状态管理库; +- [ElementPlus](https://element-plus.gitee.io/zh-CN),桌面端组件库; +- [Vite](https://vitejs.cn),构建工具; diff --git a/packages/crud/index.d.ts b/packages/crud/index.d.ts new file mode 100644 index 0000000..2d403ac --- /dev/null +++ b/packages/crud/index.d.ts @@ -0,0 +1,811 @@ +// vue +declare namespace Vue { + interface Ref { + value: T; + } + + type Emit = (name: any, ...args: any[]) => void; +} + +// element-plus +declare namespace ElementPlus { + type Size = "large" | "default" | "small"; + type Align = "left" | "center" | "right"; + + interface FormProps { + inline?: boolean; + labelPosition?: "left" | "right" | "top"; + labelWidth?: string | number; + labelSuffix?: string; + hideRequiredAsterisk?: boolean; + showMessage?: boolean; + inlineMessage?: boolean; + statusIcon?: boolean; + validateOnRuleChange?: boolean; + size?: Size; + disabled?: boolean; + [key: string]: any; + } +} + +// mitt +declare interface Mitt { + on(name: string, callback: (data: any) => void): void; + off(name: string, callback: (data: any) => void): void; + emit(name: string, data?: any): void; +} + +// emitter +declare interface EmitterItem { + name: string; + callback(data: any, events: { refresh(params: any): void; crudList: ClCrud.Ref[] }): void; +} + +declare interface Emitter { + list: EmitterItem[]; + init(events: any): void; + on(name: string, callback: (data: any) => void): void; + emit(name: string, data?: any): void; +} + +// 方法 +declare type fn = () => void; + +// 对象 +declare type obj = { + [key: string]: any; +}; + +// 全部可选 +declare type DeepPartial = T extends Function + ? T + : T extends object + ? { [P in keyof T]?: DeepPartial } + : T; + +// 合并 +declare type Merge = Omit & B; + +// 移除 [key] +declare type RemoveIndex = { + [P in keyof T as string extends P ? never : number extends P ? never : P]: T[P]; +}; + +// 任用列表 +declare type List = Array | (() => DeepPartial)>; + +// 获取keys +declare type PropKey = keyof RemoveIndex | (string & {}); + +// 任意字符串 +declare type AnyString = string & {}; + +// 类型或者 Ref 泛型 +declare type RefData = T | Vue.Ref; + +// browser +declare type Browser = { + screen: string; + isMini: boolean; +}; + +// 字典选项 +declare type DictOptions = { + label?: string; + value?: any; + color?: string; + type?: string; + [key: string]: any; +}[]; + +// render +declare namespace Render { + type OpButton = + | `slot-${string}` + | { + label: string; + type?: string; + hidden?: boolean; + onClick(options: { scope: obj }): void; + [key: string]: any; + }; + + interface Props { + onChange?(value: any): void; + [key: string]: any; + } + + interface Component { + name?: string; + options?: RefData; + props?: RefData; + style?: obj; + slots?: { + [key: string]: (data?: any) => any; + }; + vm?: any; + [key: string]: any; + } +} + +// crud +declare namespace ClCrud { + declare interface Field { + comment: string; + source: string; + propertyName: string; + type: string; + dict: string | string[]; + nullable: boolean; + } + + interface Label { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + placeholderSelect: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; + [key: string]: string; + } + + interface Dict { + primaryId: string; + api: { + list: string; + add: string; + update: string; + delete: string; + info: string; + page: string; + }; + pagination: { + page: string; + size: string; + }; + search: { + keyWord: string; + query: string; + }; + sort: { + order: string; + prop: string; + }; + label: Label; + } + + interface Permission { + page?: boolean; + list?: boolean; + add?: boolean; + delete?: boolean; + update?: boolean; + info?: boolean; + [key: string]: any; + } + + interface Params { + page: { + page?: number; + size?: number; + [key: string]: any; + }; + list: obj; + add: obj; + delete: { + ids?: any[]; + [key: string]: any; + }; + update: { + id?: any; + [key: string]: any; + }; + info: { + id?: any; + [key: string]: any; + }; + } + + interface Response { + page: { + list: any[]; + pagination: { + total: number; + page: number; + size: number; + [key: string]: any; + }; + [key: string]: any; + }; + list: any[]; + add: any; + update: any; + info: any; + delete: any; + } + + interface Service { + api: { + page(params?: Params["page"]): Promise; + list(params?: Params["list"]): Promise; + add(params?: Params["add"]): Promise; + update(params?: Params["update"]): Promise; + info(params?: Params["info"]): Promise; + delete(params?: Params["delete"]): Promise; + permission: Permission; + search: { + fieldEq: Field[]; + fieldLike: Field[]; + keyWordLikeFields: Field[]; + }; + [key: string]: any; + }; + } + + interface Config { + name: string; + service: Service["api"]; + permission: Permission; + dict: Dict; + onRefresh( + params: obj, + event: { + done: fn; + next: Service["api"]["page"]; + render: (data: any | any[], pagination?: Response["page"]["pagination"]) => void; + } + ): void; + onDelete( + selection: obj[], + event: { + next: Service["api"]["delete"]; + } + ): void; + } + + interface Ref { + "cl-table": ClTable.Ref; + "cl-upsert": ClUpsert.Ref; + id: number; + mitt: Mitt; + name: string; + routePath: string; + permission: Permission; + dict: Dict; + service: Service["api"]; + loading: boolean; + params: obj; + selection: obj[]; + set(key: "dict" | "style" | "service" | "permission", value: any): void; + done(): void; + getParams(): obj; + setParams(data: obj): void; + getPermission(key?: string): boolean; + rowInfo(data: obj): void; + rowAdd(): void; + rowEdit(data: obj): void; + rowAppend(data?: obj): void; + rowClose(): void; + rowDelete(...selection: obj[]): void; + proxy(name: string, data?: any[]): any; + paramsReplace(params: obj): obj; + refresh: Service["api"]["page"]; + [key: string]: any; + } + + interface Options extends DeepPartial { + service?: any; + } +} + +declare namespace ClTable { + type OpButton = Array<"info" | "edit" | "delete" | AnyString | Render.OpButton>; + + type ColumnType = "index" | "selection" | "expand" | "op" | AnyString; + + interface Column { + type: ColumnType; + hidden: RefData; + component: Render.Component; + search: { + isInput: boolean; + value: any; + icon: () => any; + refreshOnChange: boolean; + component: Render.Component; + }; + dict: RefData; + dictFormatter: (values: DictOptions) => string; + dictColor: boolean; + dictSeparator: string; + dictAllLevels: boolean; + buttons: OpButton | ((options: { scope: T }) => OpButton); + align: ElementPlus.Align; + label: any; + renderLabel: (options: { column: any; $index: number }) => any; + className: string; + prop: PropKey; + orderNum: number; + width: RefData; + minWidth: RefData; + renderHeader: (options: { column: any; $index: number }) => any; + sortable: boolean | "desc" | "descending" | "ascending" | "asc" | "custom"; + sortMethod: fn; + sortBy: string | ((row: T, index: number) => any) | any[]; + resizable: boolean; + columnKey: string; + headerAlign: ElementPlus.Align; + showOverflowTooltip: boolean; + fixed: boolean | string; + render: (row: T, column: any, value: any, index: number) => any; + formatter: (row: T, column: any, value: any, index: number) => any; + selectable: (row: T, index: number) => boolean; + reserveSelection: boolean; + filterMethod: fn; + filteredValue: unknown[]; + filters: unknown[]; + filterPlacement: string; + filterMultiple: boolean; + index: ((index: number) => number) | number; + sortOrders: unknown[]; + children: Column[]; + [key: string]: any; + } + + type ContextMenu = Array< + | ClContextMenu.Item + | ((row: obj, column: obj, event: PointerEvent) => ClContextMenu.Item) + | "refresh" + | "check" + | "update" + | "edit" + | "delete" + | "info" + | "order-desc" + | "order-asc" + >; + + type Plugin = (options: { exposed: Ref }) => void; + + interface Config { + columns: Column[]; + autoHeight: boolean; + height: any; + contextMenu: ContextMenu; + defaultSort: { + prop: string; + order: "descending" | "ascending"; + }; + sortRefresh: boolean; + emptyText: string; + rowKey: string; + on?: { + [key: string]: (...args: any[]) => void; + }; + props?: { + [key: string]: any; + }; + plugins?: Plugin[]; + onRowContextmenu?(row: T, column: any, event: any): void; + } + + interface Ref { + Table: any; + config: obj; + selection: T[]; + data: T[]; + columns: Column[]; + reBuild(cb?: fn): void; + calcMaxHeight(): void; + setData(data: T[]): void; + setColumns(columns: Column[]): void; + showColumn(props: PropKey | PropKey[], status?: boolean): void; + hideColumn(props: PropKey | PropKey[]): void; + changeSort(prop: PropKey, order: string): void; + clearSelection(): void; + getSelectionRows(): any[]; + toggleRowSelection(row: T, selected?: boolean): void; + toggleAllSelection(): void; + toggleRowExpansion(row: T, expanded?: boolean): void; + setCurrentRow(row: T): void; + clearSort(): void; + clearFilter(columnKeys: PropKey[]): void; + doLayout(): void; + sort(prop: PropKey, order: string): void; + scrollTo(position: { top?: number; left?: number }): void; + setScrollTop(top: number): void; + setScrollLeft(left: number): void; + updateKeyChildren(key: string, children: any[]): void; + } + + interface Options extends DeepPartial> { + columns?: List>; + } +} + +declare namespace ClFormTabs { + type labels = { + label: string; + value: string; + name?: string; + icon?: any; + lazy?: boolean; + [key: string]: any; + }[]; +} + +declare namespace ClForm { + type CloseAction = "close" | "save" | AnyString; + + interface Rule { + type?: + | "string" + | "number" + | "boolean" + | "method" + | "regexp" + | "integer" + | "float" + | "array" + | "object" + | "enum" + | "date" + | "url" + | "hex" + | "email" + | "any"; + required?: boolean; + message?: string; + min?: number; + max?: number; + trigger?: any; + validator?(rule: any, value: any, callback: (error?: Error) => void): void; + [key: string]: any; + } + + interface Hook { + Fn: (value: any, options: { form: obj; prop: string; method: "submit" | "bind" }) => any; + Key: + | "number" + | "string" + | "split" + | "join" + | "boolean" + | "booleanNumber" + | "datetimeRange" + | "splitJoin" + | "json" + | "empty" + | AnyString; + Pipe: Hook["Key"] | Hook["Fn"]; + Event: { + bind?: Hook["Pipe"] | Hook["Pipe"][]; + submit?: Hook["Pipe"] | Hook["Pipe"][]; + reset?: (prop: string) => string[]; + }; + } + + interface Item { + type?: "tabs"; + prop?: PropKey; + props?: { + labels?: ClFormTabs.labels; + justify?: "left" | "center" | "right"; + color?: string; + mergeProp?: boolean; + labelWidth?: string; + error?: string; + showMessage?: boolean; + inlineMessage?: boolean; + size?: "medium" | "default" | "small"; + [key: string]: any; + }; + span?: number; + col?: { + span: number; + offset: number; + push: number; + pull: number; + xs: any; + sm: any; + md: any; + lg: any; + xl: any; + tag: string; + }; + group?: string; + collapse?: boolean; + value?: any; + label?: string; + renderLabel?: any; + flex?: boolean; + hook?: Hook["Event"] | Hook["Key"]; + hidden?: boolean | ((options: { scope: obj }) => boolean); + prepend?: Render.Component; + component?: Render.Component; + append?: Render.Component; + rules?: Rule | Rule[]; + required?: boolean; + children?: Item[]; + [key: string]: any; + } + + interface Config { + title?: any; + height?: any; + width?: any; + props: ElementPlus.FormProps; + items: Item[]; + form: obj; + isReset?: boolean; + on?: { + open?(data: T): void; + close?(action: CloseAction, done: fn): void; + submit?(data: T, event: { close: fn; done: fn }): void; + change?(data: T, prop: string): void; + }; + op: { + hidden?: boolean; + saveButtonText?: string; + closeButtonText?: string; + justify?: "flex-start" | "center" | "flex-end"; + buttons?: Array; + }; + dialog: { + title?: any; + height?: string; + width?: string; + hideHeader?: boolean; + controls?: Array<"fullscreen" | "close" | AnyString>; + [key: string]: any; + }; + [key: string]: any; + } + + type Plugin = (options: { + exposed: Ref; + onOpen(cb: () => void): void; + onClose(cb: () => void): void; + onSubmit(cb: (data: obj) => obj): void; + }) => void; + + type Items = List>; + + interface Ref { + Form: any; + form: T; + config: { + items: Item[]; + [key: string]: any; + }; + open(options: Options, plugins?: Plugin[]): void; + close(action?: CloseAction): void; + done(): void; + clear(): void; + reset(): void; + showLoading(): void; + hideLoading(): void; + setDisabled(flag?: boolean): void; + invokeData(data: any): void; + setData(prop: string, value: any): void; + bindForm(data: obj): void; + getForm(prop?: string): any; + setForm(prop: string, value: any): void; + setOptions(prop: string, list: DictOptions): void; + setProps(prop: string, value: any): void; + setConfig(path: string, value: any): void; + showItem(props: string[] | string): void; + hideItem(props: string[] | string): void; + toggleItem(prop: string, flag?: boolean): void; + resetFields(): void; + clearValidate(props?: string[] | string): void; + validateField( + props?: string[] | string, + callback?: (isValid: boolean, invalidFields: any[]) => void + ): Promise; + validate(callback: (isValid: boolean, invalidFields: any[]) => void): Promise; + changeTab(value: any, valid?: boolean): Promise; + setTitle(value: string): void; + submit(cb?: (data: obj) => void): void; + Tabs: { + active: RefData; + list: ClFormTabs.labels; + change(value: any, valid?: boolean): Promise; + [key: string]: any; + }; + [key: string]: any; + } + + interface Options extends DeepPartial { + items?: Items; + } +} + +declare namespace ClUpsert { + interface Config { + sync: boolean; + items: ClForm.Item[]; + props: ClForm.Config["props"]; + op: ClForm.Config["op"]; + dialog: ClForm.Config["dialog"]; + onOpen?(): void; + onOpened?(data: T): void; + onClose?(action: ClForm.CloseAction, done: fn): void; + onClosed?(): void; + onInfo?( + data: T, + event: { close: fn; done(data: T): void; next: ClCrud.Service["api"]["info"] } + ): void; + onSubmit?( + data: T, + event: { close: fn; done: fn; next: ClCrud.Service["api"]["update"] } + ): void; + plugins?: ClForm.Plugin[]; + } + + interface Ref extends ClForm.Ref { + mode: "add" | "update" | "info" | AnyString; + } + + interface Options extends DeepPartial> { + items?: ClForm.Items; + } +} + +declare namespace ClAdvSearch { + interface Config { + items?: ClForm.Item[]; + title?: string; + size?: string | number; + op?: ("clear" | "reset" | "close" | "search" | `slot-${string}`)[]; + onSearch?(data: T, options: { next: ClCrud.Service["api"]["page"]; close(): void }): void; + } + + interface Ref extends ClForm.Ref {} + + interface Options extends DeepPartial> { + items?: ClForm.Items; + } +} + +declare namespace ClSearch { + type Plugin = (options: { exposed: Ref }) => void; + + interface Config { + inline?: boolean; + items?: ClForm.Item[]; + data?: T; + props?: ElementPlus.FormProps; + resetBtn?: boolean; + collapse?: boolean; + Form?: ClForm.Ref; + onChange?(data: T, prop: string): void; + onLoad?(data: T): void; + onSearch?(data: T, options: { next: ClCrud.Service["api"]["page"] }): void; + plugins?: Plugin[]; + } + + interface Ref extends ClForm.Ref { + search(params?: obj): void; + reset(): void; + } + + interface Options extends DeepPartial> { + items?: ClForm.Items; + } +} + +declare namespace ClContextMenu { + interface Item { + label: string; + prefixIcon?: any; + suffixIcon?: any; + ellipsis?: boolean; + disabled?: boolean; + hidden?: boolean; + children?: Item[]; + showChildren?: boolean; + callback?(done: fn): void; + [key: string]: any; + } + + interface Event { + pageX: number; + pageY: number; + [key: string]: any; + } + + interface Options { + class?: string; + hover?: + | boolean + | { + target?: string; + className?: string; + }; + list?: Item[]; + } + + interface Ref { + open(event: Event, options: Options): Exposed; + close(): void; + } + + interface Exposed { + close(): void; + } +} + +declare namespace ClDialog { + interface Provide { + visible: Vue.Ref; + fullscreen: Vue.Ref; + } +} + +declare interface Config { + dict: ClCrud.Dict; + permission: ClCrud.Permission; + events: { + [key: string]: (...args: any[]) => any; + }; + style: { + size: ElementPlus.Size; + colors: string[]; + form: { + labelPosition: ElementPlus.FormProps["labelPosition"]; + labelWidth: ElementPlus.FormProps["labelWidth"]; + span: number; + plugins: ClForm.Plugin[]; + }; + table: { + stripe: boolean; + border: boolean; + highlightCurrentRow: boolean; + resizable: boolean; + autoHeight: boolean; + contextMenu: ClTable.ContextMenu; + column: { + minWidth: number | string; + align: ElementPlus.Align; + headerAlign: ElementPlus.Align; + opWidth: number | string; + }; + plugins: ClTable.Plugin[]; + }; + search: { + plugins: ClSearch.Plugin[]; + }; + }; +} + +declare type Options = DeepPartial; + +declare interface CrudOptions { + options: Options; +} diff --git a/packages/crud/index.html b/packages/crud/index.html new file mode 100644 index 0000000..79f5bc6 --- /dev/null +++ b/packages/crud/index.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + +
+
+

+
+

+

+
+
+ +
+ + + diff --git a/packages/crud/package.json b/packages/crud/package.json new file mode 100644 index 0000000..9ababe6 --- /dev/null +++ b/packages/crud/package.json @@ -0,0 +1,38 @@ +{ + "name": "@cool-vue/crud", + "version": "8.0.6", + "private": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.es.js", + "types": "types/entry.d.ts", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@vue/runtime-core": "^3.5.13", + "element-plus": "^2.10.4", + "lodash-es": "^4.17.21", + "vue": "^3.5.13" + }, + "devDependencies": { + "@types/node": "^20.11.16", + "@vitejs/plugin-vue": "^5.2.1", + "@vitejs/plugin-vue-jsx": "^4.1.1", + "prettier": "^3.5.1", + "sass": "^1.85.0", + "sass-loader": "^16.0.5", + "typescript": "^5.3.3", + "vite": "^6.1.0", + "vite-plugin-dts": "^4.5.0", + "vue-tsc": "^2.2.2" + }, + "files": [ + "types", + "dist", + "index.d.ts", + "index.ts" + ] +} diff --git a/packages/crud/pnpm-lock.yaml b/packages/crud/pnpm-lock.yaml new file mode 100644 index 0000000..471c806 --- /dev/null +++ b/packages/crud/pnpm-lock.yaml @@ -0,0 +1,2350 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@vue/runtime-core': + specifier: ^3.5.13 + version: 3.5.13 + element-plus: + specifier: ^2.9.4 + version: 2.9.4(vue@3.5.13(typescript@5.7.3)) + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + vue: + specifier: ^3.5.13 + version: 3.5.13(typescript@5.7.3) + devDependencies: + '@types/node': + specifier: ^20.11.16 + version: 20.17.19 + '@vitejs/plugin-vue': + specifier: ^5.2.1 + version: 5.2.1(vite@6.1.0(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3)) + '@vitejs/plugin-vue-jsx': + specifier: ^4.1.1 + version: 4.1.1(vite@6.1.0(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3)) + prettier: + specifier: ^3.5.1 + version: 3.5.1 + sass: + specifier: ^1.85.0 + version: 1.85.0 + sass-loader: + specifier: ^16.0.5 + version: 16.0.5(sass@1.85.0) + typescript: + specifier: ^5.3.3 + version: 5.7.3 + vite: + specifier: ^6.1.0 + version: 6.1.0(@types/node@20.17.19)(sass@1.85.0) + vite-plugin-dts: + specifier: ^4.5.0 + version: 4.5.0(@types/node@20.17.19)(rollup@4.34.8)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(sass@1.85.0)) + vue-tsc: + specifier: ^2.2.2 + version: 2.2.2(typescript@5.7.3) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.26.8': + resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.26.9': + resolution: {integrity: sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.26.9': + resolution: {integrity: sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.25.9': + resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.26.5': + resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.26.9': + resolution: {integrity: sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-member-expression-to-functions@7.25.9': + resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.25.9': + resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.26.5': + resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.26.5': + resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.26.9': + resolution: {integrity: sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.26.9': + resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.26.8': + resolution: {integrity: sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.26.9': + resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.26.9': + resolution: {integrity: sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.26.9': + resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} + engines: {node: '>=6.9.0'} + + '@ctrl/tinycolor@3.6.1': + resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} + engines: {node: '>=10'} + + '@element-plus/icons-vue@2.3.1': + resolution: {integrity: sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==} + peerDependencies: + vue: ^3.2.0 + + '@esbuild/aix-ppc64@0.24.2': + resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.24.2': + resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.24.2': + resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.24.2': + resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.24.2': + resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.24.2': + resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.24.2': + resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.24.2': + resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.24.2': + resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.24.2': + resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.24.2': + resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.24.2': + resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.24.2': + resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.24.2': + resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.24.2': + resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.24.2': + resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.24.2': + resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.24.2': + resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.24.2': + resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.24.2': + resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.2': + resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.24.2': + resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.24.2': + resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.24.2': + resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.24.2': + resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@floating-ui/core@1.6.9': + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + + '@floating-ui/dom@1.6.13': + resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@microsoft/api-extractor-model@7.30.3': + resolution: {integrity: sha512-yEAvq0F78MmStXdqz9TTT4PZ05Xu5R8nqgwI5xmUmQjWBQ9E6R2n8HB/iZMRciG4rf9iwI2mtuQwIzDXBvHn1w==} + + '@microsoft/api-extractor@7.50.0': + resolution: {integrity: sha512-Ds/PHTiVzuENQsmXrJKkSdfgNkr/SDG/2rDef0AWl3BchAnXdO7gXaYsAkNx4gWiC4OngNA3fQfd3+BcQxP1DQ==} + hasBin: true + + '@microsoft/tsdoc-config@0.17.1': + resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==} + + '@microsoft/tsdoc@0.15.1': + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + + '@rollup/pluginutils@5.1.4': + resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.34.8': + resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.34.8': + resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.34.8': + resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.34.8': + resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.34.8': + resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.34.8': + resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.34.8': + resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.34.8': + resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.34.8': + resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.34.8': + resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loongarch64-gnu@4.34.8': + resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': + resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-gnu@4.34.8': + resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-s390x-gnu@4.34.8': + resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.34.8': + resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.34.8': + resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-win32-arm64-msvc@4.34.8': + resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.34.8': + resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.34.8': + resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==} + cpu: [x64] + os: [win32] + + '@rushstack/node-core-library@5.11.0': + resolution: {integrity: sha512-I8+VzG9A0F3nH2rLpPd7hF8F7l5Xb7D+ldrWVZYegXM6CsKkvWc670RlgK3WX8/AseZfXA/vVrh0bpXe2Y2UDQ==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.5.3': + resolution: {integrity: sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==} + + '@rushstack/terminal@0.15.0': + resolution: {integrity: sha512-vXQPRQ+vJJn4GVqxkwRe+UGgzNxdV8xuJZY2zem46Y0p3tlahucH9/hPmLGj2i9dQnUBFiRnoM9/KW7PYw8F4Q==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@4.23.5': + resolution: {integrity: sha512-jg70HfoK44KfSP3MTiL5rxsZH7X1ktX3cZs9Sl8eDu1/LxJSbPsh0MOFRC710lIuYYSgxWjI5AjbCBAl7u3RxA==} + + '@sxzz/popperjs-es@2.11.7': + resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==} + + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash@4.17.15': + resolution: {integrity: sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==} + + '@types/node@20.17.19': + resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==} + + '@types/web-bluetooth@0.0.16': + resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} + + '@vitejs/plugin-vue-jsx@4.1.1': + resolution: {integrity: sha512-uMJqv/7u1zz/9NbWAD3XdjaY20tKTf17XVfQ9zq4wY1BjsB/PjpJPMe2xiG39QpP4ZdhYNhm4Hvo66uJrykNLA==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.0.0 + + '@vitejs/plugin-vue@5.2.1': + resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.2.25 + + '@volar/language-core@2.4.11': + resolution: {integrity: sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==} + + '@volar/source-map@2.4.11': + resolution: {integrity: sha512-ZQpmafIGvaZMn/8iuvCFGrW3smeqkq/IIh9F1SdSx9aUl0J4Iurzd6/FhmjNO5g2ejF3rT45dKskgXWiofqlZQ==} + + '@volar/typescript@2.4.11': + resolution: {integrity: sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==} + + '@vue/babel-helper-vue-transform-on@1.2.5': + resolution: {integrity: sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==} + + '@vue/babel-plugin-jsx@1.2.5': + resolution: {integrity: sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + + '@vue/babel-plugin-resolve-type@1.2.5': + resolution: {integrity: sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@vue/compiler-core@3.5.13': + resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + + '@vue/compiler-dom@3.5.13': + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + + '@vue/compiler-sfc@3.5.13': + resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + + '@vue/compiler-ssr@3.5.13': + resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + + '@vue/language-core@2.2.0': + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/language-core@2.2.2': + resolution: {integrity: sha512-QotO41kurE5PLf3vrNgGTk3QswO2PdUFjBwNiOi7zMmGhwb25PSTh9hD1MCgKC06AVv+8sZQvlL3Do4TTVHSiQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/reactivity@3.5.13': + resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + + '@vue/runtime-core@3.5.13': + resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + + '@vue/runtime-dom@3.5.13': + resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + + '@vue/server-renderer@3.5.13': + resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + peerDependencies: + vue: 3.5.13 + + '@vue/shared@3.5.13': + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + + '@vueuse/core@9.13.0': + resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} + + '@vueuse/metadata@9.13.0': + resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} + + '@vueuse/shared@9.13.0': + resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + + ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + + alien-signals@0.4.14: + resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} + + alien-signals@1.0.3: + resolution: {integrity: sha512-zQOh3wAYK5ujENxvBBR3CFGF/b6afaSzZ/c9yNhJ1ENrGHETvpUuKQsa93Qrclp0+PzTF93MaZ7scVp1uUozhA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + async-validator@4.2.5: + resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + caniuse-lite@1.0.30001700: + resolution: {integrity: sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + electron-to-chromium@1.5.102: + resolution: {integrity: sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==} + + element-plus@2.9.4: + resolution: {integrity: sha512-sGnW0wd9zf6lEGixXV2gfwx3X6VTMkP52qTkX7zbURJ2oariyslrKTBh2txt1sdn1pUvj2l0KY3OfSXoZGmDOw==} + peerDependencies: + vue: ^3.2.0 + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + esbuild@0.24.2: + resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + engines: {node: '>=14.14'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + + immutable@5.0.3: + resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} + + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + local-pkg@0.5.1: + resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} + engines: {node: '>=14'} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash-unified@1.0.3: + resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==} + peerDependencies: + '@types/lodash-es': '*' + lodash: '*' + lodash-es: '*' + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.0.8: + resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-wheel-es@1.2.0: + resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + postcss@8.5.2: + resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.5.1: + resolution: {integrity: sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==} + engines: {node: '>=14'} + hasBin: true + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + rollup@4.34.8: + resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + sass-loader@16.0.5: + resolution: {integrity: sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==} + engines: {node: '>= 18.12.0'} + peerDependencies: + '@rspack/core': 0.x || 1.x + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + sass: ^1.3.0 + sass-embedded: '*' + webpack: ^5.0.0 + peerDependenciesMeta: + '@rspack/core': + optional: true + node-sass: + optional: true + sass: + optional: true + sass-embedded: + optional: true + webpack: + optional: true + + sass@1.85.0: + resolution: {integrity: sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==} + engines: {node: '>=14.0.0'} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svg-tags@1.0.0: + resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + update-browserslist-db@1.1.2: + resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + vite-plugin-dts@4.5.0: + resolution: {integrity: sha512-M1lrPTdi7gilLYRZoLmGYnl4fbPryVYsehPN9JgaxjJKTs8/f7tuAlvCCvOLB5gRDQTTKnptBcB0ACsaw2wNLw==} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + vite@6.1.0: + resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-tsc@2.2.2: + resolution: {integrity: sha512-1icPKkxAA5KTAaSwg0wVWdE48EdsH8fgvcbAiqojP4jXKl6LEM3soiW1aG/zrWrFt8Mw1ncG2vG1PvpZpVfehA==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue@3.5.13: + resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.26.8': {} + + '@babel/core@7.26.9': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.9 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) + '@babel/helpers': 7.26.9 + '@babel/parser': 7.26.9 + '@babel/template': 7.26.9 + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.26.9': + dependencies: + '@babel/parser': 7.26.9 + '@babel/types': 7.26.9 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.25.9': + dependencies: + '@babel/types': 7.26.9 + + '@babel/helper-compilation-targets@7.26.5': + dependencies: + '@babel/compat-data': 7.26.8 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.4 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.26.9(@babel/core@7.26.9)': + dependencies: + '@babel/core': 7.26.9 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/traverse': 7.26.9 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-member-expression-to-functions@7.25.9': + dependencies: + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.9)': + dependencies: + '@babel/core': 7.26.9 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.25.9': + dependencies: + '@babel/types': 7.26.9 + + '@babel/helper-plugin-utils@7.26.5': {} + + '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.9)': + dependencies: + '@babel/core': 7.26.9 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/traverse': 7.26.9 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + dependencies: + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helpers@7.26.9': + dependencies: + '@babel/template': 7.26.9 + '@babel/types': 7.26.9 + + '@babel/parser@7.26.9': + dependencies: + '@babel/types': 7.26.9 + + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.9)': + dependencies: + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.9)': + dependencies: + '@babel/core': 7.26.9 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-typescript@7.26.8(@babel/core@7.26.9)': + dependencies: + '@babel/core': 7.26.9 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.9) + transitivePeerDependencies: + - supports-color + + '@babel/template@7.26.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.9 + '@babel/types': 7.26.9 + + '@babel/traverse@7.26.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.9 + '@babel/parser': 7.26.9 + '@babel/template': 7.26.9 + '@babel/types': 7.26.9 + debug: 4.4.0 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.26.9': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@ctrl/tinycolor@3.6.1': {} + + '@element-plus/icons-vue@2.3.1(vue@3.5.13(typescript@5.7.3))': + dependencies: + vue: 3.5.13(typescript@5.7.3) + + '@esbuild/aix-ppc64@0.24.2': + optional: true + + '@esbuild/android-arm64@0.24.2': + optional: true + + '@esbuild/android-arm@0.24.2': + optional: true + + '@esbuild/android-x64@0.24.2': + optional: true + + '@esbuild/darwin-arm64@0.24.2': + optional: true + + '@esbuild/darwin-x64@0.24.2': + optional: true + + '@esbuild/freebsd-arm64@0.24.2': + optional: true + + '@esbuild/freebsd-x64@0.24.2': + optional: true + + '@esbuild/linux-arm64@0.24.2': + optional: true + + '@esbuild/linux-arm@0.24.2': + optional: true + + '@esbuild/linux-ia32@0.24.2': + optional: true + + '@esbuild/linux-loong64@0.24.2': + optional: true + + '@esbuild/linux-mips64el@0.24.2': + optional: true + + '@esbuild/linux-ppc64@0.24.2': + optional: true + + '@esbuild/linux-riscv64@0.24.2': + optional: true + + '@esbuild/linux-s390x@0.24.2': + optional: true + + '@esbuild/linux-x64@0.24.2': + optional: true + + '@esbuild/netbsd-arm64@0.24.2': + optional: true + + '@esbuild/netbsd-x64@0.24.2': + optional: true + + '@esbuild/openbsd-arm64@0.24.2': + optional: true + + '@esbuild/openbsd-x64@0.24.2': + optional: true + + '@esbuild/sunos-x64@0.24.2': + optional: true + + '@esbuild/win32-arm64@0.24.2': + optional: true + + '@esbuild/win32-ia32@0.24.2': + optional: true + + '@esbuild/win32-x64@0.24.2': + optional: true + + '@floating-ui/core@1.6.9': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.6.13': + dependencies: + '@floating-ui/core': 1.6.9 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/utils@0.2.9': {} + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@microsoft/api-extractor-model@7.30.3(@types/node@20.17.19)': + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.11.0(@types/node@20.17.19) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.50.0(@types/node@20.17.19)': + dependencies: + '@microsoft/api-extractor-model': 7.30.3(@types/node@20.17.19) + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.11.0(@types/node@20.17.19) + '@rushstack/rig-package': 0.5.3 + '@rushstack/terminal': 0.15.0(@types/node@20.17.19) + '@rushstack/ts-command-line': 4.23.5(@types/node@20.17.19) + lodash: 4.17.21 + minimatch: 3.0.8 + resolve: 1.22.10 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.7.2 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.17.1': + dependencies: + '@microsoft/tsdoc': 0.15.1 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.10 + + '@microsoft/tsdoc@0.15.1': {} + + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + optional: true + + '@rollup/pluginutils@5.1.4(rollup@4.34.8)': + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 4.0.2 + optionalDependencies: + rollup: 4.34.8 + + '@rollup/rollup-android-arm-eabi@4.34.8': + optional: true + + '@rollup/rollup-android-arm64@4.34.8': + optional: true + + '@rollup/rollup-darwin-arm64@4.34.8': + optional: true + + '@rollup/rollup-darwin-x64@4.34.8': + optional: true + + '@rollup/rollup-freebsd-arm64@4.34.8': + optional: true + + '@rollup/rollup-freebsd-x64@4.34.8': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.34.8': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.34.8': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.34.8': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.34.8': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.34.8': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.34.8': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.34.8': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.34.8': + optional: true + + '@rollup/rollup-linux-x64-musl@4.34.8': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.34.8': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.34.8': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.34.8': + optional: true + + '@rushstack/node-core-library@5.11.0(@types/node@20.17.19)': + dependencies: + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 11.3.0 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.10 + semver: 7.5.4 + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/rig-package@0.5.3': + dependencies: + resolve: 1.22.10 + strip-json-comments: 3.1.1 + + '@rushstack/terminal@0.15.0(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': 5.11.0(@types/node@20.17.19) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/ts-command-line@4.23.5(@types/node@20.17.19)': + dependencies: + '@rushstack/terminal': 0.15.0(@types/node@20.17.19) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + + '@sxzz/popperjs-es@2.11.7': {} + + '@types/argparse@1.0.38': {} + + '@types/estree@1.0.6': {} + + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.15 + + '@types/lodash@4.17.15': {} + + '@types/node@20.17.19': + dependencies: + undici-types: 6.19.8 + + '@types/web-bluetooth@0.0.16': {} + + '@vitejs/plugin-vue-jsx@4.1.1(vite@6.1.0(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@babel/core': 7.26.9 + '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.9) + '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.9) + vite: 6.1.0(@types/node@20.17.19)(sass@1.85.0) + vue: 3.5.13(typescript@5.7.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-vue@5.2.1(vite@6.1.0(@types/node@20.17.19)(sass@1.85.0))(vue@3.5.13(typescript@5.7.3))': + dependencies: + vite: 6.1.0(@types/node@20.17.19)(sass@1.85.0) + vue: 3.5.13(typescript@5.7.3) + + '@volar/language-core@2.4.11': + dependencies: + '@volar/source-map': 2.4.11 + + '@volar/source-map@2.4.11': {} + + '@volar/typescript@2.4.11': + dependencies: + '@volar/language-core': 2.4.11 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue/babel-helper-vue-transform-on@1.2.5': {} + + '@vue/babel-plugin-jsx@1.2.5(@babel/core@7.26.9)': + dependencies: + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9) + '@babel/template': 7.26.9 + '@babel/traverse': 7.26.9 + '@babel/types': 7.26.9 + '@vue/babel-helper-vue-transform-on': 1.2.5 + '@vue/babel-plugin-resolve-type': 1.2.5(@babel/core@7.26.9) + html-tags: 3.3.1 + svg-tags: 1.0.0 + optionalDependencies: + '@babel/core': 7.26.9 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-resolve-type@1.2.5(@babel/core@7.26.9)': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/core': 7.26.9 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/parser': 7.26.9 + '@vue/compiler-sfc': 3.5.13 + transitivePeerDependencies: + - supports-color + + '@vue/compiler-core@3.5.13': + dependencies: + '@babel/parser': 7.26.9 + '@vue/shared': 3.5.13 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.13': + dependencies: + '@vue/compiler-core': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/compiler-sfc@3.5.13': + dependencies: + '@babel/parser': 7.26.9 + '@vue/compiler-core': 3.5.13 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.5.2 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.13': + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/compiler-vue2@2.7.16': + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + '@vue/language-core@2.2.0(typescript@5.7.3)': + dependencies: + '@volar/language-core': 2.4.11 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.13 + alien-signals: 0.4.14 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.7.3 + + '@vue/language-core@2.2.2(typescript@5.7.3)': + dependencies: + '@volar/language-core': 2.4.11 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.13 + alien-signals: 1.0.3 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.7.3 + + '@vue/reactivity@3.5.13': + dependencies: + '@vue/shared': 3.5.13 + + '@vue/runtime-core@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/runtime-dom@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/runtime-core': 3.5.13 + '@vue/shared': 3.5.13 + csstype: 3.1.3 + + '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + vue: 3.5.13(typescript@5.7.3) + + '@vue/shared@3.5.13': {} + + '@vueuse/core@9.13.0(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@types/web-bluetooth': 0.0.16 + '@vueuse/metadata': 9.13.0 + '@vueuse/shared': 9.13.0(vue@3.5.13(typescript@5.7.3)) + vue-demi: 0.14.10(vue@3.5.13(typescript@5.7.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/metadata@9.13.0': {} + + '@vueuse/shared@9.13.0(vue@3.5.13(typescript@5.7.3))': + dependencies: + vue-demi: 0.14.10(vue@3.5.13(typescript@5.7.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + acorn@8.14.0: {} + + ajv-draft-04@1.0.0(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv-formats@3.0.1(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv@8.12.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + ajv@8.13.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + alien-signals@0.4.14: {} + + alien-signals@1.0.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + async-validator@4.2.5: {} + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + optional: true + + browserslist@4.24.4: + dependencies: + caniuse-lite: 1.0.30001700 + electron-to-chromium: 1.5.102 + node-releases: 2.0.19 + update-browserslist-db: 1.1.2(browserslist@4.24.4) + + caniuse-lite@1.0.30001700: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + compare-versions@6.1.1: {} + + concat-map@0.0.1: {} + + confbox@0.1.8: {} + + convert-source-map@2.0.0: {} + + csstype@3.1.3: {} + + dayjs@1.11.13: {} + + de-indent@1.0.2: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + detect-libc@1.0.3: + optional: true + + electron-to-chromium@1.5.102: {} + + element-plus@2.9.4(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@ctrl/tinycolor': 3.6.1 + '@element-plus/icons-vue': 2.3.1(vue@3.5.13(typescript@5.7.3)) + '@floating-ui/dom': 1.6.13 + '@popperjs/core': '@sxzz/popperjs-es@2.11.7' + '@types/lodash': 4.17.15 + '@types/lodash-es': 4.17.12 + '@vueuse/core': 9.13.0(vue@3.5.13(typescript@5.7.3)) + async-validator: 4.2.5 + dayjs: 1.11.13 + escape-html: 1.0.3 + lodash: 4.17.21 + lodash-es: 4.17.21 + lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21) + memoize-one: 6.0.0 + normalize-wheel-es: 1.2.0 + vue: 3.5.13(typescript@5.7.3) + transitivePeerDependencies: + - '@vue/composition-api' + + entities@4.5.0: {} + + esbuild@0.24.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.2 + '@esbuild/android-arm': 0.24.2 + '@esbuild/android-arm64': 0.24.2 + '@esbuild/android-x64': 0.24.2 + '@esbuild/darwin-arm64': 0.24.2 + '@esbuild/darwin-x64': 0.24.2 + '@esbuild/freebsd-arm64': 0.24.2 + '@esbuild/freebsd-x64': 0.24.2 + '@esbuild/linux-arm': 0.24.2 + '@esbuild/linux-arm64': 0.24.2 + '@esbuild/linux-ia32': 0.24.2 + '@esbuild/linux-loong64': 0.24.2 + '@esbuild/linux-mips64el': 0.24.2 + '@esbuild/linux-ppc64': 0.24.2 + '@esbuild/linux-riscv64': 0.24.2 + '@esbuild/linux-s390x': 0.24.2 + '@esbuild/linux-x64': 0.24.2 + '@esbuild/netbsd-arm64': 0.24.2 + '@esbuild/netbsd-x64': 0.24.2 + '@esbuild/openbsd-arm64': 0.24.2 + '@esbuild/openbsd-x64': 0.24.2 + '@esbuild/sunos-x64': 0.24.2 + '@esbuild/win32-arm64': 0.24.2 + '@esbuild/win32-ia32': 0.24.2 + '@esbuild/win32-x64': 0.24.2 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + estree-walker@2.0.2: {} + + fast-deep-equal@3.1.3: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + optional: true + + fs-extra@11.3.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + globals@11.12.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + html-tags@3.3.1: {} + + immutable@5.0.3: {} + + import-lazy@4.0.0: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: + optional: true + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + optional: true + + is-number@7.0.0: + optional: true + + jju@1.4.0: {} + + js-tokens@4.0.0: {} + + jsesc@3.1.0: {} + + json-schema-traverse@1.0.0: {} + + json5@2.2.3: {} + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + kolorist@1.8.0: {} + + local-pkg@0.5.1: + dependencies: + mlly: 1.7.4 + pkg-types: 1.3.1 + + lodash-es@4.17.21: {} + + lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21): + dependencies: + '@types/lodash-es': 4.17.12 + lodash: 4.17.21 + lodash-es: 4.17.21 + + lodash@4.17.21: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + memoize-one@6.0.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + optional: true + + minimatch@3.0.8: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + mlly@1.7.4: + dependencies: + acorn: 8.14.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.5.4 + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.8: {} + + neo-async@2.6.2: {} + + node-addon-api@7.1.1: + optional: true + + node-releases@2.0.19: {} + + normalize-wheel-es@1.2.0: {} + + path-browserify@1.0.1: {} + + path-parse@1.0.7: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: + optional: true + + picomatch@4.0.2: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + + postcss@8.5.2: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.5.1: {} + + punycode@2.3.1: {} + + readdirp@4.1.2: {} + + require-from-string@2.0.2: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + rollup@4.34.8: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.34.8 + '@rollup/rollup-android-arm64': 4.34.8 + '@rollup/rollup-darwin-arm64': 4.34.8 + '@rollup/rollup-darwin-x64': 4.34.8 + '@rollup/rollup-freebsd-arm64': 4.34.8 + '@rollup/rollup-freebsd-x64': 4.34.8 + '@rollup/rollup-linux-arm-gnueabihf': 4.34.8 + '@rollup/rollup-linux-arm-musleabihf': 4.34.8 + '@rollup/rollup-linux-arm64-gnu': 4.34.8 + '@rollup/rollup-linux-arm64-musl': 4.34.8 + '@rollup/rollup-linux-loongarch64-gnu': 4.34.8 + '@rollup/rollup-linux-powerpc64le-gnu': 4.34.8 + '@rollup/rollup-linux-riscv64-gnu': 4.34.8 + '@rollup/rollup-linux-s390x-gnu': 4.34.8 + '@rollup/rollup-linux-x64-gnu': 4.34.8 + '@rollup/rollup-linux-x64-musl': 4.34.8 + '@rollup/rollup-win32-arm64-msvc': 4.34.8 + '@rollup/rollup-win32-ia32-msvc': 4.34.8 + '@rollup/rollup-win32-x64-msvc': 4.34.8 + fsevents: 2.3.3 + + sass-loader@16.0.5(sass@1.85.0): + dependencies: + neo-async: 2.6.2 + optionalDependencies: + sass: 1.85.0 + + sass@1.85.0: + dependencies: + chokidar: 4.0.3 + immutable: 5.0.3 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 + + semver@6.3.1: {} + + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + + source-map-js@1.2.1: {} + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + string-argv@0.3.2: {} + + strip-json-comments@3.1.1: {} + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + svg-tags@1.0.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + optional: true + + typescript@5.7.2: {} + + typescript@5.7.3: {} + + ufo@1.5.4: {} + + undici-types@6.19.8: {} + + universalify@2.0.1: {} + + update-browserslist-db@1.1.2(browserslist@4.24.4): + dependencies: + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + vite-plugin-dts@4.5.0(@types/node@20.17.19)(rollup@4.34.8)(typescript@5.7.3)(vite@6.1.0(@types/node@20.17.19)(sass@1.85.0)): + dependencies: + '@microsoft/api-extractor': 7.50.0(@types/node@20.17.19) + '@rollup/pluginutils': 5.1.4(rollup@4.34.8) + '@volar/typescript': 2.4.11 + '@vue/language-core': 2.2.0(typescript@5.7.3) + compare-versions: 6.1.1 + debug: 4.4.0 + kolorist: 1.8.0 + local-pkg: 0.5.1 + magic-string: 0.30.17 + typescript: 5.7.3 + optionalDependencies: + vite: 6.1.0(@types/node@20.17.19)(sass@1.85.0) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + + vite@6.1.0(@types/node@20.17.19)(sass@1.85.0): + dependencies: + esbuild: 0.24.2 + postcss: 8.5.2 + rollup: 4.34.8 + optionalDependencies: + '@types/node': 20.17.19 + fsevents: 2.3.3 + sass: 1.85.0 + + vscode-uri@3.1.0: {} + + vue-demi@0.14.10(vue@3.5.13(typescript@5.7.3)): + dependencies: + vue: 3.5.13(typescript@5.7.3) + + vue-tsc@2.2.2(typescript@5.7.3): + dependencies: + '@volar/typescript': 2.4.11 + '@vue/language-core': 2.2.2(typescript@5.7.3) + typescript: 5.7.3 + + vue@3.5.13(typescript@5.7.3): + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-sfc': 3.5.13 + '@vue/runtime-dom': 3.5.13 + '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.3)) + '@vue/shared': 3.5.13 + optionalDependencies: + typescript: 5.7.3 + + yallist@3.1.1: {} + + yallist@4.0.0: {} diff --git a/packages/crud/src/App.vue b/packages/crud/src/App.vue new file mode 100644 index 0000000..32f62ac --- /dev/null +++ b/packages/crud/src/App.vue @@ -0,0 +1,208 @@ + + + + + diff --git a/packages/crud/src/components/add-btn/index.tsx b/packages/crud/src/components/add-btn/index.tsx new file mode 100644 index 0000000..1f42fac --- /dev/null +++ b/packages/crud/src/components/add-btn/index.tsx @@ -0,0 +1,21 @@ +import { defineComponent } from "vue"; +import { useConfig, useCore } from "../../hooks"; + +export default defineComponent({ + name: "cl-add-btn", + + setup(_, { slots }) { + const { crud } = useCore(); + const { style } = useConfig(); + + return () => { + return ( + crud.getPermission("add") && ( + + {slots.default?.() || crud.dict.label.add} + + ) + ); + }; + } +}); diff --git a/packages/crud/src/components/adv/btn.tsx b/packages/crud/src/components/adv/btn.tsx new file mode 100644 index 0000000..34b4da5 --- /dev/null +++ b/packages/crud/src/components/adv/btn.tsx @@ -0,0 +1,31 @@ +import { useConfig, useCore } from "../../hooks"; +import { defineComponent } from "vue"; +import { Search } from "@element-plus/icons-vue"; + +export default defineComponent({ + name: "cl-adv-btn", + + components: { + Search + }, + + setup(_, { slots }) { + const { crud, mitt } = useCore(); + const { style } = useConfig(); + + function open() { + mitt.emit("crud.openAdvSearch"); + } + + return () => { + return ( + + + + + {slots.default?.() || crud.dict.label.advSearch} + + ); + }; + } +}); diff --git a/packages/crud/src/components/adv/search.tsx b/packages/crud/src/components/adv/search.tsx new file mode 100644 index 0000000..b94300c --- /dev/null +++ b/packages/crud/src/components/adv/search.tsx @@ -0,0 +1,203 @@ +import { defineComponent, h, inject, mergeProps, nextTick, type PropType, reactive, ref } from "vue"; +import { Close } from "@element-plus/icons-vue"; +import { useBrowser, useConfig, useCore } from "../../hooks"; +import { renderNode } from "../../utils/vnode"; +import { useApi } from "../form/helper"; +import { isArray } from "lodash-es"; + +export default defineComponent({ + name: "cl-adv-search", + + components: { + Close + }, + + props: { + // 表单项 + items: { + type: Array as PropType, + default: () => [] + }, + // 标题 + title: String, + // 窗体大小 + size: { + type: [Number, String], + default: "30%" + }, + // 操作按钮 + op: { + type: Array, + default: () => ["clear", "reset", "close", "search"] + }, + // 搜索钩子 + onSearch: Function + }, + + emits: ["reset", "clear"], + + setup(props, { emit, slots, expose }) { + const { crud, mitt } = useCore(); + const { style } = useConfig(); + const browser = useBrowser(); + + // 配置 + const config = reactive( + mergeProps(props, inject("useAdvSearch__options") || {}) + ); + + // cl-form + const Form = ref(); + + // el-drawer + const Drawer = ref(); + + // 是否可见 + const visible = ref(false); + + // 打开 + function open() { + visible.value = true; + + nextTick(() => { + Form.value?.open({ + items: config.items || [], + op: { + hidden: true + }, + isReset: false + }); + }); + } + + // 关闭 + function close() { + Drawer.value.handleClose(); + } + + // 重置数据 + function reset() { + const d: any = {}; + + config.items?.map((e) => { + if (typeof e.hook != 'string' && e.hook?.reset) { + const props = e.hook.reset(e.prop!) + + if (isArray(props)) { + props.forEach((prop) => { + d[prop] = undefined; + }) + } + } + + d[e.prop!] = undefined; + }); + + // 重置表单 + Form.value?.reset(); + + // 列表刷新 + search(); + + // 重置事件 + emit("reset", d); + } + + // 清空数据 + function clear() { + Form.value?.clear(); + emit("clear"); + } + + // 搜素请求 + function search(params?: any) { + const form = Form.value?.getForm(); + + function next(data: any) { + Form.value?.done(); + close(); + + return crud.refresh({ + ...data, + ...params, + page: 1 + }); + } + + if (config.onSearch) { + config.onSearch(form, { next, close }); + } else { + next(form); + } + } + + // 消息事件 + mitt.on("crud.openAdvSearch", open); + + // 渲染表单 + function renderForm() { + return h(, {}, slots); + } + + // 渲染底部 + function renderFooter() { + const fns = { search, reset, clear, close }; + + return config.op?.map((e: string) => { + switch (e) { + case "search": + case "reset": + case "clear": + case "close": + return h( + , + { + type: e == "search" ? "primary" : null, + size: style.size, + onClick: () => { + fns[e]() + } + }, + { default: () => crud.dict.label[e] } + ); + + default: + return renderNode(e, { + scope: Form.value?.getForm(), + slots + }); + } + }); + } + + expose({ + open, + close, + clear, + ...useApi({ Form }), + reset, + Form + }); + + return () => { + return ( + +
+ {config.title || crud.dict.label.advSearch} + + + +
+
{renderForm()}
+ +
+ ); + }; + } +}); diff --git a/packages/crud/src/components/context-menu/index.tsx b/packages/crud/src/components/context-menu/index.tsx new file mode 100644 index 0000000..a9fc39c --- /dev/null +++ b/packages/crud/src/components/context-menu/index.tsx @@ -0,0 +1,282 @@ +import { + defineComponent, + nextTick, + onMounted, + reactive, + ref, + h, + render, + toRaw, + type PropType +} from "vue"; +import { isString } from "lodash-es"; +import { addClass, contains, removeClass } from "../../utils"; +import { useRefs } from "../../hooks"; +import { ElIcon } from "element-plus"; +import { ArrowRight } from "@element-plus/icons-vue"; + +const ClContextMenu = defineComponent({ + name: "cl-context-menu", + + props: { + show: Boolean, + options: { + type: Object as PropType, + default: () => ({}) + }, + event: { + type: Object, + default: () => ({}) + } + }, + + setup(props, { expose, slots }) { + const { refs, setRefs } = useRefs(); + + // 是否可见 + const visible = ref(props.show || false); + + // 按钮列表 + const list = ref([]); + + // 样式 + const style = reactive({ + left: "0px", + top: "0px" + }); + + // 选中值 + const ids = ref(""); + + // 阻止默认事件 + function stopDefault(e: any) { + if (e.preventDefault) { + e.preventDefault(); + } + + if (e.stopPropagation) { + e.stopPropagation(); + } + } + + // 解析列表 + function parseList(list: ClContextMenu.Item[]) { + function deep(list: ClContextMenu.Item[]) { + list.forEach((e) => { + e.showChildren = false; + + if (e.children) { + deep(e.children); + } + }); + } + + deep(list); + + return list; + } + + // 目标元素 + let targetEl: any; + + // 关闭 + function close() { + visible.value = false; + ids.value = ""; + + if (targetEl) { + removeClass(targetEl, "cl-context-menu__target"); + } + } + + // 打开 + function open(event: any, options: ClContextMenu.Options = {}) { + // 阻止默认事件 + stopDefault(event); + + // 显示 + visible.value = true; + + // 元素 + const el = refs["context-menu"].querySelector(".cl-context-menu__box") as HTMLElement; + + // 点击样式 + if (options?.hover) { + const d = options.hover === true ? {} : options.hover; + targetEl = event.target; + + if (targetEl && isString(targetEl.className)) { + if (d.target) { + while (!targetEl.className.includes(d.target)) { + targetEl = targetEl.parentNode; + } + } + + addClass(targetEl, d.className || "cl-context-menu__target"); + } + } + + // 自定义样式 + if (options?.class) { + addClass(el, options.class); + } + + // 菜单列表 + if (options?.list) { + list.value = parseList(options.list); + } + + nextTick(() => { + // 计算位置 + let left = event.pageX; + let top = event.pageY; + + // 组件方式用 offset 计算 + if (!props.show) { + left = event.offsetX; + top = event.offsetY; + } + + const { clientHeight: h1, clientWidth: w1 } = event.target?.ownerDocument.body; + const { clientHeight: h2, clientWidth: w2 } = el; + + if (top + h2 > h1) { + top = h1 - h2 - 5; + } + + if (left + w2 > w1) { + left = w1 - w2 - 5; + } + + style.left = left + "px"; + style.top = top + "px"; + }) + + return { + close + }; + } + + // 行点击 + function rowClick(item: ClContextMenu.Item, id: string) { + ids.value = id; + + if (item.disabled) { + return false; + } + + if (item.callback) { + return item.callback(close); + } + + if (item.children) { + item.showChildren = !item.showChildren; + } else { + close(); + } + } + + expose({ + open, + close + }); + + onMounted(function () { + if (visible.value) { + const { body, documentElement } = props.event.target.ownerDocument; + + // 添加到 body 下 + body.appendChild(refs["context-menu"]); + // 关闭事件 + (documentElement || body).addEventListener("mousedown", (e: any) => { + const el = refs["context-menu"]; + if (!contains(el, e.target) && el != e.target) { + close(); + } + }); + + // 默认打开 + open(props.event, props?.options); + } + }); + + return () => { + function deep(list: ClContextMenu.Item[], pId: string, level: number) { + return ( +
1 && "is-append"]}> + {list + .filter((e) => !e.hidden) + .map((e, i) => { + const id = `${pId}-${i}`; + + if (!e.suffixIcon) { + // 默认图标 + if (e.children) { + e.suffixIcon = ArrowRight; + } + } + + return ( +
{ + rowClick(e, id); + ev.stopPropagation(); + }} + > + {/* 前缀图标 */} + {e.prefixIcon && {h(toRaw(e.prefixIcon))}} + + {/* 标题 */} + + {e.label} + + + {/* 后缀图标 */} + {e.suffixIcon && {h(toRaw(e.suffixIcon))}} + + {/* 子集 */} + {e.children && + e.showChildren && + deep(e.children, id, level + 1)} +
+ ); + })} +
+ ); + } + + return ( + visible.value && ( +
+ {slots.default ? slots.default() : deep(list.value, "0", 1)} +
+ ) + ); + }; + } +}); + +export const ContextMenu = { + open(event: any, options: ClContextMenu.Options) { + const vm = h(ClContextMenu, { + show: true, + event, + options + }); + + render(vm, event.target.ownerDocument.createElement("div")); + + return vm.component?.exposed as ClContextMenu.Exposed; + } +}; + +export default ClContextMenu; diff --git a/packages/crud/src/components/crud/helper.ts b/packages/crud/src/components/crud/helper.ts new file mode 100644 index 0000000..ea25316 --- /dev/null +++ b/packages/crud/src/components/crud/helper.ts @@ -0,0 +1,287 @@ +import { ElMessageBox, ElMessage } from "element-plus"; +import { Mitt } from "../../utils/mitt"; +import { ref } from "vue"; +import { assign, isArray, isFunction } from "lodash-es"; +import { merge } from "../../utils"; + +interface Options { + mitt: Mitt; + config: ClCrud.Config; + crud: ClCrud.Ref; +} + +export function useHelper({ config, crud, mitt }: Options) { + // 刷新随机值,避免脏数据 + const refreshRd = ref(0); + + // 获取权限 + function getPermission(key: "page" | "list" | "info" | "update" | "add" | "delete"): boolean { + return Boolean(crud.permission[key]); + } + + // 根据字典替换请求参数 + function paramsReplace(params: obj) { + const { pagination, search, sort } = crud.dict; + + // 请求参数 + const a: any = { ...params }; + + // 字典 + const b: any = { ...pagination, ...search, ...sort }; + + for (const i in b) { + if (a[i]) { + if (i != b[i]) { + a[`_${b[i]}`] = a[i]; + + delete a[i]; + } + } + } + + for (const i in a) { + if (i[0] === "_") { + a[i.substr(1)] = a[i]; + + delete a[i]; + } + } + + return a; + } + + // 刷新请求 + function refresh(params?: obj) { + const { service, dict } = crud; + + return new Promise((success, error) => { + // 合并请求参数 + const reqParams = paramsReplace(assign(crud.params, params)); + + // Loading + crud.loading = true; + + // 预防脏数据 + const rd = (refreshRd.value = Math.random()); + + // 完成事件 + function done() { + crud.loading = false; + } + + // 渲染 + function render(data: any | any[], pagination?: any) { + const res = isArray(data) ? { list: data, pagination } : data; + done(); + success(res); + mitt.emit("crud.refresh", res); + } + + // 下一步 + function next(params: obj): Promise { + return new Promise(async (resolve, reject) => { + await service[dict.api.page](params) + .then((res) => { + if (rd != refreshRd.value) { + return false; + } + + if (isArray(res)) { + res = { + list: res, + pagination: { + total: res.length + } + }; + } + + render(res); + resolve(res); + }) + .catch((err) => { + ElMessage.error(err.message); + error(err); + reject(err); + }); + + done(); + }); + } + + // 刷新钩子 + if (config.onRefresh) { + config.onRefresh(reqParams, { next, done, render }); + } else { + next(reqParams); + } + }); + } + + // 打开详情 + function rowInfo(data: any) { + mitt.emit("crud.proxy", { + name: "info", + data: [data] + }); + } + + // 打开新增 + function rowAdd() { + mitt.emit("crud.proxy", { + name: "add" + }); + } + + // 打开编辑 + function rowEdit(data: any) { + mitt.emit("crud.proxy", { + name: "edit", + data: [data] + }); + } + + // 打开追加 + function rowAppend(data: any) { + mitt.emit("crud.proxy", { + name: "append", + data: [data] + }); + } + + // 关闭新增、编辑弹窗 + function rowClose() { + mitt.emit("crud.proxy", { + name: "close" + }); + } + + // 删除请求 + function rowDelete(...selection: any[]) { + const { service, dict } = crud; + + // 参数 + const params = { + ids: selection.map((e) => e[dict.primaryId]) + }; + + // 下一步 + async function next(data: obj) { + return new Promise((resolve, reject) => { + ElMessageBox({ + type: "warning", + title: dict.label.tips, + message: dict.label.deleteConfirm, + confirmButtonText: dict.label.confirm, + cancelButtonText: dict.label.close, + showCancelButton: true, + async beforeClose(action, instance, done) { + if (action === "confirm") { + instance.confirmButtonLoading = true; + + await service[dict.api.delete]({ ...params, ...data }) + .then((res) => { + ElMessage.success(dict.label.deleteSuccess); + + refresh(); + resolve(res); + }) + .catch((err) => { + ElMessage.error(err.message); + reject(err); + }); + + instance.confirmButtonLoading = false; + } + + done(); + } + }).catch(() => null); + }); + } + + // 删除钩子 + if (config.onDelete) { + config.onDelete(selection, { next }); + } else { + next(params); + } + } + + // 代理 + function proxy(name: string, data?: any[]) { + mitt.emit("crud.proxy", { + name, + data + }); + } + + // 获取请求参数 + function getParams() { + return crud.params; + } + + // 替换请求参数 + function setParams(data: obj) { + merge(crud.params, data); + } + + // 设置 + function set(key: string, value: any) { + if (!value) { + return false; + } + + switch (key) { + // 服务 + case "service": + Object.assign(crud.service, value); + crud.service.__proto__ = value.__proto__; + if (value._permission) { + for (const i in value._permission) { + crud.permission[i] = value._permission[i]; + } + } + break; + + // 权限 + case "permission": + if (isFunction(value)) { + merge(crud.permission, value(crud)); + } else { + merge(crud.permission, value); + } + break; + + default: + merge(crud[key], value); + break; + } + } + + // 监听事件 + function on(name: string, callback: fn) { + mitt.on(`${name}-${crud.id}`, callback); + } + + // 默认值 + set("dict", config.dict); + set("service", config.service); + set("permission", config.permission); + + return { + proxy, + set, + on, + rowInfo, + rowAdd, + rowEdit, + rowAppend, + rowDelete, + rowClose, + refresh, + getPermission, + paramsReplace, + getParams, + setParams + }; +} diff --git a/packages/crud/src/components/crud/index.tsx b/packages/crud/src/components/crud/index.tsx new file mode 100644 index 0000000..a87a7b4 --- /dev/null +++ b/packages/crud/src/components/crud/index.tsx @@ -0,0 +1,91 @@ +import { defineComponent, getCurrentInstance, inject, provide, reactive } from "vue"; +import { cloneDeep } from "lodash-es"; +import { useHelper } from "./helper"; +import { Mitt } from "../../utils/mitt"; +import { mergeConfig, merge } from "../../utils"; +import { crudList } from "../../emitter"; +import { useConfig } from "../../hooks"; + +export default defineComponent({ + name: "cl-crud", + + props: { + // 组件名 + name: String, + // 是否有边框 + border: Boolean, + // 内间距 + padding: { + type: String, + default: "10px" + } + }, + + setup(props, { slots, expose }) { + // 当前实例 + const inst = getCurrentInstance(); + + // 配置 + const config = reactive(mergeConfig(inject("useCrud__options") || {})); + + // 事件 + const mitt = new Mitt(inst?.uid); + + // 全局配置 + const { dict, permission } = useConfig(); + + // 参数 + const crud = reactive( + merge( + { + id: props.name || inst?.uid, + // 绑定的路由地址 + routePath: location.pathname || "/", + // 表格加载状态 + loading: false, + // 表格已选列 + selection: [], + // 请求参数 + params: { + page: 1, + size: 20 + }, + // 请求服务 + service: {}, + // 字典 + dict: {}, + // 权限 + permission: {}, + // 事件 + mitt, + // 配置 + config + }, + cloneDeep({ dict, permission }) + ) + ); + + // 追加参数 + merge(crud, useHelper({ config, crud, mitt })); + + // 集合 + crudList.push(crud); + + // 值穿透 + provide("crud", crud); + provide("mitt", mitt); + + // 导出 + expose(crud); + + return () => { + return ( +
+ {slots.default?.()} +
+ ); + }; + } +}); diff --git a/packages/crud/src/components/dialog/index.tsx b/packages/crud/src/components/dialog/index.tsx new file mode 100644 index 0000000..8aa9544 --- /dev/null +++ b/packages/crud/src/components/dialog/index.tsx @@ -0,0 +1,288 @@ +import { defineComponent, h, ref, watch, computed, provide } from "vue"; +import { Close, FullScreen, Minus } from "@element-plus/icons-vue"; +import { renderNode } from "../../utils/vnode"; +import { isArray, isBoolean } from "lodash-es"; +import { useBrowser } from "../../hooks"; + +export default defineComponent({ + name: "cl-dialog", + + components: { + Close, + FullScreen, + Minus + }, + + props: { + // 是否可见 + modelValue: { + type: Boolean, + default: false + }, + // Extraneous non-props attributes + props: Object, + // 标题 + title: { + type: String, + default: "-" + }, + // 高度 + height: String, + // 宽度 + width: { + type: String, + default: "50%" + }, + // 內间距 + padding: { + type: String, + default: "20px" + }, + // 是否缓存 + keepAlive: Boolean, + // 是否全屏 + fullscreen: Boolean, + // 控制按钮 + controls: { + type: Array, + default: () => ["fullscreen", "close"] + }, + // 隐藏头部元素 + hideHeader: Boolean, + // 关闭前 + beforeClose: Function, + // 是否需要滚动条 + scrollbar: { + type: Boolean, + default: true + }, + // 背景透明 + transparent: Boolean + }, + + emits: ["update:modelValue", "fullscreen-change"], + + setup(props, { emit, expose, slots }) { + const browser = useBrowser(); + + // el-dialog + const Dialog = ref(); + + // 是否全屏 + const fullscreen = ref(false); + + // 是否可见 + const visible = ref(false); + + // 缓存数 + const cacheKey = ref(0); + + // 是否全屏 + const isFullscreen = computed(() => { + return browser && browser.isMini ? true : fullscreen.value; + }); + + // 监听绑定值 + watch( + () => props.modelValue, + (val) => { + visible.value = val; + if (val && !props.keepAlive) { + cacheKey.value += 1; + } + }, + { + immediate: true + } + ); + + // 监听 fullscreen 变化 + watch( + () => props.fullscreen, + (val) => { + fullscreen.value = val; + }, + { + immediate: true + } + ); + + // fullscreen-change 回调 + watch(fullscreen, (val: boolean) => { + emit("fullscreen-change", val); + }); + + // 提供 + provide("dialog", { + visible, + fullscreen: isFullscreen + }); + + // 打开 + function open() { + fullscreen.value = true; + } + + // 关闭 + function close() { + function done() { + onClose(); + } + + if (props.beforeClose) { + props.beforeClose(done); + } else { + done(); + } + } + + // 关闭后 + function onClose() { + emit("update:modelValue", false); + } + + // 切换全屏 + function changeFullscreen(val?: boolean) { + fullscreen.value = isBoolean(val) ? Boolean(val) : !fullscreen.value; + } + + // 双击全屏 + function dblClickFullscreen() { + if (isArray(props.controls) && props.controls.includes("fullscreen")) { + changeFullscreen(); + } + } + + // 渲染头部 + function renderHeader() { + return ( + props.hideHeader || ( +
+ {props.title} + +
+ {props.controls.map((e: any) => { + switch (e) { + //全屏按钮 + case "fullscreen": + if (browser.screen === "xs") { + return null; + } + + // 是否显示全屏按钮 + if (isFullscreen.value) { + return ( + + ); + } else { + return ( + + ); + } + + // 关闭按钮 + case "close": + return ( + + ); + + // 自定义按钮 + default: + return renderNode(e, { + slots + }); + } + })} +
+
+ ) + ); + } + + expose({ + Dialog, + visible, + isFullscreen, + open, + close, + changeFullscreen + }); + + return () => { + return h( + , + {}, + { + header() { + return renderHeader(); + }, + default() { + const height = isFullscreen.value ? "100%" : props.height; + + const style = { + padding: props.padding, + height + }; + + function content() { + return ( +
+ {slots.default?.()} +
+ ); + } + + if (props.scrollbar) { + style.height = "auto"; + + return {content()}; + } else { + return content(); + } + }, + footer() { + const d = slots.footer?.(); + + if (d && d[0]?.shapeFlag) { + return ; + } + + return null; + } + } + ); + }; + } +}); diff --git a/packages/crud/src/components/error-message/index.tsx b/packages/crud/src/components/error-message/index.tsx new file mode 100644 index 0000000..1f17a72 --- /dev/null +++ b/packages/crud/src/components/error-message/index.tsx @@ -0,0 +1,17 @@ +import { defineComponent } from "vue"; + +export default defineComponent({ + name: "cl-error-message", + + props: { + title: String + }, + + setup(props) { + return () => { + return
+ {props.title} +
; + }; + } +}); diff --git a/packages/crud/src/components/filter/index.tsx b/packages/crud/src/components/filter/index.tsx new file mode 100644 index 0000000..851c270 --- /dev/null +++ b/packages/crud/src/components/filter/index.tsx @@ -0,0 +1,23 @@ +import { defineComponent } from "vue"; + +export default defineComponent({ + name: "cl-filter", + + props: { + label: String + }, + + setup(props, { slots }) { + return () => { + return ( +
+ + {props.label} + + + {slots.default?.()} +
+ ); + }; + } +}); diff --git a/packages/crud/src/components/flex1/index.tsx b/packages/crud/src/components/flex1/index.tsx new file mode 100644 index 0000000..b22955f --- /dev/null +++ b/packages/crud/src/components/flex1/index.tsx @@ -0,0 +1,11 @@ +import { defineComponent } from "vue"; + +export default defineComponent({ + name: "cl-flex1", + + setup() { + return () => { + return
; + }; + } +}); diff --git a/packages/crud/src/components/form-card/index.tsx b/packages/crud/src/components/form-card/index.tsx new file mode 100644 index 0000000..b3fdde4 --- /dev/null +++ b/packages/crud/src/components/form-card/index.tsx @@ -0,0 +1,51 @@ +import { defineComponent, ref } from "vue"; +import { ArrowDown, ArrowUp } from "@element-plus/icons-vue"; + +export default defineComponent({ + name: "cl-form-card", + + components: { + ArrowDown, + ArrowUp + }, + + props: { + label: String, + // 展开状态 + expand: { + type: Boolean, + default: true + }, + // 是否能展开、收起 + isExpand: { + type: Boolean, + default: true + } + }, + + setup(props, { slots }) { + const visible = ref(props.expand); + + function toExpand() { + if (props.isExpand) { + visible.value = !visible.value; + } + } + + return () => { + return ( +
+
+ {props.label} + + + + + +
+
{slots.default?.()}
+
+ ); + }; + } +}); diff --git a/packages/crud/src/components/form-tabs/index.tsx b/packages/crud/src/components/form-tabs/index.tsx new file mode 100644 index 0000000..038b19a --- /dev/null +++ b/packages/crud/src/components/form-tabs/index.tsx @@ -0,0 +1,145 @@ +import { + defineComponent, + h, + nextTick, + onMounted, + PropType, + reactive, + ref, + toRaw, + watch +} from "vue"; +import { isEmpty } from "lodash-es"; +import { useRefs, useDialog } from "../../hooks"; + +export default defineComponent({ + name: "cl-form-tabs", + + props: { + modelValue: [String, Number], + labels: { + type: Array, + default: () => [] + }, + justify: { + type: String as PropType< + "start" | "end" | "left" | "right" | "center" | "justify" | "match-parent" + >, + default: "center" + }, + type: { + type: String as PropType<"card" | "default">, + default: "default" + } + }, + + emits: ["update:modelValue", "change"], + + setup(props, { emit, expose }) { + const { refs, setRefs } = useRefs(); + + // 标识 + const active = ref(""); + + // 切换列表 + const list = ref([]); + + // 下划线 + const line = reactive({ + width: "", + offsetLeft: "", + transform: "", + backgroundColor: "" + }); + + function update(val: any) { + if (!val) { + return false; + } + + nextTick(() => { + const index = list.value.findIndex((e) => e.value === val); + const item = refs[`tab-${index}`]; + + if (item) { + // 下划线位置 + line.width = item.offsetWidth + "px"; + line.transform = `translateX(${item.offsetLeft}px)`; + + // 靠左位置 + let left = item.offsetLeft + item.clientWidth / 2 - 414 / 2 + 15; + + if (left < 0) { + left = 0; + } + + // 设置滚动距离 + refs.tabs.scrollLeft = left; + } + }); + + active.value = val; + emit("update:modelValue", val); + } + + // 监听绑定值变化 + watch(() => props.modelValue, update); + + // 监听值修改 + watch( + () => active.value, + (val) => { + emit("change", val); + } + ); + + useDialog({ + onFullscreen() { + update(active.value); + } + }); + + onMounted(function () { + if (!isEmpty(props.labels)) { + list.value = props.labels; + update(isEmpty(props.modelValue) ? list.value[0].value : props.modelValue); + } + }); + + expose({ + active, + list, + line, + update + }); + + return () => { + return ( +
+
+
    + {list.value.map((e, i) => { + return ( +
  • { + update(e.value); + }}> + {e.icon && {h(toRaw(e.icon))}} + {e.label} +
  • + ); + })} + + {line.width &&
    } +
+
+
+ ); + }; + } +}); diff --git a/packages/crud/src/components/form/helper/action.ts b/packages/crud/src/components/form/helper/action.ts new file mode 100644 index 0000000..eaf9674 --- /dev/null +++ b/packages/crud/src/components/form/helper/action.ts @@ -0,0 +1,146 @@ +import { assign } from "lodash-es"; +import { dataset } from "../../../utils"; + +export function useAction({ + config, + form, + Form +}: { + config: ClForm.Config; + form: obj; + Form: Vue.Ref; +}) { + // 设置数据 + function set( + { + prop, + key, + path + }: { prop?: string; key?: "options" | "props" | "hidden" | "hidden-toggle"; path?: string }, + data?: any + ) { + const p: string = path || ""; + + if (path) { + dataset(config, p, data); + } else { + let d: any; + + if (prop) { + function deep(arr: ClForm.Item[]) { + arr.forEach((e) => { + if (e.prop == prop) { + d = e; + } else { + if (e.children) { + deep(e.children); + } + } + }); + } + + deep(config.items); + } + + if (d) { + switch (key) { + case "options": + d.component.options = data; + break; + + case "props": + assign(d.component.props, data); + break; + + case "hidden": + d.hidden = data; + break; + + case "hidden-toggle": + d.hidden = data === undefined ? !d.hidden : !data; + break; + + default: + assign(d, data); + break; + } + } else { + console.error(`[set] ${prop} is not found`); + } + } + } + + // 获取表单值 + function getForm(prop: string) { + return prop ? form[prop] : form; + } + + // 设置表单值 + function setForm(prop: string, value: any) { + form[prop] = value; + } + + // 设置配置 + function setConfig(path: string, value: any) { + set({ path }, value); + } + + // 设置数据 + function setData(prop: string, value: any) { + set({ prop }, value); + } + + // 设置表单项的下拉数据列表 + function setOptions(prop: string, value: any[]) { + set({ prop, key: "options" }, value); + } + + // 设置表单项的组件参数 + function setProps(prop: string, value: any) { + set({ prop, key: "props" }, value); + } + + // 切换表单项的显示、隐藏 + function toggleItem(prop: string, value?: boolean) { + set({ prop, key: "hidden-toggle" }, value); + } + + // 对部分表单项隐藏 + function hideItem(...props: string[]) { + props.forEach((prop) => { + set({ prop, key: "hidden" }, true); + }); + } + + // 对部分表单项显示 + function showItem(...props: string[]) { + props.forEach((prop) => { + set({ prop, key: "hidden" }, false); + }); + } + + // 设置标题 + function setTitle(value: string) { + config.title = value; + } + + // 是否展开表单项 + function collapseItem(e: any) { + Form.value?.clearValidate(e.prop); + e.collapse = !e.collapse; + } + + return { + getForm, + setForm, + setData, + setConfig, + setOptions, + setProps, + toggleItem, + hideItem, + showItem, + setTitle, + collapseItem + }; +} diff --git a/packages/crud/src/components/form/helper/api.ts b/packages/crud/src/components/form/helper/api.ts new file mode 100644 index 0000000..a37190c --- /dev/null +++ b/packages/crud/src/components/form/helper/api.ts @@ -0,0 +1,36 @@ +import { useElApi } from "../../../hooks"; + +export function useApi({ Form }: { Form: Vue.Ref }) { + return useElApi( + [ + "open", + "close", + "clear", + "reset", + "submit", + "bindForm", + "changeTab", + "setTitle", + "showLoading", + "hideLoading", + "collapseItem", + "getForm", + "setForm", + "invokeData", + "setData", + "setConfig", + "setOptions", + "setProps", + "toggleItem", + "hideItem", + "showItem", + "validate", + "validateField", + "resetFields", + "scrollToField", + "clearValidate", + "fields" + ], + Form + ); +} diff --git a/packages/crud/src/components/form/helper/index.ts b/packages/crud/src/components/form/helper/index.ts new file mode 100644 index 0000000..f89d7ad --- /dev/null +++ b/packages/crud/src/components/form/helper/index.ts @@ -0,0 +1,85 @@ +import { reactive, ref, watch } from "vue"; +import { useConfig } from "../../../hooks"; +import { cloneDeep } from "lodash-es"; + +export function useForm() { + const { dict } = useConfig(); + + // 表单配置 + const config = reactive({ + title: "-", + height: undefined, + width: "50%", + props: { + labelWidth: 100 + }, + on: {}, + op: { + hidden: false, + saveButtonText: dict.label.save, + closeButtonText: dict.label.close, + buttons: ["close", "save"] + }, + dialog: { + closeOnClickModal: false, + appendToBody: true + }, + items: [], + form: {}, + _data: {} + }); + + const Form = ref(); + + // 表单数据 + const form = reactive({}); + + // 表单数据备份 + const oldForm = ref({}); + + // 表单是否可见 + const visible = ref(false); + + // 表单提交保存状态 + const saving = ref(false); + + // 表单加载状态 + const loading = ref(false); + + // 表单禁用状态 + const disabled = ref(false); + + // 监听表单变化 + watch( + () => form, + (val) => { + if (config.on?.change) { + for (const i in val) { + if (form[i] !== oldForm.value[i]) { + config.on?.change(val, i); + } + } + } + + oldForm.value = cloneDeep(val); + }, + { + deep: true + } + ); + + return { + Form, + config, + form, + visible, + saving, + loading, + disabled + }; +} + +export * from "./action"; +export * from "./api"; +export * from "./plugins"; +export * from "./tabs"; diff --git a/packages/crud/src/components/form/helper/plugins.ts b/packages/crud/src/components/form/helper/plugins.ts new file mode 100644 index 0000000..f0a37e6 --- /dev/null +++ b/packages/crud/src/components/form/helper/plugins.ts @@ -0,0 +1,92 @@ +import { type Ref, type WatchStopHandle, getCurrentInstance, watch } from "vue"; +import { useConfig } from "../../../hooks"; +import { uniqueFns } from "../../../utils"; + +export function usePlugins(enable: boolean, { visible }: { visible: Ref }) { + const that: any = getCurrentInstance(); + const { style } = useConfig(); + + interface Event { + onOpen: (() => void)[]; + onClose: (() => void)[]; + onSubmit: ((data: obj) => Promise | obj)[]; + [key: string]: any; + } + + // 事件 + const ev: Event = { + onOpen: [], + onClose: [], + onSubmit: [] + }; + + // 监听器 + let timer: WatchStopHandle | null = null; + + // 插件创建 + function create(plugins: ClForm.Plugin[] = []) { + if (!enable) { + return false; + } + + for (const i in ev) { + ev[i] = []; + } + + // 停止监听 + if (timer) { + timer(); + } + + // 执行 + uniqueFns([...(style.form.plugins || []), ...plugins]).forEach((p) => { + const d: any = { + exposed: that.exposed + }; + + for (const i in ev) { + d[i] = (cb: any) => { + ev[i].push(cb); + }; + } + + p(d); + }); + + timer = watch( + visible, + (val) => { + if (val) { + setTimeout(() => { + ev.onOpen.forEach((e) => e()); + }, 10); + } else { + ev.onClose.forEach((e) => e()); + } + }, + { + immediate: true + } + ); + } + + // 表单提交 + async function submit(data: any) { + let d = data; + + for (let i = 0; i < ev.onSubmit.length; i++) { + const d2 = await ev.onSubmit[i](d); + + if (d2) { + d = d2; + } + } + + return d; + } + + return { + create, + submit + }; +} diff --git a/packages/crud/src/components/form/helper/tabs.ts b/packages/crud/src/components/form/helper/tabs.ts new file mode 100644 index 0000000..e067616 --- /dev/null +++ b/packages/crud/src/components/form/helper/tabs.ts @@ -0,0 +1,151 @@ +import { computed, ref } from "vue"; + +export function useTabs({ config, Form }: { config: ClForm.Config; Form: Vue.Ref }) { + // 选中 + const active = ref(); + + // 列表 + const list = computed(() => { + return get()?.props?.labels || []; + }); + + // 获取选项 + function getItem(value: any) { + return list.value.find((e) => e.value == value); + } + + // 是否已加载 + function isLoaded(value: any) { + const d = getItem(value); + return d?.lazy ? d.loaded : true; + } + + // 加载后 + function onLoad(value: any) { + const d = getItem(value); + d!.loaded = true; + } + + // 查找分组 + function toGroup(opts: { config: ClForm.Config; prop: string; refs: any }) { + if (active.value) { + let name; + + // 查找标签上绑定的数据 + const el = opts.refs.form.querySelector(`[data-prop="${opts.prop}"]`); + + // 各自判断 + if (el) { + name = el?.getAttribute("data-group"); + } else { + function deep(d: ClForm.Item) { + if (d.prop == opts.prop) { + name = d.group; + } else { + if (d.children) { + d.children.forEach(deep); + } + } + } + + config.items.forEach(deep); + } + + if (name) { + set(name); + } + } + } + + // 获取参数 + function get() { + return config.items.find((e) => e.type === "tabs"); + } + + // 设置参数 + function set(data: any) { + active.value = data; + } + + // 清空 + function clear() { + // 清空选中 + active.value = undefined; + + // 清空加载状态 + list.value.forEach((e) => { + if (e.lazy && e.loaded) { + e.loaded = undefined; + } + }); + } + + // 切换 + function change(value: any, isValid = true) { + return new Promise((resolve: Function, reject: Function) => { + function next() { + active.value = value; + resolve(); + } + + if (isValid) { + let isError = false; + + const arr = config.items + .filter((e) => e.group == active.value && !e._hidden && e.prop) + .map((e) => { + return new Promise((r: Function) => { + // 验证表单 + Form.value.validateField(e.prop, (valid: string) => { + if (valid) { + isError = true; + } + + r(valid); + }); + }); + }); + + Promise.all(arr).then((msg) => { + if (isError) { + reject(msg.filter(Boolean)); + } else { + next(); + } + }); + } else { + next(); + } + }); + } + + // 合并 + function mergeProp(item: ClForm.Item) { + const d = get(); + + if (d && d.props) { + const { mergeProp, labels = [] } = d.props; + + if (mergeProp) { + const t = labels.find((e) => e.value == item.group); + + if (t && t.name) { + item.prop = `${t.name}-${item.prop}`; + } + } + } + } + + return { + active, + list, + isLoaded, + onLoad, + get, + set, + change, + clear, + mergeProp, + toGroup + }; +} diff --git a/packages/crud/src/components/form/index.tsx b/packages/crud/src/components/form/index.tsx new file mode 100644 index 0000000..c27b4d4 --- /dev/null +++ b/packages/crud/src/components/form/index.tsx @@ -0,0 +1,683 @@ +import { defineComponent, h, nextTick } from "vue"; +import { assign, cloneDeep, isBoolean, isFunction, keys } from "lodash-es"; +import { useAction, useForm, usePlugins, useTabs } from "./helper"; +import { useBrowser, useConfig, useElApi, useRefs } from "../../hooks"; +import { getValue, merge } from "../../utils"; +import formHook from "../../utils/form-hook"; +import { renderNode } from "../../utils/vnode"; + +export default defineComponent({ + name: "cl-form", + + props: { + name: String, + inner: Boolean, + inline: Boolean, + enablePlugin: { + type: Boolean, + default: true + } + }, + + setup(props, { expose, slots }) { + const { refs, setRefs } = useRefs(); + const { style, dict } = useConfig(); + const browser = useBrowser(); + const { Form, config, form, visible, saving, loading, disabled } = useForm(); + + // 关闭的操作类型 + let closeAction: ClForm.CloseAction = "close"; + + // 旧表单数据 + let defForm: obj | undefined; + + // 选项卡 + const Tabs = useTabs({ config, Form }); + + // 操作 + const Action = useAction({ config, form, Form }); + + // 方法 + const ElFormApi = useElApi( + [ + "validate", + "validateField", + "resetFields", + "scrollToField", + "clearValidate", + "fields" + ], + Form + ); + + // 插件 + const plugin = usePlugins(props.enablePlugin, { visible }); + + // 显示加载中 + function showLoading() { + loading.value = true; + } + + // 隐藏加载 + function hideLoading() { + loading.value = false; + } + + // 设置是否禁用 + function setDisabled(val: boolean = true) { + disabled.value = val; + } + + // 请求表单保存状态 + function done() { + saving.value = false; + } + + // 关闭表单 + function close(action?: ClForm.CloseAction) { + if (action) { + closeAction = action; + } + + beforeClose(() => { + visible.value = false; + done(); + }); + } + + // 关闭前 + function beforeClose(done: fn) { + if (config.on?.close) { + config.on.close(closeAction, done); + } else { + done(); + } + } + + // 关闭后 + function onClosed() { + Tabs.clear(); + Form.value?.clearValidate(); + } + + // 清空表单验证 + function clear() { + for (const i in form) { + delete form[i]; + } + + setTimeout(() => { + Form.value?.clearValidate(); + }, 0); + } + + // 重置 + function reset() { + if (defForm) { + for (const i in defForm) { + form[i] = cloneDeep(defForm[i]); + } + } + } + + // 转换表单值,处理多层级等数据 + function invokeData(d: any) { + for (const i in d) { + if (i.includes("-")) { + // 结构参数 + const [a, ...arr] = i.split("-"); + + // 关键值的key + const k: string = arr.pop() || ""; + + if (!d[a]) { + d[a] = {}; + } + + let f: any = d[a]; + + // 设置默认值 + arr.forEach((e) => { + if (!f[e]) { + f[e] = {}; + } + + f = f[e]; + }); + + // 设置关键值 + f[k] = d[i]; + + delete d[i]; + } + } + } + + // 表单提交 + function submit(callback?: fn) { + // 验证表单 + Form.value.validate(async (valid: boolean, error: any) => { + if (valid) { + saving.value = true; + + // 拷贝表单值 + const d = cloneDeep(form); + + config.items.forEach((e) => { + function deep(e: ClForm.Item) { + if (e.prop) { + // 过滤隐藏的表单项 + if (e._hidden) { + if (e.prop) { + delete d[e.prop]; + } + } + + // hook 提交处理 + if (e.hook) { + formHook.submit({ + ...e, + value: e.prop ? d[e.prop] : undefined, + form: d + }); + } + } + + if (e.children) { + e.children.forEach(deep); + } + } + + deep(e); + }); + + // 处理数据 + invokeData(d); + + const submit = callback || config.on?.submit; + + // 提交事件 + if (submit) { + submit(await plugin.submit(d), { + close() { + close("save"); + }, + done + }); + } else { + done(); + } + } else { + // 切换到对应的选项卡 + Tabs.toGroup({ + refs, + config, + prop: keys(error)[0] + }); + } + }); + } + + // 打开表单 + function open(options?: ClForm.Options, plugins?: ClForm.Plugin[]) { + if (!options) { + return console.error("Options is not null"); + } + + // 清空 + if (options.isReset !== false) { + clear(); + } + + // 显示对话框 + visible.value = true; + + // 默认关闭方式 + closeAction = "close"; + + // 合并配置 + for (const i in config) { + switch (i) { + // 表单项 + case "items": + function deep(arr: any[]): any[] { + return arr.map((e) => { + const d = getValue(e); + + return { + ...d, + children: d?.children ? deep(d.children) : undefined + }; + }); + } + + config.items = deep(options.items || []); + break; + // 事件、参数、操作 + case "on": + case "op": + case "props": + case "dialog": + case "_data": + merge(config[i], options[i] || {}); + break; + // 其他 + default: + config[i] = options[i]; + break; + } + } + + // 预设表单值 + if (options?.form) { + for (const i in options.form) { + form[i] = options.form[i]; + } + } + + // 设置表单数据 + config.items.forEach((e) => { + function deep(e: ClForm.Item) { + if (e.prop) { + // 解析 prop + if (e.prop.includes(".")) { + e.prop = e.prop.replace(/\./g, "-"); + } + + // prop 合并 + Tabs.mergeProp(e); + + // hook 绑定值 + formHook.bind({ + ...e, + value: form[e.prop] !== undefined ? form[e.prop] : cloneDeep(e.value), + form + }); + + // 表单验证 + if (e.required) { + e.rules = { + required: true, + message: dict.label.nonEmpty.replace("{label}", e.label || "") + }; + } + } + + // 设置 tabs 默认值 + if (e.type == "tabs") { + Tabs.set(e.value); + } + + // 子集 + if (e.children) { + e.children.forEach(deep); + } + } + + deep(e); + }); + + // 设置默认值 + if (!defForm) { + defForm = cloneDeep(form); + } + + // 创建插件 + plugin.create(plugins); + + // 打开回调 + nextTick(() => { + setTimeout(() => { + // 打开事件 + if (config.on?.open) { + config.on.open(form); + } + }, 10); + }); + } + + // 绑定表单数据 + function bindForm(data: any) { + config.items.forEach((e) => { + function deep(e: ClForm.Item) { + formHook.bind({ + ...e, + value: e.prop ? data[e.prop] : undefined, + form: data + }); + + if (e.children) { + e.children.forEach(deep); + } + } + + deep(e); + }); + + assign(form, data); + } + + // 渲染表单项 + function renderFormItem(e: ClForm.Item) { + const { isDisabled } = config._data; + + if (e.type == "tabs") { + return ( + + ); + } + + // 是否隐藏 + e._hidden = parseHidden(e.hidden, { + scope: form + }); + + // 分组显示 + const inGroup = e.group ? e.group === Tabs.active.value : true; + + // 是否已加载完成 + const isLoaded = e.component && Tabs.isLoaded(e.group); + + // 表单项 + const FormItem = h( + , + e.props, + { + label() { + if (e.renderLabel) { + return renderNode(e.renderLabel, { + scope: form, + render: "slot", + slots + }); + } else { + return e.label; + } + }, + default() { + return ( +
+
+ {["prepend", "component", "append"] + .filter((k) => e[k]) + .map((name) => { + const children = e.children && ( +
+ + {e.children.map(renderFormItem)} + +
+ ); + + const Item = renderNode(e[name], { + item: e, + prop: e.prop, + scope: form, + slots, + children, + _data: { + isDisabled + } + }); + + return ( +
+ {Item} +
+ ); + })} +
+ + {isBoolean(e.collapse) && ( +
{ + Action.collapseItem(e); + }}> + + {e.collapse + ? dict.label.seeMore + : dict.label.hideContent} + +
+ )} +
+ ); + } + } + ); + + let span = e.span || style.form.span; + + if (browser.isMini) { + span = 24; + } + + // 是否行内 + const Item = props.inline ? ( + FormItem + ) : ( + + {FormItem} + + ); + + return isLoaded ? Item : null; + } + + // 渲染表单 + function renderContainer() { + // 表单项列表 + const children = config.items.map(renderFormItem); + + // 表单标签位置 + const labelPosition = + browser.isMini && !props.inline + ? "top" + : config.props.labelPosition || style.form.labelPosition; + + return ( +
+ {h( + { + submit(); + e.preventDefault(); + }} + />, + { + ...config.props, + labelPosition + }, + { + default: () => { + const items = [ + slots.prepend && slots.prepend({ scope: form }), + children, + slots.append && slots.append({ scope: form }) + ]; + + return ( +
+ {props.inline ? ( + items + ) : ( + {items} + )} +
+ ); + } + } + )} +
+ ); + } + + // 渲染表单底部按钮 + function renderFooter() { + const { hidden, buttons, saveButtonText, closeButtonText, justify } = config.op; + + if (hidden) { + return null; + } + + const Btns = buttons?.map((e: any) => { + switch (e) { + case "save": + return ( + { + submit(); + }}> + {saveButtonText} + + ); + case "close": + return ( + { + close("close"); + }}> + {closeButtonText} + + ); + default: + return renderNode(e, { + scope: form, + slots, + custom() { + return ( + { + e.onClick({ scope: form }); + }}> + {e.label} + + ); + } + }); + } + }); + + return ( + + ); + } + + // Tools + function parseHidden(value: any, { scope }: any) { + if (isBoolean(value)) { + return value; + } else if (isFunction(value)) { + return value({ scope }); + } + + return false; + } + + const ctx = { + name: props.name, + refs, + Form, + visible, + saving, + form, + config, + loading, + disabled, + open, + close, + done, + clear, + reset, + submit, + invokeData, + bindForm, + showLoading, + hideLoading, + setDisabled, + Tabs, + ...Action, + ...ElFormApi + }; + + expose(ctx); + + return () => { + if (props.inner) { + return ( + visible.value && ( +
+ {renderContainer()} + {renderFooter()} +
+ ) + ); + } else { + return h( + , + { + title: config.title, + height: config.height, + width: config.width, + ...config.dialog, + beforeClose, + onClosed, + keepAlive: false + }, + { + default() { + return renderContainer(); + }, + footer() { + return renderFooter(); + } + } + ); + } + }; + } +}); diff --git a/packages/crud/src/components/index.tsx b/packages/crud/src/components/index.tsx new file mode 100644 index 0000000..b23c344 --- /dev/null +++ b/packages/crud/src/components/index.tsx @@ -0,0 +1,50 @@ +import { App } from "vue"; +import Crud from "./crud"; +import AddBtn from "./add-btn"; +import AdvBtn from "./adv/btn"; +import AdvSearch from "./adv/search"; +import Flex from "./flex1"; +import Form from "./form"; +import FormTabs from "./form-tabs"; +import FormCard from "./form-card"; +import MultiDeleteBtn from "./multi-delete-btn"; +import Pagination from "./pagination"; +import RefreshBtn from "./refresh-btn"; +import SearchKey from "./search-key"; +import Table from "./table"; +import Upsert from "./upsert"; +import Dialog from "./dialog"; +import Filter from "./filter"; +import Search from "./search"; +import ErrorMessage from "./error-message"; +import Row from "./row"; +import ContextMenu from "./context-menu"; + +export const components: { [key: string]: any } = { + Crud, + AddBtn, + AdvBtn, + AdvSearch, + Flex, + Form, + FormTabs, + FormCard, + MultiDeleteBtn, + Pagination, + RefreshBtn, + SearchKey, + Table, + Upsert, + Dialog, + Filter, + Search, + ErrorMessage, + Row, + ContextMenu +}; + +export function useComponent(app: App) { + for (const i in components) { + app.component(components[i].name, components[i]); + } +} diff --git a/packages/crud/src/components/multi-delete-btn/index.tsx b/packages/crud/src/components/multi-delete-btn/index.tsx new file mode 100644 index 0000000..a1d9433 --- /dev/null +++ b/packages/crud/src/components/multi-delete-btn/index.tsx @@ -0,0 +1,27 @@ +import { defineComponent } from "vue"; +import { useConfig, useCore } from "../../hooks"; + +export default defineComponent({ + name: "cl-multi-delete-btn", + + setup(_, { slots }) { + const { crud } = useCore(); + const { style } = useConfig(); + + return () => { + return ( + crud.getPermission("delete") && ( + { + crud.rowDelete(...crud.selection); + }}> + {slots.default?.() || crud.dict.label.multiDelete} + + ) + ); + }; + } +}); diff --git a/packages/crud/src/components/pagination/index.tsx b/packages/crud/src/components/pagination/index.tsx new file mode 100644 index 0000000..adc358c --- /dev/null +++ b/packages/crud/src/components/pagination/index.tsx @@ -0,0 +1,90 @@ +import { defineComponent, h, onMounted, onUnmounted, ref } from "vue"; +import { useBrowser, useConfig, useCore } from "../../hooks"; + +export default defineComponent({ + name: "cl-pagination", + + setup(_, { expose }) { + const { crud, mitt } = useCore(); + const { style } = useConfig(); + const browser = useBrowser(); + + // 总数 + const total = ref(0); + + // 当前页数 + const currentPage = ref(1); + + // 每页大小 + const pageSize = ref(20); + + // 页数发生变化 + function onCurrentChange(index: number) { + crud.refresh({ + page: index + }); + } + + // 条目发生变化 + function onSizeChange(size: number) { + crud.refresh({ + page: 1, + size + }); + } + + // 设置分页信息 + function setPagination(res: obj) { + if (res) { + currentPage.value = res.currentPage || res.page || 1; + pageSize.value = res.pageSize || res.size || 20; + total.value = res.total || 0; + crud.params.size = pageSize.value; + } + } + + // 数据刷新 + function onRefresh(res: ClCrud.Response["page"]) { + setPagination(res.pagination); + } + + // 监听刷新事件 + onMounted(() => { + mitt.on("crud.refresh", onRefresh); + }); + + // 移除监听事件 + onUnmounted(() => { + mitt.off("crud.refresh", onRefresh); + }); + + expose({ + total, + currentPage, + pageSize, + setPagination + }); + + return () => { + return h( + , + { + onSizeChange, + onCurrentChange, + total: total.value, + currentPage: currentPage.value, + pageSize: pageSize.value + } + ); + }; + } +}); diff --git a/packages/crud/src/components/refresh-btn/index.tsx b/packages/crud/src/components/refresh-btn/index.tsx new file mode 100644 index 0000000..df8b8cd --- /dev/null +++ b/packages/crud/src/components/refresh-btn/index.tsx @@ -0,0 +1,23 @@ +import { defineComponent } from "vue"; +import { useConfig, useCore } from "../../hooks"; + +export default defineComponent({ + name: "cl-refresh-btn", + + setup(_, { slots }) { + const { crud } = useCore(); + const { style } = useConfig(); + + return () => { + return ( + { + crud.refresh(); + }}> + {slots.default?.() || crud.dict.label.refresh} + + ); + }; + } +}); diff --git a/packages/crud/src/components/row/index.tsx b/packages/crud/src/components/row/index.tsx new file mode 100644 index 0000000..4ea69c6 --- /dev/null +++ b/packages/crud/src/components/row/index.tsx @@ -0,0 +1,11 @@ +import { defineComponent } from "vue"; + +export default defineComponent({ + name: "cl-row", + + setup(_, { slots }) { + return () => { + return {slots.default && slots.default()}; + }; + } +}); diff --git a/packages/crud/src/components/search-key/index.tsx b/packages/crud/src/components/search-key/index.tsx new file mode 100644 index 0000000..e213424 --- /dev/null +++ b/packages/crud/src/components/search-key/index.tsx @@ -0,0 +1,178 @@ +import { defineComponent, ref, computed, type PropType, useModel } from "vue"; +import { useConfig, useCore } from "../../hooks"; +import { parsePx } from "../../utils"; +import { debounce } from "lodash-es"; + +export default defineComponent({ + name: "cl-search-key", + + props: { + // 绑定值 + modelValue: String, + // 选中字段 + field: { + type: String, + default: "keyWord" + }, + // 字段列表 + fieldList: { + type: Array as PropType>, + default: () => [] + }, + // 搜索时的钩子 + onSearch: Function, + // 输入框占位内容 + placeholder: String, + // 宽度 + width: { + type: [String, Number], + default: 280 + }, + // 是否实时刷新 + refreshOnInput: Boolean + }, + + emits: ["update:modelValue", "change", "field-change"], + + setup(props, { emit, expose }) { + const { crud } = useCore(); + const { style } = useConfig(); + + // 选中字段 + const selectField = ref(props.field); + + // 加载状态 + const loading = ref(false); + + // 文字提示 + const placeholder = computed(() => { + if (props.placeholder) { + return props.placeholder; + } else { + const item = props.fieldList.find((e) => e.value == selectField.value); + + if (item) { + return crud.dict.label.placeholder + item.label; + } else { + return crud.dict.label.searchKey; + } + } + }); + + // 搜索内容 + const value = useModel(props, "modelValue"); + + // 锁 + let lock = false; + + // 搜索 + function search() { + if (!lock) { + const params: obj = {}; + + props.fieldList.forEach((e) => { + params[e.value] = undefined; + }); + + async function next(newParams?: obj) { + loading.value = true; + + await crud.refresh({ + page: 1, + ...params, + [selectField.value]: value.value || undefined, + ...newParams + }) + .catch(err => { + console.error(err); + }) + + loading.value = false; + } + + if (props.onSearch) { + props.onSearch(params, { next }); + } else { + next(); + } + } + } + + // 回车搜索 + function onKeydown({ key }: KeyboardEvent) { + if (key === "Enter") { + search(); + } + } + + // 监听变化 + function onChange(val: string) { + if (!props.refreshOnInput) { + search(); + lock = true; + + setTimeout(() => { + lock = false; + }, 300); + + emit("change", val); + } + } + + // 监听输入 + const onInput = debounce((val: string) => { + emit("change", val); + + if (props.refreshOnInput) { + search(); + } + }, 300); + + // 监听字段选择 + function onFieldChange() { + emit("field-change", selectField.value); + value.value = undefined; + } + + expose({ + search + }); + + return () => { + return ( +
+ 0} + onChange={onFieldChange}> + {props.fieldList.map((e, i) => ( + + ))} + + +
+ + + + {crud.dict.label.search} + +
+
+ ); + }; + } +}); diff --git a/packages/crud/src/components/search/helper/plugins.ts b/packages/crud/src/components/search/helper/plugins.ts new file mode 100644 index 0000000..05628e6 --- /dev/null +++ b/packages/crud/src/components/search/helper/plugins.ts @@ -0,0 +1,21 @@ +import { getCurrentInstance } from "vue"; +import { useConfig } from "../../../hooks"; +import { uniqueFns } from "../../../utils"; + +export function usePlugins() { + const that: any = getCurrentInstance(); + const { style } = useConfig(); + + // 插件创建 + function create(plugins: ClSearch.Plugin[] = []) { + uniqueFns([...(style.search?.plugins || []), ...plugins]).forEach((p) => { + p({ + exposed: that.exposed + }); + }); + } + + return { + create + }; +} diff --git a/packages/crud/src/components/search/index.tsx b/packages/crud/src/components/search/index.tsx new file mode 100644 index 0000000..305413f --- /dev/null +++ b/packages/crud/src/components/search/index.tsx @@ -0,0 +1,298 @@ +import { useConfig, useCore, useForm, useProxy, useRefs } from "../../hooks"; +import { + onMounted, + PropType, + defineComponent, + ref, + h, + reactive, + inject, + mergeProps, + nextTick, + onUnmounted +} from "vue"; +import { useApi } from "../form/helper"; +import { Search, Refresh, Bottom, Top } from "@element-plus/icons-vue"; +import { mitt } from "../../utils/mitt"; +import { isArray, isEmpty } from "lodash-es"; +import { usePlugins } from "./helper/plugins"; + +export default defineComponent({ + name: "cl-search", + + props: { + // 是否行内 + inline: { + type: Boolean, + default: true + }, + + // cl-form 表单配置 + props: { + type: Object, + default: () => ({}) + }, + + // 表单值 + data: { + type: Object, + default: () => ({}) + }, + + // 列 + items: { + type: Array as PropType, + default: () => [] + }, + + // 是否需要重置按钮 + resetBtn: { + type: Boolean, + default: false + }, + + // 是否需要折叠 + collapse: { + type: Boolean, + default: false + }, + + // 初始化 + onLoad: Function, + + // 搜索时钩子 + onSearch: Function + }, + + emits: ["reset"], + + setup(props, { slots, expose, emit }) { + const { crud } = useCore(); + const { refs, setRefs } = useRefs() + const { style } = useConfig(); + const plugin = usePlugins() + + // 配置 + const config = reactive( + mergeProps(props, inject("useSearch__options") || {}) + ); + + // cl-form + const Form = useForm(); + + // 加载中 + const loading = ref(false); + + // 展开 + const isExpand = ref(!config.collapse); + + // 显示展开、收起按钮 + const showExpandBtn = ref(false); + + // 搜索 + function search(params?: any) { + const form = Form.value?.getForm(); + + async function next(data?: any) { + loading.value = true; + + const d = { + page: 1, + ...form, + ...data, + ...params + }; + + for (const i in d) { + if (d[i] === "") { + d[i] = undefined; + } + } + + const res = await crud.refresh(d); + + loading.value = false; + + return res; + } + + if (config.onSearch) { + config.onSearch(form, { next }); + } else { + next(); + } + } + + // 重置 + function reset() { + const d: any = {}; + + config.items?.map((e) => { + if (typeof e.hook != 'string' && e.hook?.reset) { + const props = e.hook.reset(e.prop!) + + if (isArray(props)) { + props.forEach((prop) => { + d[prop] = undefined; + }) + } + } + + d[e.prop!] = undefined; + }); + + // 重置表单 + Form.value?.reset(); + + // 列表刷新 + search(d); + + // 重置事件 + emit("reset", d); + } + + // 收起、展开 + function expand() { + isExpand.value = !isExpand.value; + + nextTick(() => { + crud?.["cl-table"].calcMaxHeight() + }) + } + + // 判断展开状态 + function onExpand() { + if (config.collapse) { + const el = refs.form?.querySelector(".cl-form__items"); + + if (el) { + showExpandBtn.value = el.clientHeight > 84; + } + } + } + + function onResize() { + onExpand(); + } + + const ctx = { + search, + reset, + Form, + config, + ...useApi({ Form }) + }; + + useProxy(ctx); + expose(ctx); + plugin.create(config.plugins); + + onMounted(() => { + Form.value?.open({ + op: { + hidden: true + }, + props: { + labelPosition: 'right', + ...config.props + }, + items: config.items?.map(e => { + return { + col: { + sm: 12, + md: 8, + xs: 24, + lg: 6, + }, + ...e, + } + }), + form: config.data, + on: { + open(data) { + config.onLoad?.(data); + onExpand(); + }, + change(data, prop) { + config.onChange?.(data, prop); + } + } + }); + + mitt.on("resize", onResize); + }); + + onUnmounted(() => { + mitt.off("resize", onResize); + }) + + return () => { + const btnEl = ( + + {/* 重置按钮 */} + {config.resetBtn && ( + + {crud.dict.label.reset} + + )} + + {/* 搜索按钮 */} + { + search(); + }}> + {crud.dict.label.search} + + + {/* 自定义按钮 */} + {slots?.buttons?.(Form.value?.form)} + + ); + + return ( +
+
+ {h( + , + {}, + { + append() { + return config.collapse ? null : (isEmpty(config.items) || btnEl); + }, + ...slots + } + )} +
+ + {config.collapse && ( +
+ {showExpandBtn.value && ( + + {isExpand.value ? crud.dict.label.collapse : crud.dict.label.expand} + {isExpand.value ? : } + + )} + + + + {btnEl} +
+ )} +
+ ); + }; + } +}); diff --git a/packages/crud/src/components/table/helper/data.ts b/packages/crud/src/components/table/helper/data.ts new file mode 100644 index 0000000..53ac4a8 --- /dev/null +++ b/packages/crud/src/components/table/helper/data.ts @@ -0,0 +1,35 @@ +import { nextTick, ref } from "vue"; +import { useCore } from "../../../hooks"; + +export function useData({ config, Table }: { config: ClTable.Config; Table: Vue.Ref }) { + const { mitt, crud } = useCore(); + + // 列表数据 + const data = ref([]); + + // 设置数据 + function setData(list: obj[]) { + data.value = list; + } + + // 监听刷新 + mitt.on("crud.refresh", ({ list }: ClCrud.Response["page"]) => { + data.value = list; + + // 显示选中行 + nextTick(() => { + crud.selection.forEach((e) => { + const d = list.find((a) => a[config.rowKey] == e[config.rowKey]); + + if (d) { + Table.value.toggleRowSelection(d, true); + } + }); + }); + }); + + return { + data, + setData + }; +} diff --git a/packages/crud/src/components/table/helper/header.tsx b/packages/crud/src/components/table/helper/header.tsx new file mode 100644 index 0000000..3f20a14 --- /dev/null +++ b/packages/crud/src/components/table/helper/header.tsx @@ -0,0 +1,91 @@ +import { CloseBold, Search } from "@element-plus/icons-vue"; +import { h } from "vue"; +import { useCrud } from "../../../hooks"; +import { renderNode } from "../../../utils/vnode"; + +export function renderHeader(item: ClTable.Column, { scope, slots }: any) { + const crud = useCrud(); + + const slot = slots[`header-${item.prop}`]; + + if (slot) { + return slot({ + scope + }); + } + + if (!item.search || !item.search.component) { + return item.label; + } + + // 显示输入框 + function show(e: MouseEvent) { + item.search.isInput = true; + e.stopPropagation(); + } + + // 隐藏输入框 + function hide() { + if (item.search.value !== undefined) { + item.search.value = undefined; + refresh(); + } + + item.search.isInput = false; + } + + // 刷新 + function refresh(params?: any) { + const { value } = item.search; + + crud.value?.refresh({ + page: 1, + [item.prop]: value === "" ? undefined : value, + ...params + }); + } + + // 文字 + const text = ( +
+ {item.search.icon?.() ?? } + + {item.renderLabel ? item.renderLabel(scope) : item.label} +
+ ); + + // 输入框 + const input = h(renderNode(item.search.component, { prop: item.prop }), { + clearable: true, + modelValue: item.search.value, + onVnodeMounted(vn) { + // 默认聚焦 + vn.component?.exposed?.focus?.(); + }, + onInput(val: any) { + item.search.value = val; + }, + onChange(val: any) { + item.search.value = val; + + // 更改时刷新列表 + if (item.search.refreshOnChange) { + refresh(); + } + } + }); + + return ( +
+
{item.search.isInput ? input : text}
+ + {item.search.isInput && ( +
+ + + +
+ )} +
+ ); +} diff --git a/packages/crud/src/components/table/helper/height.ts b/packages/crud/src/components/table/helper/height.ts new file mode 100644 index 0000000..76f0586 --- /dev/null +++ b/packages/crud/src/components/table/helper/height.ts @@ -0,0 +1,99 @@ +import { debounce, last } from "lodash-es"; +import { nextTick, onActivated, onMounted, ref } from "vue"; +import { addClass, removeClass } from "../../../utils"; +import { mitt } from "../../../utils/mitt"; + +// 表格高度 +export function useHeight({ config, Table }: { Table: Vue.Ref; config: ClTable.Config }) { + // 最大高度 + const maxHeight = ref(0); + + // 计算表格最大高度 + const update = debounce(async () => { + await nextTick(); + + let vm = Table.value; + + if (vm) { + while (!vm.$parent?.$el.className?.includes("cl-crud")) { + vm = vm.$parent; + } + + if (vm) { + const p = vm.$parent.$el; + + await nextTick(); + + // 高度 + let h = 0; + + // 表格下间距 + if (vm.$el.className.includes("cl-row")) { + h += 10; + } + + // 上高度 + h += vm.$el.offsetTop; + + // 获取下高度 + let n = vm.$el.nextSibling; + + // 集合 + const arr = [vm.$el]; + + while (n) { + if (n.offsetHeight > 0) { + h += n.offsetHeight || 0; + arr.push(n); + + if (n.className.includes("cl-row--last")) { + h += 10; + } + } + + n = n.nextSibling; + } + + // 移除 cl-row--last + arr.forEach((e) => { + removeClass(e, "cl-row--last"); + }); + + // 最后一个可视元素 + const z = last(arr); + + // 去掉 cl-row 下间距高度 + if (z?.className.includes("cl-row")) { + addClass(z, "cl-row--last"); + h -= 10; + } + + // 上间距 + h += parseInt(window.getComputedStyle(p).paddingTop, 10); + + // 设置最大高度 + if (config.autoHeight) { + maxHeight.value = p.clientHeight - h; + } + } + } + }, 100); + + // 窗口大小改变事件 + mitt.on("resize", () => { + update(); + }); + + onMounted(function () { + update(); + }); + + onActivated(function () { + update(); + }); + + return { + maxHeight, + calcMaxHeight: update + }; +} diff --git a/packages/crud/src/components/table/helper/index.ts b/packages/crud/src/components/table/helper/index.ts new file mode 100644 index 0000000..27f6f7d --- /dev/null +++ b/packages/crud/src/components/table/helper/index.ts @@ -0,0 +1,43 @@ +import { inject, reactive, ref } from "vue"; +import { useConfig } from "../../../hooks"; +import { getValue, mergeConfig } from "../../../utils"; +import type { TableInstance } from "element-plus"; + +export function useTable(props: any) { + const { style } = useConfig(); + + const Table = ref(); + + // 配置 + const config = reactive(mergeConfig(props, inject("useTable__options") || {})); + + // 列表项动态处理 + config.columns = (config.columns || []).map((e) => getValue(e)); + + // 自动高度 + config.autoHeight = config.autoHeight ?? style.table.autoHeight; + + // 右键菜单 + config.contextMenu = config.contextMenu ?? style.table.contextMenu; + + // 事件 + if (!config.on) { + config.on = {}; + } + + // 参数 + if (!config.props) { + config.props = {}; + } + + return { Table, config }; +} + +export * from "./data"; +export * from "./height"; +export * from "./op"; +export * from "./render"; +export * from "./row"; +export * from "./selection"; +export * from "./sort"; +export * from "./header"; diff --git a/packages/crud/src/components/table/helper/op.ts b/packages/crud/src/components/table/helper/op.ts new file mode 100644 index 0000000..556be31 --- /dev/null +++ b/packages/crud/src/components/table/helper/op.ts @@ -0,0 +1,69 @@ +import { nextTick, ref } from "vue"; +import { useCore } from "../../../hooks"; +import { isArray, isBoolean } from "lodash-es"; + +export function useOp({ config }: { config: ClTable.Config }) { + const { mitt } = useCore(); + + // 是否可见,用于解决一些显示隐藏的副作用 + const visible = ref(true); + + // 重新构建 + async function reBuild(cb?: fn) { + visible.value = false; + + await nextTick(); + + if (cb) { + cb(); + } + + visible.value = true; + + await nextTick(); + + mitt.emit("resize"); + } + + // 显示列 + function showColumn(prop: string | string[], status?: boolean) { + const keys = isArray(prop) ? prop : [prop]; + + // 多级表头 + function deep(list: ClTable.Column[]) { + list.forEach((e) => { + if (e.prop && keys.includes(e.prop)) { + e.hidden = isBoolean(status) ? !status : false; + } + + if (e.children) { + deep(e.children); + } + }); + } + + deep(config.columns); + } + + // 隐藏列 + function hideColumn(prop: string | string[]) { + showColumn(prop, false); + } + + // 设置列 + function setColumns(list: ClTable.Column[]) { + if (list) { + reBuild(() => { + config.columns.splice(0, config.columns.length, ...list); + }); + } + } + + return { + visible, + reBuild, + showColumn, + hideColumn, + setColumns + }; +} diff --git a/packages/crud/src/components/table/helper/plugins.ts b/packages/crud/src/components/table/helper/plugins.ts new file mode 100644 index 0000000..4d47605 --- /dev/null +++ b/packages/crud/src/components/table/helper/plugins.ts @@ -0,0 +1,22 @@ +import { getCurrentInstance } from "vue"; +import { useConfig } from "../../../hooks"; +import { uniqueFns } from "../../../utils"; + +export function usePlugins() { + const that: any = getCurrentInstance(); + const { style } = useConfig(); + + // 插件创建 + function create(plugins: ClTable.Plugin[] = []) { + // 执行 + uniqueFns([...(style.table.plugins || []), ...plugins]).forEach((p) => { + p({ + exposed: that.exposed + }); + }); + } + + return { + create + }; +} diff --git a/packages/crud/src/components/table/helper/render.tsx b/packages/crud/src/components/table/helper/render.tsx new file mode 100644 index 0000000..b57df76 --- /dev/null +++ b/packages/crud/src/components/table/helper/render.tsx @@ -0,0 +1,327 @@ +import { h, useSlots } from "vue"; +import { useCore, useBrowser, useConfig } from "../../../hooks"; +import { assign, cloneDeep, isArray, isEmpty, isObject, isString, orderBy } from "lodash-es"; +import { deepFind, getValue } from "../../../utils"; +import { renderNode } from "../../../utils/vnode"; +import { renderHeader } from "./header"; + +// 渲染 +export function useRender() { + const browser = useBrowser(); + const slots = useSlots(); + const { crud } = useCore(); + const { style } = useConfig(); + + // 渲染列 + function renderColumn(columns: ClTable.Column[]) { + const arr = columns.map((e) => { + const d = getValue(e); + + if (!d.orderNum) { + d.orderNum = 0; + } + + return d; + }); + + return orderBy(arr, "orderNum", "asc") + .map((item, index) => { + if (item.hidden) { + return null; + } + + const ElTableColumn = ( + + ); + + // 操作按钮 + if (item.type === "op") { + const props = assign( + { + label: crud.dict.label.op, + width: style.table.column.opWidth, + fixed: browser.isMini ? null : "right" + }, + item + ); + + return h(ElTableColumn, props, { + default: (scope: any) => { + return ( +
+ {renderOpButtons(item.buttons, { scope })} +
+ ); + } + }); + } + // 多选,序号 + else if (["selection", "index"].includes(item.type)) { + return h(ElTableColumn, item); + } + // 默认 + else { + function deep(item: ClTable.Column) { + if (item.hidden) { + return null; + } + + const props: obj = cloneDeep(item); + + // Cannot set property children of # + delete props.children; + + return h(ElTableColumn, props, { + header(scope: any) { + return renderHeader(item, { scope, slots }); + }, + default(scope: any) { + if (item.children) { + return item.children.map(deep); + } + + // 使用插槽 + const slot = slots[`column-${item.prop}`]; + + if (slot) { + return slot({ + scope, + item + }); + } else { + // 绑定值 + let value = scope.row[item.prop]; + + // 格式化 + if (item.formatter) { + value = item.formatter( + scope.row, + scope.column, + value, + scope.$index + ); + + if (isObject(value)) { + return value; + } + } + + // 自定义渲染 + if (item.render) { + return item.render( + scope.row, + scope.column, + value, + scope.$index + ); + } + // 自定义渲染2 + else if (item.component) { + return renderNode(item.component, { + prop: item.prop, + scope: scope.row, + _data: { + column: scope.column, + index: scope.$index, + row: scope.row + } + }); + } + // 字典状态 + else if (item.dict) { + return renderDict(value, item); + } + // 空数据 + else if (isEmpty(value)) { + return scope.emptyText; + } else { + return value; + } + } + } + }); + } + + return deep(item); + } + }) + .filter(Boolean); + } + + // 渲染操作按钮 + function renderOpButtons(buttons: any, { scope }: any) { + const list = getValue(buttons || ["edit", "delete"], { scope }) as ClTable.OpButton; + + return list.map((vnode) => { + if (vnode === "info") { + return ( + { + crud.rowInfo(scope.row); + e.stopPropagation(); + }}> + {crud.dict.label?.info} + + ); + } else if (vnode === "edit") { + return ( + { + crud.rowEdit(scope.row); + e.stopPropagation(); + }}> + {crud.dict.label?.update} + + ); + } else if (vnode === "delete") { + return ( + { + crud.rowDelete(scope.row); + e.stopPropagation(); + }}> + {crud.dict.label?.delete} + + ); + } else { + if (typeof vnode === "object") { + if (vnode.hidden) { + return null; + } + } + + return renderNode(vnode, { + scope, + slots, + custom(vnode) { + return ( + { + vnode.onClick({ scope }); + e.stopPropagation(); + }}> + {vnode.label} + + ); + } + }); + } + }); + } + + // 渲染字典 + function renderDict(value: any, item: ClTable.Column) { + // 选项列表 + const list = cloneDeep(item.dict || []) as DictOptions; + + // 字符串分隔符 + const separator = item.dictSeparator === undefined ? "," : item.dictSeparator; + + // 设置颜色 + if (item.dictColor) { + list.forEach((e, i) => { + if (!e.color) { + e.color = style.colors[i]; + } + }); + } + + // 绑定值 + let values: any[] = []; + + // 格式化值 + if (isArray(value)) { + values = value; + } else if (isString(value)) { + if (separator) { + values = value.split(separator); + } else { + values = [value]; + } + } else { + values = [value]; + } + + // 返回值 + const result = values + .filter((e) => e !== undefined && e !== null && e !== "") + .map((v) => { + const d = deepFind(v, list, { allLevels: item.dictAllLevels }) || { + label: v, + value: v + }; + + return { + ...d, + children: [] + }; + }); + + // 格式化返回 + if (item.dictFormatter) { + return item.dictFormatter(result); + } else { + // tag 返回 + return result.map((e) => { + return h( + , + { + type: e.type, + closable: e.closable, + hit: e.hit, + color: e.color, + size: e.size, + effect: e.effect || "dark", + round: e.round + }, + { + default: () => {e.label} + } + ); + }); + } + } + + // 插槽 empty + function renderEmpty(emptyText: string) { + return ( +
+ {slots.empty ? ( + slots.empty() + ) : ( + + )} +
+ ); + } + + // 插槽 append + function renderAppend() { + return
{slots.append && slots.append()}
; + } + + return { + renderColumn, + renderEmpty, + renderAppend + }; +} diff --git a/packages/crud/src/components/table/helper/row.ts b/packages/crud/src/components/table/helper/row.ts new file mode 100644 index 0000000..80b7620 --- /dev/null +++ b/packages/crud/src/components/table/helper/row.ts @@ -0,0 +1,130 @@ +import { isEmpty, isFunction } from "lodash-es"; +import { useCore } from "../../../hooks"; +import { ContextMenu } from "../../context-menu"; + +// 单元行事件 +export function useRow({ + Table, + config, + Sort +}: { + Table: Vue.Ref; + config: ClTable.Config; + Sort: { + defaultSort: { + prop?: string; + order?: string; + }; + changeSort(prop: string, order: string): void; + }; +}) { + const { crud } = useCore(); + + // 右键菜单 + function onRowContextMenu(row: obj, column: obj, event: PointerEvent) { + // 菜单按钮 + const buttons = config.contextMenu; + // 是否开启 + const enable = !isEmpty(buttons); + + if (enable) { + // 高亮 + Table.value.setCurrentRow(row); + + // 解析按钮 + const list = buttons + .map((e) => { + switch (e) { + case "refresh": + return { + label: crud.dict.label.refresh, + callback(done: fn) { + crud.refresh(); + done(); + } + }; + case "edit": + case "update": + return { + label: crud.dict.label.update, + hidden: !crud.getPermission("update"), + callback(done: fn) { + crud.rowEdit(row); + done(); + } + }; + case "delete": + return { + label: crud.dict.label.delete, + hidden: !crud.getPermission("delete"), + callback(done: fn) { + crud.rowDelete(row); + done(); + } + }; + case "info": + return { + label: crud.dict.label.info, + hidden: !crud.getPermission("info"), + callback(done: fn) { + crud.rowInfo(row); + done(); + } + }; + case "check": + return { + label: crud.selection.find((e) => e.id == row.id) + ? crud.dict.label.deselect + : crud.dict.label.select, + hidden: !config.columns.find((e) => e.type === "selection"), + callback(done: fn) { + Table.value.toggleRowSelection(row); + done(); + } + }; + case "order-desc": + return { + label: `${column.label} - ${crud.dict.label.desc}`, + hidden: !column.sortable, + callback(done: fn) { + Sort.changeSort(column.property, "desc"); + done(); + } + }; + case "order-asc": + return { + label: `${column.label} - ${crud.dict.label.asc}`, + hidden: !column.sortable, + callback(done: fn) { + Sort.changeSort(column.property, "asc"); + done(); + } + }; + default: + if (isFunction(e)) { + return e(row, column, event); + } else { + return e; + } + } + }) + .filter((e) => Boolean(e) && !e.hidden); + + // 打开菜单 + if (!isEmpty(list)) { + ContextMenu.open(event, { + list + }); + } + } + + // 回调 + if (config.onRowContextmenu) { + config.onRowContextmenu(row, column, event); + } + } + + return { + onRowContextMenu + }; +} diff --git a/packages/crud/src/components/table/helper/selection.ts b/packages/crud/src/components/table/helper/selection.ts new file mode 100644 index 0000000..67a2dd2 --- /dev/null +++ b/packages/crud/src/components/table/helper/selection.ts @@ -0,0 +1,16 @@ +import { useCore } from "../../../hooks"; + +export function useSelection({ emit }: { emit: Vue.Emit }) { + const { crud } = useCore(); + + // 选择项发生变化 + function onSelectionChange(selection: any[]) { + crud.selection.splice(0, crud.selection.length, ...selection); + emit("selection-change", crud.selection); + } + + return { + selection: crud.selection, + onSelectionChange + }; +} diff --git a/packages/crud/src/components/table/helper/sort.ts b/packages/crud/src/components/table/helper/sort.ts new file mode 100644 index 0000000..2b95fe8 --- /dev/null +++ b/packages/crud/src/components/table/helper/sort.ts @@ -0,0 +1,86 @@ +import { useCore } from "../../../hooks"; + +// 排序 +export function useSort({ + config, + Table, + emit +}: { + config: ClTable.Config; + Table: Vue.Ref; + emit: Vue.Emit; +}) { + const { crud } = useCore(); + + // 设置默认排序Ï + const defaultSort = (function () { + let { prop, order } = config.defaultSort || {}; + + const item = config.columns.find((e) => + ["desc", "asc", "descending", "ascending"].find((a) => a == e.sortable) + ); + + if (item) { + prop = item.prop; + order = ["descending", "desc"].find((a) => a == item.sortable) + ? "descending" + : "ascending"; + } + + if (order && prop) { + crud.params.order = ["descending", "desc"].includes(order) ? "desc" : "asc"; + crud.params.prop = prop; + + return { + prop, + order + }; + } + + return {}; + })(); + + // 排序监听 + function onSortChange({ prop, order }: { prop: string | undefined; order: string }) { + if (config.sortRefresh) { + if (order === "descending") { + order = "desc"; + } + + if (order === "ascending") { + order = "asc"; + } + + if (!order) { + prop = undefined; + } + + crud.refresh({ + prop, + order, + page: 1 + }); + } + + emit("sort-change", { prop, order }); + } + + // 改变排序 + function changeSort(prop: string, order: string) { + if (order === "desc") { + order = "descending"; + } + + if (order === "asc") { + order = "ascending"; + } + + Table.value?.sort(prop, order); + } + + return { + defaultSort, + onSortChange, + changeSort + }; +} diff --git a/packages/crud/src/components/table/index.tsx b/packages/crud/src/components/table/index.tsx new file mode 100644 index 0000000..3120841 --- /dev/null +++ b/packages/crud/src/components/table/index.tsx @@ -0,0 +1,165 @@ +import { defineComponent, h } from "vue"; +import { + useRow, + useHeight, + useRender, + useSort, + useData, + useSelection, + useOp, + useTable +} from "./helper"; +import { useCore, useProxy, useElApi, useConfig } from "../../hooks"; +import { usePlugins } from "./helper/plugins"; + +export default defineComponent({ + name: "cl-table", + + props: { + // 列配置 + columns: { + type: Array, + default: () => [] + }, + // 是否自动计算高度 + autoHeight: { + type: Boolean, + default: null + }, + // 固定高度 + height: null, + // 右键菜单 + contextMenu: { + type: [Array, Boolean], + default: null + }, + // 默认排序 + defaultSort: Object, + // 排序后是否刷新 + sortRefresh: { + type: Boolean, + default: true + }, + // 空数据显示文案 + emptyText: String, + // 当前行的 key + rowKey: { + type: String, + default: "id" + } + }, + + emits: ["selection-change", "sort-change"], + + setup(props, { emit, expose }) { + const { crud } = useCore(); + const { style } = useConfig(); + const { Table, config } = useTable(props); + const plugin = usePlugins(); + + // 排序 + const Sort = useSort({ config, emit, Table }); + + // 行 + const Row = useRow({ + config, + Table, + Sort + }); + + // 高度 + const Height = useHeight({ config, Table }); + + // 数据 + const Data = useData({ config, Table }); + + // 多选 + const Selection = useSelection({ emit }); + + // 操作 + const Op = useOp({ config }); + + // 方法 + const ElTableApi = useElApi( + [ + "clearSelection", + "getSelectionRows", + "toggleRowSelection", + "toggleAllSelection", + "toggleRowExpansion", + "setCurrentRow", + "clearSort", + "clearFilter", + "doLayout", + "sort", + "scrollTo", + "setScrollTop", + "setScrollLeft", + "updateKeyChildren" + ], + Table + ); + + const ctx = { + Table, + config, + columns: config.columns, + ...Selection, + ...Data, + ...Sort, + ...Row, + ...Height, + ...Op, + ...ElTableApi + }; + + useProxy(ctx); + expose(ctx); + plugin.create(config.plugins); + + return () => { + const { renderColumn, renderAppend, renderEmpty } = useRender(); + + return ( + ctx.visible.value && + h( + , + { + ...config.on, + ...config.props, + + // config + maxHeight: config.autoHeight ? ctx.maxHeight.value : null, + height: config.autoHeight ? config.height : null, + rowKey: config.rowKey, + + // ctx + defaultSort: ctx.defaultSort, + data: ctx.data.value, + onRowContextmenu: ctx.onRowContextMenu, + onSelectionChange: ctx.onSelectionChange, + onSortChange: ctx.onSortChange, + + // style + size: style.size, + border: style.table.border, + highlightCurrentRow: style.table.highlightCurrentRow, + resizable: style.table.resizable, + stripe: style.table.stripe, + }, + { + default() { + return renderColumn(ctx.columns); + }, + empty() { + return renderEmpty(config.emptyText || crud.dict.label.empty); + }, + append() { + return renderAppend(); + } + } + ) + ); + }; + } +}); diff --git a/packages/crud/src/components/upsert/index.tsx b/packages/crud/src/components/upsert/index.tsx new file mode 100644 index 0000000..37c7f87 --- /dev/null +++ b/packages/crud/src/components/upsert/index.tsx @@ -0,0 +1,306 @@ +import { defineComponent, h, inject, reactive, ref, toRefs } from "vue"; +import { ElMessage } from "element-plus"; +import { useCore, useProxy } from "../../hooks"; +import { useApi } from "../form/helper"; +import { mergeConfig } from "../../utils"; + +export default defineComponent({ + name: "cl-upsert", + + props: { + // 表单项 + items: { + type: Array, + default: () => [] + }, + // 参数 + props: Object, + // 编辑时是否同步打开 + sync: Boolean, + // 操作按钮参数 + op: Object, + // 参数 + dialog: Object, + // 打开表单钩子 + onOpen: Function, + // 打开表单后钩子 + onOpened: Function, + // 关闭表单钩子 + onClose: Function, + // 关闭表单后钩子 + onClosed: Function, + // 获取表单数据钩子 + onInfo: Function, + // 表单提交钩子 + onSubmit: Function + }, + + emits: ["opened", "closed"], + + setup(props, { slots, expose }) { + const { crud } = useCore(); + + const config = reactive( + mergeConfig(props, inject("useUpsert__options") || {}) + ); + + // el-form + const Form = ref(); + + // 模式 + const mode = ref("info"); + + // 关闭表单 + function close(action?: ClForm.CloseAction) { + Form.value?.close(action); + } + + // 关闭后 + function onClosed() { + Form.value?.hideLoading(); + + if (config.onClosed) { + config.onClosed(); + } + } + + // 关闭前 + function beforeClose(action: ClForm.CloseAction, done: fn) { + function next() { + done(); + onClosed(); + } + + if (config.onClose) { + config.onClose(action, next); + } else { + next(); + } + } + + // 提交 + function submit(data: obj) { + const { service, dict, refresh } = crud; + + function done() { + Form.value?.done(); + } + + function next(data: obj) { + return new Promise((resolve, reject) => { + // 发送请求 + service[dict.api[mode.value]](data) + .then((res) => { + ElMessage.success(dict.label.saveSuccess); + done(); + close("save"); + refresh(); + resolve(res); + }) + .catch((err) => { + ElMessage.error(err.message); + done(); + reject(err); + }); + }); + } + + // 提交钩子 + if (config.onSubmit) { + config.onSubmit(data, { + done, + next, + close() { + close("save"); + } + }); + } else { + next(data); + } + } + + // 打开表单 + function open() { + // 是否禁用 + const isDisabled = mode.value == "info"; + + return new Promise((resolve) => { + if (!Form.value) { + return console.error(" is not found"); + } + + Form.value?.open( + { + title: crud.dict.label[mode.value], + props: { + ...config.props, + disabled: isDisabled + }, + op: { + ...config.op, + hidden: isDisabled + }, + dialog: config.dialog, + items: config.items || [], + on: { + open() { + if (config.onOpen) { + config.onOpen(); + } + + resolve(true); + }, + submit, + close: beforeClose + }, + form: {}, + _data: { + isDisabled + } + }, + config.plugins + ); + }); + } + + // 打开后事件 + function onOpened() { + const data = Form.value?.getForm(); + + if (config.onOpened) { + config.onOpened(data); + } + } + + // 新增 + async function add() { + mode.value = "add"; + + // 打开中 + await open(); + + // 打开后 + onOpened(); + } + + // 追加 + async function append(data: any) { + mode.value = "add"; + + // 打开中 + await open(); + + // 绑定值 + if (data) { + Form.value?.bindForm(data); + } + + // 打开后 + onOpened(); + } + + // 编辑 + function edit(data?: any) { + mode.value = "update"; + getInfo(data); + } + + // 详情 + function info(data?: any) { + mode.value = "info"; + getInfo(data); + } + + // 信息 + function getInfo(data: any) { + // 显示加载中 + Form.value?.showLoading(); + + // 是否同步打开 + if (!config.sync) { + open(); + } + + // 完成 + async function done(data?: any) { + // 加载完成 + Form.value?.hideLoading(); + + // 合并数据 + if (data) { + Form.value?.bindForm(data); + } + + // 同步打开表单 + if (config.sync) { + await open(); + } + + onOpened(); + } + + // 获取详情 + function next(data: any): Promise { + return new Promise(async (resolve, reject) => { + // 发送请求 + await crud.service[crud.dict.api.info]({ + [crud.dict.primaryId]: data[crud.dict.primaryId] + }) + .then((res) => { + done(res); + resolve(res); + }) + .catch((err) => { + ElMessage.error(err.message); + reject(err); + }); + + // 隐藏加载框 + Form.value?.hideLoading(); + }); + } + + // 详情钩子 + if (config.onInfo) { + config.onInfo(data, { + close, + next, + done + }); + } else { + next(data); + } + } + + // 完成 + function done() { + Form.value?.hideLoading(); + } + + const ctx = { + config, + ...toRefs(config), + ...useApi({ Form }), + Form, + get form() { + return Form.value?.form || {}; + }, + mode, + add, + append, + edit, + info, + open, + close, + done, + submit + }; + + useProxy(ctx); + expose(ctx); + + return () => { + return
{h(, {}, slots)}
; + }; + } +}); diff --git a/packages/crud/src/emitter.ts b/packages/crud/src/emitter.ts new file mode 100644 index 0000000..3099ff4 --- /dev/null +++ b/packages/crud/src/emitter.ts @@ -0,0 +1,27 @@ +export const crudList: ClCrud.Ref[] = []; + +export const emitter: Emitter = { + list: [], + init(events) { + for (const i in events) { + this.on(i, events[i]); + } + }, + emit(name, data) { + this.list.forEach((e: EmitterItem) => { + const [_name] = e.name.split("-"); + + if (name == _name) { + e.callback(data, { + crudList, + refresh(params) { + crudList.forEach((c) => c.refresh(params)); + } + }); + } + }); + }, + on(name, callback) { + this.list.push({ name, callback }); + } +}; diff --git a/packages/crud/src/entry.ts b/packages/crud/src/entry.ts new file mode 100644 index 0000000..07562c1 --- /dev/null +++ b/packages/crud/src/entry.ts @@ -0,0 +1,30 @@ +import { type App } from "vue"; +import { useComponent } from "./components"; +import { useProvide } from "./provide"; +import global from "./utils/global"; +import "./static/index.scss"; + +const Crud = { + install(app: App, options?: any) { + global.set("__CrudApp__", app); + + // 穿透值 + useProvide(app, options); + + // 设置组件 + useComponent(app); + + return { + name: "cl-crud" + }; + } +}; + +export { Crud }; + +export * from "./emitter"; +export * from "./hooks"; +export * from "./locale"; +export { registerFormHook } from "./utils/form-hook"; +export { renderNode } from "./utils/vnode"; +export { ContextMenu } from "./components/context-menu"; diff --git a/packages/crud/src/hooks/crud.ts b/packages/crud/src/hooks/crud.ts new file mode 100644 index 0000000..5570134 --- /dev/null +++ b/packages/crud/src/hooks/crud.ts @@ -0,0 +1,191 @@ +import { assign } from "lodash-es"; +import { TestService } from "../test/service"; +import { watch, ref, nextTick, getCurrentInstance, type Ref, inject, provide } from "vue"; + +// 获取上级 +function useParent(name: string, r: Ref) { + const d = getCurrentInstance(); + + if (d) { + let parent = d.proxy?.$.parent; + + if (parent) { + while (parent && parent.type?.name != name && parent.type?.name != "cl-crud") { + parent = parent?.parent; + } + + if (parent) { + if (parent.type.name == name) { + r.value = parent.exposed; + } + } + } + } +} + +// 多事件 +function useEvent( + names: string[], + { r, options, clear, isChild }: { r: any; options: any; clear?: string; isChild?: boolean } +) { + if (!r.__ev) r.__ev = {}; + + const d: { [key: string]: (args: any[]) => void } = {}; + const ev = r.__ev as { [key: string]: { fn: any; isChild?: boolean }[] }; + + names.forEach((k) => { + if (!ev[k]) ev[k] = []; + + if (options[k]) { + ev[k].push({ + fn: options[k], + isChild + }); + } + + d[k] = (...args: any[]) => { + ev[k].forEach((e) => { + if (e.fn) { + e.fn(...args); + } + }); + + if (clear == k) { + for (const i in ev) { + ev[i] = ev[i].filter((e) => !e.isChild); + } + } + }; + }); + + return d; +} + +// crud +export function useCrud(options?: ClCrud.Options, cb?: (app: ClCrud.Ref) => void) { + const Crud = ref(); + useParent("cl-crud", Crud); + + if (options) { + // 测试模式 + if (options.service == "test") { + options.service = new TestService(); + } + + provide("useCrud__options", options); + } + + watch(Crud, (val) => { + if (val) { + if (cb) { + cb(val); + } + } + }); + + return Crud; +} + +// 新增、编辑 +export function useUpsert(options?: ClUpsert.Options) { + const Upsert = ref(); + useParent("cl-upsert", Upsert); + const isChild = !!Upsert.value; + + if (options) { + provide("useUpsert__options", options); + } + + watch( + Upsert, + (val) => { + if (val) { + if (options) { + const event = useEvent(["onOpen", "onOpened", "onClosed"], { + r: val, + options, + clear: "onClosed", + isChild + }); + + assign(val.config, event); + } + } + }, + { + immediate: true + } + ); + + return Upsert; +} + +// 表格 +export function useTable(options?: ClTable.Options, cb?: (table: ClTable.Ref) => void) { + const Table = ref>(); + useParent("cl-table", Table); + + if (options) { + provide("useTable__options", options); + } + + watch(Table, (val) => { + if (val) { + if (cb) { + cb(val); + } + } + }); + + return Table; +} + +// 表单 +export function useForm(cb?: (app: ClForm.Ref) => void) { + const Form = ref>(); + useParent("cl-form", Form); + + nextTick(() => { + if (cb && Form.value) { + cb(Form.value); + } + }); + + return Form; +} + +// 高级搜索 +export function useAdvSearch(options?: ClAdvSearch.Options) { + const AdvSearch = ref>(); + useParent("cl-adv-search", AdvSearch); + + if (options) { + provide("useAdvSearch__options", options); + } + + return AdvSearch; +} + +// 搜索 +export function useSearch(options?: ClSearch.Options) { + const Search = ref>(); + useParent("cl-search", Search); + + provide("useSearch__options", options); + + return Search; +} + +// 对话框 +export function useDialog(options?: { onFullscreen(visible: boolean): void }) { + const Dialog = inject("dialog") as ClDialog.Provide; + + watch( + () => Dialog?.fullscreen.value, + (val) => { + options?.onFullscreen(val); + } + ); + + return Dialog; +} diff --git a/packages/crud/src/hooks/index.ts b/packages/crud/src/hooks/index.ts new file mode 100644 index 0000000..14fd596 --- /dev/null +++ b/packages/crud/src/hooks/index.ts @@ -0,0 +1,74 @@ +import { Mitt } from "../utils/mitt"; +import { isFunction } from "lodash-es"; +import { getCurrentInstance, inject, reactive } from "vue"; + +export function useCore() { + const crud = inject("crud") as ClCrud.Ref; + const mitt = inject("mitt") as Mitt; + + return { + crud, + mitt + }; +} + +export function useConfig() { + return inject("__config__") as Config; +} + +export function useBrowser() { + return inject("__browser__") as Browser; +} + +export function useRefs() { + const refs = reactive<{ [key: string]: obj }>({}); + + function setRefs(name: string) { + return (el: any) => { + refs[name] = el; + }; + } + + return { refs, setRefs }; +} + +export function useProxy(ctx: any) { + const { type }: any = getCurrentInstance(); + const { mitt, crud } = useCore(); + + // 挂载 + crud[type.name] = ctx; + + // 事件 + mitt.on("crud.proxy", ({ name, data = [], callback }: any) => { + if (ctx[name]) { + let d = null; + + if (isFunction(ctx[name])) { + d = ctx[name](...data); + } else { + d = ctx[name]; + } + + if (callback) { + callback(d); + } + } + }); + + return ctx; +} + +export function useElApi(keys: string[], el: any) { + const apis: obj = {}; + + keys.forEach((e) => { + apis[e] = (...args: any[]) => { + return el.value[e](...args); + }; + }); + + return apis; +} + +export * from "./crud"; diff --git a/packages/crud/src/index.ts b/packages/crud/src/index.ts new file mode 100644 index 0000000..363490f --- /dev/null +++ b/packages/crud/src/index.ts @@ -0,0 +1 @@ +export * from "./entry"; diff --git a/packages/crud/src/locale/en.ts b/packages/crud/src/locale/en.ts new file mode 100644 index 0000000..0de015e --- /dev/null +++ b/packages/crud/src/locale/en.ts @@ -0,0 +1,33 @@ +export default { + op: "Operation", + add: "Add", + delete: "Delete", + multiDelete: "Delete", + update: "Edit", + refresh: "Refresh", + info: "Details", + search: "Search", + reset: "Reset", + clear: "Clear", + save: "Save", + close: "Cancel", + confirm: "Confirm", + advSearch: "Advanced Search", + searchKey: "Search Keyword", + placeholder: "Please enter", + tips: "Tips", + saveSuccess: "Save successful", + deleteSuccess: "Delete successful", + deleteConfirm: + "This operation will permanently delete the selected data. Do you want to continue?", + empty: "No data available", + desc: "Descending", + asc: "Ascending", + select: "Select", + deselect: "Deselect", + seeMore: "See more", + hideContent: "Hide content", + nonEmpty: "{label} cannot be empty", + collapse: "Collapse", + expand: "Expand" +}; diff --git a/packages/crud/src/locale/index.ts b/packages/crud/src/locale/index.ts new file mode 100644 index 0000000..087df5e --- /dev/null +++ b/packages/crud/src/locale/index.ts @@ -0,0 +1,11 @@ +import en from "./en"; +import ja from "./ja"; +import zhCn from "./zh-cn"; +import zhTw from "./zh-tw"; + +export const locale = { + en, + ja, + "zh-cn": zhCn, + "zh-tw": zhTw +}; diff --git a/packages/crud/src/locale/ja.ts b/packages/crud/src/locale/ja.ts new file mode 100644 index 0000000..9d67240 --- /dev/null +++ b/packages/crud/src/locale/ja.ts @@ -0,0 +1,32 @@ +export default { + op: "操作", + add: "追加", + delete: "削除", + multiDelete: "削除", + update: "編集", + refresh: "リフレッシュ", + info: "詳細", + search: "検索", + reset: "リセット", + clear: "クリア", + save: "保存", + close: "キャンセル", + confirm: "確認", + advSearch: "高度な検索", + searchKey: "検索キーワード", + placeholder: "入力してください", + tips: "ヒント", + saveSuccess: "保存が成功しました", + deleteSuccess: "削除が成功しました", + deleteConfirm: "この操作は選択したデータを永久に削除します。続行しますか?", + empty: "データがありません", + desc: "降順", + asc: "昇順", + select: "選択", + deselect: "選択解除", + seeMore: "詳細を表示", + hideContent: "コンテンツを非表示", + nonEmpty: "{label}は空にできません", + collapse: "折り畳む", + expand: "展開" +}; diff --git a/packages/crud/src/locale/zh-cn.ts b/packages/crud/src/locale/zh-cn.ts new file mode 100644 index 0000000..69d9e7d --- /dev/null +++ b/packages/crud/src/locale/zh-cn.ts @@ -0,0 +1,32 @@ +export default { + op: "操作", + add: "新增", + delete: "删除", + multiDelete: "删除", + update: "编辑", + refresh: "刷新", + info: "详情", + search: "搜索", + reset: "重置", + clear: "清空", + save: "保存", + close: "取消", + confirm: "确定", + advSearch: "高级搜索", + searchKey: "搜索关键字", + placeholder: "请输入", + tips: "提示", + saveSuccess: "保存成功", + deleteSuccess: "删除成功", + deleteConfirm: "此操作将永久删除选中数据,是否继续?", + empty: "暂无数据", + desc: "降序", + asc: "升序", + select: "选择", + deselect: "取消选择", + seeMore: "查看更多", + hideContent: "隐藏内容", + nonEmpty: "{label}不能为空", + collapse: "收起", + expand: "展开更多" +}; diff --git a/packages/crud/src/locale/zh-tw.ts b/packages/crud/src/locale/zh-tw.ts new file mode 100644 index 0000000..dbd83e8 --- /dev/null +++ b/packages/crud/src/locale/zh-tw.ts @@ -0,0 +1,32 @@ +export default { + op: "操作", + add: "新增", + delete: "刪除", + multiDelete: "刪除", + update: "編輯", + refresh: "刷新", + info: "詳情", + search: "搜尋", + reset: "重置", + clear: "清空", + save: "保存", + close: "取消", + confirm: "確定", + advSearch: "高級搜索", + searchKey: "搜索關鍵字", + placeholder: "請輸入", + tips: "提示", + saveSuccess: "保存成功", + deleteSuccess: "刪除成功", + deleteConfirm: "此操作將永久刪除選中數據,是否繼續?", + empty: "暫無數據", + desc: "降序", + asc: "升序", + select: "選擇", + deselect: "取消選擇", + seeMore: "查看更多", + hideContent: "隱藏內容", + nonEmpty: "{label}不能為空", + collapse: "收起", + expand: "展開" +}; diff --git a/packages/crud/src/main.ts b/packages/crud/src/main.ts new file mode 100644 index 0000000..e667063 --- /dev/null +++ b/packages/crud/src/main.ts @@ -0,0 +1,28 @@ +import { createApp } from "vue"; +import App from "./App.vue"; +import { Crud, locale } from "./entry"; +// import Crud, { locale } from "../dist/index.umd"; +// import "../dist/index.css"; + +import ElementPlus from "element-plus"; +import "element-plus/dist/index.css"; + +const app = createApp(App); + +app.use(ElementPlus) + .use(Crud, { + dict: { + sort: { + prop: "order", + order: "sort" + }, + label: locale["zh-cn"] + }, + style: { + // size: "default" + }, + render: { + autoHeight: true + } + }) + .mount("#app"); diff --git a/packages/crud/src/provide.ts b/packages/crud/src/provide.ts new file mode 100644 index 0000000..0248bff --- /dev/null +++ b/packages/crud/src/provide.ts @@ -0,0 +1,129 @@ +import { type App, reactive } from "vue"; +import { mitt } from "./utils/mitt"; +import { emitter } from "./emitter"; +import { locale } from "./locale"; +import { merge } from "./utils"; + +// 设置配置 +function setConfig(app: App, options: Options = {}) { + const config = merge( + { + permission: { + update: true, + page: true, + info: true, + list: true, + add: true, + delete: true + }, + dict: { + primaryId: "id", + api: { + list: "list", + add: "add", + update: "update", + delete: "delete", + info: "info", + page: "page" + }, + pagination: { + page: "page", + size: "size" + }, + search: { + keyWord: "keyWord", + query: "query" + }, + sort: { + order: "order", + prop: "prop" + }, + label: locale["zh-cn"] + }, + style: { + colors: [ + "#d42ca8", + "#1c109d", + "#6d17c3", + "#6dc9f1", + "#04c273", + "#06b31c", + "#f9f494", + "#aa7a24", + "#d57121", + "#e93f4d" + ], + form: { + labelPostion: "right", + labelWidth: "100px", + span: 24 + }, + table: { + border: true, + highlightCurrentRow: true, + autoHeight: true, + contextMenu: ["refresh", "check", "edit", "delete", "order-asc", "order-desc"], + column: { + align: "center", + opWidth: 180 + } + } + }, + events: {} + } as Options, + options + ); + + // 初始化事件 + if (config.events) { + emitter.init(config.events); + } + + app.provide("__config__", config); + + return config; +} + +// 设置浏览器 +function setBrowser(app: App) { + // 浏览器信息 + const browser = reactive({ + isMini: false, + screen: "full" + }); + + // 更新信息 + function update() { + const w = document.body.clientWidth; + + if (w < 768) { + browser.screen = "xs"; + } else if (w < 992) { + browser.screen = "sm"; + } else if (w < 1200) { + browser.screen = "md"; + } else if (w < 1920) { + browser.screen = "xl"; + } else { + browser.screen = "full"; + } + + browser.isMini = browser.screen === "xs"; + } + + // 监听浏览器窗口变化 + window.addEventListener("resize", () => { + update(); + + // 事件 + mitt.emit("resize"); + }); + + update(); + app.provide("__browser__", browser); +} + +export function useProvide(app: App, options: Options = {}) { + setBrowser(app); + setConfig(app, options); +} diff --git a/packages/crud/src/static/index.scss b/packages/crud/src/static/index.scss new file mode 100644 index 0000000..1b7ee65 --- /dev/null +++ b/packages/crud/src/static/index.scss @@ -0,0 +1,862 @@ +.cl-crud { + height: 100%; + overflow: hidden auto; + position: relative; + box-sizing: border-box; + background-color: #fff; + + &.is-border { + border: 1px solid var(--el-border-color); + border-radius: var(--el-border-radius-base); + } + + & > .cl-row { + width: 100%; + + &:not(.cl-row--last) > * { + margin: 0 10px 10px 0; + + &:last-child { + margin-right: 0; + } + } + + .cl-flex1 { + margin-right: 0; + } + } +} + +.cl-flex1 { + flex: 1; + font-size: 12px; +} + +.cl-search-key { + display: inline-flex; + + &__select { + margin-right: 10px; + + &.el-select { + width: 100px; + } + } + + &__wrap { + display: inline-flex; + + .el-input { + flex: 1; + } + + .el-button { + margin-left: 10px; + } + } +} + +.cl-table { + width: 100%; + + .el-table { + &.el-loading-parent--relative { + box-sizing: border-box; + } + + &__header { + .el-table__cell { + background-color: var(--el-fill-color-lighter) !important; + color: var(--el-text-color-primary); + + .cell { + line-height: normal; + } + + &.is-sortable { + .cl-table-header__search { + width: auto; + + &.is-input { + width: calc(100% - 24px) !important; + } + } + } + } + } + + &__empty-block { + height: auto !important; + } + } + + .el-loading-mask { + .el-loading-spinner { + .el-icon-loading { + font-size: 25px; + color: #000; + } + + .el-loading-text { + color: var(--el-text-color-secondary); + margin-top: 5px; + } + } + } + + &__op { + margin-bottom: -5px; + + .el-button { + margin-bottom: 5px; + outline-offset: -2px !important; + + &.is-text { + border: 1px solid var(--el-button-border-color) !important; + + &:hover { + background-color: var(--el-button-bg-color) !important; + } + } + } + } + + .cl-table-header__search { + display: inline-flex; + align-items: center; + gap: 5px; + width: 100%; + cursor: pointer; + + &-label { + display: flex; + align-items: center; + justify-content: center; + gap: 5px; + } + + &:hover { + color: var(--el-color-primary); + } + + &-inner { + flex: 1; + + & > div { + width: 100%; + + .el-date-editor { + margin-right: 0; + } + } + } + + &-close { + font-size: 14px; + height: 30px; + width: 30px; + border: 1px solid var(--el-border-color); + border-radius: 6px; + background-color: var(--el-fill-color-blank); + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; + color: var(--el-text-color-secondary); + + &:hover { + border-color: var(--el-border-color-hover); + color: var(--el-text-color-primary); + } + } + } + + .is-left { + .cl-table-header__search-label { + justify-content: flex-start; + } + } + + .is-right { + .cl-table-header__search-label { + justify-content: flex-end; + } + } +} + +.cl-pagination { + &.el-pagination { + --el-pagination-border-radius: var(--el-border-radius-base); + } + + .btn-prev, + .btn-next, + .el-pager li { + border-radius: var(--el-border-radius-base); + } +} + +.cl-filter { + display: flex; + align-items: center; + margin: 0 10px; + + &__label { + font-size: 12px; + margin-right: 10px; + white-space: nowrap; + } + + .el-select { + min-width: 120px; + } +} + +.cl-search { + &__btns { + margin-left: 5px; + } + + &__more { + display: flex; + align-items: center; + justify-content: space-between; + + .el-form-item { + margin-bottom: 0; + } + } + + .el-form:not(.el-form--label-top) { + .el-form-item__label { + &:empty { + display: none; + } + } + + .cl-search__btns { + .el-form-item__label { + display: none; + } + } + } + + .cl-search__btns { + .el-button + .el-button { + margin-left: 10px; + } + } + + &.is-inline { + margin-bottom: 0 !important; + } + + &.is-collapse { + background-color: var(--el-fill-color-lighter); + padding: 10px; + margin-bottom: 10px !important; + border-radius: 6px; + border: 1px solid var(--el-border-color-extra-light); + + &.is-fold { + .cl-search__form { + max-height: 42px; + overflow: hidden; + + &:has(.el-form--label-top) { + max-height: 68px; + } + } + } + } +} + +.cl-adv-btn { + margin-left: 10px; + + .el-icon { + margin-right: 5px; + } +} + +.cl-adv-search { + &.el-drawer { + background-color: #fff; + } + + .el-drawer__body { + padding: 0; + } + + &__header { + display: flex; + align-items: center; + justify-content: space-between; + height: 50px; + padding: 0 15px 0 20px; + user-select: none; + + .text { + font-size: 16px; + } + + .el-icon { + cursor: pointer; + + &:hover { + color: red; + } + } + } + + &__container { + height: calc(100% - 110px); + overflow-y: auto; + padding: 10px 20px; + box-sizing: border-box; + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + border-radius: 6px; + background-color: rgba(144, 147, 153, 0.3); + } + + .el-form-item__content { + & > div { + width: 100%; + } + } + } + + &__footer { + display: flex; + align-items: center; + justify-content: flex-end; + height: 60px; + border-top: 1px solid var(--el-border-color-extra-light); + padding: 0 10px; + box-sizing: border-box; + } +} + +.cl-form { + [class*="el-col-"].is-guttered { + min-height: 0; + } + + &-item { + display: flex; + + &__component { + display: flex; + + &.flex1 { + flex: 1; + width: 100%; + + & > div { + width: 100%; + } + } + } + + &__prepend { + margin-right: 10px; + } + + &__append { + margin-left: 10px; + } + + &__collapse { + width: 100%; + font-size: 12px; + cursor: pointer; + + .el-divider { + margin: 16px 0; + + &__text { + font-size: 12px; + } + } + + i { + margin-left: 6px; + } + } + + .el-table__header tr { + line-height: normal; + } + } + + &__footer { + display: flex; + justify-content: flex-end; + } + + .cl-crud { + line-height: normal; + } + + .el-form { + .el-form-item { + .el-form-item { + margin-bottom: 18px; + } + + .el-input-number { + &__decrease, + &__increase { + border: 0; + background-color: transparent; + } + } + + &__label { + .el-tooltip { + i { + margin-left: 5px; + } + } + } + + &__content { + min-width: 0px; + + & > div { + width: 100%; + } + } + } + + &:not(.el-form--label-top) { + .el-form-item { + &.no-label { + & > .el-form-item__label { + padding: 0; + display: none; + } + } + } + } + + &.el-form--label-top { + .el-form-item { + margin-bottom: 22px; + } + + .el-form-item__label { + margin: 0 0 4px 0; + min-height: 22px; + } + + .el-form-item__error { + padding-top: 4px; + } + } + + &.el-form--inline { + .cl-form__items { + display: flex; + flex-wrap: wrap; + } + + .el-form-item { + margin: 0 10px 10px 0; + + .el-date-editor { + box-sizing: border-box; + + .el-range-input { + &:nth-child(2) { + margin-left: 5px; + } + } + } + + .el-select { + width: 173px; + } + + &:last-child { + margin-right: 0; + } + } + } + } +} + +.cl-form-tabs { + border-bottom: 1px solid var(--el-border-color); + overflow: hidden; + width: calc(100% - 10px); + margin: 0 5px 20px 5px; + + &__wrap { + height: 35px; + width: 100%; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; + -ms-overflow-style: none; + position: relative; + + &::-webkit-scrollbar { + display: none; + } + } + + ul { + display: inline-flex; + white-space: nowrap; + margin: 0; + padding: 0; + + li { + display: inline-flex; + align-items: center; + list-style: none; + padding: 0 20px; + height: 35px; + cursor: pointer; + + .el-icon { + margin-right: 5px; + font-size: 16px; + } + + &.is-active { + color: var(--el-color-primary); + } + } + } + + &__line { + height: 3px; + width: 100%; + position: absolute; + bottom: -1px; + left: 0; + transition: + transform 0.3s ease-in-out, + width 0.2s 0.1s cubic-bezier(0.645, 0.045, 0.355, 1); + background-color: var(--el-color-primary); + } + + &--card { + .cl-form-tabs__line { + display: none; + } + + ul { + border: 1px solid var(--el-border-color); + border-top-left-radius: 5px; + border-top-right-radius: 5px; + + li { + border-left: 1px solid var(--el-border-color); + + &:first-child { + border-left-width: 0; + } + } + } + } +} + +.cl-form-card { + margin-top: 0; + + &__header { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 14px; + height: 32px; + line-height: normal; + font-weight: bold; + padding: 0 10px; + background-color: var(--el-fill-color-lighter); + border-radius: var(--el-border-radius-base); + cursor: pointer; + user-select: none; + + &:hover { + background-color: var(--el-fill-color-light); + } + } + + &__container { + transition: all 0.3s; + display: grid; + grid-template-rows: 0fr; + + > .cl-form-item__children { + min-height: 0; + overflow: hidden; + + .el-row { + margin-top: 10px; + } + } + } + + &.is-expand { + > .cl-form-card__container { + grid-template-rows: 1fr; + margin-bottom: -18px; + } + } + + .cl-form-card { + margin-left: 10px; + } +} + +.cl-dialog { + display: flex; + flex-direction: column; + + &.el-dialog { + padding: 0; + border-radius: 8px; + } + + .el-dialog { + &__header { + padding: 0; + margin-right: 0; + + &-slot { + &.is-drag { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + -khtml-user-select: none; + user-select: none; + cursor: move; + } + } + } + + &__body { + padding: 0; + box-sizing: border-box; + flex: 1; + overflow: hidden; + } + + &__footer { + padding: 0; + } + } + + &__header { + position: relative; + padding: 10px; + border-bottom: 1px solid var(--el-border-color-extra-light); + text-align: center; + user-select: none; + } + + &__default { + box-sizing: border-box; + } + + &__footer { + border-top: 1px solid var(--el-border-color-extra-light); + padding: 20px; + } + + &__title { + display: block; + font-size: 15px; + letter-spacing: 0.5px; + } + + &__controls { + display: flex; + justify-content: flex-end; + position: absolute; + right: 8px; + top: 8px; + z-index: 9; + width: 100%; + + &-icon, + .minimize, + .maximize, + .close { + display: flex; + align-items: center; + justify-content: center; + height: 28px; + width: 28px; + border: 0; + background-color: transparent; + cursor: pointer; + outline: none; + border-radius: 6px; + margin-left: 5px; + + i { + font-size: 18px; + } + + &:hover { + background-color: var(--el-fill-color-darker); + } + } + } + + &.hidden-header { + .el-dialog__header { + display: none; + } + } + + &.is-fullscreen { + height: 100vh !important; + border-radius: 0; + overflow: hidden; + + .cl-dialog__container { + height: 100% !important; + } + } + + &.is-transparent { + background-color: transparent !important; + } +} + +.cl-context-menu { + position: absolute; + z-index: 9999; + + &__box { + width: 160px; + background-color: var(--el-bg-color); + border: 1px solid var(--el-border-color-extra-light); + box-shadow: + 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -2px rgba(0, 0, 0, 0.1); + border-radius: 6px; + position: absolute; + top: 0; + padding: 5px; + + &.is-append { + right: calc(-100% - 5px); + top: -5px; + } + + & > div { + display: flex; + align-items: center; + font-size: 12px; + cursor: pointer; + padding: 5px 15px; + color: var(--el-text-color-primary); + position: relative; + border-radius: 4px; + + span { + flex: 1; + user-select: none; + } + + &:hover { + background-color: var(--el-fill-color-lighter); + } + + i { + &:first-child { + margin-right: 5px; + } + + &:last-child { + margin-left: 5px; + } + } + + &.is-active { + background-color: #f7f7f7; + color: #000; + } + + &.is-ellipsis { + span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + &.is-disabled { + span { + color: #ccc; + + &:hover { + color: #ccc; + } + } + } + } + } + + &__target { + position: relative; + + &::after { + content: ""; + display: block; + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 100%; + background-color: rgba(0, 0, 0, 0.05); + } + } +} + +@media only screen and (max-width: 768px) { + .el-table { + &__body { + &-wrapper { + &::-webkit-scrollbar { + height: 6px; + width: 6px; + } + } + } + } + + .cl-search-key { + width: 100%; + margin-right: 0 !important; + + &__wrap { + width: 100% !important; + } + } +} + +.cl-error-message { + display: flex; + align-items: center; + height: 32px; + padding: 0 10px; + font-size: 14px; + color: var(--el-color-danger); + border: 1px solid var(--el-color-danger); + border-radius: 4px; + box-sizing: border-box; + user-select: none; +} diff --git a/packages/crud/src/test/service.ts b/packages/crud/src/test/service.ts new file mode 100644 index 0000000..90e8f8a --- /dev/null +++ b/packages/crud/src/test/service.ts @@ -0,0 +1,231 @@ +import { assign, orderBy } from "lodash-es"; +import { uuid } from "../utils"; + +const userList = [ + { + id: 1, + name: "楚行云", + createTime: "1996-09-14", + wages: 73026, + status: 1, + account: "chuxingyun", + occupation: 4, + phone: 13797353874 + }, + { + id: 2, + name: "秦尘", + createTime: "1977-11-09", + wages: 74520, + status: 0, + account: "qincheng", + occupation: 3, + phone: 18593911044 + }, + { + id: 3, + name: "叶凡", + createTime: "1982-11-28", + wages: 81420, + status: 0, + account: "yefan", + occupation: 1, + phone: 16234136338 + }, + { + id: 4, + name: "白小纯", + createTime: "2012-12-17", + wages: 65197, + status: 1, + account: "baixiaochun", + occupation: 2, + phone: 16325661110 + }, + { + id: 5, + name: "韩立", + createTime: "1982-07-10", + wages: 99107, + status: 1, + account: "hanli", + occupation: 2, + phone: 18486594866 + }, + { + id: 6, + name: "唐三", + createTime: "2019-07-31", + wages: 80658, + status: 1, + account: "tangsan", + occupation: 5, + phone: 15565014642 + }, + { + id: 7, + name: "王林", + createTime: "2009-07-26", + wages: 57408, + status: 1, + account: "wanglin", + occupation: 1, + phone: 13852767084 + }, + { + id: 8, + name: "李强", + createTime: "2016-04-26", + wages: 71782, + status: 1, + account: "liqiang", + occupation: 3, + phone: 18365332834 + }, + { + id: 9, + name: "秦羽", + createTime: "1984-01-18", + wages: 87860, + status: 1, + account: "qinyu", + occupation: 0, + phone: 18149247129 + } +]; + +class TestService { + // 分页列表 + async page(params: any) { + const { keyWord, page, size, sort, order } = params || {}; + + // 关键字查询 + const keyWordLikeFields = ["phone", "name"]; + + // 等值查询 + const fieldEq = ["createTime", "occupation", "status"]; + + // 模糊查询 + const likeFields = ["phone", "name"]; + + // 过滤后的列表 + const list = orderBy(userList, order, sort).filter((e: any) => { + let f = true; + + if (keyWord !== undefined) { + f = !!keyWordLikeFields.find((k) => String(e[k]).includes(String(params.keyWord))); + } + + fieldEq.forEach((k) => { + if (f) { + if (params[k] !== undefined) { + f = e[k] == params[k]; + } + } + }); + + likeFields.forEach((k) => { + if (f) { + if (params[k] !== undefined) { + f = String(e[k]).includes(String(params[k])); + } + } + }); + + return f; + }); + + return new Promise((resolve) => { + // 模拟延迟 + setTimeout(() => { + resolve({ + list: list.slice((page - 1) * size, page * size), + pagination: { + total: list.length, + page, + size + }, + subData: { + wages: list.reduce((a, b) => { + return a + b.wages; + }, 0) + } + }); + }, 500); + }); + } + + // 更新 + async update(params: { id: any; [key: string]: any }) { + const item = userList.find((e) => e.id == params.id); + + if (item) { + assign(item, params); + } + } + + // 新增 + async add(params: any) { + const id = uuid(); + + userList.push({ + id, + ...params + }); + + return id; + } + + // 详情 + async info(params: { id: any }) { + const { id } = params || {}; + return userList.find((e) => e.id == id); + } + + // 删除 + async delete(params: { ids: any[] }) { + const { ids = [] } = params || {}; + + ids.forEach((id) => { + const index = userList.findIndex((e) => e.id == id); + userList.splice(index, 1); + }); + } + + // 全部列表 + async list() { + return userList; + } + + search = { + fieldEq: [ + { + propertyName: "occupation", + comment: "工作", + source: "a.occupation" + } + ], + fieldLike: [ + { + propertyName: "status", + comment: "状态", + dict: ["关闭", "开启"], + source: "a.status" + } + ], + keyWordLikeFields: [ + { + propertyName: "name", + comment: "姓名", + source: "a.name" + }, + { + propertyName: "phone", + comment: "手机号", + source: "a.phone" + } + ] + }; +} + +export { TestService }; diff --git a/packages/crud/src/utils/form-hook.ts b/packages/crud/src/utils/form-hook.ts new file mode 100644 index 0000000..df30051 --- /dev/null +++ b/packages/crud/src/utils/form-hook.ts @@ -0,0 +1,149 @@ +import { isArray, isEmpty, isFunction, isObject, isString } from "lodash-es"; + +export const format: { [key: string]: ClForm.Hook["Fn"] } = { + number(value) { + return value ? (isArray(value) ? value.map(Number) : Number(value)) : value; + }, + string(value) { + return value ? (isArray(value) ? value.map(String) : String(value)) : value; + }, + split(value) { + if (isString(value)) { + return value.split(",").filter(Boolean); + } else if (isArray(value)) { + return value; + } else { + return []; + } + }, + join(value) { + return isArray(value) ? value.join(",") : value; + }, + boolean(value) { + return Boolean(value); + }, + booleanNumber(value) { + return value ? 1 : 0; + }, + datetimeRange(value, { form, method, prop }) { + const key = prop.charAt(0).toUpperCase() + prop.slice(1); + + const start = `start${key}`; + const end = `end${key}`; + + if (method == "bind") { + return [form[start], form[end]]; + } else { + const [startTime, endTime] = value || []; + form[start] = startTime; + form[end] = endTime; + return undefined; + } + }, + splitJoin(value, { method }) { + if (method == "bind") { + return isString(value) ? value.split(",").filter(Boolean) : value; + } else { + return isArray(value) ? value.join(",") : value; + } + }, + json(value, { method }) { + if (method == "bind") { + try { + return JSON.parse(value); + } catch (e) { + return {}; + } + } else { + return JSON.stringify(value); + } + }, + empty(value) { + if (isString(value)) { + return value === "" ? undefined : value; + } + + if (isArray(value)) { + return isEmpty(value) ? undefined : value; + } + + return value; + } +}; + +function init({ value, form, prop }: any) { + if (prop) { + const [a, b] = prop.split("-"); + if (b) { + form[prop] = form[a] ? form[a][b] : form[a]; + } else { + form[prop] = value; + } + } +} + +function parse(method: "submit" | "bind", { value, hook: pipe, form, prop }: any) { + init({ value, method, form, prop }); + + if (!pipe) { + return false; + } + + let pipes: any[] = []; + + if (isString(pipe)) { + if (format[pipe]) { + pipes = [pipe]; + } else { + console.error(`[hook] ${pipe} is not found`); + } + } else if (isArray(pipe)) { + pipes = pipe; + } else if (isObject(pipe)) { + pipes = isArray(pipe[method]) ? pipe[method] : [pipe[method]]; + } else if (isFunction(pipe)) { + pipes = [pipe]; + } else { + console.error(`[hook] ${pipe} format error`); + } + + let v = value; + + pipes.forEach((e) => { + let f: any = null; + + if (isString(e)) { + f = format[e]; + } else if (isFunction(e)) { + f = e; + } + + if (f) { + v = f(v, { + method, + form, + prop + }); + } + }); + + if (prop) { + form[prop] = v; + } +} + +const formHook = { + bind(data: any) { + parse("bind", data); + }, + + submit(data: any) { + parse("submit", data); + } +}; + +export function registerFormHook(name: string, fn: ClForm.Hook["Fn"]) { + format[name] = fn; +} + +export default formHook; diff --git a/packages/crud/src/utils/global.ts b/packages/crud/src/utils/global.ts new file mode 100644 index 0000000..83b7b0b --- /dev/null +++ b/packages/crud/src/utils/global.ts @@ -0,0 +1,16 @@ +// @ts-nocheck +import { type App } from "vue"; + +export default { + get vue(): App { + return window.__CrudApp__; + }, + + get(key: string) { + return window[key]; + }, + + set(key: string, value: any) { + window[key] = value; + } +}; diff --git a/packages/crud/src/utils/index.ts b/packages/crud/src/utils/index.ts new file mode 100644 index 0000000..05ae097 --- /dev/null +++ b/packages/crud/src/utils/index.ts @@ -0,0 +1,164 @@ +import { isRef, mergeProps, toValue } from "vue"; +import { assign, flatMap, isArray, isFunction, isNumber, mergeWith } from "lodash-es"; + +// 是否对象 +export function isObject(val: any) { + return val !== null && typeof val === "object"; +} + +// 解析px +export function parsePx(val: string | number) { + return isNumber(val) ? `${val}px` : val; +} + +// 数据设置 +export function dataset(obj: any, key: string, value: any): any { + const isGet = value === undefined; + let d = obj; + + const arr = flatMap( + key.split(".").map((e) => { + if (e.includes("[")) { + return e.split("[").map((e) => e.replace(/"/g, "")); + } else { + return e; + } + }) + ); + + try { + for (let i = 0; i < arr.length; i++) { + const e: any = arr[i]; + let n: any = null; + + if (e.includes("]")) { + const [k, v] = e.replace("]", "").split(":"); + + if (v) { + n = d.findIndex((x: any) => x[k] == v); + } else { + n = Number(k); + } + } else { + n = e; + } + + if (i != arr.length - 1) { + d = d[n]; + } else { + if (isGet) { + return d[n]; + } else { + if (isObject(value)) { + assign(d[n], value); + } else { + d[n] = value; + } + } + } + } + + return obj; + } catch (e) { + console.error("[dataset] format error", `${key}`); + return {}; + } +} + +// 元素是否包含 +export function contains(parent: any, node: any) { + return parent !== node && parent && parent.contains(node); +} + +// 合并配置 +export function mergeConfig(a: any, b?: any): any { + return b ? mergeProps(a, b) : a; +} + +// 合并数据 +export function merge(d1: any, d2: any) { + return mergeWith(d1, d2, (_, b) => { + if (isArray(b)) { + return b; + } + }); +} + +// 添加元素 +export function addClass(el: Element, name: string) { + if (el?.classList) { + el.classList.add(name); + } +} + +// 移除元素 +export function removeClass(el: Element, name: string) { + if (el?.classList) { + el.classList.remove(name); + } +} + +// 获取值 +export function getValue(value: T | Vue.Ref | ((d: any) => T), data?: any): T { + if (isRef(value)) { + return toValue(value) as T; + } else { + if (isFunction(value)) { + return value(data); + } else { + return value as T; + } + } +} + +// 深度查找 +export function deepFind(value: any, list: any[], options?: { allLevels: boolean }) { + const { allLevels = true } = options || {}; + + function deep(arr: DictOptions, name: string[]): any | undefined { + for (const e of arr) { + if (e.value === value) { + if (allLevels) { + return { + ...e, + label: [...name, e.label].join(" / ") + }; + } else { + return e; + } + } else if (e.children) { + const d = deep(e.children, [...name!, e.label!]); + + if (d !== undefined) { + return d; + } + } + } + return undefined; + } + + return deep(list, []); +} + +// uuid +export function uuid(separator = "-"): string { + const s: any[] = []; + const hexDigits = "0123456789abcdef"; + for (let i = 0; i < 36; i++) { + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); + } + s[14] = "4"; + s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); + s[8] = s[13] = s[18] = s[23] = separator; + + return s.join(""); +} + +// 移除相同的方法 +export function uniqueFns(fns: any[]) { + const arr = new Map(); + fns.forEach((fn) => { + arr.set(fn.name, fn); + }); + return Array.from(arr.values()); +} diff --git a/packages/crud/src/utils/mitt.ts b/packages/crud/src/utils/mitt.ts new file mode 100644 index 0000000..b79cedb --- /dev/null +++ b/packages/crud/src/utils/mitt.ts @@ -0,0 +1,30 @@ +import _mitt from "mitt"; + +const mitt = _mitt(); + +class Mitt { + id: number; + + constructor(id?: number) { + this.id = id || 0; + } + + send(type: "emit" | "off" | "on", name: string, ...args: any[]) { + // @ts-expect-error + mitt[type](`${this.id}__${name}`, ...args); + } + + emit(name: string, ...args: any[]) { + this.send("emit", name, ...args); + } + + off(name: string, handler: (...args: any[]) => void) { + this.send("off", name, handler); + } + + on(name: string, handler: (...args: any[]) => void) { + this.send("on", name, handler); + } +} + +export { Mitt, mitt }; diff --git a/packages/crud/src/utils/parse.tsx b/packages/crud/src/utils/parse.tsx new file mode 100644 index 0000000..404ccbb --- /dev/null +++ b/packages/crud/src/utils/parse.tsx @@ -0,0 +1,52 @@ +import { isString } from "lodash-es"; +import { getValue, isObject } from "."; + +// 解析扩展组件 +export function parseExtensionComponent(vnode: Render.Component) { + if (["el-select", "el-radio-group", "el-checkbox-group"].includes(vnode.name!)) { + const list = getValue(vnode.options || []); + + const children = ( +
+ {list.map((e, i) => { + let label: any; + let value: any; + + if (isString(e)) { + label = value = e; + } else if (isObject(e)) { + label = e.label; + value = e.value; + } else { + return ; + } + + switch (vnode.name) { + case "el-select": + return ; + case "el-radio-group": + return ( + + {label} + + ); + case "el-checkbox-group": + return ( + + {label} + + ); + default: + return null; + } + })} +
+ ); + + return { + children + }; + } else { + return {}; + } +} diff --git a/packages/crud/src/utils/vnode.tsx b/packages/crud/src/utils/vnode.tsx new file mode 100644 index 0000000..e213eb1 --- /dev/null +++ b/packages/crud/src/utils/vnode.tsx @@ -0,0 +1,182 @@ +import { h, resolveComponent, toRaw, type VNode } from "vue"; +import { isObject } from "./index"; +import { parseExtensionComponent } from "./parse"; +import global from "./global"; +import { useConfig } from "../hooks"; +import { isFunction, isString } from "lodash-es"; + +// 配置 +interface Options { + // 标识 + prop?: string; + // 数据值 + scope?: any; + // 当前行 + item?: any; + // 插槽 + slots?: any; + // 子集 + children?: any[] & any; + // 自定义 + custom?: (vnode: any) => any; + // 渲染方式 + render?: "slot" | null; + // 其他 + [key: string]: any; +} + +// 临时注册组件列表 +const regs: Map = new Map(); + +// 解析节点 +export function parseNode(vnode: any, options: Options): VNode { + const { scope, prop, slots, children, _data } = options || {}; + + // 渲染后组件 + let comp: VNode | null = null; + + // 插槽模式渲染 + if (vnode.name?.includes("slot-")) { + const rn = slots[vnode.name]; + + if (rn) { + return rn({ scope, prop, ..._data }); + } else { + return ; + } + } + + // 实例模式下,先注册到全局,再分解组件渲染 + if (vnode.vm && !regs.get(vnode.name)) { + global.vue.component(vnode.name, { ...vnode.vm }); + regs.set(vnode.name, { ...vnode.vm }); + } + + // 处理 props + if (isFunction(vnode.props)) { + vnode.props = vnode.props({ scope, prop, ..._data }); + } + + // 组件参数 + const props = { + ...vnode.props, + ..._data, + prop, + scope + }; + + // 是否禁用 + props.disabled = _data?.isDisabled || props.disabled; + + // 添加双向绑定 + if (props && scope) { + if (prop) { + props.modelValue = scope[prop]; + props["onUpdate:modelValue"] = function (val: any) { + scope[prop] = val; + }; + } + } + + // 组件实例渲染 + if (vnode.vm) { + comp = h(regs.get(vnode.name), props); + } else { + const slots = { + ...vnode.slots + }; + + if (children) { + slots.default = () => children; + } + + // 渲染组件 + comp = h(toRaw(resolveComponent(vnode.name)), props, slots); + } + + // 挂载到 refs 中 + const refBind = vnode.ref || options.ref; + if (isFunction(refBind)) { + setTimeout(() => { + refBind(comp?.component?.exposed); + }, 0); + } + + return comp; +} + +// 渲染节点 +export function renderNode(vnode: any, options: Options) { + const config = useConfig(); + const { item, scope, children, _data, render } = options || {}; + + if (!vnode) { + return null; + } + + if (vnode.__v_isVNode) { + return vnode; + } + + // 默认参数配置 + if (item) { + if (item.component) { + if (!item.component.props) { + item.component.props = {}; + } + + // 占位符 + let placeholder = ""; + + switch (item.component?.name) { + case "el-input": + placeholder = config.dict.label.placeholder; + break; + } + + if (placeholder) { + if (!item.component.props.placeholder) { + item.component.props.placeholder = placeholder; + } + } + } + } + + // 组件实例 + if (vnode.vm) { + if (!vnode.name) { + vnode.name = vnode.vm?.name || vnode.vm?.__hmrId; + } + + return parseNode(vnode, options); + } + + // 组件名渲染 + if (isString(vnode)) { + if (render == "slot") { + if (!vnode.includes("slot-")) { + return vnode; + } + } + + return parseNode({ name: vnode }, options); + } + + // 方法回调 + if (isFunction(vnode)) { + return vnode({ scope, h, ..._data }); + } + + // jsx 模式 + if (isObject(vnode)) { + if (vnode.name) { + return parseNode(vnode, { ...options, children, ...parseExtensionComponent(vnode) }); + } else { + if (options.custom) { + return options.custom(vnode); + } + + return ; + } + } +} diff --git a/packages/crud/tsconfig.json b/packages/crud/tsconfig.json new file mode 100644 index 0000000..75d48c2 --- /dev/null +++ b/packages/crud/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "strict": false, + "noImplicitAny": false, + + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + "types": ["./index.d.ts"], + + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + }, + "declaration": true, + "declarationDir": "types", + "emitDeclarationOnly": true + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "exclude": ["src/App.vue", "node_modules", "dist"] +} diff --git a/packages/crud/types/components/add-btn/index.d.ts b/packages/crud/types/components/add-btn/index.d.ts new file mode 100644 index 0000000..29d4988 --- /dev/null +++ b/packages/crud/types/components/add-btn/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import('vue').DefineComponent<{}, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/adv/btn.d.ts b/packages/crud/types/components/adv/btn.d.ts new file mode 100644 index 0000000..5091404 --- /dev/null +++ b/packages/crud/types/components/adv/btn.d.ts @@ -0,0 +1,4 @@ +declare const _default: import('vue').DefineComponent<{}, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, { + Search: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/adv/search.d.ts b/packages/crud/types/components/adv/search.d.ts new file mode 100644 index 0000000..7792c7d --- /dev/null +++ b/packages/crud/types/components/adv/search.d.ts @@ -0,0 +1,42 @@ +import { PropType } from 'vue'; +declare const _default: import('vue').DefineComponent; + default: () => any[]; + }; + title: StringConstructor; + size: { + type: (NumberConstructor | StringConstructor)[]; + default: string; + }; + op: { + type: ArrayConstructor; + default: () => string[]; + }; + onSearch: FunctionConstructor; +}>, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("clear" | "reset")[], "clear" | "reset", import('vue').PublicProps, Readonly; + default: () => any[]; + }; + title: StringConstructor; + size: { + type: (NumberConstructor | StringConstructor)[]; + default: string; + }; + op: { + type: ArrayConstructor; + default: () => string[]; + }; + onSearch: FunctionConstructor; +}>> & Readonly<{ + onReset?: (...args: any[]) => any; + onClear?: (...args: any[]) => any; +}>, { + size: string | number; + items: ClForm.Item[]; + op: unknown[]; +}, {}, { + Close: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/context-menu/index.d.ts b/packages/crud/types/components/context-menu/index.d.ts new file mode 100644 index 0000000..20e5af1 --- /dev/null +++ b/packages/crud/types/components/context-menu/index.d.ts @@ -0,0 +1,30 @@ +import { PropType } from 'vue'; +declare const ClContextMenu: import('vue').DefineComponent; + default: () => {}; + }; + event: { + type: ObjectConstructor; + default: () => {}; + }; +}>, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly; + default: () => {}; + }; + event: { + type: ObjectConstructor; + default: () => {}; + }; +}>> & Readonly<{}>, { + options: ClContextMenu.Options; + show: boolean; + event: Record; +}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export declare const ContextMenu: { + open(event: any, options: ClContextMenu.Options): ClContextMenu.Exposed; +}; +export default ClContextMenu; diff --git a/packages/crud/types/components/crud/helper.d.ts b/packages/crud/types/components/crud/helper.d.ts new file mode 100644 index 0000000..04d46e6 --- /dev/null +++ b/packages/crud/types/components/crud/helper.d.ts @@ -0,0 +1,23 @@ +import { Mitt } from '../../utils/mitt'; +interface Options { + mitt: Mitt; + config: ClCrud.Config; + crud: ClCrud.Ref; +} +export declare function useHelper({ config, crud, mitt }: Options): { + proxy: (name: string, data?: any[]) => void; + set: (key: string, value: any) => boolean; + on: (name: string, callback: fn) => void; + rowInfo: (data: any) => void; + rowAdd: () => void; + rowEdit: (data: any) => void; + rowAppend: (data: any) => void; + rowDelete: (...selection: any[]) => void; + rowClose: () => void; + refresh: (params?: obj) => Promise; + getPermission: (key: "page" | "list" | "info" | "update" | "add" | "delete") => boolean; + paramsReplace: (params: obj) => any; + getParams: () => obj; + setParams: (data: obj) => void; +}; +export {}; diff --git a/packages/crud/types/components/crud/index.d.ts b/packages/crud/types/components/crud/index.d.ts new file mode 100644 index 0000000..93e8de9 --- /dev/null +++ b/packages/crud/types/components/crud/index.d.ts @@ -0,0 +1,19 @@ +declare const _default: import('vue').DefineComponent, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly> & Readonly<{}>, { + border: boolean; + padding: string; +}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/dialog/index.d.ts b/packages/crud/types/components/dialog/index.d.ts new file mode 100644 index 0000000..6482060 --- /dev/null +++ b/packages/crud/types/components/dialog/index.d.ts @@ -0,0 +1,86 @@ +declare const _default: import('vue').DefineComponent string[]; + }; + hideHeader: BooleanConstructor; + beforeClose: FunctionConstructor; + scrollbar: { + type: BooleanConstructor; + default: boolean; + }; + transparent: BooleanConstructor; +}>, () => import('vue').VNode, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("update:modelValue" | "fullscreen-change")[], "update:modelValue" | "fullscreen-change", import('vue').PublicProps, Readonly string[]; + }; + hideHeader: BooleanConstructor; + beforeClose: FunctionConstructor; + scrollbar: { + type: BooleanConstructor; + default: boolean; + }; + transparent: BooleanConstructor; +}>> & Readonly<{ + "onUpdate:modelValue"?: (...args: any[]) => any; + "onFullscreen-change"?: (...args: any[]) => any; +}>, { + title: string; + padding: string; + width: string; + hideHeader: boolean; + controls: unknown[]; + fullscreen: boolean; + keepAlive: boolean; + modelValue: boolean; + transparent: boolean; + scrollbar: boolean; +}, {}, { + Close: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; + FullScreen: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; + Minus: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/error-message/index.d.ts b/packages/crud/types/components/error-message/index.d.ts new file mode 100644 index 0000000..bcc538c --- /dev/null +++ b/packages/crud/types/components/error-message/index.d.ts @@ -0,0 +1,6 @@ +declare const _default: import('vue').DefineComponent, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/filter/index.d.ts b/packages/crud/types/components/filter/index.d.ts new file mode 100644 index 0000000..bb8f8c6 --- /dev/null +++ b/packages/crud/types/components/filter/index.d.ts @@ -0,0 +1,6 @@ +declare const _default: import('vue').DefineComponent, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/flex1/index.d.ts b/packages/crud/types/components/flex1/index.d.ts new file mode 100644 index 0000000..29d4988 --- /dev/null +++ b/packages/crud/types/components/flex1/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import('vue').DefineComponent<{}, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/form-card/index.d.ts b/packages/crud/types/components/form-card/index.d.ts new file mode 100644 index 0000000..8c93df5 --- /dev/null +++ b/packages/crud/types/components/form-card/index.d.ts @@ -0,0 +1,28 @@ +declare const _default: import('vue').DefineComponent, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly> & Readonly<{}>, { + expand: boolean; + isExpand: boolean; +}, {}, { + ArrowDown: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; + ArrowUp: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/form-tabs/index.d.ts b/packages/crud/types/components/form-tabs/index.d.ts new file mode 100644 index 0000000..429a6d7 --- /dev/null +++ b/packages/crud/types/components/form-tabs/index.d.ts @@ -0,0 +1,38 @@ +import { PropType } from 'vue'; +declare const _default: import('vue').DefineComponent any[]; + }; + justify: { + type: PropType<"start" | "end" | "left" | "right" | "center" | "justify" | "match-parent">; + default: string; + }; + type: { + type: PropType<"card" | "default">; + default: string; + }; +}>, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("change" | "update:modelValue")[], "change" | "update:modelValue", import('vue').PublicProps, Readonly any[]; + }; + justify: { + type: PropType<"start" | "end" | "left" | "right" | "center" | "justify" | "match-parent">; + default: string; + }; + type: { + type: PropType<"card" | "default">; + default: string; + }; +}>> & Readonly<{ + onChange?: (...args: any[]) => any; + "onUpdate:modelValue"?: (...args: any[]) => any; +}>, { + type: "default" | "card"; + labels: unknown[]; + justify: "left" | "center" | "right" | "justify" | "start" | "end" | "match-parent"; +}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/form/helper/action.d.ts b/packages/crud/types/components/form/helper/action.d.ts new file mode 100644 index 0000000..fef6a4d --- /dev/null +++ b/packages/crud/types/components/form/helper/action.d.ts @@ -0,0 +1,17 @@ +export declare function useAction({ config, form, Form }: { + config: ClForm.Config; + form: obj; + Form: Vue.Ref; +}): { + getForm: (prop: string) => any; + setForm: (prop: string, value: any) => void; + setData: (prop: string, value: any) => void; + setConfig: (path: string, value: any) => void; + setOptions: (prop: string, value: any[]) => void; + setProps: (prop: string, value: any) => void; + toggleItem: (prop: string, value?: boolean) => void; + hideItem: (...props: string[]) => void; + showItem: (...props: string[]) => void; + setTitle: (value: string) => void; + collapseItem: (e: any) => void; +}; diff --git a/packages/crud/types/components/form/helper/api.d.ts b/packages/crud/types/components/form/helper/api.d.ts new file mode 100644 index 0000000..ea4f483 --- /dev/null +++ b/packages/crud/types/components/form/helper/api.d.ts @@ -0,0 +1,3 @@ +export declare function useApi({ Form }: { + Form: Vue.Ref; +}): obj; diff --git a/packages/crud/types/components/form/helper/index.d.ts b/packages/crud/types/components/form/helper/index.d.ts new file mode 100644 index 0000000..a6ae9b9 --- /dev/null +++ b/packages/crud/types/components/form/helper/index.d.ts @@ -0,0 +1,237 @@ +export declare function useForm(): { + Form: import('vue').Ref; + config: { + [x: string]: any; + title?: any; + height?: any; + width?: any; + props: { + [x: string]: any; + inline?: boolean; + labelPosition?: "left" | "right" | "top"; + labelWidth?: string | number; + labelSuffix?: string; + hideRequiredAsterisk?: boolean; + showMessage?: boolean; + inlineMessage?: boolean; + statusIcon?: boolean; + validateOnRuleChange?: boolean; + size?: ElementPlus.Size; + disabled?: boolean; + }; + items: { + [x: string]: any; + type?: "tabs"; + prop?: string & {}; + props?: { + [x: string]: any; + labels?: { + [x: string]: any; + label: string; + value: string; + name?: string; + icon?: any; + lazy?: boolean; + }[]; + justify?: "left" | "center" | "right"; + color?: string; + mergeProp?: boolean; + labelWidth?: string; + error?: string; + showMessage?: boolean; + inlineMessage?: boolean; + size?: "medium" | "default" | "small"; + }; + span?: number; + col?: { + span: number; + offset: number; + push: number; + pull: number; + xs: any; + sm: any; + md: any; + lg: any; + xl: any; + tag: string; + }; + group?: string; + collapse?: boolean; + value?: any; + label?: string; + renderLabel?: any; + flex?: boolean; + hook?: "string" | "number" | "boolean" | "join" | "split" | AnyString | "empty" | "booleanNumber" | "datetimeRange" | "splitJoin" | "json" | { + bind?: ClForm.Hook["Pipe"] | ClForm.Hook["Pipe"][]; + submit?: ClForm.Hook["Pipe"] | ClForm.Hook["Pipe"][]; + reset?: (prop: string) => string[]; + }; + hidden?: boolean | ((options: { + scope: obj; + }) => boolean); + prepend?: { + [x: string]: any; + name?: string; + options?: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[] | { + value: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[]; + }; + props?: { + [x: string]: any; + onChange?: (value: any) => void; + } | { + value: { + [x: string]: any; + onChange?: (value: any) => void; + }; + }; + style?: obj; + slots?: { + [key: string]: (data?: any) => any; + }; + vm?: any; + }; + component?: { + [x: string]: any; + name?: string; + options?: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[] | { + value: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[]; + }; + props?: { + [x: string]: any; + onChange?: (value: any) => void; + } | { + value: { + [x: string]: any; + onChange?: (value: any) => void; + }; + }; + style?: obj; + slots?: { + [key: string]: (data?: any) => any; + }; + vm?: any; + }; + append?: { + [x: string]: any; + name?: string; + options?: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[] | { + value: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[]; + }; + props?: { + [x: string]: any; + onChange?: (value: any) => void; + } | { + value: { + [x: string]: any; + onChange?: (value: any) => void; + }; + }; + style?: obj; + slots?: { + [key: string]: (data?: any) => any; + }; + vm?: any; + }; + rules?: { + [x: string]: any; + type?: "string" | "number" | "boolean" | "method" | "regexp" | "integer" | "float" | "array" | "object" | "enum" | "date" | "url" | "hex" | "email" | "any"; + required?: boolean; + message?: string; + min?: number; + max?: number; + trigger?: any; + validator?: (rule: any, value: any, callback: (error?: Error) => void) => void; + } | { + [x: string]: any; + type?: "string" | "number" | "boolean" | "method" | "regexp" | "integer" | "float" | "array" | "object" | "enum" | "date" | "url" | "hex" | "email" | "any"; + required?: boolean; + message?: string; + min?: number; + max?: number; + trigger?: any; + validator?: (rule: any, value: any, callback: (error?: Error) => void) => void; + }[]; + required?: boolean; + children?: /*elided*/ any[]; + }[]; + form: obj; + isReset?: boolean; + on?: { + open?: (data: any) => void; + close?: (action: ClForm.CloseAction, done: fn) => void; + submit?: (data: any, event: { + close: fn; + done: fn; + }) => void; + change?: (data: any, prop: string) => void; + }; + op: { + hidden?: boolean; + saveButtonText?: string; + closeButtonText?: string; + justify?: "flex-start" | "center" | "flex-end"; + buttons?: (`slot-${string}` | ClForm.CloseAction | { + [x: string]: any; + label: string; + type?: string; + hidden?: boolean; + onClick: (options: { + scope: obj; + }) => void; + })[]; + }; + dialog: { + [x: string]: any; + title?: any; + height?: string; + width?: string; + hideHeader?: boolean; + controls?: Array<"fullscreen" | "close" | AnyString>; + }; + }; + form: obj; + visible: import('vue').Ref; + saving: import('vue').Ref; + loading: import('vue').Ref; + disabled: import('vue').Ref; +}; +export * from './action'; +export * from './api'; +export * from './plugins'; +export * from './tabs'; diff --git a/packages/crud/types/components/form/helper/plugins.d.ts b/packages/crud/types/components/form/helper/plugins.d.ts new file mode 100644 index 0000000..6811d5d --- /dev/null +++ b/packages/crud/types/components/form/helper/plugins.d.ts @@ -0,0 +1,7 @@ +import { Ref } from 'vue'; +export declare function usePlugins(enable: boolean, { visible }: { + visible: Ref; +}): { + create: (plugins?: ClForm.Plugin[]) => boolean; + submit: (data: any) => Promise; +}; diff --git a/packages/crud/types/components/form/helper/tabs.d.ts b/packages/crud/types/components/form/helper/tabs.d.ts new file mode 100644 index 0000000..f1c24a6 --- /dev/null +++ b/packages/crud/types/components/form/helper/tabs.d.ts @@ -0,0 +1,19 @@ +export declare function useTabs({ config, Form }: { + config: ClForm.Config; + Form: Vue.Ref; +}): { + active: import('vue').Ref; + list: import('vue').ComputedRef; + isLoaded: (value: any) => any; + onLoad: (value: any) => void; + get: () => ClForm.Item; + set: (data: any) => void; + change: (value: any, isValid?: boolean) => Promise; + clear: () => void; + mergeProp: (item: ClForm.Item) => void; + toGroup: (opts: { + config: ClForm.Config; + prop: string; + refs: any; + }) => void; +}; diff --git a/packages/crud/types/components/form/index.d.ts b/packages/crud/types/components/form/index.d.ts new file mode 100644 index 0000000..a006771 --- /dev/null +++ b/packages/crud/types/components/form/index.d.ts @@ -0,0 +1,22 @@ +declare const _default: import('vue').DefineComponent, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly> & Readonly<{}>, { + inline: boolean; + inner: boolean; + enablePlugin: boolean; +}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/index.d.ts b/packages/crud/types/components/index.d.ts new file mode 100644 index 0000000..e648ab0 --- /dev/null +++ b/packages/crud/types/components/index.d.ts @@ -0,0 +1,5 @@ +import { App } from 'vue'; +export declare const components: { + [key: string]: any; +}; +export declare function useComponent(app: App): void; diff --git a/packages/crud/types/components/multi-delete-btn/index.d.ts b/packages/crud/types/components/multi-delete-btn/index.d.ts new file mode 100644 index 0000000..29d4988 --- /dev/null +++ b/packages/crud/types/components/multi-delete-btn/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import('vue').DefineComponent<{}, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/pagination/index.d.ts b/packages/crud/types/components/pagination/index.d.ts new file mode 100644 index 0000000..b82693a --- /dev/null +++ b/packages/crud/types/components/pagination/index.d.ts @@ -0,0 +1,4 @@ +declare const _default: import('vue').DefineComponent<{}, () => import('vue').VNode, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/refresh-btn/index.d.ts b/packages/crud/types/components/refresh-btn/index.d.ts new file mode 100644 index 0000000..29d4988 --- /dev/null +++ b/packages/crud/types/components/refresh-btn/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import('vue').DefineComponent<{}, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/row/index.d.ts b/packages/crud/types/components/row/index.d.ts new file mode 100644 index 0000000..29d4988 --- /dev/null +++ b/packages/crud/types/components/row/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import('vue').DefineComponent<{}, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/search-key/index.d.ts b/packages/crud/types/components/search-key/index.d.ts new file mode 100644 index 0000000..47a2bbc --- /dev/null +++ b/packages/crud/types/components/search-key/index.d.ts @@ -0,0 +1,55 @@ +import { PropType } from 'vue'; +declare const _default: import('vue').DefineComponent>; + default: () => any[]; + }; + onSearch: FunctionConstructor; + placeholder: StringConstructor; + width: { + type: (NumberConstructor | StringConstructor)[]; + default: number; + }; + refreshOnInput: BooleanConstructor; +}>, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("change" | "update:modelValue" | "field-change")[], "change" | "update:modelValue" | "field-change", import('vue').PublicProps, Readonly>; + default: () => any[]; + }; + onSearch: FunctionConstructor; + placeholder: StringConstructor; + width: { + type: (NumberConstructor | StringConstructor)[]; + default: number; + }; + refreshOnInput: BooleanConstructor; +}>> & Readonly<{ + onChange?: (...args: any[]) => any; + "onUpdate:modelValue"?: (...args: any[]) => any; + "onField-change"?: (...args: any[]) => any; +}>, { + width: string | number; + refreshOnInput: boolean; + field: string; + fieldList: { + label: string; + value: string; + }[]; +}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/search/helper/plugins.d.ts b/packages/crud/types/components/search/helper/plugins.d.ts new file mode 100644 index 0000000..7d1138c --- /dev/null +++ b/packages/crud/types/components/search/helper/plugins.d.ts @@ -0,0 +1,3 @@ +export declare function usePlugins(): { + create: (plugins?: ClSearch.Plugin[]) => void; +}; diff --git a/packages/crud/types/components/search/index.d.ts b/packages/crud/types/components/search/index.d.ts new file mode 100644 index 0000000..17ba12a --- /dev/null +++ b/packages/crud/types/components/search/index.d.ts @@ -0,0 +1,66 @@ +import { PropType } from 'vue'; +declare const _default: import('vue').DefineComponent {}; + }; + data: { + type: ObjectConstructor; + default: () => {}; + }; + items: { + type: PropType; + default: () => any[]; + }; + resetBtn: { + type: BooleanConstructor; + default: boolean; + }; + collapse: { + type: BooleanConstructor; + default: boolean; + }; + onLoad: FunctionConstructor; + onSearch: FunctionConstructor; +}>, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, "reset"[], "reset", import('vue').PublicProps, Readonly {}; + }; + data: { + type: ObjectConstructor; + default: () => {}; + }; + items: { + type: PropType; + default: () => any[]; + }; + resetBtn: { + type: BooleanConstructor; + default: boolean; + }; + collapse: { + type: BooleanConstructor; + default: boolean; + }; + onLoad: FunctionConstructor; + onSearch: FunctionConstructor; +}>> & Readonly<{ + onReset?: (...args: any[]) => any; +}>, { + data: Record; + props: Record; + items: ClForm.Item[]; + inline: boolean; + resetBtn: boolean; + collapse: boolean; +}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/table/helper/data.d.ts b/packages/crud/types/components/table/helper/data.d.ts new file mode 100644 index 0000000..932629f --- /dev/null +++ b/packages/crud/types/components/table/helper/data.d.ts @@ -0,0 +1,7 @@ +export declare function useData({ config, Table }: { + config: ClTable.Config; + Table: Vue.Ref; +}): { + data: import('vue').Ref; + setData: (list: obj[]) => void; +}; diff --git a/packages/crud/types/components/table/helper/header.d.ts b/packages/crud/types/components/table/helper/header.d.ts new file mode 100644 index 0000000..0b4bd8b --- /dev/null +++ b/packages/crud/types/components/table/helper/header.d.ts @@ -0,0 +1 @@ +export declare function renderHeader(item: ClTable.Column, { scope, slots }: any): any; diff --git a/packages/crud/types/components/table/helper/height.d.ts b/packages/crud/types/components/table/helper/height.d.ts new file mode 100644 index 0000000..12d050a --- /dev/null +++ b/packages/crud/types/components/table/helper/height.d.ts @@ -0,0 +1,7 @@ +export declare function useHeight({ config, Table }: { + Table: Vue.Ref; + config: ClTable.Config; +}): { + maxHeight: import('vue').Ref; + calcMaxHeight: import('lodash').DebouncedFunc<() => Promise>; +}; diff --git a/packages/crud/types/components/table/helper/index.d.ts b/packages/crud/types/components/table/helper/index.d.ts new file mode 100644 index 0000000..cee1073 --- /dev/null +++ b/packages/crud/types/components/table/helper/index.d.ts @@ -0,0 +1,191 @@ +import { TableInstance } from 'element-plus'; +export declare function useTable(props: any): { + Table: import('vue').Ref; + config: { + columns: { + [x: string]: any; + type: ClTable.ColumnType; + hidden: boolean | { + value: boolean; + }; + component: { + [x: string]: any; + name?: string; + options?: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[] | { + value: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[]; + }; + props?: { + [x: string]: any; + onChange?: (value: any) => void; + } | { + value: { + [x: string]: any; + onChange?: (value: any) => void; + }; + }; + style?: obj; + slots?: { + [key: string]: (data?: any) => any; + }; + vm?: any; + }; + search: { + isInput: boolean; + value: any; + icon: () => any; + refreshOnChange: boolean; + component: { + [x: string]: any; + name?: string; + options?: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[] | { + value: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[]; + }; + props?: { + [x: string]: any; + onChange?: (value: any) => void; + } | { + value: { + [x: string]: any; + onChange?: (value: any) => void; + }; + }; + style?: obj; + slots?: { + [key: string]: (data?: any) => any; + }; + vm?: any; + }; + }; + dict: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[] | { + value: { + [x: string]: any; + label?: string; + value?: any; + color?: string; + type?: string; + }[]; + }; + dictFormatter: (values: DictOptions) => string; + dictColor: boolean; + dictSeparator: string; + dictAllLevels: boolean; + buttons: ((options: { + scope: any; + }) => ClTable.OpButton) | ("info" | "delete" | "edit" | AnyString | `slot-${string}` | { + [x: string]: any; + label: string; + type?: string; + hidden?: boolean; + onClick: (options: { + scope: obj; + }) => void; + })[]; + align: ElementPlus.Align; + label: any; + renderLabel: (options: { + column: any; + $index: number; + }) => any; + className: string; + prop: string & {}; + orderNum: number; + width: string | number | { + value: string | number; + }; + minWidth: string | number | { + value: string | number; + }; + renderHeader: (options: { + column: any; + $index: number; + }) => any; + sortable: boolean | "desc" | "descending" | "ascending" | "asc" | "custom"; + sortMethod: fn; + sortBy: string | any[] | ((row: any, index: number) => any); + resizable: boolean; + columnKey: string; + headerAlign: ElementPlus.Align; + showOverflowTooltip: boolean; + fixed: boolean | string; + render: (row: any, column: any, value: any, index: number) => any; + formatter: (row: any, column: any, value: any, index: number) => any; + selectable: (row: any, index: number) => boolean; + reserveSelection: boolean; + filterMethod: fn; + filteredValue: unknown[]; + filters: unknown[]; + filterPlacement: string; + filterMultiple: boolean; + index: ((index: number) => number) | number; + sortOrders: unknown[]; + children: /*elided*/ any[]; + }[]; + autoHeight: boolean; + height: any; + contextMenu: ("info" | "update" | "delete" | "edit" | "refresh" | { + [x: string]: any; + label: string; + prefixIcon?: any; + suffixIcon?: any; + ellipsis?: boolean; + disabled?: boolean; + hidden?: boolean; + children?: /*elided*/ any[]; + showChildren?: boolean; + callback?: (done: fn) => void; + } | ((row: obj, column: obj, event: PointerEvent) => ClContextMenu.Item) | "check" | "order-desc" | "order-asc")[]; + defaultSort: { + prop: string; + order: "descending" | "ascending"; + }; + sortRefresh: boolean; + emptyText: string; + rowKey: string; + on?: { + [key: string]: (...args: any[]) => void; + }; + props?: { + [key: string]: any; + }; + plugins?: ClTable.Plugin[]; + onRowContextmenu?: (row: any, column: any, event: any) => void; + }; +}; +export * from './data'; +export * from './height'; +export * from './op'; +export * from './render'; +export * from './row'; +export * from './selection'; +export * from './sort'; +export * from './header'; diff --git a/packages/crud/types/components/table/helper/op.d.ts b/packages/crud/types/components/table/helper/op.d.ts new file mode 100644 index 0000000..6e8a7a7 --- /dev/null +++ b/packages/crud/types/components/table/helper/op.d.ts @@ -0,0 +1,9 @@ +export declare function useOp({ config }: { + config: ClTable.Config; +}): { + visible: import('vue').Ref; + reBuild: (cb?: fn) => Promise; + showColumn: (prop: string | string[], status?: boolean) => void; + hideColumn: (prop: string | string[]) => void; + setColumns: (list: ClTable.Column[]) => void; +}; diff --git a/packages/crud/types/components/table/helper/plugins.d.ts b/packages/crud/types/components/table/helper/plugins.d.ts new file mode 100644 index 0000000..5e94af8 --- /dev/null +++ b/packages/crud/types/components/table/helper/plugins.d.ts @@ -0,0 +1,3 @@ +export declare function usePlugins(): { + create: (plugins?: ClTable.Plugin[]) => void; +}; diff --git a/packages/crud/types/components/table/helper/render.d.ts b/packages/crud/types/components/table/helper/render.d.ts new file mode 100644 index 0000000..226bd5e --- /dev/null +++ b/packages/crud/types/components/table/helper/render.d.ts @@ -0,0 +1,7 @@ +export declare function useRender(): { + renderColumn: (columns: ClTable.Column[]) => import('vue').VNode[]; + renderEmpty: (emptyText: string) => any; + renderAppend: () => any; +}; diff --git a/packages/crud/types/components/table/helper/row.d.ts b/packages/crud/types/components/table/helper/row.d.ts new file mode 100644 index 0000000..1b70cad --- /dev/null +++ b/packages/crud/types/components/table/helper/row.d.ts @@ -0,0 +1,13 @@ +export declare function useRow({ Table, config, Sort }: { + Table: Vue.Ref; + config: ClTable.Config; + Sort: { + defaultSort: { + prop?: string; + order?: string; + }; + changeSort(prop: string, order: string): void; + }; +}): { + onRowContextMenu: (row: obj, column: obj, event: PointerEvent) => void; +}; diff --git a/packages/crud/types/components/table/helper/selection.d.ts b/packages/crud/types/components/table/helper/selection.d.ts new file mode 100644 index 0000000..568a302 --- /dev/null +++ b/packages/crud/types/components/table/helper/selection.d.ts @@ -0,0 +1,6 @@ +export declare function useSelection({ emit }: { + emit: Vue.Emit; +}): { + selection: obj[]; + onSelectionChange: (selection: any[]) => void; +}; diff --git a/packages/crud/types/components/table/helper/sort.d.ts b/packages/crud/types/components/table/helper/sort.d.ts new file mode 100644 index 0000000..f996d62 --- /dev/null +++ b/packages/crud/types/components/table/helper/sort.d.ts @@ -0,0 +1,18 @@ +export declare function useSort({ config, Table, emit }: { + config: ClTable.Config; + Table: Vue.Ref; + emit: Vue.Emit; +}): { + defaultSort: { + prop: string; + order: "descending" | "ascending"; + } | { + prop?: undefined; + order?: undefined; + }; + onSortChange: ({ prop, order }: { + prop: string | undefined; + order: string; + }) => void; + changeSort: (prop: string, order: string) => void; +}; diff --git a/packages/crud/types/components/table/index.d.ts b/packages/crud/types/components/table/index.d.ts new file mode 100644 index 0000000..9ae9df3 --- /dev/null +++ b/packages/crud/types/components/table/index.d.ts @@ -0,0 +1,62 @@ +declare const _default: import('vue').DefineComponent any[]; + }; + autoHeight: { + type: BooleanConstructor; + default: any; + }; + height: any; + contextMenu: { + type: (ArrayConstructor | BooleanConstructor)[]; + default: any; + }; + defaultSort: ObjectConstructor; + sortRefresh: { + type: BooleanConstructor; + default: boolean; + }; + emptyText: StringConstructor; + rowKey: { + type: StringConstructor; + default: string; + }; +}>, () => import('vue').VNode, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("selection-change" | "sort-change")[], "selection-change" | "sort-change", import('vue').PublicProps, Readonly any[]; + }; + autoHeight: { + type: BooleanConstructor; + default: any; + }; + height: any; + contextMenu: { + type: (ArrayConstructor | BooleanConstructor)[]; + default: any; + }; + defaultSort: ObjectConstructor; + sortRefresh: { + type: BooleanConstructor; + default: boolean; + }; + emptyText: StringConstructor; + rowKey: { + type: StringConstructor; + default: string; + }; +}>> & Readonly<{ + "onSelection-change"?: (...args: any[]) => any; + "onSort-change"?: (...args: any[]) => any; +}>, { + columns: unknown[]; + autoHeight: boolean; + height: any; + contextMenu: boolean | unknown[]; + sortRefresh: boolean; + rowKey: string; +}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/components/upsert/index.d.ts b/packages/crud/types/components/upsert/index.d.ts new file mode 100644 index 0000000..7b9fb0b --- /dev/null +++ b/packages/crud/types/components/upsert/index.d.ts @@ -0,0 +1,38 @@ +declare const _default: import('vue').DefineComponent any[]; + }; + props: ObjectConstructor; + sync: BooleanConstructor; + op: ObjectConstructor; + dialog: ObjectConstructor; + onOpen: FunctionConstructor; + onOpened: FunctionConstructor; + onClose: FunctionConstructor; + onClosed: FunctionConstructor; + onInfo: FunctionConstructor; + onSubmit: FunctionConstructor; +}>, () => any, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, ("opened" | "closed")[], "opened" | "closed", import('vue').PublicProps, Readonly any[]; + }; + props: ObjectConstructor; + sync: BooleanConstructor; + op: ObjectConstructor; + dialog: ObjectConstructor; + onOpen: FunctionConstructor; + onOpened: FunctionConstructor; + onClose: FunctionConstructor; + onClosed: FunctionConstructor; + onInfo: FunctionConstructor; + onSubmit: FunctionConstructor; +}>> & Readonly<{ + onOpened?: (...args: any[]) => any; + onClosed?: (...args: any[]) => any; +}>, { + sync: boolean; + items: unknown[]; +}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>; +export default _default; diff --git a/packages/crud/types/emitter.d.ts b/packages/crud/types/emitter.d.ts new file mode 100644 index 0000000..b4d8fef --- /dev/null +++ b/packages/crud/types/emitter.d.ts @@ -0,0 +1,2 @@ +export declare const crudList: ClCrud.Ref[]; +export declare const emitter: Emitter; diff --git a/packages/crud/types/entry.d.ts b/packages/crud/types/entry.d.ts new file mode 100644 index 0000000..b78771c --- /dev/null +++ b/packages/crud/types/entry.d.ts @@ -0,0 +1,13 @@ +import { App } from 'vue'; +declare const Crud: { + install(app: App, options?: any): { + name: string; + }; +}; +export { Crud }; +export * from './emitter'; +export * from './hooks'; +export * from './locale'; +export { registerFormHook } from './utils/form-hook'; +export { renderNode } from './utils/vnode'; +export { ContextMenu } from './components/context-menu'; diff --git a/packages/crud/types/hooks/crud.d.ts b/packages/crud/types/hooks/crud.d.ts new file mode 100644 index 0000000..47788c3 --- /dev/null +++ b/packages/crud/types/hooks/crud.d.ts @@ -0,0 +1,10 @@ +import { Ref } from 'vue'; +export declare function useCrud(options?: ClCrud.Options, cb?: (app: ClCrud.Ref) => void): Ref; +export declare function useUpsert(options?: ClUpsert.Options): Ref, ClUpsert.Ref>; +export declare function useTable(options?: ClTable.Options, cb?: (table: ClTable.Ref) => void): Ref, ClTable.Ref>; +export declare function useForm(cb?: (app: ClForm.Ref) => void): Ref, ClForm.Ref>; +export declare function useAdvSearch(options?: ClAdvSearch.Options): Ref, ClAdvSearch.Ref>; +export declare function useSearch(options?: ClSearch.Options): Ref, ClSearch.Ref>; +export declare function useDialog(options?: { + onFullscreen(visible: boolean): void; +}): ClDialog.Provide; diff --git a/packages/crud/types/hooks/index.d.ts b/packages/crud/types/hooks/index.d.ts new file mode 100644 index 0000000..d1f89af --- /dev/null +++ b/packages/crud/types/hooks/index.d.ts @@ -0,0 +1,16 @@ +import { Mitt } from '../utils/mitt'; +export declare function useCore(): { + crud: ClCrud.Ref; + mitt: Mitt; +}; +export declare function useConfig(): Config; +export declare function useBrowser(): Browser; +export declare function useRefs(): { + refs: { + [key: string]: obj; + }; + setRefs: (name: string) => (el: any) => void; +}; +export declare function useProxy(ctx: any): any; +export declare function useElApi(keys: string[], el: any): obj; +export * from './crud'; diff --git a/packages/crud/types/locale/en.d.ts b/packages/crud/types/locale/en.d.ts new file mode 100644 index 0000000..d0c88bd --- /dev/null +++ b/packages/crud/types/locale/en.d.ts @@ -0,0 +1,33 @@ +declare const _default: { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; +}; +export default _default; diff --git a/packages/crud/types/locale/index.d.ts b/packages/crud/types/locale/index.d.ts new file mode 100644 index 0000000..a9e8362 --- /dev/null +++ b/packages/crud/types/locale/index.d.ts @@ -0,0 +1,130 @@ +export declare const locale: { + en: { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; + }; + ja: { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; + }; + "zh-cn": { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; + }; + "zh-tw": { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; + }; +}; diff --git a/packages/crud/types/locale/ja.d.ts b/packages/crud/types/locale/ja.d.ts new file mode 100644 index 0000000..d0c88bd --- /dev/null +++ b/packages/crud/types/locale/ja.d.ts @@ -0,0 +1,33 @@ +declare const _default: { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; +}; +export default _default; diff --git a/packages/crud/types/locale/zh-cn.d.ts b/packages/crud/types/locale/zh-cn.d.ts new file mode 100644 index 0000000..d0c88bd --- /dev/null +++ b/packages/crud/types/locale/zh-cn.d.ts @@ -0,0 +1,33 @@ +declare const _default: { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; +}; +export default _default; diff --git a/packages/crud/types/locale/zh-tw.d.ts b/packages/crud/types/locale/zh-tw.d.ts new file mode 100644 index 0000000..d0c88bd --- /dev/null +++ b/packages/crud/types/locale/zh-tw.d.ts @@ -0,0 +1,33 @@ +declare const _default: { + op: string; + add: string; + delete: string; + multiDelete: string; + update: string; + refresh: string; + info: string; + search: string; + reset: string; + clear: string; + save: string; + close: string; + confirm: string; + advSearch: string; + searchKey: string; + placeholder: string; + tips: string; + saveSuccess: string; + deleteSuccess: string; + deleteConfirm: string; + empty: string; + desc: string; + asc: string; + select: string; + deselect: string; + seeMore: string; + hideContent: string; + nonEmpty: string; + collapse: string; + expand: string; +}; +export default _default; diff --git a/packages/crud/types/main.d.ts b/packages/crud/types/main.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/crud/types/provide.d.ts b/packages/crud/types/provide.d.ts new file mode 100644 index 0000000..ad73709 --- /dev/null +++ b/packages/crud/types/provide.d.ts @@ -0,0 +1,2 @@ +import { App } from 'vue'; +export declare function useProvide(app: App, options?: Options): void; diff --git a/packages/crud/types/test/service.d.ts b/packages/crud/types/test/service.d.ts new file mode 100644 index 0000000..84d6dd2 --- /dev/null +++ b/packages/crud/types/test/service.d.ts @@ -0,0 +1,52 @@ +declare class TestService { + page(params: any): Promise; + update(params: { + id: any; + [key: string]: any; + }): Promise; + add(params: any): Promise; + info(params: { + id: any; + }): Promise<{ + id: number; + name: string; + createTime: string; + wages: number; + status: number; + account: string; + occupation: number; + phone: number; + }>; + delete(params: { + ids: any[]; + }): Promise; + list(): Promise<{ + id: number; + name: string; + createTime: string; + wages: number; + status: number; + account: string; + occupation: number; + phone: number; + }[]>; + search: { + fieldEq: { + propertyName: string; + comment: string; + source: string; + }[]; + fieldLike: { + propertyName: string; + comment: string; + dict: string[]; + source: string; + }[]; + keyWordLikeFields: { + propertyName: string; + comment: string; + source: string; + }[]; + }; +} +export { TestService }; diff --git a/packages/crud/types/utils/form-hook.d.ts b/packages/crud/types/utils/form-hook.d.ts new file mode 100644 index 0000000..7e5b2cf --- /dev/null +++ b/packages/crud/types/utils/form-hook.d.ts @@ -0,0 +1,9 @@ +export declare const format: { + [key: string]: ClForm.Hook["Fn"]; +}; +declare const formHook: { + bind(data: any): void; + submit(data: any): void; +}; +export declare function registerFormHook(name: string, fn: ClForm.Hook["Fn"]): void; +export default formHook; diff --git a/packages/crud/types/utils/global.d.ts b/packages/crud/types/utils/global.d.ts new file mode 100644 index 0000000..fb15cd0 --- /dev/null +++ b/packages/crud/types/utils/global.d.ts @@ -0,0 +1,7 @@ +import { App } from 'vue'; +declare const _default: { + readonly vue: App; + get(key: string): any; + set(key: string, value: any): void; +}; +export default _default; diff --git a/packages/crud/types/utils/index.d.ts b/packages/crud/types/utils/index.d.ts new file mode 100644 index 0000000..2351cd0 --- /dev/null +++ b/packages/crud/types/utils/index.d.ts @@ -0,0 +1,14 @@ +export declare function isObject(val: any): boolean; +export declare function parsePx(val: string | number): string; +export declare function dataset(obj: any, key: string, value: any): any; +export declare function contains(parent: any, node: any): any; +export declare function mergeConfig(a: any, b?: any): any; +export declare function merge(d1: any, d2: any): any; +export declare function addClass(el: Element, name: string): void; +export declare function removeClass(el: Element, name: string): void; +export declare function getValue(value: T | Vue.Ref | ((d: any) => T), data?: any): T; +export declare function deepFind(value: any, list: any[], options?: { + allLevels: boolean; +}): any; +export declare function uuid(separator?: string): string; +export declare function uniqueFns(fns: any[]): any[]; diff --git a/packages/crud/types/utils/mitt.d.ts b/packages/crud/types/utils/mitt.d.ts new file mode 100644 index 0000000..be94bfc --- /dev/null +++ b/packages/crud/types/utils/mitt.d.ts @@ -0,0 +1,10 @@ +declare const mitt: import('mitt').Emitter>; +declare class Mitt { + id: number; + constructor(id?: number); + send(type: "emit" | "off" | "on", name: string, ...args: any[]): void; + emit(name: string, ...args: any[]): void; + off(name: string, handler: (...args: any[]) => void): void; + on(name: string, handler: (...args: any[]) => void): void; +} +export { Mitt, mitt }; diff --git a/packages/crud/types/utils/parse.d.ts b/packages/crud/types/utils/parse.d.ts new file mode 100644 index 0000000..d4639fd --- /dev/null +++ b/packages/crud/types/utils/parse.d.ts @@ -0,0 +1,5 @@ +export declare function parseExtensionComponent(vnode: Render.Component): { + children: any; +} | { + children?: undefined; +}; diff --git a/packages/crud/types/utils/vnode.d.ts b/packages/crud/types/utils/vnode.d.ts new file mode 100644 index 0000000..534c600 --- /dev/null +++ b/packages/crud/types/utils/vnode.d.ts @@ -0,0 +1,14 @@ +import { VNode } from 'vue'; +interface Options { + prop?: string; + scope?: any; + item?: any; + slots?: any; + children?: any[] & any; + custom?: (vnode: any) => any; + render?: "slot" | null; + [key: string]: any; +} +export declare function parseNode(vnode: any, options: Options): VNode; +export declare function renderNode(vnode: any, options: Options): any; +export {}; diff --git a/packages/crud/vite.config.ts b/packages/crud/vite.config.ts new file mode 100644 index 0000000..b8e622c --- /dev/null +++ b/packages/crud/vite.config.ts @@ -0,0 +1,49 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; +import vueJsx from "@vitejs/plugin-vue-jsx"; +import dts from "vite-plugin-dts"; +import { resolve } from "path"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + dts({ + include: ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], + outDir: "types" + }) + ], + + css: { + preprocessorOptions: { + scss: { + charset: false, + api: "modern-compiler" + } + } + }, + + build: { + lib: { + entry: resolve(__dirname, "src/entry.ts"), + name: "index", + fileName: (format) => `index.${format}.js`, + cssFileName: "index" + }, + rollupOptions: { + external: ["element-plus", "@element-plus/icons-vue", "vue"], + output: { + exports: "named", + globals: { + "element-plus": "ElementPlus", + "@element-plus/icons-vue": "ElementPlusIconsVue", + vue: "Vue" + } + } + }, + sourcemap: true, + minify: "terser", + cssCodeSplit: false + } +}); diff --git a/packages/crud/yarn.lock b/packages/crud/yarn.lock new file mode 100644 index 0000000..4271e79 --- /dev/null +++ b/packages/crud/yarn.lock @@ -0,0 +1,1790 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.26.2", "@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2": + version "7.28.0" + resolved "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790" + integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw== + +"@babel/core@^7.27.1": + version "7.28.0" + resolved "https://registry.npmmirror.com/@babel/core/-/core-7.28.0.tgz#55dad808d5bf3445a108eefc88ea3fdf034749a4" + integrity sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.27.3" + "@babel/helpers" "^7.27.6" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.0" + "@babel/types" "^7.28.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.28.0": + version "7.28.0" + resolved "https://registry.npmmirror.com/@babel/generator/-/generator-7.28.0.tgz#9cc2f7bd6eb054d77dc66c2664148a0c5118acd2" + integrity sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg== + dependencies: + "@babel/parser" "^7.28.0" + "@babel/types" "^7.28.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-annotate-as-pure@^7.27.1", "@babel/helper-annotate-as-pure@^7.27.3": + version "7.27.3" + resolved "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5" + integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg== + dependencies: + "@babel/types" "^7.27.3" + +"@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz#5bee4262a6ea5ddc852d0806199eb17ca3de9281" + integrity sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/traverse" "^7.27.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-member-expression-to-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44" + integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-imports@^7.25.9", "@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.27.3": + version "7.27.3" + resolved "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz#db0bbcfba5802f9ef7870705a7ef8788508ede02" + integrity sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.27.3" + +"@babel/helper-optimise-call-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" + integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw== + dependencies: + "@babel/types" "^7.27.1" + +"@babel/helper-plugin-utils@^7.26.5", "@babel/helper-plugin-utils@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-replace-supers@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0" + integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/helper-skip-transparent-expression-wrappers@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" + integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.27.6": + version "7.27.6" + resolved "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.27.6.tgz#6456fed15b2cb669d2d1fabe84b66b34991d812c" + integrity sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.27.6" + +"@babel/parser@^7.26.9", "@babel/parser@^7.27.2", "@babel/parser@^7.27.5", "@babel/parser@^7.28.0": + version "7.28.0" + resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" + integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== + dependencies: + "@babel/types" "^7.28.0" + +"@babel/plugin-syntax-jsx@^7.25.9": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" + integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-typescript@^7.27.1": + version "7.27.1" + resolved "https://registry.npmmirror.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" + integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-typescript@^7.27.1": + version "7.28.0" + resolved "https://registry.npmmirror.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz#796cbd249ab56c18168b49e3e1d341b72af04a6b" + integrity sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-syntax-typescript" "^7.27.1" + +"@babel/template@^7.26.9", "@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.npmmirror.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.26.9", "@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0": + version "7.28.0" + resolved "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.28.0.tgz#518aa113359b062042379e333db18380b537e34b" + integrity sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.0" + debug "^4.3.1" + +"@babel/types@^7.26.9", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.27.6", "@babel/types@^7.28.0": + version "7.28.1" + resolved "https://registry.npmmirror.com/@babel/types/-/types-7.28.1.tgz#2aaf3c10b31ba03a77ac84f52b3912a0edef4cf9" + integrity sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + +"@ctrl/tinycolor@^3.4.1": + version "3.6.1" + resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31" + integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA== + +"@element-plus/icons-vue@^2.3.1": + version "2.3.1" + resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a" + integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg== + +"@esbuild/aix-ppc64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz#a1414903bb38027382f85f03dda6065056757727" + integrity sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA== + +"@esbuild/android-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz#c859994089e9767224269884061f89dae6fb51c6" + integrity sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w== + +"@esbuild/android-arm@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.8.tgz#96a8f2ca91c6cd29ea90b1af79d83761c8ba0059" + integrity sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw== + +"@esbuild/android-x64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.8.tgz#a3a626c4fec4a024a9fa8c7679c39996e92916f0" + integrity sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA== + +"@esbuild/darwin-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz#a5e1252ca2983d566af1c0ea39aded65736fc66d" + integrity sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw== + +"@esbuild/darwin-x64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz#5271b0df2bb12ce8df886704bfdd1c7cc01385d2" + integrity sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg== + +"@esbuild/freebsd-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz#d0a0e7fdf19733b8bb1566b81df1aa0bb7e46ada" + integrity sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA== + +"@esbuild/freebsd-x64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz#2de8b2e0899d08f1cb1ef3128e159616e7e85343" + integrity sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw== + +"@esbuild/linux-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz#a4209efadc0c2975716458484a4e90c237c48ae9" + integrity sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w== + +"@esbuild/linux-arm@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz#ccd9e291c24cd8d9142d819d463e2e7200d25b19" + integrity sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg== + +"@esbuild/linux-ia32@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz#006ad1536d0c2b28fb3a1cf0b53bcb85aaf92c4d" + integrity sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg== + +"@esbuild/linux-loong64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz#127b3fbfb2c2e08b1397e985932f718f09a8f5c4" + integrity sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ== + +"@esbuild/linux-mips64el@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz#837d1449517791e3fa7d82675a2d06d9f56cb340" + integrity sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw== + +"@esbuild/linux-ppc64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz#aa2e3bd93ab8df084212f1895ca4b03c42d9e0fe" + integrity sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ== + +"@esbuild/linux-riscv64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz#a340620e31093fef72767dd28ab04214b3442083" + integrity sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg== + +"@esbuild/linux-s390x@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz#ddfed266c8c13f5efb3105a0cd47f6dcd0e79e71" + integrity sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg== + +"@esbuild/linux-x64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz#9a4f78c75c051e8c060183ebb39a269ba936a2ac" + integrity sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ== + +"@esbuild/netbsd-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz#902c80e1d678047926387230bc037e63e00697d0" + integrity sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw== + +"@esbuild/netbsd-x64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz#2d9eb4692add2681ff05a14ce99de54fbed7079c" + integrity sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg== + +"@esbuild/openbsd-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz#89c3b998c6de739db38ab7fb71a8a76b3fa84a45" + integrity sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ== + +"@esbuild/openbsd-x64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz#2f01615cf472b0e48c077045cfd96b5c149365cc" + integrity sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ== + +"@esbuild/openharmony-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz#a201f720cd2c3ebf9a6033fcc3feb069a54b509a" + integrity sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg== + +"@esbuild/sunos-x64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz#07046c977985a3334667f19e6ab3a01a80862afb" + integrity sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w== + +"@esbuild/win32-arm64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz#4a5470caf0d16127c05d4833d4934213c69392d1" + integrity sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ== + +"@esbuild/win32-ia32@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz#3de3e8470b7b328d99dbc3e9ec1eace207e5bbc4" + integrity sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg== + +"@esbuild/win32-x64@0.25.8": + version "0.25.8" + resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz#610d7ea539d2fcdbe39237b5cc175eb2c4451f9c" + integrity sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw== + +"@floating-ui/core@^1.7.2": + version "1.7.2" + resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.2.tgz#3d1c35263950b314b6d5a72c8bfb9e3c1551aefd" + integrity sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw== + dependencies: + "@floating-ui/utils" "^0.2.10" + +"@floating-ui/dom@^1.0.1": + version "1.7.2" + resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.2.tgz#3540b051cf5ce0d4f4db5fb2507a76e8ea5b4a45" + integrity sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA== + dependencies: + "@floating-ui/core" "^1.7.2" + "@floating-ui/utils" "^0.2.10" + +"@floating-ui/utils@^0.2.10": + version "0.2.10" + resolved "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c" + integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.12" + resolved "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b" + integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.4" + resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" + integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.29" + resolved "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" + integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@microsoft/api-extractor-model@7.30.6": + version "7.30.6" + resolved "https://registry.npmmirror.com/@microsoft/api-extractor-model/-/api-extractor-model-7.30.6.tgz#cd9c434521dda3b226cc0f6aefb9c20afaf99c92" + integrity sha512-znmFn69wf/AIrwHya3fxX6uB5etSIn6vg4Q4RB/tb5VDDs1rqREc+AvMC/p19MUN13CZ7+V/8pkYPTj7q8tftg== + dependencies: + "@microsoft/tsdoc" "~0.15.1" + "@microsoft/tsdoc-config" "~0.17.1" + "@rushstack/node-core-library" "5.13.1" + +"@microsoft/api-extractor@^7.50.1": + version "7.52.8" + resolved "https://registry.npmmirror.com/@microsoft/api-extractor/-/api-extractor-7.52.8.tgz#7cc944f44ca1b1ad9d7272ab5d98e81987c1f8ca" + integrity sha512-cszYIcjiNscDoMB1CIKZ3My61+JOhpERGlGr54i6bocvGLrcL/wo9o+RNXMBrb7XgLtKaizZWUpqRduQuHQLdg== + dependencies: + "@microsoft/api-extractor-model" "7.30.6" + "@microsoft/tsdoc" "~0.15.1" + "@microsoft/tsdoc-config" "~0.17.1" + "@rushstack/node-core-library" "5.13.1" + "@rushstack/rig-package" "0.5.3" + "@rushstack/terminal" "0.15.3" + "@rushstack/ts-command-line" "5.0.1" + lodash "~4.17.15" + minimatch "~3.0.3" + resolve "~1.22.1" + semver "~7.5.4" + source-map "~0.6.1" + typescript "5.8.2" + +"@microsoft/tsdoc-config@~0.17.1": + version "0.17.1" + resolved "https://registry.npmmirror.com/@microsoft/tsdoc-config/-/tsdoc-config-0.17.1.tgz#e0f0b50628f4ad7fe121ca616beacfe6a25b9335" + integrity sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw== + dependencies: + "@microsoft/tsdoc" "0.15.1" + ajv "~8.12.0" + jju "~1.4.0" + resolve "~1.22.2" + +"@microsoft/tsdoc@0.15.1", "@microsoft/tsdoc@~0.15.1": + version "0.15.1" + resolved "https://registry.npmmirror.com/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz#d4f6937353bc4568292654efb0a0e0532adbcba2" + integrity sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw== + +"@parcel/watcher-android-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1" + integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== + +"@parcel/watcher-darwin-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67" + integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== + +"@parcel/watcher-darwin-x64@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8" + integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== + +"@parcel/watcher-freebsd-x64@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b" + integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== + +"@parcel/watcher-linux-arm-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1" + integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== + +"@parcel/watcher-linux-arm-musl@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e" + integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== + +"@parcel/watcher-linux-arm64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30" + integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== + +"@parcel/watcher-linux-arm64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2" + integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== + +"@parcel/watcher-linux-x64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e" + integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== + +"@parcel/watcher-linux-x64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee" + integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== + +"@parcel/watcher-win32-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243" + integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== + +"@parcel/watcher-win32-ia32@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6" + integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== + +"@parcel/watcher-win32-x64@2.5.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947" + integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA== + +"@parcel/watcher@^2.4.1": + version "2.5.1" + resolved "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200" + integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg== + dependencies: + detect-libc "^1.0.3" + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.5.1" + "@parcel/watcher-darwin-arm64" "2.5.1" + "@parcel/watcher-darwin-x64" "2.5.1" + "@parcel/watcher-freebsd-x64" "2.5.1" + "@parcel/watcher-linux-arm-glibc" "2.5.1" + "@parcel/watcher-linux-arm-musl" "2.5.1" + "@parcel/watcher-linux-arm64-glibc" "2.5.1" + "@parcel/watcher-linux-arm64-musl" "2.5.1" + "@parcel/watcher-linux-x64-glibc" "2.5.1" + "@parcel/watcher-linux-x64-musl" "2.5.1" + "@parcel/watcher-win32-arm64" "2.5.1" + "@parcel/watcher-win32-ia32" "2.5.1" + "@parcel/watcher-win32-x64" "2.5.1" + +"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7": + version "2.11.7" + resolved "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671" + integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ== + +"@rolldown/pluginutils@^1.0.0-beta.9": + version "1.0.0-beta.28" + resolved "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.28.tgz#3a5887a3cd4b556afedf1f4a282fd061e2bb2524" + integrity sha512-fe3/1HZ3qJmXvkGv1kacKq2b+x9gbcyF1hnmLBVrRFEQWoOcRapQjXf8+hgyxI0EJAbnKEtrp5yhohQCFCjycw== + +"@rollup/pluginutils@^5.1.4": + version "5.2.0" + resolved "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.2.0.tgz#eac25ca5b0bdda4ba735ddaca5fbf26bd435f602" + integrity sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + +"@rollup/rollup-android-arm-eabi@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz#8560592f0dcf43b8cb0949af9f1d916205148d12" + integrity sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA== + +"@rollup/rollup-android-arm64@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz#6bfb777bbce998691b6fd3e916b05cd46392d020" + integrity sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ== + +"@rollup/rollup-darwin-arm64@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz#7efce10220293a22e7b7b595d05d8b8400a7bcf3" + integrity sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA== + +"@rollup/rollup-darwin-x64@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz#c617a8ece21050bfbea299c126767d2e70cfa79a" + integrity sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og== + +"@rollup/rollup-freebsd-arm64@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz#5a6af0a9acf82162d2910933649ae24fc0ea3ecb" + integrity sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g== + +"@rollup/rollup-freebsd-x64@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz#ae9709463560196fc275bd0da598668a2e341023" + integrity sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A== + +"@rollup/rollup-linux-arm-gnueabihf@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz#6ec52661764dbd54c19d6520a403aa385a5c0fbf" + integrity sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q== + +"@rollup/rollup-linux-arm-musleabihf@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz#fd33ba4a43ef8419e96811236493d19436271923" + integrity sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q== + +"@rollup/rollup-linux-arm64-gnu@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz#933b3d99b73c9d7bf4506cab0d5d313c7e74fd2d" + integrity sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw== + +"@rollup/rollup-linux-arm64-musl@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz#dbe9ae24ee9e97b75662fddcb69eb7f23c89280a" + integrity sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog== + +"@rollup/rollup-linux-loongarch64-gnu@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz#818c5a071eec744436dbcdd76fe9c3c869dc9a8d" + integrity sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg== + +"@rollup/rollup-linux-powerpc64le-gnu@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz#6b8591def27d886fa147fb0340126c7d6682a7e4" + integrity sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg== + +"@rollup/rollup-linux-riscv64-gnu@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz#f1861ac4ee8da64e0b0d23853ff26fe2baa876cf" + integrity sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw== + +"@rollup/rollup-linux-riscv64-musl@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz#320c961401a923b374e358664527b188e374e1ae" + integrity sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA== + +"@rollup/rollup-linux-s390x-gnu@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz#1763eed3362b50b6164d3f0947486c03cc7e616d" + integrity sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw== + +"@rollup/rollup-linux-x64-gnu@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz#0d4c8d0b8f801902f0844a40a9d981a0179f4971" + integrity sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw== + +"@rollup/rollup-linux-x64-musl@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz#ec30bb48b5fe22a3aaba98072f2d5b7139e1a8eb" + integrity sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw== + +"@rollup/rollup-win32-arm64-msvc@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz#27a6e48d1502e8e4bed96bedfb533738655874f2" + integrity sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg== + +"@rollup/rollup-win32-ia32-msvc@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz#a2fbad3bec20ff879f3fd51720adf33692ca8f3d" + integrity sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw== + +"@rollup/rollup-win32-x64-msvc@4.45.1": + version "4.45.1" + resolved "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz#e5085c6d13da15b4c5133cd2a6bb11f25b6bb77a" + integrity sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA== + +"@rushstack/node-core-library@5.13.1": + version "5.13.1" + resolved "https://registry.npmmirror.com/@rushstack/node-core-library/-/node-core-library-5.13.1.tgz#e56b915ecb08b5a92711acac6b233417353a32dc" + integrity sha512-5yXhzPFGEkVc9Fu92wsNJ9jlvdwz4RNb2bMso+/+TH0nMm1jDDDsOIf4l8GAkPxGuwPw5DH24RliWVfSPhlW/Q== + dependencies: + ajv "~8.13.0" + ajv-draft-04 "~1.0.0" + ajv-formats "~3.0.1" + fs-extra "~11.3.0" + import-lazy "~4.0.0" + jju "~1.4.0" + resolve "~1.22.1" + semver "~7.5.4" + +"@rushstack/rig-package@0.5.3": + version "0.5.3" + resolved "https://registry.npmmirror.com/@rushstack/rig-package/-/rig-package-0.5.3.tgz#ea4d8a3458540b1295500149c04e645f23134e5d" + integrity sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow== + dependencies: + resolve "~1.22.1" + strip-json-comments "~3.1.1" + +"@rushstack/terminal@0.15.3": + version "0.15.3" + resolved "https://registry.npmmirror.com/@rushstack/terminal/-/terminal-0.15.3.tgz#365e0ae5ac73bb4883b096ae36c5011f52911861" + integrity sha512-DGJ0B2Vm69468kZCJkPj3AH5nN+nR9SPmC0rFHtzsS4lBQ7/dgOwtwVxYP7W9JPDMuRBkJ4KHmWKr036eJsj9g== + dependencies: + "@rushstack/node-core-library" "5.13.1" + supports-color "~8.1.1" + +"@rushstack/ts-command-line@5.0.1": + version "5.0.1" + resolved "https://registry.npmmirror.com/@rushstack/ts-command-line/-/ts-command-line-5.0.1.tgz#e147394b5ce87ef79db95b5b4f155461d6f2c50e" + integrity sha512-bsbUucn41UXrQK7wgM8CNM/jagBytEyJqXw/umtI8d68vFm1Jwxh1OtLrlW7uGZgjCWiiPH6ooUNa1aVsuVr3Q== + dependencies: + "@rushstack/terminal" "0.15.3" + "@types/argparse" "1.0.38" + argparse "~1.0.9" + string-argv "~0.3.1" + +"@types/argparse@1.0.38": + version "1.0.38" + resolved "https://registry.npmmirror.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" + integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA== + +"@types/estree@1.0.8", "@types/estree@^1.0.0": + version "1.0.8" + resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/lodash-es@^4.17.6": + version "4.17.12" + resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b" + integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*", "@types/lodash@^4.14.182": + version "4.17.20" + resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.20.tgz#1ca77361d7363432d29f5e55950d9ec1e1c6ea93" + integrity sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA== + +"@types/node@^20.11.16": + version "20.19.9" + resolved "https://registry.npmmirror.com/@types/node/-/node-20.19.9.tgz#ca9a58193fec361cc6e859d88b52261853f1f0d3" + integrity sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw== + dependencies: + undici-types "~6.21.0" + +"@types/web-bluetooth@^0.0.16": + version "0.0.16" + resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8" + integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ== + +"@vitejs/plugin-vue-jsx@^4.1.1": + version "4.2.0" + resolved "https://registry.npmmirror.com/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-4.2.0.tgz#2738ec05d4705ed553a107342017192e37351640" + integrity sha512-DSTrmrdLp+0LDNF77fqrKfx7X0ErRbOcUAgJL/HbSesqQwoUvUQ4uYQqaex+rovqgGcoPqVk+AwUh3v9CuiYIw== + dependencies: + "@babel/core" "^7.27.1" + "@babel/plugin-transform-typescript" "^7.27.1" + "@rolldown/pluginutils" "^1.0.0-beta.9" + "@vue/babel-plugin-jsx" "^1.4.0" + +"@vitejs/plugin-vue@^5.2.1": + version "5.2.4" + resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz#9e8a512eb174bfc2a333ba959bbf9de428d89ad8" + integrity sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA== + +"@volar/language-core@2.4.15": + version "2.4.15" + resolved "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.15.tgz#759d04cb4eab9920560b8bcfa4515d5b08a1b7ce" + integrity sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA== + dependencies: + "@volar/source-map" "2.4.15" + +"@volar/language-core@2.4.20", "@volar/language-core@~2.4.11": + version "2.4.20" + resolved "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.20.tgz#be6d4efc6bb2f77d6c01bbbb3ef53661a869e0d0" + integrity sha512-dRDF1G33xaAIDqR6+mXUIjXYdu9vzSxlMGfMEwBxQsfY/JMUEXSpLTR057oTKlUQ2nIvCmP9k94A8h8z2VrNSA== + dependencies: + "@volar/source-map" "2.4.20" + +"@volar/source-map@2.4.15": + version "2.4.15" + resolved "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.15.tgz#18aba09994c0268e59a418f9d738e4a85302781d" + integrity sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg== + +"@volar/source-map@2.4.20": + version "2.4.20" + resolved "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.20.tgz#55ff844410d8d670ef2c3722e2717223edbf8717" + integrity sha512-mVjmFQH8mC+nUaVwmbxoYUy8cww+abaO8dWzqPUjilsavjxH0jCJ3Mp8HFuHsdewZs2c+SP+EO7hCd8Z92whJg== + +"@volar/typescript@2.4.15": + version "2.4.15" + resolved "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.15.tgz#1445d23f8e4f9ad821b6bfa58cf4a2b980dc5f97" + integrity sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg== + dependencies: + "@volar/language-core" "2.4.15" + path-browserify "^1.0.1" + vscode-uri "^3.0.8" + +"@volar/typescript@^2.4.11": + version "2.4.20" + resolved "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.20.tgz#c388d6fe5ee31ddeb5338d01dbbfc71054065a7c" + integrity sha512-Oc4DczPwQyXcVbd+5RsNEqX6ia0+w3p+klwdZQ6ZKhFjWoBP9PCPQYlKYRi/tDemWphW93P/Vv13vcE9I9D2GQ== + dependencies: + "@volar/language-core" "2.4.20" + path-browserify "^1.0.1" + vscode-uri "^3.0.8" + +"@vue/babel-helper-vue-transform-on@1.4.0": + version "1.4.0" + resolved "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.4.0.tgz#616020488692a9c42a613280d62ed1b727045d95" + integrity sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw== + +"@vue/babel-plugin-jsx@^1.4.0": + version "1.4.0" + resolved "https://registry.npmmirror.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.4.0.tgz#c155c795ce980edf46aa6feceed93945a95ca658" + integrity sha512-9zAHmwgMWlaN6qRKdrg1uKsBKHvnUU+Py+MOCTuYZBoZsopa90Di10QRjB+YPnVss0BZbG/H5XFwJY1fTxJWhA== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/plugin-syntax-jsx" "^7.25.9" + "@babel/template" "^7.26.9" + "@babel/traverse" "^7.26.9" + "@babel/types" "^7.26.9" + "@vue/babel-helper-vue-transform-on" "1.4.0" + "@vue/babel-plugin-resolve-type" "1.4.0" + "@vue/shared" "^3.5.13" + +"@vue/babel-plugin-resolve-type@1.4.0": + version "1.4.0" + resolved "https://registry.npmmirror.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.4.0.tgz#4d357a81fb0cc9cad0e8c81b118115bda2c51543" + integrity sha512-4xqDRRbQQEWHQyjlYSgZsWj44KfiF6D+ktCuXyZ8EnVDYV3pztmXJDf1HveAjUAXxAnR8daCQT51RneWWxtTyQ== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/parser" "^7.26.9" + "@vue/compiler-sfc" "^3.5.13" + +"@vue/compiler-core@3.5.17": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.17.tgz#23d291bd01b863da3ef2e26e7db84d8e01a9b4c5" + integrity sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA== + dependencies: + "@babel/parser" "^7.27.5" + "@vue/shared" "3.5.17" + entities "^4.5.0" + estree-walker "^2.0.2" + source-map-js "^1.2.1" + +"@vue/compiler-dom@3.5.17", "@vue/compiler-dom@^3.5.0": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz#7bc19a20e23b670243a64b47ce3a890239b870be" + integrity sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ== + dependencies: + "@vue/compiler-core" "3.5.17" + "@vue/shared" "3.5.17" + +"@vue/compiler-sfc@3.5.17", "@vue/compiler-sfc@^3.5.13": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz#c518871276e26593612bdab36f3f5bcd053b13bf" + integrity sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww== + dependencies: + "@babel/parser" "^7.27.5" + "@vue/compiler-core" "3.5.17" + "@vue/compiler-dom" "3.5.17" + "@vue/compiler-ssr" "3.5.17" + "@vue/shared" "3.5.17" + estree-walker "^2.0.2" + magic-string "^0.30.17" + postcss "^8.5.6" + source-map-js "^1.2.1" + +"@vue/compiler-ssr@3.5.17": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz#14ba3b7bba6e0e1fd02002316263165a5d1046c7" + integrity sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ== + dependencies: + "@vue/compiler-dom" "3.5.17" + "@vue/shared" "3.5.17" + +"@vue/compiler-vue2@^2.7.16": + version "2.7.16" + resolved "https://registry.npmmirror.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz#2ba837cbd3f1b33c2bc865fbe1a3b53fb611e249" + integrity sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A== + dependencies: + de-indent "^1.0.2" + he "^1.2.0" + +"@vue/language-core@2.2.0": + version "2.2.0" + resolved "https://registry.npmmirror.com/@vue/language-core/-/language-core-2.2.0.tgz#e48c54584f889f78b120ce10a050dfb316c7fcdf" + integrity sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw== + dependencies: + "@volar/language-core" "~2.4.11" + "@vue/compiler-dom" "^3.5.0" + "@vue/compiler-vue2" "^2.7.16" + "@vue/shared" "^3.5.0" + alien-signals "^0.4.9" + minimatch "^9.0.3" + muggle-string "^0.4.1" + path-browserify "^1.0.1" + +"@vue/language-core@2.2.12": + version "2.2.12" + resolved "https://registry.npmmirror.com/@vue/language-core/-/language-core-2.2.12.tgz#d01f7e865f593f968cb65c12a13d8337e65641f0" + integrity sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA== + dependencies: + "@volar/language-core" "2.4.15" + "@vue/compiler-dom" "^3.5.0" + "@vue/compiler-vue2" "^2.7.16" + "@vue/shared" "^3.5.0" + alien-signals "^1.0.3" + minimatch "^9.0.3" + muggle-string "^0.4.1" + path-browserify "^1.0.1" + +"@vue/reactivity@3.5.17": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.17.tgz#169b5dcf96c7f23788e5ed9745ec8a7227f2125e" + integrity sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw== + dependencies: + "@vue/shared" "3.5.17" + +"@vue/runtime-core@3.5.17", "@vue/runtime-core@^3.5.13": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.17.tgz#b17bd41e13011e85e9b1025545292d43f5512730" + integrity sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q== + dependencies: + "@vue/reactivity" "3.5.17" + "@vue/shared" "3.5.17" + +"@vue/runtime-dom@3.5.17": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz#8e325e29cd03097fe179032fc8df384a426fc83a" + integrity sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g== + dependencies: + "@vue/reactivity" "3.5.17" + "@vue/runtime-core" "3.5.17" + "@vue/shared" "3.5.17" + csstype "^3.1.3" + +"@vue/server-renderer@3.5.17": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.17.tgz#9b8fd6a40a3d55322509fafe78ac841ede649fbe" + integrity sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA== + dependencies: + "@vue/compiler-ssr" "3.5.17" + "@vue/shared" "3.5.17" + +"@vue/shared@3.5.17", "@vue/shared@^3.5.0", "@vue/shared@^3.5.13": + version "3.5.17" + resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.17.tgz#e8b3a41f0be76499882a89e8ed40d86a70fa4b70" + integrity sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg== + +"@vueuse/core@^9.1.0": + version "9.13.0" + resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4" + integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw== + dependencies: + "@types/web-bluetooth" "^0.0.16" + "@vueuse/metadata" "9.13.0" + "@vueuse/shared" "9.13.0" + vue-demi "*" + +"@vueuse/metadata@9.13.0": + version "9.13.0" + resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff" + integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ== + +"@vueuse/shared@9.13.0": + version "9.13.0" + resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9" + integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw== + dependencies: + vue-demi "*" + +acorn@^8.14.0: + version "8.15.0" + resolved "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +ajv-draft-04@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" + integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw== + +ajv-formats@~3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578" + integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ== + dependencies: + ajv "^8.0.0" + +ajv@^8.0.0: + version "8.17.1" + resolved "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ajv@~8.12.0: + version "8.12.0" + resolved "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ajv@~8.13.0: + version "8.13.0" + resolved "https://registry.npmmirror.com/ajv/-/ajv-8.13.0.tgz#a3939eaec9fb80d217ddf0c3376948c023f28c91" + integrity sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA== + dependencies: + fast-deep-equal "^3.1.3" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.4.1" + +alien-signals@^0.4.9: + version "0.4.14" + resolved "https://registry.npmmirror.com/alien-signals/-/alien-signals-0.4.14.tgz#9ff8f72a272300a51692f54bd9bbbada78fbf539" + integrity sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q== + +alien-signals@^1.0.3: + version "1.0.13" + resolved "https://registry.npmmirror.com/alien-signals/-/alien-signals-1.0.13.tgz#8d6db73462f742ee6b89671fbd8c37d0b1727a7e" + integrity sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg== + +argparse@~1.0.9: + version "1.0.10" + resolved "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +async-validator@^4.2.5: + version "4.2.5" + resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339" + integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0: + version "4.25.1" + resolved "https://registry.npmmirror.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111" + integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== + dependencies: + caniuse-lite "^1.0.30001726" + electron-to-chromium "^1.5.173" + node-releases "^2.0.19" + update-browserslist-db "^1.1.3" + +caniuse-lite@^1.0.30001726: + version "1.0.30001727" + resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz#22e9706422ad37aa50556af8c10e40e2d93a8b85" + integrity sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q== + +chokidar@^4.0.0: + version "4.0.3" + resolved "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +compare-versions@^6.1.1: + version "6.1.1" + resolved "https://registry.npmmirror.com/compare-versions/-/compare-versions-6.1.1.tgz#7af3cc1099ba37d244b3145a9af5201b629148a9" + integrity sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + +confbox@^0.2.2: + version "0.2.2" + resolved "https://registry.npmmirror.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110" + integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +csstype@^3.1.3: + version "3.1.3" + resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +dayjs@^1.11.13: + version "1.11.13" + resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== + +debug@^4.1.0, debug@^4.3.1, debug@^4.4.0: + version "4.4.1" + resolved "https://registry.npmmirror.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +electron-to-chromium@^1.5.173: + version "1.5.187" + resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.187.tgz#8c58854e065962351dc87e95614dd78d50425966" + integrity sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA== + +element-plus@^2.10.4: + version "2.10.4" + resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.10.4.tgz#72de60a6074be79f9f1b299f422e7ac96a3b5e9a" + integrity sha512-UD4elWHrCnp1xlPhbXmVcaKFLCRaRAY6WWRwemGfGW3ceIjXm9fSYc9RNH3AiOEA6Ds1p9ZvhCs76CR9J8Vd+A== + dependencies: + "@ctrl/tinycolor" "^3.4.1" + "@element-plus/icons-vue" "^2.3.1" + "@floating-ui/dom" "^1.0.1" + "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7" + "@types/lodash" "^4.14.182" + "@types/lodash-es" "^4.17.6" + "@vueuse/core" "^9.1.0" + async-validator "^4.2.5" + dayjs "^1.11.13" + escape-html "^1.0.3" + lodash "^4.17.21" + lodash-es "^4.17.21" + lodash-unified "^1.0.2" + memoize-one "^6.0.0" + normalize-wheel-es "^1.2.0" + +entities@^4.5.0: + version "4.5.0" + resolved "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +esbuild@^0.25.0: + version "0.25.8" + resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.8.tgz#482d42198b427c9c2f3a81b63d7663aecb1dda07" + integrity sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.8" + "@esbuild/android-arm" "0.25.8" + "@esbuild/android-arm64" "0.25.8" + "@esbuild/android-x64" "0.25.8" + "@esbuild/darwin-arm64" "0.25.8" + "@esbuild/darwin-x64" "0.25.8" + "@esbuild/freebsd-arm64" "0.25.8" + "@esbuild/freebsd-x64" "0.25.8" + "@esbuild/linux-arm" "0.25.8" + "@esbuild/linux-arm64" "0.25.8" + "@esbuild/linux-ia32" "0.25.8" + "@esbuild/linux-loong64" "0.25.8" + "@esbuild/linux-mips64el" "0.25.8" + "@esbuild/linux-ppc64" "0.25.8" + "@esbuild/linux-riscv64" "0.25.8" + "@esbuild/linux-s390x" "0.25.8" + "@esbuild/linux-x64" "0.25.8" + "@esbuild/netbsd-arm64" "0.25.8" + "@esbuild/netbsd-x64" "0.25.8" + "@esbuild/openbsd-arm64" "0.25.8" + "@esbuild/openbsd-x64" "0.25.8" + "@esbuild/openharmony-arm64" "0.25.8" + "@esbuild/sunos-x64" "0.25.8" + "@esbuild/win32-arm64" "0.25.8" + "@esbuild/win32-ia32" "0.25.8" + "@esbuild/win32-x64" "0.25.8" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +exsolve@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/exsolve/-/exsolve-1.0.7.tgz#3b74e4c7ca5c5f9a19c3626ca857309fa99f9e9e" + integrity sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== + +fdir@^6.4.4: + version "6.4.6" + resolved "https://registry.npmmirror.com/fdir/-/fdir-6.4.6.tgz#2b268c0232697063111bbf3f64810a2a741ba281" + integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +fs-extra@~11.3.0: + version "11.3.0" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d" + integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +immutable@^5.0.2: + version "5.1.3" + resolved "https://registry.npmmirror.com/immutable/-/immutable-5.1.3.tgz#e6486694c8b76c37c063cca92399fa64098634d4" + integrity sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg== + +import-lazy@~4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== + +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +jju@~1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +kolorist@^1.8.0: + version "1.8.0" + resolved "https://registry.npmmirror.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + +local-pkg@^1.0.0: + version "1.1.1" + resolved "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.1.tgz#f5fe74a97a3bd3c165788ee08ca9fbe998dc58dd" + integrity sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg== + dependencies: + mlly "^1.7.4" + pkg-types "^2.0.1" + quansync "^0.2.8" + +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash-unified@^1.0.2: + version "1.0.3" + resolved "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz#80b1eac10ed2eb02ed189f08614a29c27d07c894" + integrity sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ== + +lodash@^4.17.21, lodash@~4.17.15: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.30.17: + version "0.30.17" + resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + +micromatch@^4.0.5: + version "4.0.8" + resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +minimatch@^9.0.3: + version "9.0.5" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimatch@~3.0.3: + version "3.0.8" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== + dependencies: + brace-expansion "^1.1.7" + +mlly@^1.7.4: + version "1.7.4" + resolved "https://registry.npmmirror.com/mlly/-/mlly-1.7.4.tgz#3d7295ea2358ec7a271eaa5d000a0f84febe100f" + integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw== + dependencies: + acorn "^8.14.0" + pathe "^2.0.1" + pkg-types "^1.3.0" + ufo "^1.5.4" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +muggle-string@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz#3b366bd43b32f809dc20659534dd30e7c8a0d328" + integrity sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ== + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +normalize-wheel-es@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e" + integrity sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw== + +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pathe@^2.0.1, pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.3" + resolved "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +pkg-types@^1.3.0: + version "1.3.1" + resolved "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== + dependencies: + confbox "^0.1.8" + mlly "^1.7.4" + pathe "^2.0.1" + +pkg-types@^2.0.1: + version "2.2.0" + resolved "https://registry.npmmirror.com/pkg-types/-/pkg-types-2.2.0.tgz#049bf404f82a66c465200149457acf0c5fb0fb2d" + integrity sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ== + dependencies: + confbox "^0.2.2" + exsolve "^1.0.7" + pathe "^2.0.3" + +postcss@^8.5.3, postcss@^8.5.6: + version "8.5.6" + resolved "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +prettier@^3.5.1: + version "3.6.2" + resolved "https://registry.npmmirror.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" + integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +quansync@^0.2.8: + version "0.2.10" + resolved "https://registry.npmmirror.com/quansync/-/quansync-0.2.10.tgz#32053cf166fa36511aae95fc49796116f2dc20e1" + integrity sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A== + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve@~1.22.1, resolve@~1.22.2: + version "1.22.10" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rollup@^4.34.9: + version "4.45.1" + resolved "https://registry.npmmirror.com/rollup/-/rollup-4.45.1.tgz#d0ef72a8d0a9210d832f9c3c5f3b6a2aa4b0ba64" + integrity sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.45.1" + "@rollup/rollup-android-arm64" "4.45.1" + "@rollup/rollup-darwin-arm64" "4.45.1" + "@rollup/rollup-darwin-x64" "4.45.1" + "@rollup/rollup-freebsd-arm64" "4.45.1" + "@rollup/rollup-freebsd-x64" "4.45.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.45.1" + "@rollup/rollup-linux-arm-musleabihf" "4.45.1" + "@rollup/rollup-linux-arm64-gnu" "4.45.1" + "@rollup/rollup-linux-arm64-musl" "4.45.1" + "@rollup/rollup-linux-loongarch64-gnu" "4.45.1" + "@rollup/rollup-linux-powerpc64le-gnu" "4.45.1" + "@rollup/rollup-linux-riscv64-gnu" "4.45.1" + "@rollup/rollup-linux-riscv64-musl" "4.45.1" + "@rollup/rollup-linux-s390x-gnu" "4.45.1" + "@rollup/rollup-linux-x64-gnu" "4.45.1" + "@rollup/rollup-linux-x64-musl" "4.45.1" + "@rollup/rollup-win32-arm64-msvc" "4.45.1" + "@rollup/rollup-win32-ia32-msvc" "4.45.1" + "@rollup/rollup-win32-x64-msvc" "4.45.1" + fsevents "~2.3.2" + +sass-loader@^16.0.5: + version "16.0.5" + resolved "https://registry.npmmirror.com/sass-loader/-/sass-loader-16.0.5.tgz#257bc90119ade066851cafe7f2c3f3504c7cda98" + integrity sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw== + dependencies: + neo-async "^2.6.2" + +sass@^1.85.0: + version "1.89.2" + resolved "https://registry.npmmirror.com/sass/-/sass-1.89.2.tgz#a771716aeae774e2b529f72c0ff2dfd46c9de10e" + integrity sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA== + dependencies: + chokidar "^4.0.0" + immutable "^5.0.2" + source-map-js ">=0.6.2 <2.0.0" + optionalDependencies: + "@parcel/watcher" "^2.4.1" + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@~7.5.4: + version "7.5.4" + resolved "https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +string-argv@~0.3.1: + version "0.3.2" + resolved "https://registry.npmmirror.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + +strip-json-comments@~3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@~8.1.1: + version "8.1.1" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tinyglobby@^0.2.13: + version "0.2.14" + resolved "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" + integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== + dependencies: + fdir "^6.4.4" + picomatch "^4.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +typescript@5.8.2: + version "5.8.2" + resolved "https://registry.npmmirror.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4" + integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ== + +typescript@^5.3.3: + version "5.8.3" + resolved "https://registry.npmmirror.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + +ufo@^1.5.4: + version "1.6.1" + resolved "https://registry.npmmirror.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" + integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2, uri-js@^4.4.1: + version "4.4.1" + resolved "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +vite-plugin-dts@^4.5.0: + version "4.5.4" + resolved "https://registry.npmmirror.com/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz#51b60aaaa760d9cf5c2bb3676c69d81910d6b08c" + integrity sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg== + dependencies: + "@microsoft/api-extractor" "^7.50.1" + "@rollup/pluginutils" "^5.1.4" + "@volar/typescript" "^2.4.11" + "@vue/language-core" "2.2.0" + compare-versions "^6.1.1" + debug "^4.4.0" + kolorist "^1.8.0" + local-pkg "^1.0.0" + magic-string "^0.30.17" + +vite@^6.1.0: + version "6.3.5" + resolved "https://registry.npmmirror.com/vite/-/vite-6.3.5.tgz#fec73879013c9c0128c8d284504c6d19410d12a3" + integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ== + dependencies: + esbuild "^0.25.0" + fdir "^6.4.4" + picomatch "^4.0.2" + postcss "^8.5.3" + rollup "^4.34.9" + tinyglobby "^0.2.13" + optionalDependencies: + fsevents "~2.3.3" + +vscode-uri@^3.0.8: + version "3.1.0" + resolved "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c" + integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ== + +vue-demi@*: + version "0.14.10" + resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04" + integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg== + +vue-tsc@^2.2.2: + version "2.2.12" + resolved "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-2.2.12.tgz#5f719b08ef7390a763c1a20169ca5c9d09d55688" + integrity sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw== + dependencies: + "@volar/typescript" "2.4.15" + "@vue/language-core" "2.2.12" + +vue@^3.5.13: + version "3.5.17" + resolved "https://registry.npmmirror.com/vue/-/vue-3.5.17.tgz#ea8a6a45abb2b0620e7d479319ce8434b55650cf" + integrity sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g== + dependencies: + "@vue/compiler-dom" "3.5.17" + "@vue/compiler-sfc" "3.5.17" + "@vue/runtime-dom" "3.5.17" + "@vue/server-renderer" "3.5.17" + "@vue/shared" "3.5.17" + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== diff --git a/packages/vite-plugin/.eslintrc.js b/packages/vite-plugin/.eslintrc.js new file mode 100644 index 0000000..53106c1 --- /dev/null +++ b/packages/vite-plugin/.eslintrc.js @@ -0,0 +1,12 @@ +export default { + parser: "@typescript-eslint/parser", + extends: ["plugin:@typescript-eslint/recommended"], + parserOptions: { + project: "./tsconfig.json", + tsconfigRootDir: __dirname, + ecmaVersion: 2020, + sourceType: "module", + createDefaultProgram: true, + }, + rules: {}, +}; diff --git a/packages/vite-plugin/.prettierrc b/packages/vite-plugin/.prettierrc new file mode 100644 index 0000000..5305129 --- /dev/null +++ b/packages/vite-plugin/.prettierrc @@ -0,0 +1,8 @@ +{ + "tabWidth": 4, + "useTabs": true, + "semi": true, + "jsxBracketSameLine": true, + "singleQuote": false, + "printWidth": 100 +} diff --git a/packages/vite-plugin/client.d.ts b/packages/vite-plugin/client.d.ts new file mode 100644 index 0000000..4982a91 --- /dev/null +++ b/packages/vite-plugin/client.d.ts @@ -0,0 +1,48 @@ +declare module "virtual:ctx" { + const ctx: { + serviceLang: string; + modules: string[]; + }; + + export { ctx }; +} + +declare module "virtual:eps" { + const eps: { + isUpdate: boolean; + list: { + prefix: string; + api: { + method: string; + path: string; + summary: string; + dts: { + [key: string]: string; + }; + [key: string]: any; + }[]; + namespace: string; + name: string; + module: string; + columns: { + comment: string; + nullable: boolean; + propertyName: string; + type: string; + [key: string]: any; + }[]; + [key: string]: any; + }[]; + service: any; + }; + + export { eps }; +} + +declare module "virtual:demo"; +declare module "virtual:svg-register"; + +declare module "virtual:svg-icons" { + const svgIcons: string[]; + export { svgIcons }; +} diff --git a/packages/vite-plugin/dist/base.d.ts b/packages/vite-plugin/dist/base.d.ts new file mode 100644 index 0000000..8345a78 --- /dev/null +++ b/packages/vite-plugin/dist/base.d.ts @@ -0,0 +1,2 @@ +import type { Plugin } from "vite"; +export declare function base(): Plugin; diff --git a/packages/vite-plugin/dist/config.d.ts b/packages/vite-plugin/dist/config.d.ts new file mode 100644 index 0000000..7674c2f --- /dev/null +++ b/packages/vite-plugin/dist/config.d.ts @@ -0,0 +1,39 @@ +import type { Type } from "../types"; +export declare const config: { + type: Type; + reqUrl: string; + demo: boolean; + nameTag: boolean; + eps: { + enable: boolean; + api: string; + dist: string; + mapping: ({ + custom: ({ propertyName, type }: { + propertyName: string; + type: string; + }) => null; + type?: undefined; + test?: undefined; + } | { + type: string; + test: string[]; + custom?: undefined; + })[]; + }; + svg: { + skipNames: string[]; + }; + tailwind: { + enable: boolean; + remUnit: number; + remPrecision: number; + rpxRatio: number; + darkTextClass: string; + }; + uniapp: { + isPlugin: boolean; + }; + clean: boolean; + utsPlatform: string; +}; diff --git a/packages/vite-plugin/dist/ctx/index.d.ts b/packages/vite-plugin/dist/ctx/index.d.ts new file mode 100644 index 0000000..87eafb6 --- /dev/null +++ b/packages/vite-plugin/dist/ctx/index.d.ts @@ -0,0 +1,2 @@ +import type { Ctx } from "../../types"; +export declare function createCtx(): Promise; diff --git a/packages/vite-plugin/dist/demo.d.ts b/packages/vite-plugin/dist/demo.d.ts new file mode 100644 index 0000000..5f66c93 --- /dev/null +++ b/packages/vite-plugin/dist/demo.d.ts @@ -0,0 +1,2 @@ +import type { Plugin } from "vite"; +export declare function demo(enable?: boolean): Plugin; diff --git a/packages/vite-plugin/dist/eps/flatten.d.ts b/packages/vite-plugin/dist/eps/flatten.d.ts new file mode 100644 index 0000000..8aba397 --- /dev/null +++ b/packages/vite-plugin/dist/eps/flatten.d.ts @@ -0,0 +1,7 @@ +/** + * 将模板字符串扁平化处理,转换为 Service 类型定义 + * @param template - 包含 Service 类型定义的模板字符串 + * @returns 处理后的 Service 类型定义字符串 + * @throws {Error} 当模板中找不到 Service 类型定义时抛出错误 + */ +export declare function flatten(template: string): string; diff --git a/packages/vite-plugin/dist/eps/index.d.ts b/packages/vite-plugin/dist/eps/index.d.ts new file mode 100644 index 0000000..a3719cf --- /dev/null +++ b/packages/vite-plugin/dist/eps/index.d.ts @@ -0,0 +1,18 @@ +import type { Eps } from "../../types"; +/** + * 主入口:创建 eps 相关文件和 service + */ +export declare function createEps(): Promise<{ + service: {}; + serviceCode: { + content: string; + types: string[]; + }; + list: Eps.Entity[]; + isUpdate: boolean; +} | { + service: {}; + list: never[]; + serviceCode?: undefined; + isUpdate?: undefined; +}>; diff --git a/packages/vite-plugin/dist/file/index.d.ts b/packages/vite-plugin/dist/file/index.d.ts new file mode 100644 index 0000000..c96a4b3 --- /dev/null +++ b/packages/vite-plugin/dist/file/index.d.ts @@ -0,0 +1,6 @@ +interface Item { + path: string; + code: string; +} +export declare function createFile(data: Item | Item[]): Promise; +export {}; diff --git a/packages/vite-plugin/dist/index.d.ts b/packages/vite-plugin/dist/index.d.ts new file mode 100644 index 0000000..007de2c --- /dev/null +++ b/packages/vite-plugin/dist/index.d.ts @@ -0,0 +1,2 @@ +import type { Config } from "../types"; +export declare function cool(options: Config.Options): (import("vite").Plugin | Promise> | Promise[]>)[]; diff --git a/packages/vite-plugin/dist/index.js b/packages/vite-plugin/dist/index.js new file mode 100644 index 0000000..9d64378 --- /dev/null +++ b/packages/vite-plugin/dist/index.js @@ -0,0 +1,2505 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fs'), require('path'), require('prettier'), require('axios'), require('lodash'), require('@vue/compiler-sfc'), require('magic-string'), require('glob'), require('node:util'), require('svgo'), require('postcss-value-parser')) : + typeof define === 'function' && define.amd ? define(['exports', 'fs', 'path', 'prettier', 'axios', 'lodash', '@vue/compiler-sfc', 'magic-string', 'glob', 'node:util', 'svgo', 'postcss-value-parser'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.index = {}, global.fs, global.path, global.prettier, global.axios, global.lodash, global.compilerSfc, global.magicString, global.glob, global.util, global.svgo, global.valueParser)); +})(this, (function (exports, fs, path, prettier, axios, lodash, compilerSfc, magicString, glob, util, svgo, valueParser) { 'use strict'; + + const config = { + type: "admin", + reqUrl: "", + nameTag: true, + eps: { + enable: true, + api: "", + dist: "./build/cool", + mapping: [ + { + // 自定义匹配 + custom: ({ propertyName, type }) => { + // 如果没有,返回null或者不返回,则继续遍历其他匹配规则 + return null; + }, + }, + { + type: "string", + test: ["varchar", "text", "simple-json"], + }, + { + type: "string[]", + test: ["simple-array"], + }, + { + type: "Date", + test: ["datetime", "date"], + }, + { + type: "number", + test: ["tinyint", "int", "decimal"], + }, + { + type: "BigInt", + test: ["bigint"], + }, + { + type: "any", + test: ["json"], + }, + ], + }, + svg: { + skipNames: ["base"], + }, + tailwind: { + enable: true, + remUnit: 14, + remPrecision: 6, + rpxRatio: 2, + darkTextClass: "dark:text-surface-50", + }, + uniapp: { + isPlugin: false, + }, + clean: false, + utsPlatform: "web", + }; + + // 根目录 + function rootDir(path$1) { + switch (config.type) { + case "app": + case "uniapp-x": + return path.join(process.env.UNI_INPUT_DIR, path$1); + default: + return path.join(process.cwd(), path$1); + } + } + // 首字母大写 + function firstUpperCase(value) { + return value.replace(/\b(\w)(\w*)/g, function ($0, $1, $2) { + return $1.toUpperCase() + $2; + }); + } + // 横杠转驼峰 + function toCamel(str) { + return str.replace(/([^-])(?:-+([^-]))/g, function ($0, $1, $2) { + return $1 + $2.toUpperCase(); + }); + } + // 创建目录 + function createDir(path, recursive) { + try { + if (!fs.existsSync(path)) + fs.mkdirSync(path, { recursive }); + } + catch (err) { } + } + // 读取文件 + function readFile(path, json) { + try { + const content = fs.readFileSync(path, "utf8"); + return json ? JSON.parse(removeJsonComments(content)) : content; + } + catch (err) { } + return ""; + } + // 安全地移除JSON中的注释 + function removeJsonComments(content) { + let result = ""; + let inString = false; + let stringChar = ""; + let escaped = false; + let i = 0; + while (i < content.length) { + const char = content[i]; + const nextChar = content[i + 1]; + // 处理字符串状态 + if (!inString && (char === '"' || char === "'")) { + inString = true; + stringChar = char; + result += char; + } + else if (inString && char === stringChar && !escaped) { + inString = false; + stringChar = ""; + result += char; + } + else if (inString) { + // 在字符串内,直接添加字符 + result += char; + escaped = char === "\\" && !escaped; + } + else { + // 不在字符串内,检查注释 + if (char === "/" && nextChar === "/") { + // 单行注释,跳过到行尾 + while (i < content.length && content[i] !== "\n") { + i++; + } + if (i < content.length) { + result += content[i]; // 保留换行符 + } + } + else if (char === "/" && nextChar === "*") { + // 多行注释,跳过到 */ + i += 2; + while (i < content.length - 1) { + if (content[i] === "*" && content[i + 1] === "/") { + i += 2; + break; + } + i++; + } + continue; + } + else { + result += char; + escaped = false; + } + } + i++; + } + return result; + } + // 写入文件 + function writeFile(path, data) { + try { + return fs.writeFileSync(path, data); + } + catch (err) { } + return ""; + } + // 解析body + function parseJson(req) { + return new Promise((resolve) => { + let d = ""; + req.on("data", function (chunk) { + d += chunk; + }); + req.on("end", function () { + try { + resolve(JSON.parse(d)); + } + catch { + resolve({}); + } + }); + }); + } + // 格式化内容 + function formatContent(content, options) { + return prettier.format(content, { + parser: "typescript", + useTabs: true, + tabWidth: 4, + endOfLine: "lf", + semi: true, + ...options, + }); + } + function error(message) { + console.log("\x1B[31m%s\x1B[0m", message); + } + + /** + * 将模板字符串扁平化处理,转换为 Service 类型定义 + * @param template - 包含 Service 类型定义的模板字符串 + * @returns 处理后的 Service 类型定义字符串 + * @throws {Error} 当模板中找不到 Service 类型定义时抛出错误 + */ + function flatten(template) { + // 查找 Service 类型定义的起始位置 + const startIndex = template.indexOf("export type Service = {"); + // 保留 Service 类型定义前的内容 + let header = template.substring(0, startIndex); + // 获取 Service 类型定义及其内容,去除换行和制表符 + const serviceTemplateContent = template.substring(startIndex).replace(/\n|\t/g, ""); + // 找到 Service 的内容部分 + const serviceStartIndex = serviceTemplateContent.indexOf("{") + 1; + const serviceEndIndex = findClosingBrace(serviceTemplateContent, serviceStartIndex); + const serviceInnerContent = serviceTemplateContent + .substring(serviceStartIndex, serviceEndIndex) + .trim(); + // 存储所有接口定义 + const allInterfaces = new Map(); + // 处理 Service 内容,保持原有结构但替换嵌套对象为接口引用 + const serviceContent = buildCurrentLevelContent(serviceInnerContent); + // 递归收集所有需要生成的接口 + flattenContent(serviceInnerContent, allInterfaces); + // 生成所有接口定义 + let interfaces = ""; + allInterfaces.forEach((content, key) => { + interfaces += `\nexport interface ${firstUpperCase(key)}Interface { ${content} }\n`; + }); + return `${header}${interfaces}\nexport type Service = { ${serviceContent} }`; + } + /** + * 查找匹配的右花括号位置 + * @param str - 要搜索的字符串 + * @param startIndex - 开始搜索的位置 + * @returns 匹配的右花括号位置 + * @throws {Error} 当找不到匹配的右花括号时抛出错误 + */ + function findClosingBrace(str, startIndex) { + let braceCount = 1; + let currentIndex = startIndex; + while (currentIndex < str.length && braceCount > 0) { + if (str[currentIndex] === "{") + braceCount++; + if (str[currentIndex] === "}") + braceCount--; + currentIndex++; + } + if (braceCount !== 0) { + throw new Error("Unmatched braces in the template"); + } + return currentIndex - 1; + } + /** + * 递归收集所有需要生成的接口 + * @param content - 要处理的内容 + * @param allInterfaces - 存储所有接口定义的 Map + * @param parentFields - 父级字段数组(暂未使用) + */ + function flattenContent(content, allInterfaces, parentFields) { + const interfacePattern = /(\w+)\s*:\s*\{/g; + let match; + while ((match = interfacePattern.exec(content)) !== null) { + const key = match[1]; + const startIndex = match.index + match[0].length; + const endIndex = findClosingBrace(content, startIndex); + if (endIndex > startIndex) { + const innerContent = content.substring(startIndex, endIndex).trim(); + // 构建当前接口的内容,将嵌套对象替换为接口引用 + const currentLevelContent = buildCurrentLevelContent(innerContent); + allInterfaces.set(key, currentLevelContent); + // 递归处理嵌套内容 + flattenContent(innerContent, allInterfaces); + } + } + } + /** + * 构建当前级别的内容,将嵌套对象替换为接口引用 + * @param content - 内容字符串 + * @returns 处理后的内容 + */ + function buildCurrentLevelContent(content) { + const interfacePattern = /(\w+)\s*:\s*\{/g; + let result = content; + let match; + // 重置正则表达式的 lastIndex + interfacePattern.lastIndex = 0; + while ((match = interfacePattern.exec(content)) !== null) { + const key = match[1]; + const startIndex = match.index + match[0].length; + const endIndex = findClosingBrace(content, startIndex); + if (endIndex > startIndex) { + const fullMatch = content.substring(match.index, endIndex + 1); + const replacement = `${key}: ${firstUpperCase(key)}Interface;`; + result = result.replace(fullMatch, replacement); + } + } + // 清理多余的分号和空格 + result = result.replace(/;+/g, ";").replace(/\s+/g, " ").trim(); + return result; + } + + /** + * 获取动态类名 + */ + const getDynamicClassNames = (value) => { + const names = new Set(); + // 匹配函数调用中的对象参数(如 parseClass({'!bg-surface-50': hoverable})) + const functionCallRegex = /\w+\s*\(\s*\{([^}]*)\}\s*\)/gs; + let funcMatch; + while ((funcMatch = functionCallRegex.exec(value)) !== null) { + const objContent = funcMatch[1]; + // 提取对象中的键 + const keyRegex = /['"](.*?)['"]\s*:/gs; + let keyMatch; + while ((keyMatch = keyRegex.exec(objContent)) !== null) { + keyMatch[1].trim() && names.add(keyMatch[1]); + } + } + // 匹配对象键(如 { 'text-a': 1 })- 优化版本,避免跨行错误匹配 + const objKeyRegex = /[{,]\s*['"](.*?)['"]\s*:/gs; + let objKeyMatch; + while ((objKeyMatch = objKeyRegex.exec(value)) !== null) { + const className = objKeyMatch[1].trim(); + // 确保是有效的CSS类名,避免匹配到错误内容 + if (className && !className.includes("\n") && !className.includes("\t")) { + names.add(className); + } + } + // 匹配数组中的字符串元素(如 'text-center')- 优化版本 + const arrayStringRegex = /(?:^|[,\[\s])\s*['"](.*?)['"]/gs; + let arrayMatch; + while ((arrayMatch = arrayStringRegex.exec(value)) !== null) { + const className = arrayMatch[1].trim(); + // 确保是有效的CSS类名 + if (className && !className.includes("\n") && !className.includes("\t")) { + names.add(className); + } + } + // 匹配三元表达式中的字符串(如 'dark' 和 'light') + const ternaryRegex = /(\?|:)\s*['"](.*?)['"]/gs; + let ternaryMatch; + while ((ternaryMatch = ternaryRegex.exec(value)) !== null) { + ternaryMatch[2].trim() && names.add(ternaryMatch[2]); + } + // 匹配反引号模板字符串 - 改进版本 + const templateRegex = /`([^`]*)`/gs; + let templateMatch; + while ((templateMatch = templateRegex.exec(value)) !== null) { + const templateContent = templateMatch[1]; + // 提取模板字符串中的普通文本部分(排除 ${} 表达式) + const textParts = templateContent.split(/\$\{[^}]*\}/); + textParts.forEach((part) => { + part.trim() + .split(/\s+/) + .forEach((className) => { + className.trim() && names.add(className.trim()); + }); + }); + // 提取模板字符串中 ${} 表达式内的字符串 + const expressionRegex = /\$\{([^}]*)\}/gs; + let expressionMatch; + while ((expressionMatch = expressionRegex.exec(templateContent)) !== null) { + const expression = expressionMatch[1]; + // 递归处理表达式中的动态类名 + getDynamicClassNames(expression).forEach((name) => names.add(name)); + } + } + // 处理混合字符串(模板字符串 + 普通文本),如 "`text-red-900` text-red-1000" + const mixedStringRegex = /`[^`]*`\s+([a-zA-Z0-9\-_\s]+)/g; + let mixedMatch; + while ((mixedMatch = mixedStringRegex.exec(value)) !== null) { + const additionalClasses = mixedMatch[1].trim().split(/\s+/); + additionalClasses.forEach((className) => { + className.trim() && names.add(className.trim()); + }); + } + // 处理普通字符串,多个类名用空格分割 + const stringRegex = /['"]([\w\s\-!:\/]+?)['"]/gs; + let stringMatch; + while ((stringMatch = stringRegex.exec(value)) !== null) { + const classNames = stringMatch[1].trim().split(/\s+/); + classNames.forEach((className) => { + className.trim() && names.add(className.trim()); + }); + } + return Array.from(names); + }; + /** + * 获取类名 + */ + function getClassNames(code) { + // 修改正则表达式以支持多行匹配,避免内层引号冲突 + const classRegex = /(?:class|:class|:pt|:hover-class)\s*=\s*(['"`])((?:[^'"`\\]|\\.|`[^`]*`|'[^']*'|"[^"]*")*?)\1/gis; + const classNames = new Set(); + let match; + while ((match = classRegex.exec(code)) !== null) { + const attribute = match[0].split("=")[0].trim(); + const isStaticClass = attribute === "class" || attribute === "hover-class"; + const isPtAttribute = attribute.includes("pt"); + const value = match[2].trim(); + if (isStaticClass) { + // 处理静态 class 和 hover-class + value.split(/\s+/).forEach((name) => name && classNames.add(name)); + } + else if (isPtAttribute) { + // 处理 :pt 属性中的 className + parseClasNameFromPt(value, classNames); + } + else { + // 处理动态 :class 和 :hover-class + getDynamicClassNames(value).forEach((name) => classNames.add(name)); + } + } + return Array.from(classNames); + } + /** + * 从 :pt 属性中解析 className + */ + function parseClasNameFromPt(value, classNames) { + // 递归查找所有 className 属性 + const classNameRegex = /className\s*:\s*/g; + let match; + while ((match = classNameRegex.exec(value)) !== null) { + const startPos = match.index + match[0].length; + const classNameValue = extractComplexValue(value, startPos); + if (classNameValue) { + // 如果是字符串字面量 + if (classNameValue.startsWith('"') || + classNameValue.startsWith("'") || + classNameValue.startsWith("`")) { + if (classNameValue.startsWith("`")) { + // 处理模板字符串 + getDynamicClassNames(classNameValue).forEach((name) => classNames.add(name)); + } + else { + // 处理普通字符串 + const strMatch = classNameValue.match(/['"](.*?)['"]/); + if (strMatch) { + strMatch[1].split(/\s+/).forEach((name) => name && classNames.add(name)); + } + } + } + else { + // 处理动态值(如函数调用、对象等) + getDynamicClassNames(classNameValue).forEach((name) => classNames.add(name)); + } + } + } + } + /** + * 提取复杂值(支持嵌套引号和括号) + */ + function extractComplexValue(text, startPos) { + let pos = startPos; + let depth = 0; + let inString = false; + let stringChar = ""; + let result = ""; + // 跳过开头的空白字符 + while (pos < text.length && /\s/.test(text[pos])) { + pos++; + } + while (pos < text.length) { + const char = text[pos]; + if (!inString) { + if (char === '"' || char === "'" || char === "`") { + inString = true; + stringChar = char; + result += char; + } + else if (char === "{" || char === "(" || char === "[") { + depth++; + result += char; + } + else if (char === "}" || char === ")" || char === "]") { + if (depth === 0 && char === "}") { + // 遇到顶层的 } 时结束 + break; + } + depth--; + result += char; + } + else if (char === "," && depth === 0) { + // 遇到顶层的逗号时结束 + break; + } + else if (char === "\n" && depth === 0 && result.trim() !== "") { + // 如果遇到换行且不在嵌套结构中,且已有内容,则结束 + break; + } + else { + result += char; + } + } + else { + result += char; + if (char === stringChar && text[pos - 1] !== "\\") { + inString = false; + stringChar = ""; + // 如果字符串结束且depth为0,检查是否应该结束 + if (depth === 0) { + // 看看下一个非空白字符是什么 + let nextPos = pos + 1; + while (nextPos < text.length && /\s/.test(text[nextPos])) { + nextPos++; + } + if (nextPos < text.length && (text[nextPos] === "," || text[nextPos] === "}")) { + // 如果下一个字符是逗号或右括号,则结束 + break; + } + } + } + } + pos++; + } + return result.trim() || null; + } + /** + * 获取 class 内容 + */ + function getClassContent(code) { + // 修改正则表达式以支持多行匹配,避免内层引号冲突 + const regex = /(?:class|:class|:pt|:hover-class)\s*=\s*(['"`])((?:[^'"`\\]|\\.|`[^`]*`|'[^']*'|"[^"]*")*?)\1/gis; + const texts = []; + let match; + while ((match = regex.exec(code)) !== null) { + const attribute = match[0].split("=")[0].trim(); + const isPtAttribute = attribute.includes("pt"); + const value = match[2]; + if (isPtAttribute) { + // 手动解析 className 值 + const classNameRegex = /className\s*:\s*/g; + let classNameMatchResult; + while ((classNameMatchResult = classNameRegex.exec(value)) !== null) { + const startPos = classNameMatchResult.index + classNameMatchResult[0].length; + const classNameValue = extractComplexValue(value, startPos); + if (classNameValue) { + texts.push(classNameValue); + } + } + } + else { + texts.push(value); + } + } + return texts; + } + /** + * 获取节点 + */ + function getNodes(code) { + const nodes = []; + // 找到所有顶级template标签的完整内容 + function findTemplateContents(content) { + const results = []; + let index = 0; + while (index < content.length) { + const templateStart = content.indexOf("", templateStart); + if (tagEnd === -1) + break; + // 使用栈来匹配配对的template标签 + let stack = 1; + let currentPos = tagEnd + 1; + while (currentPos < content.length && stack > 0) { + const nextTemplateStart = content.indexOf("", currentPos); + if (nextTemplateEnd === -1) + break; + // 如果开始标签更近,说明有嵌套 + if (nextTemplateStart !== -1 && nextTemplateStart < nextTemplateEnd) { + // 找到开始标签的完整结束 + const nestedTagEnd = content.indexOf(">", nextTemplateStart); + if (nestedTagEnd !== -1) { + stack++; + currentPos = nestedTagEnd + 1; + } + else { + break; + } + } + else { + // 找到结束标签 + stack--; + currentPos = nextTemplateEnd + 11; // ''.length + } + } + if (stack === 0) { + // 提取template内容(不包括template标签本身) + const templateContent = content.substring(tagEnd + 1, currentPos - 11); + results.push(templateContent); + index = currentPos; + } + else { + // 如果没有找到匹配的结束标签,跳过这个开始标签 + index = tagEnd + 1; + } + } + return results; + } + // 递归提取所有template内容中的节点 + function extractNodesFromContent(content) { + // 先提取当前内容中的所有标签 + const regex = /<([^>]+)>/g; + let match; + while ((match = regex.exec(content)) !== null) { + if (!match[1].startsWith("/") && !match[1].startsWith("template")) { + nodes.push(match[1]); + } + } + // 递归处理嵌套的template + const nestedTemplates = findTemplateContents(content); + nestedTemplates.forEach((templateContent) => { + extractNodesFromContent(templateContent); + }); + } + // 获取所有顶级template内容 + const templateContents = findTemplateContents(code); + // 处理每个template内容 + templateContents.forEach((templateContent) => { + extractNodesFromContent(templateContent); + }); + return nodes.map((e) => `<${e}>`); + } + /** + * 添加 script 标签内容 + */ + function addScriptContent(code, content) { + const scriptMatch = /]*>([\s\S]*?)<\/script>/g.exec(code); + if (!scriptMatch) { + return code; + } + const scriptContent = scriptMatch[1]; + const scriptStartIndex = scriptMatch.index + scriptMatch[0].indexOf(">") + 1; + const scriptEndIndex = scriptStartIndex + scriptContent.length; + return (code.substring(0, scriptStartIndex) + + "\n" + + content + + "\n" + + scriptContent.trim() + + code.substring(scriptEndIndex)); + } + /** + * 判断是否为 Tailwind 类名 + */ + function isTailwindClass(className) { + const prefixes = [ + // 布局 + "container", + "flex", + "grid", + "block", + "inline", + "hidden", + "visible", + // 间距 + "p-", + "px-", + "py-", + "pt-", + "pr-", + "pb-", + "pl-", + "m-", + "mx-", + "my-", + "mt-", + "mr-", + "mb-", + "ml-", + "space-", + "gap-", + // 尺寸 + "w-", + "h-", + "min-w-", + "max-w-", + "min-h-", + "max-h-", + // 颜色 + "bg-", + "text-", + "border-", + "ring-", + "shadow-", + // 边框 + "border", + "rounded", + "ring", + // 字体 + "font-", + "text-", + "leading-", + "tracking-", + "antialiased", + // 定位 + "absolute", + "relative", + "fixed", + "sticky", + "static", + "top-", + "right-", + "bottom-", + "left-", + "inset-", + "z-", + // 变换 + "transform", + "translate-", + "rotate-", + "scale-", + "skew-", + // 过渡 + "transition", + "duration-", + "ease-", + "delay-", + // 交互 + "cursor-", + "select-", + "pointer-events-", + // 溢出 + "overflow-", + "truncate", + // 滚动 + "scroll-", + // 伪类和响应式 + "hover:", + "focus:", + "active:", + "disabled:", + "group-hover:", + ]; + const statePrefixes = ["dark:", "dark:!", "light:", "sm:", "md:", "lg:", "xl:", "2xl:"]; + if (className.startsWith("!") && !className.includes("!=")) { + return true; + } + for (const prefix of prefixes) { + if (className.startsWith(prefix)) { + return true; + } + for (const statePrefix of statePrefixes) { + if (className.startsWith(statePrefix + prefix)) { + return true; + } + } + } + return false; + } + /** + * 将 interface 转换为 type + */ + function interfaceToType(code) { + // 匹配 interface 定义 + const interfaceRegex = /interface\s+(\w+)(\s*extends\s+\w+)?\s*\{([^}]*)\}/g; + // 将 interface 转换为 type + return code.replace(interfaceRegex, (match, name, extends_, content) => { + // 处理可能存在的 extends + const extendsStr = extends_ ? extends_ : ""; + // 返回转换后的 type 定义 + return `type ${name}${extendsStr} = {${content}}`; + }); + } + + // 全局 service 对象,用于存储服务结构 + const service = {}; + // eps 实体列表 + let list = []; + /** + * 获取 eps 请求地址 + * @returns {string} eps url + */ + function getEpsUrl() { + let url = config.eps.api; + if (!url) { + url = config.type; + } + switch (url) { + case "app": + case "uniapp-x": + url = "/app/base/comm/eps"; + break; + case "admin": + url = "/admin/base/open/eps"; + break; + } + return url; + } + /** + * 获取 eps 路径 + * @param filename 文件名 + * @returns {string} 完整路径 + */ + function getEpsPath(filename) { + return path.join(config.type == "admin" ? config.eps.dist : rootDir(config.eps.dist), filename || ""); + } + /** + * 获取对象方法名(排除 namespace、permission 字段) + * @param v 对象 + * @returns {string[]} 方法名数组 + */ + function getNames(v) { + return Object.keys(v).filter((e) => !["namespace", "permission"].includes(e)); + } + /** + * 获取字段类型 + */ + function getType({ propertyName, type }) { + for (const map of config.eps.mapping) { + if (map.custom) { + const resType = map.custom({ propertyName, type }); + if (resType) + return resType; + } + if (map.test) { + if (map.test.includes(type)) + return map.type; + } + } + return type; + } + /** + * 格式化方法名,去除特殊字符 + */ + function formatName(name) { + return (name || "").replace(/[:,\s,\/,-]/g, ""); + } + /** + * 检查方法名是否合法(不包含特殊字符) + */ + function checkName(name) { + return name && !["{", "}", ":"].some((e) => name.includes(e)); + } + /** + * 不支持 uniapp-x 平台显示 + */ + function noUniappX(text, defaultText = "") { + if (config.type == "uniapp-x") { + return defaultText; + } + else { + return text; + } + } + /** + * 查找字段 + * @param sources 字段 source 数组 + * @param item eps 实体 + * @returns {Eps.Column[]} 字段数组 + */ + function findColumns(sources, item) { + const columns = [item.columns, item.pageColumns].flat().filter(Boolean); + return (sources || []) + .map((e) => columns.find((c) => c.source == e)) + .filter(Boolean); + } + /** + * 使用 prettier 格式化 TypeScript 代码 + * @param text 代码文本 + * @returns {Promise} 格式化后的代码 + */ + async function formatCode(text) { + return prettier + .format(text, { + parser: "typescript", + useTabs: true, + tabWidth: 4, + endOfLine: "lf", + semi: true, + singleQuote: false, + printWidth: 100, + trailingComma: "none", + }) + .catch((err) => { + console.log(err); + error(`[cool-eps] File format error, please try again`); + return null; + }); + } + /** + * 获取 eps 数据(本地优先,远程兜底) + */ + async function getData() { + // 读取本地 eps.json + list = readFile(getEpsPath("eps.json"), true) || []; + // 拼接请求地址 + const url = config.reqUrl + getEpsUrl(); + // 请求远程 eps 数据 + await axios + .get(url, { + timeout: 5000, + }) + .then((res) => { + const { code, data, message } = res.data; + if (code === 1000) { + if (!lodash.isEmpty(data) && data) { + list = lodash.values(data).flat(); + } + } + else { + error(`[cool-eps] ${message || "Failed to fetch data"}`); + } + }) + .catch(() => { + error(`[cool-eps] API service is not running → ${url}`); + }); + // 初始化处理,补全缺省字段 + list.forEach((e) => { + if (!e.namespace) + e.namespace = ""; + if (!e.api) + e.api = []; + if (!e.columns) + e.columns = []; + if (!e.search) { + e.search = { + fieldEq: findColumns(e.pageQueryOp?.fieldEq, e), + fieldLike: findColumns(e.pageQueryOp?.fieldLike, e), + keyWordLikeFields: findColumns(e.pageQueryOp?.keyWordLikeFields, e), + }; + } + }); + if (config.type == "uniapp-x" || config.type == "app") { + list = list.filter((e) => e.prefix.startsWith("/app") || e.prefix.startsWith("/admin")); + } + } + /** + * 创建 eps.json 文件 + * @returns {boolean} 是否有更新 + */ + function createJson() { + let data = []; + if (config.type != "uniapp-x") { + data = list.map((e) => { + return { + prefix: e.prefix, + name: e.name || "", + api: e.api.map((apiItem) => ({ + name: apiItem.name, + method: apiItem.method, + path: apiItem.path, + })), + search: e.search, + }; + }); + } + else { + data = list; + } + const content = JSON.stringify(data); + const local_content = readFile(getEpsPath("eps.json")); + // 判断是否需要更新 + const isUpdate = content != local_content; + if (isUpdate) { + fs.createWriteStream(getEpsPath("eps.json"), { + flags: "w", + }).write(content); + } + return isUpdate; + } + /** + * 创建 eps 类型描述文件(d.ts/ts) + * @param param0 list: eps实体列表, service: service对象 + */ + async function createDescribe({ list, service }) { + /** + * 创建 Entity 接口定义 + */ + function createEntity() { + const ignore = []; + let t0 = ""; + for (const item of list) { + if (!checkName(item.name)) + continue; + if (formatName(item.name) == "BusinessInterface") { + console.log(111); + } + let t = `interface ${formatName(item.name)} {`; + // 合并 columns 和 pageColumns,去重 + const columns = lodash.uniqBy(lodash.compact([...(item.columns || []), ...(item.pageColumns || [])]), "source"); + for (const col of columns || []) { + t += ` + /** + * ${col.comment} + */ + ${col.propertyName}?: ${getType({ + propertyName: col.propertyName, + type: col.type, + })}; + `; + } + t += ` + /** + * 任意键值 + */ + [key: string]: any; + } + `; + if (!ignore.includes(item.name)) { + ignore.push(item.name); + t0 += t + "\n\n"; + } + } + return t0; + } + /** + * 创建 Controller 接口定义 + */ + async function createController() { + let controller = ""; + let chain = ""; + let pageResponse = ""; + /** + * 递归处理 service 树,生成接口定义 + * @param d 当前节点 + * @param k 前缀 + */ + function deep(d, k) { + if (!k) + k = ""; + for (const i in d) { + const name = k + toCamel(firstUpperCase(formatName(i))); + // 检查方法名 + if (!checkName(name)) + continue; + if (d[i].namespace) { + // 查找配置 + const item = list.find((e) => (e.prefix || "") === `/${d[i].namespace}`); + if (item) { + // + let t = `interface ${name} {`; + // 插入方法 + if (item.api) { + // 权限列表 + const permission = []; + item.api.forEach((a) => { + // 方法名 + const n = toCamel(formatName(a.name || lodash.last(a.path.split("/")))); + // 检查方法名 + if (!checkName(n)) + return; + if (n) { + // 参数类型 + let q = []; + // 参数列表 + const { parameters = [] } = a.dts || {}; + parameters.forEach((p) => { + if (p.description) { + q.push(`\n/** ${p.description} */\n`); + } + // 检查参数名 + if (!checkName(p.name)) { + return false; + } + const a = `${p.name}${p.required ? "" : "?"}`; + const b = `${p.schema.type || "string"}`; + q.push(`${a}: ${b};`); + }); + if (lodash.isEmpty(q)) { + q = ["any"]; + } + else { + q.unshift("{"); + q.push("}"); + } + // 返回类型 + let res = ""; + // 实体名 + const en = item.name || "any"; + switch (a.path) { + case "/page": + res = `${name}PageResponse`; + pageResponse += ` + interface ${name}PageResponse { + pagination: PagePagination; + list: ${en}[]; + } + `; + break; + case "/list": + res = `${en} []`; + break; + case "/info": + res = en; + break; + default: + res = "any"; + break; + } + // 方法描述 + if (config.type == "uniapp-x") { + t += ` + /** + * ${a.summary || n} + */ + ${n}(data${q.length == 1 ? "?" : ""}: ${q.join("")}): Promise; + `; + } + else { + t += ` + /** + * ${a.summary || n} + */ + ${n}(data${q.length == 1 ? "?" : ""}: ${q.join("")}): Promise<${res}>; + `; + } + if (!permission.includes(n)) { + permission.push(n); + } + } + }); + // 权限标识 + t += noUniappX(` + /** + * 权限标识 + */ + permission: { ${permission.map((e) => `${e}: string;`).join("\n")} }; + `); + // 权限状态 + t += noUniappX(` + /** + * 权限状态 + */ + _permission: { ${permission.map((e) => `${e}: boolean;`).join("\n")} }; + `); + // 请求 + t += noUniappX(` + request: Request; + `); + } + t += "}\n\n"; + controller += t; + chain += `${formatName(i)}: ${name};`; + } + } + else { + chain += `${formatName(i)}: {`; + deep(d[i], name); + chain += "};"; + } + } + } + // 遍历 service 树 + deep(service); + return ` + type json = any; + + ${await createDict()} + + interface PagePagination { + size: number; + page: number; + total: number; + [key: string]: any; + }; + + interface PageResponse { + pagination: PagePagination; + list: T[]; + [key: string]: any; + }; + + ${pageResponse} + + ${controller} + + ${noUniappX(`interface RequestOptions { + url: string; + method?: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT'; + data?: any; + params?: any; + headers?: any; + timeout?: number; + [key: string]: any; + }`)} + + ${noUniappX("type Request = (options: RequestOptions) => Promise;")} + + type Service = { + ${noUniappX("request: Request;")} + + ${chain} + } + `; + } + // 组装文件内容 + let text = ` + ${createEntity()} + ${await createController()} + `; + // 文件名 + let name = "eps.d.ts"; + if (config.type == "uniapp-x") { + name = "eps.ts"; + text = text + .replaceAll("interface ", "export interface ") + .replaceAll("type ", "export type ") + .replaceAll("[key: string]: any;", ""); + text = flatten(text); + text = interfaceToType(text); + } + else { + text = ` + declare namespace Eps { + ${text} + } + `; + } + // 格式化文本内容 + const content = await formatCode(text); + const local_content = readFile(getEpsPath(name)); + // 是否需要更新 + if (content && content != local_content && list.length > 0) { + // 创建 eps 描述文件 + fs.createWriteStream(getEpsPath(name), { + flags: "w", + }).write(content); + } + } + /** + * 构建 service 对象树 + */ + function createService() { + // 路径第一层作为 id 标识 + const id = getEpsUrl().split("/")[1]; + list.forEach((e) => { + // 请求地址 + const path = e.prefix[0] == "/" ? e.prefix.substring(1, e.prefix.length) : e.prefix; + // 分隔路径,去除 id,转驼峰 + const arr = path.replace(id, "").split("/").filter(Boolean).map(toCamel); + /** + * 递归构建 service 树 + * @param d 当前节点 + * @param i 当前索引 + */ + function deep(d, i) { + const k = arr[i]; + if (k) { + // 是否最后一个 + if (arr[i + 1]) { + if (!d[k]) { + d[k] = {}; + } + deep(d[k], i + 1); + } + else { + // 不存在则创建 + if (!d[k]) { + d[k] = { + permission: {}, + }; + } + if (!d[k].namespace) { + d[k].namespace = path; + } + // 创建权限 + if (d[k].namespace) { + getNames(d[k]).forEach((i) => { + d[k].permission[i] = + `${d[k].namespace.replace(`${id}/`, "")}/${i}`.replace(/\//g, ":"); + }); + } + // 创建搜索 + d[k].search = e.search; + // 创建方法 + e.api.forEach((a) => { + // 方法名 + const n = a.path.replace("/", ""); + if (n && !/[-:]/g.test(n)) { + d[k][n] = a; + } + }); + } + } + } + deep(service, 0); + }); + } + /** + * 创建 service 代码 + * @returns {string} service 代码 + */ + function createServiceCode() { + const types = []; + let chain = ""; + /** + * 递归处理 service 树,生成接口代码 + * @param d 当前节点 + * @param k 前缀 + */ + function deep(d, k) { + if (!k) + k = ""; + for (const i in d) { + if (["swagger"].includes(i)) { + continue; + } + const name = k + toCamel(firstUpperCase(formatName(i))); + // 检查方法名 + if (!checkName(name)) + continue; + if (d[i].namespace) { + // 查找配置 + const item = list.find((e) => (e.prefix || "") === `/${d[i].namespace}`); + if (item) { + // + let t = `{`; + // 插入方法 + if (item.api) { + item.api.forEach((a) => { + // 方法名 + const n = toCamel(formatName(a.name || lodash.last(a.path.split("/")))); + // 检查方法名 + if (!checkName(n)) + return; + if (n) { + // 参数类型 + let q = []; + // 参数列表 + const { parameters = [] } = a.dts || {}; + parameters.forEach((p) => { + if (p.description) { + q.push(`\n/** ${p.description} */\n`); + } + // 检查参数名 + if (!checkName(p.name)) { + return false; + } + const a = `${p.name}${p.required ? "" : "?"}`; + const b = `${p.schema.type || "string"}`; + q.push(`${a}: ${b}, `); + }); + if (lodash.isEmpty(q)) { + q = ["any"]; + } + else { + q.unshift("{"); + q.push("}"); + } + if (item.name) { + types.push(item.name); + } + // 方法描述 + t += ` + /** + * ${a.summary || n} + */ + ${n}(data?: any): Promise { + return request({ + url: "/${d[i].namespace}${a.path}", + method: "${(a.method || "get").toLocaleUpperCase()}", + data, + }); + }, + `; + } + }); + } + t += `} as ${name}\n`; + types.push(name); + chain += `${formatName(i)}: ${t},\n`; + } + } + else { + chain += `${formatName(i)}: {`; + deep(d[i], name); + chain += `} as ${firstUpperCase(i)}Interface,`; + types.push(`${firstUpperCase(i)}Interface`); + } + } + } + // 遍历 service 树 + deep(service); + return { + content: `{ ${chain} }`, + types, + }; + } + /** + * 获取字典类型定义 + * @returns {Promise} 字典类型 type 定义 + */ + async function createDict() { + let p = ""; + switch (config.type) { + case "app": + case "uniapp-x": + p = "/app"; + break; + case "admin": + p = "/admin"; + break; + } + const url = config.reqUrl + p + "/dict/info/types"; + const text = await axios + .get(url) + .then((res) => { + const { code, data } = res.data; + if (code === 1000) { + let v = "string"; + if (!lodash.isEmpty(data)) { + v = data.map((e) => `"${e.key}"`).join(" | "); + } + return `type DictKey = ${v}`; + } + }) + .catch(() => { + error(`[cool-eps] Error:${url}`); + }); + return text || ""; + } + /** + * 主入口:创建 eps 相关文件和 service + */ + async function createEps() { + if (config.eps.enable) { + // 获取 eps 数据 + await getData(); + // 构建 service 对象 + createService(); + const serviceCode = createServiceCode(); + // 创建 eps 目录 + createDir(getEpsPath(), true); + // 创建 eps.json 文件 + const isUpdate = createJson(); + // 创建类型描述文件 + createDescribe({ service, list }); + return { + service, + serviceCode, + list, + isUpdate, + }; + } + else { + return { + service: {}, + list: [], + }; + } + } + + function getPlugin(name) { + let code = readFile(rootDir(`./src/plugins/${name}/config.ts`)); + // 设置插件配置 + const set = (key, value) => { + const regex = new RegExp(`(return\\s*{[^}]*?\\b${key}\\b\\s*:\\s*)([^,}]+)`); + if (regex.test(code)) { + code = code.replace(regex, `$1${JSON.stringify(value)}`); + } + else { + const insertPos = code.indexOf("return {") + 8; + code = + code.slice(0, insertPos) + + `\n ${key}: ${JSON.stringify(value)},` + + code.slice(insertPos); + } + }; + // 保存插件配置 + const save = async () => { + const content = await formatContent(code); + writeFile(rootDir(`./src/plugins/${name}/config.ts`), content); + }; + return { + set, + save, + }; + } + // 修改插件 + async function updatePlugin(options) { + const plugin = getPlugin(options.name); + if (options.enable !== undefined) { + plugin.set("enable", options.enable); + } + await plugin.save(); + } + + function getPath() { + return rootDir(`.${config.type == "admin" ? "/src" : ""}/config/proxy.ts`); + } + async function updateProxy(data) { + let code = readFile(getPath()); + const regex = /const\s+value\s*=\s*['"]([^'"]+)['"]/; + if (regex.test(code)) { + code = code.replace(regex, `const value = '${data.name}'`); + } + writeFile(getPath(), code); + } + function getProxyTarget(proxy) { + const code = readFile(getPath()); + const regex = /const\s+value\s*=\s*['"]([^'"]+)['"]/; + const match = code.match(regex); + if (match) { + const value = match[1]; + try { + const { target, rewrite } = proxy[`/${value}/`]; + return target + rewrite(`/${value}`); + } + catch (err) { + error(`[cool-proxy] Error:${value} → ` + getPath()); + return ""; + } + } + } + + // 创建文件 + async function createFile(data) { + const list = lodash.isArray(data) ? data : [data]; + for (const item of list) { + const { path: path$1, code } = item; + // 格式化内容 + const content = await formatContent(code, { + parser: "vue", + }); + // 目录路径 + const dir = (path$1 || "").split("/"); + // 文件名 + const fname = dir.pop(); + // 源码路径 + const srcPath = `./src/${dir.join("/")}`; + // 创建目录 + createDir(srcPath, true); + // 创建文件 + fs.createWriteStream(path.join(srcPath, fname), { + flags: "w", + }).write(content); + } + } + + function createTag(code, id) { + if (/\.vue$/.test(id)) { + let s; + const str = () => s || (s = new magicString(code)); + const { descriptor } = compilerSfc.parse(code); + if (!descriptor.script && descriptor.scriptSetup) { + const res = compilerSfc.compileScript(descriptor, { id }); + const { name, lang } = res.attrs; + str().appendLeft(0, ` + + diff --git a/src/modules/base/pages/kefulogin/index.vue b/src/modules/base/pages/kefulogin/index.vue new file mode 100644 index 0000000..6129d52 --- /dev/null +++ b/src/modules/base/pages/kefulogin/index.vue @@ -0,0 +1,343 @@ + + + + + diff --git a/src/modules/base/pages/login/components/pic-captcha.vue b/src/modules/base/pages/login/components/pic-captcha.vue new file mode 100644 index 0000000..87af631 --- /dev/null +++ b/src/modules/base/pages/login/components/pic-captcha.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/modules/base/pages/login/index.vue b/src/modules/base/pages/login/index.vue new file mode 100644 index 0000000..2a235b8 --- /dev/null +++ b/src/modules/base/pages/login/index.vue @@ -0,0 +1,307 @@ + + + + + diff --git a/src/modules/base/pages/login/static/bg.svg b/src/modules/base/pages/login/static/bg.svg new file mode 100644 index 0000000..a96530d --- /dev/null +++ b/src/modules/base/pages/login/static/bg.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + diff --git a/src/modules/base/pages/main/components/amenu.vue b/src/modules/base/pages/main/components/amenu.vue new file mode 100644 index 0000000..b34000d --- /dev/null +++ b/src/modules/base/pages/main/components/amenu.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/src/modules/base/pages/main/components/bmenu.tsx b/src/modules/base/pages/main/components/bmenu.tsx new file mode 100644 index 0000000..6f0be72 --- /dev/null +++ b/src/modules/base/pages/main/components/bmenu.tsx @@ -0,0 +1,153 @@ +import { defineComponent, h, watch } from 'vue'; +import { useBase } from '/$/base'; +import { useCool } from '/@/cool'; +import { debounce } from 'lodash-es'; + +export default defineComponent({ + name: 'b-menu', + + props: { + keyWord: String + }, + + setup(props) { + const { router, route, browser, refs, setRefs } = useCool(); + const { menu, app } = useBase(); + + // 页面跳转 + function onSelect(url: string) { + if (url != route.path) { + router.push(url); + } + + // 小屏下点击收起左侧菜单 + if (browser.isMini) { + app.fold(true); + } + } + + // 渲染子菜单 + function renderMenu() { + function deep(list: Menu.Item[], show?: boolean) { + const keyWord = props.keyWord?.toLowerCase() || ''; + + function filterMenu(item: Menu.Item): boolean { + if (!item.isShow) return false; + + if (show) { + return true; + } + + if (item.meta?.label?.toLowerCase().includes(keyWord)) return true; + + if (item.children) { + return item.children.some(filterMenu); + } + + return false; + } + + return list.filter(filterMenu).map(e => { + if (e.meta?.label?.toLowerCase().includes(keyWord)) { + show = true; + } + + const item = (e: Menu.Item) => { + const arr = [ + , + + {e.meta?.label} + + ]; + + if (e.type == 1 && e.badge) { + arr.push( +
+ {e.badge} +
+ ); + } + return arr; + }; + + if (e.type == 0) { + return h( + , + { + index: String(e.id), + key: e.id, + popperClass: 'app-slider__menu' + }, + { + title() { + return item(e); + }, + default() { + return deep(e.children || [], show); + } + } + ); + } else { + return h( + , + { + index: e.meta?.isHome ? '/' : e.path, + key: e.id + }, + { + default() { + return item(e); + } + } + ); + } + }); + } + + return deep(menu.list); + } + + // 展开所有 + const expand = debounce(() => { + if (!props.keyWord) { + return; + } + + const deep = (list: Menu.Item[]) => { + list.forEach(e => { + if (e.type == 0) { + try { + refs.menu?.open(String(e.id)); + } catch (err) { } + + if (e.children) { + deep(e.children); + } + } + }); + }; + + deep(menu.list); + }, 300); + + watch(() => props.keyWord, expand); + + return () => { + return ( +
+ + {renderMenu()} + +
+ ); + }; + } +}); diff --git a/src/modules/base/pages/main/components/global.vue b/src/modules/base/pages/main/components/global.vue new file mode 100644 index 0000000..7134814 --- /dev/null +++ b/src/modules/base/pages/main/components/global.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/modules/base/pages/main/components/process.vue b/src/modules/base/pages/main/components/process.vue new file mode 100644 index 0000000..cf82f72 --- /dev/null +++ b/src/modules/base/pages/main/components/process.vue @@ -0,0 +1,279 @@ + + + + + diff --git a/src/modules/base/pages/main/components/route-nav.vue b/src/modules/base/pages/main/components/route-nav.vue new file mode 100644 index 0000000..54b9bfb --- /dev/null +++ b/src/modules/base/pages/main/components/route-nav.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/src/modules/base/pages/main/components/slider.vue b/src/modules/base/pages/main/components/slider.vue new file mode 100644 index 0000000..635262c --- /dev/null +++ b/src/modules/base/pages/main/components/slider.vue @@ -0,0 +1,188 @@ + + + + + diff --git a/src/modules/base/pages/main/components/topbar.vue b/src/modules/base/pages/main/components/topbar.vue new file mode 100644 index 0000000..5559d13 --- /dev/null +++ b/src/modules/base/pages/main/components/topbar.vue @@ -0,0 +1,219 @@ + + + + + + + diff --git a/src/modules/base/pages/main/components/views.vue b/src/modules/base/pages/main/components/views.vue new file mode 100644 index 0000000..0ae0219 --- /dev/null +++ b/src/modules/base/pages/main/components/views.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/modules/base/pages/main/index.vue b/src/modules/base/pages/main/index.vue new file mode 100644 index 0000000..e078958 --- /dev/null +++ b/src/modules/base/pages/main/index.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/src/modules/base/static/css/index.scss b/src/modules/base/static/css/index.scss new file mode 100644 index 0000000..e31abc7 --- /dev/null +++ b/src/modules/base/static/css/index.scss @@ -0,0 +1,81 @@ +#app { + height: 100vh; + width: 100vw; + overflow: hidden; +} + +:root { + --bg-color: var(--el-fill-color-lighter); +} + +a { + text-decoration: none; +} + +input, +button { + outline: none; +} + +input { + &:-webkit-autofill { + box-shadow: 0 0 0px 1000px white inset; + } +} + +// scrollbar +::-webkit-scrollbar { + width: 6px; +} + +::-webkit-scrollbar:horizontal { + height: 6px; +} + +::-webkit-scrollbar-track { + border-radius: 10px; +} + +::-webkit-scrollbar-thumb { + background-color: #0003; + border-radius: 10px; + transition: all 0.2s ease-in-out; +} + +::-webkit-scrollbar-thumb:hover { + cursor: pointer; + background-color: #0000004d; +} + +.dark ::-webkit-scrollbar-thumb { + background-color: #fff3; +} + +.dark ::-webkit-scrollbar-thumb:hover { + background-color: #fff6; +} + +// custom +.cl-comm__icon { + display: flex; + align-items: center; + justify-content: center; + height: 26px; + width: 26px; + background-color: var(--el-bg-color); + border: 1px solid var(--el-fill-color-dark); + border-radius: 6px; + transition: all 0.2s ease-in-out; + outline: none; + cursor: pointer; + flex-shrink: 0; + + .cl-svg { + font-size: 16px; + color: var(--el-text-color-primary); + } + + &:hover { + background-color: var(--el-fill-color-light); + } +} diff --git a/src/modules/base/static/svg/amount.svg b/src/modules/base/static/svg/amount.svg new file mode 100644 index 0000000..78fae7f --- /dev/null +++ b/src/modules/base/static/svg/amount.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/back.svg b/src/modules/base/static/svg/back.svg new file mode 100644 index 0000000..1212879 --- /dev/null +++ b/src/modules/base/static/svg/back.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/modules/base/static/svg/close-border.svg b/src/modules/base/static/svg/close-border.svg new file mode 100644 index 0000000..4c125fa --- /dev/null +++ b/src/modules/base/static/svg/close-border.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/close.svg b/src/modules/base/static/svg/close.svg new file mode 100644 index 0000000..b45fab1 --- /dev/null +++ b/src/modules/base/static/svg/close.svg @@ -0,0 +1,21 @@ + + + + + diff --git a/src/modules/base/static/svg/delete.svg b/src/modules/base/static/svg/delete.svg new file mode 100644 index 0000000..fccd1e8 --- /dev/null +++ b/src/modules/base/static/svg/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/edit.svg b/src/modules/base/static/svg/edit.svg new file mode 100644 index 0000000..e1de5c5 --- /dev/null +++ b/src/modules/base/static/svg/edit.svg @@ -0,0 +1,21 @@ + + + + + diff --git a/src/modules/base/static/svg/exit.svg b/src/modules/base/static/svg/exit.svg new file mode 100644 index 0000000..f6071c5 --- /dev/null +++ b/src/modules/base/static/svg/exit.svg @@ -0,0 +1,25 @@ + + + + + + diff --git a/src/modules/base/static/svg/expand.svg b/src/modules/base/static/svg/expand.svg new file mode 100644 index 0000000..453a7b3 --- /dev/null +++ b/src/modules/base/static/svg/expand.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/export.svg b/src/modules/base/static/svg/export.svg new file mode 100644 index 0000000..65c8e16 --- /dev/null +++ b/src/modules/base/static/svg/export.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/fail.svg b/src/modules/base/static/svg/fail.svg new file mode 100644 index 0000000..545abc6 --- /dev/null +++ b/src/modules/base/static/svg/fail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/fold.svg b/src/modules/base/static/svg/fold.svg new file mode 100644 index 0000000..feb1d41 --- /dev/null +++ b/src/modules/base/static/svg/fold.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/github.svg b/src/modules/base/static/svg/github.svg new file mode 100644 index 0000000..a2663ad --- /dev/null +++ b/src/modules/base/static/svg/github.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/modules/base/static/svg/home.svg b/src/modules/base/static/svg/home.svg new file mode 100644 index 0000000..d6f732d --- /dev/null +++ b/src/modules/base/static/svg/home.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/modules/base/static/svg/icon-activity.svg b/src/modules/base/static/svg/icon-activity.svg new file mode 100644 index 0000000..be00ee9 --- /dev/null +++ b/src/modules/base/static/svg/icon-activity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-amount.svg b/src/modules/base/static/svg/icon-amount.svg new file mode 100644 index 0000000..13c68d9 --- /dev/null +++ b/src/modules/base/static/svg/icon-amount.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-app.svg b/src/modules/base/static/svg/icon-app.svg new file mode 100644 index 0000000..1d82a1c --- /dev/null +++ b/src/modules/base/static/svg/icon-app.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-approve.svg b/src/modules/base/static/svg/icon-approve.svg new file mode 100644 index 0000000..e77593c --- /dev/null +++ b/src/modules/base/static/svg/icon-approve.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-auth.svg b/src/modules/base/static/svg/icon-auth.svg new file mode 100644 index 0000000..b299f59 --- /dev/null +++ b/src/modules/base/static/svg/icon-auth.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-ban.svg b/src/modules/base/static/svg/icon-ban.svg new file mode 100644 index 0000000..0376a77 --- /dev/null +++ b/src/modules/base/static/svg/icon-ban.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-call.svg b/src/modules/base/static/svg/icon-call.svg new file mode 100644 index 0000000..d35cabc --- /dev/null +++ b/src/modules/base/static/svg/icon-call.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-camera.svg b/src/modules/base/static/svg/icon-camera.svg new file mode 100644 index 0000000..97dff8f --- /dev/null +++ b/src/modules/base/static/svg/icon-camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-card.svg b/src/modules/base/static/svg/icon-card.svg new file mode 100644 index 0000000..f6ae0e8 --- /dev/null +++ b/src/modules/base/static/svg/icon-card.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-cart.svg b/src/modules/base/static/svg/icon-cart.svg new file mode 100644 index 0000000..f6833eb --- /dev/null +++ b/src/modules/base/static/svg/icon-cart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-common.svg b/src/modules/base/static/svg/icon-common.svg new file mode 100644 index 0000000..7fe6060 --- /dev/null +++ b/src/modules/base/static/svg/icon-common.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-component.svg b/src/modules/base/static/svg/icon-component.svg new file mode 100644 index 0000000..a44dae7 --- /dev/null +++ b/src/modules/base/static/svg/icon-component.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/modules/base/static/svg/icon-count.svg b/src/modules/base/static/svg/icon-count.svg new file mode 100644 index 0000000..daf26ba --- /dev/null +++ b/src/modules/base/static/svg/icon-count.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-crown.svg b/src/modules/base/static/svg/icon-crown.svg new file mode 100644 index 0000000..71429de --- /dev/null +++ b/src/modules/base/static/svg/icon-crown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-data.svg b/src/modules/base/static/svg/icon-data.svg new file mode 100644 index 0000000..1dbfe70 --- /dev/null +++ b/src/modules/base/static/svg/icon-data.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-db.svg b/src/modules/base/static/svg/icon-db.svg new file mode 100644 index 0000000..4a5d345 --- /dev/null +++ b/src/modules/base/static/svg/icon-db.svg @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-delete.svg b/src/modules/base/static/svg/icon-delete.svg new file mode 100644 index 0000000..610d33e --- /dev/null +++ b/src/modules/base/static/svg/icon-delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-dept.svg b/src/modules/base/static/svg/icon-dept.svg new file mode 100644 index 0000000..f0af65d --- /dev/null +++ b/src/modules/base/static/svg/icon-dept.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-design.svg b/src/modules/base/static/svg/icon-design.svg new file mode 100644 index 0000000..3aed42f --- /dev/null +++ b/src/modules/base/static/svg/icon-design.svg @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-device.svg b/src/modules/base/static/svg/icon-device.svg new file mode 100644 index 0000000..f82b640 --- /dev/null +++ b/src/modules/base/static/svg/icon-device.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-dict.svg b/src/modules/base/static/svg/icon-dict.svg new file mode 100644 index 0000000..444ceee --- /dev/null +++ b/src/modules/base/static/svg/icon-dict.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-discover.svg b/src/modules/base/static/svg/icon-discover.svg new file mode 100644 index 0000000..3747d7e --- /dev/null +++ b/src/modules/base/static/svg/icon-discover.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-doc.svg b/src/modules/base/static/svg/icon-doc.svg new file mode 100644 index 0000000..d82fa34 --- /dev/null +++ b/src/modules/base/static/svg/icon-doc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-download.svg b/src/modules/base/static/svg/icon-download.svg new file mode 100644 index 0000000..b86f044 --- /dev/null +++ b/src/modules/base/static/svg/icon-download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-emoji.svg b/src/modules/base/static/svg/icon-emoji.svg new file mode 100644 index 0000000..2809858 --- /dev/null +++ b/src/modules/base/static/svg/icon-emoji.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-favor.svg b/src/modules/base/static/svg/icon-favor.svg new file mode 100644 index 0000000..98ad58e --- /dev/null +++ b/src/modules/base/static/svg/icon-favor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-file.svg b/src/modules/base/static/svg/icon-file.svg new file mode 100644 index 0000000..5ab59d6 --- /dev/null +++ b/src/modules/base/static/svg/icon-file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-folder.svg b/src/modules/base/static/svg/icon-folder.svg new file mode 100644 index 0000000..7ad8ab7 --- /dev/null +++ b/src/modules/base/static/svg/icon-folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-goods.svg b/src/modules/base/static/svg/icon-goods.svg new file mode 100644 index 0000000..391d0ea --- /dev/null +++ b/src/modules/base/static/svg/icon-goods.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-home.svg b/src/modules/base/static/svg/icon-home.svg new file mode 100644 index 0000000..94cf445 --- /dev/null +++ b/src/modules/base/static/svg/icon-home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-hot.svg b/src/modules/base/static/svg/icon-hot.svg new file mode 100644 index 0000000..b907eeb --- /dev/null +++ b/src/modules/base/static/svg/icon-hot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-info.svg b/src/modules/base/static/svg/icon-info.svg new file mode 100644 index 0000000..4805c9a --- /dev/null +++ b/src/modules/base/static/svg/icon-info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-iot.svg b/src/modules/base/static/svg/icon-iot.svg new file mode 100644 index 0000000..f7ccae0 --- /dev/null +++ b/src/modules/base/static/svg/icon-iot.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-light.svg b/src/modules/base/static/svg/icon-light.svg new file mode 100644 index 0000000..b07a126 --- /dev/null +++ b/src/modules/base/static/svg/icon-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-like.svg b/src/modules/base/static/svg/icon-like.svg new file mode 100644 index 0000000..c49af81 --- /dev/null +++ b/src/modules/base/static/svg/icon-like.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-list.svg b/src/modules/base/static/svg/icon-list.svg new file mode 100644 index 0000000..a53f8ba --- /dev/null +++ b/src/modules/base/static/svg/icon-list.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-local.svg b/src/modules/base/static/svg/icon-local.svg new file mode 100644 index 0000000..6bedcdf --- /dev/null +++ b/src/modules/base/static/svg/icon-local.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-log.svg b/src/modules/base/static/svg/icon-log.svg new file mode 100644 index 0000000..e35c47b --- /dev/null +++ b/src/modules/base/static/svg/icon-log.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-map.svg b/src/modules/base/static/svg/icon-map.svg new file mode 100644 index 0000000..9befbd4 --- /dev/null +++ b/src/modules/base/static/svg/icon-map.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-match.svg b/src/modules/base/static/svg/icon-match.svg new file mode 100644 index 0000000..f7c68ef --- /dev/null +++ b/src/modules/base/static/svg/icon-match.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-menu.svg b/src/modules/base/static/svg/icon-menu.svg new file mode 100644 index 0000000..b58dbf9 --- /dev/null +++ b/src/modules/base/static/svg/icon-menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-monitor.svg b/src/modules/base/static/svg/icon-monitor.svg new file mode 100644 index 0000000..5fa7b77 --- /dev/null +++ b/src/modules/base/static/svg/icon-monitor.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-msg.svg b/src/modules/base/static/svg/icon-msg.svg new file mode 100644 index 0000000..54c0992 --- /dev/null +++ b/src/modules/base/static/svg/icon-msg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-news.svg b/src/modules/base/static/svg/icon-news.svg new file mode 100644 index 0000000..5cec609 --- /dev/null +++ b/src/modules/base/static/svg/icon-news.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-notice.svg b/src/modules/base/static/svg/icon-notice.svg new file mode 100644 index 0000000..5c8048d --- /dev/null +++ b/src/modules/base/static/svg/icon-notice.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-params.svg b/src/modules/base/static/svg/icon-params.svg new file mode 100644 index 0000000..9683e72 --- /dev/null +++ b/src/modules/base/static/svg/icon-params.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-phone.svg b/src/modules/base/static/svg/icon-phone.svg new file mode 100644 index 0000000..8910aab --- /dev/null +++ b/src/modules/base/static/svg/icon-phone.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-pic.svg b/src/modules/base/static/svg/icon-pic.svg new file mode 100644 index 0000000..02265cd --- /dev/null +++ b/src/modules/base/static/svg/icon-pic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-question.svg b/src/modules/base/static/svg/icon-question.svg new file mode 100644 index 0000000..1731198 --- /dev/null +++ b/src/modules/base/static/svg/icon-question.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-quick.svg b/src/modules/base/static/svg/icon-quick.svg new file mode 100644 index 0000000..61bdb79 --- /dev/null +++ b/src/modules/base/static/svg/icon-quick.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-rank.svg b/src/modules/base/static/svg/icon-rank.svg new file mode 100644 index 0000000..60916c5 --- /dev/null +++ b/src/modules/base/static/svg/icon-rank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-reward.svg b/src/modules/base/static/svg/icon-reward.svg new file mode 100644 index 0000000..f01f848 --- /dev/null +++ b/src/modules/base/static/svg/icon-reward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-search.svg b/src/modules/base/static/svg/icon-search.svg new file mode 100644 index 0000000..166aebf --- /dev/null +++ b/src/modules/base/static/svg/icon-search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-set.svg b/src/modules/base/static/svg/icon-set.svg new file mode 100644 index 0000000..fb53057 --- /dev/null +++ b/src/modules/base/static/svg/icon-set.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-tag.svg b/src/modules/base/static/svg/icon-tag.svg new file mode 100644 index 0000000..84adbce --- /dev/null +++ b/src/modules/base/static/svg/icon-tag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-task.svg b/src/modules/base/static/svg/icon-task.svg new file mode 100644 index 0000000..470280f --- /dev/null +++ b/src/modules/base/static/svg/icon-task.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-time.svg b/src/modules/base/static/svg/icon-time.svg new file mode 100644 index 0000000..7ac6296 --- /dev/null +++ b/src/modules/base/static/svg/icon-time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-tutorial.svg b/src/modules/base/static/svg/icon-tutorial.svg new file mode 100644 index 0000000..cc2323e --- /dev/null +++ b/src/modules/base/static/svg/icon-tutorial.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-unlock.svg b/src/modules/base/static/svg/icon-unlock.svg new file mode 100644 index 0000000..78b6413 --- /dev/null +++ b/src/modules/base/static/svg/icon-unlock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-user.svg b/src/modules/base/static/svg/icon-user.svg new file mode 100644 index 0000000..66d8df7 --- /dev/null +++ b/src/modules/base/static/svg/icon-user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-video.svg b/src/modules/base/static/svg/icon-video.svg new file mode 100644 index 0000000..1eee5b9 --- /dev/null +++ b/src/modules/base/static/svg/icon-video.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-vip.svg b/src/modules/base/static/svg/icon-vip.svg new file mode 100644 index 0000000..31f4f67 --- /dev/null +++ b/src/modules/base/static/svg/icon-vip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-warn.svg b/src/modules/base/static/svg/icon-warn.svg new file mode 100644 index 0000000..3eab18d --- /dev/null +++ b/src/modules/base/static/svg/icon-warn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-work.svg b/src/modules/base/static/svg/icon-work.svg new file mode 100644 index 0000000..bea8473 --- /dev/null +++ b/src/modules/base/static/svg/icon-work.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/icon-workbench.svg b/src/modules/base/static/svg/icon-workbench.svg new file mode 100644 index 0000000..ff959d3 --- /dev/null +++ b/src/modules/base/static/svg/icon-workbench.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/image.svg b/src/modules/base/static/svg/image.svg new file mode 100644 index 0000000..fca2c66 --- /dev/null +++ b/src/modules/base/static/svg/image.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/modules/base/static/svg/import.svg b/src/modules/base/static/svg/import.svg new file mode 100644 index 0000000..ae272f2 --- /dev/null +++ b/src/modules/base/static/svg/import.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/left.svg b/src/modules/base/static/svg/left.svg new file mode 100644 index 0000000..f49a79b --- /dev/null +++ b/src/modules/base/static/svg/left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/my.svg b/src/modules/base/static/svg/my.svg new file mode 100644 index 0000000..a422ae4 --- /dev/null +++ b/src/modules/base/static/svg/my.svg @@ -0,0 +1,21 @@ + + + + + diff --git a/src/modules/base/static/svg/order.svg b/src/modules/base/static/svg/order.svg new file mode 100644 index 0000000..1dbbc68 --- /dev/null +++ b/src/modules/base/static/svg/order.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/play.svg b/src/modules/base/static/svg/play.svg new file mode 100644 index 0000000..e5b5f40 --- /dev/null +++ b/src/modules/base/static/svg/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/plus-border.svg b/src/modules/base/static/svg/plus-border.svg new file mode 100644 index 0000000..a36cf9d --- /dev/null +++ b/src/modules/base/static/svg/plus-border.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/plus.svg b/src/modules/base/static/svg/plus.svg new file mode 100644 index 0000000..4207733 --- /dev/null +++ b/src/modules/base/static/svg/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/refresh.svg b/src/modules/base/static/svg/refresh.svg new file mode 100644 index 0000000..a9f1281 --- /dev/null +++ b/src/modules/base/static/svg/refresh.svg @@ -0,0 +1,21 @@ + + + + + diff --git a/src/modules/base/static/svg/right.svg b/src/modules/base/static/svg/right.svg new file mode 100644 index 0000000..d488008 --- /dev/null +++ b/src/modules/base/static/svg/right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/screen-full.svg b/src/modules/base/static/svg/screen-full.svg new file mode 100644 index 0000000..a0e4c57 --- /dev/null +++ b/src/modules/base/static/svg/screen-full.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/modules/base/static/svg/screen-normal.svg b/src/modules/base/static/svg/screen-normal.svg new file mode 100644 index 0000000..c5d80d5 --- /dev/null +++ b/src/modules/base/static/svg/screen-normal.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/modules/base/static/svg/search.svg b/src/modules/base/static/svg/search.svg new file mode 100644 index 0000000..54e1135 --- /dev/null +++ b/src/modules/base/static/svg/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/set.svg b/src/modules/base/static/svg/set.svg new file mode 100644 index 0000000..aa84b0a --- /dev/null +++ b/src/modules/base/static/svg/set.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/sort.svg b/src/modules/base/static/svg/sort.svg new file mode 100644 index 0000000..f842b4b --- /dev/null +++ b/src/modules/base/static/svg/sort.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/stats.svg b/src/modules/base/static/svg/stats.svg new file mode 100644 index 0000000..25eec42 --- /dev/null +++ b/src/modules/base/static/svg/stats.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/success.svg b/src/modules/base/static/svg/success.svg new file mode 100644 index 0000000..66d15fd --- /dev/null +++ b/src/modules/base/static/svg/success.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/team.svg b/src/modules/base/static/svg/team.svg new file mode 100644 index 0000000..32acf07 --- /dev/null +++ b/src/modules/base/static/svg/team.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/static/svg/trend.svg b/src/modules/base/static/svg/trend.svg new file mode 100644 index 0000000..aa8215b --- /dev/null +++ b/src/modules/base/static/svg/trend.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/base/store/app.ts b/src/modules/base/store/app.ts new file mode 100644 index 0000000..0a0bd57 --- /dev/null +++ b/src/modules/base/store/app.ts @@ -0,0 +1,69 @@ +import { defineStore } from 'pinia'; +import { reactive, ref } from 'vue'; +import { merge } from 'lodash-es'; +import { useBrowser } from '/@/cool'; +import { storage } from '/@/cool/utils'; +import { config } from '/@/config'; + +export const useAppStore = defineStore('app', function () { + const { browser, onScreenChange } = useBrowser(); + + // 基本信息 + const info = reactive({ + ...config.app + }); + + // 设置基本信息 + function set(data: any) { + merge(info, data); + storage.set('__app__', info); + } + + // 是否折叠 + const isFold = ref(false); + + // 折叠 + function fold(v?: boolean) { + if (v === undefined) { + v = !isFold.value; + } + + isFold.value = v; + } + + // 是否全屏 + const isFull = ref(false); + + // 设置全屏 + function setFull(state: boolean) { + isFull.value = state; + } + + // 事件 + const events = reactive<{ [key: string]: any[] }>({ + hasToken: [] + }); + + // 添加事件 + function addEvent(name: string, func: any) { + if (func) { + events[name].push(func); + } + } + + // 监听屏幕变化 + onScreenChange(() => { + isFold.value = browser.isMini; + }); + + return { + info, + isFold, + fold, + isFull, + setFull, + events, + set, + addEvent + }; +}); diff --git a/src/modules/base/store/index.ts b/src/modules/base/store/index.ts new file mode 100644 index 0000000..1aa03f8 --- /dev/null +++ b/src/modules/base/store/index.ts @@ -0,0 +1,18 @@ +import { useAppStore } from './app'; +import { useMenuStore } from './menu'; +import { useProcessStore } from './process'; +import { useUserStore } from './user'; + +export function useStore() { + const app = useAppStore(); + const menu = useMenuStore(); + const process = useProcessStore(); + const user = useUserStore(); + + return { + app, + menu, + process, + user + }; +} diff --git a/src/modules/base/store/menu.ts b/src/modules/base/store/menu.ts new file mode 100644 index 0000000..5dfbc1d --- /dev/null +++ b/src/modules/base/store/menu.ts @@ -0,0 +1,205 @@ +import { defineStore } from 'pinia'; +import { ref } from 'vue'; +import { deepTree, revDeepTree, storage } from '/@/cool/utils'; +import { isArray, isEmpty, orderBy } from 'lodash-es'; +import { router, service } from '/@/cool'; +import { revisePath } from '../utils'; +import { config } from '/@/config'; + +// 本地缓存 +const data = storage.info(); + +export const useMenuStore = defineStore('menu', function () { + // 所有菜单 + const all = ref([]); + + // 视图路由 + const routes = ref([]); + + // 菜单组 + const group = ref(data['base.menuGroup'] || []); + + // 左侧菜单列表 + const list = ref([]); + + // 权限列表 + const perms = ref(data['base.menuPerms'] || []); + + // 设置左侧菜单 + function setMenu(i: number = 0) { + // 显示分组显示菜单 + if (config.app.menu.isGroup) { + list.value = group.value.filter(e => e.isShow)[i]?.children || []; + } else { + list.value = group.value; + } + } + + // 设置权限 + function setPerms(list: Menu.List) { + function deep(d: any) { + if (typeof d == 'object') { + if (d.permission) { + if (d.namespace) { + d._permission = {}; + for (const i in d.permission) { + d._permission[i] = + list.findIndex(e => + e + .replace(/:/g, '/') + .includes(`${d.namespace.replace('admin/', '')}/${i}`) + ) >= 0; + } + } else { + console.error('namespace is required', d); + } + } else { + for (const i in d) { + deep(d[i]); + } + } + } + } + + perms.value = list; + storage.set('base.menuPerms', list); + + deep(service); + } + + // 设置视图 + function setRoutes(list: Menu.List) { + // 获取第一个菜单路径 + const fp = getPath(group.value); + + // 查找符合路由 + const route = list.find(e => (e.meta!.isHome = e.path == fp)); + + // 过滤菜单 + routes.value = list.filter(e => e.type == 1); + + if (route) { + // 移除旧路由 + router.del('home'); + router.del('homeRedirect'); + + // 添加一个重定向 + if (route.path != '/') { + const item = routes.value.find(e => e.name == 'homeRedirect'); + + if (item) { + item.path = route.path; + } else { + routes.value.push({ + path: route.path, + redirect: '/', + name: 'homeRedirect' + } as any); + } + } + + // 设置为首页 + route.path = '/'; + route.name = 'home'; + } + } + + // 设置菜单组 + function setGroup(list: Menu.List) { + group.value = orderBy(deepTree(list), 'orderNum'); + storage.set('base.menuGroup', group.value); + } + + // 获取菜单,权限信息 + async function get() { + function next(res: { menus: Menu.List; perms?: any[] }) { + // 所有菜单 + all.value = res.menus; + + // 菜单格式化 + const list = res.menus + ?.filter(e => e.type != 2) + .map(e => { + const path = revisePath(e.router || String(e.id)); + const isShow = e.isShow === undefined ? true : e.isShow; + + return { + ...e, + path, + isShow, + meta: { + ...e.meta, + label: e.name, // 菜单名称的唯一标识 + keepAlive: e.keepAlive || 0 + }, + name: `${e.name}-${e.id}`, // 避免重复命名之前的冲突 + children: [] + }; + }); + + // 设置权限 + setPerms(res.perms || []); + + // 设置菜单组 + setGroup(list); + + // 设置视图路由 + setRoutes(list); + + // 设置菜单 + setMenu(); + + return list; + } + + // 自定义菜单 + if (!isEmpty(config.app.menu.list)) { + next({ + menus: revDeepTree(config.app.menu.list || []) + }); + } else { + // 动态菜单 + await service.base.comm.permmenu().then(next); + } + } + + // 获取菜单路径 + function getPath(data: Menu.Item | Menu.List) { + const list = isArray(data) ? data : [data]; + + let path = ''; + + function deep(arr: Menu.List) { + arr.forEach((e: Menu.Item) => { + switch (e.type) { + case 0: + deep(e.children || []); + break; + case 1: + if (!path) { + path = e.path; + } + break; + } + }); + } + + deep(list); + + return path; + } + + return { + all, + routes, + group, + list, + perms, + get, + setPerms, + setMenu, + setRoutes, + setGroup, + getPath + }; +}); diff --git a/src/modules/base/store/process.ts b/src/modules/base/store/process.ts new file mode 100644 index 0000000..076a1c0 --- /dev/null +++ b/src/modules/base/store/process.ts @@ -0,0 +1,74 @@ +import { defineStore } from 'pinia'; +import { ref } from 'vue'; +import { assign } from 'lodash-es'; + +export const useProcessStore = defineStore('process', function () { + const list = ref([]); + + // 添加 + function add(data: any) { + list.value.forEach((e: Process.Item) => { + e.active = false; + }); + + if (!data.meta) { + data.meta = {}; + } + + if (!data.meta?.isHome && data.meta?.process !== false) { + const index = list.value.findIndex(e => e.path === data.path); + + if (index < 0) { + list.value.push({ + ...data, + active: true + }); + } else { + assign(list.value[index], data, { active: true }); + } + } + } + + // 关闭当前 + function close() { + const index = list.value.findIndex(e => e.active); + + if (index > -1) { + list.value.splice(index, 1); + } + } + + // 移除 + function remove(index: number) { + list.value.splice(index, 1); + } + + // 设置 + function set(data: Process.Item[]) { + list.value = data; + } + + // 清空 + function clear() { + list.value = []; + } + + // 设置标题 + function setTitle(title: string) { + const item = list.value.find(e => e.active); + + if (item) { + item.meta.label = title; + } + } + + return { + list, + add, + remove, + close, + set, + clear, + setTitle + }; +}); diff --git a/src/modules/base/store/user.ts b/src/modules/base/store/user.ts new file mode 100644 index 0000000..071a2cf --- /dev/null +++ b/src/modules/base/store/user.ts @@ -0,0 +1,88 @@ +import { defineStore } from 'pinia'; +import { ref } from 'vue'; +import { storage } from '/@/cool/utils'; +import { service, router } from '/@/cool'; + +// 本地缓存 +const data = storage.info(); + +export const useUserStore = defineStore('user', function () { + // 标识 + const token = ref(data.token); + + // 设置标识 + function setToken(data: { + token: string; + expire: number; + refreshToken: string; + refreshExpire: number; + }) { + // 请求的唯一标识 + token.value = data.token; + storage.set('token', data.token, data.expire); + + // 刷新 token 的唯一标识 + storage.set('refreshToken', data.refreshToken, data.refreshExpire); + } + + // 刷新标识 + async function refreshToken(): Promise { + return new Promise((resolve, reject) => { + service.base.open + .refreshToken({ + refreshToken: storage.get('refreshToken') + }) + .then(res => { + setToken(res); + resolve(res.token); + }) + .catch(err => { + logout(); + reject(err); + }); + }); + } + + // 用户信息 + const info = ref(data.userInfo); + + // 设置用户信息 + function set(value: any) { + info.value = value; + storage.set('userInfo', value); + } + + // 清除用户 + function clear() { + storage.remove('userInfo'); + storage.remove('token'); + token.value = ''; + info.value = null; + } + + // 退出 + async function logout() { + clear(); + router.clear(); + router.push('/login'); + } + + // 获取用户信息 + async function get() { + return service.base.comm.person().then(res => { + set(res); + return res; + }); + } + + return { + token, + info, + get, + set, + logout, + clear, + setToken, + refreshToken + }; +}); diff --git a/src/modules/base/types/index.d.ts b/src/modules/base/types/index.d.ts new file mode 100644 index 0000000..81675fe --- /dev/null +++ b/src/modules/base/types/index.d.ts @@ -0,0 +1,52 @@ +declare namespace Menu { + enum Type { + '目录' = 0, + '菜单' = 1, + '权限' = 2 + } + + interface Item { + id: number; + parentId: number; + path: string; + router?: string; + viewPath?: string; + type: Type; + name: string; + icon: string; + badge?: number; + badgeColor?: 'primary' | 'success' | 'warning' | 'danger' | 'info'; + orderNum: number; + isShow: number | boolean; + keepAlive?: number; + meta?: { + label?: string; + keepAlive?: number | boolean; + iframeUrl?: string; + isHome?: boolean; + [key: string]: any; + }; + children?: Item[]; + component?: any; + redirect?: string; + [key: string]: any; + } + + type List = Item[]; +} + +declare namespace Process { + interface Item { + active: boolean; + name: string; + path: string; + fullPath: string; + meta: { + label: string; + [key: string]: any; + }; + [key: string]: any; + } + + type List = Item[]; +} diff --git a/src/modules/base/utils/index.ts b/src/modules/base/utils/index.ts new file mode 100644 index 0000000..fa24a0b --- /dev/null +++ b/src/modules/base/utils/index.ts @@ -0,0 +1,9 @@ +export function revisePath(path: string) { + if (!path) { + return ''; + } + + return path.startsWith('/') ? path : `/${path}`; +} + +export * from './permission'; diff --git a/src/modules/base/utils/permission.ts b/src/modules/base/utils/permission.ts new file mode 100644 index 0000000..efa9f60 --- /dev/null +++ b/src/modules/base/utils/permission.ts @@ -0,0 +1,30 @@ +import { useStore } from '../store'; +import { isObject } from 'lodash-es'; + +function parse(value: any) { + const { menu } = useStore(); + + if (typeof value == 'string') { + return value ? menu.perms.some((e: any) => e.includes(value.replace(/\s/g, ''))) : false; + } else { + return Boolean(value); + } +} + +export function checkPerm(value: string | { or?: string[]; and?: string[] }) { + if (!value) { + return false; + } + + if (isObject(value)) { + if (value.or) { + return value.or.some(parse); + } + + if (value.and) { + return value.and.some((e: any) => !parse(e)) ? false : true; + } + } + + return parse(value); +} diff --git a/src/modules/base/views/frame.vue b/src/modules/base/views/frame.vue new file mode 100644 index 0000000..4c0a491 --- /dev/null +++ b/src/modules/base/views/frame.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/src/modules/base/views/info.vue b/src/modules/base/views/info.vue new file mode 100644 index 0000000..8c836e7 --- /dev/null +++ b/src/modules/base/views/info.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/src/modules/base/views/log.vue b/src/modules/base/views/log.vue new file mode 100644 index 0000000..3204876 --- /dev/null +++ b/src/modules/base/views/log.vue @@ -0,0 +1,153 @@ + + + diff --git a/src/modules/base/views/menu/components/exp.vue b/src/modules/base/views/menu/components/exp.vue new file mode 100644 index 0000000..eb85384 --- /dev/null +++ b/src/modules/base/views/menu/components/exp.vue @@ -0,0 +1,109 @@ + + + diff --git a/src/modules/base/views/menu/components/imp.vue b/src/modules/base/views/menu/components/imp.vue new file mode 100644 index 0000000..73faf95 --- /dev/null +++ b/src/modules/base/views/menu/components/imp.vue @@ -0,0 +1,122 @@ + + + diff --git a/src/modules/base/views/menu/index.vue b/src/modules/base/views/menu/index.vue new file mode 100644 index 0000000..597a004 --- /dev/null +++ b/src/modules/base/views/menu/index.vue @@ -0,0 +1,404 @@ + + + diff --git a/src/modules/base/views/param.vue b/src/modules/base/views/param.vue new file mode 100644 index 0000000..c7ef57e --- /dev/null +++ b/src/modules/base/views/param.vue @@ -0,0 +1,226 @@ + + + diff --git a/src/modules/base/views/role.vue b/src/modules/base/views/role.vue new file mode 100644 index 0000000..8dadea2 --- /dev/null +++ b/src/modules/base/views/role.vue @@ -0,0 +1,165 @@ + + + diff --git a/src/modules/base/views/user/components/dept-list.vue b/src/modules/base/views/user/components/dept-list.vue new file mode 100644 index 0000000..19d5519 --- /dev/null +++ b/src/modules/base/views/user/components/dept-list.vue @@ -0,0 +1,503 @@ + + + + + diff --git a/src/modules/base/views/user/components/user-move.vue b/src/modules/base/views/user/components/user-move.vue new file mode 100644 index 0000000..8d51495 --- /dev/null +++ b/src/modules/base/views/user/components/user-move.vue @@ -0,0 +1,74 @@ + + + diff --git a/src/modules/base/views/user/index.vue b/src/modules/base/views/user/index.vue new file mode 100644 index 0000000..bcd761c --- /dev/null +++ b/src/modules/base/views/user/index.vue @@ -0,0 +1,342 @@ + + + diff --git a/src/modules/cs/components/index.vue b/src/modules/cs/components/index.vue new file mode 100644 index 0000000..3e4f255 --- /dev/null +++ b/src/modules/cs/components/index.vue @@ -0,0 +1,244 @@ + + + + + diff --git a/src/modules/cs/components/message.vue b/src/modules/cs/components/message.vue new file mode 100644 index 0000000..2af1d6a --- /dev/null +++ b/src/modules/cs/components/message.vue @@ -0,0 +1,526 @@ + + + + + diff --git a/src/modules/cs/components/session.vue b/src/modules/cs/components/session.vue new file mode 100644 index 0000000..b983125 --- /dev/null +++ b/src/modules/cs/components/session.vue @@ -0,0 +1,223 @@ + + + + + diff --git a/src/modules/cs/components/tools/emoji.vue b/src/modules/cs/components/tools/emoji.vue new file mode 100644 index 0000000..8f46380 --- /dev/null +++ b/src/modules/cs/components/tools/emoji.vue @@ -0,0 +1,162 @@ + + + + + + + diff --git a/src/modules/cs/config.ts b/src/modules/cs/config.ts new file mode 100644 index 0000000..4245f85 --- /dev/null +++ b/src/modules/cs/config.ts @@ -0,0 +1,10 @@ +import type { ModuleConfig } from '/@/cool'; + +export default (): ModuleConfig => { + return { + toolbar: { + order: 2, + component: import('./components/index.vue') + } + }; +}; diff --git a/src/modules/cs/hooks/index.ts b/src/modules/cs/hooks/index.ts new file mode 100644 index 0000000..df17a57 --- /dev/null +++ b/src/modules/cs/hooks/index.ts @@ -0,0 +1,5 @@ +export * from "./socket"; +export * from "./session"; +export * from "./message"; +export * from "./tools"; +export * from "./notice"; diff --git a/src/modules/cs/hooks/message.ts b/src/modules/cs/hooks/message.ts new file mode 100644 index 0000000..c05b532 --- /dev/null +++ b/src/modules/cs/hooks/message.ts @@ -0,0 +1,128 @@ +import { defineStore } from "pinia"; +import { computed, ref } from "vue"; +import type { Cs } from "../types"; +import dayjs from "dayjs"; +import { service } from "/@/cool"; +import { isEmpty, last } from "lodash-es"; +import { useSession } from "./session"; +import { uuid } from "/@/cool/utils"; +import { useTools } from "./tools"; +import { dateFormatter } from "../utils"; +import { useBase } from "/$/base"; + +export const useMessage = defineStore("cs.message", () => { + const session = useSession(); + const tools = useTools(); + const { user } = useBase(); + + // 加载中 + const loading = ref(false); + + // 未读消息数 + const unread = ref(0); + + // 所有页 + const data = ref<{ id: string; data: Cs.Msg[] }[]>([]); + + // 列表 + const list = computed(() => { + data.value.forEach((e) => { + if (e.data[0]) { + let date = e.data[0].createTime; + + if (date) { + e.data.forEach((a, i) => { + const d = dateFormatter(a.createTime); + + if (i == 0) { + a.date = d; + } + + if (dayjs(a.createTime).subtract(10, "minute").isAfter(dayjs(date))) { + a.date = d; + date = a.createTime; + } + }); + } + } + }); + + return data.value; + }); + + // 追加消息 + function append(item: Cs.Msg) { + const list = last(data.value)?.data; + + if (list) { + list.push({ + sessionId: session.info?.id, + type: 1, + nickName: user.info?.name, + avatarUrl: user.info?.headImg, + ...item + }); + + tools.scrollToBottom(); + } + } + + // 获取消息 + async function refresh(params?: any) { + loading.value = true; + + if (params.page == 1) { + data.value = []; + } + + await service.cs.msg + .page({ + sessionId: session.info?.id, + order: "createTime", + sort: "desc", + ...params + }) + .then((res) => { + if (!isEmpty(res.list)) { + res.list.forEach((e) => { + if (e.type == 1) { + e.avatarUrl = e.adminUserHeadImg; + e.nickName = e.adminUserName; + } + }); + + data.value.unshift({ + id: uuid(), + data: res.list.reverse() as any[] + }); + } + }); + + loading.value = false; + } + + // 获取未读消息 + function getUnread() { + service.cs.msg.unreadCount().then((res) => { + unread.value = res; + }); + } + + // 读消息 + function read(id: number) { + service.cs.msg.read({ + msgIds: [id] + }); + } + + return { + data, + list, + loading, + unread, + append, + refresh, + read, + getUnread + }; +}); diff --git a/src/modules/cs/hooks/notice.tsx b/src/modules/cs/hooks/notice.tsx new file mode 100644 index 0000000..8b9690d --- /dev/null +++ b/src/modules/cs/hooks/notice.tsx @@ -0,0 +1,68 @@ +import Ding from "/$/cs/static/audio/ding.wav"; +import type { Cs } from "../types"; +import { ElNotification } from "element-plus"; +import { getEmoji } from "../utils"; +import { useSession } from "./session"; + +export function useNotice() { + const session = useSession(); + + // ding + const audio = new Audio(Ding); + + // 消息提示 + function create({ content, user, sessionId }: Cs.Msg, { open }: { open: () => Promise }) { + if (content) { + const icon = ; + + let message = content.data; + + switch (content.type) { + case "image": + message = "[图片]"; + break; + + case "voice": + message = "[语音]"; + break; + + case "video": + message = "[视频]"; + break; + + case "file": + message = "[文件]"; + break; + + case "location": + message = "[位置]"; + break; + + case "emoji": + message = ( + + ); + break; + } + + ElNotification({ + title: user.nickName, + message, + icon, + async onClick() { + await open(); + + // 切换会话 + session.setById(sessionId!); + } + }); + } + + // 播放声音 + audio?.play(); + } + + return { + create + }; +} diff --git a/src/modules/cs/hooks/session.ts b/src/modules/cs/hooks/session.ts new file mode 100644 index 0000000..26b1c33 --- /dev/null +++ b/src/modules/cs/hooks/session.ts @@ -0,0 +1,97 @@ +import { defineStore } from "pinia"; +import { reactive, ref } from "vue"; +import { Cs } from "../types"; +import { service } from "/@/cool"; + +export const useSession = defineStore("cs.session", () => { + // 详情 + const info = ref(); + + // 列表 + const list = ref([]); + + // 是否加载完 + const loaded = ref(false); + + // 加载状态 + const loading = ref(false); + + // 分页 + const pagination = reactive({ + page: 1, + size: 20 + }); + + // 请求参数 + const reqParams = { + order: "updateTime", + sort: "desc" + }; + + // 刷新 + async function refresh(params?: any) { + loading.value = true; + + // 合并参数 + Object.assign(reqParams, params); + + // 请求 + await service.cs.session + .page({ + ...pagination, + ...reqParams + }) + .then((res) => { + // 设置分页 + Object.assign(pagination, res.pagination); + + if (res.pagination.page == 1) { + list.value = res.list; + } else { + list.value.push(...res.list); + } + + // 是否加载完成 + loaded.value = res.pagination.total <= list.value.length; + + // 默认第一个 + if (!info.value) { + set(list.value[0]); + } + }); + + loading.value = false; + } + + // 设置会话 + function set(data?: Cs.Session) { + if (data) { + data.adminUnreadCount = 0; + } + + info.value = data; + } + + // 通过id设置会话 + function setById(sessionId: number) { + const item = list.value.find((e) => e.id == sessionId); + set(item); + } + + // 清空会话 + function clear() { + info.value = undefined; + } + + return { + info, + list, + set, + setById, + clear, + pagination, + loaded, + loading, + refresh + }; +}); diff --git a/src/modules/cs/hooks/socket.ts b/src/modules/cs/hooks/socket.ts new file mode 100644 index 0000000..dce47a9 --- /dev/null +++ b/src/modules/cs/hooks/socket.ts @@ -0,0 +1,95 @@ +import type { Cs } from "../types"; +import { defineStore } from "pinia"; +import io, { type Socket } from "socket.io-client"; +import { useSession } from "./session"; +import { useBase } from "/$/base"; +import { config } from "/@/config"; +import { useMessage } from "./message"; +import { useCool } from "/@/cool"; + +export const useSocket = defineStore("cs.socket", () => { + const { mitt } = useCool(); + const { user } = useBase(); + const session = useSession(); + const message = useMessage(); + + let client = undefined as Socket | undefined; + + function connect() { + if (!user.token) { + return false; + } + + if (client) { + client.disconnect(); + client = undefined; + } + + if (!client) { + client = io(config.host + "/cs", { + transports: ["websocket", "polling"] + }); + + client.auth = { + isAdmin: true, + token: user.token + }; + + client.on("connect", () => { + console.log("[cs] connect"); + }); + + client.on("disconnect", () => { + console.log("[cs] disconnect"); + }); + + client.on("msg", (data: Cs.Msg) => { + if ((data.type == 1 && data.userId != user.info?.id) || data.type == 0) { + // 判断是否是当前会话 + if (data.sessionId == session.info?.id) { + message.append({ + ...data.user, + ...data + }); + } else { + // 设置其他会话信息 + session.list.forEach((e) => { + if (e.id == data.sessionId) { + if (!e.adminUnreadCount) { + e.adminUnreadCount = 0; + } + + e.adminUnreadCount += 1; + e.lastMsg = data; + } + }); + } + + // 发送事件 + mitt.emit("cs.msg", data); + } + }); + } + } + + function send(content: Cs.Content) { + if (client) { + // 发送事件 + client.emit("send", { + sessionId: session.info?.id, + content + }); + + // 追加消息 + message.append({ content }); + } else { + console.log("[cs] client error"); + } + } + + return { + connect, + client, + send + }; +}); diff --git a/src/modules/cs/hooks/tools.ts b/src/modules/cs/hooks/tools.ts new file mode 100644 index 0000000..354a862 --- /dev/null +++ b/src/modules/cs/hooks/tools.ts @@ -0,0 +1,28 @@ +import { defineStore } from "pinia"; +import { nextTick, ref } from "vue"; + +export const useTools = defineStore("cs.tools", () => { + // 是否展开 + const isExpand = ref(true); + + // 收起、展开 + function expand(value?: boolean) { + isExpand.value = value === undefined ? !isExpand.value : value; + } + + // 滚动到底部 + async function scrollToBottom() { + await nextTick(); + + document.querySelector(".cs-message .el-scrollbar__wrap")?.scroll({ + top: 9999, + behavior: "smooth" + }); + } + + return { + isExpand, + expand, + scrollToBottom + }; +}); diff --git a/src/modules/cs/index.ts b/src/modules/cs/index.ts new file mode 100644 index 0000000..b740056 --- /dev/null +++ b/src/modules/cs/index.ts @@ -0,0 +1,13 @@ +import { useMessage, useSession, useSocket } from "./hooks"; + +export function useCs() { + const socket = useSocket(); + const message = useMessage(); + const session = useSession(); + + return { + socket, + message, + session + }; +} diff --git a/src/modules/cs/static/audio/ding.wav b/src/modules/cs/static/audio/ding.wav new file mode 100644 index 0000000000000000000000000000000000000000..0479aa8fec4816e3ea95d6595d18caa2dbf60578 GIT binary patch literal 3534 zcmc(h4`iHo7{|XmC*ou$i;9Yfh^WdU(#ocyVv8)Aimck`s^Y9wXR3>;h>2(;qAIE? zs%omLDyn8;PE}RaOhrXiM8#A^MMOoMbIysl?(@9Ad-L9{mzgQMpZDJP{r;Xm-{<>0 z@4a`pr@Q;vr_y&{AN?l&<4}F2q)%9%eJ(W|l|rgiZ_knb8t|UJ?r(dJboWQO?maOa z|6*TD+n$y^t*ttBV(7#eQIz}0Yx5(=%N23tCjW7~{X45;yN~UJSi#5c+%n9+E_Dun zup5@GQnnuxE6(9^ewew~s#JczX50Ix&wrhQV17zP|2re&Tb5sehJJNrp0a*T(x$g^ zp4JY{DXX-S-b!(m#UjVCp_JCNqGgUXWx&c*j$ayNk+qCvL^~8^XI*c#gk2IZVO6Ew zYEqk8wNLxir(-&ZW5V;eZ!N5y{ z#OWYjPH$j4t*cx4Ch>lNUy3UC!tr~Z)u_&U)g9AU_-vxiLpV+5eI_)ed-{V&Iast) zOI*V`|NeqTsIFgM66qcLw>7?%WsHo!=@m8AqQoJ^@c989j;c$|{1~M)uLM<0C7CQ@9G9ouj(3^66l!JPHK#qUhp4;S2MP+iDQ=6sq-Fn zJO@dsf{u1!dyZO1h<{M^_#5ZT^upD*jKbAu*`{td#9$kPc?&c10yX?j-{CIn>ClUn zO~wG<2bh%#W@u)sv-eOj%JdxHs{8;->;hY-i+8-)nSkj6YILE^2o=ZSW$I*!^o;)6 zgiY}Mm_s-f3VAGFoDO5|K!8BG0a;}iOovKFI zkHf5-{>cV;v?<+94!g&_n)m}Ykyy@D@G|a*OD(X$Mn__Z0 z;dqV}qtYFf8Vtg&llm8lIDz7m%+LyP zdzrIgj$U+MhOH_nD!|wvfQ7fcjuUuIwJgvT9b6- z1;01#I_M`W&L$n@so&Iwa^)m?`XI zlKQ-9e1+|Oj(NB@!m|%$o3ODbJwY^k>gwp!0rr}iiWQ!LC#bxbe;T_`rpcS2Iq;{% zvEPCg(EZp)c`g>1zFFcVndwF*y9J&h;=ClvEOAmWZ3Jzit2y+1Nrrj$r5Yl%qGA;q zy7gnc8?4WGy3HPIvRY{I$*ebzx1h`mDPRXm-$I4WVhiv4TQEL>`d(7+Ui z@Ld9Z%Q-~f>p^RXmce=nbPZNftm{GT_dN-|N`_5hRD)G>&QZlXR+6h?bPfMBwM4Po zN%RPQE<%#42<)mk%HfvuBBY35=nnXnW05A8i%^kA%dkz8KS>o~vQ=SO!IizE);Tt) zq5>>RoDeq2Ei?jFfjR0(+uA9ep{%r3C?|KpTGjg$X>f*^dHm0>PIfCc`(RUzWA zAewQqeIIcwi?PBCJ`3~nKYn~amVfW|gXlh9oXtmr$lD{qj(=t6K!YH%<5#>}sE5z} h-=7OBF6C9cUwG$p4fJqGAs^r7|2>zgYkQ0u{{qX%l1l&p literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/angry-face.png b/src/modules/cs/static/emoji/angry-face.png new file mode 100644 index 0000000000000000000000000000000000000000..bd0b383210b1715293398434c1e93825742fdc99 GIT binary patch literal 3669 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/anguished-face.png b/src/modules/cs/static/emoji/anguished-face.png new file mode 100644 index 0000000000000000000000000000000000000000..fa4678b59d5aeeffa2134e8dc4d0838efddf7abf GIT binary patch literal 3584 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 BUP1r> literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/confused-face.png b/src/modules/cs/static/emoji/confused-face.png new file mode 100644 index 0000000000000000000000000000000000000000..b01d70e81b11b0b8d5e1204da063a07e1b8af876 GIT binary patch literal 3670 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 tehq(X% literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/crying-face.png b/src/modules/cs/static/emoji/crying-face.png new file mode 100644 index 0000000000000000000000000000000000000000..c5aae1ce8fba3448325f11fd2db2cca39b4b2559 GIT binary patch literal 3824 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/disappointed-but-relieved-face.png b/src/modules/cs/static/emoji/disappointed-but-relieved-face.png new file mode 100644 index 0000000000000000000000000000000000000000..f4f6e3eb594055bb555cfaa577fc9614a0a25f3c GIT binary patch literal 3709 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/disappointed-face.png b/src/modules/cs/static/emoji/disappointed-face.png new file mode 100644 index 0000000000000000000000000000000000000000..aa3e501ac4bf447b92e59dce19bc94451ff64f3a GIT binary patch literal 3584 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 BJEQ;r literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/drooling-face.png b/src/modules/cs/static/emoji/drooling-face.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e254504ae64b40ac3305a4fce22cfd297abbd8 GIT binary patch literal 3552 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 a#sC0D%Jxpe2kQ+00000gj5k{$<_&TUv_0XfLbz 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-savouring-delicious-food.png b/src/modules/cs/static/emoji/face-savouring-delicious-food.png new file mode 100644 index 0000000000000000000000000000000000000000..7f3d4344c71b57a2451a506de0afdf55b38ad4b2 GIT binary patch literal 3701 zcmc&$`8O2)_nsMB*2XSNc9Td%*%C8U23dwgwyX_$E0Luz_ANB_Fo_x!Au5!mtYhEJ zkTlk;*>{H5$M>)J-gEBroO{lF&U1fx&be`>#y8nn1X&;u2s>I|4|Br$|JSGJPS8nN z_sI#--$&j;LLlWYSZR(7Co|Lsa}xzA?GavpKP{Ds>B^>Cze2!Wz`ESf-q+7y!`Rv~~Oe?Nj z0xg$8zcQ`(H0V(Q|&2Ac>zTc>?eS| zD6kg@4!=^PVPMxAP%iw!LBY@^Fse9}L_eFtu=bjHDh{^(h7C+#0JRd}o5(>C2iVU7 zhc#g73OFKzRc%l&3&zfafs5ea?N|hK_dPqPmjHXA13nNic>bW271YXsgWR6~AfR3u z^qm83m%;HAIQWP|L2~S%fL0H>5a6f->^Oiw>Yzs+l+uBARdD!e_X8v7RRXIHppFrY zD1%ugP{;49ej;fBBxykFO|yUoUW4qsqFYOVf%h=5mI$ioX;G~-%&TyH82DoX*0Esc z4rr4FN26dJ4O-5F4y8le0-_5H9DD%#X<*hK4CsLMAn+OrNT>c&hAbq)z=8>w(gvM! z$A52tJ`ON#3OXghw&~_u1~6uKm?ea?dSKpTEe8gM zOuj_&?V(ejn?S*u4_NRA%a*kNzApA$?8rO2DDQntzBu*_x||9lSIW`+YyVbC#ppx9 z^ttP4vpQR`69{>8gRZd#{>J$56r+TJssC9MV$4nDBoYGczIQp#w z{D0N4P|x5#1j2$r>meWl_FPLXV`>hShB4l8iSPHWqtaUQqjsB%u#p*o`# zSK*)2UHRs%blk;<;k-wat6MmQf&zr2eFhJ2B(5A75{?edAMDR17Nk*nz0;nkO3Hk0 z^BWFv|B-e)R*~uu!u_GUGY$8c|MK=Vg&s(>XeH|ggPv2~O{^5{u4_wS!q$szoYTok zUdFv@+n*|5O-@eA%F1F4i-^Q}Y=D3^7qNSZ`W@p@J=$kUnR9e>j5#fuVXY<`s~#kf z6e)7m+WXwyXIZ0~1lI`*m9t+f{(SdAkffr}21u5K-zYt#STJ$Zc+SX1zpWwSUb_;y z5g!g$6X0s}*BP+!zzma5Y$Zp(+&4iY8`xw{-$0>QSniR|UX!J(&hdYxGE4~_^jpqu zor4qG4ZfuFhqI~8PkJv4>MvYgn*FU=ce!kpE-0iajvI0H>Q%*P&nDS(c*(N}W0kf2 zATz%k>w-stJx#Y-`eTZ&OI#Z#k>2I!Bj1S|8;iZohsuOX3hKuzP`8c=ODKLpxd+^F z@$r@UBlnCk1U)?0mHBylvt)fKkMP+H_wN7Xv(@`36ifPF&n2ea!kKwgnBH+T>+yfe zCKC=G=H2XdeVIaep8z@WI&N)BbYKTHPWn=;^rF7qKH62+no2xn%RKbn=i(c4?h~?xd}4vZe4XJyT0p*Y-gD zcHg-+)j7$e>*r=h$~UOL>t3u+rWibeRC{0u@5;P2ay;T?@36A==C)wa=>7k8(#k4! z_sUf_tmFw?@jt_+N8B}RtOC;QZNDI`Ioykj(C@j+eJj5TUuv8#`-N)QTF0Fu)>^kY zZ$?fnVQGQU=1xq4 zL=u$SC;DVpAn2-Fn_A?-IVV@RzKE_QsYX1md+JPEMOA4NZ=(IDB`GEb5j;w!yzu>P zTtNYZLFZxDjIt>P{@wYdQFP`v`_)I6uUxso5+oXuAo4k|^$8HO#nWr}-+fZZwwR&Y z&SZ+7VRdQq@^QZ7;~e!eXZ6OkN{yI>ncpS43@nEQuMYB%QRogI1FKhzJ@QIxvVa;E ze!P-FmiynS`qoLmVCS`>=KzIB5C1x`g z@pj>(u?TAREBqSv0x20hBkha2X;i)!Y z?Rb6!JA7d`^gJt~XdL!SNC>IhLT%wn*YiF!uIDI0Ff!$2iFd>j;akG$4PpMd{uM56 zl?h3jcdRu=S9A7V2Cdoakmx?!aeU~m7+fl^D?ut*{Dz_npRf@jAOI(?th{PK9r>0j zOVHTwevQ^tuN+kdqUqIIX&xCBey;*Zw!tk zp)3YC9Po^YU$wLY9dijQB_%hOxHxE(ek5r{`&mZTaLD>VvXFCCv4skc_UFv06nxqc zf5&WHsp@sEG+s#)MK>e5)qK+3yBnhyMbsb54o)m3J{-F)k15|kc7KoX^^a{0gmS%u z^T{j0BM73e8(@DO=bh|_9WrVIZRn))XYn(B{;^Gg!RmcO7D$(c0`l3xOI7zoJvh+O zGU$lz+QMU|%rKNvI_(}=yPKaS#y;VNTL+=5f4uj*=NZ#jKs4@iXen22nSVtykY|Ce5W##C@=Ydos6>)QK0-uHDO! z}g4l=jAi>_h&=_hY^*de!T(BjF5D(v%)W!M$(y>rIxUgkcURm<(19pM8t89n zrJA^w_s}>pPI+|lH(H0r!&t204thE|-j!u#zTr=cX?&#?l5pxy42Q3tXTJybw3#Wd zRp?~BCnpmvM5`h#WuWip)!|yc)yFjc{dVgRKW|S6q^#>7#jqX6gxA z>5IazLVr`6L;0LmZAFQC(>=l+Pkx-szn_6xJI@>9!ohFK)*1bV@b#hoD4sWe&?54|`>+82&kB={&-{x+( a3TPx&08mU+MMrQ<5NGuhaQBO^(7R*{!f64oRRF1xfW)1U zv|kg+{%|NYPar%?g#v;hA8{@aBC_{adJO98dQ`Sia4=A;19 z+WqC90QT5Au)g>G{r$zy{Qtr=|H(GukOTSo`TNWO_QU|*iUa<>FY&nmpFjZr#WfCK z_|tg+o2>Bv(KW!z`^(h)|IRe*t^nHL{_WL5;g|rZw(-`B0GL(-=9L8hv=!@{2#h`e z|GFcev-RAP0K3Qer&|H1VganW_n)rk&T{~?RRH|fH1F^4TV-;ivhDSz4g0JQ>Zkyn ztKipw0*a*9^Yio3fdQvi0k>cPr9=Se=;`pG3ZSaC!C?U4=KiN%0q5-grndHpspyQR z-phFdu1o-wrsWV)`jx5cmY9>9s@IdR@t~ujj-$Myl~KlX1gNa3o1U9{e0gneZ_m)s zkxT(fgt?(%1Hq?Y@~hh9K^tN zy1Ik1wUMi_ozSjS(WpWBu@|mV0BR-x?7BVO-QBaawR4ZailzFpia_46MtqN&etBj0 z&N2PnJK4!Y&%Z@>D*%9*xxlkZewfR3nD$R}`=gn2?xz-#jcs{}i)54ACSUkvhWf3U zWz*R4i=CrLgxa*JNxZ*(=l}o!Lv&J3Qvm$r6*m4O3Ir34{#X5Mh%Ec5J0bo4RQ_JW z{qmqp&yl}1rse+d()YJ-TJ`>nZPJ>u%jew3!QYyZ!@Xp)=jpWLZ5|#D000W7Nkl zR>PsLdW=aOSXym{p$bvGy z9K3$z%Gzaf?-%l4 zkf6ikQOBdOczSyJgZ%vb4;Id`(9r$>;_2rO5H8@bj^l^XF&;U0;2cVPnxAhzYncqU zgXiff;2h#8{2e%Y9Dm@zD>Omm43>dXf6C8ayK;ue!ra{aCy1Rv4@AP5goL9BM|C8i zzk~!VcIGr>A)wO-(?0`N+oA30X@V1z0|Nt-C(b7%B%mk$4_?k(oJ8%Xbv!jU|I74} zEOK&ko}R$DIA9x#u)TlzydIa&Uu?nJV_POqXn}6}>uqAV9a<(YV%)clRaVNS@_J=# z%Qu(xxUfD}A(6@@3Q&E8=UyDh$(dHtI@_FVCHHCSm0$l&$FMRps{jJY z1r3D~FyXYc*lwD-Hm%&WdiC(v80!`N4aq_pjY6UE`U(|Kbe`{&k}L>7yO7tXk;fAG zFNasJUN<$f^-rD*e}{OY>~G-FD9#QJ4$febE2WtP5@lhskm7)#2@9aumsp3F!%x=h z=4P^4QCTUG%cW9@QjR=WI+&6Rl~?~mP+8f)(*`KQfEWLt2lr{1XEi#F|2ukW7X-2$|RadVdR(l1A+F#`5 z<&{+S37z$aEwubz%S2^?p2&g5D;&woYtGASmkm|_6+cT%R@@jGYH!cWyCsuMOQ!Io zvLCd3Z=FTcAB3kF$-4!Ew+{{7_>)d_W2mjI>()#Wtw22%g7E`9Wtl>XezjR6w}7s; zHhoc1QCnBnojdK*%BKkXWg%0Hs{8axq6jsXcK{F--S{&hT3lOH)Y;K=r?<| z)~6obtA{L8Zzm|c{_5V|J55a;okcZ-Xx>M)HKiS8O-;SM)rGq9VPE7w-_sX`lxS!= z6D_&Et)jOaiApofi0wC8l~`(1_DEG;(N$kSl;lj|Wy0~q)#|Adr$L7_e=5mL@0)GGRt{N|#!X9Oh)SzGTlaf; zAyH6A9pM2Ob-Asm4MO|(xB8TE8K{Fu#Mxn_|Gl>OeFirb;HEJ$kO`^0f{N;N9`a3A zb_J#ZkEc(mNQCE$(#)oP)tbIbPUZOfb1tQ7P5TLvBMzC&3a!93m?tgu5{Co%J)am& z|L$Mfb4frVk^DKST!z@k)6)~FidZ)twcNx+NP~Mg{*W)=aNjkZE_#d0AyJu3I*DV< z71`jXX(C4?LK;ucvNZ4r=u{?^?w_=D#vRf-?~Cb7H#avbiIbYfRr!Dl7o8*?j@hB* zn8&BeSOgw6B)hQ_lir$fTeIK~8Em)s;CNRiiIc=gjKoYJI;rI*5`o4i(niGP2&iuH z@$s%~@o#=R^OwWY47O{qlT)xOQ;?C?^C%Lj^hGB@gn3j+B4elr%VmpaE)jeHjE}fF z`TF_>L%pdCL3kvnYFIZv)q+HziHxK&xMDhZe0`l<*%^PFb+2u-3Pihi?*`M63{esv zne;`UW{0YvDZD#_VN7Diqg1DOcE&riZbnUiheZ4KL717yB}asZha=G!S}+kbrf|t( zHq;K8zVYleMze2^e-EO4yLRnEB^iqZeCSll3e|~nvva$liBBgd37EmYSY|wX)q>eK z+Ga;wQFs@sSWGrf;q$}GvO~Z43+S>-A~d^J1)8`NK~ECe6fAMK(=Us5 z?%W9_2QxDqjl&{RQsTNhYC{pZHQ-4}Nr@0UzQ@L9h7z6Jw#}Z}!Yxp-Hxj`}Zi$Xb zaPf_Rs#Im2ogHN=xH_l6G1Zuyf%eQBAJKK&>|Hb62D`5nxx#7-sMIjrg{A~=!otF+ zq$Ec%z68K7-}sMbe~uRHh$lqeXtlX%91@*QMKS_-Plqczw$?h4&D*m?Mjz`c+V|f^ ztXM@t7z%EoiP<6no1hUPC?dAEHhVvC#T|BA$Q4^1h^5umLf8+m_XGUNdoQlbL3Wp$ zdKk!?%oGDcWt?MkwXIbHjkbjzI~Q?s7efC}+!2x=&5w0;^YH1WIi z4x9V-mhIjV;^&i15CB7>q8*dEfL^}ga#`Lu+kp@q`x9xH$}w}&ANgjmEmTwAHD7>c=%;dRKI+MRrnSzvXMapU4zn3L%j$Zg;s>E6 z$3)Gh2bgKThTBgIC}oV^A3#OvPdApIgxS9 qLR2Yvwal@NL|^ZI|62C~hxZG%c*DNI=;Mz70000BFQehEN>)4mLgeZ z5GH$Md6T7)>}H~|JwJW_i|>8T{kYC`u5<3+?sKjff`t*9^C%|-L1+_WebQew{=Y>c z{?hfdUcg^ran~`|fuQOasC^gKzaDm%WTXpK_K7Y*5CS5YSsNJnneC-O3!(6CPpCKO zXxDv-wp)U~OZj_4l-q;l$v()H=SRq1>=|%qAVhHFA!aU$Cyo_98zcPr4$o3J%Rz-u zn>(W4AG!1xPR|qEOyg^JN3>jrcYDD)J>XyO!q+2V)1jz8@lZShmI^_;*(|@a(0|i@ zKh~`T-C%9*@V|_QpaL{o0tEH@u~6LLgMKWLFlf*Zw*3N; z0YU58#~P4qZ8u?L@gw^c+=taXU_u!Ts(?`y(54RRgtrQ~K%*q+JiGlb3N(m=UJWp< z@H35V;t>q&)icXcV4n)8vS6PKcC)}2RWPpz`ZU09A!w2ZT_?e?0@(3f%Vq}$qw9Gb zVD~ln6Ao5z!FUMleH{G<2L1$r{!=S2*}>rqpcBE&X<8C1V5Wc}^_iy#z*2``ETBbdE*8EK2Z7cT zpb++x6)^^b9V`aM6X3%E(11UTj({)4BMviRVB^8Qrc(4JI28fk`d!(n7PN725?0I zya6~EqmUJBUk1xYBSiv-vloBY$N<{)wPKkh7ZeyW1D3jn4yIs;8~9zOCyC4i!@lB# z=h<2JE93x$byG@oT1B=hQtVf?%-XamnDwcKLG)>@t7ust(HThbSK73)4a(=O0dZFSdaJHOnP~2=+Umm}@{Mo2M zi)F`HyUh{tpBtv{9chkwZ7^22NE+HC%hD`)MmoHx57>tGaToqR#=t$2g%xxN{z&s4 zg|VQnJ@-FUBf2V^Tzs>i9WzjpQJy%})cWhrpS!c`l+~PC=Jw3H{;q0TyKzlHTXo{b zi9#uGPDfMYa17Eu!93ij233u@p%~7I2uHr3|D^2ePHWm}j=+m` z^-(h(-O&wP|B=4lv_tz5mN@}rC%ixvq1Imx*wkh2zH1r1qH?STzq35Pn+b@_iKC|l z-`IP9{*l{0dj~yMIgs;e6Q>wUi(`71O<8^YnqyaWHSBWpgadjavkv99ynn>Vn-;5K zQUZP89Sq!x7<;96^@PP4!^rgvS7a(i+?QC-JCF?2ECTj++K(`IfK(fU+m z_?h6_+i_L#bIOAuT`#@gz)P%Z#-^vICnud^d^7PMn_cn_uA1m#uZ4usa5*fmN*1qv zW?`G6aj>q^8Q71PhSWaOjF=qt`13ZZlG`ls;PZn#@QVreX0$A{8h`D}MQu!I71d3QjxyIHx7UOaothFD0NY>K^Qy?&zm8A zRei5vAY1uevV~16Ec^;)HhHXyl~2^f8L_G@jX|>Vm;4#0hrUzOK<8JViP4wC2K{4l z_4kjSqN@9=Q)O~50;AAR(*;Fk6Kf4(z6O+>i9UKAZ7h94!gBZ9d2!3#2Z7y6shEiL z^r|XlEmKKhXPKLpz82o%)NkKf@%#&(4sYVFY@3E(i@amJNliz(zJATd#@6}XHQ-72 z=>{QA&Wcja2bI63hDYu18|F~P9?WRZbdR%V5vE>S*xKaa?1)62Mfa*))ejN@stvwA zT+*e{SGI%lL=r>zjyJr|p|thcPmUzHRrb-M5!hqb#szzC1VUFG__Ms%e9_x93_lq_QwC{HWYs{?<4lB-Oe%tr|K?mRHig5 z;lDPWtQVg@Ra)Luz53X6duKs7;#AJ&%c3X%z@o=TE(;EKxgc9neYcHOE=fM4+0H*=mIO_}Lq zx4pcAHc%^;_X2)jS81(QxeIxya)ca7K#WPAJExY^X6$E>Vy@$9;_q+bnUgFTW8Og$ zHq*vkUx0}ww>s+^%ARl%KJKAZEghhpkrpu0_L);BF^=WbICeo&&W>YTy*p6tzNfqh zO}jxJhD#(Q5E+ASJQZS+lVo8!x624TNsyOhzW)gk5sIcveJ9QB`$D@Y2J!O{#Mrr zCNm6cpFkuf5d~fJq(n>FW@mSGYGc`!m(BOvTREc7&1+?|KJ_tQq|>|h`?dTk21u@v zE}v7+*h}#8bFmHiI3GdG9>>^X%(!iIdG)}e5F^U;jw;$F z(a%hi%5Kh`x&C&;aN*-hvyIi=@*SF2<&)xQ--Q0I*x{$!$B4H}r9Jwva^Bvu!{g%_ zdZZU3H)^Kl&MHQ9d<>W;+G;a%3>~}fdtez7PB5{yzhufWXBI&&OYL266ArE& zS08CyrV)(LMf1#o)oU@bEe@upTFYuK?+4}NWwict{903ADW;rS?G$dlG)9k_z=>yge^U3zzE4-` z55+8lH1!LV6KrRVOq1mrJ$sFB`E+NUcJI6V9y7(8et6(w5KD-{>$ zlo6RES=$m5SY7DecP}7pVQBwUBtXVevxX8 zjVL`^0o8Q+P$+?rE^%QgeN3S$MPp1Xn&xu>8H2*s8?Sg?QNYc2s6XcVLM`oADk(Y0 zH+FQi49cD+r9K;s91u+_C@YoI4~wjGwp#9DRlB;hS@}>;N~$n_>pi1ZT^A;+T={UG z62KA}o+%|`jkRVK81f_OC8nh2Sr(HDuRR_?7&=;7YTX&_Cw-vW4m0(hawj=w7jSU) zz~i1~jOSiwP0{H-SxHBx2vWv!9Ihz|`qJ7w1Xkk2@3#$QnFXY};WbS5Nq=IN@fx)O*l z;i$-oDIbHAH1W0i`rvTa72VL$J+A|j^YoT7r?h7XL+4*^V;qK6z*&=qRNdL|Gy1_Y z&J+cV!eWubug5~M*e^>cV(`;;fp#RBEQX~}zTJ%4f5(gKbiqWlLq58R?5Z`@&R3dj zn(Wn6zc0=~W zag7oM*)|#e^3K-kVL_I3Z&4z>O|U93Y9uL7b2%_U5MABJ_~xBC7Fcw)Z`w=8GNT#W z8@cxMO16$-r%;3a9h;;Y=@V)2kE+E4Zc067NF(+A2G`Kb5N)phOGInah6-DoPx&08mU+MMrQ<&3YHbXaxX`)68rE$!P%0d>7`R9Ljzx z%X}WmX#mA*2F89R$8HD&p5@DG0mp0z&29w6Zx6#~0>W$x0Bf+&Zv*Cx80d}^1BJ-g zdI0>d6id9|`KAy8fWrWExy)|{%Wehoni8>Q1jK0s_mTtquN38xA(Ywt0C&6re#69R z1o4Ie=6wO>ixBgh5d?a@{GkOYgQgCa*;T&o@P`89eg^E92I6`G-E{&1ce(hf7WbtW z^pFJji~#_2xSeD%@1F|(vl9KU5BseS^rZ~{yea?8Gyk?3|KlwG$~XVRHUGyo=92{l zr0wgP2=}NB|G6LkzcK&2BmcxP*Lnf}&@unhGymW$|M`p2asdC&H2>>7|Mpn_{nG#4 zF8}y}|LHaV??c;z0p*Va`Kt^6-75e0c9c~C|NFV%hywrSGU=BF^P&gTb^!muCI9-T z|JgDB{LBCHP5;(0|M`^RjRXJu#sB`<|MzVF_G5@l0NH*3|NFDvg#nvf0{_V}|NY?q z`k?lw2GsfgCcFO;sPPl6`2YEv|H&p8wEq6%KL7l`|J^v_eE@Vh0RPb^Ycc@;?pOc& zt>FCs?TY}8Q33px0RPx2_1-`K#0ev^_S*da|Isw@odf^VIH`CK_PHc_J^=phV*l@J z|DyrC`2YX%kuAml%KrcIupom*0XEM51grGtsv&>W{=}L&|Km&l>`VXMSM8AjobLbr z?s%>9|LoH~Z8QL@<^TWw>i@e4|IiNq)II;xOK8*n`q3r-tOVDeA*XBy0G8kX-(>%@ z1N*-v%d0fY^8fFe0{-uW{^oOjLI6|8{hw(G+LIUm+Z5fZC_KLO|J+6T=UAKK|J=Se zyK@Y(c?Wc^pXsM90SGAgcMx0t<7%fu#7qyhQFr(H z{r%v-Q;MFX_>ti4K>iwSm)`HDu|e?j!?Vba^2*|<)xyj3kb>}TT!sJu3MxrNK~z}7 ztk(xrRCg8zaH$WZ+VKEJJ??5uag(@v(zZ-t=tCVqN7aaAxN5et!4=$_%Sky_qO1d*$s7Z$|#z z-o0-`+OW5G*X}m~y`_~g^U>Q9qbtiRO6}Y!r6{kg@T&@av@1VKi>{=gxJhIC=bvf+ z7NY&x=i4_h`JHwPDL>R8&T@ z>Tczo+qKz%v|PV_U0>hRQ(qq*v;fA|-o8osH44dG&WOtI&D-++2UjkgY`JbzTUvI| zBk<6nz{K=`hBW=_EhjHs`C!i`gs&dmq))O^9}wuib*U>XgPW9%x^T5Us*_XC@LSInOK<@pf#lCb3Q12-KM1)>N-w?aH><`sqk~cn zRQlmyI#_^FSul=6;^I(xS8BOK{8@%O)CHarWKp5z2M85mzfW@dUXbGsgY zUltI6yB?BaqY~XRF*c{EyIm&oq(-eNK@6 z{)UEufvaXP+>#Sh;ZuNaHGf6s)~#lQUNrPOIqj2(6B#!rw+6Qcga+EKoyq>g;&VXp z!!B-g%`Mv5wQGp0D)V%p!Ock=H~b>gP>LD23h}*?z4*uxe*q|dsOGO^YHBX$0W^8P zG{{XdL2f~i(jat7O2DaGR!LF%v1&|w`OsxDLqpM3T(0Wm{gTq4#W@yq>{tnzv8#2E zHqM#scO_Rzed2LURcv(mc}#h9d^|ugllR9;jxCAA zU{UPt?Gqq3lag8s3JeS^Ijro=jiT#B{^Ml9!$(@tc`+bxxug^Q3HJ691R|u8 zkOV0xIAy0BVad_V&iq7l+@#*i?DtIY^aRGw z@36HMIKCE|-kIV>Qc2FN_v*OtTnmm^9t2Kc(!UmDLO&m>1jN7Au6al+Tv zOw+qQS)GQIk~8}la~&5RJsBlWr1M&nKlO}Hw>x@577Q{rHa6hoARjA(|6llZS?i=4cimnvoWC9xVpOL&<++Np>5Pv zLTpQ}KOJdWQBi%P;{utU8&gwv+jCqgNfZ(x8L?ww#&iK_4RzRvH3+daD}buLfvK*Z znkFGv>>%nwIyour?d>UINRJtLx;~jc{%{&)_C>Pw%!)7-)gu#~!=1OEbxe_+!~vy! zdT##qZP+$fbb^Lh5)d@vlaNJscX!3Z@ZxVVslwpSj=QenIJ&ma-Ods=rDBT19~OZF zOT>!o%cLQK*cQU?^JX*6EPT7?I)zQemBEn8L1C(}b1KJ?j_dU8;#A=vwXL{G7(UnS z%Q0iJBm4LvqBYvV6V!XVF!d}rBUw$w!CCH9vVx0KA54p&yM?Ken+BUIM=Z#-?&I@B zM@`8`0ISW?v#4-S9SqJ2A1;IphojWg0Vf~EaY`rzN4zb#vMIP4mIw}-fVY*tNvha} z@!_yB&59ljKDgI2+n9@K9PhdJV0hM#PGcc#8gC@GHO}_j8~#UD1x|L_ILt?MX0MgQ zMS|Hlv*V4e1$I`tR#sNlen|-lxw%P)>GR~LQ(e-DS7Y7(SJA^DP&CNMxScqXP;B6G&Yn5!B`6k|`Y&>uP8AZ^P zoz*Fc*kN?hF#?DKXEh6tnX~Oy@f*@wIiA3n5$VE$laga@NK%xvBq9bKs*sm}w|f1; zyU02pQ6)1DNQRb1Mg|7Dx{EOKseyqJIELmN9E|PaZNd-pkzV+0Lnz6HKqVa)mPj%* zM9P5HXaf}^+(tPp7aayHwZvrbPOIkQe8glyqA41qV?;Az$CQDE)Fj^g3E~}FUYIcs zhmr*?krath4-6@WcG#vmaL7Vz*DU(1C54r|7&;a=~=0!#3hLVhh$niSj>?5~! z(Wen&hb(VFlAt)%&pN}yCq{}S8QOutc(&V?eE3t8wuSXJp(H3pQRdYXm8svt4M-S1 zf=`iwI<$j>sV)0ptG?QYmRwjO%3{R5Nmv=2g?EkOi3*B=I)aStvQPE?Q#)N!F5p6$kEeNuSMN+H!zp~r?1skpeXnMEB8Q*W%p7r^>Z&ddJN z!cHnEg&l!XCJa~$Soej%Gn@+QprfX;l0#M^q}Iv$gkUM87z}T39Z{eQ!-Qf&d}P9G3N6rMs}Tw z@+7(ZXEq@!OP6I=53o5-l{wF T@mRcn00000NkvXXu0mjfB!>uD literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-cowboy-hat.png b/src/modules/cs/static/emoji/face-with-cowboy-hat.png new file mode 100644 index 0000000000000000000000000000000000000000..5801afc7807f5e9b3eec3cf305e43426cae3c663 GIT binary patch literal 3683 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 B=M?|| literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-finger-covering-closed-lips.png b/src/modules/cs/static/emoji/face-with-finger-covering-closed-lips.png new file mode 100644 index 0000000000000000000000000000000000000000..3e37c47b1a547d5b1942199161ad28278fa6bff3 GIT binary patch literal 3797 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 LNkvXXu0mjfJjzFj literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-head-bandage.png b/src/modules/cs/static/emoji/face-with-head-bandage.png new file mode 100644 index 0000000000000000000000000000000000000000..00471c046c47524d8cc9df502bea2226716bb857 GIT binary patch literal 3586 zcmcguhdbMg`%MrewbiIn6??Qw)u?KXShdG3y^7*eMUB?F7d0v=YD;5Ot)RA0yG9kU zXWO7^gp}A4s}=J3`u!8X^E~f+&ieg4?G3;c`^(KbM-!D z>hoqk*IAjF7z`#qKkr;5$0KudbBFv`*HGZ0K%U~_;?C*}a+b_5w9LDA@8&~6g@py# z+1V#JfpK4OzZc_jI73D8`?u%7VD?g=C%KT5Qm(A*?7k=9*$8gTTXffJ(=`-Z{&T}c zv^cGjYd@F&sEBXutyN*X?;)D`u!whMWo2w^Y<_;8NF)B6fM%iL zkr7}ueY|g0zVXi4mn^)hgQP|Gze^NZ2<$ffIijZQW(&qOvW%zy#Ot} zVf-Ef0@}o=(0bV3^9w%Ym?BA(ct79lNTn_wu2{sz#(aDq(;vmP@V&DlIdHl^qJ87!!E@7`Q-da~lvHsv;@G0bv09;!ZC`b0ZSgDbqHcMayN@A0uvLrqCUB=>Hhb z(#I*ZgVE(>owj-^*>iQE|DfPtm4ci216mUY%Z@Ugh}BYTt1ddHRft8n+GH62D+Sy3lSI3XUU{vd8wot z-pF^~>gUSs%>``m;@w>uJA>Rt$MMfDLss&i_rQMmZYEP;AYIL6dA~KH~RedaIsOll78}5bOCd$ko z`Mct?6isNNj=(C-uj`C5W%lWFuCRr)^gV=Gz6zy81|OCcupJr8_1Kq^yS;@Yt&>=6 zVU`!1)e9CzBDWYz+kul~nR`ypiINf$>Y6tEr3K$fN{TaMEo$B6+g)__p%69hXg2g` z?Rq}6-1XcW9^XtlTcG%pjmg7ZOJ6C8z0f;qYHC+F-xl?oAkF)RjIlC>rN@4|_4uUBB_9FuI{LPk^jw!n9_916tn|c~Ms%}B(i<%( zHwPx_`K#byjl6Q%p*16BztKS_KFkIw`<1ZTwbwmFu8T3K`_=yiOTUu+TA5&DUC5;l zJ$NiU)~`MQFLhX9rol!6s3wEgbEyZ>LNrVb53I1eLAbXHIdKsa8mii5n<{lLD9`7K zz_M7=`xFKn+pgOLvp$Q zrR1}_(HgdP<&jpvKL6dE7T(-woa?U`q+aI25xb*ILxn%BF#qN42FGSOh=+t7()?!l z9SUvbjRmu<*I`eSTZ%>g-80A-v8VsXPG^sxm&(6k#Ke3~k=qR-al)D{T4j#dVTjuq z4j9_5si{6=tjH1iYb^aAL6UeP*fo9&D&-3I6CQ+@k__K?z9*!j)o8Wu=IdxSN_ z)=bavNtn3$uqzWShps!0$N9+PL*xT0*6Z#*tXrR=W2=X!y-U0cYR#)_H2jx7|Driy z^!pQzZ*>@qmjX3B^X{Z_sbfYC*JSi{(Y!+oX7eDGGFzZCbkXghhYzd5Q@KOe&`&`Hi2+&hqk)vj);rM32xWRD^_{~qeNKD*9txl z={kA |#)h-P?EjomlUNNXsHX-`OGRg5Z=?5;Cteyw^?N8{}3zH)LM?e%2;)?qYb z#bsg*k(jel6w{lKFdqhCo%&#&R-c91^UN)wSrE#ICk=jdQ~8c-x8(jZ>qqYG{n*$z z=3)`!%6FUZzKhhndre)x733JvaX$!)2|j`e z+tthk;8R;B`PpA@`9%caK71(gb(n2x!z_&EPX%a|)F{pos(e2PGwH(zV((1jyxF+z zwioL5;~TZu*+I8d4yItmHjUL)RZc;zO}F36G=%vvp-M;Rrw=G!lN#~-j zJoWj((W3e{Rz32+_tp-&wfN%KuOglCnr)BF<%z@^!<@~+UzCN7z`*sJ!3J>5-pmkc7y=AIXvBq=ZnjaK#;@?oYd*3ac7bj}KEIR&GlQn7{@p13W{CL{A z3ZIE~zPJm=!WC-^3JS_($ga*Ni+$9Bt2xjqrl5Q;jhC&TSm}(y8;KKK?Qq%1yi1f* zb%>73%^&Hjs92AGNNLvphIogx8epODA|2?4?=#8VcD6^XQW=n3C25Nz#C*lpa!<&# zKCG8}Z#UbBDkFFQtLK!;593#!Qweuq&-baygSxn)(82H~j>h8rx#j8VL7Q$Kz2&x}Nn4Y3zq>T7Mk5onfh1ZBwIGBkEpX zp~5L7T%f@8OE>Z#@E={h6OFmQ2Qr6FJH$;Mt1Ia9UVLgLmi5y!D&6IVj07iYaAcJH zBvKD4@zM=*kIv+VqW*nCSc$PyJ5Q20D3`IkEU9~WyIH)HpljT&GAK$wm?){2A;?$ImZu^r{9Dp6 zjqZ9-=fD@A85;KKKEku*{_cQLzl@@indENk{_t%5397Aawfqu*dIK;=Aw;Z=VkXC!5)8m>Z)$J zjAB8mzBC*zUR&4U?!c27$ncwo7>>8uO_?RYxbxBBEeLtVI>Cn2xKystt4CBG)}y1q zytlN0x(rF~9EbJ9Q=QBbte-5}lE+vd3c|vpvW1C7SJ1=qbs37vsxEgAdDY+a)hkOE zOGMhjWPB#U5EPYilxD}woBRcj?h}G0xz}Z(`0W!+Vyxp5NXy#n%itS#%gk|!{)sad znm??ya}$dSrZ>Jn68-&AD1x|strihfOqp@PO zi3KwcR9BMtbkh*&oWl3-Ue!g`AsfZ?cJ+hGoHfPb%Rl&e{`1tur^=Ew;3CXzrMcQ{ zWM(AO%?S2T!3LFGm^2waOyM%|zMS#&#Qxuh25)rxOlR35A|jYyJ<|?f`Ag8t?xMjx q?UXzkO?8#r5qD#79D7RGu`oPVUKta7op|0=LB{&#h#K9;G5-TW1!VI8 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-look-of-triumph.png b/src/modules/cs/static/emoji/face-with-look-of-triumph.png new file mode 100644 index 0000000000000000000000000000000000000000..fa3bb8e3d5325e354b332f6c6df3a6b6bf6ba174 GIT binary patch literal 3809 zcmV<74j%D|P)Px&08mU+MMrQN5>3Fej#?Trlks}K046tYtS%+S=ZQv>y+7{G%@ zvzL3RsJ4Hh&;9=X|NsB`{r>;eEdI6_|K2SB#x?)ZDgCn%b2tF|tPKCyDfIgP;D`hN zyCVO}F!1*O{I3rG+bs8~3Gtu_({up-xFG+^Hvh>g|M+`kw#qYmZR^|DXZ?*+Bo@Dc$V;=#&KGj|JCz0srq`|Nh?p`>6lV zGXMS9|L983VZPxz>+6~y_~JqF+duQ^oa(?m(B19DrX|m{ zT>SE)(y}bvn;Grhis;K>ubhwl>WA{qGM&Qnw~#}odo=&y9?`jrxwf&gz|PdNcA|9@ z=dK_A%0QNAA?MFHzn^AdCII5>_2$rc(ZHVn+Fb48ZuPJqj~(Q6WOC*=C~;D@9pdB;GlCR-N;Njlm)Vpvz z1OLz&b3`4RePEG&bw=YXi~s-tKy*@0Qvm!FQ9v>N0S6(~IH=x-5&rOGbN*7@oA@5I zlls18pX`SF!pz#aZQb_#l)&xN-jB4W;q#C1(bd?wwS#x7wMe+i;{X5)Gf6~2R9M5T z)@e{v=Nboa2cZcLazSmK@dIu%{h+PAez1P%y)!Wc2;n4z3IPHbF#=WsAuItQWwGoA zv7oX95fH+@nu~zwm3{`#BfY8&nU=J01Yhriixq^(Q+D~i$1!(THQ$z^2~Z!6xG zl_e)JzdpRv=ucWy?L&uINy%juj~?B-chAugem#0r0T}DE{o2$&!R*|{N&@9x;DxM6 zndhlfp0Y@%s7vR-O7h#a^AA!K-9x)dfw^}nOLpSczn63CqGw^zIg--(1Cys3ZHh@s zt~eK!aN@X%lzfJaw*{ky*M|%@EZ}U4ETG5C#7S1tXPNA_kbad44 zLE5DK5l7h7BYo1lFxd(eiIG8n$r@huj7nAaTQfc=VJEgQ;r?$*WrV8tRjViDlsf2j zL(9uwmE#d_`Vw06|F=ZZ-HV;p$b^Q$QFHSM)k23%=D8f1tfNN~VJ_+IYfXr3C8hVy zN$X%vX;NrcVPSYUQ1_om%*}f{5@ZQ79C$G~3e4yrFyY~ag@w7vr8x)RbM7d+x0NQ@ z)xZvrfa>V2mPEYlh)hr?5*&%NrvVh~bag3`N^=gq`+3sd72{V{+?AD;<%AR2&?A+Y z_jE<7)AiC^65SFRP9Dw5>guYo^NZQFaeX~nd!e!1nwpv$K)Jg+xjQ)(E=VP+mT)po z3&;Tm4!OI-o*Oka`Ow_n_04VF7UO4GTnrGz-rgQ|J2@>>oA;^iDQnNzrkqm7gZ$#+;wT7`5SG;|c{1&e)2Wj5xRcBFH_)Ca*!#exH0LXw zcM7t7ke^>vR0Mn6qTEiS*iS!^PLuz+Q#CqmkJj9<5>-@`pP&EWosx79$ANNN2`n7H zfCHN{GBR>=b4~qn_H14CsMrCWnJTb^s2@51G&#ui)av5#7l#vk|3(iPhOwN}pm)ut9jALpW8XAjI2m8KT z$xWPY3OQKZ~o3ZUJZJCPa!$-~Ud*x1COey+K>xvf6X!Ff53&JKZfb8WCZ=HP5$W@hH$anc1K z715p+xxD00#$2B?U=!{n_j7bL|9`h(bdQ|njF#2FAjlXw0uQ?t=(-xBY`^Xk?8Rd8yj{fT#0e0zEPcDG9MSDUE{#T*`!jHMXz8czMlM)wzdjlv4K}bT> z)GJgL4!>j4jE@+;AQ7M-1o4J~XPKCoh@{Se#@c7Y!|m!v(yEsR zuZL>|8pqccCWJbJ5pC8yNT@qtNT@dkH0SHi({9dv+ zT#Fo2aL9tJqmoc_0GZadmsdx;F=%>&ZcRfFbZ`1SY~Z(u>hktl zQ_?{b@(MohYNNmWK+-luy?L?VL&@=ml7`DA@CB(qY-yowtiHYuQeQvT)-n-xR}!I= zlxM;gaG;>0sG#K$!Gr&c<&t>b-g)iO%82TryK>R%Y;^k#g&QZtv~h{sbbqKiLK)qj z=MA4lTu_{=&E{1PHvKcWBrNe3B}!>!<75*dAIt>FHW7Z{?wp-DB@!8QHdacNl0_bJ z(1gy%pV43SsMXm_mc#<7U81UNRE#W%h^BcAsgs>KI6++QA5k<`swC~mfl~$(GF<%y zkh&d}6zqkh@}Wjs-;gOeO|+D`3WAE}n+Wc{L0@0n#-Va13zamq%p0RO-FyylecKm8)a9BGlYZzr1+cI5fvlmcszAPn>?y@37nmkBPHjzWkge(qZ|+(Mze z(;6)ObKh-lDxIE+x6(v|DLw(#>FHKhX;xOO^z;Cq$3MfH5Of+&Dk1Ox2lc(shEMlh z7SU<25#Es?TCklQ^BKDKok=K# zD1DHS@WSu@@7=q=d#8*_8P63(X@;eSc4MCvrV6x}m$YR}(dD#yKEA$yDbDw2&TA0( z*C`)2w#axOaG9`Jb zyz4mOo_%wgF)3UbE!Eajit@ne&!(1Enq^IA{YNEPq?F4<@}YTqyb_K^JQYIFoacpO zW4+z$b~+DWoldvc)|F(A5IB+Rn|B5+n1nv!l)FWq2Sgn|Rk^x;eNZ^ToV2oHn15CJ@TLVkzwE#HjLk<%M6wn^g=!wsjm)w-iwZ}$BF Xucez-Fvj-$00000NkvXXu0mjf#!s=4 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-medical-mask.png b/src/modules/cs/static/emoji/face-with-medical-mask.png new file mode 100644 index 0000000000000000000000000000000000000000..8b237f5b51cc5b1f826766e7bd29468f1a987d59 GIT binary patch literal 3684 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-one-eyebrow-raised.png b/src/modules/cs/static/emoji/face-with-one-eyebrow-raised.png new file mode 100644 index 0000000000000000000000000000000000000000..c14f913df3a32a531b221a788075df65a8c30dd9 GIT binary patch literal 3483 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 RJHG$`002ovPDHLkV1jy~pG5!w literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-open-mouth.png b/src/modules/cs/static/emoji/face-with-open-mouth.png new file mode 100644 index 0000000000000000000000000000000000000000..6b9af1edfb0a617b49b2883a01b412297daadb3b GIT binary patch literal 3667 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-pleading-eyes.png b/src/modules/cs/static/emoji/face-with-pleading-eyes.png new file mode 100644 index 0000000000000000000000000000000000000000..39012990a2ae0fd407055a003fc90822a116a214 GIT binary patch literal 3498 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 Y0JlbC5vj`2HUIzs07*qoM6N<$g8E*?y#N3J literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-rolling-eyes.png b/src/modules/cs/static/emoji/face-with-rolling-eyes.png new file mode 100644 index 0000000000000000000000000000000000000000..3c1c93331f479b73ae3d015fd230ee7c000a1251 GIT binary patch literal 3461 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-stuck-out-tongue-and-winking-eye.png b/src/modules/cs/static/emoji/face-with-stuck-out-tongue-and-winking-eye.png new file mode 100644 index 0000000000000000000000000000000000000000..3c6c27629369c0c7a08b16cad9f09dcb8a1d9efe GIT binary patch literal 3561 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 z zB?CSt2W7h7B!^&RJv{|#ZEgMici7EWeHa)PY2 zEkFMZ==ycob(ya7}N(jn%e4c+FTG*T^mUu>DHLu!^T@}<8k{zaW`&I?ReWI zsysBuNNpYtf`EkCg=AR!@3h?b@JUz$XEchx&?zxP$x@y=}POo#sT4CH8OtIyA&NGyGWL@}C5w@wGp)kB~> zZ|^*8ubyq|%s@;;xH!>3pY=QrA*pDnuF&LzsgR72&g*CMz6Tx3%R7W^-r4J&5rFX# z^EH<-G@j2PBn_sTu0bMHD#C|={-G2BL3cPmafz-T^MxRaq@ilG1YC(bTl>Ai3XS>x zkavG;r&tV_m8vYldEtLE2#UopGSE!ye0nAss(gqDYMy-NX=kG5l9degm)My?LD5xp zmwo)~RDT><0A%vx`cFOkc$qG^d8wW0uHY(WeDr2pKdfo87~_)re|+;Jh8kr4Dt4xu zg1g;ofB!MR|G%4Y{P>LHGp;OpX(!3a0r3GIr3p=T! zWMD0vlE$hMK%i002ov JPDHLkV1kri#0mfa literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/face-with-thermometer.png b/src/modules/cs/static/emoji/face-with-thermometer.png new file mode 100644 index 0000000000000000000000000000000000000000..407c0c86298f222dda335ae47571760ed788d867 GIT binary patch literal 3560 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 OME{17Zn?HY)c*h$zg?vO literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/fearful-face.png b/src/modules/cs/static/emoji/fearful-face.png new file mode 100644 index 0000000000000000000000000000000000000000..f1927f0ffb0ba32a0bcb00fb7f2305b604a8a88b GIT binary patch literal 3366 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/flushed-face.png b/src/modules/cs/static/emoji/flushed-face.png new file mode 100644 index 0000000000000000000000000000000000000000..adad5ca268aaeda4a967192f2c764a161c0eaa7c GIT binary patch literal 3611 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/freezing-face.png b/src/modules/cs/static/emoji/freezing-face.png new file mode 100644 index 0000000000000000000000000000000000000000..97a93106a6969a1f345213a1150a54a7d5f25629 GIT binary patch literal 3615 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/frowning-face-with-open-mouth.png b/src/modules/cs/static/emoji/frowning-face-with-open-mouth.png new file mode 100644 index 0000000000000000000000000000000000000000..1ec8ac6f5064a382f5a439d86e22a5bb20d18b45 GIT binary patch literal 3666 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/grimacing-face.png b/src/modules/cs/static/emoji/grimacing-face.png new file mode 100644 index 0000000000000000000000000000000000000000..82ca911e9f63a2d18c8904bb16b44bab75f909e9 GIT binary patch literal 3695 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/grinning-face-with-smiling-eyes.png b/src/modules/cs/static/emoji/grinning-face-with-smiling-eyes.png new file mode 100644 index 0000000000000000000000000000000000000000..d90a62d4e9e8c343c85df443a511e74ffecd31ff GIT binary patch literal 3677 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/grinning-face-with-star-eyes.png b/src/modules/cs/static/emoji/grinning-face-with-star-eyes.png new file mode 100644 index 0000000000000000000000000000000000000000..9d3a0983168d1b61b2b401bf30252818017d205d GIT binary patch literal 3888 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/hugging-face.png b/src/modules/cs/static/emoji/hugging-face.png new file mode 100644 index 0000000000000000000000000000000000000000..edc9e01e49376d7f9f84ed3acad88b773a61bce7 GIT binary patch literal 4061 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/kissing-face-with-smiling-eyes.png b/src/modules/cs/static/emoji/kissing-face-with-smiling-eyes.png new file mode 100644 index 0000000000000000000000000000000000000000..f041364589496091ec783188c0c5f3d41f9f2fa6 GIT binary patch literal 3633 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 XcV4Z=Ih6l9)sTsSnf@m|o6!FORYkBe literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/money-mouth-face.png b/src/modules/cs/static/emoji/money-mouth-face.png new file mode 100644 index 0000000000000000000000000000000000000000..e72b3b88e4bec38b36a416c76b6260eec606a59c GIT binary patch literal 3680 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 Cg8mo) literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/nerd-face.png b/src/modules/cs/static/emoji/nerd-face.png new file mode 100644 index 0000000000000000000000000000000000000000..c9158633dd922344da30e1aa8a3ccb25a5f216d9 GIT binary patch literal 3673 zcmV-f4yN&mP)Px&08mU+MMrQ<`;-93ZV2Ok0LXqOPMe0LW+n?T7}h`1ITd>^oarTi2(el3-X;A$7li4 zas|Y456f-_=YImkX#>%72I__f%WDG2X#vA#0_ukf`kDjgeF5~B3-qKL?U)_FWdih# z1hQlS`l%82q7(6l0``;z_@NH?p$+w>3-Y52?VJb+2@L0z1=)WA{3u@L{wH4hID|I#V{`lSE38{&)u|M{5z`?BMZ1pn4C_^1v4 z&@}(MCI8wo|I;+hZ2Vqr-iQL#b^!aU51d^A|JyA8{^S4p zpa0Az`>qWC)++q15C6wC)_MT{_=x|>H>G6(|M`vo$twT-*8lv+|E>f6;yC~LlmFi` z7#SWSBPJRb5dXq5|Isi1-z;}M0sp-P^_~LJasbL%^tQ!CDWBA81|M+14@`nHM zlg_0c|KVx>=xNuwE&uRs_qQsoudY2lK4482*s3V+!!O{rEw89sI4u%DHyHozgzt|4 z|H2ag)ervbH*;SbigO-JJ{9-dGge6$R#i&o!!+iL0qT$e|HlUZ-4_4LHP@6E`_C~h zCKIxN7q^TTt(YnN{ru$Tu^utBzRdq8a9@DbkuH^Yrn2Y##m3MgQhX|Niau!6)IF7QvA! zsdo=-Q58)_Ex(Z!^X^=~q9@YT((lePoroml!zN}d0Fhh;%C0H@w+@DKFu#BofPY-) z;#pdcJK zz}8mnQ9GWVb{614SOUb*umlOXf<)O-ga8Q;M1-&efdC?_>;;q^MTb=psO*b?z*JF0 zL~s}PrM2zM{oYFmh{rB7XZ|O=oOkb+AOCyr_Z}}uN&RmmFZF*DiA0i@hr@rxkWrA` zq^9;4keb>iSp}ItMI$N6s(tgdD*4VyTzAN-Uw@+}tMo^EAtS5ycU53C78ahxRan?~ zGT@HtKh$Jp{t)I%RnLGkjfH20!$*U+y1FI?A01|&Eo?j!;HmoMrbWMZk_4vk>~OH2 z$KgHy!nNn{PP4>r|3Vxk`@0HMTDt*Z*uiE;4)2+(1G^H35o*Iy1=4TZ`6?zlppl)p z>j2VW5JI4LJm6tE+!zoY_P5_MC9{4*So9gk&}}ec>wm|~&dP!Cv@g%cWIxPB0=(k9E1Wjyhn}~r!@C8X$ z(LnlOpGfO*PLiqVUXTPfBM}3Vrlv_r1zV!Sq}P9FcCssDqEDtIB_(-znVQa_5h54> zG4=BDf@PuZ(J?D!KX8ry6&e&

`7Dx_|$EF9~h$w-N+mKz6@tVq!r-%1O_duN3BO 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 rP2t#b?e%cYPx<%oMA7^D+HBG7{M{ zBkLe5``8(W=cn&q@qJv^!gxcSNfTteF7s@kEXUv+u;hR-V#t zlDL}*h##(WP2TLi-VAebTstJT78h8b5B;BT`n9B!i-~*<&WQOC_(~+*!Ak_KfML7v z6s?SHmIzx8hgQO2eIBrHj_`T{UA+_hvnzcs@zh=(>p=;q63Fy@Yf4eaDbmuLxB+3iv)WapjHOZz60tdu%EJ3h?;(m7zu@S zxkKQn4g4h>zvBR%(%_&B99Do)ENGV6EoKCVwcsFcz#jrVn&nTTq zu%KNXbclj#UeF@?I|dGR@SvA%;@>f*ww;3jgA!oQ6)ZjiGuq&27%W`}%?!oPFhJ1< zGge^t7TClcra-IhIX^VbVZKFWr4Rcqisxg}DN5bBzw`LFfgE|BtPavprW4c7n8Iu?c5OrvbPDuU zNNtZ_0yQVWguudk>8)0+(R|TgpCmU2lzy75kp2~;!uN);DP*y~#ls;DqhmY`vX2a% zKmKZbZN6EUQJSC<>Qp15|upXw5;@--T_^PfTM3D!TdOskbARDigcKZ=fp=38?TL9+sGvl$02J5LV*XKqkKoM5Wuh3`HDXCf!PB z*-=whUmN+r@ZOZ}iswSQ61lOe;GVQW+rK>OU-`~0OM7rvk;z{^soA@0$o_Y2zFji3L6)>CSG_&~UafC+n^) zQ)NtRltROkzbX`6!*7d=ZAK-68JEbf+G86UW?B-clps#;9*V&6xawz*8_fcLCN3z| z2gu6^@Vh<7m?j^0mbBrzx_IR7Xq}jy-v3>vpTPbpp?gL@xbe@1rnlT3!h@n>qni}b z(dn=QbRaVPZD~SIG=DH(kB-eh>y9^oX>5lOua{9lU9r5Fbl>`y#+_Ka_g_=x6I6Z z*SfZvcaM)ZoAoE(I6U;z4+=e8BHP&MnFz@2Y;_cBSO&1mnAhl=T*NGpo#UDWP zl7U{G7vF~U{Js_|g}PcMCF^cO`DiKn?$nr}VQHX7RP^IERcdU{(=9ICy|41Y>bJc1 z812Pkh!;*ymvsgciBTcehFbM*6K^^T*jTD5g5jd`<{L~ob#=JT;l>x{iR{qZh7rT) zG6WR6VdOdG8E$^Sa-pHDnli~-9&xuUa_DV)Zr!>iU(;_jk%!HDr;Sk9^Tfp!&C2{o zP^3dHPMtBizL7I=Xxp#q*3OGd!@T9m&)7Q-OGh;hh93JgH3(`r|LliuU#{us<34M^ zotEm074Hx%6tw!q^Pe+sQN;CZ7x?d^%ddN}9Ge&~y_ z&VU~DIjR+2D3m16pXICrPgc{`7UnLYYp8gF5KlOhWPmxt>{XlgFnips`n;*P@Nh2) zFLHvDtBYwqJO1iDu#IVNloNOiKd;lKxv5uIJOIPqs-ZO4jM*!Oq<(3+s(S>xUOiDr31aSw+uEuxT*fc-?!G2h-E4 zWsH@RXu6sF@W|&!O1fe&YVBIOoI`}rV(#VRi*mDc-a33bW*lQ;0kL`0juGnm@j-D) ztcmJj+gs0nQt|%r9RW>y2~%n~1YWy0Q_G9sYUalplFup^!*rrxHFKlz5m^|`FD7S@ z+{$xG!iL6*RK}l(Bgj>Cee&87aZw7f55t_(L+TB9@<`dxTmtPcvR@6K&yR?o${iaW zGEOEJUkX3zh>1Z>BV(OQi3UG^&8m#NEVF-YCwWjDIyGJwd}#Cbb1;b)#60J>#4w}U zXI$Tu64UaH8b!5zb`4Ok`wI%rnb6F_%L@t$7JbDd8_8keMF|J!yz;YzY25I#F8rPM5F%8^585%?$6ro429mGyA}Xv zhM%m-f3wG<(e>K|dVD9XDgWg$uiu$i@ z?reO#>l6~{X$rH!nOtel{;UVD46|#pOj5t( zM(a#|_K) dhets$$i6{W8EJK!>)-PV;q;6zm+RPu{}1~OM2`Rf literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/overheated-face.png b/src/modules/cs/static/emoji/overheated-face.png new file mode 100644 index 0000000000000000000000000000000000000000..b8c9f63abc6adc642dd52fb2c0a54907dc33368d GIT binary patch literal 3440 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/persevering-face.png b/src/modules/cs/static/emoji/persevering-face.png new file mode 100644 index 0000000000000000000000000000000000000000..daa2cc031ea924d404ba9a3795d02ab3fda2d7e6 GIT binary patch literal 3628 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 yT7XHVwGdjDz#q#0000Z3n!t(*u&M!U8i5yO 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 A@&Et; literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/relieved-face.png b/src/modules/cs/static/emoji/relieved-face.png new file mode 100644 index 0000000000000000000000000000000000000000..502f517dacce540e92ffe0d8c380bc436a2fd833 GIT binary patch literal 3716 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

+ ); + }; + } + + // 不推荐用该方法,在 setup 中返回模板信息 + // render() { + // return
; + // } +}); diff --git a/src/modules/demo/views/crud/components/search/base.vue b/src/modules/demo/views/crud/components/search/base.vue new file mode 100644 index 0000000..ef9c311 --- /dev/null +++ b/src/modules/demo/views/crud/components/search/base.vue @@ -0,0 +1,147 @@ + + + diff --git a/src/modules/demo/views/crud/components/search/collapse.vue b/src/modules/demo/views/crud/components/search/collapse.vue new file mode 100644 index 0000000..afcb4ad --- /dev/null +++ b/src/modules/demo/views/crud/components/search/collapse.vue @@ -0,0 +1,110 @@ + + + +x diff --git a/src/modules/demo/views/crud/components/search/custom.vue b/src/modules/demo/views/crud/components/search/custom.vue new file mode 100644 index 0000000..51e8bf7 --- /dev/null +++ b/src/modules/demo/views/crud/components/search/custom.vue @@ -0,0 +1,176 @@ + + + diff --git a/src/modules/demo/views/crud/components/search/layout.vue b/src/modules/demo/views/crud/components/search/layout.vue new file mode 100644 index 0000000..ae4d3ee --- /dev/null +++ b/src/modules/demo/views/crud/components/search/layout.vue @@ -0,0 +1,149 @@ + + + diff --git a/src/modules/demo/views/crud/components/search/plugin.vue b/src/modules/demo/views/crud/components/search/plugin.vue new file mode 100644 index 0000000..93ba5a3 --- /dev/null +++ b/src/modules/demo/views/crud/components/search/plugin.vue @@ -0,0 +1,128 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/base.vue b/src/modules/demo/views/crud/components/table/base.vue new file mode 100644 index 0000000..053a3cd --- /dev/null +++ b/src/modules/demo/views/crud/components/table/base.vue @@ -0,0 +1,109 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/children.vue b/src/modules/demo/views/crud/components/table/children.vue new file mode 100644 index 0000000..fd4b71f --- /dev/null +++ b/src/modules/demo/views/crud/components/table/children.vue @@ -0,0 +1,95 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/column-custom.vue b/src/modules/demo/views/crud/components/table/column-custom.vue new file mode 100644 index 0000000..c362331 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/column-custom.vue @@ -0,0 +1,108 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/component/index.vue b/src/modules/demo/views/crud/components/table/component/index.vue new file mode 100644 index 0000000..005d153 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/component/index.vue @@ -0,0 +1,108 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/component/user-info.vue b/src/modules/demo/views/crud/components/table/component/user-info.vue new file mode 100644 index 0000000..f4fd232 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/component/user-info.vue @@ -0,0 +1,34 @@ + + + + + + diff --git a/src/modules/demo/views/crud/components/table/context-menu.vue b/src/modules/demo/views/crud/components/table/context-menu.vue new file mode 100644 index 0000000..43f77f4 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/context-menu.vue @@ -0,0 +1,191 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/dict.vue b/src/modules/demo/views/crud/components/table/dict.vue new file mode 100644 index 0000000..083297d --- /dev/null +++ b/src/modules/demo/views/crud/components/table/dict.vue @@ -0,0 +1,156 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/formatter.vue b/src/modules/demo/views/crud/components/table/formatter.vue new file mode 100644 index 0000000..3cd0172 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/formatter.vue @@ -0,0 +1,95 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/hidden.vue b/src/modules/demo/views/crud/components/table/hidden.vue new file mode 100644 index 0000000..c81ad16 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/hidden.vue @@ -0,0 +1,127 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/op.vue b/src/modules/demo/views/crud/components/table/op.vue new file mode 100644 index 0000000..d15cbe0 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/op.vue @@ -0,0 +1,182 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/plugin/base.vue b/src/modules/demo/views/crud/components/table/plugin/base.vue new file mode 100644 index 0000000..d8f2445 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/plugin/base.vue @@ -0,0 +1,130 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/plugin/row-edit.vue b/src/modules/demo/views/crud/components/table/plugin/row-edit.vue new file mode 100644 index 0000000..de8c2d0 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/plugin/row-edit.vue @@ -0,0 +1,124 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/plugin/to-tree.vue b/src/modules/demo/views/crud/components/table/plugin/to-tree.vue new file mode 100644 index 0000000..d2c58be --- /dev/null +++ b/src/modules/demo/views/crud/components/table/plugin/to-tree.vue @@ -0,0 +1,87 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/search.vue b/src/modules/demo/views/crud/components/table/search.vue new file mode 100644 index 0000000..88cb8ea --- /dev/null +++ b/src/modules/demo/views/crud/components/table/search.vue @@ -0,0 +1,137 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/selection.vue b/src/modules/demo/views/crud/components/table/selection.vue new file mode 100644 index 0000000..87549ac --- /dev/null +++ b/src/modules/demo/views/crud/components/table/selection.vue @@ -0,0 +1,109 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/slot.vue b/src/modules/demo/views/crud/components/table/slot.vue new file mode 100644 index 0000000..929ddb1 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/slot.vue @@ -0,0 +1,97 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/span-method.vue b/src/modules/demo/views/crud/components/table/span-method.vue new file mode 100644 index 0000000..d752ed9 --- /dev/null +++ b/src/modules/demo/views/crud/components/table/span-method.vue @@ -0,0 +1,115 @@ + + + diff --git a/src/modules/demo/views/crud/components/table/summary.vue b/src/modules/demo/views/crud/components/table/summary.vue new file mode 100644 index 0000000..05e37cf --- /dev/null +++ b/src/modules/demo/views/crud/components/table/summary.vue @@ -0,0 +1,95 @@ + + + diff --git a/src/modules/demo/views/crud/components/upsert/base.vue b/src/modules/demo/views/crud/components/upsert/base.vue new file mode 100644 index 0000000..96f76d0 --- /dev/null +++ b/src/modules/demo/views/crud/components/upsert/base.vue @@ -0,0 +1,133 @@ + + + diff --git a/src/modules/demo/views/crud/components/upsert/event.vue b/src/modules/demo/views/crud/components/upsert/event.vue new file mode 100644 index 0000000..e7b15a9 --- /dev/null +++ b/src/modules/demo/views/crud/components/upsert/event.vue @@ -0,0 +1,210 @@ + + + diff --git a/src/modules/demo/views/crud/components/upsert/hook/index.vue b/src/modules/demo/views/crud/components/upsert/hook/index.vue new file mode 100644 index 0000000..f5dfcc0 --- /dev/null +++ b/src/modules/demo/views/crud/components/upsert/hook/index.vue @@ -0,0 +1,200 @@ + + + diff --git a/src/modules/demo/views/crud/components/upsert/hook/reg-pca2.ts b/src/modules/demo/views/crud/components/upsert/hook/reg-pca2.ts new file mode 100644 index 0000000..472a9c8 --- /dev/null +++ b/src/modules/demo/views/crud/components/upsert/hook/reg-pca2.ts @@ -0,0 +1,14 @@ +import { registerFormHook } from '@cool-vue/crud'; + +// 注册 hook +registerFormHook('pca2', (value, { method, form, prop }) => { + if (method == 'bind') { + return [form.province, form.city, form.district]; + } else { + const [province, city, district] = value || []; + form.province = province; + form.city = city; + form.district = district; + form[prop] = undefined; + } +}); diff --git a/src/modules/demo/views/crud/components/upsert/mode.vue b/src/modules/demo/views/crud/components/upsert/mode.vue new file mode 100644 index 0000000..1b7fb8d --- /dev/null +++ b/src/modules/demo/views/crud/components/upsert/mode.vue @@ -0,0 +1,146 @@ + + + diff --git a/src/modules/demo/views/crud/index.vue b/src/modules/demo/views/crud/index.vue new file mode 100644 index 0000000..a7a712d --- /dev/null +++ b/src/modules/demo/views/crud/index.vue @@ -0,0 +1,327 @@ + + + + + diff --git a/src/modules/demo/views/home/components/category-ratio.vue b/src/modules/demo/views/home/components/category-ratio.vue new file mode 100644 index 0000000..d8f6159 --- /dev/null +++ b/src/modules/demo/views/home/components/category-ratio.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/src/modules/demo/views/home/components/count-effect.vue b/src/modules/demo/views/home/components/count-effect.vue new file mode 100644 index 0000000..845b446 --- /dev/null +++ b/src/modules/demo/views/home/components/count-effect.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/modules/demo/views/home/components/count-paid.vue b/src/modules/demo/views/home/components/count-paid.vue new file mode 100644 index 0000000..c33d996 --- /dev/null +++ b/src/modules/demo/views/home/components/count-paid.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/modules/demo/views/home/components/count-user.vue b/src/modules/demo/views/home/components/count-user.vue new file mode 100644 index 0000000..aee2948 --- /dev/null +++ b/src/modules/demo/views/home/components/count-user.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/modules/demo/views/home/components/count-views.vue b/src/modules/demo/views/home/components/count-views.vue new file mode 100644 index 0000000..5e591c8 --- /dev/null +++ b/src/modules/demo/views/home/components/count-views.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/modules/demo/views/home/components/hot-goods.vue b/src/modules/demo/views/home/components/hot-goods.vue new file mode 100644 index 0000000..8c02f23 --- /dev/null +++ b/src/modules/demo/views/home/components/hot-goods.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/src/modules/demo/views/home/components/tab-chart.vue b/src/modules/demo/views/home/components/tab-chart.vue new file mode 100644 index 0000000..0656b78 --- /dev/null +++ b/src/modules/demo/views/home/components/tab-chart.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/src/modules/demo/views/home/index.vue b/src/modules/demo/views/home/index.vue new file mode 100644 index 0000000..34ea22a --- /dev/null +++ b/src/modules/demo/views/home/index.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/modules/demo/views/test/route.vue b/src/modules/demo/views/test/route.vue new file mode 100644 index 0000000..9f438f1 --- /dev/null +++ b/src/modules/demo/views/test/route.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/src/modules/dict/config.ts b/src/modules/dict/config.ts new file mode 100644 index 0000000..291820c --- /dev/null +++ b/src/modules/dict/config.ts @@ -0,0 +1,16 @@ +import { type ModuleConfig } from '/@/cool'; +import { useDict } from './index'; + +export default (): ModuleConfig => { + return { + ignore: { + NProgress: ['/dict/info/data'] + }, + onLoad({ hasToken }) { + const { dict } = useDict(); + hasToken(() => { + dict.refresh(); + }); + } + }; +}; diff --git a/src/modules/dict/index.ts b/src/modules/dict/index.ts new file mode 100644 index 0000000..26e543e --- /dev/null +++ b/src/modules/dict/index.ts @@ -0,0 +1,7 @@ +import { useStore } from './store'; + +export function useDict() { + return { + ...useStore() + }; +} diff --git a/src/modules/dict/locales/en.json b/src/modules/dict/locales/en.json new file mode 100644 index 0000000..60e2043 --- /dev/null +++ b/src/modules/dict/locales/en.json @@ -0,0 +1,16 @@ +{ + "搜索名称": "Search Name", + "请填写值": "Please fill in the value", + "使用文件": "Use File", + "类型": "Type", + "字典列表": "Dictionary List", + "名称": "Name", + "上级节点": "Parent Node", + "值": "Value", + "排序": "Sort", + "备注": "Remarks", + "新增": "Add", + "ID": "ID", + "创建时间": "Create Time", + "更新时间": "Update Time" +} \ No newline at end of file diff --git a/src/modules/dict/locales/zh-cn.json b/src/modules/dict/locales/zh-cn.json new file mode 100644 index 0000000..196194c --- /dev/null +++ b/src/modules/dict/locales/zh-cn.json @@ -0,0 +1,16 @@ +{ + "搜索名称": "搜索名称", + "请填写值": "请填写值", + "使用文件": "使用文件", + "类型": "类型", + "字典列表": "字典列表", + "名称": "名称", + "上级节点": "上级节点", + "值": "值", + "排序": "排序", + "备注": "备注", + "新增": "新增", + "ID": "ID", + "创建时间": "创建时间", + "更新时间": "更新时间" +} \ No newline at end of file diff --git a/src/modules/dict/locales/zh-tw.json b/src/modules/dict/locales/zh-tw.json new file mode 100644 index 0000000..f91fb7a --- /dev/null +++ b/src/modules/dict/locales/zh-tw.json @@ -0,0 +1,16 @@ +{ + "搜索名称": "搜尋名稱", + "请填写值": "請填寫值", + "使用文件": "使用文件", + "类型": "類型", + "字典列表": "字典列表", + "名称": "名稱", + "上级节点": "上級節點", + "值": "值", + "排序": "排序", + "备注": "備註", + "新增": "新增", + "ID": "ID", + "创建时间": "創建時間", + "更新时间": "更新時間" +} \ No newline at end of file diff --git a/src/modules/dict/store/dict.ts b/src/modules/dict/store/dict.ts new file mode 100644 index 0000000..f4c3638 --- /dev/null +++ b/src/modules/dict/store/dict.ts @@ -0,0 +1,65 @@ +import { defineStore } from 'pinia'; +import { computed, reactive, toRaw } from 'vue'; +import { service } from '/@/cool'; +import { deepTree } from '/@/cool/utils'; +import { isDev } from '/@/config'; +import { assign, isArray, orderBy } from 'lodash-es'; +import { deepFind, isEmpty } from '../utils'; + +const useDictStore = defineStore('dict', () => { + // 对象数据 + const data = reactive({}); + + // 获取 + function get(name: Dict.Key, sort?: 'desc' | 'asc') { + return computed(() => orderBy(data[name] || [], 'orderNum', sort)); + } + + // 查找 + function find(name: Dict.Key, value: any | any[]) { + const arr = isArray(value) ? value : [value]; + return arr.filter(e => e !== undefined).map(v => deepFind(v, get(name).value)); + } + + // 刷新 + async function refresh(types?: Dict.Key[]) { + return service.dict.info + .data({ + types: types?.filter(e => !isEmpty(e)) + }) + .then((res: Dict.Data) => { + const d = {}; + + for (const [i, arr] of Object.entries(res)) { + arr.forEach(e => { + e.label = e.name; + + if (isEmpty(e.value)) { + e.value = e.id; + } + }); + + d[i] = deepTree(arr, 'desc'); + } + + assign(data, d); + + if (isDev) { + console.group('字典数据'); + console.log(toRaw(data)); + console.groupEnd(); + } + + return data; + }); + } + + return { + data, + get, + find, + refresh + }; +}); + +export { useDictStore }; diff --git a/src/modules/dict/store/index.ts b/src/modules/dict/store/index.ts new file mode 100644 index 0000000..9261de5 --- /dev/null +++ b/src/modules/dict/store/index.ts @@ -0,0 +1,9 @@ +import { useDictStore } from './dict'; + +export function useStore() { + const dict = useDictStore(); + + return { + dict + }; +} diff --git a/src/modules/dict/types/index.d.ts b/src/modules/dict/types/index.d.ts new file mode 100644 index 0000000..d2cd99d --- /dev/null +++ b/src/modules/dict/types/index.d.ts @@ -0,0 +1,15 @@ +namespace Dict { + type Key = Eps.DictKey | (string & {}); + + interface Item { + id: string; + label: string; + value: any; + children?: Item[]; + [key: string]: any; + } + + interface Data { + [key: string]: Item[]; + } +} diff --git a/src/modules/dict/utils/index.ts b/src/modules/dict/utils/index.ts new file mode 100644 index 0000000..cf19f63 --- /dev/null +++ b/src/modules/dict/utils/index.ts @@ -0,0 +1,31 @@ +export function deepFind(value: any, list: any[], options?: { allLevels: boolean }) { + const { allLevels = true } = options || {}; + + function deep(arr: any[], name: string[]): any | undefined { + for (const e of arr) { + if (e.value === value) { + if (allLevels) { + return { + ...e, + label: [...name, e.label].join(' / ') + }; + } else { + return e; + } + } else if (e.children) { + const d = deep(e.children, [...name, e.label]); + + if (d !== undefined) { + return d; + } + } + } + return undefined; + } + + return deep(list, []); +} + +export function isEmpty(val: any) { + return val === '' || val === null || val === undefined; +} diff --git a/src/modules/dict/views/list.vue b/src/modules/dict/views/list.vue new file mode 100644 index 0000000..6d2859b --- /dev/null +++ b/src/modules/dict/views/list.vue @@ -0,0 +1,281 @@ + + + diff --git a/src/modules/helper/components/ai-code/btn.vue b/src/modules/helper/components/ai-code/btn.vue new file mode 100644 index 0000000..b40449c --- /dev/null +++ b/src/modules/helper/components/ai-code/btn.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/modules/helper/components/ai-code/dev.vue b/src/modules/helper/components/ai-code/dev.vue new file mode 100644 index 0000000..6aaf325 --- /dev/null +++ b/src/modules/helper/components/ai-code/dev.vue @@ -0,0 +1,76 @@ +

3ExPr5W{+xe@#{A zl~h-ASJ&C{FrIk}K$gUO>GdN_IcFs2!B?>zbq!KwO9~El7P1goV`FJ5A2;@9M880& z$;JwuVGzTk4=v3APK^4v5er8OZEVjOPf^jIqt@N{TY5Img%PBBTvVI)#&s`>lqE^S z`S!ET(%;gk`HH5tiOG*X(of5)nGe3GVZJ|Odf>Ga=!2{|?fsOVo?gASyZgLPP5ZYx z;rMCh+%rUro8V{OjrC`c-7YvyqM4{i!0l#V!NEXAhGR{;jg9(baQS_c>_DW{8ijbx zl(5J%9|j5K@uti<9P`SqO+B@vrdi-(!2Yl7(m`}3Iy72^=Ji{9SV>VTaelk{J;T(@ z(pQ`4=;*k|DTPILFxb6dsB9Ua?fnMokY;0pcQmIFx9fI$vw-?tz`Cjd=8+B(zu6AB zU@kHDqh(@h$a5%EF`Q&xX}@^Ca6|-@hIHJ-&)932-0h@Y9wSk6I;v%5Wjiyt!;WAJ z8kJu05JT>+vMN?{9WH!k+Cox|9Y@@=A8b`&RmIfDR#C1j8I`=fb)+W#sn)p{D*4{1oxR|I@#3wi!&6QKhM~C357D81N)%8zMy@TQ*_#`9 z>l<(b+gvA9n8cvz2$^Uv9}cZNdzz+0!eYJdxLLpBaJp;!f#?0G(6HTTCh<`{i1#JL zAo*$o;!8xO4~;f7)!FHETWN;tIe07UbG&930R_3PEL;belvZ%}D_*({$FP;nO1hg{ zm_fbTMIM^bj~dr@&Xw^q(vOmFF`3q^CKH3y*o4fSedDvZoLYQl+WN3ns2)}ia~}z5 znr8YnNIL)8!)|$&F=;US=>&DR^he!2jixP$ClrM<7n`0!k5sL2kHj2`V>VB2zK9Fb z)0S7*tXbVHak(E0LtnWImPuz3$I-Inu$gWm3htBOnNw=vbA8n zJ=&;RWb?i?X7$l7PtjL*`>30l^%?(%5u}pjkxWV6v?o}~dnL5l-(6t=M6(;~21lKC zge^7y%ffUEzl&-c5j)}!vs#)5F$@}`+~Bw3yi1mfDKf!X4_yeSpzJkjO z{9&)%mFW3X@@R|Cuo*roA|B5Wuk7=*Fst2h8^61pek^tk4ntUJ&2pHt+d~f}syBS^ zSH~{T=^DEsn6uO>1;khpJ=p*|*MsT1Ops@b{tn-UKyPPMo;hPzDV7+2phM^Q8(AyB{f?fG8Hn%k<5`~FLlx}o`!Lx3!@CKxscBfBDEAbd`NHlb}MwR*_c!A&UCW^3dSM`s_N^!hVUS3YP7Pl(RLy! zepAt<*`4SeT_JPz{p3RRo%IRFBu3AJlJu7k0@#I*dtLZ*f7?CW$RJQj%(WK-_vN^` mU%Sg;Jun}61RUJyaR9q;-_eCS;L^Wq2T)VeQmmG@`t(1%KlQu- literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/sleeping-face.png b/src/modules/cs/static/emoji/sleeping-face.png new file mode 100644 index 0000000000000000000000000000000000000000..749e4ee2ac9033f5cac7b8b62b53cbc962e367c6 GIT binary patch literal 3525 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/sleepy-face.png b/src/modules/cs/static/emoji/sleepy-face.png new file mode 100644 index 0000000000000000000000000000000000000000..21b72c12dd5e612428781b34384d194b9d66df29 GIT binary patch literal 3477 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 UiKJ>>KEV)eO#_W$HEYa&02%gsQ2+n{ literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/slightly-smiling-face.png b/src/modules/cs/static/emoji/slightly-smiling-face.png new file mode 100644 index 0000000000000000000000000000000000000000..a0d68d143670f86a470f17d698344f3deb0ffafe GIT binary patch literal 3737 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 IM6N<$g1LwSkN^Mx literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/smiling-face-with-horns.png b/src/modules/cs/static/emoji/smiling-face-with-horns.png new file mode 100644 index 0000000000000000000000000000000000000000..f0b56af317f9129fb29f2392a386f94edc01c6d6 GIT binary patch literal 3957 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 P00000NkvXXu0mjfnYKJH literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/smiling-face-with-open-mouth-and-smiling-eyes.png b/src/modules/cs/static/emoji/smiling-face-with-open-mouth-and-smiling-eyes.png new file mode 100644 index 0000000000000000000000000000000000000000..a702c9355a956dc2de1c3b12335c9493e21e68b2 GIT binary patch literal 3710 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 X4wN$N)#mwszchqV*Hx=fu@3n^HY}O; literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/smiling-face-with-open-mouth.png b/src/modules/cs/static/emoji/smiling-face-with-open-mouth.png new file mode 100644 index 0000000000000000000000000000000000000000..7798b4114bcce2d2c2ce97aa15a84e4bfb07afe1 GIT binary patch literal 3581 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 Vqw&a&Z*%|v002ovPDHLkV1lXsSdRbz literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/smiling-face-with-smiling-eyes-and-three-hearts.png b/src/modules/cs/static/emoji/smiling-face-with-smiling-eyes-and-three-hearts.png new file mode 100644 index 0000000000000000000000000000000000000000..d621f0dd7030683fac524dccf253219de6060677 GIT binary patch literal 3986 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 Ef}M+JX#fBK literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/thinking-face.png b/src/modules/cs/static/emoji/thinking-face.png new file mode 100644 index 0000000000000000000000000000000000000000..7431ed01ee4c7e13e09787212877cd20b3c99532 GIT binary patch literal 3763 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 BK~Vqz literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/upside-down-face.png b/src/modules/cs/static/emoji/upside-down-face.png new file mode 100644 index 0000000000000000000000000000000000000000..677f7460ac9f189e797e2ea4c1427d9c507b4165 GIT binary patch literal 3688 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 AE&u=k literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/weary-face.png b/src/modules/cs/static/emoji/weary-face.png new file mode 100644 index 0000000000000000000000000000000000000000..74325b9be3d81ceeb8456ef4e243348185344c45 GIT binary patch literal 3726 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 literal 0 HcmV?d00001 diff --git a/src/modules/cs/static/emoji/worried-face.png b/src/modules/cs/static/emoji/worried-face.png new file mode 100644 index 0000000000000000000000000000000000000000..8638920c4bf8da93de56986ce9f1a647b9342db1 GIT binary patch literal 3655 zcmV-N4!H4&P)Px&08mU+MMrQ<$$})!fgJm;8T_LL%8M<_eH-zf6#1qH zy_HkSeICkc0Lph2#c2cfpby1p0{4vo%W46|Z3o|m7VCll#%>A5Y6Qe=3CD2^-g*Gb zdlk!S0mO3?%WVVrlLG351m}?*-HIUWl^Vfj0oQc_)OQN+mjmX73*CMU@RbnnoF2q! z1jTCx#%KZSf&%oI3;L)J(QyLBX93}V2knRj(QpCuj05F;0rr{+_o5K=p&0n56!xSP z|F|Ikwi^HAE%>Sn{`Go(+ zD)68O+k^t~qYV784*&hi|H(A}{m}pRWBX`_mV*%NJ0sr}X|L;rx z%ryVtEdT!2Z!`e^$|nEMF#p{&bU6V3{^r+u0OgGW|H~}@#W4TCBm1fj|M`}bR|435 z0sqA$|J^J9(kcI=0{{Kn|N5x^!v=>-0sifP|MN`$_;dgJwg3CE{gwd#)hhq~;ekZ~ z|J4!y^-=%!SMik#|G+Wzo(=uoKL6-V|FZ-CsRIAH1pnwg|L|b{!YKdmQl4J{jZXmX zlL7zcMg5)u|Km9S-bw%OSpUondq4pG-)P-|0srDZ|I|PKt_1(+b%am{>!~9C)>Qw) zG46=~|I|nS@sy8K0srSz|G5$W^NRo2H~;jUwwXhteJ$jJ0Ku&k2&iWS zr+XccUJ|!{4D!n+|Jqu+jwIW&J>$}8^yzy0$tL&1G_!*j-@HK9u`Z-^49uoD`R{G= z-f)_19`4mO_p~L!m?O@X73#k$&!Zgf#zXhjE5VWz|K1+$!z0YKO=2bh|HKvO)m!Mt zQ~%K)^}Z?Aj1c+JC`{)iL;wH)J#e}JK;L|V>!>9lN3YzRzI}jH zK_U{QBSqTMk#>%2S$l6=-gjq)K+yHM@4d4>JjcnsGe7>{H*;qu$jSYGP?7s1A(Q`C zgR;ERI?c7(n>TOPUaPiTLGiy6Dk`nr{I|bvo1=FPp*LsSKQ?KvQy~4`YE;*5`s;DM zYp<)$5mdc?ea(H_*3Ih_e}{&oq`lR?AhW9K+;bhrLzhcRN-kLLd=9eAqPlIHH03|m zqpJOvLeQLhem={_|H#>IfwLK&4qbO@o+Fj|Cbf@BrKq_z9cd~$9B|1LXU}?u)yJL7 zEGk^RLFpsnY*<}blzFbbYwwYaBN-VPX9-~Q2;kq5UzJ&qzE$%-T!G|uYs3(zrggvP zUQbU?I5L9(Heq1z-o5@=W+;^Q2Ro Y1jsXlu@00-eN4BP_4{`*h1R~6OeY*+Yz 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 N002ovPDHLkV1m#$SbqQj literal 0 HcmV?d00001 diff --git a/src/modules/cs/types/index.d.ts b/src/modules/cs/types/index.d.ts new file mode 100644 index 0000000..2256fa8 --- /dev/null +++ b/src/modules/cs/types/index.d.ts @@ -0,0 +1,13 @@ +export declare namespace Cs { + interface Content { + type: "text" | "image" | "voice" | "video" | "file" | "link" | "location" | "emoji"; + data: string; + } + + interface Msg extends Eps.CsMsgEntity { + content: Content; + sessionId?: number; + } + + interface Session extends Eps.CsSessionEntity {} +} diff --git a/src/modules/cs/utils/index.ts b/src/modules/cs/utils/index.ts new file mode 100644 index 0000000..9499acb --- /dev/null +++ b/src/modules/cs/utils/index.ts @@ -0,0 +1,52 @@ +import dayjs from "dayjs"; +import type { Cs } from "../types"; + +// 消息格式化 +export function msgFormatter(msg: Cs.Msg) { + if (!msg) { + return ""; + } + + switch (msg.content.type) { + case "text": + return msg.content.data; + + case "emoji": + return "【表情】"; + + case "image": + return "【图片】"; + + case "link": + return "【链接】"; + + case "voice": + return "【音频】"; + + case "file": + return "【文件】"; + + case "video": + return "【视频】"; + + case "location": + return "【定位】"; + } +} + +// 日期格式化 +export function dateFormatter(date?: Date) { + const t = dayjs(date); + + // 在今天之前 + if (t.isBefore(dayjs().hour(0).minute(0).second(0))) { + return t.format("YYYY-MM-DD HH:mm"); + } else { + return t.format("HH:mm"); + } +} + +// 表情链接 +export function getEmoji(name: string) { + return new URL(`../static/emoji/${name}`, import.meta.url).href; +} diff --git a/src/modules/cs/views/chat.vue b/src/modules/cs/views/chat.vue new file mode 100644 index 0000000..a25aa0c --- /dev/null +++ b/src/modules/cs/views/chat.vue @@ -0,0 +1,175 @@ + + + diff --git a/src/modules/demo/config.ts b/src/modules/demo/config.ts new file mode 100644 index 0000000..13c4911 --- /dev/null +++ b/src/modules/demo/config.ts @@ -0,0 +1,27 @@ +import { type ModuleConfig } from '/@/cool'; + +export default (): ModuleConfig => { + return { + components: [() => import('./views/crud/components/code.vue')], + + views: [ + { + // 单个参数 + // path: "/demo/test/route/:id", + + // 多个参数 + // path: "/demo/test/route/:id/:name", + + // 参数可选 + path: '/demo/test/route/:id/:name?', + + // 更多看文档:https://router.vuejs.org/zh/guide/essentials/route-matching-syntax.html + + meta: { + label: '动态路由参数' + }, + component: () => import('./views/test/route.vue') + } + ] + }; +}; diff --git a/src/modules/demo/directives/color.ts b/src/modules/demo/directives/color.ts new file mode 100644 index 0000000..8c5b1c6 --- /dev/null +++ b/src/modules/demo/directives/color.ts @@ -0,0 +1,5 @@ +export default { + created(el: HTMLElement, binding: any) { + el.style.color = binding.value; + } +}; diff --git a/src/modules/demo/locales/en.json b/src/modules/demo/locales/en.json new file mode 100644 index 0000000..20572fb --- /dev/null +++ b/src/modules/demo/locales/en.json @@ -0,0 +1,54 @@ +{ + "浏览量": "Views", + "访客数": "Visitors", + "总用户数": "Total Users", + "日增用户数": "Daily New Users", + "付款笔数": "Payment Transactions", + "转化率": "Conversion Rate", + "总销售额": "Total Sales", + "周同比": "Week-on-Week", + "日同比": "Day-on-Day", + "类别占比": "Category Share", + "启用": "Enabled", + "描述": "Description", + "未知": "Unknown", + "男": "Male", + "女": "Female", + "禁用": "Disabled", + "正常": "Normal", + "已注销": "Canceled", + "小程序": "Mini Program", + "公众号": "Official Account", + "H5": "H5", + "登录唯一ID": "Login Unique ID", + "头像": "Avatar", + "昵称": "Nickname", + "手机号": "Mobile Phone Number", + "性别": "Gender", + "状态": "Status", + "登录方式": "Login Method", + "来源": "Source", + "密码": "Password", + "介绍": "Introduction", + "余额": "Balance", + "标题": "Title", + "ID": "ID", + "创建时间": "Create Time", + "更新时间": "Update Time", + "搜索手机号、昵称": "Search Mobile Number, Nickname", + "{year}年": "{year} Year", + "销售金额": "Sales Amount", + "销售订单": "Sales Order", + "{i}月": "{i} Month", + "热门商品排行": "Popular Product Ranking", + "今日": "Today", + "本周": "This Week", + "本月": "This Month", + "全年": "Full Year", + "排名": "Ranking", + "商品名称": "Product Name", + "商品金额": "Product Amount", + "下单次数": "Order Placed Times", + "日涨幅": "Daily Increase", + "上架时间": "Listing Time" +} \ No newline at end of file diff --git a/src/modules/demo/locales/zh-cn.json b/src/modules/demo/locales/zh-cn.json new file mode 100644 index 0000000..8182c78 --- /dev/null +++ b/src/modules/demo/locales/zh-cn.json @@ -0,0 +1,54 @@ +{ + "未知": "未知", + "男": "男", + "女": "女", + "禁用": "禁用", + "正常": "正常", + "已注销": "已注销", + "小程序": "小程序", + "公众号": "公众号", + "H5": "H5", + "登录唯一ID": "登录唯一ID", + "头像": "头像", + "昵称": "昵称", + "手机号": "手机号", + "性别": "性别", + "状态": "状态", + "登录方式": "登录方式", + "来源": "来源", + "密码": "密码", + "介绍": "介绍", + "余额": "余额", + "标题": "标题", + "ID": "ID", + "创建时间": "创建时间", + "更新时间": "更新时间", + "搜索手机号、昵称": "搜索手机号、昵称", + "{year}年": "{year}年", + "销售金额": "销售金额", + "销售订单": "销售订单", + "{i}月": "{i}月", + "热门商品排行": "热门商品排行", + "今日": "今日", + "本周": "本周", + "本月": "本月", + "全年": "全年", + "排名": "排名", + "商品名称": "商品名称", + "商品金额": "商品金额", + "下单次数": "下单次数", + "日涨幅": "日涨幅", + "上架时间": "上架时间", + "浏览量": "浏览量", + "访客数": "访客数", + "总用户数": "总用户数", + "日增用户数": "日增用户数", + "付款笔数": "付款笔数", + "转化率": "转化率", + "总销售额": "总销售额", + "周同比": "周同比", + "日同比": "日同比", + "类别占比": "类别占比", + "启用": "启用", + "描述": "描述" +} \ No newline at end of file diff --git a/src/modules/demo/locales/zh-tw.json b/src/modules/demo/locales/zh-tw.json new file mode 100644 index 0000000..74117a5 --- /dev/null +++ b/src/modules/demo/locales/zh-tw.json @@ -0,0 +1,54 @@ +{ + "浏览量": "瀏覽量", + "访客数": "訪客數", + "总用户数": "總用戶數", + "日增用户数": "日增用戶數", + "付款笔数": "付款筆數", + "转化率": "轉化率", + "总销售额": "總銷售額", + "周同比": "周同比", + "日同比": "日同比", + "类别占比": "類別占比", + "启用": "啟用", + "描述": "描述", + "未知": "未知", + "男": "男", + "女": "女", + "禁用": "禁用", + "正常": "正常", + "已注销": "已註銷", + "小程序": "小程序", + "公众号": "公眾號", + "H5": "H5", + "登录唯一ID": "登錄唯一ID", + "头像": "頭像", + "昵称": "暱稱", + "手机号": "手機號", + "性别": "性別", + "状态": "狀態", + "登录方式": "登錄方式", + "来源": "來源", + "密码": "密碼", + "介绍": "介紹", + "余额": "餘額", + "标题": "標題", + "ID": "ID", + "创建时间": "創建時間", + "更新时间": "更新時間", + "搜索手机号、昵称": "搜索手機號、暱稱", + "{year}年": "{year}年", + "销售金额": "銷售金額", + "销售订单": "銷售訂單", + "{i}月": "{i}月", + "热门商品排行": "熱門商品排行", + "今日": "今日", + "本周": "本周", + "本月": "本月", + "全年": "全年", + "排名": "排名", + "商品名称": "商品名稱", + "商品金额": "商品金額", + "下单次数": "下單次數", + "日涨幅": "日漲幅", + "上架时间": "上架時間" +} \ No newline at end of file diff --git a/src/modules/demo/views/crud/components/adv-search/base.vue b/src/modules/demo/views/crud/components/adv-search/base.vue new file mode 100644 index 0000000..0b74d4a --- /dev/null +++ b/src/modules/demo/views/crud/components/adv-search/base.vue @@ -0,0 +1,138 @@ + + + diff --git a/src/modules/demo/views/crud/components/adv-search/custom.vue b/src/modules/demo/views/crud/components/adv-search/custom.vue new file mode 100644 index 0000000..94ce40c --- /dev/null +++ b/src/modules/demo/views/crud/components/adv-search/custom.vue @@ -0,0 +1,152 @@ + + + diff --git a/src/modules/demo/views/crud/components/code.vue b/src/modules/demo/views/crud/components/code.vue new file mode 100644 index 0000000..96b90f1 --- /dev/null +++ b/src/modules/demo/views/crud/components/code.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/modules/demo/views/crud/components/crud/all.vue b/src/modules/demo/views/crud/components/crud/all.vue new file mode 100644 index 0000000..bea553f --- /dev/null +++ b/src/modules/demo/views/crud/components/crud/all.vue @@ -0,0 +1,578 @@ + + + diff --git a/src/modules/demo/views/crud/components/crud/base.vue b/src/modules/demo/views/crud/components/crud/base.vue new file mode 100644 index 0000000..b3851af --- /dev/null +++ b/src/modules/demo/views/crud/components/crud/base.vue @@ -0,0 +1,145 @@ + + + diff --git a/src/modules/demo/views/crud/components/crud/dict.vue b/src/modules/demo/views/crud/components/crud/dict.vue new file mode 100644 index 0000000..da64ac8 --- /dev/null +++ b/src/modules/demo/views/crud/components/crud/dict.vue @@ -0,0 +1,164 @@ + + + diff --git a/src/modules/demo/views/crud/components/crud/event.vue b/src/modules/demo/views/crud/components/crud/event.vue new file mode 100644 index 0000000..f75dd27 --- /dev/null +++ b/src/modules/demo/views/crud/components/crud/event.vue @@ -0,0 +1,182 @@ + + + diff --git a/src/modules/demo/views/crud/components/crud/select-table.vue b/src/modules/demo/views/crud/components/crud/select-table.vue new file mode 100644 index 0000000..0a4a33c --- /dev/null +++ b/src/modules/demo/views/crud/components/crud/select-table.vue @@ -0,0 +1,155 @@ + + + diff --git a/src/modules/demo/views/crud/components/crud/service.vue b/src/modules/demo/views/crud/components/crud/service.vue new file mode 100644 index 0000000..fda349b --- /dev/null +++ b/src/modules/demo/views/crud/components/crud/service.vue @@ -0,0 +1,179 @@ + + + diff --git a/src/modules/demo/views/crud/components/crud/user-select.vue b/src/modules/demo/views/crud/components/crud/user-select.vue new file mode 100644 index 0000000..afbd6ab --- /dev/null +++ b/src/modules/demo/views/crud/components/crud/user-select.vue @@ -0,0 +1,77 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/children.vue b/src/modules/demo/views/crud/components/form/children.vue new file mode 100644 index 0000000..3730ef4 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/children.vue @@ -0,0 +1,118 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/component/index.vue b/src/modules/demo/views/crud/components/form/component/index.vue new file mode 100644 index 0000000..c404408 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/component/index.vue @@ -0,0 +1,124 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/component/select-labels.vue b/src/modules/demo/views/crud/components/form/component/select-labels.vue new file mode 100644 index 0000000..e21e5af --- /dev/null +++ b/src/modules/demo/views/crud/components/form/component/select-labels.vue @@ -0,0 +1,42 @@ + + + + diff --git a/src/modules/demo/views/crud/components/form/component/select-status.vue b/src/modules/demo/views/crud/components/form/component/select-status.vue new file mode 100644 index 0000000..2dfabea --- /dev/null +++ b/src/modules/demo/views/crud/components/form/component/select-status.vue @@ -0,0 +1,47 @@ + + + + diff --git a/src/modules/demo/views/crud/components/form/component/select-work.vue b/src/modules/demo/views/crud/components/form/component/select-work.vue new file mode 100644 index 0000000..6ff625f --- /dev/null +++ b/src/modules/demo/views/crud/components/form/component/select-work.vue @@ -0,0 +1,63 @@ + + + + diff --git a/src/modules/demo/views/crud/components/form/component/select-work2.vue b/src/modules/demo/views/crud/components/form/component/select-work2.vue new file mode 100644 index 0000000..818a215 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/component/select-work2.vue @@ -0,0 +1,42 @@ + + + + diff --git a/src/modules/demo/views/crud/components/form/config.vue b/src/modules/demo/views/crud/components/form/config.vue new file mode 100644 index 0000000..32d6604 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/config.vue @@ -0,0 +1,122 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/crud.vue b/src/modules/demo/views/crud/components/form/crud.vue new file mode 100644 index 0000000..ca4d892 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/crud.vue @@ -0,0 +1,151 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/disabled.vue b/src/modules/demo/views/crud/components/form/disabled.vue new file mode 100644 index 0000000..1a109ad --- /dev/null +++ b/src/modules/demo/views/crud/components/form/disabled.vue @@ -0,0 +1,64 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/event.vue b/src/modules/demo/views/crud/components/form/event.vue new file mode 100644 index 0000000..201ecf8 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/event.vue @@ -0,0 +1,93 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/group.vue b/src/modules/demo/views/crud/components/form/group.vue new file mode 100644 index 0000000..fc2e07b --- /dev/null +++ b/src/modules/demo/views/crud/components/form/group.vue @@ -0,0 +1,105 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/hidden.vue b/src/modules/demo/views/crud/components/form/hidden.vue new file mode 100644 index 0000000..e28a665 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/hidden.vue @@ -0,0 +1,77 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/layout.vue b/src/modules/demo/views/crud/components/form/layout.vue new file mode 100644 index 0000000..b4ab074 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/layout.vue @@ -0,0 +1,98 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/open.vue b/src/modules/demo/views/crud/components/form/open.vue new file mode 100644 index 0000000..8105135 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/open.vue @@ -0,0 +1,84 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/options.vue b/src/modules/demo/views/crud/components/form/options.vue new file mode 100644 index 0000000..8c51305 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/options.vue @@ -0,0 +1,172 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/plugin/index.vue b/src/modules/demo/views/crud/components/form/plugin/index.vue new file mode 100644 index 0000000..bd65b40 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/plugin/index.vue @@ -0,0 +1,109 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/plugin/role.ts b/src/modules/demo/views/crud/components/form/plugin/role.ts new file mode 100644 index 0000000..f924c1e --- /dev/null +++ b/src/modules/demo/views/crud/components/form/plugin/role.ts @@ -0,0 +1,20 @@ +/** + * 角色权限控制 + * @param role + * @returns + */ +export function setRole(role?: string): ClForm.Plugin { + return ({ exposed }) => { + function deep(arr: ClForm.Item[]) { + arr.forEach(e => { + if (e.role) { + e.hidden = e.role != role; + } + + deep(e.children || []); + }); + } + + deep(exposed.config.items); + }; +} diff --git a/src/modules/demo/views/crud/components/form/required.vue b/src/modules/demo/views/crud/components/form/required.vue new file mode 100644 index 0000000..7de191f --- /dev/null +++ b/src/modules/demo/views/crud/components/form/required.vue @@ -0,0 +1,94 @@ + + + diff --git a/src/modules/demo/views/crud/components/form/rules.vue b/src/modules/demo/views/crud/components/form/rules.vue new file mode 100644 index 0000000..818f8d5 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/rules.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/modules/demo/views/crud/components/form/setFocus.vue b/src/modules/demo/views/crud/components/form/setFocus.vue new file mode 100644 index 0000000..467e039 --- /dev/null +++ b/src/modules/demo/views/crud/components/form/setFocus.vue @@ -0,0 +1,63 @@ + + + diff --git a/src/modules/demo/views/crud/components/other/context-menu.vue b/src/modules/demo/views/crud/components/other/context-menu.vue new file mode 100644 index 0000000..3551d16 --- /dev/null +++ b/src/modules/demo/views/crud/components/other/context-menu.vue @@ -0,0 +1,71 @@ + + + diff --git a/src/modules/demo/views/crud/components/other/tips.vue b/src/modules/demo/views/crud/components/other/tips.vue new file mode 100644 index 0000000..15d545d --- /dev/null +++ b/src/modules/demo/views/crud/components/other/tips.vue @@ -0,0 +1,150 @@ + + + diff --git a/src/modules/demo/views/crud/components/other/tsx/index.scss b/src/modules/demo/views/crud/components/other/tsx/index.scss new file mode 100644 index 0000000..bd99427 --- /dev/null +++ b/src/modules/demo/views/crud/components/other/tsx/index.scss @@ -0,0 +1,28 @@ +.tsx-list { + .item { + display: flex; + align-items: center; + justify-content: space-between; + border: 1px solid var(--el-border-color); + padding: 10px; + margin-bottom: 10px; + cursor: pointer; + border-radius: var(--el-border-radius-base); + + .el-icon { + display: none; + } + + &:hover { + background-color: var(--el-bg-color-page); + } + + &.is-active { + color: var(--el-color-primary); + + .el-icon { + display: block; + } + } + } +} diff --git a/src/modules/demo/views/crud/components/other/tsx/index.tsx b/src/modules/demo/views/crud/components/other/tsx/index.tsx new file mode 100644 index 0000000..ae3396b --- /dev/null +++ b/src/modules/demo/views/crud/components/other/tsx/index.tsx @@ -0,0 +1,109 @@ +import { defineComponent, ref } from 'vue'; +import { Check } from '@element-plus/icons-vue'; +import './index.scss'; + +interface Item { + name: string; + value: number; +} + +export default defineComponent({ + emits: ['checked'], + + setup(props, { emit, expose, slots }) { + // 列表数据 + const list = ref([ + { + name: '鸡腿堡', + value: 1 + }, + { + name: '牛肉堡', + value: 2 + } + ]); + + // 选择值 + const active = ref(); + + // 是否可见 + const visible = ref(false); + + // 打开 + function open() { + visible.value = true; + } + + // 选择 + function toCheck(item: Item) { + active.value = item.value; + + // 自定义事件 + emit('checked', item); + } + + // 暴露方法和变量,使上级可以使用 ref 的方式来调用 + expose({ + toCheck + }); + + // 必须返回一个方法 + return () => { + return ( +