mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-28 13:31:04 +00:00
fix(订单中心): 用户已删除优先展示,用户搜索与订单号分离,支付方式动态加载
普通订单批量发货弹窗与导出字段对齐列表口径。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
02c11e3e19
commit
ccdaecf982
@ -500,6 +500,17 @@ class OrderCenterServices extends BaseService implements OrderCenterSyncInterfac
|
||||
// 确保 buildGroupedData 和前端引擎都能拿到正确的状态文案
|
||||
$detail['status_text'] = OrderCenter::$statusMap[$detail['status_code'] ?? ''] ?? ($detail['status_code'] ?? '');
|
||||
|
||||
// 用户已删除:详情状态统一展示「已删除」(is_del 为软删标记,不改写 status_code)
|
||||
if ((int)($detail['is_del'] ?? 0) === 1) {
|
||||
$detail['status_text'] = '已删除';
|
||||
$detail['business_status'] = [
|
||||
'code' => 'deleted',
|
||||
'label' => '已删除',
|
||||
'text' => '已删除',
|
||||
'type' => 'danger',
|
||||
];
|
||||
}
|
||||
|
||||
// 构建操作按钮(委托给产品类型 Handler)
|
||||
$detail['order_buttons'] = $this->getOrderButtonsFromHandler($detail);
|
||||
// 构建订单生命周期进度条(不同订单类型节点不同,委托给产品类型 Handler)
|
||||
@ -2622,7 +2633,8 @@ class OrderCenterServices extends BaseService implements OrderCenterSyncInterfac
|
||||
/**
|
||||
* 构建关键词搜索闭包(后台订单列表/统计共用)
|
||||
* 按 search_field 限定搜索字段:order_no=订单号前缀、contact_name=收货人、
|
||||
* contact_phone=联系电话、uid=用户ID精确匹配,all/其它=订单号+联系人+电话
|
||||
* contact_phone=联系电话、uid=用户ID精确匹配;
|
||||
* all/其它=用户相关(收货人+电话,纯数字兼查 UID),订单号走独立 order_no 条件
|
||||
* 收货人/电话存于 extra_info JSON,走 JSON 路径匹配
|
||||
* @param string $keyword 关键词(调用方需先 trim)
|
||||
* @param string $searchField 搜索字段标识
|
||||
@ -2651,10 +2663,12 @@ class OrderCenterServices extends BaseService implements OrderCenterSyncInterfac
|
||||
$q->where('uid', '=', (int) $keyword);
|
||||
break;
|
||||
default:
|
||||
// 全部字段:订单号前缀 + 收货人 + 电话
|
||||
$q->whereOr('order_no', 'LIKE', "{$escaped}%")
|
||||
->whereOrRaw("extra_info->>'$.contact.name' LIKE ?", ["%{$escaped}%"])
|
||||
// 用户搜索「全部」:收货人 + 电话;纯数字时兼查 UID(订单号由独立筛选项承担)
|
||||
$q->whereRaw("extra_info->>'$.contact.name' LIKE ?", ["%{$escaped}%"])
|
||||
->whereOrRaw("extra_info->>'$.contact.phone' LIKE ?", ["%{$escaped}%"]);
|
||||
if (ctype_digit((string) $keyword)) {
|
||||
$q->whereOr('uid', '=', (int) $keyword);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -2764,20 +2778,25 @@ class OrderCenterServices extends BaseService implements OrderCenterSyncInterfac
|
||||
}
|
||||
}
|
||||
|
||||
// 扩展表子状态(如待发货/待收货)经 _order_nos 两步筛选;不可因无 extra_conditions 而丢弃
|
||||
$orderNos = $where['_order_nos'] ?? [];
|
||||
|
||||
if (empty($extraConditions)) {
|
||||
// 无扩展条件:直接走 DAO 方法
|
||||
// 无闭包扩展条件:直接走 DAO 方法
|
||||
$finalWhere = $searchWhere;
|
||||
if (!empty($orderNos)) {
|
||||
$finalWhere[] = ['order_no', 'IN', $orderNos];
|
||||
}
|
||||
if (!empty($afterSaleOrderNos)) {
|
||||
$finalWhere[] = ['order_no', 'IN', $afterSaleOrderNos];
|
||||
}
|
||||
$list = $this->dao->selectList($finalWhere, $fields, $page, $limit, 'id DESC');
|
||||
$total = $this->dao->count($finalWhere);
|
||||
} else {
|
||||
// 有扩展条件:用 DAO 提供的查询构建器,避免直接 Db::table
|
||||
// 有闭包扩展条件:用 DAO 提供的查询构建器,避免直接 Db::table
|
||||
$query = $this->dao->getDb()->where($searchWhere);
|
||||
|
||||
// 扩展表条件用两步查询(先查 order_no,再 IN),不 JOIN
|
||||
$orderNos = $where['_order_nos'] ?? [];
|
||||
if (!empty($orderNos)) {
|
||||
$query->whereIn('order_no', $orderNos);
|
||||
}
|
||||
|
||||
@ -1243,6 +1243,23 @@ class OrderController extends AuthController
|
||||
]);
|
||||
$where['order_category'] = 'goods';
|
||||
$where['product_type'] = 'normal';
|
||||
$where['is_deleted'] = !empty($where['is_deleted']);
|
||||
|
||||
// 订单类型映射:与 list 接口一致
|
||||
$type = $where['type'] ?? '';
|
||||
if (!empty($type)) {
|
||||
$activityType = $this->mapOrderType($type);
|
||||
if ($activityType !== '') {
|
||||
$where['activity_type'] = $activityType;
|
||||
}
|
||||
}
|
||||
unset($where['type']);
|
||||
|
||||
// 业务状态(待发货/待收货等)与列表同口径翻译
|
||||
$businessStatus = (string)$this->request->get('business_status', '');
|
||||
if ($businessStatus !== '') {
|
||||
$this->translateBusinessStatus($businessStatus, $where);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $centerServices->getAdminList($where, (int)$where['page'], (int)$where['limit']);
|
||||
@ -1259,12 +1276,18 @@ class OrderController extends AuthController
|
||||
|
||||
$exportData = [];
|
||||
foreach ($list as $item) {
|
||||
$items = $item['items'] ?? [];
|
||||
$storeName = '';
|
||||
if (!empty($items)) {
|
||||
$first = $items[0];
|
||||
$storeName = $first['store_name'] ?? $first['title'] ?? '';
|
||||
// 列表接口无顶层 items,商品名在中台 title 或 extra_info.items[].store_name
|
||||
$goodsItems = $item['extra_info']['items'] ?? ($item['items'] ?? []);
|
||||
$goodsNames = [];
|
||||
foreach ((array)$goodsItems as $goods) {
|
||||
$name = trim((string)($goods['store_name'] ?? $goods['title'] ?? $goods['name'] ?? ''));
|
||||
if ($name !== '') {
|
||||
$goodsNames[] = $name;
|
||||
}
|
||||
}
|
||||
$storeName = $goodsNames
|
||||
? implode(' / ', $goodsNames)
|
||||
: (string)($item['title'] ?? $item['subtitle'] ?? '');
|
||||
|
||||
$exportData[] = [
|
||||
'order_no' => $item['order_no'] ?? '',
|
||||
|
||||
@ -14,10 +14,11 @@
|
||||
<li class="item">
|
||||
<div class="title">订单状态</div>
|
||||
<div>
|
||||
<el-tag :type="getStatusClass(detailData.status_code)">{{
|
||||
getStatusLabel(detailData.status_code)
|
||||
}}</el-tag>
|
||||
<span v-if="detailData.refund_status == 1" style="color: #ed4014; margin-left: 4px">
|
||||
<el-tag :type="getStatusClass(detailData)">{{ getStatusLabel(detailData) }}</el-tag>
|
||||
<span
|
||||
v-if="Number(detailData.is_del) !== 1 && detailData.refund_status == 1"
|
||||
style="color: #ed4014; margin-left: 4px"
|
||||
>
|
||||
退款中
|
||||
</span>
|
||||
</div>
|
||||
@ -114,7 +115,11 @@ function getLogisticsData() {
|
||||
});
|
||||
}
|
||||
|
||||
function getStatusLabel(code) {
|
||||
/** 详情状态:用户已删除优先展示「已删除」,否则按 status_code / status_text */
|
||||
function getStatusLabel(detail) {
|
||||
if (detail && Number(detail.is_del) === 1) return '已删除';
|
||||
if (detail?.status_text) return detail.status_text;
|
||||
const code = typeof detail === 'string' ? detail : detail?.status_code;
|
||||
const map = {
|
||||
pending_payment: '待支付',
|
||||
processing: '待处理',
|
||||
@ -124,12 +129,15 @@ function getStatusLabel(code) {
|
||||
after_sale: '售后中',
|
||||
refunding: '退款中',
|
||||
refunded: '已退款',
|
||||
deleted: '已删除',
|
||||
};
|
||||
return map[code] || code || '--';
|
||||
}
|
||||
|
||||
/* 与列表 getStatusClass 同口径 */
|
||||
function getStatusClass(code) {
|
||||
function getStatusClass(detail) {
|
||||
if (detail && Number(detail.is_del) === 1) return 'danger';
|
||||
const code = typeof detail === 'string' ? detail : detail?.status_code;
|
||||
const map = {
|
||||
pending_payment: 'warning',
|
||||
processing: 'primary',
|
||||
@ -139,6 +147,7 @@ function getStatusClass(code) {
|
||||
after_sale: 'warning',
|
||||
refunding: 'warning',
|
||||
refunded: 'info',
|
||||
deleted: 'danger',
|
||||
};
|
||||
return map[code] || 'info';
|
||||
}
|
||||
|
||||
@ -204,8 +204,8 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" min-width="120">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getStatusClass(scope.row.status_code)">{{ getStatusLabel(scope.row.status_code) }}</el-tag>
|
||||
<div v-if="scope.row.business_status">
|
||||
<el-tag :type="getStatusClass(scope.row)">{{ getStatusLabel(scope.row) }}</el-tag>
|
||||
<div v-if="Number(scope.row.is_del) !== 1 && scope.row.business_status">
|
||||
<span class="business-status">{{ scope.row.business_status.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
@ -469,12 +469,18 @@ function getProductTypeLabel(type) {
|
||||
return item ? item.label : type || '--';
|
||||
}
|
||||
|
||||
function getStatusLabel(code) {
|
||||
function getStatusLabel(rowOrCode) {
|
||||
const row = typeof rowOrCode === 'object' && rowOrCode ? rowOrCode : null;
|
||||
if (row && Number(row.is_del) === 1) return '已删除';
|
||||
const code = row ? row.status_code : rowOrCode;
|
||||
const item = statusCodeOptions.find((opt) => opt.key === code);
|
||||
return item ? item.label : code || '--';
|
||||
}
|
||||
|
||||
function getStatusClass(code) {
|
||||
function getStatusClass(rowOrCode) {
|
||||
const row = typeof rowOrCode === 'object' && rowOrCode ? rowOrCode : null;
|
||||
if (row && Number(row.is_del) === 1) return 'danger';
|
||||
const code = row ? row.status_code : rowOrCode;
|
||||
const map = {
|
||||
pending_payment: 'warning',
|
||||
processing: 'primary',
|
||||
@ -484,6 +490,7 @@ function getStatusClass(code) {
|
||||
after_sale: 'warning',
|
||||
refunding: 'warning',
|
||||
refunded: 'info',
|
||||
deleted: 'danger',
|
||||
};
|
||||
return map[code] || 'info';
|
||||
}
|
||||
|
||||
@ -189,7 +189,8 @@ export function getOrderExpress(orderNo) {
|
||||
* 供详情弹窗等场景复用(列表/详情状态展示保持一致)
|
||||
*/
|
||||
export function getOrderBusinessStatus(row = {}) {
|
||||
if (row.is_del === 1) {
|
||||
// is_del 可能为数字 1 或字符串 "1",与列表口径一致按真值判断
|
||||
if (Number(row.is_del) === 1) {
|
||||
return { code: 'deleted', text: '已删除', type: 'danger' };
|
||||
}
|
||||
if (row.status_code === 'pending_payment') {
|
||||
|
||||
@ -122,46 +122,73 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 批量发货对话框 -->
|
||||
<el-dialog v-model="batchShipmentModal" title="批量发货" width="560px">
|
||||
<div>
|
||||
<p class="mb10">请上传 Excel 文件(<b>xls/xlsx</b>),格式如下:</p>
|
||||
<el-table :data="templateData" border stripe class="mb10">
|
||||
<el-table-column label="订单号" width="200">
|
||||
<template>CP1234567890</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="快递公司" width="150">
|
||||
<template>顺丰速运</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="快递单号" width="150">
|
||||
<template>SF1234567890</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<p class="mb10" style="color: var(--prev-color-text-secondary); font-size: 12px">
|
||||
第一行为表头,从第二行开始为数据
|
||||
</p>
|
||||
<el-dialog
|
||||
v-model="batchShipmentModal"
|
||||
title="批量发货"
|
||||
width="560px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
class="normal-batch-shipment-dialog"
|
||||
@closed="onBatchDialogClosed"
|
||||
>
|
||||
<div class="batch-shipment">
|
||||
<div class="batch-shipment__tip">
|
||||
请按下方格式编辑 Excel(<b>xls / xlsx</b>)后上传,系统将按行完成发货。
|
||||
</div>
|
||||
|
||||
<div class="batch-shipment__format">
|
||||
<div class="batch-shipment__format-title">Excel 格式示例</div>
|
||||
<el-table :data="templateData" border size="small" class="batch-shipment__table">
|
||||
<el-table-column label="订单号" min-width="160" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.order_no }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="快递公司" min-width="120" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.delivery_name }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="快递单号" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.delivery_id }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="batch-shipment__format-note">第一行为表头,从第二行开始填写数据</div>
|
||||
</div>
|
||||
|
||||
<el-upload
|
||||
ref="upload"
|
||||
:action="adminApi + 'normal/order/batch_shipment'"
|
||||
:headers="headers"
|
||||
:on-success="onBatchUploadSuccess"
|
||||
ref="batchUploadRef"
|
||||
class="batch-shipment__upload"
|
||||
drag
|
||||
:action="batchUploadUrl"
|
||||
:headers="batchUploadHeaders"
|
||||
:disabled="batchUploading"
|
||||
:on-success="onBatchFileUploadSuccess"
|
||||
:on-error="onBatchUploadError"
|
||||
:before-upload="onBeforeUpload"
|
||||
accept=".xls,.xlsx"
|
||||
:show-file-list="false"
|
||||
>
|
||||
<template #trigger><el-button type="primary">选取文件上传</el-button></template>
|
||||
<div class="batch-shipment__upload-inner">
|
||||
<i class="el-icon-upload batch-shipment__upload-icon"></i>
|
||||
<div class="batch-shipment__upload-text">
|
||||
<template v-if="batchUploading">正在上传并处理,请稍候…</template>
|
||||
<template v-else>将文件拖到此处,或<em>点击上传</em></template>
|
||||
</div>
|
||||
<div class="batch-shipment__upload-hint">仅支持 .xls、.xlsx</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div v-if="batchResult" class="batch-result mt10">
|
||||
<p>{{ batchResult.msg }}</p>
|
||||
<p v-if="batchResult.data && batchResult.data.errors && batchResult.data.errors.length">
|
||||
<a v-db-click @click="showBatchErrors = !showBatchErrors">
|
||||
{{ showBatchErrors ? '收起' : '查看' }}失败详情({{ batchResult.data.errors.length }}条)
|
||||
</a>
|
||||
</p>
|
||||
<ul v-if="showBatchErrors" style="color: #ed4014; font-size: 12px">
|
||||
<li v-for="(err, idx) in batchResult.data.errors" :key="idx">{{ err }}</li>
|
||||
</ul>
|
||||
|
||||
<div v-if="batchResult" class="batch-shipment__result">
|
||||
<div class="batch-shipment__result-msg">{{ batchResult.msg }}</div>
|
||||
<div
|
||||
v-if="batchResult.data && batchResult.data.errors && batchResult.data.errors.length"
|
||||
class="batch-shipment__result-toggle"
|
||||
>
|
||||
<a v-db-click href="javascript:;" @click="showBatchErrors = !showBatchErrors">
|
||||
{{ showBatchErrors ? '收起' : '查看' }}失败详情({{ batchResult.data.errors.length }}条)
|
||||
</a>
|
||||
</div>
|
||||
<ul v-if="showBatchErrors" class="batch-shipment__result-errors">
|
||||
<li v-for="(err, idx) in batchResult.data.errors" :key="idx">{{ err }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@ -197,7 +224,9 @@ import {
|
||||
getPrintPickList,
|
||||
getOrderExpress,
|
||||
exportOrderList as exportNormalOrder,
|
||||
batchShipment,
|
||||
} from '../normalOrder';
|
||||
import { getCookies } from '@/libs/util';
|
||||
|
||||
import OrderStatistics from './components/OrderStatistics';
|
||||
import OrderSearch from './components/OrderSearch';
|
||||
@ -276,17 +305,24 @@ const editOrderData = ref(null);
|
||||
const batchShipmentModal = ref(false);
|
||||
const batchResult = ref(null);
|
||||
const showBatchErrors = ref(false);
|
||||
const templateData = [{}];
|
||||
const batchUploading = ref(false);
|
||||
const batchUploadRef = ref(null);
|
||||
const templateData = [
|
||||
{
|
||||
order_no: 'CP1234567890',
|
||||
delivery_name: '顺丰速运',
|
||||
delivery_id: 'SF1234567890',
|
||||
},
|
||||
];
|
||||
|
||||
// 批量删除
|
||||
const selectedIds = ref([]);
|
||||
|
||||
const adminApi = computed(() => {
|
||||
return import.meta.env.VITE_APP_API_URL + '/adminapi/';
|
||||
});
|
||||
const headers = computed(() => {
|
||||
return { 'Authori-zation': 'Bearer ' + localStorage.getItem('token') };
|
||||
});
|
||||
// 先上传到文件服务拿到路径,再调批量发货接口(与商品导入同口径)
|
||||
const batchUploadUrl = computed(() => setting.apiBaseURL + '/file/upload/1');
|
||||
const batchUploadHeaders = computed(() => ({
|
||||
'Authori-zation': 'Bearer ' + (getCookies('token') || ''),
|
||||
}));
|
||||
|
||||
/* ===== 数据加载 ===== */
|
||||
|
||||
@ -616,29 +652,61 @@ function openRecord(row) {
|
||||
function openBatchShipment() {
|
||||
batchResult.value = null;
|
||||
showBatchErrors.value = false;
|
||||
batchUploading.value = false;
|
||||
batchShipmentModal.value = true;
|
||||
}
|
||||
|
||||
function onBatchUploadSuccess(res) {
|
||||
batchResult.value = res;
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(res.msg || '批量发货完成');
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(res.msg || '批量发货失败');
|
||||
function onBatchDialogClosed() {
|
||||
batchResult.value = null;
|
||||
showBatchErrors.value = false;
|
||||
batchUploading.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传成功后,用返回路径调用批量发货接口
|
||||
*/
|
||||
function onBatchFileUploadSuccess(res) {
|
||||
if (res.status !== 200 || !res.data || !res.data.src) {
|
||||
batchUploading.value = false;
|
||||
ElMessage.error(res.msg || '文件上传失败');
|
||||
return;
|
||||
}
|
||||
batchShipment({ file: res.data.src })
|
||||
.then((result) => {
|
||||
batchResult.value = result;
|
||||
ElMessage.success(result.msg || '批量发货完成');
|
||||
getList();
|
||||
getStatistics();
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error((err && err.msg) || '批量发货失败');
|
||||
})
|
||||
.finally(() => {
|
||||
batchUploading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function onBatchUploadError(err) {
|
||||
ElMessage.error('批量发货失败:' + (err.msg || '文件上传异常'));
|
||||
batchUploading.value = false;
|
||||
let msg = '文件上传失败';
|
||||
try {
|
||||
const res = JSON.parse(err?.message || '');
|
||||
if (res && res.msg) msg = res.msg;
|
||||
} catch (e) {
|
||||
// 非 JSON 响应,保留默认提示
|
||||
}
|
||||
ElMessage.error(msg);
|
||||
}
|
||||
|
||||
function onBeforeUpload(file) {
|
||||
var suffix = file.name.split('.').pop().toLowerCase();
|
||||
const suffix = (file.name.split('.').pop() || '').toLowerCase();
|
||||
if (!['xls', 'xlsx'].includes(suffix)) {
|
||||
ElMessage.error('文件格式不正确,请上传xls或xlsx格式');
|
||||
ElMessage.error('文件格式不正确,请上传 xls 或 xlsx 格式');
|
||||
return false;
|
||||
}
|
||||
batchResult.value = null;
|
||||
showBatchErrors.value = false;
|
||||
batchUploading.value = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -750,9 +818,12 @@ function handleExport() {
|
||||
page: 1,
|
||||
limit: 200,
|
||||
...searchParams.value,
|
||||
status_code: statusTab.value === 'deleted' ? '' : statusTab.value,
|
||||
is_deleted: statusTab.value === 'deleted' ? 1 : '',
|
||||
};
|
||||
// 与列表同口径:业务子状态走 business_status,勿把 pending_shipped 等塞进 status_code
|
||||
if (statusTab.value && statusTab.value !== 'deleted') {
|
||||
params.business_status = statusTab.value;
|
||||
}
|
||||
doExport(params);
|
||||
})
|
||||
.catch(() => {});
|
||||
@ -805,13 +876,6 @@ onMounted(() => {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.batch-result {
|
||||
padding: 10px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.logistics-box {
|
||||
.logistics-header {
|
||||
display: flex;
|
||||
@ -843,3 +907,136 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- append-to-body 弹窗挂到 body,需非 scoped 样式才能命中 -->
|
||||
<style lang="scss">
|
||||
.normal-batch-shipment-dialog {
|
||||
.batch-shipment {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.batch-shipment__tip {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
color: var(--prev-color-text-regular);
|
||||
|
||||
b {
|
||||
color: var(--prev-color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.batch-shipment__format {
|
||||
padding: 12px;
|
||||
background: var(--prev-bg-color);
|
||||
border: 1px solid var(--prev-border-color-lighter);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.batch-shipment__format-title {
|
||||
margin-bottom: 10px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--prev-color-text-regular);
|
||||
}
|
||||
|
||||
.batch-shipment__table {
|
||||
width: 100%;
|
||||
|
||||
.el-table__empty-block {
|
||||
min-height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.batch-shipment__format-note {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: var(--prev-color-text-secondary);
|
||||
}
|
||||
|
||||
.batch-shipment__upload {
|
||||
width: 100%;
|
||||
|
||||
.el-upload {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-upload-dragger {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding: 28px 16px;
|
||||
border-radius: 4px;
|
||||
border-color: var(--prev-border-color-light);
|
||||
background: var(--prev-bg-white);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--prev-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.batch-shipment__upload-inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.batch-shipment__upload-icon {
|
||||
font-size: 40px;
|
||||
color: var(--prev-color-primary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.batch-shipment__upload-text {
|
||||
font-size: 14px;
|
||||
color: var(--prev-color-text-regular);
|
||||
line-height: 1.5;
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
color: var(--prev-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.batch-shipment__upload-hint {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-text-secondary);
|
||||
}
|
||||
|
||||
.batch-shipment__result {
|
||||
padding: 12px;
|
||||
background: var(--prev-bg-color);
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--prev-border-color-lighter);
|
||||
}
|
||||
|
||||
.batch-shipment__result-msg {
|
||||
font-size: 13px;
|
||||
color: var(--prev-color-text-regular);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.batch-shipment__result-toggle {
|
||||
margin-top: 8px;
|
||||
|
||||
a {
|
||||
font-size: 12px;
|
||||
color: var(--prev-color-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.batch-shipment__result-errors {
|
||||
margin: 8px 0 0;
|
||||
padding-left: 18px;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
color: var(--prev-color-danger, #f56c6c);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -33,18 +33,17 @@
|
||||
value-format="YYYY-MM-DD"
|
||||
></date-range-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单搜索:">
|
||||
<el-form-item label="用户搜索:">
|
||||
<el-input
|
||||
clearable
|
||||
v-model="formData.keyword"
|
||||
placeholder="订单号/联系人/UID"
|
||||
placeholder="联系人/联系电话/UID"
|
||||
class="form_content_width"
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<template #prepend
|
||||
><el-select v-model="formData.search_field" style="width: 100px">
|
||||
<el-option value="all" label="全部"></el-option>
|
||||
<el-option value="order_no" label="订单号"></el-option>
|
||||
<el-option value="contact_name" label="联系人"></el-option>
|
||||
<el-option value="contact_phone" label="联系电话"></el-option>
|
||||
<el-option value="uid" label="UID"></el-option> </el-select
|
||||
@ -61,11 +60,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { ref, reactive, watch, onMounted } from 'vue';
|
||||
import { orderCenterFilterOptions } from '@/api/orderCenter';
|
||||
|
||||
/**
|
||||
* 实物商品订单 - 搜索栏组件
|
||||
* 提供订单号/支付方式/创建时间/关键词等多维度搜索
|
||||
* 提供订单号/支付方式/创建时间/用户关键词等多维度搜索
|
||||
*/
|
||||
defineOptions({ name: 'OrderSearch' });
|
||||
|
||||
@ -93,12 +93,8 @@ const defaultSearch = () => ({
|
||||
|
||||
const formData = reactive(defaultSearch());
|
||||
const timeVal = ref([]);
|
||||
const payTypeOptions = [
|
||||
{ key: 'weixin', label: '微信支付' },
|
||||
{ key: 'yue', label: '余额支付' },
|
||||
{ key: 'alipay', label: '支付宝' },
|
||||
{ key: 'offline', label: '线下支付' },
|
||||
];
|
||||
/** 支付方式下拉:按已安装且启用的支付渠道动态加载,不硬编码 */
|
||||
const payTypeOptions = ref([]);
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
@ -110,6 +106,16 @@ watch(
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
orderCenterFilterOptions()
|
||||
.then((res) => {
|
||||
payTypeOptions.value = res.data?.pay_types || [];
|
||||
})
|
||||
.catch(() => {
|
||||
payTypeOptions.value = [];
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 触发搜索,重置到第一页
|
||||
*/
|
||||
|
||||
@ -508,7 +508,7 @@ function onPageChange() {
|
||||
/* ===== 工具方法 ===== */
|
||||
|
||||
function getBusinessStatus(row) {
|
||||
if (row.is_del === 1) {
|
||||
if (Number(row.is_del) === 1) {
|
||||
return { code: 'deleted', text: '已删除', type: 'danger' };
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user