Compare commits
11 Commits
d8b880cf47
...
8b144a270c
Author | SHA1 | Date | |
---|---|---|---|
|
8b144a270c | ||
|
f80f9c1651 | ||
|
e541d0b21d | ||
|
3b8bd623c0 | ||
|
fb8a72b47a | ||
|
a423a7f801 | ||
|
e6fdd0354a | ||
|
3225d91ecb | ||
|
a36a98c576 | ||
|
d3cb4d55b4 | ||
|
331b4a73b2 |
@ -29,4 +29,4 @@ export async function userArtworks(data) {
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import {message} from '@/components/x-message/useMessage.js'
|
||||
// message.success('success')
|
||||
|
||||
useHead({
|
||||
title: useI18n().t('appSetting.appName'),
|
||||
meta: [
|
||||
@ -9,9 +8,8 @@ useHead({
|
||||
{ name: 'keywords', content: useI18n().t('appSetting.appKeyWords') },
|
||||
],
|
||||
})
|
||||
const color = useColorMode()
|
||||
const mode = computed(() => {
|
||||
return color.value
|
||||
return ''
|
||||
})
|
||||
|
||||
// 添加路由中间件来处理过渡方向
|
||||
@ -42,7 +40,7 @@ provide('slideDirection', slideDirection)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VanConfigProvider :theme="mode">
|
||||
<VanConfigProvider theme="light">
|
||||
<NuxtLoadingIndicator
|
||||
color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)" />
|
||||
<NuxtLayout>
|
||||
|
@ -1,9 +1,8 @@
|
||||
<script setup>
|
||||
import { useAppFooterRouteNames as names } from '~/config/index.js'
|
||||
import MyIcon from "~/components/icons/MyIcon.vue";
|
||||
import HomeIcon from "~/components/icons/HomeIcon.vue";
|
||||
import { useAppFooterRouteNames as names } from '@/config/index.js'
|
||||
import MyIcon from "@/components/icons/MyIcon.vue";
|
||||
import HomeIcon from "@/components/icons/HomeIcon.vue";
|
||||
const route = useRoute()
|
||||
|
||||
const active = ref(0)
|
||||
const show = computed(() => {
|
||||
if (route.name && names.includes(route.name))
|
||||
@ -13,7 +12,6 @@ const show = computed(() => {
|
||||
const initData=()=>{
|
||||
active.value=route.path==='/profile'?1:0
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
initData()
|
||||
})
|
||||
@ -21,7 +19,6 @@ onMounted(()=>{
|
||||
|
||||
<template>
|
||||
<div v-if="show">
|
||||
|
||||
<van-tabbar v-model="active" route placeholder fixed>
|
||||
<van-tabbar-item replace to="/">
|
||||
<span>{{ $t('tabbar.home') }}</span>
|
||||
|
@ -1,5 +1,13 @@
|
||||
<script setup>
|
||||
import { ImagePreview } from 'vant';
|
||||
import { showImagePreview } from 'vant';
|
||||
|
||||
import xImage from '@/components/x-image/index.vue'
|
||||
const props = defineProps({
|
||||
detailInfo: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
const images = [
|
||||
'https://e-cdn.fontree.cn/fonchain-main/prod/file/default/setting/637d95b4-2ae9-4a74-bd60-a3a9d2ca2ca0.png',
|
||||
'https://e-cdn.fontree.cn/fonchain-main/prod/file/default/setting/f7b65e23-ce21-41b4-8e58-9e6dc6950727.png',
|
||||
@ -15,7 +23,10 @@ const clickSwipe=(index)=>{
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<van-swipe style="height: 188px" indicator-color="#B4B4B4" lazy-render >
|
||||
<div class="flex justify-center">
|
||||
<xImage class="h-188px" :src="detailInfo?.artwork?.hdPic"></xImage>
|
||||
</div>
|
||||
<!-- <van-swipe style="height: 188px" indicator-color="#B4B4B4" lazy-render >
|
||||
<van-swipe-item v-for="(image,index) in images" :key="image" @click="clickSwipe(index)">
|
||||
<van-image
|
||||
fit="contain"
|
||||
@ -24,25 +35,25 @@ const clickSwipe=(index)=>{
|
||||
:src="image"
|
||||
/>
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
</van-swipe>-->
|
||||
<div class="px-[16px] bg-[#fff] pt-[11px] mb-6px">
|
||||
<div class="text-[#000] text-[16px] mb-[12px]">日出而作,日落而息</div>
|
||||
<div class="text-[#000] text-[16px] mb-[12px]">{{detailInfo?.artworkTitle}}</div>
|
||||
<div class="text-#575757 text-[14px] pb-8px">
|
||||
<div class="flex mb-[4px]">
|
||||
<div class="w-[70px]">作者:</div>
|
||||
<div>张天赐</div>
|
||||
<div>{{detailInfo?.artwork?.artistName??'-'}}</div>
|
||||
</div>
|
||||
<div class="flex mb-[4px]">
|
||||
<div class="w-[70px] flex-shrink-0">总平尺数:</div>
|
||||
<div>—</div>
|
||||
<div>{{detailInfo?.artwork?.ruler??'-'}}</div>
|
||||
</div>
|
||||
<div class="flex mb-[4px]">
|
||||
<div class="w-[70px] flex-shrink-0">长*宽:</div>
|
||||
<div>100*200cm</div>
|
||||
<div>{{detailInfo?.artwork?.length}}*{{detailInfo?.artwork?.width}}cm</div>
|
||||
</div>
|
||||
<div class="flex mb-[4px]">
|
||||
<div class="w-[70px] flex-shrink-0">画作简介:</div>
|
||||
<div>是打卡时间到卡上即可点击卡拉斯科健康就阿斯科利打卡时间到卡萨带手机的啊科技是打卡时</div>
|
||||
<div>{{detailInfo?.artwork?.abstract??'-'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,7 @@
|
||||
<script setup>
|
||||
/*
|
||||
* 此组件的目的是使用该组件包裹的内容具有按压状态效果
|
||||
* */
|
||||
import {ref, defineEmits} from "vue";
|
||||
|
||||
const emit = defineEmits(["click"]);
|
56
app/components/x-image/index.vue
Normal file
56
app/components/x-image/index.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<script setup>
|
||||
import { showImagePreview } from 'vant';
|
||||
import { NuxtImg } from '#components'
|
||||
const props = defineProps({
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
preview: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 用于控制图片尺寸
|
||||
sizes: {
|
||||
type: Array,
|
||||
default: () => [320, 640, 768, 1024]
|
||||
},
|
||||
// 用于控制图片格式
|
||||
format: {
|
||||
type: String,
|
||||
default: 'webp'
|
||||
},
|
||||
// 用于控制图片质量
|
||||
quality: {
|
||||
type: Number,
|
||||
default: 80
|
||||
}
|
||||
})
|
||||
|
||||
const showImage = () => {
|
||||
if (props.preview) {
|
||||
showImagePreview([props.src]);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nuxt-img
|
||||
loading="lazy"
|
||||
v-bind="{ ...props, ...$attrs }"
|
||||
style="object-fit: cover"
|
||||
@click="showImage"
|
||||
:src="src"
|
||||
:sizes="sizes"
|
||||
:format="format"
|
||||
:quality="quality"
|
||||
placeholder
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(img) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@ -1,4 +1,7 @@
|
||||
<script setup>
|
||||
/*
|
||||
* 封装一个带标题栏的弹窗
|
||||
* */
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
@ -15,27 +18,32 @@ const close=()=>{
|
||||
<template>
|
||||
<van-popup
|
||||
:show="show"
|
||||
teleport="#__nuxt"
|
||||
position="bottom"
|
||||
:style="{ height: '74%' }"
|
||||
v-bind="{...$attrs,...$props}"
|
||||
@close="close"
|
||||
>
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- 固定的标题栏 -->
|
||||
<div class="flex items-center pl-16px pr-19px h-40px border-b-1px border-b-[#D3D3D3] shrink-0">
|
||||
<template v-if="$slots.title">
|
||||
<slot name="title"></slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="text-#000 text-16px">{{title}}</div>
|
||||
</template>
|
||||
<div class="ml-auto flex items-center">
|
||||
<van-icon size="20" name="cross" color="#939393" @click="close"/>
|
||||
</div>
|
||||
<!-- 标题栏 -->
|
||||
<div class="flex items-center pl-16px pr-19px h-40px border-b-1px border-gray-300 shrink-0 relative w-full">
|
||||
<slot v-if="$slots.title" name="title">
|
||||
</slot>
|
||||
<div v-else class="text-black text-16px text-center flex-grow-1">{{ title }}</div>
|
||||
<van-icon
|
||||
style="position: absolute"
|
||||
class="right-19px"
|
||||
size="20"
|
||||
name="cross"
|
||||
color="#939393"
|
||||
@click="close"
|
||||
/>
|
||||
</div>
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<div class="flex-1 overflow-y-auto ">
|
||||
<slot/>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="flex-1 px-16px py-18px overflow-hidden relative">
|
||||
<div class="h-full overflow-y-auto relative">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
@ -1,114 +0,0 @@
|
||||
<script setup>
|
||||
import xPopup from '@/components/x-popup/index.vue'
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<x-popup :show="show">
|
||||
<template #title>
|
||||
<div class="text-#000 text-16px">拍品列表</div>
|
||||
<div class="text-#939393 text-16px ml-14px">共188个拍品</div>
|
||||
</template>
|
||||
<div class="px-16px py-18px">
|
||||
<div class="flex mb-21px">
|
||||
<div class="mr-10px flex-shrink-0 rounded-4px overflow-hidden">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||
张天赐 | 日出而作,日落而息撒打算撒打算撒打决赛多久啊是世奥兰日落而息撒打算撒打算撒打决赛多久啊是世奥兰
|
||||
</div>
|
||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-21px">
|
||||
<div class="mr-10px flex-shrink-0 rounded-4px overflow-hidden">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||
张天赐 | 日出而作,日落而息撒打算撒打算撒打决赛多久啊是世奥兰日落而息撒打算撒打算撒打决赛多久啊是世奥兰
|
||||
</div>
|
||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-21px">
|
||||
<div class="mr-10px flex-shrink-0 rounded-4px overflow-hidden">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||
张天赐 | 日出而作
|
||||
</div>
|
||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-21px">
|
||||
<div class="mr-10px flex-shrink-0 rounded-4px overflow-hidden">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||
张天赐 | 日出而作
|
||||
</div>
|
||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-21px">
|
||||
<div class="mr-10px flex-shrink-0 rounded-4px overflow-hidden">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||
张天赐 | 日出而作
|
||||
</div>
|
||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-21px">
|
||||
<div class="mr-10px flex-shrink-0 rounded-4px overflow-hidden">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||
张天赐 | 日出而作
|
||||
</div>
|
||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex mb-21px">
|
||||
<div class="mr-10px flex-shrink-0 rounded-4px overflow-hidden">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||
张天赐 | 日出而作
|
||||
</div>
|
||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-popup>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,53 +0,0 @@
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
items: Array,
|
||||
colIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['openShow']);
|
||||
|
||||
const openShow = (item,index) => {
|
||||
emit('openShow', item,index);
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex flex-1 flex-col gap-[16px]">
|
||||
<div
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
class="w-full"
|
||||
@click="openShow(item,index)"
|
||||
>
|
||||
<div class="relative w-full">
|
||||
<img
|
||||
:src="item.artwork?.hdPic"
|
||||
class="w-full object-cover rounded-4px"
|
||||
|
||||
/>
|
||||
<div
|
||||
class="absolute left-[8px] top-[8px] h-[17px] w-[45px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]"
|
||||
>
|
||||
LOT{{ item.index+1 }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-[8px]">
|
||||
<div class="text-[14px] text-[#000000] leading-[20px]">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div class="mt-[4px] text-[12px] text-[#575757]">
|
||||
起拍价:{{ item?.startPrice??0 }}
|
||||
</div>
|
||||
<div
|
||||
v-if="item.soldPrice"
|
||||
class="mt-[4px] text-[12px] text-[#b58047]"
|
||||
>
|
||||
成交价:{{ item?.startPrice??0 }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
24
app/pages/home/components/DetailPopup/index.vue
Normal file
24
app/pages/home/components/DetailPopup/index.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<script setup>
|
||||
import xPopup from '@/components/x-popup/index.vue'
|
||||
import ItemDetail from "@/components/itemDetail/index.vue";
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
const {
|
||||
artWorkDetail
|
||||
} = goodStore()
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:show'])
|
||||
const handleClose = () => {
|
||||
emit('update:show', false)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<xPopup :show="show" title="拍品详情" @update:show="handleClose">
|
||||
<ItemDetail :detailInfo="artWorkDetail" />
|
||||
</xPopup>
|
||||
</template>
|
@ -1,96 +0,0 @@
|
||||
<template>
|
||||
<van-popup
|
||||
v-model:show="props.show"
|
||||
position="bottom"
|
||||
:style="{ height: props.height }"
|
||||
round
|
||||
closeable
|
||||
@closed="handleClose"
|
||||
>
|
||||
<div class="p-[16px] overflow-y-auto h-full">
|
||||
<!-- 商品基本信息 -->
|
||||
<div class="flex flex-col gap-[12px]">
|
||||
<img
|
||||
:src="props.detail?.artwork?.hdPic"
|
||||
class="w-full rounded-[4px] object-cover"
|
||||
:alt="props.detail?.name"
|
||||
/>
|
||||
<div class="text-[16px] font-medium text-[#000]">
|
||||
{{ props.detail?.name }}
|
||||
</div>
|
||||
|
||||
<!-- 价格信息 -->
|
||||
<div class="flex flex-col gap-[8px]">
|
||||
<div class="text-[14px] text-[#575757]">
|
||||
起拍价:{{ formatPrice(props.detail?.startPrice) }}
|
||||
</div>
|
||||
<div v-if="props.detail?.soldPrice" class="text-[14px] text-[#b58047]">
|
||||
成交价:{{ formatPrice(props.detail?.soldPrice) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 商品详情 -->
|
||||
<div class="mt-[16px]">
|
||||
<div class="text-[16px] font-medium mb-[12px]">商品详情</div>
|
||||
<div class="flex flex-col gap-[8px]">
|
||||
<div class="flex justify-between text-[14px]">
|
||||
<span class="text-[#575757]">尺寸</span>
|
||||
<span>{{ props.detail?.artwork?.size || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-[14px]">
|
||||
<span class="text-[#575757]">年代</span>
|
||||
<span>{{ props.detail?.artwork?.year || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-[14px]">
|
||||
<span class="text-[#575757]">材质</span>
|
||||
<span>{{ props.detail?.artwork?.material || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 作品描述 -->
|
||||
<div v-if="props.detail?.artwork?.description" class="mt-[16px]">
|
||||
<div class="text-[16px] font-medium mb-[12px]">作品描述</div>
|
||||
<div class="text-[14px] text-[#575757] whitespace-pre-wrap">
|
||||
{{ props.detail?.artwork?.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { formatPrice } from '~/utils/format'
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '90vh'
|
||||
},
|
||||
detail: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:show'])
|
||||
|
||||
const handleClose = () => {
|
||||
emit('update:show', false)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.van-popup) {
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
:deep(.van-popup__close-icon) {
|
||||
color: #000;
|
||||
}
|
||||
</style>
|
@ -2,9 +2,8 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRect } from "@vant/use"
|
||||
import { goodStore } from "@/stores/goods"
|
||||
import Column from "../Column/index.vue"
|
||||
import ItemDetail from "@/components/itemDetail/index.vue"
|
||||
|
||||
import DetailPopup from '../DetailPopup/index.vue'
|
||||
import MasonryWall from '@yeger/vue-masonry-wall'
|
||||
const {
|
||||
itemList,
|
||||
pageRef,
|
||||
@ -23,16 +22,6 @@ const localState = ref({
|
||||
showDetail: false,
|
||||
showHeight: ''
|
||||
})
|
||||
|
||||
// 计算列数据
|
||||
const columns = computed(() => {
|
||||
const result = [[], []]
|
||||
itemList.value.forEach((item, index) => {
|
||||
result[index % 2].push({ ...item, index })
|
||||
})
|
||||
return result
|
||||
})
|
||||
|
||||
// 加载更多
|
||||
const loadMore = async () => {
|
||||
pageRef.value.page++
|
||||
@ -51,18 +40,11 @@ const onRefresh = async () => {
|
||||
localState.value.refreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
// 打开详情
|
||||
const openShow = async (item) => {
|
||||
localState.value.showDetail = true
|
||||
currentItem.value = item
|
||||
await getArtworkDetail(item.uuid)
|
||||
|
||||
const rect = useRect(liveRef.value.$el)
|
||||
localState.value.showHeight = rect.height
|
||||
|
||||
nextTick(() => {
|
||||
localState.value.showDetail = true
|
||||
})
|
||||
getArtworkDetail(item.uuid)
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -71,8 +53,12 @@ const openShow = async (item) => {
|
||||
<van-pull-refresh
|
||||
v-model="localState.refreshing"
|
||||
success-text="刷新成功"
|
||||
:success-duration="700"
|
||||
@refresh="onRefresh"
|
||||
>
|
||||
<template #success>
|
||||
<van-icon name="success" /> 刷新成功
|
||||
</template>
|
||||
<van-list
|
||||
v-model:loading="storeLoading"
|
||||
:finished="localState.finished"
|
||||
@ -80,30 +66,45 @@ const openShow = async (item) => {
|
||||
@load="loadMore"
|
||||
>
|
||||
<div class="w-full flex gap-[16px]">
|
||||
<Column
|
||||
v-for="(column, colIndex) in columns"
|
||||
:key="colIndex"
|
||||
:colIndex="colIndex"
|
||||
:items="column"
|
||||
@openShow="openShow"
|
||||
/>
|
||||
<masonry-wall :items="itemList" :ssr-columns="2" :maxColumns="2" :minColumns="2" :gap="5">
|
||||
<template #default="{ item, index }">
|
||||
<div
|
||||
@click="openShow(item)"
|
||||
class="w-full"
|
||||
>
|
||||
<div class="relative w-full">
|
||||
<img
|
||||
:src="item.artwork?.hdPic"
|
||||
class="w-full object-cover rounded-4px"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div
|
||||
class="absolute rounded-2px overflow-hidden line-height-12px left-[8px] top-[8px] h-[17px] w-[45px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]"
|
||||
>
|
||||
LOT{{ index+1 }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-[8px]">
|
||||
<div class="text-[14px] text-[#000000] leading-[20px]">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div class="mt-[4px] text-[12px] text-[#575757]">
|
||||
起拍价:{{ item?.startPrice??0 }}
|
||||
</div>
|
||||
<div
|
||||
v-if="item.soldPrice"
|
||||
class="mt-[4px] text-[12px] text-[#b58047]"
|
||||
>
|
||||
成交价:{{ item?.startPrice??0 }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</masonry-wall>
|
||||
</div>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
|
||||
<van-action-sheet
|
||||
teleport="#__nuxt"
|
||||
:round="false"
|
||||
v-model:show="localState.showDetail"
|
||||
title="拍品详情"
|
||||
>
|
||||
<div
|
||||
class="content bg-[#F0F0F0]"
|
||||
:style="`height: calc(100vh - ${localState.showHeight + 85}px)`"
|
||||
>
|
||||
<ItemDetail />
|
||||
</div>
|
||||
</van-action-sheet>
|
||||
<DetailPopup v-model:show="localState.showDetail"></DetailPopup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import LiveRoom from '@/pages/LiveRoom/index.client.vue';
|
||||
import liveRoom from '@/pages/liveRoom/index.client.vue';
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import ItemList from './components/ItemList/index.vue'
|
||||
import Cescribe from './components/Cescribe/index.vue'
|
||||
@ -10,19 +10,19 @@ import {ref} from "vue";
|
||||
const {fullLive, getAuctionDetail, auctionDetail, itemList, pageRef, liveRef} = goodStore();
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
title: '主页',
|
||||
i18n: 'menu.home',
|
||||
})
|
||||
const changeLive = () => {
|
||||
fullLive.value = true;
|
||||
};
|
||||
const showBottom = ref(true)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-grow-1">
|
||||
|
||||
<client-only>
|
||||
<LiveRoom @click="changeLive" :class="['changeLive', fullLive ? 'expanded' : 'collapsed']" ref="liveRef"
|
||||
<liveRoom @click="changeLive" :class="['changeLive', fullLive ? 'expanded' : 'collapsed']" ref="liveRef"
|
||||
:fullLive="fullLive"/>
|
||||
</client-only>
|
||||
<div v-show="!fullLive" class="bg-#fff">
|
||||
@ -72,7 +72,7 @@ const showBottom = ref(true)
|
||||
.changeLive {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
transition: height 0.5s ease, transform 0.5s ease;
|
||||
transition: height 0.4s ease, transform 0.4s ease;
|
||||
}
|
||||
|
||||
.changeLive.collapsed {
|
||||
|
7
app/pages/index.vue
Normal file
7
app/pages/index.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<script setup>
|
||||
import Home from './home/index.vue'
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<Home/>
|
||||
</template>
|
@ -1,24 +1,31 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import lockClosed from "~/static/images/lockdfd@2x.png";
|
||||
import lockOpen from "~/static/images/lock4@2x.png";
|
||||
import { liveStore } from "~/stores/live/index.js";
|
||||
import PressableButton from './PressableButton.vue'
|
||||
const { quoteStatus, changeStatus,show,show1 } = liveStore();
|
||||
|
||||
import lockClosed from "@/static/images/lockdfd@2x.png";
|
||||
import lockOpen from "@/static/images/lock4@2x.png";
|
||||
import { liveStore } from "@/stores/live/index.js";
|
||||
import xButton from '@/components/x-button/index.vue'
|
||||
import tangPopup from './tangPopup.vue'
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
const { quoteStatus, changeStatus,show } = liveStore();
|
||||
const {pageRef} = goodStore();
|
||||
const showTang=ref(false)
|
||||
const openOne=()=>{
|
||||
showTang.value=true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-white w-60px rounded-l-4px overflow-hidden">
|
||||
<!-- 拍品信息 -->
|
||||
<PressableButton>
|
||||
<x-button @click="openOne">
|
||||
<div class="w-60px h-60px text-center border-b border-gray-300 flex flex-col justify-center items-center text-#7D7D7F text-12px">
|
||||
<div>拍品</div>
|
||||
<div>(1/188)</div>
|
||||
<div>(1/{{pageRef.itemCount??0}})</div>
|
||||
</div>
|
||||
</PressableButton>
|
||||
</x-button>
|
||||
<tangPopup v-model:show="showTang"></tangPopup>
|
||||
<!-- 出价开关 -->
|
||||
<PressableButton @click="changeStatus">
|
||||
<x-button @click="changeStatus">
|
||||
<div class="w-60px h-60px text-center border-b border-gray-300 flex flex-col justify-center items-center">
|
||||
<div class="mb-1">
|
||||
<img
|
||||
@ -31,15 +38,15 @@ const { quoteStatus, changeStatus,show,show1 } = liveStore();
|
||||
{{ quoteStatus ? '关闭出价' : '开启出价' }}
|
||||
</div>
|
||||
</div>
|
||||
</PressableButton>
|
||||
</x-button>
|
||||
<!-- 支付 -->
|
||||
<PressableButton @click="show = true">
|
||||
<div class="w-60px h-60px text-center border-b border-gray-300 flex flex-col justify-center items-center text-yellow-600">
|
||||
<x-button @click="show = true">
|
||||
<div class="w-60px h-60px text-center flex flex-col justify-center items-center text-yellow-600">
|
||||
<div class="text-10px">RMB</div>
|
||||
<div class="text-12px">5,000</div>
|
||||
<div class="text-10px">去支付</div>
|
||||
</div>
|
||||
</PressableButton>
|
||||
</x-button>
|
||||
|
||||
</div>
|
||||
</template>
|
61
app/pages/liveRoom/components/SideButton/tangPopup.vue
Normal file
61
app/pages/liveRoom/components/SideButton/tangPopup.vue
Normal file
@ -0,0 +1,61 @@
|
||||
<script setup>
|
||||
import xPopup from '@/components/x-popup/index.vue'
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
import xImage from '@/components/x-image/index.vue'
|
||||
const {pageRef,itemList} = goodStore();
|
||||
const props = defineProps({
|
||||
show: Boolean,
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['update:show'])
|
||||
|
||||
const close = () => emit('update:show', false);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<x-popup :show="show" @update:show="close">
|
||||
<template #title>
|
||||
<div class="text-#000 text-16px">拍品列表</div>
|
||||
<div class="text-#939393 text-16px ml-14px">共{{ pageRef.itemCount }}个拍品</div>
|
||||
</template>
|
||||
<div>
|
||||
<div
|
||||
v-for="(item,index) of itemList"
|
||||
:key="item.uuid"
|
||||
class="flex mb-21px"
|
||||
>
|
||||
<div
|
||||
class="mr-10px flex-shrink-0 rounded-4px overflow-hidden cursor-pointer"
|
||||
>
|
||||
<xImage
|
||||
class="w-80px h-80px"
|
||||
:src="item.artwork?.hdPic"
|
||||
:alt="item?.artworkTitle"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||
{{ item.artworkTitle }}
|
||||
</div>
|
||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-popup>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.ellipsis {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
@ -2,13 +2,12 @@
|
||||
import {ref, onMounted, onBeforeUnmount} from 'vue'
|
||||
import Aliplayer from 'aliyun-aliplayer'
|
||||
import 'aliyun-aliplayer/build/skins/default/aliplayer-min.css'
|
||||
import sideButton from '~/pages/LiveRoom/components/SideButton/index.vue'
|
||||
import broadcast from '~/pages/LiveRoom/components/Broadcast/index.vue'
|
||||
import sideButton from '~/pages/liveRoom/components/SideButton/index.vue'
|
||||
import broadcast from '~/pages/liveRoom/components/Broadcast/index.vue'
|
||||
import {liveStore} from "~/stores/live/index.js";
|
||||
import paymentResults from '~/pages/LiveRoom/components/PaymentResults/index.vue'
|
||||
import paymentInput from '~/pages/LiveRoom/components/PaymentInput/index.vue'
|
||||
import PressableButton from '~/pages/LiveRoom/components/SideButton/PressableButton.vue'
|
||||
|
||||
import paymentResults from '~/pages/liveRoom/components/PaymentResults/index.vue'
|
||||
import paymentInput from '~/pages/liveRoom/components/PaymentInput/index.vue'
|
||||
import xButton from '@/components/x-button/index.vue'
|
||||
const player = ref(null)
|
||||
const {quoteStatus, changeStatus, show, playerId, show1} = liveStore()
|
||||
const isPlayerReady = ref(false)
|
||||
@ -116,12 +115,12 @@ watch(()=>{
|
||||
下口价:RMB
|
||||
<van-rolling-text class="my-rolling-text1" :start-num="0" :duration="0.5" :target-num="3500" direction="up"/>
|
||||
</div>
|
||||
<PressableButton>
|
||||
<x-button>
|
||||
<div
|
||||
:class="`w-344px h-[40px] ${quoteStatus ? 'bg-#FFB25F' : 'bg-#D6D6D8'} rounded-4px ${quoteStatus ? 'text-#fff' : 'text-#7D7D7F'} text-14px flex justify-center items-center mt-10px mb-10px`">
|
||||
{{ quoteStatus ? '确认出价 RMB 3,000' : '点击"开启出价",即刻参与竞拍 ' }}
|
||||
</div>
|
||||
</PressableButton>
|
||||
</x-button>
|
||||
<broadcast></broadcast>
|
||||
</div>
|
||||
<paymentInput v-model:show="show"/>
|
@ -158,7 +158,7 @@ const goLogin =async () => {
|
||||
<div />
|
||||
</div>
|
||||
<div class="mt-[55px]">
|
||||
<van-button :loading="loadingRef.loading1" v-if="phoneNum" :loading-text="$t('login.getCode')" type="primary" block style="height: 48px" @click="getCode">{{ $t('login.getCode')
|
||||
<van-button :loading="loadingRef.loading1" v-if="phoneNum" :loading-text="$t('login.getCode')" color="#2B53AC" block style="height: 48px" @click="getCode">{{ $t('login.getCode')
|
||||
}}</van-button>
|
||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.getCode')
|
||||
}}</van-button>
|
||||
|
@ -1,17 +1,36 @@
|
||||
<script setup>
|
||||
import {userArtworks} from "~/api/goods/index.js";
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
|
||||
import xImage from '@/components/x-image/index.vue'
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
title: '我的',
|
||||
i18n: 'menu.profile',
|
||||
})
|
||||
const myList=ref([])
|
||||
const showMyList=ref([])
|
||||
const {userInfo}= authStore()
|
||||
const groupAndSortByDate=(data)=> {
|
||||
if (!Array.isArray(data)) {
|
||||
return
|
||||
}
|
||||
return Object.values(data.reduce((acc, curr) => {
|
||||
if (!acc[curr.userCreatedAt]) {
|
||||
acc[curr.userCreatedAt] = {
|
||||
userCreatedAt: curr.userCreatedAt,
|
||||
list: []
|
||||
};
|
||||
}
|
||||
acc[curr.userCreatedAt].list.push(curr);
|
||||
return acc;
|
||||
}, {}))
|
||||
.sort((a, b) => new Date(b.userCreatedAt) - new Date(a.userCreatedAt));
|
||||
}
|
||||
const initData=async ()=>{
|
||||
const res=await userArtworks({})
|
||||
if (res.status===0){
|
||||
|
||||
myList.value=res.data.data
|
||||
showMyList.value=groupAndSortByDate(myList.value)
|
||||
}
|
||||
}
|
||||
initData()
|
||||
@ -28,55 +47,22 @@ initData()
|
||||
<div class="text-#575757 text-14px">{{userInfo.telNum}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="flex-grow-1 ">
|
||||
<div class="border-b-1px border-b-#D3D3D3 px-16px flex">
|
||||
<div class="text-#000 text-16px border-b-3 border-b-#2B53AC h-36px">我的拍品</div>
|
||||
</div>
|
||||
<van-pull-refresh>
|
||||
<van-pull-refresh @refresh="initData">
|
||||
<van-list
|
||||
finished-text="没有更多了"
|
||||
>
|
||||
<div class="px-16px pt-14px">
|
||||
<div class="text-#575757 text-14px mb-3px">2025.01.12</div>
|
||||
<div class="flex mb-22px">
|
||||
<div class="flex-shrink-0 mr-10px">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
<div class="px-16px pt-14px" v-for="(item,index) of showMyList">
|
||||
<div class="text-#575757 text-14px mb-3px">{{item.userCreatedAt}}</div>
|
||||
<div class="flex mb-22px" v-for="(item1,index1) of item.list">
|
||||
<div class="flex-shrink-0 mr-10px rounded-4px overflow-hidden">
|
||||
<x-image class="w-80px h-80px" :src="item1?.auctionArtworkInfo?.artwork?.hdPic" alt=""/>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="text-#000 text-16px ellipsis line-height-21px">张天赐 | 日出而作,日落而息撒打算撒打算撒打决赛多久啊是世奥兰…</div>
|
||||
<div class="text-#575757 text-14px line-height-none ">起拍价:RMB 1,000</div>
|
||||
<div class="text-#B58047 text-14px line-height-none">成交价:RMB 10,000</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0 mr-10px">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="text-#000 text-16px ellipsis line-height-21px">张天赐 | 日出而作,日落而息撒打算撒打算撒打决赛多久啊是世奥兰…</div>
|
||||
<div class="text-#575757 text-14px line-height-none ">起拍价:RMB 1,000</div>
|
||||
<div class="text-[#fdc181ff] line-height-none">成交价:RMB 10,000</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-16px pt-14px">
|
||||
<div class="text-#575757 text-14px mb-3px">2025.01.12</div>
|
||||
<div class="flex mb-22px">
|
||||
<div class="flex-shrink-0 mr-10px">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="text-#000 text-16px ellipsis line-height-21px">张天赐 | 日出而作,日落而息撒打算撒打算撒打决赛多久啊是世奥兰…</div>
|
||||
<div class="text-#575757 text-14px line-height-none ">起拍价:RMB 1,000</div>
|
||||
<div class="text-#B58047 text-14px line-height-none">成交价:RMB 10,000</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0 mr-10px">
|
||||
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="text-#000 text-16px ellipsis line-height-21px">张天赐 | 日出而作,日落而息撒打算撒打算撒打决赛多久啊是世奥兰…</div>
|
||||
<div class="text-#000 text-16px ellipsis line-height-21px">{{item1?.auctionArtworkInfo?.artworkTitle}}</div>
|
||||
<div class="text-#575757 text-14px line-height-none ">起拍价:RMB 1,000</div>
|
||||
<div class="text-#B58047 text-14px line-height-none">成交价:RMB 10,000</div>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@ const {userInfo}= authStore()
|
||||
<template>
|
||||
<div class="text-#1A1A1A text-16px">
|
||||
<template v-if="type===0">
|
||||
<div class="flex mb-20px" >
|
||||
<div class="flex mb-20px">
|
||||
<div class="mr-10px">姓名:</div>
|
||||
<div>{{userInfo.realName}}</div>
|
||||
</div>
|
||||
|
24
app/pages/test/index.client.vue
Normal file
24
app/pages/test/index.client.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import MasonryWall from '@yeger/vue-masonry-wall'
|
||||
const items = [
|
||||
{
|
||||
title: 'First',
|
||||
description: 'The first item.',
|
||||
},
|
||||
{
|
||||
title: 'Second',
|
||||
description: 'The second item.',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<masonry-wall :items="items" :ssr-columns="2" :minColumns="2" :gap="16">
|
||||
<template #default="{ item, index }">
|
||||
<div :style="{ height: `${(index + 1) * 100}px` }">
|
||||
<h1>{{ item.title }}</h1>
|
||||
<span>{{ item.description }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</masonry-wall>
|
||||
</template>
|
@ -1,3 +1,10 @@
|
||||
:root:root {
|
||||
--c-primary: #3554AF;
|
||||
--c-primary-active: #3554AF;
|
||||
--van-primary-color: var(--c-primary);
|
||||
--van-cell-group-inset-padding: 0;
|
||||
|
||||
}
|
||||
#__nuxt {
|
||||
margin: 0;
|
||||
padding: 0;
|
0
app/static/styles/global.css
Normal file
0
app/static/styles/global.css
Normal file
0
app/static/styles/vars.css
Normal file
0
app/static/styles/vars.css
Normal file
@ -25,7 +25,6 @@ export const goodStore = createGlobalState(() => {
|
||||
pageRef.value.page = 1
|
||||
pageRef.value.pageSize=5
|
||||
pageRef.value.itemCount = 0
|
||||
itemList.value = []
|
||||
}
|
||||
|
||||
// 获取拍卖详情
|
||||
|
@ -1,4 +0,0 @@
|
||||
:root:root {
|
||||
--van-primary-color: var(--c-primary);
|
||||
--van-cell-group-inset-padding: 0;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
:root {
|
||||
--c-primary: #3554AF;
|
||||
--c-primary-active: #3554AF;
|
||||
}
|
215
nuxt.config.js
215
nuxt.config.js
@ -1,61 +1,58 @@
|
||||
// 导入环境变量处理库
|
||||
import dotenv from 'dotenv'
|
||||
// 导入 Node.js 进程模块
|
||||
import process from 'node:process'
|
||||
// 导入预加载工具函数
|
||||
import preload from './app/utils/preload'
|
||||
// 导入国际化语言配置
|
||||
import { currentLocales } from './i18n/i18n'
|
||||
|
||||
// 设置环境变量文件路径,默认使用 .env.test
|
||||
const envFile = process.env.ENV_FILE || '.env.test'
|
||||
// 加载环境变量配置
|
||||
dotenv.config({ path: `./env/${envFile}` })
|
||||
|
||||
// 过滤出以 NUXT_PUBLIC_ 开头的环境变量作为公共配置
|
||||
const publicConfig = Object.entries(process.env)
|
||||
.filter(([key]) => key.startsWith('NUXT_PUBLIC_'))
|
||||
.reduce((config, [key, value]) => {
|
||||
config[key] = value
|
||||
return config
|
||||
}, {})
|
||||
.filter(([key]) => key.startsWith('NUXT_PUBLIC_'))
|
||||
.reduce((config, [key, value]) => {
|
||||
config[key] = value
|
||||
return config
|
||||
}, {})
|
||||
|
||||
export default defineNuxtConfig({
|
||||
hooks: {
|
||||
'pages:extend'(pages) {
|
||||
const indexPage = pages.findIndex(page => page.path === '/')
|
||||
if (indexPage !== -1) {
|
||||
pages.splice(indexPage, 1)
|
||||
}
|
||||
pages.push({
|
||||
name: 'home',
|
||||
path: '/',
|
||||
file: '@/pages/home/index.vue'
|
||||
})
|
||||
}
|
||||
},
|
||||
// 注册 Nuxt 模块
|
||||
modules: [
|
||||
'@vant/nuxt',
|
||||
'@unocss/nuxt',
|
||||
'@nuxtjs/color-mode',
|
||||
'@nuxtjs/i18n',
|
||||
'@nuxt/image', // 图片优化模块
|
||||
'@vant/nuxt', // Vant UI 组件库
|
||||
'@unocss/nuxt', // 原子化 CSS 框架
|
||||
'@nuxtjs/i18n', // 国际化模块
|
||||
],
|
||||
|
||||
// 运行时配置
|
||||
runtimeConfig: {
|
||||
// 私有配置,只有在服务端可用
|
||||
// 私有配置,只在服务端可用
|
||||
apiSecret: process.env.NUXT_API_SECRET || 'default_secret',
|
||||
// 公共配置,客户端和服务端都可用
|
||||
public: publicConfig,
|
||||
},
|
||||
|
||||
// CSS 配置
|
||||
css: [
|
||||
'@unocss/reset/tailwind.css',
|
||||
'./app/styles/vars.css',
|
||||
'./app/styles/global.css',
|
||||
'./app/styles/default-theme.css',
|
||||
'@unocss/reset/tailwind.css', // 重置默认样式
|
||||
'@/static/styles/default-theme.css',
|
||||
],
|
||||
|
||||
// PostCSS 配置
|
||||
postcss: {
|
||||
plugins: {
|
||||
'autoprefixer': {},
|
||||
|
||||
// https://github.com/wswmsword/postcss-mobile-forever
|
||||
'autoprefixer': {}, // 自动添加 CSS 前缀
|
||||
// 移动端适配插件配置
|
||||
'postcss-mobile-forever': {
|
||||
appSelector: '#__nuxt',
|
||||
viewportWidth: 375,
|
||||
maxDisplayWidth: 600,
|
||||
// devtools excluded
|
||||
exclude: /@nuxt/,
|
||||
border: true,
|
||||
appSelector: '#__nuxt', // 根选择器
|
||||
viewportWidth: 375, // 设计稿宽度
|
||||
maxDisplayWidth: 600, // 最大显示宽度
|
||||
exclude: /@nuxt/, // 排除的文件
|
||||
border: true, // 显示边框
|
||||
rootContainingBlockSelectorList: [
|
||||
'van-tabbar',
|
||||
'van-popup',
|
||||
@ -64,89 +61,153 @@ export default defineNuxtConfig({
|
||||
},
|
||||
},
|
||||
|
||||
colorMode: {
|
||||
classSuffix: '',
|
||||
preference: 'system',
|
||||
fallback: 'light',
|
||||
storageKey: 'nuxt-color-mode',
|
||||
},
|
||||
|
||||
// 国际化配置
|
||||
i18n: {
|
||||
locales: currentLocales,
|
||||
lazy: true,
|
||||
strategy: 'no_prefix',
|
||||
locales: currentLocales, // 支持的语言列表
|
||||
lazy: true, // 懒加载语言包
|
||||
strategy: 'no_prefix', // URL 策略:不添加语言前缀
|
||||
detectBrowserLanguage: {
|
||||
useCookie: true,
|
||||
cookieKey: 'i18n_redirected',
|
||||
redirectOn: 'root',
|
||||
alwaysRedirect: true,
|
||||
fallbackLocale: 'zh-CN'
|
||||
useCookie: true, // 使用 cookie 存储语言选择
|
||||
cookieKey: 'i18n_redirected', // cookie 键名
|
||||
redirectOn: 'root', // 仅在根路径重定向
|
||||
alwaysRedirect: true, // 总是重定向
|
||||
fallbackLocale: 'zh-CN' // 默认语言
|
||||
},
|
||||
langDir: 'locales',
|
||||
defaultLocale: 'zh-CN',
|
||||
vueI18n: './i18n/i18n.config.ts',
|
||||
langDir: 'locales', // 语言文件目录
|
||||
defaultLocale: 'zh-CN', // 默认语言
|
||||
vueI18n: './i18n/i18n.config.ts', // Vue I18n 配置文件
|
||||
},
|
||||
|
||||
// 应用配置
|
||||
app: {
|
||||
layoutTransition: {
|
||||
// 布局过渡动画
|
||||
layoutTransition: {
|
||||
name: 'layout',
|
||||
mode: 'out-in'
|
||||
},
|
||||
// 头部配置
|
||||
head: {
|
||||
// 视口配置
|
||||
viewport: 'width=device-width,initial-scale=1,viewport-fit=cover',
|
||||
// 链接配置
|
||||
link: [
|
||||
{ rel: 'icon', href: '/favicon.ico', sizes: 'any' },
|
||||
{ rel: 'icon', href: '/favicon.ico', sizes: 'any' }, // 网站图标
|
||||
{ rel: 'preload', as: 'style', href: '/critical.css' }, // 预加载关键 CSS
|
||||
{ rel: 'preconnect', href: '你的API域名' }, // 预连接 API 域名
|
||||
{ rel: 'dns-prefetch', href: '你的API域名' }, // DNS 预解析
|
||||
],
|
||||
// Meta 标签配置
|
||||
meta: [
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1, viewport-fit=cover,user-scalable=no' },
|
||||
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
|
||||
{ name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' },
|
||||
{ name: 'theme-color', media: '(prefers-color-scheme: light)', content: '#ffffff' },
|
||||
{ name: 'theme-color', media: '(prefers-color-scheme: dark)', content: '#222222' },
|
||||
{ name: 'apple-mobile-web-app-capable', content: 'yes' }, // iOS 应用模式
|
||||
{ name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' }, // iOS 状态栏样式
|
||||
{ name: 'theme-color', media: '(prefers-color-scheme: light)', content: '#ffffff' }, // 浅色主题色
|
||||
{ name: 'theme-color', media: '(prefers-color-scheme: dark)', content: '#222222' }, // 深色主题色
|
||||
{ name: 'description', content: '你的网站描述' }, // SEO 描述
|
||||
{ 'http-equiv': 'x-dns-prefetch-control', content: 'on' }, // DNS 预解析控制
|
||||
],
|
||||
// 脚本配置
|
||||
script: [
|
||||
{ innerHTML: preload(), type: 'text/javascript', tagPosition: 'head' },
|
||||
{ innerHTML: preload(), type: 'text/javascript', tagPosition: 'head' }, // 预加载脚本
|
||||
// 性能监控脚本
|
||||
{
|
||||
innerHTML: `
|
||||
window.performance.mark('app-start');
|
||||
new PerformanceObserver((entryList) => {
|
||||
for (const entry of entryList.getEntries()) {
|
||||
console.log('FCP:', entry.startTime);
|
||||
}
|
||||
}).observe({entryTypes: ['paint']});
|
||||
`,
|
||||
type: 'text/javascript',
|
||||
tagPosition: 'head'
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// Vite 构建配置
|
||||
vite: {
|
||||
build: {
|
||||
target: 'esnext',
|
||||
target: 'esnext', // 构建目标
|
||||
// Rollup 配置
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
'vant': ['vant'], // Vant 单独打包
|
||||
'vendor': ['vue', 'vue-router'] // 核心库单独打包
|
||||
}
|
||||
}
|
||||
},
|
||||
minify: 'terser', // 使用 terser 压缩
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true, // 移除 console
|
||||
drop_debugger: true // 移除 debugger
|
||||
}
|
||||
}
|
||||
},
|
||||
// 依赖优化配置
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
'@intlify/core-base',
|
||||
'@intlify/shared',
|
||||
'is-https',
|
||||
'@intlify/core-base', // I18n 核心
|
||||
'@intlify/shared', // I18n 共享库
|
||||
'is-https', // HTTPS 检测
|
||||
'vant', // Vant UI
|
||||
'@vant/use', // Vant Hooks
|
||||
'@vueuse/core', // VueUse 工具集
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// 实验性功能
|
||||
experimental: {
|
||||
typedPages: true,
|
||||
typedPages: true, // 启用页面类型
|
||||
},
|
||||
|
||||
// 开发工具
|
||||
devtools: {
|
||||
enabled: true,
|
||||
enabled: true, // 启用开发工具
|
||||
},
|
||||
|
||||
// TypeScript 配置
|
||||
typescript: {
|
||||
shim: false,
|
||||
shim: false, // 禁用 shim
|
||||
},
|
||||
|
||||
// 功能特性配置
|
||||
features: {
|
||||
// For UnoCSS
|
||||
inlineStyles: false,
|
||||
inlineStyles: false, // 禁用内联样式
|
||||
},
|
||||
|
||||
// 未来特性配置
|
||||
future: {
|
||||
compatibilityVersion: 4,
|
||||
compatibilityVersion: 4, // 兼容性版本
|
||||
},
|
||||
// 指定 Nuxt 应用程序的兼容性日期,确保应用程序在未来的 Nuxt 版本中保持稳定性
|
||||
compatibilityDate: '2025-01-09',
|
||||
|
||||
// Nuxt 兼容性日期
|
||||
compatibilityDate: '2025-01-09', // 确保未来版本兼容性
|
||||
|
||||
// 开发服务器配置
|
||||
devServer: {
|
||||
host: '0.0.0.0', // Set the host to 'localhost'
|
||||
port: 3000, // Set the port to 3000 or any other port you prefer
|
||||
host: '0.0.0.0', // 主机地址
|
||||
port: 3000, // 端口号
|
||||
},
|
||||
|
||||
// 图片优化配置
|
||||
image: {
|
||||
provider: 'ipx', // 图片处理提供者
|
||||
// 响应式断点
|
||||
screens: {
|
||||
xs: 320, // 超小屏幕
|
||||
sm: 640, // 小屏幕
|
||||
md: 768, // 中等屏幕
|
||||
lg: 1024, // 大屏幕
|
||||
xl: 1280, // 超大屏幕
|
||||
xxl: 1536, // 特大屏幕
|
||||
},
|
||||
quality: 80, // 图片质量
|
||||
format: ['webp', 'jpg'], // 支持的格式
|
||||
placeholder: true, // 启用占位图
|
||||
blur: 3 // 模糊加载效果
|
||||
}
|
||||
})
|
@ -21,6 +21,7 @@
|
||||
"@nuxtjs/color-mode": "^3.5.2",
|
||||
"@nuxtjs/i18n": "^9.1.1",
|
||||
"@vueuse/core": "^12.4.0",
|
||||
"@yeger/vue-masonry-wall": "^5.0.17",
|
||||
"aliyun-aliplayer": "^2.28.5",
|
||||
"axios": "^1.7.9",
|
||||
"dotenv": "^16.4.7",
|
||||
@ -33,6 +34,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/carbon": "^1.2.5",
|
||||
"@nuxt/image": "^1.9.0",
|
||||
"@unocss/nuxt": "0.65.2",
|
||||
"@unocss/preset-rem-to-px": "0.65.2",
|
||||
"@vant/nuxt": "^1.0.6",
|
||||
|
619
pnpm-lock.yaml
619
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user