User.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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\Collection;
  8. use think\model\relation\BelongsToMany;
  9. use think\model\relation\HasMany;
  10. /**
  11. * 会员模型
  12. * @property int id
  13. * @property int coupon_num
  14. * @method static Query|self expired()
  15. * @property float level
  16. * @property int gender
  17. * @property int age
  18. * @property int county_id
  19. * @property int city_id
  20. * @property int province_id
  21. * @property string avatar
  22. * @property string mobile
  23. * @property string bio
  24. * @property string nickname
  25. * @property UserInfo userinfo
  26. * @property boolean wx_authed 是否已微信授权
  27. * @property boolean is_vip
  28. * @property boolean has_answered
  29. * @property boolean is_visitor
  30. * @property Collection orders
  31. */
  32. class User extends Model
  33. {
  34. protected $hidden=[
  35. 'password',
  36. 'salt',
  37. 'status',
  38. 'token',
  39. 'updatetime',
  40. 'loginfailure',
  41. 'url',
  42. 'type',
  43. 'openid',
  44. 'unionid',
  45. 'email',
  46. ];
  47. // 开启自动写入时间戳字段
  48. protected $autoWriteTimestamp = 'int';
  49. // 定义时间戳字段名
  50. protected $createTime = 'createtime';
  51. protected $updateTime = 'updatetime';
  52. // 追加属性
  53. protected $append = [
  54. 'level_text',
  55. ];
  56. const LEVEL_COMM=0;
  57. const LEVEL_ZS=10;
  58. const LEVEL_BJ=20;
  59. const LEVEL_JK=30;
  60. public static $levels=[
  61. self::LEVEL_COMM=>'普通用户',
  62. self::LEVEL_ZS=>'钻石',
  63. self::LEVEL_BJ=>'白金',
  64. self::LEVEL_JK=>'金卡',
  65. ];
  66. const SCORE_EDITINFO=1;
  67. const SCORE_VIEWVIDEO=2;
  68. const SCORE_WENDA=3;
  69. const SCORE_COMMENTVIDEO=4;
  70. const SCORE_SIGN=5;
  71. const SCORE_GOODS=6;
  72. public static $scoreTypes=[
  73. self::SCORE_EDITINFO=>'完善资料',
  74. self::SCORE_VIEWVIDEO=>'看视频',
  75. self::SCORE_WENDA=>'答题',
  76. self::SCORE_COMMENTVIDEO=>'评论',
  77. self::SCORE_SIGN=>'签到',
  78. self::SCORE_GOODS=>'兑换商品',
  79. ];
  80. /**
  81. * 获取个人URL
  82. * @param string $value
  83. * @param array $data
  84. * @return string
  85. */
  86. public function getUrlAttr($value, $data)
  87. {
  88. return fullUrl("/u/" . $data['id']);
  89. }
  90. public function getLevelTextAttr($value, $data)
  91. {
  92. return self::$levels[$data['level']]??'-';
  93. }
  94. /**
  95. * @return string[]
  96. */
  97. public static function getLevels(): array
  98. {
  99. return self::$levels;
  100. }
  101. /**
  102. * 获取会员的组别
  103. */
  104. public function getGroupAttr($value, $data)
  105. {
  106. return UserGroup::get($data['group_id']);
  107. }
  108. /**
  109. * 变更会员余额
  110. * @param float $money 余额
  111. * @param int $user_id 会员ID
  112. * @param string $memo 备注
  113. */
  114. public static function money($money, $user_id, $type,$memo='',$extra=[],$changeMoney=true)
  115. {
  116. $user = self::lock(true)->find($user_id);
  117. if($changeMoney && !$user){
  118. throw_user('用户不存在:'.$user_id);
  119. }
  120. if ($money != 0) {
  121. if($changeMoney){
  122. $before = $user->money;
  123. //$after = $user->money + $money;
  124. $after = function_exists('bcadd') ? bcadd($user->money, $money, 2) : $user->money + $money;
  125. if($after<0){
  126. throw_user("余额不足");
  127. }
  128. //更新会员信息
  129. $user->save(['money' => $after]);
  130. }
  131. }
  132. //写入日志
  133. MoneyLog::create(array_merge([
  134. 'user_id' => $user_id,
  135. 'type'=>$type,
  136. 'money' => $money,
  137. 'before' => $before??$user->money??0,
  138. 'after' => $after??$user->money??0,
  139. 'memo' => $memo,
  140. ],$extra));
  141. }
  142. /**
  143. * 变更会员积分
  144. * @param int $score 积分
  145. * @param int $user_id 会员ID
  146. * @param string $memo 备注
  147. */
  148. public static function score($score, $user_id, $memo,$field,$type,$extra=[])
  149. {
  150. $user = self::lock(true)->find($user_id);
  151. if ($user && $score != 0) {
  152. $before = $user->$field;
  153. $after = $user->$field + $score;
  154. if($after<0){
  155. throw_user('积分不足');
  156. }
  157. //更新会员信息
  158. $user->save([$field => $after]);
  159. //写入日志
  160. ScoreLog::create(array_merge([
  161. 'field' =>$field,
  162. 'user_id' => $user_id,
  163. 'type'=>$type,
  164. 'score' => $score,
  165. 'before' => $before,
  166. 'after' => $after,
  167. 'memo' => $memo,
  168. ],$extra));
  169. }
  170. }
  171. /**
  172. *@return HasMany|UserAddress
  173. */
  174. public function address(){
  175. return $this->hasMany(UserAddress::class);
  176. }
  177. public function userinfo(){
  178. return $this->hasOne(UserInfo::class);
  179. }
  180. public function payment(){
  181. return $this->hasMany(Payment::class);
  182. }
  183. public function comments(){
  184. return $this->hasMany(Comment::class);
  185. }
  186. /**
  187. *@return HasMany|Favourite
  188. */
  189. public function favourite(){
  190. return $this->hasMany(Favourite::class)->where('fav_type','goods');
  191. }
  192. public function feedback(){
  193. return $this->hasMany(Feedback::class);
  194. }
  195. public function moneylog(){
  196. return $this->hasMany(MoneyLog::class);
  197. }
  198. public function tax(){
  199. return $this->hasMany(UserTax::class);
  200. }
  201. /**
  202. * @return Orders|HasMany
  203. */
  204. public function orders(){
  205. return $this->hasMany(Orders::class);
  206. }
  207. public function programmes(){
  208. return $this->hasMany(Programme::class);
  209. }
  210. /**
  211. * @return OrderInfo|HasMany
  212. */
  213. public function orderInfo(){
  214. return $this->hasMany(OrderInfo::class);
  215. }
  216. /**
  217. *@return ScoreLog|HasMany
  218. */
  219. public function scorelog(){
  220. return $this->hasMany(ScoreLog::class);
  221. }
  222. public function cart(){
  223. return $this->hasMany(GoodsCart::class);
  224. }
  225. public function coupon(){
  226. return $this->hasMany(UserCoupon::class);
  227. }
  228. public static function recharge($params,Payment $payment){
  229. self::money($payment['amount'],$payment['uer_id'],MoneyLog::TYPE_CHARGE,'充值');
  230. }
  231. public function verification(){
  232. return $this->hasOne(UserVerification::class);
  233. }
  234. /** 模糊搜索 */
  235. public function scopeDim(Query $query,$keyword){
  236. $keyword="%{$keyword}%";
  237. $query
  238. ->whereLike('nickname',$keyword)
  239. ->whereOr('mobile','like',$keyword)
  240. ->whereOr('username','like',$keyword);
  241. }
  242. /** scope and expired */
  243. protected static function init()
  244. {
  245. self::beforeWrite(function (self $user){
  246. $data=$user->getChangedData();
  247. });
  248. self::afterDelete(function (self $user){
  249. });
  250. self::afterInsert(function (self $user){
  251. $user->userinfo()->save([]);
  252. });
  253. }
  254. public function scopeExpired(Query $query){
  255. $query
  256. ->whereBetween('level_close_at',[0,time()])
  257. ->where('level','>',0);
  258. }
  259. public function scopeType(Query $query,$type){
  260. $query->where('type',$type);
  261. }
  262. public function scopeUser(Query $query,$level){
  263. $query->where($this->getTable().'.level',$level);
  264. }
  265. /** attr */
  266. #获取地区
  267. public function appendArea(){
  268. $this->city_name=Area::where('id',$this->county_id?:0)->cache(true)->value('mergename','');
  269. }
  270. public function province(){
  271. return $this->belongsTo(Area::class,'province_id')->cache(true);
  272. }
  273. public function city(){
  274. return $this->belongsTo(Area::class,'city_id')->cache(true);
  275. }
  276. public function county(){
  277. return $this->belongsTo(Area::class,'county_id')->cache(true);
  278. }
  279. protected function getAvatarAttr($a){
  280. if(!$a){
  281. return request()->domain().'/assets/img/avatar.png';
  282. }
  283. return $a;
  284. }
  285. }