Преглед на файлове

chore: 移除冗余应用代码

cc12458 преди 3 седмици
родител
ревизия
616d4857af
променени са 100 файла, в които са добавени 10 реда и са изтрити 4893 реда
  1. 10 0
      .gitignore
  2. 0 3
      apps/backend-mock/.env
  3. 0 15
      apps/backend-mock/README.md
  4. 0 16
      apps/backend-mock/api/auth/codes.ts
  5. 0 42
      apps/backend-mock/api/auth/login.post.ts
  6. 0 17
      apps/backend-mock/api/auth/logout.post.ts
  7. 0 35
      apps/backend-mock/api/auth/refresh.post.ts
  8. 0 32
      apps/backend-mock/api/demo/bigint.ts
  9. 0 15
      apps/backend-mock/api/menu/all.ts
  10. 0 8
      apps/backend-mock/api/status.ts
  11. 0 16
      apps/backend-mock/api/system/dept/.post.ts
  12. 0 16
      apps/backend-mock/api/system/dept/[id].delete.ts
  13. 0 16
      apps/backend-mock/api/system/dept/[id].put.ts
  14. 0 62
      apps/backend-mock/api/system/dept/list.ts
  15. 0 13
      apps/backend-mock/api/system/menu/list.ts
  16. 0 29
      apps/backend-mock/api/system/menu/name-exists.ts
  17. 0 29
      apps/backend-mock/api/system/menu/path-exists.ts
  18. 0 84
      apps/backend-mock/api/system/role/list.ts
  19. 0 85
      apps/backend-mock/api/system/user/list.ts
  20. 0 117
      apps/backend-mock/api/table/list.ts
  21. 0 3
      apps/backend-mock/api/test.get.ts
  22. 0 3
      apps/backend-mock/api/test.post.ts
  23. 0 12
      apps/backend-mock/api/timezone/getTimezone.ts
  24. 0 11
      apps/backend-mock/api/timezone/getTimezoneOptions.ts
  25. 0 22
      apps/backend-mock/api/timezone/setTimezone.ts
  26. 0 14
      apps/backend-mock/api/upload.ts
  27. 0 11
      apps/backend-mock/api/user/info.ts
  28. 0 7
      apps/backend-mock/error.ts
  29. 0 20
      apps/backend-mock/middleware/1.api.ts
  30. 0 20
      apps/backend-mock/nitro.config.ts
  31. 0 21
      apps/backend-mock/package.json
  32. 0 15
      apps/backend-mock/routes/[...].ts
  33. 0 4
      apps/backend-mock/tsconfig.build.json
  34. 0 3
      apps/backend-mock/tsconfig.json
  35. 0 28
      apps/backend-mock/utils/cookie-utils.ts
  36. 0 77
      apps/backend-mock/utils/jwt-utils.ts
  37. 0 421
      apps/backend-mock/utils/mock-data.ts
  38. 0 70
      apps/backend-mock/utils/response.ts
  39. 0 9
      apps/backend-mock/utils/timezone-utils.ts
  40. 0 8
      apps/web-antd/.env
  41. 0 7
      apps/web-antd/.env.analyze
  42. 0 16
      apps/web-antd/.env.development
  43. 0 19
      apps/web-antd/.env.production
  44. 0 35
      apps/web-antd/index.html
  45. 0 50
      apps/web-antd/package.json
  46. BIN
      apps/web-antd/public/favicon.ico
  47. 0 743
      apps/web-antd/src/adapter/component/index.ts
  48. 0 49
      apps/web-antd/src/adapter/form.ts
  49. 0 77
      apps/web-antd/src/adapter/vxe-table.ts
  50. 0 51
      apps/web-antd/src/api/core/auth.ts
  51. 0 3
      apps/web-antd/src/api/core/index.ts
  52. 0 10
      apps/web-antd/src/api/core/menu.ts
  53. 0 10
      apps/web-antd/src/api/core/user.ts
  54. 0 1
      apps/web-antd/src/api/index.ts
  55. 0 113
      apps/web-antd/src/api/request.ts
  56. 0 39
      apps/web-antd/src/app.vue
  57. 0 76
      apps/web-antd/src/bootstrap.ts
  58. 0 25
      apps/web-antd/src/layouts/auth.vue
  59. 0 256
      apps/web-antd/src/layouts/basic.vue
  60. 0 6
      apps/web-antd/src/layouts/index.ts
  61. 0 3
      apps/web-antd/src/locales/README.md
  62. 0 102
      apps/web-antd/src/locales/index.ts
  63. 0 14
      apps/web-antd/src/locales/langs/en-US/demos.json
  64. 0 15
      apps/web-antd/src/locales/langs/en-US/page.json
  65. 0 14
      apps/web-antd/src/locales/langs/zh-CN/demos.json
  66. 0 15
      apps/web-antd/src/locales/langs/zh-CN/page.json
  67. 0 32
      apps/web-antd/src/main.ts
  68. 0 72
      apps/web-antd/src/preferences.ts
  69. 0 42
      apps/web-antd/src/router/access.ts
  70. 0 133
      apps/web-antd/src/router/guard.ts
  71. 0 37
      apps/web-antd/src/router/index.ts
  72. 0 97
      apps/web-antd/src/router/routes/core.ts
  73. 0 37
      apps/web-antd/src/router/routes/index.ts
  74. 0 38
      apps/web-antd/src/router/routes/modules/dashboard.ts
  75. 0 28
      apps/web-antd/src/router/routes/modules/demos.ts
  76. 0 116
      apps/web-antd/src/router/routes/modules/vben.ts
  77. 0 117
      apps/web-antd/src/store/auth.ts
  78. 0 1
      apps/web-antd/src/store/index.ts
  79. 0 3
      apps/web-antd/src/views/_core/README.md
  80. 0 9
      apps/web-antd/src/views/_core/about/index.vue
  81. 0 68
      apps/web-antd/src/views/_core/authentication/code-login.vue
  82. 0 42
      apps/web-antd/src/views/_core/authentication/forget-password.vue
  83. 0 98
      apps/web-antd/src/views/_core/authentication/login.vue
  84. 0 10
      apps/web-antd/src/views/_core/authentication/qrcode-login.vue
  85. 0 95
      apps/web-antd/src/views/_core/authentication/register.vue
  86. 0 7
      apps/web-antd/src/views/_core/fallback/coming-soon.vue
  87. 0 9
      apps/web-antd/src/views/_core/fallback/forbidden.vue
  88. 0 9
      apps/web-antd/src/views/_core/fallback/internal-error.vue
  89. 0 9
      apps/web-antd/src/views/_core/fallback/not-found.vue
  90. 0 9
      apps/web-antd/src/views/_core/fallback/offline.vue
  91. 0 65
      apps/web-antd/src/views/_core/profile/base-setting.vue
  92. 0 49
      apps/web-antd/src/views/_core/profile/index.vue
  93. 0 31
      apps/web-antd/src/views/_core/profile/notification-setting.vue
  94. 0 63
      apps/web-antd/src/views/_core/profile/password-setting.vue
  95. 0 43
      apps/web-antd/src/views/_core/profile/security-setting.vue
  96. 0 98
      apps/web-antd/src/views/dashboard/analytics/analytics-trends.vue
  97. 0 82
      apps/web-antd/src/views/dashboard/analytics/analytics-visits-data.vue
  98. 0 46
      apps/web-antd/src/views/dashboard/analytics/analytics-visits-sales.vue
  99. 0 65
      apps/web-antd/src/views/dashboard/analytics/analytics-visits-source.vue
  100. 0 55
      apps/web-antd/src/views/dashboard/analytics/analytics-visits.vue

+ 10 - 0
.gitignore

@@ -59,3 +59,13 @@ vite.config.ts.*
 skills-lock.json
 .atomcode
 datalog
+
+# Demo project
+docs/*
+playground/*
+apps/backend-mock/*
+apps/web-antd/*
+apps/web-antdv-next/*
+apps/web-ele/*
+apps/web-naive/*
+apps/web-tdesign/*

+ 0 - 3
apps/backend-mock/.env

@@ -1,3 +0,0 @@
-PORT=5320
-ACCESS_TOKEN_SECRET=access_token_secret
-REFRESH_TOKEN_SECRET=refresh_token_secret

+ 0 - 15
apps/backend-mock/README.md

@@ -1,15 +0,0 @@
-# @vben/backend-mock
-
-## Description
-
-Vben Admin 数据 mock 服务,没有对接任何的数据库,所有数据都是模拟的,用于前端开发时提供数据支持。线上环境不再提供 mock 集成,可自行部署服务或者对接真实数据,由于 `mock.js` 等工具有一些限制,比如上传文件不行、无法模拟复杂的逻辑等,所以这里使用了真实的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务,但是这样可以更好的模拟真实环境。该服务不需要手动启动,已经集成在 vite 插件内,随应用一起启用。
-
-## Running the app
-
-```bash
-# development
-$ pnpm run start
-
-# production mode
-$ pnpm run build
-```

+ 0 - 16
apps/backend-mock/api/auth/codes.ts

@@ -1,16 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { MOCK_CODES } from '~/utils/mock-data';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-
-export default eventHandler((event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-
-  const codes =
-    MOCK_CODES.find((item) => item.username === userinfo.username)?.codes ?? [];
-
-  return useResponseSuccess(codes);
-});

+ 0 - 42
apps/backend-mock/api/auth/login.post.ts

@@ -1,42 +0,0 @@
-import { defineEventHandler, readBody, setResponseStatus } from 'h3';
-import {
-  clearRefreshTokenCookie,
-  setRefreshTokenCookie,
-} from '~/utils/cookie-utils';
-import { generateAccessToken, generateRefreshToken } from '~/utils/jwt-utils';
-import { MOCK_USERS } from '~/utils/mock-data';
-import {
-  forbiddenResponse,
-  useResponseError,
-  useResponseSuccess,
-} from '~/utils/response';
-
-export default defineEventHandler(async (event) => {
-  const { password, username } = await readBody(event);
-  if (!password || !username) {
-    setResponseStatus(event, 400);
-    return useResponseError(
-      'BadRequestException',
-      'Username and password are required',
-    );
-  }
-
-  const findUser = MOCK_USERS.find(
-    (item) => item.username === username && item.password === password,
-  );
-
-  if (!findUser) {
-    clearRefreshTokenCookie(event);
-    return forbiddenResponse(event, 'Username or password is incorrect.');
-  }
-
-  const accessToken = generateAccessToken(findUser);
-  const refreshToken = generateRefreshToken(findUser);
-
-  setRefreshTokenCookie(event, refreshToken);
-
-  return useResponseSuccess({
-    ...findUser,
-    accessToken,
-  });
-});

+ 0 - 17
apps/backend-mock/api/auth/logout.post.ts

@@ -1,17 +0,0 @@
-import { defineEventHandler } from 'h3';
-import {
-  clearRefreshTokenCookie,
-  getRefreshTokenFromCookie,
-} from '~/utils/cookie-utils';
-import { useResponseSuccess } from '~/utils/response';
-
-export default defineEventHandler(async (event) => {
-  const refreshToken = getRefreshTokenFromCookie(event);
-  if (!refreshToken) {
-    return useResponseSuccess('');
-  }
-
-  clearRefreshTokenCookie(event);
-
-  return useResponseSuccess('');
-});

+ 0 - 35
apps/backend-mock/api/auth/refresh.post.ts

@@ -1,35 +0,0 @@
-import { defineEventHandler } from 'h3';
-import {
-  clearRefreshTokenCookie,
-  getRefreshTokenFromCookie,
-  setRefreshTokenCookie,
-} from '~/utils/cookie-utils';
-import { generateAccessToken, verifyRefreshToken } from '~/utils/jwt-utils';
-import { MOCK_USERS } from '~/utils/mock-data';
-import { forbiddenResponse } from '~/utils/response';
-
-export default defineEventHandler(async (event) => {
-  const refreshToken = getRefreshTokenFromCookie(event);
-  if (!refreshToken) {
-    return forbiddenResponse(event);
-  }
-
-  clearRefreshTokenCookie(event);
-
-  const userinfo = verifyRefreshToken(refreshToken);
-  if (!userinfo) {
-    return forbiddenResponse(event);
-  }
-
-  const findUser = MOCK_USERS.find(
-    (item) => item.username === userinfo.username,
-  );
-  if (!findUser) {
-    return forbiddenResponse(event);
-  }
-  const accessToken = generateAccessToken(findUser);
-
-  setRefreshTokenCookie(event, refreshToken);
-
-  return accessToken;
-});

+ 0 - 32
apps/backend-mock/api/demo/bigint.ts

@@ -1,32 +0,0 @@
-import { eventHandler, setHeader } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { unAuthorizedResponse } from '~/utils/response';
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  const data = `
-  {
-    "code": 0,
-    "message": "success",
-    "data": [
-              {
-                "id": 123456789012345678901234567890123456789012345678901234567890,
-                "name": "John Doe",
-                "age": 30,
-                "email": "john-doe@demo.com"
-                },
-                {
-                "id": 987654321098765432109876543210987654321098765432109876543210,
-                "name": "Jane Smith",
-                "age": 25,
-                "email": "jane@demo.com"
-                }
-            ]
-  }
-  `;
-  setHeader(event, 'Content-Type', 'application/json');
-  return data;
-});

+ 0 - 15
apps/backend-mock/api/menu/all.ts

@@ -1,15 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { MOCK_MENUS } from '~/utils/mock-data';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-
-  const menus =
-    MOCK_MENUS.find((item) => item.username === userinfo.username)?.menus ?? [];
-  return useResponseSuccess(menus);
-});

+ 0 - 8
apps/backend-mock/api/status.ts

@@ -1,8 +0,0 @@
-import { eventHandler, getQuery, setResponseStatus } from 'h3';
-import { useResponseError } from '~/utils/response';
-
-export default eventHandler((event) => {
-  const { status } = getQuery(event);
-  setResponseStatus(event, Number(status));
-  return useResponseError(`${status}`);
-});

+ 0 - 16
apps/backend-mock/api/system/dept/.post.ts

@@ -1,16 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import {
-  sleep,
-  unAuthorizedResponse,
-  useResponseSuccess,
-} from '~/utils/response';
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  await sleep(600);
-  return useResponseSuccess(null);
-});

+ 0 - 16
apps/backend-mock/api/system/dept/[id].delete.ts

@@ -1,16 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import {
-  sleep,
-  unAuthorizedResponse,
-  useResponseSuccess,
-} from '~/utils/response';
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  await sleep(1000);
-  return useResponseSuccess(null);
-});

+ 0 - 16
apps/backend-mock/api/system/dept/[id].put.ts

@@ -1,16 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import {
-  sleep,
-  unAuthorizedResponse,
-  useResponseSuccess,
-} from '~/utils/response';
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  await sleep(2000);
-  return useResponseSuccess(null);
-});

+ 0 - 62
apps/backend-mock/api/system/dept/list.ts

@@ -1,62 +0,0 @@
-import { faker } from '@faker-js/faker';
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-
-const formatterCN = new Intl.DateTimeFormat('zh-CN', {
-  timeZone: 'Asia/Shanghai',
-  year: 'numeric',
-  month: '2-digit',
-  day: '2-digit',
-  hour: '2-digit',
-  minute: '2-digit',
-  second: '2-digit',
-});
-
-function generateMockDataList(count: number) {
-  const dataList = [];
-
-  for (let i = 0; i < count; i++) {
-    const dataItem: Record<string, any> = {
-      id: faker.string.uuid(),
-      pid: 0,
-      name: faker.commerce.department(),
-      status: faker.helpers.arrayElement([0, 1]),
-      createTime: formatterCN.format(
-        faker.date.between({ from: '2021-01-01', to: '2022-12-31' }),
-      ),
-      remark: faker.lorem.sentence(),
-    };
-    if (faker.datatype.boolean()) {
-      dataItem.children = Array.from(
-        { length: faker.number.int({ min: 1, max: 5 }) },
-        () => ({
-          id: faker.string.uuid(),
-          pid: dataItem.id,
-          name: faker.commerce.department(),
-          status: faker.helpers.arrayElement([0, 1]),
-          createTime: formatterCN.format(
-            faker.date.between({ from: '2023-01-01', to: '2023-12-31' }),
-          ),
-          remark: faker.lorem.sentence(),
-        }),
-      );
-    }
-    dataList.push(dataItem);
-  }
-
-  return dataList;
-}
-
-const mockData = generateMockDataList(10);
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-
-  const listData = structuredClone(mockData);
-
-  return useResponseSuccess(listData);
-});

+ 0 - 13
apps/backend-mock/api/system/menu/list.ts

@@ -1,13 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { MOCK_MENU_LIST } from '~/utils/mock-data';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-
-  return useResponseSuccess(MOCK_MENU_LIST);
-});

+ 0 - 29
apps/backend-mock/api/system/menu/name-exists.ts

@@ -1,29 +0,0 @@
-import { eventHandler, getQuery } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { MOCK_MENU_LIST } from '~/utils/mock-data';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-
-const namesMap: Record<string, any> = {};
-
-function getNames(menus: any[]) {
-  menus.forEach((menu) => {
-    namesMap[menu.name] = String(menu.id);
-    if (menu.children) {
-      getNames(menu.children);
-    }
-  });
-}
-getNames(MOCK_MENU_LIST);
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  const { id, name } = getQuery(event);
-
-  return (name as string) in namesMap &&
-    (!id || namesMap[name as string] !== String(id))
-    ? useResponseSuccess(true)
-    : useResponseSuccess(false);
-});

+ 0 - 29
apps/backend-mock/api/system/menu/path-exists.ts

@@ -1,29 +0,0 @@
-import { eventHandler, getQuery } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { MOCK_MENU_LIST } from '~/utils/mock-data';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-
-const pathMap: Record<string, any> = { '/': 0 };
-
-function getPaths(menus: any[]) {
-  menus.forEach((menu) => {
-    pathMap[menu.path] = String(menu.id);
-    if (menu.children) {
-      getPaths(menu.children);
-    }
-  });
-}
-getPaths(MOCK_MENU_LIST);
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  const { id, path } = getQuery(event);
-
-  return (path as string) in pathMap &&
-    (!id || pathMap[path as string] !== String(id))
-    ? useResponseSuccess(true)
-    : useResponseSuccess(false);
-});

+ 0 - 84
apps/backend-mock/api/system/role/list.ts

@@ -1,84 +0,0 @@
-import { faker } from '@faker-js/faker';
-import { eventHandler, getQuery } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { getMenuIds, MOCK_MENU_LIST } from '~/utils/mock-data';
-import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
-
-const formatterCN = new Intl.DateTimeFormat('zh-CN', {
-  timeZone: 'Asia/Shanghai',
-  year: 'numeric',
-  month: '2-digit',
-  day: '2-digit',
-  hour: '2-digit',
-  minute: '2-digit',
-  second: '2-digit',
-});
-
-const menuIds = getMenuIds(MOCK_MENU_LIST);
-
-function generateMockDataList(count: number) {
-  const dataList = [];
-
-  for (let i = 0; i < count; i++) {
-    const dataItem: Record<string, any> = {
-      id: faker.string.uuid(),
-      name: faker.commerce.product(),
-      status: faker.helpers.arrayElement([0, 1]),
-      createTime: formatterCN.format(
-        faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),
-      ),
-      permissions: faker.helpers.arrayElements(menuIds),
-      remark: faker.lorem.sentence(),
-    };
-
-    dataList.push(dataItem);
-  }
-
-  return dataList;
-}
-
-const mockData = generateMockDataList(100);
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-
-  const {
-    page = 1,
-    pageSize = 20,
-    name,
-    id,
-    remark,
-    startTime,
-    endTime,
-    status,
-  } = getQuery(event);
-  let listData = structuredClone(mockData);
-  if (name) {
-    listData = listData.filter((item) =>
-      item.name.toLowerCase().includes(String(name).toLowerCase()),
-    );
-  }
-  if (id) {
-    listData = listData.filter((item) =>
-      item.id.toLowerCase().includes(String(id).toLowerCase()),
-    );
-  }
-  if (remark) {
-    listData = listData.filter((item) =>
-      item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),
-    );
-  }
-  if (startTime) {
-    listData = listData.filter((item) => item.createTime >= startTime);
-  }
-  if (endTime) {
-    listData = listData.filter((item) => item.createTime <= endTime);
-  }
-  if (['0', '1'].includes(status as string)) {
-    listData = listData.filter((item) => item.status === Number(status));
-  }
-  return usePageResponseSuccess(page as string, pageSize as string, listData);
-});

+ 0 - 85
apps/backend-mock/api/system/user/list.ts

@@ -1,85 +0,0 @@
-import { faker } from '@faker-js/faker';
-import { eventHandler, getQuery } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
-
-const formatterCN = new Intl.DateTimeFormat('zh-CN', {
-  timeZone: 'Asia/Shanghai',
-  year: 'numeric',
-  month: '2-digit',
-  day: '2-digit',
-  hour: '2-digit',
-  minute: '2-digit',
-  second: '2-digit',
-});
-
-function generateMockDataList(count: number) {
-  const dataList = [];
-
-  for (let i = 0; i < count; i++) {
-    const dataItem: Record<string, any> = {
-      id: faker.string.uuid(),
-      name: faker.commerce.product(),
-      status: faker.helpers.arrayElement([0, 1]),
-      createTime: formatterCN.format(
-        faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),
-      ),
-      deptId: faker.string.uuid(),
-      remark: faker.lorem.sentence(),
-    };
-
-    dataList.push(dataItem);
-  }
-
-  return dataList;
-}
-
-const mockData = generateMockDataList(100);
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-
-  const {
-    page = 1,
-    pageSize = 20,
-    name,
-    id,
-    remark,
-    startTime,
-    endTime,
-    deptId,
-    status,
-  } = getQuery(event);
-  let listData = structuredClone(mockData);
-  if (name) {
-    listData = listData.filter((item) =>
-      item.name.toLowerCase().includes(String(name).toLowerCase()),
-    );
-  }
-  if (id) {
-    listData = listData.filter((item) =>
-      item.id.toLowerCase().includes(String(id).toLowerCase()),
-    );
-  }
-  if (remark) {
-    listData = listData.filter((item) =>
-      item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),
-    );
-  }
-  if (startTime) {
-    listData = listData.filter((item) => item.createTime >= startTime);
-  }
-  if (endTime) {
-    listData = listData.filter((item) => item.createTime <= endTime);
-  }
-  if (['0', '1'].includes(status as string)) {
-    listData = listData.filter((item) => item.status === Number(status));
-  }
-  if (deptId) {
-    listData = listData.filter((item) => item.deptId === deptId);
-  }
-  return usePageResponseSuccess(page as string, pageSize as string, listData);
-});

+ 0 - 117
apps/backend-mock/api/table/list.ts

@@ -1,117 +0,0 @@
-import { faker } from '@faker-js/faker';
-import { eventHandler, getQuery } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import {
-  sleep,
-  unAuthorizedResponse,
-  usePageResponseSuccess,
-} from '~/utils/response';
-
-function generateMockDataList(count: number) {
-  const dataList = [];
-
-  for (let i = 0; i < count; i++) {
-    const dataItem = {
-      id: faker.string.uuid(),
-      imageUrl: faker.image.avatar(),
-      imageUrl2: faker.image.avatar(),
-      open: faker.datatype.boolean(),
-      status: faker.helpers.arrayElement(['success', 'error', 'warning']),
-      productName: faker.commerce.productName(),
-      price: faker.commerce.price(),
-      currency: faker.finance.currencyCode(),
-      quantity: faker.number.int({ min: 1, max: 100 }),
-      available: faker.datatype.boolean(),
-      category: faker.commerce.department(),
-      releaseDate: faker.date.past(),
-      rating: faker.number.float({ min: 1, max: 5 }),
-      description: faker.commerce.productDescription(),
-      weight: faker.number.float({ min: 0.1, max: 10 }),
-      color: faker.color.human(),
-      inProduction: faker.datatype.boolean(),
-      tags: Array.from({ length: 3 }, () => faker.commerce.productAdjective()),
-    };
-
-    dataList.push(dataItem);
-  }
-
-  return dataList;
-}
-
-const mockData = generateMockDataList(100);
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-
-  await sleep(600);
-
-  const { page, pageSize, sortBy, sortOrder } = getQuery(event);
-  // 规范化分页参数,处理 string[]
-  const pageRaw = Array.isArray(page) ? page[0] : page;
-  const pageSizeRaw = Array.isArray(pageSize) ? pageSize[0] : pageSize;
-  const pageNumber = Math.max(
-    1,
-    Number.parseInt(String(pageRaw ?? '1'), 10) || 1,
-  );
-  const pageSizeNumber = Math.min(
-    100,
-    Math.max(1, Number.parseInt(String(pageSizeRaw ?? '10'), 10) || 10),
-  );
-  const listData = structuredClone(mockData);
-
-  // 规范化 query 入参,兼容 string[]
-  const sortKeyRaw = Array.isArray(sortBy) ? sortBy[0] : sortBy;
-  const sortOrderRaw = Array.isArray(sortOrder) ? sortOrder[0] : sortOrder;
-  // 检查 sortBy 是否是 listData 元素的合法属性键
-  if (
-    typeof sortKeyRaw === 'string' &&
-    listData[0] &&
-    Object.prototype.hasOwnProperty.call(listData[0], sortKeyRaw)
-  ) {
-    // 定义数组元素的类型
-    type ItemType = (typeof listData)[0];
-    const sortKey = sortKeyRaw as keyof ItemType; // 将 sortBy 断言为合法键
-    const isDesc = sortOrderRaw === 'desc';
-    listData.sort((a, b) => {
-      const aValue = a[sortKey] as unknown;
-      const bValue = b[sortKey] as unknown;
-
-      let result: number;
-
-      if (typeof aValue === 'number' && typeof bValue === 'number') {
-        result = aValue - bValue;
-      } else if (aValue instanceof Date && bValue instanceof Date) {
-        result = aValue.getTime() - bValue.getTime();
-      } else if (typeof aValue === 'boolean' && typeof bValue === 'boolean') {
-        if (aValue === bValue) {
-          result = 0;
-        } else {
-          result = aValue ? 1 : -1;
-        }
-      } else {
-        const aStr = String(aValue);
-        const bStr = String(bValue);
-        const aNum = Number(aStr);
-        const bNum = Number(bStr);
-        result =
-          Number.isFinite(aNum) && Number.isFinite(bNum)
-            ? aNum - bNum
-            : aStr.localeCompare(bStr, undefined, {
-                numeric: true,
-                sensitivity: 'base',
-              });
-      }
-
-      return isDesc ? -result : result;
-    });
-  }
-
-  return usePageResponseSuccess(
-    String(pageNumber),
-    String(pageSizeNumber),
-    listData,
-  );
-});

+ 0 - 3
apps/backend-mock/api/test.get.ts

@@ -1,3 +0,0 @@
-import { defineEventHandler } from 'h3';
-
-export default defineEventHandler(() => 'Test get handler');

+ 0 - 3
apps/backend-mock/api/test.post.ts

@@ -1,3 +0,0 @@
-import { defineEventHandler } from 'h3';
-
-export default defineEventHandler(() => 'Test post handler');

+ 0 - 12
apps/backend-mock/api/timezone/getTimezone.ts

@@ -1,12 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-import { getTimezone } from '~/utils/timezone-utils';
-
-export default eventHandler((event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  return useResponseSuccess(getTimezone());
-});

+ 0 - 11
apps/backend-mock/api/timezone/getTimezoneOptions.ts

@@ -1,11 +0,0 @@
-import { eventHandler } from 'h3';
-import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
-import { useResponseSuccess } from '~/utils/response';
-
-export default eventHandler(() => {
-  const data = TIME_ZONE_OPTIONS.map((o) => ({
-    label: `${o.timezone} (GMT${o.offset >= 0 ? `+${o.offset}` : o.offset})`,
-    value: o.timezone,
-  }));
-  return useResponseSuccess(data);
-});

+ 0 - 22
apps/backend-mock/api/timezone/setTimezone.ts

@@ -1,22 +0,0 @@
-import { eventHandler, readBody } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-import { setTimezone } from '~/utils/timezone-utils';
-
-export default eventHandler(async (event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  const body = await readBody<{ timezone?: unknown }>(event);
-  const timezone =
-    typeof body?.timezone === 'string' ? body.timezone : undefined;
-  const allowed = TIME_ZONE_OPTIONS.some((o) => o.timezone === timezone);
-  if (!timezone || !allowed) {
-    setResponseStatus(event, 400);
-    return useResponseError('Bad Request', 'Invalid timezone');
-  }
-  setTimezone(timezone);
-  return useResponseSuccess({});
-});

+ 0 - 14
apps/backend-mock/api/upload.ts

@@ -1,14 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-
-export default eventHandler((event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  return useResponseSuccess({
-    url: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
-  });
-  // return useResponseError("test")
-});

+ 0 - 11
apps/backend-mock/api/user/info.ts

@@ -1,11 +0,0 @@
-import { eventHandler } from 'h3';
-import { verifyAccessToken } from '~/utils/jwt-utils';
-import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
-
-export default eventHandler((event) => {
-  const userinfo = verifyAccessToken(event);
-  if (!userinfo) {
-    return unAuthorizedResponse(event);
-  }
-  return useResponseSuccess(userinfo);
-});

+ 0 - 7
apps/backend-mock/error.ts

@@ -1,7 +0,0 @@
-import type { NitroErrorHandler } from 'nitropack';
-
-const errorHandler: NitroErrorHandler = function (error, event) {
-  event.node.res.end(`[Error Handler] ${error.stack}`);
-};
-
-export default errorHandler;

+ 0 - 20
apps/backend-mock/middleware/1.api.ts

@@ -1,20 +0,0 @@
-import { defineEventHandler } from 'h3';
-import { forbiddenResponse, sleep } from '~/utils/response';
-
-export default defineEventHandler(async (event) => {
-  event.node.res.setHeader(
-    'Access-Control-Allow-Origin',
-    event.headers.get('Origin') ?? '*',
-  );
-  if (event.method === 'OPTIONS') {
-    event.node.res.statusCode = 204;
-    event.node.res.statusMessage = 'No Content.';
-    return 'OK';
-  } else if (
-    ['DELETE', 'PATCH', 'POST', 'PUT'].includes(event.method) &&
-    event.path.startsWith('/api/system/')
-  ) {
-    await sleep(Math.floor(Math.random() * 2000));
-    return forbiddenResponse(event, '演示环境,禁止修改');
-  }
-});

+ 0 - 20
apps/backend-mock/nitro.config.ts

@@ -1,20 +0,0 @@
-import errorHandler from './error';
-
-process.env.COMPATIBILITY_DATE = new Date().toISOString();
-export default defineNitroConfig({
-  devErrorHandler: errorHandler,
-  errorHandler: '~/error',
-  routeRules: {
-    '/api/**': {
-      cors: true,
-      headers: {
-        'Access-Control-Allow-Credentials': 'true',
-        'Access-Control-Allow-Headers':
-          'Accept, Authorization, Content-Length, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With',
-        'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
-        'Access-Control-Allow-Origin': '*',
-        'Access-Control-Expose-Headers': '*',
-      },
-    },
-  },
-});

+ 0 - 21
apps/backend-mock/package.json

@@ -1,21 +0,0 @@
-{
-  "name": "@vben/backend-mock",
-  "version": "5.7.0",
-  "description": "",
-  "private": true,
-  "license": "MIT",
-  "author": "",
-  "scripts": {
-    "build": "nitro build",
-    "start": "nitro dev"
-  },
-  "dependencies": {
-    "@faker-js/faker": "catalog:",
-    "jsonwebtoken": "catalog:",
-    "nitropack": "catalog:"
-  },
-  "devDependencies": {
-    "@types/jsonwebtoken": "catalog:",
-    "h3": "catalog:"
-  }
-}

+ 0 - 15
apps/backend-mock/routes/[...].ts

@@ -1,15 +0,0 @@
-import { defineEventHandler } from 'h3';
-
-export default defineEventHandler(() => {
-  return `
-<h1>Hello Vben Admin</h1>
-<h2>Mock service is starting</h2>
-<ul>
-<li><a href="/api/user">/api/user/info</a></li>
-<li><a href="/api/menu">/api/menu/all</a></li>
-<li><a href="/api/auth/codes">/api/auth/codes</a></li>
-<li><a href="/api/auth/login">/api/auth/login</a></li>
-<li><a href="/api/upload">/api/upload</a></li>
-</ul>
-`;
-});

+ 0 - 4
apps/backend-mock/tsconfig.build.json

@@ -1,4 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
-}

+ 0 - 3
apps/backend-mock/tsconfig.json

@@ -1,3 +0,0 @@
-{
-  "extends": "./.nitro/types/tsconfig.json"
-}

+ 0 - 28
apps/backend-mock/utils/cookie-utils.ts

@@ -1,28 +0,0 @@
-import type { EventHandlerRequest, H3Event } from 'h3';
-
-import { deleteCookie, getCookie, setCookie } from 'h3';
-
-export function clearRefreshTokenCookie(event: H3Event<EventHandlerRequest>) {
-  deleteCookie(event, 'jwt', {
-    httpOnly: true,
-    sameSite: 'none',
-    secure: true,
-  });
-}
-
-export function setRefreshTokenCookie(
-  event: H3Event<EventHandlerRequest>,
-  refreshToken: string,
-) {
-  setCookie(event, 'jwt', refreshToken, {
-    httpOnly: true,
-    maxAge: 24 * 60 * 60, // unit: seconds
-    sameSite: 'none',
-    secure: true,
-  });
-}
-
-export function getRefreshTokenFromCookie(event: H3Event<EventHandlerRequest>) {
-  const refreshToken = getCookie(event, 'jwt');
-  return refreshToken;
-}

+ 0 - 77
apps/backend-mock/utils/jwt-utils.ts

@@ -1,77 +0,0 @@
-import type { EventHandlerRequest, H3Event } from 'h3';
-
-import type { UserInfo } from './mock-data';
-
-import { getHeader } from 'h3';
-import jwt from 'jsonwebtoken';
-
-import { MOCK_USERS } from './mock-data';
-
-// TODO: Replace with your own secret key
-const ACCESS_TOKEN_SECRET = 'access_token_secret';
-const REFRESH_TOKEN_SECRET = 'refresh_token_secret';
-
-export interface UserPayload extends UserInfo {
-  iat: number;
-  exp: number;
-}
-
-export function generateAccessToken(user: UserInfo) {
-  return jwt.sign(user, ACCESS_TOKEN_SECRET, { expiresIn: '7d' });
-}
-
-export function generateRefreshToken(user: UserInfo) {
-  return jwt.sign(user, REFRESH_TOKEN_SECRET, {
-    expiresIn: '30d',
-  });
-}
-
-export function verifyAccessToken(
-  event: H3Event<EventHandlerRequest>,
-): null | Omit<UserInfo, 'password'> {
-  const authHeader = getHeader(event, 'Authorization');
-  if (!authHeader?.startsWith('Bearer')) {
-    return null;
-  }
-
-  const tokenParts = authHeader.split(' ');
-  if (tokenParts.length !== 2) {
-    return null;
-  }
-  const token = tokenParts[1] as string;
-  try {
-    const decoded = jwt.verify(
-      token,
-      ACCESS_TOKEN_SECRET,
-    ) as unknown as UserPayload;
-
-    const username = decoded.username;
-    const user = MOCK_USERS.find((item) => item.username === username);
-    if (!user) {
-      return null;
-    }
-    const { password: _pwd, ...userinfo } = user;
-    return userinfo;
-  } catch {
-    return null;
-  }
-}
-
-export function verifyRefreshToken(
-  token: string,
-): null | Omit<UserInfo, 'password'> {
-  try {
-    const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET) as UserPayload;
-    const username = decoded.username;
-    const user = MOCK_USERS.find(
-      (item) => item.username === username,
-    ) as UserInfo;
-    if (!user) {
-      return null;
-    }
-    const { password: _pwd, ...userinfo } = user;
-    return userinfo;
-  } catch {
-    return null;
-  }
-}

+ 0 - 421
apps/backend-mock/utils/mock-data.ts

@@ -1,421 +0,0 @@
-export interface UserInfo {
-  id: number;
-  password: string;
-  realName: string;
-  roles: string[];
-  username: string;
-  homePath?: string;
-}
-
-export interface TimezoneOption {
-  offset: number;
-  timezone: string;
-}
-
-export const MOCK_USERS: UserInfo[] = [
-  {
-    id: 0,
-    password: '123456',
-    realName: 'Vben',
-    roles: ['super'],
-    username: 'vben',
-  },
-  {
-    id: 1,
-    password: '123456',
-    realName: 'Admin',
-    roles: ['admin'],
-    username: 'admin',
-    homePath: '/workspace',
-  },
-  {
-    id: 2,
-    password: '123456',
-    realName: 'Jack',
-    roles: ['user'],
-    username: 'jack',
-    homePath: '/analytics',
-  },
-];
-
-export const MOCK_CODES = [
-  // super
-  {
-    codes: ['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010'],
-    username: 'vben',
-  },
-  {
-    // admin
-    codes: ['AC_100010', 'AC_100020', 'AC_100030'],
-    username: 'admin',
-  },
-  {
-    // user
-    codes: ['AC_1000001', 'AC_1000002'],
-    username: 'jack',
-  },
-];
-
-const dashboardMenus = [
-  {
-    meta: {
-      order: -1,
-      title: 'page.dashboard.title',
-    },
-    name: 'Dashboard',
-    path: '/dashboard',
-    redirect: '/analytics',
-    children: [
-      {
-        name: 'Analytics',
-        path: '/analytics',
-        component: '/dashboard/analytics/index',
-        meta: {
-          affixTab: true,
-          title: 'page.dashboard.analytics',
-        },
-      },
-      {
-        name: 'Workspace',
-        path: '/workspace',
-        component: '/dashboard/workspace/index',
-        meta: {
-          title: 'page.dashboard.workspace',
-        },
-      },
-    ],
-  },
-];
-
-const createDemosMenus = (role: 'admin' | 'super' | 'user') => {
-  const roleWithMenus = {
-    admin: {
-      component: '/demos/access/admin-visible',
-      meta: {
-        icon: 'mdi:button-cursor',
-        title: 'demos.access.adminVisible',
-      },
-      name: 'AccessAdminVisibleDemo',
-      path: '/demos/access/admin-visible',
-    },
-    super: {
-      component: '/demos/access/super-visible',
-      meta: {
-        icon: 'mdi:button-cursor',
-        title: 'demos.access.superVisible',
-      },
-      name: 'AccessSuperVisibleDemo',
-      path: '/demos/access/super-visible',
-    },
-    user: {
-      component: '/demos/access/user-visible',
-      meta: {
-        icon: 'mdi:button-cursor',
-        title: 'demos.access.userVisible',
-      },
-      name: 'AccessUserVisibleDemo',
-      path: '/demos/access/user-visible',
-    },
-  };
-
-  return [
-    {
-      meta: {
-        icon: 'ic:baseline-view-in-ar',
-        keepAlive: true,
-        order: 1000,
-        title: 'demos.title',
-      },
-      name: 'Demos',
-      path: '/demos',
-      redirect: '/demos/access',
-      children: [
-        {
-          name: 'AccessDemos',
-          path: '/demosaccess',
-          meta: {
-            icon: 'mdi:cloud-key-outline',
-            title: 'demos.access.backendPermissions',
-          },
-          redirect: '/demos/access/page-control',
-          children: [
-            {
-              name: 'AccessPageControlDemo',
-              path: '/demos/access/page-control',
-              component: '/demos/access/index',
-              meta: {
-                icon: 'mdi:page-previous-outline',
-                title: 'demos.access.pageAccess',
-              },
-            },
-            {
-              name: 'AccessButtonControlDemo',
-              path: '/demos/access/button-control',
-              component: '/demos/access/button-control',
-              meta: {
-                icon: 'mdi:button-cursor',
-                title: 'demos.access.buttonControl',
-              },
-            },
-            {
-              name: 'AccessMenuVisible403Demo',
-              path: '/demos/access/menu-visible-403',
-              component: '/demos/access/menu-visible-403',
-              meta: {
-                authority: ['no-body'],
-                icon: 'mdi:button-cursor',
-                menuVisibleWithForbidden: true,
-                title: 'demos.access.menuVisible403',
-              },
-            },
-            roleWithMenus[role],
-          ],
-        },
-      ],
-    },
-  ];
-};
-
-export const MOCK_MENUS = [
-  {
-    menus: [...dashboardMenus, ...createDemosMenus('super')],
-    username: 'vben',
-  },
-  {
-    menus: [...dashboardMenus, ...createDemosMenus('admin')],
-    username: 'admin',
-  },
-  {
-    menus: [...dashboardMenus, ...createDemosMenus('user')],
-    username: 'jack',
-  },
-];
-
-export const MOCK_MENU_LIST = [
-  {
-    id: 1,
-    name: 'Workspace',
-    status: 1,
-    type: 'menu',
-    icon: 'mdi:dashboard',
-    path: '/workspace',
-    component: '/dashboard/workspace/index',
-    meta: {
-      icon: 'carbon:workspace',
-      title: 'page.dashboard.workspace',
-      affixTab: true,
-      order: 0,
-    },
-  },
-  {
-    id: 2,
-    meta: {
-      icon: 'carbon:settings',
-      order: 9997,
-      title: 'system.title',
-      badge: 'new',
-      badgeType: 'normal',
-      badgeVariants: 'primary',
-    },
-    status: 1,
-    type: 'catalog',
-    name: 'System',
-    path: '/system',
-    children: [
-      {
-        id: 201,
-        pid: 2,
-        path: '/system/menu',
-        name: 'SystemMenu',
-        authCode: 'System:Menu:List',
-        status: 1,
-        type: 'menu',
-        meta: {
-          icon: 'carbon:menu',
-          title: 'system.menu.title',
-        },
-        component: '/system/menu/list',
-        children: [
-          {
-            id: 20_101,
-            pid: 201,
-            name: 'SystemMenuCreate',
-            status: 1,
-            type: 'button',
-            authCode: 'System:Menu:Create',
-            meta: { title: 'common.create' },
-          },
-          {
-            id: 20_102,
-            pid: 201,
-            name: 'SystemMenuEdit',
-            status: 1,
-            type: 'button',
-            authCode: 'System:Menu:Edit',
-            meta: { title: 'common.edit' },
-          },
-          {
-            id: 20_103,
-            pid: 201,
-            name: 'SystemMenuDelete',
-            status: 1,
-            type: 'button',
-            authCode: 'System:Menu:Delete',
-            meta: { title: 'common.delete' },
-          },
-        ],
-      },
-      {
-        id: 202,
-        pid: 2,
-        path: '/system/dept',
-        name: 'SystemDept',
-        status: 1,
-        type: 'menu',
-        authCode: 'System:Dept:List',
-        meta: {
-          icon: 'carbon:container-services',
-          title: 'system.dept.title',
-        },
-        component: '/system/dept/list',
-        children: [
-          {
-            id: 20_401,
-            pid: 202,
-            name: 'SystemDeptCreate',
-            status: 1,
-            type: 'button',
-            authCode: 'System:Dept:Create',
-            meta: { title: 'common.create' },
-          },
-          {
-            id: 20_402,
-            pid: 202,
-            name: 'SystemDeptEdit',
-            status: 1,
-            type: 'button',
-            authCode: 'System:Dept:Edit',
-            meta: { title: 'common.edit' },
-          },
-          {
-            id: 20_403,
-            pid: 202,
-            name: 'SystemDeptDelete',
-            status: 1,
-            type: 'button',
-            authCode: 'System:Dept:Delete',
-            meta: { title: 'common.delete' },
-          },
-        ],
-      },
-    ],
-  },
-  {
-    id: 9,
-    meta: {
-      badgeType: 'dot',
-      order: 9998,
-      title: 'demos.vben.title',
-      icon: 'carbon:data-center',
-    },
-    name: 'Project',
-    path: '/vben-admin',
-    type: 'catalog',
-    status: 1,
-    children: [
-      {
-        id: 901,
-        pid: 9,
-        name: 'VbenDocument',
-        path: '/vben-admin/document',
-        component: 'IFrameView',
-        type: 'embedded',
-        status: 1,
-        meta: {
-          icon: 'carbon:book',
-          iframeSrc: 'https://doc.vben.pro',
-          title: 'demos.vben.document',
-        },
-      },
-      {
-        id: 902,
-        pid: 9,
-        name: 'VbenGithub',
-        path: '/vben-admin/github',
-        component: 'IFrameView',
-        type: 'link',
-        status: 1,
-        meta: {
-          icon: 'carbon:logo-github',
-          link: 'https://github.com/vbenjs/vue-vben-admin',
-          title: 'Github',
-        },
-      },
-      {
-        id: 903,
-        pid: 9,
-        name: 'VbenAntdv',
-        path: '/vben-admin/antdv',
-        component: 'IFrameView',
-        type: 'link',
-        status: 0,
-        meta: {
-          icon: 'carbon:hexagon-vertical-solid',
-          badgeType: 'dot',
-          link: 'https://ant.vben.pro',
-          title: 'demos.vben.antdv',
-        },
-      },
-    ],
-  },
-  {
-    id: 10,
-    component: '_core/about/index',
-    type: 'menu',
-    status: 1,
-    meta: {
-      icon: 'lucide:copyright',
-      order: 9999,
-      title: 'demos.vben.about',
-    },
-    name: 'About',
-    path: '/about',
-  },
-];
-
-export function getMenuIds(menus: any[]) {
-  const ids: number[] = [];
-  menus.forEach((item) => {
-    ids.push(item.id);
-    if (item.children && item.children.length > 0) {
-      ids.push(...getMenuIds(item.children));
-    }
-  });
-  return ids;
-}
-
-/**
- * 时区选项
- */
-export const TIME_ZONE_OPTIONS: TimezoneOption[] = [
-  {
-    offset: -5,
-    timezone: 'America/New_York',
-  },
-  {
-    offset: 0,
-    timezone: 'Europe/London',
-  },
-  {
-    offset: 8,
-    timezone: 'Asia/Shanghai',
-  },
-  {
-    offset: 9,
-    timezone: 'Asia/Tokyo',
-  },
-  {
-    offset: 9,
-    timezone: 'Asia/Seoul',
-  },
-];

+ 0 - 70
apps/backend-mock/utils/response.ts

@@ -1,70 +0,0 @@
-import type { EventHandlerRequest, H3Event } from 'h3';
-
-import { setResponseStatus } from 'h3';
-
-export function useResponseSuccess<T = any>(data: T) {
-  return {
-    code: 0,
-    data,
-    error: null,
-    message: 'ok',
-  };
-}
-
-export function usePageResponseSuccess<T = any>(
-  page: number | string,
-  pageSize: number | string,
-  list: T[],
-  { message = 'ok' } = {},
-) {
-  const pageData = pagination(
-    Number.parseInt(`${page}`),
-    Number.parseInt(`${pageSize}`),
-    list,
-  );
-
-  return {
-    ...useResponseSuccess({
-      items: pageData,
-      total: list.length,
-    }),
-    message,
-  };
-}
-
-export function useResponseError(message: string, error: any = null) {
-  return {
-    code: -1,
-    data: null,
-    error,
-    message,
-  };
-}
-
-export function forbiddenResponse(
-  event: H3Event<EventHandlerRequest>,
-  message = 'Forbidden Exception',
-) {
-  setResponseStatus(event, 403);
-  return useResponseError(message, message);
-}
-
-export function unAuthorizedResponse(event: H3Event<EventHandlerRequest>) {
-  setResponseStatus(event, 401);
-  return useResponseError('Unauthorized Exception', 'Unauthorized Exception');
-}
-
-export function sleep(ms: number) {
-  return new Promise((resolve) => setTimeout(resolve, ms));
-}
-
-export function pagination<T = any>(
-  pageNo: number,
-  pageSize: number,
-  array: T[],
-): T[] {
-  const offset = (pageNo - 1) * Number(pageSize);
-  return offset + Number(pageSize) >= array.length
-    ? array.slice(offset)
-    : array.slice(offset, offset + Number(pageSize));
-}

+ 0 - 9
apps/backend-mock/utils/timezone-utils.ts

@@ -1,9 +0,0 @@
-let mockTimeZone: null | string = null;
-
-export const setTimezone = (timeZone: string) => {
-  mockTimeZone = timeZone;
-};
-
-export const getTimezone = () => {
-  return mockTimeZone;
-};

+ 0 - 8
apps/web-antd/.env

@@ -1,8 +0,0 @@
-# 应用标题
-VITE_APP_TITLE=Vben Admin Antd
-
-# 应用命名空间,用于缓存、store等功能的前缀,确保隔离
-VITE_APP_NAMESPACE=vben-web-antd
-
-# 对store进行加密的密钥,在将store持久化到localStorage时会使用该密钥进行加密
-VITE_APP_STORE_SECURE_KEY=please-replace-me-with-your-own-key

+ 0 - 7
apps/web-antd/.env.analyze

@@ -1,7 +0,0 @@
-# public path
-VITE_BASE=/
-
-# Basic interface address SPA
-VITE_GLOB_API_URL=/api
-
-VITE_VISUALIZER=true

+ 0 - 16
apps/web-antd/.env.development

@@ -1,16 +0,0 @@
-# 端口号
-VITE_PORT=5666
-
-VITE_BASE=/
-
-# 接口地址
-VITE_GLOB_API_URL=/api
-
-# 是否开启 Nitro Mock服务,true 为开启,false 为关闭
-VITE_NITRO_MOCK=true
-
-# 是否打开 devtools,true 为打开,false 为关闭
-VITE_DEVTOOLS=false
-
-# 是否注入全局loading
-VITE_INJECT_APP_LOADING=true

+ 0 - 19
apps/web-antd/.env.production

@@ -1,19 +0,0 @@
-VITE_BASE=/
-
-# 接口地址
-VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
-
-# 是否开启压缩,可以设置为 none, brotli, gzip
-VITE_COMPRESS=none
-
-# 是否开启 PWA
-VITE_PWA=false
-
-# vue-router 的模式
-VITE_ROUTER_HISTORY=hash
-
-# 是否注入全局loading
-VITE_INJECT_APP_LOADING=true
-
-# 打包后是否生成dist.zip
-VITE_ARCHIVER=true

+ 0 - 35
apps/web-antd/index.html

@@ -1,35 +0,0 @@
-<!doctype html>
-<html lang="zh">
-  <head>
-    <meta charset="UTF-8" />
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
-    <meta name="renderer" content="webkit" />
-    <meta name="description" content="A Modern Back-end Management System" />
-    <meta name="keywords" content="Vben Admin Vue3 Vite" />
-    <meta name="author" content="Vben" />
-    <meta
-      name="viewport"
-      content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
-    />
-    <!-- 由 vite 注入 VITE_APP_TITLE 变量,在 .env 文件内配置 -->
-    <title>%VITE_APP_TITLE%</title>
-    <link rel="icon" href="/favicon.ico" />
-    <script>
-      // 生产环境下注入百度统计
-      if (window._VBEN_ADMIN_PRO_APP_CONF_) {
-        var _hmt = _hmt || [];
-        (function () {
-          var hm = document.createElement('script');
-          hm.src =
-            'https://hm.baidu.com/hm.js?b38e689f40558f20a9a686d7f6f33edf';
-          var s = document.getElementsByTagName('script')[0];
-          s.parentNode.insertBefore(hm, s);
-        })();
-      }
-    </script>
-  </head>
-  <body>
-    <div id="app"></div>
-    <script type="module" src="/src/main.ts"></script>
-  </body>
-</html>

+ 0 - 50
apps/web-antd/package.json

@@ -1,50 +0,0 @@
-{
-  "name": "@vben/web-antd",
-  "version": "5.7.0",
-  "homepage": "https://vben.pro",
-  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
-    "directory": "apps/web-antd"
-  },
-  "license": "MIT",
-  "author": {
-    "name": "vben",
-    "email": "ann.vben@gmail.com",
-    "url": "https://github.com/anncwb"
-  },
-  "type": "module",
-  "scripts": {
-    "build": "pnpm vite build --mode production",
-    "build:analyze": "pnpm vite build --mode analyze",
-    "dev": "pnpm vite --mode development",
-    "preview": "vite preview",
-    "typecheck": "vue-tsc --noEmit --skipLibCheck"
-  },
-  "imports": {
-    "#/*": "./src/*"
-  },
-  "dependencies": {
-    "@vben/access": "workspace:*",
-    "@vben/common-ui": "workspace:*",
-    "@vben/constants": "workspace:*",
-    "@vben/hooks": "workspace:*",
-    "@vben/icons": "workspace:*",
-    "@vben/layouts": "workspace:*",
-    "@vben/locales": "workspace:*",
-    "@vben/plugins": "workspace:*",
-    "@vben/preferences": "workspace:*",
-    "@vben/request": "workspace:*",
-    "@vben/stores": "workspace:*",
-    "@vben/styles": "workspace:*",
-    "@vben/types": "workspace:*",
-    "@vben/utils": "workspace:*",
-    "@vueuse/core": "catalog:",
-    "ant-design-vue": "catalog:",
-    "dayjs": "catalog:",
-    "pinia": "catalog:",
-    "vue": "catalog:",
-    "vue-router": "catalog:"
-  }
-}

BIN
apps/web-antd/public/favicon.ico


+ 0 - 743
apps/web-antd/src/adapter/component/index.ts

@@ -1,743 +0,0 @@
-/**
- * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用
- * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
- */
-
-/* eslint-disable vue/one-component-per-file */
-
-import type {
-  AutoCompleteProps,
-  ButtonProps,
-  CascaderProps,
-  CheckboxGroupProps,
-  CheckboxProps,
-  DatePickerProps,
-  DividerProps,
-  InputNumberProps,
-  InputProps,
-  MentionsProps,
-  RadioGroupProps,
-  RadioProps,
-  RateProps,
-  SelectProps,
-  SpaceProps,
-  SwitchProps,
-  TextAreaProps,
-  TimePickerProps,
-  TreeSelectProps,
-  UploadChangeParam,
-  UploadFile,
-  UploadProps,
-} from 'ant-design-vue';
-import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
-
-import type { Component, Ref } from 'vue';
-
-import type {
-  ApiComponentSharedProps,
-  BaseFormComponentType,
-  IconPickerProps,
-} from '@vben/common-ui';
-import type { Sortable } from '@vben/hooks';
-import type { Recordable } from '@vben/types';
-
-import {
-  computed,
-  defineAsyncComponent,
-  defineComponent,
-  h,
-  nextTick,
-  onMounted,
-  onUnmounted,
-  ref,
-  render,
-  unref,
-  watch,
-} from 'vue';
-
-import {
-  ApiComponent,
-  globalShareState,
-  IconPicker,
-  VCropper,
-} from '@vben/common-ui';
-import { useSortable } from '@vben/hooks';
-import { IconifyIcon } from '@vben/icons';
-import { $t } from '@vben/locales';
-import { isEmpty } from '@vben/utils';
-
-import { message, Modal, notification } from 'ant-design-vue';
-
-type AdapterUploadProps = UploadProps & {
-  aspectRatio?: string;
-  crop?: boolean;
-  draggable?: boolean;
-  handleChange?: (event: UploadChangeParam) => void;
-  maxSize?: number;
-  onDragSort?: (oldIndex: number, newIndex: number) => void;
-  onHandleChange?: (event: UploadChangeParam) => void;
-};
-
-const AutoComplete = defineAsyncComponent(
-  () => import('ant-design-vue/es/auto-complete'),
-);
-const Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));
-const Checkbox = defineAsyncComponent(
-  () => import('ant-design-vue/es/checkbox'),
-);
-const CheckboxGroup = defineAsyncComponent(() =>
-  import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),
-);
-const DatePicker = defineAsyncComponent(
-  () => import('ant-design-vue/es/date-picker'),
-);
-const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));
-const Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));
-const InputNumber = defineAsyncComponent(
-  () => import('ant-design-vue/es/input-number'),
-);
-const InputPassword = defineAsyncComponent(() =>
-  import('ant-design-vue/es/input').then((res) => res.InputPassword),
-);
-const Mentions = defineAsyncComponent(
-  () => import('ant-design-vue/es/mentions'),
-);
-const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));
-const RadioGroup = defineAsyncComponent(() =>
-  import('ant-design-vue/es/radio').then((res) => res.RadioGroup),
-);
-const RangePicker = defineAsyncComponent(() =>
-  import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),
-);
-const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));
-const Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));
-const Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));
-const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));
-const Textarea = defineAsyncComponent(() =>
-  import('ant-design-vue/es/input').then((res) => res.Textarea),
-);
-const TimePicker = defineAsyncComponent(
-  () => import('ant-design-vue/es/time-picker'),
-);
-const TreeSelect = defineAsyncComponent(
-  () => import('ant-design-vue/es/tree-select'),
-);
-const Cascader = defineAsyncComponent(
-  () => import('ant-design-vue/es/cascader'),
-);
-const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));
-const Image = defineAsyncComponent(() => import('ant-design-vue/es/image'));
-const PreviewGroup = defineAsyncComponent(() =>
-  import('ant-design-vue/es/image').then((res) => res.ImagePreviewGroup),
-);
-
-const withDefaultPlaceholder = (
-  component: Component,
-  type: 'input' | 'select',
-  componentProps: Recordable<any> = {},
-) => {
-  return defineComponent({
-    name: component.name,
-    inheritAttrs: false,
-    setup: (props: any, { attrs, expose, slots }) => {
-      const placeholder =
-        props?.placeholder ||
-        attrs?.placeholder ||
-        $t(`ui.placeholder.${type}`);
-      // 透传组件暴露的方法
-      const innerRef = ref();
-      expose(
-        new Proxy(
-          {},
-          {
-            get: (_target, key) => innerRef.value?.[key],
-            has: (_target, key) => key in (innerRef.value || {}),
-          },
-        ),
-      );
-      return () =>
-        h(
-          component,
-          { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },
-          slots,
-        );
-    },
-  });
-};
-
-const IMAGE_EXTENSIONS = new Set([
-  'bmp',
-  'gif',
-  'jpeg',
-  'jpg',
-  'png',
-  'svg',
-  'webp',
-]);
-
-/**
- * 检查是否为图片文件
- */
-function isImageFile(file: UploadFile): boolean {
-  if (file.url) {
-    try {
-      const pathname = new URL(file.url, 'http://localhost').pathname;
-      const ext = pathname.split('.').pop()?.toLowerCase();
-      return ext ? IMAGE_EXTENSIONS.has(ext) : false;
-    } catch {
-      const ext = file.url?.split('.').pop()?.toLowerCase();
-      return ext ? IMAGE_EXTENSIONS.has(ext) : false;
-    }
-  }
-  if (!file.type) {
-    const ext = file.name?.split('.').pop()?.toLowerCase();
-    return ext ? IMAGE_EXTENSIONS.has(ext) : false;
-  }
-  return file.type.startsWith('image/');
-}
-
-/**
- * 创建默认的上传按钮插槽
- */
-function createDefaultUploadSlots(listType: string, placeholder: string) {
-  if (listType === 'picture-card') {
-    return { default: () => placeholder };
-  }
-  return {
-    default: () =>
-      h(
-        Button,
-        {
-          icon: h(IconifyIcon, {
-            icon: 'ant-design:upload-outlined',
-            class: 'mb-1 size-4',
-          }),
-        },
-        () => placeholder,
-      ),
-  };
-}
-
-/**
- * 获取文件的 Base64
- */
-function getBase64(file: File): Promise<string> {
-  return new Promise((resolve, reject) => {
-    const reader = new FileReader();
-    reader.readAsDataURL(file);
-    reader.addEventListener('load', () => resolve(reader.result as string));
-    reader.addEventListener('error', reject);
-  });
-}
-
-/**
- * 预览图片
- */
-async function previewImage(
-  file: UploadFile,
-  visible: Ref<boolean>,
-  fileList: Ref<UploadProps['fileList']>,
-) {
-  // 非图片文件直接打开链接
-  if (!isImageFile(file)) {
-    const url = file.url || file.preview;
-    if (url) {
-      window.open(url, '_blank');
-    } else {
-      message.error($t('ui.formRules.previewWarning'));
-    }
-    return;
-  }
-
-  const [ImageComponent, PreviewGroupComponent] = await Promise.all([
-    Image,
-    PreviewGroup,
-  ]);
-
-  // 过滤图片文件并生成预览
-  const imageFiles = (unref(fileList) || []).filter((f) => isImageFile(f));
-
-  for (const imgFile of imageFiles) {
-    if (!imgFile.url && !imgFile.preview && imgFile.originFileObj) {
-      imgFile.preview = await getBase64(imgFile.originFileObj);
-    }
-  }
-
-  const container = document.createElement('div');
-  document.body.append(container);
-  let isUnmounted = false;
-
-  const currentIndex = imageFiles.findIndex((f) => f.uid === file.uid);
-
-  const PreviewWrapper = {
-    setup() {
-      return () => {
-        if (isUnmounted) return null;
-        return h(
-          PreviewGroupComponent,
-          {
-            class: 'hidden',
-            preview: {
-              visible: visible.value,
-              current: currentIndex,
-              onVisibleChange: (value: boolean) => {
-                visible.value = value;
-                if (!value) {
-                  setTimeout(() => {
-                    if (!isUnmounted && container) {
-                      isUnmounted = true;
-                      render(null, container);
-                      container.remove();
-                    }
-                  }, 300);
-                }
-              },
-            },
-          },
-          () =>
-            imageFiles.map((imgFile) =>
-              h(ImageComponent, {
-                key: imgFile.uid,
-                src: imgFile.url || imgFile.preview,
-              }),
-            ),
-        );
-      };
-    },
-  };
-
-  render(h(PreviewWrapper), container);
-}
-
-/**
- * 图片裁剪操作
- */
-function cropImage(file: File, aspectRatio: string | undefined) {
-  return new Promise<Blob | string | undefined>((resolve, reject) => {
-    const container = document.createElement('div');
-    document.body.append(container);
-
-    let isUnmounted = false;
-    let objectUrl: null | string = null;
-
-    const open = ref<boolean>(true);
-    const cropperRef = ref<InstanceType<typeof VCropper> | null>(null);
-
-    const closeModal = () => {
-      open.value = false;
-      setTimeout(() => {
-        if (!isUnmounted && container) {
-          if (objectUrl) {
-            URL.revokeObjectURL(objectUrl);
-          }
-          isUnmounted = true;
-          render(null, container);
-          container.remove();
-        }
-      }, 300);
-    };
-
-    const CropperWrapper = {
-      setup() {
-        return () => {
-          if (isUnmounted) return null;
-          if (!objectUrl) {
-            objectUrl = URL.createObjectURL(file);
-          }
-          return h(
-            Modal,
-            {
-              open: open.value,
-              title: h('div', {}, [
-                $t('ui.crop.title'),
-                h(
-                  'span',
-                  {
-                    class: `${aspectRatio ? '' : 'hidden'} ml-2 text-sm text-gray-400 font-normal`,
-                  },
-                  $t('ui.crop.titleTip', [aspectRatio]),
-                ),
-              ]),
-              centered: true,
-              width: 548,
-              keyboard: false,
-              maskClosable: false,
-              closable: false,
-              cancelText: $t('common.cancel'),
-              okText: $t('ui.crop.confirm'),
-              destroyOnClose: true,
-              onOk: async () => {
-                const cropper = cropperRef.value;
-                if (!cropper) {
-                  reject(new Error('Cropper not found'));
-                  closeModal();
-                  return;
-                }
-                try {
-                  const dataUrl = await cropper.getCropImage();
-                  if (dataUrl) {
-                    resolve(dataUrl);
-                  } else {
-                    reject(new Error($t('ui.crop.errorTip')));
-                  }
-                } catch {
-                  reject(new Error($t('ui.crop.errorTip')));
-                } finally {
-                  closeModal();
-                }
-              },
-              onCancel() {
-                resolve('');
-                closeModal();
-              },
-            },
-            () =>
-              h(VCropper, {
-                ref: (ref: any) => (cropperRef.value = ref),
-                img: objectUrl as string,
-                aspectRatio,
-              }),
-          );
-        };
-      },
-    };
-
-    render(h(CropperWrapper), container);
-  });
-}
-
-/**
- * 带预览功能的上传组件
- */
-const withPreviewUpload = () => {
-  return defineComponent({
-    name: Upload.name,
-    emits: ['update:modelValue'],
-    setup(
-      props: any,
-      { attrs, slots, emit }: { attrs: any; emit: any; slots: any },
-    ) {
-      const previewVisible = ref<boolean>(false);
-      const placeholder = attrs?.placeholder || $t('ui.placeholder.upload');
-      const listType = attrs?.listType || attrs?.['list-type'] || 'text';
-      const fileList = ref<UploadProps['fileList']>(
-        attrs?.fileList || attrs?.['file-list'] || [],
-      );
-
-      const maxSize = computed(() => attrs?.maxSize ?? attrs?.['max-size']);
-      const aspectRatio = computed(
-        () => attrs?.aspectRatio ?? attrs?.['aspect-ratio'],
-      );
-
-      const handleBeforeUpload = async (
-        file: UploadFile,
-        originFileList: Array<File>,
-      ) => {
-        // 文件大小限制
-        if (maxSize.value && (file.size || 0) / 1024 / 1024 > maxSize.value) {
-          message.error($t('ui.formRules.sizeLimit', [maxSize.value]));
-          file.status = 'removed';
-          return false;
-        }
-
-        // 图片裁剪处理
-        if (
-          attrs.crop &&
-          !attrs.multiple &&
-          originFileList[0] &&
-          isImageFile(file)
-        ) {
-          file.status = 'removed';
-          const blob = await cropImage(originFileList[0], aspectRatio.value);
-          if (!blob) {
-            throw new Error($t('ui.crop.errorTip'));
-          }
-          return blob;
-        }
-
-        return attrs.beforeUpload?.(file) ?? true;
-      };
-
-      const handleChange = (event: UploadChangeParam) => {
-        try {
-          attrs.handleChange?.(event);
-          attrs.onHandleChange?.(event);
-        } catch (error) {
-          console.error(error);
-        }
-        fileList.value = event.fileList.filter(
-          (file) => file.status !== 'removed',
-        );
-        emit(
-          'update:modelValue',
-          event.fileList?.length ? fileList.value : undefined,
-        );
-      };
-
-      const handlePreview = async (file: UploadFile) => {
-        previewVisible.value = true;
-        await previewImage(file, previewVisible, fileList);
-      };
-
-      const renderUploadButton = () => {
-        if (attrs.disabled) return null;
-        return isEmpty(slots)
-          ? createDefaultUploadSlots(listType, placeholder)
-          : slots;
-      };
-
-      // 拖拽排序
-      const draggable = computed(
-        () => (attrs.draggable ?? false) && !attrs.disabled,
-      );
-      const uploadId = `upload-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
-      const sortableInstance = ref<null | Sortable>(null);
-
-      const styleId = `upload-drag-style-${uploadId}`;
-
-      function injectDragStyle() {
-        if (!document.querySelector(`[id="${styleId}"]`)) {
-          const style = document.createElement('style');
-          style.id = styleId;
-          style.textContent = `
-            [data-upload-id="${uploadId}"] .ant-upload-list-item { cursor: move; }
-            [data-upload-id="${uploadId}"] .ant-upload-list-item:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.15); }
-          `;
-          document.head.append(style);
-        }
-      }
-
-      function removeDragStyle() {
-        document.querySelector(`[id="${styleId}"]`)?.remove();
-      }
-
-      async function initSortable(retryCount = 0) {
-        if (!draggable.value) return;
-
-        injectDragStyle();
-        await nextTick();
-        await new Promise((resolve) => setTimeout(resolve, 100));
-
-        const container = document.querySelector(
-          `[data-upload-id="${uploadId}"] .ant-upload-list`,
-        ) as HTMLElement;
-
-        if (!container) {
-          if (retryCount < 5) {
-            setTimeout(() => initSortable(retryCount + 1), 200);
-          }
-          return;
-        }
-
-        const { initializeSortable } = useSortable(container, {
-          animation: 300,
-          delay: 400,
-          delayOnTouchOnly: true,
-          filter:
-            '.ant-upload-select, .ant-upload-list-item-error, .ant-upload-list-item-uploading',
-          onEnd: (evt) => {
-            const { oldIndex, newIndex } = evt;
-            if (
-              oldIndex === undefined ||
-              newIndex === undefined ||
-              oldIndex === newIndex
-            ) {
-              return;
-            }
-
-            const list = [...(fileList.value || [])];
-            const [movedItem] = list.splice(oldIndex, 1);
-            if (movedItem) {
-              list.splice(newIndex, 0, movedItem);
-              fileList.value = list;
-            }
-
-            attrs.onDragSort?.(oldIndex, newIndex);
-            emit('update:modelValue', fileList.value);
-          },
-        });
-
-        sortableInstance.value = await initializeSortable();
-      }
-
-      // 监听表单值变化
-      watch(
-        () => attrs.modelValue,
-        (res) => {
-          fileList.value = res;
-        },
-      );
-
-      onMounted(initSortable);
-      onUnmounted(() => {
-        sortableInstance.value?.destroy();
-        removeDragStyle();
-      });
-
-      return () =>
-        h(
-          'div',
-          { 'data-upload-id': uploadId, class: 'w-full' },
-          h(
-            Upload,
-            {
-              ...props,
-              ...attrs,
-              fileList: fileList.value,
-              beforeUpload: handleBeforeUpload,
-              onChange: handleChange,
-              onPreview: handlePreview,
-            },
-            renderUploadButton() as any,
-          ),
-        );
-    },
-  });
-};
-
-// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
-export type ComponentType =
-  | 'ApiCascader'
-  | 'ApiSelect'
-  | 'ApiTreeSelect'
-  | 'AutoComplete'
-  | 'Cascader'
-  | 'Checkbox'
-  | 'CheckboxGroup'
-  | 'DatePicker'
-  | 'DefaultButton'
-  | 'Divider'
-  | 'IconPicker'
-  | 'Input'
-  | 'InputNumber'
-  | 'InputPassword'
-  | 'Mentions'
-  | 'PrimaryButton'
-  | 'Radio'
-  | 'RadioGroup'
-  | 'RangePicker'
-  | 'Rate'
-  | 'Select'
-  | 'Space'
-  | 'Switch'
-  | 'Textarea'
-  | 'TimePicker'
-  | 'TreeSelect'
-  | 'Upload'
-  | BaseFormComponentType;
-
-/**
- * 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
- */
-export interface ComponentPropsMap {
-  ApiCascader: ApiComponentSharedProps & CascaderProps;
-  ApiSelect: ApiComponentSharedProps & SelectProps;
-  ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
-  AutoComplete: AutoCompleteProps;
-  Cascader: CascaderProps;
-  Checkbox: CheckboxProps;
-  CheckboxGroup: CheckboxGroupProps;
-  DatePicker: DatePickerProps;
-  DefaultButton: ButtonProps;
-  Divider: DividerProps;
-  IconPicker: IconPickerProps;
-  Input: InputProps;
-  InputNumber: InputNumberProps;
-  InputPassword: InputProps;
-  Mentions: MentionsProps;
-  PrimaryButton: ButtonProps;
-  Radio: RadioProps;
-  RadioGroup: RadioGroupProps;
-  RangePicker: RangePickerProps;
-  Rate: RateProps;
-  Select: SelectProps;
-  Space: SpaceProps;
-  Switch: SwitchProps;
-  Textarea: TextAreaProps;
-  TimePicker: TimePickerProps;
-  TreeSelect: TreeSelectProps;
-  Upload: AdapterUploadProps;
-}
-
-async function initComponentAdapter() {
-  const components: Partial<Record<ComponentType, Component>> = {
-    // 如果你的组件体积比较大,可以使用异步加载
-    // Button: () =>
-    // import('xxx').then((res) => res.Button),
-
-    ApiCascader: withDefaultPlaceholder(ApiComponent, 'select', {
-      component: Cascader,
-      fieldNames: { label: 'label', value: 'value', children: 'children' },
-      loadingSlot: 'suffixIcon',
-      modelPropName: 'value',
-      visibleEvent: 'onVisibleChange',
-    }),
-    ApiSelect: withDefaultPlaceholder(ApiComponent, 'select', {
-      component: Select,
-      loadingSlot: 'suffixIcon',
-      modelPropName: 'value',
-      visibleEvent: 'onVisibleChange',
-    }),
-    ApiTreeSelect: withDefaultPlaceholder(ApiComponent, 'select', {
-      component: TreeSelect,
-      fieldNames: { label: 'label', value: 'value', children: 'children' },
-      loadingSlot: 'suffixIcon',
-      modelPropName: 'value',
-      optionsPropName: 'treeData',
-      visibleEvent: 'onVisibleChange',
-    }),
-    AutoComplete,
-    Cascader,
-    Checkbox,
-    CheckboxGroup,
-    DatePicker,
-    // 自定义默认按钮
-    DefaultButton: (props, { attrs, slots }) => {
-      return h(Button, { ...props, attrs, type: 'default' }, slots);
-    },
-    Divider,
-    IconPicker: withDefaultPlaceholder(IconPicker, 'select', {
-      iconSlot: 'addonAfter',
-      inputComponent: Input,
-      modelValueProp: 'value',
-    }),
-    Input: withDefaultPlaceholder(Input, 'input'),
-    InputNumber: withDefaultPlaceholder(InputNumber, 'input', {
-      style: { width: '100%' },
-    }),
-    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
-    Mentions: withDefaultPlaceholder(Mentions, 'input'),
-    // 自定义主要按钮
-    PrimaryButton: (props, { attrs, slots }) => {
-      return h(Button, { ...props, attrs, type: 'primary' }, slots);
-    },
-    Radio,
-    RadioGroup,
-    RangePicker,
-    Rate,
-    Select: withDefaultPlaceholder(Select, 'select'),
-    Space,
-    Switch,
-    Textarea: withDefaultPlaceholder(Textarea, 'input'),
-    TimePicker,
-    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
-    Upload: withPreviewUpload(),
-  };
-
-  // 将组件注册到全局共享状态中
-  globalShareState.setComponents(components);
-
-  // 定义全局共享状态中的消息提示
-  globalShareState.defineMessage({
-    // 复制成功消息提示
-    copyPreferencesSuccess: (title, content) => {
-      notification.success({
-        description: content,
-        message: title,
-        placement: 'bottomRight',
-      });
-    },
-  });
-}
-
-export { initComponentAdapter };

+ 0 - 49
apps/web-antd/src/adapter/form.ts

@@ -1,49 +0,0 @@
-import type {
-  VbenFormProps as FormProps,
-  VbenFormSchema as FormSchema,
-} from '@vben/common-ui';
-
-import type { ComponentPropsMap, ComponentType } from './component';
-
-import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
-import { $t } from '@vben/locales';
-
-async function initSetupVbenForm() {
-  setupVbenForm<ComponentType>({
-    config: {
-      // ant design vue组件库默认都是 v-model:value
-      baseModelPropName: 'value',
-
-      // 一些组件是 v-model:checked 或者 v-model:fileList
-      modelPropNameMap: {
-        Checkbox: 'checked',
-        Radio: 'checked',
-        Switch: 'checked',
-        Upload: 'fileList',
-      },
-    },
-    defineRules: {
-      // 输入项目必填国际化适配
-      required: (value, _params, ctx) => {
-        if (value === undefined || value === null || value.length === 0) {
-          return $t('ui.formRules.required', [ctx.label]);
-        }
-        return true;
-      },
-      // 选择项目必填国际化适配
-      selectRequired: (value, _params, ctx) => {
-        if (value === undefined || value === null) {
-          return $t('ui.formRules.selectRequired', [ctx.label]);
-        }
-        return true;
-      },
-    },
-  });
-}
-
-const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
-
-export { initSetupVbenForm, useVbenForm, z };
-
-export type VbenFormSchema = FormSchema<ComponentType, ComponentPropsMap>;
-export type VbenFormProps = FormProps<ComponentType, ComponentPropsMap>;

+ 0 - 77
apps/web-antd/src/adapter/vxe-table.ts

@@ -1,77 +0,0 @@
-import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
-
-import type { ComponentPropsMap, ComponentType } from './component';
-
-import { h } from 'vue';
-
-import {
-  setupVbenVxeTable,
-  useVbenVxeGrid as useGrid,
-} from '@vben/plugins/vxe-table';
-
-import { Button, Image } from 'ant-design-vue';
-
-import { useVbenForm } from './form';
-
-setupVbenVxeTable({
-  configVxeTable: (vxeUI) => {
-    vxeUI.setConfig({
-      grid: {
-        align: 'center',
-        border: false,
-        columnConfig: {
-          resizable: true,
-        },
-        minHeight: 180,
-        formConfig: {
-          // 全局禁用vxe-table的表单配置,使用formOptions
-          enabled: false,
-        },
-        proxyConfig: {
-          autoLoad: true,
-          response: {
-            result: 'items',
-            total: 'total',
-            list: 'items',
-          },
-          showActiveMsg: true,
-          showResponseMsg: false,
-        },
-        round: true,
-        showOverflow: true,
-        size: 'small',
-      } as VxeTableGridOptions,
-    });
-
-    // 表格配置项可以用 cellRender: { name: 'CellImage' },
-    vxeUI.renderer.add('CellImage', {
-      renderTableDefault(renderOpts, params) {
-        const { props } = renderOpts;
-        const { column, row } = params;
-        return h(Image, { src: row[column.field], ...props });
-      },
-    });
-
-    // 表格配置项可以用 cellRender: { name: 'CellLink' },
-    vxeUI.renderer.add('CellLink', {
-      renderTableDefault(renderOpts) {
-        const { props } = renderOpts;
-        return h(
-          Button,
-          { size: 'small', type: 'link' },
-          { default: () => props?.text },
-        );
-      },
-    });
-
-    // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
-    // vxeUI.formats.add
-  },
-  useVbenForm,
-});
-
-export const useVbenVxeGrid = <T extends Record<string, any>>(
-  ...rest: Parameters<typeof useGrid<T, ComponentType, ComponentPropsMap>>
-) => useGrid<T, ComponentType, ComponentPropsMap>(...rest);
-
-export type * from '@vben/plugins/vxe-table';

+ 0 - 51
apps/web-antd/src/api/core/auth.ts

@@ -1,51 +0,0 @@
-import { baseRequestClient, requestClient } from '#/api/request';
-
-export namespace AuthApi {
-  /** 登录接口参数 */
-  export interface LoginParams {
-    password?: string;
-    username?: string;
-  }
-
-  /** 登录接口返回值 */
-  export interface LoginResult {
-    accessToken: string;
-  }
-
-  export interface RefreshTokenResult {
-    data: string;
-    status: number;
-  }
-}
-
-/**
- * 登录
- */
-export async function loginApi(data: AuthApi.LoginParams) {
-  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);
-}
-
-/**
- * 刷新accessToken
- */
-export async function refreshTokenApi() {
-  return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {
-    withCredentials: true,
-  });
-}
-
-/**
- * 退出登录
- */
-export async function logoutApi() {
-  return baseRequestClient.post('/auth/logout', {
-    withCredentials: true,
-  });
-}
-
-/**
- * 获取用户权限码
- */
-export async function getAccessCodesApi() {
-  return requestClient.get<string[]>('/auth/codes');
-}

+ 0 - 3
apps/web-antd/src/api/core/index.ts

@@ -1,3 +0,0 @@
-export * from './auth';
-export * from './menu';
-export * from './user';

+ 0 - 10
apps/web-antd/src/api/core/menu.ts

@@ -1,10 +0,0 @@
-import type { RouteRecordStringComponent } from '@vben/types';
-
-import { requestClient } from '#/api/request';
-
-/**
- * 获取用户所有菜单
- */
-export async function getAllMenusApi() {
-  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');
-}

+ 0 - 10
apps/web-antd/src/api/core/user.ts

@@ -1,10 +0,0 @@
-import type { UserInfo } from '@vben/types';
-
-import { requestClient } from '#/api/request';
-
-/**
- * 获取用户信息
- */
-export async function getUserInfoApi() {
-  return requestClient.get<UserInfo>('/user/info');
-}

+ 0 - 1
apps/web-antd/src/api/index.ts

@@ -1 +0,0 @@
-export * from './core';

+ 0 - 113
apps/web-antd/src/api/request.ts

@@ -1,113 +0,0 @@
-/**
- * 该文件可自行根据业务逻辑进行调整
- */
-import type { RequestClientOptions } from '@vben/request';
-
-import { useAppConfig } from '@vben/hooks';
-import { preferences } from '@vben/preferences';
-import {
-  authenticateResponseInterceptor,
-  defaultResponseInterceptor,
-  errorMessageResponseInterceptor,
-  RequestClient,
-} from '@vben/request';
-import { useAccessStore } from '@vben/stores';
-
-import { message } from 'ant-design-vue';
-
-import { useAuthStore } from '#/store';
-
-import { refreshTokenApi } from './core';
-
-const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
-
-function createRequestClient(baseURL: string, options?: RequestClientOptions) {
-  const client = new RequestClient({
-    ...options,
-    baseURL,
-  });
-
-  /**
-   * 重新认证逻辑
-   */
-  async function doReAuthenticate() {
-    console.warn('Access token or refresh token is invalid or expired. ');
-    const accessStore = useAccessStore();
-    const authStore = useAuthStore();
-    accessStore.setAccessToken(null);
-    if (
-      preferences.app.loginExpiredMode === 'modal' &&
-      accessStore.isAccessChecked
-    ) {
-      accessStore.setLoginExpired(true);
-    } else {
-      await authStore.logout();
-    }
-  }
-
-  /**
-   * 刷新token逻辑
-   */
-  async function doRefreshToken() {
-    const accessStore = useAccessStore();
-    const resp = await refreshTokenApi();
-    const newToken = resp.data;
-    accessStore.setAccessToken(newToken);
-    return newToken;
-  }
-
-  function formatToken(token: null | string) {
-    return token ? `Bearer ${token}` : null;
-  }
-
-  // 请求头处理
-  client.addRequestInterceptor({
-    fulfilled: async (config) => {
-      const accessStore = useAccessStore();
-
-      config.headers.Authorization = formatToken(accessStore.accessToken);
-      config.headers['Accept-Language'] = preferences.app.locale;
-      return config;
-    },
-  });
-
-  // 处理返回的响应数据格式
-  client.addResponseInterceptor(
-    defaultResponseInterceptor({
-      codeField: 'code',
-      dataField: 'data',
-      successCode: 0,
-    }),
-  );
-
-  // token过期的处理
-  client.addResponseInterceptor(
-    authenticateResponseInterceptor({
-      client,
-      doReAuthenticate,
-      doRefreshToken,
-      enableRefreshToken: preferences.app.enableRefreshToken,
-      formatToken,
-    }),
-  );
-
-  // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里
-  client.addResponseInterceptor(
-    errorMessageResponseInterceptor((msg: string, error) => {
-      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
-      // 当前mock接口返回的错误字段是 error 或者 message
-      const responseData = error?.response?.data ?? {};
-      const errorMessage = responseData?.error ?? responseData?.message ?? '';
-      // 如果没有错误信息,则会根据状态码进行提示
-      message.error(errorMessage || msg);
-    }),
-  );
-
-  return client;
-}
-
-export const requestClient = createRequestClient(apiURL, {
-  responseReturn: 'data',
-});
-
-export const baseRequestClient = new RequestClient({ baseURL: apiURL });

+ 0 - 39
apps/web-antd/src/app.vue

@@ -1,39 +0,0 @@
-<script lang="ts" setup>
-import { computed } from 'vue';
-
-import { useAntdDesignTokens } from '@vben/hooks';
-import { preferences, usePreferences } from '@vben/preferences';
-
-import { App, ConfigProvider, theme } from 'ant-design-vue';
-
-import { antdLocale } from '#/locales';
-
-defineOptions({ name: 'App' });
-
-const { isDark } = usePreferences();
-const { tokens } = useAntdDesignTokens();
-
-const tokenTheme = computed(() => {
-  const algorithm = isDark.value
-    ? [theme.darkAlgorithm]
-    : [theme.defaultAlgorithm];
-
-  // antd 紧凑模式算法
-  if (preferences.app.compact) {
-    algorithm.push(theme.compactAlgorithm);
-  }
-
-  return {
-    algorithm,
-    token: tokens,
-  };
-});
-</script>
-
-<template>
-  <ConfigProvider :locale="antdLocale" :theme="tokenTheme">
-    <App>
-      <RouterView />
-    </App>
-  </ConfigProvider>
-</template>

+ 0 - 76
apps/web-antd/src/bootstrap.ts

@@ -1,76 +0,0 @@
-import { createApp, watchEffect } from 'vue';
-
-import { registerAccessDirective } from '@vben/access';
-import { registerLoadingDirective } from '@vben/common-ui/es/loading';
-import { preferences } from '@vben/preferences';
-import { initStores } from '@vben/stores';
-import '@vben/styles';
-import '@vben/styles/antd';
-
-import { useTitle } from '@vueuse/core';
-
-import { $t, setupI18n } from '#/locales';
-
-import { initComponentAdapter } from './adapter/component';
-import { initSetupVbenForm } from './adapter/form';
-import App from './app.vue';
-import { router } from './router';
-
-async function bootstrap(namespace: string) {
-  // 初始化组件适配器
-  await initComponentAdapter();
-
-  // 初始化表单组件
-  await initSetupVbenForm();
-
-  // // 设置弹窗的默认配置
-  // setDefaultModalProps({
-  //   fullscreenButton: false,
-  // });
-  // // 设置抽屉的默认配置
-  // setDefaultDrawerProps({
-  //   zIndex: 1020,
-  // });
-
-  const app = createApp(App);
-
-  // 注册v-loading指令
-  registerLoadingDirective(app, {
-    loading: 'loading', // 在这里可以自定义指令名称,也可以明确提供false表示不注册这个指令
-    spinning: 'spinning',
-  });
-
-  // 国际化 i18n 配置
-  await setupI18n(app);
-
-  // 配置 pinia-tore
-  await initStores(app, { namespace });
-
-  // 安装权限指令
-  registerAccessDirective(app);
-
-  // 初始化 tippy
-  const { initTippy } = await import('@vben/common-ui/es/tippy');
-  initTippy(app);
-
-  // 配置路由及路由守卫
-  app.use(router);
-
-  // 配置Motion插件
-  const { MotionPlugin } = await import('@vben/plugins/motion');
-  app.use(MotionPlugin);
-
-  // 动态更新标题
-  watchEffect(() => {
-    if (preferences.app.dynamicTitle) {
-      const routeTitle = router.currentRoute.value.meta?.title;
-      const pageTitle =
-        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;
-      useTitle(pageTitle);
-    }
-  });
-
-  app.mount('#app');
-}
-
-export { bootstrap };

+ 0 - 25
apps/web-antd/src/layouts/auth.vue

@@ -1,25 +0,0 @@
-<script lang="ts" setup>
-import { computed } from 'vue';
-
-import { AuthPageLayout } from '@vben/layouts';
-import { preferences } from '@vben/preferences';
-
-import { $t } from '#/locales';
-
-const appName = computed(() => preferences.app.name);
-const logo = computed(() => preferences.logo.source);
-const logoDark = computed(() => preferences.logo.sourceDark);
-</script>
-
-<template>
-  <AuthPageLayout
-    :app-name="appName"
-    :logo="logo"
-    :logo-dark="logoDark"
-    :page-description="$t('authentication.pageDesc')"
-    :page-title="$t('authentication.pageTitle')"
-  >
-    <!-- 自定义工具栏 -->
-    <!-- <template #toolbar></template> -->
-  </AuthPageLayout>
-</template>

+ 0 - 256
apps/web-antd/src/layouts/basic.vue

@@ -1,256 +0,0 @@
-<script lang="ts" setup>
-import type { NotificationItem } from '@vben/layouts';
-
-import { computed, ref, watch } from 'vue';
-import { useRouter } from 'vue-router';
-
-import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
-import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
-import { useWatermark } from '@vben/hooks';
-import { BookOpenText, CircleHelp, SvgGithubIcon } from '@vben/icons';
-import {
-  BasicLayout,
-  LockScreen,
-  Notification,
-  UserDropdown,
-} from '@vben/layouts';
-import { preferences, usePreferences } from '@vben/preferences';
-import { useAccessStore, useUserStore } from '@vben/stores';
-import { openWindow } from '@vben/utils';
-
-import { $t } from '#/locales';
-import { useAuthStore } from '#/store';
-import LoginForm from '#/views/_core/authentication/login.vue';
-
-const notifications = ref<NotificationItem[]>([
-  {
-    id: 1,
-    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
-    date: '3小时前',
-    isRead: true,
-    message: '描述信息描述信息描述信息',
-    title: '收到了 14 份新周报',
-  },
-  {
-    id: 2,
-    avatar: 'https://avatar.vercel.sh/1',
-    date: '刚刚',
-    isRead: false,
-    message: '描述信息描述信息描述信息',
-    title: '朱偏右 回复了你',
-  },
-  {
-    id: 3,
-    avatar: 'https://avatar.vercel.sh/1',
-    date: '2024-01-01',
-    isRead: false,
-    message: '描述信息描述信息描述信息',
-    title: '曲丽丽 评论了你',
-  },
-  {
-    id: 4,
-    avatar: 'https://avatar.vercel.sh/satori',
-    date: '1天前',
-    isRead: false,
-    message: '描述信息描述信息描述信息',
-    title: '代办提醒',
-  },
-  {
-    id: 5,
-    avatar: 'https://avatar.vercel.sh/satori',
-    date: '1天前',
-    isRead: false,
-    message: '描述信息描述信息描述信息',
-    title: '跳转Workspace示例',
-    link: '/workspace',
-  },
-  {
-    id: 6,
-    avatar: 'https://avatar.vercel.sh/satori',
-    date: '1天前',
-    isRead: false,
-    message: '描述信息描述信息描述信息',
-    title: '跳转外部链接示例',
-    link: 'https://doc.vben.pro',
-  },
-]);
-
-const router = useRouter();
-const userStore = useUserStore();
-const authStore = useAuthStore();
-const accessStore = useAccessStore();
-const { destroyWatermark, updateWatermark } = useWatermark();
-const { isDark } = usePreferences();
-const showDot = computed(() =>
-  notifications.value.some((item) => !item.isRead),
-);
-
-const menus = computed(() => [
-  {
-    handler: () => {
-      router.push({ name: 'Profile' });
-    },
-    icon: 'lucide:user',
-    text: $t('page.auth.profile'),
-  },
-  {
-    handler: () => {
-      openWindow(VBEN_DOC_URL, {
-        target: '_blank',
-      });
-    },
-    icon: BookOpenText,
-    text: $t('ui.widgets.document'),
-  },
-  {
-    handler: () => {
-      openWindow(VBEN_GITHUB_URL, {
-        target: '_blank',
-      });
-    },
-    icon: SvgGithubIcon,
-    text: 'GitHub',
-  },
-  {
-    handler: () => {
-      openWindow(`${VBEN_GITHUB_URL}/issues`, {
-        target: '_blank',
-      });
-    },
-    icon: CircleHelp,
-    text: $t('ui.widgets.qa'),
-  },
-]);
-
-const avatar = computed(() => {
-  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
-});
-
-async function handleLogout() {
-  await authStore.logout(false);
-}
-
-function handleNoticeClear() {
-  notifications.value = [];
-}
-
-function markRead(id: number | string) {
-  const item = notifications.value.find((item) => item.id === id);
-  if (item) {
-    item.isRead = true;
-  }
-}
-
-function remove(id: number | string) {
-  notifications.value = notifications.value.filter((item) => item.id !== id);
-}
-
-function handleMakeAll() {
-  notifications.value.forEach((item) => (item.isRead = true));
-}
-
-const viewAll = () => {};
-
-const handleClick = (item: NotificationItem) => {
-  // 如果通知项有链接,点击时跳转
-  if (item.link) {
-    navigateTo(item.link, item.query, item.state);
-  }
-};
-
-function navigateTo(
-  link: string,
-  query?: Record<string, any>,
-  state?: Record<string, any>,
-) {
-  if (link.startsWith('http://') || link.startsWith('https://')) {
-    // 外部链接,在新标签页打开
-    window.open(link, '_blank');
-  } else {
-    // 内部路由链接,支持 query 参数和 state
-    router.push({
-      path: link,
-      query: query || {},
-      state,
-    });
-  }
-}
-
-watch(
-  () => ({
-    enable: preferences.app.watermark,
-    content: preferences.app.watermarkContent,
-    isDark: isDark.value,
-  }),
-  async ({ enable, content, isDark: isDarkValue }) => {
-    if (enable) {
-      const watermarkColor = isDarkValue
-        ? 'rgba(255, 255, 255, 0.12)'
-        : 'rgba(0, 0, 0, 0.12)';
-
-      await updateWatermark({
-        advancedStyle: {
-          colorStops: [
-            {
-              color: watermarkColor,
-              offset: 0,
-            },
-            {
-              color: watermarkColor,
-              offset: 1,
-            },
-          ],
-          type: 'linear',
-        },
-        content:
-          content ||
-          `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
-      });
-    } else {
-      destroyWatermark();
-    }
-  },
-  {
-    immediate: true,
-  },
-);
-</script>
-
-<template>
-  <BasicLayout @clear-preferences-and-logout="handleLogout">
-    <template #user-dropdown>
-      <UserDropdown
-        :avatar
-        :menus
-        :text="userStore.userInfo?.realName"
-        description="ann.vben@gmail.com"
-        tag-text="Pro"
-        @logout="handleLogout"
-        @clear-preferences-and-logout="handleLogout"
-      />
-    </template>
-    <template #notification>
-      <Notification
-        :dot="showDot"
-        :notifications="notifications"
-        @clear="handleNoticeClear"
-        @read="(item) => item.id && markRead(item.id)"
-        @remove="(item) => item.id && remove(item.id)"
-        @make-all="handleMakeAll"
-        @on-click="handleClick"
-        @view-all="viewAll"
-      />
-    </template>
-    <template #extra>
-      <AuthenticationLoginExpiredModal
-        v-model:open="accessStore.loginExpired"
-        :avatar
-      >
-        <LoginForm />
-      </AuthenticationLoginExpiredModal>
-    </template>
-    <template #lock-screen>
-      <LockScreen :avatar @to-login="handleLogout" />
-    </template>
-  </BasicLayout>
-</template>

+ 0 - 6
apps/web-antd/src/layouts/index.ts

@@ -1,6 +0,0 @@
-const BasicLayout = () => import('./basic.vue');
-const AuthPageLayout = () => import('./auth.vue');
-
-const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
-
-export { AuthPageLayout, BasicLayout, IFrameView };

+ 0 - 3
apps/web-antd/src/locales/README.md

@@ -1,3 +0,0 @@
-# locale
-
-每个app使用的国际化可能不同,这里用于扩展国际化的功能,例如扩展 dayjs、antd组件库的多语言切换,以及app本身的国际化文件。

+ 0 - 102
apps/web-antd/src/locales/index.ts

@@ -1,102 +0,0 @@
-import type { Locale } from 'ant-design-vue/es/locale';
-
-import type { App } from 'vue';
-
-import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
-
-import { ref } from 'vue';
-
-import {
-  $t,
-  setupI18n as coreSetup,
-  loadLocalesMapFromDir,
-} from '@vben/locales';
-import { preferences } from '@vben/preferences';
-
-import antdEnLocale from 'ant-design-vue/es/locale/en_US';
-import antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN';
-import dayjs from 'dayjs';
-
-const antdLocale = ref<Locale>(antdDefaultLocale);
-
-const modules = import.meta.glob('./langs/**/*.json');
-
-const localesMap = loadLocalesMapFromDir(
-  /\.\/langs\/([^/]+)\/(.*)\.json$/,
-  modules,
-);
-/**
- * 加载应用特有的语言包
- * 这里也可以改造为从服务端获取翻译数据
- * @param lang
- */
-async function loadMessages(lang: SupportedLanguagesType) {
-  const [appLocaleMessages] = await Promise.all([
-    localesMap[lang]?.(),
-    loadThirdPartyMessage(lang),
-  ]);
-  return appLocaleMessages?.default;
-}
-
-/**
- * 加载第三方组件库的语言包
- * @param lang
- */
-async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
-  await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);
-}
-
-/**
- * 加载dayjs的语言包
- * @param lang
- */
-async function loadDayjsLocale(lang: SupportedLanguagesType) {
-  let locale;
-  switch (lang) {
-    case 'en-US': {
-      locale = await import('dayjs/locale/en');
-      break;
-    }
-    case 'zh-CN': {
-      locale = await import('dayjs/locale/zh-cn');
-      break;
-    }
-    // 默认使用英语
-    default: {
-      locale = await import('dayjs/locale/en');
-    }
-  }
-  if (locale) {
-    dayjs.locale(locale);
-  } else {
-    console.error(`Failed to load dayjs locale for ${lang}`);
-  }
-}
-
-/**
- * 加载antd的语言包
- * @param lang
- */
-async function loadAntdLocale(lang: SupportedLanguagesType) {
-  switch (lang) {
-    case 'en-US': {
-      antdLocale.value = antdEnLocale;
-      break;
-    }
-    case 'zh-CN': {
-      antdLocale.value = antdDefaultLocale;
-      break;
-    }
-  }
-}
-
-async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
-  await coreSetup(app, {
-    defaultLocale: preferences.app.locale,
-    loadMessages,
-    missingWarn: !import.meta.env.PROD,
-    ...options,
-  });
-}
-
-export { $t, antdLocale, setupI18n };

+ 0 - 14
apps/web-antd/src/locales/langs/en-US/demos.json

@@ -1,14 +0,0 @@
-{
-  "title": "Demos",
-  "antd": "Ant Design Vue",
-  "vben": {
-    "title": "Project",
-    "about": "About",
-    "document": "Document",
-    "antdv": "Ant Design Vue Version",
-    "antdv-next": "Antdv Next Version",
-    "naive-ui": "Naive UI Version",
-    "element-plus": "Element Plus Version",
-    "tdesign": "TDesign Vue Version"
-  }
-}

+ 0 - 15
apps/web-antd/src/locales/langs/en-US/page.json

@@ -1,15 +0,0 @@
-{
-  "auth": {
-    "login": "Login",
-    "register": "Register",
-    "codeLogin": "Code Login",
-    "qrcodeLogin": "Qr Code Login",
-    "forgetPassword": "Forget Password",
-    "profile": "Profile"
-  },
-  "dashboard": {
-    "title": "Dashboard",
-    "analytics": "Analytics",
-    "workspace": "Workspace"
-  }
-}

+ 0 - 14
apps/web-antd/src/locales/langs/zh-CN/demos.json

@@ -1,14 +0,0 @@
-{
-  "title": "演示",
-  "antd": "Ant Design Vue",
-  "vben": {
-    "title": "项目",
-    "about": "关于",
-    "document": "文档",
-    "antdv": "Ant Design Vue 版本",
-    "antdv-next": "Antdv Next 版本",
-    "naive-ui": "Naive UI 版本",
-    "element-plus": "Element Plus 版本",
-    "tdesign": "TDesign Vue 版本"
-  }
-}

+ 0 - 15
apps/web-antd/src/locales/langs/zh-CN/page.json

@@ -1,15 +0,0 @@
-{
-  "auth": {
-    "login": "登录",
-    "register": "注册",
-    "codeLogin": "验证码登录",
-    "qrcodeLogin": "二维码登录",
-    "forgetPassword": "忘记密码",
-    "profile": "个人中心"
-  },
-  "dashboard": {
-    "title": "概览",
-    "analytics": "分析页",
-    "workspace": "工作台"
-  }
-}

+ 0 - 32
apps/web-antd/src/main.ts

@@ -1,32 +0,0 @@
-import { initPreferences } from '@vben/preferences';
-import { unmountGlobalLoading } from '@vben/utils';
-
-import { overridesPreferences, preferencesExtension } from './preferences';
-
-/**
- * 应用初始化完成之后再进行页面加载渲染
- */
-async function initApplication() {
-  // name用于指定项目唯一标识
-  // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据
-  const env = import.meta.env.PROD ? 'prod' : 'dev';
-  const appVersion = import.meta.env.VITE_APP_VERSION;
-  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;
-
-  // app偏好设置初始化
-  await initPreferences({
-    extension: preferencesExtension,
-    namespace,
-    overrides: overridesPreferences,
-  });
-
-  // 启动应用并挂载
-  // vue应用主要逻辑及视图
-  const { bootstrap } = await import('./bootstrap');
-  await bootstrap(namespace);
-
-  // 移除并销毁loading
-  unmountGlobalLoading();
-}
-
-initApplication();

+ 0 - 72
apps/web-antd/src/preferences.ts

@@ -1,72 +0,0 @@
-import {
-  defineOverridesPreferences,
-  definePreferencesExtension,
-} from '@vben/preferences';
-
-interface WebAntdPreferencesExtension {
-  defaultTableSize: number;
-  enableFormFullscreen: boolean;
-  reportTitle: string;
-  tenantMode: 'multi' | 'single';
-}
-
-/**
- * @description 项目配置文件
- * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置
- * !!! 更改配置后请清空缓存,否则可能不生效
- */
-export const overridesPreferences = defineOverridesPreferences({
-  // overrides
-  app: {
-    name: import.meta.env.VITE_APP_TITLE,
-  },
-});
-
-export const preferencesExtension =
-  definePreferencesExtension<WebAntdPreferencesExtension>({
-    tabLabel: 'preferences.antd.tabLabel',
-    title: 'preferences.antd.title',
-    fields: [
-      {
-        component: 'switch',
-        defaultValue: true,
-        key: 'enableFormFullscreen',
-        label: 'preferences.antd.fields.enableFormFullscreen.label',
-        tip: 'preferences.antd.fields.enableFormFullscreen.tip',
-      },
-      {
-        component: 'select',
-        defaultValue: 'single',
-        key: 'tenantMode',
-        label: 'preferences.antd.fields.tenantMode.label',
-        options: [
-          {
-            label: 'preferences.antd.fields.tenantMode.options.single.label',
-            value: 'single',
-          },
-          {
-            label: 'preferences.antd.fields.tenantMode.options.multi.label',
-            value: 'multi',
-          },
-        ],
-      },
-      {
-        component: 'number',
-        componentProps: {
-          max: 200,
-          min: 10,
-          step: 10,
-        },
-        defaultValue: 20,
-        key: 'defaultTableSize',
-        label: 'preferences.antd.fields.defaultTableSize.label',
-      },
-      {
-        component: 'input',
-        defaultValue: '',
-        key: 'reportTitle',
-        label: 'preferences.antd.fields.reportTitle.label',
-        placeholder: 'preferences.antd.fields.reportTitle.placeholder',
-      },
-    ],
-  });

+ 0 - 42
apps/web-antd/src/router/access.ts

@@ -1,42 +0,0 @@
-import type {
-  ComponentRecordType,
-  GenerateMenuAndRoutesOptions,
-} from '@vben/types';
-
-import { generateAccessible } from '@vben/access';
-import { preferences } from '@vben/preferences';
-
-import { message } from 'ant-design-vue';
-
-import { getAllMenusApi } from '#/api';
-import { BasicLayout, IFrameView } from '#/layouts';
-import { $t } from '#/locales';
-
-const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
-
-async function generateAccess(options: GenerateMenuAndRoutesOptions) {
-  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
-
-  const layoutMap: ComponentRecordType = {
-    BasicLayout,
-    IFrameView,
-  };
-
-  return await generateAccessible(preferences.app.accessMode, {
-    ...options,
-    fetchMenuListAsync: async () => {
-      message.loading({
-        content: `${$t('common.loadingMenu')}...`,
-        duration: 1.5,
-      });
-      return await getAllMenusApi();
-    },
-    // 可以指定没有权限跳转403页面
-    forbiddenComponent,
-    // 如果 route.meta.menuVisibleWithForbidden = true
-    layoutMap,
-    pageMap,
-  });
-}
-
-export { generateAccess };

+ 0 - 133
apps/web-antd/src/router/guard.ts

@@ -1,133 +0,0 @@
-import type { Router } from 'vue-router';
-
-import { LOGIN_PATH } from '@vben/constants';
-import { preferences } from '@vben/preferences';
-import { useAccessStore, useUserStore } from '@vben/stores';
-import { startProgress, stopProgress } from '@vben/utils';
-
-import { accessRoutes, coreRouteNames } from '#/router/routes';
-import { useAuthStore } from '#/store';
-
-import { generateAccess } from './access';
-
-/**
- * 通用守卫配置
- * @param router
- */
-function setupCommonGuard(router: Router) {
-  // 记录已经加载的页面
-  const loadedPaths = new Set<string>();
-
-  router.beforeEach((to) => {
-    to.meta.loaded = loadedPaths.has(to.path);
-
-    // 页面加载进度条
-    if (!to.meta.loaded && preferences.transition.progress) {
-      startProgress();
-    }
-    return true;
-  });
-
-  router.afterEach((to) => {
-    // 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
-
-    loadedPaths.add(to.path);
-
-    // 关闭页面加载进度条
-    if (preferences.transition.progress) {
-      stopProgress();
-    }
-  });
-}
-
-/**
- * 权限访问守卫配置
- * @param router
- */
-function setupAccessGuard(router: Router) {
-  router.beforeEach(async (to, from) => {
-    const accessStore = useAccessStore();
-    const userStore = useUserStore();
-    const authStore = useAuthStore();
-
-    // 基本路由,这些路由不需要进入权限拦截
-    if (coreRouteNames.includes(to.name as string)) {
-      if (to.path === LOGIN_PATH && accessStore.accessToken) {
-        return decodeURIComponent(
-          (to.query?.redirect as string) ||
-            userStore.userInfo?.homePath ||
-            preferences.app.defaultHomePath,
-        );
-      }
-      return true;
-    }
-
-    // accessToken 检查
-    if (!accessStore.accessToken) {
-      // 明确声明忽略权限访问权限,则可以访问
-      if (to.meta.ignoreAccess) {
-        return true;
-      }
-
-      // 没有访问权限,跳转登录页面
-      if (to.fullPath !== LOGIN_PATH) {
-        return {
-          path: LOGIN_PATH,
-          // 如不需要,直接删除 query
-          query:
-            to.fullPath === preferences.app.defaultHomePath
-              ? {}
-              : { redirect: encodeURIComponent(to.fullPath) },
-          // 携带当前跳转的页面,登录后重新跳转该页面
-          replace: true,
-        };
-      }
-      return to;
-    }
-
-    // 是否已经生成过动态路由
-    if (accessStore.isAccessChecked) {
-      return true;
-    }
-
-    // 生成路由表
-    // 当前登录用户拥有的角色标识列表
-    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
-    const userRoles = userInfo.roles ?? [];
-
-    // 生成菜单和路由
-    const { accessibleMenus, accessibleRoutes } = await generateAccess({
-      roles: userRoles,
-      router,
-      // 则会在菜单中显示,但是访问会被重定向到403
-      routes: accessRoutes,
-    });
-
-    // 保存菜单信息和路由信息
-    accessStore.setAccessMenus(accessibleMenus);
-    accessStore.setAccessRoutes(accessibleRoutes);
-    accessStore.setIsAccessChecked(true);
-    const redirectPath = (from.query.redirect ??
-      (to.path === preferences.app.defaultHomePath
-        ? userInfo.homePath || preferences.app.defaultHomePath
-        : to.fullPath)) as string;
-
-    return {
-      ...router.resolve(decodeURIComponent(redirectPath)),
-      replace: true,
-    };
-  });
-}
-
-/**
- * 项目守卫配置
- * @param router
- */
-function createRouterGuard(router: Router) {
-  /** 通用 */
-  setupCommonGuard(router);
-  /** 权限访问 */
-  setupAccessGuard(router);
-}
-
-export { createRouterGuard };

+ 0 - 37
apps/web-antd/src/router/index.ts

@@ -1,37 +0,0 @@
-import {
-  createRouter,
-  createWebHashHistory,
-  createWebHistory,
-} from 'vue-router';
-
-import { resetStaticRoutes } from '@vben/utils';
-
-import { createRouterGuard } from './guard';
-import { routes } from './routes';
-
-/**
- *  @zh_CN 创建vue-router实例
- */
-const router = createRouter({
-  history:
-    import.meta.env.VITE_ROUTER_HISTORY === 'hash'
-      ? createWebHashHistory(import.meta.env.VITE_BASE)
-      : createWebHistory(import.meta.env.VITE_BASE),
-  // 应该添加到路由的初始路由列表。
-  routes,
-  scrollBehavior: (to, _from, savedPosition) => {
-    if (savedPosition) {
-      return savedPosition;
-    }
-    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };
-  },
-  // 是否应该禁止尾部斜杠。
-  // strict: true,
-});
-
-const resetRoutes = () => resetStaticRoutes(router, routes);
-
-// 创建路由守卫
-createRouterGuard(router);
-
-export { resetRoutes, router };

+ 0 - 97
apps/web-antd/src/router/routes/core.ts

@@ -1,97 +0,0 @@
-import type { RouteRecordRaw } from 'vue-router';
-
-import { LOGIN_PATH } from '@vben/constants';
-import { preferences } from '@vben/preferences';
-
-import { $t } from '#/locales';
-
-const BasicLayout = () => import('#/layouts/basic.vue');
-const AuthPageLayout = () => import('#/layouts/auth.vue');
-/** 全局404页面 */
-const fallbackNotFoundRoute: RouteRecordRaw = {
-  component: () => import('#/views/_core/fallback/not-found.vue'),
-  meta: {
-    hideInBreadcrumb: true,
-    hideInMenu: true,
-    hideInTab: true,
-    title: '404',
-  },
-  name: 'FallbackNotFound',
-  path: '/:path(.*)*',
-};
-
-/** 基本路由,这些路由是必须存在的 */
-const coreRoutes: RouteRecordRaw[] = [
-  /**
-   * 根路由
-   * 使用基础布局,作为所有页面的父级容器,子级就不必配置BasicLayout。
-   * 此路由必须存在,且不应修改
-   */
-  {
-    component: BasicLayout,
-    meta: {
-      hideInBreadcrumb: true,
-      title: 'Root',
-    },
-    name: 'Root',
-    path: '/',
-    redirect: preferences.app.defaultHomePath,
-    children: [],
-  },
-  {
-    component: AuthPageLayout,
-    meta: {
-      hideInTab: true,
-      title: 'Authentication',
-    },
-    name: 'Authentication',
-    path: '/auth',
-    redirect: LOGIN_PATH,
-    children: [
-      {
-        name: 'Login',
-        path: 'login',
-        component: () => import('#/views/_core/authentication/login.vue'),
-        meta: {
-          title: $t('page.auth.login'),
-        },
-      },
-      {
-        name: 'CodeLogin',
-        path: 'code-login',
-        component: () => import('#/views/_core/authentication/code-login.vue'),
-        meta: {
-          title: $t('page.auth.codeLogin'),
-        },
-      },
-      {
-        name: 'QrCodeLogin',
-        path: 'qrcode-login',
-        component: () =>
-          import('#/views/_core/authentication/qrcode-login.vue'),
-        meta: {
-          title: $t('page.auth.qrcodeLogin'),
-        },
-      },
-      {
-        name: 'ForgetPassword',
-        path: 'forget-password',
-        component: () =>
-          import('#/views/_core/authentication/forget-password.vue'),
-        meta: {
-          title: $t('page.auth.forgetPassword'),
-        },
-      },
-      {
-        name: 'Register',
-        path: 'register',
-        component: () => import('#/views/_core/authentication/register.vue'),
-        meta: {
-          title: $t('page.auth.register'),
-        },
-      },
-    ],
-  },
-];
-
-export { coreRoutes, fallbackNotFoundRoute };

+ 0 - 37
apps/web-antd/src/router/routes/index.ts

@@ -1,37 +0,0 @@
-import type { RouteRecordRaw } from 'vue-router';
-
-import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
-
-import { coreRoutes, fallbackNotFoundRoute } from './core';
-
-const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
-  eager: true,
-});
-
-// 有需要可以自行打开注释,并创建文件夹
-// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
-// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });
-
-/** 动态路由 */
-const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
-
-/** 外部路由列表,访问这些页面可以不需要Layout,可能用于内嵌在别的系统(不会显示在菜单中) */
-// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
-// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);
-const staticRoutes: RouteRecordRaw[] = [];
-const externalRoutes: RouteRecordRaw[] = [];
-
-/** 路由列表,由基本路由、外部路由和404兜底路由组成
- *  无需走权限验证(会一直显示在菜单中) */
-const routes: RouteRecordRaw[] = [
-  ...coreRoutes,
-  ...externalRoutes,
-  fallbackNotFoundRoute,
-];
-
-/** 基本路由列表,这些路由不需要进入权限拦截 */
-const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
-
-/** 有权限校验的路由列表,包含动态路由和静态路由 */
-const accessRoutes = [...dynamicRoutes, ...staticRoutes];
-export { accessRoutes, coreRouteNames, routes };

+ 0 - 38
apps/web-antd/src/router/routes/modules/dashboard.ts

@@ -1,38 +0,0 @@
-import type { RouteRecordRaw } from 'vue-router';
-
-import { $t } from '#/locales';
-
-const routes: RouteRecordRaw[] = [
-  {
-    meta: {
-      icon: 'lucide:layout-dashboard',
-      order: -1,
-      title: $t('page.dashboard.title'),
-    },
-    name: 'Dashboard',
-    path: '/dashboard',
-    children: [
-      {
-        name: 'Analytics',
-        path: '/analytics',
-        component: () => import('#/views/dashboard/analytics/index.vue'),
-        meta: {
-          affixTab: true,
-          icon: 'lucide:area-chart',
-          title: $t('page.dashboard.analytics'),
-        },
-      },
-      {
-        name: 'Workspace',
-        path: '/workspace',
-        component: () => import('#/views/dashboard/workspace/index.vue'),
-        meta: {
-          icon: 'carbon:workspace',
-          title: $t('page.dashboard.workspace'),
-        },
-      },
-    ],
-  },
-];
-
-export default routes;

+ 0 - 28
apps/web-antd/src/router/routes/modules/demos.ts

@@ -1,28 +0,0 @@
-import type { RouteRecordRaw } from 'vue-router';
-
-import { $t } from '#/locales';
-
-const routes: RouteRecordRaw[] = [
-  {
-    meta: {
-      icon: 'ic:baseline-view-in-ar',
-      keepAlive: true,
-      order: 1000,
-      title: $t('demos.title'),
-    },
-    name: 'Demos',
-    path: '/demos',
-    children: [
-      {
-        meta: {
-          title: $t('demos.antd'),
-        },
-        name: 'AntDesignDemos',
-        path: '/demos/ant-design',
-        component: () => import('#/views/demos/antd/index.vue'),
-      },
-    ],
-  },
-];
-
-export default routes;

+ 0 - 116
apps/web-antd/src/router/routes/modules/vben.ts

@@ -1,116 +0,0 @@
-import type { RouteRecordRaw } from 'vue-router';
-
-import {
-  VBEN_ANTDV_NEXT_PREVIEW_URL,
-  VBEN_DOC_URL,
-  VBEN_ELE_PREVIEW_URL,
-  VBEN_GITHUB_URL,
-  VBEN_LOGO_URL,
-  VBEN_NAIVE_PREVIEW_URL,
-  VBEN_TD_PREVIEW_URL,
-} from '@vben/constants';
-import { SvgAntdvNextLogoIcon, SvgTDesignIcon } from '@vben/icons';
-
-import { IFrameView } from '#/layouts';
-import { $t } from '#/locales';
-
-const routes: RouteRecordRaw[] = [
-  {
-    meta: {
-      badgeType: 'dot',
-      icon: VBEN_LOGO_URL,
-      order: 9998,
-      title: $t('demos.vben.title'),
-    },
-    name: 'VbenProject',
-    path: '/vben-admin',
-    children: [
-      {
-        name: 'VbenDocument',
-        path: '/vben-admin/document',
-        component: IFrameView,
-        meta: {
-          icon: 'lucide:book-open-text',
-          link: VBEN_DOC_URL,
-          title: $t('demos.vben.document'),
-        },
-      },
-      {
-        name: 'VbenGithub',
-        path: '/vben-admin/github',
-        component: IFrameView,
-        meta: {
-          icon: 'mdi:github',
-          link: VBEN_GITHUB_URL,
-          title: 'Github',
-        },
-      },
-      {
-        name: 'VbenAntdVNext',
-        path: '/vben-admin/antdv-next',
-        component: IFrameView,
-        meta: {
-          badgeType: 'dot',
-          icon: SvgAntdvNextLogoIcon,
-          link: VBEN_ANTDV_NEXT_PREVIEW_URL,
-          title: $t('demos.vben.antdv-next'),
-        },
-      },
-      {
-        name: 'VbenNaive',
-        path: '/vben-admin/naive',
-        component: IFrameView,
-        meta: {
-          badgeType: 'dot',
-          icon: 'logos:naiveui',
-          link: VBEN_NAIVE_PREVIEW_URL,
-          title: $t('demos.vben.naive-ui'),
-        },
-      },
-      {
-        name: 'VbenTDesign',
-        path: '/vben-admin/tdesign',
-        component: IFrameView,
-        meta: {
-          badgeType: 'dot',
-          icon: SvgTDesignIcon,
-          link: VBEN_TD_PREVIEW_URL,
-          title: $t('demos.vben.tdesign'),
-        },
-      },
-      {
-        name: 'VbenElementPlus',
-        path: '/vben-admin/ele',
-        component: IFrameView,
-        meta: {
-          badgeType: 'dot',
-          icon: 'logos:element',
-          link: VBEN_ELE_PREVIEW_URL,
-          title: $t('demos.vben.element-plus'),
-        },
-      },
-    ],
-  },
-  {
-    name: 'VbenAbout',
-    path: '/vben-admin/about',
-    component: () => import('#/views/_core/about/index.vue'),
-    meta: {
-      icon: 'lucide:copyright',
-      title: $t('demos.vben.about'),
-      order: 9999,
-    },
-  },
-  {
-    name: 'Profile',
-    path: '/profile',
-    component: () => import('#/views/_core/profile/index.vue'),
-    meta: {
-      icon: 'lucide:user',
-      hideInMenu: true,
-      title: $t('page.auth.profile'),
-    },
-  },
-];
-
-export default routes;

+ 0 - 117
apps/web-antd/src/store/auth.ts

@@ -1,117 +0,0 @@
-import type { Recordable, UserInfo } from '@vben/types';
-
-import { ref } from 'vue';
-import { useRouter } from 'vue-router';
-
-import { LOGIN_PATH } from '@vben/constants';
-import { preferences } from '@vben/preferences';
-import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
-
-import { notification } from 'ant-design-vue';
-import { defineStore } from 'pinia';
-
-import { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';
-import { $t } from '#/locales';
-
-export const useAuthStore = defineStore('auth', () => {
-  const accessStore = useAccessStore();
-  const userStore = useUserStore();
-  const router = useRouter();
-
-  const loginLoading = ref(false);
-
-  /**
-   * 异步处理登录操作
-   * Asynchronously handle the login process
-   * @param params 登录表单数据
-   */
-  async function authLogin(
-    params: Recordable<any>,
-    onSuccess?: () => Promise<void> | void,
-  ) {
-    // 异步处理用户登录操作并获取 accessToken
-    let userInfo: null | UserInfo = null;
-    try {
-      loginLoading.value = true;
-      const { accessToken } = await loginApi(params);
-
-      // 如果成功获取到 accessToken
-      if (accessToken) {
-        accessStore.setAccessToken(accessToken);
-
-        // 获取用户信息并存储到 accessStore 中
-        const [fetchUserInfoResult, accessCodes] = await Promise.all([
-          fetchUserInfo(),
-          getAccessCodesApi(),
-        ]);
-
-        userInfo = fetchUserInfoResult;
-
-        userStore.setUserInfo(userInfo);
-        accessStore.setAccessCodes(accessCodes);
-
-        if (accessStore.loginExpired) {
-          accessStore.setLoginExpired(false);
-        } else {
-          onSuccess
-            ? await onSuccess?.()
-            : await router.push(
-                userInfo.homePath || preferences.app.defaultHomePath,
-              );
-        }
-
-        if (userInfo?.realName) {
-          notification.success({
-            description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
-            duration: 3,
-            message: $t('authentication.loginSuccess'),
-          });
-        }
-      }
-    } finally {
-      loginLoading.value = false;
-    }
-
-    return {
-      userInfo,
-    };
-  }
-
-  async function logout(redirect: boolean = true) {
-    try {
-      await logoutApi();
-    } catch {
-      // 不做任何处理
-    }
-    resetAllStores();
-    accessStore.setLoginExpired(false);
-
-    // 回登录页带上当前路由地址
-    await router.replace({
-      path: LOGIN_PATH,
-      query: redirect
-        ? {
-            redirect: encodeURIComponent(router.currentRoute.value.fullPath),
-          }
-        : {},
-    });
-  }
-
-  async function fetchUserInfo() {
-    const userInfo = await getUserInfoApi();
-    userStore.setUserInfo(userInfo);
-    return userInfo;
-  }
-
-  function $reset() {
-    loginLoading.value = false;
-  }
-
-  return {
-    $reset,
-    authLogin,
-    fetchUserInfo,
-    loginLoading,
-    logout,
-  };
-});

+ 0 - 1
apps/web-antd/src/store/index.ts

@@ -1 +0,0 @@
-export * from './auth';

+ 0 - 3
apps/web-antd/src/views/_core/README.md

@@ -1,3 +0,0 @@
-# \_core
-
-此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。

+ 0 - 9
apps/web-antd/src/views/_core/about/index.vue

@@ -1,9 +0,0 @@
-<script lang="ts" setup>
-import { About } from '@vben/common-ui';
-
-defineOptions({ name: 'About' });
-</script>
-
-<template>
-  <About />
-</template>

+ 0 - 68
apps/web-antd/src/views/_core/authentication/code-login.vue

@@ -1,68 +0,0 @@
-<script lang="ts" setup>
-import type { VbenFormSchema } from '@vben/common-ui';
-import type { Recordable } from '@vben/types';
-
-import { computed, ref } from 'vue';
-
-import { AuthenticationCodeLogin, z } from '@vben/common-ui';
-import { $t } from '@vben/locales';
-
-defineOptions({ name: 'CodeLogin' });
-
-const loading = ref(false);
-const CODE_LENGTH = 6;
-
-const formSchema = computed((): VbenFormSchema[] => {
-  return [
-    {
-      component: 'VbenInput',
-      componentProps: {
-        placeholder: $t('authentication.mobile'),
-      },
-      fieldName: 'phoneNumber',
-      label: $t('authentication.mobile'),
-      rules: z
-        .string()
-        .min(1, { message: $t('authentication.mobileTip') })
-        .refine((v) => /^\d{11}$/.test(v), {
-          message: $t('authentication.mobileErrortip'),
-        }),
-    },
-    {
-      component: 'VbenPinInput',
-      componentProps: {
-        codeLength: CODE_LENGTH,
-        createText: (countdown: number) => {
-          const text =
-            countdown > 0
-              ? $t('authentication.sendText', [countdown])
-              : $t('authentication.sendCode');
-          return text;
-        },
-        placeholder: $t('authentication.code'),
-      },
-      fieldName: 'code',
-      label: $t('authentication.code'),
-      rules: z.string().length(CODE_LENGTH, {
-        message: $t('authentication.codeTip', [CODE_LENGTH]),
-      }),
-    },
-  ];
-});
-/**
- * 异步处理登录操作
- * Asynchronously handle the login process
- * @param values 登录表单数据
- */
-async function handleLogin(values: Recordable<any>) {
-  void values;
-}
-</script>
-
-<template>
-  <AuthenticationCodeLogin
-    :form-schema="formSchema"
-    :loading="loading"
-    @submit="handleLogin"
-  />
-</template>

+ 0 - 42
apps/web-antd/src/views/_core/authentication/forget-password.vue

@@ -1,42 +0,0 @@
-<script lang="ts" setup>
-import type { VbenFormSchema } from '@vben/common-ui';
-import type { Recordable } from '@vben/types';
-
-import { computed, ref } from 'vue';
-
-import { AuthenticationForgetPassword, z } from '@vben/common-ui';
-import { $t } from '@vben/locales';
-
-defineOptions({ name: 'ForgetPassword' });
-
-const loading = ref(false);
-
-const formSchema = computed((): VbenFormSchema[] => {
-  return [
-    {
-      component: 'VbenInput',
-      componentProps: {
-        placeholder: 'example@example.com',
-      },
-      fieldName: 'email',
-      label: $t('authentication.email'),
-      rules: z
-        .string()
-        .min(1, { message: $t('authentication.emailTip') })
-        .email($t('authentication.emailValidErrorTip')),
-    },
-  ];
-});
-
-function handleSubmit(value: Recordable<any>) {
-  void value;
-}
-</script>
-
-<template>
-  <AuthenticationForgetPassword
-    :form-schema="formSchema"
-    :loading="loading"
-    @submit="handleSubmit"
-  />
-</template>

+ 0 - 98
apps/web-antd/src/views/_core/authentication/login.vue

@@ -1,98 +0,0 @@
-<script lang="ts" setup>
-import type { VbenFormSchema } from '@vben/common-ui';
-import type { BasicOption } from '@vben/types';
-
-import { computed, markRaw } from 'vue';
-
-import { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';
-import { $t } from '@vben/locales';
-
-import { useAuthStore } from '#/store';
-
-defineOptions({ name: 'Login' });
-
-const authStore = useAuthStore();
-
-const MOCK_USER_OPTIONS: BasicOption[] = [
-  {
-    label: 'Super',
-    value: 'vben',
-  },
-  {
-    label: 'Admin',
-    value: 'admin',
-  },
-  {
-    label: 'User',
-    value: 'jack',
-  },
-];
-
-const formSchema = computed((): VbenFormSchema[] => {
-  return [
-    {
-      component: 'VbenSelect',
-      componentProps: {
-        options: MOCK_USER_OPTIONS,
-        placeholder: $t('authentication.selectAccount'),
-      },
-      fieldName: 'selectAccount',
-      label: $t('authentication.selectAccount'),
-      rules: z
-        .string()
-        .min(1, { message: $t('authentication.selectAccount') })
-        .optional()
-        .default('vben'),
-    },
-    {
-      component: 'VbenInput',
-      componentProps: {
-        placeholder: $t('authentication.usernameTip'),
-      },
-      dependencies: {
-        trigger(values, form) {
-          if (values.selectAccount) {
-            const findUser = MOCK_USER_OPTIONS.find(
-              (item) => item.value === values.selectAccount,
-            );
-            if (findUser) {
-              form.setValues({
-                password: '123456',
-                username: findUser.value,
-              });
-            }
-          }
-        },
-        triggerFields: ['selectAccount'],
-      },
-      fieldName: 'username',
-      label: $t('authentication.username'),
-      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
-    },
-    {
-      component: 'VbenInputPassword',
-      componentProps: {
-        placeholder: $t('authentication.password'),
-      },
-      fieldName: 'password',
-      label: $t('authentication.password'),
-      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
-    },
-    {
-      component: markRaw(SliderCaptcha),
-      fieldName: 'captcha',
-      rules: z.boolean().refine((value) => value, {
-        message: $t('authentication.verifyRequiredTip'),
-      }),
-    },
-  ];
-});
-</script>
-
-<template>
-  <AuthenticationLogin
-    :form-schema="formSchema"
-    :loading="authStore.loginLoading"
-    @submit="authStore.authLogin"
-  />
-</template>

+ 0 - 10
apps/web-antd/src/views/_core/authentication/qrcode-login.vue

@@ -1,10 +0,0 @@
-<script lang="ts" setup>
-import { AuthenticationQrCodeLogin } from '@vben/common-ui';
-import { LOGIN_PATH } from '@vben/constants';
-
-defineOptions({ name: 'QrCodeLogin' });
-</script>
-
-<template>
-  <AuthenticationQrCodeLogin :login-path="LOGIN_PATH" />
-</template>

+ 0 - 95
apps/web-antd/src/views/_core/authentication/register.vue

@@ -1,95 +0,0 @@
-<script lang="ts" setup>
-import type { VbenFormSchema } from '@vben/common-ui';
-import type { Recordable } from '@vben/types';
-
-import { computed, h, ref } from 'vue';
-
-import { AuthenticationRegister, z } from '@vben/common-ui';
-import { $t } from '@vben/locales';
-
-defineOptions({ name: 'Register' });
-
-const loading = ref(false);
-
-const formSchema = computed((): VbenFormSchema[] => {
-  return [
-    {
-      component: 'VbenInput',
-      componentProps: {
-        placeholder: $t('authentication.usernameTip'),
-      },
-      fieldName: 'username',
-      label: $t('authentication.username'),
-      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
-    },
-    {
-      component: 'VbenInputPassword',
-      componentProps: {
-        passwordStrength: true,
-        placeholder: $t('authentication.password'),
-      },
-      fieldName: 'password',
-      label: $t('authentication.password'),
-      renderComponentContent() {
-        return {
-          strengthText: () => $t('authentication.passwordStrength'),
-        };
-      },
-      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
-    },
-    {
-      component: 'VbenInputPassword',
-      componentProps: {
-        placeholder: $t('authentication.confirmPassword'),
-      },
-      dependencies: {
-        rules(values) {
-          const { password } = values;
-          return z
-            .string({ required_error: $t('authentication.passwordTip') })
-            .min(1, { message: $t('authentication.passwordTip') })
-            .refine((value) => value === password, {
-              message: $t('authentication.confirmPasswordTip'),
-            });
-        },
-        triggerFields: ['password'],
-      },
-      fieldName: 'confirmPassword',
-      label: $t('authentication.confirmPassword'),
-    },
-    {
-      component: 'VbenCheckbox',
-      fieldName: 'agreePolicy',
-      renderComponentContent: () => ({
-        default: () =>
-          h('span', [
-            $t('authentication.agree'),
-            h(
-              'a',
-              {
-                class: 'vben-link ml-1 ',
-                href: '',
-              },
-              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,
-            ),
-          ]),
-      }),
-      rules: z.boolean().refine((value) => !!value, {
-        message: $t('authentication.agreeTip'),
-      }),
-    },
-  ];
-});
-
-function handleSubmit(value: Recordable<any>) {
-  void value;
-}
-</script>
-
-<template>
-  <AuthenticationRegister
-    :form-schema="formSchema"
-    :loading="loading"
-    @submit="handleSubmit"
-  />
-</template>

+ 0 - 7
apps/web-antd/src/views/_core/fallback/coming-soon.vue

@@ -1,7 +0,0 @@
-<script lang="ts" setup>
-import { Fallback } from '@vben/common-ui';
-</script>
-
-<template>
-  <Fallback status="coming-soon" />
-</template>

+ 0 - 9
apps/web-antd/src/views/_core/fallback/forbidden.vue

@@ -1,9 +0,0 @@
-<script lang="ts" setup>
-import { Fallback } from '@vben/common-ui';
-
-defineOptions({ name: 'Fallback403Demo' });
-</script>
-
-<template>
-  <Fallback status="403" />
-</template>

+ 0 - 9
apps/web-antd/src/views/_core/fallback/internal-error.vue

@@ -1,9 +0,0 @@
-<script lang="ts" setup>
-import { Fallback } from '@vben/common-ui';
-
-defineOptions({ name: 'Fallback500Demo' });
-</script>
-
-<template>
-  <Fallback status="500" />
-</template>

+ 0 - 9
apps/web-antd/src/views/_core/fallback/not-found.vue

@@ -1,9 +0,0 @@
-<script lang="ts" setup>
-import { Fallback } from '@vben/common-ui';
-
-defineOptions({ name: 'Fallback404Demo' });
-</script>
-
-<template>
-  <Fallback status="404" />
-</template>

+ 0 - 9
apps/web-antd/src/views/_core/fallback/offline.vue

@@ -1,9 +0,0 @@
-<script lang="ts" setup>
-import { Fallback } from '@vben/common-ui';
-
-defineOptions({ name: 'FallbackOfflineDemo' });
-</script>
-
-<template>
-  <Fallback status="offline" />
-</template>

+ 0 - 65
apps/web-antd/src/views/_core/profile/base-setting.vue

@@ -1,65 +0,0 @@
-<script setup lang="ts">
-import type { BasicOption } from '@vben/types';
-
-import type { VbenFormSchema } from '#/adapter/form';
-
-import { computed, onMounted, ref } from 'vue';
-
-import { ProfileBaseSetting } from '@vben/common-ui';
-
-import { getUserInfoApi } from '#/api';
-
-const profileBaseSettingRef = ref();
-
-const MOCK_ROLES_OPTIONS: BasicOption[] = [
-  {
-    label: '管理员',
-    value: 'super',
-  },
-  {
-    label: '用户',
-    value: 'user',
-  },
-  {
-    label: '测试',
-    value: 'test',
-  },
-];
-
-const formSchema = computed((): VbenFormSchema[] => {
-  return [
-    {
-      fieldName: 'realName',
-      component: 'Input',
-      label: '姓名',
-    },
-    {
-      fieldName: 'username',
-      component: 'Input',
-      label: '用户名',
-    },
-    {
-      fieldName: 'roles',
-      component: 'Select',
-      componentProps: {
-        mode: 'tags',
-        options: MOCK_ROLES_OPTIONS,
-      },
-      label: '角色',
-    },
-    {
-      fieldName: 'introduction',
-      component: 'Textarea',
-      label: '个人简介',
-    },
-  ];
-});
-
-onMounted(async () => {
-  const data = await getUserInfoApi();
-  profileBaseSettingRef.value.getFormApi().setValues(data);
-});
-</script>
-<template>
-  <ProfileBaseSetting ref="profileBaseSettingRef" :form-schema="formSchema" />
-</template>

+ 0 - 49
apps/web-antd/src/views/_core/profile/index.vue

@@ -1,49 +0,0 @@
-<script setup lang="ts">
-import { ref } from 'vue';
-
-import { Profile } from '@vben/common-ui';
-import { useUserStore } from '@vben/stores';
-
-import ProfileBase from './base-setting.vue';
-import ProfileNotificationSetting from './notification-setting.vue';
-import ProfilePasswordSetting from './password-setting.vue';
-import ProfileSecuritySetting from './security-setting.vue';
-
-const userStore = useUserStore();
-
-const tabsValue = ref<string>('basic');
-
-const tabs = ref([
-  {
-    label: '基本设置',
-    value: 'basic',
-  },
-  {
-    label: '安全设置',
-    value: 'security',
-  },
-  {
-    label: '修改密码',
-    value: 'password',
-  },
-  {
-    label: '新消息提醒',
-    value: 'notice',
-  },
-]);
-</script>
-<template>
-  <Profile
-    v-model:model-value="tabsValue"
-    title="个人中心"
-    :user-info="userStore.userInfo"
-    :tabs="tabs"
-  >
-    <template #content>
-      <ProfileBase v-if="tabsValue === 'basic'" />
-      <ProfileSecuritySetting v-if="tabsValue === 'security'" />
-      <ProfilePasswordSetting v-if="tabsValue === 'password'" />
-      <ProfileNotificationSetting v-if="tabsValue === 'notice'" />
-    </template>
-  </Profile>
-</template>

+ 0 - 31
apps/web-antd/src/views/_core/profile/notification-setting.vue

@@ -1,31 +0,0 @@
-<script setup lang="ts">
-import { computed } from 'vue';
-
-import { ProfileNotificationSetting } from '@vben/common-ui';
-
-const formSchema = computed(() => {
-  return [
-    {
-      value: true,
-      fieldName: 'accountPassword',
-      label: '账户密码',
-      description: '其他用户的消息将以站内信的形式通知',
-    },
-    {
-      value: true,
-      fieldName: 'systemMessage',
-      label: '系统消息',
-      description: '系统消息将以站内信的形式通知',
-    },
-    {
-      value: true,
-      fieldName: 'todoTask',
-      label: '待办任务',
-      description: '待办任务将以站内信的形式通知',
-    },
-  ];
-});
-</script>
-<template>
-  <ProfileNotificationSetting :form-schema="formSchema" />
-</template>

+ 0 - 63
apps/web-antd/src/views/_core/profile/password-setting.vue

@@ -1,63 +0,0 @@
-<script setup lang="ts">
-import type { VbenFormSchema } from '#/adapter/form';
-
-import { computed } from 'vue';
-
-import { ProfilePasswordSetting, z } from '@vben/common-ui';
-
-import { message } from 'ant-design-vue';
-
-const formSchema = computed((): VbenFormSchema[] => {
-  return [
-    {
-      fieldName: 'oldPassword',
-      label: '旧密码',
-      component: 'VbenInputPassword',
-      componentProps: {
-        placeholder: '请输入旧密码',
-      },
-    },
-    {
-      fieldName: 'newPassword',
-      label: '新密码',
-      component: 'VbenInputPassword',
-      componentProps: {
-        passwordStrength: true,
-        placeholder: '请输入新密码',
-      },
-    },
-    {
-      fieldName: 'confirmPassword',
-      label: '确认密码',
-      component: 'VbenInputPassword',
-      componentProps: {
-        passwordStrength: true,
-        placeholder: '请再次输入新密码',
-      },
-      dependencies: {
-        rules(values) {
-          const { newPassword } = values;
-          return z
-            .string({ required_error: '请再次输入新密码' })
-            .min(1, { message: '请再次输入新密码' })
-            .refine((value) => value === newPassword, {
-              message: '两次输入的密码不一致',
-            });
-        },
-        triggerFields: ['newPassword'],
-      },
-    },
-  ];
-});
-
-function handleSubmit() {
-  message.success('密码修改成功');
-}
-</script>
-<template>
-  <ProfilePasswordSetting
-    class="w-1/3"
-    :form-schema="formSchema"
-    @submit="handleSubmit"
-  />
-</template>

+ 0 - 43
apps/web-antd/src/views/_core/profile/security-setting.vue

@@ -1,43 +0,0 @@
-<script setup lang="ts">
-import { computed } from 'vue';
-
-import { ProfileSecuritySetting } from '@vben/common-ui';
-
-const formSchema = computed(() => {
-  return [
-    {
-      value: true,
-      fieldName: 'accountPassword',
-      label: '账户密码',
-      description: '当前密码强度:强',
-    },
-    {
-      value: true,
-      fieldName: 'securityPhone',
-      label: '密保手机',
-      description: '已绑定手机:138****8293',
-    },
-    {
-      value: true,
-      fieldName: 'securityQuestion',
-      label: '密保问题',
-      description: '未设置密保问题,密保问题可有效保护账户安全',
-    },
-    {
-      value: true,
-      fieldName: 'securityEmail',
-      label: '备用邮箱',
-      description: '已绑定邮箱:ant***sign.com',
-    },
-    {
-      value: false,
-      fieldName: 'securityMfa',
-      label: 'MFA 设备',
-      description: '未绑定 MFA 设备,绑定后,可以进行二次确认',
-    },
-  ];
-});
-</script>
-<template>
-  <ProfileSecuritySetting :form-schema="formSchema" />
-</template>

+ 0 - 98
apps/web-antd/src/views/dashboard/analytics/analytics-trends.vue

@@ -1,98 +0,0 @@
-<script lang="ts" setup>
-import type { EchartsUIType } from '@vben/plugins/echarts';
-
-import { onMounted, ref } from 'vue';
-
-import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
-
-const chartRef = ref<EchartsUIType>();
-const { renderEcharts } = useEcharts(chartRef);
-
-onMounted(() => {
-  renderEcharts({
-    grid: {
-      bottom: 0,
-      containLabel: true,
-      left: '1%',
-      right: '1%',
-      top: '2 %',
-    },
-    series: [
-      {
-        areaStyle: {},
-        data: [
-          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,
-          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,
-          111,
-        ],
-        itemStyle: {
-          color: '#5ab1ef',
-        },
-        smooth: true,
-        type: 'line',
-      },
-      {
-        areaStyle: {},
-        data: [
-          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,
-          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,
-        ],
-        itemStyle: {
-          color: '#019680',
-        },
-        smooth: true,
-        type: 'line',
-      },
-    ],
-    tooltip: {
-      axisPointer: {
-        lineStyle: {
-          color: '#019680',
-          width: 1,
-        },
-      },
-      trigger: 'axis',
-    },
-    // xAxis: {
-    //   axisTick: {
-    //     show: false,
-    //   },
-    //   boundaryGap: false,
-    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
-    //   type: 'category',
-    // },
-    xAxis: {
-      axisTick: {
-        show: false,
-      },
-      boundaryGap: false,
-      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
-      splitLine: {
-        lineStyle: {
-          type: 'solid',
-          width: 1,
-        },
-        show: true,
-      },
-      type: 'category',
-    },
-    yAxis: [
-      {
-        axisTick: {
-          show: false,
-        },
-        max: 80_000,
-        splitArea: {
-          show: true,
-        },
-        splitNumber: 4,
-        type: 'value',
-      },
-    ],
-  });
-});
-</script>
-
-<template>
-  <EchartsUI ref="chartRef" />
-</template>

+ 0 - 82
apps/web-antd/src/views/dashboard/analytics/analytics-visits-data.vue

@@ -1,82 +0,0 @@
-<script lang="ts" setup>
-import type { EchartsUIType } from '@vben/plugins/echarts';
-
-import { onMounted, ref } from 'vue';
-
-import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
-
-const chartRef = ref<EchartsUIType>();
-const { renderEcharts } = useEcharts(chartRef);
-
-onMounted(() => {
-  renderEcharts({
-    legend: {
-      bottom: 0,
-      data: ['访问', '趋势'],
-    },
-    radar: {
-      indicator: [
-        {
-          name: '网页',
-        },
-        {
-          name: '移动端',
-        },
-        {
-          name: 'Ipad',
-        },
-        {
-          name: '客户端',
-        },
-        {
-          name: '第三方',
-        },
-        {
-          name: '其它',
-        },
-      ],
-      radius: '60%',
-      splitNumber: 8,
-    },
-    series: [
-      {
-        areaStyle: {
-          opacity: 1,
-          shadowBlur: 0,
-          shadowColor: 'rgba(0,0,0,.2)',
-          shadowOffsetX: 0,
-          shadowOffsetY: 10,
-        },
-        data: [
-          {
-            itemStyle: {
-              color: '#b6a2de',
-            },
-            name: '访问',
-            value: [90, 50, 86, 40, 50, 20],
-          },
-          {
-            itemStyle: {
-              color: '#5ab1ef',
-            },
-            name: '趋势',
-            value: [70, 75, 70, 76, 20, 85],
-          },
-        ],
-        itemStyle: {
-          // borderColor: '#fff',
-          borderRadius: 10,
-          borderWidth: 2,
-        },
-        symbolSize: 0,
-        type: 'radar',
-      },
-    ],
-    tooltip: {},
-  });
-});
-</script>
-
-<template>
-  <EchartsUI ref="chartRef" />
-</template>

+ 0 - 46
apps/web-antd/src/views/dashboard/analytics/analytics-visits-sales.vue

@@ -1,46 +0,0 @@
-<script lang="ts" setup>
-import type { EchartsUIType } from '@vben/plugins/echarts';
-
-import { onMounted, ref } from 'vue';
-
-import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
-
-const chartRef = ref<EchartsUIType>();
-const { renderEcharts } = useEcharts(chartRef);
-
-onMounted(() => {
-  renderEcharts({
-    series: [
-      {
-        animationDelay() {
-          return Math.random() * 400;
-        },
-        animationEasing: 'exponentialInOut',
-        animationType: 'scale',
-        center: ['50%', '50%'],
-        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
-        data: [
-          { name: '外包', value: 500 },
-          { name: '定制', value: 310 },
-          { name: '技术支持', value: 274 },
-          { name: '远程', value: 400 },
-        ].toSorted((a, b) => {
-          return a.value - b.value;
-        }),
-        name: '商业占比',
-        radius: '80%',
-        roseType: 'radius',
-        type: 'pie',
-      },
-    ],
-
-    tooltip: {
-      trigger: 'item',
-    },
-  });
-});
-</script>
-
-<template>
-  <EchartsUI ref="chartRef" />
-</template>

+ 0 - 65
apps/web-antd/src/views/dashboard/analytics/analytics-visits-source.vue

@@ -1,65 +0,0 @@
-<script lang="ts" setup>
-import type { EchartsUIType } from '@vben/plugins/echarts';
-
-import { onMounted, ref } from 'vue';
-
-import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
-
-const chartRef = ref<EchartsUIType>();
-const { renderEcharts } = useEcharts(chartRef);
-
-onMounted(() => {
-  renderEcharts({
-    legend: {
-      bottom: '2%',
-      left: 'center',
-    },
-    series: [
-      {
-        animationDelay() {
-          return Math.random() * 100;
-        },
-        animationEasing: 'exponentialInOut',
-        animationType: 'scale',
-        avoidLabelOverlap: false,
-        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
-        data: [
-          { name: '搜索引擎', value: 1048 },
-          { name: '直接访问', value: 735 },
-          { name: '邮件营销', value: 580 },
-          { name: '联盟广告', value: 484 },
-        ],
-        emphasis: {
-          label: {
-            fontSize: '12',
-            fontWeight: 'bold',
-            show: true,
-          },
-        },
-        itemStyle: {
-          // borderColor: '#fff',
-          borderRadius: 10,
-          borderWidth: 2,
-        },
-        label: {
-          position: 'center',
-          show: false,
-        },
-        labelLine: {
-          show: false,
-        },
-        name: '访问来源',
-        radius: ['40%', '65%'],
-        type: 'pie',
-      },
-    ],
-    tooltip: {
-      trigger: 'item',
-    },
-  });
-});
-</script>
-
-<template>
-  <EchartsUI ref="chartRef" />
-</template>

+ 0 - 55
apps/web-antd/src/views/dashboard/analytics/analytics-visits.vue

@@ -1,55 +0,0 @@
-<script lang="ts" setup>
-import type { EchartsUIType } from '@vben/plugins/echarts';
-
-import { onMounted, ref } from 'vue';
-
-import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
-
-const chartRef = ref<EchartsUIType>();
-const { renderEcharts } = useEcharts(chartRef);
-
-onMounted(() => {
-  renderEcharts({
-    grid: {
-      bottom: 0,
-      containLabel: true,
-      left: '1%',
-      right: '1%',
-      top: '2 %',
-    },
-    series: [
-      {
-        barMaxWidth: 80,
-        // color: '#4f69fd',
-        data: [
-          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,
-          3200, 4800,
-        ],
-        type: 'bar',
-      },
-    ],
-    tooltip: {
-      axisPointer: {
-        lineStyle: {
-          // color: '#4f69fd',
-          width: 1,
-        },
-      },
-      trigger: 'axis',
-    },
-    xAxis: {
-      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}月`),
-      type: 'category',
-    },
-    yAxis: {
-      max: 8000,
-      splitNumber: 4,
-      type: 'value',
-    },
-  });
-});
-</script>
-
-<template>
-  <EchartsUI ref="chartRef" />
-</template>

Някои файлове не бяха показани, защото твърде много файлове са промени