980 lines
33 KiB
Vue
980 lines
33 KiB
Vue
<script lang="ts" setup>
|
||
import { ref, computed, onMounted, nextTick } from 'vue';
|
||
import { IconSettings } from '@arco-design/web-vue/es/icon';
|
||
import HandsontablePro from '@/components/HandsontablePro/index.vue';
|
||
import PaginationPro from '@/components/PaginationPro/index.vue';
|
||
import { useTableContainerHeight } from '@/composables/useTableContainerHeight';
|
||
import { useI18n } from 'vue-i18n';
|
||
import dayjs from 'dayjs';
|
||
import OrderDetailDrawer from './components/OrderDetailDrawer.vue';
|
||
|
||
defineOptions({
|
||
name: 'MyOrders',
|
||
});
|
||
|
||
const { t } = useI18n();
|
||
const { tableContainerRef, tableHeight } = useTableContainerHeight();
|
||
|
||
// 订单详情抽屉
|
||
const detailDrawerRef = ref<InstanceType<typeof OrderDetailDrawer>>();
|
||
const currentOrder = ref<any>(null);
|
||
|
||
const handleOrderDetailClick = (row: number) => {
|
||
if (row >= 0 && row < orderList.value.length) {
|
||
currentOrder.value = orderList.value[row];
|
||
detailDrawerRef.value?.openDrawer();
|
||
}
|
||
};
|
||
|
||
// 当前激活的标签页
|
||
const activeTab = ref('all');
|
||
|
||
// 标签页配置
|
||
const tabs = ref([
|
||
{ key: 'all', labelKey: 'order.myOrders.tabs.all', count: null },
|
||
{ key: 'draft', labelKey: 'order.myOrders.tabs.draft', count: 0 },
|
||
{ key: 'predeclared', labelKey: 'order.myOrders.tabs.predeclared', count: 0 },
|
||
{ key: 'received', labelKey: 'order.myOrders.tabs.received', count: 0 },
|
||
{ key: 'pendingPayment', labelKey: 'order.myOrders.tabs.pendingPayment', count: 0 },
|
||
{ key: 'pendingShip', labelKey: 'order.myOrders.tabs.pendingShip', count: 0 },
|
||
{ key: 'pendingOnline', labelKey: 'order.myOrders.tabs.pendingOnline', count: 0 },
|
||
{ key: 'shipping', labelKey: 'order.myOrders.tabs.shipping', count: 0 },
|
||
{ key: 'deliverySuccess', labelKey: 'order.myOrders.tabs.deliverySuccess', count: 0 },
|
||
{ key: 'deliveryFailed', labelKey: 'order.myOrders.tabs.deliveryFailed', count: 0 },
|
||
{ key: 'problematic', labelKey: 'order.myOrders.tabs.problematic', count: 0 },
|
||
{ key: 'deleted', labelKey: 'order.myOrders.tabs.deleted', count: null },
|
||
{ key: 'claimed', labelKey: 'order.myOrders.tabs.claimed', count: null },
|
||
]);
|
||
|
||
// 分页相关数据
|
||
const currentPage = ref(1);
|
||
const pageSize = ref(50);
|
||
const totalCount = ref(20);
|
||
|
||
// 生成模拟订单数据
|
||
const generateMockOrders = () => {
|
||
const orders = []
|
||
const countries = ['US', 'GB', 'DE', 'FR', 'CA', 'AU', 'JP', 'KR']
|
||
const cities = ['New York', 'Los Angeles', 'London', 'Paris', 'Berlin', 'Toronto', 'Sydney', 'Tokyo', 'Seoul', 'Shanghai']
|
||
const states = ['California', 'New York', 'Texas', 'Florida', 'Illinois', 'Ontario', 'Quebec', 'NSW', 'Tokyo', 'Seoul']
|
||
const warehouses = ['深圳仓', '东莞仓', '广州仓', '上海仓', '北京仓']
|
||
const shippingMethods = ['美国空运专线(普货)', '美国空运特惠专线898(普货)', 'DHL空运快递', 'EMS国际快递', 'FedEx国际快递']
|
||
const cargoAttributes = ['general', 'electronics', 'sensitive']
|
||
const orderStatuses = ['待支付', '草稿', '已预报', '已收货', '待发货', '待上网', '运输中', '派送成功', '派送失败', '问题件', '已删除', '已理赔']
|
||
const statuses = ['pendingPayment', 'draft', 'predeclared', 'received', 'pendingShip', 'pendingOnline', 'shipping', 'deliverySuccess', 'deliveryFailed', 'problematic', 'deleted', 'claimed']
|
||
|
||
for (let i = 1; i <= 20; i++) {
|
||
const country = countries[Math.floor(Math.random() * countries.length)]
|
||
const city = cities[Math.floor(Math.random() * cities.length)]
|
||
const state = states[Math.floor(Math.random() * states.length)]
|
||
const warehouse = warehouses[Math.floor(Math.random() * warehouses.length)]
|
||
const shippingMethod = shippingMethods[Math.floor(Math.random() * shippingMethods.length)]
|
||
const cargoAttribute = cargoAttributes[Math.floor(Math.random() * cargoAttributes.length)]
|
||
const statusIndex = Math.floor(Math.random() * statuses.length)
|
||
const orderStatus = orderStatuses[statusIndex]
|
||
const status = statuses[statusIndex]
|
||
|
||
// 生成时间(随机在过去30天内)
|
||
const daysAgo = Math.floor(Math.random() * 30)
|
||
const createTime = dayjs().subtract(daysAgo, 'day').format('YYYY-MM-DD HH:mm:ss')
|
||
|
||
// 根据订单状态生成相应的时间
|
||
let receiveTime = ''
|
||
let shipTime = ''
|
||
let payTime = ''
|
||
let signTime = ''
|
||
|
||
if (status === 'pendingPayment') {
|
||
// 待支付:只有创建时间
|
||
payTime = ''
|
||
} else if (status === 'draft' || status === 'predeclared') {
|
||
// 草稿或已预报:只有创建时间
|
||
} else if (status === 'received') {
|
||
// 已收货:有创建时间和收货时间
|
||
receiveTime = daysAgo > 2 ? dayjs().subtract(daysAgo - 2, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
} else if (status === 'pendingShip') {
|
||
// 待发货:有创建时间和收货时间
|
||
receiveTime = daysAgo > 2 ? dayjs().subtract(daysAgo - 2, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
} else if (status === 'pendingOnline') {
|
||
// 待上网:有创建时间、收货时间、发货时间
|
||
receiveTime = daysAgo > 3 ? dayjs().subtract(daysAgo - 3, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
shipTime = daysAgo > 2 ? dayjs().subtract(daysAgo - 2, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
} else if (status === 'shipping') {
|
||
// 运输中:有创建时间、收货时间、发货时间
|
||
receiveTime = daysAgo > 3 ? dayjs().subtract(daysAgo - 3, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
shipTime = daysAgo > 1 ? dayjs().subtract(daysAgo - 1, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
} else if (status === 'completed') {
|
||
// 已完成:有所有时间
|
||
receiveTime = daysAgo > 5 ? dayjs().subtract(daysAgo - 5, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
shipTime = daysAgo > 4 ? dayjs().subtract(daysAgo - 4, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
payTime = daysAgo > 3 ? dayjs().subtract(daysAgo - 3, 'day').format('YYYY-MM-DD HH:mm:ss') : createTime
|
||
signTime = daysAgo > 0 ? dayjs().subtract(Math.floor(Math.random() * daysAgo), 'day').format('YYYY-MM-DD HH:mm:ss') : ''
|
||
}
|
||
|
||
const waybillNoVal = `LP${String(Math.floor(Math.random() * 100000000000000)).padStart(14, '0')}`;
|
||
const clientNoVal = `CUST${String(Math.floor(Math.random() * 100000000000)).padStart(12, '0')}`;
|
||
const trackNoVal = `TRK${String(Math.floor(Math.random() * 100000000000000)).padStart(15, '0')}`;
|
||
const consigneeName = `收件人${i}`;
|
||
const consigneePhoneVal = `1${Math.floor(Math.random() * 1000000000).toString().padStart(10, '0')}`;
|
||
const consigneeAddr = `${city}市${state}区${Math.floor(Math.random() * 999) + 1}号`;
|
||
const consigneeZip = String(Math.floor(Math.random() * 100000)).padStart(5, '0');
|
||
const eoriVal = Math.random() > 0.5 ? `EORI${String(Math.floor(Math.random() * 1000000000)).padStart(12, '0')}` : '';
|
||
|
||
orders.push({
|
||
id: i,
|
||
waybillNo: waybillNoVal,
|
||
customerOrderNo: clientNoVal,
|
||
trackingNo: trackNoVal,
|
||
serviceNo: waybillNoVal,
|
||
clientNo: clientNoVal,
|
||
trackNo: trackNoVal,
|
||
shippingMethod: shippingMethod,
|
||
productCode: 'US_AIR',
|
||
channelCode: 'CH001',
|
||
cargoAttribute: cargoAttribute,
|
||
consigneeCountry: country,
|
||
chargeableWeight: (Math.random() * 10 + 0.1).toFixed(2),
|
||
receivableAmount: (Math.random() * 500 + 50).toFixed(2),
|
||
consignee: consigneeName,
|
||
consigneePhone: consigneePhoneVal,
|
||
consigneeAddress: consigneeAddr,
|
||
consigneePostcode: consigneeZip,
|
||
consigneeState: state,
|
||
consigneeCity: city,
|
||
ioss: Math.random() > 0.5 ? `IOSS${String(Math.floor(Math.random() * 1000000000)).padStart(12, '0')}` : '',
|
||
eori: eoriVal,
|
||
orderStatus: orderStatus,
|
||
status: status,
|
||
createTime: createTime,
|
||
receiveTime: receiveTime,
|
||
shipTime: shipTime,
|
||
payTime: payTime,
|
||
signTime: signTime,
|
||
warehouse: warehouse,
|
||
warehouseId: 1,
|
||
customerId: 1,
|
||
isIntercept: Math.random() > 0.8,
|
||
isRemote: Math.random() > 0.9,
|
||
sender: {
|
||
senderName: '发件人' + i,
|
||
company: '示例公司',
|
||
phone: '13800138000',
|
||
telePhone: '',
|
||
email: 'sender@example.com',
|
||
countryCode: 0,
|
||
country: '中国',
|
||
province: '广东省',
|
||
city: '深圳市',
|
||
zipCode: '518000',
|
||
streetAddress1: '示例地址1',
|
||
streetAddress2: '',
|
||
streetAddress3: '',
|
||
houseNumber: '',
|
||
},
|
||
receiver: {
|
||
recipientsName: consigneeName,
|
||
companyName: '',
|
||
phone: consigneePhoneVal,
|
||
telePhone: '',
|
||
email: '',
|
||
countryCode: 0,
|
||
country: country,
|
||
province: state,
|
||
city: city,
|
||
streetNumber: '',
|
||
streetAddress1: consigneeAddr,
|
||
streetAddress2: '',
|
||
streetAddress3: '',
|
||
zipCode: consigneeZip,
|
||
taxType: 0,
|
||
taxNo: '',
|
||
certificateType: 0,
|
||
certificateNo: '',
|
||
eori: eoriVal,
|
||
vat: '',
|
||
},
|
||
items: [
|
||
{
|
||
cnName: '示例商品',
|
||
enName: 'Sample Product',
|
||
sku: 'SKU001',
|
||
unit: '件',
|
||
unitPrice: 10,
|
||
unitWeight: 0.5,
|
||
quantity: 1,
|
||
amount: 10,
|
||
weight: 0.5,
|
||
hsCode: '1234567890',
|
||
skuImage: '',
|
||
category: '普货',
|
||
brand: '示例品牌',
|
||
brandType: '自有',
|
||
isMagnetic: false,
|
||
distribution: '',
|
||
material: '塑料',
|
||
enMaterial: 'Plastic',
|
||
purpose: '日用',
|
||
attributes: '',
|
||
originCountry: '中国',
|
||
salesLink: '',
|
||
model: '',
|
||
specifications: '',
|
||
comment: '',
|
||
},
|
||
],
|
||
weightList: [
|
||
{
|
||
type: 'forecast',
|
||
length: String(Math.floor(Math.random() * 30) + 10),
|
||
width: String(Math.floor(Math.random() * 20) + 8),
|
||
height: String(Math.floor(Math.random() * 15) + 5),
|
||
actualWeight: (Math.random() * 5 + 0.5).toFixed(2),
|
||
volumetricWeight: (Math.random() * 4 + 0.5).toFixed(2),
|
||
chargeableWeight: (Math.random() * 5 + 0.5).toFixed(2),
|
||
cubic: (Math.random() * 0.01).toFixed(4),
|
||
},
|
||
],
|
||
})
|
||
}
|
||
return orders
|
||
}
|
||
|
||
// 全部模拟订单(按 status 对应到 tab)
|
||
const allMockOrders = ref(generateMockOrders());
|
||
|
||
// 当前 tab 筛选后的订单列表
|
||
const orderList = ref<any[]>([]);
|
||
|
||
// 选中的行数
|
||
const selectedRowCount = ref(0)
|
||
|
||
// 加载订单列表(用假数据,按 tab 筛选)
|
||
const loadOrderList = () => {
|
||
const filtered = activeTab.value === 'all'
|
||
? allMockOrders.value
|
||
: allMockOrders.value.filter((o) => (o.status || o.orderStatus) === activeTab.value);
|
||
const start = (currentPage.value - 1) * pageSize.value;
|
||
orderList.value = filtered.slice(start, start + pageSize.value);
|
||
totalCount.value = filtered.length;
|
||
|
||
// 更新各 tab 的 count
|
||
tabs.value.forEach((tab) => {
|
||
if (tab.count !== null && tab.key !== 'all') {
|
||
tab.count = allMockOrders.value.filter((o) => (o.status || o.orderStatus) === tab.key).length;
|
||
}
|
||
});
|
||
};
|
||
|
||
// 当前页数据(HandsontablePro 用)
|
||
const processedTableData = computed(() => orderList.value);
|
||
|
||
// 标签页切换
|
||
const handleTabChange = (key: string) => {
|
||
activeTab.value = key;
|
||
currentPage.value = 1;
|
||
loadOrderList();
|
||
};
|
||
|
||
// 操作按钮处理
|
||
const handlePay = () => {
|
||
};
|
||
|
||
const handlePreDeclare = () => {
|
||
};
|
||
|
||
const handleIntercept = () => {
|
||
};
|
||
|
||
const handleCancelIntercept = () => {
|
||
};
|
||
|
||
const handleDelete = () => {
|
||
};
|
||
|
||
const handlePrint = () => {
|
||
};
|
||
|
||
const handleExport = () => {
|
||
};
|
||
|
||
const handleModifyOrder = () => {
|
||
};
|
||
|
||
const handleSettings = () => {
|
||
};
|
||
|
||
// 分页处理函数
|
||
const handlePageChange = (page: number) => {
|
||
currentPage.value = page;
|
||
loadOrderList();
|
||
};
|
||
|
||
const handlePageSizeChange = (size: number) => {
|
||
pageSize.value = size;
|
||
currentPage.value = 1;
|
||
loadOrderList();
|
||
};
|
||
|
||
// HandsontablePro 列定义
|
||
const hotColumns = computed(() => [
|
||
{ key: 'waybillNo', label: t('order.myOrders.table.waybillNo'), width: 90 },
|
||
{ key: 'customerOrderNo', label: t('order.myOrders.table.customerOrderNo'), width: 120 },
|
||
{ key: 'trackingNo', label: t('order.myOrders.table.trackingNo'), width: 120 },
|
||
{ key: 'shippingMethod', label: t('order.myOrders.table.shippingMethod'), width: 140 },
|
||
{ key: 'cargoAttribute', label: t('order.myOrders.table.cargoAttribute'), width: 85 },
|
||
{ key: 'consigneeCountry', label: t('order.myOrders.table.consigneeCountry'), width: 90 },
|
||
{ key: 'chargeableWeight', label: t('order.myOrders.table.chargeableWeight'), width: 95 },
|
||
{ key: 'receivableAmount', label: t('order.myOrders.table.receivableAmount'), width: 95 },
|
||
{ key: 'consignee', label: t('order.myOrders.table.consignee'), width: 90 },
|
||
{ key: 'consigneePhone', label: t('order.myOrders.table.consigneePhone'), width: 110 },
|
||
{ key: 'consigneeAddress', label: t('order.myOrders.table.consigneeAddress'), width: 140 },
|
||
{ key: 'consigneePostcode', label: t('order.myOrders.table.consigneePostcode'), width: 90 },
|
||
{ key: 'consigneeState', label: t('order.myOrders.table.consigneeState'), width: 90 },
|
||
{ key: 'consigneeCity', label: t('order.myOrders.table.consigneeCity'), width: 90 },
|
||
{ key: 'ioss', label: t('order.myOrders.table.ioss'), width: 100 },
|
||
{ key: 'eori', label: t('order.myOrders.table.eori'), width: 100 },
|
||
{ key: 'orderStatus', label: t('order.myOrders.table.orderStatus'), width: 90 },
|
||
{ key: 'createTime', label: t('order.myOrders.table.createTime'), width: 150 },
|
||
{ key: 'receiveTime', label: t('order.myOrders.table.receiveTime'), width: 150 },
|
||
{ key: 'shipTime', label: t('order.myOrders.table.shipTime'), width: 150 },
|
||
{ key: 'payTime', label: t('order.myOrders.table.payTime'), width: 150 },
|
||
{ key: 'signTime', label: t('order.myOrders.table.signTime'), width: 150 },
|
||
{ key: 'warehouse', label: t('order.myOrders.table.warehouse'), width: 90 },
|
||
]);
|
||
|
||
const iconView = '<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:16px;height:16px;color:var(--app-primary-color,#2D8C8C);"><path d="M8 2C4.5 2 1.73 4.11 0 7c1.73 2.89 4.5 5 8 5s6.27-2.11 8-5c-1.73-2.89-4.5-5-8-5zM8 11.5c-2.48 0-4.5-2.02-4.5-4.5S5.52 2.5 8 2.5s4.5 2.02 4.5 4.5S10.48 11.5 8 11.5zM8 4.5c-1.38 0-2.5 1.12-2.5 2.5S6.62 9.5 8 9.5s2.5-1.12 2.5-2.5S9.38 4.5 8 4.5z" fill="currentColor"/></svg>';
|
||
|
||
const actionRenderer = (row: any, rowIndex: number) => {
|
||
return `<div class="view-icon-wrapper" data-action="view" data-row-index="${rowIndex}" style="display: inline-flex; align-items: center; justify-content: center; cursor: pointer; padding: 4px; border-radius: 4px; transition: all 0.2s;">${iconView}</div>`;
|
||
};
|
||
|
||
const customCellRenderer = (row: number, col: number, value: any, rowData: any) => {
|
||
const colOffset = 2; // action + serialNo
|
||
const dataColIndex = col - colOffset;
|
||
if (dataColIndex < 0 || dataColIndex >= hotColumns.value.length) return null;
|
||
const colKey = hotColumns.value[dataColIndex].key;
|
||
|
||
if (colKey === 'cargoAttribute' && value) {
|
||
const cargoKey = `order.myOrders.drawer.cargoAttribute.${value}`;
|
||
const translated = t(cargoKey);
|
||
return translated !== cargoKey ? translated : value;
|
||
}
|
||
if (colKey === 'orderStatus') {
|
||
const status = rowData?.orderStatus || rowData?.status || '';
|
||
let tagColor = '#86909c';
|
||
let tagBgColor = '#f2f3f5';
|
||
let statusKey = '';
|
||
if (status === '待支付' || status === 'pendingPayment') {
|
||
tagColor = '#ff7d00';
|
||
tagBgColor = '#fff7e6';
|
||
statusKey = 'order.myOrders.status.pendingPayment';
|
||
} else if (status === '草稿' || status === 'draft') {
|
||
statusKey = 'order.myOrders.status.draft';
|
||
} else if (status === '已预报' || status === 'predeclared') {
|
||
tagColor = '#165dff';
|
||
tagBgColor = '#e8f3ff';
|
||
statusKey = 'order.myOrders.status.predeclared';
|
||
} else if (status === '已收货' || status === 'received') {
|
||
tagColor = '#00b42a';
|
||
tagBgColor = '#e8f8e8';
|
||
statusKey = 'order.myOrders.status.received';
|
||
} else if (status === '待发货' || status === 'pendingShip') {
|
||
tagColor = '#ff7d00';
|
||
tagBgColor = '#fff7e6';
|
||
statusKey = 'order.myOrders.status.pendingShip';
|
||
} else if (status === '待上网' || status === 'pendingOnline') {
|
||
tagColor = '#165dff';
|
||
tagBgColor = '#e8f3ff';
|
||
statusKey = 'order.myOrders.status.pendingOnline';
|
||
} else if (status === '运输中' || status === 'shipping') {
|
||
tagColor = '#165dff';
|
||
tagBgColor = '#e8f3ff';
|
||
statusKey = 'order.myOrders.status.shipping';
|
||
} else if (status === '派送成功' || status === 'deliverySuccess') {
|
||
tagColor = '#00b42a';
|
||
tagBgColor = '#e8f8e8';
|
||
statusKey = 'order.myOrders.status.deliverySuccess';
|
||
} else if (status === '派送失败' || status === 'deliveryFailed') {
|
||
tagColor = '#f53f3f';
|
||
tagBgColor = '#ffece8';
|
||
statusKey = 'order.myOrders.status.deliveryFailed';
|
||
} else if (status === '问题件' || status === 'problematic') {
|
||
tagColor = '#f53f3f';
|
||
tagBgColor = '#ffece8';
|
||
statusKey = 'order.myOrders.status.problematic';
|
||
} else if (status === '已删除' || status === 'deleted') {
|
||
statusKey = 'order.myOrders.status.deleted';
|
||
} else if (status === '已理赔' || status === 'claimed') {
|
||
tagColor = '#722ed1';
|
||
tagBgColor = '#f7e8ff';
|
||
statusKey = 'order.myOrders.status.claimed';
|
||
}
|
||
const statusText = statusKey ? t(statusKey) : status;
|
||
return `<span style="display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 12px; color: ${tagColor}; background-color: ${tagBgColor}; white-space: nowrap;">${statusText}</span>`;
|
||
}
|
||
if (['chargeableWeight', 'receivableAmount'].includes(colKey)) {
|
||
return value != null && value !== '' ? Number(value).toLocaleString() : null;
|
||
}
|
||
// 首列添加 data-row-status 用于行背景样式
|
||
if (colKey === 'waybillNo') {
|
||
const status = rowData?.status || rowData?.orderStatus || '';
|
||
return `<span data-row-status="${status}">${value || '--'}</span>`;
|
||
}
|
||
return null;
|
||
};
|
||
|
||
const handleActionClick = (row: any) => {
|
||
currentOrder.value = row;
|
||
detailDrawerRef.value?.openDrawer();
|
||
};
|
||
|
||
const handleSelectionChange = (rows: any[]) => {
|
||
selectedRowCount.value = rows.length;
|
||
};
|
||
|
||
onMounted(() => {
|
||
nextTick(() => loadOrderList());
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<div class="my-orders-container">
|
||
<!-- 标签页导航和操作按钮 -->
|
||
<div class="tabs-actions-section">
|
||
<div class="tabs-container">
|
||
<div
|
||
v-for="tab in tabs"
|
||
:key="tab.key"
|
||
:class="['tab-item', { active: activeTab === tab.key }]"
|
||
@click="handleTabChange(tab.key)"
|
||
>
|
||
<span class="tab-label">{{ tab.label || $t(tab.labelKey) }}</span>
|
||
<span v-if="tab.count !== null" class="tab-count">({{ tab.count }})</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="actions-right">
|
||
<a-button class="btn-pay" @click="handlePay">{{ t('order.myOrders.actions.pay') }}</a-button>
|
||
<a-button class="btn-predeclare" @click="handlePreDeclare">{{ t('order.myOrders.actions.predeclare') }}</a-button>
|
||
<a-button class="btn-intercept" @click="handleIntercept">{{ t('order.myOrders.actions.intercept') }}</a-button>
|
||
<a-button class="btn-cancel-intercept" @click="handleCancelIntercept">{{ t('order.myOrders.actions.cancelIntercept') }}</a-button>
|
||
<a-button class="btn-delete" @click="handleDelete">{{ t('order.myOrders.actions.delete') }}</a-button>
|
||
<a-button class="btn-print" @click="handlePrint">{{ t('order.myOrders.actions.print') }}</a-button>
|
||
<a-button class="btn-export" @click="handleExport">{{ t('order.myOrders.actions.export') }}</a-button>
|
||
<a-button class="btn-modify" @click="handleModifyOrder">{{ t('order.myOrders.actions.modifyOrder') }}</a-button>
|
||
<a-button class="btn-settings" @click="handleSettings">
|
||
<icon-settings />
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 订单表格区域 -->
|
||
<div class="table-section">
|
||
<!-- 表格操作按钮和分页控制 -->
|
||
<div class="table-toolbar">
|
||
<div class="toolbar-left">
|
||
<span class="selected-count">
|
||
{{ t('order.myOrders.selectedCount', { count: selectedRowCount }) }}
|
||
</span>
|
||
</div>
|
||
|
||
<div class="toolbar-right">
|
||
<div class="pagination-controls">
|
||
<PaginationPro
|
||
:total-count="totalCount"
|
||
v-model:current-page="currentPage"
|
||
v-model:page-size="pageSize"
|
||
@page-change="handlePageChange"
|
||
@page-size-change="handlePageSizeChange"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div ref="tableContainerRef" class="list-wrap">
|
||
<HandsontablePro
|
||
:columns="hotColumns"
|
||
:data="processedTableData"
|
||
:total="totalCount"
|
||
:current-page="currentPage"
|
||
:page-size="pageSize"
|
||
:show-action-column="true"
|
||
:action-column-position="'start'"
|
||
:action-column-width="60"
|
||
:action-renderer="actionRenderer"
|
||
:custom-cell-renderer="customCellRenderer"
|
||
:stretch-columns="true"
|
||
:height="tableHeight"
|
||
@action-click="handleActionClick"
|
||
@selection-change="handleSelectionChange"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 订单详情抽屉(左侧) -->
|
||
<OrderDetailDrawer
|
||
ref="detailDrawerRef"
|
||
:order="currentOrder"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<style lang="less" scoped>
|
||
.my-orders-container {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
padding: 16px 16px 24px;
|
||
background-color: #f0f3f4;
|
||
flex: 1;
|
||
min-height: 0;
|
||
overflow-x: hidden;
|
||
overflow-y: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.page-header {
|
||
margin-bottom: 24px;
|
||
|
||
h2 {
|
||
margin: 0;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: #262626;
|
||
}
|
||
}
|
||
|
||
.tabs-actions-section {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
padding: 0 16px;
|
||
margin-bottom: 16px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.tabs-container {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.tab-item {
|
||
padding: 16px 20px;
|
||
cursor: pointer;
|
||
border-bottom: 3px solid transparent;
|
||
transition: all 0.3s;
|
||
position: relative;
|
||
|
||
&:hover {
|
||
background-color: #f8f9fa;
|
||
}
|
||
|
||
&.active {
|
||
border-bottom-color: var(--app-primary-color);
|
||
|
||
.tab-label {
|
||
color: var(--app-primary-color);
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.tab-label {
|
||
font-size: 14px;
|
||
color: #262626;
|
||
transition: color 0.3s;
|
||
}
|
||
|
||
.tab-count {
|
||
font-size: 12px;
|
||
color: #8c8c8c;
|
||
margin-left: 4px;
|
||
}
|
||
}
|
||
|
||
.actions-right {
|
||
display: flex;
|
||
gap: var(--app-button-gap, 8px);
|
||
align-items: center;
|
||
padding: 16px 0;
|
||
|
||
.arco-btn {
|
||
border-radius: 4px;
|
||
font-weight: 500;
|
||
transition: all 0.3s ease;
|
||
border: 2px solid;
|
||
position: relative;
|
||
overflow: hidden;
|
||
padding: 8px 16px;
|
||
height: auto;
|
||
|
||
// 支付按钮 - 淡黄色
|
||
&.btn-pay {
|
||
background: #fffbe6;
|
||
border-color: #ffd666;
|
||
color: #d46b08;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: #fff7d1;
|
||
border-color: #ffc53d;
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: #fff1b8;
|
||
border-color: #ffb020;
|
||
}
|
||
}
|
||
|
||
// 预报按钮 - 主题色
|
||
&.btn-predeclare {
|
||
background: var(--app-primary-color);
|
||
border-color: var(--app-primary-color);
|
||
color: #ffffff;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
}
|
||
|
||
// 拦截按钮 - 主题色
|
||
&.btn-intercept {
|
||
background: var(--app-primary-color);
|
||
border-color: var(--app-primary-color);
|
||
color: #ffffff;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
}
|
||
|
||
// 取消拦截按钮 - 主题色
|
||
&.btn-cancel-intercept {
|
||
background: var(--app-primary-color);
|
||
border-color: var(--app-primary-color);
|
||
color: #ffffff;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
}
|
||
|
||
// 删除按钮 - 主题色
|
||
&.btn-delete {
|
||
background: var(--app-primary-color);
|
||
border-color: var(--app-primary-color);
|
||
color: #ffffff;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
}
|
||
|
||
// 打印按钮 - 主题色
|
||
&.btn-print {
|
||
background: var(--app-primary-color);
|
||
border-color: var(--app-primary-color);
|
||
color: #ffffff;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
}
|
||
|
||
// 导出按钮 - 主题色
|
||
&.btn-export {
|
||
background: var(--app-primary-color);
|
||
border-color: var(--app-primary-color);
|
||
color: #ffffff;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
}
|
||
|
||
// 修改订单按钮 - 主题色
|
||
&.btn-modify {
|
||
background: var(--app-primary-color);
|
||
border-color: var(--app-primary-color);
|
||
color: #ffffff;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
}
|
||
|
||
// 设置按钮 - 主题色
|
||
&.btn-settings {
|
||
background: var(--app-primary-color);
|
||
border-color: var(--app-primary-color);
|
||
color: #ffffff;
|
||
padding: 8px 12px;
|
||
min-width: 36px;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
|
||
&:active:not(:disabled) {
|
||
background: var(--app-primary-color-hover);
|
||
border-color: var(--app-primary-color-hover);
|
||
}
|
||
}
|
||
|
||
// 禁用状态
|
||
&:disabled {
|
||
opacity: 1;
|
||
cursor: not-allowed;
|
||
background: rgba(169, 169, 169, 0.8) !important;
|
||
border-color: rgba(169, 169, 169, 0.8) !important;
|
||
color: #ffffff !important;
|
||
transform: none !important;
|
||
box-shadow: none !important;
|
||
}
|
||
}
|
||
}
|
||
|
||
.table-section {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
padding: 0;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
flex: 1;
|
||
min-height: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.table-toolbar {
|
||
padding: 16px 16px 0;
|
||
margin-bottom: 16px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
flex-wrap: nowrap;
|
||
|
||
.toolbar-left {
|
||
flex: 1;
|
||
|
||
.selected-count {
|
||
font-size: 14px;
|
||
color: #4e5969;
|
||
|
||
.count-number {
|
||
color: #f53f3f;
|
||
font-weight: 600;
|
||
margin: 0 2px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.toolbar-right {
|
||
.pagination-controls {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
}
|
||
}
|
||
|
||
.list-wrap {
|
||
width: 100%;
|
||
overflow: hidden;
|
||
flex: 1;
|
||
min-height: 0;
|
||
padding: 0 16px 16px;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overscroll-behavior: contain;
|
||
touch-action: pan-x pan-y;
|
||
|
||
:deep(.handsontable-pro-container) {
|
||
width: 100%;
|
||
flex: 1;
|
||
min-height: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.handsontable-wrapper {
|
||
width: 100%;
|
||
|
||
:deep(.handsontable) {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||
border: none !important;
|
||
|
||
// 覆盖 Handsontable 默认的 table 边框
|
||
table {
|
||
border: none !important;
|
||
}
|
||
|
||
.ht_master,
|
||
.ht_clone_top,
|
||
.ht_clone_left,
|
||
.ht_clone_corner {
|
||
border: none !important;
|
||
}
|
||
|
||
.wtHolder {
|
||
border: none !important;
|
||
}
|
||
|
||
.htCore {
|
||
border-collapse: separate;
|
||
border-spacing: 0;
|
||
border: none !important;
|
||
|
||
td {
|
||
border-right: 0.5px solid #f0f0f0 !important;
|
||
border-bottom: 0.5px solid #f0f0f0 !important;
|
||
border-top: none !important;
|
||
border-left: none !important;
|
||
padding: 7px 16px;
|
||
font-size: 13px;
|
||
line-height: 1.4;
|
||
color: #262626;
|
||
transition: all 0.2s ease;
|
||
background: #fff;
|
||
text-align: center !important;
|
||
vertical-align: middle !important;
|
||
|
||
&:hover {
|
||
background-color: #fafafa;
|
||
}
|
||
}
|
||
|
||
tr {
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
td {
|
||
// hover时,如果单元格已经有背景色(状态背景),则稍微加深
|
||
// 否则使用默认hover颜色
|
||
&:not([style*="background-color"]) {
|
||
background-color: #fafafa;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
th {
|
||
background: #f5f5f5 !important; // 表头背景颜色改为淡灰色
|
||
border-right: 0.5px solid #f0f0f0 !important;
|
||
border-bottom: 0.5px solid #f0f0f0 !important;
|
||
border-top: none !important;
|
||
border-left: none !important;
|
||
}
|
||
|
||
// 根据订单状态设置行背景
|
||
tbody tr:has([data-row-status="problematic"]) td {
|
||
background-color: #fff1f0 !important;
|
||
}
|
||
tbody tr:has([data-row-status="pendingPayment"]) td {
|
||
background-color: #fffbe6 !important;
|
||
}
|
||
|
||
// 操作列眼睛图标 hover
|
||
.view-icon-wrapper {
|
||
&:hover {
|
||
background-color: var(--app-primary-color-light, #e6f7f7);
|
||
svg {
|
||
color: var(--app-primary-color-hover) !important;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 隐藏筛选图标的边框
|
||
.changeType {
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
background: transparent !important;
|
||
}
|
||
|
||
// 隐藏筛选图标容器的边框
|
||
.ht_master .ht_clone_top th .changeType,
|
||
.ht_clone_top th .changeType,
|
||
.htCore th .changeType,
|
||
th .changeType {
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
background: transparent !important;
|
||
}
|
||
}
|
||
|
||
.ht_master .wtHolder {
|
||
overflow: auto;
|
||
}
|
||
|
||
.handsontableInput {
|
||
display: none;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 响应式设计
|
||
@media (max-width: 768px) {
|
||
.tabs-container {
|
||
overflow-x: auto;
|
||
flex-wrap: nowrap;
|
||
}
|
||
|
||
.actions-right {
|
||
flex-wrap: wrap;
|
||
gap: 4px;
|
||
}
|
||
|
||
.action-btn {
|
||
font-size: 12px;
|
||
padding: 0 8px;
|
||
height: 28px;
|
||
}
|
||
}
|
||
</style> |