feat(health): H5端新增用药统计页面
- 新增 medicationAdherence.js:统计API接口 - 新增 statistic/medication/index.vue:用药统计页面 - 概览卡片:总任务、已服药、漏服、服药率、准时率 - 趋势图:服药率和准时率折线图 - 时段分布:四时段统计卡片 - 日历视图:月度服药日历 - 修改 pages.json:添加页面路由 - 修改 statistic/index.vue:添加健康统计分析入口
This commit is contained in:
46
src/api/health/medicationAdherence.js
Normal file
46
src/api/health/medicationAdherence.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取总体依从性统计
|
||||
export function getOverallAdherence(query) {
|
||||
return request({
|
||||
url: '/health/adherence/overall',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取每日依从性统计列表
|
||||
export function getDailyAdherence(query) {
|
||||
return request({
|
||||
url: '/health/adherence/daily',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取日历视图数据
|
||||
export function getCalendarData(personId, yearMonth) {
|
||||
return request({
|
||||
url: '/health/adherence/calendar',
|
||||
method: 'get',
|
||||
params: { personId, yearMonth }
|
||||
})
|
||||
}
|
||||
|
||||
// 获取各时段服药统计
|
||||
export function getTimeSlotAdherence(query) {
|
||||
return request({
|
||||
url: '/health/adherence/timeSlot',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取仪表盘概览数据
|
||||
export function getDashboard(personId) {
|
||||
return request({
|
||||
url: '/health/adherence/dashboard',
|
||||
method: 'get',
|
||||
params: { personId }
|
||||
})
|
||||
}
|
||||
@@ -238,6 +238,14 @@
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/statistic/medication/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用药统计",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/work/accounts/accountDealRecord/list",
|
||||
"style": {
|
||||
|
||||
@@ -74,6 +74,26 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 健康统计分析 -->
|
||||
<view class="section-header" v-show="auth.hasPermi('health:medicationStatistic:query')">
|
||||
<text class="section-title">健康统计分析</text>
|
||||
</view>
|
||||
<view class="grid-body" v-show="auth.hasPermi('health:medicationStatistic:query')">
|
||||
<view class="grid-wrapper">
|
||||
<view
|
||||
v-for="(item, index) in healthGridList"
|
||||
:key="index"
|
||||
v-show="auth.hasPermi(item.permission)"
|
||||
@click="navigateTo(item.path)"
|
||||
class="grid-item">
|
||||
<view class="item-icon" :style="{ background: item.color }">
|
||||
<uni-icons :type="item.icon" size="22" color="#ffffff"></uni-icons>
|
||||
</view>
|
||||
<text class="item-text">{{ item.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <refresh></refresh> -->
|
||||
</template>
|
||||
@@ -109,6 +129,9 @@
|
||||
{ path: '/pages/statistic/bill/investAnalysis/index', text: '收益统计分析', icon: 'settings', color: 'linear-gradient(135deg, #a29bfe 0%, #6c5ce7 100%)', permission: 'invest:investAnalysis:list'},
|
||||
{ path: '/pages/statistic/bill/futuresAnalysis/index', text: '期货统计分析', icon: 'fire', color: 'linear-gradient(135deg, #fc5c65 0%, #fd79a8 100%)', permission: 'invest:futuresAnalysis:list'},
|
||||
{ path: '/pages/statistic/bill/stocksAnalysis/index', text: '股票统计分析', icon: 'flag-filled', color: 'linear-gradient(135deg, #5f72bd 0%, #9b23ea 100%)', permission: 'invest:stocksAnalysis:list' }
|
||||
])
|
||||
const healthGridList=ref([
|
||||
{ path: '/pages/statistic/medication/index', text: '用药统计', icon: 'heart-filled', color: 'linear-gradient(135deg, #409EFF 0%, #67C23A 100%)', permission: 'health:medicationStatistic:query' }
|
||||
])
|
||||
function navigateTo(path) {
|
||||
uni.navigateTo({
|
||||
|
||||
591
src/pages/statistic/medication/index.vue
Normal file
591
src/pages/statistic/medication/index.vue
Normal file
@@ -0,0 +1,591 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="custom-navbar">
|
||||
<view class="navbar-content">
|
||||
<view class="navbar-left" @click="goBack">
|
||||
<uni-icons type="back" size="20" color="#ffffff"></uni-icons>
|
||||
</view>
|
||||
<view class="navbar-title">用药统计</view>
|
||||
<view class="navbar-right"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 日期选择 -->
|
||||
<view class="date-selector">
|
||||
<view class="date-item" :class="{ active: dateType === 'week' }" @click="changeDateType('week')">近7天</view>
|
||||
<view class="date-item" :class="{ active: dateType === 'month' }" @click="changeDateType('month')">近30天</view>
|
||||
<view class="date-item" :class="{ active: dateType === 'quarter' }" @click="changeDateType('quarter')">近90天</view>
|
||||
</view>
|
||||
|
||||
<!-- 概览卡片 -->
|
||||
<view class="overview-section" v-if="overview">
|
||||
<view class="stat-row">
|
||||
<view class="stat-item">
|
||||
<view class="stat-value">{{ overview.totalTasks || 0 }}</view>
|
||||
<view class="stat-label">总任务</view>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-value success">{{ overview.completedTasks || 0 }}</view>
|
||||
<view class="stat-label">已服药</view>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-value danger">{{ overview.missedTasks || 0 }}</view>
|
||||
<view class="stat-label">漏服</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="stat-row">
|
||||
<view class="stat-item large">
|
||||
<view class="progress-ring">
|
||||
<view class="ring-value">{{ overview.adherenceRate || 0 }}%</view>
|
||||
<view class="ring-label">服药率</view>
|
||||
</view>
|
||||
<u-line-progress :percentage="overview.adherenceRate || 0" activeColor="#67C23A" height="8"></u-line-progress>
|
||||
</view>
|
||||
<view class="stat-item large">
|
||||
<view class="progress-ring">
|
||||
<view class="ring-value">{{ overview.ontimeRate || 0 }}%</view>
|
||||
<view class="ring-label">准时率</view>
|
||||
</view>
|
||||
<u-line-progress :percentage="overview.ontimeRate || 0" activeColor="#409EFF" height="8"></u-line-progress>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 趋势图 -->
|
||||
<view class="chart-section">
|
||||
<view class="section-title">服药趋势</view>
|
||||
<view class="chart-container" v-if="dailyList.length > 0">
|
||||
<qiun-data-charts type="line" :chartData="trendChartData" :opts="trendOpts" />
|
||||
</view>
|
||||
<u-empty v-else text="暂无数据" mode="data"></u-empty>
|
||||
</view>
|
||||
|
||||
<!-- 时段分布 -->
|
||||
<view class="chart-section">
|
||||
<view class="section-title">时段分布</view>
|
||||
<view class="time-slot-grid" v-if="timeSlotData">
|
||||
<view class="time-slot-item" v-for="(item, key) in timeSlotData" :key="key">
|
||||
<view class="slot-name">{{ timeSlotNames[key] }}</view>
|
||||
<view class="slot-rate">{{ item.adherenceRate || 0 }}%</view>
|
||||
<view class="slot-detail">
|
||||
<text>已服 {{ item.completedTasks || 0 }}</text>
|
||||
<text>/ {{ item.totalTasks || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 日历视图 -->
|
||||
<view class="calendar-section">
|
||||
<view class="section-header">
|
||||
<view class="section-title">日历视图</view>
|
||||
<view class="month-nav">
|
||||
<uni-icons type="left" size="18" @click="changeMonth(-1)"></uni-icons>
|
||||
<text class="current-month">{{ currentMonthText }}</text>
|
||||
<uni-icons type="right" size="18" @click="changeMonth(1)"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<view class="calendar-grid">
|
||||
<view class="calendar-header">
|
||||
<text v-for="day in ['一', '二', '三', '四', '五', '六', '日']" :key="day" class="header-cell">{{ day }}</text>
|
||||
</view>
|
||||
<view class="calendar-body">
|
||||
<view
|
||||
v-for="(day, index) in calendarDays"
|
||||
:key="index"
|
||||
class="calendar-cell"
|
||||
:class="{
|
||||
'other-month': day.otherMonth,
|
||||
'today': day.isToday,
|
||||
'has-data': day.data && day.data.totalTasks > 0
|
||||
}"
|
||||
>
|
||||
<text class="day-number">{{ day.day }}</text>
|
||||
<view class="day-indicator" v-if="day.data && day.data.totalTasks > 0">
|
||||
<view class="indicator-dot" :class="getIndicatorClass(day.data)"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="calendar-legend">
|
||||
<view class="legend-item">
|
||||
<view class="legend-dot good"></view>
|
||||
<text>服药率 ≥ 80%</text>
|
||||
</view>
|
||||
<view class="legend-item">
|
||||
<view class="legend-dot normal"></view>
|
||||
<text>服药率 50-80%</text>
|
||||
</view>
|
||||
<view class="legend-item">
|
||||
<view class="legend-dot bad"></view>
|
||||
<text>服药率 < 50%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { getOverallAdherence, getDailyAdherence, getCalendarData, getTimeSlotAdherence } from '@/api/health/medicationAdherence'
|
||||
|
||||
const dateType = ref('week')
|
||||
const overview = ref(null)
|
||||
const dailyList = ref([])
|
||||
const timeSlotData = ref(null)
|
||||
const calendarData = ref([])
|
||||
|
||||
// 当前月份
|
||||
const currentYearMonth = ref('')
|
||||
const currentMonthText = ref('')
|
||||
|
||||
// 时段名称映射
|
||||
const timeSlotNames = {
|
||||
morning: '上午(6-12)',
|
||||
afternoon: '下午(12-18)',
|
||||
evening: '晚间(18-24)',
|
||||
night: '凌晨(0-6)'
|
||||
}
|
||||
|
||||
// 趋势图配置
|
||||
const trendOpts = ref({
|
||||
color: ['#409EFF', '#67C23A'],
|
||||
padding: [15, 10, 0, 15],
|
||||
legend: {},
|
||||
xAxis: {
|
||||
disableGrid: true
|
||||
},
|
||||
yAxis: {
|
||||
data: [{ min: 0, max: 100 }]
|
||||
},
|
||||
extra: {
|
||||
line: {
|
||||
type: 'curve',
|
||||
width: 2,
|
||||
activeType: 'hollow'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 趋势图数据
|
||||
const trendChartData = computed(() => {
|
||||
const categories = dailyList.value.map(d => d.date?.substring(5) || '')
|
||||
const series = [
|
||||
{
|
||||
name: '服药率',
|
||||
data: dailyList.value.map(d => d.adherenceRate || 0)
|
||||
},
|
||||
{
|
||||
name: '准时率',
|
||||
data: dailyList.value.map(d => d.ontimeRate || 0)
|
||||
}
|
||||
]
|
||||
return { categories, series }
|
||||
})
|
||||
|
||||
// 日历天数计算
|
||||
const calendarDays = computed(() => {
|
||||
const days = []
|
||||
if (!currentYearMonth.value) return days
|
||||
|
||||
const [year, month] = currentYearMonth.value.split('-').map(Number)
|
||||
const firstDay = new Date(year, month - 1, 1)
|
||||
const lastDay = new Date(year, month, 0)
|
||||
const startWeekday = (firstDay.getDay() + 6) % 7
|
||||
|
||||
// 上月填充
|
||||
const prevMonthLastDay = new Date(year, month - 1, 0).getDate()
|
||||
for (let i = startWeekday - 1; i >= 0; i--) {
|
||||
days.push({ day: prevMonthLastDay - i, otherMonth: true, isToday: false, data: null })
|
||||
}
|
||||
|
||||
// 当月
|
||||
const today = new Date()
|
||||
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`
|
||||
|
||||
const dataMap = {}
|
||||
calendarData.value.forEach(d => { dataMap[d.date] = d })
|
||||
|
||||
for (let i = 1; i <= lastDay.getDate(); i++) {
|
||||
const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(i).padStart(2, '0')}`
|
||||
days.push({
|
||||
day: i,
|
||||
otherMonth: false,
|
||||
isToday: dateStr === todayStr,
|
||||
data: dataMap[dateStr] || null
|
||||
})
|
||||
}
|
||||
|
||||
// 下月填充
|
||||
const remaining = 42 - days.length
|
||||
for (let i = 1; i <= remaining; i++) {
|
||||
days.push({ day: i, otherMonth: true, isToday: false, data: null })
|
||||
}
|
||||
|
||||
return days
|
||||
})
|
||||
|
||||
// 获取日期范围
|
||||
const getDateRange = () => {
|
||||
const today = new Date()
|
||||
let days = 7
|
||||
if (dateType.value === 'month') days = 30
|
||||
if (dateType.value === 'quarter') days = 90
|
||||
|
||||
const endDate = today.toISOString().split('T')[0]
|
||||
const startDate = new Date(today.getTime() - days * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
|
||||
return { startDate, endDate }
|
||||
}
|
||||
|
||||
// 加载统计数据
|
||||
const loadStatistics = async () => {
|
||||
const { startDate, endDate } = getDateRange()
|
||||
const params = { startDate, endDate }
|
||||
|
||||
try {
|
||||
// 总体统计
|
||||
const overviewRes = await getOverallAdherence(params)
|
||||
overview.value = overviewRes.data
|
||||
|
||||
// 每日趋势
|
||||
const dailyRes = await getDailyAdherence(params)
|
||||
dailyList.value = dailyRes.data || []
|
||||
|
||||
// 时段统计
|
||||
const timeSlotRes = await getTimeSlotAdherence(params)
|
||||
timeSlotData.value = timeSlotRes.data
|
||||
} catch (e) {
|
||||
console.error('加载统计数据失败', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 加载日历数据
|
||||
const loadCalendarData = async () => {
|
||||
try {
|
||||
const res = await getCalendarData(null, currentYearMonth.value)
|
||||
calendarData.value = res.data || []
|
||||
} catch (e) {
|
||||
console.error('加载日历数据失败', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 切换日期类型
|
||||
const changeDateType = (type) => {
|
||||
dateType.value = type
|
||||
loadStatistics()
|
||||
}
|
||||
|
||||
// 切换月份
|
||||
const changeMonth = (delta) => {
|
||||
const [year, month] = currentYearMonth.value.split('-').map(Number)
|
||||
const newDate = new Date(year, month - 1 + delta, 1)
|
||||
currentYearMonth.value = `${newDate.getFullYear()}-${String(newDate.getMonth() + 1).padStart(2, '0')}`
|
||||
currentMonthText.value = `${newDate.getFullYear()}年${newDate.getMonth() + 1}月`
|
||||
loadCalendarData()
|
||||
}
|
||||
|
||||
// 获取日历单元格指示器样式
|
||||
const getIndicatorClass = (data) => {
|
||||
const rate = data.adherenceRate || 0
|
||||
if (rate >= 80) return 'good'
|
||||
if (rate >= 50) return 'normal'
|
||||
return 'bad'
|
||||
}
|
||||
|
||||
// 返回
|
||||
const goBack = () => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 初始化月份
|
||||
const today = new Date()
|
||||
currentYearMonth.value = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}`
|
||||
currentMonthText.value = `${today.getFullYear()}年${today.getMonth() + 1}月`
|
||||
|
||||
loadStatistics()
|
||||
loadCalendarData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background: #f5f7fa;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.custom-navbar {
|
||||
background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
|
||||
padding-top: 88rpx;
|
||||
padding-bottom: 30rpx;
|
||||
|
||||
.navbar-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.navbar-title {
|
||||
color: #ffffff;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.navbar-left, .navbar-right {
|
||||
width: 60rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.date-selector {
|
||||
display: flex;
|
||||
background: #ffffff;
|
||||
padding: 20rpx 30rpx;
|
||||
gap: 20rpx;
|
||||
|
||||
.date-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 16rpx 0;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
color: #606266;
|
||||
background: #f5f7fa;
|
||||
|
||||
&.active {
|
||||
background: #409EFF;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overview-section {
|
||||
background: #ffffff;
|
||||
margin: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
|
||||
.stat-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
|
||||
&.large {
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
|
||||
&.success { color: #67C23A; }
|
||||
&.danger { color: #F56C6C; }
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #909399;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.progress-ring {
|
||||
text-align: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.ring-value {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.ring-label {
|
||||
font-size: 24rpx;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chart-section {
|
||||
background: #ffffff;
|
||||
margin: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
height: 400rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.time-slot-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
|
||||
.time-slot-item {
|
||||
background: #f5f7fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
text-align: center;
|
||||
|
||||
.slot-name {
|
||||
font-size: 26rpx;
|
||||
color: #606266;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.slot-rate {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
.slot-detail {
|
||||
font-size: 24rpx;
|
||||
color: #909399;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-section {
|
||||
background: #ffffff;
|
||||
margin: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.month-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
|
||||
.current-month {
|
||||
font-size: 28rpx;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-grid {
|
||||
.calendar-header {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #EBEEF5;
|
||||
|
||||
.header-cell {
|
||||
font-size: 26rpx;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-body {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 4rpx;
|
||||
padding-top: 10rpx;
|
||||
|
||||
.calendar-cell {
|
||||
aspect-ratio: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8rpx;
|
||||
|
||||
&.other-month {
|
||||
.day-number { color: #C0C4CC; }
|
||||
}
|
||||
|
||||
&.today {
|
||||
background: #ECF5FF;
|
||||
.day-number { color: #409EFF; font-weight: bold; }
|
||||
}
|
||||
|
||||
&.has-data {
|
||||
.day-indicator {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.day-number {
|
||||
font-size: 26rpx;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.indicator-dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
|
||||
&.good { background: #67C23A; }
|
||||
&.normal { background: #E6A23C; }
|
||||
&.bad { background: #F56C6C; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-legend {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 30rpx;
|
||||
margin-top: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #EBEEF5;
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
font-size: 22rpx;
|
||||
color: #909399;
|
||||
|
||||
.legend-dot {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
|
||||
&.good { background: #67C23A; }
|
||||
&.normal { background: #E6A23C; }
|
||||
&.bad { background: #F56C6C; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user