This commit is contained in:
@@ -57,6 +57,11 @@ export const productApi = {
|
|||||||
getProductApiConfigByCode: (productCode) => request.get(`/products/code/${productCode}/api-config`),
|
getProductApiConfigByCode: (productCode) => request.get(`/products/code/${productCode}/api-config`),
|
||||||
getProductApiConfigsByProductIDs: (productIds) => request.get('/products/api-configs', {
|
getProductApiConfigsByProductIDs: (productIds) => request.get('/products/api-configs', {
|
||||||
params: { product_ids: productIds.join(',') }
|
params: { product_ids: productIds.join(',') }
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 下载接口文档(支持PDF和Markdown)
|
||||||
|
downloadProductDocumentation: (productId) => request.get(`/products/${productId}/documentation/download`, {
|
||||||
|
responseType: 'blob'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +86,10 @@ export const subscriptionApi = {
|
|||||||
getMySubscriptionDetail: (id) => request.get(`/my/subscriptions/${id}`),
|
getMySubscriptionDetail: (id) => request.get(`/my/subscriptions/${id}`),
|
||||||
|
|
||||||
// 获取我的订阅使用情况 (需认证)
|
// 获取我的订阅使用情况 (需认证)
|
||||||
getMySubscriptionUsage: (id) => request.get(`/my/subscriptions/${id}/usage`)
|
getMySubscriptionUsage: (id) => request.get(`/my/subscriptions/${id}/usage`),
|
||||||
|
|
||||||
|
// 取消我的订阅 (需认证)
|
||||||
|
cancelMySubscription: (id) => request.post(`/my/subscriptions/${id}/cancel`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 财务相关接口
|
// 财务相关接口
|
||||||
|
|||||||
@@ -73,12 +73,12 @@
|
|||||||
<!-- 已订阅的产品 -->
|
<!-- 已订阅的产品 -->
|
||||||
<el-button
|
<el-button
|
||||||
v-else-if="isSubscribed"
|
v-else-if="isSubscribed"
|
||||||
type="info"
|
type="danger"
|
||||||
disabled
|
@click="handleCancelSubscribe"
|
||||||
class="action-btn subscribed-btn"
|
class="action-btn cancel-subscribe-btn"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
已订阅
|
取消订阅
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<!-- 可订阅的产品 -->
|
<!-- 可订阅的产品 -->
|
||||||
@@ -104,10 +104,14 @@ const props = defineProps({
|
|||||||
isSubscribed: {
|
isSubscribed: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
subscription: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['view-detail', 'subscribe'])
|
const emit = defineEmits(['view-detail', 'subscribe', 'cancel-subscribe'])
|
||||||
|
|
||||||
// 格式化价格
|
// 格式化价格
|
||||||
const formatPrice = (price) => {
|
const formatPrice = (price) => {
|
||||||
@@ -134,6 +138,11 @@ const handleViewDetail = () => {
|
|||||||
const handleSubscribe = () => {
|
const handleSubscribe = () => {
|
||||||
emit('subscribe', props.product)
|
emit('subscribe', props.product)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 取消订阅
|
||||||
|
const handleCancelSubscribe = () => {
|
||||||
|
emit('cancel-subscribe', props.product)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -357,19 +366,17 @@ const handleSubscribe = () => {
|
|||||||
box-shadow: 0 4px 8px rgba(16, 185, 129, 0.3);
|
box-shadow: 0 4px 8px rgba(16, 185, 129, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscribed-btn {
|
.cancel-subscribe-btn {
|
||||||
background: rgba(100, 116, 139, 0.1);
|
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
||||||
border-color: rgba(100, 116, 139, 0.2);
|
border-color: #ef4444;
|
||||||
color: #64748b;
|
color: white;
|
||||||
cursor: not-allowed;
|
box-shadow: 0 2px 4px rgba(239, 68, 68, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscribed-btn:hover {
|
.cancel-subscribe-btn:hover {
|
||||||
background: rgba(100, 116, 139, 0.1);
|
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
|
||||||
border-color: rgba(100, 116, 139, 0.2);
|
border-color: #dc2626;
|
||||||
color: #64748b;
|
box-shadow: 0 4px 8px rgba(239, 68, 68, 0.3);
|
||||||
transform: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.disabled-btn {
|
.disabled-btn {
|
||||||
|
|||||||
@@ -414,13 +414,25 @@
|
|||||||
<div v-if="decryptedData" class="mt-3 pt-3 border-t border-gray-200">
|
<div v-if="decryptedData" class="mt-3 pt-3 border-t border-gray-200">
|
||||||
<h5 class="text-xs font-semibold text-gray-700 mb-1">解密后的内容</h5>
|
<h5 class="text-xs font-semibold text-gray-700 mb-1">解密后的内容</h5>
|
||||||
<pre
|
<pre
|
||||||
class="bg-green-50 p-2 rounded text-xs overflow-x-auto m-0 mb-1.5 max-h-45 border border-green-200 font-mono text-green-800">
|
class="bg-green-50 p-2 rounded text-xs overflow-x-auto m-0 mb-1.5 max-h-45 border border-green-200 font-mono text-green-800"
|
||||||
|
:key="`decrypted-${Date.now()}`">
|
||||||
{{ JSON.stringify(decryptedData, null, 2) }}</pre>
|
{{ JSON.stringify(decryptedData, null, 2) }}</pre>
|
||||||
<el-button type="success" size="default"
|
<el-button type="success" size="default"
|
||||||
@click="copyToClipboard(JSON.stringify(decryptedData, null, 2))" class="w-full">
|
@click="copyToClipboard(JSON.stringify(decryptedData, null, 2))" class="w-full">
|
||||||
复制解密内容
|
复制解密内容
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 解密加载状态 -->
|
||||||
|
<div v-else-if="debugging && debugResult && debugResult.success && debugResult.response?.data?.data"
|
||||||
|
class="mt-3 pt-3 border-t border-gray-200">
|
||||||
|
<div class="flex items-center gap-2 text-sm text-gray-500">
|
||||||
|
<svg class="animate-spin h-4 w-4 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
</svg>
|
||||||
|
<span>正在解密响应数据...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -545,6 +557,8 @@ const productsLoading = ref(false)
|
|||||||
const debugging = ref(false)
|
const debugging = ref(false)
|
||||||
const encrypting = ref(false)
|
const encrypting = ref(false)
|
||||||
const autoSelecting = ref(false) // 新增:自动选择状态
|
const autoSelecting = ref(false) // 新增:自动选择状态
|
||||||
|
const isSelectingProduct = ref(false) // 防止重复选择产品的标志
|
||||||
|
const lastSelectedProductId = ref(null) // 记录最后选择的产品ID
|
||||||
const userProducts = ref([])
|
const userProducts = ref([])
|
||||||
const apiConfig = ref(null)
|
const apiConfig = ref(null)
|
||||||
const selectedProduct = ref(null)
|
const selectedProduct = ref(null)
|
||||||
@@ -650,12 +664,22 @@ onMounted(async () => {
|
|||||||
|
|
||||||
// 监听路由参数变化,自动选择产品
|
// 监听路由参数变化,自动选择产品
|
||||||
watch(
|
watch(
|
||||||
() => route.params.productId,
|
() => route.query.productId || route.params.productId,
|
||||||
async (newProductId) => {
|
async (newProductId, oldProductId) => {
|
||||||
|
// 防止重复触发:如果产品ID没有变化,不执行
|
||||||
|
if (newProductId === oldProductId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果正在选择产品,不重复执行
|
||||||
|
if (isSelectingProduct.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (newProductId && userProducts.value.length > 0) {
|
if (newProductId && userProducts.value.length > 0) {
|
||||||
await autoSelectProduct(newProductId)
|
await autoSelectProduct(newProductId)
|
||||||
} else if (!newProductId && userProducts.value.length > 0) {
|
} else if (!newProductId && userProducts.value.length > 0 && !selectedProduct.value) {
|
||||||
// 如果没有指定产品,选择第一个
|
// 如果没有指定产品且当前没有选中产品,选择第一个
|
||||||
await selectProduct(userProducts.value[0])
|
await selectProduct(userProducts.value[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -663,6 +687,18 @@ watch(
|
|||||||
|
|
||||||
// 自动选择产品
|
// 自动选择产品
|
||||||
const autoSelectProduct = async (productId) => {
|
const autoSelectProduct = async (productId) => {
|
||||||
|
// 防止重复执行
|
||||||
|
if (isSelectingProduct.value) {
|
||||||
|
console.log('正在选择产品,跳过重复请求')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果已经选择了相同的产品,不重复选择
|
||||||
|
if (lastSelectedProductId.value === productId && selectedProduct.value) {
|
||||||
|
console.log('产品已选择,跳过重复选择:', productId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 如果用户产品列表为空,等待加载完成
|
// 如果用户产品列表为空,等待加载完成
|
||||||
if (!userProducts.value.length) {
|
if (!userProducts.value.length) {
|
||||||
console.log('等待用户产品列表加载完成...')
|
console.log('等待用户产品列表加载完成...')
|
||||||
@@ -686,7 +722,13 @@ const autoSelectProduct = async (productId) => {
|
|||||||
|
|
||||||
if (targetProduct) {
|
if (targetProduct) {
|
||||||
console.log('自动选择产品:', targetProduct)
|
console.log('自动选择产品:', targetProduct)
|
||||||
await selectProduct(targetProduct)
|
isSelectingProduct.value = true
|
||||||
|
try {
|
||||||
|
await selectProduct(targetProduct)
|
||||||
|
lastSelectedProductId.value = productId
|
||||||
|
} finally {
|
||||||
|
isSelectingProduct.value = false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('未找到指定的产品:', productId)
|
console.warn('未找到指定的产品:', productId)
|
||||||
ElMessage.warning(`未找到产品ID为 ${productId} 的产品,请手动选择`)
|
ElMessage.warning(`未找到产品ID为 ${productId} 的产品,请手动选择`)
|
||||||
@@ -699,7 +741,7 @@ const loadUserProducts = async () => {
|
|||||||
try {
|
try {
|
||||||
const response = await subscriptionApi.getMySubscriptions({
|
const response = await subscriptionApi.getMySubscriptions({
|
||||||
page: 1,
|
page: 1,
|
||||||
page_size: 100
|
page_size: 1000
|
||||||
})
|
})
|
||||||
|
|
||||||
if (response.success && response.data?.items) {
|
if (response.success && response.data?.items) {
|
||||||
@@ -712,16 +754,23 @@ const loadUserProducts = async () => {
|
|||||||
}))
|
}))
|
||||||
console.log("route.params", route)
|
console.log("route.params", route)
|
||||||
|
|
||||||
// 检查是否有params参数指定产品
|
// 检查是否有query或params参数指定产品
|
||||||
if (route.params.productId && userProducts.value.length > 0) {
|
const productId = route.query.productId || route.params.productId
|
||||||
|
if (productId && userProducts.value.length > 0) {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
// 使用 autoSelectProduct 会自动处理防重复逻辑
|
||||||
await autoSelectProduct(route.params.productId)
|
await autoSelectProduct(productId)
|
||||||
} else if (userProducts.value.length > 0) {
|
} else if (userProducts.value.length > 0 && !selectedProduct.value) {
|
||||||
// 没有指定产品时,默认选择第一个
|
// 没有指定产品时,默认选择第一个(仅在未选择产品时)
|
||||||
autoSelecting.value = true
|
autoSelecting.value = true
|
||||||
await selectProduct(userProducts.value[0])
|
isSelectingProduct.value = true
|
||||||
autoSelecting.value = false
|
try {
|
||||||
|
await selectProduct(userProducts.value[0])
|
||||||
|
lastSelectedProductId.value = userProducts.value[0].id || userProducts.value[0].product_id
|
||||||
|
} finally {
|
||||||
|
isSelectingProduct.value = false
|
||||||
|
autoSelecting.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 如果没有订阅产品,显示提示信息
|
// 如果没有订阅产品,显示提示信息
|
||||||
@@ -753,6 +802,15 @@ const loadApiKeys = async () => {
|
|||||||
|
|
||||||
// 选择产品
|
// 选择产品
|
||||||
const selectProduct = async (product) => {
|
const selectProduct = async (product) => {
|
||||||
|
// 防止重复选择相同产品
|
||||||
|
const productId = product.product_id || product.id
|
||||||
|
if (selectedProduct.value &&
|
||||||
|
(selectedProduct.value.id === productId || selectedProduct.value.product_id === productId) &&
|
||||||
|
!isSelectingProduct.value) {
|
||||||
|
console.log('产品已选择,跳过重复加载:', productId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 确保API密钥已经加载
|
// 确保API密钥已经加载
|
||||||
if (!debugForm.accessId || !debugForm.secretKey) {
|
if (!debugForm.accessId || !debugForm.secretKey) {
|
||||||
ElMessage.warning('正在加载API密钥,请稍候...')
|
ElMessage.warning('正在加载API密钥,请稍候...')
|
||||||
@@ -764,6 +822,7 @@ const selectProduct = async (product) => {
|
|||||||
debugForm.params = {}
|
debugForm.params = {}
|
||||||
debugResult.value = null
|
debugResult.value = null
|
||||||
encryptedData.value = null
|
encryptedData.value = null
|
||||||
|
decryptedData.value = null
|
||||||
activeTab.value = 'basic_info' // 重置Tab
|
activeTab.value = 'basic_info' // 重置Tab
|
||||||
productDocumentation.value = null // 重置文档
|
productDocumentation.value = null // 重置文档
|
||||||
|
|
||||||
@@ -1106,6 +1165,11 @@ const handleDebug = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debugging.value = true
|
debugging.value = true
|
||||||
|
// 清空之前的调试结果,确保UI实时更新
|
||||||
|
debugResult.value = null
|
||||||
|
decryptedData.value = null
|
||||||
|
await nextTick() // 确保DOM更新
|
||||||
|
|
||||||
const startTime = new Date()
|
const startTime = new Date()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1118,22 +1182,6 @@ const handleDebug = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1.5. 类型转换:将 page_size 和 page_num 从字符串转换为数字
|
|
||||||
if (parsedParams && typeof parsedParams === 'object') {
|
|
||||||
if (parsedParams.page_size !== undefined && typeof parsedParams.page_size === 'string') {
|
|
||||||
const pageSize = parseInt(parsedParams.page_size, 10)
|
|
||||||
if (!isNaN(pageSize)) {
|
|
||||||
parsedParams.page_size = pageSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parsedParams.page_num !== undefined && typeof parsedParams.page_num === 'string') {
|
|
||||||
const pageNum = parseInt(parsedParams.page_num, 10)
|
|
||||||
if (!isNaN(pageNum)) {
|
|
||||||
parsedParams.page_num = pageNum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 加密参数
|
// 2. 加密参数
|
||||||
const encryptedParams = await encryptWithAES(parsedParams, debugForm.secretKey)
|
const encryptedParams = await encryptWithAES(parsedParams, debugForm.secretKey)
|
||||||
if (!encryptedParams) {
|
if (!encryptedParams) {
|
||||||
@@ -1159,7 +1207,7 @@ const handleDebug = async () => {
|
|||||||
console.log('产品API调用成功:', responseData)
|
console.log('产品API调用成功:', responseData)
|
||||||
const endTime = new Date()
|
const endTime = new Date()
|
||||||
|
|
||||||
// 5. 保存调试结果
|
// 5. 保存调试结果 - 立即更新,确保UI实时显示
|
||||||
debugResult.value = createDebugResult(
|
debugResult.value = createDebugResult(
|
||||||
selectedProduct.value,
|
selectedProduct.value,
|
||||||
requestBody,
|
requestBody,
|
||||||
@@ -1170,6 +1218,9 @@ const handleDebug = async () => {
|
|||||||
responseData.success && responseData.data?.code === 0
|
responseData.success && responseData.data?.code === 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 确保DOM更新后再进行解密操作
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
// 6. 如果响应成功且包含加密数据,自动解密
|
// 6. 如果响应成功且包含加密数据,自动解密
|
||||||
console.log('responseData', responseData)
|
console.log('responseData', responseData)
|
||||||
if (responseData.success && responseData.data?.code === 0 && responseData.data?.data && typeof responseData.data.data === 'string') {
|
if (responseData.success && responseData.data?.code === 0 && responseData.data?.data && typeof responseData.data.data === 'string') {
|
||||||
@@ -1180,7 +1231,9 @@ const handleDebug = async () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (decryptResult.success) {
|
if (decryptResult.success) {
|
||||||
|
// 使用 nextTick 确保响应式更新
|
||||||
decryptedData.value = decryptResult.data
|
decryptedData.value = decryptResult.data
|
||||||
|
await nextTick()
|
||||||
ElMessage.success('调试完成,数据已自动解密')
|
ElMessage.success('调试完成,数据已自动解密')
|
||||||
} else {
|
} else {
|
||||||
ElMessage.warning('调试完成,但数据解密失败:' + (decryptResult.message || '未知错误'))
|
ElMessage.warning('调试完成,但数据解密失败:' + (decryptResult.message || '未知错误'))
|
||||||
@@ -1223,6 +1276,9 @@ const handleDebug = async () => {
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 确保DOM更新
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
ElMessage.error('API调用失败:' + apiError.message)
|
ElMessage.error('API调用失败:' + apiError.message)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1239,6 +1295,9 @@ const handleDebug = async () => {
|
|||||||
endTime,
|
endTime,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 确保DOM更新
|
||||||
|
await nextTick()
|
||||||
} finally {
|
} finally {
|
||||||
debugging.value = false
|
debugging.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="list-page-actions">
|
<div class="list-page-actions">
|
||||||
<el-button @click="$router.back()">返回</el-button>
|
<el-button @click="$router.back()">返回</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="product?.documentation"
|
||||||
|
type="info"
|
||||||
|
@click="downloadDocumentation"
|
||||||
|
:loading="downloading"
|
||||||
|
>
|
||||||
|
<el-icon><Download /></el-icon>
|
||||||
|
{{ product?.documentation?.pdf_file_path ? '下载PDF文档' : '下载接口文档' }}
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="!isSubscribed"
|
v-if="!isSubscribed"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -20,10 +29,11 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-else
|
v-else
|
||||||
type="success"
|
type="danger"
|
||||||
disabled
|
@click="handleCancelSubscription"
|
||||||
|
:loading="cancelling"
|
||||||
>
|
>
|
||||||
已订阅
|
取消订阅
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="isSubscribed"
|
v-if="isSubscribed"
|
||||||
@@ -260,7 +270,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { productApi, subscriptionApi } from '@/api'
|
import { productApi, subscriptionApi } from '@/api'
|
||||||
import { DocumentCopy } from '@element-plus/icons-vue'
|
import { DocumentCopy, Download } from '@element-plus/icons-vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { marked } from 'marked'
|
import { marked } from 'marked'
|
||||||
|
|
||||||
@@ -272,6 +282,8 @@ const loading = ref(false)
|
|||||||
const product = ref(null)
|
const product = ref(null)
|
||||||
const userSubscriptions = ref([])
|
const userSubscriptions = ref([])
|
||||||
const subscribing = ref(false)
|
const subscribing = ref(false)
|
||||||
|
const cancelling = ref(false)
|
||||||
|
const downloading = ref(false)
|
||||||
const activeTab = ref('content')
|
const activeTab = ref('content')
|
||||||
const currentTimestamp = ref('')
|
const currentTimestamp = ref('')
|
||||||
|
|
||||||
@@ -288,6 +300,12 @@ const isSubscribed = computed(() => {
|
|||||||
return userSubscriptions.value.some(sub => sub.product_id === product.value.id)
|
return userSubscriptions.value.some(sub => sub.product_id === product.value.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 获取当前产品的订阅信息
|
||||||
|
const currentSubscription = computed(() => {
|
||||||
|
if (!product.value || !userSubscriptions.value.length) return null
|
||||||
|
return userSubscriptions.value.find(sub => sub.product_id === product.value.id)
|
||||||
|
})
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadUserSubscriptions()
|
loadUserSubscriptions()
|
||||||
@@ -321,7 +339,7 @@ const startTimestampUpdate = () => {
|
|||||||
// 加载用户订阅
|
// 加载用户订阅
|
||||||
const loadUserSubscriptions = async () => {
|
const loadUserSubscriptions = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await subscriptionApi.getMySubscriptions({ page: 1, page_size: 100 })
|
const response = await subscriptionApi.getMySubscriptions({ page: 1, page_size: 1000 })
|
||||||
userSubscriptions.value = response.data?.items || []
|
userSubscriptions.value = response.data?.items || []
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载用户订阅失败:', error)
|
console.error('加载用户订阅失败:', error)
|
||||||
@@ -528,19 +546,53 @@ const handleSubscribe = async () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error !== 'cancel') {
|
if (error !== 'cancel') {
|
||||||
console.error('订阅失败:', error)
|
console.error('订阅失败:', error)
|
||||||
ElMessage.error('订阅失败')
|
const errorMessage = error.response?.data?.message || error.message || '订阅失败'
|
||||||
|
ElMessage.error(errorMessage)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
subscribing.value = false
|
subscribing.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 取消订阅
|
||||||
|
const handleCancelSubscription = async () => {
|
||||||
|
if (!product.value || !currentSubscription.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定要取消订阅产品"${product.value.name}"吗?取消后将无法继续使用该产品的API服务。`,
|
||||||
|
'取消订阅确认',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定取消',
|
||||||
|
cancelButtonText: '我再想想',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
cancelling.value = true
|
||||||
|
|
||||||
|
await subscriptionApi.cancelMySubscription(currentSubscription.value.id)
|
||||||
|
ElMessage.success('取消订阅成功')
|
||||||
|
|
||||||
|
// 重新加载用户订阅
|
||||||
|
await loadUserSubscriptions()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('取消订阅失败:', error)
|
||||||
|
const errorMessage = error.response?.data?.message || error.message || '取消订阅失败'
|
||||||
|
ElMessage.error(errorMessage)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
cancelling.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 前往在线调试
|
// 前往在线调试
|
||||||
const goToApiDebugger = () => {
|
const goToApiDebugger = () => {
|
||||||
if (!product.value) return
|
if (!product.value) return
|
||||||
router.push({
|
router.push({
|
||||||
name: 'ApiDebugger',
|
name: 'ApiDebugger',
|
||||||
params: { productId: product.value.id }
|
query: { productId: product.value.id }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,6 +711,65 @@ const getDefaultErrorCodes = () => {
|
|||||||
| 2001 | 业务失败 |`
|
| 2001 | 业务失败 |`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 下载接口文档
|
||||||
|
const downloadDocumentation = async () => {
|
||||||
|
if (!product.value) {
|
||||||
|
ElMessage.warning('产品信息不存在')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
downloading.value = true
|
||||||
|
try {
|
||||||
|
// 根据是否有PDF文件路径判断文件类型
|
||||||
|
const hasPDF = product.value.documentation?.pdf_file_path
|
||||||
|
|
||||||
|
// 使用原生fetch以获取完整的响应信息(包括headers)
|
||||||
|
const token = localStorage.getItem('access_token')
|
||||||
|
const tokenType = localStorage.getItem('token_type') || 'Bearer'
|
||||||
|
const headers = {
|
||||||
|
'Authorization': token ? `${tokenType} ${token}` : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`/api/v1/products/${product.value.id}/documentation/download`, {
|
||||||
|
headers
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('下载失败')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取Content-Type
|
||||||
|
const contentType = response.headers.get('content-type') || ''
|
||||||
|
const isPDF = contentType.includes('application/pdf') || hasPDF
|
||||||
|
|
||||||
|
// 获取文件内容
|
||||||
|
const blob = await response.blob()
|
||||||
|
|
||||||
|
// 创建下载链接
|
||||||
|
const url = URL.createObjectURL(blob)
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
const extension = isPDF ? 'pdf' : 'md'
|
||||||
|
const filename = `${product.value.name || '产品'}_接口文档.${extension}`
|
||||||
|
link.download = filename
|
||||||
|
|
||||||
|
// 触发下载
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
document.body.removeChild(link)
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
|
||||||
|
ElMessage.success('文档下载成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('下载接口文档失败:', error)
|
||||||
|
ElMessage.error('下载接口文档失败')
|
||||||
|
} finally {
|
||||||
|
downloading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 下载 Markdown 文档
|
// 下载 Markdown 文档
|
||||||
const downloadMarkdown = (type) => {
|
const downloadMarkdown = (type) => {
|
||||||
if (!product.value?.documentation) {
|
if (!product.value?.documentation) {
|
||||||
|
|||||||
@@ -50,9 +50,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 p-4">
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 p-4">
|
||||||
<ProductCard v-for="product in products" :key="product.id" :product="product"
|
<ProductCard
|
||||||
:is-subscribed="product.is_subscribed" @view-detail="handleViewDetail"
|
v-for="product in products"
|
||||||
@subscribe="handleSubscribe" />
|
:key="product.id"
|
||||||
|
:product="product"
|
||||||
|
:is-subscribed="getProductSubscriptionStatus(product.id)"
|
||||||
|
:subscription="getProductSubscription(product.id)"
|
||||||
|
@view-detail="handleViewDetail"
|
||||||
|
@subscribe="handleSubscribe"
|
||||||
|
@cancel-subscribe="handleCancelSubscribe" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -65,7 +71,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { categoryApi, productApi } from '@/api'
|
import { categoryApi, productApi, subscriptionApi } from '@/api'
|
||||||
import FilterItem from '@/components/common/FilterItem.vue'
|
import FilterItem from '@/components/common/FilterItem.vue'
|
||||||
import FilterSection from '@/components/common/FilterSection.vue'
|
import FilterSection from '@/components/common/FilterSection.vue'
|
||||||
import ListPageLayout from '@/components/common/ListPageLayout.vue'
|
import ListPageLayout from '@/components/common/ListPageLayout.vue'
|
||||||
@@ -81,6 +87,7 @@ const categories = ref([])
|
|||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const currentPage = ref(1)
|
const currentPage = ref(1)
|
||||||
const pageSize = ref(12)
|
const pageSize = ref(12)
|
||||||
|
const userSubscriptions = ref([]) // 用户订阅列表
|
||||||
|
|
||||||
// 筛选条件
|
// 筛选条件
|
||||||
const filters = reactive({
|
const filters = reactive({
|
||||||
@@ -96,6 +103,7 @@ let searchTimer = null
|
|||||||
// 初始化
|
// 初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadCategories()
|
loadCategories()
|
||||||
|
loadUserSubscriptions()
|
||||||
loadProducts()
|
loadProducts()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -109,6 +117,30 @@ const loadCategories = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载用户订阅列表
|
||||||
|
const loadUserSubscriptions = async () => {
|
||||||
|
try {
|
||||||
|
const response = await subscriptionApi.getMySubscriptions({ page: 1, page_size: 1000 })
|
||||||
|
userSubscriptions.value = response.data?.items || []
|
||||||
|
} catch (error) {
|
||||||
|
// 如果未登录或获取失败,清空订阅列表
|
||||||
|
console.error('加载用户订阅失败:', error)
|
||||||
|
userSubscriptions.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取产品的订阅状态
|
||||||
|
const getProductSubscriptionStatus = (productId) => {
|
||||||
|
if (!productId || !userSubscriptions.value.length) return false
|
||||||
|
return userSubscriptions.value.some(sub => sub.product_id === productId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取产品的订阅信息
|
||||||
|
const getProductSubscription = (productId) => {
|
||||||
|
if (!productId || !userSubscriptions.value.length) return null
|
||||||
|
return userSubscriptions.value.find(sub => sub.product_id === productId) || null
|
||||||
|
}
|
||||||
|
|
||||||
// 加载产品列表
|
// 加载产品列表
|
||||||
const loadProducts = async () => {
|
const loadProducts = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -122,6 +154,9 @@ const loadProducts = async () => {
|
|||||||
const response = await productApi.getProducts(params)
|
const response = await productApi.getProducts(params)
|
||||||
products.value = response.data?.items || []
|
products.value = response.data?.items || []
|
||||||
total.value = response.data?.total || 0
|
total.value = response.data?.total || 0
|
||||||
|
|
||||||
|
// 重新加载订阅列表以确保状态同步
|
||||||
|
await loadUserSubscriptions()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载产品失败:', error)
|
console.error('加载产品失败:', error)
|
||||||
ElMessage.error('加载产品失败')
|
ElMessage.error('加载产品失败')
|
||||||
@@ -191,12 +226,51 @@ const handleSubscribe = async (product) => {
|
|||||||
await productApi.subscribeProduct(product.id)
|
await productApi.subscribeProduct(product.id)
|
||||||
ElMessage.success('订阅成功')
|
ElMessage.success('订阅成功')
|
||||||
|
|
||||||
// 重新加载产品列表以更新订阅状态
|
// 重新加载订阅列表和产品列表以更新订阅状态
|
||||||
|
await loadUserSubscriptions()
|
||||||
await loadProducts()
|
await loadProducts()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error !== 'cancel') {
|
if (error !== 'cancel') {
|
||||||
console.error('订阅失败:', error)
|
console.error('订阅失败:', error)
|
||||||
ElMessage.error('订阅失败')
|
const errorMessage = error.response?.data?.message || error.message || '订阅失败'
|
||||||
|
ElMessage.error(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消订阅
|
||||||
|
const handleCancelSubscribe = async (product) => {
|
||||||
|
if (!product) return
|
||||||
|
|
||||||
|
// 获取该产品的订阅信息
|
||||||
|
const subscription = getProductSubscription(product.id)
|
||||||
|
if (!subscription || !subscription.id) {
|
||||||
|
ElMessage.error('订阅信息不完整')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定要取消订阅产品"${product.name}"吗?取消后将无法继续使用该产品的API服务。`,
|
||||||
|
'取消订阅确认',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定取消',
|
||||||
|
cancelButtonText: '我再想想',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
await subscriptionApi.cancelMySubscription(subscription.id)
|
||||||
|
ElMessage.success('取消订阅成功')
|
||||||
|
|
||||||
|
// 重新加载订阅列表和产品列表以更新订阅状态
|
||||||
|
await loadUserSubscriptions()
|
||||||
|
await loadProducts()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('取消订阅失败:', error)
|
||||||
|
const errorMessage = error.response?.data?.message || error.message || '取消订阅失败'
|
||||||
|
ElMessage.error(errorMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="操作" width="320" fixed="right">
|
<el-table-column label="操作" width="400" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<el-button
|
<el-button
|
||||||
@@ -155,6 +155,13 @@
|
|||||||
>
|
>
|
||||||
在线调试
|
在线调试
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
type="danger"
|
||||||
|
@click="handleCancelSubscription(row)"
|
||||||
|
>
|
||||||
|
取消订阅
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -216,7 +223,7 @@ import { subscriptionApi } from '@/api'
|
|||||||
import FilterItem from '@/components/common/FilterItem.vue'
|
import FilterItem from '@/components/common/FilterItem.vue'
|
||||||
import FilterSection from '@/components/common/FilterSection.vue'
|
import FilterSection from '@/components/common/FilterSection.vue'
|
||||||
import ListPageLayout from '@/components/common/ListPageLayout.vue'
|
import ListPageLayout from '@/components/common/ListPageLayout.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@@ -383,6 +390,50 @@ const goToApiDebugger = (product) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 取消订阅
|
||||||
|
const handleCancelSubscription = async (subscription) => {
|
||||||
|
if (!subscription || !subscription.id) {
|
||||||
|
ElMessage.error('订阅信息不完整')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 显示确认对话框
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定要取消订阅 "${subscription.product?.name || '该产品'}" 吗?取消后将无法继续使用该产品的API服务。`,
|
||||||
|
'取消订阅确认',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定取消',
|
||||||
|
cancelButtonText: '我再想想',
|
||||||
|
type: 'warning',
|
||||||
|
dangerouslyUseHTMLString: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 用户确认后执行取消操作
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
await subscriptionApi.cancelMySubscription(subscription.id)
|
||||||
|
ElMessage.success('取消订阅成功')
|
||||||
|
// 重新加载订阅列表
|
||||||
|
await loadSubscriptions()
|
||||||
|
// 重新加载统计数据
|
||||||
|
await loadStats()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('取消订阅失败:', error)
|
||||||
|
const errorMessage = error.response?.data?.message || error.message || '取消订阅失败'
|
||||||
|
ElMessage.error(errorMessage)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 用户取消操作,不做任何处理
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('取消订阅操作异常:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -315,9 +315,18 @@ const router = createRouter({
|
|||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 等待userStore初始化完成
|
// 对于不需要认证的路由(如登录页),不等待初始化,直接放行
|
||||||
if (!userStore.initialized) {
|
const isAuthRoute = to.path.startsWith('/auth')
|
||||||
|
const requiresAuth = to.meta.requiresAuth
|
||||||
|
|
||||||
|
// 只有在需要认证的路由上才等待初始化
|
||||||
|
if (requiresAuth && !userStore.initialized) {
|
||||||
await userStore.init()
|
await userStore.init()
|
||||||
|
} else if (!userStore.initialized) {
|
||||||
|
// 对于不需要认证的路由,异步初始化但不阻塞
|
||||||
|
userStore.init().catch(err => {
|
||||||
|
console.warn('UserStore初始化失败:', err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
@@ -326,7 +335,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否需要认证
|
// 检查是否需要认证
|
||||||
if (to.meta.requiresAuth && !userStore.isLoggedIn) {
|
if (requiresAuth && !userStore.isLoggedIn) {
|
||||||
next('/auth/login')
|
next('/auth/login')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -338,7 +347,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 已登录用户访问认证页面,重定向到数据大厅
|
// 已登录用户访问认证页面,重定向到数据大厅
|
||||||
if (to.path.startsWith('/auth') && userStore.isLoggedIn) {
|
if (isAuthRoute && userStore.isLoggedIn) {
|
||||||
next('/products')
|
next('/products')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,9 +135,9 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
// 检查用户信息是否完整
|
// 检查用户信息是否完整
|
||||||
const isUserInfoComplete = computed(() => {
|
const isUserInfoComplete = computed(() => {
|
||||||
return user.value &&
|
return user.value &&
|
||||||
user.value.id &&
|
user.value.id &&
|
||||||
user.value.phone &&
|
user.value.phone &&
|
||||||
user.value.user_type !== undefined
|
user.value.user_type !== undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
// 强制刷新用户信息
|
// 强制刷新用户信息
|
||||||
@@ -416,44 +416,73 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化标志,防止重复初始化
|
||||||
|
let isInitializing = false
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
// 监听认证错误事件
|
// 如果已经初始化完成,直接返回
|
||||||
authEventBus.onAuthError(handleAuthError)
|
if (initialized.value) {
|
||||||
|
|
||||||
// 监听版本更新事件
|
|
||||||
window.addEventListener('version:logout', handleVersionLogout)
|
|
||||||
window.addEventListener('version:refresh', handleVersionRefresh)
|
|
||||||
|
|
||||||
// 进行版本检查
|
|
||||||
if (!checkVersions()) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessToken.value && !user.value) {
|
// 如果正在初始化,等待完成
|
||||||
// 有token但无用户信息,自动拉取
|
if (isInitializing) {
|
||||||
loading.value = true
|
// 等待初始化完成
|
||||||
try {
|
while (isInitializing) {
|
||||||
const result = await fetchUserProfile()
|
await new Promise(resolve => setTimeout(resolve, 50))
|
||||||
isAuthenticated.value = result.success
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 如果认证成功,启动版本检查器
|
isInitializing = true
|
||||||
if (result.success) {
|
|
||||||
|
try {
|
||||||
|
// 监听认证错误事件(只注册一次)
|
||||||
|
if (!authEventBus.listeners.includes(handleAuthError)) {
|
||||||
|
authEventBus.onAuthError(handleAuthError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听版本更新事件(只注册一次)
|
||||||
|
if (!window.hasVersionListeners) {
|
||||||
|
window.addEventListener('version:logout', handleVersionLogout)
|
||||||
|
window.addEventListener('version:refresh', handleVersionRefresh)
|
||||||
|
window.hasVersionListeners = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 进行版本检查
|
||||||
|
if (!checkVersions()) {
|
||||||
|
initialized.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessToken.value && !user.value) {
|
||||||
|
// 有token但无用户信息,自动拉取
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const result = await fetchUserProfile()
|
||||||
|
isAuthenticated.value = result.success
|
||||||
|
|
||||||
|
// 如果认证成功,启动版本检查器
|
||||||
|
if (result.success) {
|
||||||
|
versionChecker.startAutoCheck()
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
isAuthenticated.value = false
|
||||||
|
logout()
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
initialized.value = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果已经认证,启动版本检查器
|
||||||
|
if (isAuthenticated.value) {
|
||||||
versionChecker.startAutoCheck()
|
versionChecker.startAutoCheck()
|
||||||
}
|
}
|
||||||
} catch {
|
|
||||||
isAuthenticated.value = false
|
|
||||||
logout()
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
initialized.value = true
|
initialized.value = true
|
||||||
}
|
}
|
||||||
} else {
|
} finally {
|
||||||
// 如果已经认证,启动版本检查器
|
isInitializing = false
|
||||||
if (isAuthenticated.value) {
|
|
||||||
versionChecker.startAutoCheck()
|
|
||||||
}
|
|
||||||
initialized.value = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user