1
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
|
||||||
// JD订单列表
|
// JD订单列表
|
||||||
export function listJDOrders(query) {
|
export function listJDOrders(query) {
|
||||||
@@ -166,7 +168,22 @@ export function delJDOrder(ids) {
|
|||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
1
|
|
||||||
|
/** 导入跟团返现 Excel(multipart,不用统一 request 以免 Content-Type 覆盖) */
|
||||||
|
export function importGroupRebateExcel(formData) {
|
||||||
|
return axios
|
||||||
|
.post(process.env.VUE_APP_BASE_API + '/system/jdorder/importGroupRebateExcel', formData, {
|
||||||
|
headers: { Authorization: 'Bearer ' + getToken() }
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
const d = res.data
|
||||||
|
if (!d || d.code !== 200) {
|
||||||
|
return Promise.reject(new Error((d && d.msg) || '导入失败'))
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 手动获取物流信息(用于调试)
|
// 手动获取物流信息(用于调试)
|
||||||
export function fetchLogisticsManually(data) {
|
export function fetchLogisticsManually(data) {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@@ -89,6 +89,20 @@
|
|||||||
<el-option label="未晒评价" :value="0" />
|
<el-option label="未晒评价" :value="0" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="后返备注">
|
||||||
|
<el-select
|
||||||
|
v-model="rebateRemarkScreen"
|
||||||
|
placeholder="全部"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
style="width: 160px;"
|
||||||
|
@change="onRebateRemarkScreenChange"
|
||||||
|
>
|
||||||
|
<el-option label="有导入记录" value="any" />
|
||||||
|
<el-option label="含异常项" value="abnormal" />
|
||||||
|
<el-option label="无异常项" value="ok" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<!-- 搜索按钮:桌面端显示,移动端展开时在底部显示 -->
|
<!-- 搜索按钮:桌面端显示,移动端展开时在底部显示 -->
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" size="small" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" size="small" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||||
@@ -116,6 +130,7 @@
|
|||||||
<el-button type="success" size="small" icon="el-icon-check" @click="handleBatchMarkRebateReceived" :loading="batchMarkLoading" title="批量将赔付金额大于0的订单标记为后返到账(仅执行一次)">批量标记后返到账</el-button>
|
<el-button type="success" size="small" icon="el-icon-check" @click="handleBatchMarkRebateReceived" :loading="batchMarkLoading" title="批量将赔付金额大于0的订单标记为后返到账(仅执行一次)">批量标记后返到账</el-button>
|
||||||
<el-button type="warning" size="small" icon="el-icon-sort" @click="handleReverseSyncThirdPartyOrderNo" :loading="reverseSyncLoading" title="从腾讯文档第850行开始,通过物流链接反向匹配订单,将腾讯文档的单号列值写入到订单的第三方单号字段">反向同步第三方单号</el-button>
|
<el-button type="warning" size="small" icon="el-icon-sort" @click="handleReverseSyncThirdPartyOrderNo" :loading="reverseSyncLoading" title="从腾讯文档第850行开始,通过物流链接反向匹配订单,将腾讯文档的单号列值写入到订单的第三方单号字段">反向同步第三方单号</el-button>
|
||||||
<el-button v-if="!isMobile" type="primary" size="small" icon="el-icon-document-copy" @click="handleBatchCopyExcelText" :disabled="selectedRows.length === 0" title="批量复制选中订单的录单格式(Excel可粘贴)">批量复制录单格式</el-button>
|
<el-button v-if="!isMobile" type="primary" size="small" icon="el-icon-document-copy" @click="handleBatchCopyExcelText" :disabled="selectedRows.length === 0" title="批量复制选中订单的录单格式(Excel可粘贴)">批量复制录单格式</el-button>
|
||||||
|
<el-button v-if="!isMobile" type="primary" size="small" icon="el-icon-upload2" @click="rebateImportDialogVisible = true" title="上传跟团返现等 Excel,按单号写入后返备注(可多次导入累加)">导入后返表</el-button>
|
||||||
<el-button v-if="!isMobile" type="success" size="small" icon="el-icon-document-copy" @click="handleBatchCopyRebateText" :disabled="selectedRows.length === 0" title="批量复制选中订单的后返录表格式(Excel可粘贴)">批量复制后返录表</el-button>
|
<el-button v-if="!isMobile" type="success" size="small" icon="el-icon-document-copy" @click="handleBatchCopyRebateText" :disabled="selectedRows.length === 0" title="批量复制选中订单的后返录表格式(Excel可粘贴)">批量复制后返录表</el-button>
|
||||||
<el-button v-if="!isMobile" type="info" size="small" icon="el-icon-document-copy" @click="handleBatchCopySichuanCommerceText" :disabled="selectedRows.length === 0" title="批量复制选中订单的四川商贸录表格式(日期 型号 数量 地址 价格 备注 是否安排 物流)">四川商贸录表</el-button>
|
<el-button v-if="!isMobile" type="info" size="small" icon="el-icon-document-copy" @click="handleBatchCopySichuanCommerceText" :disabled="selectedRows.length === 0" title="批量复制选中订单的四川商贸录表格式(日期 型号 数量 地址 价格 备注 是否安排 物流)">四川商贸录表</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -255,6 +270,14 @@
|
|||||||
<span class="field-label">后返金额</span>
|
<span class="field-label">后返金额</span>
|
||||||
<span class="field-value amount">{{ toYuan(row.rebateAmount) }}</span>
|
<span class="field-value amount">{{ toYuan(row.rebateAmount) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field-row" v-if="row.rebateRemarkJson">
|
||||||
|
<span class="field-label">后返备注</span>
|
||||||
|
<span class="field-value">
|
||||||
|
<el-tag v-if="row.rebateRemarkHasAbnormal === 1" type="danger" size="mini">异常</el-tag>
|
||||||
|
<el-tag v-else-if="row.rebateRemarkHasAbnormal === 0" type="success" size="mini">正常</el-tag>
|
||||||
|
<span style="margin-left: 6px;">{{ rebateRemarkCount(row) }} 条记录</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div class="field-row">
|
<div class="field-row">
|
||||||
<span class="field-label">下单人</span>
|
<span class="field-label">下单人</span>
|
||||||
<span class="field-value">{{ row.buyer || '-' }}</span>
|
<span class="field-value">{{ row.buyer || '-' }}</span>
|
||||||
@@ -366,6 +389,37 @@
|
|||||||
<el-table-column label="后返金额" prop="rebateAmount" width="110" align="right">
|
<el-table-column label="后返金额" prop="rebateAmount" width="110" align="right">
|
||||||
<template slot-scope="scope">{{ toYuan(scope.row.rebateAmount) }}</template>
|
<template slot-scope="scope">{{ toYuan(scope.row.rebateAmount) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="后返备注" prop="rebateRemarkJson" min-width="200" show-overflow-tooltip>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<template v-if="!scope.row.rebateRemarkJson">
|
||||||
|
<span style="color: #c0c4cc;">-</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-tag v-if="scope.row.rebateRemarkHasAbnormal === 1" type="danger" size="mini">异常</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.rebateRemarkHasAbnormal === 0" type="success" size="mini">正常</el-tag>
|
||||||
|
<el-popover trigger="click" placement="left" width="420">
|
||||||
|
<div class="rebate-remark-popover">
|
||||||
|
<div
|
||||||
|
v-for="(it, idx) in parseRebateRemarks(scope.row)"
|
||||||
|
:key="idx"
|
||||||
|
class="rebate-remark-item"
|
||||||
|
>
|
||||||
|
<div class="rebate-remark-title">
|
||||||
|
<b>{{ it.documentTitle || '(未命名)' }}</b>
|
||||||
|
<span class="rebate-remark-time">{{ formatRebateRemarkTime(it.uploadTime) }}</span>
|
||||||
|
</div>
|
||||||
|
<div>是否返现:{{ it.whetherRebate !== undefined && it.whetherRebate !== '' ? it.whetherRebate : '(空)' }}
|
||||||
|
<el-tag v-if="it.abnormal" type="danger" size="mini">异常</el-tag>
|
||||||
|
<el-tag v-else type="success" size="mini">正常</el-tag>
|
||||||
|
</div>
|
||||||
|
<div>返现金额:{{ it.rebateAmount !== undefined && it.rebateAmount !== '' ? it.rebateAmount : '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-button slot="reference" type="text" size="small">明细({{ rebateRemarkCount(scope.row) }})</el-button>
|
||||||
|
</el-popover>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="下单人" prop="buyer" width="100"/>
|
<el-table-column label="下单人" prop="buyer" width="100"/>
|
||||||
|
|
||||||
<!-- 退款状态标签列(多行显示) -->
|
<!-- 退款状态标签列(多行显示) -->
|
||||||
@@ -824,11 +878,47 @@
|
|||||||
|
|
||||||
<!-- 分销标识接收人配置 -->
|
<!-- 分销标识接收人配置 -->
|
||||||
<distribution-mark-touser-config v-model="showTouserConfig" @config-updated="handleTouserConfigUpdated" />
|
<distribution-mark-touser-config v-model="showTouserConfig" @config-updated="handleTouserConfigUpdated" />
|
||||||
|
|
||||||
|
<!-- 导入跟团返现 / 后返 Excel -->
|
||||||
|
<el-dialog
|
||||||
|
title="导入后返表(跟团返现等)"
|
||||||
|
:visible.sync="rebateImportDialogVisible"
|
||||||
|
width="520px"
|
||||||
|
append-to-body
|
||||||
|
@closed="rebateImportTitle = ''"
|
||||||
|
>
|
||||||
|
<p style="color: #909399; font-size: 13px; margin: 0 0 12px;">
|
||||||
|
表头需包含「单号」或「订单号」、「是否返现」、返现金额列(优先「总共返现」)。按单号匹配系统订单并<strong>追加</strong>一条备注记录,同一订单多次上传会保留历史。
|
||||||
|
</p>
|
||||||
|
<el-form label-width="88px" size="small">
|
||||||
|
<el-form-item label="文档标题">
|
||||||
|
<el-input
|
||||||
|
v-model="rebateImportTitle"
|
||||||
|
placeholder="如:跟团+返现 260316(留空则用文件名)"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="Excel">
|
||||||
|
<el-upload
|
||||||
|
drag
|
||||||
|
:show-file-list="true"
|
||||||
|
:limit="1"
|
||||||
|
accept=".xlsx,.xls"
|
||||||
|
:disabled="rebateImportLoading"
|
||||||
|
:http-request="handleRebateExcelUpload"
|
||||||
|
>
|
||||||
|
<i class="el-icon-upload" />
|
||||||
|
<div class="el-upload__text">拖到此处,或<em>点击上传</em></div>
|
||||||
|
<div slot="tip" class="el-upload__tip">仅解析第一个工作表;未匹配到的单号会在结果中列出</div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listJDOrders, updateJDOrder, delJDOrder, fetchLogisticsManually, batchMarkRebateReceived, generateExcelText } from '@/api/system/jdorder'
|
import { listJDOrders, updateJDOrder, delJDOrder, fetchLogisticsManually, batchMarkRebateReceived, generateExcelText, importGroupRebateExcel } from '@/api/system/jdorder'
|
||||||
import { fillLogisticsByOrderNo, getTokenStatus, getTencentDocAuthUrl, testUserInfo, getAutoWriteConfig, reverseSyncThirdPartyOrderNo } from '@/api/jarvis/tendoc'
|
import { fillLogisticsByOrderNo, getTokenStatus, getTencentDocAuthUrl, testUserInfo, getAutoWriteConfig, reverseSyncThirdPartyOrderNo } from '@/api/jarvis/tendoc'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import ListLayout from '@/components/ListLayout'
|
import ListLayout from '@/components/ListLayout'
|
||||||
@@ -875,8 +965,14 @@ export default {
|
|||||||
isRebateReceived: undefined,
|
isRebateReceived: undefined,
|
||||||
isPriceProtected: undefined,
|
isPriceProtected: undefined,
|
||||||
isInvoiceOpened: undefined,
|
isInvoiceOpened: undefined,
|
||||||
isReviewPosted: undefined
|
isReviewPosted: undefined,
|
||||||
|
hasRebateRemark: undefined,
|
||||||
|
rebateRemarkHasAbnormal: undefined
|
||||||
},
|
},
|
||||||
|
rebateRemarkScreen: undefined,
|
||||||
|
rebateImportDialogVisible: false,
|
||||||
|
rebateImportTitle: '',
|
||||||
|
rebateImportLoading: false,
|
||||||
// 同步物流对话框
|
// 同步物流对话框
|
||||||
syncLogisticsDialogVisible: false,
|
syncLogisticsDialogVisible: false,
|
||||||
syncLogisticsLoading: false,
|
syncLogisticsLoading: false,
|
||||||
@@ -1121,6 +1217,78 @@ export default {
|
|||||||
this.queryParams.pageNum = 1
|
this.queryParams.pageNum = 1
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
|
/** 后返备注列表筛选 */
|
||||||
|
onRebateRemarkScreenChange(v) {
|
||||||
|
this.queryParams.hasRebateRemark = undefined
|
||||||
|
this.queryParams.rebateRemarkHasAbnormal = undefined
|
||||||
|
if (v === 'any') {
|
||||||
|
this.queryParams.hasRebateRemark = true
|
||||||
|
} else if (v === 'abnormal') {
|
||||||
|
this.queryParams.rebateRemarkHasAbnormal = 1
|
||||||
|
} else if (v === 'ok') {
|
||||||
|
this.queryParams.hasRebateRemark = true
|
||||||
|
this.queryParams.rebateRemarkHasAbnormal = 0
|
||||||
|
}
|
||||||
|
this.queryParams.pageNum = 1
|
||||||
|
this.prepareQueryParams()
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
parseRebateRemarks(row) {
|
||||||
|
if (!row || !row.rebateRemarkJson) return []
|
||||||
|
try {
|
||||||
|
const arr = JSON.parse(row.rebateRemarkJson)
|
||||||
|
return Array.isArray(arr) ? arr : []
|
||||||
|
} catch (e) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rebateRemarkCount(row) {
|
||||||
|
return this.parseRebateRemarks(row).length
|
||||||
|
},
|
||||||
|
formatRebateRemarkTime(ts) {
|
||||||
|
if (ts == null || ts === '') return ''
|
||||||
|
const d = new Date(typeof ts === 'number' ? ts : Number(ts))
|
||||||
|
if (Number.isNaN(d.getTime())) return ''
|
||||||
|
const y = d.getFullYear()
|
||||||
|
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(d.getDate()).padStart(2, '0')
|
||||||
|
const h = String(d.getHours()).padStart(2, '0')
|
||||||
|
const min = String(d.getMinutes()).padStart(2, '0')
|
||||||
|
return `${y}-${m}-${day} ${h}:${min}`
|
||||||
|
},
|
||||||
|
handleRebateExcelUpload(req) {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', req.file)
|
||||||
|
const title = (this.rebateImportTitle || '').trim()
|
||||||
|
if (title) {
|
||||||
|
formData.append('documentTitle', title)
|
||||||
|
}
|
||||||
|
this.rebateImportLoading = true
|
||||||
|
importGroupRebateExcel(formData)
|
||||||
|
.then((res) => {
|
||||||
|
const data = res.data || {}
|
||||||
|
const msg = data.message || res.msg || '导入完成'
|
||||||
|
this.$message.success(msg)
|
||||||
|
const nf = data.notFoundOrderNos
|
||||||
|
if (nf && nf.length) {
|
||||||
|
const sample = nf.slice(0, 30).join(', ')
|
||||||
|
const more = nf.length > 30 ? ` …共 ${nf.length} 个` : ''
|
||||||
|
this.$alert(`以下单号在系统中未找到,未写入:${sample}${more}`, '未匹配单号', { type: 'warning' })
|
||||||
|
}
|
||||||
|
if (data.errors && data.errors.length) {
|
||||||
|
this.$message.warning(`部分行写入失败 ${data.errors.length} 条,详情见控制台`)
|
||||||
|
console.warn('后返表导入错误', data.errors)
|
||||||
|
}
|
||||||
|
this.rebateImportDialogVisible = false
|
||||||
|
this.getList()
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
this.$message.error(e.message || '导入失败')
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.rebateImportLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.queryParams = {
|
this.queryParams = {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
@@ -1143,8 +1311,11 @@ export default {
|
|||||||
isRebateReceived: undefined,
|
isRebateReceived: undefined,
|
||||||
isPriceProtected: undefined,
|
isPriceProtected: undefined,
|
||||||
isInvoiceOpened: undefined,
|
isInvoiceOpened: undefined,
|
||||||
isReviewPosted: undefined
|
isReviewPosted: undefined,
|
||||||
|
hasRebateRemark: undefined,
|
||||||
|
rebateRemarkHasAbnormal: undefined
|
||||||
}
|
}
|
||||||
|
this.rebateRemarkScreen = undefined
|
||||||
// 重置排序为默认降序
|
// 重置排序为默认降序
|
||||||
this.queryParams.orderBy = 'create_time'
|
this.queryParams.orderBy = 'create_time'
|
||||||
this.queryParams.isAsc = 'desc'
|
this.queryParams.isAsc = 'desc'
|
||||||
@@ -2535,6 +2706,32 @@ export default {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rebate-remark-popover .rebate-remark-item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.rebate-remark-popover .rebate-remark-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
.rebate-remark-popover .rebate-remark-title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.rebate-remark-popover .rebate-remark-time {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: normal;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* 移动端操作按钮样式 - 只在移动端生效 */
|
/* 移动端操作按钮样式 - 只在移动端生效 */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.mobile-action-wrapper {
|
.mobile-action-wrapper {
|
||||||
|
|||||||
Reference in New Issue
Block a user