v24 第 9 批:名册九条(分组按钮/加入名册/生日月日/地址四级/千人性能/拖动修复/删除人员/返回名册/Semi DatePicker)
- #131 名册卡片加「分组」按钮(details+radio,显示当前分组,选中即改) - #132 修复「从已有人里加入名册」无反应 - #133 生日只显示月和日(阳历 MM-DD / 农历中文名),PersonQuery::birthdaysOf 取代 birthdayOf - #134 地址结构化为 国家/省/市/区+详细:regions 表(3429 行全国区划)+ Region.php + ?r=regions 级联接口 + 表单 .addr-grid + 老地址回填(Schema v16) - #135 千人名册性能:.person content-visibility:auto + 名册页 ob_gzhandler (实测 服务端 1.15s/3.8MB → 0.17s/87KB;客户端导航→load 1.35s → 0.37s) - #136 拖动排序改 Pointer Events(Chrome 下 HTML5 DnD 在 DOM 变动时断) - #137 个人详情页底部「删除人员」 - #138 编辑资料页加「返回名册」 - #139 所有日期选择换 Semi Design DatePicker(渐进增强:原生四字段保 POST 契约, 懒加载 vendor semi UMD,值回写原字段;工作经历 type=month 一并升级;宣纸主题对齐) 验证:e2e 785/0、batch9 37/0、upgrade 126/0、picker 28/0、mobile 688/0、interact 97/0、 batch_e 91/0、import 21/0、douban 22/0、drag 5/0、semi-integrate 28/0、semi-probe 17/0、 geom 5/5;部署后线上自检 16/16(含 4 个 semi 资源 200 + regions 路由)。
This commit is contained in:
+61
-4
@@ -86,11 +86,10 @@ final class ContactImporter
|
||||
}
|
||||
|
||||
// ---- ③ 没命中:新建 ----
|
||||
$d = [
|
||||
$d = array_merge([
|
||||
'name' => $name !== '' ? $name : $phone,
|
||||
'phone' => $phone,
|
||||
'email' => (string)($r['email'] ?? ''),
|
||||
'address' => (string)($r['address'] ?? ''),
|
||||
'org' => (string)($r['org'] ?? ''),
|
||||
// 职务 + 职称合成一列(与 PersonJob::joinTitle 同一口径:
|
||||
// 两个都有时用 " · " 分开,只有一个就只用那个)
|
||||
@@ -109,7 +108,7 @@ final class ContactImporter
|
||||
'birthday_lunar' => '',
|
||||
'birthday_lunar_leap' => 0,
|
||||
'birthday_id_card' => '',
|
||||
];
|
||||
], self::addrFields($r));
|
||||
try {
|
||||
$pid = Person::create($familyId, $d);
|
||||
} catch (\Throwable $ex) {
|
||||
@@ -172,6 +171,53 @@ final class ContactImporter
|
||||
*
|
||||
* @return string[] 这次补上了哪些(中文标签,用来告诉用户"改了什么")
|
||||
*/
|
||||
/**
|
||||
* 把一条导入记录里的地址整理成 persons 的五个字段。
|
||||
*
|
||||
* 分两种来源:
|
||||
* · vCard 的 ADR **本来就是分段的**(街道/城市/省/国家各占一段)→ 直接用,
|
||||
* 再用 Region::parse() 从街道那一段里认出「区 / 县」;
|
||||
* · CSV 那种一整串自由文本 → 整串交给 Region::parse() 逐级前缀匹配拆开。
|
||||
*
|
||||
* ⚠️ 认不出来的部分**一律留在 address(详细地址)里**,绝不丢:
|
||||
* 结构化是为了"以后能按省找人",不是为了让地址变短。
|
||||
*
|
||||
* @return array{address:string,addr_country:string,addr_province:string,addr_city:string,addr_district:string}
|
||||
*/
|
||||
private static function addrFields(array $r): array
|
||||
{
|
||||
$country = trim((string)($r['addr_country'] ?? ''));
|
||||
$province = trim((string)($r['addr_province'] ?? ''));
|
||||
$city = trim((string)($r['addr_city'] ?? ''));
|
||||
$district = trim((string)($r['addr_district'] ?? ''));
|
||||
$detail = trim((string)($r['address'] ?? ''));
|
||||
|
||||
if ($province === '' && $city === '' && $detail !== '') {
|
||||
// 一整串自由文本 → 逐级前缀匹配
|
||||
$p = Region::parse($detail);
|
||||
$country = $country !== '' ? $country : (string)($p['country'] ?? '');
|
||||
$province = (string)($p['province'] ?? '');
|
||||
$city = (string)($p['city'] ?? '');
|
||||
$district = (string)($p['district'] ?? '');
|
||||
$detail = (string)($p['detail'] ?? '');
|
||||
} elseif ($detail !== '' && $district === '') {
|
||||
// 已经有省/市(vCard 给的),从剩下的街道里再认一次区县
|
||||
$p = Region::parse($detail);
|
||||
if (($p['district'] ?? null) !== null) {
|
||||
$district = (string)$p['district'];
|
||||
$detail = (string)($p['detail'] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'address' => $detail,
|
||||
'addr_country' => $country,
|
||||
'addr_province' => $province,
|
||||
'addr_city' => $city,
|
||||
'addr_district' => $district,
|
||||
];
|
||||
}
|
||||
|
||||
private static function fillMissing(array $person, array $r, int $meId): array
|
||||
{
|
||||
$pid = (int)$person['id'];
|
||||
@@ -179,9 +225,12 @@ final class ContactImporter
|
||||
$labels = []; // 给人看的"补了什么"
|
||||
|
||||
// ---- ① persons 上的标量列:他空着才补 ----
|
||||
$addr = self::addrFields($r);
|
||||
$scalar = [
|
||||
'email' => ['邮箱', (string)($r['email'] ?? ''), 200],
|
||||
'address' => ['住址', (string)($r['address'] ?? ''), 200],
|
||||
// ⚠️ 地址要走 addrFields() 拆过的那份:直接拿 $r['address'] 会把
|
||||
// vCard 里"省+市+街道"拼成的一整串原样塞进详细地址,等于没结构化。
|
||||
'address' => ['住址', $addr['address'], 200],
|
||||
'org' => ['工作单位', (string)($r['org'] ?? ''), 120],
|
||||
'note' => ['备注', (string)($r['note'] ?? ''), 2000],
|
||||
];
|
||||
@@ -200,6 +249,14 @@ final class ContactImporter
|
||||
$cols['`title` = ?'] = mb_substr($newTitle, 0, 120, 'UTF-8');
|
||||
$labels[] = '职务/职称';
|
||||
}
|
||||
// 地址的四级结构:同样**只补空着的**(他已经在表单里选过省市区就不动)
|
||||
foreach (['addr_country' => '国家', 'addr_province' => '省',
|
||||
'addr_city' => '市', 'addr_district' => '区/县'] as $col => $label) {
|
||||
if (trim((string)($person[$col] ?? '')) === '' && trim($addr[$col]) !== '') {
|
||||
$cols["`$col` = ?"] = mb_substr(trim($addr[$col]), 0, 60, 'UTF-8');
|
||||
$labels[] = $label;
|
||||
}
|
||||
}
|
||||
// 生日:他一个生日都没有时才补。有生日就绝不动 —— 生日是强身份信息,错了很难发现。
|
||||
$hasBd = trim((string)Birthday::solarOf($person)) !== ''
|
||||
|| trim((string)($person['birthday_lunar'] ?? '')) !== '';
|
||||
|
||||
Reference in New Issue
Block a user