| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087 |
- <template>
- <div class="quality-control">
- <!-- 质控活动标题 -->
- <div class="section-title">
- <h2>质控活动</h2>
- </div>
- <!-- 四个横向均分的内容区域 -->
- <div class="four-panel-layout">
- <!-- 第一个:任务计划安排统计 -->
- <div class="panel-item" v-show="!isTeamType && !isUserType && !isDepartmentType">
- <div class="panel-header">
- <h3>任务计划安排统计</h3>
- </div>
- <!-- 两个灰色背景统计卡片 -->
- <div class="stat-cards">
- <div class="stat-card">
- <div class="stat-title">专项任务</div>
- <div class="stat-count"><span>{{ specialTask.count }}</span>次</div>
- <div class="stat-trend">
- 同比<span :class="specialTask.yearOnYearTrend">{{ specialTask.yearOnYear }}</span>
- <template v-if="props.queryForm.dateRangeQueryType !== 'YEAR'">
- ,环比<span :class="specialTask.chainRatioTrend">{{ specialTask.chainRatio }}</span>
- </template>
- </div>
- </div>
- <div class="stat-card">
- <div class="stat-title">日常任务</div>
- <div class="stat-count"><span>{{ dailyTask.count }}</span>次</div>
- <div class="stat-trend">
- 同比<span :class="dailyTask.yearOnYearTrend">{{ dailyTask.yearOnYear }}</span>
- <template v-if="props.queryForm.dateRangeQueryType !== 'YEAR'">
- ,环比<span :class="dailyTask.chainRatioTrend">{{ dailyTask.chainRatio }}</span>
- </template>
- </div>
- </div>
- </div>
- <!-- 柱状图 -->
- <div class="chart-container">
- <div ref="planScheduleChartRef" class="echarts-chart"></div>
- </div>
- </div>
- <!-- 第二个:问题发现统计 -->
- <div class="panel-item">
- <div class="panel-header">
- <h3>问题发现统计</h3>
- </div>
- <!-- 描述卡片 -->
- <div class="describe-card" v-if="checkProblemDiscovery?.desc">
- <div class="describe-content">
- {{ checkProblemDiscovery?.desc }}
- </div>
- </div>
- <!-- 折线图 -->
- <div class="chart-container">
- <div ref="problemDiscoveryChartRef" class="echarts-chart"></div>
- </div>
- </div>
- <!-- 第三个:问题分布统计 -->
- <div class="panel-item">
- <div class="panel-header">
- <h3>问题分布统计</h3>
- </div>
- <!-- 描述卡片 -->
- <div class="describe-card" v-if="checkProblemDistribution?.desc">
- <div class="describe-content">
- {{ checkProblemDistribution?.desc }}
- </div>
- </div>
- <!-- 饼图 -->
- <div class="chart-container">
- <div ref="problemDistributionChartRef" class="echarts-chart"></div>
- </div>
- </div>
- <!-- 第四个:问题整改统计 -->
- <div class="panel-item">
- <div class="panel-header">
- <h3>问题整改统计</h3>
- </div>
- <!-- 描述卡片 -->
- <div class="describe-card" v-if="checkProblemCorrection?.desc">
- <div class="describe-content">
- {{ checkProblemCorrection?.desc }}
- </div>
- </div>
- <!-- 柱状图 -->
- <div class="chart-container">
- <div ref="problemRectificationChartRef" class="echarts-chart"></div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { ref, onMounted, onUnmounted, watch } from 'vue'
- import { useEcharts } from '@/hooks/chart.js'
- import { getAnalysisReport } from '@/api/assistant/assistant.js'
- // 定义props接收queryForm参数
- const props = defineProps({
- queryForm: {
- type: Object,
- default: () => ({
- dateRangeQueryType: '',
- year: '',
- quarter: '',
- month: ''
- })
- },
- selectedDeptObject: {
- type: Object,
- default: null
- }
- })
- // 图表容器引用
- const planScheduleChartRef = ref(null)
- const problemDiscoveryChartRef = ref(null)
- const problemDistributionChartRef = ref(null)
- const problemRectificationChartRef = ref(null)
- // 图表实例
- const { setOption: setPlanScheduleOption, dispose: disposePlanSchedule } = useEcharts(planScheduleChartRef)
- const { setOption: setProblemDiscoveryOption, dispose: disposeProblemDiscovery } = useEcharts(problemDiscoveryChartRef)
- const { setOption: setProblemDistributionOption, dispose: disposeProblemDistribution } = useEcharts(problemDistributionChartRef)
- const { setOption: setProblemRectificationOption, dispose: disposeProblemRectification } = useEcharts(problemRectificationChartRef)
- // 计算属性:处理selectedDeptObject逻辑
- const selectedDeptType = computed(() => {
- return props.selectedDeptObject && props.selectedDeptObject?.deptType
- })
- const isUserType = computed(() => {
- return selectedDeptType.value === 'USER'
- })
- const isTeamType = computed(() => {
- return selectedDeptType.value === 'TEAMS'
- })
- // 计算属性:检查是否为STATION类型
- const isStationType = computed(() => {
- return selectedDeptType.value === 'STATION' || !selectedDeptType.value
- })
- // 计算属性:检查是否为DEPARTMENT类型
- const isDepartmentType = computed(() => {
- return selectedDeptType.value === 'MANAGER'
- })
- const isBrigadeType = computed(() => {
- return selectedDeptType.value === 'BRIGADE'
- })
- // 解析desc数据并更新专项任务和日常任务数据
- const parseTaskData = (desc) => {
- if (!desc) return
- // 解析desc格式:"专项任务:发布7次,同比上升0.00%,环比上升133.33%;\n日常任务:发布2次,同比上升0.00%,环比下降33.33%"
- const lines = desc.split(';')
- lines.forEach(line => {
- if (line.includes('专项任务')) {
- const countMatch = line.match(/发布(\d+)次/)
- const yearOnYearMatch = line.match(/同比(上升|下降|持平)([\d.-]+)%/)
- const chainRatioMatch = line.match(/环比(上升|下降|持平)([\d.-]+)%/)
- if (countMatch) {
- specialTask.value.count = parseInt(countMatch[1])
- }
- if (yearOnYearMatch) {
- const trendDirection = yearOnYearMatch[1]
- const trendValue = yearOnYearMatch[2]
- let trendType = 'neutral'
- let displayValue = trendValue
- // 处理趋势值为"--"的情况
- if (trendValue === '--') {
- trendType = 'neutral'
- displayValue = '--'
- } else {
- // 正常数值处理
- const value = parseFloat(trendValue)
- if (trendDirection === '上升' && value > 0) {
- trendType = 'up'
- } else if (trendDirection === '下降' || value < 0) {
- trendType = 'down'
- } else if (trendDirection === '持平') {
- trendType = 'neutral'
- }
- }
- specialTask.value.yearOnYearTrend = trendType
- specialTask.value.yearOnYear = displayValue + '%'
- }
- if (chainRatioMatch) {
- const trendDirection = chainRatioMatch[1]
- const trendValue = chainRatioMatch[2]
- let trendType = 'neutral'
- let displayValue = trendValue
- // 处理趋势值为"--"的情况
- if (trendValue === '--') {
- trendType = 'neutral'
- displayValue = '--'
- } else {
- // 正常数值处理
- const value = parseFloat(trendValue)
- if (trendDirection === '上升' && value > 0) {
- trendType = 'up'
- } else if (trendDirection === '下降' || value < 0) {
- trendType = 'down'
- } else if (trendDirection === '持平') {
- trendType = 'neutral'
- }
- }
- specialTask.value.chainRatioTrend = trendType
- specialTask.value.chainRatio = displayValue + '%'
- }
- } else if (line.includes('日常任务')) {
- const countMatch = line.match(/发布(\d+)次/)
- const yearOnYearMatch = line.match(/同比(上升|下降|持平)([\d.-]+)%/)
- const chainRatioMatch = line.match(/环比(上升|下降|持平)([\d.-]+)%/)
- if (countMatch) {
- dailyTask.value.count = parseInt(countMatch[1])
- }
- if (yearOnYearMatch) {
- const trendDirection = yearOnYearMatch[1]
- const trendValue = yearOnYearMatch[2]
- let trendType = 'neutral'
- let displayValue = trendValue
- // 处理趋势值为"--"的情况
- if (trendValue === '--') {
- trendType = 'neutral'
- displayValue = '--'
- } else {
- // 正常数值处理
- const value = parseFloat(trendValue)
- if (trendDirection === '上升' && value > 0) {
- trendType = 'up'
- } else if (trendDirection === '下降' || value < 0) {
- trendType = 'down'
- } else if (trendDirection === '持平') {
- trendType = 'neutral'
- }
- }
- dailyTask.value.yearOnYearTrend = trendType
- dailyTask.value.yearOnYear = displayValue + '%'
- }
- if (chainRatioMatch) {
- const trendDirection = chainRatioMatch[1]
- const trendValue = chainRatioMatch[2]
- let trendType = 'neutral'
- let displayValue = trendValue
- // 处理趋势值为"--"的情况
- if (trendValue === '--') {
- trendType = 'neutral'
- displayValue = '--'
- } else {
- // 正常数值处理
- const value = parseFloat(trendValue)
- if (trendDirection === '上升' && value > 0) {
- trendType = 'up'
- } else if (trendDirection === '下降' || value < 0) {
- trendType = 'down'
- } else if (trendDirection === '持平') {
- trendType = 'neutral'
- }
- }
- dailyTask.value.chainRatioTrend = trendType
- dailyTask.value.chainRatio = displayValue + '%'
- }
- }
- })
- }
- // 调用API获取质控分析数据
- const fetchAnalysisData = async (queryParams) => {
- try {
- // 添加null检查,防止props.selectedDeptObject为null
- const selectedDept = props.selectedDeptObject
- const { deptType = "", id } = selectedDept ? selectedDept : { deptType: "", id: "" }
- let progressParams = { ...queryParams }
- if (progressParams.dateRangeQueryType === 'YEAR') {
- progressParams.yearOnYear = true
- delete progressParams.chainRatio
- } else {
- progressParams.chainRatio = true
- progressParams.yearOnYear = true
- }
- let rangParams = {
- userId: deptType == 'USER' ? id : "",
- deptId: ["STATION", "MANAGER", "TEAMS", "BRIGADE"].includes(deptType) ? id : ""
- }
- const response = await getAnalysisReport({ ...progressParams, ...rangParams })
- console.log('质控分析数据:', response.data)
- // 解构赋值API返回的数据
- const { checkTaskDto, checkProblemDiscoveryDto, checkProblemDistributionDto, checkProblemCorrectionDto } = response.data;
- // 赋值到响应式数据
- checkTask.value = checkTaskDto || {}
- checkProblemDiscovery.value = checkProblemDiscoveryDto || {}
- checkProblemDistribution.value = checkProblemDistributionDto || {}
- checkProblemCorrection.value = checkProblemCorrectionDto || {}
- // 如果checkTaskDto中有desc字段,解析并更新任务数据
- if (checkTaskDto && checkTaskDto.desc) {
- parseTaskData(checkTaskDto.desc)
- }
- // 更新图表和统计信息
- updateChartsWithData()
- } catch (error) {
- console.error('获取质控分析数据失败:', error)
- }
- }
- // 初始化图表
- onMounted(() => {
- // 确保DOM完全渲染后再初始化图表
- const initCharts = () => {
- // 任务计划安排柱状图
- if (planScheduleChartRef.value && planScheduleChartRef.value.offsetHeight > 0) {
- setPlanScheduleOption(planScheduleOptions)
- }
- // 问题发现折线图
- if (problemDiscoveryChartRef.value && problemDiscoveryChartRef.value.offsetHeight > 0) {
- setProblemDiscoveryOption(problemDiscoveryOptions)
- }
- // 问题分布饼图
- if (problemDistributionChartRef.value && problemDistributionChartRef.value.offsetHeight > 0) {
- setProblemDistributionOption(problemDistributionOptions)
- }
- // 问题整改柱状图
- if (problemRectificationChartRef.value && problemRectificationChartRef.value.offsetHeight > 0) {
- setProblemRectificationOption(problemRectificationOptions)
- }
- }
- // 延迟初始化,确保CSS已应用
- setTimeout(() => {
- initCharts()
- }, 100)
- // 如果容器高度为0,延迟重试
- setTimeout(() => {
- initCharts()
- }, 500)
- })
- // 监听queryForm参数变化,调用API获取数据
- watch(() => props.queryForm, (newQueryForm) => {
- // 只有当所有必要的查询参数都存在时才调用API
- if (newQueryForm.dateRangeQueryType && newQueryForm.year) {
- fetchAnalysisData(newQueryForm)
- }
- }, { deep: true })
- // 定义响应式数据
- const checkTask = ref({})
- const checkProblemDiscovery = ref({})
- const checkProblemDistribution = ref({})
- const checkProblemCorrection = ref({})
- // 专项任务和日常任务数据
- const specialTask = ref({
- count: 0,
- yearOnYear: '',
- yearOnYearTrend: 'up',
- chainRatio: '',
- chainRatioTrend: 'up'
- })
- const dailyTask = ref({
- count: 0,
- yearOnYear: '',
- yearOnYearTrend: 'down',
- chainRatio: '',
- chainRatioTrend: 'down'
- })
- // 更新任务计划安排图表数据
- const updatePlanScheduleChart = () => {
- if (checkTask.value && checkTask.value.checkTaskItemDtoList) {
- const taskList = checkTask.value.checkTaskItemDtoList
- // 提取横坐标数据(desc字段)
- const xAxisData = [...new Set(taskList.map(item => item.desc))]
- // 提取专项任务数据
- const specialTaskData = taskList.filter(item => item.typeDesc === '专项任务').map((item) => item.count)
- // 提取日常任务数据
- const dailyTaskData = taskList.filter(item => item.typeDesc === '日常任务').map(item => item.count)
- // 更新图表配置
- planScheduleOptions.xAxis.data = xAxisData
- planScheduleOptions.series[0].data = specialTaskData
- planScheduleOptions.series[1].data = dailyTaskData
- // 重新设置图表选项
- setPlanScheduleOption(planScheduleOptions)
- console.log('任务计划图表已更新:', {
- xAxis: xAxisData,
- 专项任务: specialTaskData,
- 日常任务: dailyTaskData
- })
- } else {
- // 无数据时清空图表
- planScheduleOptions.xAxis.data = []
- planScheduleOptions.series[0].data = []
- planScheduleOptions.series[1].data = []
- setPlanScheduleOption(planScheduleOptions)
- }
- }
- // 更新问题发现统计图表数据
- const updateProblemDiscoveryChart = () => {
- if (checkProblemDiscovery.value && checkProblemDiscovery.value.checkProblemDiscoveryItemDtoList) {
- const discoveryList = checkProblemDiscovery.value.checkProblemDiscoveryItemDtoList
- // 提取横坐标数据(desc或name字段)
- const xAxisData = discoveryList.map(item => item.desc || item.name)
- // 为每个数据点创建包含tagDesc的对象
- const seriesData = [{
- name: '问题数量',
- type: 'line',
- smooth: true,
- symbol: 'circle',
- symbolSize: 6,
- itemStyle: {
- color: '#FF6B6B'
- },
- lineStyle: {
- color: '#FF6B6B',
- width: 3
- },
- label: {
- show: true,
- position: 'top',
- formatter: '{c}'
- },
- data: discoveryList.map(item => ({
- value: item.count || 0,
- tagDesc: item.tagDesc || '默认分类'
- }))
- }]
- // 更新图表配置
- problemDiscoveryOptions.xAxis.data = xAxisData
- // problemDiscoveryOptions.legend.data = ['问题数量']
- problemDiscoveryOptions.series = seriesData
- // 重新设置图表选项
- setProblemDiscoveryOption(problemDiscoveryOptions)
- console.log('问题发现图表已更新:', {
- })
- } else {
- // 无数据时清空图表
- problemDiscoveryOptions.xAxis.data = []
- problemDiscoveryOptions.series = [{
- name: '问题数量',
- type: 'line',
- smooth: true,
- symbol: 'circle',
- symbolSize: 6,
- itemStyle: {
- color: '#FF6B6B'
- },
- lineStyle: {
- color: '#FF6B6B',
- width: 3
- },
- label: {
- show: true,
- position: 'top',
- formatter: '{c}'
- },
- data: []
- }]
- setProblemDiscoveryOption(problemDiscoveryOptions)
- }
- }
- // 更新问题分布统计图表数据
- const updateProblemDistributionChart = () => {
- if (checkProblemDistribution.value && checkProblemDistribution.value.checkProblemDistributionItemDtoList) {
- const distributionList = checkProblemDistribution.value.checkProblemDistributionItemDtoList
- // 提取饼图数据
- const pieData = distributionList.map(item => ({
- value: item.total || 0,
- name: item.desc || item.name
- }))
- // 更新图表配置
- problemDistributionOptions.series[0].data = pieData
- // 重新设置图表选项
- setProblemDistributionOption(problemDistributionOptions)
- console.log('问题分布图表已更新:', pieData)
- } else {
- // 无数据时清空图表
- problemDistributionOptions.series[0].data = []
- setProblemDistributionOption(problemDistributionOptions)
- }
- }
- // 更新问题整改统计图表数据
- const updateProblemRectificationChart = () => {
- if (checkProblemCorrection.value && checkProblemCorrection.value.checkProblemCorrectionItemDtoList) {
- const rectificationList = checkProblemCorrection.value.checkProblemCorrectionItemDtoList
- // 提取横坐标数据(科室名称)
- const xAxisData = rectificationList.map(item => item.deptName || '未知科室')
- // 提取各个数据系列
- const onTimeCompletedData = rectificationList.map(item => item.onTimeCompletedCount || 0)
- const overTimeCompletedData = rectificationList.map(item => item.overTimeCompletedCount || 0)
- const onTimeUnfinishedData = rectificationList.map(item => item.onTimeUnfinishedCount || 0)
- const overTimeUnfinishedData = rectificationList.map(item => item.overTimeUnfinishedCount || 0)
- const otherData = rectificationList.map(item => item.otherCount || 0)
- // 更新图表配置
- problemRectificationOptions.xAxis.data = xAxisData
- problemRectificationOptions.series[0].data = onTimeCompletedData
- problemRectificationOptions.series[1].data = overTimeCompletedData
- problemRectificationOptions.series[2].data = onTimeUnfinishedData
- problemRectificationOptions.series[3].data = overTimeUnfinishedData
- problemRectificationOptions.series[4].data = otherData
- // 重新设置图表选项
- setProblemRectificationOption(problemRectificationOptions)
- console.log('问题整改图表已更新:', {
- xAxis: xAxisData,
- 按期已完成: onTimeCompletedData,
- 超期已完成: overTimeCompletedData,
- 按期整改中: onTimeUnfinishedData,
- 超期整改中: overTimeUnfinishedData,
- 其他: otherData
- })
- } else {
- // 无数据时清空图表
- problemRectificationOptions.xAxis.data = []
- problemRectificationOptions.series[0].data = []
- problemRectificationOptions.series[1].data = []
- problemRectificationOptions.series[2].data = []
- problemRectificationOptions.series[3].data = []
- problemRectificationOptions.series[4].data = []
- setProblemRectificationOption(problemRectificationOptions)
- }
- }
- // 根据API数据更新图表和统计信息
- const updateChartsWithData = () => {
- // 更新任务计划安排图表
- updatePlanScheduleChart()
- // 更新问题发现统计图表
- updateProblemDiscoveryChart()
- // 更新问题分布统计图表
- updateProblemDistributionChart()
- // 更新问题整改统计图表
- updateProblemRectificationChart()
- console.log('数据已更新,所有图表已刷新')
- }
- // 组件卸载时销毁图表
- onUnmounted(() => {
- disposePlanSchedule()
- disposeProblemDiscovery()
- disposeProblemDistribution()
- disposeProblemRectification()
- })
- // 任务计划安排柱状图配置
- const planScheduleOptions = {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- },
- formatter: function (params) {
- let result = `${params[0].axisValue}<br/>`
- params.forEach(param => {
- result += `${param.seriesName}: <span style="color:${param.color};font-weight:bold">${param.data}</span><br/>`
- })
- return result
- }
- },
- legend: {
- data: ['专项任务', '日常任务'],
- top: 0
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- top: '15%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: [],
- axisLine: {
- lineStyle: {
- color: '#999'
- }
- },
- axisLabel: {
- fontSize: 12
- }
- },
- yAxis: {
- type: 'value',
- name: '任务数量',
- axisLine: {
- lineStyle: {
- color: '#999'
- }
- },
- splitLine: {
- lineStyle: {
- color: '#f0f0f0'
- }
- }
- },
- series: [
- {
- name: '专项任务',
- type: 'bar',
- barWidth: '35%',
- itemStyle: {
- color: '#FF6B6B'
- },
- label: {
- show: true,
- position: 'top',
- formatter: '{c}'
- },
- data: []
- },
- {
- name: '日常任务',
- type: 'bar',
- barWidth: '35%',
- itemStyle: {
- color: '#4ECDC4'
- },
- label: {
- show: true,
- position: 'top',
- formatter: '{c}'
- },
- data: []
- }
- ]
- }
- // 问题发现折线图配置
- const problemDiscoveryOptions = {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- },
- formatter: function (params) {
- let result = `${params[0].axisValue}<br/>`
- params.forEach(param => {
- const tagDesc = param.data.tagDesc || '默认分类'
- const value = param.data.value || 0
- result += `${tagDesc}: <span style="color:${param.color};font-weight:bold">${value}</span><br/>`
- })
- return result
- }
- },
- legend: {
- data: [],
- top: 0
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- top: '15%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: [],
- axisLine: {
- lineStyle: {
- color: '#999'
- }
- },
- axisLabel: {
- fontSize: 12
- }
- },
- yAxis: {
- type: 'value',
- name: '问题数量',
- axisLine: {
- lineStyle: {
- color: '#999'
- }
- },
- splitLine: {
- lineStyle: {
- color: '#f0f0f0'
- }
- }
- },
- series: []
- }
- // 问题分布饼图配置
- const problemDistributionOptions = {
- tooltip: {
- trigger: 'item',
- formatter: '{a} <br/>{b}: {c}个 ({d}%)'
- },
- legend: {
- orient: 'horizontal',
- left: 'center',
- top: 'top',
- textStyle: {
- color: '#333',
- fontSize: 12
- }
- },
- color: ['#FF9F43', '#54C6EB', '#A3D9B1', '#FF6B9D', '#9B59B6'],
- series: [
- {
- name: '问题分布',
- type: 'pie',
- radius: '60%',
- center: ['50%', '50%'],
- avoidLabelOverlap: false,
- itemStyle: {
- borderRadius: 10,
- borderColor: '#fff',
- borderWidth: 2
- },
- label: {
- show: true,
- formatter: '{b}: {c}个',
- fontSize: 12
- },
- emphasis: {
- label: {
- show: true,
- fontSize: 14,
- fontWeight: 'bold'
- },
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- },
- labelLine: {
- show: true,
- length: 10,
- length2: 20
- },
- data: []
- }
- ]
- }
- // 问题整改柱状图配置
- const problemRectificationOptions = {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- },
- formatter: function (params) {
- let result = `${params[0].axisValue}<br/>`
- params.forEach(param => {
- result += `${param.seriesName}: <span style="color:${param.color};font-weight:bold">${param.data}</span>个<br/>`
- })
- return result
- }
- },
- legend: {
- data: ['按期已完成', '超期已完成', '按期整改中', '超期整改中', '其他'],
- top: 0
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '0%',
- top: '30%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: [],
- axisLine: {
- lineStyle: {
- color: '#999'
- }
- },
- axisLabel: {
- fontSize: 12
- }
- },
- yAxis: {
- type: 'value',
- name: '问题数量',
- axisLine: {
- lineStyle: {
- color: '#999'
- }
- },
- splitLine: {
- lineStyle: {
- color: '#f0f0f0'
- }
- }
- },
- series: [
- {
- name: '按期已完成',
- type: 'bar',
- barWidth: '10%', temStyle: {
- color: '#4ECDC4'
- },
- label: {
- show: false,
- position: 'top',
- formatter: '{c}个'
- },
- data: []
- },
- {
- name: '超期已完成',
- type: 'bar',
- barWidth: '10%',
- itemStyle: {
- color: '#FF6B6B'
- },
- label: {
- show: false,
- position: 'top',
- formatter: '{c}个'
- },
- data: []
- },
- {
- name: '按期整改中',
- type: 'bar',
- barWidth: '10%',
- itemStyle: {
- color: '#FFD166'
- },
- label: {
- show: false,
- position: 'top',
- formatter: '{c}个'
- },
- data: []
- },
- {
- name: '超期整改中',
- type: 'bar',
- barWidth: '10%',
- itemStyle: {
- color: '#9B59B6'
- },
- label: {
- show: false,
- position: 'top',
- formatter: '{c}个'
- },
- data: []
- },
- {
- name: '其他',
- type: 'bar',
- barWidth: '10%',
- itemStyle: {
- color: '#95A5A6'
- },
- label: {
- show: false,
- position: 'top',
- formatter: '{c}个'
- },
- data: []
- }
- ]
- }
- </script>
- <style scoped>
- .quality-control {
- width: 100%;
- }
- /* 质控活动标题 */
- .section-title {
- margin: 14px 0 14px 0;
- text-align: left;
- }
- .section-title h2 {
- font-size: 24px;
- font-weight: 600;
- color: #333;
- margin: 0;
- }
- /* 四个横向均分布局 */
- .four-panel-layout {
- display: flex;
- gap: 16px;
- margin-bottom: 20px;
- }
- .panel-item {
- flex: 1;
- background: white;
- border-radius: 8px;
- padding: 20px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- display: flex;
- flex-direction: column;
- gap: 16px;
- }
- .panel-header {
- padding-bottom: 0;
- }
- .panel-header h3 {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- margin: 0;
- }
- /* 统计卡片容器 */
- .stat-cards {
- display: flex;
- gap: 12px;
- }
- /* 统计卡片样式 */
- .stat-card {
- flex: 1;
- background: #F8F8F8;
- /* border: 1px dashed #CDCCCC; */
- border-radius: 6px;
- padding: 7px 10px;
- text-align: left;
- display: flex;
- flex-direction: column;
- gap: 4px;
- }
- .stat-title {
- font-size: 14px;
- font-weight: 500;
- color: #3D3D3D;
- }
- .stat-count {
- font-size: 13px;
- color: #222222;
- span {
- font-weight: 600;
- font-size: 16px;
- }
- }
- .stat-trend {
- font-size: 12px;
- font-weight: 500;
- }
- .stat-trend .down {
- color: #67C23A;
- }
- .stat-trend .up {
- color: #F56C6C;
- }
- .stat-trend .neutral {
- color: #909399;
- }
- /* 描述卡片样式 */
- .describe-card {
- background: #F8F8F8;
- border: 1px dashed #CDCCCC;
- border-radius: 6px;
- padding: 7px 10px;
- text-align: left;
- }
- .describe-content {
- font-size: 13px;
- color: #666;
- line-height: 1.5;
- }
- .stat-number {
- font-weight: 600;
- color: #557DDB;
- font-size: 16px;
- }
- /* 图表容器 */
- .chart-container {
- /* background: #F8F8F8;
- border-radius: 6px;
- padding: 16px; */
- min-height: 200px;
- height: 250px;
- position: relative;
- box-sizing: border-box;
- overflow: hidden;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- /* 防止被压缩 */
- }
- /* ECharts图表样式 */
- .echarts-chart {
- width: 100% !important;
- height: 100% !important;
- min-height: 200px;
- display: block;
- }
- /* 响应式设计 */
- @media (max-width: 768px) {
- .four-panel-layout {
- flex-direction: column;
- }
- .stat-cards {
- flex-direction: column;
- }
- }
- </style>
|