feat: 采购到货单、库区标签打印、EBOM表格优化

- 采购到货单: 新建 arrivalnotice API,重构 Checkin 页面对齐到货通知功能
- 库区标签打印: 新增 LocationLabelPrint 组件,支持单个/批量打印(4列排版)
- EBOM: 表格表头和内容不换行,过长截断显示

Made-with: Cursor
This commit is contained in:
panchengyong
2026-03-14 14:58:17 +08:00
parent 7aee39d98e
commit dcb77279a0
6 changed files with 1041 additions and 67 deletions

View File

@@ -0,0 +1,141 @@
import request from './request'
/** 到货通知单 */
export interface ArrivalNotice {
noticeId?: number
noticeCode?: string
noticeName?: string
poCode?: string
vendorId?: number
vendorCode?: string
vendorName?: string
vendorNick?: string
arrivalDate?: string
contact?: string
tel?: string
status?: string
remark?: string
createTime?: string
updateTime?: string
}
/** 到货通知单行 */
export interface ArrivalNoticeLine {
lineId?: number
noticeId?: number
itemId?: number
itemCode?: string
itemName?: string
specification?: string
unitOfMeasure?: string
unitName?: string
quantityArrival?: number
quantityQuanlified?: number
iqcCheck?: string
iqcId?: number
iqcCode?: string
remark?: string
createTime?: string
updateTime?: string
}
/** 到货通知单查询参数 */
export interface ArrivalNoticeQuery {
noticeCode?: string
noticeName?: string
poCode?: string
vendorId?: number
vendorName?: string
arrivalDate?: string
status?: string
pageNum?: number
pageSize?: number
}
export interface ArrivalNoticeListResponse {
rows: ArrivalNotice[]
total: number
}
export interface ArrivalNoticeLineListResponse {
rows: ArrivalNoticeLine[]
total: number
}
const NOTICE_BASE = '/mes/wm/arrivalnotice'
const LINE_BASE = '/mes/wm/arrivalnoticeline'
// ============ 到货通知单 ============
/** 查询到货通知单列表 */
export function listArrivalNotice(query?: ArrivalNoticeQuery): Promise<ArrivalNoticeListResponse> {
return request.get(`${NOTICE_BASE}/list`, { params: query }).then((res: any) => ({
rows: res.rows || [],
total: res.total || 0
}))
}
/** 查询到货通知单详情 */
export function getArrivalNotice(noticeId: number): Promise<ArrivalNotice> {
return request.get(`${NOTICE_BASE}/${noticeId}`).then((res: any) => res.data)
}
/** 新增到货通知单 */
export function addArrivalNotice(data: Partial<ArrivalNotice>): Promise<{ data?: number }> {
return request.post(NOTICE_BASE, data)
}
/** 修改到货通知单 */
export function updateArrivalNotice(data: Partial<ArrivalNotice>): Promise<void> {
return request.put(NOTICE_BASE, data)
}
/** 删除到货通知单 */
export function deleteArrivalNotice(noticeId: number | number[]): Promise<void> {
const ids = Array.isArray(noticeId) ? noticeId.join(',') : String(noticeId)
return request.delete(`${NOTICE_BASE}/${ids}`)
}
/** 生成到货通知单编码 */
export function genArrivalNoticeCode(): Promise<string> {
return request.get('/system/autocode/get/ARRIVALNOTICE_CODE').then((res: any) => res.data ?? res.msg ?? '')
}
// ============ 到货通知单行 ============
/** 查询到货通知单行列表 */
export function listArrivalNoticeLine(query?: { noticeId?: number; pageNum?: number; pageSize?: number }): Promise<ArrivalNoticeLineListResponse> {
return request.get(`${LINE_BASE}/list`, { params: query }).then((res: any) => ({
rows: res.rows || [],
total: res.total || 0
}))
}
/** 查询到货通知单行详情 */
export function getArrivalNoticeLine(lineId: number): Promise<ArrivalNoticeLine> {
return request.get(`${LINE_BASE}/${lineId}`).then((res: any) => res.data)
}
/** 新增到货通知单行 */
export function addArrivalNoticeLine(data: Partial<ArrivalNoticeLine>): Promise<void> {
return request.post(LINE_BASE, data)
}
/** 修改到货通知单行 */
export function updateArrivalNoticeLine(data: Partial<ArrivalNoticeLine>): Promise<void> {
return request.put(LINE_BASE, data)
}
/** 删除到货通知单行 */
export function deleteArrivalNoticeLine(lineId: number | number[]): Promise<void> {
const ids = Array.isArray(lineId) ? lineId.join(',') : String(lineId)
return request.delete(`${LINE_BASE}/${ids}`)
}
// ============ 状态映射 ============
export const ARRIVAL_NOTICE_STATUS_MAP: Record<string, { label: string; type: string }> = {
PREPARE: { label: '开立', type: 'info' },
APPROVING: { label: '提交中', type: 'warning' },
APPROVED: { label: '待入库', type: 'success' }
}

View File

@@ -2,61 +2,63 @@
<div class="page-container"> <div class="page-container">
<el-card class="search-card" shadow="never"> <el-card class="search-card" shadow="never">
<el-form :model="queryParams" inline> <el-form :model="queryParams" inline>
<el-form-item label="单编号"> <el-form-item label="通知单编号">
<el-input v-model="queryParams.trackCode" placeholder="请输入" clearable style="width: 140px;" /> <el-input v-model="queryParams.noticeCode" placeholder="请输入" clearable style="width: 140px;" />
</el-form-item> </el-form-item>
<el-form-item label="单据编码"> <el-form-item label="通知单名称">
<el-input v-model="queryParams.checkinCode" placeholder="请输入" clearable style="width: 140px;" /> <el-input v-model="queryParams.noticeName" placeholder="请输入" clearable style="width: 140px;" />
</el-form-item> </el-form-item>
<el-form-item label="供应商"> <el-form-item label="采购订单编号">
<el-input v-model="queryParams.supplierName" placeholder="请输入" clearable style="width: 150px;" /> <el-input v-model="queryParams.poCode" placeholder="请输入" clearable style="width: 140px;" />
</el-form-item> </el-form-item>
<el-form-item label="日期"> <el-form-item label="供应商名称">
<el-date-picker v-model="dateRange" type="daterange" range-separator="-" start-placeholder="开始" end-placeholder="结束" value-format="YYYY-MM-DD" style="width: 220px;" /> <el-input v-model="queryParams.vendorName" placeholder="请输入" clearable style="width: 150px;" />
</el-form-item>
<el-form-item label="到货日期">
<el-date-picker v-model="queryParams.arrivalDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" clearable style="width: 140px;" />
</el-form-item>
<el-form-item label="单据状态">
<el-select v-model="queryParams.status" placeholder="请选择" clearable style="width: 120px;">
<el-option label="开立" value="PREPARE" />
<el-option label="提交中" value="APPROVING" />
</el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="handleQuery"><el-icon><Search /></el-icon>搜索</el-button> <el-button type="primary" @click="handleQuery"><el-icon><Search /></el-icon>搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
<el-card class="table-card" shadow="never"> <el-card class="table-card" shadow="never">
<div class="toolbar"> <div class="toolbar">
<el-button @click="handleDocument">单据</el-button>
<el-button @click="handleQueryAll">查询所有</el-button>
<el-button type="primary" @click="handleAdd"><el-icon><Plus /></el-icon>新增</el-button> <el-button type="primary" @click="handleAdd"><el-icon><Plus /></el-icon>新增</el-button>
<el-button type="success" @click="handleExport"><el-icon><Download /></el-icon>导出</el-button> <el-button @click="handleExport"><el-icon><Download /></el-icon>导出</el-button>
</div> </div>
<el-table v-loading="loading" :data="tableData" stripe border> <el-table v-loading="loading" :data="tableData" stripe border>
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="单编号" width="130"> <el-table-column label="通知单编号" width="150">
<template #default="{ row }">{{ row.lines?.[0]?.trackCode || '-' }}</template>
</el-table-column>
<el-table-column prop="checkinCode" label="单据编码" width="130">
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary">{{ row.checkinCode }}</el-link> <el-link type="primary" @click="handleView(row)">{{ row.noticeCode }}</el-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="noticeName" label="通知单名称" min-width="140" show-overflow-tooltip />
<el-table-column prop="poCode" label="采购订单号" width="130" show-overflow-tooltip />
<el-table-column prop="vendorName" label="供应商名称" min-width="160" show-overflow-tooltip />
<el-table-column prop="contact" label="联系人" width="100" />
<el-table-column prop="tel" label="联系方式" width="120" />
<el-table-column prop="arrivalDate" label="到货日期" width="110" />
<el-table-column prop="status" label="单据状态" width="90" align="center"> <el-table-column prop="status" label="单据状态" width="90" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-tag :type="row.status === '审核' ? 'success' : 'info'">{{ row.status }}</el-tag> <el-tag :type="statusTagType(row.status)">{{ statusLabel(row.status) }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="supplierName" label="供应商" min-width="180" show-overflow-tooltip /> <el-table-column label="操作" width="160" fixed="right">
<el-table-column label="物料名称" width="150">
<template #default="{ row }">{{ row.lines?.[0]?.itemName || '-' }}</template>
</el-table-column>
<el-table-column label="物料编码" width="120">
<template #default="{ row }">{{ row.lines?.[0]?.itemCode || '-' }}</template>
</el-table-column>
<el-table-column prop="totalQuantity" label="到货数量" width="100" align="right" />
<el-table-column prop="stockedQuantity" label="入库数量" width="100" align="right" />
<el-table-column prop="checkinDate" label="单据日期" width="110" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link>查看</el-button> <el-button type="primary" link @click="handleView(row)">查看</el-button>
<el-popconfirm title="确定删除吗?" @confirm="handleDelete(row)"> <el-button v-if="row.status === 'PREPARE'" type="primary" link @click="handleEdit(row)">修改</el-button>
<el-popconfirm v-if="row.status === 'PREPARE'" title="确定删除吗?" @confirm="handleDelete(row)">
<template #reference> <template #reference>
<el-button type="danger" link>删除</el-button> <el-button type="danger" link>删除</el-button>
</template> </template>
@@ -66,35 +68,238 @@
</el-table> </el-table>
<div class="table-footer"> <div class="table-footer">
<div class="summary">
到货数量: <span class="value">{{ totalCheckinQty.toLocaleString() }}</span>
入库数量: <span class="value">{{ totalStockedQty.toLocaleString() }}</span>
</div>
<el-pagination v-model:current-page="queryParams.pageNum" v-model:page-size="queryParams.pageSize" :page-sizes="[10, 20, 50, 100]" :total="total" layout="total, sizes, prev, pager, next, jumper" @size-change="loadData" @current-change="loadData" /> <el-pagination v-model:current-page="queryParams.pageNum" v-model:page-size="queryParams.pageSize" :page-sizes="[10, 20, 50, 100]" :total="total" layout="total, sizes, prev, pager, next, jumper" @size-change="loadData" @current-change="loadData" />
</div> </div>
</el-card> </el-card>
<!-- 新增/修改/查看弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="960px" destroy-on-close @close="handleDialogClose">
<el-form ref="formRef" :model="form" :rules="formRules" :disabled="dialogMode === 'view'" label-width="100px">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="通知单编号" prop="noticeCode">
<el-input v-model="form.noticeCode" placeholder="可自动生成" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item v-if="dialogMode !== 'view' && form.status === 'PREPARE'" label-width="80">
<el-switch v-model="autoGenCode" active-text="自动生成" @change="handleAutoGenChange" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="通知单名称" prop="noticeName">
<el-input v-model="form.noticeName" placeholder="请输入通知单名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="采购订单编号" prop="poCode">
<el-input v-model="form.poCode" placeholder="请输入采购订单编号" />
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="供应商" prop="vendorName">
<el-input v-model="form.vendorName" readonly placeholder="请选择供应商" @click="openSupplierDialog">
<template #append>
<el-button :icon="Search" @click="openSupplierDialog" :disabled="dialogMode === 'view'" />
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="到货日期" prop="arrivalDate">
<el-date-picker v-model="form.arrivalDate" type="date" placeholder="请选择到货日期" value-format="YYYY-MM-DD" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系人" prop="contact">
<el-input v-model="form.contact" placeholder="请输入联系人" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系方式" prop="tel">
<el-input v-model="form.tel" placeholder="请输入联系方式" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 物料明细区noticeId 存在时显示 -->
<el-divider v-if="form.noticeId" content-position="center">物料信息</el-divider>
<div v-if="form.noticeId" class="line-section">
<div class="line-toolbar">
<el-button v-if="dialogMode !== 'view'" type="primary" size="small" @click="handleAddLine">
<el-icon><Plus /></el-icon>新增
</el-button>
</div>
<el-table :data="lineList" stripe border>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="物料编码" width="130">
<template #default="{ row, $index }">
<div v-if="dialogMode !== 'view'" class="inline-select">
<span class="mono">{{ row.itemCode || '请选择' }}</span>
<el-button type="primary" link @click="openItemDialog($index)">选择</el-button>
</div>
<span v-else>{{ row.itemCode || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="itemName" label="物料名称" min-width="150" show-overflow-tooltip />
<el-table-column prop="specification" label="规格型号" width="120" show-overflow-tooltip />
<el-table-column prop="unitName" label="单位" width="70" align="center" />
<el-table-column label="到货数量" width="100">
<template #default="{ row }">
<el-input-number v-if="dialogMode !== 'view'" v-model="row.quantityArrival" :min="0" :precision="2" size="small" style="width: 90px" />
<span v-else>{{ row.quantityArrival ?? '-' }}</span>
</template>
</el-table-column>
<el-table-column label="是否检验" width="90" align="center">
<template #default="{ row }">
<el-select v-if="dialogMode !== 'view'" v-model="row.iqcCheck" size="small" style="width: 70px">
<el-option label="是" value="Y" />
<el-option label="否" value="N" />
</el-select>
<span v-else>{{ row.iqcCheck === 'Y' ? '' : '' }}</span>
</template>
</el-table-column>
<el-table-column prop="quantityQuanlified" label="合格数量" width="90" align="right" />
<el-table-column prop="iqcCode" label="检验单号" width="120" show-overflow-tooltip />
<el-table-column prop="remark" label="备注" min-width="100" show-overflow-tooltip />
<el-table-column v-if="dialogMode !== 'view'" label="操作" width="80" fixed="right">
<template #default="{ $index }">
<el-button type="danger" link @click="handleDeleteLine($index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button v-if="dialogMode !== 'view' && form.status === 'PREPARE'" type="primary" :loading="saveLoading" @click="handleSave">保存</el-button>
<el-button v-if="dialogMode !== 'view' && form.status === 'PREPARE' && form.noticeId" type="success" :loading="saveLoading" @click="handleSubmit">提交</el-button>
</template>
</el-dialog>
<!-- 选择供应商弹窗 -->
<el-dialog v-model="showSupplierDialog" title="选择供应商" width="900px" destroy-on-close>
<div class="dialog-search">
<el-input v-model="supplierSearch.supplierName" placeholder="供应商名称" clearable style="width: 200px; margin-right: 8px" />
<el-input v-model="supplierSearch.contact1" placeholder="业务联系人" clearable style="width: 160px; margin-right: 8px" />
<el-button type="primary" @click="loadSuppliers">搜索</el-button>
<el-button @click="resetSupplierSearch">查询所有</el-button>
</div>
<el-table :data="supplierList" stripe border max-height="400" highlight-current-row>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="supplierName" label="供应商名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="tel" label="电话" width="130" />
<el-table-column prop="contact1" label="业务联系人" width="120" />
<el-table-column label="操作" width="80" align="center">
<template #default="{ row }">
<el-button type="primary" link @click="handleSelectSupplier(row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!-- 选择物料弹窗 -->
<el-dialog v-model="showItemDialog" title="选择物料" width="960px" destroy-on-close @open="handleItemDialogOpen">
<div class="item-dialog-body">
<div class="category-tree">
<el-input v-model="itemTypeFilter" placeholder="请输入分类名称" clearable size="small" style="margin-bottom: 8px" />
<el-scrollbar height="360px">
<el-tree
ref="itemTreeRef"
:data="itemTypeTree"
:props="{ label: 'label', children: 'children' }"
node-key="id"
highlight-current
default-expand-all
:filter-node-method="filterTreeNode"
@node-click="handleTreeNodeClick"
/>
</el-scrollbar>
</div>
<div class="item-table-area">
<div class="item-search-area">
<el-input v-model="itemSearch.itemCode" placeholder="物料编码" clearable style="width: 140px" @keyup.enter="loadItemTableData" />
<el-input v-model="itemSearch.itemName" placeholder="物料名称" clearable style="width: 140px" @keyup.enter="loadItemTableData" />
<el-button type="primary" @click="loadItemTableData">搜索</el-button>
<el-button @click="resetItemSearch">重置</el-button>
</div>
<div class="item-toolbar">
<el-button size="small" @click="loadAllItems">查询所有</el-button>
</div>
<el-table :data="itemTableData" v-loading="itemTableLoading" stripe border max-height="340" highlight-current-row>
<el-table-column prop="itemCode" label="物料编码" width="130" />
<el-table-column prop="itemName" label="物料名称" min-width="180" show-overflow-tooltip />
<el-table-column prop="specification" label="型号规格" width="150" show-overflow-tooltip />
<el-table-column prop="unitName" label="主计量" width="80" align="center" />
<el-table-column label="操作" width="100" align="center">
<template #default="{ row }">
<el-button type="primary" link @click="handleSelectItem(row)">选择</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue' import { ref, reactive, computed, watch, onMounted } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Plus, Download } from '@element-plus/icons-vue' import { Search, Plus, Download } from '@element-plus/icons-vue'
import { getCheckinList, deleteCheckin, type Checkin, type CheckinQuery } from '@/api/checkin' import {
listArrivalNotice,
getArrivalNotice,
addArrivalNotice,
updateArrivalNotice,
deleteArrivalNotice,
listArrivalNoticeLine,
addArrivalNoticeLine,
updateArrivalNoticeLine,
deleteArrivalNoticeLine,
genArrivalNoticeCode,
ARRIVAL_NOTICE_STATUS_MAP,
type ArrivalNotice,
type ArrivalNoticeLine,
type ArrivalNoticeQuery
} from '@/api/arrivalnotice'
import { getPoSupplierList, type PoSupplier } from '@/api/purchaseOrder'
import { listMdItem, type MdItem } from '@/api/masterdata/item'
import { listItemType, handleTree, type ItemType } from '@/api/masterdata/itemtype'
const queryParams = reactive<CheckinQuery>({ trackCode: '', checkinCode: '', supplierName: '', pageNum: 1, pageSize: 10 }) const queryParams = reactive<ArrivalNoticeQuery>({
const dateRange = ref<string[]>([]) noticeCode: '',
noticeName: '',
poCode: '',
vendorName: '',
arrivalDate: '',
status: '',
pageNum: 1,
pageSize: 10
})
const loading = ref(false) const loading = ref(false)
const tableData = ref<Checkin[]>([]) const tableData = ref<ArrivalNotice[]>([])
const total = ref(0) const total = ref(0)
const totalCheckinQty = computed(() => tableData.value.reduce((sum, r) => sum + (r.totalQuantity || 0), 0)) const statusLabel = (status?: string) => ARRIVAL_NOTICE_STATUS_MAP[status || '']?.label ?? status ?? '-'
const totalStockedQty = computed(() => tableData.value.reduce((sum, r) => sum + (r.stockedQuantity || 0), 0)) const statusTagType = (status?: string) => ARRIVAL_NOTICE_STATUS_MAP[status || '']?.type ?? 'info'
const loadData = async () => { const loadData = async () => {
loading.value = true loading.value = true
try { try {
const res = await getCheckinList(queryParams) const res = await listArrivalNotice(queryParams)
tableData.value = res.rows tableData.value = res.rows
total.value = res.total total.value = res.total
} finally { } finally {
@@ -103,11 +308,383 @@ const loadData = async () => {
} }
const handleQuery = () => { queryParams.pageNum = 1; loadData() } const handleQuery = () => { queryParams.pageNum = 1; loadData() }
const handleQueryAll = () => { queryParams.trackCode = ''; queryParams.checkinCode = ''; queryParams.supplierName = ''; dateRange.value = []; handleQuery() } const handleReset = () => {
const handleDocument = () => ElMessage.info('单据视图切换') queryParams.noticeCode = ''
const handleAdd = () => ElMessage.info('新增采购到货单') queryParams.noticeName = ''
const handleDelete = async (row: Checkin) => { await deleteCheckin(String(row.checkinId)); ElMessage.success('删除成功'); loadData() } queryParams.poCode = ''
const handleExport = () => ElMessage.info('导出功能开发中') queryParams.vendorName = ''
queryParams.arrivalDate = ''
queryParams.status = ''
handleQuery()
}
// ============ 弹窗 ============
const dialogVisible = ref(false)
const dialogTitle = ref('')
const dialogMode = ref<'add' | 'edit' | 'view'>('add')
const formRef = ref()
const saveLoading = ref(false)
const autoGenCode = ref(false)
const form = reactive<Partial<ArrivalNotice>>({
noticeId: undefined,
noticeCode: '',
noticeName: '',
poCode: '',
vendorId: undefined,
vendorCode: '',
vendorName: '',
vendorNick: '',
arrivalDate: '',
contact: '',
tel: '',
status: 'PREPARE',
remark: ''
})
const formRules = {
noticeCode: [{ required: true, message: '通知单编号不能为空', trigger: 'blur' }],
noticeName: [{ required: true, message: '通知单名称不能为空', trigger: 'blur' }],
vendorName: [{ required: true, message: '请选择供应商', trigger: 'blur' }],
arrivalDate: [{ required: true, message: '请选择到货日期', trigger: 'change' }]
}
// 明细行(本地编辑用,保存时同步到后端)
const lineList = ref<ArrivalNoticeLine[]>([])
function resetForm() {
Object.assign(form, {
noticeId: undefined,
noticeCode: '',
noticeName: '',
poCode: '',
vendorId: undefined,
vendorCode: '',
vendorName: '',
vendorNick: '',
arrivalDate: '',
contact: '',
tel: '',
status: 'PREPARE',
remark: ''
})
lineList.value = []
autoGenCode.value = false
}
async function loadLines() {
if (!form.noticeId) return
const res = await listArrivalNoticeLine({ noticeId: form.noticeId, pageNum: 1, pageSize: 500 })
lineList.value = res.rows.map(r => ({ ...r, iqcCheck: r.iqcCheck || 'N' }))
}
function handleAdd() {
resetForm()
dialogTitle.value = '新增采购到货单'
dialogMode.value = 'add'
form.arrivalDate = new Date().toISOString().split('T')[0]
dialogVisible.value = true
}
async function handleEdit(row: ArrivalNotice) {
resetForm()
const data = await getArrivalNotice(row.noticeId!)
Object.assign(form, data)
await loadLines()
dialogTitle.value = '修改采购到货单'
dialogMode.value = 'edit'
dialogVisible.value = true
}
async function handleView(row: ArrivalNotice) {
resetForm()
const data = await getArrivalNotice(row.noticeId!)
Object.assign(form, data)
await loadLines()
dialogTitle.value = '查看到货通知单'
dialogMode.value = 'view'
dialogVisible.value = true
}
function handleDialogClose() {
formRef.value?.resetFields()
}
async function handleAutoGenChange(val: boolean) {
if (val) {
try {
form.noticeCode = await genArrivalNoticeCode()
} catch (e) {
ElMessage.error('生成编码失败')
autoGenCode.value = false
}
} else {
form.noticeCode = ''
}
}
async function handleSave() {
try {
await formRef.value?.validate()
} catch {
return
}
saveLoading.value = true
try {
if (form.noticeId) {
await updateArrivalNotice(form)
// 保存明细变更
await saveLines()
ElMessage.success('保存成功')
await loadLines()
} else {
await addArrivalNotice(form)
// 后端可能不返回 noticeId通过 noticeCode 查询获取
const listRes = await listArrivalNotice({ noticeCode: form.noticeCode, pageNum: 1, pageSize: 1 })
const added = listRes.rows[0]
if (added?.noticeId) {
form.noticeId = added.noticeId
await saveLines()
}
ElMessage.success('新增成功')
if (form.noticeId) await loadLines()
}
} catch (e) {
console.error('保存失败:', e)
} finally {
saveLoading.value = false
}
}
async function saveLines() {
if (!form.noticeId) return
const lines = lineList.value.filter(l => l.itemCode && (l.quantityArrival ?? 0) > 0)
for (const line of lines) {
const payload = { ...line, noticeId: form.noticeId, iqcCheck: line.iqcCheck || 'N' }
if (line.lineId) {
await updateArrivalNoticeLine(payload)
} else {
await addArrivalNoticeLine(payload)
}
}
}
async function handleSubmit() {
try {
await formRef.value?.validate()
} catch {
return
}
if (!form.noticeId) {
ElMessage.warning('请先保存表头后再提交')
return
}
const res = await listArrivalNoticeLine({ noticeId: form.noticeId, pageNum: 1, pageSize: 1 })
if (!res.rows.length) {
ElMessage.warning('请至少添加一条物料明细')
return
}
saveLoading.value = true
try {
form.status = 'APPROVING'
await updateArrivalNotice(form)
ElMessage.success('提交成功')
dialogVisible.value = false
loadData()
} catch (e) {
console.error('提交失败:', e)
} finally {
saveLoading.value = false
}
}
async function handleDelete(row: ArrivalNotice) {
try {
await ElMessageBox.confirm('确定删除该到货通知单吗?', '提示', { type: 'warning' })
await deleteArrivalNotice(row.noticeId!)
ElMessage.success('删除成功')
loadData()
} catch (e) {
if (e !== 'cancel') console.error('删除失败:', e)
}
}
function handleExport() {
ElMessage.info('导出功能开发中')
}
// ============ 明细行操作 ============
function handleAddLine() {
if (!form.noticeId) {
ElMessage.warning('请先保存表头后再添加物料')
return
}
lineList.value.push({
noticeId: form.noticeId,
itemId: undefined,
itemCode: '',
itemName: '',
specification: '',
unitOfMeasure: '',
unitName: '',
quantityArrival: 0,
quantityQuanlified: 0,
iqcCheck: 'N',
iqcCode: '',
remark: ''
})
}
function handleDeleteLine(index: number) {
const line = lineList.value[index]
if (line.lineId) {
deleteArrivalNoticeLine(line.lineId).then(() => {
lineList.value.splice(index, 1)
}).catch(() => {})
} else {
lineList.value.splice(index, 1)
}
}
// ============ 供应商选择 ============
const showSupplierDialog = ref(false)
const supplierSearch = reactive({ supplierName: '', contact1: '' })
const supplierList = ref<PoSupplier[]>([])
function openSupplierDialog() {
if (dialogMode.value === 'view') return
showSupplierDialog.value = true
loadSuppliers()
}
async function loadSuppliers() {
const res = await getPoSupplierList({
supplierName: supplierSearch.supplierName || undefined,
contact1: supplierSearch.contact1 || undefined
})
supplierList.value = res.rows
}
function resetSupplierSearch() {
supplierSearch.supplierName = ''
supplierSearch.contact1 = ''
loadSuppliers()
}
function handleSelectSupplier(row: PoSupplier) {
form.vendorId = row.supplierId
form.vendorCode = row.supplierCode
form.vendorName = row.supplierName
form.vendorNick = row.supplierNick
showSupplierDialog.value = false
}
// ============ 物料选择 ============
const showItemDialog = ref(false)
const itemTableLoading = ref(false)
const itemTableData = ref<MdItem[]>([])
const editingLineIndex = ref(-1)
const itemTreeRef = ref()
const itemTypeTree = ref<any[]>([])
const itemTypeFilter = ref('')
const itemSearch = reactive<{ itemCode: string; itemName: string; itemTypeId: number | undefined }>({
itemCode: '',
itemName: '',
itemTypeId: undefined
})
watch(itemTypeFilter, (val) => {
itemTreeRef.value?.filter(val)
})
function filterTreeNode(value: string, data: any) {
if (!value) return true
return (data.label || '').includes(value)
}
function openItemDialog(idx: number) {
editingLineIndex.value = idx
showItemDialog.value = true
}
async function handleItemDialogOpen() {
itemSearch.itemCode = ''
itemSearch.itemName = ''
itemSearch.itemTypeId = undefined
itemTypeFilter.value = ''
await Promise.all([loadItemTypeTree(), loadItemTableData()])
}
async function loadItemTypeTree() {
try {
const res = await listItemType()
const flat = (res as any).data || res || []
const list = Array.isArray(flat) ? flat : []
const tree = handleTree(list)
function toTreeNodes(items: ItemType[]): any[] {
return items.map(item => ({
id: item.itemTypeId,
label: item.itemTypeName || '',
raw: item,
children: item.children?.length ? toTreeNodes(item.children) : undefined
}))
}
itemTypeTree.value = toTreeNodes(tree)
} catch (e) {
itemTypeTree.value = []
}
}
async function loadItemTableData() {
itemTableLoading.value = true
try {
const params: any = { enableFlag: 'Y', pageNum: 1, pageSize: 100 }
if (itemSearch.itemCode) params.itemCode = itemSearch.itemCode
if (itemSearch.itemName) params.itemName = itemSearch.itemName
if (itemSearch.itemTypeId) params.itemTypeId = itemSearch.itemTypeId
const res = await listMdItem(params)
itemTableData.value = res.rows || []
} catch (e) {
itemTableData.value = []
} finally {
itemTableLoading.value = false
}
}
function handleTreeNodeClick(node: any) {
itemSearch.itemTypeId = node.id
loadItemTableData()
}
function resetItemSearch() {
itemSearch.itemCode = ''
itemSearch.itemName = ''
itemSearch.itemTypeId = undefined
itemTreeRef.value?.setCurrentKey(null)
loadItemTableData()
}
function loadAllItems() {
itemSearch.itemCode = ''
itemSearch.itemName = ''
itemSearch.itemTypeId = undefined
itemTypeFilter.value = ''
itemTreeRef.value?.setCurrentKey(null)
loadItemTableData()
}
function handleSelectItem(selected: MdItem) {
const idx = editingLineIndex.value
if (idx < 0 || !lineList.value[idx]) return
const row = lineList.value[idx]
row.itemId = selected.itemId
row.itemCode = selected.itemCode ?? ''
row.itemName = selected.itemName ?? ''
row.specification = selected.specification ?? ''
row.unitOfMeasure = selected.unitOfMeasure ?? ''
row.unitName = selected.unitName ?? selected.unitOfMeasure ?? ''
showItemDialog.value = false
}
onMounted(() => loadData()) onMounted(() => loadData())
</script> </script>
@@ -118,6 +695,20 @@ onMounted(() => loadData())
.search-card :deep(.el-card__body) { padding-bottom: 0; } .search-card :deep(.el-card__body) { padding-bottom: 0; }
.toolbar { margin-bottom: 16px; display: flex; gap: 8px; } .toolbar { margin-bottom: 16px; display: flex; gap: 8px; }
.table-footer { margin-top: 16px; display: flex; justify-content: space-between; align-items: center; } .table-footer { margin-top: 16px; display: flex; justify-content: space-between; align-items: center; }
.summary { font-size: 14px; color: #606266; } .dialog-search { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; margin-bottom: 16px; }
.summary .value { color: #409eff; font-weight: bold; margin-right: 20px; } .inline-select { display: flex; align-items: center; gap: 4px; }
.inline-select .mono { font-family: monospace; color: #606266; }
.line-section { margin-top: 12px; }
.line-toolbar { margin-bottom: 8px; }
.item-dialog-body { display: flex; gap: 12px; min-height: 420px; }
.category-tree {
width: 180px;
min-width: 180px;
border-right: 1px solid #e4e7ed;
padding-right: 12px;
}
.item-table-area { flex: 1; overflow: hidden; }
.item-search-area { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.item-toolbar { margin-bottom: 8px; }
</style> </style>

View File

@@ -162,9 +162,9 @@
</div> </div>
</div> </div>
<el-table :data="lines" border size="small" max-height="420"> <el-table :data="lines" border size="small" max-height="420" class="ebom-table ebom-table-nowrap">
<el-table-column label="序号" type="index" width="60" align="center" /> <el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="物料编码" min-width="160"> <el-table-column label="物料编码" min-width="160" show-overflow-tooltip>
<template #default="{ row, $index }"> <template #default="{ row, $index }">
<div class="inline-select"> <div class="inline-select">
<span class="mono">{{ row.bomItemCode || '请添加物料' }}</span> <span class="mono">{{ row.bomItemCode || '请添加物料' }}</span>
@@ -260,12 +260,12 @@
<el-button @click="queryAllProducts">查询所有</el-button> <el-button @click="queryAllProducts">查询所有</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table :data="productList" border size="small" max-height="380" v-loading="productLoading"> <el-table :data="productList" border size="small" max-height="380" v-loading="productLoading" class="ebom-table ebom-table-nowrap">
<el-table-column prop="itemCode" label="物料编码" width="130" /> <el-table-column prop="itemCode" label="物料编码" width="130" show-overflow-tooltip />
<el-table-column prop="itemName" label="物料名称" min-width="160" show-overflow-tooltip /> <el-table-column prop="itemName" label="物料名称" min-width="160" show-overflow-tooltip />
<el-table-column prop="specification" label="型号规格" width="130" show-overflow-tooltip /> <el-table-column prop="specification" label="型号规格" width="130" show-overflow-tooltip />
<el-table-column prop="unitName" label="主计量" width="70" align="center" /> <el-table-column prop="unitName" label="主计量" width="70" align="center" />
<el-table-column label="供应方式" width="80" align="center"> <el-table-column label="供应方式" width="80" align="center" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
{{ getSupplyLabel(row.itemOrProduct) }} {{ getSupplyLabel(row.itemOrProduct) }}
</template> </template>
@@ -323,12 +323,12 @@
<el-button @click="queryAllItems">查询所有</el-button> <el-button @click="queryAllItems">查询所有</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table :data="itemList" border size="small" max-height="380" v-loading="itemLoading"> <el-table :data="itemList" border size="small" max-height="380" v-loading="itemLoading" class="ebom-table ebom-table-nowrap">
<el-table-column prop="itemCode" label="物料编码" width="130" /> <el-table-column prop="itemCode" label="物料编码" width="130" show-overflow-tooltip />
<el-table-column prop="itemName" label="物料名称" min-width="160" show-overflow-tooltip /> <el-table-column prop="itemName" label="物料名称" min-width="160" show-overflow-tooltip />
<el-table-column prop="specification" label="型号规格" width="130" show-overflow-tooltip /> <el-table-column prop="specification" label="型号规格" width="130" show-overflow-tooltip />
<el-table-column prop="unitName" label="主计量" width="70" align="center" /> <el-table-column prop="unitName" label="主计量" width="70" align="center" />
<el-table-column label="供应方式" width="80" align="center"> <el-table-column label="供应方式" width="80" align="center" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
{{ getSupplyLabel(row.itemOrProduct) }} {{ getSupplyLabel(row.itemOrProduct) }}
</template> </template>
@@ -700,10 +700,11 @@ async function loadItemTypeTree() {
} }
} }
/** 左侧分类树显示物料/产品名称itemTypeName参考物料管理 masterdata/item */
function toTreeNode(item: ItemType): any { function toTreeNode(item: ItemType): any {
return { return {
id: item.itemTypeId, id: item.itemTypeId,
label: `${item.itemTypeCode || ''}-${item.itemTypeName || ''}`.replace(/^-/, ''), label: item.itemTypeName || item.itemTypeCode || '',
children: item.children?.map(toTreeNode) || [] children: item.children?.map(toTreeNode) || []
} }
} }
@@ -732,6 +733,7 @@ function openProductDialog() {
searchProductItems() searchProductItems()
} }
/** 从物料编码选择打开:显示产品/半成品分类下的数据(含未启用) */
async function searchProductItems() { async function searchProductItems() {
productLoading.value = true productLoading.value = true
try { try {
@@ -739,7 +741,7 @@ async function searchProductItems() {
itemCode: productQuery.itemCode || undefined, itemCode: productQuery.itemCode || undefined,
itemName: productQuery.itemName || undefined, itemName: productQuery.itemName || undefined,
itemTypeId: productQuery.itemTypeId, itemTypeId: productQuery.itemTypeId,
enableFlag: 'Y', itemOrProduct: 'PRODUCT',
pageNum: productQuery.pageNum, pageNum: productQuery.pageNum,
pageSize: productQuery.pageSize pageSize: productQuery.pageSize
}) })
@@ -799,6 +801,7 @@ function openItemDialog(idx: number) {
searchSubItems() searchSubItems()
} }
/** 从新增物料按钮打开:显示原材料分类下的数据 */
async function searchSubItems() { async function searchSubItems() {
itemLoading.value = true itemLoading.value = true
try { try {
@@ -806,6 +809,7 @@ async function searchSubItems() {
itemCode: itemQuery.itemCode || undefined, itemCode: itemQuery.itemCode || undefined,
itemName: itemQuery.itemName || undefined, itemName: itemQuery.itemName || undefined,
itemTypeId: itemQuery.itemTypeId, itemTypeId: itemQuery.itemTypeId,
itemOrProduct: 'ITEM',
enableFlag: 'Y', enableFlag: 'Y',
pageNum: itemQuery.pageNum, pageNum: itemQuery.pageNum,
pageSize: itemQuery.pageSize pageSize: itemQuery.pageSize
@@ -959,4 +963,19 @@ onMounted(() => {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
} }
/* 表格表头和内容不换行,过长截断显示 */
.ebom-table-nowrap :deep(.el-table__header th),
.ebom-table-nowrap :deep(.el-table__body td) {
white-space: nowrap;
}
.ebom-table-nowrap :deep(.el-table__body td .cell) {
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.ebom-table-nowrap :deep(.el-table__body td .el-input),
.ebom-table-nowrap :deep(.el-table__body td .el-input-number) {
max-width: 100%;
}
</style> </style>

View File

@@ -101,9 +101,10 @@
border border
style="width: 100%" style="width: 100%"
:max-height="tableHeight" :max-height="tableHeight"
class="ebom-table ebom-table-nowrap"
> >
<el-table-column type="index" label="序号" width="60" align="center" fixed="left" /> <el-table-column type="index" label="序号" width="60" align="center" fixed="left" />
<el-table-column prop="bomCode" label="单据编码" width="140" fixed="left"> <el-table-column prop="bomCode" label="单据编码" width="140" fixed="left" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="handleView(row)">{{ row.bomCode }}</el-link> <el-link type="primary" @click="handleView(row)">{{ row.bomCode }}</el-link>
</template> </template>
@@ -114,7 +115,7 @@
<el-table-column prop="version" label="版本号" width="80" align="center" /> <el-table-column prop="version" label="版本号" width="80" align="center" />
<el-table-column prop="versionDesc" label="版本说明" width="120" show-overflow-tooltip /> <el-table-column prop="versionDesc" label="版本说明" width="120" show-overflow-tooltip />
<el-table-column prop="drawingNo" label="图纸号" width="100" show-overflow-tooltip /> <el-table-column prop="drawingNo" label="图纸号" width="100" show-overflow-tooltip />
<el-table-column prop="status" label="单据状态" width="80" align="center"> <el-table-column prop="status" label="单据状态" width="100" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-tag :type="getStatusType(row.status)" size="small">{{ getStatusLabel(row.status) }}</el-tag> <el-tag :type="getStatusType(row.status)" size="small">{{ getStatusLabel(row.status) }}</el-tag>
</template> </template>
@@ -142,10 +143,11 @@
border border
style="width: 100%" style="width: 100%"
:max-height="tableHeight" :max-height="tableHeight"
class="ebom-table ebom-table-nowrap"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column type="selection" width="55" fixed="left" /> <el-table-column type="selection" width="55" fixed="left" />
<el-table-column prop="bomCode" label="单据编码" width="140" fixed="left"> <el-table-column prop="bomCode" label="单据编码" width="140" fixed="left" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<el-link type="primary" @click="handleView(row)">{{ row.bomCode }}</el-link> <el-link type="primary" @click="handleView(row)">{{ row.bomCode }}</el-link>
</template> </template>
@@ -155,7 +157,7 @@
{{ row.bomDate || row.createTime?.slice(0, 10) || '-' }} {{ row.bomDate || row.createTime?.slice(0, 10) || '-' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="status" label="单据状态" width="80" align="center"> <el-table-column prop="status" label="单据状态" width="100" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-tag :type="getStatusType(row.status)" size="small">{{ getStatusLabel(row.status) }}</el-tag> <el-tag :type="getStatusType(row.status)" size="small">{{ getStatusLabel(row.status) }}</el-tag>
</template> </template>
@@ -165,8 +167,8 @@
{{ getBizTypeLabel(row.businessType) }} {{ getBizTypeLabel(row.businessType) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="deptName" label="业务部门" width="100" align="center" /> <el-table-column prop="deptName" label="业务部门" width="100" align="center" show-overflow-tooltip />
<el-table-column prop="operatorName" label="业务人员" width="100" align="center"> <el-table-column prop="operatorName" label="业务人员" width="100" align="center" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
{{ row.operatorName || row.createBy || '-' }} {{ row.operatorName || row.createBy || '-' }}
</template> </template>
@@ -658,4 +660,14 @@ onMounted(() => {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 13px; font-size: 13px;
} }
/* 表格表头和内容不换行,过长截断显示 */
.ebom-table-nowrap :deep(.el-table__header th),
.ebom-table-nowrap :deep(.el-table__body td) {
white-space: nowrap;
}
.ebom-table-nowrap :deep(.el-table__body td .cell) {
overflow: hidden;
text-overflow: ellipsis;
}
</style> </style>

View File

@@ -0,0 +1,171 @@
<template>
<el-dialog
:visible="visible"
@close="handleClose"
fullscreen
destroy-on-close
:show-close="false"
class="location-label-print-dialog"
append-to-body
>
<template slot="title">
<div class="label-print-actions">
<el-button type="primary" size="small" @click="doPrint">打印</el-button>
<el-button size="small" @click="handleClose">关闭</el-button>
</div>
</template>
<div class="label-print-content" ref="printContentRef">
<div v-if="locations.length === 0" class="label-empty">暂无库区数据</div>
<div v-else class="label-grid">
<div
v-for="(loc, idx) in locations"
:key="loc.locationId || idx"
class="label-card"
>
<div class="label-qr">
<QrCode :value="loc.locationCode || String(loc.locationId || '')" :size="72" />
</div>
<div class="label-name">{{ loc.locationName || '-' }}</div>
<div class="label-code">{{ loc.locationCode || '-' }}</div>
<div class="label-info">
<span v-if="loc.area != null">面积{{ loc.area }} </span>
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script>
import QrCode from './QrCode.vue'
export default {
name: 'LocationLabelPrint',
components: { QrCode },
props: {
visible: {
type: Boolean,
default: false
},
locations: {
type: Array,
default: () => []
}
},
methods: {
doPrint() {
window.print()
},
handleClose() {
this.$emit('update:visible', false)
}
}
}
</script>
<style>
@media print {
body > *:not(.el-overlay) {
display: none !important;
}
.el-overlay {
position: static !important;
overflow: visible !important;
background: none !important;
}
.el-dialog__wrapper {
position: static !important;
overflow: visible !important;
}
.el-dialog {
box-shadow: none !important;
border: none !important;
margin: 0 !important;
width: 100% !important;
max-width: 100% !important;
}
.el-dialog__header,
.el-dialog__footer,
.label-print-actions {
display: none !important;
}
.el-dialog__body {
padding: 0 !important;
}
.label-print-content {
padding: 8mm !important;
}
.label-card {
page-break-inside: avoid;
}
}
</style>
<style scoped>
.label-print-actions {
display: flex;
gap: 8px;
justify-content: flex-end;
}
.label-print-content {
padding: 24px;
background: #fff;
font-family: 'Microsoft YaHei', 'SimSun', sans-serif;
color: #333;
}
.label-empty {
text-align: center;
padding: 48px;
color: #909399;
font-size: 14px;
}
.label-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
max-width: 1200px;
margin: 0 auto;
}
.label-card {
border: 1px solid #dcdfe6;
border-radius: 6px;
padding: 12px;
text-align: center;
min-height: 120px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
.label-qr {
margin-bottom: 8px;
}
.label-name {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 4px;
}
.label-code {
font-size: 12px;
color: #606266;
margin-bottom: 8px;
}
.label-info {
font-size: 11px;
color: #909399;
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
}
</style>

View File

@@ -48,6 +48,17 @@
v-hasPermi="['mes:wm:location:remove']" v-hasPermi="['mes:wm:location:remove']"
>删除</el-button> >删除</el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-printer"
size="mini"
:disabled="multiple"
@click="handleBatchPrint"
v-hasPermi="['mes:wm:location:print']"
>批量打印</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
@@ -107,6 +118,13 @@
@click="handleHiPrint(scope.row)" @click="handleHiPrint(scope.row)"
v-hasPermi="['mes:wm:location:print']" v-hasPermi="['mes:wm:location:print']"
>标签打印</el-button> >标签打印</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-document"
@click="handleSimplePrint(scope.row)"
v-hasPermi="['mes:wm:location:print']"
>简易打印</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -240,6 +258,12 @@
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
<!-- 简易标签打印不依赖MinIO -->
<LocationLabelPrint
:visible.sync="printDialogVisible"
:locations="printLocations"
/>
</div> </div>
</template> </template>
@@ -247,6 +271,7 @@
import { listLocation, getLocation, delLocation, addLocation, updateLocation, changeFrozenState, setProductMixing, setBatchMixing } from "@/api/mes/wm/location"; import { listLocation, getLocation, delLocation, addLocation, updateLocation, changeFrozenState, setProductMixing, setBatchMixing } from "@/api/mes/wm/location";
import {genCode} from "@/api/system/autocode/rule" import {genCode} from "@/api/system/autocode/rule"
import BarcodeImg from "@/components/barcodeImg/index.vue" import BarcodeImg from "@/components/barcodeImg/index.vue"
import LocationLabelPrint from "@/components/print/LocationLabelPrint.vue"
import { getBarcodeUrl } from '@/api/mes/wm/barcode'; import { getBarcodeUrl } from '@/api/mes/wm/barcode';
import {print} from "../../../../utils/print" import {print} from "../../../../utils/print"
import {getByTemplateType} from "@/api/print/template"; import {getByTemplateType} from "@/api/print/template";
@@ -255,7 +280,7 @@ export default {
name: "Location", name: "Location",
dicts: ['sys_yes_no'], dicts: ['sys_yes_no'],
mixins: [hiprintMixin], mixins: [hiprintMixin],
components: { BarcodeImg } , components: { BarcodeImg, LocationLabelPrint },
data() { data() {
return { return {
//自动生成编码 //自动生成编码
@@ -266,6 +291,7 @@ export default {
loading: true, loading: true,
// 选中数组 // 选中数组
ids: [], ids: [],
selectedRows: [],
// 非单个禁用 // 非单个禁用
single: true, single: true,
// 非多个禁用 // 非多个禁用
@@ -280,6 +306,9 @@ export default {
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
open: false, open: false,
// 简易打印弹窗
printDialogVisible: false,
printLocations: [],
// 查询参数 // 查询参数
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
@@ -314,6 +343,16 @@ export default {
this.getList(); this.getList();
}, },
methods: { methods: {
// 简易打印不依赖MinIO纯前端二维码+window.print
handleSimplePrint(row) {
this.printLocations = [row]
this.printDialogVisible = true
},
// 批量打印
handleBatchPrint() {
this.printLocations = this.selectedRows || this.locationList.filter(l => this.ids.includes(l.locationId))
this.printDialogVisible = true
},
// 使用HiPrint打印 // 使用HiPrint打印
async handleHiPrint(row) { async handleHiPrint(row) {
let printData = row let printData = row
@@ -393,6 +432,7 @@ export default {
// 多选框选中数据 // 多选框选中数据
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.ids = selection.map(item => item.locationId) this.ids = selection.map(item => item.locationId)
this.selectedRows = selection
this.single = selection.length!==1 this.single = selection.length!==1
this.multiple = !selection.length this.multiple = !selection.length
}, },