dbmsv3 init...1

This commit is contained in:
choi.jh 2025-10-03 16:41:30 +09:00
parent 5363057dec
commit 8ebabb14b4
35 changed files with 575 additions and 1677 deletions

View File

@ -2,8 +2,9 @@
namespace App\Cells\Customer;
use App\Services\PaymentService;
use App\Helpers\Equipment\ServerPartHelper;
use App\Services\Customer\ServiceService;
use App\Services\PaymentService;
class ServiceCell extends CustomerCell
{
@ -36,7 +37,8 @@ class ServiceCell extends CustomerCell
'control' => $this->getService()->getControlDatas(),
'service' => $this->getService(),
'entities' => $entities,
'unPaids' => $unPaids
'unPaids' => $unPaids,
'serverPartHelper' => new ServerPartHelper(),
]
]);
}

View File

@ -175,6 +175,7 @@ $routes->group('admin', ['namespace' => 'App\Controllers\Admin', 'filter' => 'au
$routes->get('toggle/(:num)/(:any)', 'ServerController::toggle/$1/$2');
$routes->post('batchjob', 'ServerController::batchjob');
$routes->post('batchjob_delete', 'ServerController::batchjob_delete');
$routes->get('download/(:alpha)', 'ServerPartController::download/$1');
});
$routes->group('serverpart', ['namespace' => 'App\Controllers\Admin\Equipment'], function ($routes) {
$routes->get('/', 'ServerPartController::index');

View File

@ -2,7 +2,7 @@
namespace App\Controllers\Admin\Equipment;
use App\Services\Customer\ServiceService;
use App\Entities\Equipment\ServerEntity;
use App\Services\Equipment\ServerService;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\RequestInterface;
@ -56,6 +56,20 @@ class ServerController extends EquipmentController
$formDatas = $this->getService()->getFormDatas();
$formDatas['code'] = sprintf("%d%dXX-M%d", date("y"), ceil((int)date("m") / 3), $this->getService()->getLatestPK());
$this->getService()->setFormDatas($formDatas);
$ips = [];
foreach ($this->getService()->getIPService()->getEntities(['status' => STATUS['AVAILABLE']]) as $ipEntity) {
$ips[] = $ipEntity->getTitle();
}
$this->ips = $ips;
parent::create_form_process();
}
protected function modify_form_process(mixed $entity): ServerEntity
{
$ips = [];
foreach ($this->getService()->getIPService()->getEntities('ip = "' . $entity->getIP() . '" OR status = "' . STATUS['AVAILABLE'] . '"') as $ipEntity) {
$ips[] = $ipEntity->getTitle();
}
$this->ips = $ips;
return parent::modify_form_process($entity);
}
}

View File

@ -164,6 +164,7 @@ abstract class CommonController extends BaseController
$this->getService()->setFormFilters();
$this->getService()->setFormRules();
$this->doValidations();
$this->getService()->getFormDatas();
$this->entity = $this->create_process($this->getService()->getFormDatas());
$db->transCommit();
return $this->getResultSuccess();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,8 +4,8 @@
"settings": {
"width": 3000,
"height": 3000,
"scrollTop": -538.7873,
"scrollLeft": -1597,
"scrollTop": -1484.7873,
"scrollLeft": -632,
"zoomLevel": 0.79,
"show": 511,
"database": 4,
@ -255,6 +255,7 @@
"4iRyOhmW3b7kbiZT8lQyY",
"34psXzS7RLX0sWXZyDGGf",
"I8DumSwkLWz-Ve5_vc0uE",
"4t01_53QawHcw0lfY4zDm",
"9F6QpQqxeEggZ0FHM81O1",
"tsDqk1dzwzUtvBzpjmarJ",
"hmZlcR-Pw2C_ife1zzo5o",
@ -289,6 +290,7 @@
"34psXzS7RLX0sWXZyDGGf",
"I8DumSwkLWz-Ve5_vc0uE",
"m77kSp3scTgMhInPBjsc3",
"4t01_53QawHcw0lfY4zDm",
"9F6QpQqxeEggZ0FHM81O1",
"EKrwHre6e66jqAMnAW_KR",
"Z2CriPHsk4OV0AD1jAhM4",
@ -336,7 +338,7 @@
"color": ""
},
"meta": {
"updateAt": 1758872003569,
"updateAt": 1759457394197,
"createAt": 1745819764137
}
},
@ -9523,6 +9525,26 @@
"updateAt": 1759211445971,
"createAt": 1759211431057
}
},
"4t01_53QawHcw0lfY4zDm": {
"id": "4t01_53QawHcw0lfY4zDm",
"tableId": "B4qGh3KZsXHQ3_4EOgwJZ",
"name": "ip",
"comment": "메인IP",
"dataType": "CHAR(16)",
"default": "",
"options": 4,
"ui": {
"keys": 0,
"widthName": 60,
"widthComment": 60,
"widthDataType": 60,
"widthDefault": 60
},
"meta": {
"updateAt": 1759457823730,
"createAt": 1759457280264
}
}
},
"relationshipEntities": {
@ -9957,7 +9979,7 @@
"RITMHZcQAJ7KvtxkTtMv-"
],
"x": 1746.7498,
"y": 2062.4788,
"y": 2077.4788,
"direction": 2
},
"end": {
@ -9994,7 +10016,7 @@
"4iRyOhmW3b7kbiZT8lQyY"
],
"x": 1746.7498,
"y": 1878.4788,
"y": 1881.4788,
"direction": 2
},
"meta": {
@ -10069,7 +10091,7 @@
"RITMHZcQAJ7KvtxkTtMv-"
],
"x": 1086.7498,
"y": 2016.4788,
"y": 2028.4788,
"direction": 1
},
"end": {
@ -10097,7 +10119,7 @@
"RITMHZcQAJ7KvtxkTtMv-"
],
"x": 1746.7498,
"y": 2154.4788,
"y": 2175.4788,
"direction": 2
},
"end": {
@ -10405,7 +10427,7 @@
"RITMHZcQAJ7KvtxkTtMv-"
],
"x": 1746.7498,
"y": 1970.4788,
"y": 1979.4788,
"direction": 2
},
"end": {

View File

@ -11,11 +11,11 @@ class ServerEntity extends EquipmentEntity
const DEFAULT_STATUS = STATUS['AVAILABLE'];
final public function getClientInfoUID(): string|null
{
return $this->attributes['clientinfo_uid'];
return $this->attributes['clientinfo_uid'] ?? null;
}
final public function getServiceInfoUID(): string|null
{
return $this->attributes['serviceinfo_uid'];
return $this->attributes['serviceinfo_uid'] ?? null;
}
//기본기능용
public function getCustomTitle(): string
@ -30,4 +30,8 @@ class ServerEntity extends EquipmentEntity
{
return $this->attributes['type'] ?? "";
}
public function getIP(): string|null
{
return $this->attributes['ip'] ?? null;
}
}

View File

@ -22,11 +22,26 @@ class ServerHelper extends EquipmentHelper
$form .= form_hidden($field, (string)$value);
}
break;
case 'ip': //값 그대료 표시
$form = "<div class=\"ac-wrap\" style=\"position:relative;\">";
$form .= form_input($field, $value ?? "", [
'id' => 'ipInput',
"list" => "ipList",
"placeholder" => "예: 27.125.207.100",
"autocomplete" => "off",
...$extras
]);
$form .= "<div id=\"ipPanel\" class=\"ac-panel\" hidden></div></div>";
break;
case 'manufactur_at':
case 'format_at':
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' calender' : 'calender';
$form = form_input($field, $value ?? "", $extras);
break;
case 'ip':
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' select-field' : 'select-field';
$form = $this->form_dropdown_common($field, $value, $viewDatas, $extras);
break;
default:
$form = parent::getFieldForm($field, $value, $viewDatas, $extras);
break;
@ -36,6 +51,8 @@ class ServerHelper extends EquipmentHelper
public function getFieldView(string $field, mixed $value, array $viewDatas, array $extras = []): string|null
{
switch ($field) {
case 'ip': //값 그대료 표시
break;
case 'title':
$value = parent::getFieldView($field, $value, $viewDatas, $extras);
break;

View File

@ -140,7 +140,7 @@ class ServerPartHelper extends EquipmentHelper
case 'OS':
case 'SOFTWARE':
$extras = [
"class" => "btn btn-sm btn-outline btn-circle form-label-sm",
"class" => "btn btn-sm btn-outline btn-circle btn-link form-label-sm",
"target" => "_self",
...$extras,
];

View File

@ -6,5 +6,5 @@ use App\Entities\Equipment\ServerPartEntity;
interface ServerPartInterface extends EquipmentInterface
{
public function setServerPart(string $action, ServerPartEntity $oldServerPartEntity, ServerPartEntity $serverPartEntity, array $serverPartDatas): mixed;
public function setServerPart(string $action, ServerPartEntity $serverPartEntity, array $serverPartDatas): ServerPartEntity;
}

View File

@ -6,6 +6,7 @@ return [
'serviceinfo_uid' => "서비스번호",
'code' => "장비번호",
'type' => "형식",
'ip' => "메인IP",
'title' => "모델명",
'price' => "기본가",
'manufactur_at' => "입고일",
@ -38,6 +39,8 @@ return [
"INTEL I5" => "INTEL I5",
"INTEL I7" => "INTEL I7",
"INTEL I9" => "INTEL I9",
"VPC" => "아마존-VPN",
"KCS" => "KT-VPN",
],
"STATUS" => [
STATUS['AVAILABLE'] => "사용가능",

View File

@ -19,6 +19,7 @@ class ServerModel extends EquipmentModel
"serviceinfo_uid",
"code",
"type",
"ip",
"title",
"price",
"manufactur_at",
@ -54,6 +55,10 @@ class ServerModel extends EquipmentModel
case "manufactur_at":
$rule = "required|valid_date";
break;
case "ip":
$rule = "permit_empty|trim|valid_ip[both]"; //ipv4 , ipv6 , both(ipv4,ipv6)
$rule .= in_array($action, ["create", "create_form"]) ? "|is_unique[{$this->table}.{$field}]" : "";
break;
case "format_at":
$rule = "permit_empty|valid_date";
break;

View File

@ -220,11 +220,10 @@ class ServiceService extends CustomerService
throw new \Exception(__METHOD__ . "에서 오류발생: 서버가 지정되지 않았습니다.");
}
//서버등록
$entity = $entity->setServerEntity($this->getServerService()->setService('create', $entity, $formDatas));
$entity = $this->getServerService()->setService('create', $entity, $formDatas);
//전체 서비스금액 설정
$paymentEntity = $this->getPaymentService()->setService('create', $entity, $formDatas);
$entity = $entity->setPaymentEntity($paymentEntity);
return parent::modify($entity, ['paymentifo_uid' => $paymentEntity->getPK()]);
$entity = $this->getPaymentService()->setService('create', $entity, $formDatas);
return parent::modify($entity, ['paymentifo_uid' => $entity->getPaymentEntity()->getPK()]);
}
//수정
public function modify(mixed $entity, array $formDatas): ServiceEntity
@ -237,18 +236,18 @@ class ServiceService extends CustomerService
//기존 서버정보와 다르다면 서버변경
if ($oldEntity->getServerEntity()->getPK() != $formDatas['serverinfo_uid']) {
//기존서버처리
$entity = $entity->setServerEntity($this->getServerService()->setService('delete', $oldEntity, ['serverinfo_uid' => $oldEntity->getServerInfoUID()]));
$oldEntity = $this->getServerService()->setService('delete', $oldEntity, ['serverinfo_uid' => $oldEntity->getServerInfoUID()]);
//수정할신규서버처리
$entity = $entity->setServerEntity($this->getServerService()->setService('create', $entity, $formDatas));
$entity = $this->getServerService()->setService('create', $entity, $formDatas);
}
//전체 서비스금액 설정
return $entity->setPaymentEntity($this->getPaymentService()->setService('modify', $entity, $formDatas));
return $this->getPaymentService()->setService('modify', $entity, $formDatas);
}
//삭제
public function delete(mixed $entity): ServiceEntity
{
//서버해지
$entity = $entity->setServerEntity($this->getServerService()->setService('delete', $entity, []));
$entity = $this->getServerService()->setService('delete', $entity, []);
return parent::delete($entity);
}
//비고(History)설정
@ -261,8 +260,7 @@ class ServiceService extends CustomerService
{
//대체서버추가 및 결제처리는 하지않음
$formDatas['type'] = 'alternative';
$this->getServerService()->setService('create', $entity, $formDatas);
return $entity;
return $this->getServerService()->setService('create', $entity, $formDatas);
}
//대체서버를 메인서버로 설정
public function changeServere(ServiceEntity $entity, array $formDatas): ServiceEntity
@ -272,16 +270,15 @@ class ServiceService extends CustomerService
throw new \Exception(__METHOD__ . "에서 오류발생: 기존 메인 서버정보를 찾을수 없습니다.");
}
//기존메인서버 정보회수처리용
$entity = $entity->setServerEntity($this->getServerService()->setService('delete', $entity, $formDatas));
$entity = $this->getServerService()->setService('delete', $entity, $formDatas);
//메인서버로 선정된 대체서버정보
$formDatas['type'] = $serverEntity->getType();
$this->getServerService()->setService('create', $entity, $formDatas);
$entity = $this->getServerService()->setService('create', $entity, $formDatas);
//서비스 금액 재계산 후 서비스정보 수정
$formDatas['amount'] = $this->getCaculatedAmount($entity);
$entity = parent::modify($entity, $formDatas);
//전체 서비스금액 설정
$entity = $entity->setPaymentEntity($this->getPaymentService()->setService('modify', $entity, $formDatas));
return $entity;
return $this->getPaymentService()->setService('modify', $entity, $formDatas);
}
//대체서버해지(대체서버는 해지는 가격변동은 없음)
public function terminateServer(ServiceEntity $entity, array $formDatas): ServiceEntity
@ -290,7 +287,6 @@ class ServiceService extends CustomerService
throw new \Exception(__METHOD__ . "에서 오류발생: 서비스의 메인 서버정보는 해지할 수 없습니다.");
}
//대체서버해지 및 결제처리는 하지않음
$entity = $entity->setServerEntity($this->getServerService()->setService('delete', $entity, $formDatas));
return $entity;
return $this->getServerService()->setService('delete', $entity, $formDatas);
}
}

View File

@ -4,11 +4,9 @@ namespace App\Services\Equipment;
use App\Entities\Equipment\ServerEntity;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\CPUEntity;
use App\Entities\Part\DISKEntity;
use App\Entities\Part\RAMEntity;
use App\Entities\PaymentEntity;
use App\Helpers\Equipment\ServerPartHelper;
use App\Interfaces\Equipment\ServerInterface;
use App\Models\Equipment\ServerPartModel;
use App\Services\Customer\ServiceService;
use App\Services\Equipment\EquipmentService;
@ -23,7 +21,7 @@ use App\Services\Part\SOFTWAREService;
use App\Services\Part\SWITCHService;
use App\Services\PaymentService;
class ServerPartService extends EquipmentService
class ServerPartService extends EquipmentService implements ServerInterface
{
private ?ServiceService $_serviceService = null;
private ?ServerService $_serverService = null;
@ -218,17 +216,19 @@ class ServerPartService extends EquipmentService
return $formDatas;
}
//서버정보 설정
final public function setServer(string $action, ServerEntity $serverEntity, array $serverFormDatas): void
final public function setServer(string $action, ServerEntity $serverEntity, array $serverFormDatas): ServerEntity
{
switch ($action) {
case 'create':
// 각 변수에 배정
//서버의 Type별 서버파트정보등록(서버파트연결 자동등록용)
$codes = str_split($serverEntity->getCode());
// $server_ year = $codes[0].$codes[1]; // 1,2번째(ex: 21-> 21년)
// $server_quarter = $codes[2]; // 3번째(ex: 1-> 1분기)
// $server_brand = $codes[3]; // 4번째(ex: 6-> HP DL360 Gen6)
$server_type = strtoupper($codes[4]) . "TYPE"; // 5번째(ex: A-> ATYPE Server)
foreach (SERVERPART['SERVER_PARTTYPES'] as $parttype) {
//해당 server_type의 정의된 상수값이 있으면
if (array_key_exists($server_type, SERVERPART[$parttype])) {
foreach (SERVERPART[$parttype][$server_type] as $serverpart) {
$formDatas = [];
$formDatas['serverinfo_uid'] = $serverEntity->getPK();
@ -241,12 +241,13 @@ class ServerPartService extends EquipmentService
$this->create($formDatas);
}
}
}
break;
case 'delete':
//서버정보에 해당하는 ServerPart정보 모두 회수처리 후 서버정보에 기본 ServerPart를 다시 등록해준다.
foreach ($this->getEntities(['serverinfo_uid' => $serverEntity->getPK()]) as $entity) {
//Type에 따른 부품서비스 정의
$this->getPartService($entity->getType())->setServerPart('delete', $entity, $entity, []);
$this->getPartService($entity->getType())->setServerPart('delete', $entity, []);
//서버연결정보 식제
parent::delete($entity);
}
@ -257,6 +258,7 @@ class ServerPartService extends EquipmentService
throw new \Exception(__METHOD__ . "에서 오류발생:{$action}은 정의되지 않은 작업입니다.");
// break;
}
return $serverEntity;
}
//partEntity 정보 추가
protected function getEntity_process(mixed $entity): ServerPartEntity
@ -322,7 +324,7 @@ class ServerPartService extends EquipmentService
$entity = parent::create($formDatas);
//후처리작업
//Type에 따른 부품서비스 정의
$this->getPartService($entity->getType())->setServerPart('create', $entity, $entity, $formDatas);
$this->getPartService($entity->getType())->setServerPart('create', $entity, $formDatas);
//서비스 및 결제정보 처리
switch ($entity->getBilling()) {
case PAYMENT['BILLING']['MONTH']: //월별과금일때만 처리
@ -333,7 +335,7 @@ class ServerPartService extends EquipmentService
$this->getServiceService()->setAmount($this->getServiceService()->getEntity($entity->getServiceInfoUID()));
break;
case PAYMENT['BILLING']['ONETIME']: //일회성일때만 처리
$entity->setPaymentEntity($this->getPaymentService()->setServerPart('create', $entity, $formDatas));
$entity = $this->getPaymentService()->setServerPart('create', $entity, $formDatas);
//결제정보PK정의
$entity = parent::modify($entity, ['payment_uid' => $entity->getPaymentEntity()->getPK()]);
break;
@ -366,7 +368,8 @@ class ServerPartService extends EquipmentService
$entity = parent::modify($entity, $formDatas);
//후처리작업
//Type에 따른 부품서비스 정의
$this->getPartService($entity->getType())->setServerPart('modify', $oldEntity, $entity, $formDatas);
$this->getPartService($entity->getType())->setServerPart('delete', $oldEntity, $formDatas);
$this->getPartService($entity->getType())->setServerPart('create', $entity, $formDatas);
//서비스 및 결제정보 처리
switch ($entity->getBilling()) {
case PAYMENT['BILLING']['MONTH']: //월별과금일때만 처리
@ -376,8 +379,11 @@ class ServerPartService extends EquipmentService
}
break;
case PAYMENT['BILLING']['ONETIME']: //일회성일때만 처리
if ($oldEntity->getPaymentUID() !== null) { //결제정보가 정의되어 있으면
$oldEntity = $this->getPaymentService()->setServerPart('delete', $entity, $formDatas);
}
if ($entity->getPaymentUID() !== null) { //결제정보가 정의되어 있으면
$entity->setPaymentEntity($this->getPaymentService()->setServerPart('modify', $entity, $formDatas));
$entity = $this->getPaymentService()->setServerPart('create', $entity, $formDatas);
}
break;
case PAYMENT['BILLING']['BASE']: //기본처리
@ -393,14 +399,9 @@ class ServerPartService extends EquipmentService
public function delete(mixed $entity): ServerPartEntity
{
//Type에 따른 부품서비스 정의
$this->getPartService($entity->getType())->setServerPart('delete', $entity, $entity, []);
//삭제시는 월비용 서비스만 처리
if ($entity->getBilling() === PAYMENT['BILLING']['MONTH']) {
//서비스가 정의되어 있으면 실행
if ($entity->getServiceInfoUID() !== null) {
$serviceEntity = $this->getServiceService()->getEntity($entity->getServiceInfoUID());
$entity = $this->getServiceService()->setAmount($serviceEntity);
}
$this->getPartService($entity->getType())->setServerPart('delete', $entity, []);
if ($entity->getServiceInfoUID() !== null) { //서비스가 정의되어 있으면
$entity = $this->getServiceService()->setAmount($this->getServiceService()->getEntity($entity->getServiceInfoUID()));
}
return parent::delete($entity);
}

View File

@ -5,15 +5,18 @@ namespace App\Services\Equipment;
use App\Entities\Customer\ServiceEntity;
use App\Entities\Equipment\ServerEntity;
use App\Helpers\Equipment\ServerHelper;
use App\Interfaces\Customer\ServiceInterface;
use App\Models\Equipment\ServerModel;
use App\Services\Customer\ServiceService;
use App\Services\Equipment\EquipmentService;
use App\Services\Equipment\ServerPartService;
use App\Services\Part\IPService;
class ServerService extends EquipmentService
class ServerService extends EquipmentService implements ServiceInterface
{
private ?ServiceService $_serviceService = null;
private ?ServerPartService $_serverPartService = null;
private ?IPService $_ipService = null;
public function __construct()
{
parent::__construct(new ServerModel(), new ServerHelper());
@ -24,6 +27,7 @@ class ServerService extends EquipmentService
return [
"code",
"type",
"ip",
"title",
"price",
"manufactur_at",
@ -43,6 +47,7 @@ class ServerService extends EquipmentService
'clientinfo_uid',
'serviceinfo_uid',
"type",
"ip",
'title',
'price',
'manufactur_at',
@ -71,6 +76,13 @@ class ServerService extends EquipmentService
}
return $this->_serviceService;
}
final public function getIPService(): IPService
{
if (!$this->_ipService) {
$this->_ipService = new IPService();
}
return $this->_ipService;
}
final public function getServerPartService(): ServerPartService
{
if (!$this->_serverPartService) {
@ -122,7 +134,7 @@ class ServerService extends EquipmentService
return $totalCounts;
}
//서비스정보 설정
final public function setService(string $action, ServiceEntity $serviceEntity, array $serviceFormDatas): ServerEntity
public function setService(string $action, ServiceEntity $serviceEntity, array $serviceFormDatas): ServiceEntity
{
switch ($action) {
case 'create':
@ -164,7 +176,7 @@ class ServerService extends EquipmentService
throw new \Exception(__METHOD__ . "에서 오류발생:{$action}은 정의되지 않은 작업입니다.");
// break;
}
return $entity;
return $serviceEntity->setServerEntity($entity);
}
//기본 기능부분
//FieldForm관련용
@ -174,6 +186,9 @@ class ServerService extends EquipmentService
case 'serviceinfo_uid':
$options = $this->getServiceService()->getEntities();
break;
// case 'ip':
// $options = $this->getIPService()->getEntities();
// break;
default:
$options = parent::getFormOption($field, $options);
break;
@ -183,19 +198,29 @@ class ServerService extends EquipmentService
public function create(array $formDatas): ServerEntity
{
$entity = parent::create($formDatas);
//서버파트정보등록
$this->getServerPartService()->setServer('create', $entity, []);
//서버의 Type별 서버파트정보등록(서버파트연결 자동등록용)
$entity = $this->getServerPartService()->setServer('create', $entity, []);
if ($entity->getIP() !== null) { //IP가 정의되어 있으면
$entity = $this->getIPService()->setServer('create', $entity, []);
}
return $entity;
}
//수정
public function modify(mixed $entity, array $formDatas): ServerEntity
{
//수정전 정보
$oldEntity = clone $entity; //반드시 clone 할것
//서버정보 수정
$entity = parent::modify($entity, $formDatas);
//서비스가 연결되어 있고 대체서버가 아니면, 서비스정보수정(청구액수정)
if ($entity->getServiceInfoUID() !== null && $entity->getType() !== "alternative") {
$serviceEntity = $this->getServiceService()->getEntity($entity->getServiceInfoUID());
$this->getServiceService()->setAmount($serviceEntity);
$this->getServiceService()->setAmount($this->getServiceService()->getEntity($entity->getServiceInfoUID()));
}
if ($oldEntity->getIP() !== null) { //기존 서버정보에 IP가 정의되어 있으면
$oldEntity = $this->getIPService()->setServer('delete', $oldEntity, []);
}
if ($entity->getIP() !== null) { //IP가 정의되어 있으면
$entity = $this->getIPService()->setServer('create', $entity, []);
}
return $entity;
}
@ -209,11 +234,10 @@ class ServerService extends EquipmentService
//선처리작업
//서비스가 연결되어 있고 대체서버가 아니면, 서비스정보수정(청구액수정)
if ($entity->getServiceInfoUID() !== null && $entity->getType() !== "alternative") {
$serviceEntity = $this->getServiceService()->getEntity($entity->getServiceInfoUID());
$this->getServiceService()->setAmount($serviceEntity);
$this->getServiceService()->setAmount($this->getServiceService()->getEntity($entity->getServiceInfoUID()));
}
//서버파트정보해지
$this->getServerPartService()->setServer('delete', $entity, []);
$entity = $this->getServerPartService()->setServer('delete', $entity, []);
return parent::delete($entity);
}
//List 검색용

View File

@ -2,14 +2,11 @@
namespace App\Services\Part;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\CPUEntity;
use App\Helpers\Part\CPUHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\Part\CPUModel;
class CPUService extends PartService implements ServerPartInterface
class CPUService extends PartService
{
public function __construct()
{

View File

@ -5,13 +5,12 @@ namespace App\Services\Part;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\CSEntity;
use App\Helpers\Part\CSHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\Part\CSModel;
use App\Services\Customer\ClientService;
use App\Services\Customer\ServiceService;
use App\Services\Equipment\ServerService;
class CSService extends PartService implements ServerPartInterface
class CSService extends PartService
{
private ?ClientService $_clientService = null;
private ?ServiceService $_serviceService = null;
@ -106,7 +105,7 @@ class CSService extends PartService implements ServerPartInterface
}
//서버파트관련 작업
public function setServerPart(string $action, ServerPartEntity $oldServerPartEntity, ServerPartEntity $serverPartEntity, array $serverPartDatas): CSEntity
public function setServerPart(string $action, ServerPartEntity $serverPartEntity, array $serverPartDatas): ServerPartEntity
{
switch ($action) {
case 'create':
@ -126,16 +125,7 @@ class CSService extends PartService implements ServerPartInterface
//CS정보 수정
$entity = parent::modify($entity, $formDatas);
break;
case 'modify':
//수정 전 부품연결정보관련 정보처리 파트정보가 달라졌을경우 (회수 -> 사용 처리)
//기존것 회수 처리
if ($oldServerPartEntity->getPartUID() !== $serverPartEntity->getPartUID()) {
$this->setServerPart('delete', $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
}
//신규것 사용처리
$entity = $this->setServerPart('create', $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
break;
case 'delete': //반드시 oldServerPartEntity 사용해야함
case 'delete': //반드시 serverPartEntity 사용해야함
$formDatas = [];
$formDatas['clientinfo_uid'] = null;
$formDatas['serviceinfo_uid'] = null;
@ -145,14 +135,17 @@ class CSService extends PartService implements ServerPartInterface
throw new \Exception(__METHOD__ . "에서 오류발생: CS상태가 설정되지 않았습니다.");
}
//CS정보가져오기
$entity = $this->getEntity($oldServerPartEntity->getPartUID());
$entity = $this->getEntity($serverPartEntity->getPartUID());
if (!$entity instanceof CSEntity) {
throw new \Exception("{$oldServerPartEntity->getPartUID()}에 해당하는 CS정보를 찾을수없습니다.");
throw new \Exception("{$serverPartEntity->getPartUID()}에 해당하는 CS정보를 찾을수없습니다.");
}
//CS정보 수정
$entity = parent::modify($entity, $formDatas);
break;
default:
$entity = parent::setServerPart($action, $serverPartEntity, $serverPartDatas);
break;
}
return $entity;
return $serverPartEntity;
}
}

View File

@ -3,13 +3,11 @@
namespace App\Services\Part;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\DISKEntity;
use App\Helpers\Part\DISKHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\Part\DISKModel;
class DISKService extends PartService implements ServerPartInterface
class DISKService extends PartService
{
public function __construct()
{
@ -56,26 +54,25 @@ class DISKService extends PartService implements ServerPartInterface
}
//서버파트관련 작업
public function setServerPart(string $action, ServerPartEntity $oldServerPartEntity, ServerPartEntity $serverPartEntity, array $serverPartDatas): mixed
public function setServerPart(string $action, ServerPartEntity $serverPartEntity, array $serverPartDatas): ServerPartEntity
{
switch ($action) {
case 'create':
case 'modify':
$entity = parent::setServerPart($action, $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
break;
case 'delete': //반드시 oldServerPartEntity 사용해야함
case 'delete': //반드시 serverPartEntity 사용해야함
//부품정보가져오기
$entity = $this->getEntity($oldServerPartEntity->getPartUID());
$entity = $this->getEntity($serverPartEntity->getPartUID());
if (!$entity) {
throw new \Exception("{$oldServerPartEntity->getPartUID()}에 해당하는 부품정보를 찾을수없습니다.");
throw new \Exception("{$serverPartEntity->getPartUID()}에 해당하는 부품정보를 찾을수없습니다.");
}
//부품정보에 서버정보 설정 및 서비스,고객정보 정의
if ($entity->getStock() < $oldServerPartEntity->getCnt()) {
throw new \Exception("현재 재고수[{$entity->getStock()}]보다 지정하신 갯수({$oldServerPartEntity->getCnt()})가 더 많습니다.");
if ($entity->getStock() < $serverPartEntity->getCnt()) {
throw new \Exception("현재 재고수[{$entity->getStock()}]보다 지정하신 갯수({$serverPartEntity->getCnt()})가 더 많습니다.");
}
$entity = parent::modify($entity, ['format' => $entity->getFormat() + $oldServerPartEntity->getCnt()]);
$entity = parent::modify($entity, ['format' => $entity->getFormat() + $serverPartEntity->getCnt()]);
break;
default:
$entity = parent::setServerPart($action, $serverPartEntity, $serverPartDatas);
break;
}
return $entity;
return $serverPartEntity;
}
}

View File

@ -2,10 +2,11 @@
namespace App\Services\Part;
use App\Entities\Equipment\ServerEntity;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\IPEntity;
use App\Helpers\Part\IPHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Interfaces\Equipment\ServerInterface;
use App\Models\Part\IPModel;
use App\Services\Customer\ClientService;
use App\Services\Customer\ServiceService;
@ -13,7 +14,7 @@ use App\Services\Equipment\LineService;
use App\Services\Equipment\ServerService;
use App\Services\Part\PartService;
class IPService extends PartService implements ServerPartInterface
class IPService extends PartService implements ServerInterface
{
private ?LineService $_lineService = null;
private ?ClientService $_clientService = null;
@ -119,9 +120,49 @@ class IPService extends PartService implements ServerPartInterface
$this->getModel()->orderBy('INET_ATON(ip)', 'ASC');
parent::setOrderBy($field, $value);
}
//서버파트관련 작업
public function setServer(string $action, ServerEntity $serverEntity, array $serverDatas): ServerEntity
{
switch ($action) {
case 'create':
$formDatas = [];
$formDatas['clientinfo_uid'] = $serverEntity->getClientInfoUID();
$formDatas['serviceinfo_uid'] = $serverEntity->getServiceInfoUID();
$formDatas['serverinfo_uid'] = $serverEntity->getPK();
$formDatas['status'] = STATUS['OCCUPIED'];
if (!array_key_exists('status', $formDatas)) {
throw new \Exception(__METHOD__ . ":{$action}에서 오류발생: IP상태가 설정되지 않았습니다.");
}
//IP정보가져와서 있으면 수정
$entity = $this->getEntity(['ip' => $serverEntity->getIP()]);
if ($entity instanceof IPEntity) {
$entity = parent::modify($entity, $formDatas);
}
break;
case 'delete': //반드시 serverPartEntity 사용해야함
$formDatas = [];
$formDatas['clientinfo_uid'] = null;
$formDatas['serviceinfo_uid'] = null;
$formDatas['serverinfo_uid'] = null;
$formDatas['status'] = STATUS['AVAILABLE'];
if (!array_key_exists('status', $formDatas)) {
throw new \Exception(__METHOD__ . ":{$action}에서 오류발생: IP상태가 설정되지 않았습니다.");
}
//IP정보가져와서 있으면 수정
$entity = $this->getEntity(['ip' => $serverEntity->getIP()]);
if ($entity instanceof IPEntity) {
$entity = parent::modify($entity, $formDatas);
}
break;
default:
throw new \Exception("{$action}은 정의되지 않은 작업입니다.");
// break;
}
return $serverEntity;
}
//서버파트관련 작업
public function setServerPart(string $action, ServerPartEntity $oldServerPartEntity, ServerPartEntity $serverPartEntity, array $serverPartDatas): IPEntity
public function setServerPart(string $action, ServerPartEntity $serverPartEntity, array $serverPartDatas): ServerPartEntity
{
switch ($action) {
case 'create':
@ -131,7 +172,7 @@ class IPService extends PartService implements ServerPartInterface
$formDatas['serverinfo_uid'] = $serverPartEntity->getServerInfoUID();
$formDatas['status'] = STATUS['OCCUPIED'];
if (!array_key_exists('status', $formDatas)) {
throw new \Exception(__METHOD__ . "에서 오류발생: IP상태가 설정되지 않았습니다.");
throw new \Exception(__METHOD__ . ":{$action}에서 오류발생: IP상태가 설정되지 않았습니다.");
}
//IP정보가져오기
$entity = $this->getEntity($serverPartEntity->getPartUID());
@ -141,33 +182,27 @@ class IPService extends PartService implements ServerPartInterface
//IP정보 수정
$entity = parent::modify($entity, $formDatas);
break;
case 'modify':
//수정 전 부품연결정보관련 정보처리 파트정보가 달라졌을경우 (회수 -> 사용 처리)
//기존것 회수 처리
if ($oldServerPartEntity->getPartUID() !== $serverPartEntity->getPartUID()) {
$this->setServerPart('delete', $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
}
//신규것 사용처리
$entity = $this->setServerPart('create', $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
break;
case 'delete': //반드시 oldServerPartEntity 사용해야함
case 'delete': //반드시 serverPartEntity 사용해야함
$formDatas = [];
$formDatas['clientinfo_uid'] = null;
$formDatas['serviceinfo_uid'] = null;
$formDatas['serverinfo_uid'] = null;
$formDatas['status'] = STATUS['AVAILABLE'];
if (!array_key_exists('status', $formDatas)) {
throw new \Exception(__METHOD__ . "에서 오류발생: IP상태가 설정되지 않았습니다.");
throw new \Exception(__METHOD__ . ":{$action}에서 오류발생: IP상태가 설정되지 않았습니다.");
}
//IP정보가져오기
$entity = $this->getEntity($oldServerPartEntity->getPartUID());
$entity = $this->getEntity($serverPartEntity->getPartUID());
if (!$entity instanceof IPEntity) {
throw new \Exception("{$oldServerPartEntity->getPartUID()}에 해당하는 IP정보를 찾을수없습니다.");
throw new \Exception("{$serverPartEntity->getPartUID()}에 해당하는 IP정보를 찾을수없습니다.");
}
//IP정보 수정
$entity = parent::modify($entity, $formDatas);
break;
default:
$entity = parent::setServerPart($action, $serverPartEntity, $serverPartDatas);
break;
}
return $entity;
return $serverPartEntity;
}
}

View File

@ -2,14 +2,11 @@
namespace App\Services\Part;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\OSEntity;
use App\Helpers\Part\OSHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\Part\OSModel;
class OSService extends PartService implements ServerPartInterface
class OSService extends PartService
{
public function __construct()
{

View File

@ -4,10 +4,11 @@ namespace App\Services\Part;
use App\Entities\Equipment\ServerPartEntity;
use App\Helpers\CommonHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\CommonModel;
use App\Services\CommonService;
abstract class PartService extends CommonService
abstract class PartService extends CommonService implements ServerPartInterface
{
protected function __construct(CommonModel $model, CommonHelper $helper)
{
@ -16,7 +17,7 @@ abstract class PartService extends CommonService
}
//서버파트관련 작업
public function setServerPart(string $action, ServerPartEntity $oldServerPartEntity, ServerPartEntity $serverPartEntity, array $serverPartDatas): mixed
public function setServerPart(string $action, ServerPartEntity $serverPartEntity, array $serverPartDatas): ServerPartEntity
{
switch ($action) {
case 'create':
@ -31,28 +32,22 @@ abstract class PartService extends CommonService
}
$entity = parent::modify($entity, ['stock' => $entity->getStock() - $serverPartEntity->getCnt()]);
break;
case 'modify':
//수정 전 부품연결정보관련 정보처리 갯수,파트가 달라졌을경우 (회수 -> 사용 처리)
//기존것 회수 처리
if ($oldServerPartEntity->getCnt() != $serverPartEntity->getCnt() || $oldServerPartEntity->getPartUID() !== $serverPartEntity->getPartUID()) {
$this->setServerPart('delete', $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
}
//신규것 사용처리
$entity = $this->setServerPart('create', $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
break;
case 'delete': //반드시 oldServerPartEntity 사용해야함
case 'delete':
//부품정보가져오기
$entity = $this->getEntity($oldServerPartEntity->getPartUID());
$entity = $this->getEntity($serverPartEntity->getPartUID());
if (!$entity) {
throw new \Exception("{$oldServerPartEntity->getPartUID()}에 해당하는 부품정보를 찾을수없습니다.");
throw new \Exception("{$serverPartEntity->getPartUID()}에 해당하는 부품정보를 찾을수없습니다.");
}
//부품정보에 서버정보 설정 및 서비스,고객정보 정의
if ($entity->getStock() < $oldServerPartEntity->getCnt()) {
throw new \Exception("현재 재고수[{$entity->getStock()}]보다 지정하신 갯수({$oldServerPartEntity->getCnt()})가 더 많습니다.");
if ($entity->getStock() < $serverPartEntity->getCnt()) {
throw new \Exception("현재 재고수[{$entity->getStock()}]보다 지정하신 갯수({$serverPartEntity->getCnt()})가 더 많습니다.");
}
$entity = parent::modify($entity, ['stock' => $entity->getStock() + $oldServerPartEntity->getCnt()]);
$entity = parent::modify($entity, ['stock' => $entity->getStock() + $serverPartEntity->getCnt()]);
break;
default:
throw new \Exception("{$action}은 정의되지 않은 작업입니다.");
// break;
}
return $entity;
return $serverPartEntity;
}
}

View File

@ -2,14 +2,11 @@
namespace App\Services\Part;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\RAMEntity;
use App\Helpers\Part\RAMHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\Part\RAMModel;
class RAMService extends PartService implements ServerPartInterface
class RAMService extends PartService
{
public function __construct()
{

View File

@ -2,14 +2,11 @@
namespace App\Services\Part;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\SOFTWAREEntity;
use App\Helpers\Part\SOFTWAREHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\Part\SOFTWAREModel;
class SOFTWAREService extends PartService implements ServerPartInterface
class SOFTWAREService extends PartService
{
public function __construct()
{

View File

@ -5,13 +5,12 @@ namespace App\Services\Part;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\Part\SWITCHEntity;
use App\Helpers\Part\SWITCHHelper;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\Part\SWITCHModel;
use App\Services\Customer\ServiceService;
use App\Services\Equipment\ServerService;
use App\Services\Part\PartService;
class SWITCHService extends PartService implements ServerPartInterface
class SWITCHService extends PartService
{
private ?ServiceService $_serviceService = null;
private ?ServerService $_serverService = null;
@ -91,7 +90,7 @@ class SWITCHService extends PartService implements ServerPartInterface
}
//서버파트관련 작업
public function setServerPart(string $action, ServerPartEntity $oldServerPartEntity, ServerPartEntity $serverPartEntity, array $serverPartDatas): SWITCHEntity
public function setServerPart(string $action, ServerPartEntity $serverPartEntity, array $serverPartDatas): ServerPartEntity
{
switch ($action) {
case 'create':
@ -111,15 +110,6 @@ class SWITCHService extends PartService implements ServerPartInterface
//SWITCH정보 수정
$entity = parent::modify($entity, $formDatas);
break;
case 'modify':
//수정 전 부품연결정보관련 정보처리 파트정보가 달라졌을경우 (회수 -> 사용 처리)
//기존것 회수 처리
if ($oldServerPartEntity->getPartUID() !== $serverPartEntity->getPartUID()) {
$this->setServerPart('delete', $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
}
//신규것 사용처리
$entity = $this->setServerPart('create', $oldServerPartEntity, $serverPartEntity, $serverPartDatas);
break;
case 'delete': //반드시 oldServerPartEntity 사용해야함
$formDatas = [];
$formDatas['clientinfo_uid'] = null;
@ -130,14 +120,17 @@ class SWITCHService extends PartService implements ServerPartInterface
throw new \Exception(__METHOD__ . "에서 오류발생: SWITCH상태가 설정되지 않았습니다.");
}
//SWITCH정보가져오기
$entity = $this->getEntity($oldServerPartEntity->getPartUID());
$entity = $this->getEntity($serverPartEntity->getPartUID());
if (!$entity instanceof SWITCHEntity) {
throw new \Exception("{$oldServerPartEntity->getPartUID()}에 해당하는 SWITCH정보를 찾을수없습니다.");
throw new \Exception("{$serverPartEntity->getPartUID()}에 해당하는 SWITCH정보를 찾을수없습니다.");
}
//SWITCH정보 수정
$entity = parent::modify($entity, $formDatas);
break;
default:
$entity = parent::setServerPart($action, $serverPartEntity, $serverPartDatas);
break;
}
return $entity;
return $serverPartEntity;
}
}

View File

@ -6,6 +6,8 @@ use App\Entities\Customer\ServiceEntity;
use App\Entities\Equipment\ServerPartEntity;
use App\Entities\PaymentEntity;
use App\Helpers\PaymentHelper;
use App\Interfaces\Customer\ServiceInterface;
use App\Interfaces\Equipment\ServerPartInterface;
use App\Models\PaymentModel;
use App\Services\CommonService;
use App\Services\Customer\ClientService;
@ -13,7 +15,7 @@ use App\Services\Customer\ServiceService;
use App\Services\Equipment\ServerPartService;
use App\Services\UserService;
class PaymentService extends CommonService
class PaymentService extends CommonService implements ServiceInterface, ServerPartInterface
{
private ?UserService $_userService = null;
private ?ClientService $_clientService = null;
@ -117,10 +119,10 @@ class PaymentService extends CommonService
return $unPaids;
}
//서비스정보 설정
final public function setService(string $action, ServiceEntity $serviceEntity, array $serviceFormDatas): PaymentEntity
final public function setService(string $action, ServiceEntity $serviceEntity, array $serviceFormDatas): ServiceEntity
{
switch ($action) {
case 'create':
case 'create': //서비스 가격 추가용
$formDatas = [];
$formDatas['clientinfo_uid'] = $serviceEntity->getClientInfoUID();
$formDatas['serviceinfo_uid'] = $serviceEntity->getPK();
@ -131,7 +133,7 @@ class PaymentService extends CommonService
$formDatas['billing_at'] = $serviceEntity->getBillingAt();
$entity = parent::create($formDatas);
break;
case 'modify':
case 'modify': //서비스 가격 수정용
$entity = $serviceEntity->getPaymentEntity();
if (!$entity instanceof PaymentEntity) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제정보를 찾을수 없습니다.");
@ -150,12 +152,12 @@ class PaymentService extends CommonService
throw new \Exception(__METHOD__ . "에서 오류발생:{$action}은 정의되지 않은 작업입니다.");
// break;
}
return $entity;
return $serviceEntity->setPaymentEntity($entity);
}
final public function setServerPart(string $action, ServerPartEntity $serverPartEntity, array $servicePartFormDatas): PaymentEntity
final public function setServerPart(string $action, ServerPartEntity $serverPartEntity, array $servicePartFormDatas): ServerPartEntity
{
switch ($action) {
case 'create':
case 'create': //일회성 서비스 생성용
$formDatas = [];
$formDatas['clientinfo_uid'] = $serverPartEntity->getClientInfoUID();
$formDatas['serviceinfo_uid'] = $serverPartEntity->getServiceInfoUID();
@ -168,7 +170,7 @@ class PaymentService extends CommonService
$formDatas['billing_at'] = date("Y-m-d");
$entity = parent::create($formDatas);
break;
case 'modify':
case 'modify': //일회성 서비스 수정용
$entity = $serverPartEntity->getPaymentEntity();
if (!$entity instanceof PaymentEntity) {
throw new \Exception(__METHOD__ . "에서 오류발생:결제정보를 찾을수 없습니다.");
@ -187,7 +189,7 @@ class PaymentService extends CommonService
throw new \Exception(__METHOD__ . "에서 오류발생:{$action}은 정의되지 않은 작업입니다.");
// break;
}
return $entity;
return $serverPartEntity->setPaymentEntity($entity);
}
//기본 기능부분
//FieldForm관련용

View File

@ -1,5 +1,6 @@
<?= $this->extend(LAYOUTS[$viewDatas['layout']]['path']) ?>
<?= $this->section('content') ?>
<link href="/css/<?= $viewDatas['layout'] ?>/index.css" media="screen" rel="stylesheet" type="text/css" />
<?php if ($error = session('error')): echo $viewDatas['service']->getHelper()->alert($error) ?><?php endif ?>
<div class="layout_top"><?= $this->include(LAYOUTS[$viewDatas['layout']]['path'] . '/top'); ?></div>
<!-- Layout Middle Start -->
@ -14,17 +15,6 @@
<!-- Layout Right Start -->
<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" />
<style>
table.layout_middle td.layout_right div#container * {
font-size: 12px;
}
.note-box {
height: 150px;
resize: none;
}
</style>
<div class="index_body p-4">
<!-- index_body -->
<div class="row align-items-end rounded border border-gray p-2 mt-3">

View File

@ -1,6 +1,45 @@
<?= $this->extend(LAYOUTS[$viewDatas['layout']]['path']) ?>
<?= $this->section('content') ?>
<?php if ($error = session('error')): echo $viewDatas['service']->getHelper()->alert($error) ?><?php endif ?>
<style>
/* 드롭다운 패널 */
.ac-panel {
--row-h: 34px;
/* 한 줄 높이 */
position: absolute;
z-index: 1100;
left: 0;
right: 0;
margin-top: 4px;
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 6px 20px rgba(0, 0, 0, .08);
max-height: calc(var(--row-h) * 10);
/* ← 10줄 제한 */
overflow-y: auto;
/* 스크롤 생성 */
}
.ac-item {
min-height: var(--row-h);
line-height: var(--row-h);
padding: 0 12px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ac-item:hover,
.ac-item.active {
background: #f1f5f9;
}
</style>
<script src="/js/admin/server/form.js"></script>
<script script script id="ipData" type="application/json">
<?= json_encode($viewDatas['ips'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>
</script>
<div id=" container" class="content">
<div class="form_top"><?= $this->include("templates/{$viewDatas['layout']}/form_content_top"); ?></div>
<?= form_open(current_url(), $viewDatas['forms']['attributes'], $viewDatas['forms']['hiddens']) ?>

View File

@ -42,6 +42,9 @@
<?= $viewDatas['service']->getHelper()->getListLabel('type', lang("{$viewDatas['class_path']}.label.type"), $viewDatas) ?>/
<?= $viewDatas['service']->getHelper()->getListLabel('title', lang("{$viewDatas['class_path']}.label.title"), $viewDatas) ?>
</th>
<th class="index_head_short_column">
<?= $viewDatas['service']->getHelper()->getListLabel('ip', lang("{$viewDatas['class_path']}.label.ip"), $viewDatas) ?>
</th>
<th class="index_head_short_column" style="width:900px;">
<span class="float-start rounded border border-primary" style="cursor:pointer;" onclick="copyServerPartsToClipboard()">ALL 📋</span>부품정보
</th>
@ -74,7 +77,10 @@
<?= $viewDatas['service']->getHelper()->getFieldView('type', $entity->type, $viewDatas) ?><BR>
<?= $viewDatas['service']->getHelper()->getFieldView('title', $entity->getTitle(), $viewDatas) ?>
</td>
<td>
<td nowrap>
<?= $viewDatas['service']->getHelper()->getFieldView('ip', $entity->ip, $viewDatas) ?>
</td>
<td nowrap>
<?= view_cell("\App\Cells\Equipment\ServerPartCell::parttable", [
'serverinfo_uid' => $entity->getPK(),
'types' => SERVERPART['SERVER_PARTTYPES'],
@ -90,7 +96,7 @@
<td nowrap>
<?= $viewDatas['service']->getHelper()->getFieldView('format_at', $entity->format_at, $viewDatas) ?>
</td>
<td><?= $viewDatas['service']->getHelper()->getFieldView('status', $entity->status, $viewDatas) ?></td>
<td nowrap><?= $viewDatas['service']->getHelper()->getFieldView('status', $entity->status, $viewDatas) ?></td>
<td nowrap>
<?= $viewDatas['service']->getHelper()->getListButton('view', '', $viewDatas) ?>&nbsp;
<?= $viewDatas['service']->getHelper()->getListButton('delete', '', $viewDatas) ?>

View File

@ -1,6 +1,45 @@
<?= $this->extend(LAYOUTS[$viewDatas['layout']]['path']) ?>
<?= $this->section('content') ?>
<?php if ($error = session('error')): echo $viewDatas['service']->getHelper()->alert($error) ?><?php endif ?>
<style>
/* 드롭다운 패널 */
.ac-panel {
--row-h: 34px;
/* 한 줄 높이 */
position: absolute;
z-index: 1100;
left: 0;
right: 0;
margin-top: 4px;
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 6px 20px rgba(0, 0, 0, .08);
max-height: calc(var(--row-h) * 10);
/* ← 10줄 제한 */
overflow-y: auto;
/* 스크롤 생성 */
}
.ac-item {
min-height: var(--row-h);
line-height: var(--row-h);
padding: 0 12px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ac-item:hover,
.ac-item.active {
background: #f1f5f9;
}
</style>
<script src="/js/admin/server/form.js"></script>
<script script script id="ipData" type="application/json">
<?= json_encode($viewDatas['ips'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>
</script>
<div id="container" class="content">
<div class="form_top"><?= $this->include("templates/{$viewDatas['layout']}/form_content_top"); ?></div>
<table class="table table-bordered">

View File

@ -13,10 +13,12 @@
<tr class="text-center">
<th style="width: 120px">서비스 상세정보</th>
<th style="width: 120px">사이트/위치/형식</th>
<th style="width: 250px">CPU / 메모리 / 저장장치</th>
<th style="width: 250px">OS / SOFTWARE</th>
<th style="width: 200px">IP주소</th>
<th style="width: 200px">CS</th>
<th style="width: 250px">
<?= $serviceCellDatas['serverPartHelper']->getListButton('CPU', 'CPU', ['serverinfo_uid' => $entity->getServerEntity()->getPK()]) ?>/ <?= $serviceCellDatas['serverPartHelper']->getListButton('RAM', 'RAM', ['serverinfo_uid' => $entity->getServerEntity()->getPK()]) ?> / <?= $serviceCellDatas['serverPartHelper']->getListButton('DISK', 'DISK', ['serverinfo_uid' => $entity->getServerEntity()->getPK()]) ?>
</th>
<th style=" width: 250px"><?= $serviceCellDatas['serverPartHelper']->getListButton('OS', 'OS', ['serverinfo_uid' => $entity->getServerEntity()->getPK()]) ?> / <?= $serviceCellDatas['serverPartHelper']->getListButton('SOFTWARE', 'SOFTWARE', ['serverinfo_uid' => $entity->getServerEntity()->getPK()]) ?></th>
<th style="width: 200px"><?= $serviceCellDatas['serverPartHelper']->getListButton('IP', 'IP주소', ['serverinfo_uid' => $entity->getServerEntity()->getPK()]) ?></th>
<th style="width: 200px"><?= $serviceCellDatas['serverPartHelper']->getListButton('CS', 'CS', ['serverinfo_uid' => $entity->getServerEntity()->getPK()]) ?></th>
<th>서비스 비고</th>
<th style="width: 200px">결제처리</th>
</tr>
@ -38,10 +40,10 @@
<td>
<?= form_open("/admin/customer/service/history/{$entity->getPK()}?return_url=" . urlencode(current_url()), ['method' => "post"]) ?>
<div class="row align-items-center">
<div class="col-10">
<div class="col-9">
<textarea name="history" class="form-control note-box"><?= $entity->getHistory() ?></textarea>
</div>
<div class="col-2">
<div class="col-3">
<?= form_submit('', '저장', array("class" => "btn btn-outline btn-primary")); ?>
</div>
</div>
@ -50,16 +52,16 @@
<td rowspan="4">
<table class="table m-0 p-0">
<tr>
<th class="fw-bold">결제일</th>
<td><?= $entity->getBillingAT() ?></td>
<th class="fw-bold" nowrap>결제일</th>
<td nowrap><?= $entity->getBillingAT() ?></td>
</tr>
<tr>
<th class="fw-bold">결제금</th>
<td class="amount-green"><?= number_format(intval($entity->getAmount())) ?>원</td>
<th class="fw-bold" nowrap>결제금</th>
<td class="amount-green" nowrap><?= number_format(intval($entity->getAmount())) ?>원</td>
</tr>
<tr>
<th class="fw-bold">미납금</th>
<td class="amount-red">
<th class="fw-bold" nowrap>미납금</th>
<td class="amount-red" nowrap>
<?php if (array_key_exists($entity->getPK(), $serviceCellDatas['unPaids'])): ?>
<a href="/admin/customer/payment?clientinfo_uid=<?= $entity->getClientInfoUID() ?>&serviceinfo_uid=<?= $entity->getPK() ?>"><?= $serviceCellDatas['unPaids'][$entity->getPK()]['cnt'] ?>건/<?= number_format($serviceCellDatas['unPaids'][$entity->getPK()]['amount']) ?></a>원
<?php endif ?>

View File

@ -1,34 +1,49 @@
document.addEventListener('DOMContentLoaded', function() {
//class가 calender인 inputbox용,날짜field용
if (document.querySelector(".calender")) {
$(".calender").datepicker({
/**
* 공용 초기화 함수
* @param {HTMLElement} context - 초기화 대상 (없으면 document 전체)
*/
function initFormJS(context) {
const root = context || document;
// Datepicker
if (root.querySelector(".calender")) {
$(root).find(".calender").datepicker({
changeYear: true,
changeMonth: true,
yearRange: "-10:+0",
dateFormat: "yy-mm-dd"
});
}
if (document.querySelector(".tinymce")) {
// HTML 문서가 표준 모드로 렌더링되고 있는지 확인
// TinyMCE
if (root.querySelector(".tinymce")) {
if (document.compatMode !== "CSS1Compat") {
console.error("문서가 표준 모드가 아닙니다.");
return;
}
tinymce.init({
selector: 'textarea',
selector: 'textarea.tinymce',
license_key: 'gpl',
height: 250,
plugins: 'advlist autolink lists link image charmap preview anchor',
toolbar: 'undo redo blocks fontfamily fontsize forecolor backcolor | bold italic underline strikethrough | align numlist bullist | link image | table media | code fullscreen preview',
toolbar: 'undo redo blocks fontfamily fontsize forecolor backcolor | ' +
'bold italic underline strikethrough | align numlist bullist | ' +
'link image | table media | code fullscreen preview',
menubar: 'file edit view insert format tools table help'
});
}
if (document.querySelector(".select-field")) {
//class가 select-field인 SelectBox용
$(".select-field").select2({
theme: "classic",
width: 'style',
dropdownAutoWidth: true
});
// Select2
if (root.querySelector(".select-field")) {
$(root).find(".select-field").select2({
theme: "bootstrap-5",
tags: true, // 없는 값 입력 가능
allowClear: true,
language: {
noResults: function () {
return "직접 입력 후 Enter";
}
}
});
}
}

View File

@ -0,0 +1,173 @@
// 기본 실행 (페이지 로드시 전체 document)
class IpAutoComplete {
/**
* @param {HTMLElement|string} input
* @param {HTMLElement|string} panel
* @param {string[]} ipArray
* @param {object} opts
*/
constructor(input, panel, ipArray = [], opts = {}) {
this.inputEl = typeof input === 'string' ? document.querySelector(input) : input;
this.panelEl = typeof panel === 'string' ? document.querySelector(panel) : panel;
if (!this.inputEl || !this.panelEl) throw new Error('Invalid input/panel element');
this.opts = Object.assign({
validateIPv4: true,
enforceListOnly: false,
previewOnFocus: true, // 포커스 시 상위 N개 미리보기
previewCount: 30, // 미리보기 개수
resultLimit: 1000 // 너무 많을 때 렌더 최대치(성능 안전장치)
}, opts);
this.errorEl = document.getElementById('ipError');
this.ipv4Re = /^(25[0-5]|2[0-4]\d|[01]?\d\d?)(\.(25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/;
this.setArray(ipArray);
// 상태
this.activeIndex = -1;
// 이벤트
this.onInput = this._handleInput.bind(this);
this.onChange = this._handleChange.bind(this);
this.onFocus = this._handleFocus.bind(this);
this.onKeydown = this._handleKeydown.bind(this);
this.onClickOutside = this._handleClickOutside.bind(this);
this.inputEl.addEventListener('input', this.onInput);
this.inputEl.addEventListener('change', this.onChange);
this.inputEl.addEventListener('focus', this.onFocus);
this.inputEl.addEventListener('keydown', this.onKeydown);
document.addEventListener('mousedown', this.onClickOutside);
}
destroy(){
this.inputEl.removeEventListener('input', this.onInput);
this.inputEl.removeEventListener('change', this.onChange);
this.inputEl.removeEventListener('focus', this.onFocus);
this.inputEl.removeEventListener('keydown', this.onKeydown);
document.removeEventListener('mousedown', this.onClickOutside);
this.hidePanel();
}
setArray(arr){ this.ipArray = Array.from(new Set((arr||[]).filter(Boolean))); }
_handleInput(e){
const q = (e.target.value||'').trim();
this._filterAndRender(q);
this._checkIPv4(q);
}
_handleChange(){
const v = (this.inputEl.value||'').trim();
this._checkIPv4(v);
if (this.opts.enforceListOnly && v && !this.ipArray.includes(v)) {
this._setError('❌ 목록에 없는 IP입니다.');
}
}
_handleFocus(){
if (!this.inputEl.value && this.opts.previewOnFocus) {
this._renderPanel(this.ipArray.slice(0, this.opts.resultLimit));
this.showPanel();
}
}
_handleKeydown(e){
if (this.panelEl.hidden) return;
const items = this._items();
if (!items.length) return;
if (e.key === 'ArrowDown'){ e.preventDefault(); this._move(1); }
else if (e.key === 'ArrowUp'){ e.preventDefault(); this._move(-1); }
else if (e.key === 'Enter'){
if (this.activeIndex >= 0){ e.preventDefault(); this._pick(items[this.activeIndex].dataset.value); }
} else if (e.key === 'Escape'){ this.hidePanel(); }
}
_handleClickOutside(e){
if (!this.inputEl.closest('.ac-wrap')?.contains(e.target)) this.hidePanel();
}
_filterAndRender(query){
if (!query){
this.hidePanel();
return;
}
const q = query.toLowerCase();
let results = this.ipArray.filter(ip => ip.toLowerCase().includes(q));
if (this.opts.resultLimit > 0) results = results.slice(0, this.opts.resultLimit);
if (results.length){ this._renderPanel(results); this.showPanel(); }
else { this.hidePanel(); }
}
_renderPanel(list){
this.panelEl.innerHTML = '';
this.activeIndex = -1;
const frag = document.createDocumentFragment();
list.forEach((ip) => {
const item = document.createElement('div');
item.className = 'ac-item';
item.textContent = ip;
item.dataset.value = ip;
item.addEventListener('mousedown', (ev) => { ev.preventDefault(); this._pick(ip); });
frag.appendChild(item);
});
this.panelEl.appendChild(frag);
}
_items(){ return Array.from(this.panelEl.querySelectorAll('.ac-item')); }
_move(delta){
const items = this._items();
if (!items.length) return;
this.activeIndex = (this.activeIndex + delta + items.length) % items.length;
items.forEach(el => el.classList.remove('active'));
const el = items[this.activeIndex];
el.classList.add('active');
el.scrollIntoView({ block: 'nearest' });
}
_pick(value){
this.inputEl.value = value;
this.hidePanel();
this._checkIPv4(value);
}
showPanel(){ this.panelEl.hidden = false; }
hidePanel(){ this.panelEl.hidden = true; this.activeIndex = -1; }
_checkIPv4(val){
if (!this.opts.validateIPv4 || !val){ this._setError(''); return; }
this._setError(this.ipv4Re.test(val) ? '' : '❌ IPv4 형식이 아닙니다.');
}
_setError(text){ if (this.errorEl) this.errorEl.textContent = text || ''; }
}
/* ipData(JSON) 읽기: (이미 페이지에 있다면) */
function parseEmbeddedJson(id){
const el=document.getElementById(id); if(!el) return [];
let txt=el.textContent||'';
txt = txt
.replace(/\/\*[\s\S]*?\*\//g,'')
.replace(/(^|[^:])\/\/.*$/mg,'$1')
.replace(/,\s*([}\]])/g,'$1');
try { const data=JSON.parse(txt); return Array.isArray(data)?data:[]; }
catch(e){ console.error('ipData parse error',e); return []; }
}
/* 초기화 */
document.addEventListener('DOMContentLoaded', () => {
// ipData <script>에 서버가 넣어준 배열 사용 (API 호출 없음)
const ips = parseEmbeddedJson('ipData');
const ac = new IpAutoComplete('#ipInput', '#ipPanel', ips, {
validateIPv4: true,
enforceListOnly: false,
previewOnFocus: true,
previewCount: 30,
resultLimit: 2000 // 너무 많으면 1000~2000 정도로 제한 추천
});
});