ich.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. import { writeFile } from 'fs/promises';
  2. import CommonContent, { GetContentListParams, type GetContentDetailItem, type GetContentListItem } from '../../api/CommonContent';
  3. import ProjectsContent from '../../api/inheritor/ProjectsContent';
  4. import InheritorContent from '../../api/inheritor/InheritorContent';
  5. import SeminarContent from '../../api/inheritor/SeminarContent';
  6. import UnitContent from '../../api/inheritor/UnitContent';
  7. import UnmoveableContent from '../../api/inheritor/UnmoveableContent';
  8. import path from 'path';
  9. import fs from 'fs';
  10. import { argv, cwd } from 'process';
  11. const data = [] as Array<GetContentListItem & { detail?: GetContentDetailItem }>;
  12. // HTML转Markdown的简单实现
  13. function htmlToMarkdown(html: string): string {
  14. if (!html) return '';
  15. // 处理标题
  16. html = html.replace(/<h1[^>]*>(.*?)<\/h1>/gi, '# $1\n\n');
  17. html = html.replace(/<h2[^>]*>(.*?)<\/h2>/gi, '## $1\n\n');
  18. html = html.replace(/<h3[^>]*>(.*?)<\/h3>/gi, '### $1\n\n');
  19. // 处理段落
  20. html = html.replace(/<p[^>]*>(.*?)<\/p>/gi, '$1\n\n');
  21. // 处理加粗
  22. html = html.replace(/<strong[^>]*>(.*?)<\/strong>/gi, '**$1**');
  23. html = html.replace(/<b[^>]*>(.*?)<\/b>/gi, '**$1**');
  24. // 处理斜体
  25. html = html.replace(/<em[^>]*>(.*?)<\/em>/gi, '*$1*');
  26. html = html.replace(/<i[^>]*>(.*?)<\/i>/gi, '*$1*');
  27. // 处理列表
  28. html = html.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, (match, content) => {
  29. return content.replace(/<li[^>]*>(.*?)<\/li>/gi, '- $1\n') + '\n';
  30. });
  31. html = html.replace(/<ol[^>]*>([\s\S]*?)<\/ol>/gi, (match, content, index) => {
  32. let count = 1;
  33. return content.replace(/<li[^>]*>(.*?)<\/li>/gi, () => {
  34. return `${count++}. $1\n`;
  35. }) + '\n';
  36. });
  37. // 处理图片
  38. html = html.replace(/<img[^>]*src="([^"]*)"[^>]*alt="([^"]*)"[^>]*>/gi, '![$2]($1)');
  39. // 处理链接
  40. html = html.replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, '[$2]($1)');
  41. // 处理换行
  42. html = html.replace(/<br[^>]*>/gi, '\n');
  43. // 去除所有HTML标签
  44. html = html.replace(/<[^>]*>/g, '');
  45. // 处理多余的换行
  46. html = html.replace(/\n\s*\n/g, '\n\n');
  47. return html.trim();
  48. }
  49. // 生成Markdown文本
  50. async function generateMarkdownIch(subDir: string, type: string) {
  51. for (const item of data) {
  52. let md = '';
  53. // 基本信息
  54. md += `# ${item.title}\n\n`;
  55. if (item.desc)
  56. md += `${item.desc}\n\n`;
  57. md += `## 基本信息\n\n`;
  58. md += `类型:${type}\n\n`;
  59. function addRow(key: string, value: any) {
  60. if (value)
  61. md += `- ${key}: ${value}\n`;
  62. }
  63. addRow('级别', item.levelText);
  64. addRow('类别', item.ichTypeText);
  65. addRow('地区', item.regionText);
  66. addRow('批次', item.batchText);
  67. addRow('保护单位', item.unit);
  68. addRow('地址', item.address);
  69. addRow('字号名称', item.fontName);
  70. addRow('认定类型', item.brandType);
  71. addRow('其他级别保护单位', item.detail?.otherLevel && item.detail.otherLevel.length > 0 ? `${item.detail.otherLevel.length}个` : '');
  72. md += `\n## 数据库索引ID\n\n`;
  73. md += `- 类型: intangible\n`;
  74. md += `- ID: ${item.id || '无'}\n\n`;
  75. // 图片
  76. if (item.images && item.images.length > 0) {
  77. md += `## 图片\n\n`;
  78. item.images.forEach(image => {
  79. md += `![${item.title}图片](${image})\n\n`;
  80. });
  81. }
  82. // 详细信息
  83. if (item.detail) {
  84. const detail = item.detail as GetContentDetailItem;
  85. // 简介
  86. if (detail.intro) {
  87. md += `## 简介\n\n`;
  88. md += htmlToMarkdown(detail.intro) + '\n\n';
  89. }
  90. // 内容
  91. if (detail.content) {
  92. md += `## 内容\n\n`;
  93. md += htmlToMarkdown(detail.content) + '\n\n';
  94. }
  95. // 传承谱系
  96. if (detail.pedigree) {
  97. md += `## 传承谱系\n\n`;
  98. md += htmlToMarkdown(detail.pedigree as string) + '\n\n';
  99. }
  100. // 视频
  101. if (detail.video) {
  102. md += `## 视频\n\n`;
  103. md += `[视频](${detail.video})\n\n`;
  104. }
  105. if (detail.publishVideo)
  106. md += `[介绍视频](${detail.publishVideo})\n\n`;
  107. // 传承人
  108. if (detail.inheritorsList && detail.inheritorsList.length > 0) {
  109. md += `## 相关传承人\n\n`;
  110. if (detail.inheritor) {
  111. md += htmlToMarkdown(detail.inheritor) + '\n\n';
  112. }
  113. detail.inheritorsList.forEach(inheritor => {
  114. md += `### ${inheritor.title}\n\n`;
  115. md += `级别:${inheritor.levelLext || '无'}\n\n`;
  116. md += `#### 数据库索引ID\n\n`;
  117. md += `- 类型: inheritor\n`;
  118. md += `- ID: ${inheritor.id || '无'}\n\n`;
  119. if (inheritor.image) {
  120. md += `![传承人头像](${inheritor.image})\n\n`;
  121. }
  122. });
  123. }
  124. // 传习所
  125. if (detail.ichSitesList && detail.ichSitesList.length > 0) {
  126. md += `## 相关传习所\n\n`;
  127. detail.ichSitesList.forEach(site => {
  128. md += `### ${site.title}\n\n`;
  129. md += `级别:${site.levelLext || '无'}\n\n`;
  130. md += `地址:${site.address || '无'}\n\n`;
  131. md += `#### 数据库索引ID\n\n`;
  132. md += `- 类型: seminar\n`;
  133. md += `- ID: ${site.id || '无'}\n\n`;
  134. if (site.image) {
  135. md += `![传习所图片](${site.image})\n\n`;
  136. }
  137. });
  138. }
  139. // 同级别项目
  140. if (detail.otherLevel && detail.otherLevel.length > 0) {
  141. md += `## 其他级别非遗项目\n\n`;
  142. detail.otherLevel.forEach(project => {
  143. md += `### ${project.title}\n\n`;
  144. md += `级别:${project.levelLext || '无'}\n\n`;
  145. md += `保护单位:${project.unit || '无'}\n\n`;
  146. md += `#### 数据库索引ID\n\n`;
  147. md += `- 类型: intangible\n`;
  148. md += `- ID: ${project.id || '无'}\n\n`;
  149. });
  150. }
  151. }
  152. await writeFile(path.join(subDir, `${item.id}.md`), md);
  153. }
  154. }
  155. async function generateMarkdownInheritor(subDir: string) {
  156. for (const item of data) {
  157. let md = '';
  158. // 基本信息
  159. md += `# ${item.title}\n\n`;
  160. if (item.desc)
  161. md += `${item.desc}\n\n`;
  162. md += `## 基本信息\n\n`;
  163. md += `类型:非遗传承人\n\n`;
  164. function addRow(key: string, value: any) {
  165. if (value)
  166. md += `- ${key}: ${value}\n`;
  167. }
  168. addRow('民族', item.detail?.nation);
  169. addRow('性别', item.detail?.gender == '1'? '男' : '女');
  170. addRow('出生日期', item.detail?.dateBirth);
  171. addRow('出生地区', item.detail?.birthplace);
  172. addRow('单位', item.detail?.unit);
  173. addRow('传承项目', item.detail?.associationMeList[0]?.title);
  174. addRow('传承人级别', item.detail?.batchText);
  175. addRow('公布批次', item.detail?.batchText);
  176. md += `\n## 数据库索引ID\n\n`;
  177. md += `- 类型: inheritor\n`;
  178. md += `- ID: ${item.id || '无'}\n\n`;
  179. // 图片
  180. if (item.images && item.images.length > 0) {
  181. md += `## 图片\n\n`;
  182. item.images.forEach(image => {
  183. md += `![${item.title}图片](${image})\n\n`;
  184. });
  185. }
  186. // 详细信息
  187. if (item.detail) {
  188. const detail = item.detail as GetContentDetailItem;
  189. // 简介
  190. if (detail.intro) {
  191. md += `## 简介\n\n`;
  192. md += htmlToMarkdown(detail.intro) + '\n\n';
  193. }
  194. if (detail.content) {
  195. md += `## 详情\n\n`;
  196. md += htmlToMarkdown(detail.content) + '\n\n';
  197. }
  198. // 奖项
  199. if (detail.prize) {
  200. md += `## 奖项\n\n`;
  201. md += htmlToMarkdown(detail.prize as string) + '\n\n';
  202. }
  203. // 相关项目
  204. if (detail.associationMeList && detail.associationMeList.length > 0) {
  205. md += `## 相关项目\n\n`;
  206. detail.associationMeList.forEach(inheritor => {
  207. md += `### ${inheritor.title}\n\n`;
  208. md += `#### 数据库索引ID\n\n`;
  209. md += `- 类型: intangible\n`;
  210. md += `- ID: ${inheritor.id || '无'}\n\n`;
  211. });
  212. }
  213. // 传习所
  214. if (detail.ichSitesList && detail.ichSitesList.length > 0) {
  215. md += `## 相关传习所\n\n`;
  216. detail.ichSitesList.forEach(site => {
  217. md += `### ${site.title}\n\n`;
  218. md += `级别:${site.levelLext || '无'}\n\n`;
  219. md += `地址:${site.address || '无'}\n\n`;
  220. md += `##### 数据库索引ID\n\n`;
  221. md += `- 类型: seminar\n`;
  222. md += `- ID: ${site.id || '无'}\n\n`;
  223. if (site.image) {
  224. md += `![传习所图片](${site.image})\n\n`;
  225. }
  226. });
  227. }
  228. }
  229. await writeFile(path.join(subDir, `${item.id}.md`), md);
  230. }
  231. }
  232. async function generateMarkdownArtifact(subDir: string) {
  233. for (const item of data) {
  234. let md = '';
  235. // 基本信息
  236. md += `# ${item.title}\n\n`;
  237. if (item.desc)
  238. md += `${item.desc}\n\n`;
  239. md += `## 基本信息\n\n`;
  240. md += `类型:非遗传承人\n\n`;
  241. function addRow(key: string, value: any) {
  242. if (value)
  243. md += `- ${key}: ${value}\n`;
  244. }
  245. addRow('开放时间', item.detail?.openStatusText);
  246. addRow('年代', item.age);
  247. addRow('级别', item.levelText);
  248. addRow('所属区域', item.regionText);
  249. addRow('文物类型', item.crTypeText);
  250. addRow('单位', item.detail?.unit);
  251. md += `\n## 数据库索引ID\n\n`;
  252. md += `- 类型: artifact\n`;
  253. md += `- ID: ${item.id || '无'}\n\n`;
  254. // 图片
  255. if (item.images && item.images.length > 0) {
  256. md += `## 图片\n\n`;
  257. item.images.forEach(image => {
  258. md += `![${item.title}图片](${image})\n\n`;
  259. });
  260. }
  261. if (item.video) {
  262. md += `## 视频\n\n`;
  263. md += `![${item.title}视频](${item.video})\n\n`;
  264. }
  265. // 详细信息
  266. if (item.detail) {
  267. const detail = item.detail as GetContentDetailItem;
  268. // 简介
  269. if (detail.intro) {
  270. md += `## 简介\n\n`;
  271. md += htmlToMarkdown(detail.intro) + '\n\n';
  272. }
  273. if (detail.content) {
  274. md += `## 详情\n\n`;
  275. md += htmlToMarkdown(detail.content) + '\n\n';
  276. }
  277. // 奖项
  278. if (detail.protectedArea) {
  279. md += `## 保护范围\n\n`;
  280. md += htmlToMarkdown(detail.protectedArea as string) + '\n\n';
  281. }
  282. if (detail.environment) {
  283. md += `## 建筑环境\n\n`;
  284. md += htmlToMarkdown(detail.environment as string) + '\n\n';
  285. }
  286. if (detail.价值评估) {
  287. md += `## 价值评估\n\n`;
  288. md += htmlToMarkdown(detail.价值评估 as string) + '\n\n';
  289. }
  290. }
  291. await writeFile(path.join(subDir, `${item.id}.md`), md);
  292. }
  293. }
  294. async function main() {
  295. const type = argv[2];
  296. function makeDir(nanme: string) {
  297. const dir = path.join(cwd(), `dist/${nanme}`);
  298. if (!fs.existsSync(dir))
  299. fs.mkdirSync(dir, { recursive: true });
  300. return dir;
  301. }
  302. switch (type) {
  303. case 'ich': {
  304. const dir = makeDir('ich');
  305. (await ProjectsContent.getContentList(new GetContentListParams(), 1, 1000)).list.forEach(item => {
  306. data.push(item);
  307. });
  308. for (const item of data)
  309. item.detail = (await ProjectsContent.getContentDetail(item.id)) as GetContentDetailItem;
  310. generateMarkdownIch(dir, '非遗项目');
  311. break;
  312. }
  313. case 'seminar': {
  314. const dir = makeDir('seminar');
  315. (await SeminarContent.getContentList(new GetContentListParams(), 1, 1000)).list.forEach(item => {
  316. data.push(item);
  317. });
  318. for (const item of data)
  319. item.detail = (await SeminarContent.getContentDetail(item.id)) as GetContentDetailItem;
  320. generateMarkdownIch(dir, '非遗传习所');
  321. break;
  322. }
  323. case 'old': {
  324. const dir = makeDir('old');
  325. (await CommonContent.getContentList(new GetContentListParams()
  326. .setModelId(17)
  327. .setMainBodyColumnId(312)
  328. , 1, 1000)).list.forEach(item => {
  329. data.push(item);
  330. });
  331. for (const item of data)
  332. item.detail = (await CommonContent.getContentDetail(item.id)) as GetContentDetailItem;
  333. generateMarkdownIch(dir, '老字号');
  334. break;
  335. }
  336. case 'unit': {
  337. const dir = makeDir('unit');
  338. (await UnitContent.getContentList(new GetContentListParams(), 1, 1000)).list.forEach(item => {
  339. data.push(item);
  340. });
  341. for (const item of data)
  342. item.detail = (await UnitContent.getContentDetail(item.id)) as GetContentDetailItem;
  343. generateMarkdownIch(dir, '非遗保护单位');
  344. break;
  345. }
  346. case 'inheritor': {
  347. const dir = makeDir('inheritor');
  348. (await InheritorContent.getContentList(new GetContentListParams(), 1, 1000)).list.forEach(item => {
  349. data.push(item);
  350. });
  351. for (const item of data)
  352. item.detail = (await InheritorContent.getContentDetail(item.id)) as GetContentDetailItem;
  353. generateMarkdownInheritor(dir);
  354. break;
  355. }
  356. case 'artifact': {
  357. const dir = makeDir('artifact');
  358. (await UnmoveableContent.getContentList(new GetContentListParams(), 1, 1000)).list.forEach(item => {
  359. data.push(item);
  360. });
  361. for (const item of data)
  362. item.detail = (await UnmoveableContent.getContentDetail(item.id)) as GetContentDetailItem;
  363. generateMarkdownArtifact(dir);
  364. break;
  365. }
  366. default:
  367. console.log('不支持的类型');
  368. break;
  369. }
  370. }
  371. main();