const express = require('express') const router = express.Router() const {getDB} = require('../database') /** * @swagger * tags: * name: Regions * description: 地区数据API */ /** * @swagger * components: * schemas: * Region: * type: object * properties: * code: * type: string * description: 地区编码 * name: * type: string * description: 地区名称 * ZhejiangRegion: * type: object * properties: * id: * type: integer * description: 地区ID * city_name: * type: string * description: 城市名称 * district_name: * type: string * description: 区县名称 * region_code: * type: string * description: 地区编码 * is_available: * type: integer * description: 是否可用(1:可用 0:不可用) */ /** * @swagger * /regions/zhejiang: * get: * summary: 获取浙江省所有地区数据 * tags: [Regions] * responses: * 200: * description: 成功获取浙江省地区数据 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: array * items: * $ref: '#/components/schemas/ZhejiangRegion' * message: * type: string * example: 获取地区数据成功 * 500: * description: 服务器错误 */ router.get('/zhejiang', async (req, res) => { try { const query = ` SELECT id, city_name, district_name, region_code, is_available FROM zhejiang_regions WHERE is_available = 1 ORDER BY city_name, district_name ` const [rows] = await getDB().execute(query) res.json({ success: true, data: rows, message: '获取地区数据成功' }) } catch (error) { console.error('获取浙江省地区数据失败:', error) res.status(500).json({ success: false, message: '获取地区数据失败' }) } }) /** * @swagger * /regions/provinces: * get: * summary: 获取所有省份 * tags: [Regions] * responses: * 200: * description: 成功获取省份列表 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: array * items: * $ref: '#/components/schemas/Region' * 500: * description: 服务器错误 */ router.get('/provinces', async (req, res) => { try { // 按level分组数据 const regionsByLevel = { 1: [], // 省份 2: [], // 城市 3: [] // 区县 }; if (!global.provinces) { // 一次性获取所有区域数据(省、市、区县) const [allRegions] = await getDB().execute( `SELECT code, name as label, level, parent_code FROM china_regions WHERE level <= 3 ORDER BY level, code` ); // 创建code到region的映射,便于快速查找 const regionMap = {}; // 分组并建立映射 allRegions.forEach(region => { region.children = []; // 初始化children数组 regionsByLevel[region.level].push(region); regionMap[region.code] = region; }); // 构建层级关系:先处理区县到城市的关系 regionsByLevel[3].forEach(district => { const parentCity = regionMap[district.parent_code]; if (parentCity) { parentCity.children.push(district); } }); // 再处理城市到省份的关系 regionsByLevel[2].forEach(city => { const parentProvince = regionMap[city.parent_code]; if (parentProvince) { parentProvince.children.push(city); } }); global.provinces = regionsByLevel[1]; }else { // console.log('1111') regionsByLevel[1] = global.provinces; } // 返回省份数据(已包含完整的层级结构) res.json({ success: true, data: regionsByLevel[1] }); } catch (error) { console.error('获取省份列表错误:', error); res.status(500).json({message: '获取省份列表失败'}); } }); /** * @swagger * /regions/cities/{provinceCode}: * get: * summary: 根据省份代码获取城市列表 * tags: [Regions] * parameters: * - in: path * name: provinceCode * required: true * schema: * type: string * description: 省份代码 * responses: * 200: * description: 成功获取城市列表 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: array * items: * $ref: '#/components/schemas/Region' * 500: * description: 服务器错误 */ router.get('/cities/:provinceCode', async (req, res) => { try { const provinceCode = req.params.provinceCode; const [cities] = await getDB().execute( `SELECT code, name FROM china_regions WHERE level = 2 AND parent_code = ? ORDER BY code`, [provinceCode] ); res.json({ success: true, data: cities }); } catch (error) { console.error('获取城市列表错误:', error); res.status(500).json({message: '获取城市列表失败'}); } }); /** * @swagger * /regions/districts/{cityCode}: * get: * summary: 根据城市代码获取区县列表 * tags: [Regions] * parameters: * - in: path * name: cityCode * required: true * schema: * type: string * description: 城市代码 * responses: * 200: * description: 成功获取区县列表 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: array * items: * $ref: '#/components/schemas/Region' * 500: * description: 服务器错误 */ router.get('/districts/:cityCode', async (req, res) => { try { const cityCode = req.params.cityCode; const [districts] = await getDB().execute( `SELECT code, name FROM china_regions WHERE level = 3 AND parent_code = ? ORDER BY code`, [cityCode] ); res.json({ success: true, data: districts }); } catch (error) { console.error('获取区县列表错误:', error); res.status(500).json({message: '获取区县列表失败'}); } }); /** * @swagger * /regions/path/{regionCode}: * get: * summary: 根据区域代码获取完整路径(省-市-区) * tags: [Regions] * parameters: * - in: path * name: regionCode * required: true * schema: * type: string * description: 区域代码 * responses: * 200: * description: 成功获取区域完整路径 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * data: * type: object * properties: * province: * $ref: '#/components/schemas/Region' * city: * $ref: '#/components/schemas/Region' * district: * $ref: '#/components/schemas/Region' * 404: * description: 区域不存在 * 500: * description: 服务器错误 */ router.get('/path/:regionCode', async (req, res) => { try { const regionCode = req.params.regionCode; // 获取当前区域信息 const [currentRegion] = await getDB().execute( 'SELECT code, name, level, parent_code FROM china_regions WHERE code = ?', [regionCode] ); if (currentRegion.length === 0) { return res.status(404).json({message: '区域不存在'}); } const region = currentRegion[0]; const path = [region]; // 递归获取父级区域 let parentCode = region.parent_code; while (parentCode) { const [parentRegion] = await getDB().execute( 'SELECT code, name, level, parent_code FROM china_regions WHERE code = ? AND status = "active"', [parentCode] ); if (parentRegion.length > 0) { path.unshift(parentRegion[0]); parentCode = parentRegion[0].parent_code; } else { break; } } res.json({ success: true, data: { path, province: path.find(r => r.level === 1) || null, city: path.find(r => r.level === 2) || null, district: path.find(r => r.level === 3) || null } }); } catch (error) { console.error('获取区域路径错误:', error); res.status(500).json({message: '获取区域路径失败'}); } }); // 搜索区域(支持模糊搜索) router.get('/search', async (req, res) => { try { const {keyword, level} = req.query; if (!keyword || keyword.trim() === '') { return res.status(400).json({message: '搜索关键词不能为空'}); } let sql = `SELECT code, name, level, parent_code FROM china_regions WHERE name LIKE ?`; const params = [`%${keyword.trim()}%`]; if (level) { sql += ' AND level = ?'; params.push(parseInt(level)); } sql += ' ORDER BY level, code LIMIT 50'; const [regions] = await getDB().execute(sql, params); // 为每个搜索结果获取完整路径 const results = []; for (const region of regions) { const path = [region]; let parentCode = region.parent_code; while (parentCode) { const [parentRegion] = await getDB().execute( 'SELECT code, name, level, parent_code FROM china_regions WHERE code = ? AND status = "active"', [parentCode] ); if (parentRegion.length > 0) { path.unshift(parentRegion[0]); parentCode = parentRegion[0].parent_code; } else { break; } } results.push({ ...region, path, fullName: path.map(r => r.name).join(' - ') }); } res.json({ success: true, data: results }); } catch (error) { console.error('搜索区域错误:', error); res.status(500).json({message: '搜索区域失败'}); } }); module.exports = router