张诺
5 天以前 c8b65690b946b28b179796fbe2f020e732043c58
src/components/QRCodeGenerator/index.vue
@@ -1,70 +1,79 @@
<template>
  <div class="qr-code-generator">
    <!-- 二维码生成表单 -->
    <el-form :model="form" :rules="rules" ref="formRef" label-width="120px" class="qr-form">
    <el-form :model="form"
             :rules="rules"
             ref="formRef"
             label-width="120px"
             class="qr-form">
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="标识类型" prop="type">
            <el-select v-model="form.type" placeholder="请选择标识类型" style="width: 100%">
              <el-option label="二维码" value="qrcode"></el-option>
              <el-option label="防伪码" value="security"></el-option>
          <el-form-item label="标识类型"
                        prop="type">
            <el-select v-model="form.type"
                       placeholder="请选择标识类型"
                       style="width: 100%">
              <el-option label="二维码"
                         value="qrcode"></el-option>
              <el-option label="防伪码"
                         value="security"></el-option>
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="内容" prop="content">
            <el-input
              v-model="form.content"
              placeholder="请输入要编码的内容"
              :type="form.type === 'security' ? 'textarea' : 'text'"
              :rows="form.type === 'security' ? 3 : 1"
            ></el-input>
          <el-form-item label="内容"
                        prop="content">
            <el-input v-model="form.content"
                      placeholder="请输入要编码的内容"
                      :type="form.type === 'security' ? 'textarea' : 'text'"
                      :rows="form.type === 'security' ? 3 : 1"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="尺寸" prop="size">
            <el-input-number
              v-model="form.size"
              :min="100"
              :max="500"
              :step="50"
              style="width: 100%"
            ></el-input-number>
          <el-form-item label="尺寸"
                        prop="size">
            <el-input-number v-model="form.size"
                             :min="100"
                             :max="500"
                             :step="50"
                             style="width: 100%"></el-input-number>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="边距" prop="margin">
            <el-input-number
              v-model="form.margin"
              :min="0"
              :max="10"
              :step="1"
              style="width: 100%"
            ></el-input-number>
          <el-form-item label="边距"
                        prop="margin">
            <el-input-number v-model="form.margin"
                             :min="0"
                             :max="10"
                             :step="1"
                             style="width: 100%"></el-input-number>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="前景色" prop="foregroundColor">
            <el-color-picker v-model="form.foregroundColor" style="width: 100%"></el-color-picker>
          <el-form-item label="前景色"
                        prop="foregroundColor">
            <el-color-picker v-model="form.foregroundColor"
                             style="width: 100%"></el-color-picker>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="背景色" prop="backgroundColor">
            <el-color-picker v-model="form.backgroundColor" style="width: 100%"></el-color-picker>
          <el-form-item label="背景色"
                        prop="backgroundColor">
            <el-color-picker v-model="form.backgroundColor"
                             style="width: 100%"></el-color-picker>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="24">
          <el-form-item>
            <el-button type="primary" @click="generateCode" :loading="generating">
            <el-button type="primary"
                       @click="generateCode"
                       :loading="generating">
              生成{{ form.type === 'qrcode' ? '二维码' : '防伪码' }}
            </el-button>
            <el-button @click="resetForm">重置</el-button>
@@ -72,18 +81,17 @@
        </el-col>
      </el-row>
    </el-form>
    <!-- 生成的码显示区域 -->
    <div v-if="generatedCodeUrl" class="code-display">
    <div v-if="generatedCodeUrl"
         class="code-display">
      <el-divider content-position="center">
        {{ form.type === 'qrcode' ? '生成的二维码' : '生成的防伪码' }}
      </el-divider>
      <div class="code-container">
        <div class="code-image">
          <img :src="generatedCodeUrl" :alt="form.type === 'qrcode' ? '二维码' : '防伪码'" />
          <img :src="generatedCodeUrl"
               :alt="form.type === 'qrcode' ? '二维码' : '防伪码'" />
        </div>
        <div class="code-info">
          <p><strong>内容:</strong>{{ form.content }}</p>
          <p><strong>类型:</strong>{{ form.type === 'qrcode' ? '二维码' : '防伪码' }}</p>
@@ -91,60 +99,71 @@
          <p><strong>生成时间:</strong>{{ generateTime }}</p>
        </div>
      </div>
      <div class="code-actions">
        <el-button type="success" @click="downloadCode" icon="Download">
        <el-button type="success"
                   @click="downloadCode"
                   icon="Download">
          下载图片
        </el-button>
        <el-button type="primary" @click="copyToClipboard" icon="CopyDocument">
        <el-button type="primary"
                   @click="copyToClipboard"
                   icon="CopyDocument">
          复制内容
        </el-button>
        <el-button @click="printCode" icon="Printer">
        <el-button @click="printCode"
                   icon="Printer">
          打印
        </el-button>
      </div>
    </div>
    <!-- 批量生成对话框 -->
    <el-dialog v-model="batchDialogVisible" title="批量生成" width="600px">
      <el-form :model="batchForm" label-width="120px">
    <el-dialog v-model="batchDialogVisible"
               title="批量生成"
               width="600px">
      <el-form :model="batchForm"
               label-width="120px">
        <el-form-item label="生成数量">
          <el-input-number v-model="batchForm.quantity" :min="1" :max="100" style="width: 100%"></el-input-number>
          <el-input-number v-model="batchForm.quantity"
                           :min="1"
                           :max="100"
                           style="width: 100%"></el-input-number>
        </el-form-item>
        <el-form-item label="前缀">
          <el-input v-model="batchForm.prefix" placeholder="请输入前缀,如:PROD_"></el-input>
          <el-input v-model="batchForm.prefix"
                    placeholder="请输入前缀,如:PROD_"></el-input>
        </el-form-item>
        <el-form-item label="起始编号">
          <el-input-number v-model="batchForm.startNumber" :min="1" style="width: 100%"></el-input-number>
          <el-input-number v-model="batchForm.startNumber"
                           :min="1"
                           style="width: 100%"></el-input-number>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary"
                     @click="generateBatchCodes">开始生成</el-button>
          <el-button @click="batchDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="generateBatchCodes">开始生成</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- 批量生成结果 -->
    <div v-if="batchCodes.length > 0" class="batch-results">
    <div v-if="batchCodes.length > 0"
         class="batch-results">
      <el-divider content-position="center">批量生成结果</el-divider>
      <div class="batch-grid">
        <div
          v-for="(code, index) in batchCodes"
          :key="index"
          class="batch-item"
        >
          <img :src="code.url" :alt="code.content" />
        <div v-for="(code, index) in batchCodes"
             :key="index"
             class="batch-item">
          <img :src="code.url"
               :alt="code.content" />
          <p class="batch-content">{{ code.content }}</p>
          <el-button size="small" @click="downloadSingleCode(code)">下载</el-button>
          <el-button size="small"
                     @click="downloadSingleCode(code)">下载</el-button>
        </div>
      </div>
      <div class="batch-actions">
        <el-button type="success" @click="downloadAllCodes">下载全部</el-button>
        <el-button type="success"
                   @click="downloadAllCodes">下载全部</el-button>
        <el-button @click="clearBatchCodes">清空结果</el-button>
      </div>
    </div>
@@ -152,390 +171,396 @@
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import QRCode from 'qrcode'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Download, CopyDocument, Printer } from '@element-plus/icons-vue'
  import { ref, reactive, computed, onMounted } from "vue";
  import QRCode from "qrcode";
  import { ElMessage, ElMessageBox } from "element-plus";
  import { Download, CopyDocument, Printer } from "@element-plus/icons-vue";
// 定义组件名称
defineOptions({
  name: 'QRCodeGenerator'
})
  // 定义组件名称
  defineOptions({
    name: "QRCodeGenerator",
  });
// 表单数据
const form = reactive({
  type: 'qrcode',
  content: '',
  size: 200,
  margin: 2,
  foregroundColor: '#000000',
  backgroundColor: '#FFFFFF'
})
  // 表单数据
  const form = reactive({
    type: "qrcode",
    content: "",
    size: 200,
    margin: 2,
    foregroundColor: "#000000",
    backgroundColor: "#FFFFFF",
  });
// 表单验证规则
const rules = {
  type: [{ required: true, message: '请选择标识类型', trigger: 'change' }],
  content: [{ required: true, message: '请输入内容', trigger: 'blur' }]
}
  // 表单验证规则
  const rules = {
    type: [{ required: true, message: "请选择标识类型", trigger: "change" }],
    content: [{ required: true, message: "请输入内容", trigger: "blur" }],
  };
// 响应式数据
const formRef = ref()
const generating = ref(false)
const generatedCodeUrl = ref('')
const generateTime = ref('')
const batchDialogVisible = ref(false)
const batchForm = reactive({
  quantity: 10,
  prefix: '',
  startNumber: 1
})
const batchCodes = ref([])
  // 响应式数据
  const formRef = ref();
  const generating = ref(false);
  const generatedCodeUrl = ref("");
  const generateTime = ref("");
  const batchDialogVisible = ref(false);
  const batchForm = reactive({
    quantity: 10,
    prefix: "",
    startNumber: 1,
  });
  const batchCodes = ref([]);
// 生成二维码或防伪码
const generateCode = async () => {
  try {
    await formRef.value.validate()
    if (!form.content.trim()) {
      ElMessage.warning('请输入要编码的内容')
      return
    }
    generating.value = true
    if (form.type === 'qrcode') {
      // 生成二维码
      generatedCodeUrl.value = await QRCode.toDataURL(form.content, {
        width: form.size,
        margin: form.margin,
        color: {
          dark: form.foregroundColor,
          light: form.backgroundColor
        },
        errorCorrectionLevel: 'M'
      })
    } else {
      // 生成防伪码(使用二维码技术,但内容格式不同)
      const securityContent = generateSecurityCode(form.content)
      generatedCodeUrl.value = await QRCode.toDataURL(securityContent, {
        width: form.size,
        margin: form.margin,
        color: {
          dark: form.foregroundColor,
          light: form.backgroundColor
        },
        errorCorrectionLevel: 'H' // 防伪码使用最高纠错级别
      })
    }
    generateTime.value = new Date().toLocaleString()
    ElMessage.success('生成成功!')
  } catch (error) {
    console.error('生成失败:', error)
    ElMessage.error('生成失败:' + error.message)
  } finally {
    generating.value = false
  }
}
  // 生成二维码或防伪码
  const generateCode = async () => {
    try {
      await formRef.value.validate();
// 生成防伪码内容
const generateSecurityCode = (content) => {
  const timestamp = Date.now()
  const random = Math.random().toString(36).substr(2, 8)
  return `SEC_${content}_${timestamp}_${random}`
}
      if (!form.content.trim()) {
        ElMessage.warning("请输入要编码的内容");
        return;
      }
// 下载生成的码
const downloadCode = () => {
  if (!generatedCodeUrl.value) {
    ElMessage.warning('请先生成码')
    return
  }
  const a = document.createElement('a')
  a.href = generatedCodeUrl.value
  a.download = `${form.type === 'qrcode' ? '二维码' : '防伪码'}_${new Date().getTime()}.png`
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
  ElMessage.success('下载成功!')
}
      generating.value = true;
// 复制内容到剪贴板
const copyToClipboard = async () => {
  try {
    await navigator.clipboard.writeText(form.content)
    ElMessage.success('内容已复制到剪贴板')
  } catch (error) {
    // 降级方案
    const textArea = document.createElement('textarea')
    textArea.value = form.content
    document.body.appendChild(textArea)
    textArea.select()
    document.execCommand('copy')
    document.body.removeChild(textArea)
    ElMessage.success('内容已复制到剪贴板')
  }
}
// 打印码
const printCode = () => {
  if (!generatedCodeUrl.value) {
    ElMessage.warning('请先生成码')
    return
  }
  const printWindow = window.open('', '_blank')
  printWindow.document.write(`
    <html>
      <head>
        <title>打印${form.type === 'qrcode' ? '二维码' : '防伪码'}</title>
        <style>
          body { text-align: center; padding: 20px; }
          img { max-width: 100%; height: auto; }
          .info { margin: 20px 0; }
        </style>
      </head>
      <body>
        <h2>${form.type === 'qrcode' ? '二维码' : '防伪码'}</h2>
        <img src="${generatedCodeUrl.value}" alt="${form.type === 'qrcode' ? '二维码' : '防伪码'}" />
        <div class="info">
          <p><strong>内容:</strong>${form.content}</p>
          <p><strong>生成时间:</strong>${generateTime.value}</p>
        </div>
      </body>
    </html>
  `)
  printWindow.document.close()
  printWindow.print()
}
// 重置表单
const resetForm = () => {
  formRef.value.resetFields()
  generatedCodeUrl.value = ''
  generateTime.value = ''
  batchCodes.value = []
}
// 批量生成
const generateBatchCodes = async () => {
  if (!batchForm.prefix.trim()) {
    ElMessage.warning('请输入前缀')
    return
  }
  batchCodes.value = []
  generating.value = true
  try {
    for (let i = 0; i < batchForm.quantity; i++) {
      const number = batchForm.startNumber + i
      const content = `${batchForm.prefix}${number.toString().padStart(6, '0')}`
      let codeUrl
      if (form.type === 'qrcode') {
        codeUrl = await QRCode.toDataURL(content, {
      if (form.type === "qrcode") {
        // 生成二维码
        generatedCodeUrl.value = await QRCode.toDataURL(form.content, {
          width: form.size,
          margin: form.margin,
          color: {
            dark: form.foregroundColor,
            light: form.backgroundColor
          }
        })
            light: form.backgroundColor,
          },
          errorCorrectionLevel: "M",
        });
      } else {
        const securityContent = generateSecurityCode(content)
        codeUrl = await QRCode.toDataURL(securityContent, {
        // 生成防伪码(使用二维码技术,但内容格式不同)
        const securityContent = generateSecurityCode(form.content);
        generatedCodeUrl.value = await QRCode.toDataURL(securityContent, {
          width: form.size,
          margin: form.margin,
          color: {
            dark: form.foregroundColor,
            light: form.backgroundColor
          }
        })
            light: form.backgroundColor,
          },
          errorCorrectionLevel: "H", // 防伪码使用最高纠错级别
        });
      }
      batchCodes.value.push({
        content,
        url: codeUrl
      })
      generateTime.value = new Date().toLocaleString();
      ElMessage.success("生成成功!");
    } catch (error) {
      console.error("生成失败:", error);
      ElMessage.error("生成失败:" + error.message);
    } finally {
      generating.value = false;
    }
    ElMessage.success(`批量生成完成,共生成 ${batchForm.quantity} 个码`)
    batchDialogVisible.value = false
  } catch (error) {
    console.error('批量生成失败:', error)
    ElMessage.error('批量生成失败:' + error.message)
  } finally {
    generating.value = false
  }
}
  };
// 下载单个批量生成的码
const downloadSingleCode = (code) => {
  const a = document.createElement('a')
  a.href = code.url
  a.download = `${code.content}.png`
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}
  // 生成防伪码内容
  const generateSecurityCode = content => {
    const timestamp = Date.now();
    const random = Math.random().toString(36).substr(2, 8);
    return `SEC_${content}_${timestamp}_${random}`;
  };
// 下载所有批量生成的码
const downloadAllCodes = async () => {
  if (batchCodes.value.length === 0) {
    ElMessage.warning('没有可下载的码')
    return
  }
  try {
    // 使用JSZip打包下载
    const JSZip = await import('jszip')
    const zip = new JSZip.default()
    batchCodes.value.forEach((code, index) => {
      // 将base64转换为blob
      const base64Data = code.url.split(',')[1]
      const byteCharacters = atob(base64Data)
      const byteNumbers = new Array(byteCharacters.length)
      for (let i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i)
  // 下载生成的码
  const downloadCode = () => {
    if (!generatedCodeUrl.value) {
      ElMessage.warning("请先生成码");
      return;
    }
    const a = document.createElement("a");
    a.href = generatedCodeUrl.value;
    a.download = `${
      form.type === "qrcode" ? "二维码" : "防伪码"
    }_${new Date().getTime()}.png`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    ElMessage.success("下载成功!");
  };
  // 复制内容到剪贴板
  const copyToClipboard = async () => {
    try {
      await navigator.clipboard.writeText(form.content);
      ElMessage.success("内容已复制到剪贴板");
    } catch (error) {
      // 降级方案
      const textArea = document.createElement("textarea");
      textArea.value = form.content;
      document.body.appendChild(textArea);
      textArea.select();
      document.execCommand("copy");
      document.body.removeChild(textArea);
      ElMessage.success("内容已复制到剪贴板");
    }
  };
  // 打印码
  const printCode = () => {
    if (!generatedCodeUrl.value) {
      ElMessage.warning("请先生成码");
      return;
    }
    const printWindow = window.open("", "_blank");
    printWindow.document.write(`
      <html>
        <head>
          <title>打印${form.type === "qrcode" ? "二维码" : "防伪码"}</title>
          <style>
            body { text-align: center; padding: 20px; }
            img { max-width: 100%; height: auto; }
            .info { margin: 20px 0; }
          </style>
        </head>
        <body>
          <h2>${form.type === "qrcode" ? "二维码" : "防伪码"}</h2>
          <img src="${generatedCodeUrl.value}" alt="${
      form.type === "qrcode" ? "二维码" : "防伪码"
    }" />
          <div class="info">
            <p><strong>内容:</strong>${form.content}</p>
            <p><strong>生成时间:</strong>${generateTime.value}</p>
          </div>
        </body>
      </html>
    `);
    printWindow.document.close();
    printWindow.print();
  };
  // 重置表单
  const resetForm = () => {
    formRef.value.resetFields();
    generatedCodeUrl.value = "";
    generateTime.value = "";
    batchCodes.value = [];
  };
  // 批量生成
  const generateBatchCodes = async () => {
    if (!batchForm.prefix.trim()) {
      ElMessage.warning("请输入前缀");
      return;
    }
    batchCodes.value = [];
    generating.value = true;
    try {
      for (let i = 0; i < batchForm.quantity; i++) {
        const number = batchForm.startNumber + i;
        const content = `${batchForm.prefix}${number
          .toString()
          .padStart(6, "0")}`;
        let codeUrl;
        if (form.type === "qrcode") {
          codeUrl = await QRCode.toDataURL(content, {
            width: form.size,
            margin: form.margin,
            color: {
              dark: form.foregroundColor,
              light: form.backgroundColor,
            },
          });
        } else {
          const securityContent = generateSecurityCode(content);
          codeUrl = await QRCode.toDataURL(securityContent, {
            width: form.size,
            margin: form.margin,
            color: {
              dark: form.foregroundColor,
              light: form.backgroundColor,
            },
          });
        }
        batchCodes.value.push({
          content,
          url: codeUrl,
        });
      }
      const byteArray = new Uint8Array(byteNumbers)
      zip.file(`${code.content}.png`, byteArray)
    })
    const content = await zip.generateAsync({ type: 'blob' })
    const a = document.createElement('a')
    a.href = URL.createObjectURL(content)
    a.download = `批量${form.type === 'qrcode' ? '二维码' : '防伪码'}_${new Date().getTime()}.zip`
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
    URL.revokeObjectURL(a.href)
    ElMessage.success('批量下载完成!')
  } catch (error) {
    console.error('批量下载失败:', error)
    ElMessage.error('批量下载失败,请逐个下载')
  }
}
// 清空批量生成结果
const clearBatchCodes = () => {
  batchCodes.value = []
}
      ElMessage.success(`批量生成完成,共生成 ${batchForm.quantity} 个码`);
      batchDialogVisible.value = false;
    } catch (error) {
      console.error("批量生成失败:", error);
      ElMessage.error("批量生成失败:" + error.message);
    } finally {
      generating.value = false;
    }
  };
// 暴露方法给父组件
defineExpose({
  generateCode,
  downloadCode,
  resetForm,
  form
})
  // 下载单个批量生成的码
  const downloadSingleCode = code => {
    const a = document.createElement("a");
    a.href = code.url;
    a.download = `${code.content}.png`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  };
  // 下载所有批量生成的码
  const downloadAllCodes = async () => {
    if (batchCodes.value.length === 0) {
      ElMessage.warning("没有可下载的码");
      return;
    }
    try {
      // 使用JSZip打包下载
      const JSZip = await import("jszip");
      const zip = new JSZip.default();
      batchCodes.value.forEach((code, index) => {
        // 将base64转换为blob
        const base64Data = code.url.split(",")[1];
        const byteCharacters = atob(base64Data);
        const byteNumbers = new Array(byteCharacters.length);
        for (let i = 0; i < byteCharacters.length; i++) {
          byteNumbers[i] = byteCharacters.charCodeAt(i);
        }
        const byteArray = new Uint8Array(byteNumbers);
        zip.file(`${code.content}.png`, byteArray);
      });
      const content = await zip.generateAsync({ type: "blob" });
      const a = document.createElement("a");
      a.href = URL.createObjectURL(content);
      a.download = `批量${
        form.type === "qrcode" ? "二维码" : "防伪码"
      }_${new Date().getTime()}.zip`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(a.href);
      ElMessage.success("批量下载完成!");
    } catch (error) {
      console.error("批量下载失败:", error);
      ElMessage.error("批量下载失败,请逐个下载");
    }
  };
  // 清空批量生成结果
  const clearBatchCodes = () => {
    batchCodes.value = [];
  };
  // 暴露方法给父组件
  defineExpose({
    generateCode,
    downloadCode,
    resetForm,
    form,
  });
</script>
<style scoped>
.qr-code-generator {
  padding: 20px;
}
  .qr-code-generator {
    padding: 20px;
  }
.qr-form {
  background: #f8f9fa;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 20px;
}
  .qr-form {
    background: #f8f9fa;
    padding: 20px;
    border-radius: 8px;
    margin-bottom: 20px;
  }
.code-display {
  margin-top: 30px;
}
  .code-display {
    margin-top: 30px;
  }
.code-container {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 40px;
  margin: 20px 0;
}
.code-image img {
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.code-info {
  text-align: left;
  min-width: 200px;
}
.code-info p {
  margin: 8px 0;
  color: #666;
}
.code-actions {
  text-align: center;
  margin: 20px 0;
}
.code-actions .el-button {
  margin: 0 10px;
}
.batch-results {
  margin-top: 30px;
}
.batch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 20px;
  margin: 20px 0;
}
.batch-item {
  text-align: center;
  padding: 15px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  background: #fff;
}
.batch-item img {
  width: 100px;
  height: 100px;
  margin-bottom: 10px;
}
.batch-content {
  font-size: 12px;
  color: #666;
  margin: 10px 0;
  word-break: break-all;
}
.batch-actions {
  text-align: center;
  margin: 20px 0;
}
.batch-actions .el-button {
  margin: 0 10px;
}
@media (max-width: 768px) {
  .code-container {
    flex-direction: column;
    align-items: center;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    gap: 40px;
    margin: 20px 0;
  }
  .code-image img {
    border: 2px solid #e0e0e0;
    border-radius: 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  }
  .code-info {
    text-align: left;
    min-width: 200px;
  }
  .code-info p {
    margin: 8px 0;
    color: #666;
  }
  .code-actions {
    text-align: center;
    margin: 20px 0;
  }
  .code-actions .el-button {
    margin: 0 10px;
  }
  .batch-results {
    margin-top: 30px;
  }
  .batch-grid {
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 20px;
    margin: 20px 0;
  }
}
  .batch-item {
    text-align: center;
    padding: 15px;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    background: #fff;
  }
  .batch-item img {
    width: 100px;
    height: 100px;
    margin-bottom: 10px;
  }
  .batch-content {
    font-size: 12px;
    color: #666;
    margin: 10px 0;
    word-break: break-all;
  }
  .batch-actions {
    text-align: center;
    margin: 20px 0;
  }
  .batch-actions .el-button {
    margin: 0 10px;
  }
  @media (max-width: 768px) {
    .code-container {
      flex-direction: column;
      align-items: center;
    }
    .batch-grid {
      grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    }
  }
</style>