添加条形码内容
This commit is contained in:
@ -91,8 +91,11 @@
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
||||
<el-table-column label="操作" width="160" fixed="right" align="center">
|
||||
<el-table-column label="操作" width="220" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="warning" size="default" @click="handlePrint(row)">
|
||||
<el-icon><Printer /></el-icon> 打印
|
||||
</el-button>
|
||||
<el-button link type="primary" size="default" @click="handleUpdate(row)">编辑</el-button>
|
||||
<el-popconfirm title="确定删除该条记录吗?不可恢复。" @confirm="handleDelete(row)" width="220">
|
||||
<template #reference>
|
||||
@ -194,7 +197,15 @@
|
||||
|
||||
<div class="card-content">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-form-item label="编码/SKU" prop="sku"><el-input v-model="form.sku" placeholder="选填" /></el-form-item></el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="编码/SKU" prop="sku">
|
||||
<el-input
|
||||
v-model="form.sku"
|
||||
placeholder="系统自动生成 (0000000X)"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="入库日期" prop="in_date">
|
||||
<el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled />
|
||||
@ -372,17 +383,46 @@
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="visible = false" size="large">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="submitForm" size="large" class="confirm-btn">
|
||||
{{ dialogStatus === 'create' ? '确认入库' : '保存修改' }}
|
||||
{{ dialogStatus === 'create' ? '确认入库并打印' : '保存修改' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="printVisible"
|
||||
title="标签打印预览"
|
||||
width="400px"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
>
|
||||
<div style="text-align: center;">
|
||||
<div v-loading="printLoading" class="preview-box">
|
||||
<img v-if="previewUrl" :src="previewUrl" alt="Label Preview" style="width: 100%; border: 1px solid #ccc;" />
|
||||
<div v-else class="empty-preview">正在生成预览...</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px; font-size: 14px; color: #666;">
|
||||
<p>打印机 IP: 192.168.9.205</p>
|
||||
<p>尺寸: 40mm x 30mm</p>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="printVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="printing" @click="confirmPrint">
|
||||
<el-icon><Printer /></el-icon> 确认打印
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, watch } from 'vue'
|
||||
import { Plus, Setting, Refresh, Search, Lock, Box, House, InfoFilled, Link } from '@element-plus/icons-vue'
|
||||
import { Plus, Setting, Refresh, Search, Lock, Box, House, InfoFilled, Link, Printer } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import dayjs from 'dayjs'
|
||||
import {
|
||||
@ -392,6 +432,7 @@ import {
|
||||
deleteBuyInbound,
|
||||
searchMaterialBase
|
||||
} from '@/api/inbound/buy'
|
||||
import { getLabelPreview, executePrint } from '@/api/common/print'
|
||||
|
||||
// ------------------------------------
|
||||
// 状态与变量
|
||||
@ -407,6 +448,13 @@ const formRef = ref()
|
||||
const queryParams = reactive({ page: 1, pageSize: 15, keyword: '' })
|
||||
const materialOptions = ref<any[]>([])
|
||||
|
||||
// 打印相关变量
|
||||
const printVisible = ref(false)
|
||||
const printLoading = ref(false)
|
||||
const printing = ref(false)
|
||||
const previewUrl = ref('')
|
||||
const currentPrintData = ref<any>({})
|
||||
|
||||
const entryMode = ref('batch')
|
||||
const modeLocked = ref(false)
|
||||
|
||||
@ -599,9 +647,6 @@ const querySearchCurrency = (queryString: string, cb: any) => {
|
||||
|
||||
const handleMaterialDropdownVisible = (visible: boolean) => {
|
||||
if (visible) {
|
||||
// 【修改点】: 展开时,如果列表为空,直接调用 API 加载前 20 条数据
|
||||
// 同时也会把历史记录合并进去(在 handleSearchMaterial 内部处理或分开展示)
|
||||
// 这里简单处理:直接调用 handleSearchMaterial('') 让后端返回默认数据
|
||||
if (materialOptions.value.length === 0) {
|
||||
handleSearchMaterial('')
|
||||
}
|
||||
@ -611,14 +656,11 @@ const handleMaterialDropdownVisible = (visible: boolean) => {
|
||||
const handleSearchMaterial = async (query: string) => {
|
||||
searchLoading.value = true
|
||||
try {
|
||||
// 即使 query 为空,后端现在也会返回数据
|
||||
const res: any = await searchMaterialBase(query)
|
||||
const apiResults = (res.data || []).map((i: any) => ({ ...i, isHistory: false }))
|
||||
|
||||
// 如果是空搜索,我们可以把本地历史记录插在前面,做个合并
|
||||
if (!query) {
|
||||
const history = getMaterialHistory()
|
||||
// 简单去重:如果 API 返回的 ID 在历史记录里有,就跳过 API 的那个(优先显示历史标记)
|
||||
const historyIds = new Set(history.map((h: any) => h.id))
|
||||
const filteredApi = apiResults.filter((apiItem: any) => !historyIds.has(apiItem.id))
|
||||
materialOptions.value = [...history, ...filteredApi]
|
||||
@ -630,7 +672,6 @@ const handleSearchMaterial = async (query: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 选中物料后 -> 存入历史 -> 填充表单
|
||||
const onMaterialSelected = (val: number) => {
|
||||
const item = materialOptions.value.find(i => i.id === val)
|
||||
if (item) {
|
||||
@ -758,7 +799,6 @@ const handleCreate = () => {
|
||||
entryMode.value = 'batch'
|
||||
form.batch_number = ''
|
||||
visible.value = true
|
||||
// 每次打开弹窗时,先清空选项,让下拉时触发“历史加载”
|
||||
materialOptions.value = []
|
||||
}
|
||||
|
||||
@ -806,7 +846,6 @@ const handleUpdate = (row: any) => {
|
||||
form.detail_link = row.detail_link
|
||||
form.arrival_photo = row.arrival_photo
|
||||
|
||||
// 编辑模式下,把当前物料塞入选项,防止显示为 ID
|
||||
materialOptions.value = [{
|
||||
id: row.base_id,
|
||||
name: row.material_name,
|
||||
@ -817,6 +856,9 @@ const handleUpdate = (row: any) => {
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
// 提交逻辑 (新增自动打印逻辑)
|
||||
// ------------------------------------
|
||||
const submitForm = async () => {
|
||||
if (!formRef.value) return
|
||||
await formRef.value.validate(async (valid: boolean) => {
|
||||
@ -824,8 +866,24 @@ const submitForm = async () => {
|
||||
submitting.value = true
|
||||
try {
|
||||
if (dialogStatus.value === 'create') {
|
||||
await createBuyInbound(form)
|
||||
// 1. 创建入库
|
||||
const res: any = await createBuyInbound(form)
|
||||
ElMessage.success('入库成功')
|
||||
|
||||
// 2. 自动打印 (使用返回的完整数据)
|
||||
// res.data 包含了 newly created stock item, with generated ID and SKU
|
||||
const newItem = res.data
|
||||
if (newItem) {
|
||||
ElMessage.info('正在发送打印指令...')
|
||||
try {
|
||||
await executePrint(newItem)
|
||||
ElMessage.success('打印指令已发送')
|
||||
} catch (printErr: any) {
|
||||
console.error(printErr)
|
||||
ElMessage.warning('入库成功,但自动打印失败:' + (printErr.msg || '未知错误'))
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
const payload = {
|
||||
...form,
|
||||
@ -836,7 +894,6 @@ const submitForm = async () => {
|
||||
ElMessage.success('更新成功')
|
||||
}
|
||||
|
||||
// 保存供应商等信息到历史记录
|
||||
saveToHistory(HISTORY_KEYS.SUPPLIER, form.supplier_name)
|
||||
saveToHistory(HISTORY_KEYS.PURCHASER, form.purchaser)
|
||||
saveToHistory(HISTORY_KEYS.EMAIL, form.purchaser_email)
|
||||
@ -862,6 +919,50 @@ const handleDelete = async (row: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
// 打印逻辑 (手动 & 预览)
|
||||
// ------------------------------------
|
||||
const handlePrint = async (row: any) => {
|
||||
printVisible.value = true
|
||||
printLoading.value = true
|
||||
previewUrl.value = ''
|
||||
|
||||
const printData = {
|
||||
global_print_id: row.global_print_id,
|
||||
material_name: row.material_name,
|
||||
spec_model: row.spec_model,
|
||||
category: row.category,
|
||||
material_type: row.material_type,
|
||||
warehouse_loc: row.warehouse_loc,
|
||||
serial_number: row.serial_number,
|
||||
batch_number: row.batch_number,
|
||||
sku: row.sku // 【重要】显式增加 SKU 字段传递给后端
|
||||
}
|
||||
currentPrintData.value = printData
|
||||
|
||||
try {
|
||||
const res: any = await getLabelPreview(printData)
|
||||
previewUrl.value = res.data
|
||||
} catch(e) {
|
||||
ElMessage.error('预览生成失败')
|
||||
} finally {
|
||||
printLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const confirmPrint = async () => {
|
||||
printing.value = true
|
||||
try {
|
||||
await executePrint(currentPrintData.value)
|
||||
ElMessage.success('指令已发送')
|
||||
printVisible.value = false
|
||||
} catch(e: any) {
|
||||
ElMessage.error(e.msg || '打印失败')
|
||||
} finally {
|
||||
printing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
materialOptions.value = []
|
||||
Object.assign(form, {
|
||||
@ -1031,4 +1132,14 @@ onMounted(() => fetchData())
|
||||
.opt-name { font-weight: bold; }
|
||||
.opt-spec { color: #8492a6; font-size: 13px; margin-right: 10px; }
|
||||
.total-price-input :deep(.el-input__inner) { color: #F56C6C; font-weight: bold; }
|
||||
|
||||
.preview-box {
|
||||
min-height: 150px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.empty-preview { color: #909399; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user