mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +00:00
[API Nodes] Add credit management panel UI (#3535)
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
const { defineConfig } = require('@lobehub/i18n-cli');
|
const { defineConfig } = require('@lobehub/i18n-cli');
|
||||||
|
|
||||||
module.exports = defineConfig({
|
module.exports = defineConfig({
|
||||||
modelName: 'o4-mini',
|
modelName: 'gpt-4.1',
|
||||||
splitToken: 1024,
|
splitToken: 1024,
|
||||||
entry: 'src/locales/en',
|
entry: 'src/locales/en',
|
||||||
entryLocale: 'en',
|
entryLocale: 'en',
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
</PanelTemplate>
|
</PanelTemplate>
|
||||||
|
|
||||||
<AboutPanel />
|
<AboutPanel />
|
||||||
|
<CreditsPanel />
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<KeybindingPanel />
|
<KeybindingPanel />
|
||||||
<template #fallback>
|
<template #fallback>
|
||||||
@@ -90,6 +91,7 @@ import { flattenTree } from '@/utils/treeUtil'
|
|||||||
|
|
||||||
import AboutPanel from './setting/AboutPanel.vue'
|
import AboutPanel from './setting/AboutPanel.vue'
|
||||||
import ColorPaletteMessage from './setting/ColorPaletteMessage.vue'
|
import ColorPaletteMessage from './setting/ColorPaletteMessage.vue'
|
||||||
|
import CreditsPanel from './setting/CreditsPanel.vue'
|
||||||
import CurrentUserMessage from './setting/CurrentUserMessage.vue'
|
import CurrentUserMessage from './setting/CurrentUserMessage.vue'
|
||||||
import FirstTimeUIMessage from './setting/FirstTimeUIMessage.vue'
|
import FirstTimeUIMessage from './setting/FirstTimeUIMessage.vue'
|
||||||
import PanelTemplate from './setting/PanelTemplate.vue'
|
import PanelTemplate from './setting/PanelTemplate.vue'
|
||||||
|
|||||||
130
src/components/dialog/content/setting/CreditsPanel.vue
Normal file
130
src/components/dialog/content/setting/CreditsPanel.vue
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<template>
|
||||||
|
<TabPanel value="Credits" class="credits-container h-full">
|
||||||
|
<div class="flex flex-col h-full">
|
||||||
|
<h2 class="text-2xl font-bold mb-2">
|
||||||
|
{{ $t('credits.credits') }}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<h3 class="text-sm font-medium text-muted">
|
||||||
|
{{ $t('credits.yourCreditBalance') }}
|
||||||
|
</h3>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<Tag
|
||||||
|
severity="secondary"
|
||||||
|
icon="pi pi-dollar"
|
||||||
|
rounded
|
||||||
|
class="text-amber-400 p-1"
|
||||||
|
/>
|
||||||
|
<div class="text-3xl font-bold">{{ creditBalance }}</div>
|
||||||
|
</div>
|
||||||
|
<Button :label="$t('credits.purchaseCredits')" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider class="mt-12" />
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<h3 class="text-base font-medium">
|
||||||
|
{{ $t('credits.creditsHistory') }}
|
||||||
|
</h3>
|
||||||
|
<Button
|
||||||
|
:label="$t('credits.paymentDetails')"
|
||||||
|
text
|
||||||
|
severity="secondary"
|
||||||
|
icon="pi pi-arrow-up-right"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-grow">
|
||||||
|
<DataTable :value="creditHistory" :show-headers="false">
|
||||||
|
<Column field="title" :header="$t('g.name')">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<div class="text-sm font-medium">{{ data.title }}</div>
|
||||||
|
<div class="text-xs text-muted">{{ data.timestamp }}</div>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
<Column field="amount" :header="$t('g.amount')">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'text-base font-medium text-center',
|
||||||
|
data.isPositive ? 'text-sky-500' : 'text-red-400'
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
{{ data.isPositive ? '+' : '-' }}{{ data.amount }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
|
<Button
|
||||||
|
:label="$t('credits.faqs')"
|
||||||
|
text
|
||||||
|
severity="secondary"
|
||||||
|
icon="pi pi-question-circle"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
:label="$t('credits.messageSupport')"
|
||||||
|
text
|
||||||
|
severity="secondary"
|
||||||
|
icon="pi pi-comments"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabPanel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
import Column from 'primevue/column'
|
||||||
|
import DataTable from 'primevue/datatable'
|
||||||
|
import Divider from 'primevue/divider'
|
||||||
|
import TabPanel from 'primevue/tabpanel'
|
||||||
|
import Tag from 'primevue/tag'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
// Mock data - in a real implementation, this would come from a store or API
|
||||||
|
const creditBalance = ref(0.05)
|
||||||
|
|
||||||
|
interface CreditHistoryItemData {
|
||||||
|
title: string
|
||||||
|
timestamp: string
|
||||||
|
amount: number
|
||||||
|
isPositive: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const creditHistory = ref<CreditHistoryItemData[]>([
|
||||||
|
{
|
||||||
|
title: 'Kling Text-to-Video v1-6',
|
||||||
|
timestamp: '2025-04-09, 12:50:08 p.m.',
|
||||||
|
amount: 4,
|
||||||
|
isPositive: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Kling Text-to-Video v1-6',
|
||||||
|
timestamp: '2025-04-09, 12:50:08 p.m.',
|
||||||
|
amount: 23,
|
||||||
|
isPositive: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Kling Text-to-Video v1-6',
|
||||||
|
timestamp: '2025-04-09, 12:50:08 p.m.',
|
||||||
|
amount: 22,
|
||||||
|
isPositive: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Free monthly credits',
|
||||||
|
timestamp: '2025-04-09, 12:46:08 p.m.',
|
||||||
|
amount: 166,
|
||||||
|
isPositive: true
|
||||||
|
}
|
||||||
|
])
|
||||||
|
</script>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||||
import { SettingTreeNode, useSettingStore } from '@/stores/settingStore'
|
import { SettingTreeNode, useSettingStore } from '@/stores/settingStore'
|
||||||
import type { SettingParams } from '@/types/settingTypes'
|
import type { SettingParams } from '@/types/settingTypes'
|
||||||
import { isElectron } from '@/utils/envUtil'
|
import { isElectron } from '@/utils/envUtil'
|
||||||
@@ -11,6 +12,7 @@ export function useSettingUI(
|
|||||||
defaultPanel?: 'about' | 'keybinding' | 'extension' | 'server-config'
|
defaultPanel?: 'about' | 'keybinding' | 'extension' | 'server-config'
|
||||||
) {
|
) {
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
const firebaseAuthStore = useFirebaseAuthStore()
|
||||||
const settingStore = useSettingStore()
|
const settingStore = useSettingStore()
|
||||||
const activeCategory = ref<SettingTreeNode | null>(null)
|
const activeCategory = ref<SettingTreeNode | null>(null)
|
||||||
|
|
||||||
@@ -47,6 +49,12 @@ export function useSettingUI(
|
|||||||
children: []
|
children: []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const creditsPanelNode: SettingTreeNode = {
|
||||||
|
key: 'credits',
|
||||||
|
label: 'Credits',
|
||||||
|
children: []
|
||||||
|
}
|
||||||
|
|
||||||
const keybindingPanelNode: SettingTreeNode = {
|
const keybindingPanelNode: SettingTreeNode = {
|
||||||
key: 'keybinding',
|
key: 'keybinding',
|
||||||
label: 'Keybinding',
|
label: 'Keybinding',
|
||||||
@@ -91,6 +99,16 @@ export function useSettingUI(
|
|||||||
})
|
})
|
||||||
|
|
||||||
const groupedMenuTreeNodes = computed<SettingTreeNode[]>(() => [
|
const groupedMenuTreeNodes = computed<SettingTreeNode[]>(() => [
|
||||||
|
// Account settings - only show when user is authenticated
|
||||||
|
...(firebaseAuthStore.isAuthenticated
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
key: 'account',
|
||||||
|
label: 'Account',
|
||||||
|
children: [creditsPanelNode].map(translateCategory)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: []),
|
||||||
// Normal settings stored in the settingStore
|
// Normal settings stored in the settingStore
|
||||||
{
|
{
|
||||||
key: 'settings',
|
key: 'settings',
|
||||||
|
|||||||
@@ -110,7 +110,8 @@
|
|||||||
"migrate": "Migrate",
|
"migrate": "Migrate",
|
||||||
"updateAvailable": "Update Available",
|
"updateAvailable": "Update Available",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"learnMore": "Learn more"
|
"learnMore": "Learn more",
|
||||||
|
"amount": "Amount"
|
||||||
},
|
},
|
||||||
"manager": {
|
"manager": {
|
||||||
"title": "Custom Nodes Manager",
|
"title": "Custom Nodes Manager",
|
||||||
@@ -1107,5 +1108,14 @@
|
|||||||
"special": "Must contain at least one special character",
|
"special": "Must contain at least one special character",
|
||||||
"match": "Passwords must match"
|
"match": "Passwords must match"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"credits": {
|
||||||
|
"credits": "Credits",
|
||||||
|
"yourCreditBalance": "Your credit balance",
|
||||||
|
"purchaseCredits": "Purchase Credits",
|
||||||
|
"creditsHistory": "Credits History",
|
||||||
|
"paymentDetails": "Payment Details",
|
||||||
|
"faqs": "FAQs",
|
||||||
|
"messageSupport": "Message Support"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,6 +92,15 @@
|
|||||||
"Title": "Título",
|
"Title": "Título",
|
||||||
"Unpin": "Desanclar"
|
"Unpin": "Desanclar"
|
||||||
},
|
},
|
||||||
|
"credits": {
|
||||||
|
"credits": "Créditos",
|
||||||
|
"creditsHistory": "Historial de créditos",
|
||||||
|
"faqs": "Preguntas frecuentes",
|
||||||
|
"messageSupport": "Contactar soporte",
|
||||||
|
"paymentDetails": "Detalles de pago",
|
||||||
|
"purchaseCredits": "Comprar créditos",
|
||||||
|
"yourCreditBalance": "Tu saldo de créditos"
|
||||||
|
},
|
||||||
"dataTypes": {
|
"dataTypes": {
|
||||||
"AUDIO": "AUDIO",
|
"AUDIO": "AUDIO",
|
||||||
"BOOLEAN": "BOOLEANO",
|
"BOOLEAN": "BOOLEANO",
|
||||||
@@ -168,6 +177,7 @@
|
|||||||
"about": "Acerca de",
|
"about": "Acerca de",
|
||||||
"add": "Añadir",
|
"add": "Añadir",
|
||||||
"all": "Todo",
|
"all": "Todo",
|
||||||
|
"amount": "Cantidad",
|
||||||
"apply": "Aplicar",
|
"apply": "Aplicar",
|
||||||
"back": "Atrás",
|
"back": "Atrás",
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
|
|||||||
@@ -92,6 +92,15 @@
|
|||||||
"Title": "Titre",
|
"Title": "Titre",
|
||||||
"Unpin": "Désépingler"
|
"Unpin": "Désépingler"
|
||||||
},
|
},
|
||||||
|
"credits": {
|
||||||
|
"credits": "Crédits",
|
||||||
|
"creditsHistory": "Historique des crédits",
|
||||||
|
"faqs": "FAQ",
|
||||||
|
"messageSupport": "Contacter le support",
|
||||||
|
"paymentDetails": "Détails de paiement",
|
||||||
|
"purchaseCredits": "Acheter des crédits",
|
||||||
|
"yourCreditBalance": "Votre solde de crédits"
|
||||||
|
},
|
||||||
"dataTypes": {
|
"dataTypes": {
|
||||||
"AUDIO": "AUDIO",
|
"AUDIO": "AUDIO",
|
||||||
"BOOLEAN": "BOOLEAN",
|
"BOOLEAN": "BOOLEAN",
|
||||||
@@ -168,6 +177,7 @@
|
|||||||
"about": "À propos",
|
"about": "À propos",
|
||||||
"add": "Ajouter",
|
"add": "Ajouter",
|
||||||
"all": "Tout",
|
"all": "Tout",
|
||||||
|
"amount": "Quantité",
|
||||||
"apply": "Appliquer",
|
"apply": "Appliquer",
|
||||||
"back": "Retour",
|
"back": "Retour",
|
||||||
"cancel": "Annuler",
|
"cancel": "Annuler",
|
||||||
|
|||||||
@@ -92,6 +92,15 @@
|
|||||||
"Title": "タイトル",
|
"Title": "タイトル",
|
||||||
"Unpin": "ピンを解除"
|
"Unpin": "ピンを解除"
|
||||||
},
|
},
|
||||||
|
"credits": {
|
||||||
|
"credits": "クレジット",
|
||||||
|
"creditsHistory": "クレジット履歴",
|
||||||
|
"faqs": "よくある質問",
|
||||||
|
"messageSupport": "サポートにメッセージ",
|
||||||
|
"paymentDetails": "支払い詳細",
|
||||||
|
"purchaseCredits": "クレジットを購入",
|
||||||
|
"yourCreditBalance": "あなたのクレジット残高"
|
||||||
|
},
|
||||||
"dataTypes": {
|
"dataTypes": {
|
||||||
"AUDIO": "オーディオ",
|
"AUDIO": "オーディオ",
|
||||||
"BOOLEAN": "ブール",
|
"BOOLEAN": "ブール",
|
||||||
@@ -168,6 +177,7 @@
|
|||||||
"about": "情報",
|
"about": "情報",
|
||||||
"add": "追加",
|
"add": "追加",
|
||||||
"all": "すべて",
|
"all": "すべて",
|
||||||
|
"amount": "量",
|
||||||
"apply": "適用する",
|
"apply": "適用する",
|
||||||
"back": "戻る",
|
"back": "戻る",
|
||||||
"cancel": "キャンセル",
|
"cancel": "キャンセル",
|
||||||
|
|||||||
@@ -92,6 +92,15 @@
|
|||||||
"Title": "제목",
|
"Title": "제목",
|
||||||
"Unpin": "고정 해제"
|
"Unpin": "고정 해제"
|
||||||
},
|
},
|
||||||
|
"credits": {
|
||||||
|
"credits": "크레딧",
|
||||||
|
"creditsHistory": "크레딧 내역",
|
||||||
|
"faqs": "자주 묻는 질문",
|
||||||
|
"messageSupport": "지원 문의",
|
||||||
|
"paymentDetails": "결제 정보",
|
||||||
|
"purchaseCredits": "크레딧 구매",
|
||||||
|
"yourCreditBalance": "보유 크레딧 잔액"
|
||||||
|
},
|
||||||
"dataTypes": {
|
"dataTypes": {
|
||||||
"AUDIO": "오디오",
|
"AUDIO": "오디오",
|
||||||
"BOOLEAN": "논리값",
|
"BOOLEAN": "논리값",
|
||||||
@@ -168,6 +177,7 @@
|
|||||||
"about": "정보",
|
"about": "정보",
|
||||||
"add": "추가",
|
"add": "추가",
|
||||||
"all": "모두",
|
"all": "모두",
|
||||||
|
"amount": "수량",
|
||||||
"apply": "적용",
|
"apply": "적용",
|
||||||
"back": "뒤로",
|
"back": "뒤로",
|
||||||
"cancel": "취소",
|
"cancel": "취소",
|
||||||
|
|||||||
@@ -92,6 +92,15 @@
|
|||||||
"Title": "Заголовок",
|
"Title": "Заголовок",
|
||||||
"Unpin": "Открепить"
|
"Unpin": "Открепить"
|
||||||
},
|
},
|
||||||
|
"credits": {
|
||||||
|
"credits": "Кредиты",
|
||||||
|
"creditsHistory": "История кредитов",
|
||||||
|
"faqs": "Часто задаваемые вопросы",
|
||||||
|
"messageSupport": "Связаться с поддержкой",
|
||||||
|
"paymentDetails": "Детали оплаты",
|
||||||
|
"purchaseCredits": "Купить кредиты",
|
||||||
|
"yourCreditBalance": "Ваш баланс кредитов"
|
||||||
|
},
|
||||||
"dataTypes": {
|
"dataTypes": {
|
||||||
"AUDIO": "АУДИО",
|
"AUDIO": "АУДИО",
|
||||||
"BOOLEAN": "БУЛЕВО",
|
"BOOLEAN": "БУЛЕВО",
|
||||||
@@ -168,6 +177,7 @@
|
|||||||
"about": "О программе",
|
"about": "О программе",
|
||||||
"add": "Добавить",
|
"add": "Добавить",
|
||||||
"all": "Все",
|
"all": "Все",
|
||||||
|
"amount": "Количество",
|
||||||
"apply": "Применить",
|
"apply": "Применить",
|
||||||
"back": "Назад",
|
"back": "Назад",
|
||||||
"cancel": "Отмена",
|
"cancel": "Отмена",
|
||||||
|
|||||||
@@ -92,6 +92,15 @@
|
|||||||
"Title": "标题",
|
"Title": "标题",
|
||||||
"Unpin": "取消固定"
|
"Unpin": "取消固定"
|
||||||
},
|
},
|
||||||
|
"credits": {
|
||||||
|
"credits": "积分",
|
||||||
|
"creditsHistory": "积分历史",
|
||||||
|
"faqs": "常见问题",
|
||||||
|
"messageSupport": "联系客服",
|
||||||
|
"paymentDetails": "支付详情",
|
||||||
|
"purchaseCredits": "购买积分",
|
||||||
|
"yourCreditBalance": "您的积分余额"
|
||||||
|
},
|
||||||
"dataTypes": {
|
"dataTypes": {
|
||||||
"AUDIO": "音频",
|
"AUDIO": "音频",
|
||||||
"BOOLEAN": "布尔",
|
"BOOLEAN": "布尔",
|
||||||
@@ -168,6 +177,7 @@
|
|||||||
"about": "关于",
|
"about": "关于",
|
||||||
"add": "添加",
|
"add": "添加",
|
||||||
"all": "全部",
|
"all": "全部",
|
||||||
|
"amount": "数量",
|
||||||
"apply": "应用",
|
"apply": "应用",
|
||||||
"back": "返回",
|
"back": "返回",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
|
|||||||
Reference in New Issue
Block a user