feat:법인카드 서버 저장 기능 구현
- CorporateCard 모델 추가 - CorporateCardController API 추가 (CRUD) - 라우트 추가 (list, store, update, deactivate, destroy) - React 컴포넌트 API 연동 (fetch 호출) - 로딩 상태 UI 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
182
app/Http/Controllers/Finance/CorporateCardController.php
Normal file
182
app/Http/Controllers/Finance/CorporateCardController.php
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Finance;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Finance\CorporateCard;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class CorporateCardController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 카드 목록 조회
|
||||||
|
*/
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$tenantId = session('selected_tenant_id', 1);
|
||||||
|
|
||||||
|
$cards = CorporateCard::forTenant($tenantId)
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get()
|
||||||
|
->map(function ($card) {
|
||||||
|
return [
|
||||||
|
'id' => $card->id,
|
||||||
|
'cardName' => $card->card_name,
|
||||||
|
'cardCompany' => $card->card_company,
|
||||||
|
'cardNumber' => $card->card_number,
|
||||||
|
'cardType' => $card->card_type,
|
||||||
|
'paymentDay' => $card->payment_day,
|
||||||
|
'creditLimit' => (float) $card->credit_limit,
|
||||||
|
'currentUsage' => (float) $card->current_usage,
|
||||||
|
'cardHolderName' => $card->card_holder_name,
|
||||||
|
'actualUser' => $card->actual_user,
|
||||||
|
'expiryDate' => $card->expiry_date,
|
||||||
|
'cvc' => $card->cvc,
|
||||||
|
'status' => $card->status,
|
||||||
|
'memo' => $card->memo,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'data' => $cards,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 카드 등록
|
||||||
|
*/
|
||||||
|
public function store(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'cardName' => 'required|string|max:100',
|
||||||
|
'cardCompany' => 'required|string|max:50',
|
||||||
|
'cardNumber' => 'required|string|max:30',
|
||||||
|
'cardType' => 'required|in:credit,debit',
|
||||||
|
'cardHolderName' => 'required|string|max:100',
|
||||||
|
'actualUser' => 'required|string|max:100',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$tenantId = session('selected_tenant_id', 1);
|
||||||
|
|
||||||
|
$card = CorporateCard::create([
|
||||||
|
'tenant_id' => $tenantId,
|
||||||
|
'card_name' => $request->input('cardName'),
|
||||||
|
'card_company' => $request->input('cardCompany'),
|
||||||
|
'card_number' => $request->input('cardNumber'),
|
||||||
|
'card_type' => $request->input('cardType'),
|
||||||
|
'payment_day' => $request->input('paymentDay', 15),
|
||||||
|
'credit_limit' => $request->input('creditLimit', 0),
|
||||||
|
'current_usage' => 0,
|
||||||
|
'card_holder_name' => $request->input('cardHolderName'),
|
||||||
|
'actual_user' => $request->input('actualUser'),
|
||||||
|
'expiry_date' => $request->input('expiryDate'),
|
||||||
|
'cvc' => $request->input('cvc'),
|
||||||
|
'status' => $request->input('status', 'active'),
|
||||||
|
'memo' => $request->input('memo'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => '카드가 등록되었습니다.',
|
||||||
|
'data' => [
|
||||||
|
'id' => $card->id,
|
||||||
|
'cardName' => $card->card_name,
|
||||||
|
'cardCompany' => $card->card_company,
|
||||||
|
'cardNumber' => $card->card_number,
|
||||||
|
'cardType' => $card->card_type,
|
||||||
|
'paymentDay' => $card->payment_day,
|
||||||
|
'creditLimit' => (float) $card->credit_limit,
|
||||||
|
'currentUsage' => (float) $card->current_usage,
|
||||||
|
'cardHolderName' => $card->card_holder_name,
|
||||||
|
'actualUser' => $card->actual_user,
|
||||||
|
'expiryDate' => $card->expiry_date,
|
||||||
|
'cvc' => $card->cvc,
|
||||||
|
'status' => $card->status,
|
||||||
|
'memo' => $card->memo,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 카드 수정
|
||||||
|
*/
|
||||||
|
public function update(Request $request, int $id): JsonResponse
|
||||||
|
{
|
||||||
|
$card = CorporateCard::findOrFail($id);
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'cardName' => 'required|string|max:100',
|
||||||
|
'cardCompany' => 'required|string|max:50',
|
||||||
|
'cardNumber' => 'required|string|max:30',
|
||||||
|
'cardType' => 'required|in:credit,debit',
|
||||||
|
'cardHolderName' => 'required|string|max:100',
|
||||||
|
'actualUser' => 'required|string|max:100',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$card->update([
|
||||||
|
'card_name' => $request->input('cardName'),
|
||||||
|
'card_company' => $request->input('cardCompany'),
|
||||||
|
'card_number' => $request->input('cardNumber'),
|
||||||
|
'card_type' => $request->input('cardType'),
|
||||||
|
'payment_day' => $request->input('paymentDay', 15),
|
||||||
|
'credit_limit' => $request->input('creditLimit', 0),
|
||||||
|
'card_holder_name' => $request->input('cardHolderName'),
|
||||||
|
'actual_user' => $request->input('actualUser'),
|
||||||
|
'expiry_date' => $request->input('expiryDate'),
|
||||||
|
'cvc' => $request->input('cvc'),
|
||||||
|
'status' => $request->input('status', 'active'),
|
||||||
|
'memo' => $request->input('memo'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => '카드가 수정되었습니다.',
|
||||||
|
'data' => [
|
||||||
|
'id' => $card->id,
|
||||||
|
'cardName' => $card->card_name,
|
||||||
|
'cardCompany' => $card->card_company,
|
||||||
|
'cardNumber' => $card->card_number,
|
||||||
|
'cardType' => $card->card_type,
|
||||||
|
'paymentDay' => $card->payment_day,
|
||||||
|
'creditLimit' => (float) $card->credit_limit,
|
||||||
|
'currentUsage' => (float) $card->current_usage,
|
||||||
|
'cardHolderName' => $card->card_holder_name,
|
||||||
|
'actualUser' => $card->actual_user,
|
||||||
|
'expiryDate' => $card->expiry_date,
|
||||||
|
'cvc' => $card->cvc,
|
||||||
|
'status' => $card->status,
|
||||||
|
'memo' => $card->memo,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 카드 비활성화
|
||||||
|
*/
|
||||||
|
public function deactivate(int $id): JsonResponse
|
||||||
|
{
|
||||||
|
$card = CorporateCard::findOrFail($id);
|
||||||
|
$card->update(['status' => 'inactive']);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => '카드가 비활성화되었습니다.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 카드 영구삭제
|
||||||
|
*/
|
||||||
|
public function destroy(int $id): JsonResponse
|
||||||
|
{
|
||||||
|
$card = CorporateCard::findOrFail($id);
|
||||||
|
$card->forceDelete();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => '카드가 영구 삭제되었습니다.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Models/Finance/CorporateCard.php
Normal file
52
app/Models/Finance/CorporateCard.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Finance;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class CorporateCard extends Model
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
|
||||||
|
protected $table = 'corporate_cards';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'tenant_id',
|
||||||
|
'card_name',
|
||||||
|
'card_company',
|
||||||
|
'card_number',
|
||||||
|
'card_type',
|
||||||
|
'payment_day',
|
||||||
|
'credit_limit',
|
||||||
|
'current_usage',
|
||||||
|
'card_holder_name',
|
||||||
|
'actual_user',
|
||||||
|
'expiry_date',
|
||||||
|
'cvc',
|
||||||
|
'status',
|
||||||
|
'memo',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'payment_day' => 'integer',
|
||||||
|
'credit_limit' => 'decimal:2',
|
||||||
|
'current_usage' => 'decimal:2',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 활성 카드만 조회
|
||||||
|
*/
|
||||||
|
public function scopeActive($query)
|
||||||
|
{
|
||||||
|
return $query->where('status', 'active');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 테넌트의 카드 조회
|
||||||
|
*/
|
||||||
|
public function scopeForTenant($query, $tenantId)
|
||||||
|
{
|
||||||
|
return $query->where('tenant_id', $tenantId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,8 +51,9 @@
|
|||||||
const Zap = createIcon('zap');
|
const Zap = createIcon('zap');
|
||||||
|
|
||||||
function CorporateCardsManagement() {
|
function CorporateCardsManagement() {
|
||||||
// 카드 목록 데이터 (빈 배열로 시작 - 실제 데이터는 서버 연동 후 로드)
|
// 카드 목록 데이터
|
||||||
const [cards, setCards] = useState([]);
|
const [cards, setCards] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [filterStatus, setFilterStatus] = useState('all');
|
const [filterStatus, setFilterStatus] = useState('all');
|
||||||
@@ -60,6 +61,9 @@ function CorporateCardsManagement() {
|
|||||||
const [modalMode, setModalMode] = useState('add'); // 'add' or 'edit'
|
const [modalMode, setModalMode] = useState('add'); // 'add' or 'edit'
|
||||||
const [editingCard, setEditingCard] = useState(null);
|
const [editingCard, setEditingCard] = useState(null);
|
||||||
|
|
||||||
|
// CSRF 토큰
|
||||||
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
||||||
|
|
||||||
// 새 카드 폼 초기값
|
// 새 카드 폼 초기값
|
||||||
const initialFormState = {
|
const initialFormState = {
|
||||||
cardName: '',
|
cardName: '',
|
||||||
@@ -77,8 +81,28 @@ function CorporateCardsManagement() {
|
|||||||
};
|
};
|
||||||
const [formData, setFormData] = useState(initialFormState);
|
const [formData, setFormData] = useState(initialFormState);
|
||||||
|
|
||||||
|
// 초기 데이터 로드
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCards();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const fetchCards = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const response = await fetch('/finance/corporate-cards/list');
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
setCards(result.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('카드 목록 로드 실패:', error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 테스트용 임시 데이터 생성
|
// 테스트용 임시 데이터 생성
|
||||||
const generateTestData = () => {
|
const generateTestData = async () => {
|
||||||
const companies = ['삼성카드', '현대카드', '국민카드', '신한카드', '롯데카드'];
|
const companies = ['삼성카드', '현대카드', '국민카드', '신한카드', '롯데카드'];
|
||||||
const names = ['업무용', '마케팅', '개발팀', '영업팀', '관리팀'];
|
const names = ['업무용', '마케팅', '개발팀', '영업팀', '관리팀'];
|
||||||
const users = ['김철수', '이영희', '박민수', '최지영', '정대한'];
|
const users = ['김철수', '이영희', '박민수', '최지영', '정대한'];
|
||||||
@@ -87,24 +111,40 @@ function CorporateCardsManagement() {
|
|||||||
const randomCard = () => `${randomNum(1000,9999)}-${randomNum(1000,9999)}-${randomNum(1000,9999)}-${randomNum(1000,9999)}`;
|
const randomCard = () => `${randomNum(1000,9999)}-${randomNum(1000,9999)}-${randomNum(1000,9999)}-${randomNum(1000,9999)}`;
|
||||||
const randomExpiry = () => `${randomNum(25,30)}/${String(randomNum(1,12)).padStart(2,'0')}`;
|
const randomExpiry = () => `${randomNum(25,30)}/${String(randomNum(1,12)).padStart(2,'0')}`;
|
||||||
|
|
||||||
const newCards = Array.from({ length: 3 }, (_, i) => ({
|
// 3개의 테스트 카드를 서버에 저장
|
||||||
id: Date.now() + i,
|
for (let i = 0; i < 3; i++) {
|
||||||
cardName: `${names[randomNum(0,4)]} 법인카드`,
|
const testCard = {
|
||||||
cardCompany: companies[randomNum(0,4)],
|
cardName: `${names[randomNum(0,4)]} 법인카드`,
|
||||||
cardNumber: randomCard(),
|
cardCompany: companies[randomNum(0,4)],
|
||||||
cardType: Math.random() > 0.3 ? 'credit' : 'debit',
|
cardNumber: randomCard(),
|
||||||
paymentDay: [10, 15, 20, 25][randomNum(0,3)],
|
cardType: Math.random() > 0.3 ? 'credit' : 'debit',
|
||||||
creditLimit: randomNum(3, 20) * 1000000,
|
paymentDay: [10, 15, 20, 25][randomNum(0,3)],
|
||||||
currentUsage: randomNum(0, 10) * 100000,
|
creditLimit: randomNum(3, 20) * 1000000,
|
||||||
cardHolderName: '(주)테스트회사',
|
cardHolderName: '(주)테스트회사',
|
||||||
actualUser: users[randomNum(0,4)],
|
actualUser: users[randomNum(0,4)],
|
||||||
expiryDate: randomExpiry(),
|
expiryDate: randomExpiry(),
|
||||||
cvc: String(randomNum(100,999)),
|
cvc: String(randomNum(100,999)),
|
||||||
status: 'active',
|
status: 'active',
|
||||||
memo: '테스트 데이터'
|
memo: '테스트 데이터'
|
||||||
}));
|
};
|
||||||
|
|
||||||
setCards(prev => [...prev, ...newCards]);
|
try {
|
||||||
|
const response = await fetch('/finance/corporate-cards/store', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-TOKEN': csrfToken,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(testCard),
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
setCards(prev => [...prev, result.data]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('테스트 데이터 생성 실패:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 카드사 목록
|
// 카드사 목록
|
||||||
@@ -174,52 +214,111 @@ function CorporateCardsManagement() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 카드 저장
|
// 카드 저장
|
||||||
const handleSaveCard = () => {
|
const handleSaveCard = async () => {
|
||||||
if (!formData.cardName || !formData.cardNumber || !formData.cardHolderName || !formData.actualUser) {
|
if (!formData.cardName || !formData.cardNumber || !formData.cardHolderName || !formData.actualUser) {
|
||||||
alert('필수 항목을 입력해주세요.');
|
alert('필수 항목을 입력해주세요.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modalMode === 'add') {
|
try {
|
||||||
const newCard = {
|
if (modalMode === 'add') {
|
||||||
id: Date.now(),
|
const response = await fetch('/finance/corporate-cards/store', {
|
||||||
...formData,
|
method: 'POST',
|
||||||
creditLimit: parseInt(formData.creditLimit) || 0,
|
headers: {
|
||||||
currentUsage: 0
|
'Content-Type': 'application/json',
|
||||||
};
|
'X-CSRF-TOKEN': csrfToken,
|
||||||
setCards(prev => [...prev, newCard]);
|
},
|
||||||
} else {
|
body: JSON.stringify({
|
||||||
setCards(prev => prev.map(card =>
|
...formData,
|
||||||
card.id === editingCard.id
|
creditLimit: parseInt(formData.creditLimit) || 0,
|
||||||
? { ...card, ...formData, creditLimit: parseInt(formData.creditLimit) || 0 }
|
}),
|
||||||
: card
|
});
|
||||||
));
|
const result = await response.json();
|
||||||
}
|
if (result.success) {
|
||||||
|
setCards(prev => [...prev, result.data]);
|
||||||
|
} else {
|
||||||
|
alert(result.message || '저장에 실패했습니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const response = await fetch(`/finance/corporate-cards/${editingCard.id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-TOKEN': csrfToken,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
...formData,
|
||||||
|
creditLimit: parseInt(formData.creditLimit) || 0,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
setCards(prev => prev.map(card =>
|
||||||
|
card.id === editingCard.id ? result.data : card
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
alert(result.message || '수정에 실패했습니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setShowModal(false);
|
setShowModal(false);
|
||||||
setEditingCard(null);
|
setEditingCard(null);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('저장 실패:', error);
|
||||||
|
alert('저장 중 오류가 발생했습니다.');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 카드 비활성화 (소프트 삭제)
|
// 카드 비활성화 (소프트 삭제)
|
||||||
const handleDeactivateCard = (id) => {
|
const handleDeactivateCard = async (id) => {
|
||||||
if (confirm('카드를 비활성화하시겠습니까?\n(목록에서 숨겨지지만 데이터는 유지됩니다)')) {
|
if (confirm('카드를 비활성화하시겠습니까?\n(목록에서 숨겨지지만 데이터는 유지됩니다)')) {
|
||||||
setCards(prev => prev.map(card =>
|
try {
|
||||||
card.id === id ? { ...card, status: 'inactive' } : card
|
const response = await fetch(`/finance/corporate-cards/${id}/deactivate`, {
|
||||||
));
|
method: 'POST',
|
||||||
if (showModal) {
|
headers: {
|
||||||
setShowModal(false);
|
'X-CSRF-TOKEN': csrfToken,
|
||||||
setEditingCard(null);
|
},
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
setCards(prev => prev.map(card =>
|
||||||
|
card.id === id ? { ...card, status: 'inactive' } : card
|
||||||
|
));
|
||||||
|
if (showModal) {
|
||||||
|
setShowModal(false);
|
||||||
|
setEditingCard(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('비활성화 실패:', error);
|
||||||
|
alert('비활성화 중 오류가 발생했습니다.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 카드 영구삭제
|
// 카드 영구삭제
|
||||||
const handlePermanentDeleteCard = (id) => {
|
const handlePermanentDeleteCard = async (id) => {
|
||||||
if (confirm('⚠️ 카드를 영구 삭제하시겠습니까?\n\n이 작업은 되돌릴 수 없습니다.')) {
|
if (confirm('⚠️ 카드를 영구 삭제하시겠습니까?\n\n이 작업은 되돌릴 수 없습니다.')) {
|
||||||
setCards(prev => prev.filter(card => card.id !== id));
|
try {
|
||||||
if (showModal) {
|
const response = await fetch(`/finance/corporate-cards/${id}`, {
|
||||||
setShowModal(false);
|
method: 'DELETE',
|
||||||
setEditingCard(null);
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': csrfToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
setCards(prev => prev.filter(card => card.id !== id));
|
||||||
|
if (showModal) {
|
||||||
|
setShowModal(false);
|
||||||
|
setEditingCard(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('삭제 실패:', error);
|
||||||
|
alert('삭제 중 오류가 발생했습니다.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -426,7 +525,14 @@ className={`h-1.5 rounded-full ${getUsageColor(getUsagePercent(card.currentUsage
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{filteredCards.length === 0 && (
|
{loading && (
|
||||||
|
<div className="text-center py-12 text-gray-400">
|
||||||
|
<div className="animate-spin w-8 h-8 border-4 border-violet-500 border-t-transparent rounded-full mx-auto mb-4"></div>
|
||||||
|
<p>카드 목록을 불러오는 중...</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!loading && filteredCards.length === 0 && (
|
||||||
<div className="text-center py-12 text-gray-400">
|
<div className="text-center py-12 text-gray-400">
|
||||||
<CreditCard className="w-12 h-12 mx-auto mb-4 opacity-50" />
|
<CreditCard className="w-12 h-12 mx-auto mb-4 opacity-50" />
|
||||||
<p>등록된 카드가 없습니다.</p>
|
<p>등록된 카드가 없습니다.</p>
|
||||||
|
|||||||
@@ -690,6 +690,16 @@
|
|||||||
|
|
||||||
return view('finance.corporate-cards');
|
return view('finance.corporate-cards');
|
||||||
})->name('corporate-cards');
|
})->name('corporate-cards');
|
||||||
|
|
||||||
|
// 법인카드 API
|
||||||
|
Route::prefix('corporate-cards')->name('corporate-cards.')->group(function () {
|
||||||
|
Route::get('/list', [\App\Http\Controllers\Finance\CorporateCardController::class, 'index'])->name('list');
|
||||||
|
Route::post('/store', [\App\Http\Controllers\Finance\CorporateCardController::class, 'store'])->name('store');
|
||||||
|
Route::put('/{id}', [\App\Http\Controllers\Finance\CorporateCardController::class, 'update'])->name('update');
|
||||||
|
Route::post('/{id}/deactivate', [\App\Http\Controllers\Finance\CorporateCardController::class, 'deactivate'])->name('deactivate');
|
||||||
|
Route::delete('/{id}', [\App\Http\Controllers\Finance\CorporateCardController::class, 'destroy'])->name('destroy');
|
||||||
|
});
|
||||||
|
|
||||||
Route::get('/card-transactions', function () {
|
Route::get('/card-transactions', function () {
|
||||||
if (request()->header('HX-Request')) {
|
if (request()->header('HX-Request')) {
|
||||||
return response('', 200)->header('HX-Redirect', route('finance.card-transactions'));
|
return response('', 200)->header('HX-Redirect', route('finance.card-transactions'));
|
||||||
|
|||||||
Reference in New Issue
Block a user