fix: polish planning layout selectors

This commit is contained in:
WuYongJie 2026-05-13 09:50:17 +08:00
parent 62bceabc66
commit c3f3b8e218
2 changed files with 74 additions and 21 deletions

View File

@ -2830,7 +2830,10 @@ describe("NonIntegratedDetailClient", () => {
screen.getByTestId(
"planning-layout-spaces-draft-sku-planning-layout-fields-1",
),
).toHaveAttribute("placeholder", "?");
).toHaveAttribute("placeholder", "");
expect(
screen.queryByTestId("planning-layout-spaces-add-sku-planning-layout-fields-1"),
).not.toBeInTheDocument();
fireEvent.change(
screen.getByTestId(
"planning-layout-categories-draft-sku-planning-layout-fields-1",
@ -2850,7 +2853,12 @@ describe("NonIntegratedDetailClient", () => {
screen.getByTestId(
"planning-layout-categories-draft-sku-planning-layout-fields-1",
),
).toHaveAttribute("placeholder", "?");
).toHaveAttribute("placeholder", "");
expect(
screen.queryByTestId(
"planning-layout-categories-add-sku-planning-layout-fields-1",
),
).not.toBeInTheDocument();
await waitFor(() => {
const savedProduct = getNonIntegratedProductById(

View File

@ -8387,6 +8387,10 @@ export default function NonIntegratedDetailClient({
>({});
const [planningLayoutBrandPickerSkuId, setPlanningLayoutBrandPickerSkuId] =
useState<string | null>(null);
const [
planningLayoutBrandPickerPosition,
setPlanningLayoutBrandPickerPosition,
] = useState<{ skuId: string; left: number; top: number } | null>(null);
const [productLimitRows, setProductLimitRows] = useState<
NonIntegratedProductLimitRow[]
>(existingProduct?.productLimitRows ?? []);
@ -8579,6 +8583,22 @@ export default function NonIntegratedDetailClient({
onDocumentWorkspaceStateChange,
]);
useEffect(() => {
if (!planningLayoutBrandPickerSkuId) return;
const handleWindowChange = () => {
closePlanningLayoutBrandPicker();
};
window.addEventListener("resize", handleWindowChange);
window.addEventListener("scroll", handleWindowChange, true);
return () => {
window.removeEventListener("resize", handleWindowChange);
window.removeEventListener("scroll", handleWindowChange, true);
};
}, [planningLayoutBrandPickerSkuId]);
useEffect(() => {
if (typeof fetch !== "function") {
return;
@ -12509,6 +12529,11 @@ export default function NonIntegratedDetailClient({
});
}
function closePlanningLayoutBrandPicker() {
setPlanningLayoutBrandPickerSkuId(null);
setPlanningLayoutBrandPickerPosition(null);
}
function updateSampleMeasurementRow(
skuId: string,
key: Exclude<keyof NonIntegratedSampleMeasurementRow, "skuId">,
@ -17691,7 +17716,7 @@ export default function NonIntegratedDetailClient({
)}
</div>
{isReadOnly ? null : (
<>
<div className="relative ml-auto h-6 w-10 shrink-0">
<input
type="text"
aria-label={`企划布局${label}`}
@ -17715,20 +17740,16 @@ export default function NonIntegratedDetailClient({
event.preventDefault();
addPlanningLayoutListValue(row.skuId, field);
}}
placeholder="?"
className="h-6 w-10 shrink-0 rounded-apple-sm border border-apple-separator bg-apple-bg-primary px-1 text-center text-xs text-apple-label-primary outline-none placeholder:text-apple-label-tertiary"
placeholder=""
className="h-6 w-full rounded-apple-sm border border-apple-separator bg-apple-bg-primary px-1 pr-3 text-center text-xs text-apple-label-primary outline-none placeholder:text-apple-label-tertiary"
/>
<button
type="button"
aria-label={`添加${label}`}
title={`添加${label}`}
data-testid={`planning-layout-${field}-add-${row.skuId}`}
onClick={() => addPlanningLayoutListValue(row.skuId, field)}
className="inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-apple-sm bg-black text-white transition-opacity hover:opacity-80"
<span
aria-hidden="true"
className="pointer-events-none absolute right-1 top-1/2 -translate-y-1/2 text-[9px] leading-none text-apple-label-tertiary"
>
<Plus className="h-3 w-3" />
</button>
</>
⌄
</span>
</div>
)}
</div>
<datalist id={listId}>
@ -17752,6 +17773,11 @@ export default function NonIntegratedDetailClient({
}) => {
const selectedValues = getUniqueNonEmptyStrings(values);
const pickerOpen = planningLayoutBrandPickerSkuId === row.skuId;
const pickerDropdownId = `planning-layout-brands-dropdown-${row.skuId}`;
const pickerPosition =
pickerOpen && planningLayoutBrandPickerPosition?.skuId === row.skuId
? planningLayoutBrandPickerPosition
: null;
return (
<div className="w-max" style={{ minWidth }}>
@ -17789,23 +17815,42 @@ export default function NonIntegratedDetailClient({
)}
</div>
{isReadOnly ? null : (
<div className="relative">
<div className="relative ml-auto">
<button
type="button"
aria-label="选择适配品牌"
aria-expanded={pickerOpen}
aria-controls={pickerOpen ? pickerDropdownId : undefined}
data-testid={`planning-layout-brands-picker-${row.skuId}`}
onClick={() =>
onClick={(event) => {
const buttonRect =
event.currentTarget.getBoundingClientRect();
setPlanningLayoutBrandPickerSkuId((current) =>
current === row.skuId ? null : row.skuId,
)
}
);
setPlanningLayoutBrandPickerPosition((current) =>
current?.skuId === row.skuId
? null
: {
skuId: row.skuId,
left: buttonRect.right - 148,
top: buttonRect.bottom + 6,
},
);
}}
className="inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-apple-sm bg-black text-[10px] text-white transition-opacity hover:opacity-80"
>
✓
</button>
{pickerOpen ? (
<div className="absolute right-0 top-[calc(100%+6px)] z-20 min-w-[148px] rounded-apple-lg border border-apple-separator bg-apple-bg-primary p-2 shadow-apple-md">
{pickerOpen && pickerPosition ? (
<div
id={pickerDropdownId}
className="fixed z-50 min-w-[148px] rounded-apple-lg border border-apple-separator bg-apple-bg-primary p-2 shadow-apple-md"
style={{
left: Math.max(8, pickerPosition.left),
top: pickerPosition.top,
}}
>
<div className="space-y-1.5">
{options.map((brand) => {
const checked = selectedValues.includes(brand);