|
@@ -63,33 +63,7 @@
|
|
|
<el-pagination v-if="listTotal > listSize" @current-change="onListPageChange" :current-page="listPage" :page-size="listSize" :total="listTotal" layout="total, prev, pager, next" style="margin-top:16px;text-align:right" />
|
|
<el-pagination v-if="listTotal > listSize" @current-change="onListPageChange" :current-page="listPage" :page-size="listSize" :total="listTotal" layout="total, prev, pager, next" style="margin-top:16px;text-align:right" />
|
|
|
</el-tab-pane>
|
|
</el-tab-pane>
|
|
|
|
|
|
|
|
- <!-- Tab 2: 报告审核 -->
|
|
|
|
|
- <el-tab-pane label="报告审核" name="audit">
|
|
|
|
|
- <el-table :data="auditList" v-loading="auditLoading" border stripe :max-height="tableHeight">
|
|
|
|
|
- <el-table-column prop="id" label="草稿ID" width="80" />
|
|
|
|
|
- <el-table-column label="上传用户" width="140">
|
|
|
|
|
- <template slot-scope="{ row }">{{ row.userName || '用户' + row.userId }}</template>
|
|
|
|
|
- </el-table-column>
|
|
|
|
|
- <el-table-column prop="reportType" label="报告类型" width="120" />
|
|
|
|
|
- <el-table-column prop="originalFilename" label="文件名" min-width="200" show-overflow-tooltip />
|
|
|
|
|
- <el-table-column label="状态" width="100">
|
|
|
|
|
- <template slot-scope="{ row }"><el-tag type="warning">待审核</el-tag></template>
|
|
|
|
|
- </el-table-column>
|
|
|
|
|
- <el-table-column label="上传时间" width="160">
|
|
|
|
|
- <template slot-scope="{ row }">{{ formatTime(row.createdAt) }}</template>
|
|
|
|
|
- </el-table-column>
|
|
|
|
|
- <el-table-column label="操作" width="240">
|
|
|
|
|
- <template slot-scope="{ row }">
|
|
|
|
|
- <el-button size="mini" type="primary" @click="viewAuditDetail(row)">查看详情</el-button>
|
|
|
|
|
- <el-button size="mini" type="success" @click="handleAuditConfirm(row)">确认</el-button>
|
|
|
|
|
- <el-button size="mini" type="danger" @click="handleAuditDiscard(row)">丢弃</el-button>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-table-column>
|
|
|
|
|
- </el-table>
|
|
|
|
|
- <el-pagination v-if="auditTotal > auditSize" @current-change="onAuditPageChange" :current-page="auditPage" :page-size="auditSize" :total="auditTotal" layout="total, prev, pager, next" class="pagination-wrap" />
|
|
|
|
|
- </el-tab-pane>
|
|
|
|
|
-
|
|
|
|
|
- <!-- Tab 3: 代传报告 -->
|
|
|
|
|
|
|
+ <!-- Tab 2: 代传报告 -->
|
|
|
<el-tab-pane label="代传报告" name="proxy">
|
|
<el-tab-pane label="代传报告" name="proxy">
|
|
|
<el-form ref="uploadForm" :model="uploadForm" label-width="100px" class="upload-form">
|
|
<el-form ref="uploadForm" :model="uploadForm" label-width="100px" class="upload-form">
|
|
|
<el-form-item label="选择家庭" prop="familyId" required>
|
|
<el-form-item label="选择家庭" prop="familyId" required>
|
|
@@ -195,64 +169,6 @@
|
|
|
</el-descriptions>
|
|
</el-descriptions>
|
|
|
<span slot="footer"><el-button @click="detailDialogVisible = false">关闭</el-button></span>
|
|
<span slot="footer"><el-button @click="detailDialogVisible = false">关闭</el-button></span>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
-
|
|
|
|
|
- <!-- 审核详情弹窗 -->
|
|
|
|
|
- <el-dialog title="审核详情" :visible.sync="auditDetailVisible" width="800px">
|
|
|
|
|
- <div v-if="auditDetail">
|
|
|
|
|
- <el-descriptions :column="2" border>
|
|
|
|
|
- <el-descriptions-item label="草稿ID">{{ auditDetail.id }}</el-descriptions-item>
|
|
|
|
|
- <el-descriptions-item label="上传用户">{{ auditDetail.userName || '用户' + auditDetail.userId }}</el-descriptions-item>
|
|
|
|
|
- <el-descriptions-item label="报告类型">{{ auditDetail.reportType }}</el-descriptions-item>
|
|
|
|
|
- <el-descriptions-item label="文件名">{{ auditDetail.originalFilename }}</el-descriptions-item>
|
|
|
|
|
- <el-descriptions-item label="上传时间">{{ formatTime(auditDetail.createdAt) }}</el-descriptions-item>
|
|
|
|
|
- <el-descriptions-item label="过期时间">{{ formatTime(auditDetail.expireAt) }}</el-descriptions-item>
|
|
|
|
|
- </el-descriptions>
|
|
|
|
|
- <el-divider content-position="left">解析数据</el-divider>
|
|
|
|
|
- <div v-if="parsedPayload">
|
|
|
|
|
- <el-row :gutter="20" style="margin-bottom:16px">
|
|
|
|
|
- <el-col :span="6" v-for="(val, key) in scoreFields" :key="key">
|
|
|
|
|
- <div class="score-card" :style="{ borderColor: scoreColor(val.value) }">
|
|
|
|
|
- <div class="score-label">{{ val.label }}</div>
|
|
|
|
|
- <div class="score-value" :style="{ color: scoreColor(val.value) }">{{ val.value ?? '-' }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- </el-row>
|
|
|
|
|
- <el-tabs v-model="auditTab">
|
|
|
|
|
- <el-tab-pane label="指标" name="indicators">
|
|
|
|
|
- <el-table :data="parsedPayload.indicators || []" border size="small" :max-height="tableHeight">
|
|
|
|
|
- <el-table-column prop="category" label="类别" width="100" />
|
|
|
|
|
- <el-table-column prop="indicatorName" label="指标名称" width="160" />
|
|
|
|
|
- <el-table-column prop="indicatorValue" label="检测值" width="100" />
|
|
|
|
|
- <el-table-column prop="unit" label="单位" width="80" />
|
|
|
|
|
- <el-table-column prop="refRange" label="参考范围" width="140" />
|
|
|
|
|
- <el-table-column prop="status" label="状态" width="80">
|
|
|
|
|
- <template slot-scope="{ row }">
|
|
|
|
|
- <el-tag :type="row.status === '异常' ? 'danger' : 'success'" size="small">{{ row.status || '正常' }}</el-tag>
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-table-column>
|
|
|
|
|
- </el-table>
|
|
|
|
|
- </el-tab-pane>
|
|
|
|
|
- <el-tab-pane label="菌群" name="gutFlora">
|
|
|
|
|
- <el-table :data="parsedPayload.gutFlora || []" border size="small" :max-height="tableHeight">
|
|
|
|
|
- <el-table-column prop="bacteriaName" label="菌种" width="160" />
|
|
|
|
|
- <el-table-column prop="bacteriaValue" label="检测值" width="100" />
|
|
|
|
|
- <el-table-column prop="normalRange" label="正常范围" width="140" />
|
|
|
|
|
- <el-table-column prop="populationLevel" label="水平" width="80" />
|
|
|
|
|
- <el-table-column prop="level" label="级别" width="80" />
|
|
|
|
|
- </el-table>
|
|
|
|
|
- </el-tab-pane>
|
|
|
|
|
- <el-tab-pane label="疾病风险" name="diseaseRisks">
|
|
|
|
|
- <el-table :data="parsedPayload.diseaseRisks || []" border size="small" :max-height="tableHeight">
|
|
|
|
|
- <el-table-column prop="diseaseName" label="疾病" width="200" />
|
|
|
|
|
- <el-table-column prop="riskValue" label="风险值" width="100" />
|
|
|
|
|
- <el-table-column prop="riskLevel" label="风险等级" width="100" />
|
|
|
|
|
- </el-table>
|
|
|
|
|
- </el-tab-pane>
|
|
|
|
|
- </el-tabs>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div v-else><el-alert title="无法解析负载数据" type="warning" :closable="false" /></div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </el-dialog>
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -260,7 +176,6 @@
|
|
|
import axios from 'axios'
|
|
import axios from 'axios'
|
|
|
import { getFamilyList, getFamilyMemberList } from '@/api/admin'
|
|
import { getFamilyList, getFamilyMemberList } from '@/api/admin'
|
|
|
import { proxyParseReport, proxyConfirmReport, listHealthReports, getHealthReportDetail } from '@/api/admin'
|
|
import { proxyParseReport, proxyConfirmReport, listHealthReports, getHealthReportDetail } from '@/api/admin'
|
|
|
-import { searchUsers } from '@/api/admin'
|
|
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
name: 'UnifiedHealthReports',
|
|
name: 'UnifiedHealthReports',
|
|
@@ -277,16 +192,6 @@ export default {
|
|
|
query: { type: '', keyword: '' },
|
|
query: { type: '', keyword: '' },
|
|
|
dateRange: [],
|
|
dateRange: [],
|
|
|
|
|
|
|
|
- // 报告审核
|
|
|
|
|
- auditList: [],
|
|
|
|
|
- auditLoading: false,
|
|
|
|
|
- auditPage: 1,
|
|
|
|
|
- auditSize: 20,
|
|
|
|
|
- auditTotal: 0,
|
|
|
|
|
- auditDetailVisible: false,
|
|
|
|
|
- auditDetail: null,
|
|
|
|
|
- auditTab: 'indicators',
|
|
|
|
|
-
|
|
|
|
|
// 代传报告
|
|
// 代传报告
|
|
|
uploading: false,
|
|
uploading: false,
|
|
|
confirming: false,
|
|
confirming: false,
|
|
@@ -309,32 +214,14 @@ export default {
|
|
|
computed: {
|
|
computed: {
|
|
|
tableHeight() {
|
|
tableHeight() {
|
|
|
return window.innerHeight - 280
|
|
return window.innerHeight - 280
|
|
|
- },
|
|
|
|
|
- parsedPayload() {
|
|
|
|
|
- if (!this.auditDetail || !this.auditDetail.payloadJson) return null
|
|
|
|
|
- try {
|
|
|
|
|
- var p = JSON.parse(this.auditDetail.payloadJson)
|
|
|
|
|
- return typeof p === 'string' ? JSON.parse(p) : p
|
|
|
|
|
- } catch { return null }
|
|
|
|
|
- },
|
|
|
|
|
- scoreFields() {
|
|
|
|
|
- if (!this.parsedPayload) return []
|
|
|
|
|
- var p = this.parsedPayload
|
|
|
|
|
- return [
|
|
|
|
|
- { label: '综合评分', value: p.overallScore, key: 'overallScore' },
|
|
|
|
|
- { label: '肠道健康', value: p.gutHealthScore, key: 'gutHealthScore' },
|
|
|
|
|
- { label: '慢病风险', value: p.chronicDiseaseScore, key: 'chronicDiseaseScore' },
|
|
|
|
|
- { label: '营养评分', value: p.nutritionScore, key: 'nutritionScore' }
|
|
|
|
|
- ]
|
|
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
mounted() {
|
|
mounted() {
|
|
|
var tab = this.$route.query.tab
|
|
var tab = this.$route.query.tab
|
|
|
- if (tab && ['list', 'audit', 'proxy'].indexOf(tab) >= 0) {
|
|
|
|
|
|
|
+ if (tab && ['list', 'proxy'].indexOf(tab) >= 0) {
|
|
|
this.activeTab = tab
|
|
this.activeTab = tab
|
|
|
}
|
|
}
|
|
|
this.loadReportList()
|
|
this.loadReportList()
|
|
|
- this.loadAuditList()
|
|
|
|
|
this.loadFamilies()
|
|
this.loadFamilies()
|
|
|
this.loadProxyReports()
|
|
this.loadProxyReports()
|
|
|
},
|
|
},
|
|
@@ -386,67 +273,6 @@ export default {
|
|
|
.catch(function() { this.$message.error('分析失败') }.bind(this))
|
|
.catch(function() { this.$message.error('分析失败') }.bind(this))
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // ===== 报告审核 =====
|
|
|
|
|
- async loadAuditList() {
|
|
|
|
|
- this.auditLoading = true
|
|
|
|
|
- try {
|
|
|
|
|
- var baseURL = process.env.VUE_APP_BASE_API || ''
|
|
|
|
|
- var token = localStorage.getItem('token')
|
|
|
|
|
- var axios_ = this.$axios || (await import('axios')).default
|
|
|
|
|
- var res = await axios_.post(baseURL + '/api/health/report/audit/pending', { page: this.auditPage, size: this.auditSize }, {
|
|
|
|
|
- headers: { Authorization: 'Bearer ' + token }
|
|
|
|
|
- })
|
|
|
|
|
- var records = res.data && res.data.data ? (res.data.data.records || res.data.data) : []
|
|
|
|
|
- this.auditList = records
|
|
|
|
|
- this.auditTotal = res.data && res.data.data ? (res.data.data.total || records.length) : records.length
|
|
|
|
|
- await this.resolveUserNames(records, 'userId')
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- this.$message.error('加载审核列表失败')
|
|
|
|
|
- } finally {
|
|
|
|
|
- this.auditLoading = false
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- onAuditPageChange(val) { this.auditPage = val; this.loadAuditList() },
|
|
|
|
|
- viewAuditDetail(row) {
|
|
|
|
|
- this.auditDetail = row
|
|
|
|
|
- this.auditTab = 'indicators'
|
|
|
|
|
- this.auditDetailVisible = true
|
|
|
|
|
- },
|
|
|
|
|
- async handleAuditConfirm(row) {
|
|
|
|
|
- try {
|
|
|
|
|
- await this.$confirm('确认草稿 #' + row.id + '?确认后将生成正式报告。', '提示', { type: 'warning' })
|
|
|
|
|
- var baseURL = process.env.VUE_APP_BASE_API || ''
|
|
|
|
|
- var token = localStorage.getItem('token')
|
|
|
|
|
- var axios_ = this.$axios || (await import('axios')).default
|
|
|
|
|
- await axios_.post(baseURL + '/api/health/report/audit/confirm', { draftId: row.id }, { headers: { Authorization: 'Bearer ' + token } })
|
|
|
|
|
- this.$message.success('审核确认完成')
|
|
|
|
|
- this.loadAuditList()
|
|
|
|
|
- } catch (e) { if (e !== 'cancel') this.$message.error('确认失败') }
|
|
|
|
|
- },
|
|
|
|
|
- async handleAuditDiscard(row) {
|
|
|
|
|
- try {
|
|
|
|
|
- await this.$confirm('确认丢弃草稿 #' + row.id + '?丢弃后不可恢复。', '警告', { type: 'warning' })
|
|
|
|
|
- var baseURL = process.env.VUE_APP_BASE_API || ''
|
|
|
|
|
- var token = localStorage.getItem('token')
|
|
|
|
|
- var axios_ = this.$axios || (await import('axios')).default
|
|
|
|
|
- await axios_.post(baseURL + '/api/health/report/audit/discard', { draftId: row.id }, { headers: { Authorization: 'Bearer ' + token } })
|
|
|
|
|
- this.$message.success('已丢弃')
|
|
|
|
|
- this.loadAuditList()
|
|
|
|
|
- } catch (e) { if (e !== 'cancel') this.$message.error('操作失败') }
|
|
|
|
|
- },
|
|
|
|
|
- resolveUserNames(items, idField) {
|
|
|
|
|
- if (!items || items.length === 0) return Promise.resolve()
|
|
|
|
|
- var ids = []; var nameMap = {}
|
|
|
|
|
- items.forEach(function(item) { if (item[idField] && ids.indexOf(item[idField]) === -1) ids.push(item[idField]) })
|
|
|
|
|
- return Promise.all(ids.map(function(id) {
|
|
|
|
|
- return searchUsers({ keyword: String(id) }).then(function(res) {
|
|
|
|
|
- nameMap[id] = (res.data && res.data.length > 0) ? (res.data[0].nickname || res.data[0].realName || '用户' + id) : '用户' + id
|
|
|
|
|
- }).catch(function() { nameMap[id] = '用户' + id })
|
|
|
|
|
- })).then(function() {
|
|
|
|
|
- items.forEach(function(item) { item.userName = nameMap[item[idField]] || '用户' + item[idField] })
|
|
|
|
|
- })
|
|
|
|
|
- },
|
|
|
|
|
-
|
|
|
|
|
// ===== 代传报告 =====
|
|
// ===== 代传报告 =====
|
|
|
async loadFamilies() {
|
|
async loadFamilies() {
|
|
|
try { var res = await getFamilyList({ page: 1, size: 200 }); this.familyList = res.data && res.data.records ? res.data.records : (res.data || []) } catch (e) { console.error(e) }
|
|
try { var res = await getFamilyList({ page: 1, size: 200 }); this.familyList = res.data && res.data.records ? res.data.records : (res.data || []) } catch (e) { console.error(e) }
|