Compare commits
No commits in common. "107966dabc7d10927f85e57fac097c5fa3a25ff7" and "fc3e833605e7b2b3ab80785fc4f109c9b694d6e1" have entirely different histories.
107966dabc
...
fc3e833605
@ -1,25 +1,23 @@
|
|||||||
import { request } from '@/api/http.js'
|
import { getHttp } from '~/api/http.js'
|
||||||
|
|
||||||
export async function senCode(data) {
|
export async function senCode(data) {
|
||||||
|
const http = getHttp()
|
||||||
return await request({
|
return await http('/api/v1/m/user/send', {
|
||||||
url:'/api/v1/m/user/send',
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
body: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export async function userLogin(data) {
|
export async function userLogin(data) {
|
||||||
|
const http = getHttp()
|
||||||
return await request( {
|
return await http('/api/v1/m/user/login', {
|
||||||
url:'/api/v1/m/user/login',
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
body: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export async function userUpdate(data) {
|
export async function userUpdate(data) {
|
||||||
return await request( {
|
const http = getHttp()
|
||||||
url:'/api/v1/m/user/update',
|
return await http('/api/v1/m/user/update', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
body: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
@ -1,32 +1,30 @@
|
|||||||
import { request } from '@/api/http.js'
|
import { getHttp } from '~/api/http.js'
|
||||||
|
|
||||||
export async function artworkList(data) {
|
export async function artworkList(data) {
|
||||||
return await request( {
|
const http = getHttp()
|
||||||
url:'/api/v1/m/auction/default/artwork/list',
|
return await http('/api/v1/m/auction/default/artwork/list', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
body: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export async function defaultDetail(data) {
|
export async function defaultDetail(data) {
|
||||||
return await request ({
|
const http = getHttp()
|
||||||
url:'/api/v1/m/auction/default/detail',
|
return await http('/api/v1/m/auction/default/detail', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
body: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export async function artworkDetail(data) {
|
export async function artworkDetail(data) {
|
||||||
|
const http = getHttp()
|
||||||
return await request( {
|
return await http('/api/v1/m/artwork/detail', {
|
||||||
url:'/api/v1/m/artwork/detail',
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data,
|
body: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export async function userArtworks(data) {
|
export async function userArtworks(data) {
|
||||||
|
const http = getHttp()
|
||||||
return await request( {
|
return await http('/api/v1/m/user/artworks', {
|
||||||
url:'/api/v1/m/user/artworks',
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
body: data,
|
||||||
})
|
})
|
||||||
}
|
}
|
123
app/api/http.js
123
app/api/http.js
@ -1,109 +1,52 @@
|
|||||||
import {useRuntimeConfig} from '#app'
|
|
||||||
import {ofetch} from 'ofetch'
|
|
||||||
import {message} from '@/components/x-message/useMessage.js'
|
|
||||||
import {authStore} from "@/stores/auth/index.js"
|
|
||||||
|
|
||||||
|
import { useRuntimeConfig } from '#app'
|
||||||
|
import { ofetch } from 'ofetch'
|
||||||
|
import {message} from '@/components/x-message/useMessage.js'
|
||||||
|
import {authStore} from "@/stores/auth/index.js";
|
||||||
let httpStatusErrorHandler
|
let httpStatusErrorHandler
|
||||||
|
|
||||||
let http
|
let http
|
||||||
|
|
||||||
// HTTP 状态码映射
|
|
||||||
const HTTP_STATUS_MAP = {
|
|
||||||
400: '请求参数错误',
|
|
||||||
401: '未授权或登录过期',
|
|
||||||
403: '访问被禁止',
|
|
||||||
404: '请求的资源不存在',
|
|
||||||
500: '服务器内部错误',
|
|
||||||
502: '网关错误',
|
|
||||||
503: '服务暂时不可用',
|
|
||||||
504: '网关超时'
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setupHttp() {
|
export function setupHttp() {
|
||||||
if (http) return http
|
if (http)
|
||||||
|
return http
|
||||||
|
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const baseURL = config.public.NUXT_PUBLIC_API_BASE
|
const baseURL = config.public.NUXT_PUBLIC_API_BASE
|
||||||
const { token } = authStore()
|
const {token}= authStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
http = ofetch.create({
|
||||||
const defaultOptions = {
|
|
||||||
baseURL,
|
baseURL,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
timeout: 15000, // 15秒超时
|
async onRequest({ options }) {
|
||||||
retry: 3,
|
|
||||||
retryDelay: 1000,
|
|
||||||
}
|
|
||||||
|
|
||||||
http = ofetch.create({
|
|
||||||
...defaultOptions,
|
|
||||||
|
|
||||||
// 请求拦截
|
|
||||||
async onRequest({ options, request }) {
|
|
||||||
// 添加 token
|
|
||||||
options.headers = {
|
options.headers = {
|
||||||
...options.headers,
|
...options.headers,
|
||||||
Authorization: token.value
|
Authorization:token.value
|
||||||
}
|
|
||||||
|
|
||||||
// GET 请求添加时间戳防止缓存
|
|
||||||
if (request.toLowerCase().includes('get')) {
|
|
||||||
options.params = {
|
|
||||||
...options.params,
|
|
||||||
_t: Date.now()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 响应拦截
|
|
||||||
async onResponse({ response }) {
|
async onResponse({ response }) {
|
||||||
const data = response._data
|
if (response._data.status===1){
|
||||||
|
message.error(response._data.msg)
|
||||||
// 处理业务错误
|
}
|
||||||
if (data.status === 1) {
|
if (response._data.status===401){
|
||||||
message.error(data.msg || '操作失败')
|
router.replace('/login')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理登录失效
|
|
||||||
if (data.status === 401) {
|
|
||||||
message.error('登录已过期,请重新登录')
|
|
||||||
token.value = '' // 清除 token
|
|
||||||
router.replace('/login')
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
},
|
},
|
||||||
|
async onResponseError({ response }) {
|
||||||
// 响应错误处理
|
const { message } = response._data
|
||||||
async onResponseError({ response, request }) {
|
if (Array.isArray(message)) {
|
||||||
// 网络错误
|
message.forEach((item) => {
|
||||||
if (!response) {
|
httpStatusErrorHandler?.(item, response.status)
|
||||||
message.error('网络连接失败,请检查网络设置')
|
|
||||||
return Promise.reject(new Error('网络错误'))
|
|
||||||
}
|
|
||||||
const status = response.status
|
|
||||||
const data = response._data
|
|
||||||
|
|
||||||
// 处理 HTTP 状态错误
|
|
||||||
const errorMessage = data.msg || HTTP_STATUS_MAP[status] || '请求失败'
|
|
||||||
|
|
||||||
if (Array.isArray(data.msg)) {
|
|
||||||
data.msg.forEach(item => {
|
|
||||||
httpStatusErrorHandler?.(item, status)
|
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
httpStatusErrorHandler?.(errorMessage, status)
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
message.error(errorMessage)
|
httpStatusErrorHandler?.(message, response.status)
|
||||||
return Promise.reject(data)
|
}
|
||||||
|
return Promise.reject(response._data)
|
||||||
},
|
},
|
||||||
|
retry: 3,
|
||||||
|
retryDelay: 1000,
|
||||||
})
|
})
|
||||||
|
|
||||||
return http
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createAbortController() {
|
|
||||||
return new AbortController()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function injectHttpStatusErrorHandler(handler) {
|
export function injectHttpStatusErrorHandler(handler) {
|
||||||
@ -116,13 +59,3 @@ export function getHttp() {
|
|||||||
}
|
}
|
||||||
return http
|
return http
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出请求工具函数
|
|
||||||
export async function request({url,...options}) {
|
|
||||||
const http = getHttp()
|
|
||||||
try {
|
|
||||||
return await http(url, {...options,body:options.data})
|
|
||||||
} catch (error) {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
15
app/app.vue
15
app/app.vue
@ -1,12 +1,12 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {useI18n} from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import {message} from '@/components/x-message/useMessage.js'
|
import {message} from '@/components/x-message/useMessage.js'
|
||||||
// message.success('success')
|
// message.success('success')
|
||||||
useHead({
|
useHead({
|
||||||
title: useI18n().t('appSetting.appName'),
|
title: useI18n().t('appSetting.appName'),
|
||||||
meta: [
|
meta: [
|
||||||
{name: 'description', content: useI18n().t('appSetting.appDescription')},
|
{ name: 'description', content: useI18n().t('appSetting.appDescription') },
|
||||||
{name: 'keywords', content: useI18n().t('appSetting.appKeyWords')},
|
{ name: 'keywords', content: useI18n().t('appSetting.appKeyWords') },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
const color = useColorMode()
|
const color = useColorMode()
|
||||||
@ -25,7 +25,7 @@ const routeHistory = ref([])
|
|||||||
router.beforeEach((to, from) => {
|
router.beforeEach((to, from) => {
|
||||||
// 记录路由历史
|
// 记录路由历史
|
||||||
routeHistory.value.push(from.path)
|
routeHistory.value.push(from.path)
|
||||||
|
|
||||||
// 如果是返回操作(在历史记录中找到目标路由)
|
// 如果是返回操作(在历史记录中找到目标路由)
|
||||||
if (routeHistory.value.includes(to.path)) {
|
if (routeHistory.value.includes(to.path)) {
|
||||||
slideDirection.value = 'slide-right'
|
slideDirection.value = 'slide-right'
|
||||||
@ -44,11 +44,11 @@ provide('slideDirection', slideDirection)
|
|||||||
<template>
|
<template>
|
||||||
<VanConfigProvider :theme="mode">
|
<VanConfigProvider :theme="mode">
|
||||||
<NuxtLoadingIndicator
|
<NuxtLoadingIndicator
|
||||||
color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)"/>
|
color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)" />
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<NuxtPage :transition="{
|
<NuxtPage :transition="{
|
||||||
name: slideDirection
|
name: slideDirection
|
||||||
}"/>
|
}" />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</VanConfigProvider>
|
</VanConfigProvider>
|
||||||
</template>
|
</template>
|
||||||
@ -78,8 +78,7 @@ provide('slideDirection', slideDirection)
|
|||||||
.slide-right-leave-to {
|
.slide-right-leave-to {
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
}
|
}
|
||||||
|
:root{
|
||||||
:root {
|
|
||||||
--safe-area-inset-bottom: env(safe-area-inset-bottom);
|
--safe-area-inset-bottom: env(safe-area-inset-bottom);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,8 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useAppFooterRouteNames as names } from '@/config/index.js'
|
import { useAppFooterRouteNames as names } from '~/config/index.js'
|
||||||
import MyIcon from "@/components/icons/MyIcon.vue";
|
import MyIcon from "~/components/icons/MyIcon.vue";
|
||||||
import HomeIcon from "@/components/icons/HomeIcon.vue";
|
import HomeIcon from "~/components/icons/HomeIcon.vue";
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const active = ref(0)
|
const active = ref(0)
|
||||||
const show = computed(() => {
|
const show = computed(() => {
|
||||||
if (route.name && names.includes(route.name))
|
if (route.name && names.includes(route.name))
|
||||||
@ -12,6 +13,7 @@ const show = computed(() => {
|
|||||||
const initData=()=>{
|
const initData=()=>{
|
||||||
active.value=route.path==='/profile'?1:0
|
active.value=route.path==='/profile'?1:0
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
initData()
|
initData()
|
||||||
})
|
})
|
||||||
@ -19,6 +21,7 @@ onMounted(()=>{
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="show">
|
<div v-if="show">
|
||||||
|
|
||||||
<van-tabbar v-model="active" route placeholder fixed>
|
<van-tabbar v-model="active" route placeholder fixed>
|
||||||
<van-tabbar-item replace to="/">
|
<van-tabbar-item replace to="/">
|
||||||
<span>{{ $t('tabbar.home') }}</span>
|
<span>{{ $t('tabbar.home') }}</span>
|
||||||
|
@ -30,9 +30,7 @@ const subTitle = computed(() => {
|
|||||||
return route.meta.subTitle ? t(route.meta.subTitle) : ''
|
return route.meta.subTitle ? t(route.meta.subTitle) : ''
|
||||||
})
|
})
|
||||||
const showLeftArrow = computed(() => route.name && routeWhiteList.includes(route.name))
|
const showLeftArrow = computed(() => route.name && routeWhiteList.includes(route.name))
|
||||||
console.log('route.meta.i18n',route.meta.i18n)
|
|
||||||
console.log('t(route.meta.i18n)',route.meta.i18n)
|
|
||||||
console.log('route.meta.title',route.meta.title)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -1,39 +1,48 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { showImagePreview } from 'vant';
|
import { ImagePreview } from 'vant';
|
||||||
|
const images = [
|
||||||
import xImage from '@/components/x-image/index.vue'
|
'https://e-cdn.fontree.cn/fonchain-main/prod/file/default/setting/637d95b4-2ae9-4a74-bd60-a3a9d2ca2ca0.png',
|
||||||
const props = defineProps({
|
'https://e-cdn.fontree.cn/fonchain-main/prod/file/default/setting/f7b65e23-ce21-41b4-8e58-9e6dc6950727.png',
|
||||||
detailInfo: {
|
'https://e-cdn.fontree.cn/fonchain-main/prod/file/default/setting/41eceb23-d168-4049-ae8e-48c5328b192f.png',
|
||||||
type: Object,
|
];
|
||||||
default: null
|
const clickSwipe=(index)=>{
|
||||||
}
|
showImagePreview({
|
||||||
})
|
images: images,
|
||||||
|
startPosition:index,
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-center">
|
<van-swipe style="height: 188px" indicator-color="#B4B4B4" lazy-render >
|
||||||
<xImage class="h-188px" :src="detailInfo?.artwork?.hdPic"></xImage>
|
<van-swipe-item v-for="(image,index) in images" :key="image" @click="clickSwipe(index)">
|
||||||
</div>
|
<van-image
|
||||||
|
fit="contain"
|
||||||
|
width="100%"
|
||||||
|
:height="188"
|
||||||
|
:src="image"
|
||||||
|
/>
|
||||||
|
</van-swipe-item>
|
||||||
|
</van-swipe>
|
||||||
<div class="px-[16px] bg-[#fff] pt-[11px] mb-6px">
|
<div class="px-[16px] bg-[#fff] pt-[11px] mb-6px">
|
||||||
<div class="text-[#000] text-[16px] mb-[12px]">{{detailInfo?.artworkTitle}}</div>
|
<div class="text-[#000] text-[16px] mb-[12px]">日出而作,日落而息</div>
|
||||||
<div class="text-#575757 text-[14px] pb-8px">
|
<div class="text-#575757 text-[14px] pb-8px">
|
||||||
<div class="flex mb-[4px]">
|
<div class="flex mb-[4px]">
|
||||||
<div class="w-[70px]">作者:</div>
|
<div class="w-[70px]">作者:</div>
|
||||||
<div>{{detailInfo?.artwork?.artistName??'-'}}</div>
|
<div>张天赐</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-[4px]">
|
<div class="flex mb-[4px]">
|
||||||
<div class="w-[70px] flex-shrink-0">总平尺数:</div>
|
<div class="w-[70px] flex-shrink-0">总平尺数:</div>
|
||||||
<div>{{detailInfo?.artwork?.ruler??'-'}}</div>
|
<div>—</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-[4px]">
|
<div class="flex mb-[4px]">
|
||||||
<div class="w-[70px] flex-shrink-0">长*宽:</div>
|
<div class="w-[70px] flex-shrink-0">长*宽:</div>
|
||||||
<div>{{detailInfo?.artwork?.length}}*{{detailInfo?.artwork?.width}}cm</div>
|
<div>100*200cm</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-[4px]">
|
<div class="flex mb-[4px]">
|
||||||
<div class="w-[70px] flex-shrink-0">画作简介:</div>
|
<div class="w-[70px] flex-shrink-0">画作简介:</div>
|
||||||
<div>{{detailInfo?.artwork?.abstract??'-'}}</div>
|
<div>是打卡时间到卡上即可点击卡拉斯科健康就阿斯科利打卡时间到卡萨带手机的啊科技是打卡时</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
<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,54 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
/*
|
|
||||||
* 封装一个带标题栏的弹窗
|
|
||||||
* */
|
|
||||||
const props = defineProps({
|
|
||||||
show: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
title:''
|
|
||||||
})
|
|
||||||
const emit = defineEmits(['update:show'])
|
|
||||||
const close=()=>{
|
|
||||||
emit('update:show',false)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<van-popup
|
|
||||||
:show="show"
|
|
||||||
teleport="#__nuxt"
|
|
||||||
position="bottom"
|
|
||||||
:style="{ height: '74%' }"
|
|
||||||
v-bind="{...$attrs,...$props}"
|
|
||||||
>
|
|
||||||
<div class="flex flex-col h-full">
|
|
||||||
<!-- 标题栏 -->
|
|
||||||
<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 px-16px py-18px overflow-hidden relative">
|
|
||||||
<div class="h-full overflow-y-auto relative">
|
|
||||||
<slot/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-popup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,3 +1,3 @@
|
|||||||
|
|
||||||
export const useAppFooterRouteNames= ['index', 'profile']
|
export const useAppFooterRouteNames= ['home', 'profile']
|
||||||
export const useAppHeaderRouteNames= ['index', 'profile','login','collectCode-login','collectCode-mine']
|
export const useAppHeaderRouteNames= ['home', 'profile','login']
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
/*
|
|
||||||
* 此组件的目的是使用该组件包裹的内容具有按压状态效果
|
|
||||||
* */
|
|
||||||
import {ref, defineEmits} from "vue";
|
import {ref, defineEmits} from "vue";
|
||||||
|
|
||||||
const emit = defineEmits(["click"]);
|
const emit = defineEmits(["click"]);
|
@ -1,31 +1,24 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import lockClosed from "@/static/images/lockdfd@2x.png";
|
import lockClosed from "~/static/images/lockdfd@2x.png";
|
||||||
import lockOpen from "@/static/images/lock4@2x.png";
|
import lockOpen from "~/static/images/lock4@2x.png";
|
||||||
import { liveStore } from "@/stores/live/index.js";
|
import { liveStore } from "~/stores/live/index.js";
|
||||||
import xButton from '@/components/x-button/index.vue'
|
import PressableButton from './PressableButton.vue'
|
||||||
import tangPopup from './tangPopup.vue'
|
const { quoteStatus, changeStatus,show,show1 } = liveStore();
|
||||||
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-white w-60px rounded-l-4px overflow-hidden">
|
<div class="bg-white w-60px rounded-l-4px overflow-hidden">
|
||||||
<!-- 拍品信息 -->
|
<!-- 拍品信息 -->
|
||||||
<x-button @click="openOne">
|
<PressableButton>
|
||||||
<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 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>拍品</div>
|
||||||
<div>(1/{{pageRef.itemCount??0}})</div>
|
<div>(1/188)</div>
|
||||||
</div>
|
</div>
|
||||||
</x-button>
|
</PressableButton>
|
||||||
<tangPopup v-model:show="showTang"></tangPopup>
|
|
||||||
<!-- 出价开关 -->
|
<!-- 出价开关 -->
|
||||||
<x-button @click="changeStatus">
|
<PressableButton @click="changeStatus">
|
||||||
<div class="w-60px h-60px text-center border-b border-gray-300 flex flex-col justify-center items-center">
|
<div class="w-60px h-60px text-center border-b border-gray-300 flex flex-col justify-center items-center">
|
||||||
<div class="mb-1">
|
<div class="mb-1">
|
||||||
<img
|
<img
|
||||||
@ -38,15 +31,14 @@ const openOne=()=>{
|
|||||||
{{ quoteStatus ? '关闭出价' : '开启出价' }}
|
{{ quoteStatus ? '关闭出价' : '开启出价' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</x-button>
|
</PressableButton>
|
||||||
<!-- 支付 -->
|
<!-- 支付 -->
|
||||||
<x-button @click="show = true">
|
<PressableButton @click="show = true">
|
||||||
<div class="w-60px h-60px text-center flex flex-col justify-center items-center text-yellow-600">
|
<div class="w-60px h-60px text-center border-b border-gray-300 flex flex-col justify-center items-center text-yellow-600">
|
||||||
<div class="text-10px">RMB</div>
|
<div class="text-10px">RMB</div>
|
||||||
<div class="text-12px">5,000</div>
|
<div class="text-12px">5,000</div>
|
||||||
<div class="text-10px">去支付</div>
|
<div class="text-10px">去支付</div>
|
||||||
</div>
|
</div>
|
||||||
</x-button>
|
</PressableButton>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
@ -2,12 +2,13 @@
|
|||||||
import {ref, onMounted, onBeforeUnmount} from 'vue'
|
import {ref, onMounted, onBeforeUnmount} from 'vue'
|
||||||
import Aliplayer from 'aliyun-aliplayer'
|
import Aliplayer from 'aliyun-aliplayer'
|
||||||
import 'aliyun-aliplayer/build/skins/default/aliplayer-min.css'
|
import 'aliyun-aliplayer/build/skins/default/aliplayer-min.css'
|
||||||
import sideButton from '~/pages/liveRoom/components/SideButton/index.vue'
|
import sideButton from '~/pages/LiveRoom/components/SideButton/index.vue'
|
||||||
import broadcast from '~/pages/liveRoom/components/Broadcast/index.vue'
|
import broadcast from '~/pages/LiveRoom/components/Broadcast/index.vue'
|
||||||
import {liveStore} from "~/stores/live/index.js";
|
import {liveStore} from "~/stores/live/index.js";
|
||||||
import paymentResults from '~/pages/liveRoom/components/PaymentResults/index.vue'
|
import paymentResults from '~/pages/LiveRoom/components/PaymentResults/index.vue'
|
||||||
import paymentInput from '~/pages/liveRoom/components/PaymentInput/index.vue'
|
import paymentInput from '~/pages/LiveRoom/components/PaymentInput/index.vue'
|
||||||
import xButton from '@/components/x-button/index.vue'
|
import PressableButton from '~/pages/LiveRoom/components/SideButton/PressableButton.vue'
|
||||||
|
|
||||||
const player = ref(null)
|
const player = ref(null)
|
||||||
const {quoteStatus, changeStatus, show, playerId, show1} = liveStore()
|
const {quoteStatus, changeStatus, show, playerId, show1} = liveStore()
|
||||||
const isPlayerReady = ref(false)
|
const isPlayerReady = ref(false)
|
||||||
@ -109,18 +110,18 @@ watch(()=>{
|
|||||||
<div class="absolute left-1/2 transform -translate-x-1/2 flex flex-col items-center" style="bottom:calc(var(--safe-area-inset-bottom) + 26px)">
|
<div class="absolute left-1/2 transform -translate-x-1/2 flex flex-col items-center" style="bottom:calc(var(--safe-area-inset-bottom) + 26px)">
|
||||||
<div class="text-16px text-#FFB25F font-600">
|
<div class="text-16px text-#FFB25F font-600">
|
||||||
当前价:RMB
|
当前价:RMB
|
||||||
<van-rolling-text class="my-rolling-text" :start-num="0" :duration="0.5" :target-num="3000" direction="up"/>
|
<van-rolling-text class="my-rolling-text" :start-num="0" :target-num="3000" direction="up"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-16px text-#fff font-600">
|
<div class="text-16px text-#fff font-600">
|
||||||
下口价:RMB
|
下口价:RMB
|
||||||
<van-rolling-text class="my-rolling-text1" :start-num="0" :duration="0.5" :target-num="3500" direction="up"/>
|
<van-rolling-text class="my-rolling-text1" :start-num="0" :target-num="3500" direction="up"/>
|
||||||
</div>
|
</div>
|
||||||
<x-button>
|
<PressableButton>
|
||||||
<div
|
<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`">
|
: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' : '点击"开启出价",即刻参与竞拍 ' }}
|
{{ quoteStatus ? '确认出价 RMB 3,000' : '点击"开启出价",即刻参与竞拍 ' }}
|
||||||
</div>
|
</div>
|
||||||
</x-button>
|
</PressableButton>
|
||||||
<broadcast></broadcast>
|
<broadcast></broadcast>
|
||||||
</div>
|
</div>
|
||||||
<paymentInput v-model:show="show"/>
|
<paymentInput v-model:show="show"/>
|
@ -1,211 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
|
||||||
import { useI18n } from 'vue-i18n'
|
|
||||||
import { senCode, userLogin } from "@/api/auth/index.js";
|
|
||||||
import { authStore } from "~/stores/auth/index.js";
|
|
||||||
import { message } from '@/components/x-message/useMessage.js'
|
|
||||||
// ... 现有导入 ...
|
|
||||||
import FingerprintJS from '@fingerprintjs/fingerprintjs'
|
|
||||||
const { userInfo, token,fingerprint } = authStore()
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const { locale } = useI18n()
|
|
||||||
definePageMeta({
|
|
||||||
title: '登录',
|
|
||||||
i18n: 'login.title',
|
|
||||||
})
|
|
||||||
const loadingRef = ref({
|
|
||||||
loading1: false,
|
|
||||||
loading2: false,
|
|
||||||
})
|
|
||||||
const password = ref('')
|
|
||||||
const loginType = ref(0)
|
|
||||||
const interval = ref(null)
|
|
||||||
const startCountdown = () => {
|
|
||||||
if (interval.value) {
|
|
||||||
clearInterval(interval.value);
|
|
||||||
}
|
|
||||||
countdown.value = 60;
|
|
||||||
interval.value = setInterval(() => {
|
|
||||||
if (countdown.value > 0) {
|
|
||||||
countdown.value--;
|
|
||||||
} else {
|
|
||||||
clearInterval(interval.value);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
const countdown = ref(0);
|
|
||||||
const phoneNum = ref('17630920520')
|
|
||||||
const code = ref('123789')
|
|
||||||
const pane = ref(0)
|
|
||||||
const showKeyboard = ref(false);
|
|
||||||
const getFingerprint = async () => {
|
|
||||||
const fp = await FingerprintJS.load()
|
|
||||||
const result = await fp.get()
|
|
||||||
return result.visitorId // 稳定的指纹哈希值
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果指纹存在,且指纹和指纹库中的指纹一致,则直接登录
|
|
||||||
const checkFingerprint = async () => {
|
|
||||||
const tempFingerprint = await getFingerprint()
|
|
||||||
if (fingerprint && fingerprint === tempFingerprint) {
|
|
||||||
await router.push('/collectCode/mine')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkFingerprint()
|
|
||||||
const vanSwipeRef = ref(null)
|
|
||||||
const getCode = async () => {
|
|
||||||
loadingRef.value.loading1 = true
|
|
||||||
const res = await senCode({
|
|
||||||
telNum: phoneNum.value,
|
|
||||||
zone: '86'
|
|
||||||
})
|
|
||||||
loadingRef.value.loading1 = false
|
|
||||||
if (res.status === 0) {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
pane.value = 1
|
|
||||||
vanSwipeRef.value?.swipeTo(pane.value)
|
|
||||||
showKeyboard.value = true
|
|
||||||
startCountdown();
|
|
||||||
/* pane.value = 1
|
|
||||||
vanSwipeRef.value?.swipeTo(pane.value)
|
|
||||||
showKeyboard.value=true
|
|
||||||
startCountdown();*/
|
|
||||||
|
|
||||||
}
|
|
||||||
const changeToPwd = async () => {
|
|
||||||
loginType.value = loginType.value === 0 ? 1 : 0
|
|
||||||
}
|
|
||||||
const goBack = () => {
|
|
||||||
code.value = ''
|
|
||||||
pane.value = 0
|
|
||||||
vanSwipeRef.value?.swipeTo(pane.value)
|
|
||||||
}
|
|
||||||
const goLogin = async () => {
|
|
||||||
loadingRef.value.loading2 = true
|
|
||||||
const res = await userLogin({
|
|
||||||
telNum: phoneNum.value,
|
|
||||||
zone: '86',
|
|
||||||
code: code.value
|
|
||||||
})
|
|
||||||
if (res.status === 0) {
|
|
||||||
userInfo.value = res.data.accountInfo
|
|
||||||
token.value = res.data.token
|
|
||||||
fingerprint.value = await getFingerprint()
|
|
||||||
|
|
||||||
await router.push('/collectCode/mine');
|
|
||||||
|
|
||||||
}
|
|
||||||
loadingRef.value.loading2 = false
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="h-[100vh] w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-cover px-[31px] pt-[86px]">
|
|
||||||
<div class="w-full flex justify-center mb-[100px] flex-col items-center">
|
|
||||||
<img class="h-[105px] w-[189px]" src="@/static/images/ghfggff.png" alt="">
|
|
||||||
<img class="h-[29px] w-[108px]" src="@/static/images/qrcodetext.png" alt="">
|
|
||||||
</div>
|
|
||||||
<van-swipe ref="vanSwipeRef" :show-indicators="false" :touchable="false" :lazy-render="true" :loop="false">
|
|
||||||
<van-swipe-item>
|
|
||||||
<div v-show="pane === 0">
|
|
||||||
<div class="">
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field v-model="phoneNum" clearable :placeholder="$t('login.phonePlaceholder')">
|
|
||||||
<template #label>
|
|
||||||
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
|
||||||
手机号
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]" v-show="loginType === 1">
|
|
||||||
<van-field v-model="password" clearable :placeholder="$t('login.passwordPlaceholder')">
|
|
||||||
<template #label>
|
|
||||||
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
|
||||||
密码
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-end mt-[10px]" @click="changeToPwd">
|
|
||||||
<div class="text-[14px] text-[#2B53AC]">
|
|
||||||
{{ loginType === 0 ? '密码登录' : '验证码登录' }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div />
|
|
||||||
</div>
|
|
||||||
<div class="mt-[55px]">
|
|
||||||
<div v-if="loginType === 0">
|
|
||||||
<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>
|
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{
|
|
||||||
$t('login.getCode')
|
|
||||||
}}</van-button>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<van-button type="primary" v-if="password" block :loading="loadingRef.loading2" :loading-text="$t('login.login')"
|
|
||||||
style="height: 48px;margin-top:10px" @click="goLogin">{{
|
|
||||||
$t('login.login')
|
|
||||||
}}</van-button>
|
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{
|
|
||||||
$t('login.login')
|
|
||||||
}}</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-swipe-item>
|
|
||||||
<van-swipe-item>
|
|
||||||
<div v-show="pane === 1">
|
|
||||||
<div class="flex mb-[16px]">
|
|
||||||
<div class="text-[16px] text-[#BDBDBD] mr-[10px]">{{ $t('login.hasSendTo') }}</div>
|
|
||||||
<div class="text-[16px] text-[#000]">+{{ selectedZone }} {{ phoneNum }}</div>
|
|
||||||
</div>
|
|
||||||
<van-password-input :value="code" :gutter="10" :mask="false" focused @focus="showKeyboard = true" />
|
|
||||||
<div :class="`${countdown > 0 ? 'text-#BDBDBD' : 'text-#2B53AC'} text-14px`">
|
|
||||||
{{ $t('login.reSend') }}<span v-if="countdown > 0">({{ countdown }})</span>
|
|
||||||
</div>
|
|
||||||
<div class="mt-[17px]">
|
|
||||||
|
|
||||||
<van-button v-if="code.length === 6" type="primary" block :loading="loadingRef.loading2"
|
|
||||||
:loading-text="$t('login.login')" style="height: 48px" @click="goLogin">{{
|
|
||||||
$t('login.login')
|
|
||||||
}}</van-button>
|
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{
|
|
||||||
$t('login.login')
|
|
||||||
}}</van-button>
|
|
||||||
</div>
|
|
||||||
<div class="mt-[17px]">
|
|
||||||
<van-button type="primary" @click="goBack" block style="height: 48px">{{ $t('login.back')
|
|
||||||
}}</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-swipe-item>
|
|
||||||
</van-swipe>
|
|
||||||
<van-number-keyboard v-model="code" :show="showKeyboard" @blur="showKeyboard = false" />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
:deep(.van-cell.van-field) {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.van-password-input) {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.van-password-input__item) {
|
|
||||||
border: 1px solid #E5E5E5;
|
|
||||||
width: 41px;
|
|
||||||
height: 41px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,55 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { userArtworks } from "~/api/goods/index.js";
|
|
||||||
import { authStore } from "~/stores/auth/index.js";
|
|
||||||
|
|
||||||
definePageMeta({
|
|
||||||
layout: 'default',
|
|
||||||
title: '收款二维码',
|
|
||||||
i18n: 'menu.profile',
|
|
||||||
})
|
|
||||||
const { userInfo } = authStore()
|
|
||||||
const initData = async () => {
|
|
||||||
const res = await userArtworks({})
|
|
||||||
if (res.status === 0) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
initData()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="w-[100vw] bg-[url('@/static/images/3532@2x.png')] bg-cover pt-43px flex-grow-1 flex flex-col">
|
|
||||||
<div class="flex items-center px-16px mb-43px">
|
|
||||||
<div class="mr-23px">
|
|
||||||
<img class="w-57px h-57px" src="@/static/images/5514@2x.png" alt="">
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="text-18px text-#181818">{{ userInfo.realName }}</div>
|
|
||||||
<div class="text-#575757 text-14px">{{ userInfo.telNum }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1 flex justify-end">
|
|
||||||
<img class="w-40px h-40px" src="@/static/images/logout.png" alt="">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<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-list finished-text="没有更多了">
|
|
||||||
<van-swipe-cell>
|
|
||||||
|
|
||||||
<van-cell :border="false" title="单元格" value="内容" />
|
|
||||||
<template #right>
|
|
||||||
<van-button square type="danger" text="删除" />
|
|
||||||
<van-button square type="primary" text="收藏" />
|
|
||||||
</template>
|
|
||||||
</van-swipe-cell>
|
|
||||||
</van-list>
|
|
||||||
</van-pull-refresh>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
53
app/pages/home/components/Column/index.vue
Normal file
53
app/pages/home/components/Column/index.vue
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<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>
|
@ -1,24 +0,0 @@
|
|||||||
<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,116 +1,90 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import Column from "~/pages/home/components/Column/index.vue";
|
||||||
import { useRect } from "@vant/use"
|
import {goodStore} from "~/stores/goods";
|
||||||
import { goodStore } from "@/stores/goods"
|
import {artworkDetail, artworkList} from "~/api/goods";
|
||||||
import DetailPopup from '../DetailPopup/index.vue'
|
import {useRect} from "@vant/use";
|
||||||
import MasonryWall from '@yeger/vue-masonry-wall'
|
const {itemList, pageRef,auctionDetail,liveRef,artWorkDetail,currentItem} = goodStore();
|
||||||
const {
|
const loading = ref(false);
|
||||||
itemList,
|
const showHeight = ref('');
|
||||||
pageRef,
|
const show = ref(false);
|
||||||
auctionDetail,
|
const loading1 = ref(false);
|
||||||
liveRef,
|
const finished = ref(false);
|
||||||
artWorkDetail,
|
const getArtworkList=async ()=>{
|
||||||
currentItem,
|
const res= await artworkList({auctionUuid: auctionDetail.value.uuid,...pageRef.value})
|
||||||
loading: storeLoading,
|
if (res.status===0){
|
||||||
getArtworkList,
|
if (Array.isArray(res.data.data)&&res.data.data?.length>0){
|
||||||
getArtworkDetail
|
itemList.value.push(...res.data.data)
|
||||||
} = goodStore()
|
}
|
||||||
|
if (!res.data.data){
|
||||||
const localState = ref({
|
finished.value=true
|
||||||
finished: false,
|
}
|
||||||
refreshing: false,
|
if (res.data.data?.length<pageRef.value.pageSize){
|
||||||
showDetail: false,
|
finished.value=true
|
||||||
showHeight: ''
|
}
|
||||||
})
|
pageRef.value.itemCount=res.data.count
|
||||||
// 加载更多
|
|
||||||
const loadMore = async () => {
|
|
||||||
pageRef.value.page++
|
|
||||||
const { finished } = await getArtworkList()
|
|
||||||
localState.value.finished = finished
|
|
||||||
}
|
|
||||||
|
|
||||||
// 刷新
|
|
||||||
const onRefresh = async () => {
|
|
||||||
try {
|
|
||||||
localState.value.refreshing = true
|
|
||||||
localState.value.finished = false
|
|
||||||
const { finished } = await getArtworkList(true)
|
|
||||||
localState.value.finished = finished
|
|
||||||
} finally {
|
|
||||||
localState.value.refreshing = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 打开详情
|
const loadData = async () => {
|
||||||
const openShow = async (item) => {
|
pageRef.value.page++
|
||||||
localState.value.showDetail = true
|
await getArtworkList()
|
||||||
currentItem.value = item
|
loading.value = false;
|
||||||
getArtworkDetail(item.uuid)
|
if (pageRef.value.itemCount <= itemList.value.length) {
|
||||||
|
finished.value = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const columns = computed(() => {
|
||||||
|
const result = [[], []];
|
||||||
|
itemList.value.forEach((item, index) => {
|
||||||
|
result[index % 2].push({...item, index});
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
const refreshData = async () => {
|
||||||
|
pageRef.value.page = 1
|
||||||
|
finished.value=false
|
||||||
|
const res= await artworkList({auctionUuid: auctionDetail.value.uuid,...pageRef.value})
|
||||||
|
if (res.status===0){
|
||||||
|
itemList.value=res.data.data
|
||||||
|
pageRef.value.itemCount=res.data.count
|
||||||
|
}
|
||||||
|
loading1.value = false
|
||||||
}
|
}
|
||||||
</script>
|
|
||||||
|
|
||||||
|
const getDetail=async ()=>{
|
||||||
|
const res=await artworkDetail({uuid:currentItem.value.uuid})
|
||||||
|
if (res.status===0){
|
||||||
|
artWorkDetail.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watch(itemList,(newValue)=>{
|
||||||
|
console.log('newValue',newValue)
|
||||||
|
|
||||||
|
})
|
||||||
|
const openShow = (item,index) => {
|
||||||
|
currentItem.value=item
|
||||||
|
getDetail()
|
||||||
|
const rect = useRect(liveRef.value.$el);
|
||||||
|
showHeight.value = rect.height;
|
||||||
|
nextTick(() => {
|
||||||
|
show.value = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="px-[16px] pt-[16px]">
|
<div class="px-[16px] pt-[16px]">
|
||||||
<van-pull-refresh
|
<van-pull-refresh v-model="loading1" success-text="刷新成功" @refresh="refreshData">
|
||||||
v-model="localState.refreshing"
|
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了"
|
||||||
success-text="刷新成功"
|
@load="loadData">
|
||||||
:success-duration="700"
|
|
||||||
@refresh="onRefresh"
|
|
||||||
>
|
|
||||||
<template #success>
|
|
||||||
<van-icon name="success" /> 刷新成功
|
|
||||||
</template>
|
|
||||||
<van-list
|
|
||||||
v-model:loading="storeLoading"
|
|
||||||
:finished="localState.finished"
|
|
||||||
finished-text="没有更多了"
|
|
||||||
@load="loadMore"
|
|
||||||
>
|
|
||||||
<div class="w-full flex gap-[16px]">
|
<div class="w-full flex gap-[16px]">
|
||||||
<masonry-wall :items="itemList" :ssr-columns="2" :maxColumns="2" :minColumns="2" :gap="5">
|
<Column v-for="(column, colIndex) in columns" :key="colIndex" :colIndex="colIndex" :items="column" @openShow="openShow" />
|
||||||
<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>
|
</div>
|
||||||
</van-list>
|
</van-list>
|
||||||
</van-pull-refresh>
|
</van-pull-refresh>
|
||||||
<DetailPopup v-model:show="localState.showDetail"></DetailPopup>
|
<van-action-sheet teleport="#__nuxt" :round="false" v-model:show="show" title="拍品详情">
|
||||||
|
<div class="content bg-[#F0F0F0]" :style="`height: calc(100vh - ${showHeight + 85}px)`">
|
||||||
|
<itemDetail/>
|
||||||
|
</div>
|
||||||
|
</van-action-sheet>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.content {
|
|
||||||
overflow-y: auto;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,19 +1,25 @@
|
|||||||
<script setup>
|
<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 {goodStore} from "@/stores/goods/index.js";
|
||||||
import ItemList from './components/ItemList/index.vue'
|
import ItemList from './components/ItemList/index.vue'
|
||||||
import Cescribe from './components/Cescribe/index.vue'
|
import Cescribe from './components/Cescribe/index.vue'
|
||||||
const {fullLive, liveRef} = goodStore();
|
import {artworkList} from "~/api/goods/index.js";
|
||||||
|
const {fullLive,getAuctionDetail,auctionDetail,itemList,pageRef,liveRef} = goodStore();
|
||||||
|
definePageMeta({
|
||||||
|
layout: 'default',
|
||||||
|
i18n: 'menu.home',
|
||||||
|
})
|
||||||
const changeLive = () => {
|
const changeLive = () => {
|
||||||
fullLive.value = true;
|
fullLive.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<client-only>
|
<client-only>
|
||||||
<liveRoom @click="changeLive" :class="['changeLive', fullLive ? 'expanded' : 'collapsed']" ref="liveRef"
|
<LiveRoom @click="changeLive" :class="['changeLive', fullLive ? 'expanded' : 'collapsed']" ref="liveRef" :fullLive="fullLive"/>
|
||||||
:fullLive="fullLive"/>
|
</client-only>
|
||||||
</client-only>
|
|
||||||
<div v-show="!fullLive" class="bg-#fff">
|
<div v-show="!fullLive" class="bg-#fff">
|
||||||
<van-tabs sticky animated>
|
<van-tabs sticky animated>
|
||||||
<van-tab title="拍品列表">
|
<van-tab title="拍品列表">
|
||||||
@ -27,14 +33,12 @@ const changeLive = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style scoped lang="scss">
|
<style>
|
||||||
.ellipsis {
|
:root:root {
|
||||||
display: -webkit-box;
|
--van-action-sheet-header-height: 39px;
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
|
<style scoped lang="scss">
|
||||||
:deep(.van-swipe__indicator) {
|
:deep(.van-swipe__indicator) {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
@ -55,7 +59,7 @@ const changeLive = () => {
|
|||||||
.changeLive {
|
.changeLive {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: height 0.4s ease, transform 0.4s ease;
|
transition: height 0.5s ease, transform 0.5s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.changeLive.collapsed {
|
.changeLive.collapsed {
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import Home from './home/index.vue'
|
|
||||||
definePageMeta({
|
|
||||||
layout: 'default',
|
|
||||||
title: '主页',
|
|
||||||
i18n: 'menu.home',
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<Home/>
|
|
||||||
</template>
|
|
@ -1,61 +0,0 @@
|
|||||||
<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>
|
|
@ -158,7 +158,7 @@ const goLogin =async () => {
|
|||||||
<div />
|
<div />
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[55px]">
|
<div class="mt-[55px]">
|
||||||
<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 :loading="loadingRef.loading1" v-if="phoneNum" :loading-text="$t('login.getCode')" type="primary" block style="height: 48px" @click="getCode">{{ $t('login.getCode')
|
||||||
}}</van-button>
|
}}</van-button>
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.getCode')
|
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.getCode')
|
||||||
}}</van-button>
|
}}</van-button>
|
||||||
|
@ -1,36 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {userArtworks} from "~/api/goods/index.js";
|
import {userArtworks} from "~/api/goods/index.js";
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
import {authStore} from "~/stores/auth/index.js";
|
||||||
import xImage from '@/components/x-image/index.vue'
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'default',
|
layout: 'default',
|
||||||
title: '我的',
|
title: '我的',
|
||||||
i18n: 'menu.profile',
|
i18n: 'menu.profile',
|
||||||
})
|
})
|
||||||
const myList=ref([])
|
|
||||||
const showMyList=ref([])
|
|
||||||
const {userInfo}= authStore()
|
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 initData=async ()=>{
|
||||||
const res=await userArtworks({})
|
const res=await userArtworks({})
|
||||||
if (res.status===0){
|
if (res.status===0){
|
||||||
myList.value=res.data.data
|
|
||||||
showMyList.value=groupAndSortByDate(myList.value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initData()
|
initData()
|
||||||
@ -47,22 +28,55 @@ initData()
|
|||||||
<div class="text-#575757 text-14px">{{userInfo.telNum}}</div>
|
<div class="text-#575757 text-14px">{{userInfo.telNum}}</div>
|
||||||
</div>
|
</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="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 class="text-#000 text-16px border-b-3 border-b-#2B53AC h-36px">我的拍品</div>
|
||||||
</div>
|
</div>
|
||||||
<van-pull-refresh @refresh="initData">
|
<van-pull-refresh>
|
||||||
<van-list
|
<van-list
|
||||||
finished-text="没有更多了"
|
finished-text="没有更多了"
|
||||||
>
|
>
|
||||||
<div class="px-16px pt-14px" v-for="(item,index) of showMyList">
|
<div class="px-16px pt-14px">
|
||||||
<div class="text-#575757 text-14px mb-3px">{{item.userCreatedAt}}</div>
|
<div class="text-#575757 text-14px mb-3px">2025.01.12</div>
|
||||||
<div class="flex mb-22px" v-for="(item1,index1) of item.list">
|
<div class="flex mb-22px">
|
||||||
<div class="flex-shrink-0 mr-10px rounded-4px overflow-hidden">
|
<div class="flex-shrink-0 mr-10px">
|
||||||
<x-image class="w-80px h-80px" :src="item1?.auctionArtworkInfo?.artwork?.hdPic" alt=""/>
|
<img class="w-80px h-80px" src="@/static/images/ddfdcaer.png" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col justify-between">
|
<div class="flex flex-col justify-between">
|
||||||
<div class="text-#000 text-16px ellipsis line-height-21px">{{item1?.auctionArtworkInfo?.artworkTitle}}</div>
|
<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-#575757 text-14px line-height-none ">起拍价:RMB 1,000</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 class="text-#B58047 text-14px line-height-none">成交价:RMB 10,000</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@ const {userInfo}= authStore()
|
|||||||
<template>
|
<template>
|
||||||
<div class="text-#1A1A1A text-16px">
|
<div class="text-#1A1A1A text-16px">
|
||||||
<template v-if="type===0">
|
<template v-if="type===0">
|
||||||
<div class="flex mb-20px">
|
<div class="flex mb-20px" >
|
||||||
<div class="mr-10px">姓名:</div>
|
<div class="mr-10px">姓名:</div>
|
||||||
<div>{{userInfo.realName}}</div>
|
<div>{{userInfo.realName}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
<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>
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.3 KiB |
@ -1,21 +0,0 @@
|
|||||||
: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;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
background: var(--van-gray-1);
|
|
||||||
color-scheme: light;
|
|
||||||
}
|
|
||||||
|
|
||||||
html.dark {
|
|
||||||
background: #222;
|
|
||||||
color-scheme: dark;
|
|
||||||
}
|
|
@ -3,11 +3,9 @@ export const authStore = createGlobalState(() => {
|
|||||||
const token=useLocalStorage('token','')
|
const token=useLocalStorage('token','')
|
||||||
const RefreshToken=useLocalStorage('RefreshToken','')
|
const RefreshToken=useLocalStorage('RefreshToken','')
|
||||||
const userInfo=useLocalStorage('userInfo',{})
|
const userInfo=useLocalStorage('userInfo',{})
|
||||||
const fingerprint=useLocalStorage('fingerprint','')
|
|
||||||
return{
|
return{
|
||||||
userInfo,
|
userInfo,
|
||||||
RefreshToken,
|
RefreshToken,
|
||||||
token,
|
token
|
||||||
fingerprint
|
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -1,115 +1,40 @@
|
|||||||
import { createGlobalState } from '@vueuse/core'
|
import {createGlobalState} from '@vueuse/core'
|
||||||
import { ref } from 'vue'
|
import {artworkList, defaultDetail} from "~/api/goods/index.js";
|
||||||
import { artworkList, defaultDetail, artworkDetail } from "~/api/goods/index.js"
|
|
||||||
|
|
||||||
export const goodStore = createGlobalState(() => {
|
export const goodStore = createGlobalState(() => {
|
||||||
// 状态定义
|
|
||||||
const actionDetails = ref({})
|
const actionDetails = ref({})
|
||||||
const fullLive = ref(false)
|
const fullLive = ref(false)
|
||||||
const liveRef = ref(null)
|
const liveRef = ref(null);
|
||||||
const currentItem = ref({})
|
const currentItem=ref({})
|
||||||
const myArtWorks = ref([])
|
const myArtWorks=ref([])
|
||||||
const pageRef = ref({
|
const pageRef = ref({
|
||||||
page: 0,
|
page: 0,
|
||||||
pageSize: 5,
|
pageSize: 5,
|
||||||
itemCount: 0
|
itemCount: 0
|
||||||
})
|
})
|
||||||
const artWorkDetail = ref(null)
|
const artWorkDetail=ref(null)
|
||||||
const itemList = ref([])
|
const itemList = ref([])
|
||||||
const auctionDetail = ref({})
|
const auctionDetail = ref({})
|
||||||
const loading = ref(false)
|
|
||||||
const error = ref(null)
|
|
||||||
|
|
||||||
// 重置分页
|
|
||||||
const resetPage = () => {
|
|
||||||
pageRef.value.page = 1
|
|
||||||
pageRef.value.pageSize=5
|
|
||||||
pageRef.value.itemCount = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取拍卖详情
|
|
||||||
const getAuctionDetail = async () => {
|
const getAuctionDetail = async () => {
|
||||||
try {
|
const res = await defaultDetail({})
|
||||||
loading.value = true
|
if (res.status === 0) {
|
||||||
const res = await defaultDetail({})
|
auctionDetail.value = res.data
|
||||||
if (res.status === 0) {
|
|
||||||
auctionDetail.value = res.data
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取拍卖详情错误:', err)
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const getArtworkList = async (page = pageRef.value) => {
|
||||||
// 获取艺术品列表
|
return artworkList({auctionUuid: auctionDetail.value.uuid, ...page})
|
||||||
const getArtworkList = async (isRefresh = false) => {
|
|
||||||
if (isRefresh) {
|
|
||||||
resetPage()
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
loading.value = true
|
|
||||||
const res = await artworkList({
|
|
||||||
auctionUuid: auctionDetail.value.uuid,
|
|
||||||
page: pageRef.value.page,
|
|
||||||
pageSize: pageRef.value.pageSize
|
|
||||||
})
|
|
||||||
if (res.status === 0) {
|
|
||||||
const newItems = res.data.data || []
|
|
||||||
|
|
||||||
if (isRefresh) {
|
|
||||||
itemList.value = newItems
|
|
||||||
} else {
|
|
||||||
itemList.value = [...itemList.value, ...newItems]
|
|
||||||
}
|
|
||||||
|
|
||||||
pageRef.value.itemCount = res.data.count || 0
|
|
||||||
return {
|
|
||||||
finished: !newItems.length || newItems.length < pageRef.value.pageSize,
|
|
||||||
items: newItems
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { finished: true, items: [] }
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取艺术品列表错误:', err)
|
|
||||||
return { finished: true, items: [] }
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取艺术品详情
|
|
||||||
const getArtworkDetail = async (uuid) => {
|
|
||||||
try {
|
|
||||||
loading.value = true
|
|
||||||
const res = await artworkDetail({ uuid })
|
|
||||||
if (res.status === 0) {
|
|
||||||
artWorkDetail.value = res.data
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取艺术品详情错误:', err)
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// 状态
|
|
||||||
actionDetails,
|
|
||||||
fullLive,
|
|
||||||
liveRef,
|
|
||||||
currentItem,
|
|
||||||
myArtWorks,
|
myArtWorks,
|
||||||
pageRef,
|
currentItem,
|
||||||
artWorkDetail,
|
artWorkDetail,
|
||||||
itemList,
|
liveRef,
|
||||||
auctionDetail,
|
pageRef,
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
// 方法
|
|
||||||
getAuctionDetail,
|
|
||||||
getArtworkList,
|
getArtworkList,
|
||||||
getArtworkDetail,
|
auctionDetail,
|
||||||
resetPage
|
getAuctionDetail,
|
||||||
|
actionDetails,
|
||||||
|
itemList,
|
||||||
|
fullLive
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* 格式化价格
|
|
||||||
* @param {number} price - 价格数值
|
|
||||||
* @param {string} currency - 货币符号,默认为 ¥
|
|
||||||
* @returns {string} 格式化后的价格字符串
|
|
||||||
*/
|
|
||||||
export const formatPrice = (price, currency = '¥') => {
|
|
||||||
if (price == null || isNaN(price)) return `${currency}0`
|
|
||||||
|
|
||||||
// 将价格转换为数字
|
|
||||||
const numPrice = Number(price)
|
|
||||||
|
|
||||||
// 处理小数点,保留两位小数
|
|
||||||
const formattedPrice = numPrice.toFixed(2)
|
|
||||||
|
|
||||||
// 添加千位分隔符
|
|
||||||
const parts = formattedPrice.toString().split('.')
|
|
||||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
||||||
|
|
||||||
return `${currency}${parts.join('.')}`
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化数字
|
|
||||||
* @param {number} num - 需要格式化的数字
|
|
||||||
* @returns {string} 格式化后的数字字符串
|
|
||||||
*/
|
|
||||||
export const formatNumber = (num) => {
|
|
||||||
if (num == null || isNaN(num)) return '0'
|
|
||||||
|
|
||||||
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化百分比
|
|
||||||
* @param {number} value - 需要格式化的值
|
|
||||||
* @param {number} decimals - 小数位数,默认为 2
|
|
||||||
* @returns {string} 格式化后的百分比字符串
|
|
||||||
*/
|
|
||||||
export const formatPercent = (value, decimals = 2) => {
|
|
||||||
if (value == null || isNaN(value)) return '0%'
|
|
||||||
|
|
||||||
return `${(Number(value) * 100).toFixed(decimals)}%`
|
|
||||||
}
|
|
@ -5,18 +5,30 @@ import { currentLocales } from './i18n/i18n'
|
|||||||
const envFile = process.env.ENV_FILE || '.env.test'
|
const envFile = process.env.ENV_FILE || '.env.test'
|
||||||
dotenv.config({ path: `./env/${envFile}` })
|
dotenv.config({ path: `./env/${envFile}` })
|
||||||
const publicConfig = Object.entries(process.env)
|
const publicConfig = Object.entries(process.env)
|
||||||
.filter(([key]) => key.startsWith('NUXT_PUBLIC_'))
|
.filter(([key]) => key.startsWith('NUXT_PUBLIC_'))
|
||||||
.reduce((config, [key, value]) => {
|
.reduce((config, [key, value]) => {
|
||||||
config[key] = value
|
config[key] = value
|
||||||
return config
|
return config
|
||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
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'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
modules: [
|
modules: [
|
||||||
'@vant/nuxt',
|
'@vant/nuxt',
|
||||||
'@unocss/nuxt',
|
'@unocss/nuxt',
|
||||||
'@nuxt/image',
|
|
||||||
'@nuxtjs/color-mode',
|
'@nuxtjs/color-mode',
|
||||||
'@nuxtjs/i18n',
|
'@nuxtjs/i18n',
|
||||||
],
|
],
|
||||||
@ -29,7 +41,9 @@ export default defineNuxtConfig({
|
|||||||
|
|
||||||
css: [
|
css: [
|
||||||
'@unocss/reset/tailwind.css',
|
'@unocss/reset/tailwind.css',
|
||||||
'@/static/styles/default-theme.css',
|
'./app/styles/vars.css',
|
||||||
|
'./app/styles/global.css',
|
||||||
|
'./app/styles/default-theme.css',
|
||||||
],
|
],
|
||||||
|
|
||||||
postcss: {
|
postcss: {
|
||||||
@ -76,7 +90,7 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
|
|
||||||
app: {
|
app: {
|
||||||
layoutTransition: {
|
layoutTransition: {
|
||||||
name: 'layout',
|
name: 'layout',
|
||||||
mode: 'out-in'
|
mode: 'out-in'
|
||||||
},
|
},
|
||||||
|
@ -17,11 +17,9 @@
|
|||||||
"start": "cross-env ENV_FILE=.env.prod nuxt start"
|
"start": "cross-env ENV_FILE=.env.prod nuxt start"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fingerprintjs/fingerprintjs": "^4.5.1",
|
|
||||||
"@nuxtjs/color-mode": "^3.5.2",
|
"@nuxtjs/color-mode": "^3.5.2",
|
||||||
"@nuxtjs/i18n": "^9.1.1",
|
"@nuxtjs/i18n": "^9.1.1",
|
||||||
"@vueuse/core": "^12.4.0",
|
"@vueuse/core": "^12.4.0",
|
||||||
"@yeger/vue-masonry-wall": "^5.0.17",
|
|
||||||
"aliyun-aliplayer": "^2.28.5",
|
"aliyun-aliplayer": "^2.28.5",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
@ -34,7 +32,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/carbon": "^1.2.5",
|
"@iconify-json/carbon": "^1.2.5",
|
||||||
"@nuxt/image": "^1.9.0",
|
|
||||||
"@unocss/nuxt": "0.65.2",
|
"@unocss/nuxt": "0.65.2",
|
||||||
"@unocss/preset-rem-to-px": "0.65.2",
|
"@unocss/preset-rem-to-px": "0.65.2",
|
||||||
"@vant/nuxt": "^1.0.6",
|
"@vant/nuxt": "^1.0.6",
|
||||||
|
636
pnpm-lock.yaml
636
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user