Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/lanecarford_front
All checks were successful
git提交控制 AiDA WEB-Node.js main 分支构建部署 / build (20.19.0) (push) Has been skipped
All checks were successful
git提交控制 AiDA WEB-Node.js main 分支构建部署 / build (20.19.0) (push) Has been skipped
This commit is contained in:
BIN
src/assets/images/female_thumb.png
Normal file
BIN
src/assets/images/female_thumb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
src/assets/images/male_thumb.png
Normal file
BIN
src/assets/images/male_thumb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
@@ -8,9 +8,9 @@ const VerifyIDs = (num: number) => {
|
||||
!!useGenerateStore().styleId,
|
||||
// !!useGenerateStore().modelPhotoId,
|
||||
true,
|
||||
!!useGenerateStore().originalTryOnId,
|
||||
];
|
||||
return ids.splice(0, num).every(id => id) ? true : "/stylist/customer";
|
||||
!!useGenerateStore().originalTryOnId
|
||||
]
|
||||
return ids.splice(0, num).every((id) => id) ? true : '/stylist/customer'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,7 @@ const router = createRouter({
|
||||
{
|
||||
path: '/customer',
|
||||
name: 'customer',
|
||||
component: () => import('@/views/login/customer.vue'),
|
||||
component: () => import('@/views/login/customer.vue')
|
||||
},
|
||||
{
|
||||
path: '/asistant',
|
||||
@@ -115,8 +115,7 @@ const router = createRouter({
|
||||
name: 'dressfor',
|
||||
component: () => import('@/views/stylist/dressfor.vue'),
|
||||
meta: { verify: () => VerifyIDs(2) }
|
||||
},
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -9,7 +9,8 @@ export const useUserInfoStore = defineStore('userInfo', () => {
|
||||
token: '',
|
||||
generateParams: {
|
||||
stylist: '',
|
||||
sex: ''
|
||||
sex: '',
|
||||
stylistImage: ''
|
||||
}
|
||||
})
|
||||
|
||||
@@ -37,7 +38,8 @@ export const useUserInfoStore = defineStore('userInfo', () => {
|
||||
const resetGenerateParams = () => {
|
||||
state.value.generateParams = {
|
||||
stylist: '',
|
||||
sex: ''
|
||||
sex: '',
|
||||
stylistImage: ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
emit('view-type', 1)
|
||||
})
|
||||
const list = reactive([])
|
||||
const size = ref(10)
|
||||
const page = computed(() => Math.ceil(list.length / size.value) + 1)
|
||||
const loading = ref(false)
|
||||
const finish = ref(false)
|
||||
const selectCount = computed(() => list.filter((v) => v.selected).length)
|
||||
@@ -48,16 +50,21 @@
|
||||
const clickNav = (v) => {
|
||||
if (v.value === navActive.value || loading.value) return
|
||||
navActive.value = v.value
|
||||
onLoad()
|
||||
onBackChooseSave()
|
||||
onLoad('reload')
|
||||
}
|
||||
const onLoad = () => {
|
||||
loading.value = true
|
||||
const onLoad = (type?: 'reload') => {
|
||||
if (type === 'reload') {
|
||||
finish.value = false
|
||||
list.splice(0, list.length)
|
||||
}
|
||||
loading.value = true
|
||||
const params = {
|
||||
customerId: generateStore.customerId,
|
||||
type: navActive.value,
|
||||
isLibrary: false
|
||||
isLibrary: false,
|
||||
pageNum: page.value,
|
||||
pageSize: size.value
|
||||
}
|
||||
if (props.isChooseOne) {
|
||||
params['visitRecordId'] = ''
|
||||
@@ -68,8 +75,8 @@
|
||||
params['visitRecordId'] = generateStore.visitRecordId
|
||||
}
|
||||
getGenerateHistoricals(params)
|
||||
.then((data) => {
|
||||
data?.forEach((v) => {
|
||||
.then((data: any) => {
|
||||
data.records?.forEach((v) => {
|
||||
const obj = {
|
||||
// tryOnId: v.tryOnId,
|
||||
tryOnUrl: v.tryOnUrl,
|
||||
@@ -86,7 +93,7 @@
|
||||
list.push(obj)
|
||||
})
|
||||
loading.value = false
|
||||
finish.value = true
|
||||
finish.value = !data.hasNext
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
@@ -229,11 +236,11 @@
|
||||
hGenerateStore.originalTryOn.id = selectedItem.id
|
||||
hGenerateStore.originalTryOn.tryOnUrl = selectedItem.tryOnUrl
|
||||
hGenerateStore.originalTryOn.isLike = selectedItem.isFavorite
|
||||
hGenerateStore.style.id = '';
|
||||
hGenerateStore.style.id = ''
|
||||
hGenerateStore.style.url = selectedItem.styleUrl
|
||||
} else {
|
||||
// style
|
||||
hGenerateStore.style.id = selectedItem.id;
|
||||
hGenerateStore.style.id = selectedItem.id
|
||||
hGenerateStore.style.url = selectedItem.url
|
||||
// selectedItem.isFavorite
|
||||
}
|
||||
@@ -262,7 +269,14 @@
|
||||
</div>
|
||||
<div class="list">
|
||||
<my-list v-model:loading="loading" v-model:finish="finish" @load="onLoad">
|
||||
<div class="item" v-for="(v, i) in list" :key="i" @click="onItem(v)" :type="navActive">
|
||||
<div
|
||||
class="item"
|
||||
v-for="(v, i) in list"
|
||||
:key="i"
|
||||
@click="onItem(v)"
|
||||
:type="navActive"
|
||||
:class="{ active: (isChooseSave || isChooseOne) && v.selected }"
|
||||
>
|
||||
<img v-lazy="v.tryOnUrl || v.url" />
|
||||
<!-- <div class="corner">
|
||||
<div class="ai" v-if="v.isRegenerated">Gen-AI</div>
|
||||
@@ -360,12 +374,14 @@
|
||||
.item {
|
||||
width: 47%;
|
||||
height: 62.2rem;
|
||||
// overflow: hidden;
|
||||
border-radius: var(--border-radius);
|
||||
background-color: #fff;
|
||||
margin-bottom: 4rem;
|
||||
border: 0.1rem solid #000;
|
||||
// overflow: hidden;
|
||||
position: relative;
|
||||
&.active {
|
||||
border: 0.3rem solid #d9d9d9;
|
||||
}
|
||||
&[type='Outfit'] {
|
||||
height: 50rem;
|
||||
> img {
|
||||
@@ -456,7 +472,7 @@
|
||||
}
|
||||
}
|
||||
> .btns {
|
||||
margin: 9rem 0;
|
||||
margin: 5.4rem 0 6.4rem 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { FlowType } from '@/types/enum'
|
||||
//const props = defineProps({
|
||||
//})
|
||||
const emit = defineEmits([
|
||||
'view-type'
|
||||
'viewType'
|
||||
])
|
||||
|
||||
// const data = reactive({
|
||||
@@ -23,7 +23,7 @@ const historicalReview = ()=>{
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
emit('view-type', 1)
|
||||
emit('viewType', 1)
|
||||
})
|
||||
onUnmounted(()=>{
|
||||
})
|
||||
|
||||
@@ -4,9 +4,13 @@ import router from '@/router'
|
||||
import { showConfirmDialog } from 'vant'
|
||||
import { useUserInfoStore, useOverallStore } from '@/stores'
|
||||
import { LogOut } from '@/api/login'
|
||||
import { getCustomerList, type CustomerListParams } from '@/api/workshop'
|
||||
import { getCustomerList, type CustomerListParams,customerCheckin } from '@/api/workshop'
|
||||
import MyEvent from '@/utils/myEvent'
|
||||
|
||||
const props = defineProps<{
|
||||
isCustomer?: boolean
|
||||
}>()
|
||||
|
||||
const userInfoStore = useUserInfoStore()
|
||||
const overallStore = useOverallStore()
|
||||
const emit = defineEmits(['view-type', 'selected-customer'])
|
||||
@@ -148,6 +152,14 @@ const handleSelectCustomer = () => {
|
||||
if (selectedCustomer) {
|
||||
emit('selected-customer', selectedCustomer)
|
||||
}
|
||||
if(!props.isCustomer){
|
||||
// show.value = true
|
||||
customerCheckin({ nickname: selectedCustomer.name }).then((res) => {
|
||||
useUserInfoStore().resetGenerateParams()
|
||||
MyEvent.emit('clear-generate-state')
|
||||
useUserInfoStore().setCustomerInfo(res)
|
||||
})
|
||||
}
|
||||
showSwitchCustomerPopup.value = false
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="chat-message" :class="{ 'user-message': isMyself, 'ai-message': !isMyself }">
|
||||
<!-- AI消息显示头像 -->
|
||||
<div v-if="!isMyself" class="chat-avatar">
|
||||
<img src="@/assets/images/asistant.png" alt="AI Avatar" />
|
||||
<img class="avatar" :src="thumb" alt="AI Avatar" />
|
||||
</div>
|
||||
|
||||
<!-- 消息内容 -->
|
||||
@@ -27,9 +27,15 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import { useUserInfoStore } from '@/stores'
|
||||
|
||||
const md = new MarkdownIt()
|
||||
|
||||
const userInfoStore = useUserInfoStore()
|
||||
const thumb = computed(() => {
|
||||
return userInfoStore.state.generateParams.stylistImage
|
||||
})
|
||||
|
||||
// 定义消息类型
|
||||
interface ChatMessage {
|
||||
sessionId: string | number
|
||||
@@ -133,16 +139,17 @@ const actionList: ActionItem[] = [
|
||||
|
||||
.chat-avatar {
|
||||
width: 7.8rem;
|
||||
height: 7.4rem;
|
||||
height: 7.8rem;
|
||||
border-radius: 50%;
|
||||
margin-right: 1.88rem;
|
||||
border: .2rem solid #000;
|
||||
padding: 1.4rem;
|
||||
overflow: hidden;
|
||||
// border: 0.2rem solid #000;
|
||||
// padding: 1.4rem;
|
||||
|
||||
img {
|
||||
width: 4.9rem;
|
||||
height: 4.9rem;
|
||||
border-radius: 50%;
|
||||
width: 100%;
|
||||
// height: 100%;
|
||||
// border-radius: 50%;
|
||||
// object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<div class="header">
|
||||
<HeaderTitle hasSetting styleType="3" />
|
||||
</div>
|
||||
<template>
|
||||
<div class="content flex-1">
|
||||
<NoticeList
|
||||
ref="noticeListRef"
|
||||
@@ -15,10 +14,9 @@
|
||||
<div class="footer">
|
||||
<InputArea @send-message="handleSendMessage" />
|
||||
<div class="continue flex">
|
||||
<div class="btn flex flex-center" @click="handleContinue">Continue</div>
|
||||
<div class="btn flex flex-center" @click="handleContinue">Generate</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -274,7 +272,7 @@ const handleContinue = () => {
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.asistant-container {
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -306,5 +304,4 @@ const handleContinue = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<div class="title">Log in.</div>
|
||||
<p class="subtitle">Redefine the styling experience with AI.</p>
|
||||
<p class="subtitle">Use Styling Angel to speed up your fashion journey.</p>
|
||||
<div class="title">Staff Login.</div>
|
||||
<p class="subtitle">
|
||||
<span>Experience our personalised styling journey with</span>
|
||||
<br />
|
||||
<span>Lane Crawford.</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="login-container">
|
||||
@@ -32,7 +35,11 @@
|
||||
<img :src="google" class="google-icon" />
|
||||
Sign in with Google
|
||||
</div> -->
|
||||
<GoogleLogin @googelLogin="handleGoogleLogin" ref="googleLoginRef" @click="clickGooleLogin"></GoogleLogin>
|
||||
<GoogleLogin
|
||||
@googelLogin="handleGoogleLogin"
|
||||
ref="googleLoginRef"
|
||||
@click="clickGooleLogin"
|
||||
></GoogleLogin>
|
||||
<div class="sign-up-button" @click="handleSignup">Don’t have an account? Sign Up</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -191,12 +198,14 @@ const handleSignup = () => {
|
||||
|
||||
.header {
|
||||
margin-top: 1.42rem;
|
||||
padding-left: 15.5rem;
|
||||
padding-left: 14.5rem;
|
||||
padding-right: 14.3rem;
|
||||
color: white;
|
||||
font-family: 'satoshiRegular';
|
||||
.title {
|
||||
font-size: 11rem;
|
||||
font-weight: bold;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.8rem;
|
||||
color: white;
|
||||
font-family: 'satoshiBold';
|
||||
@@ -226,11 +235,7 @@ const handleSignup = () => {
|
||||
position: relative;
|
||||
width: calc(100% - 28.4rem);
|
||||
height: 107.8rem;
|
||||
background: radial-gradient(
|
||||
100% 100% at 0% 0%,
|
||||
rgba(0, 0, 0, 0.4) 0%,
|
||||
rgba(0, 0, 0, 0.2) 100%
|
||||
);
|
||||
background: radial-gradient(100% 100% at 0% 0%, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0.2) 100%);
|
||||
backdrop-filter: blur(35px);
|
||||
-webkit-backdrop-filter: blur(35px);
|
||||
-moz-backdrop-filter: blur(35px);
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
|
||||
<!-- 标题区域 -->
|
||||
<div class="header">
|
||||
<div class="title">Log in.</div>
|
||||
<p class="subtitle">Redefine the styling experience with AI.</p>
|
||||
<p class="subtitle">Use Styling Angel to speed up your fashion journey.</p>
|
||||
<div class="title">Staff Login.</div>
|
||||
<p class="subtitle">
|
||||
<span>Experience our personalised styling journey with</span>
|
||||
<br />
|
||||
<span>Lane Crawford.</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="login-container">
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<div class="title">Sign up.</div>
|
||||
<p class="subtitle">Redefine the styling experience with AI.</p>
|
||||
<p class="subtitle">Use Styling Angel to speed up your fashion journey.</p>
|
||||
<div class="title">Staff Sign up.</div>
|
||||
<p class="subtitle">Start my personalised styling journey with Lane Crawford.</p>
|
||||
</div>
|
||||
|
||||
<div class="login-container">
|
||||
@@ -30,7 +29,12 @@
|
||||
|
||||
<button type="button" class="login-button" @click="handleConfirm">Sign Up</button>
|
||||
|
||||
<GoogleLogin text="Sign up with Google" @googelLogin="handleGoogleSignup" ref="googleSignupRef" @click="clickGooleLogin" />
|
||||
<GoogleLogin
|
||||
text="Sign up with Google"
|
||||
@googelLogin="handleGoogleSignup"
|
||||
ref="googleSignupRef"
|
||||
@click="clickGooleLogin"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -191,7 +195,8 @@ const handleGoogleSignup = async (accessToken: string) => {
|
||||
|
||||
.header {
|
||||
margin-top: 1.42rem;
|
||||
padding-left: 15.5rem;
|
||||
padding-left: 14.5rem;
|
||||
padding-right: 14.3rem;
|
||||
color: white;
|
||||
font-family: 'satoshiRegular';
|
||||
.title {
|
||||
@@ -281,7 +286,6 @@ const handleGoogleSignup = async (accessToken: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.footer {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
<div class="welcome-page safe-area-top safe-area-bottom">
|
||||
<div class="content">
|
||||
<div class="title">
|
||||
AI STYLING <br />
|
||||
ASSISTANT
|
||||
Styling <br />
|
||||
Assistant
|
||||
</div>
|
||||
<p class="subtitle">Redefine the styling experience with AI.</p>
|
||||
<p class="subtitle">
|
||||
<span>Experience our personalised styling journey with</span>
|
||||
<br>
|
||||
<span> Lane Crawford.</span>
|
||||
</p>
|
||||
<div class="btn-container flex">
|
||||
<div class="log btn" @click="goToLogin">Log in</div>
|
||||
<div class="sign btn" @click="goToSignup">Sign up</div>
|
||||
@@ -49,15 +53,16 @@ const goToLogin = () => {
|
||||
font-weight: 400;
|
||||
margin-bottom: 31.5rem;
|
||||
.title {
|
||||
font-family: 'boskaRegular';
|
||||
line-height: 93%;
|
||||
letter-spacing: -0.02em;
|
||||
font-family: 'satoshiMedium';
|
||||
line-height: 120%;
|
||||
// letter-spacing: -0.02em;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 3.2rem;
|
||||
font-family: 'satoshiRegular';
|
||||
margin: 3.2rem 0 6rem;
|
||||
list-style: 124%;
|
||||
font-weight: 400;
|
||||
line-height: 124%;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
.btn-container {
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
<div class="text">
|
||||
<div class="form-title">{{ formTitle }}</div>
|
||||
<div class="description">
|
||||
<p>Redefine the styling experience with AI.</p>
|
||||
<p>Use Styling Angel to speed up your fashion journey.</p>
|
||||
<p>Unlock personalized styling insights.</p>
|
||||
<p>Enter a client profile to begin curating their next look with Styling Angel.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<Profile ref="profileRef" @selected-customer="handleSelectCustomer" />
|
||||
<Profile ref="profileRef" @selected-customer="handleSelectCustomer" is-customer />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -70,7 +70,6 @@ import { customerCheckin, createCustomer, type CreateCustomerParams } from '@/ap
|
||||
import Profile from '../Workshop/profile.vue'
|
||||
import MyEvent from '@/utils/myEvent'
|
||||
|
||||
|
||||
const profileRef = ref<typeof Profile>(null)
|
||||
const handleOpenProfile = () => {
|
||||
profileRef.value.open()
|
||||
@@ -107,6 +106,7 @@ const handleConfirm = async () => {
|
||||
customerCheckin({ nickname: customerData.value.nickname }).then((res) => {
|
||||
useUserInfoStore().resetGenerateParams()
|
||||
generateStore.setCustomerInfo(res)
|
||||
MyEvent.emit('clear-generate-state')
|
||||
router.push('/workshop/home')
|
||||
})
|
||||
} else {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<!-- Continue按钮 -->
|
||||
<div class="continue-button" @click="handleContinue" v-if="!$route.query?.demo">Continue</div>
|
||||
<van-dialog
|
||||
<!-- <van-dialog
|
||||
class="video-dialog"
|
||||
:show-confirm-button="false"
|
||||
:show-cancel-button="false"
|
||||
@@ -47,7 +47,7 @@
|
||||
<van-icon name="cross" class="close-icon" />
|
||||
</div>
|
||||
<Video ref="videoRef" />
|
||||
</van-dialog>
|
||||
</van-dialog> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -57,7 +57,9 @@ import { useRouter } from 'vue-router'
|
||||
import Video from './components/Video.vue'
|
||||
import { useUserInfoStore } from '@/stores'
|
||||
import male from '@/assets/images/male.png'
|
||||
import maleThumb from '@/assets/images/male_thumb.png'
|
||||
import female from '@/assets/images/female.png'
|
||||
import femaleThumb from '@/assets/images/female_thumb.png'
|
||||
import HeaderTitle from '@/components/HeaderTitle.vue'
|
||||
import FooterNavigation from '@/components/FooterNavigation.vue'
|
||||
|
||||
@@ -70,28 +72,32 @@ const stylists = ref<any[]>([
|
||||
value: 'crystal',
|
||||
name: 'Vera Lo',
|
||||
description: 'Contemporary, Classic, Simple Silhouettes, Statement Pieces',
|
||||
image: female
|
||||
image: female,
|
||||
thumb: femaleThumb
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
value: 'mini',
|
||||
name: 'Sarah Chen',
|
||||
description: 'Modern, Edgy, Bold Colors, Street Style',
|
||||
image: male
|
||||
image: male,
|
||||
thumb: maleThumb
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
value: 'crystal',
|
||||
name: 'Emma Wilson',
|
||||
description: 'Elegant, Feminine, Vintage Inspired, Soft Tones',
|
||||
image: female
|
||||
image: female,
|
||||
thumb: femaleThumb
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
value: 'mini',
|
||||
name: 'Alex Johnson',
|
||||
description: 'Minimalist, Professional, Neutral Palette, Clean Lines',
|
||||
image: male
|
||||
image: male,
|
||||
thumb: maleThumb
|
||||
}
|
||||
])
|
||||
const currentChoosed = ref(1)
|
||||
@@ -119,20 +125,22 @@ const handleClickStylist = (item: any) => {
|
||||
|
||||
const handleContinue = () => {
|
||||
const generateParams = userInfoStore.getGenerateParams()
|
||||
generateParams.stylist =
|
||||
stylists.value.find((item) => item.id === currentChoosed.value)?.value || ''
|
||||
const selected = stylists.value.find((item) => item.id === currentChoosed.value)
|
||||
generateParams.stylist = selected?.value
|
||||
generateParams.stylistImage = selected?.thumb
|
||||
|
||||
userInfoStore.setGenerateParams(generateParams)
|
||||
|
||||
router.push('/workshop/stylist/sex')
|
||||
}
|
||||
|
||||
// 监听showVideo变化,关闭时暂停视频
|
||||
watch(showVideo, (newValue) => {
|
||||
if (!newValue && videoRef.value) {
|
||||
videoRef.value.pause()
|
||||
videoRef.value.reset()
|
||||
}
|
||||
})
|
||||
// watch(showVideo, (newValue) => {
|
||||
// if (!newValue && videoRef.value) {
|
||||
// videoRef.value.pause()
|
||||
// videoRef.value.reset()
|
||||
// }
|
||||
// })
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
Reference in New Issue
Block a user