24 changed files with 319 additions and 4141 deletions
-
67.eslintrc
-
BIN.husky/commit-msg
-
1.husky/pre-commit
-
23README.md
-
BINcommitlint.config.js
-
39package.json
-
3768pnpm-lock.yaml
-
BINpublic/favicon.ico
-
5src/apis/system.ts
-
10src/components/common/FTTable/expand.ts
-
199src/components/common/FTTable/index.vue
-
10src/env.d.ts
-
4src/libs/constant.ts
-
154src/libs/http.ts
-
20src/libs/token.ts
-
28src/main.ts
-
37src/router/index.ts
-
30src/router/routes.ts
-
12src/stores/useMainStore.ts
-
15src/views/login/index.vue
-
2src/views/main/index.vue
-
4src/views/page/index.vue
-
30tsconfig.json
-
2vite.config.ts
@ -1,67 +0,0 @@ |
|||
{ |
|||
"root": true, |
|||
"env": { |
|||
"browser": true, |
|||
"node": true, |
|||
"vue/setup-compiler-macros": true, |
|||
"es2021": true |
|||
}, |
|||
"globals": { |
|||
"defineEmits": "readonly", |
|||
"defineProps": "readonly", |
|||
"defineExpose": "readonly" |
|||
}, |
|||
"parser": "vue-eslint-parser", |
|||
"extends": [ |
|||
"eslint:recommended", |
|||
"plugin:vue/vue3-recommended", |
|||
"plugin:@typescript-eslint/recommended", |
|||
"plugin:prettier/recommended", |
|||
"prettier", |
|||
"./.eslintrc-auto-import.json" |
|||
], |
|||
"parserOptions": { |
|||
"ecmaVersion": 12, |
|||
"parser": "@typescript-eslint/parser", |
|||
"sourceType": "module", |
|||
"ecmaFeatures": { |
|||
"jsx": true |
|||
} |
|||
}, |
|||
"plugins": ["vue", "@typescript-eslint", "prettier"], |
|||
"rules": { |
|||
"no-explicit-any": "off", |
|||
"@typescript-eslint/ban-ts-ignore": "off", |
|||
"@typescript-eslint/no-unused-vars": "off", |
|||
"@typescript-eslint/explicit-function-return-type": "off", |
|||
"@typescript-eslint/no-explicit-any": "off", |
|||
"@typescript-eslint/no-var-requires": "off", |
|||
"@typescript-eslint/no-empty-function": "off", |
|||
"@typescript-eslint/no-use-before-define": "off", |
|||
"@typescript-eslint/ban-ts-comment": "off", |
|||
"@typescript-eslint/ban-types": "off", |
|||
"@typescript-eslint/no-non-null-assertion": "off", |
|||
"@typescript-eslint/explicit-module-boundary-types": "off", |
|||
"no-var": "error", |
|||
"prettier/prettier": "error", |
|||
"vue/multi-word-component-names": 0, |
|||
"camelcase": 2, |
|||
"consistent-this": [2, "that"], |
|||
"eqeqeq": 2, |
|||
"no-await-in-loop": 0, |
|||
"consistent-return": 0, |
|||
"no-plusplus": 0, |
|||
"no-unused-expressions": 0, |
|||
"operator-linebreak": 0, |
|||
"comma-dangle": [ |
|||
2, |
|||
{ |
|||
"arrays": "ignore", |
|||
"objects": "ignore", |
|||
"imports": "never", |
|||
"exports": "never", |
|||
"functions": "ignore" |
|||
} |
|||
] |
|||
} |
|||
} |
@ -1 +0,0 @@ |
|||
npm run lint:lint-staged |
@ -0,0 +1,23 @@ |
|||
### 前端项目模板 |
|||
##### 文件目录 |
|||
- src |
|||
- components 组件目录 |
|||
- apis 接口文件目录 |
|||
- assets 静态资源目录 |
|||
- hooks hooks目录 |
|||
- libs 公共工具类 |
|||
- router 页面路由 |
|||
- stores 项目公共状态管理 |
|||
- types 类型申明 |
|||
- views 页面目录 |
|||
##### 项目运行 |
|||
项目采用pnpm 进行依赖构建,请先安装pnpm |
|||
[pnpm - 速度快、节省磁盘空间的软件包管理器](https://pnpm.io/) |
|||
```bash |
|||
npm install pnpm -g |
|||
``` |
|||
|
|||
```bash |
|||
pnpm install // 安装依赖 |
|||
pnpm dev // 运行项目 |
|||
``` |
3768
pnpm-lock.yaml
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,9 +1,8 @@ |
|||
import http from 'libs/http'; |
|||
import {AxiosResponse} from "axios"; |
|||
import http from 'libs/http' |
|||
|
|||
/** |
|||
* 登录接口 |
|||
* @param params |
|||
*/ |
|||
|
|||
export const login = (params : {username:string; password:string}) => http.post('/auth/login', params); |
|||
export const login = (params: { username: string, password: string }) => http.post('/auth/login', params) |
@ -1,7 +1,7 @@ |
|||
export default { |
|||
props: ['row', 'render', 'index', 'column'], |
|||
inheritAttrs: false, |
|||
setup(props: any) { |
|||
return () => props.render(props.row); |
|||
}, |
|||
props: ['row', 'render', 'index', 'column'], |
|||
inheritAttrs: false, |
|||
setup(props: any) { |
|||
return () => props.render(props.row) |
|||
}, |
|||
} |
@ -1,6 +1,6 @@ |
|||
declare module '*.vue' { |
|||
import type { DefineComponent } from 'vue'; |
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
|||
const component: DefineComponent<{}, {}, any>; |
|||
export default component; |
|||
} |
|||
import type { DefineComponent } from 'vue' |
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
|||
const component: DefineComponent<{}, {}, any> |
|||
export default component |
|||
} |
@ -1,5 +1,5 @@ |
|||
// 请求头里token的名称
|
|||
export const HEADER_TOKEN_KEY = 'Authorization'; |
|||
export const HEADER_TOKEN_KEY = 'Authorization' |
|||
|
|||
// sessionStorage里token的名称
|
|||
export const SESSIONSTORAGE_TOKEN_KEY = 'web_token'; |
|||
export const SESSIONSTORAGE_TOKEN_KEY = 'web_token' |
@ -1,93 +1,99 @@ |
|||
import axios from 'axios'; |
|||
import { ElMessage } from 'element-plus'; |
|||
import { getToken } from 'libs/token'; |
|||
import { HEADER_TOKEN_KEY } from '@/libs/constant'; |
|||
import { HEADER_TOKEN_KEY } from '@/libs/constant' |
|||
import axios from 'axios' |
|||
import { ElMessage } from 'element-plus' |
|||
import { getToken } from 'libs/token' |
|||
|
|||
const http = axios.create({ |
|||
baseURL: `/api`, |
|||
timeout: 1000 * 60 |
|||
}); |
|||
baseURL: `/api`, |
|||
timeout: 1000 * 60, |
|||
}) |
|||
|
|||
// 请求拦截器
|
|||
http.interceptors.request.use( |
|||
(config) => { |
|||
if (getToken()) { |
|||
config.headers![HEADER_TOKEN_KEY] = getToken(); |
|||
} |
|||
return config; |
|||
}, |
|||
(error: any) => { |
|||
return Promise.reject(error); |
|||
(config) => { |
|||
if (getToken()) { |
|||
config.headers![HEADER_TOKEN_KEY] = getToken() |
|||
} |
|||
); |
|||
return config |
|||
}, |
|||
(error: any) => { |
|||
return Promise.reject(error) |
|||
}, |
|||
) |
|||
|
|||
// 响应拦截器
|
|||
http.interceptors.response.use( |
|||
(response) => { |
|||
if ( |
|||
response.status === 200 && |
|||
response.data.data !== undefined && |
|||
!response.data.data |
|||
) { |
|||
// 返回错误拦截
|
|||
ElMessage.error(response.data.msg); |
|||
return Promise.reject(response); |
|||
} else if ( |
|||
response.config.url?.includes('/files/download') || |
|||
response.config.url?.includes('downloadStream') |
|||
) { |
|||
return response.data; |
|||
} else if (response.data instanceof Blob) { |
|||
return response.data; |
|||
} else if ( |
|||
response.config.url?.includes('/espAnalysis/generateReport') || |
|||
response.config.url?.includes('/dcDataQuery/downLoadData') |
|||
) { |
|||
return response; |
|||
} |
|||
return response.data.data; // 返回数据体
|
|||
}, |
|||
(error: any) => { |
|||
console.log(error); |
|||
if (error.response && error.response.status === 401) { |
|||
ElMessage.error('账号权限过期'); |
|||
// TODO 登出
|
|||
} else { |
|||
if (error.message.indexOf('timeout') > -1) { |
|||
ElMessage.error('请求超时'); |
|||
} else if (error.message.indexOf('Network') > -1) { |
|||
ElMessage.error('网络连接错误'); |
|||
} else { |
|||
ElMessage.error(error.message); |
|||
} |
|||
error.response = { |
|||
data: { |
|||
res: false |
|||
} |
|||
}; |
|||
return Promise.reject(error.response); |
|||
} |
|||
(response) => { |
|||
if ( |
|||
response.status === 200 |
|||
&& response.data.data !== undefined |
|||
&& !response.data.data |
|||
) { |
|||
// 返回错误拦截
|
|||
ElMessage.error(response.data.msg) |
|||
return Promise.reject(response) |
|||
} |
|||
); |
|||
else if ( |
|||
response.config.url?.includes('/files/download') |
|||
|| response.config.url?.includes('downloadStream') |
|||
) { |
|||
return response.data |
|||
} |
|||
else if (response.data instanceof Blob) { |
|||
return response.data |
|||
} |
|||
else if ( |
|||
response.config.url?.includes('/espAnalysis/generateReport') |
|||
|| response.config.url?.includes('/dcDataQuery/downLoadData') |
|||
) { |
|||
return response |
|||
} |
|||
return response.data.data // 返回数据体
|
|||
}, |
|||
(error: any) => { |
|||
console.log(error) |
|||
if (error.response && error.response.status === 401) { |
|||
ElMessage.error('账号权限过期') |
|||
// TODO 登出
|
|||
} |
|||
else { |
|||
if (error.message.includes('timeout')) { |
|||
ElMessage.error('请求超时') |
|||
} |
|||
else if (error.message.includes('Network')) { |
|||
ElMessage.error('网络连接错误') |
|||
} |
|||
else { |
|||
ElMessage.error(error.message) |
|||
} |
|||
error.response = { |
|||
data: { |
|||
res: false, |
|||
}, |
|||
} |
|||
return Promise.reject(error.response) |
|||
} |
|||
}, |
|||
) |
|||
|
|||
// 封装 GET 请求
|
|||
export const get = <T>(url: string, params?: any): Promise<T> => { |
|||
return http.get(url, { params }); |
|||
}; |
|||
export function get<T>(url: string, params?: any): Promise<T> { |
|||
return http.get(url, { params }) |
|||
} |
|||
|
|||
// 封装 POST 请求
|
|||
export const post = <T>(url: string, data?: any): Promise<T> => { |
|||
return http.post(url, data); |
|||
}; |
|||
export function post<T>(url: string, data?: any): Promise<T> { |
|||
return http.post(url, data) |
|||
} |
|||
|
|||
// 封装 PUT 请求
|
|||
export const put = <T>(url: string, data?: any): Promise<T> => { |
|||
return http.put(url, data); |
|||
}; |
|||
export function put<T>(url: string, data?: any): Promise<T> { |
|||
return http.put(url, data) |
|||
} |
|||
|
|||
// 封装 DELETE 请求
|
|||
export const del = <T>(url: string, params?: any): Promise<T> => { |
|||
return http.delete(url, { params }); |
|||
}; |
|||
export function del<T>(url: string, params?: any): Promise<T> { |
|||
return http.delete(url, { params }) |
|||
} |
|||
|
|||
export default http; |
|||
export default http |
@ -1,13 +1,13 @@ |
|||
import { SESSIONSTORAGE_TOKEN_KEY } from './constant'; |
|||
import { SESSIONSTORAGE_TOKEN_KEY } from './constant' |
|||
|
|||
export const getToken = () => { |
|||
return sessionStorage[SESSIONSTORAGE_TOKEN_KEY]; |
|||
}; |
|||
export function getToken() { |
|||
return sessionStorage[SESSIONSTORAGE_TOKEN_KEY] |
|||
} |
|||
|
|||
export const setToken = (token: string) => { |
|||
sessionStorage[SESSIONSTORAGE_TOKEN_KEY] = token; |
|||
}; |
|||
export function setToken(token: string) { |
|||
sessionStorage[SESSIONSTORAGE_TOKEN_KEY] = token |
|||
} |
|||
|
|||
export const delToken = () => { |
|||
sessionStorage.removeItem(SESSIONSTORAGE_TOKEN_KEY); |
|||
}; |
|||
export function delToken() { |
|||
sessionStorage.removeItem(SESSIONSTORAGE_TOKEN_KEY) |
|||
} |
@ -1,17 +1,17 @@ |
|||
import { createApp } from 'vue'; |
|||
import { createPinia } from 'pinia'; |
|||
import App from './app.vue'; |
|||
import router from './router'; |
|||
import ElementPlus from 'element-plus'; |
|||
import 'element-plus/dist/index.css'; |
|||
import locale from 'element-plus/es/locale/lang/zh-cn' |
|||
import FtTable from 'components/common/FTTable/index.vue' |
|||
import ElementPlus from 'element-plus' |
|||
import locale from 'element-plus/es/locale/lang/zh-cn' |
|||
import { createPinia } from 'pinia' |
|||
import { createApp } from 'vue' |
|||
import App from './app.vue' |
|||
import router from './router' |
|||
import 'element-plus/dist/index.css' |
|||
|
|||
const app = createApp(App); |
|||
const pinia = createPinia(); |
|||
app.component('FtTable', FtTable); |
|||
const app = createApp(App) |
|||
const pinia = createPinia() |
|||
app.component('FtTable', FtTable) |
|||
app |
|||
.use(router) |
|||
.use(pinia) |
|||
.use(ElementPlus, { locale: locale, zIndex: 3000 }) |
|||
.mount('#app') |
|||
.use(router) |
|||
.use(pinia) |
|||
.use(ElementPlus, { locale, zIndex: 3000 }) |
|||
.mount('#app') |
@ -1,23 +1,26 @@ |
|||
import { createRouter, createWebHashHistory, RouteLocationNormalized, NavigationGuardNext } from 'vue-router'; |
|||
import { getToken } from '@/libs/token'; |
|||
import routes from './routes'; |
|||
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router' |
|||
import { getToken } from '@/libs/token' |
|||
import { createRouter, createWebHashHistory } from 'vue-router' |
|||
import routes from './routes' |
|||
|
|||
const router = createRouter({ |
|||
history: createWebHashHistory(), |
|||
routes |
|||
}); |
|||
history: createWebHashHistory(), |
|||
routes, |
|||
}) |
|||
|
|||
router.beforeEach((to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => { |
|||
if (getToken()) { |
|||
next(); |
|||
} else { |
|||
// 未登录
|
|||
if (to.name === 'login') { |
|||
next(); |
|||
} else { |
|||
next({ name: 'login' }); |
|||
} |
|||
if (getToken()) { |
|||
next() |
|||
} |
|||
else { |
|||
// 未登录
|
|||
if (to.name === 'login') { |
|||
next() |
|||
} |
|||
}); |
|||
else { |
|||
next({ name: 'login' }) |
|||
} |
|||
} |
|||
}) |
|||
|
|||
export default router; |
|||
export default router |
@ -1,28 +1,28 @@ |
|||
import { RouteRecordRaw } from 'vue-router'; |
|||
import type { RouteRecordRaw } from 'vue-router' |
|||
|
|||
const authRoutes: RouteRecordRaw[] = [ |
|||
{ |
|||
path: '', |
|||
name: 'home', |
|||
component: () => import('../views/page/index.vue'), |
|||
meta: { |
|||
isDefault: true, |
|||
tagName: '首页' |
|||
} |
|||
path: '', |
|||
name: 'home', |
|||
component: () => import('../views/page/index.vue'), |
|||
meta: { |
|||
isDefault: true, |
|||
tagName: '首页', |
|||
}, |
|||
}, |
|||
]; |
|||
] |
|||
const routes: RouteRecordRaw[] = [ |
|||
{ |
|||
path: '/login', |
|||
name: 'login', |
|||
component: () => import('../views/login/index.vue') |
|||
component: () => import('../views/login/index.vue'), |
|||
}, |
|||
{ |
|||
path: '/', |
|||
component: () => import('../views/main/index.vue'), |
|||
children: authRoutes |
|||
} |
|||
]; |
|||
children: authRoutes, |
|||
}, |
|||
] |
|||
|
|||
export { authRoutes }; |
|||
export default routes; |
|||
export { authRoutes } |
|||
export default routes |
@ -1,13 +1,13 @@ |
|||
import { defineStore } from 'pinia' |
|||
|
|||
export const useMainStore = defineStore('main',{ |
|||
state:()=>{ |
|||
export const useMainStore = defineStore('main', { |
|||
state: () => { |
|||
return { |
|||
userInfo: { |
|||
userName: '', |
|||
} |
|||
}, |
|||
} |
|||
}, |
|||
getters:{}, |
|||
actions:{} |
|||
}) |
|||
getters: {}, |
|||
actions: {}, |
|||
}) |
@ -1,17 +1,16 @@ |
|||
<script setup lang="ts"> |
|||
import {setToken} from "libs/token"; |
|||
import router from "@/router"; |
|||
import {login} from "apis/system"; |
|||
import router from '@/router' |
|||
import { login } from 'apis/system' |
|||
import { setToken } from 'libs/token' |
|||
|
|||
login({username: 'admin', password: '12345'}).then((res) => { |
|||
console.log(res) |
|||
// setToken(res.data) |
|||
login({ username: 'admin', password: '12345' }).then((res) => { |
|||
setToken(res.data) |
|||
router.push('/') |
|||
}) |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
|
|||
<div>登录</div> |
|||
</template> |
|||
|
|||
<style scoped></style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue