front/src/views/order/myOrders/index.vue
2026-03-23 18:03:05 +08:00

980 lines
33 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>