PondForm.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. <?php
  2. namespace app\modules\client\models\v1\pond;
  3. use app\models\AccountLog;
  4. use app\models\Goods;
  5. use app\models\Pond;
  6. use app\models\PondLog;
  7. use app\models\PondSetting;
  8. use app\models\PondUserNum;
  9. use app\models\User;
  10. use yii\base\Model;
  11. class PondForm extends Model
  12. {
  13. public $user_id;
  14. public $store_id;
  15. public function index()
  16. {
  17. $pond_id = Pond::find()->where(['store_id' => $this->store_id])->orderBy('id ASC')->column();
  18. $pond_num = 6;//大转盘目前固定位数6位
  19. if (count($pond_id) > $pond_num) {
  20. //保留最后的6个
  21. $del_pond_id = array_splice($pond_id, 0, count($pond_id) - $pond_num);
  22. if ($del_pond_id) {
  23. Pond::deleteAll(['id' => $del_pond_id]);
  24. }
  25. }
  26. $list = Pond::find()
  27. ->where([
  28. 'store_id' => $this->store_id,
  29. ])->with(['gift' => function ($query) {
  30. $query->where([
  31. 'store_id' => $this->store_id,
  32. 'is_delete' => 0
  33. ]);
  34. }])
  35. ->asArray()->all();
  36. $setting = PondSetting::findOne(['store_id' => $this->store_id]);
  37. if ($setting['start_time'] > time() || $setting['end_time'] < time()) {
  38. return [
  39. 'code' => 1,
  40. 'msg' => '不在活动时间范围内',
  41. ];
  42. }
  43. $oppty = 0;
  44. //根据用户积分计算还能抽几次 向下取整
  45. if ($setting->integral > 0) {
  46. $user = get_user();
  47. $user_integral = $user->integral;
  48. $oppty = floor_num($user_integral / $setting->integral, 0);
  49. }
  50. $win_log = PondLog::find()->alias('pl')
  51. ->leftJoin(['p' => Pond::tableName()], 'pl.pond_id = p.id')
  52. ->leftJoin(['u' => User::tableName()], 'pl.user_id = u.id')
  53. ->leftJoin(['g' => Goods::tableName()], 'pl.gift_id = g.id')
  54. ->where(['pl.store_id' => $this->store_id, 'pl.type' => 2])
  55. ->select('u.nickname,u.binding, p.name, g.name as gift_name')
  56. ->orderBy('pl.id desc')
  57. ->limit(10)
  58. ->asArray()
  59. ->all();
  60. foreach ($win_log as &$item) {
  61. $item['name'] = $item['name'] ?: $item['gift_name'];
  62. }
  63. return [
  64. 'code' => 0,
  65. 'data' => [
  66. 'setting' => $setting,
  67. 'oppty' => $oppty,
  68. 'win_log' => $win_log,
  69. 'list' => $list,
  70. ],
  71. ];
  72. }
  73. protected function get_rand($succ, $probability)
  74. {
  75. $rand = $this->random_num(1, $probability);
  76. $winning_rate = 0;
  77. foreach ($succ as $val) {
  78. $winning_rate += $val->winning_rate;
  79. if ($winning_rate > $rand && $val->user_id != $this->user_id) {
  80. return $val->id;
  81. }
  82. }
  83. }
  84. public function lottery()
  85. {
  86. $setting = PondSetting::findOne(['store_id' => $this->store_id]);
  87. if ($setting['start_time'] > time() || $setting['end_time'] < time()) {
  88. return [
  89. 'code' => 1,
  90. 'msg' => '活动已结束或未开启'
  91. ];
  92. }
  93. $user = get_user();
  94. $oppty = 0;
  95. //根据用户积分计算还能抽几次 向下取整
  96. if ($setting->integral > 0) {
  97. $user_integral = $user->integral;
  98. $oppty = floor_num($user_integral / $setting->integral, 0);
  99. }
  100. // $oppty = PondUserNum::find()->where(['store_id' => $this->store_id, 'user_id' => $this->user_id, 'status' => 0])->count();
  101. if ($oppty <= 0) {
  102. return [
  103. 'code' => 1,
  104. 'msg' => '机会已用完'
  105. ];
  106. }
  107. $pond = Pond::find()->where(['store_id' => $this->store_id])->all();
  108. $succ = $err = array();
  109. $probability = $stock = 0;
  110. foreach ($pond as $v) {
  111. if ($v->type != 1) {
  112. if ($v->stock > 0) {
  113. $succ[$v->id] = $v;
  114. $probability += $v->winning_rate;
  115. $stock += $v->stock;
  116. }
  117. } else {
  118. $err[$v->id] = $v;
  119. }
  120. }
  121. $rand = $this->random_num(1, 10000);
  122. if (empty($err)) {
  123. if ($stock > 0) {
  124. $id = $this->get_rand($succ, $probability);
  125. } else {
  126. return [
  127. 'code' => 1,
  128. 'msg' => '库存不足'
  129. ];
  130. }
  131. } else {
  132. if ($rand < $probability && $stock > 0) {
  133. $id = $this->get_rand($succ, $probability);
  134. } else {
  135. $id = array_rand($err, 1);
  136. }
  137. }
  138. $form = Pond::findOne([
  139. 'store_id' => $this->store_id,
  140. 'id' => $id
  141. ]);
  142. // $cishu = PondUserNum::findOne(['store_id' => $this->store_id, 'user_id' => $this->user_id, 'status' => 0]);
  143. // $cishu->status = 1;
  144. // $cishu->save();
  145. $pondLog = new PondLog;
  146. $pondLog->store_id = $this->store_id;
  147. $pondLog->user_id = $this->user_id;
  148. $pondLog->type = $form->type;
  149. $pondLog->status = 0;
  150. if ($form->type == 1) {
  151. $pondLog->num = 0;
  152. $pondLog->status = 1;
  153. }
  154. $pondLog->pond_id = $id;
  155. $pondLog->pond_name = $form->name;
  156. $pondLog->gift_id = $form->gift_id;
  157. $pondLog->create_time = time();
  158. $t = \Yii::$app->db->beginTransaction();
  159. if ($form->type != 1) {
  160. $sql = 'select * from ' . Pond::tableName() . ' where store_id = ' . $this->store_id . ' and id = ' . $id . ' for update';
  161. $pond = \Yii::$app->db->createCommand($sql)->queryOne();
  162. //判断库存是否大于0
  163. if ($pond['stock'] > 0) {
  164. //将库存数量减1
  165. $form->stock = $pond['stock'] - 1;
  166. $pondLog->num = 1;
  167. if (!$form->save()) {
  168. $t->rollBack();
  169. return [
  170. 'code' => 1,
  171. 'msg' => '网络异常'
  172. ];
  173. }
  174. } else {
  175. $pondLog->type = 1;
  176. if (empty($err)) {
  177. return [
  178. 'code' => 1,
  179. 'msg' => '网络异常'
  180. ];
  181. } else {
  182. $id = array_rand($err, 1);
  183. };
  184. $pondLog->pond_id = $id;
  185. $pondLog->num = 0;
  186. $pondLog->gift_id = 0;
  187. }
  188. }
  189. if ($pondLog->save()) {
  190. //扣减积分
  191. $result = AccountLog::saveLog(
  192. $user->id,
  193. $setting->integral,
  194. AccountLog::TYPE_INTEGRAL,
  195. AccountLog::LOG_TYPE_EXPEND,
  196. AccountLog::TYPE_POND_COMMISSION,
  197. $pondLog->id,
  198. '大转盘抽奖扣减积分'
  199. );
  200. if (!$result) {
  201. $t->rollBack();
  202. return [
  203. 'code' => 1,
  204. 'msg' => '扣减积分失败'
  205. ];
  206. }
  207. $t->commit();
  208. $array = [
  209. 'oppty' => $oppty - 1,
  210. 'id' => $id,
  211. 'p_id' => $pondLog->id,
  212. ];
  213. return [
  214. 'code' => 0,
  215. 'data' => (object)$array
  216. ];
  217. } else {
  218. return $this->getErrorResponse($pondLog);
  219. }
  220. }
  221. public function setting()
  222. {
  223. $list = PondSetting::findOne(['store_id' => $this->store_id]);
  224. $list->end_time = date('Y.m.d H', $list->end_time);
  225. $list->start_time = date('Y.m.d H', $list->start_time);
  226. if ($list) {
  227. return [
  228. 'code' => 0,
  229. 'msg' => '成功',
  230. 'data' => $list
  231. ];
  232. }
  233. }
  234. protected function random_num($min, $max)
  235. {
  236. return mt_rand() % ($max - $min + 1) - $min;
  237. }
  238. public function qrcode()
  239. {
  240. $goods_qrcode_dst = \Yii::$app->basePath . '/web/cyy/images/pond_qrcode.png';
  241. $font_path = \Yii::$app->basePath . '/web/cyy/font/st-heiti-light.ttc';
  242. $editor = Grafika::createEditor(GrafikaHelper::getSupportEditorLib());
  243. $editor->open($goods_qrcode, $goods_qrcode_dst);
  244. //获取小程序码图片
  245. $user_id = \Yii::$app->user->id;
  246. if (\Yii::$app->fromAlipayApp()) {
  247. $scene = "user_id={$user_id}";
  248. } else {
  249. $scene = "user_id:{$user_id}";
  250. }
  251. $wxapp_qrcode_file_res = $this->getQrcode($scene, 240, "pond/pond/pond");
  252. if ($wxapp_qrcode_file_res['code'] == 1) {
  253. return [
  254. 'code' => 1,
  255. 'msg' => '获取小程序码失败,' . $wxapp_qrcode_file_res['msg'],
  256. ];
  257. }
  258. $wxapp_qrcode_file_path = $wxapp_qrcode_file_res['file_path'];
  259. $editor->open($wxapp_qrcode, $wxapp_qrcode_file_path);
  260. $user = \Yii::$app->user->identity;
  261. // 用户头像
  262. $user_pic_path = $this->saveTempImage($user->avatar_url);
  263. if (!$user_pic_path) {
  264. return [
  265. 'code' => 1,
  266. 'msg' => '获取海报失败:用户头像丢失',
  267. ];
  268. }
  269. $goods_pic_save_path = \Yii::$app->basePath . '/web/temp/';
  270. $goods_pic_save_name = md5("v=1.6.2&user_id={$user_id}") . '.jpg';
  271. list($w, $h) = getimagesize($user_pic_path);
  272. $user_pic_path = $this->avatar($user_pic_path, $goods_pic_save_path, $w, $h);
  273. $editor->open($user_pic, $user_pic_path);
  274. //附加用户头像
  275. $editor->resizeExactWidth($user_pic, 80);
  276. $editor->blend($goods_qrcode, $user_pic, 'normal', 1.0, 'top-left', 160, 480);
  277. //加上文字
  278. $username = $this->setName($user->nickname);
  279. $editor->text($goods_qrcode, $username, 25, 272, 490, new Color('#ffffff'), $font_path, 0);
  280. $editor->text($goods_qrcode, '邀请你一起抽大奖', 25, 272, 530, new Color('#ffffff'), $font_path, 0);
  281. //加下文字
  282. $editor->text($goods_qrcode, '扫描二维码', 30, 270, 1064, new Color('#ffffff'), $font_path, 0);
  283. $editor->text($goods_qrcode, '和我一起抽奖!', 30, 240, 1114, new Color('#ffffff'), $font_path, 0);
  284. //附加小程序码图片
  285. $editor->resizeFit($wxapp_qrcode, 400, 400);
  286. $editor->blend($goods_qrcode, $wxapp_qrcode, 'normal', 1.0, 'top-center', 0, 616);
  287. //保存图片
  288. $editor->save($goods_qrcode, $goods_pic_save_path . $goods_pic_save_name, 'jpeg', 85);
  289. $pic_url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . \Yii::$app->request->baseUrl . '/temp/' . $goods_pic_save_name);
  290. //删除临时图片
  291. unlink($wxapp_qrcode_file_path);
  292. unlink($goods_qrcode);
  293. return [
  294. 'code' => 0,
  295. 'data' => [
  296. 'pic_url' => $pic_url . '?v=' . time(),
  297. ],
  298. ];
  299. }
  300. private function setName($text)
  301. {
  302. if (mb_strlen($text, 'UTF-8') > 8) {
  303. $text = mb_substr($text, 0, 8, 'UTF-8') . '...';
  304. }
  305. return $text;
  306. }
  307. //获取网络图片到临时目录
  308. private function saveTempImage($url)
  309. {
  310. $wdcp_patch = false;
  311. $wdcp_patch_file = \Yii::$app->basePath . '/patch/wdcp.json';
  312. if (file_exists($wdcp_patch_file)) {
  313. $wdcp_patch = json_decode(file_get_contents($wdcp_patch_file), true);
  314. if ($wdcp_patch && in_array(\Yii::$app->request->hostName, $wdcp_patch)) {
  315. $wdcp_patch = true;
  316. } else {
  317. $wdcp_patch = false;
  318. }
  319. }
  320. if ($wdcp_patch) {
  321. $url = str_replace('http://', 'https://', $url);
  322. }
  323. if (!is_dir(\Yii::$app->runtimePath . '/image')) {
  324. mkdir(\Yii::$app->runtimePath . '/image');
  325. }
  326. $save_path = \Yii::$app->runtimePath . '/image/' . md5($url) . '.jpg';
  327. $ch = curl_init($url);
  328. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  329. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  330. curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
  331. $img = curl_exec($ch);
  332. curl_close($ch);
  333. $fp = fopen($save_path, 'w');
  334. fwrite($fp, $img);
  335. fclose($fp);
  336. return $save_path;
  337. }
  338. //第一步生成圆角图片
  339. public function avatar($url, $path = './', $w, $h)
  340. {
  341. $original_path = $url;
  342. $dest_path = $path . uniqid() . '.png';
  343. $src = imagecreatefromstring(file_get_contents($original_path));
  344. $newpic = imagecreatetruecolor($w, $h);
  345. imagealphablending($newpic, false);
  346. $transparent = imagecolorallocatealpha($newpic, 0, 0, 0, 127);
  347. $r = $w / 2;
  348. for ($x = 0; $x < $w; $x++) {
  349. for ($y = 0; $y < $h; $y++) {
  350. $c = imagecolorat($src, $x, $y);
  351. $_x = $x - $w / 2;
  352. $_y = $y - $h / 2;
  353. if ((($_x * $_x) + ($_y * $_y)) < ($r * $r)) {
  354. imagesetpixel($newpic, $x, $y, $c);
  355. } else {
  356. imagesetpixel($newpic, $x, $y, $transparent);
  357. }
  358. }
  359. }
  360. imagesavealpha($newpic, true);
  361. imagepng($newpic, $dest_path);
  362. imagedestroy($newpic);
  363. imagedestroy($src);
  364. unlink($url);
  365. return $dest_path;
  366. }
  367. private function getQrcode($scene, $width = 430, $page = null)
  368. {
  369. return GenerateShareQrcode::getQrcode($this->store_id, $scene, $width, $page, false);
  370. }
  371. //保存图片内容到临时文件
  372. private function saveTempImageByContent($content)
  373. {
  374. if (!is_dir(\Yii::$app->runtimePath . '/image')) {
  375. mkdir(\Yii::$app->runtimePath . '/image');
  376. }
  377. $save_path = \Yii::$app->runtimePath . '/image/' . md5(base64_encode($content)) . '.jpg';
  378. $fp = fopen($save_path, 'w');
  379. fwrite($fp, $content);
  380. fclose($fp);
  381. return $save_path;
  382. }
  383. }