feat:영업관리 대시보드 화면 추가
- SalesDashboardController 생성 - 대시보드 뷰 생성 (/sales/salesmanagement/dashboard) - 전체 누적 실적, 기간별 조회, 역할별 수당 상세 섹션 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
68
app/Http/Controllers/Sales/SalesDashboardController.php
Normal file
68
app/Http/Controllers/Sales/SalesDashboardController.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Sales;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* 영업관리 대시보드 컨트롤러
|
||||
*/
|
||||
class SalesDashboardController extends Controller
|
||||
{
|
||||
/**
|
||||
* 대시보드 화면
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
// 기간 설정
|
||||
$period = $request->input('period', 'month'); // month or custom
|
||||
$year = $request->input('year', now()->year);
|
||||
$month = $request->input('month', now()->month);
|
||||
|
||||
// 통계 데이터 (임시 데이터 - 추후 실제 데이터로 교체)
|
||||
$stats = [
|
||||
'total_membership_fee' => 0, // 총 가입비
|
||||
'total_commission' => 0, // 총 수당
|
||||
'commission_rate' => 0, // 지급 승인 완료 비율
|
||||
'total_contracts' => 0, // 전체 건수
|
||||
'pending_membership_approval' => 0, // 가입 승인 대기
|
||||
'pending_payment_approval' => 0, // 지급 승인 대기
|
||||
];
|
||||
|
||||
// 역할별 수당 상세
|
||||
$commissionByRole = [
|
||||
[
|
||||
'name' => '판매자',
|
||||
'rate' => 20,
|
||||
'amount' => 0,
|
||||
'color' => 'green',
|
||||
],
|
||||
[
|
||||
'name' => '관리자',
|
||||
'rate' => 5,
|
||||
'amount' => 0,
|
||||
'color' => 'blue',
|
||||
],
|
||||
[
|
||||
'name' => '매뉴제작 협업수당',
|
||||
'rate' => null, // 별도
|
||||
'amount' => null, // 운영팀 산정
|
||||
'color' => 'red',
|
||||
],
|
||||
];
|
||||
|
||||
// 총 가입비 대비 수당
|
||||
$totalCommissionRatio = 0;
|
||||
|
||||
return view('sales.dashboard.index', compact(
|
||||
'stats',
|
||||
'commissionByRole',
|
||||
'totalCommissionRatio',
|
||||
'period',
|
||||
'year',
|
||||
'month'
|
||||
));
|
||||
}
|
||||
}
|
||||
207
resources/views/sales/dashboard/index.blade.php
Normal file
207
resources/views/sales/dashboard/index.blade.php
Normal file
@@ -0,0 +1,207 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', '영업관리 대시보드')
|
||||
|
||||
@section('content')
|
||||
<div class="space-y-6">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="text-2xl font-bold text-gray-800">영업관리 대시보드</h1>
|
||||
</div>
|
||||
|
||||
<!-- 수당 지급 일정 안내 -->
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-xl p-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="flex-shrink-0 mt-0.5">
|
||||
<svg class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-blue-800">수당 지급 일정 안내</h3>
|
||||
<p class="text-sm text-blue-700 mt-1">* 가입비 수당은 가입비 완료 후 지급됩니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 전체 누적 실적 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-6">
|
||||
<h2 class="text-lg font-bold text-gray-800 mb-4">전체 누적 실적</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
|
||||
<!-- 총 가입비 -->
|
||||
<div class="bg-white border border-gray-200 rounded-xl p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-start justify-between">
|
||||
<span class="text-sm text-gray-500">총 가입비</span>
|
||||
<div class="p-2 bg-gray-100 rounded-lg">
|
||||
<svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-2xl font-bold text-gray-900 mt-2">₩{{ number_format($stats['total_membership_fee']) }}</p>
|
||||
<p class="text-xs text-gray-400 mt-1">전체 누적 가입비</p>
|
||||
</div>
|
||||
|
||||
<!-- 총 수당 -->
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-xl p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-start justify-between">
|
||||
<span class="text-sm text-blue-600">총 수당</span>
|
||||
<div class="p-2 bg-blue-100 rounded-lg">
|
||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-2xl font-bold text-blue-700 mt-2">₩{{ number_format($stats['total_commission']) }}</p>
|
||||
<p class="text-xs text-blue-500 mt-1">지급 승인 완료 기준 ({{ $stats['commission_rate'] }}%)</p>
|
||||
</div>
|
||||
|
||||
<!-- 전체 건수 -->
|
||||
<div class="bg-white border border-gray-200 rounded-xl p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-start justify-between">
|
||||
<span class="text-sm text-gray-500">전체 건수</span>
|
||||
<div class="p-2 bg-gray-100 rounded-lg">
|
||||
<svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-2xl font-bold text-gray-900 mt-2">{{ number_format($stats['total_contracts']) }}건</p>
|
||||
<p class="text-xs text-gray-400 mt-1">전체 계약 건수</p>
|
||||
</div>
|
||||
|
||||
<!-- 가입 승인 대기 -->
|
||||
<div class="bg-white border border-gray-200 rounded-xl p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-start justify-between">
|
||||
<span class="text-sm text-gray-500">가입 승인 대기</span>
|
||||
<div class="p-2 bg-gray-100 rounded-lg">
|
||||
<svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-2xl font-bold text-gray-900 mt-2">{{ number_format($stats['pending_membership_approval']) }}건</p>
|
||||
<p class="text-xs text-gray-400 mt-1">조직 내 가입 승인 대기</p>
|
||||
</div>
|
||||
|
||||
<!-- 지급 승인 대기 -->
|
||||
<div class="bg-white border border-gray-200 rounded-xl p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-start justify-between">
|
||||
<span class="text-sm text-gray-500">지급 승인 대기</span>
|
||||
<div class="p-2 bg-gray-100 rounded-lg">
|
||||
<svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-2xl font-bold text-gray-900 mt-2">{{ number_format($stats['pending_payment_approval']) }}건</p>
|
||||
<p class="text-xs text-gray-400 mt-1">조직 내 지급 승인 대기</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 기간별 조회 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<h2 class="text-lg font-bold text-gray-800">기간별 조회</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="inline-flex rounded-lg border border-gray-200 p-1">
|
||||
<button type="button"
|
||||
class="px-4 py-2 text-sm font-medium rounded-md {{ $period === 'month' ? 'bg-blue-600 text-white' : 'text-gray-600 hover:bg-gray-100' }}"
|
||||
onclick="setPeriod('month')">
|
||||
당월
|
||||
</button>
|
||||
<button type="button"
|
||||
class="px-4 py-2 text-sm font-medium rounded-md {{ $period === 'custom' ? 'bg-blue-600 text-white' : 'text-gray-600 hover:bg-gray-100' }}"
|
||||
onclick="setPeriod('custom')">
|
||||
기간 설정
|
||||
</button>
|
||||
</div>
|
||||
<span class="text-sm text-gray-600">{{ $year }}년 {{ $month }}월</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 역할별 수당 상세 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-6">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||
</svg>
|
||||
<h2 class="text-lg font-bold text-gray-800">역할별 수당 상세</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
||||
@foreach($commissionByRole as $role)
|
||||
<div class="rounded-xl p-4 border
|
||||
@if($role['color'] === 'green') bg-green-50 border-green-200
|
||||
@elseif($role['color'] === 'blue') bg-blue-50 border-blue-200
|
||||
@elseif($role['color'] === 'red') bg-red-50 border-red-200
|
||||
@else bg-gray-50 border-gray-200
|
||||
@endif">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-5 h-5
|
||||
@if($role['color'] === 'green') text-green-600
|
||||
@elseif($role['color'] === 'blue') text-blue-600
|
||||
@elseif($role['color'] === 'red') text-red-600
|
||||
@else text-gray-600
|
||||
@endif" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
<span class="text-sm font-medium
|
||||
@if($role['color'] === 'green') text-green-800
|
||||
@elseif($role['color'] === 'blue') text-blue-800
|
||||
@elseif($role['color'] === 'red') text-red-800
|
||||
@else text-gray-800
|
||||
@endif">{{ $role['name'] }}</span>
|
||||
</div>
|
||||
@if($role['rate'] !== null)
|
||||
<span class="text-sm font-semibold
|
||||
@if($role['color'] === 'green') text-green-600
|
||||
@elseif($role['color'] === 'blue') text-blue-600
|
||||
@else text-gray-600
|
||||
@endif">{{ $role['rate'] }}%</span>
|
||||
@else
|
||||
<span class="px-2 py-0.5 text-xs font-medium bg-red-100 text-red-700 rounded">별도</span>
|
||||
@endif
|
||||
</div>
|
||||
@if($role['amount'] !== null)
|
||||
<p class="text-2xl font-bold
|
||||
@if($role['color'] === 'green') text-green-700
|
||||
@elseif($role['color'] === 'blue') text-blue-700
|
||||
@else text-gray-700
|
||||
@endif">₩{{ number_format($role['amount']) }}</p>
|
||||
@else
|
||||
<p class="text-xl font-bold text-red-600">운영팀 산정</p>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- 총 가입비 대비 수당 -->
|
||||
<div class="bg-gray-50 rounded-xl p-4 border border-gray-200">
|
||||
<div class="flex items-center justify-end gap-4">
|
||||
<div class="text-right">
|
||||
<p class="text-2xl font-bold text-gray-900">₩{{ number_format($totalCommissionRatio) }}</p>
|
||||
<p class="text-sm text-gray-500">총 가입비 대비 수당</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function setPeriod(period) {
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.set('period', period);
|
||||
window.location = url;
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@endsection
|
||||
@@ -788,6 +788,9 @@
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
Route::middleware(['auth', 'hq.member'])->prefix('sales')->name('sales.')->group(function () {
|
||||
// 영업관리 대시보드
|
||||
Route::get('salesmanagement/dashboard', [\App\Http\Controllers\Sales\SalesDashboardController::class, 'index'])->name('salesmanagement.dashboard');
|
||||
|
||||
// 영업 담당자 관리
|
||||
Route::resource('managers', \App\Http\Controllers\Sales\SalesManagerController::class);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user