cm-wisdom-cube/frontend/src/views/MainPage.vue

286 lines
7.8 KiB
Vue
Raw Normal View History

2025-03-14 16:57:26 +08:00
<script setup>
import {NSpace, NButton, NModal, NInput, NSelect, useMessage, NSpin, NPopconfirm} from 'naive-ui'
import {onMounted, ref} from "vue";
import {useRouter} from 'vue-router';
import DeveloperList from "../components/developer/DeveloperList.vue";
import ProjectList from "../components/project/ProjectList.vue";
import RequirementList from "../components/requirement/RequirementList.vue";
import {errorHandler, request} from "../utils/request.js";
import {marked} from "marked";
const message = useMessage();
const router = useRouter();
const systemTitle = ref(import.meta.env.VITE_SYSTEM_TITLE)
const systemCopyright = ref(import.meta.env.VITE_SYSTEM_COPYRIGHT)
const showDeveloperListModal = ref(false)
const showProjectListModal = ref(false)
const showRequirementListModal = ref(false)
const mainContentRef = ref(null)
const promptTextareaHeight = ref('100px')
const responseChatContentHeight = ref('100px')
const prompt = ref(null)
const requirement_id = ref(null)
const requirementOptions = ref([])
// 是否对话中
const isChatting = ref(false)
// 是否对话结束
const isChatDone = ref(true)
const chatResponse = ref(``)
const listRequirement = () => {
request.get('/requirement/list').then(res => {
requirementOptions.value = res.data.map(requirement => {
return {
label: requirement.title,
value: requirement.id.toString()
}
})
}).catch(error => {
errorHandler(error, message, router)
})
}
onMounted(() => {
setTimeout(() => {
const mainContentHeight = parseInt(mainContentRef.value.getBoundingClientRect().height)
promptTextareaHeight.value = (mainContentHeight - 150) + 'px'
responseChatContentHeight.value = (mainContentHeight - 100) + 'px'
}, 500)
listRequirement();
})
/**
* 提交内容
*/
const onChatSubmit = () => {
isChatting.value = true
isChatDone.value = false
request.post('/chat/work-score', {
prompt: prompt.value,
requirement_id: requirement_id.value
}).then(res => {
chatResponse.value = res.data.data
}).catch(error => {
errorHandler(error, message, router)
}).finally(() => {
isChatDone.value = true
})
}
const logout = () => {
sessionStorage.removeItem('access_token');
router.replace('/login')
}
</script>
<template>
<div class="main-layout">
<header class="main-header">
<div class="logo">{{systemTitle}}</div>
<div class="header-actions">
<n-space>
<n-button style="background-color: #FFF" @click="showDeveloperListModal = true">
<span>研发管理</span>
</n-button>
<n-button type="primary" @click="showProjectListModal = true">
<span>项目管理</span>
</n-button>
<n-button type="info" @click="showRequirementListModal = true">
<span>需求管理</span>
</n-button>
<n-popconfirm
positive-text="确认"
negative-text="取消"
@positive-click="logout"
>
<template #trigger>
<n-button strong secondary type="success" round>退出系统</n-button>
</template>
确认退出系统吗
</n-popconfirm>
</n-space>
</div>
</header>
<main class="main-content" ref="mainContentRef">
<div class="chat-container" v-show="!isChatting">
<div class="title">请输入需求相关代码</div>
<div class="chat">
<div class="prompt">
<n-input
v-model:value="prompt"
:show-count="true"
ref="promptTextareaRef"
type="textarea"
placeholder="请输入需求描述"
:style="{
height: promptTextareaHeight
}"
/>
</div>
</div>
<div class="actions">
<n-space align="center" style="width: 750px;">
选择需求
<n-select v-model:value="requirement_id"
:options="requirementOptions"
placeholder="请选择需求"
clearable
style="width: 200px"/>
</n-space>
<n-space>
<n-button type="primary"
circle
:disabled="!prompt && !requirement_id"
@click="onChatSubmit"
>
<i class="fas fa-arrow-up"></i>
</n-button>
</n-space>
</div>
</div>
<div class="chat-response" v-show="isChatting">
<div class="content markdown-content"
:style="{height: responseChatContentHeight}">
<div v-html="marked(chatResponse)"></div>
</div>
<div class="actions">
<n-space justify="space-between" align="center">
<n-space align="center" v-if="!isChatDone">
<n-spin size="small"/>
<span style="color: var(--success-color)">AI正在分析</span>
</n-space>
<n-space v-if="isChatDone"
style="color: var(--primary-color)">分析结束
</n-space>
<n-button type="primary"
circle
:disabled="!isChatDone"
@click="() => {
isChatting = false
chatResponse = ''
}"
>
<i class="fas fa-arrow-left"></i>
</n-button>
</n-space>
</div>
</div>
</main>
<footer class="main-footer">
<p>{{systemCopyright}}</p>
</footer>
<n-modal v-model:show="showDeveloperListModal"
preset="card"
:style="{width: '1000px', height: responseChatContentHeight}"
title="研发管理"
size="small"
:bordered="false">
<DeveloperList/>
</n-modal>
<n-modal v-model:show="showProjectListModal"
preset="card"
:style="{width: '1000px', height: responseChatContentHeight}"
title="项目管理"
size="small"
:bordered="false">
<ProjectList/>
</n-modal>
<n-modal v-model:show="showRequirementListModal"
preset="card"
:style="{width: '1000px', height: responseChatContentHeight}"
title="需求管理"
size="small"
:bordered="false"
@close="() => {
listRequirement()
}">
<RequirementList/>
</n-modal>
</div>
</template>
<style scoped>
.main-layout {
display: flex;
flex-direction: column;
height: 100vh;
.main-header {
flex-shrink: 0;
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background-color: #f5f5f5;
.logo {
font-size: 20px;
font-weight: bold;
color: var(--primary-color)
}
}
.main-content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
.chat-container {
padding: 15px;
border-radius: 10px;
border: 1px solid var(--border-color);
.title {
font-size: 20px;
text-align: center;
}
.chat {
margin-top: 10px;
width: 800px;
}
.actions {
margin-top: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.chat-response {
width: 800px;
padding: 15px;
border-radius: 10px;
border: 1px solid var(--border-color);
.content {
overflow: auto;
table {
background-color: black;
}
}
}
.actions {
margin-top: 15px;
}
}
.main-footer {
flex-shrink: 0;
height: 30px;
line-height: 30px;
background-color: #f5f5f5;
text-align: center;
}
}
</style>