feat: restore learning feedback and knowledge capabilities

This commit is contained in:
2026-07-18 00:50:11 +08:00
parent 876a23a123
commit 6bdc86e3fc
152 changed files with 30337 additions and 953 deletions
@@ -0,0 +1,77 @@
<template>
<view class="page employee-page-shell points-page">
<view class="subpage-header">
<button class="subpage-back-button" aria-label="返回" @click="goBack">←</button>
<view class="subpage-heading">
<text class="employee-kicker">积分与学分分账</text>
<text class="page-title">我的积分</text>
<text class="page-subtitle">这里只记录积分和学习学分,不是现金、不能提现。</text>
</view>
</view>
<text v-if="message" class="status-message">{{ message }}</text>
<view class="balance-grid">
<view v-for="item in balances" :key="item.accountType" class="balance-card employee-card">
<text class="balance-label">{{ item.displayName }}</text>
<text class="balance-value">{{ item.balance }}</text>
<text class="balance-unit">{{ item.unitName }}</text>
</view>
</view>
<view class="panel employee-card rules-card">
<text class="panel-title">获得规则</text>
<text>问题或回答审核通过后,按当前规则记基础积分;最佳答案可获额外积分。只有经人工确认并沉淀知识库的成果才可能记学习学分。</text>
</view>
<view class="panel employee-card ledger-card">
<text class="panel-title">最近明细</text>
<view v-if="ledger.length" class="ledger-list">
<view v-for="item in ledger" :key="item.id" class="ledger-row">
<view>
<text class="ledger-title">{{ item.remark || item.sourceType }} · {{ item.accountType === 'STUDY_CREDIT' ? '学习学分' : '奖励积分' }}</text>
<text class="ledger-time">{{ item.createTime }}</text>
</view>
<text class="ledger-points" :class="{ reverse: item.direction === 'REVERSE' }">
{{ item.direction === 'REVERSE' ? '-' : '+' }}{{ Math.abs(item.points) }}{{ item.accountType === 'STUDY_CREDIT' ? ' 学分' : ' 积分' }}
</text>
</view>
</view>
<text v-else class="muted empty">暂无积分明细</text>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import type { IncentiveBalance, IncentiveLedgerItem } from '@/types/api';
import { getMyIncentiveBalances, getMyIncentiveLedger } from '@/services/questions';
const balances = ref<IncentiveBalance[]>([]);
const ledger = ref<IncentiveLedgerItem[]>([]);
const message = ref('');
const goBack = () => uni.navigateBack({ delta: 1 });
const load = async () => {
message.value = '';
try { [balances.value, ledger.value] = await Promise.all([getMyIncentiveBalances(), getMyIncentiveLedger()]); }
catch (error) { message.value = error instanceof Error ? error.message : '积分读取失败'; }
};
onShow(() => { void load(); });
</script>
<style scoped>
.points-page { max-width: var(--mobile-shell-max-width); margin: 0 auto; }
.status-message { display: block; margin-top: 14px; color: #a9000d; }
.balance-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 18px; }
.balance-card { display: grid; gap: 4px; padding: 18px; }
.balance-label, .balance-unit { color: var(--muted); font-size: 12px; }
.balance-value { color: var(--brand); font-size: 34px; font-weight: 900; }
.rules-card { color: var(--muted); font-size: 13px; line-height: 1.65; }
.rules-card .panel-title { display: block; margin-bottom: 8px; }
.ledger-card { display: grid; gap: 12px; }
.ledger-list { display: grid; }
.ledger-row { display: flex; gap: 12px; align-items: center; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid var(--line); }
.ledger-title, .ledger-time { display: block; }
.ledger-title { font-weight: 800; }
.ledger-time { margin-top: 4px; color: var(--muted); font-size: 12px; }
.ledger-points { color: var(--success); font-size: 18px; font-weight: 900; }
.ledger-points.reverse { color: var(--brand); }
.empty { padding: 8px 0; }
</style>