diff --git a/app.json b/app.json
index 8bded97..47e22b0 100644
--- a/app.json
+++ b/app.json
@@ -7,11 +7,11 @@
"pages/defaults/index"
],
"window": {
- "navigationBarBackgroundColor": "#F4F8FE",
+ "navigationBarBackgroundColor": "#F4F7FB",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "教学反馈助手",
- "backgroundColor": "#F4F8FE",
- "backgroundTextStyle": "light"
+ "backgroundColor": "#F4F7FB",
+ "backgroundTextStyle": "dark"
},
"permission": {
"scope.record": {
@@ -20,9 +20,9 @@
},
"tabBar": {
"custom": true,
- "color": "#7B8796",
- "selectedColor": "#2B67E8",
- "backgroundColor": "#FFFFFF",
+ "color": "#8E8E93",
+ "selectedColor": "#007AFF",
+ "backgroundColor": "#F8FAFC",
"borderStyle": "white",
"list": [
{ "pagePath": "pages/feedback/index", "text": "反馈生成" },
diff --git a/app.wxss b/app.wxss
index d42a395..cf43bdb 100644
--- a/app.wxss
+++ b/app.wxss
@@ -1,15 +1,18 @@
page {
min-height: 100%;
box-sizing: border-box;
- background: #f4f8fe;
- color: #17233a;
+ background: #f4f7fb;
+ color: #1c1c1e;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
view,
text,
input,
-button {
+button,
+textarea,
+picker,
+scroll-view {
box-sizing: border-box;
}
@@ -19,50 +22,42 @@ button::after {
.page-shell {
min-height: 100vh;
- padding: 40rpx 32rpx 164rpx;
+ padding: 44rpx 32rpx 184rpx;
}
.eyebrow {
- color: #2b67e8;
- font-size: 28rpx;
+ color: #007aff;
+ font-size: 26rpx;
font-weight: 700;
- line-height: 1.4;
+ line-height: 1.35;
}
.page-heading {
display: flex;
align-items: center;
- gap: 14rpx;
- margin-top: 12rpx;
-}
-
-.heading-icon {
- color: #2b67e8;
- font-size: 46rpx;
- font-weight: 500;
- line-height: 1;
+ margin-top: 10rpx;
}
.page-title {
- color: #111b32;
- font-size: 52rpx;
+ color: #1c1c1e;
+ font-size: 50rpx;
font-weight: 800;
- line-height: 1.2;
+ line-height: 1.15;
}
.page-subtitle {
- margin-top: 18rpx;
- color: #718096;
- font-size: 30rpx;
- line-height: 1.55;
+ margin-top: 16rpx;
+ color: #6e6e73;
+ font-size: 28rpx;
+ line-height: 1.5;
}
.surface {
overflow: hidden;
- border: 2rpx solid #d7e5f4;
+ border: 1rpx solid #e5e5ea;
border-radius: 16rpx;
background: #ffffff;
- box-shadow: 0 8rpx 22rpx rgba(45, 78, 120, 0.08);
+ box-shadow: 0 4rpx 18rpx rgba(60, 60, 67, 0.06);
}
.primary-button,
@@ -76,19 +71,40 @@ button::after {
font-size: 30rpx;
font-weight: 700;
line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+ transform-origin: center;
}
.primary-button {
- border: 2rpx solid #2b67e8;
- background: #2b67e8;
+ border: 0;
+ background: #007aff;
color: #ffffff;
}
.secondary-button,
.icon-button {
- border: 2rpx solid #c9dced;
+ border: 1rpx solid #d1d1d6;
background: #ffffff;
- color: #2b67e8;
+ color: #007aff;
+}
+
+.primary-button:active,
+.secondary-button:active,
+.icon-button:active {
+ transform: scale(0.98);
+}
+
+.primary-button:active {
+ background: #006ee6;
+}
+
+.secondary-button:active,
+.icon-button:active {
+ background: #f2f7ff;
+}
+
+button[disabled]:active {
+ transform: none;
}
.button-icon {
@@ -98,21 +114,21 @@ button::after {
}
.helper-text {
- color: #7b8796;
+ color: #6e6e73;
font-size: 26rpx;
line-height: 1.55;
}
.field-label {
- color: #2b67e8;
- font-size: 28rpx;
+ color: #6e6e73;
+ font-size: 26rpx;
font-weight: 700;
}
.field-value {
- margin-top: 18rpx;
- color: #17233a;
- font-size: 32rpx;
+ margin-top: 14rpx;
+ color: #1c1c1e;
+ font-size: 30rpx;
font-weight: 700;
}
@@ -123,9 +139,9 @@ button::after {
gap: 20rpx;
margin-top: 24rpx;
padding: 20rpx 22rpx;
- border: 2rpx solid #efc7c7;
+ border: 1rpx solid #f1c4c4;
border-radius: 12rpx;
- background: #fff7f7;
+ background: #fff2f2;
color: #a83d3d;
font-size: 25rpx;
line-height: 1.45;
@@ -133,13 +149,27 @@ button::after {
.status-action {
flex: none;
- color: #2b67e8;
+ color: #007aff;
font-weight: 700;
}
.loading-state {
padding: 70rpx 32rpx;
- color: #718096;
+ color: #6e6e73;
font-size: 28rpx;
text-align: center;
}
+
+@media (prefers-reduced-motion: reduce) {
+ .primary-button,
+ .secondary-button,
+ .icon-button {
+ transition: none;
+ }
+
+ .primary-button:active,
+ .secondary-button:active,
+ .icon-button:active {
+ transform: none;
+ }
+}
diff --git a/custom-tab-bar/index.wxss b/custom-tab-bar/index.wxss
index 3a03f73..6b09d89 100644
--- a/custom-tab-bar/index.wxss
+++ b/custom-tab-bar/index.wxss
@@ -7,8 +7,10 @@
display: flex;
min-height: 112rpx;
padding-bottom: env(safe-area-inset-bottom);
- border-top: 1rpx solid #edf1f6;
- background: #ffffff;
+ border-top: 1rpx solid rgba(209, 209, 214, 0.72);
+ background: rgba(248, 250, 252, 0.92);
+ -webkit-backdrop-filter: blur(24rpx) saturate(180%);
+ backdrop-filter: blur(24rpx) saturate(180%);
}
.tab-item {
@@ -19,11 +21,17 @@
justify-content: center;
gap: 6rpx;
min-height: 112rpx;
- color: #8995a5;
+ color: #8e8e93;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+ transform-origin: center;
}
.tab-item-active {
- color: #2b67e8;
+ color: #007aff;
+}
+
+.tab-item:active {
+ transform: scale(0.96);
}
.tab-glyph {
@@ -36,3 +44,21 @@
font-size: 24rpx;
line-height: 1.2;
}
+
+@media (prefers-reduced-motion: reduce) {
+ .tab-item {
+ transition: none;
+ }
+
+ .tab-item:active {
+ transform: none;
+ }
+}
+
+@media (prefers-reduced-transparency: reduce) {
+ .tabbar {
+ background: #f8fafc;
+ -webkit-backdrop-filter: none;
+ backdrop-filter: none;
+ }
+}
diff --git a/pages/defaults/index.json b/pages/defaults/index.json
index 02d30dd..879fa2e 100644
--- a/pages/defaults/index.json
+++ b/pages/defaults/index.json
@@ -1,3 +1,3 @@
{
- "navigationBarTitleText": "学生档案预设项"
+ "navigationBarTitleText": "设置预设项"
}
diff --git a/pages/defaults/index.ts b/pages/defaults/index.ts
index 5b01e18..93ac5d6 100644
--- a/pages/defaults/index.ts
+++ b/pages/defaults/index.ts
@@ -3,6 +3,10 @@ import type { StudentProfileDefaults } from '../../utils/types'
const grades = ['初一', '初二', '初三']
const subjects = ['美术', '书法', '音乐', '舞蹈', '语文', '数学', '英语']
+const durationPresets = [45, 60, 90, 120]
+const durationStep = 15
+const minimumDuration = 15
+const maximumDuration = 360
const initialDefaults: StudentProfileDefaults = {
grade: '初一',
subject: '数学',
@@ -10,11 +14,10 @@ const initialDefaults: StudentProfileDefaults = {
}
type PickerEvent = { detail: { value: string | number } }
-type InputEvent = { detail: { value: string } }
function normalizeDuration(value: number): number {
if (Number.isNaN(value)) return 60
- return Math.min(360, Math.max(15, Math.round(value / 15) * 15))
+ return Math.min(maximumDuration, Math.max(minimumDuration, Math.round(value / durationStep) * durationStep))
}
Page({
@@ -22,6 +25,9 @@ Page({
defaults: initialDefaults,
grades,
subjects,
+ durationPresets,
+ minimumDuration,
+ maximumDuration,
loading: false,
saving: false,
errorMessage: ''
@@ -34,7 +40,13 @@ Page({
async loadDefaults(showSuccess = false) {
this.setData({ loading: true, errorMessage: '' })
try {
- this.setData({ defaults: await getProfileDefaults() })
+ const defaults = await getProfileDefaults()
+ this.setData({
+ defaults: {
+ ...defaults,
+ lessonDurationMinutes: normalizeDuration(defaults.lessonDurationMinutes)
+ }
+ })
if (showSuccess) wx.showToast({ title: '预设已刷新', icon: 'success' })
} catch (error) {
this.setData({ errorMessage: getApiErrorMessage(error) })
@@ -55,12 +67,25 @@ Page({
this.setData({ 'defaults.subject': subjects[Number(event.detail.value)] })
},
- onDurationInput(event: InputEvent) {
- this.setData({ 'defaults.lessonDurationMinutes': normalizeDuration(Number(event.detail.value)) })
+ decreaseDuration() {
+ this.setData({
+ 'defaults.lessonDurationMinutes': normalizeDuration(
+ this.data.defaults.lessonDurationMinutes - durationStep
+ )
+ })
},
- onDurationChange(event: PickerEvent) {
- this.setData({ 'defaults.lessonDurationMinutes': normalizeDuration(Number(event.detail.value)) })
+ increaseDuration() {
+ this.setData({
+ 'defaults.lessonDurationMinutes': normalizeDuration(
+ this.data.defaults.lessonDurationMinutes + durationStep
+ )
+ })
+ },
+
+ selectDurationPreset(event: WechatMiniprogram.TouchEvent) {
+ const { value } = event.currentTarget.dataset as { value: number | string }
+ this.setData({ 'defaults.lessonDurationMinutes': normalizeDuration(Number(value)) })
},
async save() {
diff --git a/pages/defaults/index.wxml b/pages/defaults/index.wxml
index 2c317af..6191c45 100644
--- a/pages/defaults/index.wxml
+++ b/pages/defaults/index.wxml
@@ -3,12 +3,13 @@
档案预设
- +
- 学生档案预设项
+ 新增学生默认值
- 用于新增学生时自动带出
+ 新增学生时自动带出以下信息
-
+
@@ -18,41 +19,70 @@
-
- 年级
- {{defaults.grade}}
+
+
+
+ 年级
+ {{defaults.grade}}
+
+ ›
+
-
- 学科
- {{defaults.subject}}
+
+
+
+ 学科
+ {{defaults.subject}}
+
+ ›
+
- 上课时长
-
-
- 分钟
+
+ 上课时长
+ 15 分钟间隔
-
-
- 15 分钟
- 360 分钟
+
+
+
+
+ {{defaults.lessonDurationMinutes}}
+ 分钟
+
+
+
+
+
+
- 新增学生时会按开始时间自动推算结束时间。
-
+
+
+ 新增学生时会根据开始时间自动推算结束时间
+
+
+
+
diff --git a/pages/defaults/index.wxss b/pages/defaults/index.wxss
index 8cb586c..4ac2562 100644
--- a/pages/defaults/index.wxss
+++ b/pages/defaults/index.wxss
@@ -1,5 +1,5 @@
.defaults-page {
- padding-top: 38rpx;
+ padding-top: 44rpx;
}
.top-row {
@@ -27,93 +27,287 @@
}
.reload-button {
+ display: flex;
flex: none;
- width: 148rpx;
- min-width: 148rpx;
- max-width: 148rpx;
- min-height: 70rpx;
+ align-items: center;
+ justify-content: center;
+ width: 72rpx;
+ min-width: 72rpx;
+ max-width: 72rpx;
+ height: 72rpx;
margin: 0;
padding: 0;
- font-size: 26rpx;
+ border: 0;
+ border-radius: 50%;
+ background: #f1f3f6;
+ color: #007aff;
+ line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.reload-button:active {
+ transform: scale(0.94);
+ background: #e5e5ea;
+}
+
+.reload-button[disabled] {
+ opacity: 1;
+}
+
+.reload-icon {
+ display: block;
+ font-size: 36rpx;
+ line-height: 1;
+}
+
+.reload-button-loading .reload-icon {
+ animation: reload-spin 800ms linear infinite;
+}
+
+@keyframes reload-spin {
+ to {
+ transform: rotate(360deg);
+ }
}
.defaults-card {
- margin-top: 34rpx;
- padding: 24rpx;
+ margin-top: 28rpx;
+ padding: 0;
}
.defaults-grid {
display: flex;
- gap: 16rpx;
+ gap: 0;
}
.defaults-grid .select-field {
- width: calc((100% - 16rpx) / 2);
+ width: 50%;
}
.select-field,
.duration-field {
- padding: 24rpx;
- border: 2rpx solid #d8e5f2;
- border-radius: 14rpx;
- background: #fbfdff;
+ background: transparent;
}
.select-field {
- min-height: 158rpx;
+ min-height: 112rpx;
+ transition: opacity 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.select-field-content {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 14rpx;
+ min-height: 112rpx;
+ padding: 18rpx 20rpx;
+}
+
+.select-field + .select-field {
+ border-left: 1rpx solid #e5e5ea;
+}
+
+.select-field:active {
+ opacity: 0.68;
+}
+
+.select-copy {
+ min-width: 0;
+}
+
+.select-field .field-label,
+.select-field .field-value {
+ display: block;
+}
+
+.select-field .field-label {
+ color: #6e6e73;
+ font-size: 22rpx;
+ line-height: 1.25;
+}
+
+.select-field .field-value {
+ margin-top: 7rpx;
+ color: #1c1c1e;
+ font-size: 29rpx;
+ font-weight: 700;
+ line-height: 1.25;
+}
+
+.select-chevron {
+ flex: none;
+ color: #8e8e93;
+ font-size: 36rpx;
+ line-height: 1;
}
.duration-field {
- margin-top: 16rpx;
+ padding: 24rpx;
+ border-top: 1rpx solid #e5e5ea;
}
-.duration-input-row {
+.duration-heading {
display: flex;
align-items: center;
- gap: 12rpx;
- margin-top: 20rpx;
+ justify-content: space-between;
+ gap: 16rpx;
}
-.duration-input {
- width: 150rpx;
- height: 64rpx;
- padding: 0 16rpx;
- border: 2rpx solid #bed4e8;
- border-radius: 12rpx;
- background: #ffffff;
- color: #17233a;
+.duration-step-label {
+ color: #8e8e93;
+ font-size: 22rpx;
+}
+
+.duration-stepper {
+ display: grid;
+ grid-template-columns: 72rpx minmax(0, 1fr) 72rpx;
+ width: 330rpx;
+ height: 76rpx;
+ margin: 18rpx auto 0;
+ overflow: hidden;
+ border: 1rpx solid #e5e5ea;
+ border-radius: 14rpx;
+ background: #f1f3f6;
+}
+
+.duration-step-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 72rpx;
+ min-width: 72rpx;
+ max-width: 72rpx;
+ height: 76rpx;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ border-radius: 0;
+ background: transparent;
+ color: #007aff;
font-size: 38rpx;
+ font-weight: 500;
+ line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.duration-step-button:active {
+ transform: scale(0.9);
+}
+
+.duration-step-button[disabled] {
+ color: #c7c7cc;
+ opacity: 1;
+}
+
+.duration-value {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8rpx;
+ min-width: 0;
+ border-right: 1rpx solid #d1d1d6;
+ border-left: 1rpx solid #d1d1d6;
+}
+
+.duration-number {
+ color: #1c1c1e;
+ font-size: 34rpx;
font-weight: 800;
- text-align: center;
+ line-height: 1;
}
.duration-unit {
- color: #65758a;
- font-size: 28rpx;
+ color: #6e6e73;
+ font-size: 22rpx;
}
-.duration-slider {
- margin: 12rpx -12rpx 0;
-}
-
-.duration-bounds {
+.duration-presets {
display: flex;
- justify-content: space-between;
- color: #8a97a6;
- font-size: 23rpx;
+ align-items: stretch;
+ gap: 4rpx;
+ margin-top: 18rpx;
+ padding: 4rpx;
+ border-radius: 12rpx;
+ background: #f1f3f6;
+}
+
+.duration-preset {
+ display: flex;
+ flex: 1 1 0;
+ align-items: center;
+ justify-content: center;
+ width: 0;
+ min-width: 0;
+ max-width: none;
+ min-height: 58rpx;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ border-radius: 9rpx;
+ background: transparent;
+ color: #6e6e73;
+ font-size: 24rpx;
+ font-weight: 600;
+ line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.duration-preset-active {
+ background: #ffffff;
+ box-shadow: 0 2rpx 8rpx rgba(60, 60, 67, 0.12);
+ color: #007aff;
+}
+
+.duration-preset:active {
+ transform: scale(0.96);
}
.time-help {
- margin-top: 18rpx;
- padding: 20rpx;
- border: 2rpx dashed #c6ddea;
- border-radius: 12rpx;
- color: #65758a;
- font-size: 25rpx;
+ display: flex;
+ align-items: flex-start;
+ gap: 10rpx;
+ margin: 0 24rpx;
+ padding: 2rpx 0 0;
+ color: #6e6e73;
+ font-size: 24rpx;
line-height: 1.5;
}
-.save-defaults {
- width: 420rpx;
- margin: 26rpx auto 4rpx;
+.time-help-icon {
+ flex: none;
+ margin-top: 3rpx;
+}
+
+.save-area {
+ padding: 24rpx;
+}
+
+.save-defaults {
+ width: 100%;
+ min-width: 0;
+ max-width: none;
+ margin: 0;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .reload-button,
+ .select-field,
+ .duration-step-button,
+ .duration-preset {
+ transition: none;
+ }
+
+ .reload-button:active,
+ .duration-step-button:active,
+ .duration-preset:active {
+ transform: none;
+ }
+
+ .select-field:active {
+ opacity: 1;
+ }
+
+ .reload-button-loading .reload-icon {
+ animation: none;
+ }
}
diff --git a/pages/feedback/index.wxml b/pages/feedback/index.wxml
index 1b81878..1550255 100644
--- a/pages/feedback/index.wxml
+++ b/pages/feedback/index.wxml
@@ -1,7 +1,6 @@
课堂反馈
- ✦
反馈生成
填写课堂表现并保存到教学反馈记录。
diff --git a/pages/feedback/index.wxss b/pages/feedback/index.wxss
index be68c21..df9147e 100644
--- a/pages/feedback/index.wxss
+++ b/pages/feedback/index.wxss
@@ -1,23 +1,34 @@
.feedback-page {
- padding-top: 44rpx;
+ padding-top: 48rpx;
}
.feedback-form {
- margin-top: 32rpx;
- padding: 24rpx;
+ margin-top: 30rpx;
+ padding: 0;
}
.feedback-field,
.content-field {
- padding: 22rpx;
- border: 2rpx solid #d8e5f2;
- border-radius: 14rpx;
- background: #fbfdff;
+ padding: 24rpx;
+ background: transparent;
+}
+
+.feedback-field .form-label,
+.feedback-field .form-value {
+ display: block;
+}
+
+.feedback-field .form-value {
+ margin-top: 10rpx;
+ color: #1c1c1e;
+ font-size: 30rpx;
+ line-height: 1.35;
}
.feedback-field + .feedback-field,
.content-field {
- margin-top: 16rpx;
+ margin-top: 0;
+ border-top: 1rpx solid #e5e5ea;
}
.content-label-row,
@@ -29,45 +40,51 @@
}
.content-count {
- color: #8a97a6;
+ color: #8e8e93;
font-size: 23rpx;
}
.feedback-textarea {
width: 100%;
- min-height: 300rpx;
- margin-top: 18rpx;
- color: #17233a;
- font-size: 29rpx;
- line-height: 1.6;
+ min-height: 280rpx;
+ margin-top: 16rpx;
+ padding: 18rpx;
+ border-radius: 12rpx;
+ background: #f1f3f6;
+ color: #1c1c1e;
+ font-size: 28rpx;
+ line-height: 1.65;
}
.voice-input-row {
display: flex;
flex-direction: column;
align-items: stretch;
- gap: 14rpx;
- margin-top: 18rpx;
- padding-top: 18rpx;
- border-top: 2rpx solid #e7eef6;
+ gap: 12rpx;
+ margin-top: 20rpx;
}
.voice-button {
display: flex;
+ align-self: stretch;
align-items: center;
justify-content: center;
gap: 12rpx;
width: 100%;
- height: 80rpx;
+ min-width: 100%;
+ max-width: 100%;
+ height: 84rpx;
margin: 0;
padding: 0 20rpx;
- border: 2rpx solid #b8cbe1;
+ border: 0;
border-radius: 12rpx;
- background: #ffffff;
- color: #2b67e8;
+ background: #eaf3ff;
+ color: #007aff;
font-size: 26rpx;
font-weight: 600;
line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+ transform-origin: center;
}
.voice-button::after {
@@ -75,16 +92,24 @@
}
.voice-button[disabled] {
- background: #f4f7fa;
- color: #99a5b3;
+ background: #f1f3f6;
+ color: #aeaeb2;
opacity: 1;
}
.voice-button-recording,
.voice-button-recording[disabled] {
- border-color: #e46b65;
- background: #fff4f3;
- color: #c83f39;
+ background: #fff0f0;
+ color: #d13f3a;
+}
+
+.voice-button:active {
+ transform: scale(0.98);
+ background: #dcecff;
+}
+
+.voice-button-recording:active {
+ background: #ffe2e1;
}
.voice-button-icon {
@@ -99,7 +124,7 @@
align-items: center;
justify-content: space-between;
min-width: 0;
- color: #65758a;
+ color: #6e6e73;
font-size: 24rpx;
}
@@ -113,12 +138,22 @@
.voice-state-actionable {
min-height: 64rpx;
+ padding: 14rpx 16rpx;
+ border: 1rpx solid #e5e5ea;
+ border-radius: 12rpx;
+ background: #f7f7f8;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.voice-state-actionable:active {
+ transform: scale(0.99);
+ background: #ededf0;
}
.voice-state-arrow {
flex: none;
margin-left: 10rpx;
- color: #7f8da0;
+ color: #8e8e93;
font-size: 38rpx;
line-height: 1;
}
@@ -126,20 +161,36 @@
.recording-time {
flex: none;
margin-left: 12rpx;
- color: #c83f39;
+ color: #d13f3a;
font-variant-numeric: tabular-nums;
}
.save-feedback {
- margin-top: 24rpx;
+ width: calc(100% - 48rpx);
+ min-width: calc(100% - 48rpx);
+ max-width: calc(100% - 48rpx);
+ margin: 20rpx 24rpx 24rpx;
}
.profiles-hint {
margin-top: 22rpx;
padding: 20rpx 22rpx;
- border: 2rpx dashed #c7ddeb;
+ border: 1rpx solid #d1e3fb;
border-radius: 12rpx;
- color: #65758a;
+ background: #f7fbff;
+ color: #6e6e73;
font-size: 24rpx;
line-height: 1.45;
}
+
+@media (prefers-reduced-motion: reduce) {
+ .voice-button,
+ .voice-state-actionable {
+ transition: none;
+ }
+
+ .voice-button:active,
+ .voice-state-actionable:active {
+ transform: none;
+ }
+}
diff --git a/pages/profile/index.wxml b/pages/profile/index.wxml
index 90527c8..5b6d991 100644
--- a/pages/profile/index.wxml
+++ b/pages/profile/index.wxml
@@ -1,7 +1,6 @@
个人中心
- ◉
我的
管理小程序连接的教学反馈服务。
diff --git a/pages/profile/index.wxss b/pages/profile/index.wxss
index 5dc6dc9..b063fa3 100644
--- a/pages/profile/index.wxss
+++ b/pages/profile/index.wxss
@@ -1,11 +1,11 @@
.profile-page {
- padding-top: 44rpx;
+ padding-top: 48rpx;
}
.server-card,
.identity-card {
- margin-top: 30rpx;
- padding: 26rpx;
+ margin-top: 28rpx;
+ padding: 24rpx;
}
.identity-card {
@@ -18,8 +18,8 @@
}
.section-title {
- color: #17233a;
- font-size: 32rpx;
+ color: #1c1c1e;
+ font-size: 30rpx;
font-weight: 800;
}
@@ -32,10 +32,10 @@
height: 78rpx;
margin-top: 12rpx;
padding: 0 20rpx;
- border: 2rpx solid #cbdced;
+ border: 1rpx solid #e5e5ea;
border-radius: 12rpx;
- background: #fbfdff;
- color: #17233a;
+ background: #f1f3f6;
+ color: #1c1c1e;
font-size: 27rpx;
}
@@ -50,23 +50,23 @@
width: 16rpx;
height: 16rpx;
border-radius: 50%;
- background: #8a97a6;
+ background: #8e8e93;
}
.connection-success {
- background: #23855b;
+ background: #248a3d;
}
.connection-warning {
- background: #c17a18;
+ background: #c66a00;
}
.connection-error {
- background: #c34343;
+ background: #d13f3a;
}
.connection-text {
- color: #566577;
+ color: #3a3a3c;
font-size: 25rpx;
}
@@ -76,7 +76,7 @@
.identity-value {
margin-top: 18rpx;
- color: #2b67e8;
+ color: #007aff;
font-size: 24rpx;
font-weight: 700;
word-break: break-all;
diff --git a/pages/records/index.wxml b/pages/records/index.wxml
index 096a846..83d7fe7 100644
--- a/pages/records/index.wxml
+++ b/pages/records/index.wxml
@@ -1,7 +1,6 @@
课堂反馈
- ◴
反馈记录
按学生查阅已保存的课堂反馈。
diff --git a/pages/records/index.wxss b/pages/records/index.wxss
index 9ca6b8c..a25c581 100644
--- a/pages/records/index.wxss
+++ b/pages/records/index.wxss
@@ -1,10 +1,10 @@
.records-page {
- padding-top: 44rpx;
+ padding-top: 48rpx;
}
.records-filter {
- margin-top: 30rpx;
- padding: 22rpx 24rpx;
+ margin-top: 28rpx;
+ padding: 24rpx;
}
.filter-label,
@@ -13,13 +13,13 @@
}
.filter-label {
- color: #718096;
+ color: #6e6e73;
font-size: 23rpx;
}
.filter-value {
margin-top: 8rpx;
- color: #17233a;
+ color: #1c1c1e;
font-size: 29rpx;
font-weight: 700;
}
@@ -34,13 +34,13 @@
}
.empty-icon {
- color: #2b67e8;
+ color: #007aff;
font-size: 56rpx;
}
.empty-title {
margin: 20rpx 0 12rpx;
- color: #17233a;
+ color: #1c1c1e;
font-size: 36rpx;
font-weight: 800;
}
@@ -53,12 +53,12 @@
.record-list {
display: flex;
flex-direction: column;
- gap: 18rpx;
- margin-top: 22rpx;
+ gap: 14rpx;
+ margin-top: 18rpx;
}
.record-card {
- padding: 24rpx;
+ padding: 26rpx 24rpx;
}
.record-top {
@@ -75,22 +75,22 @@
}
.record-profile {
- color: #17233a;
+ color: #1c1c1e;
font-size: 31rpx;
font-weight: 800;
}
.record-date {
margin-top: 6rpx;
- color: #718096;
+ color: #6e6e73;
font-size: 23rpx;
}
.record-content {
margin-top: 20rpx;
padding-top: 18rpx;
- border-top: 1rpx solid #e8eef5;
- color: #334258;
+ border-top: 1rpx solid #e5e5ea;
+ color: #3a3a3c;
font-size: 27rpx;
line-height: 1.65;
white-space: pre-wrap;
@@ -99,10 +99,10 @@
.delete-button {
margin: 0;
padding: 8rpx 14rpx;
- border: 1rpx solid #f2c6c6;
+ border: 1rpx solid #f1c4c4;
border-radius: 10rpx;
- background: #ffffff;
- color: #c34343;
+ background: #fff2f2;
+ color: #d13f3a;
font-size: 22rpx;
line-height: 1.3;
}
diff --git a/pages/students/index.ts b/pages/students/index.ts
index 500bdcc..0c56f9e 100644
--- a/pages/students/index.ts
+++ b/pages/students/index.ts
@@ -3,10 +3,11 @@ import {
deleteProfile as deleteProfileRequest,
getApiErrorMessage,
getProfileDefaults,
+ listFeedbackRecords,
listProfiles
} from '../../utils/api'
import { addMinutes, formatUpdatedAt } from '../../utils/time'
-import type { StudentDraft, StudentProfile, StudentProfileDefaults, Term } from '../../utils/types'
+import type { FeedbackRecord, StudentDraft, StudentProfile, StudentProfileDefaults, Term } from '../../utils/types'
const grades = ['初一', '初二', '初三']
const subjects = ['美术', '书法', '音乐', '舞蹈', '语文', '数学', '英语']
@@ -17,9 +18,23 @@ const initialDefaults: StudentProfileDefaults = {
subject: '数学',
lessonDurationMinutes: 60
}
+const termLabels: Record = {
+ 春: '春季',
+ 暑: '暑期',
+ 秋: '秋季',
+ 寒: '寒假'
+}
type InputEvent = { detail: { value: string } }
type PickerEvent = { detail: { value: string | number } }
+type StudentProfileView = StudentProfile & { academicTermLabel: string }
+
+function withAcademicTermLabel(profile: StudentProfile): StudentProfileView {
+ return {
+ ...profile,
+ academicTermLabel: `${profile.academicYear} 年${termLabels[profile.term]}`
+ }
+}
function getCurrentTerm(): Term {
const month = new Date().getMonth() + 1
@@ -44,11 +59,11 @@ function buildDraft(defaults: StudentProfileDefaults = initialDefaults): Student
}
function filterProfiles(
- profiles: StudentProfile[],
+ profiles: StudentProfileView[],
query: string,
filterGrade: string,
filterSubject: string
-): StudentProfile[] {
+): StudentProfileView[] {
const keyword = query.trim().toLocaleLowerCase()
return profiles.filter((profile) => {
const searchable = [profile.name, profile.grade, profile.subject, profile.guardianTitle]
@@ -69,12 +84,17 @@ function getLastUpdatedText(profiles: StudentProfile[]): string {
Page({
data: {
- profiles: [] as StudentProfile[],
- filteredProfiles: [] as StudentProfile[],
+ profiles: [] as StudentProfileView[],
+ filteredProfiles: [] as StudentProfileView[],
query: '',
filterVisible: false,
filterGrade: '',
filterSubject: '',
+ filterCount: 0,
+ expandedProfileId: '',
+ recentFeedbackByProfile: {} as Record,
+ feedbackLoadingByProfile: {} as Record,
+ feedbackErrorsByProfile: {} as Record,
grades,
subjects,
terms,
@@ -101,7 +121,7 @@ Page({
async refreshProfiles(showSuccess = false) {
this.setData({ loading: true, errorMessage: '' })
try {
- const profiles = await listProfiles()
+ const profiles = (await listProfiles()).map(withAcademicTermLabel)
const filteredProfiles = filterProfiles(
profiles,
this.data.query,
@@ -111,7 +131,11 @@ Page({
this.setData({
profiles,
filteredProfiles,
- lastUpdatedText: getLastUpdatedText(profiles)
+ lastUpdatedText: getLastUpdatedText(profiles),
+ expandedProfileId: '',
+ recentFeedbackByProfile: {},
+ feedbackLoadingByProfile: {},
+ feedbackErrorsByProfile: {}
})
if (showSuccess) wx.showToast({ title: '档案已刷新', icon: 'success' })
} catch (error) {
@@ -153,6 +177,7 @@ Page({
this.setData({
filterGrade,
filterSubject,
+ filterCount: Number(Boolean(filterGrade)) + Number(Boolean(filterSubject)),
filteredProfiles: filterProfiles(this.data.profiles, this.data.query, filterGrade, filterSubject)
})
},
@@ -162,10 +187,67 @@ Page({
query: '',
filterGrade: '',
filterSubject: '',
+ filterCount: 0,
filteredProfiles: this.data.profiles
})
},
+ toggleProfile(event: WechatMiniprogram.TouchEvent) {
+ const { id } = event.currentTarget.dataset as { id: string }
+ if (this.data.expandedProfileId === id) {
+ this.setData({ expandedProfileId: '' })
+ return
+ }
+
+ const hasFeedback = Object.prototype.hasOwnProperty.call(this.data.recentFeedbackByProfile, id)
+ this.setData({
+ expandedProfileId: id,
+ ...(hasFeedback
+ ? {}
+ : {
+ feedbackLoadingByProfile: { ...this.data.feedbackLoadingByProfile, [id]: true },
+ feedbackErrorsByProfile: { ...this.data.feedbackErrorsByProfile, [id]: '' }
+ })
+ })
+ if (!hasFeedback) void this.loadRecentFeedback(id)
+ },
+
+ async loadRecentFeedback(profileId: string) {
+ try {
+ const records = await listFeedbackRecords(profileId)
+ this.setData({
+ recentFeedbackByProfile: {
+ ...this.data.recentFeedbackByProfile,
+ [profileId]: records.slice(0, 3)
+ }
+ })
+ } catch (error) {
+ this.setData({
+ feedbackErrorsByProfile: {
+ ...this.data.feedbackErrorsByProfile,
+ [profileId]: getApiErrorMessage(error)
+ }
+ })
+ } finally {
+ this.setData({
+ feedbackLoadingByProfile: {
+ ...this.data.feedbackLoadingByProfile,
+ [profileId]: false
+ }
+ })
+ }
+ },
+
+ retryRecentFeedback(event: WechatMiniprogram.TouchEvent) {
+ const { id } = event.currentTarget.dataset as { id: string }
+ if (this.data.feedbackLoadingByProfile[id]) return
+ this.setData({
+ feedbackLoadingByProfile: { ...this.data.feedbackLoadingByProfile, [id]: true },
+ feedbackErrorsByProfile: { ...this.data.feedbackErrorsByProfile, [id]: '' }
+ })
+ void this.loadRecentFeedback(id)
+ },
+
async openCreate() {
this.setData({
sheetVisible: true,
@@ -262,11 +344,13 @@ Page({
this.setData({ saving: true })
try {
- const profile = await createProfile({
- ...draft,
- name: draft.name.trim(),
- guardianTitle: draft.guardianTitle.trim() || `${draft.name.trim()}妈妈`
- })
+ const profile = withAcademicTermLabel(
+ await createProfile({
+ ...draft,
+ name: draft.name.trim(),
+ guardianTitle: draft.guardianTitle.trim() || `${draft.name.trim()}妈妈`
+ })
+ )
const profiles = [profile, ...this.data.profiles]
this.setData({
sheetVisible: false,
@@ -284,25 +368,48 @@ Page({
}
},
- deleteProfile(event: WechatMiniprogram.TouchEvent) {
+ openProfileActions(event: WechatMiniprogram.TouchEvent) {
const { id } = event.currentTarget.dataset as { id: string }
const profile = this.data.profiles.find((item) => item.id === id)
if (!profile) return
+ wx.showActionSheet({
+ itemList: ['删除学生档案'],
+ itemColor: '#D13F3A',
+ success: (result) => {
+ if (result.tapIndex === 0) this.confirmDeleteProfile(id)
+ }
+ })
+ },
+
+ confirmDeleteProfile(id: string) {
+ const profile = this.data.profiles.find((item) => item.id === id)
+ if (!profile) return
+
wx.showModal({
title: '删除学生档案',
content: `确认删除“${profile.name}”吗?`,
- confirmColor: '#D14343',
+ confirmColor: '#D13F3A',
success: async (result) => {
if (!result.confirm) return
this.setData({ deletingId: id })
try {
await deleteProfileRequest(id)
const profiles = this.data.profiles.filter((item) => item.id !== id)
+ const recentFeedbackByProfile = { ...this.data.recentFeedbackByProfile }
+ const feedbackLoadingByProfile = { ...this.data.feedbackLoadingByProfile }
+ const feedbackErrorsByProfile = { ...this.data.feedbackErrorsByProfile }
+ delete recentFeedbackByProfile[id]
+ delete feedbackLoadingByProfile[id]
+ delete feedbackErrorsByProfile[id]
this.setData({
profiles,
filteredProfiles: filterProfiles(profiles, this.data.query, this.data.filterGrade, this.data.filterSubject),
lastUpdatedText: getLastUpdatedText(profiles),
+ expandedProfileId: this.data.expandedProfileId === id ? '' : this.data.expandedProfileId,
+ recentFeedbackByProfile,
+ feedbackLoadingByProfile,
+ feedbackErrorsByProfile,
errorMessage: ''
})
wx.showToast({ title: '已删除', icon: 'success' })
diff --git a/pages/students/index.wxml b/pages/students/index.wxml
index 5203a89..9eeb79d 100644
--- a/pages/students/index.wxml
+++ b/pages/students/index.wxml
@@ -1,7 +1,6 @@
个人档案
- ◎
学生档案
管理学生默认信息,用于快速生成课堂反馈
@@ -13,7 +12,7 @@
- ⌕
+
-
@@ -45,13 +49,9 @@
-
+
-
- ▣
- 档案卡片
-
- 点击卡片展开最近三条反馈
+ 学生列表
上次更新:{{lastUpdatedText}}
@@ -78,21 +78,61 @@
-
-
- {{item.name}}
- {{item.guardianTitle}}
+
+
+
+ {{item.name}}
+ {{item.guardianTitle}}
+
+
+
+ ›
+
+
+
+
+ {{item.grade}}
+ {{item.subject}}
+ {{item.academicTermLabel}}
+
+
+ 上课时间
+ {{item.startTime}} - {{item.endTime}}
- 删除
-
- {{item.grade}}
- {{item.subject}}
- {{item.academicYear}}{{item.term}}
-
-
- 上课时间
- {{item.startTime}} - {{item.endTime}}
+
+
+
+ 最近反馈
+ {{recentFeedbackByProfile[item.id].length}} 条
+
+ 正在读取反馈...
+
+ {{feedbackErrorsByProfile[item.id]}}
+ 重试
+
+ 暂无反馈记录
+
+
+ {{feedback.feedbackDate}}
+ {{feedback.content}}
+
+
@@ -103,12 +143,14 @@
- ▣
新增学生档案
保存后会同步到学生档案列表
- 设置预设项 ›
+
+ 设置预设项 ›
+ ×
+
diff --git a/pages/students/index.wxss b/pages/students/index.wxss
index 2c69e4f..b002970 100644
--- a/pages/students/index.wxss
+++ b/pages/students/index.wxss
@@ -2,7 +2,7 @@
display: grid;
grid-template-columns: minmax(0, 1fr) 88rpx;
gap: 16rpx;
- margin-top: 42rpx;
+ margin-top: 34rpx;
}
.search-box {
@@ -12,31 +12,29 @@
min-width: 0;
height: 88rpx;
padding: 0 24rpx;
- border: 2rpx solid #cbdced;
+ border: 1rpx solid transparent;
border-radius: 16rpx;
- background: #ffffff;
- box-shadow: 0 4rpx 12rpx rgba(45, 78, 120, 0.05);
+ background: #f1f3f6;
}
.search-icon {
+ flex: none;
margin-right: 14rpx;
- color: #2b67e8;
- font-size: 44rpx;
- line-height: 1;
}
.search-input {
flex: 1;
min-width: 0;
- color: #17233a;
+ color: #1c1c1e;
font-size: 28rpx;
}
.search-placeholder {
- color: #9aa8b8;
+ color: #8e8e93;
}
.filter-button {
+ position: relative;
display: flex;
flex: none;
align-items: center;
@@ -47,12 +45,86 @@
height: 88rpx;
margin: 0;
padding: 0;
- border: 2rpx solid #cbdced;
+ border: 1rpx solid transparent;
border-radius: 16rpx;
- background: #ffffff;
- color: #2b67e8;
- font-size: 44rpx;
+ background: #f1f3f6;
+ color: #6e6e73;
line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.filter-button-active {
+ border-color: #b8d9ff;
+ background: #eaf3ff;
+ color: #007aff;
+}
+
+.filter-button:active {
+ transform: scale(0.96);
+}
+
+.filter-icon {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ width: 34rpx;
+ height: 30rpx;
+}
+
+.filter-icon-line {
+ position: relative;
+ width: 34rpx;
+ height: 3rpx;
+ border-radius: 2rpx;
+ background: currentColor;
+}
+
+.filter-icon-line::after {
+ position: absolute;
+ top: -4rpx;
+ width: 10rpx;
+ height: 10rpx;
+ border: 3rpx solid currentColor;
+ border-radius: 50%;
+ background: #f1f3f6;
+ content: '';
+}
+
+.filter-button-active .filter-icon-line::after {
+ background: #eaf3ff;
+}
+
+.filter-icon-line-first::after,
+.filter-icon-line-third::after {
+ left: 5rpx;
+}
+
+.filter-icon-line-second::after {
+ right: 5rpx;
+}
+
+.filter-count {
+ position: absolute;
+ top: 8rpx;
+ right: 8rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 28rpx;
+ height: 28rpx;
+ padding: 0 5rpx;
+ box-sizing: border-box;
+ border: 3rpx solid #f1f3f6;
+ border-radius: 14rpx;
+ background: #007aff;
+ color: #ffffff;
+ font-size: 18rpx;
+ font-weight: 700;
+ line-height: 1;
+}
+
+.filter-button-active .filter-count {
+ border-color: #eaf3ff;
}
.filter-panel {
@@ -68,20 +140,20 @@
}
.filter-title {
- color: #17233a;
+ color: #1c1c1e;
font-size: 30rpx;
font-weight: 700;
}
.filter-clear {
- color: #2b67e8;
+ color: #007aff;
font-size: 26rpx;
}
.filter-label {
display: block;
margin: 16rpx 0 12rpx;
- color: #718096;
+ color: #6e6e73;
font-size: 24rpx;
}
@@ -93,17 +165,23 @@
.filter-chip {
padding: 10rpx 18rpx;
- border: 1rpx solid #d6e1ed;
- border-radius: 12rpx;
- color: #566577;
+ border: 1rpx solid #e5e5ea;
+ border-radius: 10rpx;
+ background: #f1f3f6;
+ color: #3a3a3c;
font-size: 24rpx;
line-height: 1.2;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.filter-chip-active {
- border-color: #2b67e8;
- background: #eaf1ff;
- color: #2b67e8;
+ border-color: #b8d9ff;
+ background: #eaf3ff;
+ color: #007aff;
+}
+
+.filter-chip:active {
+ transform: scale(0.97);
}
.archive-toolbar {
@@ -111,8 +189,8 @@
grid-template-columns: minmax(0, 1fr) 264rpx;
align-items: center;
gap: 20rpx;
- margin-top: 20rpx;
- padding: 28rpx;
+ margin-top: 22rpx;
+ padding: 18rpx 0 4rpx;
}
.toolbar-copy {
@@ -120,36 +198,21 @@
min-width: 0;
}
-.toolbar-title-row {
- display: flex;
- align-items: center;
- gap: 12rpx;
-}
-
-.toolbar-icon {
- color: #2b67e8;
- font-size: 34rpx;
-}
-
.toolbar-title {
- color: #17233a;
- font-size: 34rpx;
+ display: block;
+ color: #1c1c1e;
+ font-size: 29rpx;
font-weight: 800;
}
-.toolbar-description,
.toolbar-updated {
display: block;
- margin-top: 8rpx;
- color: #7b8796;
- font-size: 24rpx;
+ margin-top: 5rpx;
+ color: #6e6e73;
+ font-size: 22rpx;
line-height: 1.4;
}
-.toolbar-updated {
- font-weight: 600;
-}
-
.toolbar-actions {
display: grid;
grid-template-columns: 62rpx 190rpx;
@@ -162,18 +225,27 @@
.refresh-button {
flex: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
width: 62rpx;
min-width: 62rpx;
max-width: 62rpx;
height: 62rpx;
margin: 0;
padding: 0;
- border: 2rpx solid #cbdced;
+ border: 0;
border-radius: 12rpx;
- background: #ffffff;
- color: #2b67e8;
+ background: #f1f3f6;
+ color: #007aff;
font-size: 36rpx;
line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.refresh-button:active {
+ transform: scale(0.94);
+ background: #e5e5ea;
}
.new-student-button {
@@ -187,13 +259,19 @@
height: 62rpx;
margin: 0;
padding: 0 18rpx;
- border: 2rpx solid #cbdced;
+ border: 0;
border-radius: 12rpx;
- background: #ffffff;
- color: #2b67e8;
+ background: #007aff;
+ color: #ffffff;
font-size: 26rpx;
font-weight: 700;
line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.new-student-button:active {
+ transform: scale(0.97);
+ background: #006ee6;
}
.new-student-icon {
@@ -217,21 +295,21 @@
}
.empty-icon {
- color: #2b67e8;
+ color: #007aff;
font-size: 54rpx;
line-height: 1;
}
.empty-title {
margin-top: 18rpx;
- color: #17233a;
+ color: #1c1c1e;
font-size: 36rpx;
font-weight: 800;
}
.empty-description {
margin-top: 14rpx;
- color: #7b8796;
+ color: #6e6e73;
font-size: 28rpx;
}
@@ -253,7 +331,17 @@
}
.profile-card {
+ overflow: hidden;
+ padding: 0;
+}
+
+.profile-summary {
padding: 24rpx;
+ transition: opacity 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.profile-summary:active {
+ opacity: 0.72;
}
.profile-card-top,
@@ -264,9 +352,16 @@
gap: 20rpx;
}
+.profile-card-actions {
+ display: flex;
+ flex: none;
+ align-items: center;
+ gap: 4rpx;
+}
+
.profile-name {
display: block;
- color: #17233a;
+ color: #1c1c1e;
font-size: 34rpx;
font-weight: 800;
}
@@ -274,19 +369,46 @@
.profile-guardian {
display: block;
margin-top: 8rpx;
- color: #718096;
+ color: #6e6e73;
font-size: 24rpx;
}
-.delete-button {
+.profile-menu-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 56rpx;
+ min-width: 56rpx;
+ max-width: 56rpx;
+ height: 56rpx;
margin: 0;
- padding: 8rpx 14rpx;
- border: 1rpx solid #f2c6c6;
- border-radius: 10rpx;
- background: #ffffff;
- color: #c34343;
- font-size: 22rpx;
- line-height: 1.3;
+ padding: 0;
+ border: 0;
+ border-radius: 50%;
+ background: transparent;
+ color: #6e6e73;
+ font-size: 25rpx;
+ line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.profile-menu-button:active {
+ transform: scale(0.94);
+ background: #f1f3f6;
+}
+
+.profile-chevron {
+ width: 24rpx;
+ color: #8e8e93;
+ font-size: 40rpx;
+ line-height: 1;
+ text-align: center;
+ transform: rotate(0deg);
+ transition: transform 180ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.profile-chevron-expanded {
+ transform: rotate(90deg);
}
.profile-tags {
@@ -299,8 +421,8 @@
.profile-tag {
padding: 8rpx 12rpx;
border-radius: 8rpx;
- background: #eef4ff;
- color: #3563b5;
+ background: #f1f3f6;
+ color: #3a3a3c;
font-size: 22rpx;
line-height: 1.2;
}
@@ -308,20 +430,99 @@
.profile-time-row {
margin-top: 20rpx;
padding-top: 18rpx;
- border-top: 1rpx solid #e8eef5;
+ border-top: 1rpx solid #e5e5ea;
}
.profile-time-label {
- color: #7b8796;
+ color: #6e6e73;
font-size: 24rpx;
}
.profile-time-value {
- color: #17233a;
+ color: #1c1c1e;
font-size: 26rpx;
font-weight: 700;
}
+.profile-feedback-panel {
+ padding: 20rpx 24rpx 24rpx;
+ border-top: 1rpx solid #e5e5ea;
+ background: #fbfcfe;
+}
+
+.profile-feedback-heading {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16rpx;
+}
+
+.profile-feedback-title {
+ color: #1c1c1e;
+ font-size: 25rpx;
+ font-weight: 700;
+}
+
+.profile-feedback-count,
+.profile-feedback-status {
+ color: #6e6e73;
+ font-size: 22rpx;
+}
+
+.profile-feedback-status {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16rpx;
+ min-height: 64rpx;
+ padding-top: 14rpx;
+}
+
+.profile-feedback-error {
+ color: #d13f3a;
+}
+
+.profile-feedback-retry {
+ flex: none;
+ padding: 10rpx 0 10rpx 18rpx;
+ color: #007aff;
+ font-weight: 700;
+}
+
+.recent-feedback-list {
+ margin-top: 10rpx;
+}
+
+.recent-feedback-item {
+ padding: 14rpx 0;
+}
+
+.recent-feedback-item + .recent-feedback-item {
+ border-top: 1rpx solid #e5e5ea;
+}
+
+.recent-feedback-date,
+.recent-feedback-content {
+ display: block;
+}
+
+.recent-feedback-date {
+ color: #6e6e73;
+ font-size: 21rpx;
+}
+
+.recent-feedback-content {
+ display: -webkit-box;
+ margin-top: 6rpx;
+ overflow: hidden;
+ color: #3a3a3c;
+ font-size: 24rpx;
+ line-height: 1.55;
+ word-break: break-all;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+}
+
.sheet-mask {
position: fixed;
z-index: 200;
@@ -332,19 +533,22 @@
display: flex;
align-items: flex-end;
padding: 16rpx;
- background: rgba(17, 27, 50, 0.42);
+ background: rgba(244, 247, 251, 0.82);
+ -webkit-backdrop-filter: blur(10rpx) saturate(110%);
+ backdrop-filter: blur(10rpx) saturate(110%);
}
.create-sheet {
width: 100%;
- height: 90vh;
- max-height: 90vh;
+ height: auto;
+ max-height: 88vh;
overflow: hidden;
display: flex;
flex-direction: column;
+ border: 1rpx solid rgba(255, 255, 255, 0.72);
border-radius: 16rpx;
background: #ffffff;
- box-shadow: 0 24rpx 56rpx rgba(17, 27, 50, 0.22);
+ box-shadow: 0 24rpx 56rpx rgba(28, 28, 30, 0.24);
}
.sheet-top {
@@ -353,7 +557,9 @@
align-items: center;
justify-content: space-between;
gap: 16rpx;
- padding: 24rpx 24rpx 16rpx;
+ padding: 24rpx 24rpx 18rpx;
+ border-bottom: 1rpx solid #e5e5ea;
+ background: #ffffff;
}
.sheet-top > view {
@@ -367,13 +573,8 @@
gap: 10rpx;
}
-.sheet-title-icon {
- color: #2b67e8;
- font-size: 34rpx;
-}
-
.sheet-title {
- color: #17233a;
+ color: #1c1c1e;
font-size: 34rpx;
font-weight: 800;
}
@@ -381,25 +582,58 @@
.sheet-subtitle {
display: block;
margin-top: 12rpx;
- color: #7b8796;
+ color: #6e6e73;
font-size: 24rpx;
}
+.sheet-actions {
+ display: flex;
+ flex: none;
+ align-items: center;
+ gap: 12rpx;
+}
+
.defaults-link {
flex: none;
- padding: 10rpx 0 10rpx 12rpx;
- color: #2b67e8;
+ padding: 10rpx 0;
+ color: #007aff;
font-size: 24rpx;
font-weight: 700;
line-height: 1.2;
white-space: nowrap;
}
+.sheet-close {
+ display: flex;
+ flex: none;
+ align-items: center;
+ justify-content: center;
+ width: 56rpx;
+ min-width: 56rpx;
+ max-width: 56rpx;
+ height: 56rpx;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ border-radius: 50%;
+ background: #f1f3f6;
+ color: #6e6e73;
+ font-size: 38rpx;
+ font-weight: 400;
+ line-height: 1;
+ transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.sheet-close:active {
+ transform: scale(0.94);
+ background: #e5e5ea;
+}
+
.sheet-scroll {
- flex: 1;
- height: 0;
+ flex: none;
+ height: auto;
min-height: 0;
- max-height: none;
+ max-height: calc(88vh - 236rpx);
width: 100%;
padding: 0;
box-sizing: border-box;
@@ -407,7 +641,7 @@
.sheet-form {
width: 100%;
- padding: 0 24rpx 16rpx;
+ padding: 16rpx 24rpx 16rpx;
box-sizing: border-box;
}
@@ -431,9 +665,9 @@ picker.form-field {
.form-field {
min-height: 108rpx;
padding: 16rpx;
- border: 2rpx solid #d8e5f2;
+ border: 1rpx solid #e5e5ea;
border-radius: 14rpx;
- background: #fbfdff;
+ background: #f1f3f6;
}
.full-field {
@@ -442,7 +676,7 @@ picker.form-field {
.form-label {
display: block;
- color: #2b67e8;
+ color: #6e6e73;
font-size: 24rpx;
font-weight: 700;
}
@@ -450,7 +684,7 @@ picker.form-field {
.form-value {
display: block;
margin-top: 14rpx;
- color: #17233a;
+ color: #1c1c1e;
font-size: 28rpx;
font-weight: 700;
}
@@ -459,7 +693,7 @@ picker.form-field {
width: 100%;
height: 48rpx;
margin-top: 10rpx;
- color: #17233a;
+ color: #1c1c1e;
font-size: 28rpx;
font-weight: 600;
}
@@ -477,10 +711,45 @@ picker.form-field {
display: flex;
gap: 16rpx;
padding: 18rpx 24rpx calc(18rpx + env(safe-area-inset-bottom));
- border-top: 1rpx solid #e7eef6;
+ border-top: 1rpx solid #e5e5ea;
+ background: #ffffff;
}
.sheet-cancel,
.sheet-save {
flex: 1;
}
+
+@media (prefers-reduced-motion: reduce) {
+ .filter-button,
+ .filter-chip,
+ .refresh-button,
+ .new-student-button,
+ .profile-summary,
+ .profile-menu-button,
+ .profile-chevron,
+ .sheet-close {
+ transition: none;
+ }
+
+ .filter-button:active,
+ .filter-chip:active,
+ .refresh-button:active,
+ .new-student-button:active,
+ .profile-menu-button:active,
+ .sheet-close:active {
+ transform: none;
+ }
+
+ .profile-summary:active {
+ opacity: 1;
+ }
+}
+
+@media (prefers-reduced-transparency: reduce) {
+ .sheet-mask {
+ background: rgba(244, 247, 251, 0.96);
+ -webkit-backdrop-filter: none;
+ backdrop-filter: none;
+ }
+}