feat(i18n): 优化国际化文案并添加通用拍卖术语- 更新了多个组件中的国际化文案,使其更加统一和准确
- 在 zh-CN.json 中添加了"common"字段,用于存储通用拍卖术语 - 调整了部分组件的布局和样式,以更好地展示国际化文案
This commit is contained in:
parent
b927267c6a
commit
226057ce8f
@ -1,9 +1,11 @@
|
||||
<script setup>
|
||||
import { useAppHeaderRouteNames as routeWhiteList } from '@/config'
|
||||
import { liveStore } from "@/stores/live/index.js";
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
const { fullLive } = liveStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const {auctionDetail} = goodStore();
|
||||
function onBack() {
|
||||
if (fullLive.value){
|
||||
fullLive.value=false
|
||||
@ -40,11 +42,9 @@ const showLeftArrow = computed(() => route.name && routeWhiteList.includes(route
|
||||
placeholder clickable fixed
|
||||
@click-left="onBack"
|
||||
>
|
||||
<template #title v-if="route.meta.i18n==='menu.goods'">
|
||||
|
||||
<template #title v-if="route.meta.i18n==='menu.home'">
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
<div class="text-#000000 text-17px mb-5px font-600">{{ title }}</div>
|
||||
<div class="text-#939393 text-10px line-height-none font-100">{{subTitle}}</div>
|
||||
<div class="text-#000000 text-17px mb-5px font-600">{{ auctionDetail.title }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</VanNavBar>
|
||||
|
199
app/components/drag-window/index.vue
Normal file
199
app/components/drag-window/index.vue
Normal file
@ -0,0 +1,199 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
initialPosition: {
|
||||
type: Object,
|
||||
default: () => ({ x: 0, y: 0 })
|
||||
},
|
||||
stick: {
|
||||
type: String,
|
||||
default: null,
|
||||
validator: (value) => ['left', 'right', 'top', 'bottom', null].includes(value)
|
||||
},
|
||||
dragMode: {
|
||||
type: String,
|
||||
default: 'free',
|
||||
validator: (value) => ['free', 'horizontal', 'vertical'].includes(value)
|
||||
},
|
||||
stickyDistance: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
margin: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:position'])
|
||||
|
||||
const containerRef = ref(null)
|
||||
const position = ref(props.initialPosition)
|
||||
const isDragging = ref(false)
|
||||
const startPos = ref({ x: 0, y: 0 })
|
||||
const windowSize = ref({ width: 0, height: 0 })
|
||||
const elementSize = ref({ width: 0, height: 0 })
|
||||
|
||||
const transformStyle = computed(() => ({
|
||||
transform: `translate3d(${position.value.x}px, ${position.value.y}px, 0)`,
|
||||
zIndex: props.zIndex,
|
||||
position: 'fixed',
|
||||
top: '0',
|
||||
left: '0', // 添加基准定位点
|
||||
right: 'auto',
|
||||
bottom: 'auto'
|
||||
}))
|
||||
|
||||
const updateSizes = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
windowSize.value = {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
}
|
||||
if (containerRef.value) {
|
||||
elementSize.value = {
|
||||
width: containerRef.value.offsetWidth,
|
||||
height: containerRef.value.offsetHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleStick = (pos) => {
|
||||
if (!props.stick) return pos
|
||||
|
||||
const { width, height } = elementSize.value
|
||||
const { stickyDistance, margin } = props
|
||||
const maxX = windowSize.value.width - width - margin
|
||||
const maxY = windowSize.value.height - height - margin
|
||||
|
||||
const newPos = { ...pos }
|
||||
|
||||
switch (props.stick) {
|
||||
case 'left':
|
||||
if (pos.x < stickyDistance) newPos.x = margin
|
||||
break
|
||||
case 'right':
|
||||
if (maxX - pos.x < stickyDistance) newPos.x = maxX
|
||||
break
|
||||
case 'top':
|
||||
if (pos.y < stickyDistance) newPos.y = margin
|
||||
break
|
||||
case 'bottom':
|
||||
if (maxY - pos.y < stickyDistance) newPos.y = maxY
|
||||
break
|
||||
}
|
||||
|
||||
return newPos
|
||||
}
|
||||
|
||||
const constrainPosition = (pos) => {
|
||||
const { width, height } = elementSize.value
|
||||
const { margin } = props
|
||||
const maxX = windowSize.value.width - width - margin
|
||||
const maxY = windowSize.value.height - height - margin
|
||||
|
||||
return {
|
||||
x: Math.min(Math.max(pos.x, margin), maxX),
|
||||
y: Math.min(Math.max(pos.y, margin), maxY)
|
||||
}
|
||||
}
|
||||
|
||||
const handleStart = (event) => {
|
||||
if (!props.draggable) return
|
||||
|
||||
const e = event.touches ? event.touches[0] : event
|
||||
isDragging.value = true
|
||||
startPos.value = {
|
||||
x: e.clientX - position.value.x,
|
||||
y: e.clientY - position.value.y
|
||||
}
|
||||
}
|
||||
|
||||
const handleMove = (event) => {
|
||||
if (!isDragging.value) return
|
||||
|
||||
const e = event.touches ? event.touches[0] : event
|
||||
let newPos = {
|
||||
x: e.clientX - startPos.value.x,
|
||||
y: e.clientY - startPos.value.y
|
||||
}
|
||||
|
||||
if (props.dragMode === 'horizontal') {
|
||||
newPos.y = position.value.y
|
||||
} else if (props.dragMode === 'vertical') {
|
||||
newPos.x = position.value.x
|
||||
}
|
||||
|
||||
newPos = handleStick(newPos)
|
||||
newPos = constrainPosition(newPos)
|
||||
|
||||
position.value = newPos
|
||||
emit('update:position', newPos)
|
||||
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
const handleEnd = () => {
|
||||
isDragging.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
updateSizes()
|
||||
window.addEventListener('resize', updateSizes)
|
||||
document.addEventListener('mousemove', handleMove)
|
||||
document.addEventListener('mouseup', handleEnd)
|
||||
document.addEventListener('touchmove', handleMove, { passive: false })
|
||||
document.addEventListener('touchend', handleEnd)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', updateSizes)
|
||||
document.removeEventListener('mousemove', handleMove)
|
||||
document.removeEventListener('mouseup', handleEnd)
|
||||
document.removeEventListener('touchmove', handleMove)
|
||||
document.removeEventListener('touchend', handleEnd)
|
||||
})
|
||||
|
||||
watch(() => props.initialPosition, (newPos) => {
|
||||
position.value = newPos
|
||||
}, {deep: true})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="containerRef"
|
||||
class="drag-window"
|
||||
:class="{ 'dragging': isDragging }"
|
||||
:style="transformStyle"
|
||||
@mousedown="handleStart"
|
||||
@touchstart="handleStart"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.drag-window {
|
||||
position: fixed;
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
will-change: transform;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.drag-window.dragging {
|
||||
transition: none;
|
||||
cursor: move;
|
||||
}
|
||||
</style>
|
@ -20,29 +20,29 @@ const props = defineProps({
|
||||
<div class="text-[#000] text-[16px] mb-[12px]">{{detailInfo?.artworkTitle}}</div>
|
||||
<div class="text-#575757 text-[14px] pb-8px">
|
||||
<div class="flex mb-[4px]">
|
||||
<div class="w-[70px]">作者:</div>
|
||||
<div class="w-[70px]">{{$t('detail.text1')}}:</div>
|
||||
<div>{{detailInfo?.artwork?.artistName??'-'}}</div>
|
||||
</div>
|
||||
<div class="flex mb-[4px]">
|
||||
<div class="w-[70px] flex-shrink-0">总平尺数:</div>
|
||||
<div class="w-[70px] flex-shrink-0">{{$t('detail.text2')}}:</div>
|
||||
<div>{{detailInfo?.artwork?.ruler??'-'}}</div>
|
||||
</div>
|
||||
<div class="flex mb-[4px]">
|
||||
<div class="w-[70px] flex-shrink-0">长*宽:</div>
|
||||
<div class="w-[70px] flex-shrink-0">{{$t('detail.text3')}}*{{$t('detail.text4')}}:</div>
|
||||
<div>{{detailInfo?.artwork?.length}}*{{detailInfo?.artwork?.width}}cm</div>
|
||||
</div>
|
||||
<div class="flex mb-[4px]">
|
||||
<div class="w-[70px] flex-shrink-0">画作简介:</div>
|
||||
<div class="w-[70px] flex-shrink-0">{{$t('detail.text5')}}:</div>
|
||||
<div>{{detailInfo?.artwork?.abstract??'-'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex px-[16px] bg-#fff h-[36px] items-center mb-6px">
|
||||
<div class="text-[#575757] text-[14px]">起拍价:</div>
|
||||
<div class="text-[#575757] text-[14px]">{{$t('detail.text6')}}:</div>
|
||||
<div class="text-#575757 text-14px font-bold">RMB 1,000</div>
|
||||
</div>
|
||||
<div class="px-[16px] bg-#fff pt-12px pb-18px">
|
||||
<div class="text-[#575757] text-[14px] mb-4px">竞价表:</div>
|
||||
<div class="text-[#575757] text-[14px] mb-4px">{{$t('detail.text7')}}:</div>
|
||||
<div v-if="detailInfo?.priceRuleType!=='diy'">
|
||||
<xImage :src="detailInfo?.priceRuleImage" alt=""/>
|
||||
</div>
|
||||
|
@ -5,7 +5,6 @@ import countryCode from './data/index.js';
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
definePageMeta({
|
||||
title: '国家地区',
|
||||
i18n: 'countryRegion.title',
|
||||
})
|
||||
const router = useRouter()
|
||||
|
@ -52,12 +52,11 @@ const openShow = async (item) => {
|
||||
<div class="px-[16px] pt-[16px]">
|
||||
<van-pull-refresh
|
||||
v-model="localState.refreshing"
|
||||
:success-text="$t('refresh_show')"
|
||||
:success-duration="700"
|
||||
@refresh="onRefresh"
|
||||
>
|
||||
<template #success>
|
||||
<van-icon name="success" /> <span>{{ $t('refresh_show') }}</span>
|
||||
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
|
||||
</template>
|
||||
<van-list
|
||||
v-model:loading="storeLoading"
|
||||
|
@ -5,6 +5,7 @@ import ItemList from './components/ItemList/index.vue'
|
||||
import Cescribe from './components/Cescribe/index.vue'
|
||||
import {message} from '@/components/x-message/useMessage.js'
|
||||
import {liveStore} from "~/stores/live/index.js";
|
||||
|
||||
const {getAuctionDetail, auctionDetail} = goodStore();
|
||||
const {fullLive} = liveStore()
|
||||
const changeLive = () => {
|
||||
@ -18,7 +19,15 @@ if (!auctionDetail.value.uuid){
|
||||
<template>
|
||||
<div class="flex-grow-1">
|
||||
<client-only>
|
||||
<liveRoom @click="changeLive" :class="['changeLive', fullLive ? 'expanded' : 'collapsed']"/>
|
||||
<div class="relative" @click="changeLive">
|
||||
<liveRoom :class="['changeLive', fullLive ? 'expanded' : 'collapsed']"/>
|
||||
<div class="absolute h-188px w-screen pt-36px flex flex-col text-#fff top-0 left-0 items-center">
|
||||
<div class="text-18px mb-5px">{{ auctionDetail.title }}</div>
|
||||
<div class="text-12px mb-54px">{{ $t('home.text1') }}<van-icon name="arrow" /></div>
|
||||
<div><span>-</span> <span class="text-12px mx-5px">{{auctionDetail.totalNum}}{{ auctionDetail.totalNum }}{{ $t('common.items') }}{{ $t('common.auction') }}</span> <span>-</span></div>
|
||||
<div class="text-12px">{{auctionDetail.startDate}} {{$t('home.text2')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</client-only>
|
||||
<div v-if="!fullLive" class="bg-#fff">
|
||||
<van-tabs sticky animated>
|
||||
@ -42,6 +51,7 @@ if (!auctionDetail.value.uuid){
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
:deep(.van-swipe__indicator) {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
|
@ -2,7 +2,6 @@
|
||||
import Home from './home/index.vue'
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
title: '主页',
|
||||
i18n: 'menu.home',
|
||||
})
|
||||
</script>
|
||||
|
@ -77,7 +77,7 @@ watch(()=>props.show,(newValue)=>{
|
||||
<x-popup :show="show" @update:show="close">
|
||||
<template #title>
|
||||
<div class="text-#000 text-16px">{{ $t('home.tab1')}}</div>
|
||||
<div class="text-#939393 text-16px ml-14px">{{ $t('home.total') }}{{ pageRef.itemCount }}{{ $t('home.lots_num') }}</div>
|
||||
<div class="text-#939393 text-16px ml-14px">{{ $t('live_room.total') }}{{ pageRef.itemCount }}{{ $t('live_room.lots_num') }}</div>
|
||||
</template>
|
||||
<div>
|
||||
<van-pull-refresh
|
||||
|
@ -10,8 +10,7 @@ const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { locale } = useI18n()
|
||||
definePageMeta({
|
||||
title: '登录',
|
||||
i18n: 'login.title',
|
||||
i18n: 'login.title'
|
||||
})
|
||||
const loadingRef=ref({
|
||||
loading1:false,
|
||||
|
@ -87,6 +87,9 @@ const onRefresh = async () => {
|
||||
:success-text="$t('home.refresh_show')"
|
||||
:success-duration="700"
|
||||
@refresh="onRefresh">
|
||||
<template #success>
|
||||
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
|
||||
</template>
|
||||
<van-list
|
||||
:finished-text="$t('home.finished_text')"
|
||||
>
|
||||
|
@ -1,24 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import MasonryWall from '@yeger/vue-masonry-wall'
|
||||
const items = [
|
||||
{
|
||||
title: 'First',
|
||||
description: 'The first item.',
|
||||
},
|
||||
{
|
||||
title: 'Second',
|
||||
description: 'The second item.',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<masonry-wall :items="items" :ssr-columns="2" :minColumns="2" :gap="16">
|
||||
<template #default="{ item, index }">
|
||||
<div :style="{ height: `${(index + 1) * 100}px` }">
|
||||
<h1>{{ item.title }}</h1>
|
||||
<span>{{ item.description }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</masonry-wall>
|
||||
</template>
|
@ -6,10 +6,11 @@ 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";
|
||||
|
||||
import {useI18n} from 'vue-i18n'
|
||||
export const liveStore = createGlobalState(() => {
|
||||
const {auctionDetail} = goodStore();
|
||||
const { token } = authStore()
|
||||
const t=useI18n().t
|
||||
const fullLive = ref(false)
|
||||
const quoteStatus = ref(false)
|
||||
const show = ref(false)
|
||||
@ -127,7 +128,7 @@ export const liveStore = createGlobalState(() => {
|
||||
if (data.data?.tip?.tipType === 'falling'){
|
||||
message.warning({
|
||||
title: {
|
||||
text: '即将落槌',
|
||||
text: t('live_room.text1'),
|
||||
color: '#F09F1F',
|
||||
align: 'center',
|
||||
},
|
||||
@ -139,13 +140,13 @@ export const liveStore = createGlobalState(() => {
|
||||
}else if (data.data?.tip?.tipType === 'othersBid'){
|
||||
message.error({
|
||||
title: {
|
||||
text: '已有人出价',
|
||||
text: t('live_room.text2'),
|
||||
color: '#CF3050',
|
||||
align: 'center',
|
||||
},
|
||||
icon:false,
|
||||
subTitle:{
|
||||
text:'更新后再出价',
|
||||
text:t('live_room.text3'),
|
||||
color: '#939393',
|
||||
align: 'center',
|
||||
},
|
||||
@ -157,13 +158,13 @@ export const liveStore = createGlobalState(() => {
|
||||
}else if (data.data?.tip?.tipType === 'successBid'){
|
||||
message.success({
|
||||
title: {
|
||||
text: '恭喜您,竞拍成功',
|
||||
text: t('live_room.text4'),
|
||||
color: '#18A058',
|
||||
align: 'center',
|
||||
},
|
||||
icon:false,
|
||||
subTitle:{
|
||||
text:'请缴款',
|
||||
text:t('live_room.text5'),
|
||||
color: '#939393',
|
||||
align: 'center',
|
||||
},
|
||||
@ -175,14 +176,14 @@ export const liveStore = createGlobalState(() => {
|
||||
}else if (data.data?.tip?.tipType === 'artworkOver'){
|
||||
message.success({
|
||||
title: {
|
||||
text: '本拍品已结束',
|
||||
text: t('live_room.text6'),
|
||||
color: '#575757',
|
||||
align: 'center',
|
||||
|
||||
},
|
||||
icon:false,
|
||||
subTitle:{
|
||||
text:'请期待下个拍品',
|
||||
text:t('live_room.text7'),
|
||||
color: '#939393',
|
||||
align: 'center',
|
||||
},
|
||||
@ -196,13 +197,13 @@ export const liveStore = createGlobalState(() => {
|
||||
}else if (data.data?.tip?.tipType === 'failBid'){
|
||||
message.error({
|
||||
title: {
|
||||
text: '很遗憾,竞拍失败',
|
||||
text: t('live_room.text8'),
|
||||
color: '#CF3050',
|
||||
align: 'center',
|
||||
},
|
||||
icon:false,
|
||||
subTitle:{
|
||||
text:'竞拍结束',
|
||||
text: t('live_room.text9'),
|
||||
color: '#939393',
|
||||
align: 'center',
|
||||
},
|
||||
@ -218,10 +219,9 @@ export const liveStore = createGlobalState(() => {
|
||||
}else if (data.data?.wsType==='over'){
|
||||
message.success({
|
||||
title: {
|
||||
text: '竞拍结束,谢谢参与',
|
||||
text: t('live_room.text10'),
|
||||
color: '#575757',
|
||||
align: 'center',
|
||||
|
||||
},
|
||||
icon:false,
|
||||
style: {
|
||||
|
@ -5,7 +5,7 @@
|
||||
"appKeyWords": "泰丰,泰丰文化,豐和,京都,拍卖会"
|
||||
},
|
||||
"menu": {
|
||||
"home": "主页",
|
||||
"home": "京都拍卖会",
|
||||
"profile": "我的",
|
||||
"darkMode": "🌗 暗黑模式",
|
||||
"language": "📚 语言",
|
||||
@ -28,6 +28,10 @@
|
||||
"hasSendTo": "已发送验证码至",
|
||||
"reSend": "重新发送"
|
||||
},
|
||||
"common": {
|
||||
"items": "件",
|
||||
"auction": "拍品"
|
||||
},
|
||||
"profile": {
|
||||
"name": "姓名",
|
||||
"phone": "手机号"
|
||||
@ -71,6 +75,15 @@
|
||||
"confirm": "确定",
|
||||
"success_mess": "提交成功"
|
||||
},
|
||||
"detail": {
|
||||
"text1": "作者",
|
||||
"text2": "总平尺数",
|
||||
"text3": "长",
|
||||
"text4": "宽",
|
||||
"text5": "画作简介",
|
||||
"text6": "起拍价",
|
||||
"text7": "竞价表",
|
||||
},
|
||||
"art_detail_page": {
|
||||
"button": "去支付",
|
||||
"prompt_title": "恭喜您",
|
||||
@ -85,7 +98,9 @@
|
||||
"start_price": "起拍价",
|
||||
"close_price": "成交价",
|
||||
"my_lots": "我的拍品",
|
||||
"go_home": "去首页"
|
||||
"go_home": "去首页",
|
||||
"text1": "点击进入直播间",
|
||||
"text2": "北京时间"
|
||||
},
|
||||
"live_room": {
|
||||
"error_mess": "直播内容获取失败,是否刷新页面重新获取",
|
||||
@ -111,7 +126,17 @@
|
||||
"total": "共",
|
||||
"lots_num": "个拍品",
|
||||
"cast": "投屏中",
|
||||
"wait_update": "等待更新"
|
||||
"wait_update": "等待更新",
|
||||
"text1": "即将落槌",
|
||||
"text2": "已有人出价",
|
||||
"text3": "更新后再出价",
|
||||
"text4": "恭喜您,竞拍成功",
|
||||
"text5": "请缴款",
|
||||
"text6": "本拍品已结束",
|
||||
"text7": "请期待下个拍品",
|
||||
"text8": "很遗憾,竞拍失败",
|
||||
"text9": "竞拍结束",
|
||||
"text10": "竞拍结束,谢谢参与",
|
||||
},
|
||||
"personal": {
|
||||
"title": "请填写个人相关信息",
|
||||
|
Loading…
Reference in New Issue
Block a user