Initial commit of akmon project
This commit is contained in:
834
pages/sport/student/record-detail.uvue
Normal file
834
pages/sport/student/record-detail.uvue
Normal file
@@ -0,0 +1,834 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user