Compare commits
4 Commits
368298a29d
...
11f5a1f51e
| Author | SHA1 | Date | |
|---|---|---|---|
| 11f5a1f51e | |||
| 7829cac59a | |||
| 4857581963 | |||
| c1c494893f |
@ -1,6 +1,6 @@
|
|||||||
# 文件路径: app/api/v1/inbound/base.py
|
# 文件路径: app/api/v1/inbound/base.py
|
||||||
|
|
||||||
from flask import Blueprint, request, jsonify, send_file, g
|
from flask import Blueprint, request, jsonify, send_file, g, current_app
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.services.inbound.base_service import MaterialBaseService
|
from app.services.inbound.base_service import MaterialBaseService
|
||||||
from app.utils.decorators import login_required, permission_required, audit_log
|
from app.utils.decorators import login_required, permission_required, audit_log
|
||||||
@ -410,3 +410,49 @@ def batch_set_warning():
|
|||||||
db.session.rollback()
|
db.session.rollback()
|
||||||
current_app.logger.error(f"批量设置预警失败: {str(e)}")
|
current_app.logger.error(f"批量设置预警失败: {str(e)}")
|
||||||
return jsonify({"code": 500, "msg": f"批量设置预警失败: {str(e)}"}), 500
|
return jsonify({"code": 500, "msg": f"批量设置预警失败: {str(e)}"}), 500
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# 2.6 批量设置强制质检 API (POST /api/v1/inbound/base/batch-inspection)
|
||||||
|
# ==============================================================================
|
||||||
|
@inbound_base_bp.route('/batch-inspection', methods=['POST'])
|
||||||
|
@permission_required('material_list:operation')
|
||||||
|
def batch_set_inspection():
|
||||||
|
"""
|
||||||
|
批量设置物料强制质检标记
|
||||||
|
请求体格式: {
|
||||||
|
"ids": [1, 2, 3],
|
||||||
|
"isInspectionRequired": true
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
data = request.get_json()
|
||||||
|
if not data:
|
||||||
|
return jsonify({"code": 400, "msg": "No data provided"}), 400
|
||||||
|
|
||||||
|
ids = data.get('ids', [])
|
||||||
|
is_inspection_required = bool(data.get('isInspectionRequired', False))
|
||||||
|
|
||||||
|
if not ids:
|
||||||
|
return jsonify({"code": 400, "msg": "请选择要设置的物料"}), 400
|
||||||
|
|
||||||
|
updated_count = 0
|
||||||
|
for base_id in ids:
|
||||||
|
material = MaterialBase.query.get(base_id)
|
||||||
|
if material:
|
||||||
|
material.is_inspection_required = is_inspection_required
|
||||||
|
updated_count += 1
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return jsonify({
|
||||||
|
"code": 200,
|
||||||
|
"msg": f"批量设置成功,已更新 {updated_count} 条记录",
|
||||||
|
"data": {
|
||||||
|
"updated": updated_count
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
db.session.rollback()
|
||||||
|
current_app.logger.error(f"批量设置强制质检失败: {str(e)}")
|
||||||
|
return jsonify({"code": 500, "msg": f"批量设置强制质检失败: {str(e)}"}), 500
|
||||||
|
|||||||
@ -31,6 +31,9 @@ class MaterialBase(db.Model):
|
|||||||
# 启用状态
|
# 启用状态
|
||||||
is_enabled = db.Column(db.Boolean, default=True, comment='是否启用')
|
is_enabled = db.Column(db.Boolean, default=True, comment='是否启用')
|
||||||
|
|
||||||
|
# 强制质检标记(采购入库时必须上传检测报告)
|
||||||
|
is_inspection_required = db.Column(db.Boolean, default=False, comment='是否强制要求质检')
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 关联关系区域
|
# 关联关系区域
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@ -81,6 +84,8 @@ class MaterialBase(db.Model):
|
|||||||
'generalImage': parse_list(self.product_image),
|
'generalImage': parse_list(self.product_image),
|
||||||
# 【核心修改】:直接返回布尔值,不再转成 1 或 0
|
# 【核心修改】:直接返回布尔值,不再转成 1 或 0
|
||||||
'isEnabled': bool(self.is_enabled),
|
'isEnabled': bool(self.is_enabled),
|
||||||
|
# 强制质检标记
|
||||||
|
'isInspectionRequired': bool(self.is_inspection_required),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -81,6 +81,8 @@ class StockBuy(db.Model):
|
|||||||
'category': self.base.category if self.base else '',
|
'category': self.base.category if self.base else '',
|
||||||
'unit': self.base.unit if self.base else '',
|
'unit': self.base.unit if self.base else '',
|
||||||
'material_type': self.base.material_type if self.base else '',
|
'material_type': self.base.material_type if self.base else '',
|
||||||
|
# 强制质检标记
|
||||||
|
'isInspectionRequired': bool(self.base.is_inspection_required) if self.base else False,
|
||||||
|
|
||||||
'sku': self.sku,
|
'sku': self.sku,
|
||||||
'inbound_date': self.in_date.strftime('%Y-%m-%d') if self.in_date else '',
|
'inbound_date': self.in_date.strftime('%Y-%m-%d') if self.in_date else '',
|
||||||
|
|||||||
@ -75,7 +75,9 @@ class MaterialBaseService:
|
|||||||
'category': item.category,
|
'category': item.category,
|
||||||
'unit': item.unit,
|
'unit': item.unit,
|
||||||
'type': item.material_type,
|
'type': item.material_type,
|
||||||
'status': '启用'
|
'status': '启用',
|
||||||
|
# 强制质检标记
|
||||||
|
'isInspectionRequired': bool(item.is_inspection_required)
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@ -94,6 +94,24 @@ class BuyInboundService:
|
|||||||
if not material: raise ValueError("所选物料不存在")
|
if not material: raise ValueError("所选物料不存在")
|
||||||
if not material.is_enabled: raise ValueError(f"物料【{material.name}】已停用")
|
if not material.is_enabled: raise ValueError(f"物料【{material.name}】已停用")
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 强制质检校验:如果物料标记为强制质检,则必须提供到检状态和检测报告
|
||||||
|
# ============================================================
|
||||||
|
if material.is_inspection_required:
|
||||||
|
inspection_status = data.get('inspection_status')
|
||||||
|
if not inspection_status:
|
||||||
|
raise ValueError(f"物料【{material.name}】为强管控物料,必须选择到检状态")
|
||||||
|
|
||||||
|
# 检查检测报告:文件列表或外部链接至少有一个
|
||||||
|
# 前端会将外部链接添加到 inspection_report 数组中一起提交
|
||||||
|
inspection_report_list = data.get('inspection_report', [])
|
||||||
|
# 过滤空字符串,只保留有效报告(字符串长度 > 0 且去除空格后非空)
|
||||||
|
valid_reports = [r for r in inspection_report_list if r and str(r).strip()]
|
||||||
|
has_report_file = valid_reports and len(valid_reports) > 0
|
||||||
|
|
||||||
|
if not has_report_file:
|
||||||
|
raise ValueError(f"物料【{material.name}】为强管控物料,必须提供检测报告文件或外部链接")
|
||||||
|
|
||||||
BuyInboundService._check_unique(
|
BuyInboundService._check_unique(
|
||||||
base_id=base_id,
|
base_id=base_id,
|
||||||
serial_number=data.get('serial_number'),
|
serial_number=data.get('serial_number'),
|
||||||
@ -171,7 +189,40 @@ class BuyInboundService:
|
|||||||
try:
|
try:
|
||||||
stock = StockBuy.query.get(stock_id)
|
stock = StockBuy.query.get(stock_id)
|
||||||
if not stock: raise ValueError("记录不存在")
|
if not stock: raise ValueError("记录不存在")
|
||||||
BuyInboundService._check_unique(base_id=data.get('base_id', stock.base_id),
|
|
||||||
|
# 获取物料信息用于校验
|
||||||
|
base_id = data.get('base_id', stock.base_id)
|
||||||
|
material = MaterialBase.query.get(base_id)
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 强制质检校验:如果物料标记为强制质检,则必须提供到检状态和检测报告
|
||||||
|
# ============================================================
|
||||||
|
if material and material.is_inspection_required:
|
||||||
|
inspection_status = data.get('inspection_status', stock.inspection_status)
|
||||||
|
if not inspection_status:
|
||||||
|
raise ValueError(f"物料【{material.name}】为强管控物料,必须选择到检状态")
|
||||||
|
|
||||||
|
# 检查检测报告:文件列表至少有一个
|
||||||
|
inspection_report_list = data.get('inspection_report')
|
||||||
|
if inspection_report_list is None:
|
||||||
|
# 如果没有传入,使用现有的
|
||||||
|
import json as json_module
|
||||||
|
try:
|
||||||
|
existing_reports = json_module.loads(stock.inspection_report) if stock.inspection_report else []
|
||||||
|
except:
|
||||||
|
existing_reports = []
|
||||||
|
# 过滤空字符串,只保留有效报告
|
||||||
|
valid_reports = [r for r in existing_reports if r and str(r).strip()]
|
||||||
|
has_report_file = valid_reports and len(valid_reports) > 0
|
||||||
|
else:
|
||||||
|
# 过滤空字符串,只保留有效报告
|
||||||
|
valid_reports = [r for r in inspection_report_list if r and str(r).strip()]
|
||||||
|
has_report_file = valid_reports and len(valid_reports) > 0
|
||||||
|
|
||||||
|
if not has_report_file:
|
||||||
|
raise ValueError(f"物料【{material.name}】为强管控物料,必须提供检测报告文件或外部链接")
|
||||||
|
|
||||||
|
BuyInboundService._check_unique(base_id=base_id,
|
||||||
serial_number=data.get('serial_number', stock.serial_number),
|
serial_number=data.get('serial_number', stock.serial_number),
|
||||||
batch_number=data.get('batch_number', stock.batch_number),
|
batch_number=data.get('batch_number', stock.batch_number),
|
||||||
exclude_id=stock_id)
|
exclude_id=stock_id)
|
||||||
|
|||||||
@ -61,3 +61,12 @@ export function batchSetWarning(data: any[]) {
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 6. 批量设置强制质检
|
||||||
|
export function batchSetInspection(data: { ids: number[], isInspectionRequired: boolean }) {
|
||||||
|
return request({
|
||||||
|
url: '/inbound/base/batch-inspection',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -118,32 +118,30 @@
|
|||||||
<el-icon style="margin-right: 5px"><Download /></el-icon>导出库存统计
|
<el-icon style="margin-right: 5px"><Download /></el-icon>导出库存统计
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<!-- 批量设置预警按钮 (需要 edit_warning 权限) -->
|
<!-- 批量操作按钮 (需要相应权限) -->
|
||||||
<template v-if="userStore.hasPermission('material_list:edit_warning')">
|
<template v-if="!isBatchMode">
|
||||||
<!-- 常规状态 -->
|
|
||||||
<el-button
|
<el-button
|
||||||
v-if="!isBatchMode"
|
v-if="userStore.hasPermission('material_list:edit_warning')"
|
||||||
type="warning"
|
type="warning"
|
||||||
plain
|
plain
|
||||||
@click="enterBatchMode"
|
@click="enterBatchMode('warning')"
|
||||||
style="margin-right: 10px"
|
style="margin-right: 10px"
|
||||||
>
|
>
|
||||||
<el-icon style="margin-right: 5px"><Bell /></el-icon>批量设置预警
|
<el-icon style="margin-right: 5px"><Bell /></el-icon>批量设置预警
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- 批量模式 -->
|
<el-button
|
||||||
<template v-if="isBatchMode">
|
v-if="userStore.hasPermission('material_list:operation')"
|
||||||
<el-button
|
type="danger"
|
||||||
type="warning"
|
plain
|
||||||
:disabled="selectedItems.length === 0"
|
@click="enterBatchMode('inspection')"
|
||||||
@click="handleBatchSetWarning"
|
style="margin-right: 10px"
|
||||||
style="margin-right: 10px"
|
>
|
||||||
>
|
<el-icon style="margin-right: 5px"><CircleCheck /></el-icon>批量质检设置
|
||||||
确认批量设置 (已选 {{ selectedItems.length }} 项)
|
</el-button>
|
||||||
</el-button>
|
</template>
|
||||||
<el-button plain @click="exitBatchMode" style="margin-right: 10px">
|
<template v-else>
|
||||||
退出批量操作
|
<el-button @click="cancelBatchMode">取消选择</el-button>
|
||||||
</el-button>
|
<el-button type="primary" @click="confirmBatchSelection">确认勾选</el-button>
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-button v-if="userStore.hasPermission('material_list:operation')" type="primary" @click="handleAdd" style="margin-right: 10px">
|
<el-button v-if="userStore.hasPermission('material_list:operation')" type="primary" @click="handleAdd" style="margin-right: 10px">
|
||||||
@ -295,6 +293,13 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column v-if="columns.isInspectionRequired.visible" prop="isInspectionRequired" label="强制质检" min-width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.isInspectionRequired ? 'danger' : 'info'" size="small">
|
||||||
|
{{ scope.row.isInspectionRequired ? '是' : '否' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column v-if="userStore.hasPermission('material_list:operation')" label="操作" min-width="200" fixed="right" align="center">
|
<el-table-column v-if="userStore.hasPermission('material_list:operation')" label="操作" min-width="200" fixed="right" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button v-if="userStore.hasPermission('material_list:operation')" link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
|
<el-button v-if="userStore.hasPermission('material_list:operation')" link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
|
||||||
@ -526,13 +531,41 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 批量质检设置弹窗 -->
|
||||||
|
<el-dialog v-model="inspectionDialog.visible" title="批量质检设置" width="500px" append-to-body destroy-on-close>
|
||||||
|
<el-alert
|
||||||
|
:title="`已选择 ${inspectionDialog.selectedCount} 条物料进行批量质检设置`"
|
||||||
|
type="info"
|
||||||
|
:closable="false"
|
||||||
|
style="margin-bottom: 20px"
|
||||||
|
/>
|
||||||
|
<el-form label-position="top">
|
||||||
|
<el-form-item label="是否强制要求入库上传检测报告?">
|
||||||
|
<el-switch
|
||||||
|
v-model="inspectionForm.isInspectionRequired"
|
||||||
|
active-text="是 (强制管控)"
|
||||||
|
inactive-text="否 (免检入库)"
|
||||||
|
/>
|
||||||
|
<div style="color: #909399; font-size: 12px; width: 100%; margin-top: 8px; line-height: 1.5;">
|
||||||
|
开启后,这些物料在采购入库时必须上传检测报告文件或填写外部报告链接,否则将被拦截无法入库。
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="inspectionDialog.visible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="submitBatchInspection" :loading="inspectionLoading">确 定</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, nextTick, computed } from 'vue';
|
import { ref, reactive, onMounted, nextTick, computed } from 'vue';
|
||||||
import { Plus, Document, Refresh, Setting, Rank, Camera, Link, Download, Bell } from '@element-plus/icons-vue';
|
import { Plus, Document, Refresh, Setting, Rank, Camera, Link, Download, Bell, CircleCheck } from '@element-plus/icons-vue';
|
||||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
import type { FormInstance, FormRules } from 'element-plus';
|
||||||
import { useUserStore } from '@/stores/user';
|
import { useUserStore } from '@/stores/user';
|
||||||
@ -544,7 +577,8 @@ import {
|
|||||||
delMaterialBase,
|
delMaterialBase,
|
||||||
getMaterialBaseOptions,
|
getMaterialBaseOptions,
|
||||||
exportAssetStatistics,
|
exportAssetStatistics,
|
||||||
batchSetWarning
|
batchSetWarning,
|
||||||
|
batchSetInspection
|
||||||
} from '@/api/material_base';
|
} from '@/api/material_base';
|
||||||
import { uploadFile, deleteFile } from '@/api/common/upload';
|
import { uploadFile, deleteFile } from '@/api/common/upload';
|
||||||
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue';
|
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue';
|
||||||
@ -648,14 +682,53 @@ const handleSelectionChange = (selection: MaterialBaseVO[]) => {
|
|||||||
|
|
||||||
// 批量操作模式
|
// 批量操作模式
|
||||||
const isBatchMode = ref(false);
|
const isBatchMode = ref(false);
|
||||||
const enterBatchMode = () => {
|
const batchActionType = ref(''); // 'warning' | 'inspection'
|
||||||
|
|
||||||
|
const enterBatchMode = (actionType: string) => {
|
||||||
|
batchActionType.value = actionType;
|
||||||
selectedItems.value = [];
|
selectedItems.value = [];
|
||||||
isBatchMode.value = true;
|
isBatchMode.value = true;
|
||||||
|
tableRef.value?.clearSelection();
|
||||||
};
|
};
|
||||||
const exitBatchMode = () => {
|
|
||||||
selectedItems.value = [];
|
const cancelBatchMode = () => {
|
||||||
tableRef.value?.clearSelection(); // 清除表格勾选状态
|
|
||||||
isBatchMode.value = false;
|
isBatchMode.value = false;
|
||||||
|
batchActionType.value = '';
|
||||||
|
tableRef.value?.clearSelection();
|
||||||
|
selectedItems.value = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmBatchSelection = () => {
|
||||||
|
const selected = tableRef.value?.getSelectionRows() || [];
|
||||||
|
if (selected.length === 0) {
|
||||||
|
return ElMessage.warning('请先勾选需要操作的物料');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据操作类型路由到对应的业务弹窗
|
||||||
|
if (batchActionType.value === 'inspection') {
|
||||||
|
inspectionDialog.selectedIds = selected.map((row: any) => row.id);
|
||||||
|
inspectionDialog.selectedCount = selected.length;
|
||||||
|
inspectionForm.isInspectionRequired = false;
|
||||||
|
inspectionDialog.visible = true;
|
||||||
|
} else if (batchActionType.value === 'warning') {
|
||||||
|
// 打开预警设置弹窗
|
||||||
|
warningDialog.selectedIds = selected.map((row: any) => row.id);
|
||||||
|
warningDialog.selectedCount = selected.length;
|
||||||
|
warningForm.isEnabled = false;
|
||||||
|
warningForm.redThreshold = undefined;
|
||||||
|
warningForm.yellowThreshold = undefined;
|
||||||
|
warningDialog.title = '批量设置预警';
|
||||||
|
warningDialog.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭批量模式
|
||||||
|
isBatchMode.value = false;
|
||||||
|
batchActionType.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 兼容旧的 exitBatchMode
|
||||||
|
const exitBatchMode = () => {
|
||||||
|
cancelBatchMode();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 预警设置相关
|
// 预警设置相关
|
||||||
@ -691,6 +764,17 @@ const warningRules = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 批量质检设置相关
|
||||||
|
const inspectionDialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
selectedCount: 0,
|
||||||
|
selectedIds: [] as number[]
|
||||||
|
});
|
||||||
|
const inspectionLoading = ref(false);
|
||||||
|
const inspectionForm = reactive({
|
||||||
|
isInspectionRequired: false
|
||||||
|
});
|
||||||
|
|
||||||
const columns = reactive({
|
const columns = reactive({
|
||||||
id: { visible: false },
|
id: { visible: false },
|
||||||
companyName: { visible: true },
|
companyName: { visible: true },
|
||||||
@ -703,7 +787,8 @@ const columns = reactive({
|
|||||||
inventory: { visible: true },
|
inventory: { visible: true },
|
||||||
available: { visible: true },
|
available: { visible: true },
|
||||||
files: { visible: true },
|
files: { visible: true },
|
||||||
isEnabled: { visible: true }
|
isEnabled: { visible: true },
|
||||||
|
isInspectionRequired: { visible: true }
|
||||||
});
|
});
|
||||||
|
|
||||||
// 列与权限Code的映射关系(数据库中的code)
|
// 列与权限Code的映射关系(数据库中的code)
|
||||||
@ -719,7 +804,8 @@ const permissionMap: Record<string, string> = {
|
|||||||
inventory: 'material_list:inventoryCount',
|
inventory: 'material_list:inventoryCount',
|
||||||
available: 'material_list:availableCount',
|
available: 'material_list:availableCount',
|
||||||
files: 'material_list:files',
|
files: 'material_list:files',
|
||||||
isEnabled: 'material_list:isEnabled'
|
isEnabled: 'material_list:isEnabled',
|
||||||
|
isInspectionRequired: 'material_list:operation'
|
||||||
};
|
};
|
||||||
|
|
||||||
// 根据用户权限初始化列显示状态
|
// 根据用户权限初始化列显示状态
|
||||||
@ -1174,26 +1260,6 @@ const handleDelete = (row: MaterialBaseVO) => {
|
|||||||
|
|
||||||
// --- 预警设置函数 ---
|
// --- 预警设置函数 ---
|
||||||
|
|
||||||
// 批量设置预警
|
|
||||||
const handleBatchSetWarning = () => {
|
|
||||||
if (selectedItems.value.length === 0) {
|
|
||||||
ElMessage.warning('请先勾选需要设置预警的物料');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用已选中的行
|
|
||||||
warningDialog.selectedIds = selectedItems.value.map((row: MaterialBaseVO) => row.id);
|
|
||||||
warningDialog.selectedCount = selectedItems.value.length;
|
|
||||||
|
|
||||||
// 重置表单
|
|
||||||
warningForm.isEnabled = false;
|
|
||||||
warningForm.redThreshold = undefined;
|
|
||||||
warningForm.yellowThreshold = undefined;
|
|
||||||
|
|
||||||
warningDialog.title = '批量设置预警';
|
|
||||||
warningDialog.visible = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 单条设置预警
|
// 单条设置预警
|
||||||
const handleSetSingleWarning = (row: MaterialBaseVO) => {
|
const handleSetSingleWarning = (row: MaterialBaseVO) => {
|
||||||
warningDialog.selectedIds = [row.id];
|
warningDialog.selectedIds = [row.id];
|
||||||
@ -1247,6 +1313,35 @@ const submitWarning = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 提交批量质检设置
|
||||||
|
const submitBatchInspection = async () => {
|
||||||
|
if (inspectionDialog.selectedIds.length === 0) {
|
||||||
|
ElMessage.warning('请先勾选物料');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inspectionLoading.value = true;
|
||||||
|
try {
|
||||||
|
await batchSetInspection({
|
||||||
|
ids: inspectionDialog.selectedIds,
|
||||||
|
isInspectionRequired: inspectionForm.isInspectionRequired
|
||||||
|
});
|
||||||
|
|
||||||
|
ElMessage.success('批量质检设置成功');
|
||||||
|
inspectionDialog.visible = false;
|
||||||
|
// 清理批量模式状态
|
||||||
|
isBatchMode.value = false;
|
||||||
|
batchActionType.value = '';
|
||||||
|
selectedItems.value = [];
|
||||||
|
tableRef.value?.clearSelection();
|
||||||
|
getList();
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.msg || '设置失败');
|
||||||
|
} finally {
|
||||||
|
inspectionLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 表格行样式(根据预警状态)
|
// 表格行样式(根据预警状态)
|
||||||
const tableRowClassName = ({ row }: { row: MaterialBaseVO }) => {
|
const tableRowClassName = ({ row }: { row: MaterialBaseVO }) => {
|
||||||
// 只有拥有 view_warning 权限且有预警状态时才显示特殊样式
|
// 只有拥有 view_warning 权限且有预警状态时才显示特殊样式
|
||||||
|
|||||||
@ -821,6 +821,10 @@ const printCopies = ref(1)
|
|||||||
|
|
||||||
const entryMode = ref('batch')
|
const entryMode = ref('batch')
|
||||||
const modeLocked = ref(false)
|
const modeLocked = ref(false)
|
||||||
|
|
||||||
|
// 强制质检标记
|
||||||
|
const isCurrentMaterialInspectionRequired = ref(false)
|
||||||
|
|
||||||
const dialogImageUrl = ref('')
|
const dialogImageUrl = ref('')
|
||||||
const dialogVisibleImage = ref(false)
|
const dialogVisibleImage = ref(false)
|
||||||
const arrivalFileList = ref<any[]>([])
|
const arrivalFileList = ref<any[]>([])
|
||||||
@ -1136,10 +1140,23 @@ const onMaterialSelected = (val: number) => {
|
|||||||
form.category = item.category
|
form.category = item.category
|
||||||
form.unit = item.unit
|
form.unit = item.unit
|
||||||
form.material_type = item.type
|
form.material_type = item.type
|
||||||
|
// 保存强制质检标记
|
||||||
|
isCurrentMaterialInspectionRequired.value = item.isInspectionRequired || false
|
||||||
|
// 更新表单校验规则
|
||||||
|
updateInspectionRules()
|
||||||
checkHistoryAndSetMode(item.id)
|
checkHistoryAndSetMode(item.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 动态更新质检相关校验规则
|
||||||
|
const updateInspectionRules = () => {
|
||||||
|
if (formRef.value) {
|
||||||
|
// 清除旧的校验结果
|
||||||
|
formRef.value.clearValidate('inspection_status')
|
||||||
|
formRef.value.clearValidate('inspection_report')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
// 校验规则
|
// 校验规则
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
@ -1159,12 +1176,41 @@ const validateIdentity = (rule: any, value: any, callback: any) => {
|
|||||||
else if (entryMode.value === 'batch' && !form.batch_number && rule.field === 'batch_number') callback(new Error('批号必填'))
|
else if (entryMode.value === 'batch' && !form.batch_number && rule.field === 'batch_number') callback(new Error('批号必填'))
|
||||||
else callback()
|
else callback()
|
||||||
}
|
}
|
||||||
const rules = {
|
const rules = computed(() => {
|
||||||
base_id: [{required: true, message: '请选择物料', trigger: 'change'}],
|
const baseRules = {
|
||||||
in_quantity: [{required: true, message: '请输入数量', trigger: 'blur'}],
|
base_id: [{required: true, message: '请选择物料', trigger: 'change'}],
|
||||||
serial_number: [{validator: validateIdentity, trigger: 'blur'}, {validator: validateUnique, trigger: 'blur'}],
|
in_quantity: [{required: true, message: '请输入数量', trigger: 'blur'}],
|
||||||
batch_number: [{validator: validateIdentity, trigger: 'blur'}, {validator: validateUnique, trigger: 'blur'}]
|
serial_number: [{validator: validateIdentity, trigger: 'blur'}, {validator: validateUnique, trigger: 'blur'}],
|
||||||
}
|
batch_number: [{validator: validateIdentity, trigger: 'blur'}, {validator: validateUnique, trigger: 'blur'}]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前物料需要强制质检,添加质检相关校验
|
||||||
|
if (isCurrentMaterialInspectionRequired.value) {
|
||||||
|
// 到检状态必填
|
||||||
|
baseRules.inspection_status = [
|
||||||
|
{ required: true, message: '该物料为强管控物料,必须选择到检状态', trigger: 'change' }
|
||||||
|
]
|
||||||
|
// 检测报告必填(通过自定义校验规则:文件或外部链接至少有一个)
|
||||||
|
baseRules.inspection_report = [
|
||||||
|
{
|
||||||
|
validator: (rule: any, value: any, callback: any) => {
|
||||||
|
// 过滤空字符串,只保留有效报告
|
||||||
|
const validFiles = (form.inspection_report || []).filter((r: string) => r && r.trim())
|
||||||
|
const hasFile = validFiles.length > 0
|
||||||
|
const hasLink = inspection_report_url.value && inspection_report_url.value.trim() !== ''
|
||||||
|
if (!hasFile && !hasLink) {
|
||||||
|
callback(new Error('该物料为强管控物料,必须提供检测报告文件或链接'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseRules
|
||||||
|
})
|
||||||
|
|
||||||
const checkHistoryAndSetMode = async (baseId: number) => {
|
const checkHistoryAndSetMode = async (baseId: number) => {
|
||||||
try {
|
try {
|
||||||
@ -1366,7 +1412,10 @@ const handleUpdate = (row: any) => {
|
|||||||
inspection_report_url.value = reportLinks.length > 0 ? reportLinks[0] : ''
|
inspection_report_url.value = reportLinks.length > 0 ? reportLinks[0] : ''
|
||||||
if (row.serial_number) { entryMode.value = 'serial'; form.serial_number = row.serial_number; form.batch_number = '' }
|
if (row.serial_number) { entryMode.value = 'serial'; form.serial_number = row.serial_number; form.batch_number = '' }
|
||||||
else { entryMode.value = 'batch'; form.batch_number = row.batch_number; form.serial_number = '' }
|
else { entryMode.value = 'batch'; form.batch_number = row.batch_number; form.serial_number = '' }
|
||||||
materialOptions.value = [{ id: row.base_id, name: row.material_name, spec: row.spec_model, category: row.category, company_name: row.company_name }]
|
materialOptions.value = [{ id: row.base_id, name: row.material_name, spec: row.spec_model, category: row.category, company_name: row.company_name, isInspectionRequired: row.isInspectionRequired }]
|
||||||
|
// 设置强制质检标记
|
||||||
|
isCurrentMaterialInspectionRequired.value = row.isInspectionRequired || false
|
||||||
|
updateInspectionRules()
|
||||||
visible.value = true
|
visible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1598,6 +1647,8 @@ const confirmPrint = async () => {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
materialOptions.value = []; arrivalFileList.value = []; reportFileList.value = []; inspection_report_url.value = ''
|
materialOptions.value = []; arrivalFileList.value = []; reportFileList.value = []; inspection_report_url.value = ''
|
||||||
searchPage.value = 1; hasNextPage.value = true; searchKeyword.value = '';
|
searchPage.value = 1; hasNextPage.value = true; searchKeyword.value = '';
|
||||||
|
// 重置强制质检标记
|
||||||
|
isCurrentMaterialInspectionRequired.value = false
|
||||||
Object.assign(form, {
|
Object.assign(form, {
|
||||||
id: undefined, base_id: undefined,
|
id: undefined, base_id: undefined,
|
||||||
company_name: '',
|
company_name: '',
|
||||||
|
|||||||
Reference in New Issue
Block a user