Looka vs Brandmark 비교 마크다운 문서를 세련된 디자인의 PHP 대시보드 페이지로 변환 완료

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
aweso
2026-01-15 17:09:54 +09:00
parent 78bb6b6378
commit 3b691596cc
48 changed files with 1899 additions and 484 deletions

View File

@@ -35,3 +35,7 @@ g "작업 요약 내용"
- 단지 제안만 하세요
- 커밋 메시지는 작업 내용을 정확히 반영해야 합니다
## 문서 작성 규칙
1. **한국어 사용**: `.md` (Markdown) 파일을 작성할 때는 항상 한국어를 사용하세요.
2. **명확한 구조**: 문서의 가독성을 위해 헤더, 목록, 코드 블록 등을 적절히 사용하여 구조화하세요.

View File

@@ -5,8 +5,8 @@
*/
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once __DIR__ . '/../../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../../.env'))->load();
require_once('barobill_account_config.php');
require_once(getenv('DOCUMENT_ROOT') . '/session.php');

View File

@@ -15,8 +15,8 @@
// 인증서 키(CERTKEY) 파일 경로
// load .env file
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once __DIR__ . '/../../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../../.env'))->load();
// 인증서 키(CERTKEY) 파일 경로
$documentRoot = getenv('DOCUMENT_ROOT');

View File

@@ -15,8 +15,8 @@
// 인증서 키(CERTKEY) 파일 경로
// load .env file
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once __DIR__ . '/../../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../../.env'))->load();
// 인증서 키(CERTKEY) 파일 경로
$documentRoot = getenv('DOCUMENT_ROOT');

View File

@@ -5,8 +5,8 @@
*/
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once __DIR__ . '/../../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../../.env'))->load();
require_once('barobill_account_config.php');
require_once(getenv('DOCUMENT_ROOT') . '/session.php');

View File

@@ -5,8 +5,8 @@
*/
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once __DIR__ . '/../../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../../.env'))->load();
require_once(getenv('DOCUMENT_ROOT') . '/session.php');
require_once(getenv('DOCUMENT_ROOT') . '/lib/mydb.php');

View File

@@ -5,8 +5,8 @@
*/
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once __DIR__ . '/../../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../../.env'))->load();
require_once(getenv('DOCUMENT_ROOT') . '/session.php');
require_once(getenv('DOCUMENT_ROOT') . '/lib/mydb.php');

View File

@@ -16,8 +16,8 @@
header('Content-Type: application/json; charset=utf-8');
// load .env
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once __DIR__ . '/../../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../../.env'))->load();
require_once('barobill_card_config.php');

View File

@@ -70,31 +70,47 @@
<line x1="12" x2="12" y1="21" y2="8"/>
</svg>
),
arrowUp: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-red-500">
<line x1="12" y1="19" x2="12" y2="5"></line>
<polyline points="5 12 12 5 19 12"></polyline>
</svg>
),
arrowDown: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-blue-500">
<line x1="12" y1="5" x2="12" y2="19"></line>
<polyline points="19 12 12 19 5 12"></polyline>
</svg>
),
search: () => (
building: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="11" cy="11" r="8"/>
<path d="m21 21-4.3-4.3"/>
<rect width="16" height="20" x="4" y="2" rx="2" ry="2"/>
<path d="M9 22v-4h6v4"/>
<path d="M8 6h.01"/>
<path d="M16 6h.01"/>
<path d="M12 6h.01"/>
<path d="M12 10h.01"/>
<path d="M12 14h.01"/>
<path d="M16 10h.01"/>
<path d="M16 14h.01"/>
<path d="M8 10h.01"/>
<path d="M8 14h.01"/>
</svg>
),
fileText: () => (
creditCard: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
<path d="M14 2v4a2 2 0 0 0 2 2h4"/>
<path d="M10 9H8"/>
<path d="M16 13H8"/>
<path d="M16 17H8"/>
<rect width="20" height="14" x="2" y="5" rx="2"/>
<line x1="2" x2="22" y1="10" y2="10"/>
</svg>
),
receipt: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1-2-1Z"/>
<path d="M14 8H8"/>
<path d="M16 12H8"/>
<path d="M13 16H8"/>
</svg>
),
users: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
),
bookOpen: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M2 3h6a4 4 0 0 1 4 4v14a4 4 0 0 0-4-4H2z"/>
<path d="M22 3h-6a4 4 0 0 0-4 4v14a4 4 0 0 1 4-4h6z"/>
</svg>
),
home: () => (
@@ -103,26 +119,10 @@
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
),
chevronsLeft: () => (
search: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m11 17-5-5 5-5"/>
<path d="m18 17-5-5 5-5"/>
</svg>
),
chevronLeft: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m15 18-6-6 6-6"/>
</svg>
),
chevronRight: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m9 18 6-6-6-6"/>
</svg>
),
chevronsRight: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m6 17 5-5-5-5"/>
<path d="m13 17 5-5-5-5"/>
<circle cx="11" cy="11" r="8"/>
<path d="m21 21-4.3-4.3"/>
</svg>
),
download: ({ className }) => (
@@ -139,18 +139,16 @@
<path d="M12 8h.01"/>
</svg>
),
receipt: ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1-2-1Z"/>
<path d="M14 8H8"/>
<path d="M16 12H8"/>
<path d="M13 16H8"/>
arrowUp: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="12" y1="19" x2="12" y2="5"></line>
<polyline points="5 12 12 5 19 12"></polyline>
</svg>
),
creditCard: ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<rect width="20" height="14" x="2" y="5" rx="2"/>
<line x1="2" x2="22" y1="10" y2="10"/>
arrowDown: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line>
<polyline points="19 12 12 19 5 12"></polyline>
</svg>
),
x: ({ className }) => (
@@ -158,27 +156,40 @@
<path d="M18 6 6 18"/>
<path d="m6 6 12 12"/>
</svg>
),
fileText: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
<path d="M14 2v4a2 2 0 0 0 2 2h4"/>
<path d="M10 9H8"/>
<path d="M16 13H8"/>
<path d="M16 17H8"/>
</svg>
)
};
// Header Component
const Header = ({ activeTab, onTabChange, tenants, currentTenantId, onTenantChange }) => (
<header className="bg-white border-b border-gray-100 sticky top-0 z-50 transition-all">
const Header = ({ activeTab, onTabChange, tenants, currentTenantId, onTenantChange, onOpenApiInfo }) => (
<header className="bg-white/80 backdrop-blur-md border-b border-blue-100/50 sticky top-0 z-50 transition-all shadow-sm">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="h-16 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center text-blue-600 font-bold shadow-sm">
🏦
<div className="h-18 flex items-center justify-between py-3">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-xl flex items-center justify-center text-white shadow-lg shadow-blue-200/50 ring-4 ring-blue-50">
<Icons.wallet />
</div>
<div>
<h1 className="text-lg font-bold text-slate-900 tracking-tight leading-none">계좌 입출금내역</h1>
<p className="text-[10px] text-blue-600 font-semibold mt-1 uppercase tracking-wider opacity-70">Bank Transaction History</p>
</div>
<h1 className="text-lg font-semibold text-slate-900">계좌 입출금내역</h1>
</div>
<div className="flex items-center gap-4 text-sm text-slate-500 font-medium">
<div className="flex items-center gap-2 text-sm text-slate-500 font-medium">
{/* 테넌트 선택 드롭다운 */}
{tenants.length > 0 && (
<select
value={currentTenantId}
onChange={(e) => onTenantChange(e.target.value)}
className="text-sm border border-slate-300 rounded-lg px-3 py-1.5 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-blue-500 mr-2"
className="text-xs border border-slate-200 rounded-lg px-3 py-2 bg-white/50 hover:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500 mr-2 transition-all"
>
{tenants.map(tenant => (
<option key={tenant.id} value={tenant.id}>
@@ -188,29 +199,31 @@
</select>
)}
<a href="../eaccount/index.php" className="text-blue-600 flex items-center gap-1 bg-blue-50 px-3 py-1.5 rounded-lg border border-blue-100 cursor-default font-bold">
<Icons.wallet /> 계좌조회
</a>
<a href="../ecard/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<Icons.creditCard /> 카드내역
</a>
<a href="../tenant/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<Icons.bank /> 테넌트관리
</a>
<a href="../barobill_registration/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg> 회원관리
</a>
<a href="../etax/barobill_api_info.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<Icons.info className="w-4 h-4" /> API정보
</a>
<div className="flex bg-slate-100/50 p-1 rounded-xl border border-slate-200/50 mr-2">
<a href="index.php" className="flex items-center gap-2 px-4 py-2 rounded-lg bg-white text-blue-600 shadow-sm border border-blue-100 font-bold transition-all">
<Icons.wallet /> <span>계좌조회</span>
</a>
<a href="../ecard/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<Icons.creditCard /> <span>카드내역</span>
</a>
<a href="../tenant/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<Icons.bank /> <span>테넌트</span>
</a>
<a href="../registration/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<Icons.users /> <span>바로빌 회원관리</span>
</a>
<button onClick={(e) => { e.preventDefault(); onOpenApiInfo(); }} className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<Icons.bookOpen /> <span>API정보</span>
</button>
</div>
<div className="h-4 w-px bg-slate-200 mx-1"></div>
<div className="h-4 w-px bg-slate-200 mx-2"></div>
<a href="../etax/index.php" className="hover:text-blue-700 flex items-center gap-1">
<Icons.receipt /> 세금계산서
<a href="../etax/index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-blue-600 transition-colors">
<Icons.receipt /> <span className="hidden lg:inline text-xs">세금계산서</span>
</a>
<a href="../index.php" className="hover:text-blue-700 flex items-center gap-1">
<Icons.home />
<a href="../../index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-blue-600 transition-colors">
<Icons.home /> <span className="hidden lg:inline text-xs"></span>
</a>
</div>
</div>
@@ -435,6 +448,32 @@
);
};
const ApiInfoModal = ({ isOpen, onClose }) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4" onClick={onClose}>
<div className="bg-white rounded-2xl shadow-2xl w-full max-w-5xl max-h-[90vh] flex flex-col overflow-hidden animate-in fade-in zoom-in-95 duration-200" onClick={e => e.stopPropagation()}>
<div className="p-4 border-b border-slate-100 flex justify-between items-center bg-slate-50/50">
<h3 className="text-lg font-bold text-slate-900 flex items-center gap-2">
<span className="w-1.5 h-6 bg-blue-500 rounded-full"></span>
바로빌 API 상세 정보
</h3>
<button onClick={onClose} className="p-2 rounded-full text-slate-400 hover:text-slate-600 hover:bg-slate-100 transition-colors">
<Icons.x className="w-5 h-5" />
</button>
</div>
<div className="flex-1 bg-slate-50">
<iframe
src="../etax/barobill_api_info.php"
className="w-full h-full border-none min-h-[600px]"
title="API Information"
/>
</div>
</div>
</div>
);
};
// Usage Table Component
const UsageTable = ({ logs, loading }) => {
if (loading) {
@@ -597,6 +636,7 @@
const [diagnosticModal, setDiagnosticModal] = useState({ open: false, content: '', title: '' });
const [tenants, setTenants] = useState([]);
const [currentTenantId, setCurrentTenantId] = useState('');
const [isApiInfoModalOpen, setIsApiInfoModalOpen] = useState(false);
// 날짜 초기화
useEffect(() => {
@@ -872,6 +912,7 @@
tenants={tenants}
currentTenantId={currentTenantId}
onTenantChange={changeTenant}
onOpenApiInfo={() => setIsApiInfoModalOpen(true)}
/>
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-8">
@@ -1419,6 +1460,11 @@
title={diagnosticModal.title}
content={diagnosticModal.content}
/>
<ApiInfoModal
isOpen={isApiInfoModalOpen}
onClose={() => setIsApiInfoModalOpen(false)}
/>
</div>
);
};

View File

@@ -59,54 +59,8 @@
<path d="M18 12a2 2 0 0 0 0 4h4v-4Z"/>
</svg>
),
receipt: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z"/>
<path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8"/>
<path d="M12 17.5v-11"/>
</svg>
),
creditCard: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<rect width="20" height="14" x="2" y="5" rx="2"/>
<line x1="2" x2="22" y1="10" y2="10"/>
</svg>
),
xCircle: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10"/>
<path d="m15 9-6 6"/>
<path d="m9 9 6 6"/>
</svg>
),
filter: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>
</svg>
),
search: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="11" cy="11" r="8"/>
<path d="m21 21-4.3-4.3"/>
</svg>
),
fileText: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
<path d="M14 2v4a2 2 0 0 0 2 2h4"/>
<path d="M10 9H8"/>
<path d="M16 13H8"/>
<path d="M16 17H8"/>
</svg>
),
home: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
),
bank: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M3 21h18"/>
<path d="M5 21v-7"/>
<path d="M19 21v-7"/>
@@ -131,6 +85,66 @@
<path d="M8 14h.01"/>
</svg>
),
creditCard: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<rect width="20" height="14" x="2" y="5" rx="2"/>
<line x1="2" x2="22" y1="10" y2="10"/>
</svg>
),
creditCardLarge: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="opacity-50">
<rect width="20" height="14" x="2" y="5" rx="2"/>
<line x1="2" x2="22" y1="10" y2="10"/>
</svg>
),
receipt: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1-2-1Z"/>
<path d="M14 8H8"/>
<path d="M16 12H8"/>
<path d="M13 16H8"/>
</svg>
),
users: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
),
bookOpen: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M2 3h6a4 4 0 0 1 4 4v14a4 4 0 0 0-4-4H2z"/>
<path d="M22 3h-6a4 4 0 0 0-4 4v14a4 4 0 0 1 4-4h6z"/>
</svg>
),
home: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
),
search: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="11" cy="11" r="8"/>
<path d="m21 21-4.3-4.3"/>
</svg>
),
download: ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" x2="12" y1="15" y2="3"/>
</svg>
),
info: ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<circle cx="12" cy="12" r="10"/>
<path d="M12 16v-4"/>
<path d="M12 8h.01"/>
</svg>
),
alertCircle: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10"/>
@@ -138,6 +152,30 @@
<line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>
),
xCircle: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10"/>
<path d="m15 9-6 6"/>
<path d="m9 9 6 6"/>
</svg>
),
filter: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>
</svg>
),
arrowUp: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="12" y1="19" x2="12" y2="5"></line>
<polyline points="5 12 12 5 19 12"></polyline>
</svg>
),
arrowDown: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line>
<polyline points="19 12 12 19 5 12"></polyline>
</svg>
),
chevronsLeft: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="m11 17-5-5 5-5"/>
@@ -160,68 +198,63 @@
<path d="m13 17 5-5-5-5"/>
</svg>
),
creditCardLarge: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="opacity-50">
<rect width="20" height="14" x="2" y="5" rx="2"/>
<line x1="2" x2="22" y1="10" y2="10"/>
</svg>
),
download: ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" x2="12" y1="15" y2="3"/>
</svg>
),
info: ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<circle cx="12" cy="12" r="10"/>
<path d="M12 16v-4"/>
<path d="M12 8h.01"/>
</svg>
),
x: ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
<path d="M18 6 6 18"/>
<path d="m6 6 12 12"/>
</svg>
),
fileText: () => (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
<path d="M14 2v4a2 2 0 0 0 2 2h4"/>
<path d="M10 9H8"/>
<path d="M16 13H8"/>
<path d="M16 17H8"/>
</svg>
)
};
// Header Component
const Header = () => (
<header className="bg-white border-b border-gray-100 sticky top-0 z-50 transition-all">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-emerald-100 rounded-lg flex items-center justify-center text-emerald-600 font-bold shadow-sm">
💳
const Header = ({ onOpenApiInfo }) => (
<header className="bg-white/80 backdrop-blur-md border-b border-emerald-100/50 sticky top-0 z-50 transition-all shadow-sm">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-18 flex items-center justify-between py-3">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-gradient-to-br from-emerald-500 to-teal-600 rounded-xl flex items-center justify-center text-white shadow-lg shadow-emerald-200/50 ring-4 ring-emerald-50">
<Icons.creditCard />
</div>
<div>
<h1 className="text-lg font-bold text-slate-900 tracking-tight leading-none">법인카드 내역</h1>
<p className="text-[10px] text-emerald-600 font-semibold mt-1 uppercase tracking-wider opacity-70">Corporate Card History</p>
</div>
<h1 className="text-lg font-semibold text-slate-900">법인카드 사용내역</h1>
</div>
<div className="flex items-center gap-4 text-sm text-slate-500 font-medium">
<a href="../eaccount/index.php" className="hover:text-emerald-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<Icons.wallet /> 계좌조회
</a>
<a href="../ecard/index.php" className="text-emerald-600 flex items-center gap-1 bg-emerald-50 px-3 py-1.5 rounded-lg border border-emerald-100 cursor-default font-bold">
<Icons.creditCard /> 카드내역
</a>
<a href="../tenant/index.php" className="hover:text-emerald-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<Icons.building /> 테넌트관리
</a>
<a href="../barobill_registration/index.php" className="hover:text-emerald-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg> 회원관리
</a>
<a href="../etax/barobill_api_info.php" className="hover:text-emerald-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<Icons.info className="w-4 h-4" /> API정보
</a>
<div className="h-4 w-px bg-slate-200 mx-1"></div>
<div className="flex items-center gap-2 text-sm text-slate-500 font-medium">
<div className="flex bg-slate-100/50 p-1 rounded-xl border border-slate-200/50 mr-2">
<a href="../eaccount/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-emerald-600 hover:bg-white transition-all duration-200">
<Icons.wallet /> <span>계좌조회</span>
</a>
<a href="index.php" className="flex items-center gap-4 px-4 py-2 rounded-lg bg-white text-emerald-600 shadow-sm border border-emerald-100 font-bold">
<Icons.creditCard /> <span>카드내역</span>
</a>
<a href="../tenant/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-emerald-600 hover:bg-white transition-all duration-200">
<Icons.building /> <span>테넌트</span>
</a>
<a href="../registration/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-emerald-600 hover:bg-white transition-all duration-200">
<Icons.users /> <span>바로빌 회원관리</span>
</a>
<button onClick={(e) => { e.preventDefault(); onOpenApiInfo(); }} className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-emerald-600 hover:bg-white transition-all duration-200">
<Icons.bookOpen /> <span>API정보</span>
</button>
</div>
<a href="../etax/index.php" className="hover:text-emerald-700 flex items-center gap-1">
<Icons.receipt /> 세금계산서
<div className="h-4 w-px bg-slate-200 mx-2"></div>
<a href="../etax/index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-emerald-600 transition-colors">
<Icons.receipt /> <span className="hidden lg:inline text-xs">세금계산서</span>
</a>
<a href="../index.php" className="hover:text-emerald-700 flex items-center gap-1">
<Icons.home />
<a href="../../index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-emerald-600 transition-colors">
<Icons.home /> <span className="hidden lg:inline text-xs"></span>
</a>
</div>
</div>
@@ -492,6 +525,32 @@
);
};
const ApiInfoModal = ({ isOpen, onClose }) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4" onClick={onClose}>
<div className="bg-white rounded-2xl shadow-2xl w-full max-w-5xl max-h-[90vh] flex flex-col overflow-hidden animate-in fade-in zoom-in-95 duration-200" onClick={e => e.stopPropagation()}>
<div className="p-4 border-b border-emerald-100 flex justify-between items-center bg-emerald-50/50">
<h3 className="text-lg font-bold text-slate-900 flex items-center gap-2">
<span className="w-1.5 h-6 bg-emerald-500 rounded-full"></span>
바로빌 API 상세 정보
</h3>
<button onClick={onClose} className="p-2 rounded-full text-slate-400 hover:text-slate-600 hover:bg-slate-100 transition-colors">
<Icons.x className="w-5 h-5" />
</button>
</div>
<div className="flex-1 bg-slate-50">
<iframe
src="../etax/barobill_api_info.php"
className="w-full h-full border-none min-h-[600px]"
title="API Information"
/>
</div>
</div>
</div>
);
};
// Date Range Selector Component
const DateRangeSelector = ({ startDate, endDate, onStartChange, onEndChange, onSearch }) => (
<div className="flex flex-wrap items-center gap-3">
@@ -700,6 +759,7 @@
const [error, setError] = useState(null);
const [txtExportModalOpen, setTxtExportModalOpen] = useState(false);
const [fieldExportModalOpen, setFieldExportModalOpen] = useState(false);
const [isApiInfoModalOpen, setIsApiInfoModalOpen] = useState(false);
// 날짜 초기화
useEffect(() => {
@@ -783,7 +843,7 @@
return (
<div className="min-h-screen pb-20">
<Header />
<Header onOpenApiInfo={() => setIsApiInfoModalOpen(true)} />
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-8">
{/* 통계 카드 */}
@@ -916,6 +976,11 @@
onClose={() => setFieldExportModalOpen(false)}
logs={logs}
/>
<ApiInfoModal
isOpen={isApiInfoModalOpen}
onClose={() => setIsApiInfoModalOpen(false)}
/>
</div>
);
};

View File

@@ -16,8 +16,8 @@
// load .env file
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once __DIR__ . '/../../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../../.env'))->load();
// 인증서 키(CERTKEY) 파일 경로
$documentRoot = getenv('DOCUMENT_ROOT');

View File

@@ -5,21 +5,21 @@ error_reporting(E_ALL);
header('Content-Type: text/plain');
echo "Current Dir: " . __DIR__ . "\n";
echo "DotEnv Path: " . __DIR__ . '/../../lib/DotEnv.php' . "\n";
echo "Env File Path: " . __DIR__ . '/../../.env' . "\n";
echo "DotEnv Path: " . __DIR__ . '/../../../lib/DotEnv.php' . "\n";
echo "Env File Path: " . __DIR__ . '/../../../.env' . "\n";
if (file_exists(__DIR__ . '/../../lib/DotEnv.php')) {
if (file_exists(__DIR__ . '/../../../lib/DotEnv.php')) {
echo "DotEnv file exists.\n";
require_once __DIR__ . '/../../lib/DotEnv.php';
require_once __DIR__ . '/../../../lib/DotEnv.php';
echo "DotEnv loaded.\n";
} else {
echo "DotEnv file NOT found.\n";
}
if (file_exists(__DIR__ . '/../../.env')) {
if (file_exists(__DIR__ . '/../../../.env')) {
echo ".env file exists.\n";
try {
(new DotEnv(__DIR__ . '/../../.env'))->load();
(new DotEnv(__DIR__ . '/../../../.env'))->load();
echo ".env loaded.\n";
} catch (Exception $e) {
echo "Error loading .env: " . $e->getMessage() . "\n";

View File

@@ -313,6 +313,34 @@
"memo": "A\/S 납품",
"createdAt": "2026-01-14T09:13:58",
"barobillInvoiceId": "1"
},
{
"id": "inv_1768384628",
"issueKey": "MGT202601141857081230",
"mgtKey": "MGT202601141857081230",
"supplierBizno": "664-86-03713",
"supplierName": "(주)코드브릿지엑스",
"recipientBizno": "311-46-00378",
"recipientName": "김인태",
"supplyDate": "2025-12-22",
"items": [
{
"name": "조명기구",
"qty": 21,
"unitPrice": 173624,
"vatType": "vat",
"supplyAmt": 3646104,
"vat": 364610,
"total": 4010714
}
],
"totalSupplyAmt": 3646104,
"totalVat": 364610,
"total": 4010714,
"status": "issued",
"memo": "A\/S 납품",
"createdAt": "2026-01-14T18:57:08",
"barobillInvoiceId": "1"
}
]
}

View File

@@ -1,6 +1,6 @@
<?php
require_once __DIR__ . '/../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../.env'))->load();
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();
require_once(getenv('DOCUMENT_ROOT') . "/session.php");
?>
<!DOCTYPE html>
@@ -20,12 +20,12 @@ require_once(getenv('DOCUMENT_ROOT') . "/session.php");
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #43cea2 0%, #185a9d 100%);
min-height: 100vh;
padding: 20px;
padding: 40px 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
margin: 20px auto;
background: white;
border-radius: 20px;
padding: 40px;
@@ -166,31 +166,6 @@ require_once(getenv('DOCUMENT_ROOT') . "/session.php");
color: #e83e8c;
}
.home-btn {
position: fixed;
top: 30px;
left: 30px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 12px 25px;
border-radius: 50px;
cursor: pointer;
font-size: 1em;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
z-index: 1000;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 8px;
font-weight: 600;
}
.home-btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
}
@media (max-width: 768px) {
.container {
@@ -201,21 +176,10 @@ require_once(getenv('DOCUMENT_ROOT') . "/session.php");
font-size: 1.8em;
}
.home-btn {
top: 15px;
left: 15px;
padding: 10px 20px;
font-size: 0.9em;
}
}
</style>
</head>
<body>
<!-- Home Button -->
<a href="../index.php" class="home-btn">
<span>🏠</span>
<span>홈으로</span>
</a>
<div class="container">
<div class="header">
@@ -425,7 +389,6 @@ Content-Type: application/json
<li>인증서 등록 연동</li>
<li>실제 프로젝트에 통합</li>
</ol>
<p><a href="../strategy/electronicTaxInvoice_index.php" class="btn">전략 페이지로 돌아가기</a></p>
</div>
</div>
</body>

View File

@@ -8,21 +8,26 @@
<!-- Fonts: Pretendard -->
<link rel="stylesheet" as="style" crossorigin href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.8/dist/web/static/pretendard.css" />
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Global Meta & Scripts -->
<?php include_once __DIR__ . '/../../lib/meta_common.php'; ?>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Pretendard', 'sans-serif'],
sans: ['Pretendard', 'Inter', 'Noto Sans KR', 'sans-serif'],
},
colors: {
background: 'rgb(250, 250, 250)',
primary: {
DEFAULT: '#2563eb',
foreground: '#ffffff',
},
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
900: '#0c4a6e',
}
},
borderRadius: {
'card': '12px',
@@ -31,18 +36,8 @@
}
}
</script>
<!-- React & ReactDOM -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Babel for JSX -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Icons: Lucide -->
<script src="https://unpkg.com/lucide@latest"></script>
</head>
<body class="bg-background text-slate-800 antialiased">
<body class="bg-slate-50 text-slate-800 antialiased">
<div id="root"></div>
<script type="text/babel">
@@ -51,44 +46,63 @@
// --- Components ---
// 1. Header Component
const Header = ({ onOpenHelp }) => {
const Header = ({ onOpenApiInfo }) => {
return (
<header className="bg-white border-b border-gray-100 sticky top-0 z-50 transition-all">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center text-blue-600 font-bold shadow-sm">
📋
<nav className="sticky top-0 z-30 bg-white/80 backdrop-blur-md border-b border-slate-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo Section */}
<div className="flex items-center gap-3 cursor-pointer" onClick={() => window.location.href='../../index.php'}>
<div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center text-white font-bold text-lg shadow-lg shadow-blue-200">
S
</div>
<span className="text-xl font-bold tracking-tight text-slate-900">CodeBridgeX <span className="text-blue-600">SAM</span></span>
<div className="h-4 w-px bg-slate-200 mx-2 hidden sm:block"></div>
<h1 className="text-sm font-bold text-slate-500 hidden sm:block">전자세금계산서</h1>
</div>
<h1 className="text-lg font-semibold text-slate-900">전자세금계산서 솔루션</h1>
</div>
<div className="flex items-center gap-4 text-sm text-slate-500 font-medium">
<a href="../eaccount/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="wallet" className="w-4 h-4 text-blue-500"></i> 계좌조회
</a>
<a href="../ecard/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="credit-card" className="w-4 h-4 text-purple-500"></i> 카드내역
</a>
<a href="../tenant/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="building" className="w-4 h-4 text-blue-600"></i> 테넌트관리
</a>
<a href="../barobill_registration/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="users" className="w-4 h-4 text-teal-500"></i> 회원관리
</a>
<a href="barobill_api_info.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="book-open" className="w-4 h-4 text-orange-500"></i> API정보
</a>
<div className="h-4 w-px bg-slate-200 mx-1"></div>
{/* Desktop Navigation */}
<div className="hidden md:flex items-center gap-4">
<div className="flex bg-slate-100/50 p-1 rounded-xl border border-slate-200/50 mr-4">
<a href="../eaccount/index.php" className="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-semibold text-slate-600 hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="wallet" className="w-3.5 h-3.5 text-blue-500"></i> <span>계좌조회</span>
</a>
<a href="../ecard/index.php" className="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-semibold text-slate-600 hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="credit-card" className="w-3.5 h-3.5 text-purple-500"></i> <span>카드내역</span>
</a>
<a href="../tenant/index.php" className="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-semibold text-slate-600 hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="building" className="w-3.5 h-3.5 text-teal-500"></i> <span>테넌트</span>
</a>
<a href="../registration/index.php" className="flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-semibold text-slate-600 hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="users" className="w-3.5 h-3.5 text-amber-500"></i> <span>바로빌 회원관리</span>
</a>
</div>
<a href="../etax/index.php" className="text-blue-600 flex items-center gap-1 bg-blue-50 px-3 py-1.5 rounded-lg border border-blue-100 cursor-default font-bold">
<i data-lucide="file-text" className="w-4 h-4"></i> 세금계산서
</a>
<a href="../index.php" className="hover:text-blue-700 flex items-center gap-1">
<i data-lucide="home" className="w-4 h-4"></i>
</a>
<a href="../../salesmanagement/" className="text-sm font-medium text-slate-600 hover:text-blue-600 transition-colors">영업관리</a>
<a href="../../price/index.php" className="text-sm font-medium text-slate-600 hover:text-blue-600 transition-colors">가격정책</a>
<button
onClick={onOpenApiInfo}
className="px-4 py-2 bg-slate-900 text-white text-sm font-bold rounded-lg hover:bg-slate-800 transition-all shadow-lg shadow-slate-200 flex items-center gap-2"
>
<i data-lucide="code-2" className="w-4 h-4"></i>
API정보
</button>
<a href="../../index.php" className="p-2 rounded-lg text-slate-400 hover:text-blue-600 hover:bg-slate-50 transition-all">
<i data-lucide="home" className="w-5 h-5"></i>
</a>
</div>
{/* Mobile Toggle (Simplified for now) */}
<div className="md:hidden">
<button className="p-2 text-slate-600">
<i data-lucide="menu" className="w-6 h-6"></i>
</button>
</div>
</div>
</div>
</header>
</nav>
);
};
@@ -788,6 +802,7 @@
const [selectedInvoice, setSelectedInvoice] = useState(null);
const [showIssueForm, setShowIssueForm] = useState(false);
const [apiLogs, setApiLogs] = useState([]);
const [isApiInfoModalOpen, setIsApiInfoModalOpen] = useState(false);
useEffect(() => {
loadInvoices();
@@ -935,7 +950,7 @@
return (
<div className="min-h-screen pb-20">
<Header />
<Header onOpenApiInfo={() => setIsApiInfoModalOpen(true)} />
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-8">
{/* Dashboard Section */}
@@ -1069,11 +1084,47 @@
{/* Detail Modal */}
{selectedInvoice && (
<InvoiceDetailModal
<InvoiceDetailModal
invoice={selectedInvoice}
onClose={() => setSelectedInvoice(null)}
/>
)}
<ApiInfoModal
isOpen={isApiInfoModalOpen}
onClose={() => setIsApiInfoModalOpen(false)}
/>
</div>
);
};
const ApiInfoModal = ({ isOpen, onClose }) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-slate-900/60 backdrop-blur-sm">
<div className="bg-white rounded-3xl w-full max-w-6xl overflow-hidden shadow-2xl animate-in fade-in zoom-in-95 duration-300 border border-slate-200 flex flex-col h-[85vh]">
<div className="p-4 border-b border-slate-100 flex justify-between items-center bg-white/50 backdrop-blur-sm z-10">
<div className="flex items-center gap-4">
<div className="p-3 bg-slate-900 rounded-xl text-white shadow-lg shadow-slate-200">
<i data-lucide="code-2" className="w-6 h-6"></i>
</div>
<div>
<h3 className="text-xl font-black text-slate-900 tracking-tight">바로빌 API 연동 가이드</h3>
<p className="text-sm text-slate-500 font-medium">SAM 플랫폼의 전자세금계산서 연동 상세 규격 정보</p>
</div>
</div>
<button onClick={onClose} className="btn-close-modal group">
<span></span>
</button>
</div>
<div className="flex-1 overflow-auto bg-slate-50 relative">
<iframe
src="barobill_api_info.php"
className="w-full h-full border-none"
title="API Information"
/>
</div>
</div>
</div>
);
};

View File

@@ -48,43 +48,63 @@
#modalOverlay.show {
opacity: 1;
}
/* 상세 단가표 (Shadcn 스타일) */
.pricing-card { background: white; border-radius: 0.75rem; border: 1px solid #e2e8f0; box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1); }
.pricing-badge { display: inline-flex; align-items: center; border-radius: 9999px; padding: 0.125rem 0.625rem; font-size: 0.75rem; font-weight: 500; }
.pricing-table-header { background: #f8fafc; }
.pricing-tier-row:hover { background: #f1f5f9; }
.pricing-tab-active { background: white; box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1); font-weight: 600; color: #0d9488 !important; }
.pricing-example-card { background: linear-gradient(135deg, #f8fafc, #f1f5f9); border: 1px solid #e2e8f0; }
.pricing-summary-row { background: rgba(13, 148, 136, 0.05); }
.pricing-collapsible { max-height: 0; overflow: hidden; transition: max-height 0.3s ease-out; }
.pricing-collapsible.open { max-height: 2000px; }
.pricing-rotate { transition: transform 0.3s ease; }
.pricing-rotate.open { transform: rotate(180deg); }
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<!-- Header -->
<header class="bg-white shadow-sm sticky top-0 z-50">
<div class="max-w-6xl mx-auto px-4">
<div class="flex items-center justify-between py-4">
<div class="flex items-center space-x-4">
<a href="../index.php" class="flex items-center justify-center w-10 h-10 bg-slate-100 hover:bg-teal-100 rounded-lg transition-colors" title="홈으로">
<span class="text-xl">🏠</span>
</a>
<h1 class="text-xl font-bold text-slate-800">바로빌 API 회계 솔루션</h1>
<header class="bg-white/80 backdrop-blur-md border-b border-teal-100/50 sticky top-0 z-50 transition-all shadow-sm">
<div class="max-w-6xl mx-auto px-4 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="w-10 h-10 bg-gradient-to-br from-teal-500 to-emerald-600 rounded-xl flex items-center justify-center text-white shadow-lg shadow-teal-200/50 ring-4 ring-teal-50">
<span class="text-xl">📊</span>
</div>
<div>
<h1 class="text-lg font-bold text-slate-900 tracking-tight leading-none">바로빌 솔루션</h1>
<p class="text-[10px] text-teal-600 font-semibold mt-1 uppercase tracking-wider opacity-70">API Integration Dashboard</p>
</div>
</div>
<div class="flex items-center gap-4 text-xs text-slate-500 font-medium">
<a href="../eaccount/index.php" class="hover:text-teal-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<span>💰</span> 계좌조회
</a>
<a href="../ecard/index.php" class="hover:text-teal-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<span>💳</span> 카드내역
</a>
<a href="../tenant/index.php" class="hover:text-teal-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<span>🏢</span> 테넌트관리
</a>
<a href="../barobill_registration/index.php" class="hover:text-teal-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<span>👥</span> 회원관리
</a>
<a href="../etax/barobill_api_info.php" class="hover:text-teal-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<span>📖</span> API정보
</a>
<div class="flex items-center gap-2 text-xs text-slate-500 font-medium">
<div class="flex bg-slate-100/50 p-1 rounded-xl border border-slate-200/50 mr-2">
<a href="eaccount/index.php" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-teal-600 hover:bg-white transition-all duration-200">
<span>💰</span> <span>계좌조회</span>
</a>
<a href="ecard/index.php" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-teal-600 hover:bg-white transition-all duration-200">
<span>💳</span> <span>카드내역</span>
</a>
<a href="tenant/index.php" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-teal-600 hover:bg-white transition-all duration-200">
<span>🏢</span> <span>테넌트</span>
</a>
<a href="registration/index.php" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-teal-600 hover:bg-white transition-all duration-200">
<span>👥</span> <span>바로빌 회원관리</span>
</a>
<button onclick="openApiInfoModal(); event.preventDefault();" class="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-teal-600 hover:bg-white transition-all duration-200">
<span>📖</span> <span>API정보</span>
</button>
</div>
<div class="h-4 w-px bg-slate-200 mx-1"></div>
<div class="h-4 w-px bg-slate-200 mx-2"></div>
<a href="../etax/index.php" class="hover:text-teal-700 flex items-center gap-1">
<span>📄</span> 세금계산서
<a href="etax/index.php" class="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-teal-600 transition-colors">
<span>📄</span> <span class="hidden lg:inline text-[10px]">세금계산서</span>
</a>
<a href="../index.php" class="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-teal-600 transition-colors">
<span>🏠</span> <span class="hidden lg:inline text-[10px]"></span>
</a>
<span class="text-[10px] text-slate-400 opacity-50 ml-2"><?php echo date('Y-m-d'); ?></span>
</div>
</div>
</div>
@@ -1117,6 +1137,304 @@
</div>
</div>
</div>
<!-- ============================================ -->
<!-- 상세 단가표 (Shadcn Style) -->
<!-- ============================================ -->
<div class="mt-12 pt-12 border-t border-slate-200 fade-in fade-in-4">
<div class="mb-8">
<div class="flex items-center gap-3 mb-2">
<div class="w-12 h-12 rounded-xl bg-gradient-to-br from-teal-500 to-teal-600 flex items-center justify-center shadow-lg">
<svg class="w-7 h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
</svg>
</div>
<div>
<h2 class="text-2xl font-bold text-slate-900">바로빌 API 구간별 상세 단가표</h2>
<p class="text-sm text-slate-500">전체 구간별 할인 요율 및 계산 예시 · VAT 별도</p>
</div>
</div>
</div>
<!-- Pricing Tabs -->
<div class="bg-slate-100 p-1 rounded-lg inline-flex mb-6 gap-1 flex-wrap border border-slate-200">
<button onclick="showPricingTab('all')" id="tab-pricing-all" class="pricing-tab-btn px-4 py-2 rounded-md text-sm font-medium transition-all pricing-tab-active">전체 보기</button>
<button onclick="showPricingTab('tax')" id="tab-pricing-tax" class="pricing-tab-btn px-4 py-2 rounded-md text-sm font-medium transition-all text-slate-600 hover:text-slate-900">전자세금계산서</button>
<button onclick="showPricingTab('account')" id="tab-pricing-account" class="pricing-tab-btn px-4 py-2 rounded-md text-sm font-medium transition-all text-slate-600 hover:text-slate-900">계좌조회</button>
<button onclick="showPricingTab('card')" id="tab-pricing-card" class="pricing-tab-btn px-4 py-2 rounded-md text-sm font-medium transition-all text-slate-600 hover:text-slate-900">카드</button>
<button onclick="showPricingTab('hometax')" id="tab-pricing-hometax" class="pricing-tab-btn px-4 py-2 rounded-md text-sm font-medium transition-all text-slate-600 hover:text-slate-900">홈택스</button>
</div>
<!-- Card: Tax -->
<div class="pricing-card mb-6" id="card-pricing-tax">
<div class="p-6 border-b border-slate-100">
<div class="flex items-center justify-between flex-wrap gap-4">
<div class="flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-emerald-100 flex items-center justify-center">
<svg class="w-6 h-6 text-emerald-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"></path>
</svg>
</div>
<div>
<h2 class="text-xl font-bold text-slate-900">전자세금계산서</h2>
<p class="text-sm text-slate-500">발급 건당 과금 · 6개 구간</p>
</div>
</div>
<span class="pricing-badge bg-emerald-100 text-emerald-700 text-sm px-3 py-1">건당 50~100원</span>
</div>
</div>
<div class="p-6 border-b border-slate-100">
<h3 class="text-sm font-semibold text-slate-700 mb-4 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16"></path></svg>
구간별 기본 단가
</h3>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="pricing-table-header">
<th class="text-left py-3 px-4 rounded-l-lg font-medium text-slate-600">구간</th>
<th class="text-left py-3 px-4 font-medium text-slate-600">발급건수</th>
<th class="text-right py-3 px-4 rounded-r-lg font-medium text-slate-600">단가</th>
</tr>
</thead>
<tbody>
<tr class="pricing-tier-row border-b border-slate-50">
<td class="py-3 px-4"><span class="pricing-badge bg-slate-100 text-slate-700">기본</span></td>
<td class="py-3 px-4 text-slate-600">3,000건 이하</td>
<td class="py-3 px-4 text-right font-semibold text-slate-900">100원</td>
</tr>
<tr class="pricing-tier-row border-b border-slate-50">
<td class="py-3 px-4"><span class="pricing-badge bg-teal-50 text-teal-700">1구간</span></td>
<td class="py-3 px-4 text-slate-600">3,001 ~ 4,000</td>
<td class="py-3 px-4 text-right font-semibold text-slate-900">90원</td>
</tr>
<tr class="pricing-tier-row border-b border-slate-50">
<td class="py-3 px-4"><span class="pricing-badge bg-teal-50 text-teal-700">2구간</span></td>
<td class="py-3 px-4 text-slate-600">4,001 ~ 5,000</td>
<td class="py-3 px-4 text-right font-semibold text-slate-900">80원</td>
</tr>
<tr class="pricing-tier-row border-b border-slate-50">
<td class="py-3 px-4"><span class="pricing-badge bg-teal-50 text-teal-700">3구간</span></td>
<td class="py-3 px-4 text-slate-600">5,001 ~ 8,000</td>
<td class="py-3 px-4 text-right font-semibold text-slate-900">70원</td>
</tr>
<tr class="pricing-tier-row border-b border-slate-50">
<td class="py-3 px-4"><span class="pricing-badge bg-teal-50 text-teal-700">4구간</span></td>
<td class="py-3 px-4 text-slate-600">8,001 ~ 10,000</td>
<td class="py-3 px-4 text-right font-semibold text-slate-900">60원</td>
</tr>
<tr class="pricing-tier-row">
<td class="py-3 px-4"><span class="pricing-badge bg-purple-50 text-purple-700">5구간</span></td>
<td class="py-3 px-4 text-slate-600">10,000건 초과</td>
<td class="py-3 px-4 text-right font-semibold text-teal-600">50원</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="p-6">
<button onclick="togglePricingSection('tax-examples')" class="w-full flex items-center justify-between text-left mb-4">
<h3 class="text-sm font-semibold text-slate-700 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path></svg>
상세 계산 예시 (대표 사례)
</h3>
<svg id="tax-examples-icon" class="w-5 h-5 text-slate-400 pricing-rotate" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<div id="tax-examples" class="pricing-collapsible open space-y-4">
<div class="pricing-example-card rounded-lg p-4">
<div class="flex items-center justify-between mb-3">
<span class="font-semibold text-slate-900 text-sm">📊 월 4,000건 발급 시</span>
<span class="pricing-badge bg-teal-100 text-teal-700">평균 98원</span>
</div>
<table class="w-full text-xs">
<thead><tr class="text-slate-500"><th class="text-left py-1">구간</th><th class="text-left py-1">수량</th><th class="text-right py-1">단가</th><th class="text-right py-1">금액</th></tr></thead>
<tbody>
<tr class="border-b border-slate-100"><td class="py-1 text-slate-600">기본 (3,000)</td><td>3,000</td><td class="text-right">100원</td><td class="text-right">300,000</td></tr>
<tr class="border-b border-slate-100"><td class="py-1 text-slate-600">1구간 (1,000)</td><td>1,000</td><td class="text-right">90원</td><td class="text-right">90,000</td></tr>
</tbody>
<tfoot><tr class="pricing-summary-row font-bold"><td colspan="3" class="py-2 text-slate-800">계</td><td class="text-right text-teal-600">390,000원</td></tr></tfoot>
</table>
</div>
</div>
</div>
</div>
<!-- Card: Account -->
<div class="pricing-card mb-6" id="card-pricing-account">
<div class="p-6 border-b border-slate-100">
<div class="flex items-center justify-between flex-wrap gap-4">
<div class="flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-blue-100 flex items-center justify-center">
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
</svg>
</div>
<div>
<h2 class="text-xl font-bold text-slate-900">계좌조회 (10분주기)</h2>
<p class="text-sm text-slate-500">등록 건당 과금 · 5개 구간</p>
</div>
</div>
<span class="pricing-badge bg-blue-100 text-blue-700 text-sm px-3 py-1">건당 3,000~6,000원</span>
</div>
</div>
<div class="p-6">
<h3 class="text-sm font-semibold text-slate-700 mb-4 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16"></path></svg>
구간별 기본 단가
</h3>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="pricing-table-header">
<th class="text-left py-3 px-4 rounded-l-lg font-medium text-slate-600">구간</th>
<th class="text-left py-3 px-4 font-medium text-slate-600">등록수</th>
<th class="text-right py-3 px-4 rounded-r-lg font-medium text-slate-600">단가</th>
</tr>
</thead>
<tbody>
<tr class="pricing-tier-row border-b border-slate-50"><td>기본 (1~50)</td><td>50개</td><td class="text-right font-semibold">6,000원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>1구간 (51~100)</td><td>50개</td><td class="text-right font-semibold">5,000원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>2구간 (101~500)</td><td>400개</td><td class="text-right font-semibold">4,000원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>3구간 (501~1,000)</td><td>500개</td><td class="text-right font-semibold">3,500원</td></tr>
<tr class="pricing-tier-row"><td>4구간 (1,000 초과)</td><td>-</td><td class="text-right font-semibold text-teal-600">3,000원</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Card: Card -->
<div class="pricing-card mb-6" id="card-pricing-card">
<div class="p-6 border-b border-slate-100">
<div class="flex items-center justify-between flex-wrap gap-4">
<div class="flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-orange-100 flex items-center justify-center">
<svg class="w-6 h-6 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
</svg>
</div>
<div>
<h2 class="text-xl font-bold text-slate-900">법인/개인카드 조회</h2>
<p class="text-sm text-slate-500">등록 건당 과금 · 5개 구간</p>
</div>
</div>
<span class="pricing-badge bg-orange-100 text-orange-700 text-sm px-3 py-1">건당 1,700~3,000원</span>
</div>
</div>
<div class="p-6">
<h3 class="text-sm font-semibold text-slate-700 mb-4 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16"></path></svg>
구간별 기본 단가
</h3>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="pricing-table-header">
<th class="text-left py-3 px-4 rounded-l-lg font-medium text-slate-600">구간</th>
<th class="text-left py-3 px-4 font-medium text-slate-600">등록수</th>
<th class="text-right py-3 px-4 rounded-r-lg font-medium text-slate-600">단가</th>
</tr>
</thead>
<tbody>
<tr class="pricing-tier-row border-b border-slate-50"><td>기본 (1~50)</td><td>50개</td><td class="text-right font-semibold">3,000원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>1구간 (51~100)</td><td>50개</td><td class="text-right font-semibold">2,500원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>2구간 (101~500)</td><td>400개</td><td class="text-right font-semibold">2,300원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>3구간 (501~1,000)</td><td>500개</td><td class="text-right font-semibold">1,900원</td></tr>
<tr class="pricing-tier-row"><td>4구간 (1,000 초과)</td><td>-</td><td class="text-right font-semibold text-teal-600">1,700원</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Card: Hometax -->
<div class="pricing-card mb-6" id="card-pricing-hometax">
<div class="p-6 border-b border-slate-100">
<div class="flex items-center justify-between flex-wrap gap-4">
<div class="flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-violet-100 flex items-center justify-center">
<svg class="w-6 h-6 text-violet-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
</div>
<div>
<h2 class="text-xl font-bold text-slate-900">홈택스 매입/매출 조회</h2>
<p class="text-sm text-slate-500">개사당 월정액 · 6개 구간</p>
</div>
</div>
<span class="pricing-badge bg-violet-100 text-violet-700 text-sm px-3 py-1">월 10,000~30,000원</span>
</div>
</div>
<div class="p-6">
<h3 class="text-sm font-semibold text-slate-700 mb-4 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16"></path></svg>
구간별 기본 단가
</h3>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="pricing-table-header">
<th class="text-left py-3 px-4 rounded-l-lg font-medium text-slate-600">구간</th>
<th class="text-left py-3 px-4 font-medium text-slate-600">개사수</th>
<th class="text-right py-3 px-4 rounded-r-lg font-medium text-slate-600">단가</th>
</tr>
</thead>
<tbody>
<tr class="pricing-tier-row border-b border-slate-50"><td>기본 (1~20)</td><td>20개사</td><td class="text-right font-semibold">30,000원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>1구간 (21~50)</td><td>30개사</td><td class="text-right font-semibold">20,000원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>2구간 (51~100)</td><td>50개사</td><td class="text-right font-semibold">18,000원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>3구간 (101~200)</td><td>100개사</td><td class="text-right font-semibold">15,000원</td></tr>
<tr class="pricing-tier-row border-b border-slate-50"><td>4구간 (201~500)</td><td>300개사</td><td class="text-right font-semibold">12,000원</td></tr>
<tr class="pricing-tier-row"><td>5구간 (500 초과)</td><td>-</td><td class="text-right font-semibold text-teal-600">10,000원</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Summary Table -->
<div class="pricing-card mt-8" id="pricing-summary-section">
<div class="p-6 border-b border-slate-100">
<h3 class="text-lg font-bold text-slate-900 flex items-center gap-2">
<svg class="w-5 h-5 text-teal-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
</svg>
서비스별 할인 요율 요약
</h3>
<p class="text-sm text-slate-500 mt-1">대량 사용 시 최대 할인폭 비교</p>
</div>
<div class="p-6">
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-emerald-50 rounded-lg p-4 text-center border border-emerald-100">
<div class="text-xs text-emerald-600 font-medium mb-1">전자세금계산서</div>
<div class="text-2xl font-bold text-emerald-700">50% <span class="text-xs font-normal">OFF</span></div>
<div class="text-[10px] text-slate-500 mt-1">100원 → 50원</div>
</div>
<div class="bg-blue-50 rounded-lg p-4 text-center border border-blue-100">
<div class="text-xs text-blue-600 font-medium mb-1">계좌조회</div>
<div class="text-2xl font-bold text-blue-700">50% <span class="text-xs font-normal">OFF</span></div>
<div class="text-[10px] text-slate-500 mt-1">6,000원 → 3,000원</div>
</div>
<div class="bg-orange-50 rounded-lg p-4 text-center border border-orange-100">
<div class="text-xs text-orange-600 font-medium mb-1">카드조회</div>
<div class="text-2xl font-bold text-orange-700">43% <span class="text-xs font-normal">OFF</span></div>
<div class="text-[10px] text-slate-500 mt-1">3,000원 → 1,700원</div>
</div>
<div class="bg-violet-50 rounded-lg p-4 text-center border border-violet-100">
<div class="text-xs text-violet-600 font-medium mb-1">홈택스조회</div>
<div class="text-2xl font-bold text-violet-700">67% <span class="text-xs font-normal">OFF</span></div>
<div class="text-[10px] text-slate-500 mt-1">30,000원 → 10,000원</div>
</div>
</div>
</div>
</div>
<!-- Additional Info -->
<div class="mt-8 text-center text-xs text-slate-500">
<p>위 단가표는 Code Bridge X 파트너 전용 특별 할인 단가입니다.</p>
<p class="mt-1">정확한 견적은 사용량 추이에 따라 매달 정산됩니다.</p>
</div>
</div>
</section>
</div>
</main>
@@ -1126,7 +1444,23 @@
<!-- ============================================ -->
<!-- 모달 오버레이 -->
<div id="modalOverlay" class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden flex items-center justify-center p-4" onclick="closeModal(event)">
<div id="modalOverlay" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 hidden flex items-center justify-center p-4 transition-opacity duration-200" onclick="closeModal(event)">
<!-- 바로빌 API 상세 정보 모달 -->
<div id="apiInfoModal" class="modal-content bg-white rounded-2xl shadow-2xl w-full max-w-5xl h-[85vh] flex flex-col overflow-hidden hidden" onclick="event.stopPropagation()">
<div class="px-6 py-4 border-b border-teal-100 flex justify-between items-center bg-teal-50/50">
<h3 class="text-lg font-bold text-slate-800 flex items-center gap-2">
<span class="w-1.5 h-6 bg-teal-500 rounded-full"></span>
바로빌 API 상세 정보
</h3>
<button onclick="closeModal()" class="w-10 h-10 flex items-center justify-center rounded-full text-slate-600 hover:text-slate-900 hover:bg-slate-200 transition-all duration-200 bg-white/50 shadow-sm border border-slate-200">
<span class="text-2xl leading-none">×</span>
</button>
</div>
<div class="flex-1 bg-slate-50 min-h-0">
<iframe src="etax/barobill_api_info.php" class="w-full h-full border-none" title="API Information"></iframe>
</div>
</div>
<!-- 회사 정보 관리 모달 -->
<div id="companyModal" class="modal-content bg-white rounded-xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto hidden" onclick="event.stopPropagation()">
@@ -1545,6 +1879,44 @@
closeModal();
}
});
function openApiInfoModal() {
openModal('apiInfoModal');
}
// 상세 단가표 제어 함수
function showPricingTab(tabId) {
document.querySelectorAll('.pricing-tab-btn').forEach(btn => {
btn.classList.remove('pricing-tab-active');
btn.classList.add('text-slate-600');
});
const activeTab = document.getElementById('tab-pricing-' + tabId);
activeTab.classList.add('pricing-tab-active');
activeTab.classList.remove('text-slate-600');
const cards = ['tax', 'account', 'card', 'hometax'];
const summarySection = document.getElementById('pricing-summary-section');
if (tabId === 'all') {
cards.forEach(card => {
document.getElementById('card-pricing-' + card).style.display = 'block';
});
summarySection.style.display = 'block';
} else {
cards.forEach(card => {
document.getElementById('card-pricing-' + card).style.display = (card === tabId) ? 'block' : 'none';
});
summarySection.style.display = 'none';
}
}
function togglePricingSection(sectionId) {
const section = document.getElementById(sectionId);
const icon = document.getElementById(sectionId + '-icon');
section.classList.toggle('open');
icon.classList.toggle('open');
}
</script>
</body>
</html>

View File

@@ -3,10 +3,10 @@ header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
try {
if (!file_exists("../lib/mydb.php")) {
throw new Exception("Required library file ../lib/mydb.php not found.");
if (!file_exists("../../lib/mydb.php")) {
throw new Exception("Required library file ../../lib/mydb.php not found.");
}
require_once("../lib/mydb.php");
require_once("../../lib/mydb.php");
$pdo = db_connect();

View File

@@ -47,42 +47,48 @@
// --- Layout Components ---
const Header = () => (
<header className="bg-white border-b border-gray-100 sticky top-0 z-50">
<div className="max-w-7xl mx-auto px-4 lg:px-8 h-16 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center text-white">
const Header = ({ onOpenApiInfo }) => (
<header className="bg-white/80 backdrop-blur-md border-b border-blue-100/50 sticky top-0 z-50 transition-all shadow-sm">
<div className="max-w-7xl mx-auto px-4 lg:px-8 h-18 flex items-center justify-between py-3">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-xl flex items-center justify-center text-white shadow-lg shadow-blue-200/50 ring-4 ring-blue-50">
<i data-lucide="users" className="w-5 h-5"></i>
</div>
<h1 className="text-lg font-semibold text-slate-900">바로빌 회원관리 솔루션</h1>
<div>
<h1 className="text-lg font-bold text-slate-900 tracking-tight leading-none">바로빌 회원관리</h1>
<p className="text-[10px] text-blue-600 font-semibold mt-1 uppercase tracking-wider opacity-70">Barobill Member Management</p>
</div>
</div>
<div className="flex items-center gap-4 text-sm text-slate-500 font-medium">
<a href="../eaccount/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="wallet" className="w-4 h-4 text-blue-500"></i> 계좌조회
</a>
<a href="../ecard/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="credit-card" className="w-4 h-4 text-purple-500"></i> 카드내역
</a>
<a href="../tenant/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="building" className="w-4 h-4 text-teal-500"></i> 테넌트관리
</a>
<a href="../barobill_registration/index.php" className="text-blue-600 flex items-center gap-1 bg-blue-50 px-3 py-1.5 rounded-lg border border-blue-100 cursor-default font-bold">
<i data-lucide="users" className="w-4 h-4 text-blue-600"></i> 회원관리
</a>
<a href="../etax/barobill_api_info.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="book-open" className="w-4 h-4 text-orange-500"></i> API정보
</a>
<div className="flex items-center gap-2 text-sm text-slate-500 font-medium">
<div className="flex bg-slate-100/50 p-1 rounded-xl border border-slate-200/50 mr-2">
<a href="../eaccount/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="wallet" className="w-4 h-4 text-blue-500"></i> <span>계좌조회</span>
</a>
<a href="../ecard/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="credit-card" className="w-4 h-4 text-purple-500"></i> <span>카드내역</span>
</a>
<a href="../tenant/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="building" className="w-4 h-4 text-teal-500"></i> <span>테넌트</span>
</a>
<a href="index.php" className="flex items-center gap-4 px-4 py-2 rounded-lg bg-white text-blue-600 shadow-sm border border-blue-100 font-bold transition-all">
<i data-lucide="users" className="w-4 h-4 text-blue-600"></i> <span>바로빌 회원관리</span>
</a>
<button onClick={(e) => { e.preventDefault(); onOpenApiInfo(); }} className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="book-open" className="w-4 h-4 text-orange-500"></i> <span>API정보</span>
</button>
</div>
<div className="h-4 w-px bg-slate-200 mx-2"></div>
<a href="../barobill/index.php" className="hover:text-blue-700 flex items-center gap-1">
<i data-lucide="layout-dashboard" className="w-4 h-4"></i> 현황
<a href="../index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-blue-600 transition-colors">
<i data-lucide="layout-dashboard" className="w-4 h-4"></i> <span className="hidden lg:inline text-xs">현황</span>
</a>
<a href="../etax/index.php" className="hover:text-blue-700 flex items-center gap-1">
<i data-lucide="file-text" className="w-4 h-4"></i> 세금계산서
<a href="../etax/index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-blue-600 transition-colors">
<i data-lucide="file-text" className="w-4 h-4"></i> <span className="hidden lg:inline text-xs">세금계산서</span>
</a>
<a href="../index.php" className="hover:text-blue-700 flex items-center gap-1">
<i data-lucide="home" className="w-4 h-4"></i>
<a href="../../index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-blue-600 transition-colors">
<i data-lucide="home" className="w-4 h-4"></i> <span className="hidden lg:inline text-xs"></span>
</a>
</div>
</div>
@@ -191,21 +197,40 @@
);
};
const Modal = ({ isOpen, onClose, title, children }) => {
const Modal = ({ isOpen, onClose, title, children, maxWidth = "max-w-2xl" }) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-sm">
<div className="bg-white rounded-2xl w-full max-w-2xl overflow-hidden shadow-2xl">
<div className="p-4 border-b border-slate-100 flex justify-between items-center">
<h3 className="font-bold text-slate-800">{title}</h3>
<button onClick={onClose} className="p-2 text-slate-400 hover:text-slate-600"><i data-lucide="x" className="w-5 h-5"></i></button>
<div className={`bg-white rounded-2xl w-full ${maxWidth} overflow-hidden shadow-2xl animate-in fade-in zoom-in-95 duration-200`}>
<div className="p-4 border-b border-slate-100 flex justify-between items-center bg-slate-50/50">
<h3 className="font-bold text-slate-800 flex items-center gap-2">
<span className="w-1.5 h-6 bg-blue-500 rounded-full"></span>
{title}
</h3>
<button onClick={onClose} className="w-10 h-10 flex items-center justify-center rounded-full text-slate-600 hover:text-slate-900 hover:bg-slate-200 transition-all duration-200 bg-white/50 shadow-sm border border-slate-200">
<i data-lucide="x" className="w-6 h-6"></i>
</button>
</div>
<div className="p-6 overflow-y-auto max-h-[80vh]">{children}</div>
<div className="p-0 overflow-y-auto max-h-[85vh]">{children}</div>
</div>
</div>
);
};
const ApiInfoModal = ({ isOpen, onClose }) => {
return (
<Modal isOpen={isOpen} onClose={onClose} title="바로빌 API 상세 정보" maxWidth="max-w-5xl">
<div className="relative w-full h-[700px] bg-slate-50">
<iframe
src="../etax/barobill_api_info.php"
className="w-full h-full border-none"
title="API Information"
/>
</div>
</Modal>
);
};
// --- Main App ---
const App = () => {
@@ -213,6 +238,7 @@
const [loading, setLoading] = useState(true);
const [activeTab, setActiveTab] = useState('list');
const [editingMember, setEditingMember] = useState(null);
const [isApiInfoModalOpen, setIsApiInfoModalOpen] = useState(false);
// Auto-fill feature states
const [registerKey, setRegisterKey] = useState(0);
@@ -246,7 +272,7 @@
useEffect(() => {
setTimeout(() => lucide.createIcons(), 100);
}, [activeTab, members, editingMember]);
}, [activeTab, members, editingMember, isApiInfoModalOpen]);
const handleRegister = async (data) => {
try {
@@ -300,7 +326,7 @@
return (
<div className="min-h-screen">
<Header />
<Header onOpenApiInfo={() => setIsApiInfoModalOpen(true)} />
<main className="max-w-7xl mx-auto px-4 lg:px-8 py-8">
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
@@ -422,6 +448,11 @@
onCancel={() => setEditingMember(null)}
/>
</Modal>
<ApiInfoModal
isOpen={isApiInfoModalOpen}
onClose={() => setIsApiInfoModalOpen(false)}
/>
</main>
<footer className="mt-20 py-8 border-t border-slate-100 text-center">

View File

@@ -1,9 +1,9 @@
<?php
try {
if (!file_exists("../lib/mydb.php")) {
throw new Exception("Required library file ../lib/mydb.php not found.");
if (!file_exists("../../lib/mydb.php")) {
throw new Exception("Required library file ../../lib/mydb.php not found.");
}
require_once("../lib/mydb.php");
require_once("../../lib/mydb.php");
$pdo = db_connect();

View File

@@ -1,6 +1,6 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
include '../lib/mydb.php';
include '../../lib/mydb.php';
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');

View File

@@ -68,39 +68,45 @@ require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
const { useState, useEffect, useRef } = React;
// --- Header Component ---
const Header = () => (
<header className="bg-white border-b border-gray-100 sticky top-0 z-50 transition-all">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center text-white shadow-sm">
const Header = ({ onOpenApiInfo }) => (
<header className="bg-white/80 backdrop-blur-md border-b border-blue-100/50 sticky top-0 z-50 transition-all shadow-sm">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-18 flex items-center justify-between py-3">
<div className="flex items-center gap-4">
<div className="w-10 h-10 bg-gradient-to-br from-blue-600 to-indigo-700 rounded-xl flex items-center justify-center text-white shadow-lg shadow-blue-200/50 ring-4 ring-blue-50">
<i data-lucide="building" className="w-5 h-5"></i>
</div>
<h1 className="text-lg font-semibold text-slate-900">바로빌 테넌트 관리</h1>
<div>
<h1 className="text-lg font-bold text-slate-900 tracking-tight leading-none">테넌트 관리</h1>
<p className="text-[10px] text-blue-600 font-semibold mt-1 uppercase tracking-wider opacity-70">Tenant Configuration</p>
</div>
</div>
<div className="flex items-center gap-4 text-sm text-slate-500 font-medium">
<a href="../eaccount/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="wallet" className="w-4 h-4 text-blue-500"></i> 계좌조회
</a>
<a href="../ecard/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="credit-card" className="w-4 h-4 text-purple-500"></i> 카드내역
</a>
<a href="../tenant/index.php" className="text-blue-600 flex items-center gap-1 bg-blue-50 px-3 py-1.5 rounded-lg border border-blue-100 cursor-default font-bold">
<i data-lucide="building" className="w-4 h-4 text-blue-600"></i> 테넌트관리
</a>
<a href="../barobill_registration/index.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="users" className="w-4 h-4 text-teal-500"></i> 회원관리
</a>
<a href="../etax/barobill_api_info.php" className="hover:text-blue-600 flex items-center gap-1 bg-slate-50 hover:bg-slate-100 px-3 py-1.5 rounded-lg transition-colors border border-slate-100">
<i data-lucide="book-open" className="w-4 h-4 text-orange-500"></i> API정보
</a>
<div className="h-4 w-px bg-slate-200 mx-1"></div>
<div className="flex items-center gap-2 text-sm text-slate-500 font-medium">
<div className="flex bg-slate-100/50 p-1 rounded-xl border border-slate-200/50 mr-2">
<a href="../eaccount/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="wallet" className="w-4 h-4 text-blue-500"></i> <span>계좌조회</span>
</a>
<a href="../ecard/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="credit-card" className="w-4 h-4 text-purple-500"></i> <span>카드내역</span>
</a>
<a href="index.php" className="flex items-center gap-2 px-4 py-2 rounded-lg bg-white text-blue-600 shadow-sm border border-blue-100 font-bold">
<i data-lucide="building" className="w-4 h-4 text-blue-600"></i> <span>테넌트</span>
</a>
<a href="../registration/index.php" className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="users" className="w-4 h-4 text-teal-500"></i> <span>바로빌 회원관리</span>
</a>
<button onClick={(e) => { e.preventDefault(); onOpenApiInfo(); }} className="flex items-center gap-2 px-3 py-2 rounded-lg hover:text-blue-600 hover:bg-white transition-all duration-200">
<i data-lucide="book-open" className="w-4 h-4 text-orange-500"></i> <span>API정보</span>
</button>
</div>
<a href="../etax/index.php" className="hover:text-blue-700 flex items-center gap-1">
<i data-lucide="file-text" className="w-4 h-4"></i> 세금계산서
<div className="h-4 w-px bg-slate-200 mx-2"></div>
<a href="../etax/index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-blue-600 transition-colors">
<i data-lucide="file-text" className="w-4 h-4"></i> <span className="hidden lg:inline text-xs">세금계산서</span>
</a>
<a href="../index.php" className="hover:text-blue-700 flex items-center gap-1">
<i data-lucide="home" className="w-4 h-4"></i>
<a href="../../index.php" className="flex items-center gap-1.5 px-3 py-2 text-slate-400 hover:text-blue-600 transition-colors">
<i data-lucide="home" className="w-4 h-4"></i> <span className="hidden lg:inline text-xs"></span>
</a>
</div>
</div>
@@ -138,6 +144,7 @@ require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
const [isAccountModalOpen, setIsAccountModalOpen] = useState(false);
const [selectedCompanyForAccounts, setSelectedCompanyForAccounts] = useState(null);
const [isApiInfoModalOpen, setIsApiInfoModalOpen] = useState(false);
useEffect(() => {
fetchCompanies();
@@ -146,7 +153,7 @@ require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
useEffect(() => {
lucide.createIcons();
}, [companies, isCompanyModalOpen, isCardModalOpen, isAccountModalOpen]);
}, [companies, isCompanyModalOpen, isCardModalOpen, isAccountModalOpen, isApiInfoModalOpen]);
const fetchCompanies = async () => {
try {
@@ -167,7 +174,7 @@ require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
return (
<div className="flex flex-col h-full bg-gray-50">
<Header />
<Header onOpenApiInfo={() => setIsApiInfoModalOpen(true)} />
<main className="flex-1 overflow-auto p-4 sm:p-6 lg:p-8">
<div className="max-w-7xl mx-auto">
@@ -269,6 +276,11 @@ require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
company={selectedCompanyForAccounts}
/>}
<ApiInfoModal
isOpen={isApiInfoModalOpen}
onClose={() => setIsApiInfoModalOpen(false)}
/>
</div>
);
};
@@ -500,6 +512,32 @@ require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
);
};
const ApiInfoModal = ({ isOpen, onClose }) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/40 backdrop-blur-sm">
<div className="bg-white rounded-2xl w-full max-w-5xl overflow-hidden shadow-2xl animate-in fade-in zoom-in-95 duration-200">
<div className="p-4 border-b border-slate-100 flex justify-between items-center bg-slate-50/50">
<h3 className="font-bold text-slate-800 flex items-center gap-2">
<span className="w-1.5 h-6 bg-blue-500 rounded-full"></span>
바로빌 API 상세 정보
</h3>
<button onClick={onClose} className="w-10 h-10 flex items-center justify-center rounded-full text-slate-600 hover:text-slate-900 hover:bg-slate-200 transition-all duration-200 bg-white/50 shadow-sm border border-slate-200">
<i data-lucide="x" className="w-6 h-6"></i>
</button>
</div>
<div className="relative w-full h-[700px] bg-slate-50">
<iframe
src="../etax/barobill_api_info.php"
className="w-full h-full border-none"
title="API Information"
/>
</div>
</div>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>

148
company/index.php Normal file
View File

@@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>기업 분석 리스트 | SAM Sales</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
body { font-family: 'Inter', 'Noto Sans KR', sans-serif; }
.glass-card {
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(8px);
border: 1px solid rgba(226, 232, 240, 0.8);
}
.shard-glow:hover {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.1);
border-color: rgba(59, 130, 246, 0.3);
}
</style>
</head>
<body class="bg-slate-50 min-h-screen">
<!-- Navigation -->
<nav class="sticky top-0 z-40 w-full border-b bg-white/80 backdrop-blur-md">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex h-16 items-center justify-between">
<div class="flex items-center gap-2">
<div class="bg-blue-600 p-1.5 rounded-lg shadow-sm">
<i data-lucide="layout-dashboard" class="text-white w-5 h-5"></i>
</div>
<span class="font-bold text-slate-900 tracking-tight">SAM Corporate Analysis</span>
</div>
<div class="flex items-center gap-4">
<a href="../index.php" class="text-sm font-medium text-slate-500 hover:text-slate-900 transition-colors">홈으로</a>
</div>
</div>
</div>
</nav>
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-10">
<!-- Hero Section -->
<div class="mb-12">
<h1 class="text-3xl font-bold tracking-tight text-slate-900 mb-2">기업 분석 라이브러리</h1>
<p class="text-slate-500 max-w-2xl">
다양한 산업군의 주요 기업들에 대한 심층적인 재무, 성장, 경쟁 분석 리포트를 확인하고 비즈니스 인사이트를 얻으세요.
</p>
</div>
<!-- Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Loudsourcing Card -->
<a href="loudsourcing/index.php" class="group">
<div class="bg-white rounded-xl border border-slate-200 p-6 flex flex-col h-full transition-all duration-300 hover:shadow-lg hover:border-blue-200 shard-glow relative overflow-hidden">
<div class="absolute top-0 right-0 w-24 h-24 bg-blue-50 -mr-12 -mt-12 rounded-full transition-transform group-hover:scale-110"></div>
<div class="mb-4 flex items-center justify-between relative">
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center text-blue-600">
<i data-lucide="palette" class="w-6 h-6"></i>
</div>
<span class="inline-flex items-center rounded-full bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10">IT/디자인</span>
</div>
<h3 class="text-xl font-bold text-slate-900 mb-2">라우드소싱 (LOUDSOURCING)</h3>
<p class="text-slate-500 text-sm mb-6 flex-grow">
국내 최대 디자인 크라우드소싱 플랫폼. 디자이너와 기업을 연결하는 혁신적인 콘테스트 기반 비즈니스 모델.
</p>
<div class="flex items-center text-blue-600 text-sm font-semibold mt-auto">
분석 리포트 보기
<i data-lucide="arrow-right" class="w-4 h-4 ml-1 transition-transform group-hover:translate-x-1"></i>
</div>
</div>
</a>
<!-- PeopleLife Card -->
<a href="peoplelife/index.php" class="group">
<div class="bg-white rounded-xl border border-slate-200 p-6 flex flex-col h-full transition-all duration-300 hover:shadow-lg hover:border-blue-200 shard-glow relative overflow-hidden">
<div class="absolute top-0 right-0 w-24 h-24 bg-indigo-50 -mr-12 -mt-12 rounded-full transition-transform group-hover:scale-110"></div>
<div class="mb-4 flex items-center justify-between relative">
<div class="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center text-indigo-600">
<i data-lucide="shield-check" class="w-6 h-6"></i>
</div>
<span class="inline-flex items-center rounded-full bg-indigo-50 px-2 py-1 text-xs font-medium text-indigo-700 ring-1 ring-inset ring-indigo-700/10">금융/GA</span>
</div>
<h3 class="text-xl font-bold text-slate-900 mb-2">피플라이프 (PeopleLife)</h3>
<p class="text-slate-500 text-sm mb-6 flex-grow">
대한민국 대표 초대형 GA. 법인 컨설팅의 전문성을 바탕으로 O2O 플랫폼 보험클리닉을 운영하는 보험 금융 그룹.
</p>
<div class="flex items-center text-indigo-600 text-sm font-semibold mt-auto">
분석 리포트 보기
<i data-lucide="arrow-right" class="w-4 h-4 ml-1 transition-transform group-hover:translate-x-1"></i>
</div>
</div>
</a>
<!-- Looka vs Brandmark Card -->
<a href="looka/index.php" class="group">
<div class="bg-white rounded-xl border border-slate-200 p-6 flex flex-col h-full transition-all duration-300 hover:shadow-lg hover:border-blue-200 shard-glow relative overflow-hidden">
<div class="absolute top-0 right-0 w-24 h-24 bg-purple-50 -mr-12 -mt-12 rounded-full transition-transform group-hover:scale-110"></div>
<div class="mb-4 flex items-center justify-between relative">
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center text-purple-600">
<i data-lucide="sparkles" class="w-6 h-6"></i>
</div>
<span class="inline-flex items-center rounded-full bg-purple-50 px-2 py-1 text-xs font-medium text-purple-700 ring-1 ring-inset ring-purple-700/10">AI/디자인</span>
</div>
<h3 class="text-xl font-bold text-slate-900 mb-2">Looka vs Brandmark</h3>
<p class="text-slate-500 text-sm mb-6 flex-grow">
AI 기반 로고 디자인 비교. 비용, 기능, 서비스 규모를 바탕으로 비즈니스에 최적화된 로고 제작 도구를 추천합니다.
</p>
<div class="flex items-center text-purple-600 text-sm font-semibold mt-auto">
비교 결과 보기
<i data-lucide="arrow-right" class="w-4 h-4 ml-1 transition-transform group-hover:translate-x-1"></i>
</div>
</div>
</a>
<!-- Placeholder for future addition -->
<div class="bg-white rounded-xl border border-dashed border-slate-300 p-6 flex flex-col items-center justify-center h-full text-slate-400 group">
<div class="w-12 h-12 rounded-lg border border-dashed border-slate-300 flex items-center justify-center mb-4 group-hover:bg-slate-50 transition-colors">
<i data-lucide="plus" class="w-6 h-6"></i>
</div>
<p class="text-sm font-medium">새로운 기업 추가 예정</p>
</div>
</div>
</main>
<footer class="border-t bg-white mt-20 py-10">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center text-slate-400 text-sm">
<p>&copy; 2026 SAM Corporate Analysis Dashboard. All rights reserved.</p>
</div>
</footer>
<script>
// Initialize Lucide Icons
lucide.createIcons();
</script>
</body>
</html>

266
company/looka/index.php Normal file
View File

@@ -0,0 +1,266 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Looka vs Brandmark 비교 분석</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
* { font-family: 'Noto Sans KR', sans-serif; }
.tab-content { display: none; }
.tab-content.active { display: block; }
.nav-active { background-color: #2563eb; color: white; shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); }
.fade-in { animation: fadeIn 0.5s ease-out forwards; }
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body class="min-h-screen bg-gradient-to-br from-slate-50 to-indigo-50 p-6">
<div class="max-w-5xl mx-auto">
<!-- Header -->
<div class="bg-white rounded-2xl shadow-lg p-8 mb-6 fade-in">
<div class="flex items-center gap-4 mb-4">
<div class="w-16 h-16 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-xl flex items-center justify-center">
<i data-lucide="sparkles" class="text-white w-8 h-8"></i>
</div>
<div>
<h1 class="text-3xl font-bold text-gray-800">Looka vs Brandmark</h1>
<p class="text-gray-500">생성형 AI 기반 로고 디자인 플랫폼 비교 분석</p>
</div>
</div>
<p class="text-gray-600 leading-relaxed">
디자인 전문 지식 없이도 고품질 로고와 브랜드 키트를 제작할 있는 대표적인 AI 디자인 툴입니다.
Looka의 범용성과 Brandmark의 창의성을 중심으로 비즈니스 목적에 맞는 최적의 선택을 제안합니다.
</p>
</div>
<!-- Summary Metrics -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div class="bg-white rounded-xl shadow-md p-5 border-l-4 border-indigo-500 fade-in" style="animation-delay: 0.1s">
<div class="flex items-center gap-2 text-indigo-600 mb-2">
<i data-lucide="users" size="20"></i>
<span class="text-sm font-medium">Looka 인기</span>
</div>
<p class="text-2xl font-bold text-gray-800">2,000+</p>
<p class="text-xs text-gray-500">글로벌 압도적 1</p>
</div>
<div class="bg-white rounded-xl shadow-md p-5 border-l-4 border-green-500 fade-in" style="animation-delay: 0.2s">
<div class="flex items-center gap-2 text-green-600 mb-2">
<i data-lucide="dollar-sign" size="20"></i>
<span class="text-sm font-medium">최저 비용</span>
</div>
<p class="text-2xl font-bold text-gray-800">$20~</p>
<p class="text-xs text-gray-500">전문가 외주 대비 저렴</p>
</div>
<div class="bg-white rounded-xl shadow-md p-5 border-l-4 border-amber-500 fade-in" style="animation-delay: 0.3s">
<div class="flex items-center gap-2 text-amber-600 mb-2">
<i data-lucide="thumbs-up" size="20"></i>
<span class="text-sm font-medium">추천 선택</span>
</div>
<p class="text-2xl font-bold text-gray-800">Looka</p>
<p class="text-xs text-gray-500">종합 완성도 9/10</p>
</div>
</div>
<!-- Tab Navigation -->
<div class="flex gap-2 mb-6 overflow-x-auto">
<button onclick="showTab('popular')" id="tab-popular" class="tab-btn px-5 py-2.5 rounded-lg font-medium transition-all whitespace-nowrap nav-active">인기 & 규모</button>
<button onclick="showTab('pricing')" id="tab-pricing" class="tab-btn px-5 py-2.5 rounded-lg font-medium transition-all whitespace-nowrap bg-white text-gray-600 hover:bg-gray-100">가격 비교</button>
<button onclick="showTab('strength')" id="tab-strength" class="tab-btn px-5 py-2.5 rounded-lg font-medium transition-all whitespace-nowrap bg-white text-gray-600 hover:bg-gray-100">강점 & 약점</button>
<button onclick="showTab('recommend')" id="tab-recommend" class="tab-btn px-5 py-2.5 rounded-lg font-medium transition-all whitespace-nowrap bg-white text-gray-600 hover:bg-gray-100">최종 추천</button>
</div>
<!-- Tab Content -->
<div class="bg-white rounded-2xl shadow-lg p-6 min-h-[400px]">
<!-- Popularity Tab -->
<div id="popular" class="tab-content active space-y-6">
<h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
<i data-lucide="bar-chart-3" class="text-indigo-600" size="24"></i>
인기도 사용자 규모
</h2>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="bg-slate-50 border-b">
<th class="p-4 text-left font-semibold text-slate-700">항목</th>
<th class="p-4 text-center font-bold text-indigo-600">Looka</th>
<th class="p-4 text-center font-semibold text-slate-700">Brandmark</th>
</tr>
</thead>
<tbody class="divide-y">
<tr>
<td class="p-4 font-medium text-slate-600 text-center">사용자 </td>
<td class="p-4 text-center font-semibold text-slate-900">2,000만명 이상</td>
<td class="p-4 text-center text-slate-500">상대적으로 적음</td>
</tr>
<tr class="bg-slate-50/50">
<td class="p-4 font-medium text-slate-600 text-center">Trustpilot 리뷰</td>
<td class="p-4 text-center font-semibold text-slate-900">14,352</td>
<td class="p-4 text-center text-slate-500">리뷰 거의 없음</td>
</tr>
<tr>
<td class="p-4 font-medium text-slate-600 text-center">서비스 국가</td>
<td class="p-4 text-center font-semibold text-slate-900">188개국</td>
<td class="p-4 text-center text-slate-500">-</td>
</tr>
</tbody>
</table>
</div>
<div class="p-4 bg-indigo-50 rounded-xl border border-indigo-100 text-sm text-indigo-800">
<i data-lucide="info" class="inline-block w-4 h-4 mr-1 mb-0.5"></i>
<strong>결론:</strong> Looka가 압도적으로 인기 있고, 검증된 사용자 기반을 가지고 있습니다.
</div>
</div>
<!-- Pricing Tab -->
<div id="pricing" class="tab-content space-y-6">
<h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
<i data-lucide="tags" class="text-green-600" size="24"></i>
가격 플랜 비교
</h2>
<div class="grid md:grid-cols-2 gap-4">
<div class="bg-white border rounded-xl p-5 hover:border-indigo-300 transition-colors">
<h3 class="font-bold text-lg mb-4 text-slate-800">Looka</h3>
<ul class="space-y-3">
<li class="flex justify-between text-sm"><span>기본 로고 (저해상도 PNG)</span><span class="font-bold">$20</span></li>
<li class="flex justify-between text-sm"><span>프리미엄 (고해상도 + 벡터)</span><span class="font-bold">$65</span></li>
<li class="flex justify-between text-sm text-slate-500 italic"><span>브랜드 키트 (연간 구독)</span><span class="font-bold">$96~129/</span></li>
</ul>
</div>
<div class="bg-white border rounded-xl p-5 hover:border-indigo-300 transition-colors">
<h3 class="font-bold text-lg mb-4 text-slate-800">Brandmark</h3>
<ul class="space-y-3">
<li class="flex justify-between text-sm"><span>기초 플랜</span><span class="font-bold">$25</span></li>
<li class="flex justify-between text-sm"><span>디자이너 플랜 (벡터 포함)</span><span class="font-bold">$65</span></li>
<li class="flex justify-between text-sm"><span>엔터프라이즈 플랜</span><span class="font-bold">$175</span></li>
</ul>
</div>
</div>
<div class="p-4 bg-slate-50 rounded-xl text-sm text-slate-600">
전문가 평가에 따르면 서비스 모두 "심각한 브랜딩을 위해 가장 좋은 가치를 제공"하며, 특히 $65 플랜이 서비스 모두에서 가장 권장되는 선택입니다.
</div>
</div>
<!-- Strength Tab -->
<div id="strength" class="tab-content space-y-6">
<h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
<i data-lucide="award" class="text-amber-600" size="24"></i>
강점 약점 상세
</h2>
<div class="grid md:grid-cols-2 gap-6">
<!-- Looka -->
<div class="space-y-4">
<div class="bg-indigo-50 p-4 rounded-xl border border-indigo-100">
<h3 class="font-bold text-indigo-900 mb-2 flex items-center gap-2"><i data-lucide="check-circle" size="18"></i> Looka 강점</h3>
<ul class="text-sm text-indigo-800 space-y-1">
<li> 압도적으로 쉬운 인터페이스 (초보자용)</li>
<li> 빠르고 친절한 고객 지원 (주말 응대)</li>
<li> 종합 브랜드 패키지 (명함, SNS 에셋 )</li>
</ul>
</div>
<div class="bg-rose-50 p-4 rounded-xl border border-rose-100">
<h3 class="font-bold text-rose-900 mb-2 flex items-center gap-2"><i data-lucide="alert-circle" size="18"></i> Looka 약점</h3>
<ul class="text-sm text-rose-800 space-y-1">
<li> 기본 패키지가 다소 빈약 (저해상도)</li>
<li> 커스터마이징의 세부 조정 한계</li>
</ul>
</div>
</div>
<!-- Brandmark -->
<div class="space-y-4">
<div class="bg-emerald-50 p-4 rounded-xl border border-emerald-100">
<h3 class="font-bold text-emerald-900 mb-2 flex items-center gap-2"><i data-lucide="check-circle" size="18"></i> Brandmark 강점</h3>
<ul class="text-sm text-emerald-800 space-y-1">
<li> 1 결제 로직과 무제한 수정</li>
<li> 독창적인 생성형 AI 엔진</li>
<li> 미니멀하고 모던한 미학 특화</li>
</ul>
</div>
<div class="bg-amber-50 p-4 rounded-xl border border-amber-100">
<h3 class="font-bold text-amber-900 mb-2 flex items-center gap-2"><i data-lucide="alert-circle" size="18"></i> Brandmark 약점</h3>
<ul class="text-sm text-amber-800 space-y-1">
<li> 결과물이 때때로 지나치게 단순함</li>
<li> Looka 대비 제한적인 브랜드 </li>
<li> 시각적 감각이 부족하다는 평가 존재</li>
</ul>
</div>
</div>
</div>
</div>
<!-- Recommend Tab -->
<div id="recommend" class="tab-content space-y-6">
<h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
<i data-lucide="check-square" class="text-blue-600" size="24"></i>
상황별 최종 추천
</h2>
<div class="grid md:grid-cols-2 gap-4">
<div class="p-5 bg-gradient-to-br from-indigo-50 to-white border border-indigo-200 rounded-2xl shadow-sm">
<h3 class="text-lg font-bold text-indigo-900 mb-3"> Looka를 추천하는 경우</h3>
<ul class="text-sm text-indigo-700 space-y-2">
<li class="flex items-start gap-2"><i data-lucide="arrow-right-circle" class="w-4 h-4 mt-0.5 flex-shrink-0"></i> 기업용 종합 마케팅 자료가 필요한 경우</li>
<li class="flex items-start gap-2"><i data-lucide="arrow-right-circle" class="w-4 h-4 mt-0.5 flex-shrink-0"></i> 검증된 서비스와 안정적인 지원을 선호하는 경우</li>
<li class="flex items-start gap-2"><i data-lucide="arrow-right-circle" class="w-4 h-4 mt-0.5 flex-shrink-0"></i> 디자인 경험이 전무하여 최고의 UI를 원하는 경우</li>
</ul>
</div>
<div class="p-5 bg-gradient-to-br from-indigo-50 to-white border border-indigo-200 rounded-2xl shadow-sm">
<h3 class="text-lg font-bold text-indigo-900 mb-3"> Brandmark를 추천하는 경우</h3>
<ul class="text-sm text-indigo-700 space-y-2">
<li class="flex items-start gap-2"><i data-lucide="arrow-right-circle" class="w-4 h-4 mt-0.5 flex-shrink-0"></i> 1회성 결제로 평생 수정을 원하는 경우</li>
<li class="flex items-start gap-2"><i data-lucide="arrow-right-circle" class="w-4 h-4 mt-0.5 flex-shrink-0"></i> 더욱 독창적이고 미니멀한 로고를 찾는 경우</li>
<li class="flex items-start gap-2"><i data-lucide="arrow-right-circle" class="w-4 h-4 mt-0.5 flex-shrink-0"></i> 예산이 극도로 제한적인 경우 ($25 플랜)</li>
</ul>
</div>
</div>
<div class="mt-8 bg-slate-900 rounded-2xl p-6 text-white text-center">
<h3 class="text-xl font-bold mb-3 flex items-center justify-center gap-2">
<i data-lucide="lightbulb" class="text-amber-400"></i>
Antigravity의 마디
</h3>
<p class="text-indigo-100 text-sm leading-relaxed max-w-2xl mx-auto">
"먼저 **Looka**에서 무료로 로고를 생성해 보세요. 다운로드 전까지는 비용이 들지 않으므로 시안의 품질을 직접 확인할 수 있습니다.
폰트나 컬러 조합이 마음에 든다면 $20 기본 패키지로 방향성을 잡고, 필요 시 프리미엄으로 업그레이드하는 전략이 가장 효율적입니다."
</p>
</div>
</div>
</div>
<!-- Footer -->
<div class="mt-6 text-center text-sm text-gray-500">
<p>데이터 출처: Fahimai, Trustpilot, 공식 홈페이지 </p>
<p>분석 기준일: 2026 1</p>
</div>
</div>
<script>
// Lucide 아이콘 렌더링
lucide.createIcons();
// 탭 전환 기능
function showTab(tabId) {
// 모든 탭 컨텐츠 숨기기
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
// 선택된 탭 컨텐츠 보이기
document.getElementById(tabId).classList.add('active');
// 탭 버튼 스타일 업데이트
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.classList.remove('nav-active');
btn.classList.add('bg-white', 'text-gray-600', 'hover:bg-gray-100');
});
const activeBtn = document.getElementById('tab-' + tabId);
activeBtn.classList.add('nav-active');
activeBtn.classList.remove('bg-white', 'text-gray-600', 'hover:bg-gray-100');
}
</script>
</body>
</html>

View File

@@ -0,0 +1,426 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>라우드소싱 (LOUDSOURCING) 기업분석</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
* { font-family: 'Noto Sans KR', sans-serif; }
.tab-content { display: none; }
.tab-content.active { display: block; }
.nav-active { background-color: #2563eb; color: white; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); }
.fade-in { animation: fadeIn 0.5s ease-out forwards; }
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body class="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 p-6">
<div class="max-w-5xl mx-auto">
<!-- Header -->
<div class="bg-white rounded-2xl shadow-lg p-8 mb-6 fade-in">
<div class="flex items-center gap-4 mb-4">
<div class="w-16 h-16 bg-gradient-to-br from-blue-500 to-purple-600 rounded-xl flex items-center justify-center">
<span class="text-white font-bold text-2xl">L</span>
</div>
<div>
<h1 class="text-3xl font-bold text-gray-800">라우드소싱 (LOUDSOURCING)</h1>
<p class="text-gray-500">운영사: 주식회사 스터닝 (STUNNING INC.)</p>
</div>
</div>
<p class="text-gray-600 leading-relaxed">
국내 최대 디자인 크라우드소싱 플랫폼으로, 디자이너와 기업을 연결하는 콘테스트 기반 비즈니스 모델을 운영합니다.
2020 포트폴리오 플랫폼 '노트폴리오' 합병하여 통합 크리에이티브 플랫폼으로 성장했습니다.
</p>
</div>
<!-- Key Metrics -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<div class="bg-white rounded-xl shadow-md p-5 fade-in" style="animation-delay: 0.1s">
<div class="flex items-center gap-2 text-blue-600 mb-2">
<i data-lucide="users" size="20"></i>
<span class="text-sm font-medium">등록 디자이너</span>
</div>
<p class="text-2xl font-bold text-gray-800">28만명</p>
<p class="text-xs text-gray-500">국내 디자이너 80%</p>
</div>
<div class="bg-white rounded-xl shadow-md p-5 fade-in" style="animation-delay: 0.2s">
<div class="flex items-center gap-2 text-green-600 mb-2">
<i data-lucide="dollar-sign" size="20"></i>
<span class="text-sm font-medium">2023 매출</span>
</div>
<p class="text-2xl font-bold text-gray-800">64.3</p>
<p class="text-xs text-gray-500"> 50~60% 성장</p>
</div>
<div class="bg-white rounded-xl shadow-md p-5 fade-in" style="animation-delay: 0.3s">
<div class="flex items-center gap-2 text-purple-600 mb-2">
<i data-lucide="briefcase" size="20"></i>
<span class="text-sm font-medium">임직원 </span>
</div>
<p class="text-2xl font-bold text-gray-800">43</p>
<p class="text-xs text-gray-500">2025 7 기준</p>
</div>
<div class="bg-white rounded-xl shadow-md p-5 fade-in" style="animation-delay: 0.4s">
<div class="flex items-center gap-2 text-orange-600 mb-2">
<i data-lucide="award" size="20"></i>
<span class="text-sm font-medium">누적 상금</span>
</div>
<p class="text-2xl font-bold text-gray-800">200+</p>
<p class="text-xs text-gray-500">콘테스트 2만건+</p>
</div>
</div>
<!-- Tab Navigation -->
<div class="flex gap-2 mb-6 overflow-x-auto">
<button onclick="showTab('overview')" id="tab-overview" class="tab-btn px-5 py-2.5 rounded-lg font-medium transition-all whitespace-nowrap nav-active">기업개요</button>
<button onclick="showTab('financial')" id="tab-financial" class="tab-btn px-5 py-2.5 rounded-lg font-medium transition-all whitespace-nowrap bg-white text-gray-600 hover:bg-gray-100">재무/성장</button>
<button onclick="showTab('history')" id="tab-history" class="tab-btn px-5 py-2.5 rounded-lg font-medium transition-all whitespace-nowrap bg-white text-gray-600 hover:bg-gray-100">연혁</button>
<button onclick="showTab('competition')" id="tab-competition" class="tab-btn px-5 py-2.5 rounded-lg font-medium transition-all whitespace-nowrap bg-white text-gray-600 hover:bg-gray-100">경쟁분석</button>
</div>
<!-- Tab Content -->
<div class="bg-white rounded-2xl shadow-lg p-6 min-h-[400px]">
<!-- Overview Tab -->
<div id="overview" class="tab-content active space-y-6">
<h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
<i data-lucide="building-2" class="text-blue-600" size="24"></i>
기업 개요
</h2>
<div class="grid md:grid-cols-2 gap-6">
<div class="space-y-4">
<h3 class="font-semibold text-gray-700 border-b pb-2">기본 정보</h3>
<div class="space-y-2 text-sm">
<div class="flex justify-between"><span class="text-gray-500">대표</span><span class="font-medium">김승환</span></div>
<div class="flex justify-between"><span class="text-gray-500">설립일</span><span class="font-medium">2011 6</span></div>
<div class="flex justify-between"><span class="text-gray-500">업력</span><span class="font-medium">14.2</span></div>
<div class="flex justify-between"><span class="text-gray-500">사업자번호</span><span class="font-medium">120-87-69298</span></div>
<div class="flex justify-between"><span class="text-gray-500">자본금</span><span class="font-medium">1 468만원</span></div>
<div class="flex justify-between"><span class="text-gray-500">기업형태</span><span class="font-medium">비상장 / 중소기업</span></div>
</div>
</div>
<div class="space-y-4">
<h3 class="font-semibold text-gray-700 border-b pb-2">소재지</h3>
<p class="text-sm text-gray-600">
서울특별시 강남구 선릉로 636,<br />
키스톤빌딩 3 302 (삼성동)
</p>
<h3 class="font-semibold text-gray-700 border-b pb-2 mt-4">운영 서비스</h3>
<div class="flex flex-wrap gap-2">
<span class="px-3 py-1 bg-blue-100 text-blue-700 rounded-full text-sm">라우드소싱</span>
<span class="px-3 py-1 bg-purple-100 text-purple-700 rounded-full text-sm">노트폴리오</span>
<span class="px-3 py-1 bg-green-100 text-green-700 rounded-full text-sm">스터닝 에이전시</span>
</div>
</div>
</div>
<div class="mt-6">
<h3 class="font-semibold text-gray-700 border-b pb-2 mb-4">비즈니스 모델</h3>
<div class="grid md:grid-cols-2 gap-4">
<div class="bg-gradient-to-r from-blue-50 to-blue-100 rounded-xl p-4">
<h4 class="font-semibold text-blue-800 mb-2">🏆 콘테스트</h4>
<p class="text-sm text-gray-600">의뢰자가 상금을 걸고 공모전 개최, 다수의 디자이너가 참여하여 경쟁</p>
</div>
<div class="bg-gradient-to-r from-purple-50 to-purple-100 rounded-xl p-4">
<h4 class="font-semibold text-purple-800 mb-2">🛒 라우드마켓</h4>
<p class="text-sm text-gray-600">1:1 직접 의뢰 방식, 원하는 디자이너를 선택해 프로젝트 진행</p>
</div>
<div class="bg-gradient-to-r from-green-50 to-green-100 rounded-xl p-4">
<h4 class="font-semibold text-green-800 mb-2">🤝 디자이너 매칭</h4>
<p class="text-sm text-gray-600">23만명 디자이너로부터 무료 비교견적 수령 가능</p>
</div>
<div class="bg-gradient-to-r from-orange-50 to-orange-100 rounded-xl p-4">
<h4 class="font-semibold text-orange-800 mb-2">🎯 에이전시</h4>
<p class="text-sm text-gray-600">전담 매니저가 프로젝트 매니징, 컨시어지 서비스 제공</p>
</div>
</div>
</div>
<div class="mt-6">
<h3 class="font-semibold text-gray-700 border-b pb-2 mb-4">주요 고객사</h3>
<div class="flex flex-wrap gap-2">
<?php
$clients = ['티몬', '농협', '포스코', '삼성 테크윈', '제주도 개발공사', '바카디코리아', '잡코리아', '도미노피자', 'BC카드', 'LG그램'];
foreach($clients as $client) {
echo '<span class="px-3 py-1 bg-gray-100 text-gray-700 rounded-lg text-sm">'.$client.'</span>';
}
?>
</div>
</div>
</div>
<!-- Financial Tab -->
<div id="financial" class="tab-content space-y-6">
<h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
<i data-lucide="trending-up" class="text-green-600" size="24"></i>
재무 및 성장 현황
</h2>
<div class="bg-gradient-to-r from-green-50 to-emerald-50 rounded-xl p-6">
<h3 class="font-semibold text-gray-700 mb-4">매출 추이</h3>
<div class="flex items-end justify-around h-40 mb-4">
<div class="flex flex-col items-center">
<div class="bg-green-400 w-16 rounded-t-lg" style="height: 51%"></div>
<span class="text-xs mt-2 text-gray-600">2020년</span>
<span class="text-sm font-bold">33억+</span>
</div>
<div class="flex flex-col items-center">
<div class="bg-green-500 w-16 rounded-t-lg" style="height: 100%"></div>
<span class="text-xs mt-2 text-gray-600">2023년</span>
<span class="text-sm font-bold">64.3억</span>
</div>
</div>
<p class="text-sm text-gray-600 text-center">연평균 50~60% 성장률 유지</p>
</div>
<div class="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-xl p-6">
<h3 class="font-semibold text-gray-700 mb-4">직원 수 변화</h3>
<div class="flex items-end justify-around h-32 mb-4">
<div class="flex flex-col items-center">
<div class="bg-blue-400 w-16 rounded-t-lg" style="height: 28%"></div>
<span class="text-xs mt-2 text-gray-600">2020년</span>
<span class="text-sm font-bold">12명</span>
</div>
<div class="flex flex-col items-center">
<div class="bg-blue-500 w-16 rounded-t-lg" style="height: 100%"></div>
<span class="text-xs mt-2 text-gray-600">2025년</span>
<span class="text-sm font-bold">43명</span>
</div>
</div>
<p class="text-sm text-gray-600 text-center">5년간 약 3.5배 인력 확대</p>
</div>
<div>
<h3 class="font-semibold text-gray-700 border-b pb-2 mb-4">투자 유치 현황</h3>
<div class="space-y-3">
<div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
<div>
<span class="font-medium">Series A</span>
<span class="text-gray-500 text-sm ml-2">2020년 3월</span>
</div>
<span class="font-bold text-green-600">20억원</span>
</div>
<div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg">
<div>
<span class="font-medium">Series A Bridge</span>
<span class="text-gray-500 text-sm ml-2">2021년 9월</span>
</div>
<span class="font-bold text-green-600">60억원</span>
</div>
<div class="flex items-center justify-between p-4 bg-blue-50 rounded-lg border-2 border-blue-200">
<span class="font-semibold">누적 투자금</span>
<span class="font-bold text-blue-600 text-lg">60~80억원</span>
</div>
</div>
<div class="mt-4 p-4 bg-gray-100 rounded-lg text-sm text-gray-600">
<strong>투자사:</strong> DSC 인베스트먼트, 미래에셋벤처투자, 나이스투자파트너스, KDB캐피탈, 신한캐피탈
</div>
</div>
<div>
<h3 class="font-semibold text-gray-700 border-b pb-2 mb-4">핵심 성장 지표</h3>
<div class="grid md:grid-cols-3 gap-4">
<div class="text-center p-4 bg-purple-50 rounded-xl">
<p class="text-3xl font-bold text-purple-600">3.7배</p>
<p class="text-sm text-gray-600">MAU 증가 (2년간)</p>
</div>
<div class="text-center p-4 bg-blue-50 rounded-xl">
<p class="text-3xl font-bold text-blue-600">2.5배</p>
<p class="text-sm text-gray-600">디자이너 수 증가</p>
</div>
<div class="text-center p-4 bg-green-50 rounded-xl">
<p class="text-3xl font-bold text-green-600">2.7배</p>
<p class="text-sm text-gray-600">등록 작품 수 증가</p>
</div>
</div>
</div>
</div>
<!-- History Tab -->
<div id="history" class="tab-content space-y-6">
<h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
<i data-lucide="calendar" class="text-purple-600" size="24"></i>
성장 연혁
</h2>
<div class="relative">
<div class="absolute left-4 top-0 bottom-0 w-0.5 bg-gradient-to-b from-blue-500 to-purple-500"></div>
<?php
$history = [
['year' => '2011', 'title' => '창업', 'desc' => '(주)라우더스 창업, 라우드소싱 론칭', 'color' => 'blue'],
['year' => '2012', 'title' => '노트폴리오 설립', 'desc' => '디자이너 포트폴리오 커뮤니티 시작', 'color' => 'purple'],
['year' => '2017', 'title' => '벤처기업 인증', 'desc' => '기술혁신형 벤처기업 인증 획득', 'color' => 'green'],
['year' => '2020.03', 'title' => 'Series A 투자', 'desc' => '20억원 투자 유치', 'color' => 'blue'],
['year' => '2020.09', 'title' => '합병 & 스터닝 설립', 'desc' => '라우드소싱 + 노트폴리오 합병', 'color' => 'purple'],
['year' => '2021', 'title' => 'Main-Biz 인증', 'desc' => '경영혁신형 중소기업 인증', 'color' => 'green'],
['year' => '2021.09', 'title' => 'Bridge 투자', 'desc' => '60억원 추가 투자 유치', 'color' => 'blue'],
['year' => '2022', 'title' => '라우드마켓 출시', 'desc' => '1:1 의뢰 서비스 런칭', 'color' => 'purple'],
['year' => '2022.하반기', 'title' => '에이전시 출시', 'desc' => '컨시어지 서비스 시작', 'color' => 'orange'],
['year' => '2023', 'title' => '매칭 서비스', 'desc' => '디자이너 매칭 서비스 런칭', 'color' => 'green'],
];
foreach($history as $idx => $item) {
$color = $item['color'];
echo '
<div class="relative pl-10 pb-6">
<div class="absolute left-2 w-5 h-5 rounded-full bg-'.$color.'-500 border-4 border-white shadow"></div>
<div class="bg-gray-50 rounded-lg p-4">
<div class="flex items-center gap-3 mb-1">
<span class="px-2 py-0.5 bg-'.$color.'-100 text-'.$color.'-700 rounded text-xs font-medium">
'.$item['year'].'
</span>
<span class="font-semibold text-gray-800">'.$item['title'].'</span>
</div>
<p class="text-sm text-gray-600">'.$item['desc'].'</p>
</div>
</div>';
}
?>
</div>
</div>
<!-- Competition Tab -->
<div id="competition" class="tab-content space-y-6">
<h2 class="text-xl font-bold text-gray-800 flex items-center gap-2">
<i data-lucide="target" class="text-orange-600" size="24"></i>
경쟁 분석
</h2>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="bg-gray-100">
<th class="p-3 text-left font-semibold">구분</th>
<th class="p-3 text-center font-semibold text-blue-600">라우드소싱</th>
<th class="p-3 text-center font-semibold">크몽</th>
<th class="p-3 text-center font-semibold">숨고</th>
</tr>
</thead>
<tbody>
<tr class="border-b">
<td class="p-3 font-medium">특화 분야</td>
<td class="p-3 text-center text-blue-600">디자인 전문</td>
<td class="p-3 text-center">종합 프리랜서</td>
<td class="p-3 text-center">생활 서비스</td>
</tr>
<tr class="border-b bg-gray-50">
<td class="p-3 font-medium">핵심 방식</td>
<td class="p-3 text-center text-blue-600">콘테스트/공모전</td>
<td class="p-3 text-center">판매자 상품 등록</td>
<td class="p-3 text-center">요청서 기반 견적</td>
</tr>
<tr class="border-b">
<td class="p-3 font-medium">가격 결정</td>
<td class="p-3 text-center text-blue-600">의뢰자가 상금 설정</td>
<td class="p-3 text-center">판매자가 단가 설정</td>
<td class="p-3 text-center">고수가 견적 제시</td>
</tr>
<tr class="border-b bg-gray-50">
<td class="p-3 font-medium">수수료</td>
<td class="p-3 text-center text-blue-600">19.7%</td>
<td class="p-3 text-center">~20%</td>
<td class="p-3 text-center">포인트 차감</td>
</tr>
<tr>
<td class="p-3 font-medium">차별점</td>
<td class="p-3 text-center text-blue-600">다수 시안 비교</td>
<td class="p-3 text-center">빠른 매칭</td>
<td class="p-3 text-center">지역 기반</td>
</tr>
</tbody>
</table>
</div>
<div>
<h3 class="font-semibold text-gray-700 border-b pb-2 mb-4">SWOT 분석</h3>
<div class="grid md:grid-cols-2 gap-4">
<div class="bg-green-50 rounded-xl p-4">
<h4 class="font-semibold text-green-700 mb-3">💪 강점 (Strengths)</h4>
<ul class="text-sm text-gray-600 space-y-1">
<li>• 국내 디자이너 80% 점유율</li>
<li>• 14년 운영 노하우</li>
<li>• 다양한 시안 비교 가능</li>
<li>• 노트폴리오와 시너지</li>
</ul>
</div>
<div class="bg-red-50 rounded-xl p-4">
<h4 class="font-semibold text-red-700 mb-3">⚠️ 약점 (Weaknesses)</h4>
<ul class="text-sm text-gray-600 space-y-1">
<li>• 낙선 디자이너 보상 없음</li>
<li>• 수수료 부담 (19.7%)</li>
<li>• 콘테스트 방식 한계</li>
</ul>
</div>
<div class="bg-blue-50 rounded-xl p-4">
<h4 class="font-semibold text-blue-700 mb-3">🚀 기회 (Opportunities)</h4>
<ul class="text-sm text-gray-600 space-y-1">
<li>• 18조 국내 디자인 시장</li>
<li>• 프리랜서 경제 성장</li>
<li>• 아이디어 콘테스트 확장</li>
<li>• 기업 디자인 아웃소싱 증가</li>
</ul>
</div>
<div class="bg-orange-50 rounded-xl p-4">
<h4 class="font-semibold text-orange-700 mb-3">⚡ 위협 (Threats)</h4>
<ul class="text-sm text-gray-600 space-y-1">
<li>• AI 디자인 툴 부상</li>
<li>• Canva, 미리캔버스 등 경쟁</li>
<li>• 크몽, 숨고 등 플랫폼 경쟁</li>
</ul>
</div>
</div>
</div>
<div class="bg-gradient-to-r from-indigo-50 to-purple-50 rounded-xl p-6">
<h3 class="font-semibold text-gray-700 mb-3">시장 규모</h3>
<div class="grid md:grid-cols-2 gap-6">
<div class="text-center">
<p class="text-4xl font-bold text-indigo-600">18조원</p>
<p class="text-sm text-gray-600">국내 디자인 시장</p>
</div>
<div class="text-center">
<p class="text-4xl font-bold text-purple-600">1조원</p>
<p class="text-sm text-gray-600">국내 프리랜서 시장</p>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
<div class="mt-6 text-center text-sm text-gray-500">
<p>데이터 출처: THE VC, 혁신의숲, 원티드, 인크루트, 잡플래닛, 나무위키 등</p>
<p>분석 기준일: 2026년 1월</p>
</div>
</div>
<script>
// Lucide 아이콘 렌더링
lucide.createIcons();
// 탭 전환 기능
function showTab(tabId) {
// 모든 탭 컨텐츠 숨기기
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
// 선택된 탭 컨텐츠 보이기
document.getElementById(tabId).classList.add('active');
// 탭 버튼 스타일 업데이트
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.classList.remove('nav-active');
btn.classList.add('bg-white', 'text-gray-600', 'hover:bg-gray-100');
});
const activeBtn = document.getElementById('tab-' + tabId);
activeBtn.classList.add('nav-active');
activeBtn.classList.remove('bg-white', 'text-gray-600', 'hover:bg-gray-100');
}
</script>
</body>
</html>

View File

@@ -12,8 +12,7 @@
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
<link rel="shortcut icon" href="img/favicon.png">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<?php include_once 'lib/meta_common.php'; ?>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans+KR:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
@@ -120,17 +119,6 @@
display: block;
box-shadow: 0 0 50px rgba(0,0,0,0.5);
}
.fullscreen-close {
position: fixed;
top: 1.5rem;
right: 1.5rem;
z-index: 110;
background: white;
border-radius: 9999px;
padding: 0.75rem;
cursor: pointer;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
}
/* Mobile touch optimization */
.touch-manipulation {
@@ -216,6 +204,9 @@
<a href="creditreport/index.php" class="block px-4 py-2 text-sm text-slate-700 hover:bg-brand-50 hover:text-brand-600 font-medium">
기업신용조회 리포트
</a>
<a href="company/index.php" class="block px-4 py-2 text-sm text-slate-700 hover:bg-brand-50 hover:text-brand-600 font-medium">
기타 기업분석자료
</a>
</div>
</div>
<?php if (isset($_SESSION['userid']) && $_SESSION['userid'] != ''): ?>
@@ -346,10 +337,9 @@
<!-- Modal Content injected by JS -->
</div>
<!-- Full Screen Viewer Overlay -->
<div id="fullscreen-view" onclick="closeFullscreen()">
<div class="fullscreen-close">
<i data-lucide="x" class="w-6 h-6 text-slate-900"></i>
<div class="fullscreen-close btn-close-modal group">
<span>✕</span>
</div>
<img id="fullscreen-img" src="" alt="Full size view" onclick="event.stopPropagation()">
</div>
@@ -361,8 +351,8 @@
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-[95vw] h-[95vh] flex flex-col pointer-events-auto scale-95 opacity-0 transition-all duration-300" id="pdf-modal-card">
<div class="sticky top-0 bg-white/90 backdrop-blur-sm p-4 border-b border-slate-100 flex justify-between items-center z-10">
<h3 class="text-lg font-bold text-slate-900" id="pdf-modal-title">상세자료</h3>
<button onclick="closePdfViewer()" class="w-8 h-8 rounded-full bg-slate-50 hover:bg-slate-100 flex items-center justify-center text-slate-500 transition-colors">
<i data-lucide="x" class="w-5 h-5"></i>
<button onclick="closePdfViewer()" class="btn-close-modal group">
<span>✕</span>
</button>
</div>
<div class="flex-1 overflow-hidden">
@@ -543,9 +533,10 @@
// Initial Render
function init() {
renderFilters();
renderGrid();
// Initial Lucide icons are handled by DOMContentLoaded in meta_common.php
// but we call it here for the dynamically rendered grid items
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
@@ -757,8 +748,8 @@
<div class="flex items-center gap-2">
<h3 class="text-base sm:text-lg font-bold text-slate-900 break-keep leading-tight" style="word-break: keep-all; overflow-wrap: break-word;">${asset.title}</h3>
</div>
<button onclick="closeModal()" class="w-8 h-8 rounded-full bg-slate-50 hover:bg-slate-100 flex items-center justify-center text-slate-500 transition-colors">
<i data-lucide="x" class="w-5 h-5"></i>
<button onclick="closeModal()" class="btn-close-modal group">
<span>✕</span>
</button>
</div>
@@ -1064,6 +1055,6 @@
// Initialize
init();
</script>
<script src="https://player.vimeo.com/api/player.js"></script>
</body>
</html>

33
lib/meta_common.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
/**
* Global Metadata and Shared Styles
* This file centralizes Tailwind CSS, Lucide Icons, React, and Babel scripts.
*/
?>
<!-- Core Libraries -->
<script src="https://cdn.tailwindcss.com?v=3.4.1"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script>
// Ensure Lucide icons are initialized after page load
document.addEventListener('DOMContentLoaded', () => {
if (window.lucide) {
window.lucide.createIcons();
}
});
</script>
<style type="text/tailwindcss">
@layer components {
/* Global Modal Close Button Style */
.btn-close-modal {
@apply w-10 h-10 flex items-center justify-center rounded-full bg-white shadow-lg border-2 border-slate-900 transition-all duration-200 hover:bg-red-50 hover:border-red-500 cursor-pointer pointer-events-auto;
}
.btn-close-modal span {
@apply text-xl font-bold text-black group-hover:text-red-600 select-none;
}
}
</style>

View File

@@ -11,52 +11,7 @@ if (file_exists('../session.php')) {
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>수당 계산기 | SAM</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans+KR:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'Noto Sans KR', 'sans-serif'],
},
colors: {
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
900: '#0c4a6e',
}
},
animation: {
blob: "blob 7s infinite",
'fade-in-up': 'fadeInUp 0.8s ease-out forwards',
},
keyframes: {
blob: {
"0%": { transform: "translate(0px, 0px) scale(1)" },
"33%": { transform: "translate(30px, -50px) scale(1.1)" },
"66%": { transform: "translate(-20px, 20px) scale(0.9)" },
"100%": { transform: "translate(0px, 0px) scale(1)" },
},
fadeInUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
}
},
}
}
}
</script>
<style>
.delay-100 { animation-delay: 100ms; }
.delay-200 { animation-delay: 200ms; }
.backdrop-blur-xl { backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); }
</style>
<?php require_once __DIR__ . '/../lib/meta_common.php'; ?>
</head>
<body class="bg-slate-50 text-slate-900 font-sans selection:bg-brand-200 selection:text-brand-900 overflow-x-hidden">
@@ -667,8 +622,8 @@ if (file_exists('../session.php')) {
<p class="text-xs text-slate-500">안전하고 투명한 AI 서비스 이용을 위한 안내</p>
</div>
</div>
<button onclick="closeTokenModal()" class="p-2 hover:bg-white rounded-xl transition-colors">
<i data-lucide="x" class="w-6 h-6 text-slate-400"></i>
<button onclick="closeTokenModal()" class="btn-close-modal group">
<span>✕</span>
</button>
</div>
@@ -748,8 +703,8 @@ if (file_exists('../session.php')) {
<p class="text-xs text-slate-500">패키지 구성 및 주요 기능을 확인하세요.</p>
</div>
</div>
<button onclick="closeInfoModal()" class="p-2 hover:bg-white rounded-xl transition-colors">
<i data-lucide="x" class="w-6 h-6 text-slate-400"></i>
<button onclick="closeInfoModal()" class="btn-close-modal group">
<span>✕</span>
</button>
</div>

View File

@@ -42,17 +42,25 @@
<!-- Fonts: Pretendard -->
<link rel="stylesheet" as="style" crossorigin href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.8/dist/web/static/pretendard.css" />
<?php require_once __DIR__ . '/../lib/meta_common.php'; ?>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com?v=3.4.1"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Pretendard', 'sans-serif'],
sans: ['Pretendard', 'Inter', 'Noto Sans KR', 'sans-serif'],
},
colors: {
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
900: '#0c4a6e',
},
background: 'rgb(250, 250, 250)',
primary: {
DEFAULT: '#2563eb', // blue-600
@@ -66,16 +74,6 @@
}
}
</script>
<!-- React & ReactDOM (Production Versions) -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js?v=18.2.0"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js?v=18.2.0"></script>
<!-- Babel for JSX -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Icons: Lucide React (via CDN is tricky, using simple SVG icons or a library wrapper if needed. For now, using text/simple SVGs) -->
<script src="https://unpkg.com/lucide@latest"></script>
</head>
<body class="bg-background text-slate-800 antialiased">
<div id="root"></div>
@@ -654,8 +652,8 @@
</button>
)}
</h3>
<button type="button" onClick={() => setIsModalOpen(false)} className="p-2 hover:bg-slate-200 rounded-full transition-colors text-slate-400">
<LucideIcon name="x" className="w-6 h-6" />
<button type="button" onClick={() => setIsModalOpen(false)} className="btn-close-modal group">
<span>✕</span>
</button>
</div>
@@ -807,8 +805,8 @@
</h3>
<p className="text-slate-500 mt-1">이 영업파트너에게 소속된 모든 매니저 목록입니다.</p>
</div>
<button onClick={() => setDetailModalUser(null)} className="p-2 hover:bg-slate-200 rounded-full transition-colors text-slate-400">
<LucideIcon name="x" className="w-6 h-6" />
<button onClick={() => setDetailModalUser(null)} className="btn-close-modal group">
<span>✕</span>
</button>
</div>
<div className="overflow-y-auto p-8">