mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 08:36:19 +08:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
01391ee5a1 | ||
![]() |
3572ce1538 | ||
![]() |
d1e1256202 | ||
![]() |
b7776c5148 | ||
![]() |
2d1519eca7 | ||
![]() |
93b5618b52 | ||
![]() |
639d2e1525 | ||
![]() |
26646d42f7 | ||
![]() |
17fa8eb93b | ||
![]() |
8250894a50 | ||
![]() |
a72b8acaf9 | ||
![]() |
a46c85d77d | ||
![]() |
fdc5b02c30 | ||
![]() |
476aa068d7 | ||
![]() |
bb6057cac3 | ||
![]() |
abbbbfb955 | ||
![]() |
79c87c9f46 | ||
![]() |
f815dcf3ae | ||
![]() |
1197efea26 | ||
![]() |
2a83f1d666 | ||
![]() |
4b3d2d21ed |
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@@ -19,6 +19,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
post-update:
|
post-update:
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
# if: ${{ github.actor == 'dependabot[bot]' }}
|
# if: ${{ github.actor == 'dependabot[bot]' }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
|
2
.github/workflows/changeset-version.yml
vendored
2
.github/workflows/changeset-version.yml
vendored
@@ -18,7 +18,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
version:
|
version:
|
||||||
if: (github.event.pull_request.merged || github.event_name == 'workflow_dispatch') && github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]')
|
if: (github.event.pull_request.merged || github.event_name == 'workflow_dispatch') && github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
|
||||||
# if: github.repository == 'vbenjs/vue-vben-admin'
|
# if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -17,6 +17,7 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
name: Test
|
name: Test
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -55,6 +56,7 @@ jobs:
|
|||||||
|
|
||||||
lint:
|
lint:
|
||||||
name: Lint
|
name: Lint
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -77,6 +79,7 @@ jobs:
|
|||||||
|
|
||||||
check:
|
check:
|
||||||
name: Check
|
name: Check
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
strategy:
|
strategy:
|
||||||
@@ -106,6 +109,7 @@ jobs:
|
|||||||
|
|
||||||
ci-ok:
|
ci-ok:
|
||||||
name: CI OK
|
name: CI OK
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [test, check, lint]
|
needs: [test, check, lint]
|
||||||
env:
|
env:
|
||||||
|
1
.github/workflows/codeql.yml
vendored
1
.github/workflows/codeql.yml
vendored
@@ -22,6 +22,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
name: Analyze (${{ matrix.language }})
|
name: Analyze (${{ matrix.language }})
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||||
# - https://gh.io/supported-runners-and-hardware-resources
|
# - https://gh.io/supported-runners-and-hardware-resources
|
||||||
|
10
.github/workflows/deploy.yml
vendored
10
.github/workflows/deploy.yml
vendored
@@ -8,7 +8,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
deploy-playground-ftp:
|
deploy-playground-ftp:
|
||||||
name: Deploy Push Playground Ftp
|
name: Deploy Push Playground Ftp
|
||||||
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]')
|
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
|
|
||||||
deploy-docs-ftp:
|
deploy-docs-ftp:
|
||||||
name: Deploy Push Docs Ftp
|
name: Deploy Push Docs Ftp
|
||||||
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]')
|
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
|
|
||||||
deploy-antd-ftp:
|
deploy-antd-ftp:
|
||||||
name: Deploy Push Antd Ftp
|
name: Deploy Push Antd Ftp
|
||||||
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]')
|
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -94,7 +94,7 @@ jobs:
|
|||||||
|
|
||||||
deploy-ele-ftp:
|
deploy-ele-ftp:
|
||||||
name: Deploy Push Element Ftp
|
name: Deploy Push Element Ftp
|
||||||
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]')
|
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@@ -125,7 +125,7 @@ jobs:
|
|||||||
|
|
||||||
deploy-naive-ftp:
|
deploy-naive-ftp:
|
||||||
name: Deploy Push Naive Ftp
|
name: Deploy Push Naive Ftp
|
||||||
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]')
|
if: github.actor != 'dependabot[bot]' && !contains(github.event.head_commit.message, '[skip ci]') && github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
|
1
.github/workflows/draft.yml
vendored
1
.github/workflows/draft.yml
vendored
@@ -17,6 +17,7 @@ jobs:
|
|||||||
# write permission is required for autolabeler
|
# write permission is required for autolabeler
|
||||||
# otherwise, read permission is required at least
|
# otherwise, read permission is required at least
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: release-drafter/release-drafter@v6
|
- uses: release-drafter/release-drafter@v6
|
||||||
|
20
.github/workflows/issue-close-require.yml
vendored
20
.github/workflows/issue-close-require.yml
vendored
@@ -3,23 +3,29 @@ name: Issue Close Require
|
|||||||
|
|
||||||
# 触发条件:每天零点
|
# 触发条件:每天零点
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * *'
|
- cron: '0 0 * * *'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
contents: write
|
contents: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
close-issues:
|
close-issues:
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
# 步骤1:关闭未活动的 Issues
|
# 关闭未活动的 Issues
|
||||||
- name: Close Inactive Issues
|
- name: Close Inactive Issues
|
||||||
uses: actions-cool/issues-helper@v3
|
uses: actions/stale@v9
|
||||||
with:
|
with:
|
||||||
actions: 'close-issues' # 执行动作:关闭 Issues
|
days-before-stale: -1 # Issues and PR will never be flagged stale automatically.
|
||||||
token: ${{ secrets.GITHUB_TOKEN }} # GitHub Token,用于认证
|
stale-issue-label: needs-reproduction # Label that flags an issue as stale.
|
||||||
labels: 'needs reproduction' # 目标标签
|
only-labels: needs-reproduction # Only process these issues
|
||||||
inactive-day: 3 # 未活动天数阈值
|
days-before-issue-close: 3
|
||||||
|
ignore-updates: true
|
||||||
|
remove-stale-when-updated: false
|
||||||
|
close-issue-message: This issue was closed because it was open for 3 days without a valid reproduction.
|
||||||
|
close-issue-label: closed-by-action
|
||||||
|
1
.github/workflows/issue-labeled.yml
vendored
1
.github/workflows/issue-labeled.yml
vendored
@@ -13,6 +13,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
reply-labeled:
|
reply-labeled:
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: remove enhancement pending
|
- name: remove enhancement pending
|
||||||
|
3
.github/workflows/lock.yml
vendored
3
.github/workflows/lock.yml
vendored
@@ -11,12 +11,13 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
action:
|
action:
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v5
|
- uses: dessant/lock-threads@v5
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
issue-inactive-days: '30'
|
issue-inactive-days: '14'
|
||||||
issue-lock-reason: ''
|
issue-lock-reason: ''
|
||||||
pr-inactive-days: '30'
|
pr-inactive-days: '30'
|
||||||
pr-lock-reason: ''
|
pr-lock-reason: ''
|
||||||
|
1
.github/workflows/release-tag.yml
vendored
1
.github/workflows/release-tag.yml
vendored
@@ -15,6 +15,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Create Release
|
name: Create Release
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
3
.github/workflows/semantic-pull-request.yml
vendored
3
.github/workflows/semantic-pull-request.yml
vendored
@@ -9,8 +9,9 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
main:
|
main:
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Semantic Pull Request
|
name: Semantic Pull Request
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Validate PR title
|
- name: Validate PR title
|
||||||
uses: amannn/action-semantic-pull-request@v5
|
uses: amannn/action-semantic-pull-request@v5
|
||||||
|
1
.github/workflows/stale.yml
vendored
1
.github/workflows/stale.yml
vendored
@@ -6,6 +6,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
|
if: github.repository == 'vbenjs/vue-vben-admin'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v9
|
- uses: actions/stale@v9
|
||||||
|
@@ -3,4 +3,4 @@ ports:
|
|||||||
onOpen: open-preview
|
onOpen: open-preview
|
||||||
tasks:
|
tasks:
|
||||||
- init: corepack enable && pnpm install
|
- init: corepack enable && pnpm install
|
||||||
command: pnpm run dev
|
command: pnpm run dev:play
|
||||||
|
@@ -125,6 +125,10 @@ pnpm build
|
|||||||
|
|
||||||
[@Vben](https://github.com/anncwb)
|
[@Vben](https://github.com/anncwb)
|
||||||
|
|
||||||
|
## スター歴史
|
||||||
|
|
||||||
|
[](https://star-history.com/#vbenjs/vue-vben-admin&Date)
|
||||||
|
|
||||||
## 寄付
|
## 寄付
|
||||||
|
|
||||||
このプロジェクトが役に立つと思われた場合、作者にコーヒーを一杯おごってサポートを示すことができます!
|
このプロジェクトが役に立つと思われた場合、作者にコーヒーを一杯おごってサポートを示すことができます!
|
||||||
|
@@ -124,6 +124,10 @@ Support modern browsers, not IE
|
|||||||
|
|
||||||
[@Vben](https://github.com/anncwb)
|
[@Vben](https://github.com/anncwb)
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://star-history.com/#vbenjs/vue-vben-admin&Date)
|
||||||
|
|
||||||
## Donate
|
## Donate
|
||||||
|
|
||||||
If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support!
|
If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support!
|
||||||
|
@@ -77,6 +77,10 @@ pnpm dev
|
|||||||
pnpm build
|
pnpm build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 更新日志
|
||||||
|
|
||||||
|
[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
|
||||||
|
|
||||||
## 如何贡献
|
## 如何贡献
|
||||||
|
|
||||||
非常欢迎你的加入 或者提交一个 Pull Request。
|
非常欢迎你的加入 或者提交一个 Pull Request。
|
||||||
@@ -120,6 +124,10 @@ pnpm build
|
|||||||
|
|
||||||
[@Vben](https://github.com/anncwb)
|
[@Vben](https://github.com/anncwb)
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://star-history.com/#vbenjs/vue-vben-admin&Date)
|
||||||
|
|
||||||
## 捐赠
|
## 捐赠
|
||||||
|
|
||||||
如果你觉得这个项目对你有帮助,你可以帮作者买一杯咖啡表示支持!
|
如果你觉得这个项目对你有帮助,你可以帮作者买一杯咖啡表示支持!
|
||||||
@@ -128,10 +136,6 @@ pnpm build
|
|||||||
|
|
||||||
<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
|
<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
|
||||||
|
|
||||||
## 更新日志
|
|
||||||
|
|
||||||
[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
|
|
||||||
|
|
||||||
## Contributor
|
## Contributor
|
||||||
|
|
||||||
<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
|
<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/web-antd",
|
"name": "@vben/web-antd",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://vben.pro",
|
"homepage": "https://vben.pro",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -10,10 +10,6 @@ export namespace AuthApi {
|
|||||||
/** 登录接口返回值 */
|
/** 登录接口返回值 */
|
||||||
export interface LoginResult {
|
export interface LoginResult {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
desc: string;
|
|
||||||
realName: string;
|
|
||||||
userId: string;
|
|
||||||
username: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RefreshTokenResult {
|
export interface RefreshTokenResult {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* 该文件可自行根据业务逻辑进行调整
|
* 该文件可自行根据业务逻辑进行调整
|
||||||
*/
|
*/
|
||||||
|
import type { HttpResponse } from '@vben/request';
|
||||||
|
|
||||||
import { useAppConfig } from '@vben/hooks';
|
import { useAppConfig } from '@vben/hooks';
|
||||||
import { preferences } from '@vben/preferences';
|
import { preferences } from '@vben/preferences';
|
||||||
import {
|
import {
|
||||||
@@ -68,7 +70,7 @@ function createRequestClient(baseURL: string) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// response数据解构
|
// response数据解构
|
||||||
client.addResponseInterceptor({
|
client.addResponseInterceptor<HttpResponse>({
|
||||||
fulfilled: (response) => {
|
fulfilled: (response) => {
|
||||||
const { data: responseData, status } = response;
|
const { data: responseData, status } = response;
|
||||||
|
|
||||||
@@ -93,7 +95,10 @@ function createRequestClient(baseURL: string) {
|
|||||||
|
|
||||||
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
||||||
client.addResponseInterceptor(
|
client.addResponseInterceptor(
|
||||||
errorMessageResponseInterceptor((msg: string) => message.error(msg)),
|
errorMessageResponseInterceptor((msg: string, _error) => {
|
||||||
|
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
|
||||||
|
message.error(msg);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/web-ele",
|
"name": "@vben/web-ele",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://vben.pro",
|
"homepage": "https://vben.pro",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -10,10 +10,6 @@ export namespace AuthApi {
|
|||||||
/** 登录接口返回值 */
|
/** 登录接口返回值 */
|
||||||
export interface LoginResult {
|
export interface LoginResult {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
desc: string;
|
|
||||||
realName: string;
|
|
||||||
userId: string;
|
|
||||||
username: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RefreshTokenResult {
|
export interface RefreshTokenResult {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* 该文件可自行根据业务逻辑进行调整
|
* 该文件可自行根据业务逻辑进行调整
|
||||||
*/
|
*/
|
||||||
|
import type { HttpResponse } from '@vben/request';
|
||||||
|
|
||||||
import { useAppConfig } from '@vben/hooks';
|
import { useAppConfig } from '@vben/hooks';
|
||||||
import { preferences } from '@vben/preferences';
|
import { preferences } from '@vben/preferences';
|
||||||
import {
|
import {
|
||||||
@@ -68,7 +70,7 @@ function createRequestClient(baseURL: string) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// response数据解构
|
// response数据解构
|
||||||
client.addResponseInterceptor({
|
client.addResponseInterceptor<HttpResponse>({
|
||||||
fulfilled: (response) => {
|
fulfilled: (response) => {
|
||||||
const { data: responseData, status } = response;
|
const { data: responseData, status } = response;
|
||||||
|
|
||||||
@@ -93,7 +95,10 @@ function createRequestClient(baseURL: string) {
|
|||||||
|
|
||||||
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
||||||
client.addResponseInterceptor(
|
client.addResponseInterceptor(
|
||||||
errorMessageResponseInterceptor((msg: string) => ElMessage.error(msg)),
|
errorMessageResponseInterceptor((msg: string, _error) => {
|
||||||
|
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
|
||||||
|
ElMessage.error(msg);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
|
@@ -7,6 +7,7 @@ import {
|
|||||||
ElMessage,
|
ElMessage,
|
||||||
ElNotification,
|
ElNotification,
|
||||||
ElSpace,
|
ElSpace,
|
||||||
|
ElTable,
|
||||||
} from 'element-plus';
|
} from 'element-plus';
|
||||||
|
|
||||||
type NotificationType = 'error' | 'info' | 'success' | 'warning';
|
type NotificationType = 'error' | 'info' | 'success' | 'warning';
|
||||||
@@ -38,6 +39,14 @@ function notify(type: NotificationType) {
|
|||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const tableData = [
|
||||||
|
{ prop1: '1', prop2: 'A' },
|
||||||
|
{ prop1: '2', prop2: 'B' },
|
||||||
|
{ prop1: '3', prop2: 'C' },
|
||||||
|
{ prop1: '4', prop2: 'D' },
|
||||||
|
{ prop1: '5', prop2: 'E' },
|
||||||
|
{ prop1: '6', prop2: 'F' },
|
||||||
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -74,5 +83,11 @@ function notify(type: NotificationType) {
|
|||||||
<ElButton type="success" @click="notify('success')"> 成功 </ElButton>
|
<ElButton type="success" @click="notify('success')"> 成功 </ElButton>
|
||||||
</ElSpace>
|
</ElSpace>
|
||||||
</ElCard>
|
</ElCard>
|
||||||
|
<ElCard class="mb-5">
|
||||||
|
<ElTable :data="tableData" stripe>
|
||||||
|
<ElTable.TableColumn label="测试列1" prop="prop1" />
|
||||||
|
<ElTable.TableColumn label="测试列2" prop="prop2" />
|
||||||
|
</ElTable>
|
||||||
|
</ElCard>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/web-naive",
|
"name": "@vben/web-naive",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://vben.pro",
|
"homepage": "https://vben.pro",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -10,10 +10,6 @@ export namespace AuthApi {
|
|||||||
/** 登录接口返回值 */
|
/** 登录接口返回值 */
|
||||||
export interface LoginResult {
|
export interface LoginResult {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
desc: string;
|
|
||||||
realName: string;
|
|
||||||
userId: string;
|
|
||||||
username: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RefreshTokenResult {
|
export interface RefreshTokenResult {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* 该文件可自行根据业务逻辑进行调整
|
* 该文件可自行根据业务逻辑进行调整
|
||||||
*/
|
*/
|
||||||
|
import type { HttpResponse } from '@vben/request';
|
||||||
|
|
||||||
import { useAppConfig } from '@vben/hooks';
|
import { useAppConfig } from '@vben/hooks';
|
||||||
import { preferences } from '@vben/preferences';
|
import { preferences } from '@vben/preferences';
|
||||||
import {
|
import {
|
||||||
@@ -67,7 +69,7 @@ function createRequestClient(baseURL: string) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// response数据解构
|
// response数据解构
|
||||||
client.addResponseInterceptor({
|
client.addResponseInterceptor<HttpResponse>({
|
||||||
fulfilled: (response) => {
|
fulfilled: (response) => {
|
||||||
const { data: responseData, status } = response;
|
const { data: responseData, status } = response;
|
||||||
|
|
||||||
@@ -92,7 +94,10 @@ function createRequestClient(baseURL: string) {
|
|||||||
|
|
||||||
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
||||||
client.addResponseInterceptor(
|
client.addResponseInterceptor(
|
||||||
errorMessageResponseInterceptor((msg: string) => message.error(msg)),
|
errorMessageResponseInterceptor((msg: string, _error) => {
|
||||||
|
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
|
||||||
|
message.error(msg);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
|
@@ -133,12 +133,19 @@ function sidebarCommercial(): DefaultTheme.SidebarItem[] {
|
|||||||
function nav(): DefaultTheme.NavItem[] {
|
function nav(): DefaultTheme.NavItem[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
activeMatch: '^/en/(guide|components)/',
|
||||||
text: 'Doc',
|
text: 'Doc',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
|
activeMatch: '^/en/guide/',
|
||||||
link: '/en/guide/introduction/vben',
|
link: '/en/guide/introduction/vben',
|
||||||
text: 'Guide',
|
text: 'Guide',
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// activeMatch: '^/en/components/',
|
||||||
|
// link: '/en/components/introduction',
|
||||||
|
// text: 'Components',
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
text: 'Historical Versions',
|
text: 'Historical Versions',
|
||||||
items: [
|
items: [
|
||||||
|
@@ -176,13 +176,16 @@ function sidebarComponents(): DefaultTheme.SidebarItem[] {
|
|||||||
function nav(): DefaultTheme.NavItem[] {
|
function nav(): DefaultTheme.NavItem[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
activeMatch: '^/(guide|components)/',
|
||||||
text: '文档',
|
text: '文档',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
|
activeMatch: '^/guide/',
|
||||||
link: '/guide/introduction/vben',
|
link: '/guide/introduction/vben',
|
||||||
text: '指南',
|
text: '指南',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
activeMatch: '^/components/',
|
||||||
link: '/components/introduction',
|
link: '/components/introduction',
|
||||||
text: '组件',
|
text: '组件',
|
||||||
},
|
},
|
||||||
|
@@ -9,3 +9,14 @@ html.dark {
|
|||||||
.form-valid-error p {
|
.form-valid-error p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 顶部导航栏选中项样式 */
|
||||||
|
.VPNavBarMenuLink,
|
||||||
|
.VPNavBarMenuGroup {
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.VPNavBarMenuLink.active,
|
||||||
|
.VPNavBarMenuGroup.active {
|
||||||
|
border-bottom-color: var(--vp-c-brand-1);
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/docs",
|
"name": "@vben/docs",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vitepress build",
|
"build": "vitepress build",
|
||||||
|
@@ -229,7 +229,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` |
|
| submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` |
|
||||||
| resetForm | 重置表单 | `()=>Promise<void>` |
|
| resetForm | 重置表单 | `()=>Promise<void>` |
|
||||||
| setValues | 设置表单值 | `()=>Promise<Record<string,any>>` |
|
| setValues | 设置表单值, 默认会过滤不在schema中定义的field, 可通过filterFields形参关闭过滤 | `(fields: Record<string, any>, filterFields?: boolean, shouldValidate?: boolean) => Promise<void>` |
|
||||||
| getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` |
|
| getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` |
|
||||||
| validate | 表单校验 | `()=>Promise<void>` |
|
| validate | 表单校验 | `()=>Promise<void>` |
|
||||||
| resetValidate | 重置表单校验 | `()=>Promise<void>` |
|
| resetValidate | 重置表单校验 | `()=>Promise<void>` |
|
||||||
|
@@ -46,8 +46,6 @@ The execution command is: `pnpm run [script]` or `npm run [script]`.
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
// Install dependencies
|
|
||||||
"bootstrap": "pnpm install",
|
|
||||||
// Build the project
|
// Build the project
|
||||||
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
|
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
|
||||||
// Build the project with analysis
|
// Build the project with analysis
|
||||||
@@ -77,7 +75,7 @@ The execution command is: `pnpm run [script]` or `npm run [script]`.
|
|||||||
// Check types
|
// Check types
|
||||||
"check:type": "turbo run typecheck",
|
"check:type": "turbo run typecheck",
|
||||||
// Clean the project (delete node_modules, dist, .turbo, etc.)
|
// Clean the project (delete node_modules, dist, .turbo, etc.)
|
||||||
"clean": "vsh clean",
|
"clean": "node ./scripts/clean.mjs",
|
||||||
// Commit code
|
// Commit code
|
||||||
"commit": "czg",
|
"commit": "czg",
|
||||||
// Start the project (by default, the dev scripts of all packages in the entire repository will run)
|
// Start the project (by default, the dev scripts of all packages in the entire repository will run)
|
||||||
@@ -107,9 +105,9 @@ The execution command is: `pnpm run [script]` or `npm run [script]`.
|
|||||||
// Package specification check
|
// Package specification check
|
||||||
"publint": "vsh publint",
|
"publint": "vsh publint",
|
||||||
// Delete all node_modules, yarn.lock, package.lock.json, and reinstall dependencies
|
// Delete all node_modules, yarn.lock, package.lock.json, and reinstall dependencies
|
||||||
"reinstall": "pnpm clean --del-lock && pnpm bootstrap",
|
"reinstall": "pnpm clean --del-lock && pnpm install",
|
||||||
// Run vitest unit tests
|
// Run vitest unit tests
|
||||||
"test:unit": "vitest",
|
"test:unit": "vitest run --dom",
|
||||||
// Update project dependencies
|
// Update project dependencies
|
||||||
"update:deps": " pnpm update --latest --recursive",
|
"update:deps": " pnpm update --latest --recursive",
|
||||||
// Changeset generation and versioning
|
// Changeset generation and versioning
|
||||||
|
@@ -163,6 +163,8 @@ The `src/api/request.ts` within the application can be configured according to t
|
|||||||
/**
|
/**
|
||||||
* This file can be adjusted according to business logic
|
* This file can be adjusted according to business logic
|
||||||
*/
|
*/
|
||||||
|
import type { HttpResponse } from '@vben/request';
|
||||||
|
|
||||||
import { useAppConfig } from '@vben/hooks';
|
import { useAppConfig } from '@vben/hooks';
|
||||||
import { preferences } from '@vben/preferences';
|
import { preferences } from '@vben/preferences';
|
||||||
import {
|
import {
|
||||||
@@ -227,7 +229,7 @@ function createRequestClient(baseURL: string) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Deal Response Data
|
// Deal Response Data
|
||||||
client.addResponseInterceptor({
|
client.addResponseInterceptor<HttpResponse>({
|
||||||
fulfilled: (response) => {
|
fulfilled: (response) => {
|
||||||
const { data: responseData, status } = response;
|
const { data: responseData, status } = response;
|
||||||
|
|
||||||
@@ -253,7 +255,10 @@ function createRequestClient(baseURL: string) {
|
|||||||
|
|
||||||
// Generic error handling; if none of the above error handling logic is triggered, it will fall back to this.
|
// Generic error handling; if none of the above error handling logic is triggered, it will fall back to this.
|
||||||
client.addResponseInterceptor(
|
client.addResponseInterceptor(
|
||||||
errorMessageResponseInterceptor((msg: string) => message.error(msg)),
|
errorMessageResponseInterceptor((msg: string, _error) => {
|
||||||
|
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
|
||||||
|
message.error(msg);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
|
@@ -37,8 +37,6 @@ If you want to adjust the content of the login form, you can configure the `Auth
|
|||||||
```vue
|
```vue
|
||||||
<AuthenticationLogin
|
<AuthenticationLogin
|
||||||
:loading="authStore.loginLoading"
|
:loading="authStore.loginLoading"
|
||||||
password-placeholder="123456"
|
|
||||||
username-placeholder="vben"
|
|
||||||
@submit="authStore.authLogin"
|
@submit="authStore.authLogin"
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
@@ -42,23 +42,6 @@ Check the dependency situation of the entire project and output `unused dependen
|
|||||||
pnpm vsh check-dep
|
pnpm vsh check-dep
|
||||||
```
|
```
|
||||||
|
|
||||||
### vsh clean
|
|
||||||
|
|
||||||
Delete the project's `node_modules`, `dist`, `.turbo` directories, etc., to clean the project.
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm vsh clean
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Options
|
|
||||||
|
|
||||||
| Option | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `-r,--recursive` | Recursively delete the entire project, default `true` |
|
|
||||||
| `--del-lock` | Whether to delete the `pnpm-lock.yaml` file, default `true` |
|
|
||||||
|
|
||||||
### vsh lint
|
### vsh lint
|
||||||
|
|
||||||
Lint checks the project to see if the code in the project conforms to standards.
|
Lint checks the project to see if the code in the project conforms to standards.
|
||||||
|
@@ -46,8 +46,6 @@ npm 脚本是项目常见的配置,用于执行一些常见的任务,比如
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
// 安装依赖
|
|
||||||
"bootstrap": "pnpm install",
|
|
||||||
// 构建项目
|
// 构建项目
|
||||||
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
|
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
|
||||||
// 构建项目并分析
|
// 构建项目并分析
|
||||||
@@ -77,7 +75,7 @@ npm 脚本是项目常见的配置,用于执行一些常见的任务,比如
|
|||||||
// 检查类型
|
// 检查类型
|
||||||
"check:type": "turbo run typecheck",
|
"check:type": "turbo run typecheck",
|
||||||
// 清理项目(删除node_modules、dist、.turbo)等目录
|
// 清理项目(删除node_modules、dist、.turbo)等目录
|
||||||
"clean": "vsh clean",
|
"clean": "node ./scripts/clean.mjs",
|
||||||
// 提交代码
|
// 提交代码
|
||||||
"commit": "czg",
|
"commit": "czg",
|
||||||
// 启动项目(默认会运行整个仓库所有包的dev脚本)
|
// 启动项目(默认会运行整个仓库所有包的dev脚本)
|
||||||
@@ -107,9 +105,9 @@ npm 脚本是项目常见的配置,用于执行一些常见的任务,比如
|
|||||||
// 包规范检查
|
// 包规范检查
|
||||||
"publint": "vsh publint",
|
"publint": "vsh publint",
|
||||||
// 删除所有的node_modules、yarn.lock、package.lock.json,重新安装依赖
|
// 删除所有的node_modules、yarn.lock、package.lock.json,重新安装依赖
|
||||||
"reinstall": "pnpm clean --del-lock && pnpm bootstrap",
|
"reinstall": "pnpm clean --del-lock && pnpm install",
|
||||||
// 运行 vitest 单元测试
|
// 运行 vitest 单元测试
|
||||||
"test:unit": "vitest",
|
"test:unit": "vitest run --dom",
|
||||||
// 更新项目依赖
|
// 更新项目依赖
|
||||||
"update:deps": " pnpm update --latest --recursive",
|
"update:deps": " pnpm update --latest --recursive",
|
||||||
// changeset生成提交集
|
// changeset生成提交集
|
||||||
|
@@ -163,6 +163,8 @@ export async function deleteUserApi(user: UserInfo) {
|
|||||||
/**
|
/**
|
||||||
* 该文件可自行根据业务逻辑进行调整
|
* 该文件可自行根据业务逻辑进行调整
|
||||||
*/
|
*/
|
||||||
|
import type { HttpResponse } from '@vben/request';
|
||||||
|
|
||||||
import { useAppConfig } from '@vben/hooks';
|
import { useAppConfig } from '@vben/hooks';
|
||||||
import { preferences } from '@vben/preferences';
|
import { preferences } from '@vben/preferences';
|
||||||
import {
|
import {
|
||||||
@@ -230,7 +232,7 @@ function createRequestClient(baseURL: string) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// response数据解构
|
// response数据解构
|
||||||
client.addResponseInterceptor({
|
client.addResponseInterceptor<HttpResponse>({
|
||||||
fulfilled: (response) => {
|
fulfilled: (response) => {
|
||||||
const { data: responseData, status } = response;
|
const { data: responseData, status } = response;
|
||||||
|
|
||||||
@@ -256,7 +258,10 @@ function createRequestClient(baseURL: string) {
|
|||||||
|
|
||||||
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
// 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
|
||||||
client.addResponseInterceptor(
|
client.addResponseInterceptor(
|
||||||
errorMessageResponseInterceptor((msg: string) => message.error(msg)),
|
errorMessageResponseInterceptor((msg: string, _error) => {
|
||||||
|
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
|
||||||
|
message.error(msg);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
|
@@ -1,10 +1,14 @@
|
|||||||
|
---
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
# 登录
|
# 登录
|
||||||
|
|
||||||
本文介绍如何去改造自己的应用程序登录页。
|
本文介绍如何去改造自己的应用程序登录页以及如何快速的对接登录页面接口。
|
||||||
|
|
||||||
## 登录页面调整
|
## 登录页面调整
|
||||||
|
|
||||||
如果你想调整登录页面的标题、描述和图标以及工具栏,你可以通过配置 `AuthPageLayout` 组件的 `props` 参数来实现。
|
如果你想调整登录页面的标题、描述和图标以及工具栏,你可以通过配置 `AuthPageLayout` 组件的参数来实现。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -30,8 +34,6 @@
|
|||||||
```vue
|
```vue
|
||||||
<AuthenticationLogin
|
<AuthenticationLogin
|
||||||
:loading="authStore.loginLoading"
|
:loading="authStore.loginLoading"
|
||||||
password-placeholder="123456"
|
|
||||||
username-placeholder="vben"
|
|
||||||
@submit="authStore.authLogin"
|
@submit="authStore.authLogin"
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
@@ -108,8 +110,111 @@
|
|||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
::: tip
|
::: tip Note
|
||||||
|
|
||||||
如果这些配置不能满足你的需求,你可以自行实现登录表单及相关登录逻辑。
|
如果这些配置不能满足你的需求,你可以自行实现登录表单及相关登录逻辑或者给我们提交 `PR`。
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
## 接口对接流程
|
||||||
|
|
||||||
|
这里将会快速的介绍如何快速对接自己的后端。
|
||||||
|
|
||||||
|
### 前置条件
|
||||||
|
|
||||||
|
- 首先文档用的后端服务,接口返回的格式统一如下:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface HttpResponse<T = any> {
|
||||||
|
/**
|
||||||
|
* 0 表示成功 其他表示失败
|
||||||
|
* 0 means success, others means fail
|
||||||
|
*/
|
||||||
|
code: number;
|
||||||
|
data: T;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果你不符合这个格式,你需要先阅读 [服务端交互](../essentials/server.md) 文档,改造你的`request.ts`配置。
|
||||||
|
|
||||||
|
- 其次你需要在先将本地代理地址改为你的真实后端地址,你可以在应用下的 `vite.config.mts` 内配置:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { defineConfig } from '@vben/vite-config';
|
||||||
|
|
||||||
|
export default defineConfig(async () => {
|
||||||
|
return {
|
||||||
|
vite: {
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||||
|
// 这里改为你的真实接口地址
|
||||||
|
target: 'http://localhost:5320/api',
|
||||||
|
ws: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 登录接口
|
||||||
|
|
||||||
|
为了能正常登录,你的后端最少需要提供 `2-3` 个接口:
|
||||||
|
|
||||||
|
- 登录接口
|
||||||
|
|
||||||
|
接口地址可在应用下的 `src/api/core/auth` 内修改,以下为默认接口地址:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
*/
|
||||||
|
export async function loginApi(data: AuthApi.LoginParams) {
|
||||||
|
return requestClient.post<AuthApi.LoginResult>('/auth/login', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 只需要保证登录接口返回值有 `accessToken` 字段即可 */
|
||||||
|
export interface LoginResult {
|
||||||
|
accessToken: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 获取用户信息接口
|
||||||
|
|
||||||
|
接口地址可在应用下的 `src/api/core/user` 内修改,以下为默认接口地址:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export async function getUserInfoApi() {
|
||||||
|
return requestClient.get<UserInfo>('/user/info');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 只需要保证登录接口返回值有以下字段即可,多的字段可以自行使用 */
|
||||||
|
export interface UserInfo {
|
||||||
|
roles: string[];
|
||||||
|
realName: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 获取权限码 (可选)
|
||||||
|
|
||||||
|
这个接口用于获取用户的权限码,权限码是用于控制用户的权限的,接口地址可在应用下的 `src/api/core/auth` 内修改,以下为默认接口地址:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export async function getAccessCodesApi() {
|
||||||
|
return requestClient.get<string[]>('/auth/codes');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果你不需要这个权限,你只需要把代码改为返回一个空数组即可。
|
||||||
|
|
||||||
|
```ts {2}
|
||||||
|
export async function getAccessCodesApi() {
|
||||||
|
// 这里返回一个空数组即可
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@@ -1,3 +1,7 @@
|
|||||||
|
---
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
# 精简版本
|
# 精简版本
|
||||||
|
|
||||||
从 `5.0` 版本开始,我们不再提供精简的仓库或者分支。我们的目标是提供一个更加一致的开发体验,同时减少维护成本。在这里,我们将如何介绍自己的项目,如何去精简以及移除不需要的功能。
|
从 `5.0` 版本开始,我们不再提供精简的仓库或者分支。我们的目标是提供一个更加一致的开发体验,同时减少维护成本。在这里,我们将如何介绍自己的项目,如何去精简以及移除不需要的功能。
|
||||||
@@ -74,3 +78,17 @@ pnpm install
|
|||||||
- `.github` 文件夹用于存放 GitHub 的配置文件
|
- `.github` 文件夹用于存放 GitHub 的配置文件
|
||||||
- `.vscode` 文件夹用于存放 VSCode 的配置文件,如果你使用其他编辑器,可以删除
|
- `.vscode` 文件夹用于存放 VSCode 的配置文件,如果你使用其他编辑器,可以删除
|
||||||
- `./scripts/deploy` 文件夹用于存放部署脚本,如果你不需要docker部署,可以删除
|
- `./scripts/deploy` 文件夹用于存放部署脚本,如果你不需要docker部署,可以删除
|
||||||
|
|
||||||
|
## 应用精简
|
||||||
|
|
||||||
|
当你确定了某个应用,你还可以进一步精简:
|
||||||
|
|
||||||
|
### 删除不需要的路由及页面
|
||||||
|
|
||||||
|
- 在应用的 `src/router/routes` 文件中,你可以删除不需要的路由。其中 `core` 文件夹内,如果只需要登录和忘记密码,你可以删除其他路由,如忘记密码、注册等。路由删除后,你可以删除对应的页面文件,在 `src/views/_core` 文件夹中。
|
||||||
|
|
||||||
|
- 在应用的 `src/router/routes` 文件中,你可以按需求删除不需要的路由,如`demos`、`vben` 目录等。路由删除后,你可以删除对应的页面文件,在 `src/views` 文件夹中。
|
||||||
|
|
||||||
|
### 删除不需要的组件
|
||||||
|
|
||||||
|
- 在应用的 `packages/effects/common-ui/src/ui` 文件夹中,你可以删除不需要的组件,如`about`、`dashboard` 目录等。删除之前请先确保你的路由中没有引用到这些组件。
|
||||||
|
@@ -42,16 +42,6 @@ pnpm vsh check-circular
|
|||||||
pnpm vsh check-dep
|
pnpm vsh check-dep
|
||||||
```
|
```
|
||||||
|
|
||||||
### vsh clean
|
|
||||||
|
|
||||||
删除项目的`node_modules`、`dist`、`.turbo`等目录,清理项目。
|
|
||||||
|
|
||||||
#### 用法
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm vsh clean
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 选项
|
#### 选项
|
||||||
|
|
||||||
| 选项 | 说明 |
|
| 选项 | 说明 |
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/commitlint-config",
|
"name": "@vben/commitlint-config",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
@@ -24,6 +24,7 @@ export async function node(): Promise<Linter.Config[]> {
|
|||||||
'vite',
|
'vite',
|
||||||
'@vue/test-utils',
|
'@vue/test-utils',
|
||||||
'@vben/tailwind-config',
|
'@vben/tailwind-config',
|
||||||
|
'@playwright/test',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@@ -15,10 +15,17 @@ const customConfig: Linter.Config[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['packages/effects/**/**', 'packages/types/**/**'],
|
files: [
|
||||||
|
'apps/**/**',
|
||||||
|
'packages/effects/**/**',
|
||||||
|
'packages/utils/**/**',
|
||||||
|
'packages/types/**/**',
|
||||||
|
'packages/locales/**/**',
|
||||||
|
],
|
||||||
ignores: restrictedImportIgnores,
|
ignores: restrictedImportIgnores,
|
||||||
rules: {
|
rules: {
|
||||||
'perfectionist/sort-interfaces': 'off',
|
'perfectionist/sort-interfaces': 'off',
|
||||||
|
'perfectionist/sort-objects': 'off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -135,7 +142,15 @@ const customConfig: Linter.Config[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['internal/**/**'],
|
files: ['**/**/playwright.config.ts'],
|
||||||
|
rules: {
|
||||||
|
'n/prefer-global/buffer': 'off',
|
||||||
|
'n/prefer-global/process': 'off',
|
||||||
|
'no-console': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['internal/**/**', 'scripts/**/**'],
|
||||||
rules: {
|
rules: {
|
||||||
'no-console': 'off',
|
'no-console': 'off',
|
||||||
},
|
},
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/stylelint-config",
|
"name": "@vben/stylelint-config",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/node-utils",
|
"name": "@vben/node-utils",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/tailwind-config",
|
"name": "@vben/tailwind-config",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
@@ -29,6 +29,7 @@ const shadcnUiColors = {
|
|||||||
DEFAULT: 'hsl(var(--accent))',
|
DEFAULT: 'hsl(var(--accent))',
|
||||||
foreground: 'hsl(var(--accent-foreground))',
|
foreground: 'hsl(var(--accent-foreground))',
|
||||||
hover: 'hsl(var(--accent-hover))',
|
hover: 'hsl(var(--accent-hover))',
|
||||||
|
lighter: 'has(val(--accent-lighter))',
|
||||||
},
|
},
|
||||||
background: {
|
background: {
|
||||||
deep: 'hsl(var(--background-deep))',
|
deep: 'hsl(var(--background-deep))',
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/tsconfig",
|
"name": "@vben/tsconfig",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben/vite-config",
|
"name": "@vben/vite-config",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
|
22
package.json
22
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vben-admin-pro",
|
"name": "vben-admin-pro",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"monorepo",
|
"monorepo",
|
||||||
@@ -25,11 +25,10 @@
|
|||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bootstrap": "pnpm install",
|
|
||||||
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
|
"build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
|
||||||
"build:analyze": "turbo build:analyze",
|
"build:analyze": "turbo build:analyze",
|
||||||
"build:docker": "./build-local-docker-image.sh",
|
|
||||||
"build:antd": "pnpm run build --filter=@vben/web-antd",
|
"build:antd": "pnpm run build --filter=@vben/web-antd",
|
||||||
|
"build:docker": "./build-local-docker-image.sh",
|
||||||
"build:docs": "pnpm run build --filter=@vben/docs",
|
"build:docs": "pnpm run build --filter=@vben/docs",
|
||||||
"build:ele": "pnpm run build --filter=@vben/web-ele",
|
"build:ele": "pnpm run build --filter=@vben/web-ele",
|
||||||
"build:naive": "pnpm run build --filter=@vben/web-naive",
|
"build:naive": "pnpm run build --filter=@vben/web-naive",
|
||||||
@@ -40,7 +39,7 @@
|
|||||||
"check:cspell": "cspell lint **/*.ts **/README.md .changeset/*.md --no-progress",
|
"check:cspell": "cspell lint **/*.ts **/README.md .changeset/*.md --no-progress",
|
||||||
"check:dep": "vsh check-dep",
|
"check:dep": "vsh check-dep",
|
||||||
"check:type": "turbo run typecheck",
|
"check:type": "turbo run typecheck",
|
||||||
"clean": "vsh clean",
|
"clean": "node ./scripts/clean.mjs",
|
||||||
"commit": "czg",
|
"commit": "czg",
|
||||||
"dev": "turbo-run dev",
|
"dev": "turbo-run dev",
|
||||||
"dev:antd": "pnpm -F @vben/web-antd run dev",
|
"dev:antd": "pnpm -F @vben/web-antd run dev",
|
||||||
@@ -55,15 +54,16 @@
|
|||||||
"prepare": "is-ci || husky",
|
"prepare": "is-ci || husky",
|
||||||
"preview": "turbo-run preview",
|
"preview": "turbo-run preview",
|
||||||
"publint": "vsh publint",
|
"publint": "vsh publint",
|
||||||
"reinstall": "pnpm clean --del-lock && pnpm bootstrap",
|
"reinstall": "pnpm clean --del-lock && pnpm install",
|
||||||
"test:unit": "vitest",
|
"test:unit": "vitest run --dom",
|
||||||
|
"test:e2e": "turbo run test:e2e",
|
||||||
"update:deps": "pnpm update --latest --recursive",
|
"update:deps": "pnpm update --latest --recursive",
|
||||||
"version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile"
|
"version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@changesets/changelog-github": "catalog:",
|
"@changesets/changelog-github": "catalog:",
|
||||||
"@changesets/cli": "catalog:",
|
"@changesets/cli": "catalog:",
|
||||||
"@types/jsdom": "catalog:",
|
"@playwright/test": "catalog:",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"@vben/commitlint-config": "workspace:*",
|
"@vben/commitlint-config": "workspace:*",
|
||||||
"@vben/eslint-config": "workspace:*",
|
"@vben/eslint-config": "workspace:*",
|
||||||
@@ -80,10 +80,11 @@
|
|||||||
"autoprefixer": "catalog:",
|
"autoprefixer": "catalog:",
|
||||||
"cross-env": "catalog:",
|
"cross-env": "catalog:",
|
||||||
"cspell": "catalog:",
|
"cspell": "catalog:",
|
||||||
|
"happy-dom": "catalog:",
|
||||||
"husky": "catalog:",
|
"husky": "catalog:",
|
||||||
"is-ci": "catalog:",
|
"is-ci": "catalog:",
|
||||||
"jsdom": "catalog:",
|
|
||||||
"lint-staged": "catalog:",
|
"lint-staged": "catalog:",
|
||||||
|
"playwright": "catalog:",
|
||||||
"rimraf": "catalog:",
|
"rimraf": "catalog:",
|
||||||
"tailwindcss": "catalog:",
|
"tailwindcss": "catalog:",
|
||||||
"turbo": "catalog:",
|
"turbo": "catalog:",
|
||||||
@@ -109,12 +110,11 @@
|
|||||||
"@ctrl/tinycolor": "4.1.0",
|
"@ctrl/tinycolor": "4.1.0",
|
||||||
"clsx": "2.1.1",
|
"clsx": "2.1.1",
|
||||||
"pinia": "2.2.2",
|
"pinia": "2.2.2",
|
||||||
"vue": "3.5.7"
|
"vue": "3.5.10"
|
||||||
},
|
},
|
||||||
"neverBuiltDependencies": [
|
"neverBuiltDependencies": [
|
||||||
"canvas",
|
"canvas",
|
||||||
"node-gyp",
|
"node-gyp"
|
||||||
"playwright"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/design",
|
"name": "@vben-core/design",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -82,11 +82,11 @@
|
|||||||
@apply opacity-100;
|
@apply opacity-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:-webkit-autofill {
|
/* input:-webkit-autofill {
|
||||||
@apply border-none;
|
@apply border-none;
|
||||||
|
|
||||||
box-shadow: 0 0 0 1000px transparent inset;
|
box-shadow: 0 0 0 1000px transparent inset;
|
||||||
}
|
} */
|
||||||
|
|
||||||
input[type='number']::-webkit-inner-spin-button,
|
input[type='number']::-webkit-inner-spin-button,
|
||||||
input[type='number']::-webkit-outer-spin-button {
|
input[type='number']::-webkit-outer-spin-button {
|
||||||
|
@@ -53,6 +53,7 @@
|
|||||||
|
|
||||||
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
||||||
--accent: 216 5% 19%;
|
--accent: 216 5% 19%;
|
||||||
|
--accent-lighter: 216 5% 11%;
|
||||||
--accent-hover: 216 5% 24%;
|
--accent-hover: 216 5% 24%;
|
||||||
--accent-foreground: 0 0% 98%;
|
--accent-foreground: 0 0% 98%;
|
||||||
|
|
||||||
|
@@ -53,6 +53,7 @@
|
|||||||
|
|
||||||
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
/* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
|
||||||
--accent: 240 5% 96%;
|
--accent: 240 5% 96%;
|
||||||
|
--accent-lighter: 240 0% 98%;
|
||||||
--accent-hover: 200deg 10% 90%;
|
--accent-hover: 200deg 10% 90%;
|
||||||
--accent-foreground: 240 6% 10%;
|
--accent-foreground: 240 6% 10%;
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/icons",
|
"name": "@vben-core/icons",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/shared",
|
"name": "@vben-core/shared",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
import { bindMethods } from '../util';
|
import { bindMethods, getNestedValue } from '../util';
|
||||||
|
|
||||||
class TestClass {
|
class TestClass {
|
||||||
public value: string;
|
public value: string;
|
||||||
@@ -78,3 +78,79 @@ describe('bindMethods', () => {
|
|||||||
expect(value).toBe('test');
|
expect(value).toBe('test');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getNestedValue', () => {
|
||||||
|
interface UserProfile {
|
||||||
|
age: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserSettings {
|
||||||
|
theme: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
user: {
|
||||||
|
profile: UserProfile;
|
||||||
|
settings: UserSettings;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: Data = {
|
||||||
|
user: {
|
||||||
|
profile: {
|
||||||
|
age: 25,
|
||||||
|
name: 'Alice',
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
theme: 'dark',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should get a nested value when the path is valid', () => {
|
||||||
|
const result = getNestedValue(data, 'user.profile.name');
|
||||||
|
expect(result).toBe('Alice');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined for non-existent property', () => {
|
||||||
|
const result = getNestedValue(data, 'user.profile.gender');
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when accessing a non-existent deep path', () => {
|
||||||
|
const result = getNestedValue(data, 'user.nonexistent.field');
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined if a middle level is undefined', () => {
|
||||||
|
const result = getNestedValue({ user: undefined }, 'user.profile.name');
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct value for a nested setting', () => {
|
||||||
|
const result = getNestedValue(data, 'user.settings.theme');
|
||||||
|
expect(result).toBe('dark');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work for a single-level path', () => {
|
||||||
|
const result = getNestedValue({ a: 1, b: 2 }, 'b');
|
||||||
|
expect(result).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the entire object if path is empty', () => {
|
||||||
|
expect(() => getNestedValue(data, '')()).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle paths with array indexes', () => {
|
||||||
|
const complexData = { list: [{ name: 'Item1' }, { name: 'Item2' }] };
|
||||||
|
const result = getNestedValue(complexData, 'list.1.name');
|
||||||
|
expect(result).toBe('Item2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when accessing an out-of-bounds array index', () => {
|
||||||
|
const complexData = { list: [{ name: 'Item1' }] };
|
||||||
|
const result = getNestedValue(complexData, 'list.2.name');
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@@ -1 +1,10 @@
|
|||||||
|
import { createDefu } from 'defu';
|
||||||
|
|
||||||
export { createDefu as createMerge, defu as merge } from 'defu';
|
export { createDefu as createMerge, defu as merge } from 'defu';
|
||||||
|
|
||||||
|
export const mergeWithArrayOverride = createDefu((originObj, key, updates) => {
|
||||||
|
if (Array.isArray(originObj[key]) && Array.isArray(updates)) {
|
||||||
|
originObj[key] = updates;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@@ -17,3 +17,28 @@ export function bindMethods<T extends object>(instance: T): void {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取嵌套对象的字段值
|
||||||
|
* @param obj - 要查找的对象
|
||||||
|
* @param path - 用于查找字段的路径,使用小数点分隔
|
||||||
|
* @returns 字段值,或者未找到时返回 undefined
|
||||||
|
*/
|
||||||
|
export function getNestedValue<T>(obj: T, path: string): any {
|
||||||
|
if (typeof path !== 'string' || path.length === 0) {
|
||||||
|
throw new Error('Path must be a non-empty string');
|
||||||
|
}
|
||||||
|
// 把路径字符串按 "." 分割成数组
|
||||||
|
const keys = path.split('.') as (number | string)[];
|
||||||
|
|
||||||
|
let current: any = obj;
|
||||||
|
|
||||||
|
for (const key of keys) {
|
||||||
|
if (current === null || current === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
current = current[key as keyof typeof current];
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/typings",
|
"name": "@vben-core/typings",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/composables",
|
"name": "@vben-core/composables",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -2,8 +2,8 @@ import { getScrollbarWidth, needsScrollbar } from '@vben-core/shared/utils';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
useScrollLock as _useScrollLock,
|
useScrollLock as _useScrollLock,
|
||||||
tryOnBeforeMount,
|
|
||||||
tryOnBeforeUnmount,
|
tryOnBeforeUnmount,
|
||||||
|
tryOnMounted,
|
||||||
} from '@vueuse/core';
|
} from '@vueuse/core';
|
||||||
|
|
||||||
export const SCROLL_FIXED_CLASS = `_scroll__fixed_`;
|
export const SCROLL_FIXED_CLASS = `_scroll__fixed_`;
|
||||||
@@ -12,7 +12,7 @@ export function useScrollLock() {
|
|||||||
const isLocked = _useScrollLock(document.body);
|
const isLocked = _useScrollLock(document.body);
|
||||||
const scrollbarWidth = getScrollbarWidth();
|
const scrollbarWidth = getScrollbarWidth();
|
||||||
|
|
||||||
tryOnBeforeMount(() => {
|
tryOnMounted(() => {
|
||||||
if (!needsScrollbar()) {
|
if (!needsScrollbar()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/preferences",
|
"name": "@vben-core/preferences",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -171,8 +171,9 @@ class PreferenceManager {
|
|||||||
// 加载并合并当前存储的偏好设置
|
// 加载并合并当前存储的偏好设置
|
||||||
const mergedPreference = merge(
|
const mergedPreference = merge(
|
||||||
{},
|
{},
|
||||||
overrides,
|
// overrides,
|
||||||
this.loadCachedPreferences() || defaultPreferences,
|
this.loadCachedPreferences() || {},
|
||||||
|
this.initialPreferences,
|
||||||
);
|
);
|
||||||
|
|
||||||
// 更新偏好设置
|
// 更新偏好设置
|
||||||
|
@@ -1,24 +1,7 @@
|
|||||||
// 假设这个文件为 FormApi.ts
|
|
||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
import { FormApi } from '../src/form-api';
|
import { FormApi } from '../src/form-api';
|
||||||
|
|
||||||
vi.mock('@vben-core/shared/utils', () => ({
|
|
||||||
bindMethods: vi.fn(),
|
|
||||||
createMerge: vi.fn((mergeFn) => {
|
|
||||||
return (stateOrFn: any, prev: any) => {
|
|
||||||
mergeFn(prev, 'key', stateOrFn);
|
|
||||||
return { ...prev, ...stateOrFn };
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
isFunction: (fn: any) => typeof fn === 'function',
|
|
||||||
StateHandler: vi.fn().mockImplementation(() => ({
|
|
||||||
reset: vi.fn(),
|
|
||||||
setConditionTrue: vi.fn(),
|
|
||||||
waitForCondition: vi.fn().mockResolvedValue(true),
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('formApi', () => {
|
describe('formApi', () => {
|
||||||
let formApi: FormApi;
|
let formApi: FormApi;
|
||||||
|
|
||||||
@@ -128,7 +111,6 @@ describe('formApi', () => {
|
|||||||
it('should unmount form and reset state', () => {
|
it('should unmount form and reset state', () => {
|
||||||
formApi.unmounted();
|
formApi.unmounted();
|
||||||
expect(formApi.isMounted).toBe(false);
|
expect(formApi.isMounted).toBe(false);
|
||||||
expect(formApi.stateHandler.reset).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should validate form', async () => {
|
it('should validate form', async () => {
|
||||||
|
@@ -12,17 +12,12 @@ import { toRaw } from 'vue';
|
|||||||
import { Store } from '@vben-core/shared/store';
|
import { Store } from '@vben-core/shared/store';
|
||||||
import {
|
import {
|
||||||
bindMethods,
|
bindMethods,
|
||||||
createMerge,
|
|
||||||
isFunction,
|
isFunction,
|
||||||
|
mergeWithArrayOverride,
|
||||||
StateHandler,
|
StateHandler,
|
||||||
} from '@vben-core/shared/utils';
|
} from '@vben-core/shared/utils';
|
||||||
|
|
||||||
const merge = createMerge((originObj, key, updates) => {
|
import { objectPick } from '@vueuse/core';
|
||||||
if (Array.isArray(originObj[key]) && Array.isArray(updates)) {
|
|
||||||
originObj[key] = updates;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function getDefaultState(): VbenFormProps {
|
function getDefaultState(): VbenFormProps {
|
||||||
return {
|
return {
|
||||||
@@ -43,11 +38,11 @@ function getDefaultState(): VbenFormProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class FormApi {
|
export class FormApi {
|
||||||
|
private prevState: null | VbenFormProps = null;
|
||||||
// private api: Pick<VbenFormProps, 'handleReset' | 'handleSubmit'>;
|
// private api: Pick<VbenFormProps, 'handleReset' | 'handleSubmit'>;
|
||||||
public form = {} as FormActions;
|
public form = {} as FormActions;
|
||||||
isMounted = false;
|
|
||||||
|
|
||||||
// private prevState!: ModalState;
|
isMounted = false;
|
||||||
public state: null | VbenFormProps = null;
|
public state: null | VbenFormProps = null;
|
||||||
|
|
||||||
stateHandler: StateHandler;
|
stateHandler: StateHandler;
|
||||||
@@ -66,7 +61,9 @@ export class FormApi {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
onUpdate: () => {
|
onUpdate: () => {
|
||||||
|
this.prevState = this.state;
|
||||||
this.state = this.store.state;
|
this.state = this.store.state;
|
||||||
|
this.updateState();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -87,6 +84,24 @@ export class FormApi {
|
|||||||
return this.form;
|
return this.form;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateState() {
|
||||||
|
const currentSchema = this.state?.schema ?? [];
|
||||||
|
const prevSchema = this.prevState?.schema ?? [];
|
||||||
|
// 进行了删除schema操作
|
||||||
|
if (currentSchema.length < prevSchema.length) {
|
||||||
|
const currentFields = new Set(
|
||||||
|
currentSchema.map((item) => item.fieldName),
|
||||||
|
);
|
||||||
|
const deletedSchema = prevSchema.filter(
|
||||||
|
(item) => !currentFields.has(item.fieldName),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const schema of deletedSchema) {
|
||||||
|
this.form?.setFieldValue(schema.fieldName, undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 如果需要多次更新状态,可以使用 batch 方法
|
// 如果需要多次更新状态,可以使用 batch 方法
|
||||||
batchStore(cb: () => void) {
|
batchStore(cb: () => void) {
|
||||||
this.store.batch(cb);
|
this.store.batch(cb);
|
||||||
@@ -101,6 +116,47 @@ export class FormApi {
|
|||||||
return form.values;
|
return form.values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
merge(formApi: FormApi) {
|
||||||
|
const chain = [this, formApi];
|
||||||
|
const proxy = new Proxy(formApi, {
|
||||||
|
get(target: any, prop: any) {
|
||||||
|
if (prop === 'merge') {
|
||||||
|
return (nextFormApi: FormApi) => {
|
||||||
|
chain.push(nextFormApi);
|
||||||
|
return proxy;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (prop === 'submitAllForm') {
|
||||||
|
return async (needMerge: boolean = true) => {
|
||||||
|
try {
|
||||||
|
const results = await Promise.all(
|
||||||
|
chain.map(async (api) => {
|
||||||
|
const form = await api.getForm();
|
||||||
|
const validateResult = await api.validate();
|
||||||
|
if (!validateResult.valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rawValues = toRaw(form.values || {});
|
||||||
|
return rawValues;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
if (needMerge) {
|
||||||
|
const mergedResults = Object.assign({}, ...results);
|
||||||
|
return mergedResults;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Validation error:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return target[prop];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
mount(formActions: FormActions) {
|
mount(formActions: FormActions) {
|
||||||
if (!this.isMounted) {
|
if (!this.isMounted) {
|
||||||
Object.assign(this.form, formActions);
|
Object.assign(this.form, formActions);
|
||||||
@@ -155,19 +211,32 @@ export class FormApi {
|
|||||||
) {
|
) {
|
||||||
if (isFunction(stateOrFn)) {
|
if (isFunction(stateOrFn)) {
|
||||||
this.store.setState((prev) => {
|
this.store.setState((prev) => {
|
||||||
return merge(stateOrFn(prev), prev);
|
return mergeWithArrayOverride(stateOrFn(prev), prev);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.store.setState((prev) => merge(stateOrFn, prev));
|
this.store.setState((prev) => mergeWithArrayOverride(stateOrFn, prev));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置表单值
|
||||||
|
* @param fields record
|
||||||
|
* @param filterFields 过滤不在schema中定义的字段 默认为true
|
||||||
|
* @param shouldValidate
|
||||||
|
*/
|
||||||
async setValues(
|
async setValues(
|
||||||
fields: Record<string, any>,
|
fields: Record<string, any>,
|
||||||
|
filterFields: boolean = true,
|
||||||
shouldValidate: boolean = false,
|
shouldValidate: boolean = false,
|
||||||
) {
|
) {
|
||||||
const form = await this.getForm();
|
const form = await this.getForm();
|
||||||
form.setValues(fields, shouldValidate);
|
if (!filterFields) {
|
||||||
|
form.setValues(fields, shouldValidate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fieldNames = this.state?.schema?.map((item) => item.fieldName) ?? [];
|
||||||
|
const filteredFields = objectPick(fields, fieldNames);
|
||||||
|
form.setValues(filteredFields, shouldValidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
async submitForm(e?: Event) {
|
async submitForm(e?: Event) {
|
||||||
@@ -211,7 +280,10 @@ export class FormApi {
|
|||||||
currentSchema.forEach((schema, index) => {
|
currentSchema.forEach((schema, index) => {
|
||||||
const updatedData = updatedMap[schema.fieldName];
|
const updatedData = updatedMap[schema.fieldName];
|
||||||
if (updatedData) {
|
if (updatedData) {
|
||||||
currentSchema[index] = merge(updatedData, schema) as FormSchema;
|
currentSchema[index] = mergeWithArrayOverride(
|
||||||
|
updatedData,
|
||||||
|
schema,
|
||||||
|
) as FormSchema;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.setState({ schema: currentSchema });
|
this.setState({ schema: currentSchema });
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/layout-ui",
|
"name": "@vben-core/layout-ui",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/menu-ui",
|
"name": "@vben-core/menu-ui",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { DrawerProps, ExtendedDrawerApi } from './drawer';
|
import type { DrawerProps, ExtendedDrawerApi } from './drawer';
|
||||||
|
|
||||||
import { ref, watch } from 'vue';
|
import { provide, ref, useId, watch } from 'vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useIsMobile,
|
useIsMobile,
|
||||||
@@ -33,9 +33,13 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
drawerApi: undefined,
|
drawerApi: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const id = useId();
|
||||||
|
provide('DISMISSABLE_DRAWER_ID', id);
|
||||||
|
|
||||||
const wrapperRef = ref<HTMLElement>();
|
const wrapperRef = ref<HTMLElement>();
|
||||||
const { $t } = useSimpleLocale();
|
const { $t } = useSimpleLocale();
|
||||||
const { isMobile } = useIsMobile();
|
const { isMobile } = useIsMobile();
|
||||||
|
|
||||||
const state = props.drawerApi?.useStore?.();
|
const state = props.drawerApi?.useStore?.();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -83,8 +87,8 @@ function escapeKeyDown(e: KeyboardEvent) {
|
|||||||
// pointer-down-outside
|
// pointer-down-outside
|
||||||
function pointerDownOutside(e: Event) {
|
function pointerDownOutside(e: Event) {
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
const isDismissableModal = !!target?.dataset.dismissableModal;
|
const dismissableDrawer = target?.dataset.dismissableDrawer;
|
||||||
if (!closeOnClickModal.value || !isDismissableModal) {
|
if (!closeOnClickModal.value || dismissableDrawer !== id) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { ExtendedModalApi, ModalProps } from './modal';
|
import type { ExtendedModalApi, ModalProps } from './modal';
|
||||||
|
|
||||||
import { computed, nextTick, ref, watch } from 'vue';
|
import { computed, nextTick, provide, ref, useId, watch } from 'vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useIsMobile,
|
useIsMobile,
|
||||||
@@ -40,6 +40,10 @@ const dialogRef = ref();
|
|||||||
const headerRef = ref();
|
const headerRef = ref();
|
||||||
const footerRef = ref();
|
const footerRef = ref();
|
||||||
|
|
||||||
|
const id = useId();
|
||||||
|
|
||||||
|
provide('DISMISSABLE_MODAL_ID', id);
|
||||||
|
|
||||||
const { $t } = useSimpleLocale();
|
const { $t } = useSimpleLocale();
|
||||||
const { isMobile } = useIsMobile();
|
const { isMobile } = useIsMobile();
|
||||||
const state = props.modalApi?.useStore?.();
|
const state = props.modalApi?.useStore?.();
|
||||||
@@ -141,8 +145,8 @@ function handerOpenAutoFocus(e: Event) {
|
|||||||
// pointer-down-outside
|
// pointer-down-outside
|
||||||
function pointerDownOutside(e: Event) {
|
function pointerDownOutside(e: Event) {
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
const isDismissableModal = !!target?.dataset.dismissableModal;
|
const isDismissableModal = target?.dataset.dismissableModal;
|
||||||
if (!closeOnClickModal.value || !isDismissableModal) {
|
if (!closeOnClickModal.value || isDismissableModal !== id) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "@vben-core/shadcn-ui",
|
"name": "@vben-core/shadcn-ui",
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
|
"#main": "./dist/index.mjs",
|
||||||
|
"#module": "./dist/index.mjs",
|
||||||
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
"homepage": "https://github.com/vbenjs/vue-vben-admin",
|
||||||
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -20,16 +22,14 @@
|
|||||||
"sideEffects": [
|
"sideEffects": [
|
||||||
"**/*.css"
|
"**/*.css"
|
||||||
],
|
],
|
||||||
"#main": "./dist/index.mjs",
|
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
"#module": "./dist/index.mjs",
|
|
||||||
"module": "./src/index.ts",
|
"module": "./src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./src/index.ts",
|
"types": "./src/index.ts",
|
||||||
"development": "./src/index.ts",
|
"development": "./src/index.ts",
|
||||||
"//default": "./dist/index.mjs",
|
"default": "./src/index.ts",
|
||||||
"default": "./src/index.ts"
|
"//default": "./dist/index.mjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -40,7 +40,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-icons/vue": "catalog:",
|
|
||||||
"@vben-core/composables": "workspace:*",
|
"@vben-core/composables": "workspace:*",
|
||||||
"@vben-core/icons": "workspace:*",
|
"@vben-core/icons": "workspace:*",
|
||||||
"@vben-core/shared": "workspace:*",
|
"@vben-core/shared": "workspace:*",
|
||||||
|
@@ -83,7 +83,7 @@ li:last-child a::after {
|
|||||||
|
|
||||||
li a::before,
|
li a::before,
|
||||||
li a::after {
|
li a::after {
|
||||||
@apply border-accent absolute top-0 h-0 w-0 border-[14px] border-solid content-[''];
|
@apply border-accent absolute top-0 h-0 w-0 border-[.875rem] border-solid content-[''];
|
||||||
}
|
}
|
||||||
|
|
||||||
li a::before {
|
li a::before {
|
||||||
|
@@ -14,6 +14,7 @@ export * from './input-password';
|
|||||||
export * from './link';
|
export * from './link';
|
||||||
export * from './logo';
|
export * from './logo';
|
||||||
export * from './menu-badge';
|
export * from './menu-badge';
|
||||||
|
export * from './pagination';
|
||||||
export * from './pin-input';
|
export * from './pin-input';
|
||||||
export * from './popover';
|
export * from './popover';
|
||||||
export * from './render-content';
|
export * from './render-content';
|
||||||
@@ -38,6 +39,7 @@ export * from './ui/hover-card';
|
|||||||
export * from './ui/input';
|
export * from './ui/input';
|
||||||
export * from './ui/label';
|
export * from './ui/label';
|
||||||
export * from './ui/number-field';
|
export * from './ui/number-field';
|
||||||
|
export * from './ui/pagination';
|
||||||
export * from './ui/pin-input';
|
export * from './ui/pin-input';
|
||||||
export * from './ui/popover';
|
export * from './ui/popover';
|
||||||
export * from './ui/radio-group';
|
export * from './ui/radio-group';
|
||||||
|
@@ -0,0 +1,2 @@
|
|||||||
|
export type { PaginationProps as VbenPaginationProps } from './pagination';
|
||||||
|
export { default as VbenPagination } from './pagination.vue';
|
@@ -0,0 +1,41 @@
|
|||||||
|
export interface PaginationProps {
|
||||||
|
/**
|
||||||
|
* 是否禁用
|
||||||
|
*/
|
||||||
|
disabled?: boolean;
|
||||||
|
/**
|
||||||
|
* 每页记录数选项
|
||||||
|
*/
|
||||||
|
pageSizeOptions?: number[];
|
||||||
|
/**
|
||||||
|
* 当 时true,始终显示第一页、最后一页和省略号
|
||||||
|
*/
|
||||||
|
showEdges?: boolean;
|
||||||
|
/**
|
||||||
|
* 显示当前页选择下拉框
|
||||||
|
*/
|
||||||
|
showRowsPerPage?: boolean;
|
||||||
|
/**
|
||||||
|
* 显示总条数文本
|
||||||
|
*/
|
||||||
|
showTotalText?: boolean;
|
||||||
|
/**
|
||||||
|
* 当前页面周围应显示的兄弟页面数量
|
||||||
|
*/
|
||||||
|
siblingCount?: number;
|
||||||
|
/**
|
||||||
|
* 组件尺寸
|
||||||
|
*/
|
||||||
|
size?: 'default' | 'large' | 'small';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总条数
|
||||||
|
*/
|
||||||
|
total?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SIZE_CLASS_MAP = {
|
||||||
|
default: 'size-8',
|
||||||
|
large: 'size-9',
|
||||||
|
small: 'size-7',
|
||||||
|
};
|
@@ -0,0 +1,111 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { Button } from '../ui/button';
|
||||||
|
import {
|
||||||
|
Pagination,
|
||||||
|
PaginationEllipsis,
|
||||||
|
PaginationFirst,
|
||||||
|
PaginationLast,
|
||||||
|
PaginationList,
|
||||||
|
PaginationListItem,
|
||||||
|
PaginationNext,
|
||||||
|
PaginationPrev,
|
||||||
|
} from '../ui/pagination';
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from '../ui/select';
|
||||||
|
import { type PaginationProps, SIZE_CLASS_MAP } from './pagination';
|
||||||
|
|
||||||
|
interface Props extends PaginationProps {}
|
||||||
|
|
||||||
|
const {
|
||||||
|
disabled = false,
|
||||||
|
pageSizeOptions = [10, 20, 30, 50, 100, 200],
|
||||||
|
showEdges = true,
|
||||||
|
showRowsPerPage = true,
|
||||||
|
showTotalText = true,
|
||||||
|
siblingCount = 1,
|
||||||
|
size = 'default',
|
||||||
|
total = 500,
|
||||||
|
} = defineProps<Props>();
|
||||||
|
|
||||||
|
const currentPage = defineModel<number>('currentPage', { default: 1 });
|
||||||
|
const itemPerPage = defineModel<number>('itemPerPage', { default: 20 });
|
||||||
|
|
||||||
|
const itemSize = computed(() => {
|
||||||
|
return SIZE_CLASS_MAP[size];
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = computed(() => {
|
||||||
|
return pageSizeOptions.map((item) => ({
|
||||||
|
label: `${item} 条/页`,
|
||||||
|
value: `${item}`,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleUpdateModelValue(value: string) {
|
||||||
|
itemPerPage.value = Number(value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Pagination
|
||||||
|
v-model:page="currentPage"
|
||||||
|
:disabled="disabled"
|
||||||
|
:items-per-page="itemPerPage"
|
||||||
|
:show-edges="showEdges"
|
||||||
|
:sibling-count="siblingCount"
|
||||||
|
:total="total"
|
||||||
|
>
|
||||||
|
<PaginationList
|
||||||
|
v-slot="{ items }"
|
||||||
|
class="flex w-full items-center justify-end gap-1"
|
||||||
|
>
|
||||||
|
<span v-if="showTotalText" class="mr-2">共 {{ total }} 条</span>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
v-if="showRowsPerPage"
|
||||||
|
:model-value="`${itemPerPage}`"
|
||||||
|
@update:model-value="handleUpdateModelValue"
|
||||||
|
>
|
||||||
|
<SelectTrigger class="w-30 mr-auto h-8">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<template v-for="item in options" :key="item.value">
|
||||||
|
<SelectItem :value="item.value"> {{ item.label }} </SelectItem>
|
||||||
|
</template>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<PaginationFirst :class="cn('size-8', itemSize)" />
|
||||||
|
<PaginationPrev :class="cn('size-8', itemSize)" />
|
||||||
|
<template v-for="(item, index) in items">
|
||||||
|
<PaginationListItem
|
||||||
|
v-if="item.type === 'page'"
|
||||||
|
:key="index"
|
||||||
|
:value="item.value"
|
||||||
|
as-child
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
:class="cn('size-8 p-0 shadow-none', itemSize)"
|
||||||
|
:variant="item.value === currentPage ? 'default' : 'outline'"
|
||||||
|
>
|
||||||
|
{{ item.value }}
|
||||||
|
</Button>
|
||||||
|
</PaginationListItem>
|
||||||
|
<PaginationEllipsis v-else :key="item.type" :index="index" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<PaginationNext :class="cn('size-8', itemSize)" />
|
||||||
|
<PaginationLast :class="cn('size-8', itemSize)" />
|
||||||
|
</PaginationList>
|
||||||
|
</Pagination>
|
||||||
|
</template>
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { ChevronDownIcon } from '@radix-icons/vue';
|
import { ChevronDown } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
AccordionHeader,
|
AccordionHeader,
|
||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
@@ -32,7 +32,7 @@ const delegatedProps = computed(() => {
|
|||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<slot name="icon">
|
<slot name="icon">
|
||||||
<ChevronDownIcon
|
<ChevronDown
|
||||||
class="text-muted-foreground h-4 w-4 shrink-0 transition-transform duration-200"
|
class="text-muted-foreground h-4 w-4 shrink-0 transition-transform duration-200"
|
||||||
/>
|
/>
|
||||||
</slot>
|
</slot>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { DotsHorizontalIcon } from '@radix-icons/vue';
|
import { MoreHorizontal } from 'lucide-vue-next';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: any;
|
class?: any;
|
||||||
@@ -15,7 +15,7 @@ const props = defineProps<{
|
|||||||
role="presentation"
|
role="presentation"
|
||||||
>
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<DotsHorizontalIcon class="h-4 w-4" />
|
<MoreHorizontal class="h-4 w-4" />
|
||||||
</slot>
|
</slot>
|
||||||
<span class="sr-only">More</span>
|
<span class="sr-only">More</span>
|
||||||
</span>
|
</span>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { ChevronRightIcon } from '@radix-icons/vue';
|
import { ChevronRight } from 'lucide-vue-next';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
class?: any;
|
class?: any;
|
||||||
@@ -15,7 +15,7 @@ const props = defineProps<{
|
|||||||
role="presentation"
|
role="presentation"
|
||||||
>
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<ChevronRightIcon />
|
<ChevronRight />
|
||||||
</slot>
|
</slot>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -10,7 +10,7 @@ import { buttonVariants } from './button';
|
|||||||
interface Props extends PrimitiveProps {
|
interface Props extends PrimitiveProps {
|
||||||
class?: any;
|
class?: any;
|
||||||
size?: ButtonVariantSize;
|
size?: ButtonVariantSize;
|
||||||
variant?: 'heavy' & ButtonVariants;
|
variant?: ButtonVariants;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
@@ -5,7 +5,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { CheckIcon } from '@radix-icons/vue';
|
import { Check } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
CheckboxIndicator,
|
CheckboxIndicator,
|
||||||
CheckboxRoot,
|
CheckboxRoot,
|
||||||
@@ -38,7 +38,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||||||
class="flex h-full w-full items-center justify-center text-current"
|
class="flex h-full w-full items-center justify-center text-current"
|
||||||
>
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<CheckIcon class="h-4 w-4" />
|
<Check class="h-4 w-4" />
|
||||||
</slot>
|
</slot>
|
||||||
</CheckboxIndicator>
|
</CheckboxIndicator>
|
||||||
</CheckboxRoot>
|
</CheckboxRoot>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { CheckIcon } from '@radix-icons/vue';
|
import { Check } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
ContextMenuCheckboxItem,
|
ContextMenuCheckboxItem,
|
||||||
type ContextMenuCheckboxItemEmits,
|
type ContextMenuCheckboxItemEmits,
|
||||||
@@ -36,7 +36,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||||||
>
|
>
|
||||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
<ContextMenuItemIndicator>
|
<ContextMenuItemIndicator>
|
||||||
<CheckIcon class="h-4 w-4" />
|
<Check class="h-4 w-4" />
|
||||||
</ContextMenuItemIndicator>
|
</ContextMenuItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { DotFilledIcon } from '@radix-icons/vue';
|
import { Circle } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
ContextMenuItemIndicator,
|
ContextMenuItemIndicator,
|
||||||
ContextMenuRadioItem,
|
ContextMenuRadioItem,
|
||||||
@@ -36,7 +36,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||||||
>
|
>
|
||||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
<ContextMenuItemIndicator>
|
<ContextMenuItemIndicator>
|
||||||
<DotFilledIcon class="h-4 w-4 fill-current" />
|
<Circle class="h-2 w-2 fill-current" />
|
||||||
</ContextMenuItemIndicator>
|
</ContextMenuItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { ChevronRightIcon } from '@radix-icons/vue';
|
import { ChevronRight } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
ContextMenuSubTrigger,
|
ContextMenuSubTrigger,
|
||||||
type ContextMenuSubTriggerProps,
|
type ContextMenuSubTriggerProps,
|
||||||
@@ -38,6 +38,6 @@ const forwardedProps = useForwardProps(delegatedProps);
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<ChevronRightIcon class="ml-auto h-4 w-4" />
|
<ChevronRight class="ml-auto h-4 w-4" />
|
||||||
</ContextMenuSubTrigger>
|
</ContextMenuSubTrigger>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed, ref } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { Cross2Icon } from '@radix-icons/vue';
|
import { X } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
DialogClose,
|
DialogClose,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -77,7 +77,7 @@ defineExpose({
|
|||||||
"
|
"
|
||||||
@click="() => emits('close')"
|
@click="() => emits('close')"
|
||||||
>
|
>
|
||||||
<Cross2Icon class="h-4 w-4" />
|
<X class="h-4 w-4" />
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</DialogPortal>
|
</DialogPortal>
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { inject } from 'vue';
|
||||||
|
|
||||||
import { useScrollLock } from '@vben-core/composables';
|
import { useScrollLock } from '@vben-core/composables';
|
||||||
|
|
||||||
useScrollLock();
|
useScrollLock();
|
||||||
|
const id = inject('DISMISSABLE_MODAL_ID');
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
:data-dismissable-modal="id"
|
||||||
class="bg-overlay fixed inset-0 z-[1000]"
|
class="bg-overlay fixed inset-0 z-[1000]"
|
||||||
data-dismissable-modal="true"
|
|
||||||
></div>
|
></div>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -3,6 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { X } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
DialogClose,
|
DialogClose,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -56,7 +57,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||||||
<DialogClose
|
<DialogClose
|
||||||
class="hover:bg-secondary absolute right-4 top-4 rounded-md p-0.5 transition-colors"
|
class="hover:bg-secondary absolute right-4 top-4 rounded-md p-0.5 transition-colors"
|
||||||
>
|
>
|
||||||
<Cross2Icon class="h-4 w-4" />
|
<X class="h-4 w-4" />
|
||||||
<span class="sr-only">Close</span>
|
<span class="sr-only">Close</span>
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { CheckIcon } from '@radix-icons/vue';
|
import { Check } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
DropdownMenuCheckboxItem,
|
DropdownMenuCheckboxItem,
|
||||||
type DropdownMenuCheckboxItemEmits,
|
type DropdownMenuCheckboxItemEmits,
|
||||||
@@ -36,7 +36,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||||||
>
|
>
|
||||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
<DropdownMenuItemIndicator>
|
<DropdownMenuItemIndicator>
|
||||||
<CheckIcon class="h-4 w-4" />
|
<Check class="h-4 w-4" />
|
||||||
</DropdownMenuItemIndicator>
|
</DropdownMenuItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { DotFilledIcon } from '@radix-icons/vue';
|
import { Circle } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
DropdownMenuItemIndicator,
|
DropdownMenuItemIndicator,
|
||||||
DropdownMenuRadioItem,
|
DropdownMenuRadioItem,
|
||||||
@@ -37,7 +37,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||||||
>
|
>
|
||||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
<DropdownMenuItemIndicator>
|
<DropdownMenuItemIndicator>
|
||||||
<DotFilledIcon class="h-4 w-4 fill-current" />
|
<Circle class="h-2 w-2 fill-current" />
|
||||||
</DropdownMenuItemIndicator>
|
</DropdownMenuItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { ChevronRightIcon } from '@radix-icons/vue';
|
import { ChevronRight } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
DropdownMenuSubTrigger,
|
DropdownMenuSubTrigger,
|
||||||
type DropdownMenuSubTriggerProps,
|
type DropdownMenuSubTriggerProps,
|
||||||
@@ -32,6 +32,6 @@ const forwardedProps = useForwardProps(delegatedProps);
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<ChevronRightIcon class="ml-auto h-4 w-4" />
|
<ChevronRight class="ml-auto h-4 w-4" />
|
||||||
</DropdownMenuSubTrigger>
|
</DropdownMenuSubTrigger>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -0,0 +1,27 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { MoreHorizontal } from 'lucide-vue-next';
|
||||||
|
import { PaginationEllipsis, type PaginationEllipsisProps } from 'radix-vue';
|
||||||
|
|
||||||
|
const props = defineProps<{ class?: any } & PaginationEllipsisProps>();
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
|
return delegated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PaginationEllipsis
|
||||||
|
v-bind="delegatedProps"
|
||||||
|
:class="cn('flex size-8 items-center justify-center', props.class)"
|
||||||
|
>
|
||||||
|
<slot>
|
||||||
|
<MoreHorizontal class="size-4" />
|
||||||
|
</slot>
|
||||||
|
</PaginationEllipsis>
|
||||||
|
</template>
|
@@ -0,0 +1,33 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { ChevronsLeft } from 'lucide-vue-next';
|
||||||
|
import { PaginationFirst, type PaginationFirstProps } from 'radix-vue';
|
||||||
|
|
||||||
|
import { Button } from '../button';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{ class?: any } & PaginationFirstProps>(),
|
||||||
|
{
|
||||||
|
asChild: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
|
return delegated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PaginationFirst v-bind="delegatedProps">
|
||||||
|
<Button :class="cn('size-8 p-0', props.class)" variant="outline">
|
||||||
|
<slot>
|
||||||
|
<ChevronsLeft class="size-4" />
|
||||||
|
</slot>
|
||||||
|
</Button>
|
||||||
|
</PaginationFirst>
|
||||||
|
</template>
|
@@ -0,0 +1,33 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { ChevronsRight } from 'lucide-vue-next';
|
||||||
|
import { PaginationLast, type PaginationLastProps } from 'radix-vue';
|
||||||
|
|
||||||
|
import { Button } from '../button';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{ class?: any } & PaginationLastProps>(),
|
||||||
|
{
|
||||||
|
asChild: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
|
return delegated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PaginationLast v-bind="delegatedProps">
|
||||||
|
<Button :class="cn('size-8 p-0', props.class)" variant="outline">
|
||||||
|
<slot>
|
||||||
|
<ChevronsRight class="size-4" />
|
||||||
|
</slot>
|
||||||
|
</Button>
|
||||||
|
</PaginationLast>
|
||||||
|
</template>
|
@@ -0,0 +1,33 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { ChevronRight } from 'lucide-vue-next';
|
||||||
|
import { PaginationNext, type PaginationNextProps } from 'radix-vue';
|
||||||
|
|
||||||
|
import { Button } from '../button';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{ class?: any } & PaginationNextProps>(),
|
||||||
|
{
|
||||||
|
asChild: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
|
return delegated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PaginationNext v-bind="delegatedProps">
|
||||||
|
<Button :class="cn('size-8 p-0', props.class)" variant="outline">
|
||||||
|
<slot>
|
||||||
|
<ChevronRight class="size-4" />
|
||||||
|
</slot>
|
||||||
|
</Button>
|
||||||
|
</PaginationNext>
|
||||||
|
</template>
|
@@ -0,0 +1,33 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { ChevronLeft } from 'lucide-vue-next';
|
||||||
|
import { PaginationPrev, type PaginationPrevProps } from 'radix-vue';
|
||||||
|
|
||||||
|
import { Button } from '../button';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{ class?: any } & PaginationPrevProps>(),
|
||||||
|
{
|
||||||
|
asChild: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
|
return delegated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PaginationPrev v-bind="delegatedProps">
|
||||||
|
<Button :class="cn('size-8 p-0', props.class)" variant="outline">
|
||||||
|
<slot>
|
||||||
|
<ChevronLeft class="size-4" />
|
||||||
|
</slot>
|
||||||
|
</Button>
|
||||||
|
</PaginationPrev>
|
||||||
|
</template>
|
@@ -0,0 +1,10 @@
|
|||||||
|
export { default as PaginationEllipsis } from './PaginationEllipsis.vue';
|
||||||
|
export { default as PaginationFirst } from './PaginationFirst.vue';
|
||||||
|
export { default as PaginationLast } from './PaginationLast.vue';
|
||||||
|
export { default as PaginationNext } from './PaginationNext.vue';
|
||||||
|
export { default as PaginationPrev } from './PaginationPrev.vue';
|
||||||
|
export {
|
||||||
|
PaginationList,
|
||||||
|
PaginationListItem,
|
||||||
|
PaginationRoot as Pagination,
|
||||||
|
} from 'radix-vue';
|
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DashIcon } from '@radix-icons/vue';
|
import { Dot } from 'lucide-vue-next';
|
||||||
import { Primitive, type PrimitiveProps, useForwardProps } from 'radix-vue';
|
import { Primitive, type PrimitiveProps, useForwardProps } from 'radix-vue';
|
||||||
|
|
||||||
const props = defineProps<PrimitiveProps>();
|
const props = defineProps<PrimitiveProps>();
|
||||||
@@ -9,7 +9,7 @@ const forwardedProps = useForwardProps(props);
|
|||||||
<template>
|
<template>
|
||||||
<Primitive v-bind="forwardedProps">
|
<Primitive v-bind="forwardedProps">
|
||||||
<slot>
|
<slot>
|
||||||
<DashIcon />
|
<Dot />
|
||||||
</slot>
|
</slot>
|
||||||
</Primitive>
|
</Primitive>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { CheckIcon } from '@radix-icons/vue';
|
import { Circle } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
RadioGroupIndicator,
|
RadioGroupIndicator,
|
||||||
RadioGroupItem,
|
RadioGroupItem,
|
||||||
@@ -33,7 +33,7 @@ const forwardedProps = useForwardProps(delegatedProps);
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<RadioGroupIndicator class="flex items-center justify-center">
|
<RadioGroupIndicator class="flex items-center justify-center">
|
||||||
<CheckIcon class="fill-primary h-3.5 w-3.5" />
|
<Circle class="h-2.5 w-2.5 fill-current text-current" />
|
||||||
</RadioGroupIndicator>
|
</RadioGroupIndicator>
|
||||||
</RadioGroupItem>
|
</RadioGroupItem>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { CheckIcon } from '@radix-icons/vue';
|
import { Check } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectItemIndicator,
|
SelectItemIndicator,
|
||||||
@@ -35,7 +35,7 @@ const forwardedProps = useForwardProps(delegatedProps);
|
|||||||
>
|
>
|
||||||
<span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
<span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
<SelectItemIndicator>
|
<SelectItemIndicator>
|
||||||
<CheckIcon class="h-4 w-4" />
|
<Check class="h-4 w-4" />
|
||||||
</SelectItemIndicator>
|
</SelectItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
|||||||
|
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { ChevronDownIcon } from '@radix-icons/vue';
|
import { ChevronDown } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
SelectScrollDownButton,
|
SelectScrollDownButton,
|
||||||
type SelectScrollDownButtonProps,
|
type SelectScrollDownButtonProps,
|
||||||
@@ -29,7 +29,7 @@ const forwardedProps = useForwardProps(delegatedProps);
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<ChevronDownIcon />
|
<ChevronDown class="h-4 w-4" />
|
||||||
</slot>
|
</slot>
|
||||||
</SelectScrollDownButton>
|
</SelectScrollDownButton>
|
||||||
</template>
|
</template>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user