nim_style

pull/3/head
nimtaurel 2025-03-03 18:46:45 +05:00
parent 4d5c05342e
commit a2f42b5027
24 changed files with 68326 additions and 473 deletions

26
app/components/Grid.php Normal file
View File

@ -0,0 +1,26 @@
<?php
/*
* Copyright (c) 2023.
*
* A.Сапаргалиев
* ТОО "Дизайн лаборатория А7"
* Астана
*/
namespace App\components;
use A7kz\Platform\Modules\Platform\Core\Services\Base\Component;
class Grid extends Component
{
public function __construct(array $params = [])
{
parent::__construct($params, '');
$this->template = "components.grid";
}
public function render(){
return view($this->template, $this->params)->render();
}
}

View File

@ -0,0 +1,91 @@
<?php
/*
* Copyright (c) 2023.
*
* A.Сапаргалиев
* ТОО "Дизайн лаборатория А7"
* Астана
*/
namespace App\components;
use A7kz\Platform\Modules\Platform\Acl\Facades\Acl;
use A7kz\Platform\Modules\Platform\Core\Facades\Logic;
use A7kz\Platform\Modules\Platform\Core\Services\Base\Component;
class HeadActions extends Component
{
const TYPE_LOGIC = 'logic';
const TYPE_ACTION = 'action';
const ACCESS_HANDLER_KEY = 'access_handler';
public array $actions = [];
public function __construct(array $params = [])
{
parent::__construct($params, $module = '');
$this->template = "components.head_actions";
if ($this->app->action['head'] ?? false) {
$this->prepareHeadActions();
}
$this->setParam('actions', $this->actions);
}
public function render(){
return view($this->template, $this->params)->render();
}
protected function prepareHeadActions(): void
{
$this->actions = $this->app->action['head'];
foreach ($this->actions as $action => $property) {
$this->actions[$action]->show = false;
if((!$this->app->isReadonly() || !isset($property->readonly) || !$property->readonly) && $this->app->isReadonly()) {
continue;
}
switch ($property?->type) {
case self::TYPE_LOGIC:
$this->handleLogic($action, $property);
break;
case self::TYPE_ACTION:
default:
$this->handleAction($action, $property);
break;
}
}
}
protected function handleLogic(string $action, $property): void
{
if (isset($property->{self::ACCESS_HANDLER_KEY})) {
$show = $this->handleActionAccess($action, $property->{self::ACCESS_HANDLER_KEY});
} else {
$show = Acl::isInRoleArray($property->access ?? []);
}
$this->actions[$action]->url = $this->app->getPath() . '?logic=' . $action;
$this->actions[$action]->show = $show;
}
public function handleAction(string $action, $property): void
{
if (isset($property->{self::ACCESS_HANDLER_KEY})) {
$show = $this->handleActionAccess($action, $property->{self::ACCESS_HANDLER_KEY});
} else {
$show = true;
}
$this->actions[$action]->url = $this->app->getPath() . '/' . $action;
$this->actions[$action]->show = $show;
}
protected function handleActionAccess(string $action, string $handler): bool
{
$processorResult = Logic::handle($handler, $this->app, ['action' => $action]);
return $processorResult->getStatus();
}
}

592
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -5,26 +5,43 @@
<div class="log-reg-content">
<div class="d-flex justify-content-between">
<div class="item-nav-lang">
<div class="dropdown">
<div class="item-nav lang">
<div class="dropdown">
<span class="dropdown-trigger" data-bs-toggle="dropdown">
<i class="bi bi-translate"></i>
{{__(app()->getLocale())}}
@if(app()->getLocale() == 'ru')
RU <img src="{{asset('img/ru.png')}}" alt="ru">
@elseif(app()->getLocale() == 'kz')
KZ <img src="{{asset('img/kz.png')}}" alt="kz">
@elseif(app()->getLocale() == 'en')
EN <img src="{{asset('img/en.png')}}" alt="en">
@endif
</span>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
@if(app()->getLocale() != \A7kz\Platform\Enums\Languages::Ru)
<li><a class="dropdown-item"
href="{{ \A7kz\Platform\Modules\Platform\Translate\Helpers\TranslateHelper::changeUrlLanguage(\A7kz\Platform\Enums\Languages::Ru) }}"><span>@lang('ru')</span></a>
href="{{ \A7kz\Platform\Modules\Platform\Translate\Helpers\TranslateHelper::changeUrlLanguage(\A7kz\Platform\Enums\Languages::Ru) }}">RU
<img src="{{asset('img/ru.png')}}" alt="ru"></a>
</li>
@endif
@if(app()->getLocale() != \A7kz\Platform\Enums\Languages::Kz)
<li><a class="dropdown-item"
href="{{ \A7kz\Platform\Modules\Platform\Translate\Helpers\TranslateHelper::changeUrlLanguage(\A7kz\Platform\Enums\Languages::Kz) }}"><span>@lang('kz')</span></a>
href="{{ \A7kz\Platform\Modules\Platform\Translate\Helpers\TranslateHelper::changeUrlLanguage(\A7kz\Platform\Enums\Languages::Kz) }}">KZ
<img src="{{asset('img/kz.png')}}" alt="kz"></a>
</li>
@endif
@if(app()->getLocale() != \A7kz\Platform\Enums\Languages::En)
<li><a class="dropdown-item"
href="{{ \A7kz\Platform\Modules\Platform\Translate\Helpers\TranslateHelper::changeUrlLanguage(\A7kz\Platform\Enums\Languages::En) }}">EN
<img src="{{asset('img/en.png')}}" alt="en"></a>
</li>
@endif
</ul>
</div>
</div>
<img src="{{asset('img/logo.svg')}}" alt="logo" class="logo-log">
</div>
</div>
<img src="{{asset('img/logo.png')}}" alt="logo" class="logo-log">
</div>
<form method="POST" action="{{ lurl('login') }}">
@csrf
@ -51,37 +68,24 @@
<div class="invalid-feedback form-text text-danger" role="alert">{{ $error['password'] }}</div>
@endif
</div>
<div class="mb-3 form-check">
<input class="form-check-input" type="checkbox" name="remember"
id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label" for="remember"> {{ __('Remember Me') }}</label>
<div class="reset-container">
@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ lurl('/password/reset') }}">
{{ __('Забыли пароль?') }}
</a>
@endif
</div>
<div class="d-flex align-items-center justify-content-center">
<div class="d-flex align-items-center justify-content-between">
<button type="submit" class="btn btn-success">
{{ __('Войти') }}
</button>
@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ lurl('/password/reset') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
</div>
</form>
<div class="contact-us-wrapper d-flex flex-column justify-content-center align-items-center">
<div class="phone-cont d-flex flex-column align-items-center mb-1">
<p>7 776 350 41 41<span>({{ __('звонок бесплатный') }})</span></p>
<a class="header-phone" href="tel:87763504141"><i class="bi bi-telephone-fill"></i> +7 776 350 41 41</a>
</div>
<div class="line"></div>
<div class="d-flex flex-row justify-content-between" style="column-gap: 10px">
<div class="d-flex flex-column align-items-start justify-content-start">
<p><i class="bi bi-envelope-fill"></i> support@esep.kz</p>
</div>
<div class="d-flex flex-column align-items-end justify-content-center">
<p><i class="bi bi-clock-fill"></i> {{ __('Часы работы') }}</p>
<p>{{ __('ПН—ПТ') }} 9:00—18:00</p>
</div>
</div>
</div>
</div>
</div>

View File

@ -3,6 +3,7 @@
"name": "pipicar.auto",
"type": "crud",
"title": "Автомобили",
"withHeader": false,
"data": {
"table": "pipi_auto",
"pk": "id",
@ -154,7 +155,7 @@
"ui": {
"grid": {
"title": "Автомобили",
"template": "app.base.crud.grid",
"component": "App.components.grid",
"cols": [
{
"name": "code",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

BIN
public/img/main-bg-full.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -111,6 +111,7 @@
"/img/logo-white.png": "/img/logo-white.png",
"/img/logo.png": "/img/logo.png",
"/img/logo.svg": "/img/logo.svg",
"/img/main-bg-full.jpg": "/img/main-bg-full.jpg",
"/img/ru.png": "/img/ru.png",
"/img/sidebar-bg.jpg": "/img/sidebar-bg.jpg",
"/lib/edit_area/autocompletion.js": "/lib/edit_area/autocompletion.js",

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

View File

@ -17,6 +17,10 @@
.left-content, .right-content{
display: flex;
align-items: center;
.btn {
font-size: 0.8rem;
padding: 0.6rem 0.8rem;
}
}
.right-content{
.btn{

View File

@ -6,20 +6,135 @@
height: 100%;
z-index: 99999;
display: flex;
justify-content: flex-end;
background-image: url('../../img/bg-log-reg.png');
justify-content: flex-start;
background-image: url('../../img/main-bg-full.jpg');
background-position: center;
background-size: cover;
padding: 2rem;
.log-reg-content{
width: 100%;
max-width: 500px;
height: 100vh;
height: calc(100vh - 4rem);
background-color: #fff;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 50px;
overflow: auto;
border-radius: 25px;
-webkit-box-shadow: 1px -2px 17px -5px rgba(179, 179, 179, 0.76);
-moz-box-shadow: 1px -2px 17px -5px rgba(179, 179, 179, 0.76);
box-shadow: 1px -2px 17px -5px rgba(179, 179, 179, 0.76);
.reset-container {
margin: 0 0 15px;
padding: 0;
display: flex;
justify-content: flex-end;
align-items: center;
a {
text-decoration: none;
color: $gray-color;
padding: 0;
transition: all 0.3s ease-in-out;
font-size: 0.875rem;
text-align: end;
}
a:hover {
color: $secondary-color;
}
}
.btn {
width: 100%;
}
.logo-log {
width: 170px;
height: 40.5px;
}
.header-phone {
font-size: 16px;
color: #01b0e8;
display: inline-block;
font-weight: 700;
margin-left: 10px;
text-decoration: none;
}
.dropdown-trigger {
text-transform: uppercase;
text-decoration: none;
height: 49px;
padding: 0 20px;
display: flex;
align-items: center;
cursor: pointer;
justify-content: center;
transition: 0.15s all ease;
font-size: 1rem;
&:hover {
color: $primary-color;
}
img {
width: 20px;
height: 20px;
margin: 0 8px;
}
}
.dropdown-trigger::after {
display: inline-block;
margin-left: .255em;
vertical-align: .255em;
content: "";
border-top: .3em solid;
border-right: .3em solid transparent;
border-bottom: 0;
border-left: .3em solid transparent;
}
.dropdown-menu {
img {
width: 20px;
height: 20px;
margin: 0 8px;
}
.dropdown-menu {
position: absolute;
z-index: 1000;
display: none;
min-width: 10rem;
padding: .5rem 0;
margin: 0;
font-size: 1rem;
color: #212529;
text-align: left;
list-style: none;
background-color: #fff;
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, .15);
border-radius: .25rem;
}
.dropdown-item {
padding: 5px 10px 5px 17px;
display: flex;
align-items: center;
color: $gray-color;
font-weight: 700;
transition: 0.15s all ease;
&:hover {
background-color: #01b0e836;
color: $text-color;
}
}
}
}
form{

View File

@ -66,6 +66,7 @@
&:hover {
color: $primary-color;
}
}
.dropdown-trigger::after {
display: inline-block;

View File

@ -5,7 +5,8 @@
z-index: 1002;
background:url("../../img/sidebar-bg.jpg") no-repeat;
height: 100%;
transition: 0.15s all ease;
transition: 0.15s allease;
background-size: cover;
ul {
list-style: none;
padding-inline-start: 0;
@ -40,11 +41,14 @@
min-height: 40px;
font-size: 1rem;
cursor: pointer;
transition: 0.15s all ease;
transition: 0.3s all ease;
&:hover {
color: white;
background-color: $text-color!important;
background-color: $border-color!important;
}
&:focus-visible {
border: none;
}
.menu-icon {
@ -78,8 +82,8 @@
.has-more {
transform: rotate(0);
background-color: $primary-bg-color;
color: $primary-color;
background-color: $border-color;
color: $text-color;
}
}
}

View File

@ -83,6 +83,8 @@
nav {
padding: 10px;
display: flex;
justify-content: center;
ul {
margin: 0;

View File

@ -9,6 +9,7 @@ $primary-hover: #0193c7;
$success-color: #07b385;
$danger-color: #dc3545;
$secondary-color: #424B4B;
$light-color: #eeeeee;
$primary-bg-color: rgba(11, 107, 251, 0.2);
$success-bg-color: rgba(7, 179, 133, 0.2);

View File

@ -0,0 +1,247 @@
<?php
/*
* Copyright (c) 2022.
* Aidyn Sapargaliyev
* Nur-Sultan (Astana), Kazakhstan
* ТОО Дизайн лаборатория А7
* https://a7.kz
*/
/**
* @var \A7kz\Platform\Modules\Platform\Core\Services\Application\CrudApplication $app
*/
use A7kz\Platform\Modules\Platform\Core\Services\Data\DataTypes;
use Illuminate\Support\Carbon;
$show = false;
$actions = $app->getActions();
if (isset($actions->show) && \A7kz\Platform\Modules\Platform\Acl\Facades\Acl::isCanRun($app->getName(), 'show')) {
$show = true;
}
?>
<style>
.rowStyleStatic td {}
</style>
<x-component name="Js.Before" :params="['app'=>$app]" :module="$module"/>
{!! $app->show_message() !!}
<div class="global-actions">
<div class="left-content">
@if(!is_null($app->filter))
<span class="btn btn-primary filter-trigger">{{__("Фильтр")}}</span>
@endif
<h5 class="global-title px-4">{{__($app->getUiTitle("grid"))}}</h5>
</div>
<div class="right-content">
<x-component name="App.components.HeadActions" :params="['app'=>$app]" :module="$module"/>
</div>
</div>
<div>
{!! $app->filter() !!}
</div>
<div class="table-container @if($app->data->isSubCrud() ?? false)subcrud-table @endif">
<table class="table table-hover">
<thead>
<tr>
@foreach($app->cols as $col)
<th>
<a href="@if($col->name == $app->data->getSortField())
@if($app->data->getSortOrder() == 'asc')
{{$app->getPath().'?sort=desc-'.$col->name.'&page='.$app->data->getPage()}}
@else
{{$app->getPath().'?sort=asc-'.$col->name.'&page='.$app->data->getPage()}}
@endif
@else
{{$app->getPath().'?sort=asc-'.$col->name.'&page='.$app->data->getPage()}}
@endif">
{{__($col->caption)}}
@if($col->name == $app->data->getSortField())
@if($app->data->getSortOrder() == 'asc')
<i class="bi bi-arrow-up"></i>
@else
<i class="bi bi-arrow-down"></i>
@endif
@endif
</a>
</th>
@endforeach
@if(!$app->isReadonly())
@if(isset($app->action['row']))
<th></th>
@endif
@endif
</tr>
</thead>
<tbody>
@foreach($app->rows as $row)
@php
$href = !isset($targetLink) ?
$app->getPath()."/show?pk=".$row->{$app->data->getPk()} :
lurl("app/".$targetLink->application."/show?pk=".$row->{$app->data->getPk()});
@endphp
<tr @if(\A7kz\Platform\Modules\Platform\Acl\Facades\Acl::isCanRun($app->getName(), 'show')) style="cursor: pointer;"
class="grid-table-row" data-href="{{$href}}" @endif>
@foreach($app->cols as $col)
<td @if(isset($row->style)) style="{{$row->style}}" @endif>
@if($app->data->fields[$col->name]->getType() == DataTypes::Boolean)
@if($row->{$col->name})
<i class="yes bi bi-check-circle-fill"></i>
@elseif(isset($app->data->fields[$col->name]->nullable) && is_null($row->{$col->name}))
<i class="wait bi bi-hourglass-split"></i>
@else
<i class="no bi bi-x-circle-fill"></i>
@endif
@elseif($app->data->fields[$col->name]->getType() == DataTypes::Date)
{!! $row->{$col->name}?\Illuminate\Support\Carbon::parse($row->{$col->name})->format('d.m.Y'):'' !!}
@elseif($app->data->fields[$col->name]->getType() == DataTypes::DateTime)
{!! $row->{$col->name}?\Illuminate\Support\Carbon::parse($row->{$col->name})->format('d.m.Y H:i:s'):'' !!}
@elseif($app->data->fields[$col->name]->getType() == DataTypes::Month)
{!! $row->{$col->name}?\A7kz\Platform\Models\Month::get($row->{$col->name}):'' !!}
@elseif($app->data->fields[$col->name]->getType() == DataTypes::Wysiwyg)
{!! $row->{$col->name} !!}
@elseif($app->data->fields[$col->name]->getType() == DataTypes::Foreign)
@php
$str = '';
if (isset($row->{$col->name . "_list_class_val"})) {
$str = $row->{$col->name . "_list_class_val"};
} elseif (!empty($row->{$col->name})) {
$templateKey = isset($app->data->fields[$col->name]->grid_template)
? 'grid_template'
: (isset($app->data->fields[$col->name]->template) ? 'template' : null);
if ($templateKey) {
$str = $app->data->fields[$col->name]->{$templateKey};
$str = str_replace('{lk}', app()->getLocale(), $str);
foreach ($app->data->fields[$col->name]->display as $item) {
$str = str_replace("{" . $item . "}", $row->{$col->name . "_" . $item}, $str);
}
$str = preg_replace_callback('/\{(.*?)\}/', function ($matches) use ($row) {
return $row->{$matches[1]} ?? '';
}, $str);
} else {
$str = '';
foreach ($app->data->fields[$col->name]->display as $item) {
$str .= $row->{$col->name . "_" . $item} . " ";
}
}
}
@endphp
{{ $str }}
@elseif($app->data->fields[$col->name]->getType() == DataTypes::Json)
{{var_dump(json_decode($row->{$col->name},true))}}
@elseif($app->data->fields[$col->name]->getType() == DataTypes::Combined)
{{ data_get(json_decode($row->{$app->data->fields[$col->name]->getDbFieldName()},true), $app->data->fields[$col->name]->getFieldName()) }}
@elseif($app->data->fields[$col->name]->getType() == DataTypes::ExpirationStatus)
@php
$currentDate = Carbon::now();
$expirationDate = $row->{$col->name} != '' ? Carbon::parse($row->{$col->name}) : null;
$creationDate = $app->data->fields[$col->name]->started_at_field
? Carbon::parse($row->{$app->data->fields[$col->name]->started_at_field} ?? null)
: null;
$isActive = match (true) {
is_null($expirationDate) && is_null($creationDate) => true,
is_null($creationDate) => $currentDate->lt($expirationDate),
is_null($expirationDate) => $currentDate->gte($creationDate),
default => ($currentDate->lt($expirationDate) and $currentDate->gte($creationDate)),
};
$status = $isActive ? 'active' : 'inactive';
$text = $app->data->fields[$col->name]->text[$status] ??
($isActive ? __('Активно') : __('Неактивно'));
$icon = $isActive
? '<i class="yes bi bi-check-circle-fill"></i>'
: '<i class="no bi bi-x-circle-fill"></i>';
echo "$icon <span class='status-label'>$text</span>";
@endphp
@else
@php
$truncateLength = $col->truncate_length ?? mb_strlen($row->{ $col->name });
if (mb_strlen($row->{ $col->name }) > $truncateLength) {
$row->{ $col->name } = mb_substr($row->{ $col->name }, 0, $truncateLength) . '...';
}
@endphp
@if($col->link ?? false)
<a href="{{ lurl(sprintf($col->link, ...array_map(fn($repl) => $row->{$repl}, $col->replace))) }}">
{{ $row->{ $col->name } }}
</a>
@else
{{ $row->{ $col->name } }}
@endif
@endif
</td>
@endforeach
@if(!$app->isReadonly())
@if(isset($app->action['row']))
<td class="td-actions"
@if(isset($app->action['row'])) style="width: {{count($app->action['row'])*40}}px" @endif>
@foreach($app->action['row'] as $action=>$actionProperties)
@if(!is_null($actionProperties))
<x-component name="Buttons.GridActionButton"
:params="[
'app' => $app,
'row' => $row,
'action' => $action,
'actionProps' => $actionProperties,
'label' => $actionProperties->label,
'btn' => $actionProperties->btn ?? null,
'icon' => $actionProperties->icon ?? null
]"
/>
@endif
@endforeach
</td>
@endif
@endif
</tr>
@endforeach
</tbody>
<tfoot>
@if($app->rows->total() > $app->data->limit)
<tr>
<td class="td-pagination" colspan="{{count($app->cols)+1}}">
{{$app->rows->links()}}
</td>
</tr>
@endif
</tfoot>
</table>
</div>
<x-component name="Js.After" :params="['app'=>$app]" :module="$module"/>
<x-component name="Additional.ImportAction" :params="['app'=>$app]" :module="$module"/>
@if(isset($app->getConfig()?->ui?->grid?->inject_component))
@foreach($app->getCOnfig()->ui->grid->inject_component as $inject_component)
<x-component :name="$inject_component" :module="$module" :params="['app'=>$app]"/>
@endforeach
@endif
@if(isset($app->getConfig()?->ui?->grid?->inject_component))
@if(!empty($app->getConfig()->ui->grid->on_render_emit_functions))
<x-component name="Js.OnRenderEmitFunctions" :module="$module"
:params="['app' => $app, 'emitFunctions' => $app->getConfig()->ui->grid->on_render_emit_functions]"
/>
@endif
@endif
<script>
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll(".grid-table-row").forEach((el) => {
el.addEventListener("click", (event) => {
if (event.target.classList.contains("btn") || event.target.parentNode.classList.contains("btn")) {
return;
}
else {
window.open(el.dataset.href, '_self');
}
});
});
});
</script>

View File

@ -0,0 +1,27 @@
<?php
$actions ??= [];
?>
@foreach($actions as $action=>$property)
@php
$type = $property?->type ?? '';
@endphp
@switch($type)
@case("custom")
<x-component name="{{ $property->component }}" :params="['app' => $app]"/>
@break
@default
@if($property->show ?? false)
<x-component name="Buttons.HeadActionButton" :params="[
'app' => $app,
'actionProps' => $property ?? null,
'label' => $property->label,
'btn' => $property->btn ?? null,
]"/>
@endif
@break
@endswitch
@endforeach