c892fb26a9
Города и посёлки РК (178) из официального КАТО stat.gov.kz — на русском и казахском, с кодом и областью. Справочник генерируется скриптом scripts/Build-KatoCities.ps1 и лежит на фронте: внешних API и ключей не нужно. CityPicker ищет по обоим языкам с учётом раскладки (Құлсары = Кулсары) и оставляет свой вариант для сёл и заграницы. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
100 lines
5.5 KiB
PowerShell
100 lines
5.5 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
Собирает справочник городов и посёлков РК для выпадающих списков портала из
|
||
официального КАТО (Бюро национальной статистики, stat.gov.kz) и пишет его
|
||
TS-модулем src/webparts/requestPortal/shared/dictionary/kato/katoCities.ts.
|
||
|
||
.DESCRIPTION
|
||
Берём только города («г.») и посёлки («п.»): ~180 записей, несколько KB в бандле.
|
||
Сёла (~10 тыс.) не берём — тяжело для фронта; их вводят вручную в то же поле.
|
||
Административные единицы («Г.А.», «п.а.», «г.а.» — администрации, не населённые
|
||
пункты) отбрасываются. КАТО обновляется редко: перезапустить скрипт со ссылкой
|
||
на свежий файл со страницы https://stat.gov.kz/ru/classifiers/statistical/21/
|
||
и закоммитить сгенерированный модуль.
|
||
|
||
.EXAMPLE
|
||
./scripts/Build-KatoCities.ps1
|
||
./scripts/Build-KatoCities.ps1 -XlsxUrl "https://stat.gov.kz/upload/iblock/.../КАТО_ДД.ММ.ГГГГ.xlsx"
|
||
#>
|
||
param(
|
||
[string]$XlsxUrl = 'https://stat.gov.kz/upload/iblock/a7d/eqogm92xc0udumlzfzffhcrutk0fjhb4/КАТО_18.09.2026.xlsx',
|
||
[string]$OutFile = (Join-Path $PSScriptRoot '..\src\webparts\requestPortal\shared\dictionary\kato\katoCities.ts')
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
|
||
$work = Join-Path ([System.IO.Path]::GetTempPath()) "kato-$([guid]::NewGuid())"
|
||
New-Item -ItemType Directory -Path $work | Out-Null
|
||
try {
|
||
# xlsx — это zip: читаем XML листа напрямую, без Excel и сторонних модулей.
|
||
$zip = Join-Path $work 'kato.zip'
|
||
Invoke-WebRequest -Uri $XlsxUrl -OutFile $zip -UseBasicParsing
|
||
Expand-Archive -Path $zip -DestinationPath $work
|
||
|
||
[xml]$sharedXml = Get-Content -Raw -Encoding UTF8 (Join-Path $work 'xl\sharedStrings.xml')
|
||
$shared = @($sharedXml.sst.si | ForEach-Object { $_.InnerText })
|
||
|
||
[xml]$sheetXml = Get-Content -Raw -Encoding UTF8 (Join-Path $work 'xl\worksheets\sheet1.xml')
|
||
|
||
# Колонки листа: A — код КАТО, B — код области (ab), C/D/E — нижние уровни, G/H — название на казахском/русском.
|
||
$rows = foreach ($row in $sheetXml.worksheet.sheetData.row) {
|
||
$cells = @{}
|
||
foreach ($c in $row.c) {
|
||
$column = $c.r -replace '\d', ''
|
||
$value = if ($c.t -eq 's') { $shared[[int]$c.v] } elseif ($c.t -eq 'inlineStr') { $c.is.InnerText } else { $c.v }
|
||
$cells[$column] = "$value".Trim()
|
||
}
|
||
[pscustomobject]@{ Kato = $cells['A']; Region = $cells['B']; Level2 = $cells['C']; Level3 = $cells['D']; Level4 = $cells['E']; Name = $cells['H']; NameKz = $cells['G'] }
|
||
}
|
||
|
||
# Области — строки без нижних уровней. Города республиканского значения (Астана,
|
||
# Алматы, Шымкент) сами себе «область» — для них регион не показываем.
|
||
$regions = @{}
|
||
$rows | Where-Object { $_.Level2 -eq '00' -and $_.Level3 -eq '00' -and $_.Level4 -eq '000' } | ForEach-Object {
|
||
$regions[$_.Region] = if ($_.Name -match '^г\.') { '' } else { $_.Name }
|
||
}
|
||
|
||
# «г.Атырау», «п. Асыката» — населённые пункты; «п.а.», «г.а.» — администрации.
|
||
$cities = $rows |
|
||
Where-Object { $_.Name -match '^(г|п)\.\s*[^\s.]' -and $_.Name -notmatch '^(г|п)\.а\.' } |
|
||
ForEach-Object {
|
||
[pscustomobject]@{
|
||
Kato = $_.Kato
|
||
Name = ($_.Name -replace '^(г|п)\.\s*', '')
|
||
# «Құлсары қ.» / «Шаған к.» — тип пункта последним словом с точкой (в источнике
|
||
# встречается и опечатка «ќ.»), поэтому отрезаем любое такое слово.
|
||
NameKz = ($_.NameKz -replace '\s+\S+\.$', '')
|
||
Kind = if ($_.Name -match '^г\.') { 'city' } else { 'settlement' }
|
||
Region = $regions[$_.Region]
|
||
}
|
||
} |
|
||
Sort-Object Name, Region
|
||
|
||
$esc = { param($s) $s -replace '\\', '\\' -replace "'", "\'" }
|
||
$lines = $cities | ForEach-Object {
|
||
" { kato: '$($_.Kato)', name: '$(& $esc $_.Name)', nameKz: '$(& $esc $_.NameKz)', kind: '$($_.Kind)', region: '$(& $esc $_.Region)' },"
|
||
}
|
||
|
||
$source = [System.Uri]::UnescapeDataString(($XlsxUrl -split '/')[-1])
|
||
$content = @"
|
||
// СГЕНЕРИРОВАНО scripts/Build-KatoCities.ps1 — руками не править, перезапустить скрипт.
|
||
// Источник: КАТО, Бюро национальной статистики РК (stat.gov.kz), файл «$source».
|
||
import { IKatoCity } from './IKatoCity';
|
||
|
||
export const KATO_CITIES: ReadonlyArray<IKatoCity> = [
|
||
$($lines -join "`n")
|
||
];
|
||
"@
|
||
|
||
$outPath = [System.IO.Path]::GetFullPath($OutFile)
|
||
New-Item -ItemType Directory -Force -Path (Split-Path $outPath) | Out-Null
|
||
# Без BOM и с LF — как остальные исходники репозитория.
|
||
[System.IO.File]::WriteAllText($outPath, $content.Replace("`r`n", "`n") + "`n", (New-Object System.Text.UTF8Encoding $false))
|
||
|
||
$cityCount = @($cities | Where-Object Kind -eq 'city').Count
|
||
Write-Host "Готово: $($cities.Count) записей (городов $cityCount, посёлков $($cities.Count - $cityCount)) → $OutFile"
|
||
}
|
||
finally {
|
||
Remove-Item -Recurse -Force $work
|
||
}
|