feat: 优化订单详情页UI,添加右侧悬浮操作栏
## 问题 - 原页面过长,操作按钮在底部,用户需要滚动才能操作 - 部分操作在侧边栏和主内容区重复显示 ## 改进 1. **布局重构** - 采用左右分栏布局(主内容 + 320px 侧边栏) - 侧边栏固定悬浮(sticky),始终可见 - 页面最大宽度从 1200px 扩展到 1400px 2. **操作整合(避免重复)** - 简单操作直接在侧边栏完成:提交交接、确认收号、确认结账 - 复杂操作提供快捷入口:发起结账、修改结账、拒绝修正、发起申诉 - 移除主内容区的重复表单 3. **视觉优化** - 蓝色高亮卡片:发起结账(重要操作) - 红色警告卡片:发起申诉(特殊操作) - 添加小分隔线区分主次操作 4. **响应式设计** - 桌面端:左右分栏 - 移动端:单列布局,侧边栏移到顶部 ## 用户体验提升 - 所有关键操作始终可见,无需滚动 - 简单操作一键完成,复杂操作跳转到详细表单 - 视觉层次清晰,减少误操作 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -612,6 +612,34 @@ function linesToList(value: string) {
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
function scrollToDispute() {
|
||||
const disputeSection = document.querySelector('.dispute-section')
|
||||
if (disputeSection) {
|
||||
disputeSection.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToCheckout() {
|
||||
const checkoutSection = document.querySelector('.checkout-form-section')
|
||||
if (checkoutSection) {
|
||||
checkoutSection.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToCounterCheckout() {
|
||||
const counterSection = document.querySelector('.counter-checkout-section')
|
||||
if (counterSection) {
|
||||
counterSection.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToRejectCheckout() {
|
||||
const rejectSection = document.querySelector('.reject-checkout-section')
|
||||
if (rejectSection) {
|
||||
rejectSection.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
}
|
||||
|
||||
function formatHandoffRecordType(type: string) {
|
||||
const typeMap: Record<string, string> = {
|
||||
owner_handoff: '卖家交接',
|
||||
@@ -640,6 +668,8 @@ function formatHandoffRecordType(type: string) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="order" class="content-layout">
|
||||
<div class="main-content">
|
||||
<div v-if="order" class="order-progress-section">
|
||||
<el-steps :active="getOrderStep(order.status)" align-center finish-status="success" process-status="process">
|
||||
<el-step title="待支付" :description="order.status === 'pending_payment' ? '等待租客支付' : ''" />
|
||||
@@ -726,30 +756,8 @@ function formatHandoffRecordType(type: string) {
|
||||
</el-timeline>
|
||||
</div>
|
||||
|
||||
<div v-if="order && isOwner && order.status === 'pending_handoff' && order.handoff_status === 'pending_owner'" class="form-section">
|
||||
<div class="section-header">
|
||||
<h2>提交交接说明</h2>
|
||||
</div>
|
||||
<div class="form-card">
|
||||
<el-input v-model="handoffContent" type="textarea" :rows="4" placeholder="填写登录方式、注意事项和交接说明" />
|
||||
<el-button type="primary" size="large" :loading="handoffing" @click="handleSubmitHandoff">提交交接</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="order && isRenter && order.status === 'pending_handoff' && order.handoff_status === 'pending_renter_confirm'"
|
||||
class="form-section"
|
||||
>
|
||||
<div class="section-header">
|
||||
<h2>确认收号</h2>
|
||||
</div>
|
||||
<div class="form-card">
|
||||
<p class="form-hint">确认账号可以正常登录后,订单会进入使用中并重新计算预计截止时间。</p>
|
||||
<el-button type="primary" size="large" :loading="confirming" @click="handleConfirmReceive">确认已收到账号</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="order && isRenter && ['renting', 'overdue'].includes(order.status)" class="form-section">
|
||||
<div v-if="order && isRenter && ['renting', 'overdue'].includes(order.status)" class="form-section checkout-form-section">
|
||||
<div class="section-header">
|
||||
<h2>发起结账</h2>
|
||||
</div>
|
||||
@@ -848,19 +856,12 @@ function formatHandoffRecordType(type: string) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="order && isOwner && order.status === 'pending_checkout_confirm'" class="form-section">
|
||||
<div v-if="order && isOwner && order.status === 'pending_checkout_confirm'" class="form-section counter-checkout-section">
|
||||
<div class="section-header">
|
||||
<h2>确认结账</h2>
|
||||
<h2>修改结账</h2>
|
||||
</div>
|
||||
<div class="form-card">
|
||||
<p class="form-hint">确认账号状态和扣款金额无误后,订单会完成,账号重新上架。</p>
|
||||
<el-button type="primary" size="large" :loading="completing" @click="handleConfirmCheckout">确认结账并完成订单</el-button>
|
||||
|
||||
<div class="section-divider">
|
||||
<span>或者</span>
|
||||
</div>
|
||||
|
||||
<h3 class="sub-title">修改结账</h3>
|
||||
<h3 class="sub-title">修改结账金额</h3>
|
||||
<el-form class="form-grid" label-position="top">
|
||||
<el-form-item label="额外消耗品已用金额">
|
||||
<el-input-number v-model="counterForm.consumable_amount" class="full-control" :min="0" :precision="0" controls-position="right" />
|
||||
@@ -881,22 +882,88 @@ function formatHandoffRecordType(type: string) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="order && isRenter && order.status === 'pending_checkout_accept'" class="form-section">
|
||||
<div v-if="order && isRenter && order.status === 'pending_checkout_accept'" class="form-section reject-checkout-section">
|
||||
<div class="section-header">
|
||||
<h2>确认修正结账</h2>
|
||||
<h2>拒绝修正</h2>
|
||||
</div>
|
||||
<div class="form-card">
|
||||
<p class="form-hint">同意后订单会完成结算;不同意会进入争议,由客服仲裁。</p>
|
||||
<el-button type="primary" size="large" :loading="acceptingCheckout" @click="handleAcceptCheckout">同意修正并完成订单</el-button>
|
||||
|
||||
<div class="section-divider">
|
||||
<span>或者</span>
|
||||
</div>
|
||||
|
||||
<h3 class="sub-title">拒绝修正</h3>
|
||||
<p class="form-hint">不同意修正时填写原因,订单会进入争议处理。</p>
|
||||
<el-input v-model="rejectReason" type="textarea" :rows="3" placeholder="不同意时填写原因,会进入争议处理" />
|
||||
<el-button type="danger" plain size="large" :loading="rejectingCheckout" @click="handleRejectCheckout">拒绝修正并发起争议</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧悬浮操作区 -->
|
||||
<div v-if="order" class="action-sidebar">
|
||||
<!-- 交接操作 -->
|
||||
<div v-if="isOwner && order.status === 'pending_handoff' && order.handoff_status === 'pending_owner'" class="sidebar-card">
|
||||
<h3 class="sidebar-title">提交交接说明</h3>
|
||||
<el-input v-model="handoffContent" type="textarea" :rows="5" placeholder="填写登录方式、注意事项和交接说明" />
|
||||
<el-button type="primary" size="large" :loading="handoffing" @click="handleSubmitHandoff">提交交接</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 确认收号 -->
|
||||
<div
|
||||
v-if="isRenter && order.status === 'pending_handoff' && order.handoff_status === 'pending_renter_confirm'"
|
||||
class="sidebar-card"
|
||||
>
|
||||
<h3 class="sidebar-title">确认收号</h3>
|
||||
<p class="sidebar-hint">确认账号可以正常登录后,订单会进入使用中并重新计算预计截止时间。</p>
|
||||
<el-button type="primary" size="large" :loading="confirming" @click="handleConfirmReceive">确认已收到账号</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 发起结账 -->
|
||||
<div v-if="isRenter && ['renting', 'overdue'].includes(order.status)" class="sidebar-card highlight-card">
|
||||
<h3 class="sidebar-title">快捷结账</h3>
|
||||
<el-button type="primary" size="large" :loading="returning" @click="handleSubmitCheckout">
|
||||
立即提交结账
|
||||
</el-button>
|
||||
<p class="sidebar-hint">如需修改消耗品、哈夫币等详细信息,请先向下滚动填写完整表单后再提交</p>
|
||||
<el-button type="default" size="small" @click="scrollToCheckout">
|
||||
查看详细结账表单
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 确认结账 -->
|
||||
<div v-if="isOwner && order.status === 'pending_checkout_confirm'" class="sidebar-card">
|
||||
<h3 class="sidebar-title">确认结账</h3>
|
||||
<el-button type="primary" size="large" :loading="completing" @click="handleConfirmCheckout">
|
||||
确认结账并完成订单
|
||||
</el-button>
|
||||
<div class="section-divider-mini">
|
||||
<span>或者</span>
|
||||
</div>
|
||||
<el-button type="warning" plain size="large" @click="scrollToCounterCheckout">
|
||||
需要修改结账金额
|
||||
</el-button>
|
||||
<p class="sidebar-hint">如认为金额有误,点击上方按钮修改</p>
|
||||
</div>
|
||||
|
||||
<!-- 确认修正结账 -->
|
||||
<div v-if="isRenter && order.status === 'pending_checkout_accept'" class="sidebar-card">
|
||||
<h3 class="sidebar-title">确认修正结账</h3>
|
||||
<el-button type="primary" size="large" :loading="acceptingCheckout" @click="handleAcceptCheckout">
|
||||
同意修正并完成订单
|
||||
</el-button>
|
||||
<div class="section-divider-mini">
|
||||
<span>或者</span>
|
||||
</div>
|
||||
<el-button type="danger" plain size="large" @click="scrollToRejectCheckout">
|
||||
不同意,发起争议
|
||||
</el-button>
|
||||
<p class="sidebar-hint">不同意修正时需填写原因,将进入争议处理</p>
|
||||
</div>
|
||||
|
||||
<!-- 发起申诉 -->
|
||||
<div v-if="canOpenDispute" class="sidebar-card dispute-card">
|
||||
<h3 class="sidebar-title">{{ isCheckoutDisputeStage ? '发起结账争议' : '发起申诉' }}</h3>
|
||||
<el-button type="warning" size="large" @click="scrollToDispute">
|
||||
{{ isCheckoutDisputeStage ? '提交结账争议' : '提交申诉' }}
|
||||
</el-button>
|
||||
<p class="sidebar-hint">点击后滚动到申诉表单填写详细信息</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="order && canOpenDispute" class="form-section dispute-section">
|
||||
@@ -975,7 +1042,7 @@ function formatHandoffRecordType(type: string) {
|
||||
|
||||
<style scoped>
|
||||
.order-detail-page {
|
||||
max-width: 1200px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@@ -999,6 +1066,64 @@ function formatHandoffRecordType(type: string) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.content-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 320px;
|
||||
gap: 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.action-sidebar {
|
||||
position: sticky;
|
||||
top: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.sidebar-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: 20px;
|
||||
background: #ffffff;
|
||||
border: 2px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.sidebar-card.highlight-card {
|
||||
background: #eff6ff;
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
.sidebar-card.dispute-card {
|
||||
background: #fef2f2;
|
||||
border-color: #fecaca;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #1f2937;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sidebar-hint {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.sidebar-card .el-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.order-progress-section {
|
||||
margin-bottom: 32px;
|
||||
padding: 24px;
|
||||
@@ -1244,6 +1369,29 @@ function formatHandoffRecordType(type: string) {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.section-divider-mini {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 8px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.section-divider-mini::before,
|
||||
.section-divider-mini::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: #e5e7eb;
|
||||
}
|
||||
|
||||
.section-divider-mini span {
|
||||
padding: 0 12px;
|
||||
color: #9ca3af;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
@@ -1562,6 +1710,15 @@ function formatHandoffRecordType(type: string) {
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.content-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.action-sidebar {
|
||||
position: static;
|
||||
order: -1;
|
||||
}
|
||||
|
||||
.header-top {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user