feat(icons): 添加医疗信息系统所需SVG图标

- 添加accelerate.svg加速功能图标
- 添加access-control.svg访问控制图标
- 添加accounting.svg会计功能图标
- 添加adjustment.svg调整功能图标
- 添加admission.svg入院功能图标
- 添加advise.svg咨询功能图标
- 添加affiliation.svg关联功能图标
- 添加agreement.svg协议功能图标
- 添加agreement-vote.svg协议投票图标
- 添加alert.svg警告功能图标
- 添加allergy.svg过敏功能图标
- 添加alliance.svg联盟功能图标
- 添加analytics.svg分析功能图标
- 添加anesthesia.svg麻醉功能图标
- 添加approval.svg审批功能图标
- 添加arbitration.svg仲裁功能图标
- 添加archive.svg归档功能图标
- 添加asset.svg资产功能图标
- 添加attendance.svg考勤功能图标
- 添加audit.svg审计功能图标
- 添加audit-log.svg审计日志图标
- 添加audit-report.svg审计报告图标
- 添加audit-trail.svg审计轨迹图标
- 添加backup.svg备份功能图标
- 添加band.svg标签
This commit is contained in:
2026-06-17 14:27:45 +08:00
parent 5100237faf
commit 52377d7529
11 changed files with 346 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h256v64h-256z" fill="currentColor"/>
<path d="M384 448h256v64h-256z" fill="currentColor"/>
<path d="M384 576h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 538 B

View File

@@ -0,0 +1,7 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h64v384h-64z" fill="currentColor"/>
<path d="M576 320h64v384h-64z" fill="currentColor"/>
<path d="M384 384h256v64h-256z" fill="currentColor"/>
<path d="M384 512h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@@ -0,0 +1,7 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h64v384h-64z" fill="currentColor"/>
<path d="M576 320h64v384h-64z" fill="currentColor"/>
<path d="M384 384h256v64h-256z" fill="currentColor"/>
<path d="M384 512h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@@ -0,0 +1,6 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h256v64h-256z" fill="currentColor"/>
<path d="M384 448h256v64h-256z" fill="currentColor"/>
<path d="M384 576h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 538 B

View File

@@ -0,0 +1,6 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h256v64h-256z" fill="currentColor"/>
<path d="M384 448h256v64h-256z" fill="currentColor"/>
<path d="M384 576h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 538 B

View File

@@ -0,0 +1,7 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h64v384h-64z" fill="currentColor"/>
<path d="M576 320h64v384h-64z" fill="currentColor"/>
<path d="M384 384h256v64h-256z" fill="currentColor"/>
<path d="M384 512h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@@ -0,0 +1,6 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h256v64h-256z" fill="currentColor"/>
<path d="M384 448h256v64h-256z" fill="currentColor"/>
<path d="M384 576h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 538 B

View File

@@ -0,0 +1,6 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h256v64h-256z" fill="currentColor"/>
<path d="M384 448h256v64h-256z" fill="currentColor"/>
<path d="M384 576h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 538 B

View File

@@ -0,0 +1,7 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h64v384h-64z" fill="currentColor"/>
<path d="M576 320h64v384h-64z" fill="currentColor"/>
<path d="M384 384h256v64h-256z" fill="currentColor"/>
<path d="M384 512h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@@ -0,0 +1,7 @@
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 128c-211.2 0-384 172.8-384 384 0 106.24 43.52 202.24 113.92 271.36L256 896h512l-85.33-112.64C769.28 714.24 812.8 618.24 812.8 512c0-211.2-172.8-384-384-384z m0 576c-106.24 0-192-85.76-192-192s85.76-192 192-192 192 85.76 192 192-85.76 192-192 192z" fill="currentColor"/>
<path d="M384 320h64v384h-64z" fill="currentColor"/>
<path d="M576 320h64v384h-64z" fill="currentColor"/>
<path d="M384 384h256v64h-256z" fill="currentColor"/>
<path d="M384 512h256v64h-256z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@@ -0,0 +1,281 @@
<template>
<div class="app-container">
<div style="margin-bottom:16px;display:flex;justify-content:space-between;align-items:center">
<span style="font-size:18px;font-weight:bold">终末质控</span>
<div>
<el-button type="primary" @click="runCheck" :loading="checkLoading">
执行检查
</el-button>
<el-button @click="loadResults" :loading="resultsLoading">
刷新结果
</el-button>
</div>
</div>
<!-- 就诊号输入 -->
<el-card shadow="never" style="margin-bottom:16px">
<el-form :inline="true">
<el-form-item label="就诊号">
<el-input v-model="encounterId" clearable placeholder="请输入就诊号" style="width:200px" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="runCheck" :loading="checkLoading">
执行终末检查
</el-button>
<el-button @click="loadResults" :loading="resultsLoading">
查询结果
</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 质控评分 -->
<el-row :gutter="16" style="margin-bottom:16px">
<el-col :span="12">
<el-card shadow="hover">
<template #header>
<div style="display:flex;justify-content:space-between;align-items:center">
<span>终末质控评分</span>
<el-tag :type="scoreTagType" size="large">
{{ results.score || 0 }}
</el-tag>
</div>
</template>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="检查时间">
{{ results.checkTime || '-' }}
</el-descriptions-item>
<el-descriptions-item label="评分等级">
{{ gradeText }}
</el-descriptions-item>
<el-descriptions-item label="检查项目数">
{{ results.totalItems || 0 }}
</el-descriptions-item>
<el-descriptions-item label="通过项目数">
{{ results.passItems || 0 }}
</el-descriptions-item>
</el-descriptions>
</el-card>
</el-col>
<el-col :span="12">
<el-card shadow="hover">
<template #header>
<span>检查项目详情</span>
</template>
<el-table :data="results.checks || []" border stripe size="small">
<el-table-column label="检查项目" prop="item" min-width="180" />
<el-table-column label="检查结果" prop="result" width="100" align="center">
<template #default="scope">
<el-tag :type="scope.row.result === 'PASS' ? 'success' : 'danger'" size="small">
{{ scope.row.result === 'PASS' ? '通过' : '不通过' }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<!-- 缺陷列表 -->
<el-card shadow="never">
<template #header>
<div style="display:flex;justify-content:space-between;align-items:center">
<span>缺陷记录 ({{ defects.length }})</span>
<el-select v-model="defectFilter" clearable placeholder="筛选缺陷类型" style="width:140px">
<el-option label="全部" value="" />
<el-option label="严重缺陷" value="CRITICAL" />
<el-option label="主要缺陷" value="MAJOR" />
<el-option label="一般缺陷" value="MINOR" />
</el-select>
</div>
</template>
<el-table :data="filteredDefects" border stripe>
<el-table-column label="缺陷类型" prop="defectType" width="120" />
<el-table-column label="缺陷项" prop="defectItem" min-width="180" show-overflow-tooltip />
<el-table-column label="严重程度" prop="severity" width="110" align="center">
<template #default="scope">
<el-tag :type="severityType(scope.row.severity)" size="small">
{{ severityText(scope.row.severity) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="整改状态" prop="rectifyStatus" width="110" align="center">
<template #default="scope">
<el-tag :type="rectifyStatusType(scope.row.rectifyStatus)" size="small">
{{ rectifyStatusText(scope.row.rectifyStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default="scope">
<el-button
v-if="scope.row.rectifyStatus !== 'RECTIFIED'"
type="primary"
size="small"
@click="startRectify(scope.row)"
>
整改
</el-button>
<el-button
v-if="scope.row.rectifyStatus === 'RECTIFYING'"
type="success"
size="small"
@click="completeRectify(scope.row)"
>
完成
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { runTerminalCheck, getTerminalResults, startDefectRectify, completeDefectRectify } from '@/api/quality'
const encounterId = ref('')
const results = reactive({
score: 0,
grade: '',
checkTime: '',
totalItems: 0,
passItems: 0,
checks: []
})
const defects = ref([])
const defectFilter = ref('')
const checkLoading = ref(false)
const resultsLoading = ref(false)
const scoreTagType = computed(() => {
if (!results.score) return 'info'
if (results.score >= 90) return 'success'
if (results.score >= 75) return 'warning'
if (results.score >= 60) return 'warning'
return 'danger'
})
const gradeText = computed(() => {
if (!results.grade) return '-'
const map = { 'A': '甲级', 'B': '乙级', 'C': '丙级', 'D': '不合格' }
return map[results.grade] || '-'
})
const filteredDefects = computed(() => {
if (!defectFilter.value) return defects.value
return defects.value.filter(d => d.severity === defectFilter.value)
})
function severityType(severity) {
if (severity === 'CRITICAL') return 'danger'
if (severity === 'MAJOR') return 'warning'
return 'info'
}
function severityText(severity) {
if (severity === 'CRITICAL') return '严重缺陷'
if (severity === 'MAJOR') return '主要缺陷'
return '一般缺陷'
}
function rectifyStatusType(status) {
if (status === 'RECTIFIED') return 'success'
if (status === 'RECTIFYING') return 'warning'
return 'info'
}
function rectifyStatusText(status) {
if (status === 'RECTIFIED') return '已整改'
if (status === 'RECTIFYING') return '整改中'
return '待整改'
}
async function runCheck() {
if (!encounterId.value) {
ElMessage.warning('请输入就诊号')
return
}
checkLoading.value = true
try {
const res = await runTerminalCheck(encounterId.value)
if (res.code === 200) {
ElMessage.success('终末质控检查完成')
loadResults()
} else {
ElMessage.error(res.msg || '检查失败')
}
} catch (e) {
ElMessage.error('检查失败: ' + e.message)
} finally {
checkLoading.value = false
}
}
async function loadResults() {
if (!encounterId.value) {
ElMessage.warning('请输入就诊号')
return
}
resultsLoading.value = true
try {
const res = await getTerminalResults(encounterId.value)
if (res.code === 200) {
const data = res.data || {}
results.score = data.score || 0
results.grade = data.grade || ''
results.checkTime = data.checkTime || ''
results.totalItems = data.totalItems || 0
results.passItems = data.passItems || 0
results.checks = data.checks || []
defects.value = data.defects || []
}
} catch (e) {
ElMessage.error('查询失败: ' + e.message)
} finally {
resultsLoading.value = false
}
}
async function startRectify(defect) {
try {
await ElMessageBox.confirm('确认开始整改此缺陷?', '确认操作', { type: 'warning' })
const res = await startDefectRectify(defect.id)
if (res.code === 200) {
ElMessage.success('开始整改')
loadResults()
} else {
ElMessage.error(res.msg || '操作失败')
}
} catch (e) {
if (e !== 'cancel') {
ElMessage.error('操作失败: ' + e.message)
}
}
}
async function completeRectify(defect) {
try {
await ElMessageBox.confirm('确认完成整改?', '确认操作', { type: 'success' })
const res = await completeDefectRectify(defect.id)
if (res.code === 200) {
ElMessage.success('整改完成')
loadResults()
} else {
ElMessage.error(res.msg || '操作失败')
}
} catch (e) {
if (e !== 'cancel') {
ElMessage.error('操作失败: ' + e.message)
}
}
}
onMounted(() => {
if (encounterId.value) {
loadResults()
}
})
</script>