Member.php 125 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312
  1. <?php
  2. /**
  3. * 前台注册用户管理控制器
  4. */
  5. namespace app\admin\controller;
  6. use app\common\library\MakeReportGo;
  7. use app\common\model\Members;
  8. use app\common\model\Members as MembersModel;
  9. use app\common\model\MembersTwo;
  10. use app\common\model\Channel;
  11. use app\common\model\Game;
  12. use app\common\model\Pay;
  13. use app\common\model\Subaccount;
  14. use think\Cache;
  15. use think\Db;
  16. use app\common\logic\Member as MemberService;
  17. use app\common\library\MakeReport;
  18. use think\Env;
  19. use think\Model;
  20. class Member extends Admin
  21. {
  22. protected $membersModel;
  23. protected $where;
  24. protected $start_time;
  25. protected $end_time;
  26. /**
  27. * 不进行父类的登录验证,所以增加构造方法重写了父类的初始化方法
  28. */
  29. protected function _initialize()
  30. {
  31. parent::_initialize();
  32. $this->membersModel = new MembersModel;
  33. $this->where = [];
  34. $this->gameList = $gameList = model('Common/Game')->getAllByCondition('id,name');
  35. $tmpSelfGameList = model('Common/Game')->getAllByCondition('id,name', [], '', 'self');
  36. $selfGameList = array();
  37. foreach ($tmpSelfGameList as $game) {
  38. $selfGameList[$game['id']] = $game;
  39. }
  40. $this->selfGameList = $selfGameList;
  41. }
  42. public function getWhere()
  43. {
  44. $where = [];
  45. // 推广四联查询
  46. $business_type = input('tg_business', ''); // 商务
  47. $president_type = input('tg_president', ''); // 会长
  48. $president_type_son = input('tg_president_son', ''); // 子会长
  49. $promoter_type = input('tg_promoter', ''); // 推广员
  50. if ($business_type <> '') {
  51. $where['s.channel_id'] = ['in', get_child_channel_arr($business_type)];
  52. }
  53. if ($president_type <> '') {
  54. $where['s.channel_id'] = ['in', get_child_channel_arr($president_type)];
  55. }
  56. if ($president_type_son <> '') {
  57. $where['s.channel_id'] = ['in', get_child_channel_arr($president_type_son)];
  58. }
  59. if ($promoter_type <> '') {
  60. $where['s.channel_id'] = $promoter_type;
  61. }
  62. !empty($flag = input('sub_flag')) && $where['s.flag'] = $flag;
  63. !empty($sub_gameid = input('sub_gameid')) && $where['s.game_id'] = $sub_gameid;
  64. !empty($sub_id = input('sub_id')) && $where['s.id'] = $sub_id;
  65. !empty($sub_username = input('sub_username')) && $where['s.sub_username'] = ['like', '%' . $sub_username . '%'];
  66. !empty($m_nickname = input('m_nickname')) && $where['m.nickname'] = ['like', '%' . $m_nickname . '%'];
  67. $m_username = input('m_username');
  68. if(!empty($m_username)) {
  69. $mid = Db::table('cy_members')->where(['username' => $m_username])->value('id');
  70. $where['s.member_id'] = $mid;
  71. }
  72. // 获取查询日期
  73. $start_time = input('start_time');
  74. $end_time = input('end_time');
  75. // 如果没有传入日期,设置默认值(最近7天)
  76. // if (empty($start_time)) {
  77. // $start_time = date('Y-m-d', strtotime('-7 days'));
  78. // }
  79. // if (empty($end_time)) {
  80. // $end_time = date('Y-m-d');
  81. // }
  82. // 赋值给类属性,供模板使用
  83. $this->start_time = $start_time;
  84. $this->end_time = $end_time;
  85. // if ($username=='' && $id == '' && $nickname == ''){
  86. // if(strtotime($this->end_time.' 23:59:59')-strtotime($this->start_time)>31*24*3600)
  87. // {
  88. // $this->error('单次查询日期的最长跨度为31天');
  89. // }
  90. // }
  91. if (!empty(input('gh_status'))) { // 是否聚合用户:0=否、1=是
  92. $where['channel.gh_status'] = 1;
  93. }
  94. $this->where = $where;
  95. }
  96. /**
  97. * 注册用户列表
  98. */
  99. public function index()
  100. {
  101. $this->getWhere();
  102. $param = input('get.');
  103. $page_size = input('page_size', 15);
  104. // 设置查询条件
  105. if ($this->start_time && $this->end_time) {
  106. $this->where['s.create_time'] = ['between time', [strtotime($this->start_time), strtotime($this->end_time . ' 23:59:59')]];
  107. } elseif($this->start_time){
  108. $this->where['s.create_time'] = ['>=', strtotime($this->start_time)];
  109. } elseif($this->end_time){
  110. $this->where['s.create_time'] = ['<=', strtotime($this->end_time. ' 23:59:59')];
  111. }
  112. // 游戏上线状态
  113. $cooperation_status = $this->request->param('cooperation_status', 0, 'intval'); // 游戏上线状态
  114. if(!empty($cooperation_status)){
  115. $game_cooperation_status = $cooperation_status==1?1:2;
  116. $gameIds = Model('Game')->getNormalByIds($game_cooperation_status);
  117. $this->where['s.game_id'] = ['in', $gameIds];
  118. }
  119. $list = Db::table('nw_subaccount')->alias('s')
  120. ->join('cy_members m', 's.member_id=m.id', 'left')
  121. ->join('nw_channel channel', 'channel.id=s.channel_id', 'left')
  122. ->join('nw_channel bchild', 'bchild.id=channel.parent_id AND bchild.level = 2', 'left')
  123. ->field('s.id,s.sub_username,s.real_name,m.id as mid,m.username,m.nickname,m.imeil,m.ip,s.channel_id,s.game_id as gameid,s.create_time,m.total_pay_amount,s.update_time as login_time,bchild.name as bchild_name,bchild.parent_id as bcparent_id, s.flag')
  124. ->where($this->where)
  125. // ->order('reg_time desc')
  126. ->order('s.id desc')
  127. ->paginate($page_size, false, array('query' => $param))
  128. ->each(function ($item, $key) {
  129. $channel_list = get_channel_top_by_aggregate($item['channel_id']);
  130. $item['channel_zero_name'] = !empty($channel_list['0']['name']) ? $channel_list['0']['name'] : '';
  131. $item['channel_one_name'] = !empty($channel_list['1']['name']) ? $channel_list['1']['name'] : '';
  132. $item['channel_two_name'] = !empty($channel_list['2']['name']) ? $channel_list['2']['name'] : '';
  133. $item['channel_three_name'] = !empty($channel_list['3']['name']) ? $channel_list['3']['name'] : '';
  134. return $item;
  135. });
  136. $gameList = $this->selfGameList;
  137. $gList = $gameList;
  138. $gameList = array_column($gameList, 'name', 'id');
  139. $data = $list->toArray()['data'];
  140. $memberIdArr = [];
  141. foreach ($data as &$v) {
  142. $memberIdArr[] = $v['id'];
  143. // $v['top_channel_name'] = get_top_channel($v['channel_id'])['name'];
  144. // $v['dep_name'] = get_channel_name($v['channel_id']);
  145. // $v['union_name'] = get_union_channel($v['channel_id'])['name'];
  146. $condition = [];
  147. $condition['userid'] = $v['id'];
  148. $condition['gameid'] = $v['gameid'];
  149. $roleinfo = (new MemberService())->queryUserRole($condition); // 账号查询
  150. $v['rolename'] = $roleinfo['rolename'];
  151. $v['servername'] = $roleinfo['servername'];
  152. $v['rolelevel'] = $roleinfo['rolelevel'];
  153. $userPayInfo = Db::table('cy_pay')->where(['status' => 1, 'userid' => $v['mid'], 'gameid' => $v['gameid']])->field('userid, sum(amount) as money, count(id) as paycount')->find();
  154. $v['total_pay_amount'] = isset($userPayInfo['money']) ? $userPayInfo['money'] : 0;
  155. $v['total_pay_cnt'] = isset($userPayInfo['paycount']) ? $userPayInfo['paycount'] : 0;
  156. // $v['avatar'] = $v['avatar'] ? STATIC_DOMAIN . $v['avatar'] : '';
  157. // 账号加密
  158. // $v['username'] = stringObfuscation($v['username'],3);
  159. }
  160. $channel = [];
  161. $channelId = input('request.channel_id');
  162. if ($channelId) {
  163. $channel = model('Common/Channel')->field(['id', 'name'])->find($channelId);
  164. }
  165. //$channel_list = model('Common/Channel')->getAllByCondition('id,name',['status' => 1,'flag'=>['in','3,4']]);
  166. $this->assign('list', $data);
  167. $this->assign('total', $list->total()); //总条数
  168. $this->assign('start_time', $this->start_time);
  169. $this->assign('end_time', $this->end_time);
  170. $this->assign('page', $list->render());
  171. $this->assign('game_list', $gameList);
  172. $this->assign('glist', $gList);
  173. $this->assign('channel', $channel);
  174. $this->assign('channel_list', []);
  175. $this->assign('start_time', $this->start_time);
  176. $this->assign('end_time', $this->end_time);
  177. $uniom = model('Channel')->where(['level' => 0])->field('id,name')->select();
  178. $this->assign('uniom', $uniom); //顶级渠道列表
  179. $this->assign('jh_url', url('Member/index', ['gh_status' => 1, 'page_size' => '100'], 'html'));
  180. return $this->fetch();
  181. }
  182. public function index1(){
  183. $this->getWhere();
  184. $param = input('get.');
  185. $page_size = input('page_size', 15);
  186. $list = Db::table('nw_subaccount')->alias('s')
  187. ->join('cy_members m', 's.member_id=m.id', 'left')
  188. ->join('nw_channel channel', 'channel.id=s.channel_id', 'left')
  189. ->join('nw_channel bchild', 'bchild.id=channel.parent_id AND bchild.level = 2', 'left')
  190. ->field('s.id,s.sub_username,s.real_name,m.id as mid,m.username,m.nickname,m.avatar,s.channel_id,s.game_id as gameid,m.reg_time,m.ip,m.imeil,m.total_pay_amount,m.login_time,bchild.name as bchild_name,bchild.parent_id as bcparent_id, s.flag')
  191. ->where($this->where)
  192. ->order('s.id desc')
  193. ->paginate($page_size, false, array('query' => $param));
  194. $gameList = $this->selfGameList;
  195. $gList = $gameList;
  196. $gameList = array_column($gameList, 'name', 'id');
  197. $data = $list->toArray()['data'];
  198. if(!empty($data)){
  199. $roleInfo = Db::table('cy_role_info')
  200. ->field(['servername', 'rolename', 'rolelevel','userid','gameid'])
  201. ->order('id', 'asc')
  202. ->select()->toArray();
  203. foreach ($data as &$v){
  204. foreach ($roleInfo as $val){
  205. if($v['id']==$val['userid'] && $v['gameid']==$val['gameid']){
  206. $v['rolename'] = $val['rolename'];
  207. $v['servername'] = $val['servername'];
  208. $v['rolelevel'] = $val['rolelevel'];
  209. }
  210. }
  211. $userPayInfo = model('Pay')->where(['status' => 1, 'userid' => $v['id']])->group('userid')->field(['userid', 'sum(amount) as money', 'count(id) as paycount'])->find();
  212. $v['total_pay_amount'] = isset($userPayInfo->money) ? $userPayInfo->money : 0;
  213. $v['total_pay_cnt'] = isset($userPayInfo->paycount) ? $userPayInfo->paycount : 0;
  214. $v['avatar'] = $v['avatar'] ? STATIC_DOMAIN . $v['avatar'] : '';
  215. $channel_list = get_channel_top_by_aggregate($v['channel_id']);
  216. $v['channel_zero_name'] = !empty($channel_list['0']['name']) ? $channel_list['0']['name'] : '';
  217. $v['channel_one_name'] = !empty($channel_list['1']['name']) ? $channel_list['1']['name'] : '';
  218. $v['channel_two_name'] = !empty($channel_list['2']['name']) ? $channel_list['2']['name'] : '';
  219. $v['channel_three_name'] = !empty($channel_list['3']['name']) ? $channel_list['3']['name'] : '';
  220. }
  221. }
  222. $channel = [];
  223. $channelId = input('request.channel_id');
  224. if ($channelId) {
  225. $channel = model('Common/Channel')->field(['id', 'name'])->find($channelId);
  226. }
  227. $this->assign('list', $data);
  228. $this->assign('total', $list->total()); //总条数
  229. $this->assign('start_time', $this->start_time);
  230. $this->assign('end_time', $this->end_time);
  231. $this->assign('page', $list->render());
  232. $this->assign('game_list', $gameList);
  233. $this->assign('glist', $gList);
  234. $this->assign('channel', $channel);
  235. $this->assign('channel_list', []);
  236. $this->assign('start_time', $this->start_time);
  237. $this->assign('end_time', $this->end_time);
  238. $uniom = model('Channel')->where(['level' => 0])->field('id,name')->select();
  239. $this->assign('uniom', $uniom); //顶级渠道列表
  240. $this->assign('jh_url', url('Member/index', ['gh_status' => 1, 'page_size' => '100'], 'html'));
  241. return $this->fetch();
  242. }
  243. /**
  244. * 报表下载
  245. *
  246. */
  247. public function download($is_show = ['is_show'=>false])
  248. {
  249. if (request()->isAjax()) {
  250. $this->getWhere(false);
  251. // 设置查询条件
  252. if ($this->start_time && $this->end_time) {
  253. $where['reg_time'] = ['between time', [strtotime($this->start_time), strtotime($this->end_time . ' 23:59:59')]];
  254. } elseif($this->start_time){
  255. $where['reg_time'] = ['>=', strtotime($this->start_time)];
  256. } elseif($this->end_time){
  257. $where['reg_time'] = ['<=', strtotime($this->end_time. ' 23:59:59')];
  258. }
  259. // 游戏上线状态
  260. $cooperation_status = $this->request->param('cooperation_status', 0, 'intval'); // 游戏上线状态
  261. if(!empty($cooperation_status)){
  262. $game_cooperation_status = $cooperation_status==1?1:2;
  263. $gameIds = Model('Game')->getNormalByIds($game_cooperation_status);
  264. $this->where['gameid'] = ['in', $gameIds];
  265. }
  266. if ($is_show['is_show']) {
  267. $start_time = input('request.start_time', '', 'trim');
  268. $end_time = input('request.end_time', '', 'trim');
  269. $username = input('request.username', '', 'trim');
  270. $gameid = input('request.gameid', '', 'intval');
  271. if (!$start_time) {
  272. $start_time = date("Y-m-d");
  273. }
  274. if (!$end_time) {
  275. $end_time = date("Y-m-d");
  276. }
  277. $LogStr = "时间:" . $start_time . "~" . $end_time;
  278. if ($gameid) {
  279. $game_name = get_game_nickname($gameid);
  280. } else {
  281. $game_name = "全部游戏";
  282. }
  283. $LogStr .= ",游戏:" . $game_name;
  284. $LogStr .= ",玩家账号:" . $username;
  285. $this->insertLog($this->current_node, $LogStr, 122);
  286. }
  287. $sql = $this->membersModel
  288. ->field('id,username,nickname,channel_id,flag,gameid,reg_time,total_pay_amount,login_time,imeil')
  289. ->where($this->where)
  290. ->order('reg_time desc')->fetchSql(true)->select();
  291. if ((new MakeReportGo())->addTask('memberList', $sql, session_id(), $is_show)) {
  292. $this->success('报表生成的任务已经提交, 报表生成完成后,会及时通知您,请耐心稍等');
  293. }
  294. $this->error('报表生成任务不可重复提交,如遇到无法导出情况,建议修改查询条件解除当前状态,提交重新生成报表任务!');
  295. }
  296. else{
  297. $this->error('非法请求');
  298. }
  299. }
  300. public function downloadSub()
  301. {
  302. if (request()->isAjax()) {
  303. $this->getWhere(false);
  304. // 设置查询条件
  305. if ($this->start_time && $this->end_time) {
  306. $this->where['s.create_time'] = ['between time', [strtotime($this->start_time), strtotime($this->end_time . ' 23:59:59')]];
  307. } elseif($this->start_time){
  308. $this->where['s.create_time'] = ['>=', strtotime($this->start_time)];
  309. } elseif($this->end_time){
  310. $this->where['s.create_time'] = ['<=', strtotime($this->end_time. ' 23:59:59')];
  311. }
  312. // 游戏上线状态
  313. $cooperation_status = $this->request->param('cooperation_status', 0, 'intval'); // 游戏上线状态
  314. if(!empty($cooperation_status)){
  315. $game_cooperation_status = $cooperation_status==1?1:2;
  316. $gameIds = Model('Game')->getNormalByIds($game_cooperation_status);
  317. $this->where['s.game_id'] = ['in', $gameIds];
  318. }
  319. $sql = Db::table('nw_subaccount')->alias('s')
  320. ->join('cy_members m', 's.member_id=m.id', 'left')
  321. ->join('nw_channel channel', 'channel.id=s.channel_id', 'left')
  322. ->join('nw_channel bchild', 'bchild.id=channel.parent_id AND bchild.level = 2', 'left')
  323. ->field('s.id,s.sub_username,s.real_name,m.id as mid,m.username,m.nickname,m.imeil,m.ip,s.channel_id,s.game_id as gameid,s.create_time,m.total_pay_amount,s.update_time as login_time,bchild.name as bchild_name,bchild.parent_id as bcparent_id, s.flag')
  324. ->where($this->where)
  325. ->order('s.id desc')
  326. ->fetchSql(true)->select();
  327. // dump($sql);
  328. if ((new MakeReportGo())->addTask('memberSubList', $sql, session_id(), [])) {
  329. $this->success('报表生成的任务已经提交, 报表生成完成后,会及时通知您,请耐心稍等');
  330. }
  331. $this->error('报表生成任务不可重复提交,如遇到无法导出情况,建议修改查询条件解除当前状态,提交重新生成报表任务!');
  332. }
  333. else{
  334. $this->error('非法请求');
  335. }
  336. }
  337. /**
  338. * 冻结账户
  339. */
  340. public function frozen()
  341. {
  342. $id = input('id', 0, 'intval');
  343. $flag = input('flag', 0, 'abs');
  344. if (empty($id)) {
  345. $this->error('用户ID不能为空');
  346. }
  347. $members = new MembersModel();
  348. if (!$info = $members->get(['id' => $id])) {
  349. $this->error('非法参数');
  350. }
  351. if ($flag == 1) $msg = '冻结'; else
  352. $msg = '解冻';
  353. if ($members->update(['flag' => $flag, 'update_time' => time(),], ['id' => $id])) {
  354. // 插入冻结记录
  355. model('FrozenHistory')->addData($id, $flag);
  356. $info = $msg . "玩家:{$info['username']}";
  357. $this->insertLog($this->current_node, $info, 22);
  358. $this->success($msg . '账户成功');
  359. } else {
  360. $this->error($msg . '账户失败');
  361. }
  362. }
  363. /**
  364. * 子账户 - 冻结/解冻
  365. */
  366. public function frozenSubaccount()
  367. {
  368. $id = input('id', 0, 'intval');
  369. $flag = input('flag', 0, 'abs');
  370. if (empty($id)) {
  371. $this->error('用户ID不能为空');
  372. }
  373. $nw_subaccount = new Subaccount();
  374. if (!$info = $nw_subaccount->get(['id' => $id])) {
  375. $this->error('非法参数');
  376. }
  377. if ($flag == 1) $msg = '冻结'; else
  378. $msg = '解冻';
  379. if ($nw_subaccount->update(['flag' => $flag, 'update_time' => time(),], ['id' => $id])) {
  380. // 插入冻结记录
  381. model('FrozenHistory')->addData($id, $flag);
  382. $info = $msg . "玩家:{$info['sub_username']}";
  383. $this->insertLog($this->current_node, $info, 22);
  384. $this->success($msg . '账户成功');
  385. } else {
  386. $this->error($msg . '账户失败');
  387. }
  388. }
  389. /**
  390. * 登录用户列表
  391. */
  392. private function getLoginListQuery($where)
  393. {
  394. return Db::table('cy_logininfo')->alias('l')
  395. ->join('nw_subaccount s', 's.id = l.sub_id', 'left')
  396. ->join('cy_members m', 'm.id = l.userid', 'left')
  397. ->field(
  398. 'l.id,l.ip,l.channel_id,l.userid,l.gameid,l.imeil,l.login_time,'
  399. . 's.id AS sub_id,s.sub_username,m.username,m.total_pay_amount,m.flag,'
  400. . 'COALESCE(s.create_time,l.reg_time) AS reg_time'
  401. )
  402. ->where($where)
  403. ->order('l.login_time desc,l.id desc');
  404. }
  405. public function loginList()
  406. {
  407. $where = $this->_getLoginListCondition(true);
  408. // 剔除聚合渠道数据
  409. // $where['c.flag'] = ['<>',4];
  410. $list = $this->getLoginListQuery($where)
  411. ->paginate(25, false, ['query' => input('get.')]);
  412. $data = $list->toArray()['data'];
  413. foreach ($data as $key => $value) {
  414. // 与 playerActive 保持一致:按 id_path 中的实际 level 映射推广层级。
  415. $channelInfo = get_top_second_channel_name_v2($value['channel_id']);
  416. $data[$key]['name'] = $channelInfo['channel_name'];
  417. $data[$key]['bchild_name'] = $channelInfo['second_name'];
  418. $data[$key]['top_channel_name'] = $channelInfo['top_name'];
  419. $data[$key]['union_name'] = $channelInfo['union_name'];
  420. // 账号加密
  421. if($value['username']){
  422. $data[$key]['username'] = stringObfuscation($value['username'], 3);
  423. }
  424. }
  425. $gameList = $this->selfGameList;
  426. $gList = array_column($gameList, 'name', 'id');
  427. $this->assign('list', $data);
  428. $this->assign('total', $list->total()); //总条数
  429. $this->assign('page', $list->render());
  430. $this->assign('game_list', $gList);
  431. $this->assign('gList', $gameList);
  432. $this->assign('start_time', $this->start_time);
  433. $this->assign('end_time', $this->end_time);
  434. $uniom = model('Channel')->where(['level' => 0])->field('id,name')->select();
  435. $this->assign('uniom', $uniom); //顶级渠道列表
  436. return $this->fetch('login_list');
  437. }
  438. /**
  439. * 登录用户 报表下载
  440. */
  441. public function loginListDownload($is_show = ['is_show'=>false])
  442. {
  443. if (request()->isAjax()) {
  444. $where = $this->_getLoginListCondition(true);
  445. if ($is_show['is_show']) {
  446. $start_time = input('request.start_time', '', 'trim');
  447. $end_time = input('request.end_time', '', 'trim');
  448. $username = input('request.username', '', 'trim');
  449. $gameid = input('request.gameid', '', 'intval');
  450. if (!$start_time) {
  451. $start_time = date("Y-m-d");
  452. }
  453. if (!$end_time) {
  454. $end_time = date("Y-m-d"); }
  455. $LogStr = "时间:" . $start_time . "~" . $end_time;
  456. if ($gameid) {
  457. $game_name = get_game_nickname($gameid);
  458. } else {
  459. $game_name = "全部游戏";
  460. }
  461. $LogStr .= ",游戏:" . $game_name;
  462. $LogStr .= ",玩家账号:" . $username;
  463. $this->insertLog($this->current_node, $LogStr, 121);
  464. }
  465. // 剔除聚合渠道数据
  466. // $where['c.flag'] = ['<>',4];
  467. $sql = $this->getLoginListQuery($where)
  468. ->fetchSql(true)
  469. ->select();
  470. if((new MakeReportGo())->addTask('memberLoginList', $sql, session_id(), $is_show)){
  471. $this->success('报表生成的任务已经提交, 报表生成完成后,会及时通知您,请耐心稍等');
  472. }
  473. $this->error('报表生成任务不可重复提交,如遇到无法导出情况,建议修改查询条件解除当前状态,提交重新生成报表任务!');
  474. } else {
  475. $this->error('非法请求');
  476. }
  477. }
  478. /**
  479. * 登录用户 条件查询
  480. * @return array
  481. */
  482. protected function _getLoginListCondition($isdefault)
  483. {
  484. // $where['m.is_local'] = 1;
  485. $start_time = input('request.start_time', '', 'trim');
  486. $end_time = input('request.end_time', '', 'trim');
  487. $username = input('request.username', '', 'trim');
  488. $sub_username = input('request.sub_username', '', 'trim');
  489. $imeil = input('request.imeil', '', 'trim');
  490. $gameid = input('request.gameid', '', 'intval');
  491. $channel_id = input('channel_id', 0, 'intval');
  492. $top_channel_id = input('parent_channel_id', 0, 'intval');
  493. $bplus_channel_id = $this->request->param('bplus_channel_id', 0, 'intval');
  494. // 获取查询日期
  495. $where['l.login_time'] =$this->getTimeCondition($start_time,$end_time,$isdefault);
  496. /*
  497. if ($username==''){
  498. if(strtotime($this->end_time.' 23:59:59')-strtotime($this->start_time)>31*24*3600)
  499. {
  500. $this->error('单次查询日期的最长跨度为31天');
  501. }
  502. }
  503. */
  504. //用户名
  505. if ($username != '') {
  506. $userid = $this->membersModel->where(['username' => $username])->value('id');
  507. $where['l.userid'] = intval($userid) ?: 0;
  508. }
  509. //游戏名称
  510. if (!empty($gameid)) {
  511. $where['l.gameid'] = ['=', $gameid];
  512. }
  513. // 推广四联查询
  514. $business_type = input('business_type', input('tg_business', '')); // 商务
  515. $president_type = input('president_type', input('tg_president', '')); // 会长
  516. $president_type_son = input('president_type_son', input('tg_president_son', '')); // 子会长
  517. $promoter_type = input('promoter_type', input('tg_promoter', '')); // 推广员
  518. if ($business_type <> '') {
  519. $where['l.channel_id'] = ['in', get_child_channel_arr($business_type)];
  520. }
  521. if ($president_type <> '') {
  522. $where['l.channel_id'] = ['in', get_child_channel_arr($president_type)];
  523. }
  524. if ($president_type_son <> '') {
  525. $where['l.channel_id'] = ['in', get_child_channel_arr($president_type_son)];
  526. }
  527. if ($promoter_type <> '') {
  528. $where['l.channel_id'] = $promoter_type;
  529. }
  530. //渠道名称
  531. if ( !empty($channel_id) || !empty($top_channel_id) || !empty($bplus_channel_id)) {
  532. $where['l.channel_id'] = $this->getChannelCondition($channel_id,$top_channel_id,$bplus_channel_id);
  533. }
  534. // 游戏上线状态
  535. $cooperation_status = $this->request->param('cooperation_status', 0, 'intval'); // 游戏上线状态
  536. if(!empty($cooperation_status)){
  537. $game_cooperation_status = $cooperation_status==1?1:2;
  538. $gameIds = Model('Game')->getNormalByIds($game_cooperation_status);
  539. $where['l.gameid'] = ['in', $gameIds];
  540. }
  541. return $where;
  542. }
  543. /**
  544. * 冻结用户列表
  545. */
  546. public function frozenList()
  547. {
  548. $where = [];
  549. $memberIdArr = [];
  550. $where['m.flag'] = 1;
  551. //查询参数
  552. $start_time = input('request.start_time');
  553. $end_time = input('request.end_time');
  554. $username = input('request.username');
  555. $gameid = input('request.gameid');
  556. $imeil = input('request.imeil');
  557. //开始时间和结束时间不为空时
  558. if ($start_time != '' && $end_time != '') {
  559. $where['m.reg_time'] = [
  560. ['>=', strtotime($start_time)],
  561. ['<=', strtotime($end_time . ' 23:59:59')],
  562. ];
  563. } //开始时间不为空时
  564. elseif ($start_time != '') {
  565. $where['m.reg_time'] = ['>=', strtotime($start_time)];
  566. } //结束时间不为空时
  567. elseif ($end_time != '') {
  568. $where['m.reg_time'] = ['<=', strtotime($end_time . ' 23:59:59')];
  569. } else {
  570. /*
  571. $start_time = $end_time = date('Y-m-d', time());
  572. $where['m.reg_time'] = ['>=', strtotime($start_time)];
  573. */
  574. }
  575. //用户名
  576. if ($username != '') {
  577. $where['m.username'] = ['like', '%' . $username . '%'];
  578. }
  579. //imeil
  580. if ($imeil != '') {
  581. $where['m.imeil'] = ['=', $imeil];
  582. }
  583. //游戏名称
  584. if ($gameid != '') {
  585. $where['m.gameid'] = ['=', $gameid];
  586. }
  587. $list = Db::table('cy_members')->alias('m')
  588. ->join('nw_channel c', 'm.channel_id = c.id')
  589. ->field("m.id,m.imeil,m.reg_time,m.login_time,m.gameid,m.username,m.total_pay_amount,m.flag,m.channel_id,c.name, '' as remark")
  590. ->order('m.id desc')
  591. ->where($where)->paginate(10, false, ['query' => input('get.')]);
  592. $data = $list->toArray()['data'];
  593. // 处理冻结备注
  594. $subIds = array_column($data, 'id');
  595. $frozenMaxList = Db::table('cy_frozen_history')
  596. ->field('user_id, MAX(id) as max_id')
  597. ->where(['user_id' => ['IN', $subIds], 'status' => 1])
  598. ->group('user_id')
  599. ->select();
  600. $maxIds = array_column($frozenMaxList, 'max_id');
  601. $frozenList = model('FrozenHistory')->where(['id' => ['IN', $maxIds], 'status' => 1])->order('id desc')->group('user_id')->column('user_id,remark');
  602. foreach ($data as $key => $value) {
  603. $memberIdArr[] = $value['id'];
  604. $data[ $key ]['top_channel_name'] = get_top_channel($value['channel_id'])['name'];
  605. $data[ $key ]['bchild_name'] = get_top_second_channel_name($value['channel_id'])['second_name'];
  606. $data[$key]['remark'] = $frozenList[$value['id']] ?? '';
  607. }
  608. $payArr = model('pay')->where(['status' => 1, 'userid' => ['IN', $memberIdArr]])->group('userid')
  609. ->column('userid,sum(amount) as money,count(id) as paycount');
  610. $gameList = $this->selfGameList;
  611. $gList = array_column($gameList, 'name', 'id');
  612. $this->assign('list', $data);
  613. $this->assign('total', $list->total()); //总条数
  614. $this->assign('payArr', $payArr);
  615. $this->assign('start_time', $start_time);
  616. $this->assign('end_time', $end_time);
  617. $this->assign('page', $list->render());
  618. $this->assign('game_list', $gameList);
  619. $this->assign('gList', $gList);
  620. return $this->fetch('frozen_list');
  621. }
  622. /**
  623. * 冻结子用户列表
  624. */
  625. public function frozenSubaccountList()
  626. {
  627. $where = [];
  628. $memberIdArr = [];
  629. $where['s.flag'] = 1;
  630. //查询参数
  631. $start_time = input('request.start_time');
  632. $end_time = input('request.end_time');
  633. $username = input('request.username');
  634. $sub_username = input('request.sub_username');
  635. $gameid = input('request.gameid');
  636. $imeil = input('request.imeil');
  637. //开始时间和结束时间不为空时
  638. if ($start_time != '' && $end_time != '') {
  639. $where['s.create_time'] = [
  640. ['>=', strtotime($start_time)],
  641. ['<=', strtotime($end_time . ' 23:59:59')],
  642. ];
  643. } //开始时间不为空时
  644. elseif ($start_time != '') {
  645. $where['s.create_time'] = ['>=', strtotime($start_time)];
  646. } //结束时间不为空时
  647. elseif ($end_time != '') {
  648. $where['s.create_time'] = ['<=', strtotime($end_time . ' 23:59:59')];
  649. } else {
  650. /*
  651. $start_time = $end_time = date('Y-m-d', time());
  652. $where['m.create_time'] = ['>=', strtotime($start_time)];
  653. */
  654. }
  655. // 子账号用户名
  656. if ($username != '') {
  657. $where['s.sub_username'] = ['like', '%' . $sub_username . '%'];
  658. }
  659. // 用户名
  660. if ($username != '') {
  661. $where['m.username'] = ['like', '%' . $username . '%'];
  662. }
  663. //imeil
  664. if ($imeil != '') {
  665. $where['m.imeil'] = ['=', $imeil];
  666. }
  667. //游戏名称
  668. if ($gameid != '') {
  669. $where['s.game_id'] = ['=', $gameid];
  670. }
  671. $list = Db::table('nw_subaccount')->alias('s')
  672. ->join('cy_members m', 's.member_id = m.id','left')
  673. ->join('nw_channel c', 'm.channel_id = c.id','left')
  674. ->field("s.id,s.sub_username,m.id as mid,m.imeil,m.reg_time,m.login_time,s.game_id as gameid,m.username,m.total_pay_amount,s.flag,s.channel_id,c.name, '' as remark")
  675. ->order('s.id desc')
  676. ->group('s.id')
  677. ->where($where)->paginate(20, false, ['query' => input('get.')]);
  678. $data = $list->toArray()['data'];
  679. // 处理冻结备注
  680. $subIds = array_column($data, 'id');
  681. $frozenMaxList = Db::table('cy_frozen_history')
  682. ->field('sub_user_id, MAX(id) as max_id')
  683. ->where(['sub_user_id' => ['IN', $subIds], 'status' => 1])
  684. ->group('sub_user_id')
  685. ->select();
  686. $maxIds = array_column($frozenMaxList, 'max_id');
  687. $frozenList = model('FrozenHistory')->where(['id' => ['IN', $maxIds], 'status' => 1])->order('id desc')->group('sub_user_id')->column('sub_user_id,remark');
  688. foreach ($data as $key => $value) {
  689. $memberIdArr[] = $value['id'];
  690. $data[$key]['top_channel_name'] = get_top_channel($value['channel_id'])['name'];
  691. $data[$key]['bchild_name'] = get_top_second_channel_name($value['channel_id'])['second_name'];
  692. $data[$key]['remark'] = $frozenList[$value['id']] ?? '';
  693. }
  694. $payArr = model('pay')->where(['status' => 1, 'userid' => ['IN', $memberIdArr]])->group('userid')
  695. ->column('userid,sum(amount) as money,count(id) as paycount');
  696. $gameList = $this->selfGameList;
  697. $gList = array_column($gameList, 'name', 'id');
  698. $this->assign('list', $data);
  699. $this->assign('total', $list->total()); //总条数
  700. $this->assign('payArr', $payArr);
  701. $this->assign('start_time', $start_time);
  702. $this->assign('end_time', $end_time);
  703. $this->assign('page', $list->render());
  704. $this->assign('game_list', $gameList);
  705. $this->assign('gList', $gList);
  706. return $this->fetch('frozen_subaccount_list');
  707. }
  708. /**
  709. * 实名认证列表
  710. */
  711. public function identityList()
  712. {
  713. $MembersTwoModel = new MembersTwo;
  714. $where = [];
  715. //用户名
  716. if (trim(input('request.username')) != '') {
  717. // $where['m.username'] = ['like', '%' . input('request.username') . '%'];
  718. $where['m2.username'] = trim(input('request.username'));
  719. }
  720. //渠道名称
  721. if (trim(input('request.realname')) != '') {
  722. /// $where['m2.realname'] = ['like', '%' . input('request.realname') . '%'];
  723. $where['m2.realname'] = trim(input('request.realname'));
  724. }
  725. //游戏名称
  726. if (trim(input('request.idcard')) != '') {
  727. // $where['m2.idcard'] = ['like', '%' . input('request.idcard') . '%'];
  728. $where['m2.idcard'] = trim(input('request.idcard'));
  729. }
  730. //查询参数
  731. $param = input('get.');
  732. $list = $MembersTwoModel->table('cy_memberstwo m2')->field('m2.username,m2.realname,m2.idcard,m2.userid as uid, cg.name as cg_name')
  733. // ->where('m2.userid = m.id and (realname != "") AND (realname != -1) AND (realname IS NOT NULL) AND (idcard != "") AND (idcard != -1) AND (idcard IS NOT NULL)')
  734. // ->where('m2.userid = m.id and (m2.realname>"-1" AND m2.idcard>"-1")')
  735. ->join('cy_members cm', 'm2.userid = cm.id','left')
  736. ->join('cy_game cg', 'cm.gameid = cg.id','left')
  737. ->where('m2.realname>"-1" AND m2.idcard>"-1"')
  738. ->where($where)->order('m2.id desc')
  739. ->paginate(20, false, array('query' => $param));
  740. $this->assign('list', $list);
  741. $this->assign('page', $list->render());
  742. return $this->fetch('identity_list');
  743. }
  744. /**
  745. * 绑定信息管理
  746. */
  747. public function bindList()
  748. {
  749. $where = $this->_getBindCondition();
  750. if(!empty($where)){
  751. //查询参数
  752. $param = input('get.');
  753. /*
  754. $list = $this->membersModel->field('SQL_CALC_FOUND_ROWS id,username,mobile,email,total_pay_amount,gameid')
  755. ->where('(mobile != "" AND mobile IS NOT NULL) OR (email != "" AND email IS NOT NULL)')
  756. ->where($where)
  757. ->order('id desc')->paginate(10, true, array('query' => $param));*/
  758. $curpage = input('page') ? input('page') : 1; //当前页码
  759. $list_data = $this->membersModel->field('SQL_CALC_FOUND_ROWS id,username,mobile,email,total_pay_amount,gameid')
  760. // ->where('(mobile != "" AND mobile IS NOT NULL) OR (email != "" AND email IS NOT NULL)')
  761. // ->where('(mobile>"" OR email>"")')
  762. ->where($where)
  763. ->order('id desc')->page($curpage,10)->select();
  764. //总记录数
  765. $total = Db::query("SELECT FOUND_ROWS() as total;");
  766. $list = \think\paginator\driver\Bootstrap::make($list_data,10,$curpage,$total[0]['total'],false,[
  767. 'var_page' => 'page',
  768. 'path' => url('bindList'),//这里根据需要修改url
  769. 'query' => $param,
  770. 'fragment' => '',
  771. ]);
  772. $data = $list->toArray();
  773. $gameid = array_column($data['data'], 'gameid');
  774. $gameid = array_unique($gameid);
  775. $gameList = model('game')->whereIn('id', $gameid)->column('id,name');
  776. $this->assign('list', $list);
  777. $this->assign('gameList', $gameList);
  778. $this->assign('page', $list->render());
  779. }
  780. $game_list = $this->selfGameList;
  781. $this->assign('game_list', $game_list);
  782. return $this->fetch('bind_list');
  783. }
  784. private function _getParams()
  785. {
  786. $where = [];
  787. //开始时间和结束时间不为空时
  788. if (input('request.start_time') != '' && input('request.end_time') != '') {
  789. $where['m.reg_time'] = [
  790. ['>=', strtotime(input('request.start_time'))],
  791. ['<=', strtotime(input('request.end_time') . ' 23:59:59')],
  792. ];
  793. } //开始时间不为空时
  794. elseif (input('request.start_time') != '') {
  795. $where['m.reg_time'] = ['>=', strtotime(input('request.start_time'))];
  796. } //结束时间不为空时
  797. elseif (input('request.end_time') != '') {
  798. $where['m.reg_time'] = ['<=', strtotime(input('request.end_time') . ' 23:59:59')];
  799. }
  800. //渠道名称
  801. if (input('request.channel_name') != '') {
  802. $where['d.name'] = ['like', '%' . input('request.channel_name') . '%'];
  803. }
  804. //用户名
  805. if (input('request.username') != '') {
  806. $where['m.username'] = ['like', '%' . input('request.username') . '%'];
  807. }
  808. //imeil
  809. if (input('request.imeil') != '') {
  810. $where['m.imeil'] = ['=', input('request.imeil')];
  811. }
  812. //游戏名称
  813. if (input('request.gameid') != '') {
  814. $where['g.id'] = ['=', input('request.gameid')];
  815. }
  816. //手机号
  817. if (input('request.mobile') != '') {
  818. $where['mobile'] = ['like', '%' . input('request.mobile') . '%'];
  819. }
  820. //邮箱
  821. if (input('request.email') != '') {
  822. $where['email'] = ['like', '%' . input('request.email') . '%'];
  823. }
  824. return $where;
  825. }
  826. /**
  827. * 绑定信息 查询条件
  828. * @return array
  829. */
  830. protected function _getBindCondition()
  831. {
  832. $where = [];
  833. $mobile = input('request.mobile');
  834. $email = input('request.email');
  835. $username = input('request.username');
  836. $gameid = input('request.gameid');
  837. $type = input('request.type');
  838. $total_pay_amount = input('request.total_pay_amount');
  839. if ($username != '') {
  840. $where['username'] = $username;
  841. }
  842. if ($email != '') {
  843. $where['email'] = $email;
  844. }
  845. if ($mobile != '') {
  846. $where['mobile'] = $mobile;
  847. }
  848. //游戏名称
  849. if ($gameid != '') {
  850. $where['gameid'] = ['=', $gameid];
  851. }
  852. //游戏名称
  853. if ($total_pay_amount != '') {
  854. $where['total_pay_amount'] = [$type, $total_pay_amount];
  855. }
  856. return $where;
  857. }
  858. /**
  859. * 绑定信息 报表下载
  860. */
  861. public function bindListDownload($is_show = ['is_show'=>false])
  862. {
  863. if (request()->isAjax()) {
  864. $where = $this->_getBindCondition();
  865. if($is_show['is_show']){
  866. $type = input('request.type');
  867. $total_pay_amount = input('request.total_pay_amount');
  868. $username = input('request.username', '', 'trim');
  869. $gameid = input('request.gameid', '', 'intval');
  870. if($total_pay_amount){
  871. $LogStr = "充值金额:".$type.$total_pay_amount;
  872. }
  873. else{
  874. $LogStr = "充值金额:";
  875. }
  876. if($gameid){
  877. $game_name = get_game_nickname($gameid);
  878. }
  879. else{
  880. $game_name = "全部游戏";
  881. }
  882. $LogStr .= ",游戏:".$game_name;
  883. $LogStr .= ",玩家账号:".$username;
  884. $this->insertLog($this->current_node,$LogStr,123);
  885. }
  886. $sql = $this->membersModel->field('id,username,mobile,email,total_pay_amount,gameid')
  887. // ->where('(mobile != "" AND mobile IS NOT NULL) OR (email != "" AND email IS NOT NULL)')
  888. ->where('(mobile>"" OR email>"" )')
  889. ->where($where)
  890. ->order('id desc')
  891. ->fetchSql(true)
  892. ->select();
  893. if ((new MakeReportGo())->addTask('memberBindList', $sql, session_id(),$is_show)){
  894. $this->success('报表生成的任务已经提交, 报表生成完成后,会及时通知您,请耐心稍等');
  895. }
  896. $this->error('报表生成任务不可重复提交,如遇到无法导出情况,建议修改查询条件解除当前状态,提交重新生成报表任务!');
  897. } else {
  898. $this->error('非法请求');
  899. }
  900. }
  901. /**
  902. * 修改绑定信息
  903. */
  904. public function updateBind($id)
  905. {
  906. $id = (int)$id;
  907. if (empty($id)) {
  908. $this->error('用户ID不能为空');
  909. }
  910. $memberInfo = $this->membersModel->where(['id' => $id])->find();
  911. if (empty($memberInfo)) $this->error('用户不存在');
  912. if (request()->isPost()) {
  913. $data = [
  914. 'mobile' => input('post.mobile'),
  915. 'email' => input('post.email'),
  916. ];
  917. $result = $this->validate($data, [
  918. ['mobile', 'mobile', '手机号码格式不正确'],
  919. ['email', 'email', '邮箱格式不正确'],
  920. ]);
  921. if (true !== $result) {
  922. $this->error($result);
  923. } else {
  924. $now_time = time();
  925. $data['update_time'] = $now_time;
  926. if ($this->membersModel->update($data, ['id' => $id])) {
  927. if ( $data['mobile'] != $memberInfo['mobile']) {
  928. // 插入玩家历史记录
  929. Db::table('cy_member_history')->insert([
  930. 'userid' => $id,
  931. 'mobile' => $data['mobile'],
  932. 'ip' => request()->ip(),
  933. 'create_time' => $now_time,
  934. 'admin_id' => session('ADMIN_ID')
  935. ]);
  936. }
  937. if ( $data['email'] != $memberInfo['email']) {
  938. // 插入玩家历史记录
  939. Db::table('cy_member_history')->insert([
  940. 'userid' => $id,
  941. 'email' => $data['email'],
  942. 'ip' => request()->ip(),
  943. 'create_time' => $now_time,
  944. 'admin_id' => session('ADMIN_ID')
  945. ]);
  946. }
  947. $msg = "修改玩家:{$memberInfo['username']}的手机号:{$data['mobile']},邮箱:{$data['email']}";
  948. $this->insertLog($this->current_node, $msg, 23);
  949. $this->success('绑定信息修改成功', 'Member/bindList');
  950. } else
  951. $this->error('绑定信息修改失败');
  952. }
  953. }
  954. $this->assign('memberInfo', $memberInfo);
  955. return $this->fetch('update_bind');
  956. }
  957. /**
  958. * 修改密码
  959. */
  960. public function updatePassword($id,$type = 1)
  961. {
  962. $id = (int)$id;
  963. $type = (int)$type;
  964. if (empty($id)) {
  965. $this->error('用户ID不能为空');
  966. }
  967. $memberInfo = $this->membersModel->where(['id' => $id])->find();
  968. if (empty($memberInfo)) $this->error('用户不存在');
  969. if (request()->isPost()) {
  970. $password = input('post.password');
  971. $confirm_password = input('post.confirm_password');
  972. $data = [
  973. 'password' => $password,
  974. 'confirm_password' => $confirm_password,
  975. ];
  976. $result = $this->validate($data, [
  977. ['password', 'require|length:6,15', '请输入密码|密码长度为 6 - 15'],
  978. ['confirm_password', 'require|length:6,15', '请输入确认密码|密码长度为 6 - 15'],
  979. ]);
  980. if (true !== $result) {
  981. $this->error($result);
  982. } elseif ($password != $confirm_password) {
  983. $this->error('密码不一致');
  984. } else {
  985. $now_time = time();
  986. unset($data['confirm_password']);
  987. $data['password'] = auth_code($password, "ENCODE", Env::get('auth_key'));
  988. $data['update_time'] = $now_time;
  989. if ($this->membersModel->update($data, ['id' => $id])) {
  990. // 插入玩家历史记录
  991. Db::table('cy_member_history')->insert([
  992. 'userid' => $id,
  993. 'password' => $data['password'],
  994. 'ip' => request()->ip(),
  995. 'create_time' => $now_time,
  996. 'admin_id' => session('ADMIN_ID')
  997. ]);
  998. $msg = "修改玩家:{$memberInfo['username']}的密码";
  999. $this->insertLog($this->current_node, $msg, 21);
  1000. // $memberLogic = new MemberLogic;
  1001. //
  1002. // $memberLogic->syncMember($memberInfo['username'], $password, $memberInfo['mobile'], $now_time);
  1003. if ($type == 1) {
  1004. $this->success('密码修改成功', 'Member/index');
  1005. }else{
  1006. $this->success('密码修改成功', 'Member/information');
  1007. }
  1008. } else
  1009. $this->error('密码修改失败');
  1010. }
  1011. }
  1012. $this->assign('memberInfo', $memberInfo);
  1013. return $this->fetch('update_password');
  1014. }
  1015. /**
  1016. * 游戏-账号-角色 查询
  1017. */
  1018. public function query()
  1019. {
  1020. $condition = [];
  1021. if (!empty(input('gh_status'))) { // 是否聚合用户:0=否、1=是
  1022. $condition['channel.gh_status'] = 1;
  1023. // TODO: 设置抓取频率为一分钟10次。
  1024. $redis = Cache::init()->handler();
  1025. $cache_keys = 'member_query:' . getUserIp();
  1026. $num = $redis->get($cache_keys);
  1027. if (!$num) {
  1028. $num = 1;
  1029. $redis->setex($cache_keys, 60, 1);
  1030. } else {
  1031. $num = $num + 1;
  1032. $redis->Incrby($cache_keys, 1);
  1033. }
  1034. if ($num > 10) {
  1035. return "访问次数受限,一分钟内请求为十次:" . $num;
  1036. }
  1037. }
  1038. $gameId = input('game_id', 0, 'intval');
  1039. $username = input('username', '', 'trim');
  1040. $rolename = input('rolename', '', 'trim');
  1041. $start_time = input('start_time', '', 'trim');
  1042. $end_time = input('end_time', '', 'trim');
  1043. $page_size = input('page_size', 15);
  1044. !empty($gameId) && $condition['info.gameid'] = $gameId;
  1045. // !empty($username) && $condition['user.username'] = ['LIKE', '%' . $username . '%'];
  1046. if (!empty($username)) {
  1047. $userIds = Db::table('cy_members')->where('username', $username)->column('id');
  1048. $condition['info.userid'] = ['in', $userIds];
  1049. }
  1050. !empty($rolename) && $condition['rolename'] = $rolename;
  1051. // 推广数据
  1052. $business_type = input('business_type', '');
  1053. $president_type = input('president_type', '');
  1054. $president_type_son = input('president_type_son', '');
  1055. $promoter_type = input('promoter_type', '');
  1056. if ($business_type <> '') {
  1057. $condition['info.channel_id'] = ['in', get_child_channel_arr($business_type)];
  1058. }
  1059. if ($president_type <> '') {
  1060. $condition['info.channel_id'] = ['in', get_child_channel_arr($president_type)];
  1061. }
  1062. if ($president_type_son <> '') {
  1063. $condition['info.channel_id'] = ['in', get_child_channel_arr($president_type_son)];
  1064. }
  1065. if ($promoter_type <> '') {
  1066. $condition['info.channel_id'] = $promoter_type;
  1067. }
  1068. // 获取查询日期
  1069. if ($start_time && $end_time) {
  1070. $condition['info.create_time'] = ['between time', [strtotime($start_time), strtotime($end_time . ' 23:59:59')]];
  1071. }
  1072. $infoList = Db::table('cy_role_info')->alias('info')
  1073. ->join('nw_channel channel', 'channel.id = info.channel_id')
  1074. ->join('cy_members user', 'user.id = info.userid')
  1075. ->join('cy_game game', 'game.id = info.gameid')
  1076. ->join('nw_subaccount sub', 'info.userid = sub.member_id AND info.gameid = sub.game_id')
  1077. ->field(['info.id', 'game.name as game_name', 'user.username', 'info.serverid', 'info.servername', 'info.roleid', 'info.rolename', 'info.create_time', 'info.update_time', 'sub.channel_id', 'info.userid', 'info.rolelevel'])
  1078. ->where($condition)
  1079. ->order('update_time desc')
  1080. ->group('info.roleid')
  1081. ->paginate($page_size, 5000, ['query' => input('get.')])
  1082. ->each(function ($item, $key) {
  1083. $channel_list = get_channel_top_by_aggregate($item['channel_id']);
  1084. $item['channel_zero_name'] = !empty($channel_list['0']['name']) ? $channel_list['0']['name'] : '';
  1085. $item['channel_one_name'] = !empty($channel_list['1']['name']) ? $channel_list['1']['name'] : '';
  1086. $item['channel_two_name'] = !empty($channel_list['2']['name']) ? $channel_list['2']['name'] : '';
  1087. $item['channel_three_name'] = !empty($channel_list['3']['name']) ? $channel_list['3']['name'] : '';
  1088. return $item;
  1089. });
  1090. $this->assign('list', $infoList);
  1091. $this->assign('page', $infoList ? $infoList->render() : '');
  1092. $this->assign('game_list', $this->selfGameList);
  1093. $this->assign('list_count', count($infoList));
  1094. $this->assign('jh_url', url('Member/query', ['gh_status' => 1, 'page_size' => '100'], 'html'));
  1095. return $this->fetch();
  1096. }
  1097. /**
  1098. * 游戏-账号-角色 列表
  1099. */
  1100. public function roleList()
  1101. {
  1102. $infoList = [];
  1103. $action = $this->request->param('action');
  1104. // 获取开始时间和结束时间
  1105. $start_time = $this->request->param('start_time', '');
  1106. $end_time = $this->request->param('end_time', '');
  1107. // 验证日期格式
  1108. if (!empty($start_time) && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $start_time)) {
  1109. $start_time = '';
  1110. }
  1111. if (!empty($end_time) && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $end_time)) {
  1112. $end_time = '';
  1113. }
  1114. // 日期最多选择到今天(包含今天)
  1115. if (!empty($start_time) && $start_time > date('Y-m-d')) {
  1116. $start_time = date('Y-m-d');
  1117. }
  1118. if (!empty($end_time) && $end_time > date('Y-m-d')) {
  1119. $end_time = date('Y-m-d');
  1120. }
  1121. // 开始时间不能大于结束时间
  1122. if (!empty($start_time) && !empty($end_time) && $start_time > $end_time) {
  1123. $start_time = $end_time;
  1124. }
  1125. // 未传时间(首次进入页面或查询时未选时间)时,默认查最近一个月的数据
  1126. if (empty($start_time) && empty($end_time)) {
  1127. $start_time = date('Y-m-d', strtotime('-30 days'));
  1128. $end_time = date('Y-m-d');
  1129. }
  1130. if (0 == strnatcasecmp($action, 'search')) {
  1131. $gameId = $this->request->param('game_id', 0, 'intval');
  1132. $username = $this->request->param('username', '', 'trim');
  1133. $rolename = $this->request->param('rolename', '', 'trim');
  1134. $condition = [];
  1135. if (!empty($gameId)) {
  1136. $condition['game.id'] = $gameId;
  1137. }
  1138. if(!empty($username)){
  1139. $userid = Db::table('cy_members')->where('username', $username)->value('id');
  1140. $condition['info.userid'] = $userid;
  1141. }
  1142. if(!empty($rolename)){
  1143. $condition['info.rolename'] = ['LIKE', "%{$rolename}%"];
  1144. }
  1145. } else {
  1146. $condition = [];
  1147. }
  1148. // 统一处理日期条件
  1149. if ($start_time && $end_time) {
  1150. $condition['info.create_time'] = ['between time', [strtotime($start_time), strtotime($end_time . ' 23:59:59')]];
  1151. } elseif ($start_time) {
  1152. $condition['info.create_time'] = ['>=', strtotime($start_time)];
  1153. } elseif ($end_time) {
  1154. $condition['info.create_time'] = ['<=', strtotime($end_time . ' 23:59:59')];
  1155. }
  1156. $infoList = (new MemberService())->accountQuery($condition); // 账号查询
  1157. // 格式化日期字段
  1158. if ($infoList) {
  1159. $infoList->each(function (&$item) {
  1160. $item['create_time'] = !empty($item['create_time']) ? date('Y-m-d H:i:s', $item['create_time']) : '-';
  1161. return $item;
  1162. });
  1163. }
  1164. $this->assign('list', $infoList);
  1165. $this->assign('page', $infoList ? $infoList->render() : '');
  1166. $this->assign('game_list', $this->selfGameList);
  1167. $this->assign('list_count', count($infoList));
  1168. $this->assign('start_time', $start_time);
  1169. $this->assign('end_time', $end_time);
  1170. return $this->fetch();
  1171. }
  1172. // 账户-批量冻结/解冻
  1173. public function memberFrozenHandle()
  1174. {
  1175. $ids = $this->request->param('ids', '', 'trim');
  1176. $flag = $this->request->param('flag', ''); // 类型:1=冻结, 2=解冻
  1177. $remark = $this->request->param('remark', '');
  1178. if (empty($ids)) {
  1179. $this->error('请先选择账号');
  1180. }
  1181. if (empty($flag)) {
  1182. $this->error('请选择操作类型');
  1183. }
  1184. $flagMsg = '冻结';
  1185. if($flag == 2){
  1186. $flag = 0;
  1187. $flagMsg = '解冻';
  1188. }
  1189. $idArr = explode(',', $ids);
  1190. $forzenList = $this->membersModel->where(['id' => ['IN', $idArr], 'flag' => $flag])->count();
  1191. if($forzenList){
  1192. $this->error('操作有误,存在"已'.$flagMsg.'"账号');
  1193. }
  1194. Db::startTrans();
  1195. try {
  1196. $result = Model('FrozenHistory')->addNewData(1, $idArr, $flag, $remark);
  1197. if(!$result){
  1198. throw new \Exception('更新数据状态失败');
  1199. }
  1200. $result = $this->membersModel->save(['flag' => $flag, 'update_time' => time()], ['id' => ['IN', $idArr]]);
  1201. if ($result <= 0) {
  1202. throw new \Exception('新增记录失败');
  1203. }
  1204. $forzenList = $this->membersModel->where(['id' => ['IN', $idArr]])->column('username');
  1205. if($forzenList){
  1206. $memberNameList = implode(',', $forzenList);
  1207. $info = $flagMsg . "玩家:{$memberNameList}";
  1208. $this->insertLog($this->current_node, $info, 415);
  1209. }
  1210. Db::commit();
  1211. } catch (\Exception $e) {
  1212. Db::rollback();
  1213. $this->error($flagMsg.'失败:'. $e->getMessage());
  1214. }
  1215. $this->success($flagMsg.'成功');
  1216. }
  1217. // 子账户-批量冻结/解冻
  1218. public function subaccountFrozenHandle()
  1219. {
  1220. $ids = $this->request->param('ids', '', 'trim');
  1221. $flag = $this->request->param('flag', ''); // 类型:1=冻结, 2=解冻
  1222. $remark = $this->request->param('remark', '');
  1223. if (empty($ids)) {
  1224. $this->error('请先选择账号');
  1225. }
  1226. if (empty($flag)) {
  1227. $this->error('请选择操作类型');
  1228. }
  1229. $flagMsg = '冻结';
  1230. if($flag == 2){
  1231. $flag = 0;
  1232. $flagMsg = '解冻';
  1233. }
  1234. $idArr = explode(',', $ids);
  1235. $forzenList = Model('Subaccount')->where(['id' => ['IN', $idArr], 'flag' => $flag])->count();
  1236. if($forzenList){
  1237. $this->error('操作有误,存在"已'.$flagMsg.'"账号');
  1238. }
  1239. Db::startTrans();
  1240. try {
  1241. $result = Model('FrozenHistory')->addNewData(2, $idArr, $flag, $remark);
  1242. if(!$result){
  1243. throw new \Exception('更新数据状态失败');
  1244. }
  1245. $result = Model('Subaccount')->save(['flag' => $flag, 'update_time' => time()], ['id' => ['IN', $idArr]]);
  1246. if ($result <= 0) {
  1247. throw new \Exception('新增记录失败');
  1248. }
  1249. $forzenList = Model('Subaccount')->where(['id' => ['IN', $idArr]])->column('sub_username');
  1250. if($forzenList){
  1251. $memberNameList = implode(',', $forzenList);
  1252. $info = $flagMsg . "子账户:{$memberNameList}";
  1253. $this->insertLog($this->current_node, $info, 39);
  1254. }
  1255. Db::commit();
  1256. } catch (\Exception $e) {
  1257. Db::rollback();
  1258. $this->error($flagMsg.'失败:'. $e->getMessage());
  1259. }
  1260. $this->success($flagMsg.'成功');
  1261. }
  1262. // 注册单用户
  1263. public function register()
  1264. {
  1265. if ($this->request->isPost()) {
  1266. $username = strtolower($this->request->param('username', '', 'trim'));
  1267. $password = $this->request->param('password', '', 'trim');
  1268. $channelId = $this->request->param('channel_id', 0, 'intval');
  1269. $gameId = $this->request->param('game_id', 0, 'intval');
  1270. $data = [
  1271. 'username' => $username,
  1272. 'password' => $password,
  1273. 'channel_id' => $channelId,
  1274. 'gameid' => $gameId,
  1275. ];
  1276. $validResult = $this->validate($data, 'admin/Member');
  1277. if (true !== $validResult) {
  1278. $this->error($validResult);
  1279. }
  1280. $channelInfo = model('Channel')->where(["id"=>$channelId])->find();
  1281. if($channelInfo['level'] <> 3){
  1282. $this->error('非推广员渠道,不能进行绑定');
  1283. }
  1284. if($gameId && $channelId){
  1285. //是否禁止注册
  1286. if (isFrozenOption($channelId,$gameId,'register') || isFrozenOption($channelId,$gameId)) {
  1287. $this->error('您所在渠道已被禁止注册此游戏');
  1288. }
  1289. }
  1290. if(!$gameId){
  1291. // 没有选择绑定游戏
  1292. $this->error('请选择绑定游戏');
  1293. }
  1294. if(!$channelId){
  1295. // 没有选择绑定渠道
  1296. $this->error('请选择绑定渠道');
  1297. }
  1298. // 判断该游戏是否处于白名单状态,若是,则判断是否有分包记录,没有的话,禁止注册关联
  1299. if(!empty($gameId)) {
  1300. $game_info = model('game')->where(['id' => $gameId])->find();
  1301. // 处于白名单状态
  1302. if(2 == $game_info['cooperation_status']) {
  1303. $conditions = array();
  1304. $conditions['gameid'] = $gameId;
  1305. $conditions['channel_id'] = $channelId;
  1306. $subPackageCnt = model('SdkGameList')->where($conditions)->count();
  1307. if(!$subPackageCnt){
  1308. $this->error('该游戏处于白名单状态,无法新增');
  1309. }
  1310. }
  1311. }
  1312. $result = (new MemberService())->registerUser($data);
  1313. if (true === $result) {
  1314. $this->success('注册成功');
  1315. } else {
  1316. $this->error($result);
  1317. }
  1318. }
  1319. $channelList = (new Channel)->getAllByCondition('id,name', ['status' => 1, 'flag' => 3, 'level' => 3]);
  1320. // 只能筛选上架和白名单的游戏
  1321. // , 'cooperation_status' =>['in','1,2']
  1322. $gameList = (new Game())->getAllByCondition('id,name', ['isdelete' => 0],'','self');
  1323. $selfGameList = array();
  1324. foreach ($gameList as $game) {
  1325. $selfGameList[ $game['id']] = $game;
  1326. }
  1327. $this->assign('game_list', $selfGameList);
  1328. $this->assign('channel_list', $channelList);
  1329. return $this->fetch();
  1330. }
  1331. // 批量注册
  1332. public function multiRegister()
  1333. {
  1334. $channelId = $this->request->param('channel_id', 0, 'intval');
  1335. $gameId = $this->request->param('game_id', 0, 'intval');
  1336. $file = request()->file('file');
  1337. if (empty($file)) {
  1338. $this->error('请上传txt文件');
  1339. }
  1340. if (empty($channelId)) {
  1341. $this->error('请选择绑定渠道');
  1342. }
  1343. if (empty($gameId)) {
  1344. $this->error('请选择绑定游戏');
  1345. }
  1346. $fileInfo = $file->getInfo();
  1347. if (!empty($file->getError())) {
  1348. $this->error('文件上传失败,' . $file->getError());
  1349. }
  1350. if (empty($fileInfo['name']) || strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION)) !== 'txt') {
  1351. $this->error('请上传txt文件');
  1352. }
  1353. if (!empty($fileInfo['size']) && $fileInfo['size'] > 10240000) {
  1354. $this->error('上传文件大小不能超过10M');
  1355. }
  1356. try {
  1357. if (empty($fileInfo['tmp_name']) || !is_file($fileInfo['tmp_name'])) {
  1358. throw new \Exception('上传临时文件不存在');
  1359. }
  1360. $users = file($fileInfo['tmp_name']);
  1361. if (false === $users) {
  1362. throw new \Exception('读取上传文件失败');
  1363. }
  1364. } catch (\Exception $e) {
  1365. $this->error('批量注册失败,'.$e->getMessage());
  1366. }
  1367. $channelInfo = model('Channel')->where(["id"=>$channelId])->find();
  1368. if($channelInfo['level'] <> 3){
  1369. $this->error('非推广员渠道,不能进行绑定');
  1370. }
  1371. if($gameId && $channelId){
  1372. //是否禁止注册
  1373. if (isFrozenOption($channelId,$gameId,'register') || isFrozenOption($channelId,$gameId)) {
  1374. $this->error('您所在渠道已被禁止注册此游戏');
  1375. }
  1376. }
  1377. // 判断该游戏是否处于白名单状态,若是,则判断是否有分包记录,没有的话,禁止注册关联
  1378. if(!empty($gameId)) {
  1379. $game_info = model('game')->where(['id' => $gameId])->find();
  1380. // 处于白名单状态
  1381. if(2 == $game_info['cooperation_status']) {
  1382. $conditions = array();
  1383. $conditions['gameid'] = $gameId;
  1384. $conditions['channel_id'] = $channelId;
  1385. $subPackageCnt = model('SdkGameList')->where($conditions)->count();
  1386. if(!$subPackageCnt){
  1387. $this->error('该游戏处于白名单状态,无法新增');
  1388. }
  1389. }
  1390. }
  1391. $memberService = new MemberService();
  1392. $checkResult = $memberService->checkContent($users); // 重新检测内容
  1393. if (true !== $checkResult) {
  1394. $this->error($checkResult);
  1395. }
  1396. $result = [];
  1397. foreach ($users as $user) {
  1398. list($username, $password) = explode(':', trim($user));
  1399. $data = [
  1400. 'username' => strtolower(trim($username)),
  1401. 'password' => trim($password),
  1402. 'channel_id' => $channelId,
  1403. 'gameid' => $gameId
  1404. ];
  1405. $validResult = $this->validate($data, 'admin/Member');
  1406. // 注册失败的
  1407. if (true !== $validResult) {
  1408. $result[] = ['username' => $username, 'reason' => $validResult, 'status' => 0];
  1409. } else {
  1410. // 注册用户
  1411. $flag = $memberService->registerUser($data);
  1412. if (true === $flag) {
  1413. $result[] = ['username' => $username, 'reason' => '', 'status' => 1];
  1414. } else {
  1415. $result[] = ['username' => $username, 'reason' => $flag, 'status' => 0];
  1416. }
  1417. }
  1418. }
  1419. $this->success('批量注册提交成功,具体注册结果可查看返回信息', null, $result);
  1420. }
  1421. // 首页 ajax加载渠道,避免渠道太多,页面渲染太慢
  1422. public function ajaxGetChannel()
  1423. {
  1424. $channel_list = model('Common/Channel')->getAllByCondition('id,name',['status' => 1,'flag'=>['in','3,4']]);
  1425. $this->success('', '', $channel_list);
  1426. }
  1427. /**
  1428. * 注册用户管理--账号明文查看操作
  1429. */
  1430. public function indexPassword(){
  1431. $channelId = $this->request->param('id', 0, 'intval');
  1432. if (empty($channelId)){
  1433. $this->result('',0,'参数错误!');
  1434. }
  1435. $userName = $this->membersModel->where(['id'=>$channelId])->value('username');
  1436. // 记录操作日志
  1437. $this->insertLog($this->current_node,'查看账号:'.$userName,25);
  1438. $this->result($userName,1,$userName);
  1439. }
  1440. /**
  1441. * 登录用户列表--账号明文查看操作
  1442. */
  1443. public function loginPassword(){
  1444. $logininfoId = $this->request->param('id', 0, 'intval');
  1445. if (empty($logininfoId)){
  1446. $this->result('',0,'参数错误!');
  1447. }
  1448. $info = Db::table('cy_logininfo')->alias('l')
  1449. ->join('cy_members m', 'l.userid = m.id')
  1450. ->join('cy_game c', 'l.gameid = c.id','left')
  1451. ->field("m.username,c.name")
  1452. ->where(['l.id'=>$logininfoId])
  1453. ->find();
  1454. // 记录操作日志
  1455. $this->insertLog($this->current_node,'查看账号:'.$info['username'].',关联游戏:'.$info['name'],26);
  1456. $this->result($info['username'],1,$info['username']);
  1457. }
  1458. /**
  1459. * 绑定信息管理--明文查看操作
  1460. */
  1461. public function bindPassword(){
  1462. $Id = $this->request->param('id' , 0 , 'intval');
  1463. $file = $this->request->param('file' , '' , 'trim');
  1464. if (empty($Id) || empty($file)){
  1465. $this->result('',0,'参数错误!');
  1466. }
  1467. $file = trim($file);
  1468. if ($file == 'username'){
  1469. $action = '账号';
  1470. }elseif ($file == 'mobile'){
  1471. $action = '手机号';
  1472. }elseif($file == 'email'){
  1473. $action = '邮箱';
  1474. }else{
  1475. $action = '密文';
  1476. }
  1477. if ( $file == 'username') {
  1478. $field = ["a.$file","c.name"];
  1479. }else{
  1480. $field = ["a.$file","c.name","a.username"];
  1481. }
  1482. /*dump($file);*/
  1483. $info = $this->membersModel->alias('a')->join('cy_game c', 'a.gameid = c.id','left')->where(['a.id'=>$Id])->field($field)->find();
  1484. $logStr = '';
  1485. if (empty($info['name'])){
  1486. $logStr = '查看'.$action.':'.$info[$file];
  1487. }else{
  1488. $logStr = '查看'.$action.':'.$info[$file].',关联游戏:'.$info['name'];
  1489. }
  1490. if( $file != 'username') $logStr .= ',关联账号:' .$info['username'];
  1491. // 记录操作日志
  1492. $this->insertLog($this->current_node,$logStr,27);
  1493. $this->result($info[$file],1,$info[$file]);
  1494. }
  1495. /**
  1496. * 实名认证--账号明文查看操作
  1497. */
  1498. public function identityPassword(){
  1499. $Id = $this->request->param('id', 0, 'intval');
  1500. $file = $this->request->param('file' , '' , 'trim');
  1501. if (empty($Id) || empty($file)){
  1502. $this->result('',0,'参数错误!');
  1503. }
  1504. $file = trim($file);
  1505. if ($file == 'username'){
  1506. $action = '账号';
  1507. $info = $this->membersModel->where(['id'=>$Id])->value('username');
  1508. }elseif ($file == 'idcard'){
  1509. $action = '身份证';
  1510. $info = model('MembersTwo')->where(['userid'=>$Id])->value('idcard');
  1511. }else{
  1512. $this->result('',0,'参数错误!');
  1513. }
  1514. // 记录操作日志
  1515. $this->insertLog($this->current_node,'查看'.$action.':'.$info,28);
  1516. $this->result($info,1,$info);
  1517. }
  1518. /**
  1519. * 冻结用户列表--账号明文查看操作
  1520. */
  1521. public function frozenUsername(){
  1522. $id = $this->request->param('userid', 0, 'intval');
  1523. if (empty($id)){
  1524. $this->result('',0,'玩家ID参数错误!');
  1525. }
  1526. $userName = $this->membersModel->where(['id'=>$id])->value('username');
  1527. // 记录操作日志
  1528. $this->insertLog($this->current_node,'查看账号:'.$userName,29);
  1529. $this->result($userName,1);
  1530. }
  1531. /**
  1532. * 用户汇总信息--明文查看操作
  1533. */
  1534. public function infomationPassword(){
  1535. $Id = $this->request->param('id' , 0 , 'intval');
  1536. $file = $this->request->param('file' , '' , 'trim');
  1537. if (empty($Id) || empty($file)){
  1538. $this->result('',0,'参数错误!');
  1539. }
  1540. $file = trim($file);
  1541. if ($file == 'username'){
  1542. $action = '账号';
  1543. $info = $this->membersModel->where(['id'=>$Id])->value('username');
  1544. }elseif ($file == 'idcard'){
  1545. $action = '身份证';
  1546. $info = model('MembersTwo')->where(['userid'=>$Id])->value('idcard');
  1547. }elseif ($file == 'email'){
  1548. $action = '邮箱';
  1549. $info = $this->membersModel->where(['id'=>$Id])->value('email');
  1550. }elseif ($file == 'mobile'){
  1551. $action = '手机号';
  1552. $info = $this->membersModel->where(['id'=>$Id])->value('mobile');
  1553. }else{
  1554. $this->result('',0,'参数错误!');
  1555. }
  1556. // 记录操作日志
  1557. $this->insertLog($this->current_node,'查看'.$action.':'.$info,124);
  1558. $this->result($info,1,$info);
  1559. }
  1560. /**
  1561. * 登录列表下载--无加密
  1562. */
  1563. public function loginDowmExcel(){
  1564. $this->loginlistdownload(['is_show'=>true]);
  1565. }
  1566. /**
  1567. * 注册管理页下载--无加密
  1568. */
  1569. public function registDowmExcel(){
  1570. $this->download(['is_show'=>true]);
  1571. }
  1572. /**
  1573. * 绑定信息页下载--无加密
  1574. */
  1575. public function bindDowmExcel(){
  1576. $this->bindListDownload(['is_show'=>true]);
  1577. }
  1578. /**
  1579. * 用户信息汇总
  1580. */
  1581. public function information()
  1582. {
  1583. $this->informationWhere(2);
  1584. $param = input('get.');
  1585. $list = Db::table('cy_members')->alias('m')
  1586. ->join('nw_channel channel', 'channel.id=m.channel_id', 'left')
  1587. ->join('nw_channel bchild', 'bchild.id=channel.parent_id AND bchild.level = 2', 'left')
  1588. ->field('m.id,m.username,m.nickname,m.channel_id,m.flag,m.gameid,m.reg_time,m.ip,m.imeil,m.total_pay_amount,m.login_time,bchild.name as bchild_name,bchild.parent_id as bcparent_id, m.test_status')
  1589. ->where($this->where)->order('reg_time desc')
  1590. ->paginate(10, false, array('query' => $param));
  1591. /* $list = $this->membersModel
  1592. ->field('id,username,nickname,channel_id,flag,gameid,reg_time,ip,imeil,total_pay_amount,login_time')
  1593. ->where($this->where)->order('reg_time desc')
  1594. ->paginate(10, false, array('query' => $param));*/
  1595. $gameList = $this->selfGameList;
  1596. $gList = $gameList;
  1597. $gameList = array_column($gameList, 'name', 'id');
  1598. $data = $list->toArray()['data'];
  1599. $memberIdArr = array();
  1600. foreach ($data as &$v) {
  1601. $memberIdArr[] = $v['id'];
  1602. $v['top_channel_name'] = get_top_channel($v['channel_id'])['name'];
  1603. $v['dep_name'] = get_channel_name($v['channel_id']);
  1604. $v['union_name'] = get_union_channel($v['channel_id'])['name'];
  1605. // 账号加密
  1606. $v['mdusername'] = stringObfuscation($v['username'],3);
  1607. }
  1608. // 批量查询最近登录IP(查询后绑定方式,性能更好)
  1609. // 这种方式比JOIN子查询更优:1.逻辑清晰 2.只查询当前页用户 3.易于维护和优化 4.避免复杂子查询
  1610. if (!empty($memberIdArr)) {
  1611. // 使用子查询一次性获取当前页每个用户最新登录记录(取最大id)
  1612. $latestLoginSubSql = Db::table('cy_logininfo')
  1613. ->field('userid, MAX(id) as max_id')
  1614. ->where('userid', 'in', $memberIdArr)
  1615. ->group('userid')
  1616. ->buildSql();
  1617. $latestLoginRows = Db::table('cy_logininfo')->alias('l1')
  1618. ->join([$latestLoginSubSql => 'l2'], 'l1.id = l2.max_id')
  1619. ->field('l1.userid, l1.ip')
  1620. ->select();
  1621. // ->toArray();
  1622. $lastLoginIpList = [];
  1623. foreach ($latestLoginRows as $row) {
  1624. $lastLoginIpList[$row['userid']] = $row['ip'];
  1625. }
  1626. // 将最近登录IP绑定到用户数据中
  1627. foreach ($data as &$v) {
  1628. $v['last_login_ip'] = isset($lastLoginIpList[$v['id']]) ? $lastLoginIpList[$v['id']] : '--';
  1629. }
  1630. } else {
  1631. // 如果没有数据,为每个用户设置默认值
  1632. foreach ($data as &$v) {
  1633. $v['last_login_ip'] = '--';
  1634. }
  1635. }
  1636. $this->assign('list', $data);
  1637. $this->assign('total', $list->total()); //总条数
  1638. $this->assign('start_time', $this->start_time);
  1639. $this->assign('end_time', $this->end_time);
  1640. $this->assign('page', $list->render());
  1641. $this->assign('game_list', $gameList);
  1642. $this->assign('glist', $gList);
  1643. $uniom = model('Channel')->where(['level'=>0])->field('id,name')->select();
  1644. $this->assign('uniom', $uniom); //顶级渠道列表
  1645. return $this->fetch();
  1646. }
  1647. /**
  1648. * 更新用户测试状态
  1649. */
  1650. public function updateTestStatus()
  1651. {
  1652. $id = $this->request->param('id', 0, 'intval');
  1653. $test_status = $this->request->param('test_status', 0, 'intval');
  1654. if (empty($id)) {
  1655. $this->error('用户ID不能为空');
  1656. }
  1657. $memberInfo = $this->membersModel->where(['id' => $id])->find();
  1658. if (empty($memberInfo)) {
  1659. $this->error('用户不存在');
  1660. }
  1661. $result = $this->membersModel->where(['id' => $id])->update([
  1662. 'test_status' => $test_status,
  1663. 'update_time' => time(),
  1664. ]);
  1665. if ($result !== false) {
  1666. $statusMsg = $test_status == 1 ? '测试' : '正常';
  1667. $info = "修改玩家:{$memberInfo['username']} 的测试状态为:{$statusMsg}";
  1668. $this->insertLog($this->current_node, $info, 415);
  1669. $this->success('已设置为' . $statusMsg . '状态');
  1670. } else {
  1671. $this->error('操作失败');
  1672. }
  1673. }
  1674. // 用户信息汇总查询条件
  1675. public function informationWhere($isdefault)
  1676. {
  1677. $where = [];
  1678. $id = input('request.id');
  1679. $mobile = input('request.mobile');
  1680. $email = input('request.email');
  1681. $nickname = input('request.nickname');
  1682. $ip = input('request.ip');
  1683. $last_login_ip = input('request.last_login_ip', '', 'trim'); // 最近登录IP
  1684. $idcard = input('request.idcard', '', 'trim'); // 身份证
  1685. $flag = input('request.flag');
  1686. $start_time = input('request.start_time');
  1687. $end_time = input('request.end_time');
  1688. $channel_id = input('request.channel_id');
  1689. $username = input('request.username');
  1690. $gameid = input('request.gameid');
  1691. $top_channel_id = input('request.parent_channel_id');
  1692. $bplus_channel_id = input('bplus_channel_id', 0, 'intval');
  1693. // 获取查询日期
  1694. $where['reg_time'] =$this->getTimeCondition($start_time,$end_time,$isdefault);
  1695. /*
  1696. if ($username == '' && $nickname == '' && $id == ''){
  1697. if(strtotime($this->end_time.' 23:59:59')-strtotime($this->start_time)>31*24*3600)
  1698. {
  1699. $this->error('单次查询日期的最长跨度为31天');
  1700. }
  1701. }
  1702. */
  1703. // 推广四联查询
  1704. $business_type = input('business_type', input('tg_business', '')); // 商务
  1705. $president_type = input('president_type', input('tg_president', '')); // 会长
  1706. $president_type_son = input('president_type_son', input('tg_president_son', '')); // 子会长
  1707. $promoter_type = input('promoter_type', input('tg_promoter', '')); // 推广员
  1708. if ($business_type <> '') {
  1709. $where['m.channel_id'] = ['in', get_child_channel_arr($business_type)];
  1710. }
  1711. if ($president_type <> '') {
  1712. $where['m.channel_id'] = ['in', get_child_channel_arr($president_type)];
  1713. }
  1714. if ($president_type_son <> '') {
  1715. $where['m.channel_id'] = ['in', get_child_channel_arr($president_type_son)];
  1716. }
  1717. if ($promoter_type <> '') {
  1718. $where['m.channel_id'] = $promoter_type;
  1719. }
  1720. //渠道名称
  1721. if ( !empty($channel_id) || !empty($top_channel_id) || !empty($bplus_channel_id)) {
  1722. $where['channel_id'] = $this->getChannelCondition($channel_id,$top_channel_id,$bplus_channel_id);
  1723. }
  1724. //最近登录IP(优先处理,因为可能影响用户ID条件)
  1725. if ($last_login_ip != '') {
  1726. $latestLoginSubSql = Db::table('cy_logininfo')
  1727. ->field('userid, MAX(id) as max_id')
  1728. ->group('userid')
  1729. ->buildSql();
  1730. $matchedUserIds = Db::table('cy_logininfo')->alias('l1')
  1731. ->join([$latestLoginSubSql => 'l2'], 'l1.id = l2.max_id')
  1732. ->where('l1.ip', $last_login_ip)
  1733. ->column('l1.userid');
  1734. if (!empty($matchedUserIds)) {
  1735. $where['m.id'] = ['in', $matchedUserIds];
  1736. } else {
  1737. $where['m.id'] = -1;
  1738. }
  1739. }
  1740. // 身份证查询(支持 cy_memberstwo 与 nw_subaccount)
  1741. if ($idcard != '') {
  1742. $memberIdsFromMembersTwo = Db::table('cy_memberstwo')
  1743. ->where('idcard', $idcard)
  1744. ->column('userid');
  1745. $memberIdsFromSubaccount = Db::table('nw_subaccount')
  1746. ->where('idcard_num', $idcard)
  1747. ->column('member_id');
  1748. $matchedUserIds = array_values(array_unique(array_filter(array_merge(
  1749. $memberIdsFromMembersTwo ?: [],
  1750. $memberIdsFromSubaccount ?: []
  1751. ))));
  1752. if (!empty($matchedUserIds)) {
  1753. if (isset($where['m.id'])) {
  1754. if (is_array($where['m.id']) && isset($where['m.id'][0]) && 'in' === strtolower($where['m.id'][0])) {
  1755. $existingIds = $where['m.id'][1];
  1756. $intersectIds = array_values(array_intersect($existingIds, $matchedUserIds));
  1757. $where['m.id'] = !empty($intersectIds) ? ['in', $intersectIds] : -1;
  1758. } else {
  1759. if (!in_array($where['m.id'], $matchedUserIds)) {
  1760. $where['m.id'] = -1;
  1761. }
  1762. }
  1763. } else {
  1764. $where['m.id'] = ['in', $matchedUserIds];
  1765. }
  1766. } else {
  1767. $where['m.id'] = -1;
  1768. }
  1769. }
  1770. //用户ID(注意:如果同时有最近登录IP搜索,需要合并条件)
  1771. if ($id != '') {
  1772. if (isset($where['m.id']) && is_array($where['m.id']) && $where['m.id'][0] == 'in') {
  1773. // 如果已经有IN条件(来自最近登录IP搜索),需要取交集
  1774. $existingIds = $where['m.id'][1];
  1775. if (in_array($id, $existingIds)) {
  1776. $where['m.id'] = $id;
  1777. } else {
  1778. $where['m.id'] = -1; // 不存在,设置不可能的值
  1779. }
  1780. } else {
  1781. $where['m.id'] = $id;
  1782. }
  1783. }
  1784. //用户昵称
  1785. if ($nickname != '') {
  1786. $where['nickname'] = $nickname;
  1787. }
  1788. //用户名
  1789. if ($username != '') {
  1790. $where['username'] = $username;
  1791. }
  1792. //游戏名称
  1793. if ($gameid != '') {
  1794. $where['gameid'] = ['=', $gameid];
  1795. }
  1796. //手机号
  1797. if ($mobile != '') {
  1798. $where['mobile'] = $mobile;
  1799. }
  1800. //邮箱
  1801. if ($email != '') {
  1802. $where['email'] = $email;
  1803. }
  1804. //注册IP
  1805. if ($ip != '') {
  1806. $where['ip'] = $ip;
  1807. }
  1808. //账号状态
  1809. if ($flag != '') {
  1810. $where['m.flag'] = $flag;
  1811. }
  1812. //是否测试
  1813. $test_status = input('request.test_status', '', 'trim');
  1814. if ($test_status !== '') {
  1815. $where['m.test_status'] = $test_status;
  1816. }
  1817. $this->where = $where;
  1818. }
  1819. /**
  1820. * 获取渠道查询条件
  1821. * @param int $channel_id 渠道ID
  1822. * @param int $top_channel_id 顶级渠道ID
  1823. * @return
  1824. */
  1825. private function getChannelCondition($channel_id,$top_channel_id,$bplus_channel_id=0)
  1826. {
  1827. //联盟/公会/渠道有选择时判断
  1828. if(!empty($channel_id) || !empty($top_channel_id) || !empty($bplus_channel_id)){
  1829. if(!empty($channel_id) && !empty($top_channel_id) && !empty($bplus_channel_id)){
  1830. unset($condition['p.channel_id']);
  1831. $bChannelIds = get_child_channel_arr($top_channel_id);
  1832. array_push($bChannelIds,$top_channel_id);
  1833. $bplusChannelIds = get_child_channel_arr($bplus_channel_id);
  1834. array_push($bplusChannelIds,$bplus_channel_id);
  1835. $channelIds = array_intersect($bChannelIds,$bplusChannelIds,array($channel_id));
  1836. if($channelIds){
  1837. $channel = ['in',$channelIds];
  1838. }
  1839. else{
  1840. $channel = -1;
  1841. }
  1842. } else if(!empty($top_channel_id) && !empty($bplus_channel_id)){
  1843. $bChannelIds = get_child_channel_arr($top_channel_id);
  1844. array_push($bChannelIds,$top_channel_id);
  1845. $bplusChannelIds = get_child_channel_arr($bplus_channel_id);
  1846. array_push($bplusChannelIds,$bplus_channel_id);
  1847. $channelIds = array_intersect($bChannelIds,$bplusChannelIds);
  1848. if($channelIds){
  1849. $channel = ['in',$channelIds];
  1850. }
  1851. else{
  1852. $channel = -1;
  1853. }
  1854. } elseif (!empty($channel_id) && !empty($bplus_channel_id)) {
  1855. $bplusChannelIds = get_child_channel_arr($bplus_channel_id);
  1856. array_push($bplusChannelIds,$bplus_channel_id);
  1857. $channelIds = array_intersect($bplusChannelIds,array($channel_id));
  1858. if($channelIds){
  1859. $channel = ['in',$channelIds];
  1860. }
  1861. else{
  1862. $channel = -1;
  1863. }
  1864. } elseif (!empty($channel_id) && !empty($top_channel_id)) {
  1865. $bChannelIds = get_child_channel_arr($top_channel_id);
  1866. array_push($bChannelIds,$top_channel_id);
  1867. $channelIds = array_intersect($bChannelIds,array($channel_id));
  1868. if($channelIds){
  1869. $channel = ['in',$channelIds];
  1870. }
  1871. else{
  1872. $channel = -1;
  1873. }
  1874. } elseif (!empty($top_channel_id)) {
  1875. $channelIds = get_child_channel_arr($top_channel_id);
  1876. array_push($channelIds,$top_channel_id);
  1877. $channel = ['in',$channelIds];
  1878. } elseif (!empty($bplus_channel_id)) {
  1879. $channelIds = get_child_channel_arr($bplus_channel_id);
  1880. array_push($channelIds,$bplus_channel_id);
  1881. $channel = ['in',$channelIds];
  1882. } elseif (!empty($channel_id)) {
  1883. $channel = (int)$channel_id;
  1884. }
  1885. }
  1886. /*
  1887. if(!empty($channel_id) && !empty($top_channel_id)){
  1888. $channelIds = get_child_channel_arr($top_channel_id);
  1889. array_push($channelIds,$top_channel_id);
  1890. $channel = [
  1891. ['=', (int)$channel_id],
  1892. ['in', $channelIds],
  1893. ];
  1894. }
  1895. elseif (!empty($channel_id)) {
  1896. $top_channel_id = 0; // 如果同时输入渠道名称和顶级渠道,出于性能考虑,只查询渠道名称这个条件
  1897. $channel = (int)$channel_id;
  1898. }
  1899. //顶级渠道存到pay表中 存在渠道改变时候 需要定期刷表的情况后续开发
  1900. elseif (!empty($top_channel_id)) {
  1901. unset($this->where['channel_id']); // 如果同时输入渠道名称和顶级渠道,出于性能考虑,只查询渠道名称这个条件
  1902. $channelIds = get_child_channel_arr($top_channel_id);
  1903. array_push($channelIds,$top_channel_id);
  1904. $channel = ['in',$channelIds];
  1905. }
  1906. */
  1907. return $channel;
  1908. }
  1909. /**
  1910. * 获取日期查询条件
  1911. * @param int $start_time 开始时间
  1912. * @param int $end_time 结束时间
  1913. * @param bool $isdefault 是否默认今天日期
  1914. * @return
  1915. */
  1916. private function getTimeCondition($start_time,$end_time,$isdefault = true)
  1917. {
  1918. $this->start_time = $start_time;
  1919. $this->end_time = $end_time;
  1920. $time = [];
  1921. //开始时间和结束时间不为空时
  1922. if ($start_time != '' && $end_time != '') {
  1923. $time = [
  1924. ['>=', strtotime($start_time)],
  1925. ['<=', strtotime($end_time . ' 23:59:59')],
  1926. ];
  1927. } //开始时间不为空时
  1928. elseif ($start_time != '') {
  1929. $time = ['>=', strtotime($start_time)];
  1930. } //结束时间不为空时
  1931. elseif ($end_time != '') {
  1932. $time = ['<=', strtotime($end_time . ' 23:59:59')];
  1933. } else {
  1934. if($isdefault === 2){
  1935. $this->start_time = $this->end_time = '';
  1936. $time = [
  1937. ['>=', strtotime($this->start_time)],
  1938. ['<=', strtotime($this->end_time . ' 23:59:59')],
  1939. ];
  1940. }else if($isdefault){
  1941. $this->start_time = $this->end_time = date('Y-m-d', time());
  1942. $time = [
  1943. ['>=', strtotime($this->start_time)],
  1944. ['<=', strtotime($this->end_time . ' 23:59:59')],
  1945. ];
  1946. }
  1947. }
  1948. return $time;
  1949. }
  1950. // 获取用户账号详情
  1951. public function userInfo()
  1952. {
  1953. $id = $this->request->param('id', '', 'intval');
  1954. $code = 1;
  1955. // 获取用户信息
  1956. $info = $this->membersModel->where('id',$id)
  1957. ->field('id,username,avatar,mobile,email,nickname,channel_id,flag,gameid,reg_time,ip,imeil,total_pay_amount,login_time')
  1958. ->find();
  1959. if (empty($info)) {
  1960. $code = 0;
  1961. }else{
  1962. $info['username'] = stringObfuscation($info['username'],3);
  1963. $info['top_channel_name'] = get_top_channel($info['channel_id'])['name'] ?: '';
  1964. $info['dep_name'] = get_channel_name($info['channel_id']) ?: '';
  1965. $userPayInfo = model('Pay')->where(['status' => 1, 'userid' => $id])->group('userid')->field(['userid', 'sum(amount) as money','count(id) as paycount'])->find();
  1966. $info['total_pay_amount'] = isset($userPayInfo->money) ? $userPayInfo->money : '';
  1967. $info['flag'] = $info['flag'] ? '冻结':'正常';
  1968. $info['reg_time'] = $info['reg_time'] ? date('Y-m-d H:i:s',$info['reg_time']) : '';
  1969. $info['imeil'] = $info['imeil'] ?: '';
  1970. $info['nickname'] = $info['nickname'] ?: '';
  1971. $info['gamename'] = $info['gameid'] ? model('Game')->getName($info['gameid']) : '';
  1972. $info['mobile'] = $info['mobile'] ? mobileObfuscation($info['mobile']) : '';
  1973. $info['email'] = $info['email'] ? mailObfuscation($info['email']) : '';
  1974. // 获取用户实名认证信息
  1975. $userInfo = (new MembersTwo())->where('userid',$id)->field('realname,idcard,sex,qq,birthday,address,zipcode')->find();
  1976. $info['realname'] = $userInfo['realname'] ?: '';
  1977. $info['idcard'] = $userInfo['idcard'] ? idcardObfuscation($userInfo['idcard']) : '';
  1978. $info['sex'] = $userInfo['sex'] == 1 ? '女': $userInfo['sex'] == 2 ? '男' : '保密';
  1979. $info['birthday'] = $userInfo['birthday'] ?: '';
  1980. $info['address'] = $userInfo['address'] ?: '';
  1981. $info['zipcode'] = $userInfo['zipcode'] ?: '';
  1982. $info['qq'] = $userInfo['qq'] ?: '';
  1983. $info['avatar'] = $info['avatar'] ? STATIC_DOMAIN . $info['avatar'] : '';
  1984. // 获取最后一次登录信息
  1985. $loginInfo = model('Logininfo')->where('userid',$id)->field('imeil,login_time,ip')->order('login_time desc')->find();
  1986. $info['last_imeil'] = $loginInfo['imeil'] ? : '';
  1987. $info['last_ip'] = $loginInfo['ip'] ? : '';
  1988. $info['last_login_time'] = $loginInfo['login_time'] ? date('Y-m-d H:i:s',$loginInfo['login_time']) : '';
  1989. }
  1990. echo json_encode(['code'=>$code,'data'=>$info]);
  1991. }
  1992. /**
  1993. * 用户冻结详情
  1994. */
  1995. public function frozenInfo($ids)
  1996. {
  1997. $param = input('get.');
  1998. $where['user_id'] = (int)$ids;
  1999. $admin_id = input('request.admin_id');
  2000. $flag = input('request.flag');
  2001. $start_time = input('request.start_time');
  2002. $end_time = input('request.end_time');
  2003. // 获取查询日期
  2004. if (!empty($start_time) || !empty($end_time)){
  2005. $where['create_time'] =$this->getTimeCondition($start_time,$end_time,false);
  2006. }
  2007. //操作人
  2008. if ($admin_id != '') {
  2009. $where['admin_id'] = $admin_id;
  2010. }
  2011. //冻结状态
  2012. if ($flag != '') {
  2013. $where['status'] = $flag;
  2014. }
  2015. $list = model('FrozenHistory')
  2016. ->where($where)->order('id desc')
  2017. ->paginate(10, false, array('query' => $param))->each(function($item, $key){
  2018. if ( !$item['admin_id']) {
  2019. $item['admin_name'] = '申诉冻结';
  2020. }else{
  2021. $item['admin_name'] =model('admin')->where('id',$item['admin_id'])->value('username');
  2022. }
  2023. return $item;
  2024. });
  2025. $data = $list->toArray()['data'];
  2026. // 处理冻结备注
  2027. $subIds = array_column($data, 'id');
  2028. $frozenMaxList = Db::table('cy_frozen_history')
  2029. ->field('user_id, MAX(id) as max_id')
  2030. ->where(['user_id' => ['IN', $subIds], 'status' => 1])
  2031. ->group('user_id')
  2032. ->select();
  2033. $maxIds = array_column($frozenMaxList, 'max_id');
  2034. $frozenList = model('FrozenHistory')->where(['id' => ['IN', $maxIds], 'status' => 1])->order('id desc')->group('user_id')->column('user_id,remark');
  2035. foreach ($data as $key => $value) {
  2036. $data[$key]['remark'] = $frozenList[$value['id']] ?? '';
  2037. }
  2038. $list->toArray()['data'] = $data;
  2039. $aList = model('Common/Admin')->field('id,username as name')->where(['type'=> 1 ,'status'=> 1])->order('id')->select();
  2040. $adminList = array_merge([['id'=>0,'name'=>'申诉冻结']] ,$aList);
  2041. $this->assign('list', $list);
  2042. $this->assign('total', $list->total()); //总条数
  2043. $this->assign('start_time', $this->start_time);
  2044. $this->assign('end_time', $this->end_time);
  2045. $this->assign('page', $list->render());
  2046. $this->assign('adminList',$adminList);
  2047. return $this->fetch();
  2048. }
  2049. public function membersHistory($ids)
  2050. {
  2051. $param = input('get.');
  2052. $where['userid'] = (int)$ids;
  2053. $type = input('request.type');
  2054. $start_time = input('request.start_time');
  2055. $end_time = input('request.end_time');
  2056. // 获取查询日期
  2057. $resWhere = $this->getTimeCondition($start_time,$end_time,false);
  2058. if (!empty($resWhere)){
  2059. $where['h.create_time'] = $resWhere;
  2060. }
  2061. //冻结状态
  2062. if ($type != '') {
  2063. if ( $type == 0 ) $where['h.channel'] = ['neq',''];
  2064. if ( $type == 1 ) $where['h.mobile'] = ['neq',''];
  2065. if ( $type == 2 ) $where['h.email'] = ['neq',''];
  2066. if ( $type == 3 ) $where['h.password'] = ['neq',''];
  2067. }
  2068. $list = model('MemberHistory')->alias('h')
  2069. ->join('cy_members m','m.id = h.userid')
  2070. ->field('h.*,m.username')
  2071. ->where($where)->order('id desc')
  2072. ->paginate(10, false, array('query' => $param))->each(function($item, $key){
  2073. if ( !$item['admin_id']) {
  2074. $item['admin_name'] = $item['username'];
  2075. }else{
  2076. $item['admin_name'] =model('admin')->where('id',$item['admin_id'])->value('username');
  2077. }
  2078. if ( $item['password']) {
  2079. $item['type'] = '密码';
  2080. $item['text'] = passwordObfuscation($item['password']);
  2081. }elseif( $item['email']){
  2082. $item['type'] = '邮箱';
  2083. $item['text'] = $item['email'];
  2084. }elseif( $item['mobile']){
  2085. $item['type'] = '手机';
  2086. $item['text'] = $item['mobile'];
  2087. }else{
  2088. $item['type'] = '渠道';
  2089. $item['text'] = $item['channel'];
  2090. }
  2091. return $item;
  2092. });
  2093. $this->assign('list', $list);
  2094. $this->assign('total', $list->total()); //总条数
  2095. $this->assign('start_time', $this->start_time);
  2096. $this->assign('end_time', $this->end_time);
  2097. $this->assign('page', $list->render());
  2098. return $this->fetch();
  2099. }
  2100. /**
  2101. * 用户信息汇总修改密码
  2102. */
  2103. public function updateInformationPassword($id)
  2104. {
  2105. $id = (int)$id;
  2106. if (empty($id)) {
  2107. $this->error('用户ID不能为空');
  2108. }
  2109. $memberInfo = $this->membersModel->where(['id' => $id])->find();
  2110. if (empty($memberInfo)) $this->error('用户不存在');
  2111. if (request()->isPost()) {
  2112. $password = input('post.password');
  2113. $confirm_password = input('post.confirm_password');
  2114. $data = [
  2115. 'password' => $password,
  2116. 'confirm_password' => $confirm_password,
  2117. ];
  2118. $result = $this->validate($data, [
  2119. ['password', 'require|length:6,15', '请输入密码|密码长度为 6 - 15'],
  2120. ['confirm_password', 'require|length:6,15', '请输入确认密码|密码长度为 6 - 15'],
  2121. ]);
  2122. if (true !== $result) {
  2123. $this->error($result);
  2124. } elseif ($password != $confirm_password) {
  2125. $this->error('密码不一致');
  2126. } else {
  2127. $now_time = time();
  2128. unset($data['confirm_password']);
  2129. $data['password'] = auth_code($password, "ENCODE", Env::get('auth_key'));
  2130. $data['update_time'] = $now_time;
  2131. if ($this->membersModel->update($data, ['id' => $id])) {
  2132. // 插入玩家历史记录
  2133. Db::table('cy_member_history')->insert([
  2134. 'userid' => $id,
  2135. 'password' => $data['password'],
  2136. 'ip' => request()->ip(),
  2137. 'create_time' => $now_time,
  2138. 'admin_id' => session('ADMIN_ID')
  2139. ]);
  2140. $msg = "修改玩家:{$memberInfo['username']}的密码";
  2141. $this->insertLog($this->current_node, $msg, 125);
  2142. // $memberLogic = new MemberLogic;
  2143. //
  2144. // $memberLogic->syncMember($memberInfo['username'], $password, $memberInfo['mobile'], $now_time);
  2145. $this->success('密码修改成功', 'Member/information');
  2146. } else
  2147. $this->error('密码修改失败');
  2148. }
  2149. }
  2150. $this->assign('memberInfo', $memberInfo);
  2151. return $this->fetch('update_password');
  2152. }
  2153. /**
  2154. * 用户信息汇总冻结账户
  2155. */
  2156. public function informationFrozen()
  2157. {
  2158. $id = input('id', 0, 'intval');
  2159. $flag = input('flag', 0, 'abs');
  2160. if (empty($id)) {
  2161. $this->error('用户ID不能为空');
  2162. }
  2163. if (!$info = $this->membersModel->field('id,username')->find($id)) {
  2164. $this->error('非法参数');
  2165. }
  2166. if ($flag == 1) $msg = '冻结'; else
  2167. $msg = '解冻';
  2168. if ($this->membersModel->update([
  2169. 'flag' => $flag,
  2170. 'update_time' => time(),
  2171. ], ['id' => $id])) {
  2172. // 插入冻结记录
  2173. $res = model('FrozenHistory')->addData($id,$flag);
  2174. $info = $msg . "玩家:{$info['username']}";
  2175. $this->insertLog($this->current_node, $info, 126);
  2176. $this->success($msg . '账户成功');
  2177. } else {
  2178. $this->error($msg . '账户失败');
  2179. }
  2180. }
  2181. /**
  2182. * 删除用户头像
  2183. */
  2184. public function delAvatar()
  2185. {
  2186. $id = input('id', 0, 'intval');
  2187. if (empty($id)) {
  2188. $this->error('用户ID不能为空');
  2189. }
  2190. if (!$info = $this->membersModel->field('id,username')->find($id)) {
  2191. $this->error('非法参数');
  2192. }
  2193. if ($this->membersModel->update([
  2194. 'avatar' => '',
  2195. 'update_time' => time(),
  2196. ], ['id' => $id])) {
  2197. $info = "删除玩家:{$info['username']}头像";
  2198. $this->insertLog($this->current_node, $info, 127);
  2199. $this->success('删除成功');
  2200. } else {
  2201. $this->error('删除失败');
  2202. }
  2203. }
  2204. // 清空实名
  2205. public function clearRealName(){
  2206. $id = input('id', 0, 'intval');
  2207. if (empty($id)) {
  2208. $this->error('用户ID不能为空');
  2209. }
  2210. $memberInfo = $this->membersModel->where(['id' => $id])->find();
  2211. if (empty($memberInfo)) $this->error('用户不存在');
  2212. if (model('common/MembersTwo')->where(['userid' => $id])->update(['realname' => '', 'idcard' => ''])) {
  2213. $msg = "清空玩家:{$memberInfo['username']}的实名认证";
  2214. $this->insertLog($this->current_node, $msg, 21);
  2215. $this->success('清空成功', 'Member/index');
  2216. } else {
  2217. $this->error('清空失败');
  2218. }
  2219. }
  2220. // 角色管理
  2221. public function getRole()
  2222. {
  2223. $param = input('get.');
  2224. $filters = $this->getRoleFilters();
  2225. $where = $this->getRoleCondition($filters);
  2226. $pageSize = input('page_size', 20, 'intval');
  2227. $pageSize = $pageSize > 0 ? $pageSize : 20;
  2228. $list = $this->getRoleQuery($where)
  2229. ->order('mgs.update_time desc')
  2230. ->paginate($pageSize, false, array('query' => $param))
  2231. ->each(function ($item, $key) {
  2232. $channel_list = get_channel_top_by_aggregate($item['channel_id']);
  2233. $item['channel_zero_name'] = !empty($channel_list['0']['name']) ? $channel_list['0']['name'] : '';
  2234. $item['channel_one_name'] = !empty($channel_list['1']['name']) ? $channel_list['1']['name'] : '';
  2235. $item['channel_two_name'] = !empty($channel_list['2']['name']) ? $channel_list['2']['name'] : '';
  2236. $item['channel_three_name'] = !empty($channel_list['3']['name']) ? $channel_list['3']['name'] : '';
  2237. return $item;
  2238. });
  2239. $this->assign('list', $list);
  2240. $this->assign('total', $list->total()); //总条数
  2241. $this->assign('page', $list->render());
  2242. // 所属游戏
  2243. $gameList = $this->selfGameList;
  2244. $gList = json_encode($gameList);
  2245. $gameList = array_column($gameList, 'name', 'id');
  2246. $this->assign('game_list', $gameList);
  2247. $this->assign('g_list', $gList);
  2248. // 获取区服列表(根据游戏ID筛选,如果选择了游戏)
  2249. $serverList = [];
  2250. if (!empty($filters['game_id'])) {
  2251. $serverList = Db::table('nw_game_server')
  2252. ->where(['game_id' => $filters['game_id'], 'status' => 1])
  2253. ->field('serverid,servername')
  2254. ->order('id desc')
  2255. ->select();
  2256. } else {
  2257. // 如果没有选择游戏,获取所有区服
  2258. $serverList = Db::table('nw_game_server')
  2259. ->where(['status' => 1])
  2260. ->field('serverid,servername')
  2261. ->order('id desc')
  2262. ->select();
  2263. }
  2264. $this->assign('server_list', $serverList);
  2265. $this->assign('selected_serverid', $filters['server_id']);
  2266. $this->assign('startTime', $filters['start_time']);
  2267. $this->assign('endTime', $filters['end_time']);
  2268. // 推广信息
  2269. $uniom = model('Channel')->where(['level' => 0])->field('id,name')->select();
  2270. $this->assign('uniom', $uniom);
  2271. return $this->fetch();
  2272. }
  2273. /**
  2274. * 角色管理导出。
  2275. */
  2276. public function getRoleDownload()
  2277. {
  2278. if (!request()->isAjax()) {
  2279. $this->error('非法请求');
  2280. }
  2281. $filters = $this->getRoleFilters();
  2282. $where = $this->getRoleCondition($filters);
  2283. $sql = $this->getRoleQuery($where, true)
  2284. ->order('mgs.update_time desc')
  2285. ->fetchSql(true)
  2286. ->select();
  2287. if ((new MakeReportGo())->addTask('memberRoleList', $sql, session_id())) {
  2288. $this->success('报表生成的任务已经提交, 报表生成完成后,会及时通知您,请耐心稍等');
  2289. }
  2290. $this->error('报表生成任务提交失败,请稍后重试');
  2291. }
  2292. /**
  2293. * 获取角色管理查询参数。
  2294. */
  2295. private function getRoleFilters()
  2296. {
  2297. $startTime = input('request.start_time', '', 'trim');
  2298. $endTime = input('request.end_time', '', 'trim');
  2299. // 角色表数据量较大,无时间条件时沿用原逻辑默认查询当天。
  2300. if ($startTime === '' && $endTime === '') {
  2301. $startTime = $endTime = date('Y-m-d');
  2302. }
  2303. return [
  2304. 'cooperation_status' => input('request.cooperation_status', 0, 'intval'),
  2305. 'business_type' => input('request.business_type', '', 'trim'),
  2306. 'president_type' => input('request.president_type', '', 'trim'),
  2307. 'president_type_son' => input('request.president_type_son', '', 'trim'),
  2308. 'promoter_type' => input('request.promoter_type', '', 'trim'),
  2309. 'start_time' => $startTime,
  2310. 'end_time' => $endTime,
  2311. 'username' => input('request.username', '', 'trim'),
  2312. 'role_name' => input('request.role_name', '', 'trim'),
  2313. 'role_id' => input('request.roleid', '', 'trim'),
  2314. 'game_id' => input('request.gameid', 0, 'intval'),
  2315. 'server_id' => input('request.serverid', '', 'trim'),
  2316. ];
  2317. }
  2318. /**
  2319. * 组装角色管理查询条件。
  2320. */
  2321. private function getRoleCondition(array $filters)
  2322. {
  2323. $where = [];
  2324. if ($filters['game_id'] > 0) {
  2325. $where['mgs.game_id'] = $filters['game_id'];
  2326. }
  2327. if ($filters['username'] !== '') {
  2328. $userIds = Db::table('cy_members')
  2329. ->where('username', $filters['username'])
  2330. ->column('id');
  2331. $where['mgs.member_id'] = ['in', empty($userIds) ? [0] : $userIds];
  2332. }
  2333. if ($filters['role_name'] !== '') {
  2334. $where['mgs.rolename'] = ['like', '%' . $filters['role_name'] . '%'];
  2335. }
  2336. if ($filters['role_id'] !== '') {
  2337. $where['mgs.roleid'] = $filters['role_id'];
  2338. }
  2339. if ($filters['server_id'] !== '') {
  2340. $where['mgs.serverid'] = $filters['server_id'];
  2341. }
  2342. // 渠道筛选层级越具体,优先级越高。
  2343. if ($filters['business_type'] !== '') {
  2344. $where['mgs.channel_id'] = ['in', get_child_channel_arr($filters['business_type'])];
  2345. }
  2346. if ($filters['president_type'] !== '') {
  2347. $where['mgs.channel_id'] = ['in', get_child_channel_arr($filters['president_type'])];
  2348. }
  2349. if ($filters['president_type_son'] !== '') {
  2350. $where['mgs.channel_id'] = ['in', get_child_channel_arr($filters['president_type_son'])];
  2351. }
  2352. if ($filters['promoter_type'] !== '') {
  2353. $where['mgs.channel_id'] = $filters['promoter_type'];
  2354. }
  2355. if ($filters['start_time'] !== '' && $filters['end_time'] !== '') {
  2356. $where['mgs.create_time'] = ['between time', [
  2357. strtotime($filters['start_time']),
  2358. strtotime($filters['end_time'] . ' 23:59:59'),
  2359. ]];
  2360. } elseif ($filters['start_time'] !== '') {
  2361. $where['mgs.create_time'] = ['>=', strtotime($filters['start_time'])];
  2362. } elseif ($filters['end_time'] !== '') {
  2363. $where['mgs.create_time'] = ['<=', strtotime($filters['end_time'] . ' 23:59:59')];
  2364. }
  2365. if ($filters['cooperation_status'] > 0) {
  2366. $gameCooperationStatus = $filters['cooperation_status'] == 1 ? 1 : 2;
  2367. $gameIds = Model('Game')->getNormalByIds($gameCooperationStatus);
  2368. $where['mgs.game_id'] = ['in', $gameIds];
  2369. }
  2370. return $where;
  2371. }
  2372. /**
  2373. * 创建角色管理列表与导出共用查询。
  2374. */
  2375. private function getRoleQuery(array $where, $forExport = false)
  2376. {
  2377. $field = 'mgs.*,m.username';
  2378. if ($forExport) {
  2379. $field = 'mgs.mgs_id,m.username,mgs.game_id,mgs.roleid AS role_id,'
  2380. . 'mgs.rolename AS role_name,mgs.rolelevel AS role_level,'
  2381. . 'mgs.serverid AS server_id,mgs.servername AS server_name,'
  2382. . 'mgs.channel_id,mgs.create_time,mgs.update_time';
  2383. }
  2384. return Db::table('nw_member_game_server')
  2385. ->alias('mgs')
  2386. ->field($field)
  2387. ->join('cy_members m', 'mgs.member_id=m.id', 'left')
  2388. ->where($where)
  2389. ->group('mgs.game_id,mgs.serverid,mgs.member_id,mgs.roleid');
  2390. }
  2391. /**
  2392. * 根据游戏ID获取区服列表(AJAX接口)
  2393. */
  2394. public function getServerListByGame()
  2395. {
  2396. $gameId = input('game_id', 0, 'intval');
  2397. $serverList = [];
  2398. if (!empty($gameId)) {
  2399. $serverList = Db::table('nw_game_server')
  2400. ->where(['game_id' => $gameId, 'status' => 1])
  2401. ->field('id,serverid,servername')
  2402. ->order('id desc')
  2403. ->select();
  2404. }
  2405. $this->success('', '', $serverList);
  2406. }
  2407. /**
  2408. * 玩家活跃记录
  2409. */
  2410. public function playerActive()
  2411. {
  2412. $filters = $this->getPlayerActiveFilters();
  2413. $where = $this->getPlayerActiveCondition($filters);
  2414. $pageSize = input('page_size', 20, 'intval');
  2415. $pageSize = $pageSize > 0 ? $pageSize : 20;
  2416. $list = $this->getPlayerActiveQuery($where, $filters)
  2417. ->order('a.active_hour desc,a.id desc')
  2418. ->paginate($pageSize, false, ['query' => input('get.')]);
  2419. $this->hydratePlayerActiveList($list);
  2420. $gameList = $this->selfGameList;
  2421. $serverList = [];
  2422. if (!empty($filters['game_id'])) {
  2423. $serverList = Db::table('nw_game_server')
  2424. ->where(['game_id' => $filters['game_id'], 'status' => 1])
  2425. ->field('id,servername')
  2426. ->order('id desc')
  2427. ->select();
  2428. }
  2429. $this->assign('list', $list);
  2430. $this->assign('total', $list->total());
  2431. $this->assign('page', $list->render());
  2432. $this->assign('filters', $filters);
  2433. $this->assign('game_list', $gameList);
  2434. $this->assign('server_list', $serverList);
  2435. // 推广信息,与 getRole 页面保持一致。
  2436. $uniom = model('Channel')->where(['level' => 0])->field('id,name')->select();
  2437. $this->assign('uniom', $uniom);
  2438. return $this->fetch('player_active');
  2439. }
  2440. /**
  2441. * 玩家活跃记录导出
  2442. */
  2443. public function playerActiveDownload()
  2444. {
  2445. if (!request()->isAjax()) {
  2446. $this->error('非法请求');
  2447. }
  2448. $filters = $this->getPlayerActiveFilters();
  2449. $where = $this->getPlayerActiveCondition($filters);
  2450. $sql = $this->getPlayerActiveQuery($where, $filters, true)
  2451. ->order('a.active_hour desc,a.id desc')
  2452. ->fetchSql(true)
  2453. ->select();
  2454. if ((new MakeReportGo())->addTask('playerActiveList', $sql, session_id())) {
  2455. $this->success('报表生成的任务已经提交, 报表生成完成后,会及时通知您,请耐心稍等');
  2456. }
  2457. $this->error('报表生成任务提交失败,请稍后重试');
  2458. }
  2459. /**
  2460. * 获取玩家活跃查询参数
  2461. */
  2462. private function getPlayerActiveFilters()
  2463. {
  2464. $activeStartTime = input('request.active_start_time', '', 'trim');
  2465. $activeEndTime = input('request.active_end_time', '', 'trim');
  2466. // 活跃表数据量会持续增长,无时间条件时默认查询当天。
  2467. if ($activeStartTime === '' && $activeEndTime === '') {
  2468. $activeStartTime = $activeEndTime = date('Y-m-d');
  2469. }
  2470. $filters = [
  2471. 'username' => input('request.username', '', 'trim'),
  2472. 'game_id' => input('request.game_id', 0, 'intval'),
  2473. 'server_id' => input('request.server_id', '', 'trim'),
  2474. 'role_name' => input('request.role_name', '', 'trim'),
  2475. 'role_id' => input('request.role_id', '', 'trim'),
  2476. 'business_type' => input('request.business_type', 0, 'intval'),
  2477. 'president_type' => input('request.president_type', 0, 'intval'),
  2478. 'president_type_son' => input('request.president_type_son', 0, 'intval'),
  2479. 'promoter_type' => input('request.promoter_type', 0, 'intval'),
  2480. 'create_start_time' => input('request.create_start_time', '', 'trim'),
  2481. 'create_end_time' => input('request.create_end_time', '', 'trim'),
  2482. 'active_start_time' => $activeStartTime,
  2483. 'active_end_time' => $activeEndTime,
  2484. 'register_start_time' => input('request.register_start_time', '', 'trim'),
  2485. 'register_end_time' => input('request.register_end_time', '', 'trim'),
  2486. ];
  2487. $this->validatePlayerActiveTimeRanges($filters);
  2488. return $filters;
  2489. }
  2490. /**
  2491. * 校验玩家活跃查询中的时间范围。
  2492. */
  2493. private function validatePlayerActiveTimeRanges(array $filters)
  2494. {
  2495. $ranges = [
  2496. '角色创建时间' => ['create_start_time', 'create_end_time'],
  2497. '账号注册时间' => ['register_start_time', 'register_end_time'],
  2498. '活跃时间' => ['active_start_time', 'active_end_time'],
  2499. ];
  2500. foreach ($ranges as $label => $fields) {
  2501. $startTime = $filters[$fields[0]];
  2502. $endTime = $filters[$fields[1]];
  2503. if ($startTime !== '' && $endTime !== '' && strtotime($startTime) > strtotime($endTime)) {
  2504. $this->error($label . ':开始时间 不能大于 结束时间');
  2505. }
  2506. }
  2507. }
  2508. /**
  2509. * 组装玩家活跃查询条件
  2510. */
  2511. private function getPlayerActiveCondition(array $filters)
  2512. {
  2513. $where = [];
  2514. if ($filters['game_id'] > 0) {
  2515. $where['a.game_id'] = $filters['game_id'];
  2516. }
  2517. if ($filters['server_id'] !== '') {
  2518. $where['a.server_id'] = $filters['server_id'];
  2519. }
  2520. if ($filters['role_name'] !== '') {
  2521. $where['a.role_name'] = ['like', $filters['role_name'] . '%'];
  2522. }
  2523. if ($filters['role_id'] !== '') {
  2524. $where['a.role_id'] = $filters['role_id'];
  2525. }
  2526. $this->appendPlayerActiveTimeCondition(
  2527. $where,
  2528. 'a.active_hour',
  2529. $filters['active_start_time'],
  2530. $filters['active_end_time'],
  2531. false
  2532. );
  2533. $channelCondition = $this->getPlayerActiveChannelCondition($filters);
  2534. if ($channelCondition !== null) {
  2535. $where['a.channel_id'] = $channelCondition;
  2536. }
  2537. return $where;
  2538. }
  2539. /**
  2540. * 添加时间范围条件。角色和账号时间为时间戳,活跃时间为 DATETIME。
  2541. */
  2542. private function appendPlayerActiveTimeCondition(array &$where, $field, $startTime, $endTime, $unixTime = true)
  2543. {
  2544. if ($startTime !== '' && $endTime !== '') {
  2545. $start = $unixTime ? strtotime($startTime) : $startTime . ' 00:00:00';
  2546. $end = $unixTime ? strtotime($endTime . ' 23:59:59') : $endTime . ' 23:59:59';
  2547. $where[$field] = [['>=', $start], ['<=', $end]];
  2548. } elseif ($startTime !== '') {
  2549. $where[$field] = ['>=', $unixTime ? strtotime($startTime) : $startTime . ' 00:00:00'];
  2550. } elseif ($endTime !== '') {
  2551. $where[$field] = ['<=', $unixTime ? strtotime($endTime . ' 23:59:59') : $endTime . ' 23:59:59'];
  2552. }
  2553. }
  2554. /**
  2555. * 获取渠道筛选条件,并继承充值列表对商务账号的数据权限限制。
  2556. */
  2557. private function getPlayerActiveChannelCondition(array $filters)
  2558. {
  2559. $selectedChannelIds = null;
  2560. if ($filters['promoter_type'] > 0) {
  2561. $selectedChannelIds = [$filters['promoter_type']];
  2562. } elseif ($filters['president_type_son'] > 0) {
  2563. $selectedChannelIds = get_child_channel_arr($filters['president_type_son']);
  2564. } elseif ($filters['president_type'] > 0) {
  2565. $selectedChannelIds = get_child_channel_arr($filters['president_type']);
  2566. } elseif ($filters['business_type'] > 0) {
  2567. $selectedChannelIds = get_child_channel_arr($filters['business_type']);
  2568. }
  2569. $allowedChannelIds = null;
  2570. $businessChannelIds = model('common/Business')->getChannelIds(session('ADMIN_ID'));
  2571. if ($businessChannelIds != -1) {
  2572. $allowedChannelIds = [];
  2573. if (is_array($businessChannelIds) && !empty($businessChannelIds) && $businessChannelIds[0] !== '') {
  2574. foreach (array_unique(array_map('intval', $businessChannelIds)) as $businessChannelId) {
  2575. if ($businessChannelId > 0) {
  2576. $allowedChannelIds = array_merge($allowedChannelIds, get_child_channel_arr($businessChannelId));
  2577. }
  2578. }
  2579. }
  2580. $allowedChannelIds = array_values(array_unique(array_map('intval', $allowedChannelIds)));
  2581. }
  2582. if ($selectedChannelIds !== null && $allowedChannelIds !== null) {
  2583. $selectedChannelIds = array_values(array_intersect($selectedChannelIds, $allowedChannelIds));
  2584. } elseif ($selectedChannelIds === null && $allowedChannelIds !== null) {
  2585. $selectedChannelIds = $allowedChannelIds;
  2586. }
  2587. if ($selectedChannelIds === null) {
  2588. return null;
  2589. }
  2590. $selectedChannelIds = array_values(array_unique(array_filter(array_map('intval', $selectedChannelIds))));
  2591. if (empty($selectedChannelIds)) {
  2592. return -1;
  2593. }
  2594. return count($selectedChannelIds) === 1
  2595. ? $selectedChannelIds[0]
  2596. : ['in', $selectedChannelIds];
  2597. }
  2598. /**
  2599. * 玩家活跃查询。普通列表先查活跃表,区服/角色创建时间等在分页后批量补全。
  2600. * 导出通过区服表把 a.server_id 转成 serverid,再关联角色表 create_time。
  2601. */
  2602. private function getPlayerActiveQuery(array $where, array $filters, $forExport = false)
  2603. {
  2604. $query = Db::table('cy_player_active_log')->alias('a')
  2605. ->where($where);
  2606. if ($forExport) {
  2607. $latestRoleSql = Db::table('nw_member_game_server')
  2608. ->field('member_id,game_id,serverid,roleid,MAX(create_time) as role_reg_time')
  2609. ->group('member_id,game_id,serverid,roleid')
  2610. ->buildSql();
  2611. $query
  2612. ->join('cy_members m', 'm.id=a.member_id', 'left')
  2613. ->join('cy_game game', 'game.id=a.game_id', 'left')
  2614. ->join(
  2615. 'nw_game_server game_server',
  2616. 'game_server.id=a.server_id AND game_server.game_id=a.game_id',
  2617. 'left'
  2618. )
  2619. ->join(
  2620. [$latestRoleSql => 'role_latest'],
  2621. 'role_latest.member_id=a.member_id'
  2622. . ' AND role_latest.game_id=a.game_id'
  2623. . ' AND role_latest.serverid=game_server.serverid'
  2624. . ' AND role_latest.roleid=CONVERT(a.role_id USING utf8)',
  2625. 'left'
  2626. )
  2627. // 区服名称和渠道层级名称由 Go 根据 server_id、game_id、channel_id 补全。
  2628. ->field('a.id,m.username,game.name as game_name,game_server.servername as server_name,a.role_name,a.role_id,a.active_hour,role_latest.role_reg_time,m.reg_time,a.member_id,a.subaccount_id,a.game_id,a.channel_id,a.server_id');
  2629. } else {
  2630. $query->field('a.*');
  2631. }
  2632. $query = $this->appendPlayerActiveMemberCondition($query, $filters);
  2633. return $this->appendPlayerActiveRoleTimeCondition(
  2634. $query,
  2635. $filters['create_start_time'],
  2636. $filters['create_end_time']
  2637. );
  2638. }
  2639. /**
  2640. * 账号或注册时间有筛选时才访问会员表,避免普通列表每次 JOIN。
  2641. */
  2642. private function appendPlayerActiveMemberCondition($query, array $filters)
  2643. {
  2644. if (
  2645. $filters['username'] === ''
  2646. && $filters['register_start_time'] === ''
  2647. && $filters['register_end_time'] === ''
  2648. ) {
  2649. return $query;
  2650. }
  2651. return $query->whereExists(function ($memberQuery) use ($filters) {
  2652. $memberQuery->table('cy_members')
  2653. ->alias('member_filter')
  2654. ->field('1')
  2655. ->whereExp('member_filter.id', '= a.member_id');
  2656. if ($filters['username'] !== '') {
  2657. $memberQuery->where('member_filter.username', $filters['username']);
  2658. }
  2659. if ($filters['register_start_time'] !== '') {
  2660. $memberQuery->where(
  2661. 'member_filter.reg_time',
  2662. '>=',
  2663. intval(strtotime($filters['register_start_time']))
  2664. );
  2665. }
  2666. if ($filters['register_end_time'] !== '') {
  2667. $memberQuery->where(
  2668. 'member_filter.reg_time',
  2669. '<=',
  2670. intval(strtotime($filters['register_end_time'] . ' 23:59:59'))
  2671. );
  2672. }
  2673. });
  2674. }
  2675. /**
  2676. * 角色创建时间筛选:经区服表对齐后,按角色表 create_time 过滤。
  2677. */
  2678. private function appendPlayerActiveRoleTimeCondition($query, $startTime, $endTime)
  2679. {
  2680. if ($startTime === '' && $endTime === '') {
  2681. return $query;
  2682. }
  2683. $startTs = $startTime !== '' ? intval(strtotime($startTime)) : null;
  2684. $endTs = $endTime !== '' ? intval(strtotime($endTime . ' 23:59:59')) : null;
  2685. return $query->whereExists(function ($roleQuery) use ($startTs, $endTs) {
  2686. $roleQuery->table('nw_member_game_server')
  2687. ->alias('role_filter')
  2688. ->join(
  2689. 'nw_game_server role_server',
  2690. 'role_server.serverid=role_filter.serverid AND role_server.game_id=role_filter.game_id'
  2691. )
  2692. ->field('role_filter.mgs_id')
  2693. ->whereExp('role_filter.member_id', '= a.member_id')
  2694. ->whereExp('role_filter.game_id', '= a.game_id')
  2695. ->whereExp('role_server.id', '= a.server_id')
  2696. ->whereRaw('role_filter.roleid = CONVERT(a.role_id USING utf8)');
  2697. if ($startTs !== null) {
  2698. $roleQuery->where('role_filter.create_time', '>=', $startTs);
  2699. }
  2700. if ($endTs !== null) {
  2701. $roleQuery->where('role_filter.create_time', '<=', $endTs);
  2702. }
  2703. });
  2704. }
  2705. /**
  2706. * 分页完成后批量补全:账号、游戏、区服,再按四元组查角色 create_time。
  2707. */
  2708. private function hydratePlayerActiveList($list)
  2709. {
  2710. $items = $list->getCollection();
  2711. if ($items->isEmpty()) {
  2712. return;
  2713. }
  2714. $memberIds = [];
  2715. $gameIds = [];
  2716. foreach ($items as $item) {
  2717. $memberIds[] = intval($item['member_id']);
  2718. $gameIds[] = intval($item['game_id']);
  2719. }
  2720. $memberIds = array_values(array_unique(array_filter($memberIds)));
  2721. $gameIds = array_values(array_unique(array_filter($gameIds)));
  2722. $memberById = [];
  2723. if (!empty($memberIds)) {
  2724. foreach (Db::table('cy_members')->where('id', 'in', $memberIds)->field('id,username,reg_time')->select() as $member) {
  2725. $memberById[intval($member['id'])] = $member;
  2726. }
  2727. }
  2728. $gameById = [];
  2729. if (!empty($gameIds)) {
  2730. foreach (Db::table('cy_game')->where('id', 'in', $gameIds)->field('id,name')->select() as $game) {
  2731. $gameById[intval($game['id'])] = $game['name'];
  2732. }
  2733. }
  2734. foreach ($items as $key => $item) {
  2735. $row = is_array($item) ? $item : $item->toArray();
  2736. $memberId = intval($row['member_id']);
  2737. $gameId = intval($row['game_id']);
  2738. $serverRef = (string)$row['server_id'];
  2739. $roleId = (string)$row['role_id'];
  2740. $member = $memberById[$memberId] ?? [];
  2741. $server = $this->resolvePlayerActiveServer($gameId, $serverRef);
  2742. $channelList = get_top_second_channel_name_v2($row['channel_id']);
  2743. $row['username'] = $member['username'] ?? '';
  2744. $row['reg_time'] = intval($member['reg_time'] ?? 0);
  2745. $row['game_name'] = $gameById[$gameId] ?? '';
  2746. $row['game_server_id'] = $server['serverid'] ?? '';
  2747. $row['server_name'] = $server['servername'] ?? '';
  2748. $row['role_reg_time'] = $this->getPlayerActiveRoleCreateTime(
  2749. $memberId,
  2750. $row['channel_id'],
  2751. $gameId,
  2752. $server['serverid'] ?? '',
  2753. $roleId
  2754. );
  2755. $row['channel_name'] = $channelList['channel_name'];
  2756. $row['second_channel'] = $channelList['second_name'];
  2757. $row['top_channel'] = $channelList['top_name'];
  2758. $row['union_name'] = $channelList['union_name'];
  2759. $items->offsetSet($key, $row);
  2760. }
  2761. }
  2762. /**
  2763. * 活跃表 server_id 优先按区服主键查;兼容历史数据直接存游戏侧 serverid 的情况。
  2764. */
  2765. private function resolvePlayerActiveServer($gameId, $serverRef)
  2766. {
  2767. $gameId = intval($gameId);
  2768. $serverRef = trim((string)$serverRef);
  2769. if ($gameId <= 0 || $serverRef === '') {
  2770. return [];
  2771. }
  2772. $server = Db::table('nw_game_server')
  2773. ->where('id', intval($serverRef))
  2774. ->where('game_id', $gameId)
  2775. ->field('id,serverid,servername')
  2776. ->find();
  2777. if (!empty($server)) {
  2778. return $server;
  2779. }
  2780. return Db::table('nw_game_server')
  2781. ->where(['game_id' => $gameId, 'serverid' => $serverRef])
  2782. ->field('id,serverid,servername')
  2783. ->find() ?: [];
  2784. }
  2785. /**
  2786. * 按 member_id + channel_id + game_id + serverid + role_id 查询角色创建时间。
  2787. */
  2788. private function getPlayerActiveRoleCreateTime($memberId, $channelId, $gameId, $serverid, $roleId)
  2789. {
  2790. $memberId = intval($memberId);
  2791. $channelId = intval($channelId);
  2792. $gameId = intval($gameId);
  2793. $serverid = trim((string)$serverid);
  2794. $roleId = trim((string)$roleId);
  2795. if ($memberId <= 0 || $gameId <= 0 || $serverid === '' || $roleId === '') {
  2796. return 0;
  2797. }
  2798. $createTime = Db::table('nw_member_game_server')
  2799. ->where([
  2800. 'member_id' => $memberId,
  2801. 'channel_id' => $channelId,
  2802. 'game_id' => $gameId,
  2803. 'serverid' => $serverid,
  2804. 'roleid' => $roleId,
  2805. ])
  2806. ->max('create_time');
  2807. return intval($createTime);
  2808. }
  2809. }