feat(i18n): 添加新文本并优化多语言支持

- 在 zh-CN.json 中添加了新文本 "text1": "请选择性别"
- 更新了多个组件的国际化支持,包括 realAuth、profile、itemDetail 等
-优化了部分组件的布局和样式
This commit is contained in:
xingyy 2025-02-13 11:53:24 +08:00
parent 226057ce8f
commit d840c2a453
13 changed files with 163 additions and 252 deletions

View File

@ -1,199 +1,119 @@
<script setup>
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
<template>
<div
class="draggable-container"
:style="containerStyle"
@mousedown="startDrag"
@touchstart.prevent="startDrag"
>
<slot />
</div>
</template>
<script setup>
const props = defineProps({
fixedSide: {
type: String,
default: 'none',
validator: (v) => ['left', 'right', 'top', 'bottom', 'none'].includes(v)
},
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
}
width: Number,
height: Number
})
const emit = defineEmits(['update:position'])
const containerRef = ref(null)
const position = ref(props.initialPosition)
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 startPosition = ref({ x: 0, y: 0 })
const transformStyle = computed(() => ({
transform: `translate3d(${position.value.x}px, ${position.value.y}px, 0)`,
zIndex: props.zIndex,
const containerStyle = computed(() => ({
position: 'fixed',
top: '0',
left: '0', //
right: 'auto',
bottom: 'auto'
width: props.width ? `${props.width}px` : 'auto',
height: props.height ? `${props.height}px` : 'auto',
left: `${position.value.x}px`,
top: `${position.value.y}px`,
cursor: isDragging.value ? 'grabbing' : 'grab'
}))
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 getClientPos = (e) => ({
x: e.touches ? e.touches[0].clientX : e.clientX,
y: e.touches ? e.touches[0].clientY : e.clientY
})
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
const startDrag = (e) => {
isDragging.value = true
startPos.value = {
x: e.clientX - position.value.x,
y: e.clientY - position.value.y
const { x, y } = getClientPos(e)
startPosition.value = {
x: x - position.value.x,
y: y - position.value.y
}
}
const handleMove = (event) => {
const onDrag = (e) => {
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
const { x: clientX, y: clientY } = getClientPos(e)
const maxX = window.innerWidth - (props.width || 0)
const maxY = window.innerHeight - (props.height || 0)
let newX = clientX - startPosition.value.x
let newY = clientY - startPosition.value.y
//
switch (props.fixedSide) {
case 'left':
newX = 0
newY = Math.max(0, Math.min(newY, maxY))
break
case 'right':
newX = maxX
newY = Math.max(0, Math.min(newY, maxY))
break
case 'top':
newX = Math.max(0, Math.min(newX, maxX))
newY = 0
break
case 'bottom':
newX = Math.max(0, Math.min(newX, maxX))
newY = maxY
break
default:
newX = Math.max(0, Math.min(newX, maxX))
newY = Math.max(0, Math.min(newY, maxY))
}
if (props.dragMode === 'horizontal') {
newPos.y = position.value.y
} else if (props.dragMode === 'vertical') {
newPos.x = position.value.x
position.value = {
x: ['top', 'bottom', 'none'].includes(props.fixedSide) ? newX : position.value.x,
y: ['left', 'right', 'none'].includes(props.fixedSide) ? newY : position.value.y
}
newPos = handleStick(newPos)
newPos = constrainPosition(newPos)
position.value = newPos
emit('update:position', newPos)
event.preventDefault()
}
const handleEnd = () => {
const stopDrag = () => {
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)
document.addEventListener('mousemove', onDrag)
document.addEventListener('mouseup', stopDrag)
document.addEventListener('touchmove', onDrag)
document.addEventListener('touchend', stopDrag)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', updateSizes)
document.removeEventListener('mousemove', handleMove)
document.removeEventListener('mouseup', handleEnd)
document.removeEventListener('touchmove', handleMove)
document.removeEventListener('touchend', handleEnd)
onUnmounted(() => {
document.removeEventListener('mousemove', onDrag)
document.removeEventListener('mouseup', stopDrag)
document.removeEventListener('touchmove', onDrag)
document.removeEventListener('touchend', stopDrag)
})
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;
.draggable-container {
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;
z-index: 9999;
}
</style>

View File

@ -39,7 +39,7 @@ const props = defineProps({
</div>
<div class="flex px-[16px] bg-#fff h-[36px] items-center mb-6px">
<div class="text-[#575757] text-[14px]">{{$t('detail.text6')}}</div>
<div class="text-#575757 text-14px font-bold">RMB 1,000</div>
<div class="text-#575757 text-14px font-bold">{{detailInfo?.startPriceCurrency}} {{detailInfo?.startPrice}}</div>
</div>
<div class="px-[16px] bg-#fff pt-12px pb-18px">
<div class="text-[#575757] text-[14px] mb-4px">{{$t('detail.text7')}}</div>

View File

@ -1,11 +1,10 @@
<script setup>
import { ref, computed } from 'vue'
import {ref, computed} from 'vue'
import dayjs from 'dayjs'
const props = defineProps({
modelValue: {
type: [Date, String, Number],
default: () => new Date() //
type: [Date, String, Number]
},
label: {
type: String,
@ -25,11 +24,11 @@ const props = defineProps({
},
minDate: {
type: Date,
default: () => new Date(1900, 0, 1)
default: () => dayjs('1900-01-01').toDate()
},
maxDate: {
type: Date,
default: () => new Date(2100, 11, 31)
default: () => dayjs('2100-12-31').toDate()
},
format: {
type: String,
@ -40,48 +39,58 @@ const props = defineProps({
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()
let date
if (props.modelValue) {
date = dayjs(props.modelValue)
} else {
date = dayjs()
}
//
if (!date.isValid()) {
date = dayjs()
}
return [
date.getFullYear(),
date.getMonth() + 1,
date.getDate()
date.year(),
date.month() + 1,
date.date()
]
})
//
const formatDate = (dateArr) => {
const [year, month, day] = dateArr
return dayjs(`${year}-${month}-${day}`).format(props.format)
}
//
const displayValue = computed(() => {
if (!props.modelValue) return ''
const date = dayjs(props.modelValue)
return date.isValid() ? date.format(props.format) : ''
})
//
const onConfirm = ({ selectedValues }) => {
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 formattedDate = formatDate(selectedValues)
emit('update:modelValue', formattedDate)
emit('change', formattedDate)
}
//
const onCancel = () => {
show.value = false
}
//
const reset = () => {
emit('update:modelValue', new Date())
}
defineExpose({
reset
})
</script>
<template>
<div>
<van-field
:model-value="displayText"
:model-value="displayValue"
@click="show = true"
readonly
:disabled="disabled"
@ -95,6 +104,9 @@ defineExpose({
<van-popup
v-model:show="show"
position="bottom"
teleport="#__nuxt"
destroy-on-close
safe-area-inset-bottom
>
<van-date-picker
:min-date="minDate"

View File

@ -1,7 +1,7 @@
<script setup>
import { ref } from 'vue'
const props = defineProps({
value: {
modelValue: {
type: [Number, String]
},
columns: {
@ -30,28 +30,20 @@ const props = defineProps({
}
})
const emit = defineEmits(['update:value', 'change'])
const emit = defineEmits(['update:modelValue', 'change'])
const show = ref(false)
const onConfirm = (value) => {
show.value = false
emit('update:value', value.value)
emit('change', value)
emit('update:modelValue', value.selectedValues?.[0])
emit('change', value.selectedValues?.[0])
}
const displayText = computed(() => {
const selected = props.columns.find(x => x.value === props.value)
const selected = props.columns.find(x => x.value === props.modelValue)
return selected?.text || ''
})
const reset = () => {
emit('update:value', undefined)
}
defineExpose({
reset
})
</script>
<template>
@ -72,6 +64,7 @@ defineExpose({
v-model:show="show"
destroy-on-close
position="bottom"
teleport="#__nuxt"
safe-area-inset-bottom
>
<van-picker

View File

@ -44,7 +44,7 @@ const onRefresh = async () => {
const openShow = async (item) => {
localState.value.showDetail = true
currentItem.value = item
getArtworkDetail(item.uuid)
/* getArtworkDetail(item.uuid)*/
}
</script>
@ -103,7 +103,7 @@ const openShow = async (item) => {
</div>
</van-list>
</van-pull-refresh>
<DetailPopup v-model:show="localState.showDetail" :detailInfo="artWorkDetail"></DetailPopup>
<DetailPopup v-model:show="localState.showDetail" :detailInfo="currentItem"></DetailPopup>
</div>
</template>

View File

@ -119,8 +119,8 @@ watch(()=>props.show,(newValue)=>{
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
{{ item.artworkTitle }}
</div>
<div class="text-14px text-#575757">{{ $t('home.start_price') }}RMB 1,000</div>
<div class="text-14px text-#B58047">{{ $t('home.close_price') }}{{ $t('live_room.wait_update') }}</div>
<div class="text-14px text-#575757">{{ $t('home.start_price') }}{{item?.startPriceCurrency}} {{item?.startPrice}}</div>
<div class="text-14px text-#B58047" v-if="item.soldPrice">{{ $t('home.close_price') }}{{item.soldPrice}}</div>
</div>
</div>
</van-list>

View File

@ -120,7 +120,7 @@ const goLogin =async () => {
userInfo.value=res.data.accountInfo
token.value=res.data.token
if (!res.data.isReal){
if (res.data?.accountInfo?.userExtend?.isReal===0){
await router.push('/realAuth');
}else {
await router.push('/');

View File

@ -32,7 +32,8 @@ const initData=async ()=>{
const res=await userArtworks({})
if (res.status===0){
myList.value=res.data.data
showMyList.value=groupAndSortByDate(myList.value)
// showMyList.value=groupAndSortByDate(myList.value)
showMyList.value=[]
}
}
const router = useRouter()
@ -79,21 +80,28 @@ const onRefresh = async () => {
<div class="text-#575757 text-14px">{{userInfo.telNum}}</div>
</div>
</div>
<div class="flex-grow-1 ">
<div class="grow-1 flex flex-col">
<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">{{$t('home.my_lots')}}</div>
</div>
<van-pull-refresh v-model="localState.refreshing"
:success-text="$t('home.refresh_show')"
:success-duration="700"
class="h-full grow-1"
@refresh="onRefresh">
<template #success>
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
</template>
<van-list
:finished-text="$t('home.finished_text')"
class="h-full"
>
<div class="px-16px pt-14px" v-for="(item,index) of showMyList" >
<div class="flex flex-col items-center pt-100px" v-if="showMyList?.length<1">
<img class="w-103px h-88px mb-19px" src="@/static/images/zu5512@2x.png" alt="">
<div class="text-14px text-#575757">您暂无拍品</div>
<div class="text-14px text-#575757">快去竞拍吧</div>
</div>
<div class="px-16px pt-14px" v-for="(item,index) of showMyList" v-else >
<div class="text-#575757 text-14px mb-3px">{{item.userCreatedAt}}</div>
<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">

View File

@ -44,17 +44,17 @@ const {userInfo}= authStore()
<div class="mr-10px">{{$t('realAuth.birthday')}}</div>
<div>{{userInfo.birthDate}}</div>
</div>
<div class="flex">
<div class="flex mb-20px">
<div class="mr-10px">{{$t('realAuth.adress')}}</div>
<div>{{userInfo.idNum}}</div>
<div>{{userInfo.userExtend.address}}</div>
</div>
<div class="flex">
<div class="flex mb-20px">
<div class="mr-10px">{{$t('realAuth.bank')}}</div>
<div>{{userInfo.idNum}}</div>
<div>{{userInfo.userExtend.bankName}}</div>
</div>
<div class="flex">
<div class="flex mb-20px">
<div class="mr-10px">{{$t('realAuth.bankCard')}}</div>
<div>{{userInfo.idNum}}</div>
<div>{{userInfo.userExtend.bankNo}}</div>
</div>
</template>
</div>

View File

@ -5,18 +5,14 @@ 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 XVanDate from '@/components/x-van-date/index.vue'
import XVanSelect from '@/components/x-van-select/index.vue'
const router = useRouter();
const route = useRoute();
const showPicker = ref(false);
const { locale } = useI18n()
const {userInfo}= authStore()
const birthdayDate = ref([])
const showBirthdayPicker = ref(false)
const minDate = new Date(1950, 0, 1)
const maxDate = new Date(2025, 12, 31)
const active=ref(0)
const active=ref(locale.value==='zh-CN'?0:1)
const { t } = useI18n()
const form=ref({
idNum: "",
realName: "",
sex:'',
birthDate:'',
@ -34,15 +30,6 @@ const columns=ref([
{ text: t('realAuth.male'), value: 1 },
{ text: t('realAuth.female'), value: 2 },
])
const onConfirm = ({ selectedValues, selectedOptions }) => {
form.value.sex=selectedValues?.[0]
showPicker.value = false
}
const onBirthdayConfirm = (value) => {
form.value.birthDate=value.selectedValues.join('-')
showBirthdayPicker.value = false
}
function isFormComplete(obj) {
for (const key in obj) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
@ -58,6 +45,7 @@ function isFormComplete(obj) {
const statusCode=ref(0)
const confirm=async ()=>{
const thatForm=active.value===0?form1.value:form.value
thatForm.userExtend.isMainland=active.value===0?1:0
if (isFormComplete(thatForm)){
const res=await userUpdate(thatForm)
if (res.status===0){
@ -74,7 +62,6 @@ const goHome=()=>{
router.push('/')
}
definePageMeta({
title: '实名认证',
i18n: 'realAuth.title',
})
</script>
@ -100,16 +87,13 @@ definePageMeta({
<div class="text-[#BDBDBD] text-[16px] mb-[34px]">{{ $t('realAuth.otherTabDesc') }}</div>
<div class="mb-[100px]">
<div class="border-b-[1.7px] mt-[8px]">
<van-field :label="$t('realAuth.name')" clearable :placeholder="$t('realAuth.namePlaceholder')"></van-field>
<van-field v-model="form.realName" :label="$t('realAuth.name')" clearable :placeholder="$t('realAuth.namePlaceholder')"></van-field>
</div>
<div class="border-b-[1.7px] mt-[8px]">
<van-field :modelValue="columns.find(x=>x.value===form.sex)?.text" is-link readonly name="picker" :label="$t('realAuth.gender')"
@click="showPicker = true" />
<x-van-select v-model="form.sex" :placeholder="$t('realAuth.text1')" :label="$t('realAuth.gender')" :columns="columns"/>
</div>
<div class="border-b-[1.7px] mt-[8px]">
<van-field v-model="form.birthDate" is-link readonly name="birthdayPicker" :label="$t('realAuth.birthday')"
:placeholder="$t('realAuth.birthdayPlaceholder')" @click="showBirthdayPicker = true" />
<x-van-date v-model="form.birthDate" :label="$t('realAuth.birthday')" :placeholder="$t('realAuth.birthdayPlaceholder')"/>
</div>
<div class="border-b-[1.7px] mt-[8px]">
<van-field v-model="form.userExtend.address" :label="$t('realAuth.adress')" clearable
@ -144,13 +128,6 @@ definePageMeta({
<div v-else class="mt-auto pb-94px">
<van-button color="#E9F1F8" @click="goHome" style="color: #2B53AC;font-weight: 600" block>{{ $t('home.go_home')}}</van-button>
</div>
<van-popup v-model:show="showPicker" destroy-on-close position="bottom">
<van-picker :columns="columns" @confirm="onConfirm" @cancel="showPicker = false" />
</van-popup>
<van-popup v-model:show="showBirthdayPicker" destroy-on-close position="bottom">
<van-date-picker v-model="birthdayDate" :min-date="minDate" :max-date="maxDate"
@cancel="showBirthdayPicker = false" @confirm="onBirthdayConfirm" />
</van-popup>
</div>
</template>

View File

@ -28,10 +28,10 @@ const adress=ref('')
<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">
{{$t(personal.title)}}
{{$t('personal.title')}}
</div>
<div class="grow-1 px-34px">
<van-field type="tel" :label-width="161" :label="$t(personal.text)" class="mb-10px" :placeholder="$t('login.phonePlaceholder')">
<van-field type="tel" :label-width="161" :label="$t('personal.text')" class="mb-10px" :placeholder="$t('login.phonePlaceholder')">
<template #label>
<div class="flex">
<div class="mr-41px whitespace-nowrap">{{$t('profile.phone')}}</div>
@ -50,7 +50,7 @@ const adress=ref('')
<van-field :label="$t('realAuth.bankCard')" class="mb-10px" :placeholder="$t('realAuth.bankCardPlaceholder')"/>
</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">{{$t(personal.next)}}</van-button>
<van-button color="#2B53AC" class="w-213px van-btn-h-38px">{{$t('personal.next')}}</van-button>
</div>
</div>
</template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -73,7 +73,8 @@
"bankCardPlaceholder": "请输入银行卡号码",
"cancel": "取消",
"confirm": "确定",
"success_mess": "提交成功"
"success_mess": "提交成功",
"text1": "请选择性别"
},
"detail": {
"text1": "作者",