chore: remove mockjs

This commit is contained in:
chansee97 2024-02-29 15:05:08 +08:00
parent d700af4bc4
commit b13b156bb9
34 changed files with 332 additions and 891 deletions

View File

@ -2,7 +2,7 @@ import type { ProxyOptions } from 'vite'
/**
* @description: vite代理字段
* @param {*} env -
* @param {*} envConfig -
*/
export function createViteProxy(envConfig: ServiceEnvConfig) {
const proxy: Record<string, string | ProxyOptions> = {
@ -11,11 +11,6 @@ export function createViteProxy(envConfig: ServiceEnvConfig) {
changeOrigin: true,
rewrite: path => path.replace(new RegExp(`^${envConfig.urlPattern}`), ''),
},
[envConfig.secondUrlPattern]: {
target: envConfig.secondUrl,
changeOrigin: true,
rewrite: path => path.replace(new RegExp(`^${envConfig.secondUrlPattern}`), ''),
},
}
return proxy

View File

@ -1,4 +1,6 @@
import viteCompression from 'vite-plugin-compression' // https://github.com/vbenjs/vite-plugin-compression/blob/main/README.zh_CN.md
import viteCompression from 'vite-plugin-compression'
// https://github.com/vbenjs/vite-plugin-compression/blob/main/README.zh_CN.md
export default (env: ImportMetaEnv) => {
// 默认使用gzip压缩

View File

@ -3,9 +3,6 @@ import UnoCSS from '@unocss/vite'
import vue from './vue'
import compress from './compress'
import unplugin from './unplugin'
import mock from './mock'
// import { viteMockServe } from 'vite-plugin-mock' // https://github.com/vbenjs/vite-plugin-mock/blob/main/README.zh_CN.md
/**
* @description: vite插件配置
@ -13,7 +10,7 @@ import mock from './mock'
* @return {*}
*/
export function setVitePlugins(env: ImportMetaEnv) {
const plugins: PluginOption[] = [...vue, UnoCSS(), ...unplugin, mock]
const plugins: PluginOption[] = [...vue, UnoCSS(), ...unplugin]
// 是否压缩
if (env.VITE_COMPRESS_OPEN === 'Y')
plugins.push(compress(env))

View File

@ -1,10 +0,0 @@
import { viteMockServe } from 'vite-plugin-mock' // https://github.com/vbenjs/vite-plugin-mock/blob/main/README.zh_CN.md
export default viteMockServe({
mockPath: 'mock',
prodEnabled: true,
injectCode: `
import { setupMockServer } from '../mock';
setupMockServer();
`,
})

View File

@ -3,10 +3,14 @@ import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
import Icons from 'unplugin-icons/vite' // https://github.com/antfu/unplugin-icons
import Icons from 'unplugin-icons/vite'
// https://github.com/antfu/unplugin-icons
import IconsResolver from 'unplugin-icons/resolver'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' // https://github.com/vbenjs/vite-plugin-svg-icons/blob/main/README.zh_CN.md
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
// https://github.com/vbenjs/vite-plugin-svg-icons/blob/main/README.zh_CN.md
export default [
AutoImport({
@ -15,7 +19,8 @@ export default [
/\.[tj]sx?$/,
/\.vue$/,
/\.vue\?vue/,
/\.md$/],
/\.md$/,
],
dts: 'src/typings/auto-imports.d.ts',
}),
Components({
@ -29,7 +34,7 @@ export default [
}),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
iconDirs: [path.resolve(__dirname, 'src/assets/icons')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
// inject: 'body-last',

View File

@ -1,6 +0,0 @@
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
import api from './module'
export function setupMockServer() {
createProdMockServer(api)
}

View File

@ -1,3 +0,0 @@
import user from './user'
export default [...user]

View File

@ -1,28 +0,0 @@
import { mock } from 'mockjs'
import { resultSuccess } from '../utils'
const userList = mock({
'list|20': [
{
'id': '@id',
'name': '@cname',
'age|20-36': 36,
'gender|1': ['0', '1', null],
'email': '@email("qq.com")',
'address': '@county(true)',
'role|1': ['super', 'admin', 'user'],
'disabled|1': true,
},
],
})
export default [
{
url: '/mock/userList',
timeout: 1000,
method: 'get',
response: () => {
return resultSuccess(userList.list)
},
},
]

View File

@ -1,493 +0,0 @@
import Mock from 'mockjs'
import { resultFailed, resultSuccess } from '../utils'
const Random = Mock.Random
const token = () => Random.string('upper', 32, 32)
const userData = [
{
userId: '1',
username: 'super',
password: '123456',
nickName: '超级管理员大人',
avatar: 'https://s2.loli.net/2023/08/26/6Xh3wuCV2eMZnEp.png',
role: 'super',
},
{
userId: '2',
username: 'admin',
password: '123456',
nickName: '管理员大人',
avatar: 'https://s2.loli.net/2023/08/26/6Xh3wuCV2eMZnEp.png',
role: 'admin',
},
{
userId: '3',
username: 'user',
password: '123456',
nickName: '用户大人',
avatar: 'https://s2.loli.net/2023/08/26/6Xh3wuCV2eMZnEp.png',
role: 'user',
},
]
const userRoutes = [
{
name: 'dashboard',
path: '/dashboard',
meta: {
title: '仪表盘',
requiresAuth: true,
icon: 'icon-park-outline:analysis',
},
children: [
{
name: 'dashboard_workbench',
path: '/dashboard/workbench',
meta: {
title: '工作台',
requiresAuth: true,
icon: 'icon-park-outline:alarm',
},
},
{
name: 'dashboard_monitor',
path: '/dashboard/monitor',
meta: {
title: '监控页',
requiresAuth: true,
icon: 'icon-park-outline:anchor',
},
},
],
},
{
name: 'test',
path: '/test',
meta: {
title: '多级菜单演示',
requiresAuth: true,
icon: 'icon-park-outline:list',
},
children: [
{
name: 'test1',
path: '/test/test1',
meta: {
title: '接口功能测试',
requiresAuth: true,
icon: 'icon-park-outline:list',
},
},
{
name: 'test2',
path: '/test/test2',
meta: {
title: '多级菜单子页',
requiresAuth: true,
icon: 'icon-park-outline:list',
},
children: [
{
name: 'test2_detail',
path: '/test/test2/detail',
meta: {
title: '多级菜单的详情页',
requiresAuth: true,
icon: 'icon-park-outline:list',
hide: true,
activeMenu: '/test/test2',
},
},
],
},
{
name: 'test3',
path: '/test/test3',
meta: {
title: '多级菜单',
requiresAuth: true,
icon: 'icon-park-outline:list',
},
children: [
{
name: 'test4',
path: '/test/test3/test4',
meta: {
title: '多级菜单3-1',
requiresAuth: true,
icon: 'icon-park-outline:list',
},
},
],
},
],
},
{
name: 'list',
path: '/list',
meta: {
title: '列表页',
requiresAuth: true,
icon: 'icon-park-outline:list-two',
},
children: [
{
name: 'list_commonList',
path: '/list/commonList',
meta: {
title: '常用列表',
requiresAuth: true,
icon: 'icon-park-outline:list-view',
},
},
{
name: 'list_cardList',
path: '/list/cardList',
meta: {
title: '卡片列表',
requiresAuth: true,
icon: 'icon-park-outline:view-grid-list',
},
},
],
},
{
name: 'plugin',
path: '/plugin',
meta: {
title: '组件示例',
requiresAuth: true,
icon: 'icon-park-outline:application-one',
},
children: [
{
name: 'plugin_charts',
path: '/plugin/charts',
meta: {
title: '图表',
requiresAuth: true,
icon: 'icon-park-outline:chart-line',
},
children: [
{
name: 'plugin_echarts',
path: '/plugin/charts/echarts',
meta: {
title: 'ECharts',
requiresAuth: true,
icon: 'icon-park-outline:chart-proportion',
},
},
{
name: 'plugin_antV',
path: '/plugin/charts/antV',
meta: {
title: 'antV',
requiresAuth: true,
icon: 'ant-design:ant-design-outlined',
},
},
],
},
{
name: 'PluginMap',
path: '/plugin/map',
meta: {
title: '地图',
requiresAuth: true,
icon: 'carbon:map',
keepAlive: true,
},
},
{
name: 'plugin_editor',
path: '/plugin/editor',
meta: {
title: '编辑器',
requiresAuth: true,
icon: 'icon-park-outline:editor',
},
children: [
{
name: 'plugin_md',
path: '/plugin/editor/md',
meta: {
title: 'MarkDown',
requiresAuth: true,
icon: 'ri:markdown-line',
},
},
{
name: 'plugin_rich',
path: '/plugin/editor/rich',
meta: {
title: '富文本',
requiresAuth: true,
icon: 'icon-park-outline:edit-one',
},
},
],
},
{
name: 'plugin_clipboard',
path: '/plugin/clipboard',
meta: {
title: '剪贴板',
requiresAuth: true,
icon: 'icon-park-outline:clipboard',
},
},
{
name: 'plugin_icons',
path: '/plugin/icons',
meta: {
title: '图标',
requiresAuth: true,
icon: 'icon-park-outline:winking-face-with-open-eyes',
},
},
{
name: 'plugin_QRCode',
path: '/plugin/QRCode',
meta: {
title: '二维码',
requiresAuth: true,
icon: 'icon-park-outline:two-dimensional-code',
},
},
],
},
{
name: 'docments',
path: '/docments',
meta: {
title: '外链文档',
requiresAuth: true,
icon: 'icon-park-outline:file-doc',
},
children: [
{
name: 'docments_vue',
path: '/docments/vue',
meta: {
title: 'vue',
requiresAuth: true,
icon: 'logos:vue',
},
},
{
name: 'docments_vite',
path: '/docments/vite',
meta: {
title: 'vite',
requiresAuth: true,
icon: 'logos:vitejs',
},
},
{
name: 'docments_vueuse',
path: '/docments/vueuse',
meta: {
title: 'VueUse外链',
requiresAuth: true,
icon: 'logos:vueuse',
herf: 'https://vueuse.org/guide/',
},
},
],
},
{
name: 'permission',
path: '/permission',
meta: {
title: '权限示例',
requiresAuth: true,
icon: 'icon-park-outline:people-safe',
},
children: [
{
name: 'permission_permission',
path: '/permission/permission',
meta: {
title: '权限示例',
requiresAuth: true,
icon: 'icon-park-outline:right-user',
},
},
{
name: 'permission_justSuper',
path: '/permission/justSuper',
meta: {
title: '超管super可见',
requiresAuth: true,
roles: ['super'],
icon: 'icon-park-outline:wrong-user',
},
},
],
},
{
name: 'error',
path: '/error',
meta: {
title: '异常页',
requiresAuth: true,
icon: 'icon-park-outline:error-computer',
},
children: [
{
name: '403',
path: '/error/403',
meta: {
title: '403页',
requiresAuth: true,
icon: 'carbon:error',
order: 3,
},
},
{
name: '404',
path: '/error/404',
meta: {
title: '404页',
requiresAuth: true,
icon: 'icon-park-outline:error',
order: 2,
},
},
{
name: '500',
path: '/error/500',
meta: {
title: '500页',
requiresAuth: true,
icon: 'carbon:data-error',
order: 1,
},
},
],
},
{
name: 'setting',
path: '/setting',
meta: {
title: '系统设置',
requiresAuth: true,
icon: 'icon-park-outline:setting',
},
children: [
{
name: 'setting_account',
path: '/setting/account',
meta: {
title: '用户设置',
requiresAuth: true,
icon: 'icon-park-outline:every-user',
},
},
{
name: 'setting_dictionary',
path: '/setting/dictionary',
meta: {
title: '字典设置',
requiresAuth: true,
icon: 'icon-park-outline:book-one',
},
},
{
name: 'setting_menu',
path: '/setting/menu',
meta: {
title: '菜单设置',
requiresAuth: true,
icon: 'icon-park-outline:application-menu',
},
},
{
name: 'setting_system',
path: '/setting/system',
meta: {
title: '系统配置',
requiresAuth: true,
icon: 'icon-park-outline:coordinate-system',
},
},
],
},
{
name: 'userCenter',
path: '/userCenter',
meta: {
title: '个人中心',
requiresAuth: true,
icon: 'carbon:user-avatar-filled-alt',
},
},
{
name: 'about',
path: '/about',
meta: {
title: '关于',
requiresAuth: true,
icon: 'icon-park-outline:info',
},
},
]
export default [
{
url: '/mock/auth/login',
method: 'post',
response: (options: Service.MockOption) => {
const { username = undefined, password = undefined } = options.body
if (!username || !password)
return resultFailed(null, '账号密码不全')
const userInfo = userData.find(item => item.username === username && item.password === password)
if (userInfo) {
return {
code: 200,
message: 'ok',
data: {
id: userInfo.userId,
accessToken: token(),
refreshToken: token(),
},
}
}
return resultFailed(null, '账号密码错误')
},
},
{
url: '/mock/updateToken',
method: 'post',
response: () => {
return resultSuccess({ token: token(), refreshToken: token() })
},
},
{
url: '/mock/getUserInfo',
method: 'get',
response: (options: any) => {
const { userId } = options.query
if (!userId)
return resultFailed(null, '未传入用户id')
const userInfo = userData.find(item => item.userId === userId)
if (userInfo)
return resultSuccess(userInfo)
return resultFailed(null, '未找到用户信息,请检查提交参数')
},
},
{
url: '/mock/getUserRoutes',
method: 'post',
response: () => {
return resultSuccess(userRoutes)
},
},
]

View File

@ -1,16 +0,0 @@
import Mock from 'mockjs'
export function resultSuccess(data: any, msg?: string) {
return Mock.mock({
code: 200,
data,
msg: msg || 'success',
})
}
export function resultFailed(data: any, msg?: string) {
return Mock.mock({
code: 500,
data,
msg: msg || 'failed',
})
}

View File

@ -1,5 +1,6 @@
{
"name": "nova-admin",
"type": "module",
"version": "0.1.0",
"private": true,
"description": "",
@ -70,14 +71,12 @@
"@iconify-json/icon-park-outline": "^1.1.15",
"@iconify/vue": "^4.1.1",
"@types/crypto-js": "^4.2.2",
"@types/mockjs": "^1.0.10",
"@types/node": "^20.11.22",
"@types/qs": "^6.9.12",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"eslint": "^8.57.0",
"lint-staged": "^15.2.2",
"mockjs": "^1.1.0",
"naive-ui": "^2.38.1",
"sass": "^1.71.1",
"simple-git-hooks": "^2.9.0",
@ -89,7 +88,6 @@
"vite": "^5.1.4",
"vite-bundle-visualizer": "^1.0.1",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-mock": "^3.0.1",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^1.8.27"
},

View File

@ -1,7 +1,9 @@
<script setup lang="ts">
import type { ToolbarNames } from 'md-editor-v3'
import { MdEditor } from 'md-editor-v3' // https://imzbf.github.io/md-editor-v3/zh-CN/docs
import { MdEditor } from 'md-editor-v3'
// https://imzbf.github.io/md-editor-v3/zh-CN/docs
import 'md-editor-v3/lib/style.css'
import { useAppStore } from '@/store'

View File

@ -22,7 +22,8 @@ export function setupCopy(app: App) {
}
function copyHandler(this: any) {
if (!clipboardEnable()) return
if (!clipboardEnable())
return
copy(this._copyText)
window.$message?.success('复制成功')
}

View File

@ -22,16 +22,20 @@ export function usePermission() {
function hasPermission(
permission: Auth.RoleType | Auth.RoleType[] | undefined,
) {
if (!permission) return true
if (!permission)
return true
if (!authStore.userInfo) return false
if (!authStore.userInfo)
return false
const { role } = authStore.userInfo
let has = role === 'super'
if (!has) {
if (isArray(permission)) has = permission.includes(role)
if (isArray(permission))
has = permission.includes(role)
if (isString(permission)) has = permission === role
if (isString(permission))
has = permission === role
}
return has
}

View File

@ -6,7 +6,7 @@ interface Ilogin {
}
export function fetchLogin(params: Ilogin) {
return mockRequest.post<any>('/auth/login', params)
return mockRequest.post<any>('/login', params)
}
export function fetchUpdateToken(params: any) {
return mockRequest.post<ApiAuth.loginToken>('/updateToken', params)
@ -14,6 +14,6 @@ export function fetchUpdateToken(params: any) {
export function fetchUserInfo(params: any) {
return mockRequest.get<Auth.UserInfo>('/getUserInfo', { params })
}
export function fetchUserRoutes(params: { userId: number }) {
return mockRequest.post<AppRoute.Route[]>('/getUserRoutes', params)
export function fetchUserRoutes(params: { id: number }) {
return mockRequest.get<AppRoute.Route[]>('/getUserRoutes', { params })
}

View File

@ -79,7 +79,7 @@ export function handleResponseError(response: AxiosResponse) {
/**
* @description:
* @param {Record} apiData
* @param {Record} data
* @param {Service} config axios字段配置
* @return {*}
*/
@ -127,12 +127,12 @@ export async function handleRefreshToken(config: AxiosRequestConfig) {
const refreshToken = local.get('refreshToken')
const { data } = await fetchUpdateToken(refreshToken)
if (data) {
local.set('refreshToken', data.token)
local.set('refreshToken', data.accessToken)
local.set('token', data.refreshToken)
// 设置token
if (config.headers)
typeof config.headers.set === 'function' && config.headers.set('Authorization', `Bearer ${data.token || ''}`)
typeof config.headers.set === 'function' && config.headers.set('Authorization', `Bearer ${data.accessToken || ''}`)
return config
}

View File

@ -12,4 +12,6 @@ export const request = createRequest({
})
// export const secondRequest = createRequest({ baseURL: isHttpProxy ? secondUrlPattern : secondUrl });
export const mockRequest = createRequest({ baseURL: '/mock' })
export const mockRequest = createRequest({ baseURL: 'https://mock.apifox.com/m1/4071143-0-default' }, {
msgKey: 'message',
})

View File

@ -100,7 +100,6 @@ export function createRequest(
*/
function handleDelete<T>(
url: string,
params?: any,
config?: AxiosRequestConfig,
) {
return asyncRequest<T>({ url, method: 'delete', config })

View File

@ -5,7 +5,7 @@ import { useAppRouter } from '@/hooks'
import { local } from '@/utils'
const emptyInfo: Auth.UserInfo = {
userId: 0,
id: 0,
userName: '',
nickName: '',
avatar: '',
@ -96,7 +96,7 @@ export const useAuthStore = defineStore('auth-store', {
local.set('refreshToken', refreshToken)
this.token = accessToken
this.refreshToken = refreshToken
const { error, data } = await fetchUserInfo({ userId: id })
const { error, data } = await fetchUserInfo({ id })
if (error)
return catchSuccess
// 请求/存储用户信息

View File

@ -150,11 +150,11 @@ export const useRouteStore = defineStore('route-store', {
// 根据用户id来获取用户的路由
const userInfo = local.get('userInfo')
if (!userInfo || !userInfo.userId)
if (!userInfo || !userInfo.id)
return
const { data: routes } = await fetchUserRoutes({
userId: userInfo.userId,
id: userInfo.id,
})
if (!routes)

38
src/typings/api.d.ts vendored
View File

@ -3,31 +3,31 @@
/** 后端返回的用户相关类型 */
declare namespace ApiAuth {
/** 返回的用户信息 */
type UserInfo = Auth.UserInfo;
type UserInfo = Auth.UserInfo
/* 登录token字段 */
interface loginToken {
accessToken: string;
avatar?: string;
email?: string;
id: number;
nickname?: string;
notes?: string;
refreshToken: string;
tel?: string;
username: string;
accessToken: string
avatar?: string
email?: string
id: number
nickname?: string
notes?: string
refreshToken: string
tel?: string
username: string
}
}
declare namespace CommonList {
/* 返回的性别类型 */
type GenderType = '0' | '1' | null;
type GenderType = '0' | '1' | null
interface UserList {
id: number;
name: string;
age: number;
gender: GenderType;
email: string;
address: string;
role: Auth.RoleType;
disabled: boolean;
id: number
name: string
age: number
gender: GenderType
email: string
address: string
role: Auth.RoleType
disabled: boolean
}
}

View File

@ -1,38 +1,37 @@
/** 用户相关模块 */
declare namespace Auth {
/** 用户角色类型 */
type RoleType = 'super' | 'admin' | 'user';
type RoleType = 'super' | 'admin' | 'user'
interface UserInfo {
/** 用户id */
userId: number;
id: number
/** 用户名 */
userName: string;
userName: string
/* 用户称呼 */
nickName: string;
nickName: string
/* 用户头像 */
avatar: string;
avatar: string
/** 用户角色类型 */
role: RoleType;
role: RoleType
}
}
/* 系统消息 */
declare namespace Message {
interface Tab {
key: number;
name: string;
badgeProps?: import('naive-ui').BadgeProps;
list: List[];
key: number
name: string
badgeProps?: import('naive-ui').BadgeProps
list: List[]
}
interface List {
id: number;
title: string;
icon: string;
tagTitle?: string;
tagType?: 'error' | 'info' | 'success' | 'warning';
description?: string;
isRead?: boolean;
date: string;
id: number
title: string
icon: string
tagTitle?: string
tagType?: 'error' | 'info' | 'success' | 'warning'
description?: string
isRead?: boolean
date: string
}
}

View File

@ -1,35 +1,35 @@
interface Window {
$loadingBar?: import('naive-ui').LoadingBarApi;
$dialog?: import('naive-ui').DialogApi;
$message?: import('naive-ui').MessageApi;
$notification?: import('naive-ui').NotificationApi;
$loadingBar?: import('naive-ui').LoadingBarApi
$dialog?: import('naive-ui').DialogApi
$message?: import('naive-ui').MessageApi
$notification?: import('naive-ui').NotificationApi
}
declare const AMap: any;
declare const BMap: any;
declare const AMap: any
declare const BMap: any
interface GolbalConfig {
app: {
proxyUrl: Record<ServiceEnvType, ServiceEnvConfig>;
};
proxyUrl: Record<ServiceEnvType, ServiceEnvConfig>
}
}
declare namespace NaiveUI {
type ThemeColor = 'default' | 'error' | 'primary' | 'info' | 'success' | 'warning';
type ThemeColor = 'default' | 'error' | 'primary' | 'info' | 'success' | 'warning'
}
declare namespace UnionKey {
/* http请求头content-type类型 */
type ContentType = 'application/json' | 'application/x-www-form-urlencoded' | 'multipart/form-data';
type ContentType = 'application/json' | 'application/x-www-form-urlencoded' | 'multipart/form-data'
}
declare namespace Storage {
interface Session {
demoKey: string;
demoKey: string
}
interface Local {
userInfo: Auth.UserInfo;
token: string;
refreshToken: string;
tabsRoutes: string;
login_account: any;
userInfo: Auth.UserInfo
token: string
refreshToken: string
tabsRoutes: string
login_account: any
}
}

View File

@ -1,6 +1,6 @@
declare module '~icons/*' {
import type { FunctionalComponent, SVGAttributes } from 'vue';
import type { FunctionalComponent, SVGAttributes } from 'vue'
const component: FunctionalComponent<SVGAttributes>;
export default component;
const component: FunctionalComponent<SVGAttributes>
export default component
}

View File

@ -2,37 +2,37 @@ declare namespace AppRoute {
/** 单个路由的类型结构(动态路由模式:后端返回此类型结构的路由) */
interface Route {
/** 路由名称(路由唯一标识) */
name: string;
name: string
/** 路由路径 */
path: string;
path: string
/** 路由重定向 */
redirect?: string;
redirect?: string
/** 子路由 */
children?: Route[];
children?: Route[]
/** 路由描述 */
meta: RouteMeta;
meta: RouteMeta
/** 路由属性 */
// props?: boolean | Record<string, any> | ((to: any) => Record<string, any>);
}
/** 路由描述 */
interface RouteMeta {
/* 页面标题,通常必选。 */
title: string;
title: string
/* 图标,一般配合菜单使用 */
icon?: string;
/* 是否需要登录权限。*/
requiresAuth?: boolean;
icon?: string
/* 是否需要登录权限。 */
requiresAuth?: boolean
/* 可以访问的角色 */
roles?: Auth.RoleType[];
roles?: Auth.RoleType[]
/* 是否开启页面缓存 */
keepAlive?: boolean;
keepAlive?: boolean
/* 有些路由我们并不想在菜单中显示,比如某些编辑页面。 */
hide?: boolean;
hide?: boolean
/* 菜单排序。 */
order?: number;
order?: number
/* 嵌套外链 */
herf?: string;
herf?: string
/** 当前路由需要选中的菜单项(用于跳转至不在左侧菜单显示的路由且需要高亮某个菜单的情况) */
activeMenu?: string;
activeMenu?: string
}
}

View File

@ -1,4 +1,5 @@
import 'vue-router';
import 'vue-router'
declare module 'vue-router' {
interface RouteMeta extends AppRoute.RouteMeta {}
}

View File

@ -3,50 +3,43 @@ declare namespace Service {
/** 后端接口返回的数据结构配置 */
interface BackendResultConfig {
/** 表示后端请求状态码的属性字段 */
codeKey: string;
codeKey: string
/** 表示后端请求数据的属性字段 */
dataKey: string;
dataKey: string
/** 表示后端消息的属性字段 */
msgKey: string;
msgKey: string
/** 后端业务上定义的成功请求的状态 */
successCode: number | string;
successCode: number | string
}
type RequestErrorType = 'Axios' | 'Response' | 'Business';
type RequestCode = string | number;
type RequestErrorType = 'Axios' | 'Response' | 'Business'
type RequestCode = string | number
interface RequestError {
/** 请求服务的错误类型 */
type: RequestErrorType;
type: RequestErrorType
/** 错误码 */
code: RequestCode;
code: RequestCode
/** 错误信息 */
msg: string;
msg: string
}
/** 自定义的请求成功结果 */
interface SuccessResult<T = any> {
/** 请求错误 */
error: null;
error: null
/** 请求数据 */
data: T;
data: T
}
/** 自定义的请求失败结果 */
interface FailedResult {
/** 请求错误 */
error: RequestError;
error: RequestError
/** 请求数据 */
data: null;
data: null
}
/** 自定义的请求结果 */
type RequestResult<T = any> = SuccessResult<T> | FailedResult;
interface MockOption {
url: Record<string, any>;
body: Record<string, any>;
query: Record<string, any>;
headers: Record<string, any>;
}
type RequestResult<T = any> = SuccessResult<T> | FailedResult
}

View File

@ -1,5 +1,6 @@
declare module '*.vue' {
import { DefineComponent } from 'vue';
const component: DefineComponent;
export default component;
import type { DefineComponent } from 'vue'
const component: DefineComponent
export default component
}

View File

@ -86,8 +86,8 @@ const columns: DataTableColumns = [
<NSwitch
value={rowData.disabled}
onUpdateValue={disabled =>
handleUpdateDisabled(disabled, rowData.id)
}>
handleUpdateDisabled(disabled, rowData.id)}
>
{{ checked: () => '启用', unchecked: () => '禁用' }}
</NSwitch>
)
@ -100,16 +100,17 @@ const columns: DataTableColumns = [
render: (row) => {
const rowData = row as unknown as CommonList.UserList
return (
<NSpace justify={'center'}>
<NSpace justify="center">
<NButton
size={'small'}
onClick={() => handleEditTable(rowData)}>
size="small"
onClick={() => handleEditTable(rowData)}
>
编辑
</NButton>
<NPopconfirm onPositiveClick={() => sendMail(rowData.id)}>
{{
default: () => '确认删除',
trigger: () => <NButton size={'small'}>删除</NButton>,
trigger: () => <NButton size="small">删除</NButton>,
}}
</NPopconfirm>
</NSpace>
@ -131,7 +132,7 @@ onMounted(() => {
async function getUserList() {
startLoading()
await fetchUserList().then((res: any) => {
listData.value = res.data
listData.value = res.data.list
endLoading()
})
}

View File

@ -50,7 +50,7 @@ function handleValidateClick() {
<n-descriptions label-placement="left" :column="2" :title="`傍晚好,${userInfo?.userName},这里是简单的个人中心模板`">
<n-descriptions-item label="id">
{{ userInfo?.userId }}
{{ userInfo?.id }}
</n-descriptions-item>
<n-descriptions-item label="用户名">
{{ userInfo?.userName }}

View File

@ -1,25 +1,25 @@
{
"compilerOptions": {
"baseUrl": ".",
"target": "ESNext",
"module": "ESNext",
"useDefineForClassFields": true,
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
// "sourceMap": true,
"removeComments": false, //
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"useDefineForClassFields": true,
"baseUrl": ".",
"module": "ESNext",
"moduleResolution": "Node",
"paths": {
"~/*": ["./*"],
"@/*": ["./src/*"]
},
"types": ["node", "vite/client", "naive-ui/volar"]
}, //
"resolveJsonModule": true,
"types": ["node", "vite/client", "naive-ui/volar"],
"strict": true,
// "sourceMap": true,
"removeComments": false,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"skipLibCheck": true
},
// "include": ["src/**/*.d.ts", "src/**/*.vue", "./*.d.ts"]
"exclude": ["node_modules", "dist"]

View File

@ -1,4 +1,6 @@
import { defineConfig, presetAttributify, presetUno } from 'unocss' // https://github.com/unocss/unocss
import { defineConfig, presetAttributify, presetUno } from 'unocss'
// https://github.com/unocss/unocss
export default defineConfig({
presets: [presetUno({ dark: 'class' }), presetAttributify()],

View File

@ -4,17 +4,13 @@ import { defineConfig, loadEnv } from 'vite'
import { createViteProxy, setVitePlugins } from './build'
import { proxyConfig } from './src/config'
// 当前执行node命令时文件夹的地址工作目录
const rootPath: string = resolve(process.cwd())
const srcPath = `${rootPath}/src`
// https://vitejs.dev/config/
export default defineConfig(({ mode }: ConfigEnv) => {
// 在开发环境下 command 的值为 serve 生产环境下为 build
// 根据当前工作目录中的 `mode` 加载 .env 文件
// 设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
const env = loadEnv(mode, process.cwd(), '') as unknown as ImportMetaEnv
const env = loadEnv(mode, __dirname, '') as unknown as ImportMetaEnv
const envConfig = proxyConfig[mode as ServiceEnvType]
return {
@ -22,8 +18,7 @@ export default defineConfig(({ mode }: ConfigEnv) => {
plugins: setVitePlugins(env),
resolve: {
alias: {
'~': rootPath,
'@': srcPath,
'@': resolve(__dirname, 'src'),
},
},
server: {