User.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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 mobile
  25. * @property string bio
  26. * @property string nickname
  27. * @property string password
  28. * @property string salt
  29. * @property UserInfo userinfo
  30. * @property boolean wx_authed 是否已微信授权
  31. * @property boolean is_vip
  32. * @property boolean has_answered
  33. * @property boolean is_visitor
  34. * @property Collection orders
  35. * @property Admin admin
  36. */
  37. class User extends Model
  38. {
  39. protected $hidden=[
  40. 'password',
  41. 'salt',
  42. 'status',
  43. 'token',
  44. 'updatetime',
  45. 'loginfailure',
  46. 'url',
  47. 'type',
  48. 'openid',
  49. 'unionid',
  50. 'email',
  51. ];
  52. // 开启自动写入时间戳字段
  53. protected $autoWriteTimestamp = 'int';
  54. // 定义时间戳字段名
  55. protected $createTime = 'createtime';
  56. protected $updateTime = 'updatetime';
  57. // 追加属性
  58. protected $append = [
  59. 'level_text',
  60. ];
  61. const LEVEL_COMM=0;
  62. const LEVEL_ZS=10;
  63. const LEVEL_BJ=20;
  64. const LEVEL_JK=30;
  65. public static $levels=[
  66. self::LEVEL_COMM=>'普通用户',
  67. self::LEVEL_ZS=>'钻石',
  68. self::LEVEL_BJ=>'白金',
  69. self::LEVEL_JK=>'金卡',
  70. ];
  71. const SCORE_EDITINFO=1;
  72. const SCORE_VIEWVIDEO=2;
  73. const SCORE_WENDA=3;
  74. const SCORE_COMMENTVIDEO=4;
  75. const SCORE_SIGN=5;
  76. const SCORE_GOODS=6;
  77. public static $scoreTypes=[
  78. self::SCORE_EDITINFO=>'完善资料',
  79. self::SCORE_VIEWVIDEO=>'看视频',
  80. self::SCORE_WENDA=>'答题',
  81. self::SCORE_COMMENTVIDEO=>'评论',
  82. self::SCORE_SIGN=>'签到',
  83. self::SCORE_GOODS=>'兑换商品',
  84. ];
  85. /**
  86. * 获取个人URL
  87. * @param string $value
  88. * @param array $data
  89. * @return string
  90. */
  91. public function getUrlAttr($value, $data)
  92. {
  93. return fullUrl("/u/" . $data['id']);
  94. }
  95. public function getLevelTextAttr($value, $data)
  96. {
  97. return self::$levels[$data['level']]??'-';
  98. }
  99. /**
  100. * @return string[]
  101. */
  102. public static function getLevels(): array
  103. {
  104. return self::$levels;
  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. public function userinfo(){
  183. return $this->hasOne(UserInfo::class);
  184. }
  185. public function payment(){
  186. return $this->hasMany(Payment::class);
  187. }
  188. public function comments(){
  189. return $this->hasMany(Comment::class);
  190. }
  191. /**
  192. *@return HasMany|Favourite
  193. */
  194. public function favourite(){
  195. return $this->hasMany(Favourite::class)->where('fav_type','goods');
  196. }
  197. public function feedback(){
  198. return $this->hasMany(Feedback::class);
  199. }
  200. public function moneylog(){
  201. return $this->hasMany(MoneyLog::class);
  202. }
  203. public function tax(){
  204. return $this->hasMany(UserTax::class);
  205. }
  206. /**
  207. * @return Orders|HasMany
  208. */
  209. public function orders(){
  210. return $this->hasMany(Orders::class);
  211. }
  212. /**
  213. * @return Refund|HasMany
  214. */
  215. public function refund(){
  216. return $this->hasMany(Refund::class);
  217. }
  218. public function programmes(){
  219. return $this->hasMany(Programme::class);
  220. }
  221. /**
  222. * @return OrderInfo|HasMany
  223. */
  224. public function orderInfo(){
  225. return $this->hasMany(OrderInfo::class);
  226. }
  227. /**
  228. *@return ScoreLog|HasMany
  229. */
  230. public function scorelog(){
  231. return $this->hasMany(ScoreLog::class);
  232. }
  233. public function cart(){
  234. return $this->hasMany(GoodsCart::class);
  235. }
  236. /**
  237. * @return UserCoupon
  238. */
  239. public function coupon(){
  240. return $this->hasMany(UserCoupon::class);
  241. }
  242. public function categoryView(){
  243. return $this->hasMany(UserCategoryView::class);
  244. }
  245. public function loginRange(){
  246. return $this->hasMany(UserLoginRange::class);
  247. }
  248. public static function recharge($params,Payment $payment){
  249. self::money($payment['amount'],$payment['uer_id'],MoneyLog::TYPE_CHARGE,'充值');
  250. }
  251. public function verification(){
  252. return $this->hasOne(UserVerification::class);
  253. }
  254. /**
  255. * 计算等级折扣金额
  256. */
  257. public function getLevelDiscount($amount){
  258. $radio=DiscountService::getById($this->level);
  259. if($radio>10){
  260. $radio=10;
  261. }
  262. if($radio<=0){
  263. $radio=10;
  264. }
  265. $sub=10-$radio;
  266. return bcmul($amount,$sub/10);
  267. }
  268. /** scope and expired */
  269. protected static function init()
  270. {
  271. self::beforeWrite(function (self $user){
  272. $data=$user->getChangedData();
  273. if(empty($user['level_expire'])){
  274. $user['level_expire']=null;
  275. }
  276. if(empty($user['jointime'])){
  277. $user['jointime']=time();
  278. }
  279. if(empty($user['email'])){
  280. $user['email']=null;
  281. }
  282. if(empty($user['openid'])){
  283. $user['openid']=null;
  284. }
  285. if(empty($user['admin_id'])){
  286. $user['admin_id']=null;
  287. }
  288. });
  289. self::afterDelete(function (self $user){
  290. });
  291. self::afterInsert(function (self $user){
  292. $user->userinfo()->save([]);
  293. });
  294. }
  295. public function scopeExpired(Query $query){
  296. $query
  297. ->whereBetween('level_close_at',[0,time()])
  298. ->where('level','>',0);
  299. }
  300. public function scopeType(Query $query,$type){
  301. $query->where('type',$type);
  302. }
  303. public function scopeUser(Query $query,$level){
  304. $query->where($this->getTable().'.level',$level);
  305. }
  306. /** attr */
  307. #获取地区
  308. public function appendArea(){
  309. $this->city_name=Area::where('id',$this->county_id?:0)->cache(true)->value('mergename','');
  310. }
  311. public function province(){
  312. return $this->belongsTo(Area::class,'province_id')->cache(true);
  313. }
  314. public function admin(){
  315. return $this->belongsTo(Admin::class);
  316. }
  317. public function city(){
  318. return $this->belongsTo(Area::class,'city_id')->cache(true);
  319. }
  320. public function county(){
  321. return $this->belongsTo(Area::class,'county_id')->cache(true);
  322. }
  323. protected function getAvatarAttr($a){
  324. if(!$a){
  325. return request()->domain().'/assets/img/avatar.png';
  326. }
  327. return $a;
  328. }
  329. }