优化资产订阅页面,新增用户类型选择功能,支持在开通服务时选择租户模块类型,同时优化开通成功后的跳转逻辑,增加5秒内防重复触发402状态码的保护机制,避免开通完成后立即跳转又触发未开通提示的循环问题
This commit is contained in:
@@ -86,6 +86,64 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: #475569;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.type-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.type-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.type-card {
|
||||
background: #fff;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.type-card:hover {
|
||||
border-color: #10b981;
|
||||
background: #f0fdf4;
|
||||
}
|
||||
|
||||
.type-card.selected {
|
||||
border-color: #10b981;
|
||||
background: #ecfdf5;
|
||||
}
|
||||
|
||||
.type-card.selected::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: #10b981 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E") center/12px no-repeat;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.type-card .type-name {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.sku-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
@@ -292,7 +350,7 @@
|
||||
<!-- 导航 -->
|
||||
<nav class="auth-navbar">
|
||||
<div class="auth-navbar-container">
|
||||
<a href="index.html" class="auth-back-link">
|
||||
<a href="/index.html#/home" class="auth-back-link">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
|
||||
返回首页
|
||||
</a>
|
||||
@@ -326,8 +384,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户类型选择 -->
|
||||
<div id="type-section" style="display: none;">
|
||||
<div class="section-title">选择类型</div>
|
||||
<div id="type-list" class="type-grid"></div>
|
||||
</div>
|
||||
|
||||
<!-- SKU 列表 -->
|
||||
<div id="sku-list" class="sku-grid" style="display: none;"></div>
|
||||
<div id="sku-section" style="display: none;">
|
||||
<div class="section-title">选择套餐</div>
|
||||
<div id="sku-list" class="sku-grid"></div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div id="empty" class="empty-container" style="display: none;">
|
||||
@@ -350,13 +417,16 @@
|
||||
|
||||
<script>
|
||||
// API 基础地址
|
||||
const API_BASE = 'http://192.168.3.11:8000';
|
||||
const API_BASE_NEW = 'http://192.168.3.11:8000'; // 新功能服务(资产相关)
|
||||
const API_BASE_MAIN = 'http://192.168.3.11:8808'; // 主服务(系统相关)
|
||||
|
||||
// 页面状态
|
||||
let assetId = '';
|
||||
let returnUrl = '';
|
||||
let selectedSku = null;
|
||||
let selectedType = null;
|
||||
let assetData = null;
|
||||
let tenantModuleTypes = [];
|
||||
|
||||
// 初始化
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
@@ -387,7 +457,7 @@
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE}/assets/asset/getAssetAndSku?assetId=${assetId}`, {
|
||||
const response = await fetch(`${API_BASE_NEW}/assets/asset/getAssetAndSku?assetId=${assetId}`, {
|
||||
headers: headers
|
||||
});
|
||||
|
||||
@@ -407,7 +477,9 @@
|
||||
}
|
||||
|
||||
assetData = result.data;
|
||||
tenantModuleTypes = assetData.tenantModuleType || [];
|
||||
renderAssetInfo(assetData);
|
||||
renderTypeList(tenantModuleTypes);
|
||||
renderSkuList(assetData.skus || []);
|
||||
|
||||
} catch (error) {
|
||||
@@ -422,12 +494,57 @@
|
||||
function renderAssetInfo(data) {
|
||||
document.getElementById('asset-name').textContent = data.name || '服务';
|
||||
document.getElementById('asset-description').innerHTML = data.description || '';
|
||||
document.getElementById('asset-info').style.display = 'block';
|
||||
document.getElementById('asset-info').style.display = 'flex';
|
||||
}
|
||||
|
||||
// 渲染用户类型列表
|
||||
function renderTypeList(types) {
|
||||
const container = document.getElementById('type-list');
|
||||
const section = document.getElementById('type-section');
|
||||
|
||||
if (!types || types.length === 0) {
|
||||
section.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = types.map(type => `
|
||||
<div class="type-card" data-type-key="${type.key}" onclick="selectType('${type.key}')">
|
||||
<div class="type-name">${type.value}</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
section.style.display = 'block';
|
||||
|
||||
// 默认选中第一个
|
||||
if (types.length > 0) {
|
||||
selectType(types[0].key);
|
||||
}
|
||||
}
|
||||
|
||||
// 选择用户类型
|
||||
function selectType(typeKey) {
|
||||
// 移除之前的选中状态
|
||||
document.querySelectorAll('.type-card').forEach(card => {
|
||||
card.classList.remove('selected');
|
||||
});
|
||||
|
||||
// 添加选中状态
|
||||
const card = document.querySelector(`.type-card[data-type-key="${typeKey}"]`);
|
||||
if (card) {
|
||||
card.classList.add('selected');
|
||||
}
|
||||
|
||||
// 保存选中的类型
|
||||
selectedType = tenantModuleTypes.find(t => t.key === typeKey) || null;
|
||||
|
||||
// 更新按钮状态
|
||||
updateSubmitButton();
|
||||
}
|
||||
|
||||
// 渲染SKU列表
|
||||
function renderSkuList(skus) {
|
||||
const container = document.getElementById('sku-list');
|
||||
const section = document.getElementById('sku-section');
|
||||
const actions = document.getElementById('actions');
|
||||
const empty = document.getElementById('empty');
|
||||
|
||||
@@ -451,7 +568,7 @@
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
container.style.display = 'grid';
|
||||
section.style.display = 'block';
|
||||
actions.style.display = 'flex';
|
||||
|
||||
// 默认选中第一个
|
||||
@@ -477,7 +594,18 @@
|
||||
selectedSku = assetData?.skus?.find(s => s.id === skuId) || null;
|
||||
|
||||
// 更新按钮状态
|
||||
document.getElementById('btn-submit').disabled = !selectedSku;
|
||||
updateSubmitButton();
|
||||
}
|
||||
|
||||
// 更新提交按钮状态
|
||||
function updateSubmitButton() {
|
||||
const btn = document.getElementById('btn-submit');
|
||||
// 如果有用户类型选项,则需要同时选择类型和套餐
|
||||
if (tenantModuleTypes.length > 0) {
|
||||
btn.disabled = !selectedSku || !selectedType;
|
||||
} else {
|
||||
btn.disabled = !selectedSku;
|
||||
}
|
||||
}
|
||||
|
||||
// 开通服务
|
||||
@@ -487,22 +615,36 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有用户类型选项但未选择
|
||||
if (tenantModuleTypes.length > 0 && !selectedType) {
|
||||
alert('请选择用户类型');
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = document.getElementById('btn-submit');
|
||||
btn.disabled = true;
|
||||
btn.textContent = '开通中...';
|
||||
|
||||
try {
|
||||
const token = getToken();
|
||||
const response = await fetch(`${API_BASE}/assets/asset/subscribe`, {
|
||||
|
||||
// 构建请求参数
|
||||
const requestBody = {
|
||||
assetSkuId: selectedSku.id
|
||||
};
|
||||
|
||||
// 如果选择了用户类型,添加到请求参数
|
||||
if (selectedType) {
|
||||
requestBody.tenantModuleType = selectedType.key;
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_MAIN}/api/v1/system/moduleTenant/add`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': token ? `Bearer ${token}` : '',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
skuId: selectedSku.id,
|
||||
assetId: selectedSku.assetId
|
||||
})
|
||||
body: JSON.stringify(requestBody)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
@@ -512,15 +654,37 @@
|
||||
}
|
||||
|
||||
// 显示成功
|
||||
document.getElementById('sku-list').style.display = 'none';
|
||||
document.getElementById('type-section').style.display = 'none';
|
||||
document.getElementById('sku-section').style.display = 'none';
|
||||
document.getElementById('actions').style.display = 'none';
|
||||
document.getElementById('asset-info').style.display = 'none';
|
||||
document.getElementById('success').style.display = 'block';
|
||||
|
||||
// 设置开通时间标记,防止跳转后立即又触发402
|
||||
sessionStorage.setItem('lastSubscribeTime', Date.now().toString());
|
||||
|
||||
// 延迟跳转回原页面
|
||||
const targetUrl = decodeURIComponent(returnUrl);
|
||||
console.log('[subscribe] 开通成功,即将跳转到:', targetUrl);
|
||||
console.log('[subscribe] 原始 returnUrl:', returnUrl);
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = decodeURIComponent(returnUrl);
|
||||
}, 1500);
|
||||
let finalUrl;
|
||||
// 如果 returnUrl 包含当前开通页面路径,则跳转到首页
|
||||
if (targetUrl.includes('/web/subscribe') || targetUrl.includes('subscribe.html')) {
|
||||
console.log('[subscribe] returnUrl 指向开通页面,改为跳转首页');
|
||||
finalUrl = '/index.html#/home';
|
||||
} else {
|
||||
finalUrl = targetUrl;
|
||||
}
|
||||
|
||||
// 使用 replace 跳转,然后强制刷新
|
||||
window.location.replace(finalUrl);
|
||||
// 延迟一点再刷新,确保 URL 已经改变
|
||||
setTimeout(() => {
|
||||
window.location.reload(true);
|
||||
}, 100);
|
||||
}, 2000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('开通失败:', error);
|
||||
@@ -530,13 +694,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 取消
|
||||
// 取消 - 跳转到后台首页,避免循环触发402
|
||||
function handleCancel() {
|
||||
if (returnUrl) {
|
||||
window.location.href = decodeURIComponent(returnUrl);
|
||||
} else {
|
||||
window.location.href = 'index.html';
|
||||
}
|
||||
window.location.href = '/index.html#/home';
|
||||
}
|
||||
|
||||
// 获取Token(从Cookie获取)
|
||||
|
||||
Reference in New Issue
Block a user