✨ feat(mes): 添加条码相关组件和逻辑
新增条码格式枚举、条码生成组件及其相关 API,支持条码的创建、查看和配置功能。实现了条码的自动生成逻辑,并优化了条码配置管理界面,提升用户体验。 - 新增 Barcode 组件用于条码展示 - 实现条码生成和下载功能 - 添加条码配置管理功能pull/871/MERGE
parent
e275ef417e
commit
c12d7616f2
|
|
@ -53,6 +53,7 @@
|
||||||
"element-plus": "2.11.1",
|
"element-plus": "2.11.1",
|
||||||
"fast-xml-parser": "^4.3.2",
|
"fast-xml-parser": "^4.3.2",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
|
"jsbarcode": "^3.12.3",
|
||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"jsoneditor": "^10.1.3",
|
"jsoneditor": "^10.1.3",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,9 @@ importers:
|
||||||
highlight.js:
|
highlight.js:
|
||||||
specifier: ^11.9.0
|
specifier: ^11.9.0
|
||||||
version: 11.10.0
|
version: 11.10.0
|
||||||
|
jsbarcode:
|
||||||
|
specifier: ^3.12.3
|
||||||
|
version: 3.12.3
|
||||||
jsencrypt:
|
jsencrypt:
|
||||||
specifier: ^3.3.2
|
specifier: ^3.3.2
|
||||||
version: 3.3.2
|
version: 3.3.2
|
||||||
|
|
@ -3669,6 +3672,9 @@ packages:
|
||||||
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
jsbarcode@3.12.3:
|
||||||
|
resolution: {integrity: sha512-CuHU9hC6dPsHF5oVFMo8NW76uQVjH4L22CsP4hW+dNnGywJHC/B0ThA1CTDVLnxKLrrpYdicBLnd2xsgTfRnvg==, tarball: https://registry.npmmirror.com/jsbarcode/-/jsbarcode-3.12.3.tgz}
|
||||||
|
|
||||||
jsencrypt@3.3.2:
|
jsencrypt@3.3.2:
|
||||||
resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
|
resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
|
||||||
|
|
||||||
|
|
@ -4603,7 +4609,7 @@ packages:
|
||||||
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
|
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
|
||||||
|
|
||||||
source-map@0.6.1:
|
source-map@0.6.1:
|
||||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, tarball: https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
split2@4.2.0:
|
split2@4.2.0:
|
||||||
|
|
@ -9023,6 +9029,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
argparse: 2.0.1
|
argparse: 2.0.1
|
||||||
|
|
||||||
|
jsbarcode@3.12.3: {}
|
||||||
|
|
||||||
jsencrypt@3.3.2: {}
|
jsencrypt@3.3.2: {}
|
||||||
|
|
||||||
jsesc@3.0.2: {}
|
jsesc@3.0.2: {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
<template>
|
||||||
|
<Dialog :title="dialogTitle" v-model="dialogVisible" width="600px">
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="100px"
|
||||||
|
v-loading="formLoading"
|
||||||
|
>
|
||||||
|
<el-form-item label="条码格式" prop="format">
|
||||||
|
<el-select v-model="formData.format" placeholder="请选择条码格式" class="!w-240px">
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.MES_BARCODE_FORMAT)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="业务类型" prop="bizType">
|
||||||
|
<el-select v-model="formData.bizType" placeholder="请选择业务类型" class="!w-240px">
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.MES_BARCODE_BIZ_TYPE)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- TODO @AI:需要根据 bizType,使用不同业务的 select; -->
|
||||||
|
<el-form-item label="业务编号" prop="bizId">
|
||||||
|
<el-input-number v-model="formData.bizId" :min="1" class="!w-240px" />
|
||||||
|
</el-form-item>
|
||||||
|
<!-- TODO @AI:bizCode、bizName 根据上面的 select 进行设置;必填!(后端校验也加下) -->
|
||||||
|
<el-form-item label="业务编码" prop="bizCode">
|
||||||
|
<el-input v-model="formData.bizCode" placeholder="请输入业务编码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="业务名称" prop="bizName">
|
||||||
|
<el-input v-model="formData.bizName" placeholder="请输入业务名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" prop="status">
|
||||||
|
<el-radio-group v-model="formData.status">
|
||||||
|
<el-radio
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.value"
|
||||||
|
>
|
||||||
|
{{ dict.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
|
||||||
|
import { BarcodeApi, BarcodeVO } from '@/api/mes/wm/barcode'
|
||||||
|
|
||||||
|
defineOptions({ name: 'BarcodeForm' })
|
||||||
|
|
||||||
|
// TODO @AI:注释参考 /Users/yunai/Java/yudao-all-in-one/yudao-ui-admin-vue3/src/views/system/user/UserForm.vue
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const dialogTitle = ref('')
|
||||||
|
const formLoading = ref(false)
|
||||||
|
const formType = ref('')
|
||||||
|
const formData = ref({
|
||||||
|
id: undefined,
|
||||||
|
format: undefined,
|
||||||
|
bizType: undefined,
|
||||||
|
bizId: undefined,
|
||||||
|
bizCode: '',
|
||||||
|
bizName: '',
|
||||||
|
status: 0,
|
||||||
|
remark: ''
|
||||||
|
})
|
||||||
|
const formRules = reactive({
|
||||||
|
format: [{ required: true, message: '条码格式不能为空', trigger: 'change' }],
|
||||||
|
bizType: [{ required: true, message: '业务类型不能为空', trigger: 'change' }],
|
||||||
|
bizId: [{ required: true, message: '业务编号不能为空', trigger: 'blur' }],
|
||||||
|
bizCode: [{ required: true, message: '业务编码不能为空', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (type: string, id?: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = type === 'create' ? '新增条码' : '修改条码'
|
||||||
|
formType.value = type
|
||||||
|
resetForm()
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
formData.value = await BarcodeApi.getBarcode(id)
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineExpose({ open })
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success'])
|
||||||
|
const submitForm = async () => {
|
||||||
|
await formRef.value.validate()
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = formData.value as unknown as BarcodeVO
|
||||||
|
if (formType.value === 'create') {
|
||||||
|
await BarcodeApi.createBarcode(data)
|
||||||
|
message.success(t('common.createSuccess'))
|
||||||
|
} else {
|
||||||
|
await BarcodeApi.updateBarcode(data)
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
id: undefined,
|
||||||
|
format: undefined,
|
||||||
|
bizType: undefined,
|
||||||
|
bizId: undefined,
|
||||||
|
bizCode: '',
|
||||||
|
bizName: '',
|
||||||
|
status: 0, // TODO @AI:枚举类;commonstatusenum;
|
||||||
|
remark: ''
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,281 @@
|
||||||
|
<template>
|
||||||
|
<!--
|
||||||
|
TODO @AI:挪到 /Users/yunai/Java/yudao-all-in-one/yudao-ui-admin-vue3/src/views/mes/wm/barcode/components 里,改名为 BarcodeDetail;
|
||||||
|
TODO @AI:参数有 2 种:1)一种是目前这种 BarcodeData;2)在加一种是 bizId + bizType 组合,然后去加载 BarcodeData
|
||||||
|
// TODO @AI:BarcodeData 去掉,直接使用 BarcodeVO 就好了;
|
||||||
|
-->
|
||||||
|
<Dialog title="查看条码" v-model="dialogVisible" width="500px" :close-on-click-modal="false">
|
||||||
|
<div class="barcode-view-container">
|
||||||
|
<!-- 条码显示区域 -->
|
||||||
|
<div class="barcode-display">
|
||||||
|
<div v-if="barcodeData.content" class="barcode-wrapper">
|
||||||
|
<!-- TODO @AI:二维码不够大 -->
|
||||||
|
<Barcode
|
||||||
|
ref="barcodeRef"
|
||||||
|
:content="barcodeData.content"
|
||||||
|
:format="barcodeData.format"
|
||||||
|
:width="300"
|
||||||
|
:height="150"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else description="暂无条码数据" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 条码详细信息 -->
|
||||||
|
<!-- TODO @AI:统一左对齐;目前貌似没左对齐; -->
|
||||||
|
<el-descriptions :column="1" border class="barcode-info">
|
||||||
|
<el-descriptions-item label="条码格式" label-align="center" align="left">
|
||||||
|
<!-- TODO @AI:不用 String -->
|
||||||
|
<dict-tag :type="DICT_TYPE.MES_BARCODE_FORMAT" :value="String(barcodeData.format)" />
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="业务类型" label-align="center" align="left">
|
||||||
|
<!-- TODO @AI:不用 String -->
|
||||||
|
<dict-tag :type="DICT_TYPE.MES_BARCODE_BIZ_TYPE" :value="String(barcodeData.bizType)" />
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="条码内容" label-align="center" align="left">
|
||||||
|
<el-tooltip :content="barcodeData.content" placement="top">
|
||||||
|
<span class="content-text">{{ barcodeData.content }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="业务编码" label-align="center" align="left">
|
||||||
|
{{ barcodeData.bizCode || '-' }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="业务名称" label-align="center" align="left">
|
||||||
|
{{ barcodeData.bizName || '-' }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="状态" label-align="center" align="left">
|
||||||
|
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="String(barcodeData.status)" />
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="创建时间" label-align="center" align="left">
|
||||||
|
{{ formatDate(barcodeData.createTime) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<!-- TODO @AI:如果没二维码的情况,需要支持【生成】 -->
|
||||||
|
<template #footer>
|
||||||
|
<el-button type="primary" @click="handlePrint">
|
||||||
|
<Icon icon="ep:printer" class="mr-5px" /> 打印
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="handleDownload">
|
||||||
|
<Icon icon="ep:download" class="mr-5px" /> 下载
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">关 闭</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
import { DICT_TYPE } from '@/utils/dict'
|
||||||
|
import { formatDate } from '@/utils/formatTime'
|
||||||
|
import { Barcode } from './components'
|
||||||
|
|
||||||
|
defineOptions({ name: 'BarcodeViewDialog' })
|
||||||
|
|
||||||
|
interface BarcodeData {
|
||||||
|
id?: number
|
||||||
|
format?: number
|
||||||
|
bizType?: number
|
||||||
|
content: string
|
||||||
|
bizCode?: string
|
||||||
|
bizName?: string
|
||||||
|
status?: number
|
||||||
|
createTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const barcodeRef = ref<InstanceType<typeof Barcode>>()
|
||||||
|
const barcodeData = ref<BarcodeData>({
|
||||||
|
format: undefined,
|
||||||
|
bizType: undefined,
|
||||||
|
content: '',
|
||||||
|
bizCode: '',
|
||||||
|
bizName: '',
|
||||||
|
status: undefined,
|
||||||
|
createTime: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = (row: BarcodeData) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
barcodeData.value = { ...row }
|
||||||
|
}
|
||||||
|
defineExpose({ open })
|
||||||
|
|
||||||
|
/** 打印条码 */
|
||||||
|
// TODO @AI:【晚点弄】打印可以在当前界面么?你先回复我;
|
||||||
|
const handlePrint = () => {
|
||||||
|
if (!barcodeRef.value) {
|
||||||
|
message.warning('条码组件未加载')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const base64 = barcodeRef.value.getImageBase64?.()
|
||||||
|
if (!base64) {
|
||||||
|
message.warning('条码生成失败,无法打印')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建打印窗口
|
||||||
|
const printWindow = window.open('', '_blank')
|
||||||
|
if (!printWindow) {
|
||||||
|
message.error('无法打开打印窗口,请检查浏览器设置')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const html = `<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>打印条码</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; }
|
||||||
|
body { font-family: Arial, sans-serif; padding: 20px; }
|
||||||
|
.print-container { text-align: center; }
|
||||||
|
.barcode-img { max-width: 100%; margin: 20px 0; }
|
||||||
|
.info { margin-top: 20px; text-align: left; font-size: 12px; }
|
||||||
|
.info p { margin: 5px 0; }
|
||||||
|
@media print {
|
||||||
|
body { padding: 0; }
|
||||||
|
.print-container { padding: 20px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="print-container">
|
||||||
|
<img src="${base64}" class="barcode-img" alt="条码" />
|
||||||
|
<div class="info">
|
||||||
|
<p><strong>业务编码:</strong> ${escapeHtml(barcodeData.value.bizCode || '')}</p>
|
||||||
|
<p><strong>业务名称:</strong> ${escapeHtml(barcodeData.value.bizName || '')}</p>
|
||||||
|
<p><strong>条码内容:</strong> ${escapeHtml(barcodeData.value.content || '')}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
|
||||||
|
printWindow.document.write(html)
|
||||||
|
printWindow.document.close()
|
||||||
|
|
||||||
|
// 延迟打印,确保内容加载完成
|
||||||
|
printWindow.onload = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
printWindow.print()
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('打印失败:', error)
|
||||||
|
message.error('打印失败,请重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 下载条码 */
|
||||||
|
// TODO @AI:下载有工具类的,看看复用下;download;
|
||||||
|
const handleDownload = () => {
|
||||||
|
if (!barcodeRef.value) {
|
||||||
|
message.warning('条码组件未加载')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const base64 = barcodeRef.value.getImageBase64?.()
|
||||||
|
if (!base64) {
|
||||||
|
message.warning('条码生成失败,无法下载')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 将 base64 转换为 Blob
|
||||||
|
const arr = base64.split(',')
|
||||||
|
const mime = arr[0].match(/:(.*?);/)?.[1] || 'image/png'
|
||||||
|
const bstr = atob(arr[1])
|
||||||
|
const n = bstr.length
|
||||||
|
const u8arr = new Uint8Array(n)
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
u8arr[i] = bstr.charCodeAt(i)
|
||||||
|
}
|
||||||
|
const blob = new Blob([u8arr], { type: mime })
|
||||||
|
|
||||||
|
// 创建下载链接
|
||||||
|
const url = URL.createObjectURL(blob)
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.download = `barcode_${barcodeData.value.bizCode || 'unknown'}_${Date.now()}.png`
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
|
||||||
|
message.success('下载成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('下载失败:', error)
|
||||||
|
message.error('下载失败,请重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** HTML 转义函数,防止 XSS */
|
||||||
|
// TODO @AI:是不是搞成一个公共方法;
|
||||||
|
const escapeHtml = (text: string): string => {
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
"'": '''
|
||||||
|
}
|
||||||
|
return text.replace(/[&<>"']/g, (char) => map[char])
|
||||||
|
}
|
||||||
|
// TODO @AI:下面的 css,尽量用 unocss;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.barcode-view-container {
|
||||||
|
.barcode-display {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 200px;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.barcode-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.barcode-info {
|
||||||
|
margin-top: 0;
|
||||||
|
|
||||||
|
:deep(.el-descriptions__body) {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-descriptions-item__label) {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #606266;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-descriptions-item__content) {
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-text {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 300px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// TODO @AI:迁移到 /Users/yunai/Java/yudao-all-in-one/yudao-ui-admin-vue3/src/views/mes/utils/constants.ts
|
||||||
|
/**
|
||||||
|
* 条码格式枚举
|
||||||
|
*/
|
||||||
|
export enum BarcodeFormatEnum {
|
||||||
|
QR_CODE = 1,
|
||||||
|
EAN13 = 2,
|
||||||
|
CODE39 = 3,
|
||||||
|
UPC_A = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 条码格式映射表
|
||||||
|
*/
|
||||||
|
// TODO @AI:拿到需要的地方,貌似就一次性的;
|
||||||
|
export const BARCODE_FORMAT_MAP: Record<BarcodeFormatEnum, string> = {
|
||||||
|
[BarcodeFormatEnum.QR_CODE]: 'QR_CODE',
|
||||||
|
[BarcodeFormatEnum.EAN13]: 'EAN13',
|
||||||
|
[BarcodeFormatEnum.CODE39]: 'CODE39',
|
||||||
|
[BarcodeFormatEnum.UPC_A]: 'UPC_A'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为有效的条码格式
|
||||||
|
*/
|
||||||
|
// TODO @AI:去掉,拿到需要的地方;
|
||||||
|
export const isValidBarcodeFormat = (format: number): boolean => {
|
||||||
|
return Object.values(BarcodeFormatEnum).includes(format)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,261 @@
|
||||||
|
<template>
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form
|
||||||
|
class="-mb-15px"
|
||||||
|
:model="queryParams"
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
label-width="68px"
|
||||||
|
>
|
||||||
|
<el-form-item label="业务类型" prop="bizType">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.bizType"
|
||||||
|
placeholder="请选择业务类型"
|
||||||
|
clearable
|
||||||
|
class="!w-240px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.MES_BARCODE_BIZ_TYPE)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="业务编码" prop="bizCode">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.bizCode"
|
||||||
|
placeholder="请输入业务编码"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- TODO @AI:前后端筛选,额外增加 bizName -->
|
||||||
|
<el-form-item label="条码内容" prop="content">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.content"
|
||||||
|
placeholder="请输入条码内容"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||||
|
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
@click="openForm('create')"
|
||||||
|
v-hasPermi="['mes:wm-barcode:create']"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
@click="handleDelete()"
|
||||||
|
:disabled="!selectedIds.length"
|
||||||
|
v-hasPermi="['mes:wm-barcode:delete']"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:delete" class="mr-5px" /> 删除
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
plain
|
||||||
|
@click="handleConfig"
|
||||||
|
v-hasPermi="['mes:wm-barcode-config:query']"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:setting" class="mr-5px" /> 条码设置
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="条码" align="center" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<!-- TODO @AI:改成【操作】那,有个【查看】点击开; -->
|
||||||
|
<div class="barcode-preview" @click="handleView(scope.row)">
|
||||||
|
<Barcode
|
||||||
|
v-if="scope.row.content"
|
||||||
|
:content="scope.row.content"
|
||||||
|
:format="scope.row.format"
|
||||||
|
:width="120"
|
||||||
|
:height="60"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="条码格式" align="center" prop="format">
|
||||||
|
<template #default="scope">
|
||||||
|
<!-- TODO @AI:MES_BARCODE_FORMAT => MES_WM_BARCODE_FORMAT -->
|
||||||
|
<dict-tag :type="DICT_TYPE.MES_BARCODE_FORMAT" :value="scope.row.format" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="业务类型" align="center" prop="bizType">
|
||||||
|
<!-- TODO @AI:MES_BARCODE_BIZ_TYPE => MES_WM_BARCODE_BIZ_TYPE -->
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.MES_BARCODE_BIZ_TYPE" :value="scope.row.bizType" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="条码内容" align="center" prop="content" show-overflow-tooltip />
|
||||||
|
<el-table-column label="业务编码" align="center" prop="bizCode" />
|
||||||
|
<el-table-column label="业务名称" align="center" prop="bizName" show-overflow-tooltip />
|
||||||
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" width="180px" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
@click="handleView(scope.row)"
|
||||||
|
v-hasPermi="['mes:wm-barcode:query']"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
@click="openForm('update', scope.row.id)"
|
||||||
|
v-hasPermi="['mes:wm-barcode:update']"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
type="danger"
|
||||||
|
@click="handleDelete(scope.row.id)"
|
||||||
|
v-hasPermi="['mes:wm-barcode:delete']"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 表单弹窗:添加/修改 -->
|
||||||
|
<BarcodeForm ref="formRef" @success="getList" />
|
||||||
|
|
||||||
|
<!-- 查看弹窗 -->
|
||||||
|
<BarcodeViewDialog ref="viewDialogRef" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
|
||||||
|
import { BarcodeApi } from '@/api/mes/wm/barcode'
|
||||||
|
import { Barcode } from './components'
|
||||||
|
import BarcodeForm from './BarcodeForm.vue'
|
||||||
|
import BarcodeViewDialog from './BarcodeViewDialog.vue'
|
||||||
|
|
||||||
|
defineOptions({ name: 'MesWmBarcode' })
|
||||||
|
|
||||||
|
const message = useMessage()
|
||||||
|
const { t } = useI18n()
|
||||||
|
const { push } = useRouter()
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
const list = ref([])
|
||||||
|
const total = ref(0)
|
||||||
|
const selectedIds = ref<number[]>([])
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
bizType: undefined,
|
||||||
|
bizCode: undefined,
|
||||||
|
content: undefined
|
||||||
|
})
|
||||||
|
const queryFormRef = ref()
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await BarcodeApi.getBarcodePage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection: any[]) => {
|
||||||
|
selectedIds.value = selection.map((item) => item.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加/修改操作 */
|
||||||
|
const formRef = ref()
|
||||||
|
const openForm = (type: string, id?: number) => {
|
||||||
|
formRef.value.open(type, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (id?: number) => {
|
||||||
|
const ids = id ? [id] : selectedIds.value
|
||||||
|
try {
|
||||||
|
await message.delConfirm()
|
||||||
|
await Promise.all(ids.map((id) => BarcodeApi.deleteBarcode(id)))
|
||||||
|
message.success(t('common.delSuccess'))
|
||||||
|
await getList()
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 查看条码 */
|
||||||
|
const viewDialogRef = ref()
|
||||||
|
const handleView = (row: any) => {
|
||||||
|
viewDialogRef.value.open(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 条码设置 */
|
||||||
|
const handleConfig = () => {
|
||||||
|
// TODO @AI:后续改成 name,方便路由调整!
|
||||||
|
push('/mes/wm/barcode/config')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
// TODO @AI:下面的 scss 尽量使用 unocss;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.barcode-preview {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue