User.php 9.5 KB

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