User.php 9.7 KB

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