User.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. <?php
  2. namespace app\common\model;
  3. use think\Cache;
  4. use think\Db;
  5. use think\db\Query;
  6. use think\Model;
  7. use think\model\relation\BelongsToMany;
  8. use think\model\relation\HasMany;
  9. /**
  10. * 会员模型
  11. * @property int id
  12. * @property int coupon_num
  13. * @method static Query|self expired()
  14. * @property float level
  15. * @property int gender
  16. * @property int age
  17. * @property int county_id
  18. * @property int city_id
  19. * @property int province_id
  20. * @property string avatar
  21. * @property string mobile
  22. * @property string bio
  23. * @property string nickname
  24. * @property UserInfo userinfo
  25. * @property boolean wx_authed 是否已微信授权
  26. * @property boolean is_vip
  27. * @property boolean has_answered
  28. * @property boolean is_visitor
  29. */
  30. class User extends Model
  31. {
  32. protected $hidden=[
  33. 'password',
  34. 'salt',
  35. 'status',
  36. 'token',
  37. 'updatetime',
  38. 'loginfailure',
  39. 'url',
  40. 'type',
  41. 'openid',
  42. 'unionid',
  43. 'email',
  44. ];
  45. // 开启自动写入时间戳字段
  46. protected $autoWriteTimestamp = 'int';
  47. // 定义时间戳字段名
  48. protected $createTime = 'createtime';
  49. protected $updateTime = 'updatetime';
  50. // 追加属性
  51. protected $append = [
  52. 'level_text',
  53. ];
  54. const LEVEL_0=0;
  55. const LEVEL_10=10;
  56. const LEVEL_20=20;
  57. public static $levels=[
  58. self::LEVEL_0=>'游客',
  59. self::LEVEL_10=>'安检员',
  60. self::LEVEL_20=>'正式会员',
  61. ];
  62. const SCORE_EDITINFO=1;
  63. const SCORE_VIEWVIDEO=2;
  64. const SCORE_WENDA=3;
  65. const SCORE_COMMENTVIDEO=4;
  66. const SCORE_SIGN=5;
  67. const SCORE_GOODS=6;
  68. public static $scoreTypes=[
  69. self::SCORE_EDITINFO=>'完善资料',
  70. self::SCORE_VIEWVIDEO=>'看视频',
  71. self::SCORE_WENDA=>'答题',
  72. self::SCORE_COMMENTVIDEO=>'评论',
  73. self::SCORE_SIGN=>'签到',
  74. self::SCORE_GOODS=>'兑换商品',
  75. ];
  76. /**
  77. * 获取个人URL
  78. * @param string $value
  79. * @param array $data
  80. * @return string
  81. */
  82. public function getUrlAttr($value, $data)
  83. {
  84. return fullUrl("/u/" . $data['id']);
  85. }
  86. public function getLevelTextAttr($value, $data)
  87. {
  88. return self::$levels[$data['level']]??'-';
  89. }
  90. /**
  91. * 获取头像
  92. * @param string $value
  93. * @param array $data
  94. * @return string
  95. */
  96. /* public function getAvatarAttr($value, $data)
  97. {
  98. if (!$value) {
  99. //如果不需要启用首字母头像,请使用
  100. //$value = '/assets/img/avatar.png';
  101. $value = letter_avatar($data['nickname']);
  102. }
  103. return $value;
  104. }*/
  105. /**
  106. * 获取会员的组别
  107. */
  108. public function getGroupAttr($value, $data)
  109. {
  110. return UserGroup::get($data['group_id']);
  111. }
  112. /**
  113. * 变更会员余额
  114. * @param float $money 余额
  115. * @param int $user_id 会员ID
  116. * @param string $memo 备注
  117. */
  118. public static function money($money, $user_id, $type,$memo='',$extra=[],$changeMoney=true)
  119. {
  120. $user = self::lock(true)->find($user_id);
  121. if($changeMoney && !$user){
  122. throw_user('用户不存在:'.$user_id);
  123. }
  124. if ($money != 0) {
  125. if($changeMoney){
  126. $before = $user->money;
  127. //$after = $user->money + $money;
  128. $after = function_exists('bcadd') ? bcadd($user->money, $money, 2) : $user->money + $money;
  129. if($after<0){
  130. throw_user("余额不足");
  131. }
  132. //更新会员信息
  133. $user->save(['money' => $after]);
  134. }
  135. }
  136. //写入日志
  137. MoneyLog::create(array_merge([
  138. 'user_id' => $user_id,
  139. 'type'=>$type,
  140. 'money' => $money,
  141. 'before' => $before??$user->money??0,
  142. 'after' => $after??$user->money??0,
  143. 'memo' => $memo,
  144. ],$extra));
  145. }
  146. /**
  147. * 变更会员积分
  148. * @param int $score 积分
  149. * @param int $user_id 会员ID
  150. * @param string $memo 备注
  151. */
  152. public static function score($score, $user_id, $memo,$field,$type,$extra=[])
  153. {
  154. $user = self::lock(true)->find($user_id);
  155. if ($user && $score != 0) {
  156. $before = $user->$field;
  157. $after = $user->$field + $score;
  158. if($after<0){
  159. throw_user('积分不足');
  160. }
  161. //更新会员信息
  162. $user->save([$field => $after]);
  163. //写入日志
  164. ScoreLog::create(array_merge([
  165. 'field' =>$field,
  166. 'user_id' => $user_id,
  167. 'type'=>$type,
  168. 'score' => $score,
  169. 'before' => $before,
  170. 'after' => $after,
  171. 'memo' => $memo,
  172. ],$extra));
  173. }
  174. }
  175. /**
  176. *@return HasMany|UserAddress
  177. */
  178. public function address(){
  179. return $this->hasMany(UserAddress::class);
  180. }
  181. /**
  182. *@return HasMany|UserCorrectRate
  183. */
  184. public function crate(){
  185. return $this->hasMany(UserCorrectRate::class);
  186. }
  187. public function userinfo(){
  188. return $this->hasOne(UserInfo::class);
  189. }
  190. public function payment(){
  191. return $this->hasMany(Payment::class);
  192. }
  193. public function sign(){
  194. return $this->hasMany(UserSign::class);
  195. }
  196. /**
  197. *@return HasMany|MallOrder
  198. */
  199. public function mo(){
  200. return $this->hasMany(MallOrder::class);
  201. }
  202. /**
  203. * 我关注的人
  204. *@return BelongsToMany|Guest
  205. */
  206. public function follow(){
  207. return $this->belongsToMany(Guest::class,'user_follow')->order('user_follow.id','desc');
  208. }
  209. public function comments(){
  210. return $this->hasMany(Comment::class);
  211. }
  212. /**
  213. *@return VideoPointUser|HasMany
  214. */
  215. public function pointUser(){
  216. return $this->hasMany(VideoPointUser::class);
  217. }
  218. /**
  219. *@return HasMany|Like
  220. */
  221. public function like(){
  222. return $this->hasMany(Like::class);
  223. }
  224. /**
  225. *@return HasMany|Favourite
  226. */
  227. public function favourite(){
  228. return $this->hasMany(Favourite::class);
  229. }
  230. public function feedback(){
  231. return $this->hasMany(Feedback::class);
  232. }
  233. public function getHasFollowAttr(){
  234. $user=request()->_user;
  235. if(!$user){
  236. return false;
  237. }
  238. return (bool)UserFollow::where('user_id',$user['id'])->where('follow_id',$this['id'])->value('id');
  239. }
  240. public function moneylog(){
  241. return $this->hasMany(MoneyLog::class);
  242. }
  243. /**
  244. *@return ScoreLog|HasMany
  245. */
  246. public function scorelog(){
  247. return $this->hasMany(ScoreLog::class);
  248. }
  249. public function notification(){
  250. return $this->hasMany(Notification::class);
  251. }
  252. public function viewVideo(){
  253. return $this->belongsToMany(Video::class,'video_user_view');
  254. }
  255. public static function recharge($params,Payment $payment){
  256. self::money($payment['amount'],$payment['uer_id'],MoneyLog::TYPE_CHARGE,'充值');
  257. }
  258. public function verification(){
  259. return $this->hasOne(UserVerification::class);
  260. }
  261. /** 模糊搜索 */
  262. public function scopeDim(Query $query,$keyword){
  263. $keyword="%{$keyword}%";
  264. $query
  265. ->whereLike('nickname',$keyword)
  266. ->whereOr('mobile','like',$keyword)
  267. ->whereOr('username','like',$keyword);
  268. }
  269. /** scope and expired */
  270. protected static function init()
  271. {
  272. self::beforeWrite(function (self $user){
  273. $data=$user->getChangedData();
  274. #升级安检员
  275. if($user->mobile && $user->level==self::LEVEL_0){
  276. $user->level=self::LEVEL_10;
  277. }
  278. });
  279. self::afterDelete(function (self $user){
  280. $user->comments()->delete();
  281. $user->follow()->delete();
  282. $user->userinfo()->delete();
  283. $user->like()->delete();
  284. VideoUserLog::where('user_id',$user['id'])->delete();
  285. VideoUserView::where('user_id',$user['id'])->delete();
  286. });
  287. self::afterInsert(function (self $user){
  288. $user->userinfo()->save([]);
  289. });
  290. }
  291. public function scopeExpired(Query $query){
  292. $query
  293. ->whereBetween('level_close_at',[0,time()])
  294. ->where('level','>',0);
  295. }
  296. public function scopeType(Query $query,$type){
  297. $query->where('type',$type);
  298. }
  299. public function scopeUser(Query $query,$level){
  300. $query->where($this->getTable().'.level',$level);
  301. }
  302. /** attr */
  303. #获取地区
  304. public function appendArea(){
  305. $this->city_name=Area::where('id',$this->county_id?:0)->cache(true)->value('mergename','');
  306. }
  307. public function province(){
  308. return $this->belongsTo(Area::class,'province_id')->cache(true);
  309. }
  310. public function city(){
  311. return $this->belongsTo(Area::class,'city_id')->cache(true);
  312. }
  313. public function county(){
  314. return $this->belongsTo(Area::class,'county_id')->cache(true);
  315. }
  316. protected function getAvatarAttr($a){
  317. if(!$a){
  318. return request()->domain().'/assets/img/avatar.png';
  319. }
  320. return $a;
  321. }
  322. protected function getIsVipAttr($a,$b){
  323. return $b['level']==self::LEVEL_20;
  324. }
  325. protected function getIsVisitorAttr($a,$b){
  326. return $b['level']==self::LEVEL_0;
  327. }
  328. protected function getHasAnsweredAttr($a,$b){
  329. $user=request()->_user;
  330. if(!$user){
  331. return false;
  332. }
  333. return Cache::get("user:question:{$user['id']}")==date('Ymd');
  334. }
  335. /** set */
  336. public function setVip(){
  337. $this['level']=self::LEVEL_20;
  338. $this->save();
  339. }
  340. }