feat: 文件下载
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 3m54s

This commit is contained in:
sexygoat
2026-04-30 18:04:01 +08:00
parent 81155fd8e4
commit 950520635d
19 changed files with 438 additions and 44 deletions

View File

@@ -246,8 +246,8 @@
import { useAssetFormatters } from '../composables/useAssetFormatters'
import { useUserStore } from '@/store/modules/user'
import { storeToRefs } from 'pinia'
import type { AssetPackageUsageRecord } from '@/types/api'
import { formatDateTime } from '@/utils/business/format'
import type { PackageInfo } from '../types'
const {
formatAmount,
@@ -265,10 +265,10 @@
)
interface Props {
currentPackage: PackageInfo | null
currentPackage: AssetPackageUsageRecord | null
loading?: boolean
errorMsg?: string
boundDeviceId?: number
boundDeviceId?: number | null
boundDeviceNo?: string
boundDeviceName?: string
}

View File

@@ -79,6 +79,14 @@
<span class="field-value">
<template v-if="item.type === 'change'">
<span class="new-value">{{ formatFieldValue(item.key, item.afterValue) }}</span>
<ElButton
v-if="canDownloadLogFile && isDownloadableFileKey(item.key, item.afterValue)"
link
type="primary"
@click.stop="handleDownloadLogFile(item.afterValue)"
>
下载文件
</ElButton>
</template>
<span v-else :class="['message-value', item.level === 'error' ? 'is-error' : '']">
{{ item.message }}
@@ -106,7 +114,7 @@
</template>
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
import { computed, reactive, ref, watch } from 'vue'
import {
ElButton,
ElCard,
@@ -118,13 +126,15 @@
ElTableColumn,
ElTag
} from 'element-plus'
import { AssetService } from '@/api/modules'
import { AssetService, StorageService } from '@/api/modules'
import { useAuth } from '@/composables/useAuth'
import type { AssetOperationLogItem } from '@/types/api'
import { formatDateTime } from '@/utils/business/format'
interface Props {
assetIdentifier?: string
assetType?: string
downloadPermission?: string
}
type TagType = 'primary' | 'success' | 'warning' | 'info' | 'danger'
@@ -285,10 +295,14 @@
}
const props = defineProps<Props>()
const { hasAuth } = useAuth()
const loading = ref(false)
const logList = ref<OperationLogRow[]>([])
const total = ref(0)
const canDownloadLogFile = computed(() => {
return props.downloadPermission ? hasAuth(props.downloadPermission) : false
})
const pagination = reactive({
page: 1,
page_size: 20
@@ -369,6 +383,20 @@
return textMap[status] || status
}
const isDownloadableFileKey = (key: string, value: unknown) => {
return key === 'file_key' && typeof value === 'string' && value.trim() !== ''
}
const handleDownloadLogFile = async (fileKey: string) => {
try {
await StorageService.downloadFileByKey(fileKey)
ElMessage.success('文件下载已开始')
} catch (error) {
console.error('下载日志文件失败:', error)
ElMessage.error('下载文件失败')
}
}
const getOperatorTypeText = (row: OperationLogRow) => {
if (row.operator_type_code && operatorTypeMap[row.operator_type_code]) {
return operatorTypeMap[row.operator_type_code]

View File

@@ -165,20 +165,17 @@
import { useAssetFormatters } from '../composables/useAssetFormatters'
import { formatDateTime } from '@/utils/business/format'
import { AssetService } from '@/api/modules'
interface WalletInfo {
balance: number
available_balance: number
frozen_balance: number
status: number
status_text?: string
}
import type {
AssetWalletResponse,
AssetWalletTransactionParams,
TransactionType
} from '@/types/api'
interface Props {
assetIdentifier: string
walletInfo: WalletInfo | null
walletInfo: AssetWalletResponse | null
walletLoading?: boolean
boundDeviceId?: number
boundDeviceId?: number | null
boundDeviceNo?: string
}
@@ -200,16 +197,16 @@
const total = ref(0)
const pagination = ref({ page: 1, page_size: 20 })
const filterForm = ref<{
transaction_type: string | null
transaction_type: TransactionType | null
date_range: [Date, Date] | null
}>({
transaction_type: null,
date_range: null
})
const queryParams = ref({
const queryParams = ref<AssetWalletTransactionParams>({
page: 1,
page_size: 20,
transaction_type: null as string | null,
transaction_type: null as TransactionType | null,
start_time: null as string | null,
end_time: null as string | null
})