feat(portal): rewrite /my/jobs list with V2 stepper cards
Drops the old 3-segment progress bar in favour of the dashboard's 5-step circle-and-line stepper for consistency. Uses the same state_to_idx mapping so all 6 fp.portal.job states (including 'complete') render correctly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -432,63 +432,47 @@
|
||||
<t t-call="portal.portal_layout">
|
||||
<t t-set="breadcrumbs_searchbar" t-value="True"/>
|
||||
<t t-call="portal.portal_searchbar">
|
||||
<t t-set="title">Parts Portal</t>
|
||||
<t t-set="title">Work Orders</t>
|
||||
</t>
|
||||
|
||||
<t t-if="not jobs">
|
||||
<div class="o_fp_portal_card card bg-body-tertiary border-0 p-4 text-center">
|
||||
<p class="text-muted mb-0">You have no plating jobs yet.</p>
|
||||
<div class="o_fp_card text-center text-muted">
|
||||
<p class="mb-2">You have no plating jobs yet.</p>
|
||||
<a href="/my/configurator" class="o_fp_btn_primary o_fp_btn_sm">+ Get Your First Quote</a>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="jobs">
|
||||
<div class="o_fp_jobs_list">
|
||||
<div class="o_fp_dashboard">
|
||||
<t t-foreach="jobs" t-as="job">
|
||||
<div class="card mb-3 o_fp_portal_card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<div>
|
||||
<a t-att-href="'/my/jobs/%s' % job.id"
|
||||
class="fs-6 fw-semibold text-decoration-none"
|
||||
t-out="job.name"/>
|
||||
<div class="text-muted small">
|
||||
<span t-if="job.received_date">
|
||||
Received: <span t-field="job.received_date" t-options='{"widget": "date"}'/>
|
||||
</span>
|
||||
<span t-if="job.target_ship_date" class="ms-3">
|
||||
Target: <span t-field="job.target_ship_date" t-options='{"widget": "date"}'/>
|
||||
</span>
|
||||
<span class="ms-3">Qty: <span t-out="job.quantity"/></span>
|
||||
</div>
|
||||
</div>
|
||||
<span t-attf-class="badge #{
|
||||
'text-bg-info' if job.state == 'received' else
|
||||
'text-bg-primary' if job.state == 'in_progress' else
|
||||
'text-bg-warning' if job.state == 'quality_check' else
|
||||
'text-bg-secondary' if job.state == 'ready_to_ship' else
|
||||
'text-bg-success' if job.state == 'shipped' else
|
||||
'text-bg-success'}"
|
||||
t-out="dict(job._fields['state']._description_selection(job.env)).get(job.state)"/>
|
||||
</div>
|
||||
|
||||
<!-- Segmented progress bar -->
|
||||
<t t-set="pct" t-value="job._progress_percent()"/>
|
||||
<div class="o_fp_seg_progress d-flex" style="height: 10px; border-radius: 5px; overflow: hidden; background: var(--bs-secondary-bg);">
|
||||
<!-- Receiving segment (green) -->
|
||||
<div t-attf-style="width: 20%; opacity: #{1 if pct >= 10 else 0.2};"
|
||||
style="background-color: var(--bs-success);"/>
|
||||
<!-- In Progress segment (orange) -->
|
||||
<div t-attf-style="width: 50%; opacity: #{1 if pct >= 35 else 0.2};"
|
||||
style="background-color: var(--bs-warning); margin-left: 2px;"/>
|
||||
<!-- Shipping segment (blue/green) -->
|
||||
<div t-attf-style="width: 30%; opacity: #{1 if pct >= 80 else 0.2};"
|
||||
style="background-color: var(--bs-info); margin-left: 2px;"/>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mt-1" style="font-size: 0.7rem;">
|
||||
<span class="text-muted">Receiving</span>
|
||||
<span class="text-muted">In Progress</span>
|
||||
<span class="text-muted">Shipping</span>
|
||||
<div class="o_fp_job_card">
|
||||
<div class="o_fp_job_header">
|
||||
<div>
|
||||
<a t-att-href="'/my/jobs/%s' % job.id"
|
||||
class="o_fp_job_ref text-decoration-none"
|
||||
t-out="job.name"/>
|
||||
<span class="o_fp_job_meta">
|
||||
<t t-if="job.quantity"><t t-out="job.quantity"/> units</t>
|
||||
<t t-if="job.target_ship_date"> · ETA <span t-field="job.target_ship_date" t-options='{"widget": "date"}'/></t>
|
||||
</span>
|
||||
</div>
|
||||
<t t-call="fusion_plating_portal.fp_portal_status_badge">
|
||||
<t t-set="state" t-value="job.state"/>
|
||||
<t t-set="label" t-value="dict(job._fields['state']._description_selection(job.env)).get(job.state)"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<!-- State -> active step index map (same as dashboard) -->
|
||||
<t t-set="state_to_idx" t-value="{'received': 0, 'in_progress': 2, 'quality_check': 3, 'ready_to_ship': 4, 'shipped': 5, 'complete': 5}"/>
|
||||
<t t-set="state_idx" t-value="state_to_idx.get(job.state, 0)"/>
|
||||
<t t-set="steps" t-value="[
|
||||
{'label': 'Received', 'status': 'done' if state_idx > 0 else 'active', 'time_label': ''},
|
||||
{'label': 'Inspected', 'status': 'done' if state_idx > 1 else ('active' if state_idx == 1 else 'pending'), 'time_label': ''},
|
||||
{'label': 'Plating', 'status': 'done' if state_idx > 2 else ('active' if state_idx == 2 else 'pending'), 'time_label': ''},
|
||||
{'label': 'QC', 'status': 'done' if state_idx > 3 else ('active' if state_idx == 3 else 'pending'), 'time_label': ''},
|
||||
{'label': 'Ship', 'status': 'done' if state_idx > 4 else ('active' if state_idx == 4 else 'pending'), 'time_label': ''},
|
||||
]"/>
|
||||
<t t-set="active_state" t-value="'warn' if job.state == 'quality_check' else 'normal'"/>
|
||||
<t t-call="fusion_plating_portal.fp_portal_stepper"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user