Enhance Prices view with admin batch actions and UI improvements

This commit is contained in:
wood chen 2025-02-08 21:30:28 +08:00
parent 1d16333e11
commit 7b884cd3ee
3 changed files with 143 additions and 31 deletions

View File

@ -7,6 +7,11 @@
<span>价格列表</span>
</div>
<div class="header-buttons">
<template v-if="isAdmin && selectedPrices.length > 0">
<el-button type="success" @click="batchUpdateStatus('approved')">批量通过</el-button>
<el-button type="danger" @click="batchUpdateStatus('rejected')">批量拒绝</el-button>
<el-divider direction="vertical" />
</template>
<el-button type="primary" @click="handleBatchAdd">批量添加</el-button>
<el-button type="primary" @click="handleAdd">提交价格</el-button>
</div>
@ -38,7 +43,12 @@
</div>
</div>
<el-table :data="filteredPrices" style="width: 100%">
<el-table
:data="filteredPrices"
style="width: 100%"
@selection-change="handlePriceSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column label="模型">
<template #default="{ row }">
<div class="value-container">
@ -49,7 +59,7 @@
</div>
</template>
</el-table-column>
<el-table-column label="计费类型">
<el-table-column label="计费类型" width="120">
<template #default="{ row }">
<div class="value-container">
<span>{{ getBillingType(row.billing_type) }}</span>
@ -59,7 +69,7 @@
</div>
</template>
</el-table-column>
<el-table-column label="模型厂商">
<el-table-column label="模型厂商" width="180">
<template #default="{ row }">
<div class="value-container">
<div style="display: flex; align-items: center; gap: 8px">
@ -76,7 +86,7 @@
</div>
</template>
</el-table-column>
<el-table-column label="货币">
<el-table-column label="货币" width="80">
<template #default="{ row }">
<div class="value-container">
<span>{{ row.currency }}</span>
@ -86,52 +96,69 @@
</div>
</template>
</el-table-column>
<el-table-column label="输入价格(M)">
<el-table-column label="输入价格(M)" width="120">
<template #default="{ row }">
<div class="value-container">
<span>{{ row.input_price }}</span>
<el-tag v-if="row.temp_input_price" type="warning" size="small" effect="light">
待审核: {{ row.temp_input_price }}
<span>{{ row.input_price === 0 ? '免费' : row.input_price }}</span>
<el-tag v-if="row.temp_input_price !== null && row.temp_input_price !== undefined" type="warning" size="small" effect="light">
待审核: {{ row.temp_input_price === 0 ? '免费' : row.temp_input_price }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="输出价格(M)">
<el-table-column label="输出价格(M)" width="120">
<template #default="{ row }">
<div class="value-container">
<span>{{ row.output_price }}</span>
<el-tag v-if="row.temp_output_price" type="warning" size="small" effect="light">
待审核: {{ row.temp_output_price }}
<span>{{ row.output_price === 0 ? '免费' : row.output_price }}</span>
<el-tag v-if="row.temp_output_price !== null && row.temp_output_price !== undefined" type="warning" size="small" effect="light">
待审核: {{ row.temp_output_price === 0 ? '免费' : row.temp_output_price }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="输入倍率">
<el-table-column label="输入倍率" width="120">
<template #default="{ row }">
{{ calculateRate(row.input_price, row.currency) }}
{{ row.input_price === 0 ? '免费' : calculateRate(row.input_price, row.currency) }}
</template>
</el-table-column>
<el-table-column label="输出倍率">
<el-table-column label="输出倍率" width="120">
<template #default="{ row }">
{{ calculateRate(row.output_price, row.currency) }}
{{ row.output_price === 0 ? '免费' : calculateRate(row.output_price, row.currency) }}
</template>
</el-table-column>
<el-table-column label="价格来源">
<el-table-column label="创建者" width="110">
<template #default="{ row }">
<div class="value-container">
<span>{{ row.price_source }}</span>
<el-tag v-if="row.temp_price_source" type="warning" size="small" effect="light">
待审核: {{ row.temp_price_source }}
</el-tag>
</div>
<span class="creator-name">{{ row.created_by }}</span>
</template>
</el-table-column>
<el-table-column label="状态">
<el-table-column v-if="isAdmin" width="180">
<template #default="{ row }">
{{ getStatus(row.status) }}
<el-popover
placement="left"
:width="200"
trigger="hover"
>
<template #reference>
<el-button link type="primary">详情</el-button>
</template>
<div class="price-detail">
<div class="detail-item">
<span class="detail-label">价格来源:</span>
<div class="detail-value">
<span>{{ row.price_source }}</span>
<el-tag v-if="row.temp_price_source !== null && row.temp_price_source !== undefined" type="warning" size="small" effect="light">
待审核: {{ row.temp_price_source }}
</el-tag>
</div>
</div>
<div class="detail-item">
<span class="detail-label">状态:</span>
<span class="detail-value">{{ getStatus(row.status) }}</span>
</div>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="created_by" label="创建者" />
<el-table-column v-if="isAdmin" label="操作" width="200">
<template #default="{ row }">
<el-button-group>
@ -610,7 +637,16 @@ const handleImport = () => {
const lines = importText.value.trim().split('\n')
const newRows = lines.map(line => {
const [model, billingType, providerName, currency, inputPrice, outputPrice] = line.trim().split(/\s+/)
// 使
const matches = line.trim().match(/("[^"]+"|[^\s]+)/g)
if (!matches || matches.length < 6) {
ElMessage.warning(`行格式不正确:${line}`)
return null
}
const [model, billingType, providerNameRaw, currency, inputPrice, outputPrice] = matches
//
const providerName = providerNameRaw.replace(/^"|"$/g, '')
// ID
const provider = providers.value.find(p => p.name === providerName)
@ -636,7 +672,7 @@ const handleImport = () => {
}
return {
model,
model: model.replace(/^"|"$/g, ''),
billing_type,
channel_type: provider.id.toString(),
currency: currencyCode,
@ -654,6 +690,51 @@ const handleImport = () => {
}
}
const selectedPrices = ref([])
const handlePriceSelectionChange = (selection) => {
selectedPrices.value = selection
}
const batchUpdateStatus = async (status) => {
if (!selectedPrices.value.length) {
ElMessage.warning('请先选择要审核的价格')
return
}
//
const pendingPrices = selectedPrices.value.filter(price => price.status === 'pending')
if (!pendingPrices.length) {
ElMessage.warning('选中的价格中没有待审核的项目')
return
}
try {
//
await ElMessageBox.confirm(
`确定要${status === 'approved' ? '通过' : '拒绝'}选中的 ${pendingPrices.length} 条待审核价格吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: status === 'approved' ? 'success' : 'warning'
}
)
//
for (const price of pendingPrices) {
await axios.put(`/api/prices/${price.id}/status`, { status })
}
await loadPrices()
ElMessage.success('批量审核成功')
} catch (error) {
if (error === 'cancel') return
console.error('Failed to batch update status:', error)
ElMessage.error('批量审核失败')
}
}
onMounted(async () => {
await loadPrices()
try {
@ -791,4 +872,35 @@ onMounted(async () => {
justify-content: flex-end;
margin-top: 8px;
}
.price-detail {
display: flex;
flex-direction: column;
gap: 12px;
}
.detail-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.detail-label {
color: #909399;
font-size: 13px;
}
.detail-value {
display: flex;
flex-direction: column;
gap: 4px;
}
.creator-name {
display: inline-block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -9,13 +9,13 @@
</template>
<el-table :data="sortedProviders" style="width: 100%">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="id" label="ID" />
<el-table-column label="名称">
<template #default="{ row }">
{{ row.name }}
</template>
</el-table-column>
<el-table-column label="图标" width="100">
<el-table-column label="图标">
<template #default="{ row }">
<el-image
v-if="row.icon"

View File

@ -7,7 +7,7 @@ export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
target: 'https://aimodels-prices.q58.pro',
changeOrigin: true
}
}