Cart.php 16 KB

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