cm-wisdom-cube/frontend/src/views/MainPage.vue
2025-03-14 16:57:26 +08:00

286 lines
7.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>