PosFoodController.java 34 KB

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