VideoController.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. <?php
  2. namespace addons\ShortVideo\api\modules\v1\controllers;
  3. use addons\ContentMatrix\common\models\Export;
  4. use addons\ShortVideo\common\enums\AddonsShortVideoEnum;
  5. use addons\ShortVideo\common\events\VideoRewardPush;
  6. use addons\ShortVideo\common\events\VideoTaskConfig;
  7. use addons\ShortVideo\common\models\ShortVideo;
  8. use addons\ShortVideo\common\models\ShortVideoBrowse;
  9. use addons\ShortVideo\common\models\ShortVideoBrowseAward;
  10. use addons\ShortVideo\common\models\ShortVideoConfig;
  11. use addons\ShortVideo\common\models\ShortVideoFollow;
  12. use addons\ShortVideo\common\models\ShortVideoLike;
  13. use addons\ShortVideo\common\models\ShortVideoShare;
  14. use addons\ShortVideo\common\models\ShortVideoTag;
  15. use addons\ShortVideo\common\models\ShortVideoUserWatch;
  16. use common\enums\RedisKeyEnum;
  17. use common\helpers\LockHelper;
  18. use Yii;
  19. use api\controllers\OnAuthController;
  20. use Codeception\Template\Api;
  21. use common\components\sensitivewords\SensitiveWords;
  22. use common\enums\AddonsEnum;
  23. use common\enums\RabbitMqEnum;
  24. use common\enums\StatusEnum;
  25. use common\helpers\FfmpegHelper;
  26. use common\models\common\Attachment;
  27. use common\models\goods\Goods;
  28. use common\models\mall\MallAddons;
  29. use common\models\user\User;
  30. use common\models\user\UserFollow;
  31. use Exception;
  32. use yii\db\Expression;
  33. /**
  34. * 视频控制器
  35. *
  36. * Class DefaultController
  37. * @package addons\ShortVideo\api\modules\v1\controllers
  38. */
  39. class VideoController extends BaseController
  40. {
  41. public $modelClass = '';
  42. /**
  43. * 不用进行登录验证的方法
  44. *
  45. * 例如: ['index', 'update', 'create', 'view', 'delete']
  46. * 默认全部需要验证
  47. *
  48. * @var array
  49. */
  50. protected $authOptional = ['list', 'video-browse', 'get-pub-method-data'];
  51. /**
  52. * @name:
  53. * @msg: 视频列表
  54. * @param {integer} $video_type 视频类型,1:视频列表;2:喜欢的视频
  55. * @param {integer} $user_id
  56. * @param {integer} $tag_id
  57. * @param {integer} $page
  58. * @param {integer} $limit
  59. * @return {*}
  60. */
  61. public function actionList()
  62. {
  63. // \Yii::error('short-video-list-url: ' . \Yii::$app->request->absoluteUrl);\Yii::getLogger()->flush(true);
  64. if (!\Yii::$app->request->isGet) {
  65. return $this->error('请求方式错误');
  66. }
  67. // 视频类型,1:公共视频列表;2:喜欢的视频;3:自己发布的视频
  68. $video_type = \Yii::$app->request->get('video_type');
  69. $user_id = \Yii::$app->request->get('user_id');
  70. $tag_id = \Yii::$app->request->get('tag_id');
  71. $share_video_id = \Yii::$app->request->get('video_id');
  72. $page = \Yii::$app->request->get('page', 1);
  73. $limit = \Yii::$app->request->get('limit', $this->pageSize);
  74. if (empty($video_type) || !in_array($video_type, [1, 2, 3])) return $this->error('参数错误:video_type');
  75. if ($video_type != 1 && empty($user_id)) return $this->error('参数错误:个人中心内查看视频列表,user_id 不能为空');
  76. $wheres[] = ['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'is_blacklist' => 0];
  77. // 如果不是查看自己的视频则必须是审核通过后的视频
  78. if (3 != $video_type || (3 == $video_type && $user_id != $this->user_id)) {
  79. // 不是自己的视频列表必须是审核通过的视频
  80. $wheres[] = ['check_status' => AddonsShortVideoEnum::VIDEO_AUDIT_STATUS1];
  81. }
  82. if (3 == $video_type) {
  83. // 个人中心--我的作品
  84. $wheres[] = ['user_id' => $user_id];
  85. }
  86. // 喜欢的视频
  87. if (2 == $video_type) {
  88. $likes = ShortVideoLike::find()
  89. ->select('video_id,user_id')
  90. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'user_id' => $user_id])
  91. ->asArray()
  92. ->indexBy('video_id')
  93. ->all();
  94. $wheres[] = ['id' => array_column($likes, 'video_id')];
  95. }
  96. $config = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_SHORT_VIDEO, 'basic');
  97. if (1 == $video_type && $config['is_shuffle'] == 1 && !empty($this->user_id)) {
  98. $wheres[]=['not exists', ShortVideoUserWatch::find()->alias('svb')->where(['status' => StatusEnum::ENABLED])->andWhere(['svb.user_id' => $this->user_id])
  99. ->andWhere(new Expression('svb.video_id=sv.id'))];
  100. $_GET['page'] = 1;
  101. }
  102. $select = 'id,mall_id,user_id,is_top,title,content,video_url,first_frame,video_wide,video_long,related_type,related_goods_id,related_store_id,related_address,related_detailed_address,related_lon,related_lat,comment_num,like_num,look_people_num,look_complete_num,look_num,share_num,share_click_num,created_at,open_integral_award,open_money_award,check_status,check_remark,duration_seconds,tag_id';
  103. $order_by = "is_top desc,top_time desc,created_at desc,share_num desc,like_num desc,look_num desc";
  104. // 按照标签搜索
  105. if (!empty($tag_id)) $wheres[] = new Expression("FIND_IN_SET('$tag_id', tag_id)");
  106. $params = [
  107. 'alias' => 'sv',
  108. 'select' => $select,
  109. 'where' => $wheres,
  110. 'order' => $order_by,
  111. 'page' => $page,
  112. 'limit' => $limit,
  113. ];
  114. $videos = ShortVideo::listPage($params);
  115. $video_ids = array_column($videos['list'], 'id');
  116. if($page == 1 && $share_video_id && !in_array($share_video_id, $video_ids)) {
  117. $share_video_info = ShortVideo::getOne([['id' => $share_video_id]],true);
  118. if($share_video_info) $videos['list'] = array_merge([$share_video_info], $videos['list']);
  119. }
  120. if (empty($videos['list'])) {
  121. if (is_array($videos['list'])) {
  122. return $this->success('success', $videos);
  123. } else {
  124. return $this->error(ShortVideo::getStaticError());
  125. }
  126. } else {
  127. if (($videos['count'] < 20 || $videos['page_count'] <= 1) && !empty($this->user_id)) {
  128. Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, ['mall_id' => $this->mall_id, 'user_id' => $this->user_id], ShortVideoUserWatch::class, 'changeWatchStatus');
  129. }
  130. // shuffle($videos['list']);
  131. }
  132. if (empty($user_id)) {
  133. $user_ids = array_column($videos['list'], 'user_id');
  134. } else {
  135. $user_ids = $user_id;
  136. }
  137. // 会员
  138. $users = User::find()
  139. ->select('id,nickname,avatar_url')
  140. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $user_ids])
  141. ->asArray()
  142. ->indexBy('id')
  143. ->all();
  144. // 关注
  145. $follow_users = UserFollow::find()
  146. ->select('user_id')
  147. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'follow_id' => $user_ids])
  148. ->asArray()
  149. ->column();
  150. // 商品
  151. $good_ids = array_column($videos['list'], 'related_goods_id');
  152. $goods = Goods::find()
  153. ->select('id,goods_name,cover_pic,price,sales_num')
  154. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $good_ids, 'is_on_sale' => 1])
  155. ->asArray()
  156. ->indexBy('id')
  157. ->all();
  158. // 店铺
  159. $store_ids = array_column($videos['list'], 'related_store_id');
  160. // TODO:店铺暂时没有
  161. $stores = [];
  162. // 观看奖励
  163. $video_ids = array_column($videos['list'], 'id');
  164. $rewards = ShortVideoBrowseAward::find()
  165. ->select('video_id,user_id')
  166. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'video_id' => $video_ids, 'user_id' => $this->user_id, 'user_type' => 0])
  167. ->asArray()
  168. ->indexBy('video_id')
  169. ->all();
  170. // 点赞
  171. if (empty($likes)) {
  172. $likes = ShortVideoLike::find()
  173. ->select('video_id,user_id')
  174. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'video_id' => $video_ids, 'user_id' => $this->user_id])
  175. ->asArray()
  176. ->indexBy('video_id')
  177. ->all();
  178. }
  179. // 关联标签
  180. $video_tags = [];
  181. $tag_id_arr = array_column($videos['list'], 'tag_id', 'id');
  182. if (!empty($tag_id_arr)) {
  183. $tag_ids = [];
  184. foreach ($tag_id_arr as $tag_id_str) {
  185. $tag_ids = array_merge($tag_ids, explode(',', $tag_id_str));
  186. }
  187. $tag_all = ShortVideoTag::find()
  188. ->select('id,name')
  189. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $tag_ids])
  190. ->orderBy('recommend_time desc,created_at desc')
  191. ->asArray()
  192. ->indexBy('id')
  193. ->all();
  194. foreach ($tag_id_arr as $video_id => $tag_id_str) {
  195. $video_tag_ids = explode(',', $tag_id_str);
  196. foreach ($video_tag_ids as $tag_id) {
  197. if (!empty($tag_all[$tag_id])) $video_tags[$video_id][] = $tag_all[$tag_id];
  198. }
  199. }
  200. }
  201. // 分享
  202. $shares = ShortVideoShare::find()
  203. ->select('user_id,video_id')
  204. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'video_id' => $video_ids, 'user_id' => $this->user_id])
  205. ->asArray()
  206. ->indexBy('video_id')
  207. ->all();
  208. foreach ($videos['list'] as $index => &$video) {
  209. $user = $users[$video['user_id']] ?? [];
  210. $reward = $rewards[$video['id']] ?? [];
  211. $like = $likes[$video['id']] ?? [];
  212. $share = $shares[$video['id']] ?? [];
  213. $video['nickname'] = $user['nickname'] ?? '默认会员';
  214. $video['avatar_url'] = $user['avatar_url'] ?? \Yii::$app->request->hostInfo . '/resources/img/common/default-avatar.png';
  215. $video['good_info'] = $goods[$video['related_goods_id']] ?? [];
  216. $video['store_info'] = $stores[$video['related_store_id']] ?? [];
  217. $video['is_send_browse_reward'] = empty($reward) ? 0 : 1;
  218. $video['is_liked'] = empty($like) ? 0 : 1;
  219. $video['tags'] = $video_tags[$video['id']] ?? [];
  220. if (1 == $video['open_integral_award'] || 1 == $video['open_money_award']) {
  221. $video['is_reward'] = 1;
  222. } else {
  223. $video['is_reward'] = 0;
  224. }
  225. if ($this->user_id == $video['user_id']) {
  226. $video['is_follow'] = 0;
  227. } else {
  228. $video['is_follow'] = in_array($this->user_id, $follow_users) ? 1 : 0;
  229. }
  230. $video['is_share'] = empty($share) ? 0 : 1;
  231. if (!empty($share_video_id)) {
  232. // 进来此区间说明是从分享链接点击进来短视频首页
  233. if ($video['id'] == $share_video_id) {
  234. $share_video = $video;
  235. unset($videos['list'][$index]);
  236. }
  237. }
  238. }
  239. if (!empty($share_video)) {
  240. array_unshift($videos['list'], $share_video);
  241. $video_update_params = [
  242. 'id' => $share_video['id'],
  243. 'share_click_num' => $share_video['share_click_num'] + 1,
  244. ];
  245. ShortVideo::setData($this->mall_id, $video_update_params);
  246. }
  247. $configs = ShortVideoConfig::getConfig($this->mall_id);
  248. $share_info = [
  249. 'share_img' => $configs['share_img'] ?? '',
  250. 'share_title' => $configs['share_title'] ?? '',
  251. 'share_content' => $configs['share_content'] ?? '',
  252. ];
  253. $videos['share_info'] = $share_info;
  254. $videos['status_map'] = AddonsShortVideoEnum::getAuditStatusMap();
  255. return $this->success('success', $videos);
  256. }
  257. public function actionCreateVideo()
  258. {
  259. if (!\Yii::$app->request->isPost) {
  260. return $this->error('请求方式错误');
  261. }
  262. $configs = ShortVideoConfig::getConfig($this->mall_id);
  263. if (empty($configs)) return $this->error('系统配置错误,请联系管理员');
  264. if (1 != $configs['is_enabled']) return $this->error('短视频应用未开启,请联系管理员');
  265. $rst = ShortVideo::userCanPush($this->mall_id, $this->user_id);
  266. if (!$rst['is_can_push']) {
  267. return $this->error($rst['errmsg']);
  268. }
  269. $post = \Yii::$app->request->post();
  270. $id = $post['id'] ?? 0;
  271. $rules = [
  272. [['title', 'content', 'video_url', 'tag_id', 'related_type'], 'required'],
  273. ['related_goods_id', 'required', 'when' => function ($model) {
  274. return $model->related_type == AddonsShortVideoEnum::VIDEO_RELATE_TYPE1;
  275. }],
  276. ['related_store_id', 'required', 'when' => function ($model) {
  277. return $model->related_type == AddonsShortVideoEnum::VIDEO_RELATE_TYPE2;
  278. }],
  279. ['related_address', 'required', 'when' => function ($model) {
  280. return $model->related_type == AddonsShortVideoEnum::VIDEO_RELATE_TYPE3;
  281. }],
  282. ['related_lat', 'required', 'when' => function ($model) {
  283. return $model->related_type == AddonsShortVideoEnum::VIDEO_RELATE_TYPE3;
  284. }],
  285. ['related_lat', 'required', 'when' => function ($model) {
  286. return $model->related_type == AddonsShortVideoEnum::VIDEO_RELATE_TYPE3;
  287. }],
  288. ['related_detailed_address', 'required', 'when' => function ($model) {
  289. return $model->related_type == AddonsShortVideoEnum::VIDEO_RELATE_TYPE3;
  290. }],
  291. [['related_type', 'related_goods_id', 'related_store_id'], 'number'],
  292. [['related_goods_id', 'related_store_id'], 'default', 'value' => 0],
  293. [['related_address', 'related_detailed_address','first_frame'], 'default', 'value' => ''],
  294. [['related_lat', 'related_lon'], 'default', 'value' => '0'],
  295. ['related_type', 'in', 'range' => [1, 2, 3, 4]],
  296. [['duration_seconds'], 'number']
  297. ];
  298. $res = \Yii::$app->services->validate->validate($post, $rules);
  299. if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage());
  300. $post['id'] = $id;
  301. if (AddonsShortVideoEnum::CLIENT_STATUS1 == $configs['client_status']) {
  302. //验证标题内容是否有敏感词汇
  303. $sensitive = new SensitiveWords();
  304. $textStatus = $sensitive->getTextStatus($post['title'], $this->mall_id);
  305. if ($textStatus['status'] != 0) {
  306. return $this->error('视频标题包含敏感词汇:' . $textStatus['msg']);
  307. }
  308. $textStatus = $sensitive->getTextStatus($post['content'], $this->mall_id);
  309. if ($textStatus['status'] != 0) {
  310. return $this->error('视频描述内容包含敏感词汇:' . $textStatus['msg']);
  311. }
  312. }
  313. if (1 == $post['related_type']) {
  314. $good = Goods::findOne(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $post['related_goods_id'], 'is_on_sale' => 1]);
  315. if (empty($good)) return $this->error('关联的商品不存在');
  316. }
  317. if (2 == $post['related_type']) {
  318. // 关联店铺
  319. // TODO: 验证店铺
  320. }
  321. $tag = ShortVideoTag::findOne(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $post['tag_id']]);
  322. if (empty($tag)) return $this->error('关联的标签不存在');
  323. if (1 == $configs['is_check']) {
  324. $audit_status = 0;
  325. } else {
  326. $audit_status = 1;
  327. }
  328. // 增加索引搜索,saas的表中有3000万条数据,模糊搜索url,会很久
  329. $attachment = Attachment::find()
  330. ->select(['id', 'width', 'height', 'duration_str', 'duration_seconds'])
  331. ->where(['mall_id' => $this->mall_id,'is_delete' => 0,'is_recycle' => 0,'url' => $post['video_url']])
  332. ->from('qimall_attachment USE INDEX (idx_mall_delete_recycle_url)')
  333. ->one();
  334. $post['duration_seconds'] = ceil($post['duration_seconds']);
  335. $video_data = [
  336. 'user_id' => $this->user_id,
  337. 'video_wide' => $attachment->width ?? 0,
  338. 'video_long' => $attachment->height ?? 0,
  339. 'check_status' => $audit_status,
  340. 'is_blacklist' => 0,
  341. 'is_top' => 0,
  342. 'status' => 1,
  343. 'duration_str' => $attachment->duration_str ?? '0',
  344. 'duration_seconds' => $post['duration_seconds'] ?? 0,
  345. ];
  346. $video_data = array_merge($post, $video_data);
  347. $res = ShortVideo::setData($this->mall_id, $video_data);
  348. if (false === $res) return $this->error('发布视频失败: ' . ShortVideo::getStaticError());
  349. return $this->success('发布视频成功', ['is_check' => $configs['is_check']]);
  350. }
  351. /**
  352. * @name:
  353. * @msg: 获取视频详情
  354. * @param {*}
  355. * @return {*}
  356. */
  357. public function actionDetail()
  358. {
  359. if (!\Yii::$app->request->isGet) {
  360. return $this->error('请求方式错误');
  361. }
  362. $video_id = \Yii::$app->request->get('video_id');
  363. if (empty($video_id)) return $this->error('参数错误');
  364. $video = ShortVideo::find()
  365. ->select('id,mall_id,title,content,video_url,first_frame,related_type,related_goods_id,related_store_id,related_address,related_detailed_address,related_lon,related_lat,tag_id,check_remark,check_status,created_at,duration_seconds')
  366. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'is_blacklist' => 0, 'id' => $video_id])
  367. ->asArray()
  368. ->one();
  369. if (empty($video)) return $this->error('视频不存在');
  370. $good = [];
  371. $store = [];
  372. $tags = [];
  373. if (1 == $video['related_type']) {
  374. // 关联商品
  375. $good = Goods::find()
  376. ->select('id,goods_name,price,cover_pic')
  377. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'is_on_sale' => 1, 'id' => $video['related_goods_id']])
  378. ->asArray()
  379. ->one();
  380. } elseif (2 == $video['related_type']) {
  381. // 关联店铺
  382. }
  383. if (!empty($video['tag_id'])) {
  384. $tag_ids = explode(',', $video['tag_id']);
  385. $tags = ShortVideoTag::find()
  386. ->select('id,mall_id,name,is_recommend,created_at')
  387. ->where(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $tag_ids])
  388. ->asArray()
  389. ->all();
  390. }
  391. $video['good_info'] = $good;
  392. $video['store_info'] = $store;
  393. $video['tags'] = $tags;
  394. return $this->success('success', $video);
  395. }
  396. /**
  397. * @name:
  398. * @msg: 视频点赞
  399. * @param {*}
  400. * @return {*}
  401. */
  402. public function actionPraiseVideo()
  403. {
  404. if (!\Yii::$app->request->isGet) {
  405. return $this->error('请求方式错误');
  406. }
  407. $video_id = \Yii::$app->request->get('video_id');
  408. $type = \Yii::$app->request->get('type');
  409. if (empty($video_id) || (empty($type) || !in_array($type, ['praise', 'unpraise']))) return $this->error('参数错误');
  410. $video = ShortVideo::findOne(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $video_id, 'check_status' => 1, 'is_blacklist' => 0]);
  411. if (empty($video)) return $this->error('视频不存在');
  412. $like = ShortVideoLike::findOne(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'video_id' => $video_id, 'user_id' => $this->user_id]);
  413. if (empty($like)) {
  414. if ('praise' == $type) {
  415. $like_data = [
  416. 'user_id' => $this->user_id,
  417. 'video_id' => $video_id,
  418. ];
  419. $res_like = ShortVideoLike::setData($this->mall_id, $like_data);
  420. $notice = '点赞成功';
  421. } else {
  422. return $this->success('取消成功');
  423. }
  424. } else {
  425. if ('praise' == $type) {
  426. return $this->success('点赞成功');
  427. } else {
  428. $like_data = [
  429. 'id' => $like->id,
  430. 'video_id' => $video_id,
  431. 'status' => StatusEnum::DELETE,
  432. ];
  433. $res_like = ShortVideoLike::setData($this->mall_id, $like_data);
  434. $notice = '取消成功';
  435. }
  436. }
  437. if (false === $res_like) return $this->error('点赞失败:' . ShortVideoLike::getStaticError());
  438. return $this->success($notice);
  439. }
  440. /**
  441. * @name:
  442. * @msg: 关注/取消关注会员
  443. * @param {*}
  444. * @return {*}
  445. */
  446. public function actionFollow()
  447. {
  448. if (!\Yii::$app->request->isGet) {
  449. return $this->error('请求方式错误');
  450. }
  451. $user_id = \Yii::$app->request->get('user_id');
  452. $type = \Yii::$app->request->get('type');
  453. if (empty($user_id) || (empty($type) || !in_array($type, ['follow', 'unfollow']))) return $this->error('参数错误');
  454. if ($user_id == $this->user_id) return $this->error('不可以关注自己');
  455. $follow_user = User::findOne(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'id' => $user_id]);
  456. if (empty($follow_user)) return $this->error('关注的会员不存在');
  457. $op = '关注';
  458. $params = [
  459. 'user_id' => $this->user_id,
  460. 'follow_id' => $user_id,
  461. 'status' => StatusEnum::ENABLED,
  462. ];
  463. if ('unfollow' == $type) {
  464. $params['status'] = StatusEnum::DELETE;
  465. $op = '取消关注';
  466. }
  467. $res = ShortVideoFollow::setData($this->mall_id, $params);
  468. if (false === $res) return $this->error($op . '失败:' . ShortVideoFollow::getStaticError());
  469. return $this->success($op . '成功');
  470. }
  471. /**
  472. * @name:
  473. * @msg: 浏览视频
  474. * @param {integer} $video_id
  475. * @param {integer} $share_user_id
  476. * @return {*}
  477. */
  478. public function actionVideoBrowse()
  479. {
  480. if (!\Yii::$app->request->isGet) {
  481. return $this->error('请求方式错误');
  482. }
  483. // 如果没有登录,则不记录浏览记录
  484. if (empty($this->user_id)) {
  485. return $this->success('ok');
  486. }
  487. $video_id = \Yii::$app->request->get('video_id');
  488. $share_user_id = \Yii::$app->request->get('share_user_id') ?? 0;
  489. if (empty($video_id)) return $this->error('参数错误');
  490. if (!empty($share_user_id)) {
  491. $share_log = ShortVideoShare::findOne(['mall_id' => $this->mall_id, 'status' => StatusEnum::ENABLED, 'user_id' => $share_user_id, 'video_id' => $video_id]);
  492. if (empty($share_log)) return $this->error('分享记录不存在');
  493. }
  494. $params = [
  495. 'video_id' => $video_id,
  496. 'user_id' => $this->user_id,
  497. 'share_user_id' => $share_user_id,
  498. ];
  499. $res = ShortVideo::browse($this->mall_id, $params);
  500. if (false === $res) return $this->error('操作失败');
  501. return $this->success('操作成功', ['browse_log_id' => $res->id]);
  502. }
  503. /**
  504. * @name:
  505. * @msg: 删除视频
  506. * @param {integer} $video_id
  507. * @return {*}
  508. */
  509. public function actionVideoDelete()
  510. {
  511. if (!\Yii::$app->request->isPost) {
  512. return $this->error('请求方式错误');
  513. }
  514. $video_id = \Yii::$app->request->post('video_id');
  515. if (empty($video_id) || !is_numeric($video_id)) return $this->error('参数错误');
  516. $params = [
  517. 'id' => $video_id,
  518. 'user_id' => $this->user_id,
  519. 'status' => StatusEnum::DELETE,
  520. ];
  521. $res = ShortVideo::setData($this->mall_id, $params);
  522. if (false === $res) return $this->error('删除失败:' . ShortVideo::getStaticError());
  523. return $this->success('删除成功');
  524. }
  525. /**
  526. * @name:
  527. * @msg: 视频分享
  528. * @param {integer} $video_id
  529. * @return {*}
  530. */
  531. public function actionVideoShare()
  532. {
  533. if (!\Yii::$app->request->isPost) {
  534. return $this->error('请求方式错误');
  535. }
  536. $video_id = \Yii::$app->request->post('video_id');
  537. if (empty($video_id) || !is_numeric($video_id)) return $this->error('参数错误');
  538. $params = [
  539. 'video_id' => $video_id,
  540. 'user_id' => $this->user_id,
  541. ];
  542. $res = ShortVideoShare::setData($this->mall_id, $params);
  543. if (false === $res) return $this->error('分享失败:' . ShortVideo::getStaticError());
  544. return $this->success('分享成功', ['share_log_id' => $res->id]);
  545. }
  546. /**
  547. * @name:
  548. * @msg: 会员完整观看视频,发放奖励
  549. * @param {integer} $video_id 视频id
  550. * @param {integer} $browse_log_id 观看视频记录id
  551. * @return {*}
  552. */
  553. public function actionWatchComplete()
  554. {
  555. if (!\Yii::$app->request->isPost) {
  556. return $this->error('请求方式错误');
  557. }
  558. $video_id = \Yii::$app->request->post('video_id');
  559. $share_user_id = \Yii::$app->request->post('share_user_id', 0);
  560. if (empty($video_id) || !is_numeric($video_id)) return $this->error('参数错误');
  561. $params = [
  562. 'video_id' => $video_id,
  563. 'user_id' => $this->user_id,
  564. 'share_user_id' => $share_user_id,
  565. ];
  566. $lock_key = RedisKeyEnum::suffix(AddonsShortVideoEnum::LOCK_SHORT_VIDEO_BROWSE_AWARD ,$video_id);
  567. $identification = uniqid();
  568. try {
  569. if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new \Exception('当前访问人数过多');
  570. $res = ShortVideoBrowseAward::grantReward($this->mall_id, $params);
  571. if (false === $res) throw new \Exception('奖励发放失败:' . ShortVideo::getStaticError());
  572. LockHelper::ulock($lock_key,$identification);
  573. return $this->success('奖励发放成功', $res);
  574. }catch (\Exception $e){
  575. LockHelper::ulock($lock_key,$identification);
  576. return $this->success($e->getMessage());
  577. }
  578. }
  579. //获取酒馆插件短视频打卡配置数据
  580. public function actionGetPubMethodData()
  581. {
  582. $request = Yii::$app->request;
  583. if ($request->isGet) {
  584. try {
  585. $get = $request->get();
  586. $res = Yii::$app->services->validate->validate($get, [
  587. [['video_id'], 'integer'],
  588. ]);
  589. if (!$res) throw new Exception(Yii::$app->services->validate->getErrorMessage());
  590. $data = [
  591. 'video_id' => $get['video_id'],
  592. 'user_id' => $this->user_id,
  593. 'task_list' => [], //视频任务列表
  594. 'show_video_work' => 0, //是否显示视频任务
  595. 'read_second' => 0, //视频任务进度条
  596. 'read_second_list' => [], //观看视频累计时长触发奖励节点
  597. ];
  598. //获取其他插件视频配置
  599. $event = new VideoTaskConfig($this->mall_id, $data);
  600. Yii::$app->services->events->dispatch($event);
  601. $data = $event->getResultForm();
  602. return $this->success('获取成功', $data);
  603. } catch (\Exception $e) {
  604. return $this->error($e->getMessage());
  605. }
  606. }
  607. }
  608. //添加完成视频观看数据
  609. public function actionSetVideoTaskData()
  610. {
  611. $request = Yii::$app->request;
  612. if ($request->isPost) {
  613. try {
  614. $post = $request->post();
  615. $res = Yii::$app->services->validate->validate($post, [
  616. [['video_id', 'read_second', 'share_user_id'], 'integer']
  617. ]);
  618. if (!$res) throw new Exception(Yii::$app->services->validate->getErrorMessage());
  619. $event = new VideoRewardPush($this->mall_id);
  620. $post['mall_id'] = $this->mall_id;
  621. $post['user_id'] = $this->user_id;
  622. \Yii::$app->services->events->dispatch($event, $post, $event->listeners);
  623. return $this->success('操作成功');
  624. } catch (\Exception $e) {
  625. $this->error($e->getMessage());
  626. }
  627. }
  628. }
  629. }