Files
cmroubao/backend-api/internal/transport/webui/templates/task-detail.gohtml
T

307 lines
14 KiB
Go Template
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 "task-detail"}}
<!doctype html>
<html lang="zh-CN">
<head>
<title>{{.Task.Title}} - 采购任务管理</title>
{{template "document-head" .}}
</head>
<body>
{{template "site-header" .}}
<main id="main-content" class="page">
<a class="back-link" href="/tasks">返回任务列表</a>
{{if .Notice}}
<div class="notice" role="status" tabindex="-1" data-notice>{{.Notice}}</div>
{{end}}
<div class="title-row detail-title">
<div>
<h1>{{.Task.Title}}</h1>
<p class="subtitle">SKU:{{.Task.SKU}} · 任务编号:{{.Task.ID}}</p>
</div>
<div class="title-actions">
<span class="status {{.Task.StatusClass}}" title="状态码 {{.Task.Status}}">
{{.Task.StatusLabel}}
</span>
{{if .Task.CanCancel}}
<button class="button danger-outline" type="button" data-open-cancel>取消任务</button>
{{end}}
</div>
</div>
{{range .Task.OrderSubmissions}}
{{if eq .Status "RECONCILED"}}
<section class="order-state-banner order-state-payment"
aria-labelledby="pending-payment-heading">
<div class="order-state-heading">
<div>
<p class="order-state-label">{{.StatusLabel}}</p>
<h2 id="pending-payment-heading">待人工确认付款</h2>
</div>
<span class="status status-success">待付款</span>
</div>
<p class="order-state-instruction">
请采购员打开拼多多订单列表,核对商品、规格、数量和金额后人工付款。
</p>
<div class="pending-payment-layout">
<dl class="definition-list pending-payment-details">
<dt>拼多多订单号</dt><dd class="order-number">{{.PlatformOrderNo}}</dd>
<dt>平台下单时间</dt>
<dd><time datetime="{{machineTime .PlatformOrderedAt}}">{{displayTime .PlatformOrderedAt}}</time></dd>
<dt>平台状态</dt><dd>待付款({{.PlatformOrderStatus}})</dd>
<dt>商品标题</dt><dd>{{.ExpectedTitle}}</dd>
<dt>SKU</dt><dd>{{.ExpectedSKU}}</dd>
<dt>数量</dt><dd>{{.ExpectedQuantity}}</dd>
<dt>核验单价</dt><dd>¥{{.ExpectedUnitPrice}}</dd>
<dt>核验总额</dt><dd>¥{{.ExpectedTotalPrice}}</dd>
</dl>
{{if .EvidenceContentURL}}
<figure class="pending-payment-evidence">
<img src="{{.EvidenceContentURL}}" alt="待付款订单列表对账截图">
<figcaption>设备回传的订单列表对账证据</figcaption>
</figure>
{{end}}
</div>
</section>
{{else if eq .Status "MANUAL_REVIEW"}}
<section class="order-state-banner order-state-manual" role="status">
<h2>{{.StatusLabel}}</h2>
<p>{{.ManualReasonLabel}}。提交围栏保持有效,禁止重新提交订单。</p>
</section>
{{else if eq .Status "FENCED"}}
<section class="order-state-banner order-state-reconciling" role="status">
<h2>{{.StatusLabel}}</h2>
<p>订单提交结果正在对账,提交围栏已经消费,禁止重复提交。</p>
</section>
{{end}}
{{end}}
{{if and (eq .Task.Status "SUCCEEDED") (not .Task.HasReconciledOrder)}}
<section class="success-banner" aria-labelledby="success-heading">
<div aria-hidden="true" class="success-mark">✓</div>
<div>
<h2 id="success-heading">验证完成,未提交订单</h2>
<p>采购人员已完成候选确认,系统只记录验证结果。</p>
</div>
</section>
{{end}}
<div class="detail-layout">
<section class="content-section" aria-labelledby="original-heading">
<h2 id="original-heading">原始采购要求</h2>
<p class="section-note">以下内容来自管理员输入,不会被 AI 派生结果覆盖。</p>
<div class="requirement-layout">
<figure class="reference-figure">
<img class="reference-image"
src="/api/v1/assets/{{pathPart .Task.ReferenceAssetID}}/content"
alt="商品参考图">
<figcaption>已规范化的参考图片</figcaption>
</figure>
<dl class="definition-list">
<dt>商品标题</dt><dd>{{.Task.Title}}</dd>
<dt>SKU</dt><dd>{{.Task.SKU}}</dd>
<dt>描述</dt><dd>{{if .Task.Description}}{{.Task.Description}}{{else}}未填写{{end}}</dd>
<dt>数量</dt><dd>{{.Task.Quantity}}</dd>
<dt>最高总预算</dt>
<dd>{{if .Task.MaxBudget}}{{.Task.MaxBudget}} 元{{else}}未设置{{end}}</dd>
</dl>
</div>
</section>
<aside class="content-section summary-section" aria-labelledby="summary-heading">
<h2 id="summary-heading">任务摘要</h2>
<dl class="definition-list">
<dt>状态</dt><dd>{{.Task.StatusLabel}}({{.Task.Status}})</dd>
<dt>创建时间</dt>
<dd><time datetime="{{machineTime .Task.CreatedAt}}">{{displayTime .Task.CreatedAt}}</time></dd>
<dt>最后更新</dt>
<dd><time datetime="{{machineTime .Task.UpdatedAt}}">{{displayTime .Task.UpdatedAt}}</time></dd>
</dl>
</aside>
</div>
{{if .Task.Candidates}}
<section class="content-section authorization-section" aria-labelledby="authorization-heading">
<div class="section-heading-row">
<div>
<h2 id="authorization-heading">候选确认与下单授权</h2>
<p class="section-note">选择只会授权设备创建一笔待付款订单,不授权付款。</p>
</div>
<span class="candidate-count">{{len .Task.Candidates}} 个候选</span>
</div>
{{if .Task.CanAuthorizeOrder}}
<form class="authorization-form" method="post"
action="/tasks/{{pathPart .Task.ID}}/order-authorizations">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<input type="hidden" name="authorization_key" value="{{.AuthorizationKey}}">
<input type="hidden" name="expected_task_version" value="{{.Task.Version}}">
<input type="hidden" name="supersedes_authorization_id"
value="{{.Task.ActiveAuthorizationID}}">
<fieldset class="candidate-fieldset">
<legend>选择要采购的商品</legend>
<div class="authorization-candidates">
{{range .Task.Candidates}}
<label class="authorization-candidate">
<span class="candidate-choice">
<input type="radio" name="candidate_key" value="{{.CandidateKey}}" required>
<span>候选 {{.Ordinal}}</span>
</span>
<strong>{{.Title}}</strong>
<span>规格:{{if .SKUText}}{{.SKUText}}{{else}}未读取{{end}}</span>
<span>组合价格:{{if .PriceText}}{{.PriceText}}{{else}}未读取{{end}}</span>
<code class="candidate-key">{{.CandidateKey}}</code>
{{if .EvidenceURLs}}
<span class="candidate-evidence">
{{range .EvidenceURLs}}<img src="{{.}}" alt="候选受控证据截图">{{end}}
</span>
{{end}}
</label>
{{end}}
</div>
</fieldset>
<div class="authorization-reasons">
<label>
<span>所选候选理由</span>
<select name="selected_reason_code" required>
<option value="">请选择</option>
<option value="SKU_MATCH">SKU 匹配</option>
<option value="IMAGE_MATCH">图片匹配</option>
{{if .Task.MaxBudget}}<option value="PRICE_ACCEPTABLE">价格可接受</option>{{end}}
<option value="EVIDENCE_SUFFICIENT">证据充分</option>
</select>
</label>
<label>
<span>其余候选拒绝理由</span>
<select name="rejected_reason_code" required>
<option value="">请选择</option>
<option value="NOT_BEST_MATCH">不是最佳匹配</option>
<option value="SKU_MISMATCH">SKU 不匹配</option>
<option value="IMAGE_MISMATCH">图片不匹配</option>
{{if .Task.MaxBudget}}<option value="PRICE_TOO_HIGH">价格过高</option>{{end}}
<option value="OUT_OF_STOCK">无库存</option>
<option value="EVIDENCE_INSUFFICIENT">证据不足</option>
</select>
</label>
<label class="authorization-note">
<span>授权备注(可选)</span>
<textarea name="authorization_note" rows="3" maxlength="200"></textarea>
</label>
</div>
<label class="authorization-confirm">
<input type="checkbox" required>
<span>我确认商品、SKU、数量和证据;系统只创建待付款订单,付款由人员在拼多多完成。</span>
</label>
<button class="button primary" type="submit">
{{if .Task.ActiveAuthorizationID}}改选并创建新授权{{else}}确认商品并授权下单{{end}}
</button>
</form>
{{else}}
<p class="authorization-unavailable" role="status">
当前候选不能创建或修改授权,请查看下方授权状态或刷新任务。
</p>
{{end}}
{{if .Task.OrderAuthorizations}}
<h3>授权历史</h3>
<ol class="authorization-history">
{{range .Task.OrderAuthorizations}}
<li>
<strong>版本 {{.Version}} · {{.Status}}</strong>
<span>候选 {{.CandidateKey}}</span>
<span>规格 {{if .CandidateSKUText}}{{.CandidateSKUText}}{{else}}未读取{{end}} ·
数量 {{.Quantity}} · 价格 {{if .CandidatePriceText}}{{.CandidatePriceText}}{{else}}未读取{{end}}</span>
<time datetime="{{machineTime .CreatedAt}}">{{displayTime .CreatedAt}}</time>
</li>
{{end}}
</ol>
{{end}}
</section>
{{end}}
{{with .Task.ExecutionReport}}
<section class="content-section execution-audit" aria-labelledby="execution-audit-heading">
<h2 id="execution-audit-heading">执行审计</h2>
{{if .Outcome}}
<dl class="definition-list audit-summary">
<dt>结果类型</dt><dd>{{.Outcome.ResultType}}</dd>
<dt>人工理由</dt><dd>{{if .Outcome.OperatorReason}}{{.Outcome.OperatorReason}}{{else}}未提供{{end}}</dd>
<dt>订单提交</dt><dd>{{if .Outcome.OrderSubmitted}}是{{else}}否{{end}}</dd>
{{if .Outcome.ErrorCode}}<dt>失败信息</dt><dd>{{.Outcome.ErrorCode}}:{{.Outcome.ErrorMessage}}</dd>{{end}}
</dl>
{{end}}
{{if .Mode}}<p class="section-note">模式:{{.Mode}} · 搜索词:{{.SearchQuery}}</p>{{end}}
{{if .Provenance}}<h3>本地模型出处</h3><pre class="audit-json">{{.Provenance}}</pre>{{end}}
{{if .Observations}}<h3>原始候选观察</h3><pre class="audit-json">{{.Observations}}</pre>{{end}}
{{if .ModelPredictions}}<h3>模型逐项评估</h3><pre class="audit-json">{{.ModelPredictions}}</pre>{{end}}
{{if .DeterministicRecommendation}}<h3>确定性推荐</h3><pre class="audit-json">{{.DeterministicRecommendation}}</pre>{{end}}
{{if .HumanReviews}}<h3>人工选择与拒绝</h3><pre class="audit-json">{{.HumanReviews}}</pre>{{end}}
{{if and (not .Observations) .Candidates}}<h3>候选与评估(兼容记录)</h3><pre class="audit-json">{{.Candidates}}</pre>{{end}}
{{if and (not .DeterministicRecommendation) .Recommendation}}<h3>本地推荐(兼容记录)</h3><pre class="audit-json">{{.Recommendation}}</pre>{{end}}
{{if .Evidence}}
<h3>证据截图</h3>
<div class="audit-evidence-grid">
{{range .Evidence}}<figure class="audit-evidence">
<img src="{{.ContentURL}}" alt="执行证据截图">
<figcaption>SHA-256 {{.SHA256}}({{.SizeBytes}} bytes){{if .ReceivedAfterExecutionExpiry}},授权到期后补报{{end}}</figcaption>
</figure>{{end}}
</div>
{{end}}
{{if .Events}}
<h3>执行事件</h3>
<ul class="audit-list">
{{range .Events}}<li><time datetime="{{machineTime .OccurredAt}}">{{displayTime .OccurredAt}}</time> · {{.Step}} · {{.Message}}{{if .ReceivedAfterExecutionExpiry}}(授权到期后补报){{end}}</li>{{end}}
</ul>
{{end}}
</section>
{{end}}
{{if .Task.CanCancel}}
<noscript>
<section class="noscript-cancel" aria-labelledby="noscript-cancel-heading">
{{if .Task.CancelRequiresAck}}
<h2 id="noscript-cancel-heading">请求安全停止任务</h2>
<p>设备确认安全停止前,任务仍保持当前执行状态。</p>
{{else}}
<h2 id="noscript-cancel-heading">确认取消任务</h2>
<p>取消后任务不会自动恢复。</p>
{{end}}
<form method="post" action="/tasks/{{pathPart .Task.ID}}/cancel">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<input type="hidden" name="cancel_key" value="{{.CancelKey}}">
<button class="button danger" type="submit">
{{if .Task.CancelRequiresAck}}确认请求停止{{else}}确认取消{{end}}
</button>
</form>
</section>
</noscript>
<dialog class="confirm-dialog" data-cancel-dialog aria-labelledby="cancel-title">
{{if .Task.CancelRequiresAck}}
<h2 id="cancel-title">请求安全停止任务?</h2>
<p>系统将通知采购 App 在安全检查点停止;设备确认前任务仍保持当前执行状态。</p>
{{else}}
<h2 id="cancel-title">确认取消任务?</h2>
<p>任务取消后不会自动恢复,采购执行员将不能再领取。</p>
{{end}}
<div class="dialog-actions">
<button class="button" type="button" data-keep-task>保留任务</button>
<form method="post" action="/tasks/{{pathPart .Task.ID}}/cancel" data-submit-form>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<input type="hidden" name="cancel_key" value="{{.CancelKey}}">
<button class="button danger" type="submit" data-submit-button
data-loading-label="{{if .Task.CancelRequiresAck}}正在请求停止…{{else}}正在取消…{{end}}">
{{if .Task.CancelRequiresAck}}确认请求停止{{else}}确认取消{{end}}
</button>
</form>
</div>
</dialog>
{{end}}
</main>
</body>
</html>
{{end}}