feat: 移植商户端订单管理到平台端 & 新增订单打印功能
1. 将商户端订单管理功能完整移植到平台端管理后台,包括: - 商户订单列表、退款单、预约管理(服务看板+工单管理) - 菜单名称加"商户"前缀,区别于平台端原有订单管理 - 不影响平台端原有订单管理功能 2. 新增订单打印功能: - 前端:独立打印页面(无layout),支持浏览器打印 - 后端:新增打印专用API,使用eb_sync_order_detail_staging表的product_name和info字段 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
383
mer_plat_admin/src/api/merchantOrder.js
Normal file
383
mer_plat_admin/src/api/merchantOrder.js
Normal file
@@ -0,0 +1,383 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 商户订单 列表
|
||||
* @param params
|
||||
*/
|
||||
export function merchantOrderListApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/order/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 列表 获取各状态数量
|
||||
* @param params
|
||||
*/
|
||||
export function merchantOrderStatusNumApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/order/status/num',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 删除
|
||||
* @param orderNo
|
||||
*/
|
||||
export function merchantOrderDeleteApi(orderNo) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/delete/${orderNo}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 记录
|
||||
* @param params
|
||||
*/
|
||||
export function merchantOrderLogApi(params) {
|
||||
return request({
|
||||
url: '/admin/store/order/status/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 详情
|
||||
* @param orderNo
|
||||
*/
|
||||
export function merchantOrderDetailApi(orderNo) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/info/${orderNo}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 备注
|
||||
* @param data
|
||||
*/
|
||||
export function merchantOrderMarkApi(data) {
|
||||
return request({
|
||||
url: '/admin/merchant/order/mark',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 发货
|
||||
* @param data
|
||||
*/
|
||||
export function merchantOrderSendApi(data) {
|
||||
return request({
|
||||
url: '/admin/merchant/order/send',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 打印小票
|
||||
* @param orderno
|
||||
*/
|
||||
export function merchantOrderPrintReceiptApi(orderno) {
|
||||
return request({
|
||||
url: '/admin/merchant/order/printreceipt/' + orderno,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 拒绝退款
|
||||
* @param params
|
||||
*/
|
||||
export function merchantOrderRefuseApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/refund/order/refund/refuse',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 立即退款
|
||||
* @param params
|
||||
*/
|
||||
export function merchantOrderRefundApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/refund/order/refund',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 统计 头部数据
|
||||
*/
|
||||
export function merchantOrderStatisticsApi() {
|
||||
return request({
|
||||
url: `/admin/store/order/statistics`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 核销订单 月列表数据
|
||||
*/
|
||||
export function merchantStatisticsDataApi(params) {
|
||||
return request({
|
||||
url: `/admin/store/order/statisticsData`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 一键改价
|
||||
*/
|
||||
export function merchantUpdatePriceApi(data) {
|
||||
return request({
|
||||
url: `admin/store/order/update/price`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 订单统计详情
|
||||
*/
|
||||
export function merchantOrderTimeApi(params) {
|
||||
return request({
|
||||
url: `/admin/store/order/time`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 面单默认配置信息
|
||||
*/
|
||||
export function merchantSheetInfoApi() {
|
||||
return request({
|
||||
url: `/admin/store/order/sheet/info`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户订单 物流详情
|
||||
* @param invoiceId
|
||||
*/
|
||||
export function merchantGetLogisticsInfoApi(invoiceId) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/get/${invoiceId}/logistics/info`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频号物流公司
|
||||
*/
|
||||
export function merchantCompanyGetListApi() {
|
||||
return request({
|
||||
url: `/admin/pay/component/delivery/company/get/list`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频号发货
|
||||
*/
|
||||
export function merchantVideoSendApi(data) {
|
||||
return request({
|
||||
url: `/admin/store/order/video/send`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 打印小票
|
||||
*/
|
||||
export function merchantOrderPrint(id) {
|
||||
return request({
|
||||
url: `/admin/yly/print/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 退款列表
|
||||
*/
|
||||
export function merchantRefundListApi(params) {
|
||||
return request({
|
||||
url: `/admin/merchant/refund/order/list`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 备注退款订单
|
||||
*/
|
||||
export function merchantRefundMarkApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/refund/order/mark`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 获取退款订单各状态数量
|
||||
*/
|
||||
export function merchantRefundStatusNumApi(params) {
|
||||
return request({
|
||||
url: `/admin/merchant/refund/order/status/num`,
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 核销订单
|
||||
* @param data
|
||||
*/
|
||||
export function merchantWriteUpdateApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/verification`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 订单细节详情列表(发货使用)
|
||||
* @param orderNo 订单号
|
||||
*/
|
||||
export function merchantOrderProDetailApi(orderNo) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/${orderNo}/detail/list`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 获取订单发货单列表
|
||||
* @param orderNo 订单号
|
||||
*/
|
||||
export function merchantOrderInvoiceListApi(orderNo) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/${orderNo}/invoice/list`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 退款订单详情
|
||||
* @param refundOrderNo 订单号
|
||||
*/
|
||||
export function merchantRefundOrderDetailApi(refundOrderNo) {
|
||||
return request({
|
||||
url: `/admin/merchant/refund/order/detail/${refundOrderNo}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 退款订单导出
|
||||
* @param params 对象
|
||||
*/
|
||||
export function merchantOrderExcelApi(params) {
|
||||
return request({
|
||||
url: `/admin/merchant/export/order/excel`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 退款单审核
|
||||
* @param data 对象
|
||||
*/
|
||||
export function merchantOrderAuditApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/refund/order/audit`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 退款单收到退货
|
||||
* @param refundOrderNo 退款单号
|
||||
*/
|
||||
export function merchantRefundOrderReceivingApi(refundOrderNo) {
|
||||
return request({
|
||||
url: `/admin/merchant/refund/order/receiving/${refundOrderNo}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 退款单拒绝收货
|
||||
* @param data
|
||||
*/
|
||||
export function merchantRefundOrderReceivingRejectApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/refund/order/receiving/reject`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 直接退款
|
||||
* @param data
|
||||
*/
|
||||
export function merchantOrderDirectRefundApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/direct/refund`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户 修改发货单配送信息
|
||||
* @param data
|
||||
*/
|
||||
export function merchantOrderInvoiceUpdateApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/invoice/update`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单打印详情(使用staging表数据)
|
||||
* @param orderNo 订单号
|
||||
*/
|
||||
export function merchantOrderPrintDetailApi(orderNo) {
|
||||
return request({
|
||||
url: `/admin/merchant/order/print/detail/${orderNo}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
174
mer_plat_admin/src/api/merchantReservation.js
Normal file
174
mer_plat_admin/src/api/merchantReservation.js
Normal file
@@ -0,0 +1,174 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 编辑到店服务预约信息
|
||||
* @param data
|
||||
*/
|
||||
export function merchantReservationStoreEditApi(data) {
|
||||
return request({
|
||||
url: '/admin/merchant/reservation/config/store/edit',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 到店服务详情
|
||||
*/
|
||||
export function merchantReservationStoreInfoApi() {
|
||||
return request({
|
||||
url: '/admin/merchant/reservation/config/store/info',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上门服务详情
|
||||
*/
|
||||
export function merchantReservationHomeInfoApi() {
|
||||
return request({
|
||||
url: '/admin/merchant/reservation/config/home/info',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑上门服务详情
|
||||
* @param data
|
||||
*/
|
||||
export function merchantReservationHomeEditApi(data) {
|
||||
return request({
|
||||
url: '/admin/merchant/reservation/config/home/edit',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 预约工单甘特图
|
||||
* @param params
|
||||
*/
|
||||
export function merchantWorkOrderOverViewApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/work/order/overView',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单甘特图各状态数量
|
||||
* @param params
|
||||
*/
|
||||
export function merchantWorkOrderOverViewNumApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/work/order/overView/num',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 预约工单分页列表
|
||||
* @param params
|
||||
*/
|
||||
export function merchantWorkOrderListApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/work/order/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工单各状态数量
|
||||
* @param params
|
||||
*/
|
||||
export function merchantWorkOrderStatusNumApi(params) {
|
||||
return request({
|
||||
url: '/admin/merchant/work/order/status/num',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单详情
|
||||
* @param workOrderNo
|
||||
*/
|
||||
export function merchantWorkOrderDetailApi(workOrderNo) {
|
||||
return request({
|
||||
url: `/admin/merchant/work/order/detail/${workOrderNo}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户派单
|
||||
* @param data
|
||||
*/
|
||||
export function merchantWorkOrderAssignApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/work/order/assign`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户改派
|
||||
* @param data
|
||||
*/
|
||||
export function merchantWorkOrderReassignApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/work/order/reassign`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户改约
|
||||
* @param data
|
||||
*/
|
||||
export function merchantWorkOrderUpdateAgreementApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/work/order/updateAgreement`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户备注工单
|
||||
* @param data
|
||||
*/
|
||||
export function merchantWorkOrderMarkApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/work/order/mark`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 商户强制完成工单
|
||||
* @param data
|
||||
*/
|
||||
export function merchantWorkOrderForceFinishApi(data) {
|
||||
return request({
|
||||
url: `/admin/merchant/work/order/forceFinish`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import operationRouter from './modules/operation';
|
||||
import merchant from './modules/merchant';
|
||||
import pagediy from '@/router/modules/pagediy';
|
||||
import areaRouter from './modules/area';
|
||||
import merchantOrderRouter from './modules/merchantOrder';
|
||||
/**
|
||||
* Note: sub-menu only appear when route children.length >= 1
|
||||
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
|
||||
@@ -77,6 +78,8 @@ export const constantRoutes = [
|
||||
pagediy,
|
||||
// 圈层管理
|
||||
areaRouter,
|
||||
// 商户订单管理(从商户端移植)
|
||||
merchantOrderRouter,
|
||||
{
|
||||
path: '/404',
|
||||
component: () => import('@/views/error-page/404'),
|
||||
@@ -176,6 +179,13 @@ export const constantRoutes = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/merchantOrder/print/:orderNo',
|
||||
component: () => import('@/views/merchantOrder/orderPrint'),
|
||||
name: 'MerchantOrderPrint',
|
||||
hidden: true,
|
||||
meta: { title: '订单打印' },
|
||||
},
|
||||
{
|
||||
path: '/setting/uploadPicture',
|
||||
component: () => import('@/components/base/uploadPicture.vue'),
|
||||
|
||||
59
mer_plat_admin/src/router/modules/merchantOrder.js
Normal file
59
mer_plat_admin/src/router/modules/merchantOrder.js
Normal file
@@ -0,0 +1,59 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import Layout from '@/layout';
|
||||
|
||||
const merchantOrderRouter = {
|
||||
path: '/merchantOrder',
|
||||
component: Layout,
|
||||
redirect: '/merchantOrder/list',
|
||||
name: 'MerchantOrder',
|
||||
alwaysShow: true,
|
||||
meta: {
|
||||
title: '商户订单',
|
||||
icon: 'clipboard',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
component: () => import('@/views/merchantOrder/index'),
|
||||
name: 'MerchantOrderIndex',
|
||||
meta: { title: '商户订单' },
|
||||
},
|
||||
{
|
||||
path: 'refund',
|
||||
component: () => import('@/views/merchantOrder/refund/index'),
|
||||
name: 'MerchantRefund',
|
||||
meta: { title: '商户退款订单' },
|
||||
},
|
||||
{
|
||||
path: 'reservation',
|
||||
component: () => import('@/views/merchantOrder/reservation/index'),
|
||||
name: 'MerchantOrderReservation',
|
||||
meta: { title: '商户预约', icon: '' },
|
||||
children: [
|
||||
{
|
||||
path: 'service',
|
||||
component: () => import('@/views/merchantOrder/reservation/service'),
|
||||
name: 'MerchantService',
|
||||
meta: { title: '商户预约看板', icon: '' },
|
||||
},
|
||||
{
|
||||
path: 'workOrder',
|
||||
component: () => import('@/views/merchantOrder/reservation/workOrder'),
|
||||
name: 'MerchantWorkOrder',
|
||||
meta: { title: '商户工单管理', icon: '' },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default merchantOrderRouter;
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert title="同意退款后,用户会根据下方地址将商品退回!" type="warning" show-icon class="mb20"> </el-alert>
|
||||
<div>
|
||||
<div class="detail-term mb20">
|
||||
<span class="detail-infoTitle">退货方式:</span
|
||||
><span class="detail-info">{{ refundInfo.afterSalesType === 1 ? '仅退款' : '退货退款' }}</span>
|
||||
</div>
|
||||
<div class="detail-term acea-row">
|
||||
<span class="detail-infoTitle">退回地址:</span>
|
||||
<div v-if="!addressList.length">请先去设置-商家地址管理中添加售后地址</div>
|
||||
<div v-else v-loading="listLoading" class="h-82%">
|
||||
<div v-for="item in addressList" :key="item.id">
|
||||
<div v-if="item.isShow" class="">
|
||||
<el-card class="box-card" shadow="never" :bordered="false">
|
||||
<div class="acea-row row-between">
|
||||
<div class="text-14 text-666 address">
|
||||
<div class="mb10">
|
||||
{{ item.province }}{{ item.city }}{{ item.district }}{{ item.street }}{{ item.detail }}
|
||||
<span v-show="item.isDefault" style="color: var(--prev-color-primary)" class="ml10">[默认退货]</span>
|
||||
</div>
|
||||
<div class="">
|
||||
<span class="w-70px inline-block mr15">{{ item.receiverName }}</span
|
||||
>{{ item.receiverPhone }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-radio-group v-model="defaultId" @change="handleChecked">
|
||||
<el-radio :label="item.id" size="large">
|
||||
<span class="text-14px text-#666">选择地址</span>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-footer-inner">
|
||||
<el-button @click="handleCancel">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="loading">确 定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { merchantAddressListApi } from '@/api/systemSetting';
|
||||
import { merchantOrderAuditApi as orderAuditApi, merchantOrderRefuseApi as orderRefuseApi } from '@/api/merchantOrder';
|
||||
|
||||
export default {
|
||||
name: 'agreeToReturn',
|
||||
props: {
|
||||
refundInfo: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
listLoading: false,
|
||||
addressList: [],
|
||||
defaultId: 0,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (localStorage.getItem('merchantAddressList')) {
|
||||
this.addressList = JSON.parse(localStorage.getItem('merchantAddressList'));
|
||||
let data = this.addressList.find((item) => item.isDefault);
|
||||
if (data) {
|
||||
this.defaultId = data.id;
|
||||
}
|
||||
} else {
|
||||
this.getList();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//确定提交
|
||||
handleSubmit() {
|
||||
this.submit();
|
||||
},
|
||||
// 提交方法
|
||||
submit() {
|
||||
this.loading = true;
|
||||
orderAuditApi({
|
||||
auditType: 'success',
|
||||
refundOrderNo: this.refundInfo.refundOrderNo,
|
||||
merAddressId: this.defaultId,
|
||||
})
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
this.$message.success('审核成功');
|
||||
this.$emit('onHandleSuccess');
|
||||
})
|
||||
.catch((res) => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
handleCancel() {
|
||||
this.$emit('onHandleCancel');
|
||||
},
|
||||
// 列表
|
||||
getList() {
|
||||
this.listLoading = true;
|
||||
merchantAddressListApi()
|
||||
.then((res) => {
|
||||
this.addressList = res;
|
||||
if (this.addressList.length) {
|
||||
localStorage.setItem('merchantAddressList', JSON.stringify(res));
|
||||
let data = this.addressList.find((item) => item.isDefault);
|
||||
this.defaultId = data.id;
|
||||
}
|
||||
this.listLoading = false;
|
||||
})
|
||||
.catch((res) => {
|
||||
this.listLoading = false;
|
||||
});
|
||||
},
|
||||
handleClose() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
//选中地址
|
||||
handleChecked() {},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
padding-top: 20px;
|
||||
}
|
||||
.box-card {
|
||||
width: 675px;
|
||||
}
|
||||
.address {
|
||||
width: 450px;
|
||||
}
|
||||
::v-deep .el-card__body {
|
||||
padding: 0 15px 15px 0 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,346 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
title="直接退款"
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
width="1100px"
|
||||
@close="handlerClose"
|
||||
class="dialog-bottom"
|
||||
>
|
||||
<el-form ref="pram" size="small" :model="pram" label-width="95px" @submit.native.prevent>
|
||||
<el-form-item label="退款类型:" prop="returnType">
|
||||
<el-radio-group v-model="pram.returnType" :disabled="type == 2 || secondType == OrderSecondTypeEnum.PunchCard">
|
||||
<el-radio :label="1">整单退款</el-radio>
|
||||
<el-radio :label="2">分单退款</el-radio>
|
||||
</el-radio-group>
|
||||
<div v-show="pram.returnType === 2" class="from-tips">可选择下方表格中的商品进行退款,退款后不能撤回!</div>
|
||||
</el-form-item>
|
||||
<div v-if="pram.returnType === 2 && workOrderList.length" class="tableLeft mb20 font12">
|
||||
<div class="mb10">预约类型:{{ workOrderList[0].serviceType === 1 ? '上门服务' : '到店服务' }}</div>
|
||||
<div>
|
||||
预约信息:<span class="priceBox">{{ workOrderList[0].userName }} {{ workOrderList[0].userPhone }}</span>
|
||||
<span class="ml10">{{ workOrderList[0].userAddress }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
v-if="pram.returnType === 2"
|
||||
v-loading="loading"
|
||||
class="mb15 tableSelection tableLeft"
|
||||
style="width: 91%"
|
||||
ref="multipleSelection"
|
||||
:data="productList"
|
||||
border
|
||||
tooltip-effect="dark"
|
||||
size="mini"
|
||||
:row-key="
|
||||
(row) => {
|
||||
return row.id;
|
||||
}
|
||||
"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="shouldShowColumn('workOrderList')"
|
||||
type="selection"
|
||||
:reserve-selection="true"
|
||||
min-width="50"
|
||||
/>
|
||||
<el-table-column label="商品信息" width="200">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row" style="align-items: center">
|
||||
<div class="demo-image__preview mr5 line-heightOne refundImg">
|
||||
<el-image :src="scope.row.image" :preview-src-list="[scope.row.image]" />
|
||||
<span class="priceBox product-info-text" style="width: 120px">{{ scope.row.productName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格" min-width="60">
|
||||
<template slot-scope="scope">
|
||||
<span class="priceBox">{{ scope.row.sku }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总数(件)" min-width="80">
|
||||
<template slot-scope="scope">
|
||||
<span class="priceBox">购买数量:{{ scope.row.payNum }}</span>
|
||||
(
|
||||
<span class="priceBox">已发货{{ scope.row.deliveryNum }}</span
|
||||
>)
|
||||
|
||||
<div class="priceBox textE93323 mt3">
|
||||
可退款{{ scope.row.payNum - scope.row.refundNum - scope.row.applyRefundNum }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="可退总额(元)" min-width="60">
|
||||
<template slot-scope="scope">
|
||||
<span class="priceBox">{{ scope.row.payPrice - scope.row.refundPrice }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="shouldShowColumn('workOrderList')" label="退款数量(件)" min-width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-model.trim="scope.row['num']"
|
||||
:min="1"
|
||||
:max="scope.row.payNum - scope.row.refundNum - scope.row.applyRefundNum"
|
||||
class="priceBox"
|
||||
:step="1"
|
||||
@change="limitCount(scope.row, scope.$index)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 预约商品选择工单-->
|
||||
<el-table
|
||||
border
|
||||
v-if="secondType === OrderSecondTypeEnum.Reservation && pram.returnType === 2 && workOrderList.length"
|
||||
v-loading="loading"
|
||||
class="mb15 tableSelection tableLeft"
|
||||
style="width: 91%"
|
||||
ref="multipleSelection"
|
||||
:data="workOrderList"
|
||||
tooltip-effect="dark"
|
||||
size="mini"
|
||||
:row-key="
|
||||
(row) => {
|
||||
return row.id;
|
||||
}
|
||||
"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" :reserve-selection="true" min-width="50" />
|
||||
<el-table-column label="工单号" prop="workOrderNo" min-width="200" />
|
||||
<el-table-column label="表单信息" min-width="250">
|
||||
<template slot-scope="scope">
|
||||
<ul v-if="scope.row.reservationFormData">
|
||||
<li class="item" v-for="(item, index) in JSON.parse(scope.row.reservationFormData)" :key="index">
|
||||
<system-from-info :item="item"></system-from-info>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-else>--</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 次卡商品预计退款金额 -->
|
||||
<template v-if="secondType === OrderSecondTypeEnum.PunchCard && productList[0]">
|
||||
<el-form-item label="剩余核销次数:">
|
||||
<div>{{ productList[0].verifyRemainingTimes }}/{{ productList[0].verifyTotalTimes }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="预计退款金额:">
|
||||
<div>{{ productList[0].verifyRefundPrice }} 元</div>
|
||||
<div class="from-tips">具体退款金额以实际为准</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<!-- 非次卡商品预计退款金额 -->
|
||||
<el-form-item v-else label="预计退款金额:" prop="resource">
|
||||
<div>{{ refundPrice.toFixed(2) }} 元</div>
|
||||
<div class="from-tips">具体退款金额以实际为准</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="acea-row row-right dialog-footer-inner dialog-btn-top">
|
||||
<el-button size="small" @click="handlerClose">取 消</el-button>
|
||||
<el-button size="small" type="primary" @click="handlerSubmit">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { merchantOrderDirectRefundApi as orderDirectRefundApi, merchantOrderProDetailApi as orderProDetailApi, merchantWriteUpdateApi as writeUpdateApi } from '@/api/merchantOrder';
|
||||
import { OrderSecondTypeEnum } from '@/enums/productEnums';
|
||||
import systemFromInfo from '@/views/merchantOrder/components/systemFromInfo';
|
||||
|
||||
export default {
|
||||
name: 'directRefund',
|
||||
components: {
|
||||
systemFromInfo,
|
||||
},
|
||||
props: {
|
||||
dialogVisibleDirectRefund: {
|
||||
type: Boolean,
|
||||
default: function () {
|
||||
return false;
|
||||
},
|
||||
},
|
||||
orderNo: {
|
||||
type: String,
|
||||
default: function () {
|
||||
return '';
|
||||
},
|
||||
},
|
||||
type: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
secondType: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
OrderSecondTypeEnum,
|
||||
pram: {
|
||||
returnType: 1,
|
||||
orderNo: '',
|
||||
detailList: [],
|
||||
},
|
||||
dialogVisible: this.dialogVisibleDirectRefund,
|
||||
productList: [],
|
||||
multipleSelection: [],
|
||||
refundPrice: 0, //预计退款金额
|
||||
loading: false,
|
||||
workOrderList: [], // 工单列表
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
dialogVisibleDirectRefund: {
|
||||
handler: function (val) {
|
||||
this.dialogVisible = val;
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
'pram.returnType': {
|
||||
handler: function (val) {
|
||||
if (this.multipleSelection.length === 0 && val === 2) {
|
||||
this.refundPrice = 0;
|
||||
} else {
|
||||
this.multipleSelection = [];
|
||||
this.getRefundPrice(this.productList);
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.orderProDetail();
|
||||
},
|
||||
methods: {
|
||||
shouldShowColumn(columnName) {
|
||||
// 检查至少有一行的该列值存在(非null、非undefined、非空字符串等)
|
||||
return this.productList.some((row) => {
|
||||
const value = row[columnName];
|
||||
return !value;
|
||||
});
|
||||
},
|
||||
//决定这一行的 CheckBox 是否可以勾选
|
||||
selectable(row, index) {
|
||||
if (row.deliveryNum === row.payNum) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
limitCount(row, i) {
|
||||
if (row.num > row.payNum) row.num = row.payNum;
|
||||
this.getRefundPrice(this.multipleSelection);
|
||||
},
|
||||
// 商品信息
|
||||
orderProDetail() {
|
||||
this.loading = true;
|
||||
orderProDetailApi(this.orderNo)
|
||||
.then(async (res) => {
|
||||
this.productList = res;
|
||||
this.productList.map((item) => this.$set(item, 'num', 1));
|
||||
this.workOrderList = res[0].workOrderList || [];
|
||||
this.getRefundPrice(this.productList);
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 获取一件的价格
|
||||
getOnePrice(currentValue) {
|
||||
return this.$selfUtil.Division(
|
||||
currentValue.payPrice - currentValue.refundPrice,
|
||||
currentValue.payNum - currentValue.refundNum - currentValue.applyRefundNum,
|
||||
);
|
||||
},
|
||||
//预计退款金额
|
||||
getRefundPrice(multipleSelection) {
|
||||
// 预计退款金额 = (可退总额/可退数量 * 退款数量)表格选中之和
|
||||
// 可退总额 = 购买金额-已退款金额,payPrice - refundPrice
|
||||
// 可退数量 = 购买数量-已退款数量-申请退款数量,payNum-refundNum-applyRefundNum
|
||||
// 可退总额/可退数量 onePrice = this.$selfUtil.Division(payPrice , refundPrice); //除法
|
||||
this.refundPrice = multipleSelection.reduce((accumulator, currentValue) => {
|
||||
let onePrice = this.getOnePrice(currentValue);
|
||||
//可退数量
|
||||
let refundNum =
|
||||
this.pram.returnType === 1
|
||||
? currentValue.payNum - currentValue.refundNum - currentValue.applyRefundNum
|
||||
: currentValue.num;
|
||||
return accumulator + onePrice * refundNum;
|
||||
}, 0);
|
||||
},
|
||||
// 选择商品
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
let data = [];
|
||||
this.multipleSelection.map((item) => {
|
||||
data.push({
|
||||
id: item.id,
|
||||
num: this.secondType === OrderSecondTypeEnum.Reservation ? 1 : item.num,
|
||||
});
|
||||
});
|
||||
if (this.secondType === OrderSecondTypeEnum.Reservation) {
|
||||
this.getReservationRefundPrice(this.multipleSelection);
|
||||
} else {
|
||||
this.getRefundPrice(this.multipleSelection);
|
||||
}
|
||||
},
|
||||
// 计算预约退款价格
|
||||
getReservationRefundPrice(multipleSelection) {
|
||||
let onePrice = this.getOnePrice(this.productList[0]);
|
||||
this.refundPrice = onePrice * multipleSelection.length;
|
||||
},
|
||||
//提交
|
||||
handlerSubmit() {
|
||||
if (this.pram.returnType === 2 && this.multipleSelection.length === 0)
|
||||
return this.$message.warning('分单退款请选择商品!');
|
||||
this.pram.orderNo = this.orderNo;
|
||||
if (this.secondType !== OrderSecondTypeEnum.Reservation) {
|
||||
this.multipleSelection.map((item, index) => {
|
||||
this.pram.detailList.push({ num: item.num, orderDetailId: item.id });
|
||||
});
|
||||
} else {
|
||||
const workOrderIdList = this.multipleSelection.map((item) => item.id);
|
||||
this.pram.detailList.push({
|
||||
num: this.multipleSelection.length,
|
||||
orderDetailId: this.productList[0].id,
|
||||
workOrderIdList: workOrderIdList,
|
||||
});
|
||||
}
|
||||
orderDirectRefundApi(this.pram).then(() => {
|
||||
this.$message.success('操作成功');
|
||||
this.$emit('handlerSuccessSubmit');
|
||||
});
|
||||
},
|
||||
//取消
|
||||
handlerClose() {
|
||||
this.$emit('handlerSuccessClose');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
::v-deep .el-input-number--medium {
|
||||
width: 170px !important;
|
||||
}
|
||||
.from-tips {
|
||||
margin-top: 5px !important;
|
||||
}
|
||||
.tableLeft {
|
||||
margin-left: 95px;
|
||||
}
|
||||
.refundImg {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.product-info-text {
|
||||
display: block;
|
||||
white-space: nowrap; /* 确保文本在一行内显示 */
|
||||
overflow: hidden; /* 超出容器部分隐藏 */
|
||||
text-overflow: ellipsis; /* 使用省略号表示被截断的文本 */
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="修改配送信息"
|
||||
:visible.sync="visible"
|
||||
width="540px"
|
||||
:before-close="handleClose"
|
||||
class="dialog-bottom"
|
||||
>
|
||||
<el-form ref="formItem" :model="formItem" label-width="95px" @submit.native.prevent :rules="rules">
|
||||
<SendFrom :formItem="formItem" :isShowBtn="false"></SendFrom>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" @click="handleClose">取消</el-button>
|
||||
<el-button
|
||||
:loading="loadingBtn"
|
||||
size="smalll"
|
||||
type="primary"
|
||||
@click="handleSubmit('formItem')"
|
||||
v-hasPermi="['merchant:order:invoice:update']"
|
||||
>提交</el-button
|
||||
>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useLogistics } from '@/hooks/use-order';
|
||||
import { Debounce } from '@/utils/validate';
|
||||
import { merchantOrderInvoiceUpdateApi as orderInvoiceUpdateApi } from '@/api/merchantOrder';
|
||||
import { postRules } from '@/views/merchantOrder/default';
|
||||
import SendFrom from './sendFrom';
|
||||
|
||||
export default {
|
||||
name: 'editDelivery',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
editData: {
|
||||
type: Object,
|
||||
required: null,
|
||||
},
|
||||
},
|
||||
components: { SendFrom },
|
||||
data() {
|
||||
return {
|
||||
formItem: {
|
||||
carrierPhone: '',
|
||||
deliveryCarrier: '',
|
||||
deliveryMark: '',
|
||||
expressCode: '',
|
||||
expressNumber: '',
|
||||
id: 0,
|
||||
},
|
||||
rules: postRules,
|
||||
logistics: [],
|
||||
loadingBtn: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
visible: {
|
||||
handler: function (val) {
|
||||
if (val) this.getLogistics();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
editData: {
|
||||
handler: function (val) {
|
||||
this.formItem = {
|
||||
...this.editData,
|
||||
expressNumber: this.editData.expressNumber ? this.editData.expressNumber : this.editData.trackingNumber,
|
||||
};
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleClose() {
|
||||
this.$emit('onCloseVisible');
|
||||
this.formItem = {
|
||||
...this.editData,
|
||||
expressNumber: this.editData.expressNumber ? this.editData.expressNumber : this.editData.trackingNumber,
|
||||
};
|
||||
this.$refs.formItem.resetFields();
|
||||
},
|
||||
handleSubmitSuccess() {
|
||||
this.$emit('onSubmitSuccess');
|
||||
this.loadingBtn = false;
|
||||
this.$refs.formItem.resetFields();
|
||||
},
|
||||
//物流公司
|
||||
async getLogistics() {
|
||||
const params = {
|
||||
keywords: '',
|
||||
page: 1,
|
||||
limit: 50,
|
||||
openStatus: true,
|
||||
};
|
||||
this.logistics = await useLogistics(params);
|
||||
},
|
||||
//提交
|
||||
handleSubmit: Debounce(function (name) {
|
||||
this.$refs[name].validate((valid) => {
|
||||
if (valid) {
|
||||
const { carrierPhone, deliveryCarrier, deliveryMark, expressCode, expressNumber, id } = this.formItem;
|
||||
let data = {
|
||||
carrierPhone: carrierPhone,
|
||||
deliveryCarrier: deliveryCarrier,
|
||||
deliveryMark: deliveryMark,
|
||||
expressCode: expressCode,
|
||||
expressNumber: expressNumber,
|
||||
id: id,
|
||||
toAddr: this.formItem.toAddr,
|
||||
toTel: this.formItem.toTel,
|
||||
toName: this.formItem.toName,
|
||||
expressRecordType: this.formItem.expressRecordType,
|
||||
};
|
||||
if (this.formItem.expressRecordType == '2') {
|
||||
if (!this.formItem.toAddr) {
|
||||
this.$message.warning('请填写寄件人地址');
|
||||
return;
|
||||
}
|
||||
if (!this.formItem.toTel) {
|
||||
this.$message.warning('请填写寄件人电话');
|
||||
return;
|
||||
}
|
||||
if (!this.formItem.toName) {
|
||||
this.$message.warning('请填写寄件人姓名');
|
||||
return;
|
||||
}
|
||||
if (!this.formItem.expressTempId) {
|
||||
this.$message.warning('请选择电子面单');
|
||||
return;
|
||||
}
|
||||
}
|
||||
orderInvoiceUpdateApi(data)
|
||||
.then((res) => {
|
||||
this.$message.success('修改发货单配送信息成功');
|
||||
this.handleSubmitSuccess();
|
||||
})
|
||||
.catch((res) => {
|
||||
this.loadingBtn = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,741 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer :visible.sync="dialogVisible" :direction="direction" size="1000px" :before-close="handleClose">
|
||||
<div slot="title">
|
||||
<div class="detailHead">
|
||||
<div class="full">
|
||||
<div class="order_icon"><span class="iconfont icon-dingdan"></span></div>
|
||||
<div class="text">
|
||||
<div class="acea-row">
|
||||
<div class="title">{{ orderDatalist.type | orderTypeFilter }}</div>
|
||||
<div class="ml5">一</div>
|
||||
<div class="title ml5">
|
||||
<div v-if="orderDatalist.secondType === 5 || orderDatalist.secondType === 6" class="value">
|
||||
自动发货
|
||||
</div>
|
||||
<div v-else-if="orderDatalist.secondType === 2" class="value">虚拟发货</div>
|
||||
<div v-else class="value">{{ orderDatalist.shippingType | shippingTypeFilter }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="mr20">订单号:{{ orderDatalist.orderNo }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="title">订单状态</div>
|
||||
<div class="color-warning">
|
||||
<span v-if="orderDatalist.refundStatus === 3">已退款</span>
|
||||
<!-- 次卡商品部分使用状态 -->
|
||||
<span
|
||||
v-else-if="
|
||||
orderDatalist.secondType == OrderSecondTypeEnum.PunchCard &&
|
||||
orderDatalist.status == 3 &&
|
||||
orderDatalist.orderDetailList[0].verifyRemainingTimes !=
|
||||
orderDatalist.orderDetailList[0].verifyTotalTimes
|
||||
"
|
||||
>部分使用</span
|
||||
>
|
||||
<span v-else>{{ orderDatalist.status | orderStatusFilter }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="title">实际支付</div>
|
||||
<div>¥ {{ orderDatalist.payPrice || '0.0' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="title">支付方式</div>
|
||||
<div>{{ orderDatalist.payType | payTypeFilter }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="title">支付时间</div>
|
||||
<div>{{ orderDatalist.payTime | filterEmpty }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="orderDatalist" v-loading="loading">
|
||||
<el-tabs type="border-card" v-model="activeName">
|
||||
<el-tab-pane label="订单信息" name="detail">
|
||||
<div class="detailSection" style="border: none">
|
||||
<div class="title">用户信息</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="lang">用户名称:</div>
|
||||
<div class="value">{{ orderDatalist.nickname }} | {{ orderDatalist.uid }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">用户电话:</div>
|
||||
<div class="value">{{ orderDatalist.phone }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-show="orderDatalist.shippingType < 2 && orderDatalist.secondType !== 2" class="detailSection">
|
||||
<div class="title">收货信息</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="lang">收货人:</div>
|
||||
<div class="value">
|
||||
{{ orderDatalist.realName }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">收货电话:</div>
|
||||
<div class="value">
|
||||
{{ orderDatalist.userPhone }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">收货地址:</div>
|
||||
<div class="value">
|
||||
{{ orderDatalist.userAddress }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">订单信息</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="lang">商品总价:</div>
|
||||
<div class="value">{{ orderDatalist.proTotalPrice }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">商品总数:</div>
|
||||
<div class="value">{{ orderDatalist.totalNum }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">平台优惠金额:</div>
|
||||
<div class="value">{{ orderDatalist.platCouponPrice }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">支付状态:</div>
|
||||
<div class="value">{{ orderDatalist.paid ? '已支付' : '未支付' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">实际支付:</div>
|
||||
<div class="value">{{ orderDatalist.payPrice || '0.0' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">商户优惠金额:</div>
|
||||
<div class="value">{{ orderDatalist.merCouponPrice || '0.0' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">商户会员抵扣:</div>
|
||||
<div class="value">{{ orderDatalist.merchantMemberDiscountPrice || '0.0' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">SVIP抵扣:</div>
|
||||
<div class="value">{{ orderDatalist.svipDiscountPrice || '0.0' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">支付邮费:</div>
|
||||
<div class="value">{{ orderDatalist.payPostage }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">赠送积分:</div>
|
||||
<div class="value">{{ orderDatalist.gainIntegral }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">积分抵扣金额:</div>
|
||||
<div class="value">{{ orderDatalist.integralPrice || '0.0' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">支付方式:</div>
|
||||
<div class="value">{{ orderDatalist.payType | payTypeFilter }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">支付时间:</div>
|
||||
<div class="value">{{ orderDatalist.payTime | filterEmpty }}</div>
|
||||
</li>
|
||||
<li class="item" v-if="orderDatalist.outTradeNo">
|
||||
<div class="lang">商户单号:</div>
|
||||
<div class="value">{{ orderDatalist.outTradeNo }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- 次卡商品核销信息 -->
|
||||
<div class="detailSection" v-if="orderDatalist.secondType == OrderSecondTypeEnum.PunchCard">
|
||||
<div class="title">核销信息</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="lang">总核销次数:</div>
|
||||
<div class="value">{{ orderDatalist.orderDetailList[0].verifyTotalTimes }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">已核销次数:</div>
|
||||
<div class="value">
|
||||
{{
|
||||
orderDatalist.orderDetailList[0].verifyTotalTimes -
|
||||
orderDatalist.orderDetailList[0].verifyRemainingTimes
|
||||
}}
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">有效期:</div>
|
||||
<div v-if="orderDatalist.orderDetailList[0].verifyEndDate" class="value">
|
||||
{{ orderDatalist.orderDetailList[0].verifyStartDate + ' ' }}~{{
|
||||
' ' + orderDatalist.orderDetailList[0].verifyEndDate
|
||||
}}
|
||||
</div>
|
||||
<div v-else class="value">无限期</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">买家留言</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div>{{ orderDatalist.userRemark | filterEmpty }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">商家备注</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div>{{ orderDatalist.merchantRemark | filterEmpty }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="orderExtend.length" class="detailSection">
|
||||
<div class="title">自定义留言</div>
|
||||
<ul class="orderExtends">
|
||||
<li v-for="(items, indexs) in orderExtend" :key="indexs">
|
||||
<div v-if="items.length">
|
||||
<div class="item" v-for="(item, index) in items" :key="index">
|
||||
<system-from-info :item="item"></system-from-info>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="商品信息" name="goods" class="tabBox">
|
||||
<el-table class="mt20 orderDetailList" :data="orderDatalist.orderDetailList" size="small">
|
||||
<el-table-column label="商品信息" min-width="400" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="demo-image__preview mr15">
|
||||
<el-image :src="scope.row.image" :preview-src-list="[scope.row.image]" />
|
||||
</div>
|
||||
<div style="width: 408px">
|
||||
<div class="line1 mb-8 line-heightOne">{{ scope.row.productName }}</div>
|
||||
<div class="line1 color-909399 line-heightOne">规格:{{ scope.row.sku }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品售价" min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="line1">
|
||||
{{ scope.row.price }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="购买数量" min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="line1">
|
||||
{{ scope.row.payNum }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="orderDatalist.shippingType === 1" label="发货数量" min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="line1">
|
||||
{{ scope.row.deliveryNum }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="售后数量" min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="line1 mb10 line-heightOne">退款中:{{ scope.row.applyRefundNum }}</div>
|
||||
<div class="line1 line-heightOne">退款成功:{{ scope.row.refundNum }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-if="orderDatalist.secondType === OrderSecondTypeEnum.Reservation"
|
||||
label="预约信息"
|
||||
name="reservation"
|
||||
>
|
||||
<div class="detailSection" style="border: none">
|
||||
<div class="title">预约信息</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="lang">联系人:</div>
|
||||
<div class="value">{{ orderDatalist.realName }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">联系电话:</div>
|
||||
<div class="value">{{ orderDatalist.userPhone }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">预约时间:</div>
|
||||
<div class="value">
|
||||
<span>{{ reservationInfo.reservationDate }}</span>
|
||||
<span class="ml10">{{ reservationInfo.reservationTimeSlot }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-show="orderDatalist.shippingType === 5" class="item">
|
||||
<div class="lang">上门地址:</div>
|
||||
<div class="value">
|
||||
{{ orderDatalist.userAddress }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-if="
|
||||
orderDatalist.status > 1 &&
|
||||
orderDatalist.status < 9 &&
|
||||
orderDatalist.secondType < 5 &&
|
||||
orderDatalist.shippingType != 2 &&
|
||||
orderDatalist.status !== 3
|
||||
"
|
||||
label="发货记录"
|
||||
name="delivery"
|
||||
class="tabBox"
|
||||
>
|
||||
<template v-for="item in InvoiceList">
|
||||
<div v-if="InvoiceList.length">
|
||||
<el-table class="mt20" :data="item.detailList" size="small" :key="item.id">
|
||||
<el-table-column min-width="400">
|
||||
<template slot="header" slot-scope="scope">
|
||||
<template v-if="item.deliveryType === 'express'">
|
||||
<span class="font-color">【快递配送】</span>
|
||||
<span>{{ item.expressName + ':' + item.trackingNumber }}</span>
|
||||
<span class="ml30">{{ item.createTime }}</span>
|
||||
</template>
|
||||
<template v-else-if="item.deliveryType === 'merchant'">
|
||||
<span class="font-color">【商家送货】</span>
|
||||
<span>{{ item.deliveryCarrier + ':' + item.carrierPhone }}</span>
|
||||
<span class="ml30">{{ item.createTime }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="font-color"
|
||||
>【{{
|
||||
orderDatalist.secondType === OrderSecondTypeEnum.Fictitious ? '虚拟发货' : '无需配送'
|
||||
}}】</span
|
||||
>
|
||||
<span>{{ item.createTime }}</span>
|
||||
</template>
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="demo-image__preview mr15">
|
||||
<el-image :src="scope.row.image" :preview-src-list="[scope.row.image]" fit="cover" />
|
||||
</div>
|
||||
<div style="width: 408px">
|
||||
<div class="line1 mb10 line-heightOne">{{ scope.row.productName }}</div>
|
||||
<div class="line1 color-909399 line-heightOne">规格:{{ scope.row.sku }}</div>
|
||||
</div>
|
||||
<div class="acea-row row-middle ml30">
|
||||
<div class="line1 font12 color-text">X {{ scope.row.num }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="400" fixed="right">
|
||||
<template slot="header" slot-scope="scope">
|
||||
<div class="flex mr10" style="justify-content: flex-end">
|
||||
<a
|
||||
@click="handleEditLogistics(item)"
|
||||
style="line-height: 1; height: auto"
|
||||
v-hasPermi="['merchant:order:invoice:update']"
|
||||
>修改配送信息
|
||||
</a>
|
||||
<a
|
||||
class="ml20"
|
||||
@click="openLogistics(item.id, item.expressName)"
|
||||
style="line-height: 1; height: auto"
|
||||
v-if="checkPermi(['merchant:order:logistics:info']) && item.deliveryType === 'express'"
|
||||
>查看物流
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="item.deliveryType === 'noNeed'" slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="font12 color-text">发货备注:{{ item.deliveryMark }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="orderDatalist.status > 4 && orderDatalist.status < 9 && orderDatalist.shippingType === 2">
|
||||
<div class="detailSection">
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div>核销员名称:</div>
|
||||
<div class="value">{{ orderDatalist.clerkName }} | {{ orderDatalist.clerkId }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div>核销时间:</div>
|
||||
<div class="value">{{ orderDatalist.verifyTime }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="订单记录" name="record">
|
||||
<el-table class="mt20 orderDetailList" :data="orderDatalist.flowRecordList" style="width: 100%">
|
||||
<el-table-column prop="flowType" label="操作类型" min-width="150" />
|
||||
<el-table-column prop="flowMessage" label="操作记录" min-width="280" />
|
||||
<el-table-column prop="operatorName" label="操作人" min-width="280" />
|
||||
<el-table-column prop="operatorTime" label="操作时间" min-width="200" />
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-if="
|
||||
orderDatalist.secondType == OrderSecondTypeEnum.PunchCard ||
|
||||
orderDatalist.shippingType === 2 ||
|
||||
orderDatalist.shippingType === 4
|
||||
"
|
||||
label="核销记录"
|
||||
name="verRecord"
|
||||
>
|
||||
<el-table class="mt20 orderDetailList" :data="orderDatalist.verificationRecordList" style="width: 100%">
|
||||
<el-table-column prop="id" label="ID" min-width="100" />
|
||||
<el-table-column
|
||||
v-if="orderDatalist.secondType == OrderSecondTypeEnum.PunchCard"
|
||||
prop="verifyTimes"
|
||||
label="核销次数"
|
||||
min-width="200"
|
||||
/>
|
||||
<el-table-column prop="verifyTime" label="核销时间" min-width="200" />
|
||||
<el-table-column prop="verifyName" label="核销人员" min-width="200" />
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-drawer>
|
||||
<el-dialog v-if="orderDatalist" title="提示" :visible.sync="modal2" width="600px">
|
||||
<div class="logistics acea-row row-top">
|
||||
<div class="logistics_img"><img src="@/assets/imgs/expressi.jpg" /></div>
|
||||
<div class="logistics_cent">
|
||||
<span class="mb10">物流公司:{{ expressName }}</span>
|
||||
<span>物流单号:{{ resultInfo.number }}</span>
|
||||
<span v-show="resultInfo.courierPhone">快递站:{{ resultInfo.courierPhone }}</span>
|
||||
<span v-show="resultInfo.courierPhone">快递员电话:{{ resultInfo.courierPhone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acea-row row-column-around trees-coadd">
|
||||
<div class="scollhide">
|
||||
<el-timeline :reverse="reverse">
|
||||
<el-timeline-item v-for="(item, i) in result" :key="i">
|
||||
<p class="time" v-text="item.time"></p>
|
||||
<p class="content" v-text="item.status"></p>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="modal2 = false">关闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 修改配送信息-->
|
||||
<editDelivery
|
||||
:visible="editDeliveryDialogVisible"
|
||||
:editData="editData"
|
||||
@onCloseVisible="onCloseVisible"
|
||||
@onSubmitSuccess="onSubmitSuccess"
|
||||
></editDelivery>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import { merchantGetLogisticsInfoApi as getLogisticsInfoApi, merchantOrderInvoiceListApi as orderInvoiceListApi, merchantOrderDetailApi as orderDetailApi, merchantRefundOrderDetailApi as refundOrderDetailApi } from '@/api/merchantOrder';
|
||||
import { orderRefundStatusFilter } from '@/filters';
|
||||
import editDelivery from './editDelivery';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import { OrderSecondTypeEnum } from '@/enums/productEnums';
|
||||
import systemFromInfo from '@/views/merchantOrder/components/systemFromInfo'; // 权限判断函数
|
||||
export default {
|
||||
name: 'OrderDetail',
|
||||
components: {
|
||||
editDelivery,
|
||||
systemFromInfo,
|
||||
},
|
||||
props: {
|
||||
orderNo: {
|
||||
type: String,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
OrderSecondTypeEnum: OrderSecondTypeEnum,
|
||||
activeName: 'detail',
|
||||
direction: 'rtl',
|
||||
reverse: true,
|
||||
dialogVisible: false,
|
||||
orderDatalist: {},
|
||||
loading: false,
|
||||
modal2: false,
|
||||
result: [],
|
||||
resultInfo: {},
|
||||
InvoiceList: [],
|
||||
refundInfo: {},
|
||||
editDeliveryDialogVisible: false,
|
||||
editData: {},
|
||||
orderExtend: [], //系统表单数据
|
||||
expressName: '', //快递名称
|
||||
reservationInfo: {}, //订单信息,预约信息
|
||||
};
|
||||
},
|
||||
watch: {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
checkPermi,
|
||||
orderRefundStatusFilter,
|
||||
//修改物流信息
|
||||
handleEditLogistics(row) {
|
||||
this.editDeliveryDialogVisible = true;
|
||||
this.editData = row;
|
||||
},
|
||||
//修改物流信息成功
|
||||
onSubmitSuccess() {
|
||||
this.getOrderInvoiceList(this.orderNo);
|
||||
this.onCloseVisible();
|
||||
},
|
||||
//关闭配送信息
|
||||
onCloseVisible() {
|
||||
this.editDeliveryDialogVisible = false;
|
||||
},
|
||||
handleClose() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
openLogistics(id, expressName) {
|
||||
this.expressName = expressName;
|
||||
this.getOrderData(id);
|
||||
this.modal2 = true;
|
||||
},
|
||||
// 获取订单退款信息
|
||||
getRefundOrderDetail(id) {
|
||||
refundOrderDetailApi(id).then(async (res) => {
|
||||
this.refundInfo = res;
|
||||
});
|
||||
},
|
||||
// 获取订单物流信息
|
||||
getOrderData(id) {
|
||||
getLogisticsInfoApi(id).then(async (res) => {
|
||||
this.resultInfo = res;
|
||||
this.result = res.list;
|
||||
});
|
||||
},
|
||||
// 获取订单发货单列表
|
||||
getOrderInvoiceList(id) {
|
||||
this.InvoiceList = [];
|
||||
orderInvoiceListApi(id)
|
||||
.then((res) => {
|
||||
this.InvoiceList = [...res];
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
getDetail(id) {
|
||||
this.loading = true;
|
||||
orderDetailApi(id)
|
||||
.then((res) => {
|
||||
this.orderDatalist = res;
|
||||
if (this.orderDatalist.secondType === OrderSecondTypeEnum.Reservation) {
|
||||
this.orderExtend = res.orderExtend ? JSON.parse(res.orderExtend) : [];
|
||||
}else{
|
||||
this.orderExtend = res.orderExtend ? [JSON.parse(res.orderExtend)] : [];
|
||||
}
|
||||
this.reservationInfo = res.orderDetailList[0]; // 预约信息
|
||||
this.activeName = 'detail';
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.orderDatalist = null;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.orderExtends {
|
||||
li {
|
||||
border-bottom: 1px dashed #eeeeee;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
li:last-child {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
.ml5 {
|
||||
margin-left: 5px;
|
||||
}
|
||||
::v-deep .el-drawer__header {
|
||||
display: flex !important;
|
||||
align-items: flex-start !important;
|
||||
padding: 15px 15px 0 15px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
::v-deep .el-drawer__body {
|
||||
padding: 0 0 30px 0 !important;
|
||||
}
|
||||
::v-deep .demo-drawer_title {
|
||||
width: 90%;
|
||||
}
|
||||
::v-deep .el-tabs__content {
|
||||
padding: 0 20px !important;
|
||||
}
|
||||
.detailSection {
|
||||
padding: 25px 15px !important;
|
||||
}
|
||||
::v-deep .el-table th.el-table__cell > .cell,
|
||||
::v-deep.el-table .cell,
|
||||
.el-table--border .el-table__cell:first-child .cell {
|
||||
padding-left: 15px;
|
||||
}
|
||||
.InvoiceList {
|
||||
::v-deep.el-collapse-item__header {
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
background-color: #fff;
|
||||
margin-top: 7px;
|
||||
padding: 10px 12px;
|
||||
&-num {
|
||||
font-size: 10px;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: #666666;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&-img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 10px;
|
||||
border-radius: 7px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10px;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:nth-child(5n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.demo-drawer__content {
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
.demo-image__preview {
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
.el-image {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.logistics {
|
||||
align-items: center;
|
||||
padding: 10px 0px;
|
||||
.logistics_img {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
margin-right: 12px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.logistics_cent {
|
||||
span {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.trees-coadd {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
.scollhide {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
margin-left: 18px;
|
||||
padding: 10px 0 10px 0;
|
||||
box-sizing: border-box;
|
||||
.content {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 14px;
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.description {
|
||||
&-term {
|
||||
display: table-cell;
|
||||
padding-bottom: 5px;
|
||||
line-height: 20px;
|
||||
width: 50%;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
::v-deep .el-divider--horizontal {
|
||||
margin: 12px 0 !important;
|
||||
}
|
||||
}
|
||||
.mb-8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,779 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer :visible.sync="drawerVisible" :direction="direction" size="1000px" :before-close="handleClose">
|
||||
<div v-loading="loading">
|
||||
<DetailHeader
|
||||
title="退款订单"
|
||||
icon="icon-shouhou_tuikuan-2"
|
||||
:titleLable="`退款单号:${refundInfo.refundOrderNo}`"
|
||||
:orderNo="refundInfo.refundOrderNo"
|
||||
:list="headerList"
|
||||
>
|
||||
<template slot="operation">
|
||||
<!-- 审核 -->
|
||||
<div
|
||||
v-if="refundInfo.refundStatus === 0 && checkPermi(['merchant:refund:order:audit'])"
|
||||
class="acea-row row-center-wrappe mr14"
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
v-debounceClick="
|
||||
() => {
|
||||
handleApprovedReview('success');
|
||||
}
|
||||
"
|
||||
>{{ loadingBtn ? '提交中 ...' : '审核通过' }}</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
v-debounceClick="
|
||||
() => {
|
||||
handleOrderRefuse('refuse');
|
||||
}
|
||||
"
|
||||
>拒绝</el-button
|
||||
>
|
||||
</div>
|
||||
<!-- 商家收货 -->
|
||||
<div v-if="refundInfo.refundStatus === 5" class="acea-row row-center-wrapper mr14">
|
||||
<el-button
|
||||
v-if="checkPermi(['merchant:refund:order:receiving'])"
|
||||
type="primary"
|
||||
v-debounceClick="handleConfirmReceipt"
|
||||
>{{ loadingBtn ? '提交中 ...' : '确认收货' }}</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="checkPermi(['merchant:refund:order:audit'])"
|
||||
type="danger"
|
||||
v-debounceClick="handleRefuseReceipt"
|
||||
>拒绝</el-button
|
||||
>
|
||||
</div>
|
||||
<el-button size="small" @click.native="onOrderMark()" v-if="checkPermi(['merchant:refund:order:mark'])"
|
||||
>订单备注</el-button
|
||||
>
|
||||
</template>
|
||||
</DetailHeader>
|
||||
<el-tabs type="border-card" v-model="activeName">
|
||||
<el-tab-pane label="售后信息" name="refund">
|
||||
<div class="detailSection" style="border: none">
|
||||
<div class="title">退款商品</div>
|
||||
<ul class="list">
|
||||
<li class="item row-middle">
|
||||
<div class="image mr10">
|
||||
<el-image
|
||||
:src="refundInfo.image"
|
||||
:preview-src-list="[refundInfo.image]"
|
||||
style="width: 40px; height: 40px"
|
||||
></el-image>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text666 mb10 productName line-height-15">{{ refundInfo.productName }}</div>
|
||||
<div class="text999">
|
||||
<span>{{ refundInfo.sku }}</span
|
||||
><span class="ml30">售价:¥{{ refundInfo.price }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">退款明细</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="lang">退款数量:</div>
|
||||
<div class="value">{{ refundInfo.applyRefundNum }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">购买数量:</div>
|
||||
<div class="value">{{ refundInfo.payNum }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">预计退款方式:</div>
|
||||
<div class="value">原支付返还</div>
|
||||
</li>
|
||||
<li v-show="refundInfo.refundStatus === 2 || refundInfo.refundStatus === 3" class="item">
|
||||
<div class="lang">退回运费:</div>
|
||||
<div class="value">{{ refundInfo.refundFreightFee }}</div>
|
||||
</li>
|
||||
<li v-show="refundInfo.refundStatus === 2 || refundInfo.refundStatus === 3" class="item">
|
||||
<div class="lang">退一级佣金:</div>
|
||||
<div class="value">{{ refundInfo.refundFirstBrokerageFee }}</div>
|
||||
</li>
|
||||
<li v-show="refundInfo.refundStatus === 2 || refundInfo.refundStatus === 3" class="item">
|
||||
<div class="lang">退回抵扣积分:</div>
|
||||
<div class="value">{{ refundInfo.refundUseIntegral }}</div>
|
||||
</li>
|
||||
<li v-show="refundInfo.refundStatus === 2 || refundInfo.refundStatus === 3" class="item">
|
||||
<div class="lang">收回赠送积分:</div>
|
||||
<div class="value">{{ refundInfo.refundGainIntegral }}</div>
|
||||
</li>
|
||||
<li v-show="refundInfo.refundStatus === 2 || refundInfo.refundStatus === 3" class="item">
|
||||
<div class="lang">退二级返佣:</div>
|
||||
<div class="value">{{ refundInfo.refundSecondBrokerageFee }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- 退款流程信息-->
|
||||
<div class="detailSection">
|
||||
<div class="title">退款流程信息</div>
|
||||
<div class="detail-centent acea-row">
|
||||
<div>
|
||||
<!-- 操作类型:apply-申请退款,audit-商家审核,returning-商品退回,receiving-商家确认收货,refund-退款,compulsory-平台强制退款,revoke-撤销-->
|
||||
<el-steps
|
||||
direction="vertical"
|
||||
:active="
|
||||
refundInfo.promoterType === 'merchant' ? 2 : refundInfo.statusList && refundInfo.statusList.length
|
||||
"
|
||||
finish-status="success"
|
||||
>
|
||||
<el-step title="直接退款-商家" v-if="refundInfo.promoterType === 'merchant'">
|
||||
<template slot="description">
|
||||
<div class="mb10">
|
||||
{{ refundInfo.refundTime }}
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="申请退款-用户"
|
||||
v-if="
|
||||
refundInfo.statusList &&
|
||||
refundInfo.statusList.length &&
|
||||
refundInfo.statusList.find((item) => item.changeType === 'apply')
|
||||
"
|
||||
>
|
||||
<template slot="description" v-if="refundInfo.statusList && refundInfo.statusList.length">
|
||||
<div class="mb10">
|
||||
{{ refundInfo.statusList.filter((item) => item.changeType === 'apply')[0].createTime }}
|
||||
</div>
|
||||
<div class="refundReasonWap">
|
||||
<div class="acea-row">
|
||||
<div class="detail-term" style="width: 58%">
|
||||
<span class="detail-infoTitle">退款原因:</span
|
||||
><span class="detail-info">{{ refundInfo.refundReasonWap }}</span>
|
||||
</div>
|
||||
<div class="detail-term">
|
||||
<span class="detail-infoTitle">退货方式:</span
|
||||
><span class="detail-info">{{
|
||||
refundInfo.returnGoodsType === 1
|
||||
? '快递退回'
|
||||
: refundInfo.returnGoodsType === 2
|
||||
? '到店退货'
|
||||
: '不退货'
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-term acea-row">
|
||||
<span class="detail-infoTitle">备注说明:</span>
|
||||
<div class="detail-info" style="width: 600px">
|
||||
{{ refundInfo.refundReasonWapExplain | filterEmpty }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-term">
|
||||
<div class="acea-row">
|
||||
<span class="detail-infoTitle">退款凭证:</span>
|
||||
|
||||
<div v-if="refundInfo.refundReasonWapImg">
|
||||
<el-image
|
||||
v-for="(item, index) in refundInfo.refundReasonWapImg.split(',')"
|
||||
:key="index"
|
||||
style="width: 60px; height: 60px"
|
||||
:src="item"
|
||||
class="mr10"
|
||||
:preview-src-list="refundInfo.refundReasonWapImg.split(',')"
|
||||
></el-image>
|
||||
</div>
|
||||
<div v-else>-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="商家审核-商家"
|
||||
v-if="
|
||||
refundInfo.statusList &&
|
||||
refundInfo.statusList.length &&
|
||||
refundInfo.statusList.find((item) => item.changeType === 'audit')
|
||||
"
|
||||
>
|
||||
<template slot="description" v-if="refundInfo.statusList && refundInfo.statusList.length">
|
||||
<div class="mb10">
|
||||
{{
|
||||
refundInfo.statusList.filter((item) => item.changeType === 'audit').length
|
||||
? refundInfo.statusList.filter((item) => item.changeType === 'audit')[0].createTime
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
<div v-if="refundInfo.refundStatus > 0" class="refundReasonWap">
|
||||
<div class="detail-term">
|
||||
<span class="detail-infoTitle">审核结果:</span
|
||||
><span class="detail-info">{{
|
||||
refundInfo.refundStatus === 1 && refundInfo.statusList.length === 2
|
||||
? '拒绝退款'
|
||||
: '同意退款'
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="refundInfo.refundStatus === 1 && refundInfo.statusList.length === 2"
|
||||
class="detail-term"
|
||||
>
|
||||
<span class="detail-infoTitle">拒绝原因:</span>
|
||||
<span class="detail-info">{{ refundInfo.refundReason | filterEmpty }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="refundInfo.returnGoodsType === 1 && refundInfo.refundStatus !== 1"
|
||||
class="detail-term"
|
||||
>
|
||||
<div>
|
||||
<span class="detail-infoTitle">退货地址:</span>
|
||||
<span class="detail-info">{{ refundInfo.receiverAddressDetail }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="detail-infoTitle"></span>
|
||||
<span class="detail-info">{{ refundInfo.receiver }} {{ refundInfo.receiverPhone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="商品退回信息-用户"
|
||||
v-if="
|
||||
refundInfo.statusList &&
|
||||
refundInfo.statusList.length &&
|
||||
refundInfo.statusList.find((item) => item.changeType === 'returning')
|
||||
"
|
||||
>
|
||||
<template slot="description" v-if="refundInfo.statusList && refundInfo.statusList.length">
|
||||
<div class="mb10">
|
||||
{{ refundInfo.statusList.filter((item) => item.changeType === 'returning')[0].createTime }}
|
||||
</div>
|
||||
<div v-if="refundInfo.returnGoodsType === 1" class="refundReasonWap">
|
||||
<div class="acea-row">
|
||||
<div class="detail-term" style="width: 58%">
|
||||
<span class="detail-infoTitle">物流公司:</span
|
||||
><span class="detail-info">{{ refundInfo.expressName }}</span>
|
||||
</div>
|
||||
<div class="detail-term">
|
||||
<span class="detail-infoTitle">物流单号:</span>
|
||||
<span class="detail-info">{{ refundInfo.trackingNumber }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-term">
|
||||
<div>
|
||||
<span class="detail-infoTitle">联系电话:</span>
|
||||
<span class="detail-info">{{ refundInfo.telephone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="refundInfo.returnGoodsType === 2" class="refundReasonWap">
|
||||
<div class="detail-term">
|
||||
<div>
|
||||
<span class="detail-infoTitle">联系电话:</span>
|
||||
<span class="detail-info">{{ refundInfo.telephone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="商家确认收货-商家"
|
||||
v-if="
|
||||
refundInfo.refundStatus !== 1 &&
|
||||
refundInfo.refundStatus !== 6 &&
|
||||
refundInfo.statusList &&
|
||||
refundInfo.statusList.length &&
|
||||
refundInfo.statusList.find((item) => item.changeType === 'receiving')
|
||||
"
|
||||
>
|
||||
<template slot="description" v-if="refundInfo.statusList && refundInfo.statusList.length">
|
||||
<div class="mb10">
|
||||
{{
|
||||
refundInfo.statusList.filter((item) => item.changeType === 'receiving').length
|
||||
? refundInfo.statusList.filter((item) => item.changeType === 'receiving')[0].createTime
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="商品拒绝收货-商家"
|
||||
v-if="
|
||||
refundInfo.statusList &&
|
||||
refundInfo.statusList.length &&
|
||||
refundInfo.statusList.find((item) => item.changeType === 'rejectionGoods')
|
||||
"
|
||||
>
|
||||
<template slot="description" v-if="refundInfo.statusList && refundInfo.statusList.length">
|
||||
<div class="mb10">
|
||||
{{
|
||||
refundInfo.statusList.filter((item) => item.changeType === 'rejectionGoods')[0].createTime
|
||||
}}
|
||||
</div>
|
||||
<div v-if="refundInfo.refundStatus > 0" class="refundReasonWap">
|
||||
<div class="detail-term">
|
||||
<span class="detail-infoTitle">审核结果:</span
|
||||
><span class="detail-info">{{
|
||||
refundInfo.refundStatus === 1 ? '拒绝退款' : '同意退款'
|
||||
}}</span>
|
||||
</div>
|
||||
<div v-if="refundInfo.refundStatus === 1" class="detail-term">
|
||||
<span class="detail-infoTitle">拒绝原因:</span>
|
||||
<span class="detail-info">{{ refundInfo.refundReason | filterEmpty }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="refundInfo.returnGoodsType === 1 && refundInfo.refundStatus !== 1"
|
||||
class="detail-term"
|
||||
>
|
||||
<div>
|
||||
<span class="detail-infoTitle">退货地址:</span>
|
||||
<span class="detail-info">{{ refundInfo.receiverAddressDetail }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="detail-infoTitle"></span>
|
||||
<span class="detail-info">{{ refundInfo.receiver }} {{ refundInfo.receiverPhone }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="已撤销"
|
||||
v-if="
|
||||
refundInfo.refundStatus === 6 &&
|
||||
refundInfo.statusList &&
|
||||
refundInfo.statusList.length &&
|
||||
refundInfo.statusList.find((item) => item.changeType === 'revoke')
|
||||
"
|
||||
>
|
||||
<template slot="description" v-if="refundInfo.statusList && refundInfo.statusList.length">
|
||||
<div class="mb10">
|
||||
{{
|
||||
refundInfo.statusList.filter((item) => item.changeType === 'revoke').length
|
||||
? refundInfo.statusList.filter((item) => item.changeType === 'revoke')[0].createTime
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="平台强制退款成功"
|
||||
v-if="
|
||||
refundInfo.statusList &&
|
||||
refundInfo.statusList.length &&
|
||||
refundInfo.statusList.find((item) => item.changeType === 'compulsory')
|
||||
"
|
||||
>
|
||||
<template slot="description" v-if="refundInfo.statusList && refundInfo.statusList.length">
|
||||
<div class="mb10">
|
||||
{{
|
||||
refundInfo.statusList.filter((item) => item.changeType === 'compulsory').length
|
||||
? refundInfo.statusList.filter((item) => item.changeType === 'compulsory')[0].createTime
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
:title="refundInfo.promoterType === 'user' ? '退款成功' : '退款成功-商家直接退款'"
|
||||
v-if="
|
||||
refundInfo.refundStatus !== 1 &&
|
||||
refundInfo.refundStatus !== 6 &&
|
||||
refundInfo.statusList &&
|
||||
refundInfo.statusList.length &&
|
||||
refundInfo.statusList.find((item) => item.changeType === 'refund')
|
||||
"
|
||||
>
|
||||
<template slot="description" v-if="refundInfo.statusList && refundInfo.statusList.length">
|
||||
<div class="mb10">
|
||||
{{
|
||||
refundInfo.statusList.filter((item) => item.changeType === 'refund').length
|
||||
? refundInfo.statusList.filter((item) => item.changeType === 'refund')[0].createTime
|
||||
: ''
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="商家审核-商家"
|
||||
v-if="
|
||||
refundInfo.refundStatus !== 1 &&
|
||||
refundInfo.refundStatus !== 2 &&
|
||||
refundInfo.refundStatus !== 6 &&
|
||||
refundInfo.refundStatus === 0
|
||||
"
|
||||
>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="商品退回信息-用户"
|
||||
v-if="
|
||||
refundInfo.refundStatus !== 1 &&
|
||||
refundInfo.refundStatus !== 2 &&
|
||||
refundInfo.refundStatus !== 6 &&
|
||||
refundInfo.afterSalesType === 2 &&
|
||||
(refundInfo.refundStatus === 0 || refundInfo.refundStatus === 4)
|
||||
"
|
||||
>
|
||||
</el-step>
|
||||
<el-step
|
||||
title="商家确认收货-商家"
|
||||
v-if="
|
||||
refundInfo.refundStatus !== 1 &&
|
||||
refundInfo.refundStatus !== 2 &&
|
||||
refundInfo.refundStatus !== 6 &&
|
||||
refundInfo.afterSalesType === 2 &&
|
||||
(refundInfo.refundStatus === 0 ||
|
||||
refundInfo.refundStatus === 4 ||
|
||||
refundInfo.refundStatus === 5)
|
||||
"
|
||||
>
|
||||
</el-step>
|
||||
<el-step
|
||||
:title="refundInfo.promoterType === 'user' ? '退款成功' : '退款成功-商家直接退款'"
|
||||
v-if="
|
||||
refundInfo.refundStatus !== 1 &&
|
||||
refundInfo.refundStatus !== 6 &&
|
||||
(refundInfo.refundStatus === 0 ||
|
||||
refundInfo.refundStatus === 2 ||
|
||||
refundInfo.refundStatus === 4 ||
|
||||
refundInfo.refundStatus === 5)
|
||||
"
|
||||
>
|
||||
</el-step>
|
||||
</el-steps>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">平台备注</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div>{{ refundInfo.platformRemark | filterEmpty }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">商家备注</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div>{{ refundInfo.merRemark | filterEmpty }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="订单信息" name="detail" v-if="refundInfo.orderInfoVo">
|
||||
<DetailInfo :list="orderDetailList">
|
||||
<template slot="nickname">
|
||||
<span class="mr5">{{ refundInfo.orderInfoVo.nickname }}</span>
|
||||
<span class="mr5"> | </span>
|
||||
<span>{{ refundInfo.orderInfoVo.uid }}</span>
|
||||
</template>
|
||||
<template slot="userAddress">
|
||||
<div class="userAddress acea-row">
|
||||
<div class="lang">收货地址:</div>
|
||||
<div class="value">{{ refundInfo.orderInfoVo.userAddress | filterEmpty }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template slot="orderStatus">
|
||||
<span v-if="refundInfo.orderInfoVo.refundStatus === 3">已退款</span>
|
||||
<span v-else>{{ refundInfo.orderInfoVo.status | orderStatusFilter }}</span>
|
||||
</template>
|
||||
</DetailInfo>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-drawer>
|
||||
<!-- 同意退款,退货退款-->
|
||||
<el-dialog
|
||||
title="同意退款"
|
||||
:visible.sync="dialogVisible"
|
||||
width="900px"
|
||||
:before-close="handleCloseAgreeToReturn"
|
||||
class="dialog-bottom"
|
||||
>
|
||||
<agree-to-return
|
||||
ref="agreeToReturn"
|
||||
@onHandleCancel="handleCloseAgreeToReturn"
|
||||
@onHandleSuccess="handleSuccess"
|
||||
:refundInfo="refundInfo"
|
||||
v-if="dialogVisible"
|
||||
></agree-to-return>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { merchantOrderAuditApi as orderAuditApi, merchantRefundMarkApi as refundMarkApi, merchantRefundOrderDetailApi as refundOrderDetailApi, merchantRefundOrderReceivingRejectApi as refundOrderReceivingRejectApi } from '@/api/merchantOrder';
|
||||
import AgreeToReturn from './agreeToReturn.vue';
|
||||
import DetailHeader from '@/components/base/DetailHeader.vue';
|
||||
import DetailInfo from '@/components/base/DetailInfo.vue';
|
||||
import { filterEmpty, refundStatusFilter } from '@/filters';
|
||||
import useRefundOrder from '@/libs/useRefundOrder';
|
||||
const { onConfirmReceipt, onApprovedReview } = useRefundOrder();
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import { OrderSecondTypeEnum } from '@/enums/productEnums';
|
||||
export default {
|
||||
name: 'refundOrderDetail',
|
||||
props: {
|
||||
//退款单号
|
||||
refundOrderNo: {
|
||||
type: String,
|
||||
default: 0,
|
||||
},
|
||||
//是否显示隐藏
|
||||
drawerVisible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
DetailHeader,
|
||||
DetailInfo,
|
||||
AgreeToReturn,
|
||||
},
|
||||
computed: {
|
||||
headerList() {
|
||||
return [
|
||||
{
|
||||
label: '退款状态',
|
||||
value: refundStatusFilter(this.refundInfo.refundStatus),
|
||||
color: 'color-warning',
|
||||
},
|
||||
{
|
||||
label: '退款金额',
|
||||
value: '¥ ' + (this.refundInfo.refundPrice || '0.0'),
|
||||
},
|
||||
{
|
||||
label: '实付金额',
|
||||
value: this.refundInfo.payPrice,
|
||||
},
|
||||
{
|
||||
label: '创建时间',
|
||||
value: this.refundInfo.orderInfoVo ? this.refundInfo.orderInfoVo.createTime : '',
|
||||
},
|
||||
];
|
||||
},
|
||||
orderDetailList() {
|
||||
const info = this.refundInfo.orderInfoVo || {};
|
||||
const { filterEmpty, payTypeFilter, orderStatusFilter } = this.$options.filters;
|
||||
const list = [
|
||||
{
|
||||
title: '用户信息',
|
||||
list: [
|
||||
{ label: '用户昵称', slot: 'nickname' },
|
||||
{ label: '用户电话', value: info.phone },
|
||||
],
|
||||
},
|
||||
];
|
||||
if (info.shippingType < 3 && info.secondType !== 2) {
|
||||
list.push({
|
||||
title: '配送信息',
|
||||
bottomSlot: 'userAddress',
|
||||
list: [
|
||||
{ label: '配送方式', value: info.shippingType === 1 ? '商家配送' : '到店自提' },
|
||||
{ label: '收货电话', value: filterEmpty(info.userPhone) },
|
||||
{ label: '收货人', value: filterEmpty(info.realName) },
|
||||
],
|
||||
});
|
||||
}
|
||||
list.push({
|
||||
title: '订单信息',
|
||||
list: [
|
||||
{ label: '订单号', value: info.orderNo },
|
||||
{ label: '商品总数', value: info.totalNum },
|
||||
{ label: '支付状态', value: info.paid ? '已支付' : '未支付' },
|
||||
{ label: '支付方式', value: payTypeFilter ? payTypeFilter(info.payType) : info.payType },
|
||||
{ label: '订单状态', slot: 'orderStatus', class: 'textE93323' },
|
||||
{ label: '已发货数量', value: info.deliveryNum },
|
||||
{ label: '创建时间', value: info.createTime },
|
||||
{ label: '支付时间', value: info.payTime },
|
||||
],
|
||||
});
|
||||
list.push({
|
||||
title: '订单明细',
|
||||
list: [
|
||||
{ label: '商品总价', value: '¥' + info.proTotalPrice },
|
||||
{ label: '平台优惠金额', value: '¥' + info.platCouponPrice },
|
||||
{ label: '赠送积分', value: '¥' + info.gainIntegral },
|
||||
{ label: '实际支付', value: '¥' + (info.payPrice || '0.0') },
|
||||
{ label: '扣除抵扣积分', value: info.useIntegral },
|
||||
{ label: '商家优惠金额', value: '¥' + (info.merCouponPrice || '0.0') },
|
||||
{ label: '商户会员抵扣', value: '¥' + (info.merchantMemberDiscountPrice || '0.0') },
|
||||
{ label: 'SVIP抵扣', value: '¥' + (info.svipDiscountPrice || '0.0') },
|
||||
{ label: '支付邮费', value: '¥' + (info.payPostage || '0.0') },
|
||||
{ label: '积分抵扣金额', value: '¥' + (info.integralPrice || '0.0') },
|
||||
],
|
||||
});
|
||||
if (info.secondType == this.OrderSecondTypeEnum.PunchCard) {
|
||||
list.push({
|
||||
title: '核销信息',
|
||||
list: [
|
||||
{ label: '待核销次数', value: this.refundInfo.verifyRemainingTimes },
|
||||
{ label: '总次数', value: this.refundInfo.verifyTotalTimes },
|
||||
],
|
||||
});
|
||||
}
|
||||
list.push({
|
||||
title: '用户备注',
|
||||
list: [{ label: '', value: filterEmpty(info.userRemark), class: 'productName', type: 'lang' }],
|
||||
});
|
||||
list.push({
|
||||
title: '商家备注',
|
||||
list: [{ label: '', value: filterEmpty(info.merchantRemark), class: 'productName', type: 'lang' }],
|
||||
});
|
||||
return list;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: 'refund',
|
||||
dialogVisible: false,
|
||||
loadingBtn: false,
|
||||
direction: 'rtl',
|
||||
reverse: true,
|
||||
orderDatalist: {},
|
||||
loading: false,
|
||||
modal2: false,
|
||||
result: [],
|
||||
resultInfo: {},
|
||||
refundInfo: {},
|
||||
OrderSecondTypeEnum,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getRefundOrderDetail(this.refundOrderNo);
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
// 备注
|
||||
onOrderMark() {
|
||||
this.$modalPrompt('textarea', '备注', this.refundInfo.merRemark, '退款单备注').then((V) => {
|
||||
refundMarkApi({ remark: V, refundOrderNo: this.refundOrderNo }).then(() => {
|
||||
this.$message.success('操作成功');
|
||||
this.getRefundOrderDetail(this.refundOrderNo);
|
||||
this.$emit('getReviewSuccessful');
|
||||
});
|
||||
});
|
||||
},
|
||||
//拒绝收货
|
||||
handleRefuseReceipt() {
|
||||
this.$modalPrompt('textarea', '拒绝收货', null, '拒绝收货原因').then((V) => {
|
||||
refundOrderReceivingRejectApi({ reason: V, refundOrderNo: this.refundOrderNo }).then(() => {
|
||||
this.$message.success('拒绝收货成功');
|
||||
this.getSuccessful();
|
||||
});
|
||||
});
|
||||
},
|
||||
//商家确认收货
|
||||
handleConfirmReceipt() {
|
||||
onConfirmReceipt(this.refundOrderNo).then(() => {
|
||||
this.getSuccessful();
|
||||
});
|
||||
},
|
||||
//审核同意
|
||||
handleApprovedReview() {
|
||||
if (this.refundInfo.returnGoodsType !== 1) {
|
||||
onApprovedReview({
|
||||
auditType: 'success',
|
||||
refundOrderNo: this.refundInfo.refundOrderNo,
|
||||
}).then(() => {
|
||||
this.handleSuccess();
|
||||
});
|
||||
} else {
|
||||
//退货退款
|
||||
this.dialogVisible = true;
|
||||
}
|
||||
},
|
||||
//审核成功回调
|
||||
handleSuccess() {
|
||||
this.dialogVisible = false;
|
||||
this.getSuccessful();
|
||||
},
|
||||
//操作成功之后的回调,比如关闭弹窗,刷新列表等
|
||||
getSuccessful() {
|
||||
this.getRefundOrderDetail(this.refundOrderNo);
|
||||
this.$emit('getReviewSuccessful');
|
||||
this.handleClose();
|
||||
},
|
||||
//同意弹窗
|
||||
handleCloseAgreeToReturn() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
//审核拒绝
|
||||
handleOrderRefuse() {
|
||||
this.$modalPrompt('textarea', '拒绝退款', null, '拒绝退款原因').then((V) => {
|
||||
orderAuditApi({ auditType: 'refuse', reason: V, refundOrderNo: this.refundInfo.refundOrderNo }).then(() => {
|
||||
this.$message.success('审核成功');
|
||||
this.getSuccessful();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleClose() {
|
||||
this.$emit('onClosedrawerVisible');
|
||||
},
|
||||
// 获取订单退款信息
|
||||
getRefundOrderDetail(id) {
|
||||
this.loading = true;
|
||||
refundOrderDetailApi(id)
|
||||
.then(async (res) => {
|
||||
this.refundInfo = res;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.userAddress {
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
.productName {
|
||||
width: 633px;
|
||||
}
|
||||
.detail-centent {
|
||||
margin-top: 16px;
|
||||
}
|
||||
::v-deep .el-step__main {
|
||||
margin-bottom: 30px !important;
|
||||
}
|
||||
::v-deep .el-step__title {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
.flow-path {
|
||||
margin-bottom: 70px;
|
||||
}
|
||||
.refundReasonWap {
|
||||
width: 720px;
|
||||
height: auto;
|
||||
padding: 10px 25px 0 0;
|
||||
border-radius: 14px;
|
||||
background-color: #f3f8fe;
|
||||
overflow: hidden;
|
||||
}
|
||||
.image {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.refund {
|
||||
&-title {
|
||||
font-size: 17px;
|
||||
color: #333333;
|
||||
font-weight: 600;
|
||||
}
|
||||
&-orderNo {
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
}
|
||||
&-price {
|
||||
margin-right: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
247
mer_plat_admin/src/views/merchantOrder/components/sendFrom.vue
Normal file
247
mer_plat_admin/src/views/merchantOrder/components/sendFrom.vue
Normal file
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="formItem.deliveryType === 'express'">
|
||||
<el-form-item label="发货类型:">
|
||||
<el-radio-group v-model="formItem.expressRecordType" @change="changeSendTypeRadio(formItem.expressRecordType)">
|
||||
<el-radio label="1">手动填写</el-radio>
|
||||
<el-radio label="2" :disabled="merElectPrint == 0" v-if="checkPermi(['admin:order:sheet:info'])"
|
||||
>电子面单打印</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formItem.deliveryType === 'express'" label="快递公司:" prop="expressCode">
|
||||
<el-select
|
||||
@change="onChangeExpress"
|
||||
v-model="formItem.expressCode"
|
||||
filterable
|
||||
:style="isShowBtn ? 'width: 82%' : 'width:100%'"
|
||||
>
|
||||
<el-option v-for="item in express" :key="item.id" :label="item.name" :value="item.code"
|
||||
>{{ item.name }}
|
||||
<span v-if="item.account" type="info" class="line-heightOne from-tips"> | 月结账号已配</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-button
|
||||
v-show="isShowBtn"
|
||||
class="ml24"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleCreat"
|
||||
v-hasPermi="['merchant:express:relate']"
|
||||
>设置物流公司</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
<!--手动填写-->
|
||||
<template v-if="formItem.expressRecordType === '1'">
|
||||
<el-form-item v-if="formItem.deliveryType === 'express'" label="快递单号:" prop="expressNumber">
|
||||
<el-input v-model.trim="formItem.expressNumber" placeholder="请输入快递单号"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<!--电子面单打印-->
|
||||
<template v-if="formItem.expressRecordType === '2'">
|
||||
<el-form-item label="电子面单:" class="express_temp_id" prop="expressTempId" label-width="95px">
|
||||
<div class="acea-row">
|
||||
<el-select
|
||||
v-model="formItem.expressTempId"
|
||||
placeholder="请选择电子面单"
|
||||
:class="[formItem.expressTempId ? 'width9' : 'width8']"
|
||||
@change="onChangeImg"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item, i) in exportTempList"
|
||||
:value="item.temp_id"
|
||||
:key="i"
|
||||
:label="item.title"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<div v-if="formItem.expressTempId" style="position: relative">
|
||||
<div class="tempImgList ml10">
|
||||
<div class="demo-image__preview">
|
||||
<el-image style="width: 36px; height: 36px" :src="tempImg" :preview-src-list="[tempImg]" fit="cover"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="寄件人姓名:" prop="toName">
|
||||
<el-input v-model="formItem.toName" placeholder="请输入寄件人姓名" style="width: 80%"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="寄件人电话:" prop="toTel">
|
||||
<el-input v-model="formItem.toTel" placeholder="请输入寄件人电话" style="width: 80%"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="寄件人地址:" prop="toAddr">
|
||||
<el-input v-model="formItem.toAddr" placeholder="请输入寄件人地址" style="width: 80%"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<el-form-item v-if="formItem.deliveryType === 'noNeed'" label="发货备注:">
|
||||
<el-input
|
||||
v-model.trim="formItem.deliveryMark"
|
||||
show-word-limit
|
||||
:autosize="{ minRows: 4 }"
|
||||
maxlength="250"
|
||||
type="textarea"
|
||||
placeholder="请输入备注信息,最多可输入250字"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formItem.deliveryType === 'merchant'" label="配送人员:" prop="deliveryCarrier">
|
||||
<div class="acea-row">
|
||||
<el-select
|
||||
v-model="selectedValue"
|
||||
value-key="id"
|
||||
:style="isShowBtn ? 'width: 80%' : 'width:95%'"
|
||||
filterable
|
||||
clearable
|
||||
@change="handleChangePersonnel"
|
||||
>
|
||||
<el-option v-for="item in personnelList" :key="item.id" :label="item.personnelName" :value="item" />
|
||||
</el-select>
|
||||
<el-button v-show="isShowBtn" class="ml24" @click="handleCreatPersonnel()">添加配送员</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formItem.deliveryType === 'merchant'" label="手机号码:" prop="carrierPhone">
|
||||
<el-input v-model.trim="formItem.carrierPhone" disabled placeholder="请输入配送人员手机号码"></el-input>
|
||||
</el-form-item>
|
||||
<!--物流公司-->
|
||||
<creat-express ref="craetExpressRef" @handlerSuccessSubmit="getList"></creat-express>
|
||||
<!-- 添加配送员 -->
|
||||
<creat-personnel
|
||||
:dialogVisible="dialogVisible"
|
||||
:editData="editData"
|
||||
@handlerCloseFrom="handlerCloseFrom"
|
||||
@handlerSuccessSubmit="handlerSuccessSubmit"
|
||||
></creat-personnel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CreatExpress from '@/views/systemSetting/logisticsManagement/creatExpress.vue';
|
||||
import { useLogistics } from '@/hooks/use-order';
|
||||
import { defaultData } from '@/views/systemSetting/deliveryPersonnel/default';
|
||||
import { personnelListApi } from '@/api/deliveryPersonnel';
|
||||
import CreatPersonnel from '@/views/systemSetting/deliveryPersonnel/creatPersonnel';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import { merchantElectrSheetInfo } from '@/api/systemSetting';
|
||||
import Cookies from 'js-cookie';
|
||||
import { exportTempApi } from '@/api/logistics';
|
||||
export default {
|
||||
name: 'sendFrom',
|
||||
components: { CreatExpress, CreatPersonnel },
|
||||
data() {
|
||||
return {
|
||||
selectedValue: null,
|
||||
express: [],
|
||||
dialogVisible: false,
|
||||
editData: Object.assign({}, defaultData),
|
||||
tableFrom: {
|
||||
page: 1,
|
||||
limit: 9999,
|
||||
},
|
||||
personnelList: [],
|
||||
shipmentExpress: {}, // 电子面单发货信息
|
||||
exportTempList: [],
|
||||
merElectPrint: Cookies.get('merElectPrint'), // 商家小票打印开关状态
|
||||
currentItemCode: '',
|
||||
};
|
||||
},
|
||||
props: {
|
||||
formItem: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
isShowBtn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getList();
|
||||
this.getPersonnelList();
|
||||
//if (checkPermi(['admin:pass:shipment:express']))
|
||||
this.getShipmentExpress();
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
//选择配送员
|
||||
handleChangePersonnel(e) {
|
||||
this.formItem.deliveryCarrier = e.personnelName;
|
||||
this.formItem.carrierPhone = e.personnelPhone;
|
||||
},
|
||||
// 取消选配送员弹窗
|
||||
handlerCloseFrom() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
// 选配送员确定回调
|
||||
handlerSuccessSubmit() {
|
||||
this.getPersonnelList();
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
// 配送员列表
|
||||
async getPersonnelList() {
|
||||
const data = await personnelListApi(this.tableFrom);
|
||||
this.personnelList = data.list;
|
||||
if (!this.isShowBtn)
|
||||
this.selectedValue = this.personnelList.filter((item) => item.personnelPhone === this.formItem.carrierPhone)[0];
|
||||
},
|
||||
// 添加
|
||||
handleCreatPersonnel(row) {
|
||||
this.editData = row ? row : Object.assign({}, defaultData);
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
// 添加
|
||||
handleCreat() {
|
||||
if (!localStorage.getItem('expressAllList')) this.$refs.craetExpressRef.getExpressList();
|
||||
this.$refs.craetExpressRef.dialogVisible = true;
|
||||
},
|
||||
// 物流公司列表
|
||||
async getList() {
|
||||
const params = {
|
||||
keywords: '',
|
||||
page: 1,
|
||||
limit: 50,
|
||||
openStatus: true,
|
||||
};
|
||||
this.express = await useLogistics(params);
|
||||
this.express.map((item) => {
|
||||
if (item.isDefault && !this.formItem.id) this.formItem.expressCode = item.code;
|
||||
});
|
||||
},
|
||||
getShipmentExpress() {
|
||||
merchantElectrSheetInfo().then((data) => {
|
||||
this.shipmentExpress = data;
|
||||
this.formItem.toName = data.senderUsername;
|
||||
this.formItem.toTel = data.senderPhone;
|
||||
this.formItem.toAddr = data.senderAddr;
|
||||
});
|
||||
},
|
||||
changeSendTypeRadio(expressRecordType) {
|
||||
if (expressRecordType === '2') {
|
||||
this.formItem.expressCode && this.exportTemp(this.formItem.expressCode);
|
||||
this.getShipmentExpress();
|
||||
}
|
||||
},
|
||||
// 快递公司选择
|
||||
onChangeExpress: function (val) {
|
||||
const currentItem = this.express.filter((item) => item.code == val)[0];
|
||||
this.formItem.expressName = val.name;
|
||||
this.formItem.expressTempId = '';
|
||||
this.currentItemCode = currentItem.code;
|
||||
if (this.formItem.expressRecordType === '2') this.exportTemp(currentItem.code);
|
||||
},
|
||||
// 电子面单模板
|
||||
exportTemp(code) {
|
||||
exportTempApi({ com: code }).then(async (res) => {
|
||||
this.exportTempList = res.data.data || [];
|
||||
});
|
||||
},
|
||||
onChangeImg(item) {
|
||||
this.exportTempList.map((i) => {
|
||||
if (i.temp_id === item) this.tempImg = i.pic;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="acea-row">
|
||||
<div v-if="item.title !== 'richTextEditor'" class="lang" :title="item.title">{{ item.title }}</div>
|
||||
<div v-if="item.title !== 'richTextEditor'">{{ item.title.includes(':') ? '' : ':' }}</div>
|
||||
<div v-if="item.title === 'richTextEditor'">
|
||||
<div class="contentPic" v-html="item.value"></div>
|
||||
</div>
|
||||
<div v-else-if="!Array.isArray(item.value)" class="value">{{ item.value | filterEmpty }}</div>
|
||||
<div v-else class="flex conter">
|
||||
<template v-if="item.value">
|
||||
<div v-for="(pic, idx) in item.value" :key="idx">
|
||||
<el-image v-if="pic.includes('http')" class="pictrue" :src="pic" :preview-src-list="[pic]" />
|
||||
<div v-else class="text-14px fontColor333 ml-5px acea-row row-middle mr5">
|
||||
{{ pic }}
|
||||
<div style="margin-left: 6px" v-show="idx < item.value.length - 1">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else> - </template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "systemFromInfo",
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
class="dialog-box"
|
||||
title="核销"
|
||||
v-if="writeOffData.infoResponseList"
|
||||
:visible.sync="dialogTableVisible"
|
||||
@submit.native.prevent
|
||||
@closed="closeDialog"
|
||||
>
|
||||
<div>
|
||||
<el-form label-width="70px">
|
||||
<el-form-item label="已核销:">
|
||||
<span>
|
||||
{{
|
||||
writeOffData.infoResponseList[0].verifyTotalTimes -
|
||||
writeOffData.infoResponseList[0].verifyRemainingTimes
|
||||
}}
|
||||
</span>
|
||||
<span>/</span>
|
||||
<span>{{ writeOffData.infoResponseList[0].verifyTotalTimes }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="核销次数:">
|
||||
<el-input-number
|
||||
v-model="verifyCount"
|
||||
controls-position="right"
|
||||
class="ver-count-input"
|
||||
:step="1"
|
||||
step-strictly
|
||||
:min="1"
|
||||
:max="writeOffData.infoResponseList[0].verifyRemainingTimes"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div class="flex-right">
|
||||
<el-button size="small" @click="closeDialog">取消</el-button>
|
||||
<el-button type="primary" size="small" @click="writeOff">确认</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { merchantWriteUpdateApi as writeUpdateApi } from '@/api/merchantOrder';
|
||||
import { Debounce } from '@/utils/validate';
|
||||
export default {
|
||||
name: '',
|
||||
components: {},
|
||||
mixins: [],
|
||||
props: {
|
||||
writeOffData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogTableVisible: false, // 弹窗是否显示
|
||||
verifyCount: 1, // 核销次数
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {},
|
||||
destoryed() {},
|
||||
methods: {
|
||||
// 开启弹窗
|
||||
openDialog() {
|
||||
this.dialogTableVisible = true;
|
||||
},
|
||||
// 关闭弹窗
|
||||
closeDialog() {
|
||||
this.dialogTableVisible = false;
|
||||
this.verifyCount = 1
|
||||
// this.$emit('handleSearchList');
|
||||
},
|
||||
// 核销
|
||||
writeOff: Debounce(function () {
|
||||
{
|
||||
if (!this.verifyCount) {
|
||||
this.$message.error('核销次数不能为空!');
|
||||
return
|
||||
}
|
||||
const param = {
|
||||
orderNo: this.writeOffData.orderNo,
|
||||
verifyCount: this.verifyCount,
|
||||
};
|
||||
writeUpdateApi(param).then(() => {
|
||||
this.$message.success('核销成功');
|
||||
this.closeDialog();
|
||||
this.$emit('handleSearchList');
|
||||
this.verifyCount = 1;
|
||||
});
|
||||
}
|
||||
}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dialog-box {
|
||||
.ver-count-input {
|
||||
width: 100%;
|
||||
}
|
||||
::v-deep .el-dialog {
|
||||
margin-top: 30vh !important;
|
||||
width: 410px;
|
||||
}
|
||||
}
|
||||
.flex-right {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
13
mer_plat_admin/src/views/merchantOrder/default.js
Normal file
13
mer_plat_admin/src/views/merchantOrder/default.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { validatePhone } from '@/utils/toolsValidate';
|
||||
|
||||
export const postRules = {
|
||||
expressCode: [{ required: true, message: '请选择快递公司', trigger: 'change' }],
|
||||
expressNumber: [{ required: true, message: '请输入快递单号', trigger: 'blur' }],
|
||||
deliveryCarrier: [{ required: true, message: '请输入配送人员', trigger: 'blur' }],
|
||||
carrierPhone: [{ required: true, validator: validatePhone, trigger: 'blur' }],
|
||||
isSplit: [{ required: true, message: '请选择分单发货', trigger: 'change' }],
|
||||
toName: [{ required: true, message: '请输入寄件人姓名', trigger: 'blur' }],
|
||||
expressTempId: [{ required: true, message: '请选择电子面单', trigger: 'blur' }],
|
||||
toTel: [{ required: true, message: '请输入寄件人电话', trigger: 'blur' }],
|
||||
toAddr: [{ required: true, message: '请输入寄件人地址', trigger: 'blur' }],
|
||||
};
|
||||
789
mer_plat_admin/src/views/merchantOrder/index.vue
Normal file
789
mer_plat_admin/src/views/merchantOrder/index.vue
Normal file
@@ -0,0 +1,789 @@
|
||||
<template>
|
||||
<div class="divBox relative">
|
||||
<el-card
|
||||
:bordered="false"
|
||||
shadow="never"
|
||||
class="ivu-mt"
|
||||
:body-style="{ padding: 0 }"
|
||||
v-if="checkPermi(['merchant:order:page:list'])"
|
||||
>
|
||||
<div class="padding-add">
|
||||
<el-form inline label-position="right" @submit.native.prevent>
|
||||
<el-form-item label="订单编号:" label-width="66px">
|
||||
<el-input
|
||||
v-model.trim="tableFrom.orderNo"
|
||||
placeholder="请输入订单号"
|
||||
class="form_content_width"
|
||||
size="small"
|
||||
@keyup.enter.native="handleSearchList"
|
||||
clearable
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单类型:">
|
||||
<el-select
|
||||
v-model="tableFrom.type"
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择"
|
||||
class="form_content_width"
|
||||
@change="handleSearchList"
|
||||
>
|
||||
<el-option v-for="(item, i) in fromType" :key="i" :label="item.text" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间选择:">
|
||||
<el-date-picker
|
||||
v-model="timeVal"
|
||||
value-format="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd"
|
||||
size="small"
|
||||
type="daterange"
|
||||
placement="bottom-end"
|
||||
placeholder="自定义时间"
|
||||
@change="onchangeTime"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户搜索:" label-for="nickname">
|
||||
<UserSearchInput v-model="tableFrom" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="small" @click="handleSearchList">查询</el-button>
|
||||
<el-button size="small" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card
|
||||
shadow="never"
|
||||
:bordered="false"
|
||||
class="box-card mt16"
|
||||
:body-style="{ padding: '0 20px 20px', position: 'relative' }"
|
||||
v-if="checkPermi(['merchant:order:status:num', 'merchant:order:page:list'])"
|
||||
>
|
||||
<el-tabs class="list-tabs" v-model="tableFrom.status" @tab-click="handleSearchList">
|
||||
<el-tab-pane name="all" :label="`全部(${orderChartType.all || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="notShipped" :label="`待发货(${orderChartType.notShipped || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="spike" :label="`待收货(${orderChartType.spike || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="awaitVerification" :label="`待使用(${orderChartType.verification || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="receiving" :label="`已收货(${orderChartType.receiving || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="complete" :label="`已完成(${orderChartType.complete || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="refunded" :label="`已退款(${orderChartType.refunded || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="deleted" :label="`已删除(${orderChartType.deleted || 0})`"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="mt5">
|
||||
<!-- <el-button size="small" type="primary" @click="onWriteOff" v-hasPermi="['merchant:order:verification']"
|
||||
>核销订单</el-button
|
||||
> -->
|
||||
<el-button size="small" @click="exports" v-hasPermi="['merchant:export:order:excel']">导出</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
:data="tableData.data"
|
||||
size="mini"
|
||||
class="mt20"
|
||||
highlight-current-row
|
||||
:row-key="
|
||||
(row) => {
|
||||
return row.orderNo;
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-table-column label="订单号" min-width="220" v-if="checkedCities.includes('订单号')">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row">
|
||||
<font v-show="scope.row.type === 1" class="mr5">[秒杀]</font>
|
||||
<font v-show="scope.row.type === 2" class="mr5">[拼团]</font>
|
||||
<span style="display: block" v-text="scope.row.orderNo" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<span class="colorPrompt" v-show="parseInt(scope.row.refundStatus) > 0" style="display: block">{{
|
||||
scope.row.refundStatus | orderRefundStatusFilter
|
||||
}}</span>
|
||||
<span v-show="scope.row.refundStatus == 2" class="colorPrompt">{{
|
||||
`(已退款 ${scope.row.refundNum} / 购买 ${scope.row.totalNum})`
|
||||
}}</span>
|
||||
</div>
|
||||
<span v-show="scope.row.isUserDel" class="colorPrompt" style="display: block">用户已删除</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户昵称" min-width="150" v-if="checkedCities.includes('用户昵称')">
|
||||
<template slot-scope="scope">
|
||||
<span :class="scope.row.isLogoff == true ? 'colorPrompt' : ''">{{ scope.row.nickName }}</span>
|
||||
<span :class="scope.row.isLogoff == true ? 'colorPrompt' : ''" v-if="scope.row.isLogoff == true">|</span>
|
||||
<span v-if="scope.row.isLogoff == true" class="colorPrompt">(已注销)</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payPrice" label="实际支付" min-width="80" v-if="checkedCities.includes('实际支付')" />
|
||||
<el-table-column label="支付方式" min-width="80" v-if="checkedCities.includes('支付方式')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.payType | payTypeFilter }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" min-width="100" v-if="checkedCities.includes('订单状态')">
|
||||
<template slot-scope="scope">
|
||||
<span class="textE93323 tag-background notStartTag tag-padding" v-if="scope.row.refundStatus === 3"
|
||||
>已退款</span
|
||||
>
|
||||
<!-- 次卡商品部分使用状态 -->
|
||||
<span
|
||||
class="tag-background tag-padding doingTag"
|
||||
v-else-if="
|
||||
scope.row.secondType == OrderSecondTypeEnum.PunchCard &&
|
||||
scope.row.status == 3 &&
|
||||
scope.row.infoResponseList[0].verifyRemainingTimes != scope.row.infoResponseList[0].verifyTotalTimes
|
||||
"
|
||||
>部分使用</span
|
||||
>
|
||||
<span
|
||||
:class="scope.row.status < 5 ? 'doingTag' : 'endTag'"
|
||||
class="tag-background tag-padding"
|
||||
v-else-if="
|
||||
scope.row.groupBuyRecordStatus == 99 || scope.row.status == 9 || scope.row.groupBuyRecordStatus == 10
|
||||
"
|
||||
>{{ scope.row.status | orderStatusFilter }}</span
|
||||
>
|
||||
<span class="textE93323 tag-background notStartTag tag-padding" v-else>{{
|
||||
scope.row.groupBuyRecordStatus == 0 ? '拼团中' : '拼团失败'
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.merchantRemark | filterEmpty }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="下单时间" min-width="160" v-if="checkedCities.includes('下单时间')" />
|
||||
<el-table-column width="160" fixed="right">
|
||||
<template slot="header">
|
||||
<p>
|
||||
<span style="padding-right: 5px">操作</span>
|
||||
<i class="el-icon-setting" @click="handleAddItem"></i>
|
||||
</p>
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<a
|
||||
@click="onOrderDetails(scope.row.orderNo)"
|
||||
v-if="checkPermi(['merchant:order:info']) && scope.row.groupBuyRecordStatus != 0"
|
||||
>详情
|
||||
</a>
|
||||
<el-divider direction="vertical" v-if="scope.row.groupBuyRecordStatus != 0"></el-divider>
|
||||
<template
|
||||
v-if="
|
||||
(scope.row.status === 1 || scope.row.status === 2) &&
|
||||
parseFloat(scope.row.refundStatus) < 3 &&
|
||||
checkPermi(['merchant:order:send']) &&
|
||||
scope.row.groupBuyRecordStatus != 0 &&
|
||||
scope.row.secondType !== OrderSecondTypeEnum.Reservation
|
||||
"
|
||||
>
|
||||
<a @click="sendOrder(scope.row)">发货 </a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
</template>
|
||||
<template
|
||||
v-if="
|
||||
scope.row.status === 3 &&
|
||||
parseFloat(scope.row.refundStatus) < 3 &&
|
||||
checkPermi(['merchant:order:verification']) &&
|
||||
scope.row.groupBuyRecordStatus != 0 &&
|
||||
scope.row.shippingType != 5
|
||||
"
|
||||
>
|
||||
<a @click="writeOffInTable(scope.row)">核销 </a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
</template>
|
||||
<el-dropdown trigger="click" v-if="scope.row.groupBuyRecordStatus != 0">
|
||||
<span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right" /> </span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item
|
||||
@click.native="onDirectRefund(scope.row)"
|
||||
v-if="
|
||||
scope.row.refundStatus == 0 &&
|
||||
!scope.row.userRefundSign &&
|
||||
checkPermi(['merchant:order:direct:refund'])
|
||||
"
|
||||
>直接退款
|
||||
</el-dropdown-item>
|
||||
<!-- 打印小票订单状态 待发货/待使用/待收货/已收货/已核销/已完成/已退款 原始订单状态
|
||||
订单状态(0:待支付,1:待发货,2:部分发货, 3:待使用,4:待收货,5:已收货,6:已完成,9:已取消)-->
|
||||
<el-dropdown-item
|
||||
@click.native="handlePrintReceipt(scope.row)"
|
||||
v-if="
|
||||
(parseFloat(scope.row.status) < 7 || scope.row.refundStatus == 3) &&
|
||||
merPrintStatus !== 2 &&
|
||||
checkPermi(['merchant:order:print'])
|
||||
"
|
||||
>打印小票
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
@click.native="handleOrderPrint(scope.row)"
|
||||
>订单打印
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="onOrderMark(scope.row)" v-if="checkPermi(['merchant:order:mark'])"
|
||||
>订单备注
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="scope.row.isUserDel === 1 && checkPermi(['merchant:order:delete'])"
|
||||
@click.native="handleDelete(scope.row, scope.$index)"
|
||||
>删除订单
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="block">
|
||||
<el-pagination
|
||||
background
|
||||
:page-sizes="$constants.page.limit"
|
||||
:page-size="tableFrom.limit"
|
||||
:current-page="tableFrom.page"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableData.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="card_abs" v-show="card_select_show">
|
||||
<template>
|
||||
<div class="cell_ht">
|
||||
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange"
|
||||
>全选
|
||||
</el-checkbox>
|
||||
<el-button size="small" type="text" @click="checkSave()">保存</el-button>
|
||||
</div>
|
||||
<el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
|
||||
<el-checkbox v-for="item in columnData" :label="item" :key="item" class="check_cell">{{
|
||||
item
|
||||
}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</template>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!--记录-->
|
||||
<el-dialog title="操作记录" :visible.sync="dialogVisibleJI" width="700px">
|
||||
<el-table v-loading="LogLoading" border :data="tableDataLog.data" style="width: 100%">
|
||||
<el-table-column prop="oid" label="ID" min-width="80" />
|
||||
<el-table-column prop="changeMessage" label="操作记录" min-width="280" />
|
||||
<el-table-column prop="createTime" label="操作时间" min-width="280" />
|
||||
</el-table>
|
||||
<div class="block">
|
||||
<el-pagination
|
||||
background
|
||||
:page-sizes="$constants.page.limit"
|
||||
:page-size="tableFromLog.limit"
|
||||
:current-page="tableFromLog.page"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableDataLog.total"
|
||||
@size-change="handleSizeChangeLog"
|
||||
@current-change="pageChangeLog"
|
||||
/>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!--详情-->
|
||||
<details-from ref="orderDetail" :orderNo="orderNo" />
|
||||
|
||||
<!-- 发送货 -->
|
||||
<order-send ref="send" :orderNo="orderNo" :secondType="secondType" @submitFail="handleSearchList"></order-send>
|
||||
|
||||
<!-- 直接退款 -->
|
||||
<direct-refund
|
||||
v-if="dialogVisibleDirectRefund"
|
||||
:dialogVisibleDirectRefund="dialogVisibleDirectRefund"
|
||||
:type="type"
|
||||
@handlerSuccessClose="handlerSuccessClose"
|
||||
@handlerSuccessSubmit="handlerSuccessSubmit"
|
||||
:orderNo="orderNo"
|
||||
:secondType="secondType"
|
||||
></direct-refund>
|
||||
<!-- 核销弹窗 -->
|
||||
<writeOffDialog
|
||||
ref="writeOffDialog"
|
||||
:writeOffData="writeOffData"
|
||||
@handleSearchList="handleSearchList"
|
||||
></writeOffDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import {
|
||||
merchantOrderStatusNumApi as orderStatusNumApi,
|
||||
merchantOrderListApi as orderListApi,
|
||||
merchantOrderLogApi as orderLogApi,
|
||||
merchantOrderMarkApi as orderMarkApi,
|
||||
merchantOrderDeleteApi as orderDeleteApi,
|
||||
merchantOrderPrint as orderPrint,
|
||||
merchantOrderDetailApi as orderDetailApi,
|
||||
merchantWriteUpdateApi as writeUpdateApi,
|
||||
merchantOrderExcelApi as orderExcelApi,
|
||||
merchantOrderPrintReceiptApi as orderPrintReceiptApi,
|
||||
} from '@/api/merchantOrder';
|
||||
import detailsFrom from './components/orderDetail';
|
||||
import writeOffDialog from './components/writeOffDialog';
|
||||
import orderSend from './orderSend';
|
||||
import Cookies from 'js-cookie';
|
||||
import { isWriteOff } from '@/utils';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import DirectRefund from '@/views/merchantOrder/components/directRefund.vue';
|
||||
import * as $constants from '@/utils/constants';
|
||||
import { handleDeleteTable } from '@/libs/public';
|
||||
import { OrderSecondTypeEnum } from '@/enums/productEnums'; // 权限判断函数
|
||||
let tableFroms = {
|
||||
status: 'all',
|
||||
dateLimit: '',
|
||||
orderNo: '',
|
||||
page: 1,
|
||||
limit: $constants.page.limit[0],
|
||||
type: '',
|
||||
searchType: 'all',
|
||||
content: '',
|
||||
};
|
||||
export default {
|
||||
name: 'orderlistDetails',
|
||||
components: {
|
||||
DirectRefund,
|
||||
detailsFrom,
|
||||
orderSend,
|
||||
writeOffDialog,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
RefuseVisible: false,
|
||||
RefuseData: {},
|
||||
orderNo: '',
|
||||
refundVisible: false,
|
||||
refundData: {},
|
||||
dialogVisibleJI: false,
|
||||
tableDataLog: {
|
||||
data: [],
|
||||
total: 0,
|
||||
},
|
||||
tableFromLog: {
|
||||
page: 1,
|
||||
limit: this.$constants.page.limit[0],
|
||||
orderNo: 0,
|
||||
},
|
||||
LogLoading: false,
|
||||
isCreate: 1,
|
||||
editData: null,
|
||||
dialogVisible: false,
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
},
|
||||
listLoading: false,
|
||||
tableFrom: Object.assign({}, tableFroms),
|
||||
orderChartType: {},
|
||||
timeVal: [],
|
||||
fromList: this.$constants.fromList,
|
||||
fromType: [
|
||||
{ value: '', text: '全部' },
|
||||
{ value: '0', text: '普通' },
|
||||
{ value: '1', text: '秒杀' },
|
||||
{ value: '2', text: '拼团' },
|
||||
],
|
||||
selectionList: [],
|
||||
ids: '',
|
||||
orderids: '',
|
||||
cardLists: [],
|
||||
isWriteOff: isWriteOff(),
|
||||
proType: 0,
|
||||
active: false,
|
||||
card_select_show: false,
|
||||
checkAll: true,
|
||||
checkedCities: ['订单号', '用户昵称', '实际支付', '支付方式', '订单状态', '下单时间'],
|
||||
columnData: ['订单号', '用户昵称', '实际支付', '支付方式', '订单状态', '下单时间'],
|
||||
isIndeterminate: false,
|
||||
orderDatalist: null,
|
||||
merPrintStatus: Cookies.get('merPrint'), // 商家小票打印开关状态
|
||||
dialogVisibleDirectRefund: false,
|
||||
secondType: 0, //订单二级类型:0-普通订单,1-积分订单,2-虚拟订单,4-视频号订单,5-云盘订单,6-卡密订单
|
||||
type: 0, //订单类型
|
||||
writeOffData: {}, // 核销订单数据
|
||||
OrderSecondTypeEnum: OrderSecondTypeEnum,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (checkPermi(['merchant:order:page:list'])) this.getList();
|
||||
if (checkPermi(['merchant:order:status:num'])) this.getOrderStatusNum();
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
//直接退款
|
||||
onDirectRefund(row) {
|
||||
this.secondType = row.secondType;
|
||||
this.orderNo = row.orderNo;
|
||||
this.type = row.type;
|
||||
this.dialogVisibleDirectRefund = true;
|
||||
},
|
||||
//直接退款关闭
|
||||
handlerSuccessClose() {
|
||||
this.dialogVisibleDirectRefund = false;
|
||||
},
|
||||
//直接退款成功回调
|
||||
handlerSuccessSubmit() {
|
||||
this.dialogVisibleDirectRefund = false;
|
||||
this.getList();
|
||||
},
|
||||
// 核销订单
|
||||
onWriteOff(row) {
|
||||
this.$modalPrompt('text', '核销订单', null, '核销码').then((V) => {
|
||||
writeUpdateApi({ verifyCode: V, verifyCount: 1 }).then(() => {
|
||||
this.$message.success('核销成功');
|
||||
this.handleSearchList();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleReset() {
|
||||
this.tableFrom.type = '';
|
||||
this.tableFrom.dateLimit = '';
|
||||
this.tableFrom.orderNo = '';
|
||||
this.tableFrom.page = 1;
|
||||
this.tableFrom.content = '';
|
||||
this.tableFrom.searchType = 'all';
|
||||
this.selectChange();
|
||||
},
|
||||
resetFormRefundhandler() {
|
||||
this.refundVisible = false;
|
||||
},
|
||||
resetFormRefusehand() {
|
||||
this.RefuseVisible = false;
|
||||
},
|
||||
resetForm(formValue) {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
handleSearchList() {
|
||||
this.tableFrom.page = 1;
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
},
|
||||
// 发送
|
||||
sendOrder(row) {
|
||||
if (row.isLogoff) {
|
||||
this.$modalSure('当前用户已注销,有责发货!').then(() => {
|
||||
this.onSend(row);
|
||||
});
|
||||
} else {
|
||||
if (row.refundStatus == 1) return this.$message.error('请先处理售后,再进行发货/核销操作');
|
||||
this.onSend(row);
|
||||
}
|
||||
},
|
||||
handlePrintReceipt(row) {
|
||||
this.$modalSure('确认打印小票').then(() => {
|
||||
orderPrintReceiptApi(row.orderNo).then((data) => {
|
||||
this.$message.success('小票打印成功');
|
||||
});
|
||||
});
|
||||
},
|
||||
//发货操作
|
||||
onSend(row) {
|
||||
this.secondType = row.secondType;
|
||||
this.orderNo = row.orderNo;
|
||||
this.$refs.send.modals = true;
|
||||
//this.$refs.send.getList();
|
||||
this.$refs.send.orderProDetail(row.orderNo);
|
||||
},
|
||||
// 订单删除
|
||||
handleDelete(row, idx) {
|
||||
if (row.isDel) {
|
||||
this.$modalSure().then(() => {
|
||||
orderDeleteApi({ orderNo: row.orderNo }).then(() => {
|
||||
this.$message.success('删除成功');
|
||||
handleDeleteTable(this.tableData.data.length, this.tableFrom);
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.$confirm('您选择的的订单存在用户未删除的订单,无法删除用户未删除的订单!', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
},
|
||||
// 详情
|
||||
onOrderDetails(id) {
|
||||
this.orderNo = id;
|
||||
this.$refs.orderDetail.getDetail(id);
|
||||
this.$refs.orderDetail.getOrderInvoiceList(id);
|
||||
this.$refs.orderDetail.dialogVisible = true;
|
||||
},
|
||||
getDetail(id) {
|
||||
this.loading = true;
|
||||
orderDetailApi(id)
|
||||
.then((res) => {
|
||||
this.orderDatalist = res;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.orderDatalist = null;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 订单记录
|
||||
onOrderLog(id) {
|
||||
this.dialogVisibleJI = true;
|
||||
this.LogLoading = true;
|
||||
this.tableFromLog.orderNo = id;
|
||||
orderLogApi(this.tableFromLog)
|
||||
.then((res) => {
|
||||
this.tableDataLog.data = res.list;
|
||||
this.tableDataLog.total = res.total;
|
||||
this.LogLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.LogLoading = false;
|
||||
});
|
||||
},
|
||||
pageChangeLog(page) {
|
||||
this.tableFromLog.page = page;
|
||||
this.onOrderLog();
|
||||
},
|
||||
handleSizeChangeLog(val) {
|
||||
this.tableFromLog.limit = val;
|
||||
this.onOrderLog();
|
||||
},
|
||||
handleClose() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
// 备注
|
||||
onOrderMark(row) {
|
||||
this.$modalPrompt('textarea', '备注', row.merchantRemark, '订单备注').then((V) => {
|
||||
orderMarkApi({ remark: V, orderNo: row.orderNo }).then(() => {
|
||||
this.$message.success('操作成功');
|
||||
this.getList();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.selectionList = val;
|
||||
const data = [];
|
||||
this.selectionList.map((item) => {
|
||||
data.push(item.orderNo);
|
||||
});
|
||||
this.ids = data.join(',');
|
||||
},
|
||||
// 选择时间
|
||||
selectChange(tab) {
|
||||
this.timeVal = [];
|
||||
this.tableFrom.page = 1;
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
},
|
||||
// 具体日期
|
||||
onchangeTime(e) {
|
||||
this.timeVal = e;
|
||||
this.tableFrom.dateLimit = e ? this.timeVal.join(',') : '';
|
||||
this.tableFrom.page = 1;
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
},
|
||||
// 列表
|
||||
getList() {
|
||||
this.listLoading = true;
|
||||
orderListApi(this.tableFrom)
|
||||
.then((res) => {
|
||||
this.tableData.data = res.list || [];
|
||||
this.tableData.total = res.total;
|
||||
this.listLoading = false;
|
||||
this.checkedCities = this.$cache.local.has('order_stroge')
|
||||
? this.$cache.local.getJSON('order_stroge')
|
||||
: this.checkedCities;
|
||||
})
|
||||
.catch(() => {
|
||||
this.listLoading = false;
|
||||
});
|
||||
},
|
||||
// 获取各状态数量
|
||||
getOrderStatusNum() {
|
||||
let data = Object.assign({}, this.tableFrom);
|
||||
delete data.page;
|
||||
delete data.limit;
|
||||
delete data.status;
|
||||
orderStatusNumApi(data).then((res) => {
|
||||
this.orderChartType = res;
|
||||
});
|
||||
},
|
||||
pageChange(page) {
|
||||
this.tableFrom.page = page;
|
||||
this.getList();
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.tableFrom.limit = val;
|
||||
this.getList();
|
||||
},
|
||||
exports() {
|
||||
let data = {
|
||||
dateLimit: this.tableFrom.dateLimit,
|
||||
orderNo: this.tableFrom.orderNo,
|
||||
status: this.tableFrom.status,
|
||||
type: this.tableFrom.type,
|
||||
};
|
||||
orderExcelApi(data).then((res) => {
|
||||
window.open(res.fileName);
|
||||
});
|
||||
},
|
||||
handleAddItem() {
|
||||
if (this.card_select_show) {
|
||||
this.$set(this, 'card_select_show', false);
|
||||
} else if (!this.card_select_show) {
|
||||
this.$set(this, 'card_select_show', true);
|
||||
}
|
||||
},
|
||||
handleCheckAllChange(val) {
|
||||
this.checkAll = true;
|
||||
this.checkedCities = val ? this.columnData : [];
|
||||
this.isIndeterminate = false;
|
||||
},
|
||||
handleCheckedCitiesChange(value) {
|
||||
let checkedCount = value.length;
|
||||
this.checkAll = checkedCount === this.columnData.length;
|
||||
this.isIndeterminate = checkedCount > 0 && checkedCount < this.columnData.length;
|
||||
},
|
||||
checkSave() {
|
||||
this.$set(this, 'card_select_show', false);
|
||||
this.$modal.loading('正在保存到本地,请稍候...');
|
||||
this.$cache.local.setJSON('order_stroge', this.checkedCities);
|
||||
setTimeout(this.$modal.closeLoading(), 1000);
|
||||
},
|
||||
// 订单打印(新窗口打开打印页)
|
||||
handleOrderPrint(row) {
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/merchantOrder/print/${row.orderNo}`,
|
||||
});
|
||||
window.open(routeData.href, '_blank');
|
||||
},
|
||||
//打印小票
|
||||
onOrderPrint(data) {
|
||||
orderPrint(data.orderNo)
|
||||
.then((res) => {
|
||||
this.$modal.msgSuccess('打印成功');
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$modal.msgError(error.message);
|
||||
});
|
||||
},
|
||||
// 核销订单-table内核销
|
||||
writeOffInTable(data) {
|
||||
this.writeOffData = data
|
||||
const param = {
|
||||
orderNo: data.orderNo,
|
||||
verifyCount: 1,
|
||||
};
|
||||
const orderSecondTpye = data.secondType;
|
||||
if (orderSecondTpye == this.OrderSecondTypeEnum.PunchCard) {
|
||||
this.$refs.writeOffDialog.openDialog();
|
||||
} else {
|
||||
this.$confirm('是否确认核销此订单?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
customClass: 'deleteConfirm'
|
||||
}).then(() => {
|
||||
writeUpdateApi(param).then(() => {
|
||||
this.$message.success('核销成功');
|
||||
this.handleSearchList();
|
||||
});
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消核销'
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .el-card {
|
||||
overflow: auto !important;
|
||||
}
|
||||
font {
|
||||
color: var(--prev-color-primary);
|
||||
}
|
||||
.el-table__body {
|
||||
width: 100%;
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
|
||||
.demo-table-expand {
|
||||
::v-deep .label {
|
||||
width: 83px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.refunding {
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.el-icon-arrow-down {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tabBox_tit {
|
||||
font-size: 12px !important;
|
||||
/*margin: 0 2px 0 10px;*/
|
||||
letter-spacing: 1px;
|
||||
/*padding: 5px 0;*/
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.text_overflow {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.pup_card {
|
||||
width: 200px;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.cell_ht {
|
||||
height: 50px;
|
||||
padding: 15px 20px;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.check_cell {
|
||||
width: 100%;
|
||||
padding: 15px 20px 0;
|
||||
}
|
||||
::v-deep .el-checkbox__input.is-checked + .el-checkbox__label {
|
||||
color: #606266;
|
||||
}
|
||||
</style>
|
||||
375
mer_plat_admin/src/views/merchantOrder/orderPrint.vue
Normal file
375
mer_plat_admin/src/views/merchantOrder/orderPrint.vue
Normal file
@@ -0,0 +1,375 @@
|
||||
<template>
|
||||
<div class="order-print-page" v-loading="loading">
|
||||
<div class="print-header no-print">
|
||||
<el-button type="primary" size="medium" icon="el-icon-printer" @click="handlePrint">打印</el-button>
|
||||
<el-button size="medium" @click="goBack">返回</el-button>
|
||||
</div>
|
||||
|
||||
<div class="print-content" v-if="orderData">
|
||||
<div class="print-title">
|
||||
<h2>订单详情</h2>
|
||||
<p class="order-no">订单号:{{ orderData.orderNo }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 订单基本信息 -->
|
||||
<div class="print-section">
|
||||
<div class="section-title">订单信息</div>
|
||||
<table class="info-table">
|
||||
<tr>
|
||||
<td class="label">订单号:</td>
|
||||
<td>{{ orderData.orderNo }}</td>
|
||||
<td class="label">下单时间:</td>
|
||||
<td>{{ orderData.createTime }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">订单状态:</td>
|
||||
<td>{{ orderData.status | orderStatusFilter }}</td>
|
||||
<td class="label">支付方式:</td>
|
||||
<td>{{ orderData.payType | payTypeFilter }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">实际支付:</td>
|
||||
<td>¥ {{ orderData.payPrice || '0.00' }}</td>
|
||||
<td class="label">支付时间:</td>
|
||||
<td>{{ orderData.payTime || '-' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 收货信息 -->
|
||||
<div class="print-section" v-if="orderData.realName">
|
||||
<div class="section-title">收货信息</div>
|
||||
<table class="info-table">
|
||||
<tr>
|
||||
<td class="label">收货人:</td>
|
||||
<td>{{ orderData.realName }}</td>
|
||||
<td class="label">联系电话:</td>
|
||||
<td>{{ orderData.userPhone }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label">收货地址:</td>
|
||||
<td colspan="3">{{ orderData.userAddress }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 商品信息 -->
|
||||
<div class="print-section">
|
||||
<div class="section-title">商品信息</div>
|
||||
<table class="goods-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 50px">序号</th>
|
||||
<th>商品名称</th>
|
||||
<th>商品详情</th>
|
||||
<th style="width: 80px">规格</th>
|
||||
<th style="width: 80px">单价</th>
|
||||
<th style="width: 60px">数量</th>
|
||||
<th style="width: 90px">小计</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in productList" :key="index">
|
||||
<td class="center">{{ index + 1 }}</td>
|
||||
<td>{{ item.productName }}</td>
|
||||
<td>
|
||||
<div class="product-info" v-if="item.info">
|
||||
<template v-if="typeof parsedInfo(item.info) === 'object'">
|
||||
<div v-for="(val, key) in parsedInfo(item.info)" :key="key" class="info-item">
|
||||
<span class="info-key">{{ key }}:</span> {{ val }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ item.info }}
|
||||
</template>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</td>
|
||||
<td class="center">{{ item.sku || '-' }}</td>
|
||||
<td class="center">¥ {{ item.price }}</td>
|
||||
<td class="center">{{ item.payNum }}</td>
|
||||
<td class="center">¥ {{ (item.price * item.payNum).toFixed(2) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="5" class="right"><strong>合计:</strong></td>
|
||||
<td class="center"><strong>{{ totalNum }}</strong></td>
|
||||
<td class="center"><strong>¥ {{ totalPrice }}</strong></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 买家备注 -->
|
||||
<div class="print-section" v-if="orderData.userRemark">
|
||||
<div class="section-title">买家留言</div>
|
||||
<p class="remark-text">{{ orderData.userRemark }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 商家备注 -->
|
||||
<div class="print-section" v-if="orderData.merchantRemark">
|
||||
<div class="section-title">商家备注</div>
|
||||
<p class="remark-text">{{ orderData.merchantRemark }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 页脚 -->
|
||||
<div class="print-footer">
|
||||
<p>打印时间:{{ printTime }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && !orderData" class="no-data">
|
||||
<p>未找到订单数据</p>
|
||||
<el-button type="primary" @click="goBack">返回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { merchantOrderPrintDetailApi } from '@/api/merchantOrder';
|
||||
import { parseTime } from '@/utils';
|
||||
|
||||
export default {
|
||||
name: 'MerchantOrderPrint',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
orderData: null,
|
||||
productList: [],
|
||||
printTime: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
totalNum() {
|
||||
return this.productList.reduce((sum, item) => sum + (item.payNum || 0), 0);
|
||||
},
|
||||
totalPrice() {
|
||||
return this.productList.reduce((sum, item) => sum + (item.price * item.payNum || 0), 0).toFixed(2);
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
orderStatusFilter(status) {
|
||||
const statusMap = {
|
||||
0: '待支付',
|
||||
1: '待发货',
|
||||
2: '部分发货',
|
||||
3: '待使用',
|
||||
4: '待收货',
|
||||
5: '已收货',
|
||||
6: '已完成',
|
||||
9: '已取消',
|
||||
};
|
||||
return statusMap[status] || '未知';
|
||||
},
|
||||
payTypeFilter(type) {
|
||||
const typeMap = {
|
||||
weixin: '微信支付',
|
||||
alipay: '支付宝',
|
||||
yue: '余额支付',
|
||||
shoppingCredits: '购物金',
|
||||
};
|
||||
return typeMap[type] || type || '-';
|
||||
},
|
||||
},
|
||||
created() {
|
||||
const orderNo = this.$route.params.orderNo;
|
||||
if (orderNo) {
|
||||
this.getPrintDetail(orderNo);
|
||||
} else {
|
||||
this.loading = false;
|
||||
}
|
||||
this.printTime = parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}');
|
||||
},
|
||||
methods: {
|
||||
getPrintDetail(orderNo) {
|
||||
this.loading = true;
|
||||
merchantOrderPrintDetailApi(orderNo)
|
||||
.then((res) => {
|
||||
this.orderData = res.orderInfo || {};
|
||||
this.productList = res.detailList || [];
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
parsedInfo(info) {
|
||||
if (!info) return '';
|
||||
try {
|
||||
return JSON.parse(info);
|
||||
} catch (e) {
|
||||
return info;
|
||||
}
|
||||
},
|
||||
handlePrint() {
|
||||
window.print();
|
||||
},
|
||||
goBack() {
|
||||
window.close();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.order-print-page {
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.print-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
padding: 15px 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.print-content {
|
||||
max-width: 800px;
|
||||
margin: 80px auto 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.print-title {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
h2 {
|
||||
font-size: 22px;
|
||||
margin-bottom: 8px;
|
||||
color: #303133;
|
||||
}
|
||||
.order-no {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.print-section {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #409eff;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.info-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
td {
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
border: 1px solid #ebeef5;
|
||||
}
|
||||
.label {
|
||||
width: 100px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
background: #f5f7fa;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
th,
|
||||
td {
|
||||
padding: 8px 10px;
|
||||
font-size: 13px;
|
||||
border: 1px solid #ebeef5;
|
||||
}
|
||||
th {
|
||||
background: #f5f7fa;
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
tfoot td {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
}
|
||||
|
||||
.product-info {
|
||||
.info-item {
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
color: #909399;
|
||||
}
|
||||
.info-key {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.remark-text {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
line-height: 1.6;
|
||||
padding: 10px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.print-footer {
|
||||
text-align: right;
|
||||
margin-top: 30px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px dashed #dcdfe6;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 100px 0;
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #909399;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 打印样式 */
|
||||
@media print {
|
||||
.no-print {
|
||||
display: none !important;
|
||||
}
|
||||
.print-content {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
}
|
||||
.order-print-page {
|
||||
padding: 10px;
|
||||
}
|
||||
.section-title {
|
||||
border-bottom-color: #000;
|
||||
}
|
||||
.info-table .label {
|
||||
background: #eee;
|
||||
}
|
||||
.goods-table th,
|
||||
.goods-table tfoot td {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
330
mer_plat_admin/src/views/merchantOrder/orderSend.vue
Normal file
330
mer_plat_admin/src/views/merchantOrder/orderSend.vue
Normal file
@@ -0,0 +1,330 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="modals"
|
||||
:close-on-click-modal="false"
|
||||
:title="secondType !== OrderSecondTypeEnum.Fictitious ? '订单发送货' : '虚拟商品发货'"
|
||||
class="order_box"
|
||||
:before-close="handleClose"
|
||||
width="900px"
|
||||
>
|
||||
<el-form v-if="modals" ref="formItem" :model="formItem" label-width="95px" @submit.native.prevent :rules="rules">
|
||||
<el-form-item v-show="secondType !== OrderSecondTypeEnum.Fictitious" label="配送方式:" prop="deliveryType">
|
||||
<el-radio-group v-model="formItem.deliveryType" @change="changeRadio(formItem.deliveryType)" v-removeAriaHidden>
|
||||
<el-radio label="express">快递配送</el-radio>
|
||||
<el-radio label="noNeed">无需发货</el-radio>
|
||||
<el-radio label="merchant">商家送货</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<SendFrom :formItem="formItem" :isShowBtn="true"></SendFrom>
|
||||
<el-form-item v-show="secondType !== OrderSecondTypeEnum.Fictitious" label="分单发货:" prop="isSplit">
|
||||
<el-switch
|
||||
v-model="formItem.isSplit"
|
||||
:active-value="true"
|
||||
:inactive-value="false"
|
||||
active-text="开启"
|
||||
inactive-text="关闭"
|
||||
/>
|
||||
<p v-show="formItem.isSplit" class="from-tips">可选择表格中的商品单独发货,请谨慎操作!</p>
|
||||
</el-form-item>
|
||||
<template v-if="formItem.isSplit">
|
||||
<el-table
|
||||
style="padding-left: 75px"
|
||||
ref="multipleSelection"
|
||||
:data="productList"
|
||||
tooltip-effect="dark"
|
||||
class="tableSelection"
|
||||
size="small"
|
||||
:row-key="
|
||||
(row) => {
|
||||
return row.id;
|
||||
}
|
||||
"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" :selectable="selectable" :reserve-selection="true" min-width="50" />
|
||||
<el-table-column label="商品信息" width="200">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row" style="align-items: center">
|
||||
<div class="demo-image__preview line-heightOne refundImg">
|
||||
<el-image :src="scope.row.image" :preview-src-list="[scope.row.image]" />
|
||||
<span class="priceBox product-info-text" style="width: 120px">{{ scope.row.productName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<span class="priceBox">{{ scope.row.sku }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总数(件)" min-width="80">
|
||||
<template slot-scope="scope">
|
||||
<span class="priceBox">{{ scope.row.payNum }}</span>
|
||||
<div class="priceBox textE93323">已发{{ scope.row.deliveryNum }}</div>
|
||||
<div class="priceBox textE93323">已退款{{ scope.row.refundNum }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发货数量(件)" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
:disabled="scope.row.deliveryNum === scope.row.payNum"
|
||||
v-model.trim="scope.row['num']"
|
||||
:min="1"
|
||||
:max="
|
||||
Number(scope.row.deliveryNum) == 0
|
||||
? Number(scope.row.payNum) - Number(scope.row.refundNum)
|
||||
: Number(scope.row.payNum) - Number(scope.row.deliveryNum)
|
||||
"
|
||||
class="priceBox"
|
||||
:step="1"
|
||||
@blur="limitCount(scope.row, scope.$index)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-btn-top">
|
||||
<el-button @click="cancel('formItem')">取消</el-button>
|
||||
<el-button type="primary" @click="putSend('formItem')">提交</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import { merchantOrderProDetailApi as orderProDetailApi, merchantOrderSendApi as orderSendApi } from '@/api/merchantOrder';
|
||||
import { checkPermi } from '@/utils/permission'; // 权限判断函数
|
||||
import { Debounce } from '@/utils/validate';
|
||||
import SendFrom from './components/sendFrom';
|
||||
import { useLogistics } from '@/hooks/use-order';
|
||||
import { postRules } from '@/views/merchantOrder/default';
|
||||
import { OrderSecondTypeEnum } from '@/enums/productEnums';
|
||||
const defaultObj = {
|
||||
deliveryType: 'express',
|
||||
isSplit: false,
|
||||
deliveryMark: '',
|
||||
carrierPhone: '',
|
||||
deliveryCarrier: '',
|
||||
expressCode: '',
|
||||
expressNumber: '',
|
||||
orderNo: '',
|
||||
detailList: [],
|
||||
// deliveryType: 'express',
|
||||
expressRecordType: '1', // 1=手动填写 2=电子面单
|
||||
// expressCode: '',
|
||||
company: '', //快递公司
|
||||
deliveryName: '',
|
||||
deliveryTel: '',
|
||||
expressName: '',
|
||||
// expressNumber: '',
|
||||
expressTempId: '',
|
||||
toAddr: '',
|
||||
toName: '',
|
||||
toTel: '',
|
||||
// orderNo: '',
|
||||
shipment: {
|
||||
sendRealName: '',
|
||||
sendPhone: '',
|
||||
sendAddress: '',
|
||||
kuaidicom: '', //快递公司编码
|
||||
serviceType: '', //快递业务类型
|
||||
pickupStartTime: '', // 取件开始时间
|
||||
pickupEndTime: '', // 取件结束时间
|
||||
tempid: '', //电子面单模板id
|
||||
dayType: 1, //时间
|
||||
},
|
||||
};
|
||||
export default {
|
||||
name: 'orderSend',
|
||||
components: { SendFrom },
|
||||
props: {
|
||||
orderNo: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
secondType: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
modals: {
|
||||
handler(nVal, oVal) {
|
||||
if (nVal) {
|
||||
if (this.secondType === this.OrderSecondTypeEnum.Fictitious) this.formItem.deliveryType = 'noNeed';
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
OrderSecondTypeEnum: OrderSecondTypeEnum,
|
||||
productList: [],
|
||||
formItem: { ...defaultObj },
|
||||
modals: false,
|
||||
express: [],
|
||||
exportTempList: [],
|
||||
tempImg: '',
|
||||
rules: postRules,
|
||||
multipleSelection: [],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getList();
|
||||
if (this.secondType === this.OrderSecondTypeEnum.Integral) this.formItem.deliveryType = 'noNeed';
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
//决定这一行的 CheckBox 是否可以勾选
|
||||
selectable(row, index) {
|
||||
if (row.deliveryNum === row.payNum) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
limitCount(row, i) {
|
||||
if (row.num > row.payNum) row.num = row.payNum;
|
||||
},
|
||||
// 分单发货选择商品
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
changeRadio(o) {
|
||||
this.formItem.deliveryType = o;
|
||||
this.$nextTick(function () {
|
||||
this.$refs.formItem.clearValidate();
|
||||
});
|
||||
},
|
||||
// 商品信息
|
||||
orderProDetail(orderNo) {
|
||||
orderProDetailApi(orderNo).then(async (res) => {
|
||||
this.productList = res;
|
||||
this.productList.map((item) => this.$set(item, 'num', 1));
|
||||
});
|
||||
},
|
||||
// 物流公司列表
|
||||
async getList() {
|
||||
const params = {
|
||||
keywords: '',
|
||||
page: 1,
|
||||
limit: 50,
|
||||
openStatus: true,
|
||||
};
|
||||
this.express = await useLogistics(params);
|
||||
this.express.map((item) => {
|
||||
if (item.isDefault) this.formItem.expressCode = item.code;
|
||||
});
|
||||
},
|
||||
// 提交
|
||||
putSend: Debounce(function (name) {
|
||||
let data = {};
|
||||
let attr = [];
|
||||
this.formItem.orderNo = this.orderNo;
|
||||
this.multipleSelection.map((item) => {
|
||||
attr.push({ orderDetailId: item.id, num: item.num });
|
||||
});
|
||||
this.formItem.detailList = attr;
|
||||
if (!this.formItem.isSplit) {
|
||||
data = { ...this.formItem };
|
||||
delete data.detailList;
|
||||
} else {
|
||||
if (!this.formItem.detailList.length) return this.$message.warning('请选择分单发货商品');
|
||||
let flag = false;
|
||||
this.formItem.detailList.map((item) => {
|
||||
if (!item.num) {
|
||||
flag = true;
|
||||
}
|
||||
});
|
||||
if (flag) {
|
||||
this.$message.warning('请填写发货数量');
|
||||
return;
|
||||
}
|
||||
data = this.formItem;
|
||||
}
|
||||
if (this.formItem.expressRecordType == '2') {
|
||||
if (!this.formItem.toAddr) {
|
||||
this.$message.warning('请填写寄件人地址');
|
||||
return;
|
||||
}
|
||||
if (!this.formItem.toTel) {
|
||||
this.$message.warning('请填写寄件人电话');
|
||||
return;
|
||||
}
|
||||
if (!this.formItem.toName) {
|
||||
this.$message.warning('请填写寄件人姓名');
|
||||
return;
|
||||
}
|
||||
if (!this.formItem.expressTempId) {
|
||||
this.$message.warning('请选择电子面单');
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.$refs[name].validate((valid) => {
|
||||
if (valid) {
|
||||
orderSendApi(data).then((async) => {
|
||||
this.$message.success('发货成功');
|
||||
this.cancel();
|
||||
this.$emit('submitFail');
|
||||
});
|
||||
} else {
|
||||
this.$message.error('请填写信息');
|
||||
}
|
||||
});
|
||||
}),
|
||||
handleClose() {
|
||||
this.cancel();
|
||||
},
|
||||
cancel() {
|
||||
this.modals = false;
|
||||
this.formItem = { ...defaultObj, expressCode: this.formItem.expressCode };
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.width8 {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.width9 {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.tempImgList {
|
||||
// opacity: 1;
|
||||
width: 38px !important;
|
||||
height: 30px !important;
|
||||
// margin-top: -30px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
z-index: 11;
|
||||
img {
|
||||
width: 38px !important;
|
||||
height: 30px !important;
|
||||
}
|
||||
}
|
||||
.refundImg {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.product-info-text {
|
||||
display: block;
|
||||
white-space: nowrap; /* 确保文本在一行内显示 */
|
||||
overflow: hidden; /* 超出容器部分隐藏 */
|
||||
text-overflow: ellipsis; /* 使用省略号表示被截断的文本 */
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
125
mer_plat_admin/src/views/merchantOrder/orderVideoSend.vue
Normal file
125
mer_plat_admin/src/views/merchantOrder/orderVideoSend.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<el-dialog :visible.sync="modals" title="发货" class="order_box" :before-close="handleClose" width="600px">
|
||||
<el-form ref="formItem" :model="formItem" label-width="110px" @submit.native.prevent :rules="rules">
|
||||
<el-form-item label="快递公司:" prop="expressCode">
|
||||
<el-select v-model="formItem.deliveryId" filterable style="width: 80%">
|
||||
<el-option
|
||||
v-for="(item, i) in express"
|
||||
:value="item.deliveryId"
|
||||
:key="i"
|
||||
:label="item.deliveryName"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="快递单号:" prop="waybillId">
|
||||
<el-input v-model.trim="formItem.waybillId" placeholder="请输入快递单号" style="width: 80%"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="mini" type="primary" @click="putSend('formItem')" v-hasPermi="['merchant:order:send']"
|
||||
>提交</el-button
|
||||
>
|
||||
<el-button size="mini" @click="cancel('formItem')">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import { merchantVideoSendApi as videoSendApi, merchantSheetInfoApi as sheetInfoApi, merchantCompanyGetListApi as companyGetListApi } from '@/api/merchantOrder';
|
||||
import { Debounce } from '@/utils/validate';
|
||||
export default {
|
||||
name: 'orderSend',
|
||||
props: {
|
||||
orderId: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formItem: {
|
||||
deliveryId: '',
|
||||
orderNo: '',
|
||||
waybillId: '',
|
||||
},
|
||||
modals: false,
|
||||
express: [],
|
||||
exportTempList: [],
|
||||
tempImg: '',
|
||||
rules: {
|
||||
deliveryId: [{ required: true, message: '请选择快递公司', trigger: 'change' }],
|
||||
waybillId: [{ required: true, message: '请输入快递单号', trigger: 'blur' }],
|
||||
},
|
||||
expressType: 'normal',
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.express = JSON.parse(sessionStorage.getItem('videoExpress'));
|
||||
},
|
||||
methods: {
|
||||
// 视频号快递公司
|
||||
companyGetList() {
|
||||
companyGetListApi().then(async (res) => {
|
||||
this.express = res;
|
||||
sessionStorage.setItem('videoExpress', JSON.stringify(res));
|
||||
});
|
||||
},
|
||||
// 提交
|
||||
putSend: Debounce(function (name) {
|
||||
this.formItem.orderNo = this.orderId;
|
||||
this.$refs[name].validate((valid) => {
|
||||
if (valid) {
|
||||
videoSendApi(this.formItem).then((async) => {
|
||||
this.$message.success('发货成功');
|
||||
this.modals = false;
|
||||
this.$refs[name].resetFields();
|
||||
this.$emit('submitFail');
|
||||
});
|
||||
} else {
|
||||
this.$message.error('请填写信息');
|
||||
}
|
||||
});
|
||||
}),
|
||||
handleClose() {
|
||||
this.cancel('formItem');
|
||||
},
|
||||
cancel(name) {
|
||||
this.modals = false;
|
||||
this.$refs[name].resetFields();
|
||||
this.formItem.type = '1';
|
||||
this.formItem.expressRecordType = '1';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.width8 {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.width9 {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.tempImgList {
|
||||
// opacity: 1;
|
||||
width: 38px !important;
|
||||
height: 30px !important;
|
||||
// margin-top: -30px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
z-index: 11;
|
||||
img {
|
||||
width: 38px !important;
|
||||
height: 30px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
639
mer_plat_admin/src/views/merchantOrder/refund/index.vue
Normal file
639
mer_plat_admin/src/views/merchantOrder/refund/index.vue
Normal file
@@ -0,0 +1,639 @@
|
||||
<template>
|
||||
<div class="divBox relative">
|
||||
<el-card
|
||||
:bordered="false"
|
||||
shadow="never"
|
||||
class="ivu-mt"
|
||||
:body-style="{ padding: 0 }"
|
||||
v-if="checkPermi(['merchant:refund:order:page:list'])"
|
||||
>
|
||||
<div class="padding-add">
|
||||
<el-form size="small" inline label-position="right" @submit.native.prevent>
|
||||
<el-form-item label="退款单号:">
|
||||
<el-input
|
||||
v-model.trim="tableFrom.refundOrderNo"
|
||||
placeholder="请输入退款单号"
|
||||
class="form_content_width"
|
||||
size="small"
|
||||
clearable
|
||||
@keyup.enter.native="handleSearchList"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号:" label-width="66px">
|
||||
<el-input
|
||||
v-model.trim="tableFrom.orderNo"
|
||||
placeholder="请输入订单号"
|
||||
class="form_content_width"
|
||||
size="small"
|
||||
clearable
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间选择:">
|
||||
<el-date-picker
|
||||
v-model="timeVal"
|
||||
value-format="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd"
|
||||
size="small"
|
||||
type="daterange"
|
||||
placement="bottom-end"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
class="form_content_width"
|
||||
@change="onchangeTime"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户搜索:" label-for="nickname">
|
||||
<UserSearchInput v-model="tableFrom" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退货物流:" label-width="66px">
|
||||
<el-input
|
||||
v-model.trim="tableFrom.trackingNumber"
|
||||
placeholder="请输入退货物流单号"
|
||||
class="selWidth"
|
||||
size="small"
|
||||
clearable
|
||||
@keyup.enter.native="handleSearchList"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="small" @click="handleSearchList">查询</el-button>
|
||||
<el-button size="small" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card class="box-card mt14" :body-style="{ padding: '0 20px 20px',position: 'relative' }" shadow="never" :bordered="false">
|
||||
<el-tabs class="list-tabs" v-model="tableFrom.refundStatus" @tab-click="handleSearchList">
|
||||
<el-tab-pane name="9" :label="`全部(${orderChartType.all || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="0" :label="`待审核(${orderChartType.await || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="2" :label="`退款中(${orderChartType.refunding || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="4" :label="`用户退货(${orderChartType.awaitReturning || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="5" :label="`商家待收货(${orderChartType.awaitReceiving || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="6" :label="`已撤销(${orderChartType.revoke || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="1" :label="`审核未通过(${orderChartType.reject || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="3" :label="`已退款(${orderChartType.refunded || 0})`"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
:data="tableData.data"
|
||||
size="small"
|
||||
class="table mt5"
|
||||
highlight-current-row
|
||||
:row-key="
|
||||
(row) => {
|
||||
return row.refundOrderNo;
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-table-column label="退款单号" min-width="185" v-if="checkedCities.includes('退款单号')">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row">
|
||||
<span v-show="scope.row.type === 1" class="iconfont icon-shipinhao mr5" style="color: #f6ae02"></span>
|
||||
<span style="display: block" v-text="scope.row.refundOrderNo" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="orderNo" label="订单号" min-width="180" v-if="checkedCities.includes('订单号')" />
|
||||
<el-table-column
|
||||
prop="userNickName"
|
||||
label="用户昵称"
|
||||
min-width="180"
|
||||
v-if="checkedCities.includes('用户昵称')"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="refundPrice"
|
||||
label="退款金额"
|
||||
min-width="100"
|
||||
v-if="checkedCities.includes('退款金额')"
|
||||
/>
|
||||
<el-table-column label="退款状态" min-width="100" v-if="checkedCities.includes('退款状态')">
|
||||
<template slot-scope="scope">
|
||||
<span :class="tagClass[scope.row.refundStatus]" class="tag-padding">{{
|
||||
scope.row.refundStatus | refundStatusFilter
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="售后类型" min-width="100" v-if="checkedCities.includes('售后类型')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.afterSalesType === 1 ? '仅退款' : '退货退款' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="退货类型" min-width="100" v-if="checkedCities.includes('退货类型')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{
|
||||
scope.row.returnGoodsType === 0 ? '不退货' : scope.row.returnGoodsType === 1 ? '快递退回' : '到店退货'
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="强制退款" min-width="100" v-if="checkedCities.includes('强制退款')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.isCompulsoryRefund ? '是' : '不是' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="150" v-if="checkedCities.includes('创建时间')" />
|
||||
<el-table-column width="190" fixed="right">
|
||||
<template slot="header">
|
||||
<p>
|
||||
<span style="padding-right: 5px">操作</span>
|
||||
<i class="el-icon-setting" @click="handleAddItem"></i>
|
||||
</p>
|
||||
</template>
|
||||
<!-- 售后状态:0:待审核 1:商家拒绝 2:退款中 3:已退款 4:用户退货 5:商家待收货 6:已撤销 9:全部-->
|
||||
<template slot-scope="scope">
|
||||
<a
|
||||
v-if="
|
||||
scope.row.refundStatus !== 0 &&
|
||||
scope.row.refundStatus !== 5 &&
|
||||
checkPermi(['merchant:refund:order:detail'])
|
||||
"
|
||||
@click="onOrderDetails(scope.row)"
|
||||
>详情</a
|
||||
>
|
||||
<template v-if="scope.row.refundStatus === 0 && checkPermi(['merchant:refund:order:audit'])">
|
||||
<a @click="handleApprovedReview(scope.row)">同意</a>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
</template>
|
||||
<template v-if="scope.row.refundStatus === 0 && checkPermi(['merchant:refund:order:audit'])">
|
||||
<a @click="handleOrderRefuse(scope.row)">拒绝</a>
|
||||
</template>
|
||||
<template v-if="scope.row.refundStatus === 5 && checkPermi(['merchant:refund:order:receiving:reject'])">
|
||||
<a @click="handleRefuseReceipt(scope.row)">拒绝</a>
|
||||
</template>
|
||||
<template v-if="scope.row.refundStatus === 5 && checkPermi(['merchant:refund:order:receiving'])">
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a
|
||||
v-debounceClick="
|
||||
() => {
|
||||
handleConfirmReceipt(scope.row.refundOrderNo);
|
||||
}
|
||||
"
|
||||
>确认收货</a
|
||||
>
|
||||
</template>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-dropdown trigger="click" v-if="scope.row.refundStatus === 0 || scope.row.refundStatus === 5">
|
||||
<span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right" /> </span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item
|
||||
v-if="checkPermi(['merchant:refund:order:detail'])"
|
||||
@click.native="onOrderDetails(scope.row)"
|
||||
>详情
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
@click.native="onOrderMark(scope.row)"
|
||||
v-if="checkPermi(['merchant:refund:order:mark'])"
|
||||
>备注
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<a
|
||||
@click="onOrderMark(scope.row)"
|
||||
v-if="
|
||||
checkPermi(['merchant:refund:order:mark']) &&
|
||||
scope.row.refundStatus !== 0 &&
|
||||
scope.row.refundStatus !== 5
|
||||
"
|
||||
>备注</a
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="block">
|
||||
<el-pagination
|
||||
background
|
||||
:page-sizes="$constants.page.limit"
|
||||
:page-size="tableFrom.limit"
|
||||
:current-page="tableFrom.page"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableData.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="card_abs" v-show="card_select_show">
|
||||
<template>
|
||||
<div class="cell_ht">
|
||||
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange"
|
||||
>全选
|
||||
</el-checkbox>
|
||||
<el-button type="text" @click="checkSave()">保存</el-button>
|
||||
</div>
|
||||
<el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
|
||||
<el-checkbox v-for="item in columnData" :label="item" :key="item" class="check_cell">{{ item }}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</template>
|
||||
</div>
|
||||
</el-card>
|
||||
<!--退款详情-->
|
||||
<refund-order-detail
|
||||
ref="orderDetail"
|
||||
:drawerVisible="drawerVisible"
|
||||
:refundOrderNo="refundOrderNo"
|
||||
v-if="drawerVisible"
|
||||
@onClosedrawerVisible="onClosedrawerVisible"
|
||||
@getReviewSuccessful="getReviewSuccessful"
|
||||
></refund-order-detail>
|
||||
|
||||
<!-- 同意退款,退货退款-->
|
||||
<el-dialog
|
||||
title="同意退款"
|
||||
:visible.sync="dialogVisibleAgreeToReturn"
|
||||
width="900px"
|
||||
:before-close="handleCloseAgreeToReturn"
|
||||
class="dialog-bottom"
|
||||
>
|
||||
<agree-to-return
|
||||
ref="agreeToReturn"
|
||||
@onHandleCancel="handleCloseAgreeToReturn"
|
||||
@onHandleSuccess="handleSuccess"
|
||||
:refundInfo="refundInfo"
|
||||
v-if="dialogVisibleAgreeToReturn"
|
||||
></agree-to-return>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import {
|
||||
merchantRefundStatusNumApi as refundStatusNumApi,
|
||||
merchantRefundListApi as refundListApi,
|
||||
merchantRefundMarkApi as refundMarkApi,
|
||||
orderPrint,
|
||||
merchantOrderAuditApi as orderAuditApi,
|
||||
merchantRefundOrderReceivingRejectApi as refundOrderReceivingRejectApi,
|
||||
} from '@/api/merchantOrder';
|
||||
import { isWriteOff } from '@/utils';
|
||||
import { orderExcelApi } from '@/api/product';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import RefundOrderDetail from '../components/refundOrderDetail.vue';
|
||||
import { refundStatusFilter } from '@/filters';
|
||||
import useRefundOrder from '@/libs/useRefundOrder';
|
||||
import AgreeToReturn from '@/views/merchantOrder/components/agreeToReturn.vue';
|
||||
import * as $constants from '@/utils/constants';
|
||||
const { onConfirmReceipt, onApprovedReview } = useRefundOrder();
|
||||
const tableFroms = {
|
||||
refundStatus: '9',
|
||||
dateLimit: '',
|
||||
orderNo: '',
|
||||
refundOrderNo: '',
|
||||
page: 1,
|
||||
limit: $constants.page.limit[0],
|
||||
searchType: 'all',
|
||||
content: '',
|
||||
trackingNumber: '',
|
||||
};
|
||||
// 权限判断函数
|
||||
export default {
|
||||
name: 'orderRefund',
|
||||
components: {
|
||||
AgreeToReturn,
|
||||
RefundOrderDetail,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
datekey: Date.now(),
|
||||
RefuseData: {},
|
||||
refundOrderNo: '', //退款单号
|
||||
refundData: {},
|
||||
tableDataLog: {
|
||||
data: [],
|
||||
total: 0,
|
||||
},
|
||||
LogLoading: false,
|
||||
isCreate: 1,
|
||||
editData: null,
|
||||
dialogVisible: false,
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
},
|
||||
listLoading: true,
|
||||
tableFrom: Object.assign({}, tableFroms),
|
||||
orderChartType: {},
|
||||
timeVal: [],
|
||||
fromList: this.$constants.fromList,
|
||||
selectionList: [],
|
||||
ids: '',
|
||||
orderids: '',
|
||||
cardLists: [],
|
||||
isWriteOff: isWriteOff(),
|
||||
proType: 0,
|
||||
active: false,
|
||||
card_select_show: false,
|
||||
checkAll: true,
|
||||
checkedCities: [
|
||||
'退款单号',
|
||||
'订单号',
|
||||
'用户昵称',
|
||||
'退款金额',
|
||||
'退款状态',
|
||||
'售后类型',
|
||||
'退货类型',
|
||||
'强制退款',
|
||||
'创建时间',
|
||||
],
|
||||
columnData: [
|
||||
'退款单号',
|
||||
'订单号',
|
||||
'用户昵称',
|
||||
'退款金额',
|
||||
'退款状态',
|
||||
'售后类型',
|
||||
'退货类型',
|
||||
'强制退款',
|
||||
'创建时间',
|
||||
],
|
||||
isIndeterminate: false,
|
||||
dialogVisibleAgreeToReturn: false,
|
||||
refundInfo: null,
|
||||
drawerVisible: false,
|
||||
tagClass: ['doingTag', 'notStartTag', 'doingTag', 'endTag', 'notStartTag', 'doingTag', 'endTag'],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (checkPermi(['merchant:refund:order:page:list'])) this.getList();
|
||||
if (checkPermi(['merchant:refund:order:status:num'])) this.getOrderStatusNum();
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
//商家确认收货
|
||||
handleConfirmReceipt(refundOrderNo) {
|
||||
onConfirmReceipt(refundOrderNo).then(() => {
|
||||
this.handleSearchList();
|
||||
});
|
||||
},
|
||||
//审核同意
|
||||
handleApprovedReview(row) {
|
||||
if (row.returnGoodsType !== 1) {
|
||||
onApprovedReview({
|
||||
auditType: 'success',
|
||||
refundOrderNo: row.refundOrderNo,
|
||||
}).then(() => {
|
||||
this.handleSearchList();
|
||||
});
|
||||
} else {
|
||||
//退货退款
|
||||
this.refundInfo = row;
|
||||
this.dialogVisibleAgreeToReturn = true;
|
||||
}
|
||||
},
|
||||
//审核成功回调
|
||||
handleSuccess() {
|
||||
this.dialogVisibleAgreeToReturn = false;
|
||||
this.handleSearchList();
|
||||
},
|
||||
//同意弹窗
|
||||
handleCloseAgreeToReturn() {
|
||||
this.dialogVisibleAgreeToReturn = false;
|
||||
},
|
||||
//审核拒绝
|
||||
handleOrderRefuse(row) {
|
||||
this.$modalPrompt('textarea', '拒绝退款原因', null).then((V) => {
|
||||
orderAuditApi({ auditType: 'refuse', reason: V, refundOrderNo: row.refundOrderNo }).then(() => {
|
||||
this.$message.success('审核成功');
|
||||
this.handleSearchList();
|
||||
});
|
||||
});
|
||||
},
|
||||
//拒绝收货
|
||||
handleRefuseReceipt(row) {
|
||||
this.$modalPrompt('textarea', '拒绝收货原因', null).then((V) => {
|
||||
refundOrderReceivingRejectApi({ reason: V, refundOrderNo: row.refundOrderNo }).then(() => {
|
||||
this.$message.success('拒绝收货成功');
|
||||
this.handleSearchList();
|
||||
});
|
||||
});
|
||||
},
|
||||
//重置
|
||||
handleReset() {
|
||||
this.tableFrom.dateLimit = '';
|
||||
this.tableFrom.orderNo = '';
|
||||
this.tableFrom.refundOrderNo = '';
|
||||
this.tableFrom.content = '';
|
||||
this.tableFrom.searchType = 'all';
|
||||
this.tableFrom.trackingNumber = '';
|
||||
this.selectChange();
|
||||
},
|
||||
//搜索
|
||||
handleSearchList() {
|
||||
this.tableFrom.page = 1;
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
},
|
||||
onClosedrawerVisible() {
|
||||
this.drawerVisible = false;
|
||||
},
|
||||
//详情中审核成功回调
|
||||
getReviewSuccessful() {
|
||||
this.handleSearchList();
|
||||
},
|
||||
// 详情
|
||||
onOrderDetails(row) {
|
||||
this.refundOrderNo = row.refundOrderNo;
|
||||
this.drawerVisible = true;
|
||||
},
|
||||
// 备注
|
||||
onOrderMark(row) {
|
||||
this.$modalPrompt('textarea', '备注', row.merRemark, '退款单备注').then((V) => {
|
||||
refundMarkApi({ remark: V, refundOrderNo: row.refundOrderNo }).then(() => {
|
||||
this.$message.success('操作成功');
|
||||
this.getList();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.selectionList = val;
|
||||
const data = [];
|
||||
this.selectionList.map((item) => {
|
||||
data.push(item.orderNo);
|
||||
});
|
||||
this.ids = data.join(',');
|
||||
},
|
||||
// 选择时间
|
||||
selectChange(tab) {
|
||||
this.timeVal = [];
|
||||
this.tableFrom.page = 1;
|
||||
this.handleSearchList();
|
||||
},
|
||||
// 具体日期
|
||||
onchangeTime(e) {
|
||||
this.timeVal = e;
|
||||
this.tableFrom.dateLimit = e ? this.timeVal.join(',') : '';
|
||||
this.handleSearchList();
|
||||
},
|
||||
// 列表
|
||||
getList() {
|
||||
this.listLoading = true;
|
||||
refundListApi(this.tableFrom)
|
||||
.then((res) => {
|
||||
this.tableData.data = res.list || [];
|
||||
this.tableData.total = res.total;
|
||||
this.listLoading = false;
|
||||
this.checkedCities = this.$cache.local.has('order_refund_stroge')
|
||||
? this.$cache.local.getJSON('order_refund_stroge')
|
||||
: this.checkedCities;
|
||||
})
|
||||
.catch(() => {
|
||||
this.listLoading = false;
|
||||
});
|
||||
},
|
||||
// 获取各状态数量
|
||||
getOrderStatusNum() {
|
||||
let data = Object.assign({}, this.tableFrom);
|
||||
delete data.page;
|
||||
delete data.limit;
|
||||
delete data.refundStatus;
|
||||
refundStatusNumApi(data).then((res) => {
|
||||
this.orderChartType = res;
|
||||
});
|
||||
},
|
||||
pageChange(page) {
|
||||
this.tableFrom.page = page;
|
||||
this.getList();
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.tableFrom.limit = val;
|
||||
this.getList();
|
||||
},
|
||||
exports() {
|
||||
let data = {
|
||||
dateLimit: this.tableFrom.dateLimit,
|
||||
orderNo: this.tableFrom.orderNo,
|
||||
refundStatus: this.tableFrom.status,
|
||||
type: this.tableFrom.type,
|
||||
};
|
||||
orderExcelApi(data).then((res) => {
|
||||
window.open(res.fileName);
|
||||
});
|
||||
},
|
||||
handleAddItem() {
|
||||
if (this.card_select_show) {
|
||||
this.$set(this, 'card_select_show', false);
|
||||
} else if (!this.card_select_show) {
|
||||
this.$set(this, 'card_select_show', true);
|
||||
}
|
||||
},
|
||||
handleCheckAllChange(val) {
|
||||
this.checkedCities = val ? this.columnData : [];
|
||||
this.isIndeterminate = false;
|
||||
},
|
||||
handleCheckedCitiesChange(value) {
|
||||
let checkedCount = value.length;
|
||||
this.checkAll = checkedCount === this.columnData.length;
|
||||
this.isIndeterminate = checkedCount > 0 && checkedCount < this.columnData.length;
|
||||
},
|
||||
checkSave() {
|
||||
this.$set(this, 'card_select_show', false);
|
||||
this.$modal.loading('正在保存到本地,请稍候...');
|
||||
this.$cache.local.setJSON('order_refund_stroge', this.checkedCities);
|
||||
setTimeout(this.$modal.closeLoading(), 1000);
|
||||
},
|
||||
//打印小票
|
||||
onOrderPrint(data) {
|
||||
orderPrint(data.orderNo)
|
||||
.then((res) => {
|
||||
this.$modal.msgSuccess('打印成功');
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$modal.msgError(error.message);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .el-card{
|
||||
overflow: auto !important;
|
||||
}
|
||||
.card_abs{
|
||||
top: 123px !important;
|
||||
}
|
||||
.red {
|
||||
color: #ed4014;
|
||||
}
|
||||
.el-table__body {
|
||||
width: 100%;
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
|
||||
.demo-table-expand {
|
||||
::v-deep .label {
|
||||
width: 83px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.refunding {
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.el-icon-arrow-down {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tabBox_tit {
|
||||
font-size: 12px !important;
|
||||
/*margin: 0 2px 0 10px;*/
|
||||
letter-spacing: 1px;
|
||||
/*padding: 5px 0;*/
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.text_overflow {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.pup_card {
|
||||
width: 200px;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.cell_ht {
|
||||
height: 50px;
|
||||
padding: 15px 20px;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.check_cell {
|
||||
width: 100%;
|
||||
padding: 15px 20px 0;
|
||||
}
|
||||
|
||||
::v-deep .el-checkbox__input.is-checked + .el-checkbox__label {
|
||||
color: #606266;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog title="选择服务人员" :visible.sync="dialogTableVisible" :before-close="handleClose" width="600px">
|
||||
<div class="mb10">
|
||||
员工搜索:
|
||||
<el-input
|
||||
v-model.trim="keywords"
|
||||
placeholder="请输入员工姓名或手机号搜索"
|
||||
clearable
|
||||
class="form_content_width"
|
||||
/>
|
||||
<el-button type="primary" size="mini" class="ml20" @click="getSelectStaff">查询</el-button>
|
||||
</div>
|
||||
<el-table :data="staffList" height="400px">
|
||||
<el-table-column width="55">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="staffId == scope.row.id" class="iconfont icon-xuanzhong11" @click="iconChange(scope.row.id)" />
|
||||
<span v-else class="iconfont icon-weixuan" @click="iconChange(scope.row.id)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="id" label="Id" min-width="80"> </el-table-column>
|
||||
<el-table-column property="name" label="服务人员" min-width="150"></el-table-column>
|
||||
<el-table-column property="phone" label="手机号码" min-width="150"></el-table-column>
|
||||
</el-table>
|
||||
<div class="mt10" slot="footer">
|
||||
<el-button @click="handleClose()" size="small">取消</el-button>
|
||||
<el-button type="primary" size="small" @click="submitOk()">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { serviceStaffListApi } from '@/api/staff';
|
||||
import { merchantWorkOrderAssignApi as workOrderAssignApi, merchantWorkOrderReassignApi as workOrderReassignApi } from '@/api/merchantReservation';
|
||||
export default {
|
||||
props: {
|
||||
workOrderNoList: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keywords: '',
|
||||
staffList: [],
|
||||
staffId: '', // 服务人员id
|
||||
type: '',
|
||||
dialogTableVisible: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 选择服务人员
|
||||
async getSelectStaff() {
|
||||
let res = await serviceStaffListApi({
|
||||
page: 1,
|
||||
limit: 999,
|
||||
status: 1,
|
||||
keywords: encodeURIComponent(this.keywords),
|
||||
});
|
||||
this.staffList = res.list;
|
||||
},
|
||||
handleClose() {
|
||||
this.dialogTableVisible = false;
|
||||
this.staffId = '';
|
||||
},
|
||||
iconChange(id) {
|
||||
this.staffId = id;
|
||||
},
|
||||
submitOk() {
|
||||
if (!this.staffId) return this.$message.warning('请选择服务人员');
|
||||
this.$modalSure('确认派单给该服务人员吗?').then(() => {
|
||||
this.type === 1
|
||||
? workOrderAssignApi({ serviceStaffId: this.staffId, workOrderNoList: this.workOrderNoList }).then((data) => {
|
||||
this.$message.success('派单成功');
|
||||
this.$emit('selectStaff');
|
||||
this.handleClose();
|
||||
})
|
||||
: workOrderReassignApi({ serviceStaffId: this.staffId, workOrderNoList: this.workOrderNoList }).then(
|
||||
(data) => {
|
||||
this.$message.success('改派成功');
|
||||
this.$emit('selectStaff');
|
||||
this.handleClose();
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
openBox(type) {
|
||||
this.type = type;
|
||||
this.getSelectStaff();
|
||||
this.dialogTableVisible = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.icon-xuanzhong11 {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
color: var(--prev-color-primary);
|
||||
}
|
||||
.icon-weixuan {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
color: #cccccc;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,274 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog title="改约" :visible.sync="dialogTableVisible" width="600px">
|
||||
<div class="form-box">
|
||||
<div class="title mb20">预约信息</div>
|
||||
<el-table v-show="productList.length" :data="productList" size="small" class="mt20 mb20">
|
||||
<el-table-column label="商品信息" min-width="300">
|
||||
<template slot-scope="scope">
|
||||
<div class="tab">
|
||||
<div class="demo-image__preview">
|
||||
<el-image :src="scope.row.image" :preview-src-list="[scope.row.image]" />
|
||||
</div>
|
||||
<div>
|
||||
<div>{{ scope.row.productName }}</div>
|
||||
<div class="line1 gary">规格:{{ scope.row.sku }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-form :model="form" ref="form" :rules="rules" label-width="auto">
|
||||
<el-form-item label="预约时间:" prop="reservationDate">
|
||||
<el-date-picker
|
||||
v-model="form.reservationDate"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="date"
|
||||
format="yyyy-MM-dd"
|
||||
:picker-options="pickerOptions"
|
||||
placeholder="选择日期"
|
||||
style="width: 200px"
|
||||
class="mr10"
|
||||
>
|
||||
</el-date-picker>
|
||||
<el-time-picker
|
||||
is-range
|
||||
value-format="HH:mm"
|
||||
format="HH:mm"
|
||||
type="datetimerange"
|
||||
v-model="reservationTime"
|
||||
placement="bottom-end"
|
||||
placeholder="选择时间"
|
||||
:picker-options="pickerOptions"
|
||||
size="small"
|
||||
style="width: 200px"
|
||||
:clearable="false"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="productList.length" label="服务方式:" prop="serviceType">
|
||||
<el-radio-group v-model="form.serviceType" disabled>
|
||||
<el-radio :label="1">上门服务</el-radio>
|
||||
<el-radio :label="2">到店服务</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="productList.length" label="联系人:" prop="userName">
|
||||
<el-input v-model="form.userName" size="small" placeholder="请输入联系人" style="width: 300px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="productList.length" label="联系电话:" prop="userPhone">
|
||||
<el-input
|
||||
v-model="form.userPhone"
|
||||
size="small"
|
||||
type="number"
|
||||
placeholder="请输入联系电话"
|
||||
style="width: 300px"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="上门地址:" prop="userAddress" v-if="form.serviceType == 1 && productList.length">
|
||||
<el-input
|
||||
v-model="form.userAddress"
|
||||
size="small"
|
||||
placeholder="请输入上门地址"
|
||||
style="width: 300px"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogTableVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitFn">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { merchantWorkOrderUpdateAgreementApi as workOrderUpdateAgreementApi } from '@/api/merchantReservation';
|
||||
|
||||
const cacheAddress = {};
|
||||
export default {
|
||||
name: 'DialogReschedule',
|
||||
props: {
|
||||
orderDetailList: {
|
||||
// 订单详情
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
//商品列表
|
||||
productList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 订单号
|
||||
workOrderNoList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
isBatch: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
disabledDate(time) {
|
||||
return Date.now() - 8.64e7 > time.getTime();
|
||||
},
|
||||
},
|
||||
formInfoData: {},
|
||||
checkList: ['选中且禁用', '复选框 A'],
|
||||
form: {
|
||||
reservationDate: '',
|
||||
reservationTimeSlot: '',
|
||||
serviceType: 1,
|
||||
userName: '',
|
||||
userPhone: '',
|
||||
userAddress: '',
|
||||
workOrderNoList: [],
|
||||
isBatch: false
|
||||
},
|
||||
reservationTime: ["",""], //时间段
|
||||
requiredList: [], // 必填项数据
|
||||
formProps: {},
|
||||
citysData: [], // 所有省市区数据
|
||||
rules: {
|
||||
reservationDate: [{ required: true, message: '请选择日期', trigger: 'blur' }],
|
||||
userName: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
|
||||
userPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
|
||||
userAddress: [{ required: true, message: '请输入上门地址', trigger: 'blur' }],
|
||||
},
|
||||
showPopover: false,
|
||||
dialogTableVisible: false,
|
||||
radio: null, // 初始化 radio 变量
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
orderDetailList: {
|
||||
handler(val) {
|
||||
this.setForm(val);
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
setForm(val) {
|
||||
this.form.reservationDate = val.reservationDate;
|
||||
this.reservationTime = val.reservationTimeSlot ? val.reservationTimeSlot.split('-') : '';
|
||||
this.form.serviceType = val.serviceType;
|
||||
this.form.userName = val.userName;
|
||||
this.form.userPhone = val.userPhone;
|
||||
this.form.userAddress = val.userAddress;
|
||||
},
|
||||
openBox() {
|
||||
// 获取整个省市区数据
|
||||
this.dialogTableVisible = true;
|
||||
if (this.orderDetailList) {
|
||||
this.setForm(this.orderDetailList);
|
||||
}
|
||||
},
|
||||
submitFn() {
|
||||
this.form.workOrderNoList = this.workOrderNoList;
|
||||
this.form.reservationTimeSlot = this.reservationTime.join('-');
|
||||
this.form.isBatch = this.isBatch
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
workOrderUpdateAgreementApi(this.form).then((res) => {
|
||||
this.$message.success('改约成功');
|
||||
this.dialogTableVisible = false;
|
||||
this.$emit('selectStaff');
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.form-box {
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none; /* firefox */
|
||||
-ms-overflow-style: none; /* IE 10+ */
|
||||
.label {
|
||||
.required {
|
||||
color: red;
|
||||
font-size: 13px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.pictrue {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px dotted rgba(0, 0, 0, 0.1);
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.btndel {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
left: 46px;
|
||||
top: -4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.title {
|
||||
padding-left: 10px;
|
||||
border-left: 3px solid var(--prev-color-primary);
|
||||
font-size: 15px;
|
||||
line-height: 15px;
|
||||
color: #303133;
|
||||
}
|
||||
.tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.el-image {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.plan-footer-one {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
background-color: #fff;
|
||||
background-image: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #dcdfe6;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #c0c4cc;
|
||||
display: inline-block;
|
||||
font-size: inherit;
|
||||
min-height: 32px;
|
||||
line-height: 30px;
|
||||
outline: none;
|
||||
font-size: 13px;
|
||||
padding: 0 10px;
|
||||
|
||||
-webkit-transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
width: 100%;
|
||||
}
|
||||
.el-icon-arrow-down {
|
||||
font-weight: 400;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 8px;
|
||||
}
|
||||
.flex-box {
|
||||
display: flex;
|
||||
}
|
||||
.item-box {
|
||||
padding: 5px 10px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,772 @@
|
||||
<template>
|
||||
<div class="h-full relative">
|
||||
<!-- 顶部日期选择组件 -->
|
||||
<!-- <div class="top-date-picker">-->
|
||||
<!-- <el-date-picker-->
|
||||
<!-- v-model="selectedDate"-->
|
||||
<!-- type="date"-->
|
||||
<!-- value-format="yyyy-MM-dd"-->
|
||||
<!-- @change="handleDateChange"-->
|
||||
<!-- placeholder="选择日期"-->
|
||||
<!-- style="margin-bottom: 10px;"-->
|
||||
<!-- >-->
|
||||
<!-- </el-date-picker>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<FullCalendar ref="fullCalendarRef" :options="calendarOptions">
|
||||
<template v-slot:eventContent="arg">
|
||||
<el-tooltip>
|
||||
<div slot="content">
|
||||
<div class="reservation-name flex">
|
||||
<div
|
||||
class="reservation-type border-color"
|
||||
v-if="arg.event.extendedProps.serviceType == 2"
|
||||
>
|
||||
到店
|
||||
</div>
|
||||
<div
|
||||
class="reservation-type border-color"
|
||||
v-else-if="arg.event.extendedProps.serviceType === 1"
|
||||
>
|
||||
上门
|
||||
</div>
|
||||
<div style="display: inline-block" class="name">
|
||||
{{ arg.event.extendedProps.userName }}
|
||||
</div>
|
||||
<div style="display: inline-block" class="phone text-1">
|
||||
{{ arg.event.extendedProps.userPhone }}
|
||||
<span v-if="arg.event.extendedProps.serviceType === 1">
|
||||
{{ arg.event.extendedProps.userAddress }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-1" style="margin-top: 4px;">
|
||||
{{ arg.event.extendedProps.productName }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="reservation-name">
|
||||
<div
|
||||
class="reservation-type bg-color-fff"
|
||||
:style="{color:getColor(arg.event.extendedProps.serviceStatus)}"
|
||||
v-if="arg.event.extendedProps.serviceType === 2"
|
||||
>
|
||||
到店
|
||||
</div>
|
||||
<div
|
||||
class="reservation-type bg-color-fff"
|
||||
:style="{color:getColor(arg.event.extendedProps.serviceStatus)}"
|
||||
v-else-if="arg.event.extendedProps.serviceType === 1"
|
||||
>
|
||||
上门
|
||||
</div>
|
||||
<div style="display: inline-block" class="name">
|
||||
{{ arg.event.extendedProps.userName }}
|
||||
</div>
|
||||
<div style="display: inline-block" class="phone text-1">
|
||||
{{ arg.event.extendedProps.userPhone }}
|
||||
<span v-if="arg.event.extendedProps.serviceType === 1">
|
||||
{{ arg.event.extendedProps.userAddress }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-1">
|
||||
{{ arg.event.extendedProps.productName }}
|
||||
</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</FullCalendar>
|
||||
<div class="float-box">
|
||||
<div class="list">
|
||||
<div class="item">
|
||||
<span
|
||||
class="iconfont mark"
|
||||
:class="
|
||||
checkBox.includes(2)
|
||||
? 'icon-xuanzhong11'
|
||||
: 'icon-weixuan'
|
||||
"
|
||||
@click="handleMark(2)"
|
||||
/>
|
||||
待服务 {{`(${viewNum.toService})`}}
|
||||
</div>
|
||||
<div class="item">
|
||||
<span
|
||||
class="iconfont mark mark2"
|
||||
:class="
|
||||
checkBox.includes(3)
|
||||
? 'icon-xuanzhong11'
|
||||
: 'icon-weixuan'
|
||||
"
|
||||
@click="handleMark(3)"
|
||||
></span>
|
||||
服务中 {{`(${viewNum.servicing})`}}
|
||||
</div>
|
||||
<div class="item">
|
||||
<span
|
||||
class="iconfont mark mark3"
|
||||
:class="
|
||||
checkBox.includes(4)
|
||||
? 'icon-xuanzhong11'
|
||||
: 'icon-weixuan'
|
||||
"
|
||||
@click="handleMark(4)"
|
||||
></span>
|
||||
已完成 {{`(${viewNum.serviced})`}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slider">
|
||||
<el-slider
|
||||
v-model="sliderValue"
|
||||
:min="30"
|
||||
:max="180"
|
||||
:step="30"
|
||||
:marks="marks"
|
||||
show-stops
|
||||
@change="setConfig"
|
||||
style="width: 226;white-space: nowrap"
|
||||
>
|
||||
</el-slider>
|
||||
</div>
|
||||
<!-- 日期时间选择器组件 -->
|
||||
<el-dialog title="日期时间选择" :visible.sync="dialogVisible" width="504px">
|
||||
<div class="mb30">
|
||||
<el-date-picker
|
||||
v-model="selectedDate"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
@change="handleDateChange"
|
||||
style="margin: 10px;"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import resourceTimelinePlugin from "@fullcalendar/resource-timeline";
|
||||
import {workOrderOverViewApi, workOrderOverViewNumApi} from "@/api/merchantReservation";
|
||||
import moment from "moment";
|
||||
export default {
|
||||
components: {
|
||||
FullCalendar: () => import("@fullcalendar/vue")
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: {},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
where: {
|
||||
handler(newVal) {
|
||||
this.$emit('input', newVal);
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
marks: {
|
||||
30: "30分钟",
|
||||
60: "1小时",
|
||||
90: "",
|
||||
120: "2小时",
|
||||
150: "",
|
||||
180: "3小时"
|
||||
},
|
||||
sliderValue: 30,
|
||||
checkBox: [2, 3, 4],
|
||||
dialogVisible: false,
|
||||
calendarOptions: {
|
||||
height: "calc(100vh - 276px)", // 调整高度以适应顶部日期选择器
|
||||
slotMinWidth: 90,
|
||||
eventMaxStack: 50,
|
||||
moreLinkContent: {
|
||||
html:
|
||||
'<a>全部预约<span class="fc-icon fc-icon-chevron-right"></span></a>'
|
||||
},
|
||||
// moreLinkClick: this.handleMoreLinkClick,
|
||||
locale: "zh-cn",
|
||||
plugins: [resourceTimelinePlugin],
|
||||
initialView: "resourceTimelineDay",
|
||||
aspectRatio: 3,
|
||||
headerToolbar: {
|
||||
left: "prev,customTitle,next,volume,number",
|
||||
right: ""
|
||||
},
|
||||
customTitle: {
|
||||
text: this.formatDate(this.selectedDate),
|
||||
click: () => {
|
||||
this.dialogVisible = !this.dialogVisible;
|
||||
}
|
||||
},
|
||||
customButtons: {
|
||||
volume: {
|
||||
text: "当日预约量"
|
||||
},
|
||||
number: {
|
||||
text: "0"
|
||||
},
|
||||
customTitle: {
|
||||
text: this.formatDate(this.selectedDate),
|
||||
click: () => {
|
||||
this.dialogVisible = !this.dialogVisible;
|
||||
}
|
||||
}
|
||||
},
|
||||
slotLabelFormat: {
|
||||
hour: "2-digit", // 两位数小时(如 10)
|
||||
minute: "2-digit", // 两位数分钟(如 00)
|
||||
hour12: false, // 24小时制
|
||||
omitZeroMinute: false, // 不省略分钟(强制显示:00)
|
||||
locale: "zh-cn" // 本地化(需加载中文语言包)
|
||||
},
|
||||
nowIndicator: true,
|
||||
editable: false,
|
||||
droppable: false,
|
||||
resourceAreaWidth: "15%",
|
||||
scrollTime: "9:00",
|
||||
resourceAreaHeaderContent: "",
|
||||
resources: [],
|
||||
events: [],
|
||||
slotDuration: "00:30:00",
|
||||
slotLabelInterval: "00:30", // 标签间隔2小时
|
||||
datesSet: this.handleDatesSet,
|
||||
dateClick: this.handleDateChange,
|
||||
eventClick: this.handleEventClick,
|
||||
schedulerLicenseKey: "GPL-My-Project-Is-Open-Source"
|
||||
},
|
||||
reservationTime: "",
|
||||
where: this.value,
|
||||
viewNum: {},
|
||||
selectedDate: this.moment().format('YYYY-MM-DD'),
|
||||
selectedTime: '',
|
||||
calendarApi: null,
|
||||
};
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 清理事件监听
|
||||
document.removeEventListener("click", this.closePopover);
|
||||
},
|
||||
mounted() {
|
||||
this.getConfig();
|
||||
this.getList();
|
||||
this.getViewNum();
|
||||
// 初始化日期
|
||||
this.where.reservationDate = this.selectedDate;
|
||||
},
|
||||
methods: {
|
||||
getColor(serviceStatus){
|
||||
const statusMap = {
|
||||
1: '#9fdb1d',
|
||||
2: '#377DFF',
|
||||
3: '#FF8D30',
|
||||
4: '#23C471'
|
||||
};
|
||||
return statusMap[serviceStatus];
|
||||
},
|
||||
async getViewNum(){
|
||||
this.viewNum = await workOrderOverViewNumApi(this.where)
|
||||
},
|
||||
// 预约工单甘特图
|
||||
getList() {
|
||||
for (let key in this.tableFrom) {
|
||||
this.where[key] = this.tableFrom[key];
|
||||
}
|
||||
workOrderOverViewApi(this.where).then(res => {
|
||||
let data = res.list;
|
||||
let staff = [];
|
||||
let list = [];
|
||||
data.forEach(dataItem => {
|
||||
staff.push({
|
||||
id: dataItem.staffId,
|
||||
title: dataItem.staffId == 0 ? "未指派" : dataItem.name
|
||||
});
|
||||
// 蓝色 待服务,黄色 服务中,绿色 已完成,serviceType 服务类型:1-上门服务,2-到店服务,serviceStatus 服务状态:1-未分配,2-已分配,3-服务中,4-服务结束
|
||||
dataItem.workOrderList.forEach(item => {
|
||||
let color = "#9fdb1d";
|
||||
if (item.serviceStatus === 2) {
|
||||
// s上面 1
|
||||
// 到店 01
|
||||
color = "#377DFF";
|
||||
} else if (item.serviceStatus === 3) {
|
||||
color = "#FF8D30";
|
||||
} else if (item.serviceStatus === 4) {
|
||||
color = "#23C471";
|
||||
}
|
||||
let reservationTimeSlotAttr = item.reservationTimeSlot.split('-')
|
||||
list.push({
|
||||
...item,
|
||||
id: item.workOrderNo,
|
||||
staff_name: dataItem.name,
|
||||
resourceId: dataItem.staffId + "",
|
||||
start: this.moment(
|
||||
item.reservationDate +
|
||||
" " +
|
||||
reservationTimeSlotAttr[0]
|
||||
).format("YYYY-MM-DD HH:mm"),
|
||||
end: this.moment(
|
||||
item.reservationDate +
|
||||
" " +
|
||||
reservationTimeSlotAttr[1]
|
||||
).format("YYYY-MM-DD HH:mm"),
|
||||
color
|
||||
});
|
||||
});
|
||||
});
|
||||
this.calendarOptions.resources = staff;
|
||||
this.$nextTick(function () {
|
||||
this.$set(this.calendarOptions, "events", list);
|
||||
});
|
||||
this.calendarOptions.customButtons.number.text = res.count + "";
|
||||
});
|
||||
},
|
||||
showPopover() {
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
handleMark(type) {
|
||||
if (this.checkBox.includes(type)) {
|
||||
this.checkBox = this.checkBox.filter(item => item != type);
|
||||
this.where.serviceStatus = this.checkBox.join(",");
|
||||
} else {
|
||||
this.checkBox.push(type);
|
||||
this.where.serviceStatus = this.checkBox.join(",");
|
||||
}
|
||||
this.getList();
|
||||
this.getViewNum();
|
||||
},
|
||||
handleDateChange(date) {
|
||||
if (date) {
|
||||
// 如果传入的是日期对象,更新selectedDate
|
||||
if (date instanceof Date || typeof date === 'string') {
|
||||
this.selectedDate = date instanceof Date ? this.moment(date).format('YYYY-MM-DD') : date;
|
||||
}
|
||||
this.where.reservationDate = this.selectedDate;
|
||||
|
||||
// 如果有选择时间,更新到where对象中
|
||||
if (this.selectedTime) {
|
||||
this.where.reservationTime = this.selectedTime;
|
||||
this.calendarOptions.customButtons.customTitle.text = `${this.selectedDate} ${this.selectedTime}`;
|
||||
} else {
|
||||
this.calendarOptions.customButtons.customTitle.text = this.selectedDate;
|
||||
}
|
||||
|
||||
// 立即刷新数据,不使用setTimeout
|
||||
this.getList();
|
||||
this.getViewNum();
|
||||
|
||||
// 获取日历实例并强制刷新视图
|
||||
if (this.$refs.fullCalendarRef) {
|
||||
this.calendarApi = this.$refs.fullCalendarRef.getApi();
|
||||
if (this.calendarApi) {
|
||||
// 设置日期视图到选中的日期
|
||||
this.calendarApi.gotoDate(this.selectedDate);
|
||||
// 强制重新渲染
|
||||
this.calendarApi.refetchEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 关闭日期选择器
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
handleDatesSet(arg) {
|
||||
this.where.reservationDate = this.moment(arg.start).format("YYYY-MM-DD");
|
||||
this.selectedDate = this.where.reservationDate;
|
||||
// 如果有选择时间,更新标题
|
||||
if (this.selectedTime) {
|
||||
this.calendarOptions.customButtons.customTitle.text = `${this.where.reservationDate} ${this.selectedTime}`;
|
||||
} else {
|
||||
this.calendarOptions.customButtons.customTitle.text = this.where.reservationDate;
|
||||
}
|
||||
this.getList();
|
||||
this.getViewNum();
|
||||
},
|
||||
// 日期选择相关方法
|
||||
formatDate(date) {
|
||||
if (!date) {
|
||||
return moment().format('YYYY年MM月DD日');
|
||||
}
|
||||
return moment(date).format('YYYY年MM月DD日');
|
||||
},
|
||||
handleEventClick({ event }) {
|
||||
this.$emit("onOrderDetails", event.extendedProps.workOrderNo);
|
||||
},
|
||||
|
||||
// 保存看板配置
|
||||
setConfig() {
|
||||
localStorage.setItem("sliderValue", this.sliderValue);
|
||||
this.dialogVisible = false;
|
||||
this.getConfig();
|
||||
},
|
||||
getConfig() {
|
||||
let value = 30;
|
||||
if (localStorage.getItem("sliderValue")) {
|
||||
value = localStorage.getItem("sliderValue");
|
||||
}
|
||||
this.sliderValue = Number(value);
|
||||
this.calendarOptions.slotDuration = this.moment
|
||||
.utc(this.sliderValue * 60 * 1000)
|
||||
.format("HH:mm:ss");
|
||||
this.calendarOptions.slotLabelInterval = this.moment
|
||||
.utc(this.sliderValue * 60 * 1000)
|
||||
.format("HH:mm:ss");
|
||||
},
|
||||
close() {
|
||||
this.modal = false;
|
||||
},
|
||||
handleRefresh() {
|
||||
this.isRefresh = true;
|
||||
},
|
||||
handleMoreLinkClick(info) {
|
||||
info.jsEvent.preventDefault();
|
||||
const currentEvent = info.hiddenSegs[0].event;
|
||||
const resources = currentEvent.getResources();
|
||||
const rawEvents = resources[0].getEvents();
|
||||
const overlapEvents = rawEvents.filter(({ start, end }) => {
|
||||
return currentEvent.start <= end && start < currentEvent.end;
|
||||
});
|
||||
overlapEvents.sort((a, b) => {
|
||||
return a.start - b.start;
|
||||
});
|
||||
let eventList = overlapEvents.map(({ extendedProps, id }) => {
|
||||
return {
|
||||
...extendedProps,
|
||||
id
|
||||
};
|
||||
});
|
||||
this.$emit("serviceTap", eventList);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 添加顶部日期选择器的样式
|
||||
.top-date-picker {
|
||||
padding: 10px 0 0 20px;
|
||||
background-color: #fcfcfc;
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.bg-color-fff{
|
||||
background-color: rgba(255,255,255,.7);
|
||||
}
|
||||
.slider {
|
||||
position: absolute;
|
||||
width: 500px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 20px;
|
||||
padding-top: 0;
|
||||
::v-deep .el-slider__marks-text {
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
}
|
||||
::v-deep .el-slider__stop {
|
||||
position: absolute;
|
||||
height: 10px;
|
||||
width: 2px;
|
||||
background-color: #dddddd;
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-80%);
|
||||
}
|
||||
|
||||
::v-deep .el-slider__runway {
|
||||
height: 2px;
|
||||
background: #dddddd;
|
||||
}
|
||||
::v-deep .el-slider__button {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--prev-color-primary);
|
||||
}
|
||||
::v-deep .el-slider__bar {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
::v-deep.fc {
|
||||
.fc-button-primary, .fc-button-primary:focus, .fc-button:focus,{
|
||||
background: none;
|
||||
color: #303133;
|
||||
border-style: none;
|
||||
}
|
||||
.fc-more-popover .fc-popover-body {
|
||||
max-height: 300px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.fc-timeline-lane-frame{
|
||||
padding-top: 6px;
|
||||
}
|
||||
.fc-popover {
|
||||
z-index: 22;
|
||||
}
|
||||
.fc-datagrid-cell-frame {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.fc-datagrid-header {
|
||||
background-color: #fcfcfc;
|
||||
}
|
||||
.fc-datagrid-body {
|
||||
background-color: #fcfcfc;
|
||||
}
|
||||
.fc-timeline-slot-minor {
|
||||
border-style: none;
|
||||
}
|
||||
.fc-event {
|
||||
padding: 5px 6px;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.reservation-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.reservation-type {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 29px;
|
||||
height: 17px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
border-radius: 3px;
|
||||
margin-right: 4px;
|
||||
font-family: PingFang SC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.fc-prev-button {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 50% !important;
|
||||
background: none;
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.fc-prev-button:not(:disabled):active {
|
||||
border: 1px solid #dddddd;
|
||||
background: none;
|
||||
color: #303133;
|
||||
}
|
||||
.fc-prev-button:focus, .fc-button-primary:focus{
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-prev-button:not(:disabled):active:focus,.fc-button-primary:not(:disabled):active:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-next-button {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 50% !important;
|
||||
background: none;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.fc-next-button:not(:disabled):active {
|
||||
border: 1px solid #dddddd;
|
||||
background: none;
|
||||
color: #303133;
|
||||
}
|
||||
.fc-next-button:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-next-button:not(:disabled):active:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-toolbar-title {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
min-width: 200px;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.fc-volume-button {
|
||||
border: 0;
|
||||
background: none;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
cursor: auto;
|
||||
}
|
||||
.fc-volume-button:not(:disabled):active {
|
||||
border: 0;
|
||||
background: none;
|
||||
color: #303133;
|
||||
}
|
||||
.fc-volume-button:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-volume-button:not(:disabled):active:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-number-button {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
color: #377dff;
|
||||
cursor: auto;
|
||||
}
|
||||
.fc-number-button:not(:disabled):active {
|
||||
border: 0;
|
||||
background: none;
|
||||
color: #303133;
|
||||
}
|
||||
.fc-number-button:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-number-button:not(:disabled):active:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-setup-button {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100px;
|
||||
height: 32px;
|
||||
border: 1px solid var(--prev-color-primary);
|
||||
border-radius: 20px;
|
||||
background: var(--prev-color-primary);
|
||||
font-size: 13px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.fc-setup-button:not(:disabled):active {
|
||||
border: 1px solid var(--prev-color-primary);
|
||||
background: var(--prev-color-primary);
|
||||
}
|
||||
.fc-setup-button:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-setup-button:not(:disabled):active:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.fc-timeline-slot-cushion {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
}
|
||||
.fc-datagrid-cell-cushion {
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.fc-timeline-now-indicator-container {
|
||||
z-index: auto;
|
||||
}
|
||||
.fc-timeline-now-indicator-arrow {
|
||||
border-top-color: #377dff;
|
||||
}
|
||||
.fc-timeline-now-indicator-line {
|
||||
border-width: 0px 0px 0px 2px;
|
||||
border-color: #377dff;
|
||||
}
|
||||
td {
|
||||
border-color: #ededed;
|
||||
cursor: auto;
|
||||
}
|
||||
.fc-scrollgrid-section-header > th:last-child {
|
||||
border-color: transparent;
|
||||
}
|
||||
.fc-scrollgrid-section-body > td:last-child {
|
||||
border-color: transparent;
|
||||
}
|
||||
th {
|
||||
border-color: #ededed;
|
||||
}
|
||||
.fc-scrollgrid {
|
||||
border-color: transparent;
|
||||
}
|
||||
.ivu-tooltip {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.text-1 {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-family: PingFang SC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
margin: 0 4px;
|
||||
}
|
||||
.phone {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-family: PingFang SC, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.float-box {
|
||||
position: fixed;
|
||||
right: 44px;
|
||||
bottom: 87px;
|
||||
z-index: 9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 61px;
|
||||
padding: 0 13px 0 26px;
|
||||
border-radius: 84px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.08);
|
||||
.list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
}
|
||||
.item {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 18px;
|
||||
}
|
||||
.mark {
|
||||
font-size: 14px;
|
||||
color: #377dff;
|
||||
margin-right: 8px;
|
||||
&.mark2 {
|
||||
color: #ff8d30;
|
||||
}
|
||||
&.mark3 {
|
||||
color: #23c471;
|
||||
}
|
||||
&.mark4 {
|
||||
color: #f95e45;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ml0 {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,504 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer :visible.sync="dialogVisible" :direction="direction" size="1000px" :show-close="false">
|
||||
<div v-if="orderDatalist" v-loading="loading">
|
||||
<div class="detailHead">
|
||||
<div class="acea-row row-between headerBox">
|
||||
<div class="full">
|
||||
<div class="order_icon"><span class="iconfont icon-dingdan"></span></div>
|
||||
<div class="text">
|
||||
<div class="title">
|
||||
{{ orderDatalist.serviceType === 1 ? '上门服务' : '到店服务' }} --
|
||||
{{ orderDatalist.allocateType === 0 ? '未分配' : orderDatalist.allocateType === 1 ? '派单' : '抢单' }}
|
||||
</div>
|
||||
<div>
|
||||
<span class="mr20">工单号:{{ orderDatalist.workOrderNo }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="orderDatalist.refundStatus===0" class="acea-row justify-content">
|
||||
<el-button size="small" v-if="orderDatalist.serviceStatus === 1 && checkPermi(['merchant:workOrder:assign'])" type="primary" @click="handleDispatch(1)">派单</el-button>
|
||||
<el-button size="small" v-if="(orderDatalist.serviceStatus === 2 || orderDatalist.serviceStatus === 3) && checkPermi(['merchant:workOrder:reassign'])" type="primary" @click="handleDispatch(2)" style="margin-left: 0">改派</el-button>
|
||||
<el-button size="small" v-if="orderDatalist.serviceStatus < 3 && checkPermi(['merchant:workOrder:updateAgreement'])" v-debounceClick="handleRescheduling" type="primary" style="margin-left: 0">改约</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="title">工单状态</div>
|
||||
<div class="color-warning">
|
||||
<span v-if="orderDatalist.refundStatus === 2">已退款</span>
|
||||
<span v-else>{{ orderDatalist.serviceStatus | serviceStatusFilter }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="title">预约时间</div>
|
||||
<div>
|
||||
<span>{{ orderDatalist.reservationDate }}</span>
|
||||
<span class="ml10">{{ orderDatalist.reservationTimeSlot }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<el-tabs type="border-card" v-model="activeName">
|
||||
<el-tab-pane label="基本信息" name="detail">
|
||||
<div class="detailSection" style="border: none">
|
||||
<div class="title">预约信息</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="lang">联系人:</div>
|
||||
<div class="value">{{ orderDatalist.userName }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">联系电话:</div>
|
||||
<div class="value">{{ orderDatalist.userPhone }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="lang">预约时间:</div>
|
||||
<div class="value">
|
||||
<span>{{ orderDatalist.reservationDate }}</span>
|
||||
<span class="ml10">{{ orderDatalist.reservationTimeSlot }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-show="orderDatalist.serviceType === 1" class="item">
|
||||
<div class="lang">上门地址:</div>
|
||||
<div class="value">
|
||||
{{ orderDatalist.userAddress }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">商品信息</div>
|
||||
<el-table class="mt20 orderDetailList" :data="productList" size="small">
|
||||
<el-table-column label="商品信息" min-width="350" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="demo-image__preview mr15">
|
||||
<el-image :src="scope.row.image" :preview-src-list="[scope.row.image]" />
|
||||
</div>
|
||||
<div style="width: 300px">
|
||||
<div class="line1 mb10">{{ scope.row.productName }}</div>
|
||||
<div class="line1 color-909399 line-heightOne">规格:{{ scope.row.sku }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品售价" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="line1">
|
||||
{{ scope.row.price }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="购买数量" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row row-middle">
|
||||
<div class="line1">
|
||||
{{ scope.row.payNum }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">买家留言</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div>{{ orderDatalist.userRemark | filterEmpty }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detailSection">
|
||||
<div class="title">工单备注</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div>{{ orderDatalist.remark | filterEmpty }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="reservationFormData.length" class="detailSection">
|
||||
<div class="title">自定义留言</div>
|
||||
<ul class="">
|
||||
<li class="item" v-for="(item, index) in reservationFormData" :key="index">
|
||||
<system-from-info :item="item"></system-from-info>
|
||||
<!-- <div class="lang" :title="item.title">{{ item.title }}</div>-->
|
||||
<!-- <div>{{ item.title.includes(':') ? '' : ':' }}</div>-->
|
||||
<!-- <div v-if="!Array.isArray(item.value)" class="value">{{ item.value | filterEmpty }}</div>-->
|
||||
<!-- <div v-else class="flex conter">-->
|
||||
<!-- <template v-if="item.value">-->
|
||||
<!-- <div v-for="(pic, idx) in item.value" :key="idx">-->
|
||||
<!-- <el-image v-if="pic.includes('http')" class="pictrue" :src="pic" :preview-src-list="[pic]" />-->
|
||||
<!-- <div v-else class="text-14px fontColor333 ml-5px acea-row row-middle mr5">-->
|
||||
<!-- {{ pic }}-->
|
||||
<!-- <div style="margin-left: 6px" v-show="idx < item.value.length - 1">-</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- <template v-else> - </template>-->
|
||||
<!-- </div>-->
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="服务信息" name="goods">
|
||||
<div class="detailSection" style="border: none">
|
||||
<div class="title">服务信息</div>
|
||||
<ul class="list">
|
||||
<li class="item">
|
||||
<div class="">服务人员:</div>
|
||||
<div class="value">{{ orderDatalist.serviceStaff ? orderDatalist.serviceStaff.name : '-' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="">联系电话:</div>
|
||||
<div class="value">{{ orderDatalist.serviceStaff ? orderDatalist.serviceStaff.phone : '-' }}</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="">开始服务时间:</div>
|
||||
<div class="value">
|
||||
<span>{{ orderDatalist.serviceStartTime || '-' }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="">结束服务时间:</div>
|
||||
<div class="value">
|
||||
<span>{{ orderDatalist.serviceEndTime || '-' }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="item">
|
||||
<div class="">服务时长:</div>
|
||||
<div class="value">
|
||||
<span>{{ orderDatalist.serviceDuration }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="orderDatalist.collaboratorStaffs && orderDatalist.collaboratorStaffs.length">
|
||||
<div v-for="item in orderDatalist.collaboratorStaffs" :key="item.id" class="item">
|
||||
<div class="">协作者:</div>
|
||||
<div class="value">
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detailSection" v-if="orderDatalist.serviceType === 1">
|
||||
<div class="title">打卡信息</div>
|
||||
<ul class="list">
|
||||
<li class="item item100">
|
||||
<div>打卡备注:</div>
|
||||
<div class="value">
|
||||
{{ orderDatalist.clockInRemark | filterEmpty }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="item item100">
|
||||
<div>打卡照片:</div>
|
||||
<template v-if="orderDatalist.clockInPhoto">
|
||||
<div class="flex" v-for="(item, index) in orderDatalist.clockInPhoto.split(',')" :key="index">
|
||||
<el-image
|
||||
:src="item"
|
||||
:preview-src-list="[item]"
|
||||
style="width: 40px; height: 40px; margin-right: 12px"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else>--</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="detailSection" v-if="orderDatalist.serviceType === 1 && serviceEvidenceForm.length">
|
||||
<div class="title">服务过程留凭</div>
|
||||
<ul class="list">
|
||||
<li class="item" v-for="(item, index) in serviceEvidenceForm" :key="index">
|
||||
<div class="lang" :title="item.title">{{ item.title }}</div>
|
||||
<div>{{ item.title.includes(':') ? '' : ':' }}</div>
|
||||
<div v-if="!Array.isArray(item.value)" class="value">{{ item.value | filterEmpty }}</div>
|
||||
<div v-else class="flex conter">
|
||||
<template v-if="item.value">
|
||||
<div v-for="(pic, idx) in item.value" :key="idx">
|
||||
<el-image v-if="pic.includes('http')" class="pictrue" :src="pic" :preview-src-list="[pic]" />
|
||||
<div v-else class="text-14px fontColor333 ml-5px acea-row row-middle mr5">
|
||||
{{ pic }}
|
||||
<div style="margin-left: 6px" v-show="idx < item.value.length - 1">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else> - </template>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 派单 -->
|
||||
<dialogDispatch ref="dialogDispatchRef" @selectStaff="selectStaff" :workOrderNoList="[workOrderNo]"/>
|
||||
|
||||
<!-- 改约 -->
|
||||
<dialogReschedule
|
||||
ref="dialogRescheduleRef"
|
||||
:orderDetailList="orderDatalist"
|
||||
:productList="productList"
|
||||
@selectStaff="selectStaff"
|
||||
:workOrderNoList="[workOrderNo]"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import { orderRefundStatusFilter } from '@/filters';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import { OrderSecondTypeEnum } from '@/enums/productEnums';
|
||||
import { merchantWorkOrderDetailApi as workOrderDetailApi } from '@/api/merchantReservation'; // 权限判断函数
|
||||
import dialogDispatch from "./dialogDispatch";
|
||||
import dialogReschedule from "./dialogReschedule";
|
||||
import systemFromInfo from "@/views/merchantOrder/components/systemFromInfo";
|
||||
export default {
|
||||
name: 'WorkOrderDetail',
|
||||
components: {
|
||||
dialogDispatch,
|
||||
dialogReschedule,
|
||||
systemFromInfo
|
||||
},
|
||||
props: {
|
||||
workOrderNo: {
|
||||
type: String,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
OrderSecondTypeEnum: OrderSecondTypeEnum,
|
||||
activeName: 'detail',
|
||||
direction: 'rtl',
|
||||
reverse: true,
|
||||
dialogVisible: false,
|
||||
orderDatalist: {},
|
||||
loading: false,
|
||||
result: [],
|
||||
resultInfo: {},
|
||||
InvoiceList: [],
|
||||
refundInfo: {},
|
||||
editData: {},
|
||||
reservationFormData: [], //系统表单数据,用户下单填写
|
||||
serviceEvidenceForm: [], //系统表单数据,用户下单填写
|
||||
expressName: '', //快递名称
|
||||
productList: [], //商品信息
|
||||
};
|
||||
},
|
||||
watch: {},
|
||||
mounted() {},
|
||||
methods: {
|
||||
checkPermi,
|
||||
// 派单
|
||||
handleDispatch(type){
|
||||
this.$refs.dialogDispatchRef.openBox(type, this.orderDatalist);
|
||||
},
|
||||
// 改约
|
||||
handleRescheduling(){
|
||||
this.$refs.dialogRescheduleRef.openBox();
|
||||
},
|
||||
// 服务时长
|
||||
getTimes() {
|
||||
let str = '';
|
||||
if (this.orderDatalist.serviceStartTime && this.orderDatalist.serviceEndTime) {
|
||||
let startTime = this.orderDatalist.serviceStartTime;
|
||||
let endTime = this.orderDatalist.serviceEndTime;
|
||||
const formatISOTime = (timeStr) => timeStr.replace(' ', 'T') + 'Z';
|
||||
const start = new Date(formatISOTime(startTime));
|
||||
const end = new Date(formatISOTime(endTime));
|
||||
|
||||
// 计算时间差
|
||||
const diffMs = end - start;
|
||||
const diffMinute = Math.ceil(diffMs / 60000);
|
||||
return (diffMinute > 0 ? diffMinute : 1) + '分钟'; // 1分钟 = 60,000毫秒
|
||||
} else {
|
||||
return (str = '--');
|
||||
}
|
||||
},
|
||||
orderRefundStatusFilter,
|
||||
handleClose() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
// 操作回调
|
||||
selectStaff() {
|
||||
this.getDetail(this.workOrderNo);
|
||||
this.$emit('changeStaff')
|
||||
},
|
||||
getDetail(id) {
|
||||
this.loading = true;
|
||||
workOrderDetailApi(id)
|
||||
.then((res) => {
|
||||
this.orderDatalist = res;
|
||||
this.reservationFormData = res.reservationFormData ? JSON.parse(res.reservationFormData) : [];
|
||||
this.serviceEvidenceForm = res.serviceEvidenceForm ? JSON.parse(res.serviceEvidenceForm) : [];
|
||||
this.activeName = 'detail';
|
||||
this.productList = res.orderDetail ? [res.orderDetail] : [];
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.orderDatalist = null;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
::v-deep .el-drawer__header {
|
||||
display: flex !important;
|
||||
align-items: flex-start !important;
|
||||
padding: 15px 15px 0 15px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
::v-deep .el-drawer__body {
|
||||
padding: 0 0 30px 0 !important;
|
||||
}
|
||||
::v-deep .demo-drawer_title {
|
||||
width: 90%;
|
||||
}
|
||||
::v-deep .el-tabs__content {
|
||||
padding: 0 20px !important;
|
||||
}
|
||||
.detailSection {
|
||||
padding: 25px 15px !important;
|
||||
}
|
||||
::v-deep .el-table th.el-table__cell > .cell,
|
||||
::v-deep.el-table .cell,
|
||||
.el-table--border .el-table__cell:first-child .cell {
|
||||
padding-left: 15px;
|
||||
}
|
||||
.InvoiceList {
|
||||
::v-deep.el-collapse-item__header {
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
background-color: #fff;
|
||||
margin-top: 7px;
|
||||
padding: 10px 12px;
|
||||
&-num {
|
||||
font-size: 10px;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: #666666;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&-img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 10px;
|
||||
border-radius: 7px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10px;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:nth-child(5n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.demo-drawer__content {
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
.demo-image__preview {
|
||||
display: inline-block;
|
||||
.el-image {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.logistics {
|
||||
align-items: center;
|
||||
padding: 10px 0px;
|
||||
.logistics_img {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
margin-right: 12px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.logistics_cent {
|
||||
span {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.trees-coadd {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
.scollhide {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
margin-left: 18px;
|
||||
padding: 10px 0 10px 0;
|
||||
box-sizing: border-box;
|
||||
.content {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 14px;
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.description {
|
||||
&-term {
|
||||
display: table-cell;
|
||||
padding-bottom: 5px;
|
||||
line-height: 20px;
|
||||
width: 50%;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
::v-deep .el-divider--horizontal {
|
||||
margin: 12px 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {};
|
||||
</script>
|
||||
133
mer_plat_admin/src/views/merchantOrder/reservation/service.vue
Normal file
133
mer_plat_admin/src/views/merchantOrder/reservation/service.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div class="divBox">
|
||||
<el-card
|
||||
:bordered="false"
|
||||
shadow="never"
|
||||
class="ivu-mt"
|
||||
:body-style="{ padding: 0 }"
|
||||
v-if="checkPermi(['merchant:order:page:list'])"
|
||||
>
|
||||
<div class="padding-add">
|
||||
<el-form inline label-position="right" @submit.native.prevent>
|
||||
<el-form-item label="预约人员:" label-width="66px">
|
||||
<el-input
|
||||
v-model.trim="tableFrom.reservationKeyword"
|
||||
placeholder="请输入预约人员姓名电话搜索"
|
||||
class="form_content_width"
|
||||
size="small"
|
||||
@keyup.enter.native="handleSearchList"
|
||||
clearable
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="服务方式:">
|
||||
<el-select
|
||||
v-model="tableFrom.serviceType"
|
||||
placeholder="请选择服务方式"
|
||||
class="selWidth"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@change="handleSearchList"
|
||||
>
|
||||
<el-option v-for="item in serviceList" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="small" @click="handleSearchList">查询</el-button>
|
||||
<el-button size="small" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card class="mt14 board-card">
|
||||
<!-- 预约服务展示面板 -->
|
||||
<fullCalendar ref="fullCalendar" v-model="tableFrom" @onOrderDetails="onOrderDetails" />
|
||||
</el-card>
|
||||
|
||||
<!--详情-->
|
||||
<details-from ref="orderDetail" :workOrderNo="workOrderNo" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import detailsFrom from './components/workOrderDetail';
|
||||
import fullCalendar from './components/fullCalendar';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import { serviceStaffListApi } from '@/api/staff';
|
||||
export default {
|
||||
name: '',
|
||||
components: { fullCalendar, detailsFrom },
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
tableFrom: {
|
||||
reservationDate: '',
|
||||
reservationKeyword: '',
|
||||
serviceType: '',
|
||||
serviceStatus: '2,3,4',
|
||||
},
|
||||
workOrderNo: '',
|
||||
drawer: false,
|
||||
select: '',
|
||||
staffList: [],
|
||||
serviceList: [
|
||||
{
|
||||
id: '1',
|
||||
name: '上门服务',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '到店服务',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.getSelectStaff();
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
// 查询
|
||||
handleSearchList() {
|
||||
this.$refs.fullCalendar.getList();
|
||||
this.$refs.fullCalendar.getViewNum();
|
||||
},
|
||||
// 重置
|
||||
handleReset() {
|
||||
this.tableFrom.reservationKeyword = '';
|
||||
this.tableFrom.serviceType = '';
|
||||
this.tableFrom.searchType = 'all';
|
||||
this.tableFrom.content = ''
|
||||
this.handleSearchList();
|
||||
},
|
||||
// 选择服务人员
|
||||
async getSelectStaff() {
|
||||
let res = await serviceStaffListApi({
|
||||
page: 1,
|
||||
limit: 999,
|
||||
status: 1,
|
||||
});
|
||||
this.staffList = res.list;
|
||||
},
|
||||
onOrderDetails(id) {
|
||||
this.workOrderNo = id;
|
||||
this.$refs.orderDetail.getDetail(id);
|
||||
this.$refs.orderDetail.dialogVisible = true;
|
||||
},
|
||||
closeDrawer() {
|
||||
this.drawer = false;
|
||||
},
|
||||
changeDrawer(v) {
|
||||
this.drawer = v;
|
||||
},
|
||||
getSelectList(val) {
|
||||
this.tableFrom.nickname = val.nickname;
|
||||
this.tableFrom.phone = val.phone;
|
||||
this.handleSearchList();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
483
mer_plat_admin/src/views/merchantOrder/reservation/workOrder.vue
Normal file
483
mer_plat_admin/src/views/merchantOrder/reservation/workOrder.vue
Normal file
@@ -0,0 +1,483 @@
|
||||
<template>
|
||||
<div class="divBox relative">
|
||||
<el-card
|
||||
:bordered="false"
|
||||
shadow="never"
|
||||
class="ivu-mt"
|
||||
:body-style="{ padding: 0 }"
|
||||
v-if="checkPermi(['merchant:workOrder:page:list'])"
|
||||
>
|
||||
<div class="padding-add">
|
||||
<el-form inline label-position="right" @submit.native.prevent>
|
||||
<el-form-item label="工单编号:" label-width="66px">
|
||||
<el-input
|
||||
v-model.trim="tableFrom.workOrderNo"
|
||||
placeholder="请输入工单号"
|
||||
class="form_content_width"
|
||||
size="small"
|
||||
@keyup.enter.native="handleSearchList"
|
||||
clearable
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号:" label-width="66px">
|
||||
<el-input
|
||||
v-model.trim="tableFrom.orderNo"
|
||||
placeholder="请输入订单号"
|
||||
class="form_content_width"
|
||||
size="small"
|
||||
@keyup.enter.native="handleSearchList"
|
||||
clearable
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="预约类型:">
|
||||
<el-select
|
||||
v-model="tableFrom.serviceType"
|
||||
clearable
|
||||
size="small"
|
||||
placeholder="请选择"
|
||||
class="form_content_width"
|
||||
@change="handleSearchList"
|
||||
>
|
||||
<el-option v-for="(item, i) in fromType" :key="i" :label="item.text" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间选择:">
|
||||
<el-date-picker
|
||||
v-model="timeVal"
|
||||
value-format="yyyy-MM-dd"
|
||||
format="yyyy-MM-dd"
|
||||
size="small"
|
||||
type="daterange"
|
||||
placement="bottom-end"
|
||||
placeholder="自定义时间"
|
||||
@change="onchangeTime"
|
||||
class="form_content_width"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户搜索:" label-for="nickname">
|
||||
<UserSearchInput v-model="tableFrom" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="small" @click="handleSearchList">查询</el-button>
|
||||
<el-button size="small" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card
|
||||
shadow="never"
|
||||
:bordered="false"
|
||||
class="box-card mt16"
|
||||
:body-style="{ padding: '0 20px 20px', position: 'relative' }"
|
||||
v-if="checkPermi(['merchant:workOrder:status:num', 'merchant:workOrder:page:list'])"
|
||||
>
|
||||
<el-tabs class="list-tabs" v-model="tableFrom.status" @tab-click="handleSearchList">
|
||||
<el-tab-pane name="0" :label="`全部(${orderChartType.all || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="1" :label="`待领取(${orderChartType.unReceive || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="2" :label="`已领取(${orderChartType.received || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="3" :label="`服务中(${orderChartType.inService || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="4" :label="`服务结束(${orderChartType.endService || 0})`"></el-tab-pane>
|
||||
<el-tab-pane name="9" :label="`已退款(${orderChartType.refunded || 0})`"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="mt5">
|
||||
<el-dropdown size="small">
|
||||
<el-button :class="checkedIds.length > 0 ? '' : 'active'" :disabled="isBatch">
|
||||
批量设置<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<template>
|
||||
<el-dropdown-item
|
||||
v-if="tableFrom.status == 1 && checkPermi(['merchant:workOrder:assign']) && checkedIds.length > 0"
|
||||
@click.native="handleDispatch(1)"
|
||||
>派单</el-dropdown-item
|
||||
>
|
||||
<el-dropdown-item v-if="dispatch" @click.native="handleDispatch(2)">改派</el-dropdown-item>
|
||||
<el-dropdown-item v-if="rescheduling" @click.native="handleRescheduling">改约</el-dropdown-item>
|
||||
</template>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
:data="tableData.data"
|
||||
size="mini"
|
||||
class="mt20"
|
||||
highlight-current-row
|
||||
:highlight-current-row="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55"> </el-table-column>
|
||||
<el-table-column label="工单号" min-width="190">
|
||||
<template slot-scope="scope">
|
||||
<div class="acea-row">
|
||||
<span style="display: block" v-text="scope.row.workOrderNo" />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<span class="colorPrompt" v-show="parseInt(scope.row.refundStatus) > 0" style="display: block">{{
|
||||
scope.row.refundStatus === 1 ? '退款审核中' : '已退款'
|
||||
}}</span>
|
||||
</div>
|
||||
<span v-show="scope.row.isUserDel" class="colorPrompt" style="display: block">用户已删除</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="orderNo" label="订单号" min-width="190" />
|
||||
<el-table-column prop="userPhone" label="服务类型" min-width="80">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.serviceType === 1 ? '上门服务' : '到店服务' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="服务状态" min-width="100">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.refundStatus === 0"
|
||||
class="statusBox"
|
||||
:style="{
|
||||
color: orderColorFilter(scope.row.serviceStatus),
|
||||
borderColor: orderColorFilter(scope.row.serviceStatus),
|
||||
}"
|
||||
>
|
||||
{{ scope.row.serviceStatus | serviceStatusFilter }}
|
||||
</span>
|
||||
<span v-else class="statusBox notStartTag">已退款</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="预约时间" min-width="160">
|
||||
<template slot-scope="scope">
|
||||
<span> {{ scope.row.reservationDate }} </span>
|
||||
<span class="ml10"> {{ scope.row.reservationTimeSlot }} </span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="预约人名称" min-width="150" prop="userName" />
|
||||
<el-table-column prop="userPhone" label="预约人电话" min-width="120" />
|
||||
<el-table-column prop="userAddress" label="预约地址" min-width="200" :show-overflow-tooltip="true" />
|
||||
<el-table-column width="185" fixed="right" label="操作">
|
||||
<template slot-scope="scope">
|
||||
<a @click="onOrderDetails(scope.row.workOrderNo)" v-if="checkPermi(['merchant:workOrder:detail'])">详情 </a>
|
||||
<el-divider direction="vertical" v-if="scope.row.groupBuyRecordStatus != 0"></el-divider>
|
||||
<a @click="handleOrderMark(scope.row)" v-if="checkPermi(['merchant:workOrder:mark'])">工单备注 </a>
|
||||
<template v-if="scope.row.serviceStatus === 3 && checkPermi(['merchant:workOrder:forceFinish']) &&scope.row.refundStatus===0 ">
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<a @click="handleForceFinish(scope.row)">完成工单 </a>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="block">
|
||||
<el-pagination
|
||||
background
|
||||
:page-sizes="$constants.page.limit"
|
||||
:page-size="tableFrom.limit"
|
||||
:current-page="tableFrom.page"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableData.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 派单 -->
|
||||
<dialogDispatch ref="dialogDispatchRef" @selectStaff="handleSearchList" :workOrderNoList="checkedIds" />
|
||||
|
||||
<!-- 改约 -->
|
||||
<dialogReschedule ref="dialogRescheduleRef" @selectStaff="handleSearchList" :workOrderNoList="checkedIds" :isBatch="true"/>
|
||||
|
||||
<!--详情-->
|
||||
<details-from ref="orderDetail" :workOrderNo="workOrderNo" @changeStaff="handleSearchList"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import detailsFrom from './components/workOrderDetail';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
import DirectRefund from '@/views/merchantOrder/components/directRefund.vue';
|
||||
import * as $constants from '@/utils/constants';
|
||||
import { OrderSecondTypeEnum } from '@/enums/productEnums';
|
||||
import { merchantWorkOrderForceFinishApi as workOrderForceFinishApi, merchantWorkOrderListApi as workOrderListApi, merchantWorkOrderMarkApi as workOrderMarkApi, merchantWorkOrderStatusNumApi as workOrderStatusNumApi } from '@/api/merchantReservation';
|
||||
import dialogDispatch from './components/dialogDispatch';
|
||||
import dialogReschedule from './components/dialogReschedule';
|
||||
let tableFroms = {
|
||||
status: '0',
|
||||
dateLimit: '',
|
||||
orderNo: '',
|
||||
page: 1,
|
||||
limit: $constants.page.limit[0],
|
||||
serviceType: '',
|
||||
searchType: 'all',
|
||||
content: '',
|
||||
workOrderNo: '',
|
||||
};
|
||||
export default {
|
||||
name: 'orderlistDetails',
|
||||
components: {
|
||||
dialogDispatch,
|
||||
dialogReschedule,
|
||||
DirectRefund,
|
||||
detailsFrom,
|
||||
},
|
||||
computed: {
|
||||
// 批量改派
|
||||
dispatch() {
|
||||
return (
|
||||
(this.tableFrom.status == 2 || this.tableFrom.status == 3) &&
|
||||
checkPermi(['merchant:workOrder:reassign']) &&
|
||||
this.checkedIds.length > 0
|
||||
);
|
||||
},
|
||||
// 批量改约
|
||||
rescheduling() {
|
||||
return (
|
||||
checkPermi(['merchant:workOrder:updateAgreement']) &&
|
||||
(this.tableFrom.status == 2 || this.tableFrom.status == 1) &&
|
||||
this.checkedIds.length > 0
|
||||
);
|
||||
},
|
||||
// 是否能批量操作
|
||||
isBatch() {
|
||||
return this.checkedIds.length > 0 && Number(this.tableFrom.status) > 0 && Number(this.tableFrom.status) < 4
|
||||
? false
|
||||
: true;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
workOrderNo: '',
|
||||
dialogVisible: false,
|
||||
tableData: {
|
||||
data: [],
|
||||
total: 0,
|
||||
},
|
||||
listLoading: false,
|
||||
tableFrom: Object.assign({}, tableFroms),
|
||||
orderChartType: {},
|
||||
timeVal: [],
|
||||
fromType: [
|
||||
{ value: 1, text: '上门服务' },
|
||||
{ value: 2, text: '到店服务' },
|
||||
],
|
||||
selectionList: [],
|
||||
type: 0, //订单类型
|
||||
OrderSecondTypeEnum: OrderSecondTypeEnum,
|
||||
checkedIds: [], //选中的id
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (checkPermi(['mmerchant:workOrder:page:list'])) this.getList();
|
||||
if (checkPermi(['merchant:workOrder:status:num'])) this.getOrderStatusNum();
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
// 派单
|
||||
handleDispatch(type) {
|
||||
this.$refs.dialogDispatchRef.openBox(type);
|
||||
},
|
||||
// 改约
|
||||
handleRescheduling() {
|
||||
this.$refs.dialogRescheduleRef.openBox();
|
||||
},
|
||||
// 服务状态
|
||||
orderColorFilter(status) {
|
||||
const statusMap = {
|
||||
3: '#0FC6C2',
|
||||
1: '#FF7D00',
|
||||
2: '#3491FA',
|
||||
4: '#CCCCCC',
|
||||
9: '#F56464',
|
||||
};
|
||||
return statusMap[status];
|
||||
},
|
||||
handleReset() {
|
||||
this.tableFrom.type = '';
|
||||
this.tableFrom.dateLimit = '';
|
||||
this.tableFrom.orderNo = '';
|
||||
this.tableFrom.workOrderNo = '';
|
||||
this.tableFrom.page = 1;
|
||||
this.tableFrom.content = '';
|
||||
this.tableFrom.searchType = 'all';
|
||||
this.tableFrom.serviceType = ''
|
||||
this.selectChange();
|
||||
},
|
||||
handleSearchList() {
|
||||
this.tableFrom.page = 1;
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
},
|
||||
// 详情
|
||||
onOrderDetails(id) {
|
||||
this.workOrderNo = id;
|
||||
this.$refs.orderDetail.getDetail(id);
|
||||
this.$refs.orderDetail.dialogVisible = true;
|
||||
},
|
||||
handleClose() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
// 备注
|
||||
handleOrderMark(row) {
|
||||
this.$modalPrompt('textarea', '备注', row.remark, '工单备注').then((V) => {
|
||||
workOrderMarkApi({ remark: V, workOrderNo: row.workOrderNo }).then(() => {
|
||||
this.$message.success('操作成功');
|
||||
this.getList();
|
||||
});
|
||||
});
|
||||
},
|
||||
// 完成工单
|
||||
handleForceFinish(row) {
|
||||
this.$modalSure('确认强制完成工单吗?').then(() => {
|
||||
workOrderForceFinishApi({ workOrderNoList: [row.workOrderNo] }).then((res) => {
|
||||
this.$message.success('完成工单成功');
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
});
|
||||
});
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.selectionList = val;
|
||||
const data = [];
|
||||
this.selectionList.map((item) => {
|
||||
data.push(item.workOrderNo);
|
||||
});
|
||||
this.checkedIds = data;
|
||||
},
|
||||
// 选择时间
|
||||
selectChange(tab) {
|
||||
this.timeVal = [];
|
||||
this.tableFrom.page = 1;
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
},
|
||||
// 具体日期
|
||||
onchangeTime(e) {
|
||||
this.timeVal = e;
|
||||
this.tableFrom.dateLimit = e ? this.timeVal.join(',') : '';
|
||||
this.tableFrom.page = 1;
|
||||
this.getList();
|
||||
this.getOrderStatusNum();
|
||||
},
|
||||
// 列表
|
||||
getList() {
|
||||
this.listLoading = true;
|
||||
workOrderListApi(this.tableFrom)
|
||||
.then((res) => {
|
||||
this.tableData.data = res.list || [];
|
||||
this.tableData.total = res.total;
|
||||
this.listLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.listLoading = false;
|
||||
});
|
||||
},
|
||||
// 获取各状态数量
|
||||
getOrderStatusNum() {
|
||||
let data = Object.assign({}, this.tableFrom);
|
||||
delete data.page;
|
||||
delete data.limit;
|
||||
delete data.status;
|
||||
workOrderStatusNumApi(data).then((res) => {
|
||||
this.orderChartType = res;
|
||||
});
|
||||
},
|
||||
pageChange(page) {
|
||||
this.tableFrom.page = page;
|
||||
this.getList();
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.tableFrom.limit = val;
|
||||
this.getList();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.statusBox {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #cccccc;
|
||||
}
|
||||
font {
|
||||
color: var(--prev-color-primary);
|
||||
}
|
||||
.el-table__body {
|
||||
width: 100%;
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
|
||||
.demo-table-expand {
|
||||
::v-deep .label {
|
||||
width: 83px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.refunding {
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.el-icon-arrow-down {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tabBox_tit {
|
||||
font-size: 12px !important;
|
||||
/*margin: 0 2px 0 10px;*/
|
||||
letter-spacing: 1px;
|
||||
/*padding: 5px 0;*/
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.text_overflow {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.pup_card {
|
||||
width: 200px;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.cell_ht {
|
||||
height: 50px;
|
||||
padding: 15px 20px;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.check_cell {
|
||||
width: 100%;
|
||||
padding: 15px 20px 0;
|
||||
}
|
||||
|
||||
::v-deep .el-checkbox__input.is-checked + .el-checkbox__label {
|
||||
color: #606266;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user