MobileController.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. <?php
  2. namespace app\api\controller;
  3. use addons\epay\library\Service;
  4. use app\common\controller\UserApi;
  5. use app\common\library\MobileConstant;
  6. use app\common\model\Area;
  7. use app\common\model\Mobile;
  8. use app\common\model\MobileInfo;
  9. use app\common\model\MobileOrder;
  10. use app\common\model\MobileOrderNo;
  11. use app\common\model\Payment;
  12. use app\common\model\SysConfig;
  13. use app\common\service\Jdpay;
  14. use app\common\service\SmsSend;
  15. use think\App;
  16. use think\Db;
  17. use think\db\Query;
  18. /**
  19. * 靓号管理
  20. */
  21. class MobileController extends UserApi
  22. {
  23. protected $noNeedLogin = "*";
  24. protected $noNeedRight = '*';
  25. /**
  26. * 列表
  27. * @ApiMethod (POST)
  28. * @ApiParams (name="type",description="1靓号,2流量卡,默认1")
  29. * @ApiParams (name="search_type",description="fuzzy模糊,precise精准")
  30. * @ApiParams (name="search_last",description="0,1是否搜索尾部")
  31. * @ApiParams (name="city_id",description="地区id")
  32. * @ApiParams (name="keyword",description="搜索内容,模糊就是字符串,精准就是数组")
  33. * @ApiParams (name="sort",description="price_asc价格从低到高,price_desc价格从高到低")
  34. * @ApiParams (name="network",description="网络")
  35. * @ApiParams (name="price_min",description="价格最低数字")
  36. * @ApiParams (name="price_max",description="价格最高数字")
  37. * @ApiParams (name="exclude_num",description="排除数字")
  38. * @ApiParams (name="num_max",description="数字较多,传数字")
  39. * @ApiParams (name="rule_position",description="规律位置,middle中间,tail尾部")
  40. * @ApiParams (name="rule_name",description="规律名,AAAA什么的")
  41. * @ApiParams (name="limit",description="limit")
  42. * @ApiParams (name="page",description="page")
  43. * @ApiReturnParams (name=id,description=id)
  44. * @ApiReturnParams (name="type",description="1靓号,2流量卡")
  45. * @ApiReturnParams (name=logo,description=缩略图)
  46. * @ApiReturnParams (name=name,description=号码名称)
  47. * @ApiReturnParams (name=no,description=手机号)
  48. * @ApiReturnParams (name=type,description=1靓号2流量卡)
  49. * @ApiReturnParams (name=network,description=运营商)
  50. * @ApiReturnParams (name=city,description=城市)
  51. * @ApiReturnParams (name=privince,description=省份)
  52. * @ApiReturnParams (name=amount,description=售价)
  53. * @ApiReturnParams (name=amount_original,description=原价)
  54. * @ApiReturnParams (name=amount_exists,description=含话费)
  55. * @ApiReturnParams (name=amount_base,description=售价)
  56. * @ApiReturnParams (name=amount_charge,description=预充)
  57. * @ApiReturnParams (name=summary,description=简介)
  58. * @ApiReturnParams (name=saled,description=是否已出售)
  59. * @ApiReturnParams (name=status,description=0正常1已售2已下架)
  60. * @ApiReturnParams (name=is_activity,description=是否特价号)
  61. * @ApiReturnParams (name=activity_time_end,description=特价过期时间null永不过期)
  62. * @ApiReturnParams (name=view_count,description=正在浏览人数)
  63. * @ApiReturnParams (name="info.free_app",description=免流APP列表)
  64. * @ApiReturnParams (name="info.describe",description="套餐说明|资费详情")
  65. * @ApiReturnParams (name="info.content",description="详细内容|注意事项")
  66. * @ApiReturnParams (name="info.flow_year",description="每年流量(G)")
  67. * @ApiReturnParams (name="info.fee",description="资费")
  68. * @ApiReturnParams (name="info.first_month_free",description="首月是否免月租")
  69. * @ApiReturnParams (name="info.discount_title",description="简要优惠介绍")
  70. * @ApiReturnParams (name="info.flow_free_limit",description="前多少名免单")
  71. */
  72. public function list(){
  73. $model=Mobile::show();
  74. $data=input();
  75. $this->validate($data,[
  76. 'keyword'=>['max:11'],
  77. 'num_max'=>['integer','between:0,9'],
  78. 'rule_position'=>['in:middle,tail'],
  79. ]);
  80. if(empty($data['type'])){
  81. $data['type']=1;
  82. }
  83. $model->where('type',$data['type']);
  84. if(!empty($data['search_type']) && !empty($data['keyword'])){
  85. if($data['search_type']=='fuzzy'){
  86. if(isset($data['search_last']) && $data['search_last']==1){
  87. $no=str_pad($data['keyword'],11,'-',STR_PAD_LEFT);
  88. for ($i=1;$i<=11;$i++){
  89. if(substr($no,$i-1,1)=='-'){
  90. continue;
  91. }
  92. $model->where("filter_no_pos_{$i}",substr($no,$i-1,1));
  93. }
  94. }else {
  95. $model->where('no', 'like', "%{$data['keyword']}%");
  96. }
  97. }elseif ($data['search_type']=='precise'){
  98. foreach ($data['keyword'] as $k=>$v){
  99. $pos=$k+1;
  100. if($pos==1||$v===""||is_null($v))continue;
  101. $model->where("filter_no_pos_{$pos}",$v);
  102. }
  103. }
  104. }
  105. if(!empty($data['city_id'])){
  106. $model->where('city_id',$data['city_id']);
  107. }
  108. if(!empty($data['sort'])){
  109. if($data['sort']=='price_asc'){
  110. $model->order('amount','asc');
  111. }elseif($data['sort']=='price_desc'){
  112. $model->order('amount','desc');
  113. }
  114. }else{
  115. $model->order('activity_time','desc')->order('create_time','desc');
  116. }
  117. if(!empty($data['network'])){
  118. $network=array_column(MobileConstant::getNetwork(),'search','name');
  119. $model->whereIn('network',$network[$data['network']]??[0]);
  120. }
  121. if(!empty($data['price_min']) && is_numeric($data['price_min'])){
  122. $model->where('amount','>=',$data['price_min']);
  123. }
  124. if(!empty($data['price_max']) && is_numeric($data['price_max'])){
  125. $model->where('amount','>=',$data['price_max']);
  126. }
  127. if(!empty($data['exclude_num'])){
  128. $model->whereNotLike('no',"%{$data['exclude_num']}%");
  129. }
  130. if(!empty($data['num_max'])){
  131. $model->where("filter_num_{$data['num_max']}",'>',3);
  132. }
  133. $rules=MobileConstant::getFilters();
  134. if(!empty($data['rule_name'])){
  135. if (!isset($rules[$data['rule_name']])) {
  136. $this->error('规律规则不支持');
  137. }
  138. $rule=$rules[$data['rule_name']];
  139. if(!empty($data['rule_position'])) {
  140. $model->where($rule[$data['rule_position']], 1);
  141. }else{
  142. $model->where(function (Query $query)use ($rule){
  143. $query->where($rule['middle'],1)->whereOr($rule['tail'],1);
  144. });
  145. }
  146. }
  147. $list=$model->paginate(input('limit',15));
  148. $this->success('',$list);
  149. }
  150. /**
  151. * 号码详情
  152. * @ApiParams (name=id,description=号码id)
  153. */
  154. public function show(){
  155. $data=$this->_validate([
  156. 'id'=>['require']
  157. ]);
  158. $mobile=Mobile::where('id','id')->with(['info'])->findOrFail($data['id']);
  159. $mobile->addViewCount();
  160. $mobile->append(['view_count']);
  161. $this->success('',$mobile);
  162. }
  163. /**
  164. * 下单
  165. * @ApiMethod (POST)
  166. * @ApiParams (name=mobile_id,description=手机号ID)
  167. * @ApiParams (name=name,description=姓名)
  168. * @ApiParams (name=phone,description=手机号)
  169. * @ApiParams (name=sms_code,description=验证码)
  170. * @ApiParams (name=id_no,description=身份号码)
  171. * @ApiParams (name=county,description="城市ID,区县id")
  172. * @ApiParams (name=address,description=详细地址)
  173. * @ApiParams (name=remark,description=备注)
  174. * @ApiParams (name=pay_type,description="1微信2支付宝3京东")
  175. * @ApiParams (name=return_url,description="支付完成回调页面链接")
  176. * @ApiReturnParams (name=pay_url,description="支付链接")
  177. *
  178. */
  179. public function apply(){
  180. $data=$this->_validate([
  181. 'mobile_id'=>'require',
  182. 'name'=>'require',
  183. 'phone'=>'require',
  184. 'id_no'=>'require',
  185. 'county'=>'require|integer',
  186. 'address'=>'require',
  187. ]);
  188. Db::startTrans();
  189. $mobile=Mobile::lock(true)->findOrFail($data['mobile_id']);
  190. if($mobile['type']==1){
  191. $this->_validate([
  192. 'pay_type'=>'require|in:1,2,3',
  193. ]);
  194. }
  195. $mobile->shouldBuy();
  196. Area::shouldSend($data['county']);
  197. SmsSend::setMobile($data['phone'])->setCode($data['sms_code'] ?? '')->setEvent('order')->check();
  198. $order = $data;
  199. $order['admin_id'] = $mobile['proxy_id'];
  200. $order['no'] = $mobile['no'];
  201. $order['city'] = implode(',', Area::getTreeId($data['county']));
  202. $order['amount_original'] = $mobile['amount_original'];
  203. $order['amount_hd'] = $mobile['amount'];
  204. $order['amount_charge'] = $mobile['amount_charge'];
  205. $order['amount'] = $mobile['amount'];
  206. $order['amount_di'] = $mobile['amount_di'];
  207. $order['type'] = $mobile['type'];
  208. unset($order['county'], $order['status'], $order['sms_code']);
  209. $mobileOrder = (new MobileOrder);
  210. $mobileOrder->allowField(true)->save($order);
  211. $succ=null;
  212. if($mobile['type']==1) {
  213. $succ = $this->pay($mobileOrder, $data);
  214. }
  215. Db::commit();
  216. $this->success('', $succ);
  217. }
  218. protected function pay(MobileOrder $mobileOrder,$data){
  219. $data['return_url']=sprintf("%s/build/#/pay-success/%d",request()->domain(),$mobileOrder['id']);
  220. $succ=[
  221. 'pay_url'=>'',
  222. 'id'=>$mobileOrder['id'],
  223. ];
  224. $payment=Payment::create([
  225. 'order_no'=>session_create_id(),
  226. 'amount'=>$mobileOrder['amount'],
  227. 'mobile_order_id'=>$mobileOrder['id'],
  228. ]);
  229. $filename=session_create_id(date('Ymd'));
  230. @mkdir(RUNTIME_PATH.'/payment/',0777,true);
  231. if($data['pay_type']==1){
  232. $info=Service::submitOrder($payment['amount'],
  233. $payment['order_no'],'wechat',"购买手机号{$mobileOrder['no']}",
  234. Service::notifyUrl('wechat',$payment['order_no']),$data['return_url']??'','wap');
  235. file_put_contents(RUNTIME_PATH.'/payment/'.$filename,$info->getContent());
  236. $succ['pay_url']=url('/index/index/payment/a/'.$filename,[],true,true);
  237. }elseif ($data['pay_type']==2){
  238. $info=Service::submitOrder($payment['amount'],
  239. $payment['order_no'],'alipay',"购买手机号{$mobileOrder['no']}",
  240. Service::notifyUrl('alipay',$payment['order_no']),$data['return_url']??'','wap');
  241. file_put_contents(RUNTIME_PATH.'/payment/'.$filename,view('alipay',['form'=>$info->getContent()])->getContent());
  242. $succ['pay_url']=url('/index/index/payment/a/'.$filename,[],true,true);
  243. }elseif ($data['pay_type']==3){
  244. $jdpay=App::invokeClass(Jdpay::class);
  245. $payData=$jdpay->order($payment['order_no'],$payment['amount'],"购买手机号{$mobileOrder['no']}");
  246. $succ=array_merge($succ,$payData);
  247. }
  248. return $succ;
  249. }
  250. /**
  251. * 继续支付
  252. * @ApiParams (name=id,description=订单id)
  253. * @ApiParams (name=pay_type,description=支付方式与下单一样)
  254. * @ApiParams (name=return_url,description="支付完成回调页面链接")
  255. */
  256. public function continue_pay(){
  257. $data=$this->_validate([
  258. 'id'=>['require'],
  259. 'pay_type'=>'require|in:1,2,3',
  260. ]);
  261. $mobileOrder=MobileOrder::whereNull('pay_time')->findOrFail($data['id']);
  262. $mobileOrder->continuePay();
  263. $succ=$this->pay($mobileOrder,$data);
  264. $this->success('',$succ);
  265. }
  266. /**
  267. * 订单详情
  268. * @ApiParams (name=id,description=订单id)
  269. * @ApiReturnParams (name=no,description=手机号)
  270. * @ApiReturnParams (name=order_no,description=订单号)
  271. * @ApiReturnParams (name=amount_hd,description=活动价)
  272. * @ApiReturnParams (name=amount_original,description=原价)
  273. * @ApiReturnParams (name=amount_charge,description=预充)
  274. * @ApiReturnParams (name=describe,description=套餐说明)
  275. * @ApiReturnParams (name=proxy.wx_qr,description=客服二维码)
  276. * @ApiReturnParams (name=name,description=收货人)
  277. * @ApiReturnParams (name=phone,description=收货人手机号)
  278. * @ApiReturnParams (name=id_no,description=收货人身份证)
  279. * @ApiReturnParams (name=address,description=收货地址)
  280. * @ApiReturnParams (name=remark,description=备注)
  281. * @ApiReturnParams (name=create_time,description=下单时间)
  282. * @ApiReturnParams (name=amount,description=订单金额)
  283. * @ApiReturnParams (name=trans_name,description=快递名称)
  284. * @ApiReturnParams (name=trans_no,description=快递单号)
  285. * @ApiReturnParams (name=status,description="0=>'待付款',10=>'已付款',15=>'可发货',17=>'有号码未发货',20=>'待开卡',25=>'已完成',30=>'申请退款',50=>'已关闭',60=>'无号码',70=>'换卡',80=>'争议单',90=>'已退款',")
  286. * @ApiReturnParams (name=open_uploaded,description=是否已上传开卡资料)
  287. * @ApiReturnParams (name=open_idcard_face_img,description=身份证正面照)
  288. * @ApiReturnParams (name=open_idcard_back_img,description=身份证反面照)
  289. * @ApiReturnParams (name=open_face_img,description=头像照)
  290. * @ApiReturnParams (name=open_name,description=姓名)
  291. * @ApiReturnParams (name=open_id_no,description=身份证号码)
  292. * @ApiReturnParams (name=open_phone,description=手机号)
  293. * @ApiReturnParams (name=pay_time,description=支付时间)
  294. * @ApiReturnParams (name=expire_time,description=过期时间)
  295. */
  296. public function order_detail(){
  297. $order=MobileOrder::with(['proxy'])->findOrFail(input('id'));
  298. $order['proxy']->hidden(['password']);
  299. $order['describe']=MobileInfo::where('mobile_id',$order['mobile_id'])->value('describe','');
  300. $this->success('',$order);
  301. }
  302. /**
  303. * 订单列表
  304. * @ApiParams (name=page,description=page)
  305. * @ApiParams (name=limit,description=limit)
  306. * @ApiParams (name=phone,description=手机号)
  307. */
  308. public function order_list(){
  309. $data=$this->_validate([
  310. 'phone|参数'=>['require'],
  311. ]);
  312. $order=MobileOrder::with('proxy')->where('phone',$data['phone'])->order('id','desc')->paginate(input('limit',15));
  313. $this->success('',$order);
  314. }
  315. /**
  316. * 筛选配置
  317. *
  318. */
  319. public function config(){
  320. $config=[];
  321. $networks=array_column(MobileConstant::getNetwork(),'name');
  322. $config['network']=$networks;
  323. $config['rule']=[
  324. 'AAA',
  325. 'AAAA',
  326. 'AAAAA',
  327. '6A',
  328. '7A',
  329. '8A',
  330. 'ABC',
  331. 'ABCD',
  332. 'ABCDE',
  333. 'ABCDEF',
  334. 'AAAB',
  335. 'AAAAB',
  336. 'AAAAAB',
  337. ];
  338. $this->success('',$config);
  339. }
  340. /**
  341. * 上传开卡资料
  342. * @ApiParams (name=id,description=订单id)
  343. * @ApiParams (name=idcard_face_img,description=身份证正面照片)
  344. * @ApiParams (name=idcard_back_img,description=身份证反面照片)
  345. * @ApiParams (name=face_img,description=本人照片)
  346. * @ApiParams (name=name,description=本人姓名)
  347. * @ApiParams (name=id_no,description=本人身份证号码)
  348. * @ApiParams (name=phone,description=本人联系电话)
  349. */
  350. public function upload_identity(){
  351. $data=$this->_validate([
  352. 'id'=>['require'],
  353. 'idcard_face_img'=>['require','url'],
  354. 'idcard_back_img'=>['require','url'],
  355. 'face_img'=>['require','url'],
  356. 'name'=>['require','max:10'],
  357. 'id_no'=>['require'],
  358. 'phone'=>['require','integer'],
  359. ]);
  360. $order=MobileOrder::findOrFail($data['id']);
  361. if($order['open_uploaded']){
  362. $this->error('请勿再次上传');
  363. }
  364. $order['open_uploaded']=1;
  365. $order['open_idcard_face_img']=$data['idcard_face_img'];
  366. $order['open_idcard_back_img']=$data['idcard_back_img'];
  367. $order['open_face_img']=$data['face_img'];
  368. $order['open_name']=$data['name'];
  369. $order['open_id_no']=$data['id_no'];
  370. $order['open_phone']=$data['phone'];
  371. if(!$order->save()){
  372. $this->error('保存失败');
  373. }
  374. $this->success('');
  375. }
  376. /**
  377. * 预定号码
  378. * @ApiParams (name=no,description=号码)
  379. * @ApiParams (name=price_min,description=最低承受价格)
  380. * @ApiParams (name=price_max,description=最高承受价格)
  381. * @ApiParams (name=remark,description=备注)
  382. * @ApiParams (name=name,description=姓名)
  383. * @ApiParams (name=phone,description=联系电话)
  384. * @ApiParams (name=county,description=区县ID)
  385. * @ApiParams (name=address,description=详细地址)
  386. */
  387. public function order_no(){
  388. $data=$this->_validate([
  389. 'no'=>['require','integer','length:3,8'],
  390. //'price_min'=>['require','integer','min:0'],
  391. 'price_max'=>['require','integer','min:0'],
  392. 'name'=>['require'],
  393. 'phone'=>['require','integer','length:11'],
  394. 'county'=>['require','integer'],
  395. 'address'=>['require','length:0,250'],
  396. ]);
  397. $no=new MobileOrderNo;
  398. $data['city']=implode(',',Area::getTreeId($data['county']));
  399. $no->allowField(true)->save($data);
  400. $this->success('');
  401. }
  402. /**
  403. * 横幅播报
  404. * @ApiReturnParams (name=ordered_num,description=已订购人数)
  405. * @ApiReturnParams (name=no,description=号码)
  406. * @ApiReturnParams (name=name,description=人名)
  407. */
  408. public function ordered_show(){
  409. $data=[];
  410. $data['ordered_num']=SysConfig::look('mo_ordered_num',0);
  411. $data['ordered_list']=MobileOrder::payed()
  412. ->order('id','desc')->limit(10)
  413. ->field('name,no')
  414. ->select();
  415. foreach ($data['ordered_list'] as $item){
  416. $item['no']=substr($item['no'],0,3).'****'.substr($item['no'],7,4);
  417. $item['name']=mb_substr($item['name'],0,mb_strlen($item['name'])-1).'*';
  418. }
  419. $this->success('',$data);
  420. }
  421. /**
  422. * 退款
  423. * @ApiMethod (POST)
  424. * @ApiParams (name=id,description=订单id)
  425. * @ApiParams (name=reason,description=退款原因)
  426. */
  427. public function refund(){
  428. $data=$this->_validate([
  429. 'id'=>'require',
  430. 'reason'=>'require|max:250',
  431. ]);
  432. Db::startTrans();
  433. $order=MobileOrder::findOrFail($data['id']);
  434. $order->checkAllowRefund();
  435. $order->makeRefund($data['reason']);
  436. Db::commit();
  437. $this->success();
  438. }
  439. }