resources-page.component.html 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <section class="plain-view">
  2. <header class="page-hero">
  3. <div class="page-hero-copy">
  4. <p class="eyebrow">资源库</p>
  5. <h2>把本地媒体表变成 AI 能读懂的资源池</h2>
  6. <small>媒介维护表格,AI 负责识别平台、字段、报价、缺失项和可用账号。</small>
  7. <div class="page-guide">
  8. <span><b>目标</b>检查资源是否可用</span>
  9. <span><b>操作</b>同步、确认映射、处理缺口</span>
  10. <span><b>产出</b>可召回账号资源池</span>
  11. </div>
  12. </div>
  13. <div class="page-actions">
  14. <button type="button" class="ghost-button" (click)="state.confirmAllMappings()">确认全部映射</button>
  15. <button type="button" class="primary-button compact" (click)="state.runResourceSync()">同步资源库</button>
  16. </div>
  17. </header>
  18. <div class="path-box">
  19. <span>本地资源目录</span>
  20. <strong>{{ state.resourcePath }}</strong>
  21. <small>若目录不存在,Demo 使用内置样例;正式版会扫描《4月份媒体推荐资源表.xlsx》并自动做字段映射。</small>
  22. </div>
  23. <section class="resource-health-grid">
  24. <article *ngFor="let item of state.resourceHealthItems">
  25. <span>{{ item.label }}</span>
  26. <strong>{{ item.value }}%</strong>
  27. <div class="progress"><i [style.width.%]="item.value"></i></div>
  28. <small>{{ item.detail }}</small>
  29. </article>
  30. </section>
  31. <div class="resource-grid">
  32. <article
  33. *ngFor="let resource of state.resources"
  34. [class.active]="state.selectedResourcePlatform === resource.platform"
  35. (click)="state.selectResourcePlatform(resource.platform)"
  36. >
  37. <strong>{{ resource.platform }}</strong>
  38. <span>{{ resource.status }}</span>
  39. <div class="progress"><i [style.width.%]="resource.fresh"></i></div>
  40. <small>资源 {{ resource.total }} 条 · 匹配 {{ resource.matched }} 条 · 新鲜度 {{ resource.fresh }}%</small>
  41. </article>
  42. </div>
  43. <section class="resource-detail-panel">
  44. <div class="section-mini-head">
  45. <div>
  46. <strong>{{ state.selectedResource.platform }} 平台详情</strong>
  47. <small>资源文件、样例账号和字段缺口联动展示</small>
  48. </div>
  49. <button type="button" class="ghost-button compact" (click)="state.rescanSelectedResource()">重新扫描该平台</button>
  50. </div>
  51. <div class="resource-detail-grid">
  52. <article class="resource-file-list">
  53. <strong>资源文件</strong>
  54. <section *ngFor="let file of state.selectedResourceFiles">
  55. <span>{{ file.name }}</span>
  56. <small>{{ file.owner }} · {{ file.updateTime }} · {{ file.rows }} 行</small>
  57. <div class="tag-row">
  58. <em *ngFor="let missing of file.missingFields">{{ missing }}</em>
  59. </div>
  60. </section>
  61. </article>
  62. <article class="resource-issue-list">
  63. <strong>待处理问题</strong>
  64. <section *ngFor="let issue of state.selectedResourceIssues">
  65. <header>
  66. <span [class.danger]="issue.level === '高'">{{ issue.level }}</span>
  67. <button type="button" class="text-button" (click)="state.resolveResourceIssue(issue)" [disabled]="issue.resolved">
  68. {{ issue.resolved ? '已处理' : '标记处理' }}
  69. </button>
  70. </header>
  71. <h4>{{ issue.title }}</h4>
  72. <p>{{ issue.detail }}</p>
  73. <small>{{ issue.action }}</small>
  74. </section>
  75. <p class="empty-state" *ngIf="state.selectedResourceIssues.length === 0">当前平台暂无待处理问题。</p>
  76. </article>
  77. <article class="resource-sample-list">
  78. <strong>匹配样例账号</strong>
  79. <button type="button" *ngFor="let candidate of state.selectedResourceCandidates" (click)="state.openCandidate(candidate); state.setView('workspace')">
  80. <span>{{ candidate.name }}</span>
  81. <small>{{ candidate.fans }}粉丝 · {{ candidate.price | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }} · {{ candidate.styleMatch }}% 风格</small>
  82. </button>
  83. </article>
  84. </div>
  85. </section>
  86. <section class="resource-fix-board">
  87. <div class="section-mini-head">
  88. <div>
  89. <strong>资源修复队列</strong>
  90. <small>优先处理会阻断推荐和导出的字段问题</small>
  91. </div>
  92. <button type="button" class="ghost-button compact" (click)="state.runBusinessShortcut('review-risk')">只看风险</button>
  93. </div>
  94. <div class="resource-fix-list">
  95. <article *ngFor="let issue of state.resourceFixQueue">
  96. <span [class.danger]="issue.level === '高'">{{ issue.level }}</span>
  97. <div>
  98. <strong>{{ issue.platform }} · {{ issue.title }}</strong>
  99. <p>{{ issue.detail }}</p>
  100. <small>{{ issue.action }}</small>
  101. </div>
  102. <button type="button" class="text-button" (click)="state.resolveResourceIssue(issue)">标记处理</button>
  103. </article>
  104. </div>
  105. </section>
  106. <section class="mapping-area">
  107. <div class="section-mini-head">
  108. <strong>字段映射确认</strong>
  109. <small>{{ state.confirmedMappingsCount }}/{{ state.fieldMappings.length }} 已确认</small>
  110. </div>
  111. <div class="mapping-grid">
  112. <article *ngFor="let mapping of state.fieldMappings" [class.confirmed]="mapping.confirmed">
  113. <label>
  114. <input type="checkbox" [(ngModel)]="mapping.confirmed" />
  115. <span></span>
  116. </label>
  117. <div>
  118. <strong>{{ mapping.source }}</strong>
  119. <small>映射到 {{ mapping.target }}</small>
  120. </div>
  121. <em>{{ mapping.confidence }}%</em>
  122. <button type="button" class="text-button" (click)="state.confirmMapping(mapping)">确认</button>
  123. </article>
  124. </div>
  125. </section>
  126. <section class="resource-impact-grid">
  127. <article>
  128. <strong>缺报价</strong>
  129. <p>账号不能进入客户版主推,只能作为待询价备选。</p>
  130. </article>
  131. <article>
  132. <strong>缺主页链接</strong>
  133. <p>无法做近10条内容采样,风格匹配分需要人工复核。</p>
  134. </article>
  135. <article>
  136. <strong>缺互动数据</strong>
  137. <p>爆文率、阅读单价和历史表现分会降权。</p>
  138. </article>
  139. <article>
  140. <strong>缺供应商</strong>
  141. <p>履约风险升高,导出前必须绑定媒介负责人。</p>
  142. </article>
  143. </section>
  144. </section>