<template>
|
<TableLayout :permissions="['business:order:query']">
|
<el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
|
<el-form-item label="订单编号" prop="orderNo">
|
<el-input v-model="searchForm.orderNo" placeholder="订单编号" @keypress.enter.native="search"></el-input>
|
</el-form-item>
|
<el-form-item label="主播账号" prop="anchorUsername">
|
<el-input v-model="searchForm.anchorUsername" placeholder="主播账号"></el-input>
|
</el-form-item>
|
<section>
|
<el-button type="primary" @click="search">搜索</el-button>
|
<el-button @click="reset">重置</el-button>
|
</section>
|
</el-form>
|
<template v-slot:table-wrap>
|
<el-table v-loading="isWorking.search" :data="tableData.list" stripe border :header-cell-style="rowStyle" :cell-style="rowStyle">
|
<el-table-column prop="orderNo" label="订单编号" min-width="140"></el-table-column>
|
<el-table-column prop="userBudget" label="客户预算" min-width="100"></el-table-column>
|
<el-table-column prop="categoryCount" label="品类数量" min-width="90"></el-table-column>
|
<el-table-column prop="goodsCount" label="商品数量" min-width="90"></el-table-column>
|
<el-table-column prop="totalZdPrice" label="旗舰价" min-width="100"></el-table-column>
|
<el-table-column prop="totalPrice" label="指导价" min-width="100"></el-table-column>
|
<el-table-column prop="anchorUsername" label="主播账号" min-width="120"></el-table-column>
|
<el-table-column label="创建时间" min-width="160">
|
<template slot-scope="{row}">{{ formatOrderCreateTime(row) }}</template>
|
</el-table-column>
|
<el-table-column label="提交时间" min-width="160">
|
<template slot-scope="{row}">{{ formatDateTime(row.submitTime) }}</template>
|
</el-table-column>
|
<el-table-column prop="durationText" label="创建时长" min-width="100"></el-table-column>
|
<el-table-column label="操作" min-width="200" fixed="right">
|
<template slot-scope="{row}">
|
<el-button type="text" @click="showDetail(row.id)">详情</el-button>
|
<el-button type="text" :loading="exportingId === row.id" @click="exportRow(row.id)" v-permissions="['business:order:exportExcel']">导出</el-button>
|
<el-button type="text" class="btn-delete" icon="el-icon-delete" @click="deleteRow(row)" v-permissions="['business:order:delete']">删除</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<pagination @size-change="handleSizeChange" @current-change="handlePageChange" :pagination="tableData.pagination" />
|
</template>
|
<el-dialog
|
title="订单详情"
|
:visible.sync="detailVisible"
|
width="920px"
|
custom-class="order-detail-dialog"
|
append-to-body>
|
<template v-if="detail">
|
<div class="order-detail-panel">
|
<div class="order-detail-hero">
|
<div class="order-detail-hero__content">
|
<div class="order-detail-hero__label">订单编号</div>
|
<div class="order-detail-hero__no">{{ detail.orderNo || '--' }}</div>
|
<div class="order-detail-hero__tags">
|
<span class="order-detail-tag">
|
<i class="el-icon-user"></i>
|
{{ detail.anchorUsername || '--' }}
|
</span>
|
<span class="order-detail-tag">
|
<i class="el-icon-timer"></i>
|
创建时长 {{ detail.durationText || '--' }}
|
</span>
|
</div>
|
</div>
|
</div>
|
|
<div class="order-detail-stats">
|
<div class="order-detail-stat">
|
<div class="order-detail-stat__label">客户预算</div>
|
<div class="order-detail-stat__value">{{ formatMoney(detail.userBudget) }}</div>
|
</div>
|
<div class="order-detail-stat">
|
<div class="order-detail-stat__label">品类数量</div>
|
<div class="order-detail-stat__value">{{ formatCount(detail.categoryCount) }}</div>
|
</div>
|
<div class="order-detail-stat">
|
<div class="order-detail-stat__label">商品数量</div>
|
<div class="order-detail-stat__value">{{ formatCount(detail.goodsCount) }}</div>
|
</div>
|
<div class="order-detail-stat">
|
<div class="order-detail-stat__label">旗舰价合计</div>
|
<div class="order-detail-stat__value">{{ formatMoney(detail.totalZdPrice) }}</div>
|
</div>
|
<div class="order-detail-stat order-detail-stat--primary">
|
<div class="order-detail-stat__label">指导价合计</div>
|
<div class="order-detail-stat__value">{{ formatMoney(detail.totalPrice) }}</div>
|
</div>
|
</div>
|
|
<div class="order-detail-meta">
|
<div class="order-detail-meta__item">
|
<div class="order-detail-meta__icon"><i class="el-icon-date"></i></div>
|
<div class="order-detail-meta__body">
|
<div class="order-detail-meta__label">创建时间</div>
|
<div class="order-detail-meta__value">{{ formatOrderCreateTime(detail) }}</div>
|
</div>
|
</div>
|
<div class="order-detail-meta__divider"></div>
|
<div class="order-detail-meta__item">
|
<div class="order-detail-meta__icon"><i class="el-icon-circle-check"></i></div>
|
<div class="order-detail-meta__body">
|
<div class="order-detail-meta__label">提交时间</div>
|
<div class="order-detail-meta__value">{{ formatDateTime(detail.submitTime) }}</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<div class="order-detail-table-wrap">
|
<div class="order-detail-section-head">
|
<span class="order-detail-section-head__title">商品明细</span>
|
<span class="order-detail-section-head__extra">共 {{ (detail.items && detail.items.length) || 0 }} 件</span>
|
</div>
|
<el-table v-if="detail.items" :data="detail.items" border stripe :header-cell-style="rowStyle" :cell-style="rowStyle">
|
<el-table-column prop="sortNum" label="序号" width="60"></el-table-column>
|
<el-table-column prop="categoryName" label="品类名称" min-width="120"></el-table-column>
|
<el-table-column prop="goodsName" label="产品型号" min-width="160"></el-table-column>
|
<el-table-column label="旗舰价" min-width="100">
|
<template slot-scope="{row}">{{ formatMoney(row.zdPrice) }}</template>
|
</el-table-column>
|
<el-table-column label="指导价" min-width="100">
|
<template slot-scope="{row}">{{ formatMoney(row.price) }}</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</template>
|
</el-dialog>
|
</TableLayout>
|
</template>
|
|
<script>
|
import BaseTable from '@/components/base/BaseTable'
|
import TableLayout from '@/layouts/TableLayout'
|
import Pagination from '@/components/common/Pagination'
|
import { queryById, exportDetail, deleteById } from '@/api/business/order'
|
|
export default {
|
name: 'PreselectOrder',
|
extends: BaseTable,
|
components: { TableLayout, Pagination },
|
data () {
|
return {
|
searchForm: { orderNo: '', anchorUsername: '' },
|
detailVisible: false,
|
detail: null,
|
exportingId: null
|
}
|
},
|
created () {
|
this.config({
|
module: '订单',
|
api: '/business/order',
|
'field.id': 'id',
|
'field.main': 'orderNo'
|
})
|
this.search()
|
},
|
methods: {
|
rowStyle () { return 'text-align:center' },
|
formatDateTime (val) {
|
if (val == null || val === '') return '--'
|
if (typeof val === 'string' && /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(val)) {
|
return val
|
}
|
const date = val instanceof Date ? val : new Date(val)
|
if (Number.isNaN(date.getTime())) return String(val)
|
const pad = n => String(n).padStart(2, '0')
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
|
},
|
formatOrderCreateTime (row) {
|
if (!row) return '--'
|
return this.formatDateTime(row.sessionCreateTime || row.createTime)
|
},
|
formatMoney (val) {
|
if (val == null || val === '') return '--'
|
return `¥${val}`
|
},
|
formatCount (val) {
|
if (val == null || val === '') return '--'
|
return val
|
},
|
showDetail (id) {
|
queryById(id).then(res => {
|
this.detail = res
|
this.detailVisible = true
|
})
|
},
|
exportRow (id) {
|
this.exportingId = id
|
exportDetail(id)
|
.then(response => {
|
this.download(response)
|
this.$message.success('导出成功')
|
})
|
.catch(e => {
|
this.$tip.apiFailed(e)
|
})
|
.finally(() => {
|
this.exportingId = null
|
})
|
},
|
deleteRow (row) {
|
this.$confirm(`确认删除订单【${row.orderNo}】?`, '提示').then(() => {
|
deleteById(row.id).then(() => {
|
this.$message.success('删除成功')
|
this.search()
|
})
|
})
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
@import '@/assets/style/variables.scss';
|
|
.order-detail-panel {
|
overflow: hidden;
|
border-radius: 8px;
|
border: 1px solid #e8edf5;
|
background: #fff;
|
box-shadow: 0 4px 18px rgba(46, 104, 236, 0.06);
|
}
|
|
.order-detail-hero {
|
position: relative;
|
padding: 22px 24px 20px;
|
background: linear-gradient(135deg, $primary-color 0%, #5b8def 55%, #7ba4f5 100%);
|
overflow: hidden;
|
|
&::before {
|
content: '';
|
position: absolute;
|
right: -30px;
|
top: -40px;
|
width: 160px;
|
height: 160px;
|
border-radius: 50%;
|
background: rgba(255, 255, 255, 0.08);
|
}
|
|
&::after {
|
content: '';
|
position: absolute;
|
right: 80px;
|
bottom: -50px;
|
width: 120px;
|
height: 120px;
|
border-radius: 50%;
|
background: rgba(255, 255, 255, 0.06);
|
}
|
}
|
|
.order-detail-hero__content {
|
position: relative;
|
z-index: 1;
|
}
|
|
.order-detail-hero__label {
|
font-size: 12px;
|
color: rgba(255, 255, 255, 0.82);
|
letter-spacing: 0.5px;
|
}
|
|
.order-detail-hero__no {
|
margin-top: 6px;
|
font-size: 22px;
|
font-weight: 600;
|
color: #fff;
|
letter-spacing: 0.5px;
|
line-height: 1.3;
|
word-break: break-all;
|
}
|
|
.order-detail-hero__tags {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 10px;
|
margin-top: 14px;
|
}
|
|
.order-detail-tag {
|
display: inline-flex;
|
align-items: center;
|
gap: 6px;
|
padding: 5px 12px;
|
border-radius: 999px;
|
background: rgba(255, 255, 255, 0.16);
|
backdrop-filter: blur(4px);
|
font-size: 12px;
|
color: #fff;
|
line-height: 1;
|
|
i {
|
font-size: 13px;
|
}
|
}
|
|
.order-detail-stats {
|
display: grid;
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
gap: 12px;
|
padding: 16px 18px 6px;
|
}
|
|
.order-detail-stat {
|
padding: 14px 12px;
|
border-radius: 8px;
|
background: linear-gradient(180deg, #f7f9fd 0%, #f3f6fb 100%);
|
border: 1px solid #e9eef6;
|
text-align: center;
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
&:hover {
|
transform: translateY(-1px);
|
box-shadow: 0 6px 16px rgba(46, 104, 236, 0.08);
|
}
|
}
|
|
.order-detail-stat--primary {
|
background: linear-gradient(180deg, #fff8ef 0%, #fff3e3 100%);
|
border-color: #fde6c8;
|
|
.order-detail-stat__label {
|
color: #c6842d;
|
}
|
|
.order-detail-stat__value {
|
color: #e6a23c;
|
}
|
}
|
|
.order-detail-stat__label {
|
font-size: 12px;
|
color: #909399;
|
line-height: 1.4;
|
}
|
|
.order-detail-stat__value {
|
margin-top: 8px;
|
font-size: 18px;
|
font-weight: 600;
|
color: #303133;
|
line-height: 1.2;
|
word-break: break-all;
|
}
|
|
.order-detail-meta {
|
display: flex;
|
align-items: stretch;
|
margin: 10px 18px 16px;
|
padding: 14px 16px;
|
border-radius: 8px;
|
background: #fafbfd;
|
border: 1px dashed #e3e8f0;
|
}
|
|
.order-detail-meta__item {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
gap: 12px;
|
min-width: 0;
|
}
|
|
.order-detail-meta__divider {
|
width: 1px;
|
margin: 0 18px;
|
background: #e4e7ed;
|
flex-shrink: 0;
|
}
|
|
.order-detail-meta__icon {
|
width: 36px;
|
height: 36px;
|
border-radius: 50%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
background: rgba(46, 104, 236, 0.1);
|
color: $primary-color;
|
flex-shrink: 0;
|
|
i {
|
font-size: 16px;
|
}
|
}
|
|
.order-detail-meta__body {
|
min-width: 0;
|
}
|
|
.order-detail-meta__label {
|
font-size: 12px;
|
color: #909399;
|
line-height: 1.4;
|
}
|
|
.order-detail-meta__value {
|
margin-top: 4px;
|
font-size: 14px;
|
font-weight: 500;
|
color: #303133;
|
line-height: 1.4;
|
word-break: break-all;
|
}
|
|
.order-detail-table-wrap {
|
margin-top: 4px;
|
}
|
|
.order-detail-section-head {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
margin-bottom: 12px;
|
padding-bottom: 10px;
|
border-bottom: 1px solid #eef2f7;
|
}
|
|
.order-detail-section-head__title {
|
position: relative;
|
padding-left: 11px;
|
font-size: 15px;
|
font-weight: 600;
|
color: #303133;
|
line-height: 1;
|
|
&::before {
|
content: '';
|
position: absolute;
|
left: 0;
|
top: 1px;
|
width: 3px;
|
height: 14px;
|
border-radius: 2px;
|
background: $primary-color;
|
}
|
}
|
|
.order-detail-section-head__extra {
|
font-size: 12px;
|
color: #909399;
|
}
|
</style>
|
|
<style lang="scss">
|
.order-detail-dialog {
|
.el-dialog__body {
|
padding: 16px 20px 22px;
|
}
|
|
.el-dialog__header {
|
padding: 18px 20px 10px;
|
border-bottom: 1px solid #f0f2f5;
|
}
|
|
.el-dialog__title {
|
font-size: 16px;
|
font-weight: 600;
|
color: #303133;
|
}
|
}
|
</style>
|