wlzboy
2025-09-27 c1147646b9ef1d713a202d7ab8cf3ea8d677f142
fix:优化评价
1个文件已添加
8个文件已修改
477 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/VehicleEvaluationQrcodeController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/QRCodeUtils.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/config/QRCodeConfig.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleEvaluationQrcodeService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleEvaluationQrcodeServiceImpl.java 97 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/evaluation.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/evaluation/index.vue 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/evaluation/qrcode/index.vue 98 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/VehicleEvaluationQrcodeController.java
@@ -111,11 +111,16 @@
            if (StringUtils.isEmpty(vehicleNo)) {
                return error("车牌号不能为空");
            }
            VehicleEvaluationQrcode qrcode;
            if (StringUtils.isEmpty(qrcodeUrl)) {
                return error("二维码URL不能为空");
                // 如果URL为空,使用默认URL
                qrcode = vehicleEvaluationQrcodeService.generateVehicleEvaluationQrcode(vehicleNo);
            } else {
                // 如果URL不为空,使用指定的URL
                qrcode = vehicleEvaluationQrcodeService.generateVehicleEvaluationQrcode(vehicleNo, qrcodeUrl);
            }
            
            VehicleEvaluationQrcode qrcode = vehicleEvaluationQrcodeService.generateVehicleEvaluationQrcode(vehicleNo, qrcodeUrl);
            if (qrcode != null) {
                return success(qrcode);
            } else {
@@ -133,9 +138,17 @@
    @PreAuthorize("@ss.hasPermi('evaluation:qrcode:batch')")
    @Log(title = "车辆评价二维码", businessType = BusinessType.INSERT)
    @PostMapping("/batch")
    public AjaxResult batchGenerateQrcode() {
    public AjaxResult batchGenerateQrcode(@RequestBody JSONObject params) {
        try {
            int count = vehicleEvaluationQrcodeService.batchGenerateVehicleEvaluationQrcode();
            String qrcodeUrl = params.getString("qrcodeUrl");
            @SuppressWarnings("unchecked")
            List<String> vehicleNos = (List<String>) params.get("vehicleNos");
            if (vehicleNos == null || vehicleNos.isEmpty()) {
                return error("车牌号列表不能为空");
            }
            int count = vehicleEvaluationQrcodeService.batchGenerateVehicleEvaluationQrcode(vehicleNos, qrcodeUrl);
            return success("成功生成 " + count + " 个二维码");
        } catch (Exception e) {
            logger.error("批量生成二维码失败", e);
ruoyi-admin/src/main/resources/application.yml
@@ -154,4 +154,8 @@
  dev:
    enabled: true  # 是否启用开发模式
    mockUserInfo: true  # 是否模拟用户信息
    ngrokUrl: http://your-ngrok-url.ngrok.io  # 内网穿透地址
    ngrokUrl: http://your-ngrok-url.ngrok.io  # 内网穿透地址
# 二维码配置
qrcode:
  defaultUrl: http://localhost:81/evaluation?vehicle={vehicleNo}  # 默认二维码URL模板,{vehicleNo}会被替换为实际车牌号
ruoyi-common/src/main/java/com/ruoyi/common/utils/QRCodeUtils.java
@@ -9,6 +9,7 @@
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -95,4 +96,55 @@
        }
        return null;
    }
    /**
     * 生成带车牌号的Base64编码二维码
     *
     * @param content 二维码内容
     * @param vehicleNo 车牌号
     * @return Base64编码的二维码
     */
    public static String generateQRCodeWithVehicleNoToBase64(String content, String vehicleNo) {
        try {
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.MARGIN, 1);
            BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints);
            BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
            // 创建带文字的图片
            int textHeight = 40; // 文字区域高度
            int totalHeight = HEIGHT + textHeight;
            BufferedImage finalImage = new BufferedImage(WIDTH, totalHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = finalImage.createGraphics();
            // 设置背景为白色
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, WIDTH, totalHeight);
            // 绘制二维码
            g2d.drawImage(qrImage, 0, 0, null);
            // 绘制车牌号文字
            g2d.setColor(Color.BLACK);
            g2d.setFont(new Font("微软雅黑", Font.BOLD, 16));
            FontMetrics fm = g2d.getFontMetrics();
            int textWidth = fm.stringWidth(vehicleNo);
            int x = (WIDTH - textWidth) / 2;
            int y = HEIGHT + (textHeight + fm.getAscent()) / 2;
            g2d.drawString(vehicleNo, x, y);
            g2d.dispose();
            // 转换为Base64
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(finalImage, FORMAT, baos);
            return "data:image/png;base64," + java.util.Base64.getEncoder().encodeToString(baos.toByteArray());
        } catch (Exception e) {
            log.error("生成带车牌号的二维码失败: {}", e.getMessage());
            return null;
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/config/QRCodeConfig.java
New file
@@ -0,0 +1,39 @@
package com.ruoyi.system.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
 * 二维码配置
 *
 * @author ruoyi
 */
@Component
@ConfigurationProperties(prefix = "qrcode")
public class QRCodeConfig {
    /**
     * 默认二维码URL模板
     */
    private String defaultUrl = "http://localhost:8080/evaluation?vehicle={vehicleNo}";
    public String getDefaultUrl() {
        return defaultUrl;
    }
    public void setDefaultUrl(String defaultUrl) {
        this.defaultUrl = defaultUrl;
    }
    /**
     * 根据车牌号生成二维码URL
     *
     * @param vehicleNo 车牌号
     * @return 二维码URL
     */
    public String generateUrl(String vehicleNo) {
        if (defaultUrl != null && defaultUrl.contains("{vehicleNo}")) {
            return defaultUrl.replace("{vehicleNo}", vehicleNo);
        }
        return defaultUrl + "?vehicle=" + vehicleNo;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleEvaluationQrcodeService.java
@@ -89,4 +89,13 @@
     * @return 结果
     */
    public int batchGenerateVehicleEvaluationQrcode();
    /**
     * 批量生成车辆评价二维码(指定车牌号列表)
     *
     * @param vehicleNos 车牌号列表
     * @param qrcodeUrl 二维码URL(可选)
     * @return 结果
     */
    public int batchGenerateVehicleEvaluationQrcode(List<String> vehicleNos, String qrcodeUrl);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleEvaluationQrcodeServiceImpl.java
@@ -5,6 +5,7 @@
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.QRCodeUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.config.QRCodeConfig;
import com.ruoyi.system.mapper.VehicleInfoMapper;
import com.ruoyi.system.domain.VehicleInfo;
import com.ruoyi.system.mapper.VehicleEvaluationQrcodeMapper;
@@ -27,6 +28,9 @@
    @Autowired
    private VehicleInfoMapper vehicleInfoMapper;
    @Autowired
    private QRCodeConfig qrCodeConfig;
    @Value("${ruoyi.profile}")
    private String uploadPath;
@@ -125,9 +129,48 @@
            return null;
        }
        // 检查车辆是否存在
        VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoByVehicleNo(vehicleNo);
        if (vehicleInfo == null) {
        // 注意:这里不检查车辆信息表,允许为任意车牌号生成二维码
        // 检查是否已存在二维码
        VehicleEvaluationQrcode existingQrcode = vehicleEvaluationQrcodeMapper.selectVehicleEvaluationQrcodeByVehicleNo(vehicleNo);
        if (existingQrcode != null) {
            return existingQrcode;
        }
        // 生成二维码内容
        String qrcodeContent = "EVAL:" + vehicleNo;
        String qrcodeUrl = qrCodeConfig.generateUrl(vehicleNo);
        // 生成带车牌号的二维码图片为base64格式
        String qrcodeImageBase64 = QRCodeUtils.generateQRCodeWithVehicleNoToBase64(qrcodeUrl, vehicleNo);
        if (qrcodeImageBase64 != null) {
            VehicleEvaluationQrcode qrcode = new VehicleEvaluationQrcode();
            qrcode.setVehicleNo(vehicleNo);
            qrcode.setQrcodeUrl(qrcodeUrl);
            qrcode.setQrcodeContent(qrcodeContent);
            qrcode.setQrcodeImage(qrcodeImageBase64);
            qrcode.setStatus("0");
            qrcode.setCreateBy("system");
            qrcode.setCreateTime(DateUtils.getNowDate());
            int result = vehicleEvaluationQrcodeMapper.insertVehicleEvaluationQrcode(qrcode);
            if (result > 0) {
                return qrcode;
            }
        }
        return null;
    }
    /**
     * 生成车辆评价二维码(不检查车辆信息表)
     *
     * @param vehicleNo 车牌号
     * @return 二维码信息
     */
    private VehicleEvaluationQrcode generateVehicleEvaluationQrcodeWithoutVehicleCheck(String vehicleNo) {
        if (StringUtils.isEmpty(vehicleNo)) {
            return null;
        }
@@ -139,10 +182,10 @@
        // 生成二维码内容
        String qrcodeContent = "EVAL:" + vehicleNo;
        String qrcodeUrl = "http://localhost:" + serverPort + "/evaluation?vehicle=" + vehicleNo;
        String qrcodeUrl = qrCodeConfig.generateUrl(vehicleNo);
        // 生成二维码图片为base64格式
        String qrcodeImageBase64 = QRCodeUtils.generateQRCodeToBase64(qrcodeUrl);
        // 生成带车牌号的二维码图片为base64格式
        String qrcodeImageBase64 = QRCodeUtils.generateQRCodeWithVehicleNoToBase64(qrcodeUrl, vehicleNo);
        if (qrcodeImageBase64 != null) {
            VehicleEvaluationQrcode qrcode = new VehicleEvaluationQrcode();
@@ -176,11 +219,7 @@
            return null;
        }
        // 检查车辆是否存在
        VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoByVehicleNo(vehicleNo);
        if (vehicleInfo == null) {
            return null;
        }
        // 注意:这里不检查车辆信息表,允许为任意车牌号生成二维码
        // 检查是否已存在二维码
        VehicleEvaluationQrcode existingQrcode = vehicleEvaluationQrcodeMapper.selectVehicleEvaluationQrcodeByVehicleNo(vehicleNo);
@@ -191,8 +230,8 @@
            existingQrcode.setUpdateBy("system");
            existingQrcode.setUpdateTime(DateUtils.getNowDate());
            
            // 重新生成二维码图片为base64格式
            String qrcodeImageBase64 = QRCodeUtils.generateQRCodeToBase64(qrcodeUrl);
            // 重新生成带车牌号的二维码图片为base64格式
            String qrcodeImageBase64 = QRCodeUtils.generateQRCodeWithVehicleNoToBase64(qrcodeUrl, vehicleNo);
            
            if (qrcodeImageBase64 != null) {
                existingQrcode.setQrcodeImage(qrcodeImageBase64);
@@ -205,8 +244,8 @@
        // 生成二维码内容
        String qrcodeContent = "EVAL:" + vehicleNo;
        // 生成二维码图片为base64格式
        String qrcodeImageBase64 = QRCodeUtils.generateQRCodeToBase64(qrcodeUrl);
        // 生成带车牌号的二维码图片为base64格式
        String qrcodeImageBase64 = QRCodeUtils.generateQRCodeWithVehicleNoToBase64(qrcodeUrl, vehicleNo);
        if (qrcodeImageBase64 != null) {
            VehicleEvaluationQrcode qrcode = new VehicleEvaluationQrcode();
@@ -249,4 +288,32 @@
        return successCount;
    }
    /**
     * 批量生成车辆评价二维码(指定车牌号列表)
     *
     * @param vehicleNos 车牌号列表
     * @param qrcodeUrl 二维码URL(可选)
     * @return 结果
     */
    @Override
    public int batchGenerateVehicleEvaluationQrcode(List<String> vehicleNos, String qrcodeUrl) {
        int successCount = 0;
        for (String vehicleNo : vehicleNos) {
            if (StringUtils.isEmpty(vehicleNo)) {
                continue; // 跳过空的车牌号
            }
            VehicleEvaluationQrcode qrcode;
            if (StringUtils.isEmpty(qrcodeUrl)) {
                qrcode = generateVehicleEvaluationQrcodeWithoutVehicleCheck(vehicleNo);
            } else {
                qrcode = generateVehicleEvaluationQrcode(vehicleNo, qrcodeUrl);
            }
            if (qrcode != null) {
                successCount++;
            }
        }
        return successCount;
    }
}
ruoyi-ui/src/api/evaluation.js
@@ -88,10 +88,11 @@
}
// 批量生成车辆评价二维码
export function batchGenerateQrcode() {
export function batchGenerateQrcode(data) {
  return request({
    url: '/evaluation/qrcode/batch',
    method: 'post'
    method: 'post',
    data: data
  })
}
ruoyi-ui/src/views/evaluation/index.vue
@@ -3,7 +3,7 @@
    <!-- 页面头部 -->
    <div class="evaluation-header">
      <h1>服务评价</h1>
      <p>感谢您使用我们的服务,请对本次服务进行评价</p>
      <p>感谢您使用我们的非120急救医疗转运服务,请对本次服务进行评价!</p>
    </div>
    <!-- 车辆信息 -->
@@ -19,7 +19,7 @@
      <el-form ref="evaluationForm" :model="evaluationForm" :rules="rules" label-width="80px" size="small">
        <!-- 客户信息 -->
        <div class="form-section">
          <h3>客户信息</h3>
          <h3>客户信息:</h3>
          
          <!-- 微信授权信息显示 -->
          <div v-if="evaluationForm.wechatOpenid" class="wechat-info">
@@ -46,14 +46,13 @@
            <div class="wechat-tip">点击可自动获取您的微信信息</div>
          </div>
          
          <el-form-item label="姓名" prop="customerName">
          <el-form-item label="称呼" prop="customerName">
            <el-input v-model="evaluationForm.customerName" placeholder="请输入您的姓名" />
          </el-form-item>
          <el-form-item label="手机号" prop="customerPhone">
            <el-input v-model="evaluationForm.customerPhone" placeholder="请输入您的手机号" />
            <div v-if="evaluationForm.wechatOpenid" class="phone-tip">
              <i class="el-icon-info"></i>
              微信授权无法直接获取手机号,请手动输入
            </div>
          </el-form-item>
        </div>
@@ -65,17 +64,16 @@
            <!-- 星级评价 - 标题和评分在同一行 -->
            <div v-if="dimension.dimensionType === 'star'" class="star-rating-inline">
              <div class="dimension-title-inline">
                <span>{{ dimension.dimensionName }}</span>
                <span class="dimension-name-fixed">{{ dimension.dimensionName }}</span>
                <span v-if="dimension.isRequired === '1'" class="required">*</span>
              </div>
              <div class="star-rating-content">
                <el-rate
                  :value="getDimensionScore(dimension.dimensionId)"
                  :max="5"
                  show-text
                  :texts="['很差', '较差', '一般', '满意', '非常满意']"
                  @change="updateDimensionScore(dimension.dimensionId, $event)"
                  size="small"
                  :aria-label="`评价${dimension.dimensionName}`"
                />
              </div>
            </div>
@@ -90,8 +88,16 @@
                {{ dimension.dimensionDesc }}
              </div>
              <div class="select-rating">
                <el-radio-group :value="getDimensionOption(dimension.dimensionId)" @change="updateDimensionOption(dimension.dimensionId, $event)" size="small">
                  <el-radio v-for="option in getDimensionOptions(dimension)" :key="option.value" :label="option.value">
                <el-radio-group
                  v-model="selectedOptions[dimension.dimensionId]"
                  @change="(value) => handleOptionChange(dimension.dimensionId, value)"
                  size="small"
                  :aria-label="`选择${dimension.dimensionName}`">
                  <el-radio
                    v-for="option in getDimensionOptions(dimension)"
                    :key="option.value"
                    :label="option.value"
                    :aria-label="option.label">
                    {{ option.label }}
                  </el-radio>
                </el-radio-group>
@@ -115,6 +121,7 @@
                  placeholder="请输入您的意见或建议"
                  @input="updateDimensionText(dimension.dimensionId, $event)"
                  size="small"
                  :aria-label="`${dimension.dimensionName}评价意见`"
                />
              </div>
            </div>
@@ -166,6 +173,8 @@
        wechatPhone: '',
        evaluationDetails: []
      },
      // 用于存储选择类型的评价选项
      selectedOptions: {},
      rules: {
        customerName: [
          { required: true, message: '请输入您的姓名', trigger: 'blur' }
@@ -303,13 +312,37 @@
        detail = { dimensionId, score: 0 };
        this.evaluationForm.evaluationDetails.push(detail);
      }
      detail.score = score;
      // 使用Vue.set确保响应式更新
      this.$set(detail, 'score', score);
    },
    // 获取维度选项
    getDimensionOption(dimensionId) {
      const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
      return detail ? detail.optionValue : '';
    },
    // 获取维度选项值(用于v-model)
    getDimensionOptionValue(dimensionId) {
      const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
      if (!detail) {
        // 如果不存在,创建一个新的detail对象
        const newDetail = { dimensionId, optionValue: '' };
        this.evaluationForm.evaluationDetails.push(newDetail);
        return newDetail;
      }
      return detail;
    },
    // 获取维度选项的v-model对象
    getDimensionOptionModel(dimensionId) {
      const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
      if (!detail) {
        const newDetail = { dimensionId, optionValue: '' };
        this.evaluationForm.evaluationDetails.push(newDetail);
        return newDetail;
      }
      return detail;
    },
    // 更新维度选项
@@ -319,7 +352,16 @@
        detail = { dimensionId, optionValue: '' };
        this.evaluationForm.evaluationDetails.push(detail);
      }
      detail.optionValue = optionValue;
      // 使用Vue.set确保响应式更新
      this.$set(detail, 'optionValue', optionValue);
    },
    // 处理选项变化
    handleOptionChange(dimensionId, value) {
      // 更新selectedOptions
      this.$set(this.selectedOptions, dimensionId, value);
      // 同时更新evaluationDetails
      this.updateDimensionOption(dimensionId, value);
    },
    // 获取维度文本
@@ -335,7 +377,8 @@
        detail = { dimensionId, textContent: '' };
        this.evaluationForm.evaluationDetails.push(detail);
      }
      detail.textContent = textContent;
      // 使用Vue.set确保响应式更新
      this.$set(detail, 'textContent', textContent);
    },
    // 获取维度选项配置
@@ -344,6 +387,7 @@
      try {
        return JSON.parse(dimension.options);
      } catch (error) {
        console.error('Error parsing options for', dimension.dimensionName, ':', error);
        return [];
      }
    },
@@ -372,7 +416,7 @@
        // 提交评价
        const response = await submitEvaluation(this.evaluationForm);
        if (response.code === 200) {
          this.resultMessage = response.msg;
          this.resultMessage = "感谢您的反馈,您的反馈将促使我们不断进步,我们将继续提供更好的服务";
          this.showResult = true;
        } else {
          this.$message.error(response.msg || '提交失败,请重试');
@@ -391,6 +435,7 @@
      this.evaluationForm.customerName = '';
      this.evaluationForm.customerPhone = '';
      this.evaluationForm.evaluationDetails = [];
      this.selectedOptions = {};
      this.$refs.evaluationForm.resetFields();
    }
  }
@@ -513,6 +558,15 @@
  flex-shrink: 0;
}
.dimension-name-fixed {
  display: inline-block;
  width: 100px;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.star-rating-content {
  flex: 1;
  min-width: 200px;
@@ -540,6 +594,69 @@
.select-rating .el-radio__label {
  font-size: 13px;
}
/* 改善无障碍访问 */
.select-rating .el-radio__original {
  position: absolute !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  border: none !important;
  outline: none !important;
  clip: rect(0, 0, 0, 0) !important;
  -webkit-appearance: none !important;
  -moz-appearance: none !important;
  appearance: none !important;
}
.select-rating .el-radio__input {
  position: relative;
  white-space: nowrap;
  vertical-align: middle;
  outline: none;
  line-height: 1;
}
.select-rating .el-radio__inner {
  border: 1px solid #dcdfe6;
  border-radius: 100%;
  width: 14px;
  height: 14px;
  background-color: #fff;
  position: relative;
  cursor: pointer;
  display: inline-block;
  box-sizing: border-box;
  transition: border-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46), background-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46);
}
.select-rating .el-radio__inner:hover {
  border-color: #409eff;
}
.select-rating .el-radio.is-checked .el-radio__inner {
  border-color: #409eff;
  background: #409eff;
}
.select-rating .el-radio.is-checked .el-radio__inner::after {
  transform: translate(-50%, -50%) scale(1);
}
.select-rating .el-radio__inner::after {
  width: 4px;
  height: 4px;
  border-radius: 100%;
  background-color: #fff;
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0);
  transition: transform 0.15s ease-in;
}
/* 优化文本评价显示 */
@@ -736,6 +853,11 @@
    font-size: 13px;
  }
  
  .dimension-name-fixed {
    width: 120px;
    font-size: 13px;
  }
  .star-rating-content {
    min-width: auto;
    width: 100%;
ruoyi-ui/src/views/evaluation/qrcode/index.vue
@@ -58,7 +58,7 @@
    <el-table v-loading="loading" :data="qrcodeList" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="二维码ID" align="center" prop="qrcodeId" />
      <el-table-column label="车牌号" align="center" prop="vehicleNo" />
      <el-table-column label="二维码URL" align="center" prop="qrcodeUrl" width="200">
        <template slot-scope="scope">
@@ -128,7 +128,7 @@
          <el-input v-model="form.vehicleNo" placeholder="请输入车牌号" />
        </el-form-item>
        <el-form-item label="二维码URL" prop="qrcodeUrl">
          <el-input v-model="form.qrcodeUrl" placeholder="请输入二维码URL" />
          <el-input v-model="form.qrcodeUrl" placeholder="可选,留空则使用默认URL" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
@@ -137,10 +137,30 @@
      </div>
    </el-dialog>
    <!-- 批量生成二维码对话框 -->
    <el-dialog title="批量生成二维码" :visible.sync="batchOpen" width="600px" append-to-body>
      <el-form ref="batchForm" :model="batchForm" :rules="batchRules" label-width="100px">
        <el-form-item label="车牌号" prop="vehicleNos">
          <el-input
            v-model="batchForm.vehicleNos"
            type="textarea"
            :rows="6"
            placeholder="请输入车牌号,多个车牌号用逗号分隔,例如:粤A12345,粤B67890,粤C11111" />
        </el-form-item>
        <el-form-item label="二维码URL" prop="qrcodeUrl">
          <el-input v-model="batchForm.qrcodeUrl" placeholder="可选,留空则使用默认URL" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitBatchForm">确 定</el-button>
        <el-button @click="cancelBatch">取 消</el-button>
      </div>
    </el-dialog>
    <!-- 二维码详情对话框 -->
    <el-dialog title="二维码详情" :visible.sync="viewOpen" width="600px" append-to-body>
      <el-descriptions :column="2" border>
        <el-descriptions-item label="二维码ID">{{ viewForm.qrcodeId }}</el-descriptions-item>
        <el-descriptions-item label="车牌号">{{ viewForm.vehicleNo }}</el-descriptions-item>
        <el-descriptions-item label="二维码URL" :span="2">
          <el-link :href="viewForm.qrcodeUrl" target="_blank" type="primary">{{ viewForm.qrcodeUrl }}</el-link>
@@ -194,6 +214,8 @@
      title: "",
      // 是否显示弹出层
      open: false,
      // 是否显示批量生成弹出层
      batchOpen: false,
      // 是否显示查看弹出层
      viewOpen: false,
      // 查询参数
@@ -205,6 +227,8 @@
      },
      // 表单参数
      form: {},
      // 批量生成表单参数
      batchForm: {},
      // 查看表单参数
      viewForm: {},
      // 表单校验
@@ -213,7 +237,15 @@
          { required: true, message: "车牌号不能为空", trigger: "blur" }
        ],
        qrcodeUrl: [
          { required: true, message: "二维码URL不能为空", trigger: "blur" },
          { type: 'url', message: '请输入正确的URL格式', trigger: 'blur' }
        ]
      },
      // 批量生成表单校验
      batchRules: {
        vehicleNos: [
          { required: true, message: "车牌号不能为空", trigger: "blur" }
        ],
        qrcodeUrl: [
          { type: 'url', message: '请输入正确的URL格式', trigger: 'blur' }
        ]
      }
@@ -249,6 +281,14 @@
      };
      this.resetForm("form");
    },
    // 批量表单重置
    resetBatch() {
      this.batchForm = {
        vehicleNos: null,
        qrcodeUrl: null
      };
      this.resetForm("batchForm");
    },
    /** 搜索按钮操作 */
    handleQuery() {
      this.queryParams.pageNum = 1;
@@ -277,7 +317,7 @@
        if (valid) {
          const params = {
            vehicleNo: this.form.vehicleNo,
            qrcodeUrl: this.form.qrcodeUrl
            qrcodeUrl: this.form.qrcodeUrl || null
          };
          generateQrcode(params).then(response => {
            this.$modal.msgSuccess("生成成功");
@@ -289,12 +329,48 @@
    },
    /** 批量生成按钮操作 */
    handleBatchGenerate() {
      this.$modal.confirm('是否确认批量生成所有车辆的二维码?').then(function() {
        return batchGenerateQrcode();
      }).then(() => {
        this.getList();
        this.$modal.msgSuccess("批量生成成功");
      }).catch(() => {});
      this.resetBatch();
      this.batchOpen = true;
    },
    // 取消批量生成
    cancelBatch() {
      this.batchOpen = false;
      this.resetBatch();
    },
    /** 批量提交按钮 */
    submitBatchForm() {
      this.$refs["batchForm"].validate(valid => {
        if (valid) {
          const vehicleNos = this.batchForm.vehicleNos.split(',').map(no => no.trim()).filter(no => no);
          if (vehicleNos.length === 0) {
            this.$modal.msgError("请输入有效的车牌号");
            return;
          }
          console.log('批量生成车牌号列表:', vehicleNos);
          const params = {
            vehicleNos: vehicleNos,
            qrcodeUrl: this.batchForm.qrcodeUrl || null
          };
          console.log('批量生成参数:', params);
          batchGenerateQrcode(params).then(response => {
            console.log('批量生成响应:', response);
            if (response.code === 200) {
              this.$modal.msgSuccess(response.msg || "批量生成成功");
            } else {
              this.$modal.msgError(response.msg || "批量生成失败");
            }
            this.batchOpen = false;
            this.getList();
          }).catch(error => {
            console.error('批量生成失败:', error);
            this.$modal.msgError("批量生成失败,请重试");
          });
        }
      });
    },
    /** 查看按钮操作 */
    handleView(row) {