OrderCommentFack.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. <?php
  2. /**
  3. * 厦门云联储网络科技有限公司
  4. * https://www.baokuaiyun.com
  5. * Copyright (c) 2023 爆块云 All rights reserved.
  6. */
  7. namespace app\models;
  8. use app\models\common\admin\log\CommonActionLog;
  9. use Yii;
  10. use yii\behaviors\TimestampBehavior;
  11. use yii\db\ActiveRecord;
  12. use yii\helpers\Json;
  13. /**
  14. * This is the model class for table "{{%order_comment}}".
  15. *
  16. * @property integer $id
  17. * @property integer $store_id
  18. * @property integer $order_id
  19. * @property integer $order_detail_id
  20. * @property integer $goods_id
  21. * @property integer $user_id
  22. * @property integer $mch_id
  23. * @property string $score
  24. * @property string $content
  25. * @property string $pic_list
  26. * @property integer $is_hide
  27. * @property integer $is_delete
  28. * @property integer $created_at
  29. * @property integer $updated_at
  30. * @property string $reply_content
  31. * @property integer $is_virtual
  32. * @property string $virtual_user
  33. * @property string $virtual_avatar
  34. */
  35. class OrderCommentFack extends \yii\db\ActiveRecord
  36. {
  37. /**
  38. * 是否删除评论
  39. */
  40. const IS_DELETE_FALSE = 0;
  41. const IS_DELETE_TRUE = 1;
  42. const COMMENT_CONTENTS = [
  43. "非常好,性价比高。",
  44. "东西很好,物流也很快,性价比超高,值得购买!",
  45. "非常满意的一次购物。",
  46. "很不错,已经推荐给朋友了!",
  47. "价格很亲民,超级喜欢!",
  48. "超出了预期,值得推荐!",
  49. "值得入手!",
  50. "非常值得购买,赞一个!",
  51. "东西很好物流速度很快,好评!",
  52. "物流很快,昨天下单,今天一早就收到了,惊喜!",
  53. "很好,会回购。",
  54. "和描述一样,好评。",
  55. "性价比高,推荐购买。",
  56. "不错,挺好的。",
  57. "绝对五星好评!",
  58. "和描述一模一样,好评!",
  59. "物流超快,包装完好。",
  60. "已经推荐给朋友了。",
  61. "物超所值,强烈推荐!",
  62. "可以,没问题。",
  63. "基本满意,没问题。",
  64. "还行,符合预期。",
  65. "东西收到了,挺好。",
  66. "挺好的,会考虑回购。",
  67. "物有所值,好评。",
  68. "没什么问题,好评。",
  69. "发货快,东西完好。",
  70. "跟想象中差不多。",
  71. "总体满意,给个好评。",
  72. "对得起这个价钱了。",
  73. "已经推荐给朋友了,都说好!",
  74. "回购。",
  75. "挺好。",
  76. "不错。",
  77. "很好。",
  78. "好评",
  79. "满意",
  80. "实惠",
  81. ];
  82. /**
  83. * @inheritdoc
  84. */
  85. public static function tableName()
  86. {
  87. return '{{%order_comment_fack}}';
  88. }
  89. /**
  90. * @inheritdoc
  91. */
  92. public function rules()
  93. {
  94. return [
  95. [['store_id', 'order_id', 'order_detail_id', 'goods_id', 'user_id', 'score'], 'required'],
  96. [['store_id', 'mch_id', 'order_id', 'order_detail_id', 'goods_id', 'user_id', 'is_hide', 'is_delete',
  97. 'created_at', 'updated_at', 'is_virtual'], 'integer'],
  98. [['score'], 'number'],
  99. [['pic_list'], 'string'],
  100. [['content'], 'string', 'max' => 1000],
  101. [['reply_content', 'virtual_user', 'virtual_avatar'], 'string', 'max' => 255],
  102. ];
  103. }
  104. /**
  105. * @inheritdoc
  106. */
  107. public function attributeLabels()
  108. {
  109. return [
  110. 'id' => 'ID',
  111. 'store_id' => 'Store ID',
  112. 'mch_id' => 'Mch ID',
  113. 'order_id' => 'Order ID',
  114. 'order_detail_id' => 'Order Detail ID',
  115. 'goods_id' => 'Goods ID',
  116. 'user_id' => 'User ID',
  117. 'score' => '评分:1=差评,2=中评,3=好',
  118. 'content' => '评价内容',
  119. 'pic_list' => '图片',
  120. 'is_hide' => '是否隐藏:0=不隐藏,1=隐藏',
  121. 'is_delete' => 'Is Delete',
  122. 'created_at' => 'Addtime',
  123. 'updated_at' => 'update time',
  124. 'reply_content' => 'Reply Content',
  125. 'is_virtual' => 'Is Virtual',
  126. 'virtual_user' => 'Virtual User',
  127. 'virtual_avatar' => 'Virtual Image',
  128. ];
  129. }
  130. public function behaviors()
  131. {
  132. return [
  133. [
  134. 'class' => TimestampBehavior::class,
  135. 'attributes' => [
  136. ActiveRecord::EVENT_BEFORE_INSERT => ['created_at'],
  137. ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at']
  138. ]
  139. ]
  140. ];
  141. }
  142. public static function generateVirtualComments($goodsId, $store_id, $count = null)
  143. {
  144. if ($count === null) {
  145. $count = rand(5, 20); // 随机5-20条
  146. }
  147. // 先搜索该商品是否已有虚拟评论
  148. $existingComments = self::find()
  149. ->where(['is_virtual' => 1, 'is_delete' => 0, 'goods_id' => $goodsId])
  150. ->all();
  151. // 如果没有虚拟评论,创建新的
  152. if (empty($existingComments)) {
  153. $currentTime = time();
  154. for ($i = 0; $i < $count; $i++) {
  155. $score = self::generateRandomScore();
  156. $user = User::find()->where(['store_id' => $store_id])->orderBy('RAND()')->one();
  157. // 所有评论都在10天内随机
  158. $commentTime = $currentTime - rand(0, 864000); // 0-10天
  159. $comment = new self();
  160. $comment->goods_id = $goodsId;
  161. $comment->store_id = $store_id;
  162. $comment->order_id = rand(1000, 9999);
  163. $comment->order_detail_id = rand(1000, 9999);
  164. $comment->user_id = rand(100, 999);
  165. $comment->score = $score;
  166. $comment->content = self::COMMENT_CONTENTS[array_rand(self::COMMENT_CONTENTS)];
  167. $comment->pic_list = null;
  168. $comment->is_hide = 0;
  169. $comment->is_delete = 0;
  170. $comment->created_at = $commentTime;
  171. $comment->is_virtual = 1;
  172. $comment->virtual_user = $user->username;
  173. $comment->virtual_avatar = $user->avatar_url;
  174. $comment->mch_id = 0;
  175. $comment->updated_at = $currentTime;
  176. $comment->save();
  177. }
  178. } else {
  179. // 如果有虚拟评论,修改日期为10天内
  180. $currentTime = time();
  181. foreach ($existingComments as $comment) {
  182. $commentTime = $currentTime - rand(0, 864000); // 0-10天
  183. $comment->created_at = $commentTime;
  184. $comment->updated_at =$currentTime;
  185. $comment->save();
  186. }
  187. }
  188. return true;
  189. }
  190. /**
  191. * 生成随机评分(4-5星)
  192. */
  193. private static function generateRandomScore()
  194. {
  195. $scores = [4.0, 4.5, 5.0];
  196. $weights = [20, 30, 50]; // 权重:5星50%,4.5星30%,4星20%
  197. $random = rand(1, 100);
  198. $cumulative = 0;
  199. foreach ($weights as $index => $weight) {
  200. $cumulative += $weight;
  201. if ($random <= $cumulative) {
  202. return $scores[$index];
  203. }
  204. }
  205. return 5.0; // 默认返回5星
  206. }
  207. public static function getMixedCommentsCount($goodsId)
  208. {
  209. // 真实评价数量
  210. $realCount = OrderComment::find()
  211. ->where(['goods_id' => $goodsId, 'is_delete' => 0, 'is_hide' => 0])
  212. ->count();
  213. // 虚拟评价数量
  214. $virtualCount = OrderCommentFack::find()
  215. ->where(['is_delete' => 0, 'is_hide' => 0,'goods_id' => $goodsId])
  216. ->count();
  217. return $realCount + $virtualCount;
  218. }
  219. public static function getMixedCommentsUnion($goodsId, $limit = 20, $page = 1, $score = -1, $orderBy = 'created_at_formatted DESC')
  220. {
  221. OrderCommentFack::generateVirtualComments($goodsId,get_store_id());
  222. $offset = ($page - 1) * $limit;
  223. $sql = "
  224. (SELECT
  225. c.id, c.order_id, c.goods_id, c.user_id, c.score, c.content, c.pic_list,
  226. FROM_UNIXTIME(c.created_at, '%m-%d') as created_at_formatted,
  227. u.nickname,
  228. u.avatar_url,
  229. od.attr,
  230. (SELECT COUNT(*) FROM cyy_order_detail o WHERE o.user_id = c.user_id AND o.goods_id = c.goods_id) as purchase_count
  231. FROM cyy_order_comment c
  232. LEFT JOIN cyy_user u ON c.user_id = u.id
  233. LEFT JOIN cyy_order_detail od ON c.order_id = od.order_id AND c.goods_id = od.goods_id
  234. WHERE c.goods_id = :goodsId AND c.is_delete = 0 AND c.is_hide = 0";
  235. if ($score > -1) {
  236. switch ($score) {
  237. case 1:
  238. $sql .= " AND c.score >= 4";
  239. break;
  240. case 2:
  241. $sql .= " AND c.score >= 2 AND c.score < 4";
  242. break;
  243. case 3:
  244. $sql .= " AND c.score < 2";
  245. break;
  246. default:
  247. break;
  248. }
  249. }
  250. $sql .= ")
  251. UNION ALL
  252. (SELECT
  253. cf.id, cf.order_id, cf.goods_id, cf.user_id, cf.score, cf.content, cf.pic_list,
  254. FROM_UNIXTIME(cf.created_at, '%m-%d') as created_at_formatted,
  255. u.nickname,
  256. u.avatar_url,
  257. od.attr,
  258. (SELECT COUNT(*) FROM cyy_order_detail o WHERE o.user_id = cf.user_id AND o.goods_id = cf.goods_id) as purchase_count
  259. FROM cyy_order_comment_fack cf
  260. LEFT JOIN cyy_user u ON cf.user_id = u.id
  261. LEFT JOIN cyy_order_detail od ON cf.order_id = od.order_id AND cf.goods_id = od.goods_id
  262. WHERE cf.is_delete = 0 AND cf.is_hide = 0 AND cf.goods_id = :goodsId";
  263. if ($score > -1) {
  264. switch ($score) {
  265. case 1:
  266. $sql .= " AND cf.score < 2";
  267. break;
  268. case 2:
  269. $sql .= " AND cf.score >= 2 AND cf.score < 4";
  270. break;
  271. case 3:
  272. $sql .= " AND cf.score >= 4";
  273. break;
  274. default:
  275. break;
  276. }
  277. }
  278. $sql .= ")
  279. ORDER BY {$orderBy}
  280. LIMIT :limit OFFSET :offset
  281. ";
  282. $data['list'] = Yii::$app->db->createCommand($sql, [
  283. ':goodsId' => $goodsId,
  284. ':limit' => $limit,
  285. ':offset' => $offset
  286. ])->queryAll();
  287. $goods = Goods::findOne($goodsId);
  288. $attr_f = Json::decode($goods->attr);
  289. $attr_f = $attr_f[0]['attr_list'];
  290. $attr_name = '';
  291. foreach ($attr_f as $a){
  292. $attr_name.= $attr_name==''?$a['attr_name']:'-'.$a['attr_name'];
  293. }
  294. // 确保购买次数至少为1
  295. foreach ($data['list'] as &$item) {
  296. $item['purchase_count'] = max(1, intval($item['purchase_count']));
  297. $item['pic_list'] = empty($item['pic_list']) ? [] : Json::decode($item['pic_list']);
  298. if (!empty($item['attr'])) {
  299. $attr = Json::decode($item['attr']);
  300. $item['attr_name'] = implode('-', array_column($attr, 'attr_name'));
  301. }else{
  302. $item['attr'] = [];
  303. $item['attr_name'] = $attr_name;
  304. }
  305. }
  306. unset($item);
  307. $data['pageSize'] = $limit;
  308. $data['pageNo'] = $page;
  309. $data['totalCount'] = self::getMixedCommentsCount($goodsId);
  310. $data['amazing_rate'] = OrderCommentFack::calculateAmazingRate($goodsId);
  311. $data['satisfaction_rate'] = OrderCommentFack::calculateSatisfactionRate($goodsId);
  312. $key = 'order_comment_tags_' . $goodsId;
  313. $tags = Yii::$app->cache->get($key);
  314. if (!$tags){
  315. $tags = OrderComment::distributeTags($data['totalCount']);
  316. Yii::$app->cache->set($key, $tags, 60*5);
  317. }
  318. $data['tags'] = $tags;
  319. return $data;
  320. }
  321. public static function calculateAmazingRate($goodsId)
  322. {
  323. // 真实评价中4星及以上的数量
  324. $realHighScoreCount = OrderComment::find()
  325. ->where([
  326. 'goods_id' => $goodsId,
  327. 'is_delete' => 0,
  328. 'is_hide' => 0
  329. ])
  330. ->andWhere(['>=', 'score', 4.0])
  331. ->count();
  332. // 虚拟评价中4星及以上的数量
  333. $virtualHighScoreCount = OrderCommentFack::find()
  334. ->where([
  335. 'goods_id' => $goodsId,
  336. 'is_delete' => 0,
  337. 'is_hide' => 0
  338. ])
  339. ->andWhere(['>=', 'score', 4.0])
  340. ->count();
  341. // 总评价数量
  342. $totalCount = self::getMixedCommentsCount($goodsId);
  343. if ($totalCount == 0) {
  344. return 0;
  345. }
  346. $highScoreCount = $realHighScoreCount + $virtualHighScoreCount;
  347. return round(($highScoreCount / $totalCount) * 100, 1);
  348. }
  349. /**
  350. * 计算满意度(3星及以上评分占比)
  351. */
  352. public static function calculateSatisfactionRate($goodsId)
  353. {
  354. // 真实评价中3星及以上的数量
  355. $realSatisfiedCount = OrderComment::find()
  356. ->where([
  357. 'goods_id' => $goodsId,
  358. 'is_delete' => 0,
  359. 'is_hide' => 0
  360. ])
  361. ->andWhere(['>=', 'score', 3.0])
  362. ->count();
  363. // 虚拟评价中3星及以上的数量
  364. $virtualSatisfiedCount = OrderCommentFack::find()
  365. ->where([
  366. 'goods_id' => $goodsId,
  367. 'is_delete' => 0,
  368. 'is_hide' => 0
  369. ])
  370. ->andWhere(['>=', 'score', 3.0])
  371. ->count();
  372. // 总评价数量
  373. $totalCount = self::getMixedCommentsCount($goodsId);
  374. if ($totalCount == 0) {
  375. return 0;
  376. }
  377. $satisfiedCount = $realSatisfiedCount + $virtualSatisfiedCount;
  378. return round(($satisfiedCount / $totalCount) * 100, 1);
  379. }
  380. }