dbms_init...1

This commit is contained in:
choi.jh 2025-06-20 18:50:52 +09:00
parent 4ffda43d2b
commit 0e4120f0e0
17 changed files with 484 additions and 99 deletions

View File

@ -190,6 +190,7 @@ define('ICONS', [
'CANCEL' => '<i class="bi bi-x-circle"></i>',
'CLOSE' => '<i class="bi bi-x-circle-fill"></i>',
'CLIENT' => '<i class="bi bi-person-circle"></i>',
'CHART' => '<i class="bi bi-bar-chart"></i>',
'CHECK' => '<i class="bi bi-check-circle"></i>',
'CHECK_OFF' => '<i class="bi bi-check-circle-fill"></i>',
'CHECK_ON' => '<i class="bi bi-check2-circle"></i>',
@ -390,3 +391,8 @@ define('SERVICE_ITEM_TYPES', $_ENV['SERVICEINFO_ITEM_TYPES']
"DEFENCE" => "방어(CS)",
"DOMAIN" => "도메인",
]);
//신규서비스 Interval
define('SERVICE_NEW_INTERVAL', $_ENV['SERVICE_NEW_INTERVAL'] ?? $_SERVER['SERVICE_NEW_INTERVAL'] ?? 7);
//미지급 Item_type
define('SERVICE_UNPAID_ITEM_TYPE', $_ENV['SERVICE_UNPAID_ITEM_TYPE'] ?? $_SERVER['SERVICE_UNPAID_ITEM_TYPE'] ?? "SERVER");

View File

@ -8,7 +8,7 @@ use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
use App\Helpers\Customer\ServiceHelper;
use App\Helpers\Customer\ServicePaymentHelper;
use App\Services\Customer\ServiceService;
use App\Services\Customer\ServiceItemService;
use App\Services\Equipment\CodeService;
@ -33,10 +33,10 @@ class ServiceController extends CustomerController
}
return $this->_service;
}
public function getHelper(): ServiceHelper
public function getHelper(): ServicePaymentHelper
{
if (!$this->_helper) {
$this->_helper = new ServiceHelper($this->request);
$this->_helper = new ServicePaymentHelper($this->request);
}
return $this->_helper;
}

View File

@ -2,8 +2,9 @@
namespace App\Controllers\Admin;
use App\Helpers\UserHelper;
use App\Services\UserService;
use App\Helpers\HomeHelper;
use App\Services\Customer\ServiceService;
use App\Services\Customer\ServicePaymentService;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
@ -12,30 +13,76 @@ use Psr\Log\LoggerInterface;
class Home extends AdminController
{
private $_service = null;
private ?ServiceService $_serviceService = null;
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
parent::initController($request, $response, $logger);
$this->content_title = lang("{$this->getService()->getClassName()}.title");
$this->class_path .= $this->getService()->getClassName();
$this->uri_path .= strtolower($this->getService()->getClassName('/')) . '/';
// $this->view_path .= strtolower($this->getService()->getClassName()) . DIRECTORY_SEPARATOR;
}
final public function getService(): UserService
final public function getService(): ServicePaymentService
{
if (!$this->_service) {
$this->_service = new UserService($this->request);
$this->_service = new ServicePaymentService($this->request);
}
return $this->_service;
}
public function getHelper(): mixed
{
if (!$this->_helper) {
$this->_helper = new UserHelper($this->request);
$this->_helper = new HomeHelper($this->request);
}
return $this->_helper;
}
final public function getServiceService(): ServiceService
{
if (!$this->_serviceService) {
$this->_serviceService = new ServiceService($this->request);
}
return $this->_serviceService;
}
protected function getResultSuccess(string $message = MESSAGES["SUCCESS"], ?string $actionTemplate = null): RedirectResponse|string
{
switch ($this->getAction()) {
case 'index':
$this->control = $this->getControlDatas();
$this->getHelper()->setViewDatas($this->getViewDatas());
$actionTemplate = $this->request->getVar('ActionTemplate') ?? $actionTemplate;
if ($actionTemplate) {
$view_file = $this->view_path . $actionTemplate . DIRECTORY_SEPARATOR . $this->getAction();
} else {
$view_file = $this->view_path . 'welcome_message';
}
$result = view($view_file, ['viewDatas' => $this->getViewDatas()]);
break;
default:
$result = parent::getResultSuccess($message, $actionTemplate);
}
return $result;
}
//Index,FieldForm관련
public function index(): RedirectResponse|string
{
$this->initAction(__FUNCTION__);
//신규서비스정보
$this->interval = $this->request->getVar('interval') ?? SERVICE_NEW_INTERVAL;
$this->newServiceEntities = $this->getServiceService()->getNewService(intval($this->interval));
$this->newServiceCount = count($this->newServiceEntities);
//미지금서버Count
$this->item_type = $this->request->getVar('item_type') ?? SERVICE_UNPAID_ITEM_TYPE;
$this->unPaidCount = $this->getService()->getUnPaid($this->item_type);
//LINE,IP,SERVER등 추가 FilterOption 셋팅용
foreach (SERVICE_ITEM_TYPES as $item_type => $label) {
$options = $this->getService()->getServiceItemLinkService($item_type)->getEntities();
$this->setFilterFieldOption($item_type, $options);
}
helper(['form']);
return view('admin/welcome_message', ['viewDatas' => $this->getViewDatas()]);
return $this->getResultSuccess();
}
}

View File

@ -17,11 +17,19 @@ class ServiceEntity extends CustomerEntity
{
return "S" . $this->getPK();
}
public function getSwitch(): string
{
return $this->attributes['switch'];
}
//서버코드
public function getCode(): string
{
return $this->attributes['code'];
}
public function getType(): string
{
return $this->attributes['type'];
}
final public function getBillingAt(): string
{
return $this->attributes['billing_at'];

View File

@ -0,0 +1,73 @@
<?php
namespace App\Helpers;
use App\Models\Customer\ServicePaymentModel;
use CodeIgniter\HTTP\IncomingRequest;
class HomeHelper extends CommonHelper
{
protected ?IncomingRequest $request = null;
public function __construct(?IncomingRequest $request = null)
{
parent::__construct($request);
$this->setTitleField(field: ServicePaymentModel::TITLE);
}
public function getFieldView(string $field, mixed $value, array $viewDatas, array $extras = []): string|null
{
switch ($field) {
case "countdown": //결제일Countdown
$value = $viewDatas['entity']->getView_CounDueAt();
break;
case 'item_uid':
// echo "Value:" . $viewDatas['entity']->getItemType() . ":" . $value;
// dd($viewDatas['control']['filter_optons']);
$value = $viewDatas['control']['filter_optons'][$viewDatas['entity']->getItemType()][$value]->getTitle();
break;
case 'amount':
$value = number_format($value) . "";
break;
case 'status':
$value = parent::getFieldView($field, $value, $viewDatas, $extras);
break;
default:
dd($viewDatas['entity']);
if (in_array($field, $viewDatas['control']['filter_fields'])) {
$value = $viewDatas['control']['filter_optons'][$field][$value]->getTitle();
}
break;
}
if (is_array($value)) {
echo __METHOD__ . "에서 오류: {$field}의 값이 Array형태입니다";
exit;
}
return $value;
}
public function getListButton(string $action, array $viewDatas, array $extras = []): string
{
switch ($action) {
case 'modify':
$action = $viewDatas['entity']->getPK();
break;
case 'invoice':
$action = form_submit($action . "_submit", '청구서 발행', [
"formaction" => current_url() . '/' . $action,
"class" => "btn btn-outline btn-primary",
// "onclick" => "return submitBatchJob()"
]);
break;
case 'delete':
if ($viewDatas['entity']->getStatus() !== DEFAULTS['STATUS']) {
$action = "";
} else {
$action = parent::getListButton($action, $viewDatas, $extras);
}
break;
default:
$action = parent::getListButton($action, $viewDatas, $extras);
break;
}
return $action;
}
}

View File

@ -75,6 +75,13 @@ class ServicePaymentService extends CustomerService
}
return $options;
}
//미납 Count
final public function getUnPaid(string $item_type, string $status = DEFAULTS['STATUS']): int
{
$sql = "SELECT COUNT(*) as CNT FROM serviceinfo_payment WHERE billing_at < NOW() AND item_type = ? AND status = ?";
$row = $this->getModel()->query($sql, [$item_type, $status])->getRow();
return intval($row->CNT);
}
//ServiceItemService에서 사용
public function createPaymentByServiceItem(ServiceItemEntity $serviceItemEntity): ServicePaymentEntity
{

View File

@ -97,6 +97,12 @@ class ServiceService extends CustomerService
}
return $options;
}
//interval을 기준으로 신규서비스 가져오기
final public function getNewService(int $interval, string $status = DEFAULTS['STATUS'])
{
$sql = "SELECT * FROM serviceinfo WHERE start_at >= NOW() - INTERVAL ? DAY AND status = ?";
return $this->getModel()->query($sql, [$interval, $status])->getResult(ServiceEntity::class);
}
//다음 달로 결제일을 연장합니다.
final public function extendBillingAt(string $billing_at, string $status): bool
{

View File

@ -12,7 +12,7 @@
</td>
<td class="layout_right">
<!-- Layout Right Start -->
<?= $this->include("templates/{$viewDatas['layout']}/index_header"); ?>
<div class="layout_header"><?= $this->include("templates/{$viewDatas['layout']}/index_header"); ?></div>
<div id="container" class="layout_content">
<link href="/css/<?= $viewDatas['layout'] ?>/index.css" media="screen" rel="stylesheet" type="text/css" />
<div class="index_body">

View File

@ -12,7 +12,7 @@
</td>
<td class="layout_right">
<!-- Layout Right Start -->
<?= $this->include("templates/{$viewDatas['layout']}/index_header"); ?>
<div class="layout_header"><?= $this->include("templates/{$viewDatas['layout']}/index_header"); ?></div>
<div id="container" class="layout_content">
<link href="/css/<?= $viewDatas['layout'] ?>/index.css" media="screen" rel="stylesheet" type="text/css" />
<div class="index_body">

View File

@ -12,7 +12,7 @@
</td>
<td class="layout_right">
<!-- Layout Right Start -->
<?= $this->include("templates/{$viewDatas['layout']}/index_header"); ?>
<div class="layout_header"><?= $this->include("templates/{$viewDatas['layout']}/index_header"); ?></div>
<div id="container" class="layout_content">
<link href="/css/<?= $viewDatas['layout'] ?>/index.css" media="screen" rel="stylesheet" type="text/css" />
<div class="index_body">

View File

@ -1,5 +1,6 @@
<?= $this->extend(LAYOUTS[$viewDatas['layout']]['path']) ?>
<?= $this->section('content') ?>
<!-- Layout Middle Start -->
<div class="layout_top"><?= $this->include(LAYOUTS[$viewDatas['layout']]['path'] . '/top'); ?></div>
<!-- Layout Middle Start -->
<table class="layout_middle">
@ -11,93 +12,19 @@
</td>
<td class="layout_right">
<!-- Layout Right Start -->
<?= $this->include("templates/{$viewDatas['layout']}/index_header"); ?>
<div id="container" class="layout_content">
<!-- RSS Feed Start -->
<style>
.news-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.news-item {
width: 48%;
margin-bottom: 20px;
border: 1px solid #ddd;
padding: 10px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.news-item h3 {
font-size: 18px;
margin-bottom: 5px;
}
.news-item p {
font-size: 14px;
color: #666;
}
</style>
<div class="news-container" id="newsContainer"><!-- RSS 피드 항목들이 여기에 동적으로 추가됩니다 --></div>
<script>
// fetchRSS 함수 정의
function fetchRSS() {
fetch('/RSSFeed/getITWorld')
.then(response => response.json())
.then(data => {
const newsContainer = document.getElementById('newsContainer');
newsContainer.innerHTML = '';
data.forEach(item => {
const pubDate = new Date(item.pubDate);
const newsItem = document.createElement('div');
newsItem.className = 'news-item';
let imageUrl = item.imageUrl || extractImageFromContent(item.content);
imageUrl = convertToAbsoluteUrl(imageUrl, item.link);
newsItem.innerHTML = `
<h3><img src="${imageUrl || '/images/common/news.png'}" alt="${item.title}" style="width: 30px; height: 30px; object-fit: cover; margin-bottom: 10px;" onerror="this.onerror=null; this.src='/images/common/news.png';"><a href="${item.link}" target="_blank">${item.title}</a></h3>
<p>${item.description}</p>
<small>게시일: ${pubDate.toLocaleString()}</small>
`;
newsContainer.appendChild(newsItem);
});
})
.catch(error => console.error('RSS 피드를 가져오는 중 오류 발생:', error));
}
function extractImageFromContent(content) {
const parser = new DOMParser();
const doc = parser.parseFromString(content, 'text/html');
const img = doc.querySelector('img');
return img ? img.src : null;
}
function convertToAbsoluteUrl(url, baseUrl) {
if (!url) return null;
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
const base = new URL(baseUrl);
if (url.startsWith('/')) {
return `${base.protocol}//${base.hostname}${url}`;
}
return `${base.protocol}//${base.hostname}${base.pathname.substring(0, base.pathname.lastIndexOf('/') + 1)}${url}`;
}
document.addEventListener('DOMContentLoaded', function () {
fetchRSS();
setInterval(fetchRSS, 3600000);
});
</script>
<!-- RSS Feed End -->
<?= $this->include("templates/{$viewDatas['layout']}/welcome_banner"); ?>
<div class="row align-items-start" style="padding-top:20px;">
<div class="col-5">
<?= $this->include("templates/{$viewDatas['layout']}/welcome_total"); ?>
</div>
<div class="col-7">
<?= $this->include("templates/{$viewDatas['layout']}/welcome_new"); ?>
</div>
</div>
<div class="layout_footer"><?= $this->include("templates/{$viewDatas['layout']}/index_footer"); ?></div>
<!-- Layout Right End -->
</td>
</tr>
</table>
<!-- Layout Middle End -->
<div class="layout_bottom"><?= $this->include(LAYOUTS[$viewDatas['layout']]['path'] . '/bottom'); ?></div>
<div class=" layout_bottom"><?= $this->include(LAYOUTS[$viewDatas['layout']]['path'] . '/bottom'); ?></div>
<?= $this->endSection() ?>

View File

@ -1,7 +1,7 @@
<!-- top start -->
<nav class="navbar navbar-expand-lg">
<div class="container-fluid">
<nav class="nav"><a class="navbar-brand" href="#">CFMGR 관리</a></nav>
<nav class="nav"><a class="navbar-brand" href="#">DBMS 관리</a></nav>
<ul class="nav justify-content-center">
<li class="nav-item">
<?= ICONS['LOCK'] ?>

View File

@ -1,4 +1,3 @@
<div class="layout_header">
<ul class="nav nav-tabs">
<li class="nav-item">
<span class="nav-item navbar-brand" aria-current="page">
@ -9,5 +8,4 @@
<span class="nav-link active" aria-current="page" data-bs-toggle="modal" data-bs-target="#index_header_dns" style="cursor:pointer;">Cloudflare DNS</span>
</li>
</ul>
<?= $this->include("templates/{$viewDatas['layout']}/index_header/dns"); ?>
</div>
<?= $this->include("templates/{$viewDatas['layout']}/index_header/dns"); ?>

View File

@ -0,0 +1,146 @@
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<style>
.card-clickable {
cursor: pointer;
}
.dashboard-card {
color: white;
}
.bg-blue {
background-color: #337ab7;
}
.bg-yellow {
background-color: #f0ad4e;
}
.bg-green {
background-color: #5cb85c;
}
.bg-red {
background-color: #d9534f;
}
.card-footer a {
color: white;
text-decoration: none;
}
.card-footer .fa {
font-size: 1.2em;
}
.fa-5x {
font-size: 4em;
}
.huge {
font-size: 2.5em;
font-weight: bold;
}
.bg-detail {
background-color: #F5F5F5;
}
.bg-detail .bg_blue_font {
color: #337ab7;
}
.bg-detail .bg_yellow_font {
color: #f0ad4e;
}
.bg-detail .bg_green_font {
color: #5cb85c;
}
.bg-detail .bg_red_font {
color: #d9534f;
}
</style>
</head>
<div class="row">
<div class="col-lg-3 col-md-6">
<div class="card dashboard-card bg-blue">
<div class=" card-body">
<div class="row">
<div class="col-4">
<i class="fa fa-comments fa-5x"></i>
</div>
<div class="col-8 text-end">
<div class="huge">0</div>
<div class="bg-blue"> 쪽지 알림</div>
</div>
</div>
</div>
<div class="card-footer d-flex justify-content-between align-items-center bg-detail">
<span class="bg_blue_font">자세히보기</span>
<i class="fa fa-arrow-circle-right bg_blue_font"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card dashboard-card bg-yellow card-clickable" onclick="document.location.href='/admin/customer/service';">
<div class="card-body">
<div class="row">
<div class="col-4">
<i class="fa fa-plus-square-o fa-5x"></i>
</div>
<div class="col-8 text-end">
<div class="huge"><?= $viewDatas['newServiceCount'] ?></div>
<div>최근 <?= $viewDatas['interval'] ?>일간 신규서버수</div>
</div>
</div>
</div>
<div class="card-footer d-flex justify-content-between align-items-center bg-detail">
<span class="bg_yellow_font">자세히보기</span>
<i class="fa fa-arrow-circle-right bg_yellow_font"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card dashboard-card bg-green">
<div class="card-body">
<div class="row">
<div class="col-4">
<i class="fa fa-tasks fa-5x"></i>
</div>
<div class="col-8 text-end">
<div class="huge">0</div>
<div>요청업무 알림</div>
</div>
</div>
</div>
<div class="card-footer d-flex justify-content-between align-items-center bg-detail">
<span class="bg_green_font">자세히보기</span>
<i class="fa fa-arrow-circle-right bg_green_font"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card dashboard-card bg-red card-clickable" onclick="document.location.href='/admin/customer/payment';">
<div class="card-body">
<div class="row">
<div class="col-4">
<i class="fa fa-support fa-5x"></i>
</div>
<div class="col-8 text-end">
<div class="huge"><?= $viewDatas['unPaidCount'] ?></div>
<div>금일 기준 미납 서버</div>
</div>
</div>
</div>
<div class="card-footer d-flex justify-content-between align-items-center bg-detail">
<span class="bg_red_font">자세히보기</span>
<i class="fa fa-arrow-circle-right bg_red_font"></i>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,43 @@
<div class="layout_header">
<ul class="nav nav-tabs">
<li class="nav-item">
<span class="nav-item navbar-brand" aria-current="page">
<h4>&nbsp;&nbsp;<?= ICONS['CHART'] ?> 최신 신규 서버 현황&nbsp;&nbsp;</h4>
</span>
</li>
</ul>
</div>
<div style="border-left: 1px solid black; border-right: 1px solid black; padding:20px;">
<table class="table table-bordered table-hover align-middle">
<thead class="table-light">
<tr>
<th>서비스코드</th>
<th>업체명</th>
<th>구분</th>
<th>장비번호</th>
<th>스위치정보</th>
<th>IP정보</th>
<th>CS</th>
<th>등록자</th>
<th>비고</th>
</tr>
</thead>
<tbody>
<?php foreach ($viewDatas['newServiceEntities'] as $entity): ?>
<?php $viewDatas['entity'] = $entity ?>
<tr>
<td><a href="/admin/customer/service" class="service-code"><?= $entity->getTitle() ?></a></td>
<td><?= $viewDatas['helper']->getFieldView('ownerinfo_uid', $entity->getOwnerUID(), $viewDatas) ?></td>
<td><?= $viewDatas['helper']->getFieldView('type', $entity->getType(), $viewDatas) ?></td>
<td><?= $viewDatas['helper']->getFieldView('code', $entity->getCode(), $viewDatas) ?></td>
<td><?= $viewDatas['helper']->getFieldView('switch', $entity->getSwitch(), $viewDatas) ?></td>
<td><?= $viewDatas['helper']->getFieldView('IP', null, $viewDatas) ?></td>
<td><?= $viewDatas['helper']->getFieldView('DEFEMCE', null, $viewDatas) ?></td>
<td>등록자</td>
<td>비고</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div>
<div class="layout_footer"><?= $this->include("templates/{$viewDatas['layout']}/welcome_footer"); ?></div>

View File

@ -0,0 +1,124 @@
<div class="layout_header">
<ul class="nav nav-tabs">
<li class="nav-item">
<span class="nav-item navbar-brand" aria-current="page">
<h4>&nbsp;&nbsp;<?= ICONS['CHART'] ?> 최신 신규 서버 현황&nbsp;&nbsp;</h4>
</span>
</li>
</ul>
</div>
<div style="border-left: 1px solid black; border-right: 1px solid black; padding:20px;">
<table class="table table-bordered table-hover align-middle">
<thead class="table-light">
<tr>
<th rowspan="2">고객명</th>
<th colspan="2">일반</th>
<th colspan="2">방어</th>
<th colspan="2">전용</th>
<th colspan="2">대체</th>
<th colspan="2">테스트</th>
<th colspan="3">합계</th>
</tr>
<tr>
<th>도쿄</th>
<th>치바</th>
<th>도쿄</th>
<th>치바</th>
<th>도쿄</th>
<th>치바</th>
<th>도쿄</th>
<th>치바</th>
<th>도쿄</th>
<th>치바</th>
<th>도쿄</th>
<th>치바</th>
<th>합계</th>
</tr>
</thead>
<tbody>
<tr>
<td>prime</td>
<td>4</td>
<td>192</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>12</td>
<td>0</td>
<td>0</td>
<td>3</td>
<td>3</td>
<td>4</td>
<td>204</td>
<td>208</td>
</tr>
<tr>
<td>itsolution</td>
<td>10</td>
<td>206</td>
<td>6</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>16</td>
<td>206</td>
<td>222</td>
</tr>
<tr>
<td>gdidc</td>
<td>5</td>
<td>38</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>7</td>
<td>0</td>
<td>0</td>
<td>3</td>
<td>3</td>
<td>5</td>
<td>45</td>
<td>50</td>
</tr>
<tr>
<td>gamewing</td>
<td>12</td>
<td>121</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>12</td>
<td>121</td>
<td>133</td>
</tr>
</tbody>
<tfoot class="table-light fw-bold">
<tr>
<td>총합계</td>
<td>31</td>
<td>557</td>
<td>6</td>
<td>0</td>
<td>0</td>
<td>19</td>
<td>0</td>
<td>0</td>
<td>7</td>
<td>7</td>
<td>37</td>
<td>576</td>
<td>613</td>
</tr>
</tfoot>
</table>
</div>
<div class="layout_footer"><?= $this->include("templates/{$viewDatas['layout']}/welcome_footer"); ?></div>