Mobile.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. <?php
  2. namespace app\admin\controller;
  3. use app\admin\library\Auth;
  4. use app\admin\model\Admin;
  5. use app\common\controller\Backend;
  6. use app\common\library\MobileConstant;
  7. use app\common\model\MobileSub;
  8. use app\common\service\MobileImport;
  9. use app\common\service\MobilePriceLogService;
  10. use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
  11. use PhpOffice\PhpSpreadsheet\IOFactory;
  12. use PhpOffice\PhpSpreadsheet\Reader\Csv;
  13. use PhpOffice\PhpSpreadsheet\Reader\Xls;
  14. use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
  15. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  16. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  17. use PhpOffice\PhpSpreadsheet\Style\Border;
  18. use PhpOffice\PhpSpreadsheet\Style\Fill;
  19. use think\App;
  20. use think\Db;
  21. use think\Exception;
  22. use think\exception\PDOException;
  23. use think\Loader;
  24. use think\Url;
  25. /**
  26. *
  27. *
  28. * @icon fa fa-mobile
  29. */
  30. class Mobile extends Backend
  31. {
  32. protected $noNeedRight=['mobile_rules','status','constant'];
  33. /**
  34. * Mobile模型对象
  35. * @var \app\admin\model\Mobile
  36. */
  37. protected $model = null;
  38. protected $relationSearch=true;
  39. public function _initialize()
  40. {
  41. parent::_initialize();
  42. $this->model = new \app\admin\model\Mobile;
  43. $this->assign('status',\app\common\model\Mobile::$status);
  44. $this->assign('network',MobileConstant::getNetworkString());
  45. $this->assign('network_select',MobileConstant::getNetworkSelect());
  46. }
  47. public function import()
  48. {
  49. MobileImport::import(input('file'),$this->auth->id);
  50. $this->success();
  51. }
  52. /**
  53. * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
  54. * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
  55. * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
  56. */
  57. /**
  58. * 查看
  59. */
  60. public function index()
  61. {
  62. //设置过滤方法
  63. $this->request->filter(['strip_tags', 'trim']);
  64. if ($this->request->isAjax()) {
  65. //如果发送的来源是Selectpage,则转发到Selectpage
  66. if ($this->request->request('keyField')) {
  67. return $this->selectpage();
  68. }
  69. list($where, $sort, $order, $offset, $limit) = $this->buildindexparams();
  70. $list = $this->model
  71. ->with(['info','proxy'])
  72. ->where($where)
  73. ->where('mobile.type',1)
  74. ->orderRaw($this->getOrder())
  75. ->paginate($limit);
  76. foreach ($list as $row) {
  77. $rules=[];
  78. foreach (MobileConstant::getFilters() as $rule=>$field){
  79. foreach (array_values($field) as $column){
  80. if($row[$column]==1){
  81. $rules[]=$rule;
  82. }
  83. }
  84. }
  85. $row['rules']=array_values(array_unique($rules));
  86. }
  87. $result = array("total" => $list->total(), "rows" => $list->items());
  88. return json($result);
  89. }
  90. $this->assign('no_type',array_column(MobileConstant::getNoType(),'name','id'));
  91. $this->assign('filters',MobileConstant::getFilters());
  92. return $this->view->fetch();
  93. }
  94. protected function getOrder(){
  95. $filter=json_decode(input('filter'),true);
  96. $default='mobile.id desc';
  97. if(!$filter||empty($filter['no'])){
  98. return $default;
  99. }
  100. $value=str_replace('%','',$filter['no']);
  101. if(!$value){
  102. return $default;
  103. }
  104. $lastNum=substr($value,-1);
  105. if(strlen($value)==1){
  106. return "FIELD(`mobile.filter_no_pos_11`,$lastNum) DESC";
  107. }else{
  108. $arr=[];
  109. $numLen=strlen($value);
  110. $idx=1;
  111. for ($i=11;$i>=2;$i--){
  112. if($idx>$numLen){
  113. break;
  114. }
  115. $numPos=$value[$numLen-$idx];
  116. $arr[]="FIELD(mobile.filter_no_pos_{$i},$numPos) DESC";
  117. $idx++;
  118. }
  119. return implode(',',$arr);
  120. }
  121. }
  122. #秒杀
  123. public function mobile_kill()
  124. {
  125. //设置过滤方法
  126. $this->request->filter(['strip_tags', 'trim']);
  127. if ($this->request->isAjax()) {
  128. //如果发送的来源是Selectpage,则转发到Selectpage
  129. if ($this->request->request('keyField')) {
  130. return $this->selectpage();
  131. }
  132. list($where, $sort, $order, $offset, $limit) = $this->buildindexparams();
  133. $map=[];
  134. if($this->admin('sub')){
  135. $map['hold_chan']=$this->auth->id;
  136. }
  137. $list = $this->model
  138. ->with(['info','proxy'])
  139. ->where($where)
  140. ->where($map)
  141. ->where('mobile.type',1)
  142. ->where('mobile.is_activity',1)
  143. ->order($sort, $order)
  144. ->paginate($limit);
  145. foreach ($list as $row) {
  146. $rules=[];
  147. foreach (MobileConstant::getFilters() as $rule=>$field){
  148. foreach (array_values($field) as $column){
  149. if($row[$column]==1){
  150. $rules[]=$rule;
  151. }
  152. }
  153. }
  154. $row['rules']=array_values(array_unique($rules));
  155. }
  156. $result = array("total" => $list->total(), "rows" => $list->items());
  157. return json($result);
  158. }
  159. $this->assign('no_type',array_column(MobileConstant::getNoType(),'name','id'));
  160. $this->assign('filters',MobileConstant::getFilters());
  161. return $this->view->fetch();
  162. }
  163. public function constant(){
  164. return json([
  165. 'no_type'=>MobileConstant::getNoType(),
  166. ]);
  167. }
  168. #置顶推荐
  169. public function batch(){
  170. $this->validate($data=input(),[
  171. 'id'=>'require',
  172. 'field'=>['require','in:rec_time,top_time'],
  173. 'status'=>'require',
  174. ]);
  175. $time=$data['status']?time():null;
  176. $this->model->where('id',$data['id'])->update([
  177. $data['field']=>$time
  178. ]);
  179. $this->success('','',[
  180. 'status'=>$time,
  181. ]);
  182. }
  183. #设为特价
  184. public function setdiscount($ids){
  185. if($this->request->isGet()){
  186. return view();
  187. }else{
  188. $this->validate($data=input('row/a'),[
  189. 'activity_time_end'=>['date','requireIf:activity_forever,0'],
  190. 'activity_forever'=>['require','in:0,1'],
  191. ]);
  192. if($data['activity_forever']){
  193. $activity_time_end=null;
  194. }else {
  195. if (strtotime($data['activity_time_end']) <= time()) {
  196. $this->error('请选择将来时间');
  197. }
  198. $activity_time_end=$data['activity_time_end'];
  199. }
  200. $this->model->whereIn('id',$ids)->update([
  201. 'is_activity'=>1,
  202. 'activity_time_end'=>$activity_time_end,
  203. ]);
  204. $this->success();
  205. }
  206. }
  207. #取消设为特价
  208. public function cancelsetdiscount(){
  209. $ids=input('ids/a');
  210. if($ids){
  211. $this->model->whereIn('id',$ids)->update([
  212. 'is_activity'=>0,
  213. 'activity_time_end'=>null,
  214. ]);
  215. }
  216. $this->success('');
  217. }
  218. #预占
  219. public function takeit($ids){
  220. if($this->request->isGet()){
  221. $mobile=$this->model->find($ids);
  222. $this->assign('row',$mobile);
  223. return view();
  224. }else{
  225. Db::startTrans();
  226. $mobile=$this->model->lock(true)->find($ids);
  227. $data=input('row/a');
  228. $data['is_activity']=intval($data['is_activity']);
  229. //(new MobilePriceLogService)->setMobile($mobile)->setAdminId($this->auth->id)->setBeforePrice($mobile['amount_base'])->setAfterPrice($data['amount_base'])->log();
  230. foreach (['amount_original','amount_di','amount_base','amount_charge','amount_kill','is_activity','activity_time_end'] as $field){
  231. $mobile[$field]=$data[$field];
  232. }
  233. if($mobile['amount_kill']<$mobile['amount_di']){
  234. $this->error('秒杀价不能低于底价');
  235. }
  236. $change=$mobile->getChangedData();
  237. $admin=Admin::get($this->auth->id);
  238. if(isset($change['is_activity']) && $change['is_activity']){
  239. if($admin['sub']){
  240. $mobile['hold_chan']=$this->auth->id;
  241. }
  242. $mobile['hold_user']=$this->auth->id;
  243. }
  244. $mobile->allowField(true)->save($data);
  245. Db::commit();
  246. $this->success();
  247. }
  248. }
  249. public function edit($ids=null){
  250. if($this->request->isGet()){
  251. $mobile=$this->model->find($ids);
  252. $mobile['province']=\app\common\model\Area::where('id',$mobile['province_id'])->value('name');
  253. $mobile['city']=\app\common\model\Area::where('id',$mobile['city_id'])->value('name');
  254. $this->assign('row',$mobile);
  255. return view();
  256. }else{
  257. $mobiles=$this->model->whereIn('id',$ids)->select();
  258. foreach ($mobiles as $mobile){
  259. Db::startTrans();
  260. $data=input('row/a');
  261. unset($data['no']);
  262. $city=$data['city']??null;
  263. if($city){
  264. $ex=explode('/',$city);
  265. list($data['province'],$data['city'])=$ex;
  266. $data['province_id']=\app\common\model\Area::getIdByName($data['province']);
  267. $data['city_id']=\app\common\model\Area::getIdByName($data['city']);
  268. }
  269. if(isset($data['amount_base'])) {
  270. //(new MobilePriceLogService)->setMobile($mobile)->setAdminId($this->auth->id)->setBeforePrice($mobile['amount_base'])->setAfterPrice($data['amount_base'])->log();
  271. }
  272. $mobile->allowField(true)->save($data);
  273. $describe=$data['describe']??'';
  274. if($describe) {
  275. $mobile->info()->update(compact('describe'));
  276. }
  277. Db::commit();
  278. }
  279. $this->success();
  280. }
  281. }
  282. public function multi_edit(){
  283. if($this->request->isGet()) {
  284. return view();
  285. }else{
  286. $this->edit(input('ids'));
  287. }
  288. }
  289. public function multi_edit_proxy(){
  290. if($this->request->isGet()) {
  291. return view();
  292. }else{
  293. $this->validate(input('row/a'),[
  294. 'proxy_id'=>['require','integer'],
  295. ]);
  296. $this->model->whereIn('id',input('ids'))->update([
  297. 'proxy_id'=>input('row.proxy_id'),
  298. ]);
  299. $this->success();
  300. }
  301. }
  302. public function multi_edit_status(){
  303. if($this->request->isGet()) {
  304. return view();
  305. }else{
  306. $this->validate(input('row/a'),[
  307. 'status'=>['require','integer'],
  308. ]);
  309. $this->model->whereIn('id',input('ids'))->update([
  310. 'status'=>input('row.status'),
  311. ]);
  312. $this->success();
  313. }
  314. }
  315. protected function buildindexparams($searchfields = null, $relationSearch = null)
  316. {
  317. $searchfields = is_null($searchfields) ? $this->searchFields : $searchfields;
  318. $relationSearch = is_null($relationSearch) ? $this->relationSearch : $relationSearch;
  319. $search = $this->request->get("search", '');
  320. $filter = $this->request->get("filter", '');
  321. $op = $this->request->get("op", '', 'trim');
  322. $sort = $this->request->get("sort", !empty($this->model) && $this->model->getPk() ? $this->model->getPk() : 'id');
  323. $order = $this->request->get("order", "DESC");
  324. $offset = $this->request->get("offset/d", 0);
  325. $limit = $this->request->get("limit/d", 999999);
  326. //新增自动计算页码
  327. $page = $limit ? intval($offset / $limit) + 1 : 1;
  328. if ($this->request->has("page")) {
  329. $page = $this->request->get("page/d", 1);
  330. }
  331. $this->request->get([config('paginate.var_page') => $page]);
  332. $filter = (array)json_decode($filter, true);
  333. $op = (array)json_decode($op, true);
  334. $filter = $filter ? $filter : [];
  335. $where = [];
  336. $alias = [];
  337. $bind = [];
  338. $name = '';
  339. $aliasName = '';
  340. if (!empty($this->model) && $this->relationSearch) {
  341. $name = $this->model->getTable();
  342. $alias[$name] = Loader::parseName(basename(str_replace('\\', '/', get_class($this->model))));
  343. $aliasName = $alias[$name] . '.';
  344. }
  345. $sortArr = explode(',', $sort);
  346. foreach ($sortArr as $index => & $item) {
  347. $item = stripos($item, ".") === false ? $aliasName . trim($item) : $item;
  348. }
  349. unset($item);
  350. $sort = implode(',', $sortArr);
  351. $adminIds = $this->getDataLimitAdminIds();
  352. if (is_array($adminIds)) {
  353. $where[] = [$aliasName . $this->dataLimitField, 'in', $adminIds];
  354. }
  355. if ($search) {
  356. $searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields);
  357. foreach ($searcharr as $k => &$v) {
  358. $v = stripos($v, ".") === false ? $aliasName . $v : $v;
  359. }
  360. unset($v);
  361. $where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"];
  362. }
  363. $index = 0;
  364. foreach ($filter as $k => $v) {
  365. if($k=='rules'){
  366. continue;
  367. }
  368. if (!preg_match('/^[a-zA-Z0-9_\-.]+$/', $k)) {
  369. continue;
  370. }
  371. $sym = isset($op[$k]) ? $op[$k] : '=';
  372. if (stripos($k, ".") === false) {
  373. $k = $aliasName . $k;
  374. }
  375. $v = !is_array($v) ? trim($v) : $v;
  376. $sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym);
  377. //null和空字符串特殊处理
  378. if (!is_array($v)) {
  379. if (in_array(strtoupper($v), ['NULL', 'NOT NULL'])) {
  380. $sym = strtoupper($v);
  381. }
  382. if (in_array($v, ['""', "''"])) {
  383. $v = '';
  384. $sym = '=';
  385. }
  386. }
  387. switch ($sym) {
  388. case '=':
  389. case '<>':
  390. $where[] = [$k, $sym, (string)$v];
  391. break;
  392. case 'LIKE':
  393. case 'NOT LIKE':
  394. case 'LIKE %...%':
  395. case 'NOT LIKE %...%':
  396. $where[] = [$k, trim(str_replace('%...%', '', $sym)), "%{$v}%"];
  397. break;
  398. case '>':
  399. case '>=':
  400. case '<':
  401. case '<=':
  402. $where[] = [$k, $sym, intval($v)];
  403. break;
  404. case 'FINDIN':
  405. case 'FINDINSET':
  406. case 'FIND_IN_SET':
  407. $v = is_array($v) ? $v : explode(',', str_replace(' ', ',', $v));
  408. $findArr = array_values($v);
  409. foreach ($findArr as $idx => $item) {
  410. $bindName = "item_" . $index . "_" . $idx;
  411. $bind[$bindName] = $item;
  412. $where[] = "FIND_IN_SET(:{$bindName}, `" . str_replace('.', '`.`', $k) . "`)";
  413. }
  414. break;
  415. case 'IN':
  416. case 'IN(...)':
  417. case 'NOT IN':
  418. case 'NOT IN(...)':
  419. $where[] = [$k, str_replace('(...)', '', $sym), is_array($v) ? $v : explode(',', $v)];
  420. break;
  421. case 'BETWEEN':
  422. case 'NOT BETWEEN':
  423. $arr = array_slice(explode(',', $v), 0, 2);
  424. if (stripos($v, ',') === false || !array_filter($arr)) {
  425. continue 2;
  426. }
  427. //当出现一边为空时改变操作符
  428. if ($arr[0] === '') {
  429. $sym = $sym == 'BETWEEN' ? '<=' : '>';
  430. $arr = $arr[1];
  431. } elseif ($arr[1] === '') {
  432. $sym = $sym == 'BETWEEN' ? '>=' : '<';
  433. $arr = $arr[0];
  434. }
  435. $where[] = [$k, $sym, $arr];
  436. break;
  437. case 'RANGE':
  438. case 'NOT RANGE':
  439. $v = str_replace(' - ', ',', $v);
  440. $arr = array_slice(explode(',', $v), 0, 2);
  441. if (stripos($v, ',') === false || !array_filter($arr)) {
  442. continue 2;
  443. }
  444. //当出现一边为空时改变操作符
  445. if ($arr[0] === '') {
  446. $sym = $sym == 'RANGE' ? '<=' : '>';
  447. $arr = $arr[1];
  448. } elseif ($arr[1] === '') {
  449. $sym = $sym == 'RANGE' ? '>=' : '<';
  450. $arr = $arr[0];
  451. }
  452. $tableArr = explode('.', $k);
  453. if (count($tableArr) > 1 && $tableArr[0] != $name && !in_array($tableArr[0], $alias) && !empty($this->model)) {
  454. //修复关联模型下时间无法搜索的BUG
  455. $relation = Loader::parseName($tableArr[0], 1, false);
  456. $alias[$this->model->$relation()->getTable()] = $tableArr[0];
  457. }
  458. $where[] = [$k, str_replace('RANGE', 'BETWEEN', $sym) . ' TIME', $arr];
  459. break;
  460. case 'NULL':
  461. case 'IS NULL':
  462. case 'NOT NULL':
  463. case 'IS NOT NULL':
  464. $where[] = [$k, strtolower(str_replace('IS ', '', $sym))];
  465. break;
  466. default:
  467. break;
  468. }
  469. $index++;
  470. }
  471. if (!empty($this->model)) {
  472. $this->model->alias($alias);
  473. }
  474. if(isset($filter['rules']) && $filter['rules']){
  475. $temp=[];
  476. foreach (MobileConstant::getFilters()[$filter['rules']] as $pos=>$column){
  477. $temp[]=$column;
  478. }
  479. $flip=array_reverse($temp);
  480. $where[]=[implode("|",$temp),1];
  481. }
  482. $model = $this->model;
  483. $where = function ($query) use ($where, $alias, $bind, &$model) {
  484. if (!empty($model)) {
  485. $model->alias($alias);
  486. $model->bind($bind);
  487. }
  488. foreach ($where as $k => $v) {
  489. if (is_array($v)) {
  490. call_user_func_array([$query, 'where'], $v);
  491. } else {
  492. $query->where($v);
  493. }
  494. }
  495. };
  496. return [$where, $sort, $order, $offset, $limit, $page, $alias, $bind];
  497. }
  498. public function status(){
  499. return \app\common\model\Mobile::$status;
  500. }
  501. public function add()
  502. {
  503. if($this->request->isPost()) {
  504. $data = input('row/a');
  505. if (!empty($data['city'])) {
  506. $data['city'] = explode('/', $data['city'])[1];
  507. }
  508. Db::startTrans();
  509. $this->validate($data, \app\admin\validate\Mobile::class);
  510. $data['type'] = 1;
  511. $info = [];
  512. if (isset($data['describe'])) {
  513. $info['describe'] = $data['describe'];
  514. unset($data['describe']);
  515. }
  516. $mobile = $this->model::create($data);
  517. $mobile->info()->save($info);
  518. Db::commit();
  519. $this->success();
  520. }else{
  521. return view();
  522. }
  523. }
  524. public function export($ids){
  525. $mobiles=$this->model->whereIn('id',$ids)->select();
  526. $excel = new Spreadsheet();
  527. $excel->getProperties()
  528. ->setCreator("admin")
  529. ->setLastModifiedBy("admin")
  530. ->setTitle("导出号码")
  531. ->setSubject("导出号码");
  532. $excel->getDefaultStyle()->getFont()->setName('Microsoft Yahei');
  533. $excel->getDefaultStyle()->getFont()->setSize(12);
  534. $excel->getDefaultStyle()->applyFromArray(
  535. array(
  536. 'fill' => array(
  537. 'type' => Fill::FILL_SOLID,
  538. 'color' => array('rgb' => '000000')
  539. ),
  540. 'font' => array(
  541. 'color' => array('rgb' => "000000"),
  542. ),
  543. 'alignment' => array(
  544. 'vertical' => Alignment::VERTICAL_CENTER,
  545. 'horizontal' => Alignment::HORIZONTAL_CENTER,
  546. 'indent' => 1
  547. ),
  548. 'borders' => array(
  549. 'allborders' => array('style' => Border::BORDER_THIN),
  550. )
  551. ));
  552. $excel->getActiveSheet()->setCellValue('A1','ID');
  553. $excel->getActiveSheet()->setCellValue('B1','手机号');
  554. $excel->getActiveSheet()->setCellValue('C1','省份');
  555. $excel->getActiveSheet()->setCellValue('D1','归属地');
  556. $excel->getActiveSheet()->setCellValue('E1','运营商');
  557. $excel->getActiveSheet()->setCellValue('F1','供应商');
  558. $excel->getActiveSheet()->setCellValue('G1','卡品牌');
  559. $excel->getActiveSheet()->setCellValue('H1','规律');
  560. $excel->getActiveSheet()->setCellValue('I1','套餐信息');
  561. $excel->getActiveSheet()->setCellValue('J1','原价');
  562. $excel->getActiveSheet()->setCellValue('K1','底价');
  563. $excel->getActiveSheet()->setCellValue('L1','售价');
  564. $excel->getActiveSheet()->setCellValue('M1','秒杀价');
  565. $excel->getActiveSheet()->setCellValue('N1','预存话费');
  566. $excel->getActiveSheet()->setCellValue('O1','备注');
  567. $excel->getActiveSheet()->setCellValue('P1','置顶');
  568. $excel->getActiveSheet()->setCellValue('Q1','推荐');
  569. $excel->getActiveSheet()->setCellValue('R1','号码状态');
  570. $excel->getActiveSheet()->setCellValue('S1','更新时间');
  571. $excel->getActiveSheet()->setCellValue('T1','上架时间');
  572. $excel->getActiveSheet()->setCellValue('U1','排序');
  573. $excel->getActiveSheet()->setCellValue('V1','预占通道');
  574. $excel->getActiveSheet()->setCellValue('W1','预占用户ID');
  575. $excel->getActiveSheet()->setCellValue('X1','上传用户');
  576. $i=2;
  577. foreach ($mobiles as $mobile){
  578. $rules=[];
  579. foreach (MobileConstant::getFilters() as $rule=>$field){
  580. foreach (array_values($field) as $column){
  581. if($mobile[$column]==1){
  582. $rules[]=$rule;
  583. }
  584. }
  585. }
  586. $mobile['rules']=array_values(array_unique($rules));
  587. $status=$mobile['is_activity']?'预占':\app\common\model\Mobile::$status[$mobile['status']];
  588. $excel->getActiveSheet()->setCellValue('A'.$i,$mobile['id']);
  589. $excel->getActiveSheet()->setCellValue('B'.$i,$mobile['no']);
  590. $excel->getActiveSheet()->setCellValue('C'.$i,$mobile['province']);
  591. $excel->getActiveSheet()->setCellValue('D'.$i,$mobile['city']);
  592. $excel->getActiveSheet()->setCellValue('E'.$i,$mobile['network']);
  593. $excel->getActiveSheet()->setCellValue('F'.$i,$mobile['proxy']['nickname']??'');
  594. $excel->getActiveSheet()->setCellValue('G'.$i,$mobile['brand']);
  595. $excel->getActiveSheet()->setCellValue('H'.$i,implode(',',$mobile['rules']));
  596. $excel->getActiveSheet()->setCellValue('I'.$i,$mobile['info']['describe']??'');
  597. $excel->getActiveSheet()->setCellValue('J'.$i,$mobile['amount_original']);
  598. $excel->getActiveSheet()->setCellValue('K'.$i,$mobile['amount_di']);
  599. $excel->getActiveSheet()->setCellValue('L'.$i,$mobile['amount_base']);
  600. $excel->getActiveSheet()->setCellValue('M'.$i,$mobile['amount_kill']);
  601. $excel->getActiveSheet()->setCellValue('N'.$i,$mobile['amount_charge']);
  602. $excel->getActiveSheet()->setCellValue('O'.$i,$mobile['remark']);
  603. $excel->getActiveSheet()->setCellValue('P'.$i,$mobile['top_time']?'是':'否');
  604. $excel->getActiveSheet()->setCellValue('Q'.$i,$mobile['rec_time']?'是':'否');
  605. $excel->getActiveSheet()->setCellValue('R'.$i,$status);
  606. $excel->getActiveSheet()->setCellValue('S'.$i,date('Y-m-d H:i:s',$mobile['update_time']));
  607. $excel->getActiveSheet()->setCellValue('T'.$i,date('Y-m-d H:i:s',$mobile['create_time']));
  608. $excel->getActiveSheet()->setCellValue('U'.$i,$mobile['sort']);
  609. $excel->getActiveSheet()->setCellValue('V'.$i,$mobile['hold_chan']);
  610. $excel->getActiveSheet()->setCellValue('W'.$i,$mobile['hold_user']);
  611. $excel->getActiveSheet()->setCellValue('X'.$i,$mobile['admin_id']);
  612. $i++;
  613. }
  614. $excel->createSheet();
  615. // Redirect output to a client’s web browser (Excel2007)
  616. $title = date("YmdHis");
  617. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  618. header('Content-Disposition: attachment;filename="' . $title . '.xlsx"');
  619. header('Cache-Control: max-age=0');
  620. // If you're serving to IE 9, then the following may be needed
  621. header('Cache-Control: max-age=1');
  622. // If you're serving to IE over SSL, then the following may be needed
  623. header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
  624. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
  625. header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
  626. header('Pragma: public'); // HTTP/1.0
  627. $objWriter = IOFactory::createWriter($excel, 'Xlsx');
  628. $objWriter->save('php://output');
  629. }
  630. public function force_update(){
  631. $this->success();
  632. }
  633. public function batch_set_amount($ids){
  634. if($this->request->isGet()){
  635. return view();
  636. }else{
  637. $data=input('row/a');
  638. $this->validate($data,[
  639. 'amount_base|售价'=>['require','number','gt:0'],
  640. 'amount_di|底价'=>['require','number','egt:0'],
  641. ]);
  642. $mobiles=$this->model->whereIn('id',$ids)->select();
  643. foreach ($mobiles as $mobile){
  644. $mobile['amount_base']=$data['amount_base'];
  645. $mobile['amount_di']=$data['amount_di'];
  646. $mobile->save();
  647. }
  648. $this->success();
  649. }
  650. }
  651. public function set_kill($ids){
  652. if($this->request->isGet()){
  653. return view();
  654. }else{
  655. $data=input('row/a');
  656. $this->validate($data,[
  657. 'amount_kill|秒杀价'=>['require','number','gt:0'],
  658. ]);
  659. $mobiles=$this->model->whereIn('id',$ids)->select();
  660. Db::startTrans();
  661. foreach ($mobiles as $mobile){
  662. $mobile['amount_kill']=$data['amount_kill'];
  663. $mobile['is_activity']=1;
  664. if(!$mobile->save()){
  665. Db::rollback();
  666. $this->error('保存失败');
  667. }
  668. }
  669. Db::commit();
  670. $this->success();
  671. }
  672. }
  673. public function set_online_clear(){
  674. $type = input('type',1);
  675. if($this->request->isGet()) {
  676. $this->assign('type',$type);
  677. return view();
  678. }else{
  679. $data=[];
  680. $act=input('act');
  681. $reserve=input('reserve');
  682. if($type==1){
  683. switch ($act){
  684. case 'check':
  685. $num=$this->model->where('status',0)->group('no')->having('no_cf_count>1')->column('count(no) as no_cf_count');
  686. $data['num']=array_sum($num);
  687. break;
  688. case 'del':
  689. $data['num']=$this->set_online_clear_del($reserve,$type);
  690. break;
  691. }
  692. }elseif ($type==2){
  693. switch ($act){
  694. case 'check':
  695. $num=$this->model->where('status',1)->group('no')->having('no_cf_count>1')->column('count(no) as no_cf_count');
  696. $data['num']=array_sum($num);
  697. break;
  698. case 'del':
  699. $data['num']=$this->set_online_clear_del($reserve,$type);
  700. break;
  701. }
  702. }
  703. $this->result($data,1);
  704. }
  705. }
  706. protected function set_online_clear_del($reserve,$type){
  707. if(in_array($reserve,[1,2])){
  708. return $this->set_online_clear_query($type,'id',$reserve==1);
  709. }elseif(in_array($reserve,[3,4])){
  710. return $this->set_online_clear_query($type,'amount_base',$reserve==3);
  711. }elseif(in_array($reserve,[5,6])){
  712. return $this->set_online_clear_query($type,'amount_di',$reserve==5);
  713. }
  714. }
  715. protected function set_online_clear_query($type,$column,$asc){
  716. $map=[];
  717. if($type==1) {
  718. $map['status'] = ['eq',0];
  719. }elseif($type==2) {
  720. $map['status'] = ['eq',1];
  721. }
  722. $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');
  723. $ids=[];
  724. foreach ($res as $item){
  725. $tempIds=explode(',',$item['ids']);
  726. $tempAmount=explode(',',$item[$column]);
  727. $tempNew=array_combine($tempIds,$tempAmount);
  728. $asc?asort($tempNew,1):arsort($tempNew,1);
  729. unset($tempNew[array_keys($tempNew)[0]]);
  730. $ids=array_merge($ids,array_keys($tempNew));
  731. }
  732. return $this->model->whereIn('id',$ids)->delete();
  733. }
  734. public function batch_copy_operation(){
  735. if($this->request->isGet()) {
  736. return view();
  737. }else{
  738. $num=0;
  739. $data=input('row/a');
  740. $this->validate($data,[
  741. 'no|手机号'=>['require'],
  742. 'act'=>'require',
  743. ]);
  744. if($data['act']=='delete'){
  745. $mobiles=$this->model->whereIn('no',$data['no'])->select();
  746. Db::startTrans();
  747. foreach ($mobiles as $mobile){
  748. $mobile->delete();
  749. }
  750. $num=count($mobiles);
  751. Db::commit();
  752. }elseif($data['act']=='up'){
  753. $num=$this->model->whereIn('no',$data['no'])->update(['status'=>0]);
  754. }elseif($data['act']=='down'){
  755. $num=$this->model->whereIn('no',$data['no'])->update(['status'=>2]);
  756. }
  757. $this->result(['num'=>$num],1);
  758. }
  759. }
  760. public function mobile_rules(){
  761. return MobileConstant::getRuleKeys();
  762. }
  763. public function activity_cancel($ids){
  764. $mobile=$this->model->findOrFail($ids);
  765. $admin=Admin::get($this->auth->id);
  766. if(!$mobile['is_activity']){
  767. $this->error('该号码没有被预占无法取消');
  768. }
  769. if($admin['proxy']){
  770. $this->error('您是供应商,无法使用此功能');
  771. }
  772. if($admin['sub'] && $mobile['hold_chan']!=$admin['id']){
  773. $this->error('您无法取消');
  774. }
  775. $mobile->makeNotActivity();
  776. $this->success();
  777. }
  778. public function batch_activity_cancel($ids){
  779. $map=[];
  780. if($this->admin('sub')){
  781. $map['hold_chan']=$this->admin('id');
  782. }
  783. $this->model->whereIn('id',$ids)->where($map)->update([
  784. 'is_activity'=>0,
  785. 'activity_time'=>0,
  786. 'hold_chan' =>0,
  787. 'hold_user' =>0,
  788. ]);
  789. $this->success();
  790. }
  791. /** 排序 */
  792. public function mobile_sort($ids){
  793. $mobile=$this->model->find($ids);
  794. if(!$mobile){
  795. return '';
  796. }
  797. $row=[
  798. 'sort'=>0,
  799. ];
  800. if($this->request->isGet()){
  801. if($this->admin('sub')){
  802. $row['sort']=MobileSub::getBy($mobile,$this->admin())['sub_sort'];
  803. }else{
  804. $row['sort']=$mobile['sort'];
  805. }
  806. $this->assign('row',$row);
  807. return view();
  808. }else{
  809. $data=input('row/a');
  810. $this->validate($data,[
  811. 'sort|排序'=>['require','integer','gt:0'],
  812. ]);
  813. if($this->admin('sub')){
  814. $mobileSub=MobileSub::getBy($mobile,$this->admin());
  815. $mobileSub['sub_sort']=$data['sort'];
  816. $mobileSub->save();
  817. }else{
  818. $mobile['sort']=$data['sort'];
  819. $mobile->save();
  820. }
  821. $this->success();
  822. }
  823. }
  824. }