chore(admin): 优化构建配置并升级资源格式
- 新增构建插件:打包分析、压缩、自动部署、图片优化和PWA支持 - 将SVG资源转换为WebP格式以提升加载性能 - 添加新的背景图片资源用于用户界面优化 - 更新环境配置:调整基础URL和服务地址 - 优化用户界面组件以适配新的资源格式 - 更新package.json依赖以支持新的构建功能 - 改进构建流程以支持自动部署和性能监控
@ -1,6 +1,6 @@
|
||||
# 应用的基础URL,默认为 "/"
|
||||
# 如果使用子目录,必须以 "/" 结尾,例如 "/admin/" 而不是 "/admin"
|
||||
# VITE_BASE_URL='/admin'
|
||||
VITE_BASE_URL='/'
|
||||
|
||||
# VITE_BASE_URL="https://api.qyzhjy.com"
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
# VITE_SERVICE_BASE_URL=https://api.qyzhjy.com
|
||||
|
||||
VITE_SERVICE_BASE_URL=http://api.ydzx.qyzhjy.com
|
||||
VITE_SERVICE_BASE_URL=https://172.16.10.130:5000
|
||||
|
||||
VITE_OTHER_SERVICE_BASE_URL= `{
|
||||
"demo": "http://localhost:9528"
|
||||
|
||||
11
apps/admin/build/plugins/analyzer.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { PluginOption } from 'vite'
|
||||
import { visualizer } from 'rollup-plugin-visualizer'
|
||||
|
||||
export function setupAnalyzer() {
|
||||
return visualizer({
|
||||
open: true,
|
||||
gzipSize: true,
|
||||
brotliSize: true,
|
||||
filename: 'report.html',
|
||||
}) as PluginOption
|
||||
}
|
||||
11
apps/admin/build/plugins/compression.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import viteCompression from 'vite-plugin-compression'
|
||||
|
||||
export function setupCompression() {
|
||||
return viteCompression({
|
||||
verbose: true,
|
||||
disable: false,
|
||||
threshold: 10240,
|
||||
algorithm: 'gzip',
|
||||
ext: '.gz',
|
||||
})
|
||||
}
|
||||
21
apps/admin/build/plugins/deploy.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { viteAutoDeployPlugin } from 'vite-auto-deploy'
|
||||
import { name } from '../../package.json'
|
||||
|
||||
export function setupDeploy(isBuild: boolean) {
|
||||
return viteAutoDeployPlugin({
|
||||
/** 上传地址 */
|
||||
uploadUrl: 'http://47.109.17.238:8200/api/upload/code/deploy',
|
||||
/** 项目名称 (如果多个项目都是用的同上传地址时,服务端可用此字段区分是哪一个项目) */
|
||||
projectKey: name,
|
||||
/** 上传完成后,是否保留压缩包到本地 */
|
||||
saveLocalZip: true,
|
||||
/** 是否开启自动部署 */
|
||||
autoDeploy: isBuild,
|
||||
headers: {
|
||||
'Custom-Timestamp': new Date().getTime().toString(),
|
||||
'Custom-Run-Platform': 'app',
|
||||
'Custom-Device-Id': Math.random().toString(36).substring(2),
|
||||
'Custom-Os-Name': 'windows',
|
||||
},
|
||||
})
|
||||
}
|
||||
51
apps/admin/build/plugins/image-optimizer.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'
|
||||
|
||||
export function setupImageOptimizer() {
|
||||
return ViteImageOptimizer({
|
||||
logStats: true,
|
||||
|
||||
// SVG 优化配置
|
||||
svg: {
|
||||
multipass: true,
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false,
|
||||
cleanupIds: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
'sortAttrs',
|
||||
],
|
||||
},
|
||||
|
||||
// PNG 高质量压缩
|
||||
png: {
|
||||
quality: 90,
|
||||
compressionLevel: 9,
|
||||
},
|
||||
|
||||
// JPEG 优化
|
||||
jpeg: {
|
||||
quality: 85,
|
||||
mozjpeg: true,
|
||||
},
|
||||
jpg: {
|
||||
quality: 85,
|
||||
mozjpeg: true,
|
||||
},
|
||||
|
||||
// WebP 转换
|
||||
webp: {
|
||||
quality: 80,
|
||||
lossless: false,
|
||||
force: true,
|
||||
},
|
||||
|
||||
includePublic: true,
|
||||
cache: true,
|
||||
cacheLocation: 'node_modules/.cache/image-optimizer',
|
||||
})
|
||||
}
|
||||
@ -2,14 +2,20 @@ import type { PluginOption } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import progress from 'vite-plugin-progress'
|
||||
import { setupAnalyzer } from './analyzer'
|
||||
import { setupCompression } from './compression'
|
||||
import { setupDeploy } from './deploy'
|
||||
import { setupDevtoolsPlugin } from './devtools'
|
||||
import { setupHtmlPlugin } from './html'
|
||||
import { setupImageOptimizer } from './image-optimizer'
|
||||
import { setupPWA } from './pwa'
|
||||
import { setupElegantRouter } from './router'
|
||||
import { setupUnocss } from './unocss'
|
||||
import { setupUnplugin } from './unplugin'
|
||||
|
||||
export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) {
|
||||
export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string, isBuild: boolean) {
|
||||
const plugins: PluginOption = [
|
||||
// 基础插件
|
||||
vue(),
|
||||
vueJsx(),
|
||||
setupDevtoolsPlugin(viteEnv),
|
||||
@ -18,7 +24,18 @@ export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) {
|
||||
...setupUnplugin(viteEnv),
|
||||
progress(),
|
||||
setupHtmlPlugin(buildTime),
|
||||
|
||||
// 优化插件
|
||||
setupImageOptimizer(),
|
||||
setupCompression(),
|
||||
setupPWA(),
|
||||
setupDeploy(isBuild),
|
||||
]
|
||||
|
||||
// 构建时添加打包分析插件
|
||||
if (isBuild) {
|
||||
plugins.push(setupAnalyzer())
|
||||
}
|
||||
|
||||
return plugins
|
||||
}
|
||||
|
||||
51
apps/admin/build/plugins/pwa.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { VitePWA } from 'vite-plugin-pwa'
|
||||
|
||||
export function setupPWA() {
|
||||
return VitePWA({
|
||||
registerType: 'autoUpdate',
|
||||
workbox: {
|
||||
globPatterns: ['**/*.{js,css,html,ico,png,svg,webp,jpg,jpeg}'],
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'google-fonts-cache',
|
||||
expiration: {
|
||||
maxEntries: 10,
|
||||
maxAgeSeconds: 60 * 60 * 24 * 365, // 1 year
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'masked-icon.svg'],
|
||||
manifest: {
|
||||
name: '阅读之星竞赛系统',
|
||||
short_name: '阅读之星',
|
||||
description: '教育学会树人研究院阅读之星竞赛系统',
|
||||
theme_color: '#ffffff',
|
||||
background_color: '#ffffff',
|
||||
display: 'standalone',
|
||||
orientation: 'landscape',
|
||||
icons: [
|
||||
{
|
||||
src: 'pwa-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: 'pwa-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: 'pwa-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
purpose: 'any maskable',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -82,6 +82,7 @@
|
||||
"eslint": "9.39.2",
|
||||
"eslint-plugin-vue": "10.6.2",
|
||||
"kolorist": "1.8.0",
|
||||
"rollup-plugin-visualizer": "^7.0.1",
|
||||
"sass": "1.97.1",
|
||||
"simple-git-hooks": "2.13.1",
|
||||
"tsx": "4.21.0",
|
||||
@ -90,7 +91,10 @@
|
||||
"unplugin-vue-components": "30.0.0",
|
||||
"vite": "7.3.0",
|
||||
"vite-auto-deploy": "^2.0.34",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-image-optimizer": "^2.0.3",
|
||||
"vite-plugin-progress": "0.0.7",
|
||||
"vite-plugin-pwa": "^1.2.0",
|
||||
"vite-plugin-svg-icons": "2.0.1",
|
||||
"vite-plugin-vue-devtools": "8.0.5",
|
||||
"vue-eslint-parser": "10.2.0",
|
||||
|
||||
BIN
apps/admin/src/assets/imgs/user/cover-back.webp
Normal file
|
After Width: | Height: | Size: 304 KiB |
BIN
apps/admin/src/assets/imgs/user/cover-bg-active.jpg
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 2.7 MiB |
BIN
apps/admin/src/assets/imgs/user/draw.webp
Normal file
|
After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 3.8 MiB |
BIN
apps/admin/src/assets/imgs/user/event-card-bg-icon.webp
Normal file
|
After Width: | Height: | Size: 740 KiB |
|
Before Width: | Height: | Size: 7.2 MiB |
BIN
apps/admin/src/assets/imgs/user/event-card-bg.webp
Normal file
|
After Width: | Height: | Size: 445 KiB |
BIN
apps/admin/src/assets/imgs/user/home-bg.jpg
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
apps/admin/src/assets/imgs/user/read-logo 1.webp
Normal file
|
After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 10 MiB |
BIN
apps/admin/src/assets/imgs/user/star-icon.webp
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
apps/admin/src/assets/imgs/user/team-bg-animation.webp
Normal file
|
After Width: | Height: | Size: 907 KiB |
|
Before Width: | Height: | Size: 16 MiB |
BIN
apps/admin/src/assets/imgs/user/team-bg.webp
Normal file
|
After Width: | Height: | Size: 907 KiB |
|
Before Width: | Height: | Size: 5.5 MiB |
BIN
apps/admin/src/assets/imgs/user/team-title-icon.webp
Normal file
|
After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 3.2 MiB |
BIN
apps/admin/src/assets/imgs/user/title-bg.webp
Normal file
|
After Width: | Height: | Size: 549 KiB |
|
Before Width: | Height: | Size: 3.0 MiB |
BIN
apps/admin/src/assets/imgs/user/title-bg2.webp
Normal file
|
After Width: | Height: | Size: 449 KiB |
@ -1,9 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import VScaleScreen from 'v-scale-screen'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import _defaultBg from '@/assets/imgs/user/home-bg.svg'
|
||||
import titleBg2 from '@/assets/imgs/user/title-bg2.svg'
|
||||
import _defaultTitleBg from '@/assets/imgs/user/title-bg.svg'
|
||||
import _defaultBg from '@/assets/imgs/user/home-bg.jpg'
|
||||
import titleBg2 from '@/assets/imgs/user/title-bg2.webp'
|
||||
import _defaultTitleBg from '@/assets/imgs/user/title-bg.webp'
|
||||
import { useRouterPush } from '@/hooks/common/router'
|
||||
|
||||
import ActionButton from './ActionButton.vue'
|
||||
@ -29,7 +29,7 @@ interface Props {
|
||||
btnTheme?: 'primary' | 'light'
|
||||
/** 是否禁用下一步按钮 */
|
||||
nextDisabled?: boolean
|
||||
/** 标题区域背景图片URL,不传则使用默认 title-bg.svg */
|
||||
/** 标题区域背景图片URL,不传则使用默认 title-bg.webp */
|
||||
titleBgType?: number
|
||||
/** 是否显示第二个下一步按钮 */
|
||||
showNextBtn2?: boolean
|
||||
@ -218,11 +218,11 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.scroll-bg {
|
||||
width: 412px !important; /* Fixed width to prevent squishing during animation */
|
||||
height: 165px !important;
|
||||
width: 400px !important; /* Fixed width to prevent squishing during animation */
|
||||
height: 155px !important;
|
||||
position: relative;
|
||||
background: no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
background-size: contain;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@ -344,7 +344,7 @@ onMounted(async () => {
|
||||
.card-back-design {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('@/assets/imgs/user/cover-back.svg') no-repeat center center; // 背景面
|
||||
background: url('@/assets/imgs/user/cover-back.webp') no-repeat center center; // 背景面
|
||||
background-size: contain; // 保持比例
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import drawImg from '@/assets/imgs/user/draw.svg'
|
||||
import drawImg from '@/assets/imgs/user/draw.webp'
|
||||
import CompetitionLayout from '@/components/custom/user/CompetitionLayout.vue'
|
||||
import { useRouterPush } from '@/hooks/common/router'
|
||||
import { fetchGetCurrentQuestion } from '@/service/api/game'
|
||||
@ -169,7 +169,7 @@ const questionTitle = computed(() => question.value?.QuestionList?.QuestionConte
|
||||
}}</span>
|
||||
</div> -->
|
||||
<!-- 禁用放大 -->
|
||||
<NImage :src="drawImg" class="h-full w-full object-cover" :preview-disabled="true" />
|
||||
<NImage :src="drawImg" class="h-full w-full object-cover" width="300" height="300" :preview-disabled="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -228,7 +228,16 @@ async function fetchGetGameStatisticsData(_params: Api.Competition.QuestionAddPa
|
||||
correct: item.Points || 0, // 预估得分 (使用外层 Points)
|
||||
})
|
||||
})
|
||||
chartData.value = Array.from(teamMap.values())
|
||||
|
||||
const newChartData = Array.from(teamMap.values())
|
||||
|
||||
// 只有数据真正变化时才更新
|
||||
const currentDataStr = JSON.stringify(chartData.value)
|
||||
const newDataStr = JSON.stringify(newChartData)
|
||||
|
||||
if (currentDataStr !== newDataStr) {
|
||||
chartData.value = newChartData
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import * as echarts from 'echarts/core'
|
||||
import { watch } from 'vue'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { type ECOption, useEcharts } from '@/hooks/common/echarts'
|
||||
|
||||
@ -15,6 +15,21 @@ const props = defineProps<{
|
||||
height?: number
|
||||
}>()
|
||||
|
||||
// 缓存上一次的数据,用于深度比较
|
||||
const lastDataCache = ref<string>('')
|
||||
|
||||
/**
|
||||
* 深度比较数据是否发生变化
|
||||
*/
|
||||
function isDataChanged(newData: BarDatum[]): boolean {
|
||||
const newDataStr = JSON.stringify(newData)
|
||||
if (newDataStr === lastDataCache.value) {
|
||||
return false
|
||||
}
|
||||
lastDataCache.value = newDataStr
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建柱状图配置
|
||||
* 说明:根据传入的数据生成双系列柱状图(答题数量/正确数量)
|
||||
@ -25,6 +40,8 @@ function buildOption(list: BarDatum[]): ECOption {
|
||||
const correct = list.map(i => i.correct)
|
||||
|
||||
return {
|
||||
// 禁用动画,避免频繁刷新时的抖动
|
||||
animation: false,
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' },
|
||||
@ -113,12 +130,15 @@ const { domRef, updateOptions } = useEcharts<ECOption>(() => buildOption(props.d
|
||||
|
||||
/**
|
||||
* 监听数据变化并更新图表
|
||||
* 说明:当父组件 chartData 更新时,动态刷新柱状图
|
||||
* 说明:只有当数据真正发生变化时才更新图表,避免不必要的重绘
|
||||
*/
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
updateOptions(() => buildOption(val || []))
|
||||
(newData) => {
|
||||
// 只有数据真正变化时才更新
|
||||
if (isDataChanged(newData || [])) {
|
||||
updateOptions(() => buildOption(newData || []))
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
@ -3,7 +3,7 @@ import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import groupType1 from '@/assets/imgs/user/group-type-1.svg'
|
||||
import groupType2 from '@/assets/imgs/user/group-type-2.svg'
|
||||
import startIcon from '@/assets/imgs/user/star-icon.svg'
|
||||
import startIcon from '@/assets/imgs/user/star-icon.webp'
|
||||
import CompetitionLayout from '@/components/custom/user/CompetitionLayout.vue'
|
||||
import { useRouterPush } from '@/hooks/common/router'
|
||||
import { fetchGetGroupListByActivityID } from '@/service/api/game'
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { NCarousel, NImage } from 'naive-ui'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import beacon from '@/assets/imgs/user/event-card-bg-icon.svg'
|
||||
import beacon from '@/assets/imgs/user/event-card-bg-icon.webp'
|
||||
import CompetitionLayout from '@/components/custom/user/CompetitionLayout.vue'
|
||||
import { PublishStatus } from '@/enum/business'
|
||||
import { useRouterPush } from '@/hooks/common/router'
|
||||
@ -156,7 +156,7 @@ onMounted(() => {
|
||||
.event-card {
|
||||
width: 340px;
|
||||
height: 480px;
|
||||
background: url('@/assets/imgs/user/event-card-bg.svg') no-repeat center center;
|
||||
background: url('@/assets/imgs/user/event-card-bg.webp') no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 8px 8px 40px 40px;
|
||||
position: relative;
|
||||
|
||||
@ -177,7 +177,7 @@ function rowClassName(row: TeamData) {
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: url('@/assets/imgs/user/team-bg.svg') no-repeat center center;
|
||||
background: url('@/assets/imgs/user/team-bg.webp') no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
transform-origin: center;
|
||||
padding: 40px 20px;
|
||||
|
||||
@ -111,7 +111,7 @@ onMounted(() => {
|
||||
:style="{ '--delay': `${index * 0.4}s` }" @click="selectTeam(item.id)"
|
||||
>
|
||||
<div class="icon-wrapper">
|
||||
<img src="@/assets/imgs/user/team-title-icon.svg" alt="team-icon" class="h-full w-full object-cover">
|
||||
<img src="@/assets/imgs/user/team-title-icon.webp" alt="team-icon" class="h-full w-full object-cover">
|
||||
</div>
|
||||
<div class="team-name">
|
||||
{{ item.name }}
|
||||
@ -175,10 +175,21 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
// 浮动动画关键帧
|
||||
@keyframes float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-15px);
|
||||
}
|
||||
}
|
||||
|
||||
.title-section {
|
||||
position: absolute;
|
||||
top: 18%; // 使用百分比定位,适应不同比例
|
||||
left: 7%; // 微调位置,根据 1920x1080 下的视觉效果调整
|
||||
top: 130px; // 使用固定像素值,确保在卷轴内部
|
||||
left: 40px; // 距离左边缘的固定距离
|
||||
z-index: 10;
|
||||
|
||||
.scroll-bg {
|
||||
@ -193,6 +204,38 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
// 添加响应式适配
|
||||
@media (max-width: 1920px) {
|
||||
.title-section {
|
||||
top: 70px;
|
||||
left: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1440px) {
|
||||
.title-section {
|
||||
top: 60px;
|
||||
left: 40px;
|
||||
|
||||
.scroll-bg .main-title {
|
||||
font-size: 2.5rem;
|
||||
letter-spacing: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.title-section {
|
||||
top: 50px;
|
||||
left: 30px;
|
||||
|
||||
.scroll-bg .main-title {
|
||||
font-size: 2rem;
|
||||
letter-spacing: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.competition-layout :deep(.main-content) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -217,10 +260,12 @@ onMounted(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: url('@/assets/imgs/user/team-bg-animation.svg') no-repeat center center;
|
||||
background: url('@/assets/imgs/user/team-bg-animation.webp') no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
transform-origin: center; // 确保从中心展开
|
||||
will-change: clip-path; // 优化性能
|
||||
will-change: clip-path, transform; // 优化性能
|
||||
animation: float 3s ease-in-out infinite; // 添加浮动动画
|
||||
padding: 60px 80px; // 添加内边距,确保内容在卷轴内部
|
||||
|
||||
&::before {
|
||||
left: -15px;
|
||||
@ -232,11 +277,12 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.scroll-content {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
width: 80%; // 减小宽度,为标题留出空间
|
||||
height: 70%; // 调整高度
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// margin-left: 120px; // 为左侧标题留出空间
|
||||
}
|
||||
|
||||
.teams-grid {
|
||||
|
||||
@ -27,7 +27,7 @@ export default defineConfig((configEnv) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: setupVitePlugins(viteEnv, buildTime),
|
||||
plugins: setupVitePlugins(viteEnv, buildTime, configEnv.command === 'build'),
|
||||
define: {
|
||||
BUILD_TIME: JSON.stringify(buildTime),
|
||||
},
|
||||
|
||||