Winner.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. <?php
  2. namespace App\Controllers;
  3. use CodeIgniter\RESTful\ResourceController;
  4. class Winner extends ResourceController
  5. {
  6. //당첨자 리스트
  7. public function winnerlist()
  8. {
  9. $db = \Config\Database::connect();
  10. // POST JSON 파라미터 받기
  11. $request = $this->request->getJSON(true);
  12. if (!isset($request['compId'])) {
  13. return $this->respond([
  14. 'status' => 'fail',
  15. 'message' => 'filter(compId)가 누락되었습니다.'
  16. ], 400);
  17. }
  18. $status = isset($request['status']) ? $request['status'] : null;
  19. $compId = $request['compId'];
  20. // 쿼리 빌더
  21. $builder = $db->table('EVT_LIST');
  22. // compId가 '0-000000'이 아닐 때만 COMP_ID 조건 추가
  23. if ($compId !== '0-000000') {
  24. $builder->where('COMP_ID', $compId);
  25. }
  26. if ($status !== null) {
  27. // status가 넘어오면 해당 값만 검색
  28. $builder->where('status', $status);
  29. }
  30. $lists = $builder->get()->getResultArray();
  31. foreach ($lists as &$row) {
  32. if (isset($row['STARTDATE']) && !empty($row['STARTDATE'])) {
  33. $row['STARTDATE'] = date('Y-m-d', strtotime($row['STARTDATE']));
  34. }
  35. if (isset($row['ENDDATE']) && !empty($row['ENDDATE'])) {
  36. $row['ENDDATE'] = date('Y-m-d', strtotime($row['ENDDATE']));
  37. }
  38. }
  39. // 반환 데이터 가공 (필요시)
  40. $filtered = array_reverse($lists);
  41. return $this->respond($filtered, 200);
  42. }
  43. //이벤트 마감 체크
  44. public function winnerChk()
  45. {
  46. $db = \Config\Database::connect();
  47. $seq = null;
  48. $requestJson = $this->request->getJSON(true);
  49. if (is_array($requestJson) && isset($requestJson['seq'])) {
  50. $seq = $requestJson['seq'];
  51. }
  52. if (empty($seq)) {
  53. return $this->respond(['status' => 'fail', 'message' => '필수 파라미터 누락'], 400);
  54. }
  55. // EVT_ITEM에서 해당 seq 로 아이템과 WIN_QTY 조회
  56. $items = $db->table('EVT_ITEM')
  57. ->select('ITEM_SEQ, WIN_QTY')
  58. ->where('EVT_SEQ', $seq)
  59. ->get()->getResultArray();
  60. // 아이템별 최대 당첨자수 배열 구성
  61. $maxWinners = [];
  62. foreach ($items as $idx => $item) {
  63. $rank = $idx + 1; // 1등부터 시작
  64. $maxWinners[$rank] = (int)$item['WIN_QTY'];
  65. }
  66. // PARTICIPATION_LIST에서 seq로 당첨자 집계 (RANK별 COUNT)
  67. $counts = [];
  68. $results = $db->table('PARTICIPATION_LIST')
  69. ->select('RANK, COUNT(*) as cnt')
  70. ->where('EVT_SEQ', $seq)
  71. ->groupBy('RANK')
  72. ->get()->getResultArray();
  73. foreach ($results as $row) {
  74. $counts[(int)$row['RANK']] = (int)$row['cnt'];
  75. }
  76. // 모든 RANK의 당첨자수가 max와 같거나 크면 "마감"
  77. $isClosed = true;
  78. foreach ($maxWinners as $rank => $qty) {
  79. $curr = isset($counts[$rank]) ? $counts[$rank] : 0;
  80. if ($curr < $qty) {
  81. $isClosed = false;
  82. break;
  83. }
  84. }
  85. if ($isClosed) {
  86. return $this->respond(['status' => 'closed', 'message' => '마감되었습니다'], 200);
  87. } else {
  88. return $this->respond(['status' => 'open', 'message' => '아직 마감 아님'], 200);
  89. }
  90. }
  91. //당첨자 등록 및 랭크 반환
  92. public function winnerReg()
  93. {
  94. $db = \Config\Database::connect();
  95. // 파라미터 추출
  96. $seq = null;
  97. $name = null;
  98. $phone = null;
  99. $request = $this->request->getJSON(true);
  100. if (is_array($request) && isset($request['seq'])) {
  101. $seq = $request['seq'];
  102. $name = $request['name'];
  103. $phone = $request['phone'];
  104. } else {
  105. $seq = $this->request->getPost('seq');
  106. $name = $this->request->getPost('name');
  107. $phone = $this->request->getPost('phone');
  108. }
  109. // 등수별 설정 및 ITEM_NAME 매핑
  110. $rankConfigs = [];
  111. $itemNames = [];
  112. if (!empty($seq)) {
  113. $builder = $db->table('EVT_ITEM');
  114. $builder->select('WIN_RATE, WIN_QTY, ITEM_NAME');
  115. $builder->where('EVT_SEQ', $seq);
  116. $builder->orderBy('ITEM_SEQ', 'ASC');
  117. $rows = $builder->get()->getResultArray();
  118. foreach ($rows as $i => $row) {
  119. $rank = $i + 1; // 1등부터 시작
  120. $rankConfigs[$rank] = [
  121. 'percent' => (int)$row['WIN_RATE'],
  122. 'max' => (int)$row['WIN_QTY']
  123. ];
  124. $itemNames[$rank] = $row['ITEM_NAME'];
  125. }
  126. }
  127. // 등수별 참여자 집계
  128. $builder = $db->table('PARTICIPATION_LIST')
  129. ->select('RANK, COUNT(*) AS cnt')
  130. ->where('EVT_SEQ', $seq)
  131. ->groupBy('RANK');
  132. $result = $builder->get()->getResultArray();
  133. $winnerCounts = [];
  134. foreach ($result as $row) {
  135. $winnerCounts[(int)$row['RANK']] = (int)$row['cnt'];
  136. }
  137. // 가능한 등수 구하기
  138. $availableRanks = [];
  139. $totalPercent = 0;
  140. foreach ($rankConfigs as $rank => $cfg) {
  141. $cnt = isset($winnerCounts[$rank]) ? $winnerCounts[$rank] : 0;
  142. if ($cnt < $cfg['max']) {
  143. $availableRanks[] = [
  144. 'rank' => $rank,
  145. 'percent' => $cfg['percent']
  146. ];
  147. $totalPercent += $cfg['percent'];
  148. }
  149. }
  150. // if (empty($availableRanks)) {
  151. // return $this->respond(['status' => 'fail', 'message' => '모든 등수 당첨자가 마감되었습니다.'], 200);
  152. // }
  153. if (empty($availableRanks)) {
  154. // 등수 마감 상태 => rank 0으로 처리
  155. $selectedRank = 0;
  156. $selectedItemName = "꽝";
  157. $rankIndex = 0;
  158. } else {
  159. // 기존 랜덤 등수 추출
  160. $rand = mt_rand() / mt_getrandmax() * $totalPercent;
  161. foreach ($availableRanks as $cfg) {
  162. if ($rand < $cfg['percent']) {
  163. $selectedRank = $cfg['rank'];
  164. break;
  165. }
  166. $rand -= $cfg['percent'];
  167. }
  168. if (!isset($selectedRank)) {
  169. $selectedRank = $availableRanks[count($availableRanks) - 1]['rank'];
  170. }
  171. $selectedItemName = isset($itemNames[$selectedRank]) ? $itemNames[$selectedRank] : null;
  172. // RANK_INDEX 구하기
  173. $builder = $db->table('PARTICIPATION_LIST');
  174. $builder->selectMax('RANK_INDEX');
  175. $builder->where('EVT_SEQ', $seq);
  176. $builder->where('RANK', $selectedRank);
  177. $rankIndexRow = $builder->get()->getRowArray();
  178. $rankIndex = isset($rankIndexRow['RANK_INDEX']) && $rankIndexRow['RANK_INDEX'] ? ((int)$rankIndexRow['RANK_INDEX']) + 1 : 1;
  179. }
  180. // DB 저장
  181. $insertData = [
  182. 'EVT_SEQ' => $seq,
  183. 'RANK' => $selectedRank,
  184. 'ITEM_NAME' => $selectedItemName,
  185. 'NAME' => $name,
  186. 'PHONE' => $phone,
  187. 'RANK_INDEX' => $rankIndex,
  188. 'PRIVACY_AGREE' => 1,
  189. 'THIRDPARTY_AGREE' => 1
  190. ];
  191. $db->table('PARTICIPATION_LIST')->insert($insertData);
  192. // 응답
  193. return $this->respond([
  194. 'rank' => $selectedRank,
  195. 'item_name' => $selectedItemName,
  196. 'rank_index' => $rankIndex,
  197. 'name' => $name,
  198. 'phone' => $phone,
  199. ], 200);
  200. }
  201. //아이템 리스트
  202. public function itemCount()
  203. {
  204. $db = \Config\Database::connect();
  205. // POST 파라미터 JSON 또는 폼에서 받기 (JSON 우선)
  206. $seq = null;
  207. $request = $this->request->getJSON(true);
  208. if (is_array($request) && isset($request['seq'])) {
  209. $seq = $request['seq'];
  210. } else {
  211. $seq = $this->request->getPost('seq'); // 폼 방식 대비
  212. }
  213. if (empty($seq)) {
  214. return $this->respond(['status' => 'fail', 'message' => 'seq 파라미터가 필요합니다.'], 400);
  215. }
  216. $builder = $db->table('EVT_ITEM');
  217. $builder->select('ITEM_NAME');
  218. $builder->where('EVT_SEQ', $seq);
  219. $query = $builder->get();
  220. $items = [];
  221. foreach ($query->getResultArray() as $row) {
  222. $items[] = $row['ITEM_NAME'];
  223. }
  224. $count = count($items);
  225. return $this->respond([
  226. 'count' => $count,
  227. 'items' => $items
  228. ], 200);
  229. }
  230. //당첨자 상세
  231. public function winnerDetail($seq)
  232. {
  233. $db = \Config\Database::connect();
  234. // 이벤트 + 아이템 목록 조인 조회
  235. $builder = $db->table('EVT_LIST E');
  236. $builder->join('EVT_ITEM I', 'E.SEQ = I.EVT_SEQ', 'left');
  237. $builder->join('PARTICIPATION_LIST P', 'E.SEQ = P.EVT_SEQ', 'left');
  238. $builder->select(
  239. 'E.SEQ, E.TITLE, E.STARTDATE, E.ENDDATE, E.REGDATE, ' .
  240. 'I.ITEM_SEQ, I.ITEM_NAME AS ITEM_ITEM_NAME, I.WIN_QTY, I.WIN_RATE,' .
  241. 'P.PART_SEQ, P.RANK, P.ITEM_NAME AS PART_ITEM_NAME, P.ID, P.NAME, P.PHONE, P.WINNER_DATE, P.RANK_INDEX, P.PRIVACY_AGREE, P.THIRDPARTY_AGREE'
  242. );
  243. $builder->where('E.SEQ', $seq);
  244. $rows = $builder->get()->getResultArray();
  245. if (empty($rows)) {
  246. return $this->respond(['status' => 'fail', 'message' => '해당 이벤트가 없습니다.'], 404);
  247. }
  248. // 이벤트(게시글) 정보와 아이템 배열로 가공하여 응답
  249. $event = [
  250. 'seq' => $rows[0]['SEQ'],
  251. 'title' => $rows[0]['TITLE'],
  252. 'startdate' => date('Y-m-d', strtotime( $rows[0]['STARTDATE'])),
  253. 'enddate' => date('Y-m-d', strtotime( $rows[0]['ENDDATE'])),
  254. 'regdate' =>date('Y-m-d', strtotime( $rows[0]['REGDATE'])),
  255. 'items' => [],
  256. 'participations' => [],
  257. 'participations_cal' => []
  258. ];
  259. // 중복방지용
  260. $itemSeqSet = [];
  261. $partSeqSet = [];
  262. foreach ($rows as $row) {
  263. // 아이템 중복 체크 및 추가
  264. if ($row['ITEM_SEQ'] !== null && !isset($itemSeqSet[$row['ITEM_SEQ']])) {
  265. $event['items'][] = [
  266. 'item_seq' => $row['ITEM_SEQ'],
  267. 'name' => $row['ITEM_ITEM_NAME'], // 반드시! EVT_ITEM 테이블의 컬럼명 별칭
  268. 'qty' => $row['WIN_QTY'],
  269. 'rate' => $row['WIN_RATE']
  270. ];
  271. $itemSeqSet[$row['ITEM_SEQ']] = true;
  272. }
  273. // 참여자 중복 체크 및 추가
  274. if ($row['PART_SEQ'] !== null && !isset($partSeqSet[$row['PART_SEQ']])) {
  275. $event['participations'][] = [
  276. 'part_seq' => $row['PART_SEQ'],
  277. 'rank' => $row['RANK'],
  278. 'item_name' => $row['PART_ITEM_NAME'],
  279. 'id' => $row['ID'],
  280. 'name' => $row['NAME'],
  281. 'phone' => $row['PHONE'],
  282. 'winner_date' => $row['WINNER_DATE'] = date('Y-m-d', strtotime($row['WINNER_DATE'])),
  283. 'rank_index' => $row['RANK_INDEX'],
  284. 'privacy_agree' => $row['PRIVACY_AGREE'],
  285. 'thirdparty_agree' => $row['THIRDPARTY_AGREE']
  286. ];
  287. $partSeqSet[$row['PART_SEQ']] = true;
  288. }
  289. }
  290. // 중복되는 rank에서 part_seq가 가장 낮은 값만 participations_cal에 담기
  291. // 유니크 참여자 배열 만들기
  292. $participations = [];
  293. foreach ($rows as $row) {
  294. if (
  295. !array_key_exists('PART_SEQ', $row) ||
  296. !array_key_exists('RANK', $row) ||
  297. $row['PART_SEQ'] === null ||
  298. $row['RANK'] === null ||
  299. $row['RANK'] == 0
  300. ) {
  301. continue;
  302. }
  303. $participations[$row['PART_SEQ']] = $row;
  304. }
  305. // 등수별 인원수 카운트
  306. $rankCounts = [];
  307. foreach ($participations as $part) {
  308. $rank = $part['RANK'];
  309. if (!isset($rankCounts[$rank])) {
  310. $rankCounts[$rank] = 0;
  311. }
  312. $rankCounts[$rank]++;
  313. }
  314. // 중복 등수에서 part_seq가 가장 낮은 값만 participations_cal에 담기 (참여자 기준)
  315. $rankMinPartSeq = [];
  316. foreach ($participations as $part) {
  317. $rank = $part['RANK'];
  318. $partSeq = $part['PART_SEQ'];
  319. if (!isset($rankMinPartSeq[$rank]) || $partSeq < $rankMinPartSeq[$rank]['part_seq']) {
  320. $rankMinPartSeq[$rank] = [
  321. 'part_seq' => $partSeq,
  322. 'rank' => $part['RANK'],
  323. 'item_name' => $part['PART_ITEM_NAME'],
  324. 'id' => $part['ID'],
  325. 'name' => $part['NAME'],
  326. 'phone' => $part['PHONE'],
  327. 'winner_date' => $part['WINNER_DATE'],
  328. 'rank_index' => $part['RANK_INDEX'],
  329. 'privacy_agree' => $part['PRIVACY_AGREE'],
  330. 'thirdparty_agree' => $part['THIRDPARTY_AGREE'],
  331. 'count' => $rankCounts[$rank]
  332. ];
  333. }
  334. }
  335. $event['participations_cal'] = array_values($rankMinPartSeq);
  336. return $this->respond($event, 200);
  337. }
  338. //참여자 리스트
  339. public function getParticipationByItem()
  340. {
  341. $db = \Config\Database::connect();
  342. $request = $this->request->getJSON(true);
  343. // 파라미터 추출
  344. $seq = isset($request['seq']) ? $request['seq'] : null;
  345. $itemName = isset($request['item_name']) ? $request['item_name'] : null;
  346. if (empty($seq)) {
  347. return $this->respond(['status' => 'fail', 'message' => 'seq는 필수입니다.'], 400);
  348. }
  349. // PARTICIPATION_LIST에서 EVT_SEQ와 ITEM_NAME으로 필터링
  350. $builder = $db->table('PARTICIPATION_LIST');
  351. $builder->where('EVT_SEQ', $seq);
  352. if (!empty($itemName)) {
  353. $builder->where('ITEM_NAME', $itemName);
  354. }
  355. $filterList = $builder->get()->getResultArray();
  356. // 키를 모두 소문자로 변환
  357. $filterListLower = [];
  358. foreach ($filterList as $row) {
  359. $filterListLower[] = array_change_key_case($row, CASE_LOWER);
  360. }
  361. return $this->respond([
  362. 'status' => 'success',
  363. 'list' => $filterListLower
  364. ], 200);
  365. }
  366. // 이벤트 참가 여부 체크
  367. public function matchedUser()
  368. {
  369. $data = $this->request->getJSON(true);
  370. $seq = $data['seq'] ?? null;
  371. $name = $data['name'] ?? null;
  372. $phone = $data['phone'] ?? null;
  373. if (!$seq || !$name || !$phone) {
  374. return $this->fail('필수 값이 누락되었습니다.', 400);
  375. }
  376. $db = \Config\Database::connect();
  377. $builder = $db->table('PARTICIPATION_LIST');
  378. $existing = $builder
  379. ->where('EVT_SEQ', $seq)
  380. ->where('NAME', $name)
  381. ->where('PHONE', $phone)
  382. ->get()
  383. ->getRowArray();
  384. if ($existing) {
  385. // 동일한 사람이 이미 존재할 경우
  386. return $this->respond([
  387. 'result' => 'matched'
  388. ]);
  389. }
  390. $phoneSame = $builder
  391. ->where('EVT_SEQ', $seq)
  392. ->where('NAME !=', $name)
  393. ->where('PHONE', $phone)
  394. ->get()
  395. ->getRowArray();
  396. if ($phoneSame) {
  397. return $this->respond([
  398. 'result' => 'phonesame'
  399. ]);
  400. }
  401. // 일치하는 정보가 없을 때 (필요에 따라 처리)
  402. return $this->respond([
  403. 'result' => 'not_found'
  404. ]);
  405. }
  406. }