feat: 配额优化
This commit is contained in:
100
frontend/app/web-gold/src/components/PointsTag.vue
Normal file
100
frontend/app/web-gold/src/components/PointsTag.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<span v-if="displayText" :class="['points-tag', `points-tag--${size}`, { 'points-tag--free': isFree }]">
|
||||
<span v-if="showIcon" class="points-tag__icon">⚡</span>
|
||||
<span class="points-tag__text">{{ displayText }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { usePointsConfigStore } from '@/stores/pointsConfig'
|
||||
|
||||
const props = defineProps({
|
||||
// 模型代码
|
||||
modelCode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 直接传入积分数(优先级高于 modelCode)
|
||||
points: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
// 尺寸
|
||||
size: {
|
||||
type: String,
|
||||
default: 'default', // small, default, large
|
||||
validator: (value) => ['small', 'default', 'large'].includes(value)
|
||||
},
|
||||
// 是否显示图标
|
||||
showIcon: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const pointsConfigStore = usePointsConfigStore()
|
||||
|
||||
// 获取积分数
|
||||
const consumePoints = computed(() => {
|
||||
if (props.points !== null) {
|
||||
return props.points
|
||||
}
|
||||
if (props.modelCode) {
|
||||
return pointsConfigStore.getConsumePoints(props.modelCode)
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
// 是否免费
|
||||
const isFree = computed(() => consumePoints.value === 0)
|
||||
|
||||
// 显示文本
|
||||
const displayText = computed(() => {
|
||||
if (consumePoints.value === null) {
|
||||
return ''
|
||||
}
|
||||
return pointsConfigStore.formatPoints(consumePoints.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.points-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
|
||||
&--small {
|
||||
padding: 1px 6px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
&--default {
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&--large {
|
||||
padding: 4px 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&--free {
|
||||
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
&__text {
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<teleport to="body">
|
||||
<transition name="drawer-fade">
|
||||
<div v-if="visible" class="chat-overlay" @click.self="handleOverlayClick">
|
||||
<div v-if="visible" class="chat-overlay" @click.self="handleClose">
|
||||
<div class="chat-drawer" :class="{ 'chat-drawer--visible': visible }" @click.stop>
|
||||
<!-- Background Effect -->
|
||||
<div class="drawer-bg-pattern"></div>
|
||||
@@ -104,7 +104,7 @@
|
||||
@click="modelMode = 'standard'"
|
||||
>
|
||||
标准
|
||||
<span class="model-cost">-10 积分</span>
|
||||
<PointsTag :points="10" size="small" />
|
||||
</button>
|
||||
<button
|
||||
class="model-tab pro"
|
||||
@@ -113,7 +113,7 @@
|
||||
>
|
||||
<ThunderboltFilled />
|
||||
深度
|
||||
<span class="model-cost">-50 积分</span>
|
||||
<PointsTag :points="50" size="small" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -157,7 +157,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, nextTick } from 'vue'
|
||||
import { ref, watch, nextTick, onMounted } from 'vue'
|
||||
import {
|
||||
CloseOutlined,
|
||||
RobotOutlined,
|
||||
@@ -173,6 +173,15 @@ import { message, Modal } from 'ant-design-vue'
|
||||
import { sendChatStream } from '@/api/agent'
|
||||
import { copyToClipboard } from '@/utils/clipboard'
|
||||
import HistoryPanel from './HistoryPanel.vue'
|
||||
import PointsTag from '@/components/PointsTag.vue'
|
||||
import { usePointsConfigStore } from '@/stores/pointsConfig'
|
||||
|
||||
const pointsConfigStore = usePointsConfigStore()
|
||||
|
||||
// 在组件挂载时加载积分配置
|
||||
onMounted(() => {
|
||||
pointsConfigStore.loadConfig()
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
visible: { type: Boolean, default: false },
|
||||
@@ -232,8 +241,6 @@ const doClose = () => {
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
const handleOverlayClick = () => handleClose()
|
||||
|
||||
const adjustTextareaHeight = () => {
|
||||
const el = textareaRef.value
|
||||
if (el) {
|
||||
|
||||
Reference in New Issue
Block a user