307 lines
14 KiB
Go Template
307 lines
14 KiB
Go Template
{{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}}
|