| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- <template>
- <div class="report-management">
- <el-card>
- <div class="filter-bar">
- <el-select v-model="query.type" placeholder="报告类型" clearable style="width:140px">
- <el-option label="全部" value=""></el-option>
- <el-option label="菌群检测" value="gut_flora"></el-option>
- <el-option label="体检报告" value="physical_exam"></el-option>
- <el-option label="DAN测评" value="dan"></el-option>
- <el-option label="保单" value="insurance"></el-option>
- <el-option label="家庭周报" value="fortune"></el-option>
- </el-select>
- <el-input v-model="query.keyword" placeholder="搜索标题/名称" style="width:200px" clearable @keyup.enter.native="loadData"></el-input>
- <el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" style="width:240px"></el-date-picker>
- <el-button type="primary" @click="loadData">查询</el-button>
- <el-button @click="doSync">同步数据</el-button>
- <el-button type="danger" :disabled="selectedRows.length === 0" @click="handleBatchArchive">批量归档({{ selectedRows.length }})</el-button>
- </div>
- <div class="adm-table-wrap">
- <el-table :data="tableData" border stripe v-loading="loading" style="margin-top:16px" height="100%"
- ref="listTable" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" :selectable="selectableRow" />
- <el-table-column prop="id" label="ID" width="80">
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="报告类型" width="100">
- <template slot-scope="scope">
- <el-tag size="small" :type="getTypeTag(scope.row.reportType)">{{ typeLabel(scope.row.reportType) }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column prop="title" label="标题" min-width="140" show-overflow-tooltip>
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('title', $event)">标题{{ sortIcon('title') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="报告主体" width="120">
- <template slot-scope="scope">{{ scope.row.subjectName || scope.row.childName || scope.row.personName || scope.row.userName || '-' }}</template>
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('subjectName', $event)">报告主体{{ sortIcon('subjectName') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="报告日期" width="120">
- <template slot-scope="scope">{{ formatDate(scope.row.reportDate) }}</template>
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('reportDate', $event)">报告日期{{ sortIcon('reportDate') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="综合评分" width="100">
- <template slot-scope="scope">
- <el-tag :type="scoreType(scope.row.overallScore)" size="small">{{ scope.row.overallScore == null ? '-' : scope.row.overallScore }}</el-tag>
- </template>
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('overallScore', $event)">综合评分{{ sortIcon('overallScore') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="状态" width="100">
- <template slot-scope="scope">
- <el-tag size="small">{{ scope.row.status || '已确认' }}</el-tag>
- </template>
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('status', $event)">状态{{ sortIcon('status') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" width="160">
- <template slot-scope="scope">{{ formatTime(scope.row.createdAt) }}</template>
- <template slot="header">
- <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">创建时间{{ sortIcon('createdAt') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" width="150" fixed="right">
- <template slot-scope="scope">
- <el-button size="mini" type="text" @click.stop="goEdit(scope.row)">编辑/详情</el-button>
- <el-button size="mini" type="text" @click.stop="archiveOne(scope.row)">归档</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- <el-pagination
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- :current-page="query.page"
- :page-size="query.size"
- :total="total"
- layout="total, prev, pager, next"
- style="margin-top:16px"
- ></el-pagination>
- </el-card>
- </div>
- </template>
- <script>
- import axios from 'axios'
- import SortMixin from '@/mixins/SortMixin'
- import { archiveReport, archiveReportsBatch } from '@/api/admin'
- export default {
- name: 'ReportManagement',
- mixins: [SortMixin],
- data() {
- return {
- tableData: [],
- sortableColumns: { id: 'ID', title: '标题', subjectName: '报告主体', reportDate: '报告日期', overallScore: '综合评分', createdAt: '创建时间' },
- total: 0,
- loading: false,
- selectedRows: [],
- query: {
- page: 1,
- size: 20,
- type: '',
- keyword: ''
- },
- dateRange: []
- }
- },
- created() {
- this.loadData()
- },
- methods: {
- loadList() {
- this.loadData()
- },
- loadData() {
- var self = this
- self.loading = true
- var params = {
- page: self.query.page,
- size: self.query.size,
- type: self.query.type,
- keyword: self.query.keyword
- }
- if (self.sortState.length > 0) params.sort = self.sortState
- if (self.dateRange && self.dateRange.length === 2) {
- params.startDate = self.dateRange[0].format ? self.dateRange[0].format('YYYY-MM-DD') : self.dateRange[0]
- params.endDate = self.dateRange[1].format ? self.dateRange[1].format('YYYY-MM-DD') : self.dateRange[1]
- }
- var baseURL = process.env.VUE_APP_BASE_API || ''
- var token = localStorage.getItem('token')
- axios.post(baseURL + '/api/health/report/admin-list', params, {
- headers: { Authorization: 'Bearer ' + token }
- }).then(function(res) {
- var data = res.data && res.data.data ? res.data.data : (res.data || [])
- self.tableData = data.records || []
- self.total = data.total || 0
- }).catch(function(e) {
- console.error(e)
- self.$message.error('加载报告列表失败')
- }).finally(function() {
- self.loading = false
- })
- },
- handleSizeChange(size) {
- this.query.size = size
- this.query.page = 1
- this.loadData()
- },
- handleCurrentChange(page) {
- this.query.page = page
- this.loadData()
- },
- doSync() {
- var self = this
- var baseURL = process.env.VUE_APP_BASE_API || ''
- var token = localStorage.getItem('token')
- axios.post(baseURL + '/api/admin/report-summary/sync', {}, {
- headers: { Authorization: 'Bearer ' + token }
- }).then(function(res) {
- if (res.data && res.data.code === 200) {
- self.$message.success('同步完成: ' + res.data.message)
- self.loadData()
- }
- }).catch(function(e) {
- self.$message.error('同步失败')
- })
- },
- goEdit(row) {
- if (!row || !row.id) return
- this.$router.push({ path: '/report-management/' + row.id })
- },
- selectableRow(row) {
- return !!(row && row.id)
- },
- handleSelectionChange(rows) {
- this.selectedRows = rows || []
- },
- archiveOne(row) {
- var self = this
- this.$confirm('确定要归档这份报告吗?归档后将在列表中消失(软删除)', '提示', {
- type: 'warning',
- confirmButtonText: '归档',
- cancelButtonText: '取消'
- }).then(function() {
- archiveReport(row.id).then(function() {
- self.$message.success('已归档')
- self.loadData()
- }).catch(function() {
- self.$message.error('归档失败')
- })
- }).catch(function() {})
- },
- handleBatchArchive() {
- var self = this
- var ids = this.selectedRows.map(function(r) { return r.id })
- if (ids.length === 0) return
- this.$confirm('确定要归档选中的 ' + ids.length + ' 份报告吗?归档后将在列表中消失(软删除)', '提示', {
- type: 'warning',
- confirmButtonText: '归档',
- cancelButtonText: '取消'
- }).then(function() {
- archiveReportsBatch(ids).then(function(res) {
- self.$message.success(res.message || ('已归档 ' + ids.length + ' 份报告'))
- self.selectedRows = []
- self.$refs.listTable && self.$refs.listTable.clearSelection()
- self.loadData()
- }).catch(function() {
- self.$message.error('批量归档失败')
- })
- }).catch(function() {})
- },
- typeLabel(type) {
- var map = { gut_flora: '菌群检测', physical_exam: '体检报告', dan: 'DAN测评', insurance: '保单', fortune: '家庭周报' }
- return map[type] || type || '-'
- },
- getTypeTag(type) {
- var map = { gut_flora: 'success', physical_exam: 'primary', dan: 'warning', insurance: 'info', fortune: 'danger' }
- return map[type] || 'info'
- },
- scoreType(score) {
- if (score == null) return 'info'
- if (score >= 80) return 'success'
- if (score >= 60) return 'warning'
- return 'danger'
- }
- }
- }
- </script>
- <style scoped>
- .report-management { padding: 16px; }
- .filter-bar {
- display: flex;
- flex-direction: row;
- align-items: center;
- gap: 12px;
- flex-wrap: wrap;
- }
- .sort-header {
- cursor: pointer;
- user-select: none;
- font-weight: 500;
- font-size: 12px;
- }
- .sort-header:hover {
- color: #409eff;
- }
- </style>
|