# Jing-Admin
**Repository Path**: whale_8/jing-admin
## Basic Information
- **Project Name**: Jing-Admin
- **Description**: No description available
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2025-09-08
- **Last Updated**: 2026-01-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# vue-project
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and
disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for
type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the
TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
pnpm install
```
### Compile and Hot-Reload for Development
```sh
pnpm dev
```
### Type-Check, Compile and Minify for Production
```sh
pnpm build
```
### Lint with [ESLint](https://eslint.org/)
```sh
pnpm lint
```
### 配置环境
vite.config.js
```
import { ViteEjsPlugin } from 'vite-plugin-ejs'
const root = process.cwd() // 获取根路径
//判断环境
const isBuild = command === 'build'
let actualMode = mode
if (!actualMode) {
actualMode = isBuild ? 'production' : 'development'
}
const env = loadEnv(actualMode, root)
plugins: [
vue(),
vueDevTools(),
ViteEjsPlugin({
title: env.VITE_APP_TITLE,
}),
],
```
index.html
```
<%= title %>
```
### 添加element-plus
```shell
pnpm install element-plus
```
### main.ts 中引入
```
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)
```
### 添加 animate.css 动画库
```shell
npm install animate.css --save
```
main.ts
```
import 'animate.css'
```
### 添加axios
```shell
pnpm i axios
```
#### 创建axios 文件夹
添加index.ts 文件
```
import service from './service'
import { CONTENT_TYPE } from '@/constants'
// 调用service请求
const request = (option: AxiosConfig) => {
const { url, method, params, data, headers, responseType } = option
const userStore = useUserStoreWithOut()
return service.request({
url:url,
method,
params,
data: data,
responseType: responseType,
headers: {
'Content-Type': CONTENT_TYPE,
[userStore.getTokenKey ?? 'Authorization']: userStore.getToken ?? '',
...headers,
}
})
}
// 封装请求方法
export default {
get: (option: AxiosConfig) => {
return request({ method: 'get', ...option }) as Promise>
},
post: (option: AxiosConfig) => {
return request({ method: 'post', ...option }) as Promise>
},
delete: (option: AxiosConfig) => {
return request({ method: 'delete', ...option }) as Promise>
},
put: (option: AxiosConfig) => {
return request({ method: 'put', ...option }) as Promise>
},
cancelRequest: (url: string | string[]) => {
return service.cancelRequest(url)
},
cancelAllRequest: () => {
return service.cancelAllRequest()
}
}
```
#### 创建 service.ts
```
import axios, { AxiosError } from 'axios'
import type { InternalAxiosRequestConfig, AxiosResponse } from 'axios'
import type {RequestConfig}from './types'
import { ElMessage } from 'element-plus'
import { REQUEST_TIMEOUT } from '@/constants'
import { defaultRequestInterceptors, defaultResponseInterceptors } from '@/axios/config.ts'
export const PATH_URL = import.meta.env.VITE_API_BASE_PATH
const abortControllerMap: Map = new Map()
// 创建
const axiosInstance = axios.create({
timeout: REQUEST_TIMEOUT,
baseURL: PATH_URL,
})
//拦截器
axiosInstance.interceptors.request.use(
(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => {
const controller = new AbortController() //中止控制器
const url = config?.url || ''
config.signal = controller.signal // 绑定
abortControllerMap.set(url, controller) //添加到map中
return config
},
)
// 响应拦截器
axiosInstance.interceptors.response.use(
(res: AxiosResponse) => {
const url = res.config.url || '' // 成功后再map中删除url
abortControllerMap.delete(url)
// 这里不能做任何处理,否则后面的 interceptors 拿不到完整的上下文了
return res
},
(error: AxiosError) => { //返回错误信息
console.log('err: ' + error)
ElMessage.error(error.message)
return Promise.reject(error)
},
)
// use
axiosInstance.interceptors.request.use(defaultRequestInterceptors)
axiosInstance.interceptors.response.use(defaultResponseInterceptors)
//创建service 封装请求 \取消请求 \ 取消全部请求
const service = {
request: (config: RequestConfig) => {
return new Promise((resolve, reject) => {
if (config.interceptors?.requestInterceptors) {
config = config.interceptors.requestInterceptors(config as any)
}
axiosInstance
.request(config)
.then((res) => {
resolve(res)
})
.catch((err: any) => {
reject(err)
})
})
},
cancelRequest: (url: string | string[]) => {
const urlList = Array.isArray(url) ? url : [url]
for (const _url of urlList) {
abortControllerMap.get(_url)?.abort() //取消
abortControllerMap.delete(_url) // 删除
}
},
cancelAllRequests: () => {
for (const [_, controller] of abortControllerMap) {
controller.abort() //取消
}
abortControllerMap.clear()
},
}
export default service
```
#### 创建config.ts
```
import type { AxiosResponse, InternalAxiosRequestConfig } from './types'
import { ElMessage } from 'element-plus'
import qs from 'qs'
import { SUCCESS_CODE, TRANSFORM_REQUEST_DATA } from '@/constants'
import { objToFormData } from '@/utils'
// 请求拦截器
const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
if(config.method === 'post' && config.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
// 内容类型(Content-Type),主要用于处理表单数据。 键值对(key-value pairs) 的形式
config.data = qs.stringify(config.data)
}else if (
TRANSFORM_REQUEST_DATA &&
config.method === 'post' &&
config.headers['Content-Type'] === 'multipart/form-data' &&
!(config.data instanceof FormData)
){
// 文件传输
config.data = objToFormData(config.data)
}
if (config.method === 'get' && config.params) {
let url = config.url as string
url += '?'
const keys = Object.keys(config.params)
for (const key of keys) {
if (config.params[key] !== void 0 && config.params[key] !== null) {
url += `${key}=${encodeURIComponent(config.params[key])}&`
}
}
url = url.substring(0, url.length - 1)
config.params = {}
config.url = url
}
return config
}
// 响应拦截器
const defaultResponseInterceptors = (response: AxiosResponse) => {
if (response?.config?.responseType === 'blob') {
return response
} else if (response?.data.code === SUCCESS_CODE){
return response.data
}else {
ElMessage.error(response?.data?.message)
//退出登录
if (response?.data?.code === 401) {
// const userStore = useUserStoreWithOut()
//userStore.logout()
}
}
}
export { defaultResponseInterceptors, defaultRequestInterceptors }
```
#### 使用
```
import request from '@/axios'
export const loginApi = (data: UserType): Promise> => {
return request.post({ url: '/mock/user/login', data })
}
```
### mock
```shell
import { viteMockServe } from 'vite-plugin-mock'
// vite.config.ts
viteMockServe({
ignore: /^\_/,
mockPath: 'mock',
})
```
### pinia
添加持久化 pinia-plugin-persistedstate
index.ts
```
import type { App } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const store = createPinia()
store.use(piniaPluginPersistedstate)
export const setupStore = (app: App) => {
app.use(store)
}
export { store }
```
main.ts
```
// 引入状态管理
import { setupStore } from '@/stores'
app.use(setupStore)
```