+
+
+
[
]);
const keyword = ref("");
const customerId = ref("");
+const selectedCustomer = ref();
+const scannerVisible = ref(false);
+const scanStatus = ref("点击扫码开始识别。");
+let latestDecodedText = "";
+let customerKeyword = "";
const orderType = ref("ALL");
type PaymentFilter = "ALL" | GaoSalesPaymentStatus | "PENDING_RECEIVE";
type RefundFilter = "ALL" | GaoSalesRefundStatus;
@@ -151,6 +186,24 @@ function applyRouteFilters(): void {
refundStatus.value = queryValue(route.query.refundStatus) as RefundFilter || "ALL";
}
+function setCustomerKeyword(customer: Customer): void {
+ const value = customer.name?.trim() || customer.code?.trim() || "";
+ customerId.value = customer.id || "";
+ selectedCustomer.value = customer;
+ customerKeyword = value;
+ keyword.value = value;
+}
+
+async function loadRouteCustomer(): Promise {
+ if (!customerId.value) {
+ selectedCustomer.value = undefined;
+ customerKeyword = "";
+ return;
+ }
+ selectedCustomer.value = await CustomerAPI.detail(customerId.value);
+ setCustomerKeyword(selectedCustomer.value);
+}
+
function buildPageFilter(): SalesOrderPage {
const pendingReceive = paymentStatus.value === "PENDING_RECEIVE";
return {
@@ -226,6 +279,39 @@ async function selectRefundStatus(value: DropdownValue): Promise {
}
}
+async function toggleScanner(): Promise {
+ scannerVisible.value = !scannerVisible.value;
+ if (scannerVisible.value) {
+ latestDecodedText = "";
+ scanStatus.value = "正在打开相机。";
+ }
+}
+
+async function handleDecodedText(rawText: string): Promise {
+ const code = rawText.trim();
+ if (!code || code === latestDecodedText) {
+ return;
+ }
+ latestDecodedText = code;
+ try {
+ const customer = await CustomerAPI.findByCode(code);
+ if (!customer?.id) {
+ scanStatus.value = `客户 ${code} 不存在。`;
+ return;
+ }
+ setCustomerKeyword(customer);
+ scanStatus.value = `已识别 ${customer.name || customer.code || code},已填入搜索框。`;
+ scannerVisible.value = false;
+ await fetchList(true);
+ } catch (error) {
+ scanStatus.value = getErrorMessage(error, "客户查询失败,请重试。");
+ }
+}
+
+function handleScanStatusChange(value: string): void {
+ scanStatus.value = value;
+}
+
async function toDetail(item: SalesOrder): Promise {
if (item.id) await router.push(`/management/sales-orders/${item.id}`);
}
@@ -265,16 +351,35 @@ const search = Toolkit.debounce(async () => {
Message.error(getErrorMessage(error, "销售订单加载失败"));
}
}, false);
-watch(keyword, () => search());
+watch(keyword, async () => {
+ const isCustomerKeyword = !!customerId.value && keyword.value.trim() === customerKeyword;
+ customerKeyword = "";
+ if (isCustomerKeyword) {
+ return;
+ }
+ customerId.value = "";
+ selectedCustomer.value = undefined;
+ await search();
+});
watch(routeFilterKey, async () => {
applyRouteFilters();
+ try {
+ await loadRouteCustomer();
+ } catch {
+ selectedCustomer.value = undefined;
+ }
await fetchList(true);
});
onMounted(async () => {
navBarStore.clearRight();
navBarStore.setCustomRightVisible(!!actions.value.length);
applyRouteFilters();
- try { await fetchList(true); } catch (error) { Message.error(getErrorMessage(error, "销售订单加载失败")); }
+ try {
+ await loadRouteCustomer();
+ await fetchList(true);
+ } catch (error) {
+ Message.error(getErrorMessage(error, "销售订单加载失败"));
+ }
});
onUnmounted(() => { navBarStore.clearRight(); search.cancel(); });
@@ -299,13 +404,21 @@ onUnmounted(() => { navBarStore.clearRight(); search.cancel(); });
display: flex;
.keyword {
+ --td-button-border-radius: .75rem;
--td-input-vertical-padding: .25rem 1rem;
flex: 1;
border: 1px solid var(--td-component-border);
z-index: 2;
background: var(--td-bg-color-container);
+ padding-right: .3rem;
border-radius: 1rem;
+
+ .actions {
+ gap: .25rem;
+ display: flex;
+ align-items: center;
+ }
}
.status {
@@ -336,26 +449,16 @@ onUnmounted(() => { navBarStore.clearRight(); search.cancel(); });
border-top: none;
padding-top: .8rem;
border-radius: 0 0 1rem 1rem;
-
- &:after {
- display: none;
- }
-
- :deep(.t-dropdown-menu__item) {
- min-width: 0;
- }
-
- :deep(.t-dropdown-menu__title) {
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
}
}
.list-wrap {
padding-top: 1rem;
+ .scanner-wrap {
+ margin: 0 1rem 1rem;
+ }
+
.items {
gap: 1rem;
display: flex;