Compare commits
No commits in common. "main" and "v0.1.16" have entirely different histories.
13 changed files with 157 additions and 264 deletions
|
|
@ -15,26 +15,13 @@ export const useZeroPrices = () => {
|
||||||
await apiClient.delete('/merch/zeroprices', list)
|
await apiClient.delete('/merch/zeroprices', list)
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.log('Delete target zero prices error: ', error)
|
console.log('Delete zero prices error: ', error)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteZeroPricesPeriod = async (start, end) => {
|
|
||||||
const params = new URLSearchParams({ start, end }).toString()
|
|
||||||
const url = `/merch/zeroprices/period${params ? `?${params}` : ''}`
|
|
||||||
const response = await apiClient.delete(url)
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
return response
|
|
||||||
} else {
|
|
||||||
console.log('Delete period select zero prices error: ', response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getZeroPrices,
|
getZeroPrices,
|
||||||
deleteZeroPrices,
|
deleteZeroPrices,
|
||||||
deleteZeroPricesPeriod,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import {
|
||||||
} from 'chart.js'
|
} from 'chart.js'
|
||||||
import { Line } from 'vue-chartjs'
|
import { Line } from 'vue-chartjs'
|
||||||
import 'chartjs-adapter-date-fns'
|
import 'chartjs-adapter-date-fns'
|
||||||
import { originColors } from '@/services/colors.js'
|
|
||||||
|
|
||||||
ChartJS.register(
|
ChartJS.register(
|
||||||
Title,
|
Title,
|
||||||
|
|
@ -34,6 +33,11 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const originColors = {
|
||||||
|
surugaya: '#2d3081',
|
||||||
|
mandarake: '#924646',
|
||||||
|
}
|
||||||
|
|
||||||
const chartData = ref({
|
const chartData = ref({
|
||||||
datasets: [],
|
datasets: [],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ const message = useMessage()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
text: {
|
text: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
required: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ export const BASE_URL = 'https://api.nqws.ru/api/v2'
|
||||||
// export const BASE_URL = 'http://localhost:9090/api/v2'
|
// export const BASE_URL = 'http://localhost:9090/api/v2'
|
||||||
|
|
||||||
export const BASE_MANDARAKE_LINK = 'https://order.mandarake.co.jp/order/listPage/list?soldOut=1&keyword='
|
export const BASE_MANDARAKE_LINK = 'https://order.mandarake.co.jp/order/listPage/list?soldOut=1&keyword='
|
||||||
export const BASE_AMIAMI_LINK = 'https://slist.amiami.jp/top/search/list?s_cate_tag=1&submit_btn=&s_st_list_preorder_available=1&s_st_list_backorder_available=1&s_st_list_newitem_available=1&s_st_condition_flg=1&pagemax=60&s_keywords='
|
|
||||||
// export const IMAGE_STORAGE_URL = 'http://localhost:9280'
|
// export const IMAGE_STORAGE_URL = 'http://localhost:9280'
|
||||||
export const IMAGE_STORAGE_URL = 'https://images.nqws.ru'
|
export const IMAGE_STORAGE_URL = 'https://images.nqws.ru'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
export const originColors = {
|
|
||||||
surugaya: '#2d3081',
|
|
||||||
mandarake: '#924646',
|
|
||||||
amiami: '#F27024',
|
|
||||||
};
|
|
||||||
|
|
@ -33,7 +33,7 @@ const fetchPrices = async (days = 7) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchPrices()
|
fetchPrices(7)
|
||||||
})
|
})
|
||||||
|
|
||||||
function handleSelectDays(days) {
|
function handleSelectDays(days) {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,10 @@ import router from '@/router/index.js'
|
||||||
import PeriodSelector from '@/components/PeriodSelector.vue'
|
import PeriodSelector from '@/components/PeriodSelector.vue'
|
||||||
import ChartBlock from '@/components/ChartBlock.vue'
|
import ChartBlock from '@/components/ChartBlock.vue'
|
||||||
import { useChartsApi } from '@/api/charts.js'
|
import { useChartsApi } from '@/api/charts.js'
|
||||||
|
import EditLink from '@/views/DetailsView/EditLink.vue'
|
||||||
|
import CopyToClipboard from '@/components/CopyToClipboard.vue'
|
||||||
import DetailsViewImages from '@/views/DetailsView/DetailsViewImages.vue'
|
import DetailsViewImages from '@/views/DetailsView/DetailsViewImages.vue'
|
||||||
import AttachLabel from '@/views/DetailsView/AttachLabel.vue'
|
import AttachLabel from '@/views/DetailsView/AttachLabel.vue'
|
||||||
import OriginBlock from '@/views/DetailsView/OriginBlock.vue'
|
|
||||||
|
|
||||||
const { getMerchDetails, deleteMerch } = useMerchApi()
|
const { getMerchDetails, deleteMerch } = useMerchApi()
|
||||||
const { getDistinctPrices } = useChartsApi()
|
const { getDistinctPrices } = useChartsApi()
|
||||||
|
|
@ -19,6 +20,11 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const editing = ref({
|
||||||
|
surugaya: false,
|
||||||
|
mandarake: false,
|
||||||
|
})
|
||||||
|
|
||||||
const merchDetails = ref(null)
|
const merchDetails = ref(null)
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const error = ref(null)
|
const error = ref(null)
|
||||||
|
|
@ -29,7 +35,7 @@ const fetchMerch = async () => {
|
||||||
merchDetails.value = response.data
|
merchDetails.value = response.data
|
||||||
|
|
||||||
if (!response.status === 400) {
|
if (!response.status === 400) {
|
||||||
await router.push({ name: 'collection' })
|
router.push({ name: 'collection' })
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = err.message
|
error.value = err.message
|
||||||
|
|
@ -52,7 +58,7 @@ const confirmDelete = async () => {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
showModal.value = false
|
showModal.value = false
|
||||||
await router.push({ name: 'collection' })
|
router.push({ name: 'collection' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const prices = ref(null)
|
const prices = ref(null)
|
||||||
|
|
@ -66,7 +72,7 @@ const fetchPrices = async (days = 7) => {
|
||||||
const response = await getDistinctPrices(props.merch_uuid, days)
|
const response = await getDistinctPrices(props.merch_uuid, days)
|
||||||
|
|
||||||
if (response.status === 400) {
|
if (response.status === 400) {
|
||||||
await router.push({ name: 'collection' })
|
router.push({ name: 'collection' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,6 +84,11 @@ const fetchPrices = async (days = 7) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleLinkUpdate(origin, newLink) {
|
||||||
|
merchDetails.value[`origin_${origin}`].link = newLink
|
||||||
|
editing.value[origin] = false
|
||||||
|
}
|
||||||
|
|
||||||
function handleSelectDays(days) {
|
function handleSelectDays(days) {
|
||||||
fetchPrices(days)
|
fetchPrices(days)
|
||||||
}
|
}
|
||||||
|
|
@ -109,10 +120,75 @@ onMounted(() => {
|
||||||
<ChartBlock :charts-data="prices" />
|
<ChartBlock :charts-data="prices" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="item in merchDetails.origins" :key="item">
|
<!-- Surugaya -->
|
||||||
<OriginBlock :merch_details="merchDetails" :merch_data="item" />
|
<CopyToClipboard :text="merchDetails.origin_surugaya?.link">
|
||||||
|
<n-divider title-placement="left">Surugaya</n-divider>
|
||||||
|
</CopyToClipboard>
|
||||||
|
<div v-if="!editing.surugaya">
|
||||||
|
<template v-if="merchDetails.origin_surugaya?.link">
|
||||||
|
<a
|
||||||
|
:href="merchDetails.origin_surugaya.link"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
class="default-color"
|
||||||
|
>
|
||||||
|
{{ merchDetails.origin_surugaya.link }}
|
||||||
|
</a>
|
||||||
|
<n-button type="primary" style="margin-left: 8px" @click="editing.surugaya = true">
|
||||||
|
Edit link
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span class="default-color underline link-like-text" @click="editing.surugaya = true"
|
||||||
|
>Add link</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<EditLink
|
||||||
|
v-else
|
||||||
|
:merch-uuid="merch_uuid"
|
||||||
|
origin="surugaya"
|
||||||
|
:name="merchDetails.name"
|
||||||
|
:model-value="merchDetails.origin_surugaya?.link || ''"
|
||||||
|
@update:model-value="handleLinkUpdate('surugaya', $event)"
|
||||||
|
@cancel-edit="editing.surugaya = false"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Mandarake -->
|
||||||
|
<CopyToClipboard :text="merchDetails.origin_mandarake?.link">
|
||||||
|
<n-divider title-placement="left">Mandarake</n-divider>
|
||||||
|
</CopyToClipboard>
|
||||||
|
<div v-if="!editing.mandarake">
|
||||||
|
<template v-if="merchDetails.origin_mandarake?.link">
|
||||||
|
<a
|
||||||
|
:href="merchDetails.origin_mandarake.link"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
class="default-color"
|
||||||
|
>
|
||||||
|
{{ merchDetails.origin_mandarake.link }}
|
||||||
|
</a>
|
||||||
|
<n-button type="primary" style="margin-left: 8px" @click="editing.mandarake = true">
|
||||||
|
Edit link
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span class="default-color underline link-like-text" @click="editing.mandarake = true"
|
||||||
|
>Add link</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<EditLink
|
||||||
|
v-else
|
||||||
|
:merch-uuid="merch_uuid"
|
||||||
|
origin="mandarake"
|
||||||
|
:name="merchDetails.name"
|
||||||
|
:model-value="merchDetails.origin_mandarake?.link || ''"
|
||||||
|
@update:model-value="handleLinkUpdate('mandarake', $event)"
|
||||||
|
@cancel-edit="editing.mandarake = false"
|
||||||
|
/>
|
||||||
</n-card>
|
</n-card>
|
||||||
<div v-else>Not found</div>
|
<div v-else>Not found</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, nextTick } from 'vue'
|
import { ref, nextTick } from 'vue'
|
||||||
import { useMerchApi } from '@/api/merch.js'
|
import { useMerchApi } from '@/api/merch.js'
|
||||||
import { BASE_AMIAMI_LINK, BASE_MANDARAKE_LINK } from '@/main.js'
|
import { BASE_MANDARAKE_LINK } from '@/main.js'
|
||||||
|
|
||||||
const { updateMerch } = useMerchApi()
|
const { updateMerch } = useMerchApi()
|
||||||
|
|
||||||
|
|
@ -101,29 +101,18 @@ const cancel = () => {
|
||||||
emit('cancel-edit')
|
emit('cancel-edit')
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertMandarakeLink = () => {
|
const insertAutoCompletedLink = () => {
|
||||||
tempValue.value = BASE_MANDARAKE_LINK+props.name
|
tempValue.value = BASE_MANDARAKE_LINK+props.name
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertAmiamiLink = () => {
|
|
||||||
tempValue.value = BASE_AMIAMI_LINK+props.name
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="props.origin === 'mandarake'" class="button-container-center mb-10">
|
<div v-if="props.origin === 'mandarake'" class="button-container-center mb-10">
|
||||||
<n-button type="warning" class="center-button" @click="insertMandarakeLink"
|
<n-button type="warning" class="center-button" @click="insertAutoCompletedLink"
|
||||||
>Insert auto-completed link</n-button
|
>Insert auto-completed link</n-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="props.origin === 'amiami'" class="button-container-center mb-10">
|
|
||||||
<n-button type="warning" class="center-button" @click="insertAmiamiLink"
|
|
||||||
>Insert auto-completed link</n-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="editing-area">
|
<div class="editing-area">
|
||||||
<n-input
|
<n-input
|
||||||
v-model:value="tempValue"
|
v-model:value="tempValue"
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { computed, ref } from 'vue'
|
|
||||||
import CopyToClipboard from '@/components/CopyToClipboard.vue'
|
|
||||||
import EditLink from '@/views/DetailsView/EditLink.vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
merch_data: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
merch_details: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const editing = ref(false)
|
|
||||||
|
|
||||||
const formattedName = computed(() => {
|
|
||||||
const name = props.merch_data?.name
|
|
||||||
if (!name) return ''
|
|
||||||
return name.charAt(0).toUpperCase() + name.slice(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
function handleLinkUpdate(origin, newLink) {
|
|
||||||
props.merch_data.link = newLink
|
|
||||||
editing.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<CopyToClipboard :text="merch_data.link">
|
|
||||||
<n-divider title-placement="left">{{ formattedName }}</n-divider>
|
|
||||||
</CopyToClipboard>
|
|
||||||
<div v-if="!editing">
|
|
||||||
<template v-if="merch_data.link">
|
|
||||||
<a :href="merch_data.link" target="_blank" rel="noopener" class="default-color">
|
|
||||||
{{ merch_data.link }}
|
|
||||||
</a>
|
|
||||||
<n-button type="primary" style="margin-left: 8px" @click="editing = true">
|
|
||||||
Edit link
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<span class="default-color underline link-like-text" @click="editing = true"> Add link </span>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<EditLink
|
|
||||||
v-else
|
|
||||||
:merch-uuid="merch_details.merch_uuid"
|
|
||||||
:origin="merch_data.name"
|
|
||||||
:name="merch_details.name"
|
|
||||||
:model-value="merch_data.link"
|
|
||||||
@update:model-value="handleLinkUpdate(merch_data.name, $event)"
|
|
||||||
@cancel-edit="editing=false"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
|
@ -1,20 +1,69 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import ScrollToTopButton from '@/components/ScrollToTopButton.vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import TargetZeroesTab from '@/views/ZeroPricesView/TargetZeroesTab.vue'
|
import { useZeroPrices } from '@/api/zeroPrices.js'
|
||||||
import PeriodSelectTab from '@/views/ZeroPricesView/PeriodSelectTab.vue'
|
import ZeroPriceCard from '@/views/ZeroPricesView/ZeroPriceCard.vue'
|
||||||
|
import ZeroPricesToolbar from '@/views/ZeroPricesView/ZeroPricesToolbar.vue'
|
||||||
|
|
||||||
|
const { getZeroPrices } = useZeroPrices()
|
||||||
|
|
||||||
|
const zeroPrices = ref([])
|
||||||
|
const toDelete = ref([])
|
||||||
|
|
||||||
|
const handleToggle = ({ id, merch_uuid, checked }) => {
|
||||||
|
if (checked) {
|
||||||
|
toDelete.value.push({ id, merch_uuid });
|
||||||
|
} else {
|
||||||
|
toDelete.value = toDelete.value.filter(item => item.id !== id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelectAll = () => {
|
||||||
|
toDelete.value = zeroPrices.value.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
merch_uuid: item.merch_uuid
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchZeroPrices = async () => {
|
||||||
|
try {
|
||||||
|
const response = await getZeroPrices()
|
||||||
|
zeroPrices.value = Array.isArray(response.data) ? response.data : []
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleted = () => {
|
||||||
|
toDelete.value = []
|
||||||
|
fetchZeroPrices()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchZeroPrices()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-tabs type="line" animated>
|
<div v-if="zeroPrices.length === 0">
|
||||||
<n-tab-pane name="Target zeroes" tab="Target zeroes">
|
<n-h2 class="text-center">Zero prices</n-h2>
|
||||||
<TargetZeroesTab />
|
<n-h3 class="text-center">No data</n-h3>
|
||||||
</n-tab-pane>
|
</div>
|
||||||
<n-tab-pane name="Period select" tab="Period select">
|
<div v-else>
|
||||||
<PeriodSelectTab />
|
<div class="sticky-search-container">
|
||||||
</n-tab-pane>
|
<ZeroPricesToolbar
|
||||||
</n-tabs>
|
:selected="toDelete"
|
||||||
<ScrollToTopButton />
|
@deleted="handleDeleted"
|
||||||
|
@selectAll="handleSelectAll"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-for="item in zeroPrices" :key="item.created_at">
|
||||||
|
<ZeroPriceCard
|
||||||
|
:zero-price="item"
|
||||||
|
@toggle="handleToggle"
|
||||||
|
:checked="toDelete.some(t => t.id === item.id)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { ref, onMounted, computed } from 'vue'
|
|
||||||
import { useZeroPrices } from '@/api/zeroPrices.js'
|
|
||||||
|
|
||||||
const range = ref(null)
|
|
||||||
|
|
||||||
const setTodayRange = () => {
|
|
||||||
const now = new Date()
|
|
||||||
const start = new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
|
||||||
const end = new Date(start.getTime() + 24 * 60 * 60 * 1000)
|
|
||||||
|
|
||||||
range.value = [start.getTime(), end.getTime()]
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
setTodayRange()
|
|
||||||
})
|
|
||||||
|
|
||||||
const toRFCtime = (timestamp) => {
|
|
||||||
return new Date(timestamp).toISOString()
|
|
||||||
}
|
|
||||||
|
|
||||||
const { deleteZeroPricesPeriod } = useZeroPrices()
|
|
||||||
|
|
||||||
const deleteEnabled = computed(() => {
|
|
||||||
return range.value === null
|
|
||||||
})
|
|
||||||
|
|
||||||
const deletePeriod = async () => {
|
|
||||||
if (range.value !== null) {
|
|
||||||
const start = toRFCtime(range.value[0])
|
|
||||||
const end = toRFCtime(range.value[1])
|
|
||||||
await deleteZeroPricesPeriod(start, end)
|
|
||||||
} else {
|
|
||||||
console.log('Delete period select zero prices error')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<n-date-picker
|
|
||||||
v-model:value="range"
|
|
||||||
type="datetimerange"
|
|
||||||
format="HH:mm:ss dd-MM-yyyy"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
<div class="button-container-center">
|
|
||||||
<n-button class="center-button w360" type="error" :disabled="deleteEnabled" @click="deletePeriod">Delete</n-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { onMounted, ref } from 'vue'
|
|
||||||
import { useZeroPrices } from '@/api/zeroPrices.js'
|
|
||||||
import ZeroPriceCard from '@/views/ZeroPricesView/ZeroPriceCard.vue'
|
|
||||||
import ZeroPricesToolbar from '@/views/ZeroPricesView/ZeroPricesToolbar.vue'
|
|
||||||
|
|
||||||
const { getZeroPrices } = useZeroPrices()
|
|
||||||
|
|
||||||
const zeroPrices = ref([])
|
|
||||||
const toDelete = ref([])
|
|
||||||
|
|
||||||
const handleToggle = ({ id, merch_uuid, checked }) => {
|
|
||||||
if (checked) {
|
|
||||||
toDelete.value.push({ id, merch_uuid });
|
|
||||||
} else {
|
|
||||||
toDelete.value = toDelete.value.filter(item => item.id !== id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSelectAll = () => {
|
|
||||||
toDelete.value = zeroPrices.value.map(item => ({
|
|
||||||
id: item.id,
|
|
||||||
merch_uuid: item.merch_uuid
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchZeroPrices = async () => {
|
|
||||||
try {
|
|
||||||
const response = await getZeroPrices()
|
|
||||||
zeroPrices.value = Array.isArray(response.data) ? response.data : []
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDeleted = () => {
|
|
||||||
toDelete.value = []
|
|
||||||
fetchZeroPrices()
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
fetchZeroPrices()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div v-if="zeroPrices.length === 0">
|
|
||||||
<n-h2 class="text-center">Zero prices</n-h2>
|
|
||||||
<n-h3 class="text-center">No data</n-h3>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<div class="sticky-search-container">
|
|
||||||
<ZeroPricesToolbar
|
|
||||||
:selected="toDelete"
|
|
||||||
@deleted="handleDeleted"
|
|
||||||
@selectAll="handleSelectAll"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div v-for="item in zeroPrices" :key="item.created_at">
|
|
||||||
<ZeroPriceCard
|
|
||||||
:zero-price="item"
|
|
||||||
@toggle="handleToggle"
|
|
||||||
:checked="toDelete.some(t => t.id === item.id)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
|
||||||
import { originColors } from '@/services/colors.js'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
zeroPrice: {
|
zeroPrice: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|
@ -22,10 +19,6 @@ const handleCheckboxChange = (newValue) => {
|
||||||
checked: newValue,
|
checked: newValue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentOriginColor = computed(() => {
|
|
||||||
return originColors[props.zeroPrice.origin] || '#fff';
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -38,12 +31,7 @@ const currentOriginColor = computed(() => {
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-gi><strong>Name:</strong> {{ props.zeroPrice.name }}</n-gi>
|
<n-gi><strong>Name:</strong> {{ props.zeroPrice.name }}</n-gi>
|
||||||
<n-gi><strong>Created:</strong> {{ props.zeroPrice.created_at }}</n-gi>
|
<n-gi><strong>Created:</strong> {{ props.zeroPrice.created_at }}</n-gi>
|
||||||
<n-gi
|
<n-gi><strong>Origin:</strong> {{ props.zeroPrice.origin }}</n-gi>
|
||||||
><strong>Origin:</strong>
|
|
||||||
<span class="bordered" :style="{ borderColor: currentOriginColor }">
|
|
||||||
{{ props.zeroPrice.origin }}
|
|
||||||
</span>
|
|
||||||
</n-gi>
|
|
||||||
</n-grid>
|
</n-grid>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -61,11 +49,4 @@ const currentOriginColor = computed(() => {
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
border: 1px solid #e0e0e0;
|
border: 1px solid #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bordered {
|
|
||||||
border: 1px solid;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
margin: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue