Files

74 lines
3.7 KiB
Python
Raw Permalink Normal View History

"""从版本化选择字典生成前后端城市数据;不下载、不修改生产配置。"""
import argparse
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
parser = argparse.ArgumentParser()
parser.add_argument('--backend', type=Path, required=True)
parser.add_argument('--check', action='store_true')
args = parser.parse_args()
data = json.loads((ROOT / 'docs/data/city-options.json').read_text(encoding='utf-8'))
regions = data['regions']
names = [city['name'] for region in regions for city in region['cities']]
codes = {city['code']: city['name'] for region in regions for city in region['cities'] if city['code']}
assert len(names) == len(set(names)), '城市名称不能歧义'
assert len(codes) == sum(bool(city['code']) for region in regions for city in region['cities']), '代码重复'
assert all(re.fullmatch(r'\d{6}', code) for code in codes)
uts = "// 由 scripts/generate-city-options.py 生成;来源和覆盖口径见 docs/data/city-options.json。\n"
uts += "export type CityOption = { name: string, code: string }\nexport type CityRegion = { name: string, cities: CityOption[] }\n"
uts += "export const cityRegions: CityRegion[] = [\n"
uts += ',\n'.join(' ' + json.dumps(region, ensure_ascii=False) for region in regions) + '\n]\n'
provinces = {str(index['code']) + '0000': index['name'] for index in data['provinces']}
uts += 'export const provinceOptions: CityOption[] = ' + json.dumps([{'name':name,'code':code} for code,name in provinces.items()],ensure_ascii=False) + '\n'
uts += '''
export const citySelection = (name: string): number[] => {
for (let province = 0; province < cityRegions.length; province++) {
const cities = cityRegions[province].cities
for (let city = 0; city < cities.length; city++) {
if (cities[city].name == name) return [province, city]
}
}
return [-1, -1]
}
export const cityCodeForName = (name: string): string | null => {
const selected = citySelection(name)
if (selected[0] < 0) return null
const code = cityRegions[selected[0]].cities[selected[1]].code
return code.length > 0 ? code : null
}
export const cityDisplayName = (name: string): string => {
const selected = citySelection(name)
if (selected[0] < 0) return name
const province = cityRegions[selected[0]].name
return province == name ? name : province + ' / ' + name
}
export const provinceCodeForName = (name: string): string | null => {
const index = provinceOptions.findIndex((item: CityOption): boolean => item.name == name)
return index < 0 ? null : provinceOptions[index].code
}
// 仅供历史城市资料回填为省份;未知名称不猜测。
export const provinceForCity = (name: string): string => {
if (provinceCodeForName(name) != null) return name
const selected = citySelection(name)
return selected[0] < 0 ? '' : cityRegions[selected[0]].name
}
'''
constant = ' const PROVINCES = [\n' + '\n'.join(" '%s' => '%s'," % (code, name) for code,name in provinces.items()) + '\n ];\n'
backend = args.backend / 'application/common/library/AssessmentRecords.php'
original = backend.read_text(encoding='utf-8')
php, replacements = re.subn(r' const PROVINCES = .*?;\n', lambda _: constant, original, count=1, flags=re.S)
if not replacements:
php = original.replace(' private static function only(', constant + '\n private static function only(',1)
for path, content in [(ROOT / 'services/cities.uts', uts), (backend, php)]:
if args.check:
assert path.read_text(encoding='utf-8') == content, f'生成文件不同步:{path}'
else:
path.write_text(content, encoding='utf-8', newline='\n')
print(f'{len(provinces)} province choices; legacy city lookup retained; ' + ('consistent' if args.check else 'generated'))