fix: 防止成长档案编辑弹窗被误关
微信端点击输入会冒泡到遮罩,且 onShow 刷新会清空编辑态,导致体测、笔记和照片无法填写。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -62,8 +62,8 @@
|
||||
<view v-for="n in [10, 30, 50]" :key="n" class="milestone" :class="{ locked: !archive.milestones.includes(n) }"><text class="kicker">A MOMENT TO REMEMBER</text><text class="milestone-number">{{ n }}<text>节</text></text><text class="milestone-title">{{ milestoneTitles[n] }}</text><text class="muted">{{ archive.milestones.includes(n) ? '你已走过这段旅程' : '还差 ' + (n - archive.completedCount) + ' 节,一步步来' }}</text><button v-if="archive.milestones.includes(n) && !admin" class="small" :disabled="busy" @tap="saveMilestone(n)">保存纪念卡</button></view>
|
||||
</template>
|
||||
</template>
|
||||
<view v-if="editor" class="overlay" @tap.self="closeEditor">
|
||||
<scroll-view scroll-y class="sheet"><view class="heading"><text>{{ editor === 'metrics' ? '记录身体刻度' : editor === 'notes' ? '写一份教练笔记' : '添加成长照片' }}</text><button class="text-btn" :disabled="busy" @tap="closeEditor">关闭</button></view>
|
||||
<view v-if="editor" class="overlay" @tap="onBackdropTap">
|
||||
<scroll-view scroll-y class="sheet" @tap.stop><view class="heading"><text>{{ editor === 'metrics' ? '记录身体刻度' : editor === 'notes' ? '写一份教练笔记' : '添加成长照片' }}</text><button class="text-btn" :disabled="busy" @tap="closeEditor">关闭</button></view>
|
||||
<template v-if="editor !== 'notes'"><text class="field-label">记录日期</text><picker mode="date" :value="recordDate" :end="today" @change="recordDate = $event.detail.value"><view class="input">{{ recordDate }} ›</view></picker></template>
|
||||
<template v-if="editor === 'metrics'"><view v-for="field in fields" :key="field.key" class="field"><text class="field-label">{{ field.label }}({{ field.unit }})</text><input v-model="metricForm[field.key]" :type="field.key === 'flexibility' ? 'text' : 'digit'" class="input" placeholder="未测量可留空" maxlength="8" /></view><text class="muted">柔韧度统一记录坐位体前屈,未触及脚尖可填写负值。</text><textarea v-model="remark" maxlength="200" placeholder="测量备注(选填)" /></template>
|
||||
<template v-if="editor === 'notes'"><text v-if="bookingId" class="lesson">已关联本次完成课程</text><textarea v-model="noteContent" maxlength="1000" placeholder="今天观察到了什么?下一次练习需要注意什么?" /><text class="muted">{{ noteContent.length }} / 1000</text><view class="switch-row"><view><text>分享给学员</text><text class="muted">{{ shared ? '这份评语将出现在学员档案' : '仅馆主自己可见' }}</text></view><switch :checked="shared" color="#617d70" @change="changeShared" /></view></template>
|
||||
@@ -94,10 +94,11 @@ const today = new Date(Date.now() + 8 * 3600000).toISOString().slice(0, 10), rec
|
||||
const metricForm = ref<Record<string, string>>({}), photoUrls = ref<Record<string, string>>({}), selectedPhotos = ref<string[]>([]), comparison = ref<{ id: string; url: string; date: string }[]>([])
|
||||
const milestoneTitles: Record<number, string> = { 10: '开始,与身体相识', 30: '坚持,找到自己的节奏', 50: '积累,看见自己的力量' }
|
||||
const instance = getCurrentInstance()
|
||||
let sequence = 0, timer: ReturnType<typeof setTimeout> | undefined
|
||||
let sequence = 0, openedAt = 0, timer: ReturnType<typeof setTimeout> | undefined
|
||||
async function load() {
|
||||
if (props.admin && !props.userId) return
|
||||
const seq = ++sequence; loading.value = true; error.value = ''; photoUrls.value = {}; comparison.value = []; selectedPhotos.value = []
|
||||
const seq = ++sequence; loading.value = true; error.value = ''
|
||||
if (!editor.value) { photoUrls.value = {}; comparison.value = []; selectedPhotos.value = [] }
|
||||
try { const result = await get<ProgressArchive>(base.value); if (seq === sequence) archive.value = result }
|
||||
catch (e) { if (seq === sequence) error.value = message(e) }
|
||||
finally { if (seq === sequence) loading.value = false }
|
||||
@@ -105,8 +106,20 @@ async function load() {
|
||||
function previewComparison(url: string) { uni.previewImage({ urls: comparison.value.map(p => p.url), current: url }) }
|
||||
function changeShared(event: Event) { shared.value = (event as unknown as { detail: { value: boolean } }).detail.value }
|
||||
function message(e: unknown) { return e instanceof Error ? e.message : '操作失败,请重试' }
|
||||
function openEditor(kind: string) { editor.value = kind; saveError.value = ''; metricForm.value = {}; remark.value = ''; noteContent.value = ''; shared.value = false; caption.value = ''; photoPath.value = ''; recordDate.value = today }
|
||||
function openEditor(kind: string) {
|
||||
openedAt = Date.now()
|
||||
editor.value = kind
|
||||
saveError.value = ''
|
||||
metricForm.value = {}
|
||||
remark.value = ''
|
||||
noteContent.value = ''
|
||||
shared.value = false
|
||||
caption.value = ''
|
||||
photoPath.value = ''
|
||||
recordDate.value = today
|
||||
}
|
||||
function closeEditor() { if (!busy.value) editor.value = '' }
|
||||
function onBackdropTap() { if (Date.now() - openedAt < 400) return; closeEditor() }
|
||||
async function save() {
|
||||
if (busy.value) return
|
||||
busy.value = true; saveError.value = ''
|
||||
@@ -162,7 +175,11 @@ async function saveMilestone(n: number) {
|
||||
await uni.saveImageToPhotosAlbum({ filePath: result.tempFilePath }); uni.showToast({ title: '纪念卡已保存', icon: 'success' })
|
||||
} catch { uni.showToast({ title: '保存失败,请允许保存到相册后重试', icon: 'none' }) } finally { busy.value = false }
|
||||
}
|
||||
watch(() => [props.userId, props.refreshKey], () => { archive.value = null; void load() }, { immediate: true })
|
||||
watch(() => [props.userId, props.refreshKey], () => {
|
||||
if (editor.value || busy.value) { void load(); return }
|
||||
archive.value = null
|
||||
void load()
|
||||
}, { immediate: true })
|
||||
watch(() => props.bookingId, id => { if (id) { tab.value = 'notes'; openEditor('notes') } }, { immediate: true })
|
||||
onBeforeUnmount(() => { sequence++; if (timer) clearTimeout(timer) })
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user