完善前端显示字段;去掉开放测试接口

This commit is contained in:
BBIT-Kai
2026-05-27 11:45:57 +08:00
parent a716c481da
commit bf87c09803
28 changed files with 327 additions and 213 deletions
+20 -9
View File
@@ -1,4 +1,4 @@
import http from '@/api/http'
import http from '@/api/http'
/**
* 账号状态
@@ -158,8 +158,20 @@ export interface CreateDigitalAccountRequest {
platformPassword: string
}
export function listDigitalAccountsApi(): Promise<DigitalAccountItem[]> {
return http.get('/pt/digital-accounts')
export function listDigitalAccountsApi(params: {
page: number
pageSize: number
account?: string | null
status?: string | null
}): Promise<PageResult<DigitalAccountItem>> {
return http.get('/pt/digital-accounts', { params })
}
export function digitalAccountOptionsApi(params?: {
account?: string | null
limit?: number
}): Promise<DigitalAccountItem[]> {
return http.get('/pt/digital-accounts/options', { params })
}
export function refreshDigitalAccountsApi(): Promise<DigitalAccountItem[]> {
@@ -244,7 +256,6 @@ export interface OpenInvoiceTaskItem {
account?: string | null
taskType: string
sourceType: string
runMode: string
invoiceReqSerialNo: string
batchNo?: string | null
status: string
@@ -271,7 +282,6 @@ export function openInvoiceTaskPageApi(params: {
digitalAccountId?: string
status?: string | null
sourceType?: string | null
runMode?: string | null
}): Promise<PageResult<OpenInvoiceTaskItem>> {
return http.get('/pt/openapi/tasks', { params })
}
@@ -458,9 +468,9 @@ export function invoiceIssueApi(payload: InvoiceRequest): Promise<string> {
export interface RedCreateRequest {
/** 蓝票历史记录 ID */
historyId: string
/** 平台数电账号 ID。企业管理员红时用于指定开票员 */
/** 平台数电账号 ID。企业管理员红时用于指定开票员 */
digitalAccountId?: string | null
/** 红原因:01开票有误 02销货退回 03服务中止 04销售折让 */
/** 红原因:01开票有误 02销货退回 03服务中止 04销售折让 */
redReason: string
/** 收票人名称 */
takerName?: string
@@ -577,7 +587,7 @@ export interface InvoiceHistoryItem {
// ===== 发票状态标记 =====
/** 作废状态 */
invalidFlag?: string
/** 红状态 */
/** 红状态 */
redFlag?: string
// ===== 人员信息 =====
@@ -849,7 +859,7 @@ export function queryInvoiceApi(
/** 红票申请信息 */
export interface RedInvoiceInfo {
/** 红原因:01开票有误 02销货退回 03服务中止 04销售折让 */
/** 红原因:01开票有误 02销货退回 03服务中止 04销售折让 */
redReason: string
/** 收票人名称 */
takerName?: string
@@ -976,3 +986,4 @@ export function queryAuthStatusApi(payload: {
}): Promise<AuthQrcodeStatusResponse> {
return http.post('/pt/query-auth-status', payload)
}
@@ -4,6 +4,12 @@
<div class="page-toolbar">
<h2 class="page-toolbar-title">数电账号管理</h2>
<div class="page-toolbar-actions">
<n-input
v-model:value="accountKeyword"
clearable
placeholder="税局账号"
class="toolbar-filter-input"
/>
<n-button :loading="loading" @click="refreshAccounts">
<template #icon><n-icon :component="RefreshCw" /></template>
刷新
@@ -22,9 +28,12 @@
:columns="columns"
:data="accounts"
:loading="loading"
:pagination="{ pageSize: 10 }"
:pagination="pagination"
:row-key="(row: DigitalAccountItem) => row.id"
:scroll-x="1460"
remote
@update:page="onPageChange"
@update:page-size="onPageSizeChange"
/>
</div>
</section>
@@ -133,8 +142,8 @@
</template>
<script setup lang="ts">
import { computed, h, onMounted, reactive, ref } from 'vue'
import type { DataTableColumns, FormInst, FormRules } from 'naive-ui'
import { computed, h, onMounted, reactive, ref, watch } from 'vue'
import type { DataTableColumns, FormInst, FormRules, PaginationProps } from 'naive-ui'
import {
NAlert,
NButton,
@@ -175,6 +184,8 @@ const authStore = useAuthStore()
const loading = ref(false)
const saving = ref(false)
const accounts = ref<DigitalAccountItem[]>([])
const accountKeyword = ref('')
let accountSearchTimer: ReturnType<typeof setTimeout> | null = null
const showCreate = ref(false)
const showSms = ref(false)
const showQrcode = ref(false)
@@ -195,6 +206,17 @@ const canUpdateStatus = computed(() => authStore.hasPermission('digital-account:
const qrcodeTypeLabel = computed(() =>
qrcodeType.value === '2' ? '国家网络身份认证 APP' : '电子税务局 APP'
)
const pager = reactive({
page: 1,
pageSize: 10
})
const pagination = reactive<PaginationProps>({
page: pager.page,
pageSize: pager.pageSize,
itemCount: 0,
showSizePicker: true,
pageSizes: [10, 20, 50, 100]
})
const createForm = reactive({
account: '',
@@ -352,7 +374,17 @@ function renderEllipsisText(value?: string | null) {
async function load() {
loading.value = true
try {
accounts.value = await listDigitalAccountsApi()
const result = await listDigitalAccountsApi({
page: pager.page,
pageSize: pager.pageSize,
account: accountKeyword.value.trim() || null
})
accounts.value = result.items
pager.page = result.page
pager.pageSize = result.pageSize
pagination.page = result.page
pagination.pageSize = result.pageSize
pagination.itemCount = result.total
} finally {
loading.value = false
}
@@ -361,13 +393,26 @@ async function load() {
async function refreshAccounts() {
loading.value = true
try {
accounts.value = await refreshDigitalAccountsApi()
await refreshDigitalAccountsApi()
message.success('数电账号已刷新')
pager.page = 1
await load()
} finally {
loading.value = false
}
}
function onPageChange(page: number) {
pager.page = page
load()
}
function onPageSizeChange(pageSize: number) {
pager.page = 1
pager.pageSize = pageSize
load()
}
async function createAccount() {
await createFormRef.value?.validate()
saving.value = true
@@ -451,6 +496,14 @@ async function loadQrcode() {
}
onMounted(load)
watch(accountKeyword, () => {
if (accountSearchTimer) clearTimeout(accountSearchTimer)
accountSearchTimer = setTimeout(() => {
pager.page = 1
load()
}, 300)
})
</script>
<style scoped>
@@ -461,6 +514,10 @@ onMounted(load)
gap: 8px;
}
.toolbar-filter-input {
width: 240px;
}
.row-actions {
flex-wrap: nowrap;
white-space: nowrap;
@@ -1,4 +1,4 @@
<template>
<template>
<div class="page-shell invoice-history-page">
<div class="stats-row">
<div v-for="s in stats" :key="s.label" class="stat-card">
@@ -173,9 +173,9 @@
}}</strong>
</div>
<div class="detail-item">
<span>红状态</span>
<span>状态</span>
<strong>{{
redFlagMap[detailItem.redFlag || ''] || detailItem.redFlag || '未红'
redFlagMap[detailItem.redFlag || ''] || detailItem.redFlag || '未红'
}}</strong>
</div>
<div class="detail-item">
@@ -227,10 +227,10 @@
<template v-if="detailItem.invoiceType === 'RED' && redInfo">
<div class="detail-section">
<div class="detail-section-title">红申请</div>
<div class="detail-section-title">红申请</div>
<div class="detail-grid">
<div class="detail-item">
<span>红原因</span>
<span>红原因</span>
<strong>{{ redReasonMap[redInfo.redReason] || redInfo.redReason }}</strong>
</div>
<div class="detail-item">
@@ -419,7 +419,7 @@
<n-modal
v-model:show="showRedForm"
preset="card"
title="发起红"
title="发起红"
:style="{ width: '480px', maxWidth: '92vw' }"
:mask-closable="false"
content-style="padding: 20px"
@@ -441,11 +441,11 @@
clearable
/>
</n-form-item>
<n-form-item label="红原因" path="redReason">
<n-form-item label="红原因" path="redReason">
<n-select
v-model:value="redForm.redReason"
:options="redReasonOptions"
placeholder="请选择红原因"
placeholder="请选择红原因"
/>
</n-form-item>
<n-form-item label="收票人名称" path="takerName">
@@ -461,7 +461,7 @@
<div class="modal-actions">
<n-button quaternary @click="showRedForm = false">取消</n-button>
<n-button type="error" :loading="redSubmitting" @click="handleRedSubmit"
>确认红</n-button
>确认红</n-button
>
</div>
</n-form>
@@ -506,7 +506,7 @@ import {
invoiceHistoryApi,
invoiceKindMap,
invoiceStatusMap,
listDigitalAccountsApi,
digitalAccountOptionsApi,
queryInvoiceApi,
redInvoiceCreateApi,
redInvoiceDownloadUrlApi,
@@ -539,11 +539,11 @@ const invalidFlagMap: Record<string, string> = {
}
const redFlagMap: Record<string, string> = {
NOT_RED: '未红',
ALREADY_RED: '已红',
REDING: '红中',
RED_FAIL: '红失败',
PART_RED: '部分红'
NOT_RED: '未红',
ALREADY_RED: '已红',
REDING: '红中',
RED_FAIL: '红失败',
PART_RED: '部分红'
}
const redInvoiceKindCodes = new Set(['81', '82', '83', '87'])
@@ -740,7 +740,7 @@ function getRowActions(row: InvoiceHistoryItem) {
}
if (canCreateRedInvoice(row)) {
actions.push({ label: '红', icon: RotateCcw, onClick: () => startRedTask(row) })
actions.push({ label: '红', icon: RotateCcw, onClick: () => startRedTask(row) })
}
return actions
@@ -751,7 +751,7 @@ function getActionsColumnWidth() {
详情: 58,
刷新: 58,
查看票样: 86,
: 58
: 58
}
const rowWidths = dataSource.value.map((row) => {
const actions = getRowActions(row)
@@ -847,7 +847,7 @@ const columns = computed<DataTableColumns<InvoiceHistoryItem>>(() => {
: h('span', { style: 'color:#9ca3af' }, '-')
},
{
title: '红状态',
title: '红状态',
key: 'redFlag',
width: 110,
render: (row: InvoiceHistoryItem) => {
@@ -862,7 +862,7 @@ const columns = computed<DataTableColumns<InvoiceHistoryItem>>(() => {
}[row.status]
: undefined)
if (!redFlag || redFlag === 'NOT_RED') {
return h(NTag, { size: 'small', round: true }, () => '未红')
return h(NTag, { size: 'small', round: true }, () => '未红')
}
const typeMap: Record<string, 'error' | 'warning' | 'default'> = {
ALREADY_RED: 'error',
@@ -1013,14 +1013,14 @@ const digitalAccountOptions = computed(() =>
const redFormRules = {
digitalAccountId: [{ required: true, message: '请选择开票员', trigger: 'change' }],
redReason: [{ required: true, message: '请选择红原因', trigger: 'change' }]
redReason: [{ required: true, message: '请选择红原因', trigger: 'change' }]
}
async function ensureDigitalAccountsLoaded() {
if (digitalAccounts.value.length > 0) return
digitalAccountLoading.value = true
try {
digitalAccounts.value = await listDigitalAccountsApi()
digitalAccounts.value = await digitalAccountOptionsApi({ limit: 200 })
} finally {
digitalAccountLoading.value = false
}
@@ -1057,11 +1057,11 @@ async function handleRedSubmit() {
takerEmail: redForm.takerEmail || undefined
}
await redInvoiceCreateApi(payload)
message.success('红任务创建成功')
message.success('红任务创建成功')
showRedForm.value = false
fetchData()
} catch {
message.error('创建红任务失败')
message.error('创建红任务失败')
} finally {
redSubmitting.value = false
}
@@ -1510,3 +1510,4 @@ onMounted(() => {
}
}
</style>
@@ -931,7 +931,7 @@ import {
invoiceIssueApi,
getEnterpriseInfoApi,
getPresetDataApi,
listDigitalAccountsApi
digitalAccountOptionsApi
} from '@/api/piaotong'
import type { DigitalAccountItem, InvoiceRequest, InvoiceItem, VariableLevyProof } from '@/api/piaotong'
import type { FormInst, FormRules } from 'naive-ui'
@@ -1574,7 +1574,7 @@ onMounted(async () => {
const [enterpriseInfo, presetData, accounts] = await Promise.all([
getEnterpriseInfoApi(),
getPresetDataApi(),
listDigitalAccountsApi()
digitalAccountOptionsApi({ limit: 200 })
])
digitalAccounts.value = accounts
const defaultAccount =
+39 -23
View File
@@ -66,15 +66,6 @@
class="task-filter"
@update:value="loadTasks(1)"
/>
<n-select
v-model:value="taskRunMode"
clearable
size="small"
placeholder="全部模式"
:options="runModeOptions"
class="task-filter"
@update:value="loadTasks(1)"
/>
<n-button size="small" :loading="taskLoading" @click="loadTasks(taskPage)">
<template #icon><n-icon :component="RefreshCw" /></template>
刷新
@@ -122,7 +113,6 @@ const taskPageSize = ref(20)
const taskTotal = ref(0)
const taskStatus = ref<string | null>(null)
const taskSourceType = ref<string | null>(null)
const taskRunMode = ref<string | null>(null)
const statusOptions = [
{ label: '待处理', value: 'PENDING' },
@@ -134,14 +124,35 @@ const statusOptions = [
const sourceTypeOptions = [
{ label: '单笔', value: 'SINGLE' },
{ label: '批量', value: 'BATCH' },
{ label: '测试', value: 'TEST' }
{ label: '批量', value: 'BATCH' }
]
const runModeOptions = [
{ label: '生产', value: 'REAL' },
{ label: '模拟', value: 'SIMULATED' }
]
const queueStatusLabelMap: Record<string, string> = {
RUNNING: '运行中',
PAUSED: '已暂停'
}
const taskStatusLabelMap: Record<string, string> = {
PENDING: '待处理',
PROCESSING: '处理中',
SUCCESS: '成功',
FAILED: '失败',
WAITING_AUTH: '需认证'
}
const taskTypeLabelMap: Record<string, string> = {
ISSUE_BLUE: '蓝票开具',
QUERY_BLUE: '蓝票查询'
}
const sourceTypeLabelMap: Record<string, string> = {
SINGLE: '单笔',
BATCH: '批量'
}
function labelOf(map: Record<string, string>, value?: string | null) {
return value ? map[value] || value : '-'
}
const totals = computed(() =>
rows.value.reduce(
@@ -177,7 +188,11 @@ const columns: DataTableColumns<OpenInvoiceTaskOverviewItem> = [
key: 'status',
width: 110,
render: (row) =>
h(NTag, { type: statusTagType(row.status), size: 'small' }, { default: () => row.status })
h(
NTag,
{ type: statusTagType(row.status), size: 'small' },
{ default: () => labelOf(queueStatusLabelMap, row.status) }
)
},
{ title: '待处理', key: 'pending', width: 90 },
{ title: '处理中', key: 'processing', width: 90 },
@@ -265,15 +280,18 @@ function rowProps(row: OpenInvoiceTaskOverviewItem) {
const taskColumns: DataTableColumns<OpenInvoiceTaskItem> = [
{ title: '票号', key: 'invoiceReqSerialNo', minWidth: 170 },
{ title: '任务', key: 'taskType', width: 120 },
{ title: '来源', key: 'sourceType', width: 90 },
{ title: '模式', key: 'runMode', width: 90 },
{ title: '任务', key: 'taskType', width: 120, render: (row) => labelOf(taskTypeLabelMap, row.taskType) },
{ title: '来源', key: 'sourceType', width: 90, render: (row) => labelOf(sourceTypeLabelMap, row.sourceType) },
{
title: '状态',
key: 'status',
width: 110,
render: (row) =>
h(NTag, { type: statusTagType(row.status), size: 'small' }, { default: () => row.status })
h(
NTag,
{ type: statusTagType(row.status), size: 'small' },
{ default: () => labelOf(taskStatusLabelMap, row.status) }
)
},
{ title: 'PT码', key: 'ptCode', width: 90 },
{ title: '错误', key: 'errorMessage', minWidth: 260, ellipsis: { tooltip: true } },
@@ -307,7 +325,6 @@ async function loadTasks(page = 1) {
digitalAccountId: selected.value.digitalAccountId,
status: taskStatus.value,
sourceType: taskSourceType.value,
runMode: taskRunMode.value,
page,
pageSize: taskPageSize.value
})
@@ -326,7 +343,6 @@ function openDrawer(row: OpenInvoiceTaskOverviewItem) {
drawerVisible.value = true
taskStatus.value = null
taskSourceType.value = null
taskRunMode.value = null
loadTasks(1)
}