This commit is contained in:
邓洁
2023-11-24 00:02:22 +08:00
parent ed477a0ff5
commit dd326df745
26 changed files with 10246 additions and 8 deletions

6
.env.development Normal file
View File

@@ -0,0 +1,6 @@
# 开发环境基地址
VITE_BASE_URL='/api'
# VITE_BASE_URL='http://192.168.101.7:8000'
VITE_BASE_WSURL='ws://web-tunnel.feashow.com/api'

7
.env.production Normal file
View File

@@ -0,0 +1,7 @@
# 生产环境基地址
VITE_TITLE='fateverse'
VITE_BASE_URL='/api'
VITE_BASE_WSURL='ws://web-tunnel.feashow.com/api'

33
.gitignore vendored
View File

@@ -1,11 +1,28 @@
# ---> Vue # Logs
# gitignore template for Vue.js projects logs
# *.log
# Recommended template: Node.gitignore npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# TODO: where does this rule come from? node_modules
docs/_book .DS_Store
dist
dist-ssr
coverage
*.local
# TODO: where does this rule come from? /cypress/videos/
test/ /cypress/screenshots/
# Editor directories and files
.vscode
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!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>Tunnel Cloud</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

9202
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

31
package.json Normal file
View File

@@ -0,0 +1,31 @@
{
"name": "tunnel-cloud-web",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.4.0",
"echarts": "^5.4.2",
"element-plus": "^2.3.5",
"nprogress": "^0.2.0",
"pinia": "^2.0.35",
"sass": "^1.62.1",
"scss": "^0.2.4",
"js-cookie": "^3.0.5",
"unplugin-icons": "^0.16.1",
"vite-plugin-inspect": "^0.7.26",
"vue": "^3.2.47",
"vue-router": "^4.1.6"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.1",
"unplugin-auto-import": "^0.15.3",
"unplugin-vue-components": "^0.24.1",
"vite": "^4.3.4"
}
}

1
public/vite.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

7
src/App.vue Normal file
View File

@@ -0,0 +1,7 @@
<template>
<RouterView />
</template>
<script setup>
</script>

View File

@@ -0,0 +1,227 @@
* {
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
}
a {
text-decoration: none;
color: #333;
}
html, body, #app, .el-container, .el-aside, .el-main {
height: 100%;
}
.logo {
height: 106px;
color: #EDC49A;
font-weight: bold;
font-size: 23px;
display: flex;
justify-content: center;
align-items: center;
}
.el-menu {
border: none !important;
}
.toggle {
line-height: 65px;
padding: 0 15px;
cursor: pointer;
&:hover {
background-color: #79bbff;
}
}
.icon {
width: 20px;
height: 20px;
vertical-align: middle;
transform: translateY(-2px);
}
.el-main {
padding: 0 !important;
}
.el-aside {
box-shadow: 4px 0 2px 1px rgb(171, 167, 167);
transition: width 0.3s;
overflow: hidden;
height: 100vh;
background-color: #211F31;
}
.el-popover.el-popper {
padding: 10px !important;
min-width: 60px !important;
ul{
li{
height: 25px;
line-height: 25px;
cursor: pointer;
}
}
}
.navbar {
height: 65px;
border-bottom: 1px solid #999999;
padding: 0 15px 0 0;
display: flex;
justify-content: flex-start;
align-items: center;
.right-bar {
margin-left: auto;
display: flex;
justify-content: flex-start;
align-items: center;
img {
width: 40px;
height: 40px;
border-radius: 50%;
cursor: pointer;
}
}
}
.el-dialog {
border-radius: 12px !important;
border: none;
.el-dialog__header {
border-top-left-radius: 12px;
border-top-right-radius: 12px;
// background-color: #262626;
margin: 0;
// .el-dialog__title{
// color: white;
// }
}
}
.table-header-btn {
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 10px;
}
.query-form {
.el-form-item__label {
font-weight: 700;
}
.el-button {
font-size: 13px;
}
}
.query-btn {
margin-bottom: 10px;
.el-button {
font-size: 13px;
}
}
.table {
thead .el-table-column--selection .cell {
display: none;
}
margin-bottom: 20px;
}
.dialog-form {
.el-form-item {
flex-direction: column;
margin-bottom: 10px;
.el-form-item__content {
.el-select {
flex-grow: 1;
}
}
.el-form-item__label {
justify-content: flex-start;
}
}
}
.custom-dialog {
:deep .el-dialog__header {
padding: 10px 20px;
.el-dialog__title {
font-size: 17px;
}
.el-dialog__headerbtn {
top: 15px;
.i {
font-size: large;
}
}
}
:deep .el-dialog__footer {
padding: 10px 20px;
}
}
.border {
:deep .el-dialog__header {
border-bottom: 1px solid #e8e8e8;
}
:deep .el-dialog__footer {
border-top: 1px solid #e8e8e8;
}
}
.layout {
display: flex;
justify-content: space-around;
.layout-left {
width: 30%;
border: 1px solid #ebeef5;
padding: 10px;
.dict-tree {
width: 100%;
display: flex;
justify-content: space-between;
//:deep .el-button{
// //border: 1px solid;
// background-color: #fff;
//}
.left-type {
margin-right: 20px;
font-size: 12px;
color: #999;
}
}
}
.layout-right {
width: 70%;
border: 1px solid #ebeef5;
margin-left: 10px;
padding: 10px
}
}

View File

1
src/assets/vue.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

View File

@@ -0,0 +1,40 @@
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Install
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a>
in your IDE for a better DX
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>

View File

@@ -0,0 +1,44 @@
<template>
<div class="app-main-container">
<router-view v-slot="{ Component, route }">
<transition name="fade-transform" type="transition" appear mode="out-in">
<div>
<component
:is="Component"
:key="route.fullPath"
></component>
</div>
</transition>
</router-view>
</div>
</template>
<style lang="scss">
.app-main-container {
padding: 15px;
max-height: calc(100vh - 96px);
overflow: auto;
}
/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
transition: all 0.5s;
}
/* 可能为enter失效拆分为 enter-from和enter-to */
.fade-transform-enter-from {
opacity: 0;
transform: translateX(-30px);
}
.fade-transform-enter-to {
opacity: 1;
transform: translateX(0px);
}
.fade-transform-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>

42
src/layout/index.vue Normal file
View File

@@ -0,0 +1,42 @@
<template>
<el-container>
<el-aside
:width="!siderbarStore.getSiderBarStatus() ? '200px' : 'fit-content'"
:class="!siderbarStore.getSiderBarStatus() ? 'expand' : ''"
>
<SiderBar></SiderBar>
</el-aside>
<el-main>
<NavBar></NavBar>
<TagsView></TagsView>
<AppMain></AppMain>
</el-main>
</el-container>
</template>
<script setup>
import SiderBar from './siderbar/index.vue'
import NavBar from './navbar/index.vue'
import TagsView from './tagsview/index.vue'
import AppMain from './appmain/AppMain.vue';
import {useSiderBar} from '../store/siderbar';
const siderbarStore = useSiderBar()
</script>
<style lang="scss" scoped>
.expand {
animation: Expand 0.3s ease forwards;
}
@keyframes Expand {
from {
width: 64px;
}
to {
width: 200px;
}
}
</style>

View File

@@ -0,0 +1,47 @@
<template>
<el-breadcrumb separator=">">
<el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="item.path">
<span v-if="item.meta.noRedirect || index === breadcrumbList.length-1" class="no-redirect">
{{ item.meta.title }}
</span>
<router-link v-else :to="item.redirect || item.path">
{{ item.meta.title }}
</router-link>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup>
const route = useRoute()
const router = useRouter()
watch(route, () => {
getBreadcrumb()
})
//面包屑导航数据
const breadcrumbList = ref([])
//获取面包屑导航数据
const getBreadcrumb = () => {
let matched = route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0]
if (!isDashboard(first)) {
matched = [{path: '/home', meta: {title: '首页'}}].concat(matched)
}
breadcrumbList.value.length = 0;
const reBreadcrumbList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
breadcrumbList.value.push(...reBreadcrumbList)
}
const isDashboard = (meta) => {
const name = meta && meta.name
if (!name) {
return
}
return name.trim().toLocaleLowerCase() === 'Home'.toLocaleLowerCase()
}
getBreadcrumb()
</script>

View File

@@ -0,0 +1,14 @@
<template>
<div class="toggle" @click="toggleClick">
<component :is="siderbarStore.getSiderBarStatus() ? 'Fold' : 'Expand'" class="icon"></component>
</div>
</template>
<script setup>
import {useSiderBar} from '@/store/siderbar.js'
const siderbarStore = useSiderBar()
const toggleClick = () => {
siderbarStore.setSiderBarStatus()
}
</script>

View File

@@ -0,0 +1,37 @@
<template>
<div class="navbar">
<Hamburger></Hamburger>
<Breadcrumb></Breadcrumb>
<div class="right-bar">
<el-popover
placement="bottom"
:width="80"
trigger="click"
>
<template #reference>
<img src="@/assets/vue.svg" alt="">
</template>
<template #default>
<ul>
<li @click="handleToAuth">个人中心</li>
<li @click="handleLogout">退出登录</li>
</ul>
</template>
</el-popover>
</div>
</div>
</template>
<script setup>
import Breadcrumb from './Breadcrumb.vue';
import Hamburger from './Hamburger.vue';
const router = useRouter()
const handleToAuth = () => {
router.push('/auth')
}
const handleLogout = () => {
router.push('/login')
}
</script>

View File

@@ -0,0 +1,25 @@
<template>
<div class="logo" ref="logo">
<span v-if="!siderbarStore.getSiderBarStatus()">TUNNEL-CLOUD</span>
</div>
<el-menu
router
:default-active="activeMenu"
:unique-opened="true"
:collapse="siderbarStore.getSiderBarStatus()"
active-text-color="#EDC49A"
background-color='#211F31'
text-color="#fff"
>
<el-menu-item index="/">
<el-icon><User /></el-icon>
<template #title>首页</template>
</el-menu-item>
</el-menu>
</template>
<script setup>
import {useSiderBar} from '@/store/siderbar.js'
const siderbarStore = useSiderBar()
</script>

View File

@@ -0,0 +1,92 @@
<template>
<div class="link-box">
<el-scrollbar noresize>
<div>
<router-link
v-for="item in tagsViewStore.visitedViews"
:key="item.path" :to="{ path: item.path }" class="tag"
:class="isActive(item) ? 'active' : ''"
@click.prevent
@contextmenu.prevent.native="openMenu(item, $event)">
<span>{{ item.meta.title }}</span>
<component is="CircleClose" class="close" @click.prevent="closeTagView(item.path)"></component>
</router-link>
</div>
</el-scrollbar>
</div>
</template>
<script setup>
import { useTagsView } from '@/store/tagsview.js'
const route = useRoute()
const tagsViewStore = useTagsView()
const visible = ref(false)
const left = ref()
const top = ref()
watch(route, () => {
init()
})
const init = () => {
tagsViewStore.addVisitedViews(route)
}
const closeTagView = (path) => {
tagsViewStore.delVisitedViews(path)
}
const isActive = (tag) => {
return tag.path === route.path
}
const openMenu = (tag, e) => {
left.value = e.x + 10
top.value = e.y + 10
visible.value = true
}
init()
</script>
<style lang="scss" scoped>
.close {
width: 12px;
height: 12px;
margin-left: 5px;
}
.link-box {
padding: 0 15px;
border-bottom: 1px solid #222;
line-height: 30px;
}
.tag {
padding: 3px 6px;
border: 1px solid #666;
font-size: 14px;
margin-right: 5px;
border-radius: 3px;
}
.active {
background-color: #211F31;
color: #EDC49A;
border: none;
}
.contextmenu {
position: absolute;
z-index: 3000;
background: #fff;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
li {
margin: 0;
padding: 7px 16px;
cursor: pointer;
&:hover {
background: #eee;
color: #EDC49A;
}
}
}
</style>

24
src/main.js Normal file
View File

@@ -0,0 +1,24 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
//导入图标组件
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import '@/assets/styles/index.scss'
import '@/assets/styles/sidebar.scss'
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(ElementPlus,{locale: zhCn})
app.use(createPinia())
app.use(router)
app.mount('#app')

78
src/router/index.js Normal file
View File

@@ -0,0 +1,78 @@
import { createRouter, createWebHashHistory } from 'vue-router';
import NProgress from 'nprogress'//进度条
import 'nprogress/nprogress.css'
import Layout from '@/layout/index.vue'
// import { getToken } from '../utils/auth'
// import { usePermissionStore } from '../store/permisstion.js'
// import { useAuthStore } from '../store/userstore.js'
NProgress.configure({ showSpinner: false })
const routes = [
{
path: '/login',
name: 'login',
component: ()=>import('@/views/login/index.vue'),
meta: {
hidden: true,
title: '登录'
}
},
{
path: '/',
name: 'layout',
component: Layout,
redirect: '/home',
meta: {
hidden: false
},
children: [
{
path: '/home',
name: 'home',
component: () => import('@/views/home/index.vue'),
meta: {
title: '首页',
breadcrumb: true
}
}
]
},
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
// router.beforeEach(async (to,form,next)=>{
// const permissionStore = usePermissionStore()
// const authStore = useAuthStore()
// NProgress.start()
// if(!getToken()) {
// if(to.path === '/login') {
// next()
// NProgress.done()
// }else {
// next({path: '/login'})
// }
// }else {
// if(to.path === '/login') {
// next('/')
// NProgress.done()
// }else {
// permissionStore.setIsLoadRoutes(true)
// if(permissionStore.isLoadRoutes && permissionStore.asyncRouters.length==0){
// // await authStore.setUserInfo()
// next({...to, replace: true})
// } else {
// next()
// }
// }
//
// }
// })
router.afterEach(()=>{
NProgress.done()
})
export default router;

19
src/store/siderbar.js Normal file
View File

@@ -0,0 +1,19 @@
import { defineStore } from "pinia";
export const useSiderBar = defineStore('siderbar',()=>{
//定义控制侧边栏是否展开变量默认展开
const isCollapse = ref(false)
//获取侧边栏状态
const getSiderBarStatus = () => {
return isCollapse.value
}
//设置侧边栏状态
const setSiderBarStatus = () => {
const status = getSiderBarStatus()
return isCollapse.value = !status
}
return {
getSiderBarStatus,
setSiderBarStatus,
}
})

56
src/store/tagsview.js Normal file
View File

@@ -0,0 +1,56 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { useRouter } from "vue-router";
export const useTagsView = defineStore('tagsView',()=>{
const router = useRouter()
//已显示的标签页list
const visitedViews = ref([])
//添加标签页面
const addVisitedViews = ({path,meta}) => {
if(visitedViews.value.length == 0) {
visitedViews.value.push({path,meta})
}else {
const paths = visitedViews.value.map(item => item.path)
if(paths.includes(path) == false) {
visitedViews.value.push({path,meta})
}
}
}
//删除标签页
const delVisitedViews = (path) => {
console.log('进入删除');
if(visitedViews.value.length - 1 == 0) {
return
}
visitedViews.value.forEach((item,index)=>{
if(item.path == path) {
visitedViews.value.splice(index,1)
}
})
toLastTagView(visitedViews)
}
//删除其他标签页
const delOtherVisitedViews = ({path,meta}) => {
visitedViews.value = []
visitedViews.value.push({path,meta})
toLastTagView(visitedViews)
}
//路由到末尾标签页
const toLastTagView = (view) => {
console.log(view,'进入跳转末页');
const lastTagView = view.value.slice(-1)[0]
router.push(lastTagView.path)
}
return {
visitedViews,
addVisitedViews,
delVisitedViews,
delOtherVisitedViews,
}
})

14
src/views/home/index.vue Normal file
View File

@@ -0,0 +1,14 @@
<template>
<div>
home
</div>
</template>
<script setup>
// import { useCacheStore } from '@/store/cache.js'
// const cacheStore = useCacheStore()
// cacheStore.setCacheKey(['normal_disable','show_hide'])
</script>
<style lang="scss" scoped>
</style>

92
src/views/login/index.vue Normal file
View File

@@ -0,0 +1,92 @@
<template>
<div class="login-box">
<el-form
:model="loginForm"
ref="formInstance"
:rules="rules"
label-width="65px"
>
<h3>Rib-Account-ADMIN</h3>
<el-form-item prop="username" label="账号">
<el-input v-model="loginForm.username" :prefix-icon="User"></el-input>
</el-form-item>
<el-form-item prop="password" label="密码">
<el-input v-model="loginForm.password" type="password" :prefix-icon="Lock"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="handleLogin(formInstance)" type="primary">登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import {onBeforeUnmount, reactive,} from 'vue'
// import {useAuthStore} from '@/store/userstore'
import {ElLoading} from 'element-plus'
import {User, Lock, Key} from '@element-plus/icons-vue'
const router = useRouter()
// const authStore = useAuthStore()
const loginForm = reactive({
username: 'admin',
password: '123456',
uuid: ''
})
const formInstance = ref()
const rules = reactive({
username: [
{required: true, message: '请输入账户名', trigger: 'blur'},
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
]
})
const handleLogin = (instance) => {
if (!instance) return
instance.validate(async (valid) => {
if (!valid) return
// 发送请求
// await authStore.userLogin(loginForm).then(res=>{
// if(res) {
ElLoading.service({text: '正在加载系统资源', background: '#409eff', lock: true})
await router.push('/')
// }
// })
})
}
onBeforeUnmount(() => {
ElLoading.service({text: '正在加载系统资源', background: '#409eff', lock: true}).close()
})
</script>
<style lang="scss" scoped>
.login-box {
height: 100%;
background-color: #4158D0;
background-image: linear-gradient(43deg, #4158D0 0%, #C850C0 46%, #FFCC70 100%);
display: flex;
justify-content: center;
align-items: center;
.el-form {
padding: 12px 15px;
border-radius: 12px;
width: 25%;
background-color: #fff;
h3 {
width: 100%;
text-align: center;
margin-bottom: 15px;
}
.el-button {
width: 100%;
}
}
}
</style>

102
vite.config.js Normal file
View File

@@ -0,0 +1,102 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
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 vue from '@vitejs/plugin-vue'
import Inspect from 'vite-plugin-inspect'
export default defineConfig({
plugins: [
vue(),
AutoImport({
//自动导入vue相关函数
imports: ['vue','vue-router'],
resolvers: [
ElementPlusResolver(),
//自动导入图标组件
IconsResolver({
prefix: 'Icon',
}),
],
}),
Components({
resolvers: [
// 自动注册图标组件
IconsResolver({
enabledCollections: ['ep'],
}),
//自动导入组件
ElementPlusResolver()
],
}),
Icons({
autoInstall: true,
}),
Inspect(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
minify: 'esbuild',
terserOptions: {
compress: {
drop_console: false, // 生产环境移除log
drop_debugger: false // 生产环境禁用debugger
}
}
},
server: {
host: '0.0.0.0',
port: 8888,
strictPort: false,
open: true,
proxy: {
// '/api/custom': {
// // target: 'http://web-tunnel.feashow.com/api',
// target: 'http://192.168.31.175:8000',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ''),
// },
// '/api/admin': {
// target: 'http://web-tunnel.feashow.com/api',
// // target: 'http://192.168.31.175:8000',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ''),
// },
// '/api/auth': {
// target: 'http://web-tunnel.feashow.com/api',
// // target: 'http://192.168.31.175:8000',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ''),
// },
// '/api/log': {
// // target: 'http://web-tunnel.feashow.com/api',
// target: 'http://192.168.31.175:8000',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ''),
// },
// '/api/code-gen': {
// // target: 'http://web-tunnel.feashow.com/api',
// target: 'http://192.168.31.175:8000',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ''),
// },
'/api': {
target: 'http://web-tunnel.feashow.com/api',
// target: 'http://192.168.31.175:8000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/socket': {
target: 'ws://web-tunnel.feashow.com/api/notice-ws/notice',
ws: true
}
}
}
})