2026-02-11 16:17:15 +09:00

389 lines
18 KiB
PHP

@extends('admin.layouts.app')
@section('title', '회원 상세')
@section('page_title', '회원 상세')
@section('page_desc', '회원상태/전화번호 변경/메모/변경이력을 관리합니다.')
@push('head')
<style>
/* members show only */
.lbtn{padding:8px 12px;font-size:13px;border-radius:12px;line-height:1.1;text-decoration:none;display:inline-flex;align-items:center;justify-content:center;gap:6px;
border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.06);color:inherit;cursor:pointer;}
.lbtn:hover{background:rgba(255,255,255,.10);text-decoration:none;}
.lbtn--primary{background:rgba(59,130,246,.88);border-color:rgba(59,130,246,.95);color:#fff;}
.lbtn--primary:hover{background:rgba(59,130,246,.98);}
.lbtn--danger{background:rgba(244,63,94,.88);border-color:rgba(244,63,94,.95);color:#fff;}
.lbtn--danger:hover{background:rgba(244,63,94,.98);}
.lbtn--ghost{background:transparent;}
.lbtn--sm{padding:7px 10px;font-size:12px;border-radius:11px;}
.lbtn--wide{padding:10px 14px;font-weight:800;}
.pill{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:999px;font-size:12px;
border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.06);}
.pill--ok{border-color:rgba(34,197,94,.35);background:rgba(34,197,94,.12);}
.pill--bad{border-color:rgba(244,63,94,.35);background:rgba(244,63,94,.10);}
.pill--warn{border-color:rgba(245,158,11,.35);background:rgba(245,158,11,.12);}
.pill--muted{opacity:.9;}
.mono{padding:4px 8px;border-radius:10px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.10);
font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;}
.kvgrid{display:grid;grid-template-columns:1fr;gap:12px;}
@media (min-width: 980px){ .kvgrid{grid-template-columns:1fr 1fr 1fr;} }
.kv{padding:14px;border-radius:16px;border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.04);}
.kv .k{font-size:12px;opacity:.8;margin-bottom:6px;}
.kv .v{font-weight:900;}
.actions{position:sticky;bottom:10px;z-index:5;margin-top:12px;
display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;align-items:center;
padding:12px;border-radius:16px;border:1px solid rgba(255,255,255,.10);background:rgba(0,0,0,.25);backdrop-filter:blur(10px);}
.actions__right{display:flex;gap:8px;flex-wrap:wrap;align-items:center;}
.memo{border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.04);border-radius:16px;padding:12px;}
.memo__item{padding:10px;border-radius:12px;border:1px solid rgba(255,255,255,.08);background:rgba(255,255,255,.03);}
.memo__meta{font-size:12px;opacity:.8;margin-bottom:6px;display:flex;gap:10px;flex-wrap:wrap;}
.grid2{display:grid;grid-template-columns:1fr;gap:12px;}
@media (min-width: 980px){ .grid2{grid-template-columns:1fr 1fr;} }
.warnbox{border:1px solid rgba(245,158,11,.35);background:rgba(245,158,11,.10);border-radius:16px;padding:12px;}
.warnbox b{font-weight:900;}
/* legacy log list */
.mlog{margin-top:12px; max-height:320px; overflow:auto; padding-right:6px;}
.mlog__item{padding:10px 12px; border:1px solid rgba(255,255,255,.08); background:rgba(255,255,255,.03); border-radius:14px;}
.mlog__item + .mlog__item{margin-top:10px;}
.mlog__meta{display:flex; gap:8px; flex-wrap:wrap; align-items:center;}
.mlog__meta .mono{font-size:12px;}
.mlog__body{margin-top:8px;font-size:13px;line-height:1.6;}
.arrow{opacity:.7; padding:0 6px;}
</style>
@endpush
@section('content')
@php
$no = (int)($member->mem_no ?? 0);
$s3 = (string)($member->stat_3 ?? '1');
$s3Label = $stat3Map[$s3] ?? ('stat_3='.$s3);
$sPill = 'pill--muted';
if ($s3==='1') $sPill='pill--ok';
elseif($s3==='2') $sPill='pill--warn';
elseif($s3==='3') $sPill='pill--bad';
$g = (string)($member->gender ?? 'n');
$n = (string)($member->native ?? 'n');
$gender = $genderMap[$g] ?? '-';
$native = $nativeMap[$n] ?? '-';
$birth = (string)($member->birth ?? '');
$birth = ($birth && $birth !== '0000-00-00') ? $birth : '-';
$dtReg = $member->dt_reg ?? '-';
$dtMod = $member->dt_mod ?? '-';
$dtLogin = $member->dt_login ?? '-';
$failCnt = (int)($member->login_fail_cnt ?? 0);
$rcvE = (string)($member->rcv_email ?? 'n');
$rcvS = (string)($member->rcv_sms ?? 'n');
@endphp
<div class="a-card" style="padding:16px; margin-bottom:16px;">
<div style="display:flex; justify-content:space-between; align-items:flex-start; gap:12px; flex-wrap:wrap;">
<div>
<div style="font-weight:900; font-size:16px;">회원 상세</div>
<div class="a-muted" style="font-size:12px; margin-top:4px;">
#{{ $no }} / <b>{{ $member->name ?? '-' }}</b>
@if(!empty($member->email))
· <span class="mono">{{ $member->email }}</span>
@endif
</div>
</div>
<a class="lbtn lbtn--ghost lbtn--sm"
href="{{ route('admin.members.index', request()->only(['qf','q','stat_3','date_from','date_to','page'])) }}">
목록
</a>
</div>
</div>
{{-- KV --}}
<div class="kvgrid" style="margin-bottom:16px;">
<div class="kv">
<div class="k">회원상태</div>
<div class="v"><span class="pill {{ $sPill }}"> {{ $s3Label }}</span></div>
</div>
<div class="kv">
<div class="k">성명/기본정보</div>
<div class="v">
{{ $member->name ?? '-' }}
<div class="a-muted" style="font-size:12px;margin-top:6px;">
성별: {{ $gender }} · 생년월일: {{ $birth }} · {{ $native }}
</div>
</div>
</div>
<div class="kv">
<div class="k">휴대폰(통신사)</div>
<div class="v">
<span class="mono">{{ $corpLabel ?? '-' }}</span>
<span class="mono">{{ $phoneDisplay ?? '-' }}</span>
</div>
</div>
<div class="kv">
<div class="k">수신동의</div>
<div class="v">
<span class="mono">Email : {{ $rcvE }}</span>
<span class="mono">SMS : {{ $rcvS }}</span>
</div>
</div>
<div class="kv">
<div class="k">로그인 실패횟수</div>
<div class="v">{{ $failCnt }}</div>
</div>
<div class="kv">
<div class="k">최근로그인 일시</div>
<div class="v">{{ $dtLogin }}</div>
</div>
<div class="kv">
<div class="k">가입일시</div>
<div class="v">{{ $dtReg }}</div>
</div>
<div class="kv">
<div class="k">최근정보변경 일시</div>
<div class="v">{{ $dtMod }}</div>
</div>
<div class="kv">
<div class="k">계좌정보</div>
<div class="v">
@if(($bank['has'] ?? false))
<div><span class="mono">{{ $bank['bank_name'] ?? '-' }}</span></div>
<div style="margin-top:6px;"><span class="mono">{{ $bank['account'] ?? '-' }}</span></div>
<div class="a-muted" style="font-size:12px;margin-top:6px;">예금주: <b>{{ $bank['holder'] ?? '-' }}</b></div>
@else
<span class="a-muted">등록안됨</span>
@endif
</div>
</div>
</div>
<div class="grid2" style="margin-bottom:16px;">
{{-- 수정 : stat_3(1~3), 통신사, 전화번호만 --}}
<form id="memberEditForm"
method="POST"
action="{{ route('admin.members.update', ['memNo'=>$no]) }}"
onsubmit="this.querySelector('button[type=submit][data-submit=save]')?.setAttribute('disabled','disabled');">
@csrf
<div class="a-card" style="padding:16px;">
<div style="font-weight:900; margin-bottom:10px;">접근상태/전화번호 변경</div>
<div class="a-field" style="margin-bottom:12px;">
<label class="a-label">회원상태</label>
<select class="a-input" name="stat_3">
@foreach($stat3Map as $k=>$label)
@php $disabled = in_array((string)$k, ['4','5','6'], true) ? 'disabled' : ''; @endphp
<option value="{{ $k }}" {{ (string)old('stat_3', $s3)===(string)$k ? 'selected' : '' }} {{ $disabled }}>
{{ $label }}
</option>
@endforeach
</select>
<div class="a-muted" style="font-size:12px;margin-top:6px;"> 4~6 시스템 상태로 변경 불가</div>
</div>
<div class="a-field" style="margin-bottom:12px;">
<label class="a-label">통신사</label>
<select class="a-input" name="cell_corp">
@php $corpSel = (string)old('cell_corp', $member->cell_corp ?? 'n'); @endphp
@foreach($corpMap as $k=>$label)
<option value="{{ $k }}" {{ $corpSel===(string)$k ? 'selected' : '' }}>{{ $label }}</option>
@endforeach
</select>
</div>
<div class="a-field">
<label class="a-label">전화번호(숫자만)</label>
<input class="a-input" name="cell_phone" value="{{ old('cell_phone', $plainPhone ?? '') }}" placeholder="01000000000">
</div>
<div class="warnbox" style="margin-top:12px;">
<div style="font-weight:900;margin-bottom:6px;">주의사항 : 아래 내용 회원에게 수신 처리해 주시기 바랍니다.</div>
<div style="font-size:13px;line-height:1.7;">
- 이름: <b>홍길동</b> (현재 인증받은 회원성명과 동일해야 )<br>
- 핀포유 가입 이메일: <b>test@test.com</b><br>
- 연락 가능한 전화번호: <b>010-000-0000</b><br><br>
<b>첨부파일</b> (아래 이메일 첨부파일 안내를 확인해주세요.)<br>
1. 신분증 사진<br>
2. 신분증을 들고 있는 본인 사진(비대면 실명확인)<br>
3. 통신사 이용계약증명서 사진(화면캡쳐 이미지 사용불가)
</div>
</div>
<div class="a-muted" style="font-size:12px;margin-top:10px;">
이름/이메일/수신동의/계좌정보는 변경 불가
</div>
</div>
</form>
{{-- 인증/주소 --}}
<div class="a-card" style="padding:16px;">
<div style="font-weight:900; margin-bottom:10px;">인증/주소</div>
<div style="margin-bottom:14px;">
<div style="overflow:auto;">
<table class="a-table" style="width:100%; min-width:520px;">
<thead>
<tr>
<th style="width:120px;">type</th>
<th style="width:90px;">state</th>
<th>date</th>
</tr>
</thead>
<tbody>
@forelse($authRows as $r)
@php $st = (string)($r['auth_state'] ?? 'N'); @endphp
<tr>
<td><span class="mono">{{ $r['auth_type'] ?? '-' }}</span></td>
<td><span class="pill {{ $st==='Y' ? 'pill--ok' : 'pill--muted' }}"> {{ $st }}</span></td>
<td class="a-muted">{{ $r['auth_date'] ?? '-' }}</td>
</tr>
@empty
<tr><td colspan="3" class="a-muted" style="padding:12px;">인증 내역이 없습니다.</td></tr>
@endforelse
</tbody>
</table>
</div>
</div>
<div>
<div class="a-muted" style="font-size:12px;margin-bottom:8px;">주소</div>
<div style="display:grid; gap:10px;">
@forelse($addresses as $a)
<div class="memo__item">
<div class="memo__meta">
<span class="mono">#{{ $a['seq'] ?? '-' }}</span>
<span class="mono">gubun={{ $a['gubun'] ?? '-' }}</span>
<span class="mono">shipping={{ $a['shipping'] ?? '-' }}</span>
<span class="a-muted">{{ $a['date'] ?? '-' }}</span>
</div>
<div style="font-size:13px;">
({{ $a['zipNo'] ?? '' }})
{{ $a['roadAddrPart1'] ?? '' }}
{{ $a['jibunAddr'] ?? '' }}
{{ $a['addrDetail'] ?? '' }}
</div>
</div>
@empty
<div class="a-muted">주소가 없습니다.</div>
@endforelse
</div>
</div>
</div>
</div>
{{-- 관리자 메모 (레거시: when/admin_num/memo) --}}
<div class="a-card" style="padding:16px; margin-bottom:16px;">
<div style="display:flex;justify-content:space-between;align-items:flex-end;gap:12px;flex-wrap:wrap;">
<div><div style="font-weight:900;">관리자 메모</div></div>
<form method="POST" action="{{ route('admin.members.memo.add', ['memNo'=>$no]) }}"
style="display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end;">
@csrf
<input class="a-input" name="memo" placeholder="메모 입력 (최대 1000자)" style="width:360px;max-width:70vw;">
<button class="lbtn lbtn--primary" type="submit">추가</button>
</form>
</div>
<div class="memo" style="margin-top:12px;">
<div style="display:grid; gap:10px;">
@forelse($adminMemo as $it)
@php
$aid = (int)($it['admin_num'] ?? 0);
$am = $aid > 0 ? ($adminMap[$aid] ?? null) : null;
$aEmail = is_array($am) ? trim((string)($am['email'] ?? '')) : '';
$aName = is_array($am) ? trim((string)($am['name'] ?? '')) : '';
$aDisp = trim(($aEmail !== '' ? $aEmail : '-')." / ".($aName !== '' ? $aName : '-'));
@endphp
<div class="memo__item">
<div class="memo__meta">
<span class="mono">{{ $it['when'] ?? '-' }}</span>
<span class="mono">admin : {{ $aDisp }}</span>
</div>
<div style="white-space:pre-wrap; font-size:13px;">{{ $it['memo'] ?? '' }}</div>
</div>
@empty
<div class="a-muted">메모가 없습니다.</div>
@endforelse
</div>
</div>
</div>
{{-- 관리자 변경이력 (레거시: state_log) --}}
<div class="a-card" style="padding:16px; margin-bottom:16px;">
<div style="display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;">
<div style="font-weight:900;">관리자 변경이력</div>
<div class="a-muted" style="font-size:12px;">너무 길면 아래 영역이 스크롤됩니다.</div>
</div>
<div class="mlog">
<div style="display:grid; gap:10px;">
@forelse($modifyLog as $it)
@php
$aid = (int)($it['admin_num'] ?? 0);
$am = $aid > 0 ? ($adminMap[$aid] ?? null) : null;
$aEmail = is_array($am) ? trim((string)($am['email'] ?? '')) : '';
$aName = is_array($am) ? trim((string)($am['name'] ?? '')) : '';
$aDisp = trim(($aEmail !== '' ? $aEmail : '-')." / ".($aName !== '' ? $aName : '-'));
$title = (string)($it['title'] ?? '변경');
$before = (string)($it['before'] ?? '');
$after = (string)($it['after'] ?? '');
@endphp
<div class="mlog__item">
<div class="mlog__meta">
<span class="mono">{{ $it['when'] ?? '-' }}</span>
<span class="mono">admin : {{ $aDisp }}</span>
<span class="mono">{{ $title }}</span>
</div>
<div class="mlog__body">
<b>{{ $before !== '' ? $before : '-' }}</b>
<span class="arrow"></span>
<b>{{ $after !== '' ? $after : '-' }}</b>
</div>
</div>
@empty
<div class="a-muted">변경이력이 없습니다.</div>
@endforelse
</div>
</div>
</div>
{{-- 하단 액션바 --}}
<div class="actions">
<a class="lbtn lbtn--ghost"
href="{{ route('admin.members.index', request()->only(['qf','q','stat_3','date_from','date_to','page'])) }}">
뒤로가기
</a>
<div class="actions__right">
<button class="lbtn lbtn--primary lbtn--wide" form="memberEditForm" type="submit" data-submit="save">
저장
</button>
</div>
</div>
@endsection