Выбор города
This commit is contained in:
@@ -87,6 +87,46 @@ storage/
|
|||||||
- Темы: `public/store/view/theme/`
|
- Темы: `public/store/view/theme/`
|
||||||
- Языковые файлы расширений: `public/admin/language/ru-ru/extension/`
|
- Языковые файлы расширений: `public/admin/language/ru-ru/extension/`
|
||||||
|
|
||||||
|
## Модальные окна и UI
|
||||||
|
|
||||||
|
### Модалки (modal.create)
|
||||||
|
Система модальных окон реализована в `public/store/view/theme/dominik/assets/js/script.js` (объект `modal`, строка 64).
|
||||||
|
|
||||||
|
**Вызов модалки с HTML-контентом:**
|
||||||
|
```js
|
||||||
|
modal.create({
|
||||||
|
modal: '<p>Содержимое окна</p>', // HTML-контент (обязателен)
|
||||||
|
title: 'Заголовок окна', // опционально
|
||||||
|
width: 400, // опционально, ширина в px
|
||||||
|
align: 'top', // опционально, прижать к верху
|
||||||
|
class: { // опционально, CSS-классы
|
||||||
|
'modal-body': 'p-0',
|
||||||
|
'modal-title': 'text-primary'
|
||||||
|
},
|
||||||
|
callback: { // опционально
|
||||||
|
show: function() { ... } // колбек при показе
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Загрузка контента через AJAX (modal.load):**
|
||||||
|
```js
|
||||||
|
modal.load(url, data); // ожидает JSON-ответ с ключом 'modal'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Выбор города в шапке
|
||||||
|
Выбор города реализован через:
|
||||||
|
- **Контроллер:** `public/store/controller/common/city.php`
|
||||||
|
- `index()` — отдаёт HTML-список зон (городов) для страны магазина
|
||||||
|
- `save()` — сохраняет `city_id` в сессию (`session->data['city_id']`), возвращает JSON с именем города
|
||||||
|
- **Шаблон списка:** `public/store/view/theme/dominik/template/common/city_list.twig`
|
||||||
|
- **Логика в хедере:** `public/store/controller/common/header.php` (строки с `model_localisation_zone`)
|
||||||
|
- Берёт `config_country_id` и `config_zone_id` из настроек магазина
|
||||||
|
- Если в сессии есть `city_id` — используется он, иначе `config_zone_id`
|
||||||
|
- Передаёт `current_city_name` и `city_list_url` в шаблон
|
||||||
|
- **Кнопка в шапке:** `public/store/view/theme/dominik/template/common/header.twig` — после `{{ service_menu }}`
|
||||||
|
- **JS-функция:** `citySelect(el)` в `script.js` — загружает список городов через AJAX, создаёт модалку, при клике сохраняет выбор в сессию и обновляет название на кнопке
|
||||||
|
|
||||||
## Полезные команды
|
## Полезные команды
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<label class="col-sm-2 control-label" for="input-attribute-group">{{ entry_attribute_group }}</label>
|
<label class="col-sm-2 control-label" for="input-attribute-group">{{ entry_attribute_group }}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<select name="attribute_group_id" id="input-attribute-group" class="form-control">
|
<select name="attribute_group_id" id="input-attribute-group" class="form-control">
|
||||||
<option value="0"></option>
|
|
||||||
{% for attribute_group in attribute_groups %}
|
{% for attribute_group in attribute_groups %}
|
||||||
{% if attribute_group.attribute_group_id == attribute_group_id %}
|
{% if attribute_group.attribute_group_id == attribute_group_id %}
|
||||||
<option value="{{ attribute_group.attribute_group_id }}" selected="selected">{{ attribute_group.name }}</option>
|
<option value="{{ attribute_group.attribute_group_id }}" selected="selected">{{ attribute_group.name }}</option>
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
class ControllerCommonCity extends Controller {
|
||||||
|
public function index() {
|
||||||
|
$this->load->model('localisation/zone');
|
||||||
|
|
||||||
|
$country_id = $this->config->get('config_country_id');
|
||||||
|
|
||||||
|
$zones = $this->model_localisation_zone->getZonesByCountryId($country_id);
|
||||||
|
|
||||||
|
$current_zone_id = isset($this->session->data['city_id']) ? (int)$this->session->data['city_id'] : (int)$this->config->get('config_zone_id');
|
||||||
|
|
||||||
|
$data['zones'] = array();
|
||||||
|
|
||||||
|
foreach ($zones as $zone) {
|
||||||
|
$data['zones'][] = array(
|
||||||
|
'zone_id' => $zone['zone_id'],
|
||||||
|
'name' => $zone['name'],
|
||||||
|
'active' => ($zone['zone_id'] == $current_zone_id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['action'] = $this->url->link('common/city/save');
|
||||||
|
|
||||||
|
$this->response->setOutput($this->load->view('common/city_list', $data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save() {
|
||||||
|
$json = array();
|
||||||
|
|
||||||
|
if (isset($this->request->post['city_id'])) {
|
||||||
|
$this->session->data['city_id'] = (int)$this->request->post['city_id'];
|
||||||
|
$json['success'] = true;
|
||||||
|
|
||||||
|
$this->load->model('localisation/zone');
|
||||||
|
$zone = $this->model_localisation_zone->getZone($this->session->data['city_id']);
|
||||||
|
$json['name'] = $zone ? $zone['name'] : '';
|
||||||
|
} else {
|
||||||
|
$json['success'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->addHeader('Content-Type: application/json');
|
||||||
|
$this->response->setOutput(json_encode($json));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -104,6 +104,22 @@ foreach(['name','email','telephone','address','open', 'comment'] as $item){
|
|||||||
$data['cart'] = $this->load->controller('common/cart');
|
$data['cart'] = $this->load->controller('common/cart');
|
||||||
$data['menu'] = $this->load->controller('common/menu');
|
$data['menu'] = $this->load->controller('common/menu');
|
||||||
|
|
||||||
|
$this->load->model('localisation/zone');
|
||||||
|
$country_id = $this->config->get('config_country_id');
|
||||||
|
$zones = $this->model_localisation_zone->getZonesByCountryId($country_id);
|
||||||
|
|
||||||
|
$current_zone_id = isset($this->session->data['city_id']) ? (int)$this->session->data['city_id'] : (int)$this->config->get('config_zone_id');
|
||||||
|
|
||||||
|
$data['current_city_name'] = '';
|
||||||
|
foreach ($zones as $zone) {
|
||||||
|
if ($zone['zone_id'] == $current_zone_id) {
|
||||||
|
$data['current_city_name'] = $zone['name'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['city_list_url'] = 'index.php?route=common/city';
|
||||||
|
|
||||||
return $this->load->view('common/header', $data);
|
return $this->load->view('common/header', $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -444,6 +444,30 @@ function addLoading(elem){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function citySelect(el){
|
||||||
|
var url = $(el).data('city-url');
|
||||||
|
|
||||||
|
$.get(url, function(html){
|
||||||
|
modal.create({
|
||||||
|
modal: html,
|
||||||
|
title: 'Выберите город',
|
||||||
|
width: 400,
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.city-item').click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var cityId = $(this).data('city-id');
|
||||||
|
var cityName = $(this).text();
|
||||||
|
send.post('index.php?route=common/city/save', {city_id: cityId}, function(json){
|
||||||
|
if (json.success) {
|
||||||
|
$('.current-city-name').text(json.name);
|
||||||
|
$('.modal').modal('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function SendRequest(product_id = 0){
|
function SendRequest(product_id = 0){
|
||||||
|
|
||||||
var params = {};
|
var params = {};
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<div class="city-grid">
|
||||||
|
{% for zone in zones %}
|
||||||
|
<button type="button" class="city-item{% if zone.active %} active{% endif %}" data-city-id="{{ zone.zone_id }}">{{ zone.name }}</button>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.city-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
.city-item {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #222;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
font-family: inherit;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
.city-item:hover {
|
||||||
|
border-color: #aaa;
|
||||||
|
background: #f9f9f9;
|
||||||
|
}
|
||||||
|
.city-item.active {
|
||||||
|
background: #222;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #222;
|
||||||
|
}
|
||||||
|
@media (max-width: 380px) {
|
||||||
|
.city-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -62,6 +62,9 @@
|
|||||||
{{ menu }}
|
{{ menu }}
|
||||||
{{ blog_menu }}
|
{{ blog_menu }}
|
||||||
{{ service_menu }}
|
{{ service_menu }}
|
||||||
|
{% if current_city_name %}
|
||||||
|
<li><a href="#" data-city-url="{{ city_list_url }}" onclick="citySelect(this);return false;"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 0C5.083 0 2.667 2.416 2.667 5.333C2.667 9.333 8 16 8 16S13.333 9.333 13.333 5.333C13.333 2.416 10.917 0 8 0ZM8 7.2C6.97 7.2 6.133 6.364 6.133 5.333C6.133 4.303 6.97 3.467 8 3.467C9.03 3.467 9.867 4.303 9.867 5.333C9.867 6.364 9.03 7.2 8 7.2Z" fill="currentColor"/></svg> <span class="d-none d-lg-inline-block ms-1 current-city-name">{{ current_city_name }}</span></a></li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-lg-none">
|
<div class="d-lg-none">
|
||||||
|
|||||||
Reference in New Issue
Block a user