Compare commits

..

8 Commits

Author SHA1 Message Date
Lectom C Han
d6a4443351 php 세션 유지 로직 수정 2026-02-05 13:15:54 +09:00
Lectom C Han
1cdfe27ef7 common.js 로그인 반영 개선 2026-02-05 13:07:39 +09:00
Lectom C Han
422991aaf5 세션 경로 하드코딩 제거 2026-02-05 12:53:59 +09:00
Lectom C Han
7034a3643a 리펙토링 #6 참고 2026-02-05 12:38:34 +09:00
Lectom C Han
46b30af839 라우팅 경로정리 & CDN용 정적파일 경로 추상화 2026-02-05 12:22:02 +09:00
Lectom C Han
8501529eb6 URI 중 /kngil/skin 반복제거. php 확장자 노출 제거 2026-02-05 12:09:12 +09:00
Lectom C Han
8fa50e6d0d .env 로딩방식 변경 2026-02-05 11:20:35 +09:00
Lectom C Han
6537a65d74 OIDC 변수 하드코딩 제거 2026-02-05 11:00:07 +09:00
68 changed files with 427 additions and 1067 deletions

View File

@@ -14,3 +14,7 @@ OIDC_CLIENT_SECRET=
OIDC_REDIRECT_URL= OIDC_REDIRECT_URL=
OIDC_SCOPES=openid profile email OIDC_SCOPES=openid profile email
IDP_SERVICE_URL= IDP_SERVICE_URL=
# 정적 자산 CDN (선택)
# 예: STATIC_CDN_BASE_URL=https://cdn.example.com/kngil
STATIC_CDN_BASE_URL=

View File

@@ -45,10 +45,5 @@ jobs:
${{ secrets.DEPLOY_ENV_FILE }} ${{ secrets.DEPLOY_ENV_FILE }}
ENVEOF ENVEOF
# Export variables from .env file
set -a
source .env
set +a
docker compose --env-file .env pull docker compose --env-file .env pull
docker compose --env-file .env up -d docker compose --env-file .env up -d

View File

@@ -42,11 +42,6 @@ jobs:
IDP_SERVICE_URL=${{ vars.IDP_SERVICE_URL }} IDP_SERVICE_URL=${{ vars.IDP_SERVICE_URL }}
ENVEOF ENVEOF
# Export variables from .env file
set -a
source .env
set +a
git fetch origin main git fetch origin main
git checkout -B main origin/main git checkout -B main origin/main
git pull --ff-only git pull --ff-only

View File

@@ -1,10 +1,57 @@
RewriteEngine On RewriteEngine On
# Skip existing files and directories. # /adm -> /admin (관리자 루프 방지)
RewriteRule ^adm/?$ /admin [R=301,L]
# 대소문자 혼용 경로 보정
RewriteRule ^(kngil/)?js/lib/ScrollToPlugin\.min\.js$ /js/lib/scrollToPlugin.min.js [R=301,L]
# 레거시 /kngil/skin/adm*.php -> /admin(/company)
RewriteCond %{THE_REQUEST} \s/+kngil/skin/adm_comp\.php [NC]
RewriteRule ^kngil/skin/adm_comp\.php$ /admin/company [R=301,L]
RewriteCond %{THE_REQUEST} \s/+kngil/skin/adm\.php [NC]
RewriteRule ^kngil/skin/adm\.php$ /admin [R=301,L]
# 레거시 /kngil/skin/index.php -> /
RewriteCond %{THE_REQUEST} \s/+kngil/skin/index\.php [NC]
RewriteRule ^kngil/skin/index\.php$ / [R=301,L]
# 레거시 /kngil/skin/*.skin.php -> /* (확장자 제거)
RewriteCond %{THE_REQUEST} \s/+kngil/skin/([^\s]+)\.skin\.php [NC]
RewriteRule ^kngil/skin/([^/]+)\.skin\.php$ /$1 [R=301,L]
# 레거시 /*.skin -> /* (확장자 제거)
RewriteCond %{THE_REQUEST} \s+/([^\s]+)\.skin [NC]
RewriteRule ^([^/]+)\.skin$ /$1 [R=301,L]
# 레거시 /kngil/*.skin -> /* (확장자 제거)
RewriteCond %{THE_REQUEST} \s/+kngil/([^\s]+)\.skin [NC]
RewriteRule ^kngil/([^/]+)\.skin$ /$1 [R=301,L]
# 레거시 /kngil/skin/*.php -> /* (확장자 제거)
RewriteCond %{THE_REQUEST} \s/+kngil/skin/([^\s]+)\.php [NC]
RewriteRule ^kngil/skin/([^/]+)\.php$ /$1 [R=301,L]
# 레거시 /kngil/*.php -> /* (확장자 제거)
RewriteCond %{THE_REQUEST} \s/+kngil/([^\s]+)\.php [NC]
RewriteRule ^kngil/([^/]+)\.php$ /$1 [R=301,L]
# 레거시 /kngil 또는 /kngil/ -> /
RewriteCond %{THE_REQUEST} \s/+kngil/?\s [NC]
RewriteRule ^kngil/?$ / [R=301,L]
# 정적 파일 CDN 리다이렉트(옵션: STATIC_CDN_BASE_URL 환경변수)
RewriteCond %{ENV:STATIC_CDN_BASE_URL} !=""
RewriteRule ^(kngil/)?(js|css|img|fonts|download|uploads|vendor)/(.*)$ %{ENV:STATIC_CDN_BASE_URL}/$2/$3 [R=302,L]
# 기존 파일/디렉터리는 그대로 통과
RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L] RewriteRule ^ - [L]
# 정적 파일 루트 경로 -> /kngil/ 경로로 내부 라우팅
RewriteRule ^(js|css|img|fonts|download|uploads|vendor)/(.*)$ /kngil/$1/$2 [L]
# Admin UI # Admin UI
RewriteRule ^admin/?$ /kngil/skin/adm.php [L] RewriteRule ^admin/?$ /kngil/skin/adm.php [L]
RewriteRule ^admin/company/?$ /kngil/skin/adm_comp.php [L] RewriteRule ^admin/company/?$ /kngil/skin/adm_comp.php [L]
@@ -21,3 +68,12 @@ RewriteRule ^admin/api/product/delete/?$ /kngil/bbs/adm_product_popup_delete.php
RewriteRule ^admin/api/faq/?$ /kngil/bbs/adm_faq_popup.php [QSA,L] RewriteRule ^admin/api/faq/?$ /kngil/bbs/adm_faq_popup.php [QSA,L]
RewriteRule ^admin/api/faq/save/?$ /kngil/bbs/adm_faq_popup_save.php [QSA,L] RewriteRule ^admin/api/faq/save/?$ /kngil/bbs/adm_faq_popup_save.php [QSA,L]
RewriteRule ^admin/api/faq/delete/?$ /kngil/bbs/adm_faq_popup_delete.php [QSA,L] RewriteRule ^admin/api/faq/delete/?$ /kngil/bbs/adm_faq_popup_delete.php [QSA,L]
# Q&A 라우팅 (컨트롤러 우선)
RewriteRule ^qa_list/?$ /kngil/bbs/qa_list.php [QSA,L]
RewriteRule ^qa_detail/?$ /kngil/bbs/qa_detail.php [QSA,L]
RewriteRule ^qa_write/?$ /kngil/bbs/qa_write.php [QSA,L]
# 루트 페이지 라우팅: / -> index, /{page} -> /kngil/skin/{page}.php
RewriteRule ^$ /kngil/skin/index.php [L]
RewriteRule ^([^/]+)$ /kngil/skin/$1.php [L]

View File

@@ -31,6 +31,17 @@ docker compose down
- `OIDC_SCOPES` (예: `openid profile email`) - `OIDC_SCOPES` (예: `openid profile email`)
- `IDP_SERVICE_URL` (예: `https://idp.example.com`) - `IDP_SERVICE_URL` (예: `https://idp.example.com`)
### 정적 자산 CDN (선택)
정적 파일(`/js`, `/css`, `/img`, `/fonts`, `/download`, `/uploads`, `/vendor`)을 CDN으로 리다이렉트하려면
웹 서버 환경변수 `STATIC_CDN_BASE_URL`을 설정하세요. (값이 있으면 302 리다이렉트)
예시:
```bash
STATIC_CDN_BASE_URL=https://cdn.example.com/kngil
```
> 참고: 이 변수는 Apache의 Rewrite 환경변수로 사용됩니다. Docker Compose를 사용한다면 web 서비스의 환경변수로 전달해도 됩니다.
## DB 초기화 ## DB 초기화
- `kngil_DB` 덤프는 **처음 실행 시** 자동으로 로드됩니다. - `kngil_DB` 덤프는 **처음 실행 시** 자동으로 로드됩니다.
- 이미 생성된 볼륨이 있으면 재적용되지 않습니다. 다시 초기화하려면 아래를 실행하세요. - 이미 생성된 볼륨이 있으면 재적용되지 않습니다. 다시 초기화하려면 아래를 실행하세요.

View File

@@ -1,6 +1,7 @@
<?php <?php
// /kngil/auth/oidc-callback.php // /kngil/auth/oidc-callback.php
session_start(); require_once dirname(__DIR__) . '/bbs/env.php';
kngil_start_session();
ini_set('log_errors', '1'); ini_set('log_errors', '1');
ini_set('error_log', '/proc/self/fd/2'); ini_set('error_log', '/proc/self/fd/2');
require_once dirname(__DIR__) . '/vendor/autoload.php'; require_once dirname(__DIR__) . '/vendor/autoload.php';
@@ -252,6 +253,7 @@ try {
} }
// 3. 세션 설정 (bbs/login.php 와 동일한 구조) // 3. 세션 설정 (bbs/login.php 와 동일한 구조)
session_regenerate_id(true);
$_SESSION['login'] = [ $_SESSION['login'] = [
'member_id' => $user['member_id'], 'member_id' => $user['member_id'],
'user_id' => $user['user_id'], 'user_id' => $user['user_id'],
@@ -278,7 +280,7 @@ try {
<body> <body>
<script> <script>
(function () { (function () {
const target = '/kngil/skin/index.php'; const target = '/';
if (window.opener && !window.opener.closed) { if (window.opener && !window.opener.closed) {
try { try {
window.opener.postMessage({ type: 'OIDC_LOGIN_SUCCESS' }, window.location.origin); window.opener.postMessage({ type: 'OIDC_LOGIN_SUCCESS' }, window.location.origin);
@@ -295,7 +297,7 @@ try {
})(); })();
</script> </script>
<noscript> <noscript>
<a href="/kngil/skin/index.php">메인으로 이동</a> <a href="/">메인으로 이동</a>
</noscript> </noscript>
</body> </body>
</html> </html>
@@ -305,5 +307,5 @@ try {
} catch (Exception $e) { } catch (Exception $e) {
echo "<h1>로그인 오류</h1>"; echo "<h1>로그인 오류</h1>";
echo "<p>" . htmlspecialchars($e->getMessage()) . "</p>"; echo "<p>" . htmlspecialchars($e->getMessage()) . "</p>";
echo "<a href='/kngil/index.php'>메인으로 돌아가기</a>"; echo "<a href='/'>메인으로 돌아가기</a>";
} }

View File

@@ -1,5 +1,7 @@
<?php <?php
// /kngil/auth/oidc-login.php // /kngil/auth/oidc-login.php
require_once dirname(__DIR__) . '/bbs/env.php';
kngil_start_session();
require_once dirname(__DIR__) . '/vendor/autoload.php'; require_once dirname(__DIR__) . '/vendor/autoload.php';
$config = require_once dirname(__DIR__) . '/bbs/oidc_config.php'; $config = require_once dirname(__DIR__) . '/bbs/oidc_config.php';

View File

@@ -3,10 +3,8 @@ error_reporting(E_ALL);
ini_set('display_errors', 1); ini_set('display_errors', 1);
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
if (session_status() === PHP_SESSION_NONE) { require_once __DIR__ . '/env.php';
session_start(); kngil_start_session();
}
require_once __DIR__ . '/db_conn.php'; require_once __DIR__ . '/db_conn.php';
/* ================================================= /* =================================================

View File

@@ -1,261 +0,0 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
header('Content-Type: application/json; charset=utf-8');
/* =========================
로그인 / 권한 가드
========================= */
require_once __DIR__ . '/adm_guard.php';
require_once __DIR__ . '/db_conn.php';
/* =========================
세션 기준 값 (중요)
========================= */
$login = $_SESSION['login'];
$auth_bc = $login['auth_bc']; // 권한코드
$member_id = $login['member_id']; // 회사ID
/* =========================
입력
========================= */
$input = json_decode(file_get_contents('php://input'), true) ?? [];
$action = $_GET['action'] ?? $input['action'] ?? 'list';
/* =========================
권한 플래그
========================= */
$isAdmin = in_array($auth_bc, ['BS100100','BS100200','BS100300'], true);
try {
switch ($action) {
/* =========================
0. 공통코드 조회 (콤보)
========================= */
case 'base_code':
$main_cd = $_GET['main_cd'] ?? $input['main_cd'] ?? '';
if (!$main_cd) {
throw new Exception('main_cd가 필요합니다.');
}
$stmt = $pdo->prepare("
SELECT *
FROM kngil.fn_base_cd(:main_cd)
");
$stmt->execute([
':main_cd' => $main_cd
]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode([
'status' => 'success',
'items' => $rows // [{id, text}]
]);
break;
/* =========================
1. 사용자 목록 조회
========================= */
case 'list':
$schType = $_GET['sch_type'] ?? '';
$schKeyword = $_GET['sch_keyword'] ?? '';
$schUseYn = $_GET['sch_use_yn'] ?? '';
// 기본값
$sch_id = '';
$sch_nm = '';
$sch_dept = '';
if ($schKeyword !== '') {
switch ($schType) {
case 'id':
$sch_id = $schKeyword;
break;
case 'name':
$sch_nm = $schKeyword;
break;
case 'dept':
$sch_dept = $schKeyword;
break;
default: // 전체
$sch_id = $schKeyword;
$sch_nm = $schKeyword;
$sch_dept = $schKeyword;
}
}
$sql = "
SELECT *
FROM kngil.sp_users_r(
:member_id,
:user_nm,
:dept_nm,
:use_yn
);
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':member_id' => $member_id,
':user_nm' => $_GET['user_nm'] ?? '',
':dept_nm' => $_GET['dept_nm'] ?? '',
':use_yn' => $_GET['use_yn'] ?? ''
]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$i = 1;
foreach ($rows as &$r) {
$r['recid'] = $i++;
}
echo json_encode([
'status' => 'success',
'member_id' => $member_id,
'records' => $rows
]);
break;
/* =========================
2. 사용자 저장
========================= */
case 'save':
$inserts = $input['inserts'] ?? [];
$updates = $input['updates'] ?? [];
if (!$inserts && !$updates) {
throw new Exception('저장할 데이터가 없습니다.');
}
$pdo->beginTransaction();
// INSERT
if ($inserts) {
$stmtI = $pdo->prepare("
SELECT kngil.sp_users_i(
:member_id,:user_id,:user_pw,:user_nm,:dept_nm,
:posit_nm,:tel_no,:email,:auth_bc,:use_yn,:rmks,:cid
)
");
foreach ($inserts as $r) {
$stmtI->execute([
':member_id' => $member_id,
':user_id' => $r['user_id'],
':user_pw' => $r['user_pw'] ?? '0000',
':user_nm' => $r['user_nm'],
':dept_nm' => $r['dept_nm'],
':posit_nm' => $r['posit_nm'] ?? '',
':tel_no' => $r['tel_no'],
':email' => $r['email'],
':auth_bc' => $r['auth_bc'],
':use_yn' => $r['use_yn'],
':rmks' => $r['rmks'] ?? '',
':cid' => $r['cid'] ?? 'SYSTEM'
]);
}
}
// UPDATE
if ($updates) {
$stmtU = $pdo->prepare("
SELECT kngil.sp_users_u(
:member_id,:user_id,:user_pw,:user_nm,:dept_nm,
:posit_nm,:tel_no,:email,:auth_bc,:use_yn,:rmks,:mid
)
");
foreach ($updates as $r) {
$stmtU->execute([
':member_id' => $member_id,
':user_id' => $r['user_id'],
':user_pw' => null,
':user_nm' => $r['user_nm'],
':dept_nm' => $r['dept_nm'],
':posit_nm' => $r['posit_nm'] ?? '',
':tel_no' => $r['tel_no'],
':email' => $r['email'],
':auth_bc' => $r['auth_bc'],
':use_yn' => $r['use_yn'],
':rmks' => $r['rmks'] ?? '',
':mid' => $r['mid'] ?? 'SYSTEM'
]);
}
}
$pdo->commit();
echo json_encode(['status'=>'success']);
break;
/* =========================
3. 사용자 삭제 (비활성)
========================= */
case 'delete':
$ids = $input['ids'] ?? [];
if (!$ids) throw new Exception('삭제 대상이 없습니다.');
$sql = "SELECT kngil.sp_users_d(:member_id, :user_id)";
$stmt = $pdo->prepare($sql);
foreach ($ids as $uid) {
$stmt->execute([
':member_id' => $member_id,
':user_id' => $uid
]);
}
echo json_encode(['status'=>'success']);
break;
/* =========================
4. 회원 총 구매 면적 조회
========================= */
case 'total_area':
$sql = "
SELECT COALESCE(SUM(sum_area), 0) AS total_area
FROM kngil.sp_buy_item_history_r(:member_id, '', NULL, NULL)
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':member_id' => $member_id
]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
echo json_encode([
'status' => 'success',
'member_id' => $member_id,
'total_area' => (int)$row['total_area']
]);
break;
default:
throw new Exception('잘못된 요청');
}
} catch (Exception $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
http_response_code(500);
echo json_encode([
'status' => 'error',
'message' => $e->getMessage()
]);
}

View File

@@ -1,8 +1,6 @@
<?php <?php
if (session_status() === PHP_SESSION_NONE) { require_once __DIR__ . '/env.php';
session_start(); kngil_start_session();
}
/* ========================= /* =========================
1. 로그인 체크 1. 로그인 체크
========================= */ ========================= */

View File

@@ -57,3 +57,37 @@ function kngil_load_env_once(string $path): void
$_SERVER[$name] = $value; $_SERVER[$name] = $value;
} }
} }
// 세션 쿠키 경로를 루트로 고정해 경로 변경 시 로그인 상태가 유지되도록 합니다.
function kngil_start_session(): void
{
if (session_status() !== PHP_SESSION_NONE) {
return;
}
$params = session_get_cookie_params();
$samesite = $params['samesite'] ?? 'Lax';
$cookieName = session_name();
if (!empty($_COOKIE[$cookieName])) {
setcookie($cookieName, '', [
'expires' => time() - 3600,
'path' => '/kngil',
'domain' => $params['domain'],
'secure' => $params['secure'],
'httponly' => $params['httponly'],
'samesite' => $samesite,
]);
}
session_set_cookie_params([
'lifetime' => $params['lifetime'],
'path' => '/',
'domain' => $params['domain'],
'secure' => $params['secure'],
'httponly' => $params['httponly'],
'samesite' => $samesite,
]);
session_start();
}

View File

@@ -1,160 +0,0 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php';
header('Content-Type: application/json');
$data = json_decode(file_get_contents('php://input'), true);
$action = $data['action'] ?? '';
/* =================================================
아이디 중복확인 (fn_user_id_check 사용)
================================================= */
if ($action === 'check_id') {
$userId = trim($data['userId'] ?? '');
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9]{3,11}$/', $userId)) {
echo json_encode([
'available' => false,
'message' => '아이디 형식 오류'
]);
exit;
}
$stmt = $pdo->prepare("
SELECT kngil.fn_user_id_check(:user_id)
");
$stmt->execute([
':user_id' => $userId
]);
$result = trim($stmt->fetchColumn());
if (strpos($result, 'SUCCESS') === 0) {
echo json_encode([
'available' => true,
'message' => '사용 가능한 아이디입니다.'
]);
} else {
echo json_encode([
'available' => false,
'message' => '이미 존재하는 아이디입니다.'
]);
}
exit;
}
/* =================================================
1. 필수값 검증
================================================= */
$required = [
'memberType', // 회원유형
'userId',
'password',
'userName',
'email',
'phone'
];
foreach ($required as $k) {
if (empty($data[$k])) {
echo json_encode([
'success' => false,
'message' => '필수 항목이 누락되었습니다.'
]);
exit;
}
}
/* =================================================
2. 회원유형 → co_bc 매핑
================================================= */
/*
기업회원 : '1'
개인회원 : '2'
→ 실제 코드값은 여기서 통제
*/
$co_bc = ($data['memberType'] === '1')
? 'CB100100' // 기업
: 'CB100200'; // 개인
/* =================================================
3. 비밀번호 규칙 + 암호화
================================================= */
if (!preg_match('/^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*]).{12,}$/', $data['password'])) {
echo json_encode([
'success' => false,
'message' => '비밀번호 규칙이 올바르지 않습니다.'
]);
exit;
}
$hashedPw = password_hash($data['password'], PASSWORD_DEFAULT);
/* =================================================
4. 이메일 형식
================================================= */
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
echo json_encode([
'success' => false,
'message' => '이메일 형식 오류'
]);
exit;
}
/* =================================================
5. 프로시저 호출
================================================= */
try {
$stmt = $pdo->prepare("
SELECT kngil.sp_member_i(
:p_co_bc,
:p_member_id,
:p_user_pw,
:p_member_nm,
:p_email,
:p_tel_no,
:p_co_nm,
:p_dept_nm,
:p_cid
) AS result
");
$stmt->execute([
':p_co_bc' => $co_bc,
':p_member_id' => $data['userId'],
':p_user_pw' => $hashedPw,
':p_member_nm' => $data['userName'],
':p_email' => $data['email'],
':p_tel_no' => $data['phone'],
':p_co_nm' => $data['company'] ?? null,
':p_dept_nm' => $data['department'] ?? null,
':p_cid' => $data['userId']
]);
$result = $stmt->fetchColumn();
if ($result === 'SUCCESS') {
echo json_encode([
'success' => true
]);
} else {
echo json_encode([
'success' => false,
'message' => $result
]);
}
} catch (Exception $e) {
echo json_encode([
'success' => false,
'message' => '서버 오류'
]);
}
echo json_encode([
'success' => false,
'message' => 'Invalid action'
]);
exit;

View File

@@ -1,5 +1,6 @@
<?php <?php
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php';
$input = json_decode(file_get_contents('php://input'), true); $input = json_decode(file_get_contents('php://input'), true);
@@ -54,6 +55,7 @@ if ($user['user_pw'] !== $pw) {
} }
// ✅ 로그인 성공 // ✅ 로그인 성공
session_regenerate_id(true);
$_SESSION['login'] = [ $_SESSION['login'] = [
'member_id' => $user['member_id'], 'member_id' => $user['member_id'],
'user_id' => $user['user_id'], 'user_id' => $user['user_id'],

View File

@@ -1,179 +0,0 @@
<?php
/**
* Sentinel SMS 매직링크 테스트 (PHP)
* - phoneNumber: 01086270921 (고정)
* - system: kngil
* - secret_key: MY_SECRET_KEY
*/
header('Content-Type: application/json; charset=utf-8');
/* =========================
설정값
========================= */
$AUTH_SERVER = 'http://61.98.205.242:8075';
$SYSTEM = 'kngil';
$SECRET_KEY = '9f3b2e7a0a4f1f25c41c8c2367d04d54a89a2a5b2b189d63a99a0b874db4b27f';
$PHONE = '01086270921';
/* =========================
JWT 생성 (HS256)
========================= */
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function create_jwt($payload, $secret) {
$header = ['alg'=>'HS256','typ'=>'JWT'];
$segments = [];
$segments[] = base64url_encode(json_encode($header));
$segments[] = base64url_encode(json_encode($payload));
$signing_input = implode('.', $segments);
$signature = hash_hmac('sha256', $signing_input, $secret, true);
$segments[] = base64url_encode($signature);
return implode('.', $segments);
}
/* =========================
cURL 요청 함수
========================= */
function curl_json($url, $method='GET', $headers=[], $body=null) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => $body,
CURLOPT_TIMEOUT => 10
]);
$response = curl_exec($ch);
$err = curl_error($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($err) {
throw new Exception($err);
}
return [$code, $response];
}
/* =========================
MODE 분기
========================= */
$mode = $_GET['mode'] ?? 'request';
try {
/* =========================
1⃣ 매직링크 발급 요청
========================= */
if ($mode === 'request') {
// JWT payload (3분 유효)
$payload = [
'system' => $SYSTEM,
'iat' => time(),
'exp' => time() + 180
];
$jwt = create_jwt($payload, $SECRET_KEY);
[$code, $res] = curl_json(
$AUTH_SERVER.'/auth/sentinel',
'POST',
[
'Authorization: Bearer '.$jwt,
'Content-Type: application/json'
],
json_encode([
'phoneNumber' => $PHONE
])
);
echo json_encode([
'step' => 'sentinel_request',
'http_code' => $code,
'response' => json_decode($res, true)
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
}
/* =========================
2⃣ 매직링크 상태 확인
========================= */
if ($mode === 'status') {
$token = $_GET['token'] ?? '';
if (!$token) {
throw new Exception('token 필요');
}
$payload = [
'system' => $SYSTEM,
'iat' => time(),
'exp' => time() + 180
];
$jwt = create_jwt($payload, $SECRET_KEY);
[$code, $res] = curl_json(
$AUTH_SERVER.'/auth/status?token='.$token,
'GET',
[
'Authorization: Bearer '.$jwt
]
);
$data = json_decode($res, true);
// 🔴 여기부터가 "로그인 처리"
if (!empty($data['loggedIn'])) {
$stmt = $pdo->prepare("
SELECT member_id, user_id, user_nm, auth_bc
FROM kngil.users
WHERE REPLACE(tel_no, '-', '') = :phone
AND use_yn = 'Y'
LIMIT 1
");
$stmt->execute([':phone' => $PHONE]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
throw new Exception('해당 번호로 등록된 사용자 없음');
}
$_SESSION['login'] = [
'member_id' => $user['member_id'],
'user_id' => $user['user_id'],
'user_nm' => $user['user_nm'],
'auth_bc' => $user['auth_bc']
];
echo json_encode([
'status' => 'success',
'message' => '자동 로그인 완료'
]);
exit;
}
echo json_encode([
'status' => 'pending'
]);
exit;
}
} catch (Exception $e) {
echo json_encode([
'error' => true,
'message' => $e->getMessage()
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}

View File

@@ -5,7 +5,8 @@
* - secret_key: MY_SECRET_KEY * - secret_key: MY_SECRET_KEY
*/ */
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php';
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
@@ -209,4 +210,4 @@ try {
'error' => true, 'error' => true,
'message' => $e->getMessage() 'message' => $e->getMessage()
], JSON_UNESCAPED_UNICODE); ], JSON_UNESCAPED_UNICODE);
} }

View File

@@ -1,6 +1,7 @@
<?php <?php
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
session_destroy(); session_destroy();
header('Location: /kngil/skin/index.php'); header('Location: /');
exit; exit;

View File

@@ -1,6 +1,7 @@
<?php <?php
//mypage01.php //mypage01.php
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php';
if (!isset($_SESSION['login'])) { if (!isset($_SESSION['login'])) {

View File

@@ -1,5 +1,6 @@
<?php <?php
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php';
header('Content-Type: application/json'); header('Content-Type: application/json');

View File

@@ -1,5 +1,6 @@
<?php <?php
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php';
header('Content-Type: application/json'); header('Content-Type: application/json');

View File

@@ -14,9 +14,9 @@ if ($scopesRaw !== false && $scopesRaw !== '') {
} }
return [ return [
'issuer' => 'https://api.descope.com/v1/apps/P2x26KgEwOu0xIwgNZutJjIZc1zz', // 예: https://idp.example.com/auth/realms/master 'issuer' => $issuer, // 예: https://idp.example.com/auth/realms/master
'client_id' => 'UDJ4MjZLZ0V3T3UweEl3Z05adXRKaklaYzF6ejpUUEEzOTVtSmx5MXhiczFwZWxrUHdDVFlvU2hiYXc=', 'client_id' => $clientId,
'client_secret' => 'uTjiKweHYUINalroA1LVu9OacbEEMPtPbfFITfHu3r5', 'client_secret' => $clientSecret,
'redirect_url' => "https://kngil.hmac.kr/kngil/auth/oidc-callback.php", 'redirect_url' => $redirectUrl,
'scopes' => ['openid'], 'scopes' => $scopes,
]; ];

View File

@@ -1,5 +1,6 @@
<?php <?php
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
header('Content-Type: application/json'); header('Content-Type: application/json');
if (empty($_SESSION['login'])) { if (empty($_SESSION['login'])) {

View File

@@ -1,5 +1,6 @@
<?php <?php
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
header('Content-Type: application/json'); header('Content-Type: application/json');
require_once __DIR__.'/db_conn.php'; require_once __DIR__.'/db_conn.php';

View File

@@ -1,5 +1,6 @@
<?php <?php
session_start(); require_once __DIR__ . '/env.php';
kngil_start_session();
header('Content-Type: application/json'); header('Content-Type: application/json');
require_once __DIR__.'/db_conn.php'; require_once __DIR__.'/db_conn.php';

View File

@@ -7,14 +7,12 @@ error_reporting(E_ALL);
/* =============================== /* ===============================
1. 세션 & 로그인 체크 1. 세션 & 로그인 체크
=============================== */ =============================== */
if (session_status() === PHP_SESSION_NONE) { require_once __DIR__ . '/env.php';
session_start(); kngil_start_session();
}
if (empty($_SESSION['login'])) { if (empty($_SESSION['login'])) {
echo "<script> echo "<script>
alert('로그인 후 이용 가능합니다.'); alert('로그인 후 이용 가능합니다.');
location.href = '/kngil/skin/qa_list.skin.php'; location.href = '/qa_list';
</script>"; </script>";
exit; exit;
} }
@@ -92,7 +90,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'delet
$pdo->commit(); $pdo->commit();
header("Location: /kngil/skin/qa_list.skin.php"); header("Location: /qa_list");
exit; exit;
} catch (Exception $e) { } catch (Exception $e) {
@@ -230,4 +228,4 @@ $isOwner = ($post['user_id'] === $me);
/* =============================== /* ===============================
12. 스킨 렌더링 12. 스킨 렌더링
=============================== */ =============================== */
include $_SERVER['DOCUMENT_ROOT'].'/kngil/skin/qa_detail.skin.php'; include $_SERVER['DOCUMENT_ROOT'].'/kngil/skin/qa_detail.php';

View File

@@ -1,16 +1,14 @@
<?php <?php
/** /**
* Q&A 리스트 컨트롤러 * Q&A 리스트 컨트롤러
* - 스킨: /kngil/skin/qa_list.skin.php * - 스킨: /kngil/skin/qa_list.php (URL: /qa_list)
*/ */
ini_set('display_errors', 1); ini_set('display_errors', 1);
error_reporting(E_ALL); error_reporting(E_ALL);
if (session_status() === PHP_SESSION_NONE) { require_once __DIR__ . '/env.php';
session_start(); kngil_start_session();
}
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php';
/* ========================= /* =========================
@@ -149,4 +147,4 @@ $totalPages = (int)ceil($totalCount / $pageSize);
/* ========================= /* =========================
7. 스킨 렌더링 7. 스킨 렌더링
========================= */ ========================= */
include $_SERVER['DOCUMENT_ROOT'].'/kngil/skin/qa_list.skin.php'; include $_SERVER['DOCUMENT_ROOT'].'/kngil/skin/qa_list.php';

View File

@@ -1,8 +1,6 @@
<?php <?php
if (session_status() === PHP_SESSION_NONE) { require_once __DIR__ . '/env.php';
session_start(); kngil_start_session();
}
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/db_conn.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/adm_guard.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/adm_guard.php';
@@ -42,7 +40,7 @@ try {
]); ]);
// 상세 페이지로 복귀 // 상세 페이지로 복귀
header("Location: /kngil/bbs/qa_detail.php?id={$postId}"); header("Location: /qa_detail?id={$postId}");
exit; exit;
} catch (Exception $e) { } catch (Exception $e) {

View File

@@ -6,10 +6,8 @@ error_reporting(E_ALL);
/* =============================== /* ===============================
1. 세션 & 로그인 체크 1. 세션 & 로그인 체크
=============================== */ =============================== */
if (session_status() === PHP_SESSION_NONE) { require_once __DIR__ . '/env.php';
session_start(); kngil_start_session();
}
// echo '<pre>'; // echo '<pre>';
// var_dump($_SESSION['login']); // var_dump($_SESSION['login']);
// exit; // exit;
@@ -17,7 +15,7 @@ if (session_status() === PHP_SESSION_NONE) {
if (empty($_SESSION['login'])) { if (empty($_SESSION['login'])) {
echo "<script> echo "<script>
alert('로그인이 필요합니다.'); alert('로그인이 필요합니다.');
location.href = '/kngil/skin/qa_list.skin.php'; location.href = '/qa_list';
</script>"; </script>";
exit; exit;
} }
@@ -216,7 +214,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
handle_file_uploads($pdo, $postId); handle_file_uploads($pdo, $postId);
} }
header("Location: /kngil/bbs/qa_detail.php?id={$postId}"); header("Location: /qa_detail?id={$postId}");
exit; exit;
} catch (Exception $e) { } catch (Exception $e) {
@@ -228,4 +226,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
/* =============================== /* ===============================
7. 화면 출력 7. 화면 출력
=============================== */ =============================== */
include $_SERVER['DOCUMENT_ROOT'].'/kngil/skin/qa_write.skin.php'; include $_SERVER['DOCUMENT_ROOT'].'/kngil/skin/qa_write.php';

25
kngil/img/favicon.svg Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0"?>
<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" data-name="레이어_2">
<defs>
<style>.cls-1 {
fill: #231815;
}
.cls-2 {
fill: #ca2829;
}
.cls-3 {
fill: #263b7c;
}</style>
</defs>
<g class="layer">
<title>Layer 1</title>
<g data-name="레이어_1" id="_레이어_1-2">
<g id="svg_1">
<path class="cls-2" d="m31.59,31.61c-1.81,0.72 -2.76,0.04 -3.19,-0.47l-4.83,5.85c-4.09,4.9 -8.97,6.79 -12.69,5.16l19.3,-23.16s1.93,-2.63 4.12,-4.35l0,0c0.16,-0.12 0.21,-0.25 0.18,-0.47c-0.14,-0.58 -1.42,-0.97 -2.96,-0.95l0,0l-3.83,0.02s-1.42,-0.07 -2.35,0c-0.19,0.02 -2.67,0.12 -3.48,0.21c-0.86,0.07 -3.04,0.46 -3.66,0.63c-3.91,1.07 -7.67,2.98 -10.57,6.37c-3.83,4.46 -5.82,9.74 -5.6,14.85c0.16,3.77 1.52,7.09 3.83,9.34c2.18,2.11 4.9,3.21 7.86,3.21c0.76,0 1.54,-0.07 2.32,-0.21c3.85,-0.72 7.61,-3.18 10.9,-7.13l6.98,-8.44c-0.23,-0.32 -0.91,-1 -2.28,-0.46l0,0l-0.06,0zm-25.04,3.46c-0.16,-3.69 1.36,-7.62 4.32,-11.03c3.5,-4.04 6.34,-5.23 9.05,-5.41c1.26,-0.09 2.41,0.09 3.68,0.72l-16.17,19.45c-0.53,-1.07 -0.82,-2.35 -0.88,-3.72l0,0l0,-0.02z" id="svg_2"/>
<path class="cls-3" d="m61.56,25.31c-0.31,-3.84 -1.98,-7.27 -4.59,-9.41c-6.23,-5.13 -13.46,-3.39 -19.87,4.74l-7.3,8.83l0,0l-0.6,0.74c0.14,0.21 0.66,0.75 2.04,0.19c1.69,-0.68 2.86,0.04 3.42,0.72l1.03,-1.25l4.75,-5.74l0.04,-0.05c4.88,-6.2 9.53,-7.57 13.83,-4.02c1.56,1.28 2.55,3.37 2.74,5.72c0.29,3.55 -1.11,7.58 -4.2,11.1c-4.34,4.92 -8.52,6.37 -12.72,4.86l6.27,-7.72l-3.35,-3.49l-9.36,11.53s-1.87,2.55 -4.03,4.27c-0.23,0.16 -0.33,0.28 -0.27,0.54c0.12,0.56 1.34,0.93 2.82,0.95l0.02,0l3.91,0s3.33,0.02 4.03,-0.04c0.14,-0.02 2.49,-0.23 2.96,-0.26c0.41,-0.04 2.43,-0.44 2.9,-0.56c3.97,-1.12 7.18,-2.93 10.18,-6.57c3.91,-4.71 5.84,-10.08 5.43,-15.12l0,0l-0.08,0.04z" id="svg_3"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -4921,18 +4921,28 @@ var Swiper=function(){"use strict";function e(e){return null!==e&&"object"==type
const buttons = document.querySelectorAll('[data-oidc-login]'); const buttons = document.querySelectorAll('[data-oidc-login]');
if (!buttons.length) return; if (!buttons.length) return;
buttons.forEach((button) => { buttons.forEach((button) => {
button.addEventListener('click', openOidcLogin); if (button.dataset.oidcBound === '1') return;
button.dataset.oidcBound = '1';
button.addEventListener('click', (event) => {
event.preventDefault();
window.openOidcLogin();
});
}); });
} }
window.openOidcLogin = openOidcLogin; if (!window.openOidcLogin) {
window.login = openOidcLogin; window.openOidcLogin = openOidcLogin;
}
window.login = window.openOidcLogin;
window.addEventListener('message', (event) => { if (!window.__oidcLoginMessageBound) {
if (event.data && event.data.type === 'OIDC_LOGIN_SUCCESS') { window.addEventListener('message', (event) => {
window.location.reload(); if (event.data && event.data.type === 'OIDC_LOGIN_SUCCESS') {
} window.location.reload();
}); }
});
window.__oidcLoginMessageBound = true;
}
if (document.readyState === 'loading') { if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bindOidcButtons); document.addEventListener('DOMContentLoaded', bindOidcButtons);

View File

@@ -13,11 +13,11 @@
VISITED_STORAGE_KEY: 'visited', VISITED_STORAGE_KEY: 'visited',
VIDEO_BASE_PATH: '../img/video', VIDEO_BASE_PATH: '../img/video',
PAGE_LINKS: { PAGE_LINKS: {
1: '/kngil/skin/value.php', 1: '/value',
2: '/kngil/skin/provided.php', 2: '/provided',
3: '/kngil/skin/primary.php', 3: '/primary',
4: '/kngil/skin/analysis.php', 4: '/analysis',
5: '/kngil/skin/results.php' 5: '/results'
}, },
SELECTORS: { SELECTORS: {
video: '#video_play', video: '#video_play',

View File

@@ -18,19 +18,19 @@
<div class="comp-contact"> <div class="comp-contact">
<ul class="footer-menu"> <ul class="footer-menu">
<li> <li>
<a href="value.php">KNGIL</a> <a href="/value">KNGIL</a>
</li> </li>
<li> <li>
<a href="provided.php">제공데이터</a> <a href="/provided">제공데이터</a>
</li> </li>
<li> <li>
<a href="primary.php">주요기능</a> <a href="/primary">주요기능</a>
</li> </li>
<li> <li>
<a href="analysis.php">데이터분석</a> <a href="/analysis">데이터분석</a>
</li> </li>
<li> <li>
<a href="results.php">성과품</a> <a href="/results">성과품</a>
</li> </li>
</ul> </ul>
<div class="footer-family"> <div class="footer-family">
@@ -54,4 +54,4 @@
<!-- // 모든 팝업페이지 경로 --> <!-- // 모든 팝업페이지 경로 -->
<script src="/kngil/js/common.js"></script> <script src="/kngil/js/common.js"></script>

View File

@@ -9,23 +9,23 @@
<link <link
rel="shortcut icon" rel="shortcut icon"
type="image/svg+xml" type="image/svg+xml"
href="/kngil/img/favicon.svg" href="/img/favicon.svg"
/> />
<!-- CSS --> <!-- CSS -->
<link rel="stylesheet" href="/kngil/css/lib/aos.min.css" /> <link rel="stylesheet" href="/css/lib/aos.min.css" />
<link rel="stylesheet" type="text/css" href="/kngil/css/lib/lenis.min.css" /> <link rel="stylesheet" type="text/css" href="/css/lib/lenis.min.css" />
<link rel="stylesheet" type="text/css" href="/kngil/css/common.css" /> <link rel="stylesheet" type="text/css" href="/css/common.css" />
<link rel="stylesheet" type="text/css" href="/kngil/css/style.css" /> <link rel="stylesheet" type="text/css" href="/css/style.css" />
<!-- JS (local) --> <!-- JS (local) -->
<script src="/kngil/js/lib/jquery-3.6.1.min.js"></script> <script src="/js/lib/jquery-3.6.1.min.js"></script>
<script src="/kngil/js/lib/jquery.mousewheel.min.js"></script> <script src="/js/lib/jquery.mousewheel.min.js"></script>
<script src="/kngil/js/lib/lenis.min.js"></script> <script src="/js/lib/lenis.min.js"></script>
<script src="/kngil/js/lib/aos.min.js"></script> <script src="/js/lib/aos.min.js"></script>
<script src="/kngil/js/lib/gsap.min.js"></script> <script src="/js/lib/gsap.min.js"></script>
<script src="/kngil/js/lib/scrolltrigger.min.js"></script> <script src="/js/lib/scrolltrigger.min.js"></script>
<script src="/kngil/js/lib/ScrollToPlugin.min.js"></script> <script src="/js/lib/scrollToPlugin.min.js"></script>
<!-- ScrollMagic (외부 CDN 유지) --> <!-- ScrollMagic (외부 CDN 유지) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>

View File

@@ -8,9 +8,9 @@
<link <link
rel="shortcut icon" rel="shortcut icon"
type="image/svg+xml" type="image/svg+xml"
href="/kngil/img/favicon.svg" href="/img/favicon.svg"
/> />
<link rel="stylesheet" type="text/css" href="/kngil/css/common.css" /> <link rel="stylesheet" type="text/css" href="/css/common.css" />
<link rel="stylesheet" type="text/css" href="/kngil/css/style.css" /> <link rel="stylesheet" type="text/css" href="/css/style.css" />
<script src="./js/lib/jquery-3.6.1.min.js"></script> <script src="/js/lib/jquery-3.6.1.min.js"></script>

View File

@@ -1,9 +1,6 @@
<?php <?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
require_once __DIR__ . '/../bbs/env.php'; require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
kngil_load_env_once(dirname(__DIR__, 2) . '/.env'); kngil_load_env_once(dirname(__DIR__, 2) . '/.env');
$isLogin = isset($_SESSION['login']); $isLogin = isset($_SESSION['login']);
@@ -27,7 +24,7 @@ if ($displayName === '') {
} }
// 권한 그룹 // 권한 그룹
$isSuperAdmin = in_array($auth, ['BS100100', 'BS100200']); $isSuperAdmin = in_array($auth, ['BS100100', 'BS100200']);
$isCompanyAdmin = in_array($auth, ['BS100100', 'BS100200', 'BS100300', 'BS100400']); $isCompanyAdmin = in_array($auth, ['BS100100', 'BS100200', 'BS100300', 'BS100400']);
?> ?>
<head> <head>
@@ -147,6 +144,55 @@ $isCompanyAdmin = in_array($auth, ['BS100100', 'BS100200', 'BS100300', 'BS100400
window.IS_LOGIN = <?= isset($_SESSION['login']) ? 'true' : 'false' ?>; window.IS_LOGIN = <?= isset($_SESSION['login']) ? 'true' : 'false' ?>;
window.IDP_SERVICE_URL = <?= json_encode($idpServiceUrl, JSON_UNESCAPED_SLASHES) ?>; window.IDP_SERVICE_URL = <?= json_encode($idpServiceUrl, JSON_UNESCAPED_SLASHES) ?>;
</script> </script>
<script>
(function () {
function openOidcLoginPopup() {
const width = 500;
const height = 600;
const left = (window.screen.width / 2) - (width / 2);
const top = (window.screen.height / 2) - (height / 2);
window.open(
'/kngil/auth/oidc-login.php',
'oidc_login_popup',
`width=${width},height=${height},left=${left},top=${top},scrollbars=yes`
);
}
if (!window.openOidcLogin) {
window.openOidcLogin = openOidcLoginPopup;
}
window.login = window.openOidcLogin;
if (!window.__oidcLoginMessageBound) {
window.addEventListener('message', function (event) {
if (event.data && event.data.type === 'OIDC_LOGIN_SUCCESS') {
window.location.reload();
}
});
window.__oidcLoginMessageBound = true;
}
function bindOidcButtons() {
const buttons = document.querySelectorAll('[data-oidc-login]');
if (!buttons.length) return;
buttons.forEach((button) => {
if (button.dataset.oidcBound === '1') return;
button.dataset.oidcBound = '1';
button.addEventListener('click', function (event) {
event.preventDefault();
window.openOidcLogin();
});
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bindOidcButtons);
} else {
bindOidcButtons();
}
})();
</script>
</head> </head>
<!-- header --> <!-- header -->
@@ -167,7 +213,7 @@ $isCompanyAdmin = in_array($auth, ['BS100100', 'BS100200', 'BS100300', 'BS100400
</span> </span>
<a href="/kngil/bbs/logout.php" class="btn-logout-top">로그아웃</a> <a href="/kngil/bbs/logout.php" class="btn-logout-top">로그아웃</a>
<?php else: ?> <?php else: ?>
<button type="button" class="btn-oidc-top" data-oidc-login>[바론 통합로그인]</button> <button type="button" class="btn-oidc-top" data-oidc-login>[바론 로그인]</button>
<?php endif; ?> <?php endif; ?>
</div> </div>
@@ -229,14 +275,14 @@ $isCompanyAdmin = in_array($auth, ['BS100100', 'BS100200', 'BS100300', 'BS100400
<div class="floating-menu"> <div class="floating-menu">
<ul> <ul>
<li class="floating-faq"> <li class="floating-faq">
<a href="/kngil/skin/qa_list.skin.php"> <a href="/qa_list">
<i class="ico-faq"></i> <i class="ico-faq"></i>
<span>Q&A</span> <span>Q&A</span>
</a> </a>
</li> </li>
<li class="floating-buy"> <li class="floating-buy">
<a href="/kngil/skin/buy.php"> <a href="/buy">
<i class="ico-buy"></i> <i class="ico-buy"></i>
<span>구매하기</span> <span>구매하기</span>
</a> </a>

View File

@@ -1,6 +1,6 @@
<ul class="sitemap"> <ul class="sitemap">
<li class="value"> <li class="value">
<a href="/kngil/skin/value.php"> <a href="/value">
<span>KNGIL</span> <span>KNGIL</span>
<p> <p>
공공데이터 기반으로<br> 공공데이터 기반으로<br>
@@ -12,7 +12,7 @@
<div class="bg-line down"></div> <div class="bg-line down"></div>
</li> </li>
<li class="provided"> <li class="provided">
<a href="/kngil/skin/provided.php"> <a href="/provided">
<span>제공데이터</span> <span>제공데이터</span>
<p> <p>
항목별 공공데이터를 기반으로<br> 항목별 공공데이터를 기반으로<br>
@@ -26,7 +26,7 @@
<div class="bg-line up"></div> <div class="bg-line up"></div>
</li> </li>
<li class="primary"> <li class="primary">
<a href="/kngil/skin/primary.php"> <a href="/primary">
<span>주요기능</span> <span>주요기능</span>
<p> <p>
기초현황 보고서 설정 등에 대한 <br> 기초현황 보고서 설정 등에 대한 <br>
@@ -40,7 +40,7 @@
<div class="bg-line down"></div> <div class="bg-line down"></div>
</li> </li>
<li class="analysis"> <li class="analysis">
<a href="/kngil/skin/analysis.php"> <a href="/analysis">
<span>데이터분석</span> <span>데이터분석</span>
<p> <p>
데이터의 특성과 형태에 따라 <br> 데이터의 특성과 형태에 따라 <br>
@@ -54,7 +54,7 @@
<div class="bg-line up"></div> <div class="bg-line up"></div>
</li> </li>
<li class="results"> <li class="results">
<a href="/kngil/skin/results.php"> <a href="/results">
<span>성과품</span> <span>성과품</span>
<p> <p>
데이터 분석 결과를 기반으로<br> 데이터 분석 결과를 기반으로<br>

View File

@@ -1,4 +1,6 @@
<?php <?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/adm_guard.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/adm_guard.php';
?> ?>
<!DOCTYPE html> <!DOCTYPE html>

View File

@@ -1,4 +1,6 @@
<?php <?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/adm_guard.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/adm_guard.php';
?> ?>
<!DOCTYPE html> <!DOCTYPE html>

View File

@@ -1,4 +1,6 @@
<?php <?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/adm_guard.php'; require_once $_SERVER['DOCUMENT_ROOT'].'/kngil/bbs/adm_guard.php';
?> ?>
<!DOCTYPE html> <!DOCTYPE html>

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>
@@ -82,7 +86,7 @@
</ul> </ul>
</div> </div>
<div class="btn-wrap"> <div class="btn-wrap">
<a href="/kngil/skin/faq_list.skin.php" class="btn-contact"> <a href="/faq_list" class="btn-contact">
<i class="ico-contact"></i> <i class="ico-contact"></i>
KNGIL 구매문의 KNGIL 구매문의
</a> </a>

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<meta charset="UTF-8"> <meta charset="UTF-8">
@@ -63,10 +67,10 @@
<ul class="sub-tab"> <ul class="sub-tab">
<li class="on"> <li class="on">
<a href="/kngil/skin/faq_list.skin.php">자주하는 질문(FAQ)</a> <a href="/faq_list">자주하는 질문(FAQ)</a>
</li> </li>
<li> <li>
<a href="/kngil/bbs/qa_list.php">문의하기(Q&A)</a> <a href="/qa_list">문의하기(Q&A)</a>
</li> </li>
<li> <li>
<a href="https://939.co.kr/saman/" target="_blank">원격지원</a> <a href="https://939.co.kr/saman/" target="_blank">원격지원</a>

View File

@@ -1,7 +1,6 @@
<?php <?php
if (session_status() === PHP_SESSION_NONE) { require_once __DIR__ . '/../bbs/env.php';
session_start(); kngil_start_session();
}
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<!--index.php--> <!--index.php-->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_agreement" role="dialog" aria-labelledby="agreement_title" aria-modal="true"> <div class="popup-wrap" id="pop_agreement" role="dialog" aria-labelledby="agreement_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_cancel" role="dialog" aria-labelledby="mypage03_title" aria-modal="true"> <div class="popup-wrap" id="pop_cancel" role="dialog" aria-labelledby="mypage03_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_join" role="dialog" aria-labelledby="join_title" aria-modal="true"> <div class="popup-wrap" id="pop_join" role="dialog" aria-labelledby="join_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_join2" role="dialog" aria-labelledby="join_title" aria-modal="true"> <div class="popup-wrap" id="pop_join2" role="dialog" aria-labelledby="join_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_join3" role="dialog" aria-labelledby="join_title" aria-modal="true"> <div class="popup-wrap" id="pop_join3" role="dialog" aria-labelledby="join_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_login2" role="dialog" aria-labelledby="login_title" aria-modal="true"> <div class="popup-wrap" id="pop_login2" role="dialog" aria-labelledby="login_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_mypage01" role="dialog" aria-labelledby="mypage01_title" aria-modal="true"> <div class="popup-wrap" id="pop_mypage01" role="dialog" aria-labelledby="mypage01_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_mypage02" role="dialog" aria-labelledby="mypage02_title" aria-modal="true" style="display:none;"> <div class="popup-wrap" id="pop_mypage02" role="dialog" aria-labelledby="mypage02_title" aria-modal="true" style="display:none;">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_mypage03" role="dialog" aria-labelledby="mypage03_title" aria-modal="true"> <div class="popup-wrap" id="pop_mypage03" role="dialog" aria-labelledby="mypage03_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_mypage04" role="dialog" aria-labelledby="mypage03_title" aria-modal="true"> <div class="popup-wrap" id="pop_mypage04" role="dialog" aria-labelledby="mypage03_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_mypage05" role="dialog" aria-labelledby="mypage03_title" aria-modal="true"> <div class="popup-wrap" id="pop_mypage05" role="dialog" aria-labelledby="mypage03_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_mypage06" role="dialog" aria-labelledby="mypage03_title" aria-modal="true"> <div class="popup-wrap" id="pop_mypage06" role="dialog" aria-labelledby="mypage03_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_password" role="dialog" aria-labelledby="password_title" aria-modal="true"> <div class="popup-wrap" id="pop_password" role="dialog" aria-labelledby="password_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_privacy" role="dialog" aria-labelledby="privacy-title" aria-modal="true"> <div class="popup-wrap" id="pop_privacy" role="dialog" aria-labelledby="privacy-title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- popup_wrap --> <!-- popup_wrap -->
<div class="popup-wrap" id="pop_search" role="dialog" aria-labelledby="search_title" aria-modal="true"> <div class="popup-wrap" id="pop_search" role="dialog" aria-labelledby="search_title" aria-modal="true">
<!-- popup_in --> <!-- popup_in -->

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>

View File

@@ -1,4 +1,6 @@
<?php <?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
// 슈퍼관리자 권한 체크 // 슈퍼관리자 권한 체크
?> ?>
<!DOCTYPE html> <!DOCTYPE html>

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>
@@ -29,7 +33,7 @@
if (!$isLogin) { if (!$isLogin) {
echo "<script> echo "<script>
alert('로그인 후 문의 등록이 가능합니다.'); alert('로그인 후 문의 등록이 가능합니다.');
location.href = '/kngil/skin/qa_list.skin.php'; location.href = '/qa_list';
</script>"; </script>";
exit; exit;
} }
@@ -56,8 +60,8 @@
<p class="sub-txt">KNGIL 관련 문의하기</p> <p class="sub-txt">KNGIL 관련 문의하기</p>
</div> </div>
<ul class="sub-tab"> <ul class="sub-tab">
<li><a href="/kngil/skin/faq_list.skin.php">자주하는 질문(FAQ)</a></li> <li><a href="/faq_list">자주하는 질문(FAQ)</a></li>
<li class="on"><a href="/kngil/bbs/qa_list.php">문의하기(Q&A)</a></li> <li class="on"><a href="/qa_list">문의하기(Q&A)</a></li>
<li><a href="https://939.co.kr/saman/" target="_blank">원격지원</a></li> <li><a href="https://939.co.kr/saman/" target="_blank">원격지원</a></li>
</ul> </ul>
</section> </section>
@@ -196,11 +200,11 @@
<!-- 수정 버튼 (로그인 사용자 == 작성자 경우에만) --> <!-- 수정 버튼 (로그인 사용자 == 작성자 경우에만) -->
<?php if ($me === $_SESSION['login']['user_id'] ?? ''): ?> <?php if ($me === $_SESSION['login']['user_id'] ?? ''): ?>
<button class="btn-secondary" onclick="location.href='/kngil/bbs/qa_write.php?id=<?= $post['post_id'] ?>'">수정</button> <button class="btn-secondary" onclick="location.href='/qa_write?id=<?= $post['post_id'] ?>'">수정</button>
<button class="btn-secondary" id="btn-delete" data-status="<?= $post['stat_bc'] ?>" data-id="<?= $post['post_id'] ?>">삭제</button> <button class="btn-secondary" id="btn-delete" data-status="<?= $post['stat_bc'] ?>" data-id="<?= $post['post_id'] ?>">삭제</button>
<?php endif; ?> <?php endif; ?>
<!-- <button onclick="history.back()">닫기</button> --> <!-- <button onclick="history.back()">닫기</button> -->
<button class="btn-primary" onclick="location.href='/kngil/bbs/qa_list.php'"> <button class="btn-primary" onclick="location.href='/qa_list'">
<i class="fa fa-list" aria-hidden="true"></i> 목록</button> <i class="fa fa-list" aria-hidden="true"></i> 목록</button>
</div> </div>
@@ -324,7 +328,7 @@
const form = document.createElement('form'); const form = document.createElement('form');
form.method = 'post'; form.method = 'post';
form.action = "/kngil/bbs/qa_detail.php"; // ✅ 중요 form.action = "/qa_detail"; // ✅ 중요
const actionInput = document.createElement('input'); const actionInput = document.createElement('input');
actionInput.type = 'hidden'; actionInput.type = 'hidden';

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>
@@ -56,8 +60,8 @@
<p class="sub-txt">KNGIL 관련 문의하기</p> <p class="sub-txt">KNGIL 관련 문의하기</p>
</div> </div>
<ul class="sub-tab"> <ul class="sub-tab">
<li><a href="/kngil/skin/faq_list.skin.php">자주하는 질문(FAQ)</a></li> <li><a href="/faq_list">자주하는 질문(FAQ)</a></li>
<li class="on"><a href="/kngil/bbs/qa_list.php">문의하기(Q&A)</a></li> <li class="on"><a href="/qa_list">문의하기(Q&A)</a></li>
<li><a href="https://939.co.kr/saman/" target="_blank">원격지원</a></li> <li><a href="https://939.co.kr/saman/" target="_blank">원격지원</a></li>
</ul> </ul>
</section> </section>
@@ -142,7 +146,7 @@
$rowNumber = $totalIndex - $idx; // 연속 번호 재계산 $rowNumber = $totalIndex - $idx; // 연속 번호 재계산
?> ?>
<?php $isNotice = ($row['category'] === 'notice'); ?> <?php $isNotice = ($row['category'] === 'notice'); ?>
<tr class="<?= $isNotice ? 'row-notice' : '' ?>" onclick="location.href='/kngil/bbs/qa_detail.php?id=<?= urlencode($row['post_id']) ?>'" style="cursor:pointer;"> <tr class="<?= $isNotice ? 'row-notice' : '' ?>" onclick="location.href='/qa_detail?id=<?= urlencode($row['post_id']) ?>'" style="cursor:pointer;">
<!-- 번호: 공지 or 연속번호 --> <!-- 번호: 공지 or 연속번호 -->
<td><?= $isNotice ? '공지' : $rowNumber ?></td> <td><?= $isNotice ? '공지' : $rowNumber ?></td>
<!-- 구분 --> <!-- 구분 -->
@@ -233,7 +237,7 @@
</div> </div>
<?php endif ?> <?php endif ?>
<div class="btn-wrap right"> <div class="btn-wrap right">
<button type="button" class="btn-primary" onclick="location.href='/kngil/skin/qa_write.skin.php'"> <button type="button" class="btn-primary" onclick="location.href='/qa_write'">
<i class="fa fa-pencil" aria-hidden="true"></i> 문의등록 <i class="fa fa-pencil" aria-hidden="true"></i> 문의등록
</button> </button>
</div> </div>
@@ -247,7 +251,7 @@
</div><!-- contents END /egbim1/skin/qa/basic/descope_qa_write.skin.php--> </div><!-- contents END /egbim1/skin/qa/basic/descope_qa_write.php-->
</div><!-- container END --> </div><!-- container END -->
<button class="btn_top js__top topbtn_on" onclick="window.scrollTo(0,0);" style="bottom:60px;"><div class="arrow"></div></button> <button class="btn_top js__top topbtn_on" onclick="window.scrollTo(0,0);" style="bottom:60px;"><div class="arrow"></div></button>
@@ -328,7 +332,7 @@ $(document).on("click", ".btn-move", function() {
alert("Q&A ID를 입력하세요."); alert("Q&A ID를 입력하세요.");
return; return;
} }
location.href = "/kngil/bbs/qa_detail.php?id=" + qnaId; location.href = "/qa_detail?id=" + qnaId;
}); });
$("#qna-id-search").on("keypress", function(e){ $("#qna-id-search").on("keypress", function(e){

View File

@@ -1,332 +0,0 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<?php include __DIR__ . "/_head.php"; ?>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Q&A 게시판 리스트</title>
<link rel="stylesheet" href="/kngil/css/qa/font-awesome.min.css?ver=2303229">
<!-- 디자인팀 작성 -->
<script src="/kngil/js/lib/jquery-3.6.1.min.js" type="text/javascript"></script>
<script src="/kngil/js/qa/jquery.mousewheel.min.js" type="text/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollToPlugin.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/aos@2.3.1/dist/aos.css" type="text/css"/>
<link rel="stylesheet" href="https://unpkg.com/lenis@1.1.9/dist/lenis.css">
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
<script src="https://unpkg.com/lenis@1.1.9/dist/lenis.min.js"></script>
<!-- <script src="/kngil/js/qa/qa_popup.js" type="text/javascript"></script>
<script src="/kngil/js/qa/qa_common.js" type="text/javascript"></script>
<script src="/kngil/js/qa/qa_index.js" type="text/javascript"></script> -->
<link rel="stylesheet" href="/kngil/css/qa/qa_reset.css"/>
<link rel="stylesheet" href="/kngil/css/qa/qa_font.css"/>
<link rel="stylesheet" href="/kngil/css/qa/qa_style.css"/>
<!-- <link rel="stylesheet" href="/kngil/css/style.css"/> -->
<!-- //디자인팀 작성 -->
</head>
<body>
<div class="wrapper">
<!-- HEADER -->
<?php include __DIR__ . "/_header.php"; ?>
<!-- //HEADER -->
<?php
include __DIR__ . "/pop_join.php";
include __DIR__ . "/pop_agreement.php";
include __DIR__ . "/pop_mypage01.php";
include __DIR__ . "/pop_mypage02.php";
include __DIR__ . "/pop_mypage03.php";
include __DIR__ . "/pop_password.php";
include __DIR__ . "/pop_privacy.php";
include __DIR__ . "/pop_search.php";
// include __DIR__ . "/_nav.php";
?>
<?php
$search = $search ?? '';
$cats = $cats ?? [];
$writer = $writer ?? '';
$status = $status ?? 'all';
?>
<div class="qa-container container faq">
<section class="intro">
<div class="top js__dark">
<h2 data-aos="fade-down" data-aos-duration="1000">Q&amp;A</h2>
<span>EG-BIM 관련 문의하기</span>
</div>
<ul class="sub_tab">
<li><a href="/kngil/skin/faq_list.skin.php">자주하는 질문(FAQ)</a></li>
<li class="on"><a href="/kngil/bbs/qa_list.php">문의하기(Q&A)</a></li>
<li><a href="https://939.co.kr/saman/" target="_blank">원격지원</a></li>
</ul>
</section>
<span class="sub_tit">문의하기(Q&A)</span>
<div class="contents">
<form class="qa-controls" method="get" action="">
<div class="search-wrap">
<div class="qa-filters">
<div class="check-group">
<!-- <strong>구분</strong> -->
<?php
// 선택 여부 유틸
$isChecked = function($v) use ($cats) {
return in_array($v, $cats ?? [], true) ? 'checked' : '';
};
// 아무 것도 선택 안되어 있으면 전체 on
$allOn = empty($cats);
?>
<label><input type="checkbox" name="cat[]" value="전체"> 전체</label>
<label><input type="checkbox" name="cat[]" value="일반문의"> 일반</label>
<label><input type="checkbox" name="cat[]" value="개선문의"> 개선</label>
<label><input type="checkbox" name="cat[]" value="오류문의"> 오류</label>
<?php if (!empty($_SESSION['login'])): ?>
<label><input type="checkbox" name="cat[]" value="관리글"> 관리</label>
<?php endif; ?>
</div>
<div class="check-box">
<strong>작성자</strong>
<label><input type="checkbox" name="writer" value="me" <?= $writer==='me' ?'checked':'' ?>> 내가 작성한 글</label>
</div>
<?php if (!empty($_SESSION['login'])): ?>
<?php $status = $_GET['status'] ?? 'all'; ?>
<div class="check-box1" style="margin-left:20px;">
<strong>상태</strong>
<select name="status" class="status-select">
<option value="all" <?= $status==='all'?'selected':'' ?>>전체</option>
<option value="wait" <?= $status==='wait'?'selected':'' ?>>문의접수</option>
<option value="review"<?= $status==='review'?'selected':'' ?>>문의검토</option>
<option value="deep" <?= $status==='deep'?'selected':'' ?>>정밀검토</option>
<option value="patch" <?= $status==='patch'?'selected':'' ?>>패치예정</option>
<option value="done" <?= $status==='done'?'selected':'' ?>>답변완료</option>
</select>
</div>
<?php endif; ?>
</div>
<div class="qa-search search-box">
<?php if (!empty($_SESSION['login'])): ?>
<input type="number" class="qna-id-input" placeholder="Q&A ID">
<button type="button" class="btn-move">이동</button>
<?php endif; ?>
<input type="text" name="q" value="<?= htmlspecialchars($search) ?>" placeholder="제목+내용 검색어를 입력하세요">
<button type="submit" class="btn-search">
<i class="fa fa-search"></i> 검색
</button>
</div>
</div>
</form>
<div class="tbl-wrap">
<table>
<colgroup>
<col style="width:5%"><col style="width:7%"><col style="width:12%"><col style="width:12%">
<col style="width:7%"><col style="width:auto"><col style="width:9%"><col style="width:9%">
</colgroup>
<thead>
<tr>
<th>번호</th><th>구분</th><th>회사</th><th>부서</th>
<th>작성자</th><th>제목</th><th>등록일</th><th>상태</th>
</tr>
</thead>
<tbody>
<?php
$totalIndex = $totalCount - ($page - 1) * $pageSize;
$idx = 0;
?>
<?php foreach($posts as $row): ?>
<?php
$isNotice = ($row['category'] === 'notice');
$rowNumber = $totalIndex - $idx; // 연속 번호 재계산
?>
<?php $isNotice = ($row['category'] === 'notice'); ?>
<tr class="<?= $isNotice ? 'row-notice' : '' ?>" onclick="location.href='/kngil/bbs/qa_detail.php?id=<?= urlencode($row['post_id']) ?>'" style="cursor:pointer;">
<!-- 번호: 공지 or 연속번호 -->
<td><?= $isNotice ? '공지' : $rowNumber ?></td>
<!-- 구분 -->
<td><?= htmlspecialchars($row['category']) ?></td>
<!-- 회사 -->
<td><?= htmlspecialchars($row['display_company']) ?></td>
<!-- 부서 -->
<td><?= htmlspecialchars($row['dept_nm'] ?? '') ?></td>
<!-- 작성자 -->
<td><?= htmlspecialchars($row['display_name']) ?></td>
<!-- 제목 -->
<td class="left">
<?php if (!empty($row['is_secret'])): ?>
<span style="color:#999">[비밀글]</span>
<?php endif; ?>
<span class="title-text">
<?= htmlspecialchars($row['title']) ?>
</span>
<!-- 댓글 개수 -->
<?php if (!empty($row['comment_count'])): ?>
<span class="badge badge-comment" style="color:#007bff; margin-left:5px;">
<i class="fa fa-commenting-o"></i> <?= $row['comment_count'] ?>
</span>
<?php endif; ?>
<!-- 첨부파일 개수 -->
<?php if (!empty($row['file_count'])): ?>
<span class="badge badge-file" style="color:#28a745; margin-left:5px;">
<i class="fa fa-paperclip"></i> <?= $row['file_count'] ?>
</span>
<?php endif; ?>
</td>
<!-- 등록일 -->
<td><?= htmlspecialchars(substr($row['created_at'],0,10)) ?></td>
<!-- 상태 -->
<td>
<?php if ($row['category'] === 'notice'): ?>
<!-- 공지사항이면 상태값 안 보여줌 -->
<span></span>
<?php else: ?>
<span class="status-<?= htmlspecialchars($row['status']) ?>">
<?= $row['status']==='wait' ? '문의접수'
: ($row['status']==='review' ? '문의검토'
: ($row['status']==='deep' ? '정밀검토'
: ($row['status']==='patch' ? '패치예정'
: ($row['status']==='done' ? '답변완료'
: '')))) ?>
</span>
<?php endif; ?>
</td>
</tr>
<?php $idx++; ?>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php if ($totalPages > 1): ?>
<div class="pagination">
<?php if ($page > 1): ?>
<a href="?<?= http_build_query(array_merge($_GET, ['page'=>$page-1])) ?>" class="prev">이전</a>
<?php else: ?><span class="prev">이전</span><?php endif ?>
<?php
$blockSize = 10;
$currentBlock= ceil($page / $blockSize);
$start = ($currentBlock - 1) * $blockSize + 1;
$end = min($totalPages, $currentBlock * $blockSize);
for ($i = $start; $i <= $end; $i++):
?>
<?php if ($i == $page): ?>
<!-- ✅ 여기! 현재 페이지는 span.current -->
<span class="current"><?= $i ?></span>
<?php else: ?>
<a href="?<?= http_build_query(array_merge($_GET, ['page'=>$i])) ?>"><?= $i ?></a>
<?php endif ?>
<?php endfor ?>
<?php if ($page < $totalPages): ?>
<a href="?<?= http_build_query(array_merge($_GET, ['page'=>$page+1])) ?>" class="next">다음</a>
<?php else: ?><span class="next">다음</span><?php endif ?>
</div>
<?php endif ?>
<div class="btn-group">
<button type="button" class="btn btn-write" onclick="location.href='/kngil/skin/qa_write.skin.php'">
<i class="fa fa-pencil" aria-hidden="true"></i> 문의등록
</button>
</div>
</div><!-- contents END /egbim1/skin/qa/basic/descope_qa_write.skin.php-->
</div><!-- container END -->
<button class="btn_top js__top topbtn_on" onclick="window.scrollTo(0,0);" style="bottom:60px;"><div class="arrow"></div></button>
<!-- FOOTER -->
<?php include __DIR__ . "/_footer.php"; ?>
<!-- //FOOTER -->
</div><!-- wrapper END -->
<script src="/kngil/js/index.js"></script>
<script src="/kngil/js/mypage.js"></script>
<script src="/kngil/js/join.js"></script>
<script src="/kngil/js/login_sms.js"></script>
<script>
// AOS / Lenis 초기화 (안전 가드)
try {
AOS.init();
if (typeof Lenis !== 'undefined') {
const lenis = new Lenis();
lenis.on('scroll', ScrollTrigger.update);
gsap.ticker.add((time)=>{ lenis.raf(time * 1000) });
gsap.ticker.lagSmoothing(0);
window.lenis = lenis; // 다른 코드에서 접근할 수 있게
}
} catch(e) { console.error(e); }
</script>
<script>
// ===== 공용 유틸 =====
function getQueryString(name){
// 페이지 구성 요소가 없을 수 있으므로 가드
const intro = document.querySelector('.intro_wrap');
if (intro) intro.style.display = "none";
const mainMask = document.querySelector('.main_mask');
if (mainMask) mainMask.classList.add('skip');
return new URLSearchParams(window.location.search).get(name);
}
// 필터 변경 시 자동 제출
(function(){
const form = document.querySelector('.qa-controls');
const boxes = Array.from(document.querySelectorAll('.qa-controls input[name="cat[]"]'));
const writer = document.querySelector('.qa-controls input[name="writer"]');
function submitForm(){ form && form.submit(); }
function syncAllToggle(changed){
const allBox = boxes.find(b => b.value === 'all');
const itemBoxes = boxes.filter(b => b.value !== 'all');
if (!allBox) return;
if (changed && changed.value === 'all') {
// 전체 체크 시 개별은 해제
if (allBox.checked) itemBoxes.forEach(b => b.checked = false);
} else {
// 개별 체크 시 전체 해제
if (itemBoxes.some(b => b.checked)) allBox.checked = false;
// 개별이 전부 해제되면 전체 자동 체크
if (!itemBoxes.some(b => b.checked)) allBox.checked = true;
}
}
boxes.forEach(b => {
b.addEventListener('change', function(){ syncAllToggle(this); submitForm(); });
});
if (writer) writer.addEventListener('change', submitForm);
})();
// Q&A ID 검색
$(document).on("click", ".btn-move", function() {
const qnaId = $(".qna-id-input").val().trim();
if (!qnaId) {
alert("Q&A ID를 입력하세요.");
return;
}
location.href = "/kngil/bbs/qa_detail.php?id=" + qnaId;
});
$("#qna-id-search").on("keypress", function(e){
if(e.key === "Enter"){
$("#qna-id-btn").click();
}
});
</script>

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!-- <?php if (!empty($errors)): ?> <!-- <?php if (!empty($errors)): ?>
@@ -46,7 +50,7 @@
if (!$isLogin) { if (!$isLogin) {
echo "<script> echo "<script>
alert('로그인 후 문의 등록이 가능합니다.'); alert('로그인 후 문의 등록이 가능합니다.');
location.href = '/kngil/skin/qa_list.skin.php'; location.href = '/qa_list';
</script>"; </script>";
exit; exit;
} }
@@ -70,15 +74,15 @@
<p class="sub-txt">KNGIL 관련 문의하기</p> <p class="sub-txt">KNGIL 관련 문의하기</p>
</div> </div>
<ul class="sub-tab"> <ul class="sub-tab">
<li><a href="/kngil/skin/faq_list.skin.php">자주하는 질문(FAQ)</a></li> <li><a href="/faq_list">자주하는 질문(FAQ)</a></li>
<li class="on"><a href="/kngil/bbs/qa_list.php">문의하기(Q&A)</a></li> <li class="on"><a href="/qa_list">문의하기(Q&A)</a></li>
<li><a href="https://939.co.kr/saman/" target="_blank">원격지원</a></li> <li><a href="https://939.co.kr/saman/" target="_blank">원격지원</a></li>
</ul> </ul>
</section> </section>
<section class="sub-content"> <section class="sub-content">
<h3 class="sub-tit">문의하기(Q&A)</h3> <h3 class="sub-tit">문의하기(Q&A)</h3>
<form id="qaForm" <form id="qaForm"
action="/kngil/bbs/qa_write.php<?= $isEdit ? '?id=' . $post['post_id'] : '' ?>" action="/qa_write<?= $isEdit ? '?id=' . $post['post_id'] : '' ?>"
method="POST" method="POST"
enctype="multipart/form-data"> enctype="multipart/form-data">
<div class="form-area"> <div class="form-area">

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>

View File

@@ -1,4 +1,7 @@
<?php <?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
include __DIR__ . '/layout_sales.php'; include __DIR__ . '/layout_sales.php';
sales_layout_start("영업실적"); sales_layout_start("영업실적");
?> ?>

View File

@@ -1,3 +1,7 @@
<?php
require_once __DIR__ . '/../bbs/env.php';
kngil_start_session();
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>