323acbd64cecfbe508024edb96a2135c814a2e0cR1925">1925
+    "410411": "湛河区",
1926
+    "410421": "宝丰县",
1927
+    "410422": "叶县",
1928
+    "410423": "鲁山县",
1929
+    "410425": "郏县",
1930
+    "410481": "舞钢市",
1931
+    "410482": "汝州市"
1932
+  },
1933
+  "410500": {
1934
+    "410502": "文峰区",
1935
+    "410503": "北关区",
1936
+    "410505": "殷都区",
1937
+    "410506": "龙安区",
1938
+    "410522": "安阳县",
1939
+    "410523": "汤阴县",
1940
+    "410526": "滑县",
1941
+    "410527": "内黄县",
1942
+    "410581": "林州市"
1943
+  },
1944
+  "410600": {
1945
+    "410602": "鹤山区",
1946
+    "410603": "山城区",
1947
+    "410611": "淇滨区",
1948
+    "410621": "浚县",
1949
+    "410622": "淇县"
1950
+  },
1951
+  "410700": {
1952
+    "410702": "红旗区",
1953
+    "410703": "卫滨区",
1954
+    "410704": "凤泉区",
1955
+    "410711": "牧野区",
1956
+    "410721": "新乡县",
1957
+    "410724": "获嘉县",
1958
+    "410725": "原阳县",
1959
+    "410726": "延津县",
1960
+    "410727": "封丘县",
1961
+    "410728": "长垣县",
1962
+    "410781": "卫辉市",
1963
+    "410782": "辉县市"
1964
+  },
1965
+  "410800": {
1966
+    "410802": "解放区",
1967
+    "410803": "中站区",
1968
+    "410804": "马村区",
1969
+    "410811": "山阳区",
1970
+    "410821": "修武县",
1971
+    "410822": "博爱县",
1972
+    "410823": "武陟县",
1973
+    "410825": "温县",
1974
+    "410882": "沁阳市",
1975
+    "410883": "孟州市"
1976
+  },
1977
+  "410900": {
1978
+    "410902": "华龙区",
1979
+    "410922": "清丰县",
1980
+    "410923": "南乐县",
1981
+    "410926": "范县",
1982
+    "410927": "台前县",
1983
+    "410928": "濮阳县"
1984
+  },
1985
+  "411000": {
1986
+    "411002": "魏都区",
1987
+    "411023": "许昌县",
1988
+    "411024": "鄢陵县",
1989
+    "411025": "襄城县",
1990
+    "411081": "禹州市",
1991
+    "411082": "长葛市"
1992
+  },
1993
+  "411100": {
1994
+    "411102": "源汇区",
1995
+    "411103": "郾城区",
1996
+    "411104": "召陵区",
1997
+    "411121": "舞阳县",
1998
+    "411122": "临颍县"
1999
+  },
2000
+  "411200": {
2001
+    "411202": "湖滨区",
2002
+    "411203": "陕州区",
2003
+    "411221": "渑池县",
2004
+    "411224": "卢氏县",
2005
+    "411281": "义马市",
2006
+    "411282": "灵宝市"
2007
+  },
2008
+  "411300": {
2009
+    "411302": "宛城区",
2010
+    "411303": "卧龙区",
2011
+    "411321": "南召县",
2012
+    "411322": "方城县",
2013
+    "411323": "西峡县",
2014
+    "411324": "镇平县",
2015
+    "411325": "内乡县",
2016
+    "411326": "淅川县",
2017
+    "411327": "社旗县",
2018
+    "411328": "唐河县",
2019
+    "411329": "新野县",
2020
+    "411330": "桐柏县",
2021
+    "411381": "邓州市"
2022
+  },
2023
+  "411400": {
2024
+    "411402": "梁园区",
2025
+    "411403": "睢阳区",
2026
+    "411421": "民权县",
2027
+    "411422": "睢县",
2028
+    "411423": "宁陵县",
2029
+    "411424": "柘城县",
2030
+    "411425": "虞城县",
2031
+    "411426": "夏邑县",
2032
+    "411481": "永城市"
2033
+  },
2034
+  "411500": {
2035
+    "411502": "浉河区",
2036
+    "411503": "平桥区",
2037
+    "411521": "罗山县",
2038
+    "411522": "光山县",
2039
+    "411523": "新县",
2040
+    "411524": "商城县",
2041
+    "411525": "固始县",
2042
+    "411526": "潢川县",
2043
+    "411527": "淮滨县",
2044
+    "411528": "息县"
2045
+  },
2046
+  "411600": {
2047
+    "411602": "川汇区",
2048
+    "411621": "扶沟县",
2049
+    "411622": "西华县",
2050
+    "411623": "商水县",
2051
+    "411624": "沈丘县",
2052
+    "411625": "郸城县",
2053
+    "411626": "淮阳县",
2054
+    "411627": "太康县",
2055
+    "411628": "鹿邑县",
2056
+    "411681": "项城市"
2057
+  },
2058
+  "411700": {
2059
+    "411702": "驿城区",
2060
+    "411721": "西平县",
2061
+    "411722": "上蔡县",
2062
+    "411723": "平舆县",
2063
+    "411724": "正阳县",
2064
+    "411725": "确山县",
2065
+    "411726": "泌阳县",
2066
+    "411727": "汝南县",
2067
+    "411728": "遂平县",
2068
+    "411729": "新蔡县"
2069
+  },
2070
+  "420000": {
2071
+    "420100": "武汉市",
2072
+    "420200": "黄石市",
2073
+    "420300": "十堰市",
2074
+    "420500": "宜昌市",
2075
+    "420600": "襄阳市",
2076
+    "420700": "鄂州市",
2077
+    "420800": "荆门市",
2078
+    "420900": "孝感市",
2079
+    "421000": "荆州市",
2080
+    "421100": "黄冈市",
2081
+    "421200": "咸宁市",
2082
+    "421300": "随州市",
2083
+    "422800": "恩施土家族苗族自治州",
2084
+    "429004": "仙桃市",
2085
+    "429005": "潜江市",
2086
+    "429006": "天门市",
2087
+    "429021": "神农架林区"
2088
+  },
2089
+  "420100": {
2090
+    "420102": "江岸区",
2091
+    "420103": "江汉区",
2092
+    "420104": "硚口区",
2093
+    "420105": "汉阳区",
2094
+    "420106": "武昌区",
2095
+    "420107": "青山区",
2096
+    "420111": "洪山区",
2097
+    "420112": "东西湖区",
2098
+    "420113": "汉南区",
2099
+    "420114": "蔡甸区",
2100
+    "420115": "江夏区",
2101
+    "420116": "黄陂区",
2102
+    "420117": "新洲区"
2103
+  },
2104
+  "420200": {
2105
+    "420202": "黄石港区",
2106
+    "420203": "西塞山区",
2107
+    "420204": "下陆区",
2108
+    "420205": "铁山区",
2109
+    "420222": "阳新县",
2110
+    "420281": "大冶市"
2111
+  },
2112
+  "420300": {
2113
+    "420302": "茅箭区",
2114
+    "420303": "张湾区",
2115
+    "420304": "郧阳区",
2116
+    "420322": "郧西县",
2117
+    "420323": "竹山县",
2118
+    "420324": "竹溪县",
2119
+    "420325": "房县",
2120
+    "420381": "丹江口市"
2121
+  },
2122
+  "420500": {
2123
+    "420502": "西陵区",
2124
+    "420503": "伍家岗区",
2125
+    "420504": "点军区",
2126
+    "420505": "猇亭区",
2127
+    "420506": "夷陵区",
2128
+    "420525": "远安县",
2129
+    "420526": "兴山县",
2130
+    "420527": "秭归县",
2131
+    "420528": "长阳土家族自治县",
2132
+    "420529": "五峰土家族自治县",
2133
+    "420581": "宜都市",
2134
+    "420582": "当阳市",
2135
+    "420583": "枝江市"
2136
+  },
2137
+  "420600": {
2138
+    "420602": "襄城区",
2139
+    "420606": "樊城区",
2140
+    "420607": "襄州区",
2141
+    "420624": "南漳县",
2142
+    "420625": "谷城县",
2143
+    "420626": "保康县",
2144
+    "420682": "老河口市",
2145
+    "420683": "枣阳市",
2146
+    "420684": "宜城市"
2147
+  },
2148
+  "420700": {
2149
+    "420702": "梁子湖区",
2150
+    "420703": "华容区",
2151
+    "420704": "鄂城区"
2152
+  },
2153
+  "420800": {
2154
+    "420802": "东宝区",
2155
+    "420804": "掇刀区",
2156
+    "420821": "京山县",
2157
+    "420822": "沙洋县",
2158
+    "420881": "钟祥市"
2159
+  },
2160
+  "420900": {
2161
+    "420902": "孝南区",
2162
+    "420921": "孝昌县",
2163
+    "420922": "大悟县",
2164
+    "420923": "云梦县",
2165
+    "420981": "应城市",
2166
+    "420982": "安陆市",
2167
+    "420984": "汉川市"
2168
+  },
2169
+  "421000": {
2170
+    "421002": "沙市区",
2171
+    "421003": "荆州区",
2172
+    "421022": "公安县",
2173
+    "421023": "监利县",
2174
+    "421024": "江陵县",
2175
+    "421081": "石首市",
2176
+    "421083": "洪湖市",
2177
+    "421087": "松滋市"
2178
+  },
2179
+  "421100": {
2180
+    "421102": "黄州区",
2181
+    "421121": "团风县",
2182
+    "421122": "红安县",
2183
+    "421123": "罗田县",
2184
+    "421124": "英山县",
2185
+    "421125": "浠水县",
2186
+    "421126": "蕲春县",
2187
+    "421127": "黄梅县",
2188
+    "421181": "麻城市",
2189
+    "421182": "武穴市"
2190
+  },
2191
+  "421200": {
2192
+    "421202": "咸安区",
2193
+    "421221": "嘉鱼县",
2194
+    "421222": "通城县",
2195
+    "421223": "崇阳县",
2196
+    "421224": "通山县",
2197
+    "421281": "赤壁市"
2198
+  },
2199
+  "421300": {
2200
+    "421303": "曾都区",
2201
+    "421321": "随县",
2202
+    "421381": "广水市"
2203
+  },
2204
+  "422800": {
2205
+    "422801": "恩施市",
2206
+    "422802": "利川市",
2207
+    "422822": "建始县",
2208
+    "422823": "巴东县",
2209
+    "422825": "宣恩县",
2210
+    "422826": "咸丰县",
2211
+    "422827": "来凤县",
2212
+    "422828": "鹤峰县"
2213
+  },
2214
+  "430000": {
2215
+    "430100": "长沙市",
2216
+    "430200": "株洲市",
2217
+    "430300": "湘潭市",
2218
+    "430400": "衡阳市",
2219
+    "430500": "邵阳市",
2220
+    "430600": "岳阳市",
2221
+    "430700": "常德市",
2222
+    "430800": "张家界市",
2223
+    "430900": "益阳市",
2224
+    "431000": "郴州市",
2225
+    "431100": "永州市",
2226
+    "431200": "怀化市",
2227
+    "431300": "娄底市",
2228
+    "433100": "湘西土家族苗族自治州"
2229
+  },
2230
+  "430100": {
2231
+    "430102": "芙蓉区",
2232
+    "430103": "天心区",
2233
+    "430104": "岳麓区",
2234
+    "430105": "开福区",
2235
+    "430111": "雨花区",
2236
+    "430112": "望城区",
2237
+    "430121": "长沙县",
2238
+    "430124": "宁乡县",
2239
+    "430181": "浏阳市"
2240
+  },
2241
+  "430200": {
2242
+    "430202": "荷塘区",
2243
+    "430203": "芦淞区",
2244
+    "430204": "石峰区",
2245
+    "430211": "天元区",
2246
+    "430221": "株洲县",
2247
+    "430223": "攸县",
2248
+    "430224": "茶陵县",
2249
+    "430225": "炎陵县",
2250
+    "430281": "醴陵市"
2251
+  },
2252
+  "430300": {
2253
+    "430302": "雨湖区",
2254
+    "430304": "岳塘区",
2255
+    "430321": "湘潭县",
2256
+    "430381": "湘乡市",
2257
+    "430382": "韶山市"
2258
+  },
2259
+  "430400": {
2260
+    "430405": "珠晖区",
2261
+    "430406": "雁峰区",
2262
+    "430407": "石鼓区",
2263
+    "430408": "蒸湘区",
2264
+    "430412": "南岳区",
2265
+    "430421": "衡阳县",
2266
+    "430422": "衡南县",
2267
+    "430423": "衡山县",
2268
+    "430424": "衡东县",
2269
+    "430426": "祁东县",
2270
+    "430481": "耒阳市",
2271
+    "430482": "常宁市"
2272
+  },
2273
+  "430500": {
2274
+    "430502": "双清区",
2275
+    "430503": "大祥区",
2276
+    "430511": "北塔区",
2277
+    "430521": "邵东县",
2278
+    "430522": "新邵县",
2279
+    "430523": "邵阳县",
2280
+    "430524": "隆回县",
2281
+    "430525": "洞口县",
2282
+    "430527": "绥宁县",
2283
+    "430528": "新宁县",
2284
+    "430529": "城步苗族自治县",
2285
+    "430581": "武冈市"
2286
+  },
2287
+  "430600": {
2288
+    "430602": "岳阳楼区",
2289
+    "430603": "云溪区",
2290
+    "430611": "君山区",
2291
+    "430621": "岳阳县",
2292
+    "430623": "华容县",
2293
+    "430624": "湘阴县",
2294
+    "430626": "平江县",
2295
+    "430681": "汨罗市",
2296
+    "430682": "临湘市"
2297
+  },
2298
+  "430700": {
2299
+    "430702": "武陵区",
2300
+    "430703": "鼎城区",
2301
+    "430721": "安乡县",
2302
+    "430722": "汉寿县",
2303
+    "430723": "澧县",
2304
+    "430724": "临澧县",
2305
+    "430725": "桃源县",
2306
+    "430726": "石门县",
2307
+    "430781": "津市市"
2308
+  },
2309
+  "430800": {
2310
+    "430802": "永定区",
2311
+    "430811": "武陵源区",
2312
+    "430821": "慈利县",
2313
+    "430822": "桑植县"
2314
+  },
2315
+  "430900": {
2316
+    "430902": "资阳区",
2317
+    "430903": "赫山区",
2318
+    "430921": "南县",
2319
+    "430922": "桃江县",
2320
+    "430923": "安化县",
2321
+    "430981": "沅江市"
2322
+  },
2323
+  "431000": {
2324
+    "431002": "北湖区",
2325
+    "431003": "苏仙区",
2326
+    "431021": "桂阳县",
2327
+    "431022": "宜章县",
2328
+    "431023": "永兴县",
2329
+    "431024": "嘉禾县",
2330
+    "431025": "临武县",
2331
+    "431026": "汝城县",
2332
+    "431027": "桂东县",
2333
+    "431028": "安仁县",
2334
+    "431081": "资兴市"
2335
+  },
2336
+  "431100": {
2337
+    "431102": "零陵区",
2338
+    "431103": "冷水滩区",
2339
+    "431121": "祁阳县",
2340
+    "431122": "东安县",
2341
+    "431123": "双牌县",
2342
+    "431124": "道县",
2343
+    "431125": "江永县",
2344
+    "431126": "宁远县",
2345
+    "431127": "蓝山县",
2346
+    "431128": "新田县",
2347
+    "431129": "江华瑶族自治县"
2348
+  },
2349
+  "431200": {
2350
+    "431202": "鹤城区",
2351
+    "431221": "中方县",
2352
+    "431222": "沅陵县",
2353
+    "431223": "辰溪县",
2354
+    "431224": "溆浦县",
2355
+    "431225": "会同县",
2356
+    "431226": "麻阳苗族自治县",
2357
+    "431227": "新晃侗族自治县",
2358
+    "431228": "芷江侗族自治县",
2359
+    "431229": "靖州苗族侗族自治县",
2360
+    "431230": "通道侗族自治县",
2361
+    "431281": "洪江市"
2362
+  },
2363
+  "431300": {
2364
+    "431302": "娄星区",
2365
+    "431321": "双峰县",
2366
+    "431322": "新化县",
2367
+    "431381": "冷水江市",
2368
+    "431382": "涟源市"
2369
+  },
2370
+  "433100": {
2371
+    "433101": "吉首市",
2372
+    "433122": "泸溪县",
2373
+    "433123": "凤凰县",
2374
+    "433124": "花垣县",
2375
+    "433125": "保靖县",
2376
+    "433126": "古丈县",
2377
+    "433127": "永顺县",
2378
+    "433130": "龙山县"
2379
+  },
2380
+  "440000": {
2381
+    "440100": "广州市",
2382
+    "440200": "韶关市",
2383
+    "440300": "深圳市",
2384
+    "440400": "珠海市",
2385
+    "440500": "汕头市",
2386
+    "440600": "佛山市",
2387
+    "440700": "江门市",
2388
+    "440800": "湛江市",
2389
+    "440900": "茂名市",
2390
+    "441200": "肇庆市",
2391
+    "441300": "惠州市",
2392
+    "441400": "梅州市",
2393
+    "441500": "汕尾市",
2394
+    "441600": "河源市",
2395
+    "441700": "阳江市",
2396
+    "441800": "清远市",
2397
+    "441900": "东莞市",
2398
+    "442000": "中山市",
2399
+    "445100": "潮州市",
2400
+    "445200": "揭阳市",
2401
+    "445300": "云浮市"
2402
+  },
2403
+  "440100": {
2404
+    "440103": "荔湾区",
2405
+    "440104": "越秀区",
2406
+    "440105": "海珠区",
2407
+    "440106": "天河区",
2408
+    "440111": "白云区",
2409
+    "440112": "黄埔区",
2410
+    "440113": "番禺区",
2411
+    "440114": "花都区",
2412
+    "440115": "南沙区",
2413
+    "440117": "从化区",
2414
+    "440118": "增城区"
2415
+  },
2416
+  "440200": {
2417
+    "440203": "武江区",
2418
+    "440204": "浈江区",
2419
+    "440205": "曲江区",
2420
+    "440222": "始兴县",
2421
+    "440224": "仁化县",
2422
+    "440229": "翁源县",
2423
+    "440232": "乳源瑶族自治县",
2424
+    "440233": "新丰县",
2425
+    "440281": "乐昌市",
2426
+    "440282": "南雄市"
2427
+  },
2428
+  "440300": {
2429
+    "440303": "罗湖区",
2430
+    "440304": "福田区",
2431
+    "440305": "南山区",
2432
+    "440306": "宝安区",
2433
+    "440307": "龙岗区",
2434
+    "440308": "盐田区"
2435
+  },
2436
+  "440400": {
2437
+    "440402": "香洲区",
2438
+    "440403": "斗门区",
2439
+    "440404": "金湾区"
2440
+  },
2441
+  "440500": {
2442
+    "440507": "龙湖区",
2443
+    "440511": "金平区",
2444
+    "440512": "濠江区",
2445
+    "440513": "潮阳区",
2446
+    "440514": "潮南区",
2447
+    "440515": "澄海区",
2448
+    "440523": "南澳县"
2449
+  },
2450
+  "440600": {
2451
+    "440604": "禅城区",
2452
+    "440605": "南海区",
2453
+    "440606": "顺德区",
2454
+    "440607": "三水区",
2455
+    "440608": "高明区"
2456
+  },
2457
+  "440700": {
2458
+    "440703": "蓬江区",
2459
+    "440704": "江海区",
2460
+    "440705": "新会区",
2461
+    "440781": "台山市",
2462
+    "440783": "开平市",
2463
+    "440784": "鹤山市",
2464
+    "440785": "恩平市"
2465
+  },
2466
+  "440800": {
2467
+    "440802": "赤坎区",
2468
+    "440803": "霞山区",
2469
+    "440804": "坡头区",
2470
+    "440811": "麻章区",
2471
+    "440823": "遂溪县",
2472
+    "440825": "徐闻县",
2473
+    "440881": "廉江市",
2474
+    "440882": "雷州市",
2475
+    "440883": "吴川市"
2476
+  },
2477
+  "440900": {
2478
+    "440902": "茂南区",
2479
+    "440904": "电白区",
2480
+    "440981": "高州市",
2481
+    "440982": "化州市",
2482
+    "440983": "信宜市"
2483
+  },
2484
+  "441200": {
2485
+    "441202": "端州区",
2486
+    "441203": "鼎湖区",
2487
+    "441204": "高要区",
2488
+    "441223": "广宁县",
2489
+    "441224": "怀集县",
2490
+    "441225": "封开县",
2491
+    "441226": "德庆县",
2492
+    "441284": "四会市"
2493
+  },
2494
+  "441300": {
2495
+    "441302": "惠城区",
2496
+    "441303": "惠阳区",
2497
+    "441322": "博罗县",
2498
+    "441323": "惠东县",
2499
+    "441324": "龙门县"
2500
+  },
2501
+  "441400": {
2502
+    "441402": "梅江区",
2503
+    "441403": "梅县区",
2504
+    "441422": "大埔县",
2505
+    "441423": "丰顺县",
2506
+    "441424": "五华县",
2507
+    "441426": "平远县",
2508
+    "441427": "蕉岭县",
2509
+    "441481": "兴宁市"
2510
+  },
2511
+  "441500": {
2512
+    "441502": "城区",
2513
+    "441521": "海丰县",
2514
+    "441523": "陆河县",
2515
+    "441581": "陆丰市"
2516
+  },
2517
+  "441600": {
2518
+    "441602": "源城区",
2519
+    "441621": "紫金县",
2520
+    "441622": "龙川县",
2521
+    "441623": "连平县",
2522
+    "441624": "和平县",
2523
+    "441625": "东源县"
2524
+  },
2525
+  "441700": {
2526
+    "441702": "江城区",
2527
+    "441704": "阳东区",
2528
+    "441721": "阳西县",
2529
+    "441781": "阳春市"
2530
+  },
2531
+  "441800": {
2532
+    "441802": "清城区",
2533
+    "441803": "清新区",
2534
+    "441821": "佛冈县",
2535
+    "441823": "阳山县",
2536
+    "441825": "连山壮族瑶族自治县",
2537
+    "441826": "连南瑶族自治县",
2538
+    "441881": "英德市",
2539
+    "441882": "连州市"
2540
+  },
2541
+  "445100": {
2542
+    "445102": "湘桥区",
2543
+    "445103": "潮安区",
2544
+    "445122": "饶平县"
2545
+  },
2546
+  "445200": {
2547
+    "445202": "榕城区",
2548
+    "445203": "揭东区",
2549
+    "445222": "揭西县",
2550
+    "445224": "惠来县",
2551
+    "445281": "普宁市"
2552
+  },
2553
+  "445300": {
2554
+    "445302": "云城区",
2555
+    "445303": "云安区",
2556
+    "445321": "新兴县",
2557
+    "445322": "郁南县",
2558
+    "445381": "罗定市"
2559
+  },
2560
+  "450000": {
2561
+    "450100": "南宁市",
2562
+    "450200": "柳州市",
2563
+    "450300": "桂林市",
2564
+    "450400": "梧州市",
2565
+    "450500": "北海市",
2566
+    "450600": "防城港市",
2567
+    "450700": "钦州市",
2568
+    "450800": "贵港市",
2569
+    "450900": "玉林市",
2570
+    "451000": "百色市",
2571
+    "451100": "贺州市",
2572
+    "451200": "河池市",
2573
+    "451300": "来宾市",
2574
+    "451400": "崇左市"
2575
+  },
2576
+  "450100": {
2577
+    "450102": "兴宁区",
2578
+    "450103": "青秀区",
2579
+    "450105": "江南区",
2580
+    "450107": "西乡塘区",
2581
+    "450108": "良庆区",
2582
+    "450109": "邕宁区",
2583
+    "450110": "武鸣区",
2584
+    "450123": "隆安县",
2585
+    "450124": "马山县",
2586
+    "450125": "上林县",
2587
+    "450126": "宾阳县",
2588
+    "450127": "横县"
2589
+  },
2590
+  "450200": {
2591
+    "450202": "城中区",
2592
+    "450203": "鱼峰区",
2593
+    "450204": "柳南区",
2594
+    "450205": "柳北区",
2595
+    "450206": "柳江区",
2596
+    "450222": "柳城县",
2597
+    "450223": "鹿寨县",
2598
+    "450224": "融安县",
2599
+    "450225": "融水苗族自治县",
2600
+    "450226": "三江侗族自治县"
2601
+  },
2602
+  "450300": {
2603
+    "450302": "秀峰区",
2604
+    "450303": "叠彩区",
2605
+    "450304": "象山区",
2606
+    "450305": "七星区",
2607
+    "450311": "雁山区",
2608
+    "450312": "临桂区",
2609
+    "450321": "阳朔县",
2610
+    "450323": "灵川县",
2611
+    "450324": "全州县",
2612
+    "450325": "兴安县",
2613
+    "450326": "永福县",
2614
+    "450327": "灌阳县",
2615
+    "450328": "龙胜各族自治县",
2616
+    "450329": "资源县",
2617
+    "450330": "平乐县",
2618
+    "450331": "荔浦县",
2619
+    "450332": "恭城瑶族自治县"
2620
+  },
2621
+  "450400": {
2622
+    "450403": "万秀区",
2623
+    "450405": "长洲区",
2624
+    "450406": "龙圩区",
2625
+    "450421": "苍梧县",
2626
+    "450422": "藤县",
2627
+    "450423": "蒙山县",
2628
+    "450481": "岑溪市"
2629
+  },
2630
+  "450500": {
2631
+    "450502": "海城区",
2632
+    "450503": "银海区",
2633
+    "450512": "铁山港区",
2634
+    "450521": "合浦县"
2635
+  },
2636
+  "450600": {
2637
+    "450602": "港口区",
2638
+    "450603": "防城区",
2639
+    "450621": "上思县",
2640
+    "450681": "东兴市"
2641
+  },
2642
+  "450700": {
2643
+    "450702": "钦南区",
2644
+    "450703": "钦北区",
2645
+    "450721": "灵山县",
2646
+    "450722": "浦北县"
2647
+  },
2648
+  "450800": {
2649
+    "450802": "港北区",
2650
+    "450803": "港南区",
2651
+    "450804": "覃塘区",
2652
+    "450821": "平南县",
2653
+    "450881": "桂平市"
2654
+  },
2655
+  "450900": {
2656
+    "450902": "玉州区",
2657
+    "450903": "福绵区",
2658
+    "450921": "容县",
2659
+    "450922": "陆川县",
2660
+    "450923": "博白县",
2661
+    "450924": "兴业县",
2662
+    "450981": "北流市"
2663
+  },
2664
+  "451000": {
2665
+    "451002": "右江区",
2666
+    "451021": "田阳县",
2667
+    "451022": "田东县",
2668
+    "451023": "平果县",
2669
+    "451024": "德保县",
2670
+    "451026": "那坡县",
2671
+    "451027": "凌云县",
2672
+    "451028": "乐业县",
2673
+    "451029": "田林县",
2674
+    "451030": "西林县",
2675
+    "451031": "隆林各族自治县",
2676
+    "451081": "靖西市"
2677
+  },
2678
+  "451100": {
2679
+    "451102": "八步区",
2680
+    "451103": "平桂区",
2681
+    "451121": "昭平县",
2682
+    "451122": "钟山县",
2683
+    "451123": "富川瑶族自治县"
2684
+  },
2685
+  "451200": {
2686
+    "451202": "金城江区",
2687
+    "451221": "南丹县",
2688
+    "451222": "天峨县",
2689
+    "451223": "凤山县",
2690
+    "451224": "东兰县",
2691
+    "451225": "罗城仫佬族自治县",
2692
+    "451226": "环江毛南族自治县",
2693
+    "451227": "巴马瑶族自治县",
2694
+    "451228": "都安瑶族自治县",
2695
+    "451229": "大化瑶族自治县",
2696
+    "451281": "宜州市"
2697
+  },
2698
+  "451300": {
2699
+    "451302": "兴宾区",
2700
+    "451321": "忻城县",
2701
+    "451322": "象州县",
2702
+    "451323": "武宣县",
2703
+    "451324": "金秀瑶族自治县",
2704
+    "451381": "合山市"
2705
+  },
2706
+  "451400": {
2707
+    "451402": "江州区",
2708
+    "451421": "扶绥县",
2709
+    "451422": "宁明县",
2710
+    "451423": "龙州县",
2711
+    "451424": "大新县",
2712
+    "451425": "天等县",
2713
+    "451481": "凭祥市"
2714
+  },
2715
+  "460000": {
2716
+    "460100": "海口市",
2717
+    "460200": "三亚市",
2718
+    "460300": "三沙市",
2719
+    "460400": "儋州市",
2720
+    "469001": "五指山市",
2721
+    "469002": "琼海市",
2722
+    "469005": "文昌市",
2723
+    "469006": "万宁市",
2724
+    "469007": "东方市",
2725
+    "469021": "定安县",
2726
+    "469022": "屯昌县",
2727
+    "469023": "澄迈县",
2728
+    "469024": "临高县",
2729
+    "469025": "白沙黎族自治县",
2730
+    "469026": "昌江黎族自治县",
2731
+    "469027": "乐东黎族自治县",
2732
+    "469028": "陵水黎族自治县",
2733
+    "469029": "保亭黎族苗族自治县",
2734
+    "469030": "琼中黎族苗族自治县"
2735
+  },
2736
+  "460100": {
2737
+    "460105": "秀英区",
2738
+    "460106": "龙华区",
2739
+    "460107": "琼山区",
2740
+    "460108": "美兰区"
2741
+  },
2742
+  "460200": {
2743
+    "460202": "海棠区",
2744
+    "460203": "吉阳区",
2745
+    "460204": "天涯区",
2746
+    "460205": "崖州区"
2747
+  },
2748
+  "500000": {
2749
+    "500100": "市辖区"
2750
+  },
2751
+  "500100": {
2752
+    "500101": "万州区",
2753
+    "500102": "涪陵区",
2754
+    "500103": "渝中区",
2755
+    "500104": "大渡口区",
2756
+    "500105": "江北区",
2757
+    "500106": "沙坪坝区",
2758
+    "500107": "九龙坡区",
2759
+    "500108": "南岸区",
2760
+    "500109": "北碚区",
2761
+    "500110": "綦江区",
2762
+    "500111": "大足区",
2763
+    "500112": "渝北区",
2764
+    "500113": "巴南区",
2765
+    "500114": "黔江区",
2766
+    "500115": "长寿区",
2767
+    "500116": "江津区",
2768
+    "500117": "合川区",
2769
+    "500118": "永川区",
2770
+    "500119": "南川区",
2771
+    "500120": "璧山区",
2772
+    "500151": "铜梁区",
2773
+    "500152": "潼南区",
2774
+    "500153": "荣昌区",
2775
+    "500154": "开州区",
2776
+    "500228": "梁平县",
2777
+    "500229": "城口县",
2778
+    "500230": "丰都县",
2779
+    "500231": "垫江县",
2780
+    "500232": "武隆县",
2781
+    "500233": "忠县",
2782
+    "500235": "云阳县",
2783
+    "500236": "奉节县",
2784
+    "500237": "巫山县",
2785
+    "500238": "巫溪县",
2786
+    "500240": "石柱土家族自治县",
2787
+    "500241": "秀山土家族苗族自治县",
2788
+    "500242": "酉阳土家族苗族自治县",
2789
+    "500243": "彭水苗族土家族自治县"
2790
+  },
2791
+  "510000": {
2792
+    "510100": "成都市",
2793
+    "510300": "自贡市",
2794
+    "510400": "攀枝花市",
2795
+    "510500": "泸州市",
2796
+    "510600": "德阳市",
2797
+    "510700": "绵阳市",
2798
+    "510800": "广元市",
2799
+    "510900": "遂宁市",
2800
+    "511000": "内江市",
2801
+    "511100": "乐山市",
2802
+    "511300": "南充市",
2803
+    "511400": "眉山市",
2804
+    "511500": "宜宾市",
2805
+    "511600": "广安市",
2806
+    "511700": "达州市",
2807
+    "511800": "雅安市",
2808
+    "511900": "巴中市",
2809
+    "512000": "资阳市",
2810
+    "513200": "阿坝藏族羌族自治州",
2811
+    "513300": "甘孜藏族自治州",
2812
+    "513400": "凉山彝族自治州"
2813
+  },
2814
+  "510100": {
2815
+    "510104": "锦江区",
2816
+    "510105": "青羊区",
2817
+    "510106": "金牛区",
2818
+    "510107": "武侯区",
2819
+    "510108": "成华区",
2820
+    "510112": "龙泉驿区",
2821
+    "510113": "青白江区",
2822
+    "510114": "新都区",
2823
+    "510115": "温江区",
2824
+    "510116": "双流区",
2825
+    "510121": "金堂县",
2826
+    "510124": "郫县",
2827
+    "510129": "大邑县",
2828
+    "510131": "蒲江县",
2829
+    "510132": "新津县",
2830
+    "510181": "都江堰市",
2831
+    "510182": "彭州市",
2832
+    "510183": "邛崃市",
2833
+    "510184": "崇州市",
2834
+    "510185": "简阳市"
2835
+  },
2836
+  "510300": {
2837
+    "510302": "自流井区",
2838
+    "510303": "贡井区",
2839
+    "510304": "大安区",
2840
+    "510311": "沿滩区",
2841
+    "510321": "荣县",
2842
+    "510322": "富顺县"
2843
+  },
2844
+  "510400": {
2845
+    "510402": "东区",
2846
+    "510403": "西区",
2847
+    "510411": "仁和区",
2848
+    "510421": "米易县",
2849
+    "510422": "盐边县"
2850
+  },
2851
+  "510500": {
2852
+    "510502": "江阳区",
2853
+    "510503": "纳溪区",
2854
+    "510504": "龙马潭区",
2855
+    "510521": "泸县",
2856
+    "510522": "合江县",
2857
+    "510524": "叙永县",
2858
+    "510525": "古蔺县"
2859
+  },
2860
+  "510600": {
2861
+    "510603": "旌阳区",
2862
+    "510623": "中江县",
2863
+    "510626": "罗江县",
2864
+    "510681": "广汉市",
2865
+    "510682": "什邡市",
2866
+    "510683": "绵竹市"
2867
+  },
2868
+  "510700": {
2869
+    "510703": "涪城区",
2870
+    "510704": "游仙区",
2871
+    "510705": "安州区",
2872
+    "510722": "三台县",
2873
+    "510723": "盐亭县",
2874
+    "510725": "梓潼县",
2875
+    "510726": "北川羌族自治县",
2876
+    "510727": "平武县",
2877
+    "510781": "江油市"
2878
+  },
2879
+  "510800": {
2880
+    "510802": "利州区",
2881
+    "510811": "昭化区",
2882
+    "510812": "朝天区",
2883
+    "510821": "旺苍县",
2884
+    "510822": "青川县",
2885
+    "510823": "剑阁县",
2886
+    "510824": "苍溪县"
2887
+  },
2888
+  "510900": {
2889
+    "510903": "船山区",
2890
+    "510904": "安居区",
2891
+    "510921": "蓬溪县",
2892
+    "510922": "射洪县",
2893
+    "510923": "大英县"
2894
+  },
2895
+  "511000": {
2896
+    "511002": "市中区",
2897
+    "511011": "东兴区",
2898
+    "511024": "威远县",
2899
+    "511025": "资中县",
2900
+    "511028": "隆昌县"
2901
+  },
2902
+  "511100": {
2903
+    "511102": "市中区",
2904
+    "511111": "沙湾区",
2905
+    "511112": "五通桥区",
2906
+    "511113": "金口河区",
2907
+    "511123": "犍为县",
2908
+    "511124": "井研县",
2909
+    "511126": "夹江县",
2910
+    "511129": "沐川县",
2911
+    "511132": "峨边彝族自治县",
2912
+    "511133": "马边彝族自治县",
2913
+    "511181": "峨眉山市"
2914
+  },
2915
+  "511300": {
2916
+    "511302": "顺庆区",
2917
+    "511303": "高坪区",
2918
+    "511304": "嘉陵区",
2919
+    "511321": "南部县",
2920
+    "511322": "营山县",
2921
+    "511323": "蓬安县",
2922
+    "511324": "仪陇县",
2923
+    "511325": "西充县",
2924
+    "511381": "阆中市"
2925
+  },
2926
+  "511400": {
2927
+    "511402": "东坡区",
2928
+    "511403": "彭山区",
2929
+    "511421": "仁寿县",
2930
+    "511423": "洪雅县",
2931
+    "511424": "丹棱县",
2932
+    "511425": "青神县"
2933
+  },
2934
+  "511500": {
2935
+    "511502": "翠屏区",
2936
+    "511503": "南溪区",
2937
+    "511521": "宜宾县",
2938
+    "511523": "江安县",
2939
+    "511524": "长宁县",
2940
+    "511525": "高县",
2941
+    "511526": "珙县",
2942
+    "511527": "筠连县",
2943
+    "511528": "兴文县",
2944
+    "511529": "屏山县"
2945
+  },
2946
+  "511600": {
2947
+    "511602": "广安区",
2948
+    "511603": "前锋区",
2949
+    "511621": "岳池县",
2950
+    "511622": "武胜县",
2951
+    "511623": "邻水县",
2952
+    "511681": "华蓥市"
2953
+  },
2954
+  "511700": {
2955
+    "511702": "通川区",
2956
+    "511703": "达川区",
2957
+    "511722": "宣汉县",
2958
+    "511723": "开江县",
2959
+    "511724": "大竹县",
2960
+    "511725": "渠县",
2961
+    "511781": "万源市"
2962
+  },
2963
+  "511800": {
2964
+    "511802": "雨城区",
2965
+    "511803": "名山区",
2966
+    "511822": "荥经县",
2967
+    "511823": "汉源县",
2968
+    "511824": "石棉县",
2969
+    "511825": "天全县",
2970
+    "511826": "芦山县",
2971
+    "511827": "宝兴县"
2972
+  },
2973
+  "511900": {
2974
+    "511902": "巴州区",
2975
+    "511903": "恩阳区",
2976
+    "511921": "通江县",
2977
+    "511922": "南江县",
2978
+    "511923": "平昌县"
2979
+  },
2980
+  "512000": {
2981
+    "512002": "雁江区",
2982
+    "512021": "安岳县",
2983
+    "512022": "乐至县"
2984
+  },
2985
+  "513200": {
2986
+    "513201": "马尔康市",
2987
+    "513221": "汶川县",
2988
+    "513222": "理县",
2989
+    "513223": "茂县",
2990
+    "513224": "松潘县",
2991
+    "513225": "九寨沟县",
2992
+    "513226": "金川县",
2993
+    "513227": "小金县",
2994
+    "513228": "黑水县",
2995
+    "513230": "壤塘县",
2996
+    "513231": "阿坝县",
2997
+    "513232": "若尔盖县",
2998
+    "513233": "红原县"
2999
+  },
3000
+  "513300": {
3001
+    "513301": "康定市",
3002
+    "513322": "泸定县",
3003
+    "513323": "丹巴县",
3004
+    "513324": "九龙县",
3005
+    "513325": "雅江县",
3006
+    "513326": "道孚县",
3007
+    "513327": "炉霍县",
3008
+    "513328": "甘孜县",
3009
+    "513329": "新龙县",
3010
+    "513330": "德格县",
3011
+    "513331": "白玉县",
3012
+    "513332": "石渠县",
3013
+    "513333": "色达县",
3014
+    "513334": "理塘县",
3015
+    "513335": "巴塘县",
3016
+    "513336": "乡城县",
3017
+    "513337": "稻城县",
3018
+    "513338": "得荣县"
3019
+  },
3020
+  "513400": {
3021
+    "513401": "西昌市",
3022
+    "513422": "木里藏族自治县",
3023
+    "513423": "盐源县",
3024
+    "513424": "德昌县",
3025
+    "513425": "会理县",
3026
+    "513426": "会东县",
3027
+    "513427": "宁南县",
3028
+    "513428": "普格县",
3029
+    "513429": "布拖县",
3030
+    "513430": "金阳县",
3031
+    "513431": "昭觉县",
3032
+    "513432": "喜德县",
3033
+    "513433": "冕宁县",
3034
+    "513434": "越西县",
3035
+    "513435": "甘洛县",
3036
+    "513436": "美姑县",
3037
+    "513437": "雷波县"
3038
+  },
3039
+  "520000": {
3040
+    "520100": "贵阳市",
3041
+    "520200": "六盘水市",
3042
+    "520300": "遵义市",
3043
+    "520400": "安顺市",
3044
+    "520500": "毕节市",
3045
+    "520600": "铜仁市",
3046
+    "522300": "黔西南布依族苗族自治州",
3047
+    "522600": "黔东南苗族侗族自治州",
3048
+    "522700": "黔南布依族苗族自治州"
3049
+  },
3050
+  "520100": {
3051
+    "520102": "南明区",
3052
+    "520103": "云岩区",
3053
+    "520111": "花溪区",
3054
+    "520112": "乌当区",
3055
+    "520113": "白云区",
3056
+    "520115": "观山湖区",
3057
+    "520121": "开阳县",
3058
+    "520122": "息烽县",
3059
+    "520123": "修文县",
3060
+    "520181": "清镇市"
3061
+  },
3062
+  "520200": {
3063
+    "520201": "钟山区",
3064
+    "520203": "六枝特区",
3065
+    "520221": "水城县",
3066
+    "520222": "盘县"
3067
+  },
3068
+  "520300": {
3069
+    "520302": "红花岗区",
3070
+    "520303": "汇川区",
3071
+    "520304": "播州区",
3072
+    "520322": "桐梓县",
3073
+    "520323": "绥阳县",
3074
+    "520324": "正安县",
3075
+    "520325": "道真仡佬族苗族自治县",
3076
+    "520326": "务川仡佬族苗族自治县",
3077
+    "520327": "凤冈县",
3078
+    "520328": "湄潭县",
3079
+    "520329": "余庆县",
3080
+    "520330": "习水县",
3081
+    "520381": "赤水市",
3082
+    "520382": "仁怀市"
3083
+  },
3084
+  "520400": {
3085
+    "520402": "西秀区",
3086
+    "520403": "平坝区",
3087
+    "520422": "普定县",
3088
+    "520423": "镇宁布依族苗族自治县",
3089
+    "520424": "关岭布依族苗族自治县",
3090
+    "520425": "紫云苗族布依族自治县"
3091
+  },
3092
+  "520500": {
3093
+    "520502": "七星关区",
3094
+    "520521": "大方县",
3095
+    "520522": "黔西县",
3096
+    "520523": "金沙县",
3097
+    "520524": "织金县",
3098
+    "520525": "纳雍县",
3099
+    "520526": "威宁彝族回族苗族自治县",
3100
+    "520527": "赫章县"
3101
+  },
3102
+  "520600": {
3103
+    "520602": "碧江区",
3104
+    "520603": "万山区",
3105
+    "520621": "江口县",
3106
+    "520622": "玉屏侗族自治县",
3107
+    "520623": "石阡县",
3108
+    "520624": "思南县",
3109
+    "520625": "印江土家族苗族自治县",
3110
+    "520626": "德江县",
3111
+    "520627": "沿河土家族自治县",
3112
+    "520628": "松桃苗族自治县"
3113
+  },
3114
+  "522300": {
3115
+    "522301": "兴义市",
3116
+    "522322": "兴仁县",
3117
+    "522323": "普安县",
3118
+    "522324": "晴隆县",
3119
+    "522325": "贞丰县",
3120
+    "522326": "望谟县",
3121
+    "522327": "册亨县",
3122
+    "522328": "安龙县"
3123
+  },
3124
+  "522600": {
3125
+    "522601": "凯里市",
3126
+    "522622": "黄平县",
3127
+    "522623": "施秉县",
3128
+    "522624": "三穗县",
3129
+    "522625": "镇远县",
3130
+    "522626": "岑巩县",
3131
+    "522627": "天柱县",
3132
+    "522628": "锦屏县",
3133
+    "522629": "剑河县",
3134
+    "522630": "台江县",
3135
+    "522631": "黎平县",
3136
+    "522632": "榕江县",
3137
+    "522633": "从江县",
3138
+    "522634": "雷山县",
3139
+    "522635": "麻江县",
3140
+    "522636": "丹寨县"
3141
+  },
3142
+  "522700": {
3143
+    "522701": "都匀市",
3144
+    "522702": "福泉市",
3145
+    "522722": "荔波县",
3146
+    "522723": "贵定县",
3147
+    "522725": "瓮安县",
3148
+    "522726": "独山县",
3149
+    "522727": "平塘县",
3150
+    "522728": "罗甸县",
3151
+    "522729": "长顺县",
3152
+    "522730": "龙里县",
3153
+    "522731": "惠水县",
3154
+    "522732": "三都水族自治县"
3155
+  },
3156
+  "530000": {
3157
+    "530100": "昆明市",
3158
+    "530300": "曲靖市",
3159
+    "530400": "玉溪市",
3160
+    "530500": "保山市",
3161
+    "530600": "昭通市",
3162
+    "530700": "丽江市",
3163
+    "530800": "普洱市",
3164
+    "530900": "临沧市",
3165
+    "532300": "楚雄彝族自治州",
3166
+    "532500": "红河哈尼族彝族自治州",
3167
+    "532600": "文山壮族苗族自治州",
3168
+    "532800": "西双版纳傣族自治州",
3169
+    "532900": "大理白族自治州",
3170
+    "533100": "德宏傣族景颇族自治州",
3171
+    "533300": "怒江傈僳族自治州",
3172
+    "533400": "迪庆藏族自治州"
3173
+  },
3174
+  "530100": {
3175
+    "530102": "五华区",
3176
+    "530103": "盘龙区",
3177
+    "530111": "官渡区",
3178
+    "530112": "西山区",
3179
+    "530113": "东川区",
3180
+    "530114": "呈贡区",
3181
+    "530122": "晋宁县",
3182
+    "530124": "富民县",
3183
+    "530125": "宜良县",
3184
+    "530126": "石林彝族自治县",
3185
+    "530127": "嵩明县",
3186
+    "530128": "禄劝彝族苗族自治县",
3187
+    "530129": "寻甸回族彝族自治县",
3188
+    "530181": "安宁市"
3189
+  },
3190
+  "530300": {
3191
+    "530302": "麒麟区",
3192
+    "530303": "沾益区",
3193
+    "530321": "马龙县",
3194
+    "530322": "陆良县",
3195
+    "530323": "师宗县",
3196
+    "530324": "罗平县",
3197
+    "530325": "富源县",
3198
+    "530326": "会泽县",
3199
+    "530381": "宣威市"
3200
+  },
3201
+  "530400": {
3202
+    "530402": "红塔区",
3203
+    "530403": "江川区",
3204
+    "530422": "澄江县",
3205
+    "530423": "通海县",
3206
+    "530424": "华宁县",
3207
+    "530425": "易门县",
3208
+    "530426": "峨山彝族自治县",
3209
+    "530427": "新平彝族傣族自治县",
3210
+    "530428": "元江哈尼族彝族傣族自治县"
3211
+  },
3212
+  "530500": {
3213
+    "530502": "隆阳区",
3214
+    "530521": "施甸县",
3215
+    "530523": "龙陵县",
3216
+    "530524": "昌宁县",
3217
+    "530581": "腾冲市"
3218
+  },
3219
+  "530600": {
3220
+    "530602": "昭阳区",
3221
+    "530621": "鲁甸县",
3222
+    "530622": "巧家县",
3223
+    "530623": "盐津县",
3224
+    "530624": "大关县",
3225
+    "530625": "永善县",
3226
+    "530626": "绥江县",
3227
+    "530627": "镇雄县",
3228
+    "530628": "彝良县",
3229
+    "530629": "威信县",
3230
+    "530630": "水富县"
3231
+  },
3232
+  "530700": {
3233
+    "530702": "古城区",
3234
+    "530721": "玉龙纳西族自治县",
3235
+    "530722": "永胜县",
3236
+    "530723": "华坪县",
3237
+    "530724": "宁蒗彝族自治县"
3238
+  },
3239
+  "530800": {
3240
+    "530802": "思茅区",
3241
+    "530821": "宁洱哈尼族彝族自治县",
3242
+    "530822": "墨江哈尼族自治县",
3243
+    "530823": "景东彝族自治县",
3244
+    "530824": "景谷傣族彝族自治县",
3245
+    "530825": "镇沅彝族哈尼族拉祜族自治县",
3246
+    "530826": "江城哈尼族彝族自治县",
3247
+    "530827": "孟连傣族拉祜族佤族自治县",
3248
+    "530828": "澜沧拉祜族自治县",
3249
+    "530829": "西盟佤族自治县"
3250
+  },
3251
+  "530900": {
3252
+    "530902": "临翔区",
3253
+    "530921": "凤庆县",
3254
+    "530922": "云县",
3255
+    "530923": "永德县",
3256
+    "530924": "镇康县",
3257
+    "530925": "双江拉祜族佤族布朗族傣族自治县",
3258
+    "530926": "耿马傣族佤族自治县",
3259
+    "530927": "沧源佤族自治县"
3260
+  },
3261
+  "532300": {
3262
+    "532301": "楚雄市",
3263
+    "532322": "双柏县",
3264
+    "532323": "牟定县",
3265
+    "532324": "南华县",
3266
+    "532325": "姚安县",
3267
+    "532326": "大姚县",
3268
+    "532327": "永仁县",
3269
+    "532328": "元谋县",
3270
+    "532329": "武定县",
3271
+    "532331": "禄丰县"
3272
+  },
3273
+  "532500": {
3274
+    "532501": "个旧市",
3275
+    "532502": "开远市",
3276
+    "532503": "蒙自市",
3277
+    "532504": "弥勒市",
3278
+    "532523": "屏边苗族自治县",
3279
+    "532524": "建水县",
3280
+    "532525": "石屏县",
3281
+    "532527": "泸西县",
3282
+    "532528": "元阳县",
3283
+    "532529": "红河县",
3284
+    "532530": "金平苗族瑶族傣族自治县",
3285
+    "532531": "绿春县",
3286
+    "532532": "河口瑶族自治县"
3287
+  },
3288
+  "532600": {
3289
+    "532601": "文山市",
3290
+    "532622": "砚山县",
3291
+    "532623": "西畴县",
3292
+    "532624": "麻栗坡县",
3293
+    "532625": "马关县",
3294
+    "532626": "丘北县",
3295
+    "532627": "广南县",
3296
+    "532628": "富宁县"
3297
+  },
3298
+  "532800": {
3299
+    "532801": "景洪市",
3300
+    "532822": "勐海县",
3301
+    "532823": "勐腊县"
3302
+  },
3303
+  "532900": {
3304
+    "532901": "大理市",
3305
+    "532922": "漾濞彝族自治县",
3306
+    "532923": "祥云县",
3307
+    "532924": "宾川县",
3308
+    "532925": "弥渡县",
3309
+    "532926": "南涧彝族自治县",
3310
+    "532927": "巍山彝族回族自治县",
3311
+    "532928": "永平县",
3312
+    "532929": "云龙县",
3313
+    "532930": "洱源县",
3314
+    "532931": "剑川县",
3315
+    "532932": "鹤庆县"
3316
+  },
3317
+  "533100": {
3318
+    "533102": "瑞丽市",
3319
+    "533103": "芒市",
3320
+    "533122": "梁河县",
3321
+    "533123": "盈江县",
3322
+    "533124": "陇川县"
3323
+  },
3324
+  "533300": {
3325
+    "533301": "泸水市",
3326
+    "533323": "福贡县",
3327
+    "533324": "贡山独龙族怒族自治县",
3328
+    "533325": "兰坪白族普米族自治县"
3329
+  },
3330
+  "533400": {
3331
+    "533401": "香格里拉市",
3332
+    "533422": "德钦县",
3333
+    "533423": "维西傈僳族自治县"
3334
+  },
3335
+  "540000": {
3336
+    "540100": "拉萨市",
3337
+    "540200": "日喀则市",
3338
+    "540300": "昌都市",
3339
+    "540400": "林芝市",
3340
+    "540500": "山南市",
3341
+    "542400": "那曲地区",
3342
+    "542500": "阿里地区"
3343
+  },
3344
+  "540100": {
3345
+    "540102": "城关区",
3346
+    "540103": "堆龙德庆区",
3347
+    "540121": "林周县",
3348
+    "540122": "当雄县",
3349
+    "540123": "尼木县",
3350
+    "540124": "曲水县",
3351
+    "540126": "达孜县",
3352
+    "540127": "墨竹工卡县"
3353
+  },
3354
+  "540200": {
3355
+    "540202": "桑珠孜区",
3356
+    "540221": "南木林县",
3357
+    "540222": "江孜县",
3358
+    "540223": "定日县",
3359
+    "540224": "萨迦县",
3360
+    "540225": "拉孜县",
3361
+    "540226": "昂仁县",
3362
+    "540227": "谢通门县",
3363
+    "540228": "白朗县",
3364
+    "540229": "仁布县",
3365
+    "540230": "康马县",
3366
+    "540231": "定结县",
3367
+    "540232": "仲巴县",
3368
+    "540233": "亚东县",
3369
+    "540234": "吉隆县",
3370
+    "540235": "聂拉木县",
3371
+    "540236": "萨嘎县",
3372
+    "540237": "岗巴县"
3373
+  },
3374
+  "540300": {
3375
+    "540302": "卡若区",
3376
+    "540321": "江达县",
3377
+    "540322": "贡觉县",
3378
+    "540323": "类乌齐县",
3379
+    "540324": "丁青县",
3380
+    "540325": "察雅县",
3381
+    "540326": "八宿县",
3382
+    "540327": "左贡县",
3383
+    "540328": "芒康县",
3384
+    "540329": "洛隆县",
3385
+    "540330": "边坝县"
3386
+  },
3387
+  "540400": {
3388
+    "540402": "巴宜区",
3389
+    "540421": "工布江达县",
3390
+    "540422": "米林县",
3391
+    "540423": "墨脱县",
3392
+    "540424": "波密县",
3393
+    "540425": "察隅县",
3394
+    "540426": "朗县"
3395
+  },
3396
+  "540500": {
3397
+    "540502": "乃东区",
3398
+    "540521": "扎囊县",
3399
+    "540522": "贡嘎县",
3400
+    "540523": "桑日县",
3401
+    "540524": "琼结县",
3402
+    "540525": "曲松县",
3403
+    "540526": "措美县",
3404
+    "540527": "洛扎县",
3405
+    "540528": "加查县",
3406
+    "540529": "隆子县",
3407
+    "540530": "错那县",
3408
+    "540531": "浪卡子县"
3409
+  },
3410
+  "542400": {
3411
+    "542421": "那曲县",
3412
+    "542422": "嘉黎县",
3413
+    "542423": "比如县",
3414
+    "542424": "聂荣县",
3415
+    "542425": "安多县",
3416
+    "542426": "申扎县",
3417
+    "542427": "索县",
3418
+    "542428": "班戈县",
3419
+    "542429": "巴青县",
3420
+    "542430": "尼玛县",
3421
+    "542431": "双湖县"
3422
+  },
3423
+  "542500": {
3424
+    "542521": "普兰县",
3425
+    "542522": "札达县",
3426
+    "542523": "噶尔县",
3427
+    "542524": "日土县",
3428
+    "542525": "革吉县",
3429
+    "542526": "改则县",
3430
+    "542527": "措勤县"
3431
+  },
3432
+  "610000": {
3433
+    "610100": "西安市",
3434
+    "610200": "铜川市",
3435
+    "610300": "宝鸡市",
3436
+    "610400": "咸阳市",
3437
+    "610500": "渭南市",
3438
+    "610600": "延安市",
3439
+    "610700": "汉中市",
3440
+    "610800": "榆林市",
3441
+    "610900": "安康市",
3442
+    "611000": "商洛市"
3443
+  },
3444
+  "610100": {
3445
+    "610102": "新城区",
3446
+    "610103": "碑林区",
3447
+    "610104": "莲湖区",
3448
+    "610111": "灞桥区",
3449
+    "610112": "未央区",
3450
+    "610113": "雁塔区",
3451
+    "610114": "阎良区",
3452
+    "610115": "临潼区",
3453
+    "610116": "长安区",
3454
+    "610117": "高陵区",
3455
+    "610122": "蓝田县",
3456
+    "610124": "周至县",
3457
+    "610125": "户县"
3458
+  },
3459
+  "610200": {
3460
+    "610202": "王益区",
3461
+    "610203": "印台区",
3462
+    "610204": "耀州区",
3463
+    "610222": "宜君县"
3464
+  },
3465
+  "610300": {
3466
+    "610302": "渭滨区",
3467
+    "610303": "金台区",
3468
+    "610304": "陈仓区",
3469
+    "610322": "凤翔县",
3470
+    "610323": "岐山县",
3471
+    "610324": "扶风县",
3472
+    "610326": "眉县",
3473
+    "610327": "陇县",
3474
+    "610328": "千阳县",
3475
+    "610329": "麟游县",
3476
+    "610330": "凤县",
3477
+    "610331": "太白县"
3478
+  },
3479
+  "610400": {
3480
+    "610402": "秦都区",
3481
+    "610403": "杨陵区",
3482
+    "610404": "渭城区",
3483
+    "610422": "三原县",
3484
+    "610423": "泾阳县",
3485
+    "610424": "乾县",
3486
+    "610425": "礼泉县",
3487
+    "610426": "永寿县",
3488
+    "610427": "彬县",
3489
+    "610428": "长武县",
3490
+    "610429": "旬邑县",
3491
+    "610430": "淳化县",
3492
+    "610431": "武功县",
3493
+    "610481": "兴平市"
3494
+  },
3495
+  "610500": {
3496
+    "610502": "临渭区",
3497
+    "610503": "华州区",
3498
+    "610522": "潼关县",
3499
+    "610523": "大荔县",
3500
+    "610524": "合阳县",
3501
+    "610525": "澄城县",
3502
+    "610526": "蒲城县",
3503
+    "610527": "白水县",
3504
+    "610528": "富平县",
3505
+    "610581": "韩城市",
3506
+    "610582": "华阴市"
3507
+  },
3508
+  "610600": {
3509
+    "610602": "宝塔区",
3510
+    "610603": "安塞区",
3511
+    "610621": "延长县",
3512
+    "610622": "延川县",
3513
+    "610623": "子长县",
3514
+    "610625": "志丹县",
3515
+    "610626": "吴起县",
3516
+    "610627": "甘泉县",
3517
+    "610628": "富县",
3518
+    "610629": "洛川县",
3519
+    "610630": "宜川县",
3520
+    "610631": "黄龙县",
3521
+    "610632": "黄陵县"
3522
+  },
3523
+  "610700": {
3524
+    "610702": "汉台区",
3525
+    "610721": "南郑县",
3526
+    "610722": "城固县",
3527
+    "610723": "洋县",
3528
+    "610724": "西乡县",
3529
+    "610725": "勉县",
3530
+    "610726": "宁强县",
3531
+    "610727": "略阳县",
3532
+    "610728": "镇巴县",
3533
+    "610729": "留坝县",
3534
+    "610730": "佛坪县"
3535
+  },
3536
+  "610800": {
3537
+    "610802": "榆阳区",
3538
+    "610803": "横山区",
3539
+    "610821": "神木县",
3540
+    "610822": "府谷县",
3541
+    "610824": "靖边县",
3542
+    "610825": "定边县",
3543
+    "610826": "绥德县",
3544
+    "610827": "米脂县",
3545
+    "610828": "佳县",
3546
+    "610829": "吴堡县",
3547
+    "610830": "清涧县",
3548
+    "610831": "子洲县"
3549
+  },
3550
+  "610900": {
3551
+    "610902": "汉滨区",
3552
+    "610921": "汉阴县",
3553
+    "610922": "石泉县",
3554
+    "610923": "宁陕县",
3555
+    "610924": "紫阳县",
3556
+    "610925": "岚皋县",
3557
+    "610926": "平利县",
3558
+    "610927": "镇坪县",
3559
+    "610928": "旬阳县",
3560
+    "610929": "白河县"
3561
+  },
3562
+  "611000": {
3563
+    "611002": "商州区",
3564
+    "611021": "洛南县",
3565
+    "611022": "丹凤县",
3566
+    "611023": "商南县",
3567
+    "611024": "山阳县",
3568
+    "611025": "镇安县",
3569
+    "611026": "柞水县"
3570
+  },
3571
+  "620000": {
3572
+    "620100": "兰州市",
3573
+    "620200": "嘉峪关市",
3574
+    "620300": "金昌市",
3575
+    "620400": "白银市",
3576
+    "620500": "天水市",
3577
+    "620600": "武威市",
3578
+    "620700": "张掖市",
3579
+    "620800": "平凉市",
3580
+    "620900": "酒泉市",
3581
+    "621000": "庆阳市",
3582
+    "621100": "定西市",
3583
+    "621200": "陇南市",
3584
+    "622900": "临夏回族自治州",
3585
+    "623000": "甘南藏族自治州"
3586
+  },
3587
+  "620100": {
3588
+    "620102": "城关区",
3589
+    "620103": "七里河区",
3590
+    "620104": "西固区",
3591
+    "620105": "安宁区",
3592
+    "620111": "红古区",
3593
+    "620121": "永登县",
3594
+    "620122": "皋兰县",
3595
+    "620123": "榆中县"
3596
+  },
3597
+  "620300": {
3598
+    "620302": "金川区",
3599
+    "620321": "永昌县"
3600
+  },
3601
+  "620400": {
3602
+    "620402": "白银区",
3603
+    "620403": "平川区",
3604
+    "620421": "靖远县",
3605
+    "620422": "会宁县",
3606
+    "620423": "景泰县"
3607
+  },
3608
+  "620500": {
3609
+    "620502": "秦州区",
3610
+    "620503": "麦积区",
3611
+    "620521": "清水县",
3612
+    "620522": "秦安县",
3613
+    "620523": "甘谷县",
3614
+    "620524": "武山县",
3615
+    "620525": "张家川回族自治县"
3616
+  },
3617
+  "620600": {
3618
+    "620602": "凉州区",
3619
+    "620621": "民勤县",
3620
+    "620622": "古浪县",
3621
+    "620623": "天祝藏族自治县"
3622
+  },
3623
+  "620700": {
3624
+    "620702": "甘州区",
3625
+    "620721": "肃南裕固族自治县",
3626
+    "620722": "民乐县",
3627
+    "620723": "临泽县",
3628
+    "620724": "高台县",
3629
+    "620725": "山丹县"
3630
+  },
3631
+  "620800": {
3632
+    "620802": "崆峒区",
3633
+    "620821": "泾川县",
3634
+    "620822": "灵台县",
3635
+    "620823": "崇信县",
3636
+    "620824": "华亭县",
3637
+    "620825": "庄浪县",
3638
+    "620826": "静宁县"
3639
+  },
3640
+  "620900": {
3641
+    "620902": "肃州区",
3642
+    "620921": "金塔县",
3643
+    "620922": "瓜州县",
3644
+    "620923": "肃北蒙古族自治县",
3645
+    "620924": "阿克塞哈萨克族自治县",
3646
+    "620981": "玉门市",
3647
+    "620982": "敦煌市"
3648
+  },
3649
+  "621000": {
3650
+    "621002": "西峰区",
3651
+    "621021": "庆城县",
3652
+    "621022": "环县",
3653
+    "621023": "华池县",
3654
+    "621024": "合水县",
3655
+    "621025": "正宁县",
3656
+    "621026": "宁县",
3657
+    "621027": "镇原县"
3658
+  },
3659
+  "621100": {
3660
+    "621102": "安定区",
3661
+    "621121": "通渭县",
3662
+    "621122": "陇西县",
3663
+    "621123": "渭源县",
3664
+    "621124": "临洮县",
3665
+    "621125": "漳县",
3666
+    "621126": "岷县"
3667
+  },
3668
+  "621200": {
3669
+    "621202": "武都区",
3670
+    "621221": "成县",
3671
+    "621222": "文县",
3672
+    "621223": "宕昌县",
3673
+    "621224": "康县",
3674
+    "621225": "西和县",
3675
+    "621226": "礼县",
3676
+    "621227": "徽县",
3677
+    "621228": "两当县"
3678
+  },
3679
+  "622900": {
3680
+    "622901": "临夏市",
3681
+    "622921": "临夏县",
3682
+    "622922": "康乐县",
3683
+    "622923": "永靖县",
3684
+    "622924": "广河县",
3685
+    "622925": "和政县",
3686
+    "622926": "东乡族自治县",
3687
+    "622927": "积石山保安族东乡族撒拉族自治县"
3688
+  },
3689
+  "623000": {
3690
+    "623001": "合作市",
3691
+    "623021": "临潭县",
3692
+    "623022": "卓尼县",
3693
+    "623023": "舟曲县",
3694
+    "623024": "迭部县",
3695
+    "623025": "玛曲县",
3696
+    "623026": "碌曲县",
3697
+    "623027": "夏河县"
3698
+  },
3699
+  "630000": {
3700
+    "630100": "西宁市",
3701
+    "630200": "海东市",
3702
+    "632200": "海北藏族自治州",
3703
+    "632300": "黄南藏族自治州",
3704
+    "632500": "海南藏族自治州",
3705
+    "632600": "果洛藏族自治州",
3706
+    "632700": "玉树藏族自治州",
3707
+    "632800": "海西蒙古族藏族自治州"
3708
+  },
3709
+  "630100": {
3710
+    "630102": "城东区",
3711
+    "630103": "城中区",
3712
+    "630104": "城西区",
3713
+    "630105": "城北区",
3714
+    "630121": "大通回族土族自治县",
3715
+    "630122": "湟中县",
3716
+    "630123": "湟源县"
3717
+  },
3718
+  "630200": {
3719
+    "630202": "乐都区",
3720
+    "630203": "平安区",
3721
+    "630222": "民和回族土族自治县",
3722
+    "630223": "互助土族自治县",
3723
+    "630224": "化隆回族自治县",
3724
+    "630225": "循化撒拉族自治县"
3725
+  },
3726
+  "632200": {
3727
+    "632221": "门源回族自治县",
3728
+    "632222": "祁连县",
3729
+    "632223": "海晏县",
3730
+    "632224": "刚察县"
3731
+  },
3732
+  "632300": {
3733
+    "632321": "同仁县",
3734
+    "632322": "尖扎县",
3735
+    "632323": "泽库县",
3736
+    "632324": "河南蒙古族自治县"
3737
+  },
3738
+  "632500": {
3739
+    "632521": "共和县",
3740
+    "632522": "同德县",
3741
+    "632523": "贵德县",
3742
+    "632524": "兴海县",
3743
+    "632525": "贵南县"
3744
+  },
3745
+  "632600": {
3746
+    "632621": "玛沁县",
3747
+    "632622": "班玛县",
3748
+    "632623": "甘德县",
3749
+    "632624": "达日县",
3750
+    "632625": "久治县",
3751
+    "632626": "玛多县"
3752
+  },
3753
+  "632700": {
3754
+    "632701": "玉树市",
3755
+    "632722": "杂多县",
3756
+    "632723": "称多县",
3757
+    "632724": "治多县",
3758
+    "632725": "囊谦县",
3759
+    "632726": "曲麻莱县"
3760
+  },
3761
+  "632800": {
3762
+    "632801": "格尔木市",
3763
+    "632802": "德令哈市",
3764
+    "632821": "乌兰县",
3765
+    "632822": "都兰县",
3766
+    "632823": "天峻县"
3767
+  },
3768
+  "640000": {
3769
+    "640100": "银川市",
3770
+    "640200": "石嘴山市",
3771
+    "640300": "吴忠市",
3772
+    "640400": "固原市",
3773
+    "640500": "中卫市"
3774
+  },
3775
+  "640100": {
3776
+    "640104": "兴庆区",
3777
+    "640105": "西夏区",
3778
+    "640106": "金凤区",
3779
+    "640121": "永宁县",
3780
+    "640122": "贺兰县",
3781
+    "640181": "灵武市"
3782
+  },
3783
+  "640200": {
3784
+    "640202": "大武口区",
3785
+    "640205": "惠农区",
3786
+    "640221": "平罗县"
3787
+  },
3788
+  "640300": {
3789
+    "640302": "利通区",
3790
+    "640303": "红寺堡区",
3791
+    "640323": "盐池县",
3792
+    "640324": "同心县",
3793
+    "640381": "青铜峡市"
3794
+  },
3795
+  "640400": {
3796
+    "640402": "原州区",
3797
+    "640422": "西吉县",
3798
+    "640423": "隆德县",
3799
+    "640424": "泾源县",
3800
+    "640425": "彭阳县"
3801
+  },
3802
+  "640500": {
3803
+    "640502": "沙坡头区",
3804
+    "640521": "中宁县",
3805
+    "640522": "海原县"
3806
+  },
3807
+  "650000": {
3808
+    "650100": "乌鲁木齐市",
3809
+    "650200": "克拉玛依市",
3810
+    "650400": "吐鲁番市",
3811
+    "650500": "哈密市",
3812
+    "652300": "昌吉回族自治州",
3813
+    "652700": "博尔塔拉蒙古自治州",
3814
+    "652800": "巴音郭楞蒙古自治州",
3815
+    "652900": "阿克苏地区",
3816
+    "653000": "克孜勒苏柯尔克孜自治州",
3817
+    "653100": "喀什地区",
3818
+    "653200": "和田地区",
3819
+    "654000": "伊犁哈萨克自治州",
3820
+    "654200": "塔城地区",
3821
+    "654300": "阿勒泰地区",
3822
+    "659001": "石河子市",
3823
+    "659002": "阿拉尔市",
3824
+    "659003": "图木舒克市",
3825
+    "659004": "五家渠市",
3826
+    "659006": "铁门关市"
3827
+  },
3828
+  "650100": {
3829
+    "650102": "天山区",
3830
+    "650103": "沙依巴克区",
3831
+    "650104": "新市区",
3832
+    "650105": "水磨沟区",
3833
+    "650106": "头屯河区",
3834
+    "650107": "达坂城区",
3835
+    "650109": "米东区",
3836
+    "650121": "乌鲁木齐县"
3837
+  },
3838
+  "650200": {
3839
+    "650202": "独山子区",
3840
+    "650203": "克拉玛依区",
3841
+    "650204": "白碱滩区",
3842
+    "650205": "乌尔禾区"
3843
+  },
3844
+  "650400": {
3845
+    "650402": "高昌区",
3846
+    "650421": "鄯善县",
3847
+    "650422": "托克逊县"
3848
+  },
3849
+  "650500": {
3850
+    "650502": "伊州区",
3851
+    "650521": "巴里坤哈萨克自治县",
3852
+    "650522": "伊吾县"
3853
+  },
3854
+  "652300": {
3855
+    "652301": "昌吉市",
3856
+    "652302": "阜康市",
3857
+    "652323": "呼图壁县",
3858
+    "652324": "玛纳斯县",
3859
+    "652325": "奇台县",
3860
+    "652327": "吉木萨尔县",
3861
+    "652328": "木垒哈萨克自治县"
3862
+  },
3863
+  "652700": {
3864
+    "652701": "博乐市",
3865
+    "652702": "阿拉山口市",
3866
+    "652722": "精河县",
3867
+    "652723": "温泉县"
3868
+  },
3869
+  "652800": {
3870
+    "652801": "库尔勒市",
3871
+    "652822": "轮台县",
3872
+    "652823": "尉犁县",
3873
+    "652824": "若羌县",
3874
+    "652825": "且末县",
3875
+    "652826": "焉耆回族自治县",
3876
+    "652827": "和静县",
3877
+    "652828": "和硕县",
3878
+    "652829": "博湖县"
3879
+  },
3880
+  "652900": {
3881
+    "652901": "阿克苏市",
3882
+    "652922": "温宿县",
3883
+    "652923": "库车县",
3884
+    "652924": "沙雅县",
3885
+    "652925": "新和县",
3886
+    "652926": "拜城县",
3887
+    "652927": "乌什县",
3888
+    "652928": "阿瓦提县",
3889
+    "652929": "柯坪县"
3890
+  },
3891
+  "653000": {
3892
+    "653001": "阿图什市",
3893
+    "653022": "阿克陶县",
3894
+    "653023": "阿合奇县",
3895
+    "653024": "乌恰县"
3896
+  },
3897
+  "653100": {
3898
+    "653101": "喀什市",
3899
+    "653121": "疏附县",
3900
+    "653122": "疏勒县",
3901
+    "653123": "英吉沙县",
3902
+    "653124": "泽普县",
3903
+    "653125": "莎车县",
3904
+    "653126": "叶城县",
3905
+    "653127": "麦盖提县",
3906
+    "653128": "岳普湖县",
3907
+    "653129": "伽师县",
3908
+    "653130": "巴楚县",
3909
+    "653131": "塔什库尔干塔吉克自治县"
3910
+  },
3911
+  "653200": {
3912
+    "653201": "和田市",
3913
+    "653221": "和田县",
3914
+    "653222": "墨玉县",
3915
+    "653223": "皮山县",
3916
+    "653224": "洛浦县",
3917
+    "653225": "策勒县",
3918
+    "653226": "于田县",
3919
+    "653227": "民丰县"
3920
+  },
3921
+  "654000": {
3922
+    "654002": "伊宁市",
3923
+    "654003": "奎屯市",
3924
+    "654004": "霍尔果斯市",
3925
+    "654021": "伊宁县",
3926
+    "654022": "察布查尔锡伯自治县",
3927
+    "654023": "霍城县",
3928
+    "654024": "巩留县",
3929
+    "654025": "新源县",
3930
+    "654026": "昭苏县",
3931
+    "654027": "特克斯县",
3932
+    "654028": "尼勒克县"
3933
+  },
3934
+  "654200": {
3935
+    "654201": "塔城市",
3936
+    "654202": "乌苏市",
3937
+    "654221": "额敏县",
3938
+    "654223": "沙湾县",
3939
+    "654224": "托里县",
3940
+    "654225": "裕民县",
3941
+    "654226": "和布克赛尔蒙古自治县"
3942
+  },
3943
+  "654300": {
3944
+    "654301": "阿勒泰市",
3945
+    "654321": "布尔津县",
3946
+    "654322": "富蕴县",
3947
+    "654323": "福海县",
3948
+    "654324": "哈巴河县",
3949
+    "654325": "青河县",
3950
+    "654326": "吉木乃县"
3951
+  },
3952
+  "810000": {
3953
+    "810001": "中西區",
3954
+    "810002": "灣仔區",
3955
+    "810003": "東區",
3956
+    "810004": "南區",
3957
+    "810005": "油尖旺區",
3958
+    "810006": "深水埗區",
3959
+    "810007": "九龍城區",
3960
+    "810008": "黃大仙區",
3961
+    "810009": "觀塘區",
3962
+    "810010": "荃灣區",
3963
+    "810011": "屯門區",
3964
+    "810012": "元朗區",
3965
+    "810013": "北區",
3966
+    "810014": "大埔區",
3967
+    "810015": "西貢區",
3968
+    "810016": "沙田區",
3969
+    "810017": "葵青區",
3970
+    "810018": "離島區"
3971
+  },
3972
+  "820000": {
3973
+    "820001": "花地瑪堂區",
3974
+    "820002": "花王堂區",
3975
+    "820003": "望德堂區",
3976
+    "820004": "大堂區",
3977
+    "820005": "風順堂區",
3978
+    "820006": "嘉模堂區",
3979
+    "820007": "路氹填海區",
3980
+    "820008": "聖方濟各堂區"
3981
+  }
3982
+}

+ 7 - 0
data/tests.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.test import TestCase
5
+
6
+
7
+# Create your tests here.

+ 7 - 0
data/views.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.shortcuts import render
5
+
6
+
7
+# Create your views here.

+ 0 - 0
docs/COMMANDS.md


+ 2 - 0
docs/CRONTAB.md

@@ -0,0 +1,2 @@
1
+# 定时任务
2
+# m h  dom mon dow   command

+ 3 - 0
isort.sh

@@ -0,0 +1,3 @@
1
+#!/bin/bash
2
+
3
+isort .

+ 23 - 0
manage.py

@@ -0,0 +1,23 @@
1
+#!/usr/bin/env python
2
+import os
3
+import sys
4
+
5
+
6
+if __name__ == "__main__":
7
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thermometer.settings")
8
+    try:
9
+        from django.core.management import execute_from_command_line
10
+    except ImportError:
11
+        # The above import may fail for some other reason. Ensure that the
12
+        # issue is really that Django is missing to avoid masking other
13
+        # exceptions on Python 2.
14
+        try:
15
+            import django
16
+        except ImportError:
17
+            raise ImportError(
18
+                "Couldn't import Django. Are you sure it's installed and "
19
+                "available on your PYTHONPATH environment variable? Did you "
20
+                "forget to activate a virtual environment?"
21
+            )
22
+        raise
23
+    execute_from_command_line(sys.argv)

+ 10 - 0
pep8.sh

@@ -0,0 +1,10 @@
1
+#!/bin/bash
2
+
3
+# Ignoring autogenerated files
4
+#  -- Migration directories
5
+# Ignoring error codes
6
+#  -- E128 continuation line under-indented for visual indent
7
+#  -- E402 module level import not at top of file
8
+#  -- E501 line too long
9
+
10
+pycodestyle --exclude=build,migrations,.tox --ignore=E128,E402,E501 .

+ 8 - 0
requirements.txt

@@ -0,0 +1,8 @@
1
+StatusCode==1.0.0
2
+furl==2.1.2
3
+jsonfield==3.1.0
4
+mysqlclient==2.0.3
5
+rlog==0.3
6
+-r requirements_dj.txt
7
+-r requirements_pywe.txt
8
+-r requirements_redis.txt

+ 3 - 0
requirements_deploy.txt

@@ -0,0 +1,3 @@
1
+ipdb==0.13.3
2
+ipython==7.18.1
3
+uwsgi==2.0.19.1

+ 2 - 0
requirements_dev.txt

@@ -0,0 +1,2 @@
1
+isort==5.4.2
2
+pycodestyle==2.6.0

+ 15 - 0
requirements_dj.txt

@@ -0,0 +1,15 @@
1
+Django==3.2.4
2
+django-admin==2.0.1
3
+django-detect==1.0.20
4
+django-file==1.0.4
5
+django-json-render==1.0.3
6
+django-json-response==1.1.5
7
+django-logit==1.1.3
8
+django-models-ext==1.1.10
9
+django-redis-connector==1.0.4
10
+django-response==1.1.1
11
+django-rlog==1.0.7
12
+django-short-url==1.1.6
13
+django-six==1.0.4
14
+django-uniapi==1.0.10
15
+django-we==1.5.6

+ 2 - 0
requirements_pywe.txt

@@ -0,0 +1,2 @@
1
+pywe-oauth==1.1.1
2
+pywe-pay==1.0.14

+ 3 - 0
requirements_redis.txt

@@ -0,0 +1,3 @@
1
+hiredis==2.0.0
2
+redis==3.5.3
3
+redis-extensions==2.0.7

+ 4 - 0
sysctl.sh

@@ -0,0 +1,4 @@
1
+#!/bin/bash
2
+
3
+sudo sysctl -w net.core.somaxconn=65535
4
+sudo sysctl -w net.core.netdev_max_backlog=65535

+ 0 - 0
thermometer/__init__.py


+ 26 - 0
thermometer/basemodels.py

@@ -0,0 +1,26 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+
6
+
7
+class BaseModelMixin(models.Model):
8
+    status = models.BooleanField(_(u'status'), default=True, help_text=_(u'状态'))
9
+    created_at = models.DateTimeField(_(u'created_at'), auto_now_add=True, editable=True, help_text=_(u'创建时间'))
10
+    updated_at = models.DateTimeField(_(u'updated_at'), auto_now=True, editable=True, help_text=_(u'更新时间'))
11
+
12
+    class Meta:
13
+        abstract = True
14
+
15
+
16
+class SexChoicesMixin(models.Model):
17
+    MALE = 1
18
+    FEMALE = 0
19
+
20
+    SEX_TYPE = (
21
+        (MALE, u'男'),
22
+        (FEMALE, u'女'),
23
+    )
24
+
25
+    class Meta:
26
+        abstract = True

+ 93 - 0
thermometer/decorators.py

@@ -0,0 +1,93 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from functools import wraps
4
+
5
+from django.conf import settings
6
+from django.shortcuts import redirect
7
+from furl import furl
8
+from pywe_oauth import get_oauth_redirect_url
9
+from pywe_sign import check_signature
10
+
11
+from utils.error.errno_utils import SignatureStatusCode
12
+from utils.error.response_utils import response
13
+from utils.redis.connect import r
14
+
15
+
16
+def check_user_cookie(func=None, key=settings.COOKIE_USER_CHECK_KEY):
17
+    def decorator(func):
18
+        @wraps(func)
19
+        def returned_wrapper(request, *args, **kwargs):
20
+            user_id = request.get_signed_cookie(key, default='', salt=settings.COOKIE_SALT)
21
+            if not user_id:
22
+                return redirect(get_oauth_redirect_url(settings.WECHAT_OAUTH2_REDIRECT_URI, 'snsapi_userinfo', request.get_full_path()))
23
+            return func(request, *args, **kwargs)
24
+        return returned_wrapper
25
+
26
+    if not func:
27
+        def foo(func):
28
+            return decorator(func)
29
+        return foo
30
+
31
+    return decorator(func)
32
+
33
+
34
+def check_token(func=None, entry=None):
35
+    def decorator(func):
36
+        @wraps(func)
37
+        def returned_wrapper(request, *args, **kwargs):
38
+            if not settings.DEBUG and request.wechat:
39
+                vtoken = request.GET.get('vtoken', '') or request.POST.get('vtoken', '')
40
+                token_check_key = request.GET.get(settings.TOKEN_CHECK_KEY, '') or request.POST.get(settings.TOKEN_CHECK_KEY, '')
41
+                if not r.token_exists(token_check_key, vtoken):
42
+                    # 3rd OAuth
43
+                    # return redirect(settings.WECHAT_OAUTH2_REDIRECT_URL)
44
+                    # Current OAuth
45
+                    redirect_url = furl(entry or settings.WECHAT_OAUTH2_REDIRECT_ENTRY).add({}).url
46
+                    return redirect(get_oauth_redirect_url(settings.WECHAT_OAUTH2_REDIRECT_URI, 'snsapi_userinfo', redirect_url))
47
+            return func(request, *args, **kwargs)
48
+        return returned_wrapper
49
+
50
+    if not func:
51
+        def foo(func):
52
+            return decorator(func)
53
+        return foo
54
+
55
+    return decorator(func)
56
+
57
+
58
+def check_sign(func=None, method='POST'):
59
+    def decorator(func):
60
+        @wraps(func)
61
+        def returned_wrapper(request, *args, **kwargs):
62
+            if not settings.DEBUG and not check_signature(getattr(request, method).dict(), settings.PARAMS_SIGN_KEY):
63
+                return response(SignatureStatusCode.SIGNATURE_ERROR)
64
+            return func(request, *args, **kwargs)
65
+        return returned_wrapper
66
+
67
+    if not func:
68
+        def foo(func):
69
+            return decorator(func)
70
+        return foo
71
+
72
+    return decorator(func)
73
+
74
+
75
+def check_cookie(func=None, entry=None):
76
+    def decorator(func):
77
+        @wraps(func)
78
+        def returned_wrapper(request, *args, **kwargs):
79
+            if not settings.DEBUG and not request.COOKIES.get('user_id'):
80
+                # 3rd OAuth
81
+                # return redirect(settings.WECHAT_OAUTH2_REDIRECT_URL)
82
+                # Current OAuth
83
+                redirect_url = furl(entry or settings.WECHAT_OAUTH2_REDIRECT_ENTRY).add({}).url
84
+                return redirect(get_oauth_redirect_url(settings.WECHAT_OAUTH2_REDIRECT_URI, 'snsapi_userinfo', redirect_url))
85
+            return func(request, *args, **kwargs)
86
+        return returned_wrapper
87
+
88
+    if not func:
89
+        def foo(func):
90
+            return decorator(func)
91
+        return foo
92
+
93
+    return decorator(func)

+ 12 - 0
thermometer/deploy.bak/supervisor_commands/pollqueue.ini

@@ -0,0 +1,12 @@
1
+[program:pollqueue]
2
+command=/home/diors/env/bin/python /home/diors/work/thermometer/manage.py poll_queue
3
+autostart=true
4
+autorestart=true
5
+startretries=3
6
+exitcodes=0,1,2
7
+stopsignal=KILL
8
+stopasgroup=true
9
+killasgroup=true
10
+stdout_logfile=/var/log/supervisor_pollqueue_access.log
11
+stderr_logfile=/var/log/supervisor_pollqueue_error.log
12
+user=diors

+ 12 - 0
thermometer/deploy.bak/supervisor_commands/rlistlog.ini

@@ -0,0 +1,12 @@
1
+[program:rlistlog]
2
+command=/home/diors/env/bin/python /home/diors/work/thermometer/manage.py rlistlog --key=django:logit:thermometer --filename=/tmp/thermometer.logit.log
3
+autostart=true
4
+autorestart=true
5
+startretries=3
6
+exitcodes=0,1,2
7
+stopsignal=KILL
8
+stopasgroup=true
9
+killasgroup=true
10
+stdout_logfile=/var/log/supervisor_rlistlog_access.log
11
+stderr_logfile=/var/log/supervisor_rlistlog_error.log
12
+user=diors

+ 35 - 0
thermometer/deploy.bak/templet.ini

@@ -0,0 +1,35 @@
1
+# Refer: https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html
2
+# thermometer_uwsgi.ini file
3
+[uwsgi]
4
+
5
+# Django-related settings
6
+# the base directory (full path)
7
+chdir           = /home/diors/work/thermometer
8
+# Django's wsgi file
9
+module          = thermometer.wsgi
10
+# the virtualenv (full path)
11
+# home            = /path/to/virtualenv
12
+
13
+# process-related settings
14
+# master
15
+master          = true
16
+# maximum number of worker processes
17
+processes       = 10
18
+# the socket (use the full path to be safe
19
+socket          = /home/diors/work/thermometer/thermometer/deploy/thermometer.sock
20
+# ... with appropriate permissions - may be needed
21
+chmod-socket    = 777
22
+# clear environment on exit
23
+vacuum          = true
24
+
25
+# connect() to unix:///home/xxx/xxx.sock failed (11: Resource temporarily unavailable) while connecting to upstream
26
+# Exec sysctl.sh first
27
+# #!/bin/bash
28
+# sudo sysctl -w net.core.somaxconn=65535
29
+# sudo sysctl -w net.core.netdev_max_backlog=65535
30
+reload-mercy    = 64
31
+max-requests    = 8192
32
+listen          = 8192
33
+
34
+# recv() failed (104: Connection reset by peer) while reading response header from upstream
35
+buffer-size     = 65535

+ 35 - 0
thermometer/deploy.bak/templet2.ini

@@ -0,0 +1,35 @@
1
+# Refer: https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html
2
+# thermometer_uwsgi.ini file
3
+[uwsgi]
4
+
5
+# Django-related settings
6
+# the base directory (full path)
7
+chdir           = /home/diors/work/thermometer
8
+# Django's wsgi file
9
+module          = thermometer.wsgi
10
+# the virtualenv (full path)
11
+# home            = /path/to/virtualenv
12
+
13
+# process-related settings
14
+# master
15
+master          = true
16
+# maximum number of worker processes
17
+processes       = 10
18
+# the socket (use the full path to be safe
19
+socket          = /home/diors/work/thermometer/thermometer/deploy/thermometer2.sock
20
+# ... with appropriate permissions - may be needed
21
+chmod-socket    = 777
22
+# clear environment on exit
23
+vacuum          = true
24
+
25
+# connect() to unix:///home/xxx/xxx.sock failed (11: Resource temporarily unavailable) while connecting to upstream
26
+# Exec sysctl.sh first
27
+# #!/bin/bash
28
+# sudo sysctl -w net.core.somaxconn=65535
29
+# sudo sysctl -w net.core.netdev_max_backlog=65535
30
+reload-mercy    = 64
31
+max-requests    = 8192
32
+listen          = 8192
33
+
34
+# recv() failed (104: Connection reset by peer) while reading response header from upstream
35
+buffer-size     = 65535

+ 96 - 0
thermometer/deploy.bak/templet_nginx.conf

@@ -0,0 +1,96 @@
1
+# thermometer_nginx.conf
2
+
3
+# the upstream component nginx needs to connect to
4
+upstream thermometer {
5
+    # Single Server
6
+    # server unix:///home/diors/work/thermometer/thermometer/deploy/thermometer.sock; # for a file socket
7
+    # Multi Server
8
+    # server unix:///home/diors/work/thermometer/thermometer/deploy/thermometer.sock max_fails=0 weight=1; # for a file socket
9
+    # server unix:///home/diors/work/thermometer/thermometer/deploy/thermometer2.sock max_fails=0 weight=1; # for a file socket
10
+    server 127.0.0.1:8888; # for a web port socket (we'll use this first)
11
+}
12
+
13
+# configuration of the server
14
+server {
15
+    # the port your site will be served on
16
+    listen      80;
17
+    # the domain name it will serve for
18
+    server_name .a.com; # substitute your machine's IP address or FQDN
19
+    charset     utf-8;
20
+
21
+    # access_log off;  # 设置是否存储访问日志
22
+    # access_log /var/log/nginx/thermometer_access.log;
23
+    # error_log /var/log/nginx/thermometer_error.log;
24
+
25
+    # max upload size
26
+    client_max_body_size 75M;   # adjust to taste
27
+
28
+    # JS接口安全域名 & 业务域名 验证
29
+    location /xxx.txt {
30
+        alias /home/diors/work/thermometer/docs/we/xxx.txt;
31
+    }
32
+
33
+    # Django media
34
+    location /media  {
35
+        alias /home/diors/work/thermometer/media;  # your Django project's media files - amend as required
36
+    }
37
+
38
+    location /static {
39
+        alias /home/diors/work/thermometer/collect_static; # your Django project's static files - amend as required
40
+    }
41
+
42
+    # Finally, send all non-media requests to the Django server.
43
+    location / {
44
+        # uwsgi_pass  thermometer;
45
+        proxy_pass  http://thermometer;
46
+        include     /home/diors/work/thermometer/thermometer/deploy/uwsgi_params; # the uwsgi_params file you installed
47
+    }
48
+}
49
+
50
+# configuration of the server
51
+server {
52
+    # the port your site will be served on
53
+    listen      443;
54
+    # the domain name it will serve for
55
+    server_name .a.com; # substitute your machine's IP address or FQDN
56
+    charset     utf-8;
57
+
58
+    # access_log /var/log/nginx/thermometer_ssl_access.log;
59
+    # error_log /var/log/nginx/thermometer_ssl_error.log;
60
+
61
+    ssl on;
62
+    ssl_certificate   cert/214180103970874.pem;
63
+    ssl_certificate_key  cert/214180103970874.key;
64
+    ssl_session_timeout 5m;
65
+    # worker process * exited on signal 11
66
+    # 同一台服务器部署多个 SSL 转发,Nginx 默认是开启 Session 缓存的,导致冲突,验证不通过,连接直接退出
67
+    # 解决方案:禁用 Ningx SSL Session 的缓存
68
+    ssl_session_cache none;
69
+    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
70
+    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
71
+    ssl_prefer_server_ciphers on;
72
+
73
+    # max upload size
74
+    client_max_body_size 75M;   # adjust to taste
75
+
76
+    # JS接口安全域名 & 业务域名 验证
77
+    location /xxx.txt {
78
+        alias /home/diors/work/thermometer/docs/we/xxx.txt;
79
+    }
80
+
81
+    # Django media
82
+    location /media  {
83
+        alias /home/diors/work/thermometer/media;  # your Django project's media files - amend as required
84
+    }
85
+
86
+    location /static {
87
+        alias /home/diors/work/thermometer/collect_static; # your Django project's static files - amend as required
88
+    }
89
+
90
+    # Finally, send all non-media requests to the Django server.
91
+    location / {
92
+        # uwsgi_pass  thermometer;
93
+        proxy_pass  http://thermometer;
94
+        include     /home/diors/work/thermometer/thermometer/deploy/uwsgi_params; # the uwsgi_params file you installed
95
+    }
96
+}

+ 12 - 0
thermometer/deploy.bak/templet_supervisor.ini

@@ -0,0 +1,12 @@
1
+[program:thermometer]
2
+command=/home/diors/env/bin/uwsgi --ini /home/diors/work/thermometer/thermometer/deploy/thermometer.ini
3
+autostart=true
4
+autorestart=true
5
+startretries=3
6
+exitcodes=0,1,2
7
+stopsignal=KILL
8
+stopasgroup=true
9
+killasgroup=true
10
+stdout_logfile=/var/log/supervisor_thermometer_access.log
11
+stderr_logfile=/var/log/supervisor_thermometer_error.log
12
+user=diors

+ 12 - 0
thermometer/deploy.bak/templet_supervisor2.ini

@@ -0,0 +1,12 @@
1
+[program:thermometer2]
2
+command=/home/diors/env/bin/uwsgi --ini /home/diors/work/thermometer/thermometer/deploy/thermometer2.ini
3
+autostart=true
4
+autorestart=true
5
+startretries=3
6
+exitcodes=0,1,2
7
+stopsignal=KILL
8
+stopasgroup=true
9
+killasgroup=true
10
+stdout_logfile=/var/log/supervisor_thermometer2_access.log
11
+stderr_logfile=/var/log/supervisor_thermometer2_error.log
12
+user=diors

+ 15 - 0
thermometer/deploy.bak/uwsgi_params

@@ -0,0 +1,15 @@
1
+uwsgi_param	QUERY_STRING		$query_string;
2
+uwsgi_param	REQUEST_METHOD		$request_method;
3
+uwsgi_param	CONTENT_TYPE		$content_type;
4
+uwsgi_param	CONTENT_LENGTH		$content_length;
5
+
6
+uwsgi_param	REQUEST_URI		$request_uri;
7
+uwsgi_param	PATH_INFO		$document_uri;
8
+uwsgi_param	DOCUMENT_ROOT		$document_root;
9
+uwsgi_param	SERVER_PROTOCOL		$server_protocol;
10
+uwsgi_param	UWSGI_SCHEME		$scheme;
11
+
12
+uwsgi_param	REMOTE_ADDR		$remote_addr;
13
+uwsgi_param	REMOTE_PORT		$remote_port;
14
+uwsgi_param	SERVER_PORT		$server_port;
15
+uwsgi_param	SERVER_NAME		$server_name;

+ 5 - 0
thermometer/django_file_callback_settings.py

@@ -0,0 +1,5 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+
4
+def DJANGO_FILE_UPLOAD_CALLBACK_FUNC(request, file_path=None, file_url=None):
5
+    """ DJANGO FILE UPLOAD Callback Func """

+ 84 - 0
thermometer/django_we_callback_settings.py

@@ -0,0 +1,84 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+
4
+def DJANGO_WE_CFG_FUNC(request, state=None):
5
+    """ WeChat CFG Callback Func """
6
+
7
+
8
+def DJANGO_WE_QUOTE_STATE_FUNC(request, state):
9
+    """ WeChat Quote Callback Func """
10
+    from utils.redis.connect import r
11
+    return r.quote(state, short_uuid=True)
12
+
13
+
14
+def DJANGO_WE_UNQUOTE_STATE_FUNC(request, state):
15
+    """ WeChat UnQuote Callback Func """
16
+    from utils.redis.connect import r
17
+
18
+    # If Not Buf, When Wechat Multi Request, Unquote Will Get None
19
+    # Then Once Should ReOAuth, Will Raise Error
20
+    return r.unquote(state, buf=True) or state
21
+
22
+
23
+def DJANGO_WE_BASE_FUNC(code, state, access_info=None):
24
+    """ WeChat Base Redirect Callback Func """
25
+
26
+
27
+def DJANGO_WE_BASE_COOKIE_FUNC(code, state, access_info=None):
28
+    """ WeChat Base Set Cookie Redirect Callback Func """
29
+
30
+
31
+def DJANGO_WE_USERINFO_FUNC(code, state, access_info=None, userinfo=None):
32
+    """ WeChat Userinfo Redirect Callback Func """
33
+    from django.conf import settings
34
+
35
+    from utils.redis.connect import r
36
+    from utils.user.userinfo_save import userinfo_save
37
+
38
+    # Save profile or something else
39
+    user = userinfo_save(userinfo)
40
+
41
+    token_check_key = getattr(user, settings.TOKEN_CHECK_KEY)
42
+
43
+    return {
44
+        settings.TOKEN_CHECK_KEY: token_check_key,
45
+        'vtoken': r.token(token_check_key, ex=True, time=r.REDIS_EXPIRED_ONE_DAY, buf=False, short_uuid=True),
46
+    }
47
+
48
+
49
+def DJANGO_WE_USERINFO_COOKIE_FUNC(code, state, access_info=None, userinfo=None):
50
+    """ WeChat Userinfo Set Cookie Redirect Callback Func """
51
+    from django.conf import settings
52
+
53
+    from utils.user.userinfo_save import userinfo_save
54
+
55
+    # Save profile or something else
56
+    user = userinfo_save(userinfo)
57
+
58
+    token_check_key = getattr(user, settings.TOKEN_CHECK_KEY)
59
+
60
+    return {}, settings.TOKEN_CHECK_KEY, token_check_key
61
+
62
+
63
+def DJANGO_WE_SHARE_FUNC(request, state=None):
64
+    """ WeChat Share Callback Func """
65
+    # from django.conf import settings
66
+    # return settings.WECHAT_OAUTH2_REDIRECT_URL
67
+
68
+
69
+def DJANGO_WE_MESSAGE_CALLBACK_FUNC(request, xmldict, decrypted):
70
+    """ WeChat Message Callback Func """
71
+
72
+
73
+def DJANGO_WE_COMPONENT_AUTH_FUNC(request, xmldict, decrypted):
74
+    """ WeChat COMPONENT Auth Func """
75
+
76
+
77
+def DJANGO_WE_COMPONENT_CALLBACK_FUNC(request, appid, xmldict, decrypted):
78
+    """ WeChat COMPONENT Callback Func """
79
+
80
+
81
+def DJANGO_WE_REDIS_OBJ_FUNC(request):
82
+    """ WeChat Redis Object Callback Func """
83
+    from utils.redis.connect import r
84
+    return r

+ 16 - 0
thermometer/func_settings.py

@@ -0,0 +1,16 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import redis_extensions as redis
4
+
5
+
6
+def redis_conf(conf):
7
+    return {
8
+        'host': conf.get('HOST', 'localhost'),
9
+        'port': conf.get('PORT', 6379),
10
+        'password': '{0}:{1}'.format(conf.get('USER', ''), conf.get('PASSWORD', '')) if conf.get('USER') else '',
11
+        'db': conf.get('db', 0),
12
+    }
13
+
14
+
15
+def redis_connect(conf):
16
+    return redis.StrictRedisExtensions(connection_pool=redis.ConnectionPool(**redis_conf(conf)))

+ 17 - 0
thermometer/local_settings_bak.py

@@ -0,0 +1,17 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+# DEBUG = False
4
+
5
+ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'thermometer']
6
+
7
+# DOMAIN
8
+DOMAIN = 'http://a.com'
9
+
10
+# 邮件设置
11
+# 只有当 DEBUG = False 的时候,才会邮件发送报错信息
12
+SERVER_EMAIL = 'error.notify@exmail.com'
13
+EMAIL_HOST_USER = 'error.notify@exmail.com'
14
+EMAIL_HOST_PASSWORD = '<^_^>pwd<^_^>'
15
+DEFAULT_FROM_EMAIL = 'error.notify <error.notify@exmail.com>'
16
+ADMINS = [('Zhang San', 'san.zhang@exmail.com'), ('Li Si', 'si.li@exmail.com')]
17
+EMAIL_SUBJECT_PREFIX = u'[Thermometer] '

+ 27 - 0
thermometer/local_settings_dev_bak.py

@@ -0,0 +1,27 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import os
4
+
5
+
6
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
7
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
8
+
9
+TEMPLATES = [
10
+    {
11
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
12
+        'DIRS': [os.path.join(BASE_DIR, 'templates')],
13
+        # 'APP_DIRS': True,
14
+        'OPTIONS': {
15
+            'context_processors': [
16
+                'django.template.context_processors.debug',
17
+                'django.template.context_processors.request',
18
+                'django.contrib.auth.context_processors.auth',
19
+                'django.contrib.messages.context_processors.messages',
20
+            ],
21
+            'loaders': [
22
+                'django.template.loaders.filesystem.Loader',
23
+                'django.template.loaders.app_directories.Loader',
24
+            ],
25
+        },
26
+    },
27
+]

+ 397 - 0
thermometer/settings.py

@@ -0,0 +1,397 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+"""
4
+Django settings for thermometer project.
5
+
6
+Generated by 'django-admin startproject' using Django 1.11.3.
7
+
8
+For more information on this file, see
9
+https://docs.djangoproject.com/en/1.11/topics/settings/
10
+
11
+For the full list of settings and their values, see
12
+https://docs.djangoproject.com/en/1.11/ref/settings/
13
+"""
14
+
15
+import os
16
+
17
+# try:
18
+#     from func_settings import redis_connect
19
+#     REDIS_CACHE = redis_connect(REDIS.get('default', {}))
20
+# except ImportError:
21
+#     REDIS_CACHE = None
22
+from django_redis_connector import connector
23
+
24
+
25
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
26
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
27
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
28
+
29
+
30
+# Quick-start development settings - unsuitable for production
31
+# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
32
+
33
+# SECURITY WARNING: keep the secret key used in production secret!
34
+SECRET_KEY = '0=hpv21&am(7(k5ab!^zjvvl=ntj)^i@7)87t47uzumt_5rq$+'
35
+
36
+# SECURITY WARNING: don't run with debug turned on in production!
37
+DEBUG = True
38
+
39
+ALLOWED_HOSTS = []
40
+
41
+
42
+# Application definition
43
+
44
+INSTALLED_APPS = [
45
+    'django.contrib.admin',
46
+    'django.contrib.auth',
47
+    'django.contrib.contenttypes',
48
+    'django.contrib.sessions',
49
+    'django.contrib.messages',
50
+    'django.contrib.staticfiles',
51
+    # 'django_file_upload',
52
+    # 'django_short_url',
53
+    'django_uniapi',
54
+    'django_admin',
55
+    'django_we',
56
+    'commands',
57
+    'api',
58
+]
59
+
60
+MIDDLEWARE = [
61
+    'django.middleware.security.SecurityMiddleware',
62
+    'django.contrib.sessions.middleware.SessionMiddleware',
63
+    'django.middleware.common.CommonMiddleware',
64
+    # 'django.middleware.csrf.CsrfViewMiddleware',
65
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
66
+    'django.contrib.messages.middleware.MessageMiddleware',
67
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
68
+    'detect.middleware.UserAgentDetectionMiddleware',
69
+]
70
+
71
+ROOT_URLCONF = 'thermometer.urls'
72
+
73
+TEMPLATES = [
74
+    {
75
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
76
+        'DIRS': [os.path.join(BASE_DIR, 'templates')],
77
+        # 'APP_DIRS': True,
78
+        'OPTIONS': {
79
+            'context_processors': [
80
+                'django.template.context_processors.debug',
81
+                'django.template.context_processors.request',
82
+                'django.contrib.auth.context_processors.auth',
83
+                'django.contrib.messages.context_processors.messages',
84
+            ],
85
+            'loaders': [
86
+                ('django.template.loaders.cached.Loader', [
87
+                    'django.template.loaders.filesystem.Loader',
88
+                    'django.template.loaders.app_directories.Loader',
89
+                ]),
90
+            ],
91
+        },
92
+    },
93
+]
94
+
95
+WSGI_APPLICATION = 'thermometer.wsgi.application'
96
+
97
+
98
+# Database
99
+# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
100
+
101
+DATABASES = {
102
+    # Create Database
103
+    # CREATE DATABASE thermometer DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
104
+    'default': {
105
+        'ENGINE': 'django.db.backends.mysql',
106
+        'NAME': 'thermometer',
107
+        'USER': 'root',
108
+        'PASSWORD': '',
109
+        'HOST': '127.0.0.1',
110
+        'PORT': 3306,
111
+        'CONN_MAX_AGE': 600,
112
+        'OPTIONS': {
113
+            'charset': 'utf8mb4',
114
+        },
115
+    }
116
+}
117
+
118
+
119
+# Password validation
120
+# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
121
+
122
+AUTH_PASSWORD_VALIDATORS = [
123
+    {
124
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
125
+    },
126
+    {
127
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
128
+    },
129
+    {
130
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
131
+    },
132
+    {
133
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
134
+    },
135
+]
136
+
137
+
138
+# Internationalization
139
+# https://docs.djangoproject.com/en/1.11/topics/i18n/
140
+
141
+LANGUAGE_CODE = 'zh-Hans'
142
+
143
+TIME_ZONE = 'Asia/Shanghai'
144
+
145
+USE_I18N = True
146
+
147
+USE_L10N = True
148
+
149
+USE_TZ = True
150
+
151
+
152
+# Static files (CSS, JavaScript, Images)
153
+# https://docs.djangoproject.com/en/1.11/howto/static-files/
154
+
155
+STATICFILES_DIRS = (
156
+    os.path.join(PROJ_DIR, 'static').replace('\\', '/'),
157
+)
158
+
159
+STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static').replace('\\', '/')
160
+
161
+STATIC_URL = '/static/'
162
+
163
+STATICFILES_FINDERS = (
164
+    'django.contrib.staticfiles.finders.FileSystemFinder',
165
+    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
166
+    # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
167
+)
168
+
169
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/')
170
+
171
+MEDIA_URL = '/media/'
172
+
173
+# File 设置
174
+FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880  # InMemoryUploadedFile 文件最大值,设置为 5 MB
175
+FILE_UPLOAD_PERMISSIONS = 0o644  # TemporaryUploadedFile 文件权限设置
176
+
177
+# DOMAIN
178
+DOMAIN = 'http://a.com'
179
+
180
+# Redis 设置
181
+REDIS = {
182
+    'default': {
183
+        'HOST': '127.0.0.1',
184
+        'PORT': 6379,
185
+        'USER': '',
186
+        'PASSWORD': '',
187
+        'db': 0,
188
+        'decode_responses': True,
189
+    }
190
+}
191
+
192
+# 微信设置
193
+WECHAT = {
194
+    'JSAPI': {
195
+        'trade_type': 'JSAPI',  # JSAPI-网页支付、NATIVE-原生支付、APP-APP支付、MICROPAY-刷卡支付
196
+        'token': '5201314',
197
+        'appID': '',
198
+        'appsecret': '',
199
+        'encodingaeskey': '',
200
+        'mchID': '',
201
+        'apiKey': '',
202
+        'mch_cert': '',
203
+        'mch_key': '',
204
+        'redpack': {
205
+
206
+        }
207
+    },
208
+}
209
+
210
+WECHAT_DEFAULT_CFG = 'JSAPI'
211
+
212
+# 微信唯一标识
213
+# Choices: 'unionid' or 'openid'
214
+#
215
+# models.py
216
+#   'unique_identifier': self.unionid if settings.WECHAT_UNIQUE_IDENTIFICATION == 'unionid' else self.openid,
217
+# views.py
218
+#   unique_identifier = request.POST.get(settings.WECHAT_UNIQUE_IDENTIFICATION, '')
219
+#   profile = Profile.objects.get(**{settings.WECHAT_UNIQUE_IDENTIFICATION: unique_identifier})
220
+#
221
+# If not bind to OpenPlat, change `WECHAT_UNIQUE_IDENTIFICATION` as `openid`
222
+WECHAT_UNIQUE_IDENTIFICATION = 'unionid'
223
+
224
+# Token 错误重授权设置
225
+TOKEN_CHECK_KEY = ''
226
+# TOKEN_CHECK_KEY = 'user_id'
227
+WECHAT_OAUTH2_REDIRECT_ENTRY = ''
228
+WECHAT_OAUTH2_REDIRECT_URL = ''
229
+
230
+# Cookie 设置
231
+DJANGO_WE_COOKIE_MAX_AGE = COOKIE_MAX_AGE = 31536000  # 单位:秒,1年:365 * 24 * 60 * 60 = 31536000
232
+DJANGO_WE_COOKIE_SALT = COOKIE_SALT = 'djwe'  # Salt for ``set_signed_cookie``
233
+# Cookie 校验设置
234
+COOKIE_USER_CHECK_KEY = ''
235
+# COOKIE_USER_CHECK_KEY = 'user_id'
236
+
237
+# 邮件设置
238
+# https://docs.djangoproject.com/en/1.11/howto/error-reporting/#email-reports
239
+# When DEBUG is False, Django will email the users listed in the ADMINS setting
240
+# whenever your code raises an unhandled exception and results in an internal server error (HTTP status code 500).
241
+# 只有当 DEBUG = False 的时候,才会邮件发送报错信息
242
+# Email address that error messages come from.
243
+SERVER_EMAIL = 'error.notify@exmail.com'
244
+# The email backend to use. For possible shortcuts see django.core.mail.
245
+# The default is to use the SMTP backend.
246
+# Third-party backends can be specified by providing a Python path
247
+# to a module that defines an EmailBackend class.
248
+EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
249
+# Host for sending email.
250
+EMAIL_HOST = 'smtp.exmail.qq.com'
251
+# Port for sending email.
252
+EMAIL_PORT = 25
253
+# Optional SMTP authentication information for EMAIL_HOST.
254
+EMAIL_HOST_USER = 'error.notify@exmail.com'
255
+EMAIL_HOST_PASSWORD = '<^_^>pwd<^_^>'
256
+EMAIL_USE_TLS = False
257
+EMAIL_USE_SSL = False
258
+EMAIL_SSL_CERTFILE = None
259
+EMAIL_SSL_KEYFILE = None
260
+# Default: None
261
+# Specifies a timeout in seconds for blocking operations like the connection attempt.
262
+# socket.error: [Errno 110] Connection timed out
263
+# 如果不设置 EMAIL_TIMEOUT,一旦 sock.connect 连接有问题 error: (110, 'Connection timed out')
264
+# 就会导致进程一直卡住,最终导致服务崩溃
265
+# EMAIL_TIMEOUT = None
266
+EMAIL_TIMEOUT = 3
267
+# Default email address to use for various automated correspondence from
268
+# the site managers.
269
+DEFAULT_FROM_EMAIL = 'error.notify <error.notify@exmail.com>'
270
+# People who get code error notifications.
271
+# In the format [('Full Name', 'email@example.com'), ('Full Name', 'anotheremail@example.com')]
272
+# Default: [], not send code error notifications.
273
+# https://github.com/django/django/blob/5fcfe5361e5b8c9738b1ee4c1e9a6f293a7dda40/django/core/mail/__init__.py#L90
274
+# ADMINS = [('Zhang San', 'san.zhang@exmail.com'), ('Li Si', 'si.li@exmail.com')]
275
+ADMINS = []
276
+# Not-necessarily-technical managers of the site. They get broken link
277
+# notifications and other various emails.
278
+MANAGERS = ADMINS
279
+# Subject-line prefix for email messages send with django.core.mail.mail_admins
280
+# or ...mail_managers.  Make sure to include the trailing space.
281
+EMAIL_SUBJECT_PREFIX = u'[Thermometer] '
282
+
283
+# Django-Admin Settings
284
+DJANGO_ADMIN_DISABLE_DELETE_SELECTED = False
285
+
286
+# Django-FILE-UPLOAD Settings
287
+DJANGO_FILE_UPLOAD_USE_YM = True
288
+DJANGO_FILE_UPLOAD_USE_DT = True
289
+
290
+# Django-Logit Settings
291
+DJANGO_LOGIT_ENABLED = True
292
+DJANGO_LOGIT_BODY_FLAG = False
293
+DJANGO_LOGIT_RES_FLAG = False
294
+
295
+# Django-Onerror Settings
296
+DJANGO_ONERROR_ACCEPT_REPORT = True
297
+DJANGO_ONERROR_ADMIN_SITE_REGISTER = True
298
+
299
+# Django-Short-URL Settings
300
+# Redirect url when short url not exists
301
+DJANGO_SHORT_URL_REDIRECT_URL = ''
302
+
303
+# Django-We Settings
304
+DJANGO_WE_QUOTE_OR_NOT = True
305
+DJANGO_WE_MODEL_DISPLAY_OR_NOT = True
306
+# Enable Cookie or not
307
+# DJANGO_WE_BASE_REDIRECT_SET_COOKIE = False
308
+# DJANGO_WE_USERINFO_REDIRECT_SET_COOKIE = True
309
+# Cookie Config
310
+DJANGO_WE_COOKIE_MAX_AGE = COOKIE_MAX_AGE
311
+DJANGO_WE_COOKIE_SALT = COOKIE_SALT
312
+
313
+# 开发调试相关配置
314
+if DEBUG:
315
+    try:
316
+        from .local_settings_dev import *
317
+    except ImportError:
318
+        pass
319
+
320
+try:
321
+    from .local_settings import *
322
+except ImportError:
323
+    pass
324
+
325
+try:
326
+    from .django_file_callback_settings import *
327
+except ImportError:
328
+    pass
329
+
330
+try:
331
+    from .django_we_callback_settings import *
332
+except ImportError:
333
+    pass
334
+
335
+# 依赖 local_settings 中的配置
336
+# 微信授权设置
337
+# WECHAT_OAUTH2_REDIRECT_URI = '{0}/we/oauth2?scope={{0}}&redirect_url={{1}}'.format(DOMAIN)
338
+# Shorten URL
339
+# ``o`` is short for oauth2
340
+# ``r`` is short for redirect_url
341
+WECHAT_OAUTH2_REDIRECT_URI = '{0}/we/o?scope={{0}}&r={{1}}'.format(DOMAIN)
342
+WECHAT_OAUTH2_USERINFO_REDIRECT_URI = '{0}/we/o?r={{0}}'.format(DOMAIN)  # Scope default snsapi_userinfo
343
+WECHAT_BASE_REDIRECT_URI = '{0}/we/base_redirect'.format(DOMAIN)
344
+WECHAT_USERINFO_REDIRECT_URI = '{0}/we/userinfo_redirect'.format(DOMAIN)
345
+WECHAT_DIRECT_BASE_REDIRECT_URI = '{0}/we/direct_base_redirect'.format(DOMAIN)
346
+WECHAT_DIRECT_USERINFO_REDIRECT_URI = '{0}/we/direct_userinfo_redirect'.format(DOMAIN)
347
+
348
+# Redis 连接
349
+WECHAT_REDIS_OBJ = REDIS_CACHE = connector(REDIS.get('default', {}))
350
+
351
+# LOGGER 设置
352
+# python manage.py rlistlog --key=django:logit:thermometer --filename=/tmp/thermometer.logit.log
353
+LOGGING = {
354
+    'version': 1,
355
+    'disable_existing_loggers': False,
356
+    'formatters': {
357
+        'verbose': {
358
+            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
359
+        },
360
+        'simple': {
361
+            'format': '%(levelname)s %(message)s'
362
+        },
363
+    },
364
+    'handlers': {
365
+        'logit': {
366
+            'level': 'DEBUG',
367
+            'class': 'rlog.RedisListHandler',
368
+            'redis_client': REDIS_CACHE,
369
+            'key': 'django:logit:thermometer',
370
+            'formatter': 'verbose',
371
+        },
372
+        'console': {
373
+            'level': 'DEBUG',
374
+            'class': 'logging.StreamHandler',
375
+            'formatter': 'verbose'
376
+        },
377
+    },
378
+    'loggers': {
379
+        'logit': {
380
+            'handlers': ['logit'],
381
+            'level': 'DEBUG',
382
+            'propagate': True,
383
+        },
384
+        'console': {
385
+            'handlers': ['console'],
386
+            'level': 'DEBUG',
387
+            'propagate': True,
388
+        },
389
+    },
390
+}
391
+
392
+# MAX_BIGINT
393
+# Why Not ``sys.maxint``
394
+# n bit platform sys.maxint = 2 ** (n - 1) - 1
395
+# 64 bit 9223372036854775807, 32 bit 2147483647
396
+from django.db.models import BigIntegerField  # isort:skip
397
+MAX_BIGINT = BigIntegerField.MAX_BIGINT

+ 68 - 0
thermometer/static/templet/css/common.css

@@ -0,0 +1,68 @@
1
+.text-center {
2
+    text-align: center;
3
+}
4
+
5
+/*
6
+  文本溢出省略,元素需要设置定宽度
7
+  */
8
+/* 单行 */
9
+.text_ellipsis {
10
+    overflow: hidden;
11
+    white-space: nowrap;
12
+    text-overflow: ellipsis;
13
+}
14
+/* 多行 */
15
+.a {
16
+    overflow: hidden;
17
+    text-overflow: ellipsis;
18
+    display: -webkit-box;
19
+    -webkit-line-clamp: 2;
20
+    -webkit-box-orient: vertical;
21
+}
22
+
23
+/*
24
+  浮动 & 清除浮动
25
+ */
26
+.fl {
27
+    float: left;
28
+}
29
+
30
+.fr {
31
+    float: right;
32
+}
33
+
34
+.clearfix {
35
+    zoom: 1;
36
+}
37
+
38
+.clearfix:after {
39
+    content: "\200B";
40
+    display: block;
41
+    height: 0;
42
+    clear: both;
43
+}
44
+
45
+.clearfix:after {content:"."; display:block; height:0; visibility:hidden; clear:both; }
46
+.clearfix { *zoom:1; }
47
+
48
+/*
49
+  解决安卓微信点击图片预览问题
50
+  这个会让 img 标签的点击事件失效,如果想要点击图片就要给上面再写一层
51
+  需要长按识别二维码的时候,则再单独给该图片添加
52
+  ```css
53
+  pointer-events: auto;
54
+  ```
55
+  来恢复对应的点击事件
56
+  */
57
+img {
58
+    pointer-events: none;
59
+}
60
+
61
+.clickable {
62
+    pointer-events: auto;
63
+}
64
+
65
+/* Input 自动填充后,移除 Chrome 默认黄色 */
66
+input:-webkit-autofill {
67
+    box-shadow: 0 0 0 1000px white inset !important;
68
+}

+ 574 - 0
thermometer/static/templet/js/jswe.js

@@ -0,0 +1,574 @@
1
+!(function(e, t) {
2
+    var config = {
3
+        wxconfig: 'http://api.tt4it.com/wx/jsapi_signature',
4
+        callback: 'callback'
5
+    }, wxData = {
6
+        debug: false,
7
+        imgUrl: '',
8
+        link: '',
9
+        desc: '',
10
+        title: '',
11
+        timeLine: ''
12
+    }, wxConfig = {
13
+        hide: false,
14
+        baseFlag: false,
15
+        baseHide: false,
16
+        close: false,
17
+        hideMenuItems: [],
18
+        showMenuItems: []
19
+    }, jsApiList = [
20
+        'checkJsApi',
21
+        'onMenuShareTimeline',
22
+        'onMenuShareAppMessage',
23
+        'onMenuShareQQ',
24
+        'onMenuShareWeibo',
25
+        'onMenuShareQZone',
26
+        'hideMenuItems',
27
+        'showMenuItems',
28
+        'hideAllNonBaseMenuItem',
29
+        'showAllNonBaseMenuItem',
30
+        'translateVoice',
31
+        'startRecord',
32
+        'stopRecord',
33
+        'onRecordEnd',
34
+        'playVoice',
35
+        'pauseVoice',
36
+        'stopVoice',
37
+        'uploadVoice',
38
+        'downloadVoice',
39
+        'chooseImage',
40
+        'previewImage',
41
+        'uploadImage',
42
+        'downloadImage',
43
+        'getLocalImgData',
44
+        'getNetworkType',
45
+        'openLocation',
46
+        'getLocation',
47
+        'hideOptionMenu',
48
+        'showOptionMenu',
49
+        'closeWindow',
50
+        'scanQRCode',
51
+        'chooseWXPay',
52
+        'openEnterpriseRedPacket',
53
+        'openProductSpecificView',
54
+        'addCard',
55
+        'chooseCard',
56
+        'openCard'
57
+    ], wxApiFun
58
+
59
+    function isEmpty(obj) {
60
+        if (obj == null) return true
61
+        if (obj.length > 0) return false
62
+        if (obj.length === 0) return true
63
+        for (var key in obj) {
64
+            if (Object.prototype.hasOwnProperty.call(obj, key)) return false
65
+        }
66
+        return true
67
+    }
68
+
69
+    function isNotEmpty(obj) {
70
+        return !isEmpty(obj)
71
+    }
72
+
73
+    function isOpenOnPC() {  // 判断当前网页是否在 PC 浏览器中打开
74
+        var ua = navigator.userAgent
75
+        return /windows nt/i.test(ua) || /macintosh/i.test(ua) || /linux x86_64/i.test(ua)
76
+    }
77
+
78
+    function isOpenInWeixin() {  // 判断当前网页是否在微信内置浏览器中打开
79
+        return /micromessenger/i.test(navigator.userAgent)
80
+    }
81
+
82
+    function getWeixinVersion() {
83
+        var ua = navigator.userAgent,
84
+            mt = ua.match(/micromessenger\/([\d.]+)/i)
85
+        return (mt ? mt[1] : '')
86
+    }
87
+
88
+    // This function checks whether Wechat is the appointed version or not
89
+    // Cmp: http://jsperf.com/regexp-test-vs-indexof-ignore-upper-and-lower
90
+    function isWeixinVersion(version) {
91
+        // return new RegExp('micromessenger/' + version , 'i').test(navigator.userAgent)
92
+        return navigator.userAgent.toLowerCase().indexOf('micromessenger/' + version) != -1
93
+    }
94
+
95
+    function hideOptionMenu() {
96
+        wxConfig.hide = true
97
+        fixedWxData()
98
+    }
99
+
100
+    function showOptionMenu() {
101
+        wxConfig.hide = false
102
+        fixedWxData()
103
+    }
104
+
105
+    function hideMenuItems(items) {
106
+        wxConfig.hideMenuItems = items
107
+        fixedWxData()
108
+    }
109
+
110
+    function showMenuItems(items) {
111
+        wxConfig.showMenuItems = items
112
+        fixedWxData()
113
+    }
114
+
115
+    function hideAllNonBaseMenuItem() {
116
+        wxConfig.baseFlag = true
117
+        wxConfig.baseHide = true
118
+        fixedWxData()
119
+    }
120
+
121
+    function showAllNonBaseMenuItem() {
122
+        wxConfig.baseFlag = true
123
+        wxConfig.baseHide = false
124
+        fixedWxData()
125
+    }
126
+
127
+    function closeWindow() {
128
+        wxConfig.close = true
129
+        fixedWxData()
130
+    }
131
+
132
+    function wxReady(data) {
133
+        data = typeof data === 'object' ? data : JSON.parse(data)
134
+        wx.config({
135
+            debug: wxData.debug,
136
+            appId: data.appId,
137
+            timestamp: data.timestamp,
138
+            nonceStr: data.nonceStr,
139
+            signature: data.signature,
140
+            jsApiList: jsApiList
141
+        })
142
+
143
+        var callbacks = {
144
+            trigger: function (res) {
145
+                // alert('用户点击发送给朋友')
146
+                if (JSWE.wxTrigger) {JSWE.wxTrigger(res)}
147
+            },
148
+            success: function (res) {
149
+                // alert('已分享')
150
+                if (JSWE.wxSuccess) {JSWE.wxSuccess(res)}
151
+            },
152
+            cancel: function (res) {
153
+                // alert('已取消')
154
+                if (JSWE.wxCancel) {JSWE.wxCancel(res)}
155
+            },
156
+            fail: function (res) {
157
+                // alert(JSON.stringify(res))
158
+                if (JSWE.wxFail) {JSWE.wxFail(res)}
159
+            }
160
+        }, shareInfo = function(flag) {
161
+            var _share = {
162
+                title: flag ? wxData.title : (wxData.timeLine || wxData.desc),
163
+                link: wxData.link,
164
+                imgUrl: wxData.imgUrl,
165
+                trigger: callbacks.trigger,
166
+                success: callbacks.success,
167
+                cancel: callbacks.cancel,
168
+                fail: callbacks.fail
169
+            }
170
+            if (flag) _share.desc = wxData.desc
171
+            return _share
172
+        }, wxShareApi = function() {
173
+            // 2. 分享接口
174
+            // 2.1 监听“分享给朋友”,按钮点击、自定义分享内容及分享结果接口
175
+            wx.onMenuShareAppMessage(shareInfo(1))
176
+            // 2.2 监听“分享到朋友圈”按钮点击、自定义分享内容及分享结果接口
177
+            wx.onMenuShareTimeline(shareInfo(0))
178
+            // 2.3 监听“分享到QQ”按钮点击、自定义分享内容及分享结果接口
179
+            wx.onMenuShareQQ(shareInfo(1))
180
+            // 2.4 监听“分享到微博”按钮点击、自定义分享内容及分享结果接口
181
+            wx.onMenuShareWeibo(shareInfo(1))
182
+            // 2.5 监听“分享到QQ空间”按钮点击、自定义分享内容及分享结果接口
183
+            wx.onMenuShareQZone(shareInfo(1))
184
+        }, wxMenuApi = function () {
185
+            // 8. 界面操作接口
186
+            // 8.1 隐藏右上角菜单
187
+            // 8.2 显示右上角菜单
188
+            if (wxConfig.hide) {wx.hideOptionMenu()} else {wx.showOptionMenu()}
189
+            // 8.3 批量隐藏菜单项
190
+            if (isNotEmpty(wxConfig.hideMenuItems)) {
191
+                wx.hideMenuItems({
192
+                    menuList: wxConfig.hideMenuItems,
193
+                    success: function (res) {
194
+                        if (JSWE.wxHideMenuItemsSuccess) {JSWE.wxHideMenuItemsSuccess(res)}
195
+                    },
196
+                    fail: function (res) {
197
+                        if (JSWE.wxHideMenuItemsFail) {JSWE.wxHideMenuItemsFail(res)}
198
+                    }
199
+                })
200
+            }
201
+            // 8.4 批量显示菜单项
202
+            if (isNotEmpty(wxConfig.showMenuItems)) {
203
+                wx.showMenuItems({
204
+                    menuList: wxConfig.showMenuItems,
205
+                    success: function (res) {
206
+                        if (JSWE.wxShowMenuItemsSuccess) {JSWE.wxShowMenuItemsSuccess(res)}
207
+                    },
208
+                    fail: function (res) {
209
+                        if (JSWE.wxShowMenuItemsFail) {JSWE.wxShowMenuItemsFail(res)}
210
+                    }
211
+                })
212
+            }
213
+            // 8.5 隐藏所有非基本菜单项
214
+            // 8.6 显示所有被隐藏的非基本菜单项
215
+            if (wxConfig.baseFlag) {
216
+                if (wxConfig.baseHide) {wx.hideAllNonBaseMenuItem()} else {wx.showAllNonBaseMenuItem()}
217
+            }
218
+            // 8.7 关闭当前窗口
219
+            if (wxConfig.close) {wx.closeWindow()}
220
+        }, wxVoiceApi = function() {
221
+            // 4.3 监听录音自动停止
222
+            wx.onVoiceRecordEnd({
223
+                complete: function (res) {
224
+                    voice.localId = res.localId
225
+                    if (JSWE.wxVoiceRecordEnd) {JSWE.wxVoiceRecordEnd(res)}
226
+                }
227
+            })
228
+            // 4.7 监听录音播放停止
229
+            wx.onVoicePlayEnd({
230
+                complete: function (res) {
231
+                    if (JSWE.wxVoicePlayEnd) {JSWE.wxVoicePlayEnd(res)}
232
+                }
233
+            })
234
+        }, wxApi = function () {
235
+            wxShareApi()
236
+            wxMenuApi()
237
+            wxVoiceApi()
238
+        }
239
+
240
+        wx.ready(wxApi)
241
+
242
+        return wxApiFun = wxApi
243
+    }
244
+
245
+    if (isOpenInWeixin() || isOpenOnPC()) {
246
+        if ('undefined' !== typeof JSWE_CONF_UPDATE) JSWE_CONF_UPDATE(config)
247
+        $.ajax({
248
+            url: config.wxconfig,
249
+            type: 'get',
250
+            dataType: 'jsonp',
251
+            jsonpCallback: config.callback,
252
+            data: {
253
+                url: window.location.href.split('#')[0]
254
+            },
255
+            success: wxReady
256
+        })
257
+    }
258
+
259
+    function initWxData(data, flag) {
260
+        for(var d in data) {if (d in wxData) wxData[d] = data[d]}
261
+        if (flag) fixedWxData()
262
+    }
263
+
264
+    function changeWxData(key, value, flag) {
265
+        if (key in falDwxDataata) {wxData[key] = value}
266
+        if (flag) fixedWxData()
267
+    }
268
+
269
+    function fixedWxData() {
270
+        if ('undefined' !== typeof wxApiFun) wxApiFun()
271
+    }
272
+
273
+    // 3 智能接口
274
+    var voice = {
275
+        localId: '',
276
+        serverId: ''
277
+    }
278
+    // 3.1 识别音频并返回识别结果
279
+    function translateVoice() {
280
+        if (voice.localId == '') {
281
+            if (JSWE.wxTranslateVoiceEmpty) {JSWE.wxTranslateVoiceEmpty()}
282
+            return
283
+        }
284
+        wx.translateVoice({
285
+            localId: voice.localId,
286
+            complete: function (res) {
287
+                if (JSWE.wxTranslateVoiceComplete) {JSWE.wxTranslateVoiceComplete(res)}
288
+            }
289
+        })
290
+    }
291
+
292
+    // 4 音频接口
293
+    // 4.1 开始录音
294
+    function startRecord() {
295
+        wx.startRecord({
296
+            cancel: function () {
297
+                if (JSWE.wxStartRecordCancel) {JSWE.wxStartRecordCancel(res)}
298
+            }
299
+        })
300
+    }
301
+
302
+    // 4.2 停止录音
303
+    function stopRecord() {
304
+        wx.stopRecord({
305
+          success: function (res) {
306
+              voice.localId = res.localId
307
+              if (JSWE.wxStopRecordSuccess) {JSWE.wxStopRecordSuccess(res)}
308
+          },
309
+          fail: function (res) {
310
+              if (JSWE.wxStopRecordFail) {JSWE.wxStopRecordFail(res)}
311
+          }
312
+        })
313
+    }
314
+
315
+    // 4.4 播放音频
316
+    function playVoice() {
317
+        if (voice.localId == '') {
318
+            if (JSWE.wxPlayVoiceEmpty) {JSWE.wxPlayVoiceEmpty()}
319
+            return
320
+        }
321
+        wx.playVoice({
322
+            localId: voice.localId
323
+        })
324
+    }
325
+
326
+    // 4.5 暂停播放音频
327
+    function pauseVoice() {
328
+        if (voice.localId == '') {
329
+            if (JSWE.wxPauseVoiceEmpty) {JSWE.wxPauseVoiceEmpty()}
330
+            return
331
+        }
332
+        wx.pauseVoice({
333
+            localId: voice.localId
334
+        })
335
+    }
336
+
337
+    // 4.6 停止播放音频
338
+    function stopVoice() {
339
+        if (voice.localId == '') {
340
+            if (JSWE.wxStopVoiceEmpty) {JSWE.wxStopVoiceEmpty()}
341
+            return
342
+        }
343
+        wx.stopVoice({
344
+            localId: voice.localId
345
+        })
346
+    }
347
+
348
+    // 4.8 上传语音
349
+    function uploadVoice() {
350
+        var localId = voice.localId
351
+        if (localId == '') {
352
+            if (JSWE.wxUploadVoiceEmpty) {JSWE.wxUploadVoiceEmpty()}
353
+            return
354
+        }
355
+        wx.uploadVoice({
356
+            localId: localId,
357
+            success: function (res) {
358
+                voice.serverId = res.serverId
359
+                if (JSWE.wxUploadVoiceSuccess) {JSWE.wxUploadVoiceSuccess(res, localId)}
360
+            }
361
+        })
362
+    }
363
+
364
+    // 4.9 下载语音
365
+    function downloadVoice() {
366
+        var serverId = voice.serverId
367
+        if (serverId == '') {
368
+            if (JSWE.wxDownloadVoiceEmpty) {JSWE.wxDownloadVoiceEmpty()}
369
+            return
370
+        }
371
+        wx.downloadVoice({
372
+            serverId: serverId,
373
+            success: function (res) {
374
+                voice.localId = res.localId
375
+                if (JSWE.wxDownloadVoiceSuccess) {JSWE.wxDownloadVoiceSuccess(res, serverId)}
376
+            }
377
+        })
378
+    }
379
+
380
+    // 5 图片接口
381
+    var images = {
382
+        localIds: [],
383
+        serverIds: []
384
+    }
385
+    // 5.1 拍照、本地选图
386
+    function chooseImage(choose_params) {
387
+        if ('undefined' === typeof choose_params) choose_params = {}
388
+        wx.chooseImage({
389
+            count: choose_params.count || 9, // 默认9
390
+            sizeType: choose_params.sizeType || ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
391
+            sourceType: choose_params.sourceType || ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
392
+            success: function (res) {
393
+                images.localIds = res.localIds // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
394
+                // 判断是否直接上传
395
+                if (choose_params.directUpload) {setTimeout(uploadImages({localIds: images.localIds, isShowProgressTips: choose_params.isShowProgressTips || 1}), 100)}
396
+                // 拍照、本地选图成功后的回调函数
397
+                if (JSWE.wxChooseImageSuccess) {JSWE.wxChooseImageSuccess(res, choose_params.extras || {})}
398
+            }
399
+        })
400
+    }
401
+
402
+    // 5.2 图片预览
403
+    function previewImage(preview_params) {
404
+        wx.previewImage({
405
+            current: preview_params.current, // 当前显示图片的链接,不填则默认为 urls 的第一张
406
+            urls: preview_params.urls // 需要预览的图片链接列表
407
+        })
408
+    }
409
+
410
+    // 5.3 上传图片
411
+    function uploadImage(upload_params) {
412
+        // 上传图片为异步处理,重复上传同一图片,返回的serverId也是不同的
413
+        var localId = upload_params.localId
414
+        wx.uploadImage({
415
+            localId: localId, // 需要上传的图片的本地ID,由chooseImage接口获得
416
+            isShowProgressTips: upload_params.isShowProgressTips || 1, // 默认为1,显示进度提示
417
+            success: function (res) {
418
+                images.serverIds.push(res.serverId) // 返回图片的服务器端ID
419
+                // 上传图片成功后的回调函数
420
+                if (JSWE.wxUploadImageSuccess) {JSWE.wxUploadImageSuccess(res, localId)}
421
+            }
422
+        })
423
+    }
424
+
425
+    function uploadImages(upload_params) {
426
+        var localIds = upload_params.localIds, isShowProgressTips = upload_params.isShowProgressTips || 1
427
+        images.serverIds = []
428
+        for (var idx in localIds) {uploadImage({localId: localIds[idx], isShowProgressTips: isShowProgressTips})}
429
+    }
430
+
431
+    // 5.4 下载图片
432
+    function downloadImage(download_params) {
433
+        var serverId = download_params.serverId
434
+        wx.downloadImage({
435
+            serverId: serverId, // 需要下载的图片的服务器端ID,由uploadImage接口获得
436
+            isShowProgressTips: download_params.isShowProgressTips || 1, // 默认为1,显示进度提示
437
+            success: function (res) {
438
+                images.localId.push(res.localId)
439
+                if (JSWE.wxDownloadImageSuccess) {JSWE.wxDownloadImageSuccess(res, serverId)}
440
+            }
441
+        })
442
+    }
443
+
444
+    function downloadImages(download_params) {
445
+        var serverIds = download_params.serverIds, isShowProgressTips = download_params.isShowProgressTips || 1
446
+        images.localIds = []
447
+        for (var idx in serverIds) {downloadImage({serverId: serverIds[idx], isShowProgressTips: isShowProgressTips})}
448
+    }
449
+
450
+    function getLocalImgData(localId) {
451
+        wx.getLocalImgData({
452
+            localId: localId, // 图片的localID
453
+            success: function (res) {
454
+                // var localData = res.localData; // localData是图片的base64数据,可以用img标签显示
455
+                if (JSWE.wxGetLocalImgDataSuccess) {JSWE.wxGetLocalImgDataSuccess(res)}
456
+            }
457
+        })
458
+    }
459
+
460
+    // 9 微信原生接口
461
+    // 9.1.1 扫描二维码并返回结果
462
+    // 9.1.2 扫描二维码并返回结果
463
+    function scanQRCode(scan_params) {
464
+        if ('undefined' === typeof scan_params) scan_params = {}
465
+        wx.scanQRCode({
466
+            needResult: scan_params.needResult || 0,  // 默认为0,0扫描结果由微信处理,1直接返回扫描结果
467
+            scanType: scan_params.scanType || ['qrCode', 'barCode'],  // 可以指定扫二维码还是一维码,默认二者都有
468
+            success: function (res) {  // 当 needResult 为 1 时,扫码返回的结果
469
+                if (JSWE.wxScanQRCodeSuccess) {JSWE.wxScanQRCodeSuccess(res)}
470
+            }
471
+        })
472
+    }
473
+
474
+    // QRCode & BarCode is different
475
+    function parseScanQRCodeResultStr(resultStr) {
476
+        var strs = resultStr.split(',')
477
+        return strs[strs.length - 1]
478
+    }
479
+
480
+    // 10 微信支付接口
481
+    // 10.1 发起一个支付请求
482
+    function chooseWXPay(wxpay_params) {
483
+        wx.chooseWXPay({
484
+            timestamp: wxpay_params.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
485
+            nonceStr: wxpay_params.nonceStr, // 支付签名随机串,不长于 32 位
486
+            package: wxpay_params.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
487
+            signType: wxpay_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
488
+            paySign: wxpay_params.paySign, // 支付签名
489
+            success: function (res) {
490
+                // 支付成功后的回调函数
491
+                if (JSWE.wxPaySuccess) {JSWE.wxPaySuccess(res)}
492
+            }
493
+        })
494
+    }
495
+
496
+    // xx 微信原生企业红包接口
497
+    // xx.1 发起一个发送原生企业红包请求
498
+    function openEnterpriseRedPacket(wxredpack_params) {
499
+        wx.openEnterpriseRedPacket({
500
+            timeStamp: wxredpack_params.timeStamp, // 红包签名时间戳,注意原生企业红包接口timeStamp字段名需大写其中的S字符,而支付接口timeStamp字段名无需大写其中的S字符。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
501
+            nonceStr: wxredpack_params.nonceStr, // 红包签名随机串,不长于 32 位
502
+            package: encodeURIComponent(wxredpack_params.package), // 发放红包接口返回的prepay_id参数值,提交格式如:prepay_id=***)
503
+            signType: wxredpack_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
504
+            paySign: wxredpack_params.paySign, // 红包签名
505
+            success: function (res) {
506
+                // 发送原生企业红包成功后的回调函数
507
+                if (JSWE.wxEnterpriseRedPacketSuccess) {JSWE.wxEnterpriseRedPacketSuccess(res)}
508
+            }
509
+        })
510
+    }
511
+
512
+    var v = {
513
+        version: '1.0.5',
514
+
515
+        // Basic Vars
516
+        config: config,
517
+        wxData: wxData,
518
+        jsApiList: jsApiList,
519
+
520
+        isEmpty: isEmpty,
521
+        isNotEmpty: isNotEmpty,
522
+
523
+        // Weixin Function
524
+        isOpenInWeixin: isOpenInWeixin,
525
+        getWeixinVersion: getWeixinVersion,
526
+        isWeixinVersion: isWeixinVersion,
527
+
528
+        // Menu Function
529
+        hideOptionMenu: hideOptionMenu,
530
+        showOptionMenu: showOptionMenu,
531
+        hideMenuItems: hideMenuItems,
532
+        showMenuItems: showMenuItems,
533
+        hideAllNonBaseMenuItem: hideAllNonBaseMenuItem,
534
+        showAllNonBaseMenuItem: showAllNonBaseMenuItem,
535
+        closeWindow: closeWindow,
536
+
537
+        // Share Function
538
+        initWxData: initWxData,
539
+        changeWxData: changeWxData,
540
+        fixedWxData: fixedWxData,
541
+
542
+        // Voice Function
543
+        voice: voice,
544
+        translateVoice: translateVoice,
545
+        startRecord: startRecord,
546
+        stopRecord: stopRecord,
547
+        playVoice: playVoice,
548
+        pauseVoice: pauseVoice,
549
+        stopVoice: stopVoice,
550
+        uploadVoice: uploadVoice,
551
+        downloadVoice: downloadVoice,
552
+
553
+        // Image Function
554
+        images: images,
555
+        chooseImage: chooseImage,
556
+        previewImage: previewImage,
557
+        uploadImage: uploadImage,
558
+        uploadImages: uploadImages,
559
+        downloadImage: downloadImage,
560
+        downloadImages: downloadImages,
561
+        getLocalImgData: getLocalImgData,
562
+
563
+        // Scan Function
564
+        scanQRCode: scanQRCode,
565
+        parseScanQRCodeResultStr: parseScanQRCodeResultStr,
566
+
567
+        // Pay Function
568
+        chooseWXPay: chooseWXPay,
569
+
570
+        // EnterpriseRedPacket Function
571
+        openEnterpriseRedPacket: openEnterpriseRedPacket
572
+    }
573
+    e.JSWE = e.V = v
574
+})(window)

+ 56 - 0
thermometer/urls.py

@@ -0,0 +1,56 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+"""thermometer URL Configuration
4
+
5
+The `urlpatterns` list routes URLs to views. For more information please see:
6
+    https://docs.djangoproject.com/en/1.11/topics/http/urls/
7
+Examples:
8
+Function views
9
+    1. Add an import:  from my_app import views
10
+    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
11
+Class-based views
12
+    1. Add an import:  from other_app.views import Home
13
+    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
14
+Including another URLconf
15
+    1. Import the include() function: from django.conf.urls import url, include
16
+    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
17
+"""
18
+from django.conf import settings
19
+from django.conf.urls import include, url
20
+from django.conf.urls.static import static
21
+from django.contrib import admin
22
+
23
+
24
+urlpatterns = [
25
+    url(r'^admin/', admin.site.urls),
26
+]
27
+
28
+urlpatterns += [
29
+    url(r'^api/', include(('api.urls', 'api'), namespace='api')),
30
+    url(r'^uniapi/', include(('django_uniapi.urls', 'uniapi'), namespace='uniapi')),
31
+]
32
+
33
+urlpatterns += [
34
+    # url(r'^s/', include(('django_short_url.urls', 'django_short_url'), namespace='django_short_url')),
35
+]
36
+
37
+urlpatterns += [
38
+    url(r'^w/', include(('django_we.urls', 'shortwechat'), namespace='shortwechat')),
39
+    url(r'^we/', include(('django_we.urls', 'wechat'), namespace='wechat')),
40
+]
41
+
42
+urlpatterns += [
43
+    # url(r'^p/', include(('page.urls', 'shortpage'), namespace='shortpage')),
44
+    # url(r'^page/', include(('page.urls', 'page'), namespace='page')),
45
+]
46
+
47
+if settings.DEBUG:
48
+    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
49
+    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
50
+
51
+# AdminSite
52
+admin.site.site_header = 'Django administration'
53
+admin.site.site_title = 'Django site admin'
54
+# Make site_url/index_title None to hidden
55
+admin.site.site_url = '/'
56
+admin.site.index_title = 'Site administration'

+ 17 - 0
thermometer/wsgi.py

@@ -0,0 +1,17 @@
1
+"""
2
+WSGI config for thermometer project.
3
+
4
+It exposes the WSGI callable as a module-level variable named ``application``.
5
+
6
+For more information on this file, see
7
+https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
8
+"""
9
+
10
+import os
11
+
12
+from django.core.wsgi import get_wsgi_application
13
+
14
+
15
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thermometer.settings")
16
+
17
+application = get_wsgi_application()

+ 0 - 0
utils/__init__.py


+ 0 - 0
utils/error/__init__.py


+ 77 - 0
utils/error/errno_utils.py

@@ -0,0 +1,77 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from StatusCode import BaseStatusCode, StatusCodeField
4
+
5
+
6
+class ParamStatusCode(BaseStatusCode):
7
+    """ 4000xx 参数相关错误码 """
8
+    PARAM_NOT_FOUND = StatusCodeField(400000, 'Param Not Found', description=u'参数不存在')
9
+
10
+
11
+class ProfileStatusCode(BaseStatusCode):
12
+    """ 4001xx 用户相关错误码 """
13
+    PROFILE_NOT_FOUND = StatusCodeField(400101, 'Profile Not Found', description=u'用户不存在')
14
+
15
+
16
+class PhoneStatusCode(BaseStatusCode):
17
+    """ 4002xx 手机相关错误码 """
18
+    INVALID_PHONE = StatusCodeField(400200, 'Invalid Phone', description=u'非法手机号')
19
+    PHONE_NOT_FOUND = StatusCodeField(400201, 'Phone Not Found', description=u'手机号不存在')
20
+    PHONE_ALREADY_EXISTS = StatusCodeField(400202, 'Phone Already Exists', description=u'手机号已存在')
21
+
22
+
23
+class OrderStatusCode(BaseStatusCode):
24
+    """ 4040xx 订单/支付相关错误码 """
25
+    UNIFIED_ORDER_FAIL = StatusCodeField(404000, 'Unified Order Fail', description=u'统一下单失败')
26
+    ORDER_NOT_FOUND = StatusCodeField(404001, 'Order Not Found', description=u'订单不存在')
27
+    # 订单支付状态
28
+    ORDER_NOT_PAY = StatusCodeField(404011, 'Order Not Pay', description=u'订单未支付')
29
+    ORDER_PAYING = StatusCodeField(404012, 'Order Paying', description=u'订单支付中')
30
+    ORDER_PAY_FAIL = StatusCodeField(404013, 'Order Pay Fail', description=u'微信支付失败')
31
+    # 通知校验状态
32
+    SIGN_CHECK_FAIL = StatusCodeField(404090, 'Sign Check Fail', description=u'签名校验失败')
33
+    FEE_CHECK_FAIL = StatusCodeField(404091, 'FEE Check Fail', description=u'金额校验失败')
34
+
35
+
36
+class PayStatusCode(BaseStatusCode):
37
+    """ 4041xx 支付相关错误码 """
38
+
39
+
40
+class WithdrawStatusCode(BaseStatusCode):
41
+    """ 4042xx 提现相关错误码 """
42
+    BALANCE_INSUFFICIENT = StatusCodeField(404200, 'Balance Insufficient', description=u'提现金额不足')
43
+
44
+
45
+class TokenStatusCode(BaseStatusCode):
46
+    """ 4090xx 票据相关错误码 """
47
+    TOKEN_NOT_FOUND = StatusCodeField(409001, 'Token Not Found', description=u'票据不存在')
48
+
49
+
50
+class SignatureStatusCode(BaseStatusCode):
51
+    """ 4091xx 签名校验错误 """
52
+    SIGNATURE_ERROR = StatusCodeField(409101, 'Signature Error', description=u'签名错误')
53
+
54
+
55
+class GVCodeStatusCode(BaseStatusCode):
56
+    """ 4092xx 图形验证码相关错误码 """
57
+    GRAPHIC_VCODE_ERROR = StatusCodeField(409201, 'Graphic VCode Error', description=u'图形验证码错误')
58
+
59
+
60
+class SVCodeStatusCode(BaseStatusCode):
61
+    """ 4093xx 短信验证码相关错误码 """
62
+    SMS_QUOTA_LIMIT = StatusCodeField(409300, 'SMS Quota Limit', description=u'短信次数超限')
63
+    SMS_VCODE_ERROR = StatusCodeField(409301, 'SMS VCode Error', description=u'验证码错误,请稍后重试')
64
+    SMS_VCODE_HAS_SEND = StatusCodeField(409302, 'SMS VCode Has Send', description=u'验证码已发送,请勿重复获取')
65
+
66
+
67
+class InsufficientStatusCode(BaseStatusCode):
68
+    """ 4095xx 不足相关错误码 """
69
+    BALANCE_INSUFFICIENT = StatusCodeField(409501, 'Balance Insufficient', description=u'余额不足')
70
+    INTEGRAL_INSUFFICIENT = StatusCodeField(409502, 'Integral Insufficient', description=u'积分不足')
71
+
72
+
73
+class PermissionStatusCode(BaseStatusCode):
74
+    """ 4099xx 权限相关错误码 """
75
+    PERMISSION_DENIED = StatusCodeField(409900, 'Permission Denied', description=u'权限不足')
76
+    UPLOAD_PERMISSION_DENIED = StatusCodeField(409910, 'Upload Permission Denied', description=u'上传权限不足')
77
+    UPDATE_PERMISSION_DENIED = StatusCodeField(409930, 'Update Permission Denied', description=u'更新权限不足')

+ 24 - 0
utils/error/response_utils.py

@@ -0,0 +1,24 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from json_response import JsonpResponse, JsonResponse
4
+from StatusCode import StatusCodeField
5
+
6
+
7
+def response_data(status_code=200, message=None, description=None, data={}, **kwargs):
8
+    return dict({
9
+        'status': status_code,
10
+        'message': message,
11
+        'description': description,
12
+        'data': data,
13
+    }, **kwargs)
14
+
15
+
16
+def response(status_code=200, message=None, description=None, data={}, msg_args=[], msg_kwargs={}, desc_args=[], desc_kwargs={}, request=None, callback=None, **kwargs):
17
+    # Final Message and Description
18
+    message, description = (message or status_code.message, description or status_code.description) if isinstance(status_code, StatusCodeField) else (message, description)
19
+    # Final Response Data
20
+    resp_data = response_data(status_code, (message or '').format(*msg_args, **msg_kwargs), (description or '').format(*desc_args, **desc_kwargs), data, **kwargs)
21
+    # Assign Callback
22
+    callback = callback or (request and request.GET.get('callback'))
23
+    # Call JsonResponse or JsonpResponse
24
+    return JsonpResponse(callback, resp_data, safe=False) if callback else JsonResponse(resp_data, safe=False)

+ 0 - 0
utils/redis/__init__.py


+ 6 - 0
utils/redis/connect.py

@@ -0,0 +1,6 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.conf import settings
4
+
5
+
6
+r = settings.REDIS_CACHE

+ 1 - 0
utils/redis/rkeys.py

@@ -0,0 +1 @@
1
+# -*- coding: utf-8 -*-

+ 0 - 0
utils/user/__init__.py


+ 18 - 0
utils/user/userinfo_save.py

@@ -0,0 +1,18 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+
4
+def userinfo_save(userinfo):
5
+    """ Save profile or something else """
6
+    # from account.models import UserInfo
7
+    # from django.conf import settings
8
+    #
9
+    # unique_identifier = userinfo.get(settings.WECHAT_UNIQUE_IDENTIFICATION, '')
10
+    #
11
+    # user, created = UserInfo.objects.select_for_update().get_or_create(**{settings.WECHAT_UNIQUE_IDENTIFICATION: unique_identifier})
12
+    # user.unionid = userinfo.get('unionid', '')
13
+    # user.openid = userinfo.get('openid', '')
14
+    # user.nickname = userinfo.get('nickname', '')
15
+    # user.avatar = userinfo.get('headimgurl', '')
16
+    # user.save()
17
+    #
18
+    # return user

adminSystem - Gogs: Go Git Service

暫無描述

LICENSE 1.5KB

    Copyright (c) 2016, Istanbul Code Coverage All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of babel-plugin-istanbul nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.