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;
|
|
/**
|
* 打开 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>().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) {
|
if (config.getEnabled() == null) config.setEnabled(1);
|
if (config.getId() == null) {
|
appGuideConfigMapper.delete(new QueryWrapper<AppGuideConfig>());
|
appGuideConfigMapper.insert(config);
|
} else appGuideConfigMapper.updateById(config);
|
return ok();
|
}
|
|
/**
|
* 保存 APP 下载引导宣传图。
|
*
|
* @param banner 宣传图配置
|
* @return 保存结果
|
*/
|
@ResponseBody
|
@PostMapping("/banner")
|
public Map<String, Object> saveBanner(AppGuideBanner banner) {
|
if (banner.getEnabled() == null) banner.setEnabled(1);
|
if (banner.getId() == null) appGuideBannerMapper.insert(banner);
|
else appGuideBannerMapper.updateById(banner);
|
return ok();
|
}
|
|
/**
|
* 删除 APP 下载引导宣传图。
|
*
|
* @param id 宣传图 ID
|
* @return 删除结果
|
*/
|
@ResponseBody
|
@PostMapping("/banner/delete")
|
public Map<String, Object> deleteBanner(Long id) {
|
appGuideBannerMapper.deleteById(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, 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("该场地已有启用二维码,请先停用或使用现有二维码");
|
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<String, Object> r = ok();
|
r.put("link", link);
|
r.put("url", guideUrl(link));
|
return r;
|
}
|
|
/**
|
* 修改场地订场二维码的启用状态。
|
*
|
* @param id 二维码 ID
|
* @param enabled 启用状态(0:停用;1:启用)
|
* @return 修改结果
|
*/
|
@ResponseBody
|
@PostMapping("/siteQr/status")
|
public Map<String, Object> changeStatus(Long id, Integer enabled) {
|
QrLink link = new QrLink();
|
link.setId(id);
|
link.setEnabled(enabled);
|
qrLinkMapper.updateById(link);
|
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);
|
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://package.daowepark.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<QrLink>().eq("shortCode", code)) > 0);
|
return code;
|
}
|
|
private Map<String, Object> ok() {
|
Map<String, Object> r = new HashMap<>();
|
r.put("success", true);
|
return r;
|
}
|
|
private Map<String, Object> error(String msg) {
|
Map<String, Object> r = ok();
|
r.put("success", false);
|
r.put("message", msg);
|
return r;
|
}
|
}
|