Files
cmautobuy/admin/templates/pdd/list.html
T

308 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "pdd/list"}}
{{template "header" .}}
{{/* 三段式布局的第一段:顶部工具条。
和另外四个页面保持一致,见 docs/admin/05-ui-specification.md §2。 */}}
<div class="toolbar">
{{if .CurrentUser.IsAdmin}}<a class="button" href="/integrations/catalog">导入记录</a>{{end}}
{{/* 文案写全「添加 PDD 商品」:这条工具条上还有「创建采集任务」,
两个都以「创建」开头的话,第一次用的人分不清哪个是加商品、哪个是发起采集。 */}}
<button type="button" data-modal-open="create-modal">添加 PDD 商品</button>
<button type="button" data-modal-open="import-modal">批量导入</button>
{{/* 「创建采集任务」和「删除」用的是**同一个表单**,靠按钮上的
formaction 决定提交到哪个地址。这样表格里的勾选框只需要挂一份,
不用为每个操作各复制一套(复制出来的两套迟早会不同步)。 */}}
<form id="pdd-form" method="post" action="/pdd/collect" hidden></form>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}" form="pdd-form">
{{/* 把当前筛选一起带过去,操作完还停在原来的筛选上 */}}
<input type="hidden" name="status" value="{{.StatusFilter}}" form="pdd-form">
<input type="hidden" name="q" value="{{.Keyword}}" form="pdd-form">
<input type="hidden" name="page" value="{{.CurrentPage}}" form="pdd-form">
<input type="hidden" name="page_size" value="{{.CurrentPageSize}}" form="pdd-form">
{{/* 文案是「创建采集任务」不是「采集」:点完只是排了个队,
真正去手机上采要等客户端来领,可能几秒也可能几分钟 */}}
<button type="button" data-modal-open="collect-modal" data-collect-open
data-collect-form="pdd-form"
data-need-checked>创建采集任务</button>
<form class="inline grow" method="get" action="/pdd">
<input type="hidden" name="page_size" value="{{.CurrentPageSize}}">
<label for="status">采集状态</label>
<select id="status" name="status">
{{range .StatusOptions}}
<option value="{{.Value}}" {{if eq .Value $.StatusFilter}}selected{{end}}>{{.Text}}</option>
{{end}}
</select>
<label for="q">商品 ID/链接</label>
{{/* search-narrow 把这个框收到 30%,让「搜索」按钮能紧挨着它。
用类名而不是改 .toolbar input[type="text"]——那条规则被 5 个页面共用。 */}}
<input id="q" type="text" name="q" value="{{.Keyword}}"
class="search-narrow" placeholder="商品 ID 或链接的一部分">
<a class="button-link" href="/pdd?page_size={{.CurrentPageSize}}">清除</a>
<button type="submit">搜索</button>
</form>
<button type="submit" form="pdd-form" formaction="/pdd/delete" class="danger"
data-need-checked
data-confirm-delete="将删除 {n} 条记录。删除后重新创建同一链接可恢复,但采集结果会清空。"
>删除</button>
</div>
{{/* 导入结果紧跟工具条:采购员上传后先核对统计和错误,再决定是否发采集任务。 */}}
{{with .ImportResult}}
<section class="import-result" aria-labelledby="pdd-import-result-title" aria-live="polite">
<div class="import-result-head">
<div>
<h2 id="pdd-import-result-title">本次导入结果</h2>
<p>
总行数 <strong>{{.TotalRows}}</strong> ·
新建 <strong>{{.CreatedCount}}</strong> ·
已存在 <strong>{{.ExistingCount}}</strong> ·
恢复 <strong>{{.RevivedCount}}</strong> ·
文件内重复 <strong>{{.DuplicateCount}}</strong> ·
失败 <strong>{{len .Failures}}</strong>
</p>
</div>
{{if .GoodsIDs}}
<button type="button" class="primary" data-modal-open="import-collect-modal"
data-collect-open data-collect-form="pdd-import-collect-form"
data-collect-count-value="{{len .GoodsIDs}}">
为本次导入商品创建采集任务
</button>
{{end}}
</div>
<p class="hint">
上传只建立商品档案,不会自动采集。创建任务时,已采集或正在采集的商品仍按现有规则跳过。
</p>
<form id="pdd-import-collect-form" method="post" action="/pdd/collect" hidden>
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
{{range .GoodsIDs}}<input type="hidden" name="ids" value="{{.}}">{{end}}
</form>
{{if .Failures}}
<div class="table-wrap import-failure-table" role="region" aria-label="PDD 导入失败明细" tabindex="0">
<table>
<thead>
<tr><th>Excel 行号</th><th>原始内容</th><th>失败原因与处理建议</th></tr>
</thead>
<tbody>
{{range .Failures}}
<tr class="row-warn">
<td>{{.Row}}</td>
<td class="import-raw">{{.Raw}}</td>
<td class="import-reason">{{.Reason}}</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{else}}
<p class="import-success">所有非空数据行均已处理,没有失败行。</p>
{{end}}
</section>
{{end}}
{{/* 第二段:表格。双击一行打开弹窗,见 static/js/app.js */}}
<div class="table-wrap" id="pddProductPage">
<table>
<thead>
<tr>
<th class="col-check"><input type="checkbox" data-check-all></th>
<th>商品 ID</th>
<th>标题</th>
<th>店铺</th>
<th>PDD 链接</th>
<th>采集状态</th>
{{/* 采到 1 个和采到 20 个差别很大:只采到 1 个通常是没点开规格面板,
说明这次采集有问题。这一列就是为了让它一眼能看出来 */}}
<th>规格数</th>
<th>采集时间</th>
<th>更新时间</th>
</tr>
</thead>
<tbody>
{{range .Rows}}
<tr data-detail-id="{{.ID}}" {{if .IsFailed}}class="row-warn"{{end}}>
<td class="col-check">
{{/* 勾选框的值是 goods_id:删除和建采集任务都按它定位。
form 属性把它挂到工具条里那个表单上 */}}
<input type="checkbox" value="{{.GoodsID}}" name="ids" form="pdd-form"
aria-label="选择商品 {{.GoodsID}}">
</td>
<td>{{.GoodsID}}</td>
<td class="truncate" title="{{.Title}}">{{.Title}}</td>
<td class="truncate" title="{{.ShopName}}">{{.ShopName}}</td>
<td class="truncate">
<a href="{{.URL}}" target="_blank" rel="noopener noreferrer" title="{{.URL}}">{{.URL}}</a>
</td>
{{/* 状态是中文文字,不能只靠颜色区分 */}}
<td>{{.StatusText}}{{if .CollectMsg}}<br><small class="missing">{{.CollectMsg}}</small>{{end}}</td>
<td>{{.SkuCountText}}</td>
<td>{{.CollectedAt}}</td>
<td>{{.UpdatedAt}}</td>
</tr>
{{else}}
{{/* 空状态要分情况:从没建过 和 筛选没结果,下一步动作完全不同 */}}
<tr class="empty">
<td colspan="9">
{{if .IsFiltered}}
当前筛选条件下没有商品。<br>
<small>换个采集状态或清空搜索词再试。<a href="/pdd?page_size={{.CurrentPageSize}}">查看全部</a></small>
{{else}}
还没有 PDD 商品。<br>
<small>点左上角「添加 PDD 商品」粘贴单条链接,或用「批量导入」上传 Excel。</small>
{{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<p class="hint">
双击任意一行可以查看和编辑这个商品,包括采回来的规格和价格。
</p>
{{/* ── 创建弹窗 ─────────────────────────────────
内容是固定的(只有一个输入框),所以直接写在页面里藏着,
不像编辑弹窗那样要去服务端取。 */}}
<div class="modal-backdrop" id="create-modal" hidden>
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="create-modal-title">
<div class="modal-head">
<h2 id="create-modal-title">创建 PDD 商品</h2>
<button type="button" class="modal-x" data-modal-close aria-label="关闭">×</button>
</div>
<form method="post" action="/pdd/create">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<input type="hidden" name="status" value="{{.StatusFilter}}">
<input type="hidden" name="q" value="{{.Keyword}}">
<input type="hidden" name="page" value="{{.CurrentPage}}">
<input type="hidden" name="page_size" value="{{.CurrentPageSize}}">
<div class="modal-body">
<div class="field">
<label for="create-url">PDD 链接</label>
<input id="create-url" type="text" name="url" required autocomplete="off"
placeholder="https://mobile.yangkeduo.com/goods.html?goods_id=737116531267">
</div>
<p class="hint">
只需要链接,标题和规格由客户端采集后自动回填。<br>
链接里必须带 <code>goods_id=</code>,短链接不行——请在拼多多 App
的商品页点「分享」→「复制链接」。
</p>
</div>
<div class="modal-foot">
<button type="button" data-modal-close>取消</button>
<button type="submit" class="primary">保存</button>
</div>
</form>
</div>
</div>
{{/* ── 批量导入弹窗 ─────────────────────────────── */}}
<div class="modal-backdrop" id="import-modal" hidden>
<div class="modal modal-narrow" role="dialog" aria-modal="true" aria-labelledby="import-modal-title">
<div class="modal-head">
<h2 id="import-modal-title">批量导入 PDD 链接</h2>
<button type="button" class="modal-x" data-modal-close aria-label="关闭">×</button>
</div>
<form method="post" action="/pdd/import" enctype="multipart/form-data" data-upload-form>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<input type="hidden" name="page_size" value="{{.CurrentPageSize}}">
<div class="modal-body">
<div class="field">
<label for="pdd-import-file">Excel 文件</label>
<input id="pdd-import-file" type="file" name="file" accept=".xlsx" required autofocus
aria-describedby="pdd-import-help">
</div>
<p class="hint" id="pdd-import-help">
仅支持不超过 10MB 的 <code>.xlsx</code>。第一个非空工作表第一列的表头必须是
“拼多多链接”,每行填写一个带 <code>goods_id=</code> 的完整链接,最多 5000 条;
空工作表和空行会自动忽略。
</p>
</div>
<div class="modal-foot">
<button type="button" data-modal-close>取消</button>
<button type="submit" class="primary" data-upload-submit>开始导入</button>
</div>
</form>
</div>
</div>
{{/* ── 批量采集确认弹窗 ─────────────────────────
客户端是可选项,默认留空。服务端仍会按当前账号重新校验候选范围。 */}}
<div class="modal-backdrop" id="collect-modal" hidden>
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="collect-modal-title">
<div class="modal-head">
<h2 id="collect-modal-title">创建采集任务</h2>
<button type="button" class="modal-x" data-modal-close aria-label="关闭">×</button>
</div>
<div class="modal-body">
<p>将为已选择的 <strong data-collect-count>0</strong> 个商品创建采集任务。</p>
<div class="field">
<label for="collect-client">执行客户端</label>
<select id="collect-client" name="client_id" form="pdd-form" autofocus>
<option value="">不指定(任意客户端可领取)</option>
{{range .AssignableClients}}
<option value="{{.ClientID}}">{{.Name}}({{.ClientID}},{{.Status}})</option>
{{end}}
</select>
</div>
<p class="hint">
通常保持默认即可。指定后,任务只等待该客户端领取;客户端离线时不会自动改派。
</p>
</div>
<div class="modal-foot">
<button type="button" data-modal-close>取消</button>
<button type="submit" form="pdd-form" formaction="/pdd/collect" class="primary"
data-collect-submit>确认创建</button>
</div>
</div>
</div>
{{/* ── 本次导入商品的采集确认弹窗 ─────────────────
IDs 来自刚完成的服务端导入结果,不受当前页分页影响。 */}}
{{with .ImportResult}}{{if .GoodsIDs}}
<div class="modal-backdrop" id="import-collect-modal" hidden>
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="import-collect-modal-title">
<div class="modal-head">
<h2 id="import-collect-modal-title">为本次导入商品创建采集任务</h2>
<button type="button" class="modal-x" data-modal-close aria-label="关闭">×</button>
</div>
<div class="modal-body">
<p>将按现有状态规则处理本次导入的 <strong data-collect-count>{{len .GoodsIDs}}</strong> 个商品。</p>
<div class="field">
<label for="import-collect-client">执行客户端</label>
<select id="import-collect-client" name="client_id" form="pdd-import-collect-form" autofocus>
<option value="">不指定(任意客户端可领取)</option>
{{range $.AssignableClients}}
<option value="{{.ClientID}}">{{.Name}}({{.ClientID}},{{.Status}})</option>
{{end}}
</select>
</div>
<p class="hint">
上传本身没有创建任务。确认后才会建任务;已采集、正在采集和重复项会分别统计并跳过。
</p>
</div>
<div class="modal-foot">
<button type="button" data-modal-close>取消</button>
<button type="submit" form="pdd-import-collect-form" class="primary"
data-collect-submit>确认创建</button>
</div>
</div>
</div>
{{end}}{{end}}
{{/* ── 编辑弹窗的壳子 ───────────────────────────
里面的内容双击行时由 /pdd/detail 返回,前端只负责放进来和显示。 */}}
<div class="modal-backdrop" id="detail-modal" data-detail-url="{{.DetailURL}}" hidden>
<div class="modal" role="dialog" aria-modal="true" data-detail-slot>
<div class="modal-body">正在加载…</div>
</div>
</div>
{{template "footer" .}}
{{end}}