diff --git a/src/views/SellerDashboard/MyListings/EditDetail/agents.md b/src/views/SellerDashboard/MyListings/EditDetail/agents.md
new file mode 100644
index 00000000..af80d1a8
--- /dev/null
+++ b/src/views/SellerDashboard/MyListings/EditDetail/agents.md
@@ -0,0 +1,68 @@
+# EditDetail Page Agent Notes
+
+This directory owns the seller listing edit/create detail page.
+
+## Files
+
+- `index.vue`: route-level container. Keep orchestration here: history-state entry mode, API calls, page switching, validation, save/publish navigation, image crop dialog wiring.
+- `api.ts`: API wrappers for listing detail, sketch detail, listing batch save, status update, and file upload.
+- `types.ts`: shared page-local TypeScript types. Add new cross-component page types here instead of duplicating interfaces in child components.
+- `components/TopImageSection.vue`: presentational block for `sketch`, `mainProductImage`, and `cover`.
+- `components/ProductImageList.vue`: presentational product-image selector and selected/main badge display.
+- `components/ApparelSketchList.vue`: presentational apparel sketch list and crop trigger.
+- `components/ListingForm.vue`: presentational listing form. Emits field updates; does not call APIs.
+- `components/Radio.vue`: local radio/multi-select button component.
+- `Status.vue`: save/publish result status page.
+
+## Component Boundaries
+
+- Keep `index.vue` as the single source of truth for `selectList`, `currentPage`, `currentListing`, per-listing `firstSelectedIndex`, and crop/save behavior.
+- Child components should receive props and emit events only. Do not import listing APIs or mutate parent state directly from children.
+- If a new visual section is added to this page, prefer a new child component under `components/` plus shared types in `types.ts`.
+
+## Image Category Mapping
+
+Detail API images are mapped by `category`:
+
+- `cover` -> `currentListing.cover`
+- `sketch` -> `currentListing.sketch`
+- `mainProductImage` -> `currentListing.mainProductImage`
+- `main_product` or `product` -> `currentListing.prodImageList`
+- `apparel` -> `currentListing.sketchList`
+
+When saving, preserve the backend's expected image categories. Confirm backend naming before changing `main_product`, `product`, or `mainProductImage`.
+
+## Product Image Rules
+
+- The `main` badge represents the first selected product image, not the most recently selected one.
+- `firstSelectedIndex` is stored on each `ListingItem` and passed to `ProductImageList.vue`.
+- Selecting a product image should only set `mainProductImage` when no main image is currently tracked by that listing's `firstSelectedIndex`.
+- Unselecting the current main product image clears `mainProductImage` and resets `firstSelectedIndex`.
+
+## Crop Flow
+
+- `TopImageSection.vue` and `ApparelSketchList.vue` emit `crop`.
+- `index.vue` handles `handleClickCrop`, opens `ImageClipDialog`, uploads with `uploadFile`, then writes the returned URL into the correct field/list item.
+- Keep cover crop ratio at `[4, 5]`; other crop types use `[9, 16]`.
+
+## Form Flow
+
+- `ListingForm.vue` accepts scalar form props and emits `update:*` events.
+- `index.vue` writes those events back into `currentListing`.
+- Category options are derived from current gender and Vuex `UserHabit` state.
+
+## Validation And Navigation
+
+- `validatePublishRequired()` validates each listing before publish.
+- Draft currently requires `cover` before save.
+- After save/publish, routing goes to `Status` with route param `status`.
+
+## Verification
+
+- Run `npm run build` after behavior or type changes.
+- Build can fail before code bundling completes if the existing `feedbackSurvey.vue` Google Fonts import cannot be fetched. If the failure is only `fonts.googleapis.com` socket/DNS related, retry when network is available.
+- Project ESLint currently fails before linting files because `.eslintrc.js` contains invalid env key `se6`; do not treat that as a page-specific regression.
+
+## Known Caution
+
+- This page has active local edits. Before broad refactors, inspect both staged and unstaged diffs.
diff --git a/src/views/SellerDashboard/MyListings/EditDetail/index.vue b/src/views/SellerDashboard/MyListings/EditDetail/index.vue
index b1438021..7311066f 100644
--- a/src/views/SellerDashboard/MyListings/EditDetail/index.vue
+++ b/src/views/SellerDashboard/MyListings/EditDetail/index.vue
@@ -31,7 +31,7 @@
(null) //显示main标签的图片索引
-
const getSortedDetailImages = (images: ListingDetailImage[] = []) => {
return [...images].sort((prev, next) => (prev.sortOrder ?? 0) - (next.sortOrder ?? 0))
}
@@ -234,6 +233,9 @@
listing.prodImageList.find((item) => item.selected)?.url || ""
}
+ const selectedIndex = listing.prodImageList.findIndex((item) => item.selected)
+ listing.firstSelectedIndex = selectedIndex === -1 ? null : selectedIndex
+
listing.productImage = listing.prodImageList.map((item) => item.url)
listing.apparelSketch = listing.sketchList
.map((item) => item.url)
@@ -243,20 +245,21 @@
}
const handleSelectProdImg = (index: number) => {
+ const listing = currentListing.value
const target = prodImgList.value[index]
const willSelect = !target.selected
target.selected = willSelect
- if (willSelect && firstSelectedIndex.value === null) {
- currentListing.value.mainProductImage = target.url
- firstSelectedIndex.value = index
+ if (willSelect && listing.firstSelectedIndex === null) {
+ listing.mainProductImage = target.url
+ listing.firstSelectedIndex = index
return
}
- if (!willSelect && currentListing.value.mainProductImage === target.url) {
- firstSelectedIndex.value = null
- currentListing.value.mainProductImage = ""
+ if (!willSelect && listing.mainProductImage === target.url) {
+ listing.firstSelectedIndex = null
+ listing.mainProductImage = ""
}
}
@@ -360,7 +363,7 @@
price: item.price,
status: type === "draft" ? 0 : 1,
images: [],
- designFor: item.gender.toLowerCase,
+ designFor: (item.gender || "FEMALE").toLowerCase(),
productCategory: item.category
}
@@ -394,8 +397,6 @@
})
paramsList.push(params)
})
- console.log(paramsList)
- debugger
await fetchUpdateListing(paramsList)
}
const handleClickMenu = async (status: StatusType) => {
@@ -433,11 +434,9 @@
const handleGetDetailById = () => {
fetchListingDetailById(itemId.value).then((res: ListingDetailResponse) => {
const listing = createListingItemFromDetail(res)
- const selectedIndex = listing.prodImageList.findIndex((item) => item.selected)
currentPage.value = 1
selectList.value = [listing]
- firstSelectedIndex.value = selectedIndex === -1 ? null : selectedIndex
})
}
diff --git a/src/views/SellerDashboard/MyListings/EditDetail/types.ts b/src/views/SellerDashboard/MyListings/EditDetail/types.ts
index a2414647..dc282606 100644
--- a/src/views/SellerDashboard/MyListings/EditDetail/types.ts
+++ b/src/views/SellerDashboard/MyListings/EditDetail/types.ts
@@ -20,6 +20,7 @@ export type ListingItem = {
desc: string
gender: string
category: string[] | null
+ firstSelectedIndex: number | null
prodImageList: Array<{
url: string
selected?: boolean