Mobile.php 38 KB

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