SnovioModels.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. using System.Text.Json;
  2. using System.Text.Json.Serialization;
  3. namespace OASystem.API.OAMethodLib.SnovioAPI;
  4. /// <summary>
  5. /// Snov.io OAuth access_token 请求体。
  6. /// </summary>
  7. public sealed class SnovioAccessTokenRequest
  8. {
  9. /// <summary>
  10. /// OAuth 授权类型,固定为 client_credentials。
  11. /// </summary>
  12. [JsonPropertyName("grant_type")]
  13. public string GrantType { get; set; } = "client_credentials";
  14. /// <summary>
  15. /// Snov.io Client ID。
  16. /// </summary>
  17. [JsonPropertyName("client_id")]
  18. public string ClientId { get; set; } = string.Empty;
  19. /// <summary>
  20. /// Snov.io Client Secret。
  21. /// </summary>
  22. [JsonPropertyName("client_secret")]
  23. public string ClientSecret { get; set; } = string.Empty;
  24. }
  25. /// <summary>
  26. /// Snov.io OAuth access_token 响应体。
  27. /// </summary>
  28. public sealed class SnovioAccessTokenResponse
  29. {
  30. /// <summary>
  31. /// 访问令牌。
  32. /// </summary>
  33. [JsonPropertyName("access_token")]
  34. public string AccessToken { get; set; } = string.Empty;
  35. /// <summary>
  36. /// 令牌类型,通常为 Bearer。
  37. /// </summary>
  38. [JsonPropertyName("token_type")]
  39. public string TokenType { get; set; } = string.Empty;
  40. /// <summary>
  41. /// 令牌有效期,单位为秒。
  42. /// </summary>
  43. [JsonPropertyName("expires_in")]
  44. public int ExpiresIn { get; set; }
  45. }
  46. /// <summary>
  47. /// Snov.io 公司数据库搜索请求体。
  48. /// </summary>
  49. public sealed class SnovioCompanySearchRequest
  50. {
  51. /// <summary>
  52. /// 结果页码,默认从第 1 页开始。
  53. /// </summary>
  54. [JsonPropertyName("page")]
  55. public int Page { get; set; } = 1;
  56. /// <summary>
  57. /// 可选的异步结果回调地址。
  58. /// </summary>
  59. [JsonPropertyName("webhook_url")]
  60. public string? WebhookUrl { get; set; }
  61. /// <summary>
  62. /// 公司搜索筛选条件。
  63. /// </summary>
  64. [JsonPropertyName("filters")]
  65. public SnovioCompanySearchFilters Filters { get; set; } = new();
  66. }
  67. /// <summary>
  68. /// Snov.io 公司数据库搜索筛选条件。
  69. /// </summary>
  70. public sealed class SnovioCompanySearchFilters
  71. {
  72. /// <summary>
  73. /// 公司名称、行业、规模、营收和成立年份等筛选条件。
  74. /// </summary>
  75. [JsonPropertyName("company")]
  76. public SnovioCompanyFilter Company { get; set; } = new();
  77. /// <summary>
  78. /// 公司所在地区的包含和排除条件。
  79. /// </summary>
  80. [JsonPropertyName("locations")]
  81. public SnovioLocationFilter Locations { get; set; } = new();
  82. }
  83. /// <summary>
  84. /// 公司筛选条件。
  85. /// </summary>
  86. public sealed class SnovioCompanyFilter
  87. {
  88. /// <summary>
  89. /// 公司名称包含或排除列表。
  90. /// </summary>
  91. [JsonPropertyName("name")]
  92. public SnovioStringListFilter? Name { get; set; }
  93. /// <summary>
  94. /// 公司行业包含或排除列表。
  95. /// </summary>
  96. [JsonPropertyName("industries")]
  97. public SnovioStringListFilter? Industries { get; set; }
  98. /// <summary>
  99. /// 公司规模,例如 1-10、51-200、10001+。
  100. /// </summary>
  101. [JsonPropertyName("size")]
  102. public string? Size { get; set; }
  103. /// <summary>
  104. /// 公司营收最小值和最大值,单位由 Snov.io 数据源定义。
  105. /// </summary>
  106. [JsonPropertyName("revenue")]
  107. public SnovioRevenueFilter? Revenue { get; set; }
  108. /// <summary>
  109. /// 公司专长或业务领域列表。
  110. /// </summary>
  111. [JsonPropertyName("specialities")]
  112. public List<string> Specialities { get; set; } = new();
  113. /// <summary>
  114. /// 公司成立年份范围。
  115. /// </summary>
  116. [JsonPropertyName("founded")]
  117. public SnovioFoundedFilter? Founded { get; set; }
  118. }
  119. /// <summary>
  120. /// 字符串列表包含/排除条件。
  121. /// </summary>
  122. public sealed class SnovioStringListFilter
  123. {
  124. /// <summary>
  125. /// 需要匹配的字符串列表。
  126. /// </summary>
  127. [JsonPropertyName("include")]
  128. public List<string> Include { get; set; } = new();
  129. /// <summary>
  130. /// 需要排除的字符串列表。
  131. /// </summary>
  132. [JsonPropertyName("exclude")]
  133. public List<string> Exclude { get; set; } = new();
  134. }
  135. /// <summary>
  136. /// 地区包含/排除条件。
  137. /// </summary>
  138. public sealed class SnovioLocationFilter
  139. {
  140. /// <summary>
  141. /// 需要包含的地区条件。
  142. /// </summary>
  143. [JsonPropertyName("include")]
  144. public SnovioLocationFilterItem? Include { get; set; }
  145. /// <summary>
  146. /// 需要排除的地区条件。
  147. /// </summary>
  148. [JsonPropertyName("exclude")]
  149. public SnovioLocationFilterItem? Exclude { get; set; }
  150. }
  151. /// <summary>
  152. /// 地区条件明细。
  153. /// </summary>
  154. public sealed class SnovioLocationFilterItem
  155. {
  156. /// <summary>
  157. /// 地区名称,例如 London 或 Atlanta。
  158. /// </summary>
  159. [JsonPropertyName("locality")]
  160. public string? Locality { get; set; }
  161. /// <summary>
  162. /// 地区类型,例如 city、state、country、region、subregion。
  163. /// </summary>
  164. [JsonPropertyName("location_type")]
  165. public string? LocationType { get; set; }
  166. }
  167. /// <summary>
  168. /// 公司营收范围。
  169. /// </summary>
  170. public sealed class SnovioRevenueFilter
  171. {
  172. /// <summary>
  173. /// 营收下限。
  174. /// </summary>
  175. [JsonPropertyName("min")]
  176. public long? Min { get; set; }
  177. /// <summary>
  178. /// 营收上限。
  179. /// </summary>
  180. [JsonPropertyName("max")]
  181. public long? Max { get; set; }
  182. }
  183. /// <summary>
  184. /// 公司成立年份范围。
  185. /// </summary>
  186. public sealed class SnovioFoundedFilter
  187. {
  188. /// <summary>
  189. /// 成立年份下限。
  190. /// </summary>
  191. [JsonPropertyName("from")]
  192. public int? From { get; set; }
  193. /// <summary>
  194. /// 成立年份上限。
  195. /// </summary>
  196. [JsonPropertyName("till")]
  197. public int? Till { get; set; }
  198. }
  199. /// <summary>
  200. /// Snov.io 公司搜索创建任务响应体。
  201. /// </summary>
  202. public sealed class SnovioCompanySearchStartResponse
  203. {
  204. /// <summary>
  205. /// 创建任务时通常为空数组。
  206. /// </summary>
  207. [JsonPropertyName("data")]
  208. public List<JsonElement> Data { get; set; } = new();
  209. /// <summary>
  210. /// 创建任务的元数据,包含 task_hash 和页码。
  211. /// </summary>
  212. [JsonPropertyName("meta")]
  213. public SnovioCompanySearchStartMeta Meta { get; set; } = new();
  214. /// <summary>
  215. /// Snov.io 返回的结果查询地址。
  216. /// </summary>
  217. [JsonPropertyName("links")]
  218. public SnovioApiLinks Links { get; set; } = new();
  219. /// <summary>
  220. /// 创建任务响应状态。
  221. /// </summary>
  222. [JsonPropertyName("status")]
  223. public string? Status { get; set; }
  224. }
  225. /// <summary>
  226. /// Snov.io 公司搜索创建任务元数据。
  227. /// </summary>
  228. public sealed class SnovioCompanySearchStartMeta
  229. {
  230. /// <summary>
  231. /// 异步公司搜索任务唯一标识,用于查询结果。
  232. /// </summary>
  233. [JsonPropertyName("task_hash")]
  234. public string? TaskHash { get; set; }
  235. /// <summary>
  236. /// 本次搜索请求的结果页码。
  237. /// </summary>
  238. [JsonPropertyName("page")]
  239. public int Page { get; set; }
  240. }
  241. /// <summary>
  242. /// Snov.io 公司搜索结果响应体。
  243. /// </summary>
  244. public sealed class SnovioCompanySearchResultResponse
  245. {
  246. /// <summary>
  247. /// 公司搜索结果数据。
  248. /// </summary>
  249. [JsonPropertyName("data")]
  250. public SnovioCompanySearchResultData Data { get; set; } = new();
  251. /// <summary>
  252. /// 公司搜索任务元数据。
  253. /// </summary>
  254. [JsonPropertyName("meta")]
  255. public SnovioCompanySearchResultMeta Meta { get; set; } = new();
  256. /// <summary>
  257. /// 文档示例中该字段为空数组。
  258. /// </summary>
  259. [JsonPropertyName("links")]
  260. public List<JsonElement> Links { get; set; } = new();
  261. /// <summary>
  262. /// 任务处理状态,例如 completed 或 in_progress。
  263. /// </summary>
  264. [JsonPropertyName("status")]
  265. public string? Status { get; set; }
  266. }
  267. /// <summary>
  268. /// 公司搜索结果数据。
  269. /// </summary>
  270. public sealed class SnovioCompanySearchResultData
  271. {
  272. /// <summary>
  273. /// 符合筛选条件的公司总数。
  274. /// </summary>
  275. [JsonPropertyName("total")]
  276. public long Total { get; set; }
  277. /// <summary>
  278. /// 当前结果页码。
  279. /// </summary>
  280. [JsonPropertyName("page")]
  281. public int Page { get; set; }
  282. /// <summary>
  283. /// 结果总页数。
  284. /// </summary>
  285. [JsonPropertyName("total_pages")]
  286. public int TotalPages { get; set; }
  287. /// <summary>
  288. /// 当前页的公司列表。
  289. /// </summary>
  290. [JsonPropertyName("companies")]
  291. public List<SnovioCompanySearchCompany> Companies { get; set; } = new();
  292. }
  293. /// <summary>
  294. /// Snov.io 公司搜索结果中的公司信息。
  295. /// </summary>
  296. public sealed class SnovioCompanySearchCompany
  297. {
  298. /// <summary>
  299. /// 公司名称。
  300. /// </summary>
  301. [JsonPropertyName("name")]
  302. public string? Name { get; set; }
  303. /// <summary>
  304. /// 公司域名。
  305. /// </summary>
  306. [JsonPropertyName("domain")]
  307. public string? Domain { get; set; }
  308. /// <summary>
  309. /// 公司所在地区。
  310. /// </summary>
  311. [JsonPropertyName("location")]
  312. public string? Location { get; set; }
  313. /// <summary>
  314. /// 公司所属行业。
  315. /// </summary>
  316. [JsonPropertyName("industry")]
  317. public string? Industry { get; set; }
  318. /// <summary>
  319. /// 公司规模。
  320. /// </summary>
  321. [JsonPropertyName("size")]
  322. public string? Size { get; set; }
  323. /// <summary>
  324. /// 公司营收信息。
  325. /// </summary>
  326. [JsonPropertyName("revenue")]
  327. public SnovioCompanyRevenue? Revenue { get; set; }
  328. /// <summary>
  329. /// 公司 Logo 地址。
  330. /// </summary>
  331. [JsonPropertyName("logo_url")]
  332. public string? LogoUrl { get; set; }
  333. }
  334. /// <summary>
  335. /// 公司搜索结果中的公司营收信息。
  336. /// </summary>
  337. public sealed class SnovioCompanyRevenue
  338. {
  339. /// <summary>
  340. /// 营收区间下限。
  341. /// </summary>
  342. [JsonPropertyName("min")]
  343. public long? Min { get; set; }
  344. /// <summary>
  345. /// 营收区间上限。
  346. /// </summary>
  347. [JsonPropertyName("max")]
  348. public long? Max { get; set; }
  349. /// <summary>
  350. /// Snov.io 返回的营收值。
  351. /// </summary>
  352. [JsonPropertyName("reported")]
  353. public long? Reported { get; set; }
  354. }
  355. /// <summary>
  356. /// 公司搜索结果元数据。
  357. /// </summary>
  358. public sealed class SnovioCompanySearchResultMeta
  359. {
  360. /// <summary>
  361. /// 异步公司搜索任务唯一标识。
  362. /// </summary>
  363. [JsonPropertyName("task_hash")]
  364. public string? TaskHash { get; set; }
  365. /// <summary>
  366. /// 当前结果页码。
  367. /// </summary>
  368. [JsonPropertyName("page")]
  369. public int Page { get; set; }
  370. }
  371. /// <summary>
  372. /// Snov.io 域名潜在客户搜索请求体。
  373. /// </summary>
  374. public sealed class SnovioDomainProspectsSearchRequest
  375. {
  376. /// <summary>
  377. /// 要搜索的公司域名,例如 snov.io。
  378. /// </summary>
  379. [JsonPropertyName("domain")]
  380. public string Domain { get; set; } = string.Empty;
  381. /// <summary>
  382. /// 结果页码,默认从第 1 页开始。
  383. /// </summary>
  384. [JsonPropertyName("page")]
  385. public int Page { get; set; } = 1;
  386. /// <summary>
  387. /// 潜在客户职位列表,最多 10 个。
  388. /// </summary>
  389. [JsonPropertyName("positions")]
  390. public List<string> Positions { get; set; } = new();
  391. /// <summary>
  392. /// 可选的异步结果回调地址。
  393. /// </summary>
  394. [JsonPropertyName("webhook_url")]
  395. public string? WebhookUrl { get; set; }
  396. }
  397. /// <summary>
  398. /// Snov.io 域名潜在客户搜索创建任务响应体。
  399. /// </summary>
  400. public sealed class SnovioDomainProspectsSearchStartResponse
  401. {
  402. /// <summary>
  403. /// 创建任务时通常为空数组。
  404. /// </summary>
  405. [JsonPropertyName("data")]
  406. public List<JsonElement> Data { get; set; } = new();
  407. /// <summary>
  408. /// 创建任务的元数据,包含域名、页码、职位和 task_hash。
  409. /// </summary>
  410. [JsonPropertyName("meta")]
  411. public SnovioDomainProspectsSearchStartMeta Meta { get; set; } = new();
  412. /// <summary>
  413. /// Snov.io 返回的结果查询地址。
  414. /// </summary>
  415. [JsonPropertyName("links")]
  416. public SnovioApiLinks Links { get; set; } = new();
  417. /// <summary>
  418. /// 创建任务响应状态。
  419. /// </summary>
  420. [JsonPropertyName("status")]
  421. public string? Status { get; set; }
  422. }
  423. /// <summary>
  424. /// Snov.io 域名潜在客户搜索创建任务元数据。
  425. /// </summary>
  426. public sealed class SnovioDomainProspectsSearchStartMeta
  427. {
  428. /// <summary>
  429. /// 本次搜索的公司域名。
  430. /// </summary>
  431. [JsonPropertyName("domain")]
  432. public string? Domain { get; set; }
  433. /// <summary>
  434. /// 结果类型,潜客搜索通常为 prospects。
  435. /// </summary>
  436. [JsonPropertyName("tab")]
  437. public string? Tab { get; set; }
  438. /// <summary>
  439. /// 异步域名潜客搜索任务唯一标识。
  440. /// </summary>
  441. [JsonPropertyName("task_hash")]
  442. public string? TaskHash { get; set; }
  443. /// <summary>
  444. /// 本次搜索请求的结果页码。
  445. /// </summary>
  446. [JsonPropertyName("page")]
  447. public int Page { get; set; }
  448. /// <summary>
  449. /// 用于筛选潜客的职位列表。
  450. /// </summary>
  451. [JsonPropertyName("positions")]
  452. public List<string> Positions { get; set; } = new();
  453. }
  454. /// <summary>
  455. /// Snov.io 域名潜在客户搜索结果响应体。
  456. /// </summary>
  457. public sealed class SnovioDomainProspectsSearchResultResponse
  458. {
  459. /// <summary>
  460. /// 当前页的潜在客户列表。
  461. /// </summary>
  462. [JsonPropertyName("data")]
  463. public List<SnovioDomainProspect> Data { get; set; } = new();
  464. /// <summary>
  465. /// 域名潜在客户搜索结果元数据。
  466. /// </summary>
  467. [JsonPropertyName("meta")]
  468. public SnovioDomainProspectsSearchResultMeta Meta { get; set; } = new();
  469. /// <summary>
  470. /// 下一页结果链接信息。
  471. /// </summary>
  472. [JsonPropertyName("links")]
  473. public SnovioApiLinks Links { get; set; } = new();
  474. /// <summary>
  475. /// 任务处理状态,例如 completed 或 in_progress。
  476. /// </summary>
  477. [JsonPropertyName("status")]
  478. public string? Status { get; set; }
  479. }
  480. /// <summary>
  481. /// Snov.io 域名潜在客户搜索结果中的潜客信息。
  482. /// </summary>
  483. public sealed class SnovioDomainProspect
  484. {
  485. /// <summary>
  486. /// 潜客名。
  487. /// </summary>
  488. [JsonPropertyName("first_name")]
  489. public string? FirstName { get; set; }
  490. /// <summary>
  491. /// 潜客姓。
  492. /// </summary>
  493. [JsonPropertyName("last_name")]
  494. public string? LastName { get; set; }
  495. /// <summary>
  496. /// 潜客职位。
  497. /// </summary>
  498. [JsonPropertyName("position")]
  499. public string? Position { get; set; }
  500. /// <summary>
  501. /// Snov.io 获取该潜客信息的来源页面。
  502. /// </summary>
  503. [JsonPropertyName("source_page")]
  504. public string? SourcePage { get; set; }
  505. /// <summary>
  506. /// 启动该潜客邮箱检索任务的地址,地址末段包含 prospect_hash。
  507. /// </summary>
  508. [JsonPropertyName("search_emails_start")]
  509. public string? SearchEmailsStart { get; set; }
  510. }
  511. /// <summary>
  512. /// Snov.io 域名潜在客户搜索结果元数据。
  513. /// </summary>
  514. public sealed class SnovioDomainProspectsSearchResultMeta
  515. {
  516. /// <summary>
  517. /// 本次搜索的公司域名。
  518. /// </summary>
  519. [JsonPropertyName("domain")]
  520. public string? Domain { get; set; }
  521. /// <summary>
  522. /// 结果类型,潜客搜索通常为 prospects。
  523. /// </summary>
  524. [JsonPropertyName("tab")]
  525. public string? Tab { get; set; }
  526. /// <summary>
  527. /// 异步域名潜客搜索任务唯一标识。
  528. /// </summary>
  529. [JsonPropertyName("task_hash")]
  530. public string? TaskHash { get; set; }
  531. /// <summary>
  532. /// 当前结果页码。
  533. /// </summary>
  534. [JsonPropertyName("page")]
  535. public int Page { get; set; }
  536. /// <summary>
  537. /// 本次搜索使用的职位筛选列表。
  538. /// </summary>
  539. [JsonPropertyName("positions")]
  540. public List<string> Positions { get; set; } = new();
  541. /// <summary>
  542. /// 符合条件的潜客总数。
  543. /// </summary>
  544. [JsonPropertyName("total_count")]
  545. public int TotalCount { get; set; }
  546. }
  547. /// <summary>
  548. /// Snov.io 潜客邮箱检索请求体。
  549. /// </summary>
  550. public sealed class SnovioProspectEmailSearchRequest
  551. {
  552. /// <summary>
  553. /// 可选的异步任务回调地址。
  554. /// </summary>
  555. [JsonPropertyName("webhook_url")]
  556. public string? WebhookUrl { get; set; }
  557. }
  558. /// <summary>
  559. /// Snov.io 潜客邮箱检索创建任务响应体。
  560. /// </summary>
  561. public sealed class SnovioProspectEmailSearchStartResponse
  562. {
  563. /// <summary>
  564. /// 创建任务时通常为空数组。
  565. /// </summary>
  566. [JsonPropertyName("data")]
  567. public List<JsonElement> Data { get; set; } = new();
  568. /// <summary>
  569. /// 创建任务的元数据,包含邮箱检索 task_hash。
  570. /// </summary>
  571. [JsonPropertyName("meta")]
  572. public SnovioProspectEmailSearchStartMeta Meta { get; set; } = new();
  573. /// <summary>
  574. /// Snov.io 返回的邮箱结果查询地址。
  575. /// </summary>
  576. [JsonPropertyName("links")]
  577. public SnovioApiLinks Links { get; set; } = new();
  578. /// <summary>
  579. /// 创建任务响应状态。
  580. /// </summary>
  581. [JsonPropertyName("status")]
  582. public string? Status { get; set; }
  583. }
  584. /// <summary>
  585. /// Snov.io 潜客邮箱检索创建任务元数据。
  586. /// </summary>
  587. public sealed class SnovioProspectEmailSearchStartMeta
  588. {
  589. /// <summary>
  590. /// 异步邮箱检索任务唯一标识,用于查询邮箱结果。
  591. /// </summary>
  592. [JsonPropertyName("task_hash")]
  593. public string? TaskHash { get; set; }
  594. }
  595. /// <summary>
  596. /// Snov.io 潜客邮箱检索结果响应体。
  597. /// </summary>
  598. public sealed class SnovioProspectEmailSearchResultResponse
  599. {
  600. /// <summary>
  601. /// 潜客邮箱检索结果数据。
  602. /// </summary>
  603. [JsonPropertyName("data")]
  604. public SnovioProspectEmailSearchResultData Data { get; set; } = new();
  605. /// <summary>
  606. /// 邮箱检索任务元数据。
  607. /// </summary>
  608. [JsonPropertyName("meta")]
  609. public SnovioProspectEmailSearchResultMeta Meta { get; set; } = new();
  610. // 文档示例中该字段返回空数组,因此使用 JsonElement 列表兼容实际响应。
  611. [JsonPropertyName("links")]
  612. public List<JsonElement> Links { get; set; } = new();
  613. /// <summary>
  614. /// 任务处理状态,例如 completed 或 in_progress。
  615. /// </summary>
  616. [JsonPropertyName("status")]
  617. public string? Status { get; set; }
  618. }
  619. /// <summary>
  620. /// Snov.io 潜客邮箱检索结果数据。
  621. /// </summary>
  622. [System.Text.Json.Serialization.JsonConverter(typeof(SnovioProspectEmailSearchResultDataConverter))]
  623. public sealed class SnovioProspectEmailSearchResultData
  624. {
  625. /// <summary>
  626. /// 邮箱检索任务开始时间。
  627. /// </summary>
  628. [JsonPropertyName("searching_date")]
  629. public string? SearchingDate { get; set; }
  630. /// <summary>
  631. /// 当前潜客检索到的邮箱列表。
  632. /// </summary>
  633. [JsonPropertyName("emails")]
  634. public List<SnovioProspectEmail> Emails { get; set; } = new();
  635. }
  636. /// <summary>
  637. /// 兼容 Snov.io 潜客邮箱结果中 data 为对象或空数组的响应转换器。
  638. /// </summary>
  639. internal sealed class SnovioProspectEmailSearchResultDataConverter
  640. : System.Text.Json.Serialization.JsonConverter<SnovioProspectEmailSearchResultData>
  641. {
  642. public override SnovioProspectEmailSearchResultData Read(
  643. ref Utf8JsonReader reader,
  644. Type typeToConvert,
  645. JsonSerializerOptions options)
  646. {
  647. if (reader.TokenType == JsonTokenType.Null)
  648. return new SnovioProspectEmailSearchResultData();
  649. if (reader.TokenType == JsonTokenType.StartObject)
  650. {
  651. using var document = JsonDocument.ParseValue(ref reader);
  652. var root = document.RootElement;
  653. var result = new SnovioProspectEmailSearchResultData();
  654. if (root.TryGetProperty("searching_date", out var searchingDate) &&
  655. searchingDate.ValueKind == JsonValueKind.String)
  656. {
  657. result.SearchingDate = searchingDate.GetString();
  658. }
  659. if (root.TryGetProperty("emails", out var emailsElement) &&
  660. emailsElement.ValueKind == JsonValueKind.Array)
  661. {
  662. result.Emails = emailsElement.Deserialize<List<SnovioProspectEmail>>(options)
  663. ?? new List<SnovioProspectEmail>();
  664. }
  665. return result;
  666. }
  667. if (reader.TokenType == JsonTokenType.StartArray)
  668. {
  669. using var document = JsonDocument.ParseValue(ref reader);
  670. var emails = document.RootElement.Deserialize<List<SnovioProspectEmail>>(options);
  671. return new SnovioProspectEmailSearchResultData
  672. {
  673. Emails = emails ?? new List<SnovioProspectEmail>()
  674. };
  675. }
  676. throw new System.Text.Json.JsonException(
  677. "Snov.io 潜客邮箱检索响应中的 data 必须是对象、数组或 null。");
  678. }
  679. public override void Write(
  680. Utf8JsonWriter writer,
  681. SnovioProspectEmailSearchResultData value,
  682. JsonSerializerOptions options)
  683. {
  684. writer.WriteStartObject();
  685. if (value.SearchingDate != null)
  686. writer.WriteString("searching_date", value.SearchingDate);
  687. writer.WritePropertyName("emails");
  688. System.Text.Json.JsonSerializer.Serialize(writer, value.Emails, options);
  689. writer.WriteEndObject();
  690. }
  691. }
  692. /// <summary>
  693. /// Snov.io 潜客邮箱信息。
  694. /// </summary>
  695. public sealed class SnovioProspectEmail
  696. {
  697. /// <summary>
  698. /// 潜客邮箱地址。
  699. /// </summary>
  700. [JsonPropertyName("email")]
  701. public string? Email { get; set; }
  702. /// <summary>
  703. /// SMTP 校验状态,例如 valid 或 unknown。
  704. /// </summary>
  705. [JsonPropertyName("smtp_status")]
  706. public string? SmtpStatus { get; set; }
  707. }
  708. /// <summary>
  709. /// Snov.io 潜客邮箱检索结果元数据。
  710. /// </summary>
  711. public sealed class SnovioProspectEmailSearchResultMeta
  712. {
  713. /// <summary>
  714. /// 异步邮箱检索任务唯一标识。
  715. /// </summary>
  716. [JsonPropertyName("task_hash")]
  717. public string? TaskHash { get; set; }
  718. }
  719. /// <summary>
  720. /// Snov.io 异步任务结果链接。
  721. /// </summary>
  722. public sealed class SnovioApiLinks
  723. {
  724. /// <summary>
  725. /// 当前异步任务的结果查询地址。
  726. /// </summary>
  727. [JsonPropertyName("result")]
  728. public string? Result { get; set; }
  729. /// <summary>
  730. /// 下一页结果地址;没有下一页时通常为空字符串或 null。
  731. /// </summary>
  732. [JsonPropertyName("next")]
  733. public string? Next { get; set; }
  734. }