This commit is contained in:
hrx 2026-07-22 17:20:34 +08:00
parent 2189cf34fd
commit 9465a005ba
3 changed files with 106 additions and 41 deletions

View File

@ -4,6 +4,10 @@
<router-view/> <router-view/>
<FloatingBox <FloatingBox
v-if="!$route.path.includes('kyyForm')&&!$route.path.includes('floatingBox')&&!$route.path.includes('screen')&&!$route.path.includes('wxPage')&&!$route.path.includes('wxDetailPage')"/> 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>
<!-- 弹出通话提示--> <!-- 弹出通话提示-->
<div v-if="isShowVideo" class="is-accepted" style="padding: 5px;border-radius: 6px"> <div v-if="isShowVideo" class="is-accepted" style="padding: 5px;border-radius: 6px">
@ -38,6 +42,7 @@
<script> <script>
import FloatingBox from './components/FloatingBox/FloatingBox.vue'; // import FloatingBox from './components/FloatingBox/FloatingBox.vue'; //
import LoginDialog from '@/views/LoginDialog/LoginDialog.vue'
import '@/assets/elementStyle.css' import '@/assets/elementStyle.css'
import Hammer from 'hammerjs'; import Hammer from 'hammerjs';
import {mapState} from "vuex"; import {mapState} from "vuex";
@ -45,6 +50,7 @@ export default {
name: "App", name: "App",
components: { components: {
FloatingBox, // FloatingBox, //
LoginDialog,
}, },
data() { data() {
return { return {
@ -52,7 +58,8 @@ export default {
socket: null, socket: null,
userId: sessionStorage.getItem('userId'), userId: sessionStorage.getItem('userId'),
vedioObj: {}, vedioObj: {},
customerName: '' customerName: '',
loginDialogVisible: false
} }
}, },
mounted() { mounted() {
@ -66,6 +73,10 @@ export default {
} }
this.setRemUnit() this.setRemUnit()
this.initHammer(); this.initHammer();
window.addEventListener('kboss-open-login-dialog', this.openGlobalLoginDialog)
},
beforeDestroy() {
window.removeEventListener('kboss-open-login-dialog', this.openGlobalLoginDialog)
}, },
computed: { computed: {
...mapState({ ...mapState({
@ -75,6 +86,16 @@ export default {
}) })
}, },
methods: { 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() { playAudio() {
console.log("开始按钮点击了") console.log("开始按钮点击了")
this.audioElement.play(); this.audioElement.play();

View File

@ -165,16 +165,8 @@ service.interceptors.response.use(
isRedirectingToLogin = true isRedirectingToLogin = true
saveLoginRedirectPath() saveLoginRedirectPath()
showErrorMessage('登录已过期,请重新登录') showErrorMessage('登录已过期,请重新登录')
const currentPath = (router.currentRoute && router.currentRoute.path) || '' window.dispatchEvent(new Event('kboss-open-login-dialog'))
const isHomePage = currentPath.includes('/homePage') || currentPath.includes('/ncmatchHome') isRedirectingToLogin = false
if (isHomePage) {
window.dispatchEvent(new Event('kboss-open-login-dialog'))
isRedirectingToLogin = false
} else {
router.push({path: '/login'}).finally(() => {
isRedirectingToLogin = false
})
}
} }
// window.location.href = 'https://www.opencomputing.cn/' // window.location.href = 'https://www.opencomputing.cn/'
} else if (code == 403) { } else if (code == 403) {

View File

@ -112,13 +112,20 @@
v-for="(product, index) in displayedTokenProducts" v-for="(product, index) in displayedTokenProducts"
:key="product.id" :key="product.id"
class="token-market-card" class="token-market-card"
@click="goModelDetail(product)" >
> <!-- @click="goModelDetail(product)" -->
<div class="token-card-top"> <div class="token-card-top">
<span class="token-provider-avatar"> <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 v-else>{{ getProviderInitial(product.provider || product.display_name || product.model_name) }}</span>
</span> </span>
<div class="token-title-group"> <div class="token-title-group">
<h3>{{ product.display_name || product.model_name }}</h3> <h3>{{ product.display_name || product.model_name }}</h3>
<p>{{ product.provider || product.model_name || '-' }}</p> <p>{{ product.provider || product.model_name || '-' }}</p>
@ -126,25 +133,17 @@
</div> </div>
<div class="token-price-grid"> <div class="token-price-grid">
<div class="token-price-item"> <div
<span>输入</span> v-for="(price, priceIndex) in getBillingPreview(product.billing_method)"
<strong>¥{{ formatTokenPrice(product.input_token_price) }}</strong> :key="`${product.id}-billing-${priceIndex}`"
<em>/百万 tokens</em> class="token-price-item"
>
<span>{{ price.name }}</span>
<strong>{{ price.price }}</strong>
<em>{{ price.desc }}</em>
</div> </div>
<div class="token-price-item"> <div v-if="getBillingMoreCount(product.billing_method)" class="billing-more-tip">
<span>输出</span> + {{ getBillingMoreCount(product.billing_method) }} 条计费规则进入详情查看
<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> </div>
</div> </div>
@ -395,6 +394,36 @@ export default {
return num.toFixed(4).replace(/\.?0+$/, ''); 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 // logo
getProviderInitial(provider) { getProviderInitial(provider) {
return provider ? provider.slice(0, 1) : 'M'; return provider ? provider.slice(0, 1) : 'M';
@ -408,6 +437,10 @@ export default {
return `${this.IMG_URL}${modelLogo}`; return `${this.IMG_URL}${modelLogo}`;
}, },
handleModelLogoError(product) {
this.$set(product, 'logoLoadFailed', true);
},
normalizeTokenConfigList(value) { normalizeTokenConfigList(value) {
if (!value) return []; if (!value) return [];
let parsedValue = value; let parsedValue = value;
@ -1471,13 +1504,18 @@ export default {
.token-price-grid { .token-price-grid {
position: relative; position: relative;
z-index: 1; z-index: 1;
display: grid; display: flex;
grid-template-columns: repeat(2, minmax(0, 1fr)); flex-direction: column;
gap: 8px 12px; gap: 5px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.token-price-item { .token-price-item {
padding: 7px 9px;
background: rgba(248, 250, 252, 0.86);
border: 1px solid #edf1f7;
border-radius: 10px;
span, span,
em { em {
display: block; display: block;
@ -1488,22 +1526,36 @@ export default {
span { span {
margin-bottom: 2px; margin-bottom: 2px;
font-size: 11px; font-size: 11px;
font-weight: 700;
} }
strong { strong {
display: block; display: block;
color: #111827; color: #0f172a;
font-size: 15px; font-size: 13px;
font-weight: 800; font-weight: 800;
line-height: 1.1; line-height: 1.25;
} }
em { em {
margin-top: 0; margin-top: 2px;
font-size: 10px; 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 { .token-description {
position: relative; position: relative;
z-index: 1; z-index: 1;
@ -1558,8 +1610,8 @@ export default {
img { img {
display: block; display: block;
width: 100%; width: 34px;
height: 100%; height: 34px;
object-fit: cover; object-fit: cover;
} }
} }