perf: 支持课程补录

This commit is contained in:
richarjiang
2026-09-08 15:08:29 +08:00
parent d1f193e13e
commit b4b3caac70
24 changed files with 1074 additions and 945 deletions

View File

@@ -0,0 +1,39 @@
<template>
<view class="supplements">
<view v-for="item in records" :key="item.id" class="record" :class="{ 'record--revoked': item.revokedAt }">
<view class="record-head">
<view class="record-title"><text>系统补录</text><text class="record-sub">{{ item.revokedAt ? '已撤销' : '历史课程' }}</text></view>
<text class="record-quantity">{{ item.quantity }}<text class="record-unit"> </text></text>
</view>
<text class="record-date">{{ formatDateTimeFull(item.createdAt) }} 补录</text>
<text class="record-note">{{ item.deductedTimes ? `${item.cardName} · ${item.revokedAt ? '已返还' : '扣除'} ${item.deductedTimes}` : '仅补记录 · 未扣会员卡' }}</text>
<text v-if="item.remark" class="record-note">{{ item.remark }}</text>
<view v-if="editable" class="record-footer">
<text class="record-operator"> {{ item.operatorName }} 补录</text>
<button v-if="!item.revokedAt" class="revoke" :disabled="busy" @tap="emit('revoke', item)">撤销补录</button>
<text v-else class="record-operator">{{ formatDateTimeFull(item.revokedAt) }} 撤销</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import type { LessonSupplementRecord } from '@mp-pilates/shared'
import { formatDateTimeFull } from '../utils/format'
defineProps<{ records: readonly LessonSupplementRecord[]; editable?: boolean; busy?: boolean }>()
const emit = defineEmits<{ revoke: [record: LessonSupplementRecord] }>()
</script>
<style lang="scss" scoped>
.supplements { display: flex; flex-direction: column; gap: 20rpx; }
.record { padding: 28rpx; border: 1rpx solid #e9e7df; border-radius: 26rpx; background: #fff; color: #514943; }
.record--revoked { background: #f4f1ed; color: #8b817b; }
.record-head { display: flex; align-items: center; justify-content: space-between; gap: 20rpx; }
.record-title { display: flex; flex-direction: column; gap: 8rpx; font-size: 28rpx; }
.record-sub { font-size: 20rpx; color: #8b817b; }
.record-quantity { flex-shrink: 0; font-size: 42rpx; font-variant-numeric: tabular-nums; color: #617d73; }
.record-unit { font-size: 22rpx; }
.record-date { display: block; margin-top: 20rpx; color: #8b817b; font-size: 21rpx; }
.record-note { display: block; margin-top: 12rpx; font-size: 23rpx; color: #786b61; line-height: 1.6; overflow-wrap: anywhere; }
.record-footer { margin-top: 20rpx; padding-top: 16rpx; border-top: 1rpx solid #eee8e3; display: flex; align-items: center; justify-content: space-between; gap: 16rpx; flex-wrap: wrap; }
.record-operator { color: #8b817b; font-size: 21rpx; }
.revoke { margin: 0; padding: 8rpx 12rpx; font-size: 22rpx; line-height: 1.5; background: transparent; color: #967561; &::after { border: none; } }
</style>