feat(doctor): 添加医生站报卡管理功能
- 新增医生报卡统计、列表查询、详情查看等API接口 - 实现报卡的提交、撤回、删除、批量操作等功能 - 添加报卡编辑和Word文档导出功能 - 构建完整的医生报卡管理界面,包含筛选、分页、状态显示等 - 实现报卡状态管理(待提交、已提交、已审核、已上报、失败、作废) - 添加前端表格展示、弹窗详情、表单验证等交互功能 - 创建医生报卡更新DTO数据传输对象
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package com.openhis.web.cardmanagement.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class DoctorCardUpdateDto {
|
||||
private String cardNo;
|
||||
private String phone;
|
||||
private LocalDate onsetDate;
|
||||
private LocalDateTime diagDate;
|
||||
private String diseaseType; // 修改为diseaseType,对应InfectiousCard中的diseaseType字段
|
||||
private String addressProv;
|
||||
private String addressCity;
|
||||
private String addressCounty;
|
||||
private String addressHouse;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
export function getDoctorCardStatistics() {
|
||||
return request({
|
||||
url: '/card-management/doctor/statistics',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export function getDoctorCardList(params) {
|
||||
return request({
|
||||
url: '/card-management/doctor/page',
|
||||
method: 'get',
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
export function getCardDetail(cardNo) {
|
||||
return request({
|
||||
url: `/card-management/detail/${cardNo}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export function submitCard(cardNo) {
|
||||
return request({
|
||||
url: `/card-management/doctor/submit/${cardNo}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
export function withdrawCard(cardNo) {
|
||||
return request({
|
||||
url: `/card-management/doctor/withdraw/${cardNo}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteCard(cardNo) {
|
||||
return request({
|
||||
url: `/card-management/doctor/${cardNo}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
|
||||
export function batchSubmitCards(cardNos) {
|
||||
return request({
|
||||
url: '/card-management/doctor/batch-submit',
|
||||
method: 'post',
|
||||
data: cardNos,
|
||||
});
|
||||
}
|
||||
|
||||
export function batchDeleteCards(cardNos) {
|
||||
return request({
|
||||
url: '/card-management/doctor/batch-delete',
|
||||
method: 'post',
|
||||
data: cardNos,
|
||||
});
|
||||
}
|
||||
|
||||
export function exportCardToWord(cardNo) {
|
||||
return request({
|
||||
url: `/card-management/doctor/export-word/${cardNo}`,
|
||||
method: 'get',
|
||||
responseType: 'blob',
|
||||
});
|
||||
}
|
||||
|
||||
export function updateDoctorCard(data) {
|
||||
return request({
|
||||
url: '/card-management/doctor/update',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,745 @@
|
||||
<template>
|
||||
<div class="my-card-management-container">
|
||||
<div class="page-header">
|
||||
<h2>我的报卡</h2>
|
||||
</div>
|
||||
|
||||
<div class="statistics-section">
|
||||
<div class="stat-card total">
|
||||
<div class="stat-icon">
|
||||
<el-icon><Document /></el-icon>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">{{ statistics.totalCount || 0 }}</div>
|
||||
<div class="stat-label">总报卡数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card pending">
|
||||
<div class="stat-icon">
|
||||
<el-icon><Clock /></el-icon>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">{{ statistics.pendingFailedCount || 0 }}</div>
|
||||
<div class="stat-label">待处理/失败</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card success">
|
||||
<div class="stat-icon">
|
||||
<el-icon><CircleCheck /></el-icon>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-value">{{ statistics.reportedCount || 0 }}</div>
|
||||
<div class="stat-label">已成功上报</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-section">
|
||||
<el-form :model="queryParams" :inline="true">
|
||||
<el-form-item label="日期范围">
|
||||
<el-date-picker
|
||||
v-model="queryParams.dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="queryParams.status" placeholder="全部状态" clearable style="width: 140px">
|
||||
<el-option label="全部状态" value="" />
|
||||
<el-option label="待提交" value="0" />
|
||||
<el-option label="已提交" value="1" />
|
||||
<el-option label="已审核" value="2" />
|
||||
<el-option label="已上报" value="3" />
|
||||
<el-option label="失败" value="4" />
|
||||
<el-option label="作废" value="6" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键词">
|
||||
<el-input
|
||||
v-model="queryParams.keyword"
|
||||
placeholder="患者姓名/报卡名称"
|
||||
clearable
|
||||
style="width: 180px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">
|
||||
<el-icon><Search /></el-icon>
|
||||
应用筛选
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
重置条件
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="action-section">
|
||||
<el-checkbox v-model="isAllSelected" @change="handleSelectAll">全选</el-checkbox>
|
||||
<el-button type="primary" :disabled="selectedRows.length === 0" @click="handleBatchSubmit">
|
||||
批量提交
|
||||
</el-button>
|
||||
<el-button type="danger" :disabled="selectedRows.length === 0" @click="handleBatchDelete">
|
||||
批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="table-section">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="cardList"
|
||||
@selection-change="handleSelectionChange"
|
||||
border
|
||||
stripe
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="卡片ID" prop="cardNo" min-width="150" />
|
||||
<el-table-column label="患者姓名" prop="patName" width="100" />
|
||||
<el-table-column label="身份证号" prop="idNo" min-width="180" />
|
||||
<el-table-column label="联系电话" prop="phone" width="130" />
|
||||
<el-table-column label="就诊卡号" prop="visitCardNo" width="130" />
|
||||
<el-table-column label="报卡名称" prop="cardName" min-width="200" />
|
||||
<el-table-column label="提交时间" prop="submitTime" width="160" align="center" />
|
||||
<el-table-column label="状态" prop="status" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusType(row.status)" size="small">
|
||||
{{ getStatusName(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link size="small" @click="handleView(row)">查看</el-button>
|
||||
<el-button
|
||||
v-if="row.status === '0'"
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
@click="handleEdit(row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === '0'"
|
||||
type="success"
|
||||
link
|
||||
size="small"
|
||||
@click="handleSubmit(row)"
|
||||
>
|
||||
提交
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === '1'"
|
||||
type="warning"
|
||||
link
|
||||
size="small"
|
||||
@click="handleWithdraw(row)"
|
||||
>
|
||||
撤回
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === '3'"
|
||||
type="info"
|
||||
link
|
||||
size="small"
|
||||
@click="handleExport(row)"
|
||||
>
|
||||
导出
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-section">
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.pageNo"
|
||||
v-model:page-size="queryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="getList"
|
||||
@current-change="getList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
v-model="detailVisible"
|
||||
:title="detailMode === 'view' ? '报卡详情' : '编辑报卡'"
|
||||
width="800px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-descriptions v-if="detailMode === 'view'" :column="2" border>
|
||||
<el-descriptions-item label="卡片编号">{{ currentCard.cardNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="getStatusType(currentCard.status)">{{ getStatusName(currentCard.status) }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="患者姓名">{{ currentCard.patName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="身份证号">{{ currentCard.idNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ currentCard.phone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">{{ currentCard.sex === '1' ? '男' : currentCard.sex === '2' ? '女' : '未知' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="年龄">{{ currentCard.age }}{{ getAgeUnit(currentCard.ageUnit) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="疾病名称">{{ currentCard.diseaseName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="发病日期">{{ currentCard.onsetDate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="诊断日期">{{ currentCard.diagDate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报告单位">{{ currentCard.reportOrg }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报告医生">{{ currentCard.reportDoc }}</el-descriptions-item>
|
||||
<el-descriptions-item label="填卡日期">{{ currentCard.reportDate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="现住址" :span="2">
|
||||
{{ currentCard.addressProv }}{{ currentCard.addressCity }}{{ currentCard.addressCounty }}{{ currentCard.addressTown }}{{ currentCard.addressVillage }}{{ currentCard.addressHouse }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-form v-else ref="editFormRef" :model="editForm" :rules="editFormRules" label-width="100px">
|
||||
<!-- 患者基本信息 -->
|
||||
<el-divider content-position="left">患者基本信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="患者姓名" prop="patName">
|
||||
<el-input v-model="editForm.patName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="身份证号" prop="idNo">
|
||||
<el-input v-model="editForm.idNo" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="性别" prop="sex">
|
||||
<el-input :value="editForm.sex === '1' ? '男' : editForm.sex === '2' ? '女' : '未知'" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="年龄" prop="age">
|
||||
<el-input :value="`${editForm.age}${getAgeUnit(editForm.ageUnit)}`" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="phone" required>
|
||||
<el-input v-model="editForm.phone" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 临床信息 -->
|
||||
<el-divider content-position="left">临床信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="疾病名称" prop="diseaseName">
|
||||
<el-input v-model="editForm.diseaseName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发病日期" prop="onsetDate">
|
||||
<el-date-picker v-model="editForm.onsetDate" type="date" value-format="YYYY-MM-DD" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="诊断日期" prop="diagDate" required>
|
||||
<el-date-picker v-model="editForm.diagDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="传染病类别" prop="diseaseCategory">
|
||||
<el-select v-model="editForm.diseaseCategory" placeholder="请选择传染病类别" style="width: 100%">
|
||||
<el-option label="甲类传染病" value="A" />
|
||||
<el-option label="乙类传染病" value="B" />
|
||||
<el-option label="丙类传染病" value="C" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 报告信息 -->
|
||||
<el-divider content-position="left">报告信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="报告单位" prop="reportOrg">
|
||||
<el-input v-model="editForm.reportOrg" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="报告医生" prop="reportDoc">
|
||||
<el-input v-model="editForm.reportDoc" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="填卡日期" prop="reportDate">
|
||||
<el-input v-model="editForm.reportDate" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 现住址 -->
|
||||
<el-divider content-position="left">现住址</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="省" prop="addressProv">
|
||||
<el-input v-model="editForm.addressProv" placeholder="请输入省份" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="市" prop="addressCity">
|
||||
<el-input v-model="editForm.addressCity" placeholder="请输入城市" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="区县" prop="addressCounty">
|
||||
<el-input v-model="editForm.addressCounty" placeholder="请输入区县" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="详细地址" prop="addressHouse">
|
||||
<el-input v-model="editForm.addressHouse" type="textarea" placeholder="请输入详细地址" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="detailVisible = false">取消</el-button>
|
||||
<el-button v-if="detailMode === 'edit'" type="primary" @click="handleSaveEdit">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Document, Clock, CircleCheck, Search, Refresh } from '@element-plus/icons-vue';
|
||||
import {
|
||||
getDoctorCardStatistics,
|
||||
getDoctorCardList,
|
||||
submitCard,
|
||||
withdrawCard,
|
||||
batchSubmitCards,
|
||||
batchDeleteCards,
|
||||
exportCardToWord,
|
||||
getCardDetail,
|
||||
updateDoctorCard,
|
||||
} from './api';
|
||||
|
||||
const loading = ref(false);
|
||||
const cardList = ref([]);
|
||||
const total = ref(0);
|
||||
const selectedRows = ref([]);
|
||||
const isAllSelected = ref(false);
|
||||
|
||||
const statistics = ref({
|
||||
totalCount: 0,
|
||||
pendingFailedCount: 0,
|
||||
reportedCount: 0,
|
||||
});
|
||||
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
dateRange: [],
|
||||
status: '',
|
||||
keyword: '',
|
||||
});
|
||||
|
||||
const detailVisible = ref(false);
|
||||
const detailMode = ref('view');
|
||||
const currentCard = ref({});
|
||||
const editForm = reactive({});
|
||||
const editFormRef = ref(null);
|
||||
|
||||
// 编辑表单验证规则
|
||||
const editFormRules = {
|
||||
phone: [
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
|
||||
],
|
||||
diagDate: [
|
||||
{ required: true, message: '请选择诊断日期', trigger: 'change' }
|
||||
]
|
||||
};
|
||||
|
||||
const statusMap = {
|
||||
'0': { name: '待提交', type: 'warning' },
|
||||
'1': { name: '已提交', type: 'primary' },
|
||||
'2': { name: '已审核', type: 'success' },
|
||||
'3': { name: '已上报', type: 'success' },
|
||||
'4': { name: '失败', type: 'danger' },
|
||||
'5': { name: '退回', type: 'danger' },
|
||||
'6': { name: '作废', type: 'info' },
|
||||
};
|
||||
|
||||
const ageUnitMap = {
|
||||
'1': '岁',
|
||||
'2': '月',
|
||||
'3': '天',
|
||||
};
|
||||
|
||||
function getStatusName(status) {
|
||||
return statusMap[status]?.name || '未知';
|
||||
}
|
||||
|
||||
function getStatusType(status) {
|
||||
return statusMap[status]?.type || 'info';
|
||||
}
|
||||
|
||||
function getAgeUnit(unit) {
|
||||
return ageUnitMap[unit] || '岁';
|
||||
}
|
||||
|
||||
async function getStatistics() {
|
||||
try {
|
||||
const res = await getDoctorCardStatistics();
|
||||
if (res.code === 200) {
|
||||
statistics.value = res.data || {};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取统计数据失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function getList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const params = { ...queryParams };
|
||||
if (params.dateRange && params.dateRange.length === 2) {
|
||||
params.startDate = params.dateRange[0];
|
||||
params.endDate = params.dateRange[1];
|
||||
}
|
||||
delete params.dateRange;
|
||||
|
||||
const res = await getDoctorCardList(params);
|
||||
if (res.code === 200) {
|
||||
cardList.value = res.data?.list || [];
|
||||
total.value = res.data?.total || 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error);
|
||||
ElMessage.error('获取数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.pageNo = 1;
|
||||
getList();
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
queryParams.pageNo = 1;
|
||||
queryParams.pageSize = 10;
|
||||
queryParams.dateRange = [];
|
||||
queryParams.status = '';
|
||||
queryParams.keyword = '';
|
||||
getList();
|
||||
}
|
||||
|
||||
function handleSelectionChange(selection) {
|
||||
selectedRows.value = selection;
|
||||
isAllSelected.value = selection.length === cardList.value.length && cardList.value.length > 0;
|
||||
}
|
||||
|
||||
function handleSelectAll(val) {
|
||||
if (val) {
|
||||
selectedRows.value = [...cardList.value];
|
||||
} else {
|
||||
selectedRows.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function handleView(row) {
|
||||
try {
|
||||
const res = await getCardDetail(row.cardNo);
|
||||
if (res.code === 200) {
|
||||
currentCard.value = res.data || {};
|
||||
detailMode.value = 'view';
|
||||
detailVisible.value = true;
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取详情失败');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleEdit(row) {
|
||||
try {
|
||||
const res = await getCardDetail(row.cardNo);
|
||||
if (res.code === 200) {
|
||||
Object.assign(editForm, res.data || {});
|
||||
detailMode.value = 'edit';
|
||||
detailVisible.value = true;
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取详情失败');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSaveEdit() {
|
||||
// 验证表单
|
||||
try {
|
||||
await editFormRef.value.validate();
|
||||
} catch (error) {
|
||||
ElMessage.error('表单验证失败,请检查输入');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const updateData = {
|
||||
cardNo: editForm.cardNo,
|
||||
phone: editForm.phone,
|
||||
onsetDate: editForm.onsetDate,
|
||||
diagDate: editForm.diagDate,
|
||||
diseaseCategory: editForm.diseaseCategory,
|
||||
addressProv: editForm.addressProv,
|
||||
addressCity: editForm.addressCity,
|
||||
addressCounty: editForm.addressCounty,
|
||||
addressHouse: editForm.addressHouse,
|
||||
};
|
||||
|
||||
const res = await updateDoctorCard(updateData);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('保存成功');
|
||||
detailVisible.value = false;
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败');
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('保存失败:' + (error.message || '网络错误'));
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm('确认提交该报卡?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
const res = await submitCard(row.cardNo);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('提交成功');
|
||||
getStatistics();
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(res.msg || '提交失败');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('提交失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleWithdraw(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm('确认撤回该报卡?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
const res = await withdrawCard(row.cardNo);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('撤回成功');
|
||||
getStatistics();
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(res.msg || '撤回失败');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('撤回失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleBatchSubmit() {
|
||||
const validRows = selectedRows.value.filter(row => row.status === '0');
|
||||
if (validRows.length === 0) {
|
||||
ElMessage.warning('只能提交待提交状态的报卡');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await ElMessageBox.confirm(`确认提交选中的 ${validRows.length} 条报卡?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
const cardNos = validRows.map(row => row.cardNo);
|
||||
const res = await batchSubmitCards(cardNos);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(res.msg || '批量提交成功');
|
||||
getStatistics();
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(res.msg || '批量提交失败');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('批量提交失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleBatchDelete() {
|
||||
const validRows = selectedRows.value.filter(row => row.status === '0');
|
||||
if (validRows.length === 0) {
|
||||
ElMessage.warning('只能删除待提交状态的报卡');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await ElMessageBox.confirm(`确认删除选中的 ${validRows.length} 条报卡?删除后状态将变为作废。`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
const cardNos = validRows.map(row => row.cardNo);
|
||||
const res = await batchDeleteCards(cardNos);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(res.msg || '批量删除成功');
|
||||
getStatistics();
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(res.msg || '批量删除失败');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('批量删除失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleExport(row) {
|
||||
try {
|
||||
const res = await exportCardToWord(row.cardNo);
|
||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `传染病报告卡-${row.cardNo}.docx`;
|
||||
link.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
ElMessage.error('导出失败');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getStatistics();
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-card-management-container {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
min-height: calc(100vh - 84px);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.page-header h2 {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.statistics-section {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.stat-card.pending {
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
box-shadow: 0 4px 12px rgba(245, 87, 108, 0.3);
|
||||
}
|
||||
|
||||
.stat-card.success {
|
||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||||
box-shadow: 0 4px 12px rgba(0, 242, 254, 0.3);
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.action-section {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 12px 20px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.table-section {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.pagination-section {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.statistics-section {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
scripts/screenshots/consultationApplication_1772771232211.png
Normal file
BIN
scripts/screenshots/consultationApplication_1772771232211.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 314 KiB |
Reference in New Issue
Block a user