|
|
@@ -0,0 +1,214 @@
|
|
|
+<template>
|
|
|
+ <div class="health-plan-review">
|
|
|
+ <div class="page-header">
|
|
|
+ <h2>健康方案审核</h2>
|
|
|
+ <div class="filters">
|
|
|
+ <el-select v-model="familyFilter" placeholder="选择家庭" clearable @change="loadPlans" style="width:180px">
|
|
|
+ <el-option v-for="f in families" :key="f.id" :label="f.familyName || '家庭'+f.id" :value="f.id" />
|
|
|
+ </el-select>
|
|
|
+ <el-select v-model="statusFilter" placeholder="状态筛选" clearable @change="loadPlans" style="width:140px;margin-left:10px">
|
|
|
+ <el-option label="待审核" value="pending_review" />
|
|
|
+ <el-option label="草稿" value="draft" />
|
|
|
+ <el-option label="已驳回" value="rejected" />
|
|
|
+ </el-select>
|
|
|
+ <el-button type="primary" @click="loadPlans" style="margin-left:10px">查询</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table :data="plans" border stripe style="width:100%" v-loading="loading">
|
|
|
+ <el-table-column prop="id" label="方案ID" width="80" />
|
|
|
+ <el-table-column label="家庭成员" width="150">
|
|
|
+ <template slot-scope="{ row }">{{ row.memberName || row.memberIds }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="目标" min-width="180">
|
|
|
+ <template slot-scope="{ row }">{{ row.goal ? row.goal.substring(0,60) + (row.goal.length>60?'...':'') : '-' }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="维度" width="120">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-tag v-for="(d,i) in (row.dimensions||'').split(',')" :key="i" size="mini" style="margin-right:4px">{{ d }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="状态" width="100">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-tag :type="statusType(row.status)">{{ statusLabel(row.status) }}</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="reviewComment" label="审核意见" width="150">
|
|
|
+ <template slot-scope="{ row }">{{ row.reviewComment || '-' }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="createdAt" label="创建时间" width="160" />
|
|
|
+ <el-table-column label="操作" width="220">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-button size="mini" type="primary" @click="showEdit(row)">编辑</el-button>
|
|
|
+ <el-button v-if="row.status==='pending_review'||row.status==='draft'" size="mini" type="success" @click="handleApprove(row)">通过</el-button>
|
|
|
+ <el-button v-if="row.status==='pending_review'||row.status==='draft'" size="mini" type="danger" @click="showReject(row)">驳回</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 编辑弹窗 -->
|
|
|
+ <el-dialog title="编辑健康方案" :visible.sync="editVisible" width="700px" destroy-on-close>
|
|
|
+ <el-form label-width="90px" v-if="currentPlan">
|
|
|
+ <el-form-item label="方案内容">
|
|
|
+ <el-input v-model="editForm.planContent" type="textarea" :rows="18" placeholder="编辑方案内容..." />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="审核意见">
|
|
|
+ <el-input v-model="editForm.reviewComment" type="textarea" :rows="3" placeholder="可选:添加审核备注" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer">
|
|
|
+ <el-button @click="editVisible=false">取消</el-button>
|
|
|
+ <el-button type="primary" :loading="saving" @click="saveEdit">保存修改</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 驳回弹窗 -->
|
|
|
+ <el-dialog title="驳回方案" :visible.sync="rejectVisible" width="420px">
|
|
|
+ <el-form label-width="80px">
|
|
|
+ <el-form-item label="驳回原因">
|
|
|
+ <el-input v-model="rejectForm.comment" type="textarea" :rows="4" placeholder="请输入驳回原因" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer">
|
|
|
+ <el-button @click="rejectVisible=false">取消</el-button>
|
|
|
+ <el-button type="danger" :loading="rejecting" @click="confirmReject">确认驳回</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { getPendingReviewPlans, updatePlanContent, approvePlan, rejectPlan, getHealthPlanDetail } from '@/api/healthPlan'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'HealthPlanReview',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ plans: [],
|
|
|
+ families: [],
|
|
|
+ familyFilter: '',
|
|
|
+ statusFilter: '',
|
|
|
+ loading: false,
|
|
|
+ editVisible: false,
|
|
|
+ rejectVisible: false,
|
|
|
+ saving: false,
|
|
|
+ rejecting: false,
|
|
|
+ currentPlan: null,
|
|
|
+ editForm: { planContent: '', reviewComment: '' },
|
|
|
+ rejectForm: { planId: null, comment: '' }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.loadFamilies()
|
|
|
+ this.loadPlans()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async loadFamilies() {
|
|
|
+ try {
|
|
|
+ const res = await fetch('/api/family/list', {
|
|
|
+ method: 'POST',
|
|
|
+ headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + localStorage.getItem('token') },
|
|
|
+ body: JSON.stringify({})
|
|
|
+ })
|
|
|
+ const json = await res.json()
|
|
|
+ if (json.code === 200) this.families = json.data || []
|
|
|
+ } catch(e) {}
|
|
|
+ },
|
|
|
+ async loadPlans() {
|
|
|
+ this.loading = true
|
|
|
+ try {
|
|
|
+ const res = await getPendingReviewPlans({
|
|
|
+ familyId: this.familyFilter || null,
|
|
|
+ status: this.statusFilter || null
|
|
|
+ })
|
|
|
+ if (res.code === 200) this.plans = res.data || []
|
|
|
+ } catch(e) {
|
|
|
+ this.$message.error('加载失败')
|
|
|
+ } finally {
|
|
|
+ this.loading = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ statusType(s) {
|
|
|
+ const map = { pending_review: 'warning', draft: 'info', published: 'success', rejected: 'danger' }
|
|
|
+ return map[s] || 'info'
|
|
|
+ },
|
|
|
+ statusLabel(s) {
|
|
|
+ const map = { pending_review: '待审核', draft: '草稿', published: '已发布', rejected: '已驳回' }
|
|
|
+ return map[s] || s
|
|
|
+ },
|
|
|
+ showEdit(row) {
|
|
|
+ this.currentPlan = row
|
|
|
+ this.editForm = {
|
|
|
+ planContent: row.planContent || '',
|
|
|
+ reviewComment: row.reviewComment || ''
|
|
|
+ }
|
|
|
+ this.editVisible = true
|
|
|
+ },
|
|
|
+ async saveEdit() {
|
|
|
+ this.saving = true
|
|
|
+ try {
|
|
|
+ const res = await updatePlanContent({
|
|
|
+ planId: this.currentPlan.id,
|
|
|
+ planContent: this.editForm.planContent,
|
|
|
+ planJson: this.currentPlan.planJson
|
|
|
+ })
|
|
|
+ if (res.code === 200) {
|
|
|
+ this.$message.success('保存成功')
|
|
|
+ this.editVisible = false
|
|
|
+ this.loadPlans()
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.message || '保存失败')
|
|
|
+ }
|
|
|
+ } catch(e) {
|
|
|
+ this.$message.error('请求失败')
|
|
|
+ } finally {
|
|
|
+ this.saving = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ showReject(row) {
|
|
|
+ this.rejectForm = { planId: row.id, comment: '' }
|
|
|
+ this.rejectVisible = true
|
|
|
+ },
|
|
|
+ async confirmReject() {
|
|
|
+ this.rejecting = true
|
|
|
+ try {
|
|
|
+ const res = await rejectPlan({
|
|
|
+ planId: this.rejectForm.planId,
|
|
|
+ comment: this.rejectForm.comment
|
|
|
+ })
|
|
|
+ if (res.code === 200) {
|
|
|
+ this.$message.success('已驳回')
|
|
|
+ this.rejectVisible = false
|
|
|
+ this.loadPlans()
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.message || '操作失败')
|
|
|
+ }
|
|
|
+ } catch(e) {
|
|
|
+ this.$message.error('请求失败')
|
|
|
+ } finally {
|
|
|
+ this.rejecting = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async handleApprove(row) {
|
|
|
+ try {
|
|
|
+ const res = await approvePlan({ planId: row.id })
|
|
|
+ if (res.code === 200) {
|
|
|
+ this.$message.success('方案已发布,任务自动生成')
|
|
|
+ this.loadPlans()
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.message || '操作失败')
|
|
|
+ }
|
|
|
+ } catch(e) {
|
|
|
+ this.$message.error('请求失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.health-plan-review { padding: 20px; }
|
|
|
+.page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
|
|
|
+.page-header h2 { margin: 0; font-size: 20px; }
|
|
|
+.filters { display: flex; align-items: center; }
|
|
|
+</style>
|