Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/Aida_Purchaser_Front

This commit is contained in:
2026-05-27 11:30:56 +08:00
22 changed files with 363 additions and 130 deletions

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -1,6 +1,8 @@
export default {
Login: {
signup: 'Sign up',
login: 'Log in',
logoff: 'Log off',
register: 'Register',
loginTip: 'Platform integrated with AiDA.<br />AiDA account login required.',
name: 'Name',
@@ -11,6 +13,7 @@ export default {
enterEmail: 'Enter your email',
enterPassword: 'Enter your password',
enterPasswordAgain: 'Enter your password again',
passwordTip: 'You must satisfy ALL password conditions to register.',
forgotPassword: 'Forget password?',
pleaseInputName: 'Please input the name',
nameLengthError: 'Name length must be between {min} and {max} characters',
@@ -37,7 +40,24 @@ export default {
wechatLogin: 'Sign in with Wechat',
indexTip: 'A multi-agent canvas for rapid, trend driven design iteration.',
sendCodeError: 'Send code error',
retrievePassword: 'Retrieve password'
retrievePassword: 'Retrieve password',
emailVerification: 'Email Verification',
retrievePasswordTitle: 'Please enter your email address below to verify your identity.',
submit: 'Submit',
enterNewPassword: 'Enter a new password for<br/><span>{email}</span>',
passwordsDoNotMatch: 'Passwords do not match',
logOffTip: 'Are you sure to log off?',
},
RegisterSuccess: {
title1: 'Welcome to Stylish Parade!',
title2: 'Please switch to the Login tab to log in.',
title3: 'What awaits you in Stylish Parade',
item1title: 'Behind the design',
item1tip: 'Discover how designers bring ideas to life with AiDA — from first sketch to final look.',
item2title: 'Creative digital works',
item2tip: 'Unlock a growing library of inspiring digital works to refresh your creative mind.',
item3title: 'A fashion community',
item3tip: 'Join a space where fashion speaks — exchange ideas and connect with creators worldwide.',
},
Settings: {
title: 'Settings',
@@ -235,6 +255,8 @@ export default {
digitalItem:{
BestSelling: 'Best Selling',
Price: 'Price: Low to High',
SelectedFirst: 'Selected First',
DateAdded: 'Date Added',
NewestFirst: 'Newest First',
title: 'Digital Item',
info: 'Virtual fashion creations collected in your personal archive',
@@ -250,5 +272,52 @@ export default {
},
checked: {
All: 'All',
},
MainHeader: {
Home: 'Home',
CollectionStory: 'Collection Story',
Brand: 'Brand',
DigitalItem: 'Digital Item',
HiName: 'Hi, {name}',
MyWardrobe: 'My Wardrobe',
Notifications: 'Notifications',
Settings: 'Settings',
},
ShoppingCart: {
title: 'Shopping Cart',
listNullTitle: 'Your Cart is empty',
listNullTip: 'Discover new fashion assets and add them to your cart.',
dateTimeFormat: 'SM D, YYYY, h:mm A',
noLongerAvailable: 'No Longer Available',
delistedFromMarketplace: 'Delisted from marketplace',
remove: 'Remove',
removeTip: 'Are you sure to remove this item?',
total: 'Total',
digitalAssets: 'Digital assets. Creator retains copyright.',
checkout: 'Checkout',
exploreDigitalItems: 'Explore Digital Items',
orderSummary: 'Order Summary',
selected: 'Selected',
brands: 'Brands',
item: 'item',
checkoutSelected: 'Checkout Selected',
},
digitalDetail:{
Sketch: 'Sketch',
Illustration: 'Illustration',
Product: 'Product',
EditorialVisual: 'Editorial Visual',
Back: 'Back',
ReleaseIn: 'Release in',
CopyrightLicenseNotice: 'Copyright & License Notice',
LicenseIncludedInAsset: 'License Included in Asset',
LicenseIncludedInAssetInfo: 'All products on this platform are digital assets, not physical goods. Purchase grants a usage license only; copyright and intellectual property rights remain with the original creator, unless otherwise stated.',
BuyNow: 'Buy Now',
AddToCart: 'Add to Cart',
},
addShoppingCart:{
title: 'Added to your Shopping Cart',
statement: 'Digital Assets Only. No physical product included.',
button: 'Set Shopping Cart',
}
}

View File

@@ -1,6 +1,8 @@
export default {
Login: {
signup: '注册',
login: '登录',
logoff: '退出登录',
register: '注册',
loginTip: '与 AiDA 集成的平台。<br />需要登录 AiDA 账户。',
name: '姓名',
@@ -11,6 +13,7 @@ export default {
enterEmail: '请输入邮箱',
enterPassword: '请输入密码',
enterPasswordAgain: '请输入密码确认',
passwordTip: '你必须满足所有密码条件才能注册。',
forgotPassword: '忘记密码?',
pleaseInputName: '请输入姓名',
nameLengthError: '姓名长度必须在 {min} 到 {max} 个字符之间',
@@ -37,7 +40,24 @@ export default {
wechatLogin: '使用微信登录',
indexTip: '一个多智能体画布,用于快速、趋势驱动的设计迭代。',
sendCodeError: '发送验证码失败',
retrievePassword: '找回密码'
retrievePassword: '找回密码',
emailVerification: '邮箱验证',
retrievePasswordTitle: '请输入您的邮箱地址以验证您的身份。',
submit: '提交',
enterNewPassword: '请输入新密码<br/><span>{email}</span>',
passwordsDoNotMatch: '两次输入密码不一致',
logOffTip: '确定退出登录吗?',
},
RegisterSuccess: {
title1: '欢迎来到 Stylish Parade',
title2: '请切换到登录选项卡以登录。',
title3: '在 Stylish Parade 中等待你的发现',
item1title: '设计灵感',
item1tip: '了解设计师是如何借助 AiDA 将创意变为现实的——从最初的草图到最终的成品。',
item2title: '创意数字作品',
item2tip: '解锁一个增长的数字作品库,刷新你的创意。',
item3title: '时尚社区',
item3tip: '加入一个全球的时尚社区,与设计师分享创意。',
},
Settings: {
title: '设置',
@@ -235,6 +255,8 @@ export default {
digitalItem: {
BestSelling: "畅销优先",
Price: "价格:从低到高",
SelectedFirst: "已选优先",
DateAdded: "添加日期",
NewestFirst: "最新优先",
title: "数字藏品",
info: "收藏于个人档案中的虚拟时装作品",
@@ -250,5 +272,52 @@ export default {
},
checked: {
All: "全部"
},
MainHeader: {
Home: '首页',
CollectionStory: '系列故事',
Brand: '品牌',
DigitalItem: '数字藏品',
HiName: '你好,{name}',
MyWardrobe: '我的衣橱',
Notifications: '通知',
Settings: '设置',
},
ShoppingCart: {
title: '购物车',
listNullTitle: '你的购物车为空',
listNullTip: '发现新的时尚资产并将其添加到你的购物车。',
dateTimeFormat: 'YYYY-MM-DD HH:mm',
noLongerAvailable: '已下架',
delistedFromMarketplace: '已从市场移除',
remove: '删除',
removeTip: '确认删除吗?',
total: '总金额',
digitalAssets: '数字资产。创作者保留版权。',
checkout: '结账',
exploreDigitalItems: '探索数字单品',
orderSummary: '订单信息',
selected: '已选',
brands: '品牌',
item: '数字藏品',
checkoutSelected: '结账已选',
},
digitalDetail:{
Sketch: "草图",
Illustration: "插画",
Product: "产品",
EditorialVisual: "编辑视觉",
Back: "返回",
ReleaseIn: "发布于",
CopyrightLicenseNotice: "版权与许可声明",
LicenseIncludedInAsset: "资产包含许可",
LicenseIncludedInAssetInfo: "本平台所有产品均为数字资产,非实物商品。购买仅授予使用许可;版权及知识产权仍归原作者所有,除非另有说明。",
BuyNow: "立即购买",
AddToCart: "加入购物车"
},
addShoppingCart:{
title: "已添加到您的购物车",
statement: "仅限数字资产。不包含实体产品。",
button: "去购物车"
}
}

View File

@@ -210,4 +210,8 @@ export function FormatBytes(bytes, options: { decimals?: number, unitBig?: boole
const i = Math.floor(Math.log(bytes) / Math.log(k));
const value = bytes / Math.pow(k, i);
return `${Number(value.toFixed(decimals))} ${sizes[i]}`;
}
export const openAida = () => {
window.open('https://www.aida.com.hk/', '_blank')
}

View File

@@ -28,14 +28,19 @@ const searchHistory = ref([
])
let changeSearchBrandTime = null
const changeSearchBrand = () => {
merchantList.value = []
if(!searchBrand.value)return
clearTimeout(changeSearchBrandTime)
getDesignerList({
keyword: searchBrand.value,
}).then((res)=>{
merchantList.value.push(...res)
})
changeSearchBrandTime = setTimeout(()=>{
merchantList.value = []
getDesignerList({
keyword: searchBrand.value,
}).then((res)=>{
merchantList.value.push(...res)
})
},500)
// changeSearchBrandTime = setTimeout(()=>{
// getMerchantData.pageNum = 1
// getMerchantData.isShowMark = false
@@ -129,7 +134,7 @@ const {} = toRefs(data);
<div class="content">
<div class="input">
<input type="text" v-model="searchBrand" @input="changeSearchBrand" :placeholder="$t('brand.search')">
<div class="icon">
<div class="icon" @click="changeSearchBrand">
<SvgIcon name="brand-search" size="32" />
</div>
</div>

View File

@@ -97,8 +97,8 @@ defineExpose({})
display: flex;
flex-direction: column;
.header{
position: sticky;
top: 0;
// position: sticky;
// top: 0;
z-index: 2;
background-color: #fff;
.title{

View File

@@ -6,6 +6,9 @@ import myEvent from '@/utils/myEvent'
import { getListingDetailApi } from '@/api/listing'
import { useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import { useI18n } from 'vue-i18n'
import { AddShoppingCart } from '@/api/shoppingCart'
import { CreateOrder } from '@/api/shoppingCart'
//const props = defineProps({
@@ -13,6 +16,7 @@ import { ElMessage } from 'element-plus'
//const emit = defineEmits([
//])
const route = useRoute()
const { t } = useI18n()
const router = useRouter()
let detail:any = ref({
@@ -22,30 +26,40 @@ let detail:any = ref({
shopName: '',
updateTime: '',
gender: '',
sellerId: '',
})
const sketchList = ref([])
const illustrationList = ref([])
const productList = ref([])
const editorialVisualList = ref([])
const addShopping = () => {
console.log(detail.value)
if(!detail.value.price) return ElMessage.warning('Please log in first.')
if(!detail.value.price) return ElMessage.warning(t('brandDetail.addShoppingTip'))
let data = {
cover: detail.value.images.cover[0],
price: detail.value.price,
shopName: detail.value.shopName,
title: detail.value.title,
id: detail.value.id,
}
myEvent.emit('addShopping', data)
AddShoppingCart({listingIds:[detail.value.id]}).then((res)=>{
myEvent.emit('addShopping', data)
})
}
const goShopping = () => {
if(!detail.value.price) return ElMessage.warning('Please log in first.')
router.push({path: '/shoppingCart'})
if(!detail.value.price) return ElMessage.warning(t('brandDetail.addShoppingTip'))
CreateOrder(
[detail.value.id],true
).then((res)=>{
// if(res)router.push({path: '/shoppingCart')
})
// router.push({path: '/shoppingCart'})
}
const setImgList = (list)=>{
sketchList.value = list.apparel.map((item:any) => {return {imgUrl:item}})
illustrationList.value = list.sketch.map((item:any) => {return {imgUrl:item}})
productList.value = list.main_product.map((item:any) => {return {imgUrl:item}})
sketchList.value = list?.apparel?.map((item:any) => {return {imgUrl:item}})
illustrationList.value = list?.sketch?.map((item:any) => {return {imgUrl:item}})
productList.value = list?.main_product?.map((item:any) => {return {imgUrl:item}})
editorialVisualList.value = list.product.map((item:any) => {return {imgUrl:item}})
if(list.firstFrame){
@@ -62,11 +76,14 @@ const getListingDetail = ()=>{
getListingDetailApi({
id:route.params.id + '',
}).then((res)=>{
console.log(res)
if(res)detail.value = res
setImgList(res.images)
})
}
const gobrand = () => {
if(!detail.value.sellerId)return
router.push({path: `/brand/${detail.value.sellerId}`})
}
// const vObserve = {
// mounted (el,binding) {
// },
@@ -85,7 +102,7 @@ defineExpose({})
<div class="center">
<div class="img-list">
<div class="left">
<div class="title">Sketch</div>
<div class="title">{{ $t('digitalDetail.Sketch') }}</div>
<div class="box sketch">
<div class="imgBox">
<img :src="item?.imgUrl" v-for="item in sketchList" :key="item" alt="">
@@ -95,13 +112,13 @@ defineExpose({})
<div class="right">
<div class="top">
<div class="box">
<div class="title">Illustration</div>
<div class="title">{{ $t('digitalDetail.Illustration') }}</div>
<div class="imgBox">
<img :src="item?.imgUrl" v-for="item in illustrationList" :key="item" alt="">
</div>
</div>
<div class="box">
<div class="title">Product</div>
<div class="title">{{ $t('digitalDetail.Product') }}</div>
<div class="imgBox">
<img :src="item?.imgUrl" v-for="item in productList" :key="item" alt="">
</div>
@@ -109,7 +126,7 @@ defineExpose({})
</div>
<div class="bottom">
<div class="box aa">
<div class="title">Editorial Visual</div>
<div class="title">{{ $t('digitalDetail.EditorialVisual') }}</div>
<div class="imgBox">
<img :src="item?.gif||item?.imgUrl" v-for="item in editorialVisualList" :key="item" alt="">
</div>
@@ -122,7 +139,7 @@ defineExpose({})
<div class="icon">
<svg-icon name="digital-back" size="28"></svg-icon>
</div>
<span>Back</span>
<span>{{ $t('digitalDetail.Back') }}</span>
</div>
<div class="img-info">
<div class="img-type">{{ detail.designFor?.toUpperCase() || ''}} / {{ detail.productCategory?.join(',')?.toUpperCase() || '' }}</div>
@@ -133,9 +150,9 @@ defineExpose({})
<div class="info">
<img class="profile" v-avatarLoad="detail.avatar" alt="">
<div class="detail">
<div class="name">{{ detail.shopName }}</div>
<div class="name" @click="gobrand">{{ detail.shopName }}</div>
<div class="release-time">
<span>Release in {{ detail.updateTime }}</span>
<span>{{ $t('digitalDetail.ReleaseIn') }} {{ detail.updateTime }}</span>
</div>
</div>
</div>
@@ -144,26 +161,26 @@ defineExpose({})
</div>
</div>
<div class="notice">
<div class="title">Copyright & License Notice</div>
<div class="title">{{ $t('digitalDetail.CopyrightLicenseNotice') }}</div>
<div class="conter">
<div class="contet-title">
<div class="icon">
<svg-icon name="digital-Info" size="24"></svg-icon>
</div>
<span>License Included in Asset</span>
<span>{{ $t('digitalDetail.LicenseIncludedInAsset') }}</span>
</div>
<div class="info">
All products on this platform are digital assets, not physical goods. Purchase grants a usage license only; copyright and intellectual property rights remain with the original creator, unless otherwise stated.
{{ $t('digitalDetail.LicenseIncludedInAssetInfo') }}
</div>
</div>
</div>
<div class="button">
<div class="buy-now" @click="goShopping">Buy Now</div>
<div class="buy-now" @click="goShopping">{{ $t('digitalDetail.BuyNow') }}</div>
<div class="add-cart" @click="addShopping()">
<div class="icon">
<svg-icon name="cart_0" size="24"></svg-icon>
</div>
Add to Cart
{{ $t('digitalDetail.AddToCart') }}
</div>
</div>
</div>
@@ -320,6 +337,7 @@ defineExpose({})
font-size: 1.8rem;
line-height: 100%;
margin-bottom: .8rem;
cursor: pointer;
}
.release-time{
font-family: KaiseiOpti-Regular;

View File

@@ -5,6 +5,10 @@ import MerchantInfo from "./merchant-info.vue";
import { useRouter } from "vue-router";
import scListNull from '@/views/shoppingCart/sc-list-null.vue'
import { useI18n } from 'vue-i18n'
import { AddShoppingCart } from '@/api/shoppingCart'
import { ElMessage } from 'element-plus'
import myEvent from '@/utils/myEvent'
// 定义组件名称
defineOptions({
@@ -36,7 +40,13 @@ const searechTypeList = ref([
])
const searechType = ref('updateTime')
const addShopping = (item) => {}
const addShopping = (item) => {
console.log(item)
if(!item.price) return ElMessage.warning(t('brandDetail.addShoppingTip'))
AddShoppingCart({listingIds:[item.id]}).then((res)=>{
myEvent.emit('addShopping', item)
})
}
const openDetail = (item) => {
scrollTop.value = digitalItemRef.value.scrollTop
router.push({

View File

@@ -2,7 +2,7 @@
<div class="home-index">
<section-index />
<section-designer />
<section-design />
<section-aida />
<section-digital-items1 />
<section-digital-items2 />
<section-footer />
@@ -13,7 +13,7 @@
import { computed } from 'vue'
import SectionIndex from './section-index.vue'
import SectionDesigner from './section-designer.vue'
import SectionDesign from './section-design.vue'
import SectionAida from './section-aida.vue'
import SectionDigitalItems1 from './section-digital-items1.vue'
import SectionDigitalItems2 from './section-digital-items2.vue'
import SectionFooter from './section-footer.vue'

View File

@@ -1,24 +1,25 @@
<template>
<section class="section-design bgw">
<img src="@/assets/images/home/design-bg.jpg" class="bg" />
<section class="section-aida bgw">
<img src="@/assets/images/home/aida-bg.jpg" class="bg" />
<div class="content">
<div class="aida-logo"><img src="@/assets/images/logos/aida.png" /></div>
<div class="title">Design with AiDA</div>
<div class="tip">
Each garment on this platform is where designer vision blooms through AiDA. A tool that
nurtures your creativity, never overshadows it. Let your ideas flourish.
Each garment on this platform is where designer vision blooms through AiDA. A tool
that nurtures your creativity, never overshadows it. Let your ideas flourish.
</div>
<button custom>Try Now</button>
<button custom @click="openAida">Try Now</button>
</div>
</section>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { openAida } from '@/utils/tools'
</script>
<style lang="less">
.section-design {
.section-aida {
> .content {
width: 55rem;
top: 12rem;

View File

@@ -8,7 +8,7 @@
<br />
digital visionsa virtual realm where creativity collides and evolves.
</div>
<button custom="black">Shop All</button>
<button custom="black" @click="onShopAll">Shop All</button>
<div class="list">
<div v-for="v in list" :key="v.url">
<img :src="v.url" alt="" />
@@ -22,6 +22,9 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const list = ref([
{
title: 'Womens Itemk',
@@ -44,6 +47,9 @@
url: 'http://118.31.39.42:3000/falls/digital-items-4.png'
}
])
const onShopAll = () => {
router.push({ name: 'digitalItem' })
}
</script>
<style lang="less">

View File

@@ -8,11 +8,11 @@
<img src="@/assets/images/logos/aida-black.png" />
</div>
<div class="tip">
Stylish Parade is a commerce platform for designers, serving as AiDA's commercial
extension.
Stylish Parade is a commerce platform for designers, serving as AiDA's
commercial extension.
</div>
<div class="link">
<span class="text">Bloom your Creativity with AiDA!</span>
<span class="text" @click="openAida">Bloom your Creativity with AiDA!</span>
<span class="icon"><svg-icon name="arrow_right" size="12" /></span>
</div>
</div>
@@ -54,6 +54,9 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { openAida } from '@/utils/tools'
import { useRouter } from 'vue-router'
const router = useRouter()
</script>
<style lang="less">

View File

@@ -14,26 +14,28 @@
<div class="close" @click="show = false"><svg-icon name="close" /></div>
<div class="content" v-if="curentTabInfo">
<div class="header">
<div class="title" v-show="curentTabInfo.title">
<div class="title" v-if="curentTabInfo.title">
<div class="icon" @click="onBack"><svg-icon name="back" size="17" /></div>
<div class="label">{{ curentTabInfo.title }}</div>
<div class="label">{{ $t(curentTabInfo.title) }}</div>
</div>
<div class="nav" v-show="!curentTabInfo.title">
<div
class="item"
:class="{
active: [TabNames.register, TabNames.register_success].includes(currentTab)
active: [TabNames.register, TabNames.register_success].includes(
currentTab
)
}"
@click="currentTab = TabNames.register"
>
SIGN UP
{{ $t('Login.signup') }}
</div>
<div
class="item"
:class="{ active: currentTab === TabNames.login }"
@click="currentTab = TabNames.login"
>
LOG IN
{{ $t('Login.login') }}
</div>
</div>
</div>
@@ -70,6 +72,8 @@
import retrievePassword from './retrieve-password.vue'
import myEvent from '@/utils/myEvent'
import { useUserInfoStore } from '@/stores/userInfo'
import { useRouter } from 'vue-router'
const router = useRouter()
const userStore = useUserInfoStore()
const data = ref({
name: '',
@@ -95,12 +99,12 @@
},
{
name: TabNames.email_verify,
title: 'EMAIL VERIFICATION',
title: 'Login.emailVerification',
component: emailVerify
},
{
name: TabNames.retrieve_password,
title: 'RETRIEVE PASSWORD',
title: 'Login.retrievePassword',
component: retrievePassword
},
{
@@ -157,6 +161,9 @@
AccountLogin(value).then((v) => {
userStore.setUserInfo(v)
show.value = false
setTimeout(() => {
router.go(0)
})
})
} else {
value['username'] = data.value.name
@@ -244,6 +251,7 @@
font-size: 2rem;
font-family: KaiseiOpti-Regular;
color: #9f9f9f;
text-transform: uppercase;
&.active {
font-family: KaiseiOpti-Bold;
color: #232323;
@@ -273,6 +281,7 @@
font-family: KaiseiOpti-Bold;
font-size: 2rem;
color: #232323;
text-transform: uppercase;
}
}
}

View File

@@ -1,31 +1,25 @@
<template>
<div class="register-success">
<div class="icon"><svg-icon name="dui" size="20" /></div>
<div class="title">Welcome to Stylish Parade!</div>
<div class="title">Please switch to the Login tab to log in.</div>
<div class="title">{{ t('RegisterSuccess.title1') }}</div>
<div class="title">{{ t('RegisterSuccess.title2') }}</div>
<div class="footer">
<div class="title">
<span class="text">What awaits you in Stylish Parade</span>
<span class="text">{{ t('RegisterSuccess.title3') }}</span>
<span class="icon"><svg-icon name="arrow_right" size="11" /></span>
</div>
<div class="content">
<div>
<div class="title">Behind the design</div>
<div class="tip">
Discover how designers bring ideas to life with AiDA from first sketch to final look.
</div>
<div class="title">{{ t('RegisterSuccess.item1title') }}</div>
<div class="tip">{{ t('RegisterSuccess.item1tip') }}</div>
</div>
<div>
<div class="title">Creative digital works</div>
<div class="tip">
Unlock a growing library of inspiring digital works to refresh your creative mind.
</div>
<div class="title">{{ t('RegisterSuccess.item2title') }}</div>
<div class="tip">{{ t('RegisterSuccess.item2tip') }}</div>
</div>
<div>
<div class="title">A fashion community</div>
<div class="tip">
Join a space where fashion speaks exchange ideas and connect with creators worldwide.
</div>
<div class="title">{{ t('RegisterSuccess.item3title') }}</div>
<div class="tip">{{ t('RegisterSuccess.item3tip') }}</div>
</div>
</div>
</div>

View File

@@ -19,7 +19,7 @@
<div class="password-warning">
<span class="icon"><svg-icon name="warning" size="12" /></span>
<span class="label">You must satisfy ALL password conditions to register.</span>
<span class="label">{{ $t('Login.passwordTip') }}</span>
</div>
<el-form-item :label="$t('Login.email')" prop="email">
<el-input name="email" v-model="formData.email" :placeholder="$t('Login.enterEmail')" />

View File

@@ -7,13 +7,17 @@
ref="form1Ref"
v-show="index === 0"
>
<div class="title">Please enter your email address below to verify your identity.</div>
<div class="title">{{ $t('Login.retrievePasswordTitle') }}</div>
<el-form-item :label="$t('Login.email')" prop="email">
<el-input v-model="formData.email" :placeholder="$t('Login.enterEmail')" name="email" />
<el-input
v-model="formData.email"
:placeholder="$t('Login.enterEmail')"
name="email"
/>
</el-form-item>
<el-form-item class="submit-item">
<button class="submit" type="submit" custom="black" @click.prevent="onSubmit1">
SUBMIT
{{ $t('Login.submit') }}
</button>
</el-form-item>
</el-form>
@@ -32,10 +36,10 @@
ref="form2Ref"
v-show="index === 2"
>
<div class="title">
Enter a new password for <br />
<span>{{ formData.email }}</span>
</div>
<div
class="title"
v-html="$t('Login.enterNewPassword', { email: formData.email })"
></div>
<el-form-item :label="$t('Login.password')" prop="password">
<password-tip :value="formData.password" v-show="showPasswordTip" />
<el-input
@@ -50,7 +54,7 @@
</el-form-item>
<div class="password-warning">
<span class="icon"><svg-icon name="warning" size="12" /></span>
<span class="label">You must satisfy ALL password conditions to register.</span>
<span class="label">{{ $t('Login.passwordTip') }}</span>
</div>
<el-form-item :label="$t('Login.passwordConfirmation')" prop="confirmPassword">
<el-input
@@ -63,7 +67,7 @@
</el-form-item>
<el-form-item class="submit-item">
<button class="submit" type="submit" custom="black" @click.prevent="onSubmit2">
SUBMIT
{{ $t('Login.submit') }}
</button>
</el-form-item>
</el-form>
@@ -77,10 +81,12 @@
import { validateEmail, validatePass } from './tools'
import PasswordTip from './password-tip.vue'
import EmailVerify from './email-verify.vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const emit = defineEmits(['back'])
const validateConfirmPassword = (rule: any, value: string, callback: any) => {
if (value !== formData.password) {
callback(new Error('Passwords do not match'))
callback(new Error(t('Login.passwordsDoNotMatch')))
} else {
callback()
}
@@ -158,6 +164,9 @@
flex-direction: column;
.el-form-item.submit-item {
margin-top: auto;
.submit {
text-transform: uppercase;
}
}
.el-input {
--el-input-height: 4.8rem;

View File

@@ -16,7 +16,7 @@
}"
@click="onNavItemClick(v.path)"
>
<span>{{ v.name }}</span>
<span>{{ $t(v.name) }}</span>
</div>
</div>
<div class="right">
@@ -46,30 +46,32 @@
<img src="@/assets/images/profile-content-bg.jpg" alt="" />
<div class="content">
<div class="profile"></div>
<div class="name">Hi, {{ userInfo.username }}</div>
<div class="name">
{{ $t('MainHeader.HiName', { name: userInfo.username }) }}
</div>
</div>
</div>
<div class="nav-item" @click="onMyWardrobe">
<div class="icon"><svg-icon name="my_wardrobe" size="18" /></div>
<div class="label">My Wardrobe</div>
<div class="label">{{ $t('MainHeader.MyWardrobe') }}</div>
</div>
<div class="nav-item" @click="onNotifications">
<div class="icon"><svg-icon name="notifications" size="14" /></div>
<div class="label">Notifications</div>
<div class="label">{{ $t('MainHeader.Notifications') }}</div>
</div>
<div class="nav-item" @click="onSettings">
<div class="icon"><svg-icon name="settings" size="16" /></div>
<div class="label">Settings</div>
<div class="label">{{ $t('MainHeader.Settings') }}</div>
</div>
<div class="hr"></div>
<div class="nav-item logout" @click="onLogout">
<div class="icon"><svg-icon name="logout" size="20" /></div>
<div class="label">Log off</div>
<div class="label">{{ $t('Login.logoff') }}</div>
</div>
</div>
</template>
</el-popover>
<div class="login" @click="onLogin" v-else>Login</div>
<div class="login" @click="onLogin" v-else>{{ $t('Login.login') }}</div>
<div class="language" @click="onLanguageClick">
<span :class="{ active: locale === 'CHINESE_SIMPLIFIED' }"></span> /
<span :class="{ active: locale === 'ENGLISH' }">ENG</span>
@@ -93,19 +95,19 @@
const activePath = computed(() => route.path)
const navList1 = ref([
{
name: 'Home',
name: 'MainHeader.Home',
path: '/'
},
{
name: 'Collection Story',
name: 'MainHeader.CollectionStory',
path: '/collectionStory'
},
{
name: 'Brand',
name: 'MainHeader.Brand',
path: '/brand'
},
{
name: 'Digital Item',
name: 'MainHeader.DigitalItem',
path: '/digitalItem'
}
])
@@ -142,7 +144,7 @@
}
const onLogout = () => {
hideProfilePopover()
ElMessageBox.confirm('Are you sure to log off?')
ElMessageBox.confirm(t('Login.logOffTip'))
.then(() => {
userInfoStore.logout(true)
})

View File

@@ -45,7 +45,7 @@ const {} = toRefs(data);
<el-drawer v-model="isShoppingShow" width="50rem" class="addShoppingDrawer" :close-on-click-modal="false" title="I am the title" :with-header="false">
<div class="addShoppingInfo">
<div class="header">
<div class="title">Added to your Shopping Cart</div>
<div class="title">{{ $t('addShoppingCart.title') }}</div>
<span class="close" @click="shoppingClose"
><svg-icon name="close" size="13"
/></span>
@@ -76,11 +76,11 @@ const {} = toRefs(data);
<div class="icon">
<SvgIcon name="statement" size="16.6" />
</div>
Digital Assets Only. No physical product included.
{{ $t('addShoppingCart.statement') }}
</div>
</div>
<div class="button" @click="goShopping">
SeE Shopping Cart
{{ $t('addShoppingCart.button') }}
</div>
</div>
<!-- <sc-list is-mini style="flex: 0.6;" @close="shoppingClose"/> -->

View File

@@ -1,33 +1,35 @@
<template>
<div class="order-summary">
<div class="title">Order Summary</div>
<div class="title">{{ $t('ShoppingCart.orderSummary') }}</div>
<div class="count">
<span class="label">Selected</span>
<span class="label">{{ $t('ShoppingCart.selected') }}</span>
<span class="value">{{ brandsList.length }}</span>
</div>
<div class="hr"></div>
<div class="brands-header">
<span class="icon"><svg-icon name="order-shop" size="24" /></span>
<span class="text">Brands</span>
<span class="text">{{ $t('ShoppingCart.brands') }}</span>
</div>
<div class="brands-item" v-for="v in brandsList" :key="v.brand">
<span class="label">{{ v.brand }}</span>
<span class="value"
><span>{{ v.children.length }}</span
>item</span
>{{ $t('ShoppingCart.item') }}</span
>
</div>
<br />
<br />
<div class="total">
<span class="label">Total</span>
<span class="label">{{ $t('ShoppingCart.total') }}</span>
<span class="value"
><span>${{ totalAmount }}</span> HKD</span
>
</div>
<div class="hr"></div>
<button class="checkout-btn" custom="black" @click="handleCheckout">CHECKOUT SELECTED</button>
<div class="tip">Digital assets. Creator retains copyright.</div>
<button class="checkout-btn" custom="black" @click="handleCheckout">
{{ $t('ShoppingCart.checkoutSelected') }}
</button>
<div class="tip">{{ $t('ShoppingCart.digitalAssets') }}</div>
</div>
</template>
@@ -162,6 +164,7 @@
> .checkout-btn {
width: 100%;
margin-top: 3rem;
text-transform: uppercase;
}
> .tip {
margin-top: 1rem;

View File

@@ -10,7 +10,7 @@
<img :src="info.cover" />
<div class="content">
<div class="title">{{ info.title }}</div>
<div class="brand" v-if="showBrand">
<div class="brand" v-if="showBrand" @click="handleBrandClick">
<span class="icon"><svg-icon name="order-shop" size="24" /></span>
<span class="text">{{ info.brand }}</span>
</div>
@@ -19,7 +19,7 @@
</div>
<div class="date" v-if="showDate">
<div class="text">
{{ FormatDate(info.date, 'SM D, YYYY, h:mm A') }}
{{ FormatDate(info.date, $t('ShoppingCart.dateTimeFormat')) }}
</div>
</div>
</div>
@@ -27,9 +27,9 @@
<div class="unshelve" v-show="disabled">
<div class="title">
<span><svg-icon name="order-warning" size="20" /></span>
No Longer Available
{{ $t('ShoppingCart.noLongerAvailable') }}
</div>
<div class="tip">Delisted from marketplace</div>
<div class="tip">{{ $t('ShoppingCart.delistedFromMarketplace') }}</div>
</div>
<div class="amount" v-show="!disabled">${{ info.amount }}<span> HKD</span></div>
<SvgIcon
@@ -41,7 +41,7 @@
/>
<div class="remove" v-if="showRemove" @click="onRemove">
<span class="icon"><svg-icon name="order-delete" size="18" /></span>
<span class="text">Remove</span>
<span class="text">{{ $t('ShoppingCart.remove') }}</span>
</div>
</div>
</div>
@@ -49,7 +49,9 @@
<script setup lang="ts">
import { computed, ref, onMounted } from 'vue'
import { FormatBytes, FormatDate } from '@/utils/tools'
import { FormatDate } from '@/utils/tools'
import { useRouter } from 'vue-router'
const router = useRouter()
const emit = defineEmits(['remove'])
const props = defineProps({
showTags: { type: Boolean, default: true },
@@ -67,6 +69,7 @@
date: string
amount: number
cover: string
sellerId: string
},
default: () => {}
},
@@ -79,6 +82,12 @@
const showDownload = computed(() => {
return props.isOrder ? props.info.status === 1 : props.orderActionsLayout
})
const handleBrandClick = () => {
router.push({
name: 'brand',
params: { id: props.info.sellerId }
})
}
</script>
<style lang="less" scoped>
@@ -111,6 +120,7 @@
> .brand {
display: flex;
align-items: center;
cursor: pointer;
> .icon {
width: 2.4rem;
height: 2.4rem;

View File

@@ -4,7 +4,9 @@
<img v-else-if="nullImage === 'brand'" src="@/assets/images/brand-null.png" />
<div class="title">{{ title }}</div>
<div class="tip">{{ tip }}</div>
<button custom v-show="showButton" @click="handleClick">{{ buttonText }}</button>
<button custom v-show="showButton" @click="handleClick">
{{ buttonText || $t('ShoppingCart.exploreDigitalItems') }}
</button>
</div>
</template>
@@ -15,11 +17,10 @@
title: { type: String, default: '' },
tip: { type: String, default: '' },
showButton: { type: Boolean, default: true },
buttonText: { type: String, default: 'EXPLORE DIGITAL ITEMS' }
buttonText: { type: String, default: '' }
})
const emit = defineEmits(['explore'])
const handleClick = () => {
console.log('emit("explore")')
emit('explore')
}
</script>
@@ -59,6 +60,7 @@
font-size: 1.6rem;
color: #979797;
margin-top: 3rem;
text-transform: uppercase;
}
}
</style>

View File

@@ -3,7 +3,7 @@
<div class="sc-list" :class="{ mini: isMini, view: isView }">
<div class="header">
<div class="title">
<span class="text">{{ title || 'Shopping Cart' }}</span>
<span class="text">{{ title || $t('ShoppingCart.title') }}</span>
<span class="close" v-if="isMini && !isView" @click="onClose"
><svg-icon name="close" size="13"
/></span>
@@ -15,22 +15,32 @@
:indeterminate="selectedCount === 0 ? false : selectedCount < maxLength"
@click="handleAllAllClick"
/>
<span class="count">{{ selectedCount }}&nbsp;&nbsp;Selected</span>
<span class="count">{{
$t('Wardrobe.assets.selectedCount', { count: selectedCount })
}}</span>
<div class="hr"></div>
<div class="btn" @click="handleAllAllClick(true)">Select All</div>
<div class="btn" @click="handleAllAllClick(false)">Deselect All</div>
<div class="btn" @click="handleAllAllClick(true)">
{{ $t('Wardrobe.assets.selectAll') }}
</div>
<div class="btn" @click="handleAllAllClick(false)">
{{ $t('Wardrobe.assets.deselectAll') }}
</div>
</div>
<div class="right">
<el-select v-model="sortBy" placeholder="Sort By" :teleported="false">
<el-select
v-model="sortBy"
:placeholder="$t('Wardrobe.sort.label')"
:teleported="false"
>
<template #label="{ label }">
<span class="header-label">Sort By</span>
<span class="header-value">{{ label }}</span>
<span class="header-label">{{ $t('Wardrobe.sort.label') }}</span>
<span class="header-value">{{ $t(label) }}</span>
</template>
<el-option
v-for="item in sortByOptions"
:key="item.label"
:value="item.value"
:label="item.label"
:label="$t(item.label)"
/>
</el-select>
</div>
@@ -40,8 +50,9 @@
<sc-list-null
v-show="list.length === 0"
:show-button="!isMini"
title="Your Cart is empty"
tip="Discover new fashion assets and add them to your cart."
:title="$t('ShoppingCart.listNullTitle')"
:tip="$t('ShoppingCart.listNullTip')"
@explore="handleExplore"
/>
<sc-item
v-for="v in list"
@@ -65,12 +76,12 @@
</div>
<div class="footer" v-if="isMini">
<div class="total" v-show="list.length > 0 || isView">
<span class="label">Total</span>
<span class="label">{{ $t('ShoppingCart.total') }}</span>
<span class="value">${{ allAmount }}<span> HKD</span></span>
</div>
<div class="tip" v-if="isView">Digital assets. Creator retains copyright.</div>
<button custom="black" v-if="!isView">CHECKOUT</button>
<div class="tip" v-if="isView">{{ $t('ShoppingCart.digitalAssets') }}</div>
<button custom="black" v-if="!isView">{{ $t('ShoppingCart.checkout') }}</button>
</div>
</div>
</template>
@@ -83,6 +94,10 @@
import { FormatBytes, FormatDate } from '@/utils/tools'
import scItem from './sc-item.vue'
import scListNull from './sc-list-null.vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const router = useRouter()
const emit = defineEmits(['close', 'selected-change'])
const props = defineProps({
title: { type: String, default: '' },
@@ -100,19 +115,19 @@
const sortBy = ref('DateAdded')
const sortByOptions = ref([
{
label: 'Best Selling',
label: 'digitalItem.BestSelling',
value: 'BestSelling'
},
{
label: 'Price: Low to High',
label: 'digitalItem.Price',
value: 'PriceLowToHigh'
},
{
label: 'Selected First',
label: 'digitalItem.SelectedFirst',
value: 'SelectedFirst'
},
{
label: 'Date Added',
label: 'digitalItem.DateAdded',
value: 'DateAdded'
}
])
@@ -126,7 +141,9 @@
return list_.value.filter(() => true).sort((a, b) => a.amount - b.amount)
}
if (sortBy.value === 'SelectedFirst') {
return list_.value.filter(() => true).sort((a, b) => (b.checked ? 1 : 0) - (a.checked ? 1 : 0))
return list_.value
.filter(() => true)
.sort((a, b) => (b.checked ? 1 : 0) - (a.checked ? 1 : 0))
}
if (sortBy.value === 'DateAdded') {
return list_.value.filter(() => true).sort((a, b) => b.date - a.date)
@@ -142,6 +159,7 @@
listingId: v.listingId, //资产ID
title: v.title, //标题
brand: v.shopName, //店铺名称
sellerId: v.sellerId, //店铺ID
cover: v.cover, //封面
amount: v.price, //价格
status: v.status, //状态
@@ -172,7 +190,7 @@
handleSelectedChange()
})
const handleRemoveClick = (value: any) => {
ElMessageBox.confirm('Are you sure to remove this item?')
ElMessageBox.confirm(t('ShoppingCart.removeTip'))
.then(() => {
RemoveShoppingCartItem({ listingId: value.listingId }).then(() => {
GetList()
@@ -180,8 +198,8 @@
})
.catch(() => {})
}
const handleExploreClick = () => {
console.log('探索')
const handleExplore = () => {
router.push({ name: 'brand' })
}
</script>
@@ -360,6 +378,7 @@
height: 4.6rem;
--button-font-size: 1.4rem;
margin-top: 2rem;
text-transform: uppercase;
}
}
}