feat: establish teaching feedback mini program
Connect student profiles, defaults, and feedback records to the Rust API. Configure the WeChat AppID, custom tab bar, and local development workflow for version 0.1.0.
This commit is contained in:
108
pages/feedback/index.ts
Normal file
108
pages/feedback/index.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import {
|
||||
createFeedbackRecord,
|
||||
getApiErrorMessage,
|
||||
listProfiles
|
||||
} from '../../utils/api'
|
||||
import type { FeedbackDraft, StudentProfile } from '../../utils/types'
|
||||
|
||||
type PickerEvent = { detail: { value: string | number } }
|
||||
type InputEvent = { detail: { value: string } }
|
||||
|
||||
function today(): string {
|
||||
const now = new Date()
|
||||
const year = now.getFullYear()
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(now.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
function buildDraft(): FeedbackDraft {
|
||||
return {
|
||||
profileId: null,
|
||||
feedbackDate: today(),
|
||||
content: ''
|
||||
}
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
profiles: [] as StudentProfile[],
|
||||
profileOptions: ['不关联学生'],
|
||||
selectedProfileIndex: 0,
|
||||
draft: buildDraft(),
|
||||
contentLength: 0,
|
||||
loading: false,
|
||||
saving: false,
|
||||
errorMessage: ''
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.getTabBar()?.setData({ selected: 0 })
|
||||
void this.loadProfiles()
|
||||
},
|
||||
|
||||
async loadProfiles() {
|
||||
this.setData({ loading: true, errorMessage: '' })
|
||||
try {
|
||||
const profiles = await listProfiles()
|
||||
const matchedProfileIndex = profiles.findIndex((profile) => profile.id === this.data.draft.profileId)
|
||||
const selectedProfileIndex = matchedProfileIndex + 1
|
||||
this.setData({
|
||||
profiles,
|
||||
profileOptions: ['不关联学生', ...profiles.map((profile) => `${profile.name} · ${profile.subject}`)],
|
||||
selectedProfileIndex,
|
||||
'draft.profileId': matchedProfileIndex >= 0 ? profiles[matchedProfileIndex].id : null
|
||||
})
|
||||
} catch (error) {
|
||||
this.setData({ errorMessage: getApiErrorMessage(error) })
|
||||
} finally {
|
||||
this.setData({ loading: false })
|
||||
}
|
||||
},
|
||||
|
||||
retryLoad() {
|
||||
void this.loadProfiles()
|
||||
},
|
||||
|
||||
onProfileChange(event: PickerEvent) {
|
||||
const selectedProfileIndex = Number(event.detail.value)
|
||||
const profile = this.data.profiles[selectedProfileIndex - 1]
|
||||
this.setData({
|
||||
selectedProfileIndex,
|
||||
'draft.profileId': profile?.id || null
|
||||
})
|
||||
},
|
||||
|
||||
onDateChange(event: InputEvent) {
|
||||
this.setData({ 'draft.feedbackDate': event.detail.value })
|
||||
},
|
||||
|
||||
onContentInput(event: InputEvent) {
|
||||
const content = event.detail.value
|
||||
this.setData({ 'draft.content': content, contentLength: content.length })
|
||||
},
|
||||
|
||||
async saveFeedback() {
|
||||
const content = this.data.draft.content.trim()
|
||||
if (!content) {
|
||||
wx.showToast({ title: '请填写反馈内容', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({ saving: true })
|
||||
try {
|
||||
await createFeedbackRecord({ ...this.data.draft, content })
|
||||
this.setData({ draft: buildDraft(), selectedProfileIndex: 0, contentLength: 0 })
|
||||
wx.showToast({ title: '反馈已保存', icon: 'success' })
|
||||
setTimeout(() => wx.switchTab({ url: '/pages/records/index' }), 450)
|
||||
} catch (error) {
|
||||
wx.showToast({ title: getApiErrorMessage(error), icon: 'none' })
|
||||
} finally {
|
||||
this.setData({ saving: false })
|
||||
}
|
||||
},
|
||||
|
||||
goStudents() {
|
||||
wx.switchTab({ url: '/pages/students/index' })
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user