| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- <script setup lang="ts">
- import { storeToRefs } from 'pinia'
- import { useI18n } from 'vue-i18n'
- import type { PlaymateInfoVO } from '~/types/api'
- import { useFirstOrderDiscountStore } from '~/stores/firstOrderDiscount'
- import { useAuthStore } from '~/stores/auth'
- const props = withDefaults(
- defineProps<{
- show: boolean
- skills: PlaymateInfoVO['skills']
- activeSkillId: string
- quantity: number
- formattedTotalPrice: string | number
- /** When provided, display price uses first-order discount (exclude own products). */
- ownerUserNo?: string
- }>(),
- { ownerUserNo: undefined },
- )
- const emit = defineEmits<{
- 'update:show': [value: boolean]
- 'update:quantity': [value: number]
- 'select-skill': [skillId: string]
- 'order': []
- }>()
- const { t } = useI18n()
- const firstOrderDiscountStore = useFirstOrderDiscountStore()
- const { userProfile } = storeToRefs(useAuthStore())
- const displayPrice = (price: number) =>
- firstOrderDiscountStore.getDisplayPrice(price, props.ownerUserNo, userProfile.value?.userNo)
- const showDiscount = (price: number) =>
- firstOrderDiscountStore.isDiscountEligible(price, props.ownerUserNo, userProfile.value?.userNo)
- </script>
- <template>
- <van-popup
- :show="props.show"
- round
- position="bottom"
- class="pay-popup"
- @update:show="value => emit('update:show', value)"
- >
- <div class="pay-popup__container">
- <div class="pay-popup__skills">
- <article
- v-for="skill in props.skills"
- :key="skill.id"
- class="pay-popup-skill"
- :class="{ 'pay-popup-skill--active': skill.id === props.activeSkillId }"
- @click="emit('select-skill', skill.id)"
- >
- <div class="pay-popup-skill__info">
- <img
- v-if="skill.icon"
- class="pay-popup-skill__logo"
- :src="skill.icon"
- :alt="skill.name"
- >
- <div class="pay-popup-skill__texts">
- <p class="pay-popup-skill__name">
- {{ skill.name }}
- </p>
- </div>
- </div>
- <div class="pay-popup-skill__price">
- <span
- class="pay-popup-skill__amount"
- :class="{ 'text-[#FF6F32]': showDiscount(skill.price) }"
- >
- {{ displayPrice(skill.price) }}
- </span>
- <span class="pay-popup-skill__unit">
- /{{ skill.unit }}
- </span>
- <div
- v-if="showDiscount(skill.price)"
- class="discount-tip"
- >
- <span>{{ firstOrderDiscountStore.discountRatePercent }} OFF</span>
- </div>
- </div>
- </article>
- </div>
- <div class="pay-popup__quantity">
- <span class="pay-popup__quantity-label">
- {{ t('order.detail.quantity') }}
- </span>
- <CommonStepper
- :model-value="props.quantity"
- @update:model-value="(value: number) => emit('update:quantity', value)"
- />
- </div>
- <div class="pay-popup__footer">
- <CommonOrderBtn
- :price="props.formattedTotalPrice"
- @click="emit('order')"
- />
- </div>
- </div>
- </van-popup>
- </template>
- <style lang="scss" scoped>
- .pay-popup {
- &__container {
- height: 100%;
- display: flex;
- flex-direction: column;
- padding: 16px 16px 0;
- gap: 20px;
- }
- }
- .pay-popup__skills {
- max-height: 250px;
- overflow-y: auto;
- display: flex;
- flex-direction: column;
- gap: 8px;
- }
- .pay-popup-skill {
- height: 52px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 10px 14px;
- border-radius: 12px;
- border: 1px solid #c9cdd4;
- background-color: #fff;
- cursor: pointer;
- transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
- &--active {
- border-color: #1789ff;
- background-color: #e6fffa;
- box-shadow: 0 0 0 1px rgba(23, 137, 255, 0.16);
- }
- &__info {
- display: flex;
- align-items: center;
- gap: 10px;
- }
- &__logo {
- @include size(32px);
- flex-shrink: 0;
- }
- &__texts {
- display: flex;
- flex-direction: column;
- gap: 2px;
- }
- &__name {
- font-family: var(--font-title);
- font-size: 14px;
- font-weight: 600;
- color: #1d2129;
- }
- &__price {
- display: flex;
- align-items: center;
- gap: 2px;
- font-size: 14px;
- font-weight: 600;
- color: #1d2129;
- position: relative;
- .discount-tip {
- display: flex;
- height: 20px;
- padding: 0 6px;
- border-radius: 4px;
- background: #FF6F32;
- justify-content: center;
- align-items: center;
- position: absolute;
- left: -65px;
- span {
- color: #FFF;
- font-size: 11px;
- font-weight: 400;
- line-height: 14px;
- }
- }
- }
- &__unit {
- font-size: 12px;
- font-weight: 400;
- color: var(--color-text-secondary);
- }
- }
- .pay-popup__quantity {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 4px;
- }
- .pay-popup__quantity-label {
- font-size: 16px;
- font-weight: 600;
- color: #1d2129;
- }
- .pay-popup__footer {
- margin-top: auto;
- }
- </style>
|