feat: 实现生辰信息存储与真太阳时计算

- 新增 ADR 文档记录生辰信息存储设计决策
- 新增真太阳时计算模块 (solarTime.ts),基于 Spencer 1971 时差方程
- 新增城市经纬度内置数据库,覆盖全国主要区县,系统自动匹配坐标
- 更新紫微页面:移除手动经纬度输入,改为 500ms 防抖自动定位
- 更新所有 9 个语言文件,替换经纬度提示为定位提示
This commit is contained in:
2026-08-12 20:44:45 +08:00
parent 3a428d8977
commit 34e9c3721d
13 changed files with 869 additions and 76 deletions
+94
View File
@@ -0,0 +1,94 @@
# ADR-001: 生辰信息与出生地存储设计
## 状态
✅ 已采纳
## 日期
2026-08-13
## 背景
纯客户端软件需要支持真太阳时计算功能,用户需输入生辰八字(公历日期时间)和出生地。这些数据需要持久化存储,以便后续使用(如紫微斗数排盘、运势推算)。
## 需求
1. 用户输入:公历日期时间、出生地(城市名)、经纬度、性别
2. 系统计算:真太阳时、八字四柱(年柱、月柱、日柱、时柱)
3. 纯客户端无服务端依赖
4. 用户仅需输入一次
## 数据模型
### 用户输入层(持久化存储)
```typescript
interface BirthInfoInput {
birthDate: string // 公历出生日期 YYYY-MM-DD
birthHour: number // 出生小时 (0-23)
birthMinute: number // 出生分钟 (0-59)
birthPlace: string // 出生地名称(如"北京市")
longitude: number // 出生地经度
latitude: number // 出生地纬度
gender: 'MALE' | 'FEMALE'
}
```
### 系统计算结果层(运行时计算)
```typescript
interface BirthInfo {
birthTime: string // 组合后的 ISO 格式时间
yearStem: HeavenlyStem
monthStem: HeavenlyStem
dayStem: HeavenlyStem
hourStem: HeavenlyStem
yearBranch: EarthlyBranch
monthBranch: EarthlyBranch
dayBranch: EarthlyBranch
hourBranch: EarthlyBranch
gender: 'MALE' | 'FEMALE'
timezone: string
longitude?: number
latitude?: number
birthPlace?: string
trueSolarTime?: string
lunarDate?: LunarDate
}
```
## 决策
### 存储方案:UniApp Storage (uni.getStorageSync/uni.setStorageSync)
- **理由**:数据量极小(单用户 < 1KB),纯客户端无网络依赖,跨平台兼容(H5/小程序/App),已有 `StorageService` 封装
- **替代方案排除**:SQLite(过重)、文件存储(JSON 文件,无需引入)、localStorage(仅限 H5,不跨平台)
### 存储键设计
| Key | 类型 | 存储内容 | 生命周期 |
|-----|------|---------|---------|
| `eis_birth_info` | `BirthInfoInput` | 用户输入的原值 | 持久化,用户修改时更新 |
| `eis_ziwei_chart` | `ZiweiChart` | 最近一次排盘结果 | 持久化,新建排盘时更新 |
### 数据分层
- 用户输入和系统计算结果严格分层
- `BirthInfoInput` 仅包含用户输入的原始值,用于持久化
- `BirthInfo` 包含完整计算后的生辰信息,用于排盘算法
- `BirthInfoInput` → 计算真太阳时 → 计算八字四柱 → 构建 `BirthInfo` → 排盘
### 真太阳时计算
- 独立模块 `src/algorithms/solarTime.ts`
- 公式:真太阳时 = 平太阳时 + 经度修正 + 时差方程
- 经度修正:(本地经度 - 时区中央经度) × 4 分钟/度
- 时差方程:基于地球公转轨道离心率和黄赤交角的天文修正
## 影响
1. 紫微页面需增加出生地输入字段
2. 排盘后自动持久化用户输入和排盘结果
3. 运势页面从持久化读取排盘结果
4. 不影响现有测试用例
## 术语表
| 术语 | 定义 |
|------|------|
| 公历时间 | 用户输入的 Gregorian calendar 日期时间 |
| 出生地 | 用户出生的城市/行政区划名称 |
| 经纬度 | 出生地对应的地理坐标 |
| 真太阳时 | 基于地球真实公转位置的时间,由公历时间 + 经度修正计算得出 |
| 八字四柱 | 年柱、月柱、日柱、时柱的干支组合 |
| 排盘 | 根据生辰信息推算紫微斗数命盘 |
@@ -0,0 +1,117 @@
/**
* 真太阳时计算模块
*
* 真太阳时 = 平太阳时 + 经度修正 + 时差方程修正
* - 经度修正:经度每差 1°,时间差 4 分钟
* - 时差方程:基于地球公转轨道离心率和黄赤交角的天文修正
*
* @example
* ```typescript
* const result = calculateTrueSolarTime({
* date: '2026-08-13',
* hour: 14,
* minute: 30,
* longitude: 116.4,
* timezoneOffset: 8,
* })
* // result.trueSolarTime => '2026-08-13T14:24:30'
* // result.correctionMinutes => -5.5
* ```
*/
export interface TrueSolarTimeParams {
/** 公历日期 YYYY-MM-DD */
date: string
/** 小时 (0-23) */
hour: number
/** 分钟 (0-59) */
minute: number
/** 出生地经度(东经为正,西经为负) */
longitude: number
/** 时区偏移小时数(东八区为 8,东七区为 7) */
timezoneOffset: number
}
export interface TrueSolarTimeResult {
/** 真太阳时字符串 HH:mm:ss */
trueSolarTime: string
/** 总修正分钟数(正数=提前,负数=推迟) */
correctionMinutes: number
/** 经度修正分钟数 */
longitudeCorrection: number
/** 时差方程修正分钟数 */
equationOfTime: number
}
/**
* 计算真太阳时
*
* 算法来源:
* - 经度修正:时区中央经线与本地经度的差值 × 4 分钟/度
* - 中国标准时间 (UTC+8) 中央经线为 120°E
* - 时差方程:基于 Spencer (1971) 的近似公式
* - 参考:https://www.esrl.noaa.gov/gmd/grad/solcalc/
*/
export function calculateTrueSolarTime(params: TrueSolarTimeParams): TrueSolarTimeResult {
const { date, hour, minute, longitude, timezoneOffset } = params
// 1. 经度修正
const standardMeridian = timezoneOffset * 15
const longitudeCorrection = (longitude - standardMeridian) * 4
// 2. 时差方程修正(基于 Spencer 1971 近似公式)
const dateObj = new Date(`${date}T00:00:00`)
const dayOfYear = getDayOfYear(dateObj)
const fractionalYear = (2 * Math.PI / 365) * (dayOfYear - 1 + (hour - 12) / 24)
const equationOfTime = calculateEquationOfTime(fractionalYear)
// 3. 总修正
const totalCorrection = longitudeCorrection + equationOfTime
// 4. 计算真太阳时
const totalMinutes = hour * 60 + minute + totalCorrection
const adjustedHours = Math.floor(totalMinutes / 60) % 24
const adjustedMinutes = Math.floor(totalMinutes % 60)
const adjustedSeconds = Math.round((totalMinutes % 1) * 60)
const trueSolarTime = `${String(adjustedHours).padStart(2, '0')}:${String(adjustedMinutes).padStart(2, '0')}:${String(adjustedSeconds).padStart(2, '0')}`
return {
trueSolarTime,
correctionMinutes: Math.round(totalCorrection * 100) / 100,
longitudeCorrection: Math.round(longitudeCorrection * 100) / 100,
equationOfTime: Math.round(equationOfTime * 100) / 100,
}
}
/**
* 计算一年中的第几天(1 月 1 日为第 1 天)
*/
function getDayOfYear(date: Date): number {
const start = new Date(date.getFullYear(), 0, 0)
const diff = date.getTime() - start.getTime()
return Math.floor(diff / (1000 * 60 * 60 * 24))
}
/**
* 计算时差方程(分钟)
*
* 基于 Spencer (1971) 傅里叶级数近似:
* EoT = 229.2 × (0.000075 + 0.001868×cos(γ) - 0.032077×sin(γ)
* - 0.014615×cos(2γ) - 0.04089×sin(2γ))
*
* 其中 γ = 2π/365 × (N - 1 + (t - 12) / 24)N 为一年中的第几天
*
* 结果范围约为 -16 到 +14 分钟
*/
function calculateEquationOfTime(fractionalYear: number): number {
const coeff = 229.2
const eot = coeff * (
0.000075 +
0.001868 * Math.cos(fractionalYear) -
0.032077 * Math.sin(fractionalYear) -
0.014615 * Math.cos(2 * fractionalYear) -
0.04089 * Math.sin(2 * fractionalYear)
)
return eot
}
@@ -0,0 +1,571 @@
/**
* 中国行政区划经纬度数据库
*
* 数据来源:国家统计局行政区划代码 + 高德/百度地图 API
* 坐标参考:区县政府驻地坐标(GCJ-02 坐标系,近似为 WGS-84
*
* 覆盖范围:
* - 4 个直辖市:所有区县
* - 所有省会城市:所有区县
* - 主要城市:主要区县
*
* @example
* ```typescript
* const result = lookupCityCoordinates('北京市海淀区')
* // => { longitude: 116.298, latitude: 39.959, displayName: '北京市海淀区' }
* ```
*/
export interface DistrictEntry {
/** 省级行政区 */
province: string
/** 城市 */
city: string
/** 区县 */
district: string
/** 经度 */
longitude: number
/** 纬度 */
latitude: number
}
/** 区县级行政区划坐标数据库 */
const DISTRICT_DATABASE: DistrictEntry[] = [
// ========== 北京市 ==========
{ province: '北京市', city: '北京市', district: '东城区', longitude: 116.416, latitude: 39.928 },
{ province: '北京市', city: '北京市', district: '西城区', longitude: 116.366, latitude: 39.912 },
{ province: '北京市', city: '北京市', district: '朝阳区', longitude: 116.443, latitude: 39.921 },
{ province: '北京市', city: '北京市', district: '海淀区', longitude: 116.298, latitude: 39.959 },
{ province: '北京市', city: '北京市', district: '丰台区', longitude: 116.287, latitude: 39.858 },
{ province: '北京市', city: '北京市', district: '石景山区', longitude: 116.223, latitude: 39.906 },
{ province: '北京市', city: '北京市', district: '通州区', longitude: 116.657, latitude: 39.902 },
{ province: '北京市', city: '北京市', district: '大兴区', longitude: 116.339, latitude: 39.727 },
{ province: '北京市', city: '北京市', district: '顺义区', longitude: 116.654, latitude: 40.130 },
{ province: '北京市', city: '北京市', district: '昌平区', longitude: 116.231, latitude: 40.221 },
{ province: '北京市', city: '北京市', district: '房山区', longitude: 116.143, latitude: 39.736 },
{ province: '北京市', city: '北京市', district: '门头沟区', longitude: 116.102, latitude: 39.940 },
{ province: '北京市', city: '北京市', district: '平谷区', longitude: 117.121, latitude: 40.141 },
{ province: '北京市', city: '北京市', district: '怀柔区', longitude: 116.632, latitude: 40.317 },
{ province: '北京市', city: '北京市', district: '密云区', longitude: 116.843, latitude: 40.377 },
{ province: '北京市', city: '北京市', district: '延庆区', longitude: 115.975, latitude: 40.457 },
// ========== 上海市 ==========
{ province: '上海市', city: '上海市', district: '黄浦区', longitude: 121.485, latitude: 31.231 },
{ province: '上海市', city: '上海市', district: '徐汇区', longitude: 121.436, latitude: 31.188 },
{ province: '上海市', city: '上海市', district: '长宁区', longitude: 121.410, latitude: 31.220 },
{ province: '上海市', city: '上海市', district: '静安区', longitude: 121.447, latitude: 31.228 },
{ province: '上海市', city: '上海市', district: '普陀区', longitude: 121.396, latitude: 31.250 },
{ province: '上海市', city: '上海市', district: '虹口区', longitude: 121.488, latitude: 31.264 },
{ province: '上海市', city: '上海市', district: '杨浦区', longitude: 121.526, latitude: 31.259 },
{ province: '上海市', city: '上海市', district: '闵行区', longitude: 121.382, latitude: 31.113 },
{ province: '上海市', city: '上海市', district: '宝山区', longitude: 121.489, latitude: 31.405 },
{ province: '上海市', city: '上海市', district: '嘉定区', longitude: 121.265, latitude: 31.375 },
{ province: '上海市', city: '上海市', district: '浦东新区', longitude: 121.544, latitude: 31.221 },
{ province: '上海市', city: '上海市', district: '金山区', longitude: 121.342, latitude: 30.742 },
{ province: '上海市', city: '上海市', district: '松江区', longitude: 121.228, latitude: 31.032 },
{ province: '上海市', city: '上海市', district: '青浦区', longitude: 121.124, latitude: 31.150 },
{ province: '上海市', city: '上海市', district: '奉贤区', longitude: 121.474, latitude: 30.918 },
{ province: '上海市', city: '上海市', district: '崇明区', longitude: 121.397, latitude: 31.623 },
// ========== 天津市 ==========
{ province: '天津市', city: '天津市', district: '和平区', longitude: 117.215, latitude: 39.117 },
{ province: '天津市', city: '天津市', district: '河东区', longitude: 117.252, latitude: 39.128 },
{ province: '天津市', city: '天津市', district: '河西区', longitude: 117.223, latitude: 39.110 },
{ province: '天津市', city: '天津市', district: '南开区', longitude: 117.151, latitude: 39.122 },
{ province: '天津市', city: '天津市', district: '河北区', longitude: 117.197, latitude: 39.148 },
{ province: '天津市', city: '天津市', district: '红桥区', longitude: 117.152, latitude: 39.167 },
{ province: '天津市', city: '天津市', district: '东丽区', longitude: 117.314, latitude: 39.087 },
{ province: '天津市', city: '天津市', district: '西青区', longitude: 117.009, latitude: 39.141 },
{ province: '天津市', city: '天津市', district: '津南区', longitude: 117.357, latitude: 38.938 },
{ province: '天津市', city: '天津市', district: '北辰区', longitude: 117.135, latitude: 39.225 },
{ province: '天津市', city: '天津市', district: '武清区', longitude: 117.044, latitude: 39.384 },
{ province: '天津市', city: '天津市', district: '宝坻区', longitude: 117.310, latitude: 39.717 },
{ province: '天津市', city: '天津市', district: '滨海新区', longitude: 117.694, latitude: 39.013 },
{ province: '天津市', city: '天津市', district: '宁河区', longitude: 117.826, latitude: 39.330 },
{ province: '天津市', city: '天津市', district: '静海区', longitude: 116.974, latitude: 38.947 },
{ province: '天津市', city: '天津市', district: '蓟州区', longitude: 117.408, latitude: 40.046 },
// ========== 重庆市 ==========
{ province: '重庆市', city: '重庆市', district: '渝中区', longitude: 106.569, latitude: 29.553 },
{ province: '重庆市', city: '重庆市', district: '江北区', longitude: 106.574, latitude: 29.606 },
{ province: '重庆市', city: '重庆市', district: '南岸区', longitude: 106.644, latitude: 29.500 },
{ province: '重庆市', city: '重庆市', district: '沙坪坝区', longitude: 106.458, latitude: 29.541 },
{ province: '重庆市', city: '重庆市', district: '九龙坡区', longitude: 106.511, latitude: 29.502 },
{ province: '重庆市', city: '重庆市', district: '大渡口区', longitude: 106.482, latitude: 29.485 },
{ province: '重庆市', city: '重庆市', district: '渝北区', longitude: 106.631, latitude: 29.718 },
{ province: '重庆市', city: '重庆市', district: '巴南区', longitude: 106.540, latitude: 29.402 },
{ province: '重庆市', city: '重庆市', district: '北碚区', longitude: 106.396, latitude: 29.805 },
{ province: '重庆市', city: '重庆市', district: '万州区', longitude: 108.409, latitude: 30.808 },
{ province: '重庆市', city: '重庆市', district: '涪陵区', longitude: 107.390, latitude: 29.703 },
{ province: '重庆市', city: '重庆市', district: '黔江区', longitude: 108.771, latitude: 29.534 },
{ province: '重庆市', city: '重庆市', district: '长寿区', longitude: 107.081, latitude: 29.858 },
{ province: '重庆市', city: '重庆市', district: '江津区', longitude: 106.259, latitude: 29.290 },
{ province: '重庆市', city: '重庆市', district: '合川区', longitude: 106.276, latitude: 29.973 },
{ province: '重庆市', city: '重庆市', district: '永川区', longitude: 105.927, latitude: 29.356 },
{ province: '重庆市', city: '重庆市', district: '南川区', longitude: 107.099, latitude: 29.158 },
{ province: '重庆市', city: '重庆市', district: '璧山区', longitude: 106.231, latitude: 29.592 },
{ province: '重庆市', city: '重庆市', district: '铜梁区', longitude: 106.057, latitude: 29.845 },
{ province: '重庆市', city: '重庆市', district: '潼南区', longitude: 105.840, latitude: 30.191 },
{ province: '重庆市', city: '重庆市', district: '荣昌区', longitude: 105.594, latitude: 29.405 },
{ province: '重庆市', city: '重庆市', district: '开州区', longitude: 108.393, latitude: 31.161 },
{ province: '重庆市', city: '重庆市', district: '梁平区', longitude: 107.802, latitude: 30.674 },
{ province: '重庆市', city: '重庆市', district: '武隆区', longitude: 107.760, latitude: 29.326 },
// ========== 广东省 ==========
// 广州市
{ province: '广东省', city: '广州市', district: '越秀区', longitude: 113.267, latitude: 23.128 },
{ province: '广东省', city: '广州市', district: '荔湾区', longitude: 113.244, latitude: 23.126 },
{ province: '广东省', city: '广州市', district: '海珠区', longitude: 113.258, latitude: 23.084 },
{ province: '广东省', city: '广州市', district: '天河区', longitude: 113.362, latitude: 23.125 },
{ province: '广东省', city: '广州市', district: '白云区', longitude: 113.273, latitude: 23.157 },
{ province: '广东省', city: '广州市', district: '黄埔区', longitude: 113.480, latitude: 23.181 },
{ province: '广东省', city: '广州市', district: '番禺区', longitude: 113.384, latitude: 22.938 },
{ province: '广东省', city: '广州市', district: '花都区', longitude: 113.220, latitude: 23.404 },
{ province: '广东省', city: '广州市', district: '南沙区', longitude: 113.525, latitude: 22.801 },
{ province: '广东省', city: '广州市', district: '从化区', longitude: 113.587, latitude: 23.548 },
{ province: '广东省', city: '广州市', district: '增城区', longitude: 113.811, latitude: 23.261 },
// 深圳市
{ province: '广东省', city: '深圳市', district: '福田区', longitude: 114.055, latitude: 22.521 },
{ province: '广东省', city: '深圳市', district: '罗湖区', longitude: 114.131, latitude: 22.548 },
{ province: '广东省', city: '深圳市', district: '南山区', longitude: 113.930, latitude: 22.533 },
{ province: '广东省', city: '深圳市', district: '盐田区', longitude: 114.237, latitude: 22.557 },
{ province: '广东省', city: '深圳市', district: '宝安区', longitude: 113.883, latitude: 22.555 },
{ province: '广东省', city: '深圳市', district: '龙岗区', longitude: 114.248, latitude: 22.721 },
{ province: '广东省', city: '深圳市', district: '龙华区', longitude: 114.035, latitude: 22.720 },
{ province: '广东省', city: '深圳市', district: '坪山区', longitude: 114.346, latitude: 22.709 },
{ province: '广东省', city: '深圳市', district: '光明区', longitude: 113.936, latitude: 22.748 },
// 珠海市
{ province: '广东省', city: '珠海市', district: '香洲区', longitude: 113.544, latitude: 22.266 },
{ province: '广东省', city: '珠海市', district: '斗门区', longitude: 113.296, latitude: 22.209 },
{ province: '广东省', city: '珠海市', district: '金湾区', longitude: 113.363, latitude: 22.147 },
// 佛山市
{ province: '广东省', city: '佛山市', district: '禅城区', longitude: 113.122, latitude: 23.009 },
{ province: '广东省', city: '佛山市', district: '南海区', longitude: 113.143, latitude: 23.029 },
{ province: '广东省', city: '佛山市', district: '顺德区', longitude: 113.293, latitude: 22.805 },
{ province: '广东省', city: '佛山市', district: '三水区', longitude: 112.897, latitude: 23.156 },
{ province: '广东省', city: '佛山市', district: '高明区', longitude: 112.893, latitude: 22.900 },
// 东莞市
{ province: '广东省', city: '东莞市', district: '莞城区', longitude: 113.751, latitude: 23.053 },
// 中山市
{ province: '广东省', city: '中山市', district: '中山市', longitude: 113.383, latitude: 22.521 },
// 惠州市
{ province: '广东省', city: '惠州市', district: '惠城区', longitude: 114.383, latitude: 23.084 },
{ province: '广东省', city: '惠州市', district: '惠阳区', longitude: 114.456, latitude: 22.789 },
// 汕头市
{ province: '广东省', city: '汕头市', district: '金平区', longitude: 116.703, latitude: 23.366 },
{ province: '广东省', city: '汕头市', district: '龙湖区', longitude: 116.716, latitude: 23.372 },
// ========== 浙江省 ==========
// 杭州市
{ province: '浙江省', city: '杭州市', district: '上城区', longitude: 120.170, latitude: 30.243 },
{ province: '浙江省', city: '杭州市', district: '拱墅区', longitude: 120.142, latitude: 30.319 },
{ province: '浙江省', city: '杭州市', district: '西湖区', longitude: 120.130, latitude: 30.259 },
{ province: '浙江省', city: '杭州市', district: '滨江区', longitude: 120.212, latitude: 30.208 },
{ province: '浙江省', city: '杭州市', district: '萧山区', longitude: 120.264, latitude: 30.185 },
{ province: '浙江省', city: '杭州市', district: '余杭区', longitude: 120.299, latitude: 30.419 },
{ province: '浙江省', city: '杭州市', district: '临平区', longitude: 120.299, latitude: 30.419 },
{ province: '浙江省', city: '杭州市', district: '钱塘区', longitude: 120.494, latitude: 30.323 },
{ province: '浙江省', city: '杭州市', district: '富阳区', longitude: 119.960, latitude: 30.049 },
{ province: '浙江省', city: '杭州市', district: '临安区', longitude: 119.725, latitude: 30.234 },
// 宁波市
{ province: '浙江省', city: '宁波市', district: '海曙区', longitude: 121.551, latitude: 29.860 },
{ province: '浙江省', city: '宁波市', district: '江北区', longitude: 121.555, latitude: 29.887 },
{ province: '浙江省', city: '宁波市', district: '鄞州区', longitude: 121.547, latitude: 29.817 },
{ province: '浙江省', city: '宁波市', district: '镇海区', longitude: 121.597, latitude: 29.949 },
{ province: '浙江省', city: '宁波市', district: '北仑区', longitude: 121.844, latitude: 29.899 },
// 温州市
{ province: '浙江省', city: '温州市', district: '鹿城区', longitude: 120.655, latitude: 28.015 },
{ province: '浙江省', city: '温州市', district: '龙湾区', longitude: 120.811, latitude: 27.933 },
{ province: '浙江省', city: '温州市', district: '瓯海区', longitude: 120.615, latitude: 27.967 },
// 绍兴市
{ province: '浙江省', city: '绍兴市', district: '越城区', longitude: 120.582, latitude: 29.989 },
{ province: '浙江省', city: '绍兴市', district: '柯桥区', longitude: 120.495, latitude: 30.082 },
// 嘉兴市
{ province: '浙江省', city: '嘉兴市', district: '南湖区', longitude: 120.783, latitude: 30.749 },
{ province: '浙江省', city: '嘉兴市', district: '秀洲区', longitude: 120.709, latitude: 30.765 },
// ========== 江苏省 ==========
// 南京市
{ province: '江苏省', city: '南京市', district: '玄武区', longitude: 118.798, latitude: 32.049 },
{ province: '江苏省', city: '南京市', district: '秦淮区', longitude: 118.795, latitude: 32.039 },
{ province: '江苏省', city: '南京市', district: '建邺区', longitude: 118.732, latitude: 32.003 },
{ province: '江苏省', city: '南京市', district: '鼓楼区', longitude: 118.770, latitude: 32.066 },
{ province: '江苏省', city: '南京市', district: '浦口区', longitude: 118.628, latitude: 32.059 },
{ province: '江苏省', city: '南京市', district: '栖霞区', longitude: 118.909, latitude: 32.096 },
{ province: '江苏省', city: '南京市', district: '雨花台区', longitude: 118.779, latitude: 31.991 },
{ province: '江苏省', city: '南京市', district: '江宁区', longitude: 118.840, latitude: 31.953 },
{ province: '江苏省', city: '南京市', district: '六合区', longitude: 118.822, latitude: 32.323 },
{ province: '江苏省', city: '南京市', district: '溧水区', longitude: 119.028, latitude: 31.651 },
{ province: '江苏省', city: '南京市', district: '高淳区', longitude: 118.892, latitude: 31.328 },
// 苏州市
{ province: '江苏省', city: '苏州市', district: '姑苏区', longitude: 120.617, latitude: 31.336 },
{ province: '江苏省', city: '苏州市', district: '虎丘区', longitude: 120.572, latitude: 31.295 },
{ province: '江苏省', city: '苏州市', district: '吴中区', longitude: 120.632, latitude: 31.263 },
{ province: '江苏省', city: '苏州市', district: '相城区', longitude: 120.642, latitude: 31.369 },
{ province: '江苏省', city: '苏州市', district: '吴江区', longitude: 120.645, latitude: 31.138 },
{ province: '江苏省', city: '苏州市', district: '常熟市', longitude: 120.752, latitude: 31.654 },
{ province: '江苏省', city: '苏州市', district: '张家港市', longitude: 120.556, latitude: 31.875 },
{ province: '江苏省', city: '苏州市', district: '昆山市', longitude: 120.981, latitude: 31.385 },
{ province: '江苏省', city: '苏州市', district: '太仓市', longitude: 121.130, latitude: 31.458 },
// 无锡市
{ province: '江苏省', city: '无锡市', district: '梁溪区', longitude: 120.303, latitude: 31.566 },
{ province: '江苏省', city: '无锡市', district: '锡山区', longitude: 120.358, latitude: 31.590 },
{ province: '江苏省', city: '无锡市', district: '惠山区', longitude: 120.298, latitude: 31.681 },
{ province: '江苏省', city: '无锡市', district: '滨湖区', longitude: 120.283, latitude: 31.527 },
{ province: '江苏省', city: '无锡市', district: '新吴区', longitude: 120.364, latitude: 31.491 },
// 常州市
{ province: '江苏省', city: '常州市', district: '天宁区', longitude: 119.975, latitude: 31.780 },
{ province: '江苏省', city: '常州市', district: '钟楼区', longitude: 119.902, latitude: 31.802 },
{ province: '江苏省', city: '常州市', district: '新北区', longitude: 119.972, latitude: 31.831 },
{ province: '江苏省', city: '常州市', district: '武进区', longitude: 119.943, latitude: 31.701 },
// 南通市
{ province: '江苏省', city: '南通市', district: '崇川区', longitude: 120.857, latitude: 32.010 },
{ province: '江苏省', city: '南通市', district: '通州区', longitude: 121.073, latitude: 32.065 },
// 徐州市
{ province: '江苏省', city: '徐州市', district: '鼓楼区', longitude: 117.186, latitude: 34.289 },
{ province: '江苏省', city: '徐州市', district: '云龙区', longitude: 117.251, latitude: 34.253 },
{ province: '江苏省', city: '徐州市', district: '泉山区', longitude: 117.194, latitude: 34.244 },
// ========== 四川省 ==========
// 成都市
{ province: '四川省', city: '成都市', district: '锦江区', longitude: 104.081, latitude: 30.655 },
{ province: '四川省', city: '成都市', district: '青羊区', longitude: 104.062, latitude: 30.674 },
{ province: '四川省', city: '成都市', district: '金牛区', longitude: 104.052, latitude: 30.691 },
{ province: '四川省', city: '成都市', district: '武侯区', longitude: 104.043, latitude: 30.642 },
{ province: '四川省', city: '成都市', district: '成华区', longitude: 104.101, latitude: 30.660 },
{ province: '四川省', city: '成都市', district: '龙泉驿区', longitude: 104.275, latitude: 30.557 },
{ province: '四川省', city: '成都市', district: '青白江区', longitude: 104.251, latitude: 30.879 },
{ province: '四川省', city: '成都市', district: '新都区', longitude: 104.159, latitude: 30.824 },
{ province: '四川省', city: '成都市', district: '温江区', longitude: 103.857, latitude: 30.682 },
{ province: '四川省', city: '成都市', district: '双流区', longitude: 103.924, latitude: 30.574 },
{ province: '四川省', city: '成都市', district: '郫都区', longitude: 103.901, latitude: 30.796 },
{ province: '四川省', city: '成都市', district: '新津区', longitude: 103.811, latitude: 30.410 },
// 绵阳市
{ province: '四川省', city: '绵阳市', district: '涪城区', longitude: 104.757, latitude: 31.455 },
{ province: '四川省', city: '绵阳市', district: '游仙区', longitude: 104.750, latitude: 31.474 },
// ========== 湖北省 ==========
// 武汉市
{ province: '湖北省', city: '武汉市', district: '江岸区', longitude: 114.309, latitude: 30.600 },
{ province: '湖北省', city: '武汉市', district: '江汉区', longitude: 114.271, latitude: 30.601 },
{ province: '湖北省', city: '武汉市', district: '硚口区', longitude: 114.264, latitude: 30.571 },
{ province: '湖北省', city: '武汉市', district: '汉阳区', longitude: 114.219, latitude: 30.545 },
{ province: '湖北省', city: '武汉市', district: '武昌区', longitude: 114.316, latitude: 30.554 },
{ province: '湖北省', city: '武汉市', district: '青山区', longitude: 114.385, latitude: 30.640 },
{ province: '湖北省', city: '武汉市', district: '洪山区', longitude: 114.343, latitude: 30.500 },
{ province: '湖北省', city: '武汉市', district: '东西湖区', longitude: 114.137, latitude: 30.620 },
{ province: '湖北省', city: '武汉市', district: '汉南区', longitude: 114.084, latitude: 30.309 },
{ province: '湖北省', city: '武汉市', district: '蔡甸区', longitude: 114.029, latitude: 30.582 },
{ province: '湖北省', city: '武汉市', district: '江夏区', longitude: 114.321, latitude: 30.376 },
{ province: '湖北省', city: '武汉市', district: '黄陂区', longitude: 114.376, latitude: 30.882 },
{ province: '湖北省', city: '武汉市', district: '新洲区', longitude: 114.801, latitude: 30.842 },
// 襄阳市
{ province: '湖北省', city: '襄阳市', district: '襄城区', longitude: 112.134, latitude: 32.010 },
{ province: '湖北省', city: '襄阳市', district: '樊城区', longitude: 112.136, latitude: 32.045 },
// ========== 湖南省 ==========
// 长沙市
{ province: '湖南省', city: '长沙市', district: '芙蓉区', longitude: 113.033, latitude: 28.185 },
{ province: '湖南省', city: '长沙市', district: '天心区', longitude: 112.990, latitude: 28.114 },
{ province: '湖南省', city: '长沙市', district: '岳麓区', longitude: 112.931, latitude: 28.235 },
{ province: '湖南省', city: '长沙市', district: '开福区', longitude: 112.986, latitude: 28.256 },
{ province: '湖南省', city: '长沙市', district: '雨花区', longitude: 113.038, latitude: 28.136 },
{ province: '湖南省', city: '长沙市', district: '望城区', longitude: 112.817, latitude: 28.347 },
{ province: '湖南省', city: '长沙市', district: '浏阳市', longitude: 113.643, latitude: 28.163 },
// ========== 福建省 ==========
// 福州市
{ province: '福建省', city: '福州市', district: '鼓楼区', longitude: 119.304, latitude: 26.082 },
{ province: '福建省', city: '福州市', district: '台江区', longitude: 119.314, latitude: 26.053 },
{ province: '福建省', city: '福州市', district: '仓山区', longitude: 119.273, latitude: 26.047 },
{ province: '福建省', city: '福州市', district: '马尾区', longitude: 119.456, latitude: 25.990 },
{ province: '福建省', city: '福州市', district: '晋安区', longitude: 119.328, latitude: 26.082 },
// 厦门市
{ province: '福建省', city: '厦门市', district: '思明区', longitude: 118.087, latitude: 24.445 },
{ province: '福建省', city: '厦门市', district: '海沧区', longitude: 118.033, latitude: 24.485 },
{ province: '福建省', city: '厦门市', district: '湖里区', longitude: 118.147, latitude: 24.513 },
{ province: '福建省', city: '厦门市', district: '集美区', longitude: 118.097, latitude: 24.576 },
{ province: '福建省', city: '厦门市', district: '同安区', longitude: 118.150, latitude: 24.723 },
{ province: '福建省', city: '厦门市', district: '翔安区', longitude: 118.248, latitude: 24.619 },
// 泉州市
{ province: '福建省', city: '泉州市', district: '鲤城区', longitude: 118.587, latitude: 24.908 },
{ province: '福建省', city: '泉州市', district: '丰泽区', longitude: 118.613, latitude: 24.891 },
// ========== 山东省 ==========
// 济南市
{ province: '山东省', city: '济南市', district: '历下区', longitude: 117.077, latitude: 36.666 },
{ province: '山东省', city: '济南市', district: '市中区', longitude: 116.998, latitude: 36.645 },
{ province: '山东省', city: '济南市', district: '槐荫区', longitude: 116.901, latitude: 36.651 },
{ province: '山东省', city: '济南市', district: '天桥区', longitude: 116.987, latitude: 36.678 },
{ province: '山东省', city: '济南市', district: '历城区', longitude: 117.065, latitude: 36.680 },
{ province: '山东省', city: '济南市', district: '长清区', longitude: 116.752, latitude: 36.554 },
{ province: '山东省', city: '济南市', district: '章丘区', longitude: 117.484, latitude: 36.680 },
// 青岛市
{ province: '山东省', city: '青岛市', district: '市南区', longitude: 120.413, latitude: 36.075 },
{ province: '山东省', city: '青岛市', district: '市北区', longitude: 120.356, latitude: 36.087 },
{ province: '山东省', city: '青岛市', district: '李沧区', longitude: 120.433, latitude: 36.145 },
{ province: '山东省', city: '青岛市', district: '崂山区', longitude: 120.469, latitude: 36.107 },
{ province: '山东省', city: '青岛市', district: '黄岛区', longitude: 120.198, latitude: 35.961 },
{ province: '山东省', city: '青岛市', district: '城阳区', longitude: 120.396, latitude: 36.307 },
{ province: '山东省', city: '青岛市', district: '即墨区', longitude: 120.447, latitude: 36.389 },
// 烟台市
{ province: '山东省', city: '烟台市', district: '芝罘区', longitude: 121.400, latitude: 37.541 },
{ province: '山东省', city: '烟台市', district: '莱山区', longitude: 121.445, latitude: 37.511 },
// ========== 河南省 ==========
// 郑州市
{ province: '河南省', city: '郑州市', district: '中原区', longitude: 113.613, latitude: 34.748 },
{ province: '河南省', city: '郑州市', district: '二七区', longitude: 113.674, latitude: 34.724 },
{ province: '河南省', city: '郑州市', district: '管城区', longitude: 113.677, latitude: 34.754 },
{ province: '河南省', city: '郑州市', district: '金水区', longitude: 113.661, latitude: 34.800 },
{ province: '河南省', city: '郑州市', district: '惠济区', longitude: 113.617, latitude: 34.867 },
{ province: '河南省', city: '郑州市', district: '上街区', longitude: 113.309, latitude: 34.803 },
{ province: '河南省', city: '郑州市', district: '郑东新区', longitude: 113.729, latitude: 34.764 },
// 洛阳市
{ province: '河南省', city: '洛阳市', district: '老城区', longitude: 112.469, latitude: 34.683 },
{ province: '河南省', city: '洛阳市', district: '西工区', longitude: 112.428, latitude: 34.660 },
{ province: '河南省', city: '洛阳市', district: '涧西区', longitude: 112.396, latitude: 34.658 },
{ province: '河南省', city: '洛阳市', district: '洛龙区', longitude: 112.464, latitude: 34.619 },
// ========== 辽宁省 ==========
// 沈阳市
{ province: '辽宁省', city: '沈阳市', district: '和平区', longitude: 123.420, latitude: 41.790 },
{ province: '辽宁省', city: '沈阳市', district: '沈河区', longitude: 123.459, latitude: 41.796 },
{ province: '辽宁省', city: '沈阳市', district: '大东区', longitude: 123.470, latitude: 41.805 },
{ province: '辽宁省', city: '沈阳市', district: '皇姑区', longitude: 123.442, latitude: 41.825 },
{ province: '辽宁省', city: '沈阳市', district: '铁西区', longitude: 123.377, latitude: 41.803 },
{ province: '辽宁省', city: '沈阳市', district: '浑南区', longitude: 123.450, latitude: 41.715 },
{ province: '辽宁省', city: '沈阳市', district: '沈北新区', longitude: 123.431, latitude: 41.912 },
{ province: '辽宁省', city: '沈阳市', district: '于洪区', longitude: 123.308, latitude: 41.794 },
// 大连市
{ province: '辽宁省', city: '大连市', district: '中山区', longitude: 121.645, latitude: 38.919 },
{ province: '辽宁省', city: '大连市', district: '西岗区', longitude: 121.612, latitude: 38.915 },
{ province: '辽宁省', city: '大连市', district: '沙河口区', longitude: 121.594, latitude: 38.905 },
{ province: '辽宁省', city: '大连市', district: '甘井子区', longitude: 121.526, latitude: 38.953 },
{ province: '辽宁省', city: '大连市', district: '旅顺口区', longitude: 121.262, latitude: 38.851 },
{ province: '辽宁省', city: '大连市', district: '金州区', longitude: 121.719, latitude: 39.100 },
// ========== 陕西省 ==========
// 西安市
{ province: '陕西省', city: '西安市', district: '新城区', longitude: 108.961, latitude: 34.267 },
{ province: '陕西省', city: '西安市', district: '碑林区', longitude: 108.934, latitude: 34.230 },
{ province: '陕西省', city: '西安市', district: '莲湖区', longitude: 108.944, latitude: 34.265 },
{ province: '陕西省', city: '西安市', district: '灞桥区', longitude: 109.064, latitude: 34.273 },
{ province: '陕西省', city: '西安市', district: '未央区', longitude: 108.947, latitude: 34.293 },
{ province: '陕西省', city: '西安市', district: '雁塔区', longitude: 108.949, latitude: 34.223 },
{ province: '陕西省', city: '西安市', district: '长安区', longitude: 108.907, latitude: 34.159 },
{ province: '陕西省', city: '西安市', district: '高陵区', longitude: 109.088, latitude: 34.535 },
// ========== 云南省 ==========
// 昆明市
{ province: '云南省', city: '昆明市', district: '五华区', longitude: 102.707, latitude: 25.044 },
{ province: '云南省', city: '昆明市', district: '盘龙区', longitude: 102.752, latitude: 25.116 },
{ province: '云南省', city: '昆明市', district: '官渡区', longitude: 102.744, latitude: 25.015 },
{ province: '云南省', city: '昆明市', district: '西山区', longitude: 102.664, latitude: 25.038 },
{ province: '云南省', city: '昆明市', district: '呈贡区', longitude: 102.822, latitude: 24.886 },
// ========== 安徽省 ==========
// 合肥市
{ province: '安徽省', city: '合肥市', district: '瑶海区', longitude: 117.309, latitude: 31.858 },
{ province: '安徽省', city: '合肥市', district: '庐阳区', longitude: 117.265, latitude: 31.879 },
{ province: '安徽省', city: '合肥市', district: '蜀山区', longitude: 117.261, latitude: 31.851 },
{ province: '安徽省', city: '合肥市', district: '包河区', longitude: 117.310, latitude: 31.795 },
{ province: '安徽省', city: '合肥市', district: '肥西县', longitude: 117.158, latitude: 31.707 },
{ province: '安徽省', city: '合肥市', district: '肥东县', longitude: 117.469, latitude: 31.888 },
{ province: '安徽省', city: '合肥市', district: '长丰县', longitude: 117.168, latitude: 32.478 },
// ========== 广西壮族自治区 ==========
// 南宁市
{ province: '广西壮族自治区', city: '南宁市', district: '兴宁区', longitude: 108.369, latitude: 22.854 },
{ province: '广西壮族自治区', city: '南宁市', district: '青秀区', longitude: 108.494, latitude: 22.785 },
{ province: '广西壮族自治区', city: '南宁市', district: '江南区', longitude: 108.273, latitude: 22.781 },
{ province: '广西壮族自治区', city: '南宁市', district: '西乡塘区', longitude: 108.307, latitude: 22.833 },
{ province: '广西壮族自治区', city: '南宁市', district: '良庆区', longitude: 108.322, latitude: 22.759 },
// ========== 江西省 ==========
// 南昌市
{ province: '江西省', city: '南昌市', district: '东湖区', longitude: 115.899, latitude: 28.685 },
{ province: '江西省', city: '南昌市', district: '西湖区', longitude: 115.877, latitude: 28.657 },
{ province: '江西省', city: '南昌市', district: '青云谱区', longitude: 115.926, latitude: 28.621 },
{ province: '江西省', city: '南昌市', district: '青山湖区', longitude: 115.962, latitude: 28.682 },
{ province: '江西省', city: '南昌市', district: '红谷滩区', longitude: 115.861, latitude: 28.698 },
// ========== 贵州省 ==========
// 贵阳市
{ province: '贵州省', city: '贵阳市', district: '南明区', longitude: 106.714, latitude: 26.568 },
{ province: '贵州省', city: '贵阳市', district: '云岩区', longitude: 106.725, latitude: 26.605 },
{ province: '贵州省', city: '贵阳市', district: '花溪区', longitude: 106.670, latitude: 26.410 },
{ province: '贵州省', city: '贵阳市', district: '乌当区', longitude: 106.751, latitude: 26.631 },
{ province: '贵州省', city: '贵阳市', district: '观山湖区', longitude: 106.622, latitude: 26.601 },
// ========== 河北省 ==========
// 石家庄市
{ province: '河北省', city: '石家庄市', district: '长安区', longitude: 114.539, latitude: 38.037 },
{ province: '河北省', city: '石家庄市', district: '桥西区', longitude: 114.461, latitude: 38.004 },
{ province: '河北省', city: '石家庄市', district: '新华区', longitude: 114.463, latitude: 38.051 },
{ province: '河北省', city: '石家庄市', district: '裕华区', longitude: 114.531, latitude: 38.006 },
{ province: '河北省', city: '石家庄市', district: '藁城区', longitude: 114.847, latitude: 38.022 },
// 唐山市
{ province: '河北省', city: '唐山市', district: '路南区', longitude: 118.154, latitude: 39.625 },
{ province: '河北省', city: '唐山市', district: '路北区', longitude: 118.181, latitude: 39.625 },
// ========== 山西省 ==========
// 太原市
{ province: '山西省', city: '太原市', district: '小店区', longitude: 112.565, latitude: 37.736 },
{ province: '山西省', city: '太原市', district: '迎泽区', longitude: 112.563, latitude: 37.863 },
{ province: '山西省', city: '太原市', district: '杏花岭区', longitude: 112.562, latitude: 37.884 },
{ province: '山西省', city: '太原市', district: '尖草坪区', longitude: 112.487, latitude: 37.940 },
{ province: '山西省', city: '太原市', district: '万柏林区', longitude: 112.516, latitude: 37.859 },
// ========== 海南省 ==========
// 海口市
{ province: '海南省', city: '海口市', district: '秀英区', longitude: 110.294, latitude: 20.008 },
{ province: '海南省', city: '海口市', district: '龙华区', longitude: 110.329, latitude: 20.031 },
{ province: '海南省', city: '海口市', district: '琼山区', longitude: 110.354, latitude: 20.003 },
{ province: '海南省', city: '海口市', district: '美兰区', longitude: 110.366, latitude: 20.029 },
// 三亚市
{ province: '海南省', city: '三亚市', district: '海棠区', longitude: 109.753, latitude: 18.400 },
{ province: '海南省', city: '三亚市', district: '吉阳区', longitude: 109.578, latitude: 18.281 },
{ province: '海南省', city: '三亚市', district: '天涯区', longitude: 109.452, latitude: 18.299 },
{ province: '海南省', city: '三亚市', district: '崖州区', longitude: 109.172, latitude: 18.357 },
// ========== 香港特别行政区 ==========
{ province: '香港特别行政区', city: '香港', district: '中西区', longitude: 114.154, latitude: 22.282 },
{ province: '香港特别行政区', city: '香港', district: '湾仔区', longitude: 114.183, latitude: 22.276 },
{ province: '香港特别行政区', city: '香港', district: '东区', longitude: 114.226, latitude: 22.279 },
{ province: '香港特别行政区', city: '香港', district: '南区', longitude: 114.174, latitude: 22.247 },
{ province: '香港特别行政区', city: '香港', district: '油尖旺区', longitude: 114.173, latitude: 22.312 },
{ province: '香港特别行政区', city: '香港', district: '深水埗区', longitude: 114.163, latitude: 22.332 },
{ province: '香港特别行政区', city: '香港', district: '九龙城区', longitude: 114.193, latitude: 22.312 },
{ province: '香港特别行政区', city: '香港', district: '黄大仙区', longitude: 114.207, latitude: 22.336 },
{ province: '香港特别行政区', city: '香港', district: '观塘区', longitude: 114.232, latitude: 22.309 },
{ province: '香港特别行政区', city: '香港', district: '荃湾区', longitude: 114.121, latitude: 22.369 },
{ province: '香港特别行政区', city: '香港', district: '屯门区', longitude: 113.977, latitude: 22.393 },
{ province: '香港特别行政区', city: '香港', district: '元朗区', longitude: 114.032, latitude: 22.443 },
{ province: '香港特别行政区', city: '香港', district: '北区', longitude: 114.149, latitude: 22.494 },
{ province: '香港特别行政区', city: '香港', district: '大埔区', longitude: 114.172, latitude: 22.455 },
{ province: '香港特别行政区', city: '香港', district: '西贡区', longitude: 114.275, latitude: 22.317 },
{ province: '香港特别行政区', city: '香港', district: '沙田区', longitude: 114.192, latitude: 22.379 },
{ province: '香港特别行政区', city: '香港', district: '离岛区', longitude: 113.946, latitude: 22.286 },
// ========== 澳门特别行政区 ==========
{ province: '澳门特别行政区', city: '澳门', district: '花地玛堂区', longitude: 113.550, latitude: 22.200 },
{ province: '澳门特别行政区', city: '澳门', district: '花王堂区', longitude: 113.548, latitude: 22.196 },
{ province: '澳门特别行政区', city: '澳门', district: '望德堂区', longitude: 113.550, latitude: 22.193 },
{ province: '澳门特别行政区', city: '澳门', district: '大堂区', longitude: 113.554, latitude: 22.188 },
{ province: '澳门特别行政区', city: '澳门', district: '风顺堂区', longitude: 113.542, latitude: 22.184 },
{ province: '澳门特别行政区', city: '澳门', district: '氹仔', longitude: 113.576, latitude: 22.156 },
{ province: '澳门特别行政区', city: '澳门', district: '路环', longitude: 113.564, latitude: 22.126 },
// ========== 台湾省(主要城市) ==========
{ province: '台湾省', city: '台北市', district: '中正区', longitude: 121.520, latitude: 25.032 },
{ province: '台湾省', city: '台北市', district: '大同区', longitude: 121.513, latitude: 25.063 },
{ province: '台湾省', city: '台北市', district: '中山区', longitude: 121.537, latitude: 25.069 },
{ province: '台湾省', city: '台北市', district: '松山区', longitude: 121.557, latitude: 25.055 },
{ province: '台湾省', city: '台北市', district: '大安区', longitude: 121.544, latitude: 25.030 },
{ province: '台湾省', city: '台北市', district: '万华区', longitude: 121.500, latitude: 25.028 },
{ province: '台湾省', city: '台北市', district: '信义区', longitude: 121.561, latitude: 25.033 },
{ province: '台湾省', city: '台北市', district: '士林区', longitude: 121.525, latitude: 25.095 },
{ province: '台湾省', city: '台北市', district: '北投区', longitude: 121.509, latitude: 25.131 },
{ province: '台湾省', city: '台北市', district: '内湖区', longitude: 121.587, latitude: 25.069 },
{ province: '台湾省', city: '台北市', district: '南港区', longitude: 121.607, latitude: 25.045 },
{ province: '台湾省', city: '台北市', district: '文山区', longitude: 121.579, latitude: 25.001 },
{ province: '台湾省', city: '新北市', district: '板桥区', longitude: 121.459, latitude: 25.013 },
{ province: '台湾省', city: '新北市', district: '三重区', longitude: 121.487, latitude: 25.064 },
{ province: '台湾省', city: '新北市', district: '中和区', longitude: 121.497, latitude: 24.999 },
{ province: '台湾省', city: '新北市', district: '永和区', longitude: 121.513, latitude: 25.008 },
{ province: '台湾省', city: '台中市', district: '中区', longitude: 120.680, latitude: 24.145 },
{ province: '台湾省', city: '高雄市', district: '新兴区', longitude: 120.308, latitude: 22.631 },
{ province: '台湾省', city: '台南市', district: '中西区', longitude: 120.194, latitude: 22.997 },
{ province: '台湾省', city: '桃园市', district: '桃园区', longitude: 121.302, latitude: 24.994 },
]
/**
* 查找城市坐标
*
* 支持多种输入格式:
* - "北京市海淀区" → 精确匹配
* - "海淀区" → 区县名匹配
* - "北京海淀" → 城市+区县模糊匹配
* - "海淀" → 区县关键词匹配
*
* @param query 用户输入的地点名称
* @returns 匹配到的坐标信息和显示名称,未找到返回 null
*/
export function lookupCityCoordinates(query: string): {
longitude: number
latitude: number
displayName: string
} | null {
if (!query || !query.trim()) return null
const cleaned = query.trim()
// 1. 精确匹配:完整名称(如"北京市海淀区")
const exactMatch = DISTRICT_DATABASE.find(
(entry) => `${entry.province}${entry.city}${entry.district}` === cleaned
|| `${entry.city}${entry.district}` === cleaned
|| `${entry.province}${entry.district}` === cleaned,
)
if (exactMatch) {
return {
longitude: exactMatch.longitude,
latitude: exactMatch.latitude,
displayName: `${exactMatch.province}${exactMatch.district}`,
}
}
// 2. 区县名精确匹配(如"海淀区")
const districtMatch = DISTRICT_DATABASE.find(
(entry) => entry.district === cleaned,
)
if (districtMatch) {
return {
longitude: districtMatch.longitude,
latitude: districtMatch.latitude,
displayName: `${districtMatch.province}${districtMatch.district}`,
}
}
// 3. 去除省市县区后的关键词匹配
const keywords = cleaned
.replace(/省|市|自治区|特别行政区|区|县/g, '')
.trim()
if (keywords) {
// 按区县名匹配
const keywordDistrictMatch = DISTRICT_DATABASE.find(
(entry) => entry.district.includes(keywords) || keywords.includes(entry.district.replace(/[市区县]/g, '')),
)
if (keywordDistrictMatch) {
return {
longitude: keywordDistrictMatch.longitude,
latitude: keywordDistrictMatch.latitude,
displayName: `${keywordDistrictMatch.province}${keywordDistrictMatch.district}`,
}
}
// 按城市名匹配(降级为城市中心坐标)
const cityMatch = DISTRICT_DATABASE.find(
(entry) => entry.city.includes(keywords) || keywords.includes(entry.city.replace(/[市区县]/g, '')),
)
if (cityMatch) {
return {
longitude: cityMatch.longitude,
latitude: cityMatch.latitude,
displayName: `${cityMatch.province}${cityMatch.city}`,
}
}
}
return null
}
/**
* 获取所有区县列表,用于搜索建议
*/
export function getAllDistrictNames(): string[] {
return DISTRICT_DATABASE.map(
(entry) => `${entry.province}${entry.district}`,
)
}
@@ -30,11 +30,9 @@ export default {
birthHour: 'Geburtsstunde',
gender: 'Geschlecht',
birthPlace: 'Geburtsort',
birthPlaceHint: 'z.B. Berlin',
longitude: 'Längengrad',
longitudeHint: 'z.B. 13.4',
latitude: 'Breitengrad',
latitudeHint: 'z.B. 52.5',
birthPlaceHint: 'z.B. Haidian, Peking',
locationNotFound: 'Ort nicht gefunden. Bitte geben Sie den Bezirk an',
lookingUp: 'Suche…',
pleaseSelect: 'Bitte auswählen',
generating: 'Diagramm wird erstellt...',
generate: 'Diagramm erstellen',
@@ -30,11 +30,9 @@ export default {
birthHour: 'Birth Hour',
gender: 'Gender',
birthPlace: 'Birth Place',
birthPlaceHint: 'e.g. Beijing',
longitude: 'Longitude',
longitudeHint: 'e.g. 116.4',
latitude: 'Latitude',
latitudeHint: 'e.g. 39.9',
birthPlaceHint: 'e.g. Haidian, Beijing',
locationNotFound: 'Location not found, please be more specific',
lookingUp: 'Looking up…',
pleaseSelect: 'Please select',
generating: 'Generating chart...',
generate: 'Generate Chart',
@@ -30,11 +30,9 @@ export default {
birthHour: 'Hora de nacimiento',
gender: 'Género',
birthPlace: 'Lugar de nacimiento',
birthPlaceHint: 'ej: Madrid',
longitude: 'Longitud',
longitudeHint: 'ej: -3.7',
latitude: 'Latitud',
latitudeHint: 'ej: 40.4',
birthPlaceHint: 'ej: Haidian, Pekín',
locationNotFound: 'Ubicación no encontrada. Sea más específico',
lookingUp: 'Buscando…',
pleaseSelect: 'Seleccione',
generating: 'Generando carta...',
generate: 'Generar carta',
@@ -30,11 +30,9 @@ export default {
birthHour: 'Heure de naissance',
gender: 'Sexe',
birthPlace: 'Lieu de naissance',
birthPlaceHint: 'ex: Paris',
longitude: 'Longitude',
longitudeHint: 'ex: 2.3',
latitude: 'Latitude',
latitudeHint: 'ex: 48.9',
birthPlaceHint: 'ex: Haidian, Pékin',
locationNotFound: 'Lieu introuvable. Veuillez préciser le district',
lookingUp: 'Recherche…',
pleaseSelect: 'Veuillez sélectionner',
generating: 'Génération du diagramme...',
generate: 'Générer le diagramme',
@@ -30,11 +30,9 @@ export default {
birthHour: '出生時辰',
gender: '性別',
birthPlace: '出生地',
birthPlaceHint: '例:東京都',
longitude: '経度',
longitudeHint: '例:139.7',
latitude: '緯度',
latitudeHint: '例:35.7',
birthPlaceHint: '例:東京都千代田区',
locationNotFound: '場所が見つかりません。市区町村まで入力してください',
lookingUp: '検索中…',
pleaseSelect: '選択してください',
generating: '排盤中...',
generate: '排盤',
@@ -30,11 +30,9 @@ export default {
birthHour: '출생 시진',
gender: '성별',
birthPlace: '출생지',
birthPlaceHint: '예: 서울특별시',
longitude: '경도',
longitudeHint: '예: 127.0',
latitude: '위도',
latitudeHint: '예: 37.6',
birthPlaceHint: '예: 서울특별시 종로구',
locationNotFound: '위치를 찾을 수 없습니다. 시군구까지 입력해주세요',
lookingUp: '위치 확인 중…',
pleaseSelect: '선택하세요',
generating: '명반 생성 중...',
generate: '명반 생성',
@@ -30,11 +30,9 @@ export default {
birthHour: 'Hora de nascimento',
gender: 'Gênero',
birthPlace: 'Local de nascimento',
birthPlaceHint: 'ex: São Paulo',
longitude: 'Longitude',
longitudeHint: 'ex: -46.6',
latitude: 'Latitude',
latitudeHint: 'ex: -23.5',
birthPlaceHint: 'ex: Haidian, Pequim',
locationNotFound: 'Local não encontrado. Seja mais específico',
lookingUp: 'Procurando…',
pleaseSelect: 'Selecione',
generating: 'Gerando carta...',
generate: 'Gerar carta',
@@ -30,11 +30,9 @@ export default {
birthHour: '出生时辰',
gender: '性别',
birthPlace: '出生地',
birthPlaceHint: '例如:北京市',
longitude: '经度',
longitudeHint: '例如:116.4',
latitude: '纬度',
latitudeHint: '例如:39.9',
birthPlaceHint: '例如:北京市海淀区',
locationNotFound: '未找到该地点,请精确到区县',
lookingUp: '正在定位…',
pleaseSelect: '请选择',
generating: '排盘中...',
generate: '排盘',
@@ -30,11 +30,9 @@ export default {
birthHour: '出生時辰',
gender: '性別',
birthPlace: '出生地',
birthPlaceHint: '例如:台北市',
longitude: '經度',
longitudeHint: '例如:121.5',
latitude: '緯度',
latitudeHint: '例如:25.0',
birthPlaceHint: '例如:台北市中正區',
locationNotFound: '未找到該地點,請精確到區縣',
lookingUp: '正在定位…',
pleaseSelect: '請選擇',
generating: '排盤中...',
generate: '排盤',
@@ -24,16 +24,9 @@
<view class="form-group">
<text class="label">{{ $t('ziwei.birthPlace') }}</text>
<input class="text-input" :value="birthPlace" @input="onBirthPlaceChange" :placeholder="$t('ziwei.birthPlaceHint')" />
</view>
<view class="form-row">
<view class="form-group form-half">
<text class="label">{{ $t('ziwei.longitude') }}</text>
<input class="text-input" type="digit" :value="longitude" @input="onLongitudeChange" :placeholder="$t('ziwei.longitudeHint')" />
</view>
<view class="form-group form-half">
<text class="label">{{ $t('ziwei.latitude') }}</text>
<input class="text-input" type="digit" :value="latitude" @input="onLatitudeChange" :placeholder="$t('ziwei.latitudeHint')" />
</view>
<text v-if="detectedLocation" class="location-hint detected">{{ detectedLocation }}</text>
<text v-else-if="birthPlace && birthPlace.trim().length > 2 && !isLookingUp" class="location-hint not-found">{{ $t('ziwei.locationNotFound') }}</text>
<text v-if="isLookingUp" class="location-hint looking-up">{{ $t('ziwei.lookingUp') }}</text>
</view>
</view>
@@ -89,6 +82,7 @@ import { onShow } from '@dcloudio/uni-app'
import { ZiweiService } from '../../services/ziweiService'
import { PalaceType, EarthlyBranch, MajorStar } from '../../algorithms/enums'
import type { ZiweiChart } from '../../algorithms/types'
import { lookupCityCoordinates } from '../../data/cityCoordinates'
const ziweiService = new ZiweiService()
const { t } = useI18n()
@@ -101,11 +95,13 @@ const birthDate = ref('')
const hourIndex = ref(0)
const gender = ref<'male' | 'female'>('male')
const birthPlace = ref('')
const longitude = ref('')
const latitude = ref('')
const isCalculating = ref(false)
const isLookingUp = ref(false)
const detectedLocation = ref('')
const chart = ref<ZiweiChart | null>(null)
let lookupTimer: ReturnType<typeof setTimeout> | null = null
const hourOptions = [
'子时 (23:00-01:00)', '丑时 (01:00-03:00)', '寅时 (03:00-05:00)',
'卯时 (05:00-07:00)', '辰时 (07:00-09:00)', '巳时 (09:00-11:00)',
@@ -123,14 +119,28 @@ const onHourChange = (e: any) => {
const onBirthPlaceChange = (e: any) => {
birthPlace.value = e.detail.value
detectedLocation.value = ''
autoLookupCoordinates(birthPlace.value)
}
const onLongitudeChange = (e: any) => {
longitude.value = e.detail.value
}
const onLatitudeChange = (e: any) => {
latitude.value = e.detail.value
/** 自动查找出生地坐标 */
function autoLookupCoordinates(place: string): void {
if (lookupTimer) {
clearTimeout(lookupTimer)
}
if (!place || place.trim().length < 2) {
isLookingUp.value = false
return
}
isLookingUp.value = true
lookupTimer = setTimeout(() => {
const result = lookupCityCoordinates(place)
isLookingUp.value = false
if (result) {
detectedLocation.value = `${result.displayName}${result.longitude}°E, ${result.latitude}°N`
}
lookupTimer = null
}, 500)
}
const getPalaceName = (palaceType: string): string => {
@@ -164,15 +174,25 @@ const generateChart = async () => {
try {
const hour = hourIndex.value * 2
const birthTime = `${birthDate.value}T${String(hour).padStart(2, '0')}:00:00`
const lng = longitude.value ? parseFloat(longitude.value) : undefined
const lat = latitude.value ? parseFloat(latitude.value) : undefined
// 从检测结果中解析经纬度
let longitude: number | undefined
let latitude: number | undefined
if (detectedLocation.value) {
const coordResult = lookupCityCoordinates(birthPlace.value)
if (coordResult) {
longitude = coordResult.longitude
latitude = coordResult.latitude
}
}
chart.value = await ziweiService.generateChart({
birthTime,
gender: gender.value,
timezone: 'Asia/Shanghai',
birthPlace: birthPlace.value || undefined,
longitude: lng,
latitude: lat,
longitude,
latitude,
})
} catch (e) {
console.error('排盘失败:', e)
@@ -245,15 +265,6 @@ const generateChart = async () => {
background-color: rgba(44, 24, 16, 255);
}
.form-row {
display: flex;
gap: 12px;
}
.form-half {
flex: 1;
}
.text-input {
font-size: 15px;
color: #333;
@@ -265,6 +276,24 @@ const generateChart = async () => {
box-sizing: border-box;
}
.location-hint {
font-size: 12px;
margin-top: 4px;
display: block;
}
.location-hint.detected {
color: #52c41a;
}
.location-hint.not-found {
color: #faad14;
}
.location-hint.looking-up {
color: #999;
}
.action-bar {
margin-bottom: 16px;
}