1、完善表格逻辑
2、完善配煤计算器
3、完善设备管理
4、完善采购管理
| | |
| | | <el-table-column v-if="showOperations" :label="operationsLabel" :width="operationsWidth" :show-overflow-tooltip="false" fixed="right" align="center"> |
| | | <template #default="scope"> |
| | | <slot name="operations" :row="scope.row"> |
| | | <!-- 自定义按钮 - 放在默认按钮之前 --> |
| | | <el-button |
| | | v-for="button in customButtons" |
| | | :key="button.name" |
| | | v-show="!button.show || button.show(scope.row)" |
| | | :link="button.link !== false" |
| | | :type="button.type || 'primary'" |
| | | :size="button.size || 'small'" |
| | | :icon="button.icon" |
| | | :disabled="button.disabled && button.disabled(scope.row)" |
| | | @click="handleCustomClick(button.name, scope.row)" |
| | | > |
| | | {{ button.label }} |
| | | </el-button> |
| | | |
| | | <!-- 默认操作按钮 --> |
| | | <el-button v-if="operations.includes('edit')" link type="primary" size="small" |
| | | @click="handleEdit(scope.row)">编辑</el-button> |
| | | <el-button v-if="operations.includes('viewRow')" link type="primary" size="small" |
| | |
| | | operations: { |
| | | type: Array, |
| | | default: () => ['edit', 'delete', 'export'] |
| | | }, // 删除确认信息 |
| | | }, |
| | | // 自定义按钮配置 |
| | | customButtons: { |
| | | type: Array, |
| | | default: () => [] |
| | | // 示例配置: |
| | | // [ |
| | | // { |
| | | // name: 'return', // 按钮标识 |
| | | // label: '归还', // 按钮显示文本 |
| | | // type: 'success', // 按钮类型 |
| | | // size: 'small', // 按钮大小 |
| | | // icon: '', // 图标(可选) |
| | | // show: (row) => true, // 显示条件函数(可选) |
| | | // disabled: (row) => false, // 禁用条件函数(可选) |
| | | // } |
| | | // ] |
| | | }, |
| | | // 删除确认信息 |
| | | deleteConfirmText: { |
| | | type: String, |
| | | default: '确认删除该记录?' |
| | |
| | | }; |
| | | |
| | | // 处理选择变化、编辑、删除和导出操作 |
| | | const emit = defineEmits(['selection-change', 'edit', 'delete', 'export', 'viewRow', 'viewFile']) |
| | | const emit = defineEmits(['selection-change', 'edit', 'delete', 'export', 'viewRow', 'viewFile', 'custom-click']) |
| | | const handleSelectionChange = (selection) => { |
| | | emit('selection-change', selection) |
| | | } |
| | |
| | | const handleViewFile = (row) => { |
| | | emit('viewFile', row) |
| | | } |
| | | |
| | | // 处理自定义按钮点击 |
| | | const handleCustomClick = (buttonName, row) => { |
| | | emit('custom-click', { buttonName, row }) |
| | | } |
| | | |
| | | const handleDelete = (row) => { |
| | | ElMessageBox.confirm( |
| | | props.deleteConfirmText, |
| | |
| | | <!-- 混合煤属性 --> |
| | | <div class="props-section"> |
| | | <div class="props-title">📊 混合煤属性</div> |
| | | <div class="props-grid"> |
| | | |
| | | <!-- 基础属性展示区 --> |
| | | <div class="props-display-grid"> |
| | | <div class="prop-item"> |
| | | <span class="prop-label">发热量:</span> |
| | | <span class="prop-value" |
| | |
| | | >{{ result.optimal.props.cost.toFixed(2) }} 元/吨</span |
| | | > |
| | | </div> |
| | | <div class="prop-item"> |
| | | <span class="prop-label">生成:</span> |
| | | <el-autocomplete |
| | | v-model="result.optimal.props.createCoal" |
| | | :fetch-suggestions="querySearch" |
| | | clearable |
| | | size="small" |
| | | class="inline-input red-border" |
| | | style="width: 180px; min-height: 24px !important" |
| | | placeholder="请输入生成煤种" |
| | | @blur="handleSelect($event)" |
| | | @select="handleSelect($event)" |
| | | /> |
| | | </div> |
| | | |
| | | <!-- 输入操作区 --> |
| | | <div class="props-input-section"> |
| | | <div class="input-row"> |
| | | <div class="input-item"> |
| | | <label class="input-label">生成煤种:</label> |
| | | <el-autocomplete |
| | | v-model="result.optimal.props.createCoal" |
| | | :fetch-suggestions="querySearch" |
| | | clearable |
| | | size="small" |
| | | class="coal-input" |
| | | placeholder="请输入/选择生成煤种" |
| | | @blur="handleSelect($event)" |
| | | @select="handleSelect($event)" |
| | | /> |
| | | </div> |
| | | <div class="input-item"> |
| | | <label class="input-label">生产数量:</label> |
| | | <el-input |
| | | type="number" |
| | | clearable |
| | | size="small" |
| | | class="quantity-input" |
| | | v-model="result.optimal.props.createCoalQuantity" |
| | | placeholder="请输入生产数量" |
| | | :min="0" |
| | | :max="999999" |
| | | :step="0.1" |
| | | :precision="2" |
| | | @input="handleQuantityInput" |
| | | @blur="handleQuantityBlur" |
| | | > |
| | | <template #suffix> |
| | | <span style="color: #909399; font-size: 12px;">吨</span> |
| | | </template> |
| | | </el-input> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | result.value.optimal.props.createCoal = matchedName; |
| | | } |
| | | }; |
| | | |
| | | // 处理数量输入 |
| | | const handleQuantityInput = (value) => { |
| | | // 限制输入范围和精度 |
| | | if (value !== null && value !== undefined && value !== '') { |
| | | const numValue = parseFloat(value); |
| | | if (numValue < 0) { |
| | | result.value.optimal.props.createCoalQuantity = 0; |
| | | } else if (numValue > 999999) { |
| | | result.value.optimal.props.createCoalQuantity = 999999; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 处理数量失焦 |
| | | const handleQuantityBlur = (event) => { |
| | | const value = event.target.value; |
| | | if (value && !isNaN(value)) { |
| | | // 格式化为两位小数 |
| | | const formatted = parseFloat(value).toFixed(2); |
| | | result.value.optimal.props.createCoalQuantity = formatted; |
| | | } |
| | | }; |
| | | onMounted(async () => { |
| | | getCoalInfo(); |
| | | geInfoCoals(); |
| | |
| | | const validationChecks = [ |
| | | { condition: !result.value, message: "请先计算最优配比后再添加至待入库" }, |
| | | { condition: !result.value.optimal, message: "请先计算最优配比" }, |
| | | { condition: !result.value.optimal.props.createCoal, message: "请先选择生成煤种" } |
| | | { condition: !result.value.optimal.props.createCoal, message: "请先选择生成煤种" }, |
| | | { condition: !result.value.optimal.props.createCoalQuantity || result.value.optimal.props.createCoalQuantity <= 0, message: "请输入有效的生产数量" } |
| | | ]; |
| | | |
| | | for (const check of validationChecks) { |
| | |
| | | ); |
| | | // 准备数据 |
| | | const optimalData = result.value.optimal; |
| | | optimalData.props.totalTonnage = formInline.value.totalTonnage; |
| | | optimalData.props.cost = parseFloat(optimalData.props.cost.toFixed(2)); |
| | | |
| | | // 添加官方ID |
| | |
| | | const instructions = genInstructions( |
| | | validCoals, |
| | | ratios, |
| | | formInline.value.totalTonnage, |
| | | formInline.value.scoopWeight |
| | | ); |
| | | |
| | | // 初始化扩展属性 |
| | | props.createCoal = ""; |
| | | props.createCoalQuantity = 0; |
| | | props.coalId = null; |
| | | |
| | | data.result = { |
| | | show: true, |
| | |
| | | if (altRatios) { |
| | | const altProps = calcBlendProps(coals, altRatios); |
| | | const altInstructions = genInstructions( |
| | | coals, altRatios, formInline.value.totalTonnage, formInline.value.scoopWeight |
| | | coals, altRatios, formInline.value.scoopWeight |
| | | ); |
| | | |
| | | alternatives.push({ |
| | |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | /* 基础属性展示网格 */ |
| | | .props-display-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
| | | gap: 8px; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | /* 输入操作区域 */ |
| | | .props-input-section { |
| | | border-top: 1px solid #ebeef5; |
| | | padding-top: 15px; |
| | | } |
| | | |
| | | .input-row { |
| | | display: flex; |
| | | gap: 15px; |
| | | align-items: flex-end; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .input-item { |
| | | flex: 1; |
| | | min-width: 200px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .input-label { |
| | | font-size: 13px; |
| | | color: #606266; |
| | | margin-bottom: 6px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .coal-input, |
| | | .quantity-input { |
| | | width: 100%; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .coal-input :deep(.el-input__wrapper), |
| | | .quantity-input :deep(.el-input__wrapper) { |
| | | border: 1px solid #dcdfe6; |
| | | border-radius: 4px; |
| | | transition: all 0.2s; |
| | | min-height: 32px; |
| | | } |
| | | |
| | | .coal-input :deep(.el-input__wrapper):hover, |
| | | .quantity-input :deep(.el-input__wrapper):hover { |
| | | border-color: #c0c4cc; |
| | | } |
| | | |
| | | .coal-input :deep(.el-input__wrapper.is-focus), |
| | | .quantity-input :deep(.el-input__wrapper.is-focus) { |
| | | border-color: #409eff; |
| | | box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1); |
| | | } |
| | | |
| | | .props-grid { |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .props-grid { |
| | | .props-display-grid { |
| | | grid-template-columns: 1fr; |
| | | gap: 6px; |
| | | } |
| | | |
| | | .input-row { |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .input-item { |
| | | min-width: 100%; |
| | | } |
| | | |
| | | .table-container { |
| | |
| | | :deep(.el-table .cell) { |
| | | padding: 4px 8px; |
| | | } |
| | | |
| | | .right-card { |
| | | width: 100%; |
| | | min-width: auto; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 1024px) { |
| | | .props-display-grid { |
| | | grid-template-columns: repeat(2, 1fr); |
| | | } |
| | | |
| | | .input-row { |
| | | gap: 12px; |
| | | } |
| | | } |
| | | :deep(.el-input__wrapper) { |
| | | min-height: 24px !important; |
| | |
| | | :deep(.el-input__inner) { |
| | | min-height: 24px !important; |
| | | } |
| | | |
| | | /* 数量输入框样式优化 */ |
| | | .coal-input :deep(.el-input__suffix), |
| | | .quantity-input :deep(.el-input__suffix) { |
| | | display: flex; |
| | | align-items: center; |
| | | padding-right: 8px; |
| | | } |
| | | |
| | | /* 输入框的后缀单位样式 */ |
| | | .coal-input :deep(.el-input__suffix-inner), |
| | | .quantity-input :deep(.el-input__suffix-inner) { |
| | | display: flex; |
| | | align-items: center; |
| | | font-style: normal; |
| | | color: #909399; |
| | | font-size: 12px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="visible" |
| | | :title="isEdit ? '编辑设备领用' : '新增设备领用'" |
| | | :title="isReturnMode ? '设备归还' : (isEdit ? '编辑设备领用' : '新增设备领用')" |
| | | width="600px" |
| | | @close="handleClose" |
| | | > |
| | |
| | | <el-select |
| | | v-model="form.userId" |
| | | placeholder="请选择" |
| | | :disabled="isViewMode" |
| | | :disabled="isViewMode || isReturnMode" |
| | | @change="getEquipment" |
| | | > |
| | | <el-option |
| | |
| | | <el-select |
| | | v-model="form.equipmentId" |
| | | placeholder="请选择" |
| | | :disabled="isViewMode" |
| | | :disabled="isViewMode || isReturnMode" |
| | | > |
| | | <el-option |
| | | v-for="item in equipmentList" |
| | |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="设备库存" prop="equipmentStock"> |
| | | <el-form-item label="设备库存" prop="equipmentStock" v-if="!isReturnMode && formData.status !== 2"> |
| | | <el-input |
| | | :value=" |
| | | equipmentList.find((item) => item.id == form.equipmentId) |
| | |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="领用数量" prop="usageQuantity"> |
| | | <el-form-item label="已使用数量" prop="usedQuantity" v-if="isReturnMode"> |
| | | <el-input |
| | | :value="formData.usageQuantity" |
| | | disabled |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="已归还数量" prop="returnedQuantity" v-if="isReturnMode"> |
| | | <el-input |
| | | :value="formData.totalReturnNo || 0" |
| | | disabled |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="领用数量" prop="usageQuantity" v-if="!isReturnMode && formData.status !== 2"> |
| | | <el-input-number |
| | | v-model="form.usageQuantity" |
| | | :min="1" |
| | |
| | | >(最多{{ maxQuantity }}台)</span |
| | | > |
| | | </el-form-item> |
| | | <el-form-item label="使用状态" prop="equipmentStatus"> |
| | | <!-- 编辑的时候自动匹配 --> |
| | | <el-select |
| | | v-model="form.equipmentStatus" |
| | | placeholder="请选择" |
| | | :disabled="isViewMode" |
| | | default-first-option |
| | | <el-form-item label="本次归还数量" prop="returnQuantity" v-if="isReturnMode"> |
| | | <el-input-number |
| | | v-model="form.returnQuantity" |
| | | :min="1" |
| | | :max="Math.max(1, remainingReturnQuantity)" |
| | | style="width: 100%" |
| | | :disabled="remainingReturnQuantity <= 0" |
| | | /> |
| | | <span |
| | | style="color: #999; font-size: 12px; margin-left: 8px" |
| | | v-if="remainingReturnQuantity > 0" |
| | | >(最多{{ remainingReturnQuantity }}台)</span |
| | | > |
| | | <el-option label="使用中" :value="1" /> |
| | | <el-option label="已归还" :value="2" :disabled="props.id" /> |
| | | </el-select> |
| | | <span |
| | | style="color: #ff4d4f; font-size: 12px; margin-left: 8px" |
| | | v-else |
| | | >(已全部归还)</span |
| | | > |
| | | </el-form-item> |
| | | <el-form-item label="使用开始时间" prop="usageStartTime"> |
| | | <!-- 使用开始时间 - 只在非归还模式显示 --> |
| | | <el-form-item label="使用开始时间" prop="usageStartTime" v-if="!isReturnMode"> |
| | | <el-date-picker |
| | | v-model="form.usageStartTime" |
| | | type="datetime" |
| | |
| | | :disabled="isViewMode" |
| | | /> |
| | | </el-form-item> |
| | | <!-- <el-form-item label="使用结束时间" prop="usageEndTime"> |
| | | |
| | | <!-- 归还结束时间 - 只在归还模式显示 --> |
| | | <el-form-item label="归还时间" prop="returnTime" v-if="isReturnMode"> |
| | | <el-date-picker |
| | | v-model="form.usageEndTime" |
| | | v-model="form.returnTime" |
| | | type="datetime" |
| | | placeholder="选择结束时间" |
| | | placeholder="选择归还时间" |
| | | style="width: 100%" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | /> |
| | | </el-form-item> --> |
| | | </el-form-item> |
| | | <el-form-item label="备注" prop="remarks"> |
| | | <el-input |
| | | v-model="form.remarks" |
| | |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | beforeClose: { |
| | | type: Function, |
| | | default: () => {}, |
| | | }, |
| | | addOrEdit: { |
| | | type: String, |
| | | default: "add", |
| | | }, |
| | | title: { |
| | | type: String, |
| | | default: "", |
| | | }, |
| | | equipmentStatus: { |
| | | type: [Number, String], // 允许数字或字符串 |
| | | default: 1, |
| | | }, |
| | | }); |
| | | const maxQuantity = computed(() => { |
| | |
| | | const isViewMode = computed( |
| | | () => |
| | | props.addOrEdit === "view" || |
| | | props.addOrEdit === "viewRow" || |
| | | Number(props.equipmentStatus) === 2 |
| | | props.addOrEdit === "viewRow" |
| | | ); |
| | | |
| | | // 判断是否为归还模式 |
| | | const isReturnMode = computed(() => props.addOrEdit === "return"); |
| | | |
| | | // 计算剩余可归还数量 |
| | | const remainingReturnQuantity = computed(() => { |
| | | if (!isReturnMode.value || !props.formData.usageQuantity) return 0; |
| | | |
| | | const totalUsageQuantity = props.formData.usageQuantity || 0; // 总使用数量 |
| | | const alreadyReturnedQuantity = props.formData.totalReturnNo || 0; // 已归还数量 |
| | | const remaining = totalUsageQuantity - alreadyReturnedQuantity; // 剩余可归还数量 |
| | | |
| | | return Math.max(0, remaining); // 确保不为负数 |
| | | }); |
| | | |
| | | const isEdit = computed(() => !!props.formData?.id); |
| | | const formRef = ref(); |
| | |
| | | userId: "", |
| | | equipmentId: "", |
| | | usageQuantity: 1, |
| | | equipmentStatus: 1, // 默认使用中 |
| | | usageStartTime: "", |
| | | returnQuantity: 1, |
| | | returnTime: "", |
| | | remarks: "", |
| | | }; |
| | | const form = ref({ ...defaultForm }); |
| | | |
| | | // 确保初始化时使用状态有默认值 |
| | | // 获取当前日期(YYYY-MM-DD格式) |
| | | const getCurrentDate = () => { |
| | | const now = new Date(); |
| | | const year = now.getFullYear(); |
| | | const month = String(now.getMonth() + 1).padStart(2, '0'); |
| | | const day = String(now.getDate()).padStart(2, '0'); |
| | | return `${year}-${month}-${day}`; |
| | | }; |
| | | |
| | | // 确保初始化时获取设备列表 |
| | | onMounted(() => { |
| | | if ( |
| | | form.value.equipmentStatus === undefined || |
| | | form.value.equipmentStatus === null |
| | | ) { |
| | | console.log(form.value.equipmentStatus); |
| | | form.value.equipmentStatus = 1; |
| | | } |
| | | getEquipment(); |
| | | }); |
| | | |
| | |
| | | () => props.formData, |
| | | (val) => { |
| | | if (val && Object.keys(val).length > 0) { |
| | | // 编辑模式,直接赋值,不使用默认值合并 |
| | | form.value = { ...val }; |
| | | |
| | | // 归还模式初始化 |
| | | if (isReturnMode.value) { |
| | | form.value.returnTime = getCurrentDate(); |
| | | const maxReturnQuantity = remainingReturnQuantity.value; |
| | | form.value.returnQuantity = maxReturnQuantity > 0 ? Math.min(1, maxReturnQuantity) : 0; |
| | | } |
| | | } else { |
| | | // 新增模式,使用默认值 |
| | | form.value = { ...defaultForm }; |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | const rules = { |
| | | userId: [{ required: true, message: "请输入领用人", trigger: "blur" }], |
| | | equipmentId: [{ required: true, message: "请输入设备ID", trigger: "blur" }], |
| | | usageQuantity: [ |
| | | { required: true, message: "请输入领用数量", trigger: "blur" }, |
| | | { type: "number", min: 1, message: "至少领用1台", trigger: "blur" }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (maxQuantity.value !== null && value > maxQuantity.value) { |
| | | callback(new Error("领用数量不能大于设备数量")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur", |
| | | }, |
| | | ], |
| | | equipmentStatus: [ |
| | | { required: true, message: "请选择使用状态", trigger: "change" }, |
| | | ], |
| | | usageStartTime: [ |
| | | { required: true, message: "请选择开始时间", trigger: "change" }, |
| | | ], |
| | | }; |
| | | const rules = computed(() => { |
| | | const baseRules = { |
| | | userId: [{ required: true, message: "请输入领用人", trigger: "blur" }], |
| | | equipmentId: [{ required: true, message: "请输入设备ID", trigger: "blur" }], |
| | | }; |
| | | |
| | | if (isReturnMode.value) { |
| | | // 归还模式的验证规则 |
| | | return { |
| | | ...baseRules, |
| | | returnQuantity: [ |
| | | { required: true, message: "请输入归还数量", trigger: "blur" }, |
| | | { type: "number", min: 1, message: "至少归还1台", trigger: "blur" }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | const remaining = remainingReturnQuantity.value; |
| | | if (remaining <= 0) { |
| | | callback(new Error("已全部归还,无法继续归还")); |
| | | } else if (value > remaining) { |
| | | callback(new Error(`归还数量不能大于剩余可归还数量(${remaining}台)`)); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur", |
| | | }, |
| | | ], |
| | | returnTime: [ |
| | | { required: true, message: "请选择归还时间", trigger: "change" }, |
| | | ], |
| | | }; |
| | | } else { |
| | | // 新增/编辑模式的验证规则 |
| | | return { |
| | | ...baseRules, |
| | | usageQuantity: [ |
| | | { required: true, message: "请输入领用数量", trigger: "blur" }, |
| | | { type: "number", min: 1, message: "至少领用1台", trigger: "blur" }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (maxQuantity.value !== null && value > maxQuantity.value) { |
| | | callback(new Error("领用数量不能大于设备数量")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur", |
| | | }, |
| | | ], |
| | | usageStartTime: [ |
| | | { required: true, message: "请选择开始时间", trigger: "change" }, |
| | | ], |
| | | }; |
| | | } |
| | | }); |
| | | |
| | | function handleClose() { |
| | | emit("update:modelValue", false); |
| | |
| | | function handleSubmit() { |
| | | formRef.value.validate((valid) => { |
| | | if (!valid) return; |
| | | let res = addOrEditUsageRecord(form.value); |
| | | emit("submit", { ...form.value }); |
| | | |
| | | let submitData = { ...form.value }; |
| | | |
| | | // 归还模式处理 |
| | | if (isReturnMode.value) { |
| | | const currentReturnQuantity = form.value.returnQuantity; |
| | | const totalUsageQuantity = props.formData.usageQuantity; |
| | | const alreadyReturnedQuantity = props.formData.totalReturnNo || 0; |
| | | const newTotalReturnedQuantity = alreadyReturnedQuantity + currentReturnQuantity; |
| | | |
| | | submitData = { |
| | | ...props.formData, |
| | | totalReturnNo: newTotalReturnedQuantity, |
| | | returnQuantity: currentReturnQuantity, |
| | | returnTime: form.value.returnTime, |
| | | equipmentStatus: 2, |
| | | remarks: form.value.remarks, |
| | | usageQuantity: totalUsageQuantity |
| | | }; |
| | | } |
| | | |
| | | addOrEditUsageRecord(submitData); |
| | | emit("submit", submitData); |
| | | handleClose(); |
| | | }); |
| | | } |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | :title="title" |
| | | width="600" |
| | | :close-on-click-modal="false" |
| | | @close="handleClose" |
| | | v-model="dialogFormVisible" |
| | | :title="title" |
| | | width="600" |
| | | :close-on-click-modal="false" |
| | | @close="handleClose" |
| | | > |
| | | <el-form |
| | | ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-width="auto" |
| | | class="production-form" |
| | | label-position="right" |
| | | style="max-width: 400px; margin: 0 auto" |
| | | ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-width="auto" |
| | | class="production-form" |
| | | label-position="right" |
| | | style="max-width: 400px; margin: 0 auto" |
| | | > |
| | | <el-form-item label="供应商名称" prop="supplierId"> |
| | | <el-select v-model="form.supplierId" placeholder="请选择供应商" :disabled="isViewMode"> |
| | | <el-option :label="item.label" v-for="item in supplyList" :key="item.value" :value="item.value"/> |
| | | <el-select |
| | | v-model="form.supplierId" |
| | | placeholder="请选择供应商" |
| | | :disabled="isViewMode" |
| | | > |
| | | <el-option |
| | | :label="item.label" |
| | | v-for="item in supplyList" |
| | | :key="item.value" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="煤种" prop="coalId"> |
| | | <el-select v-model="form.coalId" placeholder="请选择煤种" :disabled="isViewMode"> |
| | | <el-option :label="item.label" v-for="item in coalList" :key="item.value" :value="item.value"/> |
| | | <el-select |
| | | v-model="form.coalId" |
| | | placeholder="请选择煤种" |
| | | :disabled="isViewMode" |
| | | > |
| | | <el-option |
| | | :label="item.label" |
| | | v-for="item in coalList" |
| | | :key="item.value" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="采购数量" prop="purchaseQuantity"> |
| | | <el-input |
| | | v-model.number="form.purchaseQuantity" |
| | | placeholder="请输入" |
| | | @blur="handleQuantityBlur" |
| | | :disabled="isViewMode" |
| | | v-model.number="form.purchaseQuantity" |
| | | placeholder="请输入" |
| | | @blur="handleQuantityBlur" |
| | | :disabled="isViewMode" |
| | | > |
| | | <template v-slot:suffix> |
| | | <i style="font-style: normal">吨</i> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="税率" prop="taxRate"> |
| | | <el-input |
| | | v-model.number="form.taxRate" |
| | | placeholder="请输入税率" |
| | | @blur="handleTaxRateBlur" |
| | | :disabled="isViewMode" |
| | | v-model.number="form.taxRate" |
| | | placeholder="请输入税率" |
| | | @blur="handleTaxRateBlur" |
| | | :disabled="isViewMode" |
| | | > |
| | | <template v-slot:suffix> |
| | | <i style="font-style: normal">%</i> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="单价(含税)" prop="priceIncludingTax"> |
| | | <el-input |
| | | v-model.number="form.priceIncludingTax" |
| | | placeholder="请输入含税单价" |
| | | @blur="handlePriceBlur" |
| | | :disabled="isViewMode" |
| | | v-model.number="form.priceIncludingTax" |
| | | placeholder="请输入含税单价" |
| | | @blur="handlePriceBlur" |
| | | :disabled="isViewMode" |
| | | > |
| | | <template v-slot:suffix> |
| | | <i style="font-style: normal">元</i> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="单价(不含税)" prop="priceExcludingTax"> |
| | | <el-input |
| | | v-model.number="form.priceExcludingTax" |
| | | placeholder="自动计算" |
| | | disabled |
| | | v-model.number="form.priceExcludingTax" |
| | | placeholder="自动计算" |
| | | disabled |
| | | > |
| | | <template v-slot:suffix> |
| | | <i style="font-style: normal">元</i> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="总价(不含税)" prop="totalPriceExcludingTax"> |
| | | <el-input |
| | | v-model.number="form.totalPriceExcludingTax" |
| | | placeholder="自动计算" |
| | | disabled |
| | | v-model.number="form.totalPriceExcludingTax" |
| | | placeholder="自动计算" |
| | | disabled |
| | | > |
| | | <template v-slot:suffix> |
| | | <i style="font-style: normal">元</i> |
| | |
| | | </el-form-item> |
| | | <el-form-item label="总价(含税)" prop="totalPriceIncludingTax"> |
| | | <el-input |
| | | v-model.number="form.totalPriceIncludingTax" |
| | | placeholder="自动计算" |
| | | disabled |
| | | v-model.number="form.totalPriceIncludingTax" |
| | | placeholder="自动计算" |
| | | disabled |
| | | > |
| | | <template v-slot:suffix> |
| | | <i style="font-style: normal">元</i> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="运费" prop="freight"> |
| | | <!-- 默认为0 --> |
| | | <el-input |
| | | type="number" |
| | | :precision="2" |
| | | v-model.number="form.freight" |
| | | placeholder="请输入运费" |
| | | :disabled="isViewMode" |
| | | > |
| | | <template v-slot:suffix> |
| | | <i style="font-style: normal">元</i> |
| | |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="登记人" prop="registrantId"> |
| | | <el-input :value="match(form.registrantId)" v-model.number="form.registrantId" disabled placeholder="请输入"/> |
| | | <el-input |
| | | :value="match(form.registrantId)" |
| | | v-model.number="form.registrantId" |
| | | disabled |
| | | placeholder="请输入" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="登记日期" prop="registrationDate"> |
| | | <el-date-picker |
| | | disabled |
| | | v-model="form.registrationDate" |
| | | type="date" |
| | | placeholder="YYYY-MM-DD" |
| | | style="width: 100%" |
| | | value-format="YYYY-MM-DD" |
| | | disabled |
| | | v-model="form.registrationDate" |
| | | type="date" |
| | | placeholder="YYYY-MM-DD" |
| | | style="width: 100%" |
| | | value-format="YYYY-MM-DD" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <!-- 重置和取消 --> |
| | | <el-button @click="handleClose" v-if="title.includes('新增') || title.includes('查看')" |
| | | >取消 |
| | | </el-button |
| | | > |
| | | <el-button |
| | | @click="handleClose" |
| | | v-if="title.includes('新增') || title.includes('查看')" |
| | | >取消 |
| | | </el-button> |
| | | <el-button @click="handleReset" v-if="title.includes('编辑')" |
| | | >重置 |
| | | </el-button |
| | | >重置 |
| | | </el-button> |
| | | <el-button type="primary" v-if="!isViewMode" @click="handleSubmit" |
| | | >确认</el-button |
| | | > |
| | | <el-button type="primary" v-if="!isViewMode" @click="handleSubmit">确认</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | |
| | | </template> |
| | | |
| | | <script setup name="ProductionDialog"> |
| | | import {ref, defineProps, watch, onMounted, nextTick, computed} from "vue"; |
| | | import {ElMessage} from "element-plus"; |
| | | import { ref, defineProps, watch, onMounted, nextTick, computed } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import {addOrEditPR, getSupplyList, getCoalInfoList} from "@/api/procureMent"; |
| | | import { addOrEditPR, getSupplyList, getCoalInfoList } from "@/api/procureMent"; |
| | | |
| | | const props = defineProps({ |
| | | title: { |
| | |
| | | if (isNaN(num) || num === null || num === undefined || num === "") { |
| | | return 0; |
| | | } |
| | | return Number((Math.floor(parseFloat(num) * Math.pow(10, precision)) / Math.pow(10, precision)).toFixed(precision)); |
| | | return Number( |
| | | ( |
| | | Math.floor(parseFloat(num) * Math.pow(10, precision)) / |
| | | Math.pow(10, precision) |
| | | ).toFixed(precision) |
| | | ); |
| | | }; |
| | | |
| | | // 安全获取数值 |
| | |
| | | |
| | | // 1. 根据含税单价和税率计算不含税单价 |
| | | // 不含税单价 = 含税单价 / (1 + 税率/100) |
| | | const priceExcludingTax = priceIncludingTax && taxRate |
| | | ? parseFloat((priceIncludingTax / (1 + taxRate / 100)).toFixed(2)) |
| | | : 0; |
| | | const priceExcludingTax = |
| | | priceIncludingTax && taxRate |
| | | ? parseFloat((priceIncludingTax / (1 + taxRate / 100)).toFixed(2)) |
| | | : 0; |
| | | |
| | | // 2. 计算不含税总价 = 不含税单价 × 数量 |
| | | const totalPriceExcludingTax = priceExcludingTax && quantity |
| | | ? toFixed(priceExcludingTax * quantity, 2) |
| | | : 0; |
| | | const totalPriceExcludingTax = |
| | | priceExcludingTax && quantity |
| | | ? toFixed(priceExcludingTax * quantity, 2) |
| | | : 0; |
| | | |
| | | // 3. 计算含税总价 = 含税单价 × 数量 |
| | | const totalPriceIncludingTax = priceIncludingTax && quantity |
| | | ? toFixed(priceIncludingTax * quantity, 2) |
| | | : 0; |
| | | const totalPriceIncludingTax = |
| | | priceIncludingTax && quantity |
| | | ? toFixed(priceIncludingTax * quantity, 2) |
| | | : 0; |
| | | |
| | | // 保证显示为两位小数(如88.5显示为88.50) |
| | | form.value.priceExcludingTax = priceExcludingTax.toFixed(2); |
| | |
| | | |
| | | // 监听表单对象变化,用于处理编辑模式下的数据加载和实时计算 |
| | | watch( |
| | | () => [form.value.priceIncludingTax, form.value.taxRate, form.value.purchaseQuantity], |
| | | () => [ |
| | | form.value.priceIncludingTax, |
| | | form.value.taxRate, |
| | | form.value.purchaseQuantity, |
| | | ], |
| | | () => { |
| | | // 防抖处理,避免频繁计算 |
| | | nextTick(() => { |
| | |
| | | }; |
| | | // 处理税率输入框失焦事件 |
| | | const handleTaxRateBlur = () => { |
| | | if (form.value.taxRate !== null && form.value.taxRate !== undefined && form.value.taxRate !== "") { |
| | | if ( |
| | | form.value.taxRate !== null && |
| | | form.value.taxRate !== undefined && |
| | | form.value.taxRate !== "" |
| | | ) { |
| | | form.value.taxRate = toFixed(parseFloat(form.value.taxRate), 2); |
| | | // watch 会自动触发 calculatePrices,不需要手动调用 |
| | | } |
| | |
| | | |
| | | // 处理含税单价输入框失焦事件 |
| | | const handlePriceBlur = () => { |
| | | if (form.value.priceIncludingTax !== null && form.value.priceIncludingTax !== undefined && form.value.priceIncludingTax !== "") { |
| | | form.value.priceIncludingTax = toFixed(parseFloat(form.value.priceIncludingTax), 2); |
| | | if ( |
| | | form.value.priceIncludingTax !== null && |
| | | form.value.priceIncludingTax !== undefined && |
| | | form.value.priceIncludingTax !== "" |
| | | ) { |
| | | form.value.priceIncludingTax = toFixed( |
| | | parseFloat(form.value.priceIncludingTax), |
| | | 2 |
| | | ); |
| | | // watch 会自动触发 calculatePrices,不需要手动调用 |
| | | } |
| | | }; |
| | | |
| | | // 处理采购数量输入框失焦事件 |
| | | const handleQuantityBlur = () => { |
| | | if (form.value.purchaseQuantity !== null && form.value.purchaseQuantity !== undefined && form.value.purchaseQuantity !== "") { |
| | | form.value.purchaseQuantity = toFixed(parseFloat(form.value.purchaseQuantity), 3); // 数量保留3位小数 |
| | | if ( |
| | | form.value.purchaseQuantity !== null && |
| | | form.value.purchaseQuantity !== undefined && |
| | | form.value.purchaseQuantity !== "" |
| | | ) { |
| | | form.value.purchaseQuantity = toFixed( |
| | | parseFloat(form.value.purchaseQuantity), |
| | | 3 |
| | | ); // 数量保留3位小数 |
| | | // watch 会自动触发 calculatePrices,不需要手动调用 |
| | | } |
| | | }; |
| | |
| | | }); |
| | | const rules = { |
| | | supplierName: [ |
| | | {required: true, message: "请输入供应商名称", trigger: "blur"}, |
| | | { required: true, message: "请输入供应商名称", trigger: "blur" }, |
| | | ], |
| | | coal: [{required: true, message: "请输入煤种", trigger: "blur"}], |
| | | coal: [{ required: true, message: "请输入煤种", trigger: "blur" }], |
| | | purchaseQuantity: [ |
| | | {required: true, message: "请输入采购数量", trigger: "blur"}, |
| | | {type: "number", message: "采购数量必须为数字", trigger: "blur"}, |
| | | { required: true, message: "请输入采购数量", trigger: "blur" }, |
| | | { type: "number", message: "采购数量必须为数字", trigger: "blur" }, |
| | | ], |
| | | priceExcludingTax: [ |
| | | {required: true, message: "请输入单价", trigger: "blur"}, |
| | | { required: true, message: "请输入单价", trigger: "blur" }, |
| | | ], |
| | | priceIncludingTax: [ |
| | | {required: true, message: "请输入含税单价", trigger: "blur"}, |
| | | { required: true, message: "请输入含税单价", trigger: "blur" }, |
| | | ], |
| | | taxRate:[ |
| | | {required: true, message: "请输入税率", trigger: "blur"}, |
| | | {type: "number", message: "税率必须为数字", trigger: "blur"}, |
| | | ] |
| | | taxRate: [ |
| | | { required: true, message: "请输入税率", trigger: "blur" }, |
| | | { type: "number", message: "税率必须为数字", trigger: "blur" }, |
| | | ], |
| | | }; |
| | | // 关闭弹窗 |
| | | const handleClose = () => { |
| | |
| | | const { proxy } = getCurrentInstance(); |
| | | const dialogFormVisible = ref(false); |
| | | const form = ref({ |
| | | taxRate: "13" |
| | | taxRate: 13, |
| | | freight: 20, |
| | | }); |
| | | const title = ref(""); |
| | | // 状态变量 |
| | |
| | | { prop: "purchaseQuantity", label: "采购数量", minWidth: 100 }, |
| | | { prop: "priceIncludingTax", label: "单价(含税)", minWidth: 150 }, |
| | | { prop: "totalPriceIncludingTax", label: "总价(含税)", minWidth: 100 }, |
| | | { prop: "freight", label: "运费", minWidth: 100 }, |
| | | { prop: "taxRate", label: "税率", minWidth: 100 }, |
| | | { prop: "priceExcludingTax", label: "不含税单价", minWidth: 100 }, |
| | | { prop: "registrantId", label: "登记人", minWidth: 100, |
| | |
| | | totalPriceExcludingTax: "", |
| | | priceIncludingTax: "", |
| | | totalPriceIncludingTax: "", |
| | | taxRate: "13", |
| | | taxRate: 13, |
| | | freight:20, |
| | | registrantId: userInfo.value.userId, |
| | | registrationDate: new Date().toISOString().split("T")[0], |
| | | }; |