package com.dsh.guns.modular.system.controller.code; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.dsh.course.entity.AppGuideBanner; import com.dsh.course.entity.AppGuideConfig; import com.dsh.course.entity.QrLink; import com.dsh.course.mapper.AppGuideBannerMapper; import com.dsh.course.mapper.AppGuideConfigMapper; import com.dsh.course.mapper.QrLinkMapper; import com.dsh.guns.modular.system.model.TSite; import com.dsh.guns.modular.system.service.ITSiteService; import com.dsh.guns.modular.system.util.QRCodeUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.IOException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Controller @RequestMapping("/appGuide") public class AppGuideManagementController { private static final char[] CODE_CHARS = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); private final SecureRandom random = new SecureRandom(); @Autowired private AppGuideConfigMapper appGuideConfigMapper; @Autowired private AppGuideBannerMapper appGuideBannerMapper; @Resource private QrLinkMapper qrLinkMapper; @Autowired private ITSiteService siteService; @GetMapping("") public String index() { return "/system/appGuide/appGuide.html"; } @ResponseBody @GetMapping("/sites") public List queryAvailableSites() { return siteService.list(new QueryWrapper().orderByDesc("id")); } @ResponseBody @GetMapping("/data") public Map data() { Map r = new HashMap<>(); r.put("config", appGuideConfigMapper.selectOne(new QueryWrapper().orderByDesc("id").last("limit 1"))); r.put("banners", appGuideBannerMapper.selectList(new QueryWrapper().orderByAsc("sort").orderByDesc("id"))); List links = qrLinkMapper.selectList(new QueryWrapper().eq("type", "SITE_BOOKING").orderByDesc("id")); List> linkData = new ArrayList<>(); for (QrLink link : links) { Map item = new HashMap<>(); // Map 不会触发实体的 @JsonSerialize;雪花 ID 必须转字符串,避免前端 Number 精度丢失。 item.put("id", String.valueOf(link.getId())); item.put("name", link.getName()); item.put("pageName", link.getPageName()); item.put("storeId", link.getStoreId()); item.put("siteId", link.getSiteId()); item.put("shortCode", link.getShortCode()); item.put("enabled", link.getEnabled()); item.put("guideUrl", guideUrl(link)); linkData.add(item); } r.put("links", linkData); return r; } @ResponseBody @PostMapping("/config") public Map saveConfig(AppGuideConfig config) { if (config.getEnabled() == null) config.setEnabled(1); if (config.getId() == null) { appGuideConfigMapper.delete(new QueryWrapper()); appGuideConfigMapper.insert(config); } else appGuideConfigMapper.updateById(config); return ok(); } @ResponseBody @PostMapping("/banner") public Map saveBanner(AppGuideBanner banner) { if (banner.getEnabled() == null) banner.setEnabled(1); if (banner.getId() == null) appGuideBannerMapper.insert(banner); else appGuideBannerMapper.updateById(banner); return ok(); } @ResponseBody @PostMapping("/banner/delete") public Map deleteBanner(Long id) { appGuideBannerMapper.deleteById(id); return ok(); } @ResponseBody @PostMapping("/siteQr") public Map createSiteQr(Integer storeId, Integer siteId, String name, String channel, String pageName) { if (storeId == null || siteId == null) return error("门店 ID 和场地 ID 必填"); QrLink old = qrLinkMapper.selectOne(new QueryWrapper().eq("type", "SITE_BOOKING").eq("siteId", siteId).eq("enabled", 1).last("limit 1")); if (old != null) return error("该场地已有启用二维码,请先停用或使用现有二维码"); QrLink link = new QrLink(); link.setStoreId(storeId); link.setSiteId(siteId); link.setName(name); link.setChannel(channel); link.setPageName(pageName); link.setType("SITE_BOOKING"); link.setEnabled(1); link.setShortCode(nextCode()); qrLinkMapper.insert(link); Map r = ok(); r.put("link", link); r.put("url", guideUrl(link)); return r; } @ResponseBody @PostMapping("/siteQr/status") public Map changeStatus(Long id, Integer enabled) { QrLink link = new QrLink(); link.setId(id); link.setEnabled(enabled); qrLinkMapper.updateById(link); return ok(); } /** 逻辑删除场地订场二维码。 */ @ResponseBody @PostMapping("/siteQr/delete") public Map deleteSiteQr(Long id) { qrLinkMapper.deleteById(id); return ok(); } @GetMapping("/siteQr/{id}.png") public void qrImage(@PathVariable Long id, HttpServletResponse response) throws IOException { QrLink link = qrLinkMapper.selectById(id); if (link == null) { response.sendError(404); return; } BufferedImage image = QRCodeUtil.createImage(guideUrl(link)); response.setContentType("image/png"); ImageIO.write(image, "png", response.getOutputStream()); } private String guideUrl(QrLink link) { return "https://www.weparklife.com/appdown?code=" + link.getShortCode(); } private String nextCode() { String code; do { StringBuilder s = new StringBuilder(10); for (int i = 0; i < 10; i++) s.append(CODE_CHARS[random.nextInt(CODE_CHARS.length)]); code = s.toString(); } while (qrLinkMapper.selectCount(new QueryWrapper().eq("shortCode", code)) > 0); return code; } private Map ok() { Map r = new HashMap<>(); r.put("success", true); return r; } private Map error(String msg) { Map r = ok(); r.put("success", false); r.put("message", msg); return r; } }