mirror of
https://gitee.com/dapppp/ruoyi-plus-vben5.git
synced 2026-03-21 03:28:58 +08:00
chore: 移除 backend-mock 应用及相关配置
移除不再使用的 backend-mock 应用,包括其源代码、配置文件、依赖项以及相关的构建任务。 同时从工作区配置和 TurboRepo 构建管道中删除对该应用的引用。
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
PORT=5320
|
|
||||||
ACCESS_TOKEN_SECRET=access_token_secret
|
|
||||||
REFRESH_TOKEN_SECRET=refresh_token_secret
|
|
||||||
@@ -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
|
|
||||||
```
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -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,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -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('');
|
|
||||||
});
|
|
||||||
@@ -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;
|
|
||||||
});
|
|
||||||
@@ -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;
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -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}`);
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import { faker } from '@faker-js/faker';
|
|
||||||
import { eventHandler } from 'h3';
|
|
||||||
import { verifyAccessToken } from '~/utils/jwt-utils';
|
|
||||||
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
|
|
||||||
|
|
||||||
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
|
|
||||||
timeZone: 'Asia/Shanghai',
|
|
||||||
year: 'numeric',
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit',
|
|
||||||
second: '2-digit',
|
|
||||||
});
|
|
||||||
|
|
||||||
function generateMockDataList(count: number) {
|
|
||||||
const dataList = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
|
||||||
const dataItem: Record<string, any> = {
|
|
||||||
id: faker.string.uuid(),
|
|
||||||
pid: 0,
|
|
||||||
name: faker.commerce.department(),
|
|
||||||
status: faker.helpers.arrayElement([0, 1]),
|
|
||||||
createTime: formatterCN.format(
|
|
||||||
faker.date.between({ from: '2021-01-01', to: '2022-12-31' }),
|
|
||||||
),
|
|
||||||
remark: faker.lorem.sentence(),
|
|
||||||
};
|
|
||||||
if (faker.datatype.boolean()) {
|
|
||||||
dataItem.children = Array.from(
|
|
||||||
{ length: faker.number.int({ min: 1, max: 5 }) },
|
|
||||||
() => ({
|
|
||||||
id: faker.string.uuid(),
|
|
||||||
pid: dataItem.id,
|
|
||||||
name: faker.commerce.department(),
|
|
||||||
status: faker.helpers.arrayElement([0, 1]),
|
|
||||||
createTime: formatterCN.format(
|
|
||||||
faker.date.between({ from: '2023-01-01', to: '2023-12-31' }),
|
|
||||||
),
|
|
||||||
remark: faker.lorem.sentence(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
dataList.push(dataItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataList;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mockData = generateMockDataList(10);
|
|
||||||
|
|
||||||
export default eventHandler(async (event) => {
|
|
||||||
const userinfo = verifyAccessToken(event);
|
|
||||||
if (!userinfo) {
|
|
||||||
return unAuthorizedResponse(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
const listData = structuredClone(mockData);
|
|
||||||
|
|
||||||
return useResponseSuccess(listData);
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import { eventHandler, getQuery } from 'h3';
|
|
||||||
import { verifyAccessToken } from '~/utils/jwt-utils';
|
|
||||||
import { MOCK_MENU_LIST } from '~/utils/mock-data';
|
|
||||||
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
|
|
||||||
|
|
||||||
const namesMap: Record<string, any> = {};
|
|
||||||
|
|
||||||
function getNames(menus: any[]) {
|
|
||||||
menus.forEach((menu) => {
|
|
||||||
namesMap[menu.name] = String(menu.id);
|
|
||||||
if (menu.children) {
|
|
||||||
getNames(menu.children);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getNames(MOCK_MENU_LIST);
|
|
||||||
|
|
||||||
export default eventHandler(async (event) => {
|
|
||||||
const userinfo = verifyAccessToken(event);
|
|
||||||
if (!userinfo) {
|
|
||||||
return unAuthorizedResponse(event);
|
|
||||||
}
|
|
||||||
const { id, name } = getQuery(event);
|
|
||||||
|
|
||||||
return (name as string) in namesMap &&
|
|
||||||
(!id || namesMap[name as string] !== String(id))
|
|
||||||
? useResponseSuccess(true)
|
|
||||||
: useResponseSuccess(false);
|
|
||||||
});
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import { eventHandler, getQuery } from 'h3';
|
|
||||||
import { verifyAccessToken } from '~/utils/jwt-utils';
|
|
||||||
import { MOCK_MENU_LIST } from '~/utils/mock-data';
|
|
||||||
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
|
|
||||||
|
|
||||||
const pathMap: Record<string, any> = { '/': 0 };
|
|
||||||
|
|
||||||
function getPaths(menus: any[]) {
|
|
||||||
menus.forEach((menu) => {
|
|
||||||
pathMap[menu.path] = String(menu.id);
|
|
||||||
if (menu.children) {
|
|
||||||
getPaths(menu.children);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getPaths(MOCK_MENU_LIST);
|
|
||||||
|
|
||||||
export default eventHandler(async (event) => {
|
|
||||||
const userinfo = verifyAccessToken(event);
|
|
||||||
if (!userinfo) {
|
|
||||||
return unAuthorizedResponse(event);
|
|
||||||
}
|
|
||||||
const { id, path } = getQuery(event);
|
|
||||||
|
|
||||||
return (path as string) in pathMap &&
|
|
||||||
(!id || pathMap[path as string] !== String(id))
|
|
||||||
? useResponseSuccess(true)
|
|
||||||
: useResponseSuccess(false);
|
|
||||||
});
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
import { faker } from '@faker-js/faker';
|
|
||||||
import { eventHandler, getQuery } from 'h3';
|
|
||||||
import { verifyAccessToken } from '~/utils/jwt-utils';
|
|
||||||
import { getMenuIds, MOCK_MENU_LIST } from '~/utils/mock-data';
|
|
||||||
import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
|
|
||||||
|
|
||||||
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
|
|
||||||
timeZone: 'Asia/Shanghai',
|
|
||||||
year: 'numeric',
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit',
|
|
||||||
second: '2-digit',
|
|
||||||
});
|
|
||||||
|
|
||||||
const menuIds = getMenuIds(MOCK_MENU_LIST);
|
|
||||||
|
|
||||||
function generateMockDataList(count: number) {
|
|
||||||
const dataList = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < count; i++) {
|
|
||||||
const dataItem: Record<string, any> = {
|
|
||||||
id: faker.string.uuid(),
|
|
||||||
name: faker.commerce.product(),
|
|
||||||
status: faker.helpers.arrayElement([0, 1]),
|
|
||||||
createTime: formatterCN.format(
|
|
||||||
faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),
|
|
||||||
),
|
|
||||||
permissions: faker.helpers.arrayElements(menuIds),
|
|
||||||
remark: faker.lorem.sentence(),
|
|
||||||
};
|
|
||||||
|
|
||||||
dataList.push(dataItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataList;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mockData = generateMockDataList(100);
|
|
||||||
|
|
||||||
export default eventHandler(async (event) => {
|
|
||||||
const userinfo = verifyAccessToken(event);
|
|
||||||
if (!userinfo) {
|
|
||||||
return unAuthorizedResponse(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
page = 1,
|
|
||||||
pageSize = 20,
|
|
||||||
name,
|
|
||||||
id,
|
|
||||||
remark,
|
|
||||||
startTime,
|
|
||||||
endTime,
|
|
||||||
status,
|
|
||||||
} = getQuery(event);
|
|
||||||
let listData = structuredClone(mockData);
|
|
||||||
if (name) {
|
|
||||||
listData = listData.filter((item) =>
|
|
||||||
item.name.toLowerCase().includes(String(name).toLowerCase()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (id) {
|
|
||||||
listData = listData.filter((item) =>
|
|
||||||
item.id.toLowerCase().includes(String(id).toLowerCase()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (remark) {
|
|
||||||
listData = listData.filter((item) =>
|
|
||||||
item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (startTime) {
|
|
||||||
listData = listData.filter((item) => item.createTime >= startTime);
|
|
||||||
}
|
|
||||||
if (endTime) {
|
|
||||||
listData = listData.filter((item) => item.createTime <= endTime);
|
|
||||||
}
|
|
||||||
if (['0', '1'].includes(status as string)) {
|
|
||||||
listData = listData.filter((item) => item.status === Number(status));
|
|
||||||
}
|
|
||||||
return usePageResponseSuccess(page as string, pageSize as string, listData);
|
|
||||||
});
|
|
||||||
@@ -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,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import { defineEventHandler } from 'h3';
|
|
||||||
|
|
||||||
export default defineEventHandler(() => 'Test get handler');
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import { defineEventHandler } from 'h3';
|
|
||||||
|
|
||||||
export default defineEventHandler(() => 'Test post handler');
|
|
||||||
@@ -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());
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -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({});
|
|
||||||
});
|
|
||||||
@@ -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")
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -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;
|
|
||||||
@@ -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, '演示环境,禁止修改');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -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': '*',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -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:"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { defineEventHandler } from 'h3';
|
|
||||||
|
|
||||||
export default defineEventHandler(() => {
|
|
||||||
return `
|
|
||||||
<h1>Hello Vben Admin</h1>
|
|
||||||
<h2>Mock service is starting</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="/api/user">/api/user/info</a></li>
|
|
||||||
<li><a href="/api/menu">/api/menu/all</a></li>
|
|
||||||
<li><a href="/api/auth/codes">/api/auth/codes</a></li>
|
|
||||||
<li><a href="/api/auth/login">/api/auth/login</a></li>
|
|
||||||
<li><a href="/api/upload">/api/upload</a></li>
|
|
||||||
</ul>
|
|
||||||
`;
|
|
||||||
});
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./.nitro/types/tsconfig.json"
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import type { EventHandlerRequest, H3Event } from 'h3';
|
|
||||||
|
|
||||||
import { deleteCookie, getCookie, setCookie } from 'h3';
|
|
||||||
|
|
||||||
export function clearRefreshTokenCookie(event: H3Event<EventHandlerRequest>) {
|
|
||||||
deleteCookie(event, 'jwt', {
|
|
||||||
httpOnly: true,
|
|
||||||
sameSite: 'none',
|
|
||||||
secure: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setRefreshTokenCookie(
|
|
||||||
event: H3Event<EventHandlerRequest>,
|
|
||||||
refreshToken: string,
|
|
||||||
) {
|
|
||||||
setCookie(event, 'jwt', refreshToken, {
|
|
||||||
httpOnly: true,
|
|
||||||
maxAge: 24 * 60 * 60, // unit: seconds
|
|
||||||
sameSite: 'none',
|
|
||||||
secure: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRefreshTokenFromCookie(event: H3Event<EventHandlerRequest>) {
|
|
||||||
const refreshToken = getCookie(event, 'jwt');
|
|
||||||
return refreshToken;
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import type { EventHandlerRequest, H3Event } from 'h3';
|
|
||||||
|
|
||||||
import type { UserInfo } from './mock-data';
|
|
||||||
|
|
||||||
import { getHeader } from 'h3';
|
|
||||||
import jwt from 'jsonwebtoken';
|
|
||||||
|
|
||||||
import { MOCK_USERS } from './mock-data';
|
|
||||||
|
|
||||||
// TODO: Replace with your own secret key
|
|
||||||
const ACCESS_TOKEN_SECRET = 'access_token_secret';
|
|
||||||
const REFRESH_TOKEN_SECRET = 'refresh_token_secret';
|
|
||||||
|
|
||||||
export interface UserPayload extends UserInfo {
|
|
||||||
iat: number;
|
|
||||||
exp: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateAccessToken(user: UserInfo) {
|
|
||||||
return jwt.sign(user, ACCESS_TOKEN_SECRET, { expiresIn: '7d' });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function generateRefreshToken(user: UserInfo) {
|
|
||||||
return jwt.sign(user, REFRESH_TOKEN_SECRET, {
|
|
||||||
expiresIn: '30d',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function verifyAccessToken(
|
|
||||||
event: H3Event<EventHandlerRequest>,
|
|
||||||
): null | Omit<UserInfo, 'password'> {
|
|
||||||
const authHeader = getHeader(event, 'Authorization');
|
|
||||||
if (!authHeader?.startsWith('Bearer')) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tokenParts = authHeader.split(' ');
|
|
||||||
if (tokenParts.length !== 2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const token = tokenParts[1] as string;
|
|
||||||
try {
|
|
||||||
const decoded = jwt.verify(
|
|
||||||
token,
|
|
||||||
ACCESS_TOKEN_SECRET,
|
|
||||||
) as unknown as UserPayload;
|
|
||||||
|
|
||||||
const username = decoded.username;
|
|
||||||
const user = MOCK_USERS.find((item) => item.username === username);
|
|
||||||
if (!user) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const { password: _pwd, ...userinfo } = user;
|
|
||||||
return userinfo;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function verifyRefreshToken(
|
|
||||||
token: string,
|
|
||||||
): null | Omit<UserInfo, 'password'> {
|
|
||||||
try {
|
|
||||||
const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET) as UserPayload;
|
|
||||||
const username = decoded.username;
|
|
||||||
const user = MOCK_USERS.find(
|
|
||||||
(item) => item.username === username,
|
|
||||||
) as UserInfo;
|
|
||||||
if (!user) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const { password: _pwd, ...userinfo } = user;
|
|
||||||
return userinfo;
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import type { EventHandlerRequest, H3Event } from 'h3';
|
|
||||||
|
|
||||||
import { setResponseStatus } from 'h3';
|
|
||||||
|
|
||||||
export function useResponseSuccess<T = any>(data: T) {
|
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
data,
|
|
||||||
error: null,
|
|
||||||
message: 'ok',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function usePageResponseSuccess<T = any>(
|
|
||||||
page: number | string,
|
|
||||||
pageSize: number | string,
|
|
||||||
list: T[],
|
|
||||||
{ message = 'ok' } = {},
|
|
||||||
) {
|
|
||||||
const pageData = pagination(
|
|
||||||
Number.parseInt(`${page}`),
|
|
||||||
Number.parseInt(`${pageSize}`),
|
|
||||||
list,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...useResponseSuccess({
|
|
||||||
items: pageData,
|
|
||||||
total: list.length,
|
|
||||||
}),
|
|
||||||
message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useResponseError(message: string, error: any = null) {
|
|
||||||
return {
|
|
||||||
code: -1,
|
|
||||||
data: null,
|
|
||||||
error,
|
|
||||||
message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function forbiddenResponse(
|
|
||||||
event: H3Event<EventHandlerRequest>,
|
|
||||||
message = 'Forbidden Exception',
|
|
||||||
) {
|
|
||||||
setResponseStatus(event, 403);
|
|
||||||
return useResponseError(message, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unAuthorizedResponse(event: H3Event<EventHandlerRequest>) {
|
|
||||||
setResponseStatus(event, 401);
|
|
||||||
return useResponseError('Unauthorized Exception', 'Unauthorized Exception');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sleep(ms: number) {
|
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pagination<T = any>(
|
|
||||||
pageNo: number,
|
|
||||||
pageSize: number,
|
|
||||||
array: T[],
|
|
||||||
): T[] {
|
|
||||||
const offset = (pageNo - 1) * Number(pageSize);
|
|
||||||
return offset + Number(pageSize) >= array.length
|
|
||||||
? array.slice(offset)
|
|
||||||
: array.slice(offset, offset + Number(pageSize));
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
let mockTimeZone: null | string = null;
|
|
||||||
|
|
||||||
export const setTimezone = (timeZone: string) => {
|
|
||||||
mockTimeZone = timeZone;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getTimezone = () => {
|
|
||||||
return mockTimeZone;
|
|
||||||
};
|
|
||||||
@@ -41,10 +41,6 @@
|
|||||||
"dependsOn": ["^build"],
|
"dependsOn": ["^build"],
|
||||||
"outputs": ["dist/**"]
|
"outputs": ["dist/**"]
|
||||||
},
|
},
|
||||||
"@vben/backend-mock#build": {
|
|
||||||
"dependsOn": ["^build"],
|
|
||||||
"outputs": [".nitro/**", ".output/**"]
|
|
||||||
},
|
|
||||||
"test:e2e": {},
|
"test:e2e": {},
|
||||||
"dev": {
|
"dev": {
|
||||||
"dependsOn": [],
|
"dependsOn": [],
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
{
|
{
|
||||||
"folders": [
|
"folders": [
|
||||||
{
|
|
||||||
"name": "@vben/backend-mock",
|
|
||||||
"path": "apps/backend-mock",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "@vben/web-antd",
|
"name": "@vben/web-antd",
|
||||||
"path": "apps/web-antd",
|
"path": "apps/web-antd",
|
||||||
|
|||||||
Reference in New Issue
Block a user