PosFoodController.java 33 KB

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