Initial commit of akmon project

This commit is contained in:
2026-01-20 08:04:15 +08:00
commit 77a2bab985
1309 changed files with 343305 additions and 0 deletions

978
pages/sense/settings.uvue Normal file
View File

@@ -0,0 +1,978 @@
<template>
<view class="settings-container">
<!-- 头部导航 -->
<view class="header">
<button class="back-btn" @click="goBack">
<text class="back-icon">←</text>
</button>
<text class="title">传感器设置</text>
<button class="save-btn" @click="saveSettings">保存</button>
</view>
<!-- 通用设置 -->
<view class="section">
<text class="section-title">通用设置</text>
<view class="setting-item">
<text class="setting-label">实时数据推送</text>
<switch :checked="settings.realtime_enabled" @change="onRealtimeChange" />
</view>
<view class="setting-item">
<text class="setting-label">数据自动备份</text>
<switch :checked="settings.auto_backup" @change="onAutoBackupChange" />
</view>
<view class="setting-item">
<text class="setting-label">异常检测</text>
<switch :checked="settings.anomaly_detection" @change="onAnomalyDetectionChange" />
</view>
<view class="setting-item">
<text class="setting-label">AI分析</text>
<switch :checked="settings.ai_analysis" @change="onAIAnalysisChange" />
</view>
</view>
<!-- 数据采集频率 -->
<view class="section">
<text class="section-title">数据采集频率</text>
<view class="frequency-grid">
<view class="frequency-item" v-for="(sensor, index) in sensorFrequencies" :key="index">
<text class="sensor-name">{{ sensor.name }}</text>
<button class="picker-button" @click="showFrequencyPicker(index)">
<view class="picker-view">
<text>{{ frequencyOptions[sensor.frequency_index] }}</text>
<text class="picker-arrow">▼</text>
</view>
</button>
</view>
</view>
</view>
<!-- 阈值设置 -->
<view class="section">
<text class="section-title">异常阈值设置</text>
<view class="threshold-list">
<view class="threshold-item" v-for="(threshold, index) in thresholds" :key="index">
<text class="threshold-label">{{ threshold.name }}</text>
<view class="threshold-inputs">
<view class="input-group">
<text class="input-label">最小值</text>
<input class="threshold-input" type="number" v-model="threshold.min_value" />
</view>
<view class="input-group">
<text class="input-label">最大值</text>
<input class="threshold-input" type="number" v-model="threshold.max_value" />
</view>
</view>
</view>
</view>
</view>
<!-- 通知设置 -->
<view class="section">
<text class="section-title">通知设置</text>
<view class="notification-item">
<text class="setting-label">异常警报</text>
<switch :checked="notifications.anomaly_alert" @change="onAnomalyAlertChange" />
</view>
<view class="notification-item">
<text class="setting-label">每日报告</text>
<switch :checked="notifications.daily_report" @change="onDailyReportChange" />
</view>
<view class="notification-item">
<text class="setting-label">设备离线提醒</text>
<switch :checked="notifications.device_offline" @change="onDeviceOfflineChange" />
</view>
<view class="notification-item" v-if="notifications.daily_report">
<text class="setting-label">报告发送时间</text>
<input class="time-input" type="time" :value="notifications.report_time" @input="onReportTimeInput" />
</view>
</view>
<!-- 数据管理 -->
<view class="section">
<text class="section-title">数据管理</text>
<view class="data-management">
<view class="management-item">
<text class="setting-label">本地数据保留时间</text>
<button class="picker-button" @click="showRetentionPicker">
<view class="picker-view">
<text>{{ retentionOptions[dataManagement.retention_index] }}</text>
<text class="picker-arrow">▼</text>
</view>
</button>
</view>
<view class="management-item">
<text class="setting-label">云端同步</text>
<switch :checked="dataManagement.cloud_sync" @change="onCloudSyncChange" />
</view>
<view class="management-item">
<text class="setting-label">数据压缩</text>
<switch :checked="dataManagement.data_compression" @change="onDataCompressionChange" />
</view>
</view>
</view>
<!-- 隐私设置 -->
<view class="section">
<text class="section-title">隐私设置</text>
<view class="privacy-item">
<text class="setting-label">数据加密</text>
<switch :checked="privacy.data_encryption" @change="onDataEncryptionChange" />
</view>
<view class="privacy-item">
<text class="setting-label">匿名统计</text>
<switch :checked="privacy.anonymous_stats" @change="onAnonymousStatsChange" />
</view>
<view class="privacy-item">
<text class="setting-label">位置数据收集</text>
<switch :checked="privacy.location_data" @change="onLocationDataChange" />
</view>
</view>
<!-- 设备校准 -->
<view class="section">
<text class="section-title">设备校准</text>
<view class="calibration-list">
<button class="calibration-btn" @click="calibrateHeartRate">心率传感器校准</button>
<button class="calibration-btn" @click="calibrateSteps">步数传感器校准</button>
<button class="calibration-btn" @click="calibrateBloodPressure">血压计校准</button>
<button class="calibration-btn" @click="calibrateTemperature">体温计校准</button>
</view>
</view>
<!-- 数据导出 -->
<view class="section">
<text class="section-title">数据导出</text>
<view class="export-options">
<button class="export-btn" @click="exportData('json')">导出为JSON</button>
<button class="export-btn" @click="exportData('csv')">导出为CSV</button>
<button class="export-btn" @click="exportData('pdf')">导出为PDF报告</button>
</view>
</view>
<!-- 重置选项 -->
<view class="section">
<text class="section-title">重置选项</text>
<view class="reset-options">
<button class="reset-btn" @click="resetSettings">恢复默认设置</button>
<button class="clear-btn" @click="clearAllData">清除所有数据</button>
</view>
</view>
<!-- 校准弹窗 -->
<view class="calibration-modal" v-if="showCalibration" @click="closeCalibration">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">{{ calibrationType }}校准</text>
<button class="close-btn" @click="closeCalibration">×</button>
</view>
<view class="modal-body">
<text class="calibration-instruction">{{ calibrationInstruction }}</text>
<view class="calibration-progress" v-if="calibrationProgress > 0">
<view class="progress-bar">
<view class="progress-fill" :style="{ width: calibrationProgress + '%' }"></view>
</view>
<text class="progress-text">{{ calibrationProgress }}%</text>
</view>
<view class="calibration-actions">
<button class="start-btn" v-if="calibrationProgress === 0"
@click="startCalibration">开始校准</button>
<button class="stop-btn" v-else @click="stopCalibration">停止校准</button>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, onMounted } from 'vue'
import supa from '@/components/supadb/aksupainstance.uts'
import type {
UserSettings,
NotificationSettings,
DataManagementSettings,
PrivacySettings,
SensorFrequency,
SensorThreshold,
UserSettingsRecord,
SensorConfigItem,
ThresholdConfigItem
} from './types.uts'
// 响应式数据
const settings = ref<UserSettings>({
realtime_enabled: true,
auto_backup: true,
anomaly_detection: true,
ai_analysis: false
})
const sensorFrequencies = ref<SensorFrequency[]>([])
const thresholds = ref<SensorThreshold[]>([])
const notifications = ref<NotificationSettings>({
anomaly_alert: true,
daily_report: false,
device_offline: true,
report_time: '09:00'
})
const dataManagement = ref<DataManagementSettings>({
retention_index: 2,
cloud_sync: true,
data_compression: false
})
const privacy = ref<PrivacySettings>({
data_encryption: true,
anonymous_stats: false,
location_data: false
})
const showCalibration = ref<boolean>(false)
const calibrationType = ref<string>('')
const calibrationInstruction = ref<string>('')
const calibrationProgress = ref<number>(0)
// 选项数据
const frequencyOptions = ['关闭', '1分钟', '5分钟', '15分钟', '30分钟', '1小时']
const retentionOptions = ['7天', '30天', '90天', '1年', '永久保存']
const userId = 'eed3824b-bba1-4309-8048-19d17367c084'
let calibrationTimer : Number = 0
async function loadSettings() {
try {
const result = await supa.from('ak_training_intensity_settings')
.eq('user_id', userId)
.eq('setting_category', 'sensor')
.executeAs<Array<UserSettingsRecord>>()
if (result.data !== null && Array.isArray(result.data)) {
const dataArray = result.data as Array<any>
if (dataArray.length > 0) {
const settingsRecord = dataArray[0] as UTSJSONObject
const settingValue = settingsRecord.getJSON('setting_value')
if (settingValue !== null) {
// 更新设置
settings.value.realtime_enabled = settingValue.getBoolean('realtime_enabled') ?? true
settings.value.auto_backup = settingValue.getBoolean('auto_backup') ?? true
settings.value.anomaly_detection = settingValue.getBoolean('anomaly_detection') ?? true
settings.value.ai_analysis = settingValue.getBoolean('ai_analysis') ?? false
// 更新通知设置
const notificationData = settingValue.getJSON('notifications')
if (notificationData !== null) {
notifications.value.anomaly_alert = notificationData.getBoolean('anomaly_alert') ?? true
notifications.value.daily_report = notificationData.getBoolean('daily_report') ?? false
notifications.value.device_offline = notificationData.getBoolean('device_offline') ?? true
notifications.value.report_time = notificationData.getString('report_time') ?? '09:00'
}
// 更新数据管理设置
const dataManagementData = settingValue.getJSON('data_management')
if (dataManagementData !== null) {
dataManagement.value.retention_index = dataManagementData.getNumber('retention_index')?.toInt() ?? 2
dataManagement.value.cloud_sync = dataManagementData.getBoolean('cloud_sync') ?? true
dataManagement.value.data_compression = dataManagementData.getBoolean('data_compression') ?? false
}
// 更新隐私设置
const privacyData = settingValue.getJSON('privacy')
if (privacyData !== null) {
privacy.value.data_encryption = privacyData.getBoolean('data_encryption') ?? true
privacy.value.anonymous_stats = privacyData.getBoolean('anonymous_stats') ?? false
privacy.value.location_data = privacyData.getBoolean('location_data') ?? false
}
}
}
}
} catch (e) {
console.log('加载设置失败:', e)
}
}
function initializeSensorFrequencies() {
const frequencies : SensorFrequency[] = []
const sensors : SensorConfigItem[] = [
{ name: '心率', key: 'heart_rate', frequency_index: 2 },
{ name: '步数', key: 'steps', frequency_index: 3 },
{ name: '血氧', key: 'spo2', frequency_index: 4 },
{ name: '血压', key: 'blood_pressure', frequency_index: 5 },
{ name: '体温', key: 'temperature', frequency_index: 4 },
{ name: '位置', key: 'location', frequency_index: 3 }
]
for (let i : Int = 0; i < sensors.length; i++) {
const sensor = sensors[i]
const freq : SensorFrequency = {
name: sensor.name,
key: sensor.key,
frequency_index: sensor.frequency_index
}
frequencies.push(freq)
}
sensorFrequencies.value = frequencies
} function initializeThresholds() {
const thresholdList : SensorThreshold[] = []
const thresholdConfig : ThresholdConfigItem[] = [
{ name: '心率 (bpm)', key: 'heart_rate', min: 60, max: 100 },
{ name: '血氧 (%)', key: 'spo2', min: 95, max: 100 },
{ name: '收缩压 (mmHg)', key: 'systolic_bp', min: 90, max: 140 },
{ name: '舒张压 (mmHg)', key: 'diastolic_bp', min: 60, max: 90 },
{ name: '体温 (°C)', key: 'temperature', min: 36.0, max: 37.5 }
]
for (let i : Int = 0; i < thresholdConfig.length; i++) {
const config = thresholdConfig[i]
const threshold : SensorThreshold = {
name: config.name,
key: config.key,
min_value: config.min.toString(),
max_value: config.max.toString()
}
thresholdList.push(threshold)
}
thresholds.value = thresholdList
}
async function saveSettings() {
try {
// 构建设置数据
const settingValue = new UTSJSONObject()
settingValue.set('realtime_enabled', settings.value.realtime_enabled)
settingValue.set('auto_backup', settings.value.auto_backup)
settingValue.set('anomaly_detection', settings.value.anomaly_detection)
settingValue.set('ai_analysis', settings.value.ai_analysis)
settingValue.set('notifications', notifications.value)
settingValue.set('data_management', dataManagement.value)
settingValue.set('privacy', privacy.value)
settingValue.set('sensor_frequencies', sensorFrequencies.value)
settingValue.set('thresholds', thresholds.value)
const settingData = new UTSJSONObject()
settingData.set('user_id', userId)
settingData.set('setting_category', 'sensor')
settingData.set('setting_key', 'sensor_config')
settingData.set('setting_value', settingValue)
// 先检查是否已存在记录
const existingResult = await supa.from('ak_user_settings')
.eq('user_id', userId)
.eq('setting_category', 'sensor')
.executeAs<Array<UserSettingsRecord>>()
let result : any
if (existingResult.data !== null && Array.isArray(existingResult.data)) {
const dataArray = existingResult.data as Array<any>
if (dataArray.length > 0) {
// 存在记录,使用 update
const updateData = new UTSJSONObject()
updateData.set('setting_value', settingValue)
updateData.set('updated_at', new Date().toISOString())
result = await supa.from('ak_user_settings')
.eq('user_id', userId)
.eq('setting_category', 'sensor')
.update(updateData)
.execute()
} else {
// 不存在记录,使用 insert
settingData.set('created_at', new Date().toISOString())
settingData.set('updated_at', new Date().toISOString())
result = await supa.from('ak_user_settings')
.insert(settingData)
.execute()
}
} else {
// 不存在记录,使用 insert
settingData.set('created_at', new Date().toISOString())
settingData.set('updated_at', new Date().toISOString())
result = await supa.from('ak_user_settings')
.insert(settingData)
.execute()
}
if (result.error === null) {
uni.showToast({
title: '设置保存成功',
icon: 'success'
})
} else {
console.log('保存设置失败:', result.error)
uni.showToast({
title: '保存失败',
icon: 'error'
})
}
} catch (e) {
console.log('保存设置异常:', e)
uni.showToast({
title: '保存失败',
icon: 'error'
})
}
}
// 事件处理函数
function onRealtimeChange(e : UniSwitchChangeEvent) {
settings.value.realtime_enabled = e.detail.value
}
function onAutoBackupChange(e : UniSwitchChangeEvent) {
settings.value.auto_backup = e.detail.value
}
function onAnomalyDetectionChange(e : UniSwitchChangeEvent) {
settings.value.anomaly_detection = e.detail.value
}
function onAIAnalysisChange(e : UniSwitchChangeEvent) {
settings.value.ai_analysis = e.detail.value
}
function onFrequencyChange(value : number, index : number) {
if (index >= 0 && index < sensorFrequencies.value.length) {
sensorFrequencies.value[index].frequency_index = value
}
}
function onAnomalyAlertChange(e : UniSwitchChangeEvent) {
notifications.value.anomaly_alert = e.detail.value
}
function onDailyReportChange(e : UniSwitchChangeEvent) {
notifications.value.daily_report = e.detail.value
}
function onDeviceOfflineChange(e : UniSwitchChangeEvent) {
notifications.value.device_offline = e.detail.value
}
function onReportTimeChange(value : string) {
notifications.value.report_time = value
}
function onRetentionChange(value : number) {
dataManagement.value.retention_index = value
}
function onCloudSyncChange(e : UniSwitchChangeEvent) {
dataManagement.value.cloud_sync = e.detail.value
}
function onDataCompressionChange(e : UniSwitchChangeEvent) {
dataManagement.value.data_compression = e.detail.value
}
function onDataEncryptionChange(e : UniSwitchChangeEvent) {
privacy.value.data_encryption = e.detail.value
}
function onAnonymousStatsChange(e : UniSwitchChangeEvent) {
privacy.value.anonymous_stats = e.detail.value
}
function onLocationDataChange(e : UniSwitchChangeEvent) {
privacy.value.location_data = e.detail.value
}
function showFrequencyPicker(index : number) {
uni.showActionSheet({
itemList: frequencyOptions,
success: (res) => {
if (res.tapIndex >= 0) {
onFrequencyChange(res.tapIndex, index)
}
}
})
}
function onReportTimeInput(e : UniInputEvent) {
notifications.value.report_time = e.detail.value
}
function showRetentionPicker() {
uni.showActionSheet({
itemList: retentionOptions,
success: (res) => {
if (res.tapIndex >= 0) {
onRetentionChange(res.tapIndex)
}
}
})
}
// 校准相关函数
function startCalibrationProcess(type : string, instruction : string) {
calibrationType.value = type
calibrationInstruction.value = instruction
showCalibration.value = true
calibrationProgress.value = 0
}
function calibrateHeartRate() {
startCalibrationProcess('心率传感器', '请保持静坐放松心情校准过程约需2分钟')
}
function calibrateSteps() {
startCalibrationProcess('步数传感器', '请在平地上正常步行20步保持匀速')
}
function calibrateBloodPressure() {
startCalibrationProcess('血压计', '请使用标准血压计测量,确保袖带位置正确')
}
function calibrateTemperature() {
startCalibrationProcess('体温计', '请使用医用体温计对比校准测量时间需2分钟')
}
function stopCalibration() {
if (calibrationTimer !== 0) {
clearInterval(calibrationTimer)
calibrationTimer = 0
}
calibrationProgress.value = 0
}
function closeCalibration() {
showCalibration.value = false
stopCalibration()
}
function startCalibration() {
calibrationProgress.value = 1
// 模拟校准进度
calibrationTimer = setInterval(() => {
if (calibrationProgress.value < 100) {
calibrationProgress.value += Math.random() * 10
if (calibrationProgress.value > 100) {
calibrationProgress.value = 100
}
} else {
stopCalibration()
uni.showToast({
title: '校准完成',
icon: 'success'
})
closeCalibration()
}
}, 500)
}
// 数据导出
function exportData(format : string) {
uni.showLoading({
title: '准备导出数据...'
})
setTimeout(() => {
uni.hideLoading()
uni.showToast({
title: `${format.toUpperCase()}文件已生成`,
icon: 'success'
})
}, 2000)
}
// 重置功能
function resetSettings() {
uni.showModal({
title: '确认重置',
content: '确定要恢复所有设置到默认状态吗?',
success: (res) => {
if (res.confirm) {
// 重置所有设置到默认值
settings.value.realtime_enabled = true
settings.value.auto_backup = true
settings.value.anomaly_detection = true
settings.value.ai_analysis = false
notifications.value.anomaly_alert = true
notifications.value.daily_report = false
notifications.value.device_offline = true
notifications.value.report_time = '09:00'
dataManagement.value.retention_index = 2
dataManagement.value.cloud_sync = true
dataManagement.value.data_compression = false
privacy.value.data_encryption = true
privacy.value.anonymous_stats = false
privacy.value.location_data = false
initializeSensorFrequencies()
initializeThresholds()
uni.showToast({
title: '设置已重置',
icon: 'success'
})
}
}
})
}
function clearAllData() {
uni.showModal({
title: '危险操作',
content: '确定要清除所有传感器数据吗?此操作不可恢复!',
success: (res) => {
if (res.confirm) {
uni.showToast({
title: '数据清除完成',
icon: 'success'
})
}
}
})
}
function goBack() {
uni.navigateBack()
}
onMounted(() => {
loadSettings()
initializeSensorFrequencies()
initializeThresholds()
})
</script>
<style scoped>
.settings-container {
flex: 1;
padding: 20rpx;
background-color: #f5f5f5;
}
.header {
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
padding: 20rpx;
background-color: #ffffff;
border-radius: 12rpx;
}
.back-btn {
padding: 12rpx;
background-color: #f0f0f0;
border-radius: 8rpx;
border: none;
}
.back-icon {
font-size: 32rpx;
color: #666666;
}
.title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
.save-btn {
padding: 16rpx 24rpx;
background-color: #409EFF;
color: #ffffff;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
}
.section {
margin-bottom: 20rpx;
padding: 24rpx;
background-color: #ffffff;
border-radius: 12rpx;
}
.section-title {
font-size: 30rpx;
font-weight: bold;
color: #333333;
margin-bottom: 20rpx;
}
.setting-item,
.notification-item,
.management-item,
.privacy-item {
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.setting-item:last-child,
.notification-item:last-child,
.management-item:last-child,
.privacy-item:last-child {
border-bottom: none;
}
.setting-label {
font-size: 28rpx;
color: #333333;
}
.frequency-grid {
flex-direction: column;
}
.frequency-item {
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.frequency-item:last-child {
border-bottom: none;
}
.sensor-name {
font-size: 28rpx;
color: #333333;
width: 200rpx;
}
.picker-view {
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 16rpx 20rpx;
background-color: #f8f9fa;
border-radius: 8rpx;
min-width: 200rpx;
}
.picker-button {
background: none;
border: none;
padding: 0;
}
.picker-arrow {
color: #999999;
font-size: 24rpx;
}
.threshold-list {
flex-direction: column;
}
.threshold-item {
margin-bottom: 24rpx;
}
.threshold-label {
font-size: 28rpx;
color: #333333;
margin-bottom: 12rpx;
}
.threshold-inputs {
flex-direction: row;
justify-content: space-between;
}
.input-group {
width: 48%;
}
.input-label {
font-size: 24rpx;
color: #666666;
margin-bottom: 8rpx;
}
.threshold-input {
width: 100%;
padding: 16rpx;
border: 2rpx solid #e0e0e0;
border-radius: 8rpx;
font-size: 28rpx;
}
.calibration-list {
flex-direction: column;
}
.calibration-btn {
padding: 20rpx;
margin-bottom: 16rpx;
background-color: #E6A23C;
color: #ffffff;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
}
.calibration-btn:last-child {
margin-bottom: 0;
}
.export-options {
flex-direction: row;
justify-content: space-around;
}
.export-btn {
flex: 1;
padding: 20rpx;
margin: 0 8rpx;
background-color: #67C23A;
color: #ffffff;
border-radius: 8rpx;
font-size: 26rpx;
border: none;
}
.reset-options {
flex-direction: row;
justify-content: space-around;
}
.reset-btn {
flex: 1;
padding: 20rpx;
margin-right: 16rpx;
background-color: #909399;
color: #ffffff;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
}
.clear-btn {
flex: 1;
padding: 20rpx;
background-color: #F56C6C;
color: #ffffff;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
}
.calibration-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
width: 85%;
background-color: #ffffff;
border-radius: 16rpx;
padding: 32rpx;
}
.modal-header {
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
border-bottom: 2rpx solid #f0f0f0;
padding-bottom: 16rpx;
}
.modal-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
.close-btn {
width: 60rpx;
height: 60rpx;
border-radius: 30rpx;
background-color: #f0f0f0;
color: #666666;
font-size: 36rpx;
border: none;
justify-content: center;
align-items: center;
}
.modal-body {
align-items: center;
}
.calibration-instruction {
font-size: 28rpx;
color: #666666;
line-height: 1.6;
text-align: center;
margin-bottom: 32rpx;
}
.calibration-progress {
width: 100%;
align-items: center;
margin-bottom: 32rpx;
}
.progress-bar {
width: 100%;
height: 16rpx;
background-color: #f0f0f0;
border-radius: 8rpx;
overflow: hidden;
margin-bottom: 12rpx;
}
.progress-fill {
height: 100%;
background-color: #409EFF;
border-radius: 8rpx;
transition: width 0.3s ease;
}
.progress-text {
font-size: 24rpx;
color: #666666;
}
.calibration-actions {
width: 100%;
}
.start-btn,
.stop-btn {
width: 100%;
padding: 24rpx;
border-radius: 12rpx;
font-size: 28rpx;
border: none;
}
.start-btn {
background-color: #67C23A;
color: #ffffff;
}
.stop-btn {
background-color: #F56C6C;
color: #ffffff;
}
.time-input {
padding: 16rpx 20rpx;
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8rpx;
font-size: 28rpx;
color: #333333;
min-width: 200rpx;
text-align: center;
}
</style>