<template>
|
<div class="profit-calendar-page">
|
<!-- Header -->
|
<div class="header">
|
<div class="header-top">
|
<a class="back-btn" @click="$router.go(-1)"></a>
|
<h2 class="page-title">{{ $t('profitCalendar_title') }}</h2>
|
</div>
|
<div class="profit-display">
|
<div class="profit-label">{{ $t('profitCalendar_monthProfit') }}</div>
|
<div class="profit-value">{{ formatProfit(currentMonthProfit) }}</div>
|
</div>
|
<div class="date-tabs" v-if="false">
|
<div
|
class="tab-item"
|
:class="{ active: activeTab === 'today' }"
|
@click="activeTab = 'today'"
|
>
|
今日
|
</div>
|
<div
|
class="tab-item"
|
:class="{ active: activeTab === 'month' }"
|
@click="activeTab = 'month'"
|
>
|
本月
|
</div>
|
</div>
|
</div>
|
|
<!-- Chart Section -->
|
<div class="chart-section">
|
<div class="chart-date-range">{{ chartStartDate }} {{ $t('profitCalendar_to') }} {{ chartEndDate }}</div>
|
<div class="chart-title">{{ $t('profitCalendar_profitAmount') }}</div>
|
<div class="chart-container" ref="chartContainer"></div>
|
</div>
|
|
<!-- Calendar Section -->
|
<div class="calendar-section">
|
<div class="calendar-title">{{ $t('profitCalendar_calendar') }}</div>
|
<div class="month-navigation">
|
<span class="nav-arrow" @click="prevMonth">‹</span>
|
<div class="month-selector">
|
<span>{{ currentYear }}{{ $t('profitCalendar_year') }}{{ String(currentMonth).padStart(2, '0') }}{{ $t('profitCalendar_monthText') }}</span>
|
<span class="dropdown-icon">▼</span>
|
</div>
|
<span class="nav-arrow" @click="nextMonth">›</span>
|
</div>
|
<div class="month-summary">
|
<span class="summary-label">{{ String(currentMonth).padStart(2, '0') }}{{ $t('profitCalendar_monthText') }} {{ $t('profitCalendar_accountProfit') }}</span>
|
<span class="summary-value">{{ formatProfitShort(monthProfit) }}</span>
|
</div>
|
<div class="calendar-grid">
|
<div class="weekdays">
|
<div class="weekday" v-for="day in weekdays" :key="day">{{ day }}</div>
|
</div>
|
<div class="calendar-days">
|
<div
|
v-for="(day, index) in calendarDays"
|
:key="index"
|
class="calendar-day"
|
:class="{
|
'other-month': day.otherMonth,
|
'active': day.active,
|
'today': day.isToday
|
}"
|
>
|
<span class="day-number">{{ day.date }}</span>
|
<span v-if="day.marketClosed" class="market-status">{{ $t('profitCalendar_marketClosed') }}</span>
|
<span v-if="!day.marketClosed && !day.otherMonth && day.profit !== 0"
|
class="profit-amount"
|
:class="{ 'profit-up': day.profit > 0, 'profit-down': day.profit < 0 }">
|
{{ day.profit > 0 ? '+' : '' }}{{ formatProfitShort(day.profit) }}
|
</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import * as echarts from 'echarts'
|
import * as api from '@/axios/api'
|
|
export default {
|
name: 'ProfitCalendar',
|
data() {
|
return {
|
activeTab: 'month',
|
currentMonthProfit: 0,
|
monthProfit: 0,
|
currentYear: new Date().getFullYear(),
|
currentMonth: new Date().getMonth() + 1,
|
chartStartDate: '',
|
chartEndDate: '',
|
calendarDays: [],
|
chartData: [],
|
chartDates: [],
|
marketClosedFlags: [], // 记录每个数据点是否是休市日
|
myChart: null,
|
profitData: {}, // 存储从接口获取的收益数据
|
loading: false
|
}
|
},
|
computed: {
|
weekdays() {
|
return [
|
this.$t('profitCalendar_sunday'),
|
this.$t('profitCalendar_monday'),
|
this.$t('profitCalendar_tuesday'),
|
this.$t('profitCalendar_wednesday'),
|
this.$t('profitCalendar_thursday'),
|
this.$t('profitCalendar_friday'),
|
this.$t('profitCalendar_saturday')
|
]
|
}
|
},
|
mounted() {
|
this.loadProfitData()
|
},
|
beforeDestroy() {
|
if (this.myChart) {
|
this.myChart.dispose()
|
}
|
},
|
methods: {
|
// 加载收益数据
|
async loadProfitData() {
|
this.loading = true
|
try {
|
// 格式化年月参数为 "2026-01" 格式
|
const yearMonth = `${this.currentYear}-${String(this.currentMonth).padStart(2, '0')}`
|
const params = {
|
yearMonth: yearMonth
|
}
|
const res = await api.getProfitCalendar(params)
|
|
// 处理返回的数据
|
// 接口返回格式:data: [{recordDate: "2026-01-01", profit: 0, isWeekendAndHoliday: true}, ...]
|
|
if (res && res.data && Array.isArray(res.data)) {
|
const dataList = res.data
|
|
// 将数组转换为日历数据对象,以 recordDate 为 key
|
const calendarDataObj = {}
|
let totalProfit = 0 // 本月总收益
|
|
dataList.forEach(item => {
|
const { recordDate, profit, isWeekendAndHoliday } = item
|
const profitValue = profit || 0
|
calendarDataObj[recordDate] = {
|
active: profitValue !== 0, // 有收益数据(无论正负)的日期显示为active
|
marketClosed: isWeekendAndHoliday, // 周末或节假日显示休市
|
profit: profitValue
|
}
|
totalProfit += profitValue
|
})
|
|
// 更新收益数据
|
this.currentMonthProfit = totalProfit
|
this.monthProfit = totalProfit
|
|
// 更新图表数据,处理休市日:休市日保持前一个交易日的值,使线条连贯
|
this.chartDates = dataList.map(item => item.recordDate)
|
const processedChartData = []
|
const marketClosedFlags = [] // 记录每个数据点是否是休市日
|
let lastTradingDayProfit = null // 记录最后一个交易日的收益
|
|
dataList.forEach((item, index) => {
|
if (item.isWeekendAndHoliday) {
|
// 休市日:使用前一个交易日的收益值,保持水平
|
// 如果还没有交易日数据,使用0
|
processedChartData.push(lastTradingDayProfit !== null ? lastTradingDayProfit : 0)
|
marketClosedFlags.push(true) // 标记为休市日
|
} else {
|
// 交易日:使用实际收益值
|
const profitValue = item.profit || 0
|
lastTradingDayProfit = profitValue
|
processedChartData.push(profitValue)
|
marketClosedFlags.push(false) // 标记为交易日
|
}
|
})
|
|
this.chartData = processedChartData
|
this.marketClosedFlags = marketClosedFlags // 保存休市日标记
|
|
if (this.chartDates.length > 0) {
|
this.chartStartDate = this.chartDates[0]
|
this.chartEndDate = this.chartDates[this.chartDates.length - 1]
|
}
|
|
// 存储日历数据
|
this.profitData = calendarDataObj
|
|
// 初始化日历和图表
|
this.initCalendar()
|
this.initChart()
|
} else {
|
// 如果接口返回格式不同,可以根据实际情况调整
|
console.warn('收益数据格式异常:', res)
|
this.profitData = {}
|
this.chartDates = []
|
this.chartData = []
|
this.currentMonthProfit = 0
|
this.monthProfit = 0
|
this.initCalendar()
|
this.initChart()
|
}
|
} catch (error) {
|
console.error('加载收益数据失败:', error)
|
// 出错时仍然显示日历框架
|
this.initCalendar()
|
this.initChart()
|
} finally {
|
this.loading = false
|
}
|
},
|
initCalendar() {
|
const year = this.currentYear
|
const month = this.currentMonth
|
const firstDay = new Date(year, month - 1, 1)
|
const lastDay = new Date(year, month, 0)
|
const firstDayWeek = firstDay.getDay()
|
const daysInMonth = lastDay.getDate()
|
|
// 获取上个月的最后几天
|
const prevMonthLastDay = new Date(year, month - 1, 0).getDate()
|
const days = []
|
|
// 上个月的日期
|
for (let i = firstDayWeek - 1; i >= 0; i--) {
|
days.push({
|
date: prevMonthLastDay - i,
|
otherMonth: true,
|
active: false,
|
isToday: false,
|
marketClosed: false,
|
profit: 0
|
})
|
}
|
|
// 当前月的日期
|
const today = new Date()
|
for (let i = 1; i <= daysInMonth; i++) {
|
const date = new Date(year, month - 1, i)
|
const isToday = date.getDate() === today.getDate() &&
|
date.getMonth() === today.getMonth() &&
|
date.getFullYear() === today.getFullYear()
|
|
// 格式化日期字符串,用于查找收益数据(支持多种格式)
|
const dateStr1 = `${year}-${String(month).padStart(2, '0')}-${String(i).padStart(2, '0')}`
|
const dateStr2 = `${year}/${String(month).padStart(2, '0')}/${String(i).padStart(2, '0')}`
|
const dateStr3 = `${year}${String(month).padStart(2, '0')}${String(i).padStart(2, '0')}`
|
|
const dayData = this.profitData[dateStr1] || this.profitData[dateStr2] || this.profitData[dateStr3] || {}
|
const hasProfit = dayData.profit !== undefined && dayData.profit !== null && dayData.profit !== 0
|
|
days.push({
|
date: i,
|
otherMonth: false,
|
active: dayData.active === true || hasProfit, // 如果有收益数据(无论正负)则显示为active
|
isToday: isToday,
|
marketClosed: dayData.marketClosed === true,
|
profit: dayData.profit !== undefined && dayData.profit !== null ? dayData.profit : 0
|
})
|
}
|
|
// 补齐到42个格子(6行x7列)
|
const remaining = 42 - days.length
|
for (let i = 1; i <= remaining; i++) {
|
days.push({
|
date: i,
|
otherMonth: true,
|
active: false,
|
isToday: false,
|
marketClosed: false,
|
profit: 0
|
})
|
}
|
|
this.calendarDays = days
|
},
|
initChart() {
|
this.$nextTick(() => {
|
if (this.$refs.chartContainer) {
|
// 如果图表已存在,则销毁后重新创建
|
if (this.myChart) {
|
this.myChart.dispose()
|
}
|
|
this.myChart = echarts.init(this.$refs.chartContainer)
|
|
// 计算y轴最小值和最大值
|
let minValue = 0
|
let maxValue = 0
|
if (this.chartData.length > 0) {
|
const values = this.chartData.map(item => typeof item === 'object' ? item.value : item)
|
minValue = Math.min(...values, this.currentMonthProfit || 0)
|
maxValue = Math.max(...values, this.currentMonthProfit || 0)
|
} else {
|
minValue = this.currentMonthProfit || 0
|
maxValue = this.currentMonthProfit || 70000
|
}
|
|
// 如果有负数,需要向下取整;如果有正数,需要向上取整
|
// 确保 yAxisMin 和 yAxisMax 有合理的范围
|
let yAxisMin = minValue < 0 ? Math.floor(minValue / 10000) * 10000 : 0
|
let yAxisMax = maxValue > 0 ? Math.ceil(maxValue / 10000) * 10000 : 70000
|
|
// 如果数据全为负数,确保 yAxisMax 至少为 0
|
if (maxValue <= 0) {
|
yAxisMax = 0
|
}
|
// 如果数据全为正数,确保 yAxisMin 至少为 0
|
if (minValue >= 0) {
|
yAxisMin = 0
|
}
|
|
// 如果 minValue 和 maxValue 都为 0,设置默认范围
|
if (minValue === 0 && maxValue === 0) {
|
yAxisMin = 0
|
yAxisMax = 70000
|
}
|
|
// 计算合适的间隔
|
const range = yAxisMax - yAxisMin
|
const interval = range > 0 ? Math.ceil(range / 7) : 10000
|
|
// 准备分段数据:将数据分成多个连续段,每段使用不同颜色
|
// 涨:红色,跌:绿色,休市:黑色
|
const segments = []
|
let currentSegment = null
|
|
this.chartData.forEach((value, index) => {
|
const isClosed = this.marketClosedFlags && this.marketClosedFlags[index]
|
const isPositive = value >= 0
|
let segmentType = isClosed ? 'closed' : (isPositive ? 'positive' : 'negative')
|
|
if (!currentSegment || currentSegment.type !== segmentType) {
|
// 开始新的一段
|
if (currentSegment) {
|
segments.push(currentSegment)
|
}
|
currentSegment = {
|
type: segmentType,
|
data: [],
|
startIndex: index
|
}
|
}
|
|
currentSegment.data.push(value)
|
})
|
|
// 添加最后一段
|
if (currentSegment) {
|
segments.push(currentSegment)
|
}
|
|
const option = {
|
backgroundColor: 'transparent',
|
grid: {
|
left: '12%',
|
right: '8%',
|
top: '12%',
|
bottom: '12%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
data: this.chartDates.length > 0 ? this.chartDates : [],
|
boundaryGap: false,
|
axisLine: {
|
show: false
|
},
|
axisLabel: {
|
show: true,
|
color: '#999',
|
fontSize: 11,
|
margin: 8
|
},
|
axisTick: {
|
show: false
|
},
|
splitLine: {
|
show: false
|
}
|
},
|
yAxis: {
|
type: 'value',
|
min: yAxisMin,
|
max: yAxisMax,
|
interval: interval,
|
axisLine: {
|
show: false
|
},
|
axisLabel: {
|
show: true,
|
color: '#999',
|
fontSize: 11,
|
formatter: (value) => {
|
return (value / 10000).toFixed(2) + 'w'
|
}
|
},
|
splitLine: {
|
show: true,
|
lineStyle: {
|
color: '#f5f5f5',
|
type: 'solid',
|
width: 1
|
}
|
}
|
},
|
tooltip: {
|
trigger: 'axis',
|
backgroundColor: 'rgba(50, 50, 50, 0.9)',
|
borderColor: 'transparent',
|
borderWidth: 0,
|
textStyle: {
|
color: '#fff',
|
fontSize: 12
|
},
|
padding: [8, 12],
|
formatter: (params) => {
|
const param = params[0]
|
const value = param.value
|
const idx = param.dataIndex
|
const isClosed = this.marketClosedFlags && this.marketClosedFlags[idx]
|
const color = isClosed ? '#333' : (value >= 0 ? '#d73d3d' : '#4caf50')
|
return `<div style="color: ${color}; font-weight: 600;">${param.name}</div><div style="margin-top: 4px;">${this.$t('profitCalendar_profitAmount')}: <span style="color: ${color};">${this.formatProfit(value)}</span></div>`
|
},
|
axisPointer: {
|
type: 'line',
|
lineStyle: {
|
color: '#999',
|
width: 1,
|
type: 'dashed'
|
}
|
}
|
},
|
series: segments.map((segment, segIndex) => {
|
// 为每段创建数据,其他位置填充 null
|
// 为了确保段与段之间连接,在段的开始位置包含前一个段的最后一个点
|
const segmentData = this.chartData.map((val, idx) => {
|
if (idx === segment.startIndex - 1 && segIndex > 0) {
|
// 包含前一个段的最后一个点,确保连接
|
return this.chartData[segment.startIndex - 1]
|
}
|
if (idx >= segment.startIndex && idx < segment.startIndex + segment.data.length) {
|
return segment.data[idx - segment.startIndex]
|
}
|
return null
|
})
|
|
// 根据段类型设置颜色
|
let lineColor = '#333'
|
let itemColor = '#333'
|
if (segment.type === 'positive') {
|
lineColor = '#d73d3d' // 涨:红色
|
itemColor = '#d73d3d'
|
} else if (segment.type === 'negative') {
|
lineColor = '#4caf50' // 跌:绿色
|
itemColor = '#4caf50'
|
} else {
|
lineColor = '#333' // 休市:黑色
|
itemColor = '#333'
|
}
|
|
return {
|
name: this.$t('profitCalendar_profitAmount'),
|
type: 'line',
|
data: segmentData,
|
smooth: false, // 不使用平滑,让休市日保持水平
|
connectNulls: true, // 连接空值,确保段与段之间连接
|
symbol: 'circle',
|
symbolSize: 6,
|
showSymbol: false,
|
lineStyle: {
|
width: 3,
|
color: lineColor
|
},
|
itemStyle: {
|
color: itemColor,
|
borderColor: '#fff',
|
borderWidth: 2
|
},
|
areaStyle: segment.type === 'positive' ? {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [{
|
offset: 0,
|
color: 'rgba(215, 61, 61, 0.15)'
|
}, {
|
offset: 1,
|
color: 'rgba(215, 61, 61, 0.02)'
|
}]
|
}
|
} : (segment.type === 'negative' ? {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [{
|
offset: 0,
|
color: 'rgba(76, 175, 80, 0.15)'
|
}, {
|
offset: 1,
|
color: 'rgba(76, 175, 80, 0.02)'
|
}]
|
}
|
} : null),
|
emphasis: {
|
focus: 'series',
|
itemStyle: {
|
shadowBlur: 8,
|
shadowColor: 'rgba(0, 0, 0, 0.3)'
|
}
|
},
|
z: 10 - segIndex // 确保后面的段覆盖前面的段
|
}
|
})
|
}
|
|
this.myChart.setOption(option)
|
|
// 响应式调整
|
window.addEventListener('resize', () => {
|
if (this.myChart) {
|
this.myChart.resize()
|
}
|
})
|
}
|
})
|
},
|
prevMonth() {
|
if (this.currentMonth === 1) {
|
this.currentMonth = 12
|
this.currentYear--
|
} else {
|
this.currentMonth--
|
}
|
this.loadProfitData()
|
},
|
nextMonth() {
|
if (this.currentMonth === 12) {
|
this.currentMonth = 1
|
this.currentYear++
|
} else {
|
this.currentMonth++
|
}
|
this.loadProfitData()
|
},
|
formatProfit(value) {
|
return value.toLocaleString('zh-CN')
|
},
|
formatProfitShort(value) {
|
const absValue = Math.abs(value)
|
if (absValue >= 10000) {
|
return (value / 10000).toFixed(2) + 'w'
|
}
|
return value.toFixed(2)
|
}
|
}
|
}
|
</script>
|
|
<style lang="less" scoped>
|
.profit-calendar-page {
|
background: #f5f5f5;
|
min-height: 100vh;
|
}
|
|
.header {
|
background: linear-gradient(-55deg, rgb(241, 22, 20), rgb(240, 40, 37));
|
padding: 0.4rem 0.3rem 0.6rem;
|
color: #fff;
|
|
.header-top {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
margin-bottom: 0.5rem;
|
|
.back-btn {
|
width: 0.48rem;
|
height: 0.48rem;
|
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3E%3Cpath d='M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z'/%3E%3C/svg%3E") no-repeat center;
|
background-size: 0.48rem 0.48rem;
|
cursor: pointer;
|
}
|
|
.page-title {
|
font-size: 0.48rem;
|
font-weight: 500;
|
margin: 0;
|
flex: 1;
|
text-align: center;
|
}
|
|
.header-actions {
|
display: flex;
|
gap: 0.3rem;
|
|
.action-icon {
|
font-size: 0.32rem;
|
cursor: pointer;
|
}
|
}
|
}
|
|
.profit-display {
|
text-align: center;
|
margin-bottom: 0.4rem;
|
|
.profit-label {
|
font-size: 0.32rem;
|
opacity: 0.9;
|
margin-bottom: 0.2rem;
|
}
|
|
.profit-value {
|
font-size: 0.8rem;
|
font-weight: 600;
|
}
|
}
|
|
.date-tabs {
|
display: flex;
|
gap: 0.2rem;
|
justify-content: center;
|
|
.tab-item {
|
padding: 0.2rem 0.4rem;
|
font-size: 0.32rem;
|
border-radius: 0.2rem;
|
cursor: pointer;
|
opacity: 0.7;
|
transition: all 0.3s;
|
|
&.active {
|
opacity: 1;
|
background: rgba(255, 255, 255, 0.2);
|
}
|
}
|
}
|
}
|
|
.chart-section {
|
background: #fff;
|
margin: 0.3rem;
|
border-radius: 0.24rem;
|
padding: 0.5rem 0.4rem;
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
|
.chart-date-range {
|
font-size: 0.28rem;
|
color: #999;
|
margin-bottom: 0.3rem;
|
font-weight: 400;
|
}
|
|
.chart-title {
|
font-size: 0.38rem;
|
color: #333;
|
font-weight: 600;
|
margin-bottom: 0.4rem;
|
letter-spacing: 0.5px;
|
}
|
|
.chart-container {
|
width: 100%;
|
height: 4.5rem;
|
margin-top: 0.2rem;
|
}
|
}
|
|
.calendar-section {
|
background: #fff;
|
margin: 0.3rem;
|
border-radius: 0.24rem;
|
padding: 0.5rem 0.4rem;
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
|
.calendar-title {
|
font-size: 0.42rem;
|
color: #333;
|
font-weight: 600;
|
margin-bottom: 0.4rem;
|
letter-spacing: 0.5px;
|
}
|
|
.month-navigation {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
margin-bottom: 0.3rem;
|
|
.nav-arrow {
|
font-size: 0.6rem;
|
color: #666;
|
cursor: pointer;
|
padding: 0.15rem 0.25rem;
|
transition: all 0.3s;
|
border-radius: 0.1rem;
|
|
&:hover {
|
background: #f5f5f5;
|
color: #333;
|
}
|
|
&:active {
|
background: #e9ecef;
|
}
|
}
|
|
.month-selector {
|
display: flex;
|
align-items: center;
|
gap: 0.1rem;
|
font-size: 0.38rem;
|
color: #333;
|
font-weight: 500;
|
|
.dropdown-icon {
|
font-size: 0.24rem;
|
color: #999;
|
margin-left: 0.05rem;
|
}
|
}
|
}
|
|
.month-summary {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 0.35rem 0;
|
border-bottom: 1px solid #f0f0f0;
|
margin-bottom: 0.35rem;
|
|
.summary-label {
|
font-size: 0.32rem;
|
color: #666;
|
font-weight: 400;
|
}
|
|
.summary-value {
|
font-size: 0.38rem;
|
color: #d73d3d;
|
font-weight: 700;
|
letter-spacing: 0.5px;
|
}
|
}
|
|
.calendar-grid {
|
.weekdays {
|
display: grid;
|
grid-template-columns: repeat(7, 1fr);
|
margin-bottom: 0.2rem;
|
|
.weekday {
|
text-align: center;
|
font-size: 0.28rem;
|
color: #999;
|
padding: 0.2rem 0;
|
}
|
}
|
|
.calendar-days {
|
display: grid;
|
grid-template-columns: repeat(7, 1fr);
|
gap: 0.1rem;
|
|
.calendar-day {
|
aspect-ratio: 1;
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
border-radius: 0.12rem;
|
position: relative;
|
transition: all 0.2s;
|
|
.day-number {
|
font-size: 0.33rem;
|
color: #333;
|
font-weight: 500;
|
}
|
|
.market-status {
|
font-size: 0.2rem;
|
color: #999;
|
margin-top: 0.05rem;
|
}
|
|
.profit-amount {
|
font-size: 0.22rem;
|
margin-top: 0.08rem;
|
font-weight: 600;
|
padding: 0.02rem 0.08rem;
|
border-radius: 0.08rem;
|
background: rgba(255, 255, 255, 0.8);
|
|
&.profit-up {
|
color: #d73d3d; // 红色表示涨
|
background: rgba(215, 61, 61, 0.1);
|
}
|
|
&.profit-down {
|
color: #4caf50; // 绿色表示跌
|
background: rgba(76, 175, 80, 0.1);
|
}
|
}
|
|
&.other-month {
|
.day-number {
|
color: #ccc;
|
}
|
}
|
|
&.active {
|
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
font-weight: 600;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
}
|
|
&.today {
|
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
border: 1px solid #90caf9;
|
|
.day-number {
|
color: #1976d2;
|
font-weight: 700;
|
}
|
}
|
}
|
}
|
}
|
}
|
</style>
|