可信代码库-可信开源代码库AI助手首页开发完成
This commit is contained in:
64
src/views/Jyh/AI/Home/AIinout.vue
Normal file
64
src/views/Jyh/AI/Home/AIinout.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<McInput :value="inputValue" :loading="loading" @submit="onSubmit">
|
||||
<template #head>
|
||||
<div class="appendix-wrap">
|
||||
<div class="appendix-item">
|
||||
<span>README.md</span>
|
||||
<i class="icon-code-editor-close"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #extra>
|
||||
<div class="input-foot-left">
|
||||
<span><i class="icon-at"></i>智能体</span>
|
||||
<span><i class="icon-appendix"></i>附件</span>
|
||||
</div>
|
||||
</template>
|
||||
</McInput>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { McInput } from '@matechat/core';
|
||||
|
||||
const inputValue = ref('');
|
||||
const loading = ref(false);
|
||||
|
||||
const onSubmit = (e) => {
|
||||
loading.value = true;
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 1000);
|
||||
console.log('input submit---', e);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.input-foot-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: var(--devui-font-size-sm);
|
||||
color: var(--devui-text);
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.appendix-wrap {
|
||||
display: flex;
|
||||
padding: 4px 8px;
|
||||
|
||||
.appendix-item {
|
||||
padding: 4px;
|
||||
border-radius: var(--devui-border-radius);
|
||||
background-color: var(--devui-area);
|
||||
|
||||
i {
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
103
src/views/Jyh/AI/Home/GuessYouWantToAsk.vue
Normal file
103
src/views/Jyh/AI/Home/GuessYouWantToAsk.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<div class="guess-you-want-to-ask-card">
|
||||
<div class="card-title">
|
||||
<img src="@/assets/imgs/jyh/ai/icon_cnxw.png" style="width: 20px;height: 20px;margin-right: 8px"></img>
|
||||
<span>猜你想问</span>
|
||||
<d-button @click="changeQuestions" class="jyh-button1" variant="solid">
|
||||
<div class="flex flex-center">
|
||||
<img style="height: 15px;margin-right: 8px" width="16" src="@/assets/imgs/jyh/ai/icon_reflush.png" />
|
||||
<span>换一批</span>
|
||||
</div>
|
||||
</d-button>
|
||||
</div>
|
||||
<div class="card-description">
|
||||
<button v-for="(question, index) in questions" :key="index" class="question-button">
|
||||
{{ question }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
// 假设的图标 URL,你可以根据实际情况修改
|
||||
const iconUrl = 'https://example.com/icon.png';
|
||||
|
||||
// 初始化问题列表
|
||||
const questions = ref([
|
||||
'列出热门开源软件',
|
||||
'开源软件',
|
||||
'未通过校验列表',
|
||||
'通过校验列表',
|
||||
'可使用、未治理和有风险的软件有哪些',
|
||||
'危险和严重的个人预警通知',
|
||||
'我的订阅列表'
|
||||
]);
|
||||
|
||||
// 换一批问题的函数
|
||||
const changeQuestions = () => {
|
||||
// 这里可以实现从后端获取新问题列表的逻辑
|
||||
// 示例中简单地更新问题列表
|
||||
questions.value = [
|
||||
'热门数据库软件有哪些',
|
||||
'数据库软件的选型',
|
||||
'代码漏洞检测方法',
|
||||
'性能优化策略'
|
||||
];
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.guess-you-want-to-ask-card {
|
||||
border-radius: 24px;
|
||||
background: #FFFFFF;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #191919;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.card-title i {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.card-description {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.question-button {
|
||||
border: none;
|
||||
border-radius: 35px;
|
||||
background: #F3F3F3;
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.question-button:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.jyh-button1 {
|
||||
margin-left: auto;
|
||||
}
|
||||
</style>
|
||||
139
src/views/Jyh/AI/Home/SwiperComponent.vue
Normal file
139
src/views/Jyh/AI/Home/SwiperComponent.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<div>
|
||||
<div ref="mySwiper" class="swiper" id="swiper">
|
||||
<!-- Slides -->
|
||||
<div class="swiper-wrapper">
|
||||
<div style="padding: 20px 6px" class="swiper-slide" v-for="item in slideData" :key="item.id">
|
||||
<div class="ach-item bg-f" @click="onSelectItem(item)">
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
<img :src="item.icon" style="width: 20px;height: 20px;margin-right: 8px"></img>
|
||||
<span >{{ item.title }}</span>
|
||||
</div>
|
||||
<div class="card-description">{{ item.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Navigation buttons -->
|
||||
<div class="swiper-button-prev"></div>
|
||||
<div class="swiper-button-next"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import Swiper from 'swiper';
|
||||
import { Navigation, Autoplay } from 'swiper/modules';
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
import icon_hot from '@/assets/imgs/jyh/ai/icon_hot.png';
|
||||
import icon_yj from '@/assets/imgs/jyh/ai/icon_yj.png';
|
||||
import icon_jh from '@/assets/imgs/jyh/ai/icon_jh.png';
|
||||
|
||||
const mySwiper = ref(null);
|
||||
const slideData = [
|
||||
{ id: 1, title: '热门开源软件', description: '列出热门开源软件',icon:icon_hot },
|
||||
{ id: 2, title: '预警公告', description: '列出最近预警公告',icon:icon_yj },
|
||||
{ id: 3, title: '你可以帮我做什么', description: '了解当前AI助手可以帮忙干什么',icon:icon_jh }
|
||||
];
|
||||
|
||||
const onSelectItem = (item) => {
|
||||
console.log('Selected item:', item);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
new Swiper(mySwiper.value, {
|
||||
// Swiper选项
|
||||
observer: true,
|
||||
observeParents: true,
|
||||
modules: [Navigation, Autoplay],
|
||||
slidesPerView: 3,
|
||||
spaceBetween: 20,
|
||||
autoplay: {
|
||||
delay: 2500,
|
||||
disableOnInteraction: false
|
||||
},
|
||||
navigation: {
|
||||
nextEl: '.swiper-button-next',
|
||||
prevEl: '.swiper-button-prev'
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.swiper {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 24px;
|
||||
background: #FFFFFF;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #191919;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0px;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
|
||||
.card-title i {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.card-description {
|
||||
margin-left: 28px;
|
||||
margin-top: 4px;
|
||||
color: #595959;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: regular;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0px;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
|
||||
.swiper-button-prev {
|
||||
left: -18px;
|
||||
}
|
||||
.swiper-button-next {
|
||||
right: -18px;
|
||||
}
|
||||
|
||||
.swiper-button-prev, .swiper-button-next {
|
||||
top: 55%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: inline-flex;
|
||||
padding: 12px;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
border-radius: 100px;
|
||||
border: 2px solid #FFF;
|
||||
background: rgba(255, 255, 255, 0.50);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.swiper-button-prev:after, .swiper-button-next:after {
|
||||
color: #4E5969;
|
||||
font-family: swiper-icons;
|
||||
font-size: 16px;
|
||||
text-transform: none !important;
|
||||
letter-spacing: 0;
|
||||
font-variant: initial;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
||||
507
src/views/Jyh/AI/Home/index.vue
Normal file
507
src/views/Jyh/AI/Home/index.vue
Normal file
@@ -0,0 +1,507 @@
|
||||
<template>
|
||||
<div class="home-container">
|
||||
<div class="home-content">
|
||||
<div v-if="startChat" ref="conversationRef" class="conversation-area">
|
||||
<template v-for="(msg, idx) in messages" :key="idx">
|
||||
<McBubble v-if="msg.from === 'user'" :content="msg.content" :align="'right'" :avatarConfig="msg.avatarConfig"></McBubble>
|
||||
<McBubble v-else :loading="msg.loading ?? false" :avatarConfig="msg.avatarConfig">
|
||||
<McMarkdownCard :content="msg.content" :theme="theme"></McMarkdownCard>
|
||||
<template #bottom>
|
||||
<div class="bubble-bottom-operations">
|
||||
<i class="icon-copy-new"></i>
|
||||
<i class="icon-like"></i>
|
||||
<i class="icon-dislike"></i>
|
||||
</div>
|
||||
</template>
|
||||
</McBubble>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else class="welcome-page">
|
||||
<div class="home-title">
|
||||
<img src="@/assets/imgs/jyh/ai/aiLogo2.png" alt="logo" />
|
||||
<h1>可信开源代码库AI助手</h1>
|
||||
</div>
|
||||
<div class="home-detail">
|
||||
<div class="home-detail-1">Hi,欢迎使用可信开源代码库AI助手</div>
|
||||
<div class="home-detail-2">可信开源代码库AI助手 可以辅助研发人员进行软件查询、批量校验、查看软件详情等。</div>
|
||||
<div class="home-detail-2">作为AI模型,可信开源代码库AI助手 提供的答案可能不总是确定或准确的,但您的反馈可以帮助 可信开源代码库AI助手 做得更好。</div>
|
||||
</div>
|
||||
<div style="width: 100%;margin-top: -20px">
|
||||
<SwiperComponent />
|
||||
</div>
|
||||
<!--猜你想问-->
|
||||
<div style="width: 100%;margin-top: -20px">
|
||||
<GuessYouWantToAsk />
|
||||
</div>
|
||||
</div>
|
||||
<!--操作按钮-->
|
||||
<div class="new-convo-button">
|
||||
<McPrompt
|
||||
v-if="startChat"
|
||||
class="simple-prompt"
|
||||
style="flex: 1"
|
||||
:list="simplePrompt"
|
||||
:direction="'horizontal'"
|
||||
@itemClick="onItemClick($event)"
|
||||
></McPrompt>
|
||||
<div v-else class="agent-knowledge">
|
||||
<d-dropdown :position="['top']" @toggle="(val) => (isAgentOpen = val)">
|
||||
<div class="agent-wrapper">
|
||||
<img src="@/assets/imgs/jyh/ai/aiLogo2.png" />
|
||||
<span>{{ selectedAgent.label }}</span>
|
||||
<i class="icon-infrastructure"></i>
|
||||
<i :class="['icon-chevron-down-2', { 'is-open': isAgentOpen }]"></i>
|
||||
</div>
|
||||
<template #menu>
|
||||
<McList :data="agentList" @select="(val) => (selectedAgent = val)"></McList>
|
||||
</template>
|
||||
</d-dropdown>
|
||||
<span class="agent-knowledge-dividing-line"></span>
|
||||
<div class="knowledge-wrapper">
|
||||
<i class="icon-operation-log"></i>
|
||||
<span>添加知识</span>
|
||||
</div>
|
||||
</div>
|
||||
<d-button icon="add" shape="circle" title="新建对话" size="sm" @click="onNewConvo" />
|
||||
</div>
|
||||
<!--输入框-->
|
||||
<div style="padding: 0 12px 12px 12px;width: 100%">
|
||||
<McInput :placeholder="placeholder" :value="inputValue" :maxLength="maxLength" @change="(e) => (inputValue = e)" @submit="onSubmit">
|
||||
<template #extra>
|
||||
<div class="input-foot-wrapper">
|
||||
<div class="input-foot-left">
|
||||
<span v-for="(item, index) in inputFootIcons" :key="index" @click="() => onInputIconClick(item)">
|
||||
<i :class="item.icon"></i>
|
||||
{{ item.text }}
|
||||
</span>
|
||||
<span class="input-foot-dividing-line"></span>
|
||||
<span class="input-foot-maxlength">{{ inputValue.length }}/{{maxLength}}</span>
|
||||
</div>
|
||||
<div class="input-foot-right">
|
||||
<d-button icon="op-clearup" shape="round" :disabled="!inputValue" @click="inputValue = ''">清空输入</d-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</McInput>
|
||||
</div>
|
||||
|
||||
<!-- 添加使用条款部分 -->
|
||||
<div class="usage-terms">
|
||||
<p>内容由AI生成,无法确保准确性和完整性,仅供参考:使用条款 隐私声明</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineComponent, nextTick, onMounted } from 'vue';
|
||||
import { introPrompt, simplePrompt, mockAnswer, guessQuestions } from './mock.constants';
|
||||
import SwiperComponent from './SwiperComponent.vue';
|
||||
import GuessYouWantToAsk from './GuessYouWantToAsk.vue';
|
||||
|
||||
const inputValue = ref('');
|
||||
const startChat = ref(false);
|
||||
const conversationRef = ref();
|
||||
const isAgentOpen = ref(false);
|
||||
const theme = ref('light');
|
||||
const maxLength = ref(8000);
|
||||
const placeholder = ref('请输入问题描述,描述越详细 DevMate 回复越准确( Enter发送,Shift+Enter 换行,↑ 查看最近发出的消息 )');
|
||||
let themeService;
|
||||
const agentList = ref([
|
||||
{ label: 'MateChat', value: 'matechat', active: true },
|
||||
{ label: 'InsCode', value: 'inscode' },
|
||||
]);
|
||||
const selectedAgent = ref(agentList.value[0]);
|
||||
const aiModelAvatar = {
|
||||
imgSrc: 'https://matechat.gitcode.com/logo.svg',
|
||||
width: 32,
|
||||
height: 32,
|
||||
};
|
||||
const customerAvatar = {
|
||||
imgSrc: 'https://matechat.gitcode.com/png/demo/userAvatar.svg',
|
||||
width: 32,
|
||||
height: 32,
|
||||
};
|
||||
const inputFootIcons = [
|
||||
{ icon: 'icon-at', text: '智能体' },
|
||||
{ icon: 'icon-standard', text: '词库' },
|
||||
{ icon: 'icon-add', text: '附件' },
|
||||
];
|
||||
|
||||
const messages = ref([]);
|
||||
|
||||
const onInputIconClick = (e) => {
|
||||
if (e.icon === 'icon-at') {
|
||||
inputValue.value += `@${selectedAgent.value.label}`;
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = (e, answer = undefined) => {
|
||||
if(e === '') {
|
||||
return;
|
||||
}
|
||||
inputValue.value = '';
|
||||
if (!messages.value.length) {
|
||||
startChat.value = true;
|
||||
}
|
||||
messages.value.push({
|
||||
from: 'user',
|
||||
content: e,
|
||||
avatarPosition: 'side-right',
|
||||
avatarConfig: { ...customerAvatar },
|
||||
});
|
||||
nextTick(() => {
|
||||
conversationRef.value?.scrollTo({
|
||||
top: conversationRef.value.scrollHeight,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
});
|
||||
getAIAnswer(answer ?? e);
|
||||
};
|
||||
|
||||
const getAIAnswer = (content) => {
|
||||
messages.value.push({
|
||||
from: 'ai-model',
|
||||
content: '',
|
||||
avatarPosition: 'side-left',
|
||||
avatarConfig: { ...aiModelAvatar },
|
||||
loading: true,
|
||||
});
|
||||
|
||||
/* 模拟流式数据返回 */
|
||||
setTimeout(async () => {
|
||||
messages.value.at(-1).loading = false;
|
||||
for (let i = 0; i < content.length;) {
|
||||
await new Promise(r => setTimeout(r, 300 * Math.random()));
|
||||
messages.value[messages.value.length - 1].content = content.slice(0, i += Math.random() * 10);
|
||||
nextTick(() => {
|
||||
conversationRef.value?.scrollTo({
|
||||
top: conversationRef.value.scrollHeight
|
||||
});
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const onNewConvo = () => {
|
||||
startChat.value = false;
|
||||
messages.value = [];
|
||||
};
|
||||
|
||||
const onItemClick = (item) => {
|
||||
if (mockAnswer[item.value]) {
|
||||
// 使用 mock 数据
|
||||
onSubmit(item.label, mockAnswer[item.value]);
|
||||
}
|
||||
};
|
||||
|
||||
const themeChange = () => {
|
||||
if (themeService) {
|
||||
theme.value = themeService.currentTheme.id === 'infinity-theme' ? 'light' : 'dark';
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if(typeof window !== 'undefined'){
|
||||
themeService = window['devuiThemeService'];
|
||||
}
|
||||
themeChange();
|
||||
if (themeService && themeService.eventBus) {
|
||||
themeService.eventBus.add('themeChanged', themeChange);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.home-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.home-content {
|
||||
font-size: 14px;
|
||||
padding-top: 3%;
|
||||
padding-bottom: 1%;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-self: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
|
||||
.home-title {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
h1 {
|
||||
color: #191919;
|
||||
font-family: Huawei Sans;
|
||||
font-weight: bold;
|
||||
font-size: 36px;
|
||||
line-height: 48px;
|
||||
letter-spacing: 0px;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
img {
|
||||
width: 86px;
|
||||
//filter: brightness(0);
|
||||
}
|
||||
}
|
||||
|
||||
.home-detail {
|
||||
.home-detail-1 {
|
||||
color: #191919;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: medium;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
letter-spacing: 0px;
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.home-detail-2 {
|
||||
color: #777777;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: regular;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0px;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.conversation-area,
|
||||
.welcome-page {
|
||||
height: 90%;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
//overflow: auto;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.conversation-area {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.welcome-page {
|
||||
gap: 24px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.guess-question {
|
||||
width: 100%;
|
||||
padding: 16px 12px;
|
||||
border-radius: var(--devui-border-radius-card);
|
||||
background-color: var(--devui-gray-form-control-bg);
|
||||
|
||||
.guess-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: var(--devui-text);
|
||||
margin-bottom: 12px;
|
||||
|
||||
& > div:first-child {
|
||||
font-weight: 700;
|
||||
font-size: var(--devui-font-size);
|
||||
}
|
||||
& > div:last-child {
|
||||
font-size: var(--devui-font-size-sm);
|
||||
cursor: pointer;
|
||||
span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.guess-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
span {
|
||||
font-size: var(--devui-font-size-sm);
|
||||
color: var(--devui-text);
|
||||
padding: 4px 12px;
|
||||
border-radius: var(--devui-border-radius-full);
|
||||
background-color: var(--devui-gray-form-control-hover-bg);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bubble-bottom-operations {
|
||||
margin-top: 8px;
|
||||
i {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--devui-icon-hover-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.new-convo-button {
|
||||
width: 100%;
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
height: 39px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
:deep(.simple-prompt .mc-list) {
|
||||
justify-content: unset;
|
||||
}
|
||||
|
||||
:deep(.intro-prompt .mc-list) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.operations {
|
||||
i {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--devui-global-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.agent-knowledge {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.agent-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: var(--devui-border-radius-full);
|
||||
background-color: var(--devui-area);
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: var(--devui-font-size);
|
||||
color: var(--devui-text);
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: var(--devui-font-size);
|
||||
color: var(--devui-text);
|
||||
transition: transform 0.3s ease-in-out;
|
||||
|
||||
&:last-child {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.is-open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.agent-knowledge-dividing-line {
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
margin: 0 12px;
|
||||
background-color: var(--devui-line);
|
||||
}
|
||||
|
||||
.knowledge-wrapper {
|
||||
font-size: var(--devui-font-size);
|
||||
color: var(--devui-text);
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-foot-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-right: 8px;
|
||||
|
||||
.input-foot-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
span {
|
||||
font-size: var(--devui-font-size-sm);
|
||||
color: var(--devui-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.input-foot-dividing-line {
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
background-color: var(--devui-line);
|
||||
}
|
||||
|
||||
.input-foot-maxlength {
|
||||
font-size: var(--devui-font-size-sm);
|
||||
color: var(--devui-aide-text);
|
||||
}
|
||||
}
|
||||
|
||||
.input-foot-right {
|
||||
& > *:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.mc-input) {
|
||||
background: #ffffff;
|
||||
.mc-textarea {
|
||||
height: 100px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.usage-terms {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
color: #AEAEAE;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: regular;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
letter-spacing: 0px;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
</style>
|
||||
422
src/views/Jyh/AI/Home/index2.vue
Normal file
422
src/views/Jyh/AI/Home/index2.vue
Normal file
@@ -0,0 +1,422 @@
|
||||
<template>
|
||||
<div class="demo-test">
|
||||
<McHeader :logoImg="'@/assets/imgs/jyh/ai/aiLogo2.png'" :title="'MateChat'">
|
||||
<template #operationArea>
|
||||
<div class="operations">
|
||||
<i class="icon-helping"></i>
|
||||
</div>
|
||||
</template>
|
||||
</McHeader>
|
||||
<div v-if="startChat" ref="conversationRef" class="conversation-area">
|
||||
<template v-for="(msg, idx) in messages" :key="idx">
|
||||
<McBubble v-if="msg.from === 'user'" :content="msg.content" :align="'right'" :avatarConfig="msg.avatarConfig"></McBubble>
|
||||
<McBubble v-else :loading="msg.loading ?? false" :avatarConfig="msg.avatarConfig">
|
||||
<McMarkdownCard :content="msg.content" :theme="theme"></McMarkdownCard>
|
||||
<template #bottom>
|
||||
<div class="bubble-bottom-operations">
|
||||
<i class="icon-copy-new"></i>
|
||||
<i class="icon-like"></i>
|
||||
<i class="icon-dislike"></i>
|
||||
</div>
|
||||
</template>
|
||||
</McBubble>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else class="welcome-page">
|
||||
<McIntroduction
|
||||
logo-img="/logo2x.svg"
|
||||
title="MateChat"
|
||||
sub-title="Hi,欢迎使用 MateChat"
|
||||
:description="[
|
||||
'MateChat 可以辅助研发人员编码、查询知识和相关作业信息、编写文档等。',
|
||||
'作为AI模型,MateChat 提供的答案可能不总是确定或准确的,但您的反馈可以帮助 MateChat 做的更好。',
|
||||
]"
|
||||
></McIntroduction>
|
||||
<McPrompt :list="introPrompt.list" :direction="'horizontal'" class="intro-prompt" @itemClick="onItemClick($event)"></McPrompt>
|
||||
<div class="guess-question">
|
||||
<div class="guess-title">
|
||||
<div>猜你想问</div>
|
||||
<div>
|
||||
<i class="icon-recover"></i>
|
||||
<span>换一批</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="guess-content">
|
||||
<span v-for="(item, index) in guessQuestions" :key="index" @click="onItemClick(item)">{{ item.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="new-convo-button">
|
||||
<McPrompt
|
||||
v-if="startChat"
|
||||
class="simple-prompt"
|
||||
style="flex: 1"
|
||||
:list="simplePrompt"
|
||||
:direction="'horizontal'"
|
||||
@itemClick="onItemClick($event)"
|
||||
></McPrompt>
|
||||
<div v-else class="agent-knowledge">
|
||||
<d-dropdown :position="['top']" @toggle="(val) => (isAgentOpen = val)">
|
||||
<div class="agent-wrapper">
|
||||
<img src="@/assets/imgs/jyh/ai/aiLogo2.png" />
|
||||
<span>{{ selectedAgent.label }}</span>
|
||||
<i class="icon-infrastructure"></i>
|
||||
<i :class="['icon-chevron-down-2', { 'is-open': isAgentOpen }]"></i>
|
||||
</div>
|
||||
<template #menu>
|
||||
<McList :data="agentList" @select="(val) => (selectedAgent = val)"></McList>
|
||||
</template>
|
||||
</d-dropdown>
|
||||
<span class="agent-knowledge-dividing-line"></span>
|
||||
<div class="knowledge-wrapper">
|
||||
<i class="icon-operation-log"></i>
|
||||
<span>添加知识</span>
|
||||
</div>
|
||||
</div>
|
||||
<d-button icon="add" shape="circle" title="新建对话" size="sm" @click="onNewConvo" />
|
||||
</div>
|
||||
<div style="padding: 0 12px 12px 12px">
|
||||
<McInput :value="inputValue" :maxLength="2000" @change="(e) => (inputValue = e)" @submit="onSubmit">
|
||||
<template #extra>
|
||||
<div class="input-foot-wrapper">
|
||||
<div class="input-foot-left">
|
||||
<span v-for="(item, index) in inputFootIcons" :key="index" @click="() => onInputIconClick(item)">
|
||||
<i :class="item.icon"></i>
|
||||
{{ item.text }}
|
||||
</span>
|
||||
<span class="input-foot-dividing-line"></span>
|
||||
<span class="input-foot-maxlength">{{ inputValue.length }}/2000</span>
|
||||
</div>
|
||||
<div class="input-foot-right">
|
||||
<d-button icon="op-clearup" shape="round" :disabled="!inputValue" @click="inputValue = ''">清空输入</d-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</McInput>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineComponent, nextTick, onMounted } from 'vue';
|
||||
import { introPrompt, simplePrompt, mockAnswer, guessQuestions } from './mock.constants';
|
||||
|
||||
const inputValue = ref('');
|
||||
const startChat = ref(false);
|
||||
const conversationRef = ref();
|
||||
const isAgentOpen = ref(false);
|
||||
const theme = ref('light');
|
||||
let themeService;
|
||||
const agentList = ref([
|
||||
{ label: 'MateChat', value: 'matechat', active: true },
|
||||
{ label: 'InsCode', value: 'inscode' },
|
||||
]);
|
||||
const selectedAgent = ref(agentList.value[0]);
|
||||
const aiModelAvatar = {
|
||||
imgSrc: 'https://matechat.gitcode.com/logo.svg',
|
||||
width: 32,
|
||||
height: 32,
|
||||
};
|
||||
const customerAvatar = {
|
||||
imgSrc: 'https://matechat.gitcode.com/png/demo/userAvatar.svg',
|
||||
width: 32,
|
||||
height: 32,
|
||||
};
|
||||
const inputFootIcons = [
|
||||
{ icon: 'icon-at', text: '智能体' },
|
||||
{ icon: 'icon-standard', text: '词库' },
|
||||
{ icon: 'icon-add', text: '附件' },
|
||||
];
|
||||
|
||||
const messages = ref([]);
|
||||
|
||||
const onInputIconClick = (e) => {
|
||||
if (e.icon === 'icon-at') {
|
||||
inputValue.value += `@${selectedAgent.value.label}`;
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = (e, answer = undefined) => {
|
||||
if(e === '') {
|
||||
return;
|
||||
}
|
||||
inputValue.value = '';
|
||||
if (!messages.value.length) {
|
||||
startChat.value = true;
|
||||
}
|
||||
messages.value.push({
|
||||
from: 'user',
|
||||
content: e,
|
||||
avatarPosition: 'side-right',
|
||||
avatarConfig: { ...customerAvatar },
|
||||
});
|
||||
nextTick(() => {
|
||||
conversationRef.value?.scrollTo({
|
||||
top: conversationRef.value.scrollHeight,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
});
|
||||
getAIAnswer(answer ?? e);
|
||||
};
|
||||
|
||||
const getAIAnswer = (content) => {
|
||||
messages.value.push({
|
||||
from: 'ai-model',
|
||||
content: '',
|
||||
avatarPosition: 'side-left',
|
||||
avatarConfig: { ...aiModelAvatar },
|
||||
loading: true,
|
||||
});
|
||||
|
||||
/* 模拟流式数据返回 */
|
||||
setTimeout(async () => {
|
||||
messages.value.at(-1).loading = false;
|
||||
for (let i = 0; i < content.length;) {
|
||||
await new Promise(r => setTimeout(r, 300 * Math.random()));
|
||||
messages.value[messages.value.length - 1].content = content.slice(0, i += Math.random() * 10);
|
||||
nextTick(() => {
|
||||
conversationRef.value?.scrollTo({
|
||||
top: conversationRef.value.scrollHeight
|
||||
});
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const onNewConvo = () => {
|
||||
startChat.value = false;
|
||||
messages.value = [];
|
||||
};
|
||||
|
||||
const onItemClick = (item) => {
|
||||
if (mockAnswer[item.value]) {
|
||||
// 使用 mock 数据
|
||||
onSubmit(item.label, mockAnswer[item.value]);
|
||||
}
|
||||
};
|
||||
|
||||
const themeChange = () => {
|
||||
if (themeService) {
|
||||
theme.value = themeService.currentTheme.id === 'infinity-theme' ? 'light' : 'dark';
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if(typeof window !== 'undefined'){
|
||||
themeService = window['devuiThemeService'];
|
||||
}
|
||||
themeChange();
|
||||
if (themeService && themeService.eventBus) {
|
||||
themeService.eventBus.add('themeChanged', themeChange);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.demo-test {
|
||||
width: 100%;
|
||||
min-width: 500px;
|
||||
height: calc(100vh - 180px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.conversation-area,
|
||||
.welcome-page {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.conversation-area {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.welcome-page {
|
||||
gap: 24px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.guess-question {
|
||||
width: 100%;
|
||||
padding: 16px 12px;
|
||||
border-radius: var(--devui-border-radius-card);
|
||||
background-color: var(--devui-gray-form-control-bg);
|
||||
|
||||
.guess-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: var(--devui-text);
|
||||
margin-bottom: 12px;
|
||||
|
||||
& > div:first-child {
|
||||
font-weight: 700;
|
||||
font-size: var(--devui-font-size);
|
||||
}
|
||||
& > div:last-child {
|
||||
font-size: var(--devui-font-size-sm);
|
||||
cursor: pointer;
|
||||
span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.guess-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
span {
|
||||
font-size: var(--devui-font-size-sm);
|
||||
color: var(--devui-text);
|
||||
padding: 4px 12px;
|
||||
border-radius: var(--devui-border-radius-full);
|
||||
background-color: var(--devui-gray-form-control-hover-bg);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bubble-bottom-operations {
|
||||
margin-top: 8px;
|
||||
i {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--devui-icon-hover-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.new-convo-button {
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
height: 39px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
:deep(.simple-prompt .mc-list) {
|
||||
justify-content: unset;
|
||||
}
|
||||
|
||||
:deep(.intro-prompt .mc-list) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.operations {
|
||||
i {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--devui-global-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.agent-knowledge {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.agent-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: var(--devui-border-radius-full);
|
||||
background-color: var(--devui-area);
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: var(--devui-font-size);
|
||||
color: var(--devui-text);
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: var(--devui-font-size);
|
||||
color: var(--devui-text);
|
||||
transition: transform 0.3s ease-in-out;
|
||||
|
||||
&:last-child {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.is-open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.agent-knowledge-dividing-line {
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
margin: 0 12px;
|
||||
background-color: var(--devui-line);
|
||||
}
|
||||
|
||||
.knowledge-wrapper {
|
||||
font-size: var(--devui-font-size);
|
||||
color: var(--devui-text);
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-foot-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-right: 8px;
|
||||
|
||||
.input-foot-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
span {
|
||||
font-size: var(--devui-font-size-sm);
|
||||
color: var(--devui-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.input-foot-dividing-line {
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
background-color: var(--devui-line);
|
||||
}
|
||||
|
||||
.input-foot-maxlength {
|
||||
font-size: var(--devui-font-size-sm);
|
||||
color: var(--devui-aide-text);
|
||||
}
|
||||
}
|
||||
|
||||
.input-foot-right {
|
||||
& > *:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
473
src/views/Jyh/AI/Home/indexOld.vue
Normal file
473
src/views/Jyh/AI/Home/indexOld.vue
Normal file
@@ -0,0 +1,473 @@
|
||||
<template>
|
||||
<div class="home-container">
|
||||
<div class="home-content">
|
||||
<div class="home-title">
|
||||
<img src="@/assets/imgs/jyh/ai/aiLogo2.png" alt="logo" />
|
||||
<h1>可信开源代码库AI助手</h1>
|
||||
</div>
|
||||
<div class="home-detail">
|
||||
<div class="home-detail-1">Hi,欢迎使用可信开源代码库AI助手</div>
|
||||
<div class="home-detail-2">可信开源代码库AI助手 可以辅助研发人员进行软件查询、批量校验、查看软件详情等。</div>
|
||||
<div class="home-detail-2">作为AI模型,可信开源代码库AI助手 提供的答案可能不总是确定或准确的,但您的反馈可以帮助 可信开源代码库AI助手 做得更好。</div>
|
||||
</div>
|
||||
<!--swiper-->
|
||||
<div style="width: 100%;">
|
||||
<SwiperComponent />
|
||||
</div>
|
||||
<!--猜你想问-->
|
||||
<div style="width: 100%;margin-top: -20px">
|
||||
<GuessYouWantToAsk />
|
||||
</div>
|
||||
<!--AI大模型输入框-->
|
||||
<div style="width: 100%;">
|
||||
<AIinout />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<d-modal class="warning-modal" v-model="warningModalVisable" title="" style="width: 600px">
|
||||
<EarlyWarningDetail :warningData="currentWarning" :type="'user'"></EarlyWarningDetail>
|
||||
</d-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount, computed } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useAccount } from '@/utils/hooks/useAccount';
|
||||
import AdvanceSearch from '@/components/AdvanceSearch/index.vue';
|
||||
import { getHomeNoticeList } from '@/api/jyh';
|
||||
import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue';
|
||||
import { useGlobalInfoStore } from '@/stores/Global';
|
||||
const { updateHeaderSearch } = useGlobalInfoStore();
|
||||
const { accountInfo } = useAccount();
|
||||
import { useDiscussGetUserInfo } from '@/api/discussion/hook';
|
||||
import SwiperComponent from './SwiperComponent.vue';
|
||||
import GuessYouWantToAsk from './GuessYouWantToAsk.vue';
|
||||
import AIinout from './AIinout.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const inputGlow = ref(false);
|
||||
const searchStr = ref('');
|
||||
const position = ref(['right-start', 'right-end']);
|
||||
const industryOptions = ref(['通信', '军工', '金融', '能源']);
|
||||
const searchType = ref('软件');
|
||||
const searchOptions = ref(['软件']);
|
||||
const offset = ref({ mainAxis: 7, crossAxis: -10 });
|
||||
const isKeepOpen = ref(true);
|
||||
const isOpen = ref(false);
|
||||
const cateRotate = ref(0);
|
||||
const infoList = ref([]);
|
||||
const warningModalVisable = ref(false);
|
||||
const currentWarning = ref();
|
||||
|
||||
const { isLogin } = useDiscussGetUserInfo();
|
||||
const homeSearch = ref(null);
|
||||
const dropdownWidth = ref(0);
|
||||
const tagMap = {
|
||||
critical: {
|
||||
text: '致命',
|
||||
color: '#c7000b'
|
||||
},
|
||||
high: {
|
||||
text: '高',
|
||||
color: '#f66f6a'
|
||||
},
|
||||
medium: {
|
||||
text: '中',
|
||||
color: '#fac20a'
|
||||
},
|
||||
low: {
|
||||
text: '低',
|
||||
color: '#5e7ce0'
|
||||
},
|
||||
Critical: {
|
||||
text: '致命',
|
||||
color: '#c7000b'
|
||||
},
|
||||
High: {
|
||||
text: '高',
|
||||
color: '#f66f6a'
|
||||
},
|
||||
Medium: {
|
||||
text: '中',
|
||||
color: '#fac20a'
|
||||
},
|
||||
Low: {
|
||||
text: '低',
|
||||
color: '#5e7ce0'
|
||||
}
|
||||
};
|
||||
|
||||
const rotate = computed(() => {
|
||||
return isOpen.value ? 180 : 0;
|
||||
});
|
||||
|
||||
const searchInput = ref(null);
|
||||
const openAdvancedSearch = () => {
|
||||
isOpen.value = !isOpen.value;
|
||||
inputGlow.value = isOpen.value;
|
||||
};
|
||||
|
||||
const check = () => {
|
||||
router.push({
|
||||
name: 'Search',
|
||||
query: { tab: 'BatchVerify' } // 通过查询参数指定 Tab
|
||||
});
|
||||
};
|
||||
|
||||
const closeOutside = () => {
|
||||
return false;
|
||||
};
|
||||
|
||||
const submit = (formData) => {
|
||||
isOpen.value = false;
|
||||
router.push({
|
||||
name: 'Search',
|
||||
query: {
|
||||
softwareName: searchStr.value ? searchStr.value : '',
|
||||
searchType: getIndustryValue(searchType.value),
|
||||
softwareVersion: formData.softwareVersion || '',
|
||||
programmingLanguage: formData.programmingLanguage || '',
|
||||
interestTag: formData.interestTag || '',
|
||||
industry: formData.industry || '',
|
||||
licenseName: formData.licenseName || '',
|
||||
dependentSoftware: formData.dependentSoftware || '',
|
||||
releaseDateStart: formData.dateRange && formData.dateRange.length > 0 ? formData.dateRange[0] : '',
|
||||
releaseDateEnd: formData.dateRange && formData.dateRange.length > 0 ? formData.dateRange[1] : ''
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const inputFocus = () => {
|
||||
inputGlow.value = true;
|
||||
};
|
||||
|
||||
const inputBlur = () => {
|
||||
inputGlow.value = false;
|
||||
};
|
||||
|
||||
const updateDropdownWidth = () => {
|
||||
if (homeSearch.value) {
|
||||
dropdownWidth.value = homeSearch.value.offsetWidth * 0.85;
|
||||
}
|
||||
};
|
||||
const globalInfo = useGlobalInfoStore();
|
||||
const industryList = globalInfo.industryList;
|
||||
const getIndustryValue = (name) => {
|
||||
const industry = industryList.find((item) => item.name === name);
|
||||
return industry ? industry.value : ''; // 如果找不到,返回默认值
|
||||
};
|
||||
|
||||
const search = () => {
|
||||
// updateHeaderSearch({ searchWord: searchStr.value, searchType: selectedCate.value });
|
||||
router.push({
|
||||
name: 'Search',
|
||||
query: {
|
||||
softwareName: searchStr.value ? searchStr.value : '',
|
||||
searchType: getIndustryValue(searchType.value)
|
||||
}
|
||||
});
|
||||
// window.open(`${import.meta.env.VITE_BASE_URL}repoList?softwareName=${searchStr.value ? searchStr.value : ''}&searchType=${getIndustryValue(searchType.value)}`, '_blank')
|
||||
};
|
||||
|
||||
const onCategoryChange = (event) => {
|
||||
searchType.value = event?.name || '软件';
|
||||
globalInfo.updateHeaderSearch({ softwareName: softwareName.value, searchType: event.value });
|
||||
};
|
||||
|
||||
const onCateToggle = (event) => {
|
||||
cateRotate.value = event ? 180 : 0;
|
||||
};
|
||||
|
||||
const checkMore = () => {
|
||||
router.push({ name: 'PersonalCenter' });
|
||||
};
|
||||
|
||||
const openWarningDetail = (event, index) => {
|
||||
infoList.value.forEach((item, i) => {
|
||||
if (i <= index) {
|
||||
item.dotColor = 'var(--devui-info)';
|
||||
} else {
|
||||
item.dotColor = '';
|
||||
}
|
||||
});
|
||||
|
||||
warningModalVisable.value = true;
|
||||
currentWarning.value = event;
|
||||
};
|
||||
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
|
||||
onMounted(() => {
|
||||
resizeObserver = new ResizeObserver(updateDropdownWidth);
|
||||
if (homeSearch.value) {
|
||||
resizeObserver.observe(homeSearch.value);
|
||||
}
|
||||
|
||||
updateDropdownWidth();
|
||||
|
||||
document.querySelector('body').onclick = (e) => {
|
||||
const className = e.target.className;
|
||||
if (
|
||||
!className.includes('close-isopen') &&
|
||||
!className.includes('devui-badge__content') &&
|
||||
!className.includes('advanced-search')
|
||||
) {
|
||||
isOpen.value = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (resizeObserver && homeSearch.value) {
|
||||
resizeObserver.unobserve(homeSearch.value);
|
||||
}
|
||||
});
|
||||
|
||||
const getNoticeList = async () => {
|
||||
const res: any = await getHomeNoticeList();
|
||||
if (!res.error) {
|
||||
infoList.value = res.data.data || [];
|
||||
}
|
||||
};
|
||||
|
||||
getNoticeList();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import 'devui-theme/styles-var/devui-var.scss';
|
||||
|
||||
.home-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.home-content {
|
||||
font-size: 14px;
|
||||
height: 80%;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-self: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
|
||||
.home-title {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
h1 {
|
||||
color: #191919;
|
||||
font-family: Huawei Sans;
|
||||
font-weight: bold;
|
||||
font-size: 48px;
|
||||
line-height: 48px;
|
||||
letter-spacing: 0px;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
img {
|
||||
width: 90px;
|
||||
//filter: brightness(0);
|
||||
}
|
||||
}
|
||||
|
||||
.home-search {
|
||||
width: 574px;
|
||||
height: 46px;
|
||||
border: 1px solid #dfe1e5;
|
||||
box-shadow: 0px 2px 8px 0px rgba(60, 64, 67, 0.25);
|
||||
border-radius: 24px;
|
||||
|
||||
//width: 100%;
|
||||
//height: 40px;
|
||||
flex-shrink: 0;
|
||||
background-color: white;
|
||||
//border-radius: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
//box-shadow: var(--devui-shadow, 0 2px 12px 0);
|
||||
input {
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.advanced-search {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background-color: var(--devui-form-control-line, #d7d8da);
|
||||
}
|
||||
}
|
||||
|
||||
.advanced-search-menu {
|
||||
height: 300px;
|
||||
padding: 12px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.form-operation {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.batch-btn {
|
||||
color: $devui-aide-text;
|
||||
width: 150px;
|
||||
flex-shrink: 0;
|
||||
background-color: #f0f0f0;
|
||||
border-color: $devui-aide-text;
|
||||
}
|
||||
|
||||
.home-information {
|
||||
width: 100%;
|
||||
background-color: #f0f0f0;
|
||||
//overflow: auto;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 10px;
|
||||
padding: 12px;
|
||||
|
||||
.info-title {
|
||||
img {
|
||||
width: 20px;
|
||||
}
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.sub-title {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
margin-bottom: 20px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
:deep(.devui-timeline-item-data-left) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.devui-timeline-item-dot) {
|
||||
scale: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.home-search {
|
||||
:deep(.devui-input-slot__prepend),
|
||||
:deep(.devui-input-slot__append),
|
||||
:deep(.devui-input__wrapper) {
|
||||
border: none;
|
||||
}
|
||||
|
||||
:deep(.devui-select__selection--glow-style),
|
||||
:deep(.devui-input--glow-style) {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.glow-border {
|
||||
border: 1px solid var(--devui-form-control-line, #d7d8da);
|
||||
border-color: var(--devui-form-control-line-active, #5e7ce0) !important;
|
||||
box-shadow: 0 0 0 4px var(--devui-form-control-interactive-outline, rgba(94, 124, 224, 0.08));
|
||||
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--devui-list-item-hover-bg, #f2f5fc);
|
||||
color: var(--devui-list-item-hover-text, #526ecc);
|
||||
}
|
||||
}
|
||||
|
||||
.list-menu {
|
||||
padding: 8px;
|
||||
margin: 0;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.notice-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
margin-right: 8px;
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.time-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 140px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
:deep(.devui-timeline-item-data-right) {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.home-detail {
|
||||
.home-detail-1 {
|
||||
color: #191919;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: medium;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
letter-spacing: 0px;
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.home-detail-2 {
|
||||
color: #777777;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: regular;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
letter-spacing: 0px;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
57
src/views/Jyh/AI/Home/mock.constants.js
Normal file
57
src/views/Jyh/AI/Home/mock.constants.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// mock.constants.js
|
||||
|
||||
export const introPrompt = {
|
||||
list: [
|
||||
{
|
||||
label: '如何使用 MateChat 辅助编码?',
|
||||
value: 'how_to_use_for_coding',
|
||||
},
|
||||
{
|
||||
label: 'MateChat 能查询哪些知识?',
|
||||
value: 'what_knowledge_can_query',
|
||||
},
|
||||
{
|
||||
label: '如何添加知识到 MateChat?',
|
||||
value: 'how_to_add_knowledge',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const simplePrompt = [
|
||||
{
|
||||
label: '快速查询代码示例',
|
||||
value: 'quick_code_example',
|
||||
},
|
||||
{
|
||||
label: '获取性能优化建议',
|
||||
value: 'performance_optimization',
|
||||
},
|
||||
{
|
||||
label: '辅助编写文档',
|
||||
value: 'write_document_assistance',
|
||||
},
|
||||
];
|
||||
|
||||
export const mockAnswer = {
|
||||
how_to_use_for_coding: 'MateChat 可以通过输入相关的代码需求,比如函数实现、算法逻辑等,它会为您提供代码示例和解释。您可以输入具体的代码功能描述,例如“编写一个冒泡排序算法”,MateChat 会给出相应的代码实现。',
|
||||
what_knowledge_can_query: 'MateChat 可以查询编程知识、算法、数据结构、编程语言特性、框架使用方法等。还可以查询作业相关的信息,例如任务进度、资源分配等。',
|
||||
how_to_add_knowledge: '要添加知识到 MateChat,您可以点击界面上的“添加知识”按钮,然后按照提示上传相关的文档或者输入具体的知识内容即可。',
|
||||
quick_code_example: '以下是一个简单的 JavaScript 代码示例,用于计算数组的总和:\n```javascript\nconst arr = [1, 2, 3, 4, 5];\nconst sum = arr.reduce((acc, val) => acc + val, 0);\nconsole.log(sum);\n```',
|
||||
performance_optimization: '性能优化可以从多个方面入手,例如减少循环嵌套、合理使用缓存、优化算法复杂度等。对于具体的代码,您可以提供给 MateChat 进行分析和建议。',
|
||||
write_document_assistance: 'MateChat 可以辅助您编写文档,例如生成文档大纲、填充内容等。您可以输入文档的主题和一些关键信息,然后让 MateChat 帮助您生成相关内容。',
|
||||
};
|
||||
|
||||
export const guessQuestions = [
|
||||
{
|
||||
label: 'MateChat 支持哪些编程语言?',
|
||||
value: 'supported_programming_languages',
|
||||
},
|
||||
{
|
||||
label: '如何查看 MateChat 的使用记录?',
|
||||
value: 'how_to_view_usage_record',
|
||||
},
|
||||
{
|
||||
label: 'MateChat 能处理复杂的业务逻辑吗?',
|
||||
value: 'handle_complex_business_logic',
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user