Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/FiDA_Front
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# VITE_APP_URL = http://192.168.31.82:8771
|
# VITE_APP_URL = http://192.168.31.82:8771
|
||||||
# VITE_APP_URL = http://18.167.251.121:10095
|
# VITE_APP_URL = http://18.167.251.121:10095
|
||||||
VITE_APP_URL = https://www.lc-api.aida.com.hk
|
VITE_APP_URL = http://192.168.31.118:8080
|
||||||
VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<RouteCache />
|
<!-- <RouteCache /> -->
|
||||||
|
<router-view ></router-view>
|
||||||
<div id="loading" v-if="loading" v-loading="true"></div>
|
<div id="loading" v-if="loading" v-loading="true"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
79
src/api/agent.ts
Normal file
79
src/api/agent.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 对话
|
||||||
|
export interface AgentParamsType {
|
||||||
|
message: string // 消息
|
||||||
|
threadId: string // 对话ID
|
||||||
|
checkpointId?: string // 检查点ID
|
||||||
|
imageUrlList?: string[] // 图片URL列表
|
||||||
|
configParams: Record<string, any> // 其他配置参数
|
||||||
|
token: string
|
||||||
|
}
|
||||||
|
export const fetchAgentReply = (data: AgentParamsType): Promise<AgentResponse> => {
|
||||||
|
return request({
|
||||||
|
url: '/api/ai-design/chat',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
meta: { responseAll: true }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 流式对话
|
||||||
|
export const fetchAgentReplyStream = async (
|
||||||
|
data: AgentParamsType,
|
||||||
|
onMessage: (chunk: string) => void,
|
||||||
|
onEnd: () => void
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
message: data.message,
|
||||||
|
threadId: data.threadId,
|
||||||
|
token: data.token,
|
||||||
|
configParams: JSON.stringify(data.configParams)
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await fetch(`/api/ai-design/chat?${params.toString()}`, {
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = response.body?.getReader()
|
||||||
|
if (!reader) {
|
||||||
|
throw new Error('Response body is not readable')
|
||||||
|
}
|
||||||
|
|
||||||
|
const decoder = new TextDecoder()
|
||||||
|
let buffer = ''
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read()
|
||||||
|
if (done) break
|
||||||
|
|
||||||
|
buffer += decoder.decode(value, { stream: true })
|
||||||
|
const lines = buffer.split('\n')
|
||||||
|
buffer = lines.pop() || '' // 保留不完整的行
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
console.log('line---', line)
|
||||||
|
|
||||||
|
const trimmedLine = line.trim()
|
||||||
|
if (trimmedLine.startsWith('data: ')) {
|
||||||
|
const chunk = trimmedLine.slice(6)
|
||||||
|
if (chunk === '[DONE]') {
|
||||||
|
onEnd()
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
onMessage(chunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEnd()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Stream error:', error)
|
||||||
|
onEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,8 +29,44 @@ body,
|
|||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background-pink {
|
@keyframes opacity-in {
|
||||||
background-color: #f8f7f5;
|
0% {
|
||||||
background-image: url('@/assets/images/home-bg.png');
|
opacity: 0;
|
||||||
background-size: 100% 100%;
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes z-index-10to-1 {
|
||||||
|
0% {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.flex-center {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.flex-1 {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.relative {
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,41 +34,55 @@ body,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.background-pink {
|
@keyframes opacity-in {
|
||||||
background-color: rgba(248, 247, 245, 1);
|
0% {
|
||||||
background-image: url('@/assets/images/home-bg.png');
|
opacity: 0;
|
||||||
background-size: 100% 100%;
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex{
|
@keyframes z-index-10to-1 {
|
||||||
|
0% {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-center{
|
.flex-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-1{
|
.flex-1 {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-col{
|
.flex-col {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.align-center{
|
.align-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-between{
|
.space-between {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.justify-center{
|
.justify-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.relative{
|
.relative {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
BIN
src/assets/images/arrow-top-right.png
Normal file
BIN
src/assets/images/arrow-top-right.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 212 B |
Binary file not shown.
|
Before Width: | Height: | Size: 697 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 581 KiB |
BIN
src/assets/images/nuic/xiang.png
Normal file
BIN
src/assets/images/nuic/xiang.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
@@ -1,8 +1,9 @@
|
|||||||
export default {
|
export default {
|
||||||
|
AlphaVersion: '2026 Alpha Version',
|
||||||
Login: {
|
Login: {
|
||||||
Login: 'Log in',
|
login: 'Log in',
|
||||||
SignUp: 'Sign up',
|
register: 'Register',
|
||||||
LoginTo: 'Log on to',
|
loginTo: 'Log on to <span>FiDA</span>',
|
||||||
LoginTitle: 'A multi-agent canvas for rapid, trend driven design iteration.',
|
LoginTitle: 'A multi-agent canvas for rapid, trend driven design iteration.',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
email: 'Email',
|
email: 'Email',
|
||||||
@@ -21,7 +22,7 @@ export default {
|
|||||||
agreeTermsPolicy:
|
agreeTermsPolicy:
|
||||||
'I agree to the <span onclick="onClickPrivacy()">Terms, Policy</span> and Fees.',
|
'I agree to the <span onclick="onClickPrivacy()">Terms, Policy</span> and Fees.',
|
||||||
noAccountToSignUp: `Don't have an account? <span onclick="onClickRegister()">Sign up</span>`,
|
noAccountToSignUp: `Don't have an account? <span onclick="onClickRegister()">Sign up</span>`,
|
||||||
registerFor: 'Register for',
|
signUpFor: 'Sign up for <span>FiDA</span>',
|
||||||
registerTip: 'A multi-agent canvas for rapid, trend driven design iteration.',
|
registerTip: 'A multi-agent canvas for rapid, trend driven design iteration.',
|
||||||
havenAccountToLogin: `Already have an account? <span onclick="onClickLogin()">Log in</span>`,
|
havenAccountToLogin: `Already have an account? <span onclick="onClickLogin()">Log in</span>`,
|
||||||
verifyEmail: 'Verify your email address',
|
verifyEmail: 'Verify your email address',
|
||||||
@@ -31,21 +32,23 @@ export default {
|
|||||||
resendCodeIn: 'Resend Code in {time}',
|
resendCodeIn: 'Resend Code in {time}',
|
||||||
orContinueWith: 'or continue with',
|
orContinueWith: 'or continue with',
|
||||||
googleLogin: 'Sign in with Google',
|
googleLogin: 'Sign in with Google',
|
||||||
wechatLogin: 'Sign in with Wechat'
|
wechatLogin: 'Sign in with Wechat',
|
||||||
|
indexTip: 'A multi-agent canvas for rapid, trend driven design iteration.',
|
||||||
},
|
},
|
||||||
Nuic: {
|
Nuic: {
|
||||||
hiName: 'Hi, {name}.',
|
hiName: 'Hi, {name}. This is Fiphant.',
|
||||||
nuic1Title: `Help Fiphant discover the <b>'YOU'</b> in your space.`,
|
nuic1Title: `Help him discover the <b>"YOU"</b> in your space.`,
|
||||||
nuic1Tip: `Let's set up your profile. A few quick details will help Fiphant understand<br />your needs and find exactly what you're looking for.`,
|
nuic1Tip: `Let's set up your profile. A few quick details will help Fiphant understand<br />your needs and find exactly what you're looking for.`,
|
||||||
letsGo: 'Let’s go, Fiphant!',
|
letsGo: 'Let’s go, Fiphant!',
|
||||||
skip: 'Skip',
|
skip: 'Skip',
|
||||||
next: 'Next',
|
next: 'Next',
|
||||||
nuic2Title: `What's your dream <b>home vibe</b> ?`,
|
nuic2Title: `What <b>vibe</b> do you usually go for?`,
|
||||||
loadMore: 'Load more',
|
loadMore: 'Load more',
|
||||||
nuic3Title: `Where <b>are you based</b>? What do you <b>do</b> ?`,
|
nuic3Title: `<b>Where</b> are you based? What do you <b>do</b>?`,
|
||||||
basedIn: 'Based in',
|
basedIn: 'Based in',
|
||||||
role: 'Role',
|
role: 'Role',
|
||||||
allSet: 'All set!'
|
allSet: 'All set!',
|
||||||
|
loadingTip: 'We’re customizing your dashboard.',
|
||||||
},
|
},
|
||||||
Home: {
|
Home: {
|
||||||
creditsNum: 'Credits: {num}',
|
creditsNum: 'Credits: {num}',
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="view-404">
|
<div class="view-404">
|
||||||
<p>404 Not Found</p>
|
<!-- <p>404 Not Found</p> -->
|
||||||
|
|
||||||
|
<div class="demo">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -10,6 +16,8 @@
|
|||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.view-404 {
|
.view-404 {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
> p {
|
> p {
|
||||||
margin-top: 5rem;
|
margin-top: 5rem;
|
||||||
@@ -17,5 +25,68 @@
|
|||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
color: #0094ff;
|
color: #0094ff;
|
||||||
}
|
}
|
||||||
|
> .demo {
|
||||||
|
position: absolute;
|
||||||
|
width: 127rem;
|
||||||
|
height: 72.6rem;
|
||||||
|
opacity: 0.8;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
transform: translateX(-50%) translateY(80%);
|
||||||
|
> div {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
> div:nth-child(1) {
|
||||||
|
width: 48.4rem;
|
||||||
|
height: 57.2rem;
|
||||||
|
top: 2.3rem;
|
||||||
|
left: 0rem;
|
||||||
|
background: linear-gradient(
|
||||||
|
130.72deg,
|
||||||
|
rgba(242, 171, 180, 0.2) 29.52%,
|
||||||
|
rgba(234, 133, 200, 0.2) 39.73%,
|
||||||
|
rgba(238, 64, 173, 0.2) 55.81%,
|
||||||
|
rgba(234, 133, 158, 0.2) 69.59%,
|
||||||
|
rgba(242, 171, 180, 0.2) 82.61%
|
||||||
|
);
|
||||||
|
transform: matrix(-0.16, -0.99, 0.97, -0.24, 0, 0);
|
||||||
|
filter: blur(11.5rem);
|
||||||
|
}
|
||||||
|
> div:nth-child(2) {
|
||||||
|
width: 44.6rem;
|
||||||
|
height: 56.8rem;
|
||||||
|
left: 56.6rem;
|
||||||
|
top: 0rem;
|
||||||
|
|
||||||
|
background: conic-gradient(
|
||||||
|
from 94.36deg at 71.77% 41.01%,
|
||||||
|
#f2abb4 0deg,
|
||||||
|
#ff6175 100.75deg,
|
||||||
|
#fe3b53 179.32deg,
|
||||||
|
#ff6175 252deg,
|
||||||
|
#f2abb4 360deg
|
||||||
|
);
|
||||||
|
transform: matrix(0.75, -0.66, 0.65, 0.76, 0, 0);
|
||||||
|
filter: blur(12.927rem);
|
||||||
|
}
|
||||||
|
> div:nth-child(3) {
|
||||||
|
width: 79.958rem;
|
||||||
|
height: 28.1rem;
|
||||||
|
left: 11.724rem;
|
||||||
|
top: 12.353rem;
|
||||||
|
|
||||||
|
background: linear-gradient(
|
||||||
|
87.58deg,
|
||||||
|
#f1c191 23.02%,
|
||||||
|
rgba(255, 178, 91, 0.97) 35.36%,
|
||||||
|
#ff8e69 56.32%,
|
||||||
|
#f2ad7e 67.34%,
|
||||||
|
#ffe8c8 82.74%
|
||||||
|
);
|
||||||
|
transform: matrix(-1, 0.05, -0.03, -1, 0, 0);
|
||||||
|
filter: blur(13.17rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
import To3DModel from './to-3d-model.vue'
|
import To3DModel from './to-3d-model.vue'
|
||||||
import AddPrint from './add-print.vue'
|
import AddPrint from './add-print.vue'
|
||||||
import ToCAD from './to-cad.vue'
|
import ToCAD from './to-cad.vue'
|
||||||
|
|
||||||
import EditMaterial from './edit-material.vue'
|
import EditMaterial from './edit-material.vue'
|
||||||
const components = [
|
const components = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,16 +8,21 @@
|
|||||||
<SvgIcon name="equal" color="#0d0d0d" size="24" />
|
<SvgIcon name="equal" color="#0d0d0d" size="24" />
|
||||||
</div>
|
</div>
|
||||||
<div class="agent-body flex-1 flex flex-col">
|
<div class="agent-body flex-1 flex flex-col">
|
||||||
<List />
|
<List ref="listRef" :message-list="messageList" />
|
||||||
<Input :is-agent-mode="true" @send="handleSendMessage" />
|
<Input is-agent-mode @send="handleSendMessage" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed, onUnmounted } from 'vue'
|
||||||
import List from './List.vue'
|
import List from './List.vue'
|
||||||
import Input from '../../components/Input.vue'
|
import Input from '../../components/Input.vue'
|
||||||
|
import { fetchAgentReply } from '@/api/agent'
|
||||||
|
import type { AgentParamsType } from '@/api/agent'
|
||||||
|
import { useUserInfoStore } from '@/stores'
|
||||||
|
|
||||||
|
const userStore = useUserInfoStore()
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
title: string
|
title: string
|
||||||
@@ -27,8 +32,179 @@
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleSendMessage = (message: string) => {
|
const messageList = ref([])
|
||||||
|
const listRef = ref()
|
||||||
|
const params = reactive<AgentParamsType>({
|
||||||
|
threadId: '',
|
||||||
|
message: '',
|
||||||
|
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyIiwiaWF0IjoxNzcwNzkxMzEyLCJleHAiOjE3NzA4Nzc3MTJ9.xydPinm9l5Yq6GMkfaaVvdHjiINaYrp5VkRM7B9g83A',
|
||||||
|
checkpointId: '',
|
||||||
|
configParams: {
|
||||||
|
type: 'Chair',
|
||||||
|
region: 'China',
|
||||||
|
style: 'Transitional',
|
||||||
|
temperature: 0.7
|
||||||
|
},
|
||||||
|
imageUrlList: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const abort = new AbortController()
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
abort.abort()
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSendMessage = async (message: string) => {
|
||||||
console.log('Message sent:', message)
|
console.log('Message sent:', message)
|
||||||
|
params.message = message.text
|
||||||
|
params.imageUrlList = message.images || []
|
||||||
|
messageList.value.push({
|
||||||
|
id: messageList.value.length + 1,
|
||||||
|
text: message.text,
|
||||||
|
isUser: true
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add AI loading message
|
||||||
|
const aiMessage = reactive({
|
||||||
|
id: messageList.value.length + 1,
|
||||||
|
text: '',
|
||||||
|
isUser: false,
|
||||||
|
loading: true,
|
||||||
|
thinking: false,
|
||||||
|
thinkingText: '',
|
||||||
|
thinkingCollapsed: false,
|
||||||
|
streaming: true
|
||||||
|
})
|
||||||
|
messageList.value.push(aiMessage)
|
||||||
|
|
||||||
|
const threadId = '' //
|
||||||
|
console.log('token---', params.token, '参数---', params)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const urlParams = new URLSearchParams<AgentParamsType>({
|
||||||
|
...params,
|
||||||
|
configParams: JSON.stringify(params.configParams)
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await fetch(`/api/ai-design/chat?${urlParams.toString()}`, {
|
||||||
|
method: 'GET',
|
||||||
|
signal: abort.signal
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检查响应内容类型,判断是否为流式响应
|
||||||
|
const contentType = response.headers.get('content-type') || ''
|
||||||
|
const isStreamResponse =
|
||||||
|
contentType.includes('text/event-stream') || contentType.includes('stream')
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
// 非流式错误响应,使用 text() 读取错误信息
|
||||||
|
const errorText = await response.text()
|
||||||
|
console.error('请求错误:', errorText)
|
||||||
|
throw new Error(`发起对话错误--- ${response.status}: ${errorText}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不是流式响应,使用 text()读取错误信息
|
||||||
|
if (!isStreamResponse) {
|
||||||
|
const text = await response.text()
|
||||||
|
try {
|
||||||
|
const errorData = JSON.parse(text)
|
||||||
|
console.error('非流式响应:', errorData)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('非流式响应文本:', text)
|
||||||
|
}
|
||||||
|
aiMessage.streaming = false
|
||||||
|
aiMessage.loading = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 流式响应处理
|
||||||
|
let contentBody = ''
|
||||||
|
let buffer = ''
|
||||||
|
const reader = response.body?.getReader()
|
||||||
|
if (!reader) throw new Error('无法获取流读取器')
|
||||||
|
|
||||||
|
const decoder = new TextDecoder()
|
||||||
|
|
||||||
|
try {
|
||||||
|
let flag = true
|
||||||
|
while (flag) {
|
||||||
|
const { done, value } = await reader.read()
|
||||||
|
if (done) {
|
||||||
|
console.log('传输结束 end---', contentBody)
|
||||||
|
aiMessage.streaming = false
|
||||||
|
aiMessage.loading = false
|
||||||
|
flag = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += decoder.decode(value, { stream: true })
|
||||||
|
|
||||||
|
// 优先按空行拆分事件块(SSE标准)
|
||||||
|
let events = buffer.split(/\n\n/)
|
||||||
|
buffer = events.pop() // 保留不完整块
|
||||||
|
|
||||||
|
for (let event of events) {
|
||||||
|
if (!event.trim()) continue
|
||||||
|
|
||||||
|
// 过滤掉 id: 等字段,只取 data:
|
||||||
|
const dataLines = event
|
||||||
|
.split(/\n/)
|
||||||
|
.filter((line) => line.startsWith('data:'))
|
||||||
|
.map((line) => line.replace(/^data:\s*/, '').trim())
|
||||||
|
|
||||||
|
if (dataLines.length === 0) continue
|
||||||
|
const jsonText = dataLines.join('\n')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(jsonText)
|
||||||
|
// 赋值 thread_id 和 checkpoint_id
|
||||||
|
if (jsonData.thread_id) params.threadId = jsonData.thread_id
|
||||||
|
if (jsonData.checkpoint_id) params.checkpointId = jsonData.checkpoint_id
|
||||||
|
if (
|
||||||
|
jsonData.content &&
|
||||||
|
jsonData.content.length > 0 &&
|
||||||
|
jsonData.type !== 'end'
|
||||||
|
) {
|
||||||
|
contentBody += jsonData.content
|
||||||
|
aiMessage.text = contentBody
|
||||||
|
}
|
||||||
|
if (jsonData.type === 'end') {
|
||||||
|
aiMessage.streaming = false
|
||||||
|
aiMessage.loading = false
|
||||||
|
flag = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 检查是否为纯文本 [DONE]
|
||||||
|
if (jsonText.trim() === '[DONE]') {
|
||||||
|
console.log('结束-----------------------')
|
||||||
|
aiMessage.streaming = false
|
||||||
|
aiMessage.loading = false
|
||||||
|
flag = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// JSON 不完整:保留到下一次循环
|
||||||
|
if (!jsonText.trim().endsWith('}')) {
|
||||||
|
buffer = 'data: ' + jsonText // 重新放回缓存
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ JSON 格式错误,跳过:', jsonText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('流式传输错误:', error)
|
||||||
|
aiMessage.streaming = false
|
||||||
|
aiMessage.loading = false
|
||||||
|
} finally {
|
||||||
|
reader.releaseLock()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('fetch请求失败:', error)
|
||||||
|
aiMessage.streaming = false
|
||||||
|
aiMessage.loading = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -60,6 +236,8 @@
|
|||||||
}
|
}
|
||||||
.agent-body {
|
.agent-body {
|
||||||
padding: 3.2rem;
|
padding: 3.2rem;
|
||||||
|
overflow: hidden;
|
||||||
|
row-gap: 2.4rem;
|
||||||
.assist-input-wrapper {
|
.assist-input-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 14.4rem;
|
height: 14.4rem;
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="agent-item">
|
<div class="agent-item">
|
||||||
<div class="message-wrapper flex align-center" :class="{ 'is-user': content.isUser }">
|
<div class="message-wrapper flex" :class="{ 'is-user': content.isUser }">
|
||||||
<div class="thumb">
|
<div class="thumb">
|
||||||
<img :src="content.isUser ? userThumb : agentThumb" class="thumb-icon" />
|
<img :src="content.isUser ? userThumb : agentThumb" class="thumb-icon" />
|
||||||
</div>
|
</div>
|
||||||
<div class="message-context">
|
<div
|
||||||
<div class="message-txt">{{ content.text }}</div>
|
class="message-context"
|
||||||
|
v-show="!content.loading && !content.thinking && !content.streaming"
|
||||||
|
>
|
||||||
|
<div class="message-txt markdown-body">
|
||||||
|
<div v-html="formatMessage"></div>
|
||||||
|
</div>
|
||||||
<div class="operate flex" :class="{ 'is-user': content.isUser }">
|
<div class="operate flex" :class="{ 'is-user': content.isUser }">
|
||||||
<template v-if="content.isUser">
|
<template v-if="content.isUser">
|
||||||
<SvgIcon name="copy" size="16" color="#000" @click.stop="handleCopyText" />
|
<SvgIcon name="copy" size="16" color="#000" @click.stop="handleCopyText" />
|
||||||
@@ -22,15 +27,38 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="message-context" v-show="content.loading">
|
||||||
|
<div class="generating">Generating...</div>
|
||||||
|
</div>
|
||||||
|
<div class="message-context" v-show="content.thinking">
|
||||||
|
<div class="thinking">
|
||||||
|
<div class="thinking-header flex align-center" @click="toggleThinkingCollapsed">
|
||||||
|
<span>思考中</span>
|
||||||
|
<!-- <SvgIcon :name="content.thinkingCollapsed ? 'arrowDown' : 'arrowUp'" size="16" color="#666" /> -->
|
||||||
|
</div>
|
||||||
|
<div class="thinking-content" v-show="!content.thinkingCollapsed">
|
||||||
|
<pre>{{ content.thinkingText }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="message-context" v-show="content.streaming">
|
||||||
|
<div class="message-txt">
|
||||||
|
<div v-html="formatMessage"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import gsap from 'gsap'
|
||||||
import userThumb from '@/assets/images/user-thumb.jpg'
|
import userThumb from '@/assets/images/user-thumb.jpg'
|
||||||
import agentThumb from '@/assets/images/agent-thumb.jpg'
|
import agentThumb from '@/assets/images/agent-thumb.jpg'
|
||||||
|
import markdownIt from 'markdown-it'
|
||||||
|
|
||||||
|
const md = new markdownIt()
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@@ -38,6 +66,21 @@
|
|||||||
content: Object
|
content: Object
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const formatMessage = computed(() => {
|
||||||
|
// MARKDOWN.renderer.rules.link_open = (tokens, idx, options, env, self) => {
|
||||||
|
// const aIndex = tokens[idx].attrIndex('target')
|
||||||
|
// if (aIndex < 0) {
|
||||||
|
// tokens[idx].attrPush(['target', '_blank'])
|
||||||
|
// } else {
|
||||||
|
// tokens[idx].attrs[aIndex][1] = '_blank'
|
||||||
|
// }
|
||||||
|
// return self.renderToken(tokens, idx, options, env, self)
|
||||||
|
// }
|
||||||
|
const str = md.render(props.content.text)
|
||||||
|
console.log('str',str)
|
||||||
|
return str
|
||||||
|
})
|
||||||
|
|
||||||
const operateList = ref([
|
const operateList = ref([
|
||||||
{
|
{
|
||||||
name: 'thumbUp',
|
name: 'thumbUp',
|
||||||
@@ -65,6 +108,8 @@
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
navigator.clipboard
|
navigator.clipboard
|
||||||
.writeText(props.content.text)
|
.writeText(props.content.text)
|
||||||
@@ -85,6 +130,10 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleThinkingCollapsed = () => {
|
||||||
|
props.content.thinkingCollapsed = !props.content.thinkingCollapsed
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@@ -97,6 +146,7 @@
|
|||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
.message-wrapper {
|
.message-wrapper {
|
||||||
column-gap: 0.9rem;
|
column-gap: 0.9rem;
|
||||||
|
// align-items: flex-start;
|
||||||
&.is-user {
|
&.is-user {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
@@ -115,6 +165,10 @@
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.message-context{
|
||||||
|
line-height: 2rem;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.operate {
|
.operate {
|
||||||
margin-top: 1.3rem;
|
margin-top: 1.3rem;
|
||||||
@@ -124,4 +178,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.generating {
|
||||||
|
font-family: 'GeneralBold';
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.55rem;
|
||||||
|
background: linear-gradient(45deg, #f2ab4a, #ff6b75, #fe3b55);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thinking {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
|
||||||
|
.thinking-header {
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thinking-content {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,29 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="agent-list flex flex-col flex-1">
|
<div class="agent-list flex flex-col flex-1" ref="listContainer">
|
||||||
<Item v-for="message in messageList" :key="message.id" :content="message" />
|
<Item v-for="message in messageList" :key="message.id" :content="message" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref, nextTick, watch } from 'vue'
|
||||||
import Item from './Item.vue'
|
import Item from './Item.vue'
|
||||||
|
|
||||||
const messageList = ref([
|
const props = defineProps<{
|
||||||
{ id: 1, text: 'Hello', isUser: true },
|
messageList: Array<any>
|
||||||
{
|
}>()
|
||||||
id: 2,
|
|
||||||
text: 'Hey, I am your design assistant FiDA. I noticed that you want to design a yellow sofa. I can help you! Tell me what else you need?'
|
const listContainer = ref<HTMLDivElement>()
|
||||||
},
|
|
||||||
{
|
const scrollToBottom = () => {
|
||||||
id: 3,
|
nextTick(() => {
|
||||||
text: 'Please design a vintage-inspired sofa with smooth, flowing lines and a sculptural silhouette. The sofa features a retro aesthetic combined with elegant curves, creating a timeless and refined look.',
|
if (listContainer.value) {
|
||||||
isUser: true
|
listContainer.value.scrollTop = listContainer.value.scrollHeight
|
||||||
}
|
}
|
||||||
])
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => props.messageList, () => {
|
||||||
|
scrollToBottom()
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
defineExpose({ scrollToBottom })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.agent-list {
|
.agent-list {
|
||||||
row-gap: 3.2rem;
|
row-gap: 3.2rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
// 隐藏滚动条
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
22
src/views/home/agent/components/Menu.vue
Normal file
22
src/views/home/agent/components/Menu.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<div class="menu-wrapper flex space-between">
|
||||||
|
<div class="menu-item"></div>
|
||||||
|
<div class="menu-item"></div>
|
||||||
|
<div class="menu-item"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup></script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.menu-wrapper {
|
||||||
|
width: 1.8rem;
|
||||||
|
cursor: pointer;
|
||||||
|
.menu-item {
|
||||||
|
width: 0.4rem;
|
||||||
|
height: 0.4rem;
|
||||||
|
background-color: #000;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
83
src/views/home/agent/components/Preview.vue
Normal file
83
src/views/home/agent/components/Preview.vue
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="preview-container flex"
|
||||||
|
:class="type === 'sketch' ? 'sketch-preview' : 'report-preview'"
|
||||||
|
>
|
||||||
|
<template v-if="type === 'sketch'">
|
||||||
|
<div class="sketch-item" v-for="item in 12">
|
||||||
|
<Menu class="menu-btn" @click="handleClickMenu" />
|
||||||
|
<div class="edit-btn flex align-center space-between" @click="handleClickEdit">
|
||||||
|
<div>Edit</div>
|
||||||
|
<img src="@/assets/images/arrow-top-right.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<img :src="LoadingImg" alt="" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import Menu from './Menu.vue'
|
||||||
|
import LoadingImg from '@/assets/images/sketch-loading.gif'
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
type: 'sketch' | 'report'
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
type: 'sketch'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
const handleClickEdit = () => {
|
||||||
|
// 编辑按钮点击逻辑
|
||||||
|
console.log('Edit button clicked')
|
||||||
|
}
|
||||||
|
const handleClickMenu = () => {
|
||||||
|
// 菜单按钮点击逻辑
|
||||||
|
console.log('Menu button clicked')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.preview-container {
|
||||||
|
gap: 1.2rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
.sketch-item {
|
||||||
|
position: relative;
|
||||||
|
&,
|
||||||
|
img {
|
||||||
|
width: 21.9rem;
|
||||||
|
height: 21.9rem;
|
||||||
|
border-radius: 1.6rem;
|
||||||
|
}
|
||||||
|
.menu-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 2.1rem;
|
||||||
|
right: 1.5rem;
|
||||||
|
}
|
||||||
|
.edit-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 1rem;
|
||||||
|
bottom: 1.1rem;
|
||||||
|
width: 7.8rem;
|
||||||
|
height: 3.59rem;
|
||||||
|
border-radius: 2rem;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 0.2rem solid #e5e5e5;
|
||||||
|
font-family: 'GeneralMedium';
|
||||||
|
font-size: 1.4rem;
|
||||||
|
padding: 0 0.9rem 0 1.4rem;
|
||||||
|
cursor: pointer;
|
||||||
|
img{
|
||||||
|
width: 1.8rem;
|
||||||
|
height: 1.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="agent-wrapper flex space-between">
|
<div class="agent-wrapper flex space-between">
|
||||||
<Agent :title="agentTitle" />
|
<Agent :title="agentTitle" />
|
||||||
<div class="preview-wrapper">preview</div>
|
<div class="preview-wrapper">
|
||||||
|
<Preview :type="previewType" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import Agent from './components/Agent.vue'
|
import Agent from './components/Agent.vue'
|
||||||
|
import Preview from './components/Preview.vue'
|
||||||
|
|
||||||
const agentTitle = ref('Retro Sofa Sketch')
|
const agentTitle = ref('Retro Sofa Sketch')
|
||||||
|
const previewType = ref<'sketch' | 'report'>('sketch')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@@ -24,7 +29,6 @@
|
|||||||
|
|
||||||
.preview-wrapper {
|
.preview-wrapper {
|
||||||
width: 91.2rem;
|
width: 91.2rem;
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
:placeholder="$t('Input.placeholder')"
|
:placeholder="$t('Input.placeholder')"
|
||||||
@input="handleEditorInput"
|
@input="handleEditorInput"
|
||||||
@paste="handleEditorPaste"
|
@paste="handleEditorPaste"
|
||||||
|
@keypress="handleKeyPress"
|
||||||
>
|
>
|
||||||
<!-- <Tag v-if="showReportTag" /> -->
|
<!-- <Tag v-if="showReportTag" /> -->
|
||||||
<div
|
<div
|
||||||
@@ -295,10 +296,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSendAgent=()=>{
|
const handleKeyPress = (e) => {
|
||||||
emits('send', inputValue.value)
|
// 检测回车
|
||||||
|
if (e.key === 'Enter' && !e.shiftKey) {
|
||||||
|
e.preventDefault()
|
||||||
|
handleSendAgent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSendAgent = () => {
|
||||||
|
if (!inputValue.value.trim()) return
|
||||||
|
emits('send', { text: inputValue.value.trim(), images: uploadedImages.value })
|
||||||
// 发送后清空输入框
|
// 发送后清空输入框
|
||||||
if(editorRef.value){
|
if (editorRef.value) {
|
||||||
editorRef.value.innerHTML = ''
|
editorRef.value.innerHTML = ''
|
||||||
}
|
}
|
||||||
inputValue.value = ''
|
inputValue.value = ''
|
||||||
@@ -315,7 +325,6 @@
|
|||||||
autoResizeEditor()
|
autoResizeEditor()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const typeValue = ref<string>('')
|
const typeValue = ref<string>('')
|
||||||
const areaValue = ref<string>('')
|
const areaValue = ref<string>('')
|
||||||
const styleValue = ref<string>('')
|
const styleValue = ref<string>('')
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home background-pink">
|
<div class="bg bg-1">
|
||||||
|
<div class="topright"></div>
|
||||||
|
<div class="bottomleft"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bg bg-2">
|
||||||
|
<div class="bottom-1"></div>
|
||||||
|
<div class="bottom-2"></div>
|
||||||
|
<div class="bottom-3"></div>
|
||||||
|
</div>
|
||||||
|
<div class="home">
|
||||||
<left-nav />
|
<left-nav />
|
||||||
<div class="right-main">
|
<div class="right-main">
|
||||||
<top-nav />
|
<top-nav />
|
||||||
@@ -38,4 +47,144 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bg-1 {
|
||||||
|
z-index: -1;
|
||||||
|
animation: opacity-in 0.5s ease-in-out 1 both;
|
||||||
|
}
|
||||||
|
.bg-2 {
|
||||||
|
animation: z-index-10to-1 0.5s ease-in-out 1 both;
|
||||||
|
}
|
||||||
|
.bg {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
// background-color: rgba(248, 247, 245, 1);
|
||||||
|
> * {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
> .topright {
|
||||||
|
width: 174.7rem;
|
||||||
|
height: 42.1rem;
|
||||||
|
top: -15.7rem;
|
||||||
|
right: -70rem;
|
||||||
|
|
||||||
|
background: linear-gradient(
|
||||||
|
86.85deg,
|
||||||
|
rgba(244, 147, 116, 0.6) 13.62%,
|
||||||
|
rgba(241, 193, 145, 0.6) 25.57%,
|
||||||
|
rgba(255, 178, 91, 0.582) 41.03%,
|
||||||
|
rgba(242, 173, 126, 0.6) 59.37%,
|
||||||
|
rgba(255, 232, 200, 0.6) 75.27%
|
||||||
|
);
|
||||||
|
opacity: 0.2;
|
||||||
|
filter: blur(20.7656rem);
|
||||||
|
transform: rotate(178.95deg);
|
||||||
|
}
|
||||||
|
> .bottomleft {
|
||||||
|
// border-radius: 0;
|
||||||
|
// border: 1px solid #000;
|
||||||
|
width: 62.418rem;
|
||||||
|
height: 68.245rem;
|
||||||
|
left: -30rem;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
background: linear-gradient(
|
||||||
|
161.16deg,
|
||||||
|
rgba(132, 230, 255, 0.2) 14.98%,
|
||||||
|
rgba(255, 223, 142, 0.2) 68.79%
|
||||||
|
);
|
||||||
|
filter: blur(8.263rem);
|
||||||
|
transform: rotate(-25.36deg);
|
||||||
|
}
|
||||||
|
> .bottom-1 {
|
||||||
|
animation: bottom-1 0.5s ease-in-out 1 both;
|
||||||
|
background: linear-gradient(
|
||||||
|
87.58deg,
|
||||||
|
rgba(241, 193, 145, 0.8) 23.02%,
|
||||||
|
rgba(255, 178, 91, 0.776) 35.36%,
|
||||||
|
rgba(244, 147, 116, 0.8) 56.32%,
|
||||||
|
rgba(242, 173, 126, 0.8) 67.34%,
|
||||||
|
rgba(255, 232, 200, 0.8) 82.74%
|
||||||
|
);
|
||||||
|
filter: blur(13.17rem);
|
||||||
|
transform: matrix(-1, 0.03, -0.05, -1, 0, 0);
|
||||||
|
}
|
||||||
|
> .bottom-2 {
|
||||||
|
animation: bottom-2 0.5s ease-in-out 1 both;
|
||||||
|
|
||||||
|
background: conic-gradient(
|
||||||
|
from 94.36deg at 71.77% 41.01%,
|
||||||
|
rgba(242, 171, 180, 0.2) 0deg,
|
||||||
|
rgba(255, 105, 117, 0.2) 100.75deg,
|
||||||
|
rgba(254, 59, 83, 0.2) 179.32deg,
|
||||||
|
rgba(255, 105, 117, 0.2) 252deg,
|
||||||
|
rgba(242, 171, 180, 0.2) 360deg
|
||||||
|
);
|
||||||
|
filter: blur(12.927rem);
|
||||||
|
transform: matrix(-0.05, 1, -1, -0.03, 0, 0);
|
||||||
|
}
|
||||||
|
> .bottom-3 {
|
||||||
|
animation: bottom-3 0.5s ease-in-out 1 both;
|
||||||
|
background: linear-gradient(
|
||||||
|
130.72deg,
|
||||||
|
rgba(242, 171, 180, 0.24) 29.52%,
|
||||||
|
rgba(234, 133, 200, 0.24) 39.73%,
|
||||||
|
rgba(238, 64, 173, 0.24) 55.81%,
|
||||||
|
rgba(234, 133, 158, 0.24) 69.59%,
|
||||||
|
rgba(242, 171, 180, 0.24) 82.61%
|
||||||
|
);
|
||||||
|
filter: blur(11.5411rem);
|
||||||
|
transform: matrix(-0.26, -0.97, 0.99, -0.15, 0, 0);
|
||||||
|
}
|
||||||
|
@keyframes bottom-1 {
|
||||||
|
0% {
|
||||||
|
width: 15rem;
|
||||||
|
height: 15rem;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 50%;
|
||||||
|
transform: translate(0, 50%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 138.014rem;
|
||||||
|
height: 29.323rem;
|
||||||
|
left: 32.123rem;
|
||||||
|
bottom: -21rem;
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes bottom-2 {
|
||||||
|
0% {
|
||||||
|
width: 15rem;
|
||||||
|
height: 15rem;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 50%;
|
||||||
|
transform: translate(0, 50%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 42.215rem;
|
||||||
|
height: 98.009rem;
|
||||||
|
left: 150rem;
|
||||||
|
bottom: -65rem;
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes bottom-3 {
|
||||||
|
0% {
|
||||||
|
width: 15rem;
|
||||||
|
height: 15rem;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 50%;
|
||||||
|
transform: translate(0, 50%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 51.936rem;
|
||||||
|
height: 97.139rem;
|
||||||
|
left: 40rem;
|
||||||
|
bottom: -65rem;
|
||||||
|
transform: translate(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<img src="@/assets/images/logo-1.png" class="logo" />
|
<img src="@/assets/images/logo-1.png" class="logo" />
|
||||||
<p class="split"></p>
|
<p class="split"></p>
|
||||||
<button class="login" @click="onLogin">{{ $t('Login.login') }}</button>
|
<button class="login" @click="onLogin">{{ $t('Login.login') }}</button>
|
||||||
<button class="register" @click="onRegister">{{ $t('Login.signUp') }}</button>
|
<button class="register" @click="onRegister">{{ $t('Login.register') }}</button>
|
||||||
</div>
|
</div>
|
||||||
<img src="@/assets/images/login/index-title.png" class="title" draggable="false" />
|
<img src="@/assets/images/login/index-title.png" class="title" draggable="false" />
|
||||||
<img src="@/assets/images/login/index-zhuangshi.png" class="zhuangshi" draggable="false" />
|
<img src="@/assets/images/login/index-zhuangshi.png" class="zhuangshi" draggable="false" />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="nuic background-pink">
|
<div class="nuic">
|
||||||
<img class="logo" src="@/assets/images/logo-2.png" />
|
<img class="logo" src="@/assets/images/logo-2.png" />
|
||||||
<div class="header" v-show="!loading">
|
<div class="header" :class="{ loading }">
|
||||||
<div class="close" @click="onClose">
|
<div class="close" @click="onClose">
|
||||||
<svg-icon name="close-border" size="33" />
|
<svg-icon name="close-border" size="33" />
|
||||||
</div>
|
</div>
|
||||||
@@ -19,11 +19,14 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<component v-show="!loading" class="view" :is="list[active]" @next="onNext" />
|
<component :class="{ loading }" class="view" :is="list[active]" @next="onNext" />
|
||||||
<div class="loading" v-show="loading">
|
<div class="bg" :class="{ loading }">
|
||||||
<img src="@/assets/images/nuic/loading.png" />
|
<div class="bg-3"></div>
|
||||||
<p class="tip">{{ $t('Nuic.loadingTip') }}</p>
|
<div class="bg-2"></div>
|
||||||
|
<div class="bg-1"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<img class="loading-img" :class="{ loading }" src="@/assets/images/nuic/xiang.png" />
|
||||||
|
<div class="loading-tip" :class="{ loading }">{{ $t('Nuic.loadingTip') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -49,7 +52,7 @@
|
|||||||
loading.value = true
|
loading.value = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.push({ name: 'mainInput' })
|
router.push({ name: 'mainInput' })
|
||||||
}, 1000)
|
}, 5000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -62,8 +65,20 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
// background-color: #f8f7f5;
|
||||||
// align-items: center;
|
// align-items: center;
|
||||||
// justify-content: center;
|
// justify-content: center;
|
||||||
|
> * {
|
||||||
|
transition: opacity 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
> *:not(.bg):not(.loading-img):not(.loading-tip) {
|
||||||
|
z-index: 10;
|
||||||
|
opacity: 1;
|
||||||
|
&.loading {
|
||||||
|
opacity: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
> .logo {
|
> .logo {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2.7rem;
|
top: 2.7rem;
|
||||||
@@ -147,18 +162,228 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
> .loading {
|
> .loading-img {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 14.4rem;
|
||||||
|
height: auto;
|
||||||
|
opacity: 0;
|
||||||
|
&.loading {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .loading-tip {
|
||||||
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
left: 0;
|
||||||
display: flex;
|
bottom: 25.2rem;
|
||||||
flex-direction: column;
|
text-align: center;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background-color: #f8f7f5;
|
|
||||||
> .tip {
|
|
||||||
font-family: Regular;
|
font-family: Regular;
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
color: #585858;
|
color: #585858;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
&.loading {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .bg {
|
||||||
|
position: absolute;
|
||||||
|
// border: 1px solid #000;
|
||||||
|
&,
|
||||||
|
& > * {
|
||||||
|
transition: all 0.5s ease-in-out;
|
||||||
|
animation-delay: 0.5s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
> div {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
> div.bg-1 {
|
||||||
|
background: linear-gradient(
|
||||||
|
130.72deg,
|
||||||
|
rgba(242, 171, 180, 0.2) 29.52%,
|
||||||
|
rgba(234, 133, 200, 0.2) 39.73%,
|
||||||
|
rgba(238, 64, 173, 0.2) 55.81%,
|
||||||
|
rgba(234, 133, 158, 0.2) 69.59%,
|
||||||
|
rgba(242, 171, 180, 0.2) 82.61%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
> div.bg-2 {
|
||||||
|
background: conic-gradient(
|
||||||
|
from 94.36deg at 71.77% 41.01%,
|
||||||
|
rgba(242, 171, 180, 0.2) 0deg,
|
||||||
|
rgba(255, 97, 117, 0.2) 100.75deg,
|
||||||
|
rgba(254, 59, 83, 0.2) 179.32deg,
|
||||||
|
rgba(255, 97, 117, 0.2) 252deg,
|
||||||
|
rgba(242, 171, 180, 0.2) 360deg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
> div.bg-3 {
|
||||||
|
background: linear-gradient(
|
||||||
|
87.58deg,
|
||||||
|
#f1c191 23.02%,
|
||||||
|
rgba(255, 178, 91, 0.97) 35.36%,
|
||||||
|
#ff8e69 56.32%,
|
||||||
|
#f2ad7e 67.34%,
|
||||||
|
#ffe8c8 82.74%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .bg.loading {
|
||||||
|
width: 47.873rem;
|
||||||
|
height: 46.704rem;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
animation-name: bg;
|
||||||
|
> img {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
> div.bg-1 {
|
||||||
|
animation-name: bg_1;
|
||||||
|
width: 34.164rem;
|
||||||
|
height: 34.92rem;
|
||||||
|
left: 2rem;
|
||||||
|
top: 5rem;
|
||||||
|
filter: blur(11.5rem);
|
||||||
|
transform: matrix(-0.16, -0.99, 0.97, -0.24, 0, 0);
|
||||||
|
}
|
||||||
|
> div.bg-2 {
|
||||||
|
animation-name: bg_2;
|
||||||
|
width: 25.8rem;
|
||||||
|
height: 25.8rem;
|
||||||
|
left: 17rem;
|
||||||
|
top: 4rem;
|
||||||
|
filter: blur(5.48507rem);
|
||||||
|
transform: matrix(0.4, -0.92, 0.91, 0.42, 0, 0);
|
||||||
|
}
|
||||||
|
> div.bg-3 {
|
||||||
|
animation-name: bg_3;
|
||||||
|
width: 25.8rem;
|
||||||
|
height: 25.8rem;
|
||||||
|
left: 10.4rem;
|
||||||
|
top: 17.7rem;
|
||||||
|
filter: blur(5.48507rem);
|
||||||
|
transform: matrix(-0.97, -0.23, 0.25, -0.97, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .bg:not(.loading) {
|
||||||
|
width: 127rem;
|
||||||
|
height: 72.6rem;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
transform: translateX(-50%) translateY(80%);
|
||||||
|
> div.bg-1 {
|
||||||
|
width: 48.4rem;
|
||||||
|
height: 57.2rem;
|
||||||
|
top: 2.3rem;
|
||||||
|
left: 0rem;
|
||||||
|
transform: matrix(-0.16, -0.99, 0.97, -0.24, 0, 0);
|
||||||
|
filter: blur(11.5rem);
|
||||||
|
}
|
||||||
|
> div.bg-2 {
|
||||||
|
width: 44.6rem;
|
||||||
|
height: 56.8rem;
|
||||||
|
left: 56.6rem;
|
||||||
|
top: 0rem;
|
||||||
|
transform: matrix(0.75, -0.66, 0.65, 0.76, 0, 0);
|
||||||
|
filter: blur(12.927rem);
|
||||||
|
}
|
||||||
|
> div.bg-3 {
|
||||||
|
width: 79.958rem;
|
||||||
|
height: 28.1rem;
|
||||||
|
left: 11.724rem;
|
||||||
|
top: 12.353rem;
|
||||||
|
transform: matrix(-1, 0.05, -0.03, -1, 0, 0);
|
||||||
|
filter: blur(13.17rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bg {
|
||||||
|
15% {
|
||||||
|
width: 56.647rem;
|
||||||
|
height: 51.794rem;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
width: 46.179rem;
|
||||||
|
height: 36.712rem;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
width: 52.947rem;
|
||||||
|
height: 46.894rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bg_1 {
|
||||||
|
15% {
|
||||||
|
width: 34.2rem;
|
||||||
|
height: 34.9rem;
|
||||||
|
left: 3rem;
|
||||||
|
top: 12.7rem;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
width: 27.321rem;
|
||||||
|
height: 27.926rem;
|
||||||
|
left: 16.7rem;
|
||||||
|
top: 3.6rem;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
width: 34.164rem;
|
||||||
|
height: 34.92rem;
|
||||||
|
left: 2.5rem;
|
||||||
|
top: 8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes bg_2 {
|
||||||
|
15% {
|
||||||
|
width: 25.8rem;
|
||||||
|
height: 25.8rem;
|
||||||
|
left: 25.5rem;
|
||||||
|
top: 5rem;
|
||||||
|
transform: matrix(0.75, -0.66, 0.65, 0.76, 0, 0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
width: 25.8rem;
|
||||||
|
height: 25.8rem;
|
||||||
|
left: 4rem;
|
||||||
|
top: 4rem;
|
||||||
|
transform: matrix(0.75, -0.66, 0.65, 0.76, 0, 0);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
width: 25.8rem;
|
||||||
|
height: 25.8rem;
|
||||||
|
left: 21.8rem;
|
||||||
|
top: 5rem;
|
||||||
|
transform: matrix(0.75, -0.66, 0.65, 0.76, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes bg_3 {
|
||||||
|
15% {
|
||||||
|
width: 25.8rem;
|
||||||
|
height: 25.8rem;
|
||||||
|
left: 14.603rem;
|
||||||
|
top: 11.784rem;
|
||||||
|
transform: matrix(-1, 0.05, -0.03, -1, 0, 0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
width: 25.8rem;
|
||||||
|
height: 25.8rem;
|
||||||
|
left: 10.701rem;
|
||||||
|
top: 5.283rem;
|
||||||
|
transform: matrix(-1, 0.05, -0.03, -1, 0, 0);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
width: 25.8rem;
|
||||||
|
height: 25.8rem;
|
||||||
|
left: 12.303rem;
|
||||||
|
top: 6.884rem;
|
||||||
|
transform: matrix(-1, 0.05, -0.03, -1, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<div v-for="v in list" :key="v.id" @click="v.active = !v.active">
|
<div v-for="v in list" :key="v.id" @click="v.active = !v.active">
|
||||||
<img :src="v.url" draggable="false" />
|
<img :src="v.url" draggable="false" />
|
||||||
<div class="active" v-show="v.active">
|
<div class="active" v-show="v.active">
|
||||||
<span>这是一段文字</span>
|
<span>{{ v.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,14 +25,14 @@
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const emit = defineEmits(['next'])
|
const emit = defineEmits(['next'])
|
||||||
const list = ref([
|
const list = ref([
|
||||||
{ id: 1, url: '/image/nuic/style-1.png', active: false },
|
{ id: 1, url: '/image/nuic/style-1.png', title: '凳子', active: false },
|
||||||
{ id: 2, url: '/image/nuic/style-2.png', active: false },
|
{ id: 2, url: '/image/nuic/style-2.png', title: '沙发', active: false },
|
||||||
{ id: 3, url: '/image/nuic/style-3.png', active: false },
|
{ id: 3, url: '/image/nuic/style-3.png', title: '凳子', active: false },
|
||||||
{ id: 4, url: '/image/nuic/style-4.png', active: false },
|
{ id: 4, url: '/image/nuic/style-4.png', title: '桌子', active: false },
|
||||||
{ id: 5, url: '/image/nuic/style-5.png', active: false },
|
{ id: 5, url: '/image/nuic/style-5.png', title: '桌子', active: false },
|
||||||
{ id: 6, url: '/image/nuic/style-6.png', active: false },
|
{ id: 6, url: '/image/nuic/style-6.png', title: '桌子', active: false },
|
||||||
{ id: 7, url: '/image/nuic/style-7.png', active: false },
|
{ id: 7, url: '/image/nuic/style-7.png', title: '沙发', active: false },
|
||||||
{ id: 8, url: '/image/nuic/style-8.png', active: false }
|
{ id: 8, url: '/image/nuic/style-8.png', title: '桌子', active: false }
|
||||||
])
|
])
|
||||||
const onLoadMore = () => {}
|
const onLoadMore = () => {}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -77,10 +77,10 @@
|
|||||||
color: #252727;
|
color: #252727;
|
||||||
font-family: LBold;
|
font-family: LBold;
|
||||||
}
|
}
|
||||||
> .el-select {
|
&:deep(> .el-select) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
--el-border-radius-base: 0.8rem;
|
--el-border-radius-base: 0.8rem;
|
||||||
&:deep {
|
|
||||||
font-family: Regular;
|
font-family: Regular;
|
||||||
.el-select__wrapper {
|
.el-select__wrapper {
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
@@ -90,7 +90,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
> .btns {
|
> .btns {
|
||||||
margin-top: 15.8rem;
|
margin-top: 15.8rem;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user