'frontendadd'

This commit is contained in:
yangqiao
2024-12-30 17:47:28 +08:00
parent 8b4cc37514
commit 34e25633ba
71 changed files with 3699 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
.content {
max-width: 1196px;
// width: 100%;
margin: 0 auto;
padding-top: 98px;
.title-box {
width: 100%;
display: flex;
align-items: center;
column-gap: 8px;
margin-bottom: 16px;
img {
width: 40px;
height: 40px;
}
span {
font-size: 30px;
color: #fff;
font-weight: 600;
}
}
.recommend-box {
width: 100%;
margin-top: 72px;
box-sizing: border-box;
.recommend-title {
display: flex;
align-items: center;
column-gap: 8px;
margin-bottom: 12px;
img {
width: 22px;
height: 24px;
}
span {
font-size: 22px;
font-weight: 600;
color: #fff;
}
}
.recommend-bottm {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
column-gap: 24px;
row-gap: 24px;
.recommend-list {
width: 100%;
color: #fff;
display: flex;
flex-wrap: wrap;
column-gap: 24px;
row-gap: 12px;
box-sizing: border-box;
.item {
// max-width: 438px;
width: calc(50% - 12px);
padding: 8px 16px;
border: 1px solid rgba(37, 79, 127, 1);
border-radius: 6px;
box-sizing: border-box;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
text-align: justify;
}
}
}
}
}

View File

@@ -0,0 +1,55 @@
<template>
<div class="content">
<div class="title-box">
<img src="../../assets/logo.png" alt="" />
<span>{{ generateTitle('您好多智能体MARS为您服务') }}</span>
</div>
<TextareaView @submitFun="reasoningFun" :minRows="6"></TextareaView>
<div class="recommend-box">
<div class="recommend-title">
<img src="../../assets/home/recommend.png" alt="" />
<span>{{ generateTitle('推荐问题') }}</span>
</div>
<div class="recommend-bottm">
<div class="recommend-list">
<div
class="item"
@click="submitFun(item)"
v-for="(item, index) in recommendList"
:key="index"
>
{{ item }}
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import TextareaView from '../../components/TextareaView.vue'
import { generateTitle } from '../../utils/i18n'
const recommendList = ref<Array<any>>([
'Structure: How can the self-assembly of materials be achieved for nanoparticles by controlling intermolecular interactions?',
'Property: For perovskite nanocrystals, how can blue-shifting of the fluorescence emission wavelength be controlled through structural design?',
'Synthesis: How to synthesize CsPbBr₃ nanocubes at room temperature?',
'Application: How can the photoluminescence quantum efficiency of perovskites in LED devices be improved?'
])
const router = useRouter()
const submitFun = (e: any) => {
let data = {
chat_id: new Date().getTime(),
message: e
}
router.push('/reasoning?message=' + JSON.stringify(data))
}
const reasoningFun = (e: any) => {
router.push('/reasoning?message=' + e)
}
onMounted(() => {})
</script>
<style scoped>
@import './index.less';
</style>

View File

@@ -0,0 +1,62 @@
.login-box {
width: 100vw;
height: 100vh;
background: url('../../assets/login/background.png') no-repeat;
background-size: cover;
display: flex;
align-items: center;
justify-content: center;
.content {
width: 450px;
background: rgba(255, 255, 255, 0.8);
box-sizing: border-box;
padding: 40px;
border-radius: 16px;
box-shadow: 0px 15px 15px 0px rgba(0, 0, 0, 0.05);
.title {
width: 100%;
display: flex;
align-items: center;
column-gap: 12px;
margin-bottom: 24px;
img {
width: 40px;
height: 40px;
}
span {
font-size: 32px;
color: #333;
font-weight: 600;
}
}
.code-box {
width: 100%;
display: flex;
align-items: center;
column-gap: 12px;
}
:deep(.el-form) {
margin-bottom: 34px;
.el-input__inner {
height: 56px;
font-size: 16px;
}
}
.btn-box {
width: 100%;
.el-button {
width: 100%;
height: 60px;
}
}
}
}

View File

@@ -0,0 +1,109 @@
<template>
<div class="login-box">
<div v-loading="loading" class="content">
<div class="title">
<img src="/logo.png" alt="" />
<span>{{generateTitle('MARS模型创制系统')}}</span>
</div>
<el-form :model="loginData">
<el-form-item>
<el-input
:placeholder="generateTitle('账号')"
v-model="loginData.user_name"
:prefix-icon="UserFilled"
></el-input>
</el-form-item>
<el-form-item>
<el-input
:placeholder="generateTitle('密码')"
type="password"
v-model="loginData.pass_word"
:prefix-icon="Lock"
show-password
></el-input>
</el-form-item>
<el-form-item>
<div class="code-box">
<el-input
:placeholder="generateTitle('验证码')"
v-model="loginData.code"
:prefix-icon="Lock"
></el-input>
<ValidCode ref="validCodeRef" :height="56"></ValidCode>
</div>
</el-form-item>
</el-form>
<div class="btn-box">
<el-button
@click="submitFun"
type="primary"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.3)"
v-loading.fullscreen.lock="loading"
>{{generateTitle("登录")}}</el-button
>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { UserFilled, Lock } from '@element-plus/icons-vue'
import ValidCode from '../../components/ValidCode.vue'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import { authLogin } from '../../api/user'
import {generateTitle} from '../../utils/i18n'
const router = useRouter()
const loginData = ref<any>({
user_name: '',
pass_word: '',
code: ''
})
const loading = ref(false)
const handleKeyPress = (event: KeyboardEvent) => {
if (event.key === 'Enter') {
submitFun()
}
}
const validCodeRef = ref()
const submitFun = async () => {
if (!loginData.value.user_name) {
ElMessage.error(generateTitle('请输入账号'))
return
}
if (!loginData.value.pass_word) {
ElMessage.error(generateTitle('请输入密码'))
return
}
if (!loginData.value.user_name) {
ElMessage.error(generateTitle('请输入验证码'))
return
}
let code = validCodeRef.value.validate(loginData.value.code)
if (!code) {
ElMessage.error(generateTitle('验证码错误'))
return
}
loading.value = true
try {
const { token }: any = await authLogin(loginData.value)
localStorage.setItem('token', token)
loading.value = false
router.push('/home')
} catch (error: any) {
loading.value = false
ElMessage.error(error.response.data.error)
}
}
onMounted(() => {
window.addEventListener('keypress', handleKeyPress)
})
onUnmounted(() => {
window.removeEventListener('keypress', handleKeyPress)
})
</script>
<style scoped>
@import './index.less';
</style>

View File

@@ -0,0 +1,74 @@
.reasoning-content {
width: 100%;
display: flex;
align-items: flex-start;
box-sizing: border-box;
overflow: hidden;
.content-left {
width: 100%;
.body-box {
width: 100%;
overflow: auto;
height: calc(90vh - 175px);
&::-webkit-scrollbar {
width: 4px;
height: 4px;
}
&::-webkit-scrollbar-thumb {
background: #1A87CA;
}
&::-webkit-scrollbar-thumb:hover {
background: #1A87CA;
}
}
.message-box {
width: calc(100% - 48px);
padding-top: 30px;
.tip-box {
width: 100%;
display: flex;
align-items: center;
column-gap: 12px;
.tip-text {
color: #fff;
font-size: 16px;
}
}
.active_item {
// width: 104px;
box-sizing: border-box;
padding: 0 8px;
font-size: 14px;
height: 32px;
margin: 0;
color: rgba(73, 252, 255, 0.80);
border-radius: 32px;
border: 1px solid rgba(24, 91, 197, 1);
box-shadow: 0px 0px 6px 0px rgba(0, 213, 250, 1) inset;
display: flex;
align-items: center;
justify-content: center;
column-gap: 4px;
background: #0C3870;
margin-bottom: 8px;
.el-icon {
width: 16px;
height: 16px;
border-radius: 50%;
background: linear-gradient(180deg, #62FAF8 0%, #2DC9FE 100%);
}
}
}
}
}

View File

@@ -0,0 +1,213 @@
<template>
<div class="reasoning-content">
<div
class="content-left"
:style="{
width: isCollapse ? 'calc(100% - 200px)' : 'calc(100% - 7px)'
}"
>
<div class="body-box" ref="container">
<reasoning-view
ref="reasoningRef"
@completeFun="completeFun"
:reasoningList="reasoningList"
/>
</div>
<div class="message-box">
<div class="tip-box">
<p class="active_item">
<el-icon size="6" color="#fff"><Plus /></el-icon>
{{ generateTitle('新建对话') }}
</p>
<div class="tip-text" v-show="disableStatus">
{{ generateTitle('回答输出中暂不能再次提问') }}
</div>
</div>
<TextareaView ref="textareaRef" :minRows="1" @submitFun="submitFun" />
</div>
</div>
<collapseView
ref="collapseRef"
:reasoningList="reasoningList"
@changeStatusFun="changeStatusFun"
/>
</div>
</template>
<script setup lang="ts">
import ReasoningView from '../../components/ReasoningView/index.vue'
import TextareaView from '../../components/TextareaView.vue'
import collapseView from '../../components/collapseView/index.vue'
import { Plus } from '@element-plus/icons-vue'
import { ref, onMounted, nextTick } from 'vue'
// import { getModelList } from '../../api/user'
import { useRoute } from 'vue-router'
import useWebSocket from '../../utils/websocket'
import { getAgent } from '../../utils/agent'
import { generateTitle } from '../../utils/i18n'
const route: any = useRoute()
const reasoningRef = ref<any>(null)
const textareaRef = ref<any>(null)
const collapseRef = ref<any>(null)
const isCollapse = ref<boolean>(true)
const changeStatusFun = (val: boolean) => {
isCollapse.value = val
}
const reasoningList = ref<Array<any>>([])
// const getModelListFun = async () => {
// try {
// const { data, code } = await getModelList()
// if (code) {
// reasoningList.value = data
// }
// } catch (error) {
// console.log(error)
// }
// }
const submitFun = (val: any) => {
completeFun()
addMode(JSON.parse(val).message)
ws.send(val)
}
const addMode = (val: any) => {
endStatus.value = false
reasoningList.value.push({
title: val,
children: []
})
reasoningRef.value.completeList.push({
show: false,
index: reasoningRef.value.completeList.length
})
}
const disableStatus = ref(false)
const completeFun = () => {
disableStatus.value = true
textareaRef.value.disableStatus = true
}
const handleMessage = (e: any) => {
getMessage(e.data)
getHeight()
}
const startStatus = ref(false)
const contentStatus = ref(false)
const endStatus = ref(false)
const getMessage = async (e: any) => {
// if (e.split('TERMINATE')[1]) {
// talkList.value += e.split('TERMINATE')[0]
// reasonStatus.value.show = false
// endShow.value = true
// extractSynthesisProcess()
// } else {
// talkList.value += e
// }
reasoningRef.value.reasonStatus.show = true
// talkList.value += e
// console.log(talkList.value);
let list = reasoningList.value
let children = list[list.length - 1].children
// if (
// e.includes(
// '--------------------------------------------------------------------------------'
// )
// ) {
// startStatus.value = true
// } else if (startStatus.value) {
if (parseChatData(e)) {
if (parseChatData(e)?.type) {
children.push({
title: parseChatData(e)?.title,
content: ''
})
reasoningRef.value.reasonStatus.index = children.length - 1
} else {
if (children[children.length - 1].content) {
children[children.length - 1].content += parseChatData(e)?.current
} else {
children[children.length - 1].content = parseChatData(e)?.current
}
}
}
// }
}
function parseChatData(e: any) {
let condition =
!e.includes(
'--------------------------------------------------------------------------------'
) &&
!e.includes(
`********************************************************************************`
) &&
!e.includes('Starting a new chat....') &&
!e.includes('>>>>>>>>')
let title = ''
let current = ''
let regex = /Next speaker: (.*)/
if (condition) {
if (e.includes('Planer') || e.includes('Planner')) {
title = getAgent('Planer')
return {
title,
type: true
}
}
if (e.match(regex) && e.match(regex)[1]) {
// if (!getAgent(e.match(regex)[1])) {
// contentStatus.value = true
// return
// }
// contentStatus.value = false
// title = getAgent(e.match(regex)[1])
title = getAgent(e.match(regex)[1]) || e.match(regex)[1]
return {
title,
type: true
}
}
if (contentStatus.value) {
return
}
if (e.includes('TERMINATE')) {
endStatus.value = true
reasoningRef.value.reasonStatus.show = false
reasoningRef.value.completeList[
reasoningRef.value.completeList.length - 1
].show = true
disableStatus.value = false
textareaRef.value.disableStatus = false
startStatus.value = false
}
current = e.replace(
/(?<!`)TERMINATE(?<!\*\*)|TERMINATE(?!\*\*)|`TERMINATE`/g,
''
)
return {
current,
type: false
}
}
}
const ws = useWebSocket(handleMessage)
const sendFun = () => {
setTimeout(() => {
addMode(JSON.parse(route.query.message).message)
completeFun()
ws.send(JSON.stringify(route.query.message))
}, 300)
}
const container = ref<any>(null)
const getHeight = () => {
container.value.scrollTop = container.value.scrollHeight + 150
collapseRef.value.scrollTop = collapseRef.value.scrollHeight + 50
}
onMounted(() => {
// getModelListFun();
nextTick(() => {
getHeight()
sendFun()
})
})
</script>
<style scoped>
@import './index.less';
</style>