fix! исправлены обнаруженные баги в админке
This commit is contained in:
parent
ce78fad613
commit
55bf61a359
@ -44,6 +44,16 @@ public function edit(Company $company)
|
||||
|
||||
public function update(Request $request, Company $company)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required',
|
||||
'email' => "required|unique:companies,email,{$company->id}",
|
||||
'phone' => "required|unique:companies,phone,{$company->id}",
|
||||
],
|
||||
[
|
||||
'email.unique' => 'Указанная электронная почта уже существует',
|
||||
'phone.unique' => 'Указанный номер телефона уже существует'
|
||||
]
|
||||
);
|
||||
$company->update($request->only('name', 'email', 'phone'));
|
||||
if ($request->token) {
|
||||
$company->bitrixy->token = $request->token;
|
||||
|
||||
@ -28,6 +28,7 @@ public function index(Request $request)
|
||||
$complexes = $complexes->get();
|
||||
return view('admin::complexes.index', [
|
||||
'complexes' => $complexes,
|
||||
'cities' => City::orderBy('name')->get(),
|
||||
'filter' => $request->filter
|
||||
]);
|
||||
}
|
||||
@ -48,7 +49,16 @@ public function update(Request $request, Complex $complex)
|
||||
|
||||
public function create(Request $request)
|
||||
{
|
||||
$city = Complex::create($request->only('name'));
|
||||
$validated = $request->validate([
|
||||
'name' => "required",
|
||||
'city_id' => "required",
|
||||
],
|
||||
[
|
||||
'name.required' => 'Необходимо указать название жилого комплекса',
|
||||
'city_id.required' => 'Необходимо указать город'
|
||||
]
|
||||
);
|
||||
$city = Complex::create($request->only('name', 'city_id'));
|
||||
return to_route('admin.complexes');
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,8 @@
|
||||
@csrf
|
||||
<div class="mb-3">
|
||||
<label for="nameFormControl" class="form-label">Название</label>
|
||||
<input type="text" class="form-control" id="nameFormControl" name="name" value="{{ $company->name }}">
|
||||
<input type="text" class="form-control" id="nameFormControl" name="name"
|
||||
value="{{ old('name', $company->name) }}">
|
||||
@error('name')
|
||||
<div class="text-danger">{{ $message }}</div>
|
||||
@enderror
|
||||
@ -18,17 +19,17 @@
|
||||
<div class="mb-3">
|
||||
<label for="emailFormControl" class="form-label">Email</label>
|
||||
<input type="text" class="form-control" id="emailFormControl" name="email"
|
||||
value="{{ $company->email }}">
|
||||
value="{{ old('email', $company->email) }}">
|
||||
@error('email')
|
||||
<div class="text-danger">{{ $message }}</div>
|
||||
<div class="text-danger d-none">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="phoneFormControl" class="form-label">Телефон</label>
|
||||
<input type="text" class="form-control" id="phoneFormControl" name="phone"
|
||||
value="{{ $company->phone }}">
|
||||
<input type="tel" class="form-control" id="phoneFormControl" name="phone"
|
||||
value="{{ old('phone', $company->phone) }}">
|
||||
@error('phone')
|
||||
<div class="text-danger">{{ $message }}</div>
|
||||
<div class="text-danger d-none">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
<div class="text-danger">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="cityFormControl" class="form-label">Город</label>
|
||||
<select class="form-select" name="city_id" id="cityFormControl">
|
||||
|
||||
@ -47,8 +47,8 @@
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="dropdown" style="">
|
||||
<button class="btn btn-light" type="button" id="dropdownMenuButton"
|
||||
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<button class="btn btn-light" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
@if ($complex->trashed())
|
||||
<i class="bi bi-recycle"></i>
|
||||
@else
|
||||
@ -65,8 +65,7 @@
|
||||
@else
|
||||
<a class="dropdown-item"
|
||||
href="{{ route('admin.complexes.edit', ['complex' => $complex]) }}">Редактировать</a>
|
||||
<form method="post"
|
||||
action="{{ route('admin.complexes.delete', ['complex' => $complex]) }}">
|
||||
<form method="post" action="{{ route('admin.complexes.delete', ['complex' => $complex]) }}">
|
||||
@csrf
|
||||
<button class="dropdown-item" type="submit">Удалить</button>
|
||||
</form>
|
||||
@ -83,21 +82,28 @@
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="createCityModal" tabindex="-1" aria-labelledby="createCityModalLabel" aria-hidden="true">
|
||||
|
||||
<form class="modal-dialog modal-dialog-centered" action="{{ route('admin.cities.create') }}" method="post">
|
||||
<form class="modal-dialog modal-dialog-centered" action="{{ route('admin.complexes.create') }}" method="post">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="createCityModalLabel">Новый город</h1>
|
||||
<h1 class="modal-title fs-5" id="createCityModalLabel">Новый жилой комплекс</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="my-3">
|
||||
@csrf
|
||||
<label for="cityNameInput" class="form-label">Введите название нового города</label>
|
||||
<input class="form-control" type="text" id="cityNameInput" name="name" required>
|
||||
@error('text')
|
||||
<div class="text-danger">{{ $message }}</div>
|
||||
@enderror
|
||||
<div class="mb-3">
|
||||
<label for="nameFormControl" class="form-label">Название</label>
|
||||
<input type="text" class="form-control" id="nameFormControl" name="name"
|
||||
value="{{ old('name') }}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="cityFormControl" class="form-label">Город</label>
|
||||
<select class="form-select" name="city_id" id="cityFormControl">
|
||||
@foreach ($cities as $city)
|
||||
<option value="{{ $city->id }}" @if (old('city_id') == $city->id) selected @endif>
|
||||
{{ $city->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="phoneFormControl" class="form-label">телефон</label>
|
||||
<input type="text" class="form-control" id="phoneFormControl" name="phone"
|
||||
<input type="tel" class="form-control" id="phoneFormControl" name="phone"
|
||||
value="{{ $user->phone }}">
|
||||
@error('phone')
|
||||
<div class="text-danger">{{ $message }}</div>
|
||||
|
||||
@ -100,7 +100,7 @@
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<label for="nameInput" class="form-label">Телефон</label>
|
||||
<input class="form-control" type="text" id="phoneInput" name="phone" required>
|
||||
<input class="form-control" type="tel" id="phoneInput" name="phone" required>
|
||||
@error('phone')
|
||||
<div class="text-danger">{{ $message }}</div>
|
||||
@enderror
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="agentPhone" class="form-label">Телефон</label>
|
||||
<input type="text" class="form-control" id="agentPhone" name="phone">
|
||||
<input type="tel" class="form-control" id="agentPhone" name="phone">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check form-switch">
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="adminPhone" class="form-label">Телефон</label>
|
||||
<input type="text" class="form-control" id="adminPhone" name="phone">
|
||||
<input type="tel" class="form-control" id="adminPhone" name="phone">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check form-switch">
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
if($json['total_commits'] > 0)
|
||||
{
|
||||
$result = shell_exec("cd /var/www/lk && git reset --hard HEAD && git pull && php artisan migrate");
|
||||
$result = shell_exec("cd /var/www/lk && git reset --hard HEAD && git pull && php artisan migrate && npm run build");
|
||||
echo "<p>$result</p>";
|
||||
}
|
||||
|
||||
|
||||
81
resources/js/phone-format.js
Normal file
81
resources/js/phone-format.js
Normal file
@ -0,0 +1,81 @@
|
||||
function initPhoneMask(selector = 'input[type="tel"]') {
|
||||
const format = (digits) => {
|
||||
// Пример маски: +7 (999) 123-45-67
|
||||
const d = digits.slice(0, 11); // ограничим 11 цифрами (под РФ)
|
||||
if (!d.length) return '';
|
||||
|
||||
// если начали вводить с 8/7 — приведём к +7
|
||||
let rest = d;
|
||||
let prefix = '+7';
|
||||
if (d[0] === '8') rest = '7' + d.slice(1);
|
||||
if (rest[0] === '7') rest = rest.slice(1);
|
||||
else {
|
||||
// если первая цифра не 7, считаем что пользователь вводит локально, но всё равно показываем +7
|
||||
// (при желании можно тут менять логику)
|
||||
}
|
||||
|
||||
const a = rest.slice(0, 3);
|
||||
const b = rest.slice(3, 6);
|
||||
const c = rest.slice(6, 8);
|
||||
const e = rest.slice(8, 10);
|
||||
|
||||
let out = prefix;
|
||||
if (a) out += ` (${a}`;
|
||||
if (a && a.length === 3) out += `)`;
|
||||
if (b) out += ` ${b}`;
|
||||
if (c) out += `-${c}`;
|
||||
if (e) out += `-${e}`;
|
||||
return out;
|
||||
};
|
||||
|
||||
const applyToInput = (input) => {
|
||||
if (input.dataset.phoneMasked === '1') return;
|
||||
input.dataset.phoneMasked = '1';
|
||||
|
||||
// Подсказки браузеру: tel-поле и события input/change поддерживаются стандартно [web:2]
|
||||
input.autocomplete = input.autocomplete || 'tel';
|
||||
input.inputMode = input.inputMode || 'tel'; // подсказка клавиатуры, особенно на мобилках [web:12]
|
||||
|
||||
const handler = () => {
|
||||
const digits = input.value.replace(/\D/g, '');
|
||||
input.value = format(digits);
|
||||
};
|
||||
|
||||
input.addEventListener('input', handler); // события input/change для tel описаны в MDN [web:2]
|
||||
input.addEventListener('change', handler); // [web:2]
|
||||
};
|
||||
|
||||
// 1) применяем ко всем уже существующим
|
||||
document.querySelectorAll(selector).forEach(applyToInput);
|
||||
|
||||
// 2) применяем к добавляемым динамически
|
||||
const mo = new MutationObserver((mutations) => {
|
||||
for (const m of mutations) {
|
||||
for (const node of m.addedNodes) {
|
||||
if (!(node instanceof Element)) continue;
|
||||
if (node.matches?.(selector)) applyToInput(node);
|
||||
node.querySelectorAll?.(selector).forEach(applyToInput);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mo.observe(document.documentElement, { childList: true, subtree: true });
|
||||
return () => mo.disconnect();
|
||||
}
|
||||
// запуск
|
||||
initPhoneMask();
|
||||
|
||||
function runOnDomUpdate(fn, root = document.documentElement) {
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
// если важно “не дергать” лишний раз — фильтруем
|
||||
if (mutations.some(m => m.type === 'childList' && (m.addedNodes.length || m.removedNodes.length))) {
|
||||
fn();
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(root, { childList: true, subtree: true }); // childList/subtree — ключевые опции [web:16]
|
||||
return () => observer.disconnect();
|
||||
}
|
||||
|
||||
// пример: заново применить маску к новым инпутам
|
||||
const stop = runOnDomUpdate(() => initPhoneMask());
|
||||
@ -59,10 +59,12 @@ class="bi bi-caret-left" viewBox="0 0 16 16">
|
||||
<!-- Right Side Of Navbar -->
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button"
|
||||
<a id="navbarDropdown" class="nav-link dropdown-toggle link-secondary" href="#" role="button"
|
||||
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
|
||||
<img src="../../images/icons/user.png" class="img-fluid align-middle"
|
||||
style="height: 40px;">
|
||||
<svg class="" xmlns="http://www.w3.org/2000/svg" width="38" height="38" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
|
||||
<path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0"/>
|
||||
<path fill-rule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
|
||||
@ -119,7 +121,16 @@ class="bi bi-caret-left" viewBox="0 0 16 16">
|
||||
</div>
|
||||
@endif
|
||||
@foreach ($errors->all() as $error)
|
||||
|
||||
<div class="alert alert-danger d-flex align-items-center" role="alert">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-exclamation-triangle" viewBox="0 0 16 16">
|
||||
<path d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.15.15 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.2.2 0 0 1-.054.06.1.1 0 0 1-.066.017H1.146a.1.1 0 0 1-.066-.017.2.2 0 0 1-.054-.06.18.18 0 0 1 .002-.183L7.884 2.073a.15.15 0 0 1 .054-.057m1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767z"/>
|
||||
<path d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0M7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0z"/>
|
||||
</svg>
|
||||
<div class="ms-3 fw-bold">
|
||||
{{ $error }}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@yield('content')
|
||||
</div>
|
||||
@ -129,5 +140,5 @@ class="bi bi-caret-left" viewBox="0 0 16 16">
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@vite(['resources/js/phone-format.js'])
|
||||
</html>
|
||||
|
||||
@ -233,33 +233,7 @@ class="bi bi-emoji-astonished" viewBox="0 0 16 16">
|
||||
</div>
|
||||
@script
|
||||
<script>
|
||||
eventCalllback = function(e) {
|
||||
var el = e.target,
|
||||
clearVal = el.dataset.phoneClear,
|
||||
pattern = el.dataset.phonePattern,
|
||||
matrix_def = "+7(___) ___-__-__",
|
||||
matrix = pattern ? pattern : matrix_def,
|
||||
i = 0,
|
||||
def = matrix.replace(/\D/g, ""),
|
||||
val = e.target.value.replace(/\D/g, "");
|
||||
if (clearVal !== 'false' && e.type === 'blur') {
|
||||
if (val.length < matrix.match(/([\_\d])/g).length) {
|
||||
e.target.value = '';
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (def.length >= val.length) val = def;
|
||||
e.target.value = matrix.replace(/./g, function(a) {
|
||||
return /[_\d]/.test(a) && i < val.length ? val.charAt(i++) : i >= val.length ? "" :
|
||||
a
|
||||
});
|
||||
}
|
||||
var phone_inputs = document.querySelectorAll('[data-phone-pattern]');
|
||||
for (let elem of phone_inputs) {
|
||||
for (let ev of ['input', 'blur', 'focus']) {
|
||||
elem.addEventListener(ev, eventCalllback);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
@endscript
|
||||
</div>
|
||||
|
||||
@ -11,6 +11,7 @@ export default defineConfig({
|
||||
'resources/css/app.css',
|
||||
'resources/css/docs.css',
|
||||
'resources/css/multiselect.css',
|
||||
'resources/js/phone-format.js',
|
||||
],
|
||||
refresh: true,
|
||||
}),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user