Index.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. <?php
  2. namespace app\index\controller;
  3. use app\admin\model\SinaNotice;
  4. use app\middleware\Log;
  5. use app\middleware\Safe;
  6. use app\service\WeiboService;
  7. use InvalidArgumentException;
  8. use ReflectionException;
  9. use think\admin\Controller;
  10. use think\admin\service\SystemService;
  11. use think\exception\FuncNotFoundException;
  12. use think\exception\ClassNotFoundException;
  13. use think\db\exception\DbException;
  14. use think\db\exception\ModelNotFoundException;
  15. use think\db\exception\DataNotFoundException;
  16. use think\facade\Cache;
  17. use think\facade\Db;
  18. use \think\response\Json;
  19. /**
  20. * Class Index
  21. * @package app\index\controller
  22. */
  23. class Index extends Controller
  24. {
  25. public function index()
  26. {
  27. $this->redirect(sysuri('admin/login/index'));
  28. }
  29. /**
  30. * 检测登录 通过cookie中的SUB字段的内容,调用用户接口检测登录状态
  31. * @return mixed
  32. * @throws ClassNotFoundException
  33. * @throws ReflectionException
  34. */
  35. public function checkLogin()
  36. {
  37. $userInfoRes = (new WeiboService(0))->userinfo();
  38. if (empty($userInfoRes) || $userInfoRes['code'] != 10000) {
  39. return $this->response(403, $userInfoRes['msg'] ?? '没有登录');
  40. }
  41. // 使用客户端信息生成token
  42. $token = md5($_SERVER['HTTP_USER_AGENT'] . $_SERVER['HTTP_ACCEPT_ENCODING'] . $_SERVER['HTTP_ACCEPT_LANGUAGE'] . get_client_ip(0)) . $userInfoRes['data']['uid'];
  43. $user = $userInfoRes['data'];
  44. // 生成加密用的密钥和向量
  45. $cipher = "aes-256-gcm";
  46. $ivlen = openssl_cipher_iv_length($cipher);
  47. $iv = bin2hex(openssl_random_pseudo_bytes($ivlen));
  48. $aesKey = bin2hex(openssl_random_pseudo_bytes(32));
  49. $user = array_merge($user, [
  50. 'aes_key' => $aesKey,
  51. 'ase_iv' => $iv,
  52. ]);
  53. // 缓存用户信息1天
  54. Cache::set('u:' . $token, json_encode($user), 86400);
  55. return $this->successResponse([
  56. 'user' => $user,
  57. 'token' => $token,
  58. 'first' => Cache::get('u:f:' . $user['uid']) != 1,
  59. ]);
  60. }
  61. /**
  62. * 聚合页配置信息
  63. * @return mixed
  64. * @throws FuncNotFoundException
  65. * @throws ReflectionException
  66. * @throws InvalidArgumentException
  67. * @throws ClassNotFoundException
  68. */
  69. public function groupPageConfig()
  70. {
  71. return $this->successResponse(['config' => SystemService::instance()->getData('group:page:config')]);
  72. }
  73. /**
  74. * 聚合页通知获取
  75. * 查询最近20条通知
  76. * @return mixed
  77. * @throws DbException
  78. * @throws ModelNotFoundException
  79. * @throws DataNotFoundException
  80. */
  81. public function notices()
  82. {
  83. $rows = SinaNotice::limit(20)->order('id', 'desc')->select();
  84. return $this->successResponse([
  85. "lists" => $rows,
  86. ]);
  87. }
  88. /**
  89. * 首次弹窗
  90. * 发放邀请函微博
  91. * @return Json
  92. */
  93. public function sendInviteWeibo()
  94. {
  95. $config = SystemService::instance()->getData('group:page:config');
  96. $sendRes = (new WeiboService(Safe::$user['uid']))->status($config['firstDialog']['content']);
  97. if (empty($sendRes) || $sendRes['code'] != 10000) {
  98. return $this->response(403, $sendRes['msg'] ?? '发布失败');
  99. }
  100. Cache::set('u:f:' . Safe::$user['uid'], 1, 0);
  101. return $this->successResponse(null, '发布成功!');
  102. }
  103. /**
  104. * 首次弹窗用户未选择发送邀请函
  105. * 标记已经首次弹窗过了
  106. * @return mixed
  107. */
  108. public function setFirst()
  109. {
  110. Cache::set('u:f:' . Safe::$user['uid'], 1, 0);
  111. return $this->successResponse(null, '操作成功!');
  112. }
  113. /**
  114. * 获取活动规则
  115. * @return mixed
  116. * @throws FuncNotFoundException
  117. * @throws ReflectionException
  118. * @throws InvalidArgumentException
  119. * @throws ClassNotFoundException
  120. */
  121. public function getRule()
  122. {
  123. $config = SystemService::instance()->getData('activity:rule');
  124. return $this->successResponse($config);
  125. }
  126. /**
  127. * 获取品牌任务相关配置
  128. *
  129. * @return mixed
  130. * @throws FuncNotFoundException
  131. * @throws ClassNotFoundException
  132. * @throws ReflectionException
  133. * @throws DbException
  134. * @throws ModelNotFoundException
  135. * @throws DataNotFoundException
  136. */
  137. public function brand()
  138. {
  139. $conf = $this->getBrandConfigAndState();
  140. if ($conf instanceof Json) {
  141. return $conf;
  142. }
  143. return $this->successResponse($conf);
  144. }
  145. /**
  146. * 品牌任务关注接口
  147. * @return mixed
  148. * @throws FuncNotFoundException
  149. * @throws ClassNotFoundException
  150. * @throws ReflectionException
  151. * @throws DbException
  152. * @throws ModelNotFoundException
  153. * @throws DataNotFoundException
  154. */
  155. public function follow()
  156. {
  157. // 先获取品牌任务配置及状态
  158. $conf = $this->getBrandConfigAndState();
  159. if ($conf instanceof Json) {
  160. return $conf;
  161. }
  162. // 已经关注过了
  163. if ($conf['state']['follow_state'] == 1) {
  164. return $this->successResponse([
  165. 'result' => 2,
  166. 'brand' => $conf,
  167. ], '您已经关注过了');
  168. }
  169. // 调用接口关注
  170. $weiboRes = (new WeiboService(Safe::$user['uid']))->add($conf['config']['follow']['id']);
  171. if (empty($weiboRes) || $weiboRes['code'] != 10000) {
  172. return $this->response(600, $weiboRes['msg'] ?? '关注失败~');
  173. }
  174. $date = date('Y-m-d');
  175. $redisKey = $this->getTaskStateRedisKey(intval(Safe::$user['uid']));
  176. // 如果已经完成了另外两项,则标记品牌任务已经完成
  177. $finishState = $conf['state']['finish_state'];
  178. if ($conf['state']['view_state'] == 1 && $conf['state']['forward_state'] == 1) {
  179. $finishState = 1;
  180. }
  181. // 更新任务状态
  182. $nums = Db::table('user_task')->where('uid', Safe::$user['uid'])->where('date', $date)->update([
  183. 'follow_state' => 1,
  184. 'finish_state' => $finishState,
  185. ]);
  186. if ($nums) {
  187. $conf['state']['follow_state'] = 1;
  188. $conf['state']['finish_state'] = $finishState;
  189. Cache::set($redisKey, json_encode($conf['state']), 86400);
  190. return $this->successResponse([
  191. 'result' => 1,
  192. 'brand' => $conf,
  193. ], '关注成功');
  194. } else {
  195. return $this->response(601, '更新任务状态失败');
  196. }
  197. }
  198. /**
  199. * 品牌任务转发博文接口
  200. * @return mixed
  201. * @throws FuncNotFoundException
  202. * @throws ClassNotFoundException
  203. * @throws ReflectionException
  204. * @throws DbException
  205. * @throws ModelNotFoundException
  206. * @throws DataNotFoundException
  207. */
  208. public function forward()
  209. {
  210. // 先获取品牌任务配置及状态
  211. $conf = $this->getBrandConfigAndState();
  212. if ($conf instanceof Json) {
  213. return $conf;
  214. }
  215. // 已经转发过了
  216. if ($conf['state']['forward_state'] == 1) {
  217. return $this->successResponse([
  218. 'result' => 2,
  219. 'brand' => $conf,
  220. ], '您已经转发过了');
  221. }
  222. // 调用微博接口转发
  223. $weiboRes = (new WeiboService(Safe::$user['uid']))->repost($conf['config']['forward']['id'], $conf['config']['forward']['content'] ?? '');
  224. if (empty($weiboRes) || $weiboRes['code'] != 10000) {
  225. return $this->response(600, $weiboRes['msg'] ?? '转发失败~');
  226. }
  227. $date = date('Y-m-d');
  228. $redisKey = $this->getTaskStateRedisKey(intval(Safe::$user['uid']));
  229. // 如果已经完成了另外两项,则标记品牌任务已经完成
  230. $finishState = $conf['state']['finish_state'];
  231. if ($conf['state']['view_state'] == 1 && $conf['state']['follow_state'] == 1) {
  232. $finishState = 1;
  233. }
  234. // 更新任务状态
  235. $nums = Db::table('user_task')->where('uid', Safe::$user['uid'])->where('date', $date)->update([
  236. 'forward_state' => 1,
  237. 'finish_state' => $finishState,
  238. ]);
  239. if ($nums) {
  240. $conf['state']['forward_state'] = 1;
  241. $conf['state']['finish_state'] = $finishState;
  242. Cache::set($redisKey, json_encode($conf['state']), 86400);
  243. return $this->successResponse([
  244. 'result' => 1,
  245. 'brand' => $conf,
  246. ], '转发成功');
  247. } else {
  248. return $this->response(601, '更新任务状态失败');
  249. }
  250. }
  251. /**
  252. * 完成品牌任务后领取加票机会接口
  253. * @return mixed
  254. * @throws FuncNotFoundException
  255. * @throws ClassNotFoundException
  256. * @throws ReflectionException
  257. * @throws DbException
  258. * @throws ModelNotFoundException
  259. * @throws DataNotFoundException
  260. */
  261. public function taskFinishAddVotes()
  262. {
  263. // 先获取品牌任务配置及状态
  264. $conf = $this->getBrandConfigAndState();
  265. if ($conf instanceof Json) {
  266. return $conf;
  267. }
  268. if ($conf['state']['finish_add_votes'] == 1) {
  269. return $this->successResponse([
  270. 'result' => 2,
  271. 'brand' => $conf,
  272. ], '您今日已经领取过投票机会了~');
  273. }
  274. // 未完成品牌任务 领取失败
  275. if ($conf['state']['finish_state'] == 0) {
  276. return $this->response(603, '请先完成品牌任务,再来领取加票', [
  277. 'result' => 0,
  278. 'brand' => $conf,
  279. ]);
  280. }
  281. // 调用微博接口 给用户发券(加票)
  282. $weiboRes = (new WeiboService(Safe::$user['uid']))->setcoupons($conf['config']['task']['votes']);
  283. if (empty($weiboRes) || $weiboRes['code'] != 10000) {
  284. return $this->response(600, $weiboRes['msg'] ?? '加票失败~');
  285. }
  286. // 标记加票成功
  287. $date = date('Y-m-d');
  288. $redisKey = $this->getTaskStateRedisKey(intval(Safe::$user['uid']));
  289. $nums = Db::table('user_task')->where('uid', Safe::$user['uid'])->where('date', $date)->update([
  290. 'finish_add_votes' => 1,
  291. ]);
  292. if ($nums) {
  293. $conf['state']['finish_add_votes'] = 1;
  294. Cache::set($redisKey, json_encode($conf['state']), 86400);
  295. return $this->successResponse([
  296. 'result' => 1,
  297. 'brand' => $conf,
  298. ], '加票成功');
  299. } else {
  300. return $this->response(601, '更新任务状态失败');
  301. }
  302. }
  303. /**
  304. * 用户完成端外分享时调用接口加票
  305. * @return mixed
  306. * @throws FuncNotFoundException
  307. * @throws ClassNotFoundException
  308. * @throws ReflectionException
  309. * @throws DbException
  310. * @throws ModelNotFoundException
  311. * @throws DataNotFoundException
  312. */
  313. public function shareFinishAddVotes()
  314. {
  315. // 先获取品牌任务配置及状态
  316. $conf = $this->getBrandConfigAndState();
  317. if ($conf instanceof Json) {
  318. return $conf;
  319. }
  320. if ($conf['state']['share_add_votes'] == 1) {
  321. return $this->successResponse([
  322. 'result' => 2,
  323. 'brand' => $conf,
  324. ], '您今日已经领取过投票机会了~');
  325. }
  326. // 调用接口给用户发券(加票)
  327. $weiboRes = (new WeiboService(Safe::$user['uid']))->setcoupons($conf['config']['share']['votes']);
  328. if (empty($weiboRes) || $weiboRes['code'] != 10000) {
  329. return $this->response(600, $weiboRes['msg'] ?? '加票失败~');
  330. }
  331. // 标记状态
  332. $date = date('Y-m-d');
  333. $redisKey = $this->getTaskStateRedisKey(intval(Safe::$user['uid']));
  334. $nums = Db::table('user_task')->where('uid', Safe::$user['uid'])->where('date', $date)->update([
  335. 'share_add_votes' => 1,
  336. ]);
  337. if ($nums) {
  338. $conf['state']['share_add_votes'] = 1;
  339. Cache::set($redisKey, json_encode($conf['state']), 86400);
  340. return $this->successResponse([
  341. 'result' => 1,
  342. 'brand' => $conf,
  343. ], '加票成功');
  344. } else {
  345. return $this->response(601, '更新任务状态失败');
  346. }
  347. }
  348. /**
  349. * 标记用户已经浏览过主页了,用户点了去浏览时调用
  350. * @return mixed
  351. * @throws FuncNotFoundException
  352. * @throws ClassNotFoundException
  353. * @throws ReflectionException
  354. * @throws DbException
  355. * @throws ModelNotFoundException
  356. * @throws DataNotFoundException
  357. */
  358. public function setViewed()
  359. {
  360. // 先获取品牌任务配置及状态
  361. $conf = $this->getBrandConfigAndState();
  362. if ($conf instanceof Json) {
  363. return $conf;
  364. }
  365. if ($conf['state']['view_state'] == 1) {
  366. return $this->successResponse([
  367. 'result' => 2,
  368. 'brand' => $conf,
  369. ], '您已经浏览过了');
  370. }
  371. $date = date('Y-m-d');
  372. $redisKey = $this->getTaskStateRedisKey(intval(Safe::$user['uid']));
  373. // 如果已经完成了另外两项,则标记品牌任务已经完成
  374. $finishState = $conf['state']['finish_state'];
  375. if ($conf['state']['forward_state'] == 1 && $conf['state']['follow_state'] == 1) {
  376. $finishState = 1;
  377. }
  378. $nums = Db::table('user_task')->where('uid', Safe::$user['uid'])->where('date', $date)->update([
  379. 'view_state' => 1,
  380. 'finish_state' => $finishState,
  381. ]);
  382. if ($nums) {
  383. $conf['state']['view_state'] = 1;
  384. $conf['state']['finish_state'] = $finishState;
  385. Cache::set($redisKey, json_encode($conf['state']), 86400);
  386. return $this->successResponse([
  387. 'result' => 1,
  388. 'brand' => $conf,
  389. ], '浏览成功');
  390. } else {
  391. return $this->response(601, '更新任务状态失败');
  392. }
  393. }
  394. /**
  395. * 获取品牌任务redis 缓存键
  396. * @param int $uid
  397. * @return string
  398. */
  399. protected function getTaskStateRedisKey(int $uid): string
  400. {
  401. $dateForRedis = date('Ymd');
  402. return "t:{$dateForRedis}:" . $uid;
  403. }
  404. /**
  405. * 获取品牌任务配置及状态
  406. * @return \think\response\Json|array
  407. * @throws FuncNotFoundException
  408. * @throws ReflectionException
  409. * @throws InvalidArgumentException
  410. * @throws ClassNotFoundException
  411. * @throws DbException
  412. * @throws ModelNotFoundException
  413. * @throws DataNotFoundException
  414. */
  415. protected function getBrandConfigAndState()
  416. {
  417. $config = SystemService::instance()->getData('brand:task:config');
  418. $date = date('Y-m-d');
  419. $dateForRedis = date('Ymd');
  420. $redisKey = "t:{$dateForRedis}:" . Safe::$user['uid'];
  421. $state = Cache::get($redisKey);
  422. if (empty($state)) {
  423. // 缓存失败 查数据库
  424. $state = Db::table('user_task')->where('uid', Safe::$user['uid'])->where('date', $date)->find();
  425. if (empty($state)) {
  426. // 当天第一次,初始化数据
  427. $state = [
  428. // 品牌任务完成状态
  429. 'finish_state' => 0,
  430. // 关注子任务状态
  431. 'follow_state' => 0,
  432. // 转发子任务状态
  433. 'forward_state' => 0,
  434. // 查看浏览主页任务状态
  435. 'view_state' => 0,
  436. // 品牌任务完成后是否加票
  437. 'finish_add_votes' => 0,
  438. // 分享完成后是否加票
  439. 'share_add_votes' => 0,
  440. 'uid' => Safe::$user['uid'],
  441. 'date' => $date,
  442. ];
  443. if (0 == Db::table('user_task')->insert($state)) {
  444. return $this->response(5001, '系统错误,请稍后再试~');
  445. }
  446. }
  447. Cache::set($redisKey, json_encode($state), 86400);
  448. } else {
  449. $state = json_decode($state, true);
  450. }
  451. // 如果未关注状态,查询下已经实际已经关注了
  452. if ($state['follow_state'] == 0) {
  453. $weiboRes = (new WeiboService(Safe::$user['uid']))->friends($config['follow']['id']);
  454. if (isset($weiboRes['data'][$config['follow']['id']]) && $weiboRes['data'][$config['follow']['id']] == 1) {
  455. $nums = Db::table('user_task')->where('uid', Safe::$user['uid'])->where('date', $date)->update(['follow_state' => 1,]);
  456. if ($nums) {
  457. $state['follow_state'] = 1;
  458. Cache::set($redisKey, json_encode($state), 86400);
  459. }
  460. }
  461. }
  462. // 校准状态,可能存在异常情况关注,转发,浏览都完成了,但是总的品牌任务状态没标记成已完成
  463. if ($state['follow_state'] == 1 && $state['forward_state'] == 1 && $state['view_state'] == 1 && $state['finish_state'] != 1) {
  464. $nums = Db::table('user_task')->where('uid', Safe::$user['uid'])->where('date', $date)->update(['finish_state' => 1,]);
  465. if ($nums) {
  466. $state['finish_state'] = 1;
  467. Cache::set($redisKey, json_encode($state), 86400);
  468. }
  469. }
  470. return [
  471. 'config' => $config,
  472. 'state' => $state,
  473. ];
  474. }
  475. /**
  476. * @param $code
  477. * @param $msg
  478. * @param $data
  479. * @return Json
  480. */
  481. protected function response($code, $msg, $data = null)
  482. {
  483. return json(
  484. [
  485. 'code' => $code,
  486. 'message' => $msg,
  487. 'data' => $data,
  488. 'trackID' => Log::$logID,
  489. ],
  490. 200
  491. );
  492. }
  493. /**
  494. * @param $data
  495. * @param $msg
  496. * @return mixed
  497. */
  498. protected function successResponse($data, $msg = '操作成功')
  499. {
  500. return $this->response(0, $msg, $data);
  501. }
  502. }