PosFoodController.java 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. package com.ruoyi.app.mendian;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  5. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  6. import com.baomidou.mybatisplus.core.metadata.IPage;
  7. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  8. import com.ruoyi.app.mendian.dto.FoodSearchOutput;
  9. import com.ruoyi.app.order.OrderInvoiceService;
  10. import com.ruoyi.app.utils.ImageCompressUtils;
  11. import com.ruoyi.common.annotation.Anonymous;
  12. import com.ruoyi.common.annotation.Log;
  13. import com.ruoyi.common.core.controller.BaseController;
  14. import com.ruoyi.common.core.domain.AjaxResult;
  15. import com.ruoyi.common.core.page.TableDataInfo;
  16. import com.ruoyi.common.enums.BusinessType;
  17. import com.ruoyi.common.utils.MessageUtils;
  18. import com.ruoyi.common.utils.StringUtils;
  19. import com.ruoyi.common.utils.poi.ExcelUtil;
  20. import com.ruoyi.system.domain.*;
  21. import com.ruoyi.system.dto.menu.StoreMenuCopyExecuteRequest;
  22. import com.ruoyi.system.dto.menu.StoreMenuCopyPreviewRequest;
  23. import com.ruoyi.system.mapper.PosStoreMapper;
  24. import com.ruoyi.system.service.*;
  25. import com.ruoyi.system.utils.Auth;
  26. import com.ruoyi.system.utils.AuthContext;
  27. import com.ruoyi.system.utils.JwtUtil;
  28. import org.springframework.beans.factory.annotation.Autowired;
  29. import org.springframework.security.access.prepost.PreAuthorize;
  30. import org.springframework.web.bind.annotation.*;
  31. import jakarta.servlet.http.HttpServletResponse;
  32. import java.util.*;
  33. import java.util.concurrent.atomic.AtomicInteger;
  34. import java.util.stream.Collectors;
  35. /**
  36. * foodController
  37. *
  38. * @author ruoyi
  39. * @date 2023-05-21
  40. */
  41. @RestController
  42. @RequestMapping("/chanting/food")
  43. public class PosFoodController extends BaseController {
  44. @Autowired //商品
  45. private IPosFoodService posFoodService;
  46. @Autowired //门店
  47. private IPosStoreService posStoreService;
  48. @Autowired //商品分类
  49. private IPosFenleiService posFenleiService;
  50. @Autowired //用户
  51. private IInfoUserService infoUserService;
  52. @Autowired //店铺Mapper
  53. private PosStoreMapper posStoreMapper;
  54. @Autowired
  55. private IPosReviewService posReviewService;
  56. @Autowired
  57. private IOperatingHoursService operatingHoursService;
  58. @Autowired
  59. private IPosOrderService posOrderService;
  60. @Autowired
  61. private PosStoreEnrichService posStoreEnrichService;
  62. @Autowired //规格组
  63. private IFoodSpecsService foodSpecsService;
  64. @Autowired //规格值
  65. private IFoodSpecsValueService foodSpecsValueService;
  66. @Autowired //商品-规格关联
  67. private IFoodSpecRelationService foodSpecRelationService;
  68. @Autowired //订单电子发票(门店是否能开票)
  69. private OrderInvoiceService orderInvoiceService;
  70. @Autowired
  71. private MerchantStoreAccessService merchantStoreAccessService;
  72. @Autowired
  73. private StoreMenuCopyService storeMenuCopyService;
  74. //删除商品
  75. @Anonymous
  76. @Auth(session = true)
  77. @GetMapping("/delefood")
  78. public AjaxResult delefood(@RequestHeader String token, @RequestParam String id) {
  79. merchantStoreAccessService.requireFoodAccess(
  80. AuthContext.requireUserId(), Long.valueOf(id));
  81. return toAjax(posFoodService.deletePosFoodById(Long.valueOf(id)));
  82. }
  83. //推荐商品
  84. @Anonymous
  85. @Auth(session = true)
  86. @PutMapping("/changerecommend")
  87. public AjaxResult changerecommend(@RequestHeader String token, @RequestBody PosFood posFood) {
  88. PosFood existing = merchantStoreAccessService.requireFoodAccess(
  89. AuthContext.requireUserId(), posFood.getId());
  90. posFood.setMdid(existing.getMdid());
  91. return toAjax(posFoodService.saveOrUpdate(posFood));
  92. }
  93. /**
  94. * 添加或修改商品
  95. */
  96. @Anonymous
  97. @Auth(session = true)
  98. @PostMapping("/setposfood")
  99. public AjaxResult setposfood(@RequestHeader String token, @RequestBody PosFood posFood) {
  100. Long userId = AuthContext.requireUserId();
  101. if (posFood.getId() == null) {
  102. merchantStoreAccessService.requireStoreAccess(userId, posFood.getMdid());
  103. } else {
  104. PosFood existing = merchantStoreAccessService.requireFoodAccess(userId, posFood.getId());
  105. posFood.setMdid(existing.getMdid());
  106. }
  107. Boolean org = posFoodService.saveOrUpdate(posFood);
  108. if (!org) {
  109. return error();
  110. }
  111. handleFoodSpec(posFood);
  112. return success();
  113. }
  114. @Anonymous
  115. @Auth(session = true)
  116. @PostMapping("/menu-copy/preview")
  117. public AjaxResult menuCopyPreview(@RequestHeader String token,
  118. @RequestBody StoreMenuCopyPreviewRequest request) {
  119. return success(storeMenuCopyService.preview(AuthContext.requireUserId(), request));
  120. }
  121. @Anonymous
  122. @Auth(session = true)
  123. @PostMapping("/menu-copy/execute")
  124. public AjaxResult menuCopyExecute(@RequestHeader String token,
  125. @RequestBody StoreMenuCopyExecuteRequest request) {
  126. return success(storeMenuCopyService.execute(AuthContext.requireUserId(), request));
  127. }
  128. /**
  129. * (h5页面使用)通过分类查询商品列表
  130. */
  131. @Anonymous
  132. @GetMapping("/h5Getidlist")
  133. public AjaxResult h5Getidlist(@RequestParam Integer id, @RequestParam(defaultValue = "") String language, @RequestParam(required = false) String stackingUp) {
  134. JwtUtil jwtUtil = new JwtUtil();
  135. // String ids = jwtUtil.getusid(token);
  136. // InfoUser user = infoUserService.getById(ids);
  137. QueryWrapper<PosFood> queryWrapper = new QueryWrapper<>();
  138. queryWrapper.eq("fl_id", id);
  139. // if(!user.getUserType().equals("1")){
  140. // queryWrapper.eq("to_examine","1");
  141. // }
  142. if (stackingUp != null && !"".equals(stackingUp)) {
  143. queryWrapper.eq("stacking_up", stackingUp);
  144. }
  145. String lang = "3";
  146. if (!"".equals(language)) {
  147. lang = language;
  148. }
  149. queryWrapper.eq("language", lang);
  150. List<PosFood> list = posFoodService.list(queryWrapper);
  151. List<Long> __foodIds = list.stream().map(PosFood::getId).collect(Collectors.toList());
  152. Map<Long, List<FoodSpecs>> __specMap = loadFoodSpecsMap(__foodIds);
  153. JSONArray all = new JSONArray();
  154. for (int i = 0; i < list.size(); i++) {
  155. JSONObject org = new JSONObject();
  156. org.put("id", list.get(i).getId());
  157. org.put("fenlei", posFenleiService.getById(list.get(i).getFlId()));
  158. org.put("store", posStoreService.getById(list.get(i).getMdid()));
  159. org.put("name", list.get(i).getName());
  160. org.put("image", list.get(i).getImage());
  161. org.put("price", list.get(i).getPrice());
  162. org.put("introduce", list.get(i).getIntroduce());
  163. org.put("recommend", list.get(i).getRecommend());
  164. List<FoodSpecs> __fs = __specMap.getOrDefault(list.get(i).getId(), new ArrayList<>());
  165. org.put("foodSpecs", __fs);
  166. org.put("foodSku", __fs.isEmpty() ? JSONArray.parseArray(list.get(i).getFoodSku()) : buildFoodSkuArray(__fs));
  167. org.put("stackingUp", list.get(i).getStackingUp());
  168. org.put("toExamine", list.get(i).getToExamine());
  169. all.add(org);
  170. }
  171. return success(all);
  172. }
  173. /**
  174. * 通过分类查询商品列表
  175. */
  176. @Anonymous
  177. @Auth(session = true)
  178. @GetMapping("/getidlist")
  179. public AjaxResult getidlist(@RequestHeader String token, @RequestParam Integer id, @RequestParam(defaultValue = "") String language, @RequestParam(required = false) String stackingUp, @RequestParam(required = false) String name) {
  180. Long userId = AuthContext.requireUserId();
  181. InfoUser user = infoUserService.getById(userId);
  182. PosFenlei category = posFenleiService.getById(id);
  183. if (category != null && ("1".equals(user.getUserType()) || "5".equals(user.getUserType()))) {
  184. merchantStoreAccessService.requireStoreAccess(userId, category.getMendid());
  185. }
  186. QueryWrapper<PosFood> queryWrapper = new QueryWrapper<>();
  187. queryWrapper.eq("fl_id", id);
  188. //普通用户显示审核通过的
  189. if("0".equals(user.getUserType())){
  190. queryWrapper.eq("to_examine", "1");
  191. }
  192. queryWrapper.ne("stacking_up", "1");
  193. if (stackingUp != null && !"".equals(stackingUp)) {
  194. queryWrapper.eq("stacking_up", stackingUp);
  195. }
  196. String lang = "3";
  197. if (!"".equals(language)) {
  198. lang = language;
  199. }
  200. queryWrapper.eq("language", lang);
  201. if (name != null && !"".equals(name)) {
  202. queryWrapper.apply(" BINARY name LIKE CONCAT('%', {0}, '%')", name);
  203. }
  204. List<PosFood> list = posFoodService.list(queryWrapper);
  205. List<Long> __foodIds = list.stream().map(PosFood::getId).collect(Collectors.toList());
  206. Map<Long, List<FoodSpecs>> __specMap = loadFoodSpecsMap(__foodIds);
  207. JSONArray all = new JSONArray();
  208. for (int i = 0; i < list.size(); i++) {
  209. JSONObject org = new JSONObject();
  210. org.put("id", list.get(i).getId());
  211. org.put("fenlei", posFenleiService.getById(list.get(i).getFlId()));
  212. PosStore store = posStoreService.getById(list.get(i).getMdid());
  213. fillStallLocation(store);
  214. org.put("store", store);
  215. org.put("canInvoice", orderInvoiceService.canInvoice(list.get(i).getMdid()));
  216. org.put("name", list.get(i).getName());
  217. org.put("image", list.get(i).getImage());
  218. org.put("price", list.get(i).getPrice());
  219. org.put("introduce", list.get(i).getIntroduce());
  220. org.put("recommend", list.get(i).getRecommend());
  221. List<FoodSpecs> __fs = __specMap.getOrDefault(list.get(i).getId(), new ArrayList<>());
  222. org.put("foodSpecs", __fs);
  223. org.put("foodSku", __fs.isEmpty() ? JSONArray.parseArray(list.get(i).getFoodSku()) : buildFoodSkuArray(__fs));
  224. org.put("stackingUp", list.get(i).getStackingUp());
  225. org.put("toExamine", list.get(i).getToExamine());
  226. all.add(org);
  227. }
  228. return success(all);
  229. }
  230. /**
  231. * 查询商品详情
  232. */
  233. @Anonymous
  234. @GetMapping("/getfood")
  235. public AjaxResult getfood(@RequestParam Integer id) {
  236. JSONObject org = new JSONObject();
  237. PosFood posFood = posFoodService.getById(id);
  238. List<Long> __foodIds = new ArrayList<>();
  239. __foodIds.add(posFood.getId());
  240. Map<Long, List<FoodSpecs>> __specMap = loadFoodSpecsMap(__foodIds);
  241. List<FoodSpecs> __fs = __specMap.getOrDefault(posFood.getId(), new ArrayList<>());
  242. org.put("id", posFood.getId());
  243. org.put("fenlei", posFenleiService.getById(posFood.getFlId()));
  244. PosStore store = posStoreService.getById(posFood.getMdid());
  245. fillStallLocation(store);
  246. org.put("store", store);
  247. org.put("canInvoice", orderInvoiceService.canInvoice(posFood.getMdid()));
  248. org.put("name", posFood.getName());
  249. org.put("image", posFood.getImage());
  250. org.put("price", posFood.getPrice());
  251. org.put("introduce", posFood.getIntroduce());
  252. org.put("recommend", posFood.getRecommend());
  253. org.put("stackingUp", posFood.getStackingUp());
  254. org.put("foodSpecs", __fs);
  255. org.put("foodSku", __fs.isEmpty() ? JSONArray.parseArray(posFood.getFoodSku()) : buildFoodSkuArray(__fs));
  256. return success(org);
  257. }
  258. /**
  259. * 搜索
  260. */
  261. @Anonymous
  262. @GetMapping("/searchfor")
  263. public AjaxResult searchfor(@RequestParam String keyword, @RequestParam(defaultValue = "") String language) {
  264. if (keyword.equals("")) {
  265. return error(MessageUtils.message("no.tip.lock.keywork"));
  266. }
  267. JSONArray all = new JSONArray();
  268. JSONObject object = new JSONObject();
  269. QueryWrapper<PosFood> query = new QueryWrapper<>();
  270. String lang = "3";
  271. if (!"".equals(language)) {
  272. lang = language;
  273. }
  274. query.eq("language", lang);
  275. query.eq("to_examine", "1");
  276. // query.like("name",keyword);
  277. query.apply("BINARY name LIKE CONCAT('%', {0}, '%')", keyword);
  278. List<PosFood> folist = posFoodService.list(query);
  279. QueryWrapper<PosStore> wrapper = new QueryWrapper<>();
  280. wrapper.eq("off_shelf", "0")
  281. // .and(i->i.like("pos_name", keyword).or().like("brief_introduction",keyword));
  282. .and(i -> i.apply("BINARY pos_name LIKE CONCAT('%', {0}, '%')", keyword).or().apply("BINARY brief_introduction LIKE CONCAT('%', {0}, '%')", keyword));
  283. List<PosStore> stlist = posStoreService.list(wrapper);
  284. for (int i = 0; i < folist.size(); i++) {
  285. PosStore store = posStoreService.getById(folist.get(i).getMdid());
  286. if (store.getOffShelf().equals("0")) {
  287. JSONObject org = new JSONObject();
  288. org.put("id", folist.get(i).getId());
  289. org.put("fenlei", posFenleiService.getById(folist.get(i).getFlId()));
  290. org.put("store", posStoreService.getById(folist.get(i).getMdid()));
  291. org.put("name", folist.get(i).getName());
  292. org.put("image", folist.get(i).getImage());
  293. org.put("price", folist.get(i).getPrice());
  294. org.put("introduce", folist.get(i).getIntroduce());
  295. org.put("recommend", folist.get(i).getRecommend());
  296. org.put("stackingUp", folist.get(i).getStackingUp());
  297. org.put("foodSku", JSONArray.parseArray(folist.get(i).getFoodSku()));
  298. all.add(org);
  299. }
  300. }
  301. object.put("food", all);
  302. object.put("store", stlist);
  303. return success(object);
  304. }
  305. /**
  306. * 客户端查询美食
  307. *
  308. * @param keyword
  309. * @param language
  310. * @return
  311. */
  312. @Anonymous
  313. @GetMapping("/foodSearch")
  314. public AjaxResult foodSearch(@RequestParam String keyword, @RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam(defaultValue = "") String language) {
  315. if (keyword.isEmpty()) {
  316. return error(MessageUtils.message("no.tip.lock.keywork"));
  317. }
  318. // 设置默认分页参数
  319. if (pageNum == null || pageNum < 1) {
  320. pageNum = 1;
  321. }
  322. if (pageSize == null || pageSize < 1) {
  323. pageSize = 10;
  324. }
  325. String lang = "3";
  326. if (!"".equals(language)) {
  327. lang = language;
  328. }
  329. // 创建分页对象
  330. Page<PosStore> page = new Page<>(pageNum, pageSize);
  331. // 1. 先通过联表查询获取分页的店铺列表(包含总数)
  332. IPage<PosStore> storePage = posStoreMapper.selectStoresByFoodKeyword(page, keyword, lang);
  333. List<PosStore> stores = storePage.getRecords();
  334. List<FoodSearchOutput> result = new ArrayList<>();
  335. Map<Long, List<PosReview>> reviewMap = Collections.emptyMap();
  336. Map<Long, Long> orderCountMap = Collections.emptyMap();
  337. List<OperatingHours> hourslist=new ArrayList<>();
  338. // 2. 一次性查询所有相关商品(避免循环查询数据库)
  339. if (!stores.isEmpty()) {
  340. // 提取所有店铺ID
  341. List<Long> storeIds = stores.stream()
  342. .map(store -> store.getId().longValue())
  343. .collect(Collectors.toList());
  344. // 一次性查询所有店铺下匹配关键词的商品
  345. QueryWrapper<PosFood> foodQuery = new QueryWrapper<>();
  346. foodQuery.in("mdid", storeIds)
  347. .eq("language", lang)
  348. .eq("to_examine", "1")
  349. .apply(" CONCAT(name, ' ') LIKE CONCAT('%', {0}, '%') COLLATE utf8mb4_unicode_ci", keyword);
  350. List<PosFood> allFoods = posFoodService.list(foodQuery);
  351. {
  352. List<Long> __foodIds = allFoods.stream().map(PosFood::getId).collect(Collectors.toList());
  353. Map<Long, List<FoodSpecs>> __specMap = loadFoodSpecsMap(__foodIds);
  354. for (PosFood __f : allFoods) {
  355. __f.setFoodSpecs(__specMap.getOrDefault(__f.getId(), new ArrayList<>()));
  356. }
  357. }
  358. // 按店铺ID分组商品
  359. Map<Long, List<PosFood>> foodsByStore = allFoods.stream()
  360. .collect(Collectors.groupingBy(PosFood::getMdid));
  361. posStoreEnrichService.enrichStoreList(stores);
  362. // 3. 为每个店铺设置对应的商品
  363. for (PosStore store : stores) {
  364. FoodSearchOutput output = new FoodSearchOutput();
  365. output.setPosStore(store);
  366. // 从分组结果中获取该店铺的商品
  367. List<PosFood> storeFoods = foodsByStore.getOrDefault(store.getId().longValue(), new ArrayList<>());
  368. output.setPosFoodList(storeFoods);
  369. result.add(output);
  370. }
  371. }
  372. // 3. 返回分页结果
  373. Map<String, Object> response = new HashMap<>();
  374. response.put("list", result);
  375. response.put("total", storePage.getTotal());
  376. return success(response);
  377. }
  378. /**
  379. * 客户端查询门店
  380. *
  381. * @param keyword
  382. * @param language
  383. * @return
  384. */
  385. @Anonymous
  386. @GetMapping("/storeSearch")
  387. public AjaxResult storeSearch(@RequestParam String keyword, @RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam(defaultValue = "") String language) {
  388. if (keyword.isEmpty()) {
  389. return error(MessageUtils.message("no.tip.lock.keywork"));
  390. }
  391. QueryWrapper<PosFood> query = new QueryWrapper<>();
  392. // 设置默认分页参数
  393. if (pageNum == null || pageNum < 1) {
  394. pageNum = 1;
  395. }
  396. if (pageSize == null || pageSize < 1) {
  397. pageSize = 10;
  398. }
  399. Page<PosStore> page = new Page<>(pageNum, pageSize);
  400. QueryWrapper<PosStore> storeWrapper = new QueryWrapper<>();
  401. String finalKeyword = keyword;
  402. storeWrapper.eq("off_shelf", "0")
  403. // .and(i->i.like("pos_name", keyword).or().like("brief_introduction",keyword));
  404. .and(i -> i.apply(" CONCAT(pos_name,' ') LIKE CONCAT('%', {0}, '%') COLLATE utf8mb4_unicode_ci", finalKeyword).or().apply(" CONCAT(brief_introduction,' ') LIKE CONCAT('%', {0}, '%') COLLATE utf8mb4_unicode_ci", finalKeyword));
  405. IPage<PosStore> data = posStoreService.page(page, storeWrapper);
  406. Map<String, Object> response = new HashMap<>();
  407. List<PosStore> stores=data.getRecords();
  408. posStoreEnrichService.enrichStoreList(stores);
  409. response.put("list", stores);
  410. response.put("total", data.getTotal());
  411. return success(response);
  412. }
  413. @Anonymous
  414. @Auth(session = true)
  415. @GetMapping("/getFoodPageList")
  416. public AjaxResult getFoodPageList(@RequestHeader String token,
  417. @RequestParam Integer page,
  418. @RequestParam Integer size,
  419. @RequestParam Long flId,
  420. @RequestParam Long mdId,
  421. @RequestParam(defaultValue = "") String language,
  422. @RequestParam(defaultValue = "") String name) {
  423. Long id = AuthContext.requireUserId();
  424. merchantStoreAccessService.requireStoreAccess(id, mdId);
  425. IPage<PosFood> stlist = new Page<>(page, size);
  426. LambdaQueryWrapper<PosFood> queryWrapper = new LambdaQueryWrapper<>();
  427. queryWrapper.eq(PosFood::getFlId, flId);
  428. queryWrapper.eq(PosFood::getMdid, mdId);
  429. // language 不为 null 且不为空字符串时才加条件
  430. if (language != null && !"".equals(language)) {
  431. queryWrapper.eq(PosFood::getLanguage, language);
  432. }
  433. // name 不为 null 且不为空字符串时模糊查询
  434. if (name != null && !"".equals(name)) {
  435. queryWrapper.like(PosFood::getName, name);
  436. }
  437. IPage<PosFood> list = posFoodService.page(stlist, queryWrapper);
  438. return success(list);
  439. }
  440. /**
  441. * C端扫码:获取摊位商品列表(摊位码扫码入口)
  442. */
  443. @Anonymous
  444. @GetMapping("/stallFoodList")
  445. public AjaxResult stallFoodList(@RequestParam Long storeId,
  446. @RequestParam(required = false) Long flId,
  447. @RequestParam Integer page,
  448. @RequestParam Integer size,
  449. @RequestParam(required = false) Long tableId) {
  450. IPage<PosFood> foodPage = new Page<>(page, size);
  451. QueryWrapper<PosFood> queryWrapper = new QueryWrapper<>();
  452. queryWrapper.eq("mdid", storeId);
  453. queryWrapper.eq("to_examine", "1");
  454. queryWrapper.eq("stacking_up", "1");
  455. if (flId != null) {
  456. queryWrapper.eq("fl_id", flId);
  457. }
  458. IPage<PosFood> result = posFoodService.page(foodPage, queryWrapper);
  459. List<Long> __foodIds = result.getRecords().stream().map(PosFood::getId).collect(Collectors.toList());
  460. Map<Long, List<FoodSpecs>> __specMap = loadFoodSpecsMap(__foodIds);
  461. for (PosFood __f : result.getRecords()) {
  462. __f.setFoodSpecs(__specMap.getOrDefault(__f.getId(), new ArrayList<>()));
  463. }
  464. return success(result);
  465. }
  466. /**
  467. * 查询商品列表
  468. */
  469. @Anonymous
  470. @GetMapping("/getfoodlist")
  471. public AjaxResult getfoodlist(@RequestParam Integer page,
  472. @RequestParam Integer size,
  473. @RequestParam(defaultValue = "") String language,
  474. @RequestParam(defaultValue = "") String keyword) {
  475. IPage<PosFood> food = new Page<>(page, size);
  476. QueryWrapper<PosFood> queryWrapper = new QueryWrapper<>();
  477. String lang = "3";
  478. if (!"".equals(language)) {
  479. lang = language;
  480. }
  481. queryWrapper.eq("language", lang);
  482. queryWrapper.eq("to_examine", "1");
  483. if (!"".equals(keyword)) {
  484. queryWrapper.like("name", keyword);
  485. }
  486. IPage<PosFood> list = posFoodService.page(food, queryWrapper);
  487. List<PosFood> foodlist = list.getRecords();
  488. JSONArray all = new JSONArray();
  489. for (int i = 0; i < foodlist.size(); i++) {
  490. PosStore store = posStoreService.getById(foodlist.get(i).getMdid());
  491. if (store.getOffShelf().equals("0")) {
  492. JSONObject org = new JSONObject();
  493. org.put("id", foodlist.get(i).getId());
  494. org.put("fenlei", posFenleiService.getById(foodlist.get(i).getFlId()));
  495. org.put("store", posStoreService.getById(foodlist.get(i).getMdid()));
  496. org.put("name", foodlist.get(i).getName());
  497. org.put("image", foodlist.get(i).getImage());
  498. org.put("price", foodlist.get(i).getPrice());
  499. org.put("introduce", foodlist.get(i).getIntroduce());
  500. org.put("recommend", foodlist.get(i).getRecommend());
  501. org.put("stackingUp", foodlist.get(i).getStackingUp());
  502. org.put("foodSku", JSONArray.parseArray(foodlist.get(i).getFoodSku()));
  503. all.add(org);
  504. }
  505. }
  506. return success(all);
  507. }
  508. /**
  509. * 查询food列表
  510. */
  511. @PreAuthorize("@ss.hasPermi('chanting:food:list')")
  512. @GetMapping("/list")
  513. public TableDataInfo list(PosFood posFood) {
  514. startPage();
  515. List<PosFood> list = posFoodService.selectPosFoodList(posFood);
  516. return getDataTable(list);
  517. }
  518. /**
  519. * 导出food列表
  520. */
  521. @PreAuthorize("@ss.hasPermi('chanting:food:export')")
  522. @Log(title = "food", businessType = BusinessType.EXPORT)
  523. @PostMapping("/export")
  524. public void export(HttpServletResponse response, PosFood posFood) {
  525. List<PosFood> list = posFoodService.selectPosFoodList(posFood);
  526. ExcelUtil<PosFood> util = new ExcelUtil<PosFood>(PosFood.class);
  527. util.exportExcel(response, list, MessageUtils.message("no.export.excel.food"));
  528. }
  529. /**
  530. * 获取food详细信息
  531. */
  532. @Anonymous
  533. @GetMapping(value = "/{id}")
  534. public AjaxResult getInfo(@PathVariable("id") Long id) {
  535. return success(posFoodService.selectPosFoodById(id));
  536. }
  537. /**
  538. * 新增food
  539. */
  540. @PreAuthorize("@ss.hasPermi('chanting:food:add')")
  541. @Log(title = "food", businessType = BusinessType.INSERT)
  542. @PostMapping
  543. public AjaxResult add(@RequestBody PosFood posFood) {
  544. int rows = posFoodService.insertPosFood(posFood);
  545. if (rows > 0) {
  546. handleFoodSpec(posFood);
  547. }
  548. return toAjax(rows);
  549. }
  550. /**
  551. * 修改food
  552. */
  553. @PreAuthorize("@ss.hasPermi('chanting:food:edit')")
  554. @Log(title = "food", businessType = BusinessType.UPDATE)
  555. @PutMapping
  556. public AjaxResult edit(@RequestBody PosFood posFood) {
  557. int rows = posFoodService.updatePosFood(posFood);
  558. if (rows > 0) {
  559. handleFoodSpec(posFood);
  560. }
  561. return toAjax(rows);
  562. }
  563. /**
  564. * 删除food
  565. */
  566. @PreAuthorize("@ss.hasPermi('chanting:food:remove')")
  567. @Log(title = "food", businessType = BusinessType.DELETE)
  568. @DeleteMapping("/{ids}")
  569. public AjaxResult remove(@PathVariable Long[] ids) {
  570. return toAjax(posFoodService.deletePosFoodByIds(ids));
  571. }
  572. /**
  573. * 压缩图片店铺的商品图片
  574. */
  575. @Anonymous
  576. @GetMapping("/compressFoodImage")
  577. public AjaxResult compressFoodImage(@RequestParam Long mdId, @RequestParam String idsStr) {
  578. LambdaQueryWrapper<PosFood> queryWrapper = new LambdaQueryWrapper<>();
  579. queryWrapper.eq(PosFood::getMdid, mdId);
  580. List<Long> ids= new ArrayList<>();
  581. if(!StringUtils.isEmpty(idsStr)){
  582. ids = Arrays.stream(idsStr.split(","))
  583. .map(Long::valueOf)
  584. .collect(Collectors.toList());
  585. }
  586. queryWrapper.in(!ids.isEmpty(), PosFood::getId, ids);
  587. List<PosFood> list = posFoodService.list(queryWrapper);
  588. AtomicInteger count = new AtomicInteger();
  589. list.forEach(food -> {
  590. String compressImage = ImageCompressUtils.compressImageByWebPath(food.getImage());
  591. if (!compressImage.equals(food.getImage())) {
  592. food.setImage(compressImage);
  593. PosFood posFood = new PosFood();
  594. posFood.setId(food.getId());
  595. posFood.setImage(compressImage);
  596. posFoodService.saveOrUpdate(posFood);
  597. count.getAndIncrement();
  598. System.out.println("food成功压缩的图片数量:"+count.get());
  599. logger.info("food成功压缩的图片数量:"+count.get());
  600. }
  601. });
  602. return success("成功压缩的 :"+count.get());
  603. }
  604. /**
  605. * 压缩所有的商品图片
  606. */
  607. @Anonymous
  608. @GetMapping("/compressFoodImageAll")
  609. public AjaxResult compressFoodImage() {
  610. LambdaQueryWrapper<PosFood> queryWrapper = new LambdaQueryWrapper<>();
  611. List<PosFood> list = posFoodService.list(queryWrapper);
  612. AtomicInteger count = new AtomicInteger();
  613. list.forEach(food -> {
  614. String compressImage = ImageCompressUtils.compressImageByWebPath(food.getImage());
  615. if (!compressImage.equals(food.getImage())) {
  616. food.setImage(compressImage);
  617. PosFood posFood = new PosFood();
  618. posFood.setId(food.getId());
  619. posFood.setImage(compressImage);
  620. posFoodService.saveOrUpdate(posFood);
  621. count.getAndIncrement();
  622. System.out.println("food成功压缩的图片数量:"+count.get());
  623. logger.info("food成功压缩的图片数量:"+count.get());
  624. }
  625. });
  626. return success("成功压缩的图片数量:"+count.get());
  627. }
  628. /**
  629. * 当门店是摊位时,用夜市的经纬度覆盖摊位的经纬度
  630. */
  631. /**
  632. * 保存商品规格:sku JSON 写 food_sku(落库) -> 删除旧关联 -> 按 foodSpecs 建立新关联
  633. */
  634. private void handleFoodSpec(PosFood posFood) {
  635. if (posFood == null || posFood.getId() == null) {
  636. return;
  637. }
  638. JSONArray sku = posFood.getSku();
  639. if (sku != null) {
  640. PosFood upd = new PosFood();
  641. upd.setId(posFood.getId());
  642. upd.setFoodSku(sku.toString());
  643. posFoodService.updateById(upd);
  644. posFood.setFoodSku(sku.toString());
  645. }
  646. foodSpecRelationService.remove(new LambdaQueryWrapper<FoodSpecRelation>()
  647. .eq(FoodSpecRelation::getFoodId, posFood.getId()));
  648. List<FoodSpecs> foodSpecs = posFood.getFoodSpecs();
  649. if (foodSpecs != null && !foodSpecs.isEmpty()) {
  650. List<FoodSpecRelation> rels = foodSpecs.stream()
  651. .filter(sp -> sp.getId() != null && sp.getId() > 0)
  652. .map(sp -> {
  653. FoodSpecRelation r = new FoodSpecRelation();
  654. r.setFoodId(posFood.getId());
  655. r.setSpecsId(sp.getId());
  656. return r;
  657. }).collect(Collectors.toList());
  658. if (!rels.isEmpty()) {
  659. foodSpecRelationService.saveBatch(rels);
  660. }
  661. }
  662. }
  663. /**
  664. * 批量查询商品规格(避免 N+1):关联 -> 启用规格组 -> 启用规格值 -> 内存分组
  665. * @return foodId -> 规格组列表(含启用规格值)
  666. */
  667. private Map<Long, List<FoodSpecs>> loadFoodSpecsMap(List<Long> foodIds) {
  668. Map<Long, List<FoodSpecs>> result = new HashMap<>();
  669. if (foodIds == null || foodIds.isEmpty()) {
  670. return result;
  671. }
  672. List<FoodSpecRelation> rels = foodSpecRelationService.list(new LambdaQueryWrapper<FoodSpecRelation>()
  673. .in(FoodSpecRelation::getFoodId, foodIds));
  674. if (rels.isEmpty()) {
  675. return result;
  676. }
  677. Map<Long, List<Long>> foodToSpecIds = rels.stream()
  678. .collect(Collectors.groupingBy(FoodSpecRelation::getFoodId,
  679. Collectors.mapping(FoodSpecRelation::getSpecsId, Collectors.toList())));
  680. List<Long> specsIds = rels.stream().map(FoodSpecRelation::getSpecsId).distinct().collect(Collectors.toList());
  681. List<FoodSpecs> specsList = foodSpecsService.list(new LambdaQueryWrapper<FoodSpecs>()
  682. .in(FoodSpecs::getId, specsIds)
  683. .eq(FoodSpecs::getIsOpen, true)
  684. .eq(FoodSpecs::getIsDelete, false)
  685. .orderByAsc(FoodSpecs::getSort));
  686. if (specsList.isEmpty()) {
  687. return result;
  688. }
  689. List<Long> enabledSpecIds = specsList.stream().map(FoodSpecs::getId).collect(Collectors.toList());
  690. List<FoodSpecsValue> values = foodSpecsValueService.list(new LambdaQueryWrapper<FoodSpecsValue>()
  691. .in(FoodSpecsValue::getParentId, enabledSpecIds)
  692. .eq(FoodSpecsValue::getIsOpen, true)
  693. .orderByAsc(FoodSpecsValue::getId));
  694. Map<Long, List<FoodSpecsValue>> valueMap = values.stream()
  695. .collect(Collectors.groupingBy(FoodSpecsValue::getParentId));
  696. Map<Long, FoodSpecs> specsMap = specsList.stream().collect(Collectors.toMap(FoodSpecs::getId, sp -> sp));
  697. for (Map.Entry<Long, List<Long>> entry : foodToSpecIds.entrySet()) {
  698. List<FoodSpecs> fsList = new ArrayList<>();
  699. for (Long sid : entry.getValue()) {
  700. FoodSpecs src = specsMap.get(sid);
  701. if (src != null) {
  702. FoodSpecs copy = new FoodSpecs();
  703. copy.setId(src.getId());
  704. copy.setTitle(src.getTitle());
  705. copy.setType(src.getType());
  706. copy.setState(src.getState());
  707. copy.setLanguage(src.getLanguage());
  708. copy.setRemark(src.getRemark());
  709. copy.setMdId(src.getMdId());
  710. copy.setSort(src.getSort());
  711. copy.setIsOpen(src.getIsOpen());
  712. copy.setIsDelete(src.getIsDelete());
  713. copy.setObjects(valueMap.getOrDefault(src.getId(), new ArrayList<>()));
  714. fsList.add(copy);
  715. }
  716. }
  717. result.put(entry.getKey(), fsList);
  718. }
  719. return result;
  720. }
  721. /**
  722. * 由结构化规格构建兼容的 food_sku JSON 数组(明细字段名 foodSpecsItems)
  723. */
  724. private JSONArray buildFoodSkuArray(List<FoodSpecs> fsList) {
  725. JSONArray skuArr = new JSONArray();
  726. if (fsList == null || fsList.isEmpty()) {
  727. return skuArr;
  728. }
  729. for (FoodSpecs s : fsList) {
  730. skuArr.add(JSONObject.toJSON(s));
  731. }
  732. return skuArr;
  733. }
  734. private void fillStallLocation(PosStore store) {
  735. if (store != null && store.getIsStall() != null && store.getIsStall() == 1
  736. && store.getNightMarketId() != null) {
  737. InfoUser nightMarket = infoUserService.getById(store.getNightMarketId());
  738. if (nightMarket != null) {
  739. store.setLongitude(nightMarket.getLongitude());
  740. store.setLatitude(nightMarket.getLatitude());
  741. }
  742. }
  743. }
  744. }