- 框架初始化
 - 安装插件
 - 修复PHP8.4报错
This commit is contained in:
2025-04-19 17:21:20 +08:00
commit c6a4e1f5f6
5306 changed files with 967782 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
{include file="/shopro/common/script" /}
<div id="addLog" class="aftersale-add-log" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="回复内容" prop="content">
<el-input type="textarea" v-model="form.model.content" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="选择图片">
<sa-uploader v-model="form.model.images" :multiple="true" max="9">
</sa-uploader>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,417 @@
{include file="/shopro/common/script" /}
<style>
.aftersale-detail .el-scrollbar__wrap {
overflow-x: hidden;
}
.aftersale-detail .el-scrollbar__bar.is-horizontal {
display: none;
}
.aftersale-detail .tip {
margin-bottom: 16px;
}
.aftersale-detail .status-text {
line-height: 24px;
font-size: 18px;
font-weight: 600;
color: var(--sa-title);
margin-bottom: 4px;
}
.aftersale-detail .status-desc {
line-height: 16px;
font-size: 12px;
color: var(--sa-subfont);
margin-bottom: 16px;
}
.aftersale-detail .el-step__head .el-step__line {
top: 15px;
}
.aftersale-detail .el-step__head .el-step__icon {
width: 32px;
height: 32px;
color: var(--sa-background-assist);
background: var(--sa-place);
border: 2px solid var(--sa-table-header-bg);
}
.aftersale-detail .el-step__head.is-finish .el-step__icon {
color: var(--sa-background-assist);
background: var(--el-color-primary);
}
.aftersale-detail .el-step__title {
color: var(--sa-subfont);
font-size: 14px;
font-weight: 400;
}
.aftersale-detail .el-step__title.is-finish {
color: var(--sa-subtitle);
}
.aftersale-detail .el-step__description {
padding: 0;
color: var(--sa-subfont);
}
.aftersale-detail .el-step__description.is-finish .step-status {
color: var(--el-color-primary);
}
.aftersale-detail .step-status {
color: var(--sa-font);
font-size: 14px;
}
.aftersale-detail .status-steps-mobile {
margin-top: 32px;
display: none;
@media only screen and (max-width: 768px) {
display: flex;
}
}
.aftersale-detail .status-steps-mobile .el-step__head {
width: fit-content;
}
.aftersale-detail .status-steps-mobile .el-step__head .el-step__line {
left: 15px;
}
.aftersale-detail .status-steps-pc {
display: flex;
margin-top: 32px;
@media only screen and (max-width: 768px) {
display: none;
}
}
.aftersale-detail .status-steps-pc .step-status {
position: absolute;
top: -12px;
right: -30px;
width: 60px;
}
.aftersale-content {
padding: var(--sa-padding) var(--sa-padding) 0;
background: var(--sa-background-hex-hover);
border-radius: 8px;
margin-bottom: 16px;
}
.aftersale-detail .el-col {
margin-bottom: var(--sa-padding);
}
.aftersale-detail .title {
line-height: 20px;
font-size: 16px;
font-weight: 600;
color: var(--sa-title);
margin-bottom: 16px;
}
.aftersale-detail .subtitle {
line-height: 18px;
font-size: 14px;
font-weight: 500;
color: var(--sa-title);
margin-bottom: 12px;
}
.aftersale-detail .item {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.aftersale-detail .left {
line-height: 16px;
font-size: 12px;
color: var(--sa-subfont);
}
.aftersale-detail .right {
line-height: 16px;
font-size: 12px;
color: var(--sa-subtitle);
display: flex;
align-items: center;
}
.aftersale-detail .goods-item .goods-title {
height: 14px;
line-height: 14px;
font-size: 12px;
font-weight: 500;
margin-bottom: 6px;
}
.aftersale-detail .goods-item .goods-price {
flex-shrink: 0;
line-height: 14px;
font-size: 12px;
color: var(--sa-font);
margin-bottom: 12px;
}
.aftersale-detail .goods-item .goods-sku-text {
width: fit-content;
height: 18px;
line-height: 18px;
padding: 0 8px;
font-size: 12px;
color: var(--sa-subfont);
background: var(--sa-space);
border-radius: 10px;
}
.aftersale-detail .log-item {
line-height: 16px;
font-size: 12px;
color: var(--sa-subfont);
}
.aftersale-detail .log-oper {
margin-right: 12px;
}
.aftersale-detail .name {
font-weight: 500;
margin-bottom: 4px;
}
.aftersale-detail .create-time {
font-weight: 400;
margin-bottom: 8px;
}
.aftersale-detail .log-content {
margin-bottom: 8px;
}
.aftersale-detail .log-image {
margin-right: 4px;
}
.aftersale-detail .log-imageZ:last-of-type {
margin-right: 0;
}
.aftersale-detail .log-type-text,
.aftersale-detail .log-content {
font-weight: 500;
color: var(--sa-subtitle);
margin-bottom: 8px;
}
</style>
<div id="detail" class="aftersale-detail" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<div class="tip">
<div>温馨提示</div>
<div>1、如果同意申请请发送正确的退货地址给买家</div>
<div>2、如果拒绝申请请发送给买家拒绝理由</div>
</div>
<el-row class="aftersale-content sa-m-b-16" :gutter="10">
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<div class="status-text sa-m-b-4">
{{ state.data.aftersale_status_text }}
</div>
<div class="status-desc sa-m-b-16">
{{ state.data.aftersale_status_desc }}
</div>
<div class="tools">
<template v-if="state.data.aftersale_status == 0 || state.data.aftersale_status == 1">
{if $auth->check('shopro/order/aftersale/refund')}
<el-button type="primary" link @click="onRefund">售后退款</el-button>
{/if}
{if $auth->check('shopro/order/aftersale/refuse')}
<el-button @click="onRefuse">拒绝售后</el-button>
{/if}
{if $auth->check('shopro/order/aftersale/completed')}
<el-button type="primary" link @click="onCompleted">售后完成</el-button>
{/if}
</template>
</div>
</el-col>
<el-col :xs="24" :sm="16" :md="16" :lg="16" :xl="16">
<el-steps class="status-steps-mobile" direction="vertical" :active="state.stepActive"
:align-center="true" :space="80">
<el-step title="买家申请售后" :description="state.data.create_time"></el-step>
<el-step title="售后申请处理中" :description="
state.stepActive >= 2
? state.data.logs.length > 0
? state.data.logs[0].updatetime
: ''
: ''
"></el-step>
<el-step title="处理完成" :description="state.stepActive == 3 ? state.data.updatetime : ''">
</el-step>
</el-steps>
<el-steps class="status-steps-pc" direction="horizontal" :active="state.stepActive"
:align-center="true">
<el-step title="买家申请售后" :description="state.data.create_time"></el-step>
<el-step title="售后申请处理中" :description="
state.stepActive >= 2
? state.data.logs.length > 0
? state.data.logs[0].updatetime
: ''
: ''
"></el-step>
<el-step title="处理完成" :description="state.stepActive == 3 ? state.data.updatetime : ''">
</el-step>
</el-steps>
</el-col>
</el-row>
<div class="refund-content aftersale-content sa-m-b-26">
<div class="title sa-m-b-16">售后详情</div>
<el-row :gutter="10">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="subtitle">交易信息</div>
<div class="item">
<div class="left">用户信息:</div>
<div class="right">
<sa-user-profile :user="state.data.user" :id="state.data.user_id" :isavatar="false">
</sa-user-profile>
</div>
</div>
<div class="item">
<div class="left">订单编号:</div>
<div class="right">
<template v-if="state.data.order">
{{ state.data.order.order_sn }}
<el-icon class="copy-document" @click="onClipboard(state.data.order.order_sn)">
<copy-document />
</el-icon>
</template>
<template v-else>{{ state.data.order_id }}</template>
</div>
</div>
<div class="item">
<div class="left">物流状态:</div>
<div class="right">{{ state.data.dispatch_status_text }}</div>
</div>
<div class="item">
<div class="left">订单实付:</div>
<div class="right">¥{{ state.data?.order?.pay_fee }}</div>
</div>
<div class="item">
<div class="left">订单运费:</div>
<div class="right"> ¥{{ state.data?.order?.dispatch_amount }} </div>
</div>
<div class="item">
<div class="left">订单优惠:</div>
<div class="right"> ¥{{ state.data?.order?.total_discount_fee }} </div>
</div>
<div class="item">
<div class="left">商品运费:</div>
<div class="right">¥{{ state.data.dispatch_fee }}</div>
</div>
<div class="item">
<div class="left">商品优惠:</div>
<div class="right">¥{{ state.data.discount_fee }}</div>
</div>
<div class="item">
<div class="left">建议退款:</div>
<div class="right">¥{{ state.data.suggest_refund_fee }}</div>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="subtitle">售后信息</div>
<div class="item">
<div class="left">售后单号:</div>
<div class="right">
{{ state.data.aftersale_sn }}
<el-icon class="copy-document" @click="onClipboard(state.data.aftersale_sn)">
<copy-document />
</el-icon>
</div>
</div>
<div class="item">
<div class="left">申请时间:</div>
<div class="right">{{ state.data.createtime }}</div>
</div>
<div class="item">
<div class="left">联系电话:</div>
<div class="right">{{ state.data.mobile || '-' }}</div>
</div>
<div class="item">
<div class="left">售后类型:</div>
<div class="right">
<span class="sa-color--danger">{{ state.data.type_text }}</span>
</div>
</div>
<div class="item">
<div class="left">实际退款:</div>
<div class="right">
<span class="sa-color--danger">¥{{ state.data.refund_fee }}</span>
</div>
</div>
<div class="item">
<div class="left">申请原因:</div>
<div class="right"> {{ state.data.reason }} </div>
</div>
<div class="item">
<div class="left">相关描述:</div>
<div class="right" v-html="state.data.content"></div>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<div class="subtitle">商品信息</div>
<div class="goods-item sa-flex sa-col-top">
<sa-image class="mr-2" :url="state.data.goods_image" size="64"></sa-image>
<div>
<div class="goods-title sa-table-line-1">
{{state.data.goods_title}}</div>
<div class="goods-price">
¥{{state.data.goods_price}} <span class="ml-1">x{{state.data.goods_num}}</span>
</div>
<div v-if="state.data.goods_sku_text" class="goods-sku-text">
{{state.data.goods_sku_text}}
</div>
</div>
</div>
</el-col>
</el-row>
</div>
<div class="log-content aftersale-content">
<div class="title sa-flex sa-row-between">
<div class="left">协商记录</div>
{if $auth->check('shopro/order/aftersale/addLog')}
<el-button type="primary" link @click="onAddLog">回复买家</el-button>
{/if}
</div>
<div class="log-item sa-flex sa-col-top" v-for="(log, index) in state.data.logs" :key="log">
<sa-image v-if="log.oper" class="log-oper" :url="log.oper.avatar" size="48" radius="24">
</sa-image>
<div>
<div v-if="log.oper" class="name">{{ log.oper.name }}</div>
<div class="create-time">{{ log.createtime }}</div>
<div class="log-type-text">{{ log.log_type_text }}</div>
<div v-if="index < state.data.logs.length - 1" class="log-content" v-html="log.content">
</div>
<div class="sa-flex mb-2">
<template v-for="item in log.images" :key="img">
<sa-image class="log-image" :url="item" size="48"></sa-image>
</template>
</div>
</div>
</div>
</div>
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,200 @@
{include file="/shopro/common/script" /}
<style>
.aftersale-index .sa-table {
font-size: 12px;
}
.aftersale-index .sa-table-wrap {
height: 100%;
margin-left: -48px;
overflow: hidden;
}
.aftersale-index .sa-table-wrap .sa-table .el-table__header-wrapper {
margin-bottom: 4px;
}
.aftersale-index .sa-table-wrap .sa-table .el-table__row {
background: var(--sa-background-hex-hover);
}
.aftersale-index .sa-table-wrap .sa-table .el-table__expanded-cell {
padding: 0;
}
.aftersale-index .sa-table-wrap .sa-expand-table .el-table__header-wrapper {
margin-bottom: 0;
display: none;
}
.aftersale-index .sa-table-wrap .sa-expand-table .el-table__row {
background: var(--el-table-tr-bg-color);
}
.aftersale-index .sa-expand-table tr:hover>td.el-table__cell {
background-color: var(--el-table-tr-bg-color) !important;
}
.aftersale-index .order-detail {
margin-left: 4px;
}
.aftersale-index .goods-item {
line-height: 1;
}
.aftersale-index .goods-item .goods-image {
margin-right: 12px;
}
.aftersale-index .goods-item .goods-title {
height: 14px;
line-height: 14px;
font-size: 12px;
font-weight: 600;
color: var(--el-color-primary);
cursor: pointer;
margin-bottom: 6px;
}
.aftersale-index .goods-item .goods-price {
flex-shrink: 0;
line-height: 14px;
font-size: 12px;
color: var(--sa-font);
margin-bottom: 12px;
}
.aftersale-index .goods-item .goods-num {
margin-left: 8px;
}
.aftersale-index .goods-item .goods-sku-text {
width: fit-content;
height: 18px;
line-height: 18px;
padding: 0 8px;
font-size: 12px;
color: var(--sa-subfont);
background: var(--sa-space);
border-radius: 10px;
}
.aftersale-index .status--1 {
color: var(--el-color-danger);
}
</style>
<div id="index" class="aftersale-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data['aftersale_list.aftersale_status']"
@tab-change="onChangeTab">
<el-tab-pane v-for="item in type.data.aftersale_status" :key="item"
:label="`${item.name}${item.num ? '(' + item.num + ')' : ''}`" :name="item.type"></el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">售后管理</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<div class="sa-table-wrap">
<el-table height="100%" class="sa-table" :data="state.data" stripe default-expand-all>
<el-table-column type="expand">
<template #default="props">
<el-table class="sa-table sa-expand-table" :data="props.row.aftersales" stripe>
<el-table-column width="48"></el-table-column>
<el-table-column min-width="280">
<template #default="scope">
<div class="aftersale-sn">
售后单号:{{ scope.row.aftersale_sn }}
<el-icon class="copy-document" @click="onClipboard(scope.row.aftersale_sn)">
<copy-document />
</el-icon>
</div>
<div class="create-time"> 申请时间:{{ scope.row.createtime }} </div>
</template>
</el-table-column>
<el-table-column min-width="300">
<template #default="scope">
<div class="goods-item sa-flex sa-col-top">
<sa-image class="mr-2" :url="scope.row.goods_image" size="64"></sa-image>
<div>
<div class="goods-title sa-table-line-1"
@click="onOpenGoods(scope.row.goods_id)">
{{scope.row.goods_title}}</div>
<div class="goods-price">
¥{{scope.row.goods_price}} <span
class="goods-num">x{{scope.row.goods_num}}</span>
</div>
<div v-if="scope.row.goods_sku_text" class="goods-sku-text">
{{scope.row.goods_sku_text}}
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column min-width="130">
<template #default>{{ props.row.pay_fee }}</template>
</el-table-column>
<el-table-column prop="refund_fee" min-width="100"></el-table-column>
<el-table-column min-width="80">
<template #default="scope">
<div :class="scope.row.aftersale_status == '-1' ? 'status--1' : ''">
{{ scope.row.aftersale_status_text }}
</div>
</template>
</el-table-column>
<el-table-column prop="type_text" min-width="80"></el-table-column>
<el-table-column min-width="80">
<template #default="scope">
{if $auth->check('shopro/order/aftersale/detail')}
<el-button type="primary" link @click="onDetail(scope.row.id)">详情</el-button>
{/if}
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column label="售后信息" min-width="280">
<template #default="scope">
<div class="order-sn sa-flex">
订单号:{{ scope.row.order_sn }}
<el-button class="order-detail" type="primary" link size="small"
@click="onOpenOrderDetail(scope.row.id)">详情</el-button>
</div>
</template>
</el-table-column>
<el-table-column label="商品信息" min-width="300">
<template #default="scope">
<div class="create-time"> 下单时间:{{ scope.row.createtime }} </div>
</template>
</el-table-column>
<el-table-column label="订单实付金额" min-width="130">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id" :isavatar="false">
</sa-user-profile>
</template>
</el-table-column>
<el-table-column label="已退款金额" min-width="100"></el-table-column>
<el-table-column label="处理状态" min-width="80"></el-table-column>
<el-table-column label="售后类型" min-width="80"></el-table-column>
<el-table-column label="操作" min-width="80"></el-table-column>
</el-table>
</div>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,28 @@
{include file="/shopro/common/script" /}
<div id="refund" class="aftersale-refund" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="退款方式">
<div>
<el-radio-group v-model="form.model.refund_type">
<el-radio label="back">原路退回</el-radio>
<el-radio label="money">退回余额</el-radio>
</el-radio-group>
</div>
</el-form-item>
<el-form-item label="退款金额" prop="refund_money">
<el-input v-model="form.model.refund_money"
:placeholder="`建议退款金额${state.suggest_refund_fee}元`" />
<div class="tip"> 退款时请与买家协商好,退款之后不可撤回 </div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,18 @@
{include file="/shopro/common/script" /}
<div id="refuse" class="aftersale-refuse" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="拒绝原因" prop="refuse_msg">
<el-input v-model="form.model.refuse_msg" placeholder="请输入拒绝原因" />
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,36 @@
{include file="/shopro/common/script" /}
<div id="confirm" class="invoice-confirm" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-alert v-if="state.item.order_status_text || state.item.order_fee" class="mb-4" type="warning">
<template #title>
<div v-if="state.item.order_status_text">
{{state.item.order_status_text }}
</div>
<div v-if="state.item.order_fee">
该订单存在改价,原应付金额:¥{{
state.item.order_fee.original_pay_fee
}},改价后支付金额:¥{{state.item.order_fee.pay_fee }}
</div>
</template>
</el-alert>
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="120px">
<el-form-item label="实际开票金额" prop="invoice_amount">
<el-input class="sa-w-360" type="number" :min="0" :step="0.01"
v-model="form.model.invoice_amount" placeholder="请输入实际开票金额">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="选择发票图片" prop="download_urls">
<sa-uploader v-model="form.model.download_urls" :multiple="true"></sa-uploader>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,126 @@
{include file="/shopro/common/script" /}
<div id="index" class="invoice-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data.status" @tab-change="onChangeTab">
<el-tab-pane v-for="item in type.data.status" :key="item"
:label="`${item.name}${item.num ? '(' + item.num + ')' : ''}`" :name="item.type"></el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">订单发票</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="id" label="ID" min-width="90"> </el-table-column>
<el-table-column label="申请用户" min-width="200">
<template #default="scope">
<sa-user-profile :user="scope.row.user" :id="scope.row.user_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column label="类型" min-width="110">
<template #default="scope">
<el-tag v-if="scope.row.type == 'person'">个人</el-tag>
<el-tag v-if="scope.row.type == 'company'" type="warning">企/事业单位</el-tag>
</template>
</el-table-column>
<el-table-column label="抬头名称" min-width="240">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="联系电话" min-width="160">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.mobile || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="总金额" min-width="130">
<template #default="scope">
<div class="sa-table-line-1">{{scope.row.amount ? scope.row.amount + '元' : '-'}}</div>
</template>
</el-table-column>
<el-table-column label="实际开票金额" min-width="130">
<template #default="scope">
<div class="sa-table-line-1">{{scope.row.invoice_amount ? scope.row.invoice_amount + '元' : '-'}}
</div>
</template>
</el-table-column>
<el-table-column label="纳税人识别号" min-width="200">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.tax_no || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="单位地址" min-width="300">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.address || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="开户行" min-width="300">
<template #default="scope">
<div class="sa-table-line-1">
{{ scope.row.bank_name || '-' }}
</div>
</template>
</el-table-column>
<el-table-column label="订单编号" min-width="250">
<template #default="scope">
<div class="sa-flex sa-table-line-1">
<el-button type="primary" link @click="onOpenOrderDetail(scope.row.order_id)">{{
scope.row.order?.order_sn || '-' }}</el-button>
<el-icon class="copy-document" @click="onClipboard(scope.row.order?.order_sn)">
<copy-document />
</el-icon>
</div>
</template>
</el-table-column>
<el-table-column label="申请时间" min-width="180">
<template #default="scope">
{{ scope.row.createtime || '-' }}
</template>
</el-table-column>
<el-table-column label="处理时间" min-width="180">
<template #default="scope">
{{ scope.row.finish_time || '-' }}
</template>
</el-table-column>
<el-table-column label="状态" min-width="120">
<template #default="scope">
<div :class="`sa-color--${state.statusStyle[scope.row.status]}`">
{{ scope.row.status_text || '-' }}
</div>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="100">
<template #default="scope">
{if $auth->check('shopro/order/invoice/confirm')}
<el-button v-if="scope.row.status == 'waiting'" type="primary" link
@click="onConfirm(scope.row)">确认开具
</el-button>
{/if}
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,17 @@
{include file="/shopro/common/script" /}
<div id="action" class="order-action" v-cloak>
<el-container class="panel-block">
<el-main>
<el-table height="100%" class="sa-table" :data="state.data" stripe>
<el-table-column prop="remark" label="事件" min-width="250"></el-table-column>
<el-table-column label="操作人" min-width="120">
<template #default="scope">
<sa-user-profile type="oper" :user="scope.row.oper" :id="scope.row.oper_id"></sa-user-profile>
</template>
</el-table-column>
<el-table-column prop="createtime" label="时间" width="172" align="center"></el-table-column>
</el-table>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,91 @@
{include file="/shopro/common/script" /}
<style>
.order-batch-dispatch .batch-dispatch-card {
background: var(--sa-table-header-bg);
border-radius: 4px;
padding: 20px;
}
.order-batch-dispatch .batch-dispatch-card .select-append {
padding: 0 16px;
line-height: 30px;
background: var(--sa-table-header-bg);
border: 1px solid var(--sa-border);
box-sizing: border-box;
border-left: none;
border-radius: 0 4px 4px 0;
font-size: 12px;
font-weight: 400;
color: var(--sa-font);
cursor: pointer;
}
.order-batch-dispatch .el-upload__input {
display: none !important;
}
.order-batch-dispatch .el-form-item-file .el-form-item__content {
justify-content: center;
}
.order-batch-dispatch .el-form-item-file .el-form-item__error {
left: unset;
}
</style>
<div id="batchDispatch" class="order-batch-dispatch" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<div class="batch-dispatch-card mb-4">
<div class="title mb-4"> 方法一:如使用导入订单,需完善发货表单物流信息后再上传 </div>
<div class="order-content sa-flex sa-flex-col">
<el-form ref="expressRef" :model="express.form.model" :rules="express.form.rules">
<el-form-item class="el-form-item-file" label="" prop="file">
<div class="sa-flex sa-flex-col">
<div v-if="express.form.model.file" class="sa-table-line-1 mb-2">
<span>{{ express.form.model.file.name }}</span>
</div>
<el-upload :auto-upload="false" :show-file-list="false" accept=".xlsx,.xls"
:on-change="onSelectFile">
<template #trigger>
<el-button v-if="!express.form.model.file">导入发货单</el-button>
<el-button v-if="express.form.model.file" type="primary" link>重新导入发货单
</el-button>
</template>
</el-upload>
</div>
</el-form-item>
<el-form-item label="快递公司" prop="code">
<el-select v-model="express.form.model.code" placeholder="请选择快递公司"
@change="onChangeExpressCode" filterable remote reserve-keyword
:remote-method="remoteMethod" :loading="deliverCompany.loading" autocomplete="none">
<el-option v-for="dc in deliverCompany.select" :key="dc" :label="dc.name"
:value="dc.code" :ref="`express-${dc.code}`" :data-name="dc.name">{{
dc.name
}}&nbsp;({{ dc.code }})</el-option>
<sa-pagination class="is-ellipsis" v-model="deliverCompany.pagination"
@pagination-change="getExpressSelect">
</sa-pagination>
</el-select>
<div class="select-append" @click="onBatchDispatch">发货</div>
</el-form-item>
</el-form>
</div>
</div>
<div class="batch-dispatch-card">
<div class="title mb-4">
方法二:如使用批量发货,需确认
<el-button type="primary" link> &nbsp;商城配置-第三方服务&nbsp; </el-button>
中快递鸟配置完成
</div>
<div class="sa-flex sa-row-center">
<el-button type="primary" :disabled="state.order_ids.length == 0" @click="onDispatchList">批量发货
</el-button>
</div>
</div>
</el-scrollbar>
</el-main>
</el-container>
</div>

View File

@@ -0,0 +1,30 @@
{include file="/shopro/common/script" /}
<div id="changeFee" class="order-change-fee" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-alert class="mb-4" type="warning">
<template #title>注意:改价订单不会影响原分佣金额</template>
</el-alert>
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="110px">
<el-form-item label="当前订单总金额">
¥{{ state.pay_fee }}
</el-form-item>
<el-form-item label="修改价格" prop="pay_fee">
<el-input v-model="form.model.pay_fee" placeholder="数值必须大于0" type="number">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="改价原因" prop="change_msg">
<el-input v-model="form.model.change_msg" autosize type="textarea" placeholder="请输入改价原因">
</el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,201 @@
{include file="/shopro/common/script" /}
<style>
.order-dispatch .title {
height: 32px;
line-height: 32px;
padding: 0 16px;
background: var(--sa-table-header-bg);
border-radius: 4px;
font-size: 12px;
font-weight: 400;
color: var(--sa-subtitle);
margin-bottom: 16px;
}
.order-dispatch .main {
margin-left: 16px;
}
.order-dispatch .left {
color: var(--sa-subfont);
}
.order-dispatch.right {
color: var(--sa-subtitle);
}
.order-dispatch .address .consignee {
margin-bottom: 8px;
}
.order-dispatch .address .pcd {
margin-bottom: 16px;
}
</style>
<div id="dispatch" class="order-dispatch" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-tabs class="mb-2" v-model="state.dispatch_type">
<el-tab-pane v-if="state.nosendItem.length" label="快递发货" name="express"></el-tab-pane>
<el-tab-pane v-if="state.customItem.length" label="手动发货" name="custom"></el-tab-pane>
</el-tabs>
<el-alert class="mb-4" type="warning">
<template #title>温馨提示:正在售后中的商品,请先处理完售后再发货</template>
</el-alert>
<div v-if="state.dispatch_type=='express'">
<el-table class="sa-table" :data="state.nosendItem" @selection-change="onChangeSelection">
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column label="商品信息" min-width="360">
<template #default="scope">
<div class="sa-flex">
<sa-image :url="scope.row.goods_image" size="40"></sa-image>
<div class="ml-2">{{ scope.row.goods_title }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="goods_num" label="数量" min-width="80"></el-table-column>
<el-table-column prop="dispatch_status_text" label="状态" min-width="140">
<template #default="scope">
{{ scope.row.dispatch_status_text }}/{{ scope.row.aftersale_status_text }}
</template>
</el-table-column>
<el-table-column label="快递单号" min-width="80">
<template #default>-</template>
</el-table-column>
</el-table>
<div class="address">
<div class="title">配送信息</div>
<div class="main" v-if="state.detail.address">
<div class="consignee sa-flex">
<div class="left">收货信息:</div>
<div class="right">
{{ state.detail.address.consignee }}&nbsp;
{{ state.detail.address.mobile }}
</div>
</div>
<div class="pcd sa-flex sa-col-top">
<div class="left">收货地址:</div>
<div class="right">
<div>
{{ state.detail.address.province_name }}&nbsp;
{{ state.detail.address.city_name }}&nbsp;
{{ state.detail.address.district_name }}
</div>
<div>{{ state.detail.address.address }}</div>
</div>
</div>
</div>
</div>
<div class="express">
<div class="title">物流信息</div>
<div class="main">
<el-form-item label="发货方式">
<el-radio-group v-model="express.method">
<el-radio label="input">物流快递</el-radio>
<el-radio label="api">一键发货</el-radio>
</el-radio-group>
</el-form-item>
<el-form v-if="express.method == 'input'" ref="expressRef" :inline="true"
:model="express.form.model"
:rules="express.method == 'input' ? express.form.rules : {}">
<el-form-item label="快递公司" prop="code">
<el-select v-model="express.form.model.code" placeholder="请选择快递公司"
@change="onChangeExpressCode" filterable remote reserve-keyword
:remote-method="remoteMethod" :loading="deliverCompany.loading"
autocomplete="none">
<el-option v-for="dc in deliverCompany.select" :key="dc" :label="dc.name"
:value="dc.code" :ref="`express-${dc.code}`" :data-name="dc.name">{{
dc.name
}}&nbsp;({{ dc.code }})</el-option>
<sa-pagination class="is-ellipsis" v-model="deliverCompany.pagination"
@pagination-change="getExpressSelect">
</sa-pagination>
</el-select>
</el-form-item>
<el-form-item label="快递单号" prop="no">
<el-input v-model="express.form.model.no" placeholder="请输入快递单号"></el-input>
</el-form-item>
</el-form>
</div>
</div>
</div>
<div v-if="state.dispatch_type=='custom'">
<el-table class="sa-table" :data="state.customItem" @selection-change="onChangeSelection">
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column label="商品信息" min-width="360">
<template #default="scope">
<div class="sa-flex">
<sa-image :url="scope.row.goods_image" size="40"></sa-image>
<div class="ml-2">{{ scope.row.goods_title }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="goods_num" label="数量" min-width="80"></el-table-column>
<el-table-column prop="dispatch_status_text" label="状态" min-width="140">
<template #default="scope">
{{ scope.row.dispatch_status_text }}/{{ scope.row.aftersale_status_text }}
</template>
</el-table-column>
<el-table-column label="快递单号" min-width="80">
<template #default>-</template>
</el-table-column>
</el-table>
<el-form class="mt-4">
<el-form-item label="发货类型:">
<el-radio-group v-model="state.custom_type" @change="onChangeAutosendType">
<el-radio label="text">固定内容</el-radio>
<el-radio label="params">自定义内容</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="state.custom_type=='text'" label="发货内容:">
<el-input v-model="state.custom_content" placeholder="请输入自动发货内容"></el-input>
</el-form-item>
<el-form-item v-if="state.custom_type=='params'" label="发货内容:">
<div class="sa-template-wrap">
<div class="header sa-flex">
<div class="key">参数名称</div>
<div class="key">内容</div>
<div class="oper">操作</div>
</div>
<draggable v-model="state.custom_content" :animation="300"
handle=".sortable-drag" item-key="element">
<template #item="{ element, index }">
<div class="item">
<el-form-item class="key">
<el-input placeholder="请输入" v-model="element.title">
</el-input>
</el-form-item>
<el-form-item class="key">
<el-input placeholder="请输入" v-model="element.content">
</el-input>
</el-form-item>
<el-form-item class="oper">
<el-popconfirm width="fit-content" confirm-button-text="确认"
cancel-button-text="取消" title="确认删除这条记录?"
@confirm="onDeleteContent(index)">
<template #reference>
<el-button type="danger" link @click.stop>删除
</el-button>
</template>
</el-popconfirm>
<i class="iconfont iconmove sortable-drag"></i>
</el-form-item>
</div>
</template>
</draggable>
<el-button class="add-params" type="primary" plain icon="Plus" @click="onAddContent">添加
</el-button>
</div>
</el-form-item>
</el-form>
</div>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" :disabled="batchHandle.data.length == 0" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,98 @@
{include file="/shopro/common/script" /}
<style>
.order-dispatch-list .code-0 {
color: #ff4d4f;
}
.order-dispatch-list .code-1 {
color: #70c140;
}
.order-dispatch-list .code-nosend {
color: #999;
}
.order-dispatch-list .el-progress__text {
display: none;
}
</style>
<div id="dispatchList" class="order-dispatch-list" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.status">
<el-tab-pane v-for="(sl, key) in state.statusList" :key="sl" :label="`${sl.label}${
state[key] && state[key].length > 0 ? '(' + state[key].length + ')' : ''
}`" :name="key"></el-tab-pane>
</el-tabs>
<template v-if="
(state.status == 'all' || state.status == 'nosend') &&
loop.index < state[state.status].length
">
<div class="sa-flex sa-row-center mt-3">
已完成:{{ (loop.index / state[state.status].length) * 100 }}%
</div>
<el-progress class="mt-2" :percentage="`${(loop.index / state[state.status].length) * 100}`" />
<div class="mt-3">
当前发货:{{ loop.item.province_name }}{{ loop.item.city_name }}{{ loop.item.area_name
}}{{ loop.item.address }}
</div>
</template>
</el-header>
<el-main>
<el-table height="100%" class="sa-table" :data="state[state.status]" stripe>
<template #empty>
<sa-empty />
</template>
<el-table-column prop="order_id" label="ID" min-width="80"></el-table-column>
<el-table-column label="订单号" width="260">
<template #default="scope">
<div>
{{ scope.row.order_sn }}
</div>
</template>
</el-table-column>
<el-table-column label="子订单" width="100">
<template #default="scope">
<div>共{{ scope.row.order_item_ids?.length }}单</div>
</template>
</el-table-column>
<el-table-column label="发货状态" min-width="200">
<template #default="scope">
<div v-if="scope.row.dispatch_status || scope.row.dispatch_status == 0"
:class="['sa-flex', `code-${scope.row.dispatch_status}`]">
<el-icon v-if="scope.row.dispatch_status != 1" class="mr-2"
@click="onAloneDispatch(scope.$index)">
<Refresh />
</el-icon>
{{ scope.row.dispatch_status_text }}
</div>
<div v-else class="code-nosend">待发货</div>
</template>
</el-table-column>
<el-table-column label="快递单号" min-width="260">
<template #default="scope">
<div>
{{ scope.row.express ? scope.row.express.no : '-' }}
</div>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-right">
<template v-if="state.status == 'all' && loop.index < state.all.length">
<el-button @click="onStartDispatch">
<sa-svg class="sa-m-r-4" :name="`sa-shop-order-${loop.index == 0 ? 'start' : 'continue'}`"></sa-svg>
{{ loop.index == 0 ? '开始' : '继续' }}
</el-button>
<el-button v-if="loop.index != 0" @click="onSuspendDispatch">
<sa-svg class="sa-m-r-4" name="sa-shop-order-pause"></sa-svg>
暂停
</el-button>
</template>
<el-button v-if="state.status == 'error'" type="primary" icon="Refresh" @click="onAgainDispatch">重新发货
</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,26 @@
{include file="/shopro/common/script" /}
<div id="fullRefund" class="order-full-refund" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="退款方式">
<div>
<el-radio-group v-model="form.model.refund_type">
<el-radio label="back">原路退回</el-radio>
<el-radio label="money">退回余额</el-radio>
</el-radio-group>
<div class="tip">
将全额退款,并且退回库存减少销量
</div>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>

View File

@@ -0,0 +1,642 @@
{include file="/shopro/common/script" /}
<style>
.order-index .sa-table .el-table__row {
background: var(--sa-background-hex-hover);
}
.order-index .sa-table .el-table__header-wrapper {
margin-bottom: 4px;
}
.order-index .sa-expand-table .el-table__row {
background: var(--el-table-tr-bg-color);
}
.order-index .sa-expand-table .el-table__header-wrapper {
display: none;
}
.order-index .sa-expand-table tr:hover>td.el-table__cell {
background-color: var(--el-table-tr-bg-color) !important;
}
.order-index .goods-item .goods-image {
margin-right: 12px;
}
.order-index .goods-item .goods-id {
color: var(--el-color-primary);
}
.order-index .goods-item .goods-title {
height: 14px;
line-height: 14px;
font-size: 12px;
font-weight: 500;
margin-bottom: 4px;
}
.order-index .goods-item .goods-sku-text {
height: 14px;
line-height: 14px;
margin-bottom: 10px;
}
.order-index .goods-item .goods-price {
margin-right: 8px;
}
.order-index .goods-item .goods-num {
margin-right: 12px;
}
.order-index .dispatch-status {
height: 18px;
line-height: 18px;
padding: 0 6px;
border-radius: 9px;
font-size: 12px;
}
.order-index .dispatch-status.dispatch--1 {
color: #FF4D4F;
background: rgba(255, 77, 79, 0.16);
}
.order-index .dispatch-status.dispatch-0 {
color: #999;
background: rgba(153, 153, 153, .16);
}
.order-index .dispatch-status.dispatch-1 {
color: #faad14;
background: rgba(250, 173, 20, .16);
}
.order-index .dispatch-status.dispatch-2 {
color: #52c41a;
background: rgba(82, 196, 26, .16);
}
.order-index .status.el-button {
width: fit-content;
height: 26px;
padding: 0 12px;
font-size: 12px;
font-weight: 400;
border-radius: 13px;
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
}
.order-index .status.status-primary {
color: var(--el-color-primary);
/* background: var(--sa-background-hex-active); */
}
.order-index .status.status-success {
color: #52c41a;
/* background: rgba(82, 196, 26, 0.16); */
}
.order-index .status.status-warning {
color: #faad14;
/* background: rgba(250, 173, 20, 0.16); */
}
.order-index .status.status-danger {
color: #ff4d4f;
/* background: rgba(255, 77, 79, 0.16); */
}
.order-index .status.status-info {
color: #999999;
/* background: rgba(153, 153, 153, 0.16); */
}
.order-index .address-item .consignee {
line-height: 14px;
color: var(--sa-font);
font-size: 12px;
text-align: left;
margin-bottom: 6px;
}
.order-index .address-item .name {
line-height: 16px;
font-size: 14px;
color: var(--sa-subtitle);
text-align: left;
margin-bottom: 6px;
}
.order-index .address-item .address {
height: 14px;
line-height: 14px;
font-size: 12px;
color: var(--sa-subfont);
}
.order-index .activity-type-text {
width: fit-content;
height: 20px;
padding: 0 5px;
border-radius: 2px;
font-weight: 400;
font-size: 12px;
line-height: 20px;
text-align: center;
}
.order-index .activity-type-text.groupon,
.order-index .activity-type-text.groupon_ladder {
background: var(--t-bg-active);
color: var(--el-color-primary);
}
.order-index .activity-type-text.seckill {
background: rgba(255, 77, 79, 0.16);
color: #ff4d4f;
}
.order-index .refund-status {
font-size: 12px;
font-weight: 400;
color: #52c41a;
margin-left: 4px;
}
.order-index .discount-fee {
line-height: 14px;
font-size: 12px;
font-weight: 400;
color: var(--sa-font);
text-decoration-line: underline;
}
.discount-fee-popover .promo-type-text {
width: fit-content;
height: 20px;
padding: 0 8px;
background: rgba(250, 173, 20, 0.16);
border-radius: 10px;
font-weight: 400;
font-size: 12px;
color: #faad14;
display: flex;
align-items: center;
justify-content: center;
}
.order-index .apply-refund {
margin-right: 12px;
}
.refund-popover .title,
.confirm-popover .title {
line-height: 20px;
font-size: 12px;
font-weight: 400;
color: var(--sa-font);
margin-bottom: 16px;
}
.refund-popover .title .el-icon,
.confirm-popover .title .el-icon {
font-size: 14px;
color: #faad14;
margin-right: 8px;
}
.refund-popover .tip,
.confirm-popover .tip {
font-size: 12px;
font-weight: 400;
color: var(--sa-subfont);
}
.order-index .pay-fee-reference {
width: fit-content;
color: var(--el-color-primary);
border-bottom: 1px dashed var(--el-color-primary);
cursor: pointer;
}
.pay-fee-popover .pay-fee-item {
line-height: 16px;
font-size: 12px;
display: flex;
align-items: center;
margin-bottom: 8px;
}
.pay-fee-popover .pay-fee-item.pay-fee-item-discount {
align-items: flex-start;
}
.pay-fee-popover .pay-fee-item:last-child {
margin-bottom: 0;
}
.pay-fee-popover .pay-fee-item .left {
flex-shrink: 0;
color: var(--sa-subfont);
}
.pay-fee-popover .pay-fee-item .right {
color: var(--sa-subtitle);
}
.pay-fee-popover .pay-fee-item .original-pay-fee {
color: #999;
}
.order-index .order-wrap {
position: relative;
line-height: 14px;
font-size: 12px;
font-weight: 400;
color: var(--sa-font);
}
.order-index .order-wrap>div {
margin-right: 24px;
}
.order-index .order-wrap .id {
min-width: 80px;
color: var(--sa-subtitle);
}
.order-index .order-wrap .order-sn {
min-width: 228px;
height: 14px;
font-size: 12px;
color: var(--sa-subtitle);
}
.order-index .order-wrap .create-time {
line-height: 14px;
font-size: 12px;
color: var(--sa-subtfont);
}
.order-index .order-wrap .platform-text {
min-width: 116px;
}
.order-index .order-wrap .pay-types-text {
margin-right: 0;
}
</style>
<div id="index" class="order-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block">
<el-header class="sa-header">
<el-tabs class="sa-tabs" v-model="state.filter.data.status" @tab-change="onChangeTab">
<el-tab-pane v-for="item in type.data.status" :key="item"
:label="`${item.name}${item.num ? '(' + item.num + ')' : ''}`" :name="item.type"></el-tab-pane>
</el-tabs>
<div class="sa-title sa-flex sa-row-between">
<div class="sa-title-left">
<div class="left-name">订单管理</div>
<sa-filter-condition v-model="state.filter" @filter-delete="onChangeFilter">
</sa-filter-condition>
</div>
<div class="sa-title-right">
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
{if $auth->check('shopro/order/order/export')}
<el-button :loading="exportLoading" :disabled="exportLoading" @click="onExport('export')">订单导出
</el-button>
{/if}
{if $auth->check('shopro/order/order/exportDelivery')}
<el-button v-if="state.filter.data.status == 'nosend'" :loading="exportLoading"
:disabled="exportLoading" @click="onExport('exportDelivery')">导出发货单</el-button>
{/if}
</div>
</div>
</el-header>
<el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe default-expand-all
:span-method="spanMethod" @selection-change="onChangeSelection">
<el-table-column type="expand">
<template #default="props">
<el-table class="sa-table sa-expand-table" :data="props.row.items"
:span-method="spanMethodExpand">
<el-table-column width="96"></el-table-column>
<el-table-column width="304">
<template #default="scope">
<div class="goods-item sa-flex">
<sa-image class="goods-image" :url="scope.row.goods_image" size="58"></sa-image>
<div>
<div class="goods-title sa-table-line-1">
<span class="goods-id">
#{{scope.row.goods_id }}
</span>
{{ scope.row.goods_title }}
</div>
<div class="goods-sku-text">
<span v-if="scope.row.goods_sku_text">
{{ scope.row.goods_sku_text}}
</span>
</div>
<div class="sa-flex">
<span class="goods-price">¥{{ scope.row.goods_price }}</span>
<span class="goods-num">x{{ scope.row.goods_num }}</span>
<!-- 0=未发货|1=已发货|2=已收货 -->
<div class="dispatch-status"
:class="`dispatch-${scope.row.dispatch_status}`">
{{scope.row.dispatch_status_text}}</div>
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column min-width="140" align="center">
<template #default="scope">
<el-button v-if="scope.row.btns?.includes('aftersale_info')" class="status"
:type="aftersaleStyle(scope.row).class" plain @click="onAftersale(scope.row)">
{{scope.row.aftersale_status_text}}
<el-icon>
<arrow-right />
</el-icon>
</el-button>
<div v-else class="status" :class="`status-${aftersaleStyle(scope.row).class}`">
{{scope.row.aftersale_status_text}}</div>
</template>
</el-table-column>
<el-table-column min-width="92" align="center">
<template #default>
<sa-user-profile :user="props.row.user" :id="props.row.user_id" mode="col">
</sa-user-profile>
</template>
</el-table-column>
<el-table-column min-width="168" align="center">
<template #default>
<div v-if="props.row.address" class="address-item sa-flex sa-flex-col sa-col-top">
<div class="consignee">
<span>{{ props.row.address.consignee }}</span>
<span>{{ props.row.address.mobile }}</span>
</div>
<div class="name">
{{ props.row.address.province_name }}/{{ props.row.address.city_name }}/{{
props.row.address.district_name
}}
</div>
<div class="address sa-table-line-1">
{{ props.row.address.address }}
</div>
</div>
<div v-else>{{ props.row.address_id }}</div>
</template>
</el-table-column>
<el-table-column prop="dispatch_type_text" min-width="168" align="center">
</el-table-column>
<el-table-column min-width="160" align="center">
<template #default="scope">
<div class="sa-flex-col sa-col-center">
<div v-if="scope.row.activity_type" class="activity-type-text"
:class="scope.row.activity_type">{{ scope.row.activity_type_text }}</div>
<div class="sa-flex">
¥{{ scope.row.pay_fee }}
<div v-if="scope.row.refund_status != 0" class="refund-status">
{{scope.row.refund_status_text}}
</div>
</div>
<template v-if="Number(scope.row.discount_fee)">
<el-popover popper-class="discount-fee-popover" placement="top"
trigger="hover">
<div class="sa-flex">
<div class="promo-type-text"
v-for="text in scope.row.promo_types_text" :key="text">{{ text
}}</div>
</div>
<template #reference>
<div>
<div v-if="scope.row.promo_types_text?.length > 0"
class="discount-fee">
(含优惠: ¥{{ scope.row.discount_fee }})
</div>
</div>
</template>
</el-popover>
<div v-if="scope.row.promo_types_text?.length == 0" class="discount-fee">
(含优惠: -¥{{ scope.row.discount_fee }})
</div>
</template>
</div>
</template>
</el-table-column>
<el-table-column min-width="230">
<template #default>
<div class="sa-flex">
<el-popover v-model:visible="refundPopover[props.$index]"
popper-class="refund-popover sa-popper" placement="top-start" :width="204"
trigger="click">
<div class="title sa-flex">
<el-icon>
<question-filled />
</el-icon>
您同意用户进行申请退款吗?
</div>
<div class="sa-flex sa-row-right">
{if $auth->check('shopro/order/order/applyRefundRefuse')}
<el-button size="small" type="info" link
@click="onApplyRefundRefuse(props.row.id, props.$index)">拒绝
</el-button>
{/if}
{if $auth->check('shopro/order/order/fullRefund')}
<el-button size="small" type="danger"
@click="onFullRefund(props.row, props.$index)">同意
</el-button>
{/if}
</div>
<template #reference>
<div class="apply-refund-wrap">
<el-button v-if="props.row.btns?.includes('apply_refund_oper')"
class="status apply-refund" type="danger" plain>
用户申请退款
<el-icon>
<arrow-right />
</el-icon>
</el-button>
</div>
</template>
</el-popover>
{if $auth->check('shopro/order/order/dispatch')}
<el-button v-if="props.row.btns?.includes('send')" class="status mr-2"
type="primary" plain @click="onDispatch(props.row.id)">
立即发货
<el-icon>
<arrow-right />
</el-icon>
</el-button>
{/if}
<el-popover v-model:visible="confirmPopover[props.$index]"
popper-class="confirm-popover sa-popper" placement="top-start" :width="204"
trigger="click">
<div class="title sa-flex">
<el-icon>
<question-filled />
</el-icon>
确认用户是否收货?
</div>
<div class="sa-flex sa-row-right">
{if $auth->check('shopro/order/order/offlineRefuse')}
<el-button size="small" type="danger" link
@click="onOfflineRefuse(props.row.id, props.$index)">用户拒收
</el-button>
{/if}
{if $auth->check('shopro/order/order/offlineConfirm')}
<el-button size="small" type="primary"
@click="onOfflineConfirm(props.row.id, props.$index)">确认收货
</el-button>
{/if}
</div>
<template #reference>
<div class="apply-refund-wrap">
<el-button v-if="props.row.btns?.includes('confirm')"
class="status mr-2" type="primary" plain>
确认收货
<el-icon>
<arrow-right />
</el-icon>
</el-button>
</div>
</template>
</el-popover>
{if $auth->check('shopro/order/order/detail')}
<el-button type="primary" link @click="onDetail(props.row.id)">详情
</el-button>
{/if}
{if $auth->check('shopro/order/order/action')}
<el-button type="primary" link @click="onAction(props.row.id)">日志
</el-button>
{/if}
</div>
</template>
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column type="selection" width="48"></el-table-column>
<el-table-column label="商品信息" width="304">
<template #default="scope">
<div class="order-wrap sa-flex">
<div class="id">#{{ scope.row.id }}</div>
<div class="order-sn sa-flex">
订单号:{{ scope.row.order_sn }}
<el-icon class="copy-document" @click="onClipboard(scope.row.order_sn)">
<copy-document />
</el-icon>
</div>
<div class="create-time"> 下单时间:{{ scope.row.createtime }} </div>
<div class="pay-types-text">{{ scope.row.pay_types_text?.join(',') }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="售后状态" min-width="140" align="center"></el-table-column>
<el-table-column label="下单用户" min-width="92" align="center"></el-table-column>
<el-table-column label="收货地址" min-width="168" align="center"></el-table-column>
<el-table-column label="配送方式" min-width="168" align="center"></el-table-column>
<el-table-column label="支付信息" min-width="160" align="center">
<template #default="scope">
<div class="sa-flex sa-row-center">
<el-popover popper-class="pay-fee-popover sa-popper" placement="top" trigger="hover">
<div>
<div class="pay-fee-item">
<div class="left">商品总价:</div>
<div class="right">¥{{ scope.row.goods_amount }}</div>
</div>
<div class="pay-fee-item">
<div class="left">运费价格:</div>
<div class="right"> ¥{{ scope.row.dispatch_amount }} </div>
</div>
<div v-if="scope.row.ext && (scope.row.ext.promo_infos || scope.row.coupon_id)"
class="
pay-fee-item pay-fee-item-discount">
<div class="left">活动优惠:</div>
<div class="right">
<div class="pay-fee-item"
v-if="Number(scope.row.ext.promo_discounts.full_reduce) > 0">
<div class="left">满减</div>
<div class="right">
-¥{{ scope.row.ext.promo_discounts.full_reduce }}
</div>
</div>
<div class="pay-fee-item"
v-if="Number(scope.row.ext.promo_discounts.full_discount) > 0">
<div class="left">满折</div>
<div class="right">
-¥{{ scope.row.ext.promo_discounts.full_discount }}
</div>
</div>
<div class="pay-fee-item"
v-if="Number(scope.row.ext.promo_discounts.full_gift) > 0">
<div class="left">满赠</div>
<div class="right"></div>
</div>
<div class="pay-fee-item"
v-if="Number(scope.row.ext.promo_discounts.free_shipping) > 0">
<div class="left">满包邮</div>
<div class="right">
-¥{{ scope.row.ext.promo_discounts.free_shipping }}
</div>
</div>
<div v-if="scope.row.coupon_id" class="pay-fee-item">
<div class="left">优惠券</div>
<div class="right"> -¥{{ scope.row.coupon_discount_fee }} </div>
</div>
</div>
</div>
<div class="pay-fee-item">
<div class="left">
{{['paid', 'completed'].includes(scope.row.status)?'实付金额':'应付金额'}}
</div>
<div class="right sa-flex">
¥{{ scope.row.pay_fee }}
<s v-if="scope.row.pay_fee != scope.row.original_pay_fee"
class="original-pay-fee ml-1">
{{ scope.row.original_pay_fee }}
</s>
</div>
</div>
</div>
<template #reference>
<div class="pay-fee-reference">¥{{ scope.row.pay_fee }}</div>
</template>
</el-popover>
{if $auth->check('shopro/order/order/changeFee')}
<el-button v-if="scope.row?.btns.includes('change_fee')" type="primary" link
@click="onChangeFee(scope.row)">改价</el-button>
{/if}
</div>
</template>
</el-table-column>
<el-table-column label="操作" min-width="230">
<template #default="scope">
<div class="status" :class="statusCode(scope.row).class">{{statusCode(scope.row).text}}</div>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="sa-footer sa-flex sa-row-between sa-flex-wrap">
<div class="sa-batch sa-flex">
<div class="tip">
已选择 <span>{{batchHandle.data.length}}</span></div>
<div class="sa-flex">
{if $auth->check('shopro/order/order/batchDispatch')}
<el-button :disabled="!batchHandle.data.length" @click="onBatchHandle('dispatch')">批量发货
</el-button>
{/if}
</div>
</div>
<sa-pagination v-model="pagination" @pagination-change="getData"></sa-pagination>
</el-footer>
</el-container>
<sa-filter v-model="state.filter" @filter-change="onChangeFilter"></sa-filter>
</div>

View File

@@ -0,0 +1,28 @@
{include file="/shopro/common/script" /}
<div id="refund" class="order-refund" v-cloak>
<el-container class="panel-block">
<el-main>
<el-scrollbar height="100%">
<el-form :model="form.model" :rules="form.rules" ref="formRef" label-width="100px">
<el-form-item label="退款方式">
<div>
<el-radio-group v-model="form.model.refund_type">
<el-radio label="back">原路退回</el-radio>
<el-radio label="money">退回余额</el-radio>
</el-radio-group>
</div>
</el-form-item>
<el-form-item label="退款金额" prop="refund_money">
<el-input v-model="form.model.refund_money"
:placeholder="`建议退款金额${state.suggest_refund_fee}元`" />
<div class="tip"> 退款时请与买家协商好,退款之后不可撤回 </div>
</el-form-item>
</el-form>
</el-scrollbar>
</el-main>
<el-footer class="sa-footer--submit sa-flex sa-row-right">
<el-button type="primary" @click="onConfirm">确定</el-button>
</el-footer>
</el-container>
</div>