Skip to content

Commit 934300c

Browse files
committed
wip: refactor providers
1 parent 4dfa3f4 commit 934300c

File tree

14 files changed

+137
-27
lines changed

14 files changed

+137
-27
lines changed

ui/src/components/AppSidebar.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ zh-CN:
112112
appDescription: AI Token 聚合服务
113113
navigation: 导航
114114
appManagement: 应用管理
115-
models: 模型提供商
115+
models: 模型管理
116116
usage: 用量统计
117117
tools: 工具
118118
settings: 设置

ui/src/components/ManualConfigCard.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ async function handleManualConfigSave(config: ManualConfig) {
4949
</CardContent>
5050

5151
<CardFooter>
52-
<Button class="w-full" @click="showEditDialog = true">
52+
<Button class="w-full" variant="secondary" @click="showEditDialog = true">
5353
{{ t('add') }}
5454
</Button>
5555
</CardFooter>

ui/src/components/ProviderCard.vue

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import type { Provider } from '@/lib/providers'
3+
import { ExternalLinkIcon } from 'lucide-vue-next'
34
import { computed, onMounted, ref } from 'vue'
45
import { useI18n } from 'vue-i18n'
56
import { toast } from 'vue-sonner'
@@ -29,6 +30,11 @@ onMounted(async () => {
2930
})
3031
3132
function handleRecharge() {
33+
if ('websiteURL' in props.provider.payment!) {
34+
window.open(props.provider.payment!.websiteURL, '_blank', 'width=600,height=600,noopener=yes,noreferrer=yes')
35+
return
36+
}
37+
3238
if (!userInfo.value?.verified) {
3339
toast.error(t('realNameRequired'))
3440
openRealNameDialog.value = true
@@ -76,7 +82,10 @@ function handleRecharge() {
7682
</div>
7783
<div v-if="userInfo.balance != null" class="flex justify-between items-center text-sm">
7884
<span class="text-muted-foreground">{{ t('balance') }}</span>
79-
<span class="font-medium">{{ userInfo.balance }} {{ t('yuan') }}</span>
85+
<span class="font-medium">
86+
{{ userInfo.balance.currency === 'USD' ? '$' : '' }}{{ userInfo.balance.amount }}
87+
{{ userInfo.balance.currency === 'CNY' ? t('yuan') : userInfo.balance.currency === 'USD' ? '' : `(${userInfo.balance.currency})` }}
88+
</span>
8089
</div>
8190
</div>
8291
</CardContent>
@@ -87,6 +96,7 @@ function handleRecharge() {
8796
<div class="flex-grow" />
8897
<Button v-if="!!provider.payment" variant="secondary" size="sm" class="h-8" @click="handleRecharge">
8998
{{ t('recharge') }}
99+
<ExternalLinkIcon v-if="'websiteURL' in provider.payment" />
90100
</Button>
91101
<Button variant="secondary" size="sm" class="h-8" @click="provider.logout">
92102
{{ t('logout') }}
@@ -101,7 +111,7 @@ function handleRecharge() {
101111
<i18n lang="yaml">
102112
zh-CN:
103113
loggedIn: 已登录
104-
realname: 实名
114+
realname: 实名认证
105115
verified: 已认证
106116
unverified: 未认证
107117
phone: 手机
@@ -123,7 +133,7 @@ en-US:
123133
unverified: Unverified
124134
phone: Phone
125135
balance: Balance
126-
yuan: Yuan
136+
yuan: CNY
127137
createKey: Create Key
128138
confirmCreateKey: Confirm Create Key
129139
confirmCreateKeyDescription: Are you sure you want to create a new API key? This will generate a new access key for your account.

ui/src/components/ProviderName.vue

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script setup lang="ts">
2+
import type { Provider } from '@/lib/providers'
3+
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
4+
5+
defineProps<{
6+
provider: Provider
7+
}>()
8+
</script>
9+
10+
<template>
11+
<div class="flex gap-2 items-center text-lg">
12+
<img :src="provider.logo" :alt="provider.name" class="w-5 mb-1 rounded">
13+
{{ provider.name }}
14+
</div>
15+
</template>

ui/src/components/ProviderPaymentDialog.vue

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import type { Provider } from '@/lib/providers'
3+
import { CircleQuestionMarkIcon } from 'lucide-vue-next'
34
import { renderSVG } from 'uqr'
45
import { computed, onUnmounted, ref } from 'vue'
56
import { useI18n } from 'vue-i18n'
@@ -14,6 +15,12 @@ import {
1415
DialogTitle,
1516
} from '@/components/ui/dialog'
1617
import { Input } from '@/components/ui/input'
18+
import {
19+
Tooltip,
20+
TooltipContent,
21+
TooltipProvider,
22+
TooltipTrigger,
23+
} from '@/components/ui/tooltip'
1724
1825
const props = defineProps<{
1926
provider: Provider
@@ -137,6 +144,16 @@ function clear() {
137144
<DialogTitle>{{ t('accountRecharge') }}</DialogTitle>
138145
<DialogDescription class="flex">
139146
{{ t('accountRechargeDescription', [provider.name]) }}
147+
<TooltipProvider>
148+
<Tooltip ignore-non-keyboard-focus>
149+
<TooltipTrigger>
150+
<CircleQuestionMarkIcon class="w-4 h-4 ml-1" />
151+
</TooltipTrigger>
152+
<TooltipContent>
153+
{{ t('accountRechargeTooltip', [provider.name]) }}
154+
</TooltipContent>
155+
</Tooltip>
156+
</TooltipProvider>
140157
<div class="flex-grow" />
141158
<div v-if="qrcSvg" class="text-sm text-muted-foreground">
142159
{{ formAmount }} {{ t('currency') }}
@@ -235,6 +252,7 @@ en-US:
235252
paymentPending: Payment Not Completed
236253
generating: Generating...
237254
generatePaymentQRCode: Generate Payment QR Code
255+
accountRechargeTooltip: The funds will be directly recharged to your {0} account without going through the UniToken platform, ensuring the safety of your funds.
238256
239257
zh-CN:
240258
accountRecharge: 账户充值
@@ -252,4 +270,5 @@ zh-CN:
252270
paymentPending: 支付未完成
253271
generating: 生成中...
254272
generatePaymentQRCode: 生成支付二维码
273+
accountRechargeTooltip: 钱款会直接充值到您的{0}账户,不会经过 UniToken 平台,保证您的资金安全。
255274
</i18n>

ui/src/components/ProvidersSection.vue

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { shallowRef } from 'vue'
44
import { useI18n } from 'vue-i18n'
55
import ManualConfigCard from '@/components/ManualConfigCard.vue'
66
import ProviderConfigDialog from '@/components/ProviderConfigDialog.vue'
7+
import ProviderName from '@/components/ProviderName.vue'
78
import { Button } from '@/components/ui/button'
89
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
910
import { useProviders } from '@/lib/providers'
@@ -23,16 +24,14 @@ const showProviderDialog = shallowRef<Provider | null>(null)
2324
</div>
2425

2526
<div class="flex-grow flex flex-col">
26-
<!-- Static cards for configuration (not draggable) -->
27-
<div class="grid gap-4 grid-cols-2 lg:grid-cols-3 mb-4">
28-
<!-- SiliconFlow configuration card (if not configured) -->
29-
<Card v-for="provider in providers" :key="provider.id" class="relative gap-2">
27+
<div class="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
28+
<Card v-for="provider in providers" :key="provider.id" class="relative gap-2 hover:bg-secondary" @click="showProviderDialog = provider">
3029
<CardHeader>
31-
<div class="flex items-center justify-between">
32-
<CardTitle class="text-lg">
33-
{{ provider.name }}
30+
<div class="flex items-center justify-between flex-wrap gap-2">
31+
<CardTitle class="flex ">
32+
<ProviderName :provider="provider" />
3433
</CardTitle>
35-
<div v-show="provider.user !== undefined" class="flex items-center gap-2">
34+
<div v-if="provider.user !== undefined" class="flex items-center gap-2 self-end">
3635
<span
3736
class="inline-flex items-center rounded-full px-2 py-1 text-xs font-medium text-accent-foreground"
3837
:class="{
@@ -50,22 +49,15 @@ const showProviderDialog = shallowRef<Provider | null>(null)
5049
<div class="text-sm text-muted-foreground">
5150
<p>
5251
{{ t('description1') }}
53-
<a :href="provider.homepage" target="_blank" class="text-blue-900 dark:text-blue-200 hover:underline">
52+
<a :href="provider.homepage" target="_blank" class="text-blue-900 dark:text-blue-200 hover:underline" @click.stop>
5453
{{ provider.name }}
5554
</a>
5655
{{ t('description2') }}
5756
</p>
5857
</div>
5958
</CardContent>
60-
61-
<CardFooter>
62-
<Button class="w-full" @click="showProviderDialog = provider">
63-
{{ t('configure', [provider.name]) }}
64-
</Button>
65-
</CardFooter>
6659
</Card>
6760

68-
<!-- Manual Configuration Provider Card -->
6961
<ManualConfigCard class="relative gap-2" />
7062
</div>
7163
</div>
@@ -86,7 +78,6 @@ zh-CN:
8678
description2: 购买和配置 API
8779
loggedIn: 已登录
8880
loggedOut: 未登录
89-
configure: 配置 {0}
9081
9182
en-US:
9283
title: Model Providers
@@ -95,5 +86,4 @@ en-US:
9586
description2: ''
9687
loggedIn: Logged In
9788
loggedOut: Logged Out
98-
configure: Configure {0}
9989
</i18n>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script setup lang="ts">
2+
import type { HTMLAttributes } from "vue"
3+
import { AvatarRoot } from "reka-ui"
4+
import { cn } from "@/lib/utils"
5+
6+
const props = defineProps<{
7+
class?: HTMLAttributes["class"]
8+
}>()
9+
</script>
10+
11+
<template>
12+
<AvatarRoot
13+
data-slot="avatar"
14+
:class="cn('relative flex size-8 shrink-0 overflow-hidden rounded-full', props.class)"
15+
>
16+
<slot />
17+
</AvatarRoot>
18+
</template>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<script setup lang="ts">
2+
import type { AvatarFallbackProps } from "reka-ui"
3+
import type { HTMLAttributes } from "vue"
4+
import { reactiveOmit } from "@vueuse/core"
5+
import { AvatarFallback } from "reka-ui"
6+
import { cn } from "@/lib/utils"
7+
8+
const props = defineProps<AvatarFallbackProps & { class?: HTMLAttributes["class"] }>()
9+
10+
const delegatedProps = reactiveOmit(props, "class")
11+
</script>
12+
13+
<template>
14+
<AvatarFallback
15+
data-slot="avatar-fallback"
16+
v-bind="delegatedProps"
17+
:class="cn('bg-muted flex size-full items-center justify-center rounded-full', props.class)"
18+
>
19+
<slot />
20+
</AvatarFallback>
21+
</template>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script setup lang="ts">
2+
import type { AvatarImageProps } from "reka-ui"
3+
import { AvatarImage } from "reka-ui"
4+
5+
const props = defineProps<AvatarImageProps>()
6+
</script>
7+
8+
<template>
9+
<AvatarImage
10+
data-slot="avatar-image"
11+
v-bind="props"
12+
class="aspect-square size-full"
13+
>
14+
<slot />
15+
</AvatarImage>
16+
</template>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { default as Avatar } from "./Avatar.vue"
2+
export { default as AvatarFallback } from "./AvatarFallback.vue"
3+
export { default as AvatarImage } from "./AvatarImage.vue"

0 commit comments

Comments
 (0)