chore: 拆分组件
This commit is contained in:
@@ -144,7 +144,6 @@ const open = (url, callback, options, origin) => {
|
|||||||
coverOrigin.value = origin
|
coverOrigin.value = origin
|
||||||
data.url = origin[0].url
|
data.url = origin[0].url
|
||||||
}
|
}
|
||||||
console.log("-------", origin)
|
|
||||||
show.value = true
|
show.value = true
|
||||||
}
|
}
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { ListingItem } from "../types"
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
sketchList: ListingItem["sketchList"]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "crop", data: string | null, type: "apparel", index?: number): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="apparel-container">
|
||||||
|
<div class="title">
|
||||||
|
<span class="main-title">{{ $t("SellerListEdit.apparelSketchTitle") }}</span>
|
||||||
|
<span class="sub-title">{{ $t("SellerListEdit.apparelSketchSubTitle") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sketch-list-container flex">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in sketchList"
|
||||||
|
:key="index"
|
||||||
|
class="sketch-element flex flex-center"
|
||||||
|
>
|
||||||
|
<img class="img-src" :src="item.url || ''" alt="" />
|
||||||
|
<div class="crop-tool flex flex-center" @click="emit('crop', item.url, 'apparel', index)">
|
||||||
|
<SvgIcon name="CCrop" color="#fff" size="12" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.apparel-container {
|
||||||
|
margin-top: 3rem;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: bold;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "*";
|
||||||
|
color: #df2b2c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sketch-list-container {
|
||||||
|
column-gap: 1rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.sketch-element {
|
||||||
|
width: 10rem;
|
||||||
|
height: 14.6rem;
|
||||||
|
border: 0.15rem solid #c7c7c7;
|
||||||
|
border-radius: 1.2rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.img-src {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crop-tool {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.4rem;
|
||||||
|
right: 0.4rem;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,222 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Radio from "./Radio.vue"
|
||||||
|
import type { RadioOption } from "../types"
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
productName: string
|
||||||
|
price: string
|
||||||
|
desc: string
|
||||||
|
gender: string
|
||||||
|
category: string[] | null
|
||||||
|
genderOptions: RadioOption[]
|
||||||
|
categoryOptions: RadioOption[]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "update:productName", value: string): void
|
||||||
|
(e: "update:price", value: string): void
|
||||||
|
(e: "update:desc", value: string): void
|
||||||
|
(e: "update:gender", value: string): void
|
||||||
|
(e: "update:category", value: string[] | null): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="form-container flex flex-col">
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label required">
|
||||||
|
{{ $t("SellerListEdit.productName") }}
|
||||||
|
</div>
|
||||||
|
<div class="form-item-value product-name">
|
||||||
|
<a-input
|
||||||
|
:value="productName"
|
||||||
|
show-count
|
||||||
|
placeholder="Enter product name"
|
||||||
|
:bordered="false"
|
||||||
|
:maxlength="60"
|
||||||
|
@update:value="emit('update:productName', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label required">{{ $t("SellerListEdit.price") }}</div>
|
||||||
|
<div class="form-item-value price flex align-center">
|
||||||
|
<span>HK$</span>
|
||||||
|
<a-input
|
||||||
|
:value="price"
|
||||||
|
placeholder="0.00"
|
||||||
|
:bordered="false"
|
||||||
|
@update:value="emit('update:price', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label required">
|
||||||
|
{{ $t("SellerListEdit.productDescription") }}
|
||||||
|
</div>
|
||||||
|
<div class="form-item-value desc">
|
||||||
|
<a-textarea
|
||||||
|
:value="desc"
|
||||||
|
show-count
|
||||||
|
:rows="4"
|
||||||
|
placeholder="Enter product description"
|
||||||
|
:bordered="false"
|
||||||
|
:maxlength="500"
|
||||||
|
@update:value="emit('update:desc', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label required">
|
||||||
|
{{ $t("SellerListEdit.designFor") }}
|
||||||
|
</div>
|
||||||
|
<div class="form-item-value no-border">
|
||||||
|
<Radio
|
||||||
|
:options="genderOptions"
|
||||||
|
:model-value="gender"
|
||||||
|
@update:model-value="emit('update:gender', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label with-tip">
|
||||||
|
<span class="required">{{ $t("SellerListEdit.productCategory") }}</span>
|
||||||
|
<span class="help-text">{{ $t("SellerListEdit.categoryTips") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-item-value no-border">
|
||||||
|
<Radio
|
||||||
|
multiple
|
||||||
|
:options="categoryOptions"
|
||||||
|
:model-value="category"
|
||||||
|
@update:model-value="emit('update:category', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="license-note flex align-center">
|
||||||
|
<img src="@/assets/images/seller/tips.png" class="info-icon" />
|
||||||
|
<div class="note-copy">
|
||||||
|
{{ $t("SellerListEdit.policy") }}
|
||||||
|
<a href="javascript:void(0)">{{ $t("SellerListEdit.learnMore") }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.required {
|
||||||
|
&::after {
|
||||||
|
content: "*";
|
||||||
|
color: #df2b2c;
|
||||||
|
margin-left: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
row-gap: 3rem;
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
.form-item-label {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: bold;
|
||||||
|
margin-bottom: 0.6rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
&.with-tip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-text {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item-value {
|
||||||
|
border: 0.16rem solid #d1d1d1;
|
||||||
|
border-radius: 1.2rem;
|
||||||
|
position: relative;
|
||||||
|
padding: 1.6rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
&.no-border {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.price {
|
||||||
|
column-gap: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input),
|
||||||
|
:deep(.ant-input-affix-wrapper),
|
||||||
|
:deep(.ant-input-textarea textarea) {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #000;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input) {
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input-show-count-suffix) {
|
||||||
|
color: #df2c2c;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(textarea.ant-input) {
|
||||||
|
resize: none;
|
||||||
|
min-height: 5.4rem;
|
||||||
|
padding-bottom: 1.8rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input-textarea-show-count) {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
float: none;
|
||||||
|
position: absolute;
|
||||||
|
color: #df2c2c;
|
||||||
|
bottom: 0;
|
||||||
|
right: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-note {
|
||||||
|
padding: 1.6rem;
|
||||||
|
column-gap: 1.6rem;
|
||||||
|
background: #f7f7f7;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
|
||||||
|
.info-icon {
|
||||||
|
width: 2.4rem;
|
||||||
|
height: 2.4rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-copy {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #000;
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: medium;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #0080ed;
|
||||||
|
text-decoration: underline;
|
||||||
|
margin-left: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue"
|
||||||
|
import type { ListingItem } from "../types"
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
imageList: ListingItem["prodImageList"]
|
||||||
|
firstSelectedIndex: number | null
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "select", index: number): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const selectedCount = computed(() => props.imageList.filter((item) => item.selected).length)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="product-image-list-container">
|
||||||
|
<div class="title flex align-center space-between">
|
||||||
|
<div class="title-left">
|
||||||
|
<span class="main-title">{{ $t("SellerListEdit.productImageMainTitle") }}</span>
|
||||||
|
<span class="sub-title">{{ $t("SellerListEdit.productImageSubTitle") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="title-right">{{ selectedCount }}/{{ imageList.length }} selected</div>
|
||||||
|
</div>
|
||||||
|
<div class="product-image-list flex">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in imageList"
|
||||||
|
:key="index"
|
||||||
|
class="product-image-item flex flex-center"
|
||||||
|
:class="{ selected: item.selected }"
|
||||||
|
@click="emit('select', index)"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="item.selected"
|
||||||
|
src="@/assets/images/seller/checked.png"
|
||||||
|
class="checked"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<img class="img-src" :src="item.url" alt="" />
|
||||||
|
<div v-if="item.selected && index === firstSelectedIndex" class="main-pic">
|
||||||
|
main
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.product-image-list-container {
|
||||||
|
margin-top: 3rem;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-right {
|
||||||
|
color: #585858;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-image-list {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
column-gap: 0.8rem;
|
||||||
|
max-width: 80.2rem;
|
||||||
|
padding-bottom: 1.2rem;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
height: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #d9d9d9;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #000000;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-image-item {
|
||||||
|
width: 11.6rem;
|
||||||
|
height: 20.6rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
border: 0.15rem solid #c7c7c7;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: "";
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
opacity: 0.7;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
border-color: #000;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checked {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.8rem;
|
||||||
|
right: 0.8rem;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-src {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-pic {
|
||||||
|
position: absolute;
|
||||||
|
height: 2.4rem;
|
||||||
|
line-height: 2.4rem;
|
||||||
|
left: 0.8rem;
|
||||||
|
right: 0.8rem;
|
||||||
|
bottom: 0.8rem;
|
||||||
|
z-index: 1;
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
border-radius: 1.2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { TopImageType } from "../types"
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
images: Record<TopImageType, string | null>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "crop", data: string | null, type: TopImageType): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const topImageList: TopImageType[] = ["sketch", "mainProductImage", "cover"]
|
||||||
|
const topImageTitleMap: Record<TopImageType, string> = {
|
||||||
|
sketch: "SellerListEdit.sketch",
|
||||||
|
mainProductImage: "SellerListEdit.mainProductImage",
|
||||||
|
cover: "SellerListEdit.cover"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="main-image-container flex">
|
||||||
|
<div
|
||||||
|
v-for="type in topImageList"
|
||||||
|
:key="type"
|
||||||
|
:class="`main-image-item flex flex-col align-center ${type}`"
|
||||||
|
>
|
||||||
|
<div class="title" :class="{ required: type !== 'mainProductImage' }">
|
||||||
|
{{ $t(topImageTitleMap[type]) }}
|
||||||
|
</div>
|
||||||
|
<div class="sketch-item flex flex-center" :class="type">
|
||||||
|
<div
|
||||||
|
v-if="images[type]"
|
||||||
|
class="crop-tool flex flex-center"
|
||||||
|
@click="emit('crop', images[type], type)"
|
||||||
|
>
|
||||||
|
<SvgIcon name="CCrop" color="#fff" size="12" />
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
v-if="images[type]"
|
||||||
|
:src="images[type] || ''"
|
||||||
|
class="sketch-img"
|
||||||
|
:class="type"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<div v-else class="trigger flex flex-col align-center">
|
||||||
|
<div
|
||||||
|
v-if="type === 'cover'"
|
||||||
|
class="cover-trigger flex flex-col align-center"
|
||||||
|
@click="emit('crop', null, 'cover')"
|
||||||
|
>
|
||||||
|
<SvgIcon class="trigger-icon" name="CCrop" color="#585858" size="24" />
|
||||||
|
<div class="trigger-tips">
|
||||||
|
{{ $t("SellerListEdit.cropDesc") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template v-else>
|
||||||
|
<div class="trigger-img placeholder"></div>
|
||||||
|
<div class="trigger-tips">
|
||||||
|
{{ $t("SellerListEdit.productImageDesc") }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.c-svg {
|
||||||
|
width: initial;
|
||||||
|
height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.required {
|
||||||
|
&::after {
|
||||||
|
content: "*";
|
||||||
|
color: #df2b2c;
|
||||||
|
margin-left: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-image-container {
|
||||||
|
column-gap: 3.5rem;
|
||||||
|
|
||||||
|
.main-image-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sketch-item {
|
||||||
|
width: 11.6rem;
|
||||||
|
height: 20.4rem;
|
||||||
|
border: 0.15rem solid #d1d1d1;
|
||||||
|
border-radius: 1rem;
|
||||||
|
position: relative;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.cover {
|
||||||
|
width: 16.2rem;
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' rx='11' ry='11' fill='none' stroke='%23D1D1D1' stroke-width='1.5' stroke-dasharray='8%2c 5' stroke-linecap='square'/%3e%3c/svg%3e");
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crop-tool {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.8rem;
|
||||||
|
right: 0.8rem;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #000000;
|
||||||
|
z-index: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sketch-img {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&.sketch {
|
||||||
|
height: initial;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger {
|
||||||
|
cursor: pointer;
|
||||||
|
height: 100%;
|
||||||
|
padding: 6rem 2rem 0;
|
||||||
|
|
||||||
|
&,
|
||||||
|
.cover-trigger {
|
||||||
|
row-gap: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
width: 2.4rem;
|
||||||
|
height: 2.4rem;
|
||||||
|
border-radius: 0.6rem;
|
||||||
|
background: linear-gradient(135deg, #efefef 0%, #cdcdcd 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-tips {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
text-align: center;
|
||||||
|
color: #585858;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -28,191 +28,32 @@
|
|||||||
</seller-header>
|
</seller-header>
|
||||||
<div class="edit-detail-content flex">
|
<div class="edit-detail-content flex">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="main-image-container flex">
|
<TopImageSection :images="previewImageMap" @crop="handleClickCrop" />
|
||||||
<div
|
<ProductImageList
|
||||||
v-for="type in topImageList"
|
:image-list="prodImgList"
|
||||||
:key="type"
|
:first-selected-index="firstSelectedIndex"
|
||||||
:class="`main-image-item flex flex-col align-center ${type}`"
|
@select="handleSelectProdImg"
|
||||||
>
|
/>
|
||||||
<div class="title" :class="{ required: type !== 'mainProductImage' }">
|
<ApparelSketchList
|
||||||
{{ $t(topImageTitleMap[type]) }}
|
:sketch-list="currentListing.sketchList"
|
||||||
</div>
|
@crop="handleClickCrop"
|
||||||
<div class="sketch-item flex flex-center" :class="type">
|
/>
|
||||||
<div
|
|
||||||
v-if="previewImageMap[type]"
|
|
||||||
class="crop-tool flex flex-center"
|
|
||||||
@click="handleClickCrop(previewImageMap[type], type)"
|
|
||||||
>
|
|
||||||
<SvgIcon name="CCrop" color="#fff" size="12" />
|
|
||||||
</div>
|
|
||||||
<img
|
|
||||||
v-if="previewImageMap[type]"
|
|
||||||
:src="previewImageMap[type]"
|
|
||||||
class="sketch-img"
|
|
||||||
:class="type"
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<div v-else class="trigger flex flex-col align-center">
|
|
||||||
<div
|
|
||||||
v-if="type === 'cover'"
|
|
||||||
class="cover-trigger flex flex-col align-center"
|
|
||||||
@click="handleClickCrop(null, 'cover')"
|
|
||||||
>
|
|
||||||
<SvgIcon
|
|
||||||
class="trigger-icon"
|
|
||||||
name="CCrop"
|
|
||||||
color="#585858"
|
|
||||||
size="24"
|
|
||||||
/>
|
|
||||||
<div class="trigger-tips">
|
|
||||||
{{ $t("SellerListEdit.cropDesc") }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template v-else>
|
|
||||||
<div class="trigger-img placeholder"></div>
|
|
||||||
<div class="trigger-tips">
|
|
||||||
{{ $t("SellerListEdit.productImageDesc") }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="product-image-list-container">
|
|
||||||
<div class="title flex align-center space-between">
|
|
||||||
<div class="title-left">
|
|
||||||
<span class="main-title">{{
|
|
||||||
$t("SellerListEdit.productImageMainTitle")
|
|
||||||
}}</span>
|
|
||||||
<span class="sub-title">{{
|
|
||||||
$t("SellerListEdit.productImageSubTitle")
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="title-right">
|
|
||||||
{{ selectedProdImgs }}/{{ prodImgList.length }} selected
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="product-image-list flex">
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in prodImgList"
|
|
||||||
:key="index"
|
|
||||||
class="product-image-item flex flex-center"
|
|
||||||
:class="{ selected: item.selected }"
|
|
||||||
@click="handleSelectProdImg(index)"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-if="item.selected"
|
|
||||||
src="@/assets/images/seller/checked.png"
|
|
||||||
class="checked"
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<img class="img-src" :src="item.url" alt="" />
|
|
||||||
<div
|
|
||||||
v-if="item.selected && index === firstSelectedIndex"
|
|
||||||
class="main-pic"
|
|
||||||
>
|
|
||||||
main
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="apparel-container">
|
|
||||||
<div class="title">
|
|
||||||
<span class="main-title">{{
|
|
||||||
$t("SellerListEdit.apparelSketchTitle")
|
|
||||||
}}</span>
|
|
||||||
<span class="sub-title">
|
|
||||||
{{ $t("SellerListEdit.apparelSketchSubTitle") }}</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="sketch-list-container flex">
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in selectList[currentIndex].sketchList"
|
|
||||||
:key="index"
|
|
||||||
class="sketch-element flex flex-center"
|
|
||||||
>
|
|
||||||
<img class="img-src" :src="item.url" alt="" />
|
|
||||||
<div
|
|
||||||
class="crop-tool flex flex-center"
|
|
||||||
@click="handleClickCrop(item.url, 'apparel')"
|
|
||||||
>
|
|
||||||
<SvgIcon name="CCrop" color="#fff" size="12" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="form-container flex flex-col">
|
<ListingForm
|
||||||
<div class="form-item">
|
:product-name="currentListing.productName"
|
||||||
<div class="form-item-label required">
|
:price="currentListing.price"
|
||||||
{{ $t("SellerListEdit.productName") }}
|
:desc="currentListing.desc"
|
||||||
</div>
|
:gender="currentListing.gender"
|
||||||
<div class="form-item-value product-name">
|
:category="currentListing.category"
|
||||||
<a-input
|
:gender-options="genderOptions"
|
||||||
v-model:value="currentListing.productName"
|
:category-options="categoryOptions"
|
||||||
show-count
|
@update:product-name="currentListing.productName = $event"
|
||||||
placeholder="Enter product name"
|
@update:price="currentListing.price = $event"
|
||||||
:bordered="false"
|
@update:desc="currentListing.desc = $event"
|
||||||
:maxlength="60"
|
@update:gender="currentListing.gender = $event"
|
||||||
/>
|
@update:category="currentListing.category = $event"
|
||||||
</div>
|
/>
|
||||||
</div>
|
|
||||||
<div class="form-item">
|
|
||||||
<div class="form-item-label required">{{ $t("SellerListEdit.price") }}</div>
|
|
||||||
<div class="form-item-value price flex align-center">
|
|
||||||
<span>HK$</span>
|
|
||||||
<a-input
|
|
||||||
v-model:value="currentListing.price"
|
|
||||||
placeholder="0.00"
|
|
||||||
:bordered="false"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-item">
|
|
||||||
<div class="form-item-label required">
|
|
||||||
{{ $t("SellerListEdit.productDescription") }}
|
|
||||||
</div>
|
|
||||||
<div class="form-item-value desc">
|
|
||||||
<a-textarea
|
|
||||||
v-model:value="currentListing.desc"
|
|
||||||
show-count
|
|
||||||
:rows="4"
|
|
||||||
placeholder="Enter product description"
|
|
||||||
:bordered="false"
|
|
||||||
:maxlength="500"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-item">
|
|
||||||
<div class="form-item-label required">
|
|
||||||
{{ $t("SellerListEdit.designFor") }}
|
|
||||||
</div>
|
|
||||||
<div class="form-item-value no-border">
|
|
||||||
<Radio :options="genderOptions" v-model="currentListing.gender" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-item">
|
|
||||||
<div class="form-item-label with-tip">
|
|
||||||
<span class="required">{{ $t("SellerListEdit.productCategory") }}</span>
|
|
||||||
<span class="help-text">{{ $t("SellerListEdit.categoryTips") }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="form-item-value no-border">
|
|
||||||
<Radio
|
|
||||||
multiple
|
|
||||||
:options="categoryOptions"
|
|
||||||
v-model="currentListing.category"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="license-note flex align-center">
|
|
||||||
<img src="@/assets/images/seller/tips.png" class="info-icon" />
|
|
||||||
<div class="note-copy">
|
|
||||||
{{ $t("SellerListEdit.policy") }}
|
|
||||||
<a href="javascript:void(0)">{{ $t("SellerListEdit.learnMore") }}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="page-control flex align-center" v-if="selectList.length > 1">
|
<div class="page-control flex align-center" v-if="selectList.length > 1">
|
||||||
<a-pagination
|
<a-pagination
|
||||||
v-model:current="currentPage"
|
v-model:current="currentPage"
|
||||||
@@ -238,13 +79,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, watch, onMounted } from "vue"
|
import { computed, ref, onMounted } from "vue"
|
||||||
import { useRouter } from "vue-router"
|
import { useRouter } from "vue-router"
|
||||||
import { useI18n } from "vue-i18n"
|
import { useI18n } from "vue-i18n"
|
||||||
import { message } from "ant-design-vue"
|
import { message } from "ant-design-vue"
|
||||||
import SellerHeader from "../../seller-header.vue"
|
import SellerHeader from "../../seller-header.vue"
|
||||||
import Radio from "./components/Radio.vue"
|
|
||||||
import ImageClipDialog from "../../BrandProfile/image-clip-dialog.vue"
|
import ImageClipDialog from "../../BrandProfile/image-clip-dialog.vue"
|
||||||
|
import ApparelSketchList from "./components/ApparelSketchList.vue"
|
||||||
|
import ListingForm from "./components/ListingForm.vue"
|
||||||
|
import ProductImageList from "./components/ProductImageList.vue"
|
||||||
|
import TopImageSection from "./components/TopImageSection.vue"
|
||||||
import { useStore } from "vuex"
|
import { useStore } from "vuex"
|
||||||
import {
|
import {
|
||||||
fetchSketchDetail,
|
fetchSketchDetail,
|
||||||
@@ -252,6 +96,13 @@
|
|||||||
fetchListingDetailById,
|
fetchListingDetailById,
|
||||||
fetchUpdateListing
|
fetchUpdateListing
|
||||||
} from "./api"
|
} from "./api"
|
||||||
|
import type {
|
||||||
|
ListingDetailImage,
|
||||||
|
ListingDetailResponse,
|
||||||
|
ListingItem,
|
||||||
|
RadioOption,
|
||||||
|
StatusType
|
||||||
|
} from "./types"
|
||||||
|
|
||||||
const ROUTER = useRouter()
|
const ROUTER = useRouter()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -264,49 +115,6 @@
|
|||||||
|
|
||||||
const STORE = useStore()
|
const STORE = useStore()
|
||||||
|
|
||||||
type CategoryOption = {
|
|
||||||
label: string
|
|
||||||
value: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListingItem = {
|
|
||||||
designItemId: number | string | null
|
|
||||||
sketch: string | null
|
|
||||||
mainProductImage: string
|
|
||||||
cover: string
|
|
||||||
productImage: string[]
|
|
||||||
apparelSketch: string[]
|
|
||||||
productName: string
|
|
||||||
price: string
|
|
||||||
desc: string
|
|
||||||
gender: string
|
|
||||||
category: string[] | null
|
|
||||||
prodImageList: Array<{
|
|
||||||
url: string
|
|
||||||
selected?: boolean
|
|
||||||
}>
|
|
||||||
sketchList: Array<{ url: string | null }>
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListingDetailImage = {
|
|
||||||
category?: string | null
|
|
||||||
imageUrl?: string | null
|
|
||||||
isSelected?: boolean | number | string | null
|
|
||||||
sortOrder?: number | null
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListingDetailResponse = {
|
|
||||||
id?: number | string | null
|
|
||||||
title?: string | null
|
|
||||||
description?: string | null
|
|
||||||
price?: number | string | null
|
|
||||||
designFor?: string | null
|
|
||||||
productCategory?: string | string[] | null
|
|
||||||
images?: ListingDetailImage[] | null
|
|
||||||
}
|
|
||||||
|
|
||||||
type StatusType = "draft" | "publish"
|
|
||||||
|
|
||||||
const createListingItem = (
|
const createListingItem = (
|
||||||
sketch: string | null = null,
|
sketch: string | null = null,
|
||||||
designItemId: number | string | null = null
|
designItemId: number | string | null = null
|
||||||
@@ -326,16 +134,9 @@
|
|||||||
sketchList: []
|
sketchList: []
|
||||||
})
|
})
|
||||||
|
|
||||||
const topImageList = ["sketch", "mainProductImage", "cover"] as const
|
|
||||||
const topImageTitleMap: Record<(typeof topImageList)[number], string> = {
|
|
||||||
sketch: "SellerListEdit.sketch",
|
|
||||||
mainProductImage: "SellerListEdit.mainProductImage",
|
|
||||||
cover: "SellerListEdit.cover"
|
|
||||||
}
|
|
||||||
|
|
||||||
const genderOptions = STORE.state.UserHabit?.sex.value || []
|
const genderOptions = STORE.state.UserHabit?.sex.value || []
|
||||||
|
|
||||||
const fallbackCategoryOptions: Record<string, CategoryOption[]> = {
|
const fallbackCategoryOptions: Record<string, RadioOption[]> = {
|
||||||
MALE: STORE.state.UserHabit?.MalePosition || [],
|
MALE: STORE.state.UserHabit?.MalePosition || [],
|
||||||
FEMALE: STORE.state.UserHabit?.FemalePosition || []
|
FEMALE: STORE.state.UserHabit?.FemalePosition || []
|
||||||
}
|
}
|
||||||
@@ -362,9 +163,6 @@
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const firstSelectedIndex = ref<number | null>(null) //显示main标签的图片索引
|
const firstSelectedIndex = ref<number | null>(null) //显示main标签的图片索引
|
||||||
const selectedProdImgs = computed(() => {
|
|
||||||
return prodImgList.value.filter((item) => item.selected).length
|
|
||||||
})
|
|
||||||
|
|
||||||
const getSortedDetailImages = (images: ListingDetailImage[] = []) => {
|
const getSortedDetailImages = (images: ListingDetailImage[] = []) => {
|
||||||
return [...images].sort((prev, next) => (prev.sortOrder ?? 0) - (next.sortOrder ?? 0))
|
return [...images].sort((prev, next) => (prev.sortOrder ?? 0) - (next.sortOrder ?? 0))
|
||||||
@@ -463,7 +261,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cropType = ref("")
|
const cropType = ref("")
|
||||||
const handleClickCrop = (data, type, list = []) => {
|
const handleClickCrop = (data: any, type: string, paramThree: any = []) => {
|
||||||
|
// 处理来自TopImageSection的调用: (data, type, list)
|
||||||
|
// 处理来自ApparelSketchList的调用: (data, type, index)
|
||||||
|
const index = typeof paramThree === 'number' ? paramThree : undefined
|
||||||
|
const list = Array.isArray(paramThree) ? paramThree : []
|
||||||
|
|
||||||
// console.log(data, type)
|
// console.log(data, type)
|
||||||
// console.log(selectList.value[currentIndex.value])
|
// console.log(selectList.value[currentIndex.value])
|
||||||
let origin = []
|
let origin = []
|
||||||
@@ -488,7 +291,11 @@
|
|||||||
(file) => {
|
(file) => {
|
||||||
// console.log(file)
|
// console.log(file)
|
||||||
uploadFile(file).then((res) => {
|
uploadFile(file).then((res) => {
|
||||||
selectList.value[currentIndex.value][type] = res
|
if (type === "apparel" && typeof index !== "undefined") {
|
||||||
|
selectList.value[currentIndex.value].sketchList[index].url = res
|
||||||
|
} else {
|
||||||
|
selectList.value[currentIndex.value][type] = res
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ ratio, isPreview: true, title: titleList[type], isProduct: true },
|
{ ratio, isPreview: true, title: titleList[type], isProduct: true },
|
||||||
@@ -721,362 +528,10 @@
|
|||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.required {
|
|
||||||
&::after {
|
|
||||||
content: "*";
|
|
||||||
color: #df2b2c;
|
|
||||||
margin-left: 0.4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
|
||||||
// flex: 1;
|
|
||||||
// min-width: 0;
|
|
||||||
|
|
||||||
.main-image-container {
|
|
||||||
// max-width: 80.2rem;
|
|
||||||
column-gap: 3.5rem;
|
|
||||||
.main-image-item {
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
margin-bottom: 0.8rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sketch-item {
|
|
||||||
width: 11.6rem;
|
|
||||||
height: 20.4rem;
|
|
||||||
border: 0.15rem solid #d1d1d1;
|
|
||||||
border-radius: 1rem;
|
|
||||||
position: relative;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&.cover {
|
|
||||||
width: 16.2rem;
|
|
||||||
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' rx='11' ry='11' fill='none' stroke='%23D1D1D1' stroke-width='1.5' stroke-dasharray='8%2c 5' stroke-linecap='square'/%3e%3c/svg%3e");
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.crop-tool {
|
|
||||||
position: absolute;
|
|
||||||
top: 0.8rem;
|
|
||||||
right: 0.8rem;
|
|
||||||
width: 2rem;
|
|
||||||
height: 2rem;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: #000000;
|
|
||||||
z-index: 1;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sketch-img {
|
|
||||||
height: 100%;
|
|
||||||
&.sketch {
|
|
||||||
height: initial;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger {
|
|
||||||
cursor: pointer;
|
|
||||||
height: 100%;
|
|
||||||
padding: 6rem 2rem 0;
|
|
||||||
&,
|
|
||||||
.cover-trigger {
|
|
||||||
row-gap: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
width: 2.4rem;
|
|
||||||
height: 2.4rem;
|
|
||||||
border-radius: 0.6rem;
|
|
||||||
background: linear-gradient(135deg, #efefef 0%, #cdcdcd 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-tips {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
text-align: center;
|
|
||||||
color: #585858;
|
|
||||||
line-height: 1.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-image-list-container {
|
|
||||||
margin-top: 3rem;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
margin-bottom: 1.2rem;
|
|
||||||
|
|
||||||
.main-title {
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-title {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-right {
|
|
||||||
color: #585858;
|
|
||||||
font-size: 1.4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-image-list {
|
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
column-gap: 0.8rem;
|
|
||||||
max-width: 80.2rem;
|
|
||||||
padding-bottom: 1.2rem;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
height: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background: #d9d9d9;
|
|
||||||
border-radius: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background: #000000;
|
|
||||||
border-radius: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-image-item {
|
|
||||||
width: 11.6rem;
|
|
||||||
height: 20.6rem;
|
|
||||||
border-radius: 1rem;
|
|
||||||
border: 0.15rem solid #c7c7c7;
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
overflow: hidden;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
content: "";
|
|
||||||
background-color: #fcfcfc;
|
|
||||||
opacity: 0.7;
|
|
||||||
border-radius: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
border-color: #000;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.checked {
|
|
||||||
width: 2rem;
|
|
||||||
height: 2rem;
|
|
||||||
position: absolute;
|
|
||||||
top: 0.8rem;
|
|
||||||
right: 0.8rem;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-src {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-pic {
|
|
||||||
position: absolute;
|
|
||||||
height: 2.4rem;
|
|
||||||
line-height: 2.4rem;
|
|
||||||
left: 0.8rem;
|
|
||||||
right: 0.8rem;
|
|
||||||
bottom: 0.8rem;
|
|
||||||
z-index: 1;
|
|
||||||
background: rgba(0, 0, 0, 0.8);
|
|
||||||
color: #fff;
|
|
||||||
font-size: 1.4rem;
|
|
||||||
border-radius: 1.2rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.apparel-container {
|
|
||||||
margin-top: 3rem;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
margin-bottom: 0.8rem;
|
|
||||||
|
|
||||||
.main-title {
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: bold;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: "*";
|
|
||||||
color: #df2b2c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-title {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sketch-list-container {
|
|
||||||
column-gap: 1rem;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
.sketch-element {
|
|
||||||
width: 10rem;
|
|
||||||
height: 14.6rem;
|
|
||||||
border: 0.15rem solid #c7c7c7;
|
|
||||||
border-radius: 1.2rem;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.img-src {
|
|
||||||
// height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.crop-tool {
|
|
||||||
position: absolute;
|
|
||||||
top: 0.4rem;
|
|
||||||
right: 0.4rem;
|
|
||||||
width: 2rem;
|
|
||||||
height: 2rem;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: #000000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
width: 55.2rem;
|
width: 55.2rem;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
.form-container {
|
|
||||||
row-gap: 3rem;
|
|
||||||
|
|
||||||
.form-item {
|
|
||||||
.form-item-label {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: bold;
|
|
||||||
margin-bottom: 0.6rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
|
|
||||||
&.with-tip {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
column-gap: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-text {
|
|
||||||
font-size: 1rem;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-item-value {
|
|
||||||
border: 0.16rem solid #d1d1d1;
|
|
||||||
border-radius: 1.2rem;
|
|
||||||
position: relative;
|
|
||||||
padding: 1.6rem;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: #000;
|
|
||||||
|
|
||||||
&.no-border {
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.price {
|
|
||||||
column-gap: 0.6rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ant-input),
|
|
||||||
:deep(.ant-input-affix-wrapper),
|
|
||||||
:deep(.ant-input-textarea textarea) {
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
color: #000;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ant-input) {
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ant-input-show-count-suffix) {
|
|
||||||
color: #df2c2c;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(textarea.ant-input) {
|
|
||||||
resize: none;
|
|
||||||
min-height: 5.4rem;
|
|
||||||
padding-bottom: 1.8rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ant-input-textarea-show-count) {
|
|
||||||
position: relative;
|
|
||||||
&::after {
|
|
||||||
float: none;
|
|
||||||
position: absolute;
|
|
||||||
color: #df2c2c;
|
|
||||||
bottom: 0;
|
|
||||||
right: 1.6rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.license-note {
|
|
||||||
padding: 1.6rem;
|
|
||||||
column-gap: 1.6rem;
|
|
||||||
background: #f7f7f7;
|
|
||||||
border-radius: 0.8rem;
|
|
||||||
|
|
||||||
.info-icon {
|
|
||||||
width: 2.4rem;
|
|
||||||
height: 2.4rem;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-copy {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #000;
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: medium;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #0080ed;
|
|
||||||
text-decoration: underline;
|
|
||||||
margin-left: 0.4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.page-control {
|
.page-control {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
margin-top: 4rem;
|
margin-top: 4rem;
|
||||||
|
|||||||
47
src/views/SellerDashboard/MyListings/EditDetail/types.ts
Normal file
47
src/views/SellerDashboard/MyListings/EditDetail/types.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
export type RadioOption = {
|
||||||
|
name: string | number
|
||||||
|
value: string | number | boolean
|
||||||
|
key: string
|
||||||
|
optype: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TopImageType = "sketch" | "mainProductImage" | "cover"
|
||||||
|
export type CropType = TopImageType | "apparel"
|
||||||
|
|
||||||
|
export type ListingItem = {
|
||||||
|
designItemId: number | string | null
|
||||||
|
sketch: string | null
|
||||||
|
mainProductImage: string
|
||||||
|
cover: string
|
||||||
|
productImage: string[]
|
||||||
|
apparelSketch: string[]
|
||||||
|
productName: string
|
||||||
|
price: string
|
||||||
|
desc: string
|
||||||
|
gender: string
|
||||||
|
category: string[] | null
|
||||||
|
prodImageList: Array<{
|
||||||
|
url: string
|
||||||
|
selected?: boolean
|
||||||
|
}>
|
||||||
|
sketchList: Array<{ url: string | null }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListingDetailImage = {
|
||||||
|
category?: string | null
|
||||||
|
imageUrl?: string | null
|
||||||
|
isSelected?: boolean | number | string | null
|
||||||
|
sortOrder?: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListingDetailResponse = {
|
||||||
|
id?: number | string | null
|
||||||
|
title?: string | null
|
||||||
|
description?: string | null
|
||||||
|
price?: number | string | null
|
||||||
|
designFor?: string | null
|
||||||
|
productCategory?: string | string[] | null
|
||||||
|
images?: ListingDetailImage[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StatusType = "draft" | "publish"
|
||||||
Reference in New Issue
Block a user