Agent-Market-Arena / src /views /AddAssetView.vue
lfqian's picture
feat: save agent submissions to localStorage instead of email
73e23df
raw
history blame
10.5 kB
<template>
<div class="page-container">
<div class="title-container">
<span class="main-title">Agent Arena</span>
</div>
<div class="cards-container">
<!-- Add Agent Card -->
<Card class="feature-card">
<template #title>
<div class="card-title">
<i class="pi pi-robot"></i>
<span>Add Trading Agent</span>
</div>
</template>
<template #content>
<div class="form-container">
<div class="field">
<label for="agentName">Agent Name</label>
<InputText
id="agentName"
v-model="agentForm.name"
placeholder="e.g., MyTradingAgent"
class="w-full"
/>
</div>
<div class="field">
<label for="agentEndpoint">API Endpoint</label>
<InputText
id="agentEndpoint"
v-model="agentForm.endpoint"
placeholder="https://api.example.com/trading-agent"
class="w-full"
/>
</div>
<div class="field">
<label for="agentDescription">Description (Optional)</label>
<Textarea
id="agentDescription"
v-model="agentForm.description"
placeholder="Brief description of your agent..."
rows="3"
class="w-full"
/>
</div>
<Button
label="Submit Agent"
icon="pi pi-send"
@click="submitAgent"
:disabled="!agentForm.name || !agentForm.endpoint"
:loading="agentForm.loading"
class="w-full"
/>
<Message v-if="agentForm.message" :severity="agentForm.messageType" :closable="false">
{{ agentForm.message }}
</Message>
</div>
</template>
</Card>
<!-- Add Asset Card -->
<Card class="feature-card">
<template #title>
<div class="card-title">
<i class="pi pi-chart-line"></i>
<span>Request Asset</span>
</div>
</template>
<template #content>
<div class="form-container">
<div class="field">
<label for="assetSymbol">Asset Symbol</label>
<InputText
id="assetSymbol"
v-model="assetForm.symbol"
placeholder="e.g., NVDA, GOOGL, SOL"
class="w-full"
/>
</div>
<div class="field">
<label for="assetType">Asset Type</label>
<Dropdown
id="assetType"
v-model="assetForm.type"
:options="assetTypes"
optionLabel="label"
optionValue="value"
placeholder="Select asset type"
class="w-full"
/>
</div>
<div class="field">
<label for="assetReason">Reason for Request (Optional)</label>
<Textarea
id="assetReason"
v-model="assetForm.reason"
placeholder="Why would you like to see this asset?"
rows="3"
class="w-full"
/>
</div>
<Button
label="Request Asset"
icon="pi pi-plus"
@click="submitAsset"
:disabled="!assetForm.symbol || !assetForm.type"
:loading="assetForm.loading"
class="w-full"
/>
<Message v-if="assetForm.message" :severity="assetForm.messageType" :closable="false">
{{ assetForm.message }}
</Message>
</div>
</template>
</Card>
</div>
</div>
</template>
<script>
import Card from 'primevue/card'
import InputText from 'primevue/inputtext'
import Textarea from 'primevue/textarea'
import Dropdown from 'primevue/dropdown'
import Button from 'primevue/button'
import Message from 'primevue/message'
import emailjs from 'emailjs-com'
export default {
name: 'AddAssetsView',
components: {
Card,
InputText,
Textarea,
Dropdown,
Button,
Message
},
data() {
return {
agentForm: {
name: '',
endpoint: '',
description: '',
loading: false,
message: '',
messageType: 'info'
},
assetForm: {
symbol: '',
type: '',
reason: '',
loading: false,
message: '',
messageType: 'info'
},
assetTypes: [
{ label: 'Stock', value: 'stock' },
{ label: 'Cryptocurrency', value: 'crypto' },
{ label: 'ETF', value: 'etf' },
{ label: 'Other', value: 'other' }
]
}
},
methods: {
async submitAgent() {
this.agentForm.loading = true
this.agentForm.message = ''
try {
// 保存到 localStorage 以便管理员查看
const agentSubmissions = JSON.parse(localStorage.getItem('agentSubmissions') || '[]')
agentSubmissions.push({
name: this.agentForm.name,
endpoint: this.agentForm.endpoint,
description: this.agentForm.description,
timestamp: new Date().toISOString()
})
localStorage.setItem('agentSubmissions', JSON.stringify(agentSubmissions))
this.agentForm.message = 'Agent submitted successfully! We will review it soon.'
this.agentForm.messageType = 'success'
// 滚动到消息位置
this.$nextTick(() => {
const messageEl = this.$el.querySelector('.p-message')
if (messageEl) {
messageEl.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
})
// Clear form
setTimeout(() => {
this.agentForm.name = ''
this.agentForm.endpoint = ''
this.agentForm.description = ''
this.agentForm.message = ''
}, 5000)
} catch (error) {
console.error('Error submitting agent:', error)
this.agentForm.message = 'Failed to submit agent. Please try again.'
this.agentForm.messageType = 'error'
// 滚动到消息位置
this.$nextTick(() => {
const messageEl = this.$el.querySelector('.p-message')
if (messageEl) {
messageEl.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
})
} finally {
this.agentForm.loading = false
}
},
async submitAsset() {
this.assetForm.loading = true
this.assetForm.message = ''
try {
// 保存到 localStorage
const assetRequest = {
symbol: this.assetForm.symbol.toUpperCase(),
type: this.assetForm.type,
reason: this.assetForm.reason,
timestamp: new Date().toISOString(),
votes: 1
}
// 获取现有的请求列表
let requests = []
try {
const stored = localStorage.getItem('assetRequests')
if (stored) {
requests = JSON.parse(stored)
}
} catch (e) {
console.error('Error reading localStorage:', e)
}
// 检查是否已存在相同的 symbol
const existingIndex = requests.findIndex(r => r.symbol.toUpperCase() === assetRequest.symbol.toUpperCase())
if (existingIndex >= 0) {
// 如果已存在,增加投票数
requests[existingIndex].votes += 1
requests[existingIndex].timestamp = assetRequest.timestamp
} else {
// 否则添加新请求
requests.push(assetRequest)
}
// 保存到 localStorage
localStorage.setItem('assetRequests', JSON.stringify(requests))
// 延迟跳转,让用户看到动画
await new Promise(resolve => setTimeout(resolve, 500))
// 跳转到结果页面
this.$router.push('/asset-requests')
} catch (error) {
console.error('Error submitting asset:', error)
this.assetForm.message = 'Failed to submit request. Please try again.'
this.assetForm.messageType = 'error'
// 滚动到错误消息
this.$nextTick(() => {
const messageEl = this.$el.querySelectorAll('.p-message')[1]
if (messageEl) {
messageEl.scrollIntoView({ behavior: 'smooth', block: 'center' })
}
})
} finally {
this.assetForm.loading = false
}
}
}
}
</script>
<style scoped>
.page-container {
max-width: 1400px;
margin: 0 auto;
padding: 1rem;
}
.title-container {
text-align: center;
margin-bottom: 2rem;
}
.main-title {
font-size: 2rem;
letter-spacing: -0.02em;
font-weight: 800;
color: #1f1f33;
}
.cards-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));
gap: 2rem;
padding: 0 1rem;
}
.feature-card {
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: transform 0.2s, box-shadow 0.2s;
}
.feature-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
.card-title {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 1.25rem;
font-weight: 700;
color: #1f1f33;
}
.card-title i {
font-size: 1.5rem;
color: var(--primary-color);
}
.form-container {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.field {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.field label {
font-weight: 600;
color: #4b5563;
font-size: 0.95rem;
}
:deep(.p-inputtext),
:deep(.p-dropdown),
:deep(.p-inputtextarea) {
border-radius: 8px;
border: 1px solid #d1d5db;
padding: 0.75rem;
}
:deep(.p-inputtext:focus),
:deep(.p-dropdown:focus),
:deep(.p-inputtextarea:focus) {
border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
}
:deep(.p-button) {
border-radius: 8px;
padding: 0.75rem;
font-weight: 600;
margin-top: 0.5rem;
}
:deep(.p-message) {
border-radius: 8px;
margin-top: 0.5rem;
}
@media (max-width: 768px) {
.cards-container {
grid-template-columns: 1fr;
padding: 0 0.5rem;
}
.main-title {
font-size: 1.5rem;
}
}
</style>