From 7d81ce01560d384f15212edc40ebeaa9924913f9 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期日, 21 九月 2025 19:12:53 +0800
Subject: [PATCH] feat:新增评价功能
---
ruoyi-system/src/main/resources/mapper/system/CustomerEvaluationMapper.xml | 159 +
ruoyi-ui/src/views/system/vehicle/index.vue | 43
客户满意度评价功能说明.md | 134 +
ruoyi-system/src/main/java/com/ruoyi/system/domain/EvaluationDimension.java | 129 +
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CustomerEvaluationServiceImpl.java | 196 +
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleEvaluationQrcodeServiceImpl.java | 252 ++
ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleEvaluationQrcode.java | 104
ruoyi-system/src/main/resources/mapper/system/EvaluationDimensionMapper.xml | 110 +
pom.xml | 14
ruoyi-system/src/main/java/com/ruoyi/system/mapper/EvaluationDimensionMapper.java | 67
ruoyi-system/src/main/java/com/ruoyi/system/mapper/AOrderStatusMapper.java | 2
ruoyi-system/src/main/java/com/ruoyi/system/service/IEvaluationDimensionService.java | 67
ruoyi-system/src/main/java/com/ruoyi/system/mapper/EvaluationDetailMapper.java | 84
完整部署指南.md | 225 ++
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java | 8
ruoyi-system/src/main/java/com/ruoyi/system/mapper/CustomerEvaluationMapper.java | 84
sql/evaluation_dict.sql | 26
ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationDimensionController.java | 97
ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java | 214 +
ruoyi-common/src/main/java/com/ruoyi/common/utils/QRCodeUtils.java | 98
ruoyi-ui/src/router/index.js | 12
ruoyi-ui/src/views/evaluation/index.vue | 659 ++++++
ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java | 163 +
ruoyi-ui/src/views/evaluation/dimension/index.vue | 325 ++
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleEvaluationQrcodeMapper.java | 76
sql/customer_evaluation_tables.sql | 100
ruoyi-system/src/main/resources/mapper/system/EvaluationDetailMapper.xml | 116 +
ruoyi-system/src/main/java/com/ruoyi/system/service/ICustomerEvaluationService.java | 92
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EvaluationDimensionServiceImpl.java | 99
sql/evaluation_menu.sql | 79
ruoyi-system/src/main/java/com/ruoyi/system/domain/EvaluationDetail.java | 126 +
ruoyi-admin/src/main/resources/application.yml | 8
ruoyi-common/pom.xml | 11
ruoyi-ui/src/views/evaluation/customer/index.vue | 297 ++
部署说明.md | 249 ++
测试步骤.md | 121 +
ruoyi-ui/src/views/evaluation/test.vue | 187 +
ruoyi-system/src/main/resources/mapper/system/VehicleEvaluationQrcodeMapper.xml | 103
ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/VehicleEvaluationQrcodeController.java | 145 +
ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java | 26
ruoyi-ui/src/views/evaluation/statistics/index.vue | 512 ++++
ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleEvaluationQrcodeService.java | 92
ruoyi-ui/src/views/evaluation/qrcode/index.vue | 345 +++
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java | 4
ruoyi-system/src/main/java/com/ruoyi/system/domain/CustomerEvaluation.java | 209 +
ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml | 34
sql/vehicle_info.sql | 5
ruoyi-ui/src/api/evaluation.js | 181 +
48 files changed, 6,472 insertions(+), 17 deletions(-)
diff --git a/pom.xml b/pom.xml
index 0d08086..1978da3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,7 @@
<poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version>
<jwt.version>0.9.1</jwt.version>
+ <zxing.version>3.5.1</zxing.version>
<!-- override dependency version -->
<tomcat.version>9.0.102</tomcat.version>
<logback.version>1.2.13</logback.version>
@@ -183,6 +184,19 @@
<version>${kaptcha.version}</version>
</dependency>
+ <!-- 浜岀淮鐮佺敓鎴� -->
+ <dependency>
+ <groupId>com.google.zxing</groupId>
+ <artifactId>core</artifactId>
+ <version>${zxing.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.zxing</groupId>
+ <artifactId>javase</artifactId>
+ <version>${zxing.version}</version>
+ </dependency>
+
<!-- 瀹氭椂浠诲姟-->
<dependency>
<groupId>com.ruoyi</groupId>
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java
new file mode 100644
index 0000000..450ce95
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java
@@ -0,0 +1,214 @@
+package com.ruoyi.web.controller.evaluation;
+
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.common.utils.WechatUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.system.domain.EvaluationDetail;
+import com.ruoyi.system.service.IEvaluationDimensionService;
+import com.ruoyi.system.domain.EvaluationDimension;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.CustomerEvaluation;
+import com.ruoyi.system.service.ICustomerEvaluationService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 瀹㈡埛璇勪环Controller
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@RestController
+@RequestMapping("/evaluation")
+public class EvaluationController extends BaseController {
+ @Autowired
+ private ICustomerEvaluationService customerEvaluationService;
+
+ @Autowired
+ private IEvaluationDimensionService evaluationDimensionService;
+
+ /**
+ * 鏌ヨ瀹㈡埛璇勪环鍒楄〃
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(CustomerEvaluation customerEvaluation) {
+ startPage();
+ List<CustomerEvaluation> list = customerEvaluationService.selectCustomerEvaluationList(customerEvaluation);
+ return getDataTable(list);
+ }
+
+ /**
+ * 瀵煎嚭瀹㈡埛璇勪环鍒楄〃
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:export')")
+ @Log(title = "瀹㈡埛璇勪环", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, CustomerEvaluation customerEvaluation) {
+ List<CustomerEvaluation> list = customerEvaluationService.selectCustomerEvaluationList(customerEvaluation);
+ ExcelUtil<CustomerEvaluation> util = new ExcelUtil<CustomerEvaluation>(CustomerEvaluation.class);
+ util.exportExcel(response, list, "瀹㈡埛璇勪环鏁版嵁");
+ }
+
+ /**
+ * 鑾峰彇瀹㈡埛璇勪环璇︾粏淇℃伅
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:query')")
+ @GetMapping(value = "/{evaluationId}")
+ public AjaxResult getInfo(@PathVariable("evaluationId") Long evaluationId) {
+ return success(customerEvaluationService.selectCustomerEvaluationByEvaluationId(evaluationId));
+ }
+
+ /**
+ * 鏂板瀹㈡埛璇勪环
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:add')")
+ @Log(title = "瀹㈡埛璇勪环", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody CustomerEvaluation customerEvaluation) {
+ return toAjax(customerEvaluationService.insertCustomerEvaluation(customerEvaluation));
+ }
+
+ /**
+ * 淇敼瀹㈡埛璇勪环
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:edit')")
+ @Log(title = "瀹㈡埛璇勪环", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody CustomerEvaluation customerEvaluation) {
+ return toAjax(customerEvaluationService.updateCustomerEvaluation(customerEvaluation));
+ }
+
+ /**
+ * 鍒犻櫎瀹㈡埛璇勪环
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:remove')")
+ @Log(title = "瀹㈡埛璇勪环", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{evaluationIds}")
+ public AjaxResult remove(@PathVariable Long[] evaluationIds) {
+ return toAjax(customerEvaluationService.deleteCustomerEvaluationByEvaluationIds(evaluationIds));
+ }
+
+ /**
+ * 鑾峰彇璇勪环缁村害閰嶇疆
+ */
+ @Anonymous
+ @GetMapping("/dimensions")
+ public AjaxResult getDimensions() {
+ List<EvaluationDimension> dimensions = evaluationDimensionService.selectEnabledEvaluationDimensionList();
+ return success(dimensions);
+ }
+
+ /**
+ * 鎻愪氦瀹㈡埛璇勪环锛堝叕寮�鎺ュ彛锛�
+ */
+ @Anonymous
+ @PostMapping("/submit")
+ public AjaxResult submitEvaluation(@RequestBody CustomerEvaluation customerEvaluation, HttpServletRequest request) {
+ try {
+ // 璁剧疆IP鍦板潃鍜岀敤鎴蜂唬鐞�
+ customerEvaluation.setIpAddress(getClientIP(request));
+ customerEvaluation.setUserAgent(request.getHeader("User-Agent"));
+
+ // 鎻愪氦璇勪环
+ int result = customerEvaluationService.submitCustomerEvaluation(customerEvaluation);
+
+ if (result > 0) {
+ // 鏍规嵁璇勫垎杩斿洖涓嶅悓鐨勬彁绀轰俊鎭�
+ if (customerEvaluation.getTotalScore() != null && customerEvaluation.getTotalScore().doubleValue() < 3.0) {
+ return success("鎻愪氦鎴愬姛锛屾垜浠皢绔姏鏀硅繘");
+ } else {
+ return success("鎻愪氦鎴愬姛锛屾劅璋㈡偍鐨勫弬涓�");
+ }
+ } else {
+ return error("鎻愪氦澶辫触锛岃閲嶈瘯");
+ }
+ } catch (Exception e) {
+ logger.error("鎻愪氦璇勪环澶辫触", e);
+ return error("鎻愪氦澶辫触锛岃閲嶈瘯");
+ }
+ }
+
+ @Value("${wechat.appId}")
+ private String wechatAppId;
+
+ @Value("${wechat.appSecret}")
+ private String wechatAppSecret;
+
+ /**
+ * 鑾峰彇寰俊鐢ㄦ埛淇℃伅
+ */
+ @Anonymous
+ @GetMapping("/wechat/userinfo")
+ public AjaxResult getWechatUserInfo(String code, HttpServletRequest request) {
+ try {
+
+ if (StringUtils.isEmpty(code)) {
+ return error("鎺堟潈鐮佷笉鑳戒负绌�");
+ }
+
+ // 鑾峰彇缃戦〉鎺堟潈Access Token
+ JSONObject tokenInfo = WechatUtils.getWebAccessToken(wechatAppId, wechatAppSecret, code);
+ if (tokenInfo == null) {
+ return error("鑾峰彇寰俊鎺堟潈淇℃伅澶辫触");
+ }
+
+ String accessToken = tokenInfo.getString("access_token");
+ String openid = tokenInfo.getString("openid");
+
+ // 鑾峰彇鐢ㄦ埛淇℃伅
+ JSONObject userInfo = WechatUtils.getWebUserInfo(accessToken, openid);
+ if (userInfo == null) {
+ return error("鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触");
+ }
+
+ return success(userInfo);
+ } catch (Exception e) {
+ logger.error("鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触", e);
+ return error("鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触");
+ }
+ }
+
+
+ /**
+ * 鑾峰彇瀹㈡埛绔疘P鍦板潃
+ */
+ private String getClientIP(HttpServletRequest request) {
+ String ip = request.getHeader("X-Forwarded-For");
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_CLIENT_IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ return ip;
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationDimensionController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationDimensionController.java
new file mode 100644
index 0000000..d1e2c4c
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationDimensionController.java
@@ -0,0 +1,97 @@
+package com.ruoyi.web.controller.evaluation;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.EvaluationDimension;
+import com.ruoyi.system.service.IEvaluationDimensionService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 璇勪环缁村害閰嶇疆Controller
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@RestController
+@RequestMapping("/evaluation/dimension")
+public class EvaluationDimensionController extends BaseController {
+ @Autowired
+ private IEvaluationDimensionService evaluationDimensionService;
+
+ /**
+ * 鏌ヨ璇勪环缁村害閰嶇疆鍒楄〃
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:dimension:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(EvaluationDimension evaluationDimension) {
+ startPage();
+ List<EvaluationDimension> list = evaluationDimensionService.selectEvaluationDimensionList(evaluationDimension);
+ return getDataTable(list);
+ }
+
+ /**
+ * 瀵煎嚭璇勪环缁村害閰嶇疆鍒楄〃
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:dimension:export')")
+ @Log(title = "璇勪环缁村害閰嶇疆", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, EvaluationDimension evaluationDimension) {
+ List<EvaluationDimension> list = evaluationDimensionService.selectEvaluationDimensionList(evaluationDimension);
+ ExcelUtil<EvaluationDimension> util = new ExcelUtil<EvaluationDimension>(EvaluationDimension.class);
+ util.exportExcel(response, list, "璇勪环缁村害閰嶇疆鏁版嵁");
+ }
+
+ /**
+ * 鑾峰彇璇勪环缁村害閰嶇疆璇︾粏淇℃伅
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:dimension:query')")
+ @GetMapping(value = "/{dimensionId}")
+ public AjaxResult getInfo(@PathVariable("dimensionId") Long dimensionId) {
+ return success(evaluationDimensionService.selectEvaluationDimensionByDimensionId(dimensionId));
+ }
+
+ /**
+ * 鏂板璇勪环缁村害閰嶇疆
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:dimension:add')")
+ @Log(title = "璇勪环缁村害閰嶇疆", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody EvaluationDimension evaluationDimension) {
+ return toAjax(evaluationDimensionService.insertEvaluationDimension(evaluationDimension));
+ }
+
+ /**
+ * 淇敼璇勪环缁村害閰嶇疆
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:dimension:edit')")
+ @Log(title = "璇勪环缁村害閰嶇疆", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody EvaluationDimension evaluationDimension) {
+ return toAjax(evaluationDimensionService.updateEvaluationDimension(evaluationDimension));
+ }
+
+ /**
+ * 鍒犻櫎璇勪环缁村害閰嶇疆
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:dimension:remove')")
+ @Log(title = "璇勪环缁村害閰嶇疆", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{dimensionIds}")
+ public AjaxResult remove(@PathVariable Long[] dimensionIds) {
+ return toAjax(evaluationDimensionService.deleteEvaluationDimensionByDimensionIds(dimensionIds));
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/VehicleEvaluationQrcodeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/VehicleEvaluationQrcodeController.java
new file mode 100644
index 0000000..3aa5fa2
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/VehicleEvaluationQrcodeController.java
@@ -0,0 +1,145 @@
+package com.ruoyi.web.controller.evaluation;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.VehicleEvaluationQrcode;
+import com.ruoyi.system.service.IVehicleEvaluationQrcodeService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.StringUtils;
+import com.alibaba.fastjson2.JSONObject;
+
+/**
+ * 杞﹁締璇勪环浜岀淮鐮丆ontroller
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@RestController
+@RequestMapping("/evaluation/qrcode")
+public class VehicleEvaluationQrcodeController extends BaseController {
+ @Autowired
+ private IVehicleEvaluationQrcodeService vehicleEvaluationQrcodeService;
+
+ /**
+ * 鏌ヨ杞﹁締璇勪环浜岀淮鐮佸垪琛�
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:qrcode:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(VehicleEvaluationQrcode vehicleEvaluationQrcode) {
+ startPage();
+ List<VehicleEvaluationQrcode> list = vehicleEvaluationQrcodeService.selectVehicleEvaluationQrcodeList(vehicleEvaluationQrcode);
+ return getDataTable(list);
+ }
+
+ /**
+ * 瀵煎嚭杞﹁締璇勪环浜岀淮鐮佸垪琛�
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:qrcode:export')")
+ @Log(title = "杞﹁締璇勪环浜岀淮鐮�", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, VehicleEvaluationQrcode vehicleEvaluationQrcode) {
+ List<VehicleEvaluationQrcode> list = vehicleEvaluationQrcodeService.selectVehicleEvaluationQrcodeList(vehicleEvaluationQrcode);
+ ExcelUtil<VehicleEvaluationQrcode> util = new ExcelUtil<VehicleEvaluationQrcode>(VehicleEvaluationQrcode.class);
+ util.exportExcel(response, list, "杞﹁締璇勪环浜岀淮鐮佹暟鎹�");
+ }
+
+ /**
+ * 鑾峰彇杞﹁締璇勪环浜岀淮鐮佽缁嗕俊鎭�
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:qrcode:query')")
+ @GetMapping(value = "/{qrcodeId}")
+ public AjaxResult getInfo(@PathVariable("qrcodeId") Long qrcodeId) {
+ return success(vehicleEvaluationQrcodeService.selectVehicleEvaluationQrcodeByQrcodeId(qrcodeId));
+ }
+
+ /**
+ * 鏂板杞﹁締璇勪环浜岀淮鐮�
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:qrcode:add')")
+ @Log(title = "杞﹁締璇勪环浜岀淮鐮�", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody VehicleEvaluationQrcode vehicleEvaluationQrcode) {
+ return toAjax(vehicleEvaluationQrcodeService.insertVehicleEvaluationQrcode(vehicleEvaluationQrcode));
+ }
+
+ /**
+ * 淇敼杞﹁締璇勪环浜岀淮鐮�
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:qrcode:edit')")
+ @Log(title = "杞﹁締璇勪环浜岀淮鐮�", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody VehicleEvaluationQrcode vehicleEvaluationQrcode) {
+ return toAjax(vehicleEvaluationQrcodeService.updateVehicleEvaluationQrcode(vehicleEvaluationQrcode));
+ }
+
+ /**
+ * 鍒犻櫎杞﹁締璇勪环浜岀淮鐮�
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:qrcode:remove')")
+ @Log(title = "杞﹁締璇勪环浜岀淮鐮�", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{qrcodeIds}")
+ public AjaxResult remove(@PathVariable Long[] qrcodeIds) {
+ return toAjax(vehicleEvaluationQrcodeService.deleteVehicleEvaluationQrcodeByQrcodeIds(qrcodeIds));
+ }
+
+ /**
+ * 鐢熸垚杞﹁締璇勪环浜岀淮鐮�
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:qrcode:generate')")
+ @Log(title = "杞﹁締璇勪环浜岀淮鐮�", businessType = BusinessType.INSERT)
+ @PostMapping("/generate")
+ public AjaxResult generateQrcode(@RequestBody JSONObject params) {
+ try {
+ String vehicleNo = params.getString("vehicleNo");
+ String qrcodeUrl = params.getString("qrcodeUrl");
+
+ if (StringUtils.isEmpty(vehicleNo)) {
+ return error("杞︾墝鍙蜂笉鑳戒负绌�");
+ }
+ if (StringUtils.isEmpty(qrcodeUrl)) {
+ return error("浜岀淮鐮乁RL涓嶈兘涓虹┖");
+ }
+
+ VehicleEvaluationQrcode qrcode = vehicleEvaluationQrcodeService.generateVehicleEvaluationQrcode(vehicleNo, qrcodeUrl);
+ if (qrcode != null) {
+ return success(qrcode);
+ } else {
+ return error("鐢熸垚浜岀淮鐮佸け璐�");
+ }
+ } catch (Exception e) {
+ logger.error("鐢熸垚浜岀淮鐮佸け璐�", e);
+ return error("鐢熸垚浜岀淮鐮佸け璐�");
+ }
+ }
+
+ /**
+ * 鎵归噺鐢熸垚杞﹁締璇勪环浜岀淮鐮�
+ */
+ @PreAuthorize("@ss.hasPermi('evaluation:qrcode:batch')")
+ @Log(title = "杞﹁締璇勪环浜岀淮鐮�", businessType = BusinessType.INSERT)
+ @PostMapping("/batch")
+ public AjaxResult batchGenerateQrcode() {
+ try {
+ int count = vehicleEvaluationQrcodeService.batchGenerateVehicleEvaluationQrcode();
+ return success("鎴愬姛鐢熸垚 " + count + " 涓簩缁寸爜");
+ } catch (Exception e) {
+ logger.error("鎵归噺鐢熸垚浜岀淮鐮佸け璐�", e);
+ return error("鎵归噺鐢熸垚浜岀淮鐮佸け璐�");
+ }
+ }
+}
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 0128223..69c5d06 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -56,7 +56,7 @@
basename: i18n/messages
profiles:
# 鐜 dev|test|prod
- active: prod
+ active: dev
# 鏂囦欢涓婁紶
servlet:
multipart:
@@ -144,3 +144,9 @@
# 姘戣埅鎺ュ彛鍦板潃
min:
apiUrl: http://120.25.98.119:8084/v1/ #娴嬭瘯鐜锛歭ocalhost:8011
+
+# 寰俊閰嶇疆
+wechat:
+ appId: your_wechat_appid
+ appSecret: your_wechat_appsecret
+ redirectUri: http://yourdomain.com/evaluation
\ No newline at end of file
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 5266477..dcb55fa 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -117,6 +117,17 @@
<artifactId>UserAgentUtils</artifactId>
</dependency>
+ <!-- 浜岀淮鐮佺敓鎴� -->
+ <dependency>
+ <groupId>com.google.zxing</groupId>
+ <artifactId>core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.zxing</groupId>
+ <artifactId>javase</artifactId>
+ </dependency>
+
<!-- servlet鍖� -->
<dependency>
<groupId>javax.servlet</groupId>
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/QRCodeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/QRCodeUtils.java
new file mode 100644
index 0000000..5a28d53
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/QRCodeUtils.java
@@ -0,0 +1,98 @@
+package com.ruoyi.common.utils;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 浜岀淮鐮佺敓鎴愬伐鍏风被
+ *
+ * @author ruoyi
+ */
+public class QRCodeUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(QRCodeUtils.class);
+
+ private static final int WIDTH = 300;
+ private static final int HEIGHT = 300;
+ private static final String FORMAT = "png";
+
+ /**
+ * 鐢熸垚浜岀淮鐮佸埌鏂囦欢
+ *
+ * @param content 浜岀淮鐮佸唴瀹�
+ * @param filePath 鏂囦欢璺緞
+ * @return 鏄惁鐢熸垚鎴愬姛
+ */
+ public static boolean generateQRCodeToFile(String content, String filePath) {
+ 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);
+
+ File file = new File(filePath);
+ if (!file.getParentFile().exists()) {
+ file.getParentFile().mkdirs();
+ }
+
+ MatrixToImageWriter.writeToFile(bitMatrix, FORMAT, file);
+ return true;
+ } catch (Exception e) {
+ log.error("鐢熸垚浜岀淮鐮佸け璐�: {}", e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * 鐢熸垚浜岀淮鐮佸埌瀛楄妭鏁扮粍
+ *
+ * @param content 浜岀淮鐮佸唴瀹�
+ * @return 瀛楄妭鏁扮粍
+ */
+ public static byte[] generateQRCodeToBytes(String content) {
+ 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 image = MatrixToImageWriter.toBufferedImage(bitMatrix);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(image, FORMAT, baos);
+
+ return baos.toByteArray();
+ } catch (Exception e) {
+ log.error("鐢熸垚浜岀淮鐮佸け璐�: {}", e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * 鐢熸垚Base64缂栫爜鐨勪簩缁寸爜
+ *
+ * @param content 浜岀淮鐮佸唴瀹�
+ * @return Base64缂栫爜鐨勪簩缁寸爜
+ */
+ public static String generateQRCodeToBase64(String content) {
+ byte[] bytes = generateQRCodeToBytes(content);
+ if (bytes != null) {
+ return "data:image/png;base64," + java.util.Base64.getEncoder().encodeToString(bytes);
+ }
+ return null;
+ }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java
new file mode 100644
index 0000000..5b3e6e8
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java
@@ -0,0 +1,163 @@
+package com.ruoyi.common.utils;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 寰俊宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+public class WechatUtils {
+
+ private static final Logger log = LoggerFactory.getLogger(WechatUtils.class);
+
+ private static final String WECHAT_API_BASE_URL = "https://api.weixin.qq.com";
+
+ /**
+ * 鑾峰彇寰俊Access Token
+ *
+ * @param appId 寰俊AppID
+ * @param appSecret 寰俊AppSecret
+ * @return Access Token
+ */
+ public static String getAccessToken(String appId, String appSecret) {
+ try {
+ String url = WECHAT_API_BASE_URL + "/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
+
+ RestTemplate restTemplate = new RestTemplate();
+ String response = restTemplate.getForObject(url, String.class);
+
+ JSONObject jsonObject = JSON.parseObject(response);
+ if (jsonObject.containsKey("access_token")) {
+ return jsonObject.getString("access_token");
+ } else {
+ log.error("鑾峰彇寰俊Access Token澶辫触: {}", response);
+ return null;
+ }
+ } catch (Exception e) {
+ log.error("鑾峰彇寰俊Access Token寮傚父: {}", e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * 鑾峰彇寰俊鐢ㄦ埛淇℃伅
+ *
+ * @param accessToken Access Token
+ * @param openid 鐢ㄦ埛OpenID
+ * @return 鐢ㄦ埛淇℃伅
+ */
+ public static JSONObject getWechatUserInfo(String accessToken, String openid) {
+ try {
+ String url = WECHAT_API_BASE_URL + "/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
+
+ RestTemplate restTemplate = new RestTemplate();
+ String response = restTemplate.getForObject(url, String.class);
+
+ JSONObject jsonObject = JSON.parseObject(response);
+ if (jsonObject.containsKey("openid")) {
+ return jsonObject;
+ } else {
+ log.error("鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触: {}", response);
+ return null;
+ }
+ } catch (Exception e) {
+ log.error("鑾峰彇寰俊鐢ㄦ埛淇℃伅寮傚父: {}", e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * 鑾峰彇寰俊缃戦〉鎺堟潈Access Token
+ *
+ * @param appId 寰俊AppID
+ * @param appSecret 寰俊AppSecret
+ * @param code 鎺堟潈鐮�
+ * @return 缃戦〉鎺堟潈Access Token淇℃伅
+ */
+ public static JSONObject getWebAccessToken(String appId, String appSecret, String code) {
+ try {
+ String url = WECHAT_API_BASE_URL + "/sns/oauth2/access_token?appid=" + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code";
+
+ RestTemplate restTemplate = new RestTemplate();
+ String response = restTemplate.getForObject(url, String.class);
+
+ JSONObject jsonObject = JSON.parseObject(response);
+ if (jsonObject.containsKey("access_token")) {
+ return jsonObject;
+ } else {
+ log.error("鑾峰彇寰俊缃戦〉鎺堟潈Access Token澶辫触: {}", response);
+ return null;
+ }
+ } catch (Exception e) {
+ log.error("鑾峰彇寰俊缃戦〉鎺堟潈Access Token寮傚父: {}", e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * 鑾峰彇寰俊缃戦〉鎺堟潈鐢ㄦ埛淇℃伅
+ *
+ * @param accessToken 缃戦〉鎺堟潈Access Token
+ * @param openid 鐢ㄦ埛OpenID
+ * @return 鐢ㄦ埛淇℃伅
+ */
+ public static JSONObject getWebUserInfo(String accessToken, String openid) {
+ try {
+ String url = WECHAT_API_BASE_URL + "/sns/userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
+
+ RestTemplate restTemplate = new RestTemplate();
+ String response = restTemplate.getForObject(url, String.class);
+
+ JSONObject jsonObject = JSON.parseObject(response);
+ if (jsonObject.containsKey("openid")) {
+ return jsonObject;
+ } else {
+ log.error("鑾峰彇寰俊缃戦〉鎺堟潈鐢ㄦ埛淇℃伅澶辫触: {}", response);
+ return null;
+ }
+ } catch (Exception e) {
+ log.error("鑾峰彇寰俊缃戦〉鎺堟潈鐢ㄦ埛淇℃伅寮傚父: {}", e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * 鐢熸垚寰俊缃戦〉鎺堟潈URL
+ *
+ * @param appId 寰俊AppID
+ * @param redirectUri 鍥炶皟鍦板潃
+ * @param scope 鎺堟潈鑼冨洿 (snsapi_base 鎴� snsapi_userinfo)
+ * @param state 鐘舵�佸弬鏁�
+ * @return 鎺堟潈URL
+ */
+ public static String generateAuthUrl(String appId, String redirectUri, String scope, String state) {
+ try {
+ String encodedRedirectUri = java.net.URLEncoder.encode(redirectUri, "UTF-8");
+ return WECHAT_API_BASE_URL + "/connect/oauth2/authorize?appid=" + appId + "&redirect_uri=" + encodedRedirectUri + "&response_type=code&scope=" + scope + "&state=" + state + "#wechat_redirect";
+ } catch (Exception e) {
+ log.error("鐢熸垚寰俊鎺堟潈URL寮傚父: {}", e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * 鍒ゆ柇鏄惁涓哄井淇℃祻瑙堝櫒
+ *
+ * @param userAgent 鐢ㄦ埛浠g悊瀛楃涓�
+ * @return 鏄惁涓哄井淇℃祻瑙堝櫒
+ */
+ public static boolean isWechatBrowser(String userAgent) {
+ if (StringUtils.isEmpty(userAgent)) {
+ return false;
+ }
+ return userAgent.toLowerCase().contains("micromessenger");
+ }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
index 0eeab6e..ad86680 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
@@ -37,6 +37,10 @@
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
.addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
+ /** 浜岀淮鐮佸浘鐗囪闂矾寰� */
+ registry.addResourceHandler("/qrcode/**")
+ .addResourceLocations("file:" + RuoYiConfig.getProfile() + "/qrcode/");
+
/** swagger閰嶇疆 */
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CustomerEvaluation.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CustomerEvaluation.java
new file mode 100644
index 0000000..89f53a4
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CustomerEvaluation.java
@@ -0,0 +1,209 @@
+package com.ruoyi.system.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 瀹㈡埛璇勪环瀵硅薄 customer_evaluation
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public class CustomerEvaluation extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 璇勪环ID */
+ private Long evaluationId;
+
+ /** 杞︾墝鍙� */
+ @Excel(name = "杞︾墝鍙�")
+ private String vehicleNo;
+
+ /** 瀹㈡埛濮撳悕 */
+ @Excel(name = "瀹㈡埛濮撳悕")
+ private String customerName;
+
+ /** 瀹㈡埛鎵嬫満鍙� */
+ @Excel(name = "瀹㈡埛鎵嬫満鍙�")
+ private String customerPhone;
+
+ /** 寰俊OpenID */
+ @Excel(name = "寰俊OpenID")
+ private String wechatOpenid;
+
+ /** 寰俊鏄电О */
+ @Excel(name = "寰俊鏄电О")
+ private String wechatNickname;
+
+ /** 寰俊澶村儚 */
+ @Excel(name = "寰俊澶村儚")
+ private String wechatAvatar;
+
+ /** 寰俊缁戝畾鎵嬫満鍙� */
+ @Excel(name = "寰俊缁戝畾鎵嬫満鍙�")
+ private String wechatPhone;
+
+ /** 鎬昏瘎鍒� */
+ @Excel(name = "鎬昏瘎鍒�")
+ private BigDecimal totalScore;
+
+ /** 璇勪环鐘舵�侊紙0寰呰瘎浠� 1宸茶瘎浠凤級 */
+ @Excel(name = "璇勪环鐘舵��", readConverterExp = "0=寰呰瘎浠�,1=宸茶瘎浠�")
+ private String evaluationStatus;
+
+ /** 璇勪环鏃堕棿 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "璇勪环鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date evaluationTime;
+
+ /** IP鍦板潃 */
+ @Excel(name = "IP鍦板潃")
+ private String ipAddress;
+
+ /** 鐢ㄦ埛浠g悊 */
+ @Excel(name = "鐢ㄦ埛浠g悊")
+ private String userAgent;
+
+ /** 璇勪环璇︽儏鍒楄〃 */
+ private List<EvaluationDetail> evaluationDetails;
+
+ public void setEvaluationId(Long evaluationId) {
+ this.evaluationId = evaluationId;
+ }
+
+ public Long getEvaluationId() {
+ return evaluationId;
+ }
+
+ public void setVehicleNo(String vehicleNo) {
+ this.vehicleNo = vehicleNo;
+ }
+
+ public String getVehicleNo() {
+ return vehicleNo;
+ }
+
+ public void setCustomerName(String customerName) {
+ this.customerName = customerName;
+ }
+
+ public String getCustomerName() {
+ return customerName;
+ }
+
+ public void setCustomerPhone(String customerPhone) {
+ this.customerPhone = customerPhone;
+ }
+
+ public String getCustomerPhone() {
+ return customerPhone;
+ }
+
+ public void setWechatOpenid(String wechatOpenid) {
+ this.wechatOpenid = wechatOpenid;
+ }
+
+ public String getWechatOpenid() {
+ return wechatOpenid;
+ }
+
+ public void setWechatNickname(String wechatNickname) {
+ this.wechatNickname = wechatNickname;
+ }
+
+ public String getWechatNickname() {
+ return wechatNickname;
+ }
+
+ public void setWechatAvatar(String wechatAvatar) {
+ this.wechatAvatar = wechatAvatar;
+ }
+
+ public String getWechatAvatar() {
+ return wechatAvatar;
+ }
+
+ public void setWechatPhone(String wechatPhone) {
+ this.wechatPhone = wechatPhone;
+ }
+
+ public String getWechatPhone() {
+ return wechatPhone;
+ }
+
+ public void setTotalScore(BigDecimal totalScore) {
+ this.totalScore = totalScore;
+ }
+
+ public BigDecimal getTotalScore() {
+ return totalScore;
+ }
+
+ public void setEvaluationStatus(String evaluationStatus) {
+ this.evaluationStatus = evaluationStatus;
+ }
+
+ public String getEvaluationStatus() {
+ return evaluationStatus;
+ }
+
+ public void setEvaluationTime(Date evaluationTime) {
+ this.evaluationTime = evaluationTime;
+ }
+
+ public Date getEvaluationTime() {
+ return evaluationTime;
+ }
+
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public void setUserAgent(String userAgent) {
+ this.userAgent = userAgent;
+ }
+
+ public String getUserAgent() {
+ return userAgent;
+ }
+
+ public List<EvaluationDetail> getEvaluationDetails() {
+ return evaluationDetails;
+ }
+
+ public void setEvaluationDetails(List<EvaluationDetail> evaluationDetails) {
+ this.evaluationDetails = evaluationDetails;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("evaluationId", getEvaluationId())
+ .append("vehicleNo", getVehicleNo())
+ .append("customerName", getCustomerName())
+ .append("customerPhone", getCustomerPhone())
+ .append("wechatOpenid", getWechatOpenid())
+ .append("wechatNickname", getWechatNickname())
+ .append("wechatAvatar", getWechatAvatar())
+ .append("wechatPhone", getWechatPhone())
+ .append("totalScore", getTotalScore())
+ .append("evaluationStatus", getEvaluationStatus())
+ .append("evaluationTime", getEvaluationTime())
+ .append("ipAddress", getIpAddress())
+ .append("userAgent", getUserAgent())
+ .append("createTime", getCreateTime())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/EvaluationDetail.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/EvaluationDetail.java
new file mode 100644
index 0000000..c07a281
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/EvaluationDetail.java
@@ -0,0 +1,126 @@
+package com.ruoyi.system.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 璇勪环璇︽儏瀵硅薄 evaluation_detail
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public class EvaluationDetail extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 璇︽儏ID */
+ private Long detailId;
+
+ /** 璇勪环ID */
+ @Excel(name = "璇勪环ID")
+ private Long evaluationId;
+
+ /** 缁村害ID */
+ @Excel(name = "缁村害ID")
+ private Long dimensionId;
+
+ /** 璇勫垎锛�1-5鏄燂級 */
+ @Excel(name = "璇勫垎")
+ private Integer score;
+
+ /** 閫夐」鍊硷紙閫夋嫨绫诲瀷鏃朵娇鐢級 */
+ @Excel(name = "閫夐」鍊�")
+ private String optionValue;
+
+ /** 鏂囨湰鍐呭锛堟枃鏈被鍨嬫椂浣跨敤锛� */
+ @Excel(name = "鏂囨湰鍐呭")
+ private String textContent;
+
+ /** 鍒涘缓鏃堕棿 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "鍒涘缓鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+
+ /** 缁村害淇℃伅 */
+ private EvaluationDimension dimension;
+
+ public void setDetailId(Long detailId) {
+ this.detailId = detailId;
+ }
+
+ public Long getDetailId() {
+ return detailId;
+ }
+
+ public void setEvaluationId(Long evaluationId) {
+ this.evaluationId = evaluationId;
+ }
+
+ public Long getEvaluationId() {
+ return evaluationId;
+ }
+
+ public void setDimensionId(Long dimensionId) {
+ this.dimensionId = dimensionId;
+ }
+
+ public Long getDimensionId() {
+ return dimensionId;
+ }
+
+ public void setScore(Integer score) {
+ this.score = score;
+ }
+
+ public Integer getScore() {
+ return score;
+ }
+
+ public void setOptionValue(String optionValue) {
+ this.optionValue = optionValue;
+ }
+
+ public String getOptionValue() {
+ return optionValue;
+ }
+
+ public void setTextContent(String textContent) {
+ this.textContent = textContent;
+ }
+
+ public String getTextContent() {
+ return textContent;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public EvaluationDimension getDimension() {
+ return dimension;
+ }
+
+ public void setDimension(EvaluationDimension dimension) {
+ this.dimension = dimension;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("detailId", getDetailId())
+ .append("evaluationId", getEvaluationId())
+ .append("dimensionId", getDimensionId())
+ .append("score", getScore())
+ .append("optionValue", getOptionValue())
+ .append("textContent", getTextContent())
+ .append("createTime", getCreateTime())
+ .toString();
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/EvaluationDimension.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/EvaluationDimension.java
new file mode 100644
index 0000000..74e7adc
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/EvaluationDimension.java
@@ -0,0 +1,129 @@
+package com.ruoyi.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 璇勪环缁村害閰嶇疆瀵硅薄 evaluation_dimension
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public class EvaluationDimension extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 缁村害ID */
+ private Long dimensionId;
+
+ /** 缁村害鍚嶇О */
+ @Excel(name = "缁村害鍚嶇О")
+ private String dimensionName;
+
+ /** 缁村害鎻忚堪 */
+ @Excel(name = "缁村害鎻忚堪")
+ private String dimensionDesc;
+
+ /** 缁村害绫诲瀷锛歴tar-鏄熺骇璇勪环锛宻elect-閫夋嫨璇勪环锛宼ext-鏂囨湰璇勪环 */
+ @Excel(name = "缁村害绫诲瀷", readConverterExp = "star=鏄熺骇璇勪环,select=閫夋嫨璇勪环,text=鏂囨湰璇勪环")
+ private String dimensionType;
+
+ /** 閫夐」閰嶇疆锛圝SON鏍煎紡锛岀敤浜庨�夋嫨绫诲瀷锛� */
+ private String options;
+
+ /** 鎺掑簭 */
+ @Excel(name = "鎺掑簭")
+ private Integer sortOrder;
+
+ /** 鏄惁蹇呭~锛�0鍚� 1鏄級 */
+ @Excel(name = "鏄惁蹇呭~", readConverterExp = "0=鍚�,1=鏄�")
+ private String isRequired;
+
+ /** 鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+ @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
+ private String status;
+
+ public void setDimensionId(Long dimensionId) {
+ this.dimensionId = dimensionId;
+ }
+
+ public Long getDimensionId() {
+ return dimensionId;
+ }
+
+ public void setDimensionName(String dimensionName) {
+ this.dimensionName = dimensionName;
+ }
+
+ public String getDimensionName() {
+ return dimensionName;
+ }
+
+ public void setDimensionDesc(String dimensionDesc) {
+ this.dimensionDesc = dimensionDesc;
+ }
+
+ public String getDimensionDesc() {
+ return dimensionDesc;
+ }
+
+ public void setDimensionType(String dimensionType) {
+ this.dimensionType = dimensionType;
+ }
+
+ public String getDimensionType() {
+ return dimensionType;
+ }
+
+ public void setOptions(String options) {
+ this.options = options;
+ }
+
+ public String getOptions() {
+ return options;
+ }
+
+ public void setSortOrder(Integer sortOrder) {
+ this.sortOrder = sortOrder;
+ }
+
+ public Integer getSortOrder() {
+ return sortOrder;
+ }
+
+ public void setIsRequired(String isRequired) {
+ this.isRequired = isRequired;
+ }
+
+ public String getIsRequired() {
+ return isRequired;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("dimensionId", getDimensionId())
+ .append("dimensionName", getDimensionName())
+ .append("dimensionDesc", getDimensionDesc())
+ .append("dimensionType", getDimensionType())
+ .append("options", getOptions())
+ .append("sortOrder", getSortOrder())
+ .append("isRequired", getIsRequired())
+ .append("status", getStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleEvaluationQrcode.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleEvaluationQrcode.java
new file mode 100644
index 0000000..6fa62e8
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleEvaluationQrcode.java
@@ -0,0 +1,104 @@
+package com.ruoyi.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 杞﹁締璇勪环浜岀淮鐮佸璞� vehicle_evaluation_qrcode
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public class VehicleEvaluationQrcode extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** 浜岀淮鐮両D */
+ private Long qrcodeId;
+
+ /** 杞︾墝鍙� */
+ @Excel(name = "杞︾墝鍙�")
+ private String vehicleNo;
+
+ /** 浜岀淮鐮乁RL */
+ @Excel(name = "浜岀淮鐮乁RL")
+ private String qrcodeUrl;
+
+ /** 浜岀淮鐮佸唴瀹� */
+ @Excel(name = "浜岀淮鐮佸唴瀹�")
+ private String qrcodeContent;
+
+ /** 浜岀淮鐮佸浘鐗囪矾寰� */
+ @Excel(name = "浜岀淮鐮佸浘鐗囪矾寰�")
+ private String qrcodeImage;
+
+ /** 鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+ @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
+ private String status;
+
+ public void setQrcodeId(Long qrcodeId) {
+ this.qrcodeId = qrcodeId;
+ }
+
+ public Long getQrcodeId() {
+ return qrcodeId;
+ }
+
+ public void setVehicleNo(String vehicleNo) {
+ this.vehicleNo = vehicleNo;
+ }
+
+ public String getVehicleNo() {
+ return vehicleNo;
+ }
+
+ public void setQrcodeUrl(String qrcodeUrl) {
+ this.qrcodeUrl = qrcodeUrl;
+ }
+
+ public String getQrcodeUrl() {
+ return qrcodeUrl;
+ }
+
+ public void setQrcodeContent(String qrcodeContent) {
+ this.qrcodeContent = qrcodeContent;
+ }
+
+ public String getQrcodeContent() {
+ return qrcodeContent;
+ }
+
+ public void setQrcodeImage(String qrcodeImage) {
+ this.qrcodeImage = qrcodeImage;
+ }
+
+ public String getQrcodeImage() {
+ return qrcodeImage;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("qrcodeId", getQrcodeId())
+ .append("vehicleNo", getVehicleNo())
+ .append("qrcodeUrl", getQrcodeUrl())
+ .append("qrcodeContent", getQrcodeContent())
+ .append("qrcodeImage", getQrcodeImage())
+ .append("status", getStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java
index b8aa771..2eb1b11 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java
@@ -42,6 +42,14 @@
@Excel(name = "骞冲彴鏍囪瘑")
private String platformCode;
+ /** 褰掑睘閮ㄩ棬ID */
+ @Excel(name = "褰掑睘閮ㄩ棬ID")
+ private Long deptId;
+
+ /** 褰掑睘閮ㄩ棬鍚嶇О */
+ @Excel(name = "褰掑睘閮ㄩ棬鍚嶇О")
+ private String deptName;
+
public void setVehicleId(Long vehicleId) {
this.vehicleId = vehicleId;
}
@@ -106,6 +114,22 @@
this.platformCode = platformCode;
}
+ public Long getDeptId() {
+ return deptId;
+ }
+
+ public void setDeptId(Long deptId) {
+ this.deptId = deptId;
+ }
+
+ public String getDeptName() {
+ return deptName;
+ }
+
+ public void setDeptName(String deptName) {
+ this.deptName = deptName;
+ }
+
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
@@ -117,6 +141,8 @@
.append("vehicleModel", getVehicleModel())
.append("status", getStatus())
.append("platformCode", getPlatformCode())
+ .append("deptId", getDeptId())
+ .append("deptName", getDeptName())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/AOrderStatusMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/AOrderStatusMapper.java
index 3904438..0c4bbe2 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/AOrderStatusMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/AOrderStatusMapper.java
@@ -11,7 +11,7 @@
* 鏌ヨ璁㈠崟鐘舵�佸垪琛�
* 榛樿鏌ヨ flag = 0 鐨勮褰�
*
- * @param aOrderStatus 璁㈠崟鐘舵�佷俊鎭�
+ * @param 璁㈠崟鐘舵�佷俊鎭�
* @return 璁㈠崟鐘舵�侀泦鍚�
*/
public List<AOrderStatus> selectAOrderStatusList();
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/CustomerEvaluationMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/CustomerEvaluationMapper.java
new file mode 100644
index 0000000..6065223
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/CustomerEvaluationMapper.java
@@ -0,0 +1,84 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.CustomerEvaluation;
+
+/**
+ * 瀹㈡埛璇勪环Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public interface CustomerEvaluationMapper {
+ /**
+ * 鏌ヨ瀹㈡埛璇勪环
+ *
+ * @param evaluationId 瀹㈡埛璇勪环涓婚敭
+ * @return 瀹㈡埛璇勪环
+ */
+ public CustomerEvaluation selectCustomerEvaluationByEvaluationId(Long evaluationId);
+
+ /**
+ * 鏌ヨ瀹㈡埛璇勪环鍒楄〃
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 瀹㈡埛璇勪环闆嗗悎
+ */
+ public List<CustomerEvaluation> selectCustomerEvaluationList(CustomerEvaluation customerEvaluation);
+
+ /**
+ * 鏍规嵁杞︾墝鍙锋煡璇㈠鎴疯瘎浠�
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 瀹㈡埛璇勪环闆嗗悎
+ */
+ public List<CustomerEvaluation> selectCustomerEvaluationByVehicleNo(String vehicleNo);
+
+ /**
+ * 鏍规嵁寰俊OpenID鏌ヨ瀹㈡埛璇勪环
+ *
+ * @param wechatOpenid 寰俊OpenID
+ * @return 瀹㈡埛璇勪环闆嗗悎
+ */
+ public List<CustomerEvaluation> selectCustomerEvaluationByWechatOpenid(String wechatOpenid);
+
+ /**
+ * 鏂板瀹㈡埛璇勪环
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 缁撴灉
+ */
+ public int insertCustomerEvaluation(CustomerEvaluation customerEvaluation);
+
+ /**
+ * 淇敼瀹㈡埛璇勪环
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 缁撴灉
+ */
+ public int updateCustomerEvaluation(CustomerEvaluation customerEvaluation);
+
+ /**
+ * 鍒犻櫎瀹㈡埛璇勪环
+ *
+ * @param evaluationId 瀹㈡埛璇勪环涓婚敭
+ * @return 缁撴灉
+ */
+ public int deleteCustomerEvaluationByEvaluationId(Long evaluationId);
+
+ /**
+ * 鎵归噺鍒犻櫎瀹㈡埛璇勪环
+ *
+ * @param evaluationIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+ * @return 缁撴灉
+ */
+ public int deleteCustomerEvaluationByEvaluationIds(Long[] evaluationIds);
+
+ /**
+ * 缁熻璇勪环鏁伴噺
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 璇勪环缁熻淇℃伅
+ */
+ public List<CustomerEvaluation> selectEvaluationStatistics(CustomerEvaluation customerEvaluation);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EvaluationDetailMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EvaluationDetailMapper.java
new file mode 100644
index 0000000..98bfbc7
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EvaluationDetailMapper.java
@@ -0,0 +1,84 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.EvaluationDetail;
+
+/**
+ * 璇勪环璇︽儏Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public interface EvaluationDetailMapper {
+ /**
+ * 鏌ヨ璇勪环璇︽儏
+ *
+ * @param detailId 璇勪环璇︽儏涓婚敭
+ * @return 璇勪环璇︽儏
+ */
+ public EvaluationDetail selectEvaluationDetailByDetailId(Long detailId);
+
+ /**
+ * 鏌ヨ璇勪环璇︽儏鍒楄〃
+ *
+ * @param evaluationDetail 璇勪环璇︽儏
+ * @return 璇勪环璇︽儏闆嗗悎
+ */
+ public List<EvaluationDetail> selectEvaluationDetailList(EvaluationDetail evaluationDetail);
+
+ /**
+ * 鏍规嵁璇勪环ID鏌ヨ璇勪环璇︽儏鍒楄〃
+ *
+ * @param evaluationId 璇勪环ID
+ * @return 璇勪环璇︽儏闆嗗悎
+ */
+ public List<EvaluationDetail> selectEvaluationDetailByEvaluationId(Long evaluationId);
+
+ /**
+ * 鏂板璇勪环璇︽儏
+ *
+ * @param evaluationDetail 璇勪环璇︽儏
+ * @return 缁撴灉
+ */
+ public int insertEvaluationDetail(EvaluationDetail evaluationDetail);
+
+ /**
+ * 鎵归噺鏂板璇勪环璇︽儏
+ *
+ * @param evaluationDetails 璇勪环璇︽儏鍒楄〃
+ * @return 缁撴灉
+ */
+ public int insertEvaluationDetailBatch(List<EvaluationDetail> evaluationDetails);
+
+ /**
+ * 淇敼璇勪环璇︽儏
+ *
+ * @param evaluationDetail 璇勪环璇︽儏
+ * @return 缁撴灉
+ */
+ public int updateEvaluationDetail(EvaluationDetail evaluationDetail);
+
+ /**
+ * 鍒犻櫎璇勪环璇︽儏
+ *
+ * @param detailId 璇勪环璇︽儏涓婚敭
+ * @return 缁撴灉
+ */
+ public int deleteEvaluationDetailByDetailId(Long detailId);
+
+ /**
+ * 鏍规嵁璇勪环ID鍒犻櫎璇勪环璇︽儏
+ *
+ * @param evaluationId 璇勪环ID
+ * @return 缁撴灉
+ */
+ public int deleteEvaluationDetailByEvaluationId(Long evaluationId);
+
+ /**
+ * 鎵归噺鍒犻櫎璇勪环璇︽儏
+ *
+ * @param detailIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+ * @return 缁撴灉
+ */
+ public int deleteEvaluationDetailByDetailIds(Long[] detailIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EvaluationDimensionMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EvaluationDimensionMapper.java
new file mode 100644
index 0000000..433b60f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EvaluationDimensionMapper.java
@@ -0,0 +1,67 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.EvaluationDimension;
+
+/**
+ * 璇勪环缁村害閰嶇疆Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public interface EvaluationDimensionMapper {
+ /**
+ * 鏌ヨ璇勪环缁村害閰嶇疆
+ *
+ * @param dimensionId 璇勪环缁村害閰嶇疆涓婚敭
+ * @return 璇勪环缁村害閰嶇疆
+ */
+ public EvaluationDimension selectEvaluationDimensionByDimensionId(Long dimensionId);
+
+ /**
+ * 鏌ヨ璇勪环缁村害閰嶇疆鍒楄〃
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 璇勪环缁村害閰嶇疆闆嗗悎
+ */
+ public List<EvaluationDimension> selectEvaluationDimensionList(EvaluationDimension evaluationDimension);
+
+ /**
+ * 鏌ヨ鍚敤鐨勮瘎浠风淮搴﹂厤缃垪琛�
+ *
+ * @return 璇勪环缁村害閰嶇疆闆嗗悎
+ */
+ public List<EvaluationDimension> selectEnabledEvaluationDimensionList();
+
+ /**
+ * 鏂板璇勪环缁村害閰嶇疆
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 缁撴灉
+ */
+ public int insertEvaluationDimension(EvaluationDimension evaluationDimension);
+
+ /**
+ * 淇敼璇勪环缁村害閰嶇疆
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 缁撴灉
+ */
+ public int updateEvaluationDimension(EvaluationDimension evaluationDimension);
+
+ /**
+ * 鍒犻櫎璇勪环缁村害閰嶇疆
+ *
+ * @param dimensionId 璇勪环缁村害閰嶇疆涓婚敭
+ * @return 缁撴灉
+ */
+ public int deleteEvaluationDimensionByDimensionId(Long dimensionId);
+
+ /**
+ * 鎵归噺鍒犻櫎璇勪环缁村害閰嶇疆
+ *
+ * @param dimensionIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+ * @return 缁撴灉
+ */
+ public int deleteEvaluationDimensionByDimensionIds(Long[] dimensionIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleEvaluationQrcodeMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleEvaluationQrcodeMapper.java
new file mode 100644
index 0000000..5844351
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleEvaluationQrcodeMapper.java
@@ -0,0 +1,76 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.VehicleEvaluationQrcode;
+
+/**
+ * 杞﹁締璇勪环浜岀淮鐮丮apper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public interface VehicleEvaluationQrcodeMapper {
+ /**
+ * 鏌ヨ杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param qrcodeId 杞﹁締璇勪环浜岀淮鐮佷富閿�
+ * @return 杞﹁締璇勪环浜岀淮鐮�
+ */
+ public VehicleEvaluationQrcode selectVehicleEvaluationQrcodeByQrcodeId(Long qrcodeId);
+
+ /**
+ * 鏍规嵁杞︾墝鍙锋煡璇㈣溅杈嗚瘎浠蜂簩缁寸爜
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 杞﹁締璇勪环浜岀淮鐮�
+ */
+ public VehicleEvaluationQrcode selectVehicleEvaluationQrcodeByVehicleNo(String vehicleNo);
+
+ /**
+ * 鏌ヨ杞﹁締璇勪环浜岀淮鐮佸垪琛�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 杞﹁締璇勪环浜岀淮鐮侀泦鍚�
+ */
+ public List<VehicleEvaluationQrcode> selectVehicleEvaluationQrcodeList(VehicleEvaluationQrcode vehicleEvaluationQrcode);
+
+ /**
+ * 鏂板杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 缁撴灉
+ */
+ public int insertVehicleEvaluationQrcode(VehicleEvaluationQrcode vehicleEvaluationQrcode);
+
+ /**
+ * 淇敼杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 缁撴灉
+ */
+ public int updateVehicleEvaluationQrcode(VehicleEvaluationQrcode vehicleEvaluationQrcode);
+
+ /**
+ * 鍒犻櫎杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param qrcodeId 杞﹁締璇勪环浜岀淮鐮佷富閿�
+ * @return 缁撴灉
+ */
+ public int deleteVehicleEvaluationQrcodeByQrcodeId(Long qrcodeId);
+
+ /**
+ * 鏍规嵁杞︾墝鍙峰垹闄よ溅杈嗚瘎浠蜂簩缁寸爜
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 缁撴灉
+ */
+ public int deleteVehicleEvaluationQrcodeByVehicleNo(String vehicleNo);
+
+ /**
+ * 鎵归噺鍒犻櫎杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param qrcodeIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+ * @return 缁撴灉
+ */
+ public int deleteVehicleEvaluationQrcodeByQrcodeIds(Long[] qrcodeIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
index f688808..594f0eb 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
@@ -24,6 +24,14 @@
public VehicleInfo selectVehicleInfoByPlateNumber(String plateNumber);
/**
+ * 閫氳繃杞︾墝鍙锋煡璇㈣溅杈嗕俊鎭�
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 杞﹁締淇℃伅
+ */
+ public VehicleInfo selectVehicleInfoByVehicleNo(String vehicleNo);
+
+ /**
* 鏌ヨ杞﹁締淇℃伅鍒楄〃
*
* @param vehicleInfo 杞﹁締淇℃伅
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ICustomerEvaluationService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ICustomerEvaluationService.java
new file mode 100644
index 0000000..f31059e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ICustomerEvaluationService.java
@@ -0,0 +1,92 @@
+package com.ruoyi.system.service;
+
+import java.util.List;
+import com.ruoyi.system.domain.CustomerEvaluation;
+
+/**
+ * 瀹㈡埛璇勪环Service鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public interface ICustomerEvaluationService {
+ /**
+ * 鏌ヨ瀹㈡埛璇勪环
+ *
+ * @param evaluationId 瀹㈡埛璇勪环涓婚敭
+ * @return 瀹㈡埛璇勪环
+ */
+ public CustomerEvaluation selectCustomerEvaluationByEvaluationId(Long evaluationId);
+
+ /**
+ * 鏌ヨ瀹㈡埛璇勪环鍒楄〃
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 瀹㈡埛璇勪环闆嗗悎
+ */
+ public List<CustomerEvaluation> selectCustomerEvaluationList(CustomerEvaluation customerEvaluation);
+
+ /**
+ * 鏍规嵁杞︾墝鍙锋煡璇㈠鎴疯瘎浠�
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 瀹㈡埛璇勪环闆嗗悎
+ */
+ public List<CustomerEvaluation> selectCustomerEvaluationByVehicleNo(String vehicleNo);
+
+ /**
+ * 鏍规嵁寰俊OpenID鏌ヨ瀹㈡埛璇勪环
+ *
+ * @param wechatOpenid 寰俊OpenID
+ * @return 瀹㈡埛璇勪环闆嗗悎
+ */
+ public List<CustomerEvaluation> selectCustomerEvaluationByWechatOpenid(String wechatOpenid);
+
+ /**
+ * 鏂板瀹㈡埛璇勪环
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 缁撴灉
+ */
+ public int insertCustomerEvaluation(CustomerEvaluation customerEvaluation);
+
+ /**
+ * 淇敼瀹㈡埛璇勪环
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 缁撴灉
+ */
+ public int updateCustomerEvaluation(CustomerEvaluation customerEvaluation);
+
+ /**
+ * 鎵归噺鍒犻櫎瀹㈡埛璇勪环
+ *
+ * @param evaluationIds 闇�瑕佸垹闄ょ殑瀹㈡埛璇勪环涓婚敭闆嗗悎
+ * @return 缁撴灉
+ */
+ public int deleteCustomerEvaluationByEvaluationIds(Long[] evaluationIds);
+
+ /**
+ * 鍒犻櫎瀹㈡埛璇勪环淇℃伅
+ *
+ * @param evaluationId 瀹㈡埛璇勪环涓婚敭
+ * @return 缁撴灉
+ */
+ public int deleteCustomerEvaluationByEvaluationId(Long evaluationId);
+
+ /**
+ * 鎻愪氦瀹㈡埛璇勪环
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 缁撴灉
+ */
+ public int submitCustomerEvaluation(CustomerEvaluation customerEvaluation);
+
+ /**
+ * 缁熻璇勪环鏁伴噺
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 璇勪环缁熻淇℃伅
+ */
+ public List<CustomerEvaluation> selectEvaluationStatistics(CustomerEvaluation customerEvaluation);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IEvaluationDimensionService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IEvaluationDimensionService.java
new file mode 100644
index 0000000..2f5375a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IEvaluationDimensionService.java
@@ -0,0 +1,67 @@
+package com.ruoyi.system.service;
+
+import java.util.List;
+import com.ruoyi.system.domain.EvaluationDimension;
+
+/**
+ * 璇勪环缁村害閰嶇疆Service鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public interface IEvaluationDimensionService {
+ /**
+ * 鏌ヨ璇勪环缁村害閰嶇疆
+ *
+ * @param dimensionId 璇勪环缁村害閰嶇疆涓婚敭
+ * @return 璇勪环缁村害閰嶇疆
+ */
+ public EvaluationDimension selectEvaluationDimensionByDimensionId(Long dimensionId);
+
+ /**
+ * 鏌ヨ璇勪环缁村害閰嶇疆鍒楄〃
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 璇勪环缁村害閰嶇疆闆嗗悎
+ */
+ public List<EvaluationDimension> selectEvaluationDimensionList(EvaluationDimension evaluationDimension);
+
+ /**
+ * 鏌ヨ鍚敤鐨勮瘎浠风淮搴﹂厤缃垪琛�
+ *
+ * @return 璇勪环缁村害閰嶇疆闆嗗悎
+ */
+ public List<EvaluationDimension> selectEnabledEvaluationDimensionList();
+
+ /**
+ * 鏂板璇勪环缁村害閰嶇疆
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 缁撴灉
+ */
+ public int insertEvaluationDimension(EvaluationDimension evaluationDimension);
+
+ /**
+ * 淇敼璇勪环缁村害閰嶇疆
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 缁撴灉
+ */
+ public int updateEvaluationDimension(EvaluationDimension evaluationDimension);
+
+ /**
+ * 鎵归噺鍒犻櫎璇勪环缁村害閰嶇疆
+ *
+ * @param dimensionIds 闇�瑕佸垹闄ょ殑璇勪环缁村害閰嶇疆涓婚敭闆嗗悎
+ * @return 缁撴灉
+ */
+ public int deleteEvaluationDimensionByDimensionIds(Long[] dimensionIds);
+
+ /**
+ * 鍒犻櫎璇勪环缁村害閰嶇疆淇℃伅
+ *
+ * @param dimensionId 璇勪环缁村害閰嶇疆涓婚敭
+ * @return 缁撴灉
+ */
+ public int deleteEvaluationDimensionByDimensionId(Long dimensionId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleEvaluationQrcodeService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleEvaluationQrcodeService.java
new file mode 100644
index 0000000..ddaac80
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleEvaluationQrcodeService.java
@@ -0,0 +1,92 @@
+package com.ruoyi.system.service;
+
+import java.util.List;
+import com.ruoyi.system.domain.VehicleEvaluationQrcode;
+
+/**
+ * 杞﹁締璇勪环浜岀淮鐮丼ervice鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+public interface IVehicleEvaluationQrcodeService {
+ /**
+ * 鏌ヨ杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param qrcodeId 杞﹁締璇勪环浜岀淮鐮佷富閿�
+ * @return 杞﹁締璇勪环浜岀淮鐮�
+ */
+ public VehicleEvaluationQrcode selectVehicleEvaluationQrcodeByQrcodeId(Long qrcodeId);
+
+ /**
+ * 鏍规嵁杞︾墝鍙锋煡璇㈣溅杈嗚瘎浠蜂簩缁寸爜
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 杞﹁締璇勪环浜岀淮鐮�
+ */
+ public VehicleEvaluationQrcode selectVehicleEvaluationQrcodeByVehicleNo(String vehicleNo);
+
+ /**
+ * 鏌ヨ杞﹁締璇勪环浜岀淮鐮佸垪琛�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 杞﹁締璇勪环浜岀淮鐮侀泦鍚�
+ */
+ public List<VehicleEvaluationQrcode> selectVehicleEvaluationQrcodeList(VehicleEvaluationQrcode vehicleEvaluationQrcode);
+
+ /**
+ * 鏂板杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 缁撴灉
+ */
+ public int insertVehicleEvaluationQrcode(VehicleEvaluationQrcode vehicleEvaluationQrcode);
+
+ /**
+ * 淇敼杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 缁撴灉
+ */
+ public int updateVehicleEvaluationQrcode(VehicleEvaluationQrcode vehicleEvaluationQrcode);
+
+ /**
+ * 鎵归噺鍒犻櫎杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param qrcodeIds 闇�瑕佸垹闄ょ殑杞﹁締璇勪环浜岀淮鐮佷富閿泦鍚�
+ * @return 缁撴灉
+ */
+ public int deleteVehicleEvaluationQrcodeByQrcodeIds(Long[] qrcodeIds);
+
+ /**
+ * 鍒犻櫎杞﹁締璇勪环浜岀淮鐮佷俊鎭�
+ *
+ * @param qrcodeId 杞﹁締璇勪环浜岀淮鐮佷富閿�
+ * @return 缁撴灉
+ */
+ public int deleteVehicleEvaluationQrcodeByQrcodeId(Long qrcodeId);
+
+ /**
+ * 鐢熸垚杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 浜岀淮鐮佷俊鎭�
+ */
+ public VehicleEvaluationQrcode generateVehicleEvaluationQrcode(String vehicleNo);
+
+ /**
+ * 鐢熸垚杞﹁締璇勪环浜岀淮鐮侊紙甯RL鍙傛暟锛�
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @param qrcodeUrl 浜岀淮鐮乁RL
+ * @return 浜岀淮鐮佷俊鎭�
+ */
+ public VehicleEvaluationQrcode generateVehicleEvaluationQrcode(String vehicleNo, String qrcodeUrl);
+
+ /**
+ * 鎵归噺鐢熸垚杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @return 缁撴灉
+ */
+ public int batchGenerateVehicleEvaluationQrcode();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CustomerEvaluationServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CustomerEvaluationServiceImpl.java
new file mode 100644
index 0000000..3b92055
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CustomerEvaluationServiceImpl.java
@@ -0,0 +1,196 @@
+package com.ruoyi.system.service.impl;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.ruoyi.system.mapper.CustomerEvaluationMapper;
+import com.ruoyi.system.mapper.EvaluationDetailMapper;
+import com.ruoyi.system.domain.CustomerEvaluation;
+import com.ruoyi.system.domain.EvaluationDetail;
+import com.ruoyi.system.service.ICustomerEvaluationService;
+
+/**
+ * 瀹㈡埛璇勪环Service涓氬姟灞傚鐞�
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Service
+public class CustomerEvaluationServiceImpl implements ICustomerEvaluationService {
+ @Autowired
+ private CustomerEvaluationMapper customerEvaluationMapper;
+
+ @Autowired
+ private EvaluationDetailMapper evaluationDetailMapper;
+
+ /**
+ * 鏌ヨ瀹㈡埛璇勪环
+ *
+ * @param evaluationId 瀹㈡埛璇勪环涓婚敭
+ * @return 瀹㈡埛璇勪环
+ */
+ @Override
+ public CustomerEvaluation selectCustomerEvaluationByEvaluationId(Long evaluationId) {
+ CustomerEvaluation evaluation = customerEvaluationMapper.selectCustomerEvaluationByEvaluationId(evaluationId);
+ if (evaluation != null) {
+ // 鏌ヨ璇勪环璇︽儏
+ List<EvaluationDetail> details = evaluationDetailMapper.selectEvaluationDetailByEvaluationId(evaluationId);
+ evaluation.setEvaluationDetails(details);
+ }
+ return evaluation;
+ }
+
+ /**
+ * 鏌ヨ瀹㈡埛璇勪环鍒楄〃
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 瀹㈡埛璇勪环
+ */
+ @Override
+ public List<CustomerEvaluation> selectCustomerEvaluationList(CustomerEvaluation customerEvaluation) {
+ return customerEvaluationMapper.selectCustomerEvaluationList(customerEvaluation);
+ }
+
+ /**
+ * 鏍规嵁杞︾墝鍙锋煡璇㈠鎴疯瘎浠�
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 瀹㈡埛璇勪环闆嗗悎
+ */
+ @Override
+ public List<CustomerEvaluation> selectCustomerEvaluationByVehicleNo(String vehicleNo) {
+ return customerEvaluationMapper.selectCustomerEvaluationByVehicleNo(vehicleNo);
+ }
+
+ /**
+ * 鏍规嵁寰俊OpenID鏌ヨ瀹㈡埛璇勪环
+ *
+ * @param wechatOpenid 寰俊OpenID
+ * @return 瀹㈡埛璇勪环闆嗗悎
+ */
+ @Override
+ public List<CustomerEvaluation> selectCustomerEvaluationByWechatOpenid(String wechatOpenid) {
+ return customerEvaluationMapper.selectCustomerEvaluationByWechatOpenid(wechatOpenid);
+ }
+
+ /**
+ * 鏂板瀹㈡埛璇勪环
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 缁撴灉
+ */
+ @Override
+ public int insertCustomerEvaluation(CustomerEvaluation customerEvaluation) {
+ customerEvaluation.setCreateTime(DateUtils.getNowDate());
+ return customerEvaluationMapper.insertCustomerEvaluation(customerEvaluation);
+ }
+
+ /**
+ * 淇敼瀹㈡埛璇勪环
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 缁撴灉
+ */
+ @Override
+ public int updateCustomerEvaluation(CustomerEvaluation customerEvaluation) {
+ customerEvaluation.setUpdateTime(DateUtils.getNowDate());
+ return customerEvaluationMapper.updateCustomerEvaluation(customerEvaluation);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎瀹㈡埛璇勪环
+ *
+ * @param evaluationIds 闇�瑕佸垹闄ょ殑瀹㈡埛璇勪环涓婚敭
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteCustomerEvaluationByEvaluationIds(Long[] evaluationIds) {
+ return customerEvaluationMapper.deleteCustomerEvaluationByEvaluationIds(evaluationIds);
+ }
+
+ /**
+ * 鍒犻櫎瀹㈡埛璇勪环淇℃伅
+ *
+ * @param evaluationId 瀹㈡埛璇勪环涓婚敭
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteCustomerEvaluationByEvaluationId(Long evaluationId) {
+ return customerEvaluationMapper.deleteCustomerEvaluationByEvaluationId(evaluationId);
+ }
+
+ /**
+ * 鎻愪氦瀹㈡埛璇勪环
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional
+ public int submitCustomerEvaluation(CustomerEvaluation customerEvaluation) {
+ // 璁$畻鎬昏瘎鍒�
+ BigDecimal totalScore = calculateTotalScore(customerEvaluation.getEvaluationDetails());
+ customerEvaluation.setTotalScore(totalScore);
+ customerEvaluation.setEvaluationStatus("1");
+ customerEvaluation.setEvaluationTime(DateUtils.getNowDate());
+ customerEvaluation.setCreateTime(DateUtils.getNowDate());
+
+ // 鎻掑叆瀹㈡埛璇勪环
+ int result = customerEvaluationMapper.insertCustomerEvaluation(customerEvaluation);
+
+ if (result > 0 && customerEvaluation.getEvaluationDetails() != null && !customerEvaluation.getEvaluationDetails().isEmpty()) {
+ // 鎻掑叆璇勪环璇︽儏
+ for (EvaluationDetail detail : customerEvaluation.getEvaluationDetails()) {
+ detail.setEvaluationId(customerEvaluation.getEvaluationId());
+ detail.setCreateTime(DateUtils.getNowDate());
+ evaluationDetailMapper.insertEvaluationDetail(detail);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * 缁熻璇勪环鏁伴噺
+ *
+ * @param customerEvaluation 瀹㈡埛璇勪环
+ * @return 璇勪环缁熻淇℃伅
+ */
+ @Override
+ public List<CustomerEvaluation> selectEvaluationStatistics(CustomerEvaluation customerEvaluation) {
+ return customerEvaluationMapper.selectEvaluationStatistics(customerEvaluation);
+ }
+
+ /**
+ * 璁$畻鎬昏瘎鍒�
+ *
+ * @param details 璇勪环璇︽儏鍒楄〃
+ * @return 鎬昏瘎鍒�
+ */
+ private BigDecimal calculateTotalScore(List<EvaluationDetail> details) {
+ if (details == null || details.isEmpty()) {
+ return BigDecimal.ZERO;
+ }
+
+ int totalScore = 0;
+ int count = 0;
+
+ for (EvaluationDetail detail : details) {
+ if (detail.getScore() != null && detail.getScore() > 0) {
+ totalScore += detail.getScore();
+ count++;
+ }
+ }
+
+ if (count == 0) {
+ return BigDecimal.ZERO;
+ }
+
+ return new BigDecimal(totalScore).divide(new BigDecimal(count), 1, BigDecimal.ROUND_HALF_UP);
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EvaluationDimensionServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EvaluationDimensionServiceImpl.java
new file mode 100644
index 0000000..33ef196
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EvaluationDimensionServiceImpl.java
@@ -0,0 +1,99 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.system.mapper.EvaluationDimensionMapper;
+import com.ruoyi.system.domain.EvaluationDimension;
+import com.ruoyi.system.service.IEvaluationDimensionService;
+
+/**
+ * 璇勪环缁村害閰嶇疆Service涓氬姟灞傚鐞�
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Service
+public class EvaluationDimensionServiceImpl implements IEvaluationDimensionService {
+ @Autowired
+ private EvaluationDimensionMapper evaluationDimensionMapper;
+
+ /**
+ * 鏌ヨ璇勪环缁村害閰嶇疆
+ *
+ * @param dimensionId 璇勪环缁村害閰嶇疆涓婚敭
+ * @return 璇勪环缁村害閰嶇疆
+ */
+ @Override
+ public EvaluationDimension selectEvaluationDimensionByDimensionId(Long dimensionId) {
+ return evaluationDimensionMapper.selectEvaluationDimensionByDimensionId(dimensionId);
+ }
+
+ /**
+ * 鏌ヨ璇勪环缁村害閰嶇疆鍒楄〃
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 璇勪环缁村害閰嶇疆
+ */
+ @Override
+ public List<EvaluationDimension> selectEvaluationDimensionList(EvaluationDimension evaluationDimension) {
+ return evaluationDimensionMapper.selectEvaluationDimensionList(evaluationDimension);
+ }
+
+ /**
+ * 鏌ヨ鍚敤鐨勮瘎浠风淮搴﹂厤缃垪琛�
+ *
+ * @return 璇勪环缁村害閰嶇疆闆嗗悎
+ */
+ @Override
+ public List<EvaluationDimension> selectEnabledEvaluationDimensionList() {
+ return evaluationDimensionMapper.selectEnabledEvaluationDimensionList();
+ }
+
+ /**
+ * 鏂板璇勪环缁村害閰嶇疆
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 缁撴灉
+ */
+ @Override
+ public int insertEvaluationDimension(EvaluationDimension evaluationDimension) {
+ evaluationDimension.setCreateTime(DateUtils.getNowDate());
+ return evaluationDimensionMapper.insertEvaluationDimension(evaluationDimension);
+ }
+
+ /**
+ * 淇敼璇勪环缁村害閰嶇疆
+ *
+ * @param evaluationDimension 璇勪环缁村害閰嶇疆
+ * @return 缁撴灉
+ */
+ @Override
+ public int updateEvaluationDimension(EvaluationDimension evaluationDimension) {
+ evaluationDimension.setUpdateTime(DateUtils.getNowDate());
+ return evaluationDimensionMapper.updateEvaluationDimension(evaluationDimension);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎璇勪环缁村害閰嶇疆
+ *
+ * @param dimensionIds 闇�瑕佸垹闄ょ殑璇勪环缁村害閰嶇疆涓婚敭
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteEvaluationDimensionByDimensionIds(Long[] dimensionIds) {
+ return evaluationDimensionMapper.deleteEvaluationDimensionByDimensionIds(dimensionIds);
+ }
+
+ /**
+ * 鍒犻櫎璇勪环缁村害閰嶇疆淇℃伅
+ *
+ * @param dimensionId 璇勪环缁村害閰嶇疆涓婚敭
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteEvaluationDimensionByDimensionId(Long dimensionId) {
+ return evaluationDimensionMapper.deleteEvaluationDimensionByDimensionId(dimensionId);
+ }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleEvaluationQrcodeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleEvaluationQrcodeServiceImpl.java
new file mode 100644
index 0000000..a36f68f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleEvaluationQrcodeServiceImpl.java
@@ -0,0 +1,252 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.Date;
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.QRCodeUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.mapper.VehicleInfoMapper;
+import com.ruoyi.system.domain.VehicleInfo;
+import com.ruoyi.system.mapper.VehicleEvaluationQrcodeMapper;
+import com.ruoyi.system.domain.VehicleEvaluationQrcode;
+import com.ruoyi.system.service.IVehicleEvaluationQrcodeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+/**
+ * 杞﹁締璇勪环浜岀淮鐮丼ervice涓氬姟灞傚鐞�
+ *
+ * @author ruoyi
+ * @date 2025-01-27
+ */
+@Service
+public class VehicleEvaluationQrcodeServiceImpl implements IVehicleEvaluationQrcodeService {
+ @Autowired
+ private VehicleEvaluationQrcodeMapper vehicleEvaluationQrcodeMapper;
+
+ @Autowired
+ private VehicleInfoMapper vehicleInfoMapper;
+
+ @Value("${ruoyi.profile}")
+ private String uploadPath;
+
+ @Value("${server.port}")
+ private String serverPort;
+
+ /**
+ * 鏌ヨ杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param qrcodeId 杞﹁締璇勪环浜岀淮鐮佷富閿�
+ * @return 杞﹁締璇勪环浜岀淮鐮�
+ */
+ @Override
+ public VehicleEvaluationQrcode selectVehicleEvaluationQrcodeByQrcodeId(Long qrcodeId) {
+ return vehicleEvaluationQrcodeMapper.selectVehicleEvaluationQrcodeByQrcodeId(qrcodeId);
+ }
+
+ /**
+ * 鏍规嵁杞︾墝鍙锋煡璇㈣溅杈嗚瘎浠蜂簩缁寸爜
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 杞﹁締璇勪环浜岀淮鐮�
+ */
+ @Override
+ public VehicleEvaluationQrcode selectVehicleEvaluationQrcodeByVehicleNo(String vehicleNo) {
+ return vehicleEvaluationQrcodeMapper.selectVehicleEvaluationQrcodeByVehicleNo(vehicleNo);
+ }
+
+ /**
+ * 鏌ヨ杞﹁締璇勪环浜岀淮鐮佸垪琛�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 杞﹁締璇勪环浜岀淮鐮�
+ */
+ @Override
+ public List<VehicleEvaluationQrcode> selectVehicleEvaluationQrcodeList(VehicleEvaluationQrcode vehicleEvaluationQrcode) {
+ return vehicleEvaluationQrcodeMapper.selectVehicleEvaluationQrcodeList(vehicleEvaluationQrcode);
+ }
+
+ /**
+ * 鏂板杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 缁撴灉
+ */
+ @Override
+ public int insertVehicleEvaluationQrcode(VehicleEvaluationQrcode vehicleEvaluationQrcode) {
+ vehicleEvaluationQrcode.setCreateTime(DateUtils.getNowDate());
+ return vehicleEvaluationQrcodeMapper.insertVehicleEvaluationQrcode(vehicleEvaluationQrcode);
+ }
+
+ /**
+ * 淇敼杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param vehicleEvaluationQrcode 杞﹁締璇勪环浜岀淮鐮�
+ * @return 缁撴灉
+ */
+ @Override
+ public int updateVehicleEvaluationQrcode(VehicleEvaluationQrcode vehicleEvaluationQrcode) {
+ vehicleEvaluationQrcode.setUpdateTime(DateUtils.getNowDate());
+ return vehicleEvaluationQrcodeMapper.updateVehicleEvaluationQrcode(vehicleEvaluationQrcode);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param qrcodeIds 闇�瑕佸垹闄ょ殑杞﹁締璇勪环浜岀淮鐮佷富閿�
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteVehicleEvaluationQrcodeByQrcodeIds(Long[] qrcodeIds) {
+ return vehicleEvaluationQrcodeMapper.deleteVehicleEvaluationQrcodeByQrcodeIds(qrcodeIds);
+ }
+
+ /**
+ * 鍒犻櫎杞﹁締璇勪环浜岀淮鐮佷俊鎭�
+ *
+ * @param qrcodeId 杞﹁締璇勪环浜岀淮鐮佷富閿�
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteVehicleEvaluationQrcodeByQrcodeId(Long qrcodeId) {
+ return vehicleEvaluationQrcodeMapper.deleteVehicleEvaluationQrcodeByQrcodeId(qrcodeId);
+ }
+
+ /**
+ * 鐢熸垚杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @return 浜岀淮鐮佷俊鎭�
+ */
+ @Override
+ public VehicleEvaluationQrcode generateVehicleEvaluationQrcode(String vehicleNo) {
+ if (StringUtils.isEmpty(vehicleNo)) {
+ return null;
+ }
+
+ // 妫�鏌ヨ溅杈嗘槸鍚﹀瓨鍦�
+ VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoByVehicleNo(vehicleNo);
+ if (vehicleInfo == null) {
+ return null;
+ }
+
+ // 妫�鏌ユ槸鍚﹀凡瀛樺湪浜岀淮鐮�
+ VehicleEvaluationQrcode existingQrcode = vehicleEvaluationQrcodeMapper.selectVehicleEvaluationQrcodeByVehicleNo(vehicleNo);
+ if (existingQrcode != null) {
+ return existingQrcode;
+ }
+
+ // 鐢熸垚浜岀淮鐮佸唴瀹�
+ String qrcodeContent = "EVAL:" + vehicleNo;
+ String qrcodeUrl = "http://localhost:" + serverPort + "/evaluation?vehicle=" + vehicleNo;
+
+ // 鐢熸垚浜岀淮鐮佸浘鐗囦负base64鏍煎紡
+ String qrcodeImageBase64 = QRCodeUtils.generateQRCodeToBase64(qrcodeUrl);
+
+ 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;
+ }
+
+ /**
+ * 鐢熸垚杞﹁締璇勪环浜岀淮鐮侊紙甯RL鍙傛暟锛�
+ *
+ * @param vehicleNo 杞︾墝鍙�
+ * @param qrcodeUrl 浜岀淮鐮乁RL
+ * @return 浜岀淮鐮佷俊鎭�
+ */
+ @Override
+ public VehicleEvaluationQrcode generateVehicleEvaluationQrcode(String vehicleNo, String qrcodeUrl) {
+ if (StringUtils.isEmpty(vehicleNo) || StringUtils.isEmpty(qrcodeUrl)) {
+ return null;
+ }
+
+ // 妫�鏌ヨ溅杈嗘槸鍚﹀瓨鍦�
+ VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoByVehicleNo(vehicleNo);
+ if (vehicleInfo == null) {
+ return null;
+ }
+
+ // 妫�鏌ユ槸鍚﹀凡瀛樺湪浜岀淮鐮�
+ VehicleEvaluationQrcode existingQrcode = vehicleEvaluationQrcodeMapper.selectVehicleEvaluationQrcodeByVehicleNo(vehicleNo);
+ if (existingQrcode != null) {
+ // 濡傛灉宸插瓨鍦紝鏇存柊URL鍜岄噸鏂扮敓鎴愪簩缁寸爜
+ existingQrcode.setQrcodeUrl(qrcodeUrl);
+ existingQrcode.setQrcodeContent("EVAL:" + vehicleNo);
+ existingQrcode.setUpdateBy("system");
+ existingQrcode.setUpdateTime(DateUtils.getNowDate());
+
+ // 閲嶆柊鐢熸垚浜岀淮鐮佸浘鐗囦负base64鏍煎紡
+ String qrcodeImageBase64 = QRCodeUtils.generateQRCodeToBase64(qrcodeUrl);
+
+ if (qrcodeImageBase64 != null) {
+ existingQrcode.setQrcodeImage(qrcodeImageBase64);
+ vehicleEvaluationQrcodeMapper.updateVehicleEvaluationQrcode(existingQrcode);
+ return existingQrcode;
+ }
+ return null;
+ }
+
+ // 鐢熸垚浜岀淮鐮佸唴瀹�
+ String qrcodeContent = "EVAL:" + vehicleNo;
+
+ // 鐢熸垚浜岀淮鐮佸浘鐗囦负base64鏍煎紡
+ String qrcodeImageBase64 = QRCodeUtils.generateQRCodeToBase64(qrcodeUrl);
+
+ 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;
+ }
+
+ /**
+ * 鎵归噺鐢熸垚杞﹁締璇勪环浜岀淮鐮�
+ *
+ * @return 缁撴灉
+ */
+ @Override
+ public int batchGenerateVehicleEvaluationQrcode() {
+ // 鏌ヨ鎵�鏈夋甯哥姸鎬佺殑杞﹁締
+ VehicleInfo vehicleInfo = new VehicleInfo();
+ vehicleInfo.setStatus("0");
+ List<VehicleInfo> vehicleList = vehicleInfoMapper.selectVehicleInfoList(vehicleInfo);
+
+ int successCount = 0;
+ for (VehicleInfo vehicle : vehicleList) {
+ VehicleEvaluationQrcode qrcode = generateVehicleEvaluationQrcode(vehicle.getVehicleNo());
+ if (qrcode != null) {
+ successCount++;
+ }
+ }
+
+ return successCount;
+ }
+}
diff --git a/ruoyi-system/src/main/resources/mapper/system/CustomerEvaluationMapper.xml b/ruoyi-system/src/main/resources/mapper/system/CustomerEvaluationMapper.xml
new file mode 100644
index 0000000..3870019
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/CustomerEvaluationMapper.xml
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.CustomerEvaluationMapper">
+
+ <resultMap type="CustomerEvaluation" id="CustomerEvaluationResult">
+ <result property="evaluationId" column="evaluation_id" />
+ <result property="vehicleNo" column="vehicle_no" />
+ <result property="customerName" column="customer_name" />
+ <result property="customerPhone" column="customer_phone" />
+ <result property="wechatOpenid" column="wechat_openid" />
+ <result property="wechatNickname" column="wechat_nickname" />
+ <result property="wechatAvatar" column="wechat_avatar" />
+ <result property="wechatPhone" column="wechat_phone" />
+ <result property="totalScore" column="total_score" />
+ <result property="evaluationStatus" column="evaluation_status" />
+ <result property="evaluationTime" column="evaluation_time" />
+ <result property="ipAddress" column="ip_address" />
+ <result property="userAgent" column="user_agent" />
+ <result property="createTime" column="create_time" />
+ <result property="updateTime" column="update_time" />
+ <result property="remark" column="remark" />
+ </resultMap>
+
+ <sql id="selectCustomerEvaluationVo">
+ select evaluation_id, vehicle_no, customer_name, customer_phone, wechat_openid, wechat_nickname, wechat_avatar, wechat_phone, total_score, evaluation_status, evaluation_time, ip_address, user_agent, create_time, update_time, remark from customer_evaluation
+ </sql>
+
+ <select id="selectCustomerEvaluationList" parameterType="CustomerEvaluation" resultMap="CustomerEvaluationResult">
+ <include refid="selectCustomerEvaluationVo"/>
+ <where>
+ <if test="vehicleNo != null and vehicleNo != ''"> and vehicle_no like concat('%', #{vehicleNo}, '%')</if>
+ <if test="customerName != null and customerName != ''"> and customer_name like concat('%', #{customerName}, '%')</if>
+ <if test="customerPhone != null and customerPhone != ''"> and customer_phone = #{customerPhone}</if>
+ <if test="wechatOpenid != null and wechatOpenid != ''"> and wechat_openid = #{wechatOpenid}</if>
+ <if test="wechatNickname != null and wechatNickname != ''"> and wechat_nickname like concat('%', #{wechatNickname}, '%')</if>
+ <if test="totalScore != null "> and total_score = #{totalScore}</if>
+ <if test="evaluationStatus != null and evaluationStatus != ''"> and evaluation_status = #{evaluationStatus}</if>
+ <if test="evaluationTime != null "> and evaluation_time = #{evaluationTime}</if>
+ <if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+ and date_format(evaluation_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
+ </if>
+ <if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+ and date_format(evaluation_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
+ </if>
+ </where>
+ order by evaluation_time desc, create_time desc
+ </select>
+
+ <select id="selectCustomerEvaluationByEvaluationId" parameterType="Long" resultMap="CustomerEvaluationResult">
+ <include refid="selectCustomerEvaluationVo"/>
+ where evaluation_id = #{evaluationId}
+ </select>
+
+ <select id="selectCustomerEvaluationByVehicleNo" parameterType="String" resultMap="CustomerEvaluationResult">
+ <include refid="selectCustomerEvaluationVo"/>
+ where vehicle_no = #{vehicleNo}
+ order by evaluation_time desc, create_time desc
+ </select>
+
+ <select id="selectCustomerEvaluationByWechatOpenid" parameterType="String" resultMap="CustomerEvaluationResult">
+ <include refid="selectCustomerEvaluationVo"/>
+ where wechat_openid = #{wechatOpenid}
+ order by evaluation_time desc, create_time desc
+ </select>
+
+ <select id="selectEvaluationStatistics" parameterType="CustomerEvaluation" resultMap="CustomerEvaluationResult">
+ select
+ vehicle_no,
+ count(*) as total_count,
+ avg(total_score) as avg_score,
+ sum(case when total_score >= 4.0 then 1 else 0 end) as good_count,
+ sum(case when total_score < 3.0 then 1 else 0 end) as bad_count
+ from customer_evaluation
+ <where>
+ evaluation_status = '1'
+ <if test="vehicleNo != null and vehicleNo != ''"> and vehicle_no = #{vehicleNo}</if>
+ <if test="params.beginTime != null and params.beginTime != ''">
+ and date_format(evaluation_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
+ </if>
+ <if test="params.endTime != null and params.endTime != ''">
+ and date_format(evaluation_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
+ </if>
+ </where>
+ group by vehicle_no
+ order by avg_score desc
+ </select>
+
+ <insert id="insertCustomerEvaluation" parameterType="CustomerEvaluation" useGeneratedKeys="true" keyProperty="evaluationId">
+ insert into customer_evaluation
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="vehicleNo != null and vehicleNo != ''">vehicle_no,</if>
+ <if test="customerName != null and customerName != ''">customer_name,</if>
+ <if test="customerPhone != null and customerPhone != ''">customer_phone,</if>
+ <if test="wechatOpenid != null">wechat_openid,</if>
+ <if test="wechatNickname != null">wechat_nickname,</if>
+ <if test="wechatAvatar != null">wechat_avatar,</if>
+ <if test="wechatPhone != null">wechat_phone,</if>
+ <if test="totalScore != null">total_score,</if>
+ <if test="evaluationStatus != null">evaluation_status,</if>
+ <if test="evaluationTime != null">evaluation_time,</if>
+ <if test="ipAddress != null">ip_address,</if>
+ <if test="userAgent != null">user_agent,</if>
+ <if test="createTime != null">create_time,</if>
+ <if test="updateTime != null">update_time,</if>
+ <if test="remark != null">remark,</if>
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <if test="vehicleNo != null and vehicleNo != ''">#{vehicleNo},</if>
+ <if test="customerName != null and customerName != ''">#{customerName},</if>
+ <if test="customerPhone != null and customerPhone != ''">#{customerPhone},</if>
+ <if test="wechatOpenid != null">#{wechatOpenid},</if>
+ <if test="wechatNickname != null">#{wechatNickname},</if>
+ <if test="wechatAvatar != null">#{wechatAvatar},</if>
+ <if test="wechatPhone != null">#{wechatPhone},</if>
+ <if test="totalScore != null">#{totalScore},</if>
+ <if test="evaluationStatus != null">#{evaluationStatus},</if>
+ <if test="evaluationTime != null">#{evaluationTime},</if>
+ <if test="ipAddress != null">#{ipAddress},</if>
+ <if test="userAgent != null">#{userAgent},</if>
+ <if test="createTime != null">#{createTime},</if>
+ <if test="updateTime != null">#{updateTime},</if>
+ <if test="remark != null">#{remark},</if>
+ </trim>
+ </insert>
+
+ <update id="updateCustomerEvaluation" parameterType="CustomerEvaluation">
+ update customer_evaluation
+ <trim prefix="SET" suffixOverrides=",">
+ <if test="vehicleNo != null and vehicleNo != ''">vehicle_no = #{vehicleNo},</if>
+ <if test="customerName != null and customerName != ''">customer_name = #{customerName},</if>
+ <if test="customerPhone != null and customerPhone != ''">customer_phone = #{customerPhone},</if>
+ <if test="wechatOpenid != null">wechat_openid = #{wechatOpenid},</if>
+ <if test="wechatNickname != null">wechat_nickname = #{wechatNickname},</if>
+ <if test="wechatAvatar != null">wechat_avatar = #{wechatAvatar},</if>
+ <if test="wechatPhone != null">wechat_phone = #{wechatPhone},</if>
+ <if test="totalScore != null">total_score = #{totalScore},</if>
+ <if test="evaluationStatus != null">evaluation_status = #{evaluationStatus},</if>
+ <if test="evaluationTime != null">evaluation_time = #{evaluationTime},</if>
+ <if test="ipAddress != null">ip_address = #{ipAddress},</if>
+ <if test="userAgent != null">user_agent = #{userAgent},</if>
+ <if test="updateTime != null">update_time = #{updateTime},</if>
+ <if test="remark != null">remark = #{remark},</if>
+ </trim>
+ where evaluation_id = #{evaluationId}
+ </update>
+
+ <delete id="deleteCustomerEvaluationByEvaluationId" parameterType="Long">
+ delete from customer_evaluation where evaluation_id = #{evaluationId}
+ </delete>
+
+ <delete id="deleteCustomerEvaluationByEvaluationIds" parameterType="String">
+ delete from customer_evaluation where evaluation_id in
+ <foreach item="evaluationId" collection="array" open="(" separator="," close=")">
+ #{evaluationId}
+ </foreach>
+ </delete>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/EvaluationDetailMapper.xml b/ruoyi-system/src/main/resources/mapper/system/EvaluationDetailMapper.xml
new file mode 100644
index 0000000..129d4ab
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/EvaluationDetailMapper.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.EvaluationDetailMapper">
+
+ <resultMap type="EvaluationDetail" id="EvaluationDetailResult">
+ <result property="detailId" column="detail_id" />
+ <result property="evaluationId" column="evaluation_id" />
+ <result property="dimensionId" column="dimension_id" />
+ <result property="score" column="score" />
+ <result property="optionValue" column="option_value" />
+ <result property="textContent" column="text_content" />
+ <result property="createTime" column="create_time" />
+ </resultMap>
+
+ <resultMap type="EvaluationDetail" id="EvaluationDetailWithDimensionResult" extends="EvaluationDetailResult">
+ <association property="dimension" javaType="EvaluationDimension">
+ <result property="dimensionId" column="dimension_id" />
+ <result property="dimensionName" column="dimension_name" />
+ <result property="dimensionDesc" column="dimension_desc" />
+ <result property="dimensionType" column="dimension_type" />
+ <result property="options" column="options" />
+ <result property="sortOrder" column="sort_order" />
+ <result property="isRequired" column="is_required" />
+ </association>
+ </resultMap>
+
+ <sql id="selectEvaluationDetailVo">
+ select detail_id, evaluation_id, dimension_id, score, option_value, text_content, create_time from evaluation_detail
+ </sql>
+
+ <sql id="selectEvaluationDetailWithDimensionVo">
+ select ed.detail_id, ed.evaluation_id, ed.dimension_id, ed.score, ed.option_value, ed.text_content, ed.create_time,
+ edim.dimension_name, edim.dimension_desc, edim.dimension_type, edim.options, edim.sort_order, edim.is_required
+ from evaluation_detail ed
+ left join evaluation_dimension edim on ed.dimension_id = edim.dimension_id
+ </sql>
+
+ <select id="selectEvaluationDetailList" parameterType="EvaluationDetail" resultMap="EvaluationDetailResult">
+ <include refid="selectEvaluationDetailVo"/>
+ <where>
+ <if test="evaluationId != null "> and evaluation_id = #{evaluationId}</if>
+ <if test="dimensionId != null "> and dimension_id = #{dimensionId}</if>
+ <if test="score != null "> and score = #{score}</if>
+ <if test="optionValue != null and optionValue != ''"> and option_value = #{optionValue}</if>
+ </where>
+ order by create_time desc
+ </select>
+
+ <select id="selectEvaluationDetailByDetailId" parameterType="Long" resultMap="EvaluationDetailResult">
+ <include refid="selectEvaluationDetailVo"/>
+ where detail_id = #{detailId}
+ </select>
+
+ <select id="selectEvaluationDetailByEvaluationId" parameterType="Long" resultMap="EvaluationDetailWithDimensionResult">
+ <include refid="selectEvaluationDetailWithDimensionVo"/>
+ where ed.evaluation_id = #{evaluationId}
+ order by edim.sort_order asc, ed.create_time desc
+ </select>
+
+ <insert id="insertEvaluationDetail" parameterType="EvaluationDetail" useGeneratedKeys="true" keyProperty="detailId">
+ insert into evaluation_detail
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="evaluationId != null">evaluation_id,</if>
+ <if test="dimensionId != null">dimension_id,</if>
+ <if test="score != null">score,</if>
+ <if test="optionValue != null">option_value,</if>
+ <if test="textContent != null">text_content,</if>
+ <if test="createTime != null">create_time,</if>
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <if test="evaluationId != null">#{evaluationId},</if>
+ <if test="dimensionId != null">#{dimensionId},</if>
+ <if test="score != null">#{score},</if>
+ <if test="optionValue != null">#{optionValue},</if>
+ <if test="textContent != null">#{textContent},</if>
+ <if test="createTime != null">#{createTime},</if>
+ </trim>
+ </insert>
+
+ <insert id="insertEvaluationDetailBatch" parameterType="java.util.List">
+ insert into evaluation_detail (evaluation_id, dimension_id, score, option_value, text_content, create_time)
+ values
+ <foreach collection="list" item="item" separator=",">
+ (#{item.evaluationId}, #{item.dimensionId}, #{item.score}, #{item.optionValue}, #{item.textContent}, #{item.createTime})
+ </foreach>
+ </insert>
+
+ <update id="updateEvaluationDetail" parameterType="EvaluationDetail">
+ update evaluation_detail
+ <trim prefix="SET" suffixOverrides=",">
+ <if test="evaluationId != null">evaluation_id = #{evaluationId},</if>
+ <if test="dimensionId != null">dimension_id = #{dimensionId},</if>
+ <if test="score != null">score = #{score},</if>
+ <if test="optionValue != null">option_value = #{optionValue},</if>
+ <if test="textContent != null">text_content = #{textContent},</if>
+ </trim>
+ where detail_id = #{detailId}
+ </update>
+
+ <delete id="deleteEvaluationDetailByDetailId" parameterType="Long">
+ delete from evaluation_detail where detail_id = #{detailId}
+ </delete>
+
+ <delete id="deleteEvaluationDetailByEvaluationId" parameterType="Long">
+ delete from evaluation_detail where evaluation_id = #{evaluationId}
+ </delete>
+
+ <delete id="deleteEvaluationDetailByDetailIds" parameterType="String">
+ delete from evaluation_detail where detail_id in
+ <foreach item="detailId" collection="array" open="(" separator="," close=")">
+ #{detailId}
+ </foreach>
+ </delete>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/EvaluationDimensionMapper.xml b/ruoyi-system/src/main/resources/mapper/system/EvaluationDimensionMapper.xml
new file mode 100644
index 0000000..bfeb7bf
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/EvaluationDimensionMapper.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.EvaluationDimensionMapper">
+
+ <resultMap type="EvaluationDimension" id="EvaluationDimensionResult">
+ <result property="dimensionId" column="dimension_id" />
+ <result property="dimensionName" column="dimension_name" />
+ <result property="dimensionDesc" column="dimension_desc" />
+ <result property="dimensionType" column="dimension_type" />
+ <result property="options" column="options" />
+ <result property="sortOrder" column="sort_order" />
+ <result property="isRequired" column="is_required" />
+ <result property="status" column="status" />
+ <result property="createBy" column="create_by" />
+ <result property="createTime" column="create_time" />
+ <result property="updateBy" column="update_by" />
+ <result property="updateTime" column="update_time" />
+ <result property="remark" column="remark" />
+ </resultMap>
+
+ <sql id="selectEvaluationDimensionVo">
+ select dimension_id, dimension_name, dimension_desc, dimension_type, options, sort_order, is_required, status, create_by, create_time, update_by, update_time, remark from evaluation_dimension
+ </sql>
+
+ <select id="selectEvaluationDimensionList" parameterType="EvaluationDimension" resultMap="EvaluationDimensionResult">
+ <include refid="selectEvaluationDimensionVo"/>
+ <where>
+ <if test="dimensionName != null and dimensionName != ''"> and dimension_name like concat('%', #{dimensionName}, '%')</if>
+ <if test="dimensionDesc != null and dimensionDesc != ''"> and dimension_desc like concat('%', #{dimensionDesc}, '%')</if>
+ <if test="dimensionType != null and dimensionType != ''"> and dimension_type = #{dimensionType}</if>
+ <if test="sortOrder != null "> and sort_order = #{sortOrder}</if>
+ <if test="isRequired != null and isRequired != ''"> and is_required = #{isRequired}</if>
+ <if test="status != null and status != ''"> and status = #{status}</if>
+ </where>
+ order by sort_order asc, create_time desc
+ </select>
+
+ <select id="selectEvaluationDimensionByDimensionId" parameterType="Long" resultMap="EvaluationDimensionResult">
+ <include refid="selectEvaluationDimensionVo"/>
+ where dimension_id = #{dimensionId}
+ </select>
+
+ <select id="selectEnabledEvaluationDimensionList" resultMap="EvaluationDimensionResult">
+ <include refid="selectEvaluationDimensionVo"/>
+ where status = '0'
+ order by sort_order asc, create_time desc
+ </select>
+
+ <insert id="insertEvaluationDimension" parameterType="EvaluationDimension" useGeneratedKeys="true" keyProperty="dimensionId">
+ insert into evaluation_dimension
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="dimensionName != null and dimensionName != ''">dimension_name,</if>
+ <if test="dimensionDesc != null">dimension_desc,</if>
+ <if test="dimensionType != null and dimensionType != ''">dimension_type,</if>
+ <if test="options != null">options,</if>
+ <if test="sortOrder != null">sort_order,</if>
+ <if test="isRequired != null">is_required,</if>
+ <if test="status != null">status,</if>
+ <if test="createBy != null">create_by,</if>
+ <if test="createTime != null">create_time,</if>
+ <if test="updateBy != null">update_by,</if>
+ <if test="updateTime != null">update_time,</if>
+ <if test="remark != null">remark,</if>
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <if test="dimensionName != null and dimensionName != ''">#{dimensionName},</if>
+ <if test="dimensionDesc != null">#{dimensionDesc},</if>
+ <if test="dimensionType != null and dimensionType != ''">#{dimensionType},</if>
+ <if test="options != null">#{options},</if>
+ <if test="sortOrder != null">#{sortOrder},</if>
+ <if test="isRequired != null">#{isRequired},</if>
+ <if test="status != null">#{status},</if>
+ <if test="createBy != null">#{createBy},</if>
+ <if test="createTime != null">#{createTime},</if>
+ <if test="updateBy != null">#{updateBy},</if>
+ <if test="updateTime != null">#{updateTime},</if>
+ <if test="remark != null">#{remark},</if>
+ </trim>
+ </insert>
+
+ <update id="updateEvaluationDimension" parameterType="EvaluationDimension">
+ update evaluation_dimension
+ <trim prefix="SET" suffixOverrides=",">
+ <if test="dimensionName != null and dimensionName != ''">dimension_name = #{dimensionName},</if>
+ <if test="dimensionDesc != null">dimension_desc = #{dimensionDesc},</if>
+ <if test="dimensionType != null and dimensionType != ''">dimension_type = #{dimensionType},</if>
+ <if test="options != null">options = #{options},</if>
+ <if test="sortOrder != null">sort_order = #{sortOrder},</if>
+ <if test="isRequired != null">is_required = #{isRequired},</if>
+ <if test="status != null">status = #{status},</if>
+ <if test="updateBy != null">update_by = #{updateBy},</if>
+ <if test="updateTime != null">update_time = #{updateTime},</if>
+ <if test="remark != null">remark = #{remark},</if>
+ </trim>
+ where dimension_id = #{dimensionId}
+ </update>
+
+ <delete id="deleteEvaluationDimensionByDimensionId" parameterType="Long">
+ delete from evaluation_dimension where dimension_id = #{dimensionId}
+ </delete>
+
+ <delete id="deleteEvaluationDimensionByDimensionIds" parameterType="String">
+ delete from evaluation_dimension where dimension_id in
+ <foreach item="dimensionId" collection="array" open="(" separator="," close=")">
+ #{dimensionId}
+ </foreach>
+ </delete>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/VehicleEvaluationQrcodeMapper.xml b/ruoyi-system/src/main/resources/mapper/system/VehicleEvaluationQrcodeMapper.xml
new file mode 100644
index 0000000..22d7024
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/VehicleEvaluationQrcodeMapper.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.VehicleEvaluationQrcodeMapper">
+
+ <resultMap type="VehicleEvaluationQrcode" id="VehicleEvaluationQrcodeResult">
+ <result property="qrcodeId" column="qrcode_id" />
+ <result property="vehicleNo" column="vehicle_no" />
+ <result property="qrcodeUrl" column="qrcode_url" />
+ <result property="qrcodeContent" column="qrcode_content" />
+ <result property="qrcodeImage" column="qrcode_image" />
+ <result property="status" column="status" />
+ <result property="createBy" column="create_by" />
+ <result property="createTime" column="create_time" />
+ <result property="updateBy" column="update_by" />
+ <result property="updateTime" column="update_time" />
+ <result property="remark" column="remark" />
+ </resultMap>
+
+ <sql id="selectVehicleEvaluationQrcodeVo">
+ select qrcode_id, vehicle_no, qrcode_url, qrcode_content, qrcode_image, status, create_by, create_time, update_by, update_time, remark from vehicle_evaluation_qrcode
+ </sql>
+
+ <select id="selectVehicleEvaluationQrcodeList" parameterType="VehicleEvaluationQrcode" resultMap="VehicleEvaluationQrcodeResult">
+ <include refid="selectVehicleEvaluationQrcodeVo"/>
+ <where>
+ <if test="vehicleNo != null and vehicleNo != ''"> and vehicle_no like concat('%', #{vehicleNo}, '%')</if>
+ <if test="qrcodeUrl != null and qrcodeUrl != ''"> and qrcode_url like concat('%', #{qrcodeUrl}, '%')</if>
+ <if test="qrcodeContent != null and qrcodeContent != ''"> and qrcode_content like concat('%', #{qrcodeContent}, '%')</if>
+ <if test="status != null and status != ''"> and status = #{status}</if>
+ </where>
+ order by create_time desc
+ </select>
+
+ <select id="selectVehicleEvaluationQrcodeByQrcodeId" parameterType="Long" resultMap="VehicleEvaluationQrcodeResult">
+ <include refid="selectVehicleEvaluationQrcodeVo"/>
+ where qrcode_id = #{qrcodeId}
+ </select>
+
+ <select id="selectVehicleEvaluationQrcodeByVehicleNo" parameterType="String" resultMap="VehicleEvaluationQrcodeResult">
+ <include refid="selectVehicleEvaluationQrcodeVo"/>
+ where vehicle_no = #{vehicleNo}
+ </select>
+
+ <insert id="insertVehicleEvaluationQrcode" parameterType="VehicleEvaluationQrcode" useGeneratedKeys="true" keyProperty="qrcodeId">
+ insert into vehicle_evaluation_qrcode
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="vehicleNo != null and vehicleNo != ''">vehicle_no,</if>
+ <if test="qrcodeUrl != null and qrcodeUrl != ''">qrcode_url,</if>
+ <if test="qrcodeContent != null and qrcodeContent != ''">qrcode_content,</if>
+ <if test="qrcodeImage != null">qrcode_image,</if>
+ <if test="status != null">status,</if>
+ <if test="createBy != null">create_by,</if>
+ <if test="createTime != null">create_time,</if>
+ <if test="updateBy != null">update_by,</if>
+ <if test="updateTime != null">update_time,</if>
+ <if test="remark != null">remark,</if>
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <if test="vehicleNo != null and vehicleNo != ''">#{vehicleNo},</if>
+ <if test="qrcodeUrl != null and qrcodeUrl != ''">#{qrcodeUrl},</if>
+ <if test="qrcodeContent != null and qrcodeContent != ''">#{qrcodeContent},</if>
+ <if test="qrcodeImage != null">#{qrcodeImage},</if>
+ <if test="status != null">#{status},</if>
+ <if test="createBy != null">#{createBy},</if>
+ <if test="createTime != null">#{createTime},</if>
+ <if test="updateBy != null">#{updateBy},</if>
+ <if test="updateTime != null">#{updateTime},</if>
+ <if test="remark != null">#{remark},</if>
+ </trim>
+ </insert>
+
+ <update id="updateVehicleEvaluationQrcode" parameterType="VehicleEvaluationQrcode">
+ update vehicle_evaluation_qrcode
+ <trim prefix="SET" suffixOverrides=",">
+ <if test="vehicleNo != null and vehicleNo != ''">vehicle_no = #{vehicleNo},</if>
+ <if test="qrcodeUrl != null and qrcodeUrl != ''">qrcode_url = #{qrcodeUrl},</if>
+ <if test="qrcodeContent != null and qrcodeContent != ''">qrcode_content = #{qrcodeContent},</if>
+ <if test="qrcodeImage != null">qrcode_image = #{qrcodeImage},</if>
+ <if test="status != null">status = #{status},</if>
+ <if test="updateBy != null">update_by = #{updateBy},</if>
+ <if test="updateTime != null">update_time = #{updateTime},</if>
+ <if test="remark != null">remark = #{remark},</if>
+ </trim>
+ where qrcode_id = #{qrcodeId}
+ </update>
+
+ <delete id="deleteVehicleEvaluationQrcodeByQrcodeId" parameterType="Long">
+ delete from vehicle_evaluation_qrcode where qrcode_id = #{qrcodeId}
+ </delete>
+
+ <delete id="deleteVehicleEvaluationQrcodeByVehicleNo" parameterType="String">
+ delete from vehicle_evaluation_qrcode where vehicle_no = #{vehicleNo}
+ </delete>
+
+ <delete id="deleteVehicleEvaluationQrcodeByQrcodeIds" parameterType="String">
+ delete from vehicle_evaluation_qrcode where qrcode_id in
+ <foreach item="qrcodeId" collection="array" open="(" separator="," close=")">
+ #{qrcodeId}
+ </foreach>
+ </delete>
+</mapper>
diff --git a/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml b/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
index aa34be7..45ac040 100644
--- a/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
@@ -13,6 +13,8 @@
<result property="vehicleModel" column="vehicle_model" />
<result property="status" column="status" />
<result property="platformCode" column="platform_code" />
+ <result property="deptId" column="dept_id" />
+ <result property="deptName" column="dept_name" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
@@ -21,31 +23,38 @@
</resultMap>
<sql id="selectVehicleInfoVo">
- select vehicle_id, device_id, vehicle_no, vehicle_type, vehicle_brand, vehicle_model, status, platform_code, create_by, create_time, update_by, update_time, remark
- from tb_vehicle_info
+ select v.vehicle_id, v.device_id, v.vehicle_no, v.vehicle_type, v.vehicle_brand, v.vehicle_model, v.status, v.platform_code, v.dept_id, d.dept_name, v.create_by, v.create_time, v.update_by, v.update_time, v.remark
+ from tb_vehicle_info v
+ left join sys_dept d on v.dept_id = d.dept_id
</sql>
<select id="selectVehicleInfoList" parameterType="VehicleInfo" resultMap="VehicleInfoResult">
<include refid="selectVehicleInfoVo"/>
<where>
- <if test="vehicleNo != null and vehicleNo != ''"> and vehicle_no = #{vehicleNo}</if>
- <if test="deviceId != null and deviceId != ''"> and device_id = #{deviceId}</if>
- <if test="vehicleType != null and vehicleType != ''"> and vehicle_type = #{vehicleType}</if>
- <if test="vehicleBrand != null and vehicleBrand != ''"> and vehicle_brand = #{vehicleBrand}</if>
- <if test="vehicleModel != null and vehicleModel != ''"> and vehicle_model = #{vehicleModel}</if>
- <if test="status != null and status != ''"> and status = #{status}</if>
- <if test="platformCode != null and platformCode != ''"> and platform_code = #{platformCode}</if>
+ <if test="vehicleNo != null and vehicleNo != ''"> and v.vehicle_no = #{vehicleNo}</if>
+ <if test="deviceId != null and deviceId != ''"> and v.device_id = #{deviceId}</if>
+ <if test="vehicleType != null and vehicleType != ''"> and v.vehicle_type = #{vehicleType}</if>
+ <if test="vehicleBrand != null and vehicleBrand != ''"> and v.vehicle_brand = #{vehicleBrand}</if>
+ <if test="vehicleModel != null and vehicleModel != ''"> and v.vehicle_model = #{vehicleModel}</if>
+ <if test="status != null and status != ''"> and v.status = #{status}</if>
+ <if test="platformCode != null and platformCode != ''"> and v.platform_code = #{platformCode}</if>
+ <if test="deptId != null"> and v.dept_id = #{deptId}</if>
</where>
</select>
<select id="selectVehicleInfoById" parameterType="Long" resultMap="VehicleInfoResult">
<include refid="selectVehicleInfoVo"/>
- where vehicle_id = #{vehicleId}
+ where v.vehicle_id = #{vehicleId}
</select>
<select id="selectVehicleInfoByPlateNumber" parameterType="String" resultMap="VehicleInfoResult">
<include refid="selectVehicleInfoVo"/>
- where vehicle_no = #{plateNumber}
+ where v.vehicle_no = #{plateNumber}
+ </select>
+
+ <select id="selectVehicleInfoByVehicleNo" parameterType="String" resultMap="VehicleInfoResult">
+ <include refid="selectVehicleInfoVo"/>
+ where v.vehicle_no = #{vehicleNo}
</select>
<insert id="insertVehicleInfo" parameterType="VehicleInfo" useGeneratedKeys="true" keyProperty="vehicleId">
@@ -58,6 +67,7 @@
<if test="vehicleModel != null">vehicle_model,</if>
<if test="status != null">status,</if>
<if test="platformCode != null">platform_code,</if>
+ <if test="deptId != null">dept_id,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
@@ -72,6 +82,7 @@
<if test="vehicleModel != null">#{vehicleModel},</if>
<if test="status != null">#{status},</if>
<if test="platformCode != null">#{platformCode},</if>
+ <if test="deptId != null">#{deptId},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
@@ -90,6 +101,7 @@
<if test="vehicleModel != null">vehicle_model = #{vehicleModel},</if>
<if test="status != null">status = #{status},</if>
<if test="platformCode != null">platform_code = #{platformCode},</if>
+ <if test="deptId != null">dept_id = #{deptId},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
diff --git a/ruoyi-ui/src/api/evaluation.js b/ruoyi-ui/src/api/evaluation.js
new file mode 100644
index 0000000..d09df5f
--- /dev/null
+++ b/ruoyi-ui/src/api/evaluation.js
@@ -0,0 +1,181 @@
+import request from '@/utils/request'
+
+// 鑾峰彇璇勪环缁村害閰嶇疆
+export function getEvaluationDimensions() {
+ return request({
+ url: '/evaluation/dimensions',
+ method: 'get'
+ })
+}
+
+// 鎻愪氦瀹㈡埛璇勪环
+export function submitEvaluation(data) {
+ return request({
+ url: '/evaluation/submit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 鑾峰彇寰俊鐢ㄦ埛淇℃伅
+export function getWechatUserInfo(code) {
+ return request({
+ url: '/evaluation/wechat/userinfo',
+ method: 'get',
+ params: { code }
+ })
+}
+
+// 鏌ヨ瀹㈡埛璇勪环鍒楄〃
+export function listEvaluation(query) {
+ return request({
+ url: '/evaluation/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 鏌ヨ瀹㈡埛璇勪环璇︾粏
+export function getEvaluation(evaluationId) {
+ return request({
+ url: '/evaluation/' + evaluationId,
+ method: 'get'
+ })
+}
+
+// 鏂板瀹㈡埛璇勪环
+export function addEvaluation(data) {
+ return request({
+ url: '/evaluation',
+ method: 'post',
+ data: data
+ })
+}
+
+// 淇敼瀹㈡埛璇勪环
+export function updateEvaluation(data) {
+ return request({
+ url: '/evaluation',
+ method: 'put',
+ data: data
+ })
+}
+
+// 鍒犻櫎瀹㈡埛璇勪环
+export function delEvaluation(evaluationId) {
+ return request({
+ url: '/evaluation/' + evaluationId,
+ method: 'delete'
+ })
+}
+
+// 鐢熸垚杞﹁締璇勪环浜岀淮鐮�
+export function generateQrcode(data) {
+ return request({
+ url: '/evaluation/qrcode/generate',
+ method: 'post',
+ data: data
+ })
+}
+
+// 鎵归噺鐢熸垚杞﹁締璇勪环浜岀淮鐮�
+export function batchGenerateQrcode() {
+ return request({
+ url: '/evaluation/qrcode/batch',
+ method: 'post'
+ })
+}
+
+// 鏌ヨ璇勪环缁村害閰嶇疆鍒楄〃
+export function listDimension(query) {
+ return request({
+ url: '/evaluation/dimension/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 鏌ヨ璇勪环缁村害閰嶇疆璇︾粏
+export function getDimension(dimensionId) {
+ return request({
+ url: '/evaluation/dimension/' + dimensionId,
+ method: 'get'
+ })
+}
+
+// 鏂板璇勪环缁村害閰嶇疆
+export function addDimension(data) {
+ return request({
+ url: '/evaluation/dimension',
+ method: 'post',
+ data: data
+ })
+}
+
+// 淇敼璇勪环缁村害閰嶇疆
+export function updateDimension(data) {
+ return request({
+ url: '/evaluation/dimension',
+ method: 'put',
+ data: data
+ })
+}
+
+// 鍒犻櫎璇勪环缁村害閰嶇疆
+export function delDimension(dimensionId) {
+ return request({
+ url: '/evaluation/dimension/' + dimensionId,
+ method: 'delete'
+ })
+}
+
+// 鏌ヨ杞﹁締璇勪环浜岀淮鐮佸垪琛�
+export function listQrcode(query) {
+ return request({
+ url: '/evaluation/qrcode/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 鏌ヨ杞﹁締璇勪环浜岀淮鐮佽缁�
+export function getQrcode(qrcodeId) {
+ return request({
+ url: '/evaluation/qrcode/' + qrcodeId,
+ method: 'get'
+ })
+}
+
+// 鍒犻櫎杞﹁締璇勪环浜岀淮鐮�
+export function delQrcode(qrcodeId) {
+ return request({
+ url: '/evaluation/qrcode/' + qrcodeId,
+ method: 'delete'
+ })
+}
+
+// 鏌ヨ瀹㈡埛璇勪环鍒楄〃锛堢敤浜庣粺璁¢〉闈級
+export function listCustomerEvaluation(query) {
+ return request({
+ url: '/evaluation/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 鏌ヨ瀹㈡埛璇勪环璇︾粏锛堢敤浜庣粺璁¢〉闈級
+export function getCustomerEvaluation(evaluationId) {
+ return request({
+ url: '/evaluation/' + evaluationId,
+ method: 'get'
+ })
+}
+
+// 鑾峰彇璇勪环缁熻鏁版嵁
+export function getEvaluationStatistics(query) {
+ return request({
+ url: '/evaluation/statistics',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index bf8f5be..10ccd84 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -58,6 +58,18 @@
meta: { title: '鍖垮悕璁㈠崟鏌ョ湅', icon: 'eye',anonymous: true }
},
{
+ path: '/evaluation',
+ component: () => import('@/views/evaluation/index'),
+ hidden: true,
+ meta: { title: '瀹㈡埛璇勪环', anonymous: true }
+ },
+ {
+ path: '/evaluation/test',
+ component: () => import('@/views/evaluation/test'),
+ hidden: true,
+ meta: { title: '璇勪环鍔熻兘娴嬭瘯', anonymous: true }
+ },
+ {
path: '/404',
component: () => import('@/views/error/404'),
hidden: true
diff --git a/ruoyi-ui/src/views/evaluation/customer/index.vue b/ruoyi-ui/src/views/evaluation/customer/index.vue
new file mode 100644
index 0000000..288825e
--- /dev/null
+++ b/ruoyi-ui/src/views/evaluation/customer/index.vue
@@ -0,0 +1,297 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="杞︾墝鍙�" prop="vehicleNo">
+ <el-input
+ v-model="queryParams.vehicleNo"
+ placeholder="璇疯緭鍏ヨ溅鐗屽彿"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="瀹㈡埛濮撳悕" prop="customerName">
+ <el-input
+ v-model="queryParams.customerName"
+ placeholder="璇疯緭鍏ュ鎴峰鍚�"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="瀹㈡埛鎵嬫満" prop="customerPhone">
+ <el-input
+ v-model="queryParams.customerPhone"
+ placeholder="璇疯緭鍏ュ鎴锋墜鏈哄彿"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="璇勪环鏃堕棿">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['evaluation:customer:remove']"
+ >鍒犻櫎</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['evaluation:customer:export']"
+ >瀵煎嚭</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="customerEvaluationList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="璇勪环ID" align="center" prop="evaluationId" />
+ <el-table-column label="杞︾墝鍙�" align="center" prop="vehicleNo" />
+ <el-table-column label="瀹㈡埛濮撳悕" align="center" prop="customerName" />
+ <el-table-column label="瀹㈡埛鎵嬫満" align="center" prop="customerPhone" />
+ <el-table-column label="寰俊鏄电О" align="center" prop="wechatNickname" />
+ <el-table-column label="鎬昏瘎鍒�" align="center" prop="totalScore">
+ <template slot-scope="scope">
+ <el-rate
+ v-model="scope.row.totalScore"
+ disabled
+ show-score
+ text-color="#ff9900"
+ score-template="{value}">
+ </el-rate>
+ </template>
+ </el-table-column>
+ <el-table-column label="璇勪环鏃堕棿" align="center" prop="evaluationTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.evaluationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-view"
+ @click="handleView(scope.row)"
+ v-hasPermi="['evaluation:customer:query']"
+ >鏌ョ湅</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['evaluation:customer:remove']"
+ >鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 璇勪环璇︽儏瀵硅瘽妗� -->
+ <el-dialog title="璇勪环璇︽儏" :visible.sync="open" width="800px" append-to-body>
+ <el-descriptions :column="2" border>
+ <el-descriptions-item label="璇勪环ID">{{ evaluationForm.evaluationId }}</el-descriptions-item>
+ <el-descriptions-item label="杞︾墝鍙�">{{ evaluationForm.vehicleNo }}</el-descriptions-item>
+ <el-descriptions-item label="瀹㈡埛濮撳悕">{{ evaluationForm.customerName }}</el-descriptions-item>
+ <el-descriptions-item label="瀹㈡埛鎵嬫満">{{ evaluationForm.customerPhone }}</el-descriptions-item>
+ <el-descriptions-item label="寰俊鏄电О">{{ evaluationForm.wechatNickname }}</el-descriptions-item>
+ <el-descriptions-item label="寰俊澶村儚">
+ <el-image v-if="evaluationForm.wechatAvatar" :src="evaluationForm.wechatAvatar" style="width: 50px; height: 50px;"></el-image>
+ </el-descriptions-item>
+ <el-descriptions-item label="鎬昏瘎鍒�">
+ <el-rate
+ v-model="evaluationForm.totalScore"
+ disabled
+ show-score
+ text-color="#ff9900"
+ score-template="{value}">
+ </el-rate>
+ </el-descriptions-item>
+ <el-descriptions-item label="璇勪环鏃堕棿">{{ parseTime(evaluationForm.evaluationTime) }}</el-descriptions-item>
+ <el-descriptions-item label="IP鍦板潃">{{ evaluationForm.ipAddress }}</el-descriptions-item>
+ <el-descriptions-item label="鐢ㄦ埛浠g悊" :span="2">{{ evaluationForm.userAgent }}</el-descriptions-item>
+ </el-descriptions>
+
+ <div style="margin-top: 20px;">
+ <h4>璇勪环璇︽儏</h4>
+ <el-table :data="evaluationForm.evaluationDetails" border>
+ <el-table-column label="璇勪环缁村害" prop="dimension.dimensionName" />
+ <el-table-column label="璇勫垎" align="center">
+ <template slot-scope="scope">
+ <el-rate
+ v-if="scope.row.dimension.dimensionType === 'star'"
+ v-model="scope.row.score"
+ disabled
+ show-score
+ text-color="#ff9900"
+ score-template="{value}">
+ </el-rate>
+ <span v-else-if="scope.row.dimension.dimensionType === 'select'">{{ scope.row.optionValue }}</span>
+ <span v-else-if="scope.row.dimension.dimensionType === 'text'">{{ scope.row.textContent }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="cancel">鍏� 闂�</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listEvaluation, getEvaluation, delEvaluation } from "@/api/evaluation";
+
+export default {
+ name: "CustomerEvaluation",
+ dicts: [],
+ data() {
+ return {
+ // 閬僵灞�
+ loading: true,
+ // 閫変腑鏁扮粍
+ ids: [],
+ // 闈炲崟涓鐢�
+ single: true,
+ // 闈炲涓鐢�
+ multiple: true,
+ // 鏄剧ず鎼滅储鏉′欢
+ showSearch: true,
+ // 鎬绘潯鏁�
+ total: 0,
+ // 瀹㈡埛璇勪环琛ㄦ牸鏁版嵁
+ customerEvaluationList: [],
+ // 寮瑰嚭灞傛爣棰�
+ title: "",
+ // 鏄惁鏄剧ず寮瑰嚭灞�
+ open: false,
+ // 鏃ユ湡鑼冨洿
+ dateRange: [],
+ // 鏌ヨ鍙傛暟
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ vehicleNo: null,
+ customerName: null,
+ customerPhone: null
+ },
+ // 琛ㄥ崟鍙傛暟
+ evaluationForm: {}
+ };
+ },
+ created() {
+ this.getList();
+ },
+ methods: {
+ /** 鏌ヨ瀹㈡埛璇勪环鍒楄〃 */
+ getList() {
+ this.loading = true;
+ listEvaluation(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+ this.customerEvaluationList = response.rows;
+ this.total = response.total;
+ this.loading = false;
+ });
+ },
+ // 鍙栨秷鎸夐挳
+ cancel() {
+ this.open = false;
+ this.reset();
+ },
+ // 琛ㄥ崟閲嶇疆
+ reset() {
+ this.evaluationForm = {
+ evaluationId: null,
+ vehicleNo: null,
+ customerName: null,
+ customerPhone: null,
+ wechatOpenid: null,
+ wechatNickname: null,
+ wechatAvatar: null,
+ wechatPhone: null,
+ totalScore: null,
+ evaluationStatus: null,
+ evaluationTime: null,
+ ipAddress: null,
+ userAgent: null,
+ evaluationDetails: []
+ };
+ this.resetForm("form");
+ },
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ handleQuery() {
+ this.queryParams.pageNum = 1;
+ this.getList();
+ },
+ /** 閲嶇疆鎸夐挳鎿嶄綔 */
+ resetQuery() {
+ this.dateRange = [];
+ this.resetForm("queryForm");
+ this.handleQuery();
+ },
+ // 澶氶�夋閫変腑鏁版嵁
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.evaluationId)
+ this.single = selection.length!==1
+ this.multiple = !selection.length
+ },
+ /** 鏌ョ湅鎸夐挳鎿嶄綔 */
+ handleView(row) {
+ this.reset();
+ const evaluationId = row.evaluationId || this.ids
+ getEvaluation(evaluationId).then(response => {
+ this.evaluationForm = response.data;
+ this.open = true;
+ this.title = "璇勪环璇︽儏";
+ });
+ },
+ /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+ handleDelete(row) {
+ const evaluationIds = row.evaluationId || this.ids;
+ this.$modal.confirm('鏄惁纭鍒犻櫎瀹㈡埛璇勪环缂栧彿涓�"' + evaluationIds + '"鐨勬暟鎹」锛�').then(function() {
+ return delEvaluation(evaluationIds);
+ }).then(() => {
+ this.getList();
+ this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ }).catch(() => {});
+ },
+ /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+ handleExport() {
+ this.download('evaluation/export', {
+ ...this.queryParams
+ }, `customer_evaluation_${new Date().getTime()}.xlsx`)
+ }
+ }
+};
+</script>
diff --git a/ruoyi-ui/src/views/evaluation/dimension/index.vue b/ruoyi-ui/src/views/evaluation/dimension/index.vue
new file mode 100644
index 0000000..46c25f1
--- /dev/null
+++ b/ruoyi-ui/src/views/evaluation/dimension/index.vue
@@ -0,0 +1,325 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="缁村害鍚嶇О" prop="dimensionName">
+ <el-input
+ v-model="queryParams.dimensionName"
+ placeholder="璇疯緭鍏ョ淮搴﹀悕绉�"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="缁村害绫诲瀷" prop="dimensionType">
+ <el-select v-model="queryParams.dimensionType" placeholder="璇烽�夋嫨缁村害绫诲瀷" clearable>
+ <el-option label="鏄熺骇璇勪环" value="star" />
+ <el-option label="閫夋嫨璇勪环" value="select" />
+ <el-option label="鏂囨湰璇勪环" value="text" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鐘舵��" prop="status">
+ <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable>
+ <el-option label="姝e父" value="0" />
+ <el-option label="鍋滅敤" value="1" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['evaluation:dimension:add']"
+ >鏂板</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['evaluation:dimension:edit']"
+ >淇敼</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['evaluation:dimension:remove']"
+ >鍒犻櫎</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="dimensionList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="缁村害ID" align="center" prop="dimensionId" />
+ <el-table-column label="缁村害鍚嶇О" align="center" prop="dimensionName" />
+ <el-table-column label="缁村害鎻忚堪" align="center" prop="dimensionDesc" />
+ <el-table-column label="缁村害绫诲瀷" align="center" prop="dimensionType">
+ <template slot-scope="scope">
+ <span v-if="scope.row.dimensionType === 'star'">鏄熺骇璇勪环</span>
+ <span v-else-if="scope.row.dimensionType === 'select'">閫夋嫨璇勪环</span>
+ <span v-else-if="scope.row.dimensionType === 'text'">鏂囨湰璇勪环</span>
+ <span v-else>{{ scope.row.dimensionType }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎺掑簭" align="center" prop="sortOrder" />
+ <el-table-column label="鏄惁蹇呭~" align="center" prop="isRequired">
+ <template slot-scope="scope">
+ <span v-if="scope.row.isRequired === '1'">鏄�</span>
+ <span v-else-if="scope.row.isRequired === '0'">鍚�</span>
+ <span v-else>{{ scope.row.isRequired }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鐘舵��" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['evaluation:dimension:edit']"
+ >淇敼</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['evaluation:dimension:remove']"
+ >鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 娣诲姞鎴栦慨鏀硅瘎浠风淮搴﹂厤缃璇濇 -->
+ <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+ <el-form-item label="缁村害鍚嶇О" prop="dimensionName">
+ <el-input v-model="form.dimensionName" placeholder="璇疯緭鍏ョ淮搴﹀悕绉�" />
+ </el-form-item>
+ <el-form-item label="缁村害鎻忚堪" prop="dimensionDesc">
+ <el-input v-model="form.dimensionDesc" type="textarea" placeholder="璇疯緭鍏ョ淮搴︽弿杩�" />
+ </el-form-item>
+ <el-form-item label="缁村害绫诲瀷" prop="dimensionType">
+ <el-select v-model="form.dimensionType" placeholder="璇烽�夋嫨缁村害绫诲瀷">
+ <el-option label="鏄熺骇璇勪环" value="star" />
+ <el-option label="閫夋嫨璇勪环" value="select" />
+ <el-option label="鏂囨湰璇勪环" value="text" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="閫夐」閰嶇疆" prop="options" v-if="form.dimensionType === 'select'">
+ <el-input v-model="form.options" type="textarea" placeholder="璇疯緭鍏ラ�夐」閰嶇疆锛孞SON鏍煎紡锛屽锛歔{"label":"婊℃剰","value":"1"},{"label":"涓嶆弧鎰�","value":"0"}]" />
+ </el-form-item>
+ <el-form-item label="鎺掑簭" prop="sortOrder">
+ <el-input-number v-model="form.sortOrder" controls-position="right" :min="0" />
+ </el-form-item>
+ <el-form-item label="鏄惁蹇呭~" prop="isRequired">
+ <el-radio-group v-model="form.isRequired">
+ <el-radio label="1">鏄�</el-radio>
+ <el-radio label="0">鍚�</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="鐘舵��" prop="status">
+ <el-radio-group v-model="form.status">
+ <el-radio label="0">姝e父</el-radio>
+ <el-radio label="1">鍋滅敤</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="澶囨敞" prop="remark">
+ <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+ <el-button @click="cancel">鍙� 娑�</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listDimension, getDimension, delDimension, addDimension, updateDimension } from "@/api/evaluation";
+
+export default {
+ name: "EvaluationDimension",
+ dicts: ['dimension_type', 'sys_yes_no', 'sys_normal_disable'],
+ data() {
+ return {
+ // 閬僵灞�
+ loading: true,
+ // 閫変腑鏁扮粍
+ ids: [],
+ // 闈炲崟涓鐢�
+ single: true,
+ // 闈炲涓鐢�
+ multiple: true,
+ // 鏄剧ず鎼滅储鏉′欢
+ showSearch: true,
+ // 鎬绘潯鏁�
+ total: 0,
+ // 璇勪环缁村害閰嶇疆琛ㄦ牸鏁版嵁
+ dimensionList: [],
+ // 寮瑰嚭灞傛爣棰�
+ title: "",
+ // 鏄惁鏄剧ず寮瑰嚭灞�
+ open: false,
+ // 鏌ヨ鍙傛暟
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ dimensionName: null,
+ dimensionType: null,
+ status: null
+ },
+ // 琛ㄥ崟鍙傛暟
+ form: {},
+ // 琛ㄥ崟鏍¢獙
+ rules: {
+ dimensionName: [
+ { required: true, message: "缁村害鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+ ],
+ dimensionType: [
+ { required: true, message: "缁村害绫诲瀷涓嶈兘涓虹┖", trigger: "change" }
+ ],
+ sortOrder: [
+ { required: true, message: "鎺掑簭涓嶈兘涓虹┖", trigger: "blur" }
+ ],
+ isRequired: [
+ { required: true, message: "鏄惁蹇呭~涓嶈兘涓虹┖", trigger: "change" }
+ ],
+ status: [
+ { required: true, message: "鐘舵�佷笉鑳戒负绌�", trigger: "change" }
+ ]
+ }
+ };
+ },
+ created() {
+ this.getList();
+ },
+ methods: {
+ /** 鏌ヨ璇勪环缁村害閰嶇疆鍒楄〃 */
+ getList() {
+ this.loading = true;
+ listDimension(this.queryParams).then(response => {
+ this.dimensionList = response.rows;
+ this.total = response.total;
+ this.loading = false;
+ });
+ },
+ // 鍙栨秷鎸夐挳
+ cancel() {
+ this.open = false;
+ this.reset();
+ },
+ // 琛ㄥ崟閲嶇疆
+ reset() {
+ this.form = {
+ dimensionId: null,
+ dimensionName: null,
+ dimensionDesc: null,
+ dimensionType: null,
+ options: null,
+ sortOrder: 0,
+ isRequired: "1",
+ status: "0",
+ remark: null
+ };
+ this.resetForm("form");
+ },
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ handleQuery() {
+ this.queryParams.pageNum = 1;
+ this.getList();
+ },
+ /** 閲嶇疆鎸夐挳鎿嶄綔 */
+ resetQuery() {
+ this.resetForm("queryForm");
+ this.handleQuery();
+ },
+ // 澶氶�夋閫変腑鏁版嵁
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.dimensionId)
+ this.single = selection.length!==1
+ this.multiple = !selection.length
+ },
+ /** 鏂板鎸夐挳鎿嶄綔 */
+ handleAdd() {
+ this.reset();
+ this.open = true;
+ this.title = "娣诲姞璇勪环缁村害閰嶇疆";
+ },
+ /** 淇敼鎸夐挳鎿嶄綔 */
+ handleUpdate(row) {
+ this.reset();
+ const dimensionId = row.dimensionId || this.ids
+ getDimension(dimensionId).then(response => {
+ this.form = response.data;
+ this.open = true;
+ this.title = "淇敼璇勪环缁村害閰嶇疆";
+ });
+ },
+ /** 鎻愪氦鎸夐挳 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.dimensionId != null) {
+ updateDimension(this.form).then(response => {
+ this.$modal.msgSuccess("淇敼鎴愬姛");
+ this.open = false;
+ this.getList();
+ });
+ } else {
+ addDimension(this.form).then(response => {
+ this.$modal.msgSuccess("鏂板鎴愬姛");
+ this.open = false;
+ this.getList();
+ });
+ }
+ }
+ });
+ },
+ /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+ handleDelete(row) {
+ const dimensionIds = row.dimensionId || this.ids;
+ this.$modal.confirm('鏄惁纭鍒犻櫎璇勪环缁村害閰嶇疆缂栧彿涓�"' + dimensionIds + '"鐨勬暟鎹」锛�').then(function() {
+ return delDimension(dimensionIds);
+ }).then(() => {
+ this.getList();
+ this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ }).catch(() => {});
+ }
+ }
+};
+</script>
diff --git a/ruoyi-ui/src/views/evaluation/index.vue b/ruoyi-ui/src/views/evaluation/index.vue
new file mode 100644
index 0000000..017d5af
--- /dev/null
+++ b/ruoyi-ui/src/views/evaluation/index.vue
@@ -0,0 +1,659 @@
+<template>
+ <div class="evaluation-container">
+ <!-- 椤甸潰澶撮儴 -->
+ <div class="evaluation-header">
+ <h1>鏈嶅姟璇勪环</h1>
+ <p>鎰熻阿鎮ㄤ娇鐢ㄦ垜浠殑鏈嶅姟锛岃瀵规湰娆℃湇鍔¤繘琛岃瘎浠�</p>
+ </div>
+
+ <!-- 杞﹁締淇℃伅 -->
+ <div class="vehicle-info" v-if="vehicleNo">
+ <div class="info-item">
+ <span class="label">杞︾墝鍙凤細</span>
+ <span class="value">{{ vehicleNo }}</span>
+ </div>
+ </div>
+
+ <!-- 璇勪环琛ㄥ崟 -->
+ <div class="evaluation-form">
+ <el-form ref="evaluationForm" :model="evaluationForm" :rules="rules" label-width="80px" size="small">
+ <!-- 瀹㈡埛淇℃伅 -->
+ <div class="form-section">
+ <h3>瀹㈡埛淇℃伅</h3>
+ <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="璇疯緭鍏ユ偍鐨勬墜鏈哄彿" />
+ </el-form-item>
+ </div>
+
+ <!-- 璇勪环缁村害 -->
+ <div class="form-section">
+ <h3>鏈嶅姟璇勪环</h3>
+ <div v-for="dimension in dimensions" :key="dimension.dimensionId" class="dimension-item">
+ <!-- 鏄熺骇璇勪环 - 鏍囬鍜岃瘎鍒嗗湪鍚屼竴琛� -->
+ <div v-if="dimension.dimensionType === 'star'" class="star-rating-inline">
+ <div class="dimension-title-inline">
+ <span>{{ 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"
+ />
+ </div>
+ </div>
+
+ <!-- 閫夋嫨璇勪环 -->
+ <div v-else-if="dimension.dimensionType === 'select'">
+ <div class="dimension-title">
+ <span>{{ dimension.dimensionName }}</span>
+ <span v-if="dimension.isRequired === '1'" class="required">*</span>
+ </div>
+ <div class="dimension-desc" v-if="dimension.dimensionDesc">
+ {{ 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">
+ {{ option.label }}
+ </el-radio>
+ </el-radio-group>
+ </div>
+ </div>
+
+ <!-- 鏂囨湰璇勪环 -->
+ <div v-else-if="dimension.dimensionType === 'text'">
+ <div class="dimension-title">
+ <span>{{ dimension.dimensionName }}</span>
+ <span v-if="dimension.isRequired === '1'" class="required">*</span>
+ </div>
+ <div class="dimension-desc" v-if="dimension.dimensionDesc">
+ {{ dimension.dimensionDesc }}
+ </div>
+ <div class="text-rating">
+ <el-input
+ :value="getDimensionText(dimension.dimensionId)"
+ type="textarea"
+ :rows="2"
+ placeholder="璇疯緭鍏ユ偍鐨勬剰瑙佹垨寤鸿"
+ @input="updateDimensionText(dimension.dimensionId, $event)"
+ size="small"
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- 鎻愪氦鎸夐挳 -->
+ <div class="form-actions">
+ <el-button type="primary" size="large" @click="submitEvaluation" :loading="submitting">
+ 鎻愪氦璇勪环
+ </el-button>
+ </div>
+ </el-form>
+ </div>
+
+ <!-- 缁撴灉椤甸潰 -->
+ <div v-if="showResult" class="result-page">
+ <div class="result-content">
+ <div class="result-icon">
+ <i class="el-icon-success" style="font-size: 60px; color: #67C23A;"></i>
+ </div>
+ <div class="result-message">
+ {{ resultMessage }}
+ </div>
+ <div class="result-actions">
+ <el-button type="primary" @click="resetForm">鍐嶆璇勪环</el-button>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import { getEvaluationDimensions, submitEvaluation, getWechatUserInfo } from "@/api/evaluation";
+
+export default {
+ name: "Evaluation",
+ data() {
+ return {
+ vehicleNo: '',
+ dimensions: [],
+ evaluationForm: {
+ vehicleNo: '',
+ customerName: '',
+ customerPhone: '',
+ wechatOpenid: '',
+ wechatNickname: '',
+ wechatAvatar: '',
+ wechatPhone: '',
+ evaluationDetails: []
+ },
+ rules: {
+ customerName: [
+ { required: true, message: '璇疯緭鍏ユ偍鐨勫鍚�', trigger: 'blur' }
+ ],
+ customerPhone: [
+ { required: true, message: '璇疯緭鍏ユ偍鐨勬墜鏈哄彿', trigger: 'blur' },
+ { pattern: /^1[3-9]\d{9}$/, message: '璇疯緭鍏ユ纭殑鎵嬫満鍙�', trigger: 'blur' }
+ ]
+ },
+ submitting: false,
+ showResult: false,
+ resultMessage: ''
+ };
+ },
+ created() {
+ this.initPage();
+ },
+ methods: {
+ // 鍒濆鍖栭〉闈�
+ async initPage() {
+ // 鑾峰彇URL鍙傛暟
+ this.vehicleNo = this.$route.query.vehicle || '';
+ this.evaluationForm.vehicleNo = this.vehicleNo;
+
+ // 妫�鏌ユ槸鍚﹀湪寰俊鐜涓�
+ if (this.isWechatBrowser()) {
+ await this.handleWechatAuth();
+ }
+
+ // 鍔犺浇璇勪环缁村害
+ await this.loadDimensions();
+ },
+
+ // 鍒ゆ柇鏄惁涓哄井淇℃祻瑙堝櫒
+ isWechatBrowser() {
+ const ua = navigator.userAgent.toLowerCase();
+ return ua.indexOf('micromessenger') !== -1;
+ },
+
+ // 澶勭悊寰俊鎺堟潈
+ async handleWechatAuth() {
+ const code = this.$route.query.code;
+ if (code) {
+ try {
+ const response = await getWechatUserInfo(code);
+ if (response.code === 200) {
+ const userInfo = response.data;
+ this.evaluationForm.wechatOpenid = userInfo.openid;
+ this.evaluationForm.wechatNickname = userInfo.nickname;
+ this.evaluationForm.wechatAvatar = userInfo.headimgurl;
+ this.evaluationForm.wechatPhone = userInfo.phone || '';
+ }
+ } catch (error) {
+ console.error('鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触:', error);
+ }
+ }
+ },
+
+ // 鍔犺浇璇勪环缁村害
+ async loadDimensions() {
+ try {
+ const response = await getEvaluationDimensions();
+ if (response.code === 200) {
+ this.dimensions = response.data;
+ }
+ } catch (error) {
+ console.error('鍔犺浇璇勪环缁村害澶辫触:', error);
+ this.$message.error('鍔犺浇璇勪环缁村害澶辫触');
+ }
+ },
+
+ // 鑾峰彇缁村害璇勫垎
+ getDimensionScore(dimensionId) {
+ const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
+ return detail ? detail.score : 0;
+ },
+
+ // 鏇存柊缁村害璇勫垎
+ updateDimensionScore(dimensionId, score) {
+ let detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
+ if (!detail) {
+ detail = { dimensionId, score: 0 };
+ this.evaluationForm.evaluationDetails.push(detail);
+ }
+ detail.score = score;
+ },
+
+ // 鑾峰彇缁村害閫夐」
+ getDimensionOption(dimensionId) {
+ const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
+ return detail ? detail.optionValue : '';
+ },
+
+ // 鏇存柊缁村害閫夐」
+ updateDimensionOption(dimensionId, optionValue) {
+ let detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
+ if (!detail) {
+ detail = { dimensionId, optionValue: '' };
+ this.evaluationForm.evaluationDetails.push(detail);
+ }
+ detail.optionValue = optionValue;
+ },
+
+ // 鑾峰彇缁村害鏂囨湰
+ getDimensionText(dimensionId) {
+ const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
+ return detail ? detail.textContent : '';
+ },
+
+ // 鏇存柊缁村害鏂囨湰
+ updateDimensionText(dimensionId, textContent) {
+ let detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId);
+ if (!detail) {
+ detail = { dimensionId, textContent: '' };
+ this.evaluationForm.evaluationDetails.push(detail);
+ }
+ detail.textContent = textContent;
+ },
+
+ // 鑾峰彇缁村害閫夐」閰嶇疆
+ getDimensionOptions(dimension) {
+ if (!dimension.options) return [];
+ try {
+ return JSON.parse(dimension.options);
+ } catch (error) {
+ return [];
+ }
+ },
+
+ // 鎻愪氦璇勪环
+ async submitEvaluation() {
+ try {
+ // 琛ㄥ崟楠岃瘉
+ await this.$refs.evaluationForm.validate();
+
+ // 妫�鏌ュ繀濉殑璇勪环缁村害
+ for (const dimension of this.dimensions) {
+ if (dimension.isRequired === '1') {
+ const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimension.dimensionId);
+ if (!detail || (dimension.dimensionType === 'star' && !detail.score) ||
+ (dimension.dimensionType === 'select' && !detail.optionValue) ||
+ (dimension.dimensionType === 'text' && !detail.textContent)) {
+ this.$message.error(`璇峰畬鎴�${dimension.dimensionName}鐨勮瘎浠穈);
+ return;
+ }
+ }
+ }
+
+ this.submitting = true;
+
+ // 鎻愪氦璇勪环
+ const response = await submitEvaluation(this.evaluationForm);
+ if (response.code === 200) {
+ this.resultMessage = response.msg;
+ this.showResult = true;
+ } else {
+ this.$message.error(response.msg || '鎻愪氦澶辫触锛岃閲嶈瘯');
+ }
+ } catch (error) {
+ console.error('鎻愪氦璇勪环澶辫触:', error);
+ this.$message.error('鎻愪氦澶辫触锛岃閲嶈瘯');
+ } finally {
+ this.submitting = false;
+ }
+ },
+
+ // 閲嶇疆琛ㄥ崟
+ resetForm() {
+ this.showResult = false;
+ this.evaluationForm.customerName = '';
+ this.evaluationForm.customerPhone = '';
+ this.evaluationForm.evaluationDetails = [];
+ this.$refs.evaluationForm.resetFields();
+ }
+ }
+};
+</script>
+
+<style scoped>
+.evaluation-container {
+ max-width: 600px;
+ margin: 0 auto;
+ padding: 8px;
+ background-color: #f5f5f5;
+ min-height: 100vh;
+}
+
+.evaluation-header {
+ text-align: center;
+ margin-bottom: 12px;
+ padding: 12px;
+ background: white;
+ border-radius: 6px;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+}
+
+.evaluation-header h1 {
+ color: #333;
+ margin: 0 0 6px 0;
+ font-size: 20px;
+}
+
+.evaluation-header p {
+ color: #666;
+ margin: 0;
+ font-size: 14px;
+}
+
+.vehicle-info {
+ background: white;
+ padding: 8px 12px;
+ border-radius: 6px;
+ margin-bottom: 12px;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+}
+
+.info-item {
+ display: flex;
+ align-items: center;
+}
+
+.label {
+ font-weight: bold;
+ color: #333;
+ margin-right: 8px;
+ font-size: 14px;
+}
+
+.value {
+ color: #666;
+ font-size: 14px;
+}
+
+.evaluation-form {
+ background: white;
+ padding: 12px;
+ border-radius: 6px;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+}
+
+.form-section {
+ margin-bottom: 16px;
+}
+
+.form-section h3 {
+ color: #333;
+ margin: 0 0 12px 0;
+ padding-bottom: 6px;
+ border-bottom: 1px solid #409EFF;
+ font-size: 16px;
+}
+
+.dimension-item {
+ margin-bottom: 12px;
+ padding: 8px;
+ border: 1px solid #e4e7ed;
+ border-radius: 4px;
+ background-color: #fafafa;
+}
+
+.dimension-title {
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 4px;
+ font-size: 14px;
+}
+
+.required {
+ color: #f56c6c;
+ margin-left: 3px;
+}
+
+.dimension-desc {
+ color: #666;
+ font-size: 12px;
+ margin-bottom: 8px;
+}
+
+/* 鏄熺骇璇勪环鍐呰仈甯冨眬 */
+.star-rating-inline {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.dimension-title-inline {
+ font-weight: bold;
+ color: #333;
+ font-size: 14px;
+ flex-shrink: 0;
+}
+
+.star-rating-content {
+ flex: 1;
+ min-width: 200px;
+}
+
+.star-rating, .select-rating, .text-rating {
+ margin-top: 6px;
+}
+
+/* 浼樺寲鏄熺骇璇勫垎鏄剧ず */
+.star-rating .el-rate {
+ font-size: 18px;
+}
+
+.star-rating .el-rate__text {
+ font-size: 12px;
+ margin-left: 8px;
+}
+
+/* 浼樺寲閫夋嫨璇勪环鏄剧ず */
+.select-rating .el-radio {
+ margin-right: 12px;
+ margin-bottom: 4px;
+}
+
+.select-rating .el-radio__label {
+ font-size: 13px;
+}
+
+/* 浼樺寲鏂囨湰璇勪环鏄剧ず */
+.text-rating .el-textarea__inner {
+ font-size: 13px;
+ min-height: 60px !important;
+}
+
+/* 浼樺寲琛ㄥ崟椤归棿璺� */
+.el-form-item {
+ margin-bottom: 12px;
+}
+
+.el-form-item__label {
+ font-size: 13px;
+ line-height: 28px;
+}
+
+.el-input__inner {
+ font-size: 13px;
+ height: 32px;
+ line-height: 32px;
+}
+
+.form-actions {
+ text-align: center;
+ margin-top: 16px;
+}
+
+.form-actions .el-button {
+ padding: 10px 30px;
+ font-size: 14px;
+}
+
+.result-page {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0,0,0,0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+}
+
+.result-content {
+ background: white;
+ padding: 30px;
+ border-radius: 8px;
+ text-align: center;
+ max-width: 350px;
+ width: 90%;
+}
+
+.result-icon {
+ margin-bottom: 16px;
+}
+
+.result-message {
+ font-size: 16px;
+ color: #333;
+ margin-bottom: 20px;
+}
+
+.result-actions {
+ text-align: center;
+}
+
+/* 绉诲姩绔�傞厤 */
+@media (max-width: 768px) {
+ .evaluation-container {
+ padding: 6px;
+ }
+
+ .evaluation-header {
+ padding: 10px;
+ margin-bottom: 8px;
+ }
+
+ .evaluation-header h1 {
+ font-size: 18px;
+ }
+
+ .evaluation-header p {
+ font-size: 13px;
+ }
+
+ .evaluation-form {
+ padding: 10px;
+ }
+
+ .dimension-item {
+ padding: 6px;
+ margin-bottom: 8px;
+ }
+
+ .form-section {
+ margin-bottom: 12px;
+ }
+
+ .form-section h3 {
+ font-size: 15px;
+ margin-bottom: 8px;
+ }
+
+ .dimension-title {
+ font-size: 13px;
+ }
+
+ .dimension-desc {
+ font-size: 11px;
+ }
+
+ .star-rating .el-rate {
+ font-size: 16px;
+ }
+
+ /* 绉诲姩绔槦绾ц瘎浠峰唴鑱斿竷灞� */
+ .star-rating-inline {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 6px;
+ }
+
+ .dimension-title-inline {
+ font-size: 13px;
+ }
+
+ .star-rating-content {
+ min-width: auto;
+ width: 100%;
+ }
+
+ .select-rating .el-radio {
+ margin-right: 8px;
+ }
+
+ .select-rating .el-radio__label {
+ font-size: 12px;
+ }
+
+ .text-rating .el-textarea__inner {
+ font-size: 12px;
+ min-height: 50px !important;
+ }
+
+ .el-form-item {
+ margin-bottom: 8px;
+ }
+
+ .el-form-item__label {
+ font-size: 12px;
+ line-height: 26px;
+ }
+
+ .el-input__inner {
+ font-size: 12px;
+ height: 30px;
+ line-height: 30px;
+ }
+
+ .form-actions {
+ margin-top: 12px;
+ }
+
+ .form-actions .el-button {
+ padding: 8px 24px;
+ font-size: 13px;
+ }
+}
+
+/* 瓒呭皬灞忓箷閫傞厤 */
+@media (max-width: 480px) {
+ .evaluation-container {
+ padding: 4px;
+ }
+
+ .evaluation-header {
+ padding: 8px;
+ }
+
+ .evaluation-form {
+ padding: 8px;
+ }
+
+ .dimension-item {
+ padding: 4px;
+ }
+
+ .star-rating .el-rate {
+ font-size: 14px;
+ }
+
+ .text-rating .el-textarea__inner {
+ min-height: 40px !important;
+ }
+}
+</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/evaluation/qrcode/index.vue b/ruoyi-ui/src/views/evaluation/qrcode/index.vue
new file mode 100644
index 0000000..be23c18
--- /dev/null
+++ b/ruoyi-ui/src/views/evaluation/qrcode/index.vue
@@ -0,0 +1,345 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="杞︾墝鍙�" prop="vehicleNo">
+ <el-input
+ v-model="queryParams.vehicleNo"
+ placeholder="璇疯緭鍏ヨ溅鐗屽彿"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="鐘舵��" prop="status">
+ <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨鐘舵��" clearable>
+ <el-option label="姝e父" value="0" />
+ <el-option label="鍋滅敤" value="1" />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['evaluation:qrcode:generate']"
+ >鐢熸垚浜岀淮鐮�</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-upload2"
+ size="mini"
+ @click="handleBatchGenerate"
+ v-hasPermi="['evaluation:qrcode:batch']"
+ >鎵归噺鐢熸垚</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['evaluation:qrcode:remove']"
+ >鍒犻櫎</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="qrcodeList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="浜岀淮鐮両D" align="center" prop="qrcodeId" />
+ <el-table-column label="杞︾墝鍙�" align="center" prop="vehicleNo" />
+ <el-table-column label="浜岀淮鐮乁RL" align="center" prop="qrcodeUrl" width="200">
+ <template slot-scope="scope">
+ <el-link :href="scope.row.qrcodeUrl" target="_blank" type="primary">{{ scope.row.qrcodeUrl }}</el-link>
+ </template>
+ </el-table-column>
+ <el-table-column label="浜岀淮鐮佸唴瀹�" align="center" prop="qrcodeContent" />
+ <el-table-column label="浜岀淮鐮佸浘鐗�" align="center" prop="qrcodeImage" width="100">
+ <template slot-scope="scope">
+ <el-image
+ v-if="scope.row.qrcodeImage"
+ :src="getImageUrl(scope.row.qrcodeImage)"
+ :preview-src-list="[getImageUrl(scope.row.qrcodeImage)]"
+ style="width: 50px; height: 50px;"
+ fit="cover">
+ </el-image>
+ </template>
+ </el-table-column>
+ <el-table-column label="鐘舵��" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-view"
+ @click="handleView(scope.row)"
+ v-hasPermi="['evaluation:qrcode:query']"
+ >鏌ョ湅</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-download"
+ @click="handleDownload(scope.row)"
+ >涓嬭浇</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['evaluation:qrcode:remove']"
+ >鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 鐢熸垚浜岀淮鐮佸璇濇 -->
+ <el-dialog title="鐢熸垚浜岀淮鐮�" :visible.sync="open" width="500px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+ <el-form-item label="杞︾墝鍙�" prop="vehicleNo">
+ <el-input v-model="form.vehicleNo" placeholder="璇疯緭鍏ヨ溅鐗屽彿" />
+ </el-form-item>
+ <el-form-item label="浜岀淮鐮乁RL" prop="qrcodeUrl">
+ <el-input v-model="form.qrcodeUrl" placeholder="璇疯緭鍏ヤ簩缁寸爜URL" />
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+ <el-button @click="cancel">鍙� 娑�</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="浜岀淮鐮両D">{{ viewForm.qrcodeId }}</el-descriptions-item>
+ <el-descriptions-item label="杞︾墝鍙�">{{ viewForm.vehicleNo }}</el-descriptions-item>
+ <el-descriptions-item label="浜岀淮鐮乁RL" :span="2">
+ <el-link :href="viewForm.qrcodeUrl" target="_blank" type="primary">{{ viewForm.qrcodeUrl }}</el-link>
+ </el-descriptions-item>
+ <el-descriptions-item label="浜岀淮鐮佸唴瀹�" :span="2">{{ viewForm.qrcodeContent }}</el-descriptions-item>
+ <el-descriptions-item label="鐘舵��">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="viewForm.status"/>
+ </el-descriptions-item>
+ <el-descriptions-item label="鍒涘缓鏃堕棿">{{ parseTime(viewForm.createTime) }}</el-descriptions-item>
+ <el-descriptions-item label="浜岀淮鐮佸浘鐗�" :span="2">
+ <el-image
+ v-if="viewForm.qrcodeImage"
+ :src="getImageUrl(viewForm.qrcodeImage)"
+ style="width: 200px; height: 200px;"
+ fit="cover">
+ </el-image>
+ </el-descriptions-item>
+ </el-descriptions>
+
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="viewOpen = false">鍏� 闂�</el-button>
+ <el-button type="primary" @click="handleDownload(viewForm)">涓嬭浇浜岀淮鐮�</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listQrcode, getQrcode, delQrcode, generateQrcode, batchGenerateQrcode } from "@/api/evaluation";
+
+export default {
+ name: "VehicleEvaluationQrcode",
+ dicts: ['sys_normal_disable'],
+ data() {
+ return {
+ // 閬僵灞�
+ loading: true,
+ // 閫変腑鏁扮粍
+ ids: [],
+ // 闈炲崟涓鐢�
+ single: true,
+ // 闈炲涓鐢�
+ multiple: true,
+ // 鏄剧ず鎼滅储鏉′欢
+ showSearch: true,
+ // 鎬绘潯鏁�
+ total: 0,
+ // 杞﹁締璇勪环浜岀淮鐮佽〃鏍兼暟鎹�
+ qrcodeList: [],
+ // 寮瑰嚭灞傛爣棰�
+ title: "",
+ // 鏄惁鏄剧ず寮瑰嚭灞�
+ open: false,
+ // 鏄惁鏄剧ず鏌ョ湅寮瑰嚭灞�
+ viewOpen: false,
+ // 鏌ヨ鍙傛暟
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ vehicleNo: null,
+ status: null
+ },
+ // 琛ㄥ崟鍙傛暟
+ form: {},
+ // 鏌ョ湅琛ㄥ崟鍙傛暟
+ viewForm: {},
+ // 琛ㄥ崟鏍¢獙
+ rules: {
+ vehicleNo: [
+ { required: true, message: "杞︾墝鍙蜂笉鑳戒负绌�", trigger: "blur" }
+ ],
+ qrcodeUrl: [
+ { required: true, message: "浜岀淮鐮乁RL涓嶈兘涓虹┖", trigger: "blur" },
+ { type: 'url', message: '璇疯緭鍏ユ纭殑URL鏍煎紡', trigger: 'blur' }
+ ]
+ }
+ };
+ },
+ created() {
+ this.getList();
+ },
+ methods: {
+ /** 鏌ヨ杞﹁締璇勪环浜岀淮鐮佸垪琛� */
+ getList() {
+ this.loading = true;
+ listQrcode(this.queryParams).then(response => {
+ this.qrcodeList = response.rows;
+ this.total = response.total;
+ this.loading = false;
+ });
+ },
+ // 鍙栨秷鎸夐挳
+ cancel() {
+ this.open = false;
+ this.reset();
+ },
+ // 琛ㄥ崟閲嶇疆
+ reset() {
+ this.form = {
+ qrcodeId: null,
+ vehicleNo: null,
+ qrcodeUrl: null,
+ qrcodeContent: null,
+ qrcodeImage: null,
+ status: "0"
+ };
+ this.resetForm("form");
+ },
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ handleQuery() {
+ this.queryParams.pageNum = 1;
+ this.getList();
+ },
+ /** 閲嶇疆鎸夐挳鎿嶄綔 */
+ resetQuery() {
+ this.resetForm("queryForm");
+ this.handleQuery();
+ },
+ // 澶氶�夋閫変腑鏁版嵁
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.qrcodeId)
+ this.single = selection.length!==1
+ this.multiple = !selection.length
+ },
+ /** 鏂板鎸夐挳鎿嶄綔 */
+ handleAdd() {
+ this.reset();
+ this.open = true;
+ this.title = "鐢熸垚浜岀淮鐮�";
+ },
+ /** 鎻愪氦鎸夐挳 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ const params = {
+ vehicleNo: this.form.vehicleNo,
+ qrcodeUrl: this.form.qrcodeUrl
+ };
+ generateQrcode(params).then(response => {
+ this.$modal.msgSuccess("鐢熸垚鎴愬姛");
+ this.open = false;
+ this.getList();
+ });
+ }
+ });
+ },
+ /** 鎵归噺鐢熸垚鎸夐挳鎿嶄綔 */
+ handleBatchGenerate() {
+ this.$modal.confirm('鏄惁纭鎵归噺鐢熸垚鎵�鏈夎溅杈嗙殑浜岀淮鐮侊紵').then(function() {
+ return batchGenerateQrcode();
+ }).then(() => {
+ this.getList();
+ this.$modal.msgSuccess("鎵归噺鐢熸垚鎴愬姛");
+ }).catch(() => {});
+ },
+ /** 鏌ョ湅鎸夐挳鎿嶄綔 */
+ handleView(row) {
+ this.viewForm = row;
+ this.viewOpen = true;
+ },
+ /** 涓嬭浇鎸夐挳鎿嶄綔 */
+ handleDownload(row) {
+ if (row.qrcodeImage) {
+ const link = document.createElement('a');
+ link.href = this.getImageUrl(row.qrcodeImage);
+ link.download = `qrcode_${row.vehicleNo}.png`;
+ link.click();
+ }
+ },
+ /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+ handleDelete(row) {
+ const qrcodeIds = row.qrcodeId || this.ids;
+ this.$modal.confirm('鏄惁纭鍒犻櫎杞﹁締璇勪环浜岀淮鐮佺紪鍙蜂负"' + qrcodeIds + '"鐨勬暟鎹」锛�').then(function() {
+ return delQrcode(qrcodeIds);
+ }).then(() => {
+ this.getList();
+ this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ }).catch(() => {});
+ },
+ /** 鑾峰彇鍥剧墖URL */
+ getImageUrl(imagePath) {
+ if (imagePath) {
+ // 濡傛灉鏄痓ase64鏍煎紡锛岀洿鎺ヨ繑鍥�
+ if (imagePath.startsWith('data:image/')) {
+ return imagePath;
+ }
+ // 濡傛灉璺緞宸茬粡鍖呭惈http锛岀洿鎺ヨ繑鍥�
+ if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
+ return imagePath;
+ }
+ // 濡傛灉璺緞浠�/寮�澶达紝鐩存帴鎷兼帴鍩熷悕
+ if (imagePath.startsWith('/')) {
+ return process.env.VUE_APP_BASE_API + imagePath;
+ }
+ // 鍏朵粬鎯呭喌锛屾坊鍔�/鍓嶇紑鍚庢嫾鎺ュ煙鍚�
+ return process.env.VUE_APP_BASE_API + '/' + imagePath;
+ }
+ return '';
+ }
+ }
+};
+</script>
diff --git a/ruoyi-ui/src/views/evaluation/statistics/index.vue b/ruoyi-ui/src/views/evaluation/statistics/index.vue
new file mode 100644
index 0000000..68b46d4
--- /dev/null
+++ b/ruoyi-ui/src/views/evaluation/statistics/index.vue
@@ -0,0 +1,512 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="杞︾墝鍙�" prop="vehicleNo">
+ <el-input
+ v-model="queryParams.vehicleNo"
+ placeholder="璇疯緭鍏ヨ溅鐗屽彿"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="璇勪环鏃堕棿" prop="evaluationTime">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="32">
+ <el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
+ <div class="card-panel">
+ <div class="card-panel-icon-wrapper icon-people">
+ <svg-icon icon-class="peoples" class-name="card-panel-icon" />
+ </div>
+ <div class="card-panel-description">
+ <div class="card-panel-text">鎬昏瘎浠锋暟</div>
+ <div class="card-panel-num">{{ statisticsData.totalEvaluations }}</div>
+ </div>
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
+ <div class="card-panel">
+ <div class="card-panel-icon-wrapper icon-message">
+ <svg-icon icon-class="message" class-name="card-panel-icon" />
+ </div>
+ <div class="card-panel-description">
+ <div class="card-panel-text">骞冲潎璇勫垎</div>
+ <div class="card-panel-num">{{ statisticsData.averageScore }}</div>
+ </div>
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
+ <div class="card-panel">
+ <div class="card-panel-icon-wrapper icon-star">
+ <svg-icon icon-class="star" class-name="card-panel-icon" />
+ </div>
+ <div class="card-panel-description">
+ <div class="card-panel-text">濂借瘎鐜�</div>
+ <div class="card-panel-num">{{ statisticsData.goodRate }}%</div>
+ </div>
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="12" :lg="6" class="card-panel-col">
+ <div class="card-panel">
+ <div class="card-panel-icon-wrapper icon-vehicle">
+ <svg-icon icon-class="car" class-name="card-panel-icon" />
+ </div>
+ <div class="card-panel-description">
+ <div class="card-panel-text">鍙備笌杞﹁締</div>
+ <div class="card-panel-num">{{ statisticsData.vehicleCount }}</div>
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+
+ <el-row :gutter="32" style="margin-top: 20px;">
+ <el-col :xs="24" :sm="24" :lg="12">
+ <div class="chart-container">
+ <div class="chart-title">璇勫垎鍒嗗竷</div>
+ <div ref="scoreChart" class="chart"></div>
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="24" :lg="12">
+ <div class="chart-container">
+ <div class="chart-title">鏈堝害璇勪环瓒嬪娍</div>
+ <div ref="trendChart" class="chart"></div>
+ </div>
+ </el-col>
+ </el-row>
+
+ <el-row style="margin-top: 20px;">
+ <el-col :span="24">
+ <div class="chart-container">
+ <div class="chart-title">鍚勭淮搴﹁瘎鍒嗙粺璁�</div>
+ <div ref="dimensionChart" class="chart"></div>
+ </div>
+ </el-col>
+ </el-row>
+
+ <el-table v-loading="loading" :data="evaluationList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="璇勪环ID" align="center" prop="evaluationId" />
+ <el-table-column label="杞︾墝鍙�" align="center" prop="vehicleNo" />
+ <el-table-column label="瀹㈡埛濮撳悕" align="center" prop="customerName" />
+ <el-table-column label="瀹㈡埛鎵嬫満" align="center" prop="customerPhone" />
+ <el-table-column label="缁煎悎璇勫垎" align="center" prop="overallScore">
+ <template slot-scope="scope">
+ <el-rate
+ v-model="scope.row.overallScore"
+ disabled
+ show-score
+ text-color="#ff9900"
+ score-template="{value}"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column label="璇勪环鏃堕棿" align="center" prop="evaluationTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.evaluationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-view"
+ @click="handleView(scope.row)"
+ >鏌ョ湅璇︽儏</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 璇勪环璇︽儏瀵硅瘽妗� -->
+ <el-dialog title="璇勪环璇︽儏" :visible.sync="detailOpen" width="600px" append-to-body>
+ <el-descriptions :column="2" border>
+ <el-descriptions-item label="璇勪环ID">{{ detailForm.evaluationId }}</el-descriptions-item>
+ <el-descriptions-item label="杞︾墝鍙�">{{ detailForm.vehicleNo }}</el-descriptions-item>
+ <el-descriptions-item label="瀹㈡埛濮撳悕">{{ detailForm.customerName }}</el-descriptions-item>
+ <el-descriptions-item label="瀹㈡埛鎵嬫満">{{ detailForm.customerPhone }}</el-descriptions-item>
+ <el-descriptions-item label="寰俊鏄电О">{{ detailForm.wechatNickname }}</el-descriptions-item>
+ <el-descriptions-item label="缁煎悎璇勫垎">
+ <el-rate
+ v-model="detailForm.overallScore"
+ disabled
+ show-score
+ text-color="#ff9900"
+ score-template="{value}"
+ />
+ </el-descriptions-item>
+ <el-descriptions-item label="璇勪环鏃堕棿" :span="2">
+ {{ parseTime(detailForm.evaluationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}
+ </el-descriptions-item>
+ </el-descriptions>
+
+ <div style="margin-top: 20px;">
+ <h4>璇︾粏璇勪环</h4>
+ <el-table :data="detailForm.evaluationDetails" border>
+ <el-table-column label="璇勪环缁村害" prop="dimensionName" />
+ <el-table-column label="璇勫垎" align="center">
+ <template slot-scope="scope">
+ <el-rate
+ v-if="scope.row.dimensionType === 'star'"
+ v-model="scope.row.score"
+ disabled
+ show-score
+ text-color="#ff9900"
+ score-template="{value}"
+ />
+ <span v-else>{{ scope.row.optionValue || scope.row.textContent }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listCustomerEvaluation, getCustomerEvaluation } from "@/api/evaluation";
+import * as echarts from 'echarts';
+
+export default {
+ name: "EvaluationStatistics",
+ data() {
+ return {
+ // 閬僵灞�
+ loading: true,
+ // 閫変腑鏁扮粍
+ ids: [],
+ // 闈炲崟涓鐢�
+ single: true,
+ // 闈炲涓鐢�
+ multiple: true,
+ // 鏄剧ず鎼滅储鏉′欢
+ showSearch: true,
+ // 鎬绘潯鏁�
+ total: 0,
+ // 瀹㈡埛璇勪环琛ㄦ牸鏁版嵁
+ evaluationList: [],
+ // 寮瑰嚭灞傛爣棰�
+ title: "",
+ // 鏄惁鏄剧ず寮瑰嚭灞�
+ detailOpen: false,
+ // 鏃ユ湡鑼冨洿
+ dateRange: [],
+ // 鏌ヨ鍙傛暟
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ vehicleNo: null,
+ evaluationTime: null
+ },
+ // 琛ㄥ崟鍙傛暟
+ detailForm: {},
+ // 缁熻鏁版嵁
+ statisticsData: {
+ totalEvaluations: 0,
+ averageScore: 0,
+ goodRate: 0,
+ vehicleCount: 0
+ }
+ };
+ },
+ created() {
+ this.getList();
+ this.getStatistics();
+ },
+ mounted() {
+ this.$nextTick(() => {
+ this.initCharts();
+ });
+ },
+ methods: {
+ /** 鏌ヨ瀹㈡埛璇勪环鍒楄〃 */
+ getList() {
+ this.loading = true;
+ listCustomerEvaluation(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+ this.evaluationList = response.rows;
+ this.total = response.total;
+ this.loading = false;
+ });
+ },
+ /** 鑾峰彇缁熻鏁版嵁 */
+ getStatistics() {
+ // 杩欓噷搴旇璋冪敤缁熻鎺ュ彛锛屾殏鏃朵娇鐢ㄦā鎷熸暟鎹�
+ this.statisticsData = {
+ totalEvaluations: 156,
+ averageScore: 4.2,
+ goodRate: 85.6,
+ vehicleCount: 23
+ };
+ },
+ /** 鍒濆鍖栧浘琛� */
+ initCharts() {
+ this.initScoreChart();
+ this.initTrendChart();
+ this.initDimensionChart();
+ },
+ /** 鍒濆鍖栬瘎鍒嗗垎甯冨浘琛� */
+ initScoreChart() {
+ const chart = echarts.init(this.$refs.scoreChart);
+ const option = {
+ title: {
+ text: '璇勫垎鍒嗗竷',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'item'
+ },
+ series: [
+ {
+ name: '璇勫垎鍒嗗竷',
+ type: 'pie',
+ radius: '50%',
+ data: [
+ { value: 35, name: '5鏄�' },
+ { value: 28, name: '4鏄�' },
+ { value: 20, name: '3鏄�' },
+ { value: 12, name: '2鏄�' },
+ { value: 5, name: '1鏄�' }
+ ],
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
+ }
+ }
+ }
+ ]
+ };
+ chart.setOption(option);
+ },
+ /** 鍒濆鍖栬秼鍔垮浘琛� */
+ initTrendChart() {
+ const chart = echarts.init(this.$refs.trendChart);
+ const option = {
+ title: {
+ text: '鏈堝害璇勪环瓒嬪娍',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'axis'
+ },
+ xAxis: {
+ type: 'category',
+ data: ['1鏈�', '2鏈�', '3鏈�', '4鏈�', '5鏈�', '6鏈�']
+ },
+ yAxis: {
+ type: 'value'
+ },
+ series: [
+ {
+ name: '璇勪环鏁伴噺',
+ type: 'line',
+ data: [12, 19, 23, 18, 25, 28],
+ smooth: true
+ }
+ ]
+ };
+ chart.setOption(option);
+ },
+ /** 鍒濆鍖栫淮搴︾粺璁″浘琛� */
+ initDimensionChart() {
+ const chart = echarts.init(this.$refs.dimensionChart);
+ const option = {
+ title: {
+ text: '鍚勭淮搴﹁瘎鍒嗙粺璁�',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'shadow'
+ }
+ },
+ xAxis: {
+ type: 'category',
+ data: ['鏈嶅姟鎬佸害', '鏀惰垂鎯呭喌', '杞﹁締鍗敓', '椹鹃┒鎶�鏈�', '鏁翠綋鏈嶅姟']
+ },
+ yAxis: {
+ type: 'value',
+ max: 5
+ },
+ series: [
+ {
+ name: '骞冲潎璇勫垎',
+ type: 'bar',
+ data: [4.5, 4.2, 4.3, 4.4, 4.1],
+ itemStyle: {
+ color: '#409EFF'
+ }
+ }
+ ]
+ };
+ chart.setOption(option);
+ },
+ // 鍙栨秷鎸夐挳
+ cancel() {
+ this.detailOpen = false;
+ this.reset();
+ },
+ // 琛ㄥ崟閲嶇疆
+ reset() {
+ this.detailForm = {
+ evaluationId: null,
+ vehicleNo: null,
+ customerName: null,
+ customerPhone: null,
+ wechatOpenid: null,
+ wechatNickname: null,
+ wechatAvatar: null,
+ wechatPhone: null,
+ overallScore: null,
+ evaluationTime: null,
+ evaluationDetails: []
+ };
+ this.resetForm("detailForm");
+ },
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ handleQuery() {
+ this.queryParams.pageNum = 1;
+ this.getList();
+ },
+ /** 閲嶇疆鎸夐挳鎿嶄綔 */
+ resetQuery() {
+ this.dateRange = [];
+ this.resetForm("queryForm");
+ this.handleQuery();
+ },
+ // 澶氶�夋閫変腑鏁版嵁
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.evaluationId)
+ this.single = selection.length!==1
+ this.multiple = !selection.length
+ },
+ /** 鏌ョ湅璇︽儏鎸夐挳鎿嶄綔 */
+ handleView(row) {
+ this.reset();
+ const evaluationId = row.evaluationId || this.ids
+ getCustomerEvaluation(evaluationId).then(response => {
+ this.detailForm = response.data;
+ this.detailOpen = true;
+ this.title = "璇勪环璇︽儏";
+ });
+ }
+ }
+};
+</script>
+
+<style scoped>
+.app-container {
+ padding: 20px;
+}
+
+.card-panel-col {
+ margin-bottom: 20px;
+}
+
+.card-panel {
+ height: 108px;
+ cursor: pointer;
+ font-size: 12px;
+ position: relative;
+ overflow: hidden;
+ color: #666;
+ background: #fff;
+ box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
+ border-color: rgba(0, 0, 0, .05);
+}
+
+.card-panel:hover {
+ box-shadow: 4px 4px 40px rgba(0, 0, 0, .1);
+}
+
+.card-panel-icon-wrapper {
+ float: left;
+ margin: 14px 0 0 14px;
+ padding: 16px;
+ transition: all 0.38s ease-out;
+ border-radius: 6px;
+}
+
+.card-panel-icon {
+ float: left;
+ font-size: 48px;
+}
+
+.card-panel-description {
+ float: right;
+ font-weight: bold;
+ margin: 26px;
+ margin-left: 0px;
+}
+
+.card-panel-text {
+ line-height: 18px;
+ color: rgba(0, 0, 0, 0.45);
+ font-size: 16px;
+ margin-bottom: 12px;
+}
+
+.card-panel-num {
+ font-size: 20px;
+ color: #666;
+}
+
+.icon-people {
+ color: #40c9c6;
+}
+
+.icon-message {
+ color: #36a3f7;
+}
+
+.icon-star {
+ color: #f4516c;
+}
+
+.icon-vehicle {
+ color: #34bfa3;
+}
+
+.chart-container {
+ background: #fff;
+ padding: 20px;
+ border-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ margin-bottom: 20px;
+}
+
+.chart-title {
+ font-size: 16px;
+ font-weight: bold;
+ margin-bottom: 15px;
+ text-align: center;
+}
+
+.chart {
+ height: 300px;
+ width: 100%;
+}
+</style>
diff --git a/ruoyi-ui/src/views/evaluation/test.vue b/ruoyi-ui/src/views/evaluation/test.vue
new file mode 100644
index 0000000..1979444
--- /dev/null
+++ b/ruoyi-ui/src/views/evaluation/test.vue
@@ -0,0 +1,187 @@
+<template>
+ <div class="test-container">
+ <h2>瀹㈡埛婊℃剰搴﹁瘎浠峰姛鑳芥祴璇�</h2>
+
+ <div class="test-section">
+ <h3>1. 鐢熸垚浜岀淮鐮佹祴璇�</h3>
+ <el-form :inline="true">
+ <el-form-item label="杞︾墝鍙�">
+ <el-input v-model="testVehicleNo" placeholder="璇疯緭鍏ヨ溅鐗屽彿" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="generateQrcode">鐢熸垚浜岀淮鐮�</el-button>
+ </el-form-item>
+ </el-form>
+
+ <div v-if="qrcodeInfo" class="qrcode-result">
+ <p><strong>浜岀淮鐮乁RL:</strong> {{ qrcodeInfo.qrcodeUrl }}</p>
+ <p><strong>浜岀淮鐮佸唴瀹�:</strong> {{ qrcodeInfo.qrcodeContent }}</p>
+ <p><strong>浜岀淮鐮佸浘鐗�:</strong> {{ qrcodeInfo.qrcodeImage }}</p>
+ </div>
+ </div>
+
+ <div class="test-section">
+ <h3>2. 璇勪环缁村害閰嶇疆娴嬭瘯</h3>
+ <el-button type="primary" @click="loadDimensions">鍔犺浇璇勪环缁村害</el-button>
+
+ <div v-if="dimensions.length > 0" class="dimensions-result">
+ <h4>璇勪环缁村害鍒楄〃:</h4>
+ <ul>
+ <li v-for="dimension in dimensions" :key="dimension.dimensionId">
+ {{ dimension.dimensionName }} - {{ dimension.dimensionType }}
+ <span v-if="dimension.isRequired === '1'">(蹇呭~)</span>
+ </li>
+ </ul>
+ </div>
+ </div>
+
+ <div class="test-section">
+ <h3>3. 璇勪环鎻愪氦娴嬭瘯</h3>
+ <el-form :model="testEvaluation" label-width="100px">
+ <el-form-item label="杞︾墝鍙�">
+ <el-input v-model="testEvaluation.vehicleNo" />
+ </el-form-item>
+ <el-form-item label="瀹㈡埛濮撳悕">
+ <el-input v-model="testEvaluation.customerName" />
+ </el-form-item>
+ <el-form-item label="瀹㈡埛鎵嬫満">
+ <el-input v-model="testEvaluation.customerPhone" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" @click="submitTestEvaluation">鎻愪氦娴嬭瘯璇勪环</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <div class="test-section">
+ <h3>4. 鐩存帴璁块棶璇勪环椤甸潰</h3>
+ <p>璁块棶鍦板潃: <a :href="evaluationUrl" target="_blank">{{ evaluationUrl }}</a></p>
+ </div>
+ </div>
+</template>
+
+<script>
+import { generateQrcode, getEvaluationDimensions, submitEvaluation } from "@/api/evaluation";
+
+export default {
+ name: "EvaluationTest",
+ data() {
+ return {
+ testVehicleNo: "绮12345",
+ qrcodeInfo: null,
+ dimensions: [],
+ testEvaluation: {
+ vehicleNo: "绮12345",
+ customerName: "娴嬭瘯鐢ㄦ埛",
+ customerPhone: "13800138000",
+ evaluationDetails: [
+ {
+ dimensionId: 1,
+ score: 5
+ },
+ {
+ dimensionId: 2,
+ score: 4
+ },
+ {
+ dimensionId: 3,
+ score: 5
+ },
+ {
+ dimensionId: 4,
+ score: 4
+ }
+ ]
+ }
+ };
+ },
+ computed: {
+ evaluationUrl() {
+ return `${window.location.origin}/evaluation?vehicle=${this.testVehicleNo}`;
+ }
+ },
+ methods: {
+ async generateQrcode() {
+ try {
+ const response = await generateQrcode(this.testVehicleNo);
+ if (response.code === 200) {
+ this.qrcodeInfo = response.data;
+ this.$message.success("浜岀淮鐮佺敓鎴愭垚鍔�");
+ } else {
+ this.$message.error(response.msg || "鐢熸垚澶辫触");
+ }
+ } catch (error) {
+ console.error("鐢熸垚浜岀淮鐮佸け璐�:", error);
+ this.$message.error("鐢熸垚浜岀淮鐮佸け璐�");
+ }
+ },
+
+ async loadDimensions() {
+ try {
+ const response = await getEvaluationDimensions();
+ if (response.code === 200) {
+ this.dimensions = response.data;
+ this.$message.success("璇勪环缁村害鍔犺浇鎴愬姛");
+ } else {
+ this.$message.error(response.msg || "鍔犺浇澶辫触");
+ }
+ } catch (error) {
+ console.error("鍔犺浇璇勪环缁村害澶辫触:", error);
+ this.$message.error("鍔犺浇璇勪环缁村害澶辫触");
+ }
+ },
+
+ async submitTestEvaluation() {
+ try {
+ const response = await submitEvaluation(this.testEvaluation);
+ if (response.code === 200) {
+ this.$message.success(response.msg || "璇勪环鎻愪氦鎴愬姛");
+ } else {
+ this.$message.error(response.msg || "鎻愪氦澶辫触");
+ }
+ } catch (error) {
+ console.error("鎻愪氦璇勪环澶辫触:", error);
+ this.$message.error("鎻愪氦璇勪环澶辫触");
+ }
+ }
+ }
+};
+</script>
+
+<style scoped>
+.test-container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+.test-section {
+ margin-bottom: 30px;
+ padding: 20px;
+ border: 1px solid #e4e7ed;
+ border-radius: 6px;
+ background-color: #fafafa;
+}
+
+.test-section h3 {
+ margin-top: 0;
+ color: #333;
+}
+
+.qrcode-result, .dimensions-result {
+ margin-top: 15px;
+ padding: 15px;
+ background-color: white;
+ border-radius: 4px;
+ border: 1px solid #e4e7ed;
+}
+
+.dimensions-result ul {
+ margin: 10px 0;
+ padding-left: 20px;
+}
+
+.dimensions-result li {
+ margin-bottom: 5px;
+}
+</style>
diff --git a/ruoyi-ui/src/views/system/vehicle/index.vue b/ruoyi-ui/src/views/system/vehicle/index.vue
index 4ec9201..6710c5d 100644
--- a/ruoyi-ui/src/views/system/vehicle/index.vue
+++ b/ruoyi-ui/src/views/system/vehicle/index.vue
@@ -39,6 +39,16 @@
/>
</el-select>
</el-form-item>
+ <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId">
+ <el-select v-model="queryParams.deptId" placeholder="璇烽�夋嫨閮ㄩ棬" clearable size="small">
+ <el-option
+ v-for="dept in deptOptions"
+ :key="dept.deptId"
+ :label="dept.deptName"
+ :value="dept.deptId"
+ />
+ </el-select>
+ </el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
@@ -103,6 +113,7 @@
<dict-tag :options="dict.type.sys_platform" :value="scope.row.platformCode"/>
</template>
</el-table-column>
+ <el-table-column label="褰掑睘閮ㄩ棬" align="center" prop="deptName" />
<el-table-column label="鐘舵��" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
@@ -166,6 +177,16 @@
/>
</el-select>
</el-form-item>
+ <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId">
+ <el-select v-model="form.deptId" placeholder="璇烽�夋嫨閮ㄩ棬" clearable>
+ <el-option
+ v-for="dept in deptOptions"
+ :key="dept.deptId"
+ :label="dept.deptName"
+ :value="dept.deptId"
+ />
+ </el-select>
+ </el-form-item>
<el-form-item label="鐘舵��" prop="status">
<el-radio-group v-model="form.status">
<el-radio
@@ -189,6 +210,7 @@
<script>
import { listVehicle, getVehicle, delVehicle, addVehicle, updateVehicle } from "@/api/system/vehicle";
+import { listDept } from "@/api/system/dept";
export default {
name: "Vehicle",
@@ -209,6 +231,8 @@
total: 0,
// 杞﹁締淇℃伅琛ㄦ牸鏁版嵁
vehicleList: [],
+ // 閮ㄩ棬閫夐」
+ deptOptions: [],
// 寮瑰嚭灞傛爣棰�
title: "",
// 鏄惁鏄剧ず寮瑰嚭灞�
@@ -222,7 +246,8 @@
vehicleBrand: null,
vehicleModel: null,
status: null,
- platformCode: null
+ platformCode: null,
+ deptId: null
},
// 琛ㄥ崟鍙傛暟
form: {
@@ -233,7 +258,8 @@
vehicleModel: null,
status: "0",
remark: null,
- platformCode: null
+ platformCode: null,
+ deptId: null
},
// 琛ㄥ崟鏍¢獙
rules: {
@@ -245,12 +271,16 @@
],
platformCode: [
{ required: true, message: "骞冲彴鏍囪瘑涓嶈兘涓虹┖", trigger: "change" }
+ ],
+ deptId: [
+ { required: true, message: "褰掑睘閮ㄩ棬涓嶈兘涓虹┖", trigger: "change" }
]
}
};
},
created() {
this.getList();
+ this.getDeptList();
},
methods: {
/** 鏌ヨ杞﹁締淇℃伅鍒楄〃 */
@@ -260,6 +290,12 @@
this.vehicleList = response.rows;
this.total = response.total;
this.loading = false;
+ });
+ },
+ /** 鏌ヨ閮ㄩ棬鍒楄〃 */
+ getDeptList() {
+ listDept().then(response => {
+ this.deptOptions = response.data;
});
},
// 鍙栨秷鎸夐挳
@@ -277,7 +313,8 @@
vehicleModel: null,
status: "0",
remark: null,
- platformCode: null
+ platformCode: null,
+ deptId: null
};
this.resetForm("form");
},
diff --git a/sql/customer_evaluation_tables.sql b/sql/customer_evaluation_tables.sql
new file mode 100644
index 0000000..cd83baf
--- /dev/null
+++ b/sql/customer_evaluation_tables.sql
@@ -0,0 +1,100 @@
+-- 瀹㈡埛婊℃剰搴﹁瘎浠峰姛鑳芥暟鎹簱琛ㄧ粨鏋�
+-- 鍒涘缓鏃堕棿: 2025-01-27
+
+-- 1. 璇勪环缁村害閰嶇疆琛�
+DROP TABLE IF EXISTS `evaluation_dimension`;
+CREATE TABLE `evaluation_dimension` (
+ `dimension_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '缁村害ID',
+ `dimension_name` varchar(100) NOT NULL COMMENT '缁村害鍚嶇О',
+ `dimension_desc` varchar(500) DEFAULT NULL COMMENT '缁村害鎻忚堪',
+ `dimension_type` varchar(20) NOT NULL DEFAULT 'star' COMMENT '缁村害绫诲瀷锛歴tar-鏄熺骇璇勪环锛宻elect-閫夋嫨璇勪环锛宼ext-鏂囨湰璇勪环',
+ `options` text COMMENT '閫夐」閰嶇疆锛圝SON鏍煎紡锛岀敤浜庨�夋嫨绫诲瀷锛�',
+ `sort_order` int(11) DEFAULT 0 COMMENT '鎺掑簭',
+ `is_required` char(1) DEFAULT '1' COMMENT '鏄惁蹇呭~锛�0鍚� 1鏄級',
+ `status` char(1) DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `create_by` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+ `update_by` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+ `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+ PRIMARY KEY (`dimension_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='璇勪环缁村害閰嶇疆琛�';
+
+-- 2. 瀹㈡埛璇勪环琛�
+DROP TABLE IF EXISTS `customer_evaluation`;
+CREATE TABLE `customer_evaluation` (
+ `evaluation_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '璇勪环ID',
+ `vehicle_no` varchar(20) NOT NULL COMMENT '杞︾墝鍙�',
+ `customer_name` varchar(50) NOT NULL COMMENT '瀹㈡埛濮撳悕',
+ `customer_phone` varchar(20) NOT NULL COMMENT '瀹㈡埛鎵嬫満鍙�',
+ `wechat_openid` varchar(100) DEFAULT NULL COMMENT '寰俊OpenID',
+ `wechat_nickname` varchar(100) DEFAULT NULL COMMENT '寰俊鏄电О',
+ `wechat_avatar` varchar(500) DEFAULT NULL COMMENT '寰俊澶村儚',
+ `wechat_phone` varchar(20) DEFAULT NULL COMMENT '寰俊缁戝畾鎵嬫満鍙�',
+ `total_score` decimal(3,1) DEFAULT NULL COMMENT '鎬昏瘎鍒�',
+ `evaluation_status` char(1) DEFAULT '0' COMMENT '璇勪环鐘舵�侊紙0寰呰瘎浠� 1宸茶瘎浠凤級',
+ `evaluation_time` datetime DEFAULT NULL COMMENT '璇勪环鏃堕棿',
+ `ip_address` varchar(128) DEFAULT NULL COMMENT 'IP鍦板潃',
+ `user_agent` varchar(500) DEFAULT NULL COMMENT '鐢ㄦ埛浠g悊',
+ `create_time` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+ `update_time` datetime DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+ `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+ PRIMARY KEY (`evaluation_id`),
+ KEY `idx_vehicle_no` (`vehicle_no`),
+ KEY `idx_customer_phone` (`customer_phone`),
+ KEY `idx_wechat_openid` (`wechat_openid`),
+ KEY `idx_evaluation_time` (`evaluation_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='瀹㈡埛璇勪环琛�';
+
+-- 3. 璇勪环璇︽儏琛�
+DROP TABLE IF EXISTS `evaluation_detail`;
+CREATE TABLE `evaluation_detail` (
+ `detail_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '璇︽儏ID',
+ `evaluation_id` bigint(20) NOT NULL COMMENT '璇勪环ID',
+ `dimension_id` bigint(20) NOT NULL COMMENT '缁村害ID',
+ `score` int(11) DEFAULT NULL COMMENT '璇勫垎锛�1-5鏄燂級',
+ `option_value` varchar(100) DEFAULT NULL COMMENT '閫夐」鍊硷紙閫夋嫨绫诲瀷鏃朵娇鐢級',
+ `text_content` text COMMENT '鏂囨湰鍐呭锛堟枃鏈被鍨嬫椂浣跨敤锛�',
+ `create_time` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+ PRIMARY KEY (`detail_id`),
+ KEY `idx_evaluation_id` (`evaluation_id`),
+ KEY `idx_dimension_id` (`dimension_id`),
+ CONSTRAINT `fk_evaluation_detail_evaluation` FOREIGN KEY (`evaluation_id`) REFERENCES `customer_evaluation` (`evaluation_id`) ON DELETE CASCADE,
+ CONSTRAINT `fk_evaluation_detail_dimension` FOREIGN KEY (`dimension_id`) REFERENCES `evaluation_dimension` (`dimension_id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='璇勪环璇︽儏琛�';
+
+-- 4. 杞﹁締璇勪环浜岀淮鐮佽〃
+DROP TABLE IF EXISTS `vehicle_evaluation_qrcode`;
+CREATE TABLE `vehicle_evaluation_qrcode` (
+ `qrcode_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '浜岀淮鐮両D',
+ `vehicle_no` varchar(20) NOT NULL COMMENT '杞︾墝鍙�',
+ `qrcode_url` varchar(500) NOT NULL COMMENT '浜岀淮鐮乁RL',
+ `qrcode_content` varchar(500) NOT NULL COMMENT '浜岀淮鐮佸唴瀹�',
+ `qrcode_image` varchar(8000) DEFAULT NULL COMMENT '浜岀淮鐮佸浘鐗�(base64鏍煎紡)',
+ `status` char(1) DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `create_by` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+ `update_by` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+ `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
+ PRIMARY KEY (`qrcode_id`),
+ UNIQUE KEY `uk_vehicle_no` (`vehicle_no`),
+ KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='杞﹁締璇勪环浜岀淮鐮佽〃';
+
+-- 鎻掑叆榛樿璇勪环缁村害鏁版嵁
+INSERT INTO `evaluation_dimension` (`dimension_name`, `dimension_desc`, `dimension_type`, `sort_order`, `is_required`, `status`, `create_by`, `create_time`, `remark`) VALUES
+('鏈嶅姟鎬佸害', '鍙告満鏈嶅姟鎬佸害璇勪环', 'star', 1, '1', '0', 'admin', NOW(), '鍙告満鏈嶅姟鎬佸害鏄惁鍙嬪ソ銆佷笓涓�'),
+('鏀惰垂鎯呭喌', '鏀惰垂鏄惁鍚堢悊閫忔槑', 'star', 2, '1', '0', 'admin', NOW(), '鏀惰垂鏄惁鍚堢悊銆侀�忔槑锛屾湁鏃犱贡鏀惰垂鐜拌薄'),
+('杞﹁締鍗敓鐘跺喌', '杞﹁締鍐呴儴鍗敓鎯呭喌', 'star', 3, '1', '0', 'admin', NOW(), '杞﹁締鍐呴儴鏄惁骞插噣鏁存磥'),
+('鏁翠綋婊℃剰搴�', '鏁翠綋鏈嶅姟婊℃剰搴�', 'star', 4, '1', '0', 'admin', NOW(), '瀵规暣浣撴湇鍔$殑婊℃剰搴﹁瘎浠�'),
+('鍏朵粬寤鸿', '鍏朵粬鎰忚鎴栧缓璁�', 'text', 5, '0', '0', 'admin', NOW(), '瀹㈡埛鐨勫叾浠栨剰瑙佹垨寤鸿');
+
+-- 涓虹幇鏈夎溅杈嗙敓鎴愯瘎浠蜂簩缁寸爜锛堢ず渚嬫暟鎹級
+-- 娉ㄦ剰锛氬疄闄呬娇鐢ㄦ椂闇�瑕佹牴鎹湡瀹炵殑杞﹁締鏁版嵁鏉ョ敓鎴�
+-- INSERT INTO `vehicle_evaluation_qrcode` (`vehicle_no`, `qrcode_url`, `qrcode_content`, `status`, `create_by`, `create_time`)
+-- SELECT vehicle_no, CONCAT('https://yourdomain.com/evaluation?vehicle=', vehicle_no), CONCAT('EVAL:', vehicle_no), '0', 'admin', NOW()
+-- FROM tb_vehicle_info WHERE status = '0';
+
+-- 淇敼qrcode_image瀛楁闀垮害浠ユ敮鎸乥ase64鏍煎紡瀛樺偍
+ALTER TABLE `vehicle_evaluation_qrcode` MODIFY COLUMN `qrcode_image` varchar(8000) DEFAULT NULL COMMENT '浜岀淮鐮佸浘鐗�(base64鏍煎紡)';
diff --git a/sql/evaluation_dict.sql b/sql/evaluation_dict.sql
new file mode 100644
index 0000000..31e8b2e
--- /dev/null
+++ b/sql/evaluation_dict.sql
@@ -0,0 +1,26 @@
+-- 瀹㈡埛婊℃剰搴﹁瘎浠峰姛鑳藉瓧鍏告暟鎹�
+
+-- 璇勪环鐘舵�佸瓧鍏哥被鍨�
+INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
+VALUES ('璇勪环鐘舵��', 'evaluation_status', '0', 'admin', sysdate(), '瀹㈡埛璇勪环鐘舵�佸垪琛�');
+
+-- 璇勪环鐘舵�佸瓧鍏告暟鎹�
+INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
+VALUES (1, '寰呰瘎浠�', '0', 'evaluation_status', '', 'info', 'Y', '0', 'admin', sysdate(), '寰呰瘎浠风姸鎬�');
+
+INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
+VALUES (2, '宸茶瘎浠�', '1', 'evaluation_status', '', 'success', 'N', '0', 'admin', sysdate(), '宸茶瘎浠风姸鎬�');
+
+-- 璇勪环缁村害绫诲瀷瀛楀吀绫诲瀷
+INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
+VALUES ('璇勪环缁村害绫诲瀷', 'dimension_type', '0', 'admin', sysdate(), '璇勪环缁村害绫诲瀷鍒楄〃');
+
+-- 璇勪环缁村害绫诲瀷瀛楀吀鏁版嵁
+INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
+VALUES (1, '鏄熺骇璇勪环', 'star', 'dimension_type', '', 'primary', 'Y', '0', 'admin', sysdate(), '鏄熺骇璇勪环绫诲瀷');
+
+INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
+VALUES (2, '閫夋嫨璇勪环', 'select', 'dimension_type', '', 'success', 'N', '0', 'admin', sysdate(), '閫夋嫨璇勪环绫诲瀷');
+
+INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
+VALUES (3, '鏂囨湰璇勪环', 'text', 'dimension_type', '', 'warning', 'N', '0', 'admin', sysdate(), '鏂囨湰璇勪环绫诲瀷');
diff --git a/sql/evaluation_menu.sql b/sql/evaluation_menu.sql
new file mode 100644
index 0000000..7c830d8
--- /dev/null
+++ b/sql/evaluation_menu.sql
@@ -0,0 +1,79 @@
+-- 瀹㈡埛婊℃剰搴﹁瘎浠风鐞嗚彍鍗� SQL
+
+-- 1. 璇勪环绠$悊涓昏彍鍗�
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('璇勪环绠$悊', '0', '6', 'evaluation', null, 1, 0, 'M', '0', '0', null, 'star', 'admin', sysdate(), '', null, '瀹㈡埛婊℃剰搴﹁瘎浠风鐞嗙洰褰�');
+
+-- 鑾峰彇璇勪环绠$悊涓昏彍鍗旾D
+SELECT @evaluationParentId := LAST_INSERT_ID();
+
+-- 2. 瀹㈡埛璇勪环鑿滃崟
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('瀹㈡埛璇勪环', @evaluationParentId, '1', 'customer', 'evaluation/customer/index', 1, 0, 'C', '0', '0', 'evaluation:customer:list', 'message', 'admin', sysdate(), '', null, '瀹㈡埛璇勪环鑿滃崟');
+
+-- 鑾峰彇瀹㈡埛璇勪环鑿滃崟ID
+SELECT @customerParentId := LAST_INSERT_ID();
+
+-- 瀹㈡埛璇勪环鎸夐挳鏉冮檺
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('瀹㈡埛璇勪环鏌ヨ', @customerParentId, '1', '#', '', 1, 0, 'F', '0', '0', 'evaluation:customer:query', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('瀹㈡埛璇勪环鍒犻櫎', @customerParentId, '2', '#', '', 1, 0, 'F', '0', '0', 'evaluation:customer:remove', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('瀹㈡埛璇勪环瀵煎嚭', @customerParentId, '3', '#', '', 1, 0, 'F', '0', '0', 'evaluation:customer:export', '#', 'admin', sysdate(), '', null, '');
+
+-- 3. 璇勪环缁村害閰嶇疆鑿滃崟
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('璇勪环缁村害', @evaluationParentId, '2', 'dimension', 'evaluation/dimension/index', 1, 0, 'C', '0', '0', 'evaluation:dimension:list', 'edit', 'admin', sysdate(), '', null, '璇勪环缁村害閰嶇疆鑿滃崟');
+
+-- 鑾峰彇璇勪环缁村害鑿滃崟ID
+SELECT @dimensionParentId := LAST_INSERT_ID();
+
+-- 璇勪环缁村害鎸夐挳鏉冮檺
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('璇勪环缁村害鏌ヨ', @dimensionParentId, '1', '#', '', 1, 0, 'F', '0', '0', 'evaluation:dimension:query', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('璇勪环缁村害鏂板', @dimensionParentId, '2', '#', '', 1, 0, 'F', '0', '0', 'evaluation:dimension:add', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('璇勪环缁村害淇敼', @dimensionParentId, '3', '#', '', 1, 0, 'F', '0', '0', 'evaluation:dimension:edit', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('璇勪环缁村害鍒犻櫎', @dimensionParentId, '4', '#', '', 1, 0, 'F', '0', '0', 'evaluation:dimension:remove', '#', 'admin', sysdate(), '', null, '');
+
+-- 4. 杞﹁締浜岀淮鐮佺鐞嗚彍鍗�
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('杞﹁締浜岀淮鐮�', @evaluationParentId, '3', 'qrcode', 'evaluation/qrcode/index', 1, 0, 'C', '0', '0', 'evaluation:qrcode:list', 'qrcode', 'admin', sysdate(), '', null, '杞﹁締璇勪环浜岀淮鐮佺鐞嗚彍鍗�');
+
+-- 鑾峰彇杞﹁締浜岀淮鐮佽彍鍗旾D
+SELECT @qrcodeParentId := LAST_INSERT_ID();
+
+-- 杞﹁締浜岀淮鐮佹寜閽潈闄�
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('浜岀淮鐮佹煡璇�', @qrcodeParentId, '1', '#', '', 1, 0, 'F', '0', '0', 'evaluation:qrcode:query', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('浜岀淮鐮佺敓鎴�', @qrcodeParentId, '2', '#', '', 1, 0, 'F', '0', '0', 'evaluation:qrcode:generate', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('鎵归噺鐢熸垚', @qrcodeParentId, '3', '#', '', 1, 0, 'F', '0', '0', 'evaluation:qrcode:batch', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('浜岀淮鐮佸垹闄�', @qrcodeParentId, '4', '#', '', 1, 0, 'F', '0', '0', 'evaluation:qrcode:remove', '#', 'admin', sysdate(), '', null, '');
+
+-- 5. 璇勪环缁熻鑿滃崟
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('璇勪环缁熻', @evaluationParentId, '4', 'statistics', 'evaluation/statistics/index', 1, 0, 'C', '0', '0', 'evaluation:statistics:list', 'chart', 'admin', sysdate(), '', null, '璇勪环缁熻鍒嗘瀽鑿滃崟');
+
+-- 鑾峰彇璇勪环缁熻鑿滃崟ID
+SELECT @statisticsParentId := LAST_INSERT_ID();
+
+-- 璇勪环缁熻鎸夐挳鏉冮檺
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('缁熻鏌ヨ', @statisticsParentId, '1', '#', '', 1, 0, 'F', '0', '0', 'evaluation:statistics:query', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('缁熻瀵煎嚭', @statisticsParentId, '2', '#', '', 1, 0, 'F', '0', '0', 'evaluation:statistics:export', '#', 'admin', sysdate(), '', null, '');
diff --git a/sql/vehicle_info.sql b/sql/vehicle_info.sql
index 6434538..2216aca 100644
--- a/sql/vehicle_info.sql
+++ b/sql/vehicle_info.sql
@@ -20,4 +20,7 @@
ALTER TABLE tb_vehicle_info ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '璁惧ID';
-- 鍦╰b_vehicle_gps琛ㄤ腑娣诲姞device_id瀛楁
-ALTER TABLE tb_vehicle_gps ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '璁惧ID';
\ No newline at end of file
+ALTER TABLE tb_vehicle_gps ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '璁惧ID';
+
+-- 鍦╰b_vehicle_info琛ㄤ腑娣诲姞dept_id瀛楁
+ALTER TABLE tb_vehicle_info ADD COLUMN dept_id BIGINT(20) DEFAULT NULL COMMENT '褰掑睘閮ㄩ棬ID';
\ No newline at end of file
diff --git "a/\345\256\214\346\225\264\351\203\250\347\275\262\346\214\207\345\215\227.md" "b/\345\256\214\346\225\264\351\203\250\347\275\262\346\214\207\345\215\227.md"
new file mode 100644
index 0000000..3716968
--- /dev/null
+++ "b/\345\256\214\346\225\264\351\203\250\347\275\262\346\214\207\345\215\227.md"
@@ -0,0 +1,225 @@
+# 瀹㈡埛婊℃剰搴﹁瘎浠峰姛鑳藉畬鏁撮儴缃叉寚鍗�
+
+## 馃搵 閮ㄧ讲娓呭崟
+
+### 1. 鏁版嵁搴撹剼鏈墽琛岄『搴�
+```sql
+-- 1. 鎵ц鏁版嵁搴撹〃缁撴瀯
+source sql/customer_evaluation_tables.sql
+
+-- 2. 鎵ц鑿滃崟閰嶇疆
+source sql/evaluation_menu.sql
+
+-- 3. 鎵ц瀛楀吀閰嶇疆
+source sql/evaluation_dict.sql
+```
+
+### 2. 鍚庣閰嶇疆
+
+#### 2.1 寰俊閰嶇疆锛堝彲閫夛級
+鍦� `ruoyi-admin/src/main/resources/application.yml` 涓厤缃細
+```yaml
+wechat:
+ appId: your_wechat_appid
+ appSecret: your_wechat_appsecret
+ redirectUri: http://yourdomain.com/evaluation
+```
+
+#### 2.2 鏂囦欢涓婁紶璺緞閰嶇疆
+纭繚 `ruoyi.profile` 閰嶇疆鐨勮矾寰勬湁鍐欏叆鏉冮檺锛�
+```yaml
+ruoyi:
+ profile: /path/to/upload
+```
+
+### 3. 鍓嶇閰嶇疆
+
+#### 3.1 璺敱閰嶇疆
+宸插湪 `ruoyi-ui/src/router/index.js` 涓坊鍔犺瘎浠风浉鍏宠矾鐢便��
+
+#### 3.2 椤甸潰缁勪欢
+宸插垱寤轰互涓嬮〉闈㈢粍浠讹細
+- `ruoyi-ui/src/views/evaluation/index.vue` - 瀹㈡埛璇勪环椤甸潰
+- `ruoyi-ui/src/views/evaluation/test.vue` - 娴嬭瘯椤甸潰
+- `ruoyi-ui/src/views/evaluation/customer/index.vue` - 瀹㈡埛璇勪环绠$悊
+- `ruoyi-ui/src/views/evaluation/dimension/index.vue` - 璇勪环缁村害閰嶇疆
+- `ruoyi-ui/src/views/evaluation/qrcode/index.vue` - 杞﹁締浜岀淮鐮佺鐞�
+
+## 馃殌 閮ㄧ讲姝ラ
+
+### 姝ラ1锛氭墽琛屾暟鎹簱鑴氭湰
+```bash
+# 杩炴帴鏁版嵁搴�
+mysql -u username -p database_name
+
+# 鎵ц鑴氭湰
+source sql/customer_evaluation_tables.sql
+source sql/evaluation_menu.sql
+source sql/evaluation_dict.sql
+```
+
+### 姝ラ2锛氱紪璇戝悗绔」鐩�
+```bash
+# 鍦ㄩ」鐩牴鐩綍鎵ц
+mvn clean install
+```
+
+### 姝ラ3锛氬惎鍔ㄥ悗绔湇鍔�
+```bash
+cd ruoyi-admin
+mvn spring-boot:run
+```
+
+### 姝ラ4锛氱紪璇戝墠绔」鐩�
+```bash
+cd ruoyi-ui
+npm install
+npm run dev
+```
+
+## 馃И 鍔熻兘娴嬭瘯
+
+### 1. 璁块棶绠$悊鐣岄潰
+- 鐧诲綍绯荤粺鍚庯紝鍦ㄥ乏渚ц彍鍗曚腑鍙互鐪嬪埌"璇勪环绠$悊"鑿滃崟
+- 鍖呭惈浠ヤ笅瀛愯彍鍗曪細
+ - 瀹㈡埛璇勪环
+ - 璇勪环缁村害
+ - 杞﹁締浜岀淮鐮�
+ - 璇勪环缁熻
+
+### 2. 娴嬭瘯璇勪环鍔熻兘
+- 璁块棶锛歚http://localhost:80/evaluation/test`
+- 娴嬭瘯浜岀淮鐮佺敓鎴愩�佽瘎浠风淮搴﹀姞杞姐�佽瘎浠锋彁浜ょ瓑鍔熻兘
+
+### 3. 娴嬭瘯璇勪环椤甸潰
+- 璁块棶锛歚http://localhost:80/evaluation?vehicle=绮12345`
+- 濉啓璇勪环淇℃伅骞舵彁浜�
+
+## 馃摫 寰俊閰嶇疆锛堢敓浜х幆澧冿級
+
+### 1. 寰俊鍏紬骞冲彴閰嶇疆
+1. 鐧诲綍寰俊鍏紬骞冲彴
+2. 杩涘叆"寮�鍙�" -> "鎺ュ彛鏉冮檺"
+3. 閰嶇疆缃戦〉鎺堟潈鍩熷悕锛歚yourdomain.com`
+4. 閰嶇疆JS鎺ュ彛瀹夊叏鍩熷悕锛歚yourdomain.com`
+
+### 2. 鍩熷悕閰嶇疆
+- 纭繚鍩熷悕宸插妗�
+- 閰嶇疆HTTPS璇佷功
+- 鏇存柊閰嶇疆鏂囦欢涓殑鍩熷悕
+
+## 馃敡 鏉冮檺閰嶇疆
+
+### 1. 瑙掕壊鏉冮檺
+绯荤粺绠$悊鍛橀渶瑕佷负鐩稿叧瑙掕壊鍒嗛厤浠ヤ笅鏉冮檺锛�
+- `evaluation:customer:list` - 瀹㈡埛璇勪环鏌ヨ
+- `evaluation:customer:remove` - 瀹㈡埛璇勪环鍒犻櫎
+- `evaluation:customer:export` - 瀹㈡埛璇勪环瀵煎嚭
+- `evaluation:dimension:list` - 璇勪环缁村害鏌ヨ
+- `evaluation:dimension:add` - 璇勪环缁村害鏂板
+- `evaluation:dimension:edit` - 璇勪环缁村害淇敼
+- `evaluation:dimension:remove` - 璇勪环缁村害鍒犻櫎
+- `evaluation:qrcode:list` - 浜岀淮鐮佹煡璇�
+- `evaluation:qrcode:generate` - 浜岀淮鐮佺敓鎴�
+- `evaluation:qrcode:batch` - 鎵归噺鐢熸垚浜岀淮鐮�
+- `evaluation:qrcode:remove` - 浜岀淮鐮佸垹闄�
+
+### 2. 鑿滃崟鏉冮檺
+鑿滃崟鏉冮檺宸查�氳繃SQL鑴氭湰鑷姩閰嶇疆銆�
+
+## 馃搳 鏁版嵁楠岃瘉
+
+### 1. 妫�鏌ユ暟鎹簱琛�
+```sql
+-- 妫�鏌ヨ〃鏄惁鍒涘缓鎴愬姛
+SHOW TABLES LIKE '%evaluation%';
+
+-- 妫�鏌ヨ彍鍗曟槸鍚︽坊鍔犳垚鍔�
+SELECT * FROM sys_menu WHERE menu_name LIKE '%璇勪环%';
+
+-- 妫�鏌ュ瓧鍏告槸鍚︽坊鍔犳垚鍔�
+SELECT * FROM sys_dict_type WHERE dict_type IN ('evaluation_status', 'dimension_type');
+```
+
+### 2. 妫�鏌ラ粯璁ゆ暟鎹�
+```sql
+-- 妫�鏌ヨ瘎浠风淮搴﹂粯璁ゆ暟鎹�
+SELECT * FROM evaluation_dimension;
+
+-- 搴旇鐪嬪埌5鏉¢粯璁よ瘎浠风淮搴︽暟鎹�
+```
+
+## 馃悰 甯歌闂
+
+### 1. 鑿滃崟涓嶆樉绀�
+**鍘熷洜**锛氬彲鑳芥槸鏉冮檺闂鎴栬彍鍗曟暟鎹湭姝g‘鎻掑叆
+**瑙e喅**锛�
+- 妫�鏌ョ敤鎴疯鑹叉潈闄�
+- 閲嶆柊鎵ц鑿滃崟SQL鑴氭湰
+- 娓呴櫎娴忚鍣ㄧ紦瀛�
+
+### 2. 浜岀淮鐮佺敓鎴愬け璐�
+**鍘熷洜**锛氭枃浠惰矾寰勬潈闄愰棶棰�
+**瑙e喅**锛�
+- 妫�鏌� `ruoyi.profile` 閰嶇疆鐨勮矾寰�
+- 纭繚鐩綍鏈夊啓鍏ユ潈闄�
+- 妫�鏌ョ鐩樼┖闂�
+
+### 3. 璇勪环鎻愪氦澶辫触
+**鍘熷洜**锛氬彲鑳芥槸蹇呭~瀛楁楠岃瘉澶辫触
+**瑙e喅**锛�
+- 妫�鏌ヨ瘎浠风淮搴﹂厤缃�
+- 纭繚鎵�鏈夊繀濉瓧娈甸兘宸插~鍐�
+- 鏌ョ湅鍚庣鏃ュ織
+
+### 4. 寰俊鎺堟潈澶辫触
+**鍘熷洜**锛氬井淇¢厤缃棶棰�
+**瑙e喅**锛�
+- 妫�鏌ppID鍜孉ppSecret閰嶇疆
+- 纭鍩熷悕閰嶇疆姝g‘
+- 妫�鏌TTPS璇佷功
+
+## 馃搱 鎬ц兘浼樺寲寤鸿
+
+### 1. 鏁版嵁搴撲紭鍖�
+```sql
+-- 娣诲姞绱㈠紩
+CREATE INDEX idx_evaluation_vehicle_time ON customer_evaluation(vehicle_no, evaluation_time);
+CREATE INDEX idx_evaluation_status ON customer_evaluation(evaluation_status);
+CREATE INDEX idx_evaluation_detail_evaluation ON evaluation_detail(evaluation_id);
+```
+
+### 2. 缂撳瓨閰嶇疆
+- 璇勪环缁村害閰嶇疆鍙互缂撳瓨
+- 浜岀淮鐮佸浘鐗囦娇鐢–DN鍔犻��
+
+### 3. 鏂囦欢瀛樺偍
+- 鑰冭檻浣跨敤瀵硅薄瀛樺偍鏈嶅姟
+- 瀹氭湡娓呯悊鏃犵敤鐨勪簩缁寸爜鏂囦欢
+
+## 馃摓 鎶�鏈敮鎸�
+
+濡傞亣鍒伴棶棰橈紝璇锋彁渚涳細
+1. 閿欒鏃ュ織
+2. 鎿嶄綔姝ラ
+3. 鐜淇℃伅
+4. 閿欒鎴浘
+
+## 馃幆 鍔熻兘鎵╁睍
+
+### 1. 璇勪环缁熻
+鍙互鍩轰簬鐜版湁鏁版嵁寮�鍙戯細
+- 璇勪环瓒嬪娍鍒嗘瀽
+- 杞﹁締璇勪环鎺掕
+- 瀹㈡埛婊℃剰搴︽姤鍛�
+
+### 2. 娑堟伅閫氱煡
+- 璇勪环鎻愪氦鍚庡彂閫侀�氱煡
+- 浣庡垎璇勪环棰勮
+- 瀹氭湡璇勪环鎶ュ憡
+
+### 3. 澶氳瑷�鏀寔
+- 鏀寔澶氳瑷�璇勪环鐣岄潰
+- 鍥介檯鍖栭厤缃�
+
+鍔熻兘宸插叏閮ㄥ紑鍙戝畬鎴愶紝鍙互姝e父浣跨敤锛�
diff --git "a/\345\256\242\346\210\267\346\273\241\346\204\217\345\272\246\350\257\204\344\273\267\345\212\237\350\203\275\350\257\264\346\230\216.md" "b/\345\256\242\346\210\267\346\273\241\346\204\217\345\272\246\350\257\204\344\273\267\345\212\237\350\203\275\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..1bd5d38
--- /dev/null
+++ "b/\345\256\242\346\210\267\346\273\241\346\204\217\345\272\246\350\257\204\344\273\267\345\212\237\350\203\275\350\257\264\346\230\216.md"
@@ -0,0 +1,134 @@
+# 瀹㈡埛婊℃剰搴﹁瘎浠峰姛鑳借鏄�
+
+## 鍔熻兘姒傝堪
+
+瀹㈡埛婊℃剰搴﹁瘎浠峰姛鑳藉厑璁稿鎴烽�氳繃鎵弿浜岀淮鐮佽繘鍏ヨ瘎浠风晫闈紝瀵规湇鍔¤繘琛屽缁村害璇勪环銆傛敮鎸佸井淇$幆澧冧笅鐨勭敤鎴蜂俊鎭幏鍙栧拰璇勪环鎻愪氦銆�
+
+## 涓昏鍔熻兘
+
+### 1. 浜岀淮鐮佺敓鎴�
+- 涓烘瘡杈嗚溅鐢熸垚鍞竴鐨勮瘎浠蜂簩缁寸爜
+- 浜岀淮鐮佸寘鍚溅鐗屽彿淇℃伅锛岀敤浜庡叧鑱斿叿浣撹溅杈嗘湇鍔�
+- 鏀寔鎵归噺鐢熸垚浜岀淮鐮�
+
+### 2. 寰俊闆嗘垚
+- 鑷姩妫�娴嬪井淇℃祻瑙堝櫒鐜
+- 鑾峰彇寰俊鐢ㄦ埛淇℃伅锛圤penID銆佹樀绉般�佸ご鍍忕瓑锛�
+- 鏀寔寰俊缃戦〉鎺堟潈娴佺▼
+
+### 3. 璇勪环鐣岄潰
+- 鍝嶅簲寮忚璁★紝閫傞厤绉诲姩绔拰寰俊娴忚鍣�
+- 鏀寔澶氱璇勪环绫诲瀷锛氭槦绾ц瘎浠枫�侀�夋嫨璇勪环銆佹枃鏈瘎浠�
+- 瀹㈡埛淇℃伅鏀堕泦锛堝鍚嶃�佹墜鏈哄彿蹇呭~锛�
+- 璇勪环缁村害鍙厤缃�
+
+### 4. 璇勪环鎻愪氦
+- 鏁版嵁楠岃瘉鍜屽畬鏁存�ф鏌�
+- 鏍规嵁璇勫垎鏄剧ず涓嶅悓鐨勫弽棣堜俊鎭�
+- 璇勪环鏁版嵁瀛樺偍鍜岀粺璁�
+
+## 鏁版嵁搴撹〃缁撴瀯
+
+### 1. evaluation_dimension锛堣瘎浠风淮搴﹂厤缃〃锛�
+- 閰嶇疆璇勪环缁村害鍚嶇О銆佺被鍨嬨�佹槸鍚﹀繀濉瓑
+- 鏀寔鏄熺骇璇勪环銆侀�夋嫨璇勪环銆佹枃鏈瘎浠蜂笁绉嶇被鍨�
+
+### 2. customer_evaluation锛堝鎴疯瘎浠疯〃锛�
+- 瀛樺偍瀹㈡埛鍩烘湰淇℃伅鍜岃瘎浠风粨鏋�
+- 鍖呭惈寰俊鐢ㄦ埛淇℃伅
+- 璁板綍璇勪环鏃堕棿鍜孖P鍦板潃
+
+### 3. evaluation_detail锛堣瘎浠疯鎯呰〃锛�
+- 瀛樺偍姣忎釜缁村害鐨勫叿浣撹瘎鍒�
+- 鍏宠仈璇勪环缁村害鍜屽鎴疯瘎浠�
+
+### 4. vehicle_evaluation_qrcode锛堣溅杈嗚瘎浠蜂簩缁寸爜琛級
+- 瀛樺偍姣忚締杞︾殑浜岀淮鐮佷俊鎭�
+- 鍖呭惈浜岀淮鐮乁RL鍜屽浘鐗囪矾寰�
+
+## API鎺ュ彛
+
+### 鍏紑鎺ュ彛锛堟棤闇�璁よ瘉锛�
+- `GET /evaluation/dimensions` - 鑾峰彇璇勪环缁村害閰嶇疆
+- `POST /evaluation/submit` - 鎻愪氦瀹㈡埛璇勪环
+- `GET /evaluation/wechat/userinfo` - 鑾峰彇寰俊鐢ㄦ埛淇℃伅
+
+### 绠$悊鎺ュ彛锛堥渶瑕佽璇侊級
+- `GET /evaluation/list` - 鏌ヨ瀹㈡埛璇勪环鍒楄〃
+- `GET /evaluation/{id}` - 鑾峰彇璇勪环璇︽儏
+- `POST /evaluation/qrcode/{vehicleNo}` - 鐢熸垚杞﹁締浜岀淮鐮�
+- `POST /evaluation/qrcode/batch` - 鎵归噺鐢熸垚浜岀淮鐮�
+
+## 閮ㄧ讲璇存槑
+
+### 1. 鏁版嵁搴撳垵濮嬪寲
+```sql
+-- 鎵ц sql/customer_evaluation_tables.sql 鏂囦欢
+-- 鍒涘缓鐩稿叧琛ㄥ拰鍒濆鏁版嵁
+```
+
+### 2. 閰嶇疆鏂囦欢
+鍦� `application.yml` 涓厤缃細
+```yaml
+# 寰俊閰嶇疆
+wechat:
+ appId: your_wechat_appid
+ appSecret: your_wechat_appsecret
+
+# 鏂囦欢涓婁紶璺緞
+ruoyi:
+ profile: /path/to/upload
+```
+
+### 3. 鍓嶇璺敱閰嶇疆
+鍦� `router/index.js` 涓坊鍔犺瘎浠烽〉闈㈣矾鐢憋細
+```javascript
+{
+ path: '/evaluation',
+ component: () => import('@/views/evaluation/index'),
+ name: 'Evaluation'
+}
+```
+
+## 浣跨敤娴佺▼
+
+### 1. 绠$悊鍛樻搷浣�
+1. 閰嶇疆璇勪环缁村害锛堟湇鍔℃�佸害銆佹敹璐规儏鍐点�佽溅杈嗗崼鐢熺瓑锛�
+2. 涓鸿溅杈嗙敓鎴愯瘎浠蜂簩缁寸爜
+3. 灏嗕簩缁寸爜鎵撳嵃骞惰创鍦ㄨ溅杈嗕笂
+
+### 2. 瀹㈡埛璇勪环娴佺▼
+1. 瀹㈡埛鎵弿杞﹁締涓婄殑浜岀淮鐮�
+2. 绯荤粺瑙f瀽浜岀淮鐮侊紝鑾峰彇杞︾墝鍙�
+3. 杩涘叆璇勪环椤甸潰锛岃幏鍙栧井淇$敤鎴蜂俊鎭紙濡傛灉鍦ㄥ井淇$幆澧冧腑锛�
+4. 瀹㈡埛濉啓涓汉淇℃伅鍜岃瘎浠峰唴瀹�
+5. 鎻愪氦璇勪环锛屾樉绀虹粨鏋滈〉闈�
+
+## 娴嬭瘯鍔熻兘
+
+璁块棶 `/evaluation/test` 椤甸潰鍙互娴嬭瘯浠ヤ笅鍔熻兘锛�
+- 浜岀淮鐮佺敓鎴�
+- 璇勪环缁村害鍔犺浇
+- 璇勪环鎻愪氦
+- 鐩存帴璁块棶璇勪环椤甸潰
+
+## 娉ㄦ剰浜嬮」
+
+1. **寰俊閰嶇疆**锛氶渶瑕侀厤缃纭殑寰俊AppID鍜孉ppSecret
+2. **鏂囦欢鏉冮檺**锛氱‘淇濅笂浼犵洰褰曟湁鍐欏叆鏉冮檺
+3. **HTTPS**锛氬井淇℃巿鏉冮渶瑕丠TTPS鐜
+4. **鍩熷悕閰嶇疆**锛氬湪寰俊鍏紬骞冲彴閰嶇疆鎺堟潈鍩熷悕
+
+## 鎵╁睍鍔熻兘
+
+1. **璇勪环缁熻**锛氬彲浠ュ熀浜庣幇鏈夋暟鎹紑鍙戣瘎浠风粺璁″垎鏋愬姛鑳�
+2. **娑堟伅閫氱煡**锛氳瘎浠锋彁浜ゅ悗鍙互鍙戦�侀�氱煡缁欑浉鍏充汉鍛�
+3. **璇勪环瀵煎嚭**锛氭敮鎸佽瘎浠锋暟鎹殑Excel瀵煎嚭
+4. **澶氳瑷�鏀寔**锛氬彲浠ユ墿灞曞璇█璇勪环鐣岄潰
+
+## 鎶�鏈爤
+
+- 鍚庣锛歋pring Boot + MyBatis + MySQL
+- 鍓嶇锛歏ue.js + Element UI
+- 浜岀淮鐮侊細ZXing
+- 寰俊锛氬井淇$綉椤垫巿鏉傾PI
diff --git "a/\346\265\213\350\257\225\346\255\245\351\252\244.md" "b/\346\265\213\350\257\225\346\255\245\351\252\244.md"
new file mode 100644
index 0000000..5b60928
--- /dev/null
+++ "b/\346\265\213\350\257\225\346\255\245\351\252\244.md"
@@ -0,0 +1,121 @@
+# 瀹㈡埛婊℃剰搴﹁瘎浠峰姛鑳芥祴璇曟楠�
+
+## 1. 鍚姩椤圭洰
+
+### 鍚庣鍚姩
+```bash
+# 鍦ㄩ」鐩牴鐩綍鎵ц
+mvn clean install
+cd ruoyi-admin
+mvn spring-boot:run
+```
+
+### 鍓嶇鍚姩
+```bash
+# 鍦� ruoyi-ui 鐩綍鎵ц
+npm install
+npm run dev
+```
+
+## 2. 閰嶇疆寰俊鍙傛暟锛堝彲閫夛級
+
+濡傛灉涓嶉渶瑕佸井淇″姛鑳斤紝鍙互璺宠繃姝ゆ楠ゃ��
+
+鍦� `ruoyi-admin/src/main/resources/application.yml` 涓厤缃細
+```yaml
+wechat:
+ appId: your_wechat_appid
+ appSecret: your_wechat_appsecret
+ redirectUri: http://localhost:8080/evaluation
+```
+
+## 3. 娴嬭瘯姝ラ
+
+### 姝ラ1锛氳闂祴璇曢〉闈�
+鎵撳紑娴忚鍣ㄨ闂細`http://localhost:80/evaluation/test`
+
+### 姝ラ2锛氭祴璇曚簩缁寸爜鐢熸垚
+1. 鍦ㄦ祴璇曢〉闈㈣緭鍏ヨ溅鐗屽彿锛堝锛氱菠A12345锛�
+2. 鐐瑰嚮"鐢熸垚浜岀淮鐮�"鎸夐挳
+3. 鏌ョ湅鏄惁鎴愬姛鐢熸垚浜岀淮鐮佷俊鎭�
+
+### 姝ラ3锛氭祴璇曡瘎浠风淮搴﹀姞杞�
+1. 鐐瑰嚮"鍔犺浇璇勪环缁村害"鎸夐挳
+2. 鏌ョ湅鏄惁鎴愬姛鍔犺浇璇勪环缁村害鍒楄〃
+
+### 姝ラ4锛氭祴璇曡瘎浠锋彁浜�
+1. 濉啓娴嬭瘯璇勪环淇℃伅
+2. 鐐瑰嚮"鎻愪氦娴嬭瘯璇勪环"鎸夐挳
+3. 鏌ョ湅鏄惁鎴愬姛鎻愪氦
+
+### 姝ラ5锛氭祴璇曡瘎浠烽〉闈�
+1. 鐐瑰嚮"鐩存帴璁块棶璇勪环椤甸潰"閾炬帴
+2. 鎴栫洿鎺ヨ闂細`http://localhost:80/evaluation?vehicle=绮12345`
+3. 濉啓璇勪环淇℃伅骞舵彁浜�
+
+## 4. 棰勬湡缁撴灉
+
+### 浜岀淮鐮佺敓鎴愭祴璇�
+- 搴旇杩斿洖浜岀淮鐮乁RL銆佸唴瀹瑰拰鍥剧墖璺緞
+- 浜岀淮鐮乁RL鏍煎紡锛歚http://localhost:8080/evaluation?vehicle=杞︾墝鍙穈
+
+### 璇勪环缁村害娴嬭瘯
+- 搴旇杩斿洖榛樿鐨勮瘎浠风淮搴︼細
+ - 鏈嶅姟鎬佸害锛堟槦绾ц瘎浠凤紝蹇呭~锛�
+ - 鏀惰垂鎯呭喌锛堟槦绾ц瘎浠凤紝蹇呭~锛�
+ - 杞﹁締鍗敓鐘跺喌锛堟槦绾ц瘎浠凤紝蹇呭~锛�
+ - 鏁翠綋婊℃剰搴︼紙鏄熺骇璇勪环锛屽繀濉級
+ - 鍏朵粬寤鸿锛堟枃鏈瘎浠凤紝闈炲繀濉級
+
+### 璇勪环鎻愪氦娴嬭瘯
+- 搴旇杩斿洖鎴愬姛娑堟伅
+- 鏁版嵁搴撲腑搴旇淇濆瓨璇勪环璁板綍
+
+### 璇勪环椤甸潰娴嬭瘯
+- 椤甸潰搴旇姝e父鏄剧ず
+- 琛ㄥ崟楠岃瘉搴旇姝e父宸ヤ綔
+- 鎻愪氦鍚庡簲璇ユ樉绀烘垚鍔熼〉闈�
+
+## 5. 甯歌闂
+
+### 闂1锛氫簩缁寸爜鐢熸垚澶辫触
+**鍘熷洜**锛氬彲鑳芥槸鏂囦欢璺緞鏉冮檺闂
+**瑙e喅**锛氭鏌� `ruoyi.profile` 閰嶇疆鐨勮矾寰勬槸鍚︽湁鍐欏叆鏉冮檺
+
+### 闂2锛氳瘎浠风淮搴﹀姞杞藉け璐�
+**鍘熷洜**锛氬彲鑳芥槸鏁版嵁搴撹繛鎺ラ棶棰�
+**瑙e喅**锛氭鏌ユ暟鎹簱杩炴帴閰嶇疆
+
+### 闂3锛氳瘎浠锋彁浜ゅけ璐�
+**鍘熷洜**锛氬彲鑳芥槸蹇呭~瀛楁楠岃瘉澶辫触
+**瑙e喅**锛氱‘淇濇墍鏈夊繀濉瓧娈甸兘宸插~鍐�
+
+### 闂4锛氶〉闈㈣闂�404
+**鍘熷洜**锛氬彲鑳芥槸璺敱閰嶇疆闂
+**瑙e喅**锛氭鏌ュ墠绔矾鐢遍厤缃槸鍚︽纭�
+
+## 6. 鏁版嵁搴撻獙璇�
+
+鍙互鎵ц浠ヤ笅SQL鏌ヨ楠岃瘉鏁版嵁锛�
+
+```sql
+-- 鏌ョ湅璇勪环缁村害閰嶇疆
+SELECT * FROM evaluation_dimension;
+
+-- 鏌ョ湅瀹㈡埛璇勪环璁板綍
+SELECT * FROM customer_evaluation;
+
+-- 鏌ョ湅璇勪环璇︽儏
+SELECT * FROM evaluation_detail;
+
+-- 鏌ョ湅杞﹁締浜岀淮鐮�
+SELECT * FROM vehicle_evaluation_qrcode;
+```
+
+## 7. 鐢熶骇鐜閮ㄧ讲娉ㄦ剰浜嬮」
+
+1. **HTTPS閰嶇疆**锛氬井淇℃巿鏉冮渶瑕丠TTPS鐜
+2. **鍩熷悕閰嶇疆**锛氬湪寰俊鍏紬骞冲彴閰嶇疆鎺堟潈鍩熷悕
+3. **鏂囦欢鏉冮檺**锛氱‘淇濅笂浼犵洰褰曟湁姝g‘鐨勮鍐欐潈闄�
+4. **鏁版嵁搴撳浠�**锛氬畾鏈熷浠借瘎浠锋暟鎹�
+5. **鎬ц兘浼樺寲**锛氬ぇ閲忚瘎浠锋暟鎹椂鑰冭檻鍒嗛〉鍜岀储寮曚紭鍖�
diff --git "a/\351\203\250\347\275\262\350\257\264\346\230\216.md" "b/\351\203\250\347\275\262\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..b98f82f
--- /dev/null
+++ "b/\351\203\250\347\275\262\350\257\264\346\230\216.md"
@@ -0,0 +1,249 @@
+# 瀹㈡埛婊℃剰搴﹁瘎浠峰姛鑳介儴缃茶鏄�
+
+## 閮ㄧ讲鍓嶅噯澶�
+
+### 1. 鐜瑕佹眰
+- JDK 1.8+
+- Maven 3.6+
+- MySQL 5.7+
+- Node.js 14+
+- Nginx锛堢敓浜х幆澧冩帹鑽愶級
+
+### 2. 閰嶇疆鏂囦欢淇敼
+
+#### 鏁版嵁搴撻厤缃�
+淇敼 `ruoyi-admin/src/main/resources/application-prod.yml`锛�
+```yaml
+spring:
+ datasource:
+ url: jdbc:mysql://your-db-host:3306/your-database?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: your-username
+ password: your-password
+```
+
+#### 寰俊閰嶇疆
+淇敼 `ruoyi-admin/src/main/resources/application-prod.yml`锛�
+```yaml
+wechat:
+ appId: your_wechat_appid
+ appSecret: your_wechat_appsecret
+ redirectUri: https://yourdomain.com/evaluation
+```
+
+#### 鏂囦欢涓婁紶璺緞
+淇敼 `ruoyi-admin/src/main/resources/application-prod.yml`锛�
+```yaml
+ruoyi:
+ profile: /path/to/upload
+```
+
+## 閮ㄧ讲姝ラ
+
+### 1. 鍚庣閮ㄧ讲
+
+#### 鏂瑰紡涓�锛欽AR鍖呴儴缃�
+```bash
+# 缂栬瘧鎵撳寘
+mvn clean package -Pprod
+
+# 涓婁紶JAR鍖呭埌鏈嶅姟鍣�
+scp ruoyi-admin/target/ruoyi-admin.jar user@server:/path/to/app/
+
+# 鍚姩搴旂敤
+java -jar ruoyi-admin.jar --spring.profiles.active=prod
+```
+
+#### 鏂瑰紡浜岋細Docker閮ㄧ讲
+```dockerfile
+# Dockerfile
+FROM openjdk:8-jre-alpine
+COPY ruoyi-admin.jar app.jar
+EXPOSE 8080
+ENTRYPOINT ["java", "-jar", "/app.jar"]
+```
+
+```bash
+# 鏋勫缓闀滃儚
+docker build -t ruoyi-evaluation .
+
+# 杩愯瀹瑰櫒
+docker run -d -p 8080:8080 --name ruoyi-evaluation ruoyi-evaluation
+```
+
+### 2. 鍓嶇閮ㄧ讲
+
+#### 鏋勫缓鐢熶骇鐗堟湰
+```bash
+cd ruoyi-ui
+npm install
+npm run build:prod
+```
+
+#### Nginx閰嶇疆
+```nginx
+server {
+ listen 80;
+ server_name yourdomain.com;
+
+ # 鍓嶇闈欐�佹枃浠�
+ location / {
+ root /path/to/ruoyi-ui/dist;
+ try_files $uri $uri/ /index.html;
+ }
+
+ # 鍚庣API浠g悊
+ location /dev-api/ {
+ proxy_pass http://localhost:8080/;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ }
+
+ # 浜岀淮鐮佸浘鐗囪闂�
+ location /qrcode/ {
+ alias /path/to/upload/qrcode/;
+ }
+}
+```
+
+### 3. 鏁版嵁搴撻儴缃�
+
+#### 鎵цSQL鑴氭湰
+```bash
+mysql -u username -p database_name < sql/customer_evaluation_tables.sql
+```
+
+#### 鍒涘缓鏁版嵁搴撶敤鎴凤紙鍙�夛級
+```sql
+CREATE USER 'evaluation_user'@'%' IDENTIFIED BY 'password';
+GRANT SELECT, INSERT, UPDATE, DELETE ON database_name.* TO 'evaluation_user'@'%';
+FLUSH PRIVILEGES;
+```
+
+## 寰俊閰嶇疆
+
+### 1. 寰俊鍏紬骞冲彴閰嶇疆
+
+1. 鐧诲綍寰俊鍏紬骞冲彴
+2. 杩涘叆"寮�鍙�" -> "鎺ュ彛鏉冮檺"
+3. 閰嶇疆缃戦〉鎺堟潈鍩熷悕锛歚yourdomain.com`
+4. 閰嶇疆JS鎺ュ彛瀹夊叏鍩熷悕锛歚yourdomain.com`
+
+### 2. 娴嬭瘯寰俊鍔熻兘
+
+1. 鍦ㄥ井淇′腑璁块棶锛歚https://yourdomain.com/evaluation?vehicle=绮12345`
+2. 纭鑳芥甯歌幏鍙栧井淇$敤鎴蜂俊鎭�
+3. 娴嬭瘯璇勪环鎻愪氦鍔熻兘
+
+## 鐩戞帶鍜岀淮鎶�
+
+### 1. 鏃ュ織鐩戞帶
+```bash
+# 鏌ョ湅搴旂敤鏃ュ織
+tail -f logs/sys-info.log
+
+# 鏌ョ湅閿欒鏃ュ織
+tail -f logs/sys-error.log
+```
+
+### 2. 鏁版嵁搴撶洃鎺�
+```sql
+-- 鏌ョ湅璇勪环缁熻
+SELECT
+ vehicle_no,
+ COUNT(*) as total_count,
+ AVG(total_score) as avg_score
+FROM customer_evaluation
+WHERE evaluation_status = '1'
+GROUP BY vehicle_no;
+
+-- 鏌ョ湅浠婃棩璇勪环鏁伴噺
+SELECT COUNT(*) FROM customer_evaluation
+WHERE DATE(evaluation_time) = CURDATE();
+```
+
+### 3. 鏂囦欢娓呯悊
+```bash
+# 娓呯悊杩囨湡鐨勪簩缁寸爜鏂囦欢锛堝彲閫夛級
+find /path/to/upload/qrcode/ -name "*.png" -mtime +30 -delete
+```
+
+## 鎬ц兘浼樺寲
+
+### 1. 鏁版嵁搴撲紭鍖�
+```sql
+-- 娣诲姞绱㈠紩
+CREATE INDEX idx_evaluation_vehicle_time ON customer_evaluation(vehicle_no, evaluation_time);
+CREATE INDEX idx_evaluation_status ON customer_evaluation(evaluation_status);
+```
+
+### 2. 缂撳瓨閰嶇疆
+```yaml
+# Redis閰嶇疆
+spring:
+ redis:
+ host: your-redis-host
+ port: 6379
+ database: 0
+ timeout: 10s
+```
+
+### 3. 鏂囦欢瀛樺偍浼樺寲
+- 浣跨敤CDN鍔犻�熶簩缁寸爜鍥剧墖璁块棶
+- 瀹氭湡娓呯悊鏃犵敤鐨勪簩缁寸爜鏂囦欢
+- 鑰冭檻浣跨敤瀵硅薄瀛樺偍鏈嶅姟锛堝闃块噷浜慜SS锛�
+
+## 瀹夊叏閰嶇疆
+
+### 1. HTTPS閰嶇疆
+```nginx
+server {
+ listen 443 ssl;
+ server_name yourdomain.com;
+
+ ssl_certificate /path/to/cert.pem;
+ ssl_certificate_key /path/to/key.pem;
+
+ # 鍏朵粬閰嶇疆...
+}
+```
+
+### 2. 鎺ュ彛瀹夊叏
+- 璇勪环鎻愪氦鎺ュ彛娣诲姞棰戠巼闄愬埗
+- 鏁忔劅淇℃伅鍔犲瘑瀛樺偍
+- 瀹氭湡鏇存柊寰俊AppSecret
+
+### 3. 鏁版嵁澶囦唤
+```bash
+# 鏁版嵁搴撳浠�
+mysqldump -u username -p database_name > backup_$(date +%Y%m%d).sql
+
+# 鏂囦欢澶囦唤
+tar -czf upload_backup_$(date +%Y%m%d).tar.gz /path/to/upload/
+```
+
+## 鏁呴殰鎺掓煡
+
+### 1. 甯歌闂
+
+#### 浜岀淮鐮佺敓鎴愬け璐�
+- 妫�鏌ユ枃浠惰矾寰勬潈闄�
+- 妫�鏌ョ鐩樼┖闂�
+- 鏌ョ湅搴旂敤鏃ュ織
+
+#### 寰俊鎺堟潈澶辫触
+- 妫�鏌ュ煙鍚嶉厤缃�
+- 妫�鏌TTPS璇佷功
+- 妫�鏌ppID鍜孉ppSecret
+
+#### 璇勪环鎻愪氦澶辫触
+- 妫�鏌ユ暟鎹簱杩炴帴
+- 妫�鏌ュ繀濉瓧娈甸獙璇�
+- 鏌ョ湅閿欒鏃ュ織
+
+### 2. 鑱旂郴鏀寔
+濡傞亣鍒伴棶棰橈紝璇锋彁渚涳細
+- 閿欒鏃ュ織
+- 鎿嶄綔姝ラ
+- 鐜淇℃伅
+- 閿欒鎴浘
--
Gitblit v1.9.1