gx
chenyc
2025-03-06 509acf8dac4d27c82f00695ef12948ec6f3c6634
gx
7个文件已修改
5个文件已添加
1432 ■■■■■ 已修改文件
package-lock.json 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/QC/index.ts 207 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/QC/type.ts 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/i18n/lang/zh-cn.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/navBars/topBar/breadcrumb.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/navBars/topBar/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/route.ts 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/Export2.ts 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tongji/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/zhikong/components/components.vue 617 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/zhikong/xueqingdanbai.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -41,7 +41,8 @@
                "vue-grid-layout": "^3.0.0-beta1",
                "vue-i18n": "^9.10.2",
                "vue-router": "^4.3.0",
                "vue3-print-nb": "^0.1.4"
                "vue3-print-nb": "^0.1.4",
                "xlsx": "^0.18.5"
            },
            "devDependencies": {
                "@types/node": "^20.11.28",
@@ -1695,6 +1696,15 @@
                "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
            }
        },
        "node_modules/adler-32": {
            "version": "1.3.1",
            "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz",
            "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
            "license": "Apache-2.0",
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/ajv": {
            "version": "6.12.6",
            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -1913,6 +1923,19 @@
            "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
            "optional": true
        },
        "node_modules/cfb": {
            "version": "1.2.2",
            "resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz",
            "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
            "license": "Apache-2.0",
            "dependencies": {
                "adler-32": "~1.3.0",
                "crc-32": "~1.2.0"
            },
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/chalk": {
            "version": "4.1.2",
            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -1983,6 +2006,15 @@
                "tiny-emitter": "^2.0.0"
            }
        },
        "node_modules/codepage": {
            "version": "1.15.0",
            "resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz",
            "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
            "license": "Apache-2.0",
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/color-convert": {
            "version": "2.0.1",
            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2038,6 +2070,18 @@
            "version": "2.8.0",
            "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.8.0.tgz",
            "integrity": "sha512-f7xEhX0awl4NOElHulrl4XRfKoNH3rB+qfNSZZyjSZhaAoUk6elvhH+MNxMmlmuUJ2/QNTWPSA7U4mNtIAKljQ=="
        },
        "node_modules/crc-32": {
            "version": "1.2.2",
            "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz",
            "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
            "license": "Apache-2.0",
            "bin": {
                "crc32": "bin/crc32.njs"
            },
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/cropperjs": {
            "version": "1.6.1",
@@ -2711,6 +2755,15 @@
            },
            "engines": {
                "node": ">= 6"
            }
        },
        "node_modules/frac": {
            "version": "1.1.2",
            "resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz",
            "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
            "license": "Apache-2.0",
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/fs-extra": {
@@ -4033,6 +4086,18 @@
                "url": "https://github.com/sponsors/antoniandre"
            }
        },
        "node_modules/ssf": {
            "version": "0.11.2",
            "resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz",
            "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
            "license": "Apache-2.0",
            "dependencies": {
                "frac": "~1.1.2"
            },
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/ssr-window": {
            "version": "3.0.0",
            "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz",
@@ -4497,11 +4562,50 @@
            "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz",
            "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
        },
        "node_modules/wmf": {
            "version": "1.0.2",
            "resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz",
            "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
            "license": "Apache-2.0",
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/word": {
            "version": "0.3.0",
            "resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz",
            "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
            "license": "Apache-2.0",
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/wrappy": {
            "version": "1.0.2",
            "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
            "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
            "dev": true
        },
        "node_modules/xlsx": {
            "version": "0.18.5",
            "resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz",
            "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
            "license": "Apache-2.0",
            "dependencies": {
                "adler-32": "~1.3.0",
                "cfb": "~1.2.1",
                "codepage": "~1.15.0",
                "crc-32": "~1.2.1",
                "ssf": "~0.11.2",
                "wmf": "~1.0.1",
                "word": "~0.3.0"
            },
            "bin": {
                "xlsx": "bin/xlsx.njs"
            },
            "engines": {
                "node": ">=0.8"
            }
        },
        "node_modules/xml-name-validator": {
            "version": "4.0.0",
@@ -5572,6 +5676,11 @@
            "dev": true,
            "requires": {}
        },
        "adler-32": {
            "version": "1.3.1",
            "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz",
            "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A=="
        },
        "ajv": {
            "version": "6.12.6",
            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -5740,6 +5849,15 @@
                }
            }
        },
        "cfb": {
            "version": "1.2.2",
            "resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz",
            "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
            "requires": {
                "adler-32": "~1.3.0",
                "crc-32": "~1.2.0"
            }
        },
        "chalk": {
            "version": "4.1.2",
            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -5792,6 +5910,11 @@
                "tiny-emitter": "^2.0.0"
            }
        },
        "codepage": {
            "version": "1.15.0",
            "resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz",
            "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA=="
        },
        "color-convert": {
            "version": "2.0.1",
            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -5836,6 +5959,11 @@
            "version": "2.8.0",
            "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.8.0.tgz",
            "integrity": "sha512-f7xEhX0awl4NOElHulrl4XRfKoNH3rB+qfNSZZyjSZhaAoUk6elvhH+MNxMmlmuUJ2/QNTWPSA7U4mNtIAKljQ=="
        },
        "crc-32": {
            "version": "1.2.2",
            "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz",
            "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="
        },
        "cropperjs": {
            "version": "1.6.1",
@@ -6362,6 +6490,11 @@
                "combined-stream": "^1.0.8",
                "mime-types": "^2.1.12"
            }
        },
        "frac": {
            "version": "1.1.2",
            "resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz",
            "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
        },
        "fs-extra": {
            "version": "10.1.0",
@@ -7311,6 +7444,14 @@
            "resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-3.1.5.tgz",
            "integrity": "sha512-r3Mq2ITFQ5a2VXLOy4/Sb2Ptp7OfEO8YIbhVJqJXoFc9hc5nTXXkCvtVDjIGbvC0vdE7tse+xTM9BMjsszP6bw=="
        },
        "ssf": {
            "version": "0.11.2",
            "resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz",
            "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
            "requires": {
                "frac": "~1.1.2"
            }
        },
        "ssr-window": {
            "version": "3.0.0",
            "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz",
@@ -7622,12 +7763,36 @@
            "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz",
            "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
        },
        "wmf": {
            "version": "1.0.2",
            "resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz",
            "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw=="
        },
        "word": {
            "version": "0.3.0",
            "resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz",
            "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA=="
        },
        "wrappy": {
            "version": "1.0.2",
            "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
            "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
            "dev": true
        },
        "xlsx": {
            "version": "0.18.5",
            "resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz",
            "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
            "requires": {
                "adler-32": "~1.3.0",
                "cfb": "~1.2.1",
                "codepage": "~1.15.0",
                "crc-32": "~1.2.1",
                "ssf": "~0.11.2",
                "wmf": "~1.0.1",
                "word": "~0.3.0"
            }
        },
        "xml-name-validator": {
            "version": "4.0.0",
            "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
package.json
@@ -43,7 +43,8 @@
        "vue-grid-layout": "^3.0.0-beta1",
        "vue-i18n": "^9.10.2",
        "vue-router": "^4.3.0",
        "vue3-print-nb": "^0.1.4"
        "vue3-print-nb": "^0.1.4",
        "xlsx": "^0.18.5"
    },
    "devDependencies": {
        "@types/node": "^20.11.28",
src/api/QC/index.ts
New file
@@ -0,0 +1,207 @@
import request from "/@/utils/request";
import type { IPatientDialysisFrequencyCountRes, IPatientDialysisFrequencyCountParams, ItKtvAndUrrListByCondition, IGetKtvAndUrrListByCondition, IWypertensionStatistics, IWypertensionStatisticsParams, IQualityControlReportParams, IQualityControlReportReponse, WeightControlRateDetail, WeightControlRateByYearParams, WeightControlRateByYear, WeightControlRateDetailstParams } from './types'
import { AxiosPromise } from 'axios';
export function listWorkStats(params: object) {
    return request({
        url: '/patient/hemo/med/record/listWorkStats',
        method: 'post',
        data: params,
    });
}
export function listHemoNurseWorkStats(params: object) {
    return request({
        url: '/patient/hemo/med/record/listHemoNurseWorkStats',
        method: 'post',
        data: params,
    });
}
export function listRecordsByToolUsage(params: object) {
    return request({
        url: '/patient/hemo/med/record/listRecordsByToolUsage',
        method: 'post',
        data: params,
    });
}
export function listRecordsByMedicineUsage(params: object) {
    return request({
        url: '/patient/hemo/med/record/listRecordsByMedicineUsage',
        method: 'post',
        data: params,
    });
}
export function listDetailsOfMedicineUsage(params: object) {
    return request({
        url: '/patient/hemo/med/record/listDetailsOfMedicineUsage',
        method: 'post',
        data: params,
    });
}
export function doStatByResult(params: object) {
    return request({
        url: '/lis/stat/doStatByResult',
        method: 'post',
        data: params,
    });
}
export function doClientStat4(params: object) {
    return request({
        url: '/lis/stat/doClientStat4',
        method: 'post',
        data: params,
    });
}
export function doListResultsGroupByMonth(params: object) {
    return request({
        url: '/lis/stat/doListResultsGroupByMonth',
        method: 'post',
        data: params,
    });
}
export function doListTestItems() {
    return request({
        url: '/lis/stat/doListTestItems',
        method: 'post',
    });
}
export function doTestItemPassedCount(params: object) {
    return request({
        url: '/lis/stat/doTestItemPassedCount',
        method: 'post',
        data: params,
    });
}
export function listGroups() {
    return request({
        url: '/client/group/info/listGroups',
        method: 'post',
    });
}
export function listDetailsEachOne(params) {
    return request({
        url: '/client/group/info/listDetailsEachOne',
        method: 'post',
        // headers: {
        //     'Content-Type': 'application/x-www-form-urlencoded'
        // },
        params,
    });
}
/**
 * 重新计算KTV与URR
 * @param params
 * @returns
 */
export function doCalcKtvOrUrrApi(params) {
    return request({
        url: '/lis/stat/doCalcKtvOrUrr',
        method: 'post',
        params
    })
}
/**
 * 统计体重增长控制率
 * @param params
 * @returns
 */
export function weightControlRateByYearApi(params: WeightControlRateByYearParams): AxiosPromise<WeightControlRateByYear> {
    return request({
        url: '/patient/stat/weight/increase/range/weightControlRateByYear',
        method: 'post',
        params
    })
}
/** 统计体重增长控制率详情 */
export function weightControlRateDetailsApi(data: WeightControlRateDetailstParams): AxiosPromise<{ list: WeightControlRateDetail[]; total: number }> {
    return request({
        url: '/patient/stat/weight/increase/range/weightControlRateDetails',
        method: 'post',
        data
    })
}
/**
 * 查询KTV Or URR接口
 * @param data
 * @returns
 */
// export function getKtvAndUrrListByConditionsApi(data: IGetKtvAndUrrListByCondition) :AxiosPromise<{ list: ItKtvAndUrrListByCondition[]; total: number; }> {
//     return request({
//         url: '/patient/ktv/listByConditions',
//         method: 'post',
//         data
//     })
// }
/**
 * 查询KTV Or URR接口
 * @param data
 * @returns
 */
export function getKtvAndUrrListByConditionsApi(data: IGetKtvAndUrrListByCondition) :AxiosPromise<{ list: ItKtvAndUrrListByCondition[]; total: number; }> {
    return request({
        url: '/patient/ktv/listByConditions',
        method: 'post',
        data
    })
}
/**
 * 药物用量统计页面
 */
export function listGroupByDrug(param) {
    return request({
        url: '/patient/drug/order/vs/patient/listGroupByDrug',
        method: 'post',
        params:param
    })
}
/**
 * 获取高血压控制率
 * @param params
 * @returns
 */
export function hypertensionStatisticsApi(params: IWypertensionStatisticsParams) :AxiosPromise<IWypertensionStatistics> {
    return request({
        url: '/patient/hemo/med/body/state/pre/hypertensionStatistics',
        method: 'post',
        params
    })
}
/**
 * 获取质控报表
 * @param params
 * @returns
 */
export function qualityControlReportApi(params: IQualityControlReportParams): AxiosPromise<IQualityControlReportReponse> {
    return request({
        url: '/patient/info/qualityControlReport',
        method: 'post',
        params
    })
}
/**
 * 月度患者透析次数统计接口
 * @param data
 * @returns
 */
export function patientDialysisFrequencyCountApi(data: IPatientDialysisFrequencyCountParams) :AxiosPromise<IPatientDialysisFrequencyCountRes> {
    return request({
        url: '/patient/hemo/med/record/patientDialysisFrequencyCount',
        method: 'post',
        data
    })
}
src/api/QC/type.ts
New file
@@ -0,0 +1,159 @@
import { IComminList } from '../common.type';
export interface WeightControlRateByYearParams {
    clientCode: string;
    year: number;
    quarter: number;
    maxValue: number;
    minValue: number;
}
export interface WeightControlRateByYear {
    allcount: number;
    conditionCount: number;
}
export interface WeightControlRateDetailstParams {
    year: number;
    quarter: number;
    weightControlRateDetailsCondition: {
        page: number;
        size: number;
        clientCode: string;
        maxValue: number;
        minValue: number;
    };
}
export interface WeightControlRateDetail {
    age: string;
    code: string;
    patientGender: number;
    patientName: string;
}
export interface IGetKtvAndUrrListByCondition {
    page: number;
    size: number;
    clientCode: string;
    startTime: string;
    endTime: string;
    patientName: string;
    patientCodes: string[];
}
export interface ItKtvAndUrrListByCondition {
    code: string; //数据代码
    dataKtv: number; //KTV
    dataMedPeriod: number; //透析时间(小时)
    dataNiaosu1: number; //透前尿素
    dataNiaosu2: number; //透后尿素
    dataUrr: number; //URR
    dataWeight1: number; //透前体重
    dataWeight2: number; //透后体重
    id: number; //记录ID
    patientCode: string; //患者编号
    patientName: string; //患者姓名
    recordCode: string; //透析单
    sampleDate: string; //采样日期
}
export interface IPatientDialysisFrequencyCountParams {
    page: number;
    size: number;
    clientCode: string;
    patientCodes: string[];
    scheduleTimeSlots: string[];
    recordsStatus: string;
    startTime: string;
    endTime: string;
}
export interface IPatientDialysisFrequencyCount {
    allCount: string;
    patientCode: string;
    patientName: string;
    typeCounts: IPatientDialysisFrequencyCountTypeCount[];
}
export interface IPatientDialysisFrequencyCountTypeCount {
    schemeName: string;
    typeCount: string;
}
export interface IPatientDialysisFrequencyCountRes extends Omit<IComminList, 'list'> {
    list: IPatientDialysisFrequencyCount[];
}
export interface IWypertensionStatisticsParams {
    clientCode: string;
    beginTime: string;
    endTime: string;
}
export interface IQualityControlReportLisResults {
    client_code: string;
    item_name: string;
    item_result: string;
    item_result_flag: string;
    item_result_ref: string;
    item_result_unit: string;
    patient_name: string;
    sample_date: string;
    sample_date_str: string;
    最新报告日期: string;
}
export interface IWypertensionStatistics {
    大于60岁患者: IWypertensionStatisticsObj;
    小于等于60岁患者: IWypertensionStatisticsObj;
    没有年龄的患者: IWypertensionStatisticsItem[];
    透析总人数: number;
}
export interface IWypertensionStatisticsItem {
    patientCode: string;
    patientName: string;
    preMbpH: string;
    preMbpL: string;
    signTime: string;
}
export interface IWypertensionStatisticsObj {
    count: number;
    eligiblePatientCount: number;
    eligiblePatients: IWypertensionStatisticsItem[];
    noEligiblePatientCount: number;
    noEligiblePatients: IWypertensionStatisticsItem[];
}
export interface IQualityControlReportParams {
    clientCode: string;
    beginTime: string;
    endTime: string;
    page: number;
    size: number;
    systemItemNames: string;
}
export interface IQualityControlReport {
    accessFirstUseDate: string;
    age: number;
    code: string;
    dictText: string;
    patientDiagnose: string;
    patientName: string;
    sex: string;
    survivalTime: string;
    lisResults: IQualityControlReportLisResults[];
}
export interface IQualityControlReportReponse {
    total: number;
    list: IQualityControlReport[];
    [key: string]: any;
}
src/i18n/lang/zh-cn.ts
@@ -72,6 +72,7 @@
        visualizingLinkDemo2: '数据可视化演示2',
        personal: '个人中心',
        tongji:'患者健康服务统计',
        xueqingdanbai:'质控-血清蛋白控制率',
        tools: '工具类集合',
        layoutLinkView: '外链',
        layoutIframeViewOne: '内嵌 iframe1',
src/layout/navBars/topBar/breadcrumb.vue
@@ -26,12 +26,33 @@
        <el-avatar shape="square" style="width: 48px; height: 35px;background-color: #ffffff;margin-right: 10px;margin-left: 10px;" fit="contain" :src="logo" />
        <div class="titleHome">营养管理系统</div>
        <div style="margin-left: 20px;">
            <el-dropdown  @command="onHandleCommandClick">
                <span class="el-dropdown-link">
                    统计帮助
                    <el-icon class="el-icon--right">
                        <arrow-down />
                    </el-icon>
            </span>
            <template #dropdown>
            <el-dropdown-menu>
                <el-dropdown-item command="/tongji">患者健康服务统计</el-dropdown-item>
                <el-dropdown-item command="/zhikong/xueqingdanbai">质控-血清蛋白控制率</el-dropdown-item>
                <!-- <el-dropdown-item>Action 3</el-dropdown-item>
                <el-dropdown-item disabled>Action 4</el-dropdown-item>
                <el-dropdown-item divided>Action 5</el-dropdown-item> -->
            </el-dropdown-menu>
            </template>
        </el-dropdown>
        </div>
        
    </div>
</template>
<script setup lang="ts" name="layoutBreadcrumb">
import { ArrowDown } from '@element-plus/icons-vue'
import { reactive, computed, onMounted } from 'vue';
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
import { Local } from '/@/utils/storage';
@@ -104,6 +125,10 @@
    if (state.breadcrumbList.length > 0)
        state.breadcrumbList[state.breadcrumbList.length - 1].meta.tagsViewName = other.setTagsViewNameI18n(<RouteToFrom>route);
};
// 下拉菜单点击时
const onHandleCommandClick = (path: string) => {
    router.push(path);
};
// 页面加载时
onMounted(() => {
    initRouteSplit(route.path);
@@ -115,6 +140,12 @@
</script>
<style scoped lang="scss">
.example-showcase .el-dropdown-link {
  cursor: pointer;
  color: var(--el-color-primary);
  display: flex;
  align-items: center;
}
.layout-navbars-breadcrumb {
    flex: 1;
    height: inherit;
src/layout/navBars/topBar/index.vue
@@ -5,6 +5,7 @@
        
        <Horizontal :menuList="state.menuList" v-if="isLayoutTransverse" />
        <User />
    </div>
</template>
@@ -21,6 +22,7 @@
const User = defineAsyncComponent(() => import('/@/layout/navBars/topBar/user.vue'));
const Logo = defineAsyncComponent(() => import('/@/layout/logo/index.vue'));
const Horizontal = defineAsyncComponent(() => import('/@/layout/navMenu/horizontal.vue'));
const setings = defineAsyncComponent(() => import('/@/layout/navBars/topBar/setings.vue'));
// 定义变量内容
const stores = useRoutesList();
src/router/route.ts
@@ -1135,6 +1135,21 @@
                },
            },
            {
                path: '/zhikong/xueqingdanbai',
                name: 'xueqingdanbai',
                component: () => import('/@/views/zhikong/xueqingdanbai.vue'),
                meta: {
                    title: 'message.router.xueqingdanbai',
                    isLink: '',
                    isHide: false,
                    isKeepAlive: true,
                    isAffix: false,
                    isIframe: false,
                    roles: ['admin', 'common'],
                    icon: 'iconfont icon-gerenzhongxin',
                },
            },
            {
                path: '/tools',
                name: 'tools',
                component: () => import('/@/views/tools/index.vue'),
src/utils/Export2.ts
New file
@@ -0,0 +1,174 @@
import FileSaver from 'file-saver'
import * as XLSX from 'xlsx'
// 自动计算col列宽
function auto_width(ws, data) {
  /*set worksheet max width per col*/
  const colWidth = data.map(row => row.map(val => {
    /*if null/undefined*/
    if (val == null) {
      return { 'wch': 10 }
    }
    /*if chinese*/
    else if (val.toString().charCodeAt(0) > 255) {
      return { 'wch': val.toString().length * 2 }
    } else {
      return { 'wch': val.toString().length }
    }
  }))
  /*start in the first row*/
  let result = colWidth[0]
  for (let i = 1; i < colWidth.length; i++) {
    for (let j = 0; j < colWidth[i].length; j++) {
      if (result[j]['wch'] < colWidth[i][j]['wch']) {
        result[j]['wch'] = colWidth[i][j]['wch']
      }
    }
  }
  ws['!cols'] = result
}
// 将json数据转换成数组
function json_to_array(key, jsonData) {
  return jsonData.map(v => key.map(j => {
    return v[j]
  }))
}
/**
 * @param header Object,表头
 * @param data Array,表体数据
 * @param key Array,字段名
 * @param title String,标题(会居中显示),即excel表格第一行
 * @param filename String,文件名
 * @param autoWidth Boolean,是否自动根据key自定义列宽度
 */
export const exportJsonToExcel = ({
  header,
  data,
  key,
  title,
  filename,
  autoWidth
}) => {
  const wb = XLSX.utils.book_new()
  if (header) {
    data.unshift(header)
  }
  if (title) {
    data.unshift(title)
  }
  const ws = XLSX.utils.json_to_sheet(data, {
    header: key,
    skipHeader: true
  })
  // 合并单元格以覆盖整个第一行
  // ws['!merges'] = [{ s: {r:0, c:0}, e: {r:0, c:header.length - 1} }];
  if (autoWidth) {
    const arr = json_to_array(key, data)
    auto_width(ws, arr)
  }
  XLSX.utils.book_append_sheet(wb, ws, filename)
  XLSX.writeFile(wb, filename + '.xlsx')
}
/**
 * 自动计算并设置列宽
 * @param {Object} ws - 工作表对象
 * @param {Array} data - 表格数据(二维数组)
 */
function autoWidth(ws, data) {
  // 初始化每列宽度为默认值10
  const colWidths = Array(data[0].length).fill(10);
  // 遍历数据以计算最大宽度
  data.forEach(row => {
    row.forEach((val, index) => {
      let length = val ? (typeof val === 'string' ? getStrLen(val) : String(val).length) : 10;
      if (colWidths[index] < length) {
        colWidths[index] = length; // 更新最大宽度
      }else{
        colWidths[index] = 20; // 更新最大宽度
      }
    });
  });
  // 设置列宽
  ws['!cols'] = colWidths.map(width => ({ wch: width }));
}
/**
 * 计算字符串长度,考虑多字节字符(如中文)
 * @param {string} str - 输入字符串
 * @returns {number} 字符串长度
 */
function getStrLen(str) {
  return [...str].reduce((len, char) => len + (char.charCodeAt(0) > 255 ? 2 : 1), 0);
}
export const exportTableToExcel=(divId:string,name:string)=>{
  var wb = XLSX.utils.table_to_book(document.querySelector(divId));//关联dom节点
  console.log(wb)
  // 获取第一个工作表
  const ws = wb.Sheets[wb.SheetNames[0]];
  // 获取表格数据作为二维数组
  const data = XLSX.utils.sheet_to_json(ws, { header: 1 });
  // 设置列宽
  autoWidth(ws, data);
  var wbout = XLSX.write(wb, {
        bookType: 'xlsx',
        bookSST: true,
        type: 'array'
    })
  try {
        FileSaver.saveAs(new Blob([wbout], {
            type: 'application/octet-stream'
        }), `${name}.xlsx`)//自定义文件名
    } catch (e) {
        if (typeof console !== 'undefined') console.log(e, wbout);
    }
    return wbout
}
export const exportTableToExcel2 = async (divId: string, name: string): Promise<Uint8Array | null> => {
  try {
    // 关联 DOM 节点
    const tableElement = document.querySelector(divId);
    if (!tableElement) {
      console.error("Table element not found");
      return null;
    }
    // 转换表格为工作簿
    const wb = XLSX.utils.table_to_book(tableElement);
    console.log(wb);
    // 将工作簿写入文件
    const wbout = XLSX.write(wb, {
      bookType: 'xlsx',
      bookSST: true,
      type: 'array',
    });
    // 保存文件
    await new Promise<void>((resolve, reject) => {
      try {
        FileSaver.saveAs(
          new Blob([wbout], { type: 'application/octet-stream' }),
          `${name}.xlsx`
        );
        resolve();
      } catch (e) {
        console.error("Error saving file:", e);
        reject(e);
      }
    });
    // 返回生成的二进制数组
    return wbout;
  } catch (error) {
    console.error("Error exporting table to Excel:", error);
    return null;
  }
};
export default {
  exportJsonToExcel,
  exportTableToExcel
}
src/views/tongji/index.vue
@@ -17,6 +17,9 @@
            <el-form-item>
                <el-button type="primary" @click="onSubmit">查询</el-button>
            </el-form-item>
            <el-form-item>
                <el-button type="success" @click="daochuExcel">导出</el-button>
            </el-form-item>
        </el-form>
        <div class="scrollable-table" :style="{maxHeight:tableHe}">
@@ -130,6 +133,7 @@
import {nutritionalSummary} from '/@/api/Patients'
import {editUserInfo} from '/@/api/login'
import { ElLoading } from 'element-plus';
import * as XLSX from 'xlsx';
import {formatDate} from '/@/utils/formatTime'
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);
@@ -289,6 +293,15 @@
    },
    dialogTableVisible:false
})
const daochuExcel=()=>{
    let table = document.getElementById('tabledome');
      if (table) {
        const wb = XLSX.utils.table_to_book(table, { sheet: "Sheet1" });
          XLSX.writeFile(wb, "患者健康服务统计.xlsx"); // 文件名和扩展名可以根据需要更改
      } else {
        console.error("找不到指定的表格");
      }
}
const onSubmit=()=>{
    const pasm={
        startTime:state.formInline.date[0]+ ' 00:00:00',
@@ -297,9 +310,16 @@
        queryValue:''
    }
    console.log(pasm)
    const loading = ElLoading.service({
        lock: true,
        text: 'Loading',
        background: 'rgba(0, 0, 0, 0.7)',
    })
    nutritionalSummary(pasm).then(re=>{
        console.log(re.data)
        state.tableData=re.data
    }).finally(()=>{
        loading.close()
    })
}
src/views/zhikong/components/components.vue
New file
@@ -0,0 +1,617 @@
<template>
    <el-row class="control_rate_container">
        <el-col :span="24" class="card_box card_box_search">
            <el-form :model="searchForm" size="small" inline>
                <el-form-item label="查询日期">
                    <el-date-picker
                        v-model="searchForm.dates"
                        type="daterange"
                        unlink-panels
                        range-separator="至"
                        start-placeholder="开始日期"
                        end-placeholder="结束日期"
                        :clearable="false"
                    />
                </el-form-item>
                <el-form-item label="透析龄">
                    <el-select v-model="searchForm.medMonth" placeholder="透析龄">
                        <el-option label="全部" :value="0" />
                        <el-option label=">=三个月" :value="1" />
                        <el-option label="<三个月" :value="2" />
                    </el-select>
                </el-form-item>
                <el-form-item label="转归状态">
                    <el-select v-model="searchForm.isInState" placeholder="转归状态">
                        <el-option label="不限" :value="0" />
                        <el-option label="在院" :value="1" />
                        <el-option label="转出" :value="2" />
                    </el-select>
                </el-form-item>
                <el-form-item v-if="!isBloodPressure" label="标准值设定" prop="">
                    <el-row>
                        <span :span="8">
                            <el-input style="width: 150px" v-model="searchForm.limitBottom" @input="limitBottomInp"></el-input>
                        </span>
                        <span :span="8">≤标准值≤</span>
                        <span :span="8">
                            <el-input style="width: 150px" v-model="searchForm.limitTop" @input="limitTopInp"></el-input>
                        </span>
                    </el-row>
                </el-form-item>
                <template v-else>
                    <el-form-item label="收缩压标准值设定" prop="">
                        <el-row>
                            <span :span="8">
                                <el-input style="width: 150px" v-model="searchForm.limitBottom" @input="limitBottomInp"></el-input>
                            </span>
                            <span :span="8">≤标准值≤</span>
                            <span :span="8">
                                <el-input style="width: 150px" v-model="searchForm.limitTop" @input="limitTopInp"></el-input>
                            </span>
                        </el-row>
                    </el-form-item>
                    <el-form-item label="舒张压标准值设定" prop="">
                        <el-row>
                            <span :span="8">
                                <el-input style="width: 150px" v-model="searchForm.limitBplBottom" @input="limitBottomInp2"></el-input>
                            </span>
                            <span :span="8">≤标准值≤</span>
                            <span :span="8">
                                <el-input style="width: 150px" v-model="searchForm.limitBplTop" @input="limitTopInp2"></el-input>
                            </span>
                        </el-row>
                    </el-form-item>
                </template>
                <el-form-item label="年龄标准值设定" prop="">
                    <el-row>
                        <span :span="8">
                            <el-input style="width: 150px" v-model="searchForm.limitAgeBottom" type="number"></el-input>
                        </span>
                        <span :span="8">≤标准值≤</span>
                        <span :span="8">
                            <el-input style="width: 150px" v-model="searchForm.limitAgeTop" type="number"></el-input>
                        </span>
                    </el-row>
                </el-form-item>
                <el-form-item label="是否只展示最后一次结果">
                    <el-switch v-model="searchForm.是否只展示最后一次结果" :active-value="1" :inactive-value="0" />
                </el-form-item>
                <el-form-item>
                    <el-button size="small" :loading="loading" @click="onClickSearch" type="success">
                        <el-icon><Search /></el-icon>
                        查询</el-button
                    >
                    <slot name="right"></slot>
                </el-form-item>
                <el-form-item></el-form-item>
            </el-form>
        </el-col>
        <el-col :span="24" v-loading="loading">
            <el-row :gutter="20">
                <el-col :span="12">
                    <div class="container_l" :style="{ height: tableHeight + 'px', 'min-height': '520px' }">
                        <div v-loading="loading" ref="myEchartsRef" style="height: 500px; width: 100%; padding-top: 10px"></div>
                    </div>
                </el-col>
                <el-col :span="12">
                    <div class="container_r" :style="{ height: tableHeight + 'px', 'min-height': '520px' }">
                        <div class="untested_patients_box" v-if="untestedPatients.length > 0">
                            <div class="untested_patients_header">未检测人员</div>
                            <div class="untested_patients_conter">
                                {{ untestedPatients.join('、') }}
                            </div>
                        </div>
                        <div class="status_type_nav">
                            <span
                                v-for="(item, index) in statusTypeOptions"
                                :key="index"
                                :class="[statusType === item.value ? 'select_type' : '']"
                                @click="onClickByStatusChange(item)"
                            >
                                {{ item.label }}
                            </span>
                        </div>
                        <el-table
                            v-if="tableHeight > 0"
                            v-loading="loading"
                            id="exportTbale"
                            :row-class-name="rowClassName"
                            :data="patTableData"
                            :height="untestedPatients.length > 0 ? tableHeight - 210 : tableHeight"
                            border
                            style="width: 100%"
                        >
                            <el-table-column prop="sampleDate" label="检验日期">
                                <template #default="scope">
                                    {{ scope.row.sampleDate.substring(0, 11) }}
                                </template>
                            </el-table-column>
                            <el-table-column prop="patientName" label="患者姓名" />
                            <el-table-column prop="itemResult" :label="defaultNameAndUnit" />
                        </el-table>
                    </div>
                </el-col>
            </el-row>
        </el-col>
    </el-row>
</template>
<script lang="ts">
import { ElMessage } from 'element-plus';
import { defineComponent, reactive, toRefs, ref, onMounted, getCurrentInstance, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
import { formatDate } from '/@/utils/formatTime';
import { doStatByResult } from '/@/api/QC';
import * as echarts from 'echarts';
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
interface IDefDatas {
    title: string;
    itemName: string;
    defaultNameAndUnit: string;
    subTit: string;
    whereFrom?: Partial<{
        itemName: string;
        medMonth: number;
        isInState: number;
        statType: number;
        limitBottom: string | number;
        limitTop: string | number;
        filterStyle: number;
        dates: [Date, Date];
        attendingDoctor: '';
        是否只展示最后一次结果: 0 | 1;
    }>;
    isBloodPressure?: boolean;
}
export default defineComponent({
    name: 'ControlRate',
    setup() {
        const { proxy } = getCurrentInstance() as any;
        const myEchartsRef = ref();
        const state = reactive({
            loading: false,
            tableHeight: 0,
            title: '',
            itemName: '',
            defaultNameAndUnit: '',
            subTit: '',
            patList: [],
            untestedPatients: [],
            dabaio: true,
            budabaio: false,
            searchForm: {
                itemName: '',
                medMonth: 0,
                isInState: 1,
                statType: 0,
                limitBottom: '',
                limitTop: '',
                // filterStyle: 0,
                dates: [start, end],
                attendingDoctor: '', // 主治医师
                是否只展示最后一次结果: 0,
                limitBplBottom: null,
                limitBplTop: null,
                limitAgeBottom: null,
                limitAgeTop: null,
            },
            patTableData: [],
            statusType: 0,
            statusTypeOptions: [
                { label: '全部', value: 0 },
                { label: '达标', value: 1 },
                { label: '不达标', value: 2 },
            ],
            doctorOptions: [],
            isBloodPressure: false, // 是否是血压
        });
        // 监听 searchForm.limitBottom 的变化,确保 Vue 的双向绑定正常工作
        // watch(() => state.searchForm.limitBottom, (newValue) => {
        // if (newValue === '' || Number(newValue) < 0) {
        //     state.searchForm.limitBottom = '';
        // } else {
        //     // @ts-ignore
        //     state.searchForm.limitBottom = Number(newValue);
        // }
        // });
        const onClickByStatusChange = (item: { label: string; value: number }) => {
            state.statusType = item.value;
            if (item.value === 0) {
                state.patTableData = [...state.patList];
            } else if (item.value === 1) {
                state.patTableData = state.patList.filter((e) => e.是否达标);
            } else if (item.value === 2) {
                state.patTableData = state.patList.filter((e) => !e.是否达标);
            }
        };
        /** 查询 */
        const onClickSearch = async () => {
            if (isNaN(+state.searchForm.limitBottom) || isNaN(+state.searchForm.limitTop)) return ElMessage.warning('标准值仅可为大于等于0的数值');
            if (+state.searchForm.limitBottom < 0 || +state.searchForm.limitTop < 0) return ElMessage.warning('标准值不能小于0');
            state.loading = true;
            try {
                await getDatas();
            } finally {
                state.loading = false;
            }
        };
        // /** 导出 */
        // const onClickExportExcel = () => {
        //     exportTableToExcel('#exportTbale', state.title);
        // };
        const setTableHeight = () => {
            let height = document.documentElement.clientHeight;
            const navDom = document.querySelector('.layout-header');
            if (navDom) {
                height -= navDom.scrollHeight;
            }
            const demoFormDom = document.querySelector('.card_box_search');
            if (demoFormDom) {
                height -= demoFormDom.scrollHeight;
            }
            height = height - 40;
            state.tableHeight = height;
        };
        const initCompData = async (objData: IDefDatas) => {
            state.loading = true;
            try {
                const { title, itemName, defaultNameAndUnit, subTit, whereFrom, isBloodPressure } = objData;
                state.title = title;
                state.itemName = itemName;
                state.defaultNameAndUnit = defaultNameAndUnit;
                state.subTit = subTit;
                state.isBloodPressure = !!isBloodPressure;
                if (whereFrom) {
                    Object.keys(whereFrom).forEach((k) => {
                        state.searchForm[k] = whereFrom[k];
                    });
                }
                const primaseFuns = [getDatas()];
                await Promise.all(primaseFuns);
                await getDatas();
            } catch (error) {
                // ElMessage.error('系统异常,请联系管理员:' + error);
                console.error('xxxxxxxxxxx:', error);
            } finally {
                state.loading = false;
            }
        };
        const getDatas = async () => {
            const params = {
                clientCode: userInfos.value.clientCode,
                dateBegin: formatDate(state.searchForm.dates[0], 'YYYY-mm-dd') + ' 00:00:00',
                dateEnd: formatDate(state.searchForm.dates[1], 'YYYY-mm-dd') + ' 23:59:59',
                itemName: state.itemName,
                medMonth: state.searchForm.medMonth,
                isInState: state.searchForm.isInState,
                statType: state.searchForm.statType,
                limitBottom: state.searchForm.limitBottom,
                limitTop: state.searchForm.limitTop,
                // filterStyle: state.searchForm.filterStyle,
                attendingDoctor: state.searchForm.attendingDoctor,
                是否只展示最后一次结果: state.searchForm.是否只展示最后一次结果,
                limitBplBottom: state.searchForm.limitBplBottom,
                limitBplTop: state.searchForm.limitBplTop,
                limitAgeBottom: state.searchForm.limitAgeBottom,
                limitAgeTop: state.searchForm.limitAgeTop,
            };
            const { data } = await doStatByResult(params);
            state.defaultNameAndUnit = data.itemUnit ? `${state.subTit}(${data.itemUnit})` : state.defaultNameAndUnit;
            state.patList = data.statItemResults.slice().sort(compareDates);
            if (state.statusType === 0) {
                state.patTableData = [...state.patList];
            } else if (state.statusType === 1) {
                state.patTableData = state.patList.filter((e) => e.是否达标);
            } else if (state.statusType === 2) {
                state.patTableData = state.patList.filter((e) => !e.是否达标);
            }
            state.untestedPatients = data.未检测患者列表;
            initEcharts(
                data.statDetail.map((v) => {
                    v.tooltip = {
                        formatter: '{a}<br />{b}: ({c})({d}%)',
                    };
                    return v;
                })
            );
        };
        const initEcharts = (listdata: any) => {
            //先获取Dom上的实例
            if (echarts) {
                let myChart = echarts?.getInstanceByDom(proxy.$refs.myEchartsRef as HTMLDivElement);
                //然后判断实例是否存在,如果不存在,就创建新实例
                if (myChart == null) {
                    myChart = echarts.init(proxy.$refs.myEchartsRef as HTMLDivElement);
                }
                const option = {
                    title: {
                        text: state.title,
                        subtext: `${formatDate(state.searchForm.dates[0], 'YYYY-mm-dd')}-${formatDate(state.searchForm.dates[1], 'YYYY-mm-dd')}`,
                        left: 'center',
                    },
                    tooltip: {
                        trigger: 'item',
                    },
                    legend: {
                        orient: 'vertical',
                        left: 'top',
                    },
                    color: ['#5470c6', '#fc8251', '#91cd77', '#ef6567', '#f9c956', '#75bedc'],
                    series: [
                        {
                            name: state.subTit,
                            type: 'pie',
                            radius: '70%',
                            // avoidLabelOverlap: false,
                            label: {
                                show: true,
                                overflow: 'break',
                                position: 'outer',
                                alignTo: 'none',
                                edgeDistance: '25%',
                                bleedMargin: 10,
                                distanceToLabelLine: 5,
                                formatter(param) {
                                    return param.name + ' (' + param.value + ')' + ' (' + param.percent * 1 + '%)';
                                },
                            },
                            emphasis: {
                                itemStyle: {
                                    shadowBlur: 10,
                                    shadowOffsetX: 0,
                                    shadowColor: 'rgba(0, 0, 0, 0.5)',
                                },
                            },
                            labelLine: {
                                show: false,
                            },
                            data: listdata,
                        },
                    ],
                };
                myChart.setOption(option);
                myChart.on('legendselectchanged', function (event) {
                    // @ts-ignore
                    if (event.name === '不达标的患者人数') {
                        state.dabaio = !state.dabaio;
                        // @ts-ignore
                    } else if (event.name === '达标患者人数') {
                        state.budabaio = !state.budabaio;
                    }
                    // 在这里可以根据需要处理点击图例的逻辑
                });
            }
        };
        const compareDates = (a, b) => {
            const dateA = new Date(a.sampleDate);
            const dateB = new Date(b.sampleDate);
            // @ts-ignore
            return dateA - dateB; // 升序排序
        };
        const rowClassName = ({ row }) => {
            if (row.是否达标 === state.dabaio && row.是否达标 === state.budabaio) {
                return 'hidden-row';
            }
            return '';
        };
        const limitBottomInp = () => {
            let newValue = state.searchForm.limitBottom;
            // 过滤掉非法字符,允许数字和小数点
            newValue = newValue.replace(/[^0-9.]/g, '');
            // 确保第一个字符不是小数点
            if (newValue.startsWith('.')) {
                newValue = '0' + newValue;
            }
            // 确保只有一个小数点
            newValue = newValue.replace(/(\..*)\./g, '$1');
            // 如果值为空或小于等于0,清空输入框
            if (newValue !== '' && parseFloat(newValue) < 0) {
                newValue = '';
            }
            state.searchForm.limitBottom = newValue;
        };
        const limitTopInp = () => {
            let newValue = state.searchForm.limitTop;
            // 过滤掉非法字符,允许数字和小数点
            newValue = newValue.replace(/[^0-9.]/g, '');
            // 确保第一个字符不是小数点
            if (newValue.startsWith('.')) {
                newValue = '0' + newValue;
            }
            // 确保只有一个小数点
            newValue = newValue.replace(/(\..*)\./g, '$1');
            // 如果值为空或小于等于0,清空输入框
            if (newValue !== '' && parseFloat(newValue) < 0) {
                newValue = '';
            }
            state.searchForm.limitTop = newValue;
        };
        const limitBottomInp2 = () => {
            let newValue = state.searchForm.limitBplBottom;
            // 过滤掉非法字符,允许数字和小数点
            newValue = newValue.replace(/[^0-9.]/g, '');
            // 确保第一个字符不是小数点
            if (newValue.startsWith('.')) {
                newValue = '0' + newValue;
            }
            // 确保只有一个小数点
            newValue = newValue.replace(/(\..*)\./g, '$1');
            // 如果值为空或小于等于0,清空输入框
            if (newValue !== '' && parseFloat(newValue) < 0) {
                newValue = '';
            }
            state.searchForm.limitBplBottom = newValue;
        };
        const limitTopInp2 = () => {
            let newValue = state.searchForm.limitBplTop;
            // 过滤掉非法字符,允许数字和小数点
            newValue = newValue.replace(/[^0-9.]/g, '');
            // 确保第一个字符不是小数点
            if (newValue.startsWith('.')) {
                newValue = '0' + newValue;
            }
            // 确保只有一个小数点
            newValue = newValue.replace(/(\..*)\./g, '$1');
            // 如果值为空或小于等于0,清空输入框
            if (newValue !== '' && parseFloat(newValue) < 0) {
                newValue = '';
            }
            state.searchForm.limitBplTop = newValue;
        };
        onMounted(() => {
            setTableHeight();
        });
        return {
            ...toRefs(state),
            myEchartsRef,
            rowClassName,
            onClickSearch,
            initCompData,
            onClickByStatusChange,
            limitBottomInp,
            limitTopInp,
            limitBottomInp2,
            limitTopInp2,
        };
    },
});
</script>
<style lang="scss" scoped>
.control_rate_container {
    .card_box {
        padding: 15px;
        background: #fff;
        padding-bottom: 0;
        &.card_box_search {
            padding-bottom: 0;
            margin-bottom: 10px;
        }
    }
    .sum_count {
        padding-right: 20px;
        line-height: 40px;
        font-size: 14px;
        font-weight: bold;
        text-align: right;
        color: #67c23a;
    }
    .container_l,
    .container_r {
        background: #fff;
        overflow-y: auto;
        .untested_patients_box {
            background-color: #fff;
            padding: 10px;
            .untested_patients_header {
                text-align: center;
                font-weight: bold;
                background: #409eff;
                color: #fff;
                line-height: 40px;
            }
            .untested_patients_conter {
                padding: 20px;
                max-height: 200px;
                overflow: hidden;
                overflow-y: auto;
            }
        }
    }
    .status_type_nav {
        display: flex;
        align-items: center;
        padding-top: 20px;
        span {
            background: #fff;
            color: #333;
            padding: 8px 14px;
            font-size: 14px;
            border-radius: 5px 5px 0 0;
            box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.12);
            transition: 0.3s;
            &:hover {
                cursor: pointer;
                background: #92c3f5;
                color: #fff;
            }
            &.select_type {
                background-color: #409eff;
                color: #fff;
            }
        }
    }
}
.xuedanbai {
    .el-table .hidden-row {
        display: none;
    }
    .chaxun {
        padding-left: 10px;
        padding-top: 10px;
        padding-bottom: -10px;
        background: #ffffff;
        box-shadow: -1px 1px 6px 1px rgba(207, 212, 218, 0.5);
        border-radius: 0px 4px 4px 4px;
    }
    .bodyclass {
        background: #ffffff;
        box-shadow: -1px 1px 6px 1px rgba(207, 212, 218, 0.5);
        border-radius: 0px 4px 4px 4px;
    }
    /*在谷歌下移除input[number]的上下箭头*/
    .inputNumber input[type='number']::-webkit-outer-spin-button,
    .inputNumber input[type='number']::-webkit-inner-spin-button {
        -webkit-appearance: none !important;
        margin: 0;
    }
    /*在firefox下移除input[number]的上下箭头*/
    .inputNumber input[type='number'] {
        -moz-appearance: textfield;
    }
}
</style>
src/views/zhikong/xueqingdanbai.vue
New file
@@ -0,0 +1,36 @@
<template>
    <ControlRate ref="controlRateRef" />
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import ControlRate from './components/components.vue';
const controlRateRef = ref();
onMounted(() => {
    const end = new Date();
    const start = new Date();
    start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
    controlRateRef.value &&
        controlRateRef.value.initCompData({
            title: '血清白蛋白控制率',
            itemName: '白蛋白',
            defaultNameAndUnit: '血清白蛋白(g/L)',
            subTit: '血清白蛋白',
            whereFrom: {
                itemName: '',
                medMonth: 0,
                isInState: 1,
                statType: 0,
                limitBottom: 35,
                // filterStyle: 0,
                limitTop: '',
                dates: [start, end],
            },
        });
});
</script>
<style>
</style>