| | |
| | | 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; |
| | |
| | | @Autowired |
| | | private ITSiteService siteService; |
| | | |
| | | /** |
| | | * 打开 APP 下载引导管理页面。 |
| | | * |
| | | * @return APP 下载引导管理页面路径 |
| | | */ |
| | | @GetMapping("") |
| | | public String index() { |
| | | return "/system/appGuide/appGuide.html"; |
| | | } |
| | | |
| | | /** |
| | | * 查询可用于生成订场二维码的场地列表。 |
| | | * |
| | | * @return 按 ID 倒序排列的场地列表 |
| | | */ |
| | | @ResponseBody |
| | | @GetMapping("/sites") |
| | | public List<TSite> queryAvailableSites() { |
| | | return siteService.list(new QueryWrapper<TSite>().orderByDesc("id")); |
| | | } |
| | | |
| | | /** |
| | | * 查询 APP 下载引导页面所需的配置、宣传图和订场二维码数据。 |
| | | * |
| | | * @return 下载引导页面的聚合数据 |
| | | */ |
| | | @ResponseBody |
| | | @GetMapping("/data") |
| | | public Map<String, Object> data() { |
| | | Map<String, Object> r = new HashMap<>(); |
| | | r.put("config", appGuideConfigMapper.selectOne(new QueryWrapper<AppGuideConfig>().orderByDesc("id").last("limit 1"))); |
| | | r.put("banners", appGuideBannerMapper.selectList(new QueryWrapper<AppGuideBanner>().orderByAsc("sort").orderByDesc("id"))); |
| | | r.put("links", qrLinkMapper.selectList(new QueryWrapper<QrLink>().eq("type", "SITE_BOOKING").orderByDesc("id"))); |
| | | r.put("banners", appGuideBannerMapper.selectList(new QueryWrapper<AppGuideBanner>().orderByDesc("sort").orderByDesc("id"))); |
| | | List<QrLink> links = qrLinkMapper.selectList(new QueryWrapper<QrLink>().eq("type", "SITE_BOOKING").orderByDesc("id")); |
| | | List<Map<String, Object>> linkData = new ArrayList<>(); |
| | | for (QrLink link : links) { |
| | | Map<String, Object> 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; |
| | | } |
| | | |
| | | /** |
| | | * 保存 APP 下载引导配置。 |
| | | * |
| | | * @param config 下载引导配置 |
| | | * @return 保存结果 |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping("/config") |
| | | public Map<String, Object> saveConfig(AppGuideConfig config) { |
| | |
| | | return ok(); |
| | | } |
| | | |
| | | /** |
| | | * 保存 APP 下载引导宣传图。 |
| | | * |
| | | * @param banner 宣传图配置 |
| | | * @return 保存结果 |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping("/banner") |
| | | public Map<String, Object> saveBanner(AppGuideBanner banner) { |
| | |
| | | return ok(); |
| | | } |
| | | |
| | | /** |
| | | * 删除 APP 下载引导宣传图。 |
| | | * |
| | | * @param id 宣传图 ID |
| | | * @return 删除结果 |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping("/banner/delete") |
| | | public Map<String, Object> deleteBanner(Long id) { |
| | |
| | | return ok(); |
| | | } |
| | | |
| | | /** |
| | | * 为指定场地创建订场二维码。 |
| | | * |
| | | * @param storeId 门店 ID |
| | | * @param siteId 场地 ID |
| | | * @param name 二维码名称 |
| | | * @param channel 投放渠道 |
| | | * @param pageName 引导页面名称 |
| | | * @return 创建结果及二维码引导链接 |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping("/siteQr") |
| | | public Map<String, Object> createSiteQr(Integer storeId, Integer siteId, String name, String channel) { |
| | | public Map<String, Object> 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<QrLink>().eq("type", "SITE_BOOKING").eq("siteId", siteId).eq("enabled", 1).last("limit 1")); |
| | | if (old != null) return error("该场地已有启用二维码,请先停用或使用现有二维码"); |
| | |
| | | link.setSiteId(siteId); |
| | | link.setName(name); |
| | | link.setChannel(channel); |
| | | link.setPageName(pageName); |
| | | link.setType("SITE_BOOKING"); |
| | | link.setEnabled(1); |
| | | link.setShortCode(nextCode()); |
| | |
| | | return r; |
| | | } |
| | | |
| | | /** |
| | | * 修改场地订场二维码的启用状态。 |
| | | * |
| | | * @param id 二维码 ID |
| | | * @param enabled 启用状态(0:停用;1:启用) |
| | | * @return 修改结果 |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping("/siteQr/status") |
| | | public Map<String, Object> changeStatus(Long id, Integer enabled) { |
| | |
| | | return ok(); |
| | | } |
| | | |
| | | /** |
| | | * 逻辑删除场地订场二维码。 |
| | | * |
| | | * @param id 二维码 ID |
| | | * @return 删除结果 |
| | | */ |
| | | @ResponseBody |
| | | @PostMapping("/siteQr/delete") |
| | | public Map<String, Object> deleteSiteQr(Long id) { |
| | | qrLinkMapper.deleteById(id); |
| | | return ok(); |
| | | } |
| | | |
| | | /** |
| | | * 生成并输出场地订场二维码图片。 |
| | | * |
| | | * @param id 二维码 ID |
| | | * @param response HTTP 响应 |
| | | * @throws IOException 图片输出失败时抛出 |
| | | */ |
| | | @GetMapping("/siteQr/{id}.png") |
| | | public void qrImage(@PathVariable Long id, HttpServletResponse response) throws IOException { |
| | | QrLink link = qrLinkMapper.selectById(id); |
| | |
| | | } |
| | | |
| | | private String guideUrl(QrLink link) { |
| | | AppGuideConfig c = appGuideConfigMapper.selectOne(new QueryWrapper<AppGuideConfig>().orderByDesc("id").last("limit 1")); |
| | | String domain = c == null ? null : c.getGuideDomain(); |
| | | if (domain == null || domain.trim().isEmpty()) domain = "https://online.daowepark.com/other"; |
| | | return domain.replaceAll("/$", "") + "/q/" + link.getShortCode(); |
| | | return "https://package.daowepark.com/appdown?code=" + link.getShortCode(); |
| | | } |
| | | |
| | | private String nextCode() { |