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