2025-07-11 12:00:00 +08:00
|
|
|
|
<template>
|
|
|
|
|
<div class="app-container">
|
|
|
|
|
<!-- 页面标题 -->
|
|
|
|
|
<h2 class="page-title">结算单详情</h2>
|
|
|
|
|
|
|
|
|
|
<!-- 查询区域 -->
|
|
|
|
|
<div class="head-container">
|
|
|
|
|
<div class="filter-container">
|
|
|
|
|
<div class="filter-item">
|
|
|
|
|
<span class="label">订单批次号:</span>
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="query.batchNo"
|
|
|
|
|
placeholder="请输入订单批次号"
|
|
|
|
|
style="width: 200px"
|
|
|
|
|
clearable
|
2025-07-31 19:07:10 +08:00
|
|
|
|
@input="handleSearch"
|
2025-07-11 12:00:00 +08:00
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="filter-item">
|
|
|
|
|
<span class="label">景区:</span>
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="query.scenicArea"
|
|
|
|
|
placeholder="请选择景区"
|
|
|
|
|
clearable
|
|
|
|
|
style="width: 200px"
|
2025-07-31 19:07:10 +08:00
|
|
|
|
@change="handleSearch"
|
2025-07-11 12:00:00 +08:00
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in scenicAreaOptions"
|
|
|
|
|
:key="item.value"
|
|
|
|
|
:label="item.label"
|
|
|
|
|
:value="item.value"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="filter-item">
|
|
|
|
|
<span class="label">日期:</span>
|
|
|
|
|
<el-date-picker
|
|
|
|
|
v-model="query.dateRange"
|
|
|
|
|
type="daterange"
|
|
|
|
|
range-separator="~"
|
|
|
|
|
start-placeholder="开始日期"
|
|
|
|
|
end-placeholder="结束日期"
|
|
|
|
|
:default-time="['00:00:00', '23:59:59']"
|
|
|
|
|
:default-value="defaultDateRange"
|
|
|
|
|
style="width: 350px"
|
2025-07-31 19:07:10 +08:00
|
|
|
|
@change="handleSearch"
|
2025-07-11 12:00:00 +08:00
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 订单列表区域 -->
|
|
|
|
|
<div class="order-list-container">
|
|
|
|
|
<div class="list-header">
|
|
|
|
|
<span class="list-title">订单列表:</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 表格 -->
|
|
|
|
|
<el-table
|
|
|
|
|
ref="table"
|
|
|
|
|
v-loading="loading"
|
2025-07-31 19:07:10 +08:00
|
|
|
|
:data="paginatedData"
|
2025-07-11 12:00:00 +08:00
|
|
|
|
style="width: 100%"
|
|
|
|
|
>
|
|
|
|
|
<el-table-column prop="customerName" label="客户名称" align="center" />
|
2025-07-31 19:07:10 +08:00
|
|
|
|
<el-table-column prop="phone" label="手机号码" align="center" />
|
|
|
|
|
<el-table-column prop="createTime" label="下单时间" align="center" width="180" />
|
|
|
|
|
<el-table-column prop="totalAmount" label="下单费用" align="center">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<span>{{ scope.row.totalAmount.toLocaleString('zh', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="scenicName" label="景区" align="center" />
|
|
|
|
|
<el-table-column prop="routeIds" label="路线" align="center" />
|
|
|
|
|
<el-table-column prop="createBy" label="订单发起人" align="center" />
|
2025-07-11 12:00:00 +08:00
|
|
|
|
<el-table-column
|
2025-07-31 19:07:10 +08:00
|
|
|
|
prop="orderType"
|
|
|
|
|
label="订单类型"
|
2025-07-11 12:00:00 +08:00
|
|
|
|
align="center"
|
2025-07-31 19:07:10 +08:00
|
|
|
|
>
|
2025-07-11 12:00:00 +08:00
|
|
|
|
<template slot-scope="scope">
|
2025-07-31 19:07:10 +08:00
|
|
|
|
<span>{{ scope.row.orderType === 1 ? '载物飞行' : '载人飞行' }}</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column
|
|
|
|
|
prop="mainOrderStatus"
|
|
|
|
|
label="订单状态"
|
|
|
|
|
align="center"
|
|
|
|
|
>
|
|
|
|
|
<template slot-scope="scope">
|
2025-08-04 21:01:04 +08:00
|
|
|
|
<span :class="getOrderStatusClass(scope.row.mainOrderStatus)">
|
|
|
|
|
{{ getOrderStatusText(scope.row.mainOrderStatus) }}
|
2025-07-31 19:07:10 +08:00
|
|
|
|
</span>
|
2025-07-11 12:00:00 +08:00
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column
|
|
|
|
|
prop="settlementStatus"
|
|
|
|
|
label="结算状态"
|
|
|
|
|
align="center"
|
|
|
|
|
>
|
|
|
|
|
<template slot-scope="scope">
|
2025-08-04 21:01:04 +08:00
|
|
|
|
<span :class="getSettlementStatusClass(scope.row.settlementStatus, true)">
|
|
|
|
|
{{ getSettlementStatusText(scope.row.settlementStatus, true) }}
|
2025-07-11 12:00:00 +08:00
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<!-- 分页 -->
|
|
|
|
|
<div class="pagination-container">
|
|
|
|
|
<el-pagination
|
|
|
|
|
:current-page.sync="page.current"
|
|
|
|
|
:page-sizes="[10, 20, 50, 100]"
|
|
|
|
|
:page-size="page.size"
|
2025-07-31 19:07:10 +08:00
|
|
|
|
:total="tableData.length"
|
2025-07-11 12:00:00 +08:00
|
|
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
|
|
|
@size-change="handleSizeChange"
|
|
|
|
|
@current-change="handleCurrentChange"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 操作按钮 -->
|
|
|
|
|
<div class="action-buttons">
|
|
|
|
|
<el-button
|
2025-08-02 11:56:29 +08:00
|
|
|
|
:disabled="!(settlementStatus === 0)"
|
2025-07-11 12:00:00 +08:00
|
|
|
|
type="primary"
|
|
|
|
|
@click="handleCancelSettlement"
|
|
|
|
|
>
|
|
|
|
|
取消结算
|
|
|
|
|
</el-button>
|
2025-08-02 11:56:29 +08:00
|
|
|
|
<el-button type="primary" @click="handlePrint">打印结算单</el-button>
|
2025-07-31 19:07:10 +08:00
|
|
|
|
<el-button
|
2025-08-02 11:56:29 +08:00
|
|
|
|
v-if="settlementStatus === 2"
|
2025-07-31 19:07:10 +08:00
|
|
|
|
type="success"
|
|
|
|
|
@click="handleStatusChange(1)"
|
|
|
|
|
>
|
|
|
|
|
确认结算
|
|
|
|
|
</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
v-if="settlementStatus === 1"
|
|
|
|
|
type="success"
|
|
|
|
|
@click="handleStatusChange(2)"
|
|
|
|
|
>
|
|
|
|
|
完成结算
|
|
|
|
|
</el-button>
|
2025-07-11 12:00:00 +08:00
|
|
|
|
</div>
|
2025-07-31 19:07:10 +08:00
|
|
|
|
|
|
|
|
|
<!-- PDF导出组件 -->
|
|
|
|
|
<settlement-pdf
|
2025-08-02 11:56:29 +08:00
|
|
|
|
v-if="$route.query.orderId"
|
2025-07-31 19:07:10 +08:00
|
|
|
|
ref="settlementPdf"
|
|
|
|
|
:order-data="currentOrder"
|
2025-08-02 11:56:29 +08:00
|
|
|
|
:settlement-order-id="$route.query.orderId"
|
2025-07-31 19:07:10 +08:00
|
|
|
|
v-show="false"
|
|
|
|
|
/>
|
2025-07-11 12:00:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
2025-08-04 21:01:04 +08:00
|
|
|
|
import { getOrderStatusText, getSettlementStatusText, getOrderStatusClass, getSettlementStatusClass } from "@/utils/orderStatus";
|
2025-08-02 11:56:29 +08:00
|
|
|
|
import { getSettleOrderDetail, updateSettleOrderStatus, printSettleOrderData } from '@/api/order'
|
2025-07-31 19:07:10 +08:00
|
|
|
|
import { getDetail } from "@/api/system/pilot";
|
|
|
|
|
import { getCustomerId } from '@/api/system/customer'
|
|
|
|
|
import { getScenicValue } from '@/api/dropdown'
|
|
|
|
|
import SettlementPdf from './settlementPdf.vue'
|
|
|
|
|
|
2025-07-11 12:00:00 +08:00
|
|
|
|
export default {
|
|
|
|
|
name: "orderDetail",
|
2025-07-31 19:07:10 +08:00
|
|
|
|
components: {
|
|
|
|
|
SettlementPdf
|
|
|
|
|
},
|
2025-07-11 12:00:00 +08:00
|
|
|
|
data() {
|
|
|
|
|
return {
|
2025-08-13 21:45:35 +08:00
|
|
|
|
orderId: '',
|
2025-07-11 12:00:00 +08:00
|
|
|
|
loading: false,
|
2025-07-31 19:07:10 +08:00
|
|
|
|
scenicAreaOptions: [],
|
|
|
|
|
settlementStatus: 0,
|
|
|
|
|
currentOrder: null,
|
2025-08-02 11:56:29 +08:00
|
|
|
|
originalData: [], // 存储原始数据,用于筛选
|
2025-07-11 12:00:00 +08:00
|
|
|
|
query: {
|
|
|
|
|
batchNo: "",
|
|
|
|
|
scenicArea: "",
|
2025-08-13 21:45:35 +08:00
|
|
|
|
dateRange: [],
|
2025-07-11 12:00:00 +08:00
|
|
|
|
},
|
2025-08-13 21:45:35 +08:00
|
|
|
|
defaultDateRange: [],
|
2025-07-11 12:00:00 +08:00
|
|
|
|
page: {
|
|
|
|
|
current: 1,
|
2025-07-31 19:07:10 +08:00
|
|
|
|
size: 10
|
2025-07-11 12:00:00 +08:00
|
|
|
|
},
|
2025-07-31 19:07:10 +08:00
|
|
|
|
tableData: [],
|
2025-07-11 12:00:00 +08:00
|
|
|
|
selection: [],
|
|
|
|
|
};
|
|
|
|
|
},
|
2025-07-31 19:07:10 +08:00
|
|
|
|
computed: {
|
|
|
|
|
paginatedData() {
|
|
|
|
|
const start = (this.page.current - 1) * this.page.size
|
|
|
|
|
const end = start + this.page.size
|
|
|
|
|
return this.tableData.slice(start, end)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async created() {
|
|
|
|
|
// 获取景区下拉数据
|
|
|
|
|
const scenicResponse = await getScenicValue()
|
|
|
|
|
this.scenicAreaOptions = scenicResponse.map(item => ({
|
|
|
|
|
value: item.key,
|
|
|
|
|
label: item.value
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
// 获取订单详情并处理数据
|
2025-08-13 21:45:35 +08:00
|
|
|
|
this.orderId = this.$route.query.orderId
|
|
|
|
|
if(this.orderId) {
|
2025-07-31 19:07:10 +08:00
|
|
|
|
this.loading = true
|
2025-08-13 21:45:35 +08:00
|
|
|
|
this.getOrderDetail(this.orderId)
|
|
|
|
|
} else {
|
|
|
|
|
this.$message.error('没有提供订单ID')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
getOrderStatusText,
|
|
|
|
|
getSettlementStatusText,
|
|
|
|
|
getOrderStatusClass,
|
|
|
|
|
getSettlementStatusClass,
|
|
|
|
|
async getOrderDetail(orderId) {
|
2025-07-31 19:07:10 +08:00
|
|
|
|
try {
|
|
|
|
|
const settleOrderDetail = await getSettleOrderDetail(orderId)
|
|
|
|
|
await Promise.all(settleOrderDetail.map(async (item) => {
|
|
|
|
|
// 获取客户名称
|
|
|
|
|
const customerResponse = await getCustomerId(item.customerId)
|
|
|
|
|
item.customerName = customerResponse.name
|
|
|
|
|
|
|
|
|
|
// 获取飞行员信息
|
|
|
|
|
const pilotResponse = await getDetail(item.orderInitiatorId)
|
|
|
|
|
item.createBy = pilotResponse.name
|
|
|
|
|
|
|
|
|
|
// 获取景区名称
|
2025-08-13 21:45:35 +08:00
|
|
|
|
console.log(this.scenicAreaOptions)
|
|
|
|
|
const scenic = this.scenicAreaOptions.find(s => s.value === item.attractionId)
|
|
|
|
|
item.scenicName = scenic ? scenic.label : ''
|
2025-07-31 19:07:10 +08:00
|
|
|
|
}))
|
2025-08-02 11:56:29 +08:00
|
|
|
|
this.originalData = settleOrderDetail // 保存原始数据
|
2025-07-31 19:07:10 +08:00
|
|
|
|
this.tableData = settleOrderDetail
|
|
|
|
|
if(settleOrderDetail.length > 0) {
|
|
|
|
|
this.currentOrder = settleOrderDetail[0]
|
|
|
|
|
this.settlementStatus = settleOrderDetail[0].settlementStatus
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error fetching order details:', error)
|
|
|
|
|
this.$message.error('获取订单详情失败')
|
|
|
|
|
} finally {
|
|
|
|
|
this.loading = false
|
|
|
|
|
}
|
2025-08-13 21:45:35 +08:00
|
|
|
|
},
|
2025-08-02 11:56:29 +08:00
|
|
|
|
handleSearch() {
|
2025-07-31 19:07:10 +08:00
|
|
|
|
this.loading = true
|
|
|
|
|
try {
|
2025-08-02 11:56:29 +08:00
|
|
|
|
// 从原始数据中筛选
|
|
|
|
|
const filteredData = this.originalData.filter(item => {
|
|
|
|
|
let matchesBatchNo = true
|
|
|
|
|
let matchesScenicArea = true
|
|
|
|
|
let matchesDateRange = true
|
|
|
|
|
|
|
|
|
|
// 批次号筛选
|
|
|
|
|
if (this.query.batchNo) {
|
|
|
|
|
matchesBatchNo = item.batchNo.toLowerCase().includes(this.query.batchNo.toLowerCase())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 景区筛选
|
|
|
|
|
if (this.query.scenicArea) {
|
|
|
|
|
matchesScenicArea = item.attractionId === this.query.scenicArea
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 日期范围筛选
|
|
|
|
|
if (this.query.dateRange && this.query.dateRange.length === 2) {
|
|
|
|
|
const orderDate = new Date(item.createTime)
|
|
|
|
|
const startDate = new Date(this.query.dateRange[0])
|
|
|
|
|
const endDate = new Date(this.query.dateRange[1])
|
|
|
|
|
startDate.setHours(0, 0, 0, 0)
|
|
|
|
|
endDate.setHours(23, 59, 59, 999)
|
|
|
|
|
matchesDateRange = orderDate >= startDate && orderDate <= endDate
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return matchesBatchNo && matchesScenicArea && matchesDateRange
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
this.tableData = filteredData
|
2025-07-31 19:07:10 +08:00
|
|
|
|
// 重置分页到第一页
|
|
|
|
|
this.page.current = 1
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error searching orders:', error)
|
|
|
|
|
this.$message.error('搜索订单失败')
|
|
|
|
|
} finally {
|
|
|
|
|
this.loading = false
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async handleCancelSettlement() {
|
|
|
|
|
try {
|
2025-08-13 21:45:35 +08:00
|
|
|
|
await updateSettleOrderStatus(this.orderId, 3)
|
2025-07-31 19:07:10 +08:00
|
|
|
|
this.settlementStatus = 3
|
|
|
|
|
this.$message.success('取消结算成功')
|
2025-08-13 21:45:35 +08:00
|
|
|
|
this.getOrderDetail(this.orderId) // 刷新数据
|
2025-07-31 19:07:10 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error canceling settlement:', error)
|
|
|
|
|
this.$message.error('取消结算失败')
|
2025-07-11 12:00:00 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
handleSizeChange(val) {
|
|
|
|
|
this.page.size = val;
|
2025-07-31 19:07:10 +08:00
|
|
|
|
this.page.current = 1; // 重置到第一页
|
2025-07-11 12:00:00 +08:00
|
|
|
|
},
|
|
|
|
|
handleCurrentChange(val) {
|
|
|
|
|
this.page.current = val;
|
|
|
|
|
},
|
2025-07-31 19:07:10 +08:00
|
|
|
|
async handlePrint() {
|
2025-08-13 21:45:35 +08:00
|
|
|
|
if (this.orderId) {
|
2025-07-31 19:07:10 +08:00
|
|
|
|
try {
|
2025-08-13 21:45:35 +08:00
|
|
|
|
// 等待VUE渲染组件
|
2025-08-02 11:56:29 +08:00
|
|
|
|
await this.$nextTick()
|
2025-07-31 19:07:10 +08:00
|
|
|
|
await this.$refs.settlementPdf.generatePDF()
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error generating PDF:', error)
|
|
|
|
|
this.$message.error('导出PDF失败')
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-08-02 11:56:29 +08:00
|
|
|
|
this.$message.warning('没有结算单ID')
|
2025-07-31 19:07:10 +08:00
|
|
|
|
}
|
2025-07-11 12:00:00 +08:00
|
|
|
|
},
|
2025-07-31 19:07:10 +08:00
|
|
|
|
async handleStatusChange(status) {
|
|
|
|
|
try {
|
2025-08-13 21:45:35 +08:00
|
|
|
|
await updateSettleOrderStatus(this.orderId, status)
|
2025-07-31 19:07:10 +08:00
|
|
|
|
this.settlementStatus = status
|
|
|
|
|
const statusText = status === 1 ? '已确认' : '已完成'
|
|
|
|
|
this.$message.success(`结算单状态已更新为:${statusText}`)
|
2025-08-13 21:45:35 +08:00
|
|
|
|
this.getOrderDetail(this.orderId) // 刷新数据
|
2025-07-31 19:07:10 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error updating settlement status:', error)
|
|
|
|
|
this.$message.error('更新结算状态失败')
|
2025-07-11 12:00:00 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.page-title {
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #303133;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.filter-container {
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
.filter-item {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-right: 20px;
|
|
|
|
|
|
|
|
|
|
.label {
|
|
|
|
|
color: #606266;
|
|
|
|
|
margin-right: 8px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.order-list-container {
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
|
|
|
|
.list-header {
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
.list-title {
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #303133;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.action-buttons {
|
|
|
|
|
text-align: center;
|
|
|
|
|
margin: 20px 0;
|
|
|
|
|
padding: 20px 0;
|
|
|
|
|
|
|
|
|
|
.el-button {
|
|
|
|
|
margin: 0 10px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-04 21:01:04 +08:00
|
|
|
|
.status-default { color: #909399; }
|
|
|
|
|
.status-pending { color: #909399; }
|
|
|
|
|
.status-processing { color: #409EFF; }
|
|
|
|
|
.status-success { color: #67c23a; }
|
|
|
|
|
.status-warning { color: #e6a23c; }
|
|
|
|
|
.status-danger { color: #f56c6c; }
|
2025-07-11 12:00:00 +08:00
|
|
|
|
|
|
|
|
|
.el-table {
|
|
|
|
|
margin-bottom: 70px;
|
2025-07-31 19:07:10 +08:00
|
|
|
|
margin-top: 20px;
|
|
|
|
|
::v-deep .el-table__body-wrapper {
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
}
|
2025-07-11 12:00:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.el-button--text {
|
|
|
|
|
color: #409eff;
|
|
|
|
|
&:hover {
|
|
|
|
|
color: #66b1ff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|