whx 2 giorni fa
parent
commit
d29c6359d6
22 ha cambiato i file con 284 aggiunte e 110 eliminazioni
  1. 36 1
      virgo.wzfrontend/aiChat/src/components/AIFlowChat.vue
  2. 1 1
      virgo.wzfrontend/aiChat/src/components/HideUpload.vue
  3. 8 3
      virgo.wzfrontend/aiChat/src/views/AIChat.vue
  4. 132 13
      virgo.wzfrontend/aiChat/src/views/Home.vue
  5. 16 8
      virgo.wzfrontend/aiChat/src/views/Projects.vue
  6. 6 0
      virgo.wzfrontend/aiChat/test.md
  7. 5 0
      virgo.wzfrontend/src/main/resources/static/ai/assets/AIChat-BS85SWq5.js
  8. 0 60
      virgo.wzfrontend/src/main/resources/static/ai/assets/AIChat-DRIDzxwC.js
  9. 0 10
      virgo.wzfrontend/src/main/resources/static/ai/assets/AIChat-GpPaLiaa.css
  10. 10 0
      virgo.wzfrontend/src/main/resources/static/ai/assets/AIChat-g8x8RRYF.css
  11. 1 0
      virgo.wzfrontend/src/main/resources/static/ai/assets/Home-77DgmZjQ.js
  12. 0 1
      virgo.wzfrontend/src/main/resources/static/ai/assets/Home-SCOrT_Wn.js
  13. 1 1
      virgo.wzfrontend/src/main/resources/static/ai/assets/Home-CFLR7HUq.css
  14. 0 1
      virgo.wzfrontend/src/main/resources/static/ai/assets/Projects-DIcBWRcC.js
  15. 1 0
      virgo.wzfrontend/src/main/resources/static/ai/assets/Projects-feLmREsA.js
  16. 0 1
      virgo.wzfrontend/src/main/resources/static/ai/assets/_plugin-vue_export-helper-DlAUqK2U.js
  17. 0 6
      virgo.wzfrontend/src/main/resources/static/ai/assets/ai-1L56bMch.js
  18. 1 0
      virgo.wzfrontend/src/main/resources/static/ai/assets/ai-Dliq_KSZ.js
  19. 3 3
      virgo.wzfrontend/src/main/resources/static/ai/assets/index-CDCh93_q.js
  20. 56 0
      virgo.wzfrontend/src/main/resources/static/ai/assets/marked.esm--zrfzkwQ.js
  21. 6 0
      virgo.wzfrontend/src/main/resources/static/ai/assets/request-DU3G20Qw.js
  22. 1 1
      virgo.wzfrontend/src/main/resources/static/ai/index.html

+ 36 - 1
virgo.wzfrontend/aiChat/src/components/AIFlowChat.vue

@@ -26,6 +26,7 @@
 	// 引入 github 代码主题
 	import 'highlight.js/styles/github.css';
 	import config from '@/config'
+	const emits = defineEmits(['updateURL']);
 	const user = ref(useUserStore().userData);
 	// 对话历史
 	const chatHistory = ref([]);
@@ -38,6 +39,7 @@
 	const UUID = ref(useRoute().params.id);
 	const conversationId = ref('');
 	const chatBody = ref(null);
+	const previewUrl = ref('');
 	const formatTime = () => {
 		return ''
 	}
@@ -58,6 +60,7 @@
 				conversationId.value = flowChatData.data.conversationId;
 				loading.value = false;
 				initChatList();
+				stopTimer();
 			} else {
 				let inputs = JSON.parse(flowChatData.data.inputs);
 				chatHistory.value = [{
@@ -92,6 +95,7 @@
 				return node
 			});
 			hljs.highlightAll();
+			if (previewUrl.value) emits('updateURL', previewUrl.value);
 		}
 	}
 	const reloadMessage = (value) => {
@@ -146,6 +150,7 @@
 				result += resultString;
 				result = result.replaceAll('data:', '');
 				chatHistory.value[chatHistory.value.length - 1].AIoutputs = renderMarkdown(result);
+				initChatList();
 				scrollToBottom();
 			}
 		} catch (error) {
@@ -167,6 +172,7 @@
 	 * 使用 marked 解析 Markdown
 	 * @param markdown 解析的文本
 	 */
+	let versionIndex = 1;
 	const renderMarkdown = markdown => {
 		const renderer = new marked.Renderer();
 		renderer.code = ({
@@ -180,10 +186,30 @@
 			}).value;
 			return `<div class="hljs-box"><div class="hljs-title">${language.toLocaleUpperCase()}</div><pre><code class="hljs language-${language}">${highlighted}</code></pre></div>`;
 		};
+		renderer.link = (href) => {
+			let divBox = document.createElement('div');
+			let div = document.createElement('div');
+			div.innerHTML = `version-${versionIndex}`
+			div.id = href.href;
+			div.className = 'version-href'
+			versionIndex++;
+			divBox.appendChild(div);
+			previewUrl.value = href.href;
+			console.log(versionIndex);
+			return divBox.innerHTML;
+		};
 		return marked(markdown, {
 			renderer
 		});
 	};
+	const AIClick = (e) => {
+		let target = e.target;
+		if (target.className === 'version-href') {
+			let href = target.id;
+			emits('updateURL', href);
+		}
+
+	}
 	// 组件卸载时清除定时器(重要!)
 	onUnmounted(() => {
 		stopTimer()
@@ -206,7 +232,7 @@
 						<div class="message-header-label" style="width: 100px;">AI助手</div>
 					</div>
 					<div class="message-content">
-						<div class="ai-website-boxs" v-html="message.AIoutputs"></div>
+						<div class="ai-website-boxs" @click="AIClick" v-html="message.AIoutputs"></div>
 						<el-button size="small" @click="reloadMessage(message.query)" :disabled="loading"
 							style="margin-top: 10px;" v-if="message.AIoutputs.indexOf('系统繁忙,请重试')>-1">
 							点击重试
@@ -262,6 +288,15 @@
 			margin-top: 0;
 		}
 	}
+
+	.version-href {
+		border: 1px solid var(--el-border-color);
+		padding: 5px 15px;
+		border-radius: 6px;
+		cursor: pointer;
+		display: inline-block;
+		margin-top: 5px;
+	}
 </style>
 <style scoped lang="scss">
 	.ai-chat-container {

+ 1 - 1
virgo.wzfrontend/aiChat/src/components/HideUpload.vue

@@ -33,7 +33,7 @@
 		})
 	}
 	const progress = (res) => {
-		console.log(res);
+		// console.log(res);
 	}
 	const handleUpload = () => {
 		uploadRef.value.$el.querySelector('input').click();

+ 8 - 3
virgo.wzfrontend/aiChat/src/views/AIChat.vue

@@ -13,8 +13,13 @@
 	const user = ref(useUserStore().userData);
 	const websiteUrl = ref('');
 	const loading = ref(false);
+	const updateURL = (url) => {
+		if(	websiteUrl.value === url) return;
+		websiteUrl.value = url;
+		loading.value = true;
+	}
 	const onloadIframe = () => {
-
+		loading.value = false;
 	}
 </script>
 <template>
@@ -36,7 +41,7 @@
 			<div class="website-form ai-website-box">
 				<div class="website-form-title">AI聊天</div>
 				<div class="hui-flex-box">
-					<AIFlowChat></AIFlowChat>
+					<AIFlowChat @updateURL="updateURL"></AIFlowChat>
 				</div>
 			</div>
 			<div class="website-show ai-website-box">
@@ -47,7 +52,7 @@
 					</div>
 					<div class="html-box" v-else v-loading="loading">
 						<iframe ref="iframeDom" :src="websiteUrl" width="100%" height="100%" frameborder="0"
-							@load="onloadIframe">
+							@load="onloadIframe" :key="websiteUrl">
 						</iframe>
 					</div>
 				</div>

+ 132 - 13
virgo.wzfrontend/aiChat/src/views/Home.vue

@@ -14,7 +14,8 @@
 		ref,
 		watch,
 		computed,
-		onMounted
+		onMounted,
+		onUnmounted
 	} from 'vue'
 	import {
 		useUserStore
@@ -114,6 +115,100 @@
 	}
 	const selectVisible = ref(false);
 	const selectData = ref({});
+	// 打字机效果状态
+	const phrasesInput = ref('企业官网,电商独立站,个人独立站,生活服务独立站');
+	const typeSpeed = ref(120);
+	const isRunning = ref(true);
+	const isPaused = ref(false);
+	const placeholder = ref('');
+
+	// 动画控制变量
+	const currentPhraseIndex = ref(0);
+	const currentCharIndex = ref(0);
+	const isDeleting = ref(false);
+	let typeInterval = null;
+
+	// 计算属性 - 获取短语数组
+	const phrases = computed(() => {
+		return phrasesInput.value.split(',')
+			.map(phrase => phrase.trim())
+			.filter(phrase => phrase.length > 0);
+	});
+
+	// 打字机动画核心逻辑
+	const type = () => {
+		if (isPaused.value) return;
+		const currentPhrase = phrases.value[currentPhraseIndex.value];
+		if (!currentPhrase) return;
+
+		if (isDeleting.value) {
+			// 删除字符
+			placeholder.value = currentPhrase.substring(0, currentCharIndex.value - 1);
+			currentCharIndex.value--;
+			if (currentCharIndex.value === 0) {
+				isDeleting.value = false;
+				currentPhraseIndex.value = (currentPhraseIndex.value + 1) % phrases.value.length;
+			}
+		} else {
+			// 添加字符
+			placeholder.value = currentPhrase.substring(0, currentCharIndex.value + 1);
+			currentCharIndex.value++;
+			if (currentCharIndex.value === currentPhrase.length) {
+				// 完成输入,暂停一下然后开始删除
+				setTimeout(() => {
+					isDeleting.value = true;
+				}, 1000);
+			}
+		}
+	};
+
+	// 开始/停止动画
+	const toggleAnimation = () => {
+		isRunning.value = !isRunning.value;
+		if (isRunning.value) {
+			startTypeAnimation();
+		} else {
+			clearInterval(typeInterval);
+			typeInterval = null;
+		}
+	};
+
+	// 暂停/继续动画
+	const togglePause = () => {
+		if (!isRunning.value) return;
+		isPaused.value = !isPaused.value;
+	};
+
+	// 启动打字动画
+	const startTypeAnimation = () => {
+		if (typeInterval) {
+			clearInterval(typeInterval);
+			typeInterval = null;
+		}
+		if (phrases.value.length === 0) return;
+		// 重置状态
+		currentPhraseIndex.value = 0;
+		currentCharIndex.value = 0;
+		isDeleting.value = false;
+		placeholder.value = '';
+		typeInterval = setInterval(type, typeSpeed.value);
+	};
+
+	// 当短语变化时重置动画
+	watch(phrases, (newVal) => {
+		if (newVal.length === 0) return;
+		if (isRunning.value) {
+			startTypeAnimation();
+		}
+	});
+
+	// 当速度变化时重新设置定时器
+	watch(typeSpeed, (newVal) => {
+		if (isRunning.value && typeInterval) {
+			clearInterval(typeInterval);
+			typeInterval = setInterval(type, newVal);
+		}
+	});
 	const sendMessage = async () => {
 		if (!userStore.token) {
 			ElMessage({
@@ -123,10 +218,19 @@
 			loginVisible.value = true;
 			return;
 		}
-		loading.value = true;
-		let createChatData = await createFLowChat(7, {
+		let postData = {
 			query: message.value
-		})
+		}
+		if (websiteURL.value) {
+			if (!postData['inputs']) postData['inputs'] = {};
+			postData['inputs']['websiteURL'] = websiteURL.value;
+		}
+		if (imageList.value.length > 0) {
+			if (!postData['inputs']) postData['inputs'] = {};
+			postData['inputs']['files'] = imageList.value.join(',');
+		}
+		loading.value = true;
+		let createChatData = await createFLowChat(7, postData)
 		loading.value = false;
 		if (createChatData.state) router.push(`/aichat/${createChatData.data}`);
 	}
@@ -150,6 +254,13 @@
 	}
 	onMounted(() => {
 		init();
+		startTypeAnimation();
+	})
+	// 组件卸载时清除定时器(重要!)
+	onUnmounted(() => {
+		if (typeInterval) {
+			clearInterval(typeInterval);
+		}
 	})
 </script>
 
@@ -184,13 +295,20 @@
 				<p class="small-title">通过与AI聊天创建应用程序和网站</p>
 			</div>
 			<div class="form-box">
-				<el-input type="textarea" v-model="message" placeholder="生成一个信息科技企业官网" resize="none" :rows="5"
+				<el-input type="textarea" v-model="message" :placeholder="`生成一个${placeholder}`" resize="none" :rows="5"
 					:autosize="{ minRows: 3, maxRows: 7 }">
 				</el-input>
 				<HideUpload ref="hideUploadRef" v-show="false" @uploadImage="uploadImage"></HideUpload>
 				<div class="form-submit">
 					<div class="form-operation">
-						<el-dropdown @command="commandFunction">
+						<el-dropdown @command="commandFunction" :popper-options="{
+							modifiers: [
+							  {
+								name: 'computeStyles',
+								options: { gpuAcceleration: false, adaptive: false },
+							  },
+							],
+						  }">
 							<el-button size="default" :icon="Paperclip" circle></el-button>
 							<template #dropdown>
 								<el-dropdown-menu>
@@ -199,9 +317,9 @@
 								</el-dropdown-menu>
 							</template>
 						</el-dropdown>
-						<el-button style="margin-left: 10px;" size="default" :icon="Plus" circle
+						<!-- 	<el-button style="margin-left: 10px;" size="default" :icon="Plus" circle
 							@click="selectVisible = true">
-						</el-button>
+						</el-button> -->
 					</div>
 					<el-button type="primary" size="large" :icon="Top" circle :loading="loading"
 						style="font-size: 18px;" @click="sendMessage" :disabled="!message.trim()">
@@ -210,7 +328,7 @@
 				<div class="operation-file" v-if="websiteURL || imageList.length > 0">
 					<div class="operation-url" v-if="websiteURL">
 						<el-tag type="info" closable effect="plain" round @close="websiteURL = ''">
-							{{websiteURL}}
+							参考网站:{{websiteURL}}
 						</el-tag>
 					</div>
 					<div class="operation-image" v-if="imageList.length > 0">
@@ -392,6 +510,10 @@
 				}
 			}
 
+			.el-button:focus-visible {
+				outline: none;
+			}
+
 			.form-submit {
 				margin-top: 10px;
 				display: flex;
@@ -420,10 +542,6 @@
 					box-sizing: border-box;
 
 				}
-
-				.el-select__wrapper {
-					border-radius: 24px;
-				}
 			}
 
 			.operation-file {
@@ -432,6 +550,7 @@
 
 			.operation-image {
 				display: flex;
+				margin-top: 10px;
 			}
 
 			.image-item {

+ 16 - 8
virgo.wzfrontend/aiChat/src/views/Projects.vue

@@ -12,20 +12,27 @@
 	import {
 		getDifyChatList
 	} from '@/api/ai'
+	import {
+		marked
+	} from 'marked';
 	const router = ref(useRouter())
 	const user = ref(useUserStore().userData);
 	const projectList = ref([]);
+	const str = ref('')
 	const init = async () => {
-		let list = await getDifyChatList(7);
-		if (list.state) {
-			projectList.value = [{
-				name: '生成科技型网站',
-				id: '3683d9640fab4714a6fdbd09c6700b1c'
-			}]
-		}
+		// let list = await getDifyChatList(7);
+		// if (list.state) {
+		projectList.value = [{
+			name: '生成科技型网站1',
+			id: '3683d9640fab4714a6fdbd09c6700b1c'
+		}, {
+			name: '生成科技型网站2',
+			id: '79d14ab1c26c46a195abd4626d29a1e5'
+		}]
+		// }
 	}
 	onMounted(() => {
-		init()
+		init();
 	})
 </script>
 <template>
@@ -44,6 +51,7 @@
 			</div>
 		</header>
 		<div class="projects-content">
+			<div> {{str}}</div>
 			<el-button v-for="(item,index) in projectList" :key="index" @click="router.push(`/aichat/${item.id}`)">
 				{{item.name}}
 			</el-button>

+ 6 - 0
virgo.wzfrontend/aiChat/test.md

@@ -0,0 +1,6 @@
+```yaml
+ answer: |
+   <div class="alert alert-info">
+	 这是一个提示框
+   </div>
+```

File diff suppressed because it is too large
+ 5 - 0
virgo.wzfrontend/src/main/resources/static/ai/assets/AIChat-BS85SWq5.js


File diff suppressed because it is too large
+ 0 - 60
virgo.wzfrontend/src/main/resources/static/ai/assets/AIChat-DRIDzxwC.js


File diff suppressed because it is too large
+ 0 - 10
virgo.wzfrontend/src/main/resources/static/ai/assets/AIChat-GpPaLiaa.css


File diff suppressed because it is too large
+ 10 - 0
virgo.wzfrontend/src/main/resources/static/ai/assets/AIChat-g8x8RRYF.css


File diff suppressed because it is too large
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/ai/assets/Home-77DgmZjQ.js


File diff suppressed because it is too large
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/ai/assets/Home-SCOrT_Wn.js


File diff suppressed because it is too large
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/ai/assets/Home-CFLR7HUq.css


File diff suppressed because it is too large
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/ai/assets/Projects-DIcBWRcC.js


File diff suppressed because it is too large
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/ai/assets/Projects-feLmREsA.js


+ 0 - 1
virgo.wzfrontend/src/main/resources/static/ai/assets/_plugin-vue_export-helper-DlAUqK2U.js

@@ -1 +0,0 @@
-const s=(t,r)=>{const o=t.__vccOpts||t;for(const[c,e]of r)o[c]=e;return o};export{s as _};

File diff suppressed because it is too large
+ 0 - 6
virgo.wzfrontend/src/main/resources/static/ai/assets/ai-1L56bMch.js


+ 1 - 0
virgo.wzfrontend/src/main/resources/static/ai/assets/ai-Dliq_KSZ.js

@@ -0,0 +1 @@
+import{s as e}from"./request-DU3G20Qw.js";const i=(t,a)=>{const r=t.__vccOpts||t;for(const[o,s]of a)r[o]=s;return r};function n(t,a){return e({url:`/api/ai/chat/uuid/${t}`,method:"post",data:a})}function u(t){return e({url:`/api/ai/chat/${t}`,method:"get"})}function h(t){return e({url:`/api/ai/chat/message/${t}`,method:"get"})}export{i as _,h as a,n as c,u as g};

File diff suppressed because it is too large
+ 3 - 3
virgo.wzfrontend/src/main/resources/static/ai/assets/index-CDCh93_q.js


File diff suppressed because it is too large
+ 56 - 0
virgo.wzfrontend/src/main/resources/static/ai/assets/marked.esm--zrfzkwQ.js


File diff suppressed because it is too large
+ 6 - 0
virgo.wzfrontend/src/main/resources/static/ai/assets/request-DU3G20Qw.js


+ 1 - 1
virgo.wzfrontend/src/main/resources/static/ai/index.html

@@ -5,7 +5,7 @@
 		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
 		<link rel="icon" href="https://file-node.oss-cn-shanghai.aliyuncs.com/youji/f9617c7f80da485cb3cc72b6accc62ed">
 		<title>WorkArk AI</title>

-		<script type="module" crossorigin src="./assets/index-CDCh93_q.js"></script>
+		<script type="module" crossorigin src="./assets/index-0LZbrY1U.js"></script>
 		<link rel="stylesheet" crossorigin href="./assets/index-95H28FZP.css">
 	</head>
 	<body>