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