完善前端显示字段;去掉开放测试接口
This commit is contained in:
@@ -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 =
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user