Browse Source

feat:[模板管理][update]

lkf
luojie 2 months ago
parent
commit
420955d14b
5 changed files with 466 additions and 7 deletions
  1. +18
    -3
      src/components/Template/HandleFormItem.vue
  2. +15
    -2
      src/components/Template/operation/TableOpertaion.vue
  3. +110
    -0
      src/utils/volumeTools.js
  4. +9
    -2
      src/views/business/comps/template/TemplateTable.vue
  5. +314
    -0
      src/views/business/comps/template/dialog/SubPackageDialog.vue

+ 18
- 3
src/components/Template/HandleFormItem.vue View File

@ -147,6 +147,11 @@ export default {
fieldItemLabel: { fieldItemLabel: {
type: String, type: String,
default: "", default: "",
},
//
isFieldsRecord: {
type: Boolean,
default: true,
} }
}, },
data() { data() {
@ -373,6 +378,12 @@ export default {
return; return;
} }
if (this.oldValue && !isSame && this.templateFillType === "actFill") { if (this.oldValue && !isSame && this.templateFillType === "actFill") {
if(!this.isFieldsRecord){//
this.$emit("blur", this.inputValue);
this.$emit('input', this.inputValue);
this.$emit("change", this.inputValue);
return;
}
this.$refs.editSignRef.show() this.$refs.editSignRef.show()
// this.handleUpdateRecord(); // this.handleUpdateRecord();
}else{// }else{//
@ -406,9 +417,7 @@ export default {
if (data) { if (data) {
record.reason = data.remark record.reason = data.remark
} }
if(this.templateFillType === "actFill"){//
this.updateZdxgjl(record);
}
const params = { const params = {
type: "fieldChanged", type: "fieldChanged",
newRecord: record, newRecord: record,
@ -419,6 +428,12 @@ export default {
this.$emit("blur", this.inputValue); this.$emit("blur", this.inputValue);
this.$emit('input', this.inputValue); this.$emit('input', this.inputValue);
this.$emit("change", this.inputValue); this.$emit("change", this.inputValue);
if(!this.isFieldsRecord){//
return;
}
if(this.templateFillType === "actFill"){//
this.updateZdxgjl(record);
}
setTimeout(() => { setTimeout(() => {
EventBus.$emit('onModifyRecord', params,) EventBus.$emit('onModifyRecord', params,)
}, 10); }, 10);

+ 15
- 2
src/components/Template/operation/TableOpertaion.vue View File

@ -17,6 +17,8 @@
</template> </template>
<script> <script>
import { EventBus } from "@/utils/eventBus";
export default { export default {
name: "TableOpertaion", name: "TableOpertaion",
props: { props: {
@ -37,6 +39,12 @@ export default {
default: "preFill", default: "preFill",
}, },
}, },
mounted() {
EventBus.$on("subPackageSubmit", (data) => {
this.onSubPackageSubmit(data)
})
},
methods: { methods: {
// //
onStartConfig() { onStartConfig() {
@ -60,8 +68,13 @@ export default {
myCodeFields.forEach((key)=>{ myCodeFields.forEach((key)=>{
fields.push(row[key]) fields.push(row[key])
}) })
console.log(fields,"fields")
this.$emit("subPackage", this.row)
EventBus.$emit("showSubPackageDialog",{mybh:fields.join(""),maxVolume:10,volumeUnit:"ml",rowIndex:this.rowIndex})
},
onSubPackageSubmit(data){
if(data.rowIndex === this.rowIndex){
console.log(data,"onSubPackageSubmit")
this.$emit("subPackageSubmit", data)
}
}, },
// //
deleteRow(index) { deleteRow(index) {

+ 110
- 0
src/utils/volumeTools.js View File

@ -0,0 +1,110 @@
/**
* 体积单位换算工具
* 单位关系基于SI单位制
* 1 L = 1000 mL
* 1 mL = 1000 μL (ul)
* 1 μL = 1000 nL
* 1 nL = 1000 pL
*/
const VolumeUnit = {
// 完整单位名称和缩写
LITER: { name: 'liter', symbol: 'l', factor: 1e0 }, // 基础单位:升
MILLILITER: { name: 'milliliter', symbol: 'ml', factor: 1e-3 }, // 10^-3 升
MICROLITER: { name: 'microliter', symbol: 'μl', factor: 1e-6 }, // 10^-6 升 (也可用ul)
NANOLITER: { name: 'nanoliter', symbol: 'nl', factor: 1e-9 }, // 10^-9 升
PICOLITER: { name: 'picoliter', symbol: 'pl', factor: 1e-12 } // 10^-12 升
}
// 单位符号到标准单位的映射
const UNIT_MAP = {
// 标准符号
'l': VolumeUnit.LITER,
'ml': VolumeUnit.MILLILITER,
'μl': VolumeUnit.MICROLITER,
'ul': VolumeUnit.MICROLITER, // ul 是 μl 的替代写法
'nl': VolumeUnit.NANOLITER,
'pl': VolumeUnit.PICOLITER,
// 大写形式
'L': VolumeUnit.LITER,
'ML': VolumeUnit.MILLILITER,
'ML': VolumeUnit.MILLILITER,
'UL': VolumeUnit.MICROLITER,
'NL': VolumeUnit.NANOLITER,
'PL': VolumeUnit.PICOLITER
}
/**
* 将任意单位的值转换为升基础单位
* @param {number} value - 数值
* @param {string} unit - 单位符号 (l/ml/μl/ul/nl/pl)
* @returns {number} 换算为升的值
*/
export function convertToLiter(value, unit) {
const normalizedUnit = unit.toLowerCase()
const unitConfig = UNIT_MAP[normalizedUnit]
if (!unitConfig) {
console.warn(`不支持的体积单位: ${unit}. 支持的单位: ${Object.keys(UNIT_MAP).join(', ')}`)
}
return value * unitConfig.factor
}
/**
* 将值从一种单位转换为另一种单位
* @param {number} value - 原始值
* @param {string} fromUnit - 原始单位
* @param {string} toUnit - 目标单位
* @returns {number} 转换后的值
*/
export function convertVolume(value, fromUnit, toUnit) {
// 先转换为升,再转换为目标单位
const valueInLiters = convertToLiter(value, fromUnit)
const toUnitConfig = UNIT_MAP[toUnit.toLowerCase()]
if (!toUnitConfig) {
console.warn(`不支持的体积单位: ${toUnit}`)
}
// 从升转换为目标单位
return valueInLiters / toUnitConfig.factor
}
/**
* 比较两个不同单位的体积值
* @param {number} value1 - 第一个值
* @param {string} unit1 - 第一个值的单位
* @param {number} value2 - 第二个值
* @param {string} unit2 - 第二个值的单位
* @returns {number}
* -1: value1 < value2
* 0: value1 = value2
* 1: value1 > value2
*/
export function compareVolume(value1, unit1, value2, unit2) {
const v1InLiters = convertToLiter(value1, unit1)
const v2InLiters = convertToLiter(value2, unit2)
if (Math.abs(v1InLiters - v2InLiters) < 1e-15) { // 处理浮点数精度
return 0
}
return v1InLiters < v2InLiters ? -1 : 1
}
/**
* 获取单位换算比例
* @param {string} fromUnit - 原始单位
* @param {string} toUnit - 目标单位
* @returns {number} 换算比例fromUnit * ratio = toUnit
*/
export function getConversionRatio(fromUnit, toUnit) {
const fromConfig = UNIT_MAP[fromUnit.toLowerCase()]
const toConfig = UNIT_MAP[toUnit.toLowerCase()]
if (!fromConfig || !toConfig) {
console.warn('不支持的体积单位')
}
return fromConfig.factor / toConfig.factor
}

+ 9
- 2
src/views/business/comps/template/TemplateTable.vue View File

@ -2,11 +2,12 @@
<div class="template-table"> <div class="template-table">
<component ref="templateComponent" :is="getTemplateComponent()" :templateData="templateData" :fillType="fillType"> <component ref="templateComponent" :is="getTemplateComponent()" :templateData="templateData" :fillType="fillType">
</component> </component>
<SubPackageDialog ref = "subPackageDialogRef"></SubPackageDialog>
</div> </div>
</template> </template>
<script> <script>
import { EventBus } from "@/utils/eventBus"
import { EventBus } from "@/utils/eventBus";
// //
import SWYPFXRYPZB from "./comps/sp/SWYPFXRYPZB.vue"; import SWYPFXRYPZB from "./comps/sp/SWYPFXRYPZB.vue";
import SWYPFXCBYPZB from "./comps/sp/SWYPFXCBYPZB.vue"; import SWYPFXCBYPZB from "./comps/sp/SWYPFXCBYPZB.vue";
@ -28,10 +29,12 @@ import Demo from "./comps/sp/Demo.vue";
// //
import SYWZPZJHB from "./comps/gsp/SYWZPZJHB.vue"; import SYWZPZJHB from "./comps/gsp/SYWZPZJHB.vue";
import MJYLQSQD from "./comps/gsp/MJYLQSQD.vue"; import MJYLQSQD from "./comps/gsp/MJYLQSQD.vue";
import SubPackageDialog from "./dialog/SubPackageDialog.vue"
export default { export default {
name: "TemplateTable", name: "TemplateTable",
components: { components: {
SubPackageDialog,
// //
MJYLQSQD, SYWZPZJHB, MJYLQSQD, SYWZPZJHB,
// //
@ -147,11 +150,15 @@ export default {
mounted() { mounted() {
EventBus.$on('onModifyRecord', (data) => { EventBus.$on('onModifyRecord', (data) => {
this.$emit(this.emitName, data) this.$emit(this.emitName, data)
});
EventBus.$on("showSubPackageDialog",(data)=>{
this.$refs.subPackageDialogRef.show(data)
}) })
}, },
beforeDestroy() { beforeDestroy() {
// //
EventBus.$off('onModifyRecord')
EventBus.$off('onModifyRecord');
EventBus.$off("showSubPackageDialog");
}, },
methods: { methods: {
async getFormData() { async getFormData() {

+ 314
- 0
src/views/business/comps/template/dialog/SubPackageDialog.vue View File

@ -0,0 +1,314 @@
<template>
<el-dialog title="分装(分装后的编号可用于下一步关联选择)" append-to-body :visible.sync="visible" @close="close" width="1100px">
<div class="dialog-content">
<div class="header-container">
<div class="header-item">
<div class="header-title">母液编号</div>
<HandleFormItem :isFieldsRecord="false" :item="inputItem" :error="formErrors.mybh"
v-model="formData.mybh" />
</div>
<div class="header-item">
<div class="header-title">分装数量</div>
<HandleFormItem :isFieldsRecord="false" @blur="onBlurFzsl" :item="integerInputNumberItem"
:error="formErrors.fzsl" v-model="formData.fzsl" />
</div>
</div>
<div class="content-container">
<div class="content-item">
<span>分装编号</span>
<span class="ml-20">单位</span>
<div class="unit-select">
<HandleFormItem :isFieldsRecord="false" :item="unitItem" type="select" :error="formErrors.dw"
@blur="(e) => onCommonBlur(e, 'dw')" v-model="formData.dw" />
</div>
<span class="ml-20">每份包装量</span>
<div class="unit-select">
<HandleFormItem :isFieldsRecord="false" :item="inputNumberItem" v-model="formData.mfbzl" />
</div>
<el-button type="primary" plain @click="onAverage">平均分配</el-button>
<el-button type="primary" plain @click="onReset">重置</el-button>
</div>
<div class="header-container">
<div v-for="(item, index) in fzList" class="list-item" :key="index">
<div class="list-label">{{ formData.mybh }}-set01</div>
<HandleFormItem :isFieldsRecord="false" :item="inputNumberItem" :error="fzListErrors[index]"
@blur="onBlurFzNum(index)" v-model="item.num" />
<el-button type="primary" plain @click="onPrint">打印</el-button>
</div>
</div>
</div>
</div>
<template slot="footer" class="dialog-footer">
<el-button @click="close">{{ $t('form.cancel') }}</el-button>
<el-button type="primary" @click="onSubmit">{{ $t('form.saveConfirm') }}</el-button>
</template>
</el-dialog>
</template>
<script>
import HandleFormItem from '@/components/Template/HandleFormItem.vue';
import { compareVolume } from '@/utils/volumeTools.js';
import { EventBus } from '@/utils/eventBus'
export default {
dicts: [
'business_tjdw',
],
components: {
HandleFormItem,
},
data() {
return {
visible: false,
inputItem: {
type: "input",
fillType: "actFill",
disabled: true,
},
integerInputNumberItem: {
type: "inputNumber",
fillType: "actFill",
precision: 0,
maxlength: 3
},
inputNumberItem: {
type: "inputNumber",
fillType: "actFill",
},
formData: {
mybh: "",//
fzsl: "",//
dw: "",//
mfbzl: "",//
},
fzList: [],//
//
formErrors: {
mybh: false,
fzsl: false,
dw: false,
},
fzListErrors: [] //
}
},
computed: {
unitItem() {
return {
type: "select",
fillType: "actFill",
options: this.dict.type.business_tjdw
}
}
},
methods: {
close() {
this.visible = false;
this.resetErrors();
},
show(data) {
if (data.fzList) {
this.fzList = data.fzList;
//
this.fzListErrors = new Array(this.fzList.length).fill(false);
}
this.formData = data;
//
this.resetErrors();
this.visible = true;
},
onSubmit() {
//
if (!this.validateFormData()) {
this.$message.error('表单内容未填完,请填写后再提交')
return;
} else {
const errMsg = "分装后小份容量之和大于母液容量,是否确认分装?"
const {maxVolume,volumeUnit,dw} = this.formData;
const totalVolume = this.fzList.reduce((acc, cur) => acc + Number(cur.num), 0);
const compareResult = compareVolume(totalVolume,dw,maxVolume, volumeUnit);
if(compareResult > 0){
this.$modal.confirm(errMsg, '提示', {
confirmButtonText: this.$t('form.saveConfirm'),
cancelButtonText: this.$t('form.cancel'),
type: 'warning'
}).then(() => {
this.submitEmit();
}).catch(() => {
//
});
return;
}
this.submitEmit();
}
},
submitEmit(){
EventBus.$emit('subPackageSubmit', {...this.formData, fzList: this.fzList});
this.fzList = [];
this.formData = {};
this.close();
},
validateFormData() {
let isValid = true;
//
if (!this.formData.mybh) {
this.formErrors.mybh = true;
isValid = false;
}
//
if (!this.formData.fzsl) {
this.formErrors.fzsl = true;
isValid = false;
}
//
if (!this.formData.dw) {
this.formErrors.dw = true;
isValid = false;
}
//
if (this.fzList && this.fzList.length > 0) {
for (let i = 0; i < this.fzList.length; i++) {
if (!this.fzList[i].num) {
// fzListErrors
if (this.fzListErrors.length <= i) {
this.$set(this.fzListErrors, i, true);
} else {
this.fzListErrors[i] = true;
}
isValid = false;
}
}
}
return isValid;
},
resetErrors() {
//
Object.keys(this.formErrors).forEach(key => {
this.formErrors[key] = false;
});
//
this.fzListErrors.forEach((_, index) => {
this.$set(this.fzListErrors, index, false);
});
},
//
onBlurFzsl(e) {
//
if (e) {
this.formErrors.fzsl = false;
}
//
this.fzList = [];
this.fzListErrors = [];
//
for (let i = 0; i < e; i++) {
this.fzList.push({
num: "",
});
//
this.fzListErrors.push(false);
}
},
onAverage() {
const { mfbzl } = this.formData;
this.fzList.forEach((item, index) => {
item.num = mfbzl;
//
if (this.fzListErrors[index] !== undefined) {
this.$set(this.fzListErrors, index, false);
}
})
//
this.formErrors.mfbzl = false;
},
onReset() {
this.fzList.forEach((item, index) => {
item.num = "";
//
if (this.fzListErrors[index] !== undefined) {
this.$set(this.fzListErrors, index, false);
}
})
//
this.formErrors.mfbzl = false;
},
onPrint() { },
onCommonBlur(e, field) {
if (this.formData[field]) {
this.formErrors[field] = false;
}
},
onBlurFzNum(index) {
if (this.fzList[index] && this.fzList[index].num) {
if (this.fzListErrors[index] !== undefined) {
this.$set(this.fzListErrors, index, false);
}
}
},
}
}
</script>
<style lang="scss" scoped>
.dialog-content {
padding: 20px;
}
.unit-select {
width: 100px;
}
.content-item {
display: flex;
align-items: center;
}
.header-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 20px;
margin-top: 20px;
}
.header-item {
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
background: #fff;
border-radius: 4px;
padding: 20px;
}
.header-title {
margin-bottom: 10px;
}
.content-container {
margin-top: 20px;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-height: 50vh;
overflow: auto;
}
.ml-20 {
margin-left: 20px;
}
.list-item {
display: flex;
align-items: center;
// margin-top: 20px;
}
.list-label {
margin-right: 5px;
// width: 200px;
}
</style>

Loading…
Cancel
Save