835 lines
19 KiB
Plaintext
835 lines
19 KiB
Plaintext
<template>
|
|
<scroll-view direction="vertical" class="record-detail">
|
|
<!-- Header Card -->
|
|
<view class="header-card">
|
|
<view class="record-header">
|
|
<text class="record-title">{{ getRecordTitle() }}</text>
|
|
<view class="score-badge" :class="`score-${getScoreLevel()}`">
|
|
<text class="score-text">{{ getRecordScore() }}分</text>
|
|
</view>
|
|
</view>
|
|
<text class="record-project">{{ getProjectNameWrapper() }}</text>
|
|
<view class="record-meta">
|
|
<view class="meta-item">
|
|
<text class="meta-icon"></text>
|
|
<text class="meta-text">{{ formatDateWrapper(getRecordDate()) }}</text>
|
|
</view>
|
|
<view class="meta-item">
|
|
<text class="meta-icon">⏱️</text>
|
|
<text class="meta-text">{{ formatDuration(getRecordDuration()) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- Performance Data Card -->
|
|
<view class="performance-card">
|
|
<view class="card-header">
|
|
<text class="card-title">训练数据</text>
|
|
</view>
|
|
<view class="performance-grid"> <view
|
|
class="performance-item"
|
|
v-for="(metric, index) in getPerformanceMetrics()"
|
|
:key="index"
|
|
>
|
|
<view class="metric-icon">
|
|
<text class="icon">{{ getMetricIcon(metric) }}</text>
|
|
</view>
|
|
<view class="metric-content">
|
|
<text class="metric-value">{{ getMetricValue(metric) }}</text>
|
|
<text class="metric-label">{{ getMetricLabel(metric) }}</text>
|
|
<text class="metric-unit">{{ getMetricUnit(metric) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- Technique Analysis Card -->
|
|
<view class="technique-card">
|
|
<view class="card-header">
|
|
<text class="card-title">技术分析</text>
|
|
</view>
|
|
<view class="technique-list"> <view
|
|
class="technique-item"
|
|
v-for="(technique, index) in getTechniqueAnalysis()"
|
|
:key="index"
|
|
>
|
|
<view class="technique-header">
|
|
<text class="technique-name">{{ getTechniqueName(technique) }}</text>
|
|
<view class="rating-stars">
|
|
<text
|
|
class="star"
|
|
v-for="(star, starIndex) in 5"
|
|
:key="starIndex"
|
|
:class="starIndex < getTechniqueRating(technique) ? 'star-filled' : 'star-empty'"
|
|
>
|
|
★
|
|
</text>
|
|
</view>
|
|
</view>
|
|
<text class="technique-comment">{{ getTechniqueComment(technique) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- Improvement Suggestions Card -->
|
|
<view class="suggestions-card">
|
|
<view class="card-header">
|
|
<text class="card-title">改进建议</text>
|
|
</view>
|
|
<view class="suggestions-list"> <view
|
|
class="suggestion-item"
|
|
v-for="(suggestion, index) in getImprovementSuggestions()"
|
|
:key="index"
|
|
>
|
|
<view class="suggestion-icon">
|
|
<text class="icon"></text>
|
|
</view>
|
|
<view class="suggestion-content">
|
|
<text class="suggestion-title">{{ getSuggestionTitle(suggestion) }}</text>
|
|
<text class="suggestion-desc">{{ getSuggestionDescription(suggestion) }}</text>
|
|
<view class="priority-tag" :class="`priority-${getSuggestionPriority(suggestion)}`">
|
|
<text class="priority-text">{{ formatPriority(getSuggestionPriority(suggestion)) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- Teacher Comments Card -->
|
|
<view class="comments-card" v-if="hasTeacherComments()">
|
|
<view class="card-header">
|
|
<text class="card-title">教师点评</text>
|
|
</view>
|
|
<view class="comment-content"> <view class="comment-header">
|
|
<text class="teacher-name">{{ getTeacherName() }}</text>
|
|
<text class="comment-date">{{ formatDateWrapper(getCommentDate()) }}</text>
|
|
</view>
|
|
<text class="comment-text">{{ getTeacherComment() }}</text>
|
|
<view class="comment-rating">
|
|
<text class="rating-label">综合评价:</text>
|
|
<view class="rating-stars">
|
|
<text
|
|
class="star"
|
|
v-for="(star, index) in 5"
|
|
:key="index"
|
|
:class="index < getTeacherRating() ? 'star-filled' : 'star-empty'"
|
|
>
|
|
★
|
|
</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- Action Buttons -->
|
|
<view class="action-buttons">
|
|
<button class="action-btn secondary-btn" @click="viewAssignment">
|
|
查看作业
|
|
</button>
|
|
<button class="action-btn primary-btn" @click="retryTraining">
|
|
重新训练
|
|
</button>
|
|
</view>
|
|
</scroll-view>
|
|
</template>
|
|
|
|
<script setup lang="uts"> import { ref, computed, onMounted, onUnmounted } from 'vue'
|
|
import { onLoad, onResize } from '@dcloudio/uni-app'
|
|
import { getProjectName, formatDate } from '../types.uts'
|
|
|
|
// Reactive data
|
|
const record = ref<UTSJSONObject>({})
|
|
const recordId = ref('')
|
|
const loading = ref(true)
|
|
|
|
// Responsive state - using onResize for dynamic updates
|
|
const screenWidth = ref<number>(uni.getSystemInfoSync().windowWidth)
|
|
|
|
// Computed properties for responsive design
|
|
const isLargeScreen = computed(() : boolean => {
|
|
return screenWidth.value >= 768
|
|
})
|
|
|
|
|
|
// Methods
|
|
function loadRecordDetail() {
|
|
loading.value = true
|
|
|
|
// Mock data - replace with actual API call
|
|
setTimeout(() => {
|
|
record.value = {
|
|
"id": recordId.value,
|
|
"assignment_id": "1",
|
|
"project_name": "跳远训练",
|
|
"date": "2024-01-15T10:30:00",
|
|
"duration": 1800, // 30 minutes in seconds
|
|
"score": 85,
|
|
"performance_data": {
|
|
"distance": { "value": 4.2, "unit": "米", "icon": "" },
|
|
"attempts": { "value": 8, "unit": "次", "icon": "" },
|
|
"best_distance": { "value": 4.5, "unit": "米", "icon": "" },
|
|
"average_distance": { "value": 4.1, "unit": "米", "icon": "" }
|
|
},
|
|
"technique_analysis": [
|
|
{
|
|
"name": "助跑技术",
|
|
"rating": 4,
|
|
"comment": "助跑节奏良好,加速明显,起跳点控制较准确"
|
|
},
|
|
{
|
|
"name": "起跳技术",
|
|
"rating": 3,
|
|
"comment": "起跳时机把握较好,但起跳角度需要调整"
|
|
},
|
|
{
|
|
"name": "空中姿态",
|
|
"rating": 4,
|
|
"comment": "空中姿态保持良好,腿部动作协调"
|
|
},
|
|
{
|
|
"name": "落地技术",
|
|
"rating": 5,
|
|
"comment": "落地缓冲充分,姿态标准"
|
|
}
|
|
],
|
|
"improvement_suggestions": [
|
|
{
|
|
"title": "起跳角度调整",
|
|
"description": "适当增加起跳角度,有助于提高跳跃距离",
|
|
"priority": "high"
|
|
},
|
|
{
|
|
"title": "助跑速度控制",
|
|
"description": "在保证准确性的前提下,可以适当提高助跑速度",
|
|
"priority": "medium"
|
|
},
|
|
{
|
|
"title": "力量训练加强",
|
|
"description": "建议增加腿部力量训练,提高爆发力",
|
|
"priority": "low"
|
|
}
|
|
],
|
|
"teacher_comment": {
|
|
"teacher_name": "张老师",
|
|
"comment": "整体表现不错,技术动作比较标准。建议在起跳技术上多加练习,同时注意助跑与起跳的衔接。继续保持!",
|
|
"rating": 4,
|
|
"date": "2024-01-15T15:30:00"
|
|
}
|
|
} as UTSJSONObject
|
|
loading.value = false
|
|
}, 1000)
|
|
}
|
|
|
|
|
|
function getRecordDate(): string {
|
|
return record.value.getString('date') ?? ''
|
|
}
|
|
|
|
function getRecordDuration(): number {
|
|
return record.value.getNumber('duration') ?? 0
|
|
}
|
|
|
|
function getRecordScore(): number {
|
|
return record.value.getNumber('score') ?? 0
|
|
}
|
|
|
|
function getScoreLevel(): string {
|
|
const score = getRecordScore()
|
|
if (score >= 90) return 'excellent'
|
|
if (score >= 80) return 'good'
|
|
if (score >= 70) return 'fair'
|
|
return 'poor'
|
|
}
|
|
|
|
function formatDuration(seconds: number): string {
|
|
const minutes = Math.floor(seconds / 60)
|
|
const remainingSeconds = seconds % 60
|
|
return `${minutes}分${remainingSeconds}秒`
|
|
}
|
|
function getPerformanceMetrics(): Array<any> {
|
|
const data = record.value.getAny('performance_data') as UTSJSONObject ?? {}
|
|
const metrics: Array<any> = []
|
|
|
|
const keys = ['distance', 'attempts', 'best_distance', 'average_distance']
|
|
const labels = ['最终距离', '训练次数', '最好成绩', '平均距离']
|
|
|
|
keys.forEach((key, index) => {
|
|
const metric = (data as UTSJSONObject).getAny(key) as UTSJSONObject
|
|
if (metric !== null) {
|
|
metrics.push({
|
|
icon: metric.getString('icon') ?? '',
|
|
value: metric.getNumber('value') ?? 0,
|
|
unit: metric.getString('unit') ?? '',
|
|
label: labels[index]
|
|
})
|
|
}
|
|
})
|
|
|
|
return metrics
|
|
}
|
|
function getTechniqueAnalysis(): Array<any> {
|
|
const analysis = record.value.getArray('technique_analysis') ?? ([] as Array<any>)
|
|
if (analysis instanceof Array) {
|
|
return analysis as Array<any>
|
|
}
|
|
return []
|
|
}
|
|
function getImprovementSuggestions(): Array<any> {
|
|
const suggestions = record.value.getArray('improvement_suggestions') ?? ([] as Array<any>)
|
|
if (suggestions instanceof Array) {
|
|
return suggestions as Array<any>
|
|
}
|
|
return []
|
|
}
|
|
|
|
function formatPriority(priority: string): string {
|
|
const priorityMap = {
|
|
'high': '高优先级',
|
|
'medium': '中优先级',
|
|
'low': '低优先级'
|
|
} as UTSJSONObject
|
|
return priorityMap.getString(priority) ?? priority
|
|
}
|
|
function hasTeacherComments(): boolean {
|
|
const comment = record.value.getAny('teacher_comment')
|
|
return comment !== null
|
|
}
|
|
|
|
function getTeacherName(): string {
|
|
const comment = record.value.getAny('teacher_comment') as UTSJSONObject ?? {}
|
|
return (comment as UTSJSONObject).getString('teacher_name') ?? ''
|
|
}
|
|
|
|
function getTeacherComment(): string {
|
|
const comment = record.value.getAny('teacher_comment') as UTSJSONObject ?? {}
|
|
return (comment as UTSJSONObject).getString('comment') ?? ''
|
|
}
|
|
|
|
function getTeacherRating(): number {
|
|
const comment = record.value.getAny('teacher_comment') as UTSJSONObject ?? {}
|
|
return (comment as UTSJSONObject).getNumber('rating') ?? 0
|
|
}
|
|
|
|
function getCommentDate(): string {
|
|
const comment = record.value.getAny('teacher_comment') as UTSJSONObject ?? {}
|
|
return (comment as UTSJSONObject).getString('date') ?? ''
|
|
} function viewAssignment() {
|
|
const assignmentId = record.value.getString('assignment_id') ?? ''
|
|
if (assignmentId.length > 0) {
|
|
uni.navigateTo({
|
|
url: `/pages/sport/student/assignment-detail?id=${assignmentId}`
|
|
})
|
|
}
|
|
}
|
|
function retryTraining() {
|
|
const assignmentId = record.value.getString('assignment_id') ?? ''
|
|
if (assignmentId.length > 0) {
|
|
uni.navigateTo({
|
|
url: `/pages/sport/student/training-record?assignmentId=${assignmentId}`
|
|
})
|
|
}
|
|
} // Template wrapper functions for safe property access
|
|
function getMetricIcon(metric: any): string {
|
|
if (metric != null && typeof metric === 'object') {
|
|
const obj = metric as UTSJSONObject
|
|
return obj.getString('icon') ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function getMetricValue(metric: any): number {
|
|
if (metric != null && typeof metric === 'object') {
|
|
const obj = metric as UTSJSONObject
|
|
return obj.getNumber('value') ?? 0
|
|
}
|
|
return 0
|
|
}
|
|
|
|
function getMetricLabel(metric: any): string {
|
|
if (metric != null && typeof metric === 'object') {
|
|
const obj = metric as UTSJSONObject
|
|
return obj.getString('label') ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function getMetricUnit(metric: any): string {
|
|
if (metric != null && typeof metric === 'object') {
|
|
const obj = metric as UTSJSONObject
|
|
return obj.getString('unit') ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function getTechniqueName(technique: any): string {
|
|
if (technique != null && typeof technique === 'object') {
|
|
const obj = technique as UTSJSONObject
|
|
return obj.getString('name') ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function getTechniqueRating(technique: any): number {
|
|
if (technique != null && typeof technique === 'object') {
|
|
const obj = technique as UTSJSONObject
|
|
return obj.getNumber('rating') ?? 0
|
|
}
|
|
return 0
|
|
}
|
|
|
|
function getTechniqueComment(technique: any): string {
|
|
if (technique != null && typeof technique === 'object') {
|
|
const obj = technique as UTSJSONObject
|
|
return obj.getString('comment') ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function getSuggestionTitle(suggestion: any): string {
|
|
if (suggestion != null && typeof suggestion === 'object') {
|
|
const obj = suggestion as UTSJSONObject
|
|
return obj.getString('title') ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function getSuggestionDescription(suggestion: any): string {
|
|
if (suggestion != null && typeof suggestion === 'object') {
|
|
const obj = suggestion as UTSJSONObject
|
|
return obj.getString('description') ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function getSuggestionPriority(suggestion: any): string {
|
|
if (suggestion != null && typeof suggestion === 'object') {
|
|
const obj = suggestion as UTSJSONObject
|
|
return obj.getString('priority') ?? ''
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function getProjectNameWrapper(): string {
|
|
return getProjectName(record.value)
|
|
}
|
|
|
|
function formatDateWrapper(dateStr: string): string {
|
|
return formatDate(dateStr)
|
|
}
|
|
|
|
function getRecordTitle(): string {
|
|
const date = getRecordDate()
|
|
return `训练记录 - ${formatDateWrapper(date)}`
|
|
} // Lifecycle
|
|
onLoad((options: OnLoadOptions) => {
|
|
recordId.value = options['id'] ?? ''
|
|
loadRecordDetail()
|
|
})
|
|
|
|
onMounted(() => {
|
|
screenWidth.value = uni.getSystemInfoSync().windowWidth
|
|
})
|
|
|
|
onResize((size) => {
|
|
screenWidth.value = size.size.windowWidth
|
|
})
|
|
|
|
</script>
|
|
|
|
<style>
|
|
.record-detail {
|
|
display: flex;
|
|
flex:1;
|
|
background-color: #f5f5f5;
|
|
min-height: 100vh;
|
|
padding: 20rpx;
|
|
}
|
|
|
|
/* Header Card */
|
|
.header-card {
|
|
background: linear-gradient(to bottom right, #667eea, #764ba2);
|
|
border-radius: 20rpx;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
color: white;
|
|
}
|
|
|
|
.record-header {
|
|
display: flex;
|
|
flex-direction:row;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15rpx;
|
|
}
|
|
|
|
.record-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
flex: 1;
|
|
}
|
|
|
|
.score-badge {
|
|
padding: 8rpx 16rpx;
|
|
border-radius: 16rpx;
|
|
margin-left: 20rpx;
|
|
}
|
|
|
|
.score-excellent {
|
|
background-color: rgba(40, 167, 69, 0.3);
|
|
border: 1px solid rgba(40, 167, 69, 0.6);
|
|
}
|
|
|
|
.score-good {
|
|
background-color: rgba(0, 123, 255, 0.3);
|
|
border: 1px solid rgba(0, 123, 255, 0.6);
|
|
}
|
|
|
|
.score-fair {
|
|
background-color: rgba(255, 193, 7, 0.3);
|
|
border: 1px solid rgba(255, 193, 7, 0.6);
|
|
}
|
|
|
|
.score-poor {
|
|
background-color: rgba(220, 53, 69, 0.3);
|
|
border: 1px solid rgba(220, 53, 69, 0.6);
|
|
}
|
|
|
|
.score-text {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: white;
|
|
}
|
|
|
|
.record-project {
|
|
font-size: 28rpx;
|
|
opacity: 0.9;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.record-meta {
|
|
display: flex;
|
|
flex-direction:row;
|
|
gap: 30rpx;
|
|
}
|
|
|
|
.meta-item {
|
|
display: flex;
|
|
flex-direction:row;
|
|
|
|
align-items: center;
|
|
}
|
|
|
|
.meta-icon {
|
|
font-size: 24rpx;
|
|
margin-right: 8rpx;
|
|
}
|
|
|
|
.meta-text {
|
|
font-size: 26rpx;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* Performance Card */
|
|
.performance-card {
|
|
background-color: white;
|
|
border-radius: 20rpx;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
box-shadow: 0 2rpx 20rpx rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.card-header {
|
|
margin-bottom: 25rpx;
|
|
}
|
|
|
|
.card-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
.performance-grid {
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
margin: 0 -10rpx;
|
|
} .performance-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 20rpx;
|
|
background-color: #f8f9ff;
|
|
border-radius: 16rpx;
|
|
width: 44%;
|
|
flex: 0 0 44%;
|
|
margin: 0 10rpx 20rpx;
|
|
}
|
|
|
|
.metric-icon {
|
|
width: 60rpx;
|
|
height: 60rpx;
|
|
border-radius: 30rpx;
|
|
background-color: #667eea;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 15rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.icon {
|
|
font-size: 28rpx;
|
|
color: white;
|
|
}
|
|
|
|
.metric-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.metric-value {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
display: block;
|
|
margin-bottom: 2rpx;
|
|
}
|
|
|
|
.metric-label {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
display: block;
|
|
}
|
|
|
|
.metric-unit {
|
|
font-size: 20rpx;
|
|
color: #999;
|
|
}
|
|
|
|
/* Technique Card */
|
|
.technique-card {
|
|
background-color: white;
|
|
border-radius: 20rpx;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
box-shadow: 0 2rpx 20rpx rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.technique-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.technique-item {
|
|
padding: 20rpx;
|
|
background-color: #fafafa;
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.technique-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 10rpx;
|
|
}
|
|
|
|
.technique-name {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.rating-stars {
|
|
display: flex;
|
|
flex-direction:row;
|
|
}
|
|
|
|
.star {
|
|
font-size: 24rpx;
|
|
margin-left: 2rpx;
|
|
}
|
|
|
|
.star-filled {
|
|
color: #ffc107;
|
|
}
|
|
|
|
.star-empty {
|
|
color: #ddd;
|
|
}
|
|
|
|
.technique-comment {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* Suggestions Card */
|
|
.suggestions-card {
|
|
background-color: white;
|
|
border-radius: 20rpx;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
box-shadow: 0 2rpx 20rpx rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.suggestions-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.suggestion-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
padding: 20rpx;
|
|
background-color: #fff8e1;
|
|
border-radius: 12rpx;
|
|
border-left: 4rpx solid #ffc107;
|
|
}
|
|
|
|
.suggestion-icon {
|
|
width: 50rpx;
|
|
height: 50rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 15rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.suggestion-content {
|
|
flex: 1;
|
|
position: relative;
|
|
}
|
|
|
|
.suggestion-title {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
margin-bottom: 8rpx;
|
|
display: block;
|
|
}
|
|
|
|
.suggestion-desc {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
line-height: 1.5;
|
|
margin-bottom: 10rpx;
|
|
}
|
|
|
|
.priority-tag {
|
|
display: inline-block;
|
|
padding: 4rpx 12rpx;
|
|
border-radius: 8rpx;
|
|
font-size: 22rpx;
|
|
}
|
|
|
|
.priority-high {
|
|
background-color: rgba(220, 53, 69, 0.1);
|
|
color: #dc3545;
|
|
}
|
|
|
|
.priority-medium {
|
|
background-color: rgba(255, 193, 7, 0.1);
|
|
color: #ffc107;
|
|
}
|
|
|
|
.priority-low {
|
|
background-color: rgba(40, 167, 69, 0.1);
|
|
color: #28a745;
|
|
}
|
|
|
|
.priority-text {
|
|
font-weight: 400;
|
|
}
|
|
|
|
/* Comments Card */
|
|
.comments-card {
|
|
background-color: white;
|
|
border-radius: 20rpx;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
box-shadow: 0 2rpx 20rpx rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.comment-content {
|
|
background-color: #f8f9ff;
|
|
padding: 25rpx;
|
|
border-radius: 16rpx;
|
|
border-left: 4rpx solid #667eea;
|
|
}
|
|
|
|
.comment-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15rpx;
|
|
}
|
|
|
|
.teacher-name {
|
|
font-size: 26rpx;
|
|
font-weight: bold;
|
|
color: #667eea;
|
|
}
|
|
|
|
.comment-date {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
|
|
.comment-text {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
line-height: 1.6;
|
|
margin-bottom: 15rpx;
|
|
}
|
|
|
|
.comment-rating {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.rating-label {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
margin-right: 15rpx;
|
|
}
|
|
|
|
/* Action Buttons */
|
|
.action-buttons {
|
|
padding: 20rpx 0;
|
|
display: flex;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
height: 88rpx;
|
|
border-radius: 44rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
border: none;
|
|
}
|
|
|
|
.primary-btn {
|
|
background: linear-gradient(to bottom right, #667eea, #764ba2);
|
|
color: white;
|
|
}
|
|
|
|
.secondary-btn {
|
|
background-color: white;
|
|
color: #667eea;
|
|
border: 2rpx solid #667eea;
|
|
}
|
|
|
|
.primary-btn:active {
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
.secondary-btn:active {
|
|
transform: scale(0.98);
|
|
background-color: #f8f9ff;
|
|
}
|
|
</style>
|