commit
218b4a39b7
1591 changed files with 210686 additions and 0 deletions
@ -0,0 +1,4 @@ |
|||
> 1% |
|||
last 2 versions |
|||
not dead |
|||
not ie 11 |
@ -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: 自定义',
|
|||
}, |
|||
}; |
@ -0,0 +1,3 @@ |
|||
node_modules/ |
|||
dist/ |
|||
.vscode/ |
@ -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 |
@ -0,0 +1,3 @@ |
|||
# 网站标题 |
|||
VITE_GLOB_APP_TITLE = 国研咨询 |
|||
|
@ -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 |
@ -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 |
@ -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= |
@ -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= |
|||
|
@ -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= |
@ -0,0 +1,16 @@ |
|||
|
|||
*.sh |
|||
node_modules |
|||
*.md |
|||
*.woff |
|||
*.ttf |
|||
.vscode |
|||
.idea |
|||
dist |
|||
/public |
|||
/docs |
|||
.husky |
|||
.local |
|||
/bin |
|||
Dockerfile |
|||
package.json |
@ -0,0 +1,7 @@ |
|||
module.exports = { |
|||
root: true, |
|||
extends: ['@vben'], |
|||
rules: { |
|||
'no-undef': 'off', |
|||
}, |
|||
}; |
@ -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 |
@ -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: |
@ -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? |
@ -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) 及其版本: |
@ -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. |
@ -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. |
@ -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. |
@ -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 |
@ -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 |
@ -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 |
@ -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' |
@ -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 |
@ -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. |
@ -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 |
@ -0,0 +1,6 @@ |
|||
ports: |
|||
- port: 3344 |
|||
onOpen: open-preview |
|||
tasks: |
|||
- init: pnpm install |
|||
command: pnpm run dev |
@ -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" |
@ -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 |
@ -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 |
@ -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 |
@ -0,0 +1,12 @@ |
|||
dist |
|||
.local |
|||
.output.js |
|||
node_modules |
|||
|
|||
**/*.svg |
|||
**/*.sh |
|||
|
|||
public |
|||
.npmrc |
|||
|
|||
*-lock.yaml |
@ -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', |
|||
}, |
|||
}, |
|||
], |
|||
}; |
@ -0,0 +1,2 @@ |
|||
dist |
|||
public |
@ -0,0 +1,4 @@ |
|||
module.exports = { |
|||
root: true, |
|||
extends: ['@vben/stylelint-config'], |
|||
}; |
@ -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" |
|||
] |
|||
} |
@ -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 |
|||
} |
|||
] |
|||
} |
@ -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 |
|||
} |
@ -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` |
|||
|
|||
- 🌟 添加基础功能 |
@ -0,0 +1 @@ |
|||
vben.vvbin.cn |
@ -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 "🎉 架 🎉 设 🎉 成 🎉 功 🎉" |
@ -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. |
@ -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,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 |
|||
|
|||
``` |
@ -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(); |
@ -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(); |
@ -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, |
|||
}, |
|||
}, |
|||
], |
|||
}; |
@ -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}`); |
|||
}); |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"watch": ["src"], |
|||
"ext": "ts", |
|||
"exec": "ts-node -r tsconfig-paths/register index.ts", |
|||
"events": { |
|||
"restart": "clear" |
|||
} |
|||
} |
@ -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" |
|||
} |
|||
} |
@ -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, |
|||
}, |
|||
]; |
@ -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); |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
{ |
|||
"$schema": "https://json.schemastore.org/tsconfig", |
|||
"extends": "@vben/ts-config/node-server.json", |
|||
"compilerOptions": { |
|||
"noImplicitAny": false |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
export class Result { |
|||
static success(data: any) { |
|||
return { |
|||
code: 0, |
|||
success: true, |
|||
result: data, |
|||
}; |
|||
} |
|||
} |
@ -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> |
@ -0,0 +1,9 @@ |
|||
|
|||
*.sh |
|||
node_modules |
|||
*.md |
|||
*.woff |
|||
*.ttf |
|||
.turbo |
|||
dist |
|||
package.json |
@ -0,0 +1,4 @@ |
|||
module.exports = { |
|||
root: true, |
|||
extends: ['@vben/eslint-config/strict'], |
|||
}; |
@ -0,0 +1,10 @@ |
|||
import { defineBuildConfig } from 'unbuild'; |
|||
|
|||
export default defineBuildConfig({ |
|||
clean: true, |
|||
entries: ['src/index', 'src/strict'], |
|||
declaration: true, |
|||
rollup: { |
|||
emitCJS: true, |
|||
}, |
|||
}); |
@ -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" |
|||
} |
|||
} |
@ -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' }, |
|||
}; |
@ -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', |
|||
}, |
|||
}; |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"$schema": "https://json.schemastore.org/tsconfig", |
|||
"extends": "@vben/ts-config/node.json", |
|||
"include": ["src"] |
|||
} |
@ -0,0 +1,9 @@ |
|||
|
|||
*.sh |
|||
node_modules |
|||
*.md |
|||
*.woff |
|||
*.ttf |
|||
.turbo |
|||
dist |
|||
package.json |
@ -0,0 +1,4 @@ |
|||
module.exports = { |
|||
root: true, |
|||
extends: ['@vben/eslint-config/strict'], |
|||
}; |
@ -0,0 +1,10 @@ |
|||
import { defineBuildConfig } from 'unbuild'; |
|||
|
|||
export default defineBuildConfig({ |
|||
clean: true, |
|||
entries: ['src/index'], |
|||
declaration: true, |
|||
rollup: { |
|||
emitCJS: true, |
|||
}, |
|||
}); |
@ -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" |
|||
} |
|||
} |
@ -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'], |
|||
}; |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"$schema": "https://json.schemastore.org/tsconfig", |
|||
"extends": "@vben/ts-config/node.json", |
|||
"include": ["src"] |
|||
} |
@ -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/**"] |
|||
} |
@ -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"] |
|||
} |
@ -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": "./" |
|||
} |
|||
} |
@ -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" |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
{ |
|||
"$schema": "https://json.schemastore.org/tsconfig", |
|||
"display": "Vue Application", |
|||
"extends": "./base.json", |
|||
"compilerOptions": { |
|||
"jsx": "preserve", |
|||
"lib": ["ESNext", "DOM"], |
|||
"noImplicitAny": false |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
|
|||
*.sh |
|||
node_modules |
|||
*.md |
|||
*.woff |
|||
*.ttf |
|||
.turbo |
|||
dist |
|||
package.json |
@ -0,0 +1,4 @@ |
|||
module.exports = { |
|||
root: true, |
|||
extends: ['@vben/eslint-config/strict'], |
|||
}; |
@ -0,0 +1,10 @@ |
|||
import { defineBuildConfig } from 'unbuild'; |
|||
|
|||
export default defineBuildConfig({ |
|||
clean: true, |
|||
entries: ['src/index'], |
|||
declaration: true, |
|||
rollup: { |
|||
emitCJS: true, |
|||
}, |
|||
}); |
@ -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" |
|||
} |
|||
} |
@ -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 }; |
@ -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 }; |
@ -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 }; |
@ -0,0 +1,2 @@ |
|||
export * from './config/application'; |
|||
export * from './config/package'; |
@ -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 }; |
@ -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; |
|||
} |
@ -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; |
|||
} |
@ -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 }; |
@ -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; |
|||
} |
@ -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; |
|||
} |
@ -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; |
|||
} |
@ -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 }; |
@ -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
|
|||
}; |
|||
} |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"$schema": "https://json.schemastore.org/tsconfig", |
|||
"extends": "@vben/ts-config/node.json", |
|||
"include": ["src"] |
|||
} |
@ -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; |
|||
# } |
|||
} |
|||
} |
|||
} |
@ -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,0 +1,4 @@ |
|||
module.exports = { |
|||
root: true, |
|||
extends: ['@vben/eslint-config/strict'], |
|||
}; |
@ -0,0 +1,10 @@ |
|||
import { defineBuildConfig } from 'unbuild'; |
|||
|
|||
export default defineBuildConfig({ |
|||
clean: true, |
|||
entries: ['src/index'], |
|||
declaration: true, |
|||
rollup: { |
|||
emitCJS: true, |
|||
}, |
|||
}); |
@ -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:*" |
|||
} |
|||
} |
@ -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…
Reference in new issue