commit
33c1d32b24
9 changed files with 302 additions and 0 deletions
-
7README.md
-
13index.html
-
20package.json
-
1public/vite.svg
-
165src/App.vue
-
1src/assets/vue.svg
-
9src/main.js
-
79src/style.css
-
7vite.config.js
@ -0,0 +1,7 @@ |
|||||
|
# Vue 3 + Vite |
||||
|
|
||||
|
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more. |
||||
|
|
||||
|
## Recommended IDE Setup |
||||
|
|
||||
|
- [VS Code](https://code.visualstudio.com/) + [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously Volar) and disable Vetur |
||||
@ -0,0 +1,13 @@ |
|||||
|
<!doctype html> |
||||
|
<html lang="en"> |
||||
|
<head> |
||||
|
<meta charset="UTF-8" /> |
||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||
|
<title>Vite + Vue</title> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div id="app"></div> |
||||
|
<script type="module" src="/src/main.js"></script> |
||||
|
</body> |
||||
|
</html> |
||||
@ -0,0 +1,20 @@ |
|||||
|
{ |
||||
|
"name": "chatgpt-demo", |
||||
|
"private": true, |
||||
|
"version": "0.0.0", |
||||
|
"type": "module", |
||||
|
"scripts": { |
||||
|
"dev": "vite", |
||||
|
"build": "vite build", |
||||
|
"preview": "vite preview" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"element-plus": "^2.8.7", |
||||
|
"vue": "^3.4.21" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"@vitejs/plugin-vue": "^5.0.4", |
||||
|
"axios": "^1.7.7", |
||||
|
"vite": "^5.2.0" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg> |
||||
@ -0,0 +1,165 @@ |
|||||
|
|
||||
|
|
||||
|
<template> |
||||
|
|
||||
|
<el-row :gutter="20"> |
||||
|
<el-col :span="16"> |
||||
|
|
||||
|
<el-table :data="tableData" stripe style="width: 100%"> |
||||
|
<el-table-column prop="bookingNumber" label="#" /> |
||||
|
<el-table-column prop="name" label="Name" /> |
||||
|
<el-table-column prop="date" label="Date" /> |
||||
|
<el-table-column prop="from" label="From" /> |
||||
|
<el-table-column prop="to" label="To" /> |
||||
|
<el-table-column prop="bookingStatus" label="Status" > |
||||
|
<template #default="scope"> |
||||
|
{{ scope.row.bookingStatus === "CONFIRMED" ? "✅" : "❌"}} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="bookingClass" label="Booking class" /> |
||||
|
<el-table-column label="Operations" fixed="right" width="180" > |
||||
|
<template #default="scope"> |
||||
|
<el-button size="small" |
||||
|
type="primary"> |
||||
|
更改预定 |
||||
|
</el-button> |
||||
|
<el-button |
||||
|
size="small" |
||||
|
type="danger"> |
||||
|
退订 |
||||
|
</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
</el-col> |
||||
|
|
||||
|
<el-col :span="8" style="background-color: aliceblue;"> |
||||
|
<div style="height: 500px;overflow: scroll"> |
||||
|
<el-timeline style="max-width: 100%"> |
||||
|
<el-timeline-item |
||||
|
v-for="(activity, index) in activities" |
||||
|
:key="index" |
||||
|
:icon="activity.icon" |
||||
|
:type="activity.type" |
||||
|
:color="activity.color" |
||||
|
:size="activity.size" |
||||
|
:hollow="activity.hollow" |
||||
|
:timestamp="activity.timestamp" |
||||
|
> |
||||
|
{{ activity.content }} |
||||
|
</el-timeline-item> |
||||
|
</el-timeline> |
||||
|
</div> |
||||
|
<div id="container"> |
||||
|
<div id="chat"> |
||||
|
<el-input |
||||
|
v-model="msg" |
||||
|
input-style="width: 100%;height:50px" |
||||
|
:rows="2" |
||||
|
type="text" |
||||
|
placeholder="Please input" |
||||
|
@keydown.enter="sendMsg();" |
||||
|
/> |
||||
|
<el-button @click="sendMsg()">发送</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
|
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { MoreFilled } from '@element-plus/icons-vue' |
||||
|
import {ref, onMounted} from "vue"; |
||||
|
import axios from 'axios'//引入axios |
||||
|
|
||||
|
export default { |
||||
|
setup() { |
||||
|
const activities = ref([ |
||||
|
{ |
||||
|
content: '⭐欢迎来到图灵航空✈!请问有什么可以帮您的?', |
||||
|
timestamp: new Date().toLocaleDateString() + " " + new Date().toLocaleTimeString(), |
||||
|
color: '#0bbd87', |
||||
|
}, |
||||
|
]); |
||||
|
const msg = ref(''); |
||||
|
const tableData = ref([]); |
||||
|
let count = 2; |
||||
|
let eventSource; |
||||
|
|
||||
|
const sendMsg = () => { |
||||
|
if (eventSource) { |
||||
|
eventSource.close(); |
||||
|
} |
||||
|
|
||||
|
activities.value.push( |
||||
|
{ |
||||
|
content: `你:${msg.value}`, |
||||
|
timestamp: new Date().toLocaleDateString() + " " + new Date().toLocaleTimeString(), |
||||
|
size: 'large', |
||||
|
type: 'primary', |
||||
|
icon: MoreFilled, |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
activities.value.push( |
||||
|
{ |
||||
|
content: 'waiting...', |
||||
|
timestamp: new Date().toLocaleDateString() + " " + new Date().toLocaleTimeString(), |
||||
|
color: '#0bbd87', |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
// sse: 服务端推送 Server-Sent Events |
||||
|
eventSource = new EventSource(`http://localhost:8080/ai/generateStreamAsString?message=${msg.value}`); |
||||
|
msg.value=''; |
||||
|
eventSource.onmessage = (event) => { |
||||
|
if (event.data === '[complete]') { |
||||
|
count = count + 2; |
||||
|
eventSource.close(); |
||||
|
getBookings(); // 每次对话完后刷新列表 |
||||
|
return; |
||||
|
} |
||||
|
activities.value[count].content += event.data; |
||||
|
}; |
||||
|
eventSource.onopen = (event) => { |
||||
|
activities.value[count].content = ''; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
const getBookings = () => { |
||||
|
axios.get('http://localhost:8080/booking/list') |
||||
|
.then((response) => { |
||||
|
debugger; |
||||
|
tableData.value = response.data; |
||||
|
}) |
||||
|
.catch((error) => { |
||||
|
console.error(error); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// Use onMounted to call getBookings when the component is mounted |
||||
|
onMounted(() => { |
||||
|
getBookings(); |
||||
|
}); |
||||
|
|
||||
|
return { |
||||
|
activities, |
||||
|
msg, |
||||
|
tableData, |
||||
|
sendMsg, |
||||
|
getBookings, |
||||
|
}; |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
* { |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
} |
||||
|
#chat button{ |
||||
|
position: absolute; |
||||
|
margin-left: -60px; |
||||
|
margin-top: 19px; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1 @@ |
|||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg> |
||||
@ -0,0 +1,9 @@ |
|||||
|
import { createApp } from 'vue' |
||||
|
//import './style.css'
|
||||
|
import App from './App.vue' |
||||
|
import ElementPlus from 'element-plus' //全局引入
|
||||
|
import 'element-plus/dist/index.css' |
||||
|
|
||||
|
const app=createApp(App); |
||||
|
app.use(ElementPlus) |
||||
|
app.mount('#app') |
||||
@ -0,0 +1,79 @@ |
|||||
|
:root { |
||||
|
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; |
||||
|
line-height: 1.5; |
||||
|
font-weight: 400; |
||||
|
|
||||
|
color-scheme: light dark; |
||||
|
color: rgba(255, 255, 255, 0.87); |
||||
|
background-color: #242424; |
||||
|
|
||||
|
font-synthesis: none; |
||||
|
text-rendering: optimizeLegibility; |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; |
||||
|
} |
||||
|
|
||||
|
a { |
||||
|
font-weight: 500; |
||||
|
color: #646cff; |
||||
|
text-decoration: inherit; |
||||
|
} |
||||
|
a:hover { |
||||
|
color: #535bf2; |
||||
|
} |
||||
|
|
||||
|
body { |
||||
|
margin: 0; |
||||
|
display: flex; |
||||
|
place-items: center; |
||||
|
min-width: 320px; |
||||
|
min-height: 100vh; |
||||
|
} |
||||
|
|
||||
|
h1 { |
||||
|
font-size: 3.2em; |
||||
|
line-height: 1.1; |
||||
|
} |
||||
|
|
||||
|
button { |
||||
|
border-radius: 8px; |
||||
|
border: 1px solid transparent; |
||||
|
padding: 0.6em 1.2em; |
||||
|
font-size: 1em; |
||||
|
font-weight: 500; |
||||
|
font-family: inherit; |
||||
|
background-color: #1a1a1a; |
||||
|
cursor: pointer; |
||||
|
transition: border-color 0.25s; |
||||
|
} |
||||
|
button:hover { |
||||
|
border-color: #646cff; |
||||
|
} |
||||
|
button:focus, |
||||
|
button:focus-visible { |
||||
|
outline: 4px auto -webkit-focus-ring-color; |
||||
|
} |
||||
|
|
||||
|
.card { |
||||
|
padding: 2em; |
||||
|
} |
||||
|
|
||||
|
#app { |
||||
|
max-width: 1280px; |
||||
|
margin: 0 auto; |
||||
|
padding: 2rem; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
@media (prefers-color-scheme: light) { |
||||
|
:root { |
||||
|
color: #213547; |
||||
|
background-color: #ffffff; |
||||
|
} |
||||
|
a:hover { |
||||
|
color: #747bff; |
||||
|
} |
||||
|
button { |
||||
|
background-color: #f9f9f9; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
import { defineConfig } from 'vite' |
||||
|
import vue from '@vitejs/plugin-vue' |
||||
|
|
||||
|
// https://vitejs.dev/config/
|
||||
|
export default defineConfig({ |
||||
|
plugins: [vue()], |
||||
|
}) |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue