Compare commits
25 Commits
65f8d2d1e9
...
9334819414
Author | SHA1 | Date | |
---|---|---|---|
|
9334819414 | ||
|
86198811aa | ||
|
10cba595b0 | ||
|
eb02645658 | ||
|
69ad600f0d | ||
|
34add8d226 | ||
|
e8a89b184e | ||
|
f1bd2b183f | ||
|
ad19345db6 | ||
|
7e4fbc84ad | ||
|
a791248752 | ||
|
c86e449d52 | ||
|
36793c5c5a | ||
|
47aa573641 | ||
|
aec3825a3b | ||
|
5d645a8106 | ||
|
510b839a1b | ||
|
bd56b05e60 | ||
|
8d01653dac | ||
|
2e08e6efcb | ||
|
41ad9aeed8 | ||
|
ff053a5a8c | ||
|
e30b993601 | ||
|
b876aac28a | ||
|
7916b009e6 |
23
app/api-collect-code/auth/index.js
Normal file
23
app/api-collect-code/auth/index.js
Normal file
@ -0,0 +1,23 @@
|
||||
import { request } from '@/api/http.js'
|
||||
|
||||
export async function checkPhone(data) {
|
||||
return await request({
|
||||
url:'/api/v1/common/check/phone',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
export async function userSend(data) {
|
||||
return await request( {
|
||||
url:'/api/v1/m/user/send',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
export async function mobileLogin(data) {
|
||||
return await request( {
|
||||
url:'/api/v1/m/user/mobile/login',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
31
app/api-collect-code/goods/index.js
Normal file
31
app/api-collect-code/goods/index.js
Normal file
@ -0,0 +1,31 @@
|
||||
import { request } from '@/api/http.js'
|
||||
|
||||
export async function offlineQrcodeList(data) {
|
||||
return await request( {
|
||||
url:'/api/v1/offlineQrcode/query',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
export async function offlineQrcodeCreate(data) {
|
||||
return await request ({
|
||||
url:'/api/v1/offlineQrcode/create',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
export async function offlineQrcodeDelete(data) {
|
||||
return await request ({
|
||||
url:'/api/v1/offlineQrcode/delete',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
export async function userArtworks(data) {
|
||||
|
||||
return await request( {
|
||||
url:'/api/v1/m/user/artworks',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
128
app/api-collect-code/http.js
Normal file
128
app/api-collect-code/http.js
Normal file
@ -0,0 +1,128 @@
|
||||
import {useRuntimeConfig} from '#app'
|
||||
import {ofetch} from 'ofetch'
|
||||
import {message} from '@/components/x-message/useMessage.js'
|
||||
import {codeAuthStore} from "@/stores-collect-code/auth/index.js"
|
||||
|
||||
let httpStatusErrorHandler
|
||||
let http
|
||||
|
||||
// HTTP 状态码映射
|
||||
const HTTP_STATUS_MAP = {
|
||||
400: '请求参数错误',
|
||||
401: '未授权或登录过期',
|
||||
403: '访问被禁止',
|
||||
404: '请求的资源不存在',
|
||||
500: '服务器内部错误',
|
||||
502: '网关错误',
|
||||
503: '服务暂时不可用',
|
||||
504: '网关超时'
|
||||
}
|
||||
|
||||
export function setupHttp() {
|
||||
if (http) return http
|
||||
const {token}= codeAuthStore()
|
||||
const config = useRuntimeConfig()
|
||||
const baseURL = config.public.NUXT_PUBLIC_API_COLLECT_CODE
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const defaultOptions = {
|
||||
baseURL,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
timeout: 15000, // 15秒超时
|
||||
retry: 3,
|
||||
retryDelay: 1000,
|
||||
}
|
||||
|
||||
http = ofetch.create({
|
||||
...defaultOptions,
|
||||
|
||||
// 请求拦截
|
||||
async onRequest({ options, request }) {
|
||||
// 添加 token
|
||||
options.headers = {
|
||||
...options.headers,
|
||||
Authorization: token.value
|
||||
}
|
||||
|
||||
// GET 请求添加时间戳防止缓存
|
||||
if (request.toLowerCase().includes('get')) {
|
||||
options.params = {
|
||||
...options.params,
|
||||
_t: Date.now()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 响应拦截
|
||||
async onResponse({ response }) {
|
||||
const data = response._data
|
||||
|
||||
// 处理业务错误
|
||||
if (data.status === 1) {
|
||||
message.error(data.msg || '操作失败')
|
||||
}
|
||||
|
||||
// 处理登录失效
|
||||
if (data.status === 401) {
|
||||
message.error('登录已过期,请重新登录')
|
||||
token.value = '' // 清除 token
|
||||
router.replace('/collectCode/login')
|
||||
}
|
||||
|
||||
return response
|
||||
},
|
||||
|
||||
// 响应错误处理
|
||||
async onResponseError({ response, request }) {
|
||||
// 网络错误
|
||||
if (!response) {
|
||||
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)
|
||||
}
|
||||
|
||||
message.error(errorMessage)
|
||||
return Promise.reject(data)
|
||||
},
|
||||
})
|
||||
|
||||
return http
|
||||
}
|
||||
|
||||
export function createAbortController() {
|
||||
return new AbortController()
|
||||
}
|
||||
|
||||
export function injectHttpStatusErrorHandler(handler) {
|
||||
httpStatusErrorHandler = handler
|
||||
}
|
||||
|
||||
export function getHttp() {
|
||||
if (!http) {
|
||||
throw new Error('HTTP client not initialized. Call setupHttp first.')
|
||||
}
|
||||
return http
|
||||
}
|
||||
|
||||
// 导出请求工具函数
|
||||
export async function request({url,...options}) {
|
||||
const http = getHttp()
|
||||
try {
|
||||
return await http(url, {...options,body:options.data})
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
@ -30,3 +30,27 @@ export async function userArtworks(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
export async function userArtwork(data) {
|
||||
|
||||
return await request( {
|
||||
url:'/api/v1/m/user/artwork',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
export async function artworkBuy(data) {
|
||||
|
||||
return await request( {
|
||||
url:'/api/v1/m/artwork/buy',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
export async function logSendlog(data) {
|
||||
|
||||
return await request( {
|
||||
url:'/api/v1/m/auction/log/sendlog',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
@ -51,6 +51,9 @@ provide('slideDirection', slideDirection)
|
||||
</template>
|
||||
|
||||
<style>
|
||||
:root:root {
|
||||
--van-dialog-radius: 8px
|
||||
}
|
||||
.slide-left-enter-active,
|
||||
.slide-left-leave-active,
|
||||
.slide-right-enter-active,
|
||||
@ -79,4 +82,5 @@ provide('slideDirection', slideDirection)
|
||||
:root {
|
||||
--safe-area-inset-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
</style>
|
@ -12,6 +12,7 @@ const show = computed(() => {
|
||||
const initData=()=>{
|
||||
active.value=route.path==='/profile'?1:0
|
||||
}
|
||||
watchEffect(initData)
|
||||
onMounted(()=>{
|
||||
initData()
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { useAppHeaderRouteNames as routeWhiteList } from '~/config'
|
||||
import { useAppHeaderRouteNames as routeWhiteList } from '@/config'
|
||||
import { goodStore } from "@/stores/goods/index.js";
|
||||
const { fullLive } = goodStore()
|
||||
const route = useRoute()
|
||||
|
207
app/components/floatingVideo/index.vue
Normal file
207
app/components/floatingVideo/index.vue
Normal file
@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<div
|
||||
v-show="isVisible"
|
||||
:class="['floating-video', { minimized: isMinimized }]"
|
||||
class="!aspect-video"
|
||||
:style="[positionStyle, containerStyle]"
|
||||
@touchstart.prevent="handleTouchStart"
|
||||
@touchmove.prevent="handleTouchMove"
|
||||
@touchend="handleTouchEnd"
|
||||
>
|
||||
<video
|
||||
ref="videoRef"
|
||||
class="video-player "
|
||||
controls
|
||||
@loadedmetadata="handleVideoMetadata"
|
||||
>
|
||||
<source src="@/static/video/example.mp4" type="video/mp4" />
|
||||
您的浏览器不支持 HTML5 视频。
|
||||
</video>
|
||||
<div class="control-bar">
|
||||
<div class="minimize-btn" @click="toggleMinimize">
|
||||
<span v-if="isMinimized">⤢</span>
|
||||
<span v-else>⤓</span>
|
||||
</div>
|
||||
<div class="close-btn" @click="closeVideo">✕</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const videoRef = ref(null)
|
||||
const aspectRatio = ref(16 / 9) // 默认宽高比
|
||||
const isMinimized = ref(false)
|
||||
const position = ref({ x: 20, y: 20 })
|
||||
const isDragging = ref(false)
|
||||
const dragStart = ref({ x: 0, y: 0 })
|
||||
|
||||
// 初始化窗口尺寸为0
|
||||
const windowSize = ref({
|
||||
width: 0,
|
||||
height: 0
|
||||
})
|
||||
|
||||
const handleVideoMetadata = () => {
|
||||
const video = videoRef.value
|
||||
if (video.videoWidth && video.videoHeight) {
|
||||
aspectRatio.value = video.videoWidth / video.videoHeight
|
||||
}
|
||||
}
|
||||
|
||||
const containerDimensions = computed(() => {
|
||||
const baseWidth = isMinimized.value ? 150 : 300
|
||||
const height = baseWidth / aspectRatio.value
|
||||
return { width: baseWidth, height }
|
||||
})
|
||||
|
||||
const containerStyle = computed(() => {
|
||||
return {
|
||||
width: `${containerDimensions.value.width}px`,
|
||||
height: `${containerDimensions.value.height}px`
|
||||
}
|
||||
})
|
||||
|
||||
const positionStyle = computed(() => ({
|
||||
transform: `translate3d(${position.value.x}px, ${position.value.y}px, 0)`
|
||||
}))
|
||||
|
||||
const handleTouchStart = (event) => {
|
||||
isDragging.value = true
|
||||
const touch = event.touches[0]
|
||||
dragStart.value = {
|
||||
x: touch.clientX - position.value.x,
|
||||
y: touch.clientY - position.value.y
|
||||
}
|
||||
}
|
||||
|
||||
const handleTouchMove = (event) => {
|
||||
if (!isDragging.value) return
|
||||
|
||||
const touch = event.touches[0]
|
||||
let newX = touch.clientX - dragStart.value.x
|
||||
let newY = touch.clientY - dragStart.value.y
|
||||
|
||||
// 添加边界检测
|
||||
const maxX = windowSize.value.width - containerDimensions.value.width
|
||||
const maxY = windowSize.value.height - containerDimensions.value.height
|
||||
|
||||
newX = Math.max(0, Math.min(newX, maxX))
|
||||
newY = Math.max(0, Math.min(newY, maxY))
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
position.value = { x: newX, y: newY }
|
||||
})
|
||||
}
|
||||
|
||||
const handleTouchEnd = () => {
|
||||
isDragging.value = false
|
||||
}
|
||||
|
||||
const toggleMinimize = () => {
|
||||
isMinimized.value = !isMinimized.value
|
||||
|
||||
const maxX = windowSize.value.width - containerDimensions.value.width
|
||||
const maxY = windowSize.value.height - containerDimensions.value.height
|
||||
|
||||
position.value = {
|
||||
x: Math.max(0, Math.min(position.value.x, maxX)),
|
||||
y: Math.max(0, Math.min(position.value.y, maxY))
|
||||
}
|
||||
}
|
||||
|
||||
const closeVideo = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
const handleResize = () => {
|
||||
windowSize.value = {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
}
|
||||
|
||||
const maxX = windowSize.value.width - containerDimensions.value.width
|
||||
const maxY = windowSize.value.height - containerDimensions.value.height
|
||||
|
||||
position.value = {
|
||||
x: Math.max(0, Math.min(position.value.x, maxX)),
|
||||
y: Math.max(0, Math.min(position.value.y, maxY))
|
||||
}
|
||||
}
|
||||
|
||||
// 在组件挂载后初始化窗口尺寸和事件监听
|
||||
onMounted(() => {
|
||||
// 初始化窗口尺寸
|
||||
windowSize.value = {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
}
|
||||
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 样式部分保持不变 */
|
||||
.floating-video {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
background: #000;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
transition: width 0.3s ease, height 0.3s ease;
|
||||
overflow: hidden;
|
||||
transform: translate3d(0, 0, 0);
|
||||
will-change: transform;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.video-player {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: fill!important;
|
||||
}
|
||||
|
||||
.control-bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), transparent);
|
||||
}
|
||||
|
||||
.minimize-btn,
|
||||
.close-btn {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.minimize-btn:hover,
|
||||
.close-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
</style>
|
@ -1,30 +1,28 @@
|
||||
<script setup>
|
||||
/*
|
||||
* 此组件的目的是使用该组件包裹的内容具有按压状态效果
|
||||
* */
|
||||
import {ref, defineEmits} from "vue";
|
||||
|
||||
const emit = defineEmits(["click"]);
|
||||
import { ref } from "vue";
|
||||
|
||||
const isButtonActive = ref(false);
|
||||
|
||||
const handleButtonPress = () => {
|
||||
const handleButtonPress = (event) => {
|
||||
event.stopPropagation();
|
||||
isButtonActive.value = true;
|
||||
};
|
||||
const handleButtonRelease = () => {
|
||||
|
||||
const handleButtonRelease = (event) => {
|
||||
event.stopPropagation();
|
||||
isButtonActive.value = false;
|
||||
emit("click")
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
'transition-all duration-200',
|
||||
isButtonActive ? 'scale-95' : ''
|
||||
]"
|
||||
@touchstart="handleButtonPress"
|
||||
@touchend="handleButtonRelease"
|
||||
@touchstart.stop="handleButtonPress"
|
||||
@touchend.stop="handleButtonRelease"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
@ -36,18 +36,12 @@ const showImage = () => {
|
||||
<template>
|
||||
|
||||
<nuxt-img
|
||||
v-if="src"
|
||||
loading="lazy"
|
||||
v-bind="{ ...props, ...$attrs }"
|
||||
style="object-fit: cover"
|
||||
@click="showImage"
|
||||
:src="src"
|
||||
:sizes="sizes"
|
||||
:format="format"
|
||||
:quality="quality"
|
||||
placeholder
|
||||
/>
|
||||
<van-empty v-else description="暂无" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
BIN
app/components/x-message/images/info.png
Normal file
BIN
app/components/x-message/images/info.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 932 B |
@ -1,21 +1,65 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import MessageContent from './message/index.vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const visible = ref(false)
|
||||
const messageType = ref('success')
|
||||
const messageText = ref('')
|
||||
const messageType = ref('')
|
||||
const showIcon = ref(true)
|
||||
const customStyle = ref({})
|
||||
const title = ref({})
|
||||
const subTitle = ref({})
|
||||
|
||||
const containerStyle = computed(() => {
|
||||
const { top, bottom, left, right, transform, ...otherStyles } = customStyle.value || {}
|
||||
|
||||
const baseStyle = {
|
||||
position: 'fixed',
|
||||
zIndex: 9999
|
||||
}
|
||||
|
||||
const horizontalPosition = left || right
|
||||
? { left, right }
|
||||
: { left: '50%', transform: 'translateX(-50%)' }
|
||||
|
||||
const verticalPosition = {}
|
||||
if (bottom !== undefined) {
|
||||
verticalPosition.bottom = bottom
|
||||
} else {
|
||||
verticalPosition.top = top || '50px'
|
||||
}
|
||||
|
||||
return {
|
||||
...baseStyle,
|
||||
...horizontalPosition,
|
||||
...verticalPosition,
|
||||
...otherStyles
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['after-leave'])
|
||||
|
||||
const showMessage = ({ type = 'warning', message, duration = 2000 }) => {
|
||||
messageText.value = message
|
||||
messageType.value = type
|
||||
const showMessage = (options) => {
|
||||
if (typeof options === 'string') {
|
||||
messageText.value = options
|
||||
title.value = {}
|
||||
subTitle.value = {}
|
||||
} else {
|
||||
messageText.value = options.message || ''
|
||||
title.value = options.title || {}
|
||||
subTitle.value = options.subTitle || {}
|
||||
}
|
||||
|
||||
messageType.value = options.type || 'success'
|
||||
showIcon.value = options.icon !== false
|
||||
customStyle.value = options.style || {}
|
||||
visible.value = true
|
||||
|
||||
setTimeout(() => {
|
||||
visible.value = false
|
||||
}, duration)
|
||||
}, options.duration || 2000)
|
||||
}
|
||||
|
||||
defineExpose({ showMessage })
|
||||
</script>
|
||||
|
||||
@ -26,9 +70,12 @@ defineExpose({ showMessage })
|
||||
>
|
||||
<MessageContent
|
||||
v-if="visible"
|
||||
:text="messageText"
|
||||
:type="messageType"
|
||||
class="fixed top-50px left-1/2 -translate-x-1/2 z-9999"
|
||||
:message="messageText"
|
||||
:type="messageType"
|
||||
:title="title"
|
||||
:sub-title="subTitle"
|
||||
:show-icon="showIcon"
|
||||
:style="containerStyle"
|
||||
/>
|
||||
</transition>
|
||||
</template>
|
||||
|
@ -1,22 +1,50 @@
|
||||
<script setup>
|
||||
|
||||
import error from '../images/error.png'
|
||||
import success from '../images/success.png'
|
||||
import warning from '../images/warning.png'
|
||||
import info from '../images/info.png'
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: 'success',
|
||||
validator: value => ['success', 'error', 'warning'].includes(value),
|
||||
default: 'success'
|
||||
},
|
||||
text: {
|
||||
message: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
text: '',
|
||||
color: '',
|
||||
align: 'left'
|
||||
})
|
||||
},
|
||||
subTitle: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
text: '',
|
||||
color: '',
|
||||
align: 'left'
|
||||
})
|
||||
},
|
||||
showIcon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
style: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const typeConfig = {
|
||||
info: {
|
||||
imgSrc: info,
|
||||
borderColor: '#C6DFFB',
|
||||
bgColor: '#ECF5FE',
|
||||
},
|
||||
success: {
|
||||
imgSrc: success,
|
||||
borderColor: '#C5E7D5',
|
||||
@ -24,34 +52,70 @@ const typeConfig = {
|
||||
},
|
||||
error: {
|
||||
imgSrc: error,
|
||||
borderColor: '#F3CBD3',
|
||||
bgColor: '#FBEEF1',
|
||||
borderColor: '#FFD4D4',
|
||||
bgColor: '#FFF0F0',
|
||||
},
|
||||
warning: {
|
||||
imgSrc: warning,
|
||||
borderColor: '#FAE0B5',
|
||||
bgColor: '#FEF7ED',
|
||||
},
|
||||
borderColor: '#FFE2BA',
|
||||
bgColor: '#FFF7EC',
|
||||
}
|
||||
}
|
||||
|
||||
// 修正计算属性,使用 props.style
|
||||
const finalStyle = computed(() => {
|
||||
return {
|
||||
borderColor: props.style?.borderColor || typeConfig[props.type].borderColor,
|
||||
backgroundColor: props.style?.backgroundColor || typeConfig[props.type].bgColor,
|
||||
width: props.style?.width || '343px',
|
||||
height: props.style?.height || 'auto',
|
||||
minHeight: '46px',
|
||||
...props.style
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="box-border min-h-[46px] w-[343px] flex items-center border rounded-[4px] px-[15px] shadow-sm"
|
||||
:style="{
|
||||
borderColor: typeConfig[type].borderColor,
|
||||
backgroundColor: typeConfig[type].bgColor,
|
||||
}"
|
||||
:class="`box-border flex items-center border rounded-[4px] px-[15px] shadow-sm py-8px ${!message?'justify-center':''}`"
|
||||
:style="finalStyle"
|
||||
>
|
||||
<div class="mr-[9px] h-[20px] w-[20px]">
|
||||
<div v-if="showIcon" class="mr-[12px]">
|
||||
<img
|
||||
:src="typeConfig[type].imgSrc"
|
||||
class="h-full w-full"
|
||||
class="w-20px h-20px"
|
||||
style="object-fit: contain"
|
||||
alt=""
|
||||
>
|
||||
</div>
|
||||
<div class="text-[14px] text-black leading-normal">
|
||||
{{ text }}
|
||||
<div class="flex flex-col justify-center">
|
||||
<!-- 如果是简单文本模式 -->
|
||||
<div v-if="message" class="text-[14px] line-height-none">
|
||||
{{ message }}
|
||||
</div>
|
||||
<!-- 如果是标题+副标题模式 -->
|
||||
<template v-else>
|
||||
<div
|
||||
v-if="title.text"
|
||||
class="text-[14px] line-height-20px"
|
||||
:style="{
|
||||
color: title.color || 'inherit',
|
||||
textAlign: title.align || 'left'
|
||||
}"
|
||||
>
|
||||
{{ title.text }}
|
||||
</div>
|
||||
<div
|
||||
v-if="subTitle.text"
|
||||
class="text-[12px] leading-normal mt-1 line-height-17px"
|
||||
:style="{
|
||||
color: subTitle.color || '#939393',
|
||||
textAlign: subTitle.align || 'left'
|
||||
}"
|
||||
>
|
||||
{{ subTitle.text }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -2,22 +2,60 @@ import { createApp, nextTick } from 'vue'
|
||||
import MessagePopup from './index.vue'
|
||||
|
||||
const message = {
|
||||
success(text, duration = 2000) {
|
||||
success(options, duration = 2000) {
|
||||
if (process.client) {
|
||||
this.show({ type: 'success', message: text, duration })
|
||||
if (typeof options === 'string') {
|
||||
this.show({ type: 'success', message: options, duration })
|
||||
} else {
|
||||
this.show({
|
||||
type: 'success',
|
||||
...options,
|
||||
duration
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
error(text, duration = 2000) {
|
||||
error(options, duration = 2000) {
|
||||
if (process.client) {
|
||||
this.show({ type: 'error', message: text, duration })
|
||||
if (typeof options === 'string') {
|
||||
this.show({ type: 'error', message: options, duration })
|
||||
} else {
|
||||
this.show({
|
||||
type: 'error',
|
||||
...options,
|
||||
duration
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
warning(text, duration = 2000) {
|
||||
info(options, duration = 2000) {
|
||||
if (process.client) {
|
||||
this.show({ type: 'warning', message: text, duration })
|
||||
if (typeof options === 'string') {
|
||||
this.show({ type: 'info', message: options, duration })
|
||||
} else {
|
||||
this.show({
|
||||
type: 'error',
|
||||
...options,
|
||||
duration
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
show({ type = 'success', message, duration = 2000 }) {
|
||||
warning(options, duration = 2000) {
|
||||
if (process.client) {
|
||||
if (typeof options === 'string') {
|
||||
this.show({ type: 'warning', message: options, duration })
|
||||
} else {
|
||||
|
||||
this.show({
|
||||
type: 'warning',
|
||||
...options,
|
||||
duration
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
show(options) {
|
||||
if (!process.client) return
|
||||
|
||||
const container = document.createElement('div')
|
||||
@ -32,11 +70,7 @@ const message = {
|
||||
|
||||
const instance = app.mount(container)
|
||||
nextTick(() => {
|
||||
instance.showMessage?.({
|
||||
type,
|
||||
message,
|
||||
duration
|
||||
})
|
||||
instance.showMessage?.(options)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,13 @@ const close=()=>{
|
||||
<template>
|
||||
<van-popup
|
||||
:show="show"
|
||||
:transition-appear="true"
|
||||
teleport="#__nuxt"
|
||||
position="bottom"
|
||||
@click-overlay="close"
|
||||
:style="{ height: '74%' }"
|
||||
v-bind="{...$attrs,...$props}"
|
||||
:safe-area-inset-bottom="true"
|
||||
>
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- 标题栏 -->
|
||||
@ -41,7 +44,7 @@ const close=()=>{
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="flex-1 px-16px py-18px overflow-hidden relative">
|
||||
<div class="h-full overflow-y-auto relative">
|
||||
<div class="h-full overflow-y-auto relative list-container">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
|
109
app/components/x-van-date/index.vue
Normal file
109
app/components/x-van-date/index.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [Date, String, Number],
|
||||
default: () => new Date() // 默认当前日期
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '日期'
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择日期'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
minDate: {
|
||||
type: Date,
|
||||
default: () => new Date(1900, 0, 1)
|
||||
},
|
||||
maxDate: {
|
||||
type: Date,
|
||||
default: () => new Date(2100, 11, 31)
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: 'YYYY-MM-DD'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
const show = ref(false)
|
||||
|
||||
// 显示文本
|
||||
const displayText = computed(() => {
|
||||
return dayjs(props.modelValue).format(props.format)
|
||||
})
|
||||
|
||||
// 默认值
|
||||
const defaultValue = computed(() => {
|
||||
const date = props.modelValue || new Date()
|
||||
return [
|
||||
date.getFullYear(),
|
||||
date.getMonth() + 1,
|
||||
date.getDate()
|
||||
]
|
||||
})
|
||||
|
||||
// 确认选择
|
||||
const onConfirm = ({ selectedValues }) => {
|
||||
show.value = false
|
||||
const date = new Date(selectedValues[0], selectedValues[1] - 1, selectedValues[2])
|
||||
emit('update:modelValue', date)
|
||||
emit('change', date)
|
||||
}
|
||||
|
||||
// 取消选择
|
||||
const onCancel = () => {
|
||||
show.value = false
|
||||
}
|
||||
|
||||
// 重置为当前日期
|
||||
const reset = () => {
|
||||
emit('update:modelValue', new Date())
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
reset
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<van-field
|
||||
:model-value="displayText"
|
||||
@click="show = true"
|
||||
readonly
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
:placeholder="placeholder"
|
||||
:label="label"
|
||||
class="mb-10px"
|
||||
is-link
|
||||
/>
|
||||
|
||||
<van-popup
|
||||
v-model:show="show"
|
||||
position="bottom"
|
||||
>
|
||||
<van-date-picker
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
:model-value="defaultValue"
|
||||
@confirm="onConfirm"
|
||||
@cancel="onCancel"
|
||||
title="选择日期"
|
||||
/>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
88
app/components/x-van-select/index.vue
Normal file
88
app/components/x-van-select/index.vue
Normal file
@ -0,0 +1,88 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: [Number, String]
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
required: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:value', 'change'])
|
||||
|
||||
const show = ref(false)
|
||||
|
||||
const onConfirm = (value) => {
|
||||
show.value = false
|
||||
emit('update:value', value.value)
|
||||
emit('change', value)
|
||||
}
|
||||
|
||||
const displayText = computed(() => {
|
||||
const selected = props.columns.find(x => x.value === props.value)
|
||||
return selected?.text || ''
|
||||
})
|
||||
|
||||
const reset = () => {
|
||||
emit('update:value', undefined)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
reset
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<van-field
|
||||
:model-value="displayText"
|
||||
@click="show = true"
|
||||
readonly
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
:placeholder="placeholder"
|
||||
:label="label"
|
||||
class="mb-10px"
|
||||
is-link
|
||||
/>
|
||||
|
||||
<van-popup
|
||||
v-model:show="show"
|
||||
destroy-on-close
|
||||
position="bottom"
|
||||
safe-area-inset-bottom
|
||||
>
|
||||
<van-picker
|
||||
:columns="columns"
|
||||
@confirm="onConfirm"
|
||||
@cancel="show = false"
|
||||
:default-index="columns.findIndex(x => x.value === value)"
|
||||
title="请选择"
|
||||
confirm-button-text="确定"
|
||||
cancel-button-text="取消"
|
||||
/>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
101
app/pages/artDetail/index.vue
Normal file
101
app/pages/artDetail/index.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<script setup>
|
||||
import itemDetail from '@/components/itemDetail/index.vue'
|
||||
import {userArtwork} from "~/api/goods/index.js";
|
||||
|
||||
const route = useRoute()
|
||||
const detail = ref({})
|
||||
const uuid = route.query.uuid
|
||||
|
||||
const initData = async () => {
|
||||
const res = await userArtwork({uuid})
|
||||
if (res.status === 0) {
|
||||
detail.value = res.data
|
||||
}
|
||||
}
|
||||
const position = ref({x: window?.innerWidth - 120 || 0, y: 240}) // 设置初始位置在右侧
|
||||
const startPosition = ref({x: 0, y: 0})
|
||||
const isDragging = ref(false)
|
||||
|
||||
const startDrag = (e) => {
|
||||
isDragging.value = true
|
||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
||||
startPosition.value = {
|
||||
x: clientX - position.value.x,
|
||||
y: clientY - position.value.y
|
||||
}
|
||||
}
|
||||
|
||||
const onDrag = (e) => {
|
||||
if (isDragging.value) {
|
||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
||||
|
||||
// 获取窗口尺寸
|
||||
const maxX = window.innerWidth - 108 // 减去元素宽度
|
||||
const maxY = window.innerHeight - 137 // 减去元素高度
|
||||
|
||||
// 限制范围
|
||||
const x = Math.min(Math.max(0, clientX - startPosition.value.x), maxX)
|
||||
const y = Math.min(Math.max(0, clientY - startPosition.value.y), maxY)
|
||||
|
||||
position.value = {x, y}
|
||||
}
|
||||
}
|
||||
|
||||
const stopDrag = () => {
|
||||
isDragging.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 鼠标事件
|
||||
document.addEventListener('mousemove', onDrag)
|
||||
document.addEventListener('mouseup', stopDrag)
|
||||
// 触摸事件
|
||||
document.addEventListener('touchmove', onDrag)
|
||||
document.addEventListener('touchend', stopDrag)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('mousemove', onDrag)
|
||||
document.removeEventListener('mouseup', stopDrag)
|
||||
document.removeEventListener('touchmove', onDrag)
|
||||
document.removeEventListener('touchend', stopDrag)
|
||||
})
|
||||
|
||||
initData()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative h-screen-nav flex flex-col">
|
||||
<itemDetail class="grow-1" :detail-info="detail.auctionArtworkInfo"/>
|
||||
<div v-if="[1,3,4].includes(detail.status)" class="h-81px bg-#fff flex justify-center pt-7px">
|
||||
<van-button class="w-213px !h-38px" type="primary">
|
||||
<span class="text-#fff text-14px">去支付 RMB10,000</span>
|
||||
</van-button>
|
||||
</div>
|
||||
<div
|
||||
class="w-108px h-137px absolute cursor-move"
|
||||
:style="{
|
||||
left: position.x + 'px',
|
||||
top: position.y + 'px'
|
||||
}"
|
||||
@mousedown="startDrag"
|
||||
@touchstart.prevent="startDrag"
|
||||
>
|
||||
<img src="@/static/images/zd5530@2x.png" class="w-full h-full" alt="">
|
||||
<div
|
||||
class="flex flex-col items-center absolute bottom-25px text-14px text-#B58047 left-1/2 transform translate-x--1/2 whitespace-nowrap">
|
||||
<div>恭喜您</div>
|
||||
<div>竞拍成功</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.cursor-move {
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
@ -2,18 +2,15 @@
|
||||
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 { codeAuthStore } from "@/stores-collect-code/auth/index.js";
|
||||
import { message } from '@/components/x-message/useMessage.js'
|
||||
// ... 现有导入 ...
|
||||
import FingerprintJS from '@fingerprintjs/fingerprintjs'
|
||||
const { userInfo, token,fingerprint } = authStore()
|
||||
import {checkPhone, mobileLogin, userSend} from "@/api-collect-code/auth/index.js";
|
||||
const { userInfo, token,fingerprint } = codeAuthStore()
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { locale } = useI18n()
|
||||
definePageMeta({
|
||||
title: '登录',
|
||||
i18n: 'login.title',
|
||||
})
|
||||
const loadingRef = ref({
|
||||
loading1: false,
|
||||
loading2: false,
|
||||
@ -56,11 +53,19 @@ checkFingerprint()
|
||||
const vanSwipeRef = ref(null)
|
||||
const getCode = async () => {
|
||||
loadingRef.value.loading1 = true
|
||||
const res = await senCode({
|
||||
telNum: phoneNum.value,
|
||||
zone: '86'
|
||||
const res = await checkPhone({
|
||||
tel: phoneNum.value,
|
||||
})
|
||||
loadingRef.value.loading1 = false
|
||||
if (res.status === 0){
|
||||
const res=await userSend({telNum:phoneNum.value,zone:'+86'})
|
||||
if (res.status === 0){
|
||||
pane.value = 1
|
||||
vanSwipeRef.value?.swipeTo(pane.value)
|
||||
showKeyboard.value = true
|
||||
}
|
||||
}
|
||||
/* loadingRef.value.loading1 = false
|
||||
if (res.status === 0) {
|
||||
|
||||
|
||||
@ -68,7 +73,7 @@ const getCode = async () => {
|
||||
pane.value = 1
|
||||
vanSwipeRef.value?.swipeTo(pane.value)
|
||||
showKeyboard.value = true
|
||||
startCountdown();
|
||||
startCountdown();*/
|
||||
/* pane.value = 1
|
||||
vanSwipeRef.value?.swipeTo(pane.value)
|
||||
showKeyboard.value=true
|
||||
@ -85,10 +90,10 @@ const goBack = () => {
|
||||
}
|
||||
const goLogin = async () => {
|
||||
loadingRef.value.loading2 = true
|
||||
const res = await userLogin({
|
||||
telNum: phoneNum.value,
|
||||
zone: '86',
|
||||
code: code.value
|
||||
const res = await mobileLogin({
|
||||
TelNum: phoneNum.value,
|
||||
Password:loginType.value===1?password.value:'',
|
||||
Code: loginType.value===0?code.value:''
|
||||
})
|
||||
if (res.status === 0) {
|
||||
userInfo.value = res.data.accountInfo
|
||||
@ -114,7 +119,7 @@ const goLogin = async () => {
|
||||
<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')">
|
||||
<van-field v-model="phoneNum" clearable placeholder="请输入手机号">
|
||||
<template #label>
|
||||
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
||||
手机号
|
||||
@ -124,7 +129,7 @@ const goLogin = async () => {
|
||||
|
||||
</div>
|
||||
<div class="border-b-[1.7px] mt-[8px]" v-show="loginType === 1">
|
||||
<van-field v-model="password" clearable :placeholder="$t('login.passwordPlaceholder')">
|
||||
<van-field v-model="password" clearable placeholder="请输入密码">
|
||||
<template #label>
|
||||
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
||||
密码
|
||||
@ -137,27 +142,19 @@ const goLogin = async () => {
|
||||
<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>
|
||||
<van-button :loading="loadingRef.loading1" v-if="phoneNum" loading-text="获取验证码"
|
||||
type="primary" block style="height: 48px" @click="getCode">获取验证码</van-button>
|
||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">获取验证码</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>
|
||||
<van-button type="primary" v-if="password" block :loading="loadingRef.loading2" loading-text="登录"
|
||||
style="height: 48px;margin-top:10px" @click="goLogin">登录</van-button>
|
||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">登录</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -166,7 +163,7 @@ const goLogin = async () => {
|
||||
<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 class="text-[16px] text-[#000]">+86 {{ 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`">
|
||||
|
72
app/pages/collectCode/mine/components/codeCard/index.vue
Normal file
72
app/pages/collectCode/mine/components/codeCard/index.vue
Normal file
@ -0,0 +1,72 @@
|
||||
<script setup>
|
||||
|
||||
import XImage from "@/components/x-image/index.vue";
|
||||
import {useRuntimeConfig} from "#app";
|
||||
import QRCode from 'qrcode'
|
||||
import { showImagePreview } from 'vant';
|
||||
import {offlineQrcodeDelete} from "~/api-collect-code/goods/index.js";
|
||||
|
||||
const statusLabel=[
|
||||
{label:'已付款',value:2,color:'#18A058'}, {label:'未付款',value:1,color:'#CF3050'}, {label:'已部分付款',value:4,color:'#F09F1F'}
|
||||
]
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
});
|
||||
const itemLabel=(data)=>{
|
||||
return statusLabel.find(x=>x.value===data.payStatus)
|
||||
}
|
||||
const config = useRuntimeConfig()
|
||||
const getQRBase64 = async () => {
|
||||
try {
|
||||
return await QRCode.toDataURL(`${config.public.NUXT_PUBLIC_API_BASE}/collectCode/payment`, {
|
||||
width: 200,
|
||||
margin: 4,
|
||||
errorCorrectionLevel: 'H'
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('生成二维码失败:', err)
|
||||
return null
|
||||
}
|
||||
}
|
||||
const openQrCode=async ()=>{
|
||||
const base64=await getQRBase64()
|
||||
showImagePreview([base64])
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col h-120px bg-#F7F7F7 rounded-4px px-13px">
|
||||
<div class="flex h-40px border-b border-b-#F0F0F0 items-center justify-between px-8px">
|
||||
<div class="text-14px text-#000">¥ {{data.paidPrice}}/{{data.price}}</div>
|
||||
<div :class="`text-12px text-${itemLabel(data).color}`">{{itemLabel(data).label}}</div>
|
||||
</div>
|
||||
<div class="flex flex-grow-1 px-8px py-11px">
|
||||
<div class="mr-8px">
|
||||
<XImage class="w-57px h-56px rounded-4px" :src="data.hdPic"></XImage>
|
||||
</div>
|
||||
<div class="text-12px text-#1E1E1E">
|
||||
<div>Lot:{{ data.lotNo }}</div>
|
||||
<div>创建人:{{ data.userName }}</div>
|
||||
<div>创建时间:{{data.createdAt}}</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-end ml-auto ">
|
||||
<div class="flex w-55px h-26px bg-#2B53AC rounded-4px justify-center items-center">
|
||||
<div @click="openQrCode" class="text-12px text-#fff line-height-none mt-0.5px mr-5px">查看</div>
|
||||
<div >
|
||||
<img class="w-12px h-12px" src="@/static/images/icon-design-42@3x.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,24 +1,102 @@
|
||||
<script setup>
|
||||
import { userArtworks } from "~/api/goods/index.js";
|
||||
import { authStore } from "~/stores/auth/index.js";
|
||||
import { userArtworks } from "@/api/goods/index.js";
|
||||
import { codeAuthStore } from "@/stores-collect-code/auth/index.js";
|
||||
import { showImagePreview } from 'vant';
|
||||
|
||||
|
||||
import XImage from '@/components/x-image/index.vue'
|
||||
import {useRouter} from "#vue-router";
|
||||
import {goodStore} from "~/stores-collect-code/goods/index.js";
|
||||
import {ref} from "vue";
|
||||
import {offlineQrcodeCreate, offlineQrcodeDelete, offlineQrcodeList} from "~/api-collect-code/goods/index.js";
|
||||
import codeCard from './components/codeCard/index.vue'
|
||||
import {message} from "~/components/x-message/useMessage.js";
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
title: '收款二维码',
|
||||
i18n: 'menu.profile',
|
||||
})
|
||||
const { userInfo } = authStore()
|
||||
const initData = async () => {
|
||||
const res = await userArtworks({})
|
||||
if (res.status === 0) {
|
||||
const router = useRouter();
|
||||
const localState = ref({
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
showDetail: false,
|
||||
showHeight: ''
|
||||
})
|
||||
|
||||
const { userInfo, } = codeAuthStore()
|
||||
const {getOfflineQrcodeList,itemList, loading: storeLoading,pageRef}= goodStore()
|
||||
const initData = async () => {
|
||||
onRefresh()
|
||||
}
|
||||
const show=ref(false)
|
||||
const close=()=>{
|
||||
console.log('show',show.value)
|
||||
show.value=false
|
||||
}
|
||||
const logOut=()=>{
|
||||
localStorage.clear()
|
||||
router.push('/collectCode/login')
|
||||
}
|
||||
const createForm=ref({
|
||||
lotNo:'',
|
||||
price:'',
|
||||
})
|
||||
const confirm=async ()=>{
|
||||
if (!createForm.value.price){
|
||||
message.warning('请输入金额')
|
||||
return false
|
||||
}else if (!createForm.value.lotNo){
|
||||
message.warning('请输入Lot号')
|
||||
return false
|
||||
}
|
||||
const res=await offlineQrcodeCreate({...createForm.value,price:String(createForm.value.price)})
|
||||
if (res.status===0){
|
||||
show.value=false
|
||||
}
|
||||
|
||||
}
|
||||
const onRefresh = async () => {
|
||||
try {
|
||||
localState.value.refreshing = true
|
||||
localState.value.finished = false
|
||||
const { finished } = await getOfflineQrcodeList(true)
|
||||
localState.value.finished = finished
|
||||
} finally {
|
||||
localState.value.refreshing = false
|
||||
}
|
||||
}
|
||||
const loadMore = async () => {
|
||||
pageRef.value.page++
|
||||
const { finished } = await getOfflineQrcodeList()
|
||||
localState.value.finished = finished
|
||||
}
|
||||
const abnormal=ref(false)
|
||||
const abnormalRow=ref({})
|
||||
const inputLotNo=async (data)=>{
|
||||
const res=await offlineQrcodeList({
|
||||
lotNo:createForm.value.lotNo
|
||||
})
|
||||
if (res.status===0){
|
||||
if (res.data.Data?.length>0){
|
||||
abnormal.value=true
|
||||
abnormalRow.value=res.data.Data?.[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
const deleteData=async (qrUid)=>{
|
||||
const res=await offlineQrcodeDelete({
|
||||
qrUid:qrUid
|
||||
})
|
||||
if (res.status===0){
|
||||
getOfflineQrcodeList()
|
||||
message.success('删除成功')
|
||||
}
|
||||
}
|
||||
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="w-[100vw] bg-[url('@/static/images/3532@2x.png')] h-screen-nav 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="">
|
||||
@ -27,29 +105,106 @@ initData()
|
||||
<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">
|
||||
<div class="grow-1 flex justify-end" @click="logOut">
|
||||
<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 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>
|
||||
<div class="grow-1 flex flex-col overflow-hidden py-15px">
|
||||
<div class="overflow-auto">
|
||||
<van-pull-refresh v-model="localState.refreshing"
|
||||
success-text="刷新成功"
|
||||
:success-duration="700"
|
||||
@refresh="onRefresh">
|
||||
<van-list v-model:loading="storeLoading"
|
||||
:finished="localState.finished"
|
||||
finished-text="没有更多了"
|
||||
@load="loadMore" class="px-14px">
|
||||
<template v-for="(item,index) of itemList" :key="item.qrUid">
|
||||
<template v-if="item.payStatus===1">
|
||||
<van-swipe-cell class="mb-14px" >
|
||||
<codeCard :data="item"></codeCard>
|
||||
<template #right>
|
||||
<div class="w-65px h-full bg-#CF3050 flex items-center justify-center" @click="deleteData(item.qrUid)">
|
||||
<img class="w-22px h-24px" src="@/static/images/delete3@.png" alt="">
|
||||
</div>
|
||||
</template>
|
||||
</van-swipe-cell>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="mb-14px">
|
||||
<codeCard :data="item"></codeCard>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
</template>
|
||||
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-81px w-full flex justify-center shrink-0 pt-10px">
|
||||
<div class="w-213px h-38px bg-#2B53AC text-#fff flex justify-center items-center text-14px rounded-4px" @click="show=true">
|
||||
新增
|
||||
</div>
|
||||
</div>
|
||||
<van-dialog v-model:show="show">
|
||||
<div class="pt-18px pb-24px px-24px">
|
||||
<div class="text-16px text-#000 font-bold text-center mb-26px">新增收款二维码</div>
|
||||
<div class="">
|
||||
<div class="flex mb-6px items-center">
|
||||
<div class="w-58px">
|
||||
<div class="text-#1A1A1A text-16px">金额</div>
|
||||
<div class="text-#939393 text-12px">RMB</div>
|
||||
</div>
|
||||
<div>
|
||||
<input v-model="createForm.price" type="number"
|
||||
class="w-214px h-48px bg-#F3F3F3 rounded-4px px-11px text-16px" placeholder="请输入金额">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="w-58px">
|
||||
<div class="text-#1A1A1A text-16px">Lot号</div>
|
||||
</div>
|
||||
<div>
|
||||
<input type="number" v-model="createForm.lotNo" @input="inputLotNo" class="w-214px h-48px bg-#F3F3F3 rounded-4px px-11px text-16px" placeholder="请输入拍品序号">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center" v-if="abnormal">
|
||||
<div class="text-#CF3050 text-12px mb-8px mt-4px">*该拍品号当前已存在收款二维码,确定要创建吗?</div>
|
||||
<div>
|
||||
<XImage class="w-116px h-116px rounded-4px mb-9px" :src="abnormalRow.hdPic"></XImage>
|
||||
<div class="text-12px text-#575757 flex flex-col items-center">
|
||||
<div>日出而作,日落而息</div>
|
||||
<div>张天赐</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="border-t flex">
|
||||
<van-button class="w-50% h-56px" style="border: none;border-radius: 0;border-right: 1.5px solid #E7E7E7" @click="show=false">
|
||||
<span class="text-#000 text-16px text-center">取消</span>
|
||||
</van-button>
|
||||
<van-button class="w-50% h-56px !rounded-0" style="border: none;border-radius: 0" @click="confirm">
|
||||
<span class="text-#000 text-16px text-center text-#2B53AC">确定</span>
|
||||
</van-button>
|
||||
</div>
|
||||
</template>
|
||||
</van-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.van-hairline--top.van-dialog__footer){
|
||||
&>.van-button{
|
||||
border-top: 1px solid #E7E7E7;
|
||||
&.van-dialog__cancel{
|
||||
border-right: 1px solid #E7E7E7;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
43
app/pages/collectCode/payment/index.vue
Normal file
43
app/pages/collectCode/payment/index.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<script setup>
|
||||
const payStatus=ref(0)
|
||||
const changePayStatus=()=>{
|
||||
payStatus.value=payStatus.value===0?1:0
|
||||
}
|
||||
const validateInput = (e) => {
|
||||
const value = e.target.value
|
||||
const char = String.fromCharCode(e.charCode)
|
||||
|
||||
if (!/[\d.]/.test(char)) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (char === '.' && (value.includes('.') || !value)) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (value.includes('.') && value.split('.')[1]?.length >= 2) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover flex-grow-1 flex flex-col items-center pt-183px">
|
||||
<div class="mb-30px">
|
||||
<img class="w-126px h-126px" src="@/static/images/dddf34@2x.png" alt="">
|
||||
</div>
|
||||
<div class="text-#1A1A1A text-16px mb-25px font-bold">{{payStatus===0?'支付全部':'支付部分'}}</div>
|
||||
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">RMB 5000</div>
|
||||
<div class="mb-12px">
|
||||
<input class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text" placeholder="最多RMB5,000" @keydown="validateInput">
|
||||
</div>
|
||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{payStatus===1?'支付全部':'支付部分'}}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
18
app/pages/collectCode/signature/panel/index.vue
Normal file
18
app/pages/collectCode/signature/panel/index.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
const image = ref('');
|
||||
import { showToast } from 'vant';
|
||||
|
||||
const onSubmit = (data) => {
|
||||
image.value = data.image;
|
||||
};
|
||||
const onClear = () => showToast('clear');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<van-signature @submit="onSubmit" @clear="onClear" />
|
||||
<van-image v-if="image" :src="image" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
58
app/pages/collectCode/signature/personal-Info/index.vue
Normal file
58
app/pages/collectCode/signature/personal-Info/index.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import XVanSelect from '@/components/x-van-select/index.vue'
|
||||
import XVanDate from '@/components/x-van-date/index.vue'
|
||||
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
i18n: 'menu.profile',
|
||||
})
|
||||
const {t} = useI18n()
|
||||
const showPicker = ref(false)
|
||||
const showPicker1 = ref(false)
|
||||
const onConfirm = () => {
|
||||
|
||||
}
|
||||
const columns = ref([
|
||||
{text: t('realAuth.male'), value: 1},
|
||||
{text: t('realAuth.female'), value: 2},
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[100vw] bg-[url('@/static/images/asdfsdd.png')] h-screen-nav bg-cover pt-77px flex-grow-1 flex flex-col ">
|
||||
<div class="text-16px text-#191919 font-bold mb-40px px-34px">
|
||||
请填写个人相关信息
|
||||
</div>
|
||||
<div class="grow-1 px-34px">
|
||||
<van-field type="tel" :label-width="161" label="文本" class="mb-10px" placeholder="请输入手机号">
|
||||
<template #label>
|
||||
<div class="flex">
|
||||
<div class="mr-41px whitespace-nowrap">手机号</div>
|
||||
<div>
|
||||
<span class="mr-13px">+ 86</span>
|
||||
<van-icon name="arrow-down" class="text-#777777"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field label="姓名" class="mb-10px" placeholder="请输入姓名"/>
|
||||
<x-van-select label="性别" :columns="columns"/>
|
||||
<x-van-date label="出生日期"/>
|
||||
<van-field label="家庭住址" class="mb-10px" placeholder="请输入家庭住址"/>
|
||||
<van-field label="所属银行" class="mb-10px" placeholder="请输入所属银行"/>
|
||||
<van-field label="银行卡号码" class="mb-10px" placeholder="请输入银行卡号码"/>
|
||||
</div>
|
||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
||||
<van-button color="#2B53AC" class="w-213px van-btn-h-38px">下一步</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.van-cell.van-field){
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
</style>
|
40
app/pages/collectCode/signature/protocol/index.vue
Normal file
40
app/pages/collectCode/signature/protocol/index.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<script setup>
|
||||
const activeNames = ref(['1']);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-#EBEBEB h-screen-nav flex flex-col">
|
||||
<div class="h-50px text-14px text-#191919 bg-#fff flex items-center px-21px mb-6px">支付前需同意以下内容并签字</div>
|
||||
<van-collapse v-model="activeNames" class="grow-1">
|
||||
<van-collapse-item name="1" class="mb-6px">
|
||||
<template #title>
|
||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
||||
</template>
|
||||
代码是写出来给人看的,附带能在机器上运行。
|
||||
</van-collapse-item>
|
||||
<van-collapse-item name="2" class="mb-6px">
|
||||
<template #title>
|
||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
||||
</template>
|
||||
代码是写出来给人看的,附带能在机器上运行。
|
||||
</van-collapse-item>
|
||||
<van-collapse-item name="3" class="mb-6px">
|
||||
<template #title>
|
||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
||||
</template>
|
||||
代码是写出来给人看的,附带能在机器上运行。
|
||||
</van-collapse-item>
|
||||
</van-collapse>
|
||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
||||
<van-button color="#2B53AC" class="w-213px van-btn-h-38px">同意并签字</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.van-cell__right-icon){
|
||||
color: #ACACAC;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
@ -9,6 +9,7 @@ definePageMeta({
|
||||
i18n: 'countryRegion.title',
|
||||
})
|
||||
const router = useRouter()
|
||||
console.log('router',router)
|
||||
const { t, locale } = useI18n()
|
||||
const value = ref('');
|
||||
const alphabet = [
|
||||
@ -90,10 +91,10 @@ const searchCountry = computed(() => {
|
||||
});
|
||||
|
||||
const showIndexBar = computed(() => locale.value !== 'ja-JP')
|
||||
|
||||
const route = useRoute()
|
||||
const handleCountrySelect = (country) => {
|
||||
router.push({
|
||||
path: '/login',
|
||||
router.replace({
|
||||
path: window.history.state.back,
|
||||
query: {
|
||||
zone: country.zone,
|
||||
countryName: country.displayName
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import xImage from '@/components/x-image/index.vue'
|
||||
const {
|
||||
auctionDetail
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import xPopup from '@/components/x-popup/index.vue'
|
||||
import ItemDetail from "@/components/itemDetail/index.vue";
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
const {
|
||||
artWorkDetail
|
||||
} = goodStore()
|
||||
@ -9,6 +9,10 @@ const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
detailInfo: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
@ -19,6 +23,6 @@ const handleClose = () => {
|
||||
</script>
|
||||
<template>
|
||||
<xPopup :show="show" title="拍品详情" @update:show="handleClose">
|
||||
<ItemDetail :detailInfo="artWorkDetail" />
|
||||
<ItemDetail :detailInfo="detailInfo" />
|
||||
</xPopup>
|
||||
</template>
|
@ -65,7 +65,7 @@ const openShow = async (item) => {
|
||||
finished-text="没有更多了"
|
||||
@load="loadMore"
|
||||
>
|
||||
<div class="w-full flex gap-[16px]" v-memo="[itemList]">
|
||||
<div class="w-full flex gap-[16px]">
|
||||
<masonry-wall :items="itemList" :ssr-columns="2" :maxColumns="2" :minColumns="2" :gap="5">
|
||||
<template #default="{ item, index }">
|
||||
<div
|
||||
@ -81,7 +81,7 @@ const openShow = async (item) => {
|
||||
<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 }}
|
||||
LOT{{ item.index }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-[8px]">
|
||||
@ -104,7 +104,7 @@ const openShow = async (item) => {
|
||||
</div>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
<DetailPopup v-model:show="localState.showDetail"></DetailPopup>
|
||||
<DetailPopup v-model:show="localState.showDetail" :detailInfo="artWorkDetail"></DetailPopup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -3,21 +3,27 @@ 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'
|
||||
import {message} from '@/components/x-message/useMessage.js'
|
||||
import floatingVideo from '@/components/floatingVideo/index.vue'
|
||||
import {liveStore} from "~/stores/live/index.js";
|
||||
const {fullLive,getAuctionDetail,auctionDetail} = goodStore();
|
||||
const {getLiveLink}= liveStore()
|
||||
const changeLive = () => {
|
||||
fullLive.value = true;
|
||||
};
|
||||
if (!auctionDetail.value.uuid){
|
||||
await getAuctionDetail()
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex-grow-1">
|
||||
<!-- <floatingVideo :is-visible="true"></floatingVideo>-->
|
||||
<client-only>
|
||||
<liveRoom @click="changeLive" :class="['changeLive', fullLive ? 'expanded' : 'collapsed']"
|
||||
:fullLive="fullLive"/>
|
||||
</client-only>
|
||||
<div v-show="!fullLive" class="bg-#fff">
|
||||
<div v-if="!fullLive" class="bg-#fff">
|
||||
<van-tabs sticky animated>
|
||||
<van-tab title="拍品列表">
|
||||
<ItemList></ItemList>
|
||||
@ -28,6 +34,7 @@ if (!auctionDetail.value.uuid){
|
||||
</van-tabs>
|
||||
<van-back-top right="15vw" bottom="10vh"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import SignaturePad from '~/components/SignaturePad.vue'
|
||||
import SignaturePad from '@/components/SignaturePad.vue'
|
||||
|
||||
const signature = ref('')
|
||||
|
||||
|
@ -1,68 +1,52 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
|
||||
|
||||
const list = ref([
|
||||
import {liveStore} from "@/stores/live/index.js";
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
const {auctionData} = liveStore()
|
||||
const {userInfo}= authStore()
|
||||
const headList=[
|
||||
{
|
||||
a: '领先',
|
||||
b: '现场竞价',
|
||||
c: '10:12:12',
|
||||
d: 'RMB5,500',
|
||||
e: '我'
|
||||
label:'领先',
|
||||
color:'#D03050',
|
||||
value:'head'
|
||||
},
|
||||
{
|
||||
label:'出局',
|
||||
color:'#939393',
|
||||
value:'out'
|
||||
},
|
||||
{
|
||||
label:'成交',
|
||||
color:'#34B633',
|
||||
value:'success'
|
||||
}
|
||||
]);
|
||||
|
||||
let intervalId = null;
|
||||
|
||||
const addItem = () => {
|
||||
list.value.push({
|
||||
a: '领先',
|
||||
b: '现场竞价',
|
||||
c: '10:12:12',
|
||||
d: 'RMB5,500',
|
||||
e: ''
|
||||
});
|
||||
nextTick(() => {
|
||||
scrollToBottom();
|
||||
});
|
||||
};
|
||||
|
||||
const scrollToBottom = () => {
|
||||
const container = document.getElementById('list-container');
|
||||
if (container) {
|
||||
setTimeout(() => {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 每秒添加一条数据
|
||||
/* intervalId = setInterval(() => {
|
||||
addItem();
|
||||
}, 1000);*/
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
// 清理定时器
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
});
|
||||
]
|
||||
const headItem=(statusCode)=>{
|
||||
return headList.find(x=>x.value===statusCode)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
id="list-container"
|
||||
class="w-344px h-86px overflow-y-auto bg-#fff rounded-4px text-14px text-#939393 pt-7px pb-7px flex flex-col justify-between"
|
||||
class="w-344px h-86px overflow-y-auto bg-#fff rounded-4px text-14px text-#939393 pt-7px pb-7px px-11px flex flex-col justify-between"
|
||||
>
|
||||
<transition-group name="list" tag="div">
|
||||
<div v-for="(item, index) in list" :key="index" class="flex flex-shrink-0 h-25px">
|
||||
<div class="flex-grow-1 text-center">{{ item.a }}</div>
|
||||
<div class="flex-grow-1 text-center">{{ item.b }}</div>
|
||||
<div class="flex-grow-1 text-center">{{ item.c }}</div>
|
||||
<div class="flex-grow-1 text-center">{{ item.d }}</div>
|
||||
<div class="flex-grow-1 text-center">{{ item.e }}</div>
|
||||
</div>
|
||||
<template v-if="auctionData.wsType==='stopArtwork'">
|
||||
<div class="text-#939393 text-14px">即将开始下一个拍品</div>
|
||||
</template>
|
||||
<template v-else-if="auctionData.auctionPriceList?.buys?.length>0">
|
||||
<div v-for="(item, index) in auctionData.auctionPriceList?.buys" :key="index" class="flex flex-shrink-0 h-25px">
|
||||
<div class="flex-grow-1 text-start shrink-0" :style="`color: ${headItem(item.statusCode).color}`" >{{ headItem(item.statusCode).label }}</div>
|
||||
<div class="flex-grow-1 text-center shrink-0">{{ item.auctionType==='local'?'现场竞价':'网络竞价' }}</div>
|
||||
<div class="flex-grow-1 text-center shrink-0">{{ item.createdAt }}</div>
|
||||
<div class="flex-grow-1 text-center shrink-0">{{item.baseCurrency}}{{ item.baseMoney }}</div>
|
||||
<div class="flex-grow-1 text-center text-#2B53AC shrink-0 w-20px">{{ item.userId===userInfo.ID?'我':'' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="auctionData.wsType==='newArtwork'">
|
||||
<div class="text-#939393 text-14px">开始拍卖</div>
|
||||
</template>
|
||||
|
||||
</transition-group>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -9,6 +9,7 @@ const props = defineProps({
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
const router = useRouter()
|
||||
const emit = defineEmits(['update:show'])
|
||||
const payStatus=ref(0)
|
||||
const changePayStatus=()=>{
|
||||
@ -18,6 +19,7 @@ const close=()=>{
|
||||
emit('update:show',false)
|
||||
}
|
||||
const confirm=()=>{
|
||||
router.push('/signature/protocol')
|
||||
emit('update:show',false)
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ const props = defineProps({
|
||||
},
|
||||
price: {
|
||||
type: Number,
|
||||
default: 0
|
||||
default: 1000
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['cancel','update:show'])
|
||||
@ -23,7 +23,7 @@ const cancel= () => {
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<van-dialog :show="show" show-cancel-button :show-confirm-button="false" cancelButtonText="返回" cancelButtonColor="#2B53AC" @cancel="cancel">
|
||||
<van-dialog style="overflow: visible" :show="show" show-cancel-button :show-confirm-button="false" cancelButtonText="返回" cancelButtonColor="#2B53AC" @cancel="cancel">
|
||||
<div class="h-145px relative flex justify-center">
|
||||
<img :src="type==='success' ? successImg : errorImg" class="w-119px h-120px absolute top--74px z-9999 left-1/2 transform translate-x--1/2" alt="">
|
||||
<div class="mt-94px text-#A9A9A9 text-16px">{{price}}</div>
|
||||
@ -33,9 +33,7 @@ const cancel= () => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.van-dialog) {
|
||||
overflow: visible!important;
|
||||
}
|
||||
|
||||
:deep(.van-hairline--top.van-dialog__footer){
|
||||
border-top: 1px solid #E7E7E7;
|
||||
border-bottom-left-radius:8px ;
|
||||
|
@ -1,33 +1,49 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
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 {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();
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
|
||||
const {quoteStatus, changeStatus, show, auctionData, getSocketData} = liveStore();
|
||||
const {pageRef} = goodStore();
|
||||
const showTang=ref(false)
|
||||
const openOne=()=>{
|
||||
showTang.value=true
|
||||
const {userInfo} = authStore()
|
||||
const showTang = ref(false)
|
||||
const openOne = () => {
|
||||
showTang.value = true
|
||||
}
|
||||
|
||||
const paySide = computed(() => {
|
||||
//当前是否已成交,以及成交人是当前登录用户
|
||||
if (auctionData.value.artwork.isSoled && auctionData.value.artwork.buyInfo.userID === userInfo.value.ID) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
const goPay = () => {
|
||||
show.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-white w-60px rounded-l-4px overflow-hidden">
|
||||
<!-- 拍品信息 -->
|
||||
<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">
|
||||
<van-button class="w-60px !h-60px" @click="openOne" style="border: none;border-radius: 0">
|
||||
<div class="text-center flex flex-col justify-center items-center text-#7D7D7F text-12px">
|
||||
<div>拍品</div>
|
||||
<div>(1/{{pageRef.itemCount??0}})</div>
|
||||
<div>({{ auctionData?.artwork?.index }}/{{ pageRef.itemCount ?? 0 }})</div>
|
||||
</div>
|
||||
</x-button>
|
||||
</van-button>
|
||||
<tangPopup v-model:show="showTang"></tangPopup>
|
||||
<!-- 出价开关 -->
|
||||
<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">
|
||||
<van-button class="w-60px !h-60px" @click="changeStatus"
|
||||
style="border-right: none;border-left: none;border-radius: 0;padding: 0">
|
||||
<div class="text-center flex flex-col justify-center items-center">
|
||||
<div class="mb-4px">
|
||||
<img
|
||||
:src="quoteStatus ? lockClosed : lockOpen"
|
||||
class="w-16px h-21px"
|
||||
@ -38,15 +54,15 @@ const openOne=()=>{
|
||||
{{ quoteStatus ? '关闭出价' : '开启出价' }}
|
||||
</div>
|
||||
</div>
|
||||
</x-button>
|
||||
</van-button>
|
||||
<!-- 支付 -->
|
||||
<x-button @click="show = true">
|
||||
<div class="w-60px h-60px text-center flex flex-col justify-center items-center text-yellow-600">
|
||||
<van-button v-if="paySide" class="w-60px !h-60px" style="border: none;border-radius: 0" @click="goPay">
|
||||
<div class="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>
|
||||
</x-button>
|
||||
</van-button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,8 +1,29 @@
|
||||
<script setup>
|
||||
import xPopup from '@/components/x-popup/index.vue'
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import xImage from '@/components/x-image/index.vue'
|
||||
const {pageRef,itemList} = goodStore();
|
||||
import DetailPopup from '@/pages/home/components/DetailPopup/index.vue'
|
||||
import {liveStore} from "~/stores/live/index.js";
|
||||
import {ref} from "vue";
|
||||
const {pageRef,itemList,getArtworkList, loading: storeLoading,} = goodStore();
|
||||
const {auctionData} = liveStore()
|
||||
const showDetail=ref(false)
|
||||
const localState = ref({
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
showDetail: false,
|
||||
showHeight: ''
|
||||
})
|
||||
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 props = defineProps({
|
||||
show: Boolean,
|
||||
title: {
|
||||
@ -10,44 +31,104 @@ const props = defineProps({
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const scrollToCurrentItem = () => {
|
||||
if (!itemList.value?.length) return
|
||||
const currentIndex = itemList.value.findIndex(
|
||||
item => auctionData.value.artwork.index === item?.index
|
||||
)
|
||||
if (currentIndex > -1) {
|
||||
const container = document.querySelector('.list-container')
|
||||
const targetElement = document.querySelectorAll('.item-wrapper')[currentIndex]
|
||||
if (targetElement && container) {
|
||||
const containerTop = container.getBoundingClientRect().top
|
||||
const elementTop = targetElement.getBoundingClientRect().top
|
||||
const scrollTop = elementTop - containerTop + container.scrollTop
|
||||
container.scrollTo({
|
||||
top: scrollTop,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
const emit = defineEmits(['update:show'])
|
||||
|
||||
const showDetailInfo=ref(null)
|
||||
const close = () => emit('update:show', false);
|
||||
const openShow=(item)=>{
|
||||
showDetailInfo.value=item
|
||||
showDetail.value=true
|
||||
|
||||
}
|
||||
const loadMore = async () => {
|
||||
pageRef.value.page++
|
||||
const { finished } = await getArtworkList()
|
||||
localState.value.finished = finished
|
||||
}
|
||||
watch(()=>props.show,(newValue)=>{
|
||||
if (newValue){
|
||||
nextTick(()=>{
|
||||
scrollToCurrentItem()
|
||||
})
|
||||
}
|
||||
})
|
||||
</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"
|
||||
<div>
|
||||
<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>
|
||||
<van-pull-refresh
|
||||
v-model="localState.refreshing"
|
||||
success-text="刷新成功"
|
||||
:success-duration="700"
|
||||
@refresh="onRefresh"
|
||||
>
|
||||
<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>
|
||||
<template #success>
|
||||
<van-icon name="success" /> <span>刷新成功</span>
|
||||
</template>
|
||||
<van-list
|
||||
v-model:loading="storeLoading"
|
||||
:finished="localState.finished"
|
||||
finished-text="没有更多了"
|
||||
@load="loadMore"
|
||||
|
||||
>
|
||||
<div
|
||||
v-for="(item,index) of itemList"
|
||||
:key="item.uuid"
|
||||
class="flex mb-21px item-wrapper"
|
||||
@click="openShow(item)"
|
||||
>
|
||||
<div
|
||||
class="mr-10px flex-shrink-0 rounded-4px overflow-hidden cursor-pointer relative"
|
||||
>
|
||||
<xImage
|
||||
:preview="false"
|
||||
class="w-80px h-80px"
|
||||
:src="item.artwork?.hdPic"
|
||||
:alt="item?.artworkTitle"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div class="w-45px h-17px bg-#2B53AC text-12px line-height-none flex justify-center items-center absolute top-2px left-2px text-#fff">LOT{{item.index}}</div>
|
||||
<div v-if="auctionData.artwork.index===item?.index" class="w-80px h-20px bg-#B58047 flex line-height-none justify-center items-center text-#fff text-12px bottom-0 absolute blink">投屏中</div>
|
||||
</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>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
</x-popup>
|
||||
</x-popup>
|
||||
<DetailPopup v-model:show="showDetail" :detail-info="showDetailInfo"></DetailPopup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@ -58,4 +139,12 @@ const close = () => emit('update:show', false);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.blink {
|
||||
animation: fade 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
</style>
|
@ -1,51 +1,94 @@
|
||||
<script setup>
|
||||
import {ref, onMounted, onBeforeUnmount} from 'vue'
|
||||
import {ref, onMounted, onBeforeUnmount, computed, watch} 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 {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 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 xButton from '@/components/x-button/index.vue'
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
const {auctionDetail,getAuctionDetail} = goodStore();
|
||||
const { token } = authStore()
|
||||
import {goodStore} from "@/stores/goods/index.js"
|
||||
import {message} from "~/components/x-message/useMessage.js"
|
||||
import {artworkBuy} from "@/api/goods/index.js"
|
||||
import CryptoJS from 'crypto-js'
|
||||
|
||||
const {auctionDetail, getAuctionDetail} = goodStore()
|
||||
const player = ref(null)
|
||||
const {quoteStatus, changeStatus, show, playerId, show1} = liveStore()
|
||||
const {quoteStatus, changeStatus, show, playerId, show1, auctionData, getSocketData,getLiveLink} = liveStore()
|
||||
const isPlayerReady = ref(false)
|
||||
const pullLink=ref('')
|
||||
const props = defineProps({
|
||||
fullLive: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
})
|
||||
const isPiPActive = ref(false)
|
||||
const videoRef = ref(null)
|
||||
|
||||
// 检查浏览器是否支持画中画
|
||||
const isPiPSupported = computed(() => {
|
||||
return document.pictureInPictureEnabled ||
|
||||
document.webkitPictureInPictureEnabled
|
||||
})
|
||||
|
||||
// 进入画中画模式
|
||||
const enterPiP = async () => {
|
||||
try {
|
||||
if (!videoRef.value) return
|
||||
|
||||
if (document.pictureInPictureElement) {
|
||||
await document.exitPictureInPicture()
|
||||
}
|
||||
|
||||
await videoRef.value.requestPictureInPicture()
|
||||
isPiPActive.value = true
|
||||
} catch (error) {
|
||||
console.error('进入画中画模式失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 退出画中画模式
|
||||
const exitPiP = async () => {
|
||||
try {
|
||||
if (document.pictureInPictureElement) {
|
||||
await document.exitPictureInPicture()
|
||||
isPiPActive.value = false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('退出画中画模式失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
definePageMeta({
|
||||
title: '主页',
|
||||
i18n: 'login.title',
|
||||
})
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
const playerConfig = {
|
||||
id: playerId.value,
|
||||
source: config.public.NUXT_PUBLIC_PLAYER_SOURCE,
|
||||
isLive: true,
|
||||
preload: true,
|
||||
autoplayPolicy: {fallbackToMute: true},
|
||||
controlBarVisibility: 'never',
|
||||
}
|
||||
|
||||
|
||||
const handlePlayerError = (error) => {
|
||||
console.error('播放器错误:', error)
|
||||
if (player.value) {
|
||||
player.value?.play()
|
||||
}
|
||||
}
|
||||
|
||||
const initializePlayer = () => {
|
||||
try {
|
||||
if (player.value) {
|
||||
player.value?.dispose()
|
||||
}
|
||||
const playerConfig = {
|
||||
id: playerId.value,
|
||||
source:pullLink.value,
|
||||
isLive: true,
|
||||
preload: true,
|
||||
autoplayPolicy: {fallbackToMute: true},
|
||||
controlBarVisibility: 'never',
|
||||
}
|
||||
player.value = new Aliplayer(playerConfig, (playerInstance) => {
|
||||
isPlayerReady.value = true
|
||||
playerInstance?.play()
|
||||
@ -60,102 +103,108 @@ const initializePlayer = () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
if (!auctionDetail.value.uuid){
|
||||
await getAuctionDetail()
|
||||
}
|
||||
/* initializePlayer()*/
|
||||
const { ws, messages, onMessage } = useWebSocket()
|
||||
|
||||
// 连接
|
||||
ws.connect('/api/v1/m/auction/live',{auctionUuid: auctionDetail.value.uuid,token:token.value})
|
||||
|
||||
/*// 发送消息
|
||||
ws.send({ type: 'chat', content: 'Hello!' })*/
|
||||
|
||||
// 监听消息
|
||||
onMessage((data) => {
|
||||
console.log('收到消息:', data)
|
||||
})
|
||||
pullLink.value= await getLiveLink()
|
||||
initializePlayer()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (player.value) {
|
||||
player.value?.dispose()
|
||||
player.value = null
|
||||
}
|
||||
})
|
||||
|
||||
const goPay = () => {
|
||||
show.value = true
|
||||
}
|
||||
const fullLive1 = ref(false)
|
||||
|
||||
watch(()=>{
|
||||
const fullLive1 = ref(false)
|
||||
watch(() => {
|
||||
return props.fullLive
|
||||
}, (newVal) => {
|
||||
if (newVal) {
|
||||
getSocketData()
|
||||
setTimeout(() => {
|
||||
fullLive1.value = true
|
||||
}, 400)
|
||||
}else {
|
||||
} else {
|
||||
fullLive1.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const goBuy = async () => {
|
||||
const res = await artworkBuy({
|
||||
auctionArtworkUuid: auctionData.value?.artwork?.uuid,
|
||||
buyMoney: String(auctionData.value?.nowAuctionPrice?.nextPrice ?? 0)
|
||||
})
|
||||
if (res.status === 0) {
|
||||
message.success('出价成功')
|
||||
}
|
||||
}
|
||||
|
||||
const tipOpen = () => {
|
||||
message.warning('出价状态未开启')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative h-full">
|
||||
<div class="w-full h-full">
|
||||
<video
|
||||
class="h-full w-full"
|
||||
autoplay
|
||||
loop
|
||||
muted
|
||||
playsinline
|
||||
style=" object-fit: cover"
|
||||
>
|
||||
<source src="@/static/video/example.mp4" type="video/mp4" />
|
||||
您的浏览器不支持 HTML5 视频。
|
||||
</video>
|
||||
</div>
|
||||
<!-- <div :id="playerId" class="w-screen"
|
||||
:style="fullLive?'height: calc(100vh - var(--van-nav-bar-height))':'height:100%'"></div>-->
|
||||
<div class="relative h-full ">
|
||||
<div :id="playerId" class="w-full h-full"></div>
|
||||
|
||||
<transition>
|
||||
<div v-if="fullLive1">
|
||||
|
||||
<sideButton class="absolute top-196px right-0 z-999"></sideButton>
|
||||
<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">
|
||||
当前价:RMB
|
||||
<van-rolling-text class="my-rolling-text" :start-num="0" :duration="0.5" :target-num="3000" direction="up"/>
|
||||
当前价:{{ auctionData?.nowAuctionPrice?.currency }}
|
||||
<van-rolling-text class="my-rolling-text" :start-num="0" :duration="0.5"
|
||||
:target-num="auctionData?.nowAuctionPrice?.nowPrice??0" direction="up"/>
|
||||
</div>
|
||||
<div class="text-16px text-#fff font-600">
|
||||
下口价:RMB
|
||||
<van-rolling-text class="my-rolling-text1" :start-num="0" :duration="0.5" :target-num="3500" direction="up"/>
|
||||
下口价:{{ auctionData?.nowAuctionPrice?.currency }}
|
||||
<van-rolling-text class="my-rolling-text1" :start-num="0" :duration="0.5"
|
||||
:target-num="auctionData?.nowAuctionPrice?.nextPrice??0" direction="up"/>
|
||||
</div>
|
||||
<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>
|
||||
</x-button>
|
||||
<div v-if="quoteStatus" class="mt-10px mb-10px">
|
||||
<van-button @click="goBuy" color="#FFB25F" class="w-344px !h-[40px]">
|
||||
<div>{{
|
||||
`确认出价 ${auctionData?.nowAuctionPrice?.currency} ${auctionData?.nowAuctionPrice?.nextPrice ?? 0}`
|
||||
}}
|
||||
</div>
|
||||
</van-button>
|
||||
</div>
|
||||
<div v-else class="mt-10px mb-10px">
|
||||
<van-button @click="tipOpen" color="#D6D6D8" class=" w-344px !h-[40px]" v-if="!quoteStatus">
|
||||
<div class="text-#7D7D7F text-14px">点击"开启出价",即刻参与竞拍</div>
|
||||
</van-button>
|
||||
</div>
|
||||
|
||||
<broadcast></broadcast>
|
||||
</div>
|
||||
<paymentInput v-model:show="show"/>
|
||||
<div>
|
||||
</div>
|
||||
<paymentResults v-model:show="show1" type="error"/>
|
||||
<div v-if="auctionData?.wsType==='newArtwork'"
|
||||
class="w-344px h-31px rounded-4px absolute top-9px bg-[#151824]/45 backdrop-blur-[10px] backdrop-saturate-[180%] left-1/2 transform translate-x--1/2 flex text-#fff text-14px items-center px-12px line-height-none">
|
||||
<div class="mr-11px whitespace-nowrap">LOT{{ auctionData.artwork.index }}</div>
|
||||
<div class="mr-10px truncate">{{ auctionData.artwork.name }}</div>
|
||||
<div class="whitespace-nowrap">开始拍卖</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</transition>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
:root:root {
|
||||
--van-dialog-radius: 8px
|
||||
<style lang="scss">
|
||||
#J_prismPlayer{
|
||||
width: 100%;
|
||||
height: 100%!important;
|
||||
&>video{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
@ -168,6 +217,7 @@ watch(()=>{
|
||||
.v-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.my-rolling-text {
|
||||
--van-rolling-text-item-width: 10px;
|
||||
--van-rolling-text-font-size: 16px;
|
||||
|
@ -3,7 +3,7 @@ import { useRouter, useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import countryCode from '../countryRegion/data/index.js'
|
||||
import {senCode, userLogin} from "@/api/auth/index.js";
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
import {authStore} from "@/stores/auth/index.js";
|
||||
import {message} from '@/components/x-message/useMessage.js'
|
||||
const {userInfo,token}= authStore()
|
||||
const router = useRouter();
|
||||
@ -132,7 +132,7 @@ const goLogin =async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-[100vh] w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-cover px-[31px] pt-[86px]">
|
||||
<div class="h-screen-nav w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-cover px-[31px] pt-[86px]">
|
||||
<div class="w-full flex justify-center mb-[100px]">
|
||||
<img class="h-[105px] w-[189px]" src="@/static/images/ghfggff.png" alt="">
|
||||
</div>
|
||||
|
@ -1,12 +1,15 @@
|
||||
<script setup>
|
||||
import {userArtworks} from "~/api/goods/index.js";
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
import {userArtworks} from "@/api/goods/index.js";
|
||||
import {authStore} from "@/stores/auth/index.js";
|
||||
import xImage from '@/components/x-image/index.vue'
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
import {ref} from "vue";
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
title: '我的',
|
||||
i18n: 'menu.profile',
|
||||
})
|
||||
const {artWorkDetail} = goodStore()
|
||||
const myList=ref([])
|
||||
const showMyList=ref([])
|
||||
const {userInfo}= authStore()
|
||||
@ -19,12 +22,11 @@ const groupAndSortByDate=(data)=> {
|
||||
acc[curr.userCreatedAt] = {
|
||||
userCreatedAt: curr.userCreatedAt,
|
||||
list: []
|
||||
};
|
||||
}
|
||||
}
|
||||
acc[curr.userCreatedAt].list.push(curr);
|
||||
acc[curr.userCreatedAt].list.push(curr)
|
||||
return acc;
|
||||
}, {}))
|
||||
.sort((a, b) => new Date(b.userCreatedAt) - new Date(a.userCreatedAt));
|
||||
}, {})).sort((a, b) => new Date(b.userCreatedAt) - new Date(a.userCreatedAt));
|
||||
}
|
||||
const initData=async ()=>{
|
||||
const res=await userArtworks({})
|
||||
@ -33,7 +35,37 @@ const initData=async ()=>{
|
||||
showMyList.value=groupAndSortByDate(myList.value)
|
||||
}
|
||||
}
|
||||
const router = useRouter()
|
||||
const localState = ref({
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
showDetail: false,
|
||||
showHeight: ''
|
||||
})
|
||||
initData()
|
||||
const goPay=()=>{
|
||||
router.push({
|
||||
path:'/signature/personal-Info'
|
||||
})
|
||||
}
|
||||
const goDetail=(item)=>{
|
||||
router.push({
|
||||
path:'/artDetail',
|
||||
query:{
|
||||
uuid:item.uuid
|
||||
}
|
||||
})
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -51,20 +83,30 @@ initData()
|
||||
<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 @refresh="initData">
|
||||
<van-pull-refresh v-model="localState.refreshing"
|
||||
success-text="刷新成功"
|
||||
:success-duration="700"
|
||||
@refresh="onRefresh">
|
||||
<van-list
|
||||
finished-text="没有更多了"
|
||||
>
|
||||
<div class="px-16px pt-14px" v-for="(item,index) of showMyList">
|
||||
<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 mb-22px" v-for="(item1,index1) of item.list" @click="goDetail(item1)">
|
||||
<div class="flex-shrink-0 mr-10px rounded-4px overflow-hidden">
|
||||
<x-image class="w-80px h-80px" :src="item1?.auctionArtworkInfo?.artwork?.hdPic" alt=""/>
|
||||
<x-image class="w-80px h-80px" :src="item1?.auctionArtworkInfo?.artwork?.hdPic" :preview="false" alt=""/>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<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 class="flex flex-col justify-between grow-1">
|
||||
<div class="text-#000 text-16px ellipsis line-height-21px">{{item1?.auctionArtworkInfo?.artworkTitle}}{{item1?.auctionArtworkInfo?.artworkTitle}}{{item1?.auctionArtworkInfo?.artworkTitle}}</div>
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<div class="text-#575757 text-14px line-height-none mb-5px">起拍价:RMB 1,000</div>
|
||||
<div class="text-#B58047 text-14px line-height-none">成交价:RMB 10,000</div>
|
||||
</div>
|
||||
<div v-if="[1,3,4].includes(item1.status)" @click.stop="goPay">
|
||||
<van-button class="w-73px !h-30px" type="primary"><span class="text-12px">去支付</span></van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<script setup>
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import {userUpdate} from "~/api/auth/index.js";
|
||||
import {userUpdate} from "@/api/auth/index.js";
|
||||
import {message} from '@/components/x-message/useMessage.js'
|
||||
import detail from './components/detail.vue'
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
import {authStore} from "@/stores/auth/index.js";
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const showPicker = ref(false);
|
||||
|
18
app/pages/signature/panel/index.vue
Normal file
18
app/pages/signature/panel/index.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
const image = ref('');
|
||||
import { showToast } from 'vant';
|
||||
|
||||
const onSubmit = (data) => {
|
||||
image.value = data.image;
|
||||
};
|
||||
const onClear = () => showToast('clear');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<van-signature @submit="onSubmit" @clear="onClear" />
|
||||
<van-image v-if="image" :src="image" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
63
app/pages/signature/personal-Info/index.vue
Normal file
63
app/pages/signature/personal-Info/index.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import XVanSelect from '@/components/x-van-select/index.vue'
|
||||
import XVanDate from '@/components/x-van-date/index.vue'
|
||||
definePageMeta({
|
||||
name: 'personal-info',
|
||||
})
|
||||
const {t} = useI18n()
|
||||
const showPicker = ref(false)
|
||||
const showPicker1 = ref(false)
|
||||
const onConfirm = () => {
|
||||
|
||||
}
|
||||
const router = useRouter()
|
||||
const columns = ref([
|
||||
{text: t('realAuth.male'), value: 1},
|
||||
{text: t('realAuth.female'), value: 2},
|
||||
])
|
||||
const goCountryRegion=()=>{
|
||||
router.push({
|
||||
path:'/countryRegion'
|
||||
})
|
||||
}
|
||||
const adress=ref('')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[100vw] bg-[url('@/static/images/asdfsdd.png')] h-screen-nav bg-cover pt-77px flex-grow-1 flex flex-col ">
|
||||
<div class="text-16px text-#191919 font-bold mb-40px px-34px">
|
||||
请填写个人相关信息
|
||||
</div>
|
||||
<div class="grow-1 px-34px">
|
||||
<van-field type="tel" :label-width="161" label="文本" class="mb-10px" placeholder="请输入手机号">
|
||||
<template #label>
|
||||
<div class="flex">
|
||||
<div class="mr-41px whitespace-nowrap">手机号</div>
|
||||
<div @click="goCountryRegion">
|
||||
<span class="mr-13px">+ 86</span>
|
||||
<van-icon name="arrow-down" class="text-#777777"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field label="姓名" class="mb-10px" placeholder="请输入姓名"/>
|
||||
<x-van-select label="性别" :columns="columns"/>
|
||||
<x-van-date label="出生日期"/>
|
||||
<van-field v-model="adress" label="家庭住址" class="mb-10px" placeholder="请输入家庭住址"/>
|
||||
<van-field label="所属银行" class="mb-10px" placeholder="请输入所属银行"/>
|
||||
<van-field label="银行卡号码" class="mb-10px" placeholder="请输入银行卡号码"/>
|
||||
</div>
|
||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
||||
<van-button color="#2B53AC" class="w-213px van-btn-h-38px">下一步</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.van-cell.van-field){
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
</style>
|
40
app/pages/signature/protocol/index.vue
Normal file
40
app/pages/signature/protocol/index.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<script setup>
|
||||
const activeNames = ref(['1']);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-#EBEBEB h-screen-nav flex flex-col">
|
||||
<div class="h-50px text-14px text-#191919 bg-#fff flex items-center px-21px mb-6px">支付前需同意以下内容并签字</div>
|
||||
<van-collapse v-model="activeNames" class="grow-1">
|
||||
<van-collapse-item name="1" class="mb-6px">
|
||||
<template #title>
|
||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
||||
</template>
|
||||
代码是写出来给人看的,附带能在机器上运行。
|
||||
</van-collapse-item>
|
||||
<van-collapse-item name="2" class="mb-6px">
|
||||
<template #title>
|
||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
||||
</template>
|
||||
代码是写出来给人看的,附带能在机器上运行。
|
||||
</van-collapse-item>
|
||||
<van-collapse-item name="3" class="mb-6px">
|
||||
<template #title>
|
||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
||||
</template>
|
||||
代码是写出来给人看的,附带能在机器上运行。
|
||||
</van-collapse-item>
|
||||
</van-collapse>
|
||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
||||
<van-button color="#2B53AC" class="w-213px van-btn-h-38px">同意并签字</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.van-cell__right-icon){
|
||||
color: #ACACAC;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
@ -1,4 +1,4 @@
|
||||
import { setupHttp } from '~/api/http'
|
||||
import { setupHttp } from '@/api/http'
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
setupHttp()
|
||||
|
@ -1,5 +1,8 @@
|
||||
import {authStore} from "@/stores/auth";
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const config = useRuntimeConfig()
|
||||
const { token } = authStore()
|
||||
const ws = reactive({
|
||||
instance: null as WebSocket | null,
|
||||
isConnected: false,
|
||||
@ -11,8 +14,8 @@ export default defineNuxtPlugin(() => {
|
||||
}
|
||||
|
||||
// 构建查询字符串
|
||||
const queryString = data
|
||||
? '?' + Object.entries(data)
|
||||
const queryString =data
|
||||
? '?' + Object.entries({ token: token.value,...data})
|
||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
||||
.join('&')
|
||||
: ''
|
||||
|
BIN
app/static/images/dddf34@2x.png
Normal file
BIN
app/static/images/dddf34@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
BIN
app/static/images/delete3@.png
Normal file
BIN
app/static/images/delete3@.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
app/static/images/icon-design-42@3x.png
Normal file
BIN
app/static/images/icon-design-42@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 686 B |
BIN
app/static/images/zd5530@2x.png
Normal file
BIN
app/static/images/zd5530@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
13
app/stores-collect-code/auth/index.js
Normal file
13
app/stores-collect-code/auth/index.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { createGlobalState,useLocalStorage } from '@vueuse/core'
|
||||
export const codeAuthStore = createGlobalState(() => {
|
||||
const token=useLocalStorage('token','')
|
||||
const RefreshToken=useLocalStorage('RefreshToken','')
|
||||
const userInfo=useLocalStorage('userInfo',{})
|
||||
const fingerprint=useLocalStorage('fingerprint','')
|
||||
return{
|
||||
userInfo,
|
||||
RefreshToken,
|
||||
token,
|
||||
fingerprint
|
||||
}
|
||||
})
|
83
app/stores-collect-code/goods/index.js
Normal file
83
app/stores-collect-code/goods/index.js
Normal file
@ -0,0 +1,83 @@
|
||||
import { createGlobalState } from '@vueuse/core'
|
||||
import { ref } from 'vue'
|
||||
import { artworkList, defaultDetail, artworkDetail } from "@/api/goods/index.js"
|
||||
import {offlineQrcodeList} from "~/api-collect-code/goods/index.js";
|
||||
|
||||
export const goodStore = createGlobalState(() => {
|
||||
// 状态定义
|
||||
const actionDetails = ref({})
|
||||
const fullLive = ref(false)
|
||||
const currentItem = ref({})
|
||||
const myArtWorks = ref([])
|
||||
const pageRef = ref({
|
||||
page: 0,
|
||||
pageSize: 5,
|
||||
itemCount: 0
|
||||
})
|
||||
const artWorkDetail = ref(null)
|
||||
const itemList = 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 getOfflineQrcodeList = async (isRefresh = false) => {
|
||||
if (isRefresh) {
|
||||
resetPage()
|
||||
}
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await offlineQrcodeList({
|
||||
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) {
|
||||
return { finished: true, items: [] }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
// 状态
|
||||
actionDetails,
|
||||
fullLive,
|
||||
currentItem,
|
||||
myArtWorks,
|
||||
pageRef,
|
||||
artWorkDetail,
|
||||
itemList,
|
||||
auctionDetail,
|
||||
loading,
|
||||
error,
|
||||
// 方法
|
||||
getOfflineQrcodeList,
|
||||
resetPage
|
||||
}
|
||||
})
|
43
app/stores-collect-code/live/index.js
Normal file
43
app/stores-collect-code/live/index.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { createGlobalState } from '@vueuse/core'
|
||||
import {ref} from "vue";
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import {authStore} from "@/stores/auth/index.js";
|
||||
|
||||
export const liveStore = createGlobalState(() => {
|
||||
const {auctionDetail,getAuctionDetail} = goodStore();
|
||||
const { token } = authStore()
|
||||
const quoteStatus = ref(false)
|
||||
const show = ref(false)
|
||||
const show1=ref(true)
|
||||
const playerId=ref('J_prismPlayer')
|
||||
const auctionData=ref({})
|
||||
const getSocketData=async ()=>{
|
||||
if (!auctionDetail.value.uuid){
|
||||
await getAuctionDetail()
|
||||
}
|
||||
const { ws, messages, onMessage } = useWebSocket()
|
||||
|
||||
// 连接
|
||||
ws.connect('/api/v1/m/auction/live',{auctionUuid: auctionDetail.value.uuid,token:token.value})
|
||||
|
||||
/*// 发送消息
|
||||
ws.send({ type: 'chat', content: 'Hello!' })*/
|
||||
// 监听消息
|
||||
onMessage((data) => {
|
||||
|
||||
auctionData.value = data
|
||||
})
|
||||
}
|
||||
const changeStatus = () => {
|
||||
quoteStatus.value = !quoteStatus.value
|
||||
}
|
||||
return{
|
||||
auctionData,
|
||||
getSocketData,
|
||||
show1,
|
||||
playerId,
|
||||
show,
|
||||
quoteStatus,
|
||||
changeStatus
|
||||
}
|
||||
})
|
0
app/stores/floating/index.js
Normal file
0
app/stores/floating/index.js
Normal file
@ -1,6 +1,6 @@
|
||||
import { createGlobalState } from '@vueuse/core'
|
||||
import { createGlobalState,useLocalStorage } from '@vueuse/core'
|
||||
import { ref } from 'vue'
|
||||
import { artworkList, defaultDetail, artworkDetail } from "~/api/goods/index.js"
|
||||
import { artworkList, defaultDetail, artworkDetail } from "@/api/goods/index.js"
|
||||
|
||||
export const goodStore = createGlobalState(() => {
|
||||
// 状态定义
|
||||
@ -13,7 +13,7 @@ export const goodStore = createGlobalState(() => {
|
||||
pageSize: 5,
|
||||
itemCount: 0
|
||||
})
|
||||
const artWorkDetail = ref(null)
|
||||
const artWorkDetail = useLocalStorage('artWorkDetail',{})
|
||||
const itemList = ref([])
|
||||
const auctionDetail = ref({})
|
||||
const loading = ref(false)
|
||||
|
@ -1,14 +1,238 @@
|
||||
import { createGlobalState } from '@vueuse/core'
|
||||
import {ref} from "vue";
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import {authStore} from "@/stores/auth/index.js";
|
||||
import {message} from "~/components/x-message/useMessage.js";
|
||||
import { WebSocketClient } from '@/utils/websocket'
|
||||
import {logSendlog} from "~/api/goods/index.js";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
export const liveStore = createGlobalState(() => {
|
||||
const {auctionDetail} = goodStore();
|
||||
const { token } = authStore()
|
||||
const quoteStatus = ref(false)
|
||||
const show = ref(false)
|
||||
const cleanup = ref(null)
|
||||
const show1=ref(false)
|
||||
const playerId=ref('J_prismPlayer')
|
||||
const auctionData=ref({})
|
||||
const socket=ref(null)
|
||||
const config = useRuntimeConfig()
|
||||
const pullLink=ref('')
|
||||
// 解密工具函数
|
||||
const decryptUtils = {
|
||||
// 解密配置
|
||||
cryptConfig: {
|
||||
password: 'live-skkoql-1239-key',
|
||||
salt: 'aldk100128ls',
|
||||
iterations: 10000,
|
||||
keySize: 32
|
||||
},
|
||||
|
||||
// 生成密钥
|
||||
generateKey(password, salt, iterations, keySize) {
|
||||
return CryptoJS.PBKDF2(password, salt, {
|
||||
keySize: keySize / 4,
|
||||
iterations: iterations,
|
||||
hasher: CryptoJS.algo.SHA1
|
||||
}).toString(CryptoJS.enc.Hex)
|
||||
},
|
||||
|
||||
// AES解密
|
||||
decrypt(ciphertextBase64, key) {
|
||||
const combined = CryptoJS.enc.Base64.parse(ciphertextBase64)
|
||||
const iv = CryptoJS.lib.WordArray.create(combined.words.slice(0, 4))
|
||||
const ciphertext = CryptoJS.lib.WordArray.create(combined.words.slice(4))
|
||||
|
||||
const decrypted = CryptoJS.AES.decrypt(
|
||||
{ciphertext: ciphertext},
|
||||
CryptoJS.enc.Hex.parse(key),
|
||||
{
|
||||
iv: iv,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
}
|
||||
)
|
||||
|
||||
return decrypted.toString(CryptoJS.enc.Utf8)
|
||||
},
|
||||
|
||||
// 解密数据的主函数
|
||||
decryptData(encryptedData) {
|
||||
const keyDerived = this.generateKey(
|
||||
this.cryptConfig.password,
|
||||
this.cryptConfig.salt,
|
||||
this.cryptConfig.iterations,
|
||||
this.cryptConfig.keySize
|
||||
)
|
||||
return this.decrypt(encryptedData, keyDerived)
|
||||
}
|
||||
}
|
||||
const getLiveLink = () => {
|
||||
return new Promise(async(resolve, reject) => {
|
||||
const res = await logSendlog({
|
||||
uuid: auctionDetail.value.uuid
|
||||
})
|
||||
if (res.status===0){
|
||||
pullLink.value=decryptUtils.decryptData(res.data.code)
|
||||
resolve(decryptUtils.decryptData(res.data.code))
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
const getSocketData = async () => {
|
||||
const wsClient = new WebSocketClient(
|
||||
config.public.NUXT_PUBLIC_SOCKET_URL,
|
||||
token.value
|
||||
)
|
||||
const ws = wsClient.connect('/api/v1/m/auction/live', {
|
||||
auctionUuid: auctionDetail.value.uuid,
|
||||
})
|
||||
|
||||
ws.onOpen(() => {
|
||||
console.log('WebSocket connected')
|
||||
})
|
||||
|
||||
ws.onMessage((data) => {
|
||||
auctionData.value = data.data
|
||||
if (data.data?.wsType === 'tip' ) {
|
||||
if (data.data?.tip?.tipType === 'falling'){
|
||||
message.warning({
|
||||
title: {
|
||||
text: '即将落槌',
|
||||
color: '#F09F1F',
|
||||
align: 'center',
|
||||
},
|
||||
style: {
|
||||
width: '151px',
|
||||
bottom: '230px',
|
||||
},
|
||||
})
|
||||
}else if (data.data?.tip?.tipType === 'othersBid'){
|
||||
message.error({
|
||||
title: {
|
||||
text: '已有人出价',
|
||||
color: '#CF3050',
|
||||
align: 'center',
|
||||
},
|
||||
icon:false,
|
||||
subTitle:{
|
||||
text:'更新后再出价',
|
||||
color: '#939393',
|
||||
align: 'center',
|
||||
},
|
||||
style: {
|
||||
width: '151px',
|
||||
bottom: '230px'
|
||||
},
|
||||
})
|
||||
}else if (data.data?.tip?.tipType === 'successBid'){
|
||||
message.success({
|
||||
title: {
|
||||
text: '恭喜您,竞拍成功',
|
||||
color: '#18A058',
|
||||
align: 'center',
|
||||
},
|
||||
icon:false,
|
||||
subTitle:{
|
||||
text:'请缴款',
|
||||
color: '#939393',
|
||||
align: 'center',
|
||||
},
|
||||
style: {
|
||||
width: '151px',
|
||||
bottom: '230px'
|
||||
},
|
||||
})
|
||||
}else if (data.data?.tip?.tipType === 'artworkOver'){
|
||||
message.success({
|
||||
title: {
|
||||
text: '本拍品已结束',
|
||||
color: '#575757',
|
||||
align: 'center',
|
||||
|
||||
},
|
||||
icon:false,
|
||||
subTitle:{
|
||||
text:'请期待下个拍品',
|
||||
color: '#939393',
|
||||
align: 'center',
|
||||
},
|
||||
style: {
|
||||
width: '151px',
|
||||
bottom: '230px',
|
||||
backgroundColor: '#fff',
|
||||
borderColor:'#fff'
|
||||
},
|
||||
})
|
||||
}else if (data.data?.tip?.tipType === 'failBid'){
|
||||
message.error({
|
||||
title: {
|
||||
text: '很遗憾,竞拍失败',
|
||||
color: '#CF3050',
|
||||
align: 'center',
|
||||
},
|
||||
icon:false,
|
||||
subTitle:{
|
||||
text:'竞拍结束',
|
||||
color: '#939393',
|
||||
align: 'center',
|
||||
},
|
||||
style: {
|
||||
width: '186px',
|
||||
bottom: '230px'
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
}else if (data.data?.wsType==='stopArtwor'){
|
||||
quoteStatus.value=false
|
||||
}else if (data.data?.wsType==='over'){
|
||||
message.success({
|
||||
title: {
|
||||
text: '竞拍结束,谢谢参与',
|
||||
color: '#575757',
|
||||
align: 'center',
|
||||
|
||||
},
|
||||
icon:false,
|
||||
style: {
|
||||
width: '195px',
|
||||
bottom: '230px',
|
||||
backgroundColor: '#fff',
|
||||
borderColor:'#fff'
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
console.log('onmessage', data)
|
||||
})
|
||||
|
||||
ws.onClose(() => {
|
||||
console.log('WebSocket disconnected')
|
||||
})
|
||||
|
||||
ws.onError((error) => {
|
||||
console.error('WebSocket error:', error)
|
||||
})
|
||||
}
|
||||
const changeStatus = () => {
|
||||
quoteStatus.value = !quoteStatus.value
|
||||
if (auctionData.value.artwork.isSelling&&!auctionData.value.artwork.isSoled){
|
||||
quoteStatus.value = true
|
||||
}else {
|
||||
if (quoteStatus.value){
|
||||
quoteStatus.value = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return{
|
||||
pullLink,
|
||||
getLiveLink,
|
||||
auctionData,
|
||||
getSocketData,
|
||||
show1,
|
||||
playerId,
|
||||
show,
|
||||
|
65
app/utils/websocket.ts
Normal file
65
app/utils/websocket.ts
Normal file
@ -0,0 +1,65 @@
|
||||
export class WebSocketClient {
|
||||
private socket: WebSocket | null = null
|
||||
private baseUrl: string
|
||||
private token: string
|
||||
|
||||
constructor(baseUrl: string, token: string) {
|
||||
this.baseUrl = baseUrl
|
||||
this.token = token
|
||||
}
|
||||
|
||||
connect(path: string, params: Record<string, any> = {}) {
|
||||
// 如果存在旧连接,先关闭
|
||||
this.disconnect()
|
||||
|
||||
// 构建参数对象,自动添加 token
|
||||
const queryParams = {
|
||||
token: this.token,
|
||||
...params
|
||||
}
|
||||
|
||||
// 构建查询字符串
|
||||
const queryString = '?' + Object.entries(queryParams)
|
||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
||||
.join('&')
|
||||
|
||||
// 构建完整的 WebSocket URL
|
||||
const wsUrl = `${this.baseUrl}${path}${queryString}`
|
||||
this.socket = new WebSocket(wsUrl)
|
||||
|
||||
return {
|
||||
onOpen: (callback: () => void) => {
|
||||
this.socket!.onopen = callback
|
||||
},
|
||||
onMessage: (callback: (data: any) => void) => {
|
||||
this.socket!.onmessage = (event) => {
|
||||
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
|
||||
callback(data)
|
||||
} catch (error) {
|
||||
console.error('解析消息失败:', error)
|
||||
}
|
||||
}
|
||||
},
|
||||
onClose: (callback: () => void) => {
|
||||
this.socket!.onclose = callback
|
||||
},
|
||||
onError: (callback: (error: Event) => void) => {
|
||||
this.socket!.onerror = callback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.socket) {
|
||||
this.socket.close()
|
||||
this.socket = null
|
||||
}
|
||||
}
|
||||
|
||||
isConnected() {
|
||||
return this.socket?.readyState === WebSocket.OPEN
|
||||
}
|
||||
}
|
6
env/.env.test
vendored
6
env/.env.test
vendored
@ -1,7 +1,7 @@
|
||||
# 测试环境配置
|
||||
NUXT_PUBLIC_API_BASE=http://172.16.100.99:8005
|
||||
NUXT_PUBLIC_WS_URL=ws://test-ws.example.com
|
||||
NUXT_PUBLIC_API_BASE=https://auction-test.szjixun.cn
|
||||
NUXT_PUBLIC_API_COLLECT_CODE=https://auction-test.szjixun.cn
|
||||
NUXT_API_SECRET=test-secret
|
||||
NUXT_PUBLIC_SOCKET_URL=ws://172.16.100.99:8005
|
||||
# 阿里云播放器配置
|
||||
NUXT_PUBLIC_PLAYER_SOURCE=artc://live-pull-sh-01.szjixun.cn/live/live?auth_key=1737080180-0-0-42ad4cf26ba26eee78ca7de9c524d1e0
|
||||
NUXT_PUBLIC_PLAYER_SOURCE=artc://live-push-sh-01.szjixun.cn/live001/86180cae-1e07-4b8d-b45e-50d8ce800110?auth_key=1739255918-0-0-5251017e725a860570a59de7e4e2fd98
|
||||
|
@ -18,6 +18,11 @@ export default defineNuxtConfig({
|
||||
'@nuxt/image',
|
||||
'@nuxtjs/i18n',
|
||||
],
|
||||
image: {
|
||||
provider: 'ipx',
|
||||
format: ['webp'],
|
||||
quality: 80,
|
||||
},
|
||||
runtimeConfig: {
|
||||
// 私有配置,只有在服务端可用
|
||||
apiSecret: process.env.NUXT_API_SECRET,
|
||||
|
@ -23,9 +23,12 @@
|
||||
"@yeger/vue-masonry-wall": "^5.0.17",
|
||||
"aliyun-aliplayer": "^2.28.5",
|
||||
"axios": "^1.7.9",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"dotenv": "^16.4.7",
|
||||
"nuxt": "^3.15.0",
|
||||
"pinyin": "4.0.0-alpha.2",
|
||||
"qrcode": "^1.5.4",
|
||||
"segmentit": "^2.0.3",
|
||||
"vconsole": "^3.15.1",
|
||||
"vue": "^3.5.13",
|
||||
@ -39,9 +42,11 @@
|
||||
"@vant/nuxt": "^1.0.6",
|
||||
"bumpp": "^9.9.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"ipx": "^3.0.1",
|
||||
"postcss-mobile-forever": "^4.3.1",
|
||||
"sass": "^1.83.1",
|
||||
"sass-loader": "^16.0.4",
|
||||
"sharp": "^0.33.5",
|
||||
"typescript": "~5.7.2",
|
||||
"vant": "^4.9.15"
|
||||
},
|
||||
|
458
pnpm-lock.yaml
458
pnpm-lock.yaml
@ -29,6 +29,12 @@ importers:
|
||||
axios:
|
||||
specifier: ^1.7.9
|
||||
version: 1.7.9
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
dayjs:
|
||||
specifier: ^1.11.13
|
||||
version: 1.11.13
|
||||
dotenv:
|
||||
specifier: ^16.4.7
|
||||
version: 16.4.7
|
||||
@ -38,6 +44,9 @@ importers:
|
||||
pinyin:
|
||||
specifier: 4.0.0-alpha.2
|
||||
version: 4.0.0-alpha.2(segmentit@2.0.3)
|
||||
qrcode:
|
||||
specifier: ^1.5.4
|
||||
version: 1.5.4
|
||||
segmentit:
|
||||
specifier: ^2.0.3
|
||||
version: 2.0.3
|
||||
@ -72,6 +81,9 @@ importers:
|
||||
cross-env:
|
||||
specifier: ^7.0.3
|
||||
version: 7.0.3
|
||||
ipx:
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1(db0@0.2.1)(ioredis@5.4.2)
|
||||
postcss-mobile-forever:
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.2(postcss@8.5.1)
|
||||
@ -81,6 +93,9 @@ importers:
|
||||
sass-loader:
|
||||
specifier: ^16.0.4
|
||||
version: 16.0.4(sass@1.83.4)(webpack@5.97.1(esbuild@0.24.2))
|
||||
sharp:
|
||||
specifier: ^0.33.5
|
||||
version: 0.33.5
|
||||
typescript:
|
||||
specifier: ~5.7.2
|
||||
version: 5.7.3
|
||||
@ -251,6 +266,9 @@ packages:
|
||||
resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==}
|
||||
engines: {node: '>=16.13'}
|
||||
|
||||
'@emnapi/runtime@1.3.1':
|
||||
resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.23.1':
|
||||
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
|
||||
engines: {node: '>=18'}
|
||||
@ -615,6 +633,123 @@ packages:
|
||||
'@iconify/utils@2.2.1':
|
||||
resolution: {integrity: sha512-0/7J7hk4PqXmxo5PDBDxmnecw5PxklZJfNjIVG9FM0mEfVrvfudS22rYWsqVk6gR3UJ/mSYS90X4R3znXnqfNA==}
|
||||
|
||||
'@img/sharp-darwin-arm64@0.33.5':
|
||||
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-darwin-x64@0.33.5':
|
||||
resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-darwin-arm64@1.0.4':
|
||||
resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-darwin-x64@1.0.4':
|
||||
resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@img/sharp-libvips-linux-arm64@1.0.4':
|
||||
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.0.5':
|
||||
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.0.4':
|
||||
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.0.4':
|
||||
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
|
||||
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
|
||||
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linux-arm64@0.33.5':
|
||||
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-arm@0.33.5':
|
||||
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-s390x@0.33.5':
|
||||
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-x64@0.33.5':
|
||||
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.33.5':
|
||||
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.33.5':
|
||||
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-wasm32@0.33.5':
|
||||
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@img/sharp-win32-ia32@0.33.5':
|
||||
resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@img/sharp-win32-x64@0.33.5':
|
||||
resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@intlify/bundle-utils@10.0.0':
|
||||
resolution: {integrity: sha512-BR5yLOkF2dzrARTbAg7RGAIPcx9Aark7p1K/0O285F7rfzso9j2dsa+S4dA67clZ0rToZ10NSSTfbyUptVu7Bg==}
|
||||
engines: {node: '>= 18'}
|
||||
@ -655,8 +790,8 @@ packages:
|
||||
resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@11.0.1':
|
||||
resolution: {integrity: sha512-lH164+aDDptHZ3dBDbIhRa1dOPQUp+83iugpc+1upTOWCnwyC1PVis6rSWNMMJ8VQxvtHQB9JMib48K55y0PvQ==}
|
||||
'@intlify/shared@11.1.1':
|
||||
resolution: {integrity: sha512-2kGiWoXaeV8HZlhU/Nml12oTbhv7j2ufsJ5vQaa0VTjzUmZVdd/nmKFRAOJ/FtjO90Qba5AnZDwsrY7ZND5udA==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@6.0.3':
|
||||
@ -1690,6 +1825,10 @@ packages:
|
||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
camelcase@5.3.1:
|
||||
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
caniuse-api@3.0.0:
|
||||
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
|
||||
|
||||
@ -1733,6 +1872,9 @@ packages:
|
||||
resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
cliui@6.0.0:
|
||||
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
|
||||
|
||||
cliui@8.0.1:
|
||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||
engines: {node: '>=12'}
|
||||
@ -1921,6 +2063,9 @@ packages:
|
||||
csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
dayjs@1.11.13:
|
||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||
|
||||
db0@0.2.1:
|
||||
resolution: {integrity: sha512-BWSFmLaCkfyqbSEZBQINMVNjCVfrogi7GQ2RSy1tmtfK9OXlsup6lUMwLsqSD7FbAjD04eWFdXowSHHUp6SE/Q==}
|
||||
peerDependencies:
|
||||
@ -1958,6 +2103,10 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
decamelize@1.2.0:
|
||||
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
decompress-response@6.0.0:
|
||||
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -2027,6 +2176,9 @@ packages:
|
||||
resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
|
||||
dijkstrajs@1.0.3:
|
||||
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||
|
||||
dom-serializer@2.0.0:
|
||||
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
||||
|
||||
@ -2263,6 +2415,10 @@ packages:
|
||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
find-up@4.1.0:
|
||||
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
find-up@5.0.0:
|
||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||
engines: {node: '>=10'}
|
||||
@ -2511,6 +2667,10 @@ packages:
|
||||
resolution: {integrity: sha512-AVnPGXJ8L41vjd11Z4akIF2yd14636Klxul3tBySxHA6PKfCOQPxBDkCFK5zcWh0z/keR6toh1eg8qzdBVUgdA==}
|
||||
hasBin: true
|
||||
|
||||
ipx@3.0.1:
|
||||
resolution: {integrity: sha512-OqbP9wLqpGXtI/le0sU4exCH5cb7kZS9jaV5xDDM8wZ62VJZBBhEjR0gXwK0agA/GfS4g/GGwY9fFSIFrTb4Gg==}
|
||||
hasBin: true
|
||||
|
||||
iron-webcrypto@1.2.1:
|
||||
resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
|
||||
|
||||
@ -2727,6 +2887,10 @@ packages:
|
||||
resolution: {integrity: sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
locate-path@5.0.0:
|
||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
locate-path@6.0.0:
|
||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||
engines: {node: '>=10'}
|
||||
@ -3040,14 +3204,26 @@ packages:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
p-limit@2.3.0:
|
||||
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
p-limit@3.1.0:
|
||||
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
p-locate@4.1.0:
|
||||
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
p-locate@5.0.0:
|
||||
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
p-try@2.2.0:
|
||||
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
package-json-from-dist@1.0.1:
|
||||
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
||||
|
||||
@ -3162,6 +3338,10 @@ packages:
|
||||
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
pngjs@5.0.0:
|
||||
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
postcss-calc@10.1.0:
|
||||
resolution: {integrity: sha512-uQ/LDGsf3mgsSUEXmAt3VsCSHR3aKqtEIkmB+4PhzYwRYOW5MZs/GhCCFpsOtJJkP6EC6uGipbrnaTjqaJZcJw==}
|
||||
engines: {node: ^18.12 || ^20.9 || >=22.0}
|
||||
@ -3384,6 +3564,11 @@ packages:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
qrcode@1.5.4:
|
||||
resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
@ -3448,6 +3633,9 @@ packages:
|
||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
require-main-filename@2.0.0:
|
||||
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
||||
|
||||
resolve-from@4.0.0:
|
||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||
engines: {node: '>=4'}
|
||||
@ -3569,6 +3757,9 @@ packages:
|
||||
resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
set-blocking@2.0.0:
|
||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||
|
||||
setprototypeof@1.2.0:
|
||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||
|
||||
@ -3576,6 +3767,10 @@ packages:
|
||||
resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==}
|
||||
engines: {node: '>=14.15.0'}
|
||||
|
||||
sharp@0.33.5:
|
||||
resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
@ -4204,6 +4399,9 @@ packages:
|
||||
whatwg-url@5.0.0:
|
||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||
|
||||
which-module@2.0.1:
|
||||
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -4218,6 +4416,10 @@ packages:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
@ -4246,6 +4448,9 @@ packages:
|
||||
engines: {node: '>= 0.10.0'}
|
||||
hasBin: true
|
||||
|
||||
y18n@4.0.3:
|
||||
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||
|
||||
y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
@ -4276,10 +4481,18 @@ packages:
|
||||
engines: {node: '>= 14'}
|
||||
hasBin: true
|
||||
|
||||
yargs-parser@18.1.3:
|
||||
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
yargs-parser@21.1.1:
|
||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yargs@15.4.1:
|
||||
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
yargs@17.7.2:
|
||||
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||
engines: {node: '>=12'}
|
||||
@ -4510,6 +4723,11 @@ snapshots:
|
||||
dependencies:
|
||||
mime: 3.0.0
|
||||
|
||||
'@emnapi/runtime@1.3.1':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.23.1':
|
||||
optional: true
|
||||
|
||||
@ -4699,8 +4917,7 @@ snapshots:
|
||||
'@eslint/core': 0.10.0
|
||||
levn: 0.4.1
|
||||
|
||||
'@fastify/accept-negotiator@1.1.0':
|
||||
optional: true
|
||||
'@fastify/accept-negotiator@1.1.0': {}
|
||||
|
||||
'@fingerprintjs/fingerprintjs@4.5.1':
|
||||
dependencies:
|
||||
@ -4738,6 +4955,81 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@img/sharp-darwin-arm64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-arm64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-darwin-x64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-darwin-x64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-darwin-arm64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-darwin-x64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-arm64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.0.5':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-arm64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-arm@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-arm': 1.0.5
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-s390x@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-s390x': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linux-x64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linux-x64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.33.5':
|
||||
optionalDependencies:
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
|
||||
optional: true
|
||||
|
||||
'@img/sharp-wasm32@0.33.5':
|
||||
dependencies:
|
||||
'@emnapi/runtime': 1.3.1
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-ia32@0.33.5':
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-x64@0.33.5':
|
||||
optional: true
|
||||
|
||||
'@intlify/bundle-utils@10.0.0(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 11.0.0-rc.1
|
||||
@ -4781,14 +5073,14 @@ snapshots:
|
||||
|
||||
'@intlify/shared@11.0.0-rc.1': {}
|
||||
|
||||
'@intlify/shared@11.0.1': {}
|
||||
'@intlify/shared@11.1.1': {}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.18.0(jiti@2.4.2))(rollup@4.31.0)(typescript@5.7.3)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.2))
|
||||
'@intlify/bundle-utils': 10.0.0(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))
|
||||
'@intlify/shared': 11.0.1
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.0.1)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
'@intlify/shared': 11.1.1
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.1)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
'@rollup/pluginutils': 5.1.4(rollup@4.31.0)
|
||||
'@typescript-eslint/scope-manager': 8.21.0
|
||||
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.3)
|
||||
@ -4812,11 +5104,11 @@ snapshots:
|
||||
|
||||
'@intlify/utils@0.13.0': {}
|
||||
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.0.1)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.1)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.5(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
dependencies:
|
||||
'@babel/parser': 7.26.5
|
||||
optionalDependencies:
|
||||
'@intlify/shared': 11.0.1
|
||||
'@intlify/shared': 11.1.1
|
||||
'@vue/compiler-dom': 3.5.13
|
||||
vue: 3.5.13(typescript@5.7.3)
|
||||
vue-i18n: 10.0.5(vue@3.5.13(typescript@5.7.3))
|
||||
@ -6257,6 +6549,8 @@ snapshots:
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
camelcase@5.3.1: {}
|
||||
|
||||
caniuse-api@3.0.0:
|
||||
dependencies:
|
||||
browserslist: 4.24.4
|
||||
@ -6308,6 +6602,12 @@ snapshots:
|
||||
is-wsl: 3.1.0
|
||||
is64bit: 2.0.0
|
||||
|
||||
cliui@6.0.0:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
|
||||
cliui@8.0.1:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
@ -6326,13 +6626,11 @@ snapshots:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.2
|
||||
optional: true
|
||||
|
||||
color@4.2.3:
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
color-string: 1.9.1
|
||||
optional: true
|
||||
|
||||
colord@2.9.3: {}
|
||||
|
||||
@ -6454,8 +6752,7 @@ snapshots:
|
||||
|
||||
cssesc@3.0.0: {}
|
||||
|
||||
cssfilter@0.0.10:
|
||||
optional: true
|
||||
cssfilter@0.0.10: {}
|
||||
|
||||
cssnano-preset-default@7.0.6(postcss@8.5.1):
|
||||
dependencies:
|
||||
@ -6507,6 +6804,8 @@ snapshots:
|
||||
|
||||
csstype@3.1.3: {}
|
||||
|
||||
dayjs@1.11.13: {}
|
||||
|
||||
db0@0.2.1: {}
|
||||
|
||||
debug@2.6.9:
|
||||
@ -6519,6 +6818,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
supports-color: 9.4.0
|
||||
|
||||
decamelize@1.2.0: {}
|
||||
|
||||
decompress-response@6.0.0:
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
@ -6562,6 +6863,8 @@ snapshots:
|
||||
|
||||
diff@7.0.0: {}
|
||||
|
||||
dijkstrajs@1.0.3: {}
|
||||
|
||||
dom-serializer@2.0.0:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
@ -6862,6 +7165,11 @@ snapshots:
|
||||
dependencies:
|
||||
to-regex-range: 5.0.1
|
||||
|
||||
find-up@4.1.0:
|
||||
dependencies:
|
||||
locate-path: 5.0.0
|
||||
path-exists: 4.0.0
|
||||
|
||||
find-up@5.0.0:
|
||||
dependencies:
|
||||
locate-path: 6.0.0
|
||||
@ -7160,12 +7468,49 @@ snapshots:
|
||||
- uploadthing
|
||||
optional: true
|
||||
|
||||
ipx@3.0.1(db0@0.2.1)(ioredis@5.4.2):
|
||||
dependencies:
|
||||
'@fastify/accept-negotiator': 1.1.0
|
||||
citty: 0.1.6
|
||||
consola: 3.4.0
|
||||
defu: 6.1.4
|
||||
destr: 2.0.3
|
||||
etag: 1.8.1
|
||||
h3: 1.14.0
|
||||
image-meta: 0.2.1
|
||||
listhen: 1.9.0
|
||||
ofetch: 1.4.1
|
||||
pathe: 1.1.2
|
||||
sharp: 0.33.5
|
||||
svgo: 3.3.2
|
||||
ufo: 1.5.4
|
||||
unstorage: 1.14.4(db0@0.2.1)(ioredis@5.4.2)
|
||||
xss: 1.0.15
|
||||
transitivePeerDependencies:
|
||||
- '@azure/app-configuration'
|
||||
- '@azure/cosmos'
|
||||
- '@azure/data-tables'
|
||||
- '@azure/identity'
|
||||
- '@azure/keyvault-secrets'
|
||||
- '@azure/storage-blob'
|
||||
- '@capacitor/preferences'
|
||||
- '@deno/kv'
|
||||
- '@netlify/blobs'
|
||||
- '@planetscale/database'
|
||||
- '@upstash/redis'
|
||||
- '@vercel/blob'
|
||||
- '@vercel/kv'
|
||||
- aws4fetch
|
||||
- db0
|
||||
- idb-keyval
|
||||
- ioredis
|
||||
- uploadthing
|
||||
|
||||
iron-webcrypto@1.2.1: {}
|
||||
|
||||
is-arrayish@0.2.1: {}
|
||||
|
||||
is-arrayish@0.3.2:
|
||||
optional: true
|
||||
is-arrayish@0.3.2: {}
|
||||
|
||||
is-binary-path@2.1.0:
|
||||
dependencies:
|
||||
@ -7354,6 +7699,10 @@ snapshots:
|
||||
mlly: 1.7.4
|
||||
pkg-types: 1.3.1
|
||||
|
||||
locate-path@5.0.0:
|
||||
dependencies:
|
||||
p-locate: 4.1.0
|
||||
|
||||
locate-path@6.0.0:
|
||||
dependencies:
|
||||
p-locate: 5.0.0
|
||||
@ -7836,14 +8185,24 @@ snapshots:
|
||||
type-check: 0.4.0
|
||||
word-wrap: 1.2.5
|
||||
|
||||
p-limit@2.3.0:
|
||||
dependencies:
|
||||
p-try: 2.2.0
|
||||
|
||||
p-limit@3.1.0:
|
||||
dependencies:
|
||||
yocto-queue: 0.1.0
|
||||
|
||||
p-locate@4.1.0:
|
||||
dependencies:
|
||||
p-limit: 2.3.0
|
||||
|
||||
p-locate@5.0.0:
|
||||
dependencies:
|
||||
p-limit: 3.1.0
|
||||
|
||||
p-try@2.2.0: {}
|
||||
|
||||
package-json-from-dist@1.0.1: {}
|
||||
|
||||
package-manager-detector@0.2.8: {}
|
||||
@ -7930,6 +8289,8 @@ snapshots:
|
||||
|
||||
pluralize@8.0.0: {}
|
||||
|
||||
pngjs@5.0.0: {}
|
||||
|
||||
postcss-calc@10.1.0(postcss@8.5.1):
|
||||
dependencies:
|
||||
postcss: 8.5.1
|
||||
@ -8146,6 +8507,12 @@ snapshots:
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
qrcode@1.5.4:
|
||||
dependencies:
|
||||
dijkstrajs: 1.0.3
|
||||
pngjs: 5.0.0
|
||||
yargs: 15.4.1
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
queue-tick@1.0.1: {}
|
||||
@ -8218,6 +8585,8 @@ snapshots:
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
require-main-filename@2.0.0: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
|
||||
resolve-from@5.0.0: {}
|
||||
@ -8355,6 +8724,8 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
set-blocking@2.0.0: {}
|
||||
|
||||
setprototypeof@1.2.0: {}
|
||||
|
||||
sharp@0.32.6:
|
||||
@ -8371,6 +8742,32 @@ snapshots:
|
||||
- bare-buffer
|
||||
optional: true
|
||||
|
||||
sharp@0.33.5:
|
||||
dependencies:
|
||||
color: 4.2.3
|
||||
detect-libc: 2.0.3
|
||||
semver: 7.6.3
|
||||
optionalDependencies:
|
||||
'@img/sharp-darwin-arm64': 0.33.5
|
||||
'@img/sharp-darwin-x64': 0.33.5
|
||||
'@img/sharp-libvips-darwin-arm64': 1.0.4
|
||||
'@img/sharp-libvips-darwin-x64': 1.0.4
|
||||
'@img/sharp-libvips-linux-arm': 1.0.5
|
||||
'@img/sharp-libvips-linux-arm64': 1.0.4
|
||||
'@img/sharp-libvips-linux-s390x': 1.0.4
|
||||
'@img/sharp-libvips-linux-x64': 1.0.4
|
||||
'@img/sharp-libvips-linuxmusl-arm64': 1.0.4
|
||||
'@img/sharp-libvips-linuxmusl-x64': 1.0.4
|
||||
'@img/sharp-linux-arm': 0.33.5
|
||||
'@img/sharp-linux-arm64': 0.33.5
|
||||
'@img/sharp-linux-s390x': 0.33.5
|
||||
'@img/sharp-linux-x64': 0.33.5
|
||||
'@img/sharp-linuxmusl-arm64': 0.33.5
|
||||
'@img/sharp-linuxmusl-x64': 0.33.5
|
||||
'@img/sharp-wasm32': 0.33.5
|
||||
'@img/sharp-win32-ia32': 0.33.5
|
||||
'@img/sharp-win32-x64': 0.33.5
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
@ -8404,7 +8801,6 @@ snapshots:
|
||||
simple-swizzle@0.2.2:
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
optional: true
|
||||
|
||||
sirv@3.0.0:
|
||||
dependencies:
|
||||
@ -9064,6 +9460,8 @@ snapshots:
|
||||
tr46: 0.0.3
|
||||
webidl-conversions: 3.0.1
|
||||
|
||||
which-module@2.0.1: {}
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
@ -9074,6 +9472,12 @@ snapshots:
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
@ -9094,7 +9498,8 @@ snapshots:
|
||||
dependencies:
|
||||
commander: 2.20.3
|
||||
cssfilter: 0.0.10
|
||||
optional: true
|
||||
|
||||
y18n@4.0.3: {}
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
@ -9116,8 +9521,27 @@ snapshots:
|
||||
|
||||
yaml@2.7.0: {}
|
||||
|
||||
yargs-parser@18.1.3:
|
||||
dependencies:
|
||||
camelcase: 5.3.1
|
||||
decamelize: 1.2.0
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
yargs@15.4.1:
|
||||
dependencies:
|
||||
cliui: 6.0.0
|
||||
decamelize: 1.2.0
|
||||
find-up: 4.1.0
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
require-main-filename: 2.0.0
|
||||
set-blocking: 2.0.0
|
||||
string-width: 4.2.3
|
||||
which-module: 2.0.1
|
||||
y18n: 4.0.3
|
||||
yargs-parser: 18.1.3
|
||||
|
||||
yargs@17.7.2:
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
|
@ -13,6 +13,15 @@ import {
|
||||
|
||||
// https://unocss.dev/guide/config-file
|
||||
export default defineConfig({
|
||||
rules: [
|
||||
['h-screen-nav', { height: 'calc(100vh - var(--van-nav-bar-height))' }],
|
||||
[/^van-btn-w-(\d+)px$/, ([_, d]) => ({
|
||||
width: `${d}px !important` // 使用 !important 覆盖默认样式
|
||||
})],
|
||||
[/^van-btn-h-(\d+)px$/, ([_, d]) => ({
|
||||
height: `${d}px !important`
|
||||
})]
|
||||
],
|
||||
shortcuts: [
|
||||
// shortcuts to multiple utilities
|
||||
['btn', 'px-6 py-3 rounded-3 inline-block bg-primary text-white cursor-pointer hover:bg-primary-hover disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
|
||||
|
Loading…
Reference in New Issue
Block a user