删除无关代码

This commit is contained in:
Guwan 2025-03-12 01:11:11 +08:00
parent 8d09254180
commit 770c78733d
9 changed files with 73 additions and 2084 deletions

View File

@ -22,7 +22,7 @@ service.interceptors.request.use(
config.headers['token'] = `eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NDE2OTUyNjQsInVzZXJuYW1lIjoiYWRtaW4ifQ.gF2Y2-P5xunAWxDL68nczO8kH9l5qpucO3PuiC5I25w`
config.headers['token'] = `eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NDE3ODAxNDMsInVzZXJuYW1lIjoiYWRtaW4ifQ._jKmdu1T-zpf_qSWRTBtovJ51v2ONC6CGF-60MLJOOE`
// 根据请求方法和数据类型动态设置 Content-Type

View File

@ -1,286 +0,0 @@
<template>
<div class="health-monitor">
<el-row :gutter="20">
<!-- 实时数据卡片 -->
<el-col :span="8" v-for="(item, index) in healthData" :key="index">
<el-card class="health-card" :class="item.status">
<template #header>
<div class="card-header">
<span>{{ item.title }}</span>
<el-tag :type="item.status">{{ item.statusText }}</el-tag>
</div>
</template>
<div class="card-content">
<div class="value-container">
<span class="value">{{ item.value }}</span>
<span class="unit">{{ item.unit }}</span>
</div>
<div class="chart-container">
<v-chart class="chart" :option="getChartOption(item)" autoresize />
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 3D人体模型 -->
<el-row class="body-model">
<el-col :span="24">
<el-card>
<template #header>
<div class="card-header">
<span>人体健康状态</span>
</div>
</template>
<div class="model-container" ref="modelContainer"></div>
</el-card>
</el-col>
</el-row>
<!-- 数据录入表单 -->
<el-dialog v-model="dialogVisible" title="健康数据录入" width="50%">
<el-form :model="form" label-width="120px">
<el-form-item label="血压(mmHg)">
<el-input-number v-model="form.systolic" :min="0" :max="200" />
/
<el-input-number v-model="form.diastolic" :min="0" :max="200" />
</el-form-item>
<el-form-item label="心率(次/分)">
<el-input-number v-model="form.heartRate" :min="0" :max="200" />
</el-form-item>
<el-form-item label="体温(℃)">
<el-input-number v-model="form.temperature" :min="35" :max="42" :precision="1" :step="0.1" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</span>
</template>
</el-dialog>
<el-button class="add-btn" type="primary" size="large" circle @click="dialogVisible = true">
<el-icon><Plus /></el-icon>
</el-button>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { LineChart } from 'echarts/charts'
import { GridComponent, TooltipComponent } from 'echarts/components'
import VChart from 'vue-echarts'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { Plus } from '@element-plus/icons-vue'
use([CanvasRenderer, LineChart, GridComponent, TooltipComponent])
const dialogVisible = ref(false)
const form = ref({
systolic: 120,
diastolic: 80,
heartRate: 75,
temperature: 36.5
})
const healthData = ref([
{
title: '血压',
value: '120/80',
unit: 'mmHg',
status: 'success',
statusText: '正常',
history: [110, 115, 120, 118, 122, 120]
},
{
title: '心率',
value: '75',
unit: '次/分',
status: 'success',
statusText: '正常',
history: [72, 75, 73, 76, 75, 75]
},
{
title: '体温',
value: '36.5',
unit: '℃',
status: 'success',
statusText: '正常',
history: [36.4, 36.5, 36.6, 36.5, 36.4, 36.5]
}
])
const getChartOption = (item) => {
return {
grid: {
top: 10,
right: 10,
bottom: 20,
left: 30
},
xAxis: {
type: 'category',
boundaryGap: false
},
yAxis: {
type: 'value',
scale: true
},
tooltip: {
trigger: 'axis'
},
series: [
{
data: item.history,
type: 'line',
smooth: true,
areaStyle: {
opacity: 0.3
}
}
]
}
}
// 3D
const modelContainer = ref(null)
let scene, camera, renderer, controls
onMounted(() => {
nextTick(() => {
initThreeJS()
})
})
const initThreeJS = () => {
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera(
75,
modelContainer.value.clientWidth / modelContainer.value.clientHeight,
0.1,
1000
)
renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(modelContainer.value.clientWidth, modelContainer.value.clientHeight)
modelContainer.value.appendChild(renderer.domElement)
//
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
scene.add(ambientLight)
//
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)
directionalLight.position.set(0, 1, 0)
scene.add(directionalLight)
camera.position.z = 5
controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
//
// const loader = new GLTFLoader()
// loader.load('path/to/human-model.glb', (gltf) => {
// scene.add(gltf.scene)
// })
animate()
}
const animate = () => {
requestAnimationFrame(animate)
controls.update()
renderer.render(scene, camera)
}
const submitForm = () => {
//
dialogVisible.value = false
//
healthData.value[0].value = `${form.value.systolic}/${form.value.diastolic}`
healthData.value[1].value = form.value.heartRate.toString()
healthData.value[2].value = form.value.temperature.toString()
}
</script>
<style scoped>
.health-monitor {
padding: 20px;
}
.health-card {
margin-bottom: 20px;
transition: all 0.3s;
}
.health-card:hover {
transform: translateY(-5px);
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.card-content {
display: flex;
flex-direction: column;
}
.value-container {
text-align: center;
margin-bottom: 20px;
}
.value {
font-size: 2em;
font-weight: bold;
margin-right: 5px;
}
.unit {
font-size: 0.9em;
color: #909399;
}
.chart-container {
height: 150px;
}
.chart {
height: 100%;
}
.model-container {
height: 500px;
width: 100%;
}
.add-btn {
position: fixed;
right: 50px;
bottom: 50px;
width: 60px;
height: 60px;
}
.success {
border-top: 3px solid #67C23A;
}
.warning {
border-top: 3px solid #E6A23C;
}
.danger {
border-top: 3px solid #F56C6C;
}
</style>

View File

@ -1,426 +0,0 @@
<template>
<div class="health-news">
<!-- 顶部轮播 -->
<el-card class="carousel-card">
<el-carousel height="300px" :interval="4000" type="card">
<el-carousel-item v-for="item in carouselData" :key="item.id">
<div class="carousel-content" :style="{ backgroundImage: `url(${item.image})` }">
<div class="carousel-info">
<h3>{{ item.title }}</h3>
<p>{{ item.description }}</p>
</div>
</div>
</el-carousel-item>
</el-carousel>
</el-card>
<!-- 分类标签 -->
<div class="category-container">
<el-tabs v-model="activeCategory" @tab-click="handleCategoryChange">
<el-tab-pane v-for="category in categories" :key="category.value" :label="category.label" :name="category.value">
<!-- 文章列表 -->
<el-row :gutter="20">
<el-col :span="16">
<div class="article-list">
<el-card v-for="article in filteredArticles" :key="article.id" class="article-card">
<div class="article-content">
<div class="article-image" v-if="article.image">
<el-image :src="article.image" fit="cover" />
</div>
<div class="article-info">
<h3 class="article-title" @click="showArticleDetail(article)">
{{ article.title }}
</h3>
<p class="article-desc">{{ article.description }}</p>
<div class="article-meta">
<span>
<el-icon><Calendar /></el-icon>
{{ article.date }}
</span>
<span>
<el-icon><View /></el-icon>
{{ article.views }}
</span>
<span>
<el-icon><Star /></el-icon>
{{ article.likes }}
</span>
<el-tag size="small" :type="article.type">{{ article.category }}</el-tag>
</div>
</div>
</div>
</el-card>
<!-- 分页 -->
<div class="pagination">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[6, 12, 24, 36]"
:total="total"
layout="total, sizes, prev, pager, next"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</el-col>
<!-- 右侧边栏 -->
<el-col :span="8">
<!-- 健康小贴士 -->
<el-card class="tips-card">
<template #header>
<div class="card-header">
<span>健康小贴士</span>
<el-button text>更多</el-button>
</div>
</template>
<div v-for="tip in healthTips" :key="tip.id" class="tip-item">
<el-icon><InfoFilled /></el-icon>
<span>{{ tip.content }}</span>
</div>
</el-card>
<!-- 热门文章 -->
<el-card class="hot-articles">
<template #header>
<div class="card-header">
<span>热门文章</span>
<el-button text>更多</el-button>
</div>
</template>
<el-timeline>
<el-timeline-item
v-for="article in hotArticles"
:key="article.id"
:timestamp="article.date"
placement="top"
:type="article.type"
>
<el-card class="hot-article-card">
<h4>{{ article.title }}</h4>
<p class="hot-article-meta">
<el-icon><View /></el-icon> {{ article.views }}
<el-icon><Star /></el-icon> {{ article.likes }}
</p>
</el-card>
</el-timeline-item>
</el-timeline>
</el-card>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</div>
<!-- 文章详情对话框 -->
<el-dialog
v-model="dialogVisible"
:title="currentArticle.title"
width="70%"
class="article-dialog"
>
<div class="article-detail">
<div class="article-header">
<el-image v-if="currentArticle.image" :src="currentArticle.image" fit="cover" />
<div class="article-info">
<p class="article-meta">
<span><el-icon><Calendar /></el-icon> {{ currentArticle.date }}</span>
<span><el-icon><View /></el-icon> {{ currentArticle.views }}</span>
<span><el-icon><Star /></el-icon> {{ currentArticle.likes }}</span>
</p>
</div>
</div>
<div class="article-content" v-html="currentArticle.content"></div>
<div class="article-actions">
<el-button type="primary" @click="likeArticle">
<el-icon><Star /></el-icon>
</el-button>
<el-button type="success" @click="shareArticle">
<el-icon><Share /></el-icon>
</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import {
Calendar,
View,
Star,
InfoFilled,
Share
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
//
const carouselData = ref([
{
id: 1,
title: '健康生活方式指南',
description: '科学饮食,规律运动,健康生活',
image: 'https://via.placeholder.com/800x400'
},
{
id: 2,
title: '春季养生专题',
description: '春季养生要点,助你轻松调养',
image: 'https://via.placeholder.com/800x400'
},
{
id: 3,
title: '居家健康指南',
description: '在家也能享受专业健康服务',
image: 'https://via.placeholder.com/800x400'
}
])
//
const categories = ref([
{ label: '全部', value: 'all' },
{ label: '养生保健', value: 'health' },
{ label: '疾病预防', value: 'prevention' },
{ label: '饮食营养', value: 'nutrition' },
{ label: '运动健身', value: 'fitness' }
])
const activeCategory = ref('all')
//
const articles = ref([
{
id: 1,
title: '每天一个苹果,医生远离我',
description: '关于苹果的营养价值和健康功效的深入解析...',
image: 'https://via.placeholder.com/300x200',
date: '2024-03-20',
views: 1234,
likes: 88,
category: '饮食营养',
type: 'success',
content: '详细的文章内容...'
},
// ...
])
//
const healthTips = ref([
{
id: 1,
content: '每天喝够8杯水保持身体水分充足'
},
{
id: 2,
content: '保持良好作息每天保证7-8小时睡眠'
},
{
id: 3,
content: '适量运动每周至少运动3次每次30分钟'
}
])
//
const hotArticles = ref([
{
id: 1,
title: '2024年最新健康饮食指南',
date: '2024-03-19',
views: 2345,
likes: 156,
type: 'primary'
},
// ...
])
//
const currentPage = ref(1)
const pageSize = ref(6)
const total = ref(100)
//
const dialogVisible = ref(false)
const currentArticle = ref({})
//
const filteredArticles = computed(() => {
if (activeCategory.value === 'all') {
return articles.value
}
return articles.value.filter(article => article.category === activeCategory.value)
})
//
const handleCategoryChange = (tab) => {
console.log('切换分类:', tab.props.name)
}
const handleSizeChange = (val) => {
pageSize.value = val
}
const handleCurrentChange = (val) => {
currentPage.value = val
}
const showArticleDetail = (article) => {
currentArticle.value = article
dialogVisible.value = true
}
const likeArticle = () => {
currentArticle.value.likes++
ElMessage.success('点赞成功')
}
const shareArticle = () => {
ElMessage.success('分享功能开发中...')
}
</script>
<style scoped>
.health-news {
padding: 20px;
}
.carousel-card {
margin-bottom: 20px;
}
.carousel-content {
height: 100%;
background-size: cover;
background-position: center;
border-radius: 6px;
display: flex;
align-items: flex-end;
}
.carousel-info {
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
color: white;
padding: 20px;
width: 100%;
}
.carousel-info h3 {
margin: 0;
font-size: 24px;
}
.category-container {
margin-top: 20px;
}
.article-card {
margin-bottom: 20px;
transition: all 0.3s;
}
.article-card:hover {
transform: translateY(-5px);
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
}
.article-content {
display: flex;
gap: 20px;
}
.article-image {
width: 200px;
height: 150px;
overflow: hidden;
}
.article-image .el-image {
width: 100%;
height: 100%;
}
.article-info {
flex: 1;
}
.article-title {
margin: 0 0 10px;
cursor: pointer;
color: var(--el-color-primary);
}
.article-desc {
color: #666;
margin-bottom: 10px;
}
.article-meta {
display: flex;
align-items: center;
gap: 15px;
color: #999;
}
.article-meta span {
display: flex;
align-items: center;
gap: 5px;
}
.tips-card,
.hot-articles {
margin-bottom: 20px;
}
.tip-item {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
color: #666;
}
.hot-article-card {
margin-bottom: 10px;
}
.hot-article-meta {
display: flex;
gap: 10px;
color: #999;
margin: 5px 0 0;
}
.article-dialog :deep(.el-dialog__body) {
padding: 0;
}
.article-detail {
padding: 20px;
}
.article-header {
margin-bottom: 20px;
}
.article-header .el-image {
width: 100%;
max-height: 400px;
border-radius: 6px;
}
.article-actions {
margin-top: 20px;
display: flex;
justify-content: center;
gap: 20px;
}
.pagination {
margin-top: 20px;
display: flex;
justify-content: center;
}
</style>

View File

@ -1,539 +0,0 @@
<template>
<div class="health-shop">
<!-- 顶部搜索和筛选 -->
<el-card class="filter-card">
<el-row :gutter="20">
<el-col :span="8">
<el-input
v-model="searchQuery"
placeholder="搜索商品..."
prefix-icon="Search"
clearable
/>
</el-col>
<el-col :span="12">
<el-radio-group v-model="category" size="large">
<el-radio-button v-for="cat in categories" :key="cat.value" :label="cat.value">
{{ cat.label }}
</el-radio-button>
</el-radio-group>
</el-col>
<el-col :span="4">
<el-select v-model="sortBy" placeholder="排序方式" style="width: 100%">
<el-option label="综合排序" value="default" />
<el-option label="销量优先" value="sales" />
<el-option label="价格从低到高" value="priceAsc" />
<el-option label="价格从高到低" value="priceDesc" />
</el-select>
</el-col>
</el-row>
</el-card>
<!-- 商品展示区 -->
<el-row :gutter="20" class="product-container">
<el-col :span="6" v-for="product in filteredProducts" :key="product.id">
<el-card class="product-card" :body-style="{ padding: '0px' }">
<div class="product-image">
<el-image :src="product.image" fit="cover">
<template #error>
<div class="image-slot">
<el-icon><Picture /></el-icon>
</div>
</template>
</el-image>
<div class="product-tags" v-if="product.tags && product.tags.length">
<el-tag v-for="tag in product.tags" :key="tag" size="small" :type="getTagType(tag)">
{{ tag }}
</el-tag>
</div>
</div>
<div class="product-info">
<h3 class="product-title" @click="showProductDetail(product)">{{ product.name }}</h3>
<div class="product-price">
<span class="current-price">¥{{ product.price }}</span>
<span class="original-price" v-if="product.originalPrice">¥{{ product.originalPrice }}</span>
</div>
<div class="product-meta">
<span class="sales">月销 {{ product.sales }}+</span>
<el-rate v-model="product.rating" disabled text-color="#ff9900" />
</div>
<div class="product-actions">
<el-button type="primary" @click="addToCart(product)">加入购物车</el-button>
<el-button type="danger" @click="buyNow(product)">立即购买</el-button>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 购物车抽屉 -->
<el-drawer
v-model="cartDrawer"
title="购物车"
direction="rtl"
size="30%"
>
<div class="cart-content">
<el-empty v-if="!cartItems.length" description="购物车是空的" />
<template v-else>
<div class="cart-items">
<el-card v-for="item in cartItems" :key="item.id" class="cart-item">
<div class="cart-item-content">
<el-image :src="item.image" class="cart-item-image" />
<div class="cart-item-info">
<h4>{{ item.name }}</h4>
<div class="cart-item-price">¥{{ item.price }}</div>
<el-input-number
v-model="item.quantity"
:min="1"
:max="99"
size="small"
@change="updateCart"
/>
</div>
<el-button
type="danger"
circle
class="remove-btn"
@click="removeFromCart(item)"
>
<el-icon><Delete /></el-icon>
</el-button>
</div>
</el-card>
</div>
<div class="cart-footer">
<div class="cart-total">
总计: <span class="total-price">¥{{ totalPrice }}</span>
</div>
<el-button type="primary" size="large" @click="checkout">
结算 ({{ totalItems }})
</el-button>
</div>
</template>
</div>
</el-drawer>
<!-- 商品详情对话框 -->
<el-dialog
v-model="dialogVisible"
:title="currentProduct.name"
width="70%"
class="product-dialog"
>
<div class="product-detail">
<el-row :gutter="20">
<el-col :span="12">
<el-carousel trigger="click" height="400px">
<el-carousel-item v-for="img in currentProduct.images" :key="img">
<el-image :src="img" fit="contain" />
</el-carousel-item>
</el-carousel>
</el-col>
<el-col :span="12">
<div class="detail-info">
<div class="detail-price">
<span class="price">¥{{ currentProduct.price }}</span>
<span class="original" v-if="currentProduct.originalPrice">
原价: ¥{{ currentProduct.originalPrice }}
</span>
</div>
<div class="detail-meta">
<div class="meta-item">
<span class="label">销量:</span>
<span class="value">{{ currentProduct.sales }}+</span>
</div>
<div class="meta-item">
<span class="label">评分:</span>
<el-rate v-model="currentProduct.rating" disabled show-score />
</div>
</div>
<el-divider />
<div class="detail-desc">{{ currentProduct.description }}</div>
<div class="detail-actions">
<el-input-number v-model="purchaseQuantity" :min="1" :max="99" />
<el-button type="primary" size="large" @click="addToCart(currentProduct, purchaseQuantity)">
加入购物车
</el-button>
<el-button type="danger" size="large" @click="buyNow(currentProduct, purchaseQuantity)">
立即购买
</el-button>
</div>
</div>
</el-col>
</el-row>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { Search, Picture, Delete } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
//
const categories = ref([
{ label: '全部', value: 'all' },
{ label: '营养保健', value: 'nutrition' },
{ label: '医疗器械', value: 'medical' },
{ label: '健康食品', value: 'food' },
{ label: '运动装备', value: 'sports' }
])
//
const searchQuery = ref('')
const category = ref('all')
const sortBy = ref('default')
//
const products = ref([
{
id: 1,
name: '复合维生素片',
price: 128,
originalPrice: 168,
description: '提供每日所需的基本维生素和矿物质...',
image: 'https://via.placeholder.com/300x300',
images: [
'https://via.placeholder.com/800x800',
'https://via.placeholder.com/800x800',
'https://via.placeholder.com/800x800'
],
sales: 1000,
rating: 4.5,
category: 'nutrition',
tags: ['热销', '限时特惠']
},
// ...
])
//
const cartDrawer = ref(false)
const cartItems = ref([])
//
const dialogVisible = ref(false)
const currentProduct = ref({})
const purchaseQuantity = ref(1)
//
const filteredProducts = computed(() => {
let result = products.value
//
if (category.value !== 'all') {
result = result.filter(p => p.category === category.value)
}
//
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase()
result = result.filter(p =>
p.name.toLowerCase().includes(query) ||
p.description.toLowerCase().includes(query)
)
}
//
switch (sortBy.value) {
case 'sales':
result = [...result].sort((a, b) => b.sales - a.sales)
break
case 'priceAsc':
result = [...result].sort((a, b) => a.price - b.price)
break
case 'priceDesc':
result = [...result].sort((a, b) => b.price - a.price)
break
}
return result
})
const totalPrice = computed(() => {
return cartItems.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
})
const totalItems = computed(() => {
return cartItems.value.reduce((sum, item) => sum + item.quantity, 0)
})
//
const getTagType = (tag) => {
const types = {
'热销': 'danger',
'限时特惠': 'warning',
'新品': 'success'
}
return types[tag] || 'info'
}
const showProductDetail = (product) => {
currentProduct.value = product
purchaseQuantity.value = 1
dialogVisible.value = true
}
const addToCart = (product, quantity = 1) => {
const existingItem = cartItems.value.find(item => item.id === product.id)
if (existingItem) {
existingItem.quantity += quantity
} else {
cartItems.value.push({
...product,
quantity
})
}
ElMessage.success('已添加到购物车')
cartDrawer.value = true
}
const removeFromCart = (item) => {
const index = cartItems.value.indexOf(item)
if (index > -1) {
cartItems.value.splice(index, 1)
}
}
const updateCart = () => {
//
}
const buyNow = (product, quantity = 1) => {
ElMessageBox.confirm(
`确认购买 ${product.name} ${quantity}件?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}
).then(() => {
ElMessage.success('购买成功!')
})
}
const checkout = () => {
if (cartItems.value.length === 0) {
ElMessage.warning('购物车是空的')
return
}
ElMessageBox.confirm(
`确认结算 ${totalItems.value} 件商品,总计 ¥${totalPrice.value}`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}
).then(() => {
cartItems.value = []
cartDrawer.value = false
ElMessage.success('购买成功!')
})
}
</script>
<style scoped>
.health-shop {
padding: 20px;
}
.filter-card {
margin-bottom: 20px;
}
.product-container {
margin-top: 20px;
}
.product-card {
margin-bottom: 20px;
transition: all 0.3s;
}
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
}
.product-image {
position: relative;
height: 200px;
}
.product-image .el-image {
width: 100%;
height: 100%;
}
.product-tags {
position: absolute;
top: 10px;
left: 10px;
display: flex;
gap: 5px;
}
.product-info {
padding: 14px;
}
.product-title {
margin: 0;
font-size: 16px;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.product-price {
margin: 10px 0;
}
.current-price {
font-size: 20px;
color: #f56c6c;
font-weight: bold;
margin-right: 10px;
}
.original-price {
color: #999;
text-decoration: line-through;
}
.product-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.sales {
color: #999;
font-size: 12px;
}
.product-actions {
display: flex;
gap: 10px;
}
.cart-content {
height: 100%;
display: flex;
flex-direction: column;
}
.cart-items {
flex: 1;
overflow-y: auto;
padding: 10px;
}
.cart-item {
margin-bottom: 10px;
}
.cart-item-content {
display: flex;
gap: 10px;
align-items: center;
}
.cart-item-image {
width: 80px;
height: 80px;
}
.cart-item-info {
flex: 1;
}
.cart-item-info h4 {
margin: 0 0 5px;
}
.cart-item-price {
color: #f56c6c;
margin-bottom: 5px;
}
.remove-btn {
align-self: flex-start;
}
.cart-footer {
padding: 20px;
border-top: 1px solid #eee;
}
.cart-total {
margin-bottom: 10px;
font-size: 16px;
}
.total-price {
color: #f56c6c;
font-size: 20px;
font-weight: bold;
}
.detail-info {
padding: 20px;
}
.detail-price {
margin-bottom: 20px;
}
.detail-price .price {
font-size: 24px;
color: #f56c6c;
font-weight: bold;
margin-right: 10px;
}
.detail-price .original {
color: #999;
text-decoration: line-through;
}
.detail-meta {
margin-bottom: 20px;
}
.meta-item {
margin-bottom: 10px;
}
.meta-item .label {
color: #666;
margin-right: 10px;
}
.detail-desc {
margin: 20px 0;
color: #666;
line-height: 1.6;
}
.detail-actions {
display: flex;
gap: 20px;
margin-top: 20px;
}
.image-slot {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background: #f5f7fa;
}
</style>

View File

@ -1,388 +0,0 @@
<template>
<div class="health-warning">
<!-- 预警概览 -->
<el-row :gutter="20">
<el-col :span="6" v-for="(item, index) in warningStats" :key="index">
<el-card class="warning-card" :class="item.level">
<div class="warning-content">
<el-badge :value="item.count" :type="item.type">
<el-icon class="warning-icon"><component :is="item.icon" /></el-icon>
</el-badge>
<div class="warning-info">
<div class="warning-title">{{ item.title }}</div>
<div class="warning-desc">{{ item.description }}</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 预警规则设置 -->
<el-card class="rule-card">
<template #header>
<div class="card-header">
<span>预警规则设置</span>
<el-button type="primary" @click="addRule">
<el-icon><Plus /></el-icon>
</el-button>
</div>
</template>
<el-table :data="rules" style="width: 100%">
<el-table-column prop="name" label="规则名称" />
<el-table-column prop="type" label="监测指标">
<template #default="scope">
<el-tag>{{ scope.row.type }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="condition" label="触发条件" />
<el-table-column prop="level" label="预警等级">
<template #default="scope">
<el-tag :type="scope.row.level">{{ getLevelText(scope.row.level) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态">
<template #default="scope">
<el-switch
v-model="scope.row.status"
:active-value="1"
:inactive-value="0"
@change="handleStatusChange(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button-group>
<el-button type="primary" link @click="editRule(scope.row)">
编辑
</el-button>
<el-button type="danger" link @click="deleteRule(scope.row)">
删除
</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 预警历史 -->
<el-card class="history-card">
<template #header>
<div class="card-header">
<span>预警历史</span>
<el-radio-group v-model="timeFilter" size="small">
<el-radio-button label="today">今天</el-radio-button>
<el-radio-button label="week">本周</el-radio-button>
<el-radio-button label="month">本月</el-radio-button>
</el-radio-group>
</div>
</template>
<el-timeline>
<el-timeline-item
v-for="(activity, index) in warningHistory"
:key="index"
:type="activity.type"
:color="getWarningColor(activity.level)"
:timestamp="activity.timestamp"
:hollow="activity.hollow"
>
<el-card class="timeline-card">
<h4>{{ activity.title }}</h4>
<p>{{ activity.content }}</p>
<div class="timeline-footer">
<el-tag size="small" :type="activity.level">
{{ getLevelText(activity.level) }}
</el-tag>
<el-button type="primary" link size="small" @click="handleWarning(activity)">
处理
</el-button>
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</el-card>
<!-- 规则编辑对话框 -->
<el-dialog
v-model="dialogVisible"
:title="isEdit ? '编辑规则' : '新增规则'"
width="50%"
>
<el-form :model="ruleForm" label-width="100px">
<el-form-item label="规则名称">
<el-input v-model="ruleForm.name" placeholder="请输入规则名称" />
</el-form-item>
<el-form-item label="监测指标">
<el-select v-model="ruleForm.type" placeholder="请选择监测指标">
<el-option label="血压" value="bloodPressure" />
<el-option label="心率" value="heartRate" />
<el-option label="体温" value="temperature" />
</el-select>
</el-form-item>
<el-form-item label="触发条件">
<el-input v-model="ruleForm.condition" placeholder="请输入触发条件" />
</el-form-item>
<el-form-item label="预警等级">
<el-select v-model="ruleForm.level" placeholder="请选择预警等级">
<el-option label="一般" value="info" />
<el-option label="警告" value="warning" />
<el-option label="严重" value="danger" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="saveRule">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Warning, Bell, Plus, Notification, CircleCheck } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
//
const warningStats = ref([
{
title: '严重预警',
count: 3,
type: 'danger',
level: 'danger',
icon: 'Warning',
description: '需要立即处理'
},
{
title: '一般预警',
count: 8,
type: 'warning',
level: 'warning',
icon: 'Bell',
description: '需要关注'
},
{
title: '已处理',
count: 25,
type: 'info',
level: 'info',
icon: 'CircleCheck',
description: '本周已处理'
},
{
title: '预警规则',
count: 12,
type: 'primary',
level: 'primary',
icon: 'Notification',
description: '当前生效规则'
}
])
//
const rules = ref([
{
name: '高血压预警',
type: '血压',
condition: '收缩压 > 140 或 舒张压 > 90',
level: 'danger',
status: 1
},
{
name: '心率异常预警',
type: '心率',
condition: '心率 < 60 或 心率 > 100',
level: 'warning',
status: 1
}
])
//
const timeFilter = ref('today')
const warningHistory = ref([
{
timestamp: '2024-03-20 14:30',
title: '血压异常预警',
content: '检测到血压值 150/95超出正常范围',
level: 'danger',
type: 'danger',
hollow: false
},
{
timestamp: '2024-03-20 10:20',
title: '心率异常预警',
content: '检测到心率值 102超出正常范围',
level: 'warning',
type: 'warning',
hollow: false
}
])
//
const dialogVisible = ref(false)
const isEdit = ref(false)
const ruleForm = ref({
name: '',
type: '',
condition: '',
level: ''
})
//
const getLevelText = (level) => {
const texts = {
danger: '严重',
warning: '警告',
info: '一般'
}
return texts[level] || level
}
const getWarningColor = (level) => {
const colors = {
danger: '#F56C6C',
warning: '#E6A23C',
info: '#909399'
}
return colors[level] || '#409EFF'
}
const addRule = () => {
isEdit.value = false
ruleForm.value = {
name: '',
type: '',
condition: '',
level: ''
}
dialogVisible.value = true
}
const editRule = (row) => {
isEdit.value = true
ruleForm.value = { ...row }
dialogVisible.value = true
}
const deleteRule = (row) => {
ElMessageBox.confirm(
'确定要删除该预警规则吗?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
const index = rules.value.indexOf(row)
rules.value.splice(index, 1)
ElMessage.success('删除成功')
})
}
const saveRule = () => {
if (isEdit.value) {
const index = rules.value.findIndex(r => r.name === ruleForm.value.name)
if (index !== -1) {
rules.value[index] = { ...ruleForm.value }
}
} else {
rules.value.push({ ...ruleForm.value, status: 1 })
}
dialogVisible.value = false
ElMessage.success(isEdit.value ? '修改成功' : '添加成功')
}
const handleStatusChange = (row) => {
ElMessage.success(`${row.name}${row.status ? '启用' : '停用'}`)
}
const handleWarning = (activity) => {
ElMessage.success(`正在处理: ${activity.title}`)
}
</script>
<style scoped>
.health-warning {
padding: 20px;
}
.warning-card {
margin-bottom: 20px;
border-radius: 8px;
transition: all 0.3s;
}
.warning-card:hover {
transform: translateY(-5px);
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
}
.warning-content {
display: flex;
align-items: center;
gap: 15px;
}
.warning-icon {
font-size: 2.5em;
color: var(--el-color-primary);
}
.warning-info {
flex: 1;
}
.warning-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 5px;
}
.warning-desc {
font-size: 12px;
color: #909399;
}
.rule-card,
.history-card {
margin-top: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.timeline-card {
margin-bottom: 10px;
}
.timeline-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
.danger {
border-left: 4px solid var(--el-color-danger);
}
.warning {
border-left: 4px solid var(--el-color-warning);
}
.info {
border-left: 4px solid var(--el-color-info);
}
.primary {
border-left: 4px solid var(--el-color-primary);
}
</style>

View File

@ -106,9 +106,9 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import {
QuestionFilled, School, DocumentChecked, DataAnalysis,
Reading, Edit, User, Star
import {
QuestionFilled, School, DocumentChecked, DataAnalysis,
Reading, Edit, User, Star
} from '@element-plus/icons-vue'
const router = useRouter()
@ -139,7 +139,7 @@ const popularCourses = ref([
title: 'C++面向对象编程精讲',
category: 'cpp',
categoryName: 'C++编程',
coverImg: '/src/assets/images/course-covers/cpp.jpg',
coverImg: 'https://p5.img.cctvpic.com/photoworkspace/contentimg/2023/03/30/2023033011303020756.jpg',
studentCount: 1234,
rating: 4.8,
price: 0
@ -149,28 +149,21 @@ const popularCourses = ref([
title: '保密法律法规学习',
category: 'law',
categoryName: '法律法规',
coverImg: '/src/assets/images/course-covers/law.jpg',
coverImg: 'https://p5.img.cctvpic.com/photoworkspace/contentimg/2023/03/30/2023033011303020756.jpg',
},
{
id: 3,
title: '深度学习在气象云图识别中的应用',
category: 'test',
categoryName: '测试',
coverImg: '/src/assets/images/course-covers/weather.jpg',
coverImg: 'https://p5.img.cctvpic.com/photoworkspace/contentimg/2023/03/30/2023033011303020756.jpg',
},
{
id: 4,
title: '天气雷达与云图识别基础',
category: 'test',
categoryName: '测试',
coverImg: '/src/assets/images/course-covers/radar.jpg',
},
{
id: 5,
title: '气象卫星云图分析与天气预测',
category: 'test',
categoryName: '测试',
coverImg: '/src/assets/images/course-covers/satellite.jpg',
coverImg: 'https://p5.img.cctvpic.com/photoworkspace/contentimg/2023/03/30/2023033011303020756.jpg',
}
])
@ -266,20 +259,20 @@ onMounted(() => {
font-size: 48px;
font-weight: bold;
margin-bottom: 20px;
.line {
opacity: 0;
transform: translateY(20px);
animation: fadeInUp 0.8s forwards;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
&:first-child {
animation-delay: 0.2s;
background: linear-gradient(to right, #60a5fa, #34d399);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
&:last-child {
animation-delay: 0.4s;
}
@ -291,13 +284,13 @@ onMounted(() => {
display: inline-block;
font-size: 20px;
opacity: 0.9;
.typing-text {
display: inline-block;
opacity: 0;
animation: fadeIn 0.8s 1s forwards;
}
.cursor {
display: inline-block;
width: 2px;
@ -324,12 +317,12 @@ onMounted(() => {
font-size: 16px;
border-radius: 8px;
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
.el-icon {
font-size: 20px;
}
@ -343,7 +336,7 @@ onMounted(() => {
background-color: #f8fafc;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
@ -353,11 +346,11 @@ onMounted(() => {
height: 1px;
background: linear-gradient(to right, transparent, rgba(37, 99, 235, 0.1), transparent);
}
.section-header {
text-align: center;
margin-bottom: 60px;
.section-title {
font-size: 36px;
font-weight: bold;
@ -368,7 +361,7 @@ onMounted(() => {
opacity: 0;
animation: fadeInUp 0.8s forwards;
}
.section-subtitle {
font-size: 18px;
color: #666;
@ -386,20 +379,20 @@ onMounted(() => {
overflow: hidden;
transition: all 0.3s ease;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
&:hover {
transform: translateY(-10px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
.feature-icon {
transform: scale(1.1);
}
.feature-bg {
opacity: 1;
}
}
.feature-icon {
width: 80px;
height: 80px;
@ -410,27 +403,27 @@ onMounted(() => {
border-radius: 50%;
background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%);
transition: transform 0.3s ease;
.el-icon {
font-size: 36px;
color: white;
}
}
h3 {
font-size: 20px;
margin-bottom: 16px;
position: relative;
z-index: 1;
}
p {
color: #666;
line-height: 1.6;
position: relative;
z-index: 1;
}
.feature-bg {
position: absolute;
top: 0;
@ -447,11 +440,11 @@ onMounted(() => {
.popular-courses {
padding: 100px 0;
background-color: white;
.section-header {
text-align: center;
margin-bottom: 60px;
.section-title {
font-size: 36px;
font-weight: bold;
@ -462,7 +455,7 @@ onMounted(() => {
opacity: 0;
animation: fadeInUp 0.8s forwards;
}
.section-subtitle {
font-size: 18px;
color: #666;
@ -479,28 +472,28 @@ onMounted(() => {
transition: all 0.3s ease;
cursor: pointer;
margin-bottom: 30px;
&:hover {
transform: translateY(-10px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
.course-overlay {
opacity: 1;
}
}
.course-image {
position: relative;
height: 200px;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.course-overlay {
position: absolute;
top: 0;
@ -514,7 +507,7 @@ onMounted(() => {
opacity: 0;
transition: opacity 0.3s ease;
}
.course-badge {
position: absolute;
top: 16px;
@ -524,16 +517,16 @@ onMounted(() => {
font-size: 12px;
color: white;
background: rgba(0, 0, 0, 0.6);
&.cpp {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
}
}
}
.course-content {
padding: 20px;
.course-title {
font-size: 18px;
margin-bottom: 16px;
@ -544,34 +537,34 @@ onMounted(() => {
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.course-info {
display: flex;
justify-content: space-between;
align-items: center;
.course-stats {
display: flex;
gap: 16px;
.stat-item {
display: flex;
align-items: center;
gap: 4px;
color: #666;
font-size: 14px;
.el-icon {
font-size: 16px;
}
}
}
.course-price {
font-size: 18px;
font-weight: bold;
color: #f43f5e;
&.free {
color: #10b981;
}
@ -594,18 +587,18 @@ onMounted(() => {
:global(.introjs-tooltip) {
background-color: #4080ff;
color: white;
.introjs-tooltip-title {
color: white;
font-weight: bold;
}
.introjs-button {
background-color: white;
color: #4080ff;
border: none;
text-shadow: none;
&:hover {
background-color: #f5f7fa;
}
@ -654,22 +647,22 @@ onMounted(() => {
@media (max-width: 768px) {
.home .banner {
padding: 60px 0;
.banner-content {
.title-wrapper {
.animated-title {
font-size: 36px;
}
.subtitle {
font-size: 18px;
}
}
.banner-actions {
flex-direction: column;
padding: 0 20px;
.action-btn {
width: 100%;
}

View File

@ -1,374 +0,0 @@
<template>
<div class="statistics">
<!-- 数据概览卡片 -->
<el-row :gutter="20">
<el-col :span="6" v-for="(item, index) in overviewData" :key="index">
<el-card class="overview-card" :class="item.trend">
<div class="overview-content">
<div class="overview-icon">
<el-icon><component :is="item.icon" /></el-icon>
</div>
<div class="overview-info">
<div class="overview-title">{{ item.title }}</div>
<div class="overview-value">{{ item.value }}</div>
<div class="overview-trend">
较上周
<span :class="item.trend">{{ item.percentage }}</span>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 趋势图表 -->
<el-row :gutter="20" class="chart-row">
<el-col :span="16">
<el-card>
<template #header>
<div class="card-header">
<span>健康指标趋势分析</span>
<el-radio-group v-model="timeRange" size="small">
<el-radio-button label="week"></el-radio-button>
<el-radio-button label="month"></el-radio-button>
<el-radio-button label="year"></el-radio-button>
</el-radio-group>
</div>
</template>
<v-chart class="trend-chart" :option="trendOption" autoresize />
</el-card>
</el-col>
<el-col :span="8">
<el-card>
<template #header>
<div class="card-header">
<span>健康状态分布</span>
</div>
</template>
<v-chart class="pie-chart" :option="pieOption" autoresize />
</el-card>
</el-col>
</el-row>
<!-- 详细数据表格 -->
<el-card class="table-card">
<template #header>
<div class="card-header">
<span>历史记录</span>
<div class="header-actions">
<el-input
v-model="searchQuery"
placeholder="搜索..."
prefix-icon="Search"
style="width: 200px"
/>
<el-button type="primary" @click="exportData">
<el-icon><Download /></el-icon>
</el-button>
</div>
</div>
</template>
<el-table :data="filteredTableData" style="width: 100%" height="400">
<el-table-column prop="date" label="日期" sortable />
<el-table-column prop="bloodPressure" label="血压" sortable />
<el-table-column prop="heartRate" label="心率" sortable />
<el-table-column prop="temperature" label="体温" sortable />
<el-table-column prop="status" label="状态">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
:total="totalItems"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { LineChart, PieChart } from 'echarts/charts'
import {
GridComponent,
TooltipComponent,
LegendComponent,
TitleComponent
} from 'echarts/components'
import VChart from 'vue-echarts'
import {
TrendCharts,
Histogram,
DataLine,
Timer,
Search,
Download
} from '@element-plus/icons-vue'
use([
CanvasRenderer,
LineChart,
PieChart,
GridComponent,
TooltipComponent,
LegendComponent,
TitleComponent
])
//
const overviewData = ref([
{
title: '平均血压',
value: '120/80',
percentage: '+2.5%',
trend: 'up',
icon: 'TrendCharts'
},
{
title: '平均心率',
value: '75',
percentage: '-1.2%',
trend: 'down',
icon: 'Histogram'
},
{
title: '平均体温',
value: '36.5',
percentage: '0%',
trend: 'stable',
icon: 'DataLine'
},
{
title: '记录次数',
value: '28',
percentage: '+15%',
trend: 'up',
icon: 'Timer'
}
])
//
const timeRange = ref('week')
//
const trendOption = computed(() => ({
title: {
text: '健康指标变化趋势'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['血压', '心率', '体温']
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: [
{
type: 'value',
name: '血压/心率',
min: 0,
max: 200
},
{
type: 'value',
name: '体温',
min: 35,
max: 42
}
],
series: [
{
name: '血压',
type: 'line',
data: [120, 122, 118, 121, 119, 120, 118]
},
{
name: '心率',
type: 'line',
data: [75, 73, 77, 76, 74, 75, 72]
},
{
name: '体温',
type: 'line',
yAxisIndex: 1,
data: [36.5, 36.6, 36.4, 36.5, 36.7, 36.5, 36.4]
}
]
}))
//
const pieOption = ref({
title: {
text: '健康状态分布'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
type: 'pie',
radius: '50%',
data: [
{ value: 70, name: '正常' },
{ value: 20, name: '轻微异常' },
{ value: 10, name: '需要关注' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
})
//
const tableData = ref([
{
date: '2024-03-20',
bloodPressure: '120/80',
heartRate: 75,
temperature: 36.5,
status: '正常'
},
// ...
])
//
const currentPage = ref(1)
const pageSize = ref(10)
const totalItems = ref(100)
const searchQuery = ref('')
const filteredTableData = computed(() => {
return tableData.value.filter(data => {
return Object.values(data).some(value =>
value.toString().toLowerCase().includes(searchQuery.value.toLowerCase())
)
})
})
const handleSizeChange = (val) => {
pageSize.value = val
}
const handleCurrentChange = (val) => {
currentPage.value = val
}
const getStatusType = (status) => {
const types = {
'正常': 'success',
'轻微异常': 'warning',
'需要关注': 'danger'
}
return types[status] || 'info'
}
const exportData = () => {
//
console.log('导出数据')
}
</script>
<style scoped>
.statistics {
padding: 20px;
}
.overview-card {
margin-bottom: 20px;
}
.overview-content {
display: flex;
align-items: center;
}
.overview-icon {
font-size: 2.5em;
margin-right: 15px;
color: var(--el-color-primary);
}
.overview-info {
flex: 1;
}
.overview-title {
font-size: 14px;
color: #909399;
}
.overview-value {
font-size: 24px;
font-weight: bold;
margin: 5px 0;
}
.overview-trend {
font-size: 12px;
}
.up {
color: #67C23A;
}
.down {
color: #F56C6C;
}
.stable {
color: #909399;
}
.chart-row {
margin-bottom: 20px;
}
.trend-chart {
height: 400px;
}
.pie-chart {
height: 300px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.header-actions {
display: flex;
gap: 10px;
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@ -78,12 +78,12 @@
<div class="course-list">
<div class="container">
<el-row :gutter="24">
<el-col
v-for="course in filteredCourses"
:key="course.id"
:xs="24"
:sm="12"
:md="8"
<el-col
v-for="course in filteredCourses"
:key="course.id"
:xs="24"
:sm="12"
:md="8"
:lg="6"
>
<div class="course-card" @click="viewCourse(course.id)">
@ -233,7 +233,7 @@ const filteredCourses = computed(() => {
}
if (searchQuery.value) {
const query = searchQuery.value.toLowerCase()
result = result.filter(course =>
result = result.filter(course =>
course.title.toLowerCase().includes(query) ||
course.description.toLowerCase().includes(query)
)
@ -315,7 +315,7 @@ const handleCurrentChange = (val) => {
background: rgba(255, 255, 255, 0.1);
border: none;
box-shadow: none;
&:hover, &:focus {
background: rgba(255, 255, 255, 0.2);
}
@ -381,7 +381,7 @@ const handleCurrentChange = (val) => {
.el-tag {
cursor: pointer;
transition: all 0.3s;
&:hover {
transform: translateY(-1px);
}
@ -419,7 +419,7 @@ const handleCurrentChange = (val) => {
transition: all 0.3s;
margin-bottom: 24px;
cursor: pointer;
&:hover {
transform: translateY(-5px);
box-shadow: 0 12px 20px rgba(0, 0, 0, 0.1);
@ -654,4 +654,4 @@ const handleCurrentChange = (val) => {
}
}
}
</style>
</style>

View File

@ -17,7 +17,7 @@
>
<template #filter-content>
<el-select v-model="listQuery.params.openType" class="filter-item" placeholder="开放类型" clearable>
<el-select v-model="listQuery.params.openType" class="filter-item" placeholder="开放类型" style="width: 207px;" clearable>
<el-option
v-for="item in openTypes"
:key="item.value"
@ -171,3 +171,12 @@ export default {
}
}
</script>
<style scoped>
.filter-item {
display: inline-block;
vertical-align: middle;
margin-bottom: 10px;
}
</style>