Cart.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <?php
  2. namespace app\controller\api;
  3. use app\extra\basic\Base;
  4. use app\middleware\WxMiddleware;
  5. use app\model\saas\SaasCart;
  6. use app\model\saas\SaasCombo;
  7. use app\model\saas\SaasDiscount;
  8. use app\model\saas\SaasPrice;
  9. use app\model\saas\SaasPrintClient;
  10. use app\model\saas\SaasShop;
  11. use app\model\saas\SaasUser;
  12. use app\model\saas\SaasUserBuy;
  13. use LinFly\Annotation\Route\Controller;
  14. use LinFly\Annotation\Route\Middleware;
  15. use LinFly\Annotation\Route\Route;
  16. use Qcloud\Cos\Client;
  17. use support\Request;
  18. use support\Response;
  19. use yzh52521\EasyHttp\Http;
  20. #[Controller(prefix: "/wx_api/cart"),Middleware(WxMiddleware::class)]
  21. class Cart extends Base
  22. {
  23. protected array $noNeedLogin = [];
  24. /**
  25. * 颜色
  26. * @var array|string[]
  27. */
  28. protected array $color = ["1" => "彩色", "2" => "黑白"];
  29. /**
  30. * 单双面
  31. * @var array|string[]
  32. */
  33. protected array $duplex = ["1" => "单面", "2" => "双面"];
  34. /**
  35. * 打印方向
  36. * @var array|string[]
  37. */
  38. protected array $direction = ["1" => "自适应","2" => "横向", "3" => "竖向"];
  39. /**
  40. * 配送方式
  41. * @var array|string[]
  42. */
  43. protected array $package = ["1" => "店内打印", "2" => '远程自取' , "3" => "商家配送"];
  44. protected array $types = [
  45. '1_1_1' => ['name' => '彩色-单面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  46. '1_1_2' => ['name' => '彩色-单面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  47. '1_2_1' => ['name' => '彩色-双面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  48. '2_1_1' => ['name' => '黑白-单面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  49. '2_2_1' => ['name' => '黑白-双面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  50. '2_1_2' => ['name' => '黑白-双面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  51. ];
  52. /**
  53. * 获取打印购物车列表
  54. * @return Response
  55. */
  56. #[Route(path: "list",methods: "get")]
  57. public function getCartList(Request $request): Response
  58. {
  59. try {
  60. $param = $this->_valid([
  61. "shop.require" => trans("empty.require"),
  62. "print.require" => trans("empty.require"),
  63. "type.default" => 1
  64. ]);
  65. if (!is_array($param)) return error($param);
  66. $cart = (new SaasCart)->where("shop_id",$param['shop'])->where("openid",$request->user['openid'])->order("create_at desc")->select();
  67. if ($cart->isEmpty()) return success('ok',['cart' => []]);
  68. $totalAmount = $totalDiscount = 0;
  69. foreach ($cart as $k=>$v){
  70. $key = $v['color'] . '_' . $v['duplex'] . '_' . $v['source'];
  71. if (isset($this->types[$key])) {
  72. $this->types[$key]['quantity'] += $v['page'];
  73. $this->types[$key]['amount'] += $v['money'];
  74. }
  75. $cart[$k] = $v;
  76. $cart[$k]['money'] = format_money($v['money'] / 100,2);
  77. $cart[$k]['name'] = msubstr($v['name'],0,12);
  78. }
  79. $printData = (new SaasPrintClient)->where("shop_id",$param['shop'])->where("code",$param['print'])->select();
  80. if ($printData->isEmpty()) return error('无可用打印机');
  81. $rule = [];
  82. foreach ($printData as $key=>$value) {
  83. $rule[$key]['check'] = 0;
  84. $nameColor = "";
  85. if (empty($value['rule'])) return error("尚未配置打印机~");
  86. foreach ($value['rule']['color'] as $key2=>$val) {
  87. $rule[$key]['color'][$key2][$val] = $this->color[$val];
  88. $nameColor .= $this->color[$val];
  89. }
  90. foreach ($value['rule']['direction'] as $key2=>$val) {
  91. $rule[$key]['direction'][$key2][$val] = $this->direction[$val];
  92. }
  93. foreach ($value['rule']['duplex'] as $key2=>$val) {
  94. $rule[$key]['duplex'][$key2][$val] = $this->duplex[$val];
  95. }
  96. foreach ($value['rule']['package'] as $key2=>$val) {
  97. $rule[$key]['package'][$key2][$val] = $this->package[$val];
  98. }
  99. foreach ($value['rule']['paper_size'] as $key2=>$val) {
  100. $rule[$key]['paper_size'][$key2][$val] = $val;
  101. }
  102. if ($param['print'] == $value['code']) {
  103. $rule[$key]['check'] = 1;
  104. }
  105. $rule[$key]['name'] = $nameColor."-".$value['name'];
  106. $rule[$key]['code'] = $value['code'];
  107. }
  108. // 计算折扣
  109. foreach ($this->types as $k=>$v) {
  110. $discount = (new SaasDiscount)->where("shop_id",$param['shop'])->where("keys",$k)->where("number",'<',$v['quantity'])->findOrEmpty();
  111. if (!$discount->isEmpty()) {
  112. $v['discount'] = round($v['amount'] * $discount['rate']);
  113. $this->types[$k]['discount'] = $v['discount'];
  114. }
  115. $totalAmount += $v['amount'];
  116. $totalDiscount += $v['discount'];
  117. }
  118. $totalAmount = format_money($totalAmount / 100,2);
  119. $totalDiscount = format_money($totalDiscount / 100,2);
  120. if ($param['type'] <> 1) {
  121. $shop = (new SaasShop)->where("shop_id",$param['shop'])->field("shop_name,shop_address,user_card,user_card_price")->find();
  122. $isRecharge = (new SaasUserBuy)->where("shop_id",$param['shop'])->where("openid",$request->user['openid'])->where("status",1)->sum("money");;
  123. $cardPrice = [];
  124. if ($shop['user_card'] < 3) {
  125. if ($shop['user_card'] == 2) { // 自定义套餐
  126. $cardPrice = array_values($shop['user_card_price']);
  127. } else {
  128. $cardPrice = (new SaasCombo)->where("type",2)->field("id,name,ROUND(money/100,2) as money,ROUND(old_money/100,2) as old_money,is_first")->where("status",1)->select()->toArray();
  129. }
  130. $cardPrice = array_filter($cardPrice, function($item) use ($isRecharge) {
  131. if ($isRecharge > 0) {
  132. return $item['is_first'] != '1'; // 注意:这里使用松散比较,因为数据中有字符串'1'
  133. } else {
  134. return $item;
  135. }
  136. });
  137. foreach ($cardPrice as $key=>$val) {
  138. $cardPrice[$key] = $val;
  139. $cardPrice[$key]['money'] = $val['money'];
  140. $cardPrice[$key]['old_money'] = $val['old_money'];
  141. }
  142. $cardPrice = array_values($cardPrice);
  143. }
  144. $card = (new SaasUser)->where("openid",$request->user['openid'])->where("shop_id",$param['shop'])->field("ROUND(balance/100,2) as money")->findOrEmpty();
  145. if ($card->isEmpty()) {
  146. $card = null;
  147. }
  148. $package = $this->package;
  149. return success("",compact('rule','totalAmount','totalDiscount','shop','cardPrice','package','card'));
  150. }
  151. return success("",compact('cart','rule','totalAmount','totalDiscount'));
  152. } catch (\Throwable $th) {
  153. return error($th->getMessage());
  154. }
  155. }
  156. /**
  157. * 删除购物
  158. * @param Request $request
  159. * @return Response
  160. */
  161. #[Route(path: "del",methods: "post")]
  162. public function delCart(Request $request): Response
  163. {
  164. try {
  165. $param = $this->_valid([
  166. "shop.require" => trans("empty.require"),
  167. "id.require" => trans("empty.require"),
  168. "print.require" => trans("empty.require"),
  169. ],"post");
  170. if (!is_array($param)) return error($param);
  171. $cart = (new SaasCart)->where("id",$param['id'])->findOrEmpty();
  172. if ($cart->isEmpty()) return error("操作失败");
  173. if ($cart['openid'] <> $request->user['openid']) return error("操作失败");
  174. $state = $cart->delete();
  175. if (!$state) return error("操作失败");
  176. return success("操作成功");
  177. } catch (\Throwable $exception) {
  178. return error($exception->getMessage());
  179. }
  180. }
  181. /**
  182. * 更新购物
  183. * @param Request $request
  184. * @return Response
  185. */
  186. #[Route(path: "update",methods: "post")]
  187. public function updateCart(Request $request): Response
  188. {
  189. try {
  190. $param = $request->post();
  191. $cart = (new SaasCart)->where("id",$param['id'])->where("openid",$request->user['openid'])->findOrEmpty();
  192. if ($cart->isEmpty()) return error('数据格式错误');
  193. if ($param['end_page'] > $cart['total_page']) return error('打印范围不能大于总页数');
  194. // 查询默认打印机是否有额外收费规则
  195. $printData = (new SaasPrintClient)->where("shop_id",$param['shop_id'])->where("code",$param['print'])->findOrEmpty();
  196. $extraMoney = 0;
  197. $moneyMode = (new SaasPrice)->where([
  198. "shop_id" => $param['shop_id'],
  199. "paper_size" => $param['paper_size'],
  200. "type" => $param['source'],
  201. "color" => $param['color'],
  202. "duplex" => $param['duplex'],
  203. ])->findOrEmpty();
  204. if ($moneyMode->isEmpty()) return error("尚未设置收费规则");
  205. if (!empty($printData['price']) && $printData['is_price'] == 1) {
  206. $priceRule = isset($printData['price'][$moneyMode['id']]['price']) ? $printData['price'][$moneyMode['id']]['price'] : 0;
  207. $extraMoney = $priceRule * 100;
  208. }
  209. if ($param['duplex'] == 2) {
  210. $updateData['page'] = ceil(($param['end_page'] - $param['start_page'] + 1) / 2); // 双面
  211. } else {
  212. $updateData['page'] = $param['end_page'] - $param['start_page'] + 1;
  213. }
  214. $updateData['extra_money'] = $extraMoney;
  215. $updateData['money'] = ($moneyMode['price']*100 + $extraMoney) * $updateData['page'] * $param['number'];
  216. $updateData['single_money'] = $moneyMode['price']*100;
  217. $updateData['single_id'] = $moneyMode['id'];
  218. $updateData['paper_size'] = $param['paper_size'];
  219. $updateData['number'] = $param['number'];
  220. $updateData['duplex'] = $param['duplex'];
  221. $updateData['direction'] = $param['direction']??1;
  222. $updateData['color'] = $param['color'];
  223. $updateData['start_page'] = $param['start_page'];
  224. $updateData['end_page'] = $param['end_page'];
  225. $state = $cart->save($updateData);
  226. if (!$state) return error("数据操作失败");
  227. return success("更新成功");
  228. } catch (\Throwable $exception) {
  229. return error($exception->getMessage());
  230. }
  231. }
  232. /**
  233. * 预览
  234. * @return Response
  235. */
  236. #[Route(path: "preview",methods: "post")]
  237. public function wordPreview(): Response
  238. {
  239. try {
  240. return success("",[
  241. "host" => "https://".sConf("storage.cos_http_domain")."/",
  242. "query" => "?ci-process=doc-preview&dstType=jpg&imageDpi=120&page="
  243. ]);
  244. } catch (\Throwable $th) {
  245. return error($th->getMessage());
  246. }
  247. }
  248. /**
  249. * 图片打印
  250. * @return Response
  251. */
  252. #[Route(path: "image",methods: "post")]
  253. public function uploadMultiImage(): Response
  254. {
  255. try {
  256. return success("");
  257. } catch (\Throwable $th) {
  258. return error($th->getMessage());
  259. }
  260. }
  261. /**
  262. * 文档打印
  263. * @return Response
  264. */
  265. #[Route(path: "word",methods: "post")]
  266. public function uploadWord(Request $request): Response
  267. {
  268. try {
  269. $param = $this->_valid([
  270. "shop.require" => trans("empty.require"),
  271. "word.require" => trans("empty.require"),
  272. "print.require" => trans("empty.require"),
  273. "type.default" => 1, // 1打印 2复印
  274. ],$request->method());
  275. if (!is_array($param)) return error($param);
  276. $wordData = json_decode($param["word"], true);
  277. $printData = (new SaasPrintClient)->where(['shop_id' => $param['shop'],'code' => $param['print']])->findOrEmpty();
  278. if ($printData->isEmpty()) return error('无可用打印机');
  279. $paperRule = is_string($printData['rule'])?json_decode($printData['rule'],true):$printData['rule'];
  280. $paperSize = count($paperRule['paper_size'])==1?$paperRule['paper_size'][0]:'A4';
  281. $colorSize = count($paperRule['color'])==1?$paperRule['color'][0]:2;
  282. $moneyMode = (new SaasPrice)->where(['shop_id' => $param['shop'],'paper_size' => $paperSize,'color' => $colorSize,'type' => $param['type']])->findOrEmpty();
  283. if ($moneyMode->isEmpty()) return error("店铺未设置收费规则");
  284. $extraMoney = 0;
  285. // 计算额外收费
  286. if (!empty($printData['price']) && $printData['is_price'] == 1) {
  287. $priceRule = isset($printData['price'][$moneyMode['id']]['price']) ? $printData['price'][$moneyMode['id']]['price'] : 0;
  288. $extraMoney = $priceRule * 100 ;
  289. }
  290. $cartData = [];
  291. foreach ($wordData as $key=>$val) {
  292. $cartData[$key] = [
  293. "money" => ($val['total'] * $moneyMode['price'] * 100) + ($extraMoney * $val['total']),
  294. "extra_money" => $extraMoney,
  295. "number" => 1,
  296. "duplex" => 1,
  297. "color" => $colorSize,
  298. "page" => $val['total'],
  299. "total_page" => $val['total'],
  300. "end_page" => $val['total'],
  301. "name" => $val['name'],
  302. "openid" => $request->user['openid'],
  303. "shop_id" => $param['shop'],
  304. "paper_size" => $paperSize,
  305. "extension" => $val['ext'],
  306. "source" => $param['type'],
  307. "icon" => "https://inmei-print.oss-cn-guangzhou.aliyuncs.com/extension/{$val['ext']}.png", // 图标
  308. "single_money" => $moneyMode['price'] * 100,
  309. "single_id" => $moneyMode['id'],
  310. "path" => $val['cosKey'],
  311. "print_id" => $param['print'],
  312. "print_name" => $printData['name'],
  313. ];
  314. }
  315. if (empty($cartData)) return error('上传失败');
  316. $state = (new SaasCart)->insertAll($cartData);
  317. if (!$state) return error("解析文档失败,请重试");
  318. return success("ok");
  319. } catch (\Throwable $th) {
  320. return error($th->getMessage());
  321. }
  322. }
  323. /**
  324. * 读取页码
  325. * ?ci-process=doc-preview&page=1&dstType=jpg&imageDpi=120
  326. * ?ci-process=doc-preview&page=2&sheet=1&excelPaperDirection=0
  327. */
  328. #[Route(path: "total",methods: ['post','get'])]
  329. public function checkTotal(Request $request): Response
  330. {
  331. try {
  332. $param = $this->_valid([
  333. "cosKey.require" => trans("empty.require"),
  334. ],$request->method());
  335. if (!is_array($param)) return error($param);
  336. $suffix = pathinfo($param['cosKey'], PATHINFO_EXTENSION);
  337. if (empty($suffix)) return error("empty.data.suffix");
  338. $cosClient = new Client([
  339. 'region' => sConf("storage.cos_region"),
  340. 'schema' => 'https', // 协议头部,默认为 http
  341. 'credentials' => array(
  342. 'secretId' => sConf("storage.cos_access_key"),
  343. 'secretKey' => sConf("storage.cos_secret_key"),
  344. ),
  345. "verify" => false
  346. ]);
  347. $url = $cosClient->getObjectUrl(sConf("storage.cos_bucket"), $param['cosKey']);
  348. $params = array(
  349. 'ci-process' => 'doc-preview',
  350. 'page' => 1,
  351. 'dstType' => 'jpg',
  352. 'imageDpi' => '120',
  353. );
  354. $query = http_build_query($params);
  355. $path = $url.$query;
  356. $resp = Http::get($path)->headers();
  357. if (!isset($resp['X-Total-Page'])) return error("文档可能需要密码,请先删除后再确认");
  358. $page = $resp['X-Total-Page']?$resp['X-Total-Page'][0]:1;
  359. return success("ok",compact('page'));
  360. } catch (\Throwable $th) {
  361. return error($th->getMessage());
  362. }
  363. }
  364. }