С некоторых пор, если на сайте госуслуг нажимаещь F12, чтобы открыть консоль разработчика, то автоматически включается отладка, и подсмотреть что делает сайт «под капотом» становится проблематично т.к. после нажатия кнопки «продолжить», отладка снова автоматически останавливается. Вообще не понятно зачем они это сделали, т.к. отключается всё это одной кнопкой:
И для опытного программиста никакой трудности не возникает. А не опытные? А зачем они сюда полезут вообще и что увидят? Ну в общем так себе «защита» не понятно для кого рассчитанная
Нет, всё таки версия 3 еще сыровата для внедрения в прод. Ну или «лыжи не едут». Для решения простой задачи — отображение подсказки над полигоном, пришлось переписываться с тех поддержкой яндекса (и они даже ответили!, чем я безмерно удивлён). В результате родился скрипт, в котором требуется переопределение вызовов класса. Хм.. это определенно не то что хочется видеть для получения базовых вещей, которые в версии 2.1 работают «из коробки».
async function main() {
await ymaps3.ready;
ymaps3.import.registerCdn('https://cdn.jsdelivr.net/npm/{package}',['@yandex/ymaps3-hint@0.0.1']);
const {YMap,YMapDefaultSchemeLayer,YMapFeature,YMapDefaultFeaturesLayer,YMapFeatureSource,YMapFeatureDataSource,YMapEntity} = ymaps3;
const {YMapHint,YMapHintContext} = await ymaps3.import('@yandex/ymaps3-hint');
map = new ymaps3.YMap(
document.getElementById('app'),
{location:
{
center: [39.8491648, 59.2084992],
zoom: 9
},
showScaleInCopyrights: false //шкала масштаба рядом в логотипом
}
);
const defaultScheme = new YMapDefaultSchemeLayer({}); // Добавляем рисованное изображение карты
map.addChild(defaultScheme);
const features = new YMapDefaultFeaturesLayer();
map.addChild(features);
//получаем список районов
common.AjaxPost("index.php?r=site2/get-areas","").then(async areas_list=>{
console.log("-прочитал список районов ",areas_list);
if (areas_list.error==false){
for (var i = 0; i < areas_list.result.length; i++) {
await common.AjaxPost("areas/"+areas_list.result[i].poly_filename,"aa").then(res2=>{
console.log(areas_list.result[i].name);
res2=common.ReverseCoors(res2);
console.log(areas_list.result[i].poly_fill_color);
const polygon = new ymaps3.YMapFeature({
geometry: {
type: 'Polygon',
coordinates: res2
},
properties: {
hint: areas_list.result[i].name+" район"
},
style: {
stroke: [
{
color: '#196DFF99',
dash: [5, 10],
width: 3
}
],
fillOpacity: 0.2,
fill: "#"+areas_list.result[i].poly_fill_color
}
});
features.addChild(polygon);
});
};
};
});
const hint = new YMapHint({
layers: [features.layer],
hint: object => object?.properties?.hint
});
map.addChild(hint);
hint.addChild(
new(
class MyHint extends YMapEntity {
_onAttach() {
this._element =document.createElement('div');
this._element.className ='hint';
this._detachDom =ymaps3.useDomContext(this,this._element);
this._watchContext(
YMapHintContext,
() => {
const context =this._consumeContext(YMapHintContext);
this._element.textContent =(context?.hint || '');
console.log(this._element);
}, {
immediate: true
}
);
}
_onDetach() {this._detachDom();}
}
)()
);
};
window.map = null;
main();
Пока на работе выдалась небольшая творческая пауза, решил потыкать API версии 3, который приходит на смену версии 2.1 И рано или поздно как я понимаю версия 2.1 будет отключена. А проекты на «старой» версии есть.
Так вот, что не понравилось: все примеры в «песочнице», на typescript, а не на чистом javascript. Ну и полностью всё конечно поломано, т.е. не получится просто взять старый код, и чуть адаптировать — нужно всё переписывать. Вплоть до того что, они даже координаты «перевернули» местами, пришлось для того чтобы наложить полигоны районов со старой карты на новую, их «переворачивать».
Ну собственно, вот код,
<script crossorigin src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
<script src="https://api-maps.yandex.ru/v3/?apikey=уууу&lang=ru_RU" type="text/javascript"></script>
<div id="app"></div>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel" src="ts/variables.ts"></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel" src="ts/common.ts"></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel" src="ts/receipts.ts"></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
import * as common from '../common';
async function main() {
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer,YMapFeature,YMapDefaultFeaturesLayer} = ymaps3;
map = new YMap(
document.getElementById('app'),
{location:
{
center: [39.8491648, 59.2084992],
zoom: 9
},
showScaleInCopyrights: true
},
[
new YMapDefaultSchemeLayer({}),
new YMapDefaultFeaturesLayer({})
],
);
//получаем список районов
common.AjaxPost("index.php?r=site2/get-areas","").then(async areas_list=>{
console.log("-прочитал список районов ",areas_list);
if (areas_list.error==false){
for (var i = 0; i < areas_list.result.length; i++) {
await common.AjaxPost("areas/"+areas_list.result[i].poly_filename,"aa").then(res2=>{
console.log(areas_list.result[i].name);
res2=common.ReverseCoors(res2);
console.log(areas_list.result[i].poly_fill_color);
const polygon = new YMapFeature({
geometry: {
type: 'Polygon',
coordinates: res2
},
properties:{
hintContent: areas_list.result[i].name
},
// Описание тут: https://yandex.ru/maps-api/docs/js-api/ref/index.html#interface-drawingstyle
style: {
stroke: [
{
color: '#196DFF99',
dash: [5, 10],
width: 3
}
],
fillOpacity: 0.2,
fill: "#"+areas_list.result[i].poly_fill_color
}
});
console.log(polygon);
map.addChild(polygon);
});
};
};
});
};
window.map = null;
main();
</script>
common.ts:
/**
Получаем информацию об очертаниях районов (округов)
*/
export async function AjaxPost(url : string,payload: any): any {
try {
const response = await fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/json; charset=UTF-8' },
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(HTTP error! Status: ${response.status});
}
return response.json();
} catch (error) {
console.error('Error:', error);
throw error;
}
}
/**
Сделать паузу в милисекундах
*/
export async function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
Перевернуть все координаты в массиве
*/
export function ReverseCoors(coors : any): any {
for (var ii = 0; ii < coors.length; ii++) {
for (var iii = 0; iii < coors[ii].length; iii++) {
var x=0;
var y=0;
x=coors[ii][iii][0];
y=coors[ii][iii][1];
coors[ii][iii][1]=x;
coors[ii][iii][0]=y;
};
};
return coors;
}
Если требуется обработать и показать данные по выбранному диапазону, то необходимо использовать в запросе переменные $__from и $__to. Однако стоит учитывать, что они в запросе встают как время с эпохи unix. А именно большое длинное число. Поэтому если например в БД у даты типа дата, без времени, то приходится использовать преобразование вида:
EXTRACT(EPOCH from agreements_dt)*1000
Чтобы из даты вида 2026-01-01 получить 1767214800000. Ну и соответственно в запросе:
select to_char(date_trunc('day', dt), 'YYYY-MM-DD'),count(*) as "Великоустюгское территориальное отделение" from (
select
date_trunc('month', agreements_dt)::date as dt
from
ls
where EXTRACT(EPOCH from agreements_dt)*1000 between $__from and $__to and owner='000000003' and agreements_dt is not null
) as agr
group by dt
order by dt asc
Как бы не ругались некоторые товарищи на Habr, что «разрабатывать под Max, себя не уважать», но тем не менее не все имеют этот выбор 😉 Так что проблемы решать таки нужно..
Итак, задача: между нажатием кнопки с кэлбеком и ответом сервера происходит некоторая пауза. Иногда в несколько секунд. Пользователи не всегда дожидаются ответа, и нажимают кнопки по нескольку раз.
Решение: т.к. на основной ответ сервера требуется некоторое время на его подготовку, то перед «настоящим» ответом сервера, отправим «промежуточный», который сообщит пользователю «Подождите ответа сервера», а заодно скроет все кнопки из предыдущего сообщения пользователя, чтоб не было соблазна их нажимать. Код получается примерно такой:
...
if (isset($in->update_type)){
if ($in->update_type=="message_callback"){
$params=[];
$params["callback_id"]=$in->callback->callback_id;
$data=[];
$data["message"]["attachments"]=[];
$data["notification"]="Подождите ответа сервера...";
$res=$Max->Reqwest("answers",$params,$data,"POST");
};
if (($in->update_type=="message_created") or ($in->update_type=="message_callback") or ($in->update_type=="bot_started")){
$res=$Api1c->reqwest("MaxCallback2",["body"=>$body]); // пересылаем всё что пришло в 1С и получаем ответ
if ($res==null){
$params=[];
$params["chat_id"]=$in->message->recipient->chat_id;
$data=[];
$data["text"]="Временная ошибка серверера. Попробуйте позже.";
$data["format"]= "html";
$buttons=[];
$button=[];
$button["type"]="callback";
$button["text"]="Перейти в главное меню";
$button["payload"]="Go2MainMenu";
$buttons[]=$button;
$attachment=[];
$attachment["type"]="inline_keyboard";
$attachment["payload"]["buttons"]=[];
$attachment["payload"]["buttons"][]=$buttons;
$data["attachments"]=[];
$data["attachments"][]=$attachment;
$res=$Max->Reqwest("messages",$params,$data,"POST");
die();
};
// если 1С вернула ошибку то её и показываем пользователю
if ($res->error==true){
$params=[];
if (isset($in->message)){$params["chat_id"]=$in->message->recipient->chat_id;};
if (isset($in->chat_id)){$params["chat_id"]=$in->chat_id;};
$data=[];
$data["text"]=$res->result;
$data["format"]= "html";
$buttons=[];
$button=[];
$button["type"]="callback";
$button["text"]="Перейти в главное меню";
$button["payload"]="Go2MainMenu";
$buttons[]=$button;
$attachment=[];
$attachment["type"]="inline_keyboard";
$attachment["payload"]["buttons"]=[];
$attachment["payload"]["buttons"][]=$buttons;
$data["attachments"]=[];
$data["attachments"][]=$attachment;
$res=$Max->Reqwest("messages",$params,$data,"POST");
die();
};
// Что пришло из 1С, то и отдаём в сообщения пользователю..
$params=$res->result->params;
$data=$res->result->data;
$res=$Max->Reqwest("messages",$params,$data,"POST");
die();
...