1.06 #8
@ -1475,6 +1475,9 @@
|
||||
manualColumnResize: true,
|
||||
manualColumnMove: props.enableColumnReorder,
|
||||
stretchH: props.stretchColumns ? 'all' : 'none',
|
||||
// 列宽由列定义给出。开启后 loadData 会走 GhostTable 测量,
|
||||
// 单元格节点缺失时抛 getBoundingClientRect,并中断外层页面更新。
|
||||
autoColumnSize: false,
|
||||
// stretch 时锁定操作/序号/复选框列,避免被均分拉宽
|
||||
beforeStretchingColumnWidth: lockFixedColumnStretchWidth,
|
||||
...(props.rowHeight != null && props.rowHeight > 0
|
||||
@ -2362,6 +2365,8 @@
|
||||
hotInstance.loadData([]);
|
||||
hotInstance.render();
|
||||
publishSelection([], new Set());
|
||||
} catch (error) {
|
||||
console.warn('[HandsontablePro] clear failed', error);
|
||||
} finally {
|
||||
selectionLock -= 1;
|
||||
}
|
||||
@ -2393,6 +2398,8 @@
|
||||
} else {
|
||||
applySelectedRowStyles();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('[HandsontablePro] refresh failed', error);
|
||||
} finally {
|
||||
selectionLock -= 1;
|
||||
}
|
||||
|
||||
@ -1079,9 +1079,25 @@ export default {
|
||||
'order.platformStoreOrder.createFulfillWms.success': 'Created {count} fulfill order(s)',
|
||||
'order.platformStoreOrder.pull.store': 'Store',
|
||||
'order.platformStoreOrder.pull.storePlaceholder': 'Select stores',
|
||||
'order.platformStoreOrder.pull.storeAll': 'All stores',
|
||||
'order.platformStoreOrder.pull.status': 'Status',
|
||||
'order.platformStoreOrder.pull.statusAll': 'All',
|
||||
'order.platformStoreOrder.pull.statusClear': 'Clear',
|
||||
'order.platformStoreOrder.pull.statusCount': '{count} selected',
|
||||
'order.platformStoreOrder.pull.time': 'Time',
|
||||
'order.platformStoreOrder.pull.timeHint': 'Defaults to today',
|
||||
'order.platformStoreOrder.pull.timeHint': 'Filter by order created time. Defaults to today.',
|
||||
'order.platformStoreOrder.pull.today': 'Today',
|
||||
'order.platformStoreOrder.pull.last7': '7 days',
|
||||
'order.platformStoreOrder.pull.last15': '15 days',
|
||||
'order.platformStoreOrder.pull.status.UNPAID': 'Unpaid',
|
||||
'order.platformStoreOrder.pull.status.ON_HOLD': 'On hold',
|
||||
'order.platformStoreOrder.pull.status.PARTIALLY_SHIPPING': 'Partially shipping',
|
||||
'order.platformStoreOrder.pull.status.AWAITING_SHIPMENT': 'Awaiting shipment',
|
||||
'order.platformStoreOrder.pull.status.AWAITING_COLLECTION': 'Awaiting collection',
|
||||
'order.platformStoreOrder.pull.status.IN_TRANSIT': 'In transit',
|
||||
'order.platformStoreOrder.pull.status.DELIVERED': 'Delivered',
|
||||
'order.platformStoreOrder.pull.status.COMPLETED': 'Completed',
|
||||
'order.platformStoreOrder.pull.status.CANCELLED': 'Cancelled',
|
||||
'order.platformStoreOrder.message.loadFailed': 'Failed to load orders',
|
||||
'order.platformStoreOrder.message.detailFailed': 'Failed to load detail',
|
||||
'order.platformStoreOrder.message.matchSuccess': 'Inventory matched',
|
||||
|
||||
@ -1070,9 +1070,25 @@ export default {
|
||||
'order.platformStoreOrder.createFulfillWms.success': '成功创建 {count} 张代发订单',
|
||||
'order.platformStoreOrder.pull.store': '店铺',
|
||||
'order.platformStoreOrder.pull.storePlaceholder': '请选择店铺',
|
||||
'order.platformStoreOrder.pull.status': '类型',
|
||||
'order.platformStoreOrder.pull.storeAll': '全选店铺',
|
||||
'order.platformStoreOrder.pull.status': '状态',
|
||||
'order.platformStoreOrder.pull.statusAll': '全选',
|
||||
'order.platformStoreOrder.pull.statusClear': '清空',
|
||||
'order.platformStoreOrder.pull.statusCount': '已选 {count} 个',
|
||||
'order.platformStoreOrder.pull.time': '时间',
|
||||
'order.platformStoreOrder.pull.timeHint': '默认时间为当天',
|
||||
'order.platformStoreOrder.pull.timeHint': '按订单创建时间拉取,默认当天',
|
||||
'order.platformStoreOrder.pull.today': '今天',
|
||||
'order.platformStoreOrder.pull.last7': '近7天',
|
||||
'order.platformStoreOrder.pull.last15': '近15天',
|
||||
'order.platformStoreOrder.pull.status.UNPAID': '未付款',
|
||||
'order.platformStoreOrder.pull.status.ON_HOLD': '待处理',
|
||||
'order.platformStoreOrder.pull.status.PARTIALLY_SHIPPING': '部分发货',
|
||||
'order.platformStoreOrder.pull.status.AWAITING_SHIPMENT': '待发货',
|
||||
'order.platformStoreOrder.pull.status.AWAITING_COLLECTION': '待揽收',
|
||||
'order.platformStoreOrder.pull.status.IN_TRANSIT': '运输中',
|
||||
'order.platformStoreOrder.pull.status.DELIVERED': '已送达',
|
||||
'order.platformStoreOrder.pull.status.COMPLETED': '已完成',
|
||||
'order.platformStoreOrder.pull.status.CANCELLED': '已取消',
|
||||
'order.platformStoreOrder.message.loadFailed': '加载订单失败',
|
||||
'order.platformStoreOrder.message.detailFailed': '加载详情失败',
|
||||
'order.platformStoreOrder.message.matchSuccess': '库存匹配成功',
|
||||
|
||||
@ -9,6 +9,7 @@ import { pickField } from '@/utils/warehouseListMapper'
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
customerId?: number
|
||||
platformCode?: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -16,51 +17,77 @@ const emit = defineEmits<{
|
||||
success: []
|
||||
}>()
|
||||
|
||||
/** TikTok 订单搜索状态,与平台 order_status 一致 */
|
||||
const TIKTOK_PULL_STATUSES = [
|
||||
'UNPAID',
|
||||
'ON_HOLD',
|
||||
'PARTIALLY_SHIPPING',
|
||||
'AWAITING_SHIPMENT',
|
||||
'AWAITING_COLLECTION',
|
||||
'IN_TRANSIT',
|
||||
'DELIVERED',
|
||||
'COMPLETED',
|
||||
'CANCELLED',
|
||||
] as const
|
||||
|
||||
type StoreOption = { label: string; value: number; platform: string }
|
||||
|
||||
const { t } = useI18n()
|
||||
const loading = ref(false)
|
||||
const storeLoading = ref(false)
|
||||
const storeOptions = ref<Array<{ label: string; value: number }>>([])
|
||||
const storeOptions = ref<StoreOption[]>([])
|
||||
const storeIds = ref<number[]>([])
|
||||
const orderStatuses = ref<string[]>([
|
||||
'unpaid',
|
||||
'pending',
|
||||
'canceled',
|
||||
'ready_to_ship',
|
||||
'delivered',
|
||||
'returned',
|
||||
'shipped',
|
||||
'failed',
|
||||
'topack',
|
||||
'toship',
|
||||
'shipping',
|
||||
'lost',
|
||||
])
|
||||
const dateRange = ref<[string, string] | undefined>()
|
||||
|
||||
const statusOptions = computed(() =>
|
||||
[
|
||||
'unpaid',
|
||||
'pending',
|
||||
'canceled',
|
||||
'ready_to_ship',
|
||||
'delivered',
|
||||
'returned',
|
||||
'shipped',
|
||||
'failed',
|
||||
'topack',
|
||||
'toship',
|
||||
'shipping',
|
||||
'lost',
|
||||
].map((value) => ({ label: value, value })),
|
||||
)
|
||||
const orderStatuses = ref<string[]>([...TIKTOK_PULL_STATUSES])
|
||||
const dateRange = ref<[string, string]>(todayRange())
|
||||
|
||||
const modalVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (v: boolean) => emit('update:visible', v),
|
||||
})
|
||||
|
||||
const visibleStoreOptions = computed(() => {
|
||||
const platform = (props.platformCode || '').trim().toLowerCase()
|
||||
if (!platform || platform === 'all') return storeOptions.value
|
||||
return storeOptions.value.filter((item) => item.platform === platform)
|
||||
})
|
||||
|
||||
const allStatusesChecked = computed(
|
||||
() => orderStatuses.value.length === TIKTOK_PULL_STATUSES.length,
|
||||
)
|
||||
const allStoresChecked = computed(
|
||||
() =>
|
||||
visibleStoreOptions.value.length > 0
|
||||
&& storeIds.value.length === visibleStoreOptions.value.length,
|
||||
)
|
||||
const canSubmit = computed(
|
||||
() => storeIds.value.length > 0 && orderStatuses.value.length > 0 && !storeLoading.value,
|
||||
)
|
||||
|
||||
function todayRange(): [string, string] {
|
||||
return [dayjs().format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD')]
|
||||
}
|
||||
|
||||
function applyRange(days: number) {
|
||||
dateRange.value = [
|
||||
dayjs().subtract(days - 1, 'day').format('YYYY-MM-DD'),
|
||||
dayjs().format('YYYY-MM-DD'),
|
||||
]
|
||||
}
|
||||
|
||||
function toggleAllStatuses() {
|
||||
orderStatuses.value = allStatusesChecked.value ? [] : [...TIKTOK_PULL_STATUSES]
|
||||
}
|
||||
|
||||
function toggleAllStores() {
|
||||
storeIds.value = allStoresChecked.value
|
||||
? []
|
||||
: visibleStoreOptions.value.map((item) => item.value)
|
||||
}
|
||||
|
||||
async function loadStoreOptions() {
|
||||
storeIds.value = []
|
||||
orderStatuses.value = [...TIKTOK_PULL_STATUSES]
|
||||
dateRange.value = todayRange()
|
||||
storeLoading.value = true
|
||||
try {
|
||||
const { items } = await getPlatformStoreList({
|
||||
@ -72,12 +99,12 @@ async function loadStoreOptions() {
|
||||
.map((raw: Record<string, unknown>) => {
|
||||
const id = Number(pickField(raw, 'id', 'Id'))
|
||||
const name = String(pickField(raw, 'storeNickname', 'StoreNickname') ?? `#${id}`)
|
||||
const platform = String(pickField(raw, 'platformCode', 'PlatformCode') ?? '')
|
||||
return { label: platform ? `${name} (${platform})` : name, value: id }
|
||||
const platform = String(pickField(raw, 'platformCode', 'PlatformCode') ?? '').toLowerCase()
|
||||
return { label: platform ? `${name} (${platform})` : name, value: id, platform }
|
||||
})
|
||||
.filter((x) => x.value > 0)
|
||||
if (!storeOptions.value.length) {
|
||||
$baseMessage(t('order.platformStoreOrder.message.noStore'), 'warning')
|
||||
.filter((item) => item.value > 0)
|
||||
if (visibleStoreOptions.value.length === 1) {
|
||||
storeIds.value = [visibleStoreOptions.value[0].value]
|
||||
}
|
||||
} catch (e: any) {
|
||||
storeOptions.value = []
|
||||
@ -145,38 +172,152 @@ async function handleSubmit(): Promise<boolean> {
|
||||
<a-modal
|
||||
v-model:visible="modalVisible"
|
||||
:title="t('order.platformStoreOrder.actions.pullOrders')"
|
||||
:width="720"
|
||||
:ok-loading="loading"
|
||||
:ok-text="t('order.platformStoreOrder.actions.startPull')"
|
||||
:ok-button-props="{ disabled: !canSubmit }"
|
||||
unmount-on-close
|
||||
:on-before-ok="handleSubmit"
|
||||
>
|
||||
<a-form :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 16 }">
|
||||
<a-form class="pull-form" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 16 }">
|
||||
<a-form-item :label="t('order.platformStoreOrder.pull.store')" required>
|
||||
<a-select
|
||||
v-model="storeIds"
|
||||
multiple
|
||||
allow-clear
|
||||
:loading="storeLoading"
|
||||
:options="storeOptions"
|
||||
:placeholder="t('order.platformStoreOrder.pull.storePlaceholder')"
|
||||
:max-tag-count="3"
|
||||
/>
|
||||
<div class="pull-block">
|
||||
<div class="pull-row">
|
||||
<a-select
|
||||
v-model="storeIds"
|
||||
class="pull-grow"
|
||||
multiple
|
||||
allow-clear
|
||||
:loading="storeLoading"
|
||||
:options="visibleStoreOptions"
|
||||
:placeholder="t('order.platformStoreOrder.pull.storePlaceholder')"
|
||||
:max-tag-count="2"
|
||||
/>
|
||||
<a-button
|
||||
type="text"
|
||||
size="small"
|
||||
:disabled="!visibleStoreOptions.length"
|
||||
@click="toggleAllStores"
|
||||
>
|
||||
{{ allStoresChecked ? t('order.platformStoreOrder.pull.statusClear') : t('order.platformStoreOrder.pull.storeAll') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div v-if="!storeLoading && !visibleStoreOptions.length" class="hint">
|
||||
{{ t('order.platformStoreOrder.message.noStore') }}
|
||||
</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item :label="t('order.platformStoreOrder.pull.status')" required>
|
||||
<a-checkbox-group v-model="orderStatuses" :options="statusOptions" />
|
||||
<div class="pull-block">
|
||||
<div class="pull-row pull-row--between">
|
||||
<span class="hint">
|
||||
{{ t('order.platformStoreOrder.pull.statusCount', { count: orderStatuses.length }) }}
|
||||
</span>
|
||||
<a-button type="text" size="small" @click="toggleAllStatuses">
|
||||
{{ allStatusesChecked ? t('order.platformStoreOrder.pull.statusClear') : t('order.platformStoreOrder.pull.statusAll') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<a-checkbox-group v-model="orderStatuses" class="status-grid">
|
||||
<a-checkbox v-for="status in TIKTOK_PULL_STATUSES" :key="status" :value="status">
|
||||
<span class="status-name">{{ t(`order.platformStoreOrder.pull.status.${status}`) }}</span>
|
||||
<span class="status-code">{{ status }}</span>
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item :label="t('order.platformStoreOrder.pull.time')">
|
||||
<a-range-picker v-model="dateRange" style="width: 100%" />
|
||||
<div class="hint">{{ t('order.platformStoreOrder.pull.timeHint') }}</div>
|
||||
<div class="pull-block">
|
||||
<a-range-picker
|
||||
v-model="dateRange"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="pull-row">
|
||||
<a-button type="text" size="small" @click="applyRange(1)">
|
||||
{{ t('order.platformStoreOrder.pull.today') }}
|
||||
</a-button>
|
||||
<a-button type="text" size="small" @click="applyRange(7)">
|
||||
{{ t('order.platformStoreOrder.pull.last7') }}
|
||||
</a-button>
|
||||
<a-button type="text" size="small" @click="applyRange(15)">
|
||||
{{ t('order.platformStoreOrder.pull.last15') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="hint">{{ t('order.platformStoreOrder.pull.timeHint') }}</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.hint {
|
||||
margin-top: 8px;
|
||||
.pull-form {
|
||||
:deep(.arco-form-item) {
|
||||
align-items: flex-start;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
:deep(.arco-form-item-label-col) {
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
:deep(.arco-form-item-content) {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.pull-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pull-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pull-row--between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.pull-grow {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.status-grid {
|
||||
display: grid !important;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px 12px;
|
||||
width: 100%;
|
||||
|
||||
:deep(.arco-checkbox) {
|
||||
margin: 0;
|
||||
align-items: center;
|
||||
line-height: 22px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.status-name {
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
|
||||
.status-code {
|
||||
margin-left: 6px;
|
||||
color: var(--color-text-3);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.hint {
|
||||
color: var(--color-text-3);
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -860,6 +860,7 @@ watch(
|
||||
v-if="pullVisible"
|
||||
v-model:visible="pullVisible"
|
||||
:customer-id="withCustomerId({}).customerId"
|
||||
:platform-code="platformCode"
|
||||
@success="() => { loadSummary(); loadList() }"
|
||||
/>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user