This commit is contained in:
ChuXun
2025-10-19 20:28:31 +08:00
parent c81f8a8b03
commit eaab9a762a
100 changed files with 23416 additions and 0 deletions

421
pages/schedule/schedule.js Normal file
View File

@@ -0,0 +1,421 @@
// pages/schedule/schedule.js
const learningTracker = require('../../utils/learningTracker.js')
Page({
data: {
weekDays: ['周一', '周二', '周三', '周四', '周五'],
timePeriods: ['1-2节', '3-4节', '5-6节', '7-8节', '9-10节'],
currentWeek: 1, // 当前查看的周次
totalWeeks: 20, // 总周数(一学期)
schedule: {},
scheduleData: [], // 用于视图渲染的二维数组
showEditModal: false,
editMode: 'add', // 'add' 或 'edit'
editDay: '',
editPeriod: '',
editCourse: {
name: '',
location: ''
}
},
onLoad() {
// 初始化当前周次(可以根据学期开始日期计算)
this.initCurrentWeek()
this.loadSchedule()
},
onShow() {
// 开始跟踪学习时间
learningTracker.onPageShow('tools')
// 更新自定义TabBar选中状态
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({
selected: 2
})
}
// 刷新当前周的课表
this.loadSchedule()
},
onHide() {
// 停止跟踪学习时间
learningTracker.onPageHide()
},
onUnload() {
// 记录学习时长
learningTracker.onPageUnload()
},
// 初始化当前周次
initCurrentWeek() {
// 从缓存获取学期开始日期
let semesterStartDate = wx.getStorageSync('semesterStartDate')
if (!semesterStartDate) {
// 如果没有设置默认为当前学期第1周
// 实际应用中可以让用户设置学期开始日期
this.setData({ currentWeek: 1 })
return
}
// 计算当前是第几周
const startDate = new Date(semesterStartDate)
const today = new Date()
const diffTime = Math.abs(today - startDate)
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
const weekNumber = Math.ceil(diffDays / 7)
// 确保周数在有效范围内
const currentWeek = Math.min(Math.max(weekNumber, 1), this.data.totalWeeks)
this.setData({ currentWeek })
},
// 加载课程表
loadSchedule() {
const { currentWeek } = this.data
const allSchedules = wx.getStorageSync('allCourseSchedules') || {}
const savedSchedule = allSchedules[`week_${currentWeek}`] || {}
// 示例数据仅第1周有默认数据
let defaultSchedule = {}
if (currentWeek === 1 && Object.keys(savedSchedule).length === 0) {
defaultSchedule = {
'周一-1-2节': { name: '高等数学A', location: '主楼A201' },
'周一-3-4节': { name: '数据结构', location: '信息学馆301' },
'周二-1-2节': { name: '大学英语', location: '外语楼205' },
'周二-3-4节': { name: '大学物理', location: '主楼B305' },
'周三-1-2节': { name: '高等数学A', location: '主楼A201' },
'周三-5-6节': { name: 'Python程序设计', location: '实验室A' },
'周四-1-2节': { name: '大学物理', location: '主楼B305' },
'周四-5-6节': { name: '机器学习', location: '信息学馆505' },
'周五-1-2节': { name: '数据结构', location: '信息学馆301' }
}
}
const schedule = Object.keys(savedSchedule).length > 0 ? savedSchedule : defaultSchedule
// 构建二维数组用于渲染
const scheduleData = this.buildScheduleData(schedule)
this.setData({
schedule,
scheduleData
})
// 保存默认数据仅第1周
if (currentWeek === 1 && Object.keys(savedSchedule).length === 0 && Object.keys(defaultSchedule).length > 0) {
const allSchedules = wx.getStorageSync('allCourseSchedules') || {}
allSchedules[`week_${currentWeek}`] = defaultSchedule
wx.setStorageSync('allCourseSchedules', allSchedules)
}
},
// 上一周
onPrevWeek() {
const { currentWeek } = this.data
if (currentWeek > 1) {
this.setData({ currentWeek: currentWeek - 1 })
this.loadSchedule()
wx.showToast({
title: `${currentWeek - 1}`,
icon: 'none',
duration: 1000
})
} else {
wx.showToast({
title: '已经是第一周了',
icon: 'none',
duration: 1500
})
}
},
// 下一周
onNextWeek() {
const { currentWeek, totalWeeks } = this.data
if (currentWeek < totalWeeks) {
this.setData({ currentWeek: currentWeek + 1 })
this.loadSchedule()
wx.showToast({
title: `${currentWeek + 1}`,
icon: 'none',
duration: 1000
})
} else {
wx.showToast({
title: '已经是最后一周了',
icon: 'none',
duration: 1500
})
}
},
// 回到本周
onCurrentWeek() {
this.initCurrentWeek()
this.loadSchedule()
wx.showToast({
title: '已回到本周',
icon: 'success',
duration: 1000
})
},
// 构建课程表数据结构
buildScheduleData(schedule) {
const { weekDays, timePeriods } = this.data
const scheduleData = []
timePeriods.forEach(period => {
const row = {
period: period,
courses: []
}
weekDays.forEach(day => {
const key = `${day}-${period}`
const course = schedule[key] || null
row.courses.push({
day: day,
course: course,
hasCourse: !!course
})
})
scheduleData.push(row)
})
return scheduleData
},
// 点击添加课程按钮
onAddCourse() {
wx.showModal({
title: '添加课程',
content: '请点击课程表中的空白格子来添加课程',
showCancel: false,
confirmText: '知道了',
confirmColor: '#667eea'
})
},
// 点击课程格子
onCourseClick(e) {
const { day, period, course } = e.currentTarget.dataset
if (course) {
// 有课程,显示课程信息
wx.showModal({
title: course.name,
content: `上课时间:${day} ${period}\n上课地点:${course.location}`,
showCancel: true,
cancelText: '关闭',
confirmText: '编辑',
confirmColor: '#667eea',
success: (res) => {
if (res.confirm) {
this.openEditModal('edit', day, period, course)
}
}
})
} else {
// 无课程,添加课程
this.openEditModal('add', day, period, null)
}
},
// 长按课程格子
onCourseLongPress(e) {
const { day, period, course } = e.currentTarget.dataset
if (course) {
wx.showActionSheet({
itemList: ['编辑课程', '删除课程'],
success: (res) => {
if (res.tapIndex === 0) {
this.openEditModal('edit', day, period, course)
} else if (res.tapIndex === 1) {
this.deleteCourse(day, period)
}
}
})
}
},
// 打开编辑弹窗
openEditModal(mode, day, period, course) {
this.setData({
showEditModal: true,
editMode: mode,
editDay: day,
editPeriod: period,
editCourse: course ? { ...course } : { name: '', location: '' }
})
},
// 关闭编辑弹窗
closeEditModal() {
this.setData({
showEditModal: false,
editCourse: { name: '', location: '' }
})
},
// 课程名称输入
onCourseNameInput(e) {
this.setData({
'editCourse.name': e.detail.value
})
},
// 课程地点输入
onCourseLocationInput(e) {
this.setData({
'editCourse.location': e.detail.value
})
},
// 保存课程
onSaveCourse() {
const { editDay, editPeriod, editCourse, currentWeek } = this.data
if (!editCourse.name.trim()) {
wx.showToast({
title: '请输入课程名称',
icon: 'none'
})
return
}
if (!editCourse.location.trim()) {
wx.showToast({
title: '请输入上课地点',
icon: 'none'
})
return
}
const key = `${editDay}-${editPeriod}`
const schedule = this.data.schedule
schedule[key] = {
name: editCourse.name.trim(),
location: editCourse.location.trim()
}
// 保存到对应周次的课表
const allSchedules = wx.getStorageSync('allCourseSchedules') || {}
allSchedules[`week_${currentWeek}`] = schedule
wx.setStorageSync('allCourseSchedules', allSchedules)
// 更新视图
const scheduleData = this.buildScheduleData(schedule)
this.setData({
schedule,
scheduleData,
showEditModal: false,
editCourse: { name: '', location: '' }
})
wx.showToast({
title: '保存成功',
icon: 'success'
})
},
// 删除课程
onDeleteCourse() {
const { editDay, editPeriod } = this.data
wx.showModal({
title: '确认删除',
content: '确定要删除这门课程吗?',
confirmColor: '#FF5252',
success: (res) => {
if (res.confirm) {
this.deleteCourse(editDay, editPeriod)
this.closeEditModal()
}
}
})
},
// 删除课程逻辑
deleteCourse(day, period) {
const { currentWeek } = this.data
const key = `${day}-${period}`
const schedule = this.data.schedule
delete schedule[key]
// 保存到对应周次的课表
const allSchedules = wx.getStorageSync('allCourseSchedules') || {}
allSchedules[`week_${currentWeek}`] = schedule
wx.setStorageSync('allCourseSchedules', allSchedules)
// 更新视图
const scheduleData = this.buildScheduleData(schedule)
this.setData({
schedule,
scheduleData
})
wx.showToast({
title: '已删除',
icon: 'success'
})
},
// 复制当前周课表到其他周
onCopySchedule() {
const { currentWeek, schedule } = this.data
// 如果当前周没有课表,提示用户
if (Object.keys(schedule).length === 0) {
wx.showToast({
title: '当前周没有课程',
icon: 'none',
duration: 2000
})
return
}
wx.showModal({
title: '复制课表',
content: `是否将第${currentWeek}周的课表复制到所有周?(不会覆盖已有课程的周)`,
confirmText: '复制',
cancelText: '取消',
confirmColor: '#9B59B6',
success: (res) => {
if (res.confirm) {
const allSchedules = wx.getStorageSync('allCourseSchedules') || {}
let copiedCount = 0
// 复制到其他周(跳过已有课表的周)
for (let week = 1; week <= this.data.totalWeeks; week++) {
if (week !== currentWeek && !allSchedules[`week_${week}`]) {
allSchedules[`week_${week}`] = { ...schedule }
copiedCount++
}
}
wx.setStorageSync('allCourseSchedules', allSchedules)
wx.showToast({
title: `已复制到${copiedCount}`,
icon: 'success',
duration: 2000
})
}
}
})
},
// 阻止事件冒泡
doNothing() {}
})

View File

@@ -0,0 +1,3 @@
{
"navigationBarTitleText": "课程表"
}

View File

@@ -0,0 +1,123 @@
<!--pages/schedule/schedule.wxml-->
<view class="container">
<view class="header">
<view class="header-title">我的课程表</view>
<view class="header-right">
<view class="add-btn" bindtap="onAddCourse">
<text class="add-icon">+</text>
</view>
</view>
</view>
<!-- 周次切换器 -->
<view class="week-selector">
<view class="week-btn" bindtap="onPrevWeek">
<text class="week-arrow">◀</text>
</view>
<view class="week-display" bindtap="onCurrentWeek">
<text class="week-text">第{{currentWeek}}周</text>
<text class="week-hint">点击回到本周</text>
</view>
<view class="week-btn" bindtap="onNextWeek">
<text class="week-arrow">▶</text>
</view>
</view>
<view class="schedule-container">
<view class="schedule-table">
<!-- 表头 -->
<view class="table-header">
<view class="time-column header-cell">时间</view>
<view class="day-column header-cell" wx:for="{{weekDays}}" wx:key="index">
{{item}}
</view>
</view>
<!-- 课程格子 -->
<view class="table-row" wx:for="{{scheduleData}}" wx:key="index" wx:for-item="row">
<view class="time-column time-cell">{{row.period}}</view>
<view
class="day-column course-cell {{item.hasCourse ? 'has-course' : ''}}"
wx:for="{{row.courses}}"
wx:key="index"
wx:for-item="item"
data-day="{{item.day}}"
data-period="{{row.period}}"
data-course="{{item.course}}"
bindtap="onCourseClick"
bindlongpress="onCourseLongPress"
>
<block wx:if="{{item.course}}">
<view class="course-name">{{item.course.name}}</view>
<view class="course-location">{{item.course.location}}</view>
</block>
<view class="empty-hint" wx:else>
<text class="hint-text">+</text>
</view>
</view>
</view>
</view>
</view>
<!-- 快捷操作按钮 -->
<view class="action-buttons">
<button class="action-btn copy-btn" bindtap="onCopySchedule">
<text class="btn-icon">📋</text>
<text class="btn-text">复制课表到其他周</text>
</button>
</view>
<view class="legend">
<view class="legend-item">
<view class="legend-color has-course"></view>
<text class="legend-text">有课</text>
</view>
<view class="legend-item">
<view class="legend-color"></view>
<text class="legend-text">无课</text>
</view>
</view>
<!-- 添加/编辑课程弹窗 -->
<view class="modal-mask" wx:if="{{showEditModal}}" bindtap="closeEditModal">
<view class="modal-dialog" catchtap="doNothing">
<view class="modal-header">
<text class="modal-title">{{editMode === 'add' ? '添加课程' : '编辑课程'}}</text>
<view class="modal-close" bindtap="closeEditModal">✕</view>
</view>
<view class="modal-content">
<view class="form-item">
<text class="form-label">课程名称</text>
<input
class="form-input"
placeholder="请输入课程名称"
value="{{editCourse.name}}"
bindinput="onCourseNameInput"
/>
</view>
<view class="form-item">
<text class="form-label">上课地点</text>
<input
class="form-input"
placeholder="请输入上课地点"
value="{{editCourse.location}}"
bindinput="onCourseLocationInput"
/>
</view>
<view class="form-item">
<text class="form-label">上课时间</text>
<view class="time-display">{{editDay}} {{editPeriod}}</view>
</view>
</view>
<view class="modal-footer">
<button class="modal-btn cancel-btn" bindtap="closeEditModal">取消</button>
<button class="modal-btn delete-btn" wx:if="{{editMode === 'edit'}}" bindtap="onDeleteCourse">删除</button>
<button class="modal-btn confirm-btn" bindtap="onSaveCourse">保存</button>
</view>
</view>
</view>
</view>

View File

@@ -0,0 +1,526 @@
/* pages/schedule/schedule.wxss */
.container {
min-height: 100vh;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
animation: fadeIn 0.5s ease-out;
}
.header {
background: linear-gradient(135deg, #9B59B6 0%, #8E44AD 100%);
padding: 45rpx 30rpx;
color: #ffffff;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 8rpx 24rpx rgba(155, 89, 182, 0.3);
animation: slideInDown 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.header-title {
font-size: 44rpx;
font-weight: bold;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);
}
.header-right {
display: flex;
align-items: center;
gap: 20rpx;
}
.add-btn {
width: 60rpx;
height: 60rpx;
background: rgba(255, 255, 255, 0.3);
border-radius: 30rpx;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10rpx);
transition: all 0.3s ease;
}
.add-btn:active {
transform: scale(0.95);
background: rgba(255, 255, 255, 0.4);
}
.add-icon {
font-size: 48rpx;
color: #fff;
font-weight: bold;
line-height: 1;
}
/* 周次切换器 */
.week-selector {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 30rpx;
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
margin: 20rpx 30rpx;
border-radius: 20rpx;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
animation: slideInDown 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s both;
}
.week-btn {
width: 80rpx;
height: 80rpx;
background: linear-gradient(135deg, #9B59B6 0%, #8E44AD 100%);
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 4rpx 12rpx rgba(155, 89, 182, 0.3);
}
.week-btn:active {
transform: scale(0.95);
box-shadow: 0 2rpx 8rpx rgba(155, 89, 182, 0.2);
}
.week-arrow {
color: #ffffff;
font-size: 32rpx;
font-weight: bold;
}
.week-display {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 40rpx;
cursor: pointer;
}
.week-text {
font-size: 40rpx;
font-weight: bold;
color: #9B59B6;
margin-bottom: 8rpx;
}
.week-hint {
font-size: 22rpx;
color: #999;
}
.current-week {
font-size: 26rpx;
padding: 12rpx 24rpx;
background-color: rgba(255, 255, 255, 0.25);
border-radius: 24rpx;
backdrop-filter: blur(10rpx);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.schedule-container {
padding: 20rpx 30rpx;
}
.schedule-table {
width: 100%;
background-color: #ffffff;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.1);
animation: scaleIn 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.2s both;
}
.table-header {
display: flex;
background: linear-gradient(135deg, #9B59B6 0%, #8E44AD 100%);
color: #ffffff;
box-shadow: 0 4rpx 12rpx rgba(155, 89, 182, 0.2);
}
.table-row {
display: flex;
border-bottom: 2rpx solid #f0f0f0;
transition: all 0.3s ease;
}
.table-row:last-child {
border-bottom: none;
}
.time-column {
flex: 0 0 100rpx;
width: 100rpx;
}
.day-column {
flex: 1;
min-width: 0;
}
.header-cell {
padding: 20rpx 8rpx;
text-align: center;
font-size: 26rpx;
font-weight: bold;
border-right: 2rpx solid rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.header-cell:last-child {
border-right: none;
}
.time-cell {
display: flex;
align-items: center;
justify-content: center;
padding: 16rpx 8rpx;
font-size: 24rpx;
color: #666666;
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
border-right: 2rpx solid #f0f0f0;
font-weight: 600;
}
.course-cell {
padding: 12rpx 8rpx;
border-right: 2rpx solid #f0f0f0;
min-height: 110rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #ffffff;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
text-overflow: ellipsis;
}
.course-cell:last-child {
border-right: none;
}
.course-cell.has-course {
background: linear-gradient(135deg, #E8D5F2 0%, #F0E5F5 100%);
box-shadow: inset 0 2rpx 8rpx rgba(155, 89, 182, 0.15);
cursor: pointer;
}
.course-cell.has-course::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4rpx;
background: linear-gradient(to bottom, #9B59B6, #8E44AD);
}
.course-cell.has-course:active {
transform: scale(0.98);
background: linear-gradient(135deg, #d5b8e8 0%, #e5d5f0 100%);
}
.course-name {
font-size: 22rpx;
font-weight: bold;
color: #9B59B6;
margin-bottom: 6rpx;
text-align: center;
line-height: 1.3;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.course-location {
font-size: 20rpx;
color: #8E44AD;
text-align: center;
opacity: 0.9;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.empty-hint {
display: flex;
align-items: center;
justify-content: center;
opacity: 0.3;
width: 100%;
height: 100%;
}
.hint-text {
font-size: 32rpx;
color: #999;
font-weight: 300;
}
/* 快捷操作按钮 */
.action-buttons {
padding: 20rpx 30rpx;
animation: slideInUp 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.3s both;
}
.action-btn {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
padding: 28rpx;
background: linear-gradient(135deg, #9B59B6 0%, #8E44AD 100%);
border-radius: 20rpx;
border: none;
box-shadow: 0 8rpx 24rpx rgba(155, 89, 182, 0.3);
transition: all 0.3s ease;
}
.action-btn:active {
transform: scale(0.98);
box-shadow: 0 4rpx 16rpx rgba(155, 89, 182, 0.2);
}
.btn-icon {
font-size: 36rpx;
}
.btn-text {
font-size: 28rpx;
font-weight: bold;
color: #ffffff;
}
.legend {
display: flex;
justify-content: center;
gap: 50rpx;
padding: 35rpx;
animation: fadeIn 0.8s ease-out 0.4s both;
}
.legend-item {
display: flex;
align-items: center;
gap: 15rpx;
padding: 12rpx 24rpx;
background-color: #ffffff;
border-radius: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
}
.legend-item:active {
transform: scale(0.95);
}
.legend-color {
width: 48rpx;
height: 48rpx;
border-radius: 12rpx;
background-color: #ffffff;
border: 3rpx solid #e0e0e0;
transition: all 0.3s ease;
}
.legend-color.has-course {
background: linear-gradient(135deg, #E8D5F2 0%, #F0E5F5 100%);
border-color: #9B59B6;
box-shadow: 0 2rpx 8rpx rgba(155, 89, 182, 0.3);
}
.legend-text {
font-size: 26rpx;
color: #666666;
font-weight: 500;
}
/* 空格子提示 */
.empty-hint {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.2;
transition: all 0.2s ease;
}
.course-cell:active .empty-hint {
opacity: 0.5;
}
.hint-text {
font-size: 40rpx;
color: #9B59B6;
font-weight: 300;
}
/* 编辑弹窗样式 */
.modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
animation: fadeIn 0.3s ease;
}
.modal-dialog {
width: 85%;
max-width: 600rpx;
background-color: #ffffff;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3);
animation: modalSlideIn 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes modalSlideIn {
from {
opacity: 0;
transform: translateY(50rpx) scale(0.9);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.modal-header {
padding: 35rpx 30rpx;
background: linear-gradient(135deg, #9B59B6 0%, #8E44AD 100%);
color: #ffffff;
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-title {
font-size: 32rpx;
font-weight: bold;
}
.modal-close {
width: 50rpx;
height: 50rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 36rpx;
border-radius: 25rpx;
transition: all 0.2s ease;
}
.modal-close:active {
background-color: rgba(255, 255, 255, 0.2);
}
.modal-content {
padding: 40rpx 30rpx;
}
.form-item {
margin-bottom: 30rpx;
}
.form-item:last-child {
margin-bottom: 0;
}
.form-label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
font-weight: 600;
}
.form-input {
width: 100%;
padding: 25rpx 20rpx;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
font-size: 28rpx;
background-color: #f8f9fa;
transition: all 0.3s ease;
}
.form-input:focus {
border-color: #9B59B6;
background-color: #fff;
}
.time-display {
padding: 25rpx 20rpx;
background: linear-gradient(135deg, #E8D5F2 0%, #F0E5F5 100%);
border-radius: 12rpx;
font-size: 28rpx;
color: #9B59B6;
font-weight: 600;
text-align: center;
}
.modal-footer {
padding: 25rpx 30rpx;
background-color: #f8f9fa;
display: flex;
gap: 15rpx;
}
.modal-btn {
flex: 1;
padding: 25rpx;
border-radius: 12rpx;
font-size: 28rpx;
font-weight: 600;
border: none;
transition: all 0.3s ease;
}
.modal-btn::after {
border: none;
}
.cancel-btn {
background-color: #e0e0e0;
color: #666;
}
.cancel-btn:active {
background-color: #d0d0d0;
}
.delete-btn {
background: linear-gradient(135deg, #FF5252 0%, #E53935 100%);
color: #fff;
}
.delete-btn:active {
opacity: 0.8;
}
.confirm-btn {
background: linear-gradient(135deg, #9B59B6 0%, #8E44AD 100%);
color: #fff;
}
.confirm-btn:active {
opacity: 0.8;
}