add sku filter
This commit is contained in:
@@ -31,13 +31,18 @@
|
||||
</div>
|
||||
</template>
|
||||
</t-input>
|
||||
<t-dropdown-menu class="menus">
|
||||
<t-dropdown-menu ref="filterMenuRef" class="menus">
|
||||
<t-dropdown-item
|
||||
v-model="dateFilterType"
|
||||
:label="dateFilterLabel"
|
||||
:options="dateOptions"
|
||||
@change="selectDateFilter"
|
||||
/>
|
||||
<t-dropdown-item
|
||||
:label="skuFilterLabel"
|
||||
:options="[]"
|
||||
@open="openSkuFilter"
|
||||
/>
|
||||
<t-dropdown-item
|
||||
v-model="status"
|
||||
label="履约状态"
|
||||
@@ -53,16 +58,32 @@
|
||||
@scrolltolower="loadMore"
|
||||
>
|
||||
<div class="list-wrap">
|
||||
<t-cell-group v-if="salesOrder" class="order-info" theme="card">
|
||||
<t-cell title="订单号" :note="salesOrder.orderNo || salesOrder.id || '未知订单'" />
|
||||
<t-cell title="订单类型" :note="getSalesOrderTypeText(salesOrder.orderType)" />
|
||||
<t-cell title="订单状态">
|
||||
<t-cell-group v-if="salesOrder || selectedSkuOptionList.length" class="filter-info" theme="card">
|
||||
<template v-if="salesOrder">
|
||||
<t-cell title="订单号" :note="salesOrder.orderNo || salesOrder.id || '未知订单'" />
|
||||
<t-cell title="订单类型" :note="getSalesOrderTypeText(salesOrder.orderType)" />
|
||||
<t-cell title="订单状态">
|
||||
<template #note>
|
||||
<t-tag
|
||||
:content="getSalesOrderStatusText(salesOrder.status)"
|
||||
:theme="getStatusTheme(salesOrder.status)"
|
||||
variant="light-outline"
|
||||
/>
|
||||
</template>
|
||||
</t-cell>
|
||||
</template>
|
||||
<t-cell v-if="selectedSkuOptionList.length" class="sku-filter-cell" title="已筛选 SKU">
|
||||
<template #note>
|
||||
<t-tag
|
||||
:content="getSalesOrderStatusText(salesOrder.status)"
|
||||
:theme="getStatusTheme(salesOrder.status)"
|
||||
variant="light-outline"
|
||||
/>
|
||||
<div class="selected-sku-list">
|
||||
<t-tag
|
||||
v-for="sku in selectedSkuOptionList"
|
||||
:key="sku.skuId"
|
||||
size="small"
|
||||
theme="primary"
|
||||
variant="outline"
|
||||
:content="formatSelectedSkuName(sku.productName, sku.skuName)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</t-cell>
|
||||
</t-cell-group>
|
||||
@@ -96,6 +117,12 @@
|
||||
</t-pull-down-refresh>
|
||||
</div>
|
||||
<nav-bar-action-menu v-if="canCreate" :actions="actions" />
|
||||
<sku-filter-popup
|
||||
v-model="skuFilterVisible"
|
||||
:sku-id-list="selectedSkuIdList"
|
||||
@options-loaded="handleSkuFilterOptionsLoaded"
|
||||
@confirm="confirmSkuFilter"
|
||||
/>
|
||||
<customer-selector
|
||||
v-model="customerId"
|
||||
v-model:visible="customerSelectorVisible"
|
||||
@@ -137,6 +164,7 @@ import SalesOrderAPI from "@/api/SalesOrderAPI";
|
||||
import CustomerSelector from "@/components/CustomerSelector.vue";
|
||||
import NavBarActionMenu from "@/components/NavBarActionMenu.vue";
|
||||
import OrderFulfillmentListCell from "@/pages/fulfillment/components/OrderFulfillmentListCell.vue";
|
||||
import SkuFilterPopup from "@/pages/fulfillment/components/SkuFilterPopup.vue";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { GaoFulfillmentStatus, OrderFulfillment } from "@/types/Fulfillment";
|
||||
import type { NavBarAction } from "@/types/NavBarAction";
|
||||
@@ -152,6 +180,7 @@ defineOptions({ name: "OrderFulfillmentList" });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const filterMenuRef = ref<{ collapseMenu: () => void }>();
|
||||
const navBarStore = useNavBarStore();
|
||||
const userStore = useUserStore();
|
||||
const canCreate = computed(() => userStore.hasPermissions(permissionCodes.orderFulfillment.create));
|
||||
@@ -172,6 +201,7 @@ const actions = computed<NavBarAction[]>(() => [
|
||||
}
|
||||
]);
|
||||
type DateFilterType = "today" | "yesterday" | "thisWeek" | "thisMonth" | "lastMonth" | "all" | "custom";
|
||||
type SkuFilterOption = { skuId: string; productName: string; skuName: string };
|
||||
const dateOptions: Array<{ label: string; value: DateFilterType }> = [
|
||||
{ label: "今天", value: "today" },
|
||||
{ label: "昨天", value: "yesterday" },
|
||||
@@ -183,11 +213,14 @@ const dateOptions: Array<{ label: string; value: DateFilterType }> = [
|
||||
];
|
||||
|
||||
const customerId = ref(getQueryText(route.query.customerId));
|
||||
const selectedSkuIdList = ref(getSkuIdList(route.query.skuIds));
|
||||
const selectedCustomer = ref<Customer>();
|
||||
const salesOrder = ref<SalesOrder>();
|
||||
const skuFilterOptionList = ref<SkuFilterOption[]>([]);
|
||||
const skuFilterVisible = ref(false);
|
||||
const customerSelectorVisible = ref(false);
|
||||
const customerSearchKeyword = ref("");
|
||||
const dateFilterType = ref<DateFilterType>(parseDateFilterType(getQueryText(route.query.dateType), dateOptions, "today"));
|
||||
const dateFilterType = ref<DateFilterType>(parseDateFilterType(getQueryText(route.query.dateType), dateOptions, "all"));
|
||||
const dateRange = ref<[string, string]>(parseDateRange(dateFilterType.value));
|
||||
const startDraft = ref("");
|
||||
const endDraft = ref("");
|
||||
@@ -211,12 +244,27 @@ const statusOptions = [
|
||||
{ label: "已冲正", value: "REVOKED" }
|
||||
];
|
||||
const dateFilterLabel = computed(() => dateOptions.find(item => item.value === dateFilterType.value)?.label || "时间范围");
|
||||
const selectedSkuOptionList = computed(() => {
|
||||
const optionMap = new Map(skuFilterOptionList.value.map(option => [option.skuId, option]));
|
||||
return selectedSkuIdList.value
|
||||
.map(skuId => optionMap.get(skuId))
|
||||
.filter((option): option is SkuFilterOption => !!option);
|
||||
});
|
||||
const skuFilterLabel = computed(() => selectedSkuIdList.value.length ? `SKU (${selectedSkuIdList.value.length})` : "产品 SKU");
|
||||
const isCustomDate = computed(() => dateFilterType.value === "custom");
|
||||
|
||||
function getQueryText(value: unknown): string {
|
||||
return Array.isArray(value) ? "" : typeof value === "string" ? value : "";
|
||||
}
|
||||
|
||||
function getSkuIdList(value: unknown): string[] {
|
||||
const queryValueList = Array.isArray(value) ? value : [value];
|
||||
return [...new Set(queryValueList
|
||||
.flatMap(item => typeof item === "string" ? item.split(",") : [])
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean))];
|
||||
}
|
||||
|
||||
function getInitialStatus(value: unknown): "ALL" | GaoFulfillmentStatus {
|
||||
const statusValue = getQueryText(value);
|
||||
if (["WAITING_STOCK", "PENDING", "VERIFIED", "REJECTED", "CANCELLED", "REVOKED"].includes(statusValue)) {
|
||||
@@ -250,6 +298,7 @@ async function fetchList(reset: boolean): Promise<void> {
|
||||
size: pageSize,
|
||||
salesOrderId: getQueryText(route.query.salesOrderId) || undefined,
|
||||
customerId: customerId.value || undefined,
|
||||
skuIdList: selectedSkuIdList.value.length ? selectedSkuIdList.value : undefined,
|
||||
beginAt,
|
||||
endAt,
|
||||
status: status.value === "ALL" ? undefined : status.value
|
||||
@@ -297,6 +346,29 @@ async function selectStatus(value: DropdownValue): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function openSkuFilter(): Promise<void> {
|
||||
skuFilterVisible.value = true;
|
||||
await nextTick();
|
||||
filterMenuRef.value?.collapseMenu();
|
||||
}
|
||||
|
||||
function handleSkuFilterOptionsLoaded(optionList: SkuFilterOption[]): void {
|
||||
skuFilterOptionList.value = optionList;
|
||||
}
|
||||
|
||||
async function confirmSkuFilter(skuIdList: string[]): Promise<void> {
|
||||
selectedSkuIdList.value = skuIdList;
|
||||
await replaceFilterQuery();
|
||||
await reloadList();
|
||||
}
|
||||
|
||||
function formatSelectedSkuName(productName: string, skuName: string) {
|
||||
if (productName === skuName) {
|
||||
return productName;
|
||||
}
|
||||
return `${productName}(${skuName})`;
|
||||
}
|
||||
|
||||
async function handleCustomerChange(value: string | string[]): Promise<void> {
|
||||
customerId.value = Array.isArray(value) ? String(value[0] || "") : value;
|
||||
try {
|
||||
@@ -417,6 +489,7 @@ function buildFilterQuery(transitionDepth = getQueryText(route.query.transitionD
|
||||
const query = {
|
||||
salesOrderId: getQueryText(route.query.salesOrderId),
|
||||
customerId: customerId.value,
|
||||
skuIds: selectedSkuIdList.value.join(","),
|
||||
dateType: dateFilterType.value,
|
||||
beginAt: dateRange.value[0] || "",
|
||||
endAt: dateRange.value[1] || "",
|
||||
@@ -541,7 +614,7 @@ onUnmounted(() => navBarStore.clearRight());
|
||||
--td-spacer-1: 6px;
|
||||
|
||||
width: 100%;
|
||||
border: 1px solid rgba(148, 163, 184, .18);
|
||||
border: 1px solid var(--td-component-border);
|
||||
overflow: hidden;
|
||||
margin-top: -1rem;
|
||||
border-top: none;
|
||||
@@ -556,6 +629,42 @@ onUnmounted(() => navBarStore.clearRight());
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.filter-info {
|
||||
.selected-sku-list {
|
||||
gap: .4rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
justify-content: flex-start;
|
||||
white-space: nowrap;
|
||||
touch-action: pan-x;
|
||||
scrollbar-width: none;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.t-tag) {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sku-filter-cell {
|
||||
:deep(.t-cell__title) {
|
||||
flex: 0 0 5rem;
|
||||
}
|
||||
|
||||
:deep(.t-cell__note) {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.date-summary {
|
||||
|
||||
:deep(.t-cell__title) {
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
<template>
|
||||
<bottom-popup
|
||||
v-model="popupVisible"
|
||||
title="筛选产品 SKU"
|
||||
height="min(80vh, 48rem)"
|
||||
left-button-text="重置"
|
||||
right-button-text="确定"
|
||||
@left-button-click="resetSelection"
|
||||
@right-button-click="confirmSelection"
|
||||
>
|
||||
<div class="sku-filter-popup">
|
||||
<div class="filters glass">
|
||||
<t-input
|
||||
class="search"
|
||||
v-model="keyword"
|
||||
borderless
|
||||
clearable
|
||||
placeholder="搜索产品名称、拼音、编码或 SKU"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="singleSkuProductList.length" class="single-list">
|
||||
<t-cell-group theme="card">
|
||||
<t-cell
|
||||
class="sku-cell"
|
||||
v-for="product in singleSkuProductList"
|
||||
:key="product.id"
|
||||
@click="toggleSkuSelected(getSkuId(getProductSkuList(product)[0]))"
|
||||
>
|
||||
<template #title>
|
||||
<div @click.stop>
|
||||
<t-checkbox
|
||||
:model-value="draftSkuIdList.includes(getSkuId(getProductSkuList(product)[0]))"
|
||||
icon="line"
|
||||
:block="false"
|
||||
borderless
|
||||
@update:model-value="checked => setSkuSelected(getSkuId(getProductSkuList(product)[0]), checked)"
|
||||
>
|
||||
<span v-text="product.name || '未命名产品'" />
|
||||
</t-checkbox>
|
||||
</div>
|
||||
</template>
|
||||
</t-cell>
|
||||
</t-cell-group>
|
||||
</div>
|
||||
<t-collapse
|
||||
v-if="multiSkuProductList.length"
|
||||
v-model="expandedProductIdList"
|
||||
class="multi-list"
|
||||
:expand-mutex="false"
|
||||
>
|
||||
<t-collapse-panel
|
||||
v-for="product in multiSkuProductList"
|
||||
:key="product.id"
|
||||
:value="product.id || ''"
|
||||
class="collapse-panel"
|
||||
>
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<div class="group-checkbox" @click.stop>
|
||||
<t-checkbox
|
||||
:model-value="0 < getVisibleSelectedSkuCount(product)"
|
||||
:indeterminate="isProductPartiallySelected(product)"
|
||||
icon="line"
|
||||
:block="false"
|
||||
borderless
|
||||
@update:model-value="toggleProductSkuSelection(product)"
|
||||
/>
|
||||
</div>
|
||||
<span class="clip-text" v-text="product.name || '未命名产品'" />
|
||||
<span
|
||||
v-if="getSelectedSkuCount(product)"
|
||||
class="tips"
|
||||
v-text="`已选 ${getSelectedSkuCount(product)} 个`"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<t-cell-group theme="card" class="sku-choice-list">
|
||||
<t-cell
|
||||
v-for="sku in getVisibleProductSkuList(product)"
|
||||
:key="sku.id"
|
||||
class="sku-cell"
|
||||
@click="toggleSkuSelected(getSkuId(sku))"
|
||||
>
|
||||
<template #title>
|
||||
<div class="title">
|
||||
<div @click.stop>
|
||||
<t-checkbox
|
||||
:model-value="draftSkuIdList.includes(getSkuId(sku))"
|
||||
icon="line"
|
||||
:block="false"
|
||||
borderless
|
||||
@update:model-value="checked => setSkuSelected(getSkuId(sku), checked)"
|
||||
/>
|
||||
</div>
|
||||
<span class="clip-text" v-text="getSkuText(sku)" />
|
||||
</div>
|
||||
</template>
|
||||
</t-cell>
|
||||
</t-cell-group>
|
||||
</t-collapse-panel>
|
||||
</t-collapse>
|
||||
<div
|
||||
v-if="!singleSkuProductList.length && !multiSkuProductList.length"
|
||||
class="center-tips"
|
||||
v-text="loadingProducts ? '正在加载产品 SKU' : keyword ? '没有匹配的产品或 SKU' : '暂无可筛选的产品 SKU'"
|
||||
/>
|
||||
</div>
|
||||
</bottom-popup>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { BottomPopup } from "timi-tdesign-mobile";
|
||||
import ProductAPI from "@/api/ProductAPI";
|
||||
import type { Product, ProductSku } from "@/types/Product";
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import { Message } from "@/utils/message";
|
||||
|
||||
defineOptions({ name: "SkuFilterPopup" });
|
||||
|
||||
type SkuFilterOption = { skuId: string; productName: string; skuName: string };
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
skuIdList: string[];
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
"update:modelValue": [value: boolean];
|
||||
"options-loaded": [optionList: SkuFilterOption[]];
|
||||
confirm: [skuIdList: string[]];
|
||||
}>();
|
||||
|
||||
const popupVisible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: value => emit("update:modelValue", value)
|
||||
});
|
||||
const draftSkuIdList = ref<string[]>([...props.skuIdList]);
|
||||
const keyword = ref("");
|
||||
const productList = ref<Product[]>([]);
|
||||
const expandedProductIdList = ref<Array<string | number>>([]);
|
||||
const loadingProducts = ref(false);
|
||||
const normalizedKeyword = computed(() => keyword.value.trim().toLocaleLowerCase());
|
||||
const filterableProductList = computed(() => productList.value.filter(product => !!product.id && 0 < getProductSkuList(product).length));
|
||||
const singleSkuProductList = computed(() => filterableProductList.value.filter(product => getProductSkuList(product).length === 1 && matchesProductSearch(product)));
|
||||
const multiSkuProductList = computed(() => filterableProductList.value.filter(product => 1 < getProductSkuList(product).length && matchesProductSearch(product)));
|
||||
const skuFilterOptionList = computed<SkuFilterOption[]>(() => filterableProductList.value.flatMap(product => getProductSkuList(product).map(sku => ({
|
||||
skuId: getSkuId(sku),
|
||||
productName: product.name || "未命名产品",
|
||||
skuName: getSkuText(sku)
|
||||
}))));
|
||||
|
||||
watch(() => props.modelValue, visible => {
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
draftSkuIdList.value = [...props.skuIdList];
|
||||
expandSelectedProducts();
|
||||
});
|
||||
|
||||
watch(() => props.skuIdList, skuIdList => {
|
||||
if (!props.modelValue) {
|
||||
draftSkuIdList.value = [...skuIdList];
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
watch(normalizedKeyword, value => {
|
||||
if (value) {
|
||||
expandedProductIdList.value = multiSkuProductList.value.map(product => product.id || "");
|
||||
}
|
||||
});
|
||||
|
||||
function getProductSkuList(product: Product): ProductSku[] {
|
||||
return (product.skuList || []).filter((sku): sku is ProductSku & { id: string } => !!sku.id);
|
||||
}
|
||||
|
||||
function getSkuId(sku?: ProductSku): string {
|
||||
return sku?.id || "";
|
||||
}
|
||||
|
||||
function getSkuText(sku?: ProductSku): string {
|
||||
return sku?.specSummary || sku?.name || "默认 SKU";
|
||||
}
|
||||
|
||||
function matchesSearchText(value?: string | null): boolean {
|
||||
return !!normalizedKeyword.value && !!value?.toLocaleLowerCase().includes(normalizedKeyword.value);
|
||||
}
|
||||
|
||||
function matchesProductName(product: Product): boolean {
|
||||
return [
|
||||
product.name,
|
||||
product.namePinyinFull,
|
||||
product.namePinyinInitial,
|
||||
product.namePinyinMixed,
|
||||
product.code
|
||||
].some(matchesSearchText);
|
||||
}
|
||||
|
||||
function matchesSku(sku: ProductSku): boolean {
|
||||
return [sku.name, sku.specSummary, sku.code, sku.barcode].some(matchesSearchText);
|
||||
}
|
||||
|
||||
function matchesProductSearch(product: Product): boolean {
|
||||
return !normalizedKeyword.value
|
||||
|| matchesProductName(product)
|
||||
|| getProductSkuList(product).some(matchesSku);
|
||||
}
|
||||
|
||||
function getVisibleProductSkuList(product: Product): ProductSku[] {
|
||||
const skuList = getProductSkuList(product);
|
||||
if (!normalizedKeyword.value || matchesProductName(product)) {
|
||||
return skuList;
|
||||
}
|
||||
return skuList.filter(matchesSku);
|
||||
}
|
||||
|
||||
function getSelectedSkuCount(product: Product): number {
|
||||
const skuIdSet = new Set(getProductSkuList(product).map(getSkuId));
|
||||
return draftSkuIdList.value.filter(skuId => skuIdSet.has(skuId)).length;
|
||||
}
|
||||
|
||||
function getVisibleSelectedSkuCount(product: Product): number {
|
||||
const skuIdSet = new Set(getVisibleProductSkuList(product).map(getSkuId));
|
||||
return draftSkuIdList.value.filter(skuId => skuIdSet.has(skuId)).length;
|
||||
}
|
||||
|
||||
function isProductPartiallySelected(product: Product): boolean {
|
||||
const selectedCount = getVisibleSelectedSkuCount(product);
|
||||
return 0 < selectedCount && selectedCount < getVisibleProductSkuList(product).length;
|
||||
}
|
||||
|
||||
function toggleProductSkuSelection(product: Product): void {
|
||||
const skuIdList = getVisibleProductSkuList(product).map(getSkuId);
|
||||
const skuIdSet = new Set(draftSkuIdList.value);
|
||||
const shouldSelectAll = !skuIdList.every(skuId => skuIdSet.has(skuId));
|
||||
for (const skuId of skuIdList) {
|
||||
if (shouldSelectAll) {
|
||||
skuIdSet.add(skuId);
|
||||
} else {
|
||||
skuIdSet.delete(skuId);
|
||||
}
|
||||
}
|
||||
draftSkuIdList.value = [...skuIdSet];
|
||||
}
|
||||
|
||||
function expandSelectedProducts(): void {
|
||||
if (normalizedKeyword.value) {
|
||||
expandedProductIdList.value = multiSkuProductList.value.map(product => product.id || "");
|
||||
return;
|
||||
}
|
||||
expandedProductIdList.value = multiSkuProductList.value
|
||||
.filter(product => getProductSkuList(product).some(sku => props.skuIdList.includes(getSkuId(sku))))
|
||||
.map(product => product.id || "");
|
||||
}
|
||||
|
||||
function setSkuSelected(skuId: string, checked: boolean): void {
|
||||
if (!skuId) {
|
||||
return;
|
||||
}
|
||||
const skuIdSet = new Set(draftSkuIdList.value);
|
||||
if (checked) {
|
||||
skuIdSet.add(skuId);
|
||||
} else {
|
||||
skuIdSet.delete(skuId);
|
||||
}
|
||||
draftSkuIdList.value = [...skuIdSet];
|
||||
}
|
||||
|
||||
function toggleSkuSelected(skuId: string): void {
|
||||
setSkuSelected(skuId, !draftSkuIdList.value.includes(skuId));
|
||||
}
|
||||
|
||||
function resetSelection(): void {
|
||||
draftSkuIdList.value = [];
|
||||
}
|
||||
|
||||
function confirmSelection(): void {
|
||||
emit("confirm", [...new Set(draftSkuIdList.value)]);
|
||||
popupVisible.value = false;
|
||||
}
|
||||
|
||||
async function loadFilterProducts(): Promise<void> {
|
||||
loadingProducts.value = true;
|
||||
try {
|
||||
const result = await ProductAPI.list({ index: 0, size: 1000 });
|
||||
productList.value = result.list || [];
|
||||
emit("options-loaded", skuFilterOptionList.value);
|
||||
expandSelectedProducts();
|
||||
} catch (error) {
|
||||
Message.error(getErrorMessage(error, "产品 SKU 筛选项加载失败"));
|
||||
} finally {
|
||||
loadingProducts.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(loadFilterProducts);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.sku-filter-popup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
:deep(.t-cell-group) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.filters {
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
padding: .5rem 1rem;
|
||||
position: sticky;
|
||||
|
||||
.search {
|
||||
border: 1px solid var(--td-component-border);
|
||||
padding: .5rem 1rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.single-list,
|
||||
.multi-list {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.multi-list {
|
||||
border-top: 1px solid var(--td-component-stroke);
|
||||
|
||||
.collapse-panel {
|
||||
|
||||
:deep(.t-collapse-panel__content) {
|
||||
padding: 0 0 0 1rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.group-checkbox {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sku-choice-list {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sku-cell,
|
||||
:deep(.t-collapse-panel__title) {
|
||||
padding: .5rem;
|
||||
|
||||
.title {
|
||||
gap: .125rem;
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: var(--td-text-color-secondary);
|
||||
font-size: .75rem;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,7 +5,7 @@ function meta(title: string, depth = 3): RouteRecordRaw["meta"] {
|
||||
}
|
||||
|
||||
export default [
|
||||
{ path: "/management/order-fulfillments", name: "OrderFulfillmentList", component: () => import("@/pages/fulfillment/OrderFulfillmentList.vue"), meta: meta("统一履约") },
|
||||
{ path: "/management/order-fulfillments", name: "OrderFulfillmentList", component: () => import("@/pages/fulfillment/OrderFulfillmentList.vue"), meta: meta("履约记录") },
|
||||
{ path: "/management/order-fulfillments/create", name: "OrderFulfillmentCreate", component: () => import("@/pages/fulfillment/OrderFulfillmentCreate.vue"), meta: meta("创建履约单", 4) },
|
||||
{ path: "/management/order-fulfillments/:id", name: "OrderFulfillmentDetail", component: () => import("@/pages/fulfillment/OrderFulfillmentDetail.vue"), meta: meta("履约单详情", 4) }
|
||||
] as RouteRecordRaw[];
|
||||
|
||||
@@ -52,6 +52,7 @@ export type FulfillmentPage = {
|
||||
storeId?: string;
|
||||
salesOrderId?: string;
|
||||
customerId?: string;
|
||||
skuIdList?: string[];
|
||||
status?: GaoFulfillmentStatus;
|
||||
beginAt?: number;
|
||||
endAt?: number;
|
||||
|
||||
@@ -82,6 +82,9 @@ export type Product = {
|
||||
categoryId?: string;
|
||||
code: string;
|
||||
name: string;
|
||||
namePinyinFull?: string;
|
||||
namePinyinInitial?: string;
|
||||
namePinyinMixed?: string;
|
||||
productType: ProductType;
|
||||
stockEnabled: boolean;
|
||||
status?: ProductStatus;
|
||||
|
||||
Reference in New Issue
Block a user