Compare commits

...

2 Commits

Author SHA1 Message Date
hrx
f979732c21 Merge branch 'main' of git.opencomputing.cn:yumoqing/kboss 2026-07-22 17:20:51 +08:00
hrx
9465a005ba 更新 2026-07-22 17:20:34 +08:00
3 changed files with 106 additions and 41 deletions

View File

@ -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();

View File

@ -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) {

View File

@ -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;
}
}