Browse Source

first commit

master
zhouhaibin 6 months ago
commit
218b4a39b7
  1. 4
      .browserslistrc
  2. 107
      .commitlintrc.js
  3. 3
      .dockerignore
  4. 19
      .editorconfig
  5. 3
      .env
  6. 19
      .env.analyze
  7. 20
      .env.development
  8. 18
      .env.docker
  9. 20
      .env.production
  10. 18
      .env.test
  11. 16
      .eslintignore
  12. 7
      .eslintrc.js
  13. 11
      .gitattributes
  14. 39
      .github/ISSUE_TEMPLATE/1-bug.md
  15. 32
      .github/ISSUE_TEMPLATE/2-feature.md
  16. 28
      .github/ISSUE_TEMPLATE/3-bug-cn.md
  17. 8
      .github/ISSUE_TEMPLATE/config.yml
  18. 89
      .github/commit-convention.md
  19. 5
      .github/contributing.md
  20. 34
      .github/pull_request_template.md
  21. 126
      .github/workflows/deploy.yml
  22. 17
      .github/workflows/issue-close-require.yml
  23. 29
      .github/workflows/issue-labeled.yml
  24. 39
      .github/workflows/linter.yml
  25. 24
      .github/workflows/release.yml
  26. 34
      .gitignore
  27. 6
      .gitpod.yml
  28. 8
      .husky/commit-msg
  29. 9
      .husky/common.sh
  30. 10
      .husky/pre-commit
  31. 7
      .npmrc
  32. 12
      .prettierignore
  33. 19
      .prettierrc.js
  34. 2
      .stylelintignore
  35. 4
      .stylelintrc.js
  36. 14
      .vscode/extensions.json
  37. 13
      .vscode/launch.json
  38. 174
      .vscode/settings.json
  39. 82
      CHANGELOG.md
  40. 1
      CNAME
  41. 25
      Dockerfile
  42. 21
      LICENSE
  43. 132
      README.md
  44. 0
      apps/portal-view/.gitkeep
  45. 15
      apps/test-server/README.md
  46. 18
      apps/test-server/controller/FileController.ts
  47. 15
      apps/test-server/controller/UserController.ts
  48. 18
      apps/test-server/ecosystem.config.js
  49. 63
      apps/test-server/index.ts
  50. 8
      apps/test-server/nodemon.json
  51. 36
      apps/test-server/package.json
  52. 23
      apps/test-server/routes.ts
  53. 54
      apps/test-server/service/FileService.ts
  54. 25
      apps/test-server/service/UserService.ts
  55. 7
      apps/test-server/tsconfig.json
  56. 9
      apps/test-server/utils.ts
  57. 158
      index.html
  58. 9
      internal/eslint-config/.eslintignore
  59. 4
      internal/eslint-config/.eslintrc.js
  60. 10
      internal/eslint-config/build.config.ts
  61. 49
      internal/eslint-config/package.json
  62. 91
      internal/eslint-config/src/index.ts
  63. 57
      internal/eslint-config/src/strict.ts
  64. 5
      internal/eslint-config/tsconfig.json
  65. 9
      internal/stylelint-config/.eslintignore
  66. 4
      internal/stylelint-config/.eslintrc.js
  67. 10
      internal/stylelint-config/build.config.ts
  68. 49
      internal/stylelint-config/package.json
  69. 92
      internal/stylelint-config/src/index.ts
  70. 5
      internal/stylelint-config/tsconfig.json
  71. 27
      internal/ts-config/base.json
  72. 18
      internal/ts-config/node-server.json
  73. 12
      internal/ts-config/node.json
  74. 25
      internal/ts-config/package.json
  75. 10
      internal/ts-config/vue-app.json
  76. 9
      internal/vite-config/.eslintignore
  77. 4
      internal/vite-config/.eslintrc.js
  78. 10
      internal/vite-config/build.config.ts
  79. 58
      internal/vite-config/package.json
  80. 105
      internal/vite-config/src/config/application.ts
  81. 22
      internal/vite-config/src/config/common.ts
  82. 42
      internal/vite-config/src/config/package.ts
  83. 2
      internal/vite-config/src/index.ts
  84. 104
      internal/vite-config/src/plugins/appConfig.ts
  85. 38
      internal/vite-config/src/plugins/compress.ts
  86. 13
      internal/vite-config/src/plugins/html.ts
  87. 52
      internal/vite-config/src/plugins/index.ts
  88. 17
      internal/vite-config/src/plugins/svgSprite.ts
  89. 14
      internal/vite-config/src/plugins/visualizer.ts
  90. 49
      internal/vite-config/src/utils/env.ts
  91. 16
      internal/vite-config/src/utils/hash.ts
  92. 47
      internal/vite-config/src/utils/modifyVars.ts
  93. 5
      internal/vite-config/tsconfig.json
  94. 39
      nginx.conf
  95. 156
      package.json
  96. 0
      packages/.gitkeep
  97. 4
      packages/hooks/.eslintrc.js
  98. 10
      packages/hooks/build.config.ts
  99. 39
      packages/hooks/package.json
  100. 7
      packages/hooks/src/index.ts

4
.browserslistrc

@ -0,0 +1,4 @@
> 1%
last 2 versions
not dead
not ie 11

107
.commitlintrc.js

@ -0,0 +1,107 @@
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const scopes = fs
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name.replace(/s$/, ''));
// 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} */
module.exports = {
ignores: [(commit) => commit.includes('init')],
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [2, 'always'],
'footer-leading-blank': [1, 'always'],
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'subject-case': [0],
'type-enum': [
2,
'always',
[
'feat',
'fix',
'perf',
'style',
'docs',
'test',
'refactor',
'build',
'ci',
'chore',
'revert',
'wip',
'workflow',
'types',
'release',
],
],
},
prompt: {
/** @use `yarn commit :f` */
alias: {
f: 'docs: fix typos',
r: 'docs: update README',
s: 'style: update code format',
b: 'build: bump dependencies',
c: 'chore: update config',
},
customScopesAlign: !scopeComplete ? 'top' : 'bottom',
defaultScope: scopeComplete,
scopes: [...scopes, 'mock'],
allowEmptyIssuePrefixs: false,
allowCustomIssuePrefixs: false,
// English
typesAppend: [
{ value: 'wip', name: 'wip: work in process' },
{ value: 'workflow', name: 'workflow: workflow improvements' },
{ value: 'types', name: 'types: type definition file changes' },
],
// 中英文对照版
// 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: 自定义',
},
};

3
.dockerignore

@ -0,0 +1,3 @@
node_modules/
dist/
.vscode/

19
.editorconfig

@ -0,0 +1,19 @@
root = true
[*]
charset=utf-8
end_of_line=lf
insert_final_newline=true
indent_style=space
indent_size=2
max_line_length = 100
[*.{yml,yaml,json}]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

3
.env

@ -0,0 +1,3 @@
# 网站标题
VITE_GLOB_APP_TITLE = 国研咨询

19
.env.analyze

@ -0,0 +1,19 @@
# public path
VITE_PUBLIC_PATH=/
# 打包是否输出gz|br文件
# 可选: gzip | brotli | none
# 也可以有多个, 例如 ‘gzip’|'brotli',这样会同时生成 .gz和.br文件
VITE_BUILD_COMPRESS='none'
# 如果没有跨域问题,直接在这里配置即可
VITE_GLOB_API_URL=/basic-api
# 文件上传接口
VITE_GLOB_UPLOAD_URL=/upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_ENABLE_ANALYZE=true

20
.env.development

@ -0,0 +1,20 @@
# 资源公共路径,需要以 /开头和结尾
VITE_PUBLIC_PATH=/
# 是否打开mock
VITE_USE_MOCK = true
# 接口地址
# 如果没有跨域问题,直接在这里配置即可
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://localhost:8080/guoyan
#后台接口父地址(必填)
VITE_GLOB_API_URL=/guoyan
# 文件上传接口
VITE_GLOB_UPLOAD_URL=/api/auth/file/upload
# 接口地址前缀,有些系统所有接口地址都有前缀,可以在这里统一加,方便切换
VITE_GLOB_API_URL_PREFIX=
# 项目路径,用于代码生成
VITE_PROJECT_PATH=/Users/tengchong/workspaces/github/easy-vben-admin

18
.env.docker

@ -0,0 +1,18 @@
# public path
VITE_PUBLIC_PATH=/
# timeout(seconds)
VITE_TIMEOUT=15
# Delete console
VITE_DROP_CONSOLE=true
# 打包是否输出gz|br文件
# 可选: gzip | brotli | none
# 也可以有多个, 例如 ‘gzip’|'brotli',这样会同时生成 .gz和.br文件
VITE_BUILD_COMPRESS='none'
VITE_GLOB_API_URL="__vg_base_url"
# 文件上传接口
VITE_GLOB_UPLOAD_URL=/files/upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=

20
.env.production

@ -0,0 +1,20 @@
# 资源公共路径,需要以 /开头和结尾
VITE_PUBLIC_PATH=/
# 打包是否输出gz|br文件
# 可选: gzip | brotli | none
# 也可以有多个, 例如 ‘gzip’|'brotli',这样会同时生成 .gz和.br文件
VITE_BUILD_COMPRESS='none'
# 接口地址
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://localhost:8080/guoyan
#后台接口父地址(必填)
VITE_GLOB_API_URL=/guoyan
# 文件上传接口
VITE_GLOB_UPLOAD_URL=/api/auth/file/upload
# 接口地址前缀,有些系统所有接口地址都有前缀,可以在这里统一加,方便切换
VITE_GLOB_API_URL_PREFIX=

18
.env.test

@ -0,0 +1,18 @@
NODE_ENV=production
# public path
VITE_PUBLIC_PATH=/
# 打包是否输出gz|br文件
# 可选: gzip | brotli | none
# 也可以有多个, 例如 ‘gzip’|'brotli',这样会同时生成 .gz和.br文件
VITE_BUILD_COMPRESS='none'
# 如果没有跨域问题,直接在这里配置即可
VITE_GLOB_API_URL=/basic-api
# 文件上传接口
VITE_GLOB_UPLOAD_URL=/upload
# Interface prefix
VITE_GLOB_API_URL_PREFIX=

16
.eslintignore

@ -0,0 +1,16 @@
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
Dockerfile
package.json

7
.eslintrc.js

@ -0,0 +1,7 @@
module.exports = {
root: true,
extends: ['@vben'],
rules: {
'no-undef': 'off',
},
};

11
.gitattributes

@ -0,0 +1,11 @@
# 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

39
.github/ISSUE_TEMPLATE/1-bug.md

@ -0,0 +1,39 @@
---
name: 🐛 Bug report
about: Create a report to help us improve
title: ''
labels: 'bug: pending triage'
assignees: ''
---
<!--
抱歉,您遇到了一个错误。感谢您抽出宝贵的时间进行举报!
请尽可能填写以下模板。
Ouch, sorry you’ve run into a bug. Thank for taking the time to report it!
Please fill in as much of the template below as you’re able.
P.S. have you seen our support and contributing docs?
-->
**⚠️ IMPORTANT ⚠️ Please check the following list before proceeding. If you ignore this issue template, your issue will be directly closed.**
- [ ] Read [the docs](https://anncwb.github.io/vue-vben-admin-doc/).
- [ ] Make sure the code is up to date. (Some bugs have been fixed in the latest code)
- [ ] This is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/anncwb/vue-vben-admin/discussions) or join our [Discord](https://discord.gg/8GuAdwDhj6) Chat Server.
### Describe the bug
A clear and concise description of what the bug is..
### Reproduction
Please describe the steps of the problem in detail to ensure that we can restore the correct problem
## System Info
- Operating System:
- Node version:
- Package manager (npm/yarn/pnpm) and version:

32
.github/ISSUE_TEMPLATE/2-feature.md

@ -0,0 +1,32 @@
---
name: 🚀 Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
<!--
感谢您提出使这个项目更好的想法!
请尽可能填写以下模板。
Thank you for suggesting an idea to make this project better!
Please fill in as much of the template below as you’re able.
-->
### Subject of the feature
Describe your issue here.
### Problem
If the feature requests relates to a problem, please describe the problem you are trying to solve here.
### Expected behaviour
What should happen? Please describe the desired behaviour.
### Alternatives
What are the alternative solutions? Please describe what else you have considered?

28
.github/ISSUE_TEMPLATE/3-bug-cn.md

@ -0,0 +1,28 @@
---
name: 🐛 Bug 报告
about: 向我们报告一个Bug以帮助我们改进
title: ''
labels: 'bug: pending triage'
assignees: ''
---
**⚠️ 重要 ⚠️ 在进一步操作之前,请检查下列选项。如果您忽视此模板或者没有提供关键信息,您的 Issue 将直接被关闭**
- [ ] 已阅读 [文档](https://anncwb.github.io/vue-vben-admin-doc/).
- [ ] 确保您的代码已是最新或者所报告的 Bug 在最新版本中可以重现. (部分 Bug 可能已经在最近的代码中修复)
- [ ] 已在 Issues 中搜索了相关的关键词
- [ ] 不是 ant design vue 组件库的 Bug
### 描述 Bug
请清晰地描述此 Bug 的具体表现。
### 复现 Bug
请描述在演示页面中复现 Bug 的详细步骤,以确保我们可以理解并定位问题。部分 Bug 如果未在 Demo 中涉及,请务必提供关键代码
## 系统信息
- 操作系统:
- Node 版本:
- 包管理器 (npm/yarn/pnpm) 及其版本:

8
.github/ISSUE_TEMPLATE/config.yml

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Discord Chat
url: https://discord.gg/8GuAdwDhj6
about: Ask questions and discuss with other Vben users in real time.
- name: Questions & Discussions
url: https://github.com/anncwb/vue-vben-admin/discussions
about: Use GitHub discussions for message-board style questions and discussions.

89
.github/commit-convention.md

@ -0,0 +1,89 @@
## Git Commit Message Convention
> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).
#### TL;DR:
Messages must be matched by the following regex:
```js
/^(revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|types|wip): .{1,50}/;
```
#### Examples
Appears under "Features" header, `dev` subheader:
```
feat(dev): add 'comments' option
```
Appears under "Bug Fixes" header, `dev` subheader, with a link to issue #28:
```
fix(dev): fix dev error
close #28
```
Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
```
perf(build): remove 'foo' option
BREAKING CHANGE: The 'foo' option has been removed.
```
The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
```
revert: feat(compiler): add 'comments' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
```
### Full Message Format
A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
### Scope
The scope could be anything specifying the place of the commit change. For example `dev`, `build`, `workflow`, `cli` etc...
### Subject
The subject contains a succinct description of the change:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.

5
.github/contributing.md

@ -0,0 +1,5 @@
# Contributing Guide
1. Make sure you put things in the right category!
2. Always add your items to the end of a list. To be fair, the order is first-come-first-serve.
3. If you think something belongs in the wrong category, or think there needs to be a new category, feel free to edit things too.

34
.github/pull_request_template.md

@ -0,0 +1,34 @@
### `General`
> ✏️ Mark the necessary items without changing the structure of the PR template.
- [ ] Pull request template structure not broken
### `Type`
> ℹ️ What types of changes does your code introduce?
> 👉 _Put an `x` in the boxes that apply_
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
### `Checklist`
> ℹ️ Check all checkboxes - this will indicate that you have done everything in accordance with the rules in [CONTRIBUTING](contributing.md).
> 👉 _Put an `x` in the boxes that apply._
- [ ] My code follows the style guidelines of this project
- [ ] Is the code format correct
- [ ] Is the git submission information standard?
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules

126
.github/workflows/deploy.yml

@ -0,0 +1,126 @@
name: deploy
on:
push:
branches:
- main
jobs:
# push-to-ftp:
# if: "contains(github.event.head_commit.message, '[deploy]')"
# runs-on: ubuntu-latest
# steps:
# - name: Checkout
# uses: actions/checkout@v2
# - name: Sed Config Base
# shell: bash
# run: |
# sed -i 's#VITE_PUBLIC_PATH\s*=.*#VITE_PUBLIC_PATH = /next/#g' ./.env.production
# sed -i "s#VITE_BUILD_COMPRESS\s*=.*#VITE_BUILD_COMPRESS = 'gzip'#g" ./.env.production
# cat ./.env.production
# - name: use Node.js 14
# uses: actions/setup-node@v2.1.2
# with:
# node-version: '14.x'
# - name: Get yarn cache
# id: yarn-cache
# run: echo "::set-output name=dir::$(yarn cache dir)"
# - name: Cache dependencies
# uses: actions/cache@v2
# with:
# path: ${{ steps.yarn-cache.outputs.dir }}
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-yarn-
# - name: Build
# run: |
# yarn install
# yarn run build
# - name: Deploy
# uses: SamKirkland/FTP-Deploy-Action@2.0.0
# env:
# FTP_SERVER: ${{ secrets.FTP_SERVER }}
# FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
# FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
# METHOD: sftp
# PORT: ${{ secrets.FTP_PORT }}
# LOCAL_DIR: dist
# REMOTE_DIR: /srv/www/vben-admin
# ARGS: --delete --verbose --parallel=80
push-to-gh-pages:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
# - uses: NullVoxPopuli/action-setup-pnpm@v2
- name: Sed Config Base
shell: bash
run: |
sed -i "s#VITE_BUILD_COMPRESS\s*=.*#VITE_BUILD_COMPRESS = 'gzip'#g" ./.env.production
sed -i "s#VITE_DROP_CONSOLE\s*=.*#VITE_DROP_CONSOLE = true#g" ./.env.production
cat ./.env.production
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: use Node.js 16
uses: actions/setup-node@v3
with:
node-version: '20.x'
# - name: Get yarn cache directory path
# id: yarn-cache-dir-path
# run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
#
# - name: Cache dependencies
# uses: actions/cache@v3
# with:
# path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-yarn-
- name: Set SSH Environment
env:
DOCS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
run: |
mkdir -p ~/.ssh/
echo "$ACTIONS_DEPLOY_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com > ~/.ssh/known_hosts
chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
git config --global user.email "vbenadmin@163.com"
git config --global user.name "vbenAdmin"
- name: Build
env:
NODE_OPTIONS: '--max_old_space_size=4096'
run: |
pnpm install --no-frozen-lockfile
pnpm build
touch dist/.nojekyll
cp dist/index.html dist/404.html
- name: Delete gh-pages branch
run: |
git push origin --delete gh-pages
- name: Deploy
uses: peaceiris/actions-gh-pages@v3.9.0
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
PUBLISH_BRANCH: gh-pages
PUBLISH_DIR: ./dist
CNAME: vben.vvbin.cn

17
.github/workflows/issue-close-require.yml

@ -0,0 +1,17 @@
name: Issue Close Require
on:
schedule:
- cron: '0 0 * * *'
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- name: need reproduction
uses: actions-cool/issues-helper@v2.1.1
with:
actions: 'close-issues'
token: ${{ secrets.OPER_TOKEN }}
labels: 'need reproduction'
inactive-day: 3

29
.github/workflows/issue-labeled.yml

@ -0,0 +1,29 @@
name: Issue Labeled
on:
issues:
types: [labeled]
jobs:
reply-labeled:
runs-on: ubuntu-latest
steps:
- name: remove pending
if: github.event.label.name == 'enhancement' || github.event.label.name == 'bug'
uses: actions-cool/issues-helper@v2.1.1
with:
actions: 'remove-labels'
token: ${{ secrets.OPER_TOKEN }}
issue-number: ${{ github.event.issue.number }}
labels: 'bug: pending triage'
- name: need reproduction
if: github.event.label.name == 'need reproduction'
uses: actions-cool/issues-helper@v2.1.1
with:
actions: 'create-comment, remove-labels'
token: ${{ secrets.OPER_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. Please provide the complete reproduction steps and code. Issues labeled by `need reproduction` will be closed if no activities in 3 days.
labels: 'bug: pending triage'

39
.github/workflows/linter.yml

@ -0,0 +1,39 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name: Node.js CI
on:
push:
branches: [main, thin]
pull_request:
branches: [main, thin]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install pnpm
run: npm install -g pnpm
- name: Install dependencies
run: pnpm install
- name: Run type:check
run: pnpm run type:check
- name: Build
run: pnpm build

24
.github/workflows/release.yml

@ -0,0 +1,24 @@
name: Create Release
on:
push:
tags:
- v*
jobs:
build:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Create Release for Tag
id: release_tag
uses: yyx990803/release-tag@master
env:
GITHUB_TOKEN: ${{ secrets.OPER_TOKEN }}
with:
tag_name: ${{ github.ref }}
body: |
Please refer to [CHANGELOG.md](https://github.com/anncwb/vue-vben-admin/blob/main/CHANGELOG.md) for details.

34
.gitignore

@ -0,0 +1,34 @@
node_modules
.DS_Store
dist
.cache
.turbo
tests/server/static
tests/server/static/upload
.local
# local env files
.env.local
.env.*.local
.eslintcache
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
# .vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
package-lock.json
pnpm-lock.yaml
.history

6
.gitpod.yml

@ -0,0 +1,6 @@
ports:
- port: 3344
onOpen: open-preview
tasks:
- init: pnpm install
command: pnpm run dev

8
.husky/commit-msg

@ -0,0 +1,8 @@
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
PATH="/usr/local/bin:$PATH"
npx --no-install commitlint --edit "$1"

9
.husky/common.sh

@ -0,0 +1,9 @@
#!/bin/sh
command_exists () {
command -v "$1" >/dev/null 2>&1
}
# Workaround for Windows 10, Git Bash and Yarn
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi

10
.husky/pre-commit

@ -0,0 +1,10 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
[ -n "$CI" ] && exit 0
PATH="/usr/local/bin:$PATH"
# Format and submit code according to lintstagedrc.js configuration
pnpm exec lint-staged

7
.npmrc

@ -0,0 +1,7 @@
public-hoist-pattern[]=husky
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=lint-staged
public-hoist-pattern[]=*stylelint*
public-hoist-pattern[]=@commitlint/cli
public-hoist-pattern[]=@vben/eslint-config

12
.prettierignore

@ -0,0 +1,12 @@
dist
.local
.output.js
node_modules
**/*.svg
**/*.sh
public
.npmrc
*-lock.yaml

19
.prettierrc.js

@ -0,0 +1,19 @@
module.exports = {
printWidth: 100,
semi: true,
vueIndentScriptAndStyle: true,
singleQuote: true,
trailingComma: 'all',
proseWrap: 'never',
htmlWhitespaceSensitivity: 'strict',
endOfLine: 'auto',
plugins: ['prettier-plugin-packagejson'],
overrides: [
{
files: '.*rc',
options: {
parser: 'json',
},
},
],
};

2
.stylelintignore

@ -0,0 +1,2 @@
dist
public

4
.stylelintrc.js

@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@vben/stylelint-config'],
};

14
.vscode/extensions.json

@ -0,0 +1,14 @@
{
"recommendations": [
"vue.volar",
"dbaeumer.vscode-eslint",
"stylelint.vscode-stylelint",
"esbenp.prettier-vscode",
"mrmlnc.vscode-less",
"lokalise.i18n-ally",
"antfu.iconify",
"antfu.unocss",
"mikestead.dotenv",
"vue.vscode-typescript-vue-plugin"
]
}

13
.vscode/launch.json

@ -0,0 +1,13 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome",
"url": "http://localhost:3100",
"webRoot": "${workspaceFolder}/src",
"sourceMaps": true
}
]
}

174
.vscode/settings.json

@ -0,0 +1,174 @@
{
"typescript.tsdk": "./node_modules/typescript/lib",
"volar.tsPlugin": true,
"volar.tsPluginStatus": false,
"npm.packageManager": "pnpm",
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"files.eol": "\n",
"search.exclude": {
"**/node_modules": true,
"**/*.log": true,
"**/*.log*": true,
"**/bower_components": true,
"**/dist": true,
"**/elehukouben": true,
"**/.git": true,
"**/.gitignore": true,
"**/.svn": true,
"**/.DS_Store": true,
"**/.idea": true,
"**/.vscode": false,
"**/yarn.lock": true,
"**/tmp": true,
"out": true,
"dist": true,
"node_modules": true,
"CHANGELOG.md": true,
"examples": true,
"res": true,
"screenshots": true,
"yarn-error.log": true,
"**/.yarn": true
},
"files.exclude": {
"**/.cache": true,
"**/.editorconfig": true,
"**/.eslintcache": true,
"**/bower_components": true,
"**/.idea": true,
"**/tmp": true,
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": 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
},
"stylelint.enable": true,
"stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"],
"path-intellisense.mappings": {
"@/": "${workspaceRoot}/src"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
"[vue]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
"editor.defaultFormatter": "Vue.volar"
},
"i18n-ally.localesPaths": ["src/locales/lang"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.namespace": true,
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
"i18n-ally.enabledParsers": ["json"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": ["vue", "react"],
"cSpell.words": [
"antd",
"antv",
"brotli",
"browserslist",
"codemirror",
"commitlint",
"cropperjs",
"echarts",
"esnext",
"esno",
"iconify",
"INTLIFY",
"lintstagedrc",
"logicflow",
"mockjs",
"nprogress",
"pinia",
"pnpm",
"qrcode",
"sider",
"sortablejs",
"stylelint",
"tailwindcss",
"tinymce",
"unocss",
"unref",
"vben",
"vditor",
"Vite",
"vitejs",
"vueuse",
"zxcvbn"
],
"vetur.format.scriptInitialIndent": true,
"vetur.format.styleInitialIndent": true,
"vetur.validation.script": false,
"MicroPython.executeButton": [
{
"text": "▶",
"tooltip": "运行",
"alignment": "left",
"command": "extension.executeFile",
"priority": 3.5
}
],
"MicroPython.syncButton": [
{
"text": "$(sync)",
"tooltip": "同步",
"alignment": "left",
"command": "extension.execute",
"priority": 4
}
],
//
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": {
"*.ts": "$(capture).test.ts, $(capture).test.tsx",
"*.tsx": "$(capture).test.ts, $(capture).test.tsx",
"*.env": "$(capture).env.*",
"CHANGELOG.md": "CHANGELOG*",
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,README*,.npmrc,.browserslistrc",
".eslintrc.js": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.js,.prettierrc.js,.stylelintrc.js"
},
"terminal.integrated.scrollback": 10000,
"nuxt.isNuxtApp": false
}

82
CHANGELOG.md

@ -0,0 +1,82 @@
# 更新日志
## 1.2.0
`2023-02-17`
- 🌟 更新 Ant Design Vue 与 Vite
- 🌟 从 vben 同步更新
- 🐞 修复一些问题
## 1.1.1
`2022-09-20`
- 🌟 优化用户管理选择角色策略
- 🌟 优化部分页面
- 🌟 优化代码生成
- 🐞 修复解除锁屏问题
- 🐞 修复编辑导入模板未重新加载问题
## 1.1.0
`2022-08-19`
- 🌟 添加字典树选择器(DictSelectTree)
- 🌟 添加部门选择器(DeptSelect)
- 🌟 添加用户选择器(UserSelect)
- 🌟 添加用户对话框选择器(UserModalSelect)
- 🌟 添加角色选择器(RoleSelect)
- 🌟 优化常用按钮组件
### 🔥🔥🔥 1.0.0 正式版发布 🔥🔥🔥
`2022-07-31`
- 🌟 添加示例模块
- 🌟 添加在系统监控模块
- 🌟 添加找回密码
- 🌟 添加滑块验证
- 🐞 修复工作流动态引入组件问题
- 🐞 修复表单组件 value 同步问题
## 0.4.0
`2022-06-28`
- 🌟 添加用户选择组件
- 🌟 添加部门树
- 🌟 添加常用按钮
- 🌟 添加多数据源
- 🌟 添加代码生成示例
- 🌟 添加消息
- 🌟 优化字典组件
- 🐞 修复锁屏问题
- 🐞 修复访问隐藏子路由未选中父路由问题
## 0.3.0
`2022-06-05`
- 🌟 添加访问日志
- 🌟 添加异常日志
- 🌟 添加定时任务
- 🌟 添加个人中心
- 🌟 优化字典管理
## 0.2.0
`2022-05-01`
- 🌟 添加用户管理功能
- 🌟 添加角色管理功能
- 🌟 添加角色管理功能
- 🌟 添加系统设置功能
- 🌟 添加菜单管理功能
- 🌟 添加部门管理功能
## 0.1.0
`2022-03-05`
- 🌟 添加基础功能

1
CNAME

@ -0,0 +1 @@
vben.vvbin.cn

25
Dockerfile

@ -0,0 +1,25 @@
# node 构建
FROM node:16-alpine as build-stage
# 署名
MAINTAINER Adoin 'adoin@qq.com'
WORKDIR /app
COPY . ./
# 设置 node 阿里镜像
RUN npm config set registry https://registry.npmmirror.com
# 设置--max-old-space-size
ENV NODE_OPTIONS=--max-old-space-size=16384
# 设置阿里镜像、pnpm、依赖、编译
RUN npm install pnpm -g && \
pnpm install --frozen-lockfile && \
pnpm build:docker
# node部分结束
RUN echo "🎉 编 🎉 译 🎉 成 🎉 功 🎉"
# nginx 部署
FROM nginx:1.23.3-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html/dist
COPY --from=build-stage /app/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
## 将/usr/share/nginx/html/dist/assets/index.js 和/usr/share/nginx/html/dist/_app.config.js中的"$vg_base_url"替换为环境变量中的VG_BASE_URL,$vg_sub_domain 替换成VG_SUB_DOMAIN,$vg_default_user替换成VG_DEFAULT_USER,$vg_default_password替换成VG_DEFAULT_PASSWORD 而后启动nginx
CMD sed -i "s|__vg_base_url|$VG_BASE_URL|g" /usr/share/nginx/html/dist/assets/entry/index-*.js /usr/share/nginx/html/dist/_app.config.js && \
nginx -g 'daemon off;'
RUN echo "🎉 架 🎉 设 🎉 成 🎉 功 🎉"

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-present, Vben
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

132
README.md

@ -0,0 +1,132 @@
<div align="center">
<a href="https://github.com/TengChongChong/Easy-Vben-Admin">
<img alt="Easy-Vben-Admin Logo" width="200" height="200" src="https://raw.githubusercontent.com/TengChongChong/Easy-Vben-Admin/main/src/assets/images/logo.png">
</a>
<br>
<h1>Easy-Vben-Admin</h1>
</div>
## 简介
Easy-Vben-Admin 是一个免费开源的中后台模版。使用了最新的`vue3`,`vite2`,`TypeScript`等主流技术开发,开箱即用的中后台前端解决方案,也可用于学习参考。
## 特性
- **最新技术栈**:使用 Vue3/vite2 等前端前沿技术开发
- **TypeScript**: 应用程序级 JavaScript 的语言
- **主题**:可配置的主题
- **国际化**:内置完善的国际化方案
- **权限** 内置完善的动态路由权限生成方案
- **组件** 二次封装了多个常用的组件
## 预览
- [Easy-Vben-Admin](http://ev.easy-frame.top)
测试账号: sysadmin/admin123
## 文档
[文档地址](http://ev-doc.easy-frame.top)
## 准备
- [node](http://nodejs.org/) 和 [git](https://git-scm.com/) -项目开发环境
- [Vite](https://vitejs.dev/) - 熟悉 vite 特性
- [Vue3](https://v3.vuejs.org/) - 熟悉 Vue 基础语法
- [TypeScript](https://www.typescriptlang.org/) - 熟悉`TypeScript`基本语法
- [Es6+](http://es6.ruanyifeng.com/) - 熟悉 es6 基本语法
- [Vue-Router-Next](https://next.router.vuejs.org/) - 熟悉 vue-router 基本使用
- [Ant-Design-Vue](https://www.antdv.com/components/overview-cn) - ui 基本使用
## 安装使用
- 获取项目代码
```bash
git clone https://github.com/TengChongChong/Easy-Vben-Admin.git
```
- 安装依赖
```bash
cd Easy-Vben-Admin
pnpm install
```
- 运行
```bash
pnpm serve
```
- 打包
```bash
pnpm build
```
## 更新日志
[CHANGELOG](./CHANGELOG.md)
## 项目地址
- [Easy-Vben](https://github.com/TengChongChong/Easy-Vben) - 后端
- [Easy-Vben-Admin](https://github.com/TengChongChong/Easy-Vben-Admin) - 前端
## 预览
![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-13.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-12.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-11.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-10.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-9.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-8.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-7.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-6.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-5.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-4.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-3.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-2.png) ![预览](https://github.com/TengChongChong/easy-vben-doc/blob/main/docs/.vuepress/public/assets/preview/preive-1.png)
## 如何贡献
非常欢迎你的加入![提一个 Issue](https://github.com/TengChongChong/Easy-Vben-Admin/issues) 或者提交一个 Pull Request。
**Pull Request:**
1. Fork 代码!
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` 修复问题/BUG
- `style` 代码风格相关无影响运行结果的
- `perf` 优化/性能提升
- `refactor` 重构
- `revert` 撤销修改
- `test` 测试相关
- `docs` 文档/注释
- `chore` 依赖更新/脚手架配置修改等
- `workflow` 工作流改进
- `ci` 持续集成
- `types` 类型定义文件更改
- `wip` 开发中
## 浏览器支持
本地开发推荐使用`Chrome 80+` 浏览器
支持现代浏览器, 不支持 IE
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 交流
`Easy-Vben-Admin` 是完全开源免费的项目,在帮助开发者更方便地进行中大型管理系统开发,同时也提供 QQ 交流群使用问题欢迎在群内提问。
- QQ 群 `747030643`
## License
[MIT © EasyAdmin-2022](./LICENSE)

0
apps/portal-view/.gitkeep

15
apps/test-server/README.md

@ -0,0 +1,15 @@
# Test Server
It is used to start the test interface service, which can test the upload, websocket, login and other interfaces.
## Usage
```bash
cd ./test/server
pnpm install
pnpm run start
```

18
apps/test-server/controller/FileController.ts

@ -0,0 +1,18 @@
import FileService from '../service/FileService';
class FileController {
private service: FileService = new FileService();
upload = async (ctx) => {
const files = ctx.request.files.file;
console.log(files);
if (files.length === undefined) {
this.service.upload(ctx, files, false);
} else {
this.service.upload(ctx, files, true);
}
};
}
export default new FileController();

15
apps/test-server/controller/UserController.ts

@ -0,0 +1,15 @@
import UserService from '../service/UserService';
class UserController {
private service: UserService = new UserService();
login = async (ctx) => {
ctx.body = await this.service.login();
};
getUserInfoById = async (ctx) => {
ctx.body = await this.service.getUserInfoById();
};
}
export default new UserController();

18
apps/test-server/ecosystem.config.js

@ -0,0 +1,18 @@
const { name } = require('./package.json');
const path = require('path');
module.exports = {
apps: [
{
name,
script: path.resolve(__dirname, './dist/index.js'),
instances: require('os').cpus().length,
autorestart: true,
watch: true,
env_production: {
NODE_ENV: 'production',
PORT: 8080,
},
},
],
};

63
apps/test-server/index.ts

@ -0,0 +1,63 @@
import Koa from 'koa';
import path from 'path';
import Router from 'koa-router';
import body from 'koa-body';
import cors from 'koa2-cors';
import koaStatic from 'koa-static';
import websockify from 'koa-websocket';
import route from 'koa-route';
import AppRoutes from './routes';
const PORT = 3300;
const app = websockify(new Koa());
app.ws.use(function (ctx, next) {
ctx.websocket.send('connection succeeded!');
return next(ctx);
});
app.ws.use(
route.all('/test', function (ctx) {
// ctx.websocket.send('Hello World');
ctx.websocket.on('message', function (message) {
// do something with the message from client
if (message !== 'ping') {
const data = JSON.stringify({
id: Math.ceil(Math.random() * 1000),
time: new Date().getTime(),
res: `${message}`,
});
ctx.websocket.send(data);
}
console.log(message);
});
}),
);
const router = new Router();
// router
AppRoutes.forEach((route) => router[route.method](route.path, route.action));
app.use(cors());
app.use(
body({
encoding: 'gzip',
multipart: true,
formidable: {
// uploadDir: path.join(__dirname, '/upload/'), // 设置文件上传目录
keepExtensions: true,
maxFieldsSize: 20 * 1024 * 1024,
},
}),
);
app.use(router.routes());
app.use(router.allowedMethods());
app.use(koaStatic(path.join(__dirname)));
app.listen(PORT, () => {
console.log(`Application started successfully: http://localhost:${PORT}`);
});

8
apps/test-server/nodemon.json

@ -0,0 +1,8 @@
{
"watch": ["src"],
"ext": "ts",
"exec": "ts-node -r tsconfig-paths/register index.ts",
"events": {
"restart": "clear"
}
}

36
apps/test-server/package.json

@ -0,0 +1,36 @@
{
"name": "server",
"version": "1.0.0",
"license": "MIT",
"scripts": {
"compile": "rimraf ./dist && tsup ./index.ts --dts --format cjs,esm ",
"prod": "npx pm2 start ecosystem.config.js --env production",
"restart": "pm2 restart ecosystem.config.js --env production",
"start": "nodemon",
"stop": "npx pm2 stop ecosystem.config.js"
},
"dependencies": {
"fs-extra": "^11.1.1",
"koa": "^2.14.2",
"koa-body": "^6.0.1",
"koa-bodyparser": "^4.4.1",
"koa-route": "^3.2.0",
"koa-router": "^12.0.0",
"koa-static": "^5.0.0",
"koa-websocket": "^7.0.0",
"koa2-cors": "^2.0.6"
},
"devDependencies": {
"@types/koa": "^2.13.6",
"@types/koa-bodyparser": "^5.0.2",
"@types/koa-router": "^7.4.4",
"@types/node": "^20.4.0",
"nodemon": "^2.0.22",
"pm2": "^5.3.0",
"rimraf": "^5.0.1",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"tsup": "^7.1.0",
"typescript": "^5.1.6"
}
}

23
apps/test-server/routes.ts

@ -0,0 +1,23 @@
import UserController from './controller/UserController';
import FileController from './controller/FileController';
export default [
// user
{
path: '/login',
method: 'post',
action: UserController.login,
},
{
path: '/getUserInfoById',
method: 'get',
action: UserController.getUserInfoById,
},
// file
{
path: '/upload',
method: 'post',
action: FileController.upload,
},
];

54
apps/test-server/service/FileService.ts

@ -0,0 +1,54 @@
import path from 'path';
import fs from 'fs-extra';
const uploadUrl = 'http://localhost:3300/static/upload';
const filePath = path.join(__dirname, '../static/upload/');
fs.ensureDir(filePath);
export default class UserService {
async upload(ctx, files, isMultiple) {
let fileReader, fileResource, writeStream;
const fileFunc = function (file) {
fileReader = fs.createReadStream(file.path);
fileResource = filePath + `/${file.name}`;
console.log(fileResource);
writeStream = fs.createWriteStream(fileResource);
fileReader.pipe(writeStream);
};
const returnFunc = function (flag) {
if (flag) {
let url = '';
for (let i = 0; i < files.length; i++) {
url += uploadUrl + `/${files[i].name},`;
}
url = url.replace(/,$/gi, '');
ctx.body = {
url: url,
code: 0,
message: 'upload Success!',
};
} else {
ctx.body = {
url: uploadUrl + `/${files.name}`,
code: 0,
message: 'upload Success!',
};
}
};
console.log(isMultiple, files.length);
if (isMultiple) {
for (let i = 0; i < files.length; i++) {
const f1 = files[i];
fileFunc(f1);
}
} else {
fileFunc(files);
}
fs.ensureDir(filePath);
returnFunc(isMultiple);
}
}

25
apps/test-server/service/UserService.ts

@ -0,0 +1,25 @@
import { Result } from '../utils';
const fakeUserInfo = {
userId: '1',
username: 'vben',
realName: 'Vben Admin',
desc: 'manager',
password: '123456',
token: 'fakeToken1',
roles: [
{
roleName: 'Super Admin',
value: 'super',
},
],
};
export default class UserService {
async login() {
return Result.success(fakeUserInfo);
}
async getUserInfoById() {
return Result.success(fakeUserInfo);
}
}

7
apps/test-server/tsconfig.json

@ -0,0 +1,7 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@vben/ts-config/node-server.json",
"compilerOptions": {
"noImplicitAny": false
}
}

9
apps/test-server/utils.ts

@ -0,0 +1,9 @@
export class Result {
static success(data: any) {
return {
code: 0,
success: true,
result: data,
};
}
}

158
index.html

@ -0,0 +1,158 @@
<!DOCTYPE html>
<html lang="en" id="htmlRoot">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
<title><%= VITE_GLOB_APP_TITLE %></title>
<link rel="icon" href="/favicon.ico" />
</head>
<body>
<div id="app">
<style>
html {
/* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
line-height: 1.15;
}
html[data-theme='dark'] .app-loading {
background-color: #2c344a;
}
html[data-theme='dark'] .app-loading .app-loading-title {
color: rgb(255 255 255 / 85%);
}
.app-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: #f4f7f9;
}
.app-loading .app-loading-wrap {
display: flex;
position: absolute;
top: 50%;
left: 50%;
flex-direction: column;
align-items: center;
justify-content: center;
transform: translate3d(-50%, -50%, 0);
}
.app-loading .dots {
display: flex;
align-items: center;
justify-content: center;
padding: 98px;
}
.app-loading .app-loading-title {
display: flex;
align-items: center;
justify-content: center;
margin-top: 30px;
color: rgb(0 0 0 / 85%);
font-size: 30px;
}
.app-loading .app-loading-logo {
display: block;
width: 90px;
margin: 0 auto;
margin-bottom: 20px;
}
.dot {
display: inline-block;
position: relative;
box-sizing: border-box;
width: 48px;
height: 48px;
margin-top: 30px;
transform: rotate(45deg);
animation: ant-rotate 1.2s infinite linear;
font-size: 32px;
}
.dot i {
display: block;
position: absolute;
width: 20px;
height: 20px;
transform: scale(0.75);
transform-origin: 50% 50%;
animation: ant-spin-move 1s infinite linear alternate;
border-radius: 100%;
opacity: 0.3;
background-color: #1677ff;
}
.dot i:nth-child(1) {
top: 0;
left: 0;
}
.dot i:nth-child(2) {
top: 0;
right: 0;
animation-delay: 0.4s;
}
.dot i:nth-child(3) {
right: 0;
bottom: 0;
animation-delay: 0.8s;
}
.dot i:nth-child(4) {
bottom: 0;
left: 0;
animation-delay: 1.2s;
}
@keyframes ant-rotate {
to {
transform: rotate(405deg);
}
}
@keyframes ant-rotate {
to {
transform: rotate(405deg);
}
}
@keyframes ant-spin-move {
to {
opacity: 1;
}
}
@keyframes ant-spin-move {
to {
opacity: 1;
}
}
</style>
<div class="app-loading">
<div class="app-loading-wrap">
<img src="/logo.png" class="app-loading-logo" alt="Logo" />
<div class="app-loading-dots">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
<div class="app-loading-title"><%= VITE_GLOB_APP_TITLE %></div>
</div>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

9
internal/eslint-config/.eslintignore

@ -0,0 +1,9 @@
*.sh
node_modules
*.md
*.woff
*.ttf
.turbo
dist
package.json

4
internal/eslint-config/.eslintrc.js

@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@vben/eslint-config/strict'],
};

10
internal/eslint-config/build.config.ts

@ -0,0 +1,10 @@
import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
entries: ['src/index', 'src/strict'],
declaration: true,
rollup: {
emitCJS: true,
},
});

49
internal/eslint-config/package.json

@ -0,0 +1,49 @@
{
"name": "@vben/eslint-config",
"version": "1.0.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": {
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
"directory": "internal/eslint-config"
},
"license": "MIT",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./strict": {
"types": "./dist/strict.d.ts",
"import": "./dist/strict.mjs",
"require": "./dist/strict.cjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"clean": "pnpm rimraf .turbo node_modules dist",
"lint": "pnpm eslint .",
"stub": "pnpm unbuild --stub"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.3.0",
"@typescript-eslint/parser": "^6.3.0",
"eslint": "^8.46.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-vue": "^9.17.0",
"vue-eslint-parser": "^9.3.1"
}
}

91
internal/eslint-config/src/index.ts

@ -0,0 +1,91 @@
export default {
env: {
browser: true,
node: true,
es6: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
jsxPragma: 'React',
ecmaFeatures: {
jsx: true,
},
project: './tsconfig.*?.json',
createDefaultProgram: false,
extraFileExtensions: ['.vue'],
},
plugins: ['vue', '@typescript-eslint', 'import'],
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
rules: {
'no-unused-vars': 'off',
'no-case-declarations': 'off',
'no-use-before-define': 'off',
'space-before-function-paren': 'off',
'import/first': 'error',
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'vue/script-setup-uses-vars': 'error',
'vue/no-reserved-component-names': 'off',
'vue/custom-event-name-casing': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/require-default-prop': 'off',
'vue/require-explicit-emits': 'off',
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'never',
component: 'always',
},
svg: 'always',
math: 'always',
},
],
'vue/multi-word-component-names': 'off',
// 'sort-imports': [
// 'error',
// {
// ignoreCase: true,
// ignoreDeclarationSort: false,
// ignoreMemberSort: false,
// memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
// allowSeparatedGroups: false,
// },
// ],
},
globals: { defineOptions: 'readonly' },
};

57
internal/eslint-config/src/strict.ts

@ -0,0 +1,57 @@
export default {
extends: ['@vben'],
plugins: ['simple-import-sort'],
rules: {
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-expect-error': 'allow-with-description',
'ts-ignore': 'allow-with-description',
'ts-nocheck': 'allow-with-description',
'ts-check': false,
},
],
/**
*
* @link https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/keyword-spacing.md
*/
'keyword-spacing': 'off',
'@typescript-eslint/keyword-spacing': [
'error',
{
before: true,
after: true,
overrides: {
return: { after: true },
throw: { after: true },
case: { after: true },
},
},
],
/**
* async/await/generator
* @link https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-empty-function.md
*/
'no-empty-function': 'off',
'@typescript-eslint/no-empty-function': [
'error',
{
allow: ['arrowFunctions', 'functions', 'methods'],
},
],
/**
* 使 interface type
* @link https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-definitions.md
*/
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
'vue/attributes-order': 'error',
'vue/require-default-prop': 'error',
},
};

5
internal/eslint-config/tsconfig.json

@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@vben/ts-config/node.json",
"include": ["src"]
}

9
internal/stylelint-config/.eslintignore

@ -0,0 +1,9 @@
*.sh
node_modules
*.md
*.woff
*.ttf
.turbo
dist
package.json

4
internal/stylelint-config/.eslintrc.js

@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@vben/eslint-config/strict'],
};

10
internal/stylelint-config/build.config.ts

@ -0,0 +1,10 @@
import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
entries: ['src/index'],
declaration: true,
rollup: {
emitCJS: true,
},
});

49
internal/stylelint-config/package.json

@ -0,0 +1,49 @@
{
"name": "@vben/stylelint-config",
"version": "1.0.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": {
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
"directory": "internal/stylelint-config"
},
"license": "MIT",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"clean": "pnpm rimraf .turbo node_modules dist",
"lint": "pnpm eslint .",
"stub": "pnpm unbuild --stub"
},
"devDependencies": {
"postcss": "^8.4.24",
"postcss-html": "^1.5.0",
"postcss-less": "^6.0.0",
"postcss-scss": "^4.0.6",
"prettier": "^2.8.8",
"stylelint": "^15.10.1",
"stylelint-config-property-sort-order-smacss": "^9.1.0",
"stylelint-config-recommended": "^13.0.0",
"stylelint-config-recommended-scss": "^12.0.0",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^34.0.0",
"stylelint-config-standard-scss": "^10.0.0",
"stylelint-order": "^6.0.3",
"stylelint-prettier": "^3.0.0"
}
}

92
internal/stylelint-config/src/index.ts

@ -0,0 +1,92 @@
export default {
extends: ['stylelint-config-standard', 'stylelint-config-property-sort-order-smacss'],
plugins: ['stylelint-order', 'stylelint-prettier'],
// customSyntax: 'postcss-html',
overrides: [
{
files: ['**/*.(css|html|vue)'],
customSyntax: 'postcss-html',
},
{
files: ['*.less', '**/*.less'],
customSyntax: 'postcss-less',
extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'],
},
{
files: ['*.scss', '**/*.scss'],
customSyntax: 'postcss-scss',
extends: ['stylelint-config-standard-scss', 'stylelint-config-recommended-vue/scss'],
rule: {
'scss/percent-placeholder-pattern': null,
},
},
],
rules: {
'media-feature-range-notation': null,
'selector-not-notation': null,
'import-notation': null,
'function-no-unknown': null,
'selector-class-pattern': null,
'selector-pseudo-class-no-unknown': [
true,
{
ignorePseudoClasses: ['global', 'deep'],
},
],
'selector-pseudo-element-no-unknown': [
true,
{
ignorePseudoElements: ['v-deep'],
},
],
'at-rule-no-unknown': [
true,
{
ignoreAtRules: [
'tailwind',
'apply',
'variants',
'responsive',
'screen',
'function',
'if',
'each',
'include',
'mixin',
'extend',
],
},
],
'no-empty-source': null,
'string-quotes': null,
'named-grid-areas-no-invalid': null,
'no-descending-specificity': null,
'font-family-no-missing-generic-family-keyword': null,
'rule-empty-line-before': [
'always',
{
ignore: ['after-comment', 'first-nested'],
},
],
'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }],
'order/order': [
[
'dollar-variables',
'custom-properties',
'at-rules',
'declarations',
{
type: 'at-rule',
name: 'supports',
},
{
type: 'at-rule',
name: 'media',
},
'rules',
],
{ severity: 'error' },
],
},
ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'],
};

5
internal/stylelint-config/tsconfig.json

@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@vben/ts-config/node.json",
"include": ["src"]
}

27
internal/ts-config/base.json

@ -0,0 +1,27 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Base",
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"declaration": true,
"noImplicitOverride": true,
"noUnusedLocals": true,
"esModuleInterop": true,
"useUnknownInCatchVariables": false,
"composite": false,
"declarationMap": false,
"forceConsistentCasingInFileNames": true,
"inlineSources": false,
"isolatedModules": true,
"skipLibCheck": true,
"noUnusedParameters": false,
"preserveWatchOutput": true,
"experimentalDecorators": true,
"resolveJsonModule": true,
"removeComments": true
},
"exclude": ["**/node_modules/**", "**/dist/**"]
}

18
internal/ts-config/node-server.json

@ -0,0 +1,18 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Node Server Config",
"extends": "./base.json",
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": false,
"esModuleInterop": true,
"outDir": "./dist",
"baseUrl": "./"
},
"exclude": ["node_modules"]
}

12
internal/ts-config/node.json

@ -0,0 +1,12 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Node Config",
"extends": "./base.json",
"compilerOptions": {
"lib": ["ESNext"],
"noImplicitAny": true,
"sourceMap": true,
"noEmit": true,
"baseUrl": "./"
}
}

25
internal/ts-config/package.json

@ -0,0 +1,25 @@
{
"name": "@vben/ts-config",
"version": "1.0.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": {
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
"directory": "internal/ts-config"
},
"license": "MIT",
"files": [
"base.json",
"node.json",
"vue-app.json",
"node-server.json"
],
"dependencies": {
"@types/node": "^20.4.0",
"vite": "^4.4.0"
}
}

10
internal/ts-config/vue-app.json

@ -0,0 +1,10 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Vue Application",
"extends": "./base.json",
"compilerOptions": {
"jsx": "preserve",
"lib": ["ESNext", "DOM"],
"noImplicitAny": false
}
}

9
internal/vite-config/.eslintignore

@ -0,0 +1,9 @@
*.sh
node_modules
*.md
*.woff
*.ttf
.turbo
dist
package.json

4
internal/vite-config/.eslintrc.js

@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@vben/eslint-config/strict'],
};

10
internal/vite-config/build.config.ts

@ -0,0 +1,10 @@
import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
entries: ['src/index'],
declaration: true,
rollup: {
emitCJS: true,
},
});

58
internal/vite-config/package.json

@ -0,0 +1,58 @@
{
"name": "@vben/vite-config",
"version": "1.0.0",
"private": true,
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": {
"url": "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",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"clean": "pnpm rimraf .turbo node_modules dist",
"lint": "pnpm eslint .",
"stub": "pnpm unbuild --stub"
},
"dependencies": {
"@ant-design/colors": "^7.0.0",
"vite": "^4.4.0"
},
"devDependencies": {
"@types/fs-extra": "^11.0.1",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"ant-design-vue": "^4.0.6",
"dayjs": "^1.11.9",
"dotenv": "^16.3.1",
"fs-extra": "^11.1.1",
"less": "^4.1.3",
"picocolors": "^1.0.0",
"pkg-types": "^1.0.3",
"rollup-plugin-visualizer": "^5.9.2",
"sass": "^1.63.6",
"unocss": "0.53.4",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-dts": "^3.1.0",
"vite-plugin-html-easy": "^3.2.0",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-purge-icons": "^0.9.2",
"vite-plugin-svg-icons": "^2.0.1"
}
}

105
internal/vite-config/src/config/application.ts

@ -0,0 +1,105 @@
import { resolve } from 'node:path';
import dayjs from 'dayjs';
import { readPackageJSON } from 'pkg-types';
import { defineConfig, loadEnv, mergeConfig, type UserConfig } from 'vite';
import { createPlugins } from '../plugins';
import { generateModifyVars } from '../utils/modifyVars';
import { commonConfig } from './common';
interface DefineOptions {
overrides?: UserConfig;
options?: {
//
};
}
function defineApplicationConfig(defineOptions: DefineOptions = {}) {
const { overrides = {} } = defineOptions;
return defineConfig(async ({ command, mode }) => {
const root = process.cwd();
const isBuild = command === 'build';
const { VITE_PUBLIC_PATH, VITE_BUILD_COMPRESS, VITE_ENABLE_ANALYZE } = loadEnv(mode, root);
const defineData = await createDefineData(root);
const plugins = await createPlugins({
isBuild,
root,
enableAnalyze: VITE_ENABLE_ANALYZE === 'true',
compress: VITE_BUILD_COMPRESS,
});
const pathResolve = (pathname: string) => resolve(root, '.', pathname);
const timestamp = new Date().getTime();
const applicationConfig: UserConfig = {
base: VITE_PUBLIC_PATH,
resolve: {
alias: [
{
find: 'vue-i18n',
replacement: 'vue-i18n/dist/vue-i18n.cjs.js',
},
// @/xxxx => src/xxxx
{
find: /@\//,
replacement: pathResolve('src') + '/',
},
// #/xxxx => types/xxxx
{
find: /#\//,
replacement: pathResolve('types') + '/',
},
],
},
define: defineData,
build: {
target: 'es2015',
cssTarget: 'chrome80',
rollupOptions: {
output: {
// 入口文件名
entryFileNames: `assets/entry/[name]-[hash]-${timestamp}.js`,
manualChunks: {
vue: ['vue', 'pinia', 'vue-router'],
antd: ['ant-design-vue', '@ant-design/icons-vue'],
},
},
},
},
css: {
preprocessorOptions: {
less: {
modifyVars: generateModifyVars(),
javascriptEnabled: true,
},
},
},
plugins,
};
const mergedConfig = mergeConfig(commonConfig(mode), applicationConfig);
return mergeConfig(mergedConfig, overrides);
});
}
async function createDefineData(root: string) {
try {
const pkgJson = await readPackageJSON(root);
const { dependencies, devDependencies, name, version } = pkgJson;
const __APP_INFO__ = {
pkg: { dependencies, devDependencies, name, version },
lastBuildTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
};
return {
__APP_INFO__: JSON.stringify(__APP_INFO__),
};
} catch (error) {
return {};
}
}
export { defineApplicationConfig };

22
internal/vite-config/src/config/common.ts

@ -0,0 +1,22 @@
import UnoCSS from 'unocss/vite';
import { type UserConfig } from 'vite';
const commonConfig: (mode: string) => UserConfig = (mode) => ({
server: {
host: true,
},
esbuild: {
drop: mode === 'production' ? ['console', 'debugger'] : [],
},
build: {
reportCompressedSize: false,
chunkSizeWarningLimit: 1500,
rollupOptions: {
// TODO: Prevent memory overflow
maxParallelFileOps: 3,
},
},
plugins: [UnoCSS()],
});
export { commonConfig };

42
internal/vite-config/src/config/package.ts

@ -0,0 +1,42 @@
import { readPackageJSON } from 'pkg-types';
import { defineConfig, mergeConfig, type UserConfig } from 'vite';
import dts from 'vite-plugin-dts';
import { commonConfig } from './common';
interface DefineOptions {
overrides?: UserConfig;
options?: {
//
};
}
function definePackageConfig(defineOptions: DefineOptions = {}) {
const { overrides = {} } = defineOptions;
const root = process.cwd();
return defineConfig(async ({ mode }) => {
const { dependencies = {}, peerDependencies = {} } = await readPackageJSON(root);
const packageConfig: UserConfig = {
build: {
lib: {
entry: 'src/index.ts',
formats: ['es'],
fileName: () => 'index.mjs',
},
rollupOptions: {
external: [...Object.keys(dependencies), ...Object.keys(peerDependencies)],
},
},
plugins: [
dts({
logLevel: 'error',
}),
],
};
const mergedConfig = mergeConfig(commonConfig(mode), packageConfig);
return mergeConfig(mergedConfig, overrides);
});
}
export { definePackageConfig };

2
internal/vite-config/src/index.ts

@ -0,0 +1,2 @@
export * from './config/application';
export * from './config/package';

104
internal/vite-config/src/plugins/appConfig.ts

@ -0,0 +1,104 @@
import colors from 'picocolors';
import { readPackageJSON } from 'pkg-types';
import { type PluginOption } from 'vite';
import { getEnvConfig } from '../utils/env';
import { createContentHash } from '../utils/hash';
const GLOBAL_CONFIG_FILE_NAME = '_app.config.js';
const PLUGIN_NAME = 'app-config';
async function createAppConfigPlugin({
root,
isBuild,
}: {
root: string;
isBuild: boolean;
}): Promise<PluginOption> {
let publicPath: string;
let source: string;
if (!isBuild) {
return {
name: PLUGIN_NAME,
};
}
const { version = '' } = await readPackageJSON(root);
return {
name: PLUGIN_NAME,
async configResolved(_config) {
const appTitle = _config?.env?.VITE_GLOB_APP_TITLE ?? '';
// appTitle = appTitle.replace(/\s/g, '_').replace(/-/g, '_');
publicPath = _config.base;
source = await getConfigSource(appTitle);
},
async transformIndexHtml(html) {
publicPath = publicPath.endsWith('/') ? publicPath : `${publicPath}/`;
const appConfigSrc = `${
publicPath || '/'
}${GLOBAL_CONFIG_FILE_NAME}?v=${version}-${createContentHash(source)}`;
return {
html,
tags: [
{
tag: 'script',
attrs: {
src: appConfigSrc,
},
},
],
};
},
async generateBundle() {
try {
this.emitFile({
type: 'asset',
fileName: GLOBAL_CONFIG_FILE_NAME,
source,
});
console.log(colors.cyan(`✨configuration file is build successfully!`));
} catch (error) {
console.log(
colors.red('configuration file configuration file failed to package:\n' + error),
);
}
},
};
}
/**
* Get the configuration file variable name
* @param env
*/
const getVariableName = (title: string) => {
function strToHex(str: string) {
const result: string[] = [];
for (let i = 0; i < str.length; ++i) {
const hex = str.charCodeAt(i).toString(16);
result.push(('000' + hex).slice(-4));
}
return result.join('').toUpperCase();
}
return `__PRODUCTION__${strToHex(title) || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, '');
};
async function getConfigSource(appTitle: string) {
const config = await getEnvConfig();
const variableName = getVariableName(appTitle);
const windowVariable = `window.${variableName}`;
// Ensure that the variable will not be modified
let source = `${windowVariable}=${JSON.stringify(config)};`;
source += `
Object.freeze(${windowVariable});
Object.defineProperty(window, "${variableName}", {
configurable: false,
writable: false,
});
`.replace(/\s/g, '');
return source;
}
export { createAppConfigPlugin };

38
internal/vite-config/src/plugins/compress.ts

@ -0,0 +1,38 @@
/**
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated
* https://github.com/anncwb/vite-plugin-compression
*/
import type { PluginOption } from 'vite';
import compressPlugin from 'vite-plugin-compression';
export function configCompressPlugin({
compress,
deleteOriginFile = false,
}: {
compress: string;
deleteOriginFile?: boolean;
}): PluginOption[] {
const compressList = compress.split(',');
const plugins: PluginOption[] = [];
if (compressList.includes('gzip')) {
plugins.push(
compressPlugin({
ext: '.gz',
deleteOriginFile,
}),
);
}
if (compressList.includes('brotli')) {
plugins.push(
compressPlugin({
ext: '.br',
algorithm: 'brotliCompress',
deleteOriginFile,
}),
);
}
return plugins;
}

13
internal/vite-config/src/plugins/html.ts

@ -0,0 +1,13 @@
/**
* Plugin to minimize and use ejs template syntax in index.html.
* https://github.com/anncwb/vite-plugin-html
*/
import type { PluginOption } from 'vite';
import { createHtmlPlugin } from 'vite-plugin-html-easy';
export function configHtmlPlugin({ isBuild }: { isBuild: boolean }) {
const htmlPlugin: PluginOption[] = createHtmlPlugin({
minify: isBuild,
});
return htmlPlugin;
}

52
internal/vite-config/src/plugins/index.ts

@ -0,0 +1,52 @@
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { type PluginOption } from 'vite';
import purgeIcons from 'vite-plugin-purge-icons';
import { createAppConfigPlugin } from './appConfig';
import { configCompressPlugin } from './compress';
import { configHtmlPlugin } from './html';
import { configSvgIconsPlugin } from './svgSprite';
import { configVisualizerConfig } from './visualizer';
interface Options {
isBuild: boolean;
root: string;
compress: string;
enableAnalyze?: boolean;
}
async function createPlugins({ isBuild, root, compress, enableAnalyze }: Options) {
const vitePlugins: (PluginOption | PluginOption[])[] = [vue(), vueJsx()];
const appConfigPlugin = await createAppConfigPlugin({ root, isBuild });
vitePlugins.push(appConfigPlugin);
// vite-plugin-html
vitePlugins.push(configHtmlPlugin({ isBuild }));
// vite-plugin-svg-icons
vitePlugins.push(configSvgIconsPlugin({ isBuild }));
// vite-plugin-purge-icons
vitePlugins.push(purgeIcons());
// The following plugins only work in the production environment
if (isBuild) {
// rollup-plugin-gzip
vitePlugins.push(
configCompressPlugin({
compress,
}),
);
}
// rollup-plugin-visualizer
if (enableAnalyze) {
vitePlugins.push(configVisualizerConfig());
}
return vitePlugins;
}
export { createPlugins };

17
internal/vite-config/src/plugins/svgSprite.ts

@ -0,0 +1,17 @@
/**
* Vite Plugin for fast creating SVG sprites.
* https://github.com/anncwb/vite-plugin-svg-icons
*/
import { resolve } from 'node:path';
import type { PluginOption } from 'vite';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
export function configSvgIconsPlugin({ isBuild }: { isBuild: boolean }) {
const svgIconsPlugin = createSvgIconsPlugin({
iconDirs: [resolve(process.cwd(), 'src/assets/icons')],
svgoOptions: isBuild,
});
return svgIconsPlugin as PluginOption;
}

14
internal/vite-config/src/plugins/visualizer.ts

@ -0,0 +1,14 @@
/**
* Package file volume analysis
*/
import visualizer from 'rollup-plugin-visualizer';
import { type PluginOption } from 'vite';
export function configVisualizerConfig() {
return visualizer({
filename: './node_modules/.cache/visualizer/stats.html',
open: true,
gzipSize: true,
brotliSize: true,
}) as PluginOption;
}

49
internal/vite-config/src/utils/env.ts

@ -0,0 +1,49 @@
import { join } from 'node:path';
import dotenv from 'dotenv';
import { readFile } from 'fs-extra';
/**
*
*/
function getConfFiles() {
const script = process.env.npm_lifecycle_script as string;
const reg = new RegExp('--mode ([a-z_\\d]+)');
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
*/
export async function getEnvConfig(
match = 'VITE_GLOB_',
confFiles = getConfFiles(),
): Promise<{
[key: string]: string;
}> {
let envConfig = {};
for (const confFile of confFiles) {
try {
const envPath = await readFile(join(process.cwd(), confFile), { encoding: 'utf8' });
const env = dotenv.parse(envPath);
envConfig = { ...envConfig, ...env };
} catch (e) {
console.error(`Error in parsing ${confFile}`, e);
}
}
const reg = new RegExp(`^(${match})`);
Object.keys(envConfig).forEach((key) => {
if (!reg.test(key)) {
Reflect.deleteProperty(envConfig, key);
}
});
return envConfig;
}

16
internal/vite-config/src/utils/hash.ts

@ -0,0 +1,16 @@
import { createHash } from 'node:crypto';
function createContentHash(content: string, hashLSize = 12) {
const hash = createHash('sha256').update(content);
return hash.digest('hex').slice(0, hashLSize);
}
function strToHex(str: string) {
const result: string[] = [];
for (let i = 0; i < str.length; ++i) {
const hex = str.charCodeAt(i).toString(16);
result.push(('000' + hex).slice(-4));
}
return result.join('').toUpperCase();
}
export { createContentHash, strToHex };

47
internal/vite-config/src/utils/modifyVars.ts

@ -0,0 +1,47 @@
import { resolve } from 'node:path';
import { generate } from '@ant-design/colors';
// @ts-ignore: typo
/* import { getThemeVariables } from 'ant-design-vue/dist/theme'; */
import { theme } from 'ant-design-vue/lib';
import convertLegacyToken from 'ant-design-vue/lib/theme/convertLegacyToken';
const { defaultAlgorithm, defaultSeed } = theme;
const primaryColor = '#1890ff';
function generateAntColors(color: string, theme: 'default' | 'dark' = 'default') {
return generate(color, {
theme,
});
}
/**
* less global variable
*/
export function generateModifyVars() {
const palettes = generateAntColors(primaryColor);
const primary = palettes[5];
const primaryColorObj: Record<string, string> = {};
for (let index = 0; index < 10; index++) {
primaryColorObj[`primary-${index + 1}`] = palettes[index];
}
// const modifyVars = getThemeVariables();
const mapToken = defaultAlgorithm(defaultSeed);
const v3Token = convertLegacyToken(mapToken);
return {
...v3Token,
// reference: Avoid repeated references
hack: `true; @import (reference) "${resolve('src/design/config.less')}";`,
'primary-color': primary,
...primaryColorObj,
'info-color': primary,
'processing-color': primary,
// 'success-color': '#55D187', // Success color
// 'error-color': '#ED6F6F', // False color
// 'warning-color': '#EFBD47', // Warning color
'font-size-base': '14px', // Main font size
// 'border-radius-base': '2px', // Component/float fillet
'link-color': primary, // Link color
};
}

5
internal/vite-config/tsconfig.json

@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@vben/ts-config/node.json",
"include": ["src"]
}

39
nginx.conf

@ -0,0 +1,39 @@
#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;
server {
listen 80;
location / {
root /usr/share/nginx/html/dist;
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;
}
# docker 改造之后不再需要
# if ($request_filename ~* ^.*?.(html|htm|js)$) {
# add_header Cache-Control no-cache;
# }
}
}
}

156
package.json

@ -0,0 +1,156 @@
{
"name": "vben-admin",
"version": "2.10.1",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": {
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vbenjs/vue-vben-admin.git"
},
"license": "MIT",
"author": {
"name": "vben",
"email": "anncwb@126.com",
"url": "https://github.com/anncwb"
},
"scripts": {
"bootstrap": "pnpm install",
"build": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build",
"build:analyze": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode analyze",
"build:docker": "vite build --mode docker",
"build:no-cache": "pnpm store prune && npm run build",
"build:test": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode test",
"commit": "czg",
"dev": "pnpm vite",
"preinstall": "npx only-allow pnpm",
"postinstall": "turbo run stub",
"lint": "turbo run lint",
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
"lint:prettier": "prettier --write .",
"lint:stylelint": "stylelint \"**/*.{vue,css,less,scss}\" --fix --cache --cache-location node_modules/.cache/stylelint/",
"prepare": "husky install",
"preview": "npm run build && vite preview",
"reinstall": "rimraf pnpm-lock.yaml && rimraf package.lock.json && rimraf node_modules && npm run bootstrap",
"serve": "npm run dev",
"test:gzip": "npx http-server dist --cors --gzip -c-1",
"type:check": "vue-tsc --noEmit --skipLibCheck"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint --fix"
],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
"prettier --write--parser json"
],
"package.json": [
"prettier --write"
],
"*.vue": [
"prettier --write",
"eslint --fix",
"stylelint --fix"
],
"*.{scss,less,styl,html}": [
"prettier --write",
"stylelint --fix"
],
"*.md": [
"prettier --write"
]
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
},
"dependencies": {
"@ant-design/icons-vue": "^6.1.0",
"@iconify/iconify": "^3.1.1",
"@logicflow/core": "^1.2.9",
"@logicflow/extension": "^1.2.9",
"@vben/hooks": "workspace:*",
"@vue/shared": "^3.3.4",
"@vueuse/core": "^10.2.1",
"@vueuse/shared": "^10.2.1",
"@zxcvbn-ts/core": "^3.0.2",
"ant-design-vue": "^4.0.6",
"axios": "^1.4.0",
"codemirror": "^5.65.12",
"cropperjs": "^1.5.13",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.10",
"driver.js": "^1.3.0",
"echarts": "^5.4.2",
"exceljs": "^4.3.0",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.1",
"pinia": "2.1.4",
"pinia-plugin-persistedstate": "^3.2.0",
"print-js": "^1.6.0",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"resize-observer-polyfill": "^1.5.1",
"showdown": "^2.1.0",
"sortablejs": "^1.15.0",
"tinymce": "^5.10.7",
"unocss": "0.53.4",
"vditor": "^3.9.4",
"vue": "^3.3.4",
"vue-i18n": "^9.6.4",
"vue-json-pretty": "^2.2.4",
"vue-router": "^4.2.3",
"vue-types": "^5.1.0",
"vuedraggable": "^4.1.0",
"vxe-table": "^4.4.5",
"vxe-table-plugin-export-xlsx": "^3.0.4",
"xe-utils": "^3.5.11",
"xlsx": "^0.18.5",
"element-plus": "2.2.28"
},
"devDependencies": {
"@commitlint/cli": "^17.6.6",
"@commitlint/config-conventional": "^17.6.6",
"@iconify/json": "^2.2.87",
"@purge-icons/generated": "^0.9.0",
"@types/codemirror": "^5.60.8",
"@types/crypto-js": "^4.1.1",
"@types/lodash-es": "^4.17.7",
"@types/mockjs": "^1.0.7",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.5.1",
"@types/qs": "^6.9.7",
"@types/showdown": "^2.0.1",
"@types/sortablejs": "^1.15.1",
"@vben/eslint-config": "workspace:*",
"@vben/stylelint-config": "workspace:*",
"@vben/ts-config": "workspace:*",
"@vben/types": "workspace:*",
"@vben/vite-config": "workspace:*",
"@vue/compiler-sfc": "^3.3.4",
"@vue/test-utils": "^2.4.0",
"cross-env": "^7.0.3",
"cz-git": "^1.6.1",
"czg": "^1.6.1",
"husky": "^8.0.3",
"lint-staged": "13.2.3",
"prettier": "^2.8.8",
"prettier-plugin-packagejson": "^2.4.6",
"rimraf": "^5.0.1",
"turbo": "^1.10.7",
"typescript": "^5.2.2",
"unbuild": "^1.2.1",
"vite": "^4.4.0",
"vite-plugin-mock": "^2.9.6",
"vue-tsc": "^1.8.4"
},
"packageManager": "pnpm@8.1.0",
"engines": {
"node": ">=16.15.1",
"pnpm": ">=8.1.0"
}
}

0
packages/.gitkeep

4
packages/hooks/.eslintrc.js

@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@vben/eslint-config/strict'],
};

10
packages/hooks/build.config.ts

@ -0,0 +1,10 @@
import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
entries: ['src/index'],
declaration: true,
rollup: {
emitCJS: true,
},
});

39
packages/hooks/package.json

@ -0,0 +1,39 @@
{
"name": "@vben/hooks",
"version": "1.0.0",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": {
"url": "https://github.com/vbenjs/vue-vben-admin/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vbenjs/vue-vben-admin.git",
"directory": "packages/hooks"
},
"license": "MIT",
"sideEffects": false,
"exports": {
".": {
"default": "./src/index.ts"
}
},
"main": "./src/index.ts",
"module": "./src/index.ts",
"files": [
"dist"
],
"scripts": {
"//build": "pnpm unbuild",
"//stub": "pnpm unbuild --stub",
"clean": "pnpm rimraf .turbo node_modules dist",
"lint": "pnpm eslint ."
},
"dependencies": {
"@vueuse/core": "^10.2.1",
"lodash-es": "^4.17.21",
"vue": "^3.3.4"
},
"devDependencies": {
"@vben/types": "workspace:*"
}
}

7
packages/hooks/src/index.ts

@ -0,0 +1,7 @@
export * from './onMountedOrActivated';
export * from './useAttrs';
export * from './useRefs';
export * from './useRequest';
export * from './useScrollTo';
export * from './useWindowSizeFn';
export { useTimeoutFn } from '@vueuse/core';

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save