|
@@ -1,151 +1,175 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="reassign-container">
|
|
<div class="reassign-container">
|
|
|
- <div class="toolbar">
|
|
|
|
|
|
|
+ <div class="page-header">
|
|
|
<span>报告归属管理</span>
|
|
<span>报告归属管理</span>
|
|
|
- <a-button @click="refresh">刷新</a-button>
|
|
|
|
|
|
|
+ <el-button type="primary" size="small" icon="el-icon-refresh" @click="loadData">刷新</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <a-table
|
|
|
|
|
- :data="reports"
|
|
|
|
|
- :columns="columns"
|
|
|
|
|
- :loading="loading"
|
|
|
|
|
- :row-key="row => row.id"
|
|
|
|
|
- @selection-change="handleSelectionChange"
|
|
|
|
|
- >
|
|
|
|
|
- <template #row-actions="{ row }">
|
|
|
|
|
- <template v-if="row.subjectId">
|
|
|
|
|
- <!-- 已绑定:显示重新分配按钮 -->
|
|
|
|
|
- <a-dropdown v-dropdown="dropdown">
|
|
|
|
|
- <a-trigger>
|
|
|
|
|
- <a-icon type="setting" />
|
|
|
|
|
- </a-trigger>
|
|
|
|
|
- <a-menu>
|
|
|
|
|
- <a-menu-item @click="reassignRow(row)">重新分配</a-menu-item>
|
|
|
|
|
- </a-menu>
|
|
|
|
|
- </a-dropdown>
|
|
|
|
|
|
|
+ <!-- 家庭选择 -->
|
|
|
|
|
+ <el-form :inline="true" class="filter-bar">
|
|
|
|
|
+ <el-form-item label="选择家庭">
|
|
|
|
|
+ <el-select v-model="familyId" placeholder="请选择家庭" filterable clearable style="width: 260px" @change="loadData">
|
|
|
|
|
+ <el-option v-for="f in familyList" :key="f.id" :label="f.name" :value="f.id" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table :data="reports" v-loading="loading" border stripe>
|
|
|
|
|
+ <el-table-column prop="id" label="报告ID" width="100" />
|
|
|
|
|
+ <el-table-column prop="reportType" label="报告类型" width="120">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ <el-tag size="small">{{ row.reportType === 'gut_flora' ? '菌群检测' : row.reportType === 'physical_exam' ? '体检报告' : row.reportType }}</el-tag>
|
|
|
</template>
|
|
</template>
|
|
|
- <template v-else>
|
|
|
|
|
- <!-- 未绑定:显示绑定按钮 -->
|
|
|
|
|
- <a-button type="primary" size="small" @click="bindRow(row)">绑定归属</a-button>
|
|
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="报告对象" width="120">
|
|
|
|
|
+ <template slot-scope="{ row }">{{ row.personName || row.subjectName || '-' }}</template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="归属状态" width="120">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ <el-tag v-if="row.subjectId" type="success" size="small">已归属</el-tag>
|
|
|
|
|
+ <el-tag v-else type="warning" size="small">未归属</el-tag>
|
|
|
</template>
|
|
</template>
|
|
|
- </template>
|
|
|
|
|
- </a-table>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 选择成员弹窗 -->
|
|
|
|
|
- <a-modal :visible="visible" @ok="doReassign" @cancel="visible = false">
|
|
|
|
|
- <template #title>
|
|
|
|
|
- <span v="reassignMode">报告重新分配</span>
|
|
|
|
|
- <span v-else>绑定归属</span>
|
|
|
|
|
- </template>
|
|
|
|
|
- <template #body>
|
|
|
|
|
- <a-space direction="vertical" :space="8">
|
|
|
|
|
- <a-select
|
|
|
|
|
- :options="members"
|
|
|
|
|
- placeholder="选择家庭成员"
|
|
|
|
|
- @change="onMemberSelect"
|
|
|
|
|
- disabled="reassignMode && !row.subjectId"
|
|
|
|
|
- />
|
|
|
|
|
- </a-space>
|
|
|
|
|
- <!-- 如为重新分配模式,显示当前归属 -->
|
|
|
|
|
- <template v-if="reassignMode && row.subjectId">
|
|
|
|
|
- <p class="hint-text">当前归属:{{ getMemberName(row.subjectId) }}</p>
|
|
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="当前归属" width="120">
|
|
|
|
|
+ <template slot-scope="{ row }">{{ row.subjectId ? getMemberName(row.subjectId) : '-' }}</template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="reportDate" label="报告日期" width="120">
|
|
|
|
|
+ <template slot-scope="{ row }">{{ formatTime(row.reportDate) }}</template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="createdAt" label="上传时间" width="160">
|
|
|
|
|
+ <template slot-scope="{ row }">{{ formatTime(row.createdAt) }}</template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="操作" width="140" fixed="right">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ <el-button size="mini" type="primary" @click="openReassign(row)">重新分配</el-button>
|
|
|
</template>
|
|
</template>
|
|
|
- </template>
|
|
|
|
|
- <footer>
|
|
|
|
|
- <a-button @click="visible = false">取消</a-button>
|
|
|
|
|
- <a-button type="primary" @click="doConfirm">确认</a-button>
|
|
|
|
|
- </footer>
|
|
|
|
|
- </a-modal>
|
|
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 重新分配弹窗 -->
|
|
|
|
|
+ <el-dialog title="重新分配报告归属" :visible.sync="dialogVisible" width="480px" :close-on-click-modal="false">
|
|
|
|
|
+ <el-form label-width="90px">
|
|
|
|
|
+ <el-form-item label="报告ID">
|
|
|
|
|
+ <span>{{ currentReport && currentReport.id }}</span>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item v-if="currentReport && currentReport.subjectId" label="当前归属">
|
|
|
|
|
+ <span>{{ getMemberName(currentReport.subjectId) }}</span>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="归属成员">
|
|
|
|
|
+ <el-select v-model="newSubjectId" placeholder="选择归属成员(留空表示解除归属)" filterable clearable style="width: 100%">
|
|
|
|
|
+ <el-option v-for="m in memberList" :key="m.id" :label="m.nickname || m.realName || m.userId" :value="m.id" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <span slot="footer">
|
|
|
|
|
+ <el-button @click="dialogVisible = false">取消</el-button>
|
|
|
|
|
+ <el-button type="primary" :loading="saving" @click="doReassign">确认</el-button>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
-<script setup>
|
|
|
|
|
-import { ref, computed, watch } from 'vue'
|
|
|
|
|
-import { aTable, aSelect, aModal, aButton, aSpace, aMessage } from '/umi-design'
|
|
|
|
|
-import { request } from '/utils/api'
|
|
|
|
|
-
|
|
|
|
|
-const props = defineProps({
|
|
|
|
|
- familyId: { type: Number, required: true }
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const members = ref([])
|
|
|
|
|
-const reports = ref([])
|
|
|
|
|
-const loading = ref(false)
|
|
|
|
|
-const visible = ref(false)
|
|
|
|
|
-let currentRow = null
|
|
|
|
|
-let reassignMode = false // 'bind' | 'reassign'
|
|
|
|
|
-
|
|
|
|
|
-const columns = [
|
|
|
|
|
- { title: '报告ID', dataIndex: 'id', width: 100 },
|
|
|
|
|
- { title: '上传日期', dataIndex: 'reportDate', width: 120 },
|
|
|
|
|
- { title: '报告类型', dataIndex: 'reportType', width: 100 },
|
|
|
|
|
- { title: '主体', dataIndex: 'subjectDisplay', width: 100 },
|
|
|
|
|
- { title: '操作', dataIndex: 'actions', width: 120 }
|
|
|
|
|
-]
|
|
|
|
|
|
|
+<script>
|
|
|
|
|
+import { getFamilyList, getFamilyMemberList, reassignHealthReport, getUnlinkedReports } from '@/api/admin'
|
|
|
|
|
|
|
|
-// 从 API 获取成员列表
|
|
|
|
|
-const fetchMembers = async () => {
|
|
|
|
|
- const { data } = await request('/api/family/member/list', {
|
|
|
|
|
- includeFamily: true
|
|
|
|
|
- })
|
|
|
|
|
- members.value = data.result || data.list || []
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 刷新列表
|
|
|
|
|
-const refresh = async () => {
|
|
|
|
|
- loading.value = true
|
|
|
|
|
- const { data } = await request('/api/health/report/unlinked', { familyId: props.familyId })
|
|
|
|
|
- reports.value = data.result || data
|
|
|
|
|
- loading.value = false
|
|
|
|
|
- await fetchMembers()
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 绑定/重新分配行
|
|
|
|
|
-const bindRow = (row) => {
|
|
|
|
|
- currentRow = row
|
|
|
|
|
- reassignMode = false
|
|
|
|
|
- visible.value = true
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const reassignRow = (row) => {
|
|
|
|
|
- currentRow = row
|
|
|
|
|
- reassignMode = true
|
|
|
|
|
- visible.value = true
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 成员选择变化 - 保存选中的成员 ID
|
|
|
|
|
-const selectedMemberId = ref('')
|
|
|
|
|
-const onMemberSelect = (e) => {
|
|
|
|
|
- selectedMemberId.value = e.target.value
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 获取成员名称
|
|
|
|
|
-const getMemberName = (memberId) => {
|
|
|
|
|
- const m = members.value.find(x => x.id === memberId)
|
|
|
|
|
- return m ? (m.nickname || m.realName || m.userId.toString()) : '未知'
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 确认操作
|
|
|
|
|
-const doConfirm = async () => {
|
|
|
|
|
- if (currentRow.subjectId && reassignMode) {
|
|
|
|
|
- // 重新分配:发送新的 subjectId
|
|
|
|
|
- await request('/api/health/report/reassign', {
|
|
|
|
|
- reportId: currentRow.id,
|
|
|
|
|
- subjectId: selectedMemberId.value
|
|
|
|
|
- })
|
|
|
|
|
- } else if (!currentRow.subjectId && !reassignMode) {
|
|
|
|
|
- // 绑定:发送当前选中的 memberId
|
|
|
|
|
- await request('/api/health/report/reassign', {
|
|
|
|
|
- reportId: currentRow.id,
|
|
|
|
|
- subjectId: selectedMemberId.value
|
|
|
|
|
- })
|
|
|
|
|
|
|
+export default {
|
|
|
|
|
+ name: 'HealthReportReassign',
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ familyList: [],
|
|
|
|
|
+ familyId: null,
|
|
|
|
|
+ memberList: [],
|
|
|
|
|
+ reports: [],
|
|
|
|
|
+ loading: false,
|
|
|
|
|
+ saving: false,
|
|
|
|
|
+ dialogVisible: false,
|
|
|
|
|
+ currentReport: null,
|
|
|
|
|
+ newSubjectId: null
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ mounted() {
|
|
|
|
|
+ this.loadFamilies()
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ formatTime(t) {
|
|
|
|
|
+ return t ? String(t).replace('T', ' ').substring(0, 19) : '-'
|
|
|
|
|
+ },
|
|
|
|
|
+ getMemberName(memberId) {
|
|
|
|
|
+ if (!memberId) return '-'
|
|
|
|
|
+ var m = this.memberList.find(function(x) { return x.id === memberId })
|
|
|
|
|
+ return m ? (m.nickname || m.realName || m.userId) : String(memberId)
|
|
|
|
|
+ },
|
|
|
|
|
+ loadFamilies() {
|
|
|
|
|
+ getFamilyList({}).then(res => {
|
|
|
|
|
+ this.familyList = (res.data && res.data.list) || res.data || []
|
|
|
|
|
+ if (this.familyList.length > 0) {
|
|
|
|
|
+ this.familyId = this.familyList[0].id
|
|
|
|
|
+ this.loadData()
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(() => {
|
|
|
|
|
+ this.$message.error('获取家庭列表失败')
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ loadData() {
|
|
|
|
|
+ if (!this.familyId) {
|
|
|
|
|
+ this.reports = []
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.loading = true
|
|
|
|
|
+ getUnlinkedReports({ familyId: this.familyId }).then(res => {
|
|
|
|
|
+ this.reports = (res.data && res.data.list) || res.data || []
|
|
|
|
|
+ this.loadMembers()
|
|
|
|
|
+ }).catch(() => {
|
|
|
|
|
+ this.$message.error('加载报告列表失败')
|
|
|
|
|
+ }).finally(() => {
|
|
|
|
|
+ this.loading = false
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ loadMembers() {
|
|
|
|
|
+ getFamilyMemberList({ familyId: this.familyId }).then(res => {
|
|
|
|
|
+ this.memberList = (res.data && res.data.list) || res.data || []
|
|
|
|
|
+ }).catch(() => {
|
|
|
|
|
+ this.memberList = []
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ openReassign(row) {
|
|
|
|
|
+ this.currentReport = row
|
|
|
|
|
+ this.newSubjectId = row.subjectId || null
|
|
|
|
|
+ this.dialogVisible = true
|
|
|
|
|
+ },
|
|
|
|
|
+ doReassign() {
|
|
|
|
|
+ if (!this.currentReport) return
|
|
|
|
|
+ this.saving = true
|
|
|
|
|
+ reassignHealthReport({
|
|
|
|
|
+ reportId: this.currentReport.id,
|
|
|
|
|
+ subjectId: this.newSubjectId
|
|
|
|
|
+ }).then(res => {
|
|
|
|
|
+ this.$message.success('归属已更新')
|
|
|
|
|
+ this.dialogVisible = false
|
|
|
|
|
+ this.loadData()
|
|
|
|
|
+ }).catch(() => {
|
|
|
|
|
+ this.$message.error('归属更新失败')
|
|
|
|
|
+ }).finally(() => {
|
|
|
|
|
+ this.saving = false
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- visible.value = false
|
|
|
|
|
- await refresh()
|
|
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
-.reassign-container { margin: 16px; }
|
|
|
|
|
-.hint-text { color: #888; font-size: 12px; margin-top: 4px; }
|
|
|
|
|
|
|
+.reassign-container {
|
|
|
|
|
+ padding: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+.page-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+.filter-bar {
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|