You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
4.8 KiB
107 lines
4.8 KiB
// 批量拉取 v29 客户模块 A4 页族 + a7-3-3 规则页 HTML(OSS 公开直下)并提取文本
|
|
// 用法: node fetch-v29-a4-pages.mjs
|
|
// 产物: .scratch/lanhu-latest/v29-customer-pages/<page>.txt(id | 类型 | 名称 | 文本 全量)
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
const OSS = 'https://lanhu-axure-file.oss-cn-beijing.aliyuncs.com/';
|
|
const MANIFEST = 'e:/code/crm-backend-matt/.scratch/lanhu-latest/axure-v29.json';
|
|
const OUT_DIR = 'e:/code/crm-backend-matt/.scratch/lanhu-latest/v29-customer-pages';
|
|
|
|
// A4 客户模块全页族(41 页,含划出对照页 a4-6 查重合并 / a4-5-4 联系人导入 / a4-4-9,10 战略协议)
|
|
const PAGES = [
|
|
'a4-1-1_客户公海列表(列表视图).html',
|
|
'a4-1-2_客户公海列表(分屏视图).html',
|
|
'a4-2-1_客户总览列表(分屏视图).html',
|
|
'a4-2-1_客户总览列表(列表视图).html',
|
|
'a4-2-1_客户总览列表(卡片视图).html',
|
|
'a4-3-1_我的客户列表(分屏视图).html',
|
|
'a4-3-1_我的客户列表(列表视图).html',
|
|
'a4-3-1_我的客户列表(卡片视图).html',
|
|
'a4-3-2_客户导入.html',
|
|
'a4-3-3-1_新增客户信息.html',
|
|
'a4-3-3-2_编辑客户信息.html',
|
|
'a4-3-3-3______.html',
|
|
'a4-3-3-4_ocr____.html',
|
|
'a4-4-1_客户详情(客户信息).html',
|
|
'a4-4-1_客户详情(已归档客户).html',
|
|
'a4-4-1_客户详情(已被合并客户).html',
|
|
'a4-4-2_客户详情(联系人).html',
|
|
'a4-4-3_客户详情(跟进记录).html',
|
|
'a4-4-4_客户详情(关联商机).html',
|
|
'a4-4-5_客户详情(关联项目).html',
|
|
'a4-4-6_客户详情(战略协议).html',
|
|
'a4-4-7_客户详情(团队成员).html',
|
|
'a4-4-8_客户详情(操作日志).html',
|
|
'a4-4-9_新增战略协议.html',
|
|
'a4-4-10_编辑战略协议.html',
|
|
'a4-5-1_联系人列表(分屏视图).html',
|
|
'a4-5-1_联系人列表(列表视图).html',
|
|
'a4-5-2_新增联系人.html',
|
|
'a4-5-3_编辑联系人.html',
|
|
'a4-5-4_联系人导入.html',
|
|
'a4-5-5_联系人详情(联系人信息).html',
|
|
'a4-5-6_联系人详情(操作日志).html',
|
|
'a4-6-1_客户查重(卡片视图).html',
|
|
'a4-6-2_客户查重(列表视图).html',
|
|
'a4-6-3_客户合并.html',
|
|
'a4-7-1_客户交割(发起交接).html',
|
|
'a4-7-2_客户交割(客户分配).html',
|
|
'a4-7-3_客户交割(交接记录).html',
|
|
'a4-7-4_交接记录详情.html',
|
|
'a7-3-3-1_客户管理设置(超期未跟进提醒).html',
|
|
'a7-3-3-2_客户管理设置(客户查重设置).html',
|
|
];
|
|
|
|
const decode = (s) => s
|
|
.replace(/&#x([0-9A-Fa-f]+);/g, (_, h) => String.fromCodePoint(parseInt(h, 16)))
|
|
.replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(parseInt(d, 10)))
|
|
.replace(/ /g, ' ').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
|
|
// 与 extract-html-text.mjs 同算法,窗口放宽到 1000 字符(弹窗/表格控件文本较长)
|
|
function extract(html) {
|
|
const re = /<!--\s*(.*?)\s*-->\s*<div id="(u\d+)"[^>]*>/g;
|
|
const items = [];
|
|
let m;
|
|
while ((m = re.exec(html)) !== null) {
|
|
const [, comment, id] = m;
|
|
const tm = comment.match(/^(.*?)\s*[((](.+?)[))]$/);
|
|
const name = tm ? tm[1] : comment;
|
|
const type = tm ? tm[2] : '其他';
|
|
const after = html.slice(m.index, m.index + 1000);
|
|
const tr = after.match(new RegExp(`id="${id}_text"[^>]*>[\\s\\S]*?</div>`));
|
|
let text = '';
|
|
if (tr) {
|
|
text = (tr[0].match(/<p><span>([\s\S]*?)<\/span><\/p>/g) || [])
|
|
.map(p => decode(p.replace(/<\/?p>/g, '').replace(/<\/?span>/g, '')))
|
|
.join(' | ');
|
|
}
|
|
items.push({ id, name: decode(name), type: decode(type), text: text.trim() });
|
|
}
|
|
return items;
|
|
}
|
|
|
|
const manifest = JSON.parse(fs.readFileSync(MANIFEST, 'utf8'));
|
|
fs.mkdirSync(OUT_DIR, { recursive: true });
|
|
|
|
for (const page of PAGES) {
|
|
const entry = manifest.pages?.[page];
|
|
if (!entry?.html?.sign_md5) { console.log(`MISS ${page} (清单无条目)`); continue; }
|
|
const outFile = path.join(OUT_DIR, page.replace(/\.html$/, '.txt'));
|
|
if (fs.existsSync(outFile)) { console.log(`SKIP ${page} (已有缓存)`); continue; }
|
|
const url = OSS + entry.html.sign_md5;
|
|
try {
|
|
const res = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
|
|
if (!res.ok) { console.log(`FAIL ${page} HTTP ${res.status}`); continue; }
|
|
const html = await res.text();
|
|
const items = extract(html);
|
|
const out = items.filter(i => i.text)
|
|
.map(i => `${i.id} | ${i.type} | ${i.name} | ${i.text}`)
|
|
.join('\n');
|
|
fs.writeFileSync(outFile, `# ${page}\n# 控件 ${items.length},有文本 ${items.filter(i => i.text).length}\n\n${out}\n`, 'utf8');
|
|
console.log(`OK ${page} 控件=${items.length} 文本=${items.filter(i => i.text).length}`);
|
|
} catch (e) {
|
|
console.log(`ERR ${page} ${String(e).slice(0, 120)}`);
|
|
}
|
|
}
|
|
console.log('done ->', OUT_DIR);
|
|
|