Commit 65e91500 by 杨子

feat: 添加Lodop打印支持并优化仓库管理功能

- 新增Lodop打印插件及相关安装文件
- 添加二维码打印组件QrcodePrintDialog
- 优化仓库、库区、货架选择组件LocationCascaderSelect
- 新增RFID和PTL标签选择对话框组件
- 优化物资选择对话框,支持快速新增物资
- 调整物资管理页面,隐藏RFID相关字段
- 优化库存管理页面,调整查询条件和显示字段
- 修改主题色为绿色系
- 添加Tailwind CSS支持并配置与Element Plus的兼容
parent 51fd2e02
......@@ -7,6 +7,7 @@
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico">
<script src="/lodop/LodopFuncs.js"></script>
<title>WMS仓库管理系统</title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style>
......@@ -209,6 +210,9 @@
<div class="load_title">正在加载系统资源,请耐心等待</div>
</div>
</div>
<object id="LODOP_OB" classid="clsid:2105C259-1E0C-4534-8141-A753534CB4CA" width=0 height=0>
<embed id="LODOP_EM" type="application/x-print-lodop" width=0 height=0 pluginspage="install_lodop32.exe"></embed>
</object>
<script type="module" src="/src/main.js"></script>
</body>
......
......@@ -43,7 +43,10 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "5.2.4",
"autoprefixer": "^10.4.23",
"postcss": "^8.5.6",
"sass-embedded": "1.89.1",
"tailwindcss": "3",
"unplugin-auto-import": "0.18.6",
"unplugin-vue-setup-extend-plus": "1.0.1",
"vite": "6.3.5",
......
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
\ No newline at end of file
import request from '@/utils/request'
// 生成入库单号
export function generateInboundOrderNo() {
return request({
url: '/ware/codeGenerator/generateInboundOrderNo',
method: 'get'
})
}
// 生成出库单号
export function generateOutboundOrderNo() {
return request({
url: '/ware/codeGenerator/generateOutboundOrderNo',
method: 'get'
})
}
// 生成批次号
export function generateBatchNo() {
return request({
url: '/ware/codeGenerator/generateBatchNo',
method: 'get'
})
}
......@@ -17,7 +17,7 @@ export function getWmsInboundOrder(orderId) {
})
}
// 新增入库单
// 新增入库单
export function addWmsInboundOrder(data) {
return request({
url: '/ware/wmsInboundOrder',
......@@ -25,8 +25,24 @@ export function addWmsInboundOrder(data) {
data: data
})
}
// 保存入库单
export function saveWmsInboundOrder(data) {
return request({
url: '/ware/wmsInboundOrder/saveInBound',
method: 'post',
data: data
})
}
// 入库功能(添加到库存)
export function addToInventory(data) {
return request({
url: '/ware/wmsInboundOrder/addMy',
method: 'post',
data: data
})
}
// 修改入库单
// 修改入库单
export function updateWmsInboundOrder(data) {
return request({
url: '/ware/wmsInboundOrder',
......@@ -34,6 +50,15 @@ export function updateWmsInboundOrder(data) {
data: data
})
}
// 修改入库单明细
export function updateWmsInboundOrderItem(data) {
return request({
url: '/ware/wmsInboundOrder/updateItem',
method: 'put',
data: data
})
}
// 删除入库单主
export function delWmsInboundOrder(orderId) {
......@@ -42,3 +67,10 @@ export function delWmsInboundOrder(orderId) {
method: 'delete'
})
}
export function delWmsInboundOrderItem(orderId, itemId) {
return request({
url: '/ware/wmsInboundOrder/deleteItem/' + orderId + '/' + itemId,
method: 'delete'
})
}
@use './tailwind.css';
@use './mixin.scss';
@use './transition.scss';
@use './element-ui.scss';
......@@ -5,6 +6,7 @@
@use './btn.scss';
@use './ruoyi.scss';
body {
height: 100%;
margin: 0;
......
@tailwind base;
@tailwind components;
@tailwind utilities;
......@@ -32,7 +32,7 @@ $base-sub-menu-background: #1e3e08;
$base-sub-menu-hover: #152d06;
// 组件变量
$--color-primary: #409EFF;
$--color-primary: #2b580c;
$--color-success: #67C23A;
$--color-warning: #E6A23C;
$--color-danger: #F56C6C;
......@@ -78,6 +78,7 @@ $--color-info: #909399;
/* splitpanes default-theme 变量 */
--splitpanes-default-bg: #ffffff;
--el-color-primary: #{$--color-primary} !important;
}
// 暗黑模式变量
......
<template>
<div class="location-cascader">
<el-form :model="form" label-width="80px">
<el-form-item label="仓库" v-if="!modelValue.warehouseId">
<el-select v-model="form.warehouseId" placeholder="请选择仓库" @change="handleWarehouseChange">
<el-option
v-for="warehouse in warehouseList"
:key="warehouse.warehouseId"
:label="warehouse.warehouseName"
:value="warehouse.warehouseId"
/>
</el-select>
</el-form-item>
<el-form-item label="库区">
<el-select v-model="form.areaId" placeholder="请选择库区" @change="handleAreaChange" :disabled="!form.warehouseId">
<el-option
v-for="area in areaList"
:key="area.areaId"
:label="area.areaName"
:value="area.areaId"
/>
</el-select>
</el-form-item>
<el-form-item label="货架">
<el-select v-model="form.locationId" placeholder="请选择货架" :disabled="!form.areaId">
<el-option
v-for="location in locationList"
:key="location.locationId"
:label="location.locationCode"
:value="location.locationId"
/>
</el-select>
</el-form-item>
</el-form>
</div>
</template>
<script setup name="LocationCascaderSelect">
import { ref, reactive, watch } from 'vue'
import { listWmsWarehouse } from "@/api/ware/wmsWarehouse"
import { listWmsArea } from "@/api/ware/wmsArea"
import { listWmsLocation } from "@/api/ware/wmsLocation"
const props = defineProps({
modelValue: {
type: Object,
default: () => ({
warehouseId: null,
areaId: null,
locationId: null
})
}
})
const emit = defineEmits(['update:modelValue'])
// 表单数据
const form = reactive({
warehouseId: props.modelValue.warehouseId,
areaId: props.modelValue.areaId,
locationId: props.modelValue.locationId
})
// 监听props变化,同步本地状态
watch(() => props.modelValue, (newVal) => {
form.warehouseId = newVal.warehouseId
form.areaId = newVal.areaId
form.locationId = newVal.locationId
}, { deep: true })
// 仓库列表
const warehouseList = ref([])
// 库区列表
const areaList = ref([])
// 货架列表
const locationList = ref([])
// 加载状态
const loading = ref(false)
// 初始化获取仓库列表
const initWarehouseList = () => {
loading.value = true
listWmsWarehouse({ pageNum: 1, pageSize: 100 }).then(response => {
warehouseList.value = response.rows
loading.value = false
}).catch(error => {
console.error('获取仓库列表失败:', error)
loading.value = false
})
}
// 获取库区列表
const getAreaList = (warehouseId) => {
if (!warehouseId) {
areaList.value = []
form.areaId = null
form.locationId = null
locationList.value = []
return
}
loading.value = true
listWmsArea({ pageNum: 1, pageSize: 100, warehouseId: warehouseId }).then(response => {
areaList.value = response.rows
loading.value = false
}).catch(error => {
console.error('获取库区列表失败:', error)
loading.value = false
})
}
// 获取货架列表
const getLocationList = (areaId) => {
if (!areaId) {
locationList.value = []
form.locationId = null
return
}
loading.value = true
listWmsLocation({ pageNum: 1, pageSize: 100, areaId: areaId }).then(response => {
locationList.value = response.rows
loading.value = false
}).catch(error => {
console.error('获取货架列表失败:', error)
loading.value = false
})
}
// 仓库选择变化
const handleWarehouseChange = (warehouseId) => {
getAreaList(warehouseId)
updateModelValue()
}
// 库区选择变化
const handleAreaChange = (areaId) => {
getLocationList(areaId)
updateModelValue()
}
// 监听表单变化,更新modelValue
watch(
() => [form.warehouseId, form.areaId, form.locationId],
() => {
updateModelValue()
},
{ deep: true }
)
// 更新modelValue
const updateModelValue = () => {
emit('update:modelValue', {
warehouseId: form.warehouseId,
areaId: form.areaId,
locationId: form.locationId
})
}
// 初始化
initWarehouseList()
// 如果初始有仓库ID,获取对应库区和货架
if (props.modelValue.warehouseId) {
getAreaList(props.modelValue.warehouseId)
if (props.modelValue.areaId) {
getLocationList(props.modelValue.areaId)
}
}
</script>
<style scoped>
.location-cascader {
padding: 10px;
background-color: #f5f7fa;
border-radius: 4px;
}
</style>
\ No newline at end of file
......@@ -48,6 +48,7 @@
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<el-button type="success" icon="Plus" @click="handleAddMaterial">新增</el-button>
</el-form-item>
</el-form>
......@@ -77,12 +78,80 @@
</div>
</template>
</el-dialog>
<!-- 新增物资对话框 -->
<el-dialog :title="addMaterialTitle" v-model="addMaterialVisible" width="800px" append-to-body>
<el-form ref="addMaterialRef" :model="addMaterialForm" :rules="addMaterialRules" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="物资编码" prop="materialCode">
<el-input v-model="addMaterialForm.materialCode" placeholder="请输入物资编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物资名称" prop="materialName">
<el-input v-model="addMaterialForm.materialName" placeholder="请输入物资名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="物资分类" prop="categoryId">
<el-tree-select
v-model="addMaterialForm.categoryId"
:data="materialCategoryOptions"
:props="{ value: 'categoryId', label: 'categoryName', children: 'children' }"
value-key="categoryId"
placeholder="请选择物资分类"
check-strictly
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="规格型号" prop="specification">
<el-input v-model="addMaterialForm.specification" placeholder="请输入规格型号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="计量单位" prop="unit">
<el-input v-model="addMaterialForm.unit" placeholder="请输入计量单位" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产厂家" prop="manufacturer">
<el-input v-model="addMaterialForm.manufacturer" placeholder="请输入生产厂家" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="安全库存" prop="safetyStock">
<el-input v-model.number="addMaterialForm.safetyStock" placeholder="请输入安全库存" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="status">
<el-switch v-model="addMaterialForm.status" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitAddMaterial">确 定</el-button>
<el-button @click="cancelAddMaterial">取 消</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup name="MaterialSelectDialog">
import { ref, reactive, watch } from 'vue'
import { listWmsMaterial } from "@/api/ware/wmsMaterial"
import { listWmsMaterial, addWmsMaterial } from "@/api/ware/wmsMaterial"
import { listWmsMaterialCategory } from "@/api/ware/wmsMaterialCategory"
import { ElMessage } from 'element-plus'
const props = defineProps({
visible: {
......@@ -121,6 +190,42 @@ const selectedMaterials = ref([])
// 物资分类树选项
const materialCategoryOptions = ref([])
// 新增物资相关
const addMaterialVisible = ref(false)
const addMaterialTitle = ref('新增物资')
const addMaterialForm = reactive({
materialCode: '',
materialName: '',
categoryId: null,
specification: '',
unit: '',
manufacturer: '',
safetyStock: null,
status: true
})
// 新增物资表单验证规则
const addMaterialRules = reactive({
materialCode: [
{ required: true, message: '物资编码不能为空', trigger: 'blur' }
],
materialName: [
{ required: true, message: '物资名称不能为空', trigger: 'blur' }
],
categoryId: [
{ required: true, message: '物资分类不能为空', trigger: 'change' }
],
specification: [
{ required: true, message: '规格型号不能为空', trigger: 'blur' }
],
unit: [
{ required: true, message: '计量单位不能为空', trigger: 'blur' }
]
})
// 新增物资表单引用
const addMaterialRef = ref(null)
// 查询参数
const queryParams = reactive({
pageNum: 1,
......@@ -173,6 +278,46 @@ const handleCancel = () => {
dialogVisible.value = false
}
// 打开新增物资对话框
const handleAddMaterial = () => {
addMaterialTitle.value = '新增物资'
// 重置新增表单
if (addMaterialRef.value) {
addMaterialRef.value.resetFields()
}
// 设置默认状态为启用
addMaterialForm.status = true
addMaterialVisible.value = true
}
// 提交新增物资
const submitAddMaterial = () => {
// 表单验证
if (!addMaterialRef.value) return
addMaterialRef.value.validate((valid) => {
if (valid) {
// 提交新增请求
addWmsMaterial(addMaterialForm).then(response => {
// 关闭新增对话框
addMaterialVisible.value = false
// 刷新物资列表
handleQuery()
// 提示新增成功
ElMessage.success('新增物资成功')
}).catch(error => {
console.error('新增物资失败:', error)
ElMessage.error('新增物资失败,请重试')
})
}
})
}
// 取消新增物资
const cancelAddMaterial = () => {
addMaterialVisible.value = false
}
// 查询物资分类下拉树结构
const getTreeselect = () => {
return new Promise((resolve) => {
......
<template>
<el-dialog :title="title" v-model="dialogVisible" width="1000px" append-to-body>
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="80px">
<el-form-item label="天线编码" prop="antennaCode">
<el-input
v-model="queryParams.antennaCode"
placeholder="请输入天线编码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="读写器ID" prop="readerId">
<el-input
v-model="queryParams.readerId"
placeholder="请输入读写器ID"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="仓库ID" prop="warehouseId">
<el-input
v-model="queryParams.warehouseId"
placeholder="请输入仓库ID"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="安装位置" prop="installationLocation">
<el-input
v-model="queryParams.installationLocation"
placeholder="请输入安装位置"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="ptlTagList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="天线ID" align="center" prop="antennaId" />
<el-table-column label="天线编码" align="center" prop="antennaCode" />
<el-table-column label="读写器ID" align="center" prop="readerId" />
<el-table-column label="仓库ID" align="center" prop="warehouseId" />
<el-table-column label="库区ID" align="center" prop="areaId" />
<el-table-column label="货架ID" align="center" prop="locationId" />
<el-table-column label="安装位置" align="center" prop="installationLocation" />
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="handleQuery"
/>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleConfirm">确 定</el-button>
<el-button @click="handleCancel">取 消</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup name="PtlTagSelectDialog">
import { ref, reactive, watch } from 'vue'
import { listWmsRfidAntenna } from "@/api/ware/wmsRfidAntenna"
const props = defineProps({
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: '选择PTL标签'
}
})
const emit = defineEmits(['update:visible', 'confirm', 'cancel'])
// 本地对话框可见性状态
const dialogVisible = ref(false)
// 监听props.visible变化,更新对话框可见性
watch(() => props.visible, (newVal) => {
dialogVisible.value = newVal
})
// 监听dialogVisible变化,向父组件发送更新
watch(dialogVisible, (newVal) => {
emit('update:visible', newVal)
})
// 表格加载状态
const loading = ref(false)
// 分页总条数
const total = ref(0)
// 查询参数
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
antennaCode: undefined,
readerId: undefined,
warehouseId: undefined,
installationLocation: undefined
})
// 表格数据
const ptlTagList = ref([])
// 选中的数据
const selectionList = ref([])
// 初始化
const init = () => {
selectionList.value = []
ptlTagList.value = []
queryParams.pageNum = 1
queryParams.pageSize = 10
queryParams.antennaCode = undefined
queryParams.readerId = undefined
queryParams.warehouseId = undefined
queryParams.installationLocation = undefined
}
// 查询数据
const handleQuery = () => {
loading.value = true
listWmsRfidAntenna(queryParams).then(response => {
ptlTagList.value = response.rows
total.value = response.total
loading.value = false
})
}
// 重置查询
const resetQuery = () => {
queryParams.antennaCode = undefined
queryParams.readerId = undefined
queryParams.warehouseId = undefined
queryParams.installationLocation = undefined
handleQuery()
}
// 处理选择变化
const handleSelectionChange = (selection) => {
selectionList.value = selection
}
// 处理确认选择
const handleConfirm = () => {
if (selectionList.value.length === 0) {
ElMessage.warning('请选择一条记录')
return
}
emit('confirm', selectionList.value)
dialogVisible.value = false
}
// 处理取消
const handleCancel = () => {
emit('cancel')
dialogVisible.value = false
}
// 当对话框打开时初始化数据
watch(() => dialogVisible.value, (newVal) => {
if (newVal) {
init()
handleQuery()
}
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>
\ No newline at end of file
<template>
<el-dialog
:title="title"
:model-value="visible"
@update:model-value="handleClose"
width="600px"
append-to-body
>
<el-form :model="form" label-width="120px">
<!-- 尺寸选择 -->
<el-form-item label="二维码尺寸">
<el-radio-group v-model="form.sizeType" @change="handleSizeChange">
<el-radio label="default">系统默认尺寸</el-radio>
<el-radio label="custom">自定义尺寸</el-radio>
</el-radio-group>
</el-form-item>
<!-- 默认尺寸选择 -->
<el-form-item label="默认尺寸" v-if="form.sizeType === 'default'">
<el-select v-model="form.defaultSize" placeholder="请选择尺寸">
<el-option label="20mm×20mm" :value="{width: 20, height: 20}" />
<el-option label="30mm×30mm" :value="{width: 30, height: 30}" />
<el-option label="40mm×40mm" :value="{width: 40, height: 40}" />
<el-option label="50mm×50mm" :value="{width: 50, height: 50}" />
<el-option label="60mm×60mm" :value="{width: 60, height: 60}" />
</el-select>
</el-form-item>
<!-- 自定义尺寸 -->
<el-form-item label="自定义尺寸" v-if="form.sizeType === 'custom'">
<el-row :gutter="10">
<el-col :span="11">
<el-input-number
v-model="form.customWidth"
:min="10"
:max="200"
:step="1"
placeholder="宽度(mm)"
style="width: 100%"
/>
</el-col>
<el-col :span="2" style="text-align: center; line-height: 38px;">×</el-col>
<el-col :span="11">
<el-input-number
v-model="form.customHeight"
:min="10"
:max="200"
:step="1"
placeholder="高度(mm)"
style="width: 100%"
/>
</el-col>
</el-row>
</el-form-item>
<!-- 预览区域 -->
<el-form-item label="二维码预览">
<div class="qrcode-preview-container">
<div
class="qrcode-preview"
:style="{
width: previewSize.width + 'px',
height: previewSize.height + 'px',
border: '1px solid #dcdfe6'
}"
>
<!-- 这里使用假的二维码预览,实际应该使用二维码生成库 -->
<div class="qrcode-placeholder" v-if="!previewVisible">
点击预览按钮生成二维码
</div>
<div v-else>
<!-- 实际项目中应该使用qrcode库生成二维码 -->
<div class="qrcode-content">
<svg width="100%" height="100%" viewBox="0 0 100 100">
<rect width="100" height="100" fill="white" />
<!-- 简单的二维码样式 -->
<rect x="10" y="10" width="80" height="80" fill="none" stroke="#333" stroke-width="2" />
<rect x="20" y="20" width="10" height="10" fill="#333" />
<rect x="45" y="20" width="10" height="10" fill="#333" />
<rect x="70" y="20" width="10" height="10" fill="#333" />
<rect x="20" y="45" width="10" height="10" fill="#333" />
<rect x="45" y="45" width="10" height="10" fill="#333" />
<rect x="70" y="45" width="10" height="10" fill="#333" />
<rect x="20" y="70" width="10" height="10" fill="#333" />
<rect x="45" y="70" width="10" height="10" fill="#333" />
<rect x="70" y="70" width="10" height="10" fill="#333" />
</svg>
</div>
<div class="qrcode-value" v-if="qrcodeValue">{{ qrcodeValue }}</div>
</div>
</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handlePreview">预览二维码</el-button>
<el-button type="primary" @click="handlePrint">打印</el-button>
<el-button @click="cancel">取消</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive, computed, watch } from 'vue'
// 组件属性
const props = defineProps({
title: {
type: String,
default: '打印二维码'
},
visible: {
type: Boolean,
default: false
},
qrcodeValue: {
type: String,
default: ''
}
})
// 组件事件
const emit = defineEmits(['update:visible', 'print'])
// 表单数据
const form = reactive({
sizeType: 'default', // default: 默认尺寸, custom: 自定义尺寸
defaultSize: { width: 40, height: 40 }, // 默认尺寸
customWidth: 40, // 自定义宽度(mm)
customHeight: 40 // 自定义高度(mm)
})
// 预览相关
const previewVisible = ref(false)
const previewSize = computed(() => {
// 将毫米转换为像素进行预览 (1mm ≈ 3.7795275591px)
const scale = 3.7795275591
let width, height
if (form.sizeType === 'default') {
width = form.defaultSize.width
height = form.defaultSize.height
} else {
width = form.customWidth
height = form.customHeight
}
return {
width: width * scale,
height: height * scale
}
})
// 尺寸变化处理
function handleSizeChange() {
if (form.sizeType === 'custom') {
// 切换到自定义尺寸时,使用当前默认尺寸的值
form.customWidth = form.defaultSize.width
form.customHeight = form.defaultSize.height
}
}
// 预览二维码
function handlePreview() {
previewVisible.value = true
}
// 打印
function handlePrint() {
// 获取当前选择的尺寸 (mm)
let width, height
if (form.sizeType === 'default') {
width = form.defaultSize.width
height = form.defaultSize.height
} else {
width = form.customWidth
height = form.customHeight
}
// 调用父组件的打印方法
emit('print', {
width,
height,
qrcodeValue: props.qrcodeValue
})
// 关闭对话框
cancel()
}
// 处理对话框关闭
function handleClose(newVal) {
emit('update:visible', newVal)
}
// 取消
function cancel() {
emit('update:visible', false)
}
</script>
<style scoped>
.qrcode-preview-container {
display: flex;
justify-content: center;
margin-top: 10px;
}
.qrcode-preview {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px;
background-color: #f5f7fa;
}
.qrcode-placeholder {
color: #909399;
text-align: center;
}
.qrcode-content {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.qrcode-value {
margin-top: 10px;
text-align: center;
font-size: 14px;
color: #606266;
}
</style>
\ No newline at end of file
<template>
<el-dialog :title="title" v-model="dialogVisible" width="1200px" append-to-body>
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="80px">
<el-form-item label="标签编码" prop="tagCode">
<el-input
v-model="queryParams.tagCode"
placeholder="请输入标签编码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="EPC编码" prop="epcCode">
<el-input
v-model="queryParams.epcCode"
placeholder="请输入EPC编码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="TID编码" prop="tidCode">
<el-input
v-model="queryParams.tidCode"
placeholder="请输入TID编码"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="标签类型" prop="tagType">
<el-input
v-model="queryParams.tagType"
placeholder="请输入标签类型"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="标签状态" prop="tagStatus">
<el-input
v-model="queryParams.tagStatus"
placeholder="请输入标签状态"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="rfidTagList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="标签ID" align="center" prop="tagId" />
<el-table-column label="标签编码" align="center" prop="tagCode" />
<el-table-column label="EPC编码" align="center" prop="epcCode" />
<el-table-column label="TID编码" align="center" prop="tidCode" />
<el-table-column label="标签类型" align="center" prop="tagType" />
<el-table-column label="标签状态" align="center" prop="tagStatus" />
<el-table-column label="最后读取时间" align="center" prop="lastReadTime">
<template #default="scope">
<span>{{ parseTime(scope.row.lastReadTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="handleQuery"
/>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleConfirm"> </el-button>
<el-button @click="handleCancel"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup name="RfidTagSelectDialog">
import { ref, reactive, watch } from 'vue'
import { listWmsRfidTag } from "@/api/ware/wmsRfidTag"
import { parseTime } from "@/utils/ruoyi"
const props = defineProps({
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: '选择RFID标签'
}
})
const emit = defineEmits(['update:visible', 'confirm', 'cancel'])
// 本地对话框可见性状态
const dialogVisible = ref(false)
// 监听props.visible变化,更新对话框可见性
watch(() => props.visible, (newVal) => {
dialogVisible.value = newVal
})
// 监听dialogVisible变化,向父组件发送更新
watch(dialogVisible, (newVal) => {
emit('update:visible', newVal)
})
// 表格加载状态
const loading = ref(false)
// 分页总条数
const total = ref(0)
// 查询参数
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
tagCode: undefined,
epcCode: undefined,
tidCode: undefined,
tagType: undefined,
tagStatus: undefined
})
// 表格数据
const rfidTagList = ref([])
// 选中的数据
const selectionList = ref([])
// 初始化
const init = () => {
selectionList.value = []
rfidTagList.value = []
queryParams.pageNum = 1
queryParams.pageSize = 10
queryParams.tagCode = undefined
queryParams.epcCode = undefined
queryParams.tidCode = undefined
queryParams.tagType = undefined
queryParams.tagStatus = undefined
}
// 查询数据
const handleQuery = () => {
loading.value = true
listWmsRfidTag(queryParams).then(response => {
rfidTagList.value = response.rows
total.value = response.total
loading.value = false
})
}
// 重置查询
const resetQuery = () => {
queryParams.tagCode = undefined
queryParams.epcCode = undefined
queryParams.tidCode = undefined
queryParams.tagType = undefined
queryParams.tagStatus = undefined
handleQuery()
}
// 处理选择变化
const handleSelectionChange = (selection) => {
selectionList.value = selection
}
// 处理确认选择
const handleConfirm = () => {
if (selectionList.value.length === 0) {
ElMessage.warning('请选择一条记录')
return
}
emit('confirm', selectionList.value)
dialogVisible.value = false
}
// 处理取消
const handleCancel = () => {
emit('cancel')
dialogVisible.value = false
}
// 当对话框打开时初始化数据
watch(() => dialogVisible.value, (newVal) => {
if (newVal) {
init()
handleQuery()
}
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>
\ No newline at end of file
......@@ -2,28 +2,17 @@
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="库区编码" prop="areaCode">
<el-input
v-model="queryParams.areaCode"
placeholder="请输入库区编码"
clearable
@keyup.enter="handleQuery"
/>
<el-input v-model="queryParams.areaCode" placeholder="请输入库区编码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="库区名称" prop="areaName">
<el-input
v-model="queryParams.areaName"
placeholder="请输入库区名称"
clearable
@keyup.enter="handleQuery"
/>
<el-input v-model="queryParams.areaName" placeholder="请输入库区名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="所属仓库" prop="warehouseId">
<el-input
v-model="queryParams.warehouseId"
placeholder="请输入所属仓库ID"
clearable
@keyup.enter="handleQuery"
/>
<el-input v-model="queryParams.warehouseId" placeholder="请选择仓库" readonly clearable style="width: 280px;">
<template #append>
<el-button type="primary" @click="openQueryWarehouseSelect">选择仓库</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
......@@ -33,54 +22,25 @@
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['ware:wmsArea:add']"
>新增</el-button>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['ware:wmsArea:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['ware:wmsArea:edit']"
>修改</el-button>
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
v-hasPermi="['ware:wmsArea:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['ware:wmsArea:remove']"
>删除</el-button>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
v-hasPermi="['ware:wmsArea:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['ware:wmsArea:export']"
>导出</el-button>
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['ware:wmsArea:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table
v-loading="loading"
:data="wmsAreaList"
default-expand-all
@selection-change="handleSelectionChange"
row-key="areaId"
:tree-props="{ children: 'children' }"
>
<el-table v-loading="loading" :data="wmsAreaList" default-expand-all @selection-change="handleSelectionChange"
row-key="areaId" :tree-props="{ children: 'children' }">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="库区编码" align="center" prop="areaCode" />
<el-table-column label="库区名称" align="center" prop="areaName" />
......@@ -97,13 +57,16 @@
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['ware:wmsArea:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['ware:wmsArea:remove']">删除</el-button>
<el-button link type="primary" icon="Plus" @click="handleAddSub(scope.row)" v-hasPermi="['ware:wmsArea:add']">添加下级</el-button>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['ware:wmsArea:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['ware:wmsArea:remove']">删除</el-button>
<el-button link type="primary" icon="Plus" @click="handleAddSub(scope.row)"
v-hasPermi="['ware:wmsArea:add']">添加下级</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改库区信息对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="wmsAreaRef" :model="form" :rules="rules" label-width="80px">
......@@ -114,23 +77,15 @@
<el-input v-model="form.areaName" placeholder="请输入库区名称" />
</el-form-item>
<el-form-item label="所属仓库" prop="warehouseId">
<el-row :gutter="10">
<el-col :span="18">
<el-input v-model="form.warehouseId" placeholder="请选择仓库" readonly />
</el-col>
<el-col :span="6">
<el-input v-model="form.warehouseId" placeholder="请选择仓库" readonly clearable>
<template #append>
<el-button type="primary" @click="openWarehouseSelect">选择仓库</el-button>
</el-col>
</el-row>
</template>
</el-input>
</el-form-item>
<el-form-item label="父库区" prop="parentId">
<el-cascader
v-model="form.parentId"
:options="wmsAreaOptions"
:props="{ value: 'areaId', label: 'areaName', checkStrictly: true }"
placeholder="请选择父库区"
clearable
/>
<el-cascader v-model="form.parentId" :options="wmsAreaOptions"
:props="{ value: 'areaId', label: 'areaName', checkStrictly: true }" placeholder="请选择父库区" clearable />
</el-form-item>
<el-form-item label="温度范围" prop="temperatureRange">
<el-input v-model="form.temperatureRange" placeholder="请输入温度范围" />
......@@ -154,12 +109,8 @@
</el-dialog>
<!-- 仓库选择对话框组件 -->
<WarehouseSelectDialog
ref="warehouseSelectDialogRef"
v-model:visible="warehouseDialogVisible"
title="选择仓库"
@confirm="handleWarehouseConfirm"
/>
<WarehouseSelectDialog ref="warehouseSelectDialogRef" v-model:visible="warehouseDialogVisible" title="选择仓库"
@confirm="handleWarehouseConfirm" />
</div>
</template>
......@@ -170,7 +121,7 @@ import { handleTree } from "@/utils/ruoyi"
const { proxy } = getCurrentInstance()
const {sys_normal_disable} = proxy.useDict('sys_normal_disable')
const { sys_normal_disable } = proxy.useDict('sys_normal_disable')
const wmsAreaList = ref([])
const open = ref(false)
......@@ -186,6 +137,8 @@ const title = ref("")
const warehouseDialogVisible = ref(false)
// 仓库选择对话框实例引用
const warehouseSelectDialogRef = ref(null)
// 标记当前是否为查询表单的仓库选择
const isQueryWarehouseSelect = ref(false)
// 库区下拉树选项
const wmsAreaOptions = ref([])
......@@ -333,12 +286,12 @@ function submitForm() {
/** 删除按钮操作 */
function handleDelete(row) {
const _areaIds = row.areaId || ids.value
proxy.$modal.confirm('是否确认删除库区信息编号为"' + _areaIds + '"的数据项?').then(function() {
proxy.$modal.confirm('是否确认删除库区信息编号为"' + _areaIds + '"的数据项?').then(function () {
return delWmsArea(_areaIds)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}).catch(() => { })
}
/** 导出按钮操作 */
......@@ -348,8 +301,18 @@ function handleExport() {
}, `wmsArea_${new Date().getTime()}.xlsx`)
}
/** 打开仓库选择对话框 */
/** 打开搜索表单仓库选择对话框 */
function openQueryWarehouseSelect() {
isQueryWarehouseSelect.value = true
warehouseDialogVisible.value = true
if (warehouseSelectDialogRef.value) {
warehouseSelectDialogRef.value.handleQuery()
}
}
/** 打开编辑表单仓库选择对话框 */
function openWarehouseSelect() {
isQueryWarehouseSelect.value = false
warehouseDialogVisible.value = true
if (warehouseSelectDialogRef.value) {
warehouseSelectDialogRef.value.handleQuery()
......@@ -360,7 +323,11 @@ function openWarehouseSelect() {
function handleWarehouseConfirm(selectedWarehouses) {
if (selectedWarehouses.length > 0) {
const warehouse = selectedWarehouses[0]
form.value.warehouseId = warehouse.warehouseId
if (isQueryWarehouseSelect.value) {
queryParams.value.warehouseId = warehouse.warehouseId
} else {
form.value.warehouseId = warehouse.warehouseId
}
// 可以根据需要添加更多仓库信息字段
}
}
......
......@@ -33,14 +33,6 @@
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="批号" prop="lotNo">
<el-input
v-model="queryParams.lotNo"
placeholder="请输入批号"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="生产日期" prop="productionDate">
<el-date-picker clearable
v-model="queryParams.productionDate"
......@@ -82,20 +74,11 @@
/>
</el-form-item>
<el-form-item label="是否FIFO管理" prop="isFifo">
<el-input
v-model="queryParams.isFifo"
placeholder="请输入是否FIFO管理"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="最后RFID检测时间" prop="lastRfidDetectTime">
<el-date-picker clearable
v-model="queryParams.lastRfidDetectTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择最后RFID检测时间">
</el-date-picker>
<el-radio-group v-model="queryParams.isFifo">
<el-radio v-for="item in sys_yes_no" :label="item.value" :key="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
......@@ -159,10 +142,7 @@
<el-table-column label="物资ID" align="center" prop="materialId" />
<el-table-column label="仓库ID" align="center" prop="warehouseId" />
<el-table-column label="货架ID" align="center" prop="locationId" />
<el-table-column label="货架编码" align="center" prop="locationCode" />
<el-table-column label="货架名称" align="center" prop="locationName" />
<el-table-column label="批次号" align="center" prop="batchNo" />
<el-table-column label="批号" align="center" prop="lotNo" />
<el-table-column label="生产日期" align="center" prop="productionDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.productionDate, '{y}-{m}-{d}') }}</span>
......@@ -192,14 +172,18 @@
</el-table-column>
<el-table-column label="RFID标签" align="center" prop="rfidTag" />
<el-table-column label="条形码" align="center" prop="barcode" />
<el-table-column label="是否FIFO管理" align="center" prop="isFifo" />
<el-table-column label="是否FIFO管理" align="center" prop="isFifo">
<template #default="scope">
<dict-tag :options="sys_yes_no" :value="scope.row.isFifo" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="RFID绑定数量" align="center" prop="rfidBindingCount" />
<el-table-column label="最后RFID检测时间" align="center" prop="lastRfidDetectTime" width="180">
<!-- <el-table-column label="最后RFID检测时间" align="center" prop="lastRfidDetectTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.lastRfidDetectTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
</el-table-column> -->
<el-table-column label="RFID覆盖率" align="center" prop="rfidCoverageRate" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="220" fixed="right">
<template #default="scope">
......@@ -383,7 +367,11 @@
</el-col>
<el-col :span="12">
<el-form-item label="是否FIFO管理" prop="isFifo">
<el-input v-model="form.isFifo" placeholder="请输入是否FIFO管理" />
<el-radio-group v-model="form.isFifo">
<el-radio v-for="item in sys_yes_no" :label="item.value" :key="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
......@@ -591,6 +579,7 @@ import InventoryFlowDialog from "@/components/InventoryFlowDialog.vue"
import { View, CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons-vue'
const { proxy } = getCurrentInstance()
const {sys_yes_no} = proxy.useDict('sys_yes_no')
const wmsInventoryList = ref([])
const open = ref(false)
......
......@@ -96,7 +96,11 @@
<el-table-column label="长度" align="center" prop="length" />
<el-table-column label="宽度" align="center" prop="width" />
<el-table-column label="高度" align="center" prop="height" />
<el-table-column label="状态" align="center" prop="status" />
<el-table-column label="状态" align="center" prop="status" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="RFID天线ID" align="center" prop="rfidAntennaId" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
......@@ -192,6 +196,8 @@ import AreaSelectTreeDialog from "@/components/AreaSelectTreeDialog.vue"
const { proxy } = getCurrentInstance()
const {sys_normal_disable} = proxy.useDict('sys_normal_disable')
const wmsLocationList = ref([])
const open = ref(false)
const loading = ref(true)
......
......@@ -129,9 +129,9 @@
</el-row>
<el-table v-loading="loading" :data="wmsMaterialList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="物资编码" align="center" prop="materialCode" width="150" />
<el-table-column label="物资名称" align="center" prop="materialName" />
<el-table-column type="selection" width="55" align="center" fixed="left" />
<el-table-column label="物资编码" align="center" prop="materialCode" width="150" fixed="left" />
<el-table-column label="物资名称" align="center" prop="materialName" fixed="left"/>
<el-table-column label="物资分类" align="center" prop="categoryId" />
<el-table-column label="规格型号" align="center" prop="specification" />
<el-table-column label="计量单位" align="center" prop="unit" />
......@@ -188,13 +188,13 @@
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="是否RFID管理" align="center" prop="isRfidManaged" width="100">
<!-- <el-table-column label="是否RFID管理" align="center" prop="isRfidManaged" width="100">
<template #default="scope">
<dict-tag :options="custom_yes_no" :value="scope.row.isRfidManaged" />
</template>
</el-table-column>
<el-table-column label="RFID标签" align="center" prop="rfidStandard" />
<el-table-column label="RFID粘贴位置" align="center" prop="rfidPosition" />
<el-table-column label="RFID粘贴位置" align="center" prop="rfidPosition" /> -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['ware:wmsMaterial:edit']">修改</el-button>
......@@ -351,7 +351,7 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否RFID管理" prop="isRfidManaged">
<el-input v-model="form.isRfidManaged" placeholder="请输入是否RFID管理" />
......@@ -369,10 +369,10 @@
<el-input v-model="form.rfidPosition" placeholder="请输入RFID粘贴位置" />
</el-form-item>
</el-col>
</el-row>
</el-row> -->
<!-- 自定义属性扩展 -->
<el-divider>自定义属性</el-divider>
<!-- <el-divider>自定义属性</el-divider>
<el-form-item>
<el-button type="primary" plain size="small" @click="showCustomAttrDialog = true">添加属性</el-button>
<el-table :data="form.customAttributes" border style="margin-top: 10px;">
......@@ -390,7 +390,7 @@
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form-item> -->
</el-form>
<!-- 自定义属性编辑对话框 -->
......
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
corePlugins: {
preflight: false, // 禁用Tailwind的基础样式,避免与Element Plus的CSS变量冲突
},
}
\ No newline at end of file
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
import createVitePlugins from './vite/plugins'
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
const baseUrl = 'http://192.168.19.88:10011' // 后端接口
......@@ -62,6 +64,8 @@ export default defineConfig(({ mode, command }) => {
css: {
postcss: {
plugins: [
tailwindcss(),
autoprefixer(),
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment