GoodsPosterController.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. <?php
  2. /**
  3. * Created
  4. * Author: 芸众商城 www.yunzshop.com
  5. * Date: 2018/1/24
  6. * Time: 下午1:43
  7. */
  8. namespace app\frontend\modules\goods\controllers;
  9. use app\common\components\ApiController;
  10. use app\common\helpers\ImageHelper;
  11. use app\common\models\Member;
  12. use app\common\models\MemberLevel;
  13. use Setting;
  14. use app\common\services\Utils;
  15. use Yunshop\NewPoster\models\Poster;
  16. use Yunshop\NewPoster\services\CreateGoods;
  17. /**
  18. * 商品海报
  19. */
  20. class GoodsPosterController extends ApiController
  21. {
  22. private $shopSet;
  23. private $goodsModel;
  24. private $storeid;
  25. private $hotel_id;
  26. private $mid;
  27. private $type;
  28. private $ingress;
  29. private $shop_id;
  30. private $member;
  31. private $shopText = [
  32. 'left' => 75,
  33. 'top' => 50,
  34. 'type' => 1,
  35. 'size' => 24,
  36. 'max_width' => 500,
  37. 'br' => true,
  38. ];
  39. private $goodsText = [
  40. 'left' => 45,
  41. 'top' => 710,
  42. 'type' => 1,
  43. 'size' => 19,
  44. 'max_width' => 500,
  45. 'br' => false,
  46. ];
  47. /**
  48. * 字体路径
  49. *
  50. * @var string
  51. */
  52. private $fontPath;
  53. /**
  54. * 获取商品海报(前端生成)
  55. * @return \Illuminate\Http\JsonResponse
  56. */
  57. public function newGoodsPoster()
  58. {
  59. $id = intval(\YunShop::request()->id);
  60. $this->mid = \YunShop::app()->getMemberId();
  61. $this->storeid = intval(\YunShop::request()->storeid);
  62. $this->hotel_id = intval(\YunShop::request()->hotel_id);
  63. $this->shop_id = intval(\YunShop::request()->shop_id);
  64. $this->type = intval(\YunShop::request()->type);
  65. $this->member = $member = Member::uniacid()->select('uid', 'avatar', 'nickname')->ofUid(\YunShop::app()->getMemberId())->with('yzMember')->first();
  66. $goods_model = \app\common\modules\shop\ShopConfig::current()->get('goods.models.commodity_classification');
  67. $goods_model = new $goods_model;
  68. $this->goodsModel = $goods_model->uniacid()
  69. ->with(['hasOneShare', 'hasManyGoodsDiscount','hasManyOptions'])
  70. ->where('status', 1)->find($id);
  71. if (empty($this->goodsModel)) {
  72. return $this->errorJson('该商品不存在');
  73. }
  74. if (empty($this->storeid)) {
  75. $this->shopSet = \Setting::get('shop.shop');
  76. } else {
  77. if (app('plugins')->isEnabled('store-cashier') && !empty($this->storeid)) {
  78. $store = \app\common\models\Store::find($this->storeid);
  79. $this->shopSet['name'] = $store->store_name;
  80. $this->shopSet['logo'] = $store->thumb;
  81. }
  82. if (app('plugins')->isEnabled('hotel') && !empty($this->hotel_id)) {
  83. $hotel = \Yunshop\Hotel\common\models\Hotel::find($this->hotel_id);
  84. $this->shopSet['name'] = $hotel->hotel_name;
  85. $this->shopSet['logo'] = $hotel->thumb;
  86. }
  87. }
  88. if (\YunShop::plugin()->get('new-poster')) {
  89. $result = $this->newPoster();
  90. if ($result) {
  91. return $this->successJson('ok', $result);
  92. }
  93. }
  94. $thumb = yz_tomedia($this->goodsModel->thumb);
  95. if ($this->goodsModel->hasOneShare->share_thumb) {
  96. $thumb = yz_tomedia($this->goodsModel->hasOneShare->share_thumb);
  97. }
  98. $shareTitle = $this->goodsModel->title;
  99. if ($this->goodsModel->hasOneShare->share_title) {
  100. $shareTitle = $this->goodsModel->hasOneShare->share_title;
  101. }
  102. $goodsPrice = $this->goodsModel->price;
  103. if ($this->goodsModel->has_option) {
  104. //有规格
  105. $min = $this->goodsModel->hasManyOptions->min('product_price');
  106. $max = $this->goodsModel->hasManyOptions->max('product_price');
  107. if ($min == $max) {
  108. $goodsPrice = $min;
  109. } else {
  110. $goodsPrice = $min.'-'.$max;
  111. }
  112. }
  113. // 现在大于原价则为0
  114. $market_price = (int)$goodsPrice > (int)$this->goodsModel->market_price ? 0 : $this->goodsModel->market_price;
  115. return $this->successJson('请求接口成功',[
  116. 'logo' => yz_tomedia($this->shopSet['logo']),
  117. 'shopName' => $this->shopSet['name'],
  118. 'thumb' => $thumb,
  119. 'price' => $goodsPrice,
  120. 'market_price' => $market_price,
  121. 'shareTitle' => $shareTitle,
  122. 'backgroundImg'=> config('app.framework') == 'platform' ? request()->getSchemeAndHttpHost().'/static/post/images/post.png' : request()->getSchemeAndHttpHost().'/addons/yun_shop/static/post/images/post.png',
  123. 'qrcode' => $this->getCodeLink(200),
  124. 'new' => false,
  125. ]);
  126. }
  127. protected function newPoster()
  128. {
  129. $poster = Poster::uniacid()->where(['status' => 1, 'poster_type' => 15])->first();
  130. if (!$poster) {
  131. return false;
  132. }
  133. $thumb = yz_tomedia($this->goodsModel->thumb);
  134. $shareTitle = $this->goodsModel->title;
  135. if ($this->goodsModel->hasOneShare->share_title && $this->goodsModel->hasOneShare->share_thumb) {
  136. $thumb = yz_tomedia($this->goodsModel->hasOneShare->share_thumb);
  137. $shareTitle = $this->goodsModel->hasOneShare->share_title;
  138. }
  139. $default_logo = yz_tomedia($this->shopSet['logo']);
  140. $poster_style = json_decode($poster['style_data'], true);
  141. foreach ($poster_style as &$item) {
  142. $item = $this->getRealParams($item);
  143. switch ($item['type']) {
  144. case 'price' :
  145. $goodsPrice = $this->goodsModel->price;
  146. if ($this->goodsModel->has_option) {
  147. //有规格
  148. $min = $this->goodsModel->hasManyOptions->min('product_price');
  149. $max = $this->goodsModel->hasManyOptions->max('product_price');
  150. if ($min == $max) {
  151. $goodsPrice = $min;
  152. } else {
  153. $goodsPrice = $min.'-'.$max;
  154. }
  155. }
  156. $item['src'] = $goodsPrice;
  157. break;
  158. case 'market_price' :
  159. if ($this->goodsModel->market_price == 0 || $this->goodsModel->price == $this->goodsModel->market_price) {
  160. $market_price = 0;
  161. } else {
  162. $market_price = $this->goodsModel->market_price;
  163. }
  164. $item['src'] = $market_price;
  165. break;
  166. case 'member_price' :
  167. $item['src'] = $this->changeMemberGoodsPrice();
  168. break;
  169. case 'head' :
  170. if (strexists(ImageHelper::fix_wechatAvatar($this->member->avatar), 'https')) {
  171. $head = ImageHelper::fix_wechatAvatar($this->member->avatar);
  172. } else {
  173. $head = str_replace('http', 'https', ImageHelper::fix_wechatAvatar($this->member->avatar));
  174. }
  175. $item['src'] = $head;
  176. break;
  177. case 'nickname' :
  178. $item['src'] = $this->member->nickname;
  179. break;
  180. case 'title' :
  181. $item['src'] = $shareTitle;
  182. break;
  183. case 'qr' :
  184. $item['src'] = $this->getCodeLink(300) ?: yz_tomedia($this->goodsModel->thumb);
  185. break;
  186. case 'logo' :
  187. if ($item['logo_type'] == 1) {
  188. $logo = yz_tomedia($item['src']);
  189. } else {
  190. $logo = yz_tomedia($default_logo);
  191. }
  192. $item['src'] = $logo;
  193. break;
  194. case 'img' :
  195. $item['src'] = $thumb;
  196. break;
  197. case 'other_img' :
  198. $item['src'] = yz_tomedia($item['src']);
  199. break;
  200. case 'invite' :
  201. $item['src'] = $this->member->yzMember->invite_code;
  202. break;
  203. case 'mid' :
  204. $item['src'] = $this->member->uid;
  205. break;
  206. }
  207. }
  208. $background = [
  209. 'type' => $poster['color'] ? 'color' : 'background',
  210. 'src' => $poster['color'] ?: yz_tomedia($poster['background']),
  211. ];
  212. if ($background['type'] == 'background' && !$background['src']) {
  213. $background['src'] = config('app.framework') == 'platform' ? request()->getSchemeAndHttpHost().'/static/post/images/post.png' : request()->getSchemeAndHttpHost().'/addons/yun_shop/static/post/images/post.png';
  214. }
  215. return [
  216. 'poster_data' => $poster_style,
  217. 'background' => $background,
  218. 'new' => true,
  219. ];
  220. }
  221. public function generateGoodsPoster()
  222. {
  223. $id = intval(\YunShop::request()->id);
  224. if (\YunShop::plugin()->get('new-poster')) {
  225. $poster = Poster::uniacid()->where(['poster_type' => 15, 'status' => 1])->first();
  226. if ($poster) {
  227. $member = Member::uniacid()->with('yzMember')->where('uid', \YunShop::app()->getMemberId())->first();
  228. $createService = new CreateGoods($poster, $member, $this->type, request()->getSchemeAndHttpHost(), $id);
  229. $poster_result = $createService->getUrl();
  230. if ($poster_result['error_code'] != 0) {
  231. return $this->errorJson('生成失败', $poster_result);
  232. }
  233. $poster_result['new'] = true;
  234. return $this->successJson('ok', $poster_result);
  235. }
  236. }
  237. $this->fontPath = $this->defaultFontPath();
  238. $this->mid = \YunShop::app()->getMemberId();
  239. $this->storeid = intval(\YunShop::request()->storeid);
  240. $this->hotel_id = intval(\YunShop::request()->hotel_id);
  241. $this->shop_id = intval(\YunShop::request()->shop_id);
  242. $this->type = intval(\YunShop::request()->type);
  243. $this->ingress = \YunShop::request()->ingress ?: '';
  244. if (!$id) {
  245. return $this->errorJson('请传入正确参数.');
  246. }
  247. if (empty($this->storeid)) {
  248. $this->shopSet = \Setting::get('shop.shop');
  249. } else {
  250. if (app('plugins')->isEnabled('store-cashier') && !empty($this->storeid)) {
  251. $store = \app\common\models\Store::find($this->storeid);
  252. $this->shopSet['name'] = $store->store_name;
  253. $this->shopSet['logo'] = $store->thumb;
  254. }
  255. if (app('plugins')->isEnabled('hotel') && !empty($this->hotel_id)) {
  256. $hotel = \Yunshop\Hotel\common\models\Hotel::find($this->hotel_id);
  257. $this->shopSet['name'] = $hotel->hotel_name;
  258. $this->shopSet['logo'] = $hotel->thumb;
  259. }
  260. }
  261. if ($this->type == 2 && $this->ingress == 'weChatApplet') {
  262. if (!app('plugins')->isEnabled('min-app')) {
  263. return $this->errorJson('未开启小程序插件');
  264. }
  265. }
  266. $goods_model = \app\common\modules\shop\ShopConfig::current()->get('goods.models.commodity_classification');
  267. $goods_model = new $goods_model;
  268. $this->goodsModel = $goods_model->uniacid()->with('hasOneShare')->where('status', 1)->find($id);
  269. if (empty($this->goodsModel)) {
  270. return $this->errorJson('该商品不存在');
  271. }
  272. $imgPath = $this->get_lt();
  273. if (config('app.framework') == 'platform') {
  274. $urlPath = request()->getSchemeAndHttpHost() . '/' . substr($imgPath, strpos($imgPath, 'storage'));
  275. } else {
  276. $urlPath = request()->getSchemeAndHttpHost() . '/' . substr($imgPath, strpos($imgPath, 'addons'));
  277. }
  278. $data = $this->base64EncodeImage($imgPath);
  279. $data['image_url'] = $urlPath;
  280. $data['new'] = false;
  281. return $this->successJson('ok', $data);
  282. }
  283. /**
  284. * 圆角图片
  285. * @param $radius 角度
  286. * @return img
  287. */
  288. public function get_lt_rounder_corner($radius)
  289. {
  290. $img = imagecreatetruecolor($radius, $radius); // 创建一个正方形的图像
  291. $bgcolor = imagecolorallocate($img, 1, 1, 1); // 图像的背景
  292. $fgcolor = imagecolorallocate($img, 0, 0, 0);
  293. imagefill($img, 0, 0, $bgcolor);
  294. // $radius,$radius:以图像的右下角开始画弧
  295. // $radius*2, $radius*2:已宽度、高度画弧
  296. // 180, 270:指定了角度的起始和结束点
  297. // fgcolor:指定颜色
  298. imagefilledarc($img, $radius, $radius, $radius * 2, $radius * 2, 180, 270, $fgcolor, IMG_ARC_PIE);
  299. // 将弧角图片的颜色设置为透明
  300. imagecolortransparent($img, $fgcolor);
  301. return $img;
  302. }
  303. public function roundRadius($resource, $image_width, $image_height, $radius = 8)
  304. {
  305. // lt(左上角)
  306. $lt_corner = $this->get_lt_rounder_corner($radius);
  307. // header('Content-Type: image/png');
  308. // imagepng($lt_corner);
  309. // exit;
  310. imagecopymerge($resource, $lt_corner, 0, 0, 0, 0, $radius, $radius, 100);
  311. // lb(左下角)
  312. $lb_corner = imagerotate($lt_corner, 90, 0);
  313. imagecopymerge($resource, $lb_corner, 0, $image_height - $radius, 0, 0, $radius, $radius, 100);
  314. // rb(右上角)
  315. $rb_corner = imagerotate($lt_corner, 180, 0);
  316. imagecopymerge($resource, $rb_corner, $image_width - $radius, $image_height - $radius, 0, 0, $radius, $radius, 100);
  317. // rt(右下角)
  318. $rt_corner = imagerotate($lt_corner, 270, 0);
  319. imagecopymerge($resource, $rt_corner, $image_width - $radius, 0, 0, 0, $radius, $radius, 100);
  320. // header('Content-Type: image/png');
  321. // imagepng($resource);
  322. // exit;
  323. return $resource;
  324. }
  325. //图片返回base64 格式
  326. public function base64EncodeImage($strTmpName)
  327. {
  328. $base64Image = '';
  329. $imageInfo = getimagesize($strTmpName);
  330. //$imageData = fread(fopen($strTmpName , 'r'), filesize($strTmpName));
  331. //$base64Image = 'data:' . $imageInfo['mime'] . ';base64,' . chunk_split(base64_encode($imageData));
  332. $base64Image = base64_encode(file_get_contents($strTmpName));
  333. return [
  334. 'mime' => $imageInfo['mime'],
  335. 'base64Image' => $base64Image,
  336. ];
  337. }
  338. /**
  339. * 生成商品海报
  340. * @return string 商品海报绝对路径
  341. */
  342. public function get_lt()
  343. {
  344. set_time_limit(0);
  345. @ini_set('memory_limit', '256M');
  346. $image_width = 600; //335
  347. $image_height = 1000; //485
  348. $target = imagecreatefrompng(base_path('/static/post/images/post.png'));
  349. $target = $this->roundRadius($target, $image_width, $image_height);
  350. $target = $this->createShopImage($target);
  351. if ($this->goodsModel->hasOneShare->share_thumb) {
  352. $goodsThumb = $this->goodsModel->hasOneShare->share_thumb;
  353. } else {
  354. $goodsThumb = $this->goodsModel->thumb;
  355. }
  356. $target = $this->mergeGoodsImage($target, $goodsThumb);
  357. //商品二维码
  358. $goodsQr = $this->generateQr();
  359. if ($this->goodsModel->hasOneShare->share_title) {
  360. $text = $this->goodsModel->hasOneShare->share_title;
  361. } else {
  362. $text = $this->goodsModel->title;
  363. }
  364. $target = $this->mergeQrImage($target, $goodsQr);
  365. $target = $this->mergeText($target, $this->goodsText, $text);
  366. $target = $this->mergePriceText($target);
  367. imagepng($target, $this->getGoodsPosterPath());
  368. imagedestroy($target);
  369. return $this->getGoodsPosterPath();
  370. }
  371. //商城logo 与 商城名称处理
  372. protected function createShopImage($target)
  373. {
  374. //计算商城名称的宽度
  375. $testbox = imagettfbbox($this->shopText['size'], 0, $this->fontPath, $this->shopSet['name']);
  376. $shopTextWidth = $testbox[2] > 500 ? 500 : $testbox[2];
  377. $image_width = $shopTextWidth + 80;
  378. $image_height = 80;
  379. $img = imagecreatetruecolor($image_width, $image_height);
  380. $white = imagecolorallocate($img, 255, 255, 255);
  381. //设置白色背景色
  382. imagefill($img, 0, 0, $white);
  383. $img = $this->mergeLogoImage($img);
  384. if (empty($this->shopSet['logo'])) {
  385. $this->shopText['left'] = 45;
  386. }
  387. $img = $this->mergeText($img, $this->shopText, $this->shopSet['name']);
  388. imagecopyresized($target, $img, (600 - $image_width) / 2, 20, 0, 0, $image_width, $image_height, imagesx($img), imagesy($img));
  389. imagedestroy($img);
  390. return $target;
  391. }
  392. private function getGoodsPosterPath()
  393. {
  394. $path = storage_path('app/public/goods/' . \YunShop::app()->uniacid) . "/";
  395. Utils::mkdirs($path);
  396. $file_name = \YunShop::app()->uniacid . '-' . \YunShop::app()->getMemberId() . '-' . $this->goodsModel->id . '.png';
  397. return $path . $file_name;
  398. }
  399. /**
  400. * 合并商品图片到 $target
  401. * @param $target
  402. * @param $img
  403. * @return mixed
  404. */
  405. private function mergeGoodsImage($target, $thumb)
  406. {
  407. $thumb = $this->HttpAgreement(yz_tomedia($thumb));
  408. $img = imagecreatefromstring(\Curl::to($thumb)->get());
  409. $width = imagesx($img);
  410. $height = imagesy($img);
  411. imagecopyresized($target, $img, 45, 120, 0, 0, 480, 500, $width, $height);
  412. imagedestroy($img);
  413. return $target;
  414. }
  415. /**
  416. * 合并商城Logo 到 $target
  417. * @param [type] $target [description]
  418. * @param [type] $img [description]
  419. */
  420. private function mergeLogoImage($target)
  421. {
  422. $logo = $this->HttpAgreement(yz_tomedia($this->shopSet['logo']));
  423. $img = imagecreatefromstring(\Curl::to($logo)->get());
  424. if (!$img) {
  425. $this->shopText['left'] = 45;
  426. return $target;
  427. }
  428. $width = imagesx($img);//原图的宽度
  429. $height = imagesy($img);//原图的高度
  430. $fix = 65;
  431. //$percent = ($fix/$width);
  432. //缩放尺寸
  433. //$newwidth = $width * $percent;
  434. //$newheight = $height * $percent;
  435. // imagecopyresized($target, $img, 0, 5, 0, 0, 50, 50, $width, $height);
  436. // imagedestroy($img);
  437. $compress = imagecreatetruecolor($fix, $fix);//压缩图片
  438. $white = imagecolorallocate($compress, 255, 255, 255);
  439. imagefill($compress, 0, 0, $white);
  440. imagecopyresized($compress, $img, 0, 0, 0, 0, $fix, $fix, $width, $height);
  441. //根据压缩图生成圆形图
  442. $circular = imagecreatetruecolor($fix,$fix);
  443. $cc_white = imagecolorallocate($circular, 255, 255, 255);
  444. imagefill($circular, 0, 0, $cc_white);
  445. imagealphablending($circular,false);
  446. $transparent = imagecolorallocatealpha($circular, 255, 255, 255, 127);
  447. $r=$fix/2;
  448. for($x=0;$x<$fix;$x++) {
  449. for ($y = 0; $y < $fix; $y++) {
  450. $c = imagecolorat($compress, $x, $y);
  451. $_x = $x - $fix / 2;
  452. $_y = $y - $fix / 2;
  453. if ((($_x * $_x) + ($_y * $_y)) < ($r * $r)) {
  454. imagesetpixel($circular, $x, $y, $c);
  455. } else {
  456. imagesetpixel($circular, $x, $y, $transparent);
  457. }
  458. }
  459. }
  460. imagesavealpha($circular, true);
  461. imagecopy($target,$circular,0,5,0,0,$fix,$fix);
  462. imagedestroy($circular);
  463. imagedestroy($compress);
  464. imagedestroy($img);
  465. return $target;
  466. }
  467. /**
  468. * 合并商品二维码 到 $target
  469. * @param [type] $target [description]
  470. * @param [type] $img [description]
  471. */
  472. private function mergeQrImage($target, $img, $dst_x = 340, $dst_y = 780)
  473. {
  474. $width = imagesx($img);
  475. $height = imagesy($img);
  476. if ($this->type == 2 && $this->ingress == 'weChatApplet') {
  477. imagecopyresized($target, $img, 340, $dst_y, 0, 0, 200, 200, $width, $height);
  478. } else {
  479. imagecopy($target, $img, $dst_x, $dst_y, 0, 0, $width, $height);
  480. }
  481. // imagecopy($target, $img, $dst_x, $dst_y, 0, 0, $width, $height);
  482. imagedestroy($img);
  483. return $target;
  484. }
  485. /**
  486. * 合并名称
  487. * @param $target
  488. * @param $params
  489. * @param $text
  490. * @return mixed
  491. */
  492. private function mergeText($target, $params, $text)
  493. {
  494. if ($params['type']) {
  495. $text = $this->autowrap($params['size'], 0, $this->fontPath, $text, $params['max_width'], $params['br']);
  496. }
  497. $black = imagecolorallocate($target, 51, 51, 51);//文字颜色
  498. imagettftext($target, $params['size'], 0, $params['left'], $params['top'], $black, $this->fontPath, $text);
  499. return $target;
  500. }
  501. /**
  502. * 合并商品价格
  503. * @return [type] [description]
  504. */
  505. private function mergePriceText($target)
  506. {
  507. $color = imagecolorallocate($target, 107, 107, 107);
  508. $this->goodsModel->vip_level_status;
  509. $price_display = '';
  510. if ($this->goodsModel->vip_level_status['status']){
  511. $price_display = $this->goodsModel->vip_level_status['word'];
  512. }else{
  513. $price_display = $this->goodsModel->price;
  514. }
  515. //$price = '现价:¥' .$price_display;// $this->goodsModel->price;
  516. $price = '¥' .$price_display;// $this->goodsModel->price;
  517. $market_price = '原价:¥' . $this->goodsModel->market_price;
  518. $black = imagecolorallocate($target, 241, 83, 83);//当前价格颜色
  519. $price_box = imagettfbbox(18, 0, $this->fontPath, $price);
  520. $market_price_box = imagettfbbox(24, 0, $this->fontPath, $market_price);
  521. $gray = imagecolorallocate($target, 107, 107, 107);//原价颜色
  522. //设置删除线条
  523. // imageline($target, $price_box[2] + 12, 900, $price_box[2]+$market_price_box[2] + 14, 900, $color);
  524. $next = $price_box[2] + 120;
  525. imagettftext($target, 24, 0, 45, 670, $black, $this->fontPath, $price);
  526. if ($this->goodsModel->market_price>$price_display) {
  527. imagettftext($target, 16, 0, $next, 670, $gray, $this->fontPath, $market_price);
  528. imageline($target, $price_box[2] + 180, 663, $price_box[2] + $market_price_box[2] + 60, 663, $color);
  529. }
  530. return $target;
  531. }
  532. /**
  533. * 生成商品二维码
  534. * @return [type] [description]
  535. */
  536. private function generateQr()
  537. {
  538. if ($this->type == 2 && $this->ingress == 'weChatApplet') {
  539. //小程序海报生成
  540. $url = "packageA/detail_v2/detail_v2";
  541. $img = $this->getWxacode($url);
  542. return $img;
  543. }
  544. if (empty($this->storeid)) {
  545. //商城商品二维码
  546. //微店商品二维码
  547. if ($this->shop_id) {
  548. $url = yzAppFullUrl('/goods/' . $this->goodsModel->id, ['mid' => $this->mid,'shop_id'=>$this->shop_id]);
  549. $file = 'shop-mid-' . $this->mid . '-shop_id-'.$this->shop_id. '-goods-' . $this->goodsModel->id . '.png';
  550. } else {
  551. $url = yzAppFullUrl('/goods/' . $this->goodsModel->id, ['mid' => $this->mid]);
  552. $file = 'shop-mid-' . $this->mid . '-goods-' . $this->goodsModel->id . '.png';
  553. }
  554. } else {
  555. //门店商品二维码
  556. $url = yzAppFullUrl('/goods/' . $this->goodsModel->id . '/o2o/' . $this->storeid, ['mid' => $this->mid]);
  557. $file = 'store-' . $this->storeid . '-mid-' . $this->mid . '-goods-' . $this->goodsModel->id . '.png';
  558. }
  559. $path = storage_path('app/public/goods/qrcode/' . \YunShop::app()->uniacid);
  560. Utils::mkdirs($path);
  561. if (!is_file($path . '/' . $file)) {
  562. \QrCode::format('png')->size(220)->generate($url, $path . '/' . $file);
  563. }
  564. $img = imagecreatefromstring(file_get_contents($path . '/' . $file));
  565. return $img;
  566. }
  567. /**
  568. * 字体换行
  569. * @param [int] $fontsize [字体大小]
  570. * @param [int] $angle [角度]
  571. * @param [string] $fontface [字体类型]
  572. * @param [string] $string [字符串]
  573. * @param [int] $width [预设宽度]
  574. * @param [int] $br [大于$width是否换行]
  575. * @return [string] [处理好的字符串]
  576. */
  577. private function autowrap($fontsize, $angle, $fontface, $string, $width, $br)
  578. {
  579. $content = "";
  580. $num = 0;
  581. // 将字符串拆分成一个个单字 保存到数组 letter 中
  582. for ($i = 0; $i < mb_strlen($string); $i++) {
  583. $letter[] = mb_substr($string, $i, 1);
  584. }
  585. foreach ($letter as $l) {
  586. $teststr = $content . " " . $l;
  587. $testbox = imagettfbbox($fontsize, $angle, $fontface, $teststr);
  588. // 判断拼接后的字符串是否超过预设的宽度
  589. if (($testbox[2] > $width) && ($content !== "")) {
  590. $num += 1;
  591. if ($num > 1 || $br) {
  592. $content .= '..';
  593. // dd($content);
  594. return $content;
  595. }
  596. $content .= "\n";
  597. }
  598. $content .= $l;
  599. }
  600. return $content;
  601. }
  602. /**
  603. * 补全http协议
  604. * @param [string] $src 图片地址
  605. * @return [string]
  606. */
  607. protected function HttpAgreement($src)
  608. {
  609. $t = strtolower($src);
  610. if (strexists($t, 'http://') || strexists($t, 'https://')) {
  611. return $src;
  612. }
  613. $src = 'https://' . ltrim($src, '//');
  614. return $src;
  615. }
  616. //生成小程序二维码
  617. function getWxacode($goods_url)
  618. {
  619. $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?";
  620. $token = $this->getToken();
  621. \Log::debug('===========access_token===========', $token);
  622. $url .= "access_token=" . $token;
  623. $postdata = [
  624. "scene" => 'id=' . $this->goodsModel->id . ',mid=' . \YunShop::app()->getMemberId(),
  625. "page" => $goods_url,
  626. ];
  627. if ($this->shop_id) {
  628. $postdata['scene'] .= ',shop_id='.$this->shop_id;
  629. }
  630. $path = storage_path('app/public/goods/qrcode/' . \YunShop::app()->uniacid);
  631. if (!is_dir($path)) {
  632. Utils::mkdirs($path);
  633. }
  634. \Log::debug('=====地址信息=======', $postdata);
  635. $res = $this->curl_post($url, json_encode($postdata), $options = array());
  636. $erroe = json_decode($res);
  637. if (isset($erroe->errcode)) {
  638. return $this->errorJson('错误码' . $erroe->errcode . ';错误信息' . $erroe->errmsg);
  639. }
  640. \Log::debug('===========生成二维码===========', $res);
  641. $file = 'mid-' . $this->mid . '-goods-' . $this->goodsModel->id . '.png';
  642. file_put_contents($path . '/' . $file, $res);
  643. $img = imagecreatefromstring(file_get_contents($path . '/' . $file));
  644. return $img;
  645. }
  646. public function getCodeLink($size)
  647. {
  648. if ($this->type == 2) {
  649. $img = $this->getWXcodeLink();
  650. return $img;
  651. }
  652. if (empty($this->storeid)) {
  653. //商城商品二维码
  654. //微店商品二维码
  655. if ($this->shop_id) {
  656. $url = yzAppFullUrl('/goods/' . $this->goodsModel->id, ['mid' => $this->mid,'shop_id'=>$this->shop_id]);
  657. $file = 'shop-mid-' . $this->mid . '-shop_id-'.$this->shop_id. '-goods-' . $this->goodsModel->id . '.png';
  658. } else {
  659. $url = yzAppFullUrl('/goods/' . $this->goodsModel->id, ['mid' => $this->mid]);
  660. $file = 'shop-mid-' . $this->mid . '-goods-' . $this->goodsModel->id . '.png';
  661. }
  662. } else {
  663. //门店商品二维码
  664. $url = yzAppFullUrl('/goods/' . $this->goodsModel->id . '/o2o/' . $this->storeid, ['mid' => $this->mid]);
  665. $file = 'store-' . $this->storeid . '-mid-' . $this->mid . '-goods-' . $this->goodsModel->id . '.png';
  666. }
  667. $path = storage_path('app/public/goods/qrcode/' . \YunShop::app()->uniacid);
  668. Utils::mkdirs($path);
  669. if (!is_file($path . '/' . $file)) {
  670. \QrCode::format('png')->size($size)->generate($url, $path . '/' . $file);
  671. }
  672. $img = config('app.framework') == 'platform' ? request()->getSchemeAndHttpHost().'/storage/app/public/goods/qrcode/' . \YunShop::app()->uniacid . '/' . $file : request()->getSchemeAndHttpHost().'/addons/yun_shop/storage/app/public/goods/qrcode/' . \YunShop::app()->uniacid . '/' . $file ;
  673. return $img;
  674. }
  675. //生成小程序二维码
  676. public function getWXcodeLink()
  677. {
  678. $goods_url = "packageA/detail_v2/detail_v2";
  679. $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?";
  680. $token = $this->getToken();
  681. \Log::debug('===========access_token===========', $token);
  682. $url .= "access_token=" . $token;
  683. $postdata = [
  684. "scene" => 'id=' . $this->goodsModel->id . ',mid=' . \YunShop::app()->getMemberId(),
  685. "page" => $goods_url,
  686. ];
  687. if ($this->shop_id) {
  688. $postdata['scene'] .= ',shop_id='.$this->shop_id;
  689. }
  690. $path = storage_path('app/public/goods/qrcode/' . \YunShop::app()->uniacid);
  691. if (!is_dir($path)) {
  692. Utils::mkdirs($path);
  693. }
  694. $res = $this->curl_post($url, json_encode($postdata), $options = array());
  695. $erroe = json_decode($res, true);
  696. if (isset($erroe->errcode)) {
  697. \Log::debug('---------生成小程序码错误--------', '错误码' . $erroe->errcode . ';错误信息' . $erroe->errmsg);
  698. return '';
  699. }
  700. $file = 'mid-' . $this->mid . '-goods-' . $this->goodsModel->id . '.png';
  701. file_put_contents($path . '/' . $file, $res);
  702. return config('app.framework') == 'platform' ? request()->getSchemeAndHttpHost().'/storage/app/public/goods/qrcode/'.\YunShop::app()->uniacid.'/'.$file : request()->getSchemeAndHttpHost().'/addons/yun_shop/storage/app/public/goods/qrcode/'.\YunShop::app()->uniacid.'/'.$file;
  703. }
  704. //发送获取token请求,获取token(2小时)
  705. public function getToken()
  706. {
  707. $url = $this->getTokenUrlStr();
  708. $res = $this->curl_post($url, $postdata = '', $options = array());
  709. $data = json_decode($res, JSON_FORCE_OBJECT);
  710. return $data['access_token'];
  711. }
  712. //获取token的url参数拼接
  713. public function getTokenUrlStr()
  714. {
  715. $set = Setting::get('plugin.min_app');
  716. $getTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?"; //获取token的url
  717. $WXappid = $set['key']; //APPID
  718. $WXsecret = $set['secret']; //secret
  719. $str = $getTokenUrl;
  720. $str .= "grant_type=client_credential&";
  721. $str .= "appid=" . $WXappid . "&";
  722. $str .= "secret=" . $WXsecret;
  723. return $str;
  724. }
  725. public function curl_post($url = '', $postdata = '', $options = array())
  726. {
  727. $ch = curl_init($url);
  728. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  729. curl_setopt($ch, CURLOPT_POST, 1);
  730. curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
  731. curl_setopt($ch, CURLOPT_TIMEOUT, 5);
  732. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  733. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  734. if (!empty($options)) {
  735. curl_setopt_array($ch, $options);
  736. }
  737. $data = curl_exec($ch);
  738. curl_close($ch);
  739. return $data;
  740. }
  741. /**
  742. * 默认字体路径
  743. *
  744. * @return string
  745. */
  746. private function defaultFontPath()
  747. {
  748. return base_path() . DIRECTORY_SEPARATOR . "static" . DIRECTORY_SEPARATOR . "fonts" . DIRECTORY_SEPARATOR . "source_han_sans.ttf";
  749. }
  750. protected function changeMemberGoodsPrice()
  751. {
  752. $price = 0;
  753. if ($this->goodsModel->vip_price === null) {
  754. return $price;
  755. }
  756. $price = $this->goodsModel->next_level_price;
  757. return $price;
  758. }
  759. protected function getRealParams($params)
  760. {
  761. $params['left'] = intval(str_replace('px', '', $params['left'])) * 2;
  762. $params['top'] = intval(str_replace('px', '', $params['top'])) * 2;
  763. $params['width'] = intval(str_replace('px', '', $params['width'])) * 2;
  764. $params['height'] = intval(str_replace('px', '', $params['height'])) * 2;
  765. $params['size'] = intval(str_replace('px', '', $params['size'])) * 2;
  766. $params['src'] = yz_tomedia($params['src']);
  767. return $params;
  768. }
  769. }