feat: 查价页优化,销售产品可改代码,分区导入跳过重复

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-10-06 15:37:02 +08:00
parent 0d5ebdb591
commit 63c7e4ab6f
10 changed files with 231 additions and 146 deletions

View File

@ -117,6 +117,7 @@ export async function postForewarningServiceKpiAreaGetKpiAreaInfos(
export type KpiAreaInfoImportResult = {
successCount: number
failCount: number
skipCount: number
failures: Array<{ rowNumber: number; reason: string }>
}
@ -261,6 +262,7 @@ export async function importKpiAreaInfo(
return {
successCount: Number(d.successCount ?? d.SuccessCount ?? 0),
failCount: Number(d.failCount ?? d.FailCount ?? 0),
skipCount: Number(d.skipCount ?? d.SkipCount ?? 0),
failures,
}
}

View File

@ -62,6 +62,11 @@ export async function updateSalesProduct(body: Record<string, any> & { id: numbe
assertBusinessOk(res.data)
}
export async function updateSalesProductCode(body: { id: number | string; productCode: string }) {
const res = await axiosInstance.post(omsUrl('/channel/sales-product/product-code/update'), body)
assertBusinessOk(res.data)
}
export async function deleteSalesProduct(id: number | string) {
const res = await axiosInstance.post(omsUrl('/channel/sales-product/delete'), { id })
assertBusinessOk(res.data)

View File

@ -656,6 +656,7 @@ const CORE_GROUPS: PageButtonGroup[] = [
{ code: 'AddProduct', name: '新增产品' },
{ code: 'Create', name: '新增' },
{ code: 'Update', name: '修改' },
{ code: 'UpdateCode', name: '修改产品代码' },
{ code: 'Delete', name: '删除' },
{ code: 'EditPrice', name: '编辑' },
{ code: 'Save', name: '保存' },

View File

@ -2368,7 +2368,7 @@ export default {
'order.priceCheck.form.destinationCountry.placeholder': 'Please select',
'order.priceCheck.form.shippingMethod': 'Shipping method',
'order.priceCheck.form.shippingMethod.placeholder': 'Please select',
'order.priceCheck.form.channel': 'Channel',
'order.priceCheck.form.channel': 'Route',
'order.priceCheck.form.channel.placeholder': 'All',
'order.priceCheck.form.cargoWeight': 'Cargo weight',
'order.priceCheck.form.cargoWeight.placeholder': 'Please enter weight (KG)',
@ -2389,7 +2389,7 @@ export default {
'order.priceCheck.form.postalCode': 'Postal code',
'order.priceCheck.form.postalCode.tip': 'more accurate',
'order.priceCheck.form.postalCode.placeholder': 'Optional — improves zoning',
'order.priceCheck.form.moreFilters': 'More filters',
'order.priceCheck.form.moreFilters': 'More',
'order.priceCheck.form.activeFilters': '{count} selected',
'order.priceCheck.form.clearFilters': 'Clear',
'order.priceCheck.form.removeFilter': 'Remove filter',
@ -2465,9 +2465,9 @@ export default {
'order.priceCheck.table.viewDetail': 'Details',
'order.priceCheck.table.viewGuide': 'Channel guide',
'order.priceCheck.table.viewGuideHint': 'Click to view route guide',
'order.priceCheck.table.customsOrderNow': 'Place order',
'order.priceCheck.table.orderNow': 'Place order',
'order.priceCheck.table.askAi': 'Ask AI',
'order.priceCheck.table.customsOrderNow': 'Go to order',
'order.priceCheck.table.orderNow': 'Go to order',
'order.priceCheck.table.askAi': 'Ask advisor',
'order.priceCheck.table.askAiCanShip': 'Can this ship?',
'order.priceCheck.table.askAiCheaper': 'Anything cheaper?',
'order.priceCheck.table.empty': 'No matching quotes',
@ -5171,7 +5171,13 @@ export default {
'channel.salesProducts.placeholder.productDescription': 'Customer-facing description (optional)',
'channel.salesProducts.placeholder.preStorageScript': 'Script before order persistence (optional)',
'channel.salesProducts.tip.productCode':
'Rule: region/country code + 01 line/02 express/03 postal/04 packet + other.\nExample: US04-5DAY\nNot editable after create; uppercase letters, digits, and - only',
'Rule: region/country code + 01 line/02 express/03 postal/04 packet + other.\nExample: US04-5DAY\nUppercase letters, digits, and - only; can be changed later via the edit action',
'channel.salesProducts.form.editProductCode': 'Edit',
'channel.salesProducts.modal.editProductCodeTitle': 'Edit product code',
'channel.salesProducts.modal.editProductCodeHint':
'Updates the sales-product master code only. Historical orders keep the old code; quoting and place-order use the new one.',
'channel.salesProducts.messages.productCodeRequired': 'Enter a product code',
'channel.salesProducts.messages.productCodeUpdated': 'Product code updated',
'channel.salesProducts.tip.productName':
'Rule: region/country + product type description + other.\nExample: US air packet-5 days',
'channel.salesProducts.tip.group': 'Used for website/admin grouping, e.g. express parcel',
@ -5558,7 +5564,7 @@ export default {
'channel.area.message.deleteFailed': 'Delete failed. Please try again later.',
'channel.area.import.modalTitle': 'Import area details',
'channel.area.import.tip':
'Download the template first. Country code is required (country name is filled from the code). Put match dimension/mode codes from the Enum sheet. One row, one dimension: postcode rules if filled; state only = state match; state+city = city match; empty = country fallback.',
'Download the template first. Import is incremental: exact duplicate rules in this area are skipped, not overwritten. Country code is required (country name is filled from the code). Put match dimension/mode codes from the Enum sheet. One row, one dimension: postcode rules if filled; state only = state match; state+city = city match; empty = country fallback.',
'channel.area.import.downloadTemplate': 'Download template',
'channel.area.import.submit': 'Import',
'channel.area.import.downloadSuccess': 'Template downloaded',
@ -5569,7 +5575,7 @@ export default {
'channel.area.import.failed': 'Import failed',
'channel.area.import.partialSuccess': 'Some rows failed. See details below.',
'channel.area.import.allFailed': 'Import failed. Please check the file.',
'channel.area.import.resultSummary': '{success} succeeded, {fail} failed',
'channel.area.import.resultSummary': '{success} succeeded, {skip} duplicate skipped, {fail} failed',
'channel.area.import.failRow': 'Row {row}: {reason}',
'channel.area.export.success': 'Exported {count} row(s)',
'channel.area.export.failed': 'Export failed',

View File

@ -2254,7 +2254,7 @@ export default {
'order.priceCheck.form.destinationCountry.placeholder': '请选择',
'order.priceCheck.form.shippingMethod': '运输方式',
'order.priceCheck.form.shippingMethod.placeholder': '请选择',
'order.priceCheck.form.channel': '渠道',
'order.priceCheck.form.channel': '线路',
'order.priceCheck.form.channel.placeholder': '全部',
'order.priceCheck.form.cargoWeight': '货物重量',
'order.priceCheck.form.cargoWeight.placeholder': '请输入重量(KG)',
@ -2275,7 +2275,7 @@ export default {
'order.priceCheck.form.postalCode': '邮编',
'order.priceCheck.form.postalCode.tip': '更准',
'order.priceCheck.form.postalCode.placeholder': '选填,补全更准确',
'order.priceCheck.form.moreFilters': '更多条件',
'order.priceCheck.form.moreFilters': '更多',
'order.priceCheck.form.activeFilters': '已选 {count} 项',
'order.priceCheck.form.clearFilters': '清空',
'order.priceCheck.form.removeFilter': '移除条件',
@ -2351,9 +2351,9 @@ export default {
'order.priceCheck.table.viewDetail': '详情',
'order.priceCheck.table.viewGuide': '渠道说明',
'order.priceCheck.table.viewGuideHint': '点击查看线路说明',
'order.priceCheck.table.customsOrderNow': '立刻下单',
'order.priceCheck.table.orderNow': '立刻下单',
'order.priceCheck.table.askAi': '问 AI',
'order.priceCheck.table.customsOrderNow': '去下单',
'order.priceCheck.table.orderNow': '去下单',
'order.priceCheck.table.askAi': '问顾问',
'order.priceCheck.table.askAiCanShip': '这个能不能发?',
'order.priceCheck.table.askAiCheaper': '有没有更便宜?',
'order.priceCheck.table.empty': '暂无匹配报价',
@ -5206,7 +5206,13 @@ export default {
'channel.salesProducts.placeholder.productDescription': '面向客户的产品说明(选填)',
'channel.salesProducts.placeholder.preStorageScript': '订单落库前执行的脚本(选填)',
'channel.salesProducts.tip.productCode':
'命名规则:地区/国家代码 + 01专线/02快递/03邮政/04小包 + 其他。\n示例:US04-5DAY\n创建后不可修改;仅支持大写字母、数字和 -',
'命名规则:地区/国家代码 + 01专线/02快递/03邮政/04小包 + 其他。\n示例:US04-5DAY\n仅支持大写字母、数字和 -;创建后可通过修改入口单独改代码',
'channel.salesProducts.form.editProductCode': '修改',
'channel.salesProducts.modal.editProductCodeTitle': '修改产品代码',
'channel.salesProducts.modal.editProductCodeHint':
'仅改销售产品主数据代码。历史订单仍保留原代码;下单、查价将使用新代码。',
'channel.salesProducts.messages.productCodeRequired': '请输入产品代码',
'channel.salesProducts.messages.productCodeUpdated': '产品代码已更新',
'channel.salesProducts.tip.productName':
'命名规则:地区/国家 + 产品类型描述 + 其他。\n示例:美国空运小包-5日达',
'channel.salesProducts.tip.group': '用于官网/后台分组展示,如专线小包',
@ -5569,7 +5575,7 @@ export default {
'channel.area.search.button.query': '查询',
'channel.area.search.button.reset': '重置',
'channel.area.import.modalTitle': '导入分区明细',
'channel.area.import.tip': '请先下载模板。国家代码必填(无需填国家名称,导入时按代码自动带出)。匹配维度、匹配方式请填 Sheet「枚举值」中的编码。一行一个维度:填邮编则为邮编规则(只填起始=前缀;起止相同=精确;起止不同=闭区间);不填邮编只填州=州匹配;州+城市=城市匹配;都空=仅国家兜底。',
'channel.area.import.tip': '请先下载模板。导入为增量写入:与本分区已有规则完全相同的行会跳过,不会覆盖。国家代码必填(无需填国家名称,导入时按代码自动带出)。匹配维度、匹配方式请填 Sheet「枚举值」中的编码。一行一个维度:填邮编则为邮编规则(只填起始=前缀;起止相同=精确;起止不同=闭区间);不填邮编只填州=州匹配;州+城市=城市匹配;都空=仅国家兜底。',
'channel.area.import.downloadTemplate': '下载模板',
'channel.area.import.submit': '开始导入',
'channel.area.import.downloadSuccess': '模板下载成功',
@ -5580,7 +5586,7 @@ export default {
'channel.area.import.failed': '导入失败',
'channel.area.import.partialSuccess': '部分行导入失败,请查看失败明细',
'channel.area.import.allFailed': '导入失败,请检查文件内容',
'channel.area.import.resultSummary': '成功 {success} 条,失败 {fail} 条',
'channel.area.import.resultSummary': '成功 {success} 条,跳过重复 {skip} 条,失败 {fail} 条',
'channel.area.import.failRow': '第 {row} 行:{reason}',
'channel.area.export.success': '已导出 {count} 条',
'channel.area.export.failed': '导出失败',

View File

@ -34,6 +34,7 @@
{{
t('channel.area.import.resultSummary', {
success: importResult.successCount,
skip: importResult.skipCount,
fail: importResult.failCount,
})
}}
@ -117,7 +118,7 @@
try {
const result = await importKpiAreaInfo(areaId.value, selectedFile.value);
importResult.value = result;
if (result.successCount > 0) {
if (result.successCount > 0 || result.skipCount > 0) {
emit('success');
}
if (result.failCount === 0) {
@ -125,7 +126,7 @@
visible.value = false;
return true;
}
if (result.successCount > 0) {
if (result.successCount > 0 || result.skipCount > 0) {
Message.warning(t('channel.area.import.partialSuccess'));
} else {
Message.error(t('channel.area.import.allFailed'));

View File

@ -18,6 +18,7 @@
saveSalesProductCustomerGuide,
toggleSalesProductPriceStatus,
updateSalesProduct,
updateSalesProductCode,
updateSalesProductPrice,
} from '@/api/channel/salesProduct';
import { getLabelTemplateList } from '@/api/channel/labelTemplate';
@ -154,6 +155,9 @@
const customerGuideSaving = ref(false);
const customerGuidePanelRef = ref<InstanceType<typeof MarkdownDocPanel> | null>(null);
const savingConfig = ref(false);
const productCodeModalVisible = ref(false);
const productCodeDraft = ref('');
const savingProductCode = ref(false);
function parseAdditionalServiceCodes(raw: unknown): string[] {
if (Array.isArray(raw)) {
@ -252,6 +256,42 @@
.replace(/[^A-Z0-9-]/g, '');
}
function openProductCodeModal() {
if (selectedProduct.value == null) return;
productCodeDraft.value = normalizeBizCode(formData.productCode);
productCodeModalVisible.value = true;
}
async function handleSaveProductCode() {
const pid = selectedProduct.value;
if (pid == null) return;
const next = normalizeBizCode(productCodeDraft.value);
if (!next) {
Message.warning(t('channel.salesProducts.messages.productCodeRequired'));
return Promise.reject();
}
savingProductCode.value = true;
try {
await updateSalesProductCode({ id: pid, productCode: next });
formData.productCode = next;
const hit = productList.value.find((p: any) => p.id === pid);
if (hit?.raw) {
hit.raw.productCode = next;
hit.raw.ProductCode = next;
}
if (configFormBaseline.value) {
configFormBaseline.value = { ...configFormBaseline.value, productCode: next };
}
productCodeModalVisible.value = false;
Message.success(t('channel.salesProducts.messages.productCodeUpdated'));
} catch (e: any) {
Message.error(e?.message || '修改产品代码失败');
return Promise.reject(e);
} finally {
savingProductCode.value = false;
}
}
const selectedProductContext = computed(() => {
const pid = selectedProduct.value;
if (pid == null) return null;
@ -4014,10 +4054,18 @@
</template>
<icon-question-circle class="tip-icon" />
</a-tooltip>
<button
type="button"
class="product-code-edit-icon"
:aria-label="t('channel.salesProducts.form.editProductCode')"
@click.stop="openProductCodeModal"
>
<icon-edit />
</button>
</label>
<a-input
v-model="formData.productCode"
:placeholder="t('channel.salesProducts.form.placeholder.input')"
:placeholder="t('channel.salesProducts.placeholder.productCode')"
class="form-input"
disabled
/>
@ -5487,6 +5535,25 @@
</div>
</a-modal>
<a-modal
v-model:visible="productCodeModalVisible"
:title="t('channel.salesProducts.modal.editProductCodeTitle')"
width="420px"
:mask-closable="false"
:ok-loading="savingProductCode"
@ok="handleSaveProductCode"
@cancel="productCodeModalVisible = false"
>
<p class="product-code-edit-hint">{{ t('channel.salesProducts.modal.editProductCodeHint') }}</p>
<a-input
:model-value="productCodeDraft"
:placeholder="t('channel.salesProducts.placeholder.productCode')"
allow-clear
@update:model-value="(v) => (productCodeDraft = normalizeBizCode(v))"
@press-enter="handleSaveProductCode"
/>
</a-modal>
<ChannelReferencePreviewModal ref="referencePreviewRef" :dict-label-fn="dictLabelByType" />
</div>
</template>
@ -5691,6 +5758,31 @@
font-size: 14px;
}
.product-code-edit-icon {
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0;
border: none;
background: transparent;
color: var(--color-text-3);
font-size: 14px;
line-height: 1;
cursor: pointer;
&:hover {
color: var(--app-primary-color, #007979);
}
}
.product-code-edit-hint {
margin: 0 0 12px;
color: var(--color-text-3);
font-size: 12px;
line-height: 1.5;
}
.form-input,
.form-select,
.form-textarea {

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { IconDown } from '@arco-design/web-vue/es/icon'
import IconTabService from '@/assets/icons/h5/tab-service.svg'
defineOptions({ name: 'PriceCheckQuoteResultCard' })
@ -328,13 +328,13 @@
</div>
<div class="quote-card__actions" @click.stop>
<button type="button" class="ops-btn ops-btn--primary" @click="emit('order')">
{{ t('order.priceCheck.table.orderNow') }}
</button>
<a-dropdown trigger="click" position="br">
<button type="button" class="ops-btn ops-btn--ghost">
{{ t('order.priceCheck.table.askAi') }}
<icon-down style="margin-left: 2px" />
<a-dropdown trigger="click" position="bl">
<button
type="button"
class="advisor-icon-btn"
:aria-label="t('order.priceCheck.table.askAi')"
>
<IconTabService class="advisor-icon-btn__icon" />
</button>
<template #content>
<a-doption @click="emit('ask', 'canShip')">
@ -345,6 +345,9 @@
</a-doption>
</template>
</a-dropdown>
<button type="button" class="ops-btn ops-btn--primary" @click="emit('order')">
{{ t('order.priceCheck.table.orderNow') }}
</button>
</div>
</div>
</a-spin>
@ -666,25 +669,18 @@
.quote-card__actions {
display: flex;
flex-direction: column;
align-items: stretch;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 6px;
flex-shrink: 0;
min-width: 88px;
:deep(.arco-dropdown-open),
:deep(.arco-trigger),
> :deep(.arco-dropdown-trigger),
> .arco-dropdown-open {
width: 100%;
display: block;
}
> :deep(span),
> :deep(div) {
width: 100%;
display: block;
display: inline-flex;
flex-shrink: 0;
}
}
@ -692,36 +688,54 @@
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
height: 28px;
padding: 0 10px;
border-radius: 6px;
font-size: 12px;
cursor: pointer;
border: 1px solid transparent;
&--ghost {
background: transparent;
border-color: var(--color-border-2);
color: var(--color-text-2);
&:hover {
color: var(--app-primary-color, #007979);
border-color: color-mix(in srgb, var(--app-primary-color, #007979) 35%, var(--color-border-2));
background: color-mix(in srgb, var(--app-primary-color, #007979) 4%, transparent);
}
}
&--primary {
min-width: 88px;
height: 32px;
padding: 0 16px;
border-radius: 6px;
background: var(--app-primary-color, #007979);
color: #fff;
font-size: 13px;
font-weight: 600;
line-height: 1;
text-align: center;
box-shadow: 0 1px 2px color-mix(in srgb, var(--app-primary-color, #007979) 28%, transparent);
&:hover {
filter: brightness(1.04);
filter: brightness(1.06);
}
}
}
.advisor-icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
margin: 0;
padding: 0;
border: none;
border-radius: 16px;
background: transparent;
color: var(--app-primary-color, #007979);
cursor: pointer;
flex-shrink: 0;
&:hover {
background: color-mix(in srgb, var(--app-primary-color, #007979) 8%, transparent);
}
}
.advisor-icon-btn__icon {
width: 22px;
height: 22px;
display: block;
}
.quote-card__fee-pop {
display: flex;
flex-direction: column;
@ -799,7 +813,7 @@
.quote-card__actions {
width: 100%;
justify-content: flex-end;
justify-content: center;
}
}
@ -810,13 +824,10 @@
}
.quote-card__actions {
flex-direction: row;
width: 100%;
min-width: 0;
}
.ops-btn--primary {
flex: 1;
min-width: 120px;
}
}

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { IconDown, IconSearch } from '@arco-design/web-vue/es/icon'
import { IconClose, IconDown, IconSearch } from '@arco-design/web-vue/es/icon'
import SlidingTabs from '@/components/SlidingTabs/index.vue'
import type { PriceCheckShippingGroup } from '@/api/order'
@ -132,7 +132,7 @@ function clearSelection(e: Event) {
aria-label="clear"
@click="clearSelection"
>
×
<icon-close />
</button>
<icon-down class="trigger-icon" />
</div>
@ -233,20 +233,23 @@ function clearSelection(e: Event) {
}
.trigger-clear {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 18px;
height: 18px;
width: 16px;
height: 16px;
margin-left: 4px;
padding: 0;
border: none;
border-radius: 50%;
background: var(--color-fill-4);
color: #fff;
background: transparent;
color: var(--color-text-3);
font-size: 12px;
line-height: 16px;
line-height: 1;
cursor: pointer;
&:hover {
background: var(--color-text-3);
color: var(--color-text-1);
}
}

View File

@ -40,7 +40,7 @@
const formData = reactive({
destinationCountry: '',
shippingMethod: '',
cargoWeight: '',
cargoWeight: '1',
length: '',
width: '',
height: '',
@ -92,18 +92,6 @@
const couponInstanceId = ref<number | undefined>(undefined);
const availableCoupons = ref<CouponAvailableOutput[]>([]);
const advancedActiveCount = computed(() => {
let n = 0;
if (formData.shippingMethod) n += 1;
if (formData.cargoType) n += 1;
if (formData.warehouseId != null) n += 1;
if (hasFullDimensions() || hasPartialDimensions()) n += 1;
if (String(formData.destinationProvince || '').trim()) n += 1;
if (String(formData.destinationCity || '').trim()) n += 1;
if (couponInstanceId.value) n += 1;
return n;
});
const needPostalHint = computed(() => {
if (!hasQueried.value) return false;
if (String(formData.postalCode || '').trim()) return false;
@ -125,7 +113,6 @@
| 'destinationCity'
| 'cargoType'
| 'warehouse'
| 'shipping'
| 'coupon';
value?: string | number;
};
@ -181,17 +168,6 @@
});
}
if (formData.shippingMethod) {
const flat = (shippingMethodGroups.value || []).flatMap((g) => g.products || []);
const hit = flat.find((it) => it.productCode === formData.shippingMethod);
chips.push({
key: 'shipping',
kind: 'shipping',
value: formData.shippingMethod,
label: hit?.label || formData.shippingMethod,
});
}
if (couponInstanceId.value) {
const c = availableCoupons.value.find((x) => (x.id ?? x.Id) === couponInstanceId.value);
const name = String(c?.templateName ?? c?.TemplateName ?? '').trim();
@ -229,10 +205,6 @@
formData.warehouseId = undefined;
return;
}
if (chip.kind === 'shipping') {
formData.shippingMethod = '';
return;
}
if (chip.kind === 'coupon') {
couponInstanceId.value = undefined;
}
@ -246,7 +218,6 @@
formData.destinationCity = '';
formData.cargoType = '';
formData.warehouseId = undefined;
formData.shippingMethod = '';
couponInstanceId.value = undefined;
}
@ -621,14 +592,15 @@
availableCoupons.value = coupons ?? [];
hintBannerDismissed.value = false;
queryResults.value = processQueryResults(items || []);
selectedGuideRecord.value = null;
resetRecommendState();
sortMode.value = 'recommend';
currentPage.value = 1;
recalcLoadingKeys.value = {};
if (!queryResults.value.length) {
selectedGuideRecord.value = null;
applyPriceCheckFailures(failures ?? []);
} else {
selectedGuideRecord.value = sortedResults.value[0] ?? queryResults.value[0];
clearPriceCheckFailures();
Message.success(t('order.priceCheck.message.querySuccess', { count: queryResults.value.length }));
}
@ -648,7 +620,7 @@
Object.assign(formData, {
destinationCountry: '',
shippingMethod: '',
cargoWeight: '',
cargoWeight: '1',
length: '',
width: '',
height: '',
@ -1001,6 +973,17 @@
</div>
<div class="form-row form-row-primary">
<div class="form-item form-item-channel">
<label class="form-label">{{ $t('order.priceCheck.form.channel') }}</label>
<ShippingMethodTabSelect
v-model="formData.shippingMethod"
:groups="shippingMethodGroups"
:loading="optionsLoading"
:placeholder="$t('order.priceCheck.form.channel.placeholder')"
class="form-select"
/>
</div>
<div class="form-item form-item-country">
<label class="form-label required">{{ $t('order.priceCheck.form.destinationCountry') }}</label>
<a-select
@ -1035,21 +1018,21 @@
</a-select>
</div>
<div class="form-item">
<label class="form-label required">{{ $t('order.priceCheck.form.cargoWeight') }}</label>
<div ref="postalInputRef" class="form-item form-item-compact">
<label class="form-label">{{ $t('order.priceCheck.form.postalCode') }}</label>
<a-input
v-model="formData.cargoWeight"
:placeholder="$t('order.priceCheck.form.cargoWeight.placeholder')"
v-model="formData.postalCode"
:placeholder="$t('order.priceCheck.form.postalCode.placeholder')"
class="form-input"
@press-enter="handleQuery"
/>
</div>
<div ref="postalInputRef" class="form-item">
<label class="form-label">{{ $t('order.priceCheck.form.postalCode') }}</label>
<div class="form-item form-item-compact">
<label class="form-label required">{{ $t('order.priceCheck.form.cargoWeight') }}</label>
<a-input
v-model="formData.postalCode"
:placeholder="$t('order.priceCheck.form.postalCode.placeholder')"
v-model="formData.cargoWeight"
:placeholder="$t('order.priceCheck.form.cargoWeight.placeholder')"
class="form-input"
@press-enter="handleQuery"
/>
@ -1071,10 +1054,7 @@
{{ $t('order.priceCheck.actions.reset') }}
</a-button>
<button type="button" class="advanced-toggle-btn" @click="showAdvanced = !showAdvanced">
<span>
{{ $t('order.priceCheck.form.moreFilters') }}
<span v-if="advancedActiveCount" class="advanced-count">{{ advancedActiveCount }}</span>
</span>
<span>{{ $t('order.priceCheck.form.moreFilters') }}</span>
<icon-up v-if="showAdvanced" />
<icon-down v-else />
</button>
@ -1110,10 +1090,10 @@
<icon-close />
</span>
</button>
<button type="button" class="filter-summary-bar__clear" @click="clearAdvancedConditions">
{{ $t('order.priceCheck.form.clearFilters') }}
</button>
</div>
<button type="button" class="filter-summary-bar__clear" @click="clearAdvancedConditions">
{{ $t('order.priceCheck.form.clearFilters') }}
</button>
</div>
<div v-show="showAdvanced" class="form-row form-row-advanced">
@ -1183,17 +1163,6 @@
</a-select>
</div>
<div class="form-item">
<label class="form-label">{{ $t('order.priceCheck.form.channel') }}</label>
<ShippingMethodTabSelect
v-model="formData.shippingMethod"
:groups="shippingMethodGroups"
:loading="optionsLoading"
:placeholder="$t('order.priceCheck.form.channel.placeholder')"
class="form-select"
/>
</div>
<div class="form-item">
<label class="form-label">{{ $t('order.priceCheck.form.cargoType') }}</label>
<a-select
@ -1365,8 +1334,8 @@
background-color: var(--app-page-bg);
}
.price-check-layout { display: flex; gap: 12px; flex: 1; min-height: 0; min-width: 0; }
.price-check-main { flex: 7 1 0; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 12px; overflow: hidden; }
.price-check-aside { flex: 3 1 0; min-width: 300px; min-height: 0; display: flex; flex-direction: column; > * { flex: 1; min-height: 0; } }
.price-check-main { flex: 5 1 0; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 12px; overflow: hidden; }
.price-check-aside { flex: 3 1 0; min-width: 340px; min-height: 0; display: flex; flex-direction: column; > * { flex: 1; min-height: 0; } }
.liquid-panel {
position: relative;
z-index: 0;
@ -1439,8 +1408,9 @@
font-size: 12px;
line-height: 1.4;
}
.form-row { display: flex; gap: 20px; align-items: flex-start; flex-wrap: wrap; }
.form-row { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
.form-row-primary, .form-row-advanced { overflow-x: auto; padding-bottom: 2px; -webkit-overflow-scrolling: touch; }
.form-row-primary { flex-wrap: nowrap; }
.form-row-advanced {
margin-top: 12px;
padding-top: 16px;
@ -1543,23 +1513,9 @@
white-space: nowrap;
&:hover { color: var(--app-primary-color, #007979); }
}
.advanced-count {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 16px;
height: 16px;
margin-left: 4px;
padding: 0 4px;
border-radius: 8px;
background: rgba(0, 121, 121, 0.1);
color: var(--app-primary-color, #007979);
font-size: 11px;
line-height: 16px;
}
.form-hint { margin: 0; color: var(--color-text-3); font-size: 12px; line-height: 1.3; }
.form-item {
display: flex; flex-direction: column; gap: 8px; flex: 0 0 auto; width: 168px; min-width: 140px;
display: flex; flex-direction: column; gap: 8px; flex: 0 0 auto; width: 148px; min-width: 132px;
&.dimensions-group { width: 260px; min-width: 220px; }
&.button-group { width: auto; min-width: 0; flex-shrink: 0; }
.button-group-row {
@ -1570,7 +1526,9 @@
justify-content: flex-start;
flex-wrap: nowrap;
}
&.form-item-country { width: 280px; min-width: 240px; flex-shrink: 0; }
&.form-item-country { width: 240px; min-width: 200px; flex-shrink: 0; }
&.form-item-channel { width: 220px; min-width: 180px; flex-shrink: 0; }
&.form-item-compact { width: 112px; min-width: 100px; }
}
.country-shortcuts {
display: flex;