feat(borrow,outbound): 申请预检按需显示审批人——默认不显示,命中需审批才出现并必选
- 后端新增 /borrow/request/check-approval 与 /outbound/request/check-approval 预检接口 - 申请弹窗默认隐藏审批人;提交前预检:命中需审批→显示审批人并红字列物料、未选拦截;未命中→隐藏并直接提交(approver=null) - 申请 items 补传 base_id 供后端 ID 精确判定
This commit is contained in:
@ -429,6 +429,28 @@ def create_outbound_request():
|
|||||||
return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500
|
return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 4.1 出库申请预检(判断所选物料是否需审批,驱动前端是否显示审批人)
|
||||||
|
# POST /api/v1/outbound/request/check-approval
|
||||||
|
# --------------------------------------------------------
|
||||||
|
@outbound_bp.route('/request/check-approval', methods=['POST'])
|
||||||
|
@jwt_required()
|
||||||
|
@permission_required('outbound_selection')
|
||||||
|
def check_outbound_approval():
|
||||||
|
try:
|
||||||
|
data = request.get_json() or {}
|
||||||
|
items = data.get('items', []) or []
|
||||||
|
from app.services.approval_control import resolve_approval_control
|
||||||
|
need_approval, flagged = resolve_approval_control(items)
|
||||||
|
return jsonify({
|
||||||
|
"code": 200, "msg": "success",
|
||||||
|
"data": {"need_approval": need_approval, "materials": flagged}
|
||||||
|
}), 200
|
||||||
|
except Exception as e:
|
||||||
|
traceback.print_exc()
|
||||||
|
return jsonify({"code": 500, "msg": f"预检失败: {str(e)}"}), 500
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
# 5. 审批出库申请
|
# 5. 审批出库申请
|
||||||
# PATCH /api/v1/outbound/request/<id>/approve
|
# PATCH /api/v1/outbound/request/<id>/approve
|
||||||
|
|||||||
@ -311,6 +311,25 @@ def close_borrow_request(request_id):
|
|||||||
return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500
|
return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500
|
||||||
|
|
||||||
|
|
||||||
|
# --- 借库申请预检(判断所选物料是否需审批,驱动前端是否显示审批人) ---
|
||||||
|
@trans_bp.route('/borrow/request/check-approval', methods=['POST'])
|
||||||
|
@jwt_required()
|
||||||
|
@permission_required('op_borrow_apply')
|
||||||
|
def check_borrow_approval():
|
||||||
|
try:
|
||||||
|
data = request.get_json() or {}
|
||||||
|
items = data.get('items', []) or []
|
||||||
|
from app.services.approval_control import resolve_approval_control
|
||||||
|
need_approval, flagged = resolve_approval_control(items)
|
||||||
|
return jsonify({
|
||||||
|
"code": 200, "msg": "success",
|
||||||
|
"data": {"need_approval": need_approval, "materials": flagged}
|
||||||
|
}), 200
|
||||||
|
except Exception as e:
|
||||||
|
import traceback; traceback.print_exc()
|
||||||
|
return jsonify({"code": 500, "msg": f"预检失败: {str(e)}"}), 500
|
||||||
|
|
||||||
|
|
||||||
# --- 获取借库审批单列表 ---
|
# --- 获取借库审批单列表 ---
|
||||||
@trans_bp.route('/borrow/request', methods=['GET'])
|
@trans_bp.route('/borrow/request', methods=['GET'])
|
||||||
@jwt_required()
|
@jwt_required()
|
||||||
|
|||||||
@ -99,6 +99,15 @@ export function submitOutboundRequest(data: {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 出库申请预检:判断所选物料是否需审批
|
||||||
|
export function checkOutboundApproval(data: { items: Array<{ name?: string; spec_model?: string }> }) {
|
||||||
|
return request({
|
||||||
|
url: '/v1/outbound/request/check-approval',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取出库审批申请单列表
|
* 获取出库审批申请单列表
|
||||||
* @param params 支持 status, page, limit
|
* @param params 支持 status, page, limit
|
||||||
|
|||||||
@ -149,6 +149,15 @@ export function submitBorrowRequest(data: {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 借库申请预检:判断所选物料是否需审批
|
||||||
|
export function checkBorrowApproval(data: { items: Array<{ name?: string; spec_model?: string }> }) {
|
||||||
|
return request({
|
||||||
|
url: '/v1/transactions/borrow/request/check-approval',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取借库审批申请单列表
|
* 获取借库审批申请单列表
|
||||||
* @param params 支持 status, page, limit
|
* @param params 支持 status, page, limit
|
||||||
|
|||||||
@ -394,7 +394,10 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<el-form label-width="100px">
|
<el-form label-width="100px">
|
||||||
<el-form-item label="* 指定审批人" required>
|
<el-form-item v-if="approvalNeedVisible" label="指定审批人">
|
||||||
|
<div v-if="approvalNeedText" style="color:#E6A23C; font-size:12px; line-height:1.4; margin-bottom:4px;">
|
||||||
|
以下物料需审批出库/借库:{{ approvalNeedText }},请选择审批人
|
||||||
|
</div>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="requestApproverId"
|
v-model="requestApproverId"
|
||||||
placeholder="请选择审批人"
|
placeholder="请选择审批人"
|
||||||
@ -518,7 +521,7 @@ import { Printer, Search, Plus, Download, List } from '@element-plus/icons-vue'
|
|||||||
import { ElMessage, ElTable, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElTable, ElMessageBox } from 'element-plus'
|
||||||
import { printSelectionList } from '@/api/inbound/stock'
|
import { printSelectionList } from '@/api/inbound/stock'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
import { submitBorrowRequest, getBorrowStockList } from '@/api/transaction'
|
import { submitBorrowRequest, getBorrowStockList, checkBorrowApproval } from '@/api/transaction'
|
||||||
import { bomMatchStock } from '@/api/outbound'
|
import { bomMatchStock } from '@/api/outbound'
|
||||||
import { getApproversList } from '@/api/auth'
|
import { getApproversList } from '@/api/auth'
|
||||||
import { getBomList, getBomDetail, getBomWithStock } from '@/api/bom'
|
import { getBomList, getBomDetail, getBomWithStock } from '@/api/bom'
|
||||||
@ -554,6 +557,9 @@ const requestIndefinite = ref(false)
|
|||||||
const requestApproverId = ref<number | null>(null)
|
const requestApproverId = ref<number | null>(null)
|
||||||
const approvers = ref<any[]>([])
|
const approvers = ref<any[]>([])
|
||||||
const requestSubmitting = ref(false)
|
const requestSubmitting = ref(false)
|
||||||
|
// 是否需审批(由提交前预检驱动,需审批才显示审批人输入框)
|
||||||
|
const approvalNeedVisible = ref(false)
|
||||||
|
const approvalNeedText = ref('')
|
||||||
|
|
||||||
const stockList = ref<any[]>([])
|
const stockList = ref<any[]>([])
|
||||||
const stockTotal = ref(0)
|
const stockTotal = ref(0)
|
||||||
@ -1052,6 +1058,8 @@ const openRequestDialog = () => {
|
|||||||
requestApproverId.value = null
|
requestApproverId.value = null
|
||||||
requestExpectedReturn.value = ''
|
requestExpectedReturn.value = ''
|
||||||
requestIndefinite.value = false
|
requestIndefinite.value = false
|
||||||
|
approvalNeedVisible.value = false // 打开时默认隐藏审批人,命中需审批时由预检显示
|
||||||
|
approvalNeedText.value = ''
|
||||||
loadApprovers()
|
loadApprovers()
|
||||||
requestDialogVisible.value = true
|
requestDialogVisible.value = true
|
||||||
}
|
}
|
||||||
@ -1096,23 +1104,44 @@ const buildRemarkWithShortage = (baseRemark: string): string => {
|
|||||||
const confirmSubmitRequest = async () => {
|
const confirmSubmitRequest = async () => {
|
||||||
requestSubmitting.value = true
|
requestSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
|
const items = validSelectedItems.value.map((item: any) => ({
|
||||||
|
base_id: item.base_id ?? null,
|
||||||
|
name: item.name || '',
|
||||||
|
spec_model: item.standard || '',
|
||||||
|
warehouse_location: item.warehouse_location || '',
|
||||||
|
quantity: item.export_quantity || 0,
|
||||||
|
expected_return_time: requestIndefinite.value ? null : requestExpectedReturn.value,
|
||||||
|
is_indefinite: requestIndefinite.value
|
||||||
|
}))
|
||||||
|
|
||||||
|
// ★ 提交前预检:判断所选物料是否需审批 → 只有需审批才显示并必选审批人
|
||||||
|
let needApproval = false
|
||||||
|
let flagged: any[] = []
|
||||||
|
try {
|
||||||
|
const chk: any = await checkBorrowApproval({ items })
|
||||||
|
needApproval = !!chk?.data?.need_approval
|
||||||
|
flagged = chk?.data?.materials || []
|
||||||
|
} catch (e) { needApproval = false; flagged = [] }
|
||||||
|
approvalNeedVisible.value = needApproval
|
||||||
|
approvalNeedText.value = flagged.map((m: any) => `${m.name}(${m.spec_model || '-'})`).join(';')
|
||||||
|
|
||||||
|
if (needApproval && !requestApproverId.value) {
|
||||||
|
ElMessage.warning(`以下物料需审批出库/借库:${approvalNeedText.value}。请先选择审批人`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
items: validSelectedItems.value.map((item: any) => ({
|
items,
|
||||||
name: item.name || '',
|
|
||||||
spec_model: item.standard || '',
|
|
||||||
warehouse_location: item.warehouse_location || '',
|
|
||||||
quantity: item.export_quantity || 0,
|
|
||||||
expected_return_time: requestIndefinite.value ? null : requestExpectedReturn.value,
|
|
||||||
is_indefinite: requestIndefinite.value
|
|
||||||
})),
|
|
||||||
remark: buildRemarkWithShortage(requestRemark.value.trim()),
|
remark: buildRemarkWithShortage(requestRemark.value.trim()),
|
||||||
approver_id: requestApproverId.value
|
approver_id: needApproval ? requestApproverId.value : null
|
||||||
}
|
}
|
||||||
|
|
||||||
await submitBorrowRequest(payload)
|
await submitBorrowRequest(payload)
|
||||||
|
|
||||||
requestDialogVisible.value = false
|
requestDialogVisible.value = false
|
||||||
selectedItems.value = []
|
selectedItems.value = []
|
||||||
|
approvalNeedVisible.value = false
|
||||||
|
approvalNeedText.value = ''
|
||||||
ElMessage.success('借库申请已提交(含需审批物料时将进入审批,否则直接交库管执行)')
|
ElMessage.success('借库申请已提交(含需审批物料时将进入审批,否则直接交库管执行)')
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
ElMessage.error(err?.message || err?.msg || '提交申请失败,请重试')
|
ElMessage.error(err?.message || err?.msg || '提交申请失败,请重试')
|
||||||
|
|||||||
@ -409,7 +409,10 @@
|
|||||||
<el-option label="维修出库" value="REPAIR" />
|
<el-option label="维修出库" value="REPAIR" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="* 指定审批人" required>
|
<el-form-item v-if="approvalNeedVisible" label="指定审批人">
|
||||||
|
<div v-if="approvalNeedText" style="color:#E6A23C; font-size:12px; line-height:1.4; margin-bottom:4px;">
|
||||||
|
以下物料需审批出库/借库:{{ approvalNeedText }},请选择审批人
|
||||||
|
</div>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="requestApproverId"
|
v-model="requestApproverId"
|
||||||
placeholder="请选择审批人"
|
placeholder="请选择审批人"
|
||||||
@ -519,7 +522,7 @@ import { ElMessage, ElTable, ElMessageBox } from 'element-plus'
|
|||||||
import { getStockList, printSelectionList } from '@/api/inbound/stock'
|
import { getStockList, printSelectionList } from '@/api/inbound/stock'
|
||||||
import { getBomList, getBomDetail, getBomWithStock } from '@/api/bom'
|
import { getBomList, getBomDetail, getBomWithStock } from '@/api/bom'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
import { submitOutboundRequest, bomMatchStock } from '@/api/outbound'
|
import { submitOutboundRequest, bomMatchStock, checkOutboundApproval } from '@/api/outbound'
|
||||||
import { getApproversList } from '@/api/auth'
|
import { getApproversList } from '@/api/auth'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
@ -551,6 +554,9 @@ const requestOutboundType = ref('') // 申请时必选出库类型,扫码出
|
|||||||
const requestApproverId = ref<number | null>(null)
|
const requestApproverId = ref<number | null>(null)
|
||||||
const approvers = ref<any[]>([])
|
const approvers = ref<any[]>([])
|
||||||
const requestSubmitting = ref(false)
|
const requestSubmitting = ref(false)
|
||||||
|
// 是否需审批(由提交前预检驱动,需审批才显示审批人输入框)
|
||||||
|
const approvalNeedVisible = ref(false)
|
||||||
|
const approvalNeedText = ref('')
|
||||||
|
|
||||||
const stockList = ref<any[]>([]) // 服务端分页数据
|
const stockList = ref<any[]>([]) // 服务端分页数据
|
||||||
const stockTotal = ref(0)
|
const stockTotal = ref(0)
|
||||||
@ -1079,6 +1085,8 @@ const openRequestDialog = () => {
|
|||||||
}
|
}
|
||||||
requestRemark.value = ''
|
requestRemark.value = ''
|
||||||
requestApproverId.value = null
|
requestApproverId.value = null
|
||||||
|
approvalNeedVisible.value = false // 打开时默认隐藏审批人,命中需审批时由预检显示
|
||||||
|
approvalNeedText.value = ''
|
||||||
loadApprovers()
|
loadApprovers()
|
||||||
requestDialogVisible.value = true
|
requestDialogVisible.value = true
|
||||||
}
|
}
|
||||||
@ -1100,7 +1108,6 @@ const confirmSubmitRequest = async () => {
|
|||||||
ElMessage.warning('请填写申请原因')
|
ElMessage.warning('请填写申请原因')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 审批人改为可选:默认不审批时无需选择;所选物料命中“需审批”但未选审批人时,后端会提示补选
|
|
||||||
if (!requestOutboundType.value) {
|
if (!requestOutboundType.value) {
|
||||||
ElMessage.warning('请选择出库类型')
|
ElMessage.warning('请选择出库类型')
|
||||||
return
|
return
|
||||||
@ -1108,17 +1115,36 @@ const confirmSubmitRequest = async () => {
|
|||||||
|
|
||||||
requestSubmitting.value = true
|
requestSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
|
const items = validSelectedItems.value.map(item => ({
|
||||||
|
material_type: item.typeLabel || item.type || '',
|
||||||
|
base_id: item.base_id ?? null,
|
||||||
|
name: item.name || '',
|
||||||
|
spec_model: item.standard || '',
|
||||||
|
warehouse_location: item.warehouse_location || '',
|
||||||
|
quantity: item.export_quantity || 0
|
||||||
|
}))
|
||||||
|
|
||||||
|
// ★ 提交前预检:判断所选物料是否需审批 → 只有需审批才显示并必选审批人
|
||||||
|
let needApproval = false
|
||||||
|
let flagged: any[] = []
|
||||||
|
try {
|
||||||
|
const chk: any = await checkOutboundApproval({ items })
|
||||||
|
needApproval = !!chk?.data?.need_approval
|
||||||
|
flagged = chk?.data?.materials || []
|
||||||
|
} catch (e) { needApproval = false; flagged = [] }
|
||||||
|
approvalNeedVisible.value = needApproval
|
||||||
|
approvalNeedText.value = flagged.map((m: any) => `${m.name}(${m.spec_model || '-'})`).join(';')
|
||||||
|
|
||||||
|
if (needApproval && !requestApproverId.value) {
|
||||||
|
ElMessage.warning(`以下物料需审批出库/借库:${approvalNeedText.value}。请先选择审批人`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const payload: any = {
|
const payload: any = {
|
||||||
items: validSelectedItems.value.map(item => ({
|
items,
|
||||||
material_type: item.typeLabel || item.type || '',
|
|
||||||
name: item.name || '',
|
|
||||||
spec_model: item.standard || '',
|
|
||||||
warehouse_location: item.warehouse_location || '',
|
|
||||||
quantity: item.export_quantity || 0
|
|
||||||
})),
|
|
||||||
remark: buildRemarkWithShortage(trimmed),
|
remark: buildRemarkWithShortage(trimmed),
|
||||||
outbound_type: requestOutboundType.value,
|
outbound_type: requestOutboundType.value,
|
||||||
approver_id: requestApproverId.value
|
approver_id: needApproval ? requestApproverId.value : null
|
||||||
}
|
}
|
||||||
|
|
||||||
await submitOutboundRequest(payload)
|
await submitOutboundRequest(payload)
|
||||||
@ -1126,6 +1152,8 @@ const confirmSubmitRequest = async () => {
|
|||||||
// 成功:关闭弹窗、清空列表、提示
|
// 成功:关闭弹窗、清空列表、提示
|
||||||
requestDialogVisible.value = false
|
requestDialogVisible.value = false
|
||||||
selectedItems.value = []
|
selectedItems.value = []
|
||||||
|
approvalNeedVisible.value = false
|
||||||
|
approvalNeedText.value = ''
|
||||||
ElMessage.success('出库申请已提交(含需审批物料时将进入审批,否则直接交库管执行)')
|
ElMessage.success('出库申请已提交(含需审批物料时将进入审批,否则直接交库管执行)')
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
ElMessage.error(err?.message || err?.msg || '提交申请失败,请重试')
|
ElMessage.error(err?.message || err?.msg || '提交申请失败,请重试')
|
||||||
|
|||||||
Reference in New Issue
Block a user