mirror of
https://github.com/woodchen-ink/aimodels-prices.git
synced 2025-07-18 13:41:59 +08:00
Add batch price submission and improve UI for price list view
This commit is contained in:
parent
e7967dfeff
commit
7873fab16f
@ -6,7 +6,10 @@
|
|||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<span>价格列表</span>
|
<span>价格列表</span>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" @click="handleAdd">提交价格</el-button>
|
<div class="header-buttons">
|
||||||
|
<el-button type="primary" @click="handleBatchAdd">批量添加</el-button>
|
||||||
|
<el-button type="primary" @click="handleAdd">提交价格</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -38,27 +41,27 @@
|
|||||||
<el-table :data="filteredPrices" style="width: 100%">
|
<el-table :data="filteredPrices" style="width: 100%">
|
||||||
<el-table-column label="模型">
|
<el-table-column label="模型">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>
|
<div class="value-container">
|
||||||
<div>{{ row.model }}</div>
|
<span>{{ row.model }}</span>
|
||||||
<div v-if="row.temp_model" class="pending-update">
|
<el-tag v-if="row.temp_model" type="warning" size="small" effect="light">
|
||||||
待审核: {{ row.temp_model }}
|
待审核: {{ row.temp_model }}
|
||||||
</div>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="计费类型">
|
<el-table-column label="计费类型">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>
|
<div class="value-container">
|
||||||
<div>{{ getBillingType(row.billing_type) }}</div>
|
<span>{{ getBillingType(row.billing_type) }}</span>
|
||||||
<div v-if="row.temp_billing_type" class="pending-update">
|
<el-tag v-if="row.temp_billing_type" type="warning" size="small" effect="light">
|
||||||
待审核: {{ getBillingType(row.temp_billing_type) }}
|
待审核: {{ getBillingType(row.temp_billing_type) }}
|
||||||
</div>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="模型厂商">
|
<el-table-column label="模型厂商">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>
|
<div class="value-container">
|
||||||
<div style="display: flex; align-items: center; gap: 8px">
|
<div style="display: flex; align-items: center; gap: 8px">
|
||||||
<el-image
|
<el-image
|
||||||
v-if="getProvider(row.channel_type)?.icon"
|
v-if="getProvider(row.channel_type)?.icon"
|
||||||
@ -67,39 +70,39 @@
|
|||||||
/>
|
/>
|
||||||
<span>{{ getProvider(row.channel_type)?.name || row.channel_type }}</span>
|
<span>{{ getProvider(row.channel_type)?.name || row.channel_type }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="row.temp_channel_type" class="pending-update">
|
<el-tag v-if="row.temp_channel_type" type="warning" size="small" effect="light">
|
||||||
待审核: {{ getProvider(row.temp_channel_type)?.name || row.temp_channel_type }}
|
待审核: {{ getProvider(row.temp_channel_type)?.name || row.temp_channel_type }}
|
||||||
</div>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="货币">
|
<el-table-column label="货币">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>
|
<div class="value-container">
|
||||||
<div>{{ row.currency }}</div>
|
<span>{{ row.currency }}</span>
|
||||||
<div v-if="row.temp_currency" class="pending-update">
|
<el-tag v-if="row.temp_currency" type="warning" size="small" effect="light">
|
||||||
待审核: {{ row.temp_currency }}
|
待审核: {{ row.temp_currency }}
|
||||||
</div>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="输入价格(M)">
|
<el-table-column label="输入价格(M)">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>
|
<div class="value-container">
|
||||||
<div>{{ row.input_price }}</div>
|
<span>{{ row.input_price }}</span>
|
||||||
<div v-if="row.temp_input_price !== null" class="pending-update">
|
<el-tag v-if="row.temp_input_price" type="warning" size="small" effect="light">
|
||||||
待审核: {{ row.temp_input_price }}
|
待审核: {{ row.temp_input_price }}
|
||||||
</div>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="输出价格(M)">
|
<el-table-column label="输出价格(M)">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>
|
<div class="value-container">
|
||||||
<div>{{ row.output_price }}</div>
|
<span>{{ row.output_price }}</span>
|
||||||
<div v-if="row.temp_output_price !== null" class="pending-update">
|
<el-tag v-if="row.temp_output_price" type="warning" size="small" effect="light">
|
||||||
待审核: {{ row.temp_output_price }}
|
待审核: {{ row.temp_output_price }}
|
||||||
</div>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -115,11 +118,11 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="价格来源">
|
<el-table-column label="价格来源">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div>
|
<div class="value-container">
|
||||||
<div>{{ row.price_source }}</div>
|
<span>{{ row.price_source }}</span>
|
||||||
<div v-if="row.temp_price_source" class="pending-update">
|
<el-tag v-if="row.temp_price_source" type="warning" size="small" effect="light">
|
||||||
待审核: {{ row.temp_price_source }}
|
待审核: {{ row.temp_price_source }}
|
||||||
</div>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -142,6 +145,90 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 批量添加对话框 -->
|
||||||
|
<el-dialog v-model="batchDialogVisible" title="批量添加模型价格" width="90%">
|
||||||
|
<div class="batch-add-container">
|
||||||
|
<div class="batch-toolbar">
|
||||||
|
<el-button type="primary" @click="addRow">添加行</el-button>
|
||||||
|
<el-button type="danger" @click="removeSelectedRows" :disabled="!selectedRows.length">删除选中行</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table
|
||||||
|
:data="batchForms"
|
||||||
|
style="width: 100%"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
height="400"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<el-table-column label="模型" width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.model" placeholder="请输入模型名称" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="计费类型" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-select v-model="row.billing_type" placeholder="请选择">
|
||||||
|
<el-option label="按量计费" value="tokens" />
|
||||||
|
<el-option label="按次计费" value="times" />
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="模型厂商" width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-select v-model="row.channel_type" placeholder="请选择">
|
||||||
|
<el-option
|
||||||
|
v-for="provider in providers"
|
||||||
|
:key="provider.id"
|
||||||
|
:label="provider.name"
|
||||||
|
:value="provider.id.toString()"
|
||||||
|
>
|
||||||
|
<div style="display: flex; align-items: center; gap: 8px">
|
||||||
|
<el-image
|
||||||
|
v-if="provider.icon"
|
||||||
|
:src="provider.icon"
|
||||||
|
style="width: 24px; height: 24px"
|
||||||
|
/>
|
||||||
|
<span>{{ provider.name }}</span>
|
||||||
|
</div>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="货币" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-select v-model="row.currency" placeholder="请选择">
|
||||||
|
<el-option label="美元" value="USD" />
|
||||||
|
<el-option label="人民币" value="CNY" />
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="输入价格(M)" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number v-model="row.input_price" :precision="4" :step="0.0001" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="输出价格(M)" width="150">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input-number v-model="row.output_price" :precision="4" :step="0.0001" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="价格来源">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.price_source" placeholder="请输入价格来源" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="batchDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitBatchForms" :loading="batchSubmitting">
|
||||||
|
{{ batchSubmitting ? '提交中...' : '确定' }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 现有的单个添加对话框 -->
|
||||||
<el-dialog v-model="dialogVisible" title="提交价格">
|
<el-dialog v-model="dialogVisible" title="提交价格">
|
||||||
<el-form :model="form" label-width="120px">
|
<el-form :model="form" label-width="120px">
|
||||||
<el-form-item label="模型">
|
<el-form-item label="模型">
|
||||||
@ -401,6 +488,91 @@ const updateStatus = async (id, status) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量添加相关的状态
|
||||||
|
const batchDialogVisible = ref(false)
|
||||||
|
const batchForms = ref([])
|
||||||
|
const selectedRows = ref([])
|
||||||
|
const batchSubmitting = ref(false)
|
||||||
|
|
||||||
|
// 创建新行的默认数据
|
||||||
|
const createNewRow = () => ({
|
||||||
|
model: '',
|
||||||
|
billing_type: 'tokens',
|
||||||
|
channel_type: '',
|
||||||
|
currency: 'USD',
|
||||||
|
input_price: 0,
|
||||||
|
output_price: 0,
|
||||||
|
price_source: '',
|
||||||
|
created_by: props.user?.username || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加新行
|
||||||
|
const addRow = () => {
|
||||||
|
batchForms.value.push(createNewRow())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理选择变化
|
||||||
|
const handleSelectionChange = (rows) => {
|
||||||
|
selectedRows.value = rows
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除选中的行
|
||||||
|
const removeSelectedRows = () => {
|
||||||
|
const selectedIds = new Set(selectedRows.value.map(row => batchForms.value.indexOf(row)))
|
||||||
|
batchForms.value = batchForms.value.filter((_, index) => !selectedIds.has(index))
|
||||||
|
selectedRows.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开批量添加对话框
|
||||||
|
const handleBatchAdd = () => {
|
||||||
|
if (!props.user) {
|
||||||
|
router.push('/login')
|
||||||
|
ElMessage.warning('请先登录')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
batchForms.value = [createNewRow()]
|
||||||
|
batchDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交批量表单
|
||||||
|
const submitBatchForms = async () => {
|
||||||
|
if (!batchForms.value.length) {
|
||||||
|
ElMessage.warning('请至少添加一条数据')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证数据
|
||||||
|
const invalidForms = batchForms.value.filter(form =>
|
||||||
|
!form.model || !form.channel_type || !form.price_source
|
||||||
|
)
|
||||||
|
|
||||||
|
if (invalidForms.length) {
|
||||||
|
ElMessage.error('请填写完整所有必填字段')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
batchSubmitting.value = true
|
||||||
|
try {
|
||||||
|
// 逐个提交数据
|
||||||
|
for (const form of batchForms.value) {
|
||||||
|
await axios.post('/api/prices', form)
|
||||||
|
}
|
||||||
|
|
||||||
|
await loadPrices()
|
||||||
|
batchDialogVisible.value = false
|
||||||
|
ElMessage.success('批量添加成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to submit batch prices:', error)
|
||||||
|
if (error.response?.data?.error) {
|
||||||
|
ElMessage.error(error.response.data.error)
|
||||||
|
} else {
|
||||||
|
ElMessage.error('批量添加失败')
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
batchSubmitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadPrices()
|
await loadPrices()
|
||||||
try {
|
try {
|
||||||
@ -472,12 +644,43 @@ onMounted(async () => {
|
|||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pending-update {
|
.value-container {
|
||||||
font-size: 12px;
|
display: flex;
|
||||||
color: #E6A23C;
|
flex-direction: column;
|
||||||
margin-top: 4px;
|
gap: 4px;
|
||||||
padding: 2px 4px;
|
}
|
||||||
background-color: #FDF6EC;
|
|
||||||
border-radius: 2px;
|
.value-container :deep(.el-tag) {
|
||||||
|
margin: 0;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-container span {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-add-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-toolbar {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input-number) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-select) {
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
Loading…
x
Reference in New Issue
Block a user