Compare commits
13 Commits
0daf50ac21
...
859d783b5c
| Author | SHA1 | Date | |
|---|---|---|---|
| 859d783b5c | |||
| 478b90fe50 | |||
| eaafeaf24e | |||
| 73510d3a71 | |||
| b274ed1ed1 | |||
| 02f36b383c | |||
| 808e491fe8 | |||
| b40aa3ab90 | |||
| 2f6027b43c | |||
| b6ecde11dd | |||
| 7e3fc11bf5 | |||
| bc6e97ae97 | |||
| 3bd19c1ab5 |
@ -103,7 +103,16 @@ def get_list():
|
||||
# 字段级脱敏
|
||||
user_permissions = get_current_user_permissions()
|
||||
if result.get('items'):
|
||||
result['items'] = [filter_item_by_permissions(item, user_permissions) for item in result['items']]
|
||||
# ★ 字段权限过滤会剥离 base_id,但前端扫码/选物料联动需要它匹配历史批号(自动叠加)
|
||||
# 在过滤前保留 base_id,过滤后补回(非敏感字段,仅物料关联 ID,与 semi 列表一致)
|
||||
restored = []
|
||||
for item in result['items']:
|
||||
base_id = item.get('base_id')
|
||||
filtered = filter_item_by_permissions(item, user_permissions)
|
||||
if base_id is not None:
|
||||
filtered['base_id'] = base_id
|
||||
restored.append(filtered)
|
||||
result['items'] = restored
|
||||
return jsonify({"code": 200, "msg": "success", "data": result})
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
|
||||
@ -293,11 +293,17 @@ def _do_get_stock_list(permission_prefix=None):
|
||||
# ★ Fail-Closed: 选单/借用场景默认剥离所有价格成本字段
|
||||
_strip_price_fields = _make_price_stripper(permission_prefix)
|
||||
|
||||
# ★ 行级公司隔离:普通用户只能看到本公司的库存(超管/跨域不受限)
|
||||
from app.utils.decorators import get_current_company_filter
|
||||
company_limit = get_current_company_filter()
|
||||
|
||||
all_items = []
|
||||
|
||||
# 1. 采购件
|
||||
if StockBuy:
|
||||
q = StockBuy.query.filter(StockBuy.stock_quantity > 0)
|
||||
if company_limit is not None:
|
||||
q = q.filter(StockBuy.base.has(MaterialBase.company_name == company_limit))
|
||||
if keyword:
|
||||
q = q.filter(
|
||||
db.or_(
|
||||
@ -322,6 +328,8 @@ def _do_get_stock_list(permission_prefix=None):
|
||||
if StockSemi:
|
||||
try:
|
||||
q = StockSemi.query.filter(StockSemi.stock_quantity > 0)
|
||||
if company_limit is not None:
|
||||
q = q.filter(StockSemi.base.has(MaterialBase.company_name == company_limit))
|
||||
if keyword:
|
||||
q = q.filter(
|
||||
db.or_(
|
||||
@ -347,6 +355,8 @@ def _do_get_stock_list(permission_prefix=None):
|
||||
# 3. 成品
|
||||
if StockProduct:
|
||||
q = StockProduct.query.filter(StockProduct.stock_quantity > 0)
|
||||
if company_limit is not None:
|
||||
q = q.filter(StockProduct.base.has(MaterialBase.company_name == company_limit))
|
||||
if keyword:
|
||||
q = q.filter(
|
||||
db.or_(
|
||||
|
||||
@ -215,6 +215,11 @@ def bom_match_stock():
|
||||
# 去重
|
||||
child_ids = list(set(int(x) for x in child_ids))
|
||||
|
||||
# ★ 行级公司隔离:普通用户只能匹配本公司的库存(超管/跨域不受限)
|
||||
from app.utils.decorators import get_current_company_filter
|
||||
from app.models.base import MaterialBase
|
||||
company_limit = get_current_company_filter()
|
||||
|
||||
from app.models.inbound.buy import StockBuy
|
||||
from app.models.inbound.semi import StockSemi
|
||||
from app.models.inbound.product import StockProduct
|
||||
@ -226,7 +231,10 @@ def bom_match_stock():
|
||||
buy_items = StockBuy.query.filter(
|
||||
StockBuy.base_id.in_(child_ids),
|
||||
StockBuy.stock_quantity > 0
|
||||
).options(joinedload(StockBuy.base)).all()
|
||||
)
|
||||
if company_limit is not None:
|
||||
buy_items = buy_items.filter(StockBuy.base.has(MaterialBase.company_name == company_limit))
|
||||
buy_items = buy_items.options(joinedload(StockBuy.base)).all()
|
||||
for s in buy_items:
|
||||
d = s.to_dict()
|
||||
d['type'] = 'material'
|
||||
@ -242,7 +250,10 @@ def bom_match_stock():
|
||||
semi_items = StockSemi.query.filter(
|
||||
StockSemi.base_id.in_(child_ids),
|
||||
StockSemi.stock_quantity > 0
|
||||
).options(joinedload(StockSemi.base)).all()
|
||||
)
|
||||
if company_limit is not None:
|
||||
semi_items = semi_items.filter(StockSemi.base.has(MaterialBase.company_name == company_limit))
|
||||
semi_items = semi_items.options(joinedload(StockSemi.base)).all()
|
||||
for s in semi_items:
|
||||
d = s.to_dict()
|
||||
d['type'] = 'semi'
|
||||
@ -260,7 +271,10 @@ def bom_match_stock():
|
||||
prod_items = StockProduct.query.filter(
|
||||
StockProduct.base_id.in_(child_ids),
|
||||
StockProduct.stock_quantity > 0
|
||||
).options(joinedload(StockProduct.base)).all()
|
||||
)
|
||||
if company_limit is not None:
|
||||
prod_items = prod_items.filter(StockProduct.base.has(MaterialBase.company_name == company_limit))
|
||||
prod_items = prod_items.options(joinedload(StockProduct.base)).all()
|
||||
for s in prod_items:
|
||||
d = s.to_dict()
|
||||
d['type'] = 'product'
|
||||
@ -398,7 +412,8 @@ def create_outbound_request():
|
||||
items=items,
|
||||
allowed_approvers=allowed_approvers,
|
||||
remark=data.get('remark'),
|
||||
approver_id=approver_id
|
||||
approver_id=approver_id,
|
||||
outbound_type=data.get('outbound_type') # 出库类型(申请时确定)
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
|
||||
@ -41,6 +41,16 @@ def get_current_user_info():
|
||||
return user.id if user else None, user.role if user else None
|
||||
|
||||
|
||||
def _current_username():
|
||||
"""获取当前登录用户的用户名(姓名/账号),用于操作人展示;避免把 JWT 数字 ID 存进记录"""
|
||||
identity = get_jwt_identity()
|
||||
if not identity:
|
||||
return 'System'
|
||||
from app.models.system import SysUser
|
||||
user = SysUser.query.get(identity)
|
||||
return user.username if user else str(identity)
|
||||
|
||||
|
||||
def filter_item_by_permissions(item_dict, user_permissions, prefix='op_records'):
|
||||
"""
|
||||
根据用户权限过滤 item 字典,无权限的字段值置为 None
|
||||
@ -102,9 +112,10 @@ def scan_borrowed_item():
|
||||
)
|
||||
def submit_return():
|
||||
data = request.get_json()
|
||||
user = get_jwt_identity() # 库管
|
||||
# ★ 归还人存"姓名",而非 JWT 数字 ID
|
||||
operator_name = _current_username()
|
||||
try:
|
||||
TransService.process_return(data, operator_name=user)
|
||||
TransService.process_return(data, operator_name=operator_name)
|
||||
return jsonify({'code': 200, 'msg': '还库成功'})
|
||||
except Exception as e:
|
||||
return jsonify({'code': 400, 'msg': str(e)}), 400
|
||||
@ -131,9 +142,9 @@ def scrap_borrow():
|
||||
if not record_ids:
|
||||
return jsonify({'code': 400, 'msg': '请选择要报废的借出记录'}), 400
|
||||
|
||||
user = get_jwt_identity() or 'Unknown'
|
||||
operator_name = _current_username() or 'Unknown'
|
||||
try:
|
||||
result = TransService.scrap_borrow(record_ids, operator_name=user, reason=reason)
|
||||
result = TransService.scrap_borrow(record_ids, operator_name=operator_name, reason=reason)
|
||||
return jsonify({'code': 200, 'msg': f'已报废 {result["count"]} 条借出记录', 'data': result})
|
||||
except ValueError as e:
|
||||
return jsonify({'code': 400, 'msg': str(e)}), 400
|
||||
@ -277,6 +288,29 @@ def approve_borrow_request(request_id):
|
||||
return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500
|
||||
|
||||
|
||||
@trans_bp.route('/borrow/request/<int:request_id>/close', methods=['POST'])
|
||||
@jwt_required()
|
||||
@permission_required('op_borrow_approval')
|
||||
def close_borrow_request(request_id):
|
||||
"""
|
||||
手动完结已通过的借库审批单(status 1-已通过 → 3-已完成)
|
||||
参照出库审批的完结逻辑,供库管/主管在未走扫码借出时强制完结
|
||||
"""
|
||||
try:
|
||||
user_id, _ = get_current_user_info()
|
||||
if not user_id:
|
||||
return jsonify({'code': 401, 'msg': '用户未登录'}), 401
|
||||
|
||||
success, message, approval = BorrowApprovalService.mark_completed(request_id)
|
||||
if not success:
|
||||
return jsonify({'code': 400, 'msg': message}), 400
|
||||
|
||||
return jsonify({'code': 200, 'msg': message, 'data': approval.to_dict() if approval else None}), 200
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500
|
||||
|
||||
|
||||
# --- 获取借库审批单列表 ---
|
||||
@trans_bp.route('/borrow/request', methods=['GET'])
|
||||
@jwt_required()
|
||||
@ -351,7 +385,7 @@ def dispatch_borrow():
|
||||
borrow_no = TransService.execute_dispatch(
|
||||
approval_id=approval_id,
|
||||
items=data.get('items', []),
|
||||
operator_name=get_jwt_identity(),
|
||||
operator_name=_current_username(),
|
||||
borrower_name=data.get('borrower_name'),
|
||||
signature=data.get('signature_path'),
|
||||
remark=data.get('remark'),
|
||||
|
||||
@ -10,23 +10,25 @@ warehouse_bp = Blueprint('warehouse', __name__, url_prefix='/api/v1/warehouse')
|
||||
|
||||
def build_tree(nodes, parent_id=None):
|
||||
"""
|
||||
将平铺的数据构建为树形结构
|
||||
将平铺的数据构建为树形结构(O(N) 内存组装,避免递归时每层全量扫描导致 O(N²))
|
||||
|
||||
做法:先把全部节点按 parent_id 分组到 Map,再从根出发逐层用 Map 取子节点组装。
|
||||
每个节点只被处理一次,显著快于"每次递归 for 遍历全表"的旧实现。
|
||||
"""
|
||||
tree = []
|
||||
by_parent = {}
|
||||
for node in nodes:
|
||||
if node.parent_id == parent_id:
|
||||
children = build_tree(nodes, node.id)
|
||||
node_dict = node.to_dict()
|
||||
if children:
|
||||
# 子节点按 name 升序排序
|
||||
children_sorted = sorted(children, key=lambda x: x.get('name', ''))
|
||||
node_dict['children'] = children_sorted
|
||||
else:
|
||||
node_dict['children'] = []
|
||||
tree.append(node_dict)
|
||||
# 当前层级按 name 升序排序
|
||||
tree_sorted = sorted(tree, key=lambda x: x.get('name', ''))
|
||||
return tree_sorted
|
||||
by_parent.setdefault(node.parent_id, []).append(node)
|
||||
|
||||
def assemble(pid):
|
||||
kids = sorted(by_parent.get(pid, []), key=lambda x: (x.name or ''))
|
||||
out = []
|
||||
for k in kids:
|
||||
d = k.to_dict()
|
||||
d['children'] = assemble(k.id)
|
||||
out.append(d)
|
||||
return out
|
||||
|
||||
return assemble(parent_id)
|
||||
|
||||
|
||||
@warehouse_bp.route('/tree', methods=['GET'])
|
||||
@ -38,9 +40,9 @@ def get_tree():
|
||||
# 查询所有库位,按 name 升序排序
|
||||
all_locations = SysWarehouseLocation.query.order_by(SysWarehouseLocation.name.asc()).all()
|
||||
|
||||
# 构建树形结构
|
||||
# 构建树形结构(O(N) 内存组装,见 build_tree)
|
||||
tree_data = build_tree(all_locations, parent_id=None)
|
||||
|
||||
|
||||
return jsonify({
|
||||
'code': 200,
|
||||
'msg': 'success',
|
||||
|
||||
@ -18,6 +18,8 @@ class OutboundApproval(db.Model):
|
||||
applicant_id = db.Column(db.Integer, nullable=False, index=True)
|
||||
# 申请说明
|
||||
remark = db.Column(db.Text)
|
||||
# 出库类型:SALES/USE/PRODUCTION/LOSS/REPAIR(申请时确定,扫码出库自动带出)
|
||||
outbound_type = db.Column(db.String(50))
|
||||
# 状态: 0-待审批, 1-已通过, 2-已驳回, 3-已完成(已出库)
|
||||
status = db.Column(db.Integer, default=0, nullable=False)
|
||||
# 允许审批的人员列表 (JSON格式: [{"type": "role", "value": "admin"}, {"type": "user", "value": "123"}])
|
||||
@ -81,6 +83,7 @@ class OutboundApproval(db.Model):
|
||||
'applicant_id': self.applicant_id,
|
||||
'applicant_name': self._get_user_name(self.applicant_id),
|
||||
'remark': self.remark,
|
||||
'outbound_type': self.outbound_type or '',
|
||||
'status': self.status,
|
||||
'status_text': ['待审批', '已通过', '已驳回', '已完成', '已完结'][self.status] if self.status in [0, 1, 2, 3, 4] else '未知',
|
||||
'allowed_approvers': self.get_allowed_approvers(),
|
||||
|
||||
@ -1,6 +1,26 @@
|
||||
from app.extensions import db, beijing_time
|
||||
from datetime import datetime
|
||||
from sqlalchemy import func
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
@lru_cache(maxsize=512)
|
||||
def _borrow_user_name(uid):
|
||||
"""按用户 ID 取用户名(带缓存,避免列表页 N+1)"""
|
||||
try:
|
||||
from app.models.system import SysUser
|
||||
u = SysUser.query.get(uid)
|
||||
return u.username if u else None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _display_borrow_operator(op):
|
||||
"""归还人展示映射:历史存的是数字 user id → 映射为用户名;新数据存姓名则原样返回"""
|
||||
if op and str(op).strip().isdigit():
|
||||
mapped = _borrow_user_name(int(op))
|
||||
return mapped if mapped else op
|
||||
return op
|
||||
|
||||
|
||||
class TransBorrow(db.Model):
|
||||
@ -48,7 +68,7 @@ class TransBorrow(db.Model):
|
||||
'expected_return_time': self.expected_return_time.strftime('%Y-%m-%d %H:%M') if self.expected_return_time else None,
|
||||
'is_returned': self.is_returned,
|
||||
'return_time': self.return_time.strftime('%Y-%m-%d %H:%M') if self.return_time else None,
|
||||
'return_operator': self.return_operator,
|
||||
'return_operator': _display_borrow_operator(self.return_operator),
|
||||
'return_signature': self.return_signature,
|
||||
'return_location': self.return_location,
|
||||
'location': self.location or '',
|
||||
|
||||
@ -701,7 +701,7 @@ class OutboundApprovalService:
|
||||
return f"APR-OUT-{date_str}-{time_str}-{sequence:04d}"
|
||||
|
||||
@staticmethod
|
||||
def create_request(applicant_id, items, allowed_approvers, remark=None, approver_id=None):
|
||||
def create_request(applicant_id, items, allowed_approvers, remark=None, approver_id=None, outbound_type=None):
|
||||
"""
|
||||
创建出库审批单(申请阶段,直接存储前端传来的物料信息快照,不关联具体库存记录)
|
||||
|
||||
@ -759,6 +759,7 @@ class OutboundApprovalService:
|
||||
request_no=request_no,
|
||||
applicant_id=applicant_id,
|
||||
remark=remark,
|
||||
outbound_type=outbound_type, # 申请时确定的出库类型,扫码出库时带出
|
||||
status=0, # 待审批
|
||||
)
|
||||
|
||||
|
||||
@ -434,7 +434,12 @@ class TransService:
|
||||
order_subq = (
|
||||
db.session.query(
|
||||
TransBorrow.borrow_no.label('borrow_no'),
|
||||
func.min(TransBorrow.expected_return_time).label('sort_key')
|
||||
# 有限期梯队内:单号内最早预计归还时间
|
||||
func.min(TransBorrow.expected_return_time).label('sort_key'),
|
||||
# 无限期梯队内:单号内最早借出时间(呆滞借用盘点)
|
||||
func.min(TransBorrow.borrow_time).label('min_borrow_time'),
|
||||
# 单内是否含"有限期"明细:任一 expected_return_time 非空 → 1(有限期单排前)
|
||||
func.max(case((TransBorrow.expected_return_time.isnot(None), 1), else_=0)).label('has_finite')
|
||||
)
|
||||
.group_by(TransBorrow.borrow_no)
|
||||
.subquery()
|
||||
@ -673,8 +678,15 @@ class TransService:
|
||||
)
|
||||
)
|
||||
|
||||
# 排序(单号维度的 sort_key ASC)
|
||||
borrow_no_q = borrow_no_q.order_by(nullslast(asc(order_subq.c.sort_key)))
|
||||
# ★ 默认排序(多级复合,符合"优先关注快到期/逾期"业务):
|
||||
# 1) 有限期单(含 expected_return_time)排前,无限期单排后
|
||||
# 2) 有限期内按最早预计归还时间 ASC(越快到期/逾期越久越靠前)
|
||||
# 3) 无限期内按最早借出时间 ASC(借出越久越靠前,暴露长期未还的呆滞借用)
|
||||
borrow_no_q = borrow_no_q.order_by(
|
||||
case((order_subq.c.has_finite == 0, 1), else_=0).asc(),
|
||||
nullslast(asc(order_subq.c.sort_key)),
|
||||
asc(order_subq.c.min_borrow_time)
|
||||
)
|
||||
|
||||
# 分页(基准 = borrow_no 单号数)
|
||||
pagination = borrow_no_q.paginate(page=page, per_page=limit, error_out=False)
|
||||
|
||||
@ -239,7 +239,7 @@ const handleLogout = () => {
|
||||
<footer v-if="!isLoginPage" class="app-footer">
|
||||
<span class="version-tag">
|
||||
<el-icon style="vertical-align: middle; margin-right: 4px"><InfoFilled /></el-icon>
|
||||
当前版本:V3.71
|
||||
当前版本:V3.72
|
||||
</span>
|
||||
</footer>
|
||||
|
||||
|
||||
@ -174,6 +174,14 @@ export function approveBorrowRequest(id: number, data: { action: 'approve' | 're
|
||||
})
|
||||
}
|
||||
|
||||
// 手动完结已通过的借库审批单(status 1 → 3)
|
||||
export function closeBorrowRequest(id: number) {
|
||||
return request({
|
||||
url: `/v1/transactions/borrow/request/${id}/close`,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 借库选单专用库存列表(独立权限 op_borrow_apply)
|
||||
*/
|
||||
|
||||
@ -137,6 +137,19 @@
|
||||
驳回
|
||||
</el-button>
|
||||
</template>
|
||||
<!-- ★ 已通过的申请单:库管/主管可手动完结 -->
|
||||
<template v-else-if="row.status === 1">
|
||||
<el-button
|
||||
v-if="canCompleteRequest"
|
||||
type="danger"
|
||||
plain
|
||||
size="small"
|
||||
:loading="row._closing"
|
||||
@click="handleComplete(row)"
|
||||
>
|
||||
完结
|
||||
</el-button>
|
||||
</template>
|
||||
<span v-else style="color: #c0c4cc;">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -182,14 +195,44 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { Refresh, Warning } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getBorrowApprovalList, approveBorrowRequest } from '@/api/transaction'
|
||||
import { getBorrowApprovalList, approveBorrowRequest, closeBorrowRequest } from '@/api/transaction'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// ★ 完结权限:超管 / 审批操作(op_borrow_approval:operation) / 借库执行(op_borrow:operation)
|
||||
const canCompleteRequest = computed(() =>
|
||||
userStore.role === 'SUPER_ADMIN' ||
|
||||
userStore.hasPermission('op_borrow_approval:operation') ||
|
||||
userStore.hasPermission('op_borrow:operation') ||
|
||||
userStore.username === 'IRIS'
|
||||
)
|
||||
|
||||
// ★ 手动完结已通过的借库审批单(status 1 → 3,仿出库审批)
|
||||
const handleComplete = (row: any) => {
|
||||
ElMessageBox.confirm(
|
||||
`确定强制完结审批单【${row.request_no}】吗?\n\n完结后该单标记为「已完成」,不可再扫码借出。`,
|
||||
'⚠️ 强制完结确认',
|
||||
{ confirmButtonText: '确认完结', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
.then(async () => {
|
||||
row._closing = true
|
||||
try {
|
||||
await closeBorrowRequest(row.id)
|
||||
ElMessage.success('审批单已完结')
|
||||
fetchData()
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.msg || e?.msg || e?.message || '完结失败')
|
||||
} finally {
|
||||
row._closing = false
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// --- 状态 ---
|
||||
const list = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
@ -395,6 +395,15 @@
|
||||
</el-table>
|
||||
|
||||
<el-form label-width="80px">
|
||||
<el-form-item label="出库类型" required>
|
||||
<el-select v-model="requestOutboundType" placeholder="请选择类型" style="width: 100%">
|
||||
<el-option label="销售出库" value="SALES" />
|
||||
<el-option label="内部领用" value="USE" />
|
||||
<el-option label="生产出库" value="PRODUCTION" />
|
||||
<el-option label="盘亏出库" value="LOSS" />
|
||||
<el-option label="维修出库" value="REPAIR" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="* 指定审批人" required>
|
||||
<el-select
|
||||
v-model="requestApproverId"
|
||||
@ -533,6 +542,7 @@ const printLoading = ref(false)
|
||||
// ★ 出库申请相关
|
||||
const requestDialogVisible = ref(false)
|
||||
const requestRemark = ref('')
|
||||
const requestOutboundType = ref('SALES') // 申请时确定出库类型,扫码出库自动带出
|
||||
const requestApproverId = ref<number | null>(null)
|
||||
const approvers = ref<any[]>([])
|
||||
const requestSubmitting = ref(false)
|
||||
@ -1088,6 +1098,7 @@ const confirmSubmitRequest = async () => {
|
||||
quantity: item.export_quantity || 0
|
||||
})),
|
||||
remark: buildRemarkWithShortage(trimmed),
|
||||
outbound_type: requestOutboundType.value,
|
||||
approver_id: requestApproverId.value
|
||||
}
|
||||
|
||||
|
||||
@ -187,6 +187,7 @@
|
||||
<el-option label="内部领用" value="USE" />
|
||||
<el-option label="生产出库" value="PRODUCTION" />
|
||||
<el-option label="盘亏出库" value="LOSS" />
|
||||
<el-option label="维修出库" value="REPAIR" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -461,6 +462,10 @@ const handleRequestChange = (val: number | null) => {
|
||||
if (selectedRequest.value?.remark) {
|
||||
form.remark = selectedRequest.value.remark
|
||||
}
|
||||
// ★ 自动带出申请时确定的出库类型(库管无需再选);旧单无类型则留待手动选择
|
||||
if (selectedRequest.value?.outbound_type) {
|
||||
form.outbound_type = selectedRequest.value.outbound_type
|
||||
}
|
||||
}
|
||||
// 切换申请单时清空购物车,防止已扫物品与新单据混淆
|
||||
cartItems.value = []
|
||||
|
||||
@ -253,7 +253,8 @@ const formatType = (type: string) => {
|
||||
'USE': '内部领用',
|
||||
'PRODUCTION': '生产出库',
|
||||
'SCRAP': '报废',
|
||||
'LOSS': '盘亏出库' // ★ 补充映射:扫码出库下拉中存在「盘亏出库 LOSS」,避免出库记录显示英文
|
||||
'LOSS': '盘亏出库', // ★ 补充映射:扫码出库下拉中存在「盘亏出库 LOSS」,避免出库记录显示英文
|
||||
'REPAIR': '维修出库'
|
||||
}
|
||||
return map[type] || type
|
||||
}
|
||||
@ -264,7 +265,8 @@ const getTagType = (type: string) => {
|
||||
'USE': 'warning',
|
||||
'PRODUCTION': 'info',
|
||||
'SCRAP': 'danger',
|
||||
'LOSS': 'warning' // ★ 补充:盘亏出库标签样式
|
||||
'LOSS': 'warning', // ★ 补充:盘亏出库标签样式
|
||||
'REPAIR': 'info'
|
||||
}
|
||||
return map[type] || ''
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user