Spaces:
Paused
Paused
Upload 14 files
Browse files- frontend/babel.config.js +6 -0
- frontend/package-lock.json +0 -0
- frontend/package.json +56 -0
- frontend/public/favicon.ico +0 -0
- frontend/public/index.html +17 -0
- frontend/src/App.vue +16 -0
- frontend/src/components/ChatInterface.vue +357 -0
- frontend/src/components/DecisionAfter.vue +273 -0
- frontend/src/components/DecisionList.vue +260 -0
- frontend/src/components/InternSelection.vue +255 -0
- frontend/src/components/SurfacePro816.vue +255 -0
- frontend/src/components/UserLogin.vue +213 -0
- frontend/src/main.js +8 -0
- frontend/src/router.js +23 -0
frontend/babel.config.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module.exports = {
|
2 |
+
presets: [
|
3 |
+
'@vue/cli-plugin-babel/preset',
|
4 |
+
],
|
5 |
+
};
|
6 |
+
|
frontend/package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
frontend/package.json
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "vue-second-hand-platform",
|
3 |
+
"version": "0.1.0",
|
4 |
+
"private": true,
|
5 |
+
"scripts": {
|
6 |
+
"serve": "vue-cli-service serve",
|
7 |
+
"build": "vue-cli-service build",
|
8 |
+
"lint": "vue-cli-service lint"
|
9 |
+
},
|
10 |
+
"dependencies": {
|
11 |
+
"ajv-formats": "^3.0.1",
|
12 |
+
"axios": "^1.7.8",
|
13 |
+
"core-js": "^3.8.3",
|
14 |
+
"json-schema-traverse": "^1.0.0",
|
15 |
+
"vue": "^3.2.13",
|
16 |
+
"vue-router": "^4.5.0",
|
17 |
+
"vuex": "^4.1.0"
|
18 |
+
},
|
19 |
+
"devDependencies": {
|
20 |
+
"@babel/core": "^7.12.16",
|
21 |
+
"@babel/eslint-parser": "^7.12.16",
|
22 |
+
"@vue/cli-plugin-babel": "~5.0.0",
|
23 |
+
"@vue/cli-plugin-eslint": "~5.0.0",
|
24 |
+
"@vue/cli-service": "~5.0.0",
|
25 |
+
"eslint": "^7.32.0",
|
26 |
+
"eslint-plugin-vue": "^8.0.3",
|
27 |
+
"sass": "^1.81.0",
|
28 |
+
"sass-loader": "^16.0.3"
|
29 |
+
},
|
30 |
+
"eslintConfig": {
|
31 |
+
"root": true,
|
32 |
+
"env": {
|
33 |
+
"node": true
|
34 |
+
},
|
35 |
+
"extends": [
|
36 |
+
"plugin:vue/vue3-essential",
|
37 |
+
"eslint:recommended"
|
38 |
+
],
|
39 |
+
"parserOptions": {
|
40 |
+
"parser": "@babel/eslint-parser"
|
41 |
+
},
|
42 |
+
"rules": {
|
43 |
+
"vue/no-parsing-error": "off",
|
44 |
+
"vue/multi-word-component-names": ["error", {
|
45 |
+
"ignores": ["Result"]
|
46 |
+
}],
|
47 |
+
"no-unused-vars": ["warn"]
|
48 |
+
}
|
49 |
+
},
|
50 |
+
"browserslist": [
|
51 |
+
"> 1%",
|
52 |
+
"last 2 versions",
|
53 |
+
"not dead",
|
54 |
+
"not ie 11"
|
55 |
+
]
|
56 |
+
}
|
frontend/public/favicon.ico
ADDED
|
frontend/public/index.html
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Vue App</title>
|
7 |
+
<link rel="icon" href="<YOUR_ICON_PATH>" />
|
8 |
+
</head>
|
9 |
+
<body>
|
10 |
+
<!-- 这里是 Vue 渲染的根元素 -->
|
11 |
+
<div id="app"></div>
|
12 |
+
|
13 |
+
<!-- Vue 的构建文件,这些会在构建时自动注入 -->
|
14 |
+
<script src="/js/chunk-vendors.js"></script>
|
15 |
+
<script src="/js/app.js"></script>
|
16 |
+
</body>
|
17 |
+
</html>
|
frontend/src/App.vue
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<template>
|
2 |
+
<div id="app">
|
3 |
+
<!-- 在此处渲染路由对应的组件 -->
|
4 |
+
<router-view></router-view>
|
5 |
+
</div>
|
6 |
+
</template>
|
7 |
+
|
8 |
+
<script>
|
9 |
+
export default {
|
10 |
+
name: 'App',
|
11 |
+
};
|
12 |
+
</script>
|
13 |
+
|
14 |
+
<style>
|
15 |
+
/* 样式,可以根据需要添加 */
|
16 |
+
</style>
|
frontend/src/components/ChatInterface.vue
ADDED
@@ -0,0 +1,357 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<template>
|
2 |
+
|
3 |
+
<div id="chat-interface"> <!-- 给根元素添加一个唯一ID -->
|
4 |
+
<!-- 页面内容 -->
|
5 |
+
<div v-if="loading" class="loading-popup">Generating...</div>
|
6 |
+
<!-- 其余页面内容 -->
|
7 |
+
<div class="chat-container">
|
8 |
+
<header class="header">
|
9 |
+
<button class="menu-btn" @click="goToDecisionList">
|
10 |
+
<img
|
11 |
+
loading="lazy"
|
12 |
+
src="https://cdn.builder.io/api/v1/image/assets/TEMP/91eadb055de4658009ff495b7d3d28943f962d04f4c2f04b6234085498a9fdae?apiKey=27a3cbc05333484ba783c786c92a1338&"
|
13 |
+
alt="Navigation menu"
|
14 |
+
class="menu-icon"
|
15 |
+
/>
|
16 |
+
</button>
|
17 |
+
<h1 class="header-title">New Project</h1>
|
18 |
+
<button class="generate-button" @click="handleGenerate">
|
19 |
+
<img
|
20 |
+
loading="lazy"
|
21 |
+
src="https://cdn.builder.io/api/v1/image/assets/TEMP/455e4dfbb678e02c3414ec1d1e17cc6ec99f1c8579a6232f69f60078f6780750?apiKey=27a3cbc05333484ba783c786c92a1338&"
|
22 |
+
alt="Generate new project"
|
23 |
+
class="generate-icon"
|
24 |
+
/>
|
25 |
+
<span>Generate</span>
|
26 |
+
</button>
|
27 |
+
</header>
|
28 |
+
|
29 |
+
<main class="chat-content">
|
30 |
+
<!-- Displaying AI assistant's initial message -->
|
31 |
+
<div v-for="(message, index) in messages" :key="index" :class="['message-container', message.sender]">
|
32 |
+
<img
|
33 |
+
v-if="message.sender === 'assistant'"
|
34 |
+
loading="lazy"
|
35 |
+
src="https://cdn.builder.io/api/v1/image/assets/TEMP/71cd10158e03c2dd193a89b87b9d4fbc4ee62eb60e57692bacf8a038df1f8bfe?apiKey=27a3cbc05333484ba783c786c92a1338&"
|
36 |
+
alt="AI Assistant avatar"
|
37 |
+
class="avatar"
|
38 |
+
/>
|
39 |
+
<img
|
40 |
+
v-if="message.sender === 'user'"
|
41 |
+
loading="lazy"
|
42 |
+
src="https://cdn.builder.io/api/v1/image/assets/TEMP/05f7922f2b1c187beb89f24d171c6fbc6ba9230ec5b5aa86d29a816aad2cce17?apiKey=27a3cbc05333484ba783c786c92a1338&"
|
43 |
+
alt="User avatar"
|
44 |
+
class="avatar"
|
45 |
+
/>
|
46 |
+
<p class="message">{{ message.text }}</p>
|
47 |
+
</div>
|
48 |
+
|
49 |
+
<!-- User input form -->
|
50 |
+
<form class="input-form" @submit.prevent="handleSubmit">
|
51 |
+
<label for="userInput" class="visually-hidden">Type your message</label>
|
52 |
+
<input
|
53 |
+
type="text"
|
54 |
+
id="userInput"
|
55 |
+
class="message-input"
|
56 |
+
v-model="userInput"
|
57 |
+
/>
|
58 |
+
<button type="submit" class="send-button" aria-label="Send message">
|
59 |
+
<img
|
60 |
+
loading="lazy"
|
61 |
+
src="https://cdn.builder.io/api/v1/image/assets/TEMP/9faeb997ab01c69b2ecc19005ad6e9efa83b95810045fd99a2a93fe1348be8b0?apiKey=27a3cbc05333484ba783c786c92a1338&"
|
62 |
+
alt="Send icon"
|
63 |
+
class="send-icon"
|
64 |
+
/>
|
65 |
+
</button>
|
66 |
+
</form>
|
67 |
+
</main>
|
68 |
+
</div>
|
69 |
+
</div>
|
70 |
+
|
71 |
+
|
72 |
+
<!-- Conditional Loading Popup -->
|
73 |
+
<div v-if="loading" class="loading-popup">
|
74 |
+
<span>Generating...</span>
|
75 |
+
</div>
|
76 |
+
|
77 |
+
|
78 |
+
|
79 |
+
</template>
|
80 |
+
|
81 |
+
<script>
|
82 |
+
import { defineComponent, ref, onMounted } from 'vue'
|
83 |
+
import { useRouter } from 'vue-router'
|
84 |
+
|
85 |
+
export default defineComponent({
|
86 |
+
name: 'ChatInterface',
|
87 |
+
setup() {
|
88 |
+
onMounted(() => {
|
89 |
+
const container = document.getElementById('chat-interface'); // 获取特定页面容器
|
90 |
+
if (container) {
|
91 |
+
container.style.zoom = "0.8"; // 页面缩小到 80%
|
92 |
+
}
|
93 |
+
});
|
94 |
+
const loading = ref(false);
|
95 |
+
const userInput = ref('') // 用户输入
|
96 |
+
const messages = ref([ // 初始的Assistant消息
|
97 |
+
{ sender: 'assistant', text:
|
98 |
+
'Hello! I am your AI assistant. Let\'s get started.Please enter your decision topic and specific content.'
|
99 |
+
}
|
100 |
+
])
|
101 |
+
const step = ref(0) // 用来追踪对话阶段
|
102 |
+
const router = useRouter()
|
103 |
+
// 在组件挂载时,从 localStorage 中恢复对话内容
|
104 |
+
onMounted(() => {
|
105 |
+
const savedMessages = localStorage.getItem('NewwwwchatMessages')
|
106 |
+
if (savedMessages) {
|
107 |
+
messages.value = JSON.parse(savedMessages)
|
108 |
+
}
|
109 |
+
})
|
110 |
+
// 提交函数:用户输入后更新消息
|
111 |
+
const handleSubmit = () => {
|
112 |
+
if (!userInput.value.trim()) return
|
113 |
+
// 记录用户输入
|
114 |
+
messages.value.push({ sender: 'user', text: userInput.value })
|
115 |
+
setTimeout(() => {
|
116 |
+
// 根据当前对话阶段的step值回复不同内容
|
117 |
+
if (step.value === 0) {
|
118 |
+
// 第一阶段:询问关于offer的基本信息
|
119 |
+
messages.value.push({
|
120 |
+
sender: 'assistant',
|
121 |
+
text: 'Great! When considering an offer, you can look at several aspects like salary, location, company culture, and career growth. Could you please provide me with more details on these points? For example: "The offer is for a Software Engineer role with a salary of $X in Location Y."'
|
122 |
+
})
|
123 |
+
step.value++ // 进入下一阶段
|
124 |
+
} else if (step.value === 1) {
|
125 |
+
// 第二阶段:询问用户的个人偏好
|
126 |
+
messages.value.push({
|
127 |
+
sender: 'assistant',
|
128 |
+
text: 'Thanks! Now, could you tell me about your preferences and rate the importance of each aspect in your mind? For example: "salary:2, location:3, company culture:4, career growth:5."'
|
129 |
+
})
|
130 |
+
step.value++ // 进入下一阶段
|
131 |
+
} else if (step.value === 2) {
|
132 |
+
// 第三阶段:询问用户的个人信息
|
133 |
+
messages.value.push({
|
134 |
+
sender: 'assistant',
|
135 |
+
text: 'Got it! Is there any personal detail you want to share with me that are relevant to this decision? For example: "I have a family and the school district is important to me."'
|
136 |
+
})
|
137 |
+
step.value++ // 进入下一阶段
|
138 |
+
} else if (step.value === 3) {
|
139 |
+
// 用户已完成输入,等待用户确认
|
140 |
+
messages.value.push({
|
141 |
+
sender: 'assistant',
|
142 |
+
text: 'Thanks for providing all the details. Please type "Finished" when you are done.'
|
143 |
+
})
|
144 |
+
} else if (step.value === 4 && userInput.value.trim().toLowerCase() === 'finished') {
|
145 |
+
// 用户输入 "finished",生成决策报告
|
146 |
+
messages.value.push({
|
147 |
+
sender: 'assistant',
|
148 |
+
text: 'OK, I will now generate your decision report.'
|
149 |
+
})
|
150 |
+
handleGenerate() // 跳转到结果页面
|
151 |
+
}
|
152 |
+
// 更新 localStorage
|
153 |
+
localStorage.setItem('NewwwwchatMessages', JSON.stringify(messages.value))
|
154 |
+
}, 10000)
|
155 |
+
// 清空输入框
|
156 |
+
userInput.value = ''
|
157 |
+
}
|
158 |
+
|
159 |
+
// 用户输入 "Finished" 后生成报告
|
160 |
+
const handleGenerate = () => {
|
161 |
+
loading.value = true; // 设置 loading 为 true,显示弹窗
|
162 |
+
console.log("Loading started", loading.value);
|
163 |
+
setTimeout(() => {
|
164 |
+
loading.value = false; // 10秒后隐藏弹窗
|
165 |
+
router.push('/result'); // 跳转到结果页面
|
166 |
+
}, 20000); // 延迟10秒
|
167 |
+
};
|
168 |
+
|
169 |
+
return {
|
170 |
+
userInput,
|
171 |
+
messages,
|
172 |
+
handleSubmit,
|
173 |
+
handleGenerate
|
174 |
+
}
|
175 |
+
}
|
176 |
+
})
|
177 |
+
</script>
|
178 |
+
|
179 |
+
|
180 |
+
<style scoped>
|
181 |
+
.loading-popup {
|
182 |
+
position: fixed;
|
183 |
+
top: 50%;
|
184 |
+
left: 50%;
|
185 |
+
transform: translate(-50%, -50%); /* 居中显示 */
|
186 |
+
background-color: rgba(0, 0, 0, 0.7);
|
187 |
+
color: white;
|
188 |
+
padding: 20px;
|
189 |
+
border-radius: 5px;
|
190 |
+
font-size: 18px;
|
191 |
+
text-align: center;
|
192 |
+
z-index: 9999; /* 确保它在最上面 */
|
193 |
+
}
|
194 |
+
|
195 |
+
.chat-container {
|
196 |
+
background-color: #f1f3ff;
|
197 |
+
display: flex;
|
198 |
+
flex-direction: column;
|
199 |
+
overflow: hidden;
|
200 |
+
font-family: Inter, sans-serif;
|
201 |
+
}
|
202 |
+
|
203 |
+
.header {
|
204 |
+
background-color: #51d4e0;
|
205 |
+
box-shadow: 9px 0 16px rgba(0, 0, 0, 0.02);
|
206 |
+
display: flex;
|
207 |
+
width: 100%;
|
208 |
+
align-items: center;
|
209 |
+
justify-content: space-between;
|
210 |
+
padding: 24px 36px;
|
211 |
+
}
|
212 |
+
|
213 |
+
.menu-icon {
|
214 |
+
width: 13px;
|
215 |
+
aspect-ratio: 0.57;
|
216 |
+
object-fit: contain;
|
217 |
+
}
|
218 |
+
|
219 |
+
.header-title {
|
220 |
+
color: #fff;
|
221 |
+
font-size: 32px;
|
222 |
+
font-weight: 600;
|
223 |
+
}
|
224 |
+
|
225 |
+
.generate-button {
|
226 |
+
border-radius: 30px;
|
227 |
+
background-color: #fff;
|
228 |
+
display: flex;
|
229 |
+
gap: 7px;
|
230 |
+
align-items: center;
|
231 |
+
font-size: 20px;
|
232 |
+
color: #51d4e0;
|
233 |
+
font-weight: 700;
|
234 |
+
padding: 10px 17px;
|
235 |
+
border: 2px solid #51d4e0;
|
236 |
+
cursor: pointer;
|
237 |
+
margin-right: 80px;
|
238 |
+
}
|
239 |
+
|
240 |
+
.generate-icon {
|
241 |
+
width: 24px;
|
242 |
+
aspect-ratio: 1;
|
243 |
+
object-fit: contain;
|
244 |
+
border-radius: 30px;
|
245 |
+
}
|
246 |
+
|
247 |
+
.chat-content {
|
248 |
+
border-radius: 10px;
|
249 |
+
background-color: #fff;
|
250 |
+
box-shadow: 0 0 19px rgba(0, 0, 0, 0.05);
|
251 |
+
margin-top: 26px;
|
252 |
+
padding: 57px 62px;
|
253 |
+
}
|
254 |
+
|
255 |
+
.message-container {
|
256 |
+
display: flex;
|
257 |
+
gap: 40px;
|
258 |
+
margin-bottom: 40px;
|
259 |
+
}
|
260 |
+
|
261 |
+
.message-container.user {
|
262 |
+
flex-direction: row-reverse;
|
263 |
+
}
|
264 |
+
|
265 |
+
.avatar {
|
266 |
+
width: 70px;
|
267 |
+
aspect-ratio: 1;
|
268 |
+
object-fit: contain;
|
269 |
+
}
|
270 |
+
|
271 |
+
.message {
|
272 |
+
border-radius: 35px;
|
273 |
+
padding: 20px 56px;
|
274 |
+
font-size: 24px;
|
275 |
+
}
|
276 |
+
|
277 |
+
.message-container.assistant .message {
|
278 |
+
background-color: #f3f3f3;
|
279 |
+
}
|
280 |
+
|
281 |
+
.message-container.user .message {
|
282 |
+
background-color: #51d4e0;
|
283 |
+
color: #fff;
|
284 |
+
}
|
285 |
+
|
286 |
+
.list-item {
|
287 |
+
font-weight: 700;
|
288 |
+
line-height: 36px;
|
289 |
+
}
|
290 |
+
|
291 |
+
.input-form {
|
292 |
+
position: fixed;
|
293 |
+
bottom: 40px;
|
294 |
+
left: 20px;
|
295 |
+
right:100px;
|
296 |
+
width: 95%;
|
297 |
+
background-color: #f3f3f3;
|
298 |
+
display: flex;
|
299 |
+
align-items: center;
|
300 |
+
padding: 10px 30px;
|
301 |
+
box-shadow: 0 -4px 6px rgba(0, 0, 0, 0.1);
|
302 |
+
}
|
303 |
+
|
304 |
+
.message-input {
|
305 |
+
background: none;
|
306 |
+
border: none;
|
307 |
+
color: #b4b4b4;
|
308 |
+
font-size: 24px;
|
309 |
+
width: 100%;
|
310 |
+
margin-right: 20px;
|
311 |
+
}
|
312 |
+
|
313 |
+
.message-input:focus {
|
314 |
+
outline: none;
|
315 |
+
}
|
316 |
+
|
317 |
+
.send-icon {
|
318 |
+
width: 53px;
|
319 |
+
aspect-ratio: 1;
|
320 |
+
object-fit: contain;
|
321 |
+
}
|
322 |
+
|
323 |
+
.visually-hidden {
|
324 |
+
position: absolute;
|
325 |
+
width: 1px;
|
326 |
+
height: 1px;
|
327 |
+
padding: 0;
|
328 |
+
margin: -1px;
|
329 |
+
overflow: hidden;
|
330 |
+
clip: rect(0, 0, 0, 0);
|
331 |
+
border: 0;
|
332 |
+
}
|
333 |
+
|
334 |
+
|
335 |
+
@media (max-width: 991px) {
|
336 |
+
.header {
|
337 |
+
padding: 0 20px;
|
338 |
+
}
|
339 |
+
|
340 |
+
.chat-content {
|
341 |
+
padding: 0 20px;
|
342 |
+
}
|
343 |
+
|
344 |
+
.message {
|
345 |
+
padding: 20px;
|
346 |
+
}
|
347 |
+
|
348 |
+
.input-form {
|
349 |
+
margin-top: 40px;
|
350 |
+
padding: 16px 20px;
|
351 |
+
}
|
352 |
+
|
353 |
+
.generate-button {
|
354 |
+
white-space: normal;
|
355 |
+
}
|
356 |
+
}
|
357 |
+
</style>
|
frontend/src/components/DecisionAfter.vue
ADDED
@@ -0,0 +1,273 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<template>
|
2 |
+
<div id="decision-list-app">
|
3 |
+
<!-- 左侧导航栏 -->
|
4 |
+
<aside class="sidebar">
|
5 |
+
<input type="text" placeholder="Search" class="search-bar" />
|
6 |
+
<div class="status-filters">
|
7 |
+
<div class="filter-item active">Decisions <span>15</span></div>
|
8 |
+
<div class="filter-item">On-going <span>5</span></div>
|
9 |
+
<div class="filter-item">Finished <span>8</span></div>
|
10 |
+
<div class="filter-item">Suspend <span>2</span></div>
|
11 |
+
</div>
|
12 |
+
<div class="category">
|
13 |
+
<h3>Category</h3>
|
14 |
+
<div class="category-item">Untitled <span>5</span></div>
|
15 |
+
<div class="category-item">Business <span>3</span></div>
|
16 |
+
<div class="category-item">Study <span>6</span></div>
|
17 |
+
<div class="category-item">Entertainment <span>1</span></div>
|
18 |
+
<button class="add-category">+</button>
|
19 |
+
</div>
|
20 |
+
<div class="filter">
|
21 |
+
<h3>Filter</h3>
|
22 |
+
<div class="filter-item active">Starred</div>
|
23 |
+
</div>
|
24 |
+
</aside>
|
25 |
+
|
26 |
+
<!-- 主体内容 -->
|
27 |
+
<main class="main-content">
|
28 |
+
<div class="decision-cards">
|
29 |
+
<!-- 决策卡片示例 -->
|
30 |
+
<div class="decision-card" v-for="(decision, index) in decisions" :key="index" @click="goToSurfacePro816">
|
31 |
+
<div class="card-header">
|
32 |
+
<h2>{{ decision.title }}</h2>
|
33 |
+
<span v-if="decision.starred" class="star-icon">⭐</span>
|
34 |
+
</div>
|
35 |
+
<div class="key-notes">
|
36 |
+
<h3>Key Notes</h3>
|
37 |
+
<div v-for="(note, key) in decision.keyNotes" :key="key" class="key-note">
|
38 |
+
<span>{{ key }}</span>
|
39 |
+
<div class="progress-bar">
|
40 |
+
<div class="progress" :style="{ width: note + '%' }"></div>
|
41 |
+
</div>
|
42 |
+
<span class="value">{{ note }}%</span>
|
43 |
+
</div>
|
44 |
+
</div>
|
45 |
+
<div class="analysis">
|
46 |
+
<h3>Analysis</h3>
|
47 |
+
<p>{{ decision.analysis }}</p>
|
48 |
+
</div>
|
49 |
+
<div class="card-footer">
|
50 |
+
<span class="update-info">Update: {{ decision.updateTime }}</span>
|
51 |
+
<span class="category-label" :style="{ backgroundColor: decision.categoryColor }">
|
52 |
+
{{ decision.category }}
|
53 |
+
</span>
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
</div>
|
57 |
+
<!-- 添加按钮 -->
|
58 |
+
<button class="add-btn" @click="goToChatInterface">+</button>
|
59 |
+
</main>
|
60 |
+
</div>
|
61 |
+
</template>
|
62 |
+
|
63 |
+
<script>
|
64 |
+
export default {
|
65 |
+
data() {
|
66 |
+
return {
|
67 |
+
// 决策数据
|
68 |
+
decisions: [
|
69 |
+
{
|
70 |
+
title: "Intern Selection",
|
71 |
+
keyNotes: { Tiktok: 91, Tencent: 84 },
|
72 |
+
analysis:
|
73 |
+
"Choose TikTok for creativity and global exposure; pick Tencent for diverse platforms and strong influence in China's tech ecosystem, ideal for networking and innovation opportunities.",
|
74 |
+
category: "Business",
|
75 |
+
categoryColor: "#4CAF50",
|
76 |
+
starred: true,
|
77 |
+
},
|
78 |
+
{
|
79 |
+
title: "School Selection",
|
80 |
+
keyNotes: { Stanford: 81, Harvard: 68, MIT: 89 },
|
81 |
+
analysis:
|
82 |
+
"MIT leads with innovation and top facilities, Stanford excels in research, while Harvard scores lower likely due to metrics favoring STEM over humanities.",
|
83 |
+
updateTime: "2024/11/18 22:21",
|
84 |
+
category: "Study",
|
85 |
+
categoryColor: "#8BC34A",
|
86 |
+
starred: false,
|
87 |
+
},
|
88 |
+
{
|
89 |
+
title: "Take GRE Test or Not?",
|
90 |
+
keyNotes: { Yes: 71, No: 89 },
|
91 |
+
analysis:
|
92 |
+
"Skip the GRE if your target schools waive it, or value work experience more. It saves time, cost, and focuses on relevant strengths.",
|
93 |
+
updateTime: "2024/11/18 22:21",
|
94 |
+
category: "Untitled",
|
95 |
+
categoryColor: "#9E9E9E",
|
96 |
+
starred: true,
|
97 |
+
},
|
98 |
+
// 其他卡片数据...
|
99 |
+
],
|
100 |
+
};
|
101 |
+
},
|
102 |
+
methods: {
|
103 |
+
goToChatInterface() {
|
104 |
+
this.$router.push('/chat-interface'); // 跳转到 chatinterface 页面
|
105 |
+
},
|
106 |
+
goToSurfacePro816() {
|
107 |
+
// 使用路由跳转到 SurfacePro816 页面
|
108 |
+
this.$router.push({ name: 'surface-pro-816' });
|
109 |
+
},
|
110 |
+
},
|
111 |
+
};
|
112 |
+
</script>
|
113 |
+
|
114 |
+
<style scoped>
|
115 |
+
/* 全局设置 */
|
116 |
+
body {
|
117 |
+
margin: 0;
|
118 |
+
font-family: Arial, sans-serif;
|
119 |
+
box-sizing: border-box;
|
120 |
+
}
|
121 |
+
|
122 |
+
/* 左侧导航栏 */
|
123 |
+
.sidebar {
|
124 |
+
width: 250px;
|
125 |
+
height: 100vh;
|
126 |
+
background: #f4f4f4;
|
127 |
+
padding: 20px;
|
128 |
+
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
|
129 |
+
}
|
130 |
+
|
131 |
+
.search-bar {
|
132 |
+
width: 100%;
|
133 |
+
padding: 10px;
|
134 |
+
margin-bottom: 20px;
|
135 |
+
border: 1px solid #ddd;
|
136 |
+
border-radius: 5px;
|
137 |
+
}
|
138 |
+
|
139 |
+
.status-filters,
|
140 |
+
.category,
|
141 |
+
.filter {
|
142 |
+
margin-bottom: 30px;
|
143 |
+
}
|
144 |
+
|
145 |
+
.filter-item,
|
146 |
+
.category-item {
|
147 |
+
display: flex;
|
148 |
+
justify-content: space-between;
|
149 |
+
padding: 10px;
|
150 |
+
margin-bottom: 5px;
|
151 |
+
border-radius: 5px;
|
152 |
+
cursor: pointer;
|
153 |
+
}
|
154 |
+
|
155 |
+
.filter-item.active,
|
156 |
+
.category-item:hover {
|
157 |
+
background: #e0f7fa;
|
158 |
+
}
|
159 |
+
|
160 |
+
.add-category {
|
161 |
+
background: #4caf50;
|
162 |
+
color: white;
|
163 |
+
border: none;
|
164 |
+
padding: 10px;
|
165 |
+
border-radius: 5px;
|
166 |
+
cursor: pointer;
|
167 |
+
}
|
168 |
+
|
169 |
+
/* 主体内容 */
|
170 |
+
/* 在右下角添加按钮 */
|
171 |
+
.add-btn {
|
172 |
+
position: fixed; /* 固定定位 */
|
173 |
+
bottom: 60px; /* 距离底部20px */
|
174 |
+
right: 60px; /* 距离右侧20px */
|
175 |
+
background-color: #4CAF50; /* 按钮背景色 */
|
176 |
+
color: white; /* 按钮文字颜色 */
|
177 |
+
border: none; /* 无边框 */
|
178 |
+
border-radius: 50%; /* 圆形按钮 */
|
179 |
+
padding: 20px; /* 按钮大小 */
|
180 |
+
font-size: 24px; /* 图标大小 */
|
181 |
+
cursor: pointer; /* 鼠标悬浮时变为指针 */
|
182 |
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 给按钮加阴影 */
|
183 |
+
width: 60px; /* 给按钮设置固定宽度 */
|
184 |
+
height: 60px; /* 给按钮设置固定高度 */
|
185 |
+
display: flex; /* 使用flex布局 */
|
186 |
+
justify-content: center; /* 横向居中 */
|
187 |
+
align-items: center; /* 纵向居中 */
|
188 |
+
}
|
189 |
+
|
190 |
+
/* 添加按钮的 hover 效果 */
|
191 |
+
.add-btn:hover {
|
192 |
+
background-color: #45a049; /* 鼠标悬浮时的背景色 */
|
193 |
+
}
|
194 |
+
|
195 |
+
/* 确保加号图标是白色 */
|
196 |
+
.add-btn i {
|
197 |
+
color: white; /* 设置加号图标为白色 */
|
198 |
+
font-size: 3rem; /* 如果需要,可以调整图标大小 */
|
199 |
+
}
|
200 |
+
|
201 |
+
|
202 |
+
|
203 |
+
|
204 |
+
.main-content {
|
205 |
+
flex-grow: 1; /* 占据剩余的宽度 */
|
206 |
+
padding: 20px;
|
207 |
+
overflow-y: auto;
|
208 |
+
}
|
209 |
+
|
210 |
+
/* 卡片布局 */
|
211 |
+
.decision-cards {
|
212 |
+
display: grid; /* 使用 grid 布局 */
|
213 |
+
grid-template-columns: repeat(3, 1fr); /* 每行 3 个卡片 */
|
214 |
+
gap: 20px; /* 卡片之间的间距 */
|
215 |
+
position: absolute; /* 绝对定位 */
|
216 |
+
margin-left: 300px;
|
217 |
+
top: 20px; /* 距离顶部 20px */
|
218 |
+
width: 100%;
|
219 |
+
max-width: 900px; /* 容器最大宽度 */
|
220 |
+
}
|
221 |
+
.decision-card {
|
222 |
+
background: white;
|
223 |
+
border-radius: 10px;
|
224 |
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
225 |
+
padding: 20px;
|
226 |
+
}
|
227 |
+
|
228 |
+
.card-header {
|
229 |
+
display: flex;
|
230 |
+
justify-content: space-between;
|
231 |
+
align-items: center;
|
232 |
+
}
|
233 |
+
|
234 |
+
.key-notes .key-note {
|
235 |
+
display: flex;
|
236 |
+
align-items: center;
|
237 |
+
margin: 10px 0;
|
238 |
+
}
|
239 |
+
|
240 |
+
.progress-bar {
|
241 |
+
width: 60%;
|
242 |
+
height: 8px;
|
243 |
+
background: #ddd;
|
244 |
+
border-radius: 5px;
|
245 |
+
margin: 0 10px;
|
246 |
+
}
|
247 |
+
|
248 |
+
.progress {
|
249 |
+
height: 100%;
|
250 |
+
background: #4caf50;
|
251 |
+
border-radius: 5px;
|
252 |
+
}
|
253 |
+
|
254 |
+
.card-footer {
|
255 |
+
display: flex;
|
256 |
+
justify-content: space-between;
|
257 |
+
margin-top: 20px;
|
258 |
+
font-size: 12px;
|
259 |
+
}
|
260 |
+
|
261 |
+
.category-label {
|
262 |
+
padding: 5px 10px;
|
263 |
+
border-radius: 5px;
|
264 |
+
color: white;
|
265 |
+
font-size: 12px;
|
266 |
+
}
|
267 |
+
|
268 |
+
.new-dialog-btn i {
|
269 |
+
color: white;
|
270 |
+
font-size: 24px;
|
271 |
+
}
|
272 |
+
</style>
|
273 |
+
|
frontend/src/components/DecisionList.vue
ADDED
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<template>
|
2 |
+
<div id="decision-list-app">
|
3 |
+
<!-- 左侧导航栏 -->
|
4 |
+
<aside class="sidebar">
|
5 |
+
<input type="text" placeholder="Search" class="search-bar" />
|
6 |
+
<div class="status-filters">
|
7 |
+
<div class="filter-item active">Decisions <span>15</span></div>
|
8 |
+
<div class="filter-item">On-going <span>5</span></div>
|
9 |
+
<div class="filter-item">Finished <span>8</span></div>
|
10 |
+
<div class="filter-item">Suspend <span>2</span></div>
|
11 |
+
</div>
|
12 |
+
<div class="category">
|
13 |
+
<h3>Category</h3>
|
14 |
+
<div class="category-item">Untitled <span>5</span></div>
|
15 |
+
<div class="category-item">Business <span>3</span></div>
|
16 |
+
<div class="category-item">Study <span>6</span></div>
|
17 |
+
<div class="category-item">Entertainment <span>1</span></div>
|
18 |
+
<button class="add-category">+</button>
|
19 |
+
</div>
|
20 |
+
<div class="filter">
|
21 |
+
<h3>Filter</h3>
|
22 |
+
<div class="filter-item active">Starred</div>
|
23 |
+
</div>
|
24 |
+
</aside>
|
25 |
+
|
26 |
+
<!-- 主体内容 -->
|
27 |
+
<main class="main-content">
|
28 |
+
<div class="decision-cards">
|
29 |
+
<!-- 决策卡片示例 -->
|
30 |
+
<div class="decision-card" v-for="(decision, index) in decisions" :key="index">
|
31 |
+
<div class="card-header">
|
32 |
+
<h2>{{ decision.title }}</h2>
|
33 |
+
<span v-if="decision.starred" class="star-icon">⭐</span>
|
34 |
+
</div>
|
35 |
+
<div class="key-notes">
|
36 |
+
<h3>Key Notes</h3>
|
37 |
+
<div v-for="(note, key) in decision.keyNotes" :key="key" class="key-note">
|
38 |
+
<span>{{ key }}</span>
|
39 |
+
<div class="progress-bar">
|
40 |
+
<div class="progress" :style="{ width: note + '%' }"></div>
|
41 |
+
</div>
|
42 |
+
<span class="value">{{ note }}%</span>
|
43 |
+
</div>
|
44 |
+
</div>
|
45 |
+
<div class="analysis">
|
46 |
+
<h3>Analysis</h3>
|
47 |
+
<p>{{ decision.analysis }}</p>
|
48 |
+
</div>
|
49 |
+
<div class="card-footer">
|
50 |
+
<span class="update-info">Update: {{ decision.updateTime }}</span>
|
51 |
+
<span class="category-label" :style="{ backgroundColor: decision.categoryColor }">
|
52 |
+
{{ decision.category }}
|
53 |
+
</span>
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
</div>
|
57 |
+
<!-- 添加按钮 -->
|
58 |
+
<button class="add-btn" @click="goToChatInterface">+</button>
|
59 |
+
</main>
|
60 |
+
</div>
|
61 |
+
</template>
|
62 |
+
|
63 |
+
<script>
|
64 |
+
export default {
|
65 |
+
data() {
|
66 |
+
return {
|
67 |
+
// 决策数据
|
68 |
+
decisions: [
|
69 |
+
{
|
70 |
+
title: "School Selection",
|
71 |
+
keyNotes: { Stanford: 81, Harvard: 68, MIT: 89 },
|
72 |
+
analysis:
|
73 |
+
"MIT leads with innovation and top facilities, Stanford excels in research, while Harvard scores lower likely due to metrics favoring STEM over humanities.",
|
74 |
+
updateTime: "2024/11/18 22:21",
|
75 |
+
category: "Study",
|
76 |
+
categoryColor: "#8BC34A",
|
77 |
+
starred: false,
|
78 |
+
},
|
79 |
+
{
|
80 |
+
title: "Take GRE Test or Not?",
|
81 |
+
keyNotes: { Yes: 71, No: 89 },
|
82 |
+
analysis:
|
83 |
+
"Skip the GRE if your target schools waive it, or value work experience more. It saves time, cost, and focuses on relevant strengths.",
|
84 |
+
updateTime: "2024/11/18 22:21",
|
85 |
+
category: "Untitled",
|
86 |
+
categoryColor: "#9E9E9E",
|
87 |
+
starred: true,
|
88 |
+
},
|
89 |
+
// 其他卡片数据...
|
90 |
+
],
|
91 |
+
};
|
92 |
+
},
|
93 |
+
methods: {
|
94 |
+
goToChatInterface() {
|
95 |
+
this.$router.push('/chat-interface'); // 跳转到 chatinterface 页面
|
96 |
+
},
|
97 |
+
},
|
98 |
+
};
|
99 |
+
</script>
|
100 |
+
|
101 |
+
<style scoped>
|
102 |
+
/* 全局设置 */
|
103 |
+
body {
|
104 |
+
margin: 0;
|
105 |
+
font-family: Arial, sans-serif;
|
106 |
+
box-sizing: border-box;
|
107 |
+
}
|
108 |
+
|
109 |
+
/* 左侧导航栏 */
|
110 |
+
.sidebar {
|
111 |
+
width: 250px;
|
112 |
+
height: 100vh;
|
113 |
+
background: #f4f4f4;
|
114 |
+
padding: 20px;
|
115 |
+
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
|
116 |
+
}
|
117 |
+
|
118 |
+
.search-bar {
|
119 |
+
width: 100%;
|
120 |
+
padding: 10px;
|
121 |
+
margin-bottom: 20px;
|
122 |
+
border: 1px solid #ddd;
|
123 |
+
border-radius: 5px;
|
124 |
+
}
|
125 |
+
|
126 |
+
.status-filters,
|
127 |
+
.category,
|
128 |
+
.filter {
|
129 |
+
margin-bottom: 30px;
|
130 |
+
}
|
131 |
+
|
132 |
+
.filter-item,
|
133 |
+
.category-item {
|
134 |
+
display: flex;
|
135 |
+
justify-content: space-between;
|
136 |
+
padding: 10px;
|
137 |
+
margin-bottom: 5px;
|
138 |
+
border-radius: 5px;
|
139 |
+
cursor: pointer;
|
140 |
+
}
|
141 |
+
|
142 |
+
.filter-item.active,
|
143 |
+
.category-item:hover {
|
144 |
+
background: #e0f7fa;
|
145 |
+
}
|
146 |
+
|
147 |
+
.add-category {
|
148 |
+
background: #4caf50;
|
149 |
+
color: white;
|
150 |
+
border: none;
|
151 |
+
padding: 10px;
|
152 |
+
border-radius: 5px;
|
153 |
+
cursor: pointer;
|
154 |
+
}
|
155 |
+
|
156 |
+
/* 主体内容 */
|
157 |
+
|
158 |
+
/* 在右下角添加按钮 */
|
159 |
+
.add-btn {
|
160 |
+
position: fixed; /* 固定定位 */
|
161 |
+
bottom: 60px; /* 距离底部20px */
|
162 |
+
right: 60px; /* 距离右侧20px */
|
163 |
+
background-color: #4CAF50; /* 按钮背景色 */
|
164 |
+
color: white; /* 按钮文字颜色 */
|
165 |
+
border: none; /* 无边框 */
|
166 |
+
border-radius: 50%; /* 圆形按钮 */
|
167 |
+
padding: 20px; /* 按钮大小 */
|
168 |
+
font-size: 24px; /* 图标大小 */
|
169 |
+
cursor: pointer; /* 鼠标悬浮时变为指针 */
|
170 |
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 给按钮加阴影 */
|
171 |
+
width: 60px; /* 给按钮设置固定宽度 */
|
172 |
+
height: 60px; /* 给按钮设置固定高度 */
|
173 |
+
display: flex; /* 使用flex布局 */
|
174 |
+
justify-content: center; /* 横向居中 */
|
175 |
+
align-items: center; /* 纵向居中 */
|
176 |
+
}
|
177 |
+
|
178 |
+
/* 添加按钮的 hover 效果 */
|
179 |
+
.add-btn:hover {
|
180 |
+
background-color: #45a049; /* 鼠标悬浮时的背景色 */
|
181 |
+
}
|
182 |
+
|
183 |
+
/* 确保加号图标是白色 */
|
184 |
+
.add-btn i {
|
185 |
+
color: white; /* 设置加号图标为白色 */
|
186 |
+
font-size: 3rem; /* 如果需要,可以调整图标大小 */
|
187 |
+
}
|
188 |
+
|
189 |
+
|
190 |
+
|
191 |
+
|
192 |
+
.main-content {
|
193 |
+
flex-grow: 1; /* 占据剩余的宽度 */
|
194 |
+
padding: 20px;
|
195 |
+
overflow-y: auto;
|
196 |
+
}
|
197 |
+
|
198 |
+
/* 卡片布局 */
|
199 |
+
.decision-cards {
|
200 |
+
display: grid; /* 使用 grid 布局 */
|
201 |
+
grid-template-columns: repeat(3, 1fr); /* 每行 3 个卡片 */
|
202 |
+
gap: 20px; /* 卡片之间的间距 */
|
203 |
+
position: absolute; /* 绝对定位 */
|
204 |
+
margin-left: 300px;
|
205 |
+
top: 20px; /* 距离顶部 20px */
|
206 |
+
width: 100%;
|
207 |
+
max-width: 900px; /* 容器最大宽度 */
|
208 |
+
}
|
209 |
+
.decision-card {
|
210 |
+
background: white;
|
211 |
+
border-radius: 10px;
|
212 |
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
213 |
+
padding: 20px;
|
214 |
+
}
|
215 |
+
|
216 |
+
.card-header {
|
217 |
+
display: flex;
|
218 |
+
justify-content: space-between;
|
219 |
+
align-items: center;
|
220 |
+
}
|
221 |
+
|
222 |
+
.key-notes .key-note {
|
223 |
+
display: flex;
|
224 |
+
align-items: center;
|
225 |
+
margin: 10px 0;
|
226 |
+
}
|
227 |
+
|
228 |
+
.progress-bar {
|
229 |
+
width: 60%;
|
230 |
+
height: 8px;
|
231 |
+
background: #ddd;
|
232 |
+
border-radius: 5px;
|
233 |
+
margin: 0 10px;
|
234 |
+
}
|
235 |
+
|
236 |
+
.progress {
|
237 |
+
height: 100%;
|
238 |
+
background: #4caf50;
|
239 |
+
border-radius: 5px;
|
240 |
+
}
|
241 |
+
|
242 |
+
.card-footer {
|
243 |
+
display: flex;
|
244 |
+
justify-content: space-between;
|
245 |
+
margin-top: 20px;
|
246 |
+
font-size: 12px;
|
247 |
+
}
|
248 |
+
|
249 |
+
.category-label {
|
250 |
+
padding: 5px 10px;
|
251 |
+
border-radius: 5px;
|
252 |
+
color: white;
|
253 |
+
font-size: 12px;
|
254 |
+
}
|
255 |
+
|
256 |
+
.new-dialog-btn i {
|
257 |
+
color: white;
|
258 |
+
font-size: 24px;
|
259 |
+
}
|
260 |
+
</style>
|
frontend/src/components/InternSelection.vue
ADDED
@@ -0,0 +1,255 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<template>
|
2 |
+
<div id="app">
|
3 |
+
<!-- 标题 -->
|
4 |
+
<div class="header">
|
5 |
+
<h1>Intern Selection</h1>
|
6 |
+
</div>
|
7 |
+
|
8 |
+
<!-- 关键指标 -->
|
9 |
+
<section class="key-notes">
|
10 |
+
<h2>Key Notes</h2>
|
11 |
+
<div class="score-item" v-for="(item, index) in scores" :key="index">
|
12 |
+
<div class="score-title">
|
13 |
+
<span>{{ item.name }}</span>
|
14 |
+
<span>{{ item.score }}</span>
|
15 |
+
</div>
|
16 |
+
<div class="score-bar">
|
17 |
+
<div class="score-fill" :style="{ width: item.score + '%' }"></div>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
|
21 |
+
<!-- 单独的 result-text 部分 -->
|
22 |
+
<p class="result-text">
|
23 |
+
<strong>{{ result.main }}</strong>
|
24 |
+
{{ result.detail }}
|
25 |
+
</p>
|
26 |
+
</section>
|
27 |
+
|
28 |
+
<!-- 分析部分 -->
|
29 |
+
<section class="analysis" v-if="decisions.length">
|
30 |
+
<h2>Analysis</h2>
|
31 |
+
<div v-for="(decision, index) in decisions" :key="index" class="decision-card">
|
32 |
+
<span class="number">{{ index + 1 }}</span>
|
33 |
+
<div class="decision-text">
|
34 |
+
<strong>{{ decision.main }}</strong>
|
35 |
+
{{ decision.detail }}
|
36 |
+
</div>
|
37 |
+
</div>
|
38 |
+
</section>
|
39 |
+
|
40 |
+
|
41 |
+
<!-- 按钮 -->
|
42 |
+
<div class="footer">
|
43 |
+
<button class="chat-button" @click="goChatting">
|
44 |
+
Go Chatting!
|
45 |
+
</button>
|
46 |
+
</div>
|
47 |
+
<div class="footer1">
|
48 |
+
<button class="chat-button" @click="returnList">
|
49 |
+
Return
|
50 |
+
</button>
|
51 |
+
</div>
|
52 |
+
</div>
|
53 |
+
</template>
|
54 |
+
|
55 |
+
<script>
|
56 |
+
import { defineComponent } from 'vue'
|
57 |
+
|
58 |
+
export default defineComponent({
|
59 |
+
name: 'InternSelection',
|
60 |
+
data() {
|
61 |
+
return {
|
62 |
+
scores: [
|
63 |
+
{ name: 'Tiktok', score: 91 },
|
64 |
+
{ name: 'Tencent', score: 84 },
|
65 |
+
],
|
66 |
+
decisions: [
|
67 |
+
{
|
68 |
+
main: "Salary Comparison - 91 | 85 ",
|
69 |
+
detail: "TikTok offers a higher salary package, including bonuses and stock options, making it more attractive financially. In contrast, Tencent's salary is competitive but slightly lower than TikTok’s, with fewer additional incentives.",
|
70 |
+
},
|
71 |
+
{
|
72 |
+
main: "Location - 87 | 92 ",
|
73 |
+
detail: "TikTok's headquarters in Singapore provides international exposure and networking opportunities, ideal for those looking to work in a global environment. Tencent’s Shenzhen office is a great option for those wanting to immerse themselves in China's tech ecosystem, though it's more localized.",
|
74 |
+
},
|
75 |
+
{
|
76 |
+
main: "Company Culture - 90 |85 ",
|
77 |
+
detail: "TikTok promotes a creative and flexible work culture, encouraging innovation and personal growth. Tencent, while still offering a solid work environment, has a more traditional, hierarchical structure that may feel restrictive for some.",
|
78 |
+
},
|
79 |
+
{
|
80 |
+
main: "Work-Life Balance - 86 | 84 ",
|
81 |
+
detail: "TikTok offers a better work-life balance with fewer demands on after-hours work, making it a more relaxed environment. Tencent is known for its high-pressure culture, with long hours and a stronger focus on performance.",
|
82 |
+
},
|
83 |
+
{
|
84 |
+
main: "Career Development - 95 |80 ",
|
85 |
+
detail: "TikTok offers faster career progression with more opportunities to move across departments and regions, giving employees more visibility. Tencent offers a solid career development path, but advancement can be slower and more dependent on internal networking.",
|
86 |
+
}
|
87 |
+
],
|
88 |
+
|
89 |
+
// 注意这里是一个对象,不是数组
|
90 |
+
result: {
|
91 |
+
main: 'TikTok is a better fit based on salary, location, culture, and career growth, according to your preferences and priorities. ',
|
92 |
+
detail: 'TikTok is a better fit for those seeking a fast-paced, innovative environment with global exposure and a healthier work-life balance.'
|
93 |
+
}
|
94 |
+
}
|
95 |
+
},
|
96 |
+
|
97 |
+
|
98 |
+
methods: {
|
99 |
+
goChatting() {
|
100 |
+
// 点击按钮返回到聊天页面
|
101 |
+
this.$router.push('/chat-interface')
|
102 |
+
},
|
103 |
+
returnList() {
|
104 |
+
// 点击按钮返回到决策列表页面
|
105 |
+
this.$router.push({ name: 'decision-after' });
|
106 |
+
},
|
107 |
+
},
|
108 |
+
})
|
109 |
+
</script>
|
110 |
+
|
111 |
+
<style scoped>
|
112 |
+
/* 全局样式 */
|
113 |
+
body {
|
114 |
+
font-family: Arial, sans-serif;
|
115 |
+
margin: 0;
|
116 |
+
padding: 0;
|
117 |
+
box-sizing: border-box;
|
118 |
+
background-color: #f9f9f9;
|
119 |
+
color: #333;
|
120 |
+
}
|
121 |
+
|
122 |
+
#app {
|
123 |
+
max-width: 900px;
|
124 |
+
margin: 20px auto;
|
125 |
+
padding: 20px;
|
126 |
+
background-color: #fff;
|
127 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
128 |
+
border-radius: 10px;
|
129 |
+
}
|
130 |
+
|
131 |
+
/* 标题样式 */
|
132 |
+
.header h1 {
|
133 |
+
font-size: 2rem;
|
134 |
+
color: #52c8e8;
|
135 |
+
margin-bottom: 10px;
|
136 |
+
}
|
137 |
+
|
138 |
+
/* 关键指标样式 */
|
139 |
+
.key-notes h2 {
|
140 |
+
font-size: 1.5rem;
|
141 |
+
margin-bottom: 15px;
|
142 |
+
}
|
143 |
+
|
144 |
+
.score-item {
|
145 |
+
margin: 10px 0;
|
146 |
+
}
|
147 |
+
|
148 |
+
.score-title {
|
149 |
+
display: flex;
|
150 |
+
justify-content: space-between;
|
151 |
+
font-size: 1rem;
|
152 |
+
margin-bottom: 5px;
|
153 |
+
}
|
154 |
+
|
155 |
+
.score-bar {
|
156 |
+
background-color: #ddd;
|
157 |
+
border-radius: 10px;
|
158 |
+
height: 10px;
|
159 |
+
overflow: hidden;
|
160 |
+
}
|
161 |
+
|
162 |
+
.score-fill {
|
163 |
+
background-color: #52c8e8;
|
164 |
+
height: 100%;
|
165 |
+
}
|
166 |
+
|
167 |
+
/* 结果文字 */
|
168 |
+
.result-text {
|
169 |
+
margin-top: 15px;
|
170 |
+
font-size: 1rem;
|
171 |
+
}
|
172 |
+
|
173 |
+
/* 分析部分样式 */
|
174 |
+
.analysis h2 {
|
175 |
+
margin-top: 40px;
|
176 |
+
font-size: 1.5rem;
|
177 |
+
margin-bottom: 15px;
|
178 |
+
}
|
179 |
+
|
180 |
+
.decision-card {
|
181 |
+
display: flex;
|
182 |
+
background-color: #f2f8fc;
|
183 |
+
border-left: 4px solid #52c8e8;
|
184 |
+
padding: 10px;
|
185 |
+
border-radius: 5px;
|
186 |
+
margin-bottom: 20px;
|
187 |
+
}
|
188 |
+
|
189 |
+
.decision-card .number {
|
190 |
+
font-size: 1.5rem;
|
191 |
+
font-weight: bold;
|
192 |
+
margin-right: 10px;
|
193 |
+
}
|
194 |
+
|
195 |
+
.decision-text {
|
196 |
+
font-size: 1rem;
|
197 |
+
}
|
198 |
+
|
199 |
+
.decision-card:last-child {
|
200 |
+
margin-bottom: 100px; /* Adjust this value for more or less space */
|
201 |
+
}
|
202 |
+
/* 按钮样式 */
|
203 |
+
.footer1 {
|
204 |
+
position: absolute; /* 绝对定位 */
|
205 |
+
top: 80px; /* 距离底部 20px */
|
206 |
+
right: 0; /* 距离右侧 40px */
|
207 |
+
text-align: center;
|
208 |
+
}
|
209 |
+
|
210 |
+
.footer1 .chat-button {
|
211 |
+
border-radius: 30px;
|
212 |
+
background-color: #fff;
|
213 |
+
display: flex;
|
214 |
+
gap: 7px;
|
215 |
+
align-items: center;
|
216 |
+
font-size: 20px;
|
217 |
+
color: #42b0cf;
|
218 |
+
font-weight: 700;
|
219 |
+
padding: 10px 17px;
|
220 |
+
border: 2px solid#42b0cf;
|
221 |
+
cursor: pointer;
|
222 |
+
margin-right: 80px;
|
223 |
+
}
|
224 |
+
|
225 |
+
.footer1 .chat-button:hover {
|
226 |
+
background-color:#51d4e0; /* 悬停时背景色 */
|
227 |
+
}
|
228 |
+
|
229 |
+
.footer {
|
230 |
+
position: absolute; /* 绝对定位 */
|
231 |
+
top: 15px; /* 距离底部 20px */
|
232 |
+
right: 0; /* 距离右侧 40px */
|
233 |
+
text-align: center;
|
234 |
+
}
|
235 |
+
|
236 |
+
.footer .chat-button {
|
237 |
+
border-radius: 30px;
|
238 |
+
background-color: #fff;
|
239 |
+
display: flex;
|
240 |
+
gap: 7px;
|
241 |
+
align-items: center;
|
242 |
+
font-size: 20px;
|
243 |
+
color: #42b0cf;
|
244 |
+
font-weight: 700;
|
245 |
+
padding: 10px 17px;
|
246 |
+
border: 2px solid#42b0cf;
|
247 |
+
cursor: pointer;
|
248 |
+
margin-right: 80px;
|
249 |
+
}
|
250 |
+
|
251 |
+
.footer .chat-button:hover {
|
252 |
+
background-color:#51d4e0; /* 悬停时背景色 */
|
253 |
+
}
|
254 |
+
|
255 |
+
</style>
|
frontend/src/components/SurfacePro816.vue
ADDED
@@ -0,0 +1,255 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<template>
|
2 |
+
<div id="app">
|
3 |
+
<!-- 标题 -->
|
4 |
+
<div class="header">
|
5 |
+
<h1>Intern Selection</h1>
|
6 |
+
</div>
|
7 |
+
|
8 |
+
<!-- 关键指标 -->
|
9 |
+
<section class="key-notes">
|
10 |
+
<h2>Key Notes</h2>
|
11 |
+
<div class="score-item" v-for="(item, index) in scores" :key="index">
|
12 |
+
<div class="score-title">
|
13 |
+
<span>{{ item.name }}</span>
|
14 |
+
<span>{{ item.score }}</span>
|
15 |
+
</div>
|
16 |
+
<div class="score-bar">
|
17 |
+
<div class="score-fill" :style="{ width: item.score + '%' }"></div>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
|
21 |
+
<!-- 单独的 result-text 部分 -->
|
22 |
+
<p class="result-text">
|
23 |
+
<strong>{{ result.main }}</strong>
|
24 |
+
{{ result.detail }}
|
25 |
+
</p>
|
26 |
+
</section>
|
27 |
+
|
28 |
+
<!-- 分析部分 -->
|
29 |
+
<section class="analysis" v-if="decisions.length">
|
30 |
+
<h2>Analysis</h2>
|
31 |
+
<div v-for="(decision, index) in decisions" :key="index" class="decision-card">
|
32 |
+
<span class="number">{{ index + 1 }}</span>
|
33 |
+
<div class="decision-text">
|
34 |
+
<strong>{{ decision.main }}</strong>
|
35 |
+
{{ decision.detail }}
|
36 |
+
</div>
|
37 |
+
</div>
|
38 |
+
</section>
|
39 |
+
|
40 |
+
|
41 |
+
<!-- 按钮 -->
|
42 |
+
<div class="footer">
|
43 |
+
<button class="chat-button" @click="goChatting">
|
44 |
+
Go Chatting!
|
45 |
+
</button>
|
46 |
+
</div>
|
47 |
+
<div class="footer1">
|
48 |
+
<button class="chat-button" @click="returnList">
|
49 |
+
Return
|
50 |
+
</button>
|
51 |
+
</div>
|
52 |
+
</div>
|
53 |
+
</template>
|
54 |
+
|
55 |
+
<script>
|
56 |
+
import { defineComponent } from 'vue'
|
57 |
+
|
58 |
+
export default defineComponent({
|
59 |
+
name: 'InternSelection',
|
60 |
+
data() {
|
61 |
+
return {
|
62 |
+
scores: [
|
63 |
+
{ name: 'Tiktok', score: 91 },
|
64 |
+
{ name: 'Tencent', score: 84 },
|
65 |
+
],
|
66 |
+
decisions: [
|
67 |
+
{
|
68 |
+
main: "Salary Comparison - 91 | 85 ",
|
69 |
+
detail: "TikTok offers a higher salary package, including bonuses and stock options, making it more attractive financially. In contrast, Tencent's salary is competitive but slightly lower than TikTok’s, with fewer additional incentives.",
|
70 |
+
},
|
71 |
+
{
|
72 |
+
main: "Location - 87 | 92 ",
|
73 |
+
detail: "TikTok's headquarters in Singapore provides international exposure and networking opportunities, ideal for those looking to work in a global environment. Tencent’s Shenzhen office is a great option for those wanting to immerse themselves in China's tech ecosystem, though it's more localized.",
|
74 |
+
},
|
75 |
+
{
|
76 |
+
main: "Company Culture - 90 |85 ",
|
77 |
+
detail: "TikTok promotes a creative and flexible work culture, encouraging innovation and personal growth. Tencent, while still offering a solid work environment, has a more traditional, hierarchical structure that may feel restrictive for some.",
|
78 |
+
},
|
79 |
+
{
|
80 |
+
main: "Work-Life Balance - 86 | 84 ",
|
81 |
+
detail: "TikTok offers a better work-life balance with fewer demands on after-hours work, making it a more relaxed environment. Tencent is known for its high-pressure culture, with long hours and a stronger focus on performance.",
|
82 |
+
},
|
83 |
+
{
|
84 |
+
main: "Career Development - 95 |80 ",
|
85 |
+
detail: "TikTok offers faster career progression with more opportunities to move across departments and regions, giving employees more visibility. Tencent offers a solid career development path, but advancement can be slower and more dependent on internal networking.",
|
86 |
+
}
|
87 |
+
],
|
88 |
+
|
89 |
+
// 注意这里是一个对象,不是数组
|
90 |
+
result: {
|
91 |
+
main: 'TikTok is a better fit based on salary, location, culture, and career growth, according to your preferences and priorities. ',
|
92 |
+
detail: 'TikTok is a better fit for those seeking a fast-paced, innovative environment with global exposure and a healthier work-life balance.'
|
93 |
+
}
|
94 |
+
}
|
95 |
+
},
|
96 |
+
|
97 |
+
|
98 |
+
methods: {
|
99 |
+
goChatting() {
|
100 |
+
// 点击按钮返回到聊天页面
|
101 |
+
this.$router.push('/chat-interface')
|
102 |
+
},
|
103 |
+
returnList() {
|
104 |
+
// 点击按钮返回到决策列表页面
|
105 |
+
this.$router.push({ name: 'decision-after' });
|
106 |
+
},
|
107 |
+
},
|
108 |
+
})
|
109 |
+
</script>
|
110 |
+
|
111 |
+
<style scoped>
|
112 |
+
/* 全局样式 */
|
113 |
+
body {
|
114 |
+
font-family: Arial, sans-serif;
|
115 |
+
margin: 0;
|
116 |
+
padding: 0;
|
117 |
+
box-sizing: border-box;
|
118 |
+
background-color: #f9f9f9;
|
119 |
+
color: #333;
|
120 |
+
}
|
121 |
+
|
122 |
+
#app {
|
123 |
+
max-width: 900px;
|
124 |
+
margin: 20px auto;
|
125 |
+
padding: 20px;
|
126 |
+
background-color: #fff;
|
127 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
128 |
+
border-radius: 10px;
|
129 |
+
}
|
130 |
+
|
131 |
+
/* 标题样式 */
|
132 |
+
.header h1 {
|
133 |
+
font-size: 2rem;
|
134 |
+
color: #52c8e8;
|
135 |
+
margin-bottom: 10px;
|
136 |
+
}
|
137 |
+
|
138 |
+
/* 关键指标样式 */
|
139 |
+
.key-notes h2 {
|
140 |
+
font-size: 1.5rem;
|
141 |
+
margin-bottom: 15px;
|
142 |
+
}
|
143 |
+
|
144 |
+
.score-item {
|
145 |
+
margin: 10px 0;
|
146 |
+
}
|
147 |
+
|
148 |
+
.score-title {
|
149 |
+
display: flex;
|
150 |
+
justify-content: space-between;
|
151 |
+
font-size: 1rem;
|
152 |
+
margin-bottom: 5px;
|
153 |
+
}
|
154 |
+
|
155 |
+
.score-bar {
|
156 |
+
background-color: #ddd;
|
157 |
+
border-radius: 10px;
|
158 |
+
height: 10px;
|
159 |
+
overflow: hidden;
|
160 |
+
}
|
161 |
+
|
162 |
+
.score-fill {
|
163 |
+
background-color: #52c8e8;
|
164 |
+
height: 100%;
|
165 |
+
}
|
166 |
+
|
167 |
+
/* 结果文字 */
|
168 |
+
.result-text {
|
169 |
+
margin-top: 15px;
|
170 |
+
font-size: 1rem;
|
171 |
+
}
|
172 |
+
|
173 |
+
/* 分析部分样式 */
|
174 |
+
.analysis h2 {
|
175 |
+
margin-top: 40px;
|
176 |
+
font-size: 1.5rem;
|
177 |
+
margin-bottom: 15px;
|
178 |
+
}
|
179 |
+
|
180 |
+
.decision-card {
|
181 |
+
display: flex;
|
182 |
+
background-color: #f2f8fc;
|
183 |
+
border-left: 4px solid #52c8e8;
|
184 |
+
padding: 10px;
|
185 |
+
border-radius: 5px;
|
186 |
+
margin-bottom: 20px;
|
187 |
+
}
|
188 |
+
|
189 |
+
.decision-card .number {
|
190 |
+
font-size: 1.5rem;
|
191 |
+
font-weight: bold;
|
192 |
+
margin-right: 10px;
|
193 |
+
}
|
194 |
+
|
195 |
+
.decision-text {
|
196 |
+
font-size: 1rem;
|
197 |
+
}
|
198 |
+
|
199 |
+
.decision-card:last-child {
|
200 |
+
margin-bottom: 100px; /* Adjust this value for more or less space */
|
201 |
+
}
|
202 |
+
/* 按钮样式 */
|
203 |
+
.footer1 {
|
204 |
+
position: absolute; /* 绝对定位 */
|
205 |
+
top: 80px; /* 距离底部 20px */
|
206 |
+
right: 0; /* 距离右侧 40px */
|
207 |
+
text-align: center;
|
208 |
+
}
|
209 |
+
|
210 |
+
.footer1 .chat-button {
|
211 |
+
border-radius: 30px;
|
212 |
+
background-color: #fff;
|
213 |
+
display: flex;
|
214 |
+
gap: 7px;
|
215 |
+
align-items: center;
|
216 |
+
font-size: 20px;
|
217 |
+
color: #42b0cf;
|
218 |
+
font-weight: 700;
|
219 |
+
padding: 10px 17px;
|
220 |
+
border: 2px solid#42b0cf;
|
221 |
+
cursor: pointer;
|
222 |
+
margin-right: 80px;
|
223 |
+
}
|
224 |
+
|
225 |
+
.footer1 .chat-button:hover {
|
226 |
+
background-color:#51d4e0; /* 悬停时背景色 */
|
227 |
+
}
|
228 |
+
|
229 |
+
.footer {
|
230 |
+
position: absolute; /* 绝对定位 */
|
231 |
+
top: 15px; /* 距离底部 20px */
|
232 |
+
right: 0; /* 距离右侧 40px */
|
233 |
+
text-align: center;
|
234 |
+
}
|
235 |
+
|
236 |
+
.footer .chat-button {
|
237 |
+
border-radius: 30px;
|
238 |
+
background-color: #fff;
|
239 |
+
display: flex;
|
240 |
+
gap: 7px;
|
241 |
+
align-items: center;
|
242 |
+
font-size: 20px;
|
243 |
+
color: #42b0cf;
|
244 |
+
font-weight: 700;
|
245 |
+
padding: 10px 17px;
|
246 |
+
border: 2px solid#42b0cf;
|
247 |
+
cursor: pointer;
|
248 |
+
margin-right: 80px;
|
249 |
+
}
|
250 |
+
|
251 |
+
.footer .chat-button:hover {
|
252 |
+
background-color:#51d4e0; /* 悬停时背景色 */
|
253 |
+
}
|
254 |
+
|
255 |
+
</style>
|
frontend/src/components/UserLogin.vue
ADDED
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<template>
|
2 |
+
<div class="login-container">
|
3 |
+
<h2>用户登录</h2>
|
4 |
+
|
5 |
+
<form @submit.prevent="submitForm">
|
6 |
+
<!-- 用户名/邮箱 -->
|
7 |
+
<div class="form-group">
|
8 |
+
<label for="username">用户名/邮箱:</label>
|
9 |
+
<input
|
10 |
+
type="text"
|
11 |
+
id="username"
|
12 |
+
v-model="username"
|
13 |
+
placeholder="请输入用户名或邮箱"
|
14 |
+
required
|
15 |
+
/>
|
16 |
+
</div>
|
17 |
+
|
18 |
+
<!-- 密码 -->
|
19 |
+
<div class="form-group">
|
20 |
+
<label for="password">密码:</label>
|
21 |
+
<input
|
22 |
+
type="password"
|
23 |
+
id="password"
|
24 |
+
v-model="password"
|
25 |
+
placeholder="请输入密码"
|
26 |
+
required
|
27 |
+
/>
|
28 |
+
</div>
|
29 |
+
|
30 |
+
<!-- 错误信息 -->
|
31 |
+
<div v-if="errorMessage" class="error-message">
|
32 |
+
{{ errorMessage }}
|
33 |
+
</div>
|
34 |
+
|
35 |
+
<!-- 登录按钮 -->
|
36 |
+
<div class="form-group">
|
37 |
+
<button type="submit">登录</button>
|
38 |
+
</div>
|
39 |
+
|
40 |
+
<div class="register-link">
|
41 |
+
<p>还没有账号?<router-link to="/register">注册</router-link></p>
|
42 |
+
</div>
|
43 |
+
</form>
|
44 |
+
</div>
|
45 |
+
</template>
|
46 |
+
|
47 |
+
<script>
|
48 |
+
export default {
|
49 |
+
data() {
|
50 |
+
return {
|
51 |
+
username: "",
|
52 |
+
password: "",
|
53 |
+
errorMessage: "",
|
54 |
+
};
|
55 |
+
},
|
56 |
+
methods: {
|
57 |
+
submitForm() {
|
58 |
+
// 简化后不再校验用户名和密码
|
59 |
+
this.errorMessage = "";
|
60 |
+
|
61 |
+
// 跳转到 DecisionList 页面
|
62 |
+
this.$router.push('/decision-list'); // 跳转到首页或者 DecisionList 页面
|
63 |
+
},
|
64 |
+
},
|
65 |
+
};
|
66 |
+
</script>
|
67 |
+
|
68 |
+
<style scoped>
|
69 |
+
/* 背景设计 */
|
70 |
+
body {
|
71 |
+
background: linear-gradient(to right, #6a11cb, #2575fc); /* 漸變背景 */
|
72 |
+
font-family: 'Arial', sans-serif;
|
73 |
+
}
|
74 |
+
|
75 |
+
/* 登录容器 */
|
76 |
+
.login-container {
|
77 |
+
max-width: 400px;
|
78 |
+
margin: 100px auto;
|
79 |
+
padding: 30px;
|
80 |
+
border-radius: 10px;
|
81 |
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
82 |
+
background-color: white;
|
83 |
+
text-align: center;
|
84 |
+
}
|
85 |
+
|
86 |
+
/* 标题 */
|
87 |
+
h2 {
|
88 |
+
font-size: 24px;
|
89 |
+
color: #333;
|
90 |
+
margin-bottom: 30px;
|
91 |
+
font-weight: 600;
|
92 |
+
}
|
93 |
+
|
94 |
+
/* 输入框容器 */
|
95 |
+
.form-group {
|
96 |
+
margin-bottom: 20px;
|
97 |
+
}
|
98 |
+
|
99 |
+
label {
|
100 |
+
font-size: 14px;
|
101 |
+
color: #555;
|
102 |
+
margin-bottom: 8px;
|
103 |
+
display: block;
|
104 |
+
font-weight: 500;
|
105 |
+
}
|
106 |
+
|
107 |
+
/* 输入框样式 */
|
108 |
+
input {
|
109 |
+
width: 100%;
|
110 |
+
padding: 12px;
|
111 |
+
font-size: 16px;
|
112 |
+
border: 1px solid #ccc;
|
113 |
+
border-radius: 6px;
|
114 |
+
margin-top: 5px;
|
115 |
+
box-sizing: border-box;
|
116 |
+
transition: all 0.3s ease;
|
117 |
+
}
|
118 |
+
|
119 |
+
/* 输入框聚焦样式 */
|
120 |
+
input:focus {
|
121 |
+
border-color: #2575fc;
|
122 |
+
box-shadow: 0 0 5px rgba(37, 117, 252, 0.5);
|
123 |
+
outline: none;
|
124 |
+
}
|
125 |
+
|
126 |
+
/* 按钮样式 */
|
127 |
+
button {
|
128 |
+
width: 100%;
|
129 |
+
padding: 12px;
|
130 |
+
font-size: 16px;
|
131 |
+
background-color: #2575fc;
|
132 |
+
color: white;
|
133 |
+
border: none;
|
134 |
+
border-radius: 6px;
|
135 |
+
cursor: pointer;
|
136 |
+
transition: all 0.3s ease;
|
137 |
+
}
|
138 |
+
|
139 |
+
button:hover {
|
140 |
+
background-color: #1d61d6;
|
141 |
+
transform: translateY(-2px);
|
142 |
+
}
|
143 |
+
|
144 |
+
/* 错误提示信息 */
|
145 |
+
.error-message {
|
146 |
+
color: red;
|
147 |
+
font-size: 14px;
|
148 |
+
margin-top: 10px;
|
149 |
+
}
|
150 |
+
|
151 |
+
/* 注册链接 */
|
152 |
+
.register-link {
|
153 |
+
margin-top: 20px;
|
154 |
+
}
|
155 |
+
|
156 |
+
.register-link a {
|
157 |
+
color: #2575fc;
|
158 |
+
font-size: 14px;
|
159 |
+
text-decoration: none;
|
160 |
+
font-weight: 500;
|
161 |
+
}
|
162 |
+
|
163 |
+
.register-link a:hover {
|
164 |
+
text-decoration: underline;
|
165 |
+
}
|
166 |
+
|
167 |
+
.profile-container {
|
168 |
+
display: flex;
|
169 |
+
}
|
170 |
+
|
171 |
+
.sidebar {
|
172 |
+
width: 250px;
|
173 |
+
padding: 20px;
|
174 |
+
background-color: #f4f4f4;
|
175 |
+
}
|
176 |
+
|
177 |
+
.profile-main {
|
178 |
+
flex-grow: 1;
|
179 |
+
padding: 20px;
|
180 |
+
}
|
181 |
+
|
182 |
+
.profile-header {
|
183 |
+
display: flex;
|
184 |
+
align-items: center;
|
185 |
+
margin-bottom: 20px;
|
186 |
+
}
|
187 |
+
|
188 |
+
.profile-header .avatar {
|
189 |
+
width: 50px;
|
190 |
+
height: 50px;
|
191 |
+
border-radius: 50%;
|
192 |
+
margin-right: 20px;
|
193 |
+
}
|
194 |
+
|
195 |
+
.logout-button {
|
196 |
+
margin-top: 20px;
|
197 |
+
}
|
198 |
+
|
199 |
+
.logout-button button {
|
200 |
+
padding: 10px 20px;
|
201 |
+
background-color: #ff4444;
|
202 |
+
color: white;
|
203 |
+
border: none;
|
204 |
+
border-radius: 5px;
|
205 |
+
cursor: pointer;
|
206 |
+
}
|
207 |
+
|
208 |
+
.logout-button button:hover {
|
209 |
+
background-color: #ff0000;
|
210 |
+
}
|
211 |
+
|
212 |
+
</style>
|
213 |
+
|
frontend/src/main.js
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// src/main.js
|
2 |
+
import { createApp } from 'vue';
|
3 |
+
import App from './App.vue';
|
4 |
+
import router from './router';
|
5 |
+
|
6 |
+
createApp(App)
|
7 |
+
.use(router) // 使用路由
|
8 |
+
.mount('#app');
|
frontend/src/router.js
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { createRouter, createWebHistory } from 'vue-router';
|
2 |
+
import ChatInterface from './components/ChatInterface.vue';
|
3 |
+
import InternSelection from './components/InternSelection.vue';
|
4 |
+
import DecisionList from './components/DecisionList.vue';
|
5 |
+
import UserLogin from './components/UserLogin.vue';
|
6 |
+
import DecisionAfter from './components/DecisionAfter.vue';
|
7 |
+
import SurfacePro816 from './components/SurfacePro816.vue';
|
8 |
+
|
9 |
+
const routes = [
|
10 |
+
{ path: '/', component: UserLogin }, // 默认首页显示 UserLogin
|
11 |
+
{ path: '/decision-list', component: DecisionList, name: 'decision-list' }, // 路由到 DecisionList 页面
|
12 |
+
{ path: '/chat-interface', component: ChatInterface, name: 'chat-interface' }, // 路由到 ChatInterface 页面
|
13 |
+
{ path: '/result', component: InternSelection, name: 'result' }, // 路由到 InternSelection 页面
|
14 |
+
{ path: '/decision-after', component: DecisionAfter, name: 'decision-after' },
|
15 |
+
{ path: '/surface-pro-816', component: SurfacePro816, name: 'surface-pro-816' },// 路由到 DecisionAfter 页面
|
16 |
+
];
|
17 |
+
|
18 |
+
const router = createRouter({
|
19 |
+
history: createWebHistory(),
|
20 |
+
routes,
|
21 |
+
});
|
22 |
+
|
23 |
+
export default router;
|