| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- <template>
- <div>
- <div v-if="show" class="reagentChange">
- <el-row type="flex">
- <el-col class="button">
- <div class="title">仪器设备维修后验证记录(定量)</div>
- <div v-if="nodeId === 'Activity_0b188bo' || readonly" />
- <div v-else>
- <el-button type="primary" size="mini" icon="ibps-icon-add" @click="handleAdd"> 添加</el-button>
- <el-button type="danger" size="mini" icon="ibps-icon-remove" @click="handleDelete"> 删除</el-button>
- <el-button type="warning" size="mini" icon="ibps-icon-calculator" @click="computedResult">计算</el-button>
- </div>
- </el-col>
- </el-row>
- <el-row type="flex">
- <el-col>
- <el-table ref="reagent" :data="reagentDataFilter" :span-method="spanMethod" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" />
- <el-table-column
- label="检验项目"
- prop="jianYanXiangMu"
- width="150"
- >
- <template slot-scope="{row}">
- <el-input v-if="!disabled" v-model="row.jianYanXiangMu" type="textarea" size="mini" placeholder="请输入" />
- <span v-else>{{ row.jianYanXiangMu|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="浓度" prop="nongDu" width="100">
- <template slot-scope="{row}">
- <el-input v-if="!disabled" v-model="row.nongDu" size="mini" placeholder="请输入" />
- <span v-else>{{ row.nongDu|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="条码号或标本号" prop="tiaoBiaoHao" width="150">
- <template slot-scope="{row}">
- <el-input v-if="!disabled" v-model="row.tiaoBiaoHao" size="mini" placeholder="请输入" />
- <span v-else>{{ row.tiaoBiaoHao|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="故障前结果(X)" prop="qianJieGuo" width="130">
- <template slot-scope="{row}">
- <el-input v-if="!disabled" v-model="row.qianJieGuo" :min="0" size="mini" placeholder="请输入" />
- <span v-else>{{ row.qianJieGuo|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="故障后结果(Y)" prop="houJieGuo" width="130">
- <template slot-scope="{row}">
- <el-input v-if="!disabled" v-model="row.houJieGuo" :min="0" size="mini" placeholder="请输入" />
- <span v-else>{{ row.houJieGuo|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="计算方式" prop="jiSuanGongShi" width="140">
- <template slot-scope="{row}">
- <el-select v-if="!disabled" v-model="row.jiSuanGongShi" size="mini" placeholder="请选择">
- <el-option
- label="|Y-X|"
- value="|Y-X|"
- />
- <el-option
- label="|Y-X|/X(%)"
- value="|Y-X|/X(%)"
- />
- </el-select>
- <span v-else>{{ row.jiSuanGongShi|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="实际差值" prop="shiJiChaZhi" />
- <el-table-column label="实际偏倚" prop="shiJiPianYi" />
- <el-table-column label="限定范围" prop="xianDingFanWei" width="110">
- <template slot-scope="{row}">
- <el-input v-if="!disabled" v-model="row.xianDingFanWei" size="mini" placeholder="请输入" type="number" />
- <span v-else>{{ row.xianDingFanWei|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="允许偏倚" prop="yunXuPianYi" width="100">
- <template slot-scope="{row}">
- <el-input v-if="!disabled" v-model="row.yunXuPianYi" size="mini" placeholder="请输入" />
- <span v-else>{{ row.yunXuPianYi|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="是否相符" prop="shiFouXiangFu" width="80" />
- <el-table-column label="符合率" prop="fuHeLv" />
- <el-table-column label="符合率可接受标准" prop="fuHeBiaoZhun" width="140">
- <template slot-scope="{row}">
- <el-select v-if="!disabled" v-model="row.fuHeBiaoZhun" size="mini" placeholder="请选择" @change="handelChange($event,row.jianYanXiangMu)">
- <el-option
- label="≥80%"
- value="≥80%"
- />
- <el-option
- label="=100%"
- value="=100%"
- />
- </el-select>
- <span v-else>{{ row.fuHeBiaoZhun|| '/' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="结论" prop="jieLun" />
- </el-table>
- <el-pagination
- layout="total,sizes,prev, pager, next,jumper"
- :current-page="requestPage.pageNo"
- :page-size="requestPage.limit"
- :page-sizes="[10,15,20,30,50,100]"
- :total="reagentData.length"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- />
- </el-col>
- </el-row>
- </div>
- </div>
- </template>
- <script>
- export default {
- props: {
- formData: {
- type: Object,
- default: () => {}
- },
- readonly: {
- type: Boolean,
- default: false
- },
- params: {
- type: Object,
- default: () => {}
- }
- },
- data () {
- return {
- reagentData: [],
- copyDialogData: [],
- disabled: false,
- ypData: [],
- nodeId: '',
- show: false,
- requestPage: {
- limit: 20,
- pageNo: 1
- },
- importTableDialogVisible: false,
- multipleSelection: []
- }
- },
- computed: {
- reagentDataFilter () {
- return this.reagentData.slice((this.requestPage.pageNo - 1) * (this.requestPage.limit), (this.requestPage.pageNo - 1) * (this.requestPage.limit) + this.requestPage.limit)
- }
- },
- watch: {
- 'formData.yqsbwxhlybdjlbzbdl': {
- handler (value, old) {
- if (value && value.length) {
- this.reagentData = value
- }
- },
- immediate: true
- },
- reagentData: {
- handler (value, old) {
- this.$emit('change-data', 'yqsbwxhlybdjlbzbdl', value)
- },
- deep: true
- },
- 'formData.xiangMuLeiXing': {
- handler (val) {
- if (val === '定量') { this.show = true } else { this.show = false; this.reagentData = [] }
- },
- immediate: true
- },
- 'formData.piLiangYunXu': {
- handler (val) {
- this.reagentData.forEach(item => {
- const { jianYanXiangMu } = this.formData
- if (item.jianYanXiangMu === jianYanXiangMu) {
- item.yunXuPianYi = val
- }
- })
- },
- immediate: true
- },
- 'formData.piLiangXianDing': {
- handler (val) {
- this.reagentData.forEach(item => {
- const { jianYanXiangMu } = this.formData
- if (item.jianYanXiangMu === jianYanXiangMu) {
- item.xianDingFanWei = val
- }
- })
- }
- }
- },
- mounted () {
- const { first = '' } = this.$store.getters.level
- const { deptList = [] } = this.$store.getters || {}
- const t1 = deptList.find(i => i.positionId === first) || {}
- console.log(t1.positionName)
- this.nodeId = this.params ? this.params.nodeId : ''
- this.disabled = this.readonly || this.nodeId === 'Activity_0b188bo'
- },
- methods: {
- handelChange (event, jianYanXiangMu) {
- this.reagentData.forEach(item => {
- if (item.jianYanXiangMu === jianYanXiangMu) {
- item.fuHeBiaoZhun = event
- }
- })
- },
- // 新增
- handleAdd () {
- const { xMMingCheng, piLiangYunXu, piLiangXianDing, piLiangNongDu } = this.formData
- if (this.disabled && this.reagentData?.length > 0) {
- return this.$message.warning('导入与手动添加功能不可混用!')
- }
- if (!this.formData.xMMingCheng) {
- return this.$message.warning('请选择或输入检验项目')
- }
- this.reagentData.push({ jianYanXiangMu: xMMingCheng, nongDu: piLiangNongDu, tiaoBiaoHao: '', qianJieGuo: '', houJieGuo: '', jiSuanGongShi: '|Y-X|/X(%)', shiJiChaZhi: '', shiJiPianYi: '', xianDingFanWei: piLiangXianDing, yunXuPianYi: piLiangYunXu, shiFouXiangFu: '', fuHeLv: '', fuHeBiaoZhun: '≥80%', jieLun: '' })
- const grouped = this.reagentData.reduce((acc, item) => {
- const key = item.jianYanXiangMu
- if (!acc[key]) acc[key] = []
- acc[key].push(item)
- return acc
- }, {})
- // 先清空数组,再填充新数据(确保 Vue 检测到变化)
- this.reagentData.splice(0, this.reagentData.length, ...Object.values(grouped).flat())
- // console.log(this.reagentData)
- },
- // 删除
- handleDelete () {
- this.$confirm('确定删除当前选中数据?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- if (this.multipleSelection.length > 0) {
- this.reagentData = this.reagentData.filter(row => !this.multipleSelection.includes(row))
- } else {
- this.$message.warning('请选择数据')
- }
- })
- },
- handleSelectionChange (val) {
- this.multipleSelection = val
- },
- getColumns () {
- return [{
- field_name: 'shiFouXiangFu',
- label: '是否相符',
- name: 'shiFouXiangFu'
- },
- {
- field_name: 'jianYanXiangMu',
- label: '检验项目',
- name: 'jianYanXiangMu'
- },
- {
- field_name: 'nongDu',
- label: '浓度',
- name: 'nongDu'
- },
- {
- field_name: 'tiaoBiaoHao',
- label: '条码号或标本号',
- name: 'tiaoBiaoHao'
- },
- {
- field_name: 'qianJieGuo',
- label: '故障前结果(X)',
- name: 'qianJieGuo'
- },
- {
- field_name: 'houJieGuo',
- label: '故障后结果(Y)',
- name: 'houJieGuo'
- },
- {
- field_name: 'shiJiChaZhi',
- label: '实际差值',
- name: 'shiJiChaZhi'
- },
- {
- field_name: 'shiJiPianYi',
- label: '实际偏倚',
- name: 'shiJiPianYi'
- },
- {
- field_name: 'xianDingFanWei',
- label: '限定范围',
- name: 'xianDingFanWei'
- },
- {
- field_name: 'yunXuPianYi',
- label: '允许偏倚',
- name: 'yunXuPianYi'
- },
- {
- field_name: 'fuHeLv',
- label: '符合率',
- name: 'fuHeLv'
- }, {
- field_name: 'jieLun',
- label: '结论',
- name: 'jieLun'
- },
- {
- field_name: 'fuHeBiaoZhun',
- label: '符合率可接受标准',
- name: 'fuHeBiaoZhun'
- }]
- },
- // 当前页码改变
- handleCurrentChange (val) {
- this.requestPage.pageNo = val
- },
- // 页码选择器改变
- handleSizeChange (val) {
- this.requestPage.limit = val
- this.requestPage.pageNo = 1
- },
- // 计算结果
- computedResult () {
- if (this.disabled) {
- this.$message.warning('导入数据请勿使用计算功能!')
- return
- }
- const hasInvalidData = this.reagentData.some(item =>
- !item.qianJieGuo || item.qianJieGuo <= 0 || !item.houJieGuo || item.houJieGuo <= 0
- )
- if (hasInvalidData || this.reagentData.length === 0) {
- this.$message.warning('故障前结果(X)必须大于0且不能为空!')
- return
- }
- const hasPyOrCz = this.reagentData.some(item =>
- (item.jiSuanGongShi === '|Y-X|/X(%)' && !item.yunXuPianYi) || (item.jiSuanGongShi === '|Y-X|' && !item.xianDingFanWei)
- )
- if (hasPyOrCz) {
- this.$message.warning(`计算方式为|Y-X|/X(%)请填写允许偏倚,计算方式为|Y-X|请填写限定范围`)
- return
- }
- // 预处理函数:统一处理百分比数值
- const normalizePercent = val => Number(String(val).replace('%', '')) || 0
- // 使用 Map 存储统计信息
- const projectStats = new Map()
- this.reagentData.forEach(item => {
- const { jiSuanGongShi, houJieGuo, qianJieGuo, xianDingFanWei, jianYanXiangMu } = item
- // 计算差值/偏倚
- if (!isNaN(houJieGuo) && !isNaN(qianJieGuo)) {
- if (jiSuanGongShi === '|Y-X|') {
- item.shiJiChaZhi = Math.abs((houJieGuo * 100000 - qianJieGuo * 100000) / 100000).toFixed(2)
- item.shiFouXiangFu = normalizePercent(item.shiJiChaZhi) <= normalizePercent(xianDingFanWei) ? '相符' : '不相符'
- item.shiJiPianYi = ''
- } else {
- item.shiJiPianYi = this.deleteAccuracy(Math.abs(houJieGuo - qianJieGuo) / qianJieGuo)
- item.shiFouXiangFu = normalizePercent(item.shiJiPianYi) <= normalizePercent(item.yunXuPianYi) ? '相符' : '不相符'
- item.shiJiChaZhi = ''
- }
- }
- // 统计符合率
- const stats = projectStats.get(jianYanXiangMu) || { total: 0, yes: 0 }
- stats.total++
- if (item.shiFouXiangFu === '相符') stats.yes++
- projectStats.set(jianYanXiangMu, stats)
- })
- // 填充符合率标准,保留小数点后两位
- this.reagentData.forEach(item => {
- const stats = projectStats.get(item.jianYanXiangMu)
- item.fuHeLv = this.deleteAccuracy(stats.yes / stats.total)
- console.log(parseFloat(item.fuHeLv), item.fuHeBiaoZhun)
- item.jieLun = parseFloat(item.fuHeLv) >= parseFloat(item.fuHeBiaoZhun.replace(/[≥=%]/g, '')) ? '可接受' : '不可接受'
- })
- },
- spanMethod ({ row, column, rowIndex, columnIndex }) {
- if (columnIndex === 1 || columnIndex === 12 || columnIndex === 13 || columnIndex === 14) {
- const currentValue = row[column.property]
- const preRow = this.reagentData[rowIndex - 1]
- // 上一行这一列的数据
- const preValue = preRow ? preRow[column.property] : null
- // 如果当前值和上一行的值相同,则将当前单元格隐藏
- // 给第0,10,11,12列对数值相同且是同一个'jianYanXiangMu'进行表格合并
- if (currentValue === preValue && row['jianYanXiangMu'] === preRow['jianYanXiangMu']) {
- return { rowspan: 0, colspan: 0 }
- } else {
- let rowspan = 1
- // 计算应该合并的行数
- for (let i = rowIndex + 1; i < this.reagentData.length; i++) {
- const nextRow = this.reagentData[i]
- const nextValue = nextRow[column.property]
- if (nextValue === currentValue && nextRow['jianYanXiangMu'] === row['jianYanXiangMu']) {
- rowspan++
- } else {
- break
- }
- }
- return { rowspan, colspan: 1 }
- }
- // if (rowIndex % rowspan === 0) {
- // return {
- // rowspan,
- // colspan: 1
- // }
- // } else {
- // return {
- // rowspan: 0,
- // colspan: 0
- // }
- // }
- }
- },
- // 去除小数*100精度方法
- deleteAccuracy (num) {
- // 是否带小数点
- if ((num.toString()).includes('.')) {
- // 保留小数点后面3位
- const numArry = num.toFixed(3).toString().split('.')
- // 整数位是否大于0
- if (numArry[0] > 0) {
- return Number(numArry[0] + numArry[1].substring(0, 2) + '.' + numArry[1].substring(2, 3)) + '%'
- } else {
- // 小数位第一位是否大于0
- if (numArry[1][0] > 0) {
- return Number(numArry[1].substring(0, 2) + '.' + numArry[1].substring(2, 3)) + '%'
- } else {
- // 小数位第二位是否大于0
- if (numArry[1][1] > 0) {
- return Number(numArry[1].substring(1, 2) + '.' + numArry[1].substring(2, 3)) + '%'
- } else {
- return Number(0 + '.' + numArry[1].substring(2, 3)) + '%'
- }
- }
- }
- } else {
- return num * 100 + '%'
- }
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .reagentChange{
- margin-bottom: 20px;
- .button{
- display: flex;
- justify-content: space-between;
- padding: 0px 0px 0px 15px;
- background: #f0ffff;
- .title {
- color: #999;
- font-size: 12px;
- font-weight: bold;
- margin-bottom: 0;
- }
- .el-button {
- margin: 0;
- }
- }
- }
- </style>
|