From 16e2611a1ed05d275426b07497459d011b70a89e Mon Sep 17 00:00:00 2001 From: z9130 <984661593@qq.com> Date: Tue, 10 Sep 2024 22:30:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=80=E4=BA=9B=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .browserslistrc | 4 + .commitlintrc.mjs | 1 + .dockerignore | 5 + .editorconfig | 19 +- .env | 48 - .env.prod | 7 - .env.test | 7 - .eslintrc.js | 3 - .gitattributes | 24 +- .gitconfig | 2 + .gitignore | 55 +- .gitpod.yml | 6 + .husky/commit-msg | 6 + .husky/post-merge | 3 + .husky/pre-commit | 7 + .lintstagedrc.mjs | 20 + .ls-lint.yml | 28 + .node-version | 1 + .npmrc | 17 +- .prettierignore | 18 + .prettierrc.mjs | 1 + .stylelintignore | 4 + .vscode/extensions.json | 50 +- .vscode/global.code-snippets | 37 + .vscode/launch.json | 42 + .vscode/settings.json | 468 +- Dockerfile | 31 + LICENSE | 20 +- README.ja-JP.md | 149 + README.md | 170 +- README.zh-CN.md | 148 + alova.config.ts | 139 - apps/web-office/.env | 5 + apps/web-office/.env.analyze | 7 + apps/web-office/.env.development | 16 + apps/web-office/.env.production | 16 + apps/web-office/index.html | 34 + apps/web-office/package.json | 77 + apps/web-office/postcss.config.mjs | 1 + .../web-office/public}/favicon.ico | Bin apps/web-office/readme.md | 3 + apps/web-office/src/api/core/auth.ts | 73 + apps/web-office/src/api/core/index.ts | 3 + apps/web-office/src/api/core/menu.ts | 10 + apps/web-office/src/api/core/user.ts | 15 + apps/web-office/src/api/global.d.ts | 22 + apps/web-office/src/api/index.ts | 509 + .../web-office/src}/api/request/config.ts | 2 +- .../web-office/src}/api/request/getToken.ts | 21 +- apps/web-office/src/api/request/index.ts | 404 + .../src}/api/request/transferResponse.ts | 42 +- apps/web-office/src/api/system/auth.ts | 84 + apps/web-office/src/api/system/menu.ts | 10 + apps/web-office/src/app.vue | 66 + .../src}/assets/canteen/orderfood.png | Bin apps/web-office/src/bootstrap.ts | 42 + apps/web-office/src/common/unit.ts | 94 + .../src/components/dict-tag/dict-tag.vue | 99 + .../src/components/dict-tag/index.ts | 1 + .../web-office/src/hooks/fastCrud.ts | 0 .../web-office}/src/hooks/useRender.ts | 63 +- .../web-office/src/hooks}/vxeTable.ts | 6 +- apps/web-office/src/layouts/basic.vue | 164 + apps/web-office/src/layouts/index.ts | 8 + apps/web-office/src/locales/README.md | 3 + apps/web-office/src/locales/index.ts | 94 + apps/web-office/src/locales/langs/en-US.json | 8 + apps/web-office/src/locales/langs/zh-CN.json | 8 + apps/web-office/src/main.ts | 31 + apps/web-office/src/plugins/fastCrud.ts | 21 + apps/web-office/src/plugins/vxeTable.ts | 202 + apps/web-office/src/preferences.ts | 12 + apps/web-office/src/router/access.ts | 42 + apps/web-office/src/router/guard.ts | 240 + apps/web-office/src/router/index.ts | 32 + apps/web-office/src/router/routes/core.ts | 144 + apps/web-office/src/router/routes/index.ts | 31 + .../src/router/routes/modules/contract.ts | 438 + .../src/router/routes/modules/dashboard.ts | 49 + .../src/router/routes/modules/offfice.ts | 276 + .../src/router/routes/modules/system.ts | 29 + .../src/router/routes/modules/ucenter.ts | 51 + apps/web-office/src/store/auth.ts | 131 + .../web-office/src/store}/dict.ts | 22 +- apps/web-office/src/store/index.ts | 2 + .../web-office/src}/utils/dict/index.ts | 6 +- .../web-office/src}/utils/dict/shared.ts | 0 .../web-office/src}/utils/dict/static.data.ts | 0 apps/web-office/src/utils/file.ts | 101 + {src => apps/web-office/src}/utils/index.ts | 52 +- {src => apps/web-office/src}/utils/time.ts | 0 apps/web-office/src/views/_core/README.md | 3 + .../src/views/_core/about/index.vue | 9 + .../views/_core/authentication/code-login.vue | 30 + .../_core/authentication/forget-password.vue | 23 + .../src/views/_core/authentication/login.vue | 37 + .../_core/authentication/qrcode-login.vue | 10 + .../views/_core/authentication/register.vue | 25 + .../src/views/_core/fallback/coming-soon.vue | 7 + .../src/views/_core/fallback/forbidden.vue | 9 + .../views/_core/fallback/internal-error.vue | 9 + .../src/views/_core/fallback/not-found.vue | 9 + .../src/views/_core/fallback/offline.vue | 9 + .../src/views/bussiness-trip/edit/index.vue | 361 + .../list/choose-audit-people-modal.vue | 271 + .../src/views/bussiness-trip/list/crud.tsx | 47 +- .../src/views/bussiness-trip/list/index.vue | 266 + .../src/views/bussiness-trip/todo/crud.tsx | 51 + .../src/views/bussiness-trip/todo/index.vue | 253 + .../canteen/collect/collect-detail-modal.vue | 277 + .../src/views/canteen/collect/crud.tsx | 75 +- .../src/views/canteen/collect/index.vue | 252 + .../auto-people-batch-add-modal.vue | 184 + .../auto-people/auto-people-edit-modal.vue | 135 + .../components/auto-people/auto-people.vue | 208 + .../config/components/auto-people/crud.tsx | 32 +- .../basic-settings/basic-settings.vue | 296 + .../config/components/basic-settings/crud.tsx | 82 + .../components/delivery-address/crud.tsx | 43 + .../delivery-address-edit-modal.vue | 86 + .../delivery-address/delivery-address.vue | 177 + .../config/components/duty-people/crud.tsx | 51 + .../duty-people-batch-add-modal.vue | 208 + .../duty-people/duty-people-edit-modal.vue | 139 + .../components/duty-people/duty-people.vue | 180 + .../src/views/canteen/config/index.vue | 115 + .../canteen/orderfood/collect/collect.vue | 106 + .../views/canteen/orderfood/collect/crud.tsx | 140 + .../src/views/canteen/orderfood/index.vue | 37 + .../orderfood/choose-address-modal.vue | 93 + .../canteen/orderfood/orderfood/orderfood.vue | 519 + .../src/views/canteen/recipe/crud.tsx | 28 +- .../src/views/canteen/recipe/index.vue | 277 + .../canteen/recipe/recipe-sync-modal.vue | 315 + .../src/views/canteen/statistics/crud.tsx | 93 + .../src/views/canteen/statistics/index.vue | 44 + .../canteen/statistics/subsidy-statistics.vue | 329 + .../canteen/statistics/unit-statistics.vue | 622 + .../src/views/contract/approval/edit/curd.tsx | 181 + .../views/contract/approval/edit/index.vue | 367 + .../src/views/contract/approval/list/crud.tsx | 131 + .../views/contract/approval/list/index.vue | 219 + .../contract/approval/signing-basis/crud.tsx | 114 + .../contract/approval/signing-basis/index.vue | 250 + .../signing-basis-edit-modal.vue | 13 + .../views/contract/approval/todo/index.vue | 183 + .../src/views/contract/archive/list/crud.tsx | 97 + .../src/views/contract/archive/list/index.vue | 213 + .../views/contract/archive/todo/archive.vue | 183 + .../contract/archive/todo/retracement.vue | 183 + .../src/views/contract/audit/list/crud.tsx | 97 + .../src/views/contract/audit/list/index.vue | 213 + .../src/views/contract/audit/todo/index.vue | 183 + .../business/edit/basic-info-curd.tsx | 181 + .../src/views/contract/business/edit/curd.tsx | 181 + .../views/contract/business/edit/index.vue | 353 + .../src/views/contract/business/list/crud.tsx | 91 + .../views/contract/business/list/index.vue | 223 + .../views/contract/business/todo/index.vue | 183 + .../src/views/contract/company/edit/curd.tsx | 181 + .../src/views/contract/company/edit/index.vue | 367 + .../src/views/contract/company/list/crud.tsx | 48 + .../src/views/contract/company/list/index.vue | 160 + .../contract-type-edit-modal.vue | 150 + .../contract-type/contract-type.vue | 164 + .../config/components/contract-type/crud.tsx | 17 +- .../components/project-manager/crud.tsx | 42 + .../project-manager-edit-modal.vue | 89 + .../project-manager/project-manager.vue | 167 + .../components/project-name-manager/crud.tsx | 42 + .../project-name-manager-edit-modal.vue | 87 + .../project-name-manager.vue | 166 + .../components/template-manager/crud.tsx | 50 +- .../template-manager-edit-modal.vue | 168 + .../template-manager/template-manager.vue | 164 + .../src/views/contract/config/index.vue | 105 + .../views/contract/declaration/list/crud.tsx | 83 + .../views/contract/declaration/list/index.vue | 213 + .../views/contract/declaration/print/crud.tsx | 83 + .../contract/declaration/print/index.vue | 213 + .../views/contract/declaration/todo/index.vue | 183 + .../info-approval/info-approval.vue | 13 + .../info-archived/info-archived.vue | 13 + .../info-business/info-business.vue | 13 + .../info-declaration/info-declaration.vue | 13 + .../components/info-perform/info-perform.vue | 13 + .../components/info-sign/info-sign.vue | 13 + .../components/info-track/info-track.vue | 13 + .../src/views/contract/iframe-info/index.vue | 79 + .../src/views/contract/perform/list/crud.tsx | 71 + .../src/views/contract/perform/list/index.vue | 213 + .../views/contract/perform/result/index.vue | 183 + .../perform/temporary-archive/crud.tsx | 71 + .../perform/temporary-archive/index.vue | 213 + .../src/views/contract/perform/todo/index.vue | 183 + .../web-office/src}/views/contract/schema.ts | 9 +- .../sign-authorization/edit/index.vue | 609 + .../contract/sign-authorization/list/crud.tsx | 97 + .../sign-authorization/list/index.vue | 213 + .../src/views/contract/sign/list/crud.tsx | 97 + .../src/views/contract/sign/list/index.vue | 213 + .../src/views/contract/sign/todo/index.vue | 183 + .../web-office/src}/views/contract/utils.ts | 0 .../dashboard/analytics/analytics-trends.vue | 82 + .../analytics/analytics-visits-data.vue | 84 + .../analytics/analytics-visits-sales.vue | 48 + .../analytics/analytics-visits-source.vue | 67 + .../dashboard/analytics/analytics-visits.vue | 57 + .../src/views/dashboard/analytics/index.vue | 90 + .../dashboard/components/workbench-header.vue | 44 + .../components/workbench-quick-nav.vue | 44 + .../src/views/dashboard/home/index.vue | 79 + .../src/views/dashboard/workspace/index.vue | 225 + .../web-office/src/views/demos/antd/index.vue | 66 + apps/web-office/src/views/duty/list/crud.tsx | 160 + .../src/views/duty/list/duty-edit-modal.vue | 271 + .../src/views/duty/list/duty-upload-modal.vue | 129 + apps/web-office/src/views/duty/list/index.vue | 276 + .../src/views/duty/standing-book/crud.tsx | 153 + .../src/views/duty/standing-book/index.vue | 194 + .../src/views/meeting/edit/index.vue | 661 + .../meeting/edit/spoken-person-edit-modal.vue | 165 + .../src/views/meeting/list/crud.tsx | 179 + .../src/views/meeting/list/index.vue | 254 + .../src/views/meeting/standing-book/crud.tsx | 61 +- .../src/views/meeting/standing-book/index.vue | 194 + .../src/views/meeting/start/index.vue | 283 +- .../src/views/office-supplies/apply/crud.tsx | 131 + .../src/views/office-supplies/apply/index.vue | 161 + .../apply/office-batch-apply-modal.vue | 212 + .../src/views/office-supplies/audit/crud.tsx | 131 + .../src/views/office-supplies/audit/index.vue | 74 + .../inventory/choose-office-modal.vue | 213 + .../views/office-supplies/inventory/crud.tsx | 66 + .../views/office-supplies/inventory/index.vue | 206 + .../inventory/purchase-summary-modal.vue | 264 + .../inventory/supplies-edit-modal.vue | 123 + .../inventory/supplies-out-modal.vue | 274 + .../inventory/supplies-put-modal.vue | 219 + .../src/views/office-supplies/settle/crud.tsx | 131 + .../views/office-supplies/settle/index.vue | 149 + .../src/views/supervise/edit/index.vue | 375 + .../src/views/supervise/feedback/crud.tsx | 99 + .../src/views/supervise/feedback/index.vue | 156 + .../src/views/supervise/list/crud.tsx | 125 +- .../src/views/supervise/list/index.vue | 175 + .../src/views/supervise/summary/crud.tsx | 160 + .../src/views/supervise/summary/index.vue | 125 + .../web-office/src/views/system/dict/crud.tsx | 78 + .../system/dict/dict-data-edit-modal.vue | 187 + .../system/dict/dict-type-edit-modal.vue | 158 + .../src/views/system/dict/index.vue | 355 + .../views/system/user/choose-user-modal.vue | 355 + .../src/views/user-center/center/index.vue | 32 + .../src/views/user-center/todo/index.vue | 225 + apps/web-office/tailwind.config.mjs | 1 + apps/web-office/tsconfig.json | 14 + apps/web-office/tsconfig.node.json | 10 + apps/web-office/vite.config.mts | 97 + build-local-docker-image.sh | 55 + build/config/index.ts | 1 - build/config/proxy.ts | 36 - build/plugins/index.ts | 39 - build/plugins/router.ts | 98 - build/plugins/unocss.ts | 32 - build/plugins/unplugin.ts | 52 - cspell.json | 62 + eslint.config.js | 48 - eslint.config.mjs | 5 + index.html | 29 - .../lint-configs/commitlint-config/index.mjs | 153 + .../commitlint-config/package.json | 33 + .../eslint-config/build.config.ts | 7 + .../lint-configs/eslint-config/package.json | 57 + .../eslint-config/src/configs/command.ts | 10 + .../eslint-config/src/configs/comments.ts | 24 + .../eslint-config/src/configs/disableds.ts | 28 + .../eslint-config/src/configs/ignores.ts | 52 + .../eslint-config/src/configs/import.ts | 24 + .../eslint-config/src/configs/index.ts | 17 + .../eslint-config/src/configs/javascript.ts | 242 + .../eslint-config/src/configs/jsdoc.ts | 34 + .../eslint-config/src/configs/jsonc.ts | 258 + .../eslint-config/src/configs/node.ts | 56 + .../src/configs/perfectionist.ts | 112 + .../eslint-config/src/configs/prettier.ts | 19 + .../eslint-config/src/configs/regexp.ts | 20 + .../eslint-config/src/configs/test.ts | 45 + .../eslint-config/src/configs/turbo.ts | 18 + .../eslint-config/src/configs/typescript.ts | 72 + .../eslint-config/src/configs/unicorn.ts | 41 + .../eslint-config/src/configs/vue.ts | 134 + .../eslint-config/src/custom-config.ts | 145 + .../lint-configs/eslint-config/src/index.ts | 60 + .../lint-configs/eslint-config/src/util.ts | 8 + .../lint-configs/eslint-config/tsconfig.json | 6 + .../lint-configs/prettier-config/index.mjs | 24 + .../lint-configs/prettier-config/package.json | 28 + .../lint-configs/stylelint-config/index.mjs | 140 + .../stylelint-config/package.json | 43 + internal/node-utils/build.config.ts | 7 + internal/node-utils/package.json | 47 + .../node-utils/src/__tests__/hash.test.ts | 52 + .../node-utils/src/__tests__/path.test.ts | 67 + internal/node-utils/src/constants.ts | 6 + internal/node-utils/src/date.ts | 12 + internal/node-utils/src/fs.ts | 39 + internal/node-utils/src/git.ts | 34 + internal/node-utils/src/hash.ts | 18 + internal/node-utils/src/index.ts | 21 + internal/node-utils/src/monorepo.ts | 49 + internal/node-utils/src/path.ts | 11 + internal/node-utils/src/prettier.ts | 21 + internal/node-utils/src/spinner.ts | 24 + internal/node-utils/tsconfig.json | 6 + internal/tailwind-config/build.config.ts | 11 + internal/tailwind-config/package.json | 66 + internal/tailwind-config/src/index.ts | 264 + internal/tailwind-config/src/module.d.ts | 3 + internal/tailwind-config/src/plugins/entry.ts | 53 + .../tailwind-config/src/postcss.config.ts | 15 + internal/tailwind-config/tsconfig.json | 6 + internal/tsconfig/base.json | 40 + internal/tsconfig/library.json | 13 + internal/tsconfig/node.json | 12 + internal/tsconfig/package.json | 25 + internal/tsconfig/web-app.json | 8 + internal/tsconfig/web.json | 14 + internal/vite-config/build.config.ts | 7 + internal/vite-config/package.json | 56 + .../vite-config/src/config/application.ts | 115 + internal/vite-config/src/config/common.ts | 13 + internal/vite-config/src/config/index.ts | 37 + internal/vite-config/src/config/library.ts | 60 + internal/vite-config/src/index.ts | 4 + internal/vite-config/src/options.ts | 45 + .../src/plugins/extra-app-config.ts | 92 + internal/vite-config/src/plugins/importmap.ts | 245 + internal/vite-config/src/plugins/index.ts | 233 + .../src/plugins/inject-app-loading/README.md | 3 + .../default-loading-antd.html | 107 + .../inject-app-loading/default-loading.html | 113 + .../src/plugins/inject-app-loading/index.ts | 66 + .../src/plugins/inject-metadata.ts | 86 + internal/vite-config/src/plugins/license.ts | 63 + .../vite-config/src/plugins/nitro-mock.ts | 98 + internal/vite-config/src/plugins/print.ts | 28 + internal/vite-config/src/typing.ts | 147 + internal/vite-config/src/utils/env.ts | 105 + internal/vite-config/tsconfig.json | 6 + mock/common.ts | 14 - mock/index.ts | 0 mock/system/auth.ts | 12 - nginx.conf | 75 + package.json | 213 +- packages/@core/README.md | 3 + packages/@core/base/README.md | 5 + packages/@core/base/design/package.json | 41 + packages/@core/base/design/src/css/global.css | 149 + .../@core/base/design/src/css/nprogress.css | 59 + .../@core/base/design/src/css/transition.css | 236 + packages/@core/base/design/src/css/ui.css | 83 + .../design/src/design-tokens/dark/index.css | 433 + .../src/design-tokens/default/index.css | 370 + .../base/design/src/design-tokens/index.ts | 4 + packages/@core/base/design/src/index.ts | 7 + .../@core/base/design/src/scss-bem/bem.scss | 34 + .../base/design/src/scss-bem/constants.scss | 5 + packages/@core/base/design/tsconfig.json | 6 + packages/@core/base/design/vite.config.mts | 9 + packages/@core/base/icons/build.config.ts | 7 + packages/@core/base/icons/package.json | 41 + packages/@core/base/icons/src/create-icon.ts | 14 + packages/@core/base/icons/src/index.ts | 4 + packages/@core/base/icons/src/lucide.ts | 57 + packages/@core/base/icons/tsconfig.json | 6 + packages/@core/base/shared/build.config.ts | 14 + packages/@core/base/shared/package.json | 77 + .../cache/__tests__/storage-manager.test.ts | 130 + packages/@core/base/shared/src/cache/index.ts | 1 + .../base/shared/src/cache/storage-manager.ts | 118 + packages/@core/base/shared/src/cache/types.ts | 17 + .../src/color/__tests__/convert.test.ts | 58 + .../@core/base/shared/src/color/convert.ts | 62 + .../@core/base/shared/src/color/generator.ts | 44 + packages/@core/base/shared/src/color/index.ts | 2 + .../base/shared/src/constants/globals.ts | 11 + .../@core/base/shared/src/constants/index.ts | 2 + .../@core/base/shared/src/constants/vben.ts | 26 + packages/@core/base/shared/src/index.ts | 5 + packages/@core/base/shared/src/store.ts | 1 + .../shared/src/utils/__tests__/diff.test.ts | 53 + .../shared/src/utils/__tests__/dom.test.ts | 127 + .../src/utils/__tests__/inference.test.ts | 167 + .../shared/src/utils/__tests__/letter.test.ts | 116 + .../shared/src/utils/__tests__/tree.test.ts | 196 + .../shared/src/utils/__tests__/unique.test.ts | 60 + .../__tests__/update-css-variables.test.ts | 30 + .../shared/src/utils/__tests__/window.test.ts | 33 + packages/@core/base/shared/src/utils/cn.ts | 8 + packages/@core/base/shared/src/utils/diff.ts | 96 + packages/@core/base/shared/src/utils/dom.ts | 52 + packages/@core/base/shared/src/utils/index.ts | 13 + .../@core/base/shared/src/utils/inference.ts | 154 + .../@core/base/shared/src/utils/letter.ts | 47 + packages/@core/base/shared/src/utils/merge.ts | 1 + .../@core/base/shared/src/utils/nprogress.ts | 43 + packages/@core/base/shared/src/utils/to.ts | 21 + packages/@core/base/shared/src/utils/tree.ts | 97 + .../@core/base/shared/src/utils/unique.ts | 15 + .../shared/src/utils/update-css-variables.ts | 35 + .../@core/base/shared/src/utils/window.ts | 26 + packages/@core/base/shared/tsconfig.json | 6 + packages/@core/base/typings/build.config.ts | 7 + packages/@core/base/typings/package.json | 44 + packages/@core/base/typings/src/app.d.ts | 106 + packages/@core/base/typings/src/basic.d.ts | 33 + packages/@core/base/typings/src/helper.d.ts | 129 + packages/@core/base/typings/src/index.ts | 6 + .../@core/base/typings/src/menu-record.ts | 77 + packages/@core/base/typings/src/tabs.ts | 3 + .../@core/base/typings/src/vue-router.d.ts | 135 + packages/@core/base/typings/tsconfig.json | 6 + packages/@core/base/typings/vue-router.d.ts | 9 + packages/@core/composables/build.config.ts | 7 + packages/@core/composables/package.json | 47 + .../src/__tests__/use-sortable.test.ts | 48 + packages/@core/composables/src/index.ts | 11 + .../composables/src/use-content-style.ts | 59 + .../@core/composables/src/use-is-mobile.ts | 7 + .../@core/composables/src/use-namespace.ts | 106 + .../composables/src/use-priority-value.ts | 47 + .../@core/composables/src/use-sortable.ts | 36 + packages/@core/composables/tsconfig.json | 6 + packages/@core/preferences/build.config.ts | 7 + packages/@core/preferences/package.json | 37 + packages/@core/preferences/src/config.ts | 115 + packages/@core/preferences/src/constants.ts | 88 + packages/@core/preferences/src/index.ts | 35 + .../@core/preferences/src/preferences.test.ts | 253 + packages/@core/preferences/src/preferences.ts | 226 + packages/@core/preferences/src/types.ts | 279 + .../preferences/src/update-css-variables.ts | 117 + .../@core/preferences/src/use-preferences.ts | 216 + packages/@core/preferences/tsconfig.json | 6 + packages/@core/ui-kit/README.md | 3 + .../@core/ui-kit/layout-ui/build.config.ts | 21 + packages/@core/ui-kit/layout-ui/package.json | 47 + .../@core/ui-kit/layout-ui/postcss.config.mjs | 1 + .../ui-kit/layout-ui/src/components/index.ts | 5 + .../src/components/layout-content.vue | 60 + .../src/components/layout-footer.vue | 43 + .../src/components/layout-header.vue | 76 + .../src/components/layout-sidebar.vue | 305 + .../src/components/layout-tabbar.vue | 29 + .../layout-ui/src/components/widgets/index.ts | 2 + .../widgets/sidebar-collapse-button.vue | 19 + .../widgets/sidebar-fixed-button.vue | 19 + .../ui-kit/layout-ui/src/hooks/use-layout.ts | 41 + packages/@core/ui-kit/layout-ui/src/index.ts | 2 + .../@core/ui-kit/layout-ui/src/vben-layout.ts | 165 + .../ui-kit/layout-ui/src/vben-layout.vue | 561 + .../ui-kit/layout-ui/tailwind.config.mjs | 1 + packages/@core/ui-kit/layout-ui/tsconfig.json | 6 + packages/@core/ui-kit/menu-ui/README.md | 1 + packages/@core/ui-kit/menu-ui/build.config.ts | 33 + packages/@core/ui-kit/menu-ui/package.json | 48 + .../@core/ui-kit/menu-ui/postcss.config.mjs | 1 + .../src/components/collapse-transition.vue | 96 + .../ui-kit/menu-ui/src/components/index.ts | 3 + .../menu-ui/src/components/menu-item.vue | 121 + .../ui-kit/menu-ui/src/components/menu.vue | 848 + .../src/components/normal-menu/index.ts | 2 + .../src/components/normal-menu/normal-menu.ts | 27 + .../components/normal-menu/normal-menu.vue | 161 + .../src/components/sub-menu-content.vue | 105 + .../menu-ui/src/components/sub-menu.vue | 273 + .../@core/ui-kit/menu-ui/src/hooks/index.ts | 2 + .../menu-ui/src/hooks/use-menu-context.ts | 55 + .../ui-kit/menu-ui/src/hooks/use-menu.ts | 48 + packages/@core/ui-kit/menu-ui/src/index.ts | 3 + packages/@core/ui-kit/menu-ui/src/menu.vue | 38 + .../@core/ui-kit/menu-ui/src/sub-menu.vue | 69 + packages/@core/ui-kit/menu-ui/src/types.ts | 139 + .../@core/ui-kit/menu-ui/src/utils/index.ts | 51 + .../@core/ui-kit/menu-ui/tailwind.config.mjs | 1 + packages/@core/ui-kit/menu-ui/tsconfig.json | 6 + .../@core/ui-kit/popup-ui/build.config.ts | 21 + packages/@core/ui-kit/popup-ui/package.json | 47 + .../@core/ui-kit/popup-ui/postcss.config.mjs | 1 + .../src/drawer/__tests__/drawer-api.test.ts | 113 + .../ui-kit/popup-ui/src/drawer/drawer-api.ts | 128 + .../ui-kit/popup-ui/src/drawer/drawer.ts | 102 + .../ui-kit/popup-ui/src/drawer/drawer.vue | 184 + .../@core/ui-kit/popup-ui/src/drawer/index.ts | 3 + .../ui-kit/popup-ui/src/drawer/use-drawer.ts | 105 + packages/@core/ui-kit/popup-ui/src/index.ts | 2 + .../src/modal/__tests__/modal-api.test.ts | 112 + .../@core/ui-kit/popup-ui/src/modal/index.ts | 3 + .../ui-kit/popup-ui/src/modal/modal-api.ts | 134 + .../@core/ui-kit/popup-ui/src/modal/modal.ts | 127 + .../@core/ui-kit/popup-ui/src/modal/modal.vue | 257 + .../popup-ui/src/modal/use-modal-draggable.ts | 116 + .../ui-kit/popup-ui/src/modal/use-modal.ts | 101 + .../@core/ui-kit/popup-ui/tailwind.config.mjs | 1 + packages/@core/ui-kit/popup-ui/tsconfig.json | 6 + .../@core/ui-kit/shadcn-ui/build.config.ts | 33 + .../@core/ui-kit/shadcn-ui/components.json | 16 + packages/@core/ui-kit/shadcn-ui/package.json | 55 + .../@core/ui-kit/shadcn-ui/postcss.config.mjs | 1 + .../src/components/avatar/avatar.vue | 48 + .../shadcn-ui/src/components/avatar/index.ts | 1 + .../src/components/back-top/back-top.vue | 43 + .../src/components/back-top/backtop.ts | 38 + .../src/components/back-top/index.ts | 1 + .../src/components/back-top/use-backtop.ts | 45 + .../breadcrumb/breadcrumb-background.vue | 112 + .../src/components/breadcrumb/breadcrumb.vue | 110 + .../src/components/breadcrumb/index.ts | 4 + .../src/components/breadcrumb/types.ts | 11 + .../src/components/button/button.vue | 46 + .../src/components/button/icon-button.vue | 63 + .../shadcn-ui/src/components/button/index.ts | 2 + .../src/components/checkbox/checkbox.vue | 24 + .../src/components/checkbox/index.ts | 1 + .../components/context-menu/context-menu.vue | 95 + .../src/components/context-menu/index.ts | 3 + .../src/components/context-menu/interface.ts | 38 + .../count-to-animator/count-to-animator.vue | 111 + .../src/components/count-to-animator/index.ts | 1 + .../dropdown-menu/dropdown-menu.vue | 49 + .../dropdown-menu/dropdown-radio-menu.vue | 52 + .../src/components/dropdown-menu/index.ts | 4 + .../src/components/dropdown-menu/interface.ts | 32 + .../components/full-screen/full-screen.vue | 28 + .../src/components/full-screen/index.ts | 1 + .../src/components/hover-card/hover-card.vue | 57 + .../src/components/hover-card/index.ts | 2 + .../shadcn-ui/src/components/icon/icon.vue | 28 + .../shadcn-ui/src/components/icon/index.ts | 1 + .../ui-kit/shadcn-ui/src/components/index.ts | 46 + .../src/components/input-password/index.ts | 1 + .../input-password/input-password.vue | 52 + .../input-password/password-strength.vue | 66 + .../shadcn-ui/src/components/input/index.ts | 2 + .../shadcn-ui/src/components/input/input.vue | 53 + .../shadcn-ui/src/components/input/types.ts | 25 + .../shadcn-ui/src/components/link/index.ts | 1 + .../shadcn-ui/src/components/link/link.vue | 28 + .../shadcn-ui/src/components/logo/index.ts | 1 + .../shadcn-ui/src/components/logo/logo.vue | 64 + .../src/components/menu-badge/index.ts | 1 + .../components/menu-badge/menu-badge-dot.vue | 28 + .../src/components/menu-badge/menu-badge.vue | 57 + .../src/components/pin-input/index.ts | 3 + .../src/components/pin-input/input.vue | 86 + .../src/components/pin-input/types.ts | 38 + .../shadcn-ui/src/components/popover/index.ts | 1 + .../src/components/popover/popover.vue | 56 + .../src/components/render-content/index.ts | 1 + .../render-content/render-content.vue | 26 + .../src/components/scrollbar/index.ts | 1 + .../src/components/scrollbar/scrollbar.vue | 151 + .../src/components/segmented/index.ts | 3 + .../src/components/segmented/segmented.vue | 59 + .../components/segmented/tabs-indicator.vue | 39 + .../src/components/segmented/types.ts | 6 + .../shadcn-ui/src/components/spinner/index.ts | 2 + .../src/components/spinner/loading.vue | 137 + .../src/components/spinner/spinner.vue | 125 + .../shadcn-ui/src/components/swap/index.ts | 1 + .../shadcn-ui/src/components/swap/swap.vue | 126 + .../shadcn-ui/src/components/tooltip/index.ts | 1 + .../src/components/tooltip/tooltip.vue | 42 + .../src/components/ui/avatar/Avatar.vue | 27 + .../components/ui/avatar/AvatarFallback.vue | 11 + .../src/components/ui/avatar/AvatarImage.vue | 9 + .../src/components/ui/avatar/avatar.ts | 20 + .../src/components/ui/avatar/index.ts | 4 + .../src/components/ui/badge/Badge.vue | 18 + .../src/components/ui/badge/badge.ts | 23 + .../src/components/ui/badge/index.ts | 3 + .../components/ui/breadcrumb/Breadcrumb.vue | 13 + .../ui/breadcrumb/BreadcrumbEllipsis.vue | 24 + .../ui/breadcrumb/BreadcrumbItem.vue | 19 + .../ui/breadcrumb/BreadcrumbLink.vue | 24 + .../ui/breadcrumb/BreadcrumbList.vue | 22 + .../ui/breadcrumb/BreadcrumbPage.vue | 20 + .../ui/breadcrumb/BreadcrumbSeparator.vue | 23 + .../src/components/ui/breadcrumb/index.ts | 7 + .../src/components/ui/button/Button.vue | 30 + .../src/components/ui/button/button.ts | 42 + .../src/components/ui/button/index.ts | 3 + .../shadcn-ui/src/components/ui/card/Card.vue | 22 + .../src/components/ui/card/CardContent.vue | 15 + .../components/ui/card/CardDescription.vue | 15 + .../src/components/ui/card/CardFooter.vue | 15 + .../src/components/ui/card/CardHeader.vue | 15 + .../src/components/ui/card/CardTitle.vue | 15 + .../shadcn-ui/src/components/ui/card/index.ts | 6 + .../src/components/ui/checkbox/Checkbox.vue | 47 + .../src/components/ui/checkbox/index.ts | 1 + .../ui/context-menu/ContextMenu.vue | 18 + .../context-menu/ContextMenuCheckboxItem.vue | 46 + .../ui/context-menu/ContextMenuContent.vue | 42 + .../ui/context-menu/ContextMenuGroup.vue | 11 + .../ui/context-menu/ContextMenuItem.vue | 40 + .../ui/context-menu/ContextMenuLabel.vue | 32 + .../ui/context-menu/ContextMenuPortal.vue | 11 + .../ui/context-menu/ContextMenuRadioGroup.vue | 19 + .../ui/context-menu/ContextMenuRadioItem.vue | 46 + .../ui/context-menu/ContextMenuSeparator.vue | 27 + .../ui/context-menu/ContextMenuShortcut.vue | 19 + .../ui/context-menu/ContextMenuSub.vue | 19 + .../ui/context-menu/ContextMenuSubContent.vue | 39 + .../ui/context-menu/ContextMenuSubTrigger.vue | 43 + .../ui/context-menu/ContextMenuTrigger.vue | 17 + .../src/components/ui/context-menu/index.ts | 14 + .../src/components/ui/dialog/Dialog.vue | 19 + .../src/components/ui/dialog/DialogClose.vue | 11 + .../components/ui/dialog/DialogContent.vue | 77 + .../ui/dialog/DialogDescription.vue | 32 + .../src/components/ui/dialog/DialogFooter.vue | 20 + .../src/components/ui/dialog/DialogHeader.vue | 17 + .../ui/dialog/DialogScrollContent.vue | 67 + .../src/components/ui/dialog/DialogTitle.vue | 30 + .../components/ui/dialog/DialogTrigger.vue | 11 + .../src/components/ui/dialog/index.ts | 9 + .../ui/dropdown-menu/DropdownMenu.vue | 21 + .../DropdownMenuCheckboxItem.vue | 46 + .../ui/dropdown-menu/DropdownMenuContent.vue | 45 + .../ui/dropdown-menu/DropdownMenuGroup.vue | 11 + .../ui/dropdown-menu/DropdownMenuItem.vue | 38 + .../ui/dropdown-menu/DropdownMenuLabel.vue | 34 + .../dropdown-menu/DropdownMenuRadioGroup.vue | 19 + .../dropdown-menu/DropdownMenuRadioItem.vue | 47 + .../dropdown-menu/DropdownMenuSeparator.vue | 29 + .../ui/dropdown-menu/DropdownMenuShortcut.vue | 15 + .../ui/dropdown-menu/DropdownMenuSub.vue | 19 + .../dropdown-menu/DropdownMenuSubContent.vue | 39 + .../dropdown-menu/DropdownMenuSubTrigger.vue | 39 + .../ui/dropdown-menu/DropdownMenuTrigger.vue | 17 + .../src/components/ui/dropdown-menu/index.ts | 16 + .../components/ui/hover-card/HoverCard.vue | 19 + .../ui/hover-card/HoverCardContent.vue | 43 + .../ui/hover-card/HoverCardTrigger.vue | 11 + .../src/components/ui/hover-card/index.ts | 3 + .../src/components/ui/input/Input.vue | 34 + .../src/components/ui/input/index.ts | 1 + .../ui/number-field/NumberField.vue | 28 + .../ui/number-field/NumberFieldContent.vue | 22 + .../ui/number-field/NumberFieldDecrement.vue | 39 + .../ui/number-field/NumberFieldIncrement.vue | 39 + .../ui/number-field/NumberFieldInput.vue | 16 + .../src/components/ui/number-field/index.ts | 5 + .../src/components/ui/pin-input/PinInput.vue | 33 + .../components/ui/pin-input/PinInputGroup.vue | 25 + .../components/ui/pin-input/PinInputInput.vue | 34 + .../ui/pin-input/PinInputSeparator.vue | 15 + .../src/components/ui/pin-input/index.ts | 4 + .../src/components/ui/popover/Popover.vue | 16 + .../components/ui/popover/PopoverContent.vue | 50 + .../components/ui/popover/PopoverTrigger.vue | 11 + .../src/components/ui/popover/index.ts | 4 + .../components/ui/scroll-area/ScrollArea.vue | 49 + .../components/ui/scroll-area/ScrollBar.vue | 42 + .../src/components/ui/scroll-area/index.ts | 2 + .../src/components/ui/select/Select.vue | 16 + .../components/ui/select/SelectContent.vue | 67 + .../src/components/ui/select/SelectGroup.vue | 23 + .../src/components/ui/select/SelectItem.vue | 48 + .../components/ui/select/SelectItemText.vue | 11 + .../src/components/ui/select/SelectLabel.vue | 17 + .../ui/select/SelectScrollDownButton.vue | 37 + .../ui/select/SelectScrollUpButton.vue | 37 + .../components/ui/select/SelectSeparator.vue | 24 + .../components/ui/select/SelectTrigger.vue | 42 + .../src/components/ui/select/SelectValue.vue | 11 + .../src/components/ui/select/index.ts | 11 + .../src/components/ui/sheet/Sheet.vue | 19 + .../src/components/ui/sheet/SheetClose.vue | 11 + .../src/components/ui/sheet/SheetContent.vue | 58 + .../components/ui/sheet/SheetDescription.vue | 26 + .../src/components/ui/sheet/SheetFooter.vue | 20 + .../src/components/ui/sheet/SheetHeader.vue | 13 + .../src/components/ui/sheet/SheetTitle.vue | 26 + .../src/components/ui/sheet/SheetTrigger.vue | 11 + .../src/components/ui/sheet/index.ts | 10 + .../src/components/ui/sheet/sheet.ts | 22 + .../src/components/ui/switch/Switch.vue | 47 + .../src/components/ui/switch/index.ts | 1 + .../shadcn-ui/src/components/ui/tabs/Tabs.vue | 16 + .../src/components/ui/tabs/TabsContent.vue | 31 + .../src/components/ui/tabs/TabsList.vue | 31 + .../src/components/ui/tabs/TabsTrigger.vue | 33 + .../shadcn-ui/src/components/ui/tabs/index.ts | 5 + .../src/components/ui/toast/Toast.vue | 35 + .../src/components/ui/toast/ToastAction.vue | 31 + .../src/components/ui/toast/ToastClose.vue | 34 + .../components/ui/toast/ToastDescription.vue | 26 + .../src/components/ui/toast/ToastProvider.vue | 11 + .../src/components/ui/toast/ToastTitle.vue | 26 + .../src/components/ui/toast/ToastViewport.vue | 29 + .../src/components/ui/toast/Toaster.vue | 36 + .../src/components/ui/toast/index.ts | 11 + .../src/components/ui/toast/toast.ts | 29 + .../src/components/ui/toast/use-toast.ts | 168 + .../ui/toggle-group/ToggleGroup.vue | 48 + .../ui/toggle-group/ToggleGroupItem.vue | 51 + .../src/components/ui/toggle-group/index.ts | 2 + .../src/components/ui/toggle/Toggle.vue | 48 + .../src/components/ui/toggle/index.ts | 2 + .../src/components/ui/toggle/toggle.ts | 25 + .../src/components/ui/tooltip/Tooltip.vue | 19 + .../components/ui/tooltip/TooltipContent.vue | 52 + .../components/ui/tooltip/TooltipProvider.vue | 11 + .../components/ui/tooltip/TooltipTrigger.vue | 11 + .../src/components/ui/tooltip/index.ts | 4 + packages/@core/ui-kit/shadcn-ui/src/index.ts | 2 + .../ui-kit/shadcn-ui/tailwind.config.mjs | 1 + packages/@core/ui-kit/shadcn-ui/tsconfig.json | 12 + packages/@core/ui-kit/tabs-ui/build.config.ts | 21 + packages/@core/ui-kit/tabs-ui/package.json | 47 + .../@core/ui-kit/tabs-ui/postcss.config.mjs | 1 + .../ui-kit/tabs-ui/src/components/index.ts | 2 + .../src/components/tabs-chrome/tabs.vue | 187 + .../tabs-ui/src/components/tabs/tabs.vue | 128 + .../tabs-ui/src/components/widgets/index.ts | 3 + .../src/components/widgets/tool-more.vue | 18 + .../src/components/widgets/tool-refresh.vue | 31 + .../src/components/widgets/tool-screen.vue | 19 + packages/@core/ui-kit/tabs-ui/src/index.ts | 3 + .../@core/ui-kit/tabs-ui/src/tabs-view.vue | 95 + packages/@core/ui-kit/tabs-ui/src/types.ts | 64 + .../@core/ui-kit/tabs-ui/src/use-tabs-drag.ts | 110 + .../tabs-ui/src/use-tabs-view-scroll.ts | 194 + .../@core/ui-kit/tabs-ui/tailwind.config.mjs | 1 + packages/@core/ui-kit/tabs-ui/tsconfig.json | 6 + packages/color/package.json | 16 - packages/color/src/constant/index.ts | 2 - packages/color/src/constant/name.ts | 1579 -- packages/color/src/constant/palette.ts | 356 - packages/color/src/index.ts | 7 - packages/color/src/palette/antd.ts | 176 - packages/color/src/palette/index.ts | 45 - packages/color/src/palette/recommend.ts | 152 - packages/color/src/shared/colord.ts | 93 - packages/color/src/shared/index.ts | 2 - packages/color/src/shared/name.ts | 49 - packages/color/src/types/index.ts | 58 - packages/color/tsconfig.json | 20 - packages/common-utils/package.json | 15 - packages/common-utils/tsconfig.json | 20 - packages/constants/README.md | 19 + packages/constants/package.json | 25 + packages/constants/src/core.ts | 28 + packages/constants/src/index.ts | 2 + packages/constants/tsconfig.json | 6 + packages/effects/README.md | 10 + packages/effects/access/package.json | 29 + packages/effects/access/postcss.config.mjs | 1 + .../effects/access/src/access-control.vue | 47 + packages/effects/access/src/accessible.ts | 86 + packages/effects/access/src/directive.ts | 42 + packages/effects/access/src/index.ts | 4 + packages/effects/access/src/use-access.ts | 53 + packages/effects/access/tailwind.config.mjs | 1 + packages/effects/access/tsconfig.json | 6 + packages/effects/common-ui/package.json | 38 + packages/effects/common-ui/postcss.config.mjs | 1 + .../__tests__/ellipsis-text.test.ts | 46 + .../ellipsis-text/ellipsis-text.vue | 142 + .../src/components/ellipsis-text/index.ts | 1 + .../effects/common-ui/src/components/index.ts | 5 + .../components/page/__tests__/page.test.ts | 88 + .../common-ui/src/components/page/index.ts | 1 + .../common-ui/src/components/page/page.vue | 56 + packages/effects/common-ui/src/index.ts | 3 + .../effects/common-ui/src/ui/about/about.ts | 14 + .../effects/common-ui/src/ui/about/about.vue | 192 + .../effects/common-ui/src/ui/about/index.ts | 1 + .../src/ui/authentication/auth-title.vue | 13 + .../src/ui/authentication/code-login.vue | 157 + .../src/ui/authentication/forget-password.vue | 86 + .../common-ui/src/ui/authentication/index.ts | 11 + .../ui/authentication/login-expired-modal.vue | 64 + .../common-ui/src/ui/authentication/login.vue | 177 + .../src/ui/authentication/qrcode-login.vue | 68 + .../src/ui/authentication/register.vue | 168 + .../ui/authentication/third-party-login.vue | 36 + .../common-ui/src/ui/authentication/types.ts | 105 + .../analysis/analysis-chart-card.vue | 24 + .../analysis/analysis-charts-tabs.vue | 40 + .../dashboard/analysis/analysis-overview.vue | 55 + .../src/ui/dashboard/analysis/index.ts | 3 + .../common-ui/src/ui/dashboard/index.ts | 3 + .../common-ui/src/ui/dashboard/typing.ts | 46 + .../src/ui/dashboard/workbench/index.ts | 5 + .../dashboard/workbench/workbench-header.vue | 46 + .../dashboard/workbench/workbench-project.vue | 60 + .../workbench/workbench-quick-nav.vue | 51 + .../ui/dashboard/workbench/workbench-todo.vue | 63 + .../dashboard/workbench/workbench-trends.vue | 64 + .../common-ui/src/ui/fallback/fallback.ts | 25 + .../common-ui/src/ui/fallback/fallback.vue | 163 + .../src/ui/fallback/icons/icon-403.vue | 151 + .../src/ui/fallback/icons/icon-404.vue | 154 + .../src/ui/fallback/icons/icon-500.vue | 215 + .../ui/fallback/icons/icon-coming-soon.vue | 262 + .../src/ui/fallback/icons/icon-offline.vue | 112 + .../src/ui/fallback/icons/warning.svg | 1 + .../common-ui/src/ui/fallback/index.ts | 2 + packages/effects/common-ui/src/ui/index.ts | 4 + .../effects/common-ui/tailwind.config.mjs | 1 + packages/effects/common-ui/tsconfig.json | 6 + packages/effects/hooks/README.md | 19 + packages/effects/hooks/package.json | 32 + packages/effects/hooks/src/index.ts | 7 + packages/effects/hooks/src/use-app-config.ts | 23 + .../effects/hooks/src/use-content-maximize.ts | 24 + .../effects/hooks/src/use-design-tokens.ts | 235 + packages/effects/hooks/src/use-refresh.ts | 16 + packages/effects/hooks/src/use-tabs.ts | 113 + packages/effects/hooks/src/use-watermark.ts | 88 + packages/effects/hooks/tsconfig.json | 9 + packages/effects/layouts/package.json | 40 + packages/effects/layouts/postcss.config.mjs | 1 + .../src/authentication/authentication.vue | 118 + .../layouts/src/authentication/form.vue | 41 + .../src/authentication/icons/slogan.vue | 4568 ++++ .../layouts/src/authentication/index.ts | 1 + .../layouts/src/authentication/toolbar.vue | 46 + packages/effects/layouts/src/basic/README.md | 7 + .../src/basic/content/content-spinner.vue | 16 + .../layouts/src/basic/content/content.vue | 107 + .../layouts/src/basic/content/index.ts | 2 + .../src/basic/content/use-content-spinner.ts | 50 + .../layouts/src/basic/copyright/copyright.vue | 48 + .../layouts/src/basic/copyright/index.ts | 1 + .../layouts/src/basic/footer/footer.vue | 11 + .../effects/layouts/src/basic/footer/index.ts | 1 + .../layouts/src/basic/header/header.vue | 149 + .../effects/layouts/src/basic/header/index.ts | 1 + packages/effects/layouts/src/basic/index.ts | 1 + packages/effects/layouts/src/basic/layout.vue | 336 + .../layouts/src/basic/menu/extra-menu.vue | 40 + .../effects/layouts/src/basic/menu/index.ts | 5 + .../effects/layouts/src/basic/menu/menu.vue | 37 + .../layouts/src/basic/menu/mixed-menu.vue | 44 + .../layouts/src/basic/menu/use-extra-menu.ts | 109 + .../layouts/src/basic/menu/use-mixed-menu.ts | 129 + .../layouts/src/basic/menu/use-navigation.ts | 19 + .../effects/layouts/src/basic/tabbar/index.ts | 2 + .../layouts/src/basic/tabbar/tabbar.vue | 81 + .../layouts/src/basic/tabbar/use-tabbar.ts | 220 + .../layouts/src/iframe/iframe-router-view.vue | 85 + .../layouts/src/iframe/iframe-view.vue | 10 + packages/effects/layouts/src/iframe/index.ts | 2 + packages/effects/layouts/src/index.ts | 4 + .../layouts/src/widgets/breadcrumb.vue | 79 + .../widgets/check-updates/check-updates.vue | 134 + .../src/widgets/check-updates/index.ts | 1 + .../layouts/src/widgets/color-toggle.vue | 62 + .../widgets/global-search/global-search.vue | 147 + .../src/widgets/global-search/index.ts | 1 + .../widgets/global-search/search-panel.vue | 282 + packages/effects/layouts/src/widgets/index.ts | 11 + .../layouts/src/widgets/language-toggle.vue | 37 + .../layouts/src/widgets/layout-toggle.vue | 61 + .../layouts/src/widgets/lock-screen/index.ts | 2 + .../widgets/lock-screen/lock-screen-modal.vue | 103 + .../src/widgets/lock-screen/lock-screen.vue | 171 + .../layouts/src/widgets/notification/index.ts | 3 + .../src/widgets/notification/notification.vue | 180 + .../layouts/src/widgets/notification/types.ts | 9 + .../src/widgets/preferences/blocks/block.vue | 22 + .../preferences/blocks/general/animation.vue | 51 + .../preferences/blocks/general/general.vue | 31 + .../src/widgets/preferences/blocks/index.ts | 19 + .../widgets/preferences/blocks/input-item.vue | 51 + .../preferences/blocks/layout/breadcrumb.vue | 56 + .../preferences/blocks/layout/content.vue | 51 + .../preferences/blocks/layout/copyright.vue | 48 + .../preferences/blocks/layout/footer.vue | 21 + .../preferences/blocks/layout/header.vue | 49 + .../preferences/blocks/layout/layout.vue | 95 + .../preferences/blocks/layout/navigation.vue | 45 + .../preferences/blocks/layout/sidebar.vue | 43 + .../preferences/blocks/layout/tabbar.vue | 72 + .../preferences/blocks/layout/widget.vue | 67 + .../preferences/blocks/number-field-item.vue | 65 + .../preferences/blocks/select-item.vue | 67 + .../blocks/shortcut-keys/global.vue | 50 + .../preferences/blocks/switch-item.vue | 47 + .../preferences/blocks/theme/builtin.vue | 141 + .../preferences/blocks/theme/color-mode.vue | 26 + .../preferences/blocks/theme/radius.vue | 38 + .../preferences/blocks/theme/theme.vue | 83 + .../preferences/blocks/toggle-item.vue | 44 + .../preferences/icons/content-compact.vue | 119 + .../preferences/icons/full-content.vue | 50 + .../widgets/preferences/icons/header-nav.vue | 119 + .../src/widgets/preferences/icons/index.ts | 10 + .../widgets/preferences/icons/mixed-nav.vue | 161 + .../src/widgets/preferences/icons/setting.vue | 12 + .../preferences/icons/sidebar-mixed-nav.vue | 173 + .../widgets/preferences/icons/sidebar-nav.vue | 153 + .../layouts/src/widgets/preferences/index.ts | 3 + .../preferences/preferences-button.vue | 19 + .../preferences/preferences-drawer.vue | 421 + .../src/widgets/preferences/preferences.vue | 71 + .../preferences/use-open-preferences.ts | 16 + .../layouts/src/widgets/theme-toggle/index.ts | 1 + .../src/widgets/theme-toggle/theme-button.vue | 185 + .../src/widgets/theme-toggle/theme-toggle.vue | 82 + .../src/widgets/user-dropdown/index.ts | 1 + .../widgets/user-dropdown/user-dropdown.vue | 228 + packages/effects/layouts/tailwind.config.mjs | 1 + packages/effects/layouts/tsconfig.json | 6 + packages/effects/plugins/README.md | 28 + packages/effects/plugins/package.json | 28 + .../plugins/src/echarts/echarts-ui.vue | 15 + .../effects/plugins/src/echarts/echarts.ts | 59 + packages/effects/plugins/src/echarts/index.ts | 3 + .../plugins/src/echarts/use-echarts.ts | 113 + packages/effects/plugins/tsconfig.json | 6 + packages/effects/request/package.json | 30 + packages/effects/request/src/index.ts | 2 + .../request/src/request-client/index.ts | 3 + .../request-client/modules/downloader.test.ts | 84 + .../src/request-client/modules/downloader.ts | 30 + .../src/request-client/modules/interceptor.ts | 40 + .../request-client/modules/uploader.test.ts | 118 + .../src/request-client/modules/uploader.ts | 32 + .../src/request-client/preset-interceptors.ts | 134 + .../src/request-client/request-client.test.ts | 97 + .../src/request-client/request-client.ts | 131 + .../request/src/request-client/types.ts | 50 + packages/effects/request/tsconfig.json | 6 + packages/hooks/package.json | 15 - packages/hooks/src/index.ts | 11 - packages/hooks/src/use-boolean.ts | 31 - packages/hooks/src/use-context.ts | 96 - packages/hooks/src/use-count-down.ts | 49 - packages/hooks/src/use-loading.ts | 16 - packages/hooks/src/use-signal.ts | 144 - packages/hooks/src/use-svg-icon-render.ts | 50 - packages/hooks/src/use-table.ts | 151 - packages/hooks/tsconfig.json | 20 - packages/icons/README.md | 19 + packages/icons/package.json | 22 + packages/icons/src/iconify/index.ts | 54 + packages/icons/src/index.ts | 2 + packages/icons/src/svg/icons/avatar-1.svg | 1 + packages/icons/src/svg/icons/avatar-2.svg | 1 + packages/icons/src/svg/icons/avatar-3.svg | 1 + packages/icons/src/svg/icons/avatar-4.svg | 1 + packages/icons/src/svg/icons/bell.svg | 1 + packages/icons/src/svg/icons/cake.svg | 1 + packages/icons/src/svg/icons/card.svg | 1 + packages/icons/src/svg/icons/download.svg | 1 + packages/icons/src/svg/index.ts | 23 + packages/icons/src/svg/load.ts | 59 + packages/icons/tsconfig.json | 6 + packages/locales/package.json | 27 + packages/locales/src/i18n.ts | 91 + packages/locales/src/index.ts | 15 + packages/locales/src/langs/en-US.json | 308 + packages/locales/src/langs/zh-CN.json | 308 + packages/locales/src/typing.ts | 25 + packages/locales/tsconfig.json | 6 + packages/materials/package.json | 19 - packages/materials/src/index.ts | 6 - .../src/libs/admin-layout/index.module.css | 63 - .../libs/admin-layout/index.module.css.d.ts | 18 - .../materials/src/libs/admin-layout/index.ts | 5 - .../materials/src/libs/admin-layout/index.vue | 200 - .../materials/src/libs/admin-layout/shared.ts | 68 - .../src/libs/page-tab/button-tab.vue | 53 - .../src/libs/page-tab/chrome-tab-bg.vue | 31 - .../src/libs/page-tab/chrome-tab.vue | 58 - .../src/libs/page-tab/index.module.css | 97 - .../src/libs/page-tab/index.module.css.d.ts | 15 - packages/materials/src/libs/page-tab/index.ts | 3 - .../materials/src/libs/page-tab/index.vue | 85 - .../materials/src/libs/page-tab/shared.ts | 31 - .../materials/src/libs/page-tab/svg-close.vue | 18 - .../src/libs/simple-scrollbar/index.ts | 3 - .../src/libs/simple-scrollbar/index.vue | 18 - packages/materials/src/types/index.ts | 294 - packages/materials/tsconfig.json | 20 - packages/ofetch/package.json | 15 - packages/ofetch/src/index.ts | 10 - packages/ofetch/tsconfig.json | 20 - packages/plugin-render-naive/.eslintrc.js | 31 - packages/plugin-render-naive/.gitignore | 24 - packages/plugin-render-naive/LICENSE | 21 - packages/plugin-render-naive/README.md | 151 - packages/plugin-render-naive/gulpfile.js | 125 - packages/plugin-render-naive/package.json | 73 - .../src/form-design/checkbox-widget.ts | 164 - .../src/form-design/date-picker-widget.ts | 144 - .../src/form-design/index.ts | 101 - .../src/form-design/input-widget.ts | 144 - .../src/form-design/number-input-widget.ts | 144 - .../src/form-design/radio-widget.ts | 164 - .../src/form-design/select-widget.ts | 156 - .../src/form-design/switch-widget.ts | 140 - .../src/form-design/textarea-widget.ts | 148 - .../src/form-design/use.ts | 255 - .../plugin-render-naive/src/form/index.ts | 244 - packages/plugin-render-naive/src/index.ts | 71 - .../plugin-render-naive/src/table/index.ts | 545 - packages/plugin-render-naive/style.scss | 131 - packages/plugin-render-naive/tsconfig.json | 17 - packages/plugin-render-naive/types/index.d.ts | 12 - packages/preferences/package.json | 26 + packages/preferences/src/index.ts | 70 + packages/preferences/tsconfig.json | 6 + packages/scripts/bin.ts | 3 - packages/scripts/package.json | 27 - packages/scripts/src/commands/changelog.ts | 10 - packages/scripts/src/commands/cleanup.ts | 5 - packages/scripts/src/commands/git-commit.ts | 86 - packages/scripts/src/commands/index.ts | 6 - packages/scripts/src/commands/release.ts | 12 - packages/scripts/src/commands/router.ts | 90 - packages/scripts/src/commands/update-dict.ts | 5 - packages/scripts/src/commands/update-pkg.ts | 5 - packages/scripts/src/config/index.ts | 55 - packages/scripts/src/index.ts | 107 - packages/scripts/src/shared/index.ts | 7 - packages/scripts/src/types/index.ts | 33 - packages/scripts/tsconfig.json | 20 - packages/stores/package.json | 30 + packages/stores/shim-pinia.d.ts | 9 + packages/stores/src/index.ts | 3 + packages/stores/src/modules/access.test.ts | 46 + packages/stores/src/modules/access.ts | 85 + packages/stores/src/modules/index.ts | 4 + packages/stores/src/modules/lock.test.ts | 32 + packages/stores/src/modules/lock.ts | 33 + packages/stores/src/modules/tabbar.test.ts | 296 + packages/stores/src/modules/tabbar.ts | 539 + packages/stores/src/modules/user.test.ts | 37 + packages/stores/src/modules/user.ts | 63 + packages/stores/src/setup.ts | 44 + packages/stores/tsconfig.json | 5 + packages/styles/README.md | 19 + packages/styles/package.json | 31 + packages/styles/src/antd/index.css | 13 + packages/styles/src/ele/index.css | 3 + packages/styles/src/global/index.scss | 1 + packages/styles/src/index.ts | 1 + packages/styles/tsconfig.json | 6 + packages/types/README.md | 20 + packages/types/global.d.ts | 22 + packages/types/package.json | 27 + packages/types/src/index.ts | 2 + packages/types/src/user.d.ts | 20 + packages/types/tsconfig.json | 6 + packages/uno-preset/package.json | 12 - packages/uno-preset/src/index.ts | 55 - packages/uno-preset/tsconfig.json | 20 - packages/utils/README.md | 19 + packages/utils/package.json | 36 +- packages/utils/src/crypto.ts | 27 - .../__tests__/find-menu-by-path.test.ts | 88 + .../helpers/__tests__/generate-menus.test.ts | 238 + .../generate-routes-frontend.test.ts | 105 + .../__tests__/merge-route-modules.test.ts | 68 + .../utils/src/helpers/find-menu-by-path.ts | 37 + packages/utils/src/helpers/generate-menus.ts | 80 + .../src/helpers/generate-routes-backend.ts | 82 + .../src/helpers/generate-routes-frontend.ts | 58 + .../utils/src/helpers/get-popup-container.ts | 6 + packages/utils/src/helpers/index.ts | 8 + .../utils/src/helpers/merge-route-modules.ts | 28 + packages/utils/src/helpers/reset-routes.ts | 31 + .../src/helpers/unmount-global-loading.ts | 31 + packages/utils/src/index.ts | 6 +- packages/utils/src/nanoid.ts | 3 - packages/utils/src/storage.ts | 76 - packages/utils/tsconfig.json | 21 +- playground/.env | 5 + playground/.env.analyze | 7 + playground/.env.development | 16 + playground/.env.production | 16 + playground/index.html | 35 + playground/package.json | 50 + playground/postcss.config.mjs | 1 + playground/public/favicon.ico | Bin 0 -> 5430 bytes playground/src/api/core/auth.ts | 55 + playground/src/api/core/index.ts | 3 + playground/src/api/core/menu.ts | 10 + playground/src/api/core/user.ts | 10 + playground/src/api/demos/index.ts | 1 + playground/src/api/demos/status.ts | 10 + playground/src/api/index.ts | 2 + playground/src/api/request.ts | 105 + playground/src/app.vue | 39 + playground/src/bootstrap.ts | 31 + playground/src/layouts/basic.vue | 143 + playground/src/layouts/index.ts | 8 + playground/src/locales/README.md | 3 + playground/src/locales/index.ts | 94 + playground/src/locales/langs/en-US.json | 77 + playground/src/locales/langs/zh-CN.json | 77 + playground/src/main.ts | 31 + playground/src/preferences.ts | 12 + playground/src/router/access.ts | 42 + playground/src/router/guard.ts | 136 + playground/src/router/index.ts | 32 + playground/src/router/routes/core.ts | 86 + playground/src/router/routes/index.ts | 31 + .../src/router/routes/modules/dashboard.ts | 39 + playground/src/router/routes/modules/demos.ts | 512 + .../src/router/routes/modules/examples.ts | 46 + playground/src/router/routes/modules/vben.ts | 90 + playground/src/store/auth.ts | 114 + playground/src/store/index.ts | 1 + playground/src/views/_core/README.md | 3 + playground/src/views/_core/about/index.vue | 9 + .../views/_core/authentication/code-login.vue | 30 + .../_core/authentication/forget-password.vue | 23 + .../src/views/_core/authentication/login.vue | 18 + .../_core/authentication/qrcode-login.vue | 10 + .../views/_core/authentication/register.vue | 25 + .../src/views/_core/fallback/coming-soon.vue | 7 + .../src/views/_core/fallback/forbidden.vue | 9 + .../views/_core/fallback/internal-error.vue | 9 + .../src/views/_core/fallback/not-found.vue | 9 + .../src/views/_core/fallback/offline.vue | 9 + .../dashboard/analytics/analytics-trends.vue | 82 + .../analytics/analytics-visits-data.vue | 84 + .../analytics/analytics-visits-sales.vue | 48 + .../analytics/analytics-visits-source.vue | 67 + .../dashboard/analytics/analytics-visits.vue | 57 + .../src/views/dashboard/analytics/index.vue | 90 + .../src/views/dashboard/workspace/index.vue | 225 + .../src/views/demos/access/admin-visible.vue | 11 + .../src/views/demos/access/button-control.vue | 157 + playground/src/views/demos/access/index.vue | 98 + .../views/demos/access/menu-visible-403.vue | 11 + .../src/views/demos/access/super-visible.vue | 11 + .../src/views/demos/access/user-visible.vue | 11 + .../src/views/demos/active-icon/index.vue | 11 + playground/src/views/demos/badge/index.vue | 7 + .../views/demos/breadcrumb/lateral-detail.vue | 21 + .../src/views/demos/breadcrumb/lateral.vue | 25 + .../views/demos/breadcrumb/level-detail.vue | 11 + .../views/demos/features/clipboard/index.vue | 25 + .../demos/features/full-screen/index.vue | 47 + .../features/hide-menu-children/children.vue | 3 + .../features/hide-menu-children/parent.vue | 11 + .../src/views/demos/features/icons/index.vue | 61 + .../demos/features/login-expired/index.vue | 39 + .../src/views/demos/features/tabs/index.vue | 105 + .../views/demos/features/tabs/tab-detail.vue | 23 + .../views/demos/features/watermark/index.vue | 66 + playground/src/views/demos/nested/menu-1.vue | 7 + .../src/views/demos/nested/menu-2-1.vue | 7 + .../src/views/demos/nested/menu-3-1.vue | 7 + .../src/views/demos/nested/menu-3-2-1.vue | 7 + playground/src/views/examples/doc-button.vue | 16 + .../examples/drawer/auto-height-demo.vue | 47 + .../src/views/examples/drawer/base-demo.vue | 24 + .../views/examples/drawer/dynamic-demo.vue | 31 + .../src/views/examples/drawer/index.vue | 93 + .../examples/drawer/shared-data-demo.vue | 29 + .../src/views/examples/ellipsis/index.vue | 41 + .../views/examples/modal/auto-height-demo.vue | 46 + .../src/views/examples/modal/base-demo.vue | 20 + .../src/views/examples/modal/drag-demo.vue | 19 + .../src/views/examples/modal/dynamic-demo.vue | 41 + playground/src/views/examples/modal/index.vue | 108 + .../views/examples/modal/shared-data-demo.vue | 29 + playground/tailwind.config.mjs | 1 + playground/tsconfig.json | 12 + playground/tsconfig.node.json | 10 + playground/vite.config.mts | 20 + pnpm-lock.yaml | 22202 ++++++++++------ pnpm-workspace.yaml | 12 + scripts/turbo-run/README.md | 3 + scripts/turbo-run/bin/turbo-run.mjs | 3 + scripts/turbo-run/build.config.ts | 7 + scripts/turbo-run/package.json | 29 + scripts/turbo-run/src/index.ts | 29 + scripts/turbo-run/src/run.ts | 65 + scripts/turbo-run/tsconfig.json | 6 + scripts/vsh/README.md | 3 + scripts/vsh/bin/vsh.mjs | 3 + scripts/vsh/build.config.ts | 7 + scripts/vsh/package.json | 31 + scripts/vsh/src/check-circular/index.ts | 80 + scripts/vsh/src/check-dep/index.ts | 85 + scripts/vsh/src/clean/index.ts | 88 + scripts/vsh/src/code-workspace/index.ts | 78 + scripts/vsh/src/index.ts | 45 + scripts/vsh/src/lint/index.ts | 49 + scripts/vsh/src/publint/index.ts | 185 + scripts/vsh/tsconfig.json | 6 + src/App.vue | 63 - src/api/apiDefinitions.ts | 198 - src/api/createApis.ts | 78 - src/api/globals.d.ts | 11022 -------- src/api/index.ts | 189 - src/api/office/bussiness-trip.ts | 12 - src/api/office/canteen.ts | 78 - src/api/office/duty.ts | 27 - src/api/office/meeting.ts | 21 - src/api/office/supervise.ts | 35 - src/api/office/supplies.ts | 33 - src/api/request/utils.ts | 0 src/api/system/auth.ts | 16 - src/api/system/dept.ts | 4 - src/api/system/dict.ts | 20 - src/api/system/file.ts | 26 - src/api/system/menu.ts | 34 - src/api/system/user.ts | 7 - src/assets/imgs/soybean.jpg | Bin 114241 -> 0 bytes src/assets/logo.png | Bin 137972 -> 0 bytes src/assets/meeting/bg35.jpg | Bin 797 -> 0 bytes src/assets/svg-icon/activity.svg | 1 - src/assets/svg-icon/at-sign.svg | 1 - src/assets/svg-icon/avatar.svg | 1 - src/assets/svg-icon/banner.svg | 1 - src/assets/svg-icon/cast.svg | 1 - src/assets/svg-icon/chrome.svg | 1 - src/assets/svg-icon/copy.svg | 1 - src/assets/svg-icon/custom-icon.svg | 1 - src/assets/svg-icon/empty-data.svg | 1 - src/assets/svg-icon/expectation.svg | 1 - src/assets/svg-icon/heart.svg | 1 - src/assets/svg-icon/logo.svg | 8 - src/assets/svg-icon/network-error.svg | 1 - src/assets/svg-icon/no-icon.svg | 1 - src/assets/svg-icon/no-permission.svg | 1 - src/assets/svg-icon/not-found.svg | 1 - src/assets/svg-icon/service-error.svg | 1 - src/assets/svg-icon/wind.svg | 1 - src/common/unit.ts | 62 - src/components/DetailModal/index.ts | 4 - .../DetailModal/src/DetailModal.vue | 73 - src/components/DictTag/index.ts | 4 - src/components/DictTag/src/DictTag.vue | 151 - src/components/Form/index.ts | 4 - src/components/Form/src/BasicForm.vue | 343 - src/components/Form/src/helper.ts | 42 - src/components/Form/src/hooks/useForm.ts | 94 - .../Form/src/hooks/useFormContext.ts | 11 - .../Form/src/hooks/useFormEvents.ts | 116 - .../Form/src/hooks/useFormValues.ts | 49 - src/components/Form/src/props.ts | 82 - src/components/Form/src/types/form.ts | 62 - src/components/Form/src/types/index.ts | 31 - src/components/Lockscreen/Lockscreen.vue | 304 - src/components/Lockscreen/Recharge.vue | 164 - src/components/Lockscreen/index.ts | 3 - src/components/Modal/index.ts | 3 - src/components/Modal/src/basicModal.vue | 108 - src/components/Modal/src/hooks/useModal.ts | 62 - src/components/Modal/src/props.ts | 30 - src/components/Modal/src/type/index.ts | 20 - src/components/Table/index.ts | 3 - .../Table/src/components/TableImg.vue | 88 - src/components/VxeTable/src/VxeBasicTable.tsx | 0 .../advanced/table-column-setting.vue | 35 - .../advanced/table-header-operation.vue | 74 - src/components/common/api-select.vue | 120 - src/components/common/api-tree-select.vue | 94 - src/components/common/app-provider.vue | 39 - src/components/common/dark-mode-container.vue | 17 - src/components/common/exception-base.vue | 50 - src/components/common/full-screen.vue | 22 - src/components/common/lang-switch.vue | 49 - src/components/common/menu-toggler.vue | 52 - src/components/common/pin-toggler.vue | 26 - src/components/common/reload-button.vue | 21 - src/components/common/system-logo.vue | 27 - src/components/common/theme-schema-switch.vue | 56 - src/components/custom/better-scroll.vue | 53 - src/components/custom/button-icon.vue | 80 - src/components/custom/count-to.vue | 88 - src/components/custom/look-forward.vue | 20 - src/components/custom/seal.vue | 167 - src/components/custom/soybean-avatar.vue | 13 - src/components/custom/svg-icon.vue | 54 - src/components/custom/wave-bg.vue | 53 - src/constants/app.ts | 52 - src/constants/business.ts | 29 - src/constants/common.ts | 8 - src/constants/reg.ts | 25 - src/enums/breakpointEnum.ts | 28 - src/enums/cacheEnum.ts | 20 - src/enums/httpEnum.ts | 34 - src/enums/index.ts | 16 - src/enums/pageEnum.ts | 14 - src/enums/permissionsEnum.ts | 4 - src/enums/roleEnum.ts | 7 - src/enums/systemMessageEnum.ts | 239 - src/env.d.ts | 3 - src/hooks/business/auth.ts | 21 - src/hooks/business/captcha.ts | 71 - src/hooks/common/alova.ts | 0 src/hooks/common/echarts.ts | 235 - src/hooks/common/form.ts | 97 - src/hooks/common/icon.ts | 10 - src/hooks/common/router.ts | 102 - src/hooks/common/table.ts | 249 - src/layouts/base-layout/index.vue | 146 - src/layouts/blank-layout/index.vue | 13 - src/layouts/context/index.ts | 47 - .../modules/global-breadcrumb/index.vue | 47 - src/layouts/modules/global-content/index.vue | 50 - src/layouts/modules/global-footer/index.vue | 15 - .../global-header/components/message-list.vue | 90 - .../components/system-message.vue | 127 - .../global-header/components/theme-button.vue | 20 - .../global-header/components/todo-message.vue | 40 - .../global-header/components/user-avatar.vue | 90 - src/layouts/modules/global-header/index.vue | 74 - src/layouts/modules/global-logo/index.vue | 27 - src/layouts/modules/global-menu/base-menu.vue | 96 - .../modules/global-menu/first-level-menu.vue | 106 - .../global-menu/horizontal-mix-menu.vue | 28 - .../modules/global-menu/vertical-mix-menu.vue | 72 - .../components/search-footer.vue | 36 - .../global-search/components/search-modal.vue | 123 - .../components/search-result.vue | 56 - src/layouts/modules/global-search/index.vue | 18 - src/layouts/modules/global-sider/index.vue | 40 - .../modules/global-tab/context-menu.vue | 123 - src/layouts/modules/global-tab/index.vue | 205 - .../components/layout-mode-card.vue | 94 - .../theme-drawer/components/setting-item.vue | 24 - src/layouts/modules/theme-drawer/index.vue | 31 - .../theme-drawer/modules/config-operation.vue | 58 - .../theme-drawer/modules/dark-mode.vue | 69 - .../theme-drawer/modules/layout-mode.vue | 69 - .../modules/theme-drawer/modules/page-fun.vue | 122 - .../theme-drawer/modules/theme-color.vue | 78 - src/locales/dayjs.ts | 20 - src/locales/index.ts | 26 - src/locales/langs/en-us.ts | 478 - src/locales/langs/zh-cn.ts | 478 - src/locales/locale.ts | 9 - src/locales/naive.ts | 12 - src/main.ts | 79 - src/plugins/assets.ts | 3 - src/plugins/dayjs.ts | 9 - src/plugins/iconify.ts | 12 - src/plugins/index.ts | 4 - src/plugins/loading.ts | 45 - src/plugins/naive.ts | 148 - src/plugins/nprogress.ts | 9 - src/router/elegant/imports.ts | 86 - src/router/elegant/routes.ts | 992 - src/router/elegant/transform.ts | 291 - src/router/guard/index.ts | 15 - src/router/guard/progress.ts | 11 - src/router/guard/route.ts | 198 - src/router/guard/title.ts | 13 - src/router/index.ts | 30 - src/router/routes/builtin.ts | 31 - src/router/routes/index.ts | 41 - src/router/routes/router.data.ts | 159 - src/settings/encryptionSetting.ts | 13 - src/store/index.ts | 16 - src/store/modules/app/index.ts | 165 - src/store/modules/notification.ts | 108 - src/store/modules/route/index.ts | 615 - src/store/modules/route/shared.ts | 321 - src/store/modules/tab/index.ts | 325 - src/store/modules/tab/shared.ts | 251 - src/store/modules/theme/index.ts | 194 - src/store/modules/theme/shared.ts | 259 - src/store/modules/user.ts | 242 - src/store/mutation-types.ts | 12 - src/store/plugins/index.ts | 22 - src/styles/css/global.css | 22 - src/styles/css/nprogress.css | 83 - src/styles/css/reset.css | 377 - src/styles/css/transition.css | 82 - src/styles/scss/global.scss | 1 - src/styles/scss/scrollbar.scss | 21 - src/theme/settings.ts | 57 - src/theme/vars.ts | 35 - src/types/api.d.ts | 222 - src/types/app.d.ts | 698 - src/types/common.d.ts | 25 - src/types/components.d.ts | 140 - src/types/elegant-router.d.ts | 332 - src/types/env.d.ts | 107 - src/types/global.d.ts | 72 - src/types/naive-ui.d.ts | 53 - src/types/router.d.ts | 67 - src/types/storage.d.ts | 41 - src/types/store.d.ts | 0 src/types/union-key.d.ts | 149 - src/typings/elegant-router.d.ts | 442 - src/utils/alova.ts | 14 - src/utils/cache/index.ts | 32 - src/utils/cache/memory.ts | 107 - src/utils/cache/persistent.ts | 134 - src/utils/cache/storageCache.ts | 109 - src/utils/cipher.ts | 159 - src/utils/common.ts | 58 - src/utils/drag.ts | 98 - src/utils/env.ts | 36 - src/utils/file.ts | 139 - src/utils/icon.ts | 9 - src/utils/is.ts | 128 - src/utils/logger.ts | 58 - src/utils/propTypes.ts | 34 - src/utils/service.ts | 73 - src/utils/storage.ts | 9 - src/utils/vxeTable.ts | 60 - src/views/_builtin/403/index.vue | 7 - src/views/_builtin/404/index.vue | 7 - src/views/_builtin/500/index.vue | 7 - src/views/_builtin/iframe-page/[url].vue | 25 - src/views/_builtin/login/index.vue | 93 - .../_builtin/login/modules/bind-wechat.vue | 11 - .../_builtin/login/modules/code-login.vue | 66 - .../_builtin/login/modules/pwd-login.vue | 124 - src/views/_builtin/login/modules/register.vue | 88 - .../_builtin/login/modules/reset-pwd.vue | 82 - src/views/about/index.vue | 85 - src/views/bussiness-trip/edit/[id].vue | 425 - .../bussiness-trip/home/TripAuditModal.vue | 252 - .../bussiness-trip/home/TripEditModal.vue | 473 - .../home/components/AuditDone.vue | 205 - .../home/components/AuditTodo.vue | 180 - src/views/bussiness-trip/home/index.vue | 192 - src/views/bussiness-trip/todo/index.vue | 158 - src/views/bussiness-trip/todo/schema.ts | 39 - src/views/canteen/collect/index.vue | 182 - .../personal-statistics.vue | 241 - .../components/personal-statistics/schema.ts | 104 - .../components/auto-people/AutoPeople.vue | 226 - .../auto-people/AutoPeopleBatchAddModal.vue | 272 - .../auto-people/AutoPeopleEditModal.vue | 141 - .../basic-settings/BasicSettings.vue | 233 - .../delivery-address/delivery-address.vue | 250 - .../components/delivery-address/schema.ts | 30 - .../duty-people/AutoPeopleBatchAddModal.vue | 312 - .../duty-people/AutoPeopleEditModal.vue | 163 - .../components/duty-people/duty-people.vue | 222 - .../config/components/duty-people/schema.ts | 48 - src/views/canteen/config/index.vue | 136 - src/views/canteen/menu/MenuEditModal.vue | 232 - src/views/canteen/menu/index.vue | 136 - .../canteen/menu/modules/ChooseMenuModal.vue | 182 - src/views/canteen/menu/modules/MenuCard.vue | 59 - src/views/canteen/menu/schema.ts | 75 - src/views/canteen/orderfood/index.vue | 602 - src/views/canteen/recipe/RecipeEditModal.vue | 226 - src/views/canteen/recipe/RecipeSyncModal.vue | 490 - .../canteen/recipe/RecipeUploadModal.vue | 176 - src/views/canteen/recipe/index.vue | 412 - src/views/canteen/statistics/index.vue | 420 - src/views/canteen/statistics/schema.ts | 323 - src/views/contract/approval/edit/[id].vue | 508 - src/views/contract/approval/list/index.vue | 197 - src/views/contract/approval/list/schema.ts | 112 - src/views/contract/approval/todo/index.vue | 158 - src/views/contract/approval/todo/schema.ts | 39 - src/views/contract/archive/edit/[id].vue | 500 - src/views/contract/archive/list/index.vue | 193 - src/views/contract/archive/list/schema.ts | 61 - src/views/contract/audit/edit/[id].vue | 503 - src/views/contract/audit/list/index.vue | 197 - src/views/contract/audit/list/schema.ts | 112 - src/views/contract/audit/todo/index.vue | 158 - src/views/contract/audit/todo/schema.ts | 39 - src/views/contract/business/edit/[id].vue | 809 - src/views/contract/business/list/index.vue | 164 - src/views/contract/business/list/schema.ts | 58 - src/views/contract/business/todo/index.vue | 158 - src/views/contract/business/todo/schema.ts | 39 - src/views/contract/company/edit/[id].vue | 668 - .../contract/company/list/DetailModal.vue | 356 - src/views/contract/company/list/index.vue | 186 - src/views/contract/company/list/schema.ts | 61 - .../basis-contract/basis-contract.vue | 154 - .../components/basis-contract/schema.ts | 23 - .../company-manager/company-manager.vue | 180 - .../components/company-manager/schema.ts | 36 - .../components/contract-type/EditModal.vue | 207 - .../contract-type/contract-type.vue | 155 - .../components/project-manager/EditModal.vue | 140 - .../project-manager/project-manager.vue | 170 - .../components/project-manager/schema.ts | 36 - .../project-name-manager/EditModal.vue | 140 - .../project-name-manager.vue | 170 - .../components/project-name-manager/schema.ts | 36 - .../components/template-manager/EditModal.vue | 240 - .../template-manager/template-manager.vue | 178 - src/views/contract/config/index.vue | 123 - src/views/contract/declaration/edit/[id].vue | 664 - src/views/contract/declaration/list/index.vue | 178 - src/views/contract/declaration/list/schema.ts | 99 - src/views/contract/declaration/todo/index.vue | 158 - src/views/contract/declaration/todo/schema.ts | 39 - .../contract-break/contract-break.vue | 309 - .../contract-modify/contract-modify.vue | 398 - .../contract-payment/contract-payment.vue | 414 - .../contract-relieve/contract-relieve.vue | 317 - src/views/contract/perform/edit/[id].vue | 294 - src/views/contract/perform/list/index.vue | 186 - src/views/contract/perform/list/schema.ts | 68 - src/views/contract/perform/result/index.vue | 157 - src/views/contract/perform/result/schema.ts | 39 - src/views/contract/perform/todo/index.vue | 158 - src/views/contract/perform/todo/schema.ts | 39 - src/views/contract/sign/edit/[id].vue | 502 - src/views/contract/sign/list/index.vue | 197 - src/views/contract/sign/list/schema.ts | 112 - src/views/contract/sign/todo/index.vue | 158 - src/views/contract/sign/todo/schema.ts | 39 - src/views/duty/list/DutyEditModal.vue | 344 - src/views/duty/list/DutyUploadModal.vue | 181 - src/views/duty/list/index.vue | 295 - src/views/duty/list/schema.ts | 107 - src/views/flow/home/index.vue | 25 - src/views/function/hide-child/one/index.vue | 7 - src/views/function/hide-child/three/index.vue | 7 - src/views/function/hide-child/two/index.vue | 7 - src/views/function/multi-tab/index.vue | 24 - src/views/function/super-page/index.vue | 7 - src/views/function/tab/index.vue | 71 - src/views/function/toggle-auth/index.vue | 93 - src/views/home/index.vue | 119 - src/views/home/modules/card-data.vue | 109 - src/views/home/modules/creativity-banner.vue | 17 - src/views/home/modules/header-banner.vue | 66 - src/views/home/modules/line-chart.vue | 151 - src/views/home/modules/pie-chart.vue | 109 - src/views/home/modules/project-news.vue | 47 - .../info/components/Approval/approval.vue | 152 - .../info/components/Archived/archived.vue | 104 - .../info/components/Business/business.vue | 191 - .../components/Declaration/declaration.vue | 104 - .../info/components/Execution/execution.vue | 104 - .../info/components/Perform/perform.vue | 104 - .../contract/info/components/Track/track.vue | 112 - src/views/iframe/contract/info/index.vue | 75 - .../iframe/meeting/spokesperson/index.vue | 122 - .../iframe/meeting/standing-book/index.vue | 157 - src/views/meeting/edit/[id].vue | 947 - src/views/meeting/edit/file.hooks.ts | 46 - .../meeting/home/EditSpokenPersonModal.vue | 252 - src/views/meeting/home/MeetingEditModal.vue | 276 - src/views/meeting/home/MeetingRecordModal.vue | 296 - .../meeting/home/MeetingSpokespersonModal.vue | 365 - src/views/meeting/home/index.vue | 237 - src/views/message/todo/index.vue | 106 - src/views/multi-menu/first_child/index.vue | 7 - .../multi-menu/second_child_home/index.vue | 7 - .../office-supplies/apply/ApplyEditModal.vue | 244 - src/views/office-supplies/apply/index.vue | 250 - src/views/office-supplies/apply/schema.ts | 96 - .../office-supplies/audit/PromptModal.vue | 72 - .../audit/SuppliesAuditModal.vue | 229 - src/views/office-supplies/audit/index.vue | 280 - src/views/office-supplies/audit/schema.ts | 59 - .../inventory/ChooseSuppliesModal.vue | 200 - .../inventory/InventoryEditModal.vue | 147 - .../inventory/InventoryOutModal.vue | 333 - .../inventory/InventoryPutModal.vue | 248 - .../inventory/PurchaseSummaryModal.vue | 186 - src/views/office-supplies/inventory/index.vue | 241 - src/views/office-supplies/inventory/render.ts | 61 - src/views/office-supplies/inventory/schema.ts | 73 - src/views/office-supplies/purchase/index.vue | 11 - src/views/supervise/edit/[id].vue | 560 - src/views/supervise/feedback/index.vue | 227 - src/views/supervise/list/BatchAddModal.vue | 219 - src/views/supervise/list/DetailDrawer.vue | 150 - src/views/supervise/list/DetailModal.vue | 270 - src/views/supervise/list/EditDetailModal.vue | 163 - src/views/supervise/list/EditModal.vue | 323 - src/views/supervise/list/index.vue | 230 - src/views/supervise/list/schema.ts | 137 - src/views/supervise/statistics/index.vue | 66 - src/views/supervise/statistics/schema.ts | 42 - .../department/components/ChooseDeptModal.vue | 192 - src/views/system/dict/DictDataEditModal.vue | 198 - src/views/system/dict/DictTypeEditModal.vue | 157 - src/views/system/dict/index.vue | 324 - src/views/system/dict/schema.ts | 58 - src/views/user-center/ChooseUserModal.vue | 423 - src/views/user-center/index.vue | 30 - src/views/user-center/render.ts | 61 - stylelint.config.mjs | 4 + tea.yaml | 6 + tsconfig.json | 50 - turbo.json | 44 + uno.config.ts | 36 - vben-admin.code-workspace | 168 + vite.config.ts | 120 - vitest.config.ts | 10 + vitest.workspace.ts | 3 + 1604 files changed, 90057 insertions(+), 79153 deletions(-) create mode 100644 .browserslistrc create mode 100644 .commitlintrc.mjs create mode 100644 .dockerignore delete mode 100644 .env delete mode 100644 .env.prod delete mode 100644 .env.test delete mode 100644 .eslintrc.js create mode 100644 .gitconfig create mode 100644 .gitpod.yml create mode 100644 .husky/commit-msg create mode 100644 .husky/post-merge create mode 100644 .husky/pre-commit create mode 100644 .lintstagedrc.mjs create mode 100644 .ls-lint.yml create mode 100644 .node-version create mode 100644 .prettierignore create mode 100644 .prettierrc.mjs create mode 100644 .stylelintignore create mode 100644 .vscode/global.code-snippets create mode 100644 .vscode/launch.json create mode 100644 Dockerfile create mode 100644 README.ja-JP.md create mode 100644 README.zh-CN.md delete mode 100644 alova.config.ts create mode 100644 apps/web-office/.env create mode 100644 apps/web-office/.env.analyze create mode 100644 apps/web-office/.env.development create mode 100644 apps/web-office/.env.production create mode 100644 apps/web-office/index.html create mode 100644 apps/web-office/package.json create mode 100644 apps/web-office/postcss.config.mjs rename {public => apps/web-office/public}/favicon.ico (100%) create mode 100644 apps/web-office/readme.md create mode 100644 apps/web-office/src/api/core/auth.ts create mode 100644 apps/web-office/src/api/core/index.ts create mode 100644 apps/web-office/src/api/core/menu.ts create mode 100644 apps/web-office/src/api/core/user.ts create mode 100644 apps/web-office/src/api/global.d.ts create mode 100644 apps/web-office/src/api/index.ts rename {src => apps/web-office/src}/api/request/config.ts (93%) rename {src => apps/web-office/src}/api/request/getToken.ts (78%) create mode 100644 apps/web-office/src/api/request/index.ts rename {src => apps/web-office/src}/api/request/transferResponse.ts (77%) create mode 100644 apps/web-office/src/api/system/auth.ts create mode 100644 apps/web-office/src/api/system/menu.ts create mode 100644 apps/web-office/src/app.vue rename {src => apps/web-office/src}/assets/canteen/orderfood.png (100%) create mode 100644 apps/web-office/src/bootstrap.ts create mode 100644 apps/web-office/src/common/unit.ts create mode 100644 apps/web-office/src/components/dict-tag/dict-tag.vue create mode 100644 apps/web-office/src/components/dict-tag/index.ts rename CHANGELOG.md => apps/web-office/src/hooks/fastCrud.ts (100%) rename {src/components/Table => apps/web-office}/src/hooks/useRender.ts (72%) rename {src/hooks/common => apps/web-office/src/hooks}/vxeTable.ts (92%) create mode 100644 apps/web-office/src/layouts/basic.vue create mode 100644 apps/web-office/src/layouts/index.ts create mode 100644 apps/web-office/src/locales/README.md create mode 100644 apps/web-office/src/locales/index.ts create mode 100644 apps/web-office/src/locales/langs/en-US.json create mode 100644 apps/web-office/src/locales/langs/zh-CN.json create mode 100644 apps/web-office/src/main.ts create mode 100644 apps/web-office/src/plugins/fastCrud.ts create mode 100644 apps/web-office/src/plugins/vxeTable.ts create mode 100644 apps/web-office/src/preferences.ts create mode 100644 apps/web-office/src/router/access.ts create mode 100644 apps/web-office/src/router/guard.ts create mode 100644 apps/web-office/src/router/index.ts create mode 100644 apps/web-office/src/router/routes/core.ts create mode 100644 apps/web-office/src/router/routes/index.ts create mode 100644 apps/web-office/src/router/routes/modules/contract.ts create mode 100644 apps/web-office/src/router/routes/modules/dashboard.ts create mode 100644 apps/web-office/src/router/routes/modules/offfice.ts create mode 100644 apps/web-office/src/router/routes/modules/system.ts create mode 100644 apps/web-office/src/router/routes/modules/ucenter.ts create mode 100644 apps/web-office/src/store/auth.ts rename {src/store/modules => apps/web-office/src/store}/dict.ts (94%) create mode 100644 apps/web-office/src/store/index.ts rename {src => apps/web-office/src}/utils/dict/index.ts (94%) rename {src => apps/web-office/src}/utils/dict/shared.ts (100%) rename {src => apps/web-office/src}/utils/dict/static.data.ts (100%) create mode 100644 apps/web-office/src/utils/file.ts rename {src => apps/web-office/src}/utils/index.ts (81%) rename {src => apps/web-office/src}/utils/time.ts (100%) create mode 100644 apps/web-office/src/views/_core/README.md create mode 100644 apps/web-office/src/views/_core/about/index.vue create mode 100644 apps/web-office/src/views/_core/authentication/code-login.vue create mode 100644 apps/web-office/src/views/_core/authentication/forget-password.vue create mode 100644 apps/web-office/src/views/_core/authentication/login.vue create mode 100644 apps/web-office/src/views/_core/authentication/qrcode-login.vue create mode 100644 apps/web-office/src/views/_core/authentication/register.vue create mode 100644 apps/web-office/src/views/_core/fallback/coming-soon.vue create mode 100644 apps/web-office/src/views/_core/fallback/forbidden.vue create mode 100644 apps/web-office/src/views/_core/fallback/internal-error.vue create mode 100644 apps/web-office/src/views/_core/fallback/not-found.vue create mode 100644 apps/web-office/src/views/_core/fallback/offline.vue create mode 100644 apps/web-office/src/views/bussiness-trip/edit/index.vue create mode 100644 apps/web-office/src/views/bussiness-trip/list/choose-audit-people-modal.vue rename src/views/bussiness-trip/home/schema.ts => apps/web-office/src/views/bussiness-trip/list/crud.tsx (54%) create mode 100644 apps/web-office/src/views/bussiness-trip/list/index.vue create mode 100644 apps/web-office/src/views/bussiness-trip/todo/crud.tsx create mode 100644 apps/web-office/src/views/bussiness-trip/todo/index.vue create mode 100644 apps/web-office/src/views/canteen/collect/collect-detail-modal.vue rename src/views/canteen/collect/schema.ts => apps/web-office/src/views/canteen/collect/crud.tsx (52%) create mode 100644 apps/web-office/src/views/canteen/collect/index.vue create mode 100644 apps/web-office/src/views/canteen/config/components/auto-people/auto-people-batch-add-modal.vue create mode 100644 apps/web-office/src/views/canteen/config/components/auto-people/auto-people-edit-modal.vue create mode 100644 apps/web-office/src/views/canteen/config/components/auto-people/auto-people.vue rename src/views/canteen/config/components/auto-people/schema.ts => apps/web-office/src/views/canteen/config/components/auto-people/crud.tsx (50%) create mode 100644 apps/web-office/src/views/canteen/config/components/basic-settings/basic-settings.vue create mode 100644 apps/web-office/src/views/canteen/config/components/basic-settings/crud.tsx create mode 100644 apps/web-office/src/views/canteen/config/components/delivery-address/crud.tsx create mode 100644 apps/web-office/src/views/canteen/config/components/delivery-address/delivery-address-edit-modal.vue create mode 100644 apps/web-office/src/views/canteen/config/components/delivery-address/delivery-address.vue create mode 100644 apps/web-office/src/views/canteen/config/components/duty-people/crud.tsx create mode 100644 apps/web-office/src/views/canteen/config/components/duty-people/duty-people-batch-add-modal.vue create mode 100644 apps/web-office/src/views/canteen/config/components/duty-people/duty-people-edit-modal.vue create mode 100644 apps/web-office/src/views/canteen/config/components/duty-people/duty-people.vue create mode 100644 apps/web-office/src/views/canteen/config/index.vue create mode 100644 apps/web-office/src/views/canteen/orderfood/collect/collect.vue create mode 100644 apps/web-office/src/views/canteen/orderfood/collect/crud.tsx create mode 100644 apps/web-office/src/views/canteen/orderfood/index.vue create mode 100644 apps/web-office/src/views/canteen/orderfood/orderfood/choose-address-modal.vue create mode 100644 apps/web-office/src/views/canteen/orderfood/orderfood/orderfood.vue rename src/views/canteen/recipe/schema.ts => apps/web-office/src/views/canteen/recipe/crud.tsx (67%) create mode 100644 apps/web-office/src/views/canteen/recipe/index.vue create mode 100644 apps/web-office/src/views/canteen/recipe/recipe-sync-modal.vue create mode 100644 apps/web-office/src/views/canteen/statistics/crud.tsx create mode 100644 apps/web-office/src/views/canteen/statistics/index.vue create mode 100644 apps/web-office/src/views/canteen/statistics/subsidy-statistics.vue create mode 100644 apps/web-office/src/views/canteen/statistics/unit-statistics.vue create mode 100644 apps/web-office/src/views/contract/approval/edit/curd.tsx create mode 100644 apps/web-office/src/views/contract/approval/edit/index.vue create mode 100644 apps/web-office/src/views/contract/approval/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/approval/list/index.vue create mode 100644 apps/web-office/src/views/contract/approval/signing-basis/crud.tsx create mode 100644 apps/web-office/src/views/contract/approval/signing-basis/index.vue create mode 100644 apps/web-office/src/views/contract/approval/signing-basis/signing-basis-edit-modal.vue create mode 100644 apps/web-office/src/views/contract/approval/todo/index.vue create mode 100644 apps/web-office/src/views/contract/archive/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/archive/list/index.vue create mode 100644 apps/web-office/src/views/contract/archive/todo/archive.vue create mode 100644 apps/web-office/src/views/contract/archive/todo/retracement.vue create mode 100644 apps/web-office/src/views/contract/audit/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/audit/list/index.vue create mode 100644 apps/web-office/src/views/contract/audit/todo/index.vue create mode 100644 apps/web-office/src/views/contract/business/edit/basic-info-curd.tsx create mode 100644 apps/web-office/src/views/contract/business/edit/curd.tsx create mode 100644 apps/web-office/src/views/contract/business/edit/index.vue create mode 100644 apps/web-office/src/views/contract/business/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/business/list/index.vue create mode 100644 apps/web-office/src/views/contract/business/todo/index.vue create mode 100644 apps/web-office/src/views/contract/company/edit/curd.tsx create mode 100644 apps/web-office/src/views/contract/company/edit/index.vue create mode 100644 apps/web-office/src/views/contract/company/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/company/list/index.vue create mode 100644 apps/web-office/src/views/contract/config/components/contract-type/contract-type-edit-modal.vue create mode 100644 apps/web-office/src/views/contract/config/components/contract-type/contract-type.vue rename src/views/contract/config/components/contract-type/schema.ts => apps/web-office/src/views/contract/config/components/contract-type/crud.tsx (74%) create mode 100644 apps/web-office/src/views/contract/config/components/project-manager/crud.tsx create mode 100644 apps/web-office/src/views/contract/config/components/project-manager/project-manager-edit-modal.vue create mode 100644 apps/web-office/src/views/contract/config/components/project-manager/project-manager.vue create mode 100644 apps/web-office/src/views/contract/config/components/project-name-manager/crud.tsx create mode 100644 apps/web-office/src/views/contract/config/components/project-name-manager/project-name-manager-edit-modal.vue create mode 100644 apps/web-office/src/views/contract/config/components/project-name-manager/project-name-manager.vue rename src/views/contract/config/components/template-manager/schema.ts => apps/web-office/src/views/contract/config/components/template-manager/crud.tsx (63%) create mode 100644 apps/web-office/src/views/contract/config/components/template-manager/template-manager-edit-modal.vue create mode 100644 apps/web-office/src/views/contract/config/components/template-manager/template-manager.vue create mode 100644 apps/web-office/src/views/contract/config/index.vue create mode 100644 apps/web-office/src/views/contract/declaration/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/declaration/list/index.vue create mode 100644 apps/web-office/src/views/contract/declaration/print/crud.tsx create mode 100644 apps/web-office/src/views/contract/declaration/print/index.vue create mode 100644 apps/web-office/src/views/contract/declaration/todo/index.vue create mode 100644 apps/web-office/src/views/contract/iframe-info/components/info-approval/info-approval.vue create mode 100644 apps/web-office/src/views/contract/iframe-info/components/info-archived/info-archived.vue create mode 100644 apps/web-office/src/views/contract/iframe-info/components/info-business/info-business.vue create mode 100644 apps/web-office/src/views/contract/iframe-info/components/info-declaration/info-declaration.vue create mode 100644 apps/web-office/src/views/contract/iframe-info/components/info-perform/info-perform.vue create mode 100644 apps/web-office/src/views/contract/iframe-info/components/info-sign/info-sign.vue create mode 100644 apps/web-office/src/views/contract/iframe-info/components/info-track/info-track.vue create mode 100644 apps/web-office/src/views/contract/iframe-info/index.vue create mode 100644 apps/web-office/src/views/contract/perform/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/perform/list/index.vue create mode 100644 apps/web-office/src/views/contract/perform/result/index.vue create mode 100644 apps/web-office/src/views/contract/perform/temporary-archive/crud.tsx create mode 100644 apps/web-office/src/views/contract/perform/temporary-archive/index.vue create mode 100644 apps/web-office/src/views/contract/perform/todo/index.vue rename {src => apps/web-office/src}/views/contract/schema.ts (91%) create mode 100644 apps/web-office/src/views/contract/sign-authorization/edit/index.vue create mode 100644 apps/web-office/src/views/contract/sign-authorization/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/sign-authorization/list/index.vue create mode 100644 apps/web-office/src/views/contract/sign/list/crud.tsx create mode 100644 apps/web-office/src/views/contract/sign/list/index.vue create mode 100644 apps/web-office/src/views/contract/sign/todo/index.vue rename {src => apps/web-office/src}/views/contract/utils.ts (100%) create mode 100644 apps/web-office/src/views/dashboard/analytics/analytics-trends.vue create mode 100644 apps/web-office/src/views/dashboard/analytics/analytics-visits-data.vue create mode 100644 apps/web-office/src/views/dashboard/analytics/analytics-visits-sales.vue create mode 100644 apps/web-office/src/views/dashboard/analytics/analytics-visits-source.vue create mode 100644 apps/web-office/src/views/dashboard/analytics/analytics-visits.vue create mode 100644 apps/web-office/src/views/dashboard/analytics/index.vue create mode 100644 apps/web-office/src/views/dashboard/components/workbench-header.vue create mode 100644 apps/web-office/src/views/dashboard/components/workbench-quick-nav.vue create mode 100644 apps/web-office/src/views/dashboard/home/index.vue create mode 100644 apps/web-office/src/views/dashboard/workspace/index.vue create mode 100644 apps/web-office/src/views/demos/antd/index.vue create mode 100644 apps/web-office/src/views/duty/list/crud.tsx create mode 100644 apps/web-office/src/views/duty/list/duty-edit-modal.vue create mode 100644 apps/web-office/src/views/duty/list/duty-upload-modal.vue create mode 100644 apps/web-office/src/views/duty/list/index.vue create mode 100644 apps/web-office/src/views/duty/standing-book/crud.tsx create mode 100644 apps/web-office/src/views/duty/standing-book/index.vue create mode 100644 apps/web-office/src/views/meeting/edit/index.vue create mode 100644 apps/web-office/src/views/meeting/edit/spoken-person-edit-modal.vue create mode 100644 apps/web-office/src/views/meeting/list/crud.tsx create mode 100644 apps/web-office/src/views/meeting/list/index.vue rename src/views/meeting/home/schema.ts => apps/web-office/src/views/meeting/standing-book/crud.tsx (63%) create mode 100644 apps/web-office/src/views/meeting/standing-book/index.vue rename src/views/iframe/meeting/start/[id].vue => apps/web-office/src/views/meeting/start/index.vue (62%) create mode 100644 apps/web-office/src/views/office-supplies/apply/crud.tsx create mode 100644 apps/web-office/src/views/office-supplies/apply/index.vue create mode 100644 apps/web-office/src/views/office-supplies/apply/office-batch-apply-modal.vue create mode 100644 apps/web-office/src/views/office-supplies/audit/crud.tsx create mode 100644 apps/web-office/src/views/office-supplies/audit/index.vue create mode 100644 apps/web-office/src/views/office-supplies/inventory/choose-office-modal.vue create mode 100644 apps/web-office/src/views/office-supplies/inventory/crud.tsx create mode 100644 apps/web-office/src/views/office-supplies/inventory/index.vue create mode 100644 apps/web-office/src/views/office-supplies/inventory/purchase-summary-modal.vue create mode 100644 apps/web-office/src/views/office-supplies/inventory/supplies-edit-modal.vue create mode 100644 apps/web-office/src/views/office-supplies/inventory/supplies-out-modal.vue create mode 100644 apps/web-office/src/views/office-supplies/inventory/supplies-put-modal.vue create mode 100644 apps/web-office/src/views/office-supplies/settle/crud.tsx create mode 100644 apps/web-office/src/views/office-supplies/settle/index.vue create mode 100644 apps/web-office/src/views/supervise/edit/index.vue create mode 100644 apps/web-office/src/views/supervise/feedback/crud.tsx create mode 100644 apps/web-office/src/views/supervise/feedback/index.vue rename src/views/supervise/feedback/schema.ts => apps/web-office/src/views/supervise/list/crud.tsx (52%) create mode 100644 apps/web-office/src/views/supervise/list/index.vue create mode 100644 apps/web-office/src/views/supervise/summary/crud.tsx create mode 100644 apps/web-office/src/views/supervise/summary/index.vue create mode 100644 apps/web-office/src/views/system/dict/crud.tsx create mode 100644 apps/web-office/src/views/system/dict/dict-data-edit-modal.vue create mode 100644 apps/web-office/src/views/system/dict/dict-type-edit-modal.vue create mode 100644 apps/web-office/src/views/system/dict/index.vue create mode 100644 apps/web-office/src/views/system/user/choose-user-modal.vue create mode 100644 apps/web-office/src/views/user-center/center/index.vue create mode 100644 apps/web-office/src/views/user-center/todo/index.vue create mode 100644 apps/web-office/tailwind.config.mjs create mode 100644 apps/web-office/tsconfig.json create mode 100644 apps/web-office/tsconfig.node.json create mode 100644 apps/web-office/vite.config.mts create mode 100644 build-local-docker-image.sh delete mode 100644 build/config/index.ts delete mode 100644 build/config/proxy.ts delete mode 100644 build/plugins/index.ts delete mode 100644 build/plugins/router.ts delete mode 100644 build/plugins/unocss.ts delete mode 100644 build/plugins/unplugin.ts create mode 100644 cspell.json delete mode 100644 eslint.config.js create mode 100644 eslint.config.mjs delete mode 100644 index.html create mode 100644 internal/lint-configs/commitlint-config/index.mjs create mode 100644 internal/lint-configs/commitlint-config/package.json create mode 100644 internal/lint-configs/eslint-config/build.config.ts create mode 100644 internal/lint-configs/eslint-config/package.json create mode 100644 internal/lint-configs/eslint-config/src/configs/command.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/comments.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/disableds.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/ignores.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/import.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/index.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/javascript.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/jsdoc.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/jsonc.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/node.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/perfectionist.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/prettier.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/regexp.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/test.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/turbo.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/typescript.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/unicorn.ts create mode 100644 internal/lint-configs/eslint-config/src/configs/vue.ts create mode 100644 internal/lint-configs/eslint-config/src/custom-config.ts create mode 100644 internal/lint-configs/eslint-config/src/index.ts create mode 100644 internal/lint-configs/eslint-config/src/util.ts create mode 100644 internal/lint-configs/eslint-config/tsconfig.json create mode 100644 internal/lint-configs/prettier-config/index.mjs create mode 100644 internal/lint-configs/prettier-config/package.json create mode 100644 internal/lint-configs/stylelint-config/index.mjs create mode 100644 internal/lint-configs/stylelint-config/package.json create mode 100644 internal/node-utils/build.config.ts create mode 100644 internal/node-utils/package.json create mode 100644 internal/node-utils/src/__tests__/hash.test.ts create mode 100644 internal/node-utils/src/__tests__/path.test.ts create mode 100644 internal/node-utils/src/constants.ts create mode 100644 internal/node-utils/src/date.ts create mode 100644 internal/node-utils/src/fs.ts create mode 100644 internal/node-utils/src/git.ts create mode 100644 internal/node-utils/src/hash.ts create mode 100644 internal/node-utils/src/index.ts create mode 100644 internal/node-utils/src/monorepo.ts create mode 100644 internal/node-utils/src/path.ts create mode 100644 internal/node-utils/src/prettier.ts create mode 100644 internal/node-utils/src/spinner.ts create mode 100644 internal/node-utils/tsconfig.json create mode 100644 internal/tailwind-config/build.config.ts create mode 100644 internal/tailwind-config/package.json create mode 100644 internal/tailwind-config/src/index.ts create mode 100644 internal/tailwind-config/src/module.d.ts create mode 100644 internal/tailwind-config/src/plugins/entry.ts create mode 100644 internal/tailwind-config/src/postcss.config.ts create mode 100644 internal/tailwind-config/tsconfig.json create mode 100644 internal/tsconfig/base.json create mode 100644 internal/tsconfig/library.json create mode 100644 internal/tsconfig/node.json create mode 100644 internal/tsconfig/package.json create mode 100644 internal/tsconfig/web-app.json create mode 100644 internal/tsconfig/web.json create mode 100644 internal/vite-config/build.config.ts create mode 100644 internal/vite-config/package.json create mode 100644 internal/vite-config/src/config/application.ts create mode 100644 internal/vite-config/src/config/common.ts create mode 100644 internal/vite-config/src/config/index.ts create mode 100644 internal/vite-config/src/config/library.ts create mode 100644 internal/vite-config/src/index.ts create mode 100644 internal/vite-config/src/options.ts create mode 100644 internal/vite-config/src/plugins/extra-app-config.ts create mode 100644 internal/vite-config/src/plugins/importmap.ts create mode 100644 internal/vite-config/src/plugins/index.ts create mode 100644 internal/vite-config/src/plugins/inject-app-loading/README.md create mode 100644 internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html create mode 100644 internal/vite-config/src/plugins/inject-app-loading/default-loading.html create mode 100644 internal/vite-config/src/plugins/inject-app-loading/index.ts create mode 100644 internal/vite-config/src/plugins/inject-metadata.ts create mode 100644 internal/vite-config/src/plugins/license.ts create mode 100644 internal/vite-config/src/plugins/nitro-mock.ts create mode 100644 internal/vite-config/src/plugins/print.ts create mode 100644 internal/vite-config/src/typing.ts create mode 100644 internal/vite-config/src/utils/env.ts create mode 100644 internal/vite-config/tsconfig.json delete mode 100644 mock/common.ts delete mode 100644 mock/index.ts delete mode 100644 mock/system/auth.ts create mode 100644 nginx.conf create mode 100644 packages/@core/README.md create mode 100644 packages/@core/base/README.md create mode 100644 packages/@core/base/design/package.json create mode 100644 packages/@core/base/design/src/css/global.css create mode 100644 packages/@core/base/design/src/css/nprogress.css create mode 100644 packages/@core/base/design/src/css/transition.css create mode 100644 packages/@core/base/design/src/css/ui.css create mode 100644 packages/@core/base/design/src/design-tokens/dark/index.css create mode 100644 packages/@core/base/design/src/design-tokens/default/index.css create mode 100644 packages/@core/base/design/src/design-tokens/index.ts create mode 100644 packages/@core/base/design/src/index.ts create mode 100644 packages/@core/base/design/src/scss-bem/bem.scss create mode 100644 packages/@core/base/design/src/scss-bem/constants.scss create mode 100644 packages/@core/base/design/tsconfig.json create mode 100644 packages/@core/base/design/vite.config.mts create mode 100644 packages/@core/base/icons/build.config.ts create mode 100644 packages/@core/base/icons/package.json create mode 100644 packages/@core/base/icons/src/create-icon.ts create mode 100644 packages/@core/base/icons/src/index.ts create mode 100644 packages/@core/base/icons/src/lucide.ts create mode 100644 packages/@core/base/icons/tsconfig.json create mode 100644 packages/@core/base/shared/build.config.ts create mode 100644 packages/@core/base/shared/package.json create mode 100644 packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts create mode 100644 packages/@core/base/shared/src/cache/index.ts create mode 100644 packages/@core/base/shared/src/cache/storage-manager.ts create mode 100644 packages/@core/base/shared/src/cache/types.ts create mode 100644 packages/@core/base/shared/src/color/__tests__/convert.test.ts create mode 100644 packages/@core/base/shared/src/color/convert.ts create mode 100644 packages/@core/base/shared/src/color/generator.ts create mode 100644 packages/@core/base/shared/src/color/index.ts create mode 100644 packages/@core/base/shared/src/constants/globals.ts create mode 100644 packages/@core/base/shared/src/constants/index.ts create mode 100644 packages/@core/base/shared/src/constants/vben.ts create mode 100644 packages/@core/base/shared/src/index.ts create mode 100644 packages/@core/base/shared/src/store.ts create mode 100644 packages/@core/base/shared/src/utils/__tests__/diff.test.ts create mode 100644 packages/@core/base/shared/src/utils/__tests__/dom.test.ts create mode 100644 packages/@core/base/shared/src/utils/__tests__/inference.test.ts create mode 100644 packages/@core/base/shared/src/utils/__tests__/letter.test.ts create mode 100644 packages/@core/base/shared/src/utils/__tests__/tree.test.ts create mode 100644 packages/@core/base/shared/src/utils/__tests__/unique.test.ts create mode 100644 packages/@core/base/shared/src/utils/__tests__/update-css-variables.test.ts create mode 100644 packages/@core/base/shared/src/utils/__tests__/window.test.ts create mode 100644 packages/@core/base/shared/src/utils/cn.ts create mode 100644 packages/@core/base/shared/src/utils/diff.ts create mode 100644 packages/@core/base/shared/src/utils/dom.ts create mode 100644 packages/@core/base/shared/src/utils/index.ts create mode 100644 packages/@core/base/shared/src/utils/inference.ts create mode 100644 packages/@core/base/shared/src/utils/letter.ts create mode 100644 packages/@core/base/shared/src/utils/merge.ts create mode 100644 packages/@core/base/shared/src/utils/nprogress.ts create mode 100644 packages/@core/base/shared/src/utils/to.ts create mode 100644 packages/@core/base/shared/src/utils/tree.ts create mode 100644 packages/@core/base/shared/src/utils/unique.ts create mode 100644 packages/@core/base/shared/src/utils/update-css-variables.ts create mode 100644 packages/@core/base/shared/src/utils/window.ts create mode 100644 packages/@core/base/shared/tsconfig.json create mode 100644 packages/@core/base/typings/build.config.ts create mode 100644 packages/@core/base/typings/package.json create mode 100644 packages/@core/base/typings/src/app.d.ts create mode 100644 packages/@core/base/typings/src/basic.d.ts create mode 100644 packages/@core/base/typings/src/helper.d.ts create mode 100644 packages/@core/base/typings/src/index.ts create mode 100644 packages/@core/base/typings/src/menu-record.ts create mode 100644 packages/@core/base/typings/src/tabs.ts create mode 100644 packages/@core/base/typings/src/vue-router.d.ts create mode 100644 packages/@core/base/typings/tsconfig.json create mode 100644 packages/@core/base/typings/vue-router.d.ts create mode 100644 packages/@core/composables/build.config.ts create mode 100644 packages/@core/composables/package.json create mode 100644 packages/@core/composables/src/__tests__/use-sortable.test.ts create mode 100644 packages/@core/composables/src/index.ts create mode 100644 packages/@core/composables/src/use-content-style.ts create mode 100644 packages/@core/composables/src/use-is-mobile.ts create mode 100644 packages/@core/composables/src/use-namespace.ts create mode 100644 packages/@core/composables/src/use-priority-value.ts create mode 100644 packages/@core/composables/src/use-sortable.ts create mode 100644 packages/@core/composables/tsconfig.json create mode 100644 packages/@core/preferences/build.config.ts create mode 100644 packages/@core/preferences/package.json create mode 100644 packages/@core/preferences/src/config.ts create mode 100644 packages/@core/preferences/src/constants.ts create mode 100644 packages/@core/preferences/src/index.ts create mode 100644 packages/@core/preferences/src/preferences.test.ts create mode 100644 packages/@core/preferences/src/preferences.ts create mode 100644 packages/@core/preferences/src/types.ts create mode 100644 packages/@core/preferences/src/update-css-variables.ts create mode 100644 packages/@core/preferences/src/use-preferences.ts create mode 100644 packages/@core/preferences/tsconfig.json create mode 100644 packages/@core/ui-kit/README.md create mode 100644 packages/@core/ui-kit/layout-ui/build.config.ts create mode 100644 packages/@core/ui-kit/layout-ui/package.json create mode 100644 packages/@core/ui-kit/layout-ui/postcss.config.mjs create mode 100644 packages/@core/ui-kit/layout-ui/src/components/index.ts create mode 100644 packages/@core/ui-kit/layout-ui/src/components/layout-content.vue create mode 100644 packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue create mode 100644 packages/@core/ui-kit/layout-ui/src/components/layout-header.vue create mode 100644 packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue create mode 100644 packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue create mode 100644 packages/@core/ui-kit/layout-ui/src/components/widgets/index.ts create mode 100644 packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue create mode 100644 packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-fixed-button.vue create mode 100644 packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts create mode 100644 packages/@core/ui-kit/layout-ui/src/index.ts create mode 100644 packages/@core/ui-kit/layout-ui/src/vben-layout.ts create mode 100644 packages/@core/ui-kit/layout-ui/src/vben-layout.vue create mode 100644 packages/@core/ui-kit/layout-ui/tailwind.config.mjs create mode 100644 packages/@core/ui-kit/layout-ui/tsconfig.json create mode 100644 packages/@core/ui-kit/menu-ui/README.md create mode 100644 packages/@core/ui-kit/menu-ui/build.config.ts create mode 100644 packages/@core/ui-kit/menu-ui/package.json create mode 100644 packages/@core/ui-kit/menu-ui/postcss.config.mjs create mode 100644 packages/@core/ui-kit/menu-ui/src/components/collapse-transition.vue create mode 100644 packages/@core/ui-kit/menu-ui/src/components/index.ts create mode 100644 packages/@core/ui-kit/menu-ui/src/components/menu-item.vue create mode 100644 packages/@core/ui-kit/menu-ui/src/components/menu.vue create mode 100644 packages/@core/ui-kit/menu-ui/src/components/normal-menu/index.ts create mode 100644 packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts create mode 100644 packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.vue create mode 100644 packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue create mode 100644 packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue create mode 100644 packages/@core/ui-kit/menu-ui/src/hooks/index.ts create mode 100644 packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts create mode 100644 packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts create mode 100644 packages/@core/ui-kit/menu-ui/src/index.ts create mode 100644 packages/@core/ui-kit/menu-ui/src/menu.vue create mode 100644 packages/@core/ui-kit/menu-ui/src/sub-menu.vue create mode 100644 packages/@core/ui-kit/menu-ui/src/types.ts create mode 100644 packages/@core/ui-kit/menu-ui/src/utils/index.ts create mode 100644 packages/@core/ui-kit/menu-ui/tailwind.config.mjs create mode 100644 packages/@core/ui-kit/menu-ui/tsconfig.json create mode 100644 packages/@core/ui-kit/popup-ui/build.config.ts create mode 100644 packages/@core/ui-kit/popup-ui/package.json create mode 100644 packages/@core/ui-kit/popup-ui/postcss.config.mjs create mode 100644 packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue create mode 100644 packages/@core/ui-kit/popup-ui/src/drawer/index.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/index.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/modal/index.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/modal/modal.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/modal/modal.vue create mode 100644 packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts create mode 100644 packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts create mode 100644 packages/@core/ui-kit/popup-ui/tailwind.config.mjs create mode 100644 packages/@core/ui-kit/popup-ui/tsconfig.json create mode 100644 packages/@core/ui-kit/shadcn-ui/build.config.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/components.json create mode 100644 packages/@core/ui-kit/shadcn-ui/package.json create mode 100644 packages/@core/ui-kit/shadcn-ui/postcss.config.mjs create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/avatar/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/back-top/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-background.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/types.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/button/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/checkbox/checkbox.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/checkbox/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/context-menu/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-menu.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-radio-menu.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/full-screen/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/hover-card/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/icon/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/input-password/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/input/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/input/input.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/input/types.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/link/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/link/link.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/logo/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/menu-badge/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/menu-badge/menu-badge-dot.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/menu-badge/menu-badge.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/pin-input/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/popover/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/render-content/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/segmented/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/segmented/segmented.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/segmented/types.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/spinner/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/swap/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/swap/swap.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/tooltip/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/avatar/Avatar.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/avatar/AvatarFallback.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/avatar/AvatarImage.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/avatar/avatar.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/avatar/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/badge/Badge.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/badge/badge.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/badge/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/breadcrumb/Breadcrumb.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/breadcrumb/BreadcrumbItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/breadcrumb/BreadcrumbLink.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/breadcrumb/BreadcrumbList.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/breadcrumb/BreadcrumbPage.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/breadcrumb/BreadcrumbSeparator.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/breadcrumb/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/button/Button.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/button/button.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/button/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/card/Card.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/card/CardContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/card/CardDescription.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/card/CardFooter.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/card/CardHeader.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/card/CardTitle.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/card/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/checkbox/Checkbox.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/checkbox/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenu.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuCheckboxItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuGroup.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuLabel.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuPortal.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuRadioGroup.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuRadioItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuSeparator.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuShortcut.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuSub.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuSubContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuSubTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/ContextMenuTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/context-menu/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/Dialog.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogClose.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogDescription.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogFooter.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogHeader.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogScrollContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogTitle.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenu.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuGroup.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuLabel.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuSub.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dropdown-menu/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/hover-card/HoverCard.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/hover-card/HoverCardContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/hover-card/HoverCardTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/hover-card/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/input/Input.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/input/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/number-field/NumberField.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/number-field/NumberFieldContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/number-field/NumberFieldDecrement.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/number-field/NumberFieldIncrement.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/number-field/NumberFieldInput.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/number-field/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/pin-input/PinInput.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/pin-input/PinInputGroup.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/pin-input/PinInputInput.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/pin-input/PinInputSeparator.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/pin-input/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/popover/Popover.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/popover/PopoverContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/popover/PopoverTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/popover/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/scroll-area/ScrollArea.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/scroll-area/ScrollBar.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/scroll-area/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/Select.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectGroup.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectItemText.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectLabel.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectScrollDownButton.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectScrollUpButton.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectSeparator.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/SelectValue.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/select/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/Sheet.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/SheetClose.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/SheetContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/SheetDescription.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/SheetFooter.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/SheetHeader.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/SheetTitle.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/SheetTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/sheet.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/switch/Switch.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/switch/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tabs/Tabs.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tabs/TabsContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tabs/TabsList.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tabs/TabsTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tabs/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/Toast.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/ToastAction.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/ToastClose.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/ToastDescription.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/ToastProvider.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/ToastTitle.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/ToastViewport.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/Toaster.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/toast.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toast/use-toast.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toggle-group/ToggleGroup.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toggle-group/ToggleGroupItem.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toggle-group/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toggle/Toggle.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toggle/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/toggle/toggle.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tooltip/Tooltip.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tooltip/TooltipContent.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tooltip/TooltipProvider.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tooltip/TooltipTrigger.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/tooltip/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/index.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs create mode 100644 packages/@core/ui-kit/shadcn-ui/tsconfig.json create mode 100644 packages/@core/ui-kit/tabs-ui/build.config.ts create mode 100644 packages/@core/ui-kit/tabs-ui/package.json create mode 100644 packages/@core/ui-kit/tabs-ui/postcss.config.mjs create mode 100644 packages/@core/ui-kit/tabs-ui/src/components/index.ts create mode 100644 packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue create mode 100644 packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue create mode 100644 packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts create mode 100644 packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue create mode 100644 packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-refresh.vue create mode 100644 packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue create mode 100644 packages/@core/ui-kit/tabs-ui/src/index.ts create mode 100644 packages/@core/ui-kit/tabs-ui/src/tabs-view.vue create mode 100644 packages/@core/ui-kit/tabs-ui/src/types.ts create mode 100644 packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts create mode 100644 packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts create mode 100644 packages/@core/ui-kit/tabs-ui/tailwind.config.mjs create mode 100644 packages/@core/ui-kit/tabs-ui/tsconfig.json delete mode 100644 packages/color/package.json delete mode 100644 packages/color/src/constant/index.ts delete mode 100644 packages/color/src/constant/name.ts delete mode 100644 packages/color/src/constant/palette.ts delete mode 100644 packages/color/src/index.ts delete mode 100644 packages/color/src/palette/antd.ts delete mode 100644 packages/color/src/palette/index.ts delete mode 100644 packages/color/src/palette/recommend.ts delete mode 100644 packages/color/src/shared/colord.ts delete mode 100644 packages/color/src/shared/index.ts delete mode 100644 packages/color/src/shared/name.ts delete mode 100644 packages/color/src/types/index.ts delete mode 100644 packages/color/tsconfig.json delete mode 100644 packages/common-utils/package.json delete mode 100644 packages/common-utils/tsconfig.json create mode 100644 packages/constants/README.md create mode 100644 packages/constants/package.json create mode 100644 packages/constants/src/core.ts create mode 100644 packages/constants/src/index.ts create mode 100644 packages/constants/tsconfig.json create mode 100644 packages/effects/README.md create mode 100644 packages/effects/access/package.json create mode 100644 packages/effects/access/postcss.config.mjs create mode 100644 packages/effects/access/src/access-control.vue create mode 100644 packages/effects/access/src/accessible.ts create mode 100644 packages/effects/access/src/directive.ts create mode 100644 packages/effects/access/src/index.ts create mode 100644 packages/effects/access/src/use-access.ts create mode 100644 packages/effects/access/tailwind.config.mjs create mode 100644 packages/effects/access/tsconfig.json create mode 100644 packages/effects/common-ui/package.json create mode 100644 packages/effects/common-ui/postcss.config.mjs create mode 100644 packages/effects/common-ui/src/components/ellipsis-text/__tests__/ellipsis-text.test.ts create mode 100644 packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue create mode 100644 packages/effects/common-ui/src/components/ellipsis-text/index.ts create mode 100644 packages/effects/common-ui/src/components/index.ts create mode 100644 packages/effects/common-ui/src/components/page/__tests__/page.test.ts create mode 100644 packages/effects/common-ui/src/components/page/index.ts create mode 100644 packages/effects/common-ui/src/components/page/page.vue create mode 100644 packages/effects/common-ui/src/index.ts create mode 100644 packages/effects/common-ui/src/ui/about/about.ts create mode 100644 packages/effects/common-ui/src/ui/about/about.vue create mode 100644 packages/effects/common-ui/src/ui/about/index.ts create mode 100644 packages/effects/common-ui/src/ui/authentication/auth-title.vue create mode 100644 packages/effects/common-ui/src/ui/authentication/code-login.vue create mode 100644 packages/effects/common-ui/src/ui/authentication/forget-password.vue create mode 100644 packages/effects/common-ui/src/ui/authentication/index.ts create mode 100644 packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue create mode 100644 packages/effects/common-ui/src/ui/authentication/login.vue create mode 100644 packages/effects/common-ui/src/ui/authentication/qrcode-login.vue create mode 100644 packages/effects/common-ui/src/ui/authentication/register.vue create mode 100644 packages/effects/common-ui/src/ui/authentication/third-party-login.vue create mode 100644 packages/effects/common-ui/src/ui/authentication/types.ts create mode 100644 packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue create mode 100644 packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue create mode 100644 packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue create mode 100644 packages/effects/common-ui/src/ui/dashboard/analysis/index.ts create mode 100644 packages/effects/common-ui/src/ui/dashboard/index.ts create mode 100644 packages/effects/common-ui/src/ui/dashboard/typing.ts create mode 100644 packages/effects/common-ui/src/ui/dashboard/workbench/index.ts create mode 100644 packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue create mode 100644 packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue create mode 100644 packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue create mode 100644 packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue create mode 100644 packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue create mode 100644 packages/effects/common-ui/src/ui/fallback/fallback.ts create mode 100644 packages/effects/common-ui/src/ui/fallback/fallback.vue create mode 100644 packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue create mode 100644 packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue create mode 100644 packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue create mode 100644 packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue create mode 100644 packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue create mode 100644 packages/effects/common-ui/src/ui/fallback/icons/warning.svg create mode 100644 packages/effects/common-ui/src/ui/fallback/index.ts create mode 100644 packages/effects/common-ui/src/ui/index.ts create mode 100644 packages/effects/common-ui/tailwind.config.mjs create mode 100644 packages/effects/common-ui/tsconfig.json create mode 100644 packages/effects/hooks/README.md create mode 100644 packages/effects/hooks/package.json create mode 100644 packages/effects/hooks/src/index.ts create mode 100644 packages/effects/hooks/src/use-app-config.ts create mode 100644 packages/effects/hooks/src/use-content-maximize.ts create mode 100644 packages/effects/hooks/src/use-design-tokens.ts create mode 100644 packages/effects/hooks/src/use-refresh.ts create mode 100644 packages/effects/hooks/src/use-tabs.ts create mode 100644 packages/effects/hooks/src/use-watermark.ts create mode 100644 packages/effects/hooks/tsconfig.json create mode 100644 packages/effects/layouts/package.json create mode 100644 packages/effects/layouts/postcss.config.mjs create mode 100644 packages/effects/layouts/src/authentication/authentication.vue create mode 100644 packages/effects/layouts/src/authentication/form.vue create mode 100644 packages/effects/layouts/src/authentication/icons/slogan.vue create mode 100644 packages/effects/layouts/src/authentication/index.ts create mode 100644 packages/effects/layouts/src/authentication/toolbar.vue create mode 100644 packages/effects/layouts/src/basic/README.md create mode 100644 packages/effects/layouts/src/basic/content/content-spinner.vue create mode 100644 packages/effects/layouts/src/basic/content/content.vue create mode 100644 packages/effects/layouts/src/basic/content/index.ts create mode 100644 packages/effects/layouts/src/basic/content/use-content-spinner.ts create mode 100644 packages/effects/layouts/src/basic/copyright/copyright.vue create mode 100644 packages/effects/layouts/src/basic/copyright/index.ts create mode 100644 packages/effects/layouts/src/basic/footer/footer.vue create mode 100644 packages/effects/layouts/src/basic/footer/index.ts create mode 100644 packages/effects/layouts/src/basic/header/header.vue create mode 100644 packages/effects/layouts/src/basic/header/index.ts create mode 100644 packages/effects/layouts/src/basic/index.ts create mode 100644 packages/effects/layouts/src/basic/layout.vue create mode 100644 packages/effects/layouts/src/basic/menu/extra-menu.vue create mode 100644 packages/effects/layouts/src/basic/menu/index.ts create mode 100644 packages/effects/layouts/src/basic/menu/menu.vue create mode 100644 packages/effects/layouts/src/basic/menu/mixed-menu.vue create mode 100644 packages/effects/layouts/src/basic/menu/use-extra-menu.ts create mode 100644 packages/effects/layouts/src/basic/menu/use-mixed-menu.ts create mode 100644 packages/effects/layouts/src/basic/menu/use-navigation.ts create mode 100644 packages/effects/layouts/src/basic/tabbar/index.ts create mode 100644 packages/effects/layouts/src/basic/tabbar/tabbar.vue create mode 100644 packages/effects/layouts/src/basic/tabbar/use-tabbar.ts create mode 100644 packages/effects/layouts/src/iframe/iframe-router-view.vue create mode 100644 packages/effects/layouts/src/iframe/iframe-view.vue create mode 100644 packages/effects/layouts/src/iframe/index.ts create mode 100644 packages/effects/layouts/src/index.ts create mode 100644 packages/effects/layouts/src/widgets/breadcrumb.vue create mode 100644 packages/effects/layouts/src/widgets/check-updates/check-updates.vue create mode 100644 packages/effects/layouts/src/widgets/check-updates/index.ts create mode 100644 packages/effects/layouts/src/widgets/color-toggle.vue create mode 100644 packages/effects/layouts/src/widgets/global-search/global-search.vue create mode 100644 packages/effects/layouts/src/widgets/global-search/index.ts create mode 100644 packages/effects/layouts/src/widgets/global-search/search-panel.vue create mode 100644 packages/effects/layouts/src/widgets/index.ts create mode 100644 packages/effects/layouts/src/widgets/language-toggle.vue create mode 100644 packages/effects/layouts/src/widgets/layout-toggle.vue create mode 100644 packages/effects/layouts/src/widgets/lock-screen/index.ts create mode 100644 packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue create mode 100644 packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue create mode 100644 packages/effects/layouts/src/widgets/notification/index.ts create mode 100644 packages/effects/layouts/src/widgets/notification/notification.vue create mode 100644 packages/effects/layouts/src/widgets/notification/types.ts create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/block.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/index.ts create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/icons/full-content.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/icons/index.ts create mode 100644 packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/icons/setting.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/index.ts create mode 100644 packages/effects/layouts/src/widgets/preferences/preferences-button.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/preferences.vue create mode 100644 packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts create mode 100644 packages/effects/layouts/src/widgets/theme-toggle/index.ts create mode 100644 packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue create mode 100644 packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue create mode 100644 packages/effects/layouts/src/widgets/user-dropdown/index.ts create mode 100644 packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue create mode 100644 packages/effects/layouts/tailwind.config.mjs create mode 100644 packages/effects/layouts/tsconfig.json create mode 100644 packages/effects/plugins/README.md create mode 100644 packages/effects/plugins/package.json create mode 100644 packages/effects/plugins/src/echarts/echarts-ui.vue create mode 100644 packages/effects/plugins/src/echarts/echarts.ts create mode 100644 packages/effects/plugins/src/echarts/index.ts create mode 100644 packages/effects/plugins/src/echarts/use-echarts.ts create mode 100644 packages/effects/plugins/tsconfig.json create mode 100644 packages/effects/request/package.json create mode 100644 packages/effects/request/src/index.ts create mode 100644 packages/effects/request/src/request-client/index.ts create mode 100644 packages/effects/request/src/request-client/modules/downloader.test.ts create mode 100644 packages/effects/request/src/request-client/modules/downloader.ts create mode 100644 packages/effects/request/src/request-client/modules/interceptor.ts create mode 100644 packages/effects/request/src/request-client/modules/uploader.test.ts create mode 100644 packages/effects/request/src/request-client/modules/uploader.ts create mode 100644 packages/effects/request/src/request-client/preset-interceptors.ts create mode 100644 packages/effects/request/src/request-client/request-client.test.ts create mode 100644 packages/effects/request/src/request-client/request-client.ts create mode 100644 packages/effects/request/src/request-client/types.ts create mode 100644 packages/effects/request/tsconfig.json delete mode 100644 packages/hooks/package.json delete mode 100644 packages/hooks/src/index.ts delete mode 100644 packages/hooks/src/use-boolean.ts delete mode 100644 packages/hooks/src/use-context.ts delete mode 100644 packages/hooks/src/use-count-down.ts delete mode 100644 packages/hooks/src/use-loading.ts delete mode 100644 packages/hooks/src/use-signal.ts delete mode 100644 packages/hooks/src/use-svg-icon-render.ts delete mode 100644 packages/hooks/src/use-table.ts delete mode 100644 packages/hooks/tsconfig.json create mode 100644 packages/icons/README.md create mode 100644 packages/icons/package.json create mode 100644 packages/icons/src/iconify/index.ts create mode 100644 packages/icons/src/index.ts create mode 100644 packages/icons/src/svg/icons/avatar-1.svg create mode 100644 packages/icons/src/svg/icons/avatar-2.svg create mode 100644 packages/icons/src/svg/icons/avatar-3.svg create mode 100644 packages/icons/src/svg/icons/avatar-4.svg create mode 100644 packages/icons/src/svg/icons/bell.svg create mode 100644 packages/icons/src/svg/icons/cake.svg create mode 100644 packages/icons/src/svg/icons/card.svg create mode 100644 packages/icons/src/svg/icons/download.svg create mode 100644 packages/icons/src/svg/index.ts create mode 100644 packages/icons/src/svg/load.ts create mode 100644 packages/icons/tsconfig.json create mode 100644 packages/locales/package.json create mode 100644 packages/locales/src/i18n.ts create mode 100644 packages/locales/src/index.ts create mode 100644 packages/locales/src/langs/en-US.json create mode 100644 packages/locales/src/langs/zh-CN.json create mode 100644 packages/locales/src/typing.ts create mode 100644 packages/locales/tsconfig.json delete mode 100644 packages/materials/package.json delete mode 100644 packages/materials/src/index.ts delete mode 100644 packages/materials/src/libs/admin-layout/index.module.css delete mode 100644 packages/materials/src/libs/admin-layout/index.module.css.d.ts delete mode 100644 packages/materials/src/libs/admin-layout/index.ts delete mode 100644 packages/materials/src/libs/admin-layout/index.vue delete mode 100644 packages/materials/src/libs/admin-layout/shared.ts delete mode 100644 packages/materials/src/libs/page-tab/button-tab.vue delete mode 100644 packages/materials/src/libs/page-tab/chrome-tab-bg.vue delete mode 100644 packages/materials/src/libs/page-tab/chrome-tab.vue delete mode 100644 packages/materials/src/libs/page-tab/index.module.css delete mode 100644 packages/materials/src/libs/page-tab/index.module.css.d.ts delete mode 100644 packages/materials/src/libs/page-tab/index.ts delete mode 100644 packages/materials/src/libs/page-tab/index.vue delete mode 100644 packages/materials/src/libs/page-tab/shared.ts delete mode 100644 packages/materials/src/libs/page-tab/svg-close.vue delete mode 100644 packages/materials/src/libs/simple-scrollbar/index.ts delete mode 100644 packages/materials/src/libs/simple-scrollbar/index.vue delete mode 100644 packages/materials/src/types/index.ts delete mode 100644 packages/materials/tsconfig.json delete mode 100644 packages/ofetch/package.json delete mode 100644 packages/ofetch/src/index.ts delete mode 100644 packages/ofetch/tsconfig.json delete mode 100644 packages/plugin-render-naive/.eslintrc.js delete mode 100644 packages/plugin-render-naive/.gitignore delete mode 100644 packages/plugin-render-naive/LICENSE delete mode 100644 packages/plugin-render-naive/README.md delete mode 100644 packages/plugin-render-naive/gulpfile.js delete mode 100644 packages/plugin-render-naive/package.json delete mode 100644 packages/plugin-render-naive/src/form-design/checkbox-widget.ts delete mode 100644 packages/plugin-render-naive/src/form-design/date-picker-widget.ts delete mode 100644 packages/plugin-render-naive/src/form-design/index.ts delete mode 100644 packages/plugin-render-naive/src/form-design/input-widget.ts delete mode 100644 packages/plugin-render-naive/src/form-design/number-input-widget.ts delete mode 100644 packages/plugin-render-naive/src/form-design/radio-widget.ts delete mode 100644 packages/plugin-render-naive/src/form-design/select-widget.ts delete mode 100644 packages/plugin-render-naive/src/form-design/switch-widget.ts delete mode 100644 packages/plugin-render-naive/src/form-design/textarea-widget.ts delete mode 100644 packages/plugin-render-naive/src/form-design/use.ts delete mode 100644 packages/plugin-render-naive/src/form/index.ts delete mode 100644 packages/plugin-render-naive/src/index.ts delete mode 100644 packages/plugin-render-naive/src/table/index.ts delete mode 100644 packages/plugin-render-naive/style.scss delete mode 100644 packages/plugin-render-naive/tsconfig.json delete mode 100644 packages/plugin-render-naive/types/index.d.ts create mode 100644 packages/preferences/package.json create mode 100644 packages/preferences/src/index.ts create mode 100644 packages/preferences/tsconfig.json delete mode 100644 packages/scripts/bin.ts delete mode 100644 packages/scripts/package.json delete mode 100644 packages/scripts/src/commands/changelog.ts delete mode 100644 packages/scripts/src/commands/cleanup.ts delete mode 100644 packages/scripts/src/commands/git-commit.ts delete mode 100644 packages/scripts/src/commands/index.ts delete mode 100644 packages/scripts/src/commands/release.ts delete mode 100644 packages/scripts/src/commands/router.ts delete mode 100644 packages/scripts/src/commands/update-dict.ts delete mode 100644 packages/scripts/src/commands/update-pkg.ts delete mode 100644 packages/scripts/src/config/index.ts delete mode 100644 packages/scripts/src/index.ts delete mode 100644 packages/scripts/src/shared/index.ts delete mode 100644 packages/scripts/src/types/index.ts delete mode 100644 packages/scripts/tsconfig.json create mode 100644 packages/stores/package.json create mode 100644 packages/stores/shim-pinia.d.ts create mode 100644 packages/stores/src/index.ts create mode 100644 packages/stores/src/modules/access.test.ts create mode 100644 packages/stores/src/modules/access.ts create mode 100644 packages/stores/src/modules/index.ts create mode 100644 packages/stores/src/modules/lock.test.ts create mode 100644 packages/stores/src/modules/lock.ts create mode 100644 packages/stores/src/modules/tabbar.test.ts create mode 100644 packages/stores/src/modules/tabbar.ts create mode 100644 packages/stores/src/modules/user.test.ts create mode 100644 packages/stores/src/modules/user.ts create mode 100644 packages/stores/src/setup.ts create mode 100644 packages/stores/tsconfig.json create mode 100644 packages/styles/README.md create mode 100644 packages/styles/package.json create mode 100644 packages/styles/src/antd/index.css create mode 100644 packages/styles/src/ele/index.css create mode 100644 packages/styles/src/global/index.scss create mode 100644 packages/styles/src/index.ts create mode 100644 packages/styles/tsconfig.json create mode 100644 packages/types/README.md create mode 100644 packages/types/global.d.ts create mode 100644 packages/types/package.json create mode 100644 packages/types/src/index.ts create mode 100644 packages/types/src/user.d.ts create mode 100644 packages/types/tsconfig.json delete mode 100644 packages/uno-preset/package.json delete mode 100644 packages/uno-preset/src/index.ts delete mode 100644 packages/uno-preset/tsconfig.json create mode 100644 packages/utils/README.md delete mode 100644 packages/utils/src/crypto.ts create mode 100644 packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts create mode 100644 packages/utils/src/helpers/__tests__/generate-menus.test.ts create mode 100644 packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts create mode 100644 packages/utils/src/helpers/__tests__/merge-route-modules.test.ts create mode 100644 packages/utils/src/helpers/find-menu-by-path.ts create mode 100644 packages/utils/src/helpers/generate-menus.ts create mode 100644 packages/utils/src/helpers/generate-routes-backend.ts create mode 100644 packages/utils/src/helpers/generate-routes-frontend.ts create mode 100644 packages/utils/src/helpers/get-popup-container.ts create mode 100644 packages/utils/src/helpers/index.ts create mode 100644 packages/utils/src/helpers/merge-route-modules.ts create mode 100644 packages/utils/src/helpers/reset-routes.ts create mode 100644 packages/utils/src/helpers/unmount-global-loading.ts delete mode 100644 packages/utils/src/nanoid.ts delete mode 100644 packages/utils/src/storage.ts create mode 100644 playground/.env create mode 100644 playground/.env.analyze create mode 100644 playground/.env.development create mode 100644 playground/.env.production create mode 100644 playground/index.html create mode 100644 playground/package.json create mode 100644 playground/postcss.config.mjs create mode 100644 playground/public/favicon.ico create mode 100644 playground/src/api/core/auth.ts create mode 100644 playground/src/api/core/index.ts create mode 100644 playground/src/api/core/menu.ts create mode 100644 playground/src/api/core/user.ts create mode 100644 playground/src/api/demos/index.ts create mode 100644 playground/src/api/demos/status.ts create mode 100644 playground/src/api/index.ts create mode 100644 playground/src/api/request.ts create mode 100644 playground/src/app.vue create mode 100644 playground/src/bootstrap.ts create mode 100644 playground/src/layouts/basic.vue create mode 100644 playground/src/layouts/index.ts create mode 100644 playground/src/locales/README.md create mode 100644 playground/src/locales/index.ts create mode 100644 playground/src/locales/langs/en-US.json create mode 100644 playground/src/locales/langs/zh-CN.json create mode 100644 playground/src/main.ts create mode 100644 playground/src/preferences.ts create mode 100644 playground/src/router/access.ts create mode 100644 playground/src/router/guard.ts create mode 100644 playground/src/router/index.ts create mode 100644 playground/src/router/routes/core.ts create mode 100644 playground/src/router/routes/index.ts create mode 100644 playground/src/router/routes/modules/dashboard.ts create mode 100644 playground/src/router/routes/modules/demos.ts create mode 100644 playground/src/router/routes/modules/examples.ts create mode 100644 playground/src/router/routes/modules/vben.ts create mode 100644 playground/src/store/auth.ts create mode 100644 playground/src/store/index.ts create mode 100644 playground/src/views/_core/README.md create mode 100644 playground/src/views/_core/about/index.vue create mode 100644 playground/src/views/_core/authentication/code-login.vue create mode 100644 playground/src/views/_core/authentication/forget-password.vue create mode 100644 playground/src/views/_core/authentication/login.vue create mode 100644 playground/src/views/_core/authentication/qrcode-login.vue create mode 100644 playground/src/views/_core/authentication/register.vue create mode 100644 playground/src/views/_core/fallback/coming-soon.vue create mode 100644 playground/src/views/_core/fallback/forbidden.vue create mode 100644 playground/src/views/_core/fallback/internal-error.vue create mode 100644 playground/src/views/_core/fallback/not-found.vue create mode 100644 playground/src/views/_core/fallback/offline.vue create mode 100644 playground/src/views/dashboard/analytics/analytics-trends.vue create mode 100644 playground/src/views/dashboard/analytics/analytics-visits-data.vue create mode 100644 playground/src/views/dashboard/analytics/analytics-visits-sales.vue create mode 100644 playground/src/views/dashboard/analytics/analytics-visits-source.vue create mode 100644 playground/src/views/dashboard/analytics/analytics-visits.vue create mode 100644 playground/src/views/dashboard/analytics/index.vue create mode 100644 playground/src/views/dashboard/workspace/index.vue create mode 100644 playground/src/views/demos/access/admin-visible.vue create mode 100644 playground/src/views/demos/access/button-control.vue create mode 100644 playground/src/views/demos/access/index.vue create mode 100644 playground/src/views/demos/access/menu-visible-403.vue create mode 100644 playground/src/views/demos/access/super-visible.vue create mode 100644 playground/src/views/demos/access/user-visible.vue create mode 100644 playground/src/views/demos/active-icon/index.vue create mode 100644 playground/src/views/demos/badge/index.vue create mode 100644 playground/src/views/demos/breadcrumb/lateral-detail.vue create mode 100644 playground/src/views/demos/breadcrumb/lateral.vue create mode 100644 playground/src/views/demos/breadcrumb/level-detail.vue create mode 100644 playground/src/views/demos/features/clipboard/index.vue create mode 100644 playground/src/views/demos/features/full-screen/index.vue create mode 100644 playground/src/views/demos/features/hide-menu-children/children.vue create mode 100644 playground/src/views/demos/features/hide-menu-children/parent.vue create mode 100644 playground/src/views/demos/features/icons/index.vue create mode 100644 playground/src/views/demos/features/login-expired/index.vue create mode 100644 playground/src/views/demos/features/tabs/index.vue create mode 100644 playground/src/views/demos/features/tabs/tab-detail.vue create mode 100644 playground/src/views/demos/features/watermark/index.vue create mode 100644 playground/src/views/demos/nested/menu-1.vue create mode 100644 playground/src/views/demos/nested/menu-2-1.vue create mode 100644 playground/src/views/demos/nested/menu-3-1.vue create mode 100644 playground/src/views/demos/nested/menu-3-2-1.vue create mode 100644 playground/src/views/examples/doc-button.vue create mode 100644 playground/src/views/examples/drawer/auto-height-demo.vue create mode 100644 playground/src/views/examples/drawer/base-demo.vue create mode 100644 playground/src/views/examples/drawer/dynamic-demo.vue create mode 100644 playground/src/views/examples/drawer/index.vue create mode 100644 playground/src/views/examples/drawer/shared-data-demo.vue create mode 100644 playground/src/views/examples/ellipsis/index.vue create mode 100644 playground/src/views/examples/modal/auto-height-demo.vue create mode 100644 playground/src/views/examples/modal/base-demo.vue create mode 100644 playground/src/views/examples/modal/drag-demo.vue create mode 100644 playground/src/views/examples/modal/dynamic-demo.vue create mode 100644 playground/src/views/examples/modal/index.vue create mode 100644 playground/src/views/examples/modal/shared-data-demo.vue create mode 100644 playground/tailwind.config.mjs create mode 100644 playground/tsconfig.json create mode 100644 playground/tsconfig.node.json create mode 100644 playground/vite.config.mts create mode 100644 scripts/turbo-run/README.md create mode 100644 scripts/turbo-run/bin/turbo-run.mjs create mode 100644 scripts/turbo-run/build.config.ts create mode 100644 scripts/turbo-run/package.json create mode 100644 scripts/turbo-run/src/index.ts create mode 100644 scripts/turbo-run/src/run.ts create mode 100644 scripts/turbo-run/tsconfig.json create mode 100644 scripts/vsh/README.md create mode 100644 scripts/vsh/bin/vsh.mjs create mode 100644 scripts/vsh/build.config.ts create mode 100644 scripts/vsh/package.json create mode 100644 scripts/vsh/src/check-circular/index.ts create mode 100644 scripts/vsh/src/check-dep/index.ts create mode 100644 scripts/vsh/src/clean/index.ts create mode 100644 scripts/vsh/src/code-workspace/index.ts create mode 100644 scripts/vsh/src/index.ts create mode 100644 scripts/vsh/src/lint/index.ts create mode 100644 scripts/vsh/src/publint/index.ts create mode 100644 scripts/vsh/tsconfig.json delete mode 100644 src/App.vue delete mode 100644 src/api/apiDefinitions.ts delete mode 100644 src/api/createApis.ts delete mode 100644 src/api/globals.d.ts delete mode 100644 src/api/index.ts delete mode 100644 src/api/office/bussiness-trip.ts delete mode 100644 src/api/office/canteen.ts delete mode 100644 src/api/office/duty.ts delete mode 100644 src/api/office/meeting.ts delete mode 100644 src/api/office/supervise.ts delete mode 100644 src/api/office/supplies.ts delete mode 100644 src/api/request/utils.ts delete mode 100644 src/api/system/auth.ts delete mode 100644 src/api/system/dept.ts delete mode 100644 src/api/system/dict.ts delete mode 100644 src/api/system/file.ts delete mode 100644 src/api/system/menu.ts delete mode 100644 src/api/system/user.ts delete mode 100644 src/assets/imgs/soybean.jpg delete mode 100644 src/assets/logo.png delete mode 100644 src/assets/meeting/bg35.jpg delete mode 100644 src/assets/svg-icon/activity.svg delete mode 100644 src/assets/svg-icon/at-sign.svg delete mode 100644 src/assets/svg-icon/avatar.svg delete mode 100644 src/assets/svg-icon/banner.svg delete mode 100644 src/assets/svg-icon/cast.svg delete mode 100644 src/assets/svg-icon/chrome.svg delete mode 100644 src/assets/svg-icon/copy.svg delete mode 100644 src/assets/svg-icon/custom-icon.svg delete mode 100644 src/assets/svg-icon/empty-data.svg delete mode 100644 src/assets/svg-icon/expectation.svg delete mode 100644 src/assets/svg-icon/heart.svg delete mode 100644 src/assets/svg-icon/logo.svg delete mode 100644 src/assets/svg-icon/network-error.svg delete mode 100644 src/assets/svg-icon/no-icon.svg delete mode 100644 src/assets/svg-icon/no-permission.svg delete mode 100644 src/assets/svg-icon/not-found.svg delete mode 100644 src/assets/svg-icon/service-error.svg delete mode 100644 src/assets/svg-icon/wind.svg delete mode 100644 src/common/unit.ts delete mode 100644 src/components/DetailModal/index.ts delete mode 100644 src/components/DetailModal/src/DetailModal.vue delete mode 100644 src/components/DictTag/index.ts delete mode 100644 src/components/DictTag/src/DictTag.vue delete mode 100644 src/components/Form/index.ts delete mode 100644 src/components/Form/src/BasicForm.vue delete mode 100644 src/components/Form/src/helper.ts delete mode 100644 src/components/Form/src/hooks/useForm.ts delete mode 100644 src/components/Form/src/hooks/useFormContext.ts delete mode 100644 src/components/Form/src/hooks/useFormEvents.ts delete mode 100644 src/components/Form/src/hooks/useFormValues.ts delete mode 100644 src/components/Form/src/props.ts delete mode 100644 src/components/Form/src/types/form.ts delete mode 100644 src/components/Form/src/types/index.ts delete mode 100644 src/components/Lockscreen/Lockscreen.vue delete mode 100644 src/components/Lockscreen/Recharge.vue delete mode 100644 src/components/Lockscreen/index.ts delete mode 100644 src/components/Modal/index.ts delete mode 100644 src/components/Modal/src/basicModal.vue delete mode 100644 src/components/Modal/src/hooks/useModal.ts delete mode 100644 src/components/Modal/src/props.ts delete mode 100644 src/components/Modal/src/type/index.ts delete mode 100644 src/components/Table/index.ts delete mode 100644 src/components/Table/src/components/TableImg.vue delete mode 100644 src/components/VxeTable/src/VxeBasicTable.tsx delete mode 100644 src/components/advanced/table-column-setting.vue delete mode 100644 src/components/advanced/table-header-operation.vue delete mode 100644 src/components/common/api-select.vue delete mode 100644 src/components/common/api-tree-select.vue delete mode 100644 src/components/common/app-provider.vue delete mode 100644 src/components/common/dark-mode-container.vue delete mode 100644 src/components/common/exception-base.vue delete mode 100644 src/components/common/full-screen.vue delete mode 100644 src/components/common/lang-switch.vue delete mode 100644 src/components/common/menu-toggler.vue delete mode 100644 src/components/common/pin-toggler.vue delete mode 100644 src/components/common/reload-button.vue delete mode 100644 src/components/common/system-logo.vue delete mode 100644 src/components/common/theme-schema-switch.vue delete mode 100644 src/components/custom/better-scroll.vue delete mode 100644 src/components/custom/button-icon.vue delete mode 100644 src/components/custom/count-to.vue delete mode 100644 src/components/custom/look-forward.vue delete mode 100644 src/components/custom/seal.vue delete mode 100644 src/components/custom/soybean-avatar.vue delete mode 100644 src/components/custom/svg-icon.vue delete mode 100644 src/components/custom/wave-bg.vue delete mode 100644 src/constants/app.ts delete mode 100644 src/constants/business.ts delete mode 100644 src/constants/common.ts delete mode 100644 src/constants/reg.ts delete mode 100644 src/enums/breakpointEnum.ts delete mode 100644 src/enums/cacheEnum.ts delete mode 100644 src/enums/httpEnum.ts delete mode 100644 src/enums/index.ts delete mode 100644 src/enums/pageEnum.ts delete mode 100644 src/enums/permissionsEnum.ts delete mode 100644 src/enums/roleEnum.ts delete mode 100644 src/enums/systemMessageEnum.ts delete mode 100644 src/env.d.ts delete mode 100644 src/hooks/business/auth.ts delete mode 100644 src/hooks/business/captcha.ts delete mode 100644 src/hooks/common/alova.ts delete mode 100644 src/hooks/common/echarts.ts delete mode 100644 src/hooks/common/form.ts delete mode 100644 src/hooks/common/icon.ts delete mode 100644 src/hooks/common/router.ts delete mode 100644 src/hooks/common/table.ts delete mode 100644 src/layouts/base-layout/index.vue delete mode 100644 src/layouts/blank-layout/index.vue delete mode 100644 src/layouts/context/index.ts delete mode 100644 src/layouts/modules/global-breadcrumb/index.vue delete mode 100644 src/layouts/modules/global-content/index.vue delete mode 100644 src/layouts/modules/global-footer/index.vue delete mode 100644 src/layouts/modules/global-header/components/message-list.vue delete mode 100644 src/layouts/modules/global-header/components/system-message.vue delete mode 100644 src/layouts/modules/global-header/components/theme-button.vue delete mode 100644 src/layouts/modules/global-header/components/todo-message.vue delete mode 100644 src/layouts/modules/global-header/components/user-avatar.vue delete mode 100644 src/layouts/modules/global-header/index.vue delete mode 100644 src/layouts/modules/global-logo/index.vue delete mode 100644 src/layouts/modules/global-menu/base-menu.vue delete mode 100644 src/layouts/modules/global-menu/first-level-menu.vue delete mode 100644 src/layouts/modules/global-menu/horizontal-mix-menu.vue delete mode 100644 src/layouts/modules/global-menu/vertical-mix-menu.vue delete mode 100644 src/layouts/modules/global-search/components/search-footer.vue delete mode 100644 src/layouts/modules/global-search/components/search-modal.vue delete mode 100644 src/layouts/modules/global-search/components/search-result.vue delete mode 100644 src/layouts/modules/global-search/index.vue delete mode 100644 src/layouts/modules/global-sider/index.vue delete mode 100644 src/layouts/modules/global-tab/context-menu.vue delete mode 100644 src/layouts/modules/global-tab/index.vue delete mode 100644 src/layouts/modules/theme-drawer/components/layout-mode-card.vue delete mode 100644 src/layouts/modules/theme-drawer/components/setting-item.vue delete mode 100644 src/layouts/modules/theme-drawer/index.vue delete mode 100644 src/layouts/modules/theme-drawer/modules/config-operation.vue delete mode 100644 src/layouts/modules/theme-drawer/modules/dark-mode.vue delete mode 100644 src/layouts/modules/theme-drawer/modules/layout-mode.vue delete mode 100644 src/layouts/modules/theme-drawer/modules/page-fun.vue delete mode 100644 src/layouts/modules/theme-drawer/modules/theme-color.vue delete mode 100644 src/locales/dayjs.ts delete mode 100644 src/locales/index.ts delete mode 100644 src/locales/langs/en-us.ts delete mode 100644 src/locales/langs/zh-cn.ts delete mode 100644 src/locales/locale.ts delete mode 100644 src/locales/naive.ts delete mode 100644 src/main.ts delete mode 100644 src/plugins/assets.ts delete mode 100644 src/plugins/dayjs.ts delete mode 100644 src/plugins/iconify.ts delete mode 100644 src/plugins/index.ts delete mode 100644 src/plugins/loading.ts delete mode 100644 src/plugins/naive.ts delete mode 100644 src/plugins/nprogress.ts delete mode 100644 src/router/elegant/imports.ts delete mode 100644 src/router/elegant/routes.ts delete mode 100644 src/router/elegant/transform.ts delete mode 100644 src/router/guard/index.ts delete mode 100644 src/router/guard/progress.ts delete mode 100644 src/router/guard/route.ts delete mode 100644 src/router/guard/title.ts delete mode 100644 src/router/index.ts delete mode 100644 src/router/routes/builtin.ts delete mode 100644 src/router/routes/index.ts delete mode 100644 src/router/routes/router.data.ts delete mode 100644 src/settings/encryptionSetting.ts delete mode 100644 src/store/index.ts delete mode 100644 src/store/modules/app/index.ts delete mode 100644 src/store/modules/notification.ts delete mode 100644 src/store/modules/route/index.ts delete mode 100644 src/store/modules/route/shared.ts delete mode 100644 src/store/modules/tab/index.ts delete mode 100644 src/store/modules/tab/shared.ts delete mode 100644 src/store/modules/theme/index.ts delete mode 100644 src/store/modules/theme/shared.ts delete mode 100644 src/store/modules/user.ts delete mode 100644 src/store/mutation-types.ts delete mode 100644 src/store/plugins/index.ts delete mode 100644 src/styles/css/global.css delete mode 100644 src/styles/css/nprogress.css delete mode 100644 src/styles/css/reset.css delete mode 100644 src/styles/css/transition.css delete mode 100644 src/styles/scss/global.scss delete mode 100644 src/styles/scss/scrollbar.scss delete mode 100644 src/theme/settings.ts delete mode 100644 src/theme/vars.ts delete mode 100644 src/types/api.d.ts delete mode 100644 src/types/app.d.ts delete mode 100644 src/types/common.d.ts delete mode 100644 src/types/components.d.ts delete mode 100644 src/types/elegant-router.d.ts delete mode 100644 src/types/env.d.ts delete mode 100644 src/types/global.d.ts delete mode 100644 src/types/naive-ui.d.ts delete mode 100644 src/types/router.d.ts delete mode 100644 src/types/storage.d.ts delete mode 100644 src/types/store.d.ts delete mode 100644 src/types/union-key.d.ts delete mode 100644 src/typings/elegant-router.d.ts delete mode 100644 src/utils/alova.ts delete mode 100644 src/utils/cache/index.ts delete mode 100644 src/utils/cache/memory.ts delete mode 100644 src/utils/cache/persistent.ts delete mode 100644 src/utils/cache/storageCache.ts delete mode 100644 src/utils/cipher.ts delete mode 100644 src/utils/common.ts delete mode 100644 src/utils/drag.ts delete mode 100644 src/utils/env.ts delete mode 100644 src/utils/file.ts delete mode 100644 src/utils/icon.ts delete mode 100644 src/utils/is.ts delete mode 100644 src/utils/logger.ts delete mode 100644 src/utils/propTypes.ts delete mode 100644 src/utils/service.ts delete mode 100644 src/utils/storage.ts delete mode 100644 src/utils/vxeTable.ts delete mode 100644 src/views/_builtin/403/index.vue delete mode 100644 src/views/_builtin/404/index.vue delete mode 100644 src/views/_builtin/500/index.vue delete mode 100644 src/views/_builtin/iframe-page/[url].vue delete mode 100644 src/views/_builtin/login/index.vue delete mode 100644 src/views/_builtin/login/modules/bind-wechat.vue delete mode 100644 src/views/_builtin/login/modules/code-login.vue delete mode 100644 src/views/_builtin/login/modules/pwd-login.vue delete mode 100644 src/views/_builtin/login/modules/register.vue delete mode 100644 src/views/_builtin/login/modules/reset-pwd.vue delete mode 100644 src/views/about/index.vue delete mode 100644 src/views/bussiness-trip/edit/[id].vue delete mode 100644 src/views/bussiness-trip/home/TripAuditModal.vue delete mode 100644 src/views/bussiness-trip/home/TripEditModal.vue delete mode 100644 src/views/bussiness-trip/home/components/AuditDone.vue delete mode 100644 src/views/bussiness-trip/home/components/AuditTodo.vue delete mode 100644 src/views/bussiness-trip/home/index.vue delete mode 100644 src/views/bussiness-trip/todo/index.vue delete mode 100644 src/views/bussiness-trip/todo/schema.ts delete mode 100644 src/views/canteen/collect/index.vue delete mode 100644 src/views/canteen/components/personal-statistics/personal-statistics.vue delete mode 100644 src/views/canteen/components/personal-statistics/schema.ts delete mode 100644 src/views/canteen/config/components/auto-people/AutoPeople.vue delete mode 100644 src/views/canteen/config/components/auto-people/AutoPeopleBatchAddModal.vue delete mode 100644 src/views/canteen/config/components/auto-people/AutoPeopleEditModal.vue delete mode 100644 src/views/canteen/config/components/basic-settings/BasicSettings.vue delete mode 100644 src/views/canteen/config/components/delivery-address/delivery-address.vue delete mode 100644 src/views/canteen/config/components/delivery-address/schema.ts delete mode 100644 src/views/canteen/config/components/duty-people/AutoPeopleBatchAddModal.vue delete mode 100644 src/views/canteen/config/components/duty-people/AutoPeopleEditModal.vue delete mode 100644 src/views/canteen/config/components/duty-people/duty-people.vue delete mode 100644 src/views/canteen/config/components/duty-people/schema.ts delete mode 100644 src/views/canteen/config/index.vue delete mode 100644 src/views/canteen/menu/MenuEditModal.vue delete mode 100644 src/views/canteen/menu/index.vue delete mode 100644 src/views/canteen/menu/modules/ChooseMenuModal.vue delete mode 100644 src/views/canteen/menu/modules/MenuCard.vue delete mode 100644 src/views/canteen/menu/schema.ts delete mode 100644 src/views/canteen/orderfood/index.vue delete mode 100644 src/views/canteen/recipe/RecipeEditModal.vue delete mode 100644 src/views/canteen/recipe/RecipeSyncModal.vue delete mode 100644 src/views/canteen/recipe/RecipeUploadModal.vue delete mode 100644 src/views/canteen/recipe/index.vue delete mode 100644 src/views/canteen/statistics/index.vue delete mode 100644 src/views/canteen/statistics/schema.ts delete mode 100644 src/views/contract/approval/edit/[id].vue delete mode 100644 src/views/contract/approval/list/index.vue delete mode 100644 src/views/contract/approval/list/schema.ts delete mode 100644 src/views/contract/approval/todo/index.vue delete mode 100644 src/views/contract/approval/todo/schema.ts delete mode 100644 src/views/contract/archive/edit/[id].vue delete mode 100644 src/views/contract/archive/list/index.vue delete mode 100644 src/views/contract/archive/list/schema.ts delete mode 100644 src/views/contract/audit/edit/[id].vue delete mode 100644 src/views/contract/audit/list/index.vue delete mode 100644 src/views/contract/audit/list/schema.ts delete mode 100644 src/views/contract/audit/todo/index.vue delete mode 100644 src/views/contract/audit/todo/schema.ts delete mode 100644 src/views/contract/business/edit/[id].vue delete mode 100644 src/views/contract/business/list/index.vue delete mode 100644 src/views/contract/business/list/schema.ts delete mode 100644 src/views/contract/business/todo/index.vue delete mode 100644 src/views/contract/business/todo/schema.ts delete mode 100644 src/views/contract/company/edit/[id].vue delete mode 100644 src/views/contract/company/list/DetailModal.vue delete mode 100644 src/views/contract/company/list/index.vue delete mode 100644 src/views/contract/company/list/schema.ts delete mode 100644 src/views/contract/config/components/basis-contract/basis-contract.vue delete mode 100644 src/views/contract/config/components/basis-contract/schema.ts delete mode 100644 src/views/contract/config/components/company-manager/company-manager.vue delete mode 100644 src/views/contract/config/components/company-manager/schema.ts delete mode 100644 src/views/contract/config/components/contract-type/EditModal.vue delete mode 100644 src/views/contract/config/components/contract-type/contract-type.vue delete mode 100644 src/views/contract/config/components/project-manager/EditModal.vue delete mode 100644 src/views/contract/config/components/project-manager/project-manager.vue delete mode 100644 src/views/contract/config/components/project-manager/schema.ts delete mode 100644 src/views/contract/config/components/project-name-manager/EditModal.vue delete mode 100644 src/views/contract/config/components/project-name-manager/project-name-manager.vue delete mode 100644 src/views/contract/config/components/project-name-manager/schema.ts delete mode 100644 src/views/contract/config/components/template-manager/EditModal.vue delete mode 100644 src/views/contract/config/components/template-manager/template-manager.vue delete mode 100644 src/views/contract/config/index.vue delete mode 100644 src/views/contract/declaration/edit/[id].vue delete mode 100644 src/views/contract/declaration/list/index.vue delete mode 100644 src/views/contract/declaration/list/schema.ts delete mode 100644 src/views/contract/declaration/todo/index.vue delete mode 100644 src/views/contract/declaration/todo/schema.ts delete mode 100644 src/views/contract/perform/components/contract-break/contract-break.vue delete mode 100644 src/views/contract/perform/components/contract-modify/contract-modify.vue delete mode 100644 src/views/contract/perform/components/contract-payment/contract-payment.vue delete mode 100644 src/views/contract/perform/components/contract-relieve/contract-relieve.vue delete mode 100644 src/views/contract/perform/edit/[id].vue delete mode 100644 src/views/contract/perform/list/index.vue delete mode 100644 src/views/contract/perform/list/schema.ts delete mode 100644 src/views/contract/perform/result/index.vue delete mode 100644 src/views/contract/perform/result/schema.ts delete mode 100644 src/views/contract/perform/todo/index.vue delete mode 100644 src/views/contract/perform/todo/schema.ts delete mode 100644 src/views/contract/sign/edit/[id].vue delete mode 100644 src/views/contract/sign/list/index.vue delete mode 100644 src/views/contract/sign/list/schema.ts delete mode 100644 src/views/contract/sign/todo/index.vue delete mode 100644 src/views/contract/sign/todo/schema.ts delete mode 100644 src/views/duty/list/DutyEditModal.vue delete mode 100644 src/views/duty/list/DutyUploadModal.vue delete mode 100644 src/views/duty/list/index.vue delete mode 100644 src/views/duty/list/schema.ts delete mode 100644 src/views/flow/home/index.vue delete mode 100644 src/views/function/hide-child/one/index.vue delete mode 100644 src/views/function/hide-child/three/index.vue delete mode 100644 src/views/function/hide-child/two/index.vue delete mode 100644 src/views/function/multi-tab/index.vue delete mode 100644 src/views/function/super-page/index.vue delete mode 100644 src/views/function/tab/index.vue delete mode 100644 src/views/function/toggle-auth/index.vue delete mode 100644 src/views/home/index.vue delete mode 100644 src/views/home/modules/card-data.vue delete mode 100644 src/views/home/modules/creativity-banner.vue delete mode 100644 src/views/home/modules/header-banner.vue delete mode 100644 src/views/home/modules/line-chart.vue delete mode 100644 src/views/home/modules/pie-chart.vue delete mode 100644 src/views/home/modules/project-news.vue delete mode 100644 src/views/iframe/contract/info/components/Approval/approval.vue delete mode 100644 src/views/iframe/contract/info/components/Archived/archived.vue delete mode 100644 src/views/iframe/contract/info/components/Business/business.vue delete mode 100644 src/views/iframe/contract/info/components/Declaration/declaration.vue delete mode 100644 src/views/iframe/contract/info/components/Execution/execution.vue delete mode 100644 src/views/iframe/contract/info/components/Perform/perform.vue delete mode 100644 src/views/iframe/contract/info/components/Track/track.vue delete mode 100644 src/views/iframe/contract/info/index.vue delete mode 100644 src/views/iframe/meeting/spokesperson/index.vue delete mode 100644 src/views/iframe/meeting/standing-book/index.vue delete mode 100644 src/views/meeting/edit/[id].vue delete mode 100644 src/views/meeting/edit/file.hooks.ts delete mode 100644 src/views/meeting/home/EditSpokenPersonModal.vue delete mode 100644 src/views/meeting/home/MeetingEditModal.vue delete mode 100644 src/views/meeting/home/MeetingRecordModal.vue delete mode 100644 src/views/meeting/home/MeetingSpokespersonModal.vue delete mode 100644 src/views/meeting/home/index.vue delete mode 100644 src/views/message/todo/index.vue delete mode 100644 src/views/multi-menu/first_child/index.vue delete mode 100644 src/views/multi-menu/second_child_home/index.vue delete mode 100644 src/views/office-supplies/apply/ApplyEditModal.vue delete mode 100644 src/views/office-supplies/apply/index.vue delete mode 100644 src/views/office-supplies/apply/schema.ts delete mode 100644 src/views/office-supplies/audit/PromptModal.vue delete mode 100644 src/views/office-supplies/audit/SuppliesAuditModal.vue delete mode 100644 src/views/office-supplies/audit/index.vue delete mode 100644 src/views/office-supplies/audit/schema.ts delete mode 100644 src/views/office-supplies/inventory/ChooseSuppliesModal.vue delete mode 100644 src/views/office-supplies/inventory/InventoryEditModal.vue delete mode 100644 src/views/office-supplies/inventory/InventoryOutModal.vue delete mode 100644 src/views/office-supplies/inventory/InventoryPutModal.vue delete mode 100644 src/views/office-supplies/inventory/PurchaseSummaryModal.vue delete mode 100644 src/views/office-supplies/inventory/index.vue delete mode 100644 src/views/office-supplies/inventory/render.ts delete mode 100644 src/views/office-supplies/inventory/schema.ts delete mode 100644 src/views/office-supplies/purchase/index.vue delete mode 100644 src/views/supervise/edit/[id].vue delete mode 100644 src/views/supervise/feedback/index.vue delete mode 100644 src/views/supervise/list/BatchAddModal.vue delete mode 100644 src/views/supervise/list/DetailDrawer.vue delete mode 100644 src/views/supervise/list/DetailModal.vue delete mode 100644 src/views/supervise/list/EditDetailModal.vue delete mode 100644 src/views/supervise/list/EditModal.vue delete mode 100644 src/views/supervise/list/index.vue delete mode 100644 src/views/supervise/list/schema.ts delete mode 100644 src/views/supervise/statistics/index.vue delete mode 100644 src/views/supervise/statistics/schema.ts delete mode 100644 src/views/system/department/components/ChooseDeptModal.vue delete mode 100644 src/views/system/dict/DictDataEditModal.vue delete mode 100644 src/views/system/dict/DictTypeEditModal.vue delete mode 100644 src/views/system/dict/index.vue delete mode 100644 src/views/system/dict/schema.ts delete mode 100644 src/views/user-center/ChooseUserModal.vue delete mode 100644 src/views/user-center/index.vue delete mode 100644 src/views/user-center/render.ts create mode 100644 stylelint.config.mjs create mode 100644 tea.yaml delete mode 100644 tsconfig.json create mode 100644 turbo.json delete mode 100644 uno.config.ts create mode 100644 vben-admin.code-workspace delete mode 100644 vite.config.ts create mode 100644 vitest.config.ts create mode 100644 vitest.workspace.ts diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 00000000..dc3bc09a --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,4 @@ +> 1% +last 2 versions +not dead +not ie 11 diff --git a/.commitlintrc.mjs b/.commitlintrc.mjs new file mode 100644 index 00000000..02e33fa6 --- /dev/null +++ b/.commitlintrc.mjs @@ -0,0 +1 @@ +export { default } from '@vben/commitlint-config'; diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..4f75c951 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.git +.gitignore +*.md +dist diff --git a/.editorconfig b/.editorconfig index 0552777e..179aec6f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,11 +1,18 @@ -# Editor configuration, see http://editorconfig.org - root = true [*] -charset = utf-8 +charset=utf-8 +end_of_line=lf +insert_final_newline=true +indent_style=space +indent_size=2 +max_line_length = 100 +trim_trailing_whitespace = true +quote_type = single + +[*.{yml,yaml,json}] indent_style = space indent_size = 2 -end_of_line = lf -trim_trailing_whitespace = true -insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.env b/.env deleted file mode 100644 index 72b39275..00000000 --- a/.env +++ /dev/null @@ -1,48 +0,0 @@ -VITE_BASE_URL=/ - -VITE_APP_TITLE=ERP 综合办公系统 - -VITE_APP_DESC= - -# the prefix of the icon name -VITE_ICON_PREFIX=icon - -# the prefix of the local svg icon component, must include VITE_ICON_PREFIX -# format {VITE_ICON_PREFIX}-{local icon name} -VITE_ICON_LOCAL_PREFIX=icon-local - -# 路由模式: static 静态 | dynamic 动态 -VITE_AUTH_ROUTE_MODE=dynamic - -# static 静态路由首页地址 -VITE_ROUTE_HOME=home - -# 默认菜单图标 -VITE_MENU_ICON=mdi:menu - -# 当在开发模式下,是否使用代理 -VITE_HTTP_PROXY=Y - -# vue-router 路由模式: hash | history | memory -VITE_ROUTER_HISTORY_MODE=history - -# success code of backend service, when the code is received, the request is successful -VITE_SERVICE_SUCCESS_CODE=200 - -# logout codes of backend service, when the code is received, the user will be logged out and redirected to login page -VITE_SERVICE_LOGOUT_CODES=8888,8889 - -# modal logout codes of backend service, when the code is received, the user will be logged out by displaying a modal -VITE_SERVICE_MODAL_LOGOUT_CODES=7777,7778 - -# token expired codes of backend service, when the code is received, it will refresh the token and resend the request -VITE_SERVICE_EXPIRED_TOKEN_CODES=9999,9998 - -# when the route mode is static, the defined super role -VITE_STATIC_SUPER_ROLE=R_SUPER - -# sourcemap -VITE_SOURCE_MAP=N - -# Used to differentiate storage across different domains -VITE_STORAGE_PREFIX=app_ diff --git a/.env.prod b/.env.prod deleted file mode 100644 index 832d4d6c..00000000 --- a/.env.prod +++ /dev/null @@ -1,7 +0,0 @@ -# backend service base url, prod environment -VITE_SERVICE_BASE_URL=https://mock.apifox.com/m1/3109515-0-default - -# other backend service base url, prod environment -VITE_OTHER_SERVICE_BASE_URL= `{ - "demo": "http://localhost:9529" -}` diff --git a/.env.test b/.env.test deleted file mode 100644 index 98181738..00000000 --- a/.env.test +++ /dev/null @@ -1,7 +0,0 @@ -# backend service base url, prod environment -VITE_SERVICE_BASE_URL=http://192.168.147.238:8083 - -# other backend service base url, prod environment -VITE_OTHER_SERVICE_BASE_URL= `{ - "demo": "http://localhost:9529" -}` diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 5ac65678..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ['antfu'], -}; diff --git a/.gitattributes b/.gitattributes index 9553ccb8..d4e5bd3e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,13 +1,11 @@ -"*.vue" eol=lf -"*.js" eol=lf -"*.ts" eol=lf -"*.jsx" eol=lf -"*.tsx" eol=lf -"*.mjs" eol=lf -"*.json" eol=lf -"*.html" eol=lf -"*.css" eol=lf -"*.scss" eol=lf -"*.md" eol=lf -"*.yaml" eol=lf -"*.yml" eol=lf +# https://docs.github.com/cn/get-started/getting-started-with-git/configuring-git-to-handle-line-endings + +# Automatically normalize line endings (to LF) for all text-based files. +* text=auto eol=lf + +# Declare files that will always have CRLF line endings on checkout. +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.{ico,png,jpg,jpeg,gif,webp,svg,woff,woff2} binary \ No newline at end of file diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 00000000..4b28a69c --- /dev/null +++ b/.gitconfig @@ -0,0 +1,2 @@ +[core] + ignorecase = false diff --git a/.gitignore b/.gitignore index 51099144..c2a8a771 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,33 @@ -# Logs +node_modules +.DS_Store +dist +dist-ssr +dist.zip +dist.tar +dist.war +.nitro +.output +*-dist.zip +*-dist.tar +*-dist.war +coverage +*.local +**/.vitepress/cache +.cache +.turbo +.temp +dev-dist +.stylelintcache +yarn.lock +package-lock.json +.VSCodeCounter +**/backend-mock/data + +# local env files +.env.local +.env.*.local +.eslintcache + logs *.log npm-debug.log* @@ -6,31 +35,17 @@ yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* - -node_modules -.DS_Store -dist -dist-ssr -coverage -*.local - -/cypress/videos/ -/cypress/screenshots/ +vite.config.mts.* +vite.config.mjs.* +vite.config.js.* +vite.config.ts.* # Editor directories and files -.vscode/* -!.vscode/extensions.json -!.vscode/settings.json -!.vscode/launch.json .idea +# .vscode *.suo *.ntvs* *.njsproj *.sln *.sw? - -package-lock.json -yarn.lock .history -.VSCodeCounter -vite.config.ts.** diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000..2192d953 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,6 @@ +ports: + - port: 5555 + onOpen: open-preview +tasks: + - init: corepack enable && pnpm install + command: pnpm run dev diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 00000000..270ebb8c --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,6 @@ +echo Start running commit-msg hook... + +# Check whether the git commit information is standardized +pnpm exec commitlint --edit "$1" + +echo Run commit-msg hook done. diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100644 index 00000000..83fa775d --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1,3 @@ +# 每次 git pull 之后, 安装依赖 + +pnpm install diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..5dccee28 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,7 @@ +# update `.vscode/vben-admin.code-workspace` file +pnpm vsh code-workspace --auto-commit + +# Format and submit code according to lintstagedrc.js configuration +pnpm exec lint-staged + +echo Run pre-commit hook done. diff --git a/.lintstagedrc.mjs b/.lintstagedrc.mjs new file mode 100644 index 00000000..3deda6c2 --- /dev/null +++ b/.lintstagedrc.mjs @@ -0,0 +1,20 @@ +export default { + '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [ + 'prettier --cache --write--parser json', + ], + '*.{js,jsx,ts,tsx}': [ + 'prettier --cache --ignore-unknown --write', + 'eslint --cache --fix', + ], + '*.{scss,less,styl,html,vue,css}': [ + 'prettier --cache --ignore-unknown --write', + 'stylelint --fix --allow-empty-input', + ], + '*.md': ['prettier --cache --ignore-unknown --write'], + '*.vue': [ + 'prettier --write', + 'eslint --cache --fix', + 'stylelint --fix --allow-empty-input', + ], + 'package.json': ['prettier --cache --write'], +}; diff --git a/.ls-lint.yml b/.ls-lint.yml new file mode 100644 index 00000000..7f8b7ce6 --- /dev/null +++ b/.ls-lint.yml @@ -0,0 +1,28 @@ +ls: + .js: kebab-case | pointcase + .vue: kebab-case | pointcase + .ts: kebab-case | pointcase + .tsx: kebab-case | pointcase + .jsx: kebab-case | pointcase + .css: kebab-case | pointcase + .d.ts: kebab-case | pointcase + # shadcn 自动生成文件为 PascalCase 格式 + packages/@core/ui-kit/shadcn-ui/src/components/ui: + .vue: PascalCase + +ignore: + - "**/*.png" + - "**/*.jpg" + - "**/*.jpeg" + - "**/*.jpeg" + - "**/*.gif" + - "**/_util.ts" + - "**/deps/**" + - "**/dist/**" + - "**/node_modules/**" + - "**/.turbo/**" + - .git + - .vscode + - .idea + - node_modules + - .cache diff --git a/.node-version b/.node-version new file mode 100644 index 00000000..48b14e6b --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +20.14.0 diff --git a/.npmrc b/.npmrc index dfc2d686..f4a1ad48 100644 --- a/.npmrc +++ b/.npmrc @@ -1,4 +1,13 @@ -registry=https://registry.npmmirror.com/ -shamefully-hoist=true -ignore-workspace-root-check=true -link-workspace-packages=true +registry = "https://registry.npmmirror.com" +public-hoist-pattern[]=husky +public-hoist-pattern[]=eslint +public-hoist-pattern[]=prettier +public-hoist-pattern[]=prettier-plugin-tailwindcss +public-hoist-pattern[]=stylelint +public-hoist-pattern[]=*postcss* +public-hoist-pattern[]=@commitlint/* +public-hoist-pattern[]=czg + +strict-peer-dependencies=false +auto-install-peers=true +dedupe-peer-dependents=true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..d0b0ca13 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,18 @@ +dist +dev-dist +.local +.output.js +node_modules +.nvmrc +coverage +CODEOWNERS +.nitro +.output + + +**/*.svg +**/*.sh + +public +.npmrc +*-lock.yaml diff --git a/.prettierrc.mjs b/.prettierrc.mjs new file mode 100644 index 00000000..3e25d2cf --- /dev/null +++ b/.prettierrc.mjs @@ -0,0 +1 @@ +export { default } from '@vben/prettier-config'; diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 00000000..f4b2db2c --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,4 @@ +dist +public +__tests__ +coverage diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c4cbb7c9..cf48052d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,34 +1,28 @@ { "recommendations": [ - // my extensions, ofc :P - "antfu.browse-lite", - "antfu.iconify", - "antfu.slidev", - "antfu.unocss", - "antfu.vite", - "antfu.where-am-i", - "antfu.open-in-github-button", - "lokalise.i18n-ally", - // themes & icons - "antfu.icons-carbon", - "antfu.theme-vitesse", - "file-icons.file-icons", - "sainnhe.gruvbox-material", - // life savers! - "dbaeumer.vscode-eslint", + // Vue 3 的语言支持 "Vue.volar", - "GitHub.copilot", - "usernamehw.errorlens", + // 将 ESLint JavaScript 集成到 VS Code 中。 + "dbaeumer.vscode-eslint", + // Visual Studio Code 的官方 Stylelint 扩展 + "stylelint.vscode-stylelint", + // 使用 Prettier 的代码格式化程序 + "esbenp.prettier-vscode", + // 支持 dotenv 文件语法 + "mikestead.dotenv", + // 源代码的拼写检查器 "streetsidesoftware.code-spell-checker", - // up to you - "eamodio.gitlens", - "EditorConfig.EditorConfig", - "github.vscode-github-actions", - "GitHub.vscode-pull-request-github", - "johnsoncodehk.vscode-tsconfig-helper", - "mpontus.tab-cycle", - "naumovs.color-highlight", - "WakaTime.vscode-wakatime", - "znck.grammarly" + // Tailwind CSS 的官方 VS Code 插件 + "bradlc.vscode-tailwindcss", + // iconify 图标插件 + "antfu.iconify", + // i18n 插件 + "Lokalise.i18n-ally", + // CSS 变量提示 + "vunguyentuan.vscode-css-variables" + ], + "unwantedRecommendations": [ + // 和 volar 冲突 + "octref.vetur" ] } diff --git a/.vscode/global.code-snippets b/.vscode/global.code-snippets new file mode 100644 index 00000000..7604b014 --- /dev/null +++ b/.vscode/global.code-snippets @@ -0,0 +1,37 @@ +{ + "import": { + "scope": "javascript,typescript", + "prefix": "im", + "body": ["import { $2 } from '$1';"], + "description": "Import a module", + }, + "export-all": { + "scope": "javascript,typescript", + "prefix": "ex", + "body": ["export * from '$1';"], + "description": "Export a module", + }, + "vue-script-setup": { + "scope": "vue", + "prefix": "", + "const props = defineProps<{", + " modelValue?: boolean,", + "}>()", + "$1", + "", + "", + "", + ], + }, + "vue-computed": { + "scope": "javascript,typescript,vue", + "prefix": "com", + "body": ["computed(() => { $1 })"], + }, +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..3b4e323c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "name": "vben admin playground dev", + "request": "launch", + "url": "http://localhost:5555", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/playground/src" + }, + { + "type": "chrome", + "name": "vben admin antd dev", + "request": "launch", + "url": "http://localhost:5666", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/apps/web-antd/src" + }, + { + "type": "chrome", + "name": "vben admin ele dev", + "request": "launch", + "url": "http://localhost:5777", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/apps/web-ele/src" + }, + { + "type": "chrome", + "name": "vben admin naive dev", + "request": "launch", + "url": "http://localhost:5888", + "env": { "NODE_ENV": "development" }, + "sourceMaps": true, + "webRoot": "${workspaceFolder}/apps/web-naive/src" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 7b6acfa7..95f6e14a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,304 +1,228 @@ { - // ========== Visuals ========== - "editor.cursorSmoothCaretAnimation": "on", - // "editor.fontFamily": "Input Mono, monospace", - "editor.guides.bracketPairs": "active", - "editor.lineNumbers": "interval", - "editor.renderWhitespace": "boundary", - "window.autoDetectColorScheme": true, - "workbench.colorTheme": "Vitesse Dark Soft", - "workbench.editor.tabActionLocation": "left", - "workbench.fontAliasing": "antialiased", - "workbench.iconTheme": "file-icons-colourless", + "tailwindCSS.experimental.configFile": "internal/tailwind-config/src/index.ts", + // workbench "workbench.list.smoothScrolling": true, - "workbench.preferredDarkColorTheme": "Vitesse Dark", - "workbench.preferredLightColorTheme": "Vitesse Dark Soft", - "workbench.productIconTheme": "icons-carbon", - "workbench.sideBar.location": "right", "workbench.startupEditor": "newUntitledFile", - "workbench.tree.expandMode": "singleClick", "workbench.tree.indent": 10, - // ========== Editor ========== - "debug.onTaskErrors": "debugAnyway", - "diffEditor.ignoreTrimWhitespace": true, - "editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?", - "editor.find.addExtraSpaceOnTop": false, - "editor.inlineSuggest.enabled": true, - "editor.multiCursorModifier": "ctrlCmd", - "editor.suggestSelection": "first", - "editor.tabSize": 2, - "editor.unicodeHighlight.invisibleCharacters": false, - "editor.stickyScroll.enabled": true, - "editor.hover.sticky": true, - "editor.codeActionsOnSave": { - "source.fixAll": "never", - "source.fixAll.eslint": "explicit", - "source.organizeImports": "never" - }, - "explorer.confirmDelete": false, - "explorer.confirmDragAndDrop": false, - "files.eol": "\n", - "files.insertFinalNewline": true, - "files.simpleDialog.enable": true, - "git.autofetch": true, - "git.confirmSync": false, - "git.enableSmartCommit": true, - "git.untrackedChanges": "separate", - "scm.diffDecorationsGutterWidth": 2, - "terminal.integrated.cursorBlinking": true, - "terminal.integrated.cursorStyle": "line", - "terminal.integrated.fontWeight": "300", - "terminal.integrated.persistentSessionReviveProcess": "never", - "terminal.integrated.tabs.enabled": true, - "workbench.editor.closeOnFileDelete": true, "workbench.editor.highlightModifiedTabs": true, + "workbench.editor.closeOnFileDelete": true, "workbench.editor.limit.enabled": true, "workbench.editor.limit.perEditorGroup": true, "workbench.editor.limit.value": 5, - "search.exclude": { - "**/*.snap": true, - "**/*.svg": true, - "**/.git": true, - "**/.github": false, - "**/.nuxt": true, - "**/.output": true, - "**/.pnpm": true, - "**/.vscode": true, - "**/.yarn": true, - "**/assets": true, - "**/bower_components": true, - "**/dist/**": true, - "**/logs": true, - "**/node_modules": true, - "**/out/**": true, - "**/package-lock.json": true, - "**/pnpm-lock.yaml": true, - "**/public": true, - "**/temp": true, - "**/yarn.lock": true, - "**/CHANGELOG*": true, - "**/LICENSE*": true, + + // editor + "editor.tabSize": 2, + "editor.detectIndentation": false, + "editor.cursorBlinking": "expand", + "editor.largeFileOptimizations": false, + "editor.accessibilitySupport": "off", + "editor.cursorSmoothCaretAnimation": "on", + "editor.guides.bracketPairs": "active", + "editor.inlineSuggest.enabled": true, + "editor.suggestSelection": "recentlyUsedByPrefix", + "editor.acceptSuggestionOnEnter": "smart", + "editor.suggest.snippetsPreventQuickSuggestions": false, + "editor.stickyScroll.enabled": true, + "editor.hover.sticky": true, + "editor.suggest.insertMode": "replace", + "editor.bracketPairColorization.enabled": true, + "editor.autoClosingBrackets": "beforeWhitespace", + "editor.autoClosingDelete": "always", + "editor.autoClosingOvertype": "always", + "editor.autoClosingQuotes": "beforeWhitespace", + "editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "explicit", + "source.organizeImports": "never" }, - // ========== Global Level Config, needs to put in User Settings ========== - "window.dialogStyle": "custom", - "window.nativeTabs": true, // this is great, macOS only - "window.title": "${rootName}", // this make tabs more readable - "window.titleBarStyle": "custom", - "extensions.autoUpdate": "onlyEnabledExtensions", - // ========== Extension configs ========== + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[html]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[scss]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "vscode.typescript-language-features" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[vue]": { + "editor.defaultFormatter": "Vue.volar" + }, + // extensions + "extensions.ignoreRecommendations": true, + + // terminal + "terminal.integrated.cursorBlinking": true, + "terminal.integrated.persistentSessionReviveProcess": "never", + "terminal.integrated.tabs.enabled": true, + "terminal.integrated.scrollback": 10000, + "terminal.integrated.stickyScroll.enabled": true, + + // files + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.simpleDialog.enable": true, + "files.associations": { + "*.ejs": "html", + "*.art": "html", + "**/tsconfig.json": "jsonc", + "*.json": "jsonc", + "package.json": "json" + }, + + "files.exclude": { + "**/.eslintcache": true, + "**/bower_components": true, + "**/.turbo": true, + "**/.idea": true, + "**/tmp": true, + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.stylelintcache": true, + "**/.DS_Store": true, + "**/vite.config.mts.*": true, + "**/tea.yaml": true + }, + "files.watcherExclude": { + "**/.git/objects/**": true, + "**/.git/subtree-cache/**": true, + "**/.vscode/**": true, + "**/node_modules/**": true, + "**/tmp/**": true, + "**/bower_components/**": true, + "**/dist/**": true, + "**/yarn.lock": true + }, + + // search + "search.searchEditor.singleClickBehaviour": "peekDefinition", + "search.followSymlinks": false, + // 在使用搜索功能时,将这些文件夹/文件排除在外 + "search.exclude": { + "**/node_modules": true, + "**/*.log": true, + "**/*.log*": true, + "**/bower_components": true, + "**/dist": true, + "**/elehukouben": true, + "**/.git": true, + "**/.github": true, + "**/.gitignore": true, + "**/.svn": true, + "**/.DS_Store": true, + "**/.vitepress/cache": true, + "**/.idea": true, + "**/.vscode": false, + "**/.yarn": true, + "**/tmp": true, + "*.xml": true, + "out": true, + "dist": true, + "node_modules": true, + "CHANGELOG.md": true, + "**/pnpm-lock.yaml": true, + "**/yarn.lock": true + }, + + "debug.onTaskErrors": "debugAnyway", + "diffEditor.ignoreTrimWhitespace": false, + "npm.packageManager": "pnpm", + + "css.validate": false, + "less.validate": false, + "scss.validate": false, + + // extension "emmet.showSuggestionsAsSnippets": true, "emmet.triggerExpansionOnTab": false, - "errorLens.enabledDiagnosticLevels": [ - "warning", - "error" - ], - "errorLens.excludeBySource": [ - "cSpell", - "Grammarly", - "eslint" - ], - // ESLint config: https://github.com/antfu/eslint-config - "eslint.codeAction.showDocumentation": { - "enable": true - }, - "eslint.quiet": true, - // Silent the stylistic rules in you IDE, but still auto fix them - "eslint.rules.customizations": [ - { - "rule": "style/*", - "severity": "off" - }, - { - "rule": "format/*", - "severity": "off" - }, - { - "rule": "*-indent", - "severity": "off" - }, - { - "rule": "*-spacing", - "severity": "off" - }, - { - "rule": "*-spaces", - "severity": "off" - }, - { - "rule": "*-order", - "severity": "off" - }, - { - "rule": "*-dangle", - "severity": "off" - }, - { - "rule": "*-newline", - "severity": "off" - }, - { - "rule": "*quotes", - "severity": "off" - }, - { - "rule": "*semi", - "severity": "off" - } - ], + + "errorLens.enabledDiagnosticLevels": ["warning", "error"], + "errorLens.excludeBySource": ["cSpell", "Grammarly", "eslint"], + + "stylelint.enable": true, + "stylelint.packageManager": "pnpm", + "stylelint.validate": ["css", "less", "postcss", "scss", "vue"], + "stylelint.snippet": ["css", "less", "postcss", "scss", "vue"], + + "typescript.inlayHints.enumMemberValues.enabled": true, + "typescript.preferences.preferTypeOnlyAutoImports": true, + "typescript.preferences.includePackageJsonAutoImports": "on", + "eslint.validate": [ "javascript", - "javascriptreact", "typescript", + "javascriptreact", "typescriptreact", "vue", "html", "markdown", "json", "jsonc", - "yaml", - "toml" + "json5" ], + + "tailwindCSS.experimental.classRegex": [ + ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] + ], + "github.copilot.enable": { "*": true, "markdown": true, "plaintext": false, + "yaml": false }, - "cSpell.allowCompoundWords": true, - "cSpell.language": "en,en-US", - "css.lint.hexColorLength": "ignore", - "githubIssues.workingIssueFormatScm": "#${issueNumberLabel}", - "githubPullRequests.fileListLayout": "tree", - "gitlens.codeLens.authors.enabled": false, - "gitlens.codeLens.enabled": false, - "gitlens.codeLens.recentChange.enabled": false, - "gitlens.menus": { - "editor": { - "blame": false, - "clipboard": true, - "compare": true, - "history": false, - "remote": false - }, - "editorGroup": { - "blame": true, - "compare": false - }, - "editorTab": { - "clipboard": true, - "compare": true, - "history": true, - "remote": true - }, - "explorer": { - "clipboard": true, - "compare": true, - "history": true, - "remote": true - }, - "scm": { - "authors": true - }, - "scmGroup": { - "compare": true, - "openClose": true, - "stash": true - }, - "scmGroupInline": { - "stash": true - }, - "scmItem": { - "clipboard": true, - "compare": true, - "history": true, - "remote": false, - "stash": true - } - }, - "i18n-ally.autoDetection": false, - "i18n-ally.displayLanguage": "en", - "i18n-ally.ignoredLocales": [], - "iconify.annotations": true, - "iconify.inplace": true, - "svg.preview.mode": "svg", - // I only use Prettier for manually formatting - "prettier.enable": false, - "prettier.printWidth": 200, - "prettier.semi": false, - "prettier.singleQuote": true, - // ========== File Nesting ========== - // this might not be up to date with the repo, please check yourself - // https://github.com/antfu/vscode-file-nesting-config + + "cssVariables.lookupFiles": ["packages/core/base/design/src/**/*.css"], + + "i18n-ally.localesPaths": [ + "packages/locales/src/langs", + "playground/src/locales/langs", + "apps/*/src/locales/langs" + ], + "i18n-ally.pathMatcher": "{locale}.json", + "i18n-ally.enabledParsers": ["json", "ts", "js", "yaml"], + "i18n-ally.sourceLanguage": "en", + "i18n-ally.displayLanguage": "zh-CN", + "i18n-ally.enabledFrameworks": ["vue", "react"], + + // 控制相关文件嵌套展示 "explorer.fileNesting.enabled": true, "explorer.fileNesting.expand": false, "explorer.fileNesting.patterns": { - "*.asax": "$(capture).*.cs, $(capture).*.vb", - "*.ascx": "$(capture).*.cs, $(capture).*.vb", - "*.ashx": "$(capture).*.cs, $(capture).*.vb", - "*.aspx": "$(capture).*.cs, $(capture).*.vb", - "*.bloc.dart": "$(capture).event.dart, $(capture).state.dart", - "*.c": "$(capture).h", - "*.cc": "$(capture).hpp, $(capture).h, $(capture).hxx", - "*.cjs": "$(capture).cjs.map, $(capture).*.cjs, $(capture)_*.cjs", - "*.component.ts": "$(capture).component.html, $(capture).component.spec.ts, $(capture).component.css, $(capture).component.scss, $(capture).component.sass, $(capture).component.less", - "*.cpp": "$(capture).hpp, $(capture).h, $(capture).hxx", - "*.cs": "$(capture).*.cs", - "*.cshtml": "$(capture).cshtml.cs", - "*.csproj": "*.config, *proj.user, appsettings.*, bundleconfig.json", - "*.css": "$(capture).css.map, $(capture).*.css", - "*.cxx": "$(capture).hpp, $(capture).h, $(capture).hxx", - "*.dart": "$(capture).freezed.dart, $(capture).g.dart", - "*.ex": "$(capture).html.eex, $(capture).html.heex, $(capture).html.leex", - "*.go": "$(capture)_test.go", - "*.java": "$(capture).class", - "*.js": "$(capture).js.map, $(capture).*.js, $(capture)_*.js", - "*.jsx": "$(capture).js, $(capture).*.jsx, $(capture)_*.js, $(capture)_*.jsx", - "*.master": "$(capture).*.cs, $(capture).*.vb", - "*.mjs": "$(capture).mjs.map, $(capture).*.mjs, $(capture)_*.mjs", - "*.module.ts": "$(capture).resolver.ts, $(capture).controller.ts, $(capture).service.ts", - "*.pubxml": "$(capture).pubxml.user", - "*.resx": "$(capture).*.resx, $(capture).designer.cs, $(capture).designer.vb", - "*.tex": "$(capture).acn, $(capture).acr, $(capture).alg, $(capture).aux, $(capture).bbl, $(capture).blg, $(capture).fdb_latexmk, $(capture).fls, $(capture).glg, $(capture).glo, $(capture).gls, $(capture).idx, $(capture).ind, $(capture).ist, $(capture).lof, $(capture).log, $(capture).lot, $(capture).out, $(capture).pdf, $(capture).synctex.gz, $(capture).toc, $(capture).xdv", - "*.ts": "$(capture).js, $(capture).d.ts.map, $(capture).*.ts, $(capture)_*.js, $(capture)_*.ts", - "*.tsx": "$(capture).ts, $(capture).*.tsx, $(capture)_*.ts, $(capture)_*.tsx", - "*.vbproj": "*.config, *proj.user, appsettings.*, bundleconfig.json", - "*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue", - "*.xaml": "$(capture).xaml.cs", - "+layout.svelte": "+layout.ts,+layout.ts,+layout.js,+layout.server.ts,+layout.server.js,+layout.gql", - "+page.svelte": "+page.server.ts,+page.server.js,+page.ts,+page.js,+page.gql", - ".clang-tidy": ".clang-format, .clangd, compile_commands.json", - ".env": "*.env, .env.*, .envrc, env.d.ts", - ".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*", - ".project": ".classpath", - "//": "Last update at 4/29/2023, 2:04:58 PM", - "BUILD.bazel": "*.bzl, *.bazel, *.bazelrc, bazel.rc, .bazelignore, .bazelproject, WORKSPACE", - "CMakeLists.txt": "*.cmake, *.cmake.in, .cmake-format.yaml, CMakePresets.json", - "I*.cs": "$(capture).cs", - "artisan": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, server.php, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, webpack.mix.js, windi.config.*", - "astro.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", - "cargo.toml": ".clippy.toml, .rustfmt.toml, cargo.lock, clippy.toml, cross.toml, rust-toolchain.toml, rustfmt.toml", - "composer.json": ".php*.cache, composer.lock, phpunit.xml*, psalm*.xml", - "default.nix": "shell.nix", - "deno.json*": "*.env, .env.*, .envrc, api-extractor.json, deno.lock, env.d.ts, import-map.json, import_map.json, jsconfig.*, tsconfig.*, tsdoc.*", - "dockerfile": ".dockerignore, docker-compose.*, dockerfile*", - "flake.nix": "flake.lock", - "gatsby-config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, gatsby-browser.*, gatsby-node.*, gatsby-ssr.*, gatsby-transformer.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", - "gemfile": ".ruby-version, gemfile.lock", - "go.mod": ".air*, go.sum", - "go.work": "go.work.sum", - "mix.exs": ".credo.exs, .dialyzer_ignore.exs, .formatter.exs, .iex.exs, .tool-versions, mix.lock", - "next.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, next-env.d.ts, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", - "nuxt.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", - "package.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*", - "pubspec.yaml": ".metadata, .packages, all_lint_rules.yaml, analysis_options.yaml, build.yaml, pubspec.lock, pubspec_overrides.yaml", - "pyproject.toml": ".pdm.toml, pdm.lock, pyproject.toml", - "quasar.conf.js": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, quasar.extensions.json, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", - "readme*": "authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying, credits, governance.md, history.md, license*, maintainers, readme*, security.md, sponsors*", - "remix.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, remix.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", - "rush.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*", - "shims.d.ts": "*.d.ts", - "svelte.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, houdini.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, mdsvex.config.js, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vite.config.*, vitest.config.*, webpack.config.*, windi.config.*", - "vite.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", - "vue.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*" + "*.ts": "$(capture).test.ts, $(capture).test.tsx, $(capture).spec.ts, $(capture).spec.tsx, $(capture).d.ts", + "*.tsx": "$(capture).test.ts, $(capture).test.tsx, $(capture).spec.ts, $(capture).spec.tsx,$(capture).d.ts", + "*.env": "$(capture).env.*", + "README.md": "README*,CHANGELOG*,LICENSE,CNAME", + "package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,.gitattributes,.gitignore,.gitpod.yml,.npmrc,.browserslistrc,.node-version,.git*,.tazerc.json", + "Dockerfile": "Dockerfile,.docker*,docker-entrypoint.sh,build-local-docker*,nginx.conf", + "eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,stylelint.config.*,.lintstagedrc.mjs,.ls-lint*,cspell.json", + "tailwind.config.mjs": "postcss.*" }, + "commentTranslate.hover.enabled": false, + "i18n-ally.keystyle": "nested", + "commentTranslate.multiLineMerge": true, + "vue.server.hybridMode": true, + "typescript.tsdk": "node_modules/typescript/lib", "vue3snippets.enable-compile-vue-file-on-did-save-code": false, + "[typescriptreact]": { + "editor.defaultFormatter": "vscode.typescript-language-features" + } } diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..61076b6d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +FROM node:20-slim AS builder + +# --max-old-space-size +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +ENV NODE_OPTIONS=--max-old-space-size=8192 +ENV TZ=Asia/Shanghai + +RUN corepack enable + +WORKDIR /app + +# copy package.json and pnpm-lock.yaml to workspace +COPY . /app + +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile +RUN pnpm run build + +RUN echo "Builder Success 🎉" + +FROM nginx:stable-alpine as production + +RUN echo "types { application/javascript js mjs; }" > /etc/nginx/conf.d/mjs.conf +COPY --from=builder /app/playground/dist /usr/share/nginx/html + +COPY ./nginx.conf /etc/nginx/nginx.conf + +EXPOSE 8080 + +# start nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/LICENSE b/LICENSE index 20547de8..cec5b427 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,9 @@ MIT License -Copyright (c) 2021 Soybean +Copyright (c) 2024-present, Vben -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +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 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. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.ja-JP.md b/README.ja-JP.md new file mode 100644 index 00000000..093585d8 --- /dev/null +++ b/README.ja-JP.md @@ -0,0 +1,149 @@ +
VbenAdmin Logo

+ +[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE) + +

Vue Vben Admin

+
+ +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg) + +**日本語** | [English](./README.md) | [中文](./README.zh-CN.md) + +## 紹介 + +Vue Vben Adminは、最新の`vue3`、`vite`、`TypeScript`などの主流技術を使用して開発された、無料でオープンソースの中・後端テンプレートです。すぐに使える中・後端のフロントエンドソリューションとして、学習の参考にもなります。 + +## アップグレード通知 + +これは最新バージョン5.0であり、以前のバージョンとは互換性がありません。新しいプロジェクトを開始する場合は、最新バージョンを使用することをお勧めします。古いバージョンを表示したい場合は、[v2ブランチ](https://github.com/vbenjs/vue-vben-admin/tree/v2)を使用してください。 + +## 特徴 + +- **最新技術スタック**: Vue 3やViteなどの最先端フロントエンド技術で開発 +- **TypeScript**: アプリケーション規模のJavaScriptのための言語 +- **テーマ**: 複数のテーマカラーが利用可能で、カスタマイズオプションも豊富 +- **国際化**: 完全な内蔵国際化サポート +- **権限管理**: 動的ルートベースの権限生成ソリューションを内蔵 + +## プレビュー + +- [Vben Admin](https://vben.pro/) - フルバージョンの中国語サイト + +テストアカウント: vben/123456 + +

+ VbenAdmin Logo + VbenAdmin Logo + VbenAdmin Logo +

+ +### Gitpodを使用 + +Gitpod(GitHub用の無料オンライン開発環境)でプロジェクトを開き、すぐにコーディングを開始します。 + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin) + +## ドキュメント + +[ドキュメント](https://doc.vben.pro/) + +## インストールと使用 + +- プロジェクトコードを取得 + +```bash +git clone https://github.com/vbenjs/vue-vben-admin.git +``` + +- 依存関係のインストール + +```bash +cd vue-vben-admin + +corepack enable + +pnpm install + +``` + +- 実行 + +```bash +pnpm dev +``` + +- ビルド + +```bash +pnpm build +``` + +## 変更ログ + +[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases) + +## 貢献方法 + +ご参加をお待ちしております![Issueを提出](https://github.com/anncwb/vue-vben-admin/issues/new/choose)するか、Pull Requestを送信してください。 + +**Pull Request:** + +1. コードをフォーク! +2. 自分のブランチを作成: `git checkout -b feat/xxxx` +3. 変更をコミット: `git commit -am 'feat(function): add xxxxx'` +4. ブランチをプッシュ: `git push origin feat/xxxx` +5. `pull request`を送信 + +## Git貢献提出規則 + +- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 規則 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)) + + - `feat` 新機能の追加 + - `fix` 問題/バグの修正 + - `style` コードスタイルに関連し、実行結果に影響しない + - `perf` 最適化/パフォーマンス向上 + - `refactor` リファクタリング + - `revert` 変更の取り消し + - `test` テスト関連 + - `docs` ドキュメント/注釈 + - `chore` 依存関係の更新/スキャフォールディング設定の変更など + - `ci` 継続的インテグレーション + - `types` 型定義ファイルの変更 + - `wip` 開発中 + +## ブラウザサポート + +ローカル開発には`Chrome 80+`ブラウザを推奨します + +モダンブラウザをサポートし、IEはサポートしません + +| [ Edge](http://godban.github.io/browsers-support-badges/)
IE | [ Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | +| :-: | :-: | :-: | :-: | :-: | +| サポートしない | 最新2バージョン | 最新2バージョン | 最新2バージョン | 最新2バージョン | + +## メンテナー + +[@Vben](https://github.com/anncwb) + +## 寄付 + +このプロジェクトが役に立つと思われた場合、作者にコーヒーを一杯おごってサポートを示すことができます! + +![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png) + +Paypal Me + +## 貢献者 + + + Contributors + + +## Discord + +- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions) + +## ライセンス + +[MIT © Vben-2020](./LICENSE) diff --git a/README.md b/README.md index be8142fe..0f58308c 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,148 @@ -# 前端 +
VbenAdmin Logo

+[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE) +

Vue Vben Admin

+
-## Getting started +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg) -To make it easy for you to get started with GitLab, here's a list of recommended next steps. +**English** | [中文](./README.zh-CN.md) | [日本語](./README.ja-JP.md) -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! +## Introduction -## Add your files +Vue Vben Admin is a free and open source middle and back-end template. Using the latest `vue3`, `vite`, `TypeScript` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference. -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: +## Upgrade Notice -``` -cd existing_repo -git remote add origin https://git.openserver.cn:8089/XinJiang/TheProjectOfFour/kelamayireligongsi/plrl/vue.git -git branch -M main -git push -uf origin main +This is the latest version, 5.0, and it is not compatible with previous versions. If you are starting a new project, it is recommended to use the latest version. If you wish to view the old version, please use the [v2 branch](https://github.com/vbenjs/vue-vben-admin/tree/v2). + +## Feature + +- **Latest Technology Stack**: Developed with cutting-edge front-end technologies like Vue 3 and Vite +- **TypeScript**: A language for application-scale JavaScript +- **Themes**: Multiple theme colors available with customizable options +- **Internationalization**: Comprehensive built-in internationalization support +- **Permissions**: Built-in solution for dynamic route-based permission generation + +## Preview + +- [Vben Admin](https://vben.pro/) - Full version Chinese site + +Test Account: vben/123456 + +

+ VbenAdmin Logo + VbenAdmin Logo + VbenAdmin Logo +

+ +### Use Gitpod + +Open the project in Gitpod (free online dev environment for GitHub) and start coding immediately. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin) + +## Documentation + +[Document](https://doc.vben.pro/) + +## Install and use + +- Get the project code + +```bash +git clone https://github.com/vbenjs/vue-vben-admin.git ``` -## Integrate with your tools +- Installation dependencies -- [ ] [Set up project integrations](https://git.openserver.cn:8089/XinJiang/TheProjectOfFour/kelamayireligongsi/plrl/vue/-/settings/integrations) +```bash +cd vue-vben-admin -## Collaborate with your team +corepack enable -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) +pnpm install +``` -## Test and Deploy +- run -Use the built-in continuous integration in GitLab. +```bash +pnpm dev +``` -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) +- build -*** +```bash +pnpm build +``` -# Editing this README +## Change Log -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. +[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases) -## Suggestions for a good README -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. +## How to contribute -## Name -Choose a self-explaining name for your project. +You are very welcome to join![Raise an issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) Or submit a Pull Request。 -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. +**Pull Request:** -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. +1. Fork code! +2. Create your own branch: `git checkout -b feat/xxxx` +3. Submit your changes: `git commit -am 'feat(function): add xxxxx'` +4. Push your branch: `git push origin feat/xxxx` +5. submit`pull request` -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. +## Git Contribution submission specification -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. +- reference [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) specification ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)) -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. + - `feat` Add new features + - `fix` Fix the problem/BUG + - `style` The code style is related and does not affect the running result + - `perf` Optimization/performance improvement + - `refactor` Refactor + - `revert` Undo edit + - `test` Test related + - `docs` Documentation/notes + - `chore` Dependency update/scaffolding configuration modification etc. + - `ci` Continuous integration + - `types` Type definition file changes + - `wip` In development -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. +## Browser support -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. +The `Chrome 80+` browser is recommended for local development -## Contributing -State if you are open to contributions and what your requirements are for accepting them. +Support modern browsers, not IE -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. +| [ Edge](http://godban.github.io/browsers-support-badges/)
IE | [ Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | +| :-: | :-: | :-: | :-: | :-: | +| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions | -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. +## Maintainer -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. +[@Vben](https://github.com/anncwb) + +## Donate + +If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support! + +![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png) + +Paypal Me + +## Contributor + + + Contributors + + +## Discord + +- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions) ## License -For open source projects, say how it is licensed. -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. +[MIT © Vben-2020](./LICENSE) diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 00000000..3c586bd5 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,148 @@ +
VbenAdmin Logo

+ +[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE) + +

Vue Vben Admin

+
+ +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg) + +**中文** | [English](./README.md) | [日本語](./README.ja-JP.md) + +## 简介 + +Vue Vben Admin 是 Vue Vben Admin 的升级版本。作为一个免费开源的中后台模板,它采用了最新的 Vue 3、Vite、TypeScript 等主流技术开发,开箱即用,可用于中后台前端开发,也适合学习参考。 + +## 升级提示 + +该版本为最新版本`5.0`, 与其他版本不兼容,如果你是新项目,建议使用最新版本。如果你想查看旧版本,请使用 [v2 分支](https://github.com/vbenjs/vue-vben-admin/tree/v2) + +## 特性 + +- **最新技术栈**:使用 Vue3/vite 等前端前沿技术开发 +- **TypeScript**: 应用程序级 JavaScript 的语言 +- **主题**:提供多套主题色彩,可配置自定义主题 +- **国际化**:内置完善的国际化方案 +- **权限** 内置完善的动态路由权限生成方案 + +## 预览 + +- [Vben Admin](https://vben.pro/) - 完整版中文站点 + +测试账号: vben/123456 + +

+ VbenAdmin Logo + VbenAdmin Logo + VbenAdmin Logo +

+ +### 使用 Gitpod + +在 Gitpod(适用于 GitHub 的免费在线开发环境)中打开项目,并立即开始编码. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin) + +## 文档 + +[文档地址](https://doc.vben.pro/) + +## 安装使用 + +- 获取项目代码 + +```bash +git clone https://github.com/vbenjs/vue-vben-admin.git +``` + +- 安装依赖 + +```bash +cd vue-vben-admin + +corepack enable + +pnpm install +``` + +- 运行 + +```bash +pnpm dev +``` + +- 打包 + +```bash +pnpm build +``` + +## 如何贡献 + +非常欢迎你的加入![提一个 Issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) 或者提交一个 Pull Request。 + +**Pull Request:** + +1. Fork 代码! +2. 创建自己的分支: `git checkout -b feature/xxxx` +3. 提交你的修改: `git commit -am 'feat(function): add xxxxx'` +4. 推送您的分支: `git push origin feature/xxxx` +5. 提交`pull request` + +## Git 贡献提交规范 + +- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 规范 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)) + + - `feat` 增加新功能 + - `fix` 修复问题/BUG + - `style` 代码风格相关无影响运行结果的 + - `perf` 优化/性能提升 + - `refactor` 重构 + - `revert` 撤销修改 + - `test` 测试相关 + - `docs` 文档/注释 + - `chore` 依赖更新/脚手架配置修改等 + - `ci` 持续集成 + - `types` 类型定义文件更改 + - `wip` 开发中 + +## 浏览器支持 + +本地开发推荐使用`Chrome 80+` 浏览器 + +支持现代浏览器, 不支持 IE + +| [ Edge](http://godban.github.io/browsers-support-badges/)
IE | [ Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | +| :-: | :-: | :-: | :-: | :-: | +| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions | + +## 维护者 + +[@Vben](https://github.com/anncwb) + +## 捐赠 + +如果你觉得这个项目对你有帮助,你可以帮作者买一杯咖啡表示支持! + +![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png) + +Paypal Me + +## 更新日志 + +[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases) + +## Contributor + + + Contributors + + +## Discord + +- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions) + +## License + +[MIT © Vben-2020](./LICENSE) diff --git a/alova.config.ts b/alova.config.ts deleted file mode 100644 index 8e8b1f38..00000000 --- a/alova.config.ts +++ /dev/null @@ -1,139 +0,0 @@ - -/** - * Alova 请求插件配置文件 - * 作用:自动根据swagger生成对应的api调用函数 - */ -export default { - // api生成设置数组,每项代表一个自动生成的规则,包含生成的输入输出目录、规范文件地址等等 - generator: [ - // 服务器1 - { - // input参数1:openapi的json文件url地址 - input: 'http://127.0.0.1:4523/export/openapi/2?version=3.0', - - // input参数2:以当前项目为相对目录的本地地址 - // input: 'openapi/api.json' - - // input参数3:没有直接指向openapi文件时,是一个文档地址,必须配合platform参数指定文档类型 - // input: 'http://192.168.5.123:8080' - - // (可选)platform为支持openapi的平台,目前只支持swagger,默认为空 - // 当指定了此参数后,input字段只需要指定文档的地址而不需要指定到openapi文件 - platform: 'swagger', - - // 接口文件和类型文件的输出路径,多个generator不能重复的地址,否则生成的代码会相互覆盖 - output: 'src/api', - - // (可选)指定生成的响应数据的mediaType,以此数据类型来生成200状态码的响应ts格式,默认application/json - responseMediaType: 'application/json', - - // (可选)指定生成的请求体数据的bodyMediaType,以此数据类型来生成请求体的ts格式,默认application/json - bodyMediaType: 'application/json', - - // (可选)指定生成的api版本,默认为auto,会通过当前项目安装的alova版本判断当前项目的版本,如果生成不正确你也可以自定义指定版本 - version: 'auto', - - /** - * (可选)生成代码的类型,可选值为auto/ts/typescript/module/commonjs,默认为auto,会通过一定规则判断当前项目的类型,如果生成不正确你也可以自定义指定类型: - * ts/typescript:意思相同,表示生成ts类型文件 - * module:生成esModule规范文件 - * commonjs:表示生成commonjs规范文件 - */ - type: 'typescript', - - /** - * 全局导出的api名称,可通过此名称全局范围访问自动生成的api,默认为`Apis`,配置了多个generator时为必填,且不可以重复 - */ - global: 'Apis', - - /** - * (可选)过滤或转换生成的api接口函数,返回一个新的apiDescriptor来生成api调用函数,未指定此函数时则不转换apiDescripor对象 - */ - handleApi: (apiDescriptor, log) => { - // 返回falsy值表示过滤此api - // if (!apiDescriptor.path.startWith('/user')) { - // return; - // } - - // apiDescriptor.parameter = apiDescriptor.parameter.filter( - // param => param.in === 'header' && param.name === 'token' - // ); - // delete apiDescriptor.requestBody.id; - // apiDescriptor.url = '/app/rl' + apiDescriptor.url; - - /** - * 检查字符串数组中的任意一个字符串是否存在于目标字符串中。 - * @param target - 目标字符串 - * @param searchStrings - 要检查的字符串数组 - * @returns 是否至少有一个字符串存在于目标字符串中 - */ - const anyStringExistsInTarget = (target, searchStrings) => { - // 提前返回,如果搜索数组为空 - if (searchStrings.length === 0) return false; - - // 预处理目标字符串,确保只有一次字符串操作 - const lowerCaseTarget = target.toLowerCase(); - - for (const searchString of searchStrings) { - if (lowerCaseTarget.includes(searchString.toLowerCase())) { - return true; // 只要有一个字符串匹配,立即返回 true - } - } - return false; // 所有字符串都不匹配,返回 false - } - - // 接口包含某些参数的时候,需要生成 - if (anyStringExistsInTarget(apiDescriptor.url, [ - '/api/core', // 人员相关 - ])) { - apiDescriptor.url = '/uc' + apiDescriptor.url; - apiDescriptor.tags = ['user'] - return apiDescriptor; - } - - apiDescriptor.url = '/app/rl' + apiDescriptor.url; - if (anyStringExistsInTarget(apiDescriptor.url, [ - '/ccsq', // 出差申请 - '/meeting', '/addressor', // 会议 - '/zbgl', // 值班 - '/dish', '/orderfoods', '/recipe', // 订餐 - '/officeSuppliesApply', '/officeSuppliesList', '/warehousing', '/inorout', // 办公 - '/supervise', '/feedback' // 督察督办 - ])) { - apiDescriptor.tags = ['erp'] - return apiDescriptor; - } - - if (anyStringExistsInTarget(apiDescriptor.url, [ - '/contractrefertype', // 合同类别 - '/contractBaseInfo', //立项 - '/selectMerchantsBasicInfo', // 选商 - '/sbCtrBasePt', - '/proproviderinfo', - '/contractModelInfo' - ])) { - apiDescriptor.tags = ['ht'] - return apiDescriptor; - } - - apiDescriptor.tags = ['common'] - - return apiDescriptor; - } - }, - ], - - // (可选)是否自动更新接口,默认开启,每5分钟检查一次,false时关闭 - autoUpdate: false - - /* 也可以配置更详细的参数 - autoUpdate: { - // 编辑器开启时更新,默认false - launchEditor: true, - // 自动更新间隔,单位毫秒 - interval: 5 * 60 * 1000 - } - */ -}; - - diff --git a/apps/web-office/.env b/apps/web-office/.env new file mode 100644 index 00000000..0d46c537 --- /dev/null +++ b/apps/web-office/.env @@ -0,0 +1,5 @@ +# 应用标题 +VITE_APP_TITLE=ERP协同办公系统 + +# 应用命名空间,用于缓存、store等功能的前缀,确保隔离 +VITE_APP_NAMESPACE=erp-office diff --git a/apps/web-office/.env.analyze b/apps/web-office/.env.analyze new file mode 100644 index 00000000..ffafa8dd --- /dev/null +++ b/apps/web-office/.env.analyze @@ -0,0 +1,7 @@ +# public path +VITE_BASE=/ + +# Basic interface address SPA +VITE_GLOB_API_URL=/api + +VITE_VISUALIZER=true diff --git a/apps/web-office/.env.development b/apps/web-office/.env.development new file mode 100644 index 00000000..c138f482 --- /dev/null +++ b/apps/web-office/.env.development @@ -0,0 +1,16 @@ +# 端口号 +VITE_PORT=5666 + +VITE_BASE=/ + +# 接口地址 +VITE_GLOB_API_URL=/api + +# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 +VITE_NITRO_MOCK=true + +# 是否打开 devtools,true 为打开,false 为关闭 +VITE_DEVTOOLS=false + +# 是否注入全局loading +VITE_INJECT_APP_LOADING=true diff --git a/apps/web-office/.env.production b/apps/web-office/.env.production new file mode 100644 index 00000000..1c92699b --- /dev/null +++ b/apps/web-office/.env.production @@ -0,0 +1,16 @@ +VITE_BASE=/ + +# 接口地址 +VITE_GLOB_API_URL=/api + +# 是否开启压缩,可以设置为 none, brotli, gzip +VITE_COMPRESS=none + +# 是否开启 PWA +VITE_PWA=false + +# vue-router 的模式 +VITE_ROUTER_HISTORY=history + +# 是否注入全局loading +VITE_INJECT_APP_LOADING=true diff --git a/apps/web-office/index.html b/apps/web-office/index.html new file mode 100644 index 00000000..edb5c1bc --- /dev/null +++ b/apps/web-office/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + + <%= VITE_APP_TITLE %> + + + + +
+ + + diff --git a/apps/web-office/package.json b/apps/web-office/package.json new file mode 100644 index 00000000..e5a22cff --- /dev/null +++ b/apps/web-office/package.json @@ -0,0 +1,77 @@ +{ + "name": "web-office", + "version": "5.1.2", + "homepage": "https://vben.pro", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "apps/web-antd" + }, + "license": "MIT", + "author": { + "name": "vben", + "email": "ann.vben@gmail.com", + "url": "https://github.com/anncwb" + }, + "type": "module", + "scripts": { + "build": "pnpm vite build --mode production", + "build:analyze": "pnpm vite build --mode analyze", + "dev": "pnpm vite --mode development", + "dev:prod": "pnpm vite --mode production", + "preview": "vite preview", + "typecheck": "vue-tsc --noEmit --skipLibCheck" + }, + "imports": { + "#/*": "./src/*" + }, + "dependencies": { + "@fast-crud/fast-crud": "^1.21.2", + "@fast-crud/fast-extends": "^1.21.2", + "@fast-crud/ui-antdv4": "^1.21.2", + "@fast-crud/ui-interface": "^1.21.2", + "@vben-core/shadcn-ui": "workspace:*", + "@vben/access": "workspace:*", + "@vben/common-ui": "workspace:*", + "@vben/constants": "workspace:*", + "@vben/hooks": "workspace:*", + "@vben/icons": "workspace:*", + "@vben/layouts": "workspace:*", + "@vben/locales": "workspace:*", + "@vben/plugins": "workspace:*", + "@vben/preferences": "workspace:*", + "@vben/request": "workspace:*", + "@vben/stores": "workspace:*", + "@vben/styles": "workspace:*", + "@vben/types": "workspace:*", + "@vben/utils": "workspace:*", + "@vueuse/core": "^11.0.3", + "alova": "^3.0.14", + "ant-design-vue": "^4.2.3", + "big.js": "^6.2.1", + "dayjs": "^1.11.13", + "exceljs": "^4.4.0", + "lodash-es": "^4.17.21", + "pinia": "2.2.2", + "pinia-plugin-persistedstate": "^3.2.1", + "sortablejs": "^1.15.2", + "tyme4ts": "^1.1.2", + "vue": "^3.4.38", + "vue-router": "^4.4.3", + "vxe-pc-ui": "^4.1.12", + "vxe-table": "^4.7.74", + "vxe-table-plugin-antd": "^4.0.8", + "vxe-table-plugin-export-xlsx": "^4.0.2", + "xe-utils": "^3.5.30" + }, + "devDependencies": { + "@types/big.js": "^6.2.2", + "@types/lodash-es": "^4.17.12", + "sass": "^1.77.8", + "typescript": "^5.5.4", + "unplugin-auto-import": "^0.18.2", + "unplugin-vue-components": "^0.27.4", + "vite-plugin-lazy-import": "^1.0.7" + } +} diff --git a/apps/web-office/postcss.config.mjs b/apps/web-office/postcss.config.mjs new file mode 100644 index 00000000..3d807045 --- /dev/null +++ b/apps/web-office/postcss.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config/postcss'; diff --git a/public/favicon.ico b/apps/web-office/public/favicon.ico similarity index 100% rename from public/favicon.ico rename to apps/web-office/public/favicon.ico diff --git a/apps/web-office/readme.md b/apps/web-office/readme.md new file mode 100644 index 00000000..2d70e919 --- /dev/null +++ b/apps/web-office/readme.md @@ -0,0 +1,3 @@ +pnpm i @fast-crud/fast-crud +pnpm i @fast-crud/fast-extends +pnpm i @fast-crud/ui-interface diff --git a/apps/web-office/src/api/core/auth.ts b/apps/web-office/src/api/core/auth.ts new file mode 100644 index 00000000..24ffa3e3 --- /dev/null +++ b/apps/web-office/src/api/core/auth.ts @@ -0,0 +1,73 @@ +import { baseRequestClient, requestClient } from '#/api/request/index'; + + +export namespace AuthApi { + /** 登录接口参数 */ + export interface LoginParams { + password: string; + username: string; + } + + /** 登录接口返回值 */ + export interface LoginResult { + accessToken: string; + desc: string; + realName: string; + userId: string; + username: string; + } + + export interface RefreshTokenResult { + data: string; + status: number; + } +} + +/** + * 登录 + */ +export async function loginApi(data: AuthApi.LoginParams) { + return requestClient.post( + '/uc/uaa/validateAccount', + data, + { + transformResponse: (res) => { + res = JSON.parse(res); + console.log(res); + const info = res.data; + if (info) { + info.accessToken = info.access_token; + info.realName = info.display_name; + return info + } + return res; + }, + }, + ); +} + +/** + * 刷新accessToken + */ +export async function refreshTokenApi() { + return baseRequestClient.post('/auth/refresh', { + withCredentials: true, + }); +} + +/** + * 退出登录 + */ +export async function logoutApi() { + return baseRequestClient.post('/uc/uaa/logout', { + withCredentials: true, + }); +} + +/** + * 获取用户权限码 + */ +export async function getAccessCodesApi() { + return requestClient.get('/auth/codes'); +} + diff --git a/apps/web-office/src/api/core/index.ts b/apps/web-office/src/api/core/index.ts new file mode 100644 index 00000000..28a5aef4 --- /dev/null +++ b/apps/web-office/src/api/core/index.ts @@ -0,0 +1,3 @@ +export * from './auth'; +export * from './menu'; +export * from './user'; diff --git a/apps/web-office/src/api/core/menu.ts b/apps/web-office/src/api/core/menu.ts new file mode 100644 index 00000000..da355a6c --- /dev/null +++ b/apps/web-office/src/api/core/menu.ts @@ -0,0 +1,10 @@ +import type { RouteRecordStringComponent } from '@vben/types'; + +import { requestClient } from '#/api/request/index'; + +/** + * 获取用户所有菜单 + */ +export async function getAllMenusApi() { + return requestClient.get('/menu/all'); +} diff --git a/apps/web-office/src/api/core/user.ts b/apps/web-office/src/api/core/user.ts new file mode 100644 index 00000000..f8697f89 --- /dev/null +++ b/apps/web-office/src/api/core/user.ts @@ -0,0 +1,15 @@ +import type { UserInfo } from '@vben/types'; + +import { useAccessStore } from '@vben/stores'; + +import { requestClient } from '#/api/request/index'; + +/** + * 获取用户信息 + */ +export async function getUserInfoApi() { + const accessStore = useAccessStore(); + return requestClient.post('/uc/sys/user/checkToken', { + token: accessStore.accessToken, + }); +} diff --git a/apps/web-office/src/api/global.d.ts b/apps/web-office/src/api/global.d.ts new file mode 100644 index 00000000..efaaa939 --- /dev/null +++ b/apps/web-office/src/api/global.d.ts @@ -0,0 +1,22 @@ +export interface QueryOptions { + params?: AnyObject; + pathParams?: AnyObject; + config?: AnyObject; +} + +export interface BodyOptions { + params?: AnyObject; + data?: AnyObject; + pathParams?: AnyObject; + config?: AnyObject; +} + +export interface RequestOptions { + url: string; + data?: QueryOptions; +} + +export interface MutationOptions { + url: string; + data?: BodyOptions; +} diff --git a/apps/web-office/src/api/index.ts b/apps/web-office/src/api/index.ts new file mode 100644 index 00000000..1db74cce --- /dev/null +++ b/apps/web-office/src/api/index.ts @@ -0,0 +1,509 @@ +import { http } from "./request/index" +import type { QueryOptions, BodyOptions } from "./global.d" + +export default { + + meeting: { + /** 协同办公/会议管理 分页查询 */ + get_page: (data?: QueryOptions) => http.get("/app/meeting/page", data), + /** 协同办公/会议管理 删除会议 */ + post_deletes: (data?: BodyOptions) => http.post("/app/meeting/deletes", data), + /** 协同办公/会议管理 会议保存 */ + post_save: (data?: BodyOptions) => http.post("/app/meeting/save", data), + /** 协同办公/会议管理 查看会议台账 */ + get_list: (data?: QueryOptions) => http.get("/app/meeting/list", data), + list: { + /** 协同办公/会议管理 会议台账导出 */ + get_export: (data?: QueryOptions) => http.get("/app/meeting/list/export", data), + }, + }, + tysq: { + zzjg: { + yhjbda: { + YhjbdaController: { + /** 统一授权 未命名接口 */ + get_yhjbdaGrid: (data?: QueryOptions) => http.get("/app/tysq/zzjg/yhjbda/YhjbdaController/yhjbdaGrid", data), + }, + }, + }, + }, + dictType: { + /** 协同办公/字典表 字典类型查询 */ + get_list: (data?: QueryOptions) => http.get("/app/dictType/list", data), + /** 协同办公/字典表 字典类型保存 */ + post_save: (data?: BodyOptions) => http.post("/app/dictType/save", data), + /** 协同办公/字典表 字典类型删除 */ + post_delete: (data?: BodyOptions) => http.post("/app/dictType/deletes", data), + }, + uaa: { + /** 用户中心 用户登陆 Copy */ + post_validateAccount: (data?: BodyOptions) => http.post("/uc/uaa/validateAccount", data), + }, + api: { + core: { + orgemplbc: { + employee: { + /** 用户中心 获取用户信息(分页) */ + post_paging: (data?: BodyOptions) => http.post("/uc/api/core/orgemplbc/employee/paging", data), + }, + organization: { + RL: { + /** 用户中心 根据组织机构id获取员工信息 */ + get_employee: (data?: QueryOptions) => http.get("/uc/api/core/orgemplbc/organization/RL/employee", data), + }, + /** 用户中心 获取组织结构信息 */ + post_paging: (data?: BodyOptions) => http.post("/uc/api/core/orgemplbc/organization/paging", data), + }, + /** 用户中心 根据组织机构id和用户信息查询 */ + post_employee: (data?: BodyOptions) => http.post("/uc/api/core/orgemplbc/employee", data), + }, + }, + }, + sys: { + user: { + /** 用户中心 根据token获取用户信息 */ + post_checkToken: (data?: BodyOptions) => http.post("/uc/sys/user/checkToken", data), + functiontree: { + /** 用户中心 获取菜单接口 */ + get_XTBGXT: (data?: QueryOptions) => http.get("/uc/sys/user/functiontree/XTBGXT", data), + /** 统一授权 未命名接口 */ + get_PLRL: (data?: QueryOptions) => http.get("/uc/sys/user/functiontree/PLRL", data), + }, + }, + }, + zbgl: { + /** 协同办公/值班管理 值班查询 */ + get_queryZbInfo: (data?: QueryOptions) => http.get("/app/zbgl/queryZbInfo", data), + /** 协同办公/值班管理 保存值班信息 */ + post_save: (data?: BodyOptions) => http.post("/app/zbgl/save", data), + /** 协同办公/值班管理 删除值班信息 */ + get_deletes: (data?: QueryOptions) => http.get("/app/zbgl/deletes", data), + /** 协同办公/值班管理 导入值班人员信息 */ + post_importZbry: (data?: BodyOptions) => http.post("/app/zbgl/importZbry", data), + /** 协同办公/值班管理 门户值班信息查询 */ + get_getDutyInfo: (data?: QueryOptions) => http.get("/app/zbgl/getDutyInfo", data), + /** 协同办公/值班管理 导出 */ + post_export: (data?: BodyOptions) => http.post("/app/zbgl/export", data), + }, + dictData: { + /** 协同办公/字典表 字典数据保存 */ + post_save: (data?: BodyOptions) => http.post("/app/dictData/save", data), + /** 合同系统/项目管理 保存 */ + get_save: (data?: QueryOptions) => http.get("/app/dictData/save", data), + /** 合同系统/项目名称管理 查询 */ + get_page: (data?: QueryOptions) => http.get("/app/dictData/page", data), + /** 协同办公/字典表 字典数据删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/dictData/deletes", data), + /** 合同系统/项目管理 删除 */ + get_deletes: (data?: QueryOptions) => http.get("/app/dictData/deletes", data), + }, + user: { + /** 统一授权 获取用户列表 */ + get_page: (data?: QueryOptions) => http.get("/app/user/page", data), + }, + dish: { + /** 协同办公/订餐管理/菜谱管理 菜谱查询 */ + get_page: (data?: QueryOptions) => http.get("/app/dish/page", data), + /** 协同办公/订餐管理/菜谱管理 菜谱保存 */ + post_save: (data?: BodyOptions) => http.post("/app/dish/save", data), + /** 协同办公/订餐管理/食谱管理 菜谱删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/dish/deletes", data), + }, + recipe: { + /** 协同办公/订餐管理/食谱管理 食谱查询 */ + get_page: (data?: QueryOptions) => http.get("/app/recipe/page", data), + /** 协同办公/订餐管理/食谱管理 食谱保存 */ + post_save: (data?: BodyOptions) => http.post("/app/recipe/save", data), + /** 协同办公/订餐管理/食谱管理 食谱导出 */ + get_export: (data?: QueryOptions) => http.get("/app/recipe/export", data), + /** 协同办公/订餐管理/食谱管理 批量保存 */ + post_saveBatch: (data?: BodyOptions) => http.post("/app/recipe/saveBatch", data), + /** 协同办公/订餐管理/食谱管理 食谱编辑 */ + post_edit: (data?: BodyOptions) => http.post("/app/recipe/edit", data), + }, + ccsq: { + /** 协同办公/出差申请 出差申请查询 */ + get_page: (data?: QueryOptions) => http.get("/app/ccsq/page", data), + /** 协同办公/出差申请 申请单保存 */ + post_save: (data?: BodyOptions) => http.post("/app/ccsq/save", data), + /** 协同办公/出差申请 申请单删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/ccsq/deletes", data), + /** 协同办公/出差申请 出差送审、审核 */ + post_audit: (data?: BodyOptions) => http.post("/app/ccsq/audit", data), + /** 协同办公/出差申请 退回 */ + post_turnTask: (data?: BodyOptions) => http.post("/app/ccsq/turnTask", data), + /** 协同办公/出差申请 启动流程 */ + post_startWorkFlow: (data?: BodyOptions) => http.post("/app/ccsq/startWorkFlow", data), + /** 协同办公/出差申请 送审 */ + post_submit: (data?: BodyOptions) => http.post("/app/ccsq/submit", data), + /** 协同办公/出差申请 待办 */ + get_toDoPage: (data?: QueryOptions) => http.get("/app/ccsq/toDoPage", data), + /** 协同办公/出差申请 已办 */ + get_donePage: (data?: QueryOptions) => http.get("/app/ccsq/donePage", data), + /** 协同办公/出差申请 获取可退回节点信息 */ + get_getBackNode: (data?: QueryOptions) => http.get("/app/ccsq/getBackNode", data), + + }, + orderfood: { + /** 协同办公/订餐管理/订餐 订餐加载接口 */ + get_getOne: (data?: QueryOptions) => http.get("/app/orderfood/getOne", data), + /** 协同办公/订餐管理/订餐 订餐保存 */ + post_save: (data?: BodyOptions) => http.post("/app/orderfood/save", data), + /** 协同办公/订餐管理/订餐 取消订餐 */ + post_cancel: (data?: BodyOptions) => http.post("/app/orderfood/cancel", data), + /** 协同办公/订餐管理/订餐 协助取消他人订餐 */ + post_assistCancel: (data?: BodyOptions) => http.post("/app/orderfood/assistCancel", data), + }, + orderfoods: { + /** 协同办公/订餐管理/汇总 部门结算汇总 */ + get_departmentSummary: (data?: QueryOptions) => http.get("/app/orderfoods/departmentSummary", data), + /** 协同办公/订餐管理/汇总 订餐汇总 */ + get_infoList: (data?: QueryOptions) => http.get("/app/orderfoods/infoList", data), + /** 协同办公/订餐管理/汇总 个人结算汇总 */ + get_personalSummary: (data?: QueryOptions) => http.get("/app/orderfoods/personalSummary", data), + infoList: { + /** 协同办公/订餐管理/汇总 订餐汇总导出 */ + get_export: (data?: QueryOptions) => http.get("/app/orderfoods/infoList/export", data), + }, + personalSummary: { + /** 协同办公/订餐管理/汇总 个人结算汇总导出 */ + get_export: (data?: QueryOptions) => http.get("/app/orderfoods/personalSummary/export", data), + }, + departmentSummary: { + /** 协同办公/订餐管理/汇总 部门结算汇总导出 */ + get_export: (data?: QueryOptions) => http.get("/app/orderfoods/departmentSummary/export", data), + }, + /** 协同办公/订餐管理/汇总 结算单 */ + get_finalStatement: (data?: QueryOptions) => http.get("/app/orderfoods/finalStatement", data), + finalStatement: { + /** 协同办公/订餐管理/汇总 结算表导出 */ + get_export: (data?: QueryOptions) => http.get("/app/orderfoods/finalStatement/export", data), + }, + /** 协同办公/订餐管理/汇总 结算操作 */ + post_balance: (data?: BodyOptions) => http.post("/app/orderfoods/balance", data), + }, + officeSuppliesApply: { + /** 协同办公/办公用品/办公用品申请 申请页面查询 */ + get_page: (data?: QueryOptions) => http.get("/app/officeSuppliesApply/page", data), + /** 协同办公/办公用品/办公用品申请 申请保存 */ + post_save: (data?: BodyOptions) => http.post("/app/officeSuppliesApply/save", data), + /** 协同办公/办公用品/办公用品申请 批量审核 */ + post_audit: (data?: BodyOptions) => http.post("/app/officeSuppliesApply/audit", data), + /** 协同办公/办公用品/办公用品申请 批量申请 */ + post_saveBatch: (data?: BodyOptions) => http.post("/app/officeSuppliesApply/saveBatch", data), + /** 协同办公/办公用品/办公用品申请 撤销申请 */ + post_deletes: (data?: BodyOptions) => http.post("/app/officeSuppliesApply/deletes", data), + }, + warehousing: { + /** 协同办公/办公用品/入库/出库 入库查询 */ + get_page: (data?: QueryOptions) => http.get("/app/warehousing/page", data), + }, + inOrOut: { + /** 协同办公/办公用品/入库/出库 入库/保存 */ + post_saveBatch: (data?: BodyOptions) => http.post("/app/inOrOut/saveBatch", data), + }, + supervise: { + /** 协同办公/督查督办/立项发起 立项分页查询 */ + get_page: (data?: QueryOptions) => http.get("/app/supervise/page", data), + /** 协同办公/督查督办/立项发起 立项保存 */ + post_save: (data?: BodyOptions) => http.post("/app/supervise/save", data), + /** 协同办公/督查督办/立项发起 立项删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/supervise/deletes", data), + /** 协同办公/督查督办/立项发起 立项提交 */ + post_audit: (data?: BodyOptions) => http.post("/app/supervise/audit", data), + /** 协同办公/督查督办/执行反馈 执行反馈提交 */ + post_auditFankui: (data?: BodyOptions) => http.post("/app/supervise/auditFankui", data), + /** 协同办公/督查督办/报表汇总 统计 */ + get_huizong: (data?: QueryOptions) => http.get("/app/supervise/huizong", data), + /** 协同办公/督查督办/立项发起 更新状态 */ + post_updateStatus: (data?: BodyOptions) => http.post("/app/supervise/updateStatus", data), + }, + feedback: { + /** 协同办公/督查督办/执行反馈 执行反馈待办查询 */ + get_page: (data?: QueryOptions) => http.get("/app/feedback/page", data), + /** 协同办公/督查督办/执行反馈 执行反馈保存,实际修改操作,保存反馈时间,反馈内容,进度 */ + post_saveUpdate: (data?: BodyOptions) => http.post("/app/feedback/saveUpdate", data), + /** 协同办公/督查督办/执行反馈 查询负责部门列表,返回所有的反馈信息 */ + get_getDepartment: (data?: QueryOptions) => http.get("/app/feedback/getDepartment", data), + /** 协同办公/督查督办/执行反馈 分发立项任务 */ + post_save: (data?: BodyOptions) => http.post("/app/feedback/save", data), + /** 协同办公/督查督办/执行反馈 执行反馈已办查询 */ + get_pageDone: (data?: QueryOptions) => http.get("/app/feedback/pageDone", data), + }, + file: { + /** 协同办公/文件上传/下载 多文件上传 */ + post_uploads: (data?: BodyOptions) => http.post("/app/file/uploads", data), + }, + addressor: { + /** 协同办公/会议管理/发言人 发言人查询 */ + get_list: (data?: QueryOptions) => http.get("/app/addressor/list", data), + /** 协同办公/会议管理/发言人 发言人批量保存 */ + post_saveBatch: (data?: BodyOptions) => http.post("/app/addressor/saveBatch", data), + /** 协同办公/会议管理/发言人 发言人保存 */ + post_save: (data?: BodyOptions) => http.post("/app/addressor/save", data), + post_deletes: (data?: BodyOptions) => http.post("/app/addressor/deletes", data), + }, + officeSuppliesList: { + /** 协同办公/办公用品/办公用品清单 分页查询 */ + get_page: (data?: QueryOptions) => http.get("/app/officeSuppliesList/page", data), + /** 协同办公/办公用品/办公用品清单 批量保存 */ + post_saveBatch: (data?: BodyOptions) => http.post("/app/officeSuppliesList/saveBatch", data), + post_deletes: (data?: BodyOptions) => http.post("/app/officeSuppliesList/deletes", data), + }, + officeSuppliesApplySum: { + /** 协同办公/办公用品 采购汇总 */ + get_list: (data?: QueryOptions) => http.get("/app/officeSuppliesApplySum/list", data), + }, + autoOrderfoodPeoples: { + /** 协同办公/订餐管理/自动订餐人员管理 分页查询 */ + get_page: (data?: QueryOptions) => http.get("/app/autoOrderfoodPeoples/page", data), + /** 协同办公/订餐管理/自动订餐人员管理 批量保存 */ + post_saveBatch: (data?: BodyOptions) => http.post("/app/autoOrderfoodPeoples/saveBatch", data), + post_deletes: (data?: BodyOptions) => http.post("/app/autoOrderfoodPeoples/deletes", data), + }, + usercenter: { + /** 协同办公 获取菜单 */ + get_menus: (data?: QueryOptions) => http.get("/app/usercenter/menus", data), + }, + workflow: { + /** 协同办公/工作流 待办 */ + post_queryMyTodoTask: (data?: BodyOptions) => http.post("/app/workflow/queryMyTodoTask", data), + /** 协同办公/工作流 已办 */ + post_getHistoricTaskByUserID: (data?: BodyOptions) => http.post("/app/workflow/getHistoricTaskByUserID", data), + }, + personTask: { + /** 合同系统/签订 待办查询 */ + get_page: (data?: QueryOptions) => http.get("/app/personTask/page", data), + /** 合同系统/签订 已办查询 */ + get_pagePersonTaskOver: (data?: QueryOptions) => http.get("/app/personTask/pagePersonTaskOver", data), + /** 合同系统/履行/履行查询 分页合同履行审批查询 */ + get_pagePerformanceAudit: (data?: QueryOptions) => http.get("/app/personTask/pagePerformanceAudit", data), + /** 合同系统/履行/履行提示/申请归档 归档保存 */ + post_applicationFiling: (data?: BodyOptions) => http.post("/app/personTask/applicationFiling", data), + }, + sbCtrBasePt: { + /** 合同系统/申报 合同申报数据查询 */ + get_QuerySbCtrBase: (data?: QueryOptions) => http.get("/app/sbCtrBasePt/QuerySbCtrBase", data), + /** 合同系统/申报 合同申报基本信息加载 */ + post_page: (data?: BodyOptions) => http.post("/app/sbCtrBasePt/page", data), + /** 合同系统/申报 合同申报基本信息保存 */ + post_save: (data?: BodyOptions) => http.post("/app/sbCtrBasePt/save", data), + /** 合同系统/申报 合同申报基本信息删除 */ + get_deletes: (data?: QueryOptions) => http.get("/app/sbCtrBasePt/deletes", data), + /** 合同系统/申报 获取资金渠道 */ + get_getFundingSource: (data?: QueryOptions) => http.get("/app/sbCtrBasePt/getFundingSource", data), + }, + contractBaseInfo: { + /** 合同系统/立项 合同立项保存 */ + post_apply: (data?: BodyOptions) => http.post("/app/contractBaseInfo/apply", data), + /** 合同系统/立项 合同立项查询 */ + get_page: (data?: QueryOptions) => http.get("/app/contractBaseInfo/page", data), + /** 合同系统/立项 删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/contractBaseInfo/deletes", data), + /** 合同系统/立项 单条查询 */ + get_getOne: (data?: QueryOptions) => http.get("/app/contractBaseInfo/getOne", data), + /** 合同系统/立项 提交 */ + post_submit: (data?: BodyOptions) => http.post("/app/contractBaseInfo/submit", data), + /** 合同系统/立项 退回 */ + post_rollback: (data?: BodyOptions) => http.post("/app/contractBaseInfo/rollback", data), + }, + proProviderInfo: { + /** 合同系统/相对人管理 合同相对人查询 */ + get_Query: (data?: QueryOptions) => http.get("/app/proProviderInfo/Query", data), + /** 合同系统/相对人管理 获取币种 */ + get_getBz: (data?: QueryOptions) => http.get("/app/proProviderInfo/getBz", data), + /** 合同系统/相对人管理 保存 */ + post_save: (data?: BodyOptions) => http.post("/app/proProviderInfo/save", data), + /** 合同系统/相对人管理 删除 */ + get_deletes: (data?: QueryOptions) => http.get("/app/proProviderInfo/deletes", data), + /** 合同系统/相对人管理 加载 */ + post_page: (data?: BodyOptions) => http.post("/app/proProviderInfo/page", data), + }, + contractModelInfo: { + /** 合同系统/模板管理 保存 */ + post_save: (data?: BodyOptions) => http.post("/app/contractModelInfo/save", data), + /** 合同系统/模板管理 删除 */ + get_deletes: (data?: QueryOptions) => http.get("/app/contractModelInfo/deletes", data), + /** 合同系统/模板管理 加载 */ + post_page: (data?: BodyOptions) => http.post("/app/contractModelInfo/page", data), + }, + contractReferType: { + /** 合同系统/合同类型参照 查询 */ + get_list: (data?: QueryOptions) => http.get("/app/contractReferType/list", data), + /** 合同系统/合同类型参照 保存 */ + post_save: (data?: BodyOptions) => http.post("/app/contractReferType/save", data), + /** 合同系统/合同类型参照 删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/contractReferType/deletes", data), + }, + attachment: { + /** 文件上传/下载(新) 附件加载 */ + get_list: (data?: QueryOptions) => http.get("/app/attachment/list", data), + /** 文件上传/下载(新) 文件下载 */ + get_download: (data?: QueryOptions) => http.get("/app/attachment/download/{fileUuid}", data), + /** 文件上传/下载(新) 多文件上传 */ + post_uploads: (data?: BodyOptions) => http.post("/app/attachment/uploads", data), + }, + contractPayment: { + /** 合同系统/履行/履行提示/合同付款 获取合同付款信息 */ + get_queryPaymentInfo: (data?: QueryOptions) => http.get("/app/contractPayment/queryPaymentInfo", data), + /** 合同系统/归档/合同归档 历史记录 */ + get_historyPaymentInfo: (data?: QueryOptions) => http.get("/app/contractPayment/historyPaymentInfo", data), + /** 合同系统/履行/履行提示/合同付款 保存付款申请 */ + post_save: (data?: BodyOptions) => http.post("/app/contractPayment/save", data), + }, + selectMerchantsBasicInfo: { + /** 合同系统/选商 分页查询 */ + get_page: (data?: QueryOptions) => http.get("/app/selectMerchantsBasicInfo/page", data), + /** 合同系统/选商 选商信息查询(单条) */ + get_getOne: (data?: QueryOptions) => http.get("/app/selectMerchantsBasicInfo/getOne", data), + /** 合同系统/选商 选商信息保存 */ + post_save: (data?: BodyOptions) => http.post("/app/selectMerchantsBasicInfo/save", data), + /** 合同系统/选商 合同选商保存操作(多个对象) */ + post_saveMultiEntity: (data?: BodyOptions) => http.post("/app/selectMerchantsBasicInfo/saveMultiEntity", data), + /** 合同系统/选商 提交 */ + post_submit: (data?: BodyOptions) => http.post("/app/selectMerchantsBasicInfo/submit", data), + /** 合同系统/选商 退回 */ + post_rollback: (data?: BodyOptions) => http.post("/app/selectMerchantsBasicInfo/rollback", data), + }, + lvxChange: { + /** 合同系统/履行/履行提示/合同变更 保存合同变更申请 */ + post_save: (data?: BodyOptions) => http.post("/app/lvxChange/save", data), + /** 合同系统/履行/履行提示/合同变更 获取合同变更信息 */ + get_getContractChangeInfo: (data?: QueryOptions) => http.get("/app/lvxChange/getContractChangeInfo", data), + }, + contractRelieve: { + /** 合同系统/履行/履行提示/合同终止(解除) 获取合同终止(解除)信息 */ + get_getContractRelieveInfo: (data?: QueryOptions) => http.get("/app/contractRelieve/getContractRelieveInfo", data), + /** 合同系统/履行/履行提示/合同终止(解除) 保存合同终止信息 */ + post_save: (data?: BodyOptions) => http.post("/app/contractRelieve/save", data), + }, + contractBreach: { + /** 合同系统/履行/履行提示/合同违约情况 保存合同违约信息 */ + post_save: (data?: BodyOptions) => http.post("/app/contractBreach/save", data), + /** 合同系统/履行/履行提示/合同违约情况 获取合同违约信息 */ + get_getContractBreachInfo: (data?: QueryOptions) => http.get("/app/contractBreach/getContractBreachInfo", data), + }, + lvxResult: { + /** 合同系统/履行/履行结果 履行结果保存 */ + post_save: (data?: BodyOptions) => http.post("/app/lvxResult/save", data), + }, + contractFiling: { + /** 合同系统/履行/履行提示/临时归档 保存临时归档信息 */ + post_save: (data?: BodyOptions) => http.post("/app/contractFiling/save", data), + }, + biddingExpert: { + /** 合同系统/选商/选商招标专家 招标专家查询 */ + get_list: (data?: QueryOptions) => http.get("/app/biddingExpert/list", data), + /** 合同系统/选商/选商招标专家 选商招标专家保存 */ + post_saveBatch: (data?: BodyOptions) => http.post("/app/biddingExpert/saveBatch", data), + /** 合同系统/选商/选商招标专家 选商招标专家删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/biddingExpert/deletes", data), + }, + contractFilingFormal: { + /** 合同系统/归档/合同归档 分页查询归档信息 */ + get_queryContractFiling: (data?: QueryOptions) => http.get("/app/contractFilingFormal/queryContractFiling", data), + /** 合同系统/归档/合同归档 获取合同招标选商申请信息 */ + get_getContractSupplier: (data?: QueryOptions) => http.get("/app/contractFilingFormal/getContractSupplier", data), + /** 合同系统/归档/合同归档 保存合同归档 */ + post_save: (data?: BodyOptions) => http.post("/app/contractFilingFormal/save", data), + /** 合同系统/归档/合同回档 分页查询 */ + get_pageArchivedContract: (data?: QueryOptions) => http.get("/app/contractFilingFormal/pageArchivedContract", data), + /** 合同系统/归档/合同回档 回档 */ + post_saveFilingBack: (data?: BodyOptions) => http.post("/app/contractFilingFormal/saveFilingBack", data), + }, + lvxProduct: { + /** 合同系统/履行/履行提示/产品或服务 获取合同产品信息 */ + get_getContractProductInfo: (data?: QueryOptions) => http.get("/app/lvxProduct/getContractProductInfo", data), + /** 合同系统/履行/履行提示/产品或服务 累计收款金额 */ + get_getSumFromProduct: (data?: QueryOptions) => http.get("/app/lvxProduct/getSumFromProduct", data), + /** 合同系统/履行/履行提示/产品或服务 历史记录 */ + get_getListFromHistoryRecord: (data?: QueryOptions) => http.get("/app/lvxProduct/getListFromHistoryRecord", data), + /** 合同系统/履行/履行提示/产品或服务 保存合同产品服务 */ + post_save: (data?: BodyOptions) => http.post("/app/lvxProduct/save", data), + }, + qdSign: { + /** 合同系统/签订 签订查询 */ + get_page: (data?: QueryOptions) => http.get("/app/qdSign/page", data), + /** 合同系统/签订 获取合同签订信息 */ + get_getContractSignInfo: (data?: QueryOptions) => http.get("/app/qdSign/getContractSignInfo", data), + /** 合同系统/签订 打印签订审批表 */ + get_createUserListWord: (data?: QueryOptions) => http.get("/app/qdSign/createUserListWord", data), + /** 合同系统/签订 打印文本 */ + get_textPrint: (data?: QueryOptions) => http.get("/app/qdSign/textPrint", data), + /** 合同系统/签订 保存送审 */ + post_save: (data?: BodyOptions) => http.post("/app/qdSign/save", data), + /** 合同系统/签订 废除 */ + post_abolish: (data?: BodyOptions) => http.post("/app/qdSign/abolish", data), + }, + flowCenter: { + /** 流程中心 启动流程 */ + post_start: (data?: BodyOptions) => http.post("/app/flowCenter/start", data), + /** 流程中心 审核通过 */ + post_agree: (data?: BodyOptions) => http.post("/app/flowCenter/agree", data), + /** 流程中心 审核退回 */ + post_rollback: (data?: BodyOptions) => http.post("/app/flowCenter/rollback", data), + /** 流程中心 获取待办 */ + post_getTodoList: (data?: BodyOptions) => http.post("/app/flowCenter/getTodoList", data), + /** 流程中心 获取已办 */ + post_doneList: (data?: BodyOptions) => http.post("/app/flowCenter/doneList", data), + /** 流程中心 审核撤回 */ + get_revoke: (data?: QueryOptions) => http.get("/app/flowCenter/revoke", data), + /** 流程中心 审核记录 */ + get_history: (data?: QueryOptions) => http.get("/app/flowCenter/history", data), + /** 流程中心 查看流程图 */ + get_getFlowImg: (data?: QueryOptions) => http.get("/app/flowCenter/getFlowImg", data), + /** 流程中心 获取可退回节点 */ + get_getReturnNode: (data?: QueryOptions) => http.get("/app/flowCenter/getReturnNode", data), + /** 流程中心 获取流程节点人员配置信息 */ + get_getNextNodeUserConfig: (data?: QueryOptions) => http.get("/app/flowCenter/getNextNodeUserConfig", data), + /** 流程中心 获取待办数量 */ + get_getTodoListSize: (data?: QueryOptions) => http.get("/app/flowCenter/getTodoListSize", data), + /** 流程中心 获取当前审核节点配置信息 */ + get_getNodeConfigInfo: (data?: QueryOptions) => http.get("/app/flowCenter/getNodeConfigInfo", data), + /** 流程中心 获取下一节点配置信息 */ + get_getNextNodeConfig: (data?: QueryOptions) => http.get("/app/flowCenter/getNextNodeConfig", data), + /** 流程中心 获取流程节点人员配置信息 */ + post_getFlowNodeUserConfig: (data?: BodyOptions) => http.post("/app/flowCenter/getFlowNodeUserConfig", data), + }, + rl: { + moduleParameter: { + /** 流程中心/流程规划 保存 */ + post_save: (data?: BodyOptions) => http.post("/app/rl/moduleParameter/save", data), + /** 流程中心/流程规划 查询 */ + post_page: (data?: BodyOptions) => http.post("/app/rl/moduleParameter/page", data), + /** 流程中心/流程规划 删除 */ + get_deletes: (data?: QueryOptions) => http.get("/app/rl/moduleParameter/deletes", data), + /** 流程中心/流程规划 获取节点审核人 */ + get_getNextNodeUser: (data?: QueryOptions) => http.get("/app/rl/moduleParameter/getNextNodeUser", data), + }, + }, + dutyCount: { + /** 协同办公/订餐管理/值班天数 分页查询 */ + get_page: (data?: QueryOptions) => http.get("/app/dutyCount/page", data), + /** 协同办公/订餐管理/值班天数 批量保存 */ + post_saveBatch: (data?: BodyOptions) => http.post("/app/dutyCount/saveBatch", data), + /** 协同办公/订餐管理/值班天数 删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/dutyCount/deletes", data), + }, + common: { + /** 公共 获取请求ip */ + get_getClientIp: (data?: QueryOptions) => http.get("/app/common/getClientIp", data), + }, + address: { + /** 协同办公/订餐管理/订餐地址 查询(分页) */ + get_page: (data?: QueryOptions) => http.get("/app/address/page", data), + /** 协同办公/订餐管理/订餐地址 保存 */ + post_save: (data?: BodyOptions) => http.post("/app/address/save", data), + /** 协同办公/订餐管理/订餐地址 删除 */ + post_deletes: (data?: BodyOptions) => http.post("/app/address/deletes", data), + }, + superviseFeedbackRecord: { + /** 协同办公/督查督办/反馈记录 保存反馈记录 */ + post_save: (data?: BodyOptions) => http.post("/app/superviseFeedbackRecord/save", data), + /** 协同办公/督查督办/反馈记录 查询反馈记录 */ + get_page: (data?: QueryOptions) => http.get("/app/superviseFeedbackRecord/page", data), + /** 协同办公/督查督办/反馈记录 删除反馈记录 */ + post_deletes: (data?: BodyOptions) => http.post("/app/superviseFeedbackRecord/deletes", data), + }, + +} diff --git a/src/api/request/config.ts b/apps/web-office/src/api/request/config.ts similarity index 93% rename from src/api/request/config.ts rename to apps/web-office/src/api/request/config.ts index ed6efe8d..6577a11e 100644 --- a/src/api/request/config.ts +++ b/apps/web-office/src/api/request/config.ts @@ -1,6 +1,6 @@ /** BaseUrl: 基础路径 */ -const BASE_URL: string = '/proxy-adm' +const BASE_URL: string = '/api' /** AccessTokenField: header 里传accessToken的键名,一般为 Authorization */ export const ACCESS_TOKEN_FIELD = 'Token' diff --git a/src/api/request/getToken.ts b/apps/web-office/src/api/request/getToken.ts similarity index 78% rename from src/api/request/getToken.ts rename to apps/web-office/src/api/request/getToken.ts index 00d61585..4e905d94 100644 --- a/src/api/request/getToken.ts +++ b/apps/web-office/src/api/request/getToken.ts @@ -4,10 +4,9 @@ * @description: 创建新的请求实例实现 */ import { createAlova } from 'alova' -import { useUserStore } from '@/store/modules/user' +import { useAccessStore } from '@vben/stores'; import fetchAdapter from 'alova/fetch'; import vueHook from 'alova/vue'; -import { ResultEnum } from '@/enums/httpEnum' import { getBaseURL, ACCESS_TOKEN_FIELD } from './config'; let lock = false @@ -20,10 +19,12 @@ const alova = createAlova({ requestAdapter: fetchAdapter(), beforeRequest: (method) => { // ...原请求前拦截器 - const userStore = useUserStore() - console.log('beforeRequest', userStore.accessToken) + const accessStore = useAccessStore(); + + // const userStore = useUserStore() + // console.log('beforeRequest', userStore.accessToken) // 添加token到请求头 - method.config.headers[ACCESS_TOKEN_FIELD] = `${userStore.accessToken}` + // method.config.headers[ACCESS_TOKEN_FIELD] = `${userStore.accessToken}` }, responded: async (response, method) => { let json = await response.json(); @@ -37,7 +38,7 @@ export function getAccessToken(rToken: string): Promise { resolve, reject }) - const userStore = useUserStore(); + // const userStore = useUserStore(); if (!lock) { lock = true @@ -52,9 +53,9 @@ export function getAccessToken(rToken: string): Promise { console.log(data) // 如果 refreshToken 请求成功,则将新的token存储到本地 if (data && data.accessToken) { - userStore.setToken(data.accessToken); - userStore.setTokenExpiresTime(data.accessExpire) - userStore.setRefreshToken(data.refreshToken); + // userStore.setToken(data.accessToken); + // userStore.setTokenExpiresTime(data.accessExpire) + // userStore.setRefreshToken(data.refreshToken); while (promiseResult.length) { // p1.resolve(res.data) promiseResult.shift().resolve(data) @@ -62,7 +63,7 @@ export function getAccessToken(rToken: string): Promise { lock = false return } - userStore.resetStore() + // userStore.resetStore() while (promiseResult.length) { // p1.reject(err) promiseResult.shift().reject("身份认证已失效,请重新登录") diff --git a/apps/web-office/src/api/request/index.ts b/apps/web-office/src/api/request/index.ts new file mode 100644 index 00000000..f466e6fb --- /dev/null +++ b/apps/web-office/src/api/request/index.ts @@ -0,0 +1,404 @@ +/** + * 该文件可自行根据业务逻辑进行调整 + */ +import { useAppConfig } from '@vben/hooks'; +import { preferences } from '@vben/preferences'; +import { + authenticateResponseInterceptor, + errorMessageResponseInterceptor, + RequestClient, +} from '@vben/request'; +import { useAccessStore } from '@vben/stores'; + +import { message } from 'ant-design-vue'; + +import { useAuthStore } from '#/store'; + +import { refreshTokenApi } from '../core'; +import { transferResponse } from './transferResponse'; +import { type QueryOptions, type BodyOptions } from '../global.d'; +import { merge } from 'lodash-es'; + + +import { createAlova } from 'alova'; +import fetchAdapter from 'alova/fetch'; +import vueHook from 'alova/vue'; +import { ACCESS_TOKEN_FIELD, getBaseURL } from './config'; +import { createServerTokenAuthentication } from 'alova/client'; + +const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); + +function createRequestClient(baseURL: string) { + const client = new RequestClient({ + baseURL, + }); + + /** + * 重新认证逻辑 + */ + async function doReAuthenticate() { + console.warn('Access token or refresh token is invalid or expired. '); + const accessStore = useAccessStore(); + const authStore = useAuthStore(); + accessStore.setAccessToken(null); + if ( + preferences.app.loginExpiredMode === 'modal' && + accessStore.isAccessChecked + ) { + accessStore.setLoginExpired(true); + } else { + await authStore.logout(); + } + } + + /** + * 刷新token逻辑 + */ + async function doRefreshToken() { + const accessStore = useAccessStore(); + const resp = await refreshTokenApi(); + const newToken = resp.data; + accessStore.setAccessToken(newToken); + return newToken; + } + + function formatToken(token: null | string) { + return token ? `Bearer ${token}` : null; + } + + // 请求头处理 + client.addRequestInterceptor({ + fulfilled: async (config) => { + const accessStore = useAccessStore(); + + config.headers.Authorization = formatToken(accessStore.accessToken); + config.headers.Token = accessStore.accessToken; + config.headers['Accept-Language'] = preferences.app.locale; + return config; + }, + }); + + // response数据解构 + client.addResponseInterceptor({ + fulfilled: (response) => { + let { data: responseData, status } = response; + + // 统一处理响应数据 + responseData = transferResponse(responseData); + + console.log('【转换响应】', JSON.parse(JSON.stringify(responseData))); + const { code, data, msg } = responseData; + if (status >= 200 && status < 400 && code === 0) { + return data; + } + throw new Error(`Error ${status}: ${msg}`); + }, + }); + + // token过期的处理 + client.addResponseInterceptor( + authenticateResponseInterceptor({ + client, + doReAuthenticate, + doRefreshToken, + enableRefreshToken: preferences.app.enableRefreshToken, + formatToken, + }), + ); + + // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里 + client.addResponseInterceptor( + errorMessageResponseInterceptor((msg: string) => message.error(msg)), + ); + + return client; +} + +export const requestClient = createRequestClient(apiURL); + +/** 储存过期的token */ +let expireTokenCache = [] + +/** 服务端 Token 校验 */ +const { onAuthRequired, onResponseRefreshToken } = createServerTokenAuthentication({ + refreshTokenOnSuccess: { + /** + * 判断 Token 是否过期 + * 响应时触发,可获取到response和method,并返回boolean表示token是否过期 + */ + isExpired: async (response, method) => { + // 文件下载操作 + if (method.meta?.responseType === 'blob') { + return false + } + + const responseClone = response.clone(); + let data = await responseClone.json() + + // 当服务端返回401时,表示token过期 + let isExpired = ['401'].includes(data.code); + if (isExpired) { + console.log('AccessToken已过期', data.code) + expireTokenCache.push(method.config.headers[ACCESS_TOKEN_FIELD]) + } + + return isExpired; + }, + /** 当token过期时触发,在此函数中触发刷新token */ + handler: async (response, method) => { + console.warn('Access token or refresh token is invalid or expired. '); + const accessStore = useAccessStore(); + const authStore = useAuthStore(); + accessStore.setAccessToken(null); + if ( + preferences.app.loginExpiredMode === 'modal' && + accessStore.isAccessChecked + ) { + accessStore.setLoginExpired(true); + } else { + await authStore.logout(); + } + throw new Error('登录已过期,请重新登录'); + // const userStore = useUserStore(); + // try { + // let rToken = userStore.refreshToken; + // // 如果没有refreshToken,则跳转登录页 + // if (!rToken) { + // throw new Error('登录已过期,请重新登录'); + // } + // await getAccessToken(rToken) + // expireTokenCache = [] + // } catch (error: any) { + // window.$message?.error(error.message); + // userStore.resetStore() + // throw error; + // } + } + } +}); + +export const alovaInstance = createAlova({ + /** 动态代理配置 */ + baseURL: getBaseURL(), + /** 框架请求适配器 */ + statesHook: vueHook, + requestAdapter: fetchAdapter(), + /** 设置缓存状态:不开启 */ + cacheFor: null, + // cacheFor: { + // // 统一设置POST的缓存模式 + // GET: { + // mode: 'restore', + // expire: 60 * 10 * 1000 + // }, + // POST: { + // mode: 'restore', + // expire: 60 * 10 * 1000 + // }, + // // 统一设置HEAD请求的缓存模式 + // HEAD: 60 * 10 * 1000 + // }, + /** 请求拦截器 */ + beforeRequest: onAuthRequired(method => { + + const accessStore = useAccessStore(); + + + if (accessStore.accessToken) { + method.config.headers.Token = accessStore.accessToken; + // 统一授权的这个接口需要以Authorization传参,无语 /sys/user/functiontree/XTBGXT + method.config.headers.Authorization = `Bearer ${accessStore.accessToken}`; + + } + method.config.headers['Accept-Language'] = preferences.app.locale; + + // const userStore = useUserStore() + // // 添加token到请求头 + // if (userStore.accessToken) { + // method.config.headers[ACCESS_TOKEN_FIELD] = `Bearer ${userStore.accessToken}` + + + // method.config.headers["Authorization"] = `Bearer ${userStore.accessToken}` + // } + + // method.config.cacheFor = { + // // 设置缓存模式为内存模式 + // mode: 'restore', + // // 单位为毫秒 + // // 当设置为`Infinity`,表示数据永不过期,设置为0或负数时表示不缓存 + // expire: 60 * 10 * 1000 + // } + // method.config.transform = (rawData, headers) => { + // console.log('接口响应', rawData) + // return transferResponse(rawData) + // } + + }), + /** 响应拦截器 */ + responded: onResponseRefreshToken(async (response, method) => { + + if (method.meta?.responseType === 'blob') { + + let blob = await response.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + const contentDisposition = response.headers.get('content-disposition'); + let fileName = 'downloaded-file'; + if (contentDisposition) { + const matches = /filename="?([^"]+)"?/.exec(contentDisposition); + if (matches != null && matches[1]) { + fileName = decodeURIComponent(matches[1]); + } + } + a.download = fileName; + // 触发下载 + document.body.appendChild(a); + a.click(); + // 移除链接 + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + return { + blob: blob, + url: url, + filename: fileName + } + } + + + // if (response.status >= 400) { + // throw new Error(response.statusText); + // } + + + let json = await response.json(); + console.log('【接口】', method.url) + console.log('原始响应', JSON.parse(JSON.stringify(json))) + + json = transferResponse(json) + console.log('改造响应', JSON.parse(JSON.stringify(json))) + + if (json.code != 0) { + if (json.code == '401') { + message.error("用户身份过期,请重新登录"); + // const userStore = useUserStore(); + // userStore.resetStore(); + } else { + message.error(json.msg || '服务器开小差,请稍后再试'); + } + // 抛出错误或返回reject状态的Promise实例时,此请求将抛出错误 + throw new Error((json && json.msg) || '出错了'); + } + + // 解析的响应数据将传给method实例的transformData钩子函数,这些函数将在后续讲解 + return json.data; + }) +}); + +class Http { + /** + * 适配swagger路径参数,针对于pathParams + * 输入参数 "/api/v1/user/{id}",{ pathParams:{ id :1 },params:{ id:2 } } + * 输出请求 /api/v1/user/1?id=2 + */ + private replacePathParams(url: string, pathParams?: any): string { + if (!pathParams) return url; + return url.replace(/{(\w+)}/g, (_, key) => pathParams[key] || `{${key}}`); + } + + /** + * 全局默认配置 + * @param customConfig + * @returns + */ + private getConfig(customConfig?: any): any { + // 递归属性拷贝 + return merge({}, { + meta: { + showLoading: false, + showError: false, + }, + }, customConfig); + } + + private request(method: string, url: string, data?: BodyOptions | QueryOptions) { + let finalUrl = this.replacePathParams(url, data?.pathParams); + const config = this.getConfig(data?.config); + + // 当组件使用allowClear属性时,会将数据置为null,导致数据查询失败 + if (data && data.params) { + Object.keys(data.params).forEach(key => { + if (data.params[key] === null || data.params[key] === undefined) { + delete data.params[key] + } + }) + } + if (data && data.data) { + Object.keys(data.data).forEach(key => { + if (data.data[key] === null || data.data[key] === undefined) { + delete data.data[key] + } + }) + } + + let alovaMethod: 'Get' | 'Post' | 'Delete' | 'Put' = 'Get'; + + if (method === 'get' || method === 'delete') { + if (method === 'get') { + alovaMethod = 'Get' + } + if (method === 'delete') { + alovaMethod = 'Delete' + } + return alovaInstance[alovaMethod](finalUrl, { ...config, params: data?.params }); + } else { + // 处理 params 到 url 的逻辑 + if (data?.params) { + finalUrl = this.appendParamsToUrl(finalUrl, data.params); + } + if (method === 'post') { + alovaMethod = 'Post' + } + if (method === 'put') { + alovaMethod = 'Put' + } + + + return alovaInstance[alovaMethod](finalUrl, data?.data, { ...config }); + } + } + + private appendParamsToUrl(url: string, params: any): string { + let queryString = ''; + for (const key in params) { + if (Object.prototype.hasOwnProperty.call(params, key)) { + queryString += `${queryString ? '&' : '?'}${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`; + } + } + return url + queryString; + } + + get(url: string, data?: QueryOptions) { + return this.request('get', url, data); + } + + post(url: string, data?: BodyOptions) { + return this.request('post', url, data); + } + + put(url: string, data?: BodyOptions) { + return this.request('put', url, data); + } + + patch(url: string, data?: BodyOptions) { + return this.request('patch', url, data); + } + + delete(url: string, data?: QueryOptions) { + return this.request('delete', url, data); + } +} + +export const http = new Http(); + +export const baseRequestClient = new RequestClient({ baseURL: apiURL }); diff --git a/src/api/request/transferResponse.ts b/apps/web-office/src/api/request/transferResponse.ts similarity index 77% rename from src/api/request/transferResponse.ts rename to apps/web-office/src/api/request/transferResponse.ts index 9f09a077..f2b775cd 100644 --- a/src/api/request/transferResponse.ts +++ b/apps/web-office/src/api/request/transferResponse.ts @@ -1,3 +1,4 @@ +const SUCCESS_CODE = 0; /** * 统一相应处理,伪BFF层 很多接口返回的响应信息不统一,防止因后端规范问题导致前端工作量增加!!!!!!!故在此做统一处理 @@ -10,42 +11,45 @@ export function transferResponse(response: any) { // 如果后端直接返回数组,如[xxx] if (Array.isArray(response)) { return { - code: import.meta.env.VITE_SERVICE_SUCCESS_CODE, - msg: 'Ok', + code: SUCCESS_CODE, data: { - rows: response - } + rows: response, + }, + msg: 'Ok', }; } - // 如果后端直接返回数据内容对象,如{xxx},则先进行统一响应包装 if (response.code == undefined) { response = { - code: import.meta.env.VITE_SERVICE_SUCCESS_CODE, + code: SUCCESS_CODE, + data: response, msg: 'Ok', - data: response - } + }; } - let { code, msg, data = {}, ...rest } = response; + let { code, data = {}, msg, ...rest } = response; if (!data) { - data = {} + data = {}; } if (typeof data === 'string') { data = { - value: data - } + value: data, + }; } // eslint-disable-next-line eqeqeq if (code == 'success') { - code = import.meta.env.VITE_SERVICE_SUCCESS_CODE; + code = 0; + } + + if (code == 'failure' || (msg && msg.includes('token无效'))) { + code = 401; } if (Array.isArray(data)) { data = { - rows: data + rows: data, }; } @@ -69,15 +73,17 @@ export function transferResponse(response: any) { } if (response.code == 200 && response.flag === false) { - code = 500 + code = 500; + } else if (response.code == '200') { + code = 0; } return { code, - msg, data: { ...data, - ...rest - } + ...rest, + }, + msg, }; } diff --git a/apps/web-office/src/api/system/auth.ts b/apps/web-office/src/api/system/auth.ts new file mode 100644 index 00000000..2aab2972 --- /dev/null +++ b/apps/web-office/src/api/system/auth.ts @@ -0,0 +1,84 @@ +import { baseRequestClient, requestClient } from '#/api/request/index'; +import type { UserInfo } from '@vben/types'; + +import { useAccessStore } from '@vben/stores'; + +export namespace AuthApi { + /** 登录接口参数 */ + export interface LoginParams { + password: string; + username: string; + } + + /** 登录接口返回值 */ + export interface LoginResult { + accessToken: string; + desc: string; + realName: string; + userId: string; + username: string; + } + + export interface RefreshTokenResult { + data: string; + status: number; + } +} + +/** + * 登录 + */ +export async function loginApi(data: AuthApi.LoginParams) { + return requestClient.post( + '/uc/uaa/validateAccount', + data, + { + transformResponse: (res) => { + res = JSON.parse(res); + console.log(res); + const info = res.data; + if (info.access_token) { + info.accessToken = info.access_token; + info.realName = info.display_name; + return info + } + return res; + }, + }, + ); +} + +/** + * 刷新accessToken + */ +export async function refreshTokenApi() { + return baseRequestClient.post('/auth/refresh', { + withCredentials: true, + }); +} + +/** + * 退出登录 + */ +export async function logoutApi() { + return baseRequestClient.post('/uc/uaa/logout', { + withCredentials: true, + }); +} + +/** + * 获取用户权限码 + */ +export async function getAccessCodesApi() { + return requestClient.get('/auth/codes'); +} + +/** + * 获取用户信息 + */ +export async function getUserInfoApi() { + const accessStore = useAccessStore(); + return requestClient.post('/uc/sys/user/checkToken', { + token: accessStore.accessToken, + }); +} diff --git a/apps/web-office/src/api/system/menu.ts b/apps/web-office/src/api/system/menu.ts new file mode 100644 index 00000000..da355a6c --- /dev/null +++ b/apps/web-office/src/api/system/menu.ts @@ -0,0 +1,10 @@ +import type { RouteRecordStringComponent } from '@vben/types'; + +import { requestClient } from '#/api/request/index'; + +/** + * 获取用户所有菜单 + */ +export async function getAllMenusApi() { + return requestClient.get('/menu/all'); +} diff --git a/apps/web-office/src/app.vue b/apps/web-office/src/app.vue new file mode 100644 index 00000000..62ab9f79 --- /dev/null +++ b/apps/web-office/src/app.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/src/assets/canteen/orderfood.png b/apps/web-office/src/assets/canteen/orderfood.png similarity index 100% rename from src/assets/canteen/orderfood.png rename to apps/web-office/src/assets/canteen/orderfood.png diff --git a/apps/web-office/src/bootstrap.ts b/apps/web-office/src/bootstrap.ts new file mode 100644 index 00000000..8d29b946 --- /dev/null +++ b/apps/web-office/src/bootstrap.ts @@ -0,0 +1,42 @@ +import { createApp } from 'vue'; + +import { registerAccessDirective } from '@vben/access'; +import { initStores } from '@vben/stores'; +import '@vben/styles'; +import '@vben/styles/antd'; + +import { setupI18n } from '#/locales'; + +import App from './app.vue'; +import { registerFastCrud } from './plugins/fastCrud'; +import { registerVxeTable } from './plugins/vxeTable'; + +import { router } from './router'; +import { VbenButton } from '@vben-core/shadcn-ui'; + +async function bootstrap(namespace: string) { + const app = createApp(App); + + // 国际化 i18n 配置 + await setupI18n(app); + + // 配置 pinia-tore + await initStores(app, { namespace }); + + // 安装权限指令 + registerAccessDirective(app); + + // 配置路由及路由守卫 + app.use(router); + + // 引入 fast-crud 相关组件 + registerFastCrud(app); + + registerVxeTable(app) + + app.component('vben-button', VbenButton); + + app.mount('#app'); +} + +export { bootstrap }; diff --git a/apps/web-office/src/common/unit.ts b/apps/web-office/src/common/unit.ts new file mode 100644 index 00000000..a2be8f14 --- /dev/null +++ b/apps/web-office/src/common/unit.ts @@ -0,0 +1,94 @@ +import { dict } from "@fast-crud/fast-crud"; +import Apis from '#/api' + +export const unitComponentProps = { + name: 'fs-dict-tree', + vModel: 'value', + allowClear: true, + class: 'min-w-[180px]', + showCheckedStrategy: "SHOW_CHILD", + dict: dict({ + isTree: true, + async getData(dict, context) { + const data = await Apis.api.core.orgemplbc.organization.post_paging({ + params: { + page: 1, + size: 1000 + }, + data: { + subFilter: [ + { + symbol: "like", + singleValue: "0001%", + key: "ORG_ID", + logic: "AND", + }, + ], + } + }); + data.rows.forEach((item: any) => { + item.label = item.ORG_NAME + item.value = item.ORG_ID + }) + let treeData = transTree(data.rows); + return treeData; + }, + }), +} + +export async function getUnitData(params = {}) { + const data = await Apis.api.core.orgemplbc.organization.post_paging({ + params: { + page: 1, + size: 1000 + }, + data: { + subFilter: [ + { + symbol: "like", + singleValue: "0001%", + key: "ORG_ID", + logic: "AND", + }, + ], + } + }); + data.rows.forEach((item: any) => { + item.label = item.ORG_NAME + item.value = item.ORG_ID + }) + let treeData = transTree(data.rows); + return treeData; +} + +// 转换树行数据的方法 +function transTree(list) { + // 最终生成的树行结构 + const _treeData = []; + + // 对传入进来的 数据进行遍历,查找对应的子级 + list.forEach((item) => { + // 给每一项添加子节点 + // item.children = [] + item.key = item.ORG_ID; + item.label = item.ORG_NAME; + // 如果 pid 为空,说明是最顶级,直接放到 _treeData 中即可 + if (item.ORG_LEVEL == 1) { + item.selectable = false + _treeData.push(item); + } + + // 根据前面的分析,pid 代表的是父级的 id,从而可以进行筛选子级 + // filter 方法会把满足条件到的每一项,组成一个数组进行返回 + const children = list.filter((data) => data.PARENT_ID === item.ORG_ID); + + // 如果没有子节点,直接 return 不做任何处理 + if (!children.length) return; + + // 将返回的子级进行赋值给父级(item)的 children 属性 + item.children = children; + }); + + // 将最终生成的数据返回出去 + return _treeData; +} diff --git a/apps/web-office/src/components/dict-tag/dict-tag.vue b/apps/web-office/src/components/dict-tag/dict-tag.vue new file mode 100644 index 00000000..393d1c6e --- /dev/null +++ b/apps/web-office/src/components/dict-tag/dict-tag.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/apps/web-office/src/components/dict-tag/index.ts b/apps/web-office/src/components/dict-tag/index.ts new file mode 100644 index 00000000..881265a3 --- /dev/null +++ b/apps/web-office/src/components/dict-tag/index.ts @@ -0,0 +1 @@ +export { default as DictTag } from './dict-tag.vue'; diff --git a/CHANGELOG.md b/apps/web-office/src/hooks/fastCrud.ts similarity index 100% rename from CHANGELOG.md rename to apps/web-office/src/hooks/fastCrud.ts diff --git a/src/components/Table/src/hooks/useRender.ts b/apps/web-office/src/hooks/useRender.ts similarity index 72% rename from src/components/Table/src/hooks/useRender.ts rename to apps/web-office/src/hooks/useRender.ts index c6204436..31eba247 100644 --- a/src/components/Table/src/hooks/useRender.ts +++ b/apps/web-office/src/hooks/useRender.ts @@ -1,51 +1,45 @@ import { h } from 'vue'; import dayjs from 'dayjs'; -import { NButton, NTag, NTooltip } from 'naive-ui'; -import { isArray, isString } from '@/utils/is'; -import { DictTag } from '@/components/DictTag'; +import { Button, Tag } from 'ant-design-vue'; +import { isArray, isString } from 'lodash-es'; +import { DictTag } from '#/components/dict-tag'; // import { Icon } from '@/components/Icon'; -// import { JsonPreview } from '@/components/CodeEditor'; -import TableImg from '../components/TableImg.vue'; -import { getDictOpts } from '@/utils/dict'; - +import { Tooltip } from 'ant-design-vue' +import { getDictOpts } from '#/utils/dict'; export const useRender = { /** * 渲染图片 - * * @param text 图片地址 * @returns image标签 */ - renderImg: (text: string, props?: AnyObject) => { - if (text) { - if (isArray(text)) return h(TableImg, { imgList: text, ...props }); - else if (isString(text)) return h(TableImg, { imgList: [text], ...props }); - } - return ''; - }, + // renderImg: (text: string) => { + // if (text) { + // if (isArray(text)) return h(TableImg, { imgList: text }); + // else if (isString(text)) return h(TableImg, { imgList: [text] }); + // } + // return ''; + // }, /** * 渲染链接 - * * @param url 链接地址 * @param text 文字说明 * @returns link 按钮 */ renderLink: (url: string, text?: string) => { - if (url) return h(NButton, { text: true, type: 'info', href: url, target: '_blank' }, () => text || ''); + if (url) return h(Button, { type: 'link', href: url, target: '_blank' }, () => text || ''); return ''; }, /** * 渲染文本,将text与val 拼接到一起 - * * @param text 文本1 * @param val 文本2 * @returns 文本1 + 文本2 */ - renderText(text, val) { - if (text != undefined) return h('div', `${text} ${val}`); - return h('div', ''); + renderText: (text: string, val: string) => { + if (text) return `${text} ${val}`; + else return ''; }, - /** * 渲染多行文本 * @param text @@ -59,7 +53,7 @@ export const useRender = { classArr.push('line-clamp-' + params?.maxLine) } return h( - NTooltip, + Tooltip, { trigger: 'hover' }, { trigger: () => h('span', { class: classArr.join(' ') }, text), @@ -71,34 +65,31 @@ export const useRender = { }, /** * 渲染标签 - * * @param text 标签文本 * @param color 标签颜色 * @returns 标签 */ renderTag: (text: string | number, color?: string) => { - if (color) return h(NTag, { type: color }, () => text); - return h(NTag, {}, () => text); + if (color) return h(Tag, { color }, () => text); + else return h(Tag, {}, () => text); }, /** * 渲染多标签 - * * @param texts 文本 * @returns 多标签 */ renderTags: (texts: string[]) => { if (texts) { return h('div', null, [ - texts.map(text => { - return h(NTag, null, () => text); - }) + texts.map((text) => { + return h(Tag, null, () => text); + }), ]); } return ''; }, /** * 渲染日期 - * * @param text 日期 * @param format 格式化 * @returns 格式化后日期 @@ -107,11 +98,10 @@ export const useRender = { if (!text) return ''; if (!format) return dayjs(text).format('YYYY-MM-DD HH:mm:ss'); - return dayjs(text).format(format); + else return dayjs(text).format(format); }, /** * 渲染字典 - * * @param text 字典值 * @param dictType 字典类型 * @returns 字典标签 @@ -139,15 +129,14 @@ export const useRender = { // if (text) return h(Icon, { icon: text }); // }, /** - * 使用JsonPreview组件 方便预览JSON - * + * 使用JsonPreview组件 方便预览JSON * @param json json字符串/obj * @returns 能转为json返回JsonPreview 否则返回自身 */ // renderJsonPreview: (json: any) => { // if (!json) return ''; // if (typeof json === 'object') return h(JsonPreview, { data: json }); - // + // if (typeof json === 'string') { // try { // const data = JSON.parse(json); @@ -156,5 +145,5 @@ export const useRender = { // return json; // } // } - // } + // }, }; diff --git a/src/hooks/common/vxeTable.ts b/apps/web-office/src/hooks/vxeTable.ts similarity index 92% rename from src/hooks/common/vxeTable.ts rename to apps/web-office/src/hooks/vxeTable.ts index 19baaa76..26cd7c39 100644 --- a/src/hooks/common/vxeTable.ts +++ b/apps/web-office/src/hooks/vxeTable.ts @@ -1,13 +1,13 @@ import { merge } from "lodash-es"; -import { ref, computed } from "vue"; -import { VxeGridInstance, VxeGridProps } from "vxe-table"; +import { ref } from "vue"; +import { type VxeGridInstance, type VxeGridProps } from "vxe-table"; export function useVxeTable(props: { ref: string, }) { - const xGridRef = ref>(); + const xGridRef = ref>(); return { xGridRef, diff --git a/apps/web-office/src/layouts/basic.vue b/apps/web-office/src/layouts/basic.vue new file mode 100644 index 00000000..f5c35393 --- /dev/null +++ b/apps/web-office/src/layouts/basic.vue @@ -0,0 +1,164 @@ + + + diff --git a/apps/web-office/src/layouts/index.ts b/apps/web-office/src/layouts/index.ts new file mode 100644 index 00000000..23d79d6e --- /dev/null +++ b/apps/web-office/src/layouts/index.ts @@ -0,0 +1,8 @@ +const BasicLayout = () => import('./basic.vue'); + +const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView); + +const AuthPageLayout = () => + import('@vben/layouts').then((m) => m.AuthPageLayout); + +export { AuthPageLayout, BasicLayout, IFrameView }; diff --git a/apps/web-office/src/locales/README.md b/apps/web-office/src/locales/README.md new file mode 100644 index 00000000..7b451032 --- /dev/null +++ b/apps/web-office/src/locales/README.md @@ -0,0 +1,3 @@ +# locale + +每个app使用的国际化可能不同,这里用于扩展国际化的功能,例如扩展 dayjs、antd组件库的多语言切换,以及app本身的国际化文件。 diff --git a/apps/web-office/src/locales/index.ts b/apps/web-office/src/locales/index.ts new file mode 100644 index 00000000..c3fd8c84 --- /dev/null +++ b/apps/web-office/src/locales/index.ts @@ -0,0 +1,94 @@ +import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales'; +import type { Locale } from 'ant-design-vue/es/locale'; + +import type { App } from 'vue'; +import { ref } from 'vue'; + +import { $t, setupI18n as coreSetup, loadLocalesMap } from '@vben/locales'; +import { preferences } from '@vben/preferences'; + +import antdEnLocale from 'ant-design-vue/es/locale/en_US'; +import antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN'; +import dayjs from 'dayjs'; + +const antdLocale = ref(antdDefaultLocale); + +const modules = import.meta.glob('./langs/*.json'); + +const localesMap = loadLocalesMap(modules); + +/** + * 加载应用特有的语言包 + * 这里也可以改造为从服务端获取翻译数据 + * @param lang + */ +async function loadMessages(lang: SupportedLanguagesType) { + const [appLocaleMessages] = await Promise.all([ + localesMap[lang]?.(), + loadThirdPartyMessage(lang), + ]); + return appLocaleMessages?.default; +} + +/** + * 加载第三方组件库的语言包 + * @param lang + */ +async function loadThirdPartyMessage(lang: SupportedLanguagesType) { + await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]); +} + +/** + * 加载dayjs的语言包 + * @param lang + */ +async function loadDayjsLocale(lang: SupportedLanguagesType) { + let locale; + switch (lang) { + case 'zh-CN': { + locale = await import('dayjs/locale/zh-cn'); + break; + } + case 'en-US': { + locale = await import('dayjs/locale/en'); + break; + } + // 默认使用英语 + default: { + locale = await import('dayjs/locale/en'); + } + } + if (locale) { + dayjs.locale(locale); + } else { + console.error(`Failed to load dayjs locale for ${lang}`); + } +} + +/** + * 加载antd的语言包 + * @param lang + */ +async function loadAntdLocale(lang: SupportedLanguagesType) { + switch (lang) { + case 'zh-CN': { + antdLocale.value = antdDefaultLocale; + break; + } + case 'en-US': { + antdLocale.value = antdEnLocale; + break; + } + } +} + +async function setupI18n(app: App, options: LocaleSetupOptions = {}) { + await coreSetup(app, { + defaultLocale: preferences.app.locale, + loadMessages, + missingWarn: !import.meta.env.PROD, + ...options, + }); +} + +export { $t, antdLocale, setupI18n }; diff --git a/apps/web-office/src/locales/langs/en-US.json b/apps/web-office/src/locales/langs/en-US.json new file mode 100644 index 00000000..864c721f --- /dev/null +++ b/apps/web-office/src/locales/langs/en-US.json @@ -0,0 +1,8 @@ +{ + "page": { + "demos": { + "title": "Demos", + "antd": "Ant Design Vue" + } + } +} diff --git a/apps/web-office/src/locales/langs/zh-CN.json b/apps/web-office/src/locales/langs/zh-CN.json new file mode 100644 index 00000000..31d3475b --- /dev/null +++ b/apps/web-office/src/locales/langs/zh-CN.json @@ -0,0 +1,8 @@ +{ + "page": { + "demos": { + "title": "演示", + "antd": "Ant Design Vue" + } + } +} diff --git a/apps/web-office/src/main.ts b/apps/web-office/src/main.ts new file mode 100644 index 00000000..5d728a02 --- /dev/null +++ b/apps/web-office/src/main.ts @@ -0,0 +1,31 @@ +import { initPreferences } from '@vben/preferences'; +import { unmountGlobalLoading } from '@vben/utils'; + +import { overridesPreferences } from './preferences'; + +/** + * 应用初始化完成之后再进行页面加载渲染 + */ +async function initApplication() { + // name用于指定项目唯一标识 + // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据 + const env = import.meta.env.PROD ? 'prod' : 'dev'; + const appVersion = import.meta.env.VITE_APP_VERSION; + const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`; + + // app偏好设置初始化 + await initPreferences({ + namespace, + overrides: overridesPreferences, + }); + + // 启动应用并挂载 + // vue应用主要逻辑及视图 + const { bootstrap } = await import('./bootstrap'); + await bootstrap(namespace); + + // 移除并销毁loading + unmountGlobalLoading(); +} + +initApplication(); diff --git a/apps/web-office/src/plugins/fastCrud.ts b/apps/web-office/src/plugins/fastCrud.ts new file mode 100644 index 00000000..3477afa9 --- /dev/null +++ b/apps/web-office/src/plugins/fastCrud.ts @@ -0,0 +1,21 @@ +import type { App } from 'vue'; + +import FastCrud from '@fast-crud/fast-crud'; +import ui from '@fast-crud/ui-antdv4'; +import Antdv from 'ant-design-vue'; +import { requestClient } from '#/api/request/index'; +import '@fast-crud/fast-crud/dist/style.css'; +import '@fast-crud/ui-antdv4/dist/style.css'; + +export function registerFastCrud(app: App) { + app.use(Antdv); + app.use(ui); + app.use(FastCrud, { + async dictRequest(dict) { + //通过字段组件中配置的dict.url获取远程字典数据 + let res = await requestClient.get('/app/dictData/page'); + console.log(res) + return res.rows; + }, + }); +} diff --git a/apps/web-office/src/plugins/vxeTable.ts b/apps/web-office/src/plugins/vxeTable.ts new file mode 100644 index 00000000..cc408cce --- /dev/null +++ b/apps/web-office/src/plugins/vxeTable.ts @@ -0,0 +1,202 @@ +import type { App } from 'vue'; + +import VXETable from 'vxe-table' + +import { + VxeTable, + VxeColumn, + VxeColgroup, + VxeGrid, + VxeToolbar +} from 'vxe-table' + +import VxeUI from 'vxe-pc-ui' + +import { + + VxeAlert, + VxeAnchor, + VxeAnchorLink, + VxeBreadcrumb, + VxeBreadcrumbItem, + VxeButton, + VxeButtonGroup, + VxeCalendar, + VxeCard, + VxeCarousel, + VxeCheckbox, + VxeCheckboxGroup, + VxeCol, + VxeCollapse, + VxeCollapsePane, + VxeDatePicker, + VxeDrawer, + VxeForm, + VxeFormDesign, + VxeFormGather, + VxeFormItem, + VxeFormView, + VxeIcon, + VxeIconPicker, + VxeImage, + VxeImageGroup, + VxeImagePreview, + VxeInput, + VxeLayoutAside, + VxeLayoutBody, + VxeLayoutContainer, + VxeLayoutFooter, + VxeLayoutHeader, + VxeLink, + VxeListDesign, + VxeListView, + VxeList, + VxeLoading, + VxeMenu, + VxeModal, + VxeNumberInput, + VxeOptgroup, + VxeOption, + VxePager, + VxePasswordInput, + VxePrintPageBreak, + VxePrint, + VxePulldown, + VxeRadio, + VxeRadioButton, + VxeRadioGroup, + VxeRow, + VxeSelect, + VxeSwitch, + VxeTabPane, + VxeTabs, + VxeTag, + VxeText, + VxeTextarea, + VxeTip, + VxeTooltip, + VxeTree, + VxeTreeSelect, + VxeUpload +} from 'vxe-pc-ui' + +import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx' +import ExcelJS from 'exceljs' + +import VXETablePluginAntd from 'vxe-table-plugin-antd' + +// 导入主题变量,也可以重写主题变量 +import 'vxe-pc-ui/lib/style.css' +import 'vxe-table/lib/style.css' +import 'vxe-table/styles/cssvar.scss' +import 'vxe-pc-ui/styles/cssvar.scss' + +// VxeUI.setTheme('dark') + +VxeUI.component(VxeAlert) +VxeUI.component(VxeAnchor) +VxeUI.component(VxeAnchorLink) +VxeUI.component(VxeBreadcrumb) +VxeUI.component(VxeBreadcrumbItem) +VxeUI.component(VxeButton) +VxeUI.component(VxeButtonGroup) +VxeUI.component(VxeCalendar) +VxeUI.component(VxeCard) +VxeUI.component(VxeCarousel) +VxeUI.component(VxeCheckbox) +VxeUI.component(VxeCheckboxGroup) +VxeUI.component(VxeCol) +VxeUI.component(VxeCollapse) +VxeUI.component(VxeCollapsePane) +VxeUI.component(VxeDatePicker) +VxeUI.component(VxeDrawer) +VxeUI.component(VxeForm) +VxeUI.component(VxeFormDesign) +VxeUI.component(VxeFormGather) +VxeUI.component(VxeFormItem) +VxeUI.component(VxeFormView) +VxeUI.component(VxeIcon) +VxeUI.component(VxeIconPicker) +VxeUI.component(VxeImage) +VxeUI.component(VxeImageGroup) +VxeUI.component(VxeImagePreview) +VxeUI.component(VxeInput) +VxeUI.component(VxeLayoutAside) +VxeUI.component(VxeLayoutBody) +VxeUI.component(VxeLayoutContainer) +VxeUI.component(VxeLayoutFooter) +VxeUI.component(VxeLayoutHeader) +VxeUI.component(VxeLink) +VxeUI.component(VxeListDesign) +VxeUI.component(VxeListView) +VxeUI.component(VxeList) +VxeUI.component(VxeLoading) +VxeUI.component(VxeMenu) +VxeUI.component(VxeModal) +VxeUI.component(VxeNumberInput) +VxeUI.component(VxeOptgroup) +VxeUI.component(VxeOption) +VxeUI.component(VxePager) +VxeUI.component(VxePasswordInput) +VxeUI.component(VxePrintPageBreak) +VxeUI.component(VxePrint) +VxeUI.component(VxePulldown) +VxeUI.component(VxeRadio) +VxeUI.component(VxeRadioButton) +VxeUI.component(VxeRadioGroup) +VxeUI.component(VxeRow) +VxeUI.component(VxeSelect) +VxeUI.component(VxeSwitch) +VxeUI.component(VxeTabPane) +VxeUI.component(VxeTabs) +VxeUI.component(VxeTag) +VxeUI.component(VxeText) +VxeUI.component(VxeTextarea) +VxeUI.component(VxeTip) +VxeUI.component(VxeTooltip) +VxeUI.component(VxeTree) +VxeUI.component(VxeTreeSelect) +VxeUI.component(VxeUpload) + +VxeUI.component(VxeTable) +VxeUI.component(VxeColumn) +VxeUI.component(VxeColgroup) +VxeUI.component(VxeGrid) +VxeUI.component(VxeToolbar) + +VXETable.use(VXETablePluginAntd) + +VXETable.use(VXETablePluginExportXLSX, { + ExcelJS +}) + +VXETable.setConfig({ + zIndex: 9999, + grid: { + size: 'mini', + proxyConfig: { + props: { + result: 'data.rows', + total: 'data.total', + }, + }, + toolbarConfig: { + enabled: true, + }, + }, + + pager: { + background: true, + pageSize: 50, + pageSizes: [50, 100, 300, 500, 1000], + layouts: ['PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'Sizes', 'FullJump', 'Total'], + }, +}) +export function registerVxeTable(app: App) { + app.use(VxeUI) + app.use(VxeTable) + app.use(VxeColumn) + app.use(VxeColgroup) + app.use(VxeGrid) + app.use(VxeToolbar) +} diff --git a/apps/web-office/src/preferences.ts b/apps/web-office/src/preferences.ts new file mode 100644 index 00000000..63edb3a9 --- /dev/null +++ b/apps/web-office/src/preferences.ts @@ -0,0 +1,12 @@ +import { defineOverridesPreferences } from '@vben/preferences'; + +/** + * @description 项目配置文件 + * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置 + */ +export const overridesPreferences = defineOverridesPreferences({ + // overrides + app: { + name: import.meta.env.VITE_APP_TITLE, + }, +}); diff --git a/apps/web-office/src/router/access.ts b/apps/web-office/src/router/access.ts new file mode 100644 index 00000000..72c1b2c0 --- /dev/null +++ b/apps/web-office/src/router/access.ts @@ -0,0 +1,42 @@ +import type { + ComponentRecordType, + GenerateMenuAndRoutesOptions, +} from '@vben/types'; + +import { generateAccessible } from '@vben/access'; +import { preferences } from '@vben/preferences'; + +import { message } from 'ant-design-vue'; + +import { getAllMenusApi } from '#/api/system/menu'; +import { BasicLayout, IFrameView } from '#/layouts'; +import { $t } from '#/locales'; + +const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue'); + +async function generateAccess(options: GenerateMenuAndRoutesOptions) { + const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue'); + + const layoutMap: ComponentRecordType = { + BasicLayout, + IFrameView, + }; + + return await generateAccessible(preferences.app.accessMode, { + ...options, + fetchMenuListAsync: async () => { + message.loading({ + content: `${$t('common.loadingMenu')}...`, + duration: 1.5, + }); + return await getAllMenusApi(); + }, + // 可以指定没有权限跳转403页面 + forbiddenComponent, + // 如果 route.meta.menuVisibleWithForbidden = true + layoutMap, + pageMap, + }); +} + +export { generateAccess }; diff --git a/apps/web-office/src/router/guard.ts b/apps/web-office/src/router/guard.ts new file mode 100644 index 00000000..1e94cd8d --- /dev/null +++ b/apps/web-office/src/router/guard.ts @@ -0,0 +1,240 @@ +import type { Router } from 'vue-router'; + +import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; +import { preferences } from '@vben/preferences'; +import { useAccessStore, useUserStore } from '@vben/stores'; +import { startProgress, stopProgress } from '@vben/utils'; + +import { useTitle } from '@vueuse/core'; + +import { $t } from '#/locales'; +import { coreRouteNames, dynamicRoutes } from '#/router/routes'; +import { useAuthStore } from '#/store'; +import Apis from '#/api'; +import { generateAccess } from './access'; + +/** + * 通用守卫配置 + * @param router + */ +function setupCommonGuard(router: Router) { + // 记录已经加载的页面 + const loadedPaths = new Set(); + + router.beforeEach(async (to) => { + to.meta.loaded = loadedPaths.has(to.path); + + // 页面加载进度条 + if (!to.meta.loaded && preferences.transition.progress) { + startProgress(); + } + return true; + }); + + router.afterEach((to) => { + // 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行 + + if (preferences.tabbar.enable) { + loadedPaths.add(to.path); + } + + // 关闭页面加载进度条 + if (preferences.transition.progress) { + stopProgress(); + } + + // 动态修改标题 + if (preferences.app.dynamicTitle) { + const { title } = to.meta; + // useTitle(`${$t(title)} - ${preferences.app.name}`); + useTitle(`${$t(title)} - ${preferences.app.name}`); + } + }); +} + +/** + * 匹配路径 + * permission.path = "/xx/edit" 但route.path = "/xx/edit/:id?" 这种情况,其中id可以为任意值,如meetingId roleId等, + */ +function matchPaths(routePath, permissionPath) { + const routeParts = routePath.split('/'); + const permissionParts = permissionPath.split('/'); + + if (permissionParts.length > routeParts.length) { + return false; + } + + return routeParts.every((part, index) => { + return part === permissionParts[index] || part.startsWith(':'); + }); +} + +// 过滤路由,只保留第三个数据源配置的路由 +function filterRoutesByPermissions(routes, permissions, staticRouteKeys) { + const filteredRoutes = []; + for (let route of routes) { + console.log('[ route ] >', route) + console.log('[ permission.path ] >', permissions) + + const permission = permissions.find(permission => + matchPaths(route.path, permission.path) + ); + const isStaticRoute = staticRouteKeys.includes(route.name); + + if (permission || isStaticRoute) { + const newRoute = { ...route }; + if (permission) { + newRoute.meta = { + ...newRoute.meta, + title: permission.name, + }; + if (permission.order) { + newRoute.meta.order = permission.order + } + + } + if (route.children) { + newRoute.children = filterRoutesByPermissions(route.children, permissions, staticRouteKeys); + } + filteredRoutes.push(newRoute); + console.log(JSON.parse(JSON.stringify(filteredRoutes))); + + } + } + + return filteredRoutes; +} + +/** + * 权限访问守卫配置 + * @param router + */ +function setupAccessGuard(router: Router) { + router.beforeEach(async (to, from) => { + const accessStore = useAccessStore(); + const userStore = useUserStore(); + const authStore = useAuthStore(); + + // 基本路由,这些路由不需要进入权限拦截 + if (coreRouteNames.includes(to.name as string)) { + if (to.path === LOGIN_PATH && accessStore.accessToken) { + return decodeURIComponent( + (to.query?.redirect as string) || DEFAULT_HOME_PATH, + ); + } + return true; + } + + // accessToken 检查 + if (!accessStore.accessToken) { + // 明确声明忽略权限访问权限,则可以访问 + if (to.meta.ignoreAccess) { + return true; + } + + // 没有访问权限,跳转登录页面 + if (to.fullPath !== LOGIN_PATH) { + return { + path: LOGIN_PATH, + // 如不需要,直接删除 query + query: { redirect: encodeURIComponent(to.fullPath) }, + // 携带当前跳转的页面,登录后重新跳转该页面 + replace: true, + }; + } + return to; + } + + // 是否已经生成过动态路由 + if (accessStore.isAccessChecked) { + return true; + } + + // 生成路由表 + // 当前登录用户拥有的角色标识列表 + const userInfo = userStore.userInfo || (await authStore.fetchUserInfo()); + const userRoles = userInfo.roles ?? []; + + // debugger + + // 二开,从统一授权获取菜单key值,遍历本地所有菜单进行添加 + + let staticRouteKeys = ["Dashboard", "home", "User", "UserCenter", "UserTodo","IFrame","MeetingStandingBook","MeetingStart","DutyStandingBook","ContractInfo"]; + + let r = await Apis.sys.user.functiontree.get_XTBGXT() + let originRouters = r.rows[0].children; + // 提取数据的函数 + const extractData = (input: any[]) => { + const result: any[] = []; + function traverse(node: any) { + if (node.id && node.name && node.remark) { + result.push({ + path: node.remark, + name: node.name, + order: node.showOrder || 0, + }); + } + if (node.children && node.children.length > 0) { + for (const child of node.children) { + traverse(child); + } + } + } + + for (const node of input) { + traverse(node); + } + + return result; + } + console.log('originRouters', originRouters) + originRouters = extractData(originRouters); + console.log('originRouters', originRouters) + + let finalRoutes = filterRoutesByPermissions(dynamicRoutes, originRouters, staticRouteKeys); + + console.log(originRouters) + console.log('finalRoutes', finalRoutes) + + console.log('dynamicRoutes', dynamicRoutes) + console.log('userInfo', userInfo) + + if (userInfo.accountId == 'Admin.itl'|| userInfo._isSkip) { + finalRoutes = dynamicRoutes; + } + + console.log(userInfo) + + + // 生成菜单和路由 + const { accessibleMenus, accessibleRoutes } = await generateAccess({ + roles: userRoles, + router, + // 则会在菜单中显示,但是访问会被重定向到403 + routes: finalRoutes, + }); + // 保存菜单信息和路由信息 + accessStore.setAccessMenus(accessibleMenus); + accessStore.setAccessRoutes(accessibleRoutes); + accessStore.setIsAccessChecked(true); + const redirectPath = (from.query.redirect ?? to.fullPath) as string; + + return { + ...router.resolve(decodeURIComponent(redirectPath)), + replace: true, + }; + }); +} + +/** + * 项目守卫配置 + * @param router + */ +function createRouterGuard(router: Router) { + /** 通用 */ + setupCommonGuard(router); + /** 权限访问 */ + setupAccessGuard(router); +} + +export { createRouterGuard }; diff --git a/apps/web-office/src/router/index.ts b/apps/web-office/src/router/index.ts new file mode 100644 index 00000000..313b372b --- /dev/null +++ b/apps/web-office/src/router/index.ts @@ -0,0 +1,32 @@ +import { + createRouter, + createWebHashHistory, + createWebHistory, +} from 'vue-router'; + +import { resetStaticRoutes } from '@vben/utils'; + +import { createRouterGuard } from './guard'; +import { routes } from './routes'; + +/** + * @zh_CN 创建vue-router实例 + */ +const router = createRouter({ + history: + import.meta.env.VITE_ROUTER_HISTORY === 'hash' + ? createWebHashHistory(import.meta.env.VITE_BASE) + : createWebHistory(import.meta.env.VITE_BASE), + // 应该添加到路由的初始路由列表。 + routes, + scrollBehavior: () => ({ left: 0, top: 0 }), + // 是否应该禁止尾部斜杠。 + // strict: true, +}); + +const resetRoutes = () => resetStaticRoutes(router, routes); + +// 创建路由守卫 +createRouterGuard(router); + +export { resetRoutes, router }; diff --git a/apps/web-office/src/router/routes/core.ts b/apps/web-office/src/router/routes/core.ts new file mode 100644 index 00000000..e6b2dbe4 --- /dev/null +++ b/apps/web-office/src/router/routes/core.ts @@ -0,0 +1,144 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { DEFAULT_HOME_PATH } from '@vben/constants'; + +import { AuthPageLayout, BasicLayout, IFrameView } from '#/layouts'; +import { $t } from '#/locales'; +import Login from '#/views/_core/authentication/login.vue'; + +/** 全局404页面 */ +const fallbackNotFoundRoute: RouteRecordRaw = { + component: () => import('#/views/_core/fallback/not-found.vue'), + meta: { + hideInBreadcrumb: true, + hideInMenu: true, + hideInTab: true, + title: '404', + }, + name: 'FallbackNotFound', + path: '/:path(.*)*', +}; + +/** 基本路由,这些路由是必须存在的 */ +const coreRoutes: RouteRecordRaw[] = [ + { + meta: { + title: 'Root', + }, + name: 'Root', + path: '/', + redirect: DEFAULT_HOME_PATH, + }, + { + component: AuthPageLayout, + meta: { + title: 'Authentication', + }, + name: 'Authentication', + path: '/auth', + children: [ + { + name: 'Login', + path: 'login', + component: Login, + meta: { + title: $t('page.core.login'), + }, + }, + { + name: 'CodeLogin', + path: 'code-login', + component: () => import('#/views/_core/authentication/code-login.vue'), + meta: { + title: $t('page.core.codeLogin'), + }, + }, + { + name: 'QrCodeLogin', + path: 'qrcode-login', + component: () => + import('#/views/_core/authentication/qrcode-login.vue'), + meta: { + title: $t('page.core.qrcodeLogin'), + }, + }, + { + name: 'ForgetPassword', + path: 'forget-password', + component: () => + import('#/views/_core/authentication/forget-password.vue'), + meta: { + title: $t('page.core.forgetPassword'), + }, + }, + { + name: 'Register', + path: 'register', + component: () => import('#/views/_core/authentication/register.vue'), + meta: { + title: $t('page.core.register'), + }, + }, + ], + }, + { + component: IFrameView, + meta: { + icon: 'lucide:layout-dashboard', + order: 210, + title: 'iframe', + hideInMenu: true, + hideInTab: true, + }, + name: 'IFrame', + path: '/iframe', + children: [ + { + name: 'MeetingStandingBook', + path: '/iframe/meeting/standing-book', + component: () => import('#/views/meeting/standing-book/index.vue'), + meta: { + hideInMenu: true, + hideInTab: true, + icon: 'lucide:area-chart', + title: '供热公司网络生产会议系统-会议查询篇', + }, + }, + { + name: 'MeetingStart', + path: '/iframe/meeting/start/:id?', + component: () => import('#/views/meeting/start/index.vue'), + meta: { + hideInMenu: true, + hideInTab: true, + icon: 'lucide:area-chart', + title: '会议发起', + }, + }, + { + name: 'DutyStandingBook', + path: '/iframe/duty/standing-book', + component: () => import('#/views/duty/standing-book/index.vue'), + meta: { + hideInMenu: true, + hideInTab: true, + icon: 'lucide:area-chart', + title: '值班信息栏', + }, + }, + { + name: 'ContractInfo', + path: '/iframe/contract/info', + component: () => import('#/views/contract/iframe-info/index.vue'), + meta: { + hideInMenu: true, + hideInTab: true, + icon: 'lucide:area-chart', + title: '合同明细信息', + }, + }, + ], + }, +]; + +export { coreRoutes, fallbackNotFoundRoute }; diff --git a/apps/web-office/src/router/routes/index.ts b/apps/web-office/src/router/routes/index.ts new file mode 100644 index 00000000..a70c4875 --- /dev/null +++ b/apps/web-office/src/router/routes/index.ts @@ -0,0 +1,31 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { mergeRouteModules, traverseTreeValues } from '@vben/utils'; + +import { coreRoutes, fallbackNotFoundRoute } from './core'; + +const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', { + eager: true, +}); + +// 有需要可以自行打开注释,并创建文件夹 +// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true }); + +/** 动态路由 */ +const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles); + +/** 外部路由列表,访问这些页面可以不需要Layout,可能用于内嵌在别的系统 */ +// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles); +const externalRoutes: RouteRecordRaw[] = []; + +/** 路由列表,由基本路由+静态路由组成 */ +const routes: RouteRecordRaw[] = [ + ...coreRoutes, + ...externalRoutes, + fallbackNotFoundRoute, +]; + +/** 基本路由列表,这些路由不需要进入权限拦截 */ +const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name); + +export { coreRouteNames, dynamicRoutes, routes }; diff --git a/apps/web-office/src/router/routes/modules/contract.ts b/apps/web-office/src/router/routes/modules/contract.ts new file mode 100644 index 00000000..e6191055 --- /dev/null +++ b/apps/web-office/src/router/routes/modules/contract.ts @@ -0,0 +1,438 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { BasicLayout } from '#/layouts'; + +const routes: RouteRecordRaw[] = [ + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: 2000, + title: '合同管理', + }, + name: 'Contract', + path: '/contract', + children: [ + { + name: 'ContractConfig', + path: '/contract/config', + component: () => import('#/views/contract/config/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '合同配置', + }, + }, + { + name: 'ContractApproval', + path: '/contract/approval', + meta: { + icon: 'lucide:area-chart', + title: '合同立项', + }, + children: [ + { + name: 'ContractApprovalEdit', + path: '/contract/approval/edit/:id?', + beforeEnter: (e) => { + if (e.params.id && e.params.id === ':id') { + e.params.id = '' + e.fullPath = '/contract/approval/edit' + } + }, + component: () => import('#/views/contract/approval/edit/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '立项申报', + activePath: '/contract/approval/edit/:id?' + }, + }, + { + name: 'ContractApprovalTodo', + path: '/contract/approval/todo', + component: () => import('#/views/contract/approval/todo/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '立项提示', + }, + }, + { + name: 'ContractApprovalList', + path: '/contract/approval/list', + component: () => import('#/views/contract/approval/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '立项查询', + }, + }, + { + name: 'ContractApprovalSigningBasis', + path: '/contract/approval/signing-basis', + component: () => import('#/views/contract/approval/signing-basis/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '签约依据维护', + }, + } + ], + }, + { + name: 'ContractBusiness', + path: '/contract/business', + meta: { + icon: 'lucide:area-chart', + title: '合同选商', + }, + children: [ + { + name: 'ContractBusiness', + path: '/contract/business/edit/:id?', + beforeEnter: (e) => { + if (e.params.id && e.params.id === ':id') { + e.params.id = '' + e.fullPath = '/contract/business/edit' + } + }, + component: () => import('#/views/contract/business/edit/index.vue'), + meta: { + hideInMenu: true, + hideInTab: true, + icon: 'lucide:area-chart', + title: '选商填报', + activePath: '/contract/business/edit/:id?' + }, + }, + { + name: 'ContractBusinessTodo', + path: '/contract/business/todo', + component: () => import('#/views/contract/business/todo/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '选商提示', + }, + }, + { + name: 'ContractBusinessList', + path: '/contract/business/list', + component: () => import('#/views/contract/business/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '选商查询', + }, + }, + ], + }, + { + name: 'ContractDeclaration', + path: '/contract/declaration', + meta: { + icon: 'lucide:area-chart', + title: '合同申报', + }, + children: [ + { + name: 'ContractDeclarationTodo', + path: '/contract/declaration/todo', + component: () => import('#/views/contract/declaration/todo/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '申报提示', + }, + }, + { + name: 'ContractDeclarationList', + path: '/contract/declaration/list', + component: () => import('#/views/contract/declaration/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '申报查询', + }, + }, + { + name: 'ContractDeclarationPrint', + path: '/contract/declaration/print', + component: () => import('#/views/contract/declaration/print/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '合同打印', + }, + }, + ], + }, + { + name: 'ContractAudit', + path: '/contract/audit', + meta: { + icon: 'lucide:area-chart', + title: '合同审批', + }, + children: [ + { + name: 'ContractAuditTodo', + path: '/contract/audit/todo', + component: () => import('#/views/contract/audit/todo/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '审批提示', + }, + }, + { + name: 'ContractAuditList', + path: '/contract/audit/list', + component: () => import('#/views/contract/audit/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '审批查询', + }, + }, + ], + }, + { + name: 'ContractSign', + path: '/contract/sign', + meta: { + icon: 'lucide:area-chart', + title: '合同签订', + }, + children: [ + { + name: 'ContractSignTodo', + path: '/contract/sign/todo', + component: () => import('#/views/contract/sign/todo/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '签订提示', + }, + }, + { + name: 'ContractSignList', + path: '/contract/sign/list', + component: () => import('#/views/contract/sign/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '签订查询', + }, + }, + ], + }, + { + name: 'ContractPerform', + path: '/contract/perform', + meta: { + icon: 'lucide:area-chart', + title: '合同履行', + }, + children: [ + { + name: 'ContractPerformTodo', + path: '/contract/perform/todo', + component: () => import('#/views/contract/perform/todo/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '履行提示', + }, + }, + { + name: 'ContractPerformList', + path: '/contract/perform/list', + component: () => import('#/views/contract/perform/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '履行查询', + }, + }, + { + name: 'ContractPerformResult', + path: '/contract/perform/result', + component: () => import('#/views/contract/perform/result/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '履行结果填报', + }, + }, + { + name: 'ContractPerformTemporaryArchive', + path: '/contract/perform/temporary-archive', + component: () => import('#/views/contract/perform/temporary-archive/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '临时归档', + }, + }, + ], + }, + { + name: 'ContractArchive', + path: '/contract/archive', + meta: { + icon: 'lucide:area-chart', + title: '合同归档', + }, + children: [ + { + name: 'ContractArchiveTodoArchive', + path: '/contract/archive/todo/archive', + component: () => import('#/views/contract/archive/todo/archive.vue'), + meta: { + icon: 'lucide:area-chart', + title: '合同归档', + }, + }, + { + name: 'ContractArchiveTodoRetracement', + path: '/contract/archive/todo/retracement', + component: () => import('#/views/contract/archive/todo/retracement.vue'), + meta: { + icon: 'lucide:area-chart', + title: '合同回档', + }, + }, + { + name: 'ContractArchiveList', + path: '/contract/archive/list', + component: () => import('#/views/contract/archive/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '归档查询', + }, + }, + ], + }, + { + name: 'ContractSignAuthorization', + path: '/contract/sign-authorization', + meta: { + icon: 'lucide:area-chart', + title: '签约授权管理', + }, + children: [ + { + name: 'ContractSignAuthorizationEdit', + path: '/contract/sign-authorization/edit/:id?', + beforeEnter: (e) => { + if (e.params.id && e.params.id === ':id') { + e.params.id = '' + e.fullPath = '/contract/sign-authorization/edit' + } + }, + component: () => import('#/views/contract/sign-authorization/edit/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '签约授权申报', + }, + }, + { + name: 'ContractSignAuthorizationList', + path: '/contract/sign-authorization/list', + component: () => import('#/views/contract/sign-authorization/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '签约授权查询', + }, + }, + + ], + }, + { + name: 'ContractCompany', + path: '/contract/company', + meta: { + icon: 'lucide:area-chart', + title: '合同相对人', + }, + children: [ + { + name: 'ContractCompanyEdit', + path: '/contract/company/edit/:id?', + beforeEnter: (e) => { + if (e.params.id && e.params.id === ':id') { + e.params.id = '' + e.fullPath = '/contract/company/edit' + } + }, + component: () => import('#/views/contract/company/edit/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '相对人录入维护', + }, + }, + { + name: 'ContractCompanyList', + path: '/contract/company/list', + component: () => import('#/views/contract/company/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '相对人查询', + }, + }, + + ], + }, + // { + // name: 'ContractStatistic', + // path: '/contract/statistic', + // meta: { + // icon: 'lucide:area-chart', + // title: '统计分析', + // }, + // children: [ + // { + // name: 'ContractStatisticAnalysis', + // path: '/contract/statistic/analysis', + // beforeEnter: (e) => { + // if (e.params.id && e.params.id === ':id') { + // e.params.id = '' + // e.fullPath = '/contract/company/edit' + // } + // }, + // component: () => import('#/views/contract/company/edit/index.vue'), + // meta: { + // icon: 'lucide:area-chart', + // title: '统计分析', + // }, + // }, + // { + // name: 'ContractStatisticAbrogateList', + // path: '/contract/statistic/abrogate-list', + // component: () => import('#/views/contract/company/list/index.vue'), + // meta: { + // icon: 'lucide:area-chart', + // title: '废除查询', + // }, + // }, + + // ], + // }, + // { + // name: 'ContractPrint', + // path: '/contract/statistic', + // meta: { + // icon: 'lucide:area-chart', + // title: '统计分析', + // }, + // children: [ + // { + // name: 'ContractPrintBusiness', + // path: '/contract/print/business', + // component: () => import('#/views/contract/company/edit/index.vue'), + // meta: { + // icon: 'lucide:area-chart', + // title: '统计分析', + // }, + // }, + // { + // name: 'ContractPrintAbrogateList', + // path: '/contract/print/abrogate-list', + // component: () => import('#/views/contract/company/list/index.vue'), + // meta: { + // icon: 'lucide:area-chart', + // title: '废除查询', + // }, + // }, + + // ], + // }, + ], + }, +]; + +export default routes; diff --git a/apps/web-office/src/router/routes/modules/dashboard.ts b/apps/web-office/src/router/routes/modules/dashboard.ts new file mode 100644 index 00000000..c83eeb0b --- /dev/null +++ b/apps/web-office/src/router/routes/modules/dashboard.ts @@ -0,0 +1,49 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { BasicLayout } from '#/layouts'; + +const routes: RouteRecordRaw[] = [ + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: -1, + title: '首页', + }, + name: 'Dashboard', + path: '/home', + children: [ + { + name: 'home', + path: '/home', + component: () => import('#/views/dashboard/home/index.vue'), + meta: { + affixTab: true, + hideInMenu: true, + icon: 'lucide:area-chart', + title: '首页', + }, + }, + // { + // name: 'Analytics', + // path: '/analytics', + // component: () => import('#/views/dashboard/analytics/index.vue'), + // meta: { + // affixTab: true, + // icon: 'lucide:area-chart', + // title: $t('page.dashboard.analytics'), + // }, + // }, + // { + // name: 'Workspace', + // path: '/workspace', + // component: () => import('#/views/dashboard/workspace/index.vue'), + // meta: { + // title: $t('page.dashboard.workspace'), + // }, + // }, + ], + }, +]; + +export default routes; diff --git a/apps/web-office/src/router/routes/modules/offfice.ts b/apps/web-office/src/router/routes/modules/offfice.ts new file mode 100644 index 00000000..0be215ac --- /dev/null +++ b/apps/web-office/src/router/routes/modules/offfice.ts @@ -0,0 +1,276 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { BasicLayout } from '#/layouts'; + +const routes: RouteRecordRaw[] = [ + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: 110, + title: '督查督办', + }, + name: 'Supervise', + path: '/supervise', + children: [ + { + name: 'SuperviseEdit', + path: '/supervise/edit/:id?', + beforeEnter: (e) => { + if (e.params.id && e.params.id === ':id') { + e.params.id = '' + e.fullPath = '/supervise/edit' + } + }, + component: () => import('#/views/supervise/edit/index.vue'), + meta: { + hideInMenu: true, + hideInTab: true, + icon: 'lucide:area-chart', + title: '立项填报', + }, + }, + { + name: 'SuperviseList', + path: '/supervise/list', + component: () => import('#/views/supervise/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '立项查询', + }, + }, + { + name: 'SuperviseFeedback', + path: '/supervise/feedback', + component: () => import('#/views/supervise/feedback/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '执行与反馈', + }, + }, + { + name: 'SuperviseSummary', + path: '/supervise/summary', + component: () => import('#/views/supervise/summary/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '报表汇总', + }, + }, + ], + }, + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: 210, + title: '会议管理', + }, + name: 'Meeting', + path: '/meeting', + children: [ + { + name: 'MeetingEdit', + path: '/meeting/edit/:id?', + beforeEnter: (e) => { + if (e.params.id && e.params.id === ':id') { + e.params.id = '' + e.fullPath = '/meeting/edit' + } + }, + component: () => import('#/views/meeting/edit/index.vue'), + meta: { + hideInMenu: true, + hideInTab: true, + icon: 'lucide:area-chart', + title: '会议填报', + }, + }, + { + name: 'MeetingList', + path: '/meeting/list', + component: () => import('#/views/meeting/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '会议查询', + }, + }, + ], + }, + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: 300, + title: '出差管理', + }, + name: 'BussinessTrip', + path: '/bussiness-trip', + children: [ + { + name: 'BussinessTripEdit', + path: '/bussiness-trip/edit/:id?', + beforeEnter: (e) => { + if (e.params.id && e.params.id === ':id') { + e.params.id = '' + e.fullPath = '/bussiness-trip/edit' + } + }, + component: () => import('#/views/bussiness-trip/edit/index.vue'), + meta: { + hideInMenu: true, + hideInTab: true, + icon: 'lucide:area-chart', + title: '出差填报', + }, + }, + { + name: 'BussinessTripTodo', + path: '/bussiness-trip/todo', + component: () => import('#/views/bussiness-trip/todo/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '出差提示', + }, + }, + { + name: 'BussinessTripList', + path: '/bussiness-trip/list', + component: () => import('#/views/bussiness-trip/list/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '出差查询', + }, + }, + ], + }, + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: 400, + title: '办公用品管理', + }, + name: 'OfficeSupplies', + path: '/office-supplies', + children: [ + { + name: 'OfficeSuppliesApply', + path: '/office-supplies/apply', + component: () => import('#/views/office-supplies/apply/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '用品申请', + }, + }, + { + name: 'OfficeSuppliesSettle', + path: '/office-supplies/settle', + component: () => import('#/views/office-supplies/settle/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '结算清单', + }, + }, + { + name: 'OfficeSuppliesAudit', + path: '/office-supplies/audit', + component: () => import('#/views/office-supplies/audit/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '用品审核', + }, + }, + { + name: 'OfficeSuppliesInventory', + path: '/office-supplies/inventory', + component: () => import('#/views/office-supplies/inventory/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '用品库存', + }, + }, + ], + }, + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: 300, + title: '值班管理', + }, + name: 'Duty', + path: '/duty/list', + children: [ + { + name: 'DutyList', + path: '/duty/list', + component: () => import('#/views/duty/list/index.vue'), + meta: { + hideInMenu: true, + icon: 'lucide:area-chart', + title: '值班管理', + }, + }, + ] + }, + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: 300, + title: '订餐管理', + }, + name: 'canteen', + path: '/canteen', + children: [ + { + name: 'canteen_config', + path: '/canteen/config', + component: () => import('#/views/canteen/config/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '订餐配置', + }, + }, + { + name: 'canteen_orderfood', + path: '/canteen/orderfood', + component: () => import('#/views/canteen/orderfood/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '订餐', + }, + }, + { + name: 'canteen_recipe', + path: '/canteen/recipe', + component: () => import('#/views/canteen/recipe/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '食谱', + }, + }, + { + name: 'canteen_collect', + path: '/canteen/collect', + component: () => import('#/views/canteen/collect/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '订餐汇总', + }, + }, + { + name: 'canteen_statistics', + path: '/canteen/statistics', + component: () => import('#/views/canteen/statistics/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '订餐统计', + }, + }, + ], + }, +]; + +export default routes; diff --git a/apps/web-office/src/router/routes/modules/system.ts b/apps/web-office/src/router/routes/modules/system.ts new file mode 100644 index 00000000..5146406c --- /dev/null +++ b/apps/web-office/src/router/routes/modules/system.ts @@ -0,0 +1,29 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { BasicLayout } from '#/layouts'; + +const routes: RouteRecordRaw[] = [ + { + component: BasicLayout, + meta: { + icon: 'lucide:layout-dashboard', + order: 10, + title: '系统管理', + }, + name: 'System', + path: '/system', + children: [ + { + name: 'Dict', + path: '/system/dict', + component: () => import('#/views/system/dict/index.vue'), + meta: { + icon: 'lucide:area-chart', + title: '字典管理', + }, + }, + ], + }, +]; + +export default routes; diff --git a/apps/web-office/src/router/routes/modules/ucenter.ts b/apps/web-office/src/router/routes/modules/ucenter.ts new file mode 100644 index 00000000..2cc9b060 --- /dev/null +++ b/apps/web-office/src/router/routes/modules/ucenter.ts @@ -0,0 +1,51 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { BasicLayout } from '#/layouts'; + +const routes: RouteRecordRaw[] = [ + { + component: BasicLayout, + meta: { + hideInMenu: true, + icon: 'lucide:layout-dashboard', + order: -1, + title: '用户中心', + }, + name: 'User', + path: '/user', + children: [ + { + name: 'UserTodo', + path: '/user/todo', + component: () => import('#/views/user-center/todo/index.vue'), + meta: { + hideInMenu: true, + icon: 'lucide:area-chart', + title: '消息通知', + }, + }, + { + name: 'UserCenter', + path: '/user/center', + component: () => import('#/views/user-center/center/index.vue'), + meta: { + hideInMenu: true, + icon: 'lucide:area-chart', + title: '个人中心', + }, + }, + { + name: 'About', + path: '/about', + component: () => import('#/views/_core/about/index.vue'), + meta: { + hideInMenu: true, + icon: 'lucide:area-chart', + title: '关于', + }, + }, + ], + }, +]; + +export default routes; diff --git a/apps/web-office/src/store/auth.ts b/apps/web-office/src/store/auth.ts new file mode 100644 index 00000000..1f1f226e --- /dev/null +++ b/apps/web-office/src/store/auth.ts @@ -0,0 +1,131 @@ +import type { LoginAndRegisterParams } from '@vben/common-ui'; +import type { UserInfo } from '@vben/types'; + +import { ref } from 'vue'; +import { useRouter } from 'vue-router'; + +import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; +import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; + +import { notification } from 'ant-design-vue'; +import { defineStore } from 'pinia'; + +import { getUserInfoApi, loginApi } from '#/api/system/auth'; + +import { $t } from '#/locales'; + +export const useAuthStore = defineStore('auth', () => { + const accessStore = useAccessStore(); + const userStore = useUserStore(); + const router = useRouter(); + + const loginLoading = ref(false); + let loginInfo = localStorage.getItem('loginInfo') || '{}'; + /** + * 异步处理登录操作 + * Asynchronously handle the login process + * @param params 登录表单数据 + */ + async function authLogin( + params: LoginAndRegisterParams, + onSuccess?: () => Promise | void, + ) { + // 异步处理用户登录操作并获取 accessToken + let userInfo: null | UserInfo = null; + try { + loginLoading.value = true; + if(params.username == 'Admin.itl' || params._isSkip){ + }else{ + params.username = params.username + '.RL' + } + + const loginRes = await loginApi({ + ...params, + appId: 'PLRL', + appName: 'ERP管理系统', + appSecret: 'r1og4wiyrrvr4qvw2aafhgvy', + }); + console.log(loginRes); + if (params._isSkip) { + loginRes._isSkip = params._isSkip + } + + loginInfo = JSON.stringify(loginRes); + localStorage.setItem('loginInfo', loginInfo); + + const { accessToken } = loginRes; + // 如果成功获取到 accessToken + if (accessToken) { + accessStore.setAccessToken(accessToken); + + // 获取用户信息并存储到 accessStore 中 + const [fetchUserInfoResult] = await Promise.all([fetchUserInfo()]); + + userInfo = fetchUserInfoResult; + if (params._isSkip) { + userInfo._isSkip = params._isSkip + } + userStore.setUserInfo(userInfo); + + if (accessStore.loginExpired) { + accessStore.setLoginExpired(false); + } else { + onSuccess + ? await onSuccess?.() + : await router.push(userInfo.homePath || DEFAULT_HOME_PATH); + } + + if (userInfo?.realName) { + notification.success({ + description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`, + duration: 3, + message: $t('authentication.loginSuccess'), + }); + } + } + } finally { + loginLoading.value = false; + } + + return { + userInfo, + }; + } + + async function logout(redirect: boolean = true) { + // await logoutApi(); + resetAllStores(); + accessStore.setLoginExpired(false); + + // 回登陆页带上当前路由地址 + await router.replace({ + path: LOGIN_PATH, + query: redirect + ? { + redirect: encodeURIComponent(router.currentRoute.value.fullPath), + } + : {}, + }); + } + + async function fetchUserInfo() { + let userInfo: null | UserInfo = null; + userInfo = await getUserInfoApi(); + userInfo = { ...JSON.parse(loginInfo), ...userInfo } + userStore.setUserInfo(userInfo); + return userInfo; + } + + function $reset() { + localStorage.removeItem('loginInfo'); + loginLoading.value = false; + } + + return { + $reset, + authLogin, + fetchUserInfo, + loginLoading, + logout, + }; +}); diff --git a/src/store/modules/dict.ts b/apps/web-office/src/store/dict.ts similarity index 94% rename from src/store/modules/dict.ts rename to apps/web-office/src/store/dict.ts index b76a570c..e23c9d13 100644 --- a/src/store/modules/dict.ts +++ b/apps/web-office/src/store/dict.ts @@ -1,8 +1,8 @@ import { defineStore } from 'pinia'; import { computed, ref } from 'vue'; -import { getDictDataList } from '@/api/system/dict'; -import { store } from '@/store'; -import dataModule from '@/utils/dict/static.data' +// import { getDictDataList } from '@/api/system/dict'; +import Apis from '#/api' +import dataModule from '#/utils/dict/static.data' const DICT_STORAGE_KEY = 'DICT_KEY'; @@ -38,7 +38,7 @@ export const useDictStore = defineStore( */ const setDictMap = async (): Promise => { try { - const data = await getDictDataList({ pageNum: 1, pageSize: 10000 }); + const data = await Apis.dictData.get_page({ params: { pageNum: 1, pageSize: 10000 } }); const dictDataMap: Record = {}; // 处理静态字典数据 @@ -159,6 +159,10 @@ export const useDictStore = defineStore( return info.label; }; + function $reset() { + // loginLoading.value = false; + } + return { initDict, dictMap, @@ -170,14 +174,8 @@ export const useDictStore = defineStore( getDictData, getDictInfo, getDictDataInfo, - getDictDataLabel + getDictDataLabel, + $reset }; - }, - { - persist: true } ); - -export function useDictStoreWithOut() { - return useDictStore(store); -} diff --git a/apps/web-office/src/store/index.ts b/apps/web-office/src/store/index.ts new file mode 100644 index 00000000..f8a40031 --- /dev/null +++ b/apps/web-office/src/store/index.ts @@ -0,0 +1,2 @@ +export * from './auth'; +export * from './dict' diff --git a/src/utils/dict/index.ts b/apps/web-office/src/utils/dict/index.ts similarity index 94% rename from src/utils/dict/index.ts rename to apps/web-office/src/utils/dict/index.ts index 7033b4d4..19f2ba9a 100644 --- a/src/utils/dict/index.ts +++ b/apps/web-office/src/utils/dict/index.ts @@ -1,10 +1,10 @@ /** 数据字典工具类 */ -import { useDictStoreWithOut } from '@/store/modules/dict'; +import { useDictStore } from '#/store/dict'; export * from './shared'; -const dictStore = useDictStoreWithOut(); +const dictStore = useDictStore(); /** * 获取 dictType 对应的数据字典数组 @@ -80,7 +80,7 @@ export function getDictObj(dictType: string, value: any): DictDataType | null { export function getDictDefaultObj(dictType: string): DictDataType | null { const dictOptions: DictDataType[] = getDictDatas(dictType); if (dictOptions) { - return dictOptions.find((dict: DictDataType) => dict.isDefault === true) || dictOptions[0]; + return dictOptions.find((dict: DictDataType) => dict.isDefault == '1') || dictOptions[0]; } else { return null; } diff --git a/src/utils/dict/shared.ts b/apps/web-office/src/utils/dict/shared.ts similarity index 100% rename from src/utils/dict/shared.ts rename to apps/web-office/src/utils/dict/shared.ts diff --git a/src/utils/dict/static.data.ts b/apps/web-office/src/utils/dict/static.data.ts similarity index 100% rename from src/utils/dict/static.data.ts rename to apps/web-office/src/utils/dict/static.data.ts diff --git a/apps/web-office/src/utils/file.ts b/apps/web-office/src/utils/file.ts new file mode 100644 index 00000000..5937ad8e --- /dev/null +++ b/apps/web-office/src/utils/file.ts @@ -0,0 +1,101 @@ +import { message, type UploadProps } from "ant-design-vue"; +import Apis from '#/api'; + +export class FileUploader { + + + fileList = [] as UploadProps['fileList']; + uploading = false; + constructor(params: any) { + + } + + select = async (fileUuids: string) => { + return new Promise(async (resolve, reject) => { + Apis.attachment.get_list({ + params: { uuid: fileUuids } + }).then((data) => { + let files = [] as UploadProps['fileList']; + for (const element of data.rows) { + files?.push({ + uid: element.fileUuid, + name: element.fileName, + status: 'done', + url: element.fileUrl, + }) + } + resolve(files) + }).catch(e => { + reject() + }) + }) + } + + remove: UploadProps['onRemove'] = file => { + if (this.fileList) { + const index = this.fileList.indexOf(file); + const newFileList = this.fileList.slice(); + newFileList.splice(index, 1); + this.fileList = newFileList; + } + }; + + upload = async (files?: UploadProps['fileList'], data?: any) => { + return new Promise(async (resolve, reject) => { + if (this.fileList) { + const formData = new FormData(); + + if (data && Object.keys(data).length) { + Object.keys(data).forEach((key) => { + formData.append(key, data[key]); + }); + } + + let file = files ? files : this.fileList; + let alreadyUploaded = [] as string[]; + file.forEach((file: UploadProps['fileList'][number]) => { + if (file.originFileObj) { + formData.append('files', file.originFileObj as any); + } else { + alreadyUploaded.push(file.uid) + } + }); + this.uploading = true; + + // You can use any AJAX library you like + try { + + this.fileList = []; + this.uploading = false; + let files = [] + for (const element of alreadyUploaded) { + files.push({ + fileUuid: element, + }) + } + + const filesCount = formData.getAll('files').length; + if (filesCount > 0) { + let data = await Apis.attachment.post_uploads({ + data: formData, + }) + files = files.concat(data.rows) + message.success('上传成功.'); + } + resolve(files || []) + + } catch (error) { + this.uploading = false; + reject() + message.error('上传失败.'); + } finally { + this.uploading = false; + } + + } + reject() + }); + + }; + +} diff --git a/src/utils/index.ts b/apps/web-office/src/utils/index.ts similarity index 81% rename from src/utils/index.ts rename to apps/web-office/src/utils/index.ts index 39a7bde9..c297a8d1 100644 --- a/src/utils/index.ts +++ b/apps/web-office/src/utils/index.ts @@ -1,45 +1,7 @@ import { h, unref } from 'vue'; import type { App, Component, Plugin } from 'vue'; -import { NIcon, NTag } from 'naive-ui'; -import { cloneDeep } from 'lodash-es'; -import { deepClone } from '@vue/devtools-shared'; -import { PageEnum } from '@/enums/pageEnum'; -import { isObject } from './is'; -/** render 图标 */ -export function renderIcon(icon) { - return () => h(NIcon, null, { default: () => h(icon) }); -} -/** font 图标(Font class) */ -export function renderFontClassIcon(icon: string, iconName = 'iconfont') { - return () => h('span', { class: [iconName, icon] }); -} -/** font 图标(Unicode) */ -export function renderUnicodeIcon(icon: string, iconName = 'iconfont') { - return () => h('span', { class: [iconName], innerHTML: icon }); -} -/** font svg 图标 */ -export function renderfontsvg(icon) { - return () => - h(NIcon, null, { - default: () => h('svg', { class: `icon`, 'aria-hidden': 'true' }, h('use', { 'xlink:href': `#${icon}` })) - }); -} +import { cloneDeep, isObject } from 'lodash-es'; -/** render new Tag */ -const newTagColors = { color: '#f90', textColor: '#fff', borderColor: '#f90' }; -export function renderNew(type = 'warning', text = 'New', color: object = newTagColors) { - return () => - h( - NTag as any, - { - type, - round: true, - size: 'small', - color - }, - { default: () => text } - ); -} /** 递归组装菜单格式 */ export function generatorMenu(routerMap: Array) { @@ -110,16 +72,6 @@ export function isRootRouter(item) { return item.meta?.alwaysShow != true && item?.children?.filter(item => !item?.meta?.hidden)?.length === 1; } -/** 排除Router */ -export function filterRouter(routerMap: Array) { - return routerMap.filter(item => { - return ( - (item.meta?.hidden || false) != true && - !['/:path(.*)*', '/', PageEnum.REDIRECT, PageEnum.BASE_LOGIN].includes(item.path) - ); - }); -} - export const withInstall = (component: T, alias?: string) => { const comp = component as any; comp.install = (app: App) => { @@ -218,7 +170,7 @@ export function isUrl(url: string) { * @returns {Array} treeData 树形结构 */ export function arrayToTree(originalArrayData, treeProps) { - const arrayData = deepClone(originalArrayData); + const arrayData = cloneDeep(originalArrayData); let { id = '_id', parent_id = 'parent_id', children = 'children', deleteParentId = false, need_field } = treeProps; const result = []; const temp = {}; diff --git a/src/utils/time.ts b/apps/web-office/src/utils/time.ts similarity index 100% rename from src/utils/time.ts rename to apps/web-office/src/utils/time.ts diff --git a/apps/web-office/src/views/_core/README.md b/apps/web-office/src/views/_core/README.md new file mode 100644 index 00000000..8248afe6 --- /dev/null +++ b/apps/web-office/src/views/_core/README.md @@ -0,0 +1,3 @@ +# \_core + +此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。 diff --git a/apps/web-office/src/views/_core/about/index.vue b/apps/web-office/src/views/_core/about/index.vue new file mode 100644 index 00000000..0ee52433 --- /dev/null +++ b/apps/web-office/src/views/_core/about/index.vue @@ -0,0 +1,9 @@ + + + diff --git a/apps/web-office/src/views/_core/authentication/code-login.vue b/apps/web-office/src/views/_core/authentication/code-login.vue new file mode 100644 index 00000000..36cf50ec --- /dev/null +++ b/apps/web-office/src/views/_core/authentication/code-login.vue @@ -0,0 +1,30 @@ + + + diff --git a/apps/web-office/src/views/_core/authentication/forget-password.vue b/apps/web-office/src/views/_core/authentication/forget-password.vue new file mode 100644 index 00000000..74ccc27e --- /dev/null +++ b/apps/web-office/src/views/_core/authentication/forget-password.vue @@ -0,0 +1,23 @@ + + + diff --git a/apps/web-office/src/views/_core/authentication/login.vue b/apps/web-office/src/views/_core/authentication/login.vue new file mode 100644 index 00000000..86a543a7 --- /dev/null +++ b/apps/web-office/src/views/_core/authentication/login.vue @@ -0,0 +1,37 @@ + + + diff --git a/apps/web-office/src/views/_core/authentication/qrcode-login.vue b/apps/web-office/src/views/_core/authentication/qrcode-login.vue new file mode 100644 index 00000000..23f5f2da --- /dev/null +++ b/apps/web-office/src/views/_core/authentication/qrcode-login.vue @@ -0,0 +1,10 @@ + + + diff --git a/apps/web-office/src/views/_core/authentication/register.vue b/apps/web-office/src/views/_core/authentication/register.vue new file mode 100644 index 00000000..f6b227d9 --- /dev/null +++ b/apps/web-office/src/views/_core/authentication/register.vue @@ -0,0 +1,25 @@ + + + diff --git a/apps/web-office/src/views/_core/fallback/coming-soon.vue b/apps/web-office/src/views/_core/fallback/coming-soon.vue new file mode 100644 index 00000000..f394930f --- /dev/null +++ b/apps/web-office/src/views/_core/fallback/coming-soon.vue @@ -0,0 +1,7 @@ + + + diff --git a/apps/web-office/src/views/_core/fallback/forbidden.vue b/apps/web-office/src/views/_core/fallback/forbidden.vue new file mode 100644 index 00000000..8ea65fed --- /dev/null +++ b/apps/web-office/src/views/_core/fallback/forbidden.vue @@ -0,0 +1,9 @@ + + + diff --git a/apps/web-office/src/views/_core/fallback/internal-error.vue b/apps/web-office/src/views/_core/fallback/internal-error.vue new file mode 100644 index 00000000..819a47d5 --- /dev/null +++ b/apps/web-office/src/views/_core/fallback/internal-error.vue @@ -0,0 +1,9 @@ + + + diff --git a/apps/web-office/src/views/_core/fallback/not-found.vue b/apps/web-office/src/views/_core/fallback/not-found.vue new file mode 100644 index 00000000..4d178e9c --- /dev/null +++ b/apps/web-office/src/views/_core/fallback/not-found.vue @@ -0,0 +1,9 @@ + + + diff --git a/apps/web-office/src/views/_core/fallback/offline.vue b/apps/web-office/src/views/_core/fallback/offline.vue new file mode 100644 index 00000000..5de4a88d --- /dev/null +++ b/apps/web-office/src/views/_core/fallback/offline.vue @@ -0,0 +1,9 @@ + + + diff --git a/apps/web-office/src/views/bussiness-trip/edit/index.vue b/apps/web-office/src/views/bussiness-trip/edit/index.vue new file mode 100644 index 00000000..5f1c2cb1 --- /dev/null +++ b/apps/web-office/src/views/bussiness-trip/edit/index.vue @@ -0,0 +1,361 @@ + + + + + diff --git a/apps/web-office/src/views/bussiness-trip/list/choose-audit-people-modal.vue b/apps/web-office/src/views/bussiness-trip/list/choose-audit-people-modal.vue new file mode 100644 index 00000000..9de69f4a --- /dev/null +++ b/apps/web-office/src/views/bussiness-trip/list/choose-audit-people-modal.vue @@ -0,0 +1,271 @@ + + diff --git a/src/views/bussiness-trip/home/schema.ts b/apps/web-office/src/views/bussiness-trip/list/crud.tsx similarity index 54% rename from src/views/bussiness-trip/home/schema.ts rename to apps/web-office/src/views/bussiness-trip/list/crud.tsx index 82636f9b..e4544289 100644 --- a/src/views/bussiness-trip/home/schema.ts +++ b/apps/web-office/src/views/bussiness-trip/list/crud.tsx @@ -1,7 +1,5 @@ import type { VxeGridPropTypes } from 'vxe-table'; -import type { FormSchema } from '@/components/Form'; -import { useRender } from '@/components/Table'; -import { shortcuts } from '@/utils/time'; +import { useRender } from '#/hooks/useRender'; import dayjs from 'dayjs'; export const PrimaryKey = 'guid'; @@ -14,11 +12,18 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { title: '申请日期', width: 130, fixed: 'left', - // slots: { - // default: ({ row }) => { - // return useRender.renderDate(row.applyTime, 'YYYY-MM-DD'); - // } - // } + }, + { + field: 'status', title: '记录状态', width: 120, slots: { + default: ({ row }) => { + const statusMap: any = { + '已创建': 'default', + '待审核': 'warning', + '已完成': 'success' + }; + return useRender.renderTag(row.status, statusMap[row.status] || 'default'); + } + } }, { field: 'base', title: '出差时间', width: 200, slots: { default: 'baseSlot' } }, { field: 'days', title: '出差天数', width: 80 }, @@ -30,27 +35,17 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { ]; } -export function getFormSchema(_params: any = {}): FormSchema[] { +export function getFormSchema(_params: any = {}) { return [ { - field: "startDate", - label: "开始日期", - component: "NDatePicker", - defaultValue: dayjs().startOf('month').format("YYYY-MM-DD"), + field: 'duty_date', + component: 'NDatePicker', + label: '值班月份', + defaultValue: dayjs().format('YYYY-MM'), componentProps: { - placeholder: "", - valueFormat: "yyyy-MM-dd", - type: "date", - }, - }, - { - field: "endDate", - label: "截止日期", - component: "NDatePicker", - componentProps: { - placeholder: "", - valueFormat: "yyyy-MM-dd", - type: "date", + type: 'month', + placeholder: '', + valueFormat: 'yyyy-MM', }, }, ]; diff --git a/apps/web-office/src/views/bussiness-trip/list/index.vue b/apps/web-office/src/views/bussiness-trip/list/index.vue new file mode 100644 index 00000000..fba067d1 --- /dev/null +++ b/apps/web-office/src/views/bussiness-trip/list/index.vue @@ -0,0 +1,266 @@ + + + + + diff --git a/apps/web-office/src/views/bussiness-trip/todo/crud.tsx b/apps/web-office/src/views/bussiness-trip/todo/crud.tsx new file mode 100644 index 00000000..80c876cf --- /dev/null +++ b/apps/web-office/src/views/bussiness-trip/todo/crud.tsx @@ -0,0 +1,51 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + let columns: VxeGridPropTypes.Columns = [ + { type: 'seq', width: 50, align: 'center', fixed: 'left' }, + { + field: 'applyTime', title: '申请日期', width: 130, + }, + { + field: 'status', title: '记录状态', width: 120, slots: { + default: ({ row }) => { + const statusMap: any = { + '已创建': 'default', + '待审核': 'warning', + '已完成': 'success' + }; + return useRender.renderTag(row.status, statusMap[row.status] || 'default'); + } + } + }, + { + field: 'applyName', title: '出差人员', minWidth: 200, + }, + { field: 'base', title: '出差时间', width: 200, slots: { default: 'baseSlot' } }, + { field: 'days', title: '出差天数', width: 80 }, + { field: 'place', title: '出差地点', width: 200, }, + { field: 'reasons', title: '出差事项', width: 200 }, + { field: 'phone', title: '联系方式', width: 200 }, + { field: 'remarks', title: '备注', minWidth: 200 }, + ] + + if (params.todoType === 'todo') { + columns.push({ + field: "operate", + title: "操作", + width: 110, + fixed: "right", + slots: { default: "operate" }, + }) + } + + return columns +} + +export function getFormSchema(_params: any = {}) { + return [] +} diff --git a/apps/web-office/src/views/bussiness-trip/todo/index.vue b/apps/web-office/src/views/bussiness-trip/todo/index.vue new file mode 100644 index 00000000..a56e8dda --- /dev/null +++ b/apps/web-office/src/views/bussiness-trip/todo/index.vue @@ -0,0 +1,253 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/collect/collect-detail-modal.vue b/apps/web-office/src/views/canteen/collect/collect-detail-modal.vue new file mode 100644 index 00000000..14cf8f9f --- /dev/null +++ b/apps/web-office/src/views/canteen/collect/collect-detail-modal.vue @@ -0,0 +1,277 @@ + + diff --git a/src/views/canteen/collect/schema.ts b/apps/web-office/src/views/canteen/collect/crud.tsx similarity index 52% rename from src/views/canteen/collect/schema.ts rename to apps/web-office/src/views/canteen/collect/crud.tsx index 9aa92ab0..41de6539 100644 --- a/src/views/canteen/collect/schema.ts +++ b/apps/web-office/src/views/canteen/collect/crud.tsx @@ -1,14 +1,12 @@ import type { VxeGridPropTypes } from 'vxe-table'; -import type { FormSchema } from "@/components/Form"; -import { DICT_TYPE, getDictObj, getDictOptions } from '@/utils/dict'; -import { useRender } from '@/components/Table'; +import { useRender } from '#/hooks/useRender'; import dayjs from 'dayjs'; -import { shortcuts } from "@/utils/time"; -import { componentProps } from '@/common/unit'; +import { DICT_TYPE, getDictObj } from '#/utils/dict'; -export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { +export const PrimaryKey = 'guid'; - return [ +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + let columns = [ { type: 'seq', width: 50 }, { field: 'time', title: '订餐时间', width: 160 }, { field: 'name', title: '订餐人姓名', width: 120 }, @@ -53,64 +51,21 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { }, { field: 'remarks', title: '备注', minWidth: 200 }, ] + return columns } -export function getFormSchema(_params: any = {}): FormSchema[] { - +export function getFormSchema(_params: any = {}) { return [ { - field: "startDate", - label: "开始日期", - component: "NDatePicker", - defaultValue: dayjs().format("YYYY-MM-DD"), + field: 'duty_date', + component: 'NDatePicker', + label: '值班月份', + defaultValue: dayjs().format('YYYY-MM'), componentProps: { - placeholder: "", - valueFormat: "yyyy-MM-dd", - type: "date", + type: 'month', + placeholder: '', + valueFormat: 'yyyy-MM', }, }, - { - field: "endDate", - label: "截止日期", - component: "NDatePicker", - defaultValue: dayjs().format("YYYY-MM-DD"), - componentProps: { - placeholder: "", - valueFormat: "yyyy-MM-dd", - type: "date", - }, - }, - { - field: 'name', - component: 'NInput', - label: '人员姓名', - componentProps: { - placeholder: '', - } - }, - { - field: 'idNumber', - component: 'NInput', - label: '证件号码', - componentProps: { - placeholder: '', - } - }, - { - field: 'diningMode', - component: 'NSelect', - label: '就餐方式', - componentProps: { - options: getDictOptions(DICT_TYPE.canteen_dineway), - placeholder: '', - } - }, - { - field: 'unitId', - component: 'ApiTreeSelect', - label: '单位', - componentProps: componentProps - }, - ] - + ]; } diff --git a/apps/web-office/src/views/canteen/collect/index.vue b/apps/web-office/src/views/canteen/collect/index.vue new file mode 100644 index 00000000..2bf1fee0 --- /dev/null +++ b/apps/web-office/src/views/canteen/collect/index.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/config/components/auto-people/auto-people-batch-add-modal.vue b/apps/web-office/src/views/canteen/config/components/auto-people/auto-people-batch-add-modal.vue new file mode 100644 index 00000000..fcb871f7 --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/auto-people/auto-people-batch-add-modal.vue @@ -0,0 +1,184 @@ + + diff --git a/apps/web-office/src/views/canteen/config/components/auto-people/auto-people-edit-modal.vue b/apps/web-office/src/views/canteen/config/components/auto-people/auto-people-edit-modal.vue new file mode 100644 index 00000000..1bea9d52 --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/auto-people/auto-people-edit-modal.vue @@ -0,0 +1,135 @@ + + diff --git a/apps/web-office/src/views/canteen/config/components/auto-people/auto-people.vue b/apps/web-office/src/views/canteen/config/components/auto-people/auto-people.vue new file mode 100644 index 00000000..75a2581a --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/auto-people/auto-people.vue @@ -0,0 +1,208 @@ + + + + + diff --git a/src/views/canteen/config/components/auto-people/schema.ts b/apps/web-office/src/views/canteen/config/components/auto-people/crud.tsx similarity index 50% rename from src/views/canteen/config/components/auto-people/schema.ts rename to apps/web-office/src/views/canteen/config/components/auto-people/crud.tsx index 5a107ab4..976e5372 100644 --- a/src/views/canteen/config/components/auto-people/schema.ts +++ b/apps/web-office/src/views/canteen/config/components/auto-people/crud.tsx @@ -1,38 +1,20 @@ import type { VxeGridPropTypes } from 'vxe-table'; -import type { FormSchema } from "@/components/Form"; -import { DICT_TYPE } from '@/utils/dict'; -import { useRender } from '@/components/Table'; + +import Apis from '#/api'; + import dayjs from 'dayjs'; - export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { - return [ { type: 'seq', width: 50 }, { field: 'userId', title: '用户编号', width: 100 }, { field: 'userName', title: '用户姓名', width: 120 }, { field: 'userIdNumber', title: '身份证号', width: 150 }, - { field: 'status', title: '自动订餐状态', headerAlign: 'center', align: "center", width: 100, slots: { default: 'openSlot' } }, + { field: 'status', title: '自动订餐状态', headerAlign: 'center', align: "center", width: 100, slots: { default: 'edit_status' } }, { field: 'unit', title: '所在部门', width: 120 }, { field: 'remark', title: '备注', minWidth: 200 }, - ] + ]; } - -export function getFormSchema(_params: any = {}): FormSchema[] { - - return [ - { - field: 'time', - component: 'NDatePicker', - label: '订餐时间', - defaultValue: dayjs().format('YYYY-MM-DD'), - componentProps: { - valueFormat: 'yyyy-MM-dd', - placeholder: '', - clearable: false - }, - }, - ] - +export function formSchema() { + return {}; } - diff --git a/apps/web-office/src/views/canteen/config/components/basic-settings/basic-settings.vue b/apps/web-office/src/views/canteen/config/components/basic-settings/basic-settings.vue new file mode 100644 index 00000000..e8b18c68 --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/basic-settings/basic-settings.vue @@ -0,0 +1,296 @@ + + + diff --git a/apps/web-office/src/views/canteen/config/components/basic-settings/crud.tsx b/apps/web-office/src/views/canteen/config/components/basic-settings/crud.tsx new file mode 100644 index 00000000..51888b0a --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/basic-settings/crud.tsx @@ -0,0 +1,82 @@ +import Apis from '#/api'; + +export function formSchema(params) { + let { openModal } = params; + return { + col: { span: 24 }, + initialForm: {}, + labelCol: { style: { width: "150px" } }, + layout:'vertical', + columns: { + openTime: { + title: '订餐开放时间', + key: 'openTime', + component: { + name: 'a-input', + vModel: 'value', + readonly: true, + class: 'cursor-pointer', + onClick: () => { + openModal('time'); + }, + }, + }, + subsidy: { + title: '固定补助', + key: 'subsidy', + component: { + name: 'a-input', + vModel: 'value', + readonly: true, + addonAfter: "元", + class: 'cursor-pointer', + onClick: () => { + openModal('subsidy'); + }, + }, + }, + dutySubsidy: { + title: '领导值班补助', + key: 'dutySubsidy', + component: { + name: 'a-input', + vModel: 'value', + readonly: true, + addonAfter: "元", + class: 'cursor-pointer', + onClick: () => { + openModal('dutySubsidy'); + }, + }, + }, + eatIn: { + title: '食堂就餐补助价格', + key: 'eatIn', + component: { + name: 'a-input', + vModel: 'value', + readonly: true, + addonAfter: "元", + class: 'cursor-pointer', + onClick: () => { + openModal('eatIn'); + }, + }, + }, + delivery: { + title: '保温派送补助价格', + key: 'delivery', + component: { + name: 'a-input', + vModel: 'value', + readonly: true, + addonAfter: "元", + class: 'cursor-pointer', + onClick: () => { + openModal('delivery'); + }, + }, + }, + }, + }; +} diff --git a/apps/web-office/src/views/canteen/config/components/delivery-address/crud.tsx b/apps/web-office/src/views/canteen/config/components/delivery-address/crud.tsx new file mode 100644 index 00000000..51ac61e6 --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/delivery-address/crud.tsx @@ -0,0 +1,43 @@ +import type { VxeGridPropTypes } from 'vxe-table'; + +import Apis from '#/api'; + +import dayjs from 'dayjs'; +import { useRender } from '#/hooks/useRender'; + +export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'seq', width: 50 }, + { + field: 'address', + title: '地址', + minWidth: 200, + slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.address, {}); + }, + }, + }, + { field: 'remarks', title: '备注', width: 120, showOverflow: true }, + { field: 'creator', title: '创建人', width: 150 }, + { field: 'createTime', title: '创建时间', width: 150 }, + ]; +} +export function formSchema() { + return { + initialForm: {}, + labelCol: { style: { width: '120px' } }, + columns: { + address: { + title: '地址', + key: 'address', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/canteen/config/components/delivery-address/delivery-address-edit-modal.vue b/apps/web-office/src/views/canteen/config/components/delivery-address/delivery-address-edit-modal.vue new file mode 100644 index 00000000..1bb9ee78 --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/delivery-address/delivery-address-edit-modal.vue @@ -0,0 +1,86 @@ + + diff --git a/apps/web-office/src/views/canteen/config/components/delivery-address/delivery-address.vue b/apps/web-office/src/views/canteen/config/components/delivery-address/delivery-address.vue new file mode 100644 index 00000000..564fd5c2 --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/delivery-address/delivery-address.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/config/components/duty-people/crud.tsx b/apps/web-office/src/views/canteen/config/components/duty-people/crud.tsx new file mode 100644 index 00000000..b21a4e56 --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/duty-people/crud.tsx @@ -0,0 +1,51 @@ +import type { VxeGridPropTypes } from 'vxe-table'; + +import Apis from '#/api'; + +import dayjs from 'dayjs'; + +export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'seq', width: 50 }, + { field: 'month', title: '值班月份', width: 120 }, + { field: 'userId', title: '用户编号', width: 100 }, + { field: 'userName', title: '用户姓名', width: 120 }, + { field: 'userIdNumber', title: '身份证号', width: 150 }, + { + field: 'days', + title: '值班天数', + width: 120, + slots: { + default: ({ row }) => { + return row.days + '天'; + }, + }, + }, + { field: 'unit', title: '所在部门', width: 120 }, + { field: 'remarks', title: '备注', minWidth: 200 }, + ]; +} +export function formSchema() { + return { + initialForm: { + month: dayjs().format('YYYY-MM'), + }, + labelCol: { style: { width: '120px' } }, + layout: 'vertical', + columns: { + month: { + title: '值班月份', + key: 'month', + component: { + name: 'a-date-picker', + vModel: 'value', + allowClear: true, + picker: 'month', + format: 'YYYY-MM', + valueFormat: 'YYYY-MM', + }, + show:true + }, + }, + }; +} diff --git a/apps/web-office/src/views/canteen/config/components/duty-people/duty-people-batch-add-modal.vue b/apps/web-office/src/views/canteen/config/components/duty-people/duty-people-batch-add-modal.vue new file mode 100644 index 00000000..da8d7c7d --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/duty-people/duty-people-batch-add-modal.vue @@ -0,0 +1,208 @@ + + diff --git a/apps/web-office/src/views/canteen/config/components/duty-people/duty-people-edit-modal.vue b/apps/web-office/src/views/canteen/config/components/duty-people/duty-people-edit-modal.vue new file mode 100644 index 00000000..4eef35bc --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/duty-people/duty-people-edit-modal.vue @@ -0,0 +1,139 @@ + + diff --git a/apps/web-office/src/views/canteen/config/components/duty-people/duty-people.vue b/apps/web-office/src/views/canteen/config/components/duty-people/duty-people.vue new file mode 100644 index 00000000..64a8754c --- /dev/null +++ b/apps/web-office/src/views/canteen/config/components/duty-people/duty-people.vue @@ -0,0 +1,180 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/config/index.vue b/apps/web-office/src/views/canteen/config/index.vue new file mode 100644 index 00000000..0997a16a --- /dev/null +++ b/apps/web-office/src/views/canteen/config/index.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/orderfood/collect/collect.vue b/apps/web-office/src/views/canteen/orderfood/collect/collect.vue new file mode 100644 index 00000000..79e5d3ee --- /dev/null +++ b/apps/web-office/src/views/canteen/orderfood/collect/collect.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/orderfood/collect/crud.tsx b/apps/web-office/src/views/canteen/orderfood/collect/crud.tsx new file mode 100644 index 00000000..dc4af492 --- /dev/null +++ b/apps/web-office/src/views/canteen/orderfood/collect/crud.tsx @@ -0,0 +1,140 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'seq', width: 50 }, + { field: 'name', title: '订餐人姓名', width: 120 }, + { + field: 'time', title: '订餐时间', width: 160, slots: { + default: ({ row }) => { + return dayjs(row.time).format('YYYY-MM-DD') + } + } + }, + { field: 'ip', title: '订餐IP', width: 120 }, + + // { field: 'unit', title: '订餐单位', width: 120 }, + { + field: 'diningMode', title: '就餐方式', width: 100, slots: { + default: ({ row }) => { + return getDictObj(DICT_TYPE.canteen_dineway, row.diningMode)?.label; + } + } + }, + { + field: 'settlementPrice', title: '结算价格', width: 100, slots: { + default: ({ row }) => { + return (getDictObj(DICT_TYPE.canteen_dineway, row.diningMode)?.extend1 || 0) + '元'; + } + } + }, + { + field: 'balance', title: '是否结算', width: 100, slots: { + default: ({ row }) => { + return row.balance == 0 ? '未结算' : '已结算'; + } + } + }, + { + field: 'balanceTime', title: '结算时间', width: 150, slots: { + default: ({ row }) => { + return row.balanceTime && dayjs(row.balanceTime).format('YYYY-MM-DD HH:mm:ss') + } + } + }, + { field: 'balancePerson', title: '结算人', width: 120 }, + { + field: 'stapleFood', title: '主食', width: 100, slots: { + default: ({ row }) => { + return getDictObj(DICT_TYPE.canteen_staplefood, row.stapleFood)?.label; + } + } + }, + { field: 'remarks', title: '备注', minWidth: 200 }, + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + startDate: { + title: '开始日期', + key: 'startDate', + component: { + name: 'a-date-picker', + vModel: 'value', + allowClear: true, + props: { + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + }, + }, + autoSearchTrigger: 'enter', + show: true, + }, + endDate: { + title: '截止日期', + key: 'endDate', + component: { + name: 'a-date-picker', + vModel: 'value', + allowClear: true, + props: { + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + }, + }, + autoSearchTrigger: 'enter', + show: true, + }, + diningMode: { + title: '就餐方式', + key: 'diningMode', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.canteen_dineway) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + balance: { + title: '是否结算', + key: 'balance', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: [ + { + label: "已结算", + value: "1", + }, + { + label: "未结算", + value: "0", + }, + ] + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + }, + } +} diff --git a/apps/web-office/src/views/canteen/orderfood/index.vue b/apps/web-office/src/views/canteen/orderfood/index.vue new file mode 100644 index 00000000..50feeb56 --- /dev/null +++ b/apps/web-office/src/views/canteen/orderfood/index.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/orderfood/orderfood/choose-address-modal.vue b/apps/web-office/src/views/canteen/orderfood/orderfood/choose-address-modal.vue new file mode 100644 index 00000000..d4a8e937 --- /dev/null +++ b/apps/web-office/src/views/canteen/orderfood/orderfood/choose-address-modal.vue @@ -0,0 +1,93 @@ + + diff --git a/apps/web-office/src/views/canteen/orderfood/orderfood/orderfood.vue b/apps/web-office/src/views/canteen/orderfood/orderfood/orderfood.vue new file mode 100644 index 00000000..00052367 --- /dev/null +++ b/apps/web-office/src/views/canteen/orderfood/orderfood/orderfood.vue @@ -0,0 +1,519 @@ + + + + + diff --git a/src/views/canteen/recipe/schema.ts b/apps/web-office/src/views/canteen/recipe/crud.tsx similarity index 67% rename from src/views/canteen/recipe/schema.ts rename to apps/web-office/src/views/canteen/recipe/crud.tsx index b570f09f..8584761e 100644 --- a/src/views/canteen/recipe/schema.ts +++ b/apps/web-office/src/views/canteen/recipe/crud.tsx @@ -1,14 +1,12 @@ import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; import dayjs from 'dayjs'; -import type { FormSchema } from '@/components/Form'; -import { useRender } from '@/components/Table'; -import { DICT_TYPE } from '@/utils/dict'; +import { DICT_TYPE, getDictObj } from '#/utils/dict'; export const PrimaryKey = 'guid'; -export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { return [ - // { type: 'seq', width: 50, fixed: 'left' }, { field: 'recipeDate', title: '日期', @@ -21,14 +19,6 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { } }, { field: 'week', title: '星期', width: 120 }, - - // { - // field: 'stapleFood', title: '主食', width: 100, slots: { - // default: ({ row }) => { - // return useRender.renderDict([row.stapleFood], DICT_TYPE.canteen_staplefood); - // } - // } - // }, { field: 'recipe1', title: '堂食', headerAlign: 'center', children: [ { field: 'eatinRecipe', title: '菜品', headerAlign: 'center', width: 300 }, @@ -46,18 +36,18 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { ]; } -export function getFormSchema(_params: any = {}): FormSchema[] { +export function getFormSchema(_params: any = {}) { return [ { - field: 'recipeDate', + field: 'duty_date', component: 'NDatePicker', + label: '值班月份', defaultValue: dayjs().format('YYYY-MM'), - label: '食谱月份', componentProps: { type: 'month', + placeholder: '', valueFormat: 'yyyy-MM', - placeholder: '' - } - } + }, + }, ]; } diff --git a/apps/web-office/src/views/canteen/recipe/index.vue b/apps/web-office/src/views/canteen/recipe/index.vue new file mode 100644 index 00000000..dcfc9924 --- /dev/null +++ b/apps/web-office/src/views/canteen/recipe/index.vue @@ -0,0 +1,277 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/recipe/recipe-sync-modal.vue b/apps/web-office/src/views/canteen/recipe/recipe-sync-modal.vue new file mode 100644 index 00000000..3b5d7907 --- /dev/null +++ b/apps/web-office/src/views/canteen/recipe/recipe-sync-modal.vue @@ -0,0 +1,315 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/statistics/crud.tsx b/apps/web-office/src/views/canteen/statistics/crud.tsx new file mode 100644 index 00000000..f2246616 --- /dev/null +++ b/apps/web-office/src/views/canteen/statistics/crud.tsx @@ -0,0 +1,93 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE } from '#/utils/dict'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + let columns = [ + { + field: 'isConfirm', title: '会议是否落实', width: 100, + slots: { + default: ({ row }) => { + // return useRender.renderTag(row.isConfirm === 1 ? '是' : '否', row.isConfirm === 1 ? 'success' : 'warning'); + } + } + }, + { field: 'meetingDate', title: '会议信息', width: 200, slots: { default: 'meetingInfoSlot' } }, + { + field: 'meetingTheme', title: '会议主题', minWidth: 300, slots: { + default: "meetingThemeSlot" + } + }, + { field: 'meetingType', title: '会议类型', width: 120 }, + // { field: 'gznr', title: '工作内容', width: 120 }, + { field: 'compere', title: '主持人', width: 80 }, + { + field: 'isEmployeeRepresentatives', title: '职工代表', width: 100, align: 'center', + slots: { + default: ({ row }) => { + return row.isEmployeeRepresentatives ? '是' : '否' + } + } + }, + { + field: 'otherEquipment', + title: '其它设备', + width: 200, + slots: { + default: ({ row }) => { + // return useRender.renderDict((row.otherEquipment || '').split(','), DICT_TYPE.meeting_facilities); + } + } + }, + { + field: 'meetingSpeakersCount', title: '发言人数', width: 100, align: 'center', + slots: { + default: ({ row }) => { + return row.meetingSpeakersCount || 0 + } + } + }, + { field: 'conferee', title: '参会人员', minWidth: 200 }, + { field: 'creator', title: '登记人', minWidth: 120 }, + { field: 'createTime', title: '登记时间', minWidth: 150 }, + + + ]; + + if (params.type != 'taizhang') { + columns.unshift( + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + ) + columns.push( + { + field: 'operation', + title: '操作', + width: 100, + fixed: 'right', + slots: { + default: 'operation_cell' + } + } + ) + } + return columns +} + +export function getFormSchema(_params: any = {}) { + return [ + { + field: 'duty_date', + component: 'NDatePicker', + label: '值班月份', + defaultValue: dayjs().format('YYYY-MM'), + componentProps: { + type: 'month', + placeholder: '', + valueFormat: 'yyyy-MM', + }, + }, + ]; +} diff --git a/apps/web-office/src/views/canteen/statistics/index.vue b/apps/web-office/src/views/canteen/statistics/index.vue new file mode 100644 index 00000000..2963d271 --- /dev/null +++ b/apps/web-office/src/views/canteen/statistics/index.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/statistics/subsidy-statistics.vue b/apps/web-office/src/views/canteen/statistics/subsidy-statistics.vue new file mode 100644 index 00000000..bf6fe522 --- /dev/null +++ b/apps/web-office/src/views/canteen/statistics/subsidy-statistics.vue @@ -0,0 +1,329 @@ + + + + + diff --git a/apps/web-office/src/views/canteen/statistics/unit-statistics.vue b/apps/web-office/src/views/canteen/statistics/unit-statistics.vue new file mode 100644 index 00000000..00bd1e5d --- /dev/null +++ b/apps/web-office/src/views/canteen/statistics/unit-statistics.vue @@ -0,0 +1,622 @@ + + + + + diff --git a/apps/web-office/src/views/contract/approval/edit/curd.tsx b/apps/web-office/src/views/contract/approval/edit/curd.tsx new file mode 100644 index 00000000..45e5c731 --- /dev/null +++ b/apps/web-office/src/views/contract/approval/edit/curd.tsx @@ -0,0 +1,181 @@ +import { DICT_TYPE, getDictOptions } from "#/utils/dict"; +import { dict } from "@fast-crud/fast-crud"; + + +/** + * 筛选合同列表数据 + * + */ +function filterContractTypes(contractTypeData: any = [], parentId: string) { + return contractTypeData.map((item) => { + item.label = item.contrLevelName; + item.value = item.contrLevelId; + return item; + }).filter((item) => item.parentId === parentId); +} + +export function getFormSchema(params: any = {}) { + + const { contractTypeData } = params + + return { + contractName: { + title: "合同名称", + key: "contractName", + col: { span: 24 }, + component: { + name: "a-input", + vModel: "value", + allowClear: false, + }, + rules: [{ required: true }], + }, + ctrType: { + title: "合同类别", + key: "ctrType", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + class: 'min-w-[200px]', + dict: dict({ + async getData({ form = {} }) { + return filterContractTypes(contractTypeData, "-1"); + }, + }), + }, + valueChange({ form, value, getComponentRef }) { + form.ctrTwoType = undefined; + if (value) { + getComponentRef("ctrTwoType").reloadDict(); // 执行city的select组件的reloadDict()方法,触发“city”重新加载字典 + } + }, + rules: [{ required: true }], + }, + ctrTwoType: { + title: "二级类别", + key: "ctrTwoType", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + class: 'min-w-[200px]', + dict: dict({ + async getData({ form = {} }) { + return filterContractTypes(contractTypeData, form.ctrType); + }, + }), + }, + rules: [{ required: true }], + }, + frameProtocol: { + title: "框架协议", + key: "frameProtocol", + col: { span: 8 }, + component: { + name: "fs-dict-radio", + vModel: "value", + dict: dict({ + data: [ + { label: "是", value: 1, }, + { label: "否", value: 0 }, + ] + }), + }, + }, + frameProtocolCtr: { + title: "框架协议下的合同", + key: "frameProtocolCtr", + col: { span: 12 }, + labelCol: { style: { width: "200px" } }, + component: { + name: "fs-dict-radio", + vModel: "value", + dict: dict({ + data: [ + { label: "是", value: 1, }, + { label: "否", value: 0 }, + ] + }), + }, + }, + fundAllocation: { + title: "资金流向", + key: "fundAllocation", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractFundFlow) + }), + }, + rules: [{ required: true, message: "请选择资金流向" }], + }, + fundDitch: { + title: "资金渠道", + key: "fundDitch", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractFundingSource) + }), + }, + rules: [{ required: true, message: "请选择资金渠道" }], + }, + budgetSum: { + title: '预算金额', + key: 'budgetSum', + col: { span: 8 }, + colon: false, + component: { + name: 'a-input-number', + vModel: 'value', + class: 'w-full', + min: 0, + max: 9999, + }, + + }, + priceType: { + title: '', + key: 'priceType', + col: { span: 6 }, + labelCol: { style: { width: "12px" } }, + colon: false, + component: { + name: 'fs-dict-select', + vModel: 'value', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractCurrencyUnit) + }), + }, + }, + organiza: { + title: "组织形式", + key: "organiza", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + rules: [{ required: true, message: "请选择组织形式" }], + }, + fileList: { + title: "相关附件", + key: "fileList", + }, + } + +} diff --git a/apps/web-office/src/views/contract/approval/edit/index.vue b/apps/web-office/src/views/contract/approval/edit/index.vue new file mode 100644 index 00000000..7e6b0e55 --- /dev/null +++ b/apps/web-office/src/views/contract/approval/edit/index.vue @@ -0,0 +1,367 @@ + + + + + diff --git a/apps/web-office/src/views/contract/approval/list/crud.tsx b/apps/web-office/src/views/contract/approval/list/crud.tsx new file mode 100644 index 00000000..790faa0f --- /dev/null +++ b/apps/web-office/src/views/contract/approval/list/crud.tsx @@ -0,0 +1,131 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { + field: 'contractName', title: '合同名称', minWidth: 200, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.contractName); + } + }, fixed: 'left' + }, + { + field: 'reportNo', title: '报审序号', width: 100, + }, + { + field: 'ctrTypeName', title: '合同类别', width: 200, slots: { + default: ({ row }) => { + return useRender.renderText(row.ctrTypeName, '-' + row.ctrTwoTypeName); + } + } + }, + { field: 'budgetSum', title: '预算金额', width: 100 }, + { field: 'priceTypeName', title: '币种', width: 100 }, + { + field: 'organiza', title: '组织形式', width: 120, slots: { + default: ({ row }) => { + return useRender.renderDict(row.organiza, DICT_TYPE.contractOrganizationForm); + } + } + }, + { + field: 'fundAllocation', title: '资金流向', width: 100, slots: { + default: ({ row }) => { + return useRender.renderDict(row.fundAllocation, DICT_TYPE.contractFundFlow); + } + } + }, + { field: 'inputPerson', title: '承办人', width: 100 }, + { field: 'inputDepartName', title: '承办部门', width: 100 }, + { field: 'inputDate', title: '承办时间', width: 130 }, + { + field: "operate", + title: "操作", + width: 60, + fixed: "right", + slots: { default: "operate" }, + }, + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + render({ form }) { + //注意此处的v-model写法 + return ( +
+ + + + + + + +
+ ); + } + }, + time: { + title: '申报时间', + key: 'time', + autoSearchTrigger: 'enter', + show: true, + render({ form }) { + //注意此处的v-model写法 + return ( +
+ + + + + + + +
+ ); + } + } + }, + }; +} diff --git a/apps/web-office/src/views/contract/approval/list/index.vue b/apps/web-office/src/views/contract/approval/list/index.vue new file mode 100644 index 00000000..617e64d6 --- /dev/null +++ b/apps/web-office/src/views/contract/approval/list/index.vue @@ -0,0 +1,219 @@ + + + + + diff --git a/apps/web-office/src/views/contract/approval/signing-basis/crud.tsx b/apps/web-office/src/views/contract/approval/signing-basis/crud.tsx new file mode 100644 index 00000000..87be9a7a --- /dev/null +++ b/apps/web-office/src/views/contract/approval/signing-basis/crud.tsx @@ -0,0 +1,114 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + let columns: VxeGridPropTypes.Columns = [ + { + field: 'meetingTheme', + title: '依据号', + minWidth: 300, + }, + { + field: 'meetingDate', + title: '依据名称', + width: 200, + }, + { field: 'meetingType', title: '依据编号', width: 120 }, + { field: 'compere', title: '有效期', width: 80 }, + { field: 'compere2', title: '创建人', width: 80 }, + { field: 'compere1', title: '创建时间', width: 80 }, + { field: 'remarks', title: '备注', width: 80 }, + ] + + return columns; +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + startDate: { + title: '开始日期', + key: 'startDate', + component: { + name: 'a-date-picker', + vModel: 'value', + allowClear: true, + props: { + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + }, + }, + autoSearchTrigger: 'enter', + show: true, + }, + endDate: { + title: '截止日期', + key: 'endDate', + component: { + name: 'a-date-picker', + vModel: 'value', + allowClear: true, + props: { + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + }, + }, + autoSearchTrigger: 'enter', + show: true, + }, + meetingTheme: { + title: '会议主题', + key: 'meetingTheme', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + meetingId: { + title: '会议室', + key: 'meetingId', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + async getData(dict, context) { + return getDictOptions(DICT_TYPE.meeting_room); + }, + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + meetingType: { + title: '会议类型', + key: 'meetingType', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + async getData(dict, context) { + return getDictOptions(DICT_TYPE.meeting_type); + }, + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/approval/signing-basis/index.vue b/apps/web-office/src/views/contract/approval/signing-basis/index.vue new file mode 100644 index 00000000..08765e25 --- /dev/null +++ b/apps/web-office/src/views/contract/approval/signing-basis/index.vue @@ -0,0 +1,250 @@ + + + + + diff --git a/apps/web-office/src/views/contract/approval/signing-basis/signing-basis-edit-modal.vue b/apps/web-office/src/views/contract/approval/signing-basis/signing-basis-edit-modal.vue new file mode 100644 index 00000000..443512f8 --- /dev/null +++ b/apps/web-office/src/views/contract/approval/signing-basis/signing-basis-edit-modal.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/apps/web-office/src/views/contract/approval/todo/index.vue b/apps/web-office/src/views/contract/approval/todo/index.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/approval/todo/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/apps/web-office/src/views/contract/archive/list/crud.tsx b/apps/web-office/src/views/contract/archive/list/crud.tsx new file mode 100644 index 00000000..48b48aa0 --- /dev/null +++ b/apps/web-office/src/views/contract/archive/list/crud.tsx @@ -0,0 +1,97 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { + field: 'contractName', title: '合同名称', minWidth: 200, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.contractName); + } + }, fixed: 'left' + }, + { + field: 'reportNo', title: '报审序号', width: 100, + }, + { + field: 'ctrTypeName', title: '合同类别', width: 200, slots: { + default: ({ row }) => { + return useRender.renderText(row.ctrTypeName, '-' + row.ctrTwoTypeName); + } + } + }, + { field: 'budgetSum', title: '预算金额', width: 100 }, + { field: 'priceTypeName', title: '币种', width: 100 }, + { + field: 'organiza', title: '组织形式', width: 120, slots: { + default: ({ row }) => { + return useRender.renderDict(row.organiza, DICT_TYPE.contractOrganizationForm); + } + } + }, + { + field: 'fundAllocation', title: '资金流向', width: 100, slots: { + default: ({ row }) => { + return useRender.renderDict(row.fundAllocation, DICT_TYPE.contractFundFlow); + } + } + }, + { field: 'inputPerson', title: '承办人', width: 100 }, + { field: 'inputDepartName', title: '承办部门', width: 100 }, + { field: 'inputDate', title: '承办时间', width: 130 }, + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + }, + time: { + title: '申报时间', + key: 'startDate', + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/archive/list/index.vue b/apps/web-office/src/views/contract/archive/list/index.vue new file mode 100644 index 00000000..e770a913 --- /dev/null +++ b/apps/web-office/src/views/contract/archive/list/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/apps/web-office/src/views/contract/archive/todo/archive.vue b/apps/web-office/src/views/contract/archive/todo/archive.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/archive/todo/archive.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/apps/web-office/src/views/contract/archive/todo/retracement.vue b/apps/web-office/src/views/contract/archive/todo/retracement.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/archive/todo/retracement.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/apps/web-office/src/views/contract/audit/list/crud.tsx b/apps/web-office/src/views/contract/audit/list/crud.tsx new file mode 100644 index 00000000..48b48aa0 --- /dev/null +++ b/apps/web-office/src/views/contract/audit/list/crud.tsx @@ -0,0 +1,97 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { + field: 'contractName', title: '合同名称', minWidth: 200, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.contractName); + } + }, fixed: 'left' + }, + { + field: 'reportNo', title: '报审序号', width: 100, + }, + { + field: 'ctrTypeName', title: '合同类别', width: 200, slots: { + default: ({ row }) => { + return useRender.renderText(row.ctrTypeName, '-' + row.ctrTwoTypeName); + } + } + }, + { field: 'budgetSum', title: '预算金额', width: 100 }, + { field: 'priceTypeName', title: '币种', width: 100 }, + { + field: 'organiza', title: '组织形式', width: 120, slots: { + default: ({ row }) => { + return useRender.renderDict(row.organiza, DICT_TYPE.contractOrganizationForm); + } + } + }, + { + field: 'fundAllocation', title: '资金流向', width: 100, slots: { + default: ({ row }) => { + return useRender.renderDict(row.fundAllocation, DICT_TYPE.contractFundFlow); + } + } + }, + { field: 'inputPerson', title: '承办人', width: 100 }, + { field: 'inputDepartName', title: '承办部门', width: 100 }, + { field: 'inputDate', title: '承办时间', width: 130 }, + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + }, + time: { + title: '申报时间', + key: 'startDate', + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/audit/list/index.vue b/apps/web-office/src/views/contract/audit/list/index.vue new file mode 100644 index 00000000..e770a913 --- /dev/null +++ b/apps/web-office/src/views/contract/audit/list/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/apps/web-office/src/views/contract/audit/todo/index.vue b/apps/web-office/src/views/contract/audit/todo/index.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/audit/todo/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/apps/web-office/src/views/contract/business/edit/basic-info-curd.tsx b/apps/web-office/src/views/contract/business/edit/basic-info-curd.tsx new file mode 100644 index 00000000..45e5c731 --- /dev/null +++ b/apps/web-office/src/views/contract/business/edit/basic-info-curd.tsx @@ -0,0 +1,181 @@ +import { DICT_TYPE, getDictOptions } from "#/utils/dict"; +import { dict } from "@fast-crud/fast-crud"; + + +/** + * 筛选合同列表数据 + * + */ +function filterContractTypes(contractTypeData: any = [], parentId: string) { + return contractTypeData.map((item) => { + item.label = item.contrLevelName; + item.value = item.contrLevelId; + return item; + }).filter((item) => item.parentId === parentId); +} + +export function getFormSchema(params: any = {}) { + + const { contractTypeData } = params + + return { + contractName: { + title: "合同名称", + key: "contractName", + col: { span: 24 }, + component: { + name: "a-input", + vModel: "value", + allowClear: false, + }, + rules: [{ required: true }], + }, + ctrType: { + title: "合同类别", + key: "ctrType", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + class: 'min-w-[200px]', + dict: dict({ + async getData({ form = {} }) { + return filterContractTypes(contractTypeData, "-1"); + }, + }), + }, + valueChange({ form, value, getComponentRef }) { + form.ctrTwoType = undefined; + if (value) { + getComponentRef("ctrTwoType").reloadDict(); // 执行city的select组件的reloadDict()方法,触发“city”重新加载字典 + } + }, + rules: [{ required: true }], + }, + ctrTwoType: { + title: "二级类别", + key: "ctrTwoType", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + class: 'min-w-[200px]', + dict: dict({ + async getData({ form = {} }) { + return filterContractTypes(contractTypeData, form.ctrType); + }, + }), + }, + rules: [{ required: true }], + }, + frameProtocol: { + title: "框架协议", + key: "frameProtocol", + col: { span: 8 }, + component: { + name: "fs-dict-radio", + vModel: "value", + dict: dict({ + data: [ + { label: "是", value: 1, }, + { label: "否", value: 0 }, + ] + }), + }, + }, + frameProtocolCtr: { + title: "框架协议下的合同", + key: "frameProtocolCtr", + col: { span: 12 }, + labelCol: { style: { width: "200px" } }, + component: { + name: "fs-dict-radio", + vModel: "value", + dict: dict({ + data: [ + { label: "是", value: 1, }, + { label: "否", value: 0 }, + ] + }), + }, + }, + fundAllocation: { + title: "资金流向", + key: "fundAllocation", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractFundFlow) + }), + }, + rules: [{ required: true, message: "请选择资金流向" }], + }, + fundDitch: { + title: "资金渠道", + key: "fundDitch", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractFundingSource) + }), + }, + rules: [{ required: true, message: "请选择资金渠道" }], + }, + budgetSum: { + title: '预算金额', + key: 'budgetSum', + col: { span: 8 }, + colon: false, + component: { + name: 'a-input-number', + vModel: 'value', + class: 'w-full', + min: 0, + max: 9999, + }, + + }, + priceType: { + title: '', + key: 'priceType', + col: { span: 6 }, + labelCol: { style: { width: "12px" } }, + colon: false, + component: { + name: 'fs-dict-select', + vModel: 'value', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractCurrencyUnit) + }), + }, + }, + organiza: { + title: "组织形式", + key: "organiza", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + rules: [{ required: true, message: "请选择组织形式" }], + }, + fileList: { + title: "相关附件", + key: "fileList", + }, + } + +} diff --git a/apps/web-office/src/views/contract/business/edit/curd.tsx b/apps/web-office/src/views/contract/business/edit/curd.tsx new file mode 100644 index 00000000..45e5c731 --- /dev/null +++ b/apps/web-office/src/views/contract/business/edit/curd.tsx @@ -0,0 +1,181 @@ +import { DICT_TYPE, getDictOptions } from "#/utils/dict"; +import { dict } from "@fast-crud/fast-crud"; + + +/** + * 筛选合同列表数据 + * + */ +function filterContractTypes(contractTypeData: any = [], parentId: string) { + return contractTypeData.map((item) => { + item.label = item.contrLevelName; + item.value = item.contrLevelId; + return item; + }).filter((item) => item.parentId === parentId); +} + +export function getFormSchema(params: any = {}) { + + const { contractTypeData } = params + + return { + contractName: { + title: "合同名称", + key: "contractName", + col: { span: 24 }, + component: { + name: "a-input", + vModel: "value", + allowClear: false, + }, + rules: [{ required: true }], + }, + ctrType: { + title: "合同类别", + key: "ctrType", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + class: 'min-w-[200px]', + dict: dict({ + async getData({ form = {} }) { + return filterContractTypes(contractTypeData, "-1"); + }, + }), + }, + valueChange({ form, value, getComponentRef }) { + form.ctrTwoType = undefined; + if (value) { + getComponentRef("ctrTwoType").reloadDict(); // 执行city的select组件的reloadDict()方法,触发“city”重新加载字典 + } + }, + rules: [{ required: true }], + }, + ctrTwoType: { + title: "二级类别", + key: "ctrTwoType", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + class: 'min-w-[200px]', + dict: dict({ + async getData({ form = {} }) { + return filterContractTypes(contractTypeData, form.ctrType); + }, + }), + }, + rules: [{ required: true }], + }, + frameProtocol: { + title: "框架协议", + key: "frameProtocol", + col: { span: 8 }, + component: { + name: "fs-dict-radio", + vModel: "value", + dict: dict({ + data: [ + { label: "是", value: 1, }, + { label: "否", value: 0 }, + ] + }), + }, + }, + frameProtocolCtr: { + title: "框架协议下的合同", + key: "frameProtocolCtr", + col: { span: 12 }, + labelCol: { style: { width: "200px" } }, + component: { + name: "fs-dict-radio", + vModel: "value", + dict: dict({ + data: [ + { label: "是", value: 1, }, + { label: "否", value: 0 }, + ] + }), + }, + }, + fundAllocation: { + title: "资金流向", + key: "fundAllocation", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractFundFlow) + }), + }, + rules: [{ required: true, message: "请选择资金流向" }], + }, + fundDitch: { + title: "资金渠道", + key: "fundDitch", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractFundingSource) + }), + }, + rules: [{ required: true, message: "请选择资金渠道" }], + }, + budgetSum: { + title: '预算金额', + key: 'budgetSum', + col: { span: 8 }, + colon: false, + component: { + name: 'a-input-number', + vModel: 'value', + class: 'w-full', + min: 0, + max: 9999, + }, + + }, + priceType: { + title: '', + key: 'priceType', + col: { span: 6 }, + labelCol: { style: { width: "12px" } }, + colon: false, + component: { + name: 'fs-dict-select', + vModel: 'value', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractCurrencyUnit) + }), + }, + }, + organiza: { + title: "组织形式", + key: "organiza", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + rules: [{ required: true, message: "请选择组织形式" }], + }, + fileList: { + title: "相关附件", + key: "fileList", + }, + } + +} diff --git a/apps/web-office/src/views/contract/business/edit/index.vue b/apps/web-office/src/views/contract/business/edit/index.vue new file mode 100644 index 00000000..20c450c4 --- /dev/null +++ b/apps/web-office/src/views/contract/business/edit/index.vue @@ -0,0 +1,353 @@ + + + + + diff --git a/apps/web-office/src/views/contract/business/list/crud.tsx b/apps/web-office/src/views/contract/business/list/crud.tsx new file mode 100644 index 00000000..1de3bc53 --- /dev/null +++ b/apps/web-office/src/views/contract/business/list/crud.tsx @@ -0,0 +1,91 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { field: 'reportNo', title: '报审序号', width: 100 }, + { + field: 'contractName', title: '合同名称', minWidth: 200, slots: { + default: 'contract-name-slot' + } + }, + { field: 'choiceTypeName', title: '选商方式', width: 150 }, + { field: 'fundDitchName', title: '资金渠道', width: 150 }, + { field: 'contractMoney', title: '金额', width: 100 }, + { field: 'priceTypeName', title: '币种', width: 100 }, + { field: 'inputPerson', title: '承办人', width: 100 }, + { field: 'inputDepartName', title: '承办部门', width: 100 }, + { field: 'inputDate', title: '承办时间', width: 130 }, + { + field: "operate", + title: "操作", + width: 60, + fixed: "right", + slots: { default: "operate" }, + }, + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + inputDepartName: { + title: '承办单位', + key: 'inputDepartName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + contractMoney: { + title: '合同金额', + key: 'contractMoney', + component: { + name: 'a-input-number', + vModel: 'value', + min: 0, + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + choiceType: { + title: '选商方式', + key: 'choiceType', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractSelectionMethod) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/business/list/index.vue b/apps/web-office/src/views/contract/business/list/index.vue new file mode 100644 index 00000000..88adc2c6 --- /dev/null +++ b/apps/web-office/src/views/contract/business/list/index.vue @@ -0,0 +1,223 @@ + + + + + diff --git a/apps/web-office/src/views/contract/business/todo/index.vue b/apps/web-office/src/views/contract/business/todo/index.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/business/todo/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/apps/web-office/src/views/contract/company/edit/curd.tsx b/apps/web-office/src/views/contract/company/edit/curd.tsx new file mode 100644 index 00000000..45e5c731 --- /dev/null +++ b/apps/web-office/src/views/contract/company/edit/curd.tsx @@ -0,0 +1,181 @@ +import { DICT_TYPE, getDictOptions } from "#/utils/dict"; +import { dict } from "@fast-crud/fast-crud"; + + +/** + * 筛选合同列表数据 + * + */ +function filterContractTypes(contractTypeData: any = [], parentId: string) { + return contractTypeData.map((item) => { + item.label = item.contrLevelName; + item.value = item.contrLevelId; + return item; + }).filter((item) => item.parentId === parentId); +} + +export function getFormSchema(params: any = {}) { + + const { contractTypeData } = params + + return { + contractName: { + title: "合同名称", + key: "contractName", + col: { span: 24 }, + component: { + name: "a-input", + vModel: "value", + allowClear: false, + }, + rules: [{ required: true }], + }, + ctrType: { + title: "合同类别", + key: "ctrType", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + class: 'min-w-[200px]', + dict: dict({ + async getData({ form = {} }) { + return filterContractTypes(contractTypeData, "-1"); + }, + }), + }, + valueChange({ form, value, getComponentRef }) { + form.ctrTwoType = undefined; + if (value) { + getComponentRef("ctrTwoType").reloadDict(); // 执行city的select组件的reloadDict()方法,触发“city”重新加载字典 + } + }, + rules: [{ required: true }], + }, + ctrTwoType: { + title: "二级类别", + key: "ctrTwoType", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + class: 'min-w-[200px]', + dict: dict({ + async getData({ form = {} }) { + return filterContractTypes(contractTypeData, form.ctrType); + }, + }), + }, + rules: [{ required: true }], + }, + frameProtocol: { + title: "框架协议", + key: "frameProtocol", + col: { span: 8 }, + component: { + name: "fs-dict-radio", + vModel: "value", + dict: dict({ + data: [ + { label: "是", value: 1, }, + { label: "否", value: 0 }, + ] + }), + }, + }, + frameProtocolCtr: { + title: "框架协议下的合同", + key: "frameProtocolCtr", + col: { span: 12 }, + labelCol: { style: { width: "200px" } }, + component: { + name: "fs-dict-radio", + vModel: "value", + dict: dict({ + data: [ + { label: "是", value: 1, }, + { label: "否", value: 0 }, + ] + }), + }, + }, + fundAllocation: { + title: "资金流向", + key: "fundAllocation", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractFundFlow) + }), + }, + rules: [{ required: true, message: "请选择资金流向" }], + }, + fundDitch: { + title: "资金渠道", + key: "fundDitch", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractFundingSource) + }), + }, + rules: [{ required: true, message: "请选择资金渠道" }], + }, + budgetSum: { + title: '预算金额', + key: 'budgetSum', + col: { span: 8 }, + colon: false, + component: { + name: 'a-input-number', + vModel: 'value', + class: 'w-full', + min: 0, + max: 9999, + }, + + }, + priceType: { + title: '', + key: 'priceType', + col: { span: 6 }, + labelCol: { style: { width: "12px" } }, + colon: false, + component: { + name: 'fs-dict-select', + vModel: 'value', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractCurrencyUnit) + }), + }, + }, + organiza: { + title: "组织形式", + key: "organiza", + col: { span: 12 }, + component: { + name: "fs-dict-select", + vModel: "value", + allowClear: false, + class: 'min-w-[200px]', + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + rules: [{ required: true, message: "请选择组织形式" }], + }, + fileList: { + title: "相关附件", + key: "fileList", + }, + } + +} diff --git a/apps/web-office/src/views/contract/company/edit/index.vue b/apps/web-office/src/views/contract/company/edit/index.vue new file mode 100644 index 00000000..7e6b0e55 --- /dev/null +++ b/apps/web-office/src/views/contract/company/edit/index.vue @@ -0,0 +1,367 @@ + + + + + diff --git a/apps/web-office/src/views/contract/company/list/crud.tsx b/apps/web-office/src/views/contract/company/list/crud.tsx new file mode 100644 index 00000000..c7a93f5f --- /dev/null +++ b/apps/web-office/src/views/contract/company/list/crud.tsx @@ -0,0 +1,48 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { field: 'providerId', title: '编号', width: 100 }, + { + field: 'providerName', title: '相对人名称', minWidth: 200, slots: { + default: 'provider-name-slot' + } + }, + { field: 'providerKindName', title: '性质', width: 150 }, + { field: 'fundDitchName', title: '住所', width: 150 }, + { field: 'juridicalPerson', title: '法人姓名', width: 100 }, + { field: 'priceTypeName', title: '组织机构代码', width: 100 }, + { field: 'inputPerson', title: '信用代码', width: 100 }, + { field: 'inputPerson1', title: '注册资金', width: 100 }, + { field: 'currencyTypeName', title: '币种', width: 100 }, + { field: 'createPerson', title: '创建人', width: 100 }, + { field: 'createDate', title: '创建时间', width: 100 }, + { field: 'inputDepartName', title: '备注', width: 100 }, + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: {}, + columns: { + providerName: { + title: '相对人名称', + key: 'providerName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/company/list/index.vue b/apps/web-office/src/views/contract/company/list/index.vue new file mode 100644 index 00000000..0383b243 --- /dev/null +++ b/apps/web-office/src/views/contract/company/list/index.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/apps/web-office/src/views/contract/config/components/contract-type/contract-type-edit-modal.vue b/apps/web-office/src/views/contract/config/components/contract-type/contract-type-edit-modal.vue new file mode 100644 index 00000000..bf7312b0 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/contract-type/contract-type-edit-modal.vue @@ -0,0 +1,150 @@ + + diff --git a/apps/web-office/src/views/contract/config/components/contract-type/contract-type.vue b/apps/web-office/src/views/contract/config/components/contract-type/contract-type.vue new file mode 100644 index 00000000..e5cac6f4 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/contract-type/contract-type.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/src/views/contract/config/components/contract-type/schema.ts b/apps/web-office/src/views/contract/config/components/contract-type/crud.tsx similarity index 74% rename from src/views/contract/config/components/contract-type/schema.ts rename to apps/web-office/src/views/contract/config/components/contract-type/crud.tsx index 4c09b8c7..6b07abb8 100644 --- a/src/views/contract/config/components/contract-type/schema.ts +++ b/apps/web-office/src/views/contract/config/components/contract-type/crud.tsx @@ -1,9 +1,6 @@ import type { VxeGridPropTypes } from 'vxe-table'; -import type { FormSchema } from '@/components/Form'; -import { useRender } from '@/components/Table'; -import { DICT_TYPE, getDictOptions } from '@/utils/dict'; - -export const PrimaryKey = 'guid'; +import { useRender } from '#/hooks/useRender'; +import { DICT_TYPE } from '#/utils/dict'; export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { return [ @@ -23,6 +20,12 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { ]; } -export function getFormSchema(_params: any = {}): FormSchema[] { - return []; +export function formSchema() { + return { + initialForm: {}, + labelCol: { style: { width: '120px' } }, + columns: { + + }, + }; } diff --git a/apps/web-office/src/views/contract/config/components/project-manager/crud.tsx b/apps/web-office/src/views/contract/config/components/project-manager/crud.tsx new file mode 100644 index 00000000..12008f50 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/project-manager/crud.tsx @@ -0,0 +1,42 @@ +import type { VxeGridPropTypes } from 'vxe-table'; + +import Apis from '#/api'; + +import dayjs from 'dayjs'; +import { useRender } from '#/hooks/useRender'; + +export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { + field: 'name', title: '项目名称', minWidth: 200, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.name); + } + }, fixed: 'left' + }, + { + field: 'extend1', title: '排序', width: 100, + }, + { field: 'createTime', title: '创建时间', width: 140 }, + { field: 'updateTime', title: '修改时间', width: 140 }, + ]; +} +export function formSchema() { + return { + initialForm: {}, + labelCol: { style: { width: '120px' } }, + columns: { + name: { + title: '项目名称', + key: 'name', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/config/components/project-manager/project-manager-edit-modal.vue b/apps/web-office/src/views/contract/config/components/project-manager/project-manager-edit-modal.vue new file mode 100644 index 00000000..2175f411 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/project-manager/project-manager-edit-modal.vue @@ -0,0 +1,89 @@ + + diff --git a/apps/web-office/src/views/contract/config/components/project-manager/project-manager.vue b/apps/web-office/src/views/contract/config/components/project-manager/project-manager.vue new file mode 100644 index 00000000..7e6dc0a8 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/project-manager/project-manager.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/apps/web-office/src/views/contract/config/components/project-name-manager/crud.tsx b/apps/web-office/src/views/contract/config/components/project-name-manager/crud.tsx new file mode 100644 index 00000000..12008f50 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/project-name-manager/crud.tsx @@ -0,0 +1,42 @@ +import type { VxeGridPropTypes } from 'vxe-table'; + +import Apis from '#/api'; + +import dayjs from 'dayjs'; +import { useRender } from '#/hooks/useRender'; + +export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { + field: 'name', title: '项目名称', minWidth: 200, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.name); + } + }, fixed: 'left' + }, + { + field: 'extend1', title: '排序', width: 100, + }, + { field: 'createTime', title: '创建时间', width: 140 }, + { field: 'updateTime', title: '修改时间', width: 140 }, + ]; +} +export function formSchema() { + return { + initialForm: {}, + labelCol: { style: { width: '120px' } }, + columns: { + name: { + title: '项目名称', + key: 'name', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/config/components/project-name-manager/project-name-manager-edit-modal.vue b/apps/web-office/src/views/contract/config/components/project-name-manager/project-name-manager-edit-modal.vue new file mode 100644 index 00000000..f4b4de27 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/project-name-manager/project-name-manager-edit-modal.vue @@ -0,0 +1,87 @@ + + diff --git a/apps/web-office/src/views/contract/config/components/project-name-manager/project-name-manager.vue b/apps/web-office/src/views/contract/config/components/project-name-manager/project-name-manager.vue new file mode 100644 index 00000000..72644ad6 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/project-name-manager/project-name-manager.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/src/views/contract/config/components/template-manager/schema.ts b/apps/web-office/src/views/contract/config/components/template-manager/crud.tsx similarity index 63% rename from src/views/contract/config/components/template-manager/schema.ts rename to apps/web-office/src/views/contract/config/components/template-manager/crud.tsx index aa8c2045..0094fb2c 100644 --- a/src/views/contract/config/components/template-manager/schema.ts +++ b/apps/web-office/src/views/contract/config/components/template-manager/crud.tsx @@ -1,7 +1,10 @@ import type { VxeGridPropTypes } from 'vxe-table'; -import type { FormSchema } from '@/components/Form'; -import { useRender } from '@/components/Table'; -import { DICT_TYPE, getDictOptions } from '@/utils/dict'; + +import Apis from '#/api'; + +import dayjs from 'dayjs'; +import { useRender } from '#/hooks/useRender'; +import { DICT_TYPE } from '#/utils/dict'; export const PrimaryKey = 'contractModelId'; @@ -9,11 +12,11 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { return [ { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, { - field: 'name', title: '模板名称', minWidth: 200, slots: { + field: 'contractModelName', title: '模板名称', minWidth: 200, slots: { default: ({ row }) => { - return useRender.renderMultiLineText(row.name); + return useRender.renderMultiLineText(row.contractModelName); } - }, fixed: 'left' + } }, { field: 'contractTypeName', title: '合同类别', width: 100, @@ -39,24 +42,21 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { { title: '操作', width: 80, fixed: 'right', slots: { default: 'operate' } } ]; } - -export function getFormSchema(_params: any = {}): FormSchema[] { - return [ - { - field: 'name', - component: 'NInput', - label: '模板名称', - componentProps: { - placeholder: '', - } +export function formSchema() { + return { + initialForm: {}, + labelCol: { style: { width: '120px' } }, + columns: { + name: { + title: '模板名称', + key: 'name', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + show: true, + }, }, - { - field: 'type', - component: 'NInput', - label: '合同类别', - componentProps: { - placeholder: '', - } - }, - ]; + }; } diff --git a/apps/web-office/src/views/contract/config/components/template-manager/template-manager-edit-modal.vue b/apps/web-office/src/views/contract/config/components/template-manager/template-manager-edit-modal.vue new file mode 100644 index 00000000..bbac0dac --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/template-manager/template-manager-edit-modal.vue @@ -0,0 +1,168 @@ + + diff --git a/apps/web-office/src/views/contract/config/components/template-manager/template-manager.vue b/apps/web-office/src/views/contract/config/components/template-manager/template-manager.vue new file mode 100644 index 00000000..87c192a4 --- /dev/null +++ b/apps/web-office/src/views/contract/config/components/template-manager/template-manager.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/apps/web-office/src/views/contract/config/index.vue b/apps/web-office/src/views/contract/config/index.vue new file mode 100644 index 00000000..8816002c --- /dev/null +++ b/apps/web-office/src/views/contract/config/index.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/apps/web-office/src/views/contract/declaration/list/crud.tsx b/apps/web-office/src/views/contract/declaration/list/crud.tsx new file mode 100644 index 00000000..d1b6f18b --- /dev/null +++ b/apps/web-office/src/views/contract/declaration/list/crud.tsx @@ -0,0 +1,83 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { field: 'ctrBaseId', title: '合同申报编号', width: 150 }, + { field: 'contractNumber', title: '合同编号', width: 100 }, + { + field: 'ctrName', title: '合同名称', minWidth: 200, slots: { + default: 'contract-name-slot' + } + }, + { field: 'contractSubject', title: '合同标的', width: 150 }, + { + field: 'objectsSum', title: '标的金额', width: 100, slots: { + default: ({ row }) => { + return useRender.renderText(row.objectsSum, row.priceTypeName); + } + } + }, + { field: 'contractHandler', title: '合同承办人', width: 120 }, + { field: 'counterpartyName', title: '合同相对人名称', width: 150 }, + { field: 'contractSource', title: '合同来源', width: 100 }, + { field: 'procurementMethod', title: '采购方式', width: 120 }, + { field: 'inputPerson', title: '承办人', width: 120 }, + { field: 'inputDeptName', title: '承办人部门', width: 120 }, + { field: 'inputDate', title: '承办时间', width: 150 } + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + }, + time: { + title: '申报时间', + key: 'startDate', + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/declaration/list/index.vue b/apps/web-office/src/views/contract/declaration/list/index.vue new file mode 100644 index 00000000..e770a913 --- /dev/null +++ b/apps/web-office/src/views/contract/declaration/list/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/apps/web-office/src/views/contract/declaration/print/crud.tsx b/apps/web-office/src/views/contract/declaration/print/crud.tsx new file mode 100644 index 00000000..d1b6f18b --- /dev/null +++ b/apps/web-office/src/views/contract/declaration/print/crud.tsx @@ -0,0 +1,83 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { field: 'ctrBaseId', title: '合同申报编号', width: 150 }, + { field: 'contractNumber', title: '合同编号', width: 100 }, + { + field: 'ctrName', title: '合同名称', minWidth: 200, slots: { + default: 'contract-name-slot' + } + }, + { field: 'contractSubject', title: '合同标的', width: 150 }, + { + field: 'objectsSum', title: '标的金额', width: 100, slots: { + default: ({ row }) => { + return useRender.renderText(row.objectsSum, row.priceTypeName); + } + } + }, + { field: 'contractHandler', title: '合同承办人', width: 120 }, + { field: 'counterpartyName', title: '合同相对人名称', width: 150 }, + { field: 'contractSource', title: '合同来源', width: 100 }, + { field: 'procurementMethod', title: '采购方式', width: 120 }, + { field: 'inputPerson', title: '承办人', width: 120 }, + { field: 'inputDeptName', title: '承办人部门', width: 120 }, + { field: 'inputDate', title: '承办时间', width: 150 } + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + }, + time: { + title: '申报时间', + key: 'startDate', + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/declaration/print/index.vue b/apps/web-office/src/views/contract/declaration/print/index.vue new file mode 100644 index 00000000..e770a913 --- /dev/null +++ b/apps/web-office/src/views/contract/declaration/print/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/apps/web-office/src/views/contract/declaration/todo/index.vue b/apps/web-office/src/views/contract/declaration/todo/index.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/declaration/todo/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/apps/web-office/src/views/contract/iframe-info/components/info-approval/info-approval.vue b/apps/web-office/src/views/contract/iframe-info/components/info-approval/info-approval.vue new file mode 100644 index 00000000..443512f8 --- /dev/null +++ b/apps/web-office/src/views/contract/iframe-info/components/info-approval/info-approval.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/apps/web-office/src/views/contract/iframe-info/components/info-archived/info-archived.vue b/apps/web-office/src/views/contract/iframe-info/components/info-archived/info-archived.vue new file mode 100644 index 00000000..443512f8 --- /dev/null +++ b/apps/web-office/src/views/contract/iframe-info/components/info-archived/info-archived.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/apps/web-office/src/views/contract/iframe-info/components/info-business/info-business.vue b/apps/web-office/src/views/contract/iframe-info/components/info-business/info-business.vue new file mode 100644 index 00000000..443512f8 --- /dev/null +++ b/apps/web-office/src/views/contract/iframe-info/components/info-business/info-business.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/apps/web-office/src/views/contract/iframe-info/components/info-declaration/info-declaration.vue b/apps/web-office/src/views/contract/iframe-info/components/info-declaration/info-declaration.vue new file mode 100644 index 00000000..443512f8 --- /dev/null +++ b/apps/web-office/src/views/contract/iframe-info/components/info-declaration/info-declaration.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/apps/web-office/src/views/contract/iframe-info/components/info-perform/info-perform.vue b/apps/web-office/src/views/contract/iframe-info/components/info-perform/info-perform.vue new file mode 100644 index 00000000..443512f8 --- /dev/null +++ b/apps/web-office/src/views/contract/iframe-info/components/info-perform/info-perform.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/apps/web-office/src/views/contract/iframe-info/components/info-sign/info-sign.vue b/apps/web-office/src/views/contract/iframe-info/components/info-sign/info-sign.vue new file mode 100644 index 00000000..443512f8 --- /dev/null +++ b/apps/web-office/src/views/contract/iframe-info/components/info-sign/info-sign.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/apps/web-office/src/views/contract/iframe-info/components/info-track/info-track.vue b/apps/web-office/src/views/contract/iframe-info/components/info-track/info-track.vue new file mode 100644 index 00000000..443512f8 --- /dev/null +++ b/apps/web-office/src/views/contract/iframe-info/components/info-track/info-track.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/apps/web-office/src/views/contract/iframe-info/index.vue b/apps/web-office/src/views/contract/iframe-info/index.vue new file mode 100644 index 00000000..9a908595 --- /dev/null +++ b/apps/web-office/src/views/contract/iframe-info/index.vue @@ -0,0 +1,79 @@ + + + + diff --git a/apps/web-office/src/views/contract/perform/list/crud.tsx b/apps/web-office/src/views/contract/perform/list/crud.tsx new file mode 100644 index 00000000..400726e8 --- /dev/null +++ b/apps/web-office/src/views/contract/perform/list/crud.tsx @@ -0,0 +1,71 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { field: 'contractId', title: '合同编号', width: 100 }, + { + field: 'ctrName', title: '合同名称', minWidth: 200, slots: { + default: 'contract-name-slot' + } + }, + { field: 'contractAmount', title: '标的金额', width: 100 }, + { field: 'contractSubject', title: '合同标的', width: 150 }, + { field: 'contractCounterparty', title: '合同相对人', width: 150 }, + { field: 'cumulativeSettlementAmount', title: '累计结算金额', width: 150 }, + { field: 'changeCount', title: '变更次数', width: 100 }, + { field: 'contractStatus', title: '合同状态', width: 100 } + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + }, + time: { + title: '申报时间', + key: 'startDate', + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/perform/list/index.vue b/apps/web-office/src/views/contract/perform/list/index.vue new file mode 100644 index 00000000..e770a913 --- /dev/null +++ b/apps/web-office/src/views/contract/perform/list/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/apps/web-office/src/views/contract/perform/result/index.vue b/apps/web-office/src/views/contract/perform/result/index.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/perform/result/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/apps/web-office/src/views/contract/perform/temporary-archive/crud.tsx b/apps/web-office/src/views/contract/perform/temporary-archive/crud.tsx new file mode 100644 index 00000000..400726e8 --- /dev/null +++ b/apps/web-office/src/views/contract/perform/temporary-archive/crud.tsx @@ -0,0 +1,71 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { field: 'contractId', title: '合同编号', width: 100 }, + { + field: 'ctrName', title: '合同名称', minWidth: 200, slots: { + default: 'contract-name-slot' + } + }, + { field: 'contractAmount', title: '标的金额', width: 100 }, + { field: 'contractSubject', title: '合同标的', width: 150 }, + { field: 'contractCounterparty', title: '合同相对人', width: 150 }, + { field: 'cumulativeSettlementAmount', title: '累计结算金额', width: 150 }, + { field: 'changeCount', title: '变更次数', width: 100 }, + { field: 'contractStatus', title: '合同状态', width: 100 } + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + }, + time: { + title: '申报时间', + key: 'startDate', + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/perform/temporary-archive/index.vue b/apps/web-office/src/views/contract/perform/temporary-archive/index.vue new file mode 100644 index 00000000..e770a913 --- /dev/null +++ b/apps/web-office/src/views/contract/perform/temporary-archive/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/apps/web-office/src/views/contract/perform/todo/index.vue b/apps/web-office/src/views/contract/perform/todo/index.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/perform/todo/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/src/views/contract/schema.ts b/apps/web-office/src/views/contract/schema.ts similarity index 91% rename from src/views/contract/schema.ts rename to apps/web-office/src/views/contract/schema.ts index ee1533ff..61968d7a 100644 --- a/src/views/contract/schema.ts +++ b/apps/web-office/src/views/contract/schema.ts @@ -1,9 +1,6 @@ import type { VxeGridPropTypes } from 'vxe-table'; -import type { FormSchema } from '@/components/Form'; -import { useRender } from '@/components/Table'; -import { DICT_TYPE, getDictOptions } from '@/utils/dict'; import { h } from 'vue'; -import { NTooltip } from 'naive-ui'; +import { Tooltip } from 'ant-design-vue'; export const PrimaryKey = 'guid'; @@ -19,7 +16,7 @@ export function getTodoColumns(_params: any = {}): VxeGridPropTypes.Columns { if (text) { let classArr: string[] = ["line-clamp-3"]; return h( - NTooltip, + Tooltip, { trigger: 'hover' }, { trigger: () => h('span', { class: classArr.join(' ') }, text), @@ -53,7 +50,7 @@ export function getApprovalColumns(_params: any = {}): VxeGridPropTypes.Columns if (text) { let classArr: string[] = ["line-clamp-3"]; return h( - NTooltip, + Tooltip, { trigger: 'hover' }, { trigger: () => h('span', { class: classArr.join(' ') }, text), diff --git a/apps/web-office/src/views/contract/sign-authorization/edit/index.vue b/apps/web-office/src/views/contract/sign-authorization/edit/index.vue new file mode 100644 index 00000000..c6f51837 --- /dev/null +++ b/apps/web-office/src/views/contract/sign-authorization/edit/index.vue @@ -0,0 +1,609 @@ + + + + + diff --git a/apps/web-office/src/views/contract/sign-authorization/list/crud.tsx b/apps/web-office/src/views/contract/sign-authorization/list/crud.tsx new file mode 100644 index 00000000..48b48aa0 --- /dev/null +++ b/apps/web-office/src/views/contract/sign-authorization/list/crud.tsx @@ -0,0 +1,97 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { + field: 'contractName', title: '合同名称', minWidth: 200, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.contractName); + } + }, fixed: 'left' + }, + { + field: 'reportNo', title: '报审序号', width: 100, + }, + { + field: 'ctrTypeName', title: '合同类别', width: 200, slots: { + default: ({ row }) => { + return useRender.renderText(row.ctrTypeName, '-' + row.ctrTwoTypeName); + } + } + }, + { field: 'budgetSum', title: '预算金额', width: 100 }, + { field: 'priceTypeName', title: '币种', width: 100 }, + { + field: 'organiza', title: '组织形式', width: 120, slots: { + default: ({ row }) => { + return useRender.renderDict(row.organiza, DICT_TYPE.contractOrganizationForm); + } + } + }, + { + field: 'fundAllocation', title: '资金流向', width: 100, slots: { + default: ({ row }) => { + return useRender.renderDict(row.fundAllocation, DICT_TYPE.contractFundFlow); + } + } + }, + { field: 'inputPerson', title: '承办人', width: 100 }, + { field: 'inputDepartName', title: '承办部门', width: 100 }, + { field: 'inputDate', title: '承办时间', width: 130 }, + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + }, + time: { + title: '申报时间', + key: 'startDate', + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/sign-authorization/list/index.vue b/apps/web-office/src/views/contract/sign-authorization/list/index.vue new file mode 100644 index 00000000..e770a913 --- /dev/null +++ b/apps/web-office/src/views/contract/sign-authorization/list/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/apps/web-office/src/views/contract/sign/list/crud.tsx b/apps/web-office/src/views/contract/sign/list/crud.tsx new file mode 100644 index 00000000..48b48aa0 --- /dev/null +++ b/apps/web-office/src/views/contract/sign/list/crud.tsx @@ -0,0 +1,97 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + { + field: 'contractName', title: '合同名称', minWidth: 200, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.contractName); + } + }, fixed: 'left' + }, + { + field: 'reportNo', title: '报审序号', width: 100, + }, + { + field: 'ctrTypeName', title: '合同类别', width: 200, slots: { + default: ({ row }) => { + return useRender.renderText(row.ctrTypeName, '-' + row.ctrTwoTypeName); + } + } + }, + { field: 'budgetSum', title: '预算金额', width: 100 }, + { field: 'priceTypeName', title: '币种', width: 100 }, + { + field: 'organiza', title: '组织形式', width: 120, slots: { + default: ({ row }) => { + return useRender.renderDict(row.organiza, DICT_TYPE.contractOrganizationForm); + } + } + }, + { + field: 'fundAllocation', title: '资金流向', width: 100, slots: { + default: ({ row }) => { + return useRender.renderDict(row.fundAllocation, DICT_TYPE.contractFundFlow); + } + } + }, + { field: 'inputPerson', title: '承办人', width: 100 }, + { field: 'inputDepartName', title: '承办部门', width: 100 }, + { field: 'inputDate', title: '承办时间', width: 130 }, + ] +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + contractName: { + title: '合同名称', + key: 'contractName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + organiza: { + title: '组织形式', + key: 'organiza', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.contractOrganizationForm) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + price: { + title: '预算金额', + key: 'price', + autoSearchTrigger: 'enter', + show: true, + }, + time: { + title: '申报时间', + key: 'startDate', + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/contract/sign/list/index.vue b/apps/web-office/src/views/contract/sign/list/index.vue new file mode 100644 index 00000000..e770a913 --- /dev/null +++ b/apps/web-office/src/views/contract/sign/list/index.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/apps/web-office/src/views/contract/sign/todo/index.vue b/apps/web-office/src/views/contract/sign/todo/index.vue new file mode 100644 index 00000000..4b5eb6ab --- /dev/null +++ b/apps/web-office/src/views/contract/sign/todo/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/src/views/contract/utils.ts b/apps/web-office/src/views/contract/utils.ts similarity index 100% rename from src/views/contract/utils.ts rename to apps/web-office/src/views/contract/utils.ts diff --git a/apps/web-office/src/views/dashboard/analytics/analytics-trends.vue b/apps/web-office/src/views/dashboard/analytics/analytics-trends.vue new file mode 100644 index 00000000..35e90276 --- /dev/null +++ b/apps/web-office/src/views/dashboard/analytics/analytics-trends.vue @@ -0,0 +1,82 @@ + + + diff --git a/apps/web-office/src/views/dashboard/analytics/analytics-visits-data.vue b/apps/web-office/src/views/dashboard/analytics/analytics-visits-data.vue new file mode 100644 index 00000000..30c4265d --- /dev/null +++ b/apps/web-office/src/views/dashboard/analytics/analytics-visits-data.vue @@ -0,0 +1,84 @@ + + + diff --git a/apps/web-office/src/views/dashboard/analytics/analytics-visits-sales.vue b/apps/web-office/src/views/dashboard/analytics/analytics-visits-sales.vue new file mode 100644 index 00000000..260520b8 --- /dev/null +++ b/apps/web-office/src/views/dashboard/analytics/analytics-visits-sales.vue @@ -0,0 +1,48 @@ + + + diff --git a/apps/web-office/src/views/dashboard/analytics/analytics-visits-source.vue b/apps/web-office/src/views/dashboard/analytics/analytics-visits-source.vue new file mode 100644 index 00000000..e0d0aab5 --- /dev/null +++ b/apps/web-office/src/views/dashboard/analytics/analytics-visits-source.vue @@ -0,0 +1,67 @@ + + + diff --git a/apps/web-office/src/views/dashboard/analytics/analytics-visits.vue b/apps/web-office/src/views/dashboard/analytics/analytics-visits.vue new file mode 100644 index 00000000..7e1f14ee --- /dev/null +++ b/apps/web-office/src/views/dashboard/analytics/analytics-visits.vue @@ -0,0 +1,57 @@ + + + diff --git a/apps/web-office/src/views/dashboard/analytics/index.vue b/apps/web-office/src/views/dashboard/analytics/index.vue new file mode 100644 index 00000000..00b34df1 --- /dev/null +++ b/apps/web-office/src/views/dashboard/analytics/index.vue @@ -0,0 +1,90 @@ + + + diff --git a/apps/web-office/src/views/dashboard/components/workbench-header.vue b/apps/web-office/src/views/dashboard/components/workbench-header.vue new file mode 100644 index 00000000..0bc6dc63 --- /dev/null +++ b/apps/web-office/src/views/dashboard/components/workbench-header.vue @@ -0,0 +1,44 @@ + + diff --git a/apps/web-office/src/views/dashboard/components/workbench-quick-nav.vue b/apps/web-office/src/views/dashboard/components/workbench-quick-nav.vue new file mode 100644 index 00000000..4c127cdf --- /dev/null +++ b/apps/web-office/src/views/dashboard/components/workbench-quick-nav.vue @@ -0,0 +1,44 @@ + + + diff --git a/apps/web-office/src/views/dashboard/home/index.vue b/apps/web-office/src/views/dashboard/home/index.vue new file mode 100644 index 00000000..2de67c36 --- /dev/null +++ b/apps/web-office/src/views/dashboard/home/index.vue @@ -0,0 +1,79 @@ + + + diff --git a/apps/web-office/src/views/dashboard/workspace/index.vue b/apps/web-office/src/views/dashboard/workspace/index.vue new file mode 100644 index 00000000..c8ae0273 --- /dev/null +++ b/apps/web-office/src/views/dashboard/workspace/index.vue @@ -0,0 +1,225 @@ + + + diff --git a/apps/web-office/src/views/demos/antd/index.vue b/apps/web-office/src/views/demos/antd/index.vue new file mode 100644 index 00000000..8286bebb --- /dev/null +++ b/apps/web-office/src/views/demos/antd/index.vue @@ -0,0 +1,66 @@ + + + diff --git a/apps/web-office/src/views/duty/list/crud.tsx b/apps/web-office/src/views/duty/list/crud.tsx new file mode 100644 index 00000000..4ffeac4d --- /dev/null +++ b/apps/web-office/src/views/duty/list/crud.tsx @@ -0,0 +1,160 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; + +export const PrimaryKey = 'guid'; + +export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { + return [ + { + type: 'radio', + width: 40, + slots: { radio: 'radio_cell' }, + align: 'center', + fixed: 'left', + }, + { + field: 'dutyDate', + title: '值班日期', + width: 120, + fixed: 'left', + headerAlign: 'center', + align: 'center', + slots: { + default: ({ row }) => { + return useRender.renderDate(row.dutyDate, 'YYYY年MM月DD日'); + }, + }, + }, + { + field: 'zzb', + title: '总值班', + headerAlign: 'center', + align: 'center', + children: [ + { + field: 'dutyAllPeople', + title: '姓名', + width: 120, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dutyAllPhone', + title: '办公室电话', + width: 100, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dutyAllTelphone', + title: '手机', + width: 100, + headerAlign: 'center', + align: 'center', + }, + ], + }, + { + field: 'ddy', + title: '机关部门领导', + headerAlign: 'center', + align: 'center', + children: [ + { + field: 'dispatchPeople', + title: '姓名', + width: 120, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dispatchPhone', + title: '办公室电话', + width: 100, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dispatchTelphone', + title: '手机', + width: 100, + headerAlign: 'center', + align: 'center', + }, + ], + }, + { + field: 'zb', + title: '值班人员', + headerAlign: 'center', + align: 'center', + children: [ + { + field: 'dutyPeople', + title: '姓名', + width: 120, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dutyPhone', + title: '办公室电话', + width: 100, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dutyTelphone', + title: '手机', + width: 100, + headerAlign: 'center', + align: 'center', + }, + ], + }, + { + field: 'sj', + title: '司机', + headerAlign: 'center', + align: 'center', + children: [ + { + field: 'driver', + title: '姓名', + width: 120, + headerAlign: 'center', + align: 'center', + }, + { + field: 'driverTelphone', + title: '手机', + width: 100, + headerAlign: 'center', + align: 'center', + }, + ], + }, + // { field: 'zzb', title: '总值班人员', width: 200, slots: { default: 'zzbSlot' } }, + // { field: 'ddy', title: '机关部门领导', width: 200, slots: { default: 'ddy' } }, + // { field: 'jrzb', title: '值班人员', width: 200, slots: { default: 'jrzb' } }, + // { field: 'sj', title: '司机', width: 200, slots: { default: 'sjSlot' } }, + { field: 'remark', title: '备注', headerAlign: 'center', minWidth: 200 }, + ]; +} + +export function getFormSchema(_params: any = {}) { + return [ + { + field: 'duty_date', + component: 'NDatePicker', + label: '值班月份', + defaultValue: dayjs().format('YYYY-MM'), + componentProps: { + type: 'month', + placeholder: '', + valueFormat: 'yyyy-MM', + }, + }, + ]; +} diff --git a/apps/web-office/src/views/duty/list/duty-edit-modal.vue b/apps/web-office/src/views/duty/list/duty-edit-modal.vue new file mode 100644 index 00000000..9de69f4a --- /dev/null +++ b/apps/web-office/src/views/duty/list/duty-edit-modal.vue @@ -0,0 +1,271 @@ + + diff --git a/apps/web-office/src/views/duty/list/duty-upload-modal.vue b/apps/web-office/src/views/duty/list/duty-upload-modal.vue new file mode 100644 index 00000000..3db7f988 --- /dev/null +++ b/apps/web-office/src/views/duty/list/duty-upload-modal.vue @@ -0,0 +1,129 @@ + + diff --git a/apps/web-office/src/views/duty/list/index.vue b/apps/web-office/src/views/duty/list/index.vue new file mode 100644 index 00000000..8f2f9751 --- /dev/null +++ b/apps/web-office/src/views/duty/list/index.vue @@ -0,0 +1,276 @@ + + + + + diff --git a/apps/web-office/src/views/duty/standing-book/crud.tsx b/apps/web-office/src/views/duty/standing-book/crud.tsx new file mode 100644 index 00000000..c836e29e --- /dev/null +++ b/apps/web-office/src/views/duty/standing-book/crud.tsx @@ -0,0 +1,153 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; + +export const PrimaryKey = 'guid'; + +export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { + return [ + { + field: 'dutyDate', + title: '值班日期', + width: 150, + fixed: 'left', + headerAlign: 'center', + align: 'center', + slots: { + default: ({ row }) => { + return useRender.renderDate(row.dutyDate, 'YYYY年MM月DD日'); + }, + }, + }, + { + field: 'zzb', + title: '总值班', + headerAlign: 'center', + align: 'center', + children: [ + { + field: 'dutyAllPeople', + title: '姓名', + width: 150, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dutyAllPhone', + title: '办公室电话', + width: 120, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dutyAllTelphone', + title: '手机', + width: 120, + headerAlign: 'center', + align: 'center', + }, + ], + }, + { + field: 'ddy', + title: '机关部门领导', + headerAlign: 'center', + align: 'center', + children: [ + { + field: 'dispatchPeople', + title: '姓名', + width: 150, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dispatchPhone', + title: '办公室电话', + width: 120, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dispatchTelphone', + title: '手机', + width: 120, + headerAlign: 'center', + align: 'center', + }, + ], + }, + { + field: 'zb', + title: '值班人员', + headerAlign: 'center', + align: 'center', + children: [ + { + field: 'dutyPeople', + title: '姓名', + width: 150, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dutyPhone', + title: '办公室电话', + width: 120, + headerAlign: 'center', + align: 'center', + }, + { + field: 'dutyTelphone', + title: '手机', + width: 120, + headerAlign: 'center', + align: 'center', + }, + ], + }, + { + field: 'sj', + title: '司机', + headerAlign: 'center', + align: 'center', + children: [ + { + field: 'driver', + title: '姓名', + width: 150, + headerAlign: 'center', + align: 'center', + }, + { + field: 'driverTelphone', + title: '手机', + width: 120, + headerAlign: 'center', + align: 'center', + }, + ], + }, + // { field: 'zzb', title: '总值班人员', width: 200, slots: { default: 'zzbSlot' } }, + // { field: 'ddy', title: '机关部门领导', width: 200, slots: { default: 'ddy' } }, + // { field: 'jrzb', title: '值班人员', width: 200, slots: { default: 'jrzb' } }, + // { field: 'sj', title: '司机', width: 200, slots: { default: 'sjSlot' } }, + { field: 'remark', title: '备注', headerAlign: 'center', minWidth: 150 }, + ]; +} + +export function getFormSchema(_params: any = {}) { + return [ + { + field: 'duty_date', + component: 'NDatePicker', + label: '值班月份', + defaultValue: dayjs().format('YYYY-MM'), + componentProps: { + type: 'month', + placeholder: '', + valueFormat: 'yyyy-MM', + }, + }, + ]; +} diff --git a/apps/web-office/src/views/duty/standing-book/index.vue b/apps/web-office/src/views/duty/standing-book/index.vue new file mode 100644 index 00000000..c105746e --- /dev/null +++ b/apps/web-office/src/views/duty/standing-book/index.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/apps/web-office/src/views/meeting/edit/index.vue b/apps/web-office/src/views/meeting/edit/index.vue new file mode 100644 index 00000000..05f1ea36 --- /dev/null +++ b/apps/web-office/src/views/meeting/edit/index.vue @@ -0,0 +1,661 @@ + + + + + diff --git a/apps/web-office/src/views/meeting/edit/spoken-person-edit-modal.vue b/apps/web-office/src/views/meeting/edit/spoken-person-edit-modal.vue new file mode 100644 index 00000000..b6fb29d2 --- /dev/null +++ b/apps/web-office/src/views/meeting/edit/spoken-person-edit-modal.vue @@ -0,0 +1,165 @@ + + diff --git a/apps/web-office/src/views/meeting/list/crud.tsx b/apps/web-office/src/views/meeting/list/crud.tsx new file mode 100644 index 00000000..37b4f42a --- /dev/null +++ b/apps/web-office/src/views/meeting/list/crud.tsx @@ -0,0 +1,179 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + let columns = [ + { + field: 'isConfirm', + title: '会议是否落实', + width: 100, + slots: { + default: ({ row }) => { + return useRender.renderTag(row.isConfirm === 1 ? '是' : '否', row.isConfirm === 1 ? 'success' : 'warning'); + }, + }, + }, + { + field: 'meetingTheme', + title: '会议主题', + minWidth: 300, + slots: { + default: 'meetingThemeSlot', + }, + }, + { + field: 'meetingDate', + title: '会议信息', + width: 200, + slots: { default: 'meetingInfoSlot' }, + }, + { field: 'meetingType', title: '会议类型', width: 120 }, + // { field: 'gznr', title: '工作内容', width: 120 }, + { field: 'compere', title: '主持人', width: 80 }, + { + field: 'isEmployeeRepresentatives', + title: '职工代表', + width: 100, + align: 'center', + slots: { + default: ({ row }) => { + return row.isEmployeeRepresentatives ? '是' : '否'; + }, + }, + }, + { + field: 'otherEquipment', + title: '其它设备', + width: 200, + slots: { + default: ({ row }) => { + return useRender.renderDict((row.otherEquipment || '').split(','), DICT_TYPE.meeting_facilities); + }, + }, + }, + { + field: 'meetingSpeakersCount', + title: '发言人数', + width: 100, + align: 'center', + slots: { + default: ({ row }) => { + return row.meetingSpeakersCount || 0; + }, + }, + }, + { field: 'conferee', title: '参会人员', minWidth: 200 }, + { field: 'creator', title: '登记人', minWidth: 120 }, + { field: 'createTime', title: '登记时间', minWidth: 150 }, + ]; + + if (params.type != 'taizhang') { + columns.unshift({ + type: 'radio', + width: 40, + slots: { radio: 'radio_cell' }, + align: 'center', + fixed: 'left', + }); + columns.push({ + field: 'operation', + title: '操作', + width: 100, + fixed: 'right', + slots: { + default: 'operation_cell', + }, + }); + } + return columns; +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + startDate: dayjs().startOf('month').format("YYYY-MM-DD"), + }, + columns: { + startDate: { + title: '开始日期', + key: 'startDate', + component: { + name: 'a-date-picker', + vModel: 'value', + allowClear: true, + props: { + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + }, + }, + autoSearchTrigger: 'enter', + show: true, + }, + endDate: { + title: '截止日期', + key: 'endDate', + component: { + name: 'a-date-picker', + vModel: 'value', + allowClear: true, + props: { + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + }, + }, + autoSearchTrigger: 'enter', + show: true, + }, + meetingTheme: { + title: '会议主题', + key: 'meetingTheme', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + meetingId: { + title: '会议室', + key: 'meetingId', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + async getData(dict, context) { + return getDictOptions(DICT_TYPE.meeting_room); + }, + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + meetingType: { + title: '会议类型', + key: 'meetingType', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + async getData(dict, context) { + return getDictOptions(DICT_TYPE.meeting_type); + }, + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/meeting/list/index.vue b/apps/web-office/src/views/meeting/list/index.vue new file mode 100644 index 00000000..0b31bae4 --- /dev/null +++ b/apps/web-office/src/views/meeting/list/index.vue @@ -0,0 +1,254 @@ + + + + + diff --git a/src/views/meeting/home/schema.ts b/apps/web-office/src/views/meeting/standing-book/crud.tsx similarity index 63% rename from src/views/meeting/home/schema.ts rename to apps/web-office/src/views/meeting/standing-book/crud.tsx index 8481ccfa..8f30e03e 100644 --- a/src/views/meeting/home/schema.ts +++ b/apps/web-office/src/views/meeting/standing-book/crud.tsx @@ -1,9 +1,7 @@ import type { VxeGridPropTypes } from 'vxe-table'; -import type { FormSchema } from '@/components/Form'; -import { useRender } from '@/components/Table'; -import { DICT_TYPE, getDictOptions } from '@/utils/dict'; +import { useRender } from '#/hooks/useRender'; import dayjs from 'dayjs'; -import { shortcuts } from "@/utils/time"; +import { DICT_TYPE } from '#/utils/dict'; export const PrimaryKey = 'guid'; @@ -17,12 +15,12 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns { } } }, - { field: 'meetingDate', title: '会议信息', width: 200, slots: { default: 'meetingInfoSlot' } }, { field: 'meetingTheme', title: '会议主题', minWidth: 300, slots: { default: "meetingThemeSlot" } }, + { field: 'meetingDate', title: '会议信息', width: 200, slots: { default: 'meetingInfoSlot' } }, { field: 'meetingType', title: '会议类型', width: 120 }, // { field: 'gznr', title: '工作内容', width: 120 }, { field: 'compere', title: '主持人', width: 80 }, @@ -55,8 +53,6 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns { { field: 'conferee', title: '参会人员', minWidth: 200 }, { field: 'creator', title: '登记人', minWidth: 120 }, { field: 'createTime', title: '登记时间', minWidth: 150 }, - - ]; if (params.type != 'taizhang') { @@ -78,55 +74,18 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns { return columns } -export function getFormSchema(_params: any = {}): FormSchema[] { +export function getFormSchema(_params: any = {}) { return [ { - field: 'meetingTheme', - component: 'NInput', - label: '会议主题', + field: 'duty_date', + component: 'NDatePicker', + label: '值班月份', + defaultValue: dayjs().format('YYYY-MM'), componentProps: { + type: 'month', placeholder: '', - options: getDictOptions(DICT_TYPE.meeting_room) - } - }, - { - field: "startDate", - label: "开始日期", - component: "NDatePicker", - defaultValue: dayjs().startOf('month').format("YYYY-MM-DD"), - componentProps: { - placeholder: "", - valueFormat: "yyyy-MM-dd", - type: "date", + valueFormat: 'yyyy-MM', }, }, - { - field: "endDate", - label: "截止日期", - component: "NDatePicker", - componentProps: { - placeholder: "", - valueFormat: "yyyy-MM-dd", - type: "date", - }, - }, - { - field: 'meetingId', - component: 'NSelect', - label: '会议室', - componentProps: { - placeholder: '', - options: getDictOptions(DICT_TYPE.meeting_room) - } - }, - { - field: 'meetingType', - component: 'NSelect', - label: '会议类型', - componentProps: { - placeholder: '', - options: getDictOptions(DICT_TYPE.meeting_type) - } - } ]; } diff --git a/apps/web-office/src/views/meeting/standing-book/index.vue b/apps/web-office/src/views/meeting/standing-book/index.vue new file mode 100644 index 00000000..c59afc9b --- /dev/null +++ b/apps/web-office/src/views/meeting/standing-book/index.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/src/views/iframe/meeting/start/[id].vue b/apps/web-office/src/views/meeting/start/index.vue similarity index 62% rename from src/views/iframe/meeting/start/[id].vue rename to apps/web-office/src/views/meeting/start/index.vue index baa1fbb4..b610d571 100644 --- a/src/views/iframe/meeting/start/[id].vue +++ b/apps/web-office/src/views/meeting/start/index.vue @@ -1,54 +1,31 @@ + + + + + + + + diff --git a/apps/web-office/src/views/office-supplies/inventory/supplies-edit-modal.vue b/apps/web-office/src/views/office-supplies/inventory/supplies-edit-modal.vue new file mode 100644 index 00000000..6ac952fc --- /dev/null +++ b/apps/web-office/src/views/office-supplies/inventory/supplies-edit-modal.vue @@ -0,0 +1,123 @@ + + diff --git a/apps/web-office/src/views/office-supplies/inventory/supplies-out-modal.vue b/apps/web-office/src/views/office-supplies/inventory/supplies-out-modal.vue new file mode 100644 index 00000000..bbc37fd1 --- /dev/null +++ b/apps/web-office/src/views/office-supplies/inventory/supplies-out-modal.vue @@ -0,0 +1,274 @@ + + diff --git a/apps/web-office/src/views/office-supplies/inventory/supplies-put-modal.vue b/apps/web-office/src/views/office-supplies/inventory/supplies-put-modal.vue new file mode 100644 index 00000000..2d1aaecc --- /dev/null +++ b/apps/web-office/src/views/office-supplies/inventory/supplies-put-modal.vue @@ -0,0 +1,219 @@ + + diff --git a/apps/web-office/src/views/office-supplies/settle/crud.tsx b/apps/web-office/src/views/office-supplies/settle/crud.tsx new file mode 100644 index 00000000..f5cab0a1 --- /dev/null +++ b/apps/web-office/src/views/office-supplies/settle/crud.tsx @@ -0,0 +1,131 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; +import { unitComponentProps } from '#/common/unit'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { + type: "radio", + width: 40, + slots: { radio: "radio_cell" }, + align: "center", + fixed: "left", + }, + { field: "applyName", title: "申请人", width: 120 }, + { field: "officeName", title: "申请物品", minWidth: 150 }, + { + field: "model", + title: "物品型号", + minWidth: 150, + }, + { + field: "count", + title: "申请数量", + minWidth: 80, + slots: { + default: ({ row }) => { + return row.count + "个"; + }, + }, + }, + { field: "remarks", title: "申请原因", width: 200 }, + { + field: "status", + title: "申请状态", + width: 120, + slots: { + default: ({ row }) => { + return useRender.renderDict(row.status, DICT_TYPE.officesupplies_status, { + labelField: "extend1", + }); + }, + }, + }, + { + field: "companyRealCount", + title: "实际发放量", + width: 100, + showOverflow: true, + slots: { + default: ({ row }) => { + return useRender.renderText(row.companyRealCount, "个"); + }, + }, + }, + { field: "time", title: "申请时间", width: 150 }, + ] +} + +export function getFormSchema(params: any = {}) { + + const { chooseUserModalApi } = params + + let data = getDictOptions(DICT_TYPE.officesupplies_status); + data.forEach((item) => { + item.label = item.extend1; + }); + + return { + initialForm: { + }, + columns: { + status: { + title: '申请状态', + key: 'status', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: data + }) + }, + autoSearchTrigger: 'enter', + show: true, + }, + // applyId: { + // title: '申请人员', + // key: 'applyId', + // component: { + // name: 'a-input', + // vModel: 'value', + // readOnly: true, + // onClick: () => { + // chooseUserModalApi.open(); + // }, + // }, + // autoSearchTrigger: 'enter', + // show: true, + // }, + officeName: { + title: '申请物品', + key: 'officeName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + remarks: { + title: '申请原因 ', + key: 'remarks', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + }, + } +} + diff --git a/apps/web-office/src/views/office-supplies/settle/index.vue b/apps/web-office/src/views/office-supplies/settle/index.vue new file mode 100644 index 00000000..b99768f7 --- /dev/null +++ b/apps/web-office/src/views/office-supplies/settle/index.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/apps/web-office/src/views/supervise/edit/index.vue b/apps/web-office/src/views/supervise/edit/index.vue new file mode 100644 index 00000000..3d3b26e5 --- /dev/null +++ b/apps/web-office/src/views/supervise/edit/index.vue @@ -0,0 +1,375 @@ + + + + + diff --git a/apps/web-office/src/views/supervise/feedback/crud.tsx b/apps/web-office/src/views/supervise/feedback/crud.tsx new file mode 100644 index 00000000..a914f367 --- /dev/null +++ b/apps/web-office/src/views/supervise/feedback/crud.tsx @@ -0,0 +1,99 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; +import { unitComponentProps } from '#/common/unit'; + +export const PrimaryKey = 'guid'; + +export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'seq', width: 50 }, + { field: 'taskName', title: '任务名称', width: 120 }, + { field: 'taskContent', title: '任务内容', minWidth: 200 }, + { field: 'level', title: '紧急程度', width: 120 }, + { field: 'finishStatus', title: '完成情况', width: 120 }, + { field: 'ip', title: '负责部门', width: 120 }, + { field: 'starttime', title: '发起时间', width: 120 }, + { field: 'zhushi', title: '预计完成时间', width: 120 }, + { field: 'endtime', title: '截止时间', width: 120 }, + { field: 'executeDepartmentName', title: '执行部门', width: 120 }, + // { title: '操作', width: 120, fixed: 'right', slots: { default: 'operate' } } + ]; +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + }, + columns: { + taskName: { + title: '任务名称', + key: 'taskName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + taskStatus: { + title: '任务状态', + key: 'taskStatus', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: [ + { + value: '1', + label: '未开始' + }, + { + value: '2', + label: '进行中' + }, + { + value: '3', + label: '已完成' + }, + { + value: '4', + label: '已超时' + } + ] + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + taskType: { + title: '任务类型', + key: 'taskType', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.supervise_task_type) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + // department: { + // title: '负责部门', + // key: 'department', + // component: unitComponentProps, + // autoSearchTrigger: 'enter', + // show: true, + // }, + }, + } +} + diff --git a/apps/web-office/src/views/supervise/feedback/index.vue b/apps/web-office/src/views/supervise/feedback/index.vue new file mode 100644 index 00000000..60983a30 --- /dev/null +++ b/apps/web-office/src/views/supervise/feedback/index.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/src/views/supervise/feedback/schema.ts b/apps/web-office/src/views/supervise/list/crud.tsx similarity index 52% rename from src/views/supervise/feedback/schema.ts rename to apps/web-office/src/views/supervise/list/crud.tsx index 5553ccb2..95034c06 100644 --- a/src/views/supervise/feedback/schema.ts +++ b/apps/web-office/src/views/supervise/list/crud.tsx @@ -1,11 +1,13 @@ import type { VxeGridPropTypes } from 'vxe-table'; -import type { FormSchema } from '@/components/Form'; -import { useRender } from '@/components/Table'; -import { DICT_TYPE, getDictOptions } from '@/utils/dict'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; +import { unitComponentProps } from '#/common/unit'; export const PrimaryKey = 'guid'; -export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { return [ { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, // { type: 'expand', width: 60, slots: { content: 'expand_content' } }, @@ -82,56 +84,77 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns { ]; } -export function getFormSchema(_params: any = {}): FormSchema[] { - return [ - { - field: 'taskName', - component: 'NInput', - label: '任务名称', - componentProps: { - placeholder: '', - } +export function getFormSchema(_params: any = {}) { + return { + initialForm: { }, - { - field: 'taskStatus', - component: 'NSelect', - label: '任务状态', - componentProps: { - options: [ - { - value: '1', - label: '未开始' - }, - { - value: '2', - label: '进行中' - }, - { - value: '3', - label: '已完成' - }, - { - value: '4', - label: '已超时' - } - ] + columns: { + taskName: { + title: '任务名称', + key: 'taskName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, }, - }, - { - field: 'taskType', - component: 'NSelect', - label: '任务类型', - componentProps: { - options: getDictOptions(DICT_TYPE.supervise_task_type) + taskStatus: { + title: '任务状态', + key: 'taskStatus', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: [ + { + value: '1', + label: '未开始' + }, + { + value: '2', + label: '进行中' + }, + { + value: '3', + label: '已完成' + }, + { + value: '4', + label: '已超时' + } + ] + }), + }, + autoSearchTrigger: 'enter', + show: true, }, - }, - { - field: 'department', - component: 'NSelect', - label: '负责部门', - componentProps: { - options: [] + taskType: { + title: '任务类型', + key: 'taskType', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.supervise_task_type) + }), + }, + autoSearchTrigger: 'enter', + show: true, }, + // department: { + // title: '负责部门', + // key: 'department', + // component: unitComponentProps, + // autoSearchTrigger: 'enter', + // show: true, + // }, }, - ]; + } } + diff --git a/apps/web-office/src/views/supervise/list/index.vue b/apps/web-office/src/views/supervise/list/index.vue new file mode 100644 index 00000000..5bfa113f --- /dev/null +++ b/apps/web-office/src/views/supervise/list/index.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/apps/web-office/src/views/supervise/summary/crud.tsx b/apps/web-office/src/views/supervise/summary/crud.tsx new file mode 100644 index 00000000..2351e9a7 --- /dev/null +++ b/apps/web-office/src/views/supervise/summary/crud.tsx @@ -0,0 +1,160 @@ +import type { VxeGridPropTypes } from 'vxe-table'; +import { useRender } from '#/hooks/useRender'; +import dayjs from 'dayjs'; +import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict'; +import { dict } from '@fast-crud/fast-crud'; +import { unitComponentProps } from '#/common/unit'; + +export const PrimaryKey = 'guid'; + +export function getColumns(params: any = {}): VxeGridPropTypes.Columns { + return [ + { type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' }, + // { type: 'expand', width: 60, slots: { content: 'expand_content' } }, + { + field: 'TASK_NAME', title: '任务标题', width: 200, slots: { + default: "task-name-slot" + }, + }, + { + field: 'status', title: '任务状态', width: 120, slots: { + default: "statusSlot" + }, + }, + { + field: 'taskType', + title: '任务类型', + width: 100, + slots: { + default: ({ row }) => { + return useRender.renderDict(row.taskType, DICT_TYPE.supervise_task_type); + } + } + }, + { + field: 'TASK_CONTENT', title: '任务内容', width: 300, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.TASK_CONTENT, {}); + } + }, + }, + { + field: 'taskProgress', title: '任务进度', minWidth: 200, slots: { + default: ({ row }) => { + return useRender.renderMultiLineText(row.taskProgress, {}); + } + }, + }, + { + field: 'urgentDegree', + title: '紧急程度', + width: 100, + slots: { + default: ({ row }) => { + return useRender.renderDict(row.urgentDegree, DICT_TYPE.supervise_emergency_level); + } + } + }, + { + field: 'starttime', title: '开始日期', width: 120, + slots: { + default: ({ row }) => { + return useRender.renderDate(row.starttime, 'YYYY-MM-DD'); + } + } + }, + { + field: 'endtime', title: '截止日期', width: 120, + slots: { + default: ({ row }) => { + return useRender.renderDate(row.endtime, 'YYYY-MM-DD'); + } + } + }, + { + field: 'planFinishTime', title: '预计完成日期', width: 120, + slots: { + default: ({ row }) => { + return useRender.renderDate(row.planFinishTime, 'YYYY-MM-DD'); + } + } + }, + { field: 'remarks', title: '备注', minWidth: 200 }, + // { title: '操作', width: 120, fixed: 'right', slots: { default: 'operate' } } + ]; +} + +export function getFormSchema(_params: any = {}) { + return { + initialForm: { + }, + columns: { + taskName: { + title: '任务名称', + key: 'taskName', + component: { + name: 'a-input', + vModel: 'value', + allowClear: true, + }, + autoSearchTrigger: 'enter', + show: true, + }, + taskStatus: { + title: '任务状态', + key: 'taskStatus', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: [ + { + value: '1', + label: '未开始' + }, + { + value: '2', + label: '进行中' + }, + { + value: '3', + label: '已完成' + }, + { + value: '4', + label: '已超时' + } + ] + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + taskType: { + title: '任务类型', + key: 'taskType', + component: { + name: 'fs-dict-select', + vModel: 'value', + class: 'min-w-[180px]', + allowClear: true, + dict: dict({ + data: getDictOptions(DICT_TYPE.supervise_task_type) + }), + }, + autoSearchTrigger: 'enter', + show: true, + }, + // department: { + // title: '负责部门', + // key: 'department', + // component: unitComponentProps, + // autoSearchTrigger: 'enter', + // show: true, + // }, + }, + } +} + diff --git a/apps/web-office/src/views/supervise/summary/index.vue b/apps/web-office/src/views/supervise/summary/index.vue new file mode 100644 index 00000000..e8aae711 --- /dev/null +++ b/apps/web-office/src/views/supervise/summary/index.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/apps/web-office/src/views/system/dict/crud.tsx b/apps/web-office/src/views/system/dict/crud.tsx new file mode 100644 index 00000000..70a4a8ee --- /dev/null +++ b/apps/web-office/src/views/system/dict/crud.tsx @@ -0,0 +1,78 @@ +import { type CreateCrudOptionsRet, dict, utils } from '@fast-crud/fast-crud'; + +export default function (): CreateCrudOptionsRet { + return { + crudOptions: { + columns: { + age: { + form: { + helper: '正则表达式', + rules: [{ message: '必须为整数', pattern: /^\d+$/ }], + }, + title: '年龄', + type: 'text', + }, + email: { + form: { + rules: [{ message: '请填写正确的邮箱', type: 'email' }], + }, + title: '邮箱', + type: 'text', + }, + name: { + editForm: { + rules: [{ max: 5, message: '姓名长度为2-5', min: 2 }], + }, + form: { + component: { + maxlength: 5, // 原生属性要写在这里 + props: { + showWordLimit: true, + type: 'text', + }, + }, + helper: '添加和编辑时必填,编辑时额外需要校验长度', + rules: [{ message: '请输入姓名', required: true }], + }, + search: { + show: true, + }, + title: '姓名', + type: 'text', + }, + status: { + dict: dict({ + url: '/mock/dicts/OpenStatusEnum', + }), + form: { + rules: [{ message: '请选择一个选项', required: true }], + }, + title: '必选', + type: 'dict-select', + }, + url: { + form: { + rules: [{ message: '请填写正确的url', type: 'url' }], + }, + title: 'URL', + type: 'text', + }, + }, + form: { + afterSubmit(context) { + utils.logger.log('afterSubmit', context); + }, + beforeSubmit(context) { + utils.logger.log('beforeSubmit', context); + }, + row: { + gutter: 20, + }, + }, + request: {}, + settings: { + viewFormUseCellComponent: true, + }, + }, + }; +} diff --git a/apps/web-office/src/views/system/dict/dict-data-edit-modal.vue b/apps/web-office/src/views/system/dict/dict-data-edit-modal.vue new file mode 100644 index 00000000..8bf55483 --- /dev/null +++ b/apps/web-office/src/views/system/dict/dict-data-edit-modal.vue @@ -0,0 +1,187 @@ + + diff --git a/apps/web-office/src/views/system/dict/dict-type-edit-modal.vue b/apps/web-office/src/views/system/dict/dict-type-edit-modal.vue new file mode 100644 index 00000000..60e1c9a0 --- /dev/null +++ b/apps/web-office/src/views/system/dict/dict-type-edit-modal.vue @@ -0,0 +1,158 @@ + + diff --git a/apps/web-office/src/views/system/dict/index.vue b/apps/web-office/src/views/system/dict/index.vue new file mode 100644 index 00000000..4f3c2f4f --- /dev/null +++ b/apps/web-office/src/views/system/dict/index.vue @@ -0,0 +1,355 @@ + + + + + diff --git a/apps/web-office/src/views/system/user/choose-user-modal.vue b/apps/web-office/src/views/system/user/choose-user-modal.vue new file mode 100644 index 00000000..228fab90 --- /dev/null +++ b/apps/web-office/src/views/system/user/choose-user-modal.vue @@ -0,0 +1,355 @@ + + diff --git a/apps/web-office/src/views/user-center/center/index.vue b/apps/web-office/src/views/user-center/center/index.vue new file mode 100644 index 00000000..324c1a74 --- /dev/null +++ b/apps/web-office/src/views/user-center/center/index.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/apps/web-office/src/views/user-center/todo/index.vue b/apps/web-office/src/views/user-center/todo/index.vue new file mode 100644 index 00000000..8fe14f9f --- /dev/null +++ b/apps/web-office/src/views/user-center/todo/index.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/apps/web-office/tailwind.config.mjs b/apps/web-office/tailwind.config.mjs new file mode 100644 index 00000000..f17f556f --- /dev/null +++ b/apps/web-office/tailwind.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config'; diff --git a/apps/web-office/tsconfig.json b/apps/web-office/tsconfig.json new file mode 100644 index 00000000..ea106b4a --- /dev/null +++ b/apps/web-office/tsconfig.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web-app.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "#/*": ["./src/*"] + }, + "allowImportingTsExtensions":true + }, + + "references": [{ "path": "./tsconfig.node.json" }], + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/apps/web-office/tsconfig.node.json b/apps/web-office/tsconfig.node.json new file mode 100644 index 00000000..c2f0d86c --- /dev/null +++ b/apps/web-office/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/node.json", + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "noEmit": false + }, + "include": ["vite.config.mts"] +} diff --git a/apps/web-office/vite.config.mts b/apps/web-office/vite.config.mts new file mode 100644 index 00000000..3f8d4cea --- /dev/null +++ b/apps/web-office/vite.config.mts @@ -0,0 +1,97 @@ +import { defineConfig } from '@vben/vite-config'; + +import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'; +import Components from 'unplugin-vue-components/vite'; +import AutoImport from 'unplugin-auto-import/vite' +import { lazyImport, VxeResolver } from 'vite-plugin-lazy-import' + +export default defineConfig(async () => { + return { + application: {}, + plugins: [ + AutoImport({ + // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等 + imports: ['vue'], + include: [ + /\.[tj]sx?$/, + /\.vue$/, + /\.vue\?vue/, + ], + resolvers: [ + // // 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式) + // ElementPlusResolver(), + // // 自动导入图标组件 + // IconsResolver({}) + ], + vueTemplate: true, // 是否在 vue 模板中自动导入 + dts: true // (false) 配置文件生成位置,默认是根目录 /auto-imports.d.ts + }), + Components({ + dts: true, + resolvers: [ + AntDesignVueResolver({ + importStyle: false, // css in js + }), + ], + }), + lazyImport({ + resolvers: [ + VxeResolver({ + libraryName: 'vxe-table' + }), + ] + }) + ], + vite: { + server: { + host: '0.0.0.0', + open: false, + port: 9528, + proxy: { + '/api/app': { + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api\/app/, '/'), + // target: `http://10.71.220.24:8083/rl`, + target: `http://192.168.147.164:8083/rl`, + ws: true, + }, + '/api/uc': { + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api\/uc/, '/'), + // target: `http://10.71.220.24:8082`, + target: `http://192.168.147.164:8082`, + ws: true, + }, + '/api/czg/app': { + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api\/czg\/app/, '/'), + // mock代理目标地址 + target: `http://10.71.221.222:8083/rl`, + ws: true, + }, + '/api/czg/uc': { + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api\/czg\/uc/, '/'), + // mock代理目标地址 + target: `http://10.71.220.24:8082`, + ws: true, + }, + '/api/zp/app': { + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api\/zp\/app/, '/'), + // mock代理目标地址 + target: `http://192.168.153.236:8083/rl`, + ws: true, + }, + '/api/zp/uc': { + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api\/zp\/uc/, '/'), + // mock代理目标地址 + target: `http://192.168.147.164:8082`, + ws: true, + }, + }, + }, + }, + }; +}); diff --git a/build-local-docker-image.sh b/build-local-docker-image.sh new file mode 100644 index 00000000..d33bd7c6 --- /dev/null +++ b/build-local-docker-image.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +LOG_FILE=${SCRIPT_DIR}/build-local-docker-image.log +ERROR="" +IMAGE_NAME="vben-admin-local" + +function stop_and_remove_container() { + # Stop and remove the existing container + docker stop ${IMAGE_NAME} >/dev/null 2>&1 + docker rm ${IMAGE_NAME} >/dev/null 2>&1 +} + +function remove_image() { + # Remove the existing image + docker rmi vben-admin-pro >/dev/null 2>&1 +} + +function install_dependencies() { + # Install all dependencies + cd ${SCRIPT_DIR} + pnpm install || ERROR="install_dependencies failed" +} + +function build_image() { + # build docker + docker build . -f Dockerfile -t ${IMAGE_NAME} || ERROR="build_image failed" +} + +function log_message() { + if [[ ${ERROR} != "" ]]; + then + >&2 echo "build failed, Please check build-local-docker-image.log for more details" + >&2 echo "ERROR: ${ERROR}" + exit 1 + else + echo "docker image with tag '${IMAGE_NAME}' built sussessfully. Use below sample command to run the container" + echo "" + echo "docker run -d -p 8010:8080 --name ${IMAGE_NAME} ${IMAGE_NAME}" + fi +} + +echo "Info: Stopping and removing existing container and image" | tee ${LOG_FILE} +stop_and_remove_container +remove_image + +echo "Info: Installing dependencies" | tee -a ${LOG_FILE} +install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE} + +if [[ ${ERROR} == "" ]]; then + echo "Info: Building docker image" | tee -a ${LOG_FILE} + build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE} +fi + +log_message | tee -a ${LOG_FILE} diff --git a/build/config/index.ts b/build/config/index.ts deleted file mode 100644 index 9bcd8689..00000000 --- a/build/config/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './proxy'; diff --git a/build/config/proxy.ts b/build/config/proxy.ts deleted file mode 100644 index 350dfee9..00000000 --- a/build/config/proxy.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { ProxyOptions } from 'vite'; -import { createServiceConfig } from '../../src/utils/service'; - -/** - * Set http proxy - * - * @param env - The current env - * @param isDev - Is development environment - */ -export function createViteProxy(env: Env.ImportMeta, isDev: boolean) { - const isEnableHttpProxy = isDev && env.VITE_HTTP_PROXY === 'Y'; - - if (!isEnableHttpProxy) return undefined; - - const { baseURL, proxyPattern, other } = createServiceConfig(env); - - const proxy: Record = createProxyItem({ baseURL, proxyPattern }); - - other.forEach(item => { - Object.assign(proxy, createProxyItem(item)); - }); - - return proxy; -} - -function createProxyItem(item: App.Service.ServiceConfigItem) { - const proxy: Record = {}; - - proxy[item.proxyPattern] = { - target: item.baseURL, - changeOrigin: true, - rewrite: path => path.replace(new RegExp(`^${item.proxyPattern}`), '') - }; - - return proxy; -} diff --git a/build/plugins/index.ts b/build/plugins/index.ts deleted file mode 100644 index 4934c073..00000000 --- a/build/plugins/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { PluginOption } from 'vite'; -import vue from '@vitejs/plugin-vue'; -import vueJsx from '@vitejs/plugin-vue-jsx'; -import VueDevtools from 'vite-plugin-vue-devtools'; -import progress from 'vite-plugin-progress'; -import { setupElegantRouter } from './router'; -import { setupUnocss } from './unocss'; -import { setupUnplugin } from './unplugin'; - -import { lazyImport, VxeResolver } from 'vite-plugin-lazy-import' - - -export function setupVitePlugins(viteEnv: Env.ImportMeta) { - const plugins: PluginOption = [ - vue({ - script: { - defineModel: true - } - }), - vueJsx(), - VueDevtools(), - setupElegantRouter(), - setupUnocss(viteEnv), - ...setupUnplugin(viteEnv), - progress(), - // lazyImport({ - // resolvers: [ - // VxeResolver({ - // libraryName: 'vxe-table' - // }), - // VxeResolver({ - // libraryName: 'vxe-pc-ui' - // }) - // ] - // }) - ]; - - return plugins; -} diff --git a/build/plugins/router.ts b/build/plugins/router.ts deleted file mode 100644 index 8f5a77e8..00000000 --- a/build/plugins/router.ts +++ /dev/null @@ -1,98 +0,0 @@ -import type { RouteMeta } from 'vue-router' -import ElegantVueRouter from '@elegant-router/vue/vite' -import type { RouteKey } from '@elegant-router/types' - -function generateEditPath(key) { - const editSuffix = '_edit'; - - if (key.includes(editSuffix)) { - const baseKey = key.replace(editSuffix, ''); - const path = `/${baseKey.replace(/_/g, '/')}/edit/:id?`; - return path; - } - - return null; // 如果key不包含_edit,返回null或你希望的默认值 -} - -export function setupElegantRouter() { - return ElegantVueRouter({ - layouts: { - base: 'src/layouts/base-layout/index.vue', - blank: 'src/layouts/blank-layout/index.vue', - }, - customRoutes: { - names: [ - 'exception_403', - 'exception_404', - 'exception_500', - 'document_project', - 'document_project-link', - 'document_vue', - 'document_vite', - 'document_unocss', - 'document_naive', - 'document_antd', - ], - }, - - routePathTransformer(routeName, routePath) { - const key = routeName as RouteKey - - if (key === 'login') { - const modules: UnionKey.LoginModule[] = ['pwd-login', 'code-login', 'register', 'reset-pwd', 'bind-wechat'] - - const moduleReg = modules.join('|') - - return `/login/:module(${moduleReg})?` - } - - - let newPath = generateEditPath(key) - if (newPath) { - return newPath - } - - // if (key === 'meeting_edit') { - // return '/meeting/edit/:id?' - // } - - // if (key === 'contract_approval_edit') { - // return '/contract/approval/edit/:id?' - // } - - // if (key === 'contract_business_edit') { - // return '/contract/business/edit/:id?' - // } - - // if (key === 'contract_declaration_edit') { - // return '/contract/declaration/edit/:id?' - // } - - // if (key === 'contract_archive_edit') { - // return '/contract/archive/edit/:id?' - // } - - // if (key === 'contract_company_edit') { - // return '/contract/company/edit/:id?' - // } - - return routePath - }, - onRouteMetaGen(routeName) { - const key = routeName as RouteKey - - const constantRoutes: RouteKey[] = ['login', '403', '404', '500'] - - const meta: Partial = { - title: key, - // i18nKey: `route.${key}` as App.I18n.I18nKey - } - - if (constantRoutes.includes(key)) { - meta.constant = true - } - - return meta - }, - }) -} diff --git a/build/plugins/unocss.ts b/build/plugins/unocss.ts deleted file mode 100644 index 1694d0e8..00000000 --- a/build/plugins/unocss.ts +++ /dev/null @@ -1,32 +0,0 @@ -import process from 'node:process'; -import path from 'node:path'; -import unocss from '@unocss/vite'; -import presetIcons from '@unocss/preset-icons'; -import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders'; - -export function setupUnocss(viteEnv: Env.ImportMeta) { - const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = viteEnv; - - const localIconPath = path.join(process.cwd(), 'src/assets/svg-icon'); - - /** The name of the local icon collection */ - const collectionName = VITE_ICON_LOCAL_PREFIX.replace(`${VITE_ICON_PREFIX}-`, ''); - - return unocss({ - presets: [ - presetIcons({ - // prefix: `${VITE_ICON_PREFIX}-`, - scale: 1.2, - extraProperties: { - display: 'inline-block' - }, - collections: { - [collectionName]: FileSystemIconLoader(localIconPath, svg => - svg.replace(/^ - svg.replace(/^` blocks in Vue - * By default uses Prettier - */ - css: true, - /** - * Format HTML files - * By default uses Prettier - */ - html: true, - /** - * Format Markdown files - * Supports Prettier and dprint - * By default uses Prettier - */ - markdown: 'prettier', - }, - }, - - // From the second arguments they are ESLint Flat Configs - // you can have multiple configs - { - files: ['**/*.ts'], - rules: {}, - }, - { - rules: { - 'no-console': 'off', - 'style/semi': ['error', 'never'], - }, - }, -) diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..b29b567f --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,5 @@ +// @ts-check + +import { defineConfig } from '@vben/eslint-config'; + +export default defineConfig(); diff --git a/index.html b/index.html deleted file mode 100644 index fbe9f20f..00000000 --- a/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - %VITE_APP_TITLE% - - - -
- - - - - diff --git a/internal/lint-configs/commitlint-config/index.mjs b/internal/lint-configs/commitlint-config/index.mjs new file mode 100644 index 00000000..3d854399 --- /dev/null +++ b/internal/lint-configs/commitlint-config/index.mjs @@ -0,0 +1,153 @@ +import { execSync } from 'node:child_process'; + +import { getPackagesSync } from '@vben/node-utils'; + +const { packages } = getPackagesSync(); + +const allowedScopes = [ + ...packages.map((pkg) => pkg.packageJson.name), + 'project', + 'style', + 'lint', + 'ci', + 'dev', + 'deploy', + 'other', +]; + +// precomputed scope +const scopeComplete = execSync('git status --porcelain || true') + .toString() + .trim() + .split('\n') + .find((r) => ~r.indexOf('M src')) + ?.replace(/(\/)/g, '%%') + ?.match(/src%%((\w|-)*)/)?.[1] + ?.replace(/s$/, ''); + +/** + * @type {import('cz-git').UserConfig} + */ +const userConfig = { + extends: ['@commitlint/config-conventional'], + plugins: ['commitlint-plugin-function-rules'], + prompt: { + /** @use `pnpm commit :f` */ + alias: { + b: 'build: bump dependencies', + c: 'chore: update config', + f: 'docs: fix typos', + r: 'docs: update README', + s: 'style: update code format', + }, + allowCustomIssuePrefixs: false, + // scopes: [...scopes, 'mock'], + allowEmptyIssuePrefixs: false, + customScopesAlign: scopeComplete ? 'bottom' : 'top', + defaultScope: scopeComplete, + // English + typesAppend: [ + { name: 'workflow: workflow improvements', value: 'workflow' }, + { name: 'types: type definition file changes', value: 'types' }, + ], + + // 中英文对照版 + // messages: { + // type: '选择你要提交的类型 :', + // scope: '选择一个提交范围 (可选):', + // customScope: '请输入自定义的提交范围 :', + // subject: '填写简短精炼的变更描述 :\n', + // body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n', + // breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n', + // footerPrefixsSelect: '选择关联issue前缀 (可选):', + // customFooterPrefixs: '输入自定义issue前缀 :', + // footer: '列举关联issue (可选) 例如: #31, #I3244 :\n', + // confirmCommit: '是否提交或修改commit ?', + // }, + // types: [ + // { value: 'feat', name: 'feat: 新增功能' }, + // { value: 'fix', name: 'fix: 修复缺陷' }, + // { value: 'docs', name: 'docs: 文档变更' }, + // { value: 'style', name: 'style: 代码格式' }, + // { value: 'refactor', name: 'refactor: 代码重构' }, + // { value: 'perf', name: 'perf: 性能优化' }, + // { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' }, + // { value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' }, + // { value: 'ci', name: 'ci: 修改 CI 配置、脚本' }, + // { value: 'revert', name: 'revert: 回滚 commit' }, + // { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' }, + // { value: 'wip', name: 'wip: 正在开发中' }, + // { value: 'workflow', name: 'workflow: 工作流程改进' }, + // { value: 'types', name: 'types: 类型定义文件修改' }, + // ], + // emptyScopesAlias: 'empty: 不填写', + // customScopesAlias: 'custom: 自定义', + }, + rules: { + /** + * type[scope]: [function] description + * + * ^^^^^^^^^^^^^^ empty line. + * - Something here + */ + 'body-leading-blank': [2, 'always'], + /** + * type[scope]: [function] description + * + * - something here + * + * ^^^^^^^^^^^^^^ + */ + 'footer-leading-blank': [1, 'always'], + /** + * type[scope]: [function] description + * ^^^^^ + */ + 'function-rules/scope-enum': [ + 2, // level: error + 'always', + (parsed) => { + if (!parsed.scope || allowedScopes.includes(parsed.scope)) { + return [true]; + } + + return [false, `scope must be one of ${allowedScopes.join(', ')}`]; + }, + ], + /** + * type[scope]: [function] description [No more than 108 characters] + * ^^^^^ + */ + 'header-max-length': [2, 'always', 108], + + 'scope-enum': [0], + 'subject-case': [0], + 'subject-empty': [2, 'never'], + 'type-empty': [2, 'never'], + /** + * type[scope]: [function] description + * ^^^^ + */ + 'type-enum': [ + 2, + 'always', + [ + 'feat', + 'fix', + 'perf', + 'style', + 'docs', + 'test', + 'refactor', + 'build', + 'ci', + 'chore', + 'revert', + 'types', + 'release', + ], + ], + }, +}; + +export default userConfig; diff --git a/internal/lint-configs/commitlint-config/package.json b/internal/lint-configs/commitlint-config/package.json new file mode 100644 index 00000000..92b98e0d --- /dev/null +++ b/internal/lint-configs/commitlint-config/package.json @@ -0,0 +1,33 @@ +{ + "name": "@vben/commitlint-config", + "version": "5.1.2", + "private": true, + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "internal/lint-configs/commitlint-config" + }, + "license": "MIT", + "type": "module", + "files": [ + "dist" + ], + "main": "./index.mjs", + "module": "./index.mjs", + "exports": { + ".": { + "import": "./index.mjs", + "default": "./index.mjs" + } + }, + "dependencies": { + "@commitlint/cli": "^19.4.1", + "@commitlint/config-conventional": "^19.4.1", + "@vben/node-utils": "workspace:*", + "commitlint-plugin-function-rules": "^4.0.0", + "cz-git": "^1.9.4", + "czg": "^1.9.4" + } +} diff --git a/internal/lint-configs/eslint-config/build.config.ts b/internal/lint-configs/eslint-config/build.config.ts new file mode 100644 index 00000000..97e572c5 --- /dev/null +++ b/internal/lint-configs/eslint-config/build.config.ts @@ -0,0 +1,7 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + declaration: true, + entries: ['src/index'], +}); diff --git a/internal/lint-configs/eslint-config/package.json b/internal/lint-configs/eslint-config/package.json new file mode 100644 index 00000000..fda7dc43 --- /dev/null +++ b/internal/lint-configs/eslint-config/package.json @@ -0,0 +1,57 @@ +{ + "name": "@vben/eslint-config", + "version": "5.0.0", + "private": true, + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "internal/lint-configs/eslint-config" + }, + "license": "MIT", + "type": "module", + "scripts": { + "stub": "pnpm unbuild --stub" + }, + "files": [ + "dist" + ], + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs" + } + }, + "dependencies": { + "eslint-config-turbo": "^2.1.0", + "eslint-plugin-command": "^0.2.3", + "eslint-plugin-import-x": "^4.1.0" + }, + "devDependencies": { + "@eslint/js": "^9.9.1", + "@types/eslint": "^9.6.1", + "@typescript-eslint/eslint-plugin": "^8.3.0", + "@typescript-eslint/parser": "^8.3.0", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-jsdoc": "^50.2.2", + "eslint-plugin-jsonc": "^2.16.0", + "eslint-plugin-n": "^17.10.2", + "eslint-plugin-no-only-tests": "^3.3.0", + "eslint-plugin-perfectionist": "^3.3.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-regexp": "^2.6.0", + "eslint-plugin-unicorn": "^55.0.0", + "eslint-plugin-unused-imports": "^4.1.3", + "eslint-plugin-vitest": "^0.5.4", + "eslint-plugin-vue": "^9.27.0", + "globals": "^15.9.0", + "jsonc-eslint-parser": "^2.4.0", + "vue-eslint-parser": "^9.4.3" + } +} diff --git a/internal/lint-configs/eslint-config/src/configs/command.ts b/internal/lint-configs/eslint-config/src/configs/command.ts new file mode 100644 index 00000000..67651b23 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/command.ts @@ -0,0 +1,10 @@ +import createCommand from 'eslint-plugin-command/config'; + +export async function command() { + return [ + { + // @ts-expect-error - no types + ...createCommand(), + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/comments.ts b/internal/lint-configs/eslint-config/src/configs/comments.ts new file mode 100644 index 00000000..77ccd5dd --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/comments.ts @@ -0,0 +1,24 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function comments(): Promise { + const [pluginComments] = await Promise.all([ + // @ts-expect-error - no types + interopDefault(import('eslint-plugin-eslint-comments')), + ] as const); + + return [ + { + plugins: { + 'eslint-comments': pluginComments, + }, + rules: { + 'eslint-comments/no-aggregating-enable': 'error', + 'eslint-comments/no-duplicate-disable': 'error', + 'eslint-comments/no-unlimited-disable': 'error', + 'eslint-comments/no-unused-enable': 'error', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/disableds.ts b/internal/lint-configs/eslint-config/src/configs/disableds.ts new file mode 100644 index 00000000..152b84ca --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/disableds.ts @@ -0,0 +1,28 @@ +import type { Linter } from 'eslint'; + +export async function disableds(): Promise { + return [ + { + files: ['**/__tests__/**/*.?([cm])[jt]s?(x)'], + name: 'disables/test', + rules: { + '@typescript-eslint/ban-ts-comment': 'off', + 'no-console': 'off', + }, + }, + { + files: ['**/*.d.ts'], + name: 'disables/dts', + rules: { + '@typescript-eslint/triple-slash-reference': 'off', + }, + }, + { + files: ['**/*.js', '**/*.mjs', '**/*.cjs'], + name: 'disables/js', + rules: { + '@typescript-eslint/explicit-module-boundary-types': 'off', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/ignores.ts b/internal/lint-configs/eslint-config/src/configs/ignores.ts new file mode 100644 index 00000000..136c956d --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/ignores.ts @@ -0,0 +1,52 @@ +import type { Linter } from 'eslint'; + +export async function ignores(): Promise { + return [ + { + ignores: [ + '**/node_modules', + '**/dist', + '**/dist-*', + '**/*-dist', + '**/.husky', + '**/.nitro', + '**/.output', + '**/Dockerfile', + '**/package-lock.json', + '**/yarn.lock', + '**/pnpm-lock.yaml', + '**/bun.lockb', + '**/output', + '**/coverage', + '**/temp', + '**/.temp', + '**/tmp', + '**/.tmp', + '**/.history', + '**/.turbo', + '**/.nuxt', + '**/.next', + '**/.vercel', + '**/.changeset', + '**/.idea', + '**/.cache', + '**/.output', + '**/.vite-inspect', + + '**/CHANGELOG*.md', + '**/*.min.*', + '**/LICENSE*', + '**/__snapshots__', + '**/*.snap', + '**/fixtures/**', + '**/.vitepress/cache/**', + '**/auto-import?(s).d.ts', + '**/components.d.ts', + '**/vite.config.mts.*', + '**/*.sh', + '**/*.ttf', + '**/*.woff', + ], + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/import.ts b/internal/lint-configs/eslint-config/src/configs/import.ts new file mode 100644 index 00000000..67a08fea --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/import.ts @@ -0,0 +1,24 @@ +import type { Linter } from 'eslint'; + +import * as pluginImport from 'eslint-plugin-import-x'; + +export async function importPluginConfig(): Promise { + return [ + { + plugins: { + // @ts-expect-error - This is a dynamic import + import: pluginImport, + }, + rules: { + 'import/first': 'error', + 'import/newline-after-import': 'error', + 'import/no-duplicates': 'error', + 'import/no-mutable-exports': 'error', + 'import/no-named-default': 'error', + 'import/no-self-import': 'error', + 'import/no-unresolved': 'off', + 'import/no-webpack-loader-syntax': 'error', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/index.ts b/internal/lint-configs/eslint-config/src/configs/index.ts new file mode 100644 index 00000000..c0284efb --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/index.ts @@ -0,0 +1,17 @@ +export * from './command'; +export * from './comments'; +export * from './disableds'; +export * from './ignores'; +export * from './import'; +export * from './javascript'; +export * from './jsdoc'; +export * from './jsonc'; +export * from './node'; +export * from './perfectionist'; +export * from './prettier'; +export * from './regexp'; +export * from './test'; +export * from './turbo'; +export * from './typescript'; +export * from './unicorn'; +export * from './vue'; diff --git a/internal/lint-configs/eslint-config/src/configs/javascript.ts b/internal/lint-configs/eslint-config/src/configs/javascript.ts new file mode 100644 index 00000000..cae21b81 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/javascript.ts @@ -0,0 +1,242 @@ +import type { Linter } from 'eslint'; + +// @ts-expect-error - no types +import js from '@eslint/js'; +import pluginUnusedImports from 'eslint-plugin-unused-imports'; +import globals from 'globals'; + +export async function javascript(): Promise { + return [ + { + languageOptions: { + ecmaVersion: 'latest', + globals: { + ...globals.browser, + ...globals.es2021, + ...globals.node, + document: 'readonly', + navigator: 'readonly', + window: 'readonly', + }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 'latest', + sourceType: 'module', + }, + sourceType: 'module', + }, + linterOptions: { + reportUnusedDisableDirectives: true, + }, + plugins: { + 'unused-imports': pluginUnusedImports, + }, + rules: { + ...js.configs.recommended.rules, + 'accessor-pairs': [ + 'error', + { enforceForClassMembers: true, setWithoutGet: true }, + ], + 'array-callback-return': 'error', + 'block-scoped-var': 'error', + 'constructor-super': 'error', + 'default-case-last': 'error', + 'dot-notation': ['error', { allowKeywords: true }], + eqeqeq: ['error', 'always'], + 'keyword-spacing': 'off', + + 'new-cap': [ + 'error', + { capIsNew: false, newIsCap: true, properties: true }, + ], + 'no-alert': 'error', + 'no-array-constructor': 'error', + 'no-async-promise-executor': 'error', + 'no-caller': 'error', + 'no-case-declarations': 'error', + 'no-class-assign': 'error', + 'no-compare-neg-zero': 'error', + 'no-cond-assign': ['error', 'always'], + 'no-console': ['error', { allow: ['warn', 'error'] }], + 'no-const-assign': 'error', + 'no-control-regex': 'error', + 'no-debugger': 'error', + 'no-delete-var': 'error', + 'no-dupe-args': 'error', + 'no-dupe-class-members': 'error', + 'no-dupe-keys': 'error', + 'no-duplicate-case': 'error', + 'no-empty': ['error', { allowEmptyCatch: true }], + 'no-empty-character-class': 'error', + 'no-empty-function': 'off', + 'no-empty-pattern': 'error', + 'no-eval': 'error', + 'no-ex-assign': 'error', + 'no-extend-native': 'error', + 'no-extra-bind': 'error', + 'no-extra-boolean-cast': 'error', + 'no-fallthrough': 'error', + 'no-func-assign': 'error', + 'no-global-assign': 'error', + 'no-implied-eval': 'error', + 'no-import-assign': 'error', + 'no-invalid-regexp': 'error', + 'no-irregular-whitespace': 'error', + 'no-iterator': 'error', + 'no-labels': ['error', { allowLoop: false, allowSwitch: false }], + 'no-lone-blocks': 'error', + 'no-loss-of-precision': 'error', + 'no-misleading-character-class': 'error', + 'no-multi-str': 'error', + 'no-new': 'error', + 'no-new-func': 'error', + 'no-new-object': 'error', + 'no-new-symbol': 'error', + 'no-new-wrappers': 'error', + 'no-obj-calls': 'error', + 'no-octal': 'error', + 'no-octal-escape': 'error', + 'no-proto': 'error', + 'no-prototype-builtins': 'error', + 'no-redeclare': ['error', { builtinGlobals: false }], + 'no-regex-spaces': 'error', + 'no-restricted-globals': [ + 'error', + { message: 'Use `globalThis` instead.', name: 'global' }, + { message: 'Use `globalThis` instead.', name: 'self' }, + ], + 'no-restricted-properties': [ + 'error', + { + message: + 'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.', + property: '__proto__', + }, + { + message: 'Use `Object.defineProperty` instead.', + property: '__defineGetter__', + }, + { + message: 'Use `Object.defineProperty` instead.', + property: '__defineSetter__', + }, + { + message: 'Use `Object.getOwnPropertyDescriptor` instead.', + property: '__lookupGetter__', + }, + { + message: 'Use `Object.getOwnPropertyDescriptor` instead.', + property: '__lookupSetter__', + }, + ], + 'no-restricted-syntax': [ + 'error', + 'DebuggerStatement', + 'LabeledStatement', + 'WithStatement', + 'TSEnumDeclaration[const=true]', + 'TSExportAssignment', + ], + 'no-self-assign': ['error', { props: true }], + 'no-self-compare': 'error', + 'no-sequences': 'error', + 'no-shadow-restricted-names': 'error', + 'no-sparse-arrays': 'error', + 'no-template-curly-in-string': 'error', + 'no-this-before-super': 'error', + 'no-throw-literal': 'error', + 'no-undef': 'error', + 'no-undef-init': 'error', + 'no-unexpected-multiline': 'error', + 'no-unmodified-loop-condition': 'error', + 'no-unneeded-ternary': ['error', { defaultAssignment: false }], + 'no-unreachable': 'error', + 'no-unreachable-loop': 'error', + 'no-unsafe-finally': 'error', + 'no-unsafe-negation': 'error', + 'no-unused-expressions': [ + 'error', + { + allowShortCircuit: true, + allowTaggedTemplates: true, + allowTernary: true, + }, + ], + 'no-unused-vars': [ + 'error', + { + args: 'none', + caughtErrors: 'none', + ignoreRestSiblings: true, + vars: 'all', + }, + ], + 'no-use-before-define': [ + 'error', + { classes: false, functions: false, variables: true }, + ], + 'no-useless-backreference': 'error', + 'no-useless-call': 'error', + 'no-useless-catch': 'error', + 'no-useless-computed-key': 'error', + 'no-useless-constructor': 'error', + 'no-useless-rename': 'error', + 'no-useless-return': 'error', + 'no-var': 'error', + 'no-with': 'error', + 'object-shorthand': [ + 'error', + 'always', + { avoidQuotes: true, ignoreConstructors: false }, + ], + 'one-var': ['error', { initialized: 'never' }], + 'prefer-arrow-callback': [ + 'error', + { + allowNamedFunctions: false, + allowUnboundThis: true, + }, + ], + 'prefer-const': [ + 'error', + { + destructuring: 'all', + ignoreReadBeforeAssign: true, + }, + ], + 'prefer-exponentiation-operator': 'error', + + 'prefer-promise-reject-errors': 'error', + 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }], + 'prefer-rest-params': 'error', + 'prefer-spread': 'error', + 'prefer-template': 'error', + 'space-before-function-paren': 'off', + 'spaced-comment': 'error', + 'symbol-description': 'error', + 'unicode-bom': ['error', 'never'], + + 'unused-imports/no-unused-imports': 'error', + 'unused-imports/no-unused-vars': [ + 'error', + { + args: 'after-used', + argsIgnorePattern: '^_', + vars: 'all', + varsIgnorePattern: '^_', + }, + ], + 'use-isnan': [ + 'error', + { enforceForIndexOf: true, enforceForSwitchCase: true }, + ], + 'valid-typeof': ['error', { requireStringLiterals: true }], + + 'vars-on-top': 'error', + yoda: ['error', 'never'], + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/jsdoc.ts b/internal/lint-configs/eslint-config/src/configs/jsdoc.ts new file mode 100644 index 00000000..13681976 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/jsdoc.ts @@ -0,0 +1,34 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function jsdoc(): Promise { + const [pluginJsdoc] = await Promise.all([ + interopDefault(import('eslint-plugin-jsdoc')), + ] as const); + + return [ + { + plugins: { + jsdoc: pluginJsdoc, + }, + rules: { + 'jsdoc/check-access': 'warn', + 'jsdoc/check-param-names': 'warn', + 'jsdoc/check-property-names': 'warn', + 'jsdoc/check-types': 'warn', + 'jsdoc/empty-tags': 'warn', + 'jsdoc/implements-on-classes': 'warn', + 'jsdoc/no-defaults': 'warn', + 'jsdoc/no-multi-asterisks': 'warn', + 'jsdoc/require-param-name': 'warn', + 'jsdoc/require-property': 'warn', + 'jsdoc/require-property-description': 'warn', + 'jsdoc/require-property-name': 'warn', + 'jsdoc/require-returns-check': 'warn', + 'jsdoc/require-returns-description': 'warn', + 'jsdoc/require-yields-check': 'warn', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/jsonc.ts b/internal/lint-configs/eslint-config/src/configs/jsonc.ts new file mode 100644 index 00000000..4072e4cd --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/jsonc.ts @@ -0,0 +1,258 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function jsonc(): Promise { + const [pluginJsonc, parserJsonc] = await Promise.all([ + interopDefault(import('eslint-plugin-jsonc')), + interopDefault(import('jsonc-eslint-parser')), + ] as const); + + return [ + { + files: ['**/*.json', '**/*.json5', '**/*.jsonc', '*.code-workspace'], + languageOptions: { + parser: parserJsonc as any, + }, + plugins: { + jsonc: pluginJsonc as any, + }, + rules: { + 'jsonc/no-bigint-literals': 'error', + 'jsonc/no-binary-expression': 'error', + 'jsonc/no-binary-numeric-literals': 'error', + 'jsonc/no-dupe-keys': 'error', + 'jsonc/no-escape-sequence-in-identifier': 'error', + 'jsonc/no-floating-decimal': 'error', + 'jsonc/no-hexadecimal-numeric-literals': 'error', + 'jsonc/no-infinity': 'error', + 'jsonc/no-multi-str': 'error', + 'jsonc/no-nan': 'error', + 'jsonc/no-number-props': 'error', + 'jsonc/no-numeric-separators': 'error', + 'jsonc/no-octal': 'error', + 'jsonc/no-octal-escape': 'error', + 'jsonc/no-octal-numeric-literals': 'error', + 'jsonc/no-parenthesized': 'error', + 'jsonc/no-plus-sign': 'error', + 'jsonc/no-regexp-literals': 'error', + 'jsonc/no-sparse-arrays': 'error', + 'jsonc/no-template-literals': 'error', + 'jsonc/no-undefined-value': 'error', + 'jsonc/no-unicode-codepoint-escapes': 'error', + 'jsonc/no-useless-escape': 'error', + 'jsonc/space-unary-ops': 'error', + 'jsonc/valid-json-number': 'error', + 'jsonc/vue-custom-block/no-parsing-error': 'error', + }, + }, + sortTsconfig(), + sortPackageJson(), + ]; +} + +function sortPackageJson(): Linter.Config { + return { + files: ['**/package.json'], + rules: { + 'jsonc/sort-array-values': [ + 'error', + { + order: { type: 'asc' }, + pathPattern: '^files$|^pnpm.neverBuiltDependencies$', + }, + ], + 'jsonc/sort-keys': [ + 'error', + { + order: [ + 'name', + 'version', + 'description', + 'private', + 'keywords', + 'homepage', + 'bugs', + 'repository', + 'license', + 'author', + 'contributors', + 'categories', + 'funding', + 'type', + 'scripts', + 'files', + 'sideEffects', + 'bin', + 'main', + 'module', + 'unpkg', + 'jsdelivr', + 'types', + 'typesVersions', + 'imports', + 'exports', + 'publishConfig', + 'icon', + 'activationEvents', + 'contributes', + 'peerDependencies', + 'peerDependenciesMeta', + 'dependencies', + 'optionalDependencies', + 'devDependencies', + 'engines', + 'packageManager', + 'pnpm', + 'overrides', + 'resolutions', + 'husky', + 'simple-git-hooks', + 'lint-staged', + 'eslintConfig', + ], + pathPattern: '^$', + }, + { + order: { type: 'asc' }, + pathPattern: '^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$', + }, + { + order: { type: 'asc' }, + pathPattern: '^(?:resolutions|overrides|pnpm.overrides)$', + }, + { + order: ['types', 'import', 'require', 'default'], + pathPattern: '^exports.*$', + }, + ], + }, + }; +} + +function sortTsconfig(): Linter.Config { + return { + files: [ + '**/tsconfig.json', + '**/tsconfig.*.json', + 'internal/tsconfig/*.json', + ], + rules: { + 'jsonc/sort-keys': [ + 'error', + { + order: [ + 'extends', + 'compilerOptions', + 'references', + 'files', + 'include', + 'exclude', + ], + pathPattern: '^$', + }, + { + order: [ + /* Projects */ + 'incremental', + 'composite', + 'tsBuildInfoFile', + 'disableSourceOfProjectReferenceRedirect', + 'disableSolutionSearching', + 'disableReferencedProjectLoad', + /* Language and Environment */ + 'target', + 'jsx', + 'jsxFactory', + 'jsxFragmentFactory', + 'jsxImportSource', + 'lib', + 'moduleDetection', + 'noLib', + 'reactNamespace', + 'useDefineForClassFields', + 'emitDecoratorMetadata', + 'experimentalDecorators', + /* Modules */ + 'baseUrl', + 'rootDir', + 'rootDirs', + 'customConditions', + 'module', + 'moduleResolution', + 'moduleSuffixes', + 'noResolve', + 'paths', + 'resolveJsonModule', + 'resolvePackageJsonExports', + 'resolvePackageJsonImports', + 'typeRoots', + 'types', + 'allowArbitraryExtensions', + 'allowImportingTsExtensions', + 'allowUmdGlobalAccess', + /* JavaScript Support */ + 'allowJs', + 'checkJs', + 'maxNodeModuleJsDepth', + /* Type Checking */ + 'strict', + 'strictBindCallApply', + 'strictFunctionTypes', + 'strictNullChecks', + 'strictPropertyInitialization', + 'allowUnreachableCode', + 'allowUnusedLabels', + 'alwaysStrict', + 'exactOptionalPropertyTypes', + 'noFallthroughCasesInSwitch', + 'noImplicitAny', + 'noImplicitOverride', + 'noImplicitReturns', + 'noImplicitThis', + 'noPropertyAccessFromIndexSignature', + 'noUncheckedIndexedAccess', + 'noUnusedLocals', + 'noUnusedParameters', + 'useUnknownInCatchVariables', + /* Emit */ + 'declaration', + 'declarationDir', + 'declarationMap', + 'downlevelIteration', + 'emitBOM', + 'emitDeclarationOnly', + 'importHelpers', + 'importsNotUsedAsValues', + 'inlineSourceMap', + 'inlineSources', + 'mapRoot', + 'newLine', + 'noEmit', + 'noEmitHelpers', + 'noEmitOnError', + 'outDir', + 'outFile', + 'preserveConstEnums', + 'preserveValueImports', + 'removeComments', + 'sourceMap', + 'sourceRoot', + 'stripInternal', + /* Interop Constraints */ + 'allowSyntheticDefaultImports', + 'esModuleInterop', + 'forceConsistentCasingInFileNames', + 'isolatedModules', + 'preserveSymlinks', + 'verbatimModuleSyntax', + /* Completeness */ + 'skipDefaultLibCheck', + 'skipLibCheck', + ], + pathPattern: '^compilerOptions$', + }, + ], + }, + }; +} diff --git a/internal/lint-configs/eslint-config/src/configs/node.ts b/internal/lint-configs/eslint-config/src/configs/node.ts new file mode 100644 index 00000000..56426d11 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/node.ts @@ -0,0 +1,56 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function node(): Promise { + const pluginNode = await interopDefault(import('eslint-plugin-n')); + + return [ + { + plugins: { + n: pluginNode, + }, + rules: { + 'n/handle-callback-err': ['error', '^(err|error)$'], + 'n/no-deprecated-api': 'error', + 'n/no-exports-assign': 'error', + 'n/no-extraneous-import': [ + 'error', + { + allowModules: [ + 'unbuild', + '@vben/vite-config', + 'vitest', + 'vite', + '@vue/test-utils', + '@vben/tailwind-config', + ], + }, + ], + 'n/no-new-require': 'error', + 'n/no-path-concat': 'error', + // 'n/no-unpublished-import': 'off', + 'n/no-unsupported-features/es-syntax': [ + 'error', + { + ignores: [], + version: '>=18.0.0', + }, + ], + 'n/prefer-global/buffer': ['error', 'never'], + // 'n/no-missing-import': 'off', + 'n/prefer-global/process': ['error', 'never'], + 'n/process-exit-as-throw': 'error', + }, + }, + { + files: [ + 'scripts/**/*.?([cm])[jt]s?(x)', + 'internal/**/*.?([cm])[jt]s?(x)', + ], + rules: { + 'n/prefer-global/process': 'off', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/perfectionist.ts b/internal/lint-configs/eslint-config/src/configs/perfectionist.ts new file mode 100644 index 00000000..51a2249b --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/perfectionist.ts @@ -0,0 +1,112 @@ +import type { Linter } from 'eslint'; + +import perfectionistPlugin from 'eslint-plugin-perfectionist'; + +export async function perfectionist(): Promise { + return [ + perfectionistPlugin.configs['recommended-natural'], + { + rules: { + 'perfectionist/sort-exports': [ + 'error', + { + order: 'asc', + type: 'natural', + }, + ], + 'perfectionist/sort-imports': [ + 'error', + { + customGroups: { + type: { + vben: 'vben', + vue: 'vue', + }, + value: { + vben: ['@vben*', '@vben/**/**', '@vben-core/**/**'], + vue: ['vue', 'vue-*', '@vue*'], + }, + }, + groups: [ + ['external-type', 'builtin-type', 'type'], + ['parent-type', 'sibling-type', 'index-type'], + ['internal-type'], + 'builtin', + 'vue', + 'vben', + 'external', + 'internal', + ['parent', 'sibling', 'index'], + 'side-effect', + 'side-effect-style', + 'style', + 'object', + 'unknown', + ], + internalPattern: ['#*', '#*/**'], + newlinesBetween: 'always', + order: 'asc', + type: 'natural', + }, + ], + 'perfectionist/sort-named-exports': [ + 'error', + { + order: 'asc', + type: 'natural', + }, + ], + 'perfectionist/sort-objects': [ + 'error', + { + customGroups: { + items: 'items', + list: 'list', + children: 'children', + }, + groups: ['unknown', 'items', 'list', 'children'], + ignorePattern: ['children'], + order: 'asc', + partitionByComment: 'Part:**', + type: 'alphabetical', + }, + ], + 'perfectionist/sort-vue-attributes': [ + 'error', + { + // Based on: https://vuejs.org/style-guide/rules-recommended.html#element-attribute-order + customGroups: { + /* eslint-disable perfectionist/sort-objects */ + DEFINITION: '*(is|:is|v-is)', + LIST_RENDERING: 'v-for', + CONDITIONALS: 'v-*(else-if|if|else|show|cloak)', + RENDER_MODIFIERS: 'v-*(pre|once)', + GLOBAL: '*(:id|id)', + UNIQUE: '*(ref|key|:ref|:key)', + SLOT: '*(v-slot|slot)', + TWO_WAY_BINDING: '*(v-model|v-model:*)', + // OTHER_DIRECTIVES e.g. 'v-custom-directive' + EVENTS: '*(v-on|@*)', + CONTENT: 'v-*(html|text)', + /* eslint-enable perfectionist/sort-objects */ + }, + groups: [ + 'DEFINITION', + 'LIST_RENDERING', + 'CONDITIONALS', + 'RENDER_MODIFIERS', + 'GLOBAL', + 'UNIQUE', + 'SLOT', + 'TWO_WAY_BINDING', + 'unknown', + 'EVENTS', + 'CONTENT', + ], + type: 'natural', + }, + ], + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/prettier.ts b/internal/lint-configs/eslint-config/src/configs/prettier.ts new file mode 100644 index 00000000..3cd7af40 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/prettier.ts @@ -0,0 +1,19 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function prettier(): Promise { + const [pluginPrettier] = await Promise.all([ + interopDefault(import('eslint-plugin-prettier')), + ] as const); + return [ + { + plugins: { + prettier: pluginPrettier, + }, + rules: { + 'prettier/prettier': 'error', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/regexp.ts b/internal/lint-configs/eslint-config/src/configs/regexp.ts new file mode 100644 index 00000000..c0f4c9f4 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/regexp.ts @@ -0,0 +1,20 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function regexp(): Promise { + const [pluginRegexp] = await Promise.all([ + interopDefault(import('eslint-plugin-regexp')), + ] as const); + + return [ + { + plugins: { + regexp: pluginRegexp, + }, + rules: { + ...pluginRegexp.configs.recommended.rules, + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/test.ts b/internal/lint-configs/eslint-config/src/configs/test.ts new file mode 100644 index 00000000..ddfde2b8 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/test.ts @@ -0,0 +1,45 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function test(): Promise { + const [pluginTest, pluginNoOnlyTests] = await Promise.all([ + interopDefault(import('eslint-plugin-vitest')), + // @ts-expect-error - no types + interopDefault(import('eslint-plugin-no-only-tests')), + ] as const); + + return [ + { + files: [ + `**/__tests__/**/*.?([cm])[jt]s?(x)`, + `**/*.spec.?([cm])[jt]s?(x)`, + `**/*.test.?([cm])[jt]s?(x)`, + `**/*.bench.?([cm])[jt]s?(x)`, + `**/*.benchmark.?([cm])[jt]s?(x)`, + ], + plugins: { + test: { + ...pluginTest, + rules: { + ...pluginTest.rules, + ...pluginNoOnlyTests.rules, + }, + }, + }, + rules: { + 'no-console': 'off', + 'node/prefer-global/process': 'off', + 'test/consistent-test-it': [ + 'error', + { fn: 'it', withinDescribe: 'it' }, + ], + 'test/no-identical-title': 'error', + 'test/no-import-node-test': 'error', + 'test/no-only-tests': 'error', + 'test/prefer-hooks-in-order': 'error', + 'test/prefer-lowercase-title': 'error', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/turbo.ts b/internal/lint-configs/eslint-config/src/configs/turbo.ts new file mode 100644 index 00000000..9f6bf75b --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/turbo.ts @@ -0,0 +1,18 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function turbo(): Promise { + const [pluginTurbo] = await Promise.all([ + // @ts-expect-error - no types + interopDefault(import('eslint-config-turbo')), + ] as const); + + return [ + { + plugins: { + turbo: pluginTurbo, + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/typescript.ts b/internal/lint-configs/eslint-config/src/configs/typescript.ts new file mode 100644 index 00000000..0ac12df5 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/typescript.ts @@ -0,0 +1,72 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function typescript(): Promise { + const [pluginTs, parserTs] = await Promise.all([ + interopDefault(import('@typescript-eslint/eslint-plugin')), + // @ts-expect-error missing types + interopDefault(import('@typescript-eslint/parser')), + ] as const); + + return [ + { + files: ['**/*.?([cm])[jt]s?(x)'], + languageOptions: { + parser: parserTs, + parserOptions: { + createDefaultProgram: false, + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 'latest', + extraFileExtensions: ['.vue'], + jsxPragma: 'React', + project: './tsconfig.*?.json', + sourceType: 'module', + }, + }, + plugins: { + '@typescript-eslint': pluginTs, + }, + rules: { + ...pluginTs.configs['eslint-recommended'].overrides?.[0].rules, + ...pluginTs.configs.strict.rules, + '@typescript-eslint/ban-ts-comment': [ + 'error', + { + 'ts-check': false, + 'ts-expect-error': 'allow-with-description', + 'ts-ignore': 'allow-with-description', + 'ts-nocheck': 'allow-with-description', + }, + ], + + // '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'], + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-empty-function': [ + 'error', + { + allow: ['arrowFunctions', 'functions', 'methods'], + }, + ], + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/no-unused-expressions': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + }, + ], + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/no-var-requires': 'error', + 'unused-imports/no-unused-vars': 'off', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/unicorn.ts b/internal/lint-configs/eslint-config/src/configs/unicorn.ts new file mode 100644 index 00000000..1788bedf --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/unicorn.ts @@ -0,0 +1,41 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function unicorn(): Promise { + const [pluginUnicorn] = await Promise.all([ + interopDefault(import('eslint-plugin-unicorn')), + ] as const); + + return [ + { + plugins: { + unicorn: pluginUnicorn, + }, + rules: { + ...pluginUnicorn.configs.recommended.rules, + + 'unicorn/consistent-destructuring': 'off', + 'unicorn/consistent-function-scoping': 'off', + 'unicorn/filename-case': 'off', + 'unicorn/import-style': 'off', + 'unicorn/no-array-for-each': 'off', + 'unicorn/no-null': 'off', + 'unicorn/prefer-at': 'off', + 'unicorn/prefer-dom-node-text-content': 'off', + 'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }], + 'unicorn/prefer-top-level-await': 'off', + 'unicorn/prevent-abbreviations': 'off', + }, + }, + { + files: [ + 'scripts/**/*.?([cm])[jt]s?(x)', + 'internal/**/*.?([cm])[jt]s?(x)', + ], + rules: { + 'unicorn/no-process-exit': 'off', + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/configs/vue.ts b/internal/lint-configs/eslint-config/src/configs/vue.ts new file mode 100644 index 00000000..8c45e8ad --- /dev/null +++ b/internal/lint-configs/eslint-config/src/configs/vue.ts @@ -0,0 +1,134 @@ +import type { Linter } from 'eslint'; + +import { interopDefault } from '../util'; + +export async function vue(): Promise { + const [pluginVue, parserVue, parserTs] = await Promise.all([ + // @ts-expect-error missing types + interopDefault(import('eslint-plugin-vue')), + interopDefault(import('vue-eslint-parser')), + // @ts-expect-error missing types + interopDefault(import('@typescript-eslint/parser')), + ] as const); + + return [ + { + files: ['**/*.vue'], + languageOptions: { + parser: parserVue, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + extraFileExtensions: ['.vue'], + parser: parserTs, + sourceType: 'module', + }, + }, + plugins: { + vue: pluginVue, + }, + processor: pluginVue.processors['.vue'], + rules: { + ...pluginVue.configs.base.rules, + ...pluginVue.configs['vue3-essential'].rules, + ...pluginVue.configs['vue3-strongly-recommended'].rules, + ...pluginVue.configs['vue3-recommended'].rules, + + 'vue/attribute-hyphenation': [ + 'error', + 'always', + { + ignore: [], + }, + ], + 'vue/attributes-order': 'off', + 'vue/block-order': [ + 'error', + { + order: ['script', 'template', 'style'], + }, + ], + 'vue/component-name-in-template-casing': ['error', 'PascalCase'], + 'vue/component-options-name-casing': ['error', 'PascalCase'], + 'vue/custom-event-name-casing': ['error', 'camelCase'], + 'vue/define-macros-order': [ + 'error', + { + order: [ + 'defineOptions', + 'defineProps', + 'defineEmits', + 'defineSlots', + ], + }, + ], + 'vue/dot-location': ['error', 'property'], + 'vue/dot-notation': ['error', { allowKeywords: true }], + 'vue/eqeqeq': ['error', 'smart'], + 'vue/html-closing-bracket-newline': 'error', + 'vue/html-indent': 'off', + // 'vue/html-indent': ['error', 2], + 'vue/html-quotes': ['error', 'double'], + 'vue/html-self-closing': [ + 'error', + { + html: { + component: 'always', + normal: 'never', + void: 'always', + }, + math: 'always', + svg: 'always', + }, + ], + 'vue/max-attributes-per-line': 'off', + 'vue/multi-word-component-names': 'off', + 'vue/multiline-html-element-content-newline': 'error', + 'vue/no-empty-pattern': 'error', + 'vue/no-extra-parens': ['error', 'functions'], + 'vue/no-irregular-whitespace': 'error', + 'vue/no-loss-of-precision': 'error', + 'vue/no-reserved-component-names': 'off', + 'vue/no-restricted-syntax': [ + 'error', + 'DebuggerStatement', + 'LabeledStatement', + 'WithStatement', + ], + 'vue/no-restricted-v-bind': ['error', '/^v-/'], + 'vue/no-sparse-arrays': 'error', + 'vue/no-unused-refs': 'error', + 'vue/no-useless-v-bind': 'error', + 'vue/object-shorthand': [ + 'error', + 'always', + { + avoidQuotes: true, + ignoreConstructors: false, + }, + ], + 'vue/one-component-per-file': 'error', + 'vue/prefer-import-from-vue': 'error', + 'vue/prefer-separate-static-class': 'error', + 'vue/prefer-template': 'error', + 'vue/prop-name-casing': ['error', 'camelCase'], + 'vue/require-default-prop': 'error', + 'vue/require-explicit-emits': 'error', + 'vue/require-prop-types': 'off', + 'vue/script-setup-uses-vars': 'error', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/space-infix-ops': 'error', + 'vue/space-unary-ops': ['error', { nonwords: false, words: true }], + 'vue/v-on-event-hyphenation': [ + 'error', + 'always', + { + autofix: true, + ignore: [], + }, + ], + }, + }, + ]; +} diff --git a/internal/lint-configs/eslint-config/src/custom-config.ts b/internal/lint-configs/eslint-config/src/custom-config.ts new file mode 100644 index 00000000..4cdf8d60 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/custom-config.ts @@ -0,0 +1,145 @@ +import type { Linter } from 'eslint'; + +const restrictedImportIgnores = [ + '**/vite.config.mts', + '**/tailwind.config.mjs', + '**/postcss.config.mjs', +]; + +const customConfig: Linter.Config[] = [ + // shadcn-ui 内部组件是自动生成的,不做太多限制 + { + files: ['packages/@core/ui-kit/shadcn-ui/**/**'], + rules: { + 'vue/require-default-prop': 'off', + }, + }, + { + files: ['packages/effects/**/**', 'packages/types/**/**'], + ignores: restrictedImportIgnores, + rules: { + 'perfectionist/sort-interfaces': 'off', + }, + }, + { + // apps内部的一些基础规则 + files: ['apps/**/**'], + ignores: restrictedImportIgnores, + rules: { + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['#/api/*'], + message: + 'The #/api package cannot be imported, please use the @core package itself', + }, + { + group: ['#/layouts/*'], + message: + 'The #/layouts package cannot be imported, please use the @core package itself', + }, + { + group: ['#/locales/*'], + message: + 'The #/locales package cannot be imported, please use the @core package itself', + }, + { + group: ['#/stores/*'], + message: + 'The #/stores package cannot be imported, please use the @core package itself', + }, + ], + }, + ], + 'perfectionist/sort-interfaces': 'off', + }, + }, + { + // @core内部组件,不能引入@vben/* 里面的包 + files: ['packages/@core/**/**'], + ignores: restrictedImportIgnores, + rules: { + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['@vben/*'], + message: + 'The @core package cannot import the @vben package, please use the @core package itself', + }, + ], + }, + ], + }, + }, + { + // @core/shared内部组件,不能引入@vben/* 或者 @vben-core/* 里面的包 + files: ['packages/@core/base/**/**'], + ignores: restrictedImportIgnores, + rules: { + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['@vben/*', '@vben-core/*'], + message: + 'The @vben-core/shared package cannot import the @vben package, please use the @core/shared package itself', + }, + ], + }, + ], + }, + }, + { + // 不能引入@vben/*里面的包 + files: [ + 'packages/types/**/**', + 'packages/utils/**/**', + 'packages/icons/**/**', + 'packages/constants/**/**', + 'packages/styles/**/**', + 'packages/stores/**/**', + 'packages/preferences/**/**', + 'packages/locales/**/**', + ], + ignores: restrictedImportIgnores, + rules: { + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['@vben/*'], + message: + 'The @vben package cannot be imported, please use the @core package itself', + }, + ], + }, + ], + }, + }, + // 后端模拟代码,不需要太多规则 + { + files: ['apps/backend-mock/**/**', 'docs/**/**'], + rules: { + '@typescript-eslint/no-extraneous-class': 'off', + 'n/no-extraneous-import': 'off', + 'n/prefer-global/buffer': 'off', + 'n/prefer-global/process': 'off', + 'no-console': 'off', + 'unicorn/prefer-module': 'off', + }, + }, + { + files: ['internal/**/**'], + rules: { + 'no-console': 'off', + }, + }, +]; + +export { customConfig }; diff --git a/internal/lint-configs/eslint-config/src/index.ts b/internal/lint-configs/eslint-config/src/index.ts new file mode 100644 index 00000000..c9f08bd5 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/index.ts @@ -0,0 +1,60 @@ +import type { Linter } from 'eslint'; + +import { + command, + comments, + disableds, + ignores, + importPluginConfig, + javascript, + jsdoc, + jsonc, + node, + perfectionist, + prettier, + regexp, + test, + turbo, + typescript, + unicorn, + vue, +} from './configs'; +import { customConfig } from './custom-config'; + +type FlatConfig = Linter.Config; + +type FlatConfigPromise = + | FlatConfig + | FlatConfig[] + | Promise + | Promise; + +async function defineConfig(config: FlatConfig[] = []) { + const configs: FlatConfigPromise[] = [ + vue(), + javascript(), + ignores(), + prettier(), + typescript(), + jsonc(), + disableds(), + importPluginConfig(), + node(), + perfectionist(), + comments(), + jsdoc(), + unicorn(), + test(), + regexp(), + command(), + turbo(), + ...customConfig, + ...config, + ]; + + const resolved = await Promise.all(configs); + + return resolved.flat(); +} + +export { defineConfig }; diff --git a/internal/lint-configs/eslint-config/src/util.ts b/internal/lint-configs/eslint-config/src/util.ts new file mode 100644 index 00000000..d1a10ad8 --- /dev/null +++ b/internal/lint-configs/eslint-config/src/util.ts @@ -0,0 +1,8 @@ +export type Awaitable = Promise | T; + +export async function interopDefault( + m: Awaitable, +): Promise { + const resolved = await m; + return (resolved as any).default || resolved; +} diff --git a/internal/lint-configs/eslint-config/tsconfig.json b/internal/lint-configs/eslint-config/tsconfig.json new file mode 100644 index 00000000..b2ec3b61 --- /dev/null +++ b/internal/lint-configs/eslint-config/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/node.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/internal/lint-configs/prettier-config/index.mjs b/internal/lint-configs/prettier-config/index.mjs new file mode 100644 index 00000000..41d8ff26 --- /dev/null +++ b/internal/lint-configs/prettier-config/index.mjs @@ -0,0 +1,24 @@ +export default { + endOfLine: 'auto', + overrides: [ + { + files: ['*.json5'], + options: { + quoteProps: 'preserve', + singleQuote: false, + }, + }, + { + files: ['*.yaml', '*.yml'], + options: { + singleQuote: false, + }, + }, + ], + plugins: ['prettier-plugin-tailwindcss'], + printWidth: 80, + proseWrap: 'never', + semi: true, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/internal/lint-configs/prettier-config/package.json b/internal/lint-configs/prettier-config/package.json new file mode 100644 index 00000000..50693636 --- /dev/null +++ b/internal/lint-configs/prettier-config/package.json @@ -0,0 +1,28 @@ +{ + "name": "@vben/prettier-config", + "version": "5.0.0", + "private": true, + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "internal/lint-configs/prettier-config" + }, + "license": "MIT", + "type": "module", + "files": [ + "dist" + ], + "main": "./index.mjs", + "module": "./index.mjs", + "exports": { + ".": { + "default": "./index.mjs" + } + }, + "dependencies": { + "prettier": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.6" + } +} diff --git a/internal/lint-configs/stylelint-config/index.mjs b/internal/lint-configs/stylelint-config/index.mjs new file mode 100644 index 00000000..7ef175cc --- /dev/null +++ b/internal/lint-configs/stylelint-config/index.mjs @@ -0,0 +1,140 @@ +export default { + extends: ['stylelint-config-standard', 'stylelint-config-recess-order'], + ignoreFiles: [ + '**/*.js', + '**/*.jsx', + '**/*.tsx', + '**/*.ts', + '**/*.json', + '**/*.md', + ], + overrides: [ + { + customSyntax: 'postcss-html', + files: ['*.(html|vue)', '**/*.(html|vue)'], + rules: { + 'selector-pseudo-class-no-unknown': [ + true, + { + ignorePseudoClasses: ['global', 'deep'], + }, + ], + 'selector-pseudo-element-no-unknown': [ + true, + { + ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'], + }, + ], + }, + }, + { + customSyntax: 'postcss-scss', + extends: [ + 'stylelint-config-recommended-scss', + 'stylelint-config-recommended-vue/scss', + ], + files: ['*.scss', '**/*.scss'], + }, + ], + plugins: [ + 'stylelint-order', + '@stylistic/stylelint-plugin', + 'stylelint-prettier', + 'stylelint-scss', + ], + rules: { + 'at-rule-no-unknown': [ + true, + { + ignoreAtRules: [ + 'extends', + 'ignores', + 'include', + 'mixin', + 'if', + 'else', + 'media', + 'for', + 'at-root', + 'tailwind', + 'apply', + 'variants', + 'responsive', + 'screen', + 'function', + 'each', + 'use', + 'forward', + 'return', + ], + }, + ], + 'font-family-no-missing-generic-family-keyword': null, + 'function-no-unknown': null, + 'import-notation': null, + 'media-feature-range-notation': null, + 'named-grid-areas-no-invalid': null, + 'no-descending-specificity': null, + 'no-empty-source': null, + 'order/order': [ + [ + 'dollar-variables', + 'custom-properties', + 'at-rules', + 'declarations', + { + name: 'supports', + type: 'at-rule', + }, + { + name: 'media', + type: 'at-rule', + }, + { + name: 'include', + type: 'at-rule', + }, + 'rules', + ], + { severity: 'error' }, + ], + 'prettier/prettier': true, + 'rule-empty-line-before': [ + 'always', + { + ignore: ['after-comment', 'first-nested'], + }, + ], + 'scss/at-rule-no-unknown': [ + true, + { + ignoreAtRules: [ + 'extends', + 'ignores', + 'include', + 'mixin', + 'if', + 'else', + 'media', + 'for', + 'at-root', + 'tailwind', + 'apply', + 'variants', + 'responsive', + 'screen', + 'function', + 'each', + 'use', + 'forward', + 'return', + ], + }, + ], + 'scss/operator-no-newline-after': null, + 'selector-class-pattern': + '^(?:(?:o|c|u|t|s|is|has|_|js|qa)-)?[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*(?:__[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:--[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:[.+])?$', + + 'selector-not-notation': null, + }, +}; diff --git a/internal/lint-configs/stylelint-config/package.json b/internal/lint-configs/stylelint-config/package.json new file mode 100644 index 00000000..b6c94161 --- /dev/null +++ b/internal/lint-configs/stylelint-config/package.json @@ -0,0 +1,43 @@ +{ + "name": "@vben/stylelint-config", + "version": "5.1.2", + "private": true, + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "internal/lint-configs/stylelint-config" + }, + "license": "MIT", + "type": "module", + "files": [ + "dist" + ], + "main": "./index.mjs", + "module": "./index.mjs", + "exports": { + ".": { + "import": "./index.mjs", + "default": "./index.mjs" + } + }, + "dependencies": { + "@stylistic/stylelint-plugin": "^3.0.1", + "stylelint-config-recess-order": "^5.1.0", + "stylelint-scss": "^6.5.1" + }, + "devDependencies": { + "postcss": "^8.4.41", + "postcss-html": "^1.7.0", + "postcss-scss": "^4.0.9", + "prettier": "^3.3.3", + "stylelint": "^16.9.0", + "stylelint-config-recommended": "^14.0.1", + "stylelint-config-recommended-scss": "^14.1.0", + "stylelint-config-recommended-vue": "^1.5.0", + "stylelint-config-standard": "^36.0.1", + "stylelint-order": "^6.0.4", + "stylelint-prettier": "^5.0.2" + } +} diff --git a/internal/node-utils/build.config.ts b/internal/node-utils/build.config.ts new file mode 100644 index 00000000..97e572c5 --- /dev/null +++ b/internal/node-utils/build.config.ts @@ -0,0 +1,7 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + declaration: true, + entries: ['src/index'], +}); diff --git a/internal/node-utils/package.json b/internal/node-utils/package.json new file mode 100644 index 00000000..c7a6479f --- /dev/null +++ b/internal/node-utils/package.json @@ -0,0 +1,47 @@ +{ + "name": "@vben/node-utils", + "version": "5.1.2", + "private": true, + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "internal/node-utils" + }, + "license": "MIT", + "type": "module", + "scripts": { + "stub": "pnpm unbuild --stub" + }, + "files": [ + "dist" + ], + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./dist/index.mjs", + "default": "./dist/index.mjs" + } + }, + "dependencies": { + "@changesets/git": "^3.0.0", + "@manypkg/get-packages": "^2.2.2", + "chalk": "^5.3.0", + "consola": "^3.2.3", + "dayjs": "^1.11.13", + "execa": "^9.3.1", + "find-up": "^7.0.0", + "nanoid": "^5.0.7", + "ora": "^8.1.0", + "pkg-types": "^1.2.0", + "prettier": "^3.3.3", + "rimraf": "^6.0.1" + }, + "devDependencies": { + "@types/chalk": "^2.2.0" + } +} diff --git a/internal/node-utils/src/__tests__/hash.test.ts b/internal/node-utils/src/__tests__/hash.test.ts new file mode 100644 index 00000000..38513060 --- /dev/null +++ b/internal/node-utils/src/__tests__/hash.test.ts @@ -0,0 +1,52 @@ +import { createHash } from 'node:crypto'; + +import { describe, expect, it } from 'vitest'; + +import { generatorContentHash } from '../hash'; + +describe('generatorContentHash', () => { + it('should generate an MD5 hash for the content', () => { + const content = 'example content'; + const expectedHash = createHash('md5') + .update(content, 'utf8') + .digest('hex'); + const actualHash = generatorContentHash(content); + expect(actualHash).toBe(expectedHash); + }); + + it('should generate an MD5 hash with specified length', () => { + const content = 'example content'; + const hashLength = 10; + const generatedHash = generatorContentHash(content, hashLength); + expect(generatedHash).toHaveLength(hashLength); + }); + + it('should correctly generate the hash with specified length', () => { + const content = 'example content'; + const hashLength = 8; + const expectedHash = createHash('md5') + .update(content, 'utf8') + .digest('hex') + .slice(0, hashLength); + const generatedHash = generatorContentHash(content, hashLength); + expect(generatedHash).toBe(expectedHash); + }); + + it('should return full hash if hash length parameter is not provided', () => { + const content = 'example content'; + const expectedHash = createHash('md5') + .update(content, 'utf8') + .digest('hex'); + const actualHash = generatorContentHash(content); + expect(actualHash).toBe(expectedHash); + }); + + it('should handle empty content', () => { + const content = ''; + const expectedHash = createHash('md5') + .update(content, 'utf8') + .digest('hex'); + const actualHash = generatorContentHash(content); + expect(actualHash).toBe(expectedHash); + }); +}); diff --git a/internal/node-utils/src/__tests__/path.test.ts b/internal/node-utils/src/__tests__/path.test.ts new file mode 100644 index 00000000..3bab5a16 --- /dev/null +++ b/internal/node-utils/src/__tests__/path.test.ts @@ -0,0 +1,67 @@ +// pathUtils.test.ts + +import { describe, expect, it } from 'vitest'; + +import { toPosixPath } from '../path'; + +describe('toPosixPath', () => { + // 测试 Windows 风格路径到 POSIX 风格路径的转换 + it('converts Windows-style paths to POSIX paths', () => { + const windowsPath = String.raw`C:\Users\Example\file.txt`; + const expectedPosixPath = 'C:/Users/Example/file.txt'; + expect(toPosixPath(windowsPath)).toBe(expectedPosixPath); + }); + + // 确认 POSIX 风格路径不会被改变 + it('leaves POSIX-style paths unchanged', () => { + const posixPath = '/home/user/file.txt'; + expect(toPosixPath(posixPath)).toBe(posixPath); + }); + + // 测试带有多个分隔符的路径 + it('converts paths with mixed separators', () => { + const mixedPath = String.raw`C:/Users\Example\file.txt`; + const expectedPosixPath = 'C:/Users/Example/file.txt'; + expect(toPosixPath(mixedPath)).toBe(expectedPosixPath); + }); + + // 测试空字符串 + it('handles empty strings', () => { + const emptyPath = ''; + expect(toPosixPath(emptyPath)).toBe(''); + }); + + // 测试仅包含分隔符的路径 + it('handles path with only separators', () => { + const separatorsPath = '\\\\\\'; + const expectedPosixPath = '///'; + expect(toPosixPath(separatorsPath)).toBe(expectedPosixPath); + }); + + // 测试不包含任何分隔符的路径 + it('handles path without separators', () => { + const noSeparatorPath = 'file.txt'; + expect(toPosixPath(noSeparatorPath)).toBe('file.txt'); + }); + + // 测试以分隔符结尾的路径 + it('handles path ending with a separator', () => { + const endingSeparatorPath = 'C:\\Users\\Example\\'; + const expectedPosixPath = 'C:/Users/Example/'; + expect(toPosixPath(endingSeparatorPath)).toBe(expectedPosixPath); + }); + + // 测试以分隔符开头的路径 + it('handles path starting with a separator', () => { + const startingSeparatorPath = String.raw`\Users\Example`; + const expectedPosixPath = '/Users/Example'; + expect(toPosixPath(startingSeparatorPath)).toBe(expectedPosixPath); + }); + + // 测试包含非法字符的路径 + it('handles path with invalid characters', () => { + const invalidCharsPath = String.raw`C:\Us*?ers\Ex|file.txt`; + const expectedPosixPath = 'C:/Us*?ers/Ex|file.txt'; + expect(toPosixPath(invalidCharsPath)).toBe(expectedPosixPath); + }); +}); diff --git a/internal/node-utils/src/constants.ts b/internal/node-utils/src/constants.ts new file mode 100644 index 00000000..71d8a6cb --- /dev/null +++ b/internal/node-utils/src/constants.ts @@ -0,0 +1,6 @@ +enum UNICODE { + FAILURE = '\u2716', // ✖ + SUCCESS = '\u2714', // ✔ +} + +export { UNICODE }; diff --git a/internal/node-utils/src/date.ts b/internal/node-utils/src/date.ts new file mode 100644 index 00000000..d36572d9 --- /dev/null +++ b/internal/node-utils/src/date.ts @@ -0,0 +1,12 @@ +import dayjs from 'dayjs'; +import timezone from 'dayjs/plugin/timezone'; +import utc from 'dayjs/plugin/utc'; + +dayjs.extend(utc); +dayjs.extend(timezone); + +dayjs.tz.setDefault('Asia/Shanghai'); + +const dateUtil = dayjs; + +export { dateUtil }; diff --git a/internal/node-utils/src/fs.ts b/internal/node-utils/src/fs.ts new file mode 100644 index 00000000..8eec3573 --- /dev/null +++ b/internal/node-utils/src/fs.ts @@ -0,0 +1,39 @@ +import { promises as fs } from 'node:fs'; +import { dirname } from 'node:path'; + +export async function outputJSON( + filePath: string, + data: any, + spaces: number = 2, +) { + try { + const dir = dirname(filePath); + await fs.mkdir(dir, { recursive: true }); + const jsonData = JSON.stringify(data, null, spaces); + await fs.writeFile(filePath, jsonData, 'utf8'); + } catch (error) { + console.error('Error writing JSON file:', error); + throw error; + } +} + +export async function ensureFile(filePath: string) { + try { + const dir = dirname(filePath); + await fs.mkdir(dir, { recursive: true }); + await fs.writeFile(filePath, '', { flag: 'a' }); + } catch (error) { + console.error('Error ensuring file:', error); + throw error; + } +} + +export async function readJSON(filePath: string) { + try { + const data = await fs.readFile(filePath, 'utf8'); + return JSON.parse(data); + } catch (error) { + console.error('Error reading JSON file:', error); + throw error; + } +} diff --git a/internal/node-utils/src/git.ts b/internal/node-utils/src/git.ts new file mode 100644 index 00000000..88f159cc --- /dev/null +++ b/internal/node-utils/src/git.ts @@ -0,0 +1,34 @@ +import path from 'node:path'; + +import { execa } from 'execa'; + +export * from '@changesets/git'; + +/** + * 获取暂存区文件 + */ +async function getStagedFiles(): Promise { + try { + const { stdout } = await execa('git', [ + '-c', + 'submodule.recurse=false', + 'diff', + '--staged', + '--diff-filter=ACMR', + '--name-only', + '--ignore-submodules', + '-z', + ]); + + let changedList = stdout ? stdout.replace(/\0$/, '').split('\0') : []; + changedList = changedList.map((item) => path.resolve(process.cwd(), item)); + const changedSet = new Set(changedList); + changedSet.delete(''); + return [...changedSet]; + } catch (error) { + console.error('Failed to get staged files:', error); + return []; + } +} + +export { getStagedFiles }; diff --git a/internal/node-utils/src/hash.ts b/internal/node-utils/src/hash.ts new file mode 100644 index 00000000..81f6b05c --- /dev/null +++ b/internal/node-utils/src/hash.ts @@ -0,0 +1,18 @@ +import { createHash } from 'node:crypto'; + +/** + * 生产基于内容的 hash,可自定义长度 + * @param content + * @param hashLSize + */ +function generatorContentHash(content: string, hashLSize?: number) { + const hash = createHash('md5').update(content, 'utf8').digest('hex'); + + if (hashLSize) { + return hash.slice(0, hashLSize); + } + + return hash; +} + +export { generatorContentHash }; diff --git a/internal/node-utils/src/index.ts b/internal/node-utils/src/index.ts new file mode 100644 index 00000000..cd9028d7 --- /dev/null +++ b/internal/node-utils/src/index.ts @@ -0,0 +1,21 @@ +export * from './constants'; +export * from './date'; +export * from './fs'; +export * from './git'; +export { add as gitAdd, getStagedFiles } from './git'; +export { generatorContentHash } from './hash'; +export * from './monorepo'; +export { toPosixPath } from './path'; +export { prettierFormat } from './prettier'; +export * from './spinner'; +export type { Package } from '@manypkg/get-packages'; +export { default as colors } from 'chalk'; +export { consola } from 'consola'; +export * from 'execa'; + +export { nanoid } from 'nanoid'; + +export { default as fs } from 'node:fs/promises'; + +export { type PackageJson, readPackageJSON } from 'pkg-types'; +export { rimraf } from 'rimraf'; diff --git a/internal/node-utils/src/monorepo.ts b/internal/node-utils/src/monorepo.ts new file mode 100644 index 00000000..15ddb810 --- /dev/null +++ b/internal/node-utils/src/monorepo.ts @@ -0,0 +1,49 @@ +import { dirname } from 'node:path'; + +import { + getPackages as getPackagesFunc, + getPackagesSync as getPackagesSyncFunc, +} from '@manypkg/get-packages'; +import { findUpSync } from 'find-up'; + +/** + * 查找大仓的根目录 + * @param cwd + */ +function findMonorepoRoot(cwd: string = process.cwd()) { + const lockFile = findUpSync( + ['pnpm-lock.yaml', 'yarn.lock', 'package-lock.json'], + { + cwd, + type: 'file', + }, + ); + return dirname(lockFile || ''); +} + +/** + * 获取大仓的所有包 + */ +function getPackagesSync() { + const root = findMonorepoRoot(); + return getPackagesSyncFunc(root); +} + +/** + * 获取大仓的所有包 + */ +async function getPackages() { + const root = findMonorepoRoot(); + + return await getPackagesFunc(root); +} + +/** + * 获取大仓指定的包 + */ +async function getPackage(pkgName: string) { + const { packages } = await getPackages(); + return packages.find((pkg) => pkg.packageJson.name === pkgName); +} + +export { findMonorepoRoot, getPackage, getPackages, getPackagesSync }; diff --git a/internal/node-utils/src/path.ts b/internal/node-utils/src/path.ts new file mode 100644 index 00000000..e625fd2f --- /dev/null +++ b/internal/node-utils/src/path.ts @@ -0,0 +1,11 @@ +import { posix } from 'node:path'; + +/** + * 将给定的文件路径转换为 POSIX 风格。 + * @param {string} pathname - 原始文件路径。 + */ +function toPosixPath(pathname: string) { + return pathname.split(`\\`).join(posix.sep); +} + +export { toPosixPath }; diff --git a/internal/node-utils/src/prettier.ts b/internal/node-utils/src/prettier.ts new file mode 100644 index 00000000..1e1525db --- /dev/null +++ b/internal/node-utils/src/prettier.ts @@ -0,0 +1,21 @@ +import fs from 'node:fs/promises'; + +import { format, getFileInfo, resolveConfig } from 'prettier'; + +async function prettierFormat(filepath: string) { + const prettierOptions = await resolveConfig(filepath, {}); + + const fileInfo = await getFileInfo(filepath); + + const input = await fs.readFile(filepath, 'utf8'); + const output = await format(input, { + ...prettierOptions, + parser: fileInfo.inferredParser as any, + }); + if (output !== input) { + await fs.writeFile(filepath, output, 'utf8'); + } + return output; +} + +export { prettierFormat }; diff --git a/internal/node-utils/src/spinner.ts b/internal/node-utils/src/spinner.ts new file mode 100644 index 00000000..f07cc256 --- /dev/null +++ b/internal/node-utils/src/spinner.ts @@ -0,0 +1,24 @@ +import ora, { type Ora } from 'ora'; + +interface SpinnerOptions { + failedText?: string; + successText?: string; + title: string; +} +export async function spinner( + { failedText, successText, title }: SpinnerOptions, + callback: () => Promise, +): Promise { + const loading: Ora = ora(title).start(); + + try { + const result = await callback(); + loading.succeed(successText || 'Success!'); + return result; + } catch (error) { + loading.fail(failedText || 'Failed!'); + throw error; + } finally { + loading.stop(); + } +} diff --git a/internal/node-utils/tsconfig.json b/internal/node-utils/tsconfig.json new file mode 100644 index 00000000..b2ec3b61 --- /dev/null +++ b/internal/node-utils/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/node.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/internal/tailwind-config/build.config.ts b/internal/tailwind-config/build.config.ts new file mode 100644 index 00000000..e79fb56f --- /dev/null +++ b/internal/tailwind-config/build.config.ts @@ -0,0 +1,11 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + declaration: true, + entries: ['src/index', './src/postcss.config'], + externals: ['@vben/node-utils'], + rollup: { + emitCJS: true, + }, +}); diff --git a/internal/tailwind-config/package.json b/internal/tailwind-config/package.json new file mode 100644 index 00000000..70c189ca --- /dev/null +++ b/internal/tailwind-config/package.json @@ -0,0 +1,66 @@ +{ + "name": "@vben/tailwind-config", + "version": "5.1.2", + "private": true, + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "internal/tailwind-config" + }, + "license": "MIT", + "type": "module", + "scripts": { + "stub": "pnpm unbuild --stub" + }, + "files": [ + "dist" + ], + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "typesVersions": { + "*": { + "*": [ + "./dist/*", + "./*" + ] + } + }, + "exports": { + ".": { + "types": "./src/index.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + }, + "./postcss": { + "types": "./src/postcss.config.ts", + "import": "./dist/postcss.config.mjs", + "require": "./dist/postcss.config.cjs", + "default": "./dist/postcss.config.mjs" + }, + "./*": "./*" + }, + "peerDependencies": { + "tailwindcss": "^3.4.3" + }, + "dependencies": { + "@iconify/json": "^2.2.242", + "@iconify/tailwind": "^1.1.3", + "@tailwindcss/nesting": "0.0.0-insiders.565cd3e", + "@tailwindcss/typography": "^0.5.15", + "autoprefixer": "^10.4.20", + "cssnano": "^7.0.5", + "postcss": "^8.4.41", + "postcss-antd-fixes": "^0.2.0", + "postcss-import": "^16.1.0", + "postcss-preset-env": "^10.0.2", + "tailwindcss": "^3.4.10", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "@types/postcss-import": "^14.0.3", + "@vben/node-utils": "workspace:*" + } +} diff --git a/internal/tailwind-config/src/index.ts b/internal/tailwind-config/src/index.ts new file mode 100644 index 00000000..b1b1922a --- /dev/null +++ b/internal/tailwind-config/src/index.ts @@ -0,0 +1,264 @@ +import type { Config } from 'tailwindcss'; + +import fs from 'node:fs'; +import path from 'node:path'; + +import { getPackagesSync } from '@vben/node-utils'; + +import { addDynamicIconSelectors } from '@iconify/tailwind'; +import typographyPlugin from '@tailwindcss/typography'; +import animate from 'tailwindcss-animate'; + +import { enterAnimationPlugin } from './plugins/entry'; + +// import defaultTheme from 'tailwindcss/defaultTheme'; + +const { packages } = getPackagesSync(); + +const tailwindPackages: string[] = []; + +packages.forEach((pkg) => { + // apps目录下和 @vben-core/tailwind-ui 包需要使用到 tailwindcss ui + if (fs.existsSync(path.join(pkg.dir, 'tailwind.config.mjs'))) { + tailwindPackages.push(pkg.dir); + } +}); + +const shadcnUiColors = { + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + hover: 'hsl(var(--accent-hover))', + }, + background: { + deep: 'hsl(var(--background-deep))', + DEFAULT: 'hsl(var(--background))', + }, + border: { + DEFAULT: 'hsl(var(--border))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + destructive: { + ...createColorsPalette('destructive'), + DEFAULT: 'hsl(var(--destructive))', + }, + + foreground: { + DEFAULT: 'hsl(var(--foreground))', + }, + + input: { + background: 'hsl(var(--input-background))', + DEFAULT: 'hsl(var(--input))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + primary: { + ...createColorsPalette('primary'), + DEFAULT: 'hsl(var(--primary))', + }, + + ring: 'hsl(var(--ring))', + secondary: { + DEFAULT: 'hsl(var(--secondary))', + desc: 'hsl(var(--secondary-desc))', + foreground: 'hsl(var(--secondary-foreground))', + }, +}; + +const customColors = { + green: { + ...createColorsPalette('green'), + foreground: 'hsl(var(--success-foreground))', + }, + header: { + DEFAULT: 'hsl(var(--header))', + }, + heavy: { + DEFAULT: 'hsl(var(--heavy))', + foreground: 'hsl(var(--heavy-foreground))', + }, + main: { + DEFAULT: 'hsl(var(--main))', + }, + overlay: 'hsl(var(--overlay))', + red: { + ...createColorsPalette('red'), + foreground: 'hsl(var(--destructive-foreground))', + }, + sidebar: { + deep: 'hsl(var(--sidebar-deep))', + DEFAULT: 'hsl(var(--sidebar))', + }, + success: { + ...createColorsPalette('success'), + DEFAULT: 'hsl(var(--success))', + }, + warning: { + ...createColorsPalette('warning'), + DEFAULT: 'hsl(var(--warning))', + }, + yellow: { + ...createColorsPalette('yellow'), + foreground: 'hsl(var(--warning-foreground))', + }, +}; + +export default { + content: [ + './index.html', + ...tailwindPackages.map((item) => + path.join(item, 'src/**/*.{vue,js,ts,jsx,tsx,svelte,astro,html}'), + ), + ], + darkMode: 'selector', + plugins: [ + animate, + typographyPlugin, + addDynamicIconSelectors(), + enterAnimationPlugin, + ], + prefix: '', + safelist: ['dark'], + theme: { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px', + }, + }, + extend: { + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + 'collapsible-down': 'collapsible-down 0.2s ease-in-out', + 'collapsible-up': 'collapsible-up 0.2s ease-in-out', + float: 'float 5s linear 0ms infinite', + }, + + animationDuration: { + '2000': '2000ms', + '3000': '3000ms', + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + xl: 'calc(var(--radius) + 4px)', + }, + boxShadow: { + float: `0 6px 16px 0 rgb(0 0 0 / 8%), + 0 3px 6px -4px rgb(0 0 0 / 12%), + 0 9px 28px 8px rgb(0 0 0 / 5%)`, + }, + colors: { + ...customColors, + ...shadcnUiColors, + }, + fontFamily: { + sans: [ + 'var(--font-family)', + // ...defaultTheme.fontFamily.sans + ], + }, + keyframes: { + 'accordion-down': { + from: { height: '0' }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: '0' }, + }, + 'collapsible-down': { + from: { height: '0' }, + to: { height: 'var(--radix-collapsible-content-height)' }, + }, + 'collapsible-up': { + from: { height: 'var(--radix-collapsible-content-height)' }, + to: { height: '0' }, + }, + float: { + '0%': { transform: 'translateY(0)' }, + '100%': { transform: 'translateY(0)' }, + '50%': { transform: 'translateY(-20px)' }, + }, + }, + zIndex: { + '100': '100', + '1000': '1000', + }, + }, + }, +} as Config; + +function createColorsPalette(name: string) { + // backgroundLightest: '#EFF6FF', // Tailwind CSS 默认的 `blue-50` + // backgroundLighter: '#DBEAFE', // Tailwind CSS 默认的 `blue-100` + // backgroundLight: '#BFDBFE', // Tailwind CSS 默认的 `blue-200` + // borderLight: '#93C5FD', // Tailwind CSS 默认的 `blue-300` + // border: '#60A5FA', // Tailwind CSS 默认的 `blue-400` + // main: '#3B82F6', // Tailwind CSS 默认的 `blue-500` + // hover: '#2563EB', // Tailwind CSS 默认的 `blue-600` + // active: '#1D4ED8', // Tailwind CSS 默认的 `blue-700` + // backgroundDark: '#1E40AF', // Tailwind CSS 默认的 `blue-800` + // backgroundDarker: '#1E3A8A', // Tailwind CSS 默认的 `blue-900` + // backgroundDarkest: '#172554', // Tailwind CSS 默认的 `blue-950` + + // • backgroundLightest (#EFF6FF): 适用于最浅的背景色,可能用于非常轻微的阴影或卡片的背景。 + // • backgroundLighter (#DBEAFE): 适用于略浅的背景色,通常用于次要背景或略浅的区域。 + // • backgroundLight (#BFDBFE): 适用于浅色背景,可能用于输入框或表单区域的背景。 + // • borderLight (#93C5FD): 适用于浅色边框,可能用于输入框或卡片的边框。 + // • border (#60A5FA): 适用于普通边框,可能用于按钮或卡片的边框。 + // • main (#3B82F6): 适用于主要的主题色,通常用于按钮、链接或主要的强调色。 + // • hover (#2563EB): 适用于鼠标悬停状态下的颜色,例如按钮悬停时的背景色或边框色。 + // • active (#1D4ED8): 适用于激活状态下的颜色,例如按钮按下时的背景色或边框色。 + // • backgroundDark (#1E40AF): 适用于深色背景,可能用于主要按钮或深色卡片背景。 + // • backgroundDarker (#1E3A8A): 适用于更深的背景,通常用于头部导航栏或页脚。 + // • backgroundDarkest (#172554): 适用于最深的背景,可能用于非常深色的区域或极端对比色。 + + return { + 100: `hsl(var(--${name}-100))`, + 200: `hsl(var(--${name}-200))`, + 300: `hsl(var(--${name}-300))`, + 400: `hsl(var(--${name}-400))`, + 50: `hsl(var(--${name}-50))`, + 500: `hsl(var(--${name}-500))`, + 600: `hsl(var(--${name}-600))`, + 700: `hsl(var(--${name}-700))`, + // 800: `hsl(var(--${name}-800))`, + // 900: `hsl(var(--${name}-900))`, + // 950: `hsl(var(--${name}-950))`, + // 激活状态下的颜色,适用于按钮按下时的背景色或边框色。 + active: `hsl(var(--${name}-700))`, + // 浅色背景,适用于输入框或表单区域的背景。 + 'background-light': `hsl(var(--${name}-200))`, + // 适用于略浅的背景色,通常用于次要背景或略浅的区域。 + 'background-lighter': `hsl(var(--${name}-100))`, + // 最浅的背景色,适用于非常轻微的阴影或卡片的背景。 + 'background-lightest': `hsl(var(--${name}-50))`, + // 适用于普通边框,可能用于按钮或卡片的边框。 + border: `hsl(var(--${name}-400))`, + // 浅色边框,适用于输入框或卡片的边框。 + 'border-light': `hsl(var(--${name}-300))`, + foreground: `hsl(var(--${name}-foreground))`, + // 鼠标悬停状态下的颜色,适用于按钮悬停时的背景色或边框色。 + hover: `hsl(var(--${name}-600))`, + // 主色文本 + text: `hsl(var(--${name}-500))`, + // 主色文本激活态 + 'text-active': `hsl(var(--${name}-700))`, + // 主色文本悬浮态 + 'text-hover': `hsl(var(--${name}-600))`, + }; +} diff --git a/internal/tailwind-config/src/module.d.ts b/internal/tailwind-config/src/module.d.ts new file mode 100644 index 00000000..a3996533 --- /dev/null +++ b/internal/tailwind-config/src/module.d.ts @@ -0,0 +1,3 @@ +declare module '@tailwindcss/nesting' { + export default any; +} diff --git a/internal/tailwind-config/src/plugins/entry.ts b/internal/tailwind-config/src/plugins/entry.ts new file mode 100644 index 00000000..0d8e8ec8 --- /dev/null +++ b/internal/tailwind-config/src/plugins/entry.ts @@ -0,0 +1,53 @@ +import plugin from 'tailwindcss/plugin.js'; + +const enterAnimationPlugin = plugin(({ addUtilities }) => { + const maxChild = 5; + const utilities: Record = {}; + for (let i = 1; i <= maxChild; i++) { + const baseDelay = 0.1; + const delay = `${baseDelay * i}s`; + + utilities[`.enter-x:nth-child(${i})`] = { + animation: `enter-x-animation 0.3s ease-in-out ${delay} forwards`, + opacity: '0', + transform: `translateX(50px)`, + }; + + utilities[`.enter-y:nth-child(${i})`] = { + animation: `enter-y-animation 0.3s ease-in-out ${delay} forwards`, + opacity: '0', + transform: `translateY(50px)`, + }; + + utilities[`.-enter-x:nth-child(${i})`] = { + animation: `enter-x-animation 0.3s ease-in-out ${delay} forwards`, + opacity: '0', + transform: `translateX(-50px)`, + }; + + utilities[`.-enter-y:nth-child(${i})`] = { + animation: `enter-y-animation 0.3s ease-in-out ${delay} forwards`, + opacity: '0', + transform: `translateY(-50px)`, + }; + } + + // 添加动画关键帧 + addUtilities(utilities); + addUtilities({ + '@keyframes enter-x-animation': { + to: { + opacity: '1', + transform: 'translateX(0)', + }, + }, + '@keyframes enter-y-animation': { + to: { + opacity: '1', + transform: 'translateY(0)', + }, + }, + }); +}); + +export { enterAnimationPlugin }; diff --git a/internal/tailwind-config/src/postcss.config.ts b/internal/tailwind-config/src/postcss.config.ts new file mode 100644 index 00000000..43b30b35 --- /dev/null +++ b/internal/tailwind-config/src/postcss.config.ts @@ -0,0 +1,15 @@ +import config from '.'; + +export default { + plugins: { + ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}), + // Specifying the config is not necessary in most cases, but it is included + autoprefixer: {}, + // 修复 element-plus 和 ant-design-vue 的样式和tailwindcss冲突问题 + 'postcss-antd-fixes': { prefixes: ['ant', 'el'] }, + 'postcss-import': {}, + 'postcss-preset-env': {}, + tailwindcss: { config }, + 'tailwindcss/nesting': {}, + }, +}; diff --git a/internal/tailwind-config/tsconfig.json b/internal/tailwind-config/tsconfig.json new file mode 100644 index 00000000..b2ec3b61 --- /dev/null +++ b/internal/tailwind-config/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/node.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/internal/tsconfig/base.json b/internal/tsconfig/base.json new file mode 100644 index 00000000..1e45a784 --- /dev/null +++ b/internal/tsconfig/base.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Base", + "compilerOptions": { + "composite": false, + "target": "ESNext", + + "moduleDetection": "force", + "experimentalDecorators": true, + + "baseUrl": ".", + "module": "ESNext", + + "moduleResolution": "node", + "resolveJsonModule": true, + + "strict": true, + "strictNullChecks": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitOverride": true, + "noImplicitThis": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + + "inlineSources": false, + "noEmit": true, + "removeComments": true, + "sourceMap": false, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true, + "preserveWatchOutput": true + }, + "exclude": ["**/node_modules/**", "**/dist/**", "**/.turbo/**"] +} diff --git a/internal/tsconfig/library.json b/internal/tsconfig/library.json new file mode 100644 index 00000000..7a976f09 --- /dev/null +++ b/internal/tsconfig/library.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Web Application", + "extends": "./base.json", + "compilerOptions": { + "jsx": "preserve", + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "useDefineForClassFields": true, + "moduleResolution": "bundler", + "declaration": true, + "noEmit": false + } +} diff --git a/internal/tsconfig/node.json b/internal/tsconfig/node.json new file mode 100644 index 00000000..31ce8f18 --- /dev/null +++ b/internal/tsconfig/node.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Node Config", + "extends": "./base.json", + "compilerOptions": { + "composite": false, + "lib": ["ESNext"], + "baseUrl": "./", + "types": ["node"], + "noImplicitAny": true + } +} diff --git a/internal/tsconfig/package.json b/internal/tsconfig/package.json new file mode 100644 index 00000000..cc0a8eeb --- /dev/null +++ b/internal/tsconfig/package.json @@ -0,0 +1,25 @@ +{ + "name": "@vben/tsconfig", + "version": "5.1.2", + "private": true, + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "internal/tsconfig" + }, + "license": "MIT", + "type": "module", + "files": [ + "base.json", + "library.json", + "node.json", + "web-app.json", + "web.json" + ], + "dependencies": { + "@vben/types": "workspace:*", + "vite": "^5.4.2" + } +} diff --git a/internal/tsconfig/web-app.json b/internal/tsconfig/web-app.json new file mode 100644 index 00000000..00479cb8 --- /dev/null +++ b/internal/tsconfig/web-app.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Web Application", + "extends": "./web.json", + "compilerOptions": { + "types": ["vite/client", "@vben/types/global"] + } +} diff --git a/internal/tsconfig/web.json b/internal/tsconfig/web.json new file mode 100644 index 00000000..a4b60cec --- /dev/null +++ b/internal/tsconfig/web.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Web Package", + "extends": "./base.json", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "vue", + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "useDefineForClassFields": true, + "moduleResolution": "bundler", + "types": ["vite/client"], + "declaration": false + } +} diff --git a/internal/vite-config/build.config.ts b/internal/vite-config/build.config.ts new file mode 100644 index 00000000..97e572c5 --- /dev/null +++ b/internal/vite-config/build.config.ts @@ -0,0 +1,7 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + declaration: true, + entries: ['src/index'], +}); diff --git a/internal/vite-config/package.json b/internal/vite-config/package.json new file mode 100644 index 00000000..16926623 --- /dev/null +++ b/internal/vite-config/package.json @@ -0,0 +1,56 @@ +{ + "name": "@vben/vite-config", + "version": "5.1.2", + "private": true, + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "internal/vite-config" + }, + "license": "MIT", + "type": "module", + "scripts": { + "stub": "pnpm unbuild --stub" + }, + "files": [ + "dist" + ], + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./dist/index.mjs" + } + }, + "dependencies": { + "@intlify/unplugin-vue-i18n": "^4.0.0", + "@jspm/generator": "^2.1.3", + "cheerio": "1.0.0", + "get-port": "^7.1.0", + "html-minifier-terser": "^7.2.0", + "nitropack": "^2.9.7", + "resolve.exports": "^2.0.2", + "vite-plugin-lib-inject-css": "^2.1.1", + "vite-plugin-pwa": "^0.20.1", + "vite-plugin-vue-devtools": "^7.3.9" + }, + "devDependencies": { + "@types/html-minifier-terser": "^7.0.2", + "@vben/node-utils": "workspace:*", + "@vitejs/plugin-vue": "^5.1.2", + "@vitejs/plugin-vue-jsx": "^4.0.1", + "dayjs": "^1.11.13", + "dotenv": "^16.4.5", + "rollup": "^4.21.1", + "rollup-plugin-visualizer": "^5.12.0", + "sass": "^1.77.8", + "vite": "^5.4.2", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-dts": "4.0.3", + "vite-plugin-html": "^3.2.2" + } +} diff --git a/internal/vite-config/src/config/application.ts b/internal/vite-config/src/config/application.ts new file mode 100644 index 00000000..fd05f3b4 --- /dev/null +++ b/internal/vite-config/src/config/application.ts @@ -0,0 +1,115 @@ +import type { UserConfig } from 'vite'; + +import type { DefineApplicationOptions } from '../typing'; + +import path, { relative } from 'node:path'; + +import { findMonorepoRoot } from '@vben/node-utils'; + +import { defineConfig, loadEnv, mergeConfig } from 'vite'; + +import { defaultImportmapOptions, getDefaultPwaOptions } from '../options'; +import { loadApplicationPlugins } from '../plugins'; +import { loadAndConvertEnv } from '../utils/env'; +import { getCommonConfig } from './common'; + +function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) { + return defineConfig(async (config) => { + const options = await userConfigPromise?.(config); + const { appTitle, base, port, ...envConfig } = await loadAndConvertEnv(); + const { command, mode } = config; + const { application = {}, vite = {} } = options || {}; + const root = process.cwd(); + const isBuild = command === 'build'; + const env = loadEnv(mode, root); + + const plugins = await loadApplicationPlugins({ + compress: false, + compressTypes: ['brotli', 'gzip'], + devtools: true, + env, + extraAppConfig: true, + html: true, + i18n: true, + importmapOptions: defaultImportmapOptions, + injectAppLoading: true, + injectMetadata: true, + isBuild, + license: true, + mode, + nitroMock: !isBuild, + nitroMockOptions: {}, + print: !isBuild, + printInfoMap: { + 'Vben Admin Docs': 'https://doc.vben.pro', + }, + pwa: true, + pwaOptions: getDefaultPwaOptions(appTitle), + ...envConfig, + ...application, + }); + + const { injectGlobalScss = true } = application; + + const applicationConfig: UserConfig = { + base, + build: { + rollupOptions: { + output: { + assetFileNames: '[ext]/[name]-[hash].[ext]', + chunkFileNames: 'js/[name]-[hash].mjs', + entryFileNames: 'jse/index-[name]-[hash].mjs', + }, + }, + target: 'es2015', + }, + css: createCssOptions(injectGlobalScss), + esbuild: { + drop: isBuild + ? [ + // 'console', + 'debugger', + ] + : [], + legalComments: 'none', + }, + plugins, + server: { + host: true, + port, + warmup: { + // 预热文件 + clientFiles: ['./index.html', './src/{views,layouts,router,store}/*'], + }, + }, + }; + + const mergedCommonConfig = mergeConfig( + await getCommonConfig(), + applicationConfig, + ); + return mergeConfig(mergedCommonConfig, vite); + }); +} + +function createCssOptions(injectGlobalScss = true) { + const root = findMonorepoRoot(); + return { + preprocessorOptions: injectGlobalScss + ? { + scss: { + additionalData: (content: string, filepath: string) => { + const relativePath = relative(root, filepath); + // apps下的包注入全局样式 + if (relativePath.startsWith(`apps${path.sep}`)) { + return `@import "@vben/styles/global";\n${content}`; + } + return content; + }, + }, + } + : {}, + }; +} + +export { defineApplicationConfig }; diff --git a/internal/vite-config/src/config/common.ts b/internal/vite-config/src/config/common.ts new file mode 100644 index 00000000..2addff0c --- /dev/null +++ b/internal/vite-config/src/config/common.ts @@ -0,0 +1,13 @@ +import type { UserConfig } from 'vite'; + +async function getCommonConfig(): Promise { + return { + build: { + chunkSizeWarningLimit: 1000, + reportCompressedSize: false, + sourcemap: false, + }, + }; +} + +export { getCommonConfig }; diff --git a/internal/vite-config/src/config/index.ts b/internal/vite-config/src/config/index.ts new file mode 100644 index 00000000..56ad3d40 --- /dev/null +++ b/internal/vite-config/src/config/index.ts @@ -0,0 +1,37 @@ +import type { DefineConfig } from '../typing'; + +import { existsSync } from 'node:fs'; +import { join } from 'node:path'; + +import { defineApplicationConfig } from './application'; +import { defineLibraryConfig } from './library'; + +export * from './application'; +export * from './library'; + +function defineConfig( + userConfigPromise?: DefineConfig, + type: 'application' | 'auto' | 'library' = 'auto', +) { + let projectType = type; + + // 根据包是否存在 index.html,自动判断类型 + if (type === 'auto') { + const htmlPath = join(process.cwd(), 'index.html'); + projectType = existsSync(htmlPath) ? 'application' : 'library'; + } + + switch (projectType) { + case 'application': { + return defineApplicationConfig(userConfigPromise); + } + case 'library': { + return defineLibraryConfig(userConfigPromise); + } + default: { + throw new Error(`Unsupported project type: ${projectType}`); + } + } +} + +export { defineConfig }; diff --git a/internal/vite-config/src/config/library.ts b/internal/vite-config/src/config/library.ts new file mode 100644 index 00000000..759fc7bc --- /dev/null +++ b/internal/vite-config/src/config/library.ts @@ -0,0 +1,60 @@ +import type { ConfigEnv, UserConfig } from 'vite'; + +import type { DefineLibraryOptions } from '../typing'; + +import { readPackageJSON } from '@vben/node-utils'; + +import { defineConfig, mergeConfig } from 'vite'; + +import { loadLibraryPlugins } from '../plugins'; +import { getCommonConfig } from './common'; + +function defineLibraryConfig(userConfigPromise?: DefineLibraryOptions) { + return defineConfig(async (config: ConfigEnv) => { + const options = await userConfigPromise?.(config); + const { command, mode } = config; + const { library = {}, vite = {} } = options || {}; + const root = process.cwd(); + const isBuild = command === 'build'; + + const plugins = await loadLibraryPlugins({ + dts: false, + injectLibCss: true, + injectMetadata: true, + isBuild, + mode, + ...library, + }); + + const { dependencies = {}, peerDependencies = {} } = + await readPackageJSON(root); + + const externalPackages = [ + ...Object.keys(dependencies), + ...Object.keys(peerDependencies), + ]; + + const packageConfig: UserConfig = { + build: { + lib: { + entry: 'src/index.ts', + fileName: () => 'index.mjs', + formats: ['es'], + }, + rollupOptions: { + external: (id) => { + return externalPackages.some( + (pkg) => id === pkg || id.startsWith(`${pkg}/`), + ); + }, + }, + }, + plugins, + }; + const commonConfig = await getCommonConfig(); + const mergedConmonConfig = mergeConfig(commonConfig, packageConfig); + return mergeConfig(mergedConmonConfig, vite); + }); +} + +export { defineLibraryConfig }; diff --git a/internal/vite-config/src/index.ts b/internal/vite-config/src/index.ts new file mode 100644 index 00000000..352a3235 --- /dev/null +++ b/internal/vite-config/src/index.ts @@ -0,0 +1,4 @@ +export * from './config'; +export * from './options'; +export * from './plugins'; +export { loadAndConvertEnv } from './utils/env'; diff --git a/internal/vite-config/src/options.ts b/internal/vite-config/src/options.ts new file mode 100644 index 00000000..323eee1e --- /dev/null +++ b/internal/vite-config/src/options.ts @@ -0,0 +1,45 @@ +import type { Options as PwaPluginOptions } from 'vite-plugin-pwa'; + +import type { ImportmapPluginOptions } from './typing'; + +const isDevelopment = process.env.NODE_ENV === 'development'; + +const getDefaultPwaOptions = (name: string): Partial => ({ + manifest: { + description: + 'Vben Admin is a modern admin dashboard template based on Vue 3. ', + icons: [ + { + sizes: '192x192', + src: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/pwa-icon-192.png', + type: 'image/png', + }, + { + sizes: '512x512', + src: 'https://unpkg.com/@vbenjs/static-source@0.1.6/source/pwa-icon-512.png', + type: 'image/png', + }, + ], + name: `${name}${isDevelopment ? ' dev' : ''}`, + short_name: `${name}${isDevelopment ? ' dev' : ''}`, + }, +}); + +/** + * importmap CDN 暂时不开启,因为有些包不支持,且网络不稳定 + */ +const defaultImportmapOptions: ImportmapPluginOptions = { + // 通过 Importmap CDN 方式引入, + // 目前只有esm.sh源兼容性好一点,jspm.io对于 esm 入口要求高 + defaultProvider: 'esm.sh', + importmap: [ + { name: 'vue' }, + { name: 'pinia' }, + { name: 'vue-router' }, + // { name: 'vue-i18n' }, + { name: 'dayjs' }, + { name: 'vue-demi' }, + ], +}; + +export { defaultImportmapOptions, getDefaultPwaOptions }; diff --git a/internal/vite-config/src/plugins/extra-app-config.ts b/internal/vite-config/src/plugins/extra-app-config.ts new file mode 100644 index 00000000..813819bb --- /dev/null +++ b/internal/vite-config/src/plugins/extra-app-config.ts @@ -0,0 +1,92 @@ +import type { PluginOption } from 'vite'; + +import { + colors, + generatorContentHash, + readPackageJSON, +} from '@vben/node-utils'; + +import { loadEnv } from '../utils/env'; + +interface PluginOptions { + isBuild: boolean; + root: string; +} + +const GLOBAL_CONFIG_FILE_NAME = '_app.config.js'; +const VBEN_ADMIN_PRO_APP_CONF = '_VBEN_ADMIN_PRO_APP_CONF_'; + +/** + * 用于将配置文件抽离出来并注入到项目中 + * @returns + */ + +async function viteExtraAppConfigPlugin({ + isBuild, + root, +}: PluginOptions): Promise { + let publicPath: string; + let source: string; + + if (!isBuild) { + return; + } + + const { version = '' } = await readPackageJSON(root); + + return { + async configResolved(config) { + publicPath = ensureTrailingSlash(config.base); + source = await getConfigSource(); + }, + async generateBundle() { + try { + this.emitFile({ + fileName: GLOBAL_CONFIG_FILE_NAME, + source, + type: 'asset', + }); + + console.log(colors.cyan(`✨configuration file is build successfully!`)); + } catch (error) { + console.log( + colors.red( + `configuration file configuration file failed to package:\n${error}`, + ), + ); + } + }, + name: 'vite:extra-app-config', + async transformIndexHtml(html) { + const hash = `v=${version}-${generatorContentHash(source, 8)}`; + + const appConfigSrc = `${publicPath}${GLOBAL_CONFIG_FILE_NAME}?${hash}`; + + return { + html, + tags: [{ attrs: { src: appConfigSrc }, tag: 'script' }], + }; + }, + }; +} + +async function getConfigSource() { + const config = await loadEnv(); + const windowVariable = `window.${VBEN_ADMIN_PRO_APP_CONF}`; + // 确保变量不会被修改 + let source = `${windowVariable}=${JSON.stringify(config)};`; + source += ` + Object.freeze(${windowVariable}); + Object.defineProperty(window, "${VBEN_ADMIN_PRO_APP_CONF}", { + configurable: false, + writable: false, + }); + `.replaceAll(/\s/g, ''); + return source; +} + +function ensureTrailingSlash(path: string) { + return path.endsWith('/') ? path : `${path}/`; +} + +export { viteExtraAppConfigPlugin }; diff --git a/internal/vite-config/src/plugins/importmap.ts b/internal/vite-config/src/plugins/importmap.ts new file mode 100644 index 00000000..c6154c9e --- /dev/null +++ b/internal/vite-config/src/plugins/importmap.ts @@ -0,0 +1,245 @@ +/** + * 参考 https://github.com/jspm/vite-plugin-jspm,调整为需要的功能 + */ +import type { GeneratorOptions } from '@jspm/generator'; +import type { Plugin } from 'vite'; + +import { Generator } from '@jspm/generator'; +import { load } from 'cheerio'; +import { minify } from 'html-minifier-terser'; + +const DEFAULT_PROVIDER = 'jspm.io'; + +type pluginOptions = { + debug?: boolean; + defaultProvider?: 'esm.sh' | 'jsdelivr' | 'jspm.io'; + importmap?: Array<{ name: string; range?: string }>; +} & GeneratorOptions; + +// async function getLatestVersionOfShims() { +// const result = await fetch('https://ga.jspm.io/npm:es-module-shims'); +// const version = result.text(); +// return version; +// } + +async function getShimsUrl(provide: string) { + // const version = await getLatestVersionOfShims(); + const version = '1.10.0'; + + const shimsSubpath = `dist/es-module-shims.js`; + const providerShimsMap: Record = { + 'esm.sh': `https://esm.sh/es-module-shims@${version}/${shimsSubpath}`, + // unpkg: `https://unpkg.com/es-module-shims@${version}/${shimsSubpath}`, + jsdelivr: `https://cdn.jsdelivr.net/npm/es-module-shims@${version}/${shimsSubpath}`, + + // 下面两个CDN不稳定,暂时不用 + 'jspm.io': `https://ga.jspm.io/npm:es-module-shims@${version}/${shimsSubpath}`, + }; + + return providerShimsMap[provide] || providerShimsMap[DEFAULT_PROVIDER]; +} + +let generator: Generator; + +async function viteImportMapPlugin( + pluginOptions?: pluginOptions, +): Promise { + const { importmap } = pluginOptions || {}; + + let isSSR = false; + let isBuild = false; + let installed = false; + let installError: Error | null = null; + + const options: pluginOptions = Object.assign( + {}, + { + debug: false, + defaultProvider: 'jspm.io', + env: ['production', 'browser', 'module'], + importmap: [], + }, + pluginOptions, + ); + + generator = new Generator({ + ...options, + baseUrl: process.cwd(), + }); + + if (options?.debug) { + (async () => { + for await (const { message, type } of generator.logStream()) { + console.log(`${type}: ${message}`); + } + })(); + } + + const imports = options.inputMap?.imports ?? {}; + const scopes = options.inputMap?.scopes ?? {}; + const firstLayerKeys = Object.keys(scopes); + const inputMapScopes: string[] = []; + firstLayerKeys.forEach((key) => { + inputMapScopes.push(...Object.keys(scopes[key] || {})); + }); + const inputMapImports = Object.keys(imports); + + const allDepNames: string[] = [ + ...(importmap?.map((item) => item.name) || []), + ...inputMapImports, + ...inputMapScopes, + ]; + const depNames = new Set(allDepNames); + + const installDeps = importmap?.map((item) => ({ + range: item.range, + target: item.name, + })); + + return [ + { + async config(_, { command, isSsrBuild }) { + isBuild = command === 'build'; + isSSR = !!isSsrBuild; + }, + enforce: 'pre', + name: 'importmap:external', + resolveId(id) { + if (isSSR || !isBuild) { + return null; + } + + if (!depNames.has(id)) { + return null; + } + return { external: true, id }; + }, + }, + { + enforce: 'post', + name: 'importmap:install', + async resolveId() { + if (isSSR || !isBuild || installed) { + return null; + } + try { + installed = true; + await Promise.allSettled( + (installDeps || []).map((dep) => generator.install(dep)), + ); + } catch (error: any) { + installError = error; + installed = false; + } + return null; + }, + }, + { + buildEnd() { + // 未生成importmap时,抛出错误,防止被turbo缓存 + if (!installed && !isSSR) { + installError && console.error(installError); + throw new Error('Importmap installation failed.'); + } + }, + enforce: 'post', + name: 'importmap:html', + transformIndexHtml: { + async handler(html) { + if (isSSR || !isBuild) { + return html; + } + + const importmapJson = generator.getMap(); + + if (!importmapJson) { + return html; + } + + const esModuleShimsSrc = await getShimsUrl( + options.defaultProvider || DEFAULT_PROVIDER, + ); + + const resultHtml = await injectShimsToHtml( + html, + esModuleShimsSrc || '', + ); + html = await minify(resultHtml || html, { + collapseWhitespace: true, + minifyCSS: true, + minifyJS: true, + removeComments: false, + }); + + return { + html, + tags: [ + { + attrs: { + type: 'importmap', + }, + injectTo: 'head-prepend', + tag: 'script', + children: `${JSON.stringify(importmapJson)}`, + }, + ], + }; + }, + order: 'post', + }, + }, + ]; +} + +async function injectShimsToHtml(html: string, esModuleShimUrl: string) { + const $ = load(html); + + const $script = $(`script[type='module']`); + + if (!$script) { + return; + } + + const entry = $script.attr('src'); + + $script.removeAttr('type'); + $script.removeAttr('crossorigin'); + $script.removeAttr('src'); + $script.html(` +if (!HTMLScriptElement.supports || !HTMLScriptElement.supports('importmap')) { + self.importShim = function () { + const promise = new Promise((resolve, reject) => { + document.head.appendChild( + Object.assign(document.createElement('script'), { + src: '${esModuleShimUrl}', + crossorigin: 'anonymous', + async: true, + onload() { + if (!importShim.$proxy) { + resolve(importShim); + } else { + reject(new Error('No globalThis.importShim found:' + esModuleShimUrl)); + } + }, + onerror(error) { + reject(error); + }, + }), + ); + }); + importShim.$proxy = true; + return promise.then((importShim) => importShim(...arguments)); + }; +} + +var modules = ['${entry}']; +typeof importShim === 'function' + ? modules.forEach((moduleName) => importShim(moduleName)) + : modules.forEach((moduleName) => import(moduleName)); + `); + $('body').after($script); + $('head').remove(`script[type='module']`); + return $.html(); +} + +export { viteImportMapPlugin }; diff --git a/internal/vite-config/src/plugins/index.ts b/internal/vite-config/src/plugins/index.ts new file mode 100644 index 00000000..c497edd3 --- /dev/null +++ b/internal/vite-config/src/plugins/index.ts @@ -0,0 +1,233 @@ +import type { PluginOption } from 'vite'; + +import type { + ApplicationPluginOptions, + CommonPluginOptions, + ConditionPlugin, + LibraryPluginOptions, +} from '../typing'; + +import viteVueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'; +import viteVue from '@vitejs/plugin-vue'; +import viteVueJsx from '@vitejs/plugin-vue-jsx'; +import { visualizer as viteVisualizerPlugin } from 'rollup-plugin-visualizer'; +import viteCompressPlugin from 'vite-plugin-compression'; +import viteDtsPlugin from 'vite-plugin-dts'; +import { createHtmlPlugin as viteHtmlPlugin } from 'vite-plugin-html'; +import { libInjectCss as viteLibInjectCss } from 'vite-plugin-lib-inject-css'; +import { VitePWA } from 'vite-plugin-pwa'; +import viteVueDevTools from 'vite-plugin-vue-devtools'; + +import { viteExtraAppConfigPlugin } from './extra-app-config'; +import { viteImportMapPlugin } from './importmap'; +import { viteInjectAppLoadingPlugin } from './inject-app-loading'; +import { viteMetadataPlugin } from './inject-metadata'; +import { viteLicensePlugin } from './license'; +import { viteNitroMockPlugin } from './nitro-mock'; +import { vitePrintPlugin } from './print'; + +/** + * 获取条件成立的 vite 插件 + * @param conditionPlugins + */ +async function loadConditionPlugins(conditionPlugins: ConditionPlugin[]) { + const plugins: PluginOption[] = []; + for (const conditionPlugin of conditionPlugins) { + if (conditionPlugin.condition) { + const realPlugins = await conditionPlugin.plugins(); + plugins.push(...realPlugins); + } + } + return plugins.flat(); +} + +/** + * 根据条件获取通用的vite插件 + */ +async function loadCommonPlugins( + options: CommonPluginOptions, +): Promise { + const { devtools, injectMetadata, isBuild, visualizer } = options; + return [ + { + condition: true, + plugins: () => [ + viteVue({ + script: { + defineModel: true, + // propsDestructure: true, + }, + }), + viteVueJsx(), + ], + }, + + { + condition: !isBuild && devtools, + plugins: () => [viteVueDevTools()], + }, + { + condition: injectMetadata, + plugins: async () => [await viteMetadataPlugin()], + }, + { + condition: isBuild && !!visualizer, + plugins: () => [viteVisualizerPlugin({ + filename: './node_modules/.cache/visualizer/stats.html', + gzipSize: true, + open: true, + })], + }, + ]; +} + +/** + * 根据条件获取应用类型的vite插件 + */ +async function loadApplicationPlugins( + options: ApplicationPluginOptions, +): Promise { + // 单独取,否则commonOptions拿不到 + const isBuild = options.isBuild; + const env = options.env; + + const { + compress, + compressTypes, + extraAppConfig, + html, + i18n, + importmap, + importmapOptions, + injectAppLoading, + license, + nitroMock, + nitroMockOptions, + print, + printInfoMap, + pwa, + pwaOptions, + ...commonOptions + } = options; + + const commonPlugins = await loadCommonPlugins(commonOptions); + + return await loadConditionPlugins([ + ...commonPlugins, + { + condition: i18n, + plugins: async () => { + return [ + viteVueI18nPlugin({ + compositionOnly: true, + fullInstall: true, + runtimeOnly: true, + }), + ]; + }, + }, + { + condition: print, + plugins: async () => { + return [await vitePrintPlugin({ infoMap: printInfoMap })]; + }, + }, + { + condition: nitroMock, + plugins: async () => { + return [await viteNitroMockPlugin(nitroMockOptions)]; + }, + }, + { + condition: injectAppLoading, + plugins: async () => [await viteInjectAppLoadingPlugin(!!isBuild, env)], + }, + { + condition: license, + plugins: async () => [await viteLicensePlugin()], + }, + { + condition: pwa, + plugins: () => + VitePWA({ + injectRegister: false, + workbox: { + globPatterns: [], + }, + ...pwaOptions, + manifest: { + display: 'standalone', + start_url: '/', + theme_color: '#ffffff', + ...pwaOptions?.manifest, + }, + }), + }, + { + condition: isBuild && !!compress, + plugins: () => { + const compressPlugins: PluginOption[] = []; + if (compressTypes?.includes('brotli')) { + compressPlugins.push( + viteCompressPlugin({ deleteOriginFile: false, ext: '.br' }), + ); + } + if (compressTypes?.includes('gzip')) { + compressPlugins.push( + viteCompressPlugin({ deleteOriginFile: false, ext: '.gz' }), + ); + } + return compressPlugins; + }, + }, + { + condition: !!html, + plugins: () => [viteHtmlPlugin({ minify: true })], + }, + + { + condition: isBuild && importmap, + plugins: () => { + return [viteImportMapPlugin(importmapOptions)]; + }, + }, + { + condition: isBuild && extraAppConfig, + plugins: async () => [ + await viteExtraAppConfigPlugin({ isBuild: true, root: process.cwd() }), + ], + }, + ]); +} + +/** + * 根据条件获取库类型的vite插件 + */ +async function loadLibraryPlugins( + options: LibraryPluginOptions, +): Promise { + // 单独取,否则commonOptions拿不到 + const isBuild = options.isBuild; + const { dts, injectLibCss, ...commonOptions } = options; + const commonPlugins = await loadCommonPlugins(commonOptions); + return await loadConditionPlugins([ + ...commonPlugins, + { + condition: isBuild && !!dts, + plugins: () => [viteDtsPlugin({ logLevel: 'error' })], + }, + { + condition: injectLibCss, + plugins: () => [viteLibInjectCss()], + }, + ]); +} + +export { + loadApplicationPlugins, + loadLibraryPlugins, + viteCompressPlugin, + viteDtsPlugin, + viteHtmlPlugin, + viteVisualizerPlugin, +}; diff --git a/internal/vite-config/src/plugins/inject-app-loading/README.md b/internal/vite-config/src/plugins/inject-app-loading/README.md new file mode 100644 index 00000000..8d2358f7 --- /dev/null +++ b/internal/vite-config/src/plugins/inject-app-loading/README.md @@ -0,0 +1,3 @@ +# inject-app-loading + +用于在应用加载时显示加载动画的插件,可自行选择加载动画的样式。 diff --git a/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html b/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html new file mode 100644 index 00000000..20a21fb7 --- /dev/null +++ b/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html @@ -0,0 +1,107 @@ + +
+ +
<%= VITE_APP_TITLE %>
+
diff --git a/internal/vite-config/src/plugins/inject-app-loading/default-loading.html b/internal/vite-config/src/plugins/inject-app-loading/default-loading.html new file mode 100644 index 00000000..28957058 --- /dev/null +++ b/internal/vite-config/src/plugins/inject-app-loading/default-loading.html @@ -0,0 +1,113 @@ + +
+
+
<%= VITE_APP_TITLE %>
+
diff --git a/internal/vite-config/src/plugins/inject-app-loading/index.ts b/internal/vite-config/src/plugins/inject-app-loading/index.ts new file mode 100644 index 00000000..9f6e2a5c --- /dev/null +++ b/internal/vite-config/src/plugins/inject-app-loading/index.ts @@ -0,0 +1,66 @@ +import fs from 'node:fs'; +import fsp from 'node:fs/promises'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { readPackageJSON } from '@vben/node-utils'; + +import { type PluginOption } from 'vite'; + +/** + * 用于生成将loading样式注入到项目中 + * 为多app提供loading样式,无需在每个 app -> index.html单独引入 + */ +async function viteInjectAppLoadingPlugin( + isBuild: boolean, + env: Record = {}, + loadingTemplate = 'loading.html', +): Promise { + const loadingHtml = await getLoadingRawByHtmlTemplate(loadingTemplate); + const { version } = await readPackageJSON(process.cwd()); + const envRaw = isBuild ? 'prod' : 'dev'; + const cacheName = `'${env.VITE_APP_NAMESPACE}-${version}-${envRaw}-preferences-theme'`; + + // 获取缓存的主题 + // 保证黑暗主题下,刷新页面时,loading也是黑暗主题 + const injectScript = ` + +`; + + if (!loadingHtml) { + return; + } + + return { + enforce: 'pre', + name: 'vite:inject-app-loading', + transformIndexHtml: { + handler(html) { + const re = //; + html = html.replace(re, `${injectScript}${loadingHtml}`); + return html; + }, + order: 'pre', + }, + }; +} + +/** + * 用于获取loading的html模板 + */ +async function getLoadingRawByHtmlTemplate(loadingTemplate: string) { + // 支持在app内自定义loading模板,模版参考default-loading.html即可 + let appLoadingPath = join(process.cwd(), loadingTemplate); + + if (!fs.existsSync(appLoadingPath)) { + const __dirname = fileURLToPath(new URL('.', import.meta.url)); + appLoadingPath = join(__dirname, './default-loading.html'); + } + + return await fsp.readFile(appLoadingPath, 'utf8'); +} + +export { viteInjectAppLoadingPlugin }; diff --git a/internal/vite-config/src/plugins/inject-metadata.ts b/internal/vite-config/src/plugins/inject-metadata.ts new file mode 100644 index 00000000..2731412f --- /dev/null +++ b/internal/vite-config/src/plugins/inject-metadata.ts @@ -0,0 +1,86 @@ +import type { PluginOption } from 'vite'; + +import { dateUtil, getPackages, readPackageJSON } from '@vben/node-utils'; + +function resolvePackageVersion( + pkgsMeta: Record, + name: string, + value: string, +) { + if (value.includes('workspace')) { + return pkgsMeta[name]; + } + return value; +} + +async function resolveMonorepoDependencies() { + const { packages } = await getPackages(); + + const resultDevDependencies: Record = {}; + const resultDependencies: Record = {}; + const pkgsMeta: Record = {}; + + for (const { packageJson } of packages) { + pkgsMeta[packageJson.name] = packageJson.version; + } + + for (const { packageJson } of packages) { + const { dependencies = {}, devDependencies = {} } = packageJson; + for (const [key, value] of Object.entries(dependencies)) { + resultDependencies[key] = resolvePackageVersion(pkgsMeta, key, value); + } + for (const [key, value] of Object.entries(devDependencies)) { + resultDevDependencies[key] = resolvePackageVersion(pkgsMeta, key, value); + } + } + return { + dependencies: resultDependencies, + devDependencies: resultDevDependencies, + }; +} + +/** + * 用于注入项目信息 + */ +async function viteMetadataPlugin( + root = process.cwd(), +): Promise { + const { author, description, homepage, license, version } = + await readPackageJSON(root); + + const buildTime = dateUtil().format('YYYY-MM-DD HH:mm:ss'); + + return { + async config() { + const { dependencies, devDependencies } = + await resolveMonorepoDependencies(); + + const isAuthorObject = typeof author === 'object'; + const authorName = isAuthorObject ? author.name : author; + const authorEmail = isAuthorObject ? author.email : null; + const authorUrl = isAuthorObject ? author.url : null; + + return { + define: { + __VBEN_ADMIN_METADATA__: JSON.stringify({ + authorEmail, + authorName, + authorUrl, + buildTime, + dependencies, + description, + devDependencies, + homepage, + license, + version, + }), + 'import.meta.env.VITE_APP_VERSION': JSON.stringify(version), + }, + }; + }, + enforce: 'post', + name: 'vite:inject-metadata', + }; +} + +export { viteMetadataPlugin }; diff --git a/internal/vite-config/src/plugins/license.ts b/internal/vite-config/src/plugins/license.ts new file mode 100644 index 00000000..81fc4ff0 --- /dev/null +++ b/internal/vite-config/src/plugins/license.ts @@ -0,0 +1,63 @@ +import type { + NormalizedOutputOptions, + OutputBundle, + OutputChunk, +} from 'rollup'; +import type { PluginOption } from 'vite'; + +import { EOL } from 'node:os'; + +import { dateUtil, readPackageJSON } from '@vben/node-utils'; + +/** + * 用于注入版权信息 + * @returns + */ + +async function viteLicensePlugin( + root = process.cwd(), +): Promise { + const { + description = '', + homepage = '', + version = '', + } = await readPackageJSON(root); + + return { + apply: 'build', + enforce: 'post', + generateBundle: { + handler: (_options: NormalizedOutputOptions, bundle: OutputBundle) => { + const date = dateUtil().format('YYYY-MM-DD '); + const copyrightText = `/*! + * Vben Admin + * Version: ${version} + * Author: vben + * Copyright (C) 2024 Vben + * License: MIT License + * Description: ${description} + * Date Created: ${date} + * Homepage: ${homepage} + * Contact: ann.vben@gmail.com +*/ + `.trim(); + + for (const [, fileContent] of Object.entries(bundle)) { + if (fileContent.type === 'chunk' && fileContent.isEntry) { + const chunkContent = fileContent as OutputChunk; + // 插入版权信息 + const content = chunkContent.code; + const updatedContent = `${copyrightText}${EOL}${content}`; + + // 更新bundle + (fileContent as OutputChunk).code = updatedContent; + } + } + }, + order: 'post', + }, + name: 'vite:license', + }; +} + +export { viteLicensePlugin }; diff --git a/internal/vite-config/src/plugins/nitro-mock.ts b/internal/vite-config/src/plugins/nitro-mock.ts new file mode 100644 index 00000000..60d7327d --- /dev/null +++ b/internal/vite-config/src/plugins/nitro-mock.ts @@ -0,0 +1,98 @@ +import type { PluginOption } from 'vite'; + +import type { NitroMockPluginOptions } from '../typing'; + +import { colors, consola, getPackage } from '@vben/node-utils'; + +import getPort from 'get-port'; +import { build, createDevServer, createNitro, prepare } from 'nitropack'; + +const hmrKeyRe = /^runtimeConfig\.|routeRules\./; + +export const viteNitroMockPlugin = ({ + mockServerPackage = '@vben/backend-mock', + port = 5320, + verbose = true, +}: NitroMockPluginOptions = {}): PluginOption => { + return { + async configureServer(server) { + const availablePort = await getPort({ port }); + if (availablePort !== port) { + return; + } + + const pkg = await getPackage(mockServerPackage); + if (!pkg) { + consola.log( + `Package ${mockServerPackage} not found. Skip mock server.`, + ); + return; + } + + runNitroServer(pkg.dir, port, verbose); + + const _printUrls = server.printUrls; + server.printUrls = () => { + _printUrls(); + + consola.log( + ` ${colors.green('➜')} ${colors.bold('Nitro Mock Server')}: ${colors.cyan(`http://localhost:${port}/api`)}`, + ); + }; + }, + enforce: 'pre', + name: 'vite:mock-server', + }; +}; + +async function runNitroServer(rootDir: string, port: number, verbose: boolean) { + let nitro: any; + const reload = async () => { + if (nitro) { + consola.info('Restarting dev server...'); + if ('unwatch' in nitro.options._c12) { + await nitro.options._c12.unwatch(); + } + await nitro.close(); + } + nitro = await createNitro( + { + dev: true, + preset: 'nitro-dev', + rootDir, + }, + { + c12: { + async onUpdate({ getDiff, newConfig }) { + const diff = getDiff(); + if (diff.length === 0) { + return; + } + verbose && + consola.info( + `Nitro config updated:\n${diff + .map((entry) => ` ${entry.toString()}`) + .join('\n')}`, + ); + await (diff.every((e) => hmrKeyRe.test(e.key)) + ? nitro.updateConfig(newConfig.config) + : reload()); + }, + }, + watch: true, + }, + ); + nitro.hooks.hookOnce('restart', reload); + + const server = createDevServer(nitro); + await server.listen(port, { showURL: false }); + await prepare(nitro); + await build(nitro); + + if (verbose) { + console.log(''); + consola.success(colors.bold(colors.green('Nitro Mock Server started.'))); + } + }; + return await reload(); +} diff --git a/internal/vite-config/src/plugins/print.ts b/internal/vite-config/src/plugins/print.ts new file mode 100644 index 00000000..0146b8a2 --- /dev/null +++ b/internal/vite-config/src/plugins/print.ts @@ -0,0 +1,28 @@ +import type { PluginOption } from 'vite'; + +import type { PrintPluginOptions } from '../typing'; + +import { colors } from '@vben/node-utils'; + +export const vitePrintPlugin = ( + options: PrintPluginOptions = {}, +): PluginOption => { + const { infoMap = {} } = options; + + return { + configureServer(server) { + const _printUrls = server.printUrls; + server.printUrls = () => { + _printUrls(); + + for (const [key, value] of Object.entries(infoMap)) { + console.log( + ` ${colors.green('➜')} ${colors.bold(key)}: ${colors.cyan(value)}`, + ); + } + }; + }, + enforce: 'pre', + name: 'vite:print-info', + }; +}; diff --git a/internal/vite-config/src/typing.ts b/internal/vite-config/src/typing.ts new file mode 100644 index 00000000..86609c62 --- /dev/null +++ b/internal/vite-config/src/typing.ts @@ -0,0 +1,147 @@ +import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer'; +import type { ConfigEnv, PluginOption, UserConfig } from 'vite'; +import type { PluginOptions } from 'vite-plugin-dts'; +import type { Options as PwaPluginOptions } from 'vite-plugin-pwa'; + +interface IImportMap { + imports?: Record; + scopes?: { + [scope: string]: Record; + }; +} +interface PrintPluginOptions { + /** + * 打印的数据 + */ + infoMap?: Record; +} + +interface NitroMockPluginOptions { + /** + * mock server 包名 + */ + mockServerPackage?: string; + + /** + * mock 服务端口 + */ + port?: number; + + /** + * mock 日志是否打印 + */ + verbose?: boolean; +} + +/** + * importmap 插件配置 + */ +interface ImportmapPluginOptions { + /** + * CDN 供应商 + * @default jspm.io + */ + defaultProvider?: 'esm.sh' | 'jspm.io'; + /** importmap 配置 */ + importmap?: Array<{ name: string; range?: string }>; + /** 手动配置importmap */ + inputMap?: IImportMap; +} + +/** + * 用于判断是否需要加载插件 + */ +interface ConditionPlugin { + // 判断条件 + condition?: boolean; + // 插件对象 + plugins: () => PluginOption[] | PromiseLike; +} + +interface CommonPluginOptions { + /** 是否开启devtools */ + devtools?: boolean; + /** 环境变量 */ + env?: Record; + /** 是否注入metadata */ + injectMetadata?: boolean; + /** 是否构建模式 */ + isBuild?: boolean; + /** 构建模式 */ + mode?: string; + /** 开启依赖分析 */ + visualizer?: boolean | PluginVisualizerOptions; +} + +interface ApplicationPluginOptions extends CommonPluginOptions { + /** 开启 gzip|brotli 压缩 */ + compress?: boolean; + /** 压缩类型 */ + compressTypes?: ('brotli' | 'gzip')[]; + /** 在构建的时候抽离配置文件 */ + extraAppConfig?: boolean; + /** 是否开启html插件 */ + html?: boolean; + /** 是否开启i18n */ + i18n?: boolean; + /** 是否开启 importmap CDN */ + importmap?: boolean; + /** importmap 插件配置 */ + importmapOptions?: ImportmapPluginOptions; + /** 是否注入app loading */ + injectAppLoading?: boolean; + /** 是否注入全局scss */ + injectGlobalScss?: boolean; + /** 是否注入版权信息 */ + license?: boolean; + /** 是否开启nitro mock */ + nitroMock?: boolean; + /** nitro mock 插件配置 */ + nitroMockOptions?: NitroMockPluginOptions; + /** 开启控制台自定义打印 */ + print?: boolean; + /** 打印插件配置 */ + printInfoMap?: PrintPluginOptions['infoMap']; + /** 是否开启pwa */ + pwa?: boolean; + /** pwa 插件配置 */ + pwaOptions?: Partial; +} + +interface LibraryPluginOptions extends CommonPluginOptions { + /** 开启 dts 输出 */ + dts?: boolean | PluginOptions; + + /** 是否注入lib css */ + injectLibCss?: boolean; +} + +type ApplicationOptions = ApplicationPluginOptions; + +type LibraryOptions = LibraryPluginOptions; + +type DefineApplicationOptions = (config?: ConfigEnv) => Promise<{ + application?: ApplicationOptions; + vite?: UserConfig; +}>; + +type DefineLibraryOptions = (config?: ConfigEnv) => Promise<{ + library?: LibraryOptions; + vite?: UserConfig; +}>; + +type DefineConfig = DefineApplicationOptions | DefineLibraryOptions; + +export type { + ApplicationPluginOptions, + CommonPluginOptions, + ConditionPlugin, + DefineApplicationOptions, + DefineConfig, + DefineLibraryOptions, + IImportMap, + ImportmapPluginOptions, + LibraryPluginOptions, + NitroMockPluginOptions, + PrintPluginOptions, +}; diff --git a/internal/vite-config/src/utils/env.ts b/internal/vite-config/src/utils/env.ts new file mode 100644 index 00000000..f9cdd4f5 --- /dev/null +++ b/internal/vite-config/src/utils/env.ts @@ -0,0 +1,105 @@ +import type { ApplicationPluginOptions } from '../typing'; + +import { join } from 'node:path'; + +import { fs } from '@vben/node-utils'; + +import dotenv from 'dotenv'; + +const getBoolean = (value: string | undefined) => value === 'true'; + +const getString = (value: string | undefined, fallback: string) => + value ?? fallback; + +const getNumber = (value: string | undefined, fallback: number) => + Number(value) || fallback; + +/** + * 获取当前环境下生效的配置文件名 + */ +function getConfFiles() { + const script = process.env.npm_lifecycle_script as string; + const reg = /--mode ([\d_a-z]+)/; + const result = reg.exec(script); + + if (result) { + const mode = result[1]; + return ['.env', `.env.${mode}`]; + } + return ['.env', '.env.production']; +} + +/** + * Get the environment variables starting with the specified prefix + * @param match prefix + * @param confFiles ext + */ +async function loadEnv>( + match = 'VITE_GLOB_', + confFiles = getConfFiles(), +) { + let envConfig = {}; + + for (const confFile of confFiles) { + try { + const envPath = await fs.readFile(join(process.cwd(), confFile), { + encoding: 'utf8', + }); + const env = dotenv.parse(envPath); + envConfig = { ...envConfig, ...env }; + } catch (error) { + console.error(`Error while parsing ${confFile}`, error); + } + } + const reg = new RegExp(`^(${match})`); + Object.keys(envConfig).forEach((key) => { + if (!reg.test(key)) { + Reflect.deleteProperty(envConfig, key); + } + }); + return envConfig as T; +} + +async function loadAndConvertEnv( + match = 'VITE_', + confFiles = getConfFiles(), +): Promise< + { + appTitle: string; + base: string; + port: number; + } & Partial +> { + const envConfig = await loadEnv(match, confFiles); + + const { + VITE_APP_TITLE, + VITE_BASE, + VITE_COMPRESS, + VITE_DEVTOOLS, + VITE_INJECT_APP_LOADING, + VITE_NITRO_MOCK, + VITE_PORT, + VITE_PWA, + VITE_VISUALIZER, + } = envConfig; + + const compressTypes = (VITE_COMPRESS ?? '') + .split(',') + .filter((item) => item === 'brotli' || item === 'gzip'); + + return { + appTitle: getString(VITE_APP_TITLE, 'Vben Admin'), + base: getString(VITE_BASE, '/'), + compress: compressTypes.length > 0, + compressTypes, + devtools: getBoolean(VITE_DEVTOOLS), + injectAppLoading: getBoolean(VITE_INJECT_APP_LOADING), + nitroMock: getBoolean(VITE_NITRO_MOCK), + port: getNumber(VITE_PORT, 5173), + pwa: getBoolean(VITE_PWA), + visualizer: getBoolean(VITE_VISUALIZER), + }; +} + +export { loadAndConvertEnv, loadEnv }; diff --git a/internal/vite-config/tsconfig.json b/internal/vite-config/tsconfig.json new file mode 100644 index 00000000..b2ec3b61 --- /dev/null +++ b/internal/vite-config/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/node.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/mock/common.ts b/mock/common.ts deleted file mode 100644 index 7be60121..00000000 --- a/mock/common.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function ok(data?: any) { - return { - code: 0, - data: data || {}, - msg: '' - } -} - -export function err(data?: any) { - return { - code: 0, - data: data || {}, - msg: '' - } diff --git a/mock/index.ts b/mock/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/mock/system/auth.ts b/mock/system/auth.ts deleted file mode 100644 index 0ed4423b..00000000 --- a/mock/system/auth.ts +++ /dev/null @@ -1,12 +0,0 @@ - -import { defineMock } from '@alova/mock'; -import { ok, err } from '../common' -export default defineMock( - { - // 捕获get请求 - '/todo': ok({ - nickname: '' - }), - }, - true -); diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 00000000..8e6ab101 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,75 @@ + +#user nobody; +worker_processes 1; + +#error_log logs/error.log; +#error_log logs/error.log notice; +#error_log logs/error.log info; + +#pid logs/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include mime.types; + default_type application/octet-stream; + + types { + application/javascript js mjs; + text/css css; + text/html html; + } + + sendfile on; + # tcp_nopush on; + + #keepalive_timeout 0; + # keepalive_timeout 65; + + # gzip on; + # gzip_buffers 32 16k; + # gzip_comp_level 6; + # gzip_min_length 1k; + # gzip_static on; + # gzip_types text/plain + # text/css + # application/javascript + # application/json + # application/x-javascript + # text/xml + # application/xml + # application/xml+rss + # text/javascript; #设置压缩的文件类型 + # gzip_vary on; + + server { + listen 8080; + server_name localhost; + + location / { + root /usr/share/nginx/html; + try_files $uri $uri/ /index.html; + index index.html; + # Enable CORS + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + } + + error_page 500 502 503 504 /50x.html; + + location = /50x.html { + root /usr/share/nginx/html; + } + } +} diff --git a/package.json b/package.json index ebe9b08a..b99ed203 100644 --- a/package.json +++ b/package.json @@ -1,109 +1,122 @@ { - "name": "pl-webbase-src", - "version": "naive-ui-admin", - "author": { - "name": "author", - "email": "aa@qq.com", - "url": "https://xx.git" - }, + "name": "vben-admin-pro", + "version": "5.1.2", "private": true, + "keywords": [ + "monorepo", + "turbo", + "vben", + "vben admin", + "vben pro", + "vue", + "vue admin", + "vue vben admin", + "vue vben admin pro", + "vue3" + ], + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": "vbenjs/vue-vben-admin.git", + "license": "MIT", + "author": { + "name": "vben", + "email": "ann.vben@gmail.com", + "url": "https://github.com/anncwb" + }, "type": "module", - "engines": { - "node": ">=18.12.0", - "pnpm": ">=8.7.0" - }, "scripts": { - "build": "vite build --mode prod", - "build:test": "vite build --mode test", - "cleanup": "sa cleanup", - "commit": "sa git-commit", - "dev": "vite --mode test", - "dev:prod": "vite --mode prod", - "gen-route": "sa gen-route", - "preview": "vite preview", - "release": "sa release", - "typecheck": "vue-tsc --noEmit --skipLibCheck", - "update-pkg": "sa update-pkg", - "update-dict": "sa update-dict", - "lint": "eslint .", - "lint:fix": "eslint . --fix" - }, - "dependencies": { - "@alova/mock": "2.0.0-beta.11", - "@better-scroll/core": "2.5.1", - "@iconify/vue": "4.1.2", - "@sa/color": "workspace:*", - "@sa/hooks": "workspace:*", - "@sa/materials": "workspace:*", - "@sa/utils": "workspace:*", - "@vicons/antd": "^0.12.0", - "@vueuse/core": "10.9.0", - "@vxe-ui/plugin-render-naive": "workspace:*", - "alova": "3.0.4", - "big.js": "^6.2.1", - "clipboard": "2.0.11", - "dayjs": "1.11.11", - "echarts": "5.5.0", - "exceljs": "^4.4.0", - "lodash-es": "4.17.21", - "mitt": "^3.0.1", - "mockjs": "^1.1.0", - "naive-ui": "2.38.2", - "nprogress": "0.2.0", - "pinia": "2.1.7", - "pinia-plugin-persistedstate": "^3.2.1", - "sortablejs": "^1.15.2", - "tyme4ts": "^1.0.7", - "vfonts": "^0.0.3", - "vue": "3.4.27", - "vue-draggable-plus": "0.4.1", - "vue-i18n": "9.13.1", - "vue-router": "4.3.2", - "vue-types": "^5.1.2", - "vxe-pc-ui": "^4.0.44", - "vxe-table": "^4.7.40", - "vxe-table-plugin-export-xlsx": "^4.0.5", - "xe-utils": "^3.5.26" + "bootstrap": "pnpm install", + "build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build", + "build:analyze": "turbo build:analyze", + "build:docker": "./build-local-docker-image.sh", + "build:antd": "pnpm run build --filter=@vben/web-antd", + "build:docs": "pnpm run build --filter=@vben/docs", + "build:ele": "pnpm run build --filter=@vben/web-ele", + "build:naive": "pnpm run build --filter=@vben/web-naive", + "build:play": "pnpm run build --filter=@vben/playground", + "changeset": "pnpm exec changeset", + "check": "pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell", + "check:circular": "vsh check-circular", + "check:cspell": "cspell lint **/*.ts **/README.md .changeset/*.md --no-progress", + "check:dep": "vsh check-dep", + "check:type": "turbo run typecheck", + "clean": "vsh clean", + "commit": "czg", + "dev": "turbo-run dev", + "dev:office": "pnpm -F web-office run dev:prod", + "dev:antd": "pnpm -F @vben/web-antd run dev", + "dev:docs": "pnpm -F @vben/docs run dev", + "dev:ele": "pnpm -F @vben/web-ele run dev", + "dev:naive": "pnpm -F @vben/web-naive run dev", + "dev:play": "pnpm -F @vben/playground run dev", + "format": "vsh lint --format", + "lint": "vsh lint", + "postinstall": "turbo run stub", + "preinstall": "npx only-allow pnpm", + "prepare": "is-ci || husky", + "preview": "turbo-run preview", + "publint": "vsh publint", + "reinstall": "pnpm clean --del-lock && pnpm bootstrap", + "test:unit": "vitest", + "update:deps": "pnpm update --latest --recursive", + "version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile" }, "devDependencies": { - "@antfu/eslint-config": "^2.21.1", - "@elegant-router/vue": "0.3.7", - "@iconify-json/icon-park-outline": "^1.1.15", - "@iconify/json": "2.2.211", - "@sa/scripts": "workspace:*", - "@sa/uno-preset": "workspace:*", - "@types/big.js": "^6.2.2", - "@types/lodash-es": "4.17.12", - "@types/node": "20.12.12", - "@types/nprogress": "0.2.3", - "@unocss/eslint-config": "0.60.2", - "@unocss/preset-icons": "0.60.2", - "@unocss/preset-uno": "0.60.2", - "@unocss/transformer-directives": "0.60.2", - "@unocss/transformer-variant-group": "0.60.2", - "@unocss/vite": "0.60.2", - "@vitejs/plugin-vue": "5.0.4", - "@vitejs/plugin-vue-jsx": "3.1.0", - "eslint": "9.3.0", - "eslint-plugin-format": "^0.1.2", - "eslint-plugin-vue": "9.26.0", - "lint-staged": "15.2.2", - "sass": "1.77.2", - "seemly": "^0.3.8", - "tsx": "4.10.5", - "typescript": "5.4.5", - "unplugin-icons": "0.19.0", - "unplugin-vue-components": "0.27.0", - "vite": "5.2.11", - "vite-plugin-lazy-import": "^1.0.7", - "vite-plugin-mock": "^2.9.8", - "vite-plugin-progress": "0.0.7", - "vite-plugin-svg-icons": "2.0.1", - "vite-plugin-vue-devtools": "7.2.0", - "vue-eslint-parser": "9.4.2", - "vue-tsc": "2.0.19" + "@changesets/changelog-github": "^0.5.0", + "@changesets/cli": "^2.27.7", + "@ls-lint/ls-lint": "^2.2.3", + "@types/jsdom": "^21.1.7", + "@types/node": "^22.5.1", + "@vben/commitlint-config": "workspace:*", + "@vben/eslint-config": "workspace:*", + "@vben/prettier-config": "workspace:*", + "@vben/stylelint-config": "workspace:*", + "@vben/tailwind-config": "workspace:*", + "@vben/tsconfig": "workspace:*", + "@vben/turbo-run": "workspace:*", + "@vben/vite-config": "workspace:*", + "@vben/vsh": "workspace:*", + "@vitejs/plugin-vue": "^5.1.2", + "@vitejs/plugin-vue-jsx": "^4.0.1", + "@vue/test-utils": "^2.4.6", + "autoprefixer": "^10.4.20", + "cross-env": "^7.0.3", + "cspell": "^8.14.2", + "husky": "^9.1.5", + "is-ci": "^3.0.1", + "jsdom": "^25.0.0", + "lint-staged": "^15.2.9", + "rimraf": "^6.0.1", + "tailwindcss": "^3.4.10", + "turbo": "^2.1.0", + "typescript": "^5.5.4", + "unbuild": "^2.0.0", + "vite": "^5.4.2", + "vitest": "^2.0.5", + "vue": "^3.4.38", + "vue-tsc": "^2.0.29" }, - "lint-staged": { - "*": "eslint --fix" + "engines": { + "node": ">=20", + "pnpm": ">=9" + }, + "packageManager": "pnpm@9.9.0", + "pnpm": { + "peerDependencyRules": { + "allowedVersions": { + "eslint": "*" + } + }, + "overrides": { + "@ctrl/tinycolor": "4.1.0", + "clsx": "2.1.1", + "pinia": "2.2.2", + "vue": "3.4.38" + }, + "neverBuiltDependencies": [ + "canvas", + "node-gyp", + "playwright" + ] } } diff --git a/packages/@core/README.md b/packages/@core/README.md new file mode 100644 index 00000000..8eb201dc --- /dev/null +++ b/packages/@core/README.md @@ -0,0 +1,3 @@ +# @vben-core + +系统一些比较基础的SDK和UI组件库,该目录后续完善后,可能会迁移出去或者发布到npm,请勿将任何业务逻辑和业务包放在该目录。 diff --git a/packages/@core/base/README.md b/packages/@core/base/README.md new file mode 100644 index 00000000..cc745b4e --- /dev/null +++ b/packages/@core/base/README.md @@ -0,0 +1,5 @@ +# base + +基础共享包,请勿引入 workspace 依赖 + +- diff --git a/packages/@core/base/design/package.json b/packages/@core/base/design/package.json new file mode 100644 index 00000000..238b3fc9 --- /dev/null +++ b/packages/@core/base/design/package.json @@ -0,0 +1,41 @@ +{ + "name": "@vben-core/design", + "version": "5.1.2", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/@vben-core/base/design" + }, + "license": "MIT", + "type": "module", + "scripts": { + "build": "pnpm vite build", + "prepublishOnly": "npm run build" + }, + "files": [ + "dist", + "src" + ], + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "exports": { + "./bem": { + "development": "./src/scss-bem/bem.scss", + "default": "./dist/bem.scss" + }, + ".": { + "types": "./src/index.ts", + "development": "./src/index.ts", + "default": "./dist/index.mjs" + } + }, + "publishConfig": { + "exports": { + ".": { + "default": "./dist/index.mjs" + } + } + } +} diff --git a/packages/@core/base/design/src/css/global.css b/packages/@core/base/design/src/css/global.css new file mode 100644 index 00000000..aaa52280 --- /dev/null +++ b/packages/@core/base/design/src/css/global.css @@ -0,0 +1,149 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + *, + ::after, + ::before { + @apply border-border; + + box-sizing: border-box; + border-style: solid; + border-width: 0; + } + + html { + @apply text-foreground bg-background font-sans text-[100%]; + + font-variation-settings: normal; + line-height: 1.15; + text-size-adjust: 100%; + font-synthesis-weight: none; + scroll-behavior: smooth; + text-rendering: optimizelegibility; + -webkit-tap-highlight-color: transparent; + } + + #app, + body, + html { + @apply !pointer-events-auto size-full overscroll-none; + } + + body { + min-height: 100vh; + + /* overflow: overlay; */ + + /* -webkit-font-smoothing: antialiased; */ + + /* -moz-osx-font-smoothing: grayscale; */ + } + + a, + a:active, + a:hover, + a:link, + a:visited { + @apply no-underline; + } + + ::view-transition-new(root), + ::view-transition-old(root) { + @apply animate-none mix-blend-normal; + } + + ::view-transition-old(root) { + @apply z-[1]; + } + + ::view-transition-new(root) { + @apply z-[2147483646]; + } + + html.dark::view-transition-old(root) { + @apply z-[2147483646]; + } + + html.dark::view-transition-new(root) { + @apply z-[1]; + } + + input::placeholder, + textarea::placeholder { + @apply opacity-100; + } + + input:-webkit-autofill { + @apply border-none; + + box-shadow: 0 0 0 1000px transparent inset; + } + + input[type='number']::-webkit-inner-spin-button, + input[type='number']::-webkit-outer-spin-button { + @apply m-0 appearance-none; + } + + /* 只有非mac下才进行调整,mac下使用默认滚动条 */ + html:not([data-platform='macOs']) { + ::-webkit-scrollbar { + @apply h-[10px] w-[10px]; + } + + ::-webkit-scrollbar-thumb { + @apply bg-border rounded-sm border-none; + } + + ::-webkit-scrollbar-track { + @apply rounded-sm border-none bg-transparent shadow-none; + } + + ::-webkit-scrollbar-button { + @apply hidden; + } + } +} + +@layer components { + .flex-center { + @apply flex items-center justify-center; + } + + .flex-col-center { + @apply flex flex-col items-center justify-center; + } + + .outline-box { + @apply outline-border relative cursor-pointer rounded-md p-1 outline outline-1; + } + + .outline-box::after { + @apply absolute left-1/2 top-1/2 z-20 h-0 w-[1px] rounded-sm opacity-0 outline outline-2 outline-transparent transition-all duration-300 content-[""]; + } + + .outline-box.outline-box-active { + @apply outline-primary outline outline-2; + } + + .outline-box.outline-box-active::after { + display: none; + } + + .outline-box:not(.outline-box-active):hover::after { + @apply outline-primary left-0 top-0 h-full w-full p-1 opacity-100; + } + + .card-box { + @apply bg-card text-card-foreground border-border rounded-xl border shadow; + } +} + +html.invert-mode { + @apply invert; +} + +html.grayscale-mode { + @apply grayscale; +} diff --git a/packages/@core/base/design/src/css/nprogress.css b/packages/@core/base/design/src/css/nprogress.css new file mode 100644 index 00000000..3503dab2 --- /dev/null +++ b/packages/@core/base/design/src/css/nprogress.css @@ -0,0 +1,59 @@ +/* Make clicks pass-through */ +#nprogress { + @apply pointer-events-none; +} + +#nprogress .bar { + @apply bg-primary fixed left-0 top-0 z-[1031] h-[2px] w-full; +} + +/* Fancy blur effect */ +#nprogress .peg { + @apply absolute right-0 block h-full w-[100px]; + + box-shadow: + 0 0 10px hsl(var(--primary)), + 0 0 5px hsl(var(--primary)); + opacity: 1; + transform: rotate(3deg) translate(0, -4px); +} + +/* Remove these to get rid of the spinner */ +#nprogress .spinner { + @apply fixed right-4 top-4 z-[1031] block; +} + +#nprogress .spinner-icon { + @apply border-t-primary border-l-primary size-4 rounded-full border-[2px] border-solid border-transparent; + + animation: nprogress-spinner 400ms linear infinite; +} + +.nprogress-custom-parent { + @apply relative overflow-hidden; +} + +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { + @apply absolute; +} + +@keyframes nprogress-spinner { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} + +@keyframes nprogress-spinner { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/packages/@core/base/design/src/css/transition.css b/packages/@core/base/design/src/css/transition.css new file mode 100644 index 00000000..c1cb0e48 --- /dev/null +++ b/packages/@core/base/design/src/css/transition.css @@ -0,0 +1,236 @@ +.slide-up-enter-active, +.slide-up-leave-active { + transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1); +} + +.slide-up-move { + transition: transform 0.3s; +} + +.slide-up-enter-from, +.slide-up-leave-to { + opacity: 0; + transform: translateY(-15px); +} + +.slide-down-enter-active, +.slide-down-leave-active { + transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1); +} + +.slide-down-move { + transition: transform 0.3s; +} + +.slide-down-enter-from, +.slide-down-leave-to { + opacity: 0; + transform: translateY(15px); +} + +.slide-left-enter-active, +.slide-left-leave-active { + transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1); +} + +.slide-left-move { + transition: transform 0.3s; +} + +.slide-left-enter-from, +.slide-left-leave-to { + opacity: 0; + transform: translate(-15px); +} + +.slide-right-enter-active, +.slide-right-leave-active { + transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1); +} + +.slide-right-move { + transition: transform 0.3s; +} + +.slide-right-enter-from, +.slide-right-leave-to { + opacity: 0; + transform: translate(15px); +} + +.fade-transition-enter-active, +.fade-transition-leave-active { + transition: opacity 0.2s ease-in-out; +} + +.fade-transition-enter-from, +.fade-transition-leave-to { + opacity: 0; +} + +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.2s ease-in-out; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + +.fade-slide-leave-active, +.fade-slide-enter-active { + transition: all 0.3s; +} + +.fade-slide-enter-from { + opacity: 0; + transform: translate(-30px); +} + +.fade-slide-leave-to { + opacity: 0; + transform: translate(30px); +} + +.fade-down-enter-active, +.fade-down-leave-active { + transition: + opacity 0.25s, + transform 0.3s; +} + +.fade-down-enter-from { + opacity: 0; + transform: translateY(-10%); +} + +.fade-down-leave-to { + opacity: 0; + transform: translateY(10%); +} + +.fade-scale-leave-active, +.fade-scale-enter-active { + transition: all 0.28s; +} + +.fade-scale-enter-from { + opacity: 0; + transform: scale(1.2); +} + +.fade-scale-leave-to { + opacity: 0; + transform: scale(0.8); +} + +.fade-up-enter-active, +.fade-up-leave-active { + transition: + opacity 0.2s, + transform 0.25s; +} + +.fade-up-enter-from { + opacity: 0; + transform: translateY(10%); +} + +.fade-up-leave-to { + opacity: 0; + transform: translateY(-10%); +} + +@keyframes fade-slide { + 0% { + opacity: 0; + transform: translate(-30px); + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0; + transform: translate(30px); + } +} + +@keyframes fade { + 0% { + opacity: 0; + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +@keyframes fade-up { + 0% { + opacity: 0; + transform: translateY(10%); + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0; + transform: translateY(-10%); + } +} + +@keyframes fade-down { + 0% { + opacity: 0; + transform: translateY(-10%); + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0; + transform: translateY(10%); + } +} + +.fade-slow { + animation: fade 3s infinite; +} + +.fade-slide-slow { + animation: fade-slide 3s infinite; +} + +.fade-up-slow { + animation: fade-up 3s infinite; +} + +.fade-down-slow { + animation: fade-down 3s infinite; +} + +.collapse-transition { + transition: + 0.2s height ease-in-out, + 0.2s padding-top ease-in-out, + 0.2s padding-bottom ease-in-out; +} + +.collapse-transition-leave-active, +.collapse-transition-enter-active { + transition: + 0.2s max-height ease-in-out, + 0.2s padding-top ease-in-out, + 0.2s margin-top ease-in-out; +} diff --git a/packages/@core/base/design/src/css/ui.css b/packages/@core/base/design/src/css/ui.css new file mode 100644 index 00000000..3a002f2a --- /dev/null +++ b/packages/@core/base/design/src/css/ui.css @@ -0,0 +1,83 @@ +.side-content { + animation-duration: 0.2s; + animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); +} + +.side-content[data-side='top'] { + animation-name: slide-up; +} + +.side-content[data-side='bottom'] { + animation-name: slide-down; +} + +.side-content[data-side='left'] { + animation-name: slide-left; +} + +.side-content[data-side='right'] { + animation-name: slide-right; +} + +.breadcrumb-transition-enter-active { + transition: + transform 0.4s cubic-bezier(0.76, 0, 0.24, 1), + opacity 0.4s cubic-bezier(0.76, 0, 0.24, 1); +} + +.breadcrumb-transition-leave-active { + display: none; +} + +.breadcrumb-transition-enter-from { + opacity: 0; + transform: translateX(30px) skewX(-30deg); +} + +@keyframes slide-down { + from { + opacity: 0; + transform: translateY(-10px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slide-left { + from { + opacity: 0; + transform: translateX(-10px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slide-right { + from { + opacity: 0; + transform: translateX(-10px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slide-up { + from { + opacity: 0; + transform: translateY(10px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/packages/@core/base/design/src/design-tokens/dark/index.css b/packages/@core/base/design/src/design-tokens/dark/index.css new file mode 100644 index 00000000..02394cda --- /dev/null +++ b/packages/@core/base/design/src/design-tokens/dark/index.css @@ -0,0 +1,433 @@ +.dark, +.dark[data-theme='custom'], +.dark[data-theme='default'] { + /* Default background color of ...etc */ + --background: 222.34deg 10.43% 12.27%; + + /* 主体区域背景色 */ + --background-deep: 220deg 13.06% 9%; + --foreground: 0 0% 95%; + + /* Background color for */ + --card: 222.34deg 10.43% 12.27%; + + /* --card: 222.2 84% 4.9%; */ + --card-foreground: 210 40% 98%; + + /* Background color for popovers such as , , */ + --popover: 222.82deg 8.43% 12.27%; + --popover-foreground: 210 40% 98%; + + /* Muted backgrounds such as , and */ + + /* --muted: 220deg 6.82% 17.25%; */ + + /* --muted-foreground: 215 20.2% 65.1%; */ + + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + + /* 主题颜色 */ + + /* --primary: 245 82% 67%; */ + --primary-foreground: 0 0% 98%; + + /* Used for destructive actions such as