diff --git a/apps/backend-mock/.env b/apps/backend-mock/.env deleted file mode 100644 index b20c4a6..0000000 --- a/apps/backend-mock/.env +++ /dev/null @@ -1,3 +0,0 @@ -PORT=5320 -ACCESS_TOKEN_SECRET=access_token_secret -REFRESH_TOKEN_SECRET=refresh_token_secret diff --git a/apps/backend-mock/README.md b/apps/backend-mock/README.md deleted file mode 100644 index 401bda7..0000000 --- a/apps/backend-mock/README.md +++ /dev/null @@ -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 -``` diff --git a/apps/backend-mock/api/auth/codes.ts b/apps/backend-mock/api/auth/codes.ts deleted file mode 100644 index e610b33..0000000 --- a/apps/backend-mock/api/auth/codes.ts +++ /dev/null @@ -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); -}); diff --git a/apps/backend-mock/api/auth/login.post.ts b/apps/backend-mock/api/auth/login.post.ts deleted file mode 100644 index e23942c..0000000 --- a/apps/backend-mock/api/auth/login.post.ts +++ /dev/null @@ -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, - }); -}); diff --git a/apps/backend-mock/api/auth/logout.post.ts b/apps/backend-mock/api/auth/logout.post.ts deleted file mode 100644 index 74c8d31..0000000 --- a/apps/backend-mock/api/auth/logout.post.ts +++ /dev/null @@ -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(''); -}); diff --git a/apps/backend-mock/api/auth/refresh.post.ts b/apps/backend-mock/api/auth/refresh.post.ts deleted file mode 100644 index 7d8d3a5..0000000 --- a/apps/backend-mock/api/auth/refresh.post.ts +++ /dev/null @@ -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; -}); diff --git a/apps/backend-mock/api/demo/bigint.ts b/apps/backend-mock/api/demo/bigint.ts deleted file mode 100644 index 00d6c28..0000000 --- a/apps/backend-mock/api/demo/bigint.ts +++ /dev/null @@ -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; -}); diff --git a/apps/backend-mock/api/menu/all.ts b/apps/backend-mock/api/menu/all.ts deleted file mode 100644 index 7923f7c..0000000 --- a/apps/backend-mock/api/menu/all.ts +++ /dev/null @@ -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); -}); diff --git a/apps/backend-mock/api/status.ts b/apps/backend-mock/api/status.ts deleted file mode 100644 index 4378209..0000000 --- a/apps/backend-mock/api/status.ts +++ /dev/null @@ -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}`); -}); diff --git a/apps/backend-mock/api/system/dept/.post.ts b/apps/backend-mock/api/system/dept/.post.ts deleted file mode 100644 index 9a4896a..0000000 --- a/apps/backend-mock/api/system/dept/.post.ts +++ /dev/null @@ -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); -}); diff --git a/apps/backend-mock/api/system/dept/[id].delete.ts b/apps/backend-mock/api/system/dept/[id].delete.ts deleted file mode 100644 index eac0f58..0000000 --- a/apps/backend-mock/api/system/dept/[id].delete.ts +++ /dev/null @@ -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); -}); diff --git a/apps/backend-mock/api/system/dept/[id].put.ts b/apps/backend-mock/api/system/dept/[id].put.ts deleted file mode 100644 index 6805e13..0000000 --- a/apps/backend-mock/api/system/dept/[id].put.ts +++ /dev/null @@ -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); -}); diff --git a/apps/backend-mock/api/system/dept/list.ts b/apps/backend-mock/api/system/dept/list.ts deleted file mode 100644 index a649a0d..0000000 --- a/apps/backend-mock/api/system/dept/list.ts +++ /dev/null @@ -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 = { - 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); -}); diff --git a/apps/backend-mock/api/system/menu/list.ts b/apps/backend-mock/api/system/menu/list.ts deleted file mode 100644 index ce96bb1..0000000 --- a/apps/backend-mock/api/system/menu/list.ts +++ /dev/null @@ -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); -}); diff --git a/apps/backend-mock/api/system/menu/name-exists.ts b/apps/backend-mock/api/system/menu/name-exists.ts deleted file mode 100644 index 7d5551b..0000000 --- a/apps/backend-mock/api/system/menu/name-exists.ts +++ /dev/null @@ -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 = {}; - -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); -}); diff --git a/apps/backend-mock/api/system/menu/path-exists.ts b/apps/backend-mock/api/system/menu/path-exists.ts deleted file mode 100644 index f3c3be9..0000000 --- a/apps/backend-mock/api/system/menu/path-exists.ts +++ /dev/null @@ -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 = { '/': 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); -}); diff --git a/apps/backend-mock/api/system/role/list.ts b/apps/backend-mock/api/system/role/list.ts deleted file mode 100644 index bad29a5..0000000 --- a/apps/backend-mock/api/system/role/list.ts +++ /dev/null @@ -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 = { - 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); -}); diff --git a/apps/backend-mock/api/table/list.ts b/apps/backend-mock/api/table/list.ts deleted file mode 100644 index 6664b58..0000000 --- a/apps/backend-mock/api/table/list.ts +++ /dev/null @@ -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 = 0; - - 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, - ); -}); diff --git a/apps/backend-mock/api/test.get.ts b/apps/backend-mock/api/test.get.ts deleted file mode 100644 index dc2ceef..0000000 --- a/apps/backend-mock/api/test.get.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { defineEventHandler } from 'h3'; - -export default defineEventHandler(() => 'Test get handler'); diff --git a/apps/backend-mock/api/test.post.ts b/apps/backend-mock/api/test.post.ts deleted file mode 100644 index 0e9e337..0000000 --- a/apps/backend-mock/api/test.post.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { defineEventHandler } from 'h3'; - -export default defineEventHandler(() => 'Test post handler'); diff --git a/apps/backend-mock/api/timezone/getTimezone.ts b/apps/backend-mock/api/timezone/getTimezone.ts deleted file mode 100644 index 0cbcb6e..0000000 --- a/apps/backend-mock/api/timezone/getTimezone.ts +++ /dev/null @@ -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()); -}); diff --git a/apps/backend-mock/api/timezone/getTimezoneOptions.ts b/apps/backend-mock/api/timezone/getTimezoneOptions.ts deleted file mode 100644 index 6c24186..0000000 --- a/apps/backend-mock/api/timezone/getTimezoneOptions.ts +++ /dev/null @@ -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); -}); diff --git a/apps/backend-mock/api/timezone/setTimezone.ts b/apps/backend-mock/api/timezone/setTimezone.ts deleted file mode 100644 index 34d8f19..0000000 --- a/apps/backend-mock/api/timezone/setTimezone.ts +++ /dev/null @@ -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({}); -}); diff --git a/apps/backend-mock/api/upload.ts b/apps/backend-mock/api/upload.ts deleted file mode 100644 index 436b63c..0000000 --- a/apps/backend-mock/api/upload.ts +++ /dev/null @@ -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") -}); diff --git a/apps/backend-mock/api/user/info.ts b/apps/backend-mock/api/user/info.ts deleted file mode 100644 index 138cb43..0000000 --- a/apps/backend-mock/api/user/info.ts +++ /dev/null @@ -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); -}); diff --git a/apps/backend-mock/error.ts b/apps/backend-mock/error.ts deleted file mode 100644 index e20beac..0000000 --- a/apps/backend-mock/error.ts +++ /dev/null @@ -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; diff --git a/apps/backend-mock/middleware/1.api.ts b/apps/backend-mock/middleware/1.api.ts deleted file mode 100644 index 339cda4..0000000 --- a/apps/backend-mock/middleware/1.api.ts +++ /dev/null @@ -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, '演示环境,禁止修改'); - } -}); diff --git a/apps/backend-mock/nitro.config.ts b/apps/backend-mock/nitro.config.ts deleted file mode 100644 index c0fc13e..0000000 --- a/apps/backend-mock/nitro.config.ts +++ /dev/null @@ -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': '*', - }, - }, - }, -}); diff --git a/apps/backend-mock/package.json b/apps/backend-mock/package.json deleted file mode 100644 index cc0b8d5..0000000 --- a/apps/backend-mock/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@vben/backend-mock", - "version": "0.0.1", - "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:" - } -} diff --git a/apps/backend-mock/routes/[...].ts b/apps/backend-mock/routes/[...].ts deleted file mode 100644 index 5a22563..0000000 --- a/apps/backend-mock/routes/[...].ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineEventHandler } from 'h3'; - -export default defineEventHandler(() => { - return ` -

Hello Vben Admin

-

Mock service is starting

- -`; -}); diff --git a/apps/backend-mock/tsconfig.build.json b/apps/backend-mock/tsconfig.build.json deleted file mode 100644 index 64f86c6..0000000 --- a/apps/backend-mock/tsconfig.build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] -} diff --git a/apps/backend-mock/tsconfig.json b/apps/backend-mock/tsconfig.json deleted file mode 100644 index 43008af..0000000 --- a/apps/backend-mock/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./.nitro/types/tsconfig.json" -} diff --git a/apps/backend-mock/utils/cookie-utils.ts b/apps/backend-mock/utils/cookie-utils.ts deleted file mode 100644 index 187ce2f..0000000 --- a/apps/backend-mock/utils/cookie-utils.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { EventHandlerRequest, H3Event } from 'h3'; - -import { deleteCookie, getCookie, setCookie } from 'h3'; - -export function clearRefreshTokenCookie(event: H3Event) { - deleteCookie(event, 'jwt', { - httpOnly: true, - sameSite: 'none', - secure: true, - }); -} - -export function setRefreshTokenCookie( - event: H3Event, - refreshToken: string, -) { - setCookie(event, 'jwt', refreshToken, { - httpOnly: true, - maxAge: 24 * 60 * 60, // unit: seconds - sameSite: 'none', - secure: true, - }); -} - -export function getRefreshTokenFromCookie(event: H3Event) { - const refreshToken = getCookie(event, 'jwt'); - return refreshToken; -} diff --git a/apps/backend-mock/utils/jwt-utils.ts b/apps/backend-mock/utils/jwt-utils.ts deleted file mode 100644 index 7185830..0000000 --- a/apps/backend-mock/utils/jwt-utils.ts +++ /dev/null @@ -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, -): null | Omit { - 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 { - 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; - } -} diff --git a/apps/backend-mock/utils/mock-data.ts b/apps/backend-mock/utils/mock-data.ts deleted file mode 100644 index ee38e8e..0000000 --- a/apps/backend-mock/utils/mock-data.ts +++ /dev/null @@ -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', - }, -]; diff --git a/apps/backend-mock/utils/response.ts b/apps/backend-mock/utils/response.ts deleted file mode 100644 index 2d4242e..0000000 --- a/apps/backend-mock/utils/response.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { EventHandlerRequest, H3Event } from 'h3'; - -import { setResponseStatus } from 'h3'; - -export function useResponseSuccess(data: T) { - return { - code: 0, - data, - error: null, - message: 'ok', - }; -} - -export function usePageResponseSuccess( - 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, - message = 'Forbidden Exception', -) { - setResponseStatus(event, 403); - return useResponseError(message, message); -} - -export function unAuthorizedResponse(event: H3Event) { - setResponseStatus(event, 401); - return useResponseError('Unauthorized Exception', 'Unauthorized Exception'); -} - -export function sleep(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export function pagination( - 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)); -} diff --git a/apps/backend-mock/utils/timezone-utils.ts b/apps/backend-mock/utils/timezone-utils.ts deleted file mode 100644 index da35f92..0000000 --- a/apps/backend-mock/utils/timezone-utils.ts +++ /dev/null @@ -1,9 +0,0 @@ -let mockTimeZone: null | string = null; - -export const setTimezone = (timeZone: string) => { - mockTimeZone = timeZone; -}; - -export const getTimezone = () => { - return mockTimeZone; -}; diff --git a/apps/web-ele/.env b/apps/web-ele/.env deleted file mode 100644 index 5efb2c0..0000000 --- a/apps/web-ele/.env +++ /dev/null @@ -1,8 +0,0 @@ -# 应用标题 -VITE_APP_TITLE=TakeoutSaaS TenantUI - -# 应用命名空间,用于缓存、store等功能的前缀,确保隔离 -VITE_APP_NAMESPACE=takeout-saas-tenantui - -# 对store进行加密的密钥,在将store持久化到localStorage时会使用该密钥进行加密 -VITE_APP_STORE_SECURE_KEY=please-replace-me-with-your-own-key diff --git a/apps/web-ele/.env.analyze b/apps/web-ele/.env.analyze deleted file mode 100644 index ffafa8d..0000000 --- a/apps/web-ele/.env.analyze +++ /dev/null @@ -1,7 +0,0 @@ -# public path -VITE_BASE=/ - -# Basic interface address SPA -VITE_GLOB_API_URL=/api - -VITE_VISUALIZER=true diff --git a/apps/web-ele/.env.development b/apps/web-ele/.env.development deleted file mode 100644 index 0256641..0000000 --- a/apps/web-ele/.env.development +++ /dev/null @@ -1,16 +0,0 @@ -# 端口号 -VITE_PORT=3007 - -VITE_BASE=/ - -# 接口地址 -VITE_GLOB_API_URL=/api - -# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 -VITE_NITRO_MOCK=false - -# 是否打开 devtools,true 为打开,false 为关闭 -VITE_DEVTOOLS=false - -# 是否注入全局loading -VITE_INJECT_APP_LOADING=true diff --git a/apps/web-ele/.env.production b/apps/web-ele/.env.production deleted file mode 100644 index 5375847..0000000 --- a/apps/web-ele/.env.production +++ /dev/null @@ -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 diff --git a/apps/web-ele/index.html b/apps/web-ele/index.html deleted file mode 100644 index 2b59b8d..0000000 --- a/apps/web-ele/index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - <%= VITE_APP_TITLE %> - - - - -
- - - diff --git a/apps/web-ele/package.json b/apps/web-ele/package.json deleted file mode 100644 index abbedb6..0000000 --- a/apps/web-ele/package.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "name": "@vben/web-ele", - "version": "5.5.9", - "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-ele" - }, - "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:", - "dayjs": "catalog:", - "element-plus": "catalog:", - "pinia": "catalog:", - "vue": "catalog:", - "vue-router": "catalog:" - }, - "devDependencies": { - "unplugin-element-plus": "catalog:" - } -} diff --git a/apps/web-ele/postcss.config.mjs b/apps/web-ele/postcss.config.mjs deleted file mode 100644 index 3d80704..0000000 --- a/apps/web-ele/postcss.config.mjs +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@vben/tailwind-config/postcss'; diff --git a/apps/web-ele/public/favicon.ico b/apps/web-ele/public/favicon.ico deleted file mode 100644 index fcf9818..0000000 Binary files a/apps/web-ele/public/favicon.ico and /dev/null differ diff --git a/apps/web-ele/src/adapter/component/index.ts b/apps/web-ele/src/adapter/component/index.ts deleted file mode 100644 index 79a4636..0000000 --- a/apps/web-ele/src/adapter/component/index.ts +++ /dev/null @@ -1,331 +0,0 @@ -/** - * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用 - * 可用于 vben-form、vben-modal、vben-drawer 等组件使用, - */ - -import type { Component } from 'vue'; - -import type { BaseFormComponentType } from '@vben/common-ui'; -import type { Recordable } from '@vben/types'; - -import { defineAsyncComponent, defineComponent, h, ref } from 'vue'; - -import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; -import { $t } from '@vben/locales'; - -import { ElNotification } from 'element-plus'; - -const ElButton = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/button/index'), - import('element-plus/es/components/button/style/css'), - ]).then(([res]) => res.ElButton), -); -const ElCheckbox = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/checkbox/index'), - import('element-plus/es/components/checkbox/style/css'), - ]).then(([res]) => res.ElCheckbox), -); -const ElCheckboxButton = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/checkbox/index'), - import('element-plus/es/components/checkbox-button/style/css'), - ]).then(([res]) => res.ElCheckboxButton), -); -const ElCheckboxGroup = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/checkbox/index'), - import('element-plus/es/components/checkbox-group/style/css'), - ]).then(([res]) => res.ElCheckboxGroup), -); -const ElDatePicker = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/date-picker/index'), - import('element-plus/es/components/date-picker/style/css'), - ]).then(([res]) => res.ElDatePicker), -); -const ElDivider = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/divider/index'), - import('element-plus/es/components/divider/style/css'), - ]).then(([res]) => res.ElDivider), -); -const ElInput = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/input/index'), - import('element-plus/es/components/input/style/css'), - ]).then(([res]) => res.ElInput), -); -const ElInputNumber = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/input-number/index'), - import('element-plus/es/components/input-number/style/css'), - ]).then(([res]) => res.ElInputNumber), -); -const ElRadio = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/radio/index'), - import('element-plus/es/components/radio/style/css'), - ]).then(([res]) => res.ElRadio), -); -const ElRadioButton = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/radio/index'), - import('element-plus/es/components/radio-button/style/css'), - ]).then(([res]) => res.ElRadioButton), -); -const ElRadioGroup = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/radio/index'), - import('element-plus/es/components/radio-group/style/css'), - ]).then(([res]) => res.ElRadioGroup), -); -const ElSelectV2 = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/select-v2/index'), - import('element-plus/es/components/select-v2/style/css'), - ]).then(([res]) => res.ElSelectV2), -); -const ElSpace = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/space/index'), - import('element-plus/es/components/space/style/css'), - ]).then(([res]) => res.ElSpace), -); -const ElSwitch = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/switch/index'), - import('element-plus/es/components/switch/style/css'), - ]).then(([res]) => res.ElSwitch), -); -const ElTimePicker = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/time-picker/index'), - import('element-plus/es/components/time-picker/style/css'), - ]).then(([res]) => res.ElTimePicker), -); -const ElTreeSelect = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/tree-select/index'), - import('element-plus/es/components/tree-select/style/css'), - ]).then(([res]) => res.ElTreeSelect), -); -const ElUpload = defineAsyncComponent(() => - Promise.all([ - import('element-plus/es/components/upload/index'), - import('element-plus/es/components/upload/style/css'), - ]).then(([res]) => res.ElUpload), -); - -const withDefaultPlaceholder = ( - component: T, - type: 'input' | 'select', - componentProps: Recordable = {}, -) => { - 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, - ); - }, - }); -}; - -// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明 -export type ComponentType = - | 'ApiSelect' - | 'ApiTreeSelect' - | 'Checkbox' - | 'CheckboxGroup' - | 'DatePicker' - | 'Divider' - | 'IconPicker' - | 'Input' - | 'InputNumber' - | 'RadioGroup' - | 'Select' - | 'Space' - | 'Switch' - | 'TimePicker' - | 'TreeSelect' - | 'Upload' - | BaseFormComponentType; - -async function initComponentAdapter() { - const components: Partial> = { - // 如果你的组件体积比较大,可以使用异步加载 - // Button: () => - // import('xxx').then((res) => res.Button), - ApiSelect: withDefaultPlaceholder( - { - ...ApiComponent, - name: 'ApiSelect', - }, - 'select', - { - component: ElSelectV2, - loadingSlot: 'loading', - visibleEvent: 'onVisibleChange', - }, - ), - ApiTreeSelect: withDefaultPlaceholder( - { - ...ApiComponent, - name: 'ApiTreeSelect', - }, - 'select', - { - component: ElTreeSelect, - props: { label: 'label', children: 'children' }, - nodeKey: 'value', - loadingSlot: 'loading', - optionsPropName: 'data', - visibleEvent: 'onVisibleChange', - }, - ), - Checkbox: ElCheckbox, - CheckboxGroup: (props, { attrs, slots }) => { - let defaultSlot; - if (Reflect.has(slots, 'default')) { - defaultSlot = slots.default; - } else { - const { options, isButton } = attrs; - if (Array.isArray(options)) { - defaultSlot = () => - options.map((option) => - h(isButton ? ElCheckboxButton : ElCheckbox, option), - ); - } - } - return h( - ElCheckboxGroup, - { ...props, ...attrs }, - { ...slots, default: defaultSlot }, - ); - }, - // 自定义默认按钮 - DefaultButton: (props, { attrs, slots }) => { - return h(ElButton, { ...props, attrs, type: 'info' }, slots); - }, - // 自定义主要按钮 - PrimaryButton: (props, { attrs, slots }) => { - return h(ElButton, { ...props, attrs, type: 'primary' }, slots); - }, - Divider: ElDivider, - IconPicker: withDefaultPlaceholder(IconPicker, 'select', { - iconSlot: 'append', - modelValueProp: 'model-value', - inputComponent: ElInput, - }), - Input: withDefaultPlaceholder(ElInput, 'input'), - InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'), - RadioGroup: (props, { attrs, slots }) => { - let defaultSlot; - if (Reflect.has(slots, 'default')) { - defaultSlot = slots.default; - } else { - const { options } = attrs; - if (Array.isArray(options)) { - defaultSlot = () => - options.map((option) => - h(attrs.isButton ? ElRadioButton : ElRadio, option), - ); - } - } - return h( - ElRadioGroup, - { ...props, ...attrs }, - { ...slots, default: defaultSlot }, - ); - }, - Select: (props, { attrs, slots }) => { - return h(ElSelectV2, { ...props, attrs }, slots); - }, - Space: ElSpace, - Switch: ElSwitch, - TimePicker: (props, { attrs, slots }) => { - const { name, id, isRange } = props; - const extraProps: Recordable = {}; - if (isRange) { - if (name && !Array.isArray(name)) { - extraProps.name = [name, `${name}_end`]; - } - if (id && !Array.isArray(id)) { - extraProps.id = [id, `${id}_end`]; - } - } - return h( - ElTimePicker, - { - ...props, - ...attrs, - ...extraProps, - }, - slots, - ); - }, - DatePicker: (props, { attrs, slots }) => { - const { name, id, type } = props; - const extraProps: Recordable = {}; - if (type && type.includes('range')) { - if (name && !Array.isArray(name)) { - extraProps.name = [name, `${name}_end`]; - } - if (id && !Array.isArray(id)) { - extraProps.id = [id, `${id}_end`]; - } - } - return h( - ElDatePicker, - { - ...props, - ...attrs, - ...extraProps, - }, - slots, - ); - }, - TreeSelect: withDefaultPlaceholder(ElTreeSelect, 'select'), - Upload: ElUpload, - }; - - // 将组件注册到全局共享状态中 - globalShareState.setComponents(components); - - // 定义全局共享状态中的消息提示 - globalShareState.defineMessage({ - // 复制成功消息提示 - copyPreferencesSuccess: (title, content) => { - ElNotification({ - title, - message: content, - position: 'bottom-right', - duration: 0, - type: 'success', - }); - }, - }); -} - -export { initComponentAdapter }; diff --git a/apps/web-ele/src/adapter/form.ts b/apps/web-ele/src/adapter/form.ts deleted file mode 100644 index 936c3fe..0000000 --- a/apps/web-ele/src/adapter/form.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { - VbenFormSchema as FormSchema, - VbenFormProps, -} from '@vben/common-ui'; - -import type { ComponentType } from './component'; - -import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; -import { $t } from '@vben/locales'; - -async function initSetupVbenForm() { - setupVbenForm({ - config: { - modelPropNameMap: { - Upload: 'fileList', - CheckboxGroup: 'model-value', - }, - }, - 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; - -export { initSetupVbenForm, useVbenForm, z }; - -export type VbenFormSchema = FormSchema; -export type { VbenFormProps }; diff --git a/apps/web-ele/src/adapter/vxe-table.ts b/apps/web-ele/src/adapter/vxe-table.ts deleted file mode 100644 index 81d1cdd..0000000 --- a/apps/web-ele/src/adapter/vxe-table.ts +++ /dev/null @@ -1,71 +0,0 @@ -import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; - -import { h } from 'vue'; - -import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; - -import { ElButton, ElImage } from 'element-plus'; - -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; - const src = row[column.field]; - return h(ElImage, { src, previewSrcList: [src], ...props }); - }, - }); - - // 表格配置项可以用 cellRender: { name: 'CellLink' }, - vxeUI.renderer.add('CellLink', { - renderTableDefault(renderOpts) { - const { props } = renderOpts; - return h( - ElButton, - { size: 'small', link: true }, - { default: () => props?.text }, - ); - }, - }); - - // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 - // vxeUI.formats.add - }, - useVbenForm, -}); - -export { useVbenVxeGrid }; - -export type * from '@vben/plugins/vxe-table'; diff --git a/apps/web-ele/src/api/core/auth.ts b/apps/web-ele/src/api/core/auth.ts deleted file mode 100644 index 71d9f99..0000000 --- a/apps/web-ele/src/api/core/auth.ts +++ /dev/null @@ -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('/auth/login', data); -} - -/** - * 刷新accessToken - */ -export async function refreshTokenApi() { - return baseRequestClient.post('/auth/refresh', { - withCredentials: true, - }); -} - -/** - * 退出登录 - */ -export async function logoutApi() { - return baseRequestClient.post('/auth/logout', { - withCredentials: true, - }); -} - -/** - * 获取用户权限码 - */ -export async function getAccessCodesApi() { - return requestClient.get('/auth/codes'); -} diff --git a/apps/web-ele/src/api/core/index.ts b/apps/web-ele/src/api/core/index.ts deleted file mode 100644 index 28a5aef..0000000 --- a/apps/web-ele/src/api/core/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './auth'; -export * from './menu'; -export * from './user'; diff --git a/apps/web-ele/src/api/core/menu.ts b/apps/web-ele/src/api/core/menu.ts deleted file mode 100644 index 9ef60b1..0000000 --- a/apps/web-ele/src/api/core/menu.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { RouteRecordStringComponent } from '@vben/types'; - -import { requestClient } from '#/api/request'; - -/** - * 获取用户所有菜单 - */ -export async function getAllMenusApi() { - return requestClient.get('/menu/all'); -} diff --git a/apps/web-ele/src/api/core/user.ts b/apps/web-ele/src/api/core/user.ts deleted file mode 100644 index 7e28ea8..0000000 --- a/apps/web-ele/src/api/core/user.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { UserInfo } from '@vben/types'; - -import { requestClient } from '#/api/request'; - -/** - * 获取用户信息 - */ -export async function getUserInfoApi() { - return requestClient.get('/user/info'); -} diff --git a/apps/web-ele/src/api/index.ts b/apps/web-ele/src/api/index.ts deleted file mode 100644 index 4b0e041..0000000 --- a/apps/web-ele/src/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './core'; diff --git a/apps/web-ele/src/api/request.ts b/apps/web-ele/src/api/request.ts deleted file mode 100644 index 203b35b..0000000 --- a/apps/web-ele/src/api/request.ts +++ /dev/null @@ -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 { ElMessage } from 'element-plus'; - -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 ?? ''; - // 如果没有错误信息,则会根据状态码进行提示 - ElMessage.error(errorMessage || msg); - }), - ); - - return client; -} - -export const requestClient = createRequestClient(apiURL, { - responseReturn: 'data', -}); - -export const baseRequestClient = new RequestClient({ baseURL: apiURL }); diff --git a/apps/web-ele/src/app.vue b/apps/web-ele/src/app.vue deleted file mode 100644 index 1217658..0000000 --- a/apps/web-ele/src/app.vue +++ /dev/null @@ -1,17 +0,0 @@ - - - diff --git a/apps/web-ele/src/bootstrap.ts b/apps/web-ele/src/bootstrap.ts deleted file mode 100644 index e5befb5..0000000 --- a/apps/web-ele/src/bootstrap.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { createApp, watchEffect } from 'vue'; - -import { registerAccessDirective } from '@vben/access'; -import { registerLoadingDirective } from '@vben/common-ui'; -import { preferences } from '@vben/preferences'; -import { initStores } from '@vben/stores'; -import '@vben/styles'; -import '@vben/styles/ele'; - -import { useTitle } from '@vueuse/core'; -import { ElLoading } from 'element-plus'; - -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: 2000, - // }); - const app = createApp(App); - - // 注册Element Plus提供的v-loading指令 - app.directive('loading', ElLoading.directive); - - // 注册Vben提供的v-loading和v-spinning指令 - registerLoadingDirective(app, { - loading: false, // Vben提供的v-loading指令和Element Plus提供的v-loading指令二选一即可,此处false表示不注册Vben提供的v-loading指令 - 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 }; diff --git a/apps/web-ele/src/layouts/auth.vue b/apps/web-ele/src/layouts/auth.vue deleted file mode 100644 index 8ba66e8..0000000 --- a/apps/web-ele/src/layouts/auth.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/apps/web-ele/src/layouts/basic.vue b/apps/web-ele/src/layouts/basic.vue deleted file mode 100644 index 2226c68..0000000 --- a/apps/web-ele/src/layouts/basic.vue +++ /dev/null @@ -1,206 +0,0 @@ - - - diff --git a/apps/web-ele/src/layouts/index.ts b/apps/web-ele/src/layouts/index.ts deleted file mode 100644 index a432078..0000000 --- a/apps/web-ele/src/layouts/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-ele/src/locales/README.md b/apps/web-ele/src/locales/README.md deleted file mode 100644 index 7b45103..0000000 --- a/apps/web-ele/src/locales/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# locale - -每个app使用的国际化可能不同,这里用于扩展国际化的功能,例如扩展 dayjs、antd组件库的多语言切换,以及app本身的国际化文件。 diff --git a/apps/web-ele/src/locales/index.ts b/apps/web-ele/src/locales/index.ts deleted file mode 100644 index 57b87df..0000000 --- a/apps/web-ele/src/locales/index.ts +++ /dev/null @@ -1,102 +0,0 @@ -import type { Language } from 'element-plus/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 dayjs from 'dayjs'; -import enLocale from 'element-plus/es/locale/lang/en'; -import defaultLocale from 'element-plus/es/locale/lang/zh-cn'; - -const elementLocale = ref(defaultLocale); - -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([loadElementLocale(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}`); - } -} - -/** - * 加载element-plus的语言包 - * @param lang - */ -async function loadElementLocale(lang: SupportedLanguagesType) { - switch (lang) { - case 'en-US': { - elementLocale.value = enLocale; - break; - } - case 'zh-CN': { - elementLocale.value = defaultLocale; - break; - } - } -} - -async function setupI18n(app: App, options: LocaleSetupOptions = {}) { - await coreSetup(app, { - defaultLocale: preferences.app.locale, - loadMessages, - missingWarn: !import.meta.env.PROD, - ...options, - }); -} - -export { $t, elementLocale, setupI18n }; diff --git a/apps/web-ele/src/locales/langs/en-US/demos.json b/apps/web-ele/src/locales/langs/en-US/demos.json deleted file mode 100644 index cc40451..0000000 --- a/apps/web-ele/src/locales/langs/en-US/demos.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "title": "Demos", - "elementPlus": "Element Plus", - "form": "Form", - "vben": { - "title": "Project", - "about": "About", - "document": "Document", - "antdv": "Ant Design Vue Version", - "naive-ui": "Naive UI Version", - "element-plus": "Element Plus Version", - "tdesign": "TDesign Vue Version" - } -} diff --git a/apps/web-ele/src/locales/langs/en-US/page.json b/apps/web-ele/src/locales/langs/en-US/page.json deleted file mode 100644 index 39f1641..0000000 --- a/apps/web-ele/src/locales/langs/en-US/page.json +++ /dev/null @@ -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" - } -} diff --git a/apps/web-ele/src/locales/langs/zh-CN/demos.json b/apps/web-ele/src/locales/langs/zh-CN/demos.json deleted file mode 100644 index f8379c3..0000000 --- a/apps/web-ele/src/locales/langs/zh-CN/demos.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "title": "演示", - "elementPlus": "Element Plus", - "form": "表单演示", - "vben": { - "title": "项目", - "about": "关于", - "document": "文档", - "antdv": "Ant Design Vue 版本", - "naive-ui": "Naive UI 版本", - "element-plus": "Element Plus 版本", - "tdesign": "TDesign Vue 版本" - } -} diff --git a/apps/web-ele/src/locales/langs/zh-CN/page.json b/apps/web-ele/src/locales/langs/zh-CN/page.json deleted file mode 100644 index 2192d1d..0000000 --- a/apps/web-ele/src/locales/langs/zh-CN/page.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "auth": { - "login": "登录", - "register": "注册", - "codeLogin": "验证码登录", - "qrcodeLogin": "二维码登录", - "forgetPassword": "忘记密码", - "profile": "个人中心" - }, - "dashboard": { - "title": "概览", - "analytics": "分析页", - "workspace": "工作台" - } -} diff --git a/apps/web-ele/src/main.ts b/apps/web-ele/src/main.ts deleted file mode 100644 index 5d728a0..0000000 --- a/apps/web-ele/src/main.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { initPreferences } from '@vben/preferences'; -import { unmountGlobalLoading } from '@vben/utils'; - -import { overridesPreferences } from './preferences'; - -/** - * 应用初始化完成之后再进行页面加载渲染 - */ -async function initApplication() { - // name用于指定项目唯一标识 - // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据 - const env = import.meta.env.PROD ? 'prod' : 'dev'; - const appVersion = import.meta.env.VITE_APP_VERSION; - const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`; - - // app偏好设置初始化 - await initPreferences({ - namespace, - overrides: overridesPreferences, - }); - - // 启动应用并挂载 - // vue应用主要逻辑及视图 - const { bootstrap } = await import('./bootstrap'); - await bootstrap(namespace); - - // 移除并销毁loading - unmountGlobalLoading(); -} - -initApplication(); diff --git a/apps/web-ele/src/preferences.ts b/apps/web-ele/src/preferences.ts deleted file mode 100644 index b2e9ace..0000000 --- a/apps/web-ele/src/preferences.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { defineOverridesPreferences } from '@vben/preferences'; - -/** - * @description 项目配置文件 - * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置 - * !!! 更改配置后请清空缓存,否则可能不生效 - */ -export const overridesPreferences = defineOverridesPreferences({ - // overrides - app: { - name: import.meta.env.VITE_APP_TITLE, - }, -}); diff --git a/apps/web-ele/src/router/access.ts b/apps/web-ele/src/router/access.ts deleted file mode 100644 index 2d07c89..0000000 --- a/apps/web-ele/src/router/access.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { - ComponentRecordType, - GenerateMenuAndRoutesOptions, -} from '@vben/types'; - -import { generateAccessible } from '@vben/access'; -import { preferences } from '@vben/preferences'; - -import { ElMessage } from 'element-plus'; - -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 () => { - ElMessage({ - duration: 1500, - message: `${$t('common.loadingMenu')}...`, - }); - return await getAllMenusApi(); - }, - // 可以指定没有权限跳转403页面 - forbiddenComponent, - // 如果 route.meta.menuVisibleWithForbidden = true - layoutMap, - pageMap, - }); -} - -export { generateAccess }; diff --git a/apps/web-ele/src/router/guard.ts b/apps/web-ele/src/router/guard.ts deleted file mode 100644 index a1ad6d8..0000000 --- a/apps/web-ele/src/router/guard.ts +++ /dev/null @@ -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(); - - 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 }; diff --git a/apps/web-ele/src/router/index.ts b/apps/web-ele/src/router/index.ts deleted file mode 100644 index 4840230..0000000 --- a/apps/web-ele/src/router/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-ele/src/router/routes/core.ts b/apps/web-ele/src/router/routes/core.ts deleted file mode 100644 index 949b0b6..0000000 --- a/apps/web-ele/src/router/routes/core.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-ele/src/router/routes/index.ts b/apps/web-ele/src/router/routes/index.ts deleted file mode 100644 index e6fb144..0000000 --- a/apps/web-ele/src/router/routes/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-ele/src/router/routes/modules/dashboard.ts b/apps/web-ele/src/router/routes/modules/dashboard.ts deleted file mode 100644 index 5254dc6..0000000 --- a/apps/web-ele/src/router/routes/modules/dashboard.ts +++ /dev/null @@ -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; diff --git a/apps/web-ele/src/router/routes/modules/demos.ts b/apps/web-ele/src/router/routes/modules/demos.ts deleted file mode 100644 index 907ea3f..0000000 --- a/apps/web-ele/src/router/routes/modules/demos.ts +++ /dev/null @@ -1,36 +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.elementPlus'), - }, - name: 'NaiveDemos', - path: '/demos/element', - component: () => import('#/views/demos/element/index.vue'), - }, - { - meta: { - title: $t('demos.form'), - }, - name: 'BasicForm', - path: '/demos/form', - component: () => import('#/views/demos/form/basic.vue'), - }, - ], - }, -]; - -export default routes; diff --git a/apps/web-ele/src/router/routes/modules/vben.ts b/apps/web-ele/src/router/routes/modules/vben.ts deleted file mode 100644 index 5c522f3..0000000 --- a/apps/web-ele/src/router/routes/modules/vben.ts +++ /dev/null @@ -1,104 +0,0 @@ -import type { RouteRecordRaw } from 'vue-router'; - -import { - VBEN_ANT_PREVIEW_URL, - VBEN_DOC_URL, - VBEN_GITHUB_URL, - VBEN_LOGO_URL, - VBEN_NAIVE_PREVIEW_URL, - VBEN_TD_PREVIEW_URL, -} from '@vben/constants'; -import { SvgAntdvLogoIcon, 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: '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: 'VbenAntd', - path: '/vben-admin/antd', - component: IFrameView, - meta: { - badgeType: 'dot', - icon: SvgAntdvLogoIcon, - link: VBEN_ANT_PREVIEW_URL, - title: $t('demos.vben.antdv'), - }, - }, - { - name: 'VbenTDesign', - path: '/vben-admin/tdesign', - component: IFrameView, - meta: { - badgeType: 'dot', - icon: SvgTDesignIcon, - link: VBEN_TD_PREVIEW_URL, - title: $t('demos.vben.tdesign'), - }, - }, - ], - }, - { - 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; diff --git a/apps/web-ele/src/store/auth.ts b/apps/web-ele/src/store/auth.ts deleted file mode 100644 index 74fadfe..0000000 --- a/apps/web-ele/src/store/auth.ts +++ /dev/null @@ -1,119 +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 { ElNotification } from 'element-plus'; -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, - onSuccess?: () => Promise | void, - ) { - // 异步处理用户登录操作并获取 accessToken - let userInfo: null | UserInfo = null; - try { - loginLoading.value = true; - const { accessToken } = await loginApi(params); - - // 如果成功获取到 accessToken - if (accessToken) { - // 将 accessToken 存储到 accessStore 中 - 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) { - ElNotification({ - message: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`, - title: $t('authentication.loginSuccess'), - type: 'success', - }); - } - } - } 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() { - let userInfo: null | UserInfo = null; - userInfo = await getUserInfoApi(); - userStore.setUserInfo(userInfo); - return userInfo; - } - - function $reset() { - loginLoading.value = false; - } - - return { - $reset, - authLogin, - fetchUserInfo, - loginLoading, - logout, - }; -}); diff --git a/apps/web-ele/src/store/index.ts b/apps/web-ele/src/store/index.ts deleted file mode 100644 index 269586e..0000000 --- a/apps/web-ele/src/store/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './auth'; diff --git a/apps/web-ele/src/views/_core/README.md b/apps/web-ele/src/views/_core/README.md deleted file mode 100644 index 8248afe..0000000 --- a/apps/web-ele/src/views/_core/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# \_core - -此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。 diff --git a/apps/web-ele/src/views/_core/about/index.vue b/apps/web-ele/src/views/_core/about/index.vue deleted file mode 100644 index 0ee5243..0000000 --- a/apps/web-ele/src/views/_core/about/index.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/authentication/code-login.vue b/apps/web-ele/src/views/_core/authentication/code-login.vue deleted file mode 100644 index acfd1fd..0000000 --- a/apps/web-ele/src/views/_core/authentication/code-login.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/authentication/forget-password.vue b/apps/web-ele/src/views/_core/authentication/forget-password.vue deleted file mode 100644 index fef0d42..0000000 --- a/apps/web-ele/src/views/_core/authentication/forget-password.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/authentication/login.vue b/apps/web-ele/src/views/_core/authentication/login.vue deleted file mode 100644 index 099e4c8..0000000 --- a/apps/web-ele/src/views/_core/authentication/login.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/authentication/qrcode-login.vue b/apps/web-ele/src/views/_core/authentication/qrcode-login.vue deleted file mode 100644 index 23f5f2d..0000000 --- a/apps/web-ele/src/views/_core/authentication/qrcode-login.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/authentication/register.vue b/apps/web-ele/src/views/_core/authentication/register.vue deleted file mode 100644 index b1a5de7..0000000 --- a/apps/web-ele/src/views/_core/authentication/register.vue +++ /dev/null @@ -1,96 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/fallback/coming-soon.vue b/apps/web-ele/src/views/_core/fallback/coming-soon.vue deleted file mode 100644 index f394930..0000000 --- a/apps/web-ele/src/views/_core/fallback/coming-soon.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/fallback/forbidden.vue b/apps/web-ele/src/views/_core/fallback/forbidden.vue deleted file mode 100644 index 8ea65fe..0000000 --- a/apps/web-ele/src/views/_core/fallback/forbidden.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/fallback/internal-error.vue b/apps/web-ele/src/views/_core/fallback/internal-error.vue deleted file mode 100644 index 819a47d..0000000 --- a/apps/web-ele/src/views/_core/fallback/internal-error.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/fallback/not-found.vue b/apps/web-ele/src/views/_core/fallback/not-found.vue deleted file mode 100644 index 4d178e9..0000000 --- a/apps/web-ele/src/views/_core/fallback/not-found.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/fallback/offline.vue b/apps/web-ele/src/views/_core/fallback/offline.vue deleted file mode 100644 index 5de4a88..0000000 --- a/apps/web-ele/src/views/_core/fallback/offline.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/_core/profile/base-setting.vue b/apps/web-ele/src/views/_core/profile/base-setting.vue deleted file mode 100644 index aa8a4c2..0000000 --- a/apps/web-ele/src/views/_core/profile/base-setting.vue +++ /dev/null @@ -1,65 +0,0 @@ - - diff --git a/apps/web-ele/src/views/_core/profile/index.vue b/apps/web-ele/src/views/_core/profile/index.vue deleted file mode 100644 index 8740894..0000000 --- a/apps/web-ele/src/views/_core/profile/index.vue +++ /dev/null @@ -1,49 +0,0 @@ - - diff --git a/apps/web-ele/src/views/_core/profile/notification-setting.vue b/apps/web-ele/src/views/_core/profile/notification-setting.vue deleted file mode 100644 index 324a4b3..0000000 --- a/apps/web-ele/src/views/_core/profile/notification-setting.vue +++ /dev/null @@ -1,31 +0,0 @@ - - diff --git a/apps/web-ele/src/views/_core/profile/password-setting.vue b/apps/web-ele/src/views/_core/profile/password-setting.vue deleted file mode 100644 index a0e8c7e..0000000 --- a/apps/web-ele/src/views/_core/profile/password-setting.vue +++ /dev/null @@ -1,63 +0,0 @@ - - diff --git a/apps/web-ele/src/views/_core/profile/security-setting.vue b/apps/web-ele/src/views/_core/profile/security-setting.vue deleted file mode 100644 index be30db5..0000000 --- a/apps/web-ele/src/views/_core/profile/security-setting.vue +++ /dev/null @@ -1,43 +0,0 @@ - - diff --git a/apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue b/apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue deleted file mode 100644 index f1f0b23..0000000 --- a/apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue b/apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue deleted file mode 100644 index 190fb41..0000000 --- a/apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue b/apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue deleted file mode 100644 index 6ff5208..0000000 --- a/apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue b/apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue deleted file mode 100644 index 0915c7a..0000000 --- a/apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue b/apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue deleted file mode 100644 index 7e0f101..0000000 --- a/apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/dashboard/analytics/index.vue b/apps/web-ele/src/views/dashboard/analytics/index.vue deleted file mode 100644 index 5e3d6d2..0000000 --- a/apps/web-ele/src/views/dashboard/analytics/index.vue +++ /dev/null @@ -1,90 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/dashboard/workspace/index.vue b/apps/web-ele/src/views/dashboard/workspace/index.vue deleted file mode 100644 index b95d613..0000000 --- a/apps/web-ele/src/views/dashboard/workspace/index.vue +++ /dev/null @@ -1,266 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/demos/element/index.vue b/apps/web-ele/src/views/demos/element/index.vue deleted file mode 100644 index 0a7012d..0000000 --- a/apps/web-ele/src/views/demos/element/index.vue +++ /dev/null @@ -1,117 +0,0 @@ - - - diff --git a/apps/web-ele/src/views/demos/form/basic.vue b/apps/web-ele/src/views/demos/form/basic.vue deleted file mode 100644 index 0ecab58..0000000 --- a/apps/web-ele/src/views/demos/form/basic.vue +++ /dev/null @@ -1,191 +0,0 @@ - - diff --git a/apps/web-ele/tailwind.config.mjs b/apps/web-ele/tailwind.config.mjs deleted file mode 100644 index f17f556..0000000 --- a/apps/web-ele/tailwind.config.mjs +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@vben/tailwind-config'; diff --git a/apps/web-ele/tsconfig.json b/apps/web-ele/tsconfig.json deleted file mode 100644 index 02c287f..0000000 --- a/apps/web-ele/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@vben/tsconfig/web-app.json", - "compilerOptions": { - "baseUrl": ".", - "paths": { - "#/*": ["./src/*"] - } - }, - "references": [{ "path": "./tsconfig.node.json" }], - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/apps/web-ele/tsconfig.node.json b/apps/web-ele/tsconfig.node.json deleted file mode 100644 index c2f0d86..0000000 --- a/apps/web-ele/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@vben/tsconfig/node.json", - "compilerOptions": { - "composite": true, - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "noEmit": false - }, - "include": ["vite.config.mts"] -} diff --git a/apps/web-ele/vite.config.mts b/apps/web-ele/vite.config.mts deleted file mode 100644 index e2394f7..0000000 --- a/apps/web-ele/vite.config.mts +++ /dev/null @@ -1,25 +0,0 @@ -import { defineConfig } from '@vben/vite-config'; - -import ElementPlus from 'unplugin-element-plus/vite'; - -export default defineConfig(async () => { - return { - application: {}, - vite: { - plugins: [ - ElementPlus({ - format: 'esm', - }), - ], - server: { - proxy: { - '/api': { - changeOrigin: true, - // 本地联调:后端地址(保持 /api 前缀,不做 rewrite) - target: 'http://127.0.0.1:7801', - }, - }, - }, - }, - }; -}); diff --git a/apps/web-naive/.env b/apps/web-naive/.env deleted file mode 100644 index 213b52c..0000000 --- a/apps/web-naive/.env +++ /dev/null @@ -1,8 +0,0 @@ -# 应用标题 -VITE_APP_TITLE=Vben Admin Naive - -# 应用命名空间,用于缓存、store等功能的前缀,确保隔离 -VITE_APP_NAMESPACE=vben-web-naive - -# 对store进行加密的密钥,在将store持久化到localStorage时会使用该密钥进行加密 -VITE_APP_STORE_SECURE_KEY=please-replace-me-with-your-own-key diff --git a/apps/web-naive/.env.analyze b/apps/web-naive/.env.analyze deleted file mode 100644 index ffafa8d..0000000 --- a/apps/web-naive/.env.analyze +++ /dev/null @@ -1,7 +0,0 @@ -# public path -VITE_BASE=/ - -# Basic interface address SPA -VITE_GLOB_API_URL=/api - -VITE_VISUALIZER=true diff --git a/apps/web-naive/.env.development b/apps/web-naive/.env.development deleted file mode 100644 index 11c5254..0000000 --- a/apps/web-naive/.env.development +++ /dev/null @@ -1,16 +0,0 @@ -# 端口号 -VITE_PORT=5888 - -VITE_BASE=/ - -# 接口地址 -VITE_GLOB_API_URL=/api - -# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 -VITE_NITRO_MOCK=true - -# 是否打开 devtools,true 为打开,false 为关闭 -VITE_DEVTOOLS=false - -# 是否注入全局loading -VITE_INJECT_APP_LOADING=true diff --git a/apps/web-naive/.env.production b/apps/web-naive/.env.production deleted file mode 100644 index 5375847..0000000 --- a/apps/web-naive/.env.production +++ /dev/null @@ -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 diff --git a/apps/web-naive/index.html b/apps/web-naive/index.html deleted file mode 100644 index 7ea6384..0000000 --- a/apps/web-naive/index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - <%= VITE_APP_TITLE %> - - - - -
- - - diff --git a/apps/web-naive/package.json b/apps/web-naive/package.json deleted file mode 100644 index ff69374..0000000 --- a/apps/web-naive/package.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "@vben/web-naive", - "version": "5.5.9", - "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-naive" - }, - "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:", - "naive-ui": "catalog:", - "pinia": "catalog:", - "vue": "catalog:", - "vue-router": "catalog:" - } -} diff --git a/apps/web-naive/postcss.config.mjs b/apps/web-naive/postcss.config.mjs deleted file mode 100644 index 3d80704..0000000 --- a/apps/web-naive/postcss.config.mjs +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@vben/tailwind-config/postcss'; diff --git a/apps/web-naive/public/favicon.ico b/apps/web-naive/public/favicon.ico deleted file mode 100644 index fcf9818..0000000 Binary files a/apps/web-naive/public/favicon.ico and /dev/null differ diff --git a/apps/web-naive/src/adapter/component/index.ts b/apps/web-naive/src/adapter/component/index.ts deleted file mode 100644 index f9df202..0000000 --- a/apps/web-naive/src/adapter/component/index.ts +++ /dev/null @@ -1,231 +0,0 @@ -/** - * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用 - * 可用于 vben-form、vben-modal、vben-drawer 等组件使用, - */ - -import type { Component } from 'vue'; - -import type { BaseFormComponentType } from '@vben/common-ui'; -import type { Recordable } from '@vben/types'; - -import { defineAsyncComponent, defineComponent, h, ref } from 'vue'; - -import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; -import { $t } from '@vben/locales'; - -import { message } from '#/adapter/naive'; - -const NButton = defineAsyncComponent(() => - import('naive-ui/es/button').then((res) => res.NButton), -); -const NCheckbox = defineAsyncComponent(() => - import('naive-ui/es/checkbox').then((res) => res.NCheckbox), -); -const NCheckboxGroup = defineAsyncComponent(() => - import('naive-ui/es/checkbox').then((res) => res.NCheckboxGroup), -); -const NDatePicker = defineAsyncComponent(() => - import('naive-ui/es/date-picker').then((res) => res.NDatePicker), -); -const NDivider = defineAsyncComponent(() => - import('naive-ui/es/divider').then((res) => res.NDivider), -); -const NInput = defineAsyncComponent(() => - import('naive-ui/es/input').then((res) => res.NInput), -); -const NInputNumber = defineAsyncComponent(() => - import('naive-ui/es/input-number').then((res) => res.NInputNumber), -); -const NRadio = defineAsyncComponent(() => - import('naive-ui/es/radio').then((res) => res.NRadio), -); -const NRadioButton = defineAsyncComponent(() => - import('naive-ui/es/radio').then((res) => res.NRadioButton), -); -const NRadioGroup = defineAsyncComponent(() => - import('naive-ui/es/radio').then((res) => res.NRadioGroup), -); -const NSelect = defineAsyncComponent(() => - import('naive-ui/es/select').then((res) => res.NSelect), -); -const NSpace = defineAsyncComponent(() => - import('naive-ui/es/space').then((res) => res.NSpace), -); -const NSwitch = defineAsyncComponent(() => - import('naive-ui/es/switch').then((res) => res.NSwitch), -); -const NTimePicker = defineAsyncComponent(() => - import('naive-ui/es/time-picker').then((res) => res.NTimePicker), -); -const NTreeSelect = defineAsyncComponent(() => - import('naive-ui/es/tree-select').then((res) => res.NTreeSelect), -); -const NUpload = defineAsyncComponent(() => - import('naive-ui/es/upload').then((res) => res.NUpload), -); - -const withDefaultPlaceholder = ( - component: T, - type: 'input' | 'select', - componentProps: Recordable = {}, -) => { - 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, - ); - }, - }); -}; - -// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明 -export type ComponentType = - | 'ApiSelect' - | 'ApiTreeSelect' - | 'Checkbox' - | 'CheckboxGroup' - | 'DatePicker' - | 'Divider' - | 'IconPicker' - | 'Input' - | 'InputNumber' - | 'RadioGroup' - | 'Select' - | 'Space' - | 'Switch' - | 'TimePicker' - | 'TreeSelect' - | 'Upload' - | BaseFormComponentType; - -async function initComponentAdapter() { - const components: Partial> = { - // 如果你的组件体积比较大,可以使用异步加载 - // Button: () => - // import('xxx').then((res) => res.Button), - - ApiSelect: withDefaultPlaceholder( - { - ...ApiComponent, - name: 'ApiSelect', - }, - 'select', - { - component: NSelect, - modelPropName: 'value', - }, - ), - ApiTreeSelect: withDefaultPlaceholder( - { - ...ApiComponent, - name: 'ApiTreeSelect', - }, - 'select', - { - component: NTreeSelect, - nodeKey: 'value', - loadingSlot: 'arrow', - keyField: 'value', - modelPropName: 'value', - optionsPropName: 'options', - visibleEvent: 'onVisibleChange', - }, - ), - Checkbox: NCheckbox, - CheckboxGroup: (props, { attrs, slots }) => { - let defaultSlot; - if (Reflect.has(slots, 'default')) { - defaultSlot = slots.default; - } else { - const { options } = attrs; - if (Array.isArray(options)) { - defaultSlot = () => options.map((option) => h(NCheckbox, option)); - } - } - return h( - NCheckboxGroup, - { ...props, ...attrs }, - { default: defaultSlot }, - ); - }, - DatePicker: NDatePicker, - // 自定义默认按钮 - DefaultButton: (props, { attrs, slots }) => { - return h(NButton, { ...props, attrs, type: 'default' }, slots); - }, - // 自定义主要按钮 - PrimaryButton: (props, { attrs, slots }) => { - return h(NButton, { ...props, attrs, type: 'primary' }, slots); - }, - Divider: NDivider, - IconPicker: withDefaultPlaceholder(IconPicker, 'select', { - iconSlot: 'suffix', - inputComponent: NInput, - }), - Input: withDefaultPlaceholder(NInput, 'input'), - InputNumber: withDefaultPlaceholder(NInputNumber, 'input'), - RadioGroup: (props, { attrs, slots }) => { - let defaultSlot; - if (Reflect.has(slots, 'default')) { - defaultSlot = slots.default; - } else { - const { options } = attrs; - if (Array.isArray(options)) { - defaultSlot = () => - options.map((option) => - h(attrs.isButton ? NRadioButton : NRadio, option), - ); - } - } - const groupRender = h( - NRadioGroup, - { ...props, ...attrs }, - { default: defaultSlot }, - ); - return attrs.isButton - ? h(NSpace, { vertical: true }, () => groupRender) - : groupRender; - }, - Select: withDefaultPlaceholder(NSelect, 'select'), - Space: NSpace, - Switch: NSwitch, - TimePicker: NTimePicker, - TreeSelect: withDefaultPlaceholder(NTreeSelect, 'select'), - Upload: NUpload, - }; - - // 将组件注册到全局共享状态中 - globalShareState.setComponents(components); - - // 定义全局共享状态中的消息提示 - globalShareState.defineMessage({ - // 复制成功消息提示 - copyPreferencesSuccess: (title, content) => { - message.success(content || title, { - duration: 0, - }); - }, - }); -} - -export { initComponentAdapter }; diff --git a/apps/web-naive/src/adapter/form.ts b/apps/web-naive/src/adapter/form.ts deleted file mode 100644 index 9de44a0..0000000 --- a/apps/web-naive/src/adapter/form.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { - VbenFormSchema as FormSchema, - VbenFormProps, -} from '@vben/common-ui'; - -import type { ComponentType } from './component'; - -import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; -import { $t } from '@vben/locales'; - -async function initSetupVbenForm() { - setupVbenForm({ - config: { - // naive-ui组件的空值为null,不能是undefined,否则重置表单时不生效 - emptyStateValue: null, - baseModelPropName: 'value', - modelPropNameMap: { - Checkbox: 'checked', - Radio: '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; - -export { initSetupVbenForm, useVbenForm, z }; - -export type VbenFormSchema = FormSchema; -export type { VbenFormProps }; diff --git a/apps/web-naive/src/adapter/naive.ts b/apps/web-naive/src/adapter/naive.ts deleted file mode 100644 index 1eb7b7b..0000000 --- a/apps/web-naive/src/adapter/naive.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { computed } from 'vue'; - -import { preferences } from '@vben/preferences'; -import '@vben/styles'; - -import { createDiscreteApi, darkTheme, lightTheme } from 'naive-ui'; - -const themeOverridesProviderProps = computed(() => ({ - themeOverrides: preferences.theme.mode === 'light' ? lightTheme : darkTheme, -})); - -const themeProviderProps = computed(() => ({ - theme: preferences.theme.mode === 'light' ? lightTheme : darkTheme, -})); - -export const { dialog, loadingBar, message, modal, notification } = - createDiscreteApi( - ['message', 'dialog', 'notification', 'loadingBar', 'modal'], - { - configProviderProps: themeProviderProps, - loadingBarProviderProps: themeOverridesProviderProps, - messageProviderProps: themeOverridesProviderProps, - notificationProviderProps: themeOverridesProviderProps, - }, - ); diff --git a/apps/web-naive/src/adapter/vxe-table.ts b/apps/web-naive/src/adapter/vxe-table.ts deleted file mode 100644 index 1c36000..0000000 --- a/apps/web-naive/src/adapter/vxe-table.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; - -import { h } from 'vue'; - -import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; - -import { NButton, NImage } from 'naive-ui'; - -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(NImage, { src: row[column.field], ...props }); - }, - }); - - // 表格配置项可以用 cellRender: { name: 'CellLink' }, - vxeUI.renderer.add('CellLink', { - renderTableDefault(renderOpts) { - const { props } = renderOpts; - return h( - NButton, - { size: 'small', type: 'primary', quaternary: true }, - { default: () => props?.text }, - ); - }, - }); - - // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 - // vxeUI.formats.add - }, - useVbenForm, -}); - -export { useVbenVxeGrid }; - -export type * from '@vben/plugins/vxe-table'; diff --git a/apps/web-naive/src/api/core/auth.ts b/apps/web-naive/src/api/core/auth.ts deleted file mode 100644 index 71d9f99..0000000 --- a/apps/web-naive/src/api/core/auth.ts +++ /dev/null @@ -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('/auth/login', data); -} - -/** - * 刷新accessToken - */ -export async function refreshTokenApi() { - return baseRequestClient.post('/auth/refresh', { - withCredentials: true, - }); -} - -/** - * 退出登录 - */ -export async function logoutApi() { - return baseRequestClient.post('/auth/logout', { - withCredentials: true, - }); -} - -/** - * 获取用户权限码 - */ -export async function getAccessCodesApi() { - return requestClient.get('/auth/codes'); -} diff --git a/apps/web-naive/src/api/core/index.ts b/apps/web-naive/src/api/core/index.ts deleted file mode 100644 index 28a5aef..0000000 --- a/apps/web-naive/src/api/core/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './auth'; -export * from './menu'; -export * from './user'; diff --git a/apps/web-naive/src/api/core/menu.ts b/apps/web-naive/src/api/core/menu.ts deleted file mode 100644 index 9ef60b1..0000000 --- a/apps/web-naive/src/api/core/menu.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { RouteRecordStringComponent } from '@vben/types'; - -import { requestClient } from '#/api/request'; - -/** - * 获取用户所有菜单 - */ -export async function getAllMenusApi() { - return requestClient.get('/menu/all'); -} diff --git a/apps/web-naive/src/api/core/user.ts b/apps/web-naive/src/api/core/user.ts deleted file mode 100644 index 7e28ea8..0000000 --- a/apps/web-naive/src/api/core/user.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { UserInfo } from '@vben/types'; - -import { requestClient } from '#/api/request'; - -/** - * 获取用户信息 - */ -export async function getUserInfoApi() { - return requestClient.get('/user/info'); -} diff --git a/apps/web-naive/src/api/index.ts b/apps/web-naive/src/api/index.ts deleted file mode 100644 index 4b0e041..0000000 --- a/apps/web-naive/src/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './core'; diff --git a/apps/web-naive/src/api/request.ts b/apps/web-naive/src/api/request.ts deleted file mode 100644 index f8fbacc..0000000 --- a/apps/web-naive/src/api/request.ts +++ /dev/null @@ -1,112 +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 '#/adapter/naive'; -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 }); diff --git a/apps/web-naive/src/app.vue b/apps/web-naive/src/app.vue deleted file mode 100644 index 23983c5..0000000 --- a/apps/web-naive/src/app.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - diff --git a/apps/web-naive/src/bootstrap.ts b/apps/web-naive/src/bootstrap.ts deleted file mode 100644 index df0b2cb..0000000 --- a/apps/web-naive/src/bootstrap.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { createApp, watchEffect } from 'vue'; - -import { registerAccessDirective } from '@vben/access'; -import { registerLoadingDirective } from '@vben/common-ui'; -import { preferences } from '@vben/preferences'; -import { initStores } from '@vben/stores'; -import '@vben/styles'; -import '@vben/styles/naive'; - -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: 2000, - // }); - - 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 }; diff --git a/apps/web-naive/src/layouts/auth.vue b/apps/web-naive/src/layouts/auth.vue deleted file mode 100644 index 8ba66e8..0000000 --- a/apps/web-naive/src/layouts/auth.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/apps/web-naive/src/layouts/basic.vue b/apps/web-naive/src/layouts/basic.vue deleted file mode 100644 index f8b5c81..0000000 --- a/apps/web-naive/src/layouts/basic.vue +++ /dev/null @@ -1,207 +0,0 @@ - - - diff --git a/apps/web-naive/src/layouts/index.ts b/apps/web-naive/src/layouts/index.ts deleted file mode 100644 index a432078..0000000 --- a/apps/web-naive/src/layouts/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-naive/src/locales/README.md b/apps/web-naive/src/locales/README.md deleted file mode 100644 index 7b45103..0000000 --- a/apps/web-naive/src/locales/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# locale - -每个app使用的国际化可能不同,这里用于扩展国际化的功能,例如扩展 dayjs、antd组件库的多语言切换,以及app本身的国际化文件。 diff --git a/apps/web-naive/src/locales/index.ts b/apps/web-naive/src/locales/index.ts deleted file mode 100644 index 58f63c1..0000000 --- a/apps/web-naive/src/locales/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { App } from 'vue'; - -import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales'; - -import { - $t, - setupI18n as coreSetup, - loadLocalesMapFromDir, -} from '@vben/locales'; -import { preferences } from '@vben/preferences'; - -const modules = import.meta.glob('./langs/**/*.json'); - -const localesMap = loadLocalesMapFromDir( - /\.\/langs\/([^/]+)\/(.*)\.json$/, - modules, -); - -/** - * 加载应用特有的语言包 - * 这里也可以改造为从服务端获取翻译数据 - * @param lang - */ -async function loadMessages(lang: SupportedLanguagesType) { - const appLocaleMessages = await localesMap[lang]?.(); - return appLocaleMessages?.default; -} - -async function setupI18n(app: App, options: LocaleSetupOptions = {}) { - await coreSetup(app, { - defaultLocale: preferences.app.locale, - loadMessages, - missingWarn: !import.meta.env.PROD, - ...options, - }); -} - -export { $t, setupI18n }; diff --git a/apps/web-naive/src/locales/langs/en-US/demos.json b/apps/web-naive/src/locales/langs/en-US/demos.json deleted file mode 100644 index 3128b0b..0000000 --- a/apps/web-naive/src/locales/langs/en-US/demos.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "title": "Demos", - "naive": "Naive UI", - "table": "Table", - "form": "Form", - "vben": { - "title": "Project", - "about": "About", - "document": "Document", - "antdv": "Ant Design Vue Version", - "naive-ui": "Naive UI Version", - "element-plus": "Element Plus Version", - "tdesign": "TDesign Vue Version" - } -} diff --git a/apps/web-naive/src/locales/langs/en-US/page.json b/apps/web-naive/src/locales/langs/en-US/page.json deleted file mode 100644 index 39f1641..0000000 --- a/apps/web-naive/src/locales/langs/en-US/page.json +++ /dev/null @@ -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" - } -} diff --git a/apps/web-naive/src/locales/langs/zh-CN/demos.json b/apps/web-naive/src/locales/langs/zh-CN/demos.json deleted file mode 100644 index 3c3957a..0000000 --- a/apps/web-naive/src/locales/langs/zh-CN/demos.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "title": "演示", - "naive": "Naive UI", - "table": "Table", - "form": "表单", - "vben": { - "title": "项目", - "about": "关于", - "document": "文档", - "antdv": "Ant Design Vue 版本", - "naive-ui": "Naive UI 版本", - "element-plus": "Element Plus 版本", - "tdesign": "TDesign Vue 版本" - } -} diff --git a/apps/web-naive/src/locales/langs/zh-CN/page.json b/apps/web-naive/src/locales/langs/zh-CN/page.json deleted file mode 100644 index 2192d1d..0000000 --- a/apps/web-naive/src/locales/langs/zh-CN/page.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "auth": { - "login": "登录", - "register": "注册", - "codeLogin": "验证码登录", - "qrcodeLogin": "二维码登录", - "forgetPassword": "忘记密码", - "profile": "个人中心" - }, - "dashboard": { - "title": "概览", - "analytics": "分析页", - "workspace": "工作台" - } -} diff --git a/apps/web-naive/src/main.ts b/apps/web-naive/src/main.ts deleted file mode 100644 index 5d728a0..0000000 --- a/apps/web-naive/src/main.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { initPreferences } from '@vben/preferences'; -import { unmountGlobalLoading } from '@vben/utils'; - -import { overridesPreferences } from './preferences'; - -/** - * 应用初始化完成之后再进行页面加载渲染 - */ -async function initApplication() { - // name用于指定项目唯一标识 - // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据 - const env = import.meta.env.PROD ? 'prod' : 'dev'; - const appVersion = import.meta.env.VITE_APP_VERSION; - const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`; - - // app偏好设置初始化 - await initPreferences({ - namespace, - overrides: overridesPreferences, - }); - - // 启动应用并挂载 - // vue应用主要逻辑及视图 - const { bootstrap } = await import('./bootstrap'); - await bootstrap(namespace); - - // 移除并销毁loading - unmountGlobalLoading(); -} - -initApplication(); diff --git a/apps/web-naive/src/preferences.ts b/apps/web-naive/src/preferences.ts deleted file mode 100644 index b2e9ace..0000000 --- a/apps/web-naive/src/preferences.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { defineOverridesPreferences } from '@vben/preferences'; - -/** - * @description 项目配置文件 - * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置 - * !!! 更改配置后请清空缓存,否则可能不生效 - */ -export const overridesPreferences = defineOverridesPreferences({ - // overrides - app: { - name: import.meta.env.VITE_APP_TITLE, - }, -}); diff --git a/apps/web-naive/src/router/access.ts b/apps/web-naive/src/router/access.ts deleted file mode 100644 index 7a80bac..0000000 --- a/apps/web-naive/src/router/access.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { - ComponentRecordType, - GenerateMenuAndRoutesOptions, -} from '@vben/types'; - -import { generateAccessible } from '@vben/access'; -import { preferences } from '@vben/preferences'; - -import { message } from '#/adapter/naive'; -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(`${$t('common.loadingMenu')}...`, { - duration: 1.5, - }); - return await getAllMenusApi(); - }, - // 可以指定没有权限跳转403页面 - forbiddenComponent, - // 如果 route.meta.menuVisibleWithForbidden = true - layoutMap, - pageMap, - }); -} - -export { generateAccess }; diff --git a/apps/web-naive/src/router/guard.ts b/apps/web-naive/src/router/guard.ts deleted file mode 100644 index 28d1cea..0000000 --- a/apps/web-naive/src/router/guard.ts +++ /dev/null @@ -1,132 +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(); - - 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 }; diff --git a/apps/web-naive/src/router/index.ts b/apps/web-naive/src/router/index.ts deleted file mode 100644 index 4840230..0000000 --- a/apps/web-naive/src/router/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-naive/src/router/routes/core.ts b/apps/web-naive/src/router/routes/core.ts deleted file mode 100644 index 949b0b6..0000000 --- a/apps/web-naive/src/router/routes/core.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-naive/src/router/routes/index.ts b/apps/web-naive/src/router/routes/index.ts deleted file mode 100644 index e6fb144..0000000 --- a/apps/web-naive/src/router/routes/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-naive/src/router/routes/modules/dashboard.ts b/apps/web-naive/src/router/routes/modules/dashboard.ts deleted file mode 100644 index 5254dc6..0000000 --- a/apps/web-naive/src/router/routes/modules/dashboard.ts +++ /dev/null @@ -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; diff --git a/apps/web-naive/src/router/routes/modules/demos.ts b/apps/web-naive/src/router/routes/modules/demos.ts deleted file mode 100644 index 5e49ffa..0000000 --- a/apps/web-naive/src/router/routes/modules/demos.ts +++ /dev/null @@ -1,44 +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.naive'), - }, - name: 'NaiveDemos', - path: '/demos/naive', - component: () => import('#/views/demos/naive/index.vue'), - }, - { - meta: { - title: $t('demos.table'), - }, - name: 'Table', - path: '/demos/table', - component: () => import('#/views/demos/table/index.vue'), - }, - { - meta: { - title: $t('demos.form'), - }, - name: 'Form', - path: '/demos/form', - component: () => import('#/views/demos/form/basic.vue'), - }, - ], - }, -]; - -export default routes; diff --git a/apps/web-naive/src/router/routes/modules/vben.ts b/apps/web-naive/src/router/routes/modules/vben.ts deleted file mode 100644 index 32c21ca..0000000 --- a/apps/web-naive/src/router/routes/modules/vben.ts +++ /dev/null @@ -1,104 +0,0 @@ -import type { RouteRecordRaw } from 'vue-router'; - -import { - VBEN_ANT_PREVIEW_URL, - VBEN_DOC_URL, - VBEN_ELE_PREVIEW_URL, - VBEN_GITHUB_URL, - VBEN_LOGO_URL, - VBEN_TD_PREVIEW_URL, -} from '@vben/constants'; -import { SvgAntdvLogoIcon, 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: 'VbenAntd', - path: '/vben-admin/antd', - component: IFrameView, - meta: { - badgeType: 'dot', - icon: SvgAntdvLogoIcon, - link: VBEN_ANT_PREVIEW_URL, - title: $t('demos.vben.antdv'), - }, - }, - { - 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; diff --git a/apps/web-naive/src/store/auth.ts b/apps/web-naive/src/store/auth.ts deleted file mode 100644 index 0ff050b..0000000 --- a/apps/web-naive/src/store/auth.ts +++ /dev/null @@ -1,119 +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 { defineStore } from 'pinia'; - -import { notification } from '#/adapter/naive'; -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, - onSuccess?: () => Promise | void, - ) { - // 异步处理用户登录操作并获取 accessToken - let userInfo: null | UserInfo = null; - try { - loginLoading.value = true; - const { accessToken } = await loginApi(params); - - // 如果成功获取到 accessToken - if (accessToken) { - // 将 accessToken 存储到 accessStore 中 - 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({ - content: $t('authentication.loginSuccess'), - description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`, - duration: 3000, - }); - } - } - } 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() { - let userInfo: null | UserInfo = null; - userInfo = await getUserInfoApi(); - userStore.setUserInfo(userInfo); - return userInfo; - } - - function $reset() { - loginLoading.value = false; - } - - return { - $reset, - authLogin, - fetchUserInfo, - loginLoading, - logout, - }; -}); diff --git a/apps/web-naive/src/store/index.ts b/apps/web-naive/src/store/index.ts deleted file mode 100644 index 269586e..0000000 --- a/apps/web-naive/src/store/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './auth'; diff --git a/apps/web-naive/src/views/_core/README.md b/apps/web-naive/src/views/_core/README.md deleted file mode 100644 index 8248afe..0000000 --- a/apps/web-naive/src/views/_core/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# \_core - -此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。 diff --git a/apps/web-naive/src/views/_core/about/index.vue b/apps/web-naive/src/views/_core/about/index.vue deleted file mode 100644 index 0ee5243..0000000 --- a/apps/web-naive/src/views/_core/about/index.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/authentication/code-login.vue b/apps/web-naive/src/views/_core/authentication/code-login.vue deleted file mode 100644 index acfd1fd..0000000 --- a/apps/web-naive/src/views/_core/authentication/code-login.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/authentication/forget-password.vue b/apps/web-naive/src/views/_core/authentication/forget-password.vue deleted file mode 100644 index fef0d42..0000000 --- a/apps/web-naive/src/views/_core/authentication/forget-password.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/authentication/login.vue b/apps/web-naive/src/views/_core/authentication/login.vue deleted file mode 100644 index 099e4c8..0000000 --- a/apps/web-naive/src/views/_core/authentication/login.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/authentication/qrcode-login.vue b/apps/web-naive/src/views/_core/authentication/qrcode-login.vue deleted file mode 100644 index 23f5f2d..0000000 --- a/apps/web-naive/src/views/_core/authentication/qrcode-login.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/authentication/register.vue b/apps/web-naive/src/views/_core/authentication/register.vue deleted file mode 100644 index daf89c4..0000000 --- a/apps/web-naive/src/views/_core/authentication/register.vue +++ /dev/null @@ -1,96 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/fallback/coming-soon.vue b/apps/web-naive/src/views/_core/fallback/coming-soon.vue deleted file mode 100644 index f394930..0000000 --- a/apps/web-naive/src/views/_core/fallback/coming-soon.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/fallback/forbidden.vue b/apps/web-naive/src/views/_core/fallback/forbidden.vue deleted file mode 100644 index 8ea65fe..0000000 --- a/apps/web-naive/src/views/_core/fallback/forbidden.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/fallback/internal-error.vue b/apps/web-naive/src/views/_core/fallback/internal-error.vue deleted file mode 100644 index 819a47d..0000000 --- a/apps/web-naive/src/views/_core/fallback/internal-error.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/fallback/not-found.vue b/apps/web-naive/src/views/_core/fallback/not-found.vue deleted file mode 100644 index 4d178e9..0000000 --- a/apps/web-naive/src/views/_core/fallback/not-found.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/fallback/offline.vue b/apps/web-naive/src/views/_core/fallback/offline.vue deleted file mode 100644 index 5de4a88..0000000 --- a/apps/web-naive/src/views/_core/fallback/offline.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/_core/profile/base-setting.vue b/apps/web-naive/src/views/_core/profile/base-setting.vue deleted file mode 100644 index aa8a4c2..0000000 --- a/apps/web-naive/src/views/_core/profile/base-setting.vue +++ /dev/null @@ -1,65 +0,0 @@ - - diff --git a/apps/web-naive/src/views/_core/profile/index.vue b/apps/web-naive/src/views/_core/profile/index.vue deleted file mode 100644 index 8740894..0000000 --- a/apps/web-naive/src/views/_core/profile/index.vue +++ /dev/null @@ -1,49 +0,0 @@ - - diff --git a/apps/web-naive/src/views/_core/profile/notification-setting.vue b/apps/web-naive/src/views/_core/profile/notification-setting.vue deleted file mode 100644 index 324a4b3..0000000 --- a/apps/web-naive/src/views/_core/profile/notification-setting.vue +++ /dev/null @@ -1,31 +0,0 @@ - - diff --git a/apps/web-naive/src/views/_core/profile/password-setting.vue b/apps/web-naive/src/views/_core/profile/password-setting.vue deleted file mode 100644 index 9857dc8..0000000 --- a/apps/web-naive/src/views/_core/profile/password-setting.vue +++ /dev/null @@ -1,63 +0,0 @@ - - diff --git a/apps/web-naive/src/views/_core/profile/security-setting.vue b/apps/web-naive/src/views/_core/profile/security-setting.vue deleted file mode 100644 index be30db5..0000000 --- a/apps/web-naive/src/views/_core/profile/security-setting.vue +++ /dev/null @@ -1,43 +0,0 @@ - - diff --git a/apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue b/apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue deleted file mode 100644 index f1f0b23..0000000 --- a/apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue b/apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue deleted file mode 100644 index 190fb41..0000000 --- a/apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue b/apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue deleted file mode 100644 index 6ff5208..0000000 --- a/apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue b/apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue deleted file mode 100644 index 0915c7a..0000000 --- a/apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue b/apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue deleted file mode 100644 index 7e0f101..0000000 --- a/apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/dashboard/analytics/index.vue b/apps/web-naive/src/views/dashboard/analytics/index.vue deleted file mode 100644 index 5e3d6d2..0000000 --- a/apps/web-naive/src/views/dashboard/analytics/index.vue +++ /dev/null @@ -1,90 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/dashboard/workspace/index.vue b/apps/web-naive/src/views/dashboard/workspace/index.vue deleted file mode 100644 index b95d613..0000000 --- a/apps/web-naive/src/views/dashboard/workspace/index.vue +++ /dev/null @@ -1,266 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/demos/form/basic.vue b/apps/web-naive/src/views/demos/form/basic.vue deleted file mode 100644 index 60702a1..0000000 --- a/apps/web-naive/src/views/demos/form/basic.vue +++ /dev/null @@ -1,169 +0,0 @@ - - diff --git a/apps/web-naive/src/views/demos/form/modal.vue b/apps/web-naive/src/views/demos/form/modal.vue deleted file mode 100644 index 52e2354..0000000 --- a/apps/web-naive/src/views/demos/form/modal.vue +++ /dev/null @@ -1,71 +0,0 @@ - - diff --git a/apps/web-naive/src/views/demos/naive/index.vue b/apps/web-naive/src/views/demos/naive/index.vue deleted file mode 100644 index f72cdb2..0000000 --- a/apps/web-naive/src/views/demos/naive/index.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - diff --git a/apps/web-naive/src/views/demos/table/index.vue b/apps/web-naive/src/views/demos/table/index.vue deleted file mode 100644 index ddc958b..0000000 --- a/apps/web-naive/src/views/demos/table/index.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - - - diff --git a/apps/web-naive/tailwind.config.mjs b/apps/web-naive/tailwind.config.mjs deleted file mode 100644 index f17f556..0000000 --- a/apps/web-naive/tailwind.config.mjs +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@vben/tailwind-config'; diff --git a/apps/web-naive/tsconfig.json b/apps/web-naive/tsconfig.json deleted file mode 100644 index 02c287f..0000000 --- a/apps/web-naive/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@vben/tsconfig/web-app.json", - "compilerOptions": { - "baseUrl": ".", - "paths": { - "#/*": ["./src/*"] - } - }, - "references": [{ "path": "./tsconfig.node.json" }], - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/apps/web-naive/tsconfig.node.json b/apps/web-naive/tsconfig.node.json deleted file mode 100644 index c2f0d86..0000000 --- a/apps/web-naive/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@vben/tsconfig/node.json", - "compilerOptions": { - "composite": true, - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "noEmit": false - }, - "include": ["vite.config.mts"] -} diff --git a/apps/web-naive/vite.config.mts b/apps/web-naive/vite.config.mts deleted file mode 100644 index b6360f1..0000000 --- a/apps/web-naive/vite.config.mts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineConfig } from '@vben/vite-config'; - -export default defineConfig(async () => { - return { - application: {}, - vite: { - server: { - proxy: { - '/api': { - changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, ''), - // mock代理目标地址 - target: 'http://localhost:5320/api', - ws: true, - }, - }, - }, - }, - }; -}); diff --git a/apps/web-tdesign/.env b/apps/web-tdesign/.env deleted file mode 100644 index dae0149..0000000 --- a/apps/web-tdesign/.env +++ /dev/null @@ -1,8 +0,0 @@ -# 应用标题 -VITE_APP_TITLE=Vben Admin Tdesign - -# 应用命名空间,用于缓存、store等功能的前缀,确保隔离 -VITE_APP_NAMESPACE=vben-web-tdesign - -# 对store进行加密的密钥,在将store持久化到localStorage时会使用该密钥进行加密 -VITE_APP_STORE_SECURE_KEY=please-replace-me-with-your-own-key diff --git a/apps/web-tdesign/.env.analyze b/apps/web-tdesign/.env.analyze deleted file mode 100644 index ffafa8d..0000000 --- a/apps/web-tdesign/.env.analyze +++ /dev/null @@ -1,7 +0,0 @@ -# public path -VITE_BASE=/ - -# Basic interface address SPA -VITE_GLOB_API_URL=/api - -VITE_VISUALIZER=true diff --git a/apps/web-tdesign/.env.development b/apps/web-tdesign/.env.development deleted file mode 100644 index f2b4442..0000000 --- a/apps/web-tdesign/.env.development +++ /dev/null @@ -1,16 +0,0 @@ -# 端口号 -VITE_PORT=5999 - -VITE_BASE=/ - -# 接口地址 -VITE_GLOB_API_URL=/api - -# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 -VITE_NITRO_MOCK=true - -# 是否打开 devtools,true 为打开,false 为关闭 -VITE_DEVTOOLS=false - -# 是否注入全局loading -VITE_INJECT_APP_LOADING=true diff --git a/apps/web-tdesign/.env.production b/apps/web-tdesign/.env.production deleted file mode 100644 index 5375847..0000000 --- a/apps/web-tdesign/.env.production +++ /dev/null @@ -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 diff --git a/apps/web-tdesign/index.html b/apps/web-tdesign/index.html deleted file mode 100644 index 480eb84..0000000 --- a/apps/web-tdesign/index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - <%= VITE_APP_TITLE %> - - - - -
- - - diff --git a/apps/web-tdesign/package.json b/apps/web-tdesign/package.json deleted file mode 100644 index aa504d3..0000000 --- a/apps/web-tdesign/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@vben/web-tdesign", - "version": "5.5.9", - "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-tdesign" - }, - "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:", - "dayjs": "catalog:", - "es-toolkit": "catalog:", - "pinia": "catalog:", - "tdesign-vue-next": "catalog:", - "vue": "catalog:", - "vue-router": "catalog:" - } -} diff --git a/apps/web-tdesign/postcss.config.mjs b/apps/web-tdesign/postcss.config.mjs deleted file mode 100644 index 3d80704..0000000 --- a/apps/web-tdesign/postcss.config.mjs +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@vben/tailwind-config/postcss'; diff --git a/apps/web-tdesign/public/favicon.ico b/apps/web-tdesign/public/favicon.ico deleted file mode 100644 index fcf9818..0000000 Binary files a/apps/web-tdesign/public/favicon.ico and /dev/null differ diff --git a/apps/web-tdesign/src/adapter/component/index.ts b/apps/web-tdesign/src/adapter/component/index.ts deleted file mode 100644 index b7fc054..0000000 --- a/apps/web-tdesign/src/adapter/component/index.ts +++ /dev/null @@ -1,229 +0,0 @@ -import type { Component } from 'vue'; - -import type { BaseFormComponentType } from '@vben/common-ui'; -import type { Recordable } from '@vben/types'; - -import { defineAsyncComponent, defineComponent, h, ref } from 'vue'; - -import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; -import { $t } from '@vben/locales'; - -import { notification } from '#/adapter/tdesign'; - -/** - * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用 - * 可用于 vben-form、vben-modal、vben-drawer 等组件使用, - */ - -const AutoComplete = defineAsyncComponent( - () => import('tdesign-vue-next/es/auto-complete'), -); -const Button = defineAsyncComponent(() => import('tdesign-vue-next/es/button')); -const Checkbox = defineAsyncComponent( - () => import('tdesign-vue-next/es/checkbox'), -); -const CheckboxGroup = defineAsyncComponent(() => - import('tdesign-vue-next/es/checkbox').then((res) => res.CheckboxGroup), -); -const DatePicker = defineAsyncComponent( - () => import('tdesign-vue-next/es/date-picker'), -); -const Divider = defineAsyncComponent( - () => import('tdesign-vue-next/es/divider'), -); -const Input = defineAsyncComponent(() => import('tdesign-vue-next/es/input')); -const InputNumber = defineAsyncComponent( - () => import('tdesign-vue-next/es/input-number'), -); -// const InputPassword = defineAsyncComponent(() => -// import('tdesign-vue-next/es/input').then((res) => res.InputPassword), -// ); -// const Mentions = defineAsyncComponent( -// () => import('tdesign-vue-next/es/mentions'), -// ); -const Radio = defineAsyncComponent(() => import('tdesign-vue-next/es/radio')); -const RadioGroup = defineAsyncComponent(() => - import('tdesign-vue-next/es/radio').then((res) => res.RadioGroup), -); -const RangePicker = defineAsyncComponent(() => - import('tdesign-vue-next/es/date-picker').then((res) => res.DateRangePicker), -); -const Rate = defineAsyncComponent(() => import('tdesign-vue-next/es/rate')); -const Select = defineAsyncComponent(() => import('tdesign-vue-next/es/select')); -const Space = defineAsyncComponent(() => import('tdesign-vue-next/es/space')); -const Switch = defineAsyncComponent(() => import('tdesign-vue-next/es/switch')); -const Textarea = defineAsyncComponent( - () => import('tdesign-vue-next/es/textarea'), -); -const TimePicker = defineAsyncComponent( - () => import('tdesign-vue-next/es/time-picker'), -); -const TreeSelect = defineAsyncComponent( - () => import('tdesign-vue-next/es/tree-select'), -); -const Upload = defineAsyncComponent(() => import('tdesign-vue-next/es/upload')); - -const withDefaultPlaceholder = ( - component: T, - type: 'input' | 'select', - componentProps: Recordable = {}, -) => { - 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, - ); - }, - }); -}; - -// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明 -export type ComponentType = - | 'ApiSelect' - | 'ApiTreeSelect' - | 'AutoComplete' - | 'Checkbox' - | 'CheckboxGroup' - | 'DatePicker' - | 'DefaultButton' - | 'Divider' - | 'IconPicker' - | 'Input' - | 'InputNumber' - // | 'InputPassword' - // | 'Mentions' - | 'PrimaryButton' - | 'Radio' - | 'RadioGroup' - | 'RangePicker' - | 'Rate' - | 'Select' - | 'Space' - | 'Switch' - | 'Textarea' - | 'TimePicker' - | 'TreeSelect' - | 'Upload' - | BaseFormComponentType; - -async function initComponentAdapter() { - const components: Partial> = { - // 如果你的组件体积比较大,可以使用异步加载 - // Button: () => - // import('xxx').then((res) => res.Button), - ApiSelect: withDefaultPlaceholder( - { - ...ApiComponent, - name: 'ApiSelect', - }, - 'select', - { - component: Select, - loadingSlot: 'suffixIcon', - visibleEvent: 'onDropdownVisibleChange', - modelPropName: 'value', - }, - ), - ApiTreeSelect: withDefaultPlaceholder( - { - ...ApiComponent, - name: 'ApiTreeSelect', - }, - 'select', - { - component: TreeSelect, - fieldNames: { label: 'label', value: 'value', children: 'children' }, - loadingSlot: 'suffixIcon', - modelPropName: 'value', - optionsPropName: 'treeData', - visibleEvent: 'onVisibleChange', - }, - ), - AutoComplete, - Checkbox, - CheckboxGroup, - DatePicker, - // 自定义默认按钮 - DefaultButton: (props, { attrs, slots }) => { - return h(Button, { ...props, attrs, theme: 'default' }, slots); - }, - Divider, - IconPicker: withDefaultPlaceholder(IconPicker, 'select', { - iconSlot: 'addonAfter', - inputComponent: Input, - modelValueProp: 'value', - }), - Input: withDefaultPlaceholder(Input, 'input'), - InputNumber: withDefaultPlaceholder(InputNumber, 'input'), - // InputPassword: withDefaultPlaceholder(InputPassword, 'input'), - // Mentions: withDefaultPlaceholder(Mentions, 'input'), - // 自定义主要按钮 - PrimaryButton: (props, { attrs, slots }) => { - let ghost = false; - let variant = props.variant; - if (props.variant === 'ghost') { - ghost = true; - variant = 'base'; - } - return h( - Button, - { ...props, ghost, variant, attrs, theme: 'primary' }, - slots, - ); - }, - Radio, - RadioGroup, - RangePicker: (props, { attrs, slots }) => { - return h( - RangePicker, - { ...props, modelValue: props.modelValue ?? [], attrs }, - slots, - ); - }, - Rate, - Select: withDefaultPlaceholder(Select, 'select'), - Space, - Switch, - Textarea: withDefaultPlaceholder(Textarea, 'input'), - TimePicker, - TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'), - Upload, - }; - - // 将组件注册到全局共享状态中 - globalShareState.setComponents(components); - - // 定义全局共享状态中的消息提示 - globalShareState.defineMessage({ - // 复制成功消息提示 - copyPreferencesSuccess: (title, content) => { - notification.success({ - title, - content, - placement: 'bottom-right', - }); - }, - }); -} - -export { initComponentAdapter }; diff --git a/apps/web-tdesign/src/adapter/form.ts b/apps/web-tdesign/src/adapter/form.ts deleted file mode 100644 index ed09451..0000000 --- a/apps/web-tdesign/src/adapter/form.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { - VbenFormSchema as FormSchema, - VbenFormProps, -} from '@vben/common-ui'; - -import type { ComponentType } from './component'; - -import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; -import { $t } from '@vben/locales'; - -async function initSetupVbenForm() { - setupVbenForm({ - config: { - // tdesign组件库默认都是 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; - -export { initSetupVbenForm, useVbenForm, z }; - -export type VbenFormSchema = FormSchema; -export type { VbenFormProps }; diff --git a/apps/web-tdesign/src/adapter/tdesign.ts b/apps/web-tdesign/src/adapter/tdesign.ts deleted file mode 100644 index 70c6760..0000000 --- a/apps/web-tdesign/src/adapter/tdesign.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { - DialogPlugin as dialog, - MessagePlugin as message, - NotifyPlugin as notification, -} from 'tdesign-vue-next'; diff --git a/apps/web-tdesign/src/adapter/vxe-table.ts b/apps/web-tdesign/src/adapter/vxe-table.ts deleted file mode 100644 index e406242..0000000 --- a/apps/web-tdesign/src/adapter/vxe-table.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; - -import { h } from 'vue'; - -import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; - -import { Button, Image } from 'tdesign-vue-next'; - -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', theme: 'primary', variant: 'text' }, - { default: () => props?.text }, - ); - }, - }); - - // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 - // vxeUI.formats.add - }, - useVbenForm, -}); - -export { useVbenVxeGrid }; - -export type * from '@vben/plugins/vxe-table'; diff --git a/apps/web-tdesign/src/api/core/auth.ts b/apps/web-tdesign/src/api/core/auth.ts deleted file mode 100644 index 71d9f99..0000000 --- a/apps/web-tdesign/src/api/core/auth.ts +++ /dev/null @@ -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('/auth/login', data); -} - -/** - * 刷新accessToken - */ -export async function refreshTokenApi() { - return baseRequestClient.post('/auth/refresh', { - withCredentials: true, - }); -} - -/** - * 退出登录 - */ -export async function logoutApi() { - return baseRequestClient.post('/auth/logout', { - withCredentials: true, - }); -} - -/** - * 获取用户权限码 - */ -export async function getAccessCodesApi() { - return requestClient.get('/auth/codes'); -} diff --git a/apps/web-tdesign/src/api/core/index.ts b/apps/web-tdesign/src/api/core/index.ts deleted file mode 100644 index 28a5aef..0000000 --- a/apps/web-tdesign/src/api/core/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './auth'; -export * from './menu'; -export * from './user'; diff --git a/apps/web-tdesign/src/api/core/menu.ts b/apps/web-tdesign/src/api/core/menu.ts deleted file mode 100644 index 9ef60b1..0000000 --- a/apps/web-tdesign/src/api/core/menu.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { RouteRecordStringComponent } from '@vben/types'; - -import { requestClient } from '#/api/request'; - -/** - * 获取用户所有菜单 - */ -export async function getAllMenusApi() { - return requestClient.get('/menu/all'); -} diff --git a/apps/web-tdesign/src/api/core/user.ts b/apps/web-tdesign/src/api/core/user.ts deleted file mode 100644 index 7e28ea8..0000000 --- a/apps/web-tdesign/src/api/core/user.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { UserInfo } from '@vben/types'; - -import { requestClient } from '#/api/request'; - -/** - * 获取用户信息 - */ -export async function getUserInfoApi() { - return requestClient.get('/user/info'); -} diff --git a/apps/web-tdesign/src/api/index.ts b/apps/web-tdesign/src/api/index.ts deleted file mode 100644 index 4b0e041..0000000 --- a/apps/web-tdesign/src/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './core'; diff --git a/apps/web-tdesign/src/api/request.ts b/apps/web-tdesign/src/api/request.ts deleted file mode 100644 index 86b181d..0000000 --- a/apps/web-tdesign/src/api/request.ts +++ /dev/null @@ -1,112 +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 '#/adapter/tdesign'; -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 }); diff --git a/apps/web-tdesign/src/app.vue b/apps/web-tdesign/src/app.vue deleted file mode 100644 index f2fa884..0000000 --- a/apps/web-tdesign/src/app.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/bootstrap.ts b/apps/web-tdesign/src/bootstrap.ts deleted file mode 100644 index 5d07717..0000000 --- a/apps/web-tdesign/src/bootstrap.ts +++ /dev/null @@ -1,79 +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'; - -import 'tdesign-vue-next/es/style/index.css'; - -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 }; diff --git a/apps/web-tdesign/src/layouts/auth.vue b/apps/web-tdesign/src/layouts/auth.vue deleted file mode 100644 index 18d415b..0000000 --- a/apps/web-tdesign/src/layouts/auth.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/layouts/basic.vue b/apps/web-tdesign/src/layouts/basic.vue deleted file mode 100644 index 2226c68..0000000 --- a/apps/web-tdesign/src/layouts/basic.vue +++ /dev/null @@ -1,206 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/layouts/index.ts b/apps/web-tdesign/src/layouts/index.ts deleted file mode 100644 index a432078..0000000 --- a/apps/web-tdesign/src/layouts/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-tdesign/src/locales/README.md b/apps/web-tdesign/src/locales/README.md deleted file mode 100644 index 7b45103..0000000 --- a/apps/web-tdesign/src/locales/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# locale - -每个app使用的国际化可能不同,这里用于扩展国际化的功能,例如扩展 dayjs、antd组件库的多语言切换,以及app本身的国际化文件。 diff --git a/apps/web-tdesign/src/locales/index.ts b/apps/web-tdesign/src/locales/index.ts deleted file mode 100644 index 6d98579..0000000 --- a/apps/web-tdesign/src/locales/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { App } from 'vue'; - -import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales'; - -import { - $t, - setupI18n as coreSetup, - loadLocalesMapFromDir, -} from '@vben/locales'; -import { preferences } from '@vben/preferences'; - -import dayjs from 'dayjs'; - -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 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}`); - } -} - -async function setupI18n(app: App, options: LocaleSetupOptions = {}) { - await coreSetup(app, { - defaultLocale: preferences.app.locale, - loadMessages, - missingWarn: !import.meta.env.PROD, - ...options, - }); -} - -export { $t, setupI18n }; diff --git a/apps/web-tdesign/src/locales/langs/en-US/demos.json b/apps/web-tdesign/src/locales/langs/en-US/demos.json deleted file mode 100644 index e7bcea1..0000000 --- a/apps/web-tdesign/src/locales/langs/en-US/demos.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "title": "Demos", - "tdesign": "TDesign Vue", - "vben": { - "title": "Project", - "about": "About", - "document": "Document", - "antdv": "Ant Design Vue Version", - "naive-ui": "Naive UI Version", - "element-plus": "Element Plus Version" - } -} diff --git a/apps/web-tdesign/src/locales/langs/en-US/page.json b/apps/web-tdesign/src/locales/langs/en-US/page.json deleted file mode 100644 index 39f1641..0000000 --- a/apps/web-tdesign/src/locales/langs/en-US/page.json +++ /dev/null @@ -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" - } -} diff --git a/apps/web-tdesign/src/locales/langs/zh-CN/demos.json b/apps/web-tdesign/src/locales/langs/zh-CN/demos.json deleted file mode 100644 index 843a1f3..0000000 --- a/apps/web-tdesign/src/locales/langs/zh-CN/demos.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "title": "演示", - "tdesign": "TDesign Vue", - "vben": { - "title": "项目", - "about": "关于", - "document": "文档", - "antdv": "Ant Design Vue 版本", - "naive-ui": "Naive UI 版本", - "element-plus": "Element Plus 版本" - } -} diff --git a/apps/web-tdesign/src/locales/langs/zh-CN/page.json b/apps/web-tdesign/src/locales/langs/zh-CN/page.json deleted file mode 100644 index 2192d1d..0000000 --- a/apps/web-tdesign/src/locales/langs/zh-CN/page.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "auth": { - "login": "登录", - "register": "注册", - "codeLogin": "验证码登录", - "qrcodeLogin": "二维码登录", - "forgetPassword": "忘记密码", - "profile": "个人中心" - }, - "dashboard": { - "title": "概览", - "analytics": "分析页", - "workspace": "工作台" - } -} diff --git a/apps/web-tdesign/src/main.ts b/apps/web-tdesign/src/main.ts deleted file mode 100644 index 5d728a0..0000000 --- a/apps/web-tdesign/src/main.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { initPreferences } from '@vben/preferences'; -import { unmountGlobalLoading } from '@vben/utils'; - -import { overridesPreferences } from './preferences'; - -/** - * 应用初始化完成之后再进行页面加载渲染 - */ -async function initApplication() { - // name用于指定项目唯一标识 - // 用于区分不同项目的偏好设置以及存储数据的key前缀以及其他一些需要隔离的数据 - const env = import.meta.env.PROD ? 'prod' : 'dev'; - const appVersion = import.meta.env.VITE_APP_VERSION; - const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`; - - // app偏好设置初始化 - await initPreferences({ - namespace, - overrides: overridesPreferences, - }); - - // 启动应用并挂载 - // vue应用主要逻辑及视图 - const { bootstrap } = await import('./bootstrap'); - await bootstrap(namespace); - - // 移除并销毁loading - unmountGlobalLoading(); -} - -initApplication(); diff --git a/apps/web-tdesign/src/preferences.ts b/apps/web-tdesign/src/preferences.ts deleted file mode 100644 index b2e9ace..0000000 --- a/apps/web-tdesign/src/preferences.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { defineOverridesPreferences } from '@vben/preferences'; - -/** - * @description 项目配置文件 - * 只需要覆盖项目中的一部分配置,不需要的配置不用覆盖,会自动使用默认配置 - * !!! 更改配置后请清空缓存,否则可能不生效 - */ -export const overridesPreferences = defineOverridesPreferences({ - // overrides - app: { - name: import.meta.env.VITE_APP_TITLE, - }, -}); diff --git a/apps/web-tdesign/src/router/access.ts b/apps/web-tdesign/src/router/access.ts deleted file mode 100644 index 08cb4b0..0000000 --- a/apps/web-tdesign/src/router/access.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { - ComponentRecordType, - GenerateMenuAndRoutesOptions, -} from '@vben/types'; - -import { generateAccessible } from '@vben/access'; -import { preferences } from '@vben/preferences'; - -import { message } from '#/adapter/tdesign'; -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: 1500, - }); - return await getAllMenusApi(); - }, - // 可以指定没有权限跳转403页面 - forbiddenComponent, - // 如果 route.meta.menuVisibleWithForbidden = true - layoutMap, - pageMap, - }); -} - -export { generateAccess }; diff --git a/apps/web-tdesign/src/router/guard.ts b/apps/web-tdesign/src/router/guard.ts deleted file mode 100644 index a1ad6d8..0000000 --- a/apps/web-tdesign/src/router/guard.ts +++ /dev/null @@ -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(); - - 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 }; diff --git a/apps/web-tdesign/src/router/index.ts b/apps/web-tdesign/src/router/index.ts deleted file mode 100644 index 4840230..0000000 --- a/apps/web-tdesign/src/router/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-tdesign/src/router/routes/core.ts b/apps/web-tdesign/src/router/routes/core.ts deleted file mode 100644 index 949b0b6..0000000 --- a/apps/web-tdesign/src/router/routes/core.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-tdesign/src/router/routes/index.ts b/apps/web-tdesign/src/router/routes/index.ts deleted file mode 100644 index e6fb144..0000000 --- a/apps/web-tdesign/src/router/routes/index.ts +++ /dev/null @@ -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 }; diff --git a/apps/web-tdesign/src/router/routes/modules/dashboard.ts b/apps/web-tdesign/src/router/routes/modules/dashboard.ts deleted file mode 100644 index 5254dc6..0000000 --- a/apps/web-tdesign/src/router/routes/modules/dashboard.ts +++ /dev/null @@ -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; diff --git a/apps/web-tdesign/src/router/routes/modules/demos.ts b/apps/web-tdesign/src/router/routes/modules/demos.ts deleted file mode 100644 index 9ce8ec9..0000000 --- a/apps/web-tdesign/src/router/routes/modules/demos.ts +++ /dev/null @@ -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.tdesign'), - }, - name: 'TDesignDemos', - path: '/demos/tdesign', - component: () => import('#/views/demos/tdesign/index.vue'), - }, - ], - }, -]; - -export default routes; diff --git a/apps/web-tdesign/src/router/routes/modules/vben.ts b/apps/web-tdesign/src/router/routes/modules/vben.ts deleted file mode 100644 index a5f0aa4..0000000 --- a/apps/web-tdesign/src/router/routes/modules/vben.ts +++ /dev/null @@ -1,104 +0,0 @@ -import type { RouteRecordRaw } from 'vue-router'; - -import { - VBEN_ANT_PREVIEW_URL, - VBEN_DOC_URL, - VBEN_ELE_PREVIEW_URL, - VBEN_GITHUB_URL, - VBEN_LOGO_URL, - VBEN_NAIVE_PREVIEW_URL, -} from '@vben/constants'; -import { SvgAntdvLogoIcon } 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: '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: 'VbenAntdv', - path: '/vben-admin/antdv', - component: IFrameView, - meta: { - badgeType: 'dot', - icon: SvgAntdvLogoIcon, - link: VBEN_ANT_PREVIEW_URL, - title: $t('demos.vben.antdv'), - }, - }, - { - 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; diff --git a/apps/web-tdesign/src/store/auth.ts b/apps/web-tdesign/src/store/auth.ts deleted file mode 100644 index b3b4b74..0000000 --- a/apps/web-tdesign/src/store/auth.ts +++ /dev/null @@ -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 { defineStore } from 'pinia'; - -import { notification } from '#/adapter/tdesign'; -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, - onSuccess?: () => Promise | 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({ - title: $t('authentication.loginSuccess'), - content: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`, - duration: 3000, - }); - } - } - } 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() { - let userInfo: null | UserInfo = null; - userInfo = await getUserInfoApi(); - userStore.setUserInfo(userInfo); - return userInfo; - } - - function $reset() { - loginLoading.value = false; - } - - return { - $reset, - authLogin, - fetchUserInfo, - loginLoading, - logout, - }; -}); diff --git a/apps/web-tdesign/src/store/index.ts b/apps/web-tdesign/src/store/index.ts deleted file mode 100644 index 269586e..0000000 --- a/apps/web-tdesign/src/store/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './auth'; diff --git a/apps/web-tdesign/src/views/_core/README.md b/apps/web-tdesign/src/views/_core/README.md deleted file mode 100644 index 8248afe..0000000 --- a/apps/web-tdesign/src/views/_core/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# \_core - -此目录包含应用程序正常运行所需的基本视图。这些视图是应用程序布局中使用的视图。 diff --git a/apps/web-tdesign/src/views/_core/about/index.vue b/apps/web-tdesign/src/views/_core/about/index.vue deleted file mode 100644 index 0ee5243..0000000 --- a/apps/web-tdesign/src/views/_core/about/index.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/authentication/code-login.vue b/apps/web-tdesign/src/views/_core/authentication/code-login.vue deleted file mode 100644 index acfd1fd..0000000 --- a/apps/web-tdesign/src/views/_core/authentication/code-login.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/authentication/forget-password.vue b/apps/web-tdesign/src/views/_core/authentication/forget-password.vue deleted file mode 100644 index fef0d42..0000000 --- a/apps/web-tdesign/src/views/_core/authentication/forget-password.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/authentication/login.vue b/apps/web-tdesign/src/views/_core/authentication/login.vue deleted file mode 100644 index 89af0c2..0000000 --- a/apps/web-tdesign/src/views/_core/authentication/login.vue +++ /dev/null @@ -1,99 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/authentication/qrcode-login.vue b/apps/web-tdesign/src/views/_core/authentication/qrcode-login.vue deleted file mode 100644 index 23f5f2d..0000000 --- a/apps/web-tdesign/src/views/_core/authentication/qrcode-login.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/authentication/register.vue b/apps/web-tdesign/src/views/_core/authentication/register.vue deleted file mode 100644 index 1a80ff5..0000000 --- a/apps/web-tdesign/src/views/_core/authentication/register.vue +++ /dev/null @@ -1,96 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/fallback/coming-soon.vue b/apps/web-tdesign/src/views/_core/fallback/coming-soon.vue deleted file mode 100644 index f394930..0000000 --- a/apps/web-tdesign/src/views/_core/fallback/coming-soon.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/fallback/forbidden.vue b/apps/web-tdesign/src/views/_core/fallback/forbidden.vue deleted file mode 100644 index 8ea65fe..0000000 --- a/apps/web-tdesign/src/views/_core/fallback/forbidden.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/fallback/internal-error.vue b/apps/web-tdesign/src/views/_core/fallback/internal-error.vue deleted file mode 100644 index 819a47d..0000000 --- a/apps/web-tdesign/src/views/_core/fallback/internal-error.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/fallback/not-found.vue b/apps/web-tdesign/src/views/_core/fallback/not-found.vue deleted file mode 100644 index 4d178e9..0000000 --- a/apps/web-tdesign/src/views/_core/fallback/not-found.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/fallback/offline.vue b/apps/web-tdesign/src/views/_core/fallback/offline.vue deleted file mode 100644 index 5de4a88..0000000 --- a/apps/web-tdesign/src/views/_core/fallback/offline.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/_core/profile/base-setting.vue b/apps/web-tdesign/src/views/_core/profile/base-setting.vue deleted file mode 100644 index aa8a4c2..0000000 --- a/apps/web-tdesign/src/views/_core/profile/base-setting.vue +++ /dev/null @@ -1,65 +0,0 @@ - - diff --git a/apps/web-tdesign/src/views/_core/profile/index.vue b/apps/web-tdesign/src/views/_core/profile/index.vue deleted file mode 100644 index 8740894..0000000 --- a/apps/web-tdesign/src/views/_core/profile/index.vue +++ /dev/null @@ -1,49 +0,0 @@ - - diff --git a/apps/web-tdesign/src/views/_core/profile/notification-setting.vue b/apps/web-tdesign/src/views/_core/profile/notification-setting.vue deleted file mode 100644 index 324a4b3..0000000 --- a/apps/web-tdesign/src/views/_core/profile/notification-setting.vue +++ /dev/null @@ -1,31 +0,0 @@ - - diff --git a/apps/web-tdesign/src/views/_core/profile/password-setting.vue b/apps/web-tdesign/src/views/_core/profile/password-setting.vue deleted file mode 100644 index 1db1194..0000000 --- a/apps/web-tdesign/src/views/_core/profile/password-setting.vue +++ /dev/null @@ -1,63 +0,0 @@ - - diff --git a/apps/web-tdesign/src/views/_core/profile/security-setting.vue b/apps/web-tdesign/src/views/_core/profile/security-setting.vue deleted file mode 100644 index be30db5..0000000 --- a/apps/web-tdesign/src/views/_core/profile/security-setting.vue +++ /dev/null @@ -1,43 +0,0 @@ - - diff --git a/apps/web-tdesign/src/views/dashboard/analytics/analytics-trends.vue b/apps/web-tdesign/src/views/dashboard/analytics/analytics-trends.vue deleted file mode 100644 index f1f0b23..0000000 --- a/apps/web-tdesign/src/views/dashboard/analytics/analytics-trends.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-data.vue b/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-data.vue deleted file mode 100644 index 190fb41..0000000 --- a/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-data.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-sales.vue b/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-sales.vue deleted file mode 100644 index 6ff5208..0000000 --- a/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-sales.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-source.vue b/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-source.vue deleted file mode 100644 index 0915c7a..0000000 --- a/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits-source.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits.vue b/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits.vue deleted file mode 100644 index 7e0f101..0000000 --- a/apps/web-tdesign/src/views/dashboard/analytics/analytics-visits.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/dashboard/analytics/index.vue b/apps/web-tdesign/src/views/dashboard/analytics/index.vue deleted file mode 100644 index 5e3d6d2..0000000 --- a/apps/web-tdesign/src/views/dashboard/analytics/index.vue +++ /dev/null @@ -1,90 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/dashboard/workspace/index.vue b/apps/web-tdesign/src/views/dashboard/workspace/index.vue deleted file mode 100644 index b95d613..0000000 --- a/apps/web-tdesign/src/views/dashboard/workspace/index.vue +++ /dev/null @@ -1,266 +0,0 @@ - - - diff --git a/apps/web-tdesign/src/views/demos/tdesign/index.vue b/apps/web-tdesign/src/views/demos/tdesign/index.vue deleted file mode 100644 index 27299de..0000000 --- a/apps/web-tdesign/src/views/demos/tdesign/index.vue +++ /dev/null @@ -1,67 +0,0 @@ - - - diff --git a/apps/web-tdesign/tailwind.config.mjs b/apps/web-tdesign/tailwind.config.mjs deleted file mode 100644 index f17f556..0000000 --- a/apps/web-tdesign/tailwind.config.mjs +++ /dev/null @@ -1 +0,0 @@ -export { default } from '@vben/tailwind-config'; diff --git a/apps/web-tdesign/tsconfig.json b/apps/web-tdesign/tsconfig.json deleted file mode 100644 index 02c287f..0000000 --- a/apps/web-tdesign/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@vben/tsconfig/web-app.json", - "compilerOptions": { - "baseUrl": ".", - "paths": { - "#/*": ["./src/*"] - } - }, - "references": [{ "path": "./tsconfig.node.json" }], - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/apps/web-tdesign/tsconfig.node.json b/apps/web-tdesign/tsconfig.node.json deleted file mode 100644 index c2f0d86..0000000 --- a/apps/web-tdesign/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@vben/tsconfig/node.json", - "compilerOptions": { - "composite": true, - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "noEmit": false - }, - "include": ["vite.config.mts"] -} diff --git a/apps/web-tdesign/vite.config.mts b/apps/web-tdesign/vite.config.mts deleted file mode 100644 index b6360f1..0000000 --- a/apps/web-tdesign/vite.config.mts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineConfig } from '@vben/vite-config'; - -export default defineConfig(async () => { - return { - application: {}, - vite: { - server: { - proxy: { - '/api': { - changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, ''), - // mock代理目标地址 - target: 'http://localhost:5320/api', - ws: true, - }, - }, - }, - }, - }; -}); diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0844d27..8b390d8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,11 +9,18 @@ packages: - packages/effects/* - packages/business/* - apps/web-antd - - apps/backend-mock - scripts/* - docs - playground +overrides: + '@ast-grep/napi': 'catalog:' + '@ctrl/tinycolor': 'catalog:' + clsx: 'catalog:' + esbuild: 'catalog:' + jiti: 'catalog:' + pinia: 'catalog:' + vue: 'catalog:' catalog: '@ast-grep/napi': ^0.39.9 '@changesets/changelog-github': ^0.5.2 @@ -24,7 +31,6 @@ catalog: '@commitlint/config-conventional': ^19.8.1 '@ctrl/tinycolor': ^4.2.0 '@eslint/js': ^9.39.2 - '@faker-js/faker': ^9.9.0 '@iconify/json': ^2.2.432 '@iconify/tailwind': ^1.2.0 '@iconify/vue': ^5.0.0 @@ -44,7 +50,6 @@ catalog: '@types/eslint': ^9.6.1 '@types/html-minifier-terser': ^7.0.2 '@types/json-bigint': ^1.0.4 - '@types/jsonwebtoken': ^9.0.10 '@types/lodash.clonedeep': ^4.5.9 '@types/node': ^24.10.9 '@types/nprogress': ^0.2.3 @@ -86,7 +91,6 @@ catalog: depcheck: ^1.4.7 dotenv: ^16.6.1 echarts: ^6.0.0 - element-plus: ^2.13.1 es-toolkit: ^1.44.0 esbuild: ^0.25.12 eslint: ^9.39.2 @@ -111,19 +115,16 @@ catalog: find-up: ^7.0.0 get-port: ^7.1.0 globals: ^16.5.0 - h3: ^1.15.5 happy-dom: ^17.6.3 html-minifier-terser: ^7.2.0 is-ci: ^4.1.0 jiti: ^2.6.1 json-bigint: ^1.0.0 jsonc-eslint-parser: ^2.4.2 - jsonwebtoken: ^9.0.3 lefthook: ^2.0.16 lodash.clonedeep: ^4.5.0 lucide-vue-next: ^0.553.0 medium-zoom: ^1.1.0 - naive-ui: ^2.43.2 nitropack: ^2.13.1 nprogress: ^0.2.0 ora: ^8.2.0 @@ -162,13 +163,11 @@ catalog: tailwind-merge: ^2.6.0 tailwindcss: ^3.4.19 tailwindcss-animate: ^1.0.7 - tdesign-vue-next: ^1.18.0 theme-colors: ^0.1.0 tippy.js: ^6.3.7 turbo: ^2.7.6 typescript: ^5.9.3 unbuild: ^3.6.1 - unplugin-element-plus: ^0.11.2 vee-validate: ^4.15.1 vite: ^7.3.1 vite-plugin-compression: ^0.5.1 @@ -202,12 +201,3 @@ onlyBuiltDependencies: - less - unrs-resolver - vue-demi - -overrides: - '@ast-grep/napi': 'catalog:' - '@ctrl/tinycolor': 'catalog:' - clsx: 'catalog:' - esbuild: 'catalog:' - jiti: 'catalog:' - pinia: 'catalog:' - vue: 'catalog:' diff --git a/turbo.json b/turbo.json index 3443e27..7226f13 100644 --- a/turbo.json +++ b/turbo.json @@ -31,10 +31,6 @@ "dependsOn": ["^build"], "outputs": ["dist/**"] }, - "@vben/backend-mock#build": { - "dependsOn": ["^build"], - "outputs": [".nitro/**", ".output/**"] - }, "test:e2e": {}, "dev": { "dependsOn": [], diff --git a/vben-admin.code-workspace b/vben-admin.code-workspace index 5ad3c40..db676e7 100644 --- a/vben-admin.code-workspace +++ b/vben-admin.code-workspace @@ -1,9 +1,5 @@ { "folders": [ - { - "name": "@vben/backend-mock", - "path": "apps/backend-mock", - }, { "name": "@vben/web-antd", "path": "apps/web-antd",