Mobile.php 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  1. <?php
  2. namespace app\admin\controller;
  3. use app\admin\library\Auth;
  4. use app\admin\model\Admin;
  5. use app\admin\model\MobileExportLog;
  6. use app\common\controller\Backend;
  7. use app\common\library\MobileConstant;
  8. use app\common\model\MobileInfo;
  9. use app\common\model\MobileSub;
  10. use app\common\service\MobileExport;
  11. use app\common\service\MobileImport;
  12. use app\common\service\SubService;
  13. use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
  14. use PhpOffice\PhpSpreadsheet\IOFactory;
  15. use PhpOffice\PhpSpreadsheet\Reader\Csv;
  16. use PhpOffice\PhpSpreadsheet\Reader\Xls;
  17. use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
  18. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  19. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  20. use PhpOffice\PhpSpreadsheet\Style\Border;
  21. use PhpOffice\PhpSpreadsheet\Style\Fill;
  22. use think\App;
  23. use think\Cache;
  24. use think\Config;
  25. use think\Db;
  26. use think\Exception;
  27. use think\exception\PDOException;
  28. use think\Loader;
  29. use think\Url;
  30. use app\admin\model\Mobile as MO;
  31. /**
  32. *
  33. *
  34. * @icon fa fa-mobile
  35. */
  36. class Mobile extends Backend
  37. {
  38. protected $noNeedRight=['mobile_rules','status','constant','exclude_nums'];
  39. /**
  40. * Mobile模型对象
  41. * @var \app\admin\model\Mobile
  42. */
  43. protected $model = null;
  44. protected $relationSearch=true;
  45. public function _initialize()
  46. {
  47. //ini_set('memory_limit',-1);
  48. parent::_initialize();
  49. $this->model = new \app\admin\model\Mobile;
  50. $this->assign('status',\app\common\model\Mobile::$status);
  51. $this->assign('network',MobileConstant::getNetworkString());
  52. $this->assign('network_color',MobileConstant::getNetworkColor());
  53. $this->assign('network_select',MobileConstant::getNetworkSelect());
  54. }
  55. public function import()
  56. {
  57. //MobileImport::import(input('file'),$this->auth->id);
  58. MobileImport::saveFile(input('file'),$this->auth->id);
  59. $this->success('上传成功,请等待导入');
  60. }
  61. public function import_status_disabled(){
  62. //MobileImport::import(input('file'),$this->auth->id,1,\app\common\model\Mobile::cantOrderStatus());
  63. MobileImport::saveFile(input('file'),$this->auth->id,1,\app\common\model\Mobile::cantOrderStatus());
  64. $this->success('上传成功,请等待导入');
  65. }
  66. /**
  67. * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
  68. * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
  69. * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
  70. */
  71. /**
  72. * 查看
  73. */
  74. public function index()
  75. {
  76. //设置过滤方法
  77. $this->request->filter(['strip_tags', 'trim']);
  78. list($where, $sort, $order, $offset, $limit,$page) = $this->buildindexparams();
  79. if($this->request->get('export')==1 && $this->auth->check('mobile/_mobile_export')){
  80. if(MobileExportLog::exists()){
  81. die('有未完成导出,请稍后再试');
  82. }
  83. $export=MobileExportLog::make($this->admin('id'));
  84. ini_set('memory_limit',-1);
  85. ini_set('max_execution_time',0);
  86. $db=Db::name('mobile');
  87. $db->getConnection()->setConfig('resultset_type','array');
  88. $list= $db
  89. ->where($where)
  90. ->where('mobile.type',1)
  91. ->orderRaw($this->getOrder())
  92. ->buildSql();
  93. //dd($list);
  94. $export['sql']=$list;
  95. $export->save();
  96. die('已添加到导出日志,请稍后查看');
  97. //return MobileExport::export($list,$this->admin());
  98. }
  99. if ($this->request->isAjax()) {
  100. //如果发送的来源是Selectpage,则转发到Selectpage
  101. if ($this->request->request('keyField')) {
  102. return $this->selectpage();
  103. }
  104. $deleteMode=input('_delete_condition');
  105. if($deleteMode==='true'){
  106. if(!$this->auth->check('mobile/del_condition')){
  107. $this->error('您无权进行此操作');
  108. }
  109. $num=$this->model
  110. ->alias(null)
  111. ->where($where)
  112. ->where('mobile.type',1)
  113. ->delete();
  114. \app\common\model\Mobile::deleteOtherTableInfo();
  115. $deleteConditionMsg=sprintf("成功删除%d个号码",$num);
  116. }
  117. if(!$this->admin('is_sub')){
  118. $list = $this->model
  119. ->with(['info','proxy'])
  120. ->where($where)
  121. ->where('mobile.type',1)
  122. ->orderRaw($this->getOrder())
  123. ->page($page)
  124. ->limit($limit)
  125. ->select();
  126. //->paginate($limit);
  127. }else{
  128. $list=$this->model
  129. ->with(['info'])
  130. ->join('mobile_sub','mobile_sub.mobile_id=mobile.id and mobile_sub.sub_admin_id='.$this->auth->id,'left')
  131. ->field('mobile.*,mobile_sub.*')
  132. ->where($where)
  133. ->where('mobile.type',1)
  134. ->orderRaw($this->getOrder())
  135. ->page($page)
  136. ->limit($limit)
  137. ->select();
  138. //->paginate($limit);
  139. }
  140. foreach ($list as $row) {
  141. $rules=[];
  142. foreach (MobileConstant::getFilters() as $rule=>$field){
  143. foreach (array_values($field) as $column){
  144. if($row[$column]==1){
  145. $rules[]=$rule;
  146. }
  147. }
  148. }
  149. $row['rules']=array_values(array_unique($rules));
  150. if($this->admin('is_sub')) {
  151. $row['mobile_sub'] = [
  152. 'sub_sort' => (int)$row['sub_sort'],
  153. 'sub_rec_time' => (int)$row['sub_rec_time'],
  154. 'sub_top_time' => (int)$row['sub_top_time'],
  155. ];
  156. }
  157. }
  158. //$result = array("total" => $list->total(), "rows" => $list->items(),'input'=>input(),'delete_condition_msg'=>$deleteConditionMsg??null);
  159. $result = array("total" => 100000000, "rows" => $list,'input'=>input(),'delete_condition_msg'=>$deleteConditionMsg??null,'url'=>$this->request->url().'&export=1');
  160. return json($result);
  161. }
  162. $this->assign('no_type',array_column(MobileConstant::getNoType(),'name','id'));
  163. $this->assign('filters',MobileConstant::getFilters());
  164. return $this->view->fetch();
  165. }
  166. protected function getOrder(){
  167. $filter=json_decode(input('filter'),true);
  168. $default='mobile.id desc';
  169. return $default;
  170. if(!$filter||empty($filter['no'])){
  171. return $default;
  172. }
  173. $value=str_replace('%','',$filter['no']);
  174. if(!$value){
  175. return $default;
  176. }
  177. $lastNum=substr($value,-1);
  178. if(strlen($value)==1){
  179. return "FIELD(`mobile.filter_no_pos_11`,$lastNum) DESC";
  180. }else{
  181. $arr=[];
  182. $numLen=strlen($value);
  183. $idx=1;
  184. for ($i=11;$i>=2;$i--){
  185. if($idx>$numLen){
  186. break;
  187. }
  188. $numPos=$value[$numLen-$idx];
  189. $arr[]="FIELD(mobile.filter_no_pos_{$i},$numPos) DESC";
  190. $idx++;
  191. }
  192. return implode(',',$arr);
  193. }
  194. }
  195. #秒杀
  196. public function mobile_kill()
  197. {
  198. //设置过滤方法
  199. $this->request->filter(['strip_tags', 'trim']);
  200. if ($this->request->isAjax()) {
  201. //如果发送的来源是Selectpage,则转发到Selectpage
  202. if ($this->request->request('keyField')) {
  203. return $this->selectpage();
  204. }
  205. list($where, $sort, $order, $offset, $limit) = $this->buildindexparams();
  206. $map=[];
  207. if($this->admin('is_sub')){
  208. $map['hold_chan']=$this->auth->id;
  209. }
  210. if(!$this->admin('is_sub')){
  211. $list = $this->model
  212. ->with(['info','proxy'])
  213. ->where($where)
  214. ->where($map)
  215. ->where('mobile.type',1)
  216. ->where('mobile.is_activity',1)
  217. ->orderRaw($this->getOrder())
  218. ->paginate($limit);
  219. }else{
  220. $list=$this->model
  221. ->with(['info'])
  222. ->join('mobile_sub','mobile_sub.mobile_id=mobile.id and mobile_sub.sub_admin_id='.$this->auth->id,'left')
  223. ->field('mobile.*,mobile_sub.*')
  224. ->where($where)
  225. ->where($map)
  226. ->where('mobile.type',1)
  227. ->where('mobile.is_activity',1)
  228. ->orderRaw($this->getOrder())
  229. ->paginate($limit);
  230. }
  231. foreach ($list as $row) {
  232. $rules=[];
  233. foreach (MobileConstant::getFilters() as $rule=>$field){
  234. foreach (array_values($field) as $column){
  235. if($row[$column]==1){
  236. $rules[]=$rule;
  237. }
  238. }
  239. }
  240. $row['rules']=array_values(array_unique($rules));
  241. if($this->admin('is_sub')) {
  242. $row['mobile_sub'] = [
  243. 'sub_sort' => (int)$row['sub_sort'],
  244. 'sub_rec_time' => (int)$row['sub_rec_time'],
  245. 'sub_top_time' => (int)$row['sub_top_time'],
  246. ];
  247. }
  248. }
  249. $result = array("total" => $list->total(), "rows" => $list->items());
  250. return json($result);
  251. }
  252. $this->assign('no_type',array_column(MobileConstant::getNoType(),'name','id'));
  253. $this->assign('filters',MobileConstant::getFilters());
  254. return $this->view->fetch();
  255. }
  256. public function constant(){
  257. return json([
  258. 'no_type'=>MobileConstant::getNoType(),
  259. ]);
  260. }
  261. #置顶推荐
  262. public function batch(){
  263. $this->validate($data=input(),[
  264. 'id'=>'require',
  265. 'field'=>['require','in:rec_time,top_time'],
  266. 'status'=>'require',
  267. ]);
  268. $time=$data['status']?time():null;
  269. $this->model->where('id',$data['id'])->update([
  270. $data['field']=>$time
  271. ]);
  272. $this->success('','',[
  273. 'status'=>$time,
  274. ]);
  275. }
  276. #设为特价
  277. public function setdiscount($ids){
  278. if($this->request->isGet()){
  279. return view();
  280. }else{
  281. $this->validate($data=input('row/a'),[
  282. 'activity_time_end'=>['date','requireIf:activity_forever,0'],
  283. 'activity_forever'=>['require','in:0,1'],
  284. ]);
  285. if($data['activity_forever']){
  286. $activity_time_end=null;
  287. }else {
  288. if (strtotime($data['activity_time_end']) <= time()) {
  289. $this->error('请选择将来时间');
  290. }
  291. $activity_time_end=$data['activity_time_end'];
  292. }
  293. $this->model->whereIn('id',$ids)->update([
  294. 'is_activity'=>1,
  295. 'activity_time_end'=>$activity_time_end,
  296. ]);
  297. $this->success();
  298. }
  299. }
  300. #取消设为特价
  301. public function cancelsetdiscount(){
  302. $ids=input('ids/a');
  303. if($ids){
  304. $this->model->whereIn('id',$ids)->update([
  305. 'is_activity'=>0,
  306. 'activity_time_end'=>null,
  307. ]);
  308. }
  309. $this->success('');
  310. }
  311. #
  312. protected function subDisabled(){
  313. if($this->admin('is_manager')){
  314. return false;
  315. }
  316. return true;
  317. }
  318. protected function killDisabled($mobile){
  319. if($this->admin('is_manager')){
  320. return false;
  321. }
  322. if ($mobile['is_activity']) {
  323. return $mobile['hold_chan']!=$this->admin('id');
  324. }else{
  325. //!$this->auth->check('mobile/mobile_sort')
  326. return false;
  327. }
  328. }
  329. protected function canEditActivity(){
  330. }
  331. #预占
  332. public function takeit($ids){
  333. if($this->request->isGet()){
  334. $mobile=$this->model->find($ids);
  335. $this->assign('row',$mobile);
  336. $this->assign('subDisabled',$this->subDisabled());
  337. $this->assign('killDisabled',$this->killDisabled($mobile));
  338. return view();
  339. }else{
  340. Db::startTrans();
  341. $mobile=$this->model->lock(true)->find($ids);
  342. $data=input('row/a');
  343. $editField=[];
  344. if($this->admin('is_manager')){
  345. $editField=['amount_original','amount_di','amount_base','amount_charge','amount_kill','is_activity','activity_time_end'];
  346. }elseif (!$this->killDisabled($mobile)){
  347. $editField=['amount_kill','is_activity','activity_time_end'];
  348. }else{
  349. Db::rollback();
  350. $this->error('无权操作');
  351. }
  352. foreach ($editField as $field){
  353. $mobile[$field]=$data[$field];
  354. }
  355. if($mobile['amount_kill']<$mobile['amount_di']){
  356. Db::rollback();
  357. $this->error('秒杀价不能低于底价');
  358. }
  359. $change=$mobile->getChangedData();
  360. $admin=Admin::get($this->auth->id);
  361. if(isset($change['is_activity']) && $change['is_activity']){
  362. if($admin['sub']){
  363. $mobile['hold_chan']=$this->auth->id;
  364. }
  365. $mobile['hold_user']=$this->auth->id;
  366. }
  367. $mobile->save();
  368. Db::commit();
  369. $this->success();
  370. }
  371. }
  372. public function edit($ids=null){
  373. if($this->request->isGet()){
  374. $mobile=$this->model->find($ids);
  375. $mobile['province']=\app\common\model\Area::where('id',$mobile['province_id'])->value('name');
  376. $mobile['city']=\app\common\model\Area::where('id',$mobile['city_id'])->value('name');
  377. if($this->admin('is_sub')){
  378. $sub=MobileSub::getBy($mobile,$this->admin());
  379. $mobile['rec_time']=$sub['sub_rec_time'];
  380. $mobile['top_time']=$sub['sub_top_time'];
  381. $mobile['sort']=$sub['sub_sort'];
  382. }
  383. $this->assign('row',$mobile);
  384. $this->assign('disabled',$this->subDisabled());
  385. $this->assign('otherSubDisabled',$this->killDisabled($mobile));
  386. return view();
  387. }else{
  388. $data=input('row/a');
  389. Db::startTrans();
  390. //$mobiles=$this->model->whereIn('id',$ids)->select();
  391. $mobile=$this->model->where('id',$ids)->lock(true)->find();
  392. if(!$mobile){
  393. $this->error('号码不存在');
  394. }
  395. $editField=[];
  396. if($this->admin('is_manager')){
  397. $editField=['network','proxy_id','brand','remark','status','amount_original','amount_di','amount_base','amount_charge','amount_kill','is_activity','activity_time_end','sort','top_time','rec_time'];
  398. }elseif (!$this->killDisabled($mobile)){
  399. $editField=['amount_kill','is_activity','activity_time_end'];
  400. }
  401. foreach ($editField as $field){
  402. $mobile[$field]=$data[$field];
  403. }
  404. /*foreach ($mobiles as $mobile){*/
  405. if($mobile['amount_kill']<$mobile['amount_di']){
  406. $this->error('秒杀价不能低于底价');
  407. }
  408. if($this->admin('is_manager')) {
  409. $city = $data['city'] ?? null;
  410. if ($city) {
  411. $ex = explode('/', $city);
  412. list($data['province'], $data['city']) = $ex;
  413. $data['province_id'] = \app\common\model\Area::getIdByName($data['province']);
  414. $data['city_id'] = \app\common\model\Area::getIdByName($data['city']);
  415. }
  416. $describe = $data['describe'] ?? '';
  417. if ($describe) {
  418. $mobile->info()->update(compact('describe'));
  419. }
  420. }else{
  421. $sub=MobileSub::getBy($mobile,$this->admin());
  422. if($this->service()->hasRecPower()){
  423. $sub['sub_rec_time']=$data['rec_time'];
  424. }
  425. if($this->service()->hasTopPower()){
  426. $sub['sub_top_time']=$data['top_time'];
  427. }
  428. if($this->service()->hasSortPower()){
  429. $sub['sub_sort']=$data['sort'];
  430. }
  431. $sub->save();
  432. }
  433. $mobile->save();
  434. //$mobile->makeSortLine($this->admin());
  435. Db::commit();
  436. /*}*/
  437. $this->success();
  438. }
  439. }
  440. public function multi_edit($ids){
  441. if($this->request->isGet()) {
  442. return view();
  443. }else{
  444. $tempData=input('row/a');
  445. $data=[];
  446. $infoData=[];
  447. if(!empty($tempData['brand'])){
  448. $data['brand']=$tempData['brand'];
  449. }
  450. if(!empty($tempData['remark'])){
  451. $data['remark']=$tempData['remark'];
  452. }
  453. if(isset($tempData['top_time'])){
  454. $data['top_time']=$tempData['top_time'];
  455. }
  456. if(isset($tempData['rec_time'])){
  457. $data['rec_time']=$tempData['rec_time'];
  458. }
  459. if(!empty($tempData['describe'])){
  460. $infoData['describe']=$tempData['describe'];
  461. }
  462. if($data) {
  463. $mobiles = $this->model->whereIn('id', $ids)->select();
  464. foreach ($mobiles as $mobile) {
  465. foreach ($data as $key => $value) {
  466. $mobile[$key] = $value;
  467. $mobile->save();
  468. }
  469. }
  470. }
  471. if($infoData){
  472. MobileInfo::whereIn('mobile_id',$ids)->update($infoData);
  473. }
  474. $this->success();
  475. }
  476. }
  477. public function multi_edit_proxy(){
  478. if($this->request->isGet()) {
  479. return view();
  480. }else{
  481. $this->validate(input('row/a'),[
  482. 'proxy_id'=>['require','integer'],
  483. ]);
  484. $this->model->whereIn('id',input('ids'))->update([
  485. 'proxy_id'=>input('row.proxy_id'),
  486. ]);
  487. $this->success();
  488. }
  489. }
  490. public function multi_edit_status(){
  491. if($this->request->isGet()) {
  492. return view();
  493. }else{
  494. $this->validate(input('row/a'),[
  495. 'status'=>['require','integer'],
  496. ]);
  497. $status=input('row.status');
  498. if(!isset(MO::beautiStatus()[$status])){
  499. $this->error('状态有误');
  500. }
  501. $this->model->whereIn('id',input('ids'))->update([
  502. 'status'=>$status,
  503. ]);
  504. $this->success();
  505. }
  506. }
  507. protected function buildindexparams($searchfields = null, $relationSearch = null)
  508. {
  509. $searchfields = is_null($searchfields) ? $this->searchFields : $searchfields;
  510. $relationSearch = is_null($relationSearch) ? $this->relationSearch : $relationSearch;
  511. $search = $this->request->get("search", '');
  512. $filter = $this->request->get("filter", '');
  513. $op = $this->request->get("op", '', 'trim');
  514. $sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id');
  515. $order = $this->request->get("order", "DESC");
  516. $offset = $this->request->get("offset/d", 0);
  517. $limit = $this->request->get("limit/d", 999999);
  518. //新增自动计算页码
  519. $page = $limit ? intval($offset / $limit) + 1 : 1;
  520. if ($this->request->has("page")) {
  521. $page = $this->request->get("page/d", 1);
  522. }
  523. $this->request->get([config('paginate.var_page') => $page]);
  524. $filter = (array)json_decode($filter, true);
  525. $op = (array)json_decode($op, true);
  526. $filter = $filter ? $filter : [];
  527. $where = [];
  528. $alias = [];
  529. $bind = [];
  530. $name = '';
  531. $aliasName = '';
  532. if (!empty($this->model) && $this->relationSearch) {
  533. $name = $this->model->getTable();
  534. $alias[$name] = Loader::parseName(basename(str_replace('\\', '/', get_class($this->model))));
  535. $aliasName = $alias[$name] . '.';
  536. }
  537. $sortArr = explode(',', $sort);
  538. foreach ($sortArr as $index => & $item) {
  539. $item = stripos($item, ".") === false ? $aliasName . trim($item) : $item;
  540. }
  541. unset($item);
  542. $sort = implode(',', $sortArr);
  543. $adminIds = $this->getDataLimitAdminIds();
  544. if (is_array($adminIds)) {
  545. $where[] = [$aliasName . $this->dataLimitField, 'in', $adminIds];
  546. }
  547. if ($search) {
  548. $searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields);
  549. foreach ($searcharr as $k => &$v) {
  550. $v = stripos($v, ".") === false ? $aliasName . $v : $v;
  551. }
  552. unset($v);
  553. $where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"];
  554. }
  555. $index = 0;
  556. foreach ($filter as $k => $v) {
  557. if($k=='rules'){
  558. continue;
  559. }
  560. if (!preg_match('/^[a-zA-Z0-9_\-.]+$/', $k)) {
  561. continue;
  562. }
  563. $sym = isset($op[$k]) ? $op[$k] : '=';
  564. if (stripos($k, ".") === false) {
  565. $k = $aliasName . $k;
  566. }
  567. $v = !is_array($v) ? trim($v) : $v;
  568. $sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym);
  569. //null和空字符串特殊处理
  570. if (!is_array($v)) {
  571. if (in_array(strtoupper($v), ['NULL', 'NOT NULL'])) {
  572. $sym = strtoupper($v);
  573. }
  574. if (in_array($v, ['""', "''"])) {
  575. $v = '';
  576. $sym = '=';
  577. }
  578. }
  579. switch ($sym) {
  580. case '=':
  581. case '<>':
  582. $where[] = [$k, $sym, (string)$v];
  583. break;
  584. case 'LIKE':
  585. case 'NOT LIKE':
  586. case 'LIKE %...%':
  587. case 'NOT LIKE %...%':
  588. $where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
  589. break;
  590. case '>':
  591. case '>=':
  592. case '<':
  593. case '<=':
  594. $where[] = [$k, $sym, intval($v)];
  595. break;
  596. case 'FINDIN':
  597. case 'FINDINSET':
  598. case 'FIND_IN_SET':
  599. $v = is_array($v) ? $v : explode(',', str_replace(' ', ',', $v));
  600. $findArr = array_values($v);
  601. foreach ($findArr as $idx => $item) {
  602. $bindName = "item_" . $index . "_" . $idx;
  603. $bind[$bindName] = $item;
  604. $where[] = "FIND_IN_SET(:{$bindName}, `" . str_replace('.', '`.`', $k) . "`)";
  605. }
  606. break;
  607. case 'IN':
  608. case 'IN(...)':
  609. case 'NOT IN':
  610. case 'NOT IN(...)':
  611. $where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)];
  612. break;
  613. case 'BETWEEN':
  614. case 'NOT BETWEEN':
  615. $arr = array_slice(explode(',', $v), 0, 2);
  616. if (stripos($v, ',') === false || !array_filter($arr)) {
  617. continue 2;
  618. }
  619. //当出现一边为空时改变操作符
  620. if ($arr[0] === '') {
  621. $sym = $sym == 'BETWEEN' ? '<=' : '>';
  622. $arr = $arr[1];
  623. } elseif ($arr[1] === '') {
  624. $sym = $sym == 'BETWEEN' ? '>=' : '<';
  625. $arr = $arr[0];
  626. }
  627. $where[] = [$k, $sym, $arr];
  628. break;
  629. case 'RANGE':
  630. case 'NOT RANGE':
  631. $v = str_replace(' - ', ',', $v);
  632. $arr = array_slice(explode(',', $v), 0, 2);
  633. if (stripos($v, ',') === false || !array_filter($arr)) {
  634. continue 2;
  635. }
  636. //当出现一边为空时改变操作符
  637. if ($arr[0] === '') {
  638. $sym = $sym == 'RANGE' ? '<=' : '>';
  639. $arr = $arr[1];
  640. } elseif ($arr[1] === '') {
  641. $sym = $sym == 'RANGE' ? '>=' : '<';
  642. $arr = $arr[0];
  643. }
  644. $tableArr = explode('.', $k);
  645. if (count($tableArr) > 1 && $tableArr[0] != $name && !in_array($tableArr[0], $alias) && !empty($this->model)) {
  646. //修复关联模型下时间无法搜索的BUG
  647. $relation = Loader::parseName($tableArr[0], 1, false);
  648. $alias[$this->model->$relation()->getTable()] = $tableArr[0];
  649. }
  650. $where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' TIME', $arr];
  651. break;
  652. case 'NULL':
  653. case 'IS NULL':
  654. case 'NOT NULL':
  655. case 'IS NOT NULL':
  656. $where[] = [$k, strtolower(str_replace('IS ', '', $sym))];
  657. break;
  658. default:
  659. break;
  660. }
  661. $index++;
  662. }
  663. if (!empty($this->model)) {
  664. $this->model->alias($alias);
  665. }
  666. if(isset($filter['rules']) && $filter['rules']){
  667. $temp=[];
  668. foreach (MobileConstant::getFilters()[$filter['rules']] as $pos=>$column){
  669. $temp[]=$column;
  670. }
  671. $flip=array_flip($temp);
  672. if(isset($filter['filter_first_last'])){
  673. if($filter['filter_first_last']==1){
  674. $where[] = [$temp[1],1];
  675. }elseif ($filter['filter_first_last']==2){
  676. $where[] = [$temp[0],1];
  677. }
  678. }else {
  679. $where[] = [implode("|", $temp), 1];
  680. }
  681. }
  682. $model = $this->model;
  683. $where = function ($query) use ($where, $alias, $bind, &$model,$filter) {
  684. if (!empty($model)) {
  685. $model->alias($alias);
  686. $model->bind($bind);
  687. }
  688. foreach ($where as $k => $v) {
  689. if (is_array($v)) {
  690. if(in_array($v[0],['mobile_sub.sub_top_time','mobile_sub.sub_rec_time'])){
  691. if($v[2]) {
  692. $query->whereIn($v[0], 1);
  693. }else{
  694. $query->where(function ($query)use ($v){
  695. $query->whereRaw("{$v[0]}=0 or {$v[0]} is null");
  696. });
  697. }
  698. continue;
  699. }elseif ($v[0]=='proxy.nickname'){
  700. $proxy_id=Admin::where('proxy',1)->where('nickname','like',"%{$v[2]}%")->column('id')?:[0];
  701. $query->whereIn('proxy_id',$proxy_id);
  702. continue;
  703. }elseif ($v[0]=='mobile.exclude_nums'){
  704. $arr=explode(',',$v[2]);
  705. foreach ($arr as $num){
  706. if(!is_numeric($num)){
  707. continue;
  708. }
  709. $query->where(sprintf("filter_num_%s",$num),0);
  710. }
  711. continue;
  712. }elseif ($v[0]=='mobile.filter_first_last'){
  713. continue;
  714. }elseif ($v[0]=='mobile.no'){
  715. $noSearch=$filter['no'];
  716. if(isset($filter['filter_first_last'])){
  717. if($filter['filter_first_last']==1) {
  718. $noPad = str_pad($noSearch, 11, 'a',STR_PAD_LEFT);
  719. for ($i = 11; $i >1; $i--) {
  720. if ($noPad[$i-1] !== 'a') {
  721. $query->where("filter_no_pos_{$i}", $noPad[$i-1]);
  722. }
  723. }
  724. }elseif ($filter['filter_first_last']==2){
  725. $query->where('filter_no_pos_11','<>',$noSearch[strlen($noSearch)-1])->whereRaw("LOCATE('{$noSearch}',no)");
  726. }
  727. }else{
  728. //$query->where('no','like',"%{$noSearch}%");
  729. $query->whereRaw("LOCATE('{$noSearch}',no)");
  730. }
  731. continue;
  732. }
  733. call_user_func_array([$query, 'where'], $v);
  734. } else {
  735. $query->where($v);
  736. }
  737. }
  738. };
  739. return [$where, $sort, $order, $offset, $limit, $page, $alias, $bind];
  740. }
  741. public function status(){
  742. return \app\common\model\Mobile::$status;
  743. }
  744. public function add()
  745. {
  746. if($this->request->isPost()) {
  747. $data = input('row/a');
  748. if (!empty($data['city'])) {
  749. $data['city'] = explode('/', $data['city'])[1];
  750. }
  751. Db::startTrans();
  752. $this->validate($data, \app\admin\validate\Mobile::class);
  753. $data['type'] = 1;
  754. $info = [];
  755. if (isset($data['describe'])) {
  756. $info['describe'] = $data['describe'];
  757. unset($data['describe']);
  758. }
  759. $mobile = $this->model::create($data);
  760. $mobile->info()->save($info);
  761. Db::commit();
  762. $this->success();
  763. }else{
  764. return view();
  765. }
  766. }
  767. public function export($ids){
  768. $mobiles=$this->model->whereIn('id',$ids)->select();
  769. $excel = new Spreadsheet();
  770. $excel->getProperties()
  771. ->setCreator("admin")
  772. ->setLastModifiedBy("admin")
  773. ->setTitle("导出号码")
  774. ->setSubject("导出号码");
  775. $excel->getDefaultStyle()->getFont()->setName('Microsoft Yahei');
  776. $excel->getDefaultStyle()->getFont()->setSize(12);
  777. $excel->getDefaultStyle()->applyFromArray(
  778. array(
  779. 'fill' => array(
  780. 'type' => Fill::FILL_SOLID,
  781. 'color' => array('rgb' => '000000')
  782. ),
  783. 'font' => array(
  784. 'color' => array('rgb' => "000000"),
  785. ),
  786. 'alignment' => array(
  787. 'vertical' => Alignment::VERTICAL_CENTER,
  788. 'horizontal' => Alignment::HORIZONTAL_CENTER,
  789. 'indent' => 1
  790. ),
  791. 'borders' => array(
  792. 'allborders' => array('style' => Border::BORDER_THIN),
  793. )
  794. ));
  795. $excel->getActiveSheet()->setCellValue('A1','ID');
  796. $excel->getActiveSheet()->setCellValue('B1','手机号');
  797. $excel->getActiveSheet()->setCellValue('C1','省份');
  798. $excel->getActiveSheet()->setCellValue('D1','归属地');
  799. $excel->getActiveSheet()->setCellValue('E1','运营商');
  800. $excel->getActiveSheet()->setCellValue('F1','供应商');
  801. $excel->getActiveSheet()->setCellValue('G1','卡品牌');
  802. $excel->getActiveSheet()->setCellValue('H1','规律');
  803. $excel->getActiveSheet()->setCellValue('I1','套餐信息');
  804. $excel->getActiveSheet()->setCellValue('J1','原价');
  805. $excel->getActiveSheet()->setCellValue('K1','底价');
  806. $excel->getActiveSheet()->setCellValue('L1','售价');
  807. $excel->getActiveSheet()->setCellValue('M1','秒杀价');
  808. $excel->getActiveSheet()->setCellValue('N1','预存话费');
  809. $excel->getActiveSheet()->setCellValue('O1','备注');
  810. $excel->getActiveSheet()->setCellValue('P1','置顶');
  811. $excel->getActiveSheet()->setCellValue('Q1','推荐');
  812. $excel->getActiveSheet()->setCellValue('R1','号码状态');
  813. $excel->getActiveSheet()->setCellValue('S1','更新时间');
  814. $excel->getActiveSheet()->setCellValue('T1','上架时间');
  815. $excel->getActiveSheet()->setCellValue('U1','排序');
  816. $excel->getActiveSheet()->setCellValue('V1','预占通道');
  817. $excel->getActiveSheet()->setCellValue('W1','预占用户ID');
  818. $excel->getActiveSheet()->setCellValue('X1','上传用户');
  819. $i=2;
  820. foreach ($mobiles as $mobile){
  821. $rules=[];
  822. foreach (MobileConstant::getFilters() as $rule=>$field){
  823. foreach (array_values($field) as $column){
  824. if($mobile[$column]==1){
  825. $rules[]=$rule;
  826. }
  827. }
  828. }
  829. $mobile['rules']=array_values(array_unique($rules));
  830. $status=$mobile['is_activity']?'预占':\app\common\model\Mobile::$status[$mobile['status']];
  831. $excel->getActiveSheet()->setCellValue('A'.$i,$mobile['id']);
  832. $excel->getActiveSheet()->setCellValue('B'.$i,$mobile['no']);
  833. $excel->getActiveSheet()->setCellValue('C'.$i,$mobile['province']);
  834. $excel->getActiveSheet()->setCellValue('D'.$i,$mobile['city']);
  835. $excel->getActiveSheet()->setCellValue('E'.$i,$mobile['network']);
  836. $excel->getActiveSheet()->setCellValue('F'.$i,$mobile['proxy']['nickname']??'');
  837. $excel->getActiveSheet()->setCellValue('G'.$i,$mobile['brand']);
  838. $excel->getActiveSheet()->setCellValue('H'.$i,implode(',',$mobile['rules']));
  839. $excel->getActiveSheet()->setCellValue('I'.$i,$mobile['info']['describe']??'');
  840. $excel->getActiveSheet()->setCellValue('J'.$i,$mobile['amount_original']);
  841. $excel->getActiveSheet()->setCellValue('K'.$i,$mobile['amount_di']);
  842. $excel->getActiveSheet()->setCellValue('L'.$i,$mobile['amount_base']);
  843. $excel->getActiveSheet()->setCellValue('M'.$i,$mobile['amount_kill']);
  844. $excel->getActiveSheet()->setCellValue('N'.$i,$mobile['amount_charge']);
  845. $excel->getActiveSheet()->setCellValue('O'.$i,$mobile['remark']);
  846. $excel->getActiveSheet()->setCellValue('P'.$i,$mobile['top_time']?'是':'否');
  847. $excel->getActiveSheet()->setCellValue('Q'.$i,$mobile['rec_time']?'是':'否');
  848. $excel->getActiveSheet()->setCellValue('R'.$i,$status);
  849. $excel->getActiveSheet()->setCellValue('S'.$i,date('Y-m-d H:i:s',$mobile['update_time']));
  850. $excel->getActiveSheet()->setCellValue('T'.$i,date('Y-m-d H:i:s',$mobile['create_time']));
  851. $excel->getActiveSheet()->setCellValue('U'.$i,$mobile['sort']);
  852. $excel->getActiveSheet()->setCellValue('V'.$i,$mobile['hold_chan']);
  853. $excel->getActiveSheet()->setCellValue('W'.$i,$mobile['hold_user']);
  854. $excel->getActiveSheet()->setCellValue('X'.$i,$mobile['admin_id']);
  855. $i++;
  856. }
  857. $excel->createSheet();
  858. // Redirect output to a client’s web browser (Excel2007)
  859. $title = date("YmdHis");
  860. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  861. header('Content-Disposition: attachment;filename="' . $title . '.xlsx"');
  862. header('Cache-Control: max-age=0');
  863. // If you're serving to IE 9, then the following may be needed
  864. header('Cache-Control: max-age=1');
  865. // If you're serving to IE over SSL, then the following may be needed
  866. header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
  867. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
  868. header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
  869. header('Pragma: public'); // HTTP/1.0
  870. $objWriter = IOFactory::createWriter($excel, 'Xlsx');
  871. $objWriter->save('php://output');
  872. }
  873. public function force_update(){
  874. $this->success();
  875. }
  876. public function batch_set_amount($ids){
  877. if($this->request->isGet()){
  878. return view();
  879. }else{
  880. $data=input('row/a');
  881. $this->validate($data,[
  882. 'amount_base|售价'=>['require','number','gt:0'],
  883. 'amount_di|底价'=>['require','number','egt:0'],
  884. ]);
  885. $mobiles=$this->model->whereIn('id',$ids)->select();
  886. foreach ($mobiles as $mobile){
  887. $mobile['amount_base']=$data['amount_base'];
  888. $mobile['amount_di']=$data['amount_di'];
  889. $mobile->save();
  890. }
  891. $this->success();
  892. }
  893. }
  894. public function set_kill($ids){
  895. if($this->request->isGet()){
  896. return view();
  897. }else{
  898. $data=input('row/a');
  899. $this->validate($data,[
  900. 'amount_kill|秒杀价'=>['require','number','gt:0'],
  901. ]);
  902. $mobiles=$this->model->whereIn('id',$ids)->select();
  903. Db::startTrans();
  904. foreach ($mobiles as $mobile){
  905. $mobile['amount_kill']=$data['amount_kill'];
  906. $mobile['is_activity']=1;
  907. if(!$mobile->save()){
  908. Db::rollback();
  909. $this->error('保存失败');
  910. }
  911. }
  912. Db::commit();
  913. $this->success();
  914. }
  915. }
  916. public function set_online_clear(){
  917. $type = input('type',1);
  918. if($this->request->isGet()) {
  919. $this->assign('type',$type);
  920. return view();
  921. }else{
  922. $data=[];
  923. $act=input('act');
  924. $reserve=input('reserve');
  925. if($type==1){
  926. switch ($act){
  927. case 'check':
  928. $num=$this->model->where('status',0)->group('no')->having('no_cf_count>1')->column('count(no) as no_cf_count');
  929. $data['num']=array_sum($num);
  930. break;
  931. case 'del':
  932. $data['num']=$this->set_online_clear_del($reserve,$type);
  933. break;
  934. }
  935. }elseif ($type==2){
  936. switch ($act){
  937. case 'check':
  938. $num=$this->model->where('status',1)->group('no')->having('no_cf_count>1')->column('count(no) as no_cf_count');
  939. $data['num']=array_sum($num);
  940. break;
  941. case 'del':
  942. $data['num']=$this->set_online_clear_del($reserve,$type);
  943. break;
  944. }
  945. }
  946. $this->result($data,1);
  947. }
  948. }
  949. protected function set_online_clear_del($reserve,$type){
  950. if(in_array($reserve,[1,2])){
  951. return $this->set_online_clear_query($type,'id',$reserve==1);
  952. }elseif(in_array($reserve,[3,4])){
  953. return $this->set_online_clear_query($type,'amount_base',$reserve==3);
  954. }elseif(in_array($reserve,[5,6])){
  955. return $this->set_online_clear_query($type,'amount_di',$reserve==5);
  956. }
  957. }
  958. protected function set_online_clear_query($type,$column,$asc){
  959. $map=[];
  960. if($type==1) {
  961. $map['status'] = ['eq',0];
  962. }elseif($type==2) {
  963. $map['status'] = ['eq',1];
  964. }
  965. $res=$this->model->where($map)->group('no')->having('num>1')->column("count(no) as num,no,group_concat(id) as ids,GROUP_CONCAT($column) as $column",'no');
  966. $ids=[];
  967. $num=0;
  968. foreach ($res as $item){
  969. $tempIds=explode(',',$item['ids']);
  970. $tempAmount=explode(',',$item[$column]);
  971. $tempNew=array_combine($tempIds,$tempAmount);
  972. $asc?asort($tempNew,1):arsort($tempNew,1);
  973. unset($tempNew[array_keys($tempNew)[0]]);
  974. //$ids=array_merge($ids,array_keys($tempNew));
  975. $newIds=array_keys($tempNew);
  976. $num+=count($newIds);
  977. $ids=array_merge($ids,$newIds);
  978. if(count($ids)>8000) {
  979. $this->model->whereIn('id', $ids)->delete();
  980. $ids=[];
  981. }
  982. }
  983. if($ids) {
  984. $this->model->whereIn('id', $ids)->delete();
  985. }
  986. return $num;
  987. }
  988. public function batch_copy_operation(){
  989. if($this->request->isGet()) {
  990. return view();
  991. }else{
  992. $num=0;
  993. $data=input('row/a');
  994. $this->validate($data,[
  995. 'no|手机号'=>['require'],
  996. 'act'=>'require',
  997. ]);
  998. $noFiltered=array_unique(array_filter(explode("\n",$data['no'])));
  999. if($data['act']=='delete'){
  1000. $mobiles=$this->model->whereIn('no',$noFiltered)->select();
  1001. Db::startTrans();
  1002. foreach ($mobiles as $mobile){
  1003. $mobile->delete();
  1004. }
  1005. $num=count($mobiles);
  1006. Db::commit();
  1007. }elseif($data['act']=='up'){
  1008. $num=$this->model->whereIn('no',$noFiltered)->update(['status'=>0]);
  1009. }elseif($data['act']=='down'){
  1010. $num=$this->model->whereIn('no',$noFiltered)->update(['status'=>2]);
  1011. }elseif ($data['act']=='top'){
  1012. if($noFiltered){
  1013. $mobiles=$this->model->where('top_time',0)->whereIn('no',$noFiltered)->select();
  1014. foreach ($mobiles as $mobile){
  1015. $mobile['top_time']=1;
  1016. $mobile->save();
  1017. }
  1018. $num=$mobiles->count();
  1019. }
  1020. }elseif ($data['act']=='rec'){
  1021. if($noFiltered){
  1022. $mobiles=$this->model->where('rec_time',0)->whereIn('no',$noFiltered)->select();
  1023. foreach ($mobiles as $mobile){
  1024. $mobile['rec_time']=1;
  1025. $mobile->save();
  1026. }
  1027. $num=$mobiles->count();
  1028. }
  1029. }
  1030. $this->result(['num'=>$num],1);
  1031. }
  1032. }
  1033. public function mobile_rules(){
  1034. return MobileConstant::getRuleKeys();
  1035. }
  1036. public function activity_cancel($ids){
  1037. $mobile=$this->model->findOrFail($ids);
  1038. if(!$mobile['is_activity']){
  1039. $this->error('该号码没有被预占无法取消');
  1040. }
  1041. if($this->admin('is_proxy')){
  1042. $this->error('您是供应商,无法使用此功能');
  1043. }
  1044. if($this->admin('sub') && $mobile['hold_chan']!=$this->auth->id){
  1045. $this->error('您无法取消');
  1046. }
  1047. $mobile->makeNotActivity();
  1048. $this->success();
  1049. }
  1050. public function batch_activity_cancel($ids){
  1051. $map=[];
  1052. if($this->admin('is_sub')){
  1053. $map['hold_chan']=$this->admin('id');
  1054. }
  1055. $this->model->whereIn('id',$ids)->where($map)->update([
  1056. 'is_activity'=>0,
  1057. 'activity_time'=>0,
  1058. 'hold_chan' =>0,
  1059. 'hold_user' =>0,
  1060. ]);
  1061. $this->success();
  1062. }
  1063. /** 排序 */
  1064. public function mobile_sort($ids){
  1065. $mobile=$this->model->find($ids);
  1066. if(!$mobile){
  1067. return '';
  1068. }
  1069. $row=[
  1070. 'sort'=>0,
  1071. ];
  1072. if($this->request->isGet()){
  1073. if($this->admin('is_sub')){
  1074. $row['sort']=MobileSub::getBy($mobile,$this->admin())['sub_sort'];
  1075. }else{
  1076. $row['sort']=$mobile['sort'];
  1077. }
  1078. $this->assign('row',$row);
  1079. return view();
  1080. }else{
  1081. $data=input('row/a');
  1082. $this->validate($data,[
  1083. 'sort|排序'=>['require','integer','gt:0'],
  1084. ]);
  1085. if($this->admin('is_sub')){
  1086. $mobileSub=MobileSub::getBy($mobile,$this->admin());
  1087. $mobileSub['sub_sort']=$data['sort'];
  1088. $mobileSub->save();
  1089. }else{
  1090. $mobile['sort']=$data['sort'];
  1091. $mobile->save();
  1092. }
  1093. $this->success();
  1094. }
  1095. }
  1096. public function del_all(){
  1097. $data=['num'=>0];
  1098. $data['num']=\app\admin\model\Mobile::where('type',1)->delete();
  1099. \app\common\model\Mobile::deleteOtherTableInfo();
  1100. $this->success('',null,$data);
  1101. }
  1102. public function exclude_nums(){
  1103. return json([
  1104. 'list'=>[
  1105. ['id'=>2,'title'=>'2'],
  1106. ['id'=>3,'title'=>'3'],
  1107. ['id'=>4,'title'=>'4'],
  1108. ['id'=>5,'title'=>'5'],
  1109. ['id'=>6,'title'=>'6'],
  1110. ['id'=>7,'title'=>'7'],
  1111. ['id'=>8,'title'=>'8'],
  1112. ['id'=>9,'title'=>'9'],
  1113. ['id'=>0,'title'=>'0'],
  1114. ],
  1115. 'total'=>10,
  1116. ]);
  1117. }
  1118. }