| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- <template>
- <el-dialog
- :visible.sync="dialogVisible"
- title="家庭信息"
- width="900px"
- top="6vh"
- @open="load"
- :close-on-click-modal="false"
- >
- <div v-loading="loading">
- <template v-if="overview && overview.family">
- <el-descriptions :column="2" border>
- <el-descriptions-item label="家庭名称">{{ overview.family.name }}</el-descriptions-item>
- <el-descriptions-item label="邀请码">{{ overview.family.inviteCode || '-' }}</el-descriptions-item>
- <el-descriptions-item label="主账号">{{ overview.creatorRealName || overview.creatorName || '-' }}</el-descriptions-item>
- <el-descriptions-item label="创建时间">{{ formatDate(overview.family.createdAt) }}</el-descriptions-item>
- </el-descriptions>
- <div class="count-cards">
- <StatCard label="报告" :value="counts.reports" color="primary" clickable @click="activeTab = 'reports'" />
- <StatCard label="方案" :value="counts.plans" color="success" clickable @click="activeTab = 'plans'" />
- <StatCard label="任务" :value="counts.tasks" color="warning" clickable @click="activeTab = 'tasks'" />
- </div>
- <el-tabs v-model="activeTab">
- <el-tab-pane label="报告" name="reports">
- <el-table :data="overview.reports || []" border max-height="300">
- <el-table-column label="类型">
- <template slot-scope="{ row }">
- <StatusTag :options="reportTypeOptions" :value="row.reportType" />
- </template>
- </el-table-column>
- <el-table-column prop="reportNumber" label="报告编号" width="140" />
- <el-table-column label="日期">
- <template slot-scope="{ row }">{{ formatDate(row.reportDate) }}</template>
- </el-table-column>
- <el-table-column prop="personName" label="姓名" />
- <el-table-column label="状态">
- <template slot-scope="{ row }">
- <StatusTag :options="reportStatusOptions" :value="row.status" />
- </template>
- </el-table-column>
- <el-table-column prop="overallScore" label="总分" width="70" />
- <el-table-column prop="gutHealthScore" label="肠道分" width="80" />
- </el-table>
- </el-tab-pane>
- <el-tab-pane label="方案" name="plans">
- <el-table :data="overview.plans || []" border max-height="300">
- <el-table-column label="类型">
- <template slot-scope="{ row }">
- <StatusTag :options="planTypeOptions" :value="row.planType" />
- </template>
- </el-table-column>
- <el-table-column prop="memberName" label="成员" />
- <el-table-column prop="goal" label="目标" show-overflow-tooltip />
- <el-table-column label="状态">
- <template slot-scope="{ row }">
- <StatusTag :options="planStatusOptions" :value="row.status" />
- </template>
- </el-table-column>
- <el-table-column prop="totalDays" label="天数" width="70" />
- <el-table-column label="创建时间">
- <template slot-scope="{ row }">{{ formatDate(row.createdAt) }}</template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- <el-tab-pane label="任务" name="tasks">
- <el-table :data="tasks" border max-height="300">
- <el-table-column prop="title" label="标题" show-overflow-tooltip />
- <el-table-column label="状态">
- <template slot-scope="{ row }">
- <StatusTag :options="taskStatusOptions" :value="row.status" />
- </template>
- </el-table-column>
- <el-table-column prop="category" label="分类" width="110" />
- <el-table-column prop="points" label="积分" width="70" />
- <el-table-column label="截止">
- <template slot-scope="{ row }">{{ formatDate(row.deadline) }}</template>
- </el-table-column>
- </el-table>
- <el-pagination
- class="pagination-right"
- @current-change="loadTasks"
- :current-page="taskPage"
- :page-size="taskSize"
- :total="taskTotal"
- layout="total, prev, pager, next"
- />
- </el-tab-pane>
- </el-tabs>
- </template>
- <el-empty v-else :description="loading ? '加载中...' : '暂无数据'" />
- </div>
- </el-dialog>
- </template>
- <script>
- import { getFamilyOverview, getFamilyTasks } from '@/api/admin'
- import { formatDate } from '@/utils/format'
- import StatCard from '@/components/StatCard.vue'
- import StatusTag from '@/components/StatusTag.vue'
- export default {
- name: 'FamilyOverviewDialog',
- props: {
- /** 弹窗可见性,父组件通过 :visible.sync 控制 */
- visible: { type: Boolean, default: false },
- /** 家庭 ID,变化或弹窗打开时触发加载 */
- familyId: { type: [Number, String], default: null }
- },
- data() {
- return {
- loading: false,
- overview: null,
- activeTab: 'reports',
- tasks: [],
- taskPage: 1,
- taskSize: 20,
- taskTotal: 0,
- reportTypeOptions: [
- { value: 'gut_flora', label: '菌群检测', type: 'success' },
- { value: 'physical_exam', label: '体检报告', type: 'primary' },
- { value: 'dan', label: 'DAN测评', type: 'warning' },
- { value: 'brain_status', label: '脑状态', type: 'primary' },
- { value: 'aptitude', label: '先天潜能', type: 'primary' },
- { value: 'insurance', label: '保单', type: 'info' },
- { value: 'fortune', label: '家庭周报', type: 'danger' }
- ],
- reportStatusOptions: [
- { value: 'active', label: '生效', type: 'success' },
- { value: 'archived', label: '已归档', type: 'warning' },
- { value: 'deleted', label: '已删除', type: 'info' }
- ],
- planTypeOptions: [
- { value: 'health_plan', label: '健康方案', type: 'primary' },
- { value: 'family_attribution_plan', label: '家庭归因方案', type: 'warning' }
- ],
- planStatusOptions: [
- { value: 'draft', label: '草稿', type: 'info' },
- { value: 'pending_review', label: '待审核', type: 'warning' },
- { value: 'published', label: '已发布', type: 'success' },
- { value: 'rejected', label: '已驳回', type: 'danger' }
- ],
- taskStatusOptions: [
- { value: 'pending', label: '进行中', type: 'warning' },
- { value: 'pending_review', label: '待审核', type: 'warning' },
- { value: 'completed', label: '已完成', type: 'success' },
- { value: 'locked', label: '前置锁定', type: 'info' },
- { value: 'assigned', label: '待接受', type: 'info' },
- { value: 'in_progress', label: '进行中', type: 'warning' },
- { value: 'rejected', label: '已拒绝', type: 'danger' },
- { value: 'overdue', label: '已过期', type: 'danger' },
- { value: 'cancelled', label: '已取消', type: 'info' }
- ]
- }
- },
- computed: {
- /**
- * 受控 dialog 可见性:写时派发 update:visible,保证父组件的 :visible.sync 同步。
- * (el-dialog 关闭时 emit update:visible(false),若直接绑 visible prop 会导致
- * 直接修改 prop 且无法回传父组件,故用计算属性桥接。)
- */
- dialogVisible: {
- get() {
- return this.visible
- },
- set(val) {
- this.$emit('update:visible', val)
- }
- },
- /** 计数卡片数据源(overview 未加载时兜底为空对象,避免 counts.xxx 报错) */
- counts() {
- return (this.overview && this.overview.counts) || {}
- }
- },
- watch: {
- /** 家庭 ID 变化时(弹窗已打开)重新加载 */
- familyId() {
- if (this.visible) this.load()
- }
- },
- methods: {
- formatDate,
- async load() {
- if (!this.familyId) return
- this.loading = true
- this.overview = null
- this.tasks = []
- this.taskTotal = 0
- this.taskPage = 1
- try {
- const res = await getFamilyOverview(this.familyId)
- this.overview = res.data
- this.loadTasks(1)
- } catch (e) {
- this.$message.error('加载家庭信息失败')
- } finally {
- this.loading = false
- }
- },
- async loadTasks(page) {
- this.taskPage = page
- try {
- const res = await getFamilyTasks(this.familyId, { page, size: this.taskSize })
- this.tasks = res.data.records || []
- this.taskTotal = res.data.total || 0
- } catch (e) {
- this.$message.error('加载任务列表失败')
- }
- }
- }
- }
- </script>
- <style scoped>
- .count-cards {
- display: flex;
- gap: 16px;
- margin: 16px 0;
- }
- .count-cards >>> .adm-stat-card {
- flex: 1;
- }
- .pagination-right {
- margin-top: 12px;
- text-align: right;
- }
- </style>
|