Merge branch 'main' of https://git.opencomputing.cn/yumoqing/kboss
This commit is contained in:
commit
f9cc1ed903
@ -4,6 +4,10 @@
|
||||
<router-view/>
|
||||
<FloatingBox
|
||||
v-if="!$route.path.includes('kyyForm')&&!$route.path.includes('floatingBox')&&!$route.path.includes('screen')&&!$route.path.includes('wxPage')&&!$route.path.includes('wxDetailPage')"/>
|
||||
<LoginDialog
|
||||
:visible.sync="loginDialogVisible"
|
||||
@success="handleGlobalLoginSuccess"
|
||||
/>
|
||||
<div>
|
||||
<!-- 弹出通话提示-->
|
||||
<div v-if="isShowVideo" class="is-accepted" style="padding: 5px;border-radius: 6px">
|
||||
@ -38,6 +42,7 @@
|
||||
<script>
|
||||
|
||||
import FloatingBox from './components/FloatingBox/FloatingBox.vue'; // 导入悬浮框组件
|
||||
import LoginDialog from '@/views/LoginDialog/LoginDialog.vue'
|
||||
import '@/assets/elementStyle.css'
|
||||
import Hammer from 'hammerjs';
|
||||
import {mapState} from "vuex";
|
||||
@ -45,6 +50,7 @@ export default {
|
||||
name: "App",
|
||||
components: {
|
||||
FloatingBox, // 注册悬浮框组件
|
||||
LoginDialog,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -52,7 +58,8 @@ export default {
|
||||
socket: null,
|
||||
userId: sessionStorage.getItem('userId'),
|
||||
vedioObj: {},
|
||||
customerName: ''
|
||||
customerName: '',
|
||||
loginDialogVisible: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -66,6 +73,10 @@ export default {
|
||||
}
|
||||
this.setRemUnit()
|
||||
this.initHammer();
|
||||
window.addEventListener('kboss-open-login-dialog', this.openGlobalLoginDialog)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('kboss-open-login-dialog', this.openGlobalLoginDialog)
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
@ -75,6 +86,16 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
openGlobalLoginDialog() {
|
||||
if (this.$route && this.$route.fullPath && !this.$route.fullPath.includes('/login')) {
|
||||
sessionStorage.setItem('loginRedirectPath', this.$route.fullPath)
|
||||
}
|
||||
this.loginDialogVisible = true
|
||||
},
|
||||
handleGlobalLoginSuccess() {
|
||||
this.loginDialogVisible = false
|
||||
this.userId = sessionStorage.getItem('userId')
|
||||
},
|
||||
playAudio() {
|
||||
console.log("开始按钮点击了")
|
||||
this.audioElement.play();
|
||||
|
||||
@ -165,16 +165,8 @@ service.interceptors.response.use(
|
||||
isRedirectingToLogin = true
|
||||
saveLoginRedirectPath()
|
||||
showErrorMessage('登录已过期,请重新登录')
|
||||
const currentPath = (router.currentRoute && router.currentRoute.path) || ''
|
||||
const isHomePage = currentPath.includes('/homePage') || currentPath.includes('/ncmatchHome')
|
||||
if (isHomePage) {
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
isRedirectingToLogin = false
|
||||
} else {
|
||||
router.push({path: '/login'}).finally(() => {
|
||||
isRedirectingToLogin = false
|
||||
})
|
||||
}
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
isRedirectingToLogin = false
|
||||
}
|
||||
// window.location.href = 'https://www.opencomputing.cn/'
|
||||
} else if (code == 403) {
|
||||
|
||||
@ -112,13 +112,20 @@
|
||||
v-for="(product, index) in displayedTokenProducts"
|
||||
:key="product.id"
|
||||
class="token-market-card"
|
||||
@click="goModelDetail(product)"
|
||||
>
|
||||
>
|
||||
<!-- @click="goModelDetail(product)" -->
|
||||
|
||||
<div class="token-card-top">
|
||||
<span class="token-provider-avatar">
|
||||
<img v-if="product.model_logo" :src="getModelLogoUrl(product.model_logo)" alt="">
|
||||
<img
|
||||
v-if="product.model_logo && !product.logoLoadFailed"
|
||||
:src="getModelLogoUrl(product.model_logo)"
|
||||
alt=""
|
||||
@error="handleModelLogoError(product)"
|
||||
>
|
||||
<span v-else>{{ getProviderInitial(product.provider || product.display_name || product.model_name) }}</span>
|
||||
</span>
|
||||
|
||||
<div class="token-title-group">
|
||||
<h3>{{ product.display_name || product.model_name }}</h3>
|
||||
<p>{{ product.provider || product.model_name || '-' }}</p>
|
||||
@ -126,25 +133,17 @@
|
||||
</div>
|
||||
|
||||
<div class="token-price-grid">
|
||||
<div class="token-price-item">
|
||||
<span>输入</span>
|
||||
<strong>¥{{ formatTokenPrice(product.input_token_price) }}</strong>
|
||||
<em>元/百万 tokens</em>
|
||||
<div
|
||||
v-for="(price, priceIndex) in getBillingPreview(product.billing_method)"
|
||||
:key="`${product.id}-billing-${priceIndex}`"
|
||||
class="token-price-item"
|
||||
>
|
||||
<span>{{ price.name }}</span>
|
||||
<strong>{{ price.price }}</strong>
|
||||
<em>{{ price.desc }}</em>
|
||||
</div>
|
||||
<div class="token-price-item">
|
||||
<span>输出</span>
|
||||
<strong>¥{{ formatTokenPrice(product.output_token_price) }}</strong>
|
||||
<em>元/百万 tokens</em>
|
||||
</div>
|
||||
<div class="token-price-item">
|
||||
<span>缓存读</span>
|
||||
<strong>¥{{ formatTokenPrice(product.cache_hit_input_price) }}</strong>
|
||||
<em>元/百万 tokens</em>
|
||||
</div>
|
||||
<div class="token-price-item">
|
||||
<span>缓存创建</span>
|
||||
<strong>¥{{ formatTokenPrice(product.input_token_price) }}</strong>
|
||||
<em>元/百万 tokens</em>
|
||||
<div v-if="getBillingMoreCount(product.billing_method)" class="billing-more-tip">
|
||||
+ {{ getBillingMoreCount(product.billing_method) }} 条计费规则,进入详情查看
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -395,6 +394,36 @@ export default {
|
||||
return num.toFixed(4).replace(/\.?0+$/, '');
|
||||
},
|
||||
|
||||
parseBillingMethod(value) {
|
||||
const text = String(value || '').trim();
|
||||
if (!text) {
|
||||
return [{ name: '计费方式', price: '按量计费', desc: '详情以后端配置为准' }];
|
||||
}
|
||||
return text
|
||||
.split(/\n+/)
|
||||
.map(line => line.replace(/^\s*[-–—]\s*/, '').trim())
|
||||
.filter(Boolean)
|
||||
.map(line => {
|
||||
const match = line.match(/^([^::]+)[::]\s*([^\[]+)(?:\[(.+)\])?$/);
|
||||
if (!match) {
|
||||
return { name: '计费说明', price: line, desc: '' };
|
||||
}
|
||||
return {
|
||||
name: match[1].trim(),
|
||||
price: match[2].trim(),
|
||||
desc: (match[3] || '').trim()
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
getBillingPreview(value) {
|
||||
return this.parseBillingMethod(value).slice(0, 3);
|
||||
},
|
||||
|
||||
getBillingMoreCount(value) {
|
||||
return Math.max(this.parseBillingMethod(value).length - 3, 0);
|
||||
},
|
||||
|
||||
// 供应商头像取首字,避免没有 logo 时卡片显得空。
|
||||
getProviderInitial(provider) {
|
||||
return provider ? provider.slice(0, 1) : 'M';
|
||||
@ -408,6 +437,10 @@ export default {
|
||||
return `${this.IMG_URL}${modelLogo}`;
|
||||
},
|
||||
|
||||
handleModelLogoError(product) {
|
||||
this.$set(product, 'logoLoadFailed', true);
|
||||
},
|
||||
|
||||
normalizeTokenConfigList(value) {
|
||||
if (!value) return [];
|
||||
let parsedValue = value;
|
||||
@ -1471,13 +1504,18 @@ export default {
|
||||
.token-price-grid {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 8px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.token-price-item {
|
||||
padding: 7px 9px;
|
||||
background: rgba(248, 250, 252, 0.86);
|
||||
border: 1px solid #edf1f7;
|
||||
border-radius: 10px;
|
||||
|
||||
span,
|
||||
em {
|
||||
display: block;
|
||||
@ -1488,22 +1526,36 @@ export default {
|
||||
span {
|
||||
margin-bottom: 2px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
color: #111827;
|
||||
font-size: 15px;
|
||||
color: #0f172a;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
em {
|
||||
margin-top: 0;
|
||||
margin-top: 2px;
|
||||
font-size: 10px;
|
||||
line-height: 1.4;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.billing-more-tip {
|
||||
padding: 5px 9px;
|
||||
color: #2563eb;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
background: #eff6ff;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.token-description {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@ -1558,8 +1610,8 @@ export default {
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user