Files
oil/admin-vue/src/views/order/Index.vue
T
vipnub fafd3e2c16 1、合作商余额查询
2、分油账户司机可用额度
2026-10-20 23:21:10 +08:00

785 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<a-card :bordered="false">
<a-spin :spinning="isLoading">
<div class="card-title">{{ $route.meta.title }}</div>
<div class="table-operator">
<!-- 搜索板块 -->
<a-row class="row-item-search">
<a-form class="search-form" :form="searchForm" layout="inline" @submit="handleSearch">
<a-form-item label="关键词">
<a-input style="width: 342px" placeholder="请输入关键词" v-decorator="['searchValue']">
<a-select
slot="addonBefore"
v-decorator="['searchType', { initialValue: 10 }]"
style="width: 100px"
>
<a-select-option
v-for="(item, index) in SearchTypeEnum"
:key="index"
:value="item.value"
>{{ item.name }}</a-select-option>
</a-select>
</a-input>
</a-form-item>
<a-form-item label="订单来源">
<a-select v-decorator="['orderSource', { initialValue: -1 }]">
<a-select-option :value="-1">全部</a-select-option>
<a-select-option
v-for="(item, index) in OrderSourceEnum.data"
:key="index"
:value="item.value"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="支付方式">
<a-select v-decorator="['payType', { initialValue: -1 }]">
<a-select-option :value="-1">全部</a-select-option>
<a-select-option
v-for="(item, index) in PayTypeEnum.data"
:key="index"
:value="item.value"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="一级代理商">
<a-select v-decorator="['spread_uid', { initialValue: -1 }]">
<a-select-option :value="-1">全部</a-select-option>
<a-select-option
v-for="(item, index) in merchantListData"
:key="index"
:value="item.merchant_id"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="支付状态">
<a-select v-decorator="['pay_status', { initialValue: -1 }]">
<a-select-option :value="-1">全部</a-select-option>
<a-select-option
v-for="(item, index) in PayStatusEnum.data"
:key="index"
:value="item.value"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="分油状态">
<a-select v-decorator="['oil_status', { initialValue: -1 }]">
<a-select-option :value="-1">全部</a-select-option>
<a-select-option
v-for="(item, index) in OilStatusEnum.data"
:key="index"
:value="item.value"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="使用状态">
<a-select v-decorator="['use_status', { initialValue: -1 }]">
<a-select-option :value="-1">全部</a-select-option>
<a-select-option
v-for="(item, index) in UseStatusEnum.data"
:key="index"
:value="item.value"
>{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="企油通发放态">
<a-select v-decorator="['oil_status_zsy', { initialValue: -1 }]">
<a-select-option :value="-1">全部</a-select-option>
<a-select-option :value="0">未提交</a-select-option>
<a-select-option :value="1">发放中</a-select-option>
<a-select-option :value="2">发放成功</a-select-option>
<a-select-option :value="3">发放失败</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="退款状态">
<a-select v-decorator="['refund_status', { initialValue: -1 }]">
<a-select-option :value="-1">全部</a-select-option>
<a-select-option :value="0">未退款</a-select-option>
<a-select-option :value="1">退款中</a-select-option>
<a-select-option :value="2">已退款</a-select-option>
<a-select-option :value="3">退款失败</a-select-option>
<a-select-option :value="4">待人工确认</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="商品编码">
<a-input v-decorator="['goods_no']" placeholder="商品编码" />
</a-form-item>
<a-form-item label="油卡编号">
<a-input v-decorator="['oilCardNo']" placeholder="油卡编号" />
</a-form-item>
<a-form-item label="分油记录编号">
<a-input v-decorator="['shareNo']" placeholder="分油记录编号" />
</a-form-item>
<template>
<a-config-provider :locale="zhCN">
<a-form-item label="下单时间">
<a-range-picker format="YYYY-MM-DD" v-decorator="['betweenTime']" />
</a-form-item>
</a-config-provider>
</template>
<a-form-item class="search-btn">
<a-button type="primary" icon="search" html-type="submit">搜索</a-button>
</a-form-item>
<a-form-item class="search-btn">
<a-button @click="handleReset">重置</a-button>
</a-form-item>
</a-form>
</a-row>
<div class="row-item-tab clearfix">
<span class="form-total">实付款:¥{{ total_money }}</span>
</div>
<!-- 操作板块 -->
<!-- <div class="row-item-tab clearfix">
<a-button icon="download">订单导出</a-button>
<a-button icon="upload">批量发货</a-button>
</div>-->
</div>
<!-- 列表内容 -->
<div class="ant-table ant-table-scroll-position-left ant-table-default ant-table-bordered">
<div class="ant-table-content">
<div class="ant-table-body">
<table>
<thead class="ant-table-thead">
<tr>
<th v-for="(item, index) in columns" :key="index">
<span class="ant-table-header-column">
<div>
<span class="ant-table-column-title">{{ item.title }}</span>
</div>
</span>
</th>
</tr>
</thead>
<tbody class="ant-table-tbody">
<template v-for="(item) in orderList.data">
<tr class="order-empty" :key="`order_${item.order_id}_1`">
<td colspan="16"></td>
</tr>
<tr :key="`order_${item.order_id}_2`">
<td colspan="16">
<span class="mr-20">{{ item.create_time }}</span>
<span class="mr-20">订单号:{{ item.order_no }}</span>
<platform-icon :name="item.platform" :showTips="true" />
</td>
</tr>
<tr
v-for="(goodsItm, goodsIdx) in item.goods"
:key="`orderGoods_${item.order_id}_${goodsIdx}`"
>
<td>
<GoodsItem
:data="{
image: goodsItm.goods_image,
imageAlt: '商品图片',
title: goodsItm.goods_name,
goods_no: goodsItm.goods_no,
goodsProps: goodsItm.goods_props
}"
/>
</td>
<td>
<p>¥{{ goodsItm.goods_price }}</p>
<p>×{{ goodsItm.total_num }}</p>
</td>
<td>
<div class="actions">
<!-- 企油通:发放/加油/退款/发票,与合作商订单页同一套接口 -->
<template v-if="goodsItm.qyt">
<a
v-if="goodsItm.qyt.oil_status_zsy === 3 && goodsItm.qyt.oil_status === 0"
@click="handleShare(goodsItm.qyt)"
>重新发放</a>
<a
v-if="goodsItm.qyt.oil_status_zsy === 2 && goodsItm.qyt.oil_status === 1
&& goodsItm.qyt.refund_status !== 2 && Number(remainAmount(goodsItm.qyt)) > 0"
@click="handlePay(goodsItm.qyt)"
>加油链接</a>
<a
v-if="goodsItm.qyt.oil_status_zsy === 2 && goodsItm.qyt.oil_status === 1"
@click="handleOil(goodsItm.qyt)"
>重推发放结果</a>
<a
v-if="goodsItm.qyt.oil_status_zsy === 2 && goodsItm.qyt.use_status === 1"
@click="handleUse(goodsItm.qyt)"
>重推加油结果</a>
<a v-if="canRefund(goodsItm.qyt)" @click="handleRefund(goodsItm.qyt)">{{ refundLabel(goodsItm.qyt) }}</a>
<a v-if="goodsItm.qyt.use_status === 1" @click="handleInvoice(goodsItm.qyt)">发票</a>
</template>
<span v-else-if="goodsItm.oilCardType === 'zsy_ticket'" class="c-muted-1">未生成发放单</span>
</div>
</td>
<!-- 司机(实名信息随单固化) -->
<td>
<template v-if="goodsItm.qyt">
<p class="mtb-2">{{ goodsItm.qyt.driver_name || '-' }}</p>
<p class="mtb-2 f-13">{{ goodsItm.qyt.mobile }}</p>
<p class="mtb-2 f-13">{{ goodsItm.qyt.id_card_mask || '-' }}</p>
<p class="mtb-2 f-13">车牌:{{ goodsItm.qyt.plate_no || '-' }}</p>
</template>
<span v-else>-</span>
</td>
<!-- 企油通单号 -->
<td>
<template v-if="goodsItm.qyt">
<p class="mtb-2 f-13">批次:{{ goodsItm.qyt.batch_no || '-' }}</p>
<p class="mtb-2 f-13">运单:{{ goodsItm.qyt.waybill_no || '-' }}</p>
</template>
<span v-else>-</span>
</td>
<!-- 加油信息 -->
<td>
<template v-if="goodsItm.qyt && goodsItm.qyt.use_status === 1">
<p class="mtb-2 f-13">已加油:¥{{ goodsItm.qyt.used_amount }}({{ goodsItm.qyt.used_num }} 次)</p>
<p class="mtb-2 f-13">剩余:¥{{ remainAmount(goodsItm.qyt) }}</p>
<p class="mtb-2 f-13">最近:{{ goodsItm.qyt.station_name || '-' }} {{ goodsItm.qyt.oil_name }} {{ goodsItm.qyt.litter }}L</p>
</template>
<span v-else>-</span>
</td>
<template v-if="goodsIdx===0">
<td :rowspan="item.goods.length">
<p>¥{{ item.pay_price }}</p>
<p class="c-muted-1">(含运费:¥{{ item.express_price }})</p>
</td>
<td :rowspan="item.goods.length">
<UserItem :user="item.user" />
</td>
<td :rowspan="item.goods.length">
<a-tag>{{ OrderSourceEnum[item.order_source].name }}</a-tag>
</td>
<td :rowspan="item.goods.length">
<a-tag>{{ PayTypeEnum[item.pay_type].name }}</a-tag>
</td>
<td :rowspan="item.goods.length">
<p>{{ item.spreadOne ? item.spreadOne.name : '' }}</p>
</td>
<td :rowspan="item.goods.length">
<p>{{ goodsItm.province }}</p>
</td>
<td :rowspan="item.goods.length">
<p>{{ OilCardTypeEnum[goodsItm.oilCardType].name }}</p>
</td>
<td :rowspan="item.goods.length">
<p>{{ goodsItm.oilCardNo }}</p>
</td>
<td :rowspan="item.goods.length">
<p>{{ goodsItm.shareNo }}</p>
</td>
<td :rowspan="item.goods.length">
<p class="mtb-2">
<span class="f-13">付款状态:</span>
<a-tag
:color="item.pay_status == PayStatusEnum.SUCCESS.value ? 'green' : ''"
>{{ PayStatusEnum[item.pay_status].name }}</a-tag>
</p>
<p class="mtb-2">
<span class="f-13">分油状态:</span>
<a-tag
:color="goodsItm.oil_status == OilStatusEnum.OIL.value ? 'green' : ''"
>{{ OilStatusEnum[goodsItm.oil_status].name }}</a-tag>
</p>
<p class="mtb-2">
<span class="f-13">使用状态:</span>
<a-tag
:color="goodsItm.use_status == UseStatusEnum.USE.value ? 'green' : ''"
>{{ UseStatusEnum[goodsItm.use_status].name }}</a-tag>
</p>
<template v-if="goodsItm.qyt">
<p class="mtb-2">
<span class="f-13">企油通:</span>
<a-tag :color="qytColor(goodsItm.qyt.oil_status_zsy)">{{ qytText(goodsItm.qyt.oil_status_zsy) }}</a-tag>
</p>
<p v-if="goodsItm.qyt.oil_text" class="mtb-2 f-13 order-remark">{{ goodsItm.qyt.oil_text }}</p>
<p v-if="goodsItm.qyt.refund_status > 0" class="mtb-2">
<span class="f-13">退款:</span>
<a-tag :color="refundColor(goodsItm.qyt.refund_status)">{{ refundText(goodsItm.qyt.refund_status) }}</a-tag>
</p>
</template>
<p
v-if="[OrderStatusEnum.CANCELLED.value,OrderStatusEnum.APPLY_CANCEL.value].includes(item.order_status)"
class="mtb-2"
>
<span class="f-13">订单状态:</span>
<a-tag
:color="renderOrderStatusColor(item.order_status)"
>{{ OrderStatusEnum[item.order_status].name }}</a-tag>
</p>
</td>
</template>
</tr>
</template>
</tbody>
</table>
</div>
<!-- 空状态 -->
<a-empty v-if="!orderList.data.length" :image="simpleImage" />
</div>
</div>
<!-- 分页器 -->
<div v-if="orderList.data.length" class="pagination">
<a-pagination
:current="page"
:pageSize="orderList.per_page"
:total="orderList.total"
@change="onChangePage"
/>
</div>
<DeliveryForm ref="DeliveryForm" @handleSubmit="handleRefresh" />
<CancelForm ref="CancelForm" @handleSubmit="handleRefresh" />
<CancelShareForm ref="CancelShareForm" @handleSubmit="handleRefresh" />
<!-- 企油通相关弹窗直接复用合作商订单页的组件,底层调的是 /partners.order/* -->
<ShareForm ref="ShareForm" @handleSubmit="handleRefresh" />
<PayForm ref="PayForm" @handleSubmit="handleRefresh" />
<OilForm ref="OilForm" @handleSubmit="handleRefresh" />
<UseForm ref="UseForm" @handleSubmit="handleRefresh" />
<RefundForm ref="RefundForm" @handleSubmit="handleRefresh" />
<InvoiceModal ref="InvoiceModal" />
</a-spin>
</a-card>
</template>
<script>
import { Empty } from 'ant-design-vue'
import { inArray, assignment } from '@/utils/util'
import * as Api from '@/api/order'
import * as EventApi from '@/api/order/event'
import PlatformIcon from '@/components/PlatformIcon'
import { GoodsItem, UserItem } from '@/components/Table'
import * as MerchantApi from '@/api/merchant'
import zhCN from 'ant-design-vue/es/locale/zh_CN'
import {
DeliveryStatusEnum,
DeliveryTypeEnum,
OrderSourceEnum,
OrderStatusEnum,
PayStatusEnum,
PayTypeEnum,
ReceiptStatusEnum,
OilCardTypeEnum,
OilStatusEnum,
UseStatusEnum
} from '@/common/enum/order'
import { DeliveryForm, CancelForm, CancelShareForm } from './modules'
// 企油通的发放/加油/退款/发票与合作商订单完全同构,组件和接口都直接复用
import { OilForm, UseForm, ShareForm, PayForm, RefundForm, InvoiceModal } from '@/views/partners/order/modules'
// 表格字段
const columns = [
{
title: '商品信息',
align: 'center',
dataIndex: 'goods',
scopedSlots: { customRender: 'goods' }
},
{
title: '单价/数量',
align: 'center',
scopedSlots: { customRender: 'unit_price' }
},
{
title: '操作',
dataIndex: 'action',
width: '220px',
scopedSlots: { customRender: 'action' }
},
{
title: '司机',
align: 'center',
scopedSlots: { customRender: 'driver' }
},
{
title: '企油通单号',
align: 'center',
scopedSlots: { customRender: 'qyt' }
},
{
title: '加油信息',
align: 'center',
scopedSlots: { customRender: 'consume' }
},
{
title: '实付款',
align: 'center',
dataIndex: 'pay_price',
scopedSlots: { customRender: 'pay_price' }
},
{
title: '买家',
dataIndex: 'user',
scopedSlots: { customRender: 'user' }
},
{
title: '订单来源',
dataIndex: 'order_source',
scopedSlots: { customRender: 'order_source' }
},
{
title: '支付方式',
dataIndex: 'pay_type',
scopedSlots: { customRender: 'pay_type' }
},
{
title: '一级代理商',
dataIndex: 'spreadOne',
scopedSlots: { customRender: 'spreadOne' }
},
{
title: '省份',
align: 'center',
dataIndex: 'province',
scopedSlots: { customRender: 'province' }
},
{
title: '卡券类型',
align: 'center',
dataIndex: 'oilCardType',
scopedSlots: { customRender: 'oilCardType' }
},
{
title: '油卡编号',
dataIndex: 'oilCardNo',
scopedSlots: { customRender: 'oilCardNo' }
},
{
title: '分油记录编号',
dataIndex: 'shareNo',
scopedSlots: { customRender: 'shareNo' }
},
{
title: '交易状态',
dataIndex: 'status',
scopedSlots: { customRender: 'status' }
}
]
// 搜索关键词类型枚举
const SearchTypeEnum = [
{ name: '订单号', value: 10 },
{ name: '会员昵称', value: 20 },
{ name: '会员ID', value: 30 },
{ name: '收货人姓名', value: 40 },
{ name: '收货人电话', value: 50 }
]
export default {
name: 'Index',
components: {
PlatformIcon,
GoodsItem,
UserItem,
DeliveryForm,
CancelForm,
CancelShareForm,
ShareForm,
PayForm,
OilForm,
UseForm,
RefundForm,
InvoiceModal
},
data () {
return {
// 订单类型
dataType: this.getDataType(),
// 当前表单元素
searchForm: this.$form.createForm(this),
// 查询参数
queryParam: {},
// 正在加载
isLoading: false,
// 表格字段
columns,
// 当前页码
page: 1,
// 列表数据
orderList: { data: [], total: 0, per_page: 10 },
// 代理商列表
merchantListData: [],
total_money: 0,
zhCN
}
},
beforeCreate () {
// 批量给当前实例赋值
assignment(this, {
inArray,
DeliveryStatusEnum,
DeliveryTypeEnum,
OrderSourceEnum,
OrderStatusEnum,
PayStatusEnum,
PayTypeEnum,
ReceiptStatusEnum,
SearchTypeEnum,
OilCardTypeEnum,
OilStatusEnum,
UseStatusEnum,
simpleImage: Empty.PRESENTED_IMAGE_SIMPLE
})
},
created () {
// 初始化页面
this.init()
},
watch: {
// 监听路由变化
$route () {
this.init()
}
},
methods: {
// 初始化页面
init () {
this.dataType = this.getDataType()
this.searchForm.resetFields()
this.queryParam = {}
this.handleRefresh(true)
},
// 获取当前标签
getDataType () {
return this.$route.path.split('/')[3]
},
// 获取列表数据
getList () {
const { dataType, queryParam, page } = this
this.isLoading = true
return Api.list({ dataType, ...queryParam, page })
.then(response => {
this.orderList = response.data.list
this.total_money = response.data.total_money
})
.finally(() => {
this.isLoading = false
})
},
// 渲染订单状态标签颜色
renderOrderStatusColor (orderStatus) {
const { OrderStatusEnum } = this
const ColorEnum = {
[OrderStatusEnum.NORMAL.value]: '',
[OrderStatusEnum.CANCELLED.value]: 'red',
[OrderStatusEnum.APPLY_CANCEL.value]: 'red',
[OrderStatusEnum.COMPLETED.value]: 'green'
}
return ColorEnum[orderStatus]
},
/**
* 刷新列表
* @param Boolean bool 强制刷新到第一页
*/
handleRefresh (bool = false) {
bool && (this.page = 1)
this.getMerchantList()
this.getList()
},
// 确认搜索
handleSearch (e) {
e.preventDefault()
this.searchForm.validateFields((error, values) => {
if (!error) {
this.queryParam = { ...this.queryParam, ...values }
this.handleRefresh(true)
}
})
},
// 重置搜索表单
handleReset () {
this.searchForm.resetFields()
},
// 翻页事件
onChangePage (current) {
this.page = current
this.handleRefresh()
},
// 删除记录
handleDelete (item) {
const app = this
const modal = app.$confirm({
title: '您确定要删除该订单记录吗?',
content: '删除后不可恢复,请谨慎操作',
onOk () {
return EventApi.deleted(item.order_id)
.then((result) => {
app.$message.success(result.message, 1.5)
app.handleRefresh()
})
.finally(result => {
modal.destroy()
})
}
})
},
// 订单发货
handleDelivery (record) {
this.$refs.DeliveryForm.show(record)
},
// 审核取消订单
handleCancel (record) {
this.$refs.CancelForm.show(record)
},
// 分油撤销
handleCancelShare (record) {
this.$refs.CancelShareForm.show(record)
},
// ================================================================
// 企油通:发放 / 加油 / 退款 / 发票
// 这些操作的对象是订单商品行上挂的发放单(goodsItm.qyt,即 partners_order 记录),
// 调的接口与合作商订单页是同一套 /partners.order/*
// ================================================================
// 重新发放(仅「发放失败」可用;会重新扣减下单用户余额)
handleShare (record) {
this.$refs.ShareForm.show(record)
},
// 加油链接(企油通 7.15 免登 H5)
handlePay (record) {
this.$refs.PayForm.show(record)
},
// 重推发放结果(小程序单没有下游平台,等于把状态重新同步到用户端)
handleOil (record) {
this.$refs.OilForm.show(record)
},
// 重推加油结果
handleUse (record) {
this.$refs.UseForm.show(record)
},
// 退款
handleRefund (record) {
this.$refs.RefundForm.show(record)
},
// 企业发票(企油通 7.14)
handleInvoice (record) {
this.$refs.InvoiceModal.show(record)
},
// 企油通发放态文案 / 颜色
qytText (v) {
return { 0: '未提交', 1: '发放中', 2: '发放成功', 3: '发放失败' }[v] || '未知'
},
qytColor (v) {
return { 1: 'blue', 2: 'green', 3: 'red' }[v] || ''
},
// 退款状态文案 / 颜色
refundText (v) {
return { 0: '未退款', 1: '退款中', 2: '已退款', 3: '退款失败', 4: '待人工确认' }[v] || '未知'
},
refundColor (v) {
return { 1: 'blue', 2: 'green', 3: 'red', 4: 'orange' }[v] || ''
},
// 发放成功才可能退款;已经有退款记录的单总是可以打开看流水
canRefund (item) {
if (item.oilCardType !== 'zsy_ticket' || item.oil_status_zsy !== 2 || item.oil_status !== 1) {
return false
}
return item.refund_status > 0 || Number(this.remainAmount(item)) > 0
},
// 剩余未加油金额:发放金额 − 已加油 −(已退款时)退款金额
remainAmount (item) {
const refunded = item.refund_status === 2 ? Number(item.refund_amount || 0) : 0
const remain = Number(item.total_price || 0) - Number(item.used_amount || 0) - refunded
return Math.max(0, remain).toFixed(2)
},
refundLabel (item) {
return { 2: '退款记录', 4: '确认退款' }[item.refund_status] || '退款'
},
formatTime (timestamp) {
const date = new Date(timestamp)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0') // 月份是从0开始的
const day = String(date.getDate()).padStart(2, '0')
const hour = String(date.getHours()).padStart(2, '0')
const minute = String(date.getMinutes()).padStart(2, '0')
const second = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hour}:${minute}:${second}`
},
/**
* 获取代理商列表
*/
getMerchantList () {
this.isLoading = true
MerchantApi.all()
.then(result => {
this.merchantListData = result.data.list
})
.finally(() => {
this.isLoading = false
})
}
}
}
</script>
<style lang="less" scoped>
// 分页器
.pagination {
margin-top: 16px;
.ant-pagination {
float: right;
}
}
.ant-table {
table {
border: none;
border-collapse: collapse;
}
.ant-table-thead > tr {
border: 1px solid #e8e8e8;
}
tr.order-empty {
height: 15px;
border: 1px solid #fff;
td {
padding: 0;
border-right: none;
border-left: none;
background: none !important;
}
}
}
.ant-table-thead > tr > th {
border-right: none;
border-bottom: none;
padding: 12px 12px;
font-weight: bold;
}
.ant-table-tbody > tr > td {
border-right: 1px solid #e8e8e8;
border-left: 1px solid #e8e8e8;
padding: 12px 12px;
// text-align: center;
}
.form-total{
color: #1890ff;
margin-right: 10px;
font-size: 20px;
font-weight: 500;
}
// 操作栏:按钮较多会换行,横向纵向都留出间距(覆盖全局 .actions>a 的 8px 右边距)
.actions {
display: flex;
flex-wrap: wrap;
gap: 8px 16px;
& > a {
margin-right: 0 !important;
white-space: nowrap;
}
}
</style>