Files
nuxt-claude/app/components/purchases/SellFromPurchaseModal.vue
hyeonggil 6784786262 feat: 구매 관리에 엑셀 업로드 및 중고 판매 등록 기능 추가
- usePurchases: user_id 필터링으로 타 사용자 데이터 접근 차단
- usePurchases: bulkCreatePurchases() 일괄 저장 메서드 추가
- PurchaseModal: submit 시 중복 닫힘 방지 (부모에서 제어)
- purchases/index: 엑셀 업로드 버튼 및 모달 연동
- purchases/index: 중고 판매 등록(태그 아이콘) 버튼 및 모달 연동
- purchases/index: 판매 상태 뱃지를 장비명 옆에 표시
- PurchaseExcelUpload: xlsx 파일 파싱 후 일괄 저장 컴포넌트 추가
- SellFromPurchaseModal: 구매 장비에서 중고 판매 등록 모달 추가
- xlsx 패키지 추가
2026-03-08 21:25:29 +09:00

105 lines
3.3 KiB
Vue

<script setup lang="ts">
import { z } from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'
import { PLATFORM_OPTIONS } from '~/types/used-sale'
import type { SalePlatform } from '~/types/used-sale'
import type { Purchase } from '~/types/purchase'
const props = defineProps<{
open: boolean
purchase: Purchase | null
}>()
const emit = defineEmits<{
'update:open': [value: boolean]
done: []
}>()
const { createSale, loading, error: saleError } = useUsedSales()
const schema = z.object({
item_name: z.string().min(1, '장비명을 입력하세요'),
sale_price: z.number().min(0, '희망가격을 입력하세요'),
platform: z.string().min(1, '판매 플랫폼을 선택하세요')
})
type Schema = z.output<typeof schema>
const state = reactive({
item_name: '',
sale_price: 0,
platform: undefined as SalePlatform | undefined
})
// 선택된 구매 장비로 폼 초기화
watch(() => props.purchase, (p) => {
if (p) {
state.item_name = p.name
state.sale_price = p.price
state.platform = undefined
}
}, { immediate: true })
async function onSubmit(event: FormSubmitEvent<Schema>) {
if (!props.purchase) return
await createSale({
item_name: event.data.item_name,
sale_price: event.data.sale_price,
platform: event.data.platform as SalePlatform,
status: 'listing',
listed_at: new Date().toISOString().split('T')[0] ?? '',
purchase_id: props.purchase.id
})
if (!saleError.value) {
emit('update:open', false)
emit('done')
}
}
</script>
<template>
<UModal
:open="props.open"
title="중고 판매 등록"
@update:open="emit('update:open', $event)"
>
<template #body>
<div v-if="purchase" class="space-y-4">
<!-- 연결된 구매 장비 안내 -->
<div class="flex items-center gap-2 p-3 bg-gray-50 dark:bg-gray-800 rounded-lg text-sm text-gray-600 dark:text-gray-400">
<UIcon name="i-lucide-link" class="shrink-0 text-primary-500" />
<span>구매 장비 <strong class="text-gray-900 dark:text-white">{{ purchase.name }}</strong> 연결됩니다</span>
</div>
<UAlert v-if="saleError" color="error" :description="saleError" />
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormField label="장비명" name="item_name" required>
<UInput v-model="state.item_name" class="w-full" />
</UFormField>
<div class="grid grid-cols-2 gap-4">
<UFormField label="희망가격 (원)" name="sale_price" required>
<UInput v-model.number="state.sale_price" type="number" min="0" class="w-full" />
</UFormField>
<UFormField label="판매 플랫폼" name="platform" required>
<USelect v-model="state.platform" :items="PLATFORM_OPTIONS" placeholder="선택..." class="w-full" />
</UFormField>
</div>
<div class="flex justify-end gap-3 pt-2">
<UButton label="취소" color="neutral" variant="ghost" @click="emit('update:open', false)" />
<UButton
type="submit"
label="중고 등록"
icon="i-lucide-tag"
:loading="loading"
/>
</div>
</UForm>
</div>
</template>
</UModal>
</template>