|
@@ -326,19 +326,46 @@
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
|
|
|
|
|
<!-- 生成二维码弹窗 -->
|
|
<!-- 生成二维码弹窗 -->
|
|
|
- <el-dialog :title="qrTitle" :visible.sync="qrVisible" width="420px" append-to-body>
|
|
|
|
|
- <div class="qr-card" ref="qrCard">
|
|
|
|
|
- <div class="qr-header">
|
|
|
|
|
- <div class="brand-name">{{ qrData.brandName }}</div>
|
|
|
|
|
- <div class="brand-en">{{ qrData.brandEn }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="qr-content">
|
|
|
|
|
- <div class="scan-tip">扫码查看溯源信息</div>
|
|
|
|
|
- <div class="batch-info">批次号:{{ qrData.batchNo }}</div>
|
|
|
|
|
- <div class="origin">{{ qrData.origin }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="qr-code-wrapper">
|
|
|
|
|
- <canvas id="qrCanvas"></canvas>
|
|
|
|
|
|
|
+ <el-dialog :title="qrTitle" :visible.sync="qrVisible" width="520px" append-to-body>
|
|
|
|
|
+ <div class="qr-label-wrapper">
|
|
|
|
|
+ <!-- 外层圆角标签 -->
|
|
|
|
|
+ <div class="qr-label" ref="qrCard">
|
|
|
|
|
+ <!-- 内层线框 + 四角折角 -->
|
|
|
|
|
+ <div class="qr-label-inner">
|
|
|
|
|
+ <!-- 四角折角装饰 -->
|
|
|
|
|
+ <div class="corner corner-tl"></div>
|
|
|
|
|
+ <div class="corner corner-tr"></div>
|
|
|
|
|
+ <div class="corner corner-bl"></div>
|
|
|
|
|
+ <div class="corner corner-br"></div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 上半区:左侧信息 + 右侧二维码 -->
|
|
|
|
|
+ <div class="label-top">
|
|
|
|
|
+ <!-- 左侧品牌信息 -->
|
|
|
|
|
+ <div class="label-left">
|
|
|
|
|
+ <div class="brand-name">{{ qrData.brandName }}</div>
|
|
|
|
|
+ <div class="brand-en">{{ qrData.brandEn }}</div>
|
|
|
|
|
+ <div class="divider-line"></div>
|
|
|
|
|
+ <div class="scan-tip">扫码查看溯源信息</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 右侧二维码 -->
|
|
|
|
|
+ <div class="label-right">
|
|
|
|
|
+ <div class="qr-code-area">
|
|
|
|
|
+ <canvas id="qrCanvas"></canvas>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 主分隔线 -->
|
|
|
|
|
+ <div class="main-divider"></div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 下半区:批次信息 -->
|
|
|
|
|
+ <div class="label-bottom">
|
|
|
|
|
+ <div class="batch-row">批次: {{ qrData.batchNo }}</div>
|
|
|
|
|
+ <div class="label-bottom-divider"></div>
|
|
|
|
|
+ <div class="origin-row">{{ qrData.origin }}原产</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div slot="footer" class="dialog-footer">
|
|
<div slot="footer" class="dialog-footer">
|
|
@@ -570,8 +597,8 @@ export default {
|
|
|
qrTitle: "生成二维码",
|
|
qrTitle: "生成二维码",
|
|
|
// 二维码数据
|
|
// 二维码数据
|
|
|
qrData: {
|
|
qrData: {
|
|
|
- brandName: "爱智农",
|
|
|
|
|
- brandEn: "AIZHONGNONG",
|
|
|
|
|
|
|
+ brandName: "佳友厚苑",
|
|
|
|
|
+ brandEn: "JIAYOU HOUYUAN",
|
|
|
batchNo: "",
|
|
batchNo: "",
|
|
|
origin: "",
|
|
origin: "",
|
|
|
qrUrl: ""
|
|
qrUrl: ""
|
|
@@ -784,25 +811,25 @@ export default {
|
|
|
/** 生成二维码 */
|
|
/** 生成二维码 */
|
|
|
async handleGenerateQrCode(row) {
|
|
async handleGenerateQrCode(row) {
|
|
|
this.qrData.batchNo = row.batchNo
|
|
this.qrData.batchNo = row.batchNo
|
|
|
- this.qrData.farmRegion = row.farmRegion || '未知产地'
|
|
|
|
|
|
|
+ this.qrData.origin = row.farmRegion || '未知产地'
|
|
|
// 这里替换成你的溯源页面地址,可以根据实际域名配置
|
|
// 这里替换成你的溯源页面地址,可以根据实际域名配置
|
|
|
// const baseUrl = window.location.origin
|
|
// const baseUrl = window.location.origin
|
|
|
const baseUrl = 'https://nxy.gbdfarm.com:9001'
|
|
const baseUrl = 'https://nxy.gbdfarm.com:9001'
|
|
|
this.qrData.qrUrl = `${baseUrl}/${row.id}`
|
|
this.qrData.qrUrl = `${baseUrl}/${row.id}`
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
this.qrVisible = true
|
|
this.qrVisible = true
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 等待 DOM 渲染后生成二维码
|
|
// 等待 DOM 渲染后生成二维码
|
|
|
this.$nextTick(async () => {
|
|
this.$nextTick(async () => {
|
|
|
const canvas = document.getElementById('qrCanvas')
|
|
const canvas = document.getElementById('qrCanvas')
|
|
|
if (canvas) {
|
|
if (canvas) {
|
|
|
try {
|
|
try {
|
|
|
await QRCode.toCanvas(canvas, this.qrData.qrUrl, {
|
|
await QRCode.toCanvas(canvas, this.qrData.qrUrl, {
|
|
|
- width: 150,
|
|
|
|
|
- height: 150,
|
|
|
|
|
- margin: 2,
|
|
|
|
|
|
|
+ width: 140,
|
|
|
|
|
+ height: 140,
|
|
|
|
|
+ margin: 1,
|
|
|
color: {
|
|
color: {
|
|
|
- dark: '#333333',
|
|
|
|
|
|
|
+ dark: '#000000',
|
|
|
light: '#ffffff'
|
|
light: '#ffffff'
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
@@ -1158,80 +1185,198 @@ export default {
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
-.qr-card {
|
|
|
|
|
|
|
+/* 二维码标签包装器 */
|
|
|
|
|
+.qr-label-wrapper {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
|
|
|
|
+ justify-content: center;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- padding: 30px 20px;
|
|
|
|
|
- border: 2px solid #e0e0e0;
|
|
|
|
|
- border-radius: 12px;
|
|
|
|
|
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
+ padding: 16px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.qr-header {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- text-align: left;
|
|
|
|
|
- padding-right: 15px;
|
|
|
|
|
|
|
+/* 外层圆角标签 - 3:2 比例 (60mm x 40mm) */
|
|
|
|
|
+.qr-label {
|
|
|
|
|
+ width: 390px;
|
|
|
|
|
+ height: 260px;
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ border: 1.5px solid #000000;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ padding: 5px;
|
|
|
|
|
+ box-shadow: none;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ aspect-ratio: 3 / 2;
|
|
|
|
|
+ flex: 0 0 auto;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.brand-name {
|
|
|
|
|
- font-size: 22px;
|
|
|
|
|
- font-weight: bold;
|
|
|
|
|
- color: #333;
|
|
|
|
|
- margin-bottom: 8px;
|
|
|
|
|
- letter-spacing: 1px;
|
|
|
|
|
|
|
+/* 内层线框 */
|
|
|
|
|
+.qr-label-inner {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ border: 1px solid #000000;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ padding: 14px 16px 12px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.brand-en {
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- color: #666;
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- letter-spacing: 0.5px;
|
|
|
|
|
|
|
+/* 四角折角装饰 */
|
|
|
|
|
+.corner {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ width: 12px;
|
|
|
|
|
+ height: 12px;
|
|
|
|
|
+ border: 1px solid #000000;
|
|
|
|
|
+}
|
|
|
|
|
+.corner-tl {
|
|
|
|
|
+ top: -1px;
|
|
|
|
|
+ left: -1px;
|
|
|
|
|
+ border-right: none;
|
|
|
|
|
+ border-bottom: none;
|
|
|
|
|
+ border-radius: 4px 0 0 0;
|
|
|
|
|
+}
|
|
|
|
|
+.corner-tr {
|
|
|
|
|
+ top: -1px;
|
|
|
|
|
+ right: -1px;
|
|
|
|
|
+ border-left: none;
|
|
|
|
|
+ border-bottom: none;
|
|
|
|
|
+ border-radius: 0 4px 0 0;
|
|
|
|
|
+}
|
|
|
|
|
+.corner-bl {
|
|
|
|
|
+ bottom: -1px;
|
|
|
|
|
+ left: -1px;
|
|
|
|
|
+ border-right: none;
|
|
|
|
|
+ border-top: none;
|
|
|
|
|
+ border-radius: 0 0 0 4px;
|
|
|
|
|
+}
|
|
|
|
|
+.corner-br {
|
|
|
|
|
+ bottom: -1px;
|
|
|
|
|
+ right: -1px;
|
|
|
|
|
+ border-left: none;
|
|
|
|
|
+ border-top: none;
|
|
|
|
|
+ border-radius: 0 0 4px 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.qr-content {
|
|
|
|
|
|
|
+/* 上半区 */
|
|
|
|
|
+.label-top {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
- text-align: left;
|
|
|
|
|
- padding: 0 15px;
|
|
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.scan-tip {
|
|
|
|
|
- margin-bottom: 12px;
|
|
|
|
|
- color: #333;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
|
|
+/* 左侧品牌信息 */
|
|
|
|
|
+.label-left {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ padding-right: 14px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.batch-info {
|
|
|
|
|
|
|
+.brand-name {
|
|
|
|
|
+ font-size: 28px;
|
|
|
|
|
+ font-weight: 900;
|
|
|
|
|
+ color: #000000;
|
|
|
|
|
+ letter-spacing: 8px;
|
|
|
|
|
+ margin-bottom: 2px;
|
|
|
|
|
+ line-height: 1.1;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.brand-en {
|
|
|
|
|
+ font-size: 10px;
|
|
|
|
|
+ color: #000000;
|
|
|
|
|
+ letter-spacing: 5px;
|
|
|
margin-bottom: 10px;
|
|
margin-bottom: 10px;
|
|
|
font-weight: 600;
|
|
font-weight: 600;
|
|
|
- color: #2c3e50;
|
|
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.divider-line {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 1.5px;
|
|
|
|
|
+ background: #000000;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.scan-tip {
|
|
|
font-size: 15px;
|
|
font-size: 15px;
|
|
|
|
|
+ color: #000000;
|
|
|
|
|
+ letter-spacing: 2px;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ line-height: 1.3;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.origin {
|
|
|
|
|
- color: #666;
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
|
|
+/* 右侧二维码 */
|
|
|
|
|
+.label-right {
|
|
|
|
|
+ width: 120px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.qr-code-wrapper {
|
|
|
|
|
- width: 160px;
|
|
|
|
|
- height: 160px;
|
|
|
|
|
|
|
+.qr-code-area {
|
|
|
|
|
+ width: 110px;
|
|
|
|
|
+ height: 110px;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
- background: #fff;
|
|
|
|
|
- border: 1px solid #ddd;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- padding: 8px;
|
|
|
|
|
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
|
+ padding: 3px;
|
|
|
|
|
+ border: 1px solid #000000;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+.qr-code-area canvas,
|
|
|
#qrCanvas {
|
|
#qrCanvas {
|
|
|
- width: 150px;
|
|
|
|
|
- height: 150px;
|
|
|
|
|
|
|
+ width: 102px !important;
|
|
|
|
|
+ height: 102px !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 主分隔线 */
|
|
|
|
|
+.main-divider {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 1.5px;
|
|
|
|
|
+ background: #000000;
|
|
|
|
|
+ margin: 10px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 下半区 */
|
|
|
|
|
+.label-bottom {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.batch-row {
|
|
|
|
|
+ font-size: 17px;
|
|
|
|
|
+ color: #000000;
|
|
|
|
|
+ font-weight: 800;
|
|
|
|
|
+ letter-spacing: 2px;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ line-height: 1.3;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.label-bottom-divider {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 1px;
|
|
|
|
|
+ background: #000000;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.origin-row {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ color: #000000;
|
|
|
|
|
+ letter-spacing: 4px;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ line-height: 1.3;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.dialog-footer {
|
|
.dialog-footer {
|