新增农户功能升级:身份证OCR/OSS上传、头像采集、同名村检测、Region热度排序及表单体验优化
- Region 表新增热度列,热门省份优先显示 - 区县下拉按地级市分组、已录区县优先、支持全省搜索 - 组选择内置一组至二十组 - 银行卡号独立行+粗体预览,开户行独立行 - 新增农户类型:农户/个体户/合作社/经营集体/公司 - 身份证正反面支持高拍仪/摄像头OCR与手机扫码上传,附件存本地/OSS - 新增农户头像采集组件(摄像头/本地上传),预留人脸识别收购扩展 - 同名村弹窗提醒(防选错乡镇) - 编辑窗体禁止遮罩/Esc误关,整体加宽适配高频操作 - 修复二维码局域网手机无法访问(监听0.0.0.0、局域网IP识别、Vite代理兜底)
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* AreaCity 全国行政区划数据导入脚本
|
||||
* ==================================
|
||||
* 数据源: https://github.com/xiangyuecn/AreaCity-JsSpider-StatsGov
|
||||
* 下载: https://github.com/xiangyuecn/AreaCity-JsSpider-StatsGov/releases/download/2025.251231.260403/ok_data_level3-4.csv.7z
|
||||
* (Gitee 备用: https://gitee.com/xiangyuecn/AreaCity-JsSpider-StatsGov/releases)
|
||||
* 说明: 解压后得到 ok_data_level4.csv(省市区镇四级,UTF-8 带 BOM)
|
||||
* 列: id, pid, deep, name, pinyin_prefix, pinyin, ext_id, ext_name
|
||||
* deep: 0=省 1=市(地级/直辖市虚拟) 2=县(区/县级市) 3=乡镇(镇/乡/街道)
|
||||
*
|
||||
* 用法:
|
||||
* 1) 下载并解压 ok_data_level4.csv 到本目录 tmp/ok_data_level4.csv
|
||||
* 2) npm i mysql2
|
||||
* 3) node import-regions.mjs
|
||||
* 脚本会 DROP 并重建 Regions 表后导入(幂等,可重复执行)。
|
||||
*/
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import mysql from 'mysql2/promise'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const root = path.resolve(__dirname, '../..')
|
||||
const csvPath = path.join(__dirname, 'tmp/ok_data_level4.csv')
|
||||
|
||||
if (!fs.existsSync(csvPath)) {
|
||||
console.error('未找到 ' + csvPath + ',请先下载并解压数据文件')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// ---------- 读取数据库连接串 ----------
|
||||
const appCfg = JSON.parse(fs.readFileSync(path.join(root, 'backend/AgriculturalPlatform.Api/appsettings.json'), 'utf8'))
|
||||
const parseCs = (s) => Object.fromEntries(
|
||||
s.split(';').filter(Boolean).map(kv => {
|
||||
const i = kv.indexOf('=')
|
||||
return [kv.slice(0, i).trim().toLowerCase(), kv.slice(i + 1).trim()]
|
||||
})
|
||||
)
|
||||
const dbc = parseCs(appCfg.ConnectionStrings.Default)
|
||||
|
||||
// ---------- 解析 CSV ----------
|
||||
const raw = fs.readFileSync(csvPath, 'utf8').replace(/^\uFEFF/, '')
|
||||
const lines = raw.split(/\r?\n/).filter(l => l.trim().length > 0)
|
||||
lines.shift() // 去掉表头
|
||||
|
||||
const parseRow = (line) => {
|
||||
const fields = []
|
||||
let cur = '', inQ = false
|
||||
for (const ch of line) {
|
||||
if (ch === '"') inQ = !inQ
|
||||
else if (ch === ',' && !inQ) { fields.push(cur); cur = '' }
|
||||
else cur += ch
|
||||
}
|
||||
fields.push(cur)
|
||||
return fields
|
||||
}
|
||||
|
||||
// 常用省份(热度高的排前面,值越大越靠前,供前端优先展示)
|
||||
const HOT_PROVINCES = [
|
||||
'四川省', '广西壮族自治区', '陕西省', '重庆市', '安徽省',
|
||||
'云南省', '贵州省', '河南省', '山东省', '湖北省', '湖南省',
|
||||
'甘肃省', '新疆维吾尔自治区', '江西省', '福建省', '广东省',
|
||||
'河北省', '山西省', '江苏省', '浙江省'
|
||||
]
|
||||
const hotOf = (deep, extName) => {
|
||||
if (deep !== 0) return 0
|
||||
const i = HOT_PROVINCES.indexOf(extName)
|
||||
return i < 0 ? 0 : HOT_PROVINCES.length - i
|
||||
}
|
||||
|
||||
const rows = []
|
||||
for (const line of lines) {
|
||||
const [id, pid, deep, name, pfx, pinyin, , extName] = parseRow(line)
|
||||
if (!id) continue
|
||||
rows.push([Number(id), Number(pid), Number(deep), name, extName, pinyin, pfx, hotOf(Number(deep), extName)])
|
||||
}
|
||||
console.log('解析完成,共 ' + rows.length + ' 条')
|
||||
const stat = {}
|
||||
for (const r of rows) stat[r[2]] = (stat[r[2]] || 0) + 1
|
||||
console.log('层级分布(deep):', JSON.stringify(stat))
|
||||
|
||||
// ---------- 建表并导入 ----------
|
||||
const conn = await mysql.createConnection({
|
||||
host: dbc.server,
|
||||
port: Number(dbc.port || 3306),
|
||||
user: dbc.user,
|
||||
password: dbc.password,
|
||||
database: dbc.database,
|
||||
charset: 'utf8mb4'
|
||||
})
|
||||
|
||||
await conn.query('DROP TABLE IF EXISTS Regions')
|
||||
await conn.query(`CREATE TABLE Regions (
|
||||
Id INT NOT NULL PRIMARY KEY,
|
||||
Pid INT NOT NULL,
|
||||
Deep INT NOT NULL,
|
||||
Name VARCHAR(100) NOT NULL,
|
||||
ExtName VARCHAR(100) NOT NULL,
|
||||
Pinyin VARCHAR(200) NOT NULL DEFAULT '',
|
||||
PinyinPrefix VARCHAR(10) NOT NULL DEFAULT '',
|
||||
Hot INT NOT NULL DEFAULT 0,
|
||||
KEY idx_regions_pid (Pid),
|
||||
KEY idx_regions_deep (Deep)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci`)
|
||||
|
||||
const BATCH = 1000
|
||||
for (let i = 0; i < rows.length; i += BATCH) {
|
||||
const chunk = rows.slice(i, i + BATCH)
|
||||
await conn.query('INSERT INTO Regions (Id, Pid, Deep, Name, ExtName, Pinyin, PinyinPrefix, Hot) VALUES ?', [chunk])
|
||||
}
|
||||
|
||||
const [cnt] = await conn.query('SELECT COUNT(*) AS c FROM Regions')
|
||||
console.log('导入完成,Regions 表共 ' + cnt[0].c + ' 条记录')
|
||||
await conn.end()
|
||||
Generated
+148
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"name": "areacity",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "areacity",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"mysql2": "^3.23.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "26.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz",
|
||||
"integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~8.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aws-ssl-profiles": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
||||
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/generate-function": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
|
||||
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-property": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
|
||||
"integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/is-property": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/lru.min": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz",
|
||||
"integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"bun": ">=1.0.0",
|
||||
"deno": ">=1.30.0",
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wellwelwel"
|
||||
}
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.23.3",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.23.3.tgz",
|
||||
"integrity": "sha512-ehp9HEKr4wVJaBOUVxNFa+CNrsCCCZ6363/jbGhb7WpEmSRNIXjHBjFs5K2s2cXn7j/RhDieejsQJ6nfUwD6vQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"aws-ssl-profiles": "^1.1.2",
|
||||
"generate-function": "^2.3.1",
|
||||
"iconv-lite": "^0.7.3",
|
||||
"long": "^5.3.2",
|
||||
"lru.min": "^1.1.4",
|
||||
"named-placeholders": "^1.1.6",
|
||||
"sql-escaper": "^1.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/named-placeholders": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz",
|
||||
"integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lru.min": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sql-escaper": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.5.1.tgz",
|
||||
"integrity": "sha512-4toX5E1fQbBrpfXidaHnF0669nkAdETeIPTs2SUjxxD7RRIs9ICG4gtpmfc68JCEKehsdwLFqBu9VlQqZ1P1gg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"bun": ">=1.0.0",
|
||||
"deno": ">=2.0.0",
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/mysqljs/sql-escaper?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
|
||||
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "areacity",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"mysql2": "^3.23.3"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user