首次提交
|
|
@ -0,0 +1,3 @@
|
|||
VITE_BASE_URL_API = 'http://192.168.2.9:5192'
|
||||
|
||||
VITE_ENV = 'development'
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
VITE_BASE_URL_API = https://meeting-api.23544.com/pc
|
||||
|
||||
VITE_ENV = 'production'
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
VITE_BASE_URL_API = https://meeting-api.23544.com/pc
|
||||
|
||||
VITE_ENV = 'test'
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# Windows
|
||||
[Dd]esktop.ini
|
||||
Thumbs.db
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
|
||||
# Node.js
|
||||
node_modules/
|
||||
dist/
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
export {}
|
||||
declare global {
|
||||
const ElLoading: typeof import('element-plus/es')['ElLoading']
|
||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"name": "vue3-project-template",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"test": "vite --mode test",
|
||||
"prod": "vite --mode production",
|
||||
"build": "vite build",
|
||||
"build:dev": "vite build --mode development",
|
||||
"build:test": "vite build --mode test",
|
||||
"build:prod": "vite build --mode production",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --ext src/**/*.{js,jsx,vue,ts,tsx} --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"agora-rtc-sdk-ng": "^4.23.1",
|
||||
"axios": "^1.4.0",
|
||||
"element-plus": "^2.3.7",
|
||||
"js-md5": "^0.7.3",
|
||||
"pinia": "^2.1.4",
|
||||
"vue": "^3.2.47",
|
||||
"vue-router": "^4.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/ep": "^1.1.11",
|
||||
"@types/node": "^20.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
||||
"@typescript-eslint/parser": "^6.3.0",
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"@vue/cli-plugin-eslint": "^5.0.8",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^8.46.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.28.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-plugin-vue": "^9.16.1",
|
||||
"postcss-px-to-viewport": "^1.1.1",
|
||||
"sass": "^1.63.6",
|
||||
"terser": "^5.18.1",
|
||||
"typescript": "^5.0.2",
|
||||
"unplugin-auto-import": "^0.16.4",
|
||||
"unplugin-icons": "^0.16.3",
|
||||
"unplugin-vue-components": "^0.25.1",
|
||||
"vite": "^4.3.9",
|
||||
"vite-plugin-inspect": "^0.7.29",
|
||||
"vue-tsc": "^1.4.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from "vue";
|
||||
onMounted(() => {
|
||||
init();
|
||||
})
|
||||
const init = async () => {
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { request } from '@/utils'
|
||||
export const GetRoomRtcToken = (roomNum: string) =>
|
||||
request({
|
||||
url: `/room/tk/rtc?roomNum=${roomNum}`,
|
||||
method: 'get',
|
||||
})
|
||||
|
||||
export const GetAgoraConf = () =>
|
||||
request({
|
||||
url: `/home/agora-conf`,
|
||||
method: 'get',
|
||||
})
|
||||
|
||||
export const GetPolling = (roomNum: string, count: string) =>
|
||||
request({
|
||||
url: `/room/polling?roomNum=${roomNum}&count=${count}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
After Width: | Height: | Size: 860 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 297 KiB |
|
After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 836 KiB |
|
After Width: | Height: | Size: 456 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 297 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 336 KiB |
|
After Width: | Height: | Size: 770 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 412 B |
|
After Width: | Height: | Size: 352 B |
|
After Width: | Height: | Size: 159 KiB |
|
|
@ -0,0 +1,17 @@
|
|||
// 常量配置
|
||||
enum constant {
|
||||
CONFIG_TITLE = 'vue3-vite-ts-pinia',
|
||||
CONFIG_REQUEST_TIMEOUT_TIME = 10000, // 请求超时时间 10秒
|
||||
CONFIG_TOKEN = 'token', // token
|
||||
CONFIG_USERINFO = 'USERINFO', // 用户信息
|
||||
CONFIG_STATUS_CODE_SUCCESS = 100, // 自定义代码 100成功、101失败
|
||||
CONFIG_STATUS_CODE_ERROR = 101,
|
||||
CONFIG_USERNAME_KEY = 'USERNAME', // 用户名
|
||||
CONFIG_PASSWORD_KEY = 'PASSWORD', // 密码
|
||||
CONFIG_IS_REMEMBER_KEY = 'REMEMBER', // 是否记住密码
|
||||
CONFIG_CODE_SUCCESS = 200, // 成功码
|
||||
}
|
||||
// 常规配置
|
||||
const config = {}
|
||||
|
||||
export { config, constant }
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
function user() {
|
||||
return {}
|
||||
}
|
||||
export default user
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { createApp } from 'vue'
|
||||
import router from './router'
|
||||
import './styles/index.scss'
|
||||
import App from './App.vue'
|
||||
|
||||
import Store from './store'
|
||||
|
||||
// 清除项目中的console
|
||||
if (import.meta.env.VITE_ENV !== 'development') {
|
||||
console.log = function () { }
|
||||
}
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(router).use(Store).mount('#app')
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
<template>
|
||||
<div class="home">
|
||||
<div class="home-header">
|
||||
<span>距离下次刷新监控人员还剩{{ timeNumber }}秒</span>
|
||||
<el-button type="primary" @click="refreshUserList" style="margin-left: 10px;">刷新</el-button>
|
||||
</div>
|
||||
<div class="home-content" v-if="userList.length">
|
||||
<div v-for="item in userList" class="home-content-item">
|
||||
<div class="home-content-item-card" :id="'player-wrapper-' + item.uid">
|
||||
<div class="home-content-item-card-name">{{ item.userName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<di class="home-content-item">
|
||||
<div class="home-content-item-card">
|
||||
</div>
|
||||
</di>
|
||||
<di class="home-content-item">
|
||||
<div class="home-content-item-card">
|
||||
</div>
|
||||
</di>
|
||||
<di class="home-content-item">
|
||||
<div class="home-content-item-card">
|
||||
</div>
|
||||
</di>
|
||||
<di class="home-content-item">
|
||||
<div class="home-content-item-card">
|
||||
</div>
|
||||
</di>
|
||||
<div class="home-content-item">
|
||||
<div class="home-content-item-card">
|
||||
</div>
|
||||
</div>
|
||||
<div class="home-content-item">
|
||||
<div class="home-content-item-card">
|
||||
</div>
|
||||
</div>
|
||||
<div class="home-content-item">
|
||||
<div class="home-content-item-card">
|
||||
</div>
|
||||
</div>
|
||||
<div class="home-content-item">
|
||||
<div class="home-content-item-card">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="home-content" v-else style="justify-content: center;align-items: center;align-content: center;">
|
||||
<el-empty description="暂无数据" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, onUnmounted } from "vue";
|
||||
import { agora } from "@/utils/package/agora";
|
||||
import { GetAgoraConf, GetPolling, GetRoomRtcToken } from "@/api";
|
||||
import { storage } from '@/utils'
|
||||
const userList = ref<any>([])
|
||||
const channel = ref('')
|
||||
const timer = ref<NodeJS.Timeout>()
|
||||
const timeNumber = ref(30)
|
||||
onMounted(() => {
|
||||
init()
|
||||
startCountdown()
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(timer.value)
|
||||
});
|
||||
|
||||
const startCountdown = () => {
|
||||
clearInterval(timer.value);
|
||||
timeNumber.value = 30;
|
||||
timer.value = setInterval(() => {
|
||||
timeNumber.value--;
|
||||
if (timeNumber.value === 0) {
|
||||
refreshUserList();
|
||||
timeNumber.value = 30;
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
const init = async () => {
|
||||
const paramsString = location.search.startsWith('?') ? location.search.slice(1) : location.search;
|
||||
const searchParams = new URLSearchParams(paramsString)
|
||||
channel.value = searchParams.get('channel') as string;
|
||||
storage.setItem('token', searchParams.get('token'))
|
||||
agora.setOptions('uid', Number(searchParams.get('uid')))
|
||||
agora.setOptions('channel', channel.value)
|
||||
await getAgoraConf()
|
||||
await getPolling()
|
||||
await getRoomRtcToken()
|
||||
agoraOn()
|
||||
};
|
||||
|
||||
const getAgoraConf = async () => {
|
||||
await GetAgoraConf().then(res => {
|
||||
if (res.code === 200) {
|
||||
agora.init();
|
||||
agora.setOptions('appId', res.data)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
const getPolling = async () => {
|
||||
await GetPolling(channel.value, '9').then((res: any) => {
|
||||
if (res.code === 200) {
|
||||
userList.value = res.data.map((item: any) => {
|
||||
return {
|
||||
...item,
|
||||
newScreenShareId: Number(1 + item.screenShareId)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
};
|
||||
const refreshUserList = async () => {
|
||||
await agora.leave()
|
||||
await getPolling()
|
||||
await getRoomRtcToken()
|
||||
};
|
||||
const getRoomRtcToken = async () => {
|
||||
GetRoomRtcToken(channel.value).then(res => {
|
||||
if (res.code === 200) {
|
||||
agora.setOptions('token', res.data)
|
||||
agora.join()
|
||||
}
|
||||
})
|
||||
};
|
||||
const agoraOn = async () => {
|
||||
agora.on({
|
||||
userPublished: (user: any, mediaType: 'video' | 'audio') => {
|
||||
if (mediaType === 'video') {
|
||||
user.videoTrack.play(document.getElementById(`player-wrapper-${user.uid}`));
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.home {
|
||||
background-color: rgb(7, 9, 11);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 4px 120px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&-header {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
&-content {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
|
||||
&-item {
|
||||
height: calc(100% / 3);
|
||||
width: calc(100% / 3);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-card {
|
||||
width: 516px;
|
||||
height: 290px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
background-color: #101317;
|
||||
border: 1px solid #EBEBEB;
|
||||
|
||||
&-name {
|
||||
background-color: rgb(253, 194, 41);
|
||||
color: black;
|
||||
font-size: 26px;
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
padding: 0px 10px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import { RouteRecordRaw, createRouter, createWebHashHistory } from 'vue-router'
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/home' //重定向首页
|
||||
},
|
||||
{
|
||||
path: '/home',
|
||||
name: 'Home',
|
||||
component: () => import("@/pages/Home/index.vue"), //首页
|
||||
meta: {
|
||||
title: '首页',
|
||||
hasMenu: false,
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
})
|
||||
|
||||
export default router
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
/* eslint-disable */
|
||||
declare module '*.vue' {
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
declare module 'js-md5'
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { createPinia } from 'pinia'
|
||||
|
||||
const Store = createPinia()
|
||||
|
||||
export default Store
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
export const userStore = defineStore('USER', {
|
||||
state: () => ({
|
||||
isLogin: false,
|
||||
}),
|
||||
})
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
@import './public.scss';
|
||||
@import './element.scss';
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
html,
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import storage from './package/storage'
|
||||
import request from './request'
|
||||
|
||||
export { storage, request }
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import AgoraRTC, { IAgoraRTCClient, IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng"
|
||||
let client: IAgoraRTCClient;
|
||||
type optionsType = {
|
||||
appId: string;
|
||||
channel: string;
|
||||
token: string;
|
||||
uid: number;
|
||||
};
|
||||
const options: optionsType = {
|
||||
appId: "",
|
||||
channel: "",
|
||||
token: "",
|
||||
uid: 0,
|
||||
};
|
||||
export const agora = {
|
||||
// 初始化
|
||||
init: async () => {
|
||||
client = AgoraRTC.createClient({ mode: "live", codec: "vp8" });
|
||||
},
|
||||
// 设置参数
|
||||
setOptions: <K extends keyof optionsType>(key: K, value: optionsType[K]) => {
|
||||
options[key] = value;
|
||||
},
|
||||
// 加入频道
|
||||
join: async () => {
|
||||
await client.join(
|
||||
options.appId,
|
||||
options.channel,
|
||||
options.token,
|
||||
options.uid
|
||||
);
|
||||
},
|
||||
// 离开频道
|
||||
leave: async () => {
|
||||
await client.leave();
|
||||
},
|
||||
// 监听
|
||||
on: ({ userPublished }: any) => {
|
||||
client.on("user-published", async (user: IAgoraRTCRemoteUser, mediaType: 'video' | 'audio') => {
|
||||
await client.subscribe(user, mediaType)
|
||||
userPublished(user, mediaType)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
class LocalStorage {
|
||||
private constructor() {}
|
||||
|
||||
private static instance: LocalStorage | null = null
|
||||
|
||||
static getInstance() {
|
||||
if (LocalStorage.instance === null) {
|
||||
LocalStorage.instance = new LocalStorage()
|
||||
}
|
||||
return LocalStorage.instance
|
||||
}
|
||||
|
||||
setItem(key: string, value: any) {
|
||||
localStorage.setItem(key, value)
|
||||
}
|
||||
|
||||
getItem(key: string) {
|
||||
return localStorage.getItem(key)
|
||||
}
|
||||
|
||||
removeItem(key: string) {
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
|
||||
removeAll() {
|
||||
localStorage.clear()
|
||||
}
|
||||
}
|
||||
|
||||
export default LocalStorage.getInstance()
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import { AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
import Request from './request'
|
||||
import { constant } from '@/config'
|
||||
|
||||
// 实例化
|
||||
const req = new Request({
|
||||
baseURL: import.meta.env.VITE_BASE_URL_API,
|
||||
timeout: constant.CONFIG_REQUEST_TIMEOUT_TIME as number,
|
||||
interceptors: {
|
||||
// 请求拦截器
|
||||
requestInterceptors: (config: AxiosRequestConfig) => config,
|
||||
// 响应拦截器 <T = AxiosResponse>(result: T)
|
||||
responseInterceptors: <T = AxiosResponse>(result: T) => result,
|
||||
},
|
||||
})
|
||||
|
||||
const request = (config: any) => {
|
||||
const { method = 'GET' } = config
|
||||
|
||||
if (method === 'get' || method === 'GET') {
|
||||
config.params = config.data
|
||||
}
|
||||
return req.request<any>(config)
|
||||
}
|
||||
|
||||
export default request
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
import axios, { AxiosInstance, AxiosResponse } from 'axios'
|
||||
import { RequestConfig, RequestInterceptors } from './types'
|
||||
import { storage } from '@/utils'
|
||||
import { constant } from '@/config'
|
||||
import router from '@/router'
|
||||
class Request {
|
||||
// axios实例
|
||||
instance: AxiosInstance
|
||||
|
||||
// 拦截器对象
|
||||
interceptorsObj?: RequestInterceptors
|
||||
|
||||
constructor(config: RequestConfig) {
|
||||
// 创建实例
|
||||
this.instance = axios.create(config)
|
||||
|
||||
// 类请求拦截器
|
||||
this.instance.interceptors.request.use(
|
||||
(req: any) => {
|
||||
const token = storage.getItem(constant.CONFIG_TOKEN)
|
||||
console.log(token);
|
||||
if (token) {
|
||||
// 如果有token给请求头加上
|
||||
req.headers.Authorization = `Bearer ${token}`
|
||||
req.timeout = constant.CONFIG_REQUEST_TIMEOUT_TIME
|
||||
}
|
||||
return req
|
||||
},
|
||||
(err: any) => {
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
// 类响应拦截器
|
||||
this.instance.interceptors.response.use(
|
||||
(res: AxiosResponse) => {
|
||||
const { data: resData } = res
|
||||
if (resData.code !== 200) {
|
||||
ElMessage.error(resData.message)
|
||||
}
|
||||
return resData
|
||||
},
|
||||
(err: any) => {
|
||||
// 根据自己业务/接口返回做相应调整
|
||||
const { status } = err.response
|
||||
|
||||
switch (status) {
|
||||
case 401:
|
||||
// @ts-ignore
|
||||
ElMessage.warning('登录信息已失效,请关闭窗口,重新打开!')
|
||||
storage.removeItem('token')
|
||||
storage.removeItem('user')
|
||||
// router.push({ path: '/login' })
|
||||
break
|
||||
default:
|
||||
}
|
||||
const { Code } = err.response.data
|
||||
|
||||
switch (Code) {
|
||||
case 401:
|
||||
// @ts-ignore
|
||||
ElMessage.warning('登录信息已失效,请关闭窗口,重新打开!')
|
||||
storage.removeItem('token')
|
||||
storage.removeItem('user')
|
||||
// router.push({ path: '/login' })
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
request<T>(config: RequestConfig): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (config.interceptors?.requestInterceptors) {
|
||||
config = config.interceptors.requestInterceptors(config)
|
||||
}
|
||||
this.instance
|
||||
.request<any, T>(config)
|
||||
.then((res: T) => {
|
||||
// 如果我们为单个响应设置拦截器,这里使用单个响应的拦截器
|
||||
if (config.interceptors?.responseInterceptors) {
|
||||
res = config.interceptors.responseInterceptors<T>(res)
|
||||
}
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err: any) => {
|
||||
reject(err)
|
||||
}).finally(() => {
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default Request
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
|
||||
// 实例拦截器
|
||||
export interface RequestInterceptors {
|
||||
// 请求拦截
|
||||
requestInterceptors?: (config: AxiosRequestConfig) => AxiosRequestConfig
|
||||
requestInterceptorsCatch?: (err: any) => any
|
||||
// 响应拦截
|
||||
responseInterceptors?: <T = AxiosResponse>(config: T) => T
|
||||
responseInterceptorsCatch?: (err: any) => any
|
||||
}
|
||||
|
||||
// 自定义传入的参数
|
||||
export interface RequestConfig extends AxiosRequestConfig {
|
||||
interceptors?: RequestInterceptors
|
||||
}
|
||||
|
||||
export interface useRequestConfig<T> extends RequestConfig {
|
||||
data?: T
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"./auto-imports.d.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import { resolve } from 'path'
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||
import Icons from 'unplugin-icons/vite'
|
||||
import IconsResolver from 'unplugin-icons/resolver'
|
||||
import Inspect from 'vite-plugin-inspect'
|
||||
import pxtovw from 'postcss-px-to-viewport'
|
||||
|
||||
const loder_pxtovw = pxtovw({
|
||||
// 这里是设计稿宽度 自己修改
|
||||
viewportWidth: 1920,
|
||||
viewportUnit: 'vw',
|
||||
selectorBlackList: ['.prism-player'],
|
||||
})
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(() => ({
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [loder_pxtovw]
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 8080,
|
||||
host: '0.0.0.0',
|
||||
},
|
||||
resolve: {
|
||||
alias: [
|
||||
{
|
||||
find: '@',
|
||||
replacement: resolve(__dirname, 'src'),
|
||||
},
|
||||
],
|
||||
},
|
||||
build: {
|
||||
minify: 'terser',
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
AutoImport({
|
||||
resolvers: [
|
||||
ElementPlusResolver(),
|
||||
IconsResolver({
|
||||
prefix: 'Icon',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [
|
||||
ElementPlusResolver(),
|
||||
IconsResolver({
|
||||
enabledCollections: ['ep'],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Icons({
|
||||
autoInstall: true,
|
||||
}),
|
||||
Inspect(),
|
||||
],
|
||||
}))
|
||||