Mobile.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. <?php
  2. namespace app\common\model;
  3. use app\admin\model\Admin;
  4. use app\admin\model\Network;
  5. use app\common\service\MobileComputer;
  6. use app\common\service\MobilePriceLogService;
  7. use app\service\EsMobileService;
  8. use think\Cache;
  9. use think\Db;
  10. use think\db\Query;
  11. use think\helper\Str;
  12. use think\Model;
  13. use traits\model\SoftDelete;
  14. use app\admin\model\MobileFlowAreaTemplate;
  15. /**
  16. * 配置模型
  17. */
  18. class Mobile extends Model
  19. {
  20. const S_DOWN=2;
  21. public static $status=[
  22. 0=>'正常',
  23. 1=>'已售',
  24. self::S_DOWN=>'已下架',
  25. 3=>'禁止下单',
  26. ];
  27. public static $flowStatus=[
  28. '0'=>'售卖中',
  29. //'1'=>'仓库中',
  30. '2'=>'已下架',
  31. ];
  32. protected $append=[
  33. 'saled',
  34. 'is_private',
  35. ];
  36. protected $readonly=['no'];
  37. protected $autoWriteTimestamp='int';
  38. protected $hidden=[];
  39. public function info(){
  40. return $this->hasOne(MobileInfo::class);
  41. }
  42. public function orders(){
  43. return $this->hasMany(MobileOrder::class);
  44. }
  45. public function proxy(){
  46. return $this->belongsTo(Admin::class,'proxy_id');
  47. }
  48. public function holdLog(){
  49. return $this->hasMany(MobileHoldLog::class);
  50. }
  51. public function sub(){
  52. return $this->hasMany(MobileSub::class);
  53. }
  54. public function priceLog(){
  55. return $this->hasMany(MobilePriceLog::class);
  56. }
  57. const BEAUTI=1;
  58. const FLOW=2;
  59. const API=3;
  60. public static $noTypes=[
  61. self::BEAUTI=>'靓号',
  62. self::FLOW=>'流量卡',
  63. self::API=>'api号码',
  64. ];
  65. public static function isTypeNo($type){
  66. return in_array($type,[self::BEAUTI,self::API]);
  67. }
  68. public static function isType($type){
  69. return in_array($type,array_keys(self::$noTypes));
  70. }
  71. public function getSaledAttr($a,$b){
  72. $s=$b['status']??0;
  73. return $s===1?1:0;
  74. }
  75. #是否是民营
  76. public function getIsPrivateAttr($_,$data){
  77. $network=$data['network']?:'';
  78. return mb_strpos($network,'中国')===false;
  79. }
  80. public function getLogoAttr($logo,$data=[]){
  81. if($logo){
  82. $arr=explode(',',$logo);
  83. return array_shift($arr);
  84. }
  85. return null;
  86. }
  87. public function makeAmount(){
  88. $mobile=$this;
  89. if(empty($mobile['amount_base'])){
  90. $mobile['amount_base']=0;
  91. }
  92. if(empty($mobile['amount_charge'])){
  93. $mobile['amount_charge']=0;
  94. }
  95. if(!isset($mobile['is_activity'])){
  96. $mobile['is_activity']=0;
  97. }
  98. if(!$mobile['is_activity']) {
  99. $mobile['amount'] = $mobile['amount_base'] + $mobile['amount_charge'];
  100. }else{
  101. $mobile['amount'] = $mobile['amount_kill'] + $mobile['amount_charge'];
  102. $mobile['activity_time']=time();
  103. }
  104. }
  105. public function makeArea(){
  106. $mobile=$this;
  107. if(empty($mobile['city_id'])){
  108. $mobile['city_id']=Area::getIdByName($mobile['city']??'',2);
  109. }
  110. if(empty($mobile['province_id'])){
  111. if(!empty($mobile['province'])) {
  112. $mobile['province_id'] = Area::getIdByName($mobile['province'],1);
  113. }
  114. if(!empty($mobile['city_id'])){
  115. $mobile['province_id'] = Area::where('id',$mobile['city_id'])->value('pid');
  116. }
  117. }
  118. if(!empty($mobile['province_id'])){
  119. $mobile['province']=Area::where('id',$mobile['province_id'])->cache(true)->value('shortname');
  120. }
  121. if(!empty($mobile['city_id'])){
  122. $mobile['city']=Area::where('id',$mobile['city_id'])->cache(true)->value('shortname');
  123. }
  124. }
  125. public function makePriceLog(){
  126. (new MobilePriceLogService)
  127. ->setMobile($this)
  128. ->setBeforePrice($this->origin['amount'])
  129. ->setAfterPrice($this['amount'])
  130. ->log();
  131. }
  132. public function makeRules(){
  133. $mobile=$this;
  134. if($this['type']==self::BEAUTI) {
  135. foreach (MobileComputer::setMobile($mobile['no'])->filter() as $key => $value) {
  136. $mobile[$key] = $value;
  137. }
  138. }
  139. }
  140. public function amountChangeColumn(){
  141. return [
  142. 'amount_base',
  143. 'amount_charge',
  144. 'amount_kill',
  145. 'is_activity',
  146. ];
  147. }
  148. public static function init()
  149. {
  150. self::beforeWrite(function (self $mobile){
  151. if(isset($mobile['amount_di']) && isset($mobile['amount_base']) && $mobile['amount_di']>$mobile['amount_base']){
  152. throw_user('底价不能大于售价');
  153. }
  154. });
  155. self::beforeUpdate(function (self $mobile){
  156. $data=$mobile->getChangedData();
  157. if(isset($data['is_activity'])){
  158. if($data['is_activity']==1) {
  159. $mobile['activity_time'] = time();
  160. }else{
  161. $mobile->makeNotActivity(false);
  162. }
  163. }
  164. if(isset($data['no'])){
  165. $mobile->makeRules();
  166. }
  167. if(array_intersect(array_keys($data),$mobile->amountChangeColumn())){
  168. $mobile->makeAmount();
  169. }
  170. $mobile->makeArea();
  171. $mobile->makePriceLog();
  172. $mobile->makeNetwork(true);
  173. if(isset($data['sort']) && $data['sort']!=$mobile->origin['sort']){
  174. $mobile->makeSort();
  175. }
  176. $mobile->makeSortLine();
  177. if($mobile['is_activity'] && $mobile['amount_di']>$mobile['amount_kill']){
  178. if(request()->module()=='api'){
  179. throw_user('该号码已是最低优惠');
  180. }else{
  181. throw_user('底价不能大于秒杀价');
  182. }
  183. }
  184. });
  185. self::beforeInsert(function (self $mobile){
  186. $mobile['sort']=self::max('sort')+1;
  187. $mobile->makeAmount();
  188. $mobile->makeRules();
  189. $mobile->makeArea();
  190. $mobile->makeNetwork();
  191. $mobile['sort_line']=$mobile['sort'];
  192. });
  193. self::afterInsert(function (self $mobile){
  194. if($mobile['type']==self::BEAUTI) {
  195. MobileId::insert(['id' => $mobile['id']]);
  196. }
  197. #api号码增加api
  198. MobileApi::create([
  199. 'mobile_id'=>$mobile['id'],
  200. ]);
  201. });
  202. self::afterDelete(function (self $mobile){
  203. $mobile->makeDelete();
  204. });
  205. self::afterUpdate(function (self $mobile){
  206. if(in_array($mobile['type'],[self::BEAUTI,self::API])) {
  207. EsMobileService::addMobile($mobile);
  208. }
  209. });
  210. }
  211. public function makeNewSort($type){
  212. }
  213. public function makeSortLine(){
  214. if($this['top_time']){
  215. $this['sort_line'] = -100*(10-$this['top_time']);
  216. }
  217. elseif($this['rec_time']){
  218. $this['sort_line'] = -10*(10-$this['rec_time']);
  219. }
  220. if($this['is_activity']){
  221. $this['sort_line']=-$this['activity_time'];
  222. }
  223. if(!$this['rec_time'] && !$this['top_time'] && !$this['is_activity']){
  224. $this['sort_line']=$this['sort'];
  225. }
  226. }
  227. public function makeNetwork($upd=false){
  228. $no=$this['no']??'';
  229. if(!$upd){
  230. $needMake=true;
  231. }else{
  232. $changed=$this->getChangedData();
  233. $needMake=isset($changed['no']);
  234. }
  235. if($needMake) {
  236. $this['network'] = Network::getNetWorkString($no);
  237. }
  238. }
  239. public function makeDelete(){
  240. $this->info()->delete();
  241. $this->sub()->delete();
  242. $this->priceLog()->delete();
  243. $this->holdLog()->delete();
  244. EsMobileService::delMobile($this);
  245. MobileId::destroy($this['id']);
  246. MobileUserHistory::where('mobile_id',$this['id'])->delete();
  247. }
  248. protected function initialize()
  249. {
  250. parent::initialize(); // TODO: Change the autogenerated stub
  251. static $columns=null;
  252. if(is_null($columns)){
  253. $columnsArr=self::getTableInfo('','fields');
  254. $columns=collection($columnsArr)->filter(function ($column){
  255. return Str::startsWith($column,'filter_');
  256. });
  257. }
  258. $this->hidden=$columns?:[];
  259. }
  260. public static function show($param=[]){
  261. $model=new self();
  262. $model->with(['info']);
  263. if(isset($param['type'])) {
  264. if($param['type']==1) {
  265. $model->whereIn('status', self::beautiFrontShowStatus());
  266. }else{
  267. $model->where('status',0);
  268. }
  269. }
  270. return $model->getQuery();
  271. }
  272. public static function beautiFrontShowStatus(){
  273. return [0,3];
  274. }
  275. public static function hiddenColumn(){
  276. $columnsArr=self::getTableInfo('','fields');
  277. $columns=collection($columnsArr)->filter(function ($column){
  278. return Str::startsWith($column,'filter_');
  279. });
  280. //$columns[]='sort';
  281. //$columns[]='sort_line';
  282. $columns[]='sub_admin_id';
  283. $columns[]='sub_rec_time';
  284. $columns[]='sub_sort';
  285. //$columns[]='sub_sort_line';
  286. $columns[]='sub_top_time';
  287. $columns[]='update_time';
  288. $columns[]='create_time';
  289. $columns[]='mobile_id';
  290. $columns[]='hold_chan';
  291. $columns[]='hold_user';
  292. $columns[]='admin_id';
  293. $columns[]='mobile_sub_id';
  294. $columns[]='remark';
  295. $columns[]='remark_me';
  296. //$columns[]='rec_time';
  297. $columns[]='proxy_id';
  298. $columns[]='batch_no';
  299. $columns[]='mobile_sub_id';
  300. //$columns[]='top_time';
  301. $columns[]='amount_di';
  302. return $columns->toArray();
  303. }
  304. public function makeHidden(){
  305. foreach ($this->toArray() as $key=>$_){
  306. if(Str::startsWith($key,'filter_')){
  307. $this->hidden([$key]);
  308. }
  309. }
  310. }
  311. /**
  312. *@param self $mobile
  313. */
  314. public static function whenOrderPayed($mobile){
  315. if($mobile){
  316. if(self::isTypeNo($mobile['type'])) {
  317. $mobile['status'] = 1;
  318. $mobile->makeNotActivity();
  319. $mobile->save();
  320. }else{
  321. $mobile['stock_num']=$mobile['stock_num']-1;
  322. if($mobile['stock_num']) {
  323. $mobile->save();
  324. }
  325. }
  326. }
  327. }
  328. public function shouldBuy(){
  329. if($this['type']==self::BEAUTI){
  330. if($this['status']!=0){
  331. throw_user('该号码已售或不存在');
  332. }
  333. }elseif ($this['type']==2){
  334. if($this['status']!=0){
  335. throw_user('该流量卡暂时无法购买');
  336. }
  337. if($this['stock_num']==0){
  338. throw_user('库存不足');
  339. }
  340. }
  341. }
  342. public function viewCountCacheName(){
  343. return __CLASS__."view_count_{$this['id']}_".date('ymdh');
  344. }
  345. public function getViewCountAttr(){
  346. return Cache::get($this->viewCountCacheName(),0);
  347. }
  348. public function getActivityTimeEndAttr($a){
  349. if(!$a){
  350. $a=3;
  351. }
  352. return time()+$a*60;
  353. }
  354. public function setIsActivityAttr($a){
  355. return intval($a);
  356. }
  357. public function addViewCount(){
  358. $num=Cache::get($this->viewCountCacheName(),0);
  359. Cache::set($this->viewCountCacheName(),++$num);
  360. }
  361. public function needCheckSmsCode(){
  362. return in_array($this['type'],[self::BEAUTI, self::FLOW]);
  363. }
  364. #禁止下单
  365. public static function cantOrderStatus(){
  366. return 3;
  367. }
  368. #导入状态
  369. public static function importStatus($s){
  370. $s=preg_replace('/[\s| ]+/','',$s);
  371. switch ($s){
  372. case '正常':
  373. return 0;
  374. case '禁止下单':
  375. return 3;
  376. case '下架':
  377. return 2;
  378. case '已售':
  379. return 1;
  380. }
  381. return 2;
  382. }
  383. #流量卡状态
  384. public static function flowStatus(){
  385. return self::$flowStatus;
  386. }
  387. #流量卡下架
  388. public function flowMakeDown(){
  389. $this['status']=2;
  390. $this->save();
  391. }
  392. public function flowMakeUp(){
  393. $this['status']=0;
  394. $this->save();
  395. }
  396. public function flowMakeDownProxy(){
  397. $this['proxy_status']=2;
  398. $this->save();
  399. }
  400. public function flowMakeUpProxy(){
  401. $this['proxy_status']=0;
  402. $this->save();
  403. }
  404. #设置为非活动
  405. public function makeNotActivity($save=true){
  406. $this['is_activity'] = 0;
  407. $this['activity_time'] = 0;
  408. $this['hold_chan']=0;
  409. $this['hold_user']=0;
  410. if($save) {
  411. $this->save();
  412. }
  413. }
  414. #设置活动
  415. public function makeActivity($amountKill,$chanId){
  416. $this['is_activity'] = 1;
  417. $this['activity_time'] = time();
  418. $this['hold_chan']=$chanId;
  419. $this['hold_user']=$chanId;
  420. $this['amount_kill']=$amountKill;
  421. $this->save();
  422. }
  423. #已售
  424. public function scopeFilterSaled(Query $query){
  425. $query->where('status',1);
  426. }
  427. #靓号
  428. public static function beauti($type=self::BEAUTI){
  429. return self::where('type',$type);
  430. }
  431. public function makeSort()
  432. {
  433. $sort = $this['sort'];
  434. $has = self::beauti($this['type'])->where('id', '<>', $this['id'])->where('sort', $sort)->find();
  435. if ($has) {
  436. self::beauti($this['type'])->where('sort', '>=', $sort)->setInc('sort');
  437. self::beauti($this['type'])->where('is_activity', 0)->where('top_time', 0)->where('rec_time', 0)->update([
  438. 'sort_line' => Db::raw('sort')
  439. ]);
  440. }
  441. }
  442. public function getAmountBaseAttr($amount){
  443. return str_replace('.00','',$amount);
  444. }
  445. public function getAmountAttr($amount){
  446. return str_replace('.00','',$amount);
  447. }
  448. public function getCopyWordAttr($_,$model){
  449. if($model['type']!=self::BEAUTI){
  450. return '';
  451. }
  452. $config=config('site.copy_words')?:[];
  453. $middle=array_filter(array_keys($config)?:['优惠']);
  454. shuffle($middle);
  455. $tail=array_filter(array_values($config)?:[]);
  456. shuffle($tail);
  457. $middleOne=$middle[0]??'';
  458. $tailOne=$tail[0]??'';
  459. return sprintf('%s %s %s %s %s %s',$model['province'],$model['city'],substr($model['no'],3,4),$middleOne,substr($model['no'],7,4),$tailOne);
  460. }
  461. public function getAmountKillAttr($amount){
  462. return str_replace('.00','',$amount);
  463. }
  464. public function getAmountDiAttr($amount){
  465. return str_replace('.00','',$amount);
  466. }
  467. public function getAmountOriginalAttr($amount){
  468. return str_replace('.00','',$amount);
  469. }
  470. public function getAmountChargeAttr($amount){
  471. return str_replace('.00','',$amount);
  472. }
  473. public function getAmountExistsAttr($amount){
  474. return str_replace('.00','',$amount);
  475. }
  476. public static function deleteOtherTableInfo(){
  477. MobileInfo::whereNotExists('select * from mobile where mobile_info.mobile_id=mobile.id')->delete();
  478. MobilePriceLog::whereNotExists('select * from mobile where mobile_price_log.mobile_id=mobile.id')->delete();
  479. MobileSub::whereNotExists('select * from mobile where mobile_sub.mobile_id=mobile.id')->delete();
  480. MobileUserHistory::whereNotExists('select * from mobile where mobile_user_history.mobile_id=mobile.id')->delete();
  481. MobileApi::deleteNotExists();
  482. }
  483. public function again_sell(){
  484. if($this['status']==0){
  485. throw_user('当前已是上架状态');
  486. }
  487. $this['status']=0;
  488. $this->save();
  489. }
  490. public static function beautiStatus(){
  491. return self::$status;
  492. }
  493. /**
  494. * 只发货
  495. */
  496. public function sendTemplate(){
  497. return $this->belongsTo(MobileFlowAreaTemplate::class, 'send_template', 'id');
  498. }
  499. /**
  500. * 不发货
  501. */
  502. public function notSendTemplate(){
  503. return $this->belongsTo(MobileFlowAreaTemplate::class, 'not_send_template', 'id');
  504. }
  505. /**
  506. * 只发货
  507. * dataDistrict 选择的城市
  508. */
  509. public static function sendTemplateLimit(Mobile $mobile, $dataDistrict = 0){
  510. if(!$dataDistrict) return false;
  511. $district = $mobile->sendTemplate->area()->where('district', $dataDistrict)->count();
  512. if(!$district){
  513. $tmp = Area::getTreeId($dataDistrict);
  514. $city = $mobile->sendTemplate->area()->where('city', $tmp[1])->where('district', 0)->count();
  515. if(!$city){
  516. $province = $mobile->sendTemplate->area()->where('province', $tmp[0])->where('city', 0)->where('district', 0)->count();
  517. if(!$province){
  518. return false;
  519. }
  520. }
  521. }
  522. return true;
  523. }
  524. /**
  525. * 不发货
  526. * dataDistrict 选择的城市
  527. */
  528. public static function notSendTemplateLimit(Mobile $mobile, $dataDistrict = 0){
  529. if(!$dataDistrict) return true;
  530. $district = $mobile->notSendTemplate->area()->where('district', $dataDistrict)->count();
  531. if(!$district){
  532. $tmp = Area::getTreeId($dataDistrict);
  533. $city = $mobile->notSendTemplate->area()->where('city', $tmp[1])->where('district', 0)->count();
  534. if(!$city){
  535. $province = $mobile->notSendTemplate->area()->where('province', $tmp[0])->where('city', 0)->where('district', 0)->count();
  536. if(!$province){
  537. return false;
  538. }
  539. }
  540. }
  541. return true;
  542. }
  543. public function fill($data){
  544. foreach ($data as $name=>$val){
  545. $this[$name]=$val;
  546. }
  547. }
  548. }