Compare commits
2 Commits
9fd80980e7
...
bf87c09803
| Author | SHA1 | Date | |
|---|---|---|---|
| bf87c09803 | |||
| a716c481da |
@@ -1,3 +1,4 @@
|
|||||||
web/node_modules/
|
web/node_modules/
|
||||||
web/dist/
|
web/dist/
|
||||||
log/
|
log/
|
||||||
|
server/src/main/resources/dist/
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import com.bbit.ticket.service.openapi.OpenInvoiceTaskWorker
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import io.ktor.server.application.Application
|
import io.ktor.server.application.Application
|
||||||
import io.ktor.server.auth.authenticate
|
import io.ktor.server.auth.authenticate
|
||||||
|
import io.ktor.server.http.content.singlePageApplication
|
||||||
|
import io.ktor.server.http.content.vue
|
||||||
import io.ktor.server.netty.EngineMain
|
import io.ktor.server.netty.EngineMain
|
||||||
import io.ktor.server.response.respond
|
import io.ktor.server.response.respond
|
||||||
import io.ktor.server.routing.get
|
import io.ktor.server.routing.get
|
||||||
@@ -47,7 +49,7 @@ fun Application.module() {
|
|||||||
configureCors()
|
configureCors()
|
||||||
configureSecurity()
|
configureSecurity()
|
||||||
configureDatabase()
|
configureDatabase()
|
||||||
configureRedis()
|
// configureRedis()
|
||||||
runBlocking {
|
runBlocking {
|
||||||
DatabaseInitializer.initialize()
|
DatabaseInitializer.initialize()
|
||||||
SeedData.seed()
|
SeedData.seed()
|
||||||
@@ -58,6 +60,10 @@ fun Application.module() {
|
|||||||
get("/health") {
|
get("/health") {
|
||||||
call.respond(ok(mapOf("status" to "UP", "service" to AppConfig.app.name)))
|
call.respond(ok(mapOf("status" to "UP", "service" to AppConfig.app.name)))
|
||||||
}
|
}
|
||||||
|
singlePageApplication {
|
||||||
|
useResources = true
|
||||||
|
vue("dist")
|
||||||
|
}
|
||||||
route("/api") {
|
route("/api") {
|
||||||
registerAuthRoutes()
|
registerAuthRoutes()
|
||||||
registerUserRoutes()
|
registerUserRoutes()
|
||||||
|
|||||||
@@ -105,10 +105,33 @@ object EnterpriseManageDao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun digitalAccountsForEnterprise(enterpriseId: Uuid): List<DigitalAccountManageItem> =
|
fun digitalAccountsForEnterprise(
|
||||||
PtDigitalAccountTable.selectAll()
|
enterpriseId: Uuid,
|
||||||
.where { (PtDigitalAccountTable.enterpriseId eq enterpriseId) and PtDigitalAccountTable.deletedAt.isNull() }
|
account: String?,
|
||||||
|
status: String?,
|
||||||
|
page: Int,
|
||||||
|
pageSize: Int,
|
||||||
|
): PageResult<DigitalAccountManageItem> {
|
||||||
|
val where = digitalAccountWhere(enterpriseId, account, status)
|
||||||
|
val total = PtDigitalAccountTable.selectAll().where { where }.count()
|
||||||
|
val rows = PtDigitalAccountTable.selectAll()
|
||||||
|
.where { where }
|
||||||
.orderBy(PtDigitalAccountTable.createdAt, SortOrder.DESC)
|
.orderBy(PtDigitalAccountTable.createdAt, SortOrder.DESC)
|
||||||
|
.limit(pageSize)
|
||||||
|
.offset(pageOffset(page, pageSize))
|
||||||
|
.map { it.toDigitalAccountItem() }
|
||||||
|
return PageResult(rows, page, pageSize, total)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun digitalAccountOptionsForEnterprise(
|
||||||
|
enterpriseId: Uuid,
|
||||||
|
account: String?,
|
||||||
|
limit: Int,
|
||||||
|
): List<DigitalAccountManageItem> =
|
||||||
|
PtDigitalAccountTable.selectAll()
|
||||||
|
.where { digitalAccountWhere(enterpriseId, account, "ENABLED") }
|
||||||
|
.orderBy(PtDigitalAccountTable.createdAt, SortOrder.DESC)
|
||||||
|
.limit(limit)
|
||||||
.map { it.toDigitalAccountItem() }
|
.map { it.toDigitalAccountItem() }
|
||||||
|
|
||||||
fun digitalAccount(id: Uuid): ResultRow? =
|
fun digitalAccount(id: Uuid): ResultRow? =
|
||||||
@@ -134,6 +157,18 @@ object EnterpriseManageDao {
|
|||||||
}
|
}
|
||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
|
|
||||||
|
private fun digitalAccountWhere(enterpriseId: Uuid, account: String?, status: String?): Op<Boolean> {
|
||||||
|
var where: Op<Boolean> =
|
||||||
|
(PtDigitalAccountTable.enterpriseId eq enterpriseId) and PtDigitalAccountTable.deletedAt.isNull()
|
||||||
|
account?.trim()?.takeIf { it.isNotEmpty() }?.let {
|
||||||
|
where = where and (PtDigitalAccountTable.account like "%$it%")
|
||||||
|
}
|
||||||
|
status?.trim()?.takeIf { it.isNotEmpty() }?.let {
|
||||||
|
where = where and (PtDigitalAccountTable.status eq it.uppercase())
|
||||||
|
}
|
||||||
|
return where
|
||||||
|
}
|
||||||
|
|
||||||
fun upsertDigitalAccount(enterpriseId: Uuid, item: DigitalAccountInfo): Uuid {
|
fun upsertDigitalAccount(enterpriseId: Uuid, item: DigitalAccountInfo): Uuid {
|
||||||
val existing = PtDigitalAccountTable.selectAll()
|
val existing = PtDigitalAccountTable.selectAll()
|
||||||
.where {
|
.where {
|
||||||
|
|||||||
+8
-7
@@ -1,4 +1,4 @@
|
|||||||
package com.bbit.ticket.database.piaotong
|
package com.bbit.ticket.database.piaotong
|
||||||
|
|
||||||
import org.jetbrains.exposed.v1.core.Table
|
import org.jetbrains.exposed.v1.core.Table
|
||||||
import org.jetbrains.exposed.v1.javatime.timestampWithTimeZone
|
import org.jetbrains.exposed.v1.javatime.timestampWithTimeZone
|
||||||
@@ -306,13 +306,13 @@ object HistoryInvoiceBasicTable : Table("history_invoice_basic") {
|
|||||||
.nullable()
|
.nullable()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 冲红状态
|
* 红冲状态
|
||||||
*
|
*
|
||||||
* NOT_RED:未冲红
|
* NOT_RED:未红冲
|
||||||
* ALREADY_RED:已冲红
|
* ALREADY_RED:已红冲
|
||||||
* REDING:冲红中
|
* REDING:红冲中
|
||||||
* RED_FAIL:冲红失败
|
* RED_FAIL:红冲失败
|
||||||
* PART_RED:部分冲红
|
* PART_RED:部分红冲
|
||||||
*/
|
*/
|
||||||
val redFlag = varchar("red_flag", 32)
|
val redFlag = varchar("red_flag", 32)
|
||||||
.nullable()
|
.nullable()
|
||||||
@@ -453,3 +453,4 @@ object HistoryInvoiceBasicTable : Table("history_invoice_basic") {
|
|||||||
|
|
||||||
override val primaryKey = PrimaryKey(id)
|
override val primaryKey = PrimaryKey(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@file:OptIn(ExperimentalUuidApi::class)
|
@file:OptIn(ExperimentalUuidApi::class)
|
||||||
|
|
||||||
package com.bbit.ticket.database.piaotong
|
package com.bbit.ticket.database.piaotong
|
||||||
|
|
||||||
@@ -26,13 +26,13 @@ object HistoryInvoiceRedTable : Table("history_invoice_red") {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 发票代码
|
* 发票代码
|
||||||
* 需冲红的原发票代码,冲红增值税发票管理系统开具的发票或数电纸质发票时必填
|
* 需红冲的原发票代码,红冲增值税发票管理系统开具的发票或数电纸质发票时必填
|
||||||
*/
|
*/
|
||||||
val invoiceCode = varchar("invoice_code", 12).nullable()
|
val invoiceCode = varchar("invoice_code", 12).nullable()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发票请求流水号
|
* 发票请求流水号
|
||||||
* 需冲红的原发票号码,冲红增值税发票管理系统开具的发票或数电纸质发票时必填
|
* 需红冲的原发票号码,红冲增值税发票管理系统开具的发票或数电纸质发票时必填
|
||||||
*/
|
*/
|
||||||
val invoiceNo = varchar("invoice_no", 8).nullable()
|
val invoiceNo = varchar("invoice_no", 8).nullable()
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ object HistoryInvoiceRedTable : Table("history_invoice_red") {
|
|||||||
val invoiceReqSerialNo = varchar("invoice_req_serial_no", 20)
|
val invoiceReqSerialNo = varchar("invoice_req_serial_no", 20)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 冲红原因
|
* 红冲原因
|
||||||
* 01:开票有误
|
* 01:开票有误
|
||||||
* 02:销货退回
|
* 02:销货退回
|
||||||
* 03:服务中止
|
* 03:服务中止
|
||||||
@@ -61,9 +61,9 @@ object HistoryInvoiceRedTable : Table("history_invoice_red") {
|
|||||||
* 81:数电发票(增值税专用发票)
|
* 81:数电发票(增值税专用发票)
|
||||||
* 82:数电发票(普通发票)。
|
* 82:数电发票(普通发票)。
|
||||||
* 默认蓝票的发票种类代码。
|
* 默认蓝票的发票种类代码。
|
||||||
* 此字段目的解决数电发票冲红增值税发票,只有企业不再使用增值税系统时才可以跨票种冲红。
|
* 此字段目的解决数电发票红冲增值税发票,只有企业不再使用增值税系统时才可以跨票种红冲。
|
||||||
* 数电发票(普通发票)可以冲红数电发票(普通发票)、增值税电子普通发票、增值税纸质普通发票。
|
* 数电发票(普通发票)可以红冲数电发票(普通发票)、增值税电子普通发票、增值税纸质普通发票。
|
||||||
* 数电发票(增值税专用发票)可以冲红数电发票(增值税专用发票)、增值税电子专用发票、增值税纸质专用发票。
|
* 数电发票(增值税专用发票)可以红冲数电发票(增值税专用发票)、增值税电子专用发票、增值税纸质专用发票。
|
||||||
*/
|
*/
|
||||||
val invoiceKind = varchar("invoice_kind", 2).nullable()
|
val invoiceKind = varchar("invoice_kind", 2).nullable()
|
||||||
|
|
||||||
@@ -104,3 +104,4 @@ object HistoryInvoiceRedTable : Table("history_invoice_red") {
|
|||||||
|
|
||||||
override val primaryKey = PrimaryKey(id)
|
override val primaryKey = PrimaryKey(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ object OpenInvoiceTaskTable : Table("open_invoice_task") {
|
|||||||
val taxAccount = varchar("tax_account", 64).nullable()
|
val taxAccount = varchar("tax_account", 64).nullable()
|
||||||
val taskType = varchar("task_type", 32)
|
val taskType = varchar("task_type", 32)
|
||||||
val sourceType = varchar("source_type", 32)
|
val sourceType = varchar("source_type", 32)
|
||||||
val runMode = varchar("run_mode", 16)
|
|
||||||
val invoiceReqSerialNo = varchar("invoice_req_serial_no", 20)
|
val invoiceReqSerialNo = varchar("invoice_req_serial_no", 20)
|
||||||
val batchNo = varchar("batch_no", 64).nullable()
|
val batchNo = varchar("batch_no", 64).nullable()
|
||||||
val status = varchar("status", 32)
|
val status = varchar("status", 32)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ data class OpenInvoiceTaskSubmitResponse(
|
|||||||
val invoiceReqSerialNo: String,
|
val invoiceReqSerialNo: String,
|
||||||
val status: String,
|
val status: String,
|
||||||
val taskType: String,
|
val taskType: String,
|
||||||
val runMode: String,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@@ -37,7 +36,6 @@ data class OpenInvoiceTaskItem(
|
|||||||
val account: String? = null,
|
val account: String? = null,
|
||||||
val taskType: String,
|
val taskType: String,
|
||||||
val sourceType: String,
|
val sourceType: String,
|
||||||
val runMode: String,
|
|
||||||
val invoiceReqSerialNo: String,
|
val invoiceReqSerialNo: String,
|
||||||
val batchNo: String? = null,
|
val batchNo: String? = null,
|
||||||
val status: String,
|
val status: String,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bbit.ticket.entity.request
|
package com.bbit.ticket.entity.request
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -28,7 +28,7 @@ data class CreateRedInvoiceRequest(
|
|||||||
/**
|
/**
|
||||||
* 蓝票代码
|
* 蓝票代码
|
||||||
*
|
*
|
||||||
* 冲红税控发票或数电纸质发票时必填
|
* 红冲税控发票或数电纸质发票时必填
|
||||||
*/
|
*/
|
||||||
@SerialName("blueInvoiceCode")
|
@SerialName("blueInvoiceCode")
|
||||||
val blueInvoiceCode: String? = null,
|
val blueInvoiceCode: String? = null,
|
||||||
@@ -36,7 +36,7 @@ data class CreateRedInvoiceRequest(
|
|||||||
/**
|
/**
|
||||||
* 蓝票号码
|
* 蓝票号码
|
||||||
*
|
*
|
||||||
* 冲红税控发票或数电纸质发票时必填
|
* 红冲税控发票或数电纸质发票时必填
|
||||||
*/
|
*/
|
||||||
@SerialName("blueInvoiceNo")
|
@SerialName("blueInvoiceNo")
|
||||||
val blueInvoiceNo: String? = null,
|
val blueInvoiceNo: String? = null,
|
||||||
@@ -98,4 +98,4 @@ data class CreateRedInvoiceRequest(
|
|||||||
*/
|
*/
|
||||||
@SerialName("definedData")
|
@SerialName("definedData")
|
||||||
val definedData: String? = null
|
val definedData: String? = null
|
||||||
)
|
)
|
||||||
|
|||||||
+6
-6
@@ -1,4 +1,4 @@
|
|||||||
package com.bbit.ticket.entity.request
|
package com.bbit.ticket.entity.request
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@@ -20,25 +20,25 @@ data class InitRedInvoiceConfirmRequest(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 税控蓝字发票代码(10或12位)
|
* 税控蓝字发票代码(10或12位)
|
||||||
* 冲红增值税发票管理系统开具的发票或数电纸票时必填
|
* 红冲增值税发票管理系统开具的发票或数电纸票时必填
|
||||||
*/
|
*/
|
||||||
val invoiceCode: String? = null,
|
val invoiceCode: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 税控蓝字发票号码(8位)
|
* 税控蓝字发票号码(8位)
|
||||||
* 冲红增值税发票管理系统开具的发票或数电纸票时必填
|
* 红冲增值税发票管理系统开具的发票或数电纸票时必填
|
||||||
*/
|
*/
|
||||||
val invoiceNo: String? = null,
|
val invoiceNo: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 蓝字数电票号码(20位)
|
* 蓝字数电票号码(20位)
|
||||||
* 冲红数电发票时必填
|
* 红冲数电发票时必填
|
||||||
*/
|
*/
|
||||||
val blueAllEleInvNo: String? = null,
|
val blueAllEleInvNo: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 蓝字发票开票日期(yyyyMMdd)
|
* 蓝字发票开票日期(yyyyMMdd)
|
||||||
* 冲红非票通平台开具的发票时必填
|
* 红冲非票通平台开具的发票时必填
|
||||||
*/
|
*/
|
||||||
val blueInvoiceDate: String? = null,
|
val blueInvoiceDate: String? = null,
|
||||||
|
|
||||||
@@ -48,4 +48,4 @@ data class InitRedInvoiceConfirmRequest(
|
|||||||
* 若不传:优先取蓝票开票账号,否则取企业当前账号
|
* 若不传:优先取蓝票开票账号,否则取企业当前账号
|
||||||
*/
|
*/
|
||||||
val account: String? = null
|
val account: String? = null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.bbit.ticket.entity.request
|
package com.bbit.ticket.entity.request
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 快捷冲红数电发票请求
|
* 快捷红冲数电发票请求
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class QuickRedInvoiceRequest(
|
data class QuickRedInvoiceRequest(
|
||||||
@@ -29,7 +29,7 @@ data class QuickRedInvoiceRequest(
|
|||||||
/**
|
/**
|
||||||
* 原发票代码
|
* 原发票代码
|
||||||
*
|
*
|
||||||
* 冲红增值税系统发票或数电纸质发票时必填
|
* 红冲增值税系统发票或数电纸质发票时必填
|
||||||
*/
|
*/
|
||||||
@SerialName("invoiceCode")
|
@SerialName("invoiceCode")
|
||||||
val invoiceCode: String? = null,
|
val invoiceCode: String? = null,
|
||||||
@@ -37,7 +37,7 @@ data class QuickRedInvoiceRequest(
|
|||||||
/**
|
/**
|
||||||
* 原发票号码
|
* 原发票号码
|
||||||
*
|
*
|
||||||
* 冲红增值税系统发票或数电纸质发票时必填
|
* 红冲增值税系统发票或数电纸质发票时必填
|
||||||
*/
|
*/
|
||||||
@SerialName("invoiceNo")
|
@SerialName("invoiceNo")
|
||||||
val invoiceNo: String? = null,
|
val invoiceNo: String? = null,
|
||||||
@@ -45,7 +45,7 @@ data class QuickRedInvoiceRequest(
|
|||||||
/**
|
/**
|
||||||
* 原数电发票号码
|
* 原数电发票号码
|
||||||
*
|
*
|
||||||
* 冲红数电发票时必填
|
* 红冲数电发票时必填
|
||||||
*/
|
*/
|
||||||
@SerialName("blueAllEleInvNo")
|
@SerialName("blueAllEleInvNo")
|
||||||
val blueAllEleInvNo: String? = null,
|
val blueAllEleInvNo: String? = null,
|
||||||
@@ -56,14 +56,14 @@ data class QuickRedInvoiceRequest(
|
|||||||
* 格式:yyyyMMdd
|
* 格式:yyyyMMdd
|
||||||
*
|
*
|
||||||
* 场景:
|
* 场景:
|
||||||
* 冲红非票通平台开具的发票时必填,
|
* 红冲非票通平台开具的发票时必填,
|
||||||
* 税局会结合该日期与数电发票号码拉取原票
|
* 税局会结合该日期与数电发票号码拉取原票
|
||||||
*/
|
*/
|
||||||
@SerialName("blueInvoiceDate")
|
@SerialName("blueInvoiceDate")
|
||||||
val blueInvoiceDate: String? = null,
|
val blueInvoiceDate: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 冲红原因
|
* 红冲原因
|
||||||
*
|
*
|
||||||
* 默认值:01
|
* 默认值:01
|
||||||
*
|
*
|
||||||
@@ -108,7 +108,7 @@ data class QuickRedInvoiceRequest(
|
|||||||
*
|
*
|
||||||
* 默认取蓝票票种
|
* 默认取蓝票票种
|
||||||
*
|
*
|
||||||
* 用于跨票种冲红场景
|
* 用于跨票种红冲场景
|
||||||
*/
|
*/
|
||||||
@SerialName("invoiceKind")
|
@SerialName("invoiceKind")
|
||||||
val invoiceKind: String? = null,
|
val invoiceKind: String? = null,
|
||||||
@@ -150,4 +150,4 @@ data class QuickRedInvoiceRequest(
|
|||||||
*/
|
*/
|
||||||
@SerialName("definedData")
|
@SerialName("definedData")
|
||||||
val definedData: String? = null
|
val definedData: String? = null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bbit.ticket.entity.request
|
package com.bbit.ticket.entity.request
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@@ -7,7 +7,11 @@ data class RedCreateRequest(
|
|||||||
|
|
||||||
val historyId: String,
|
val historyId: String,
|
||||||
/**
|
/**
|
||||||
* 冲红原因
|
* 平台数电账号 ID。企业管理员发起红冲时用于指定开票员。
|
||||||
|
*/
|
||||||
|
val digitalAccountId: String? = null,
|
||||||
|
/**
|
||||||
|
* 红冲原因
|
||||||
*
|
*
|
||||||
* 默认值:01
|
* 默认值:01
|
||||||
*
|
*
|
||||||
@@ -22,3 +26,4 @@ data class RedCreateRequest(
|
|||||||
val takerTel: String? = null,
|
val takerTel: String? = null,
|
||||||
val takerEmail: String? = null,
|
val takerEmail: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||||
|
|
||||||
package com.bbit.ticket.entity.response
|
package com.bbit.ticket.entity.response
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ data class InvoiceHistoryItem(
|
|||||||
// ===== 发票状态标记 =====
|
// ===== 发票状态标记 =====
|
||||||
/** 作废状态 */
|
/** 作废状态 */
|
||||||
val invalidFlag: String? = null,
|
val invalidFlag: String? = null,
|
||||||
/** 冲红状态 */
|
/** 红冲状态 */
|
||||||
val redFlag: String? = null,
|
val redFlag: String? = null,
|
||||||
|
|
||||||
// ===== 人员信息 =====
|
// ===== 人员信息 =====
|
||||||
@@ -149,3 +149,4 @@ data class InvoiceHistoryItem(
|
|||||||
/** 删除标记 */
|
/** 删除标记 */
|
||||||
val invDeletedFlag: String? = null,
|
val invDeletedFlag: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bbit.ticket.entity.response
|
package com.bbit.ticket.entity.response
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -168,13 +168,13 @@ data class InvoiceInfo(
|
|||||||
val invalidFlag: String,
|
val invalidFlag: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 冲红标志
|
* 红冲标志
|
||||||
*
|
*
|
||||||
* NOT_RED:未冲红
|
* NOT_RED:未红冲
|
||||||
* ALREADY_RED:已冲红
|
* ALREADY_RED:已红冲
|
||||||
* REDING:冲红中
|
* REDING:红冲中
|
||||||
* RED_FAIL:冲红失败
|
* RED_FAIL:红冲失败
|
||||||
* PART_RED:部分冲红
|
* PART_RED:部分红冲
|
||||||
*/
|
*/
|
||||||
@SerialName("redFlag")
|
@SerialName("redFlag")
|
||||||
val redFlag: String,
|
val redFlag: String,
|
||||||
@@ -345,4 +345,4 @@ data class InvoiceItem(
|
|||||||
*/
|
*/
|
||||||
@SerialName("itemNo")
|
@SerialName("itemNo")
|
||||||
val itemNo: String
|
val itemNo: String
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bbit.ticket.entity.response
|
package com.bbit.ticket.entity.response
|
||||||
|
|
||||||
import com.bbit.ticket.entity.request.InvoiceItem
|
import com.bbit.ticket.entity.request.InvoiceItem
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -187,12 +187,12 @@ data class GetInvoiceInfoResponse(
|
|||||||
val invalidFlag: String? = null,
|
val invalidFlag: String? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 冲红状态
|
* 红冲状态
|
||||||
* NOT_RED:未冲红
|
* NOT_RED:未红冲
|
||||||
* ALREADY_RED:已冲红
|
* ALREADY_RED:已红冲
|
||||||
* REDING:冲红中
|
* REDING:红冲中
|
||||||
* RED_FAIL:冲红失败
|
* RED_FAIL:红冲失败
|
||||||
* PART_RED:部分冲红
|
* PART_RED:部分红冲
|
||||||
*/
|
*/
|
||||||
val redFlag: String? = null,
|
val redFlag: String? = null,
|
||||||
|
|
||||||
@@ -344,4 +344,4 @@ data class GetInvoiceInfoItem(
|
|||||||
|
|
||||||
/** 蓝字发票明细序号(红票场景) */
|
/** 蓝字发票明细序号(红票场景) */
|
||||||
val blueInvOrderNo: String? = null
|
val blueInvOrderNo: String? = null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.bbit.ticket.entity.response
|
package com.bbit.ticket.entity.response
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 快捷冲红数电发票响应
|
* 快捷红冲数电发票响应
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class QuickRedInvoiceResponse(
|
data class QuickRedInvoiceResponse(
|
||||||
@@ -51,4 +51,4 @@ data class QuickRedInvoiceResponse(
|
|||||||
*/
|
*/
|
||||||
@SerialName("redApplySerialNo")
|
@SerialName("redApplySerialNo")
|
||||||
val redApplySerialNo: String? = null
|
val redApplySerialNo: String? = null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package com.bbit.ticket.entity.response
|
package com.bbit.ticket.entity.response
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 红票申请信息
|
* 红票申请信息
|
||||||
*
|
*
|
||||||
* 对应 [HistoryInvoiceRedTable] 的冲红申请字段,
|
* 对应 [HistoryInvoiceRedTable] 的红冲申请字段,
|
||||||
* 用于红票详情弹窗展示。
|
* 用于红票详情弹窗展示。
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class RedInvoiceInfoResponse(
|
data class RedInvoiceInfoResponse(
|
||||||
/** 冲红原因:01=开票有误 02=销货退回 03=服务中止 04=销售折让 */
|
/** 红冲原因:01=开票有误 02=销货退回 03=服务中止 04=销售折让 */
|
||||||
val redReason: String,
|
val redReason: String,
|
||||||
/** 收票人名称 */
|
/** 收票人名称 */
|
||||||
val takerName: String? = null,
|
val takerName: String? = null,
|
||||||
@@ -19,3 +19,4 @@ data class RedInvoiceInfoResponse(
|
|||||||
/** 收票人邮箱 */
|
/** 收票人邮箱 */
|
||||||
val takerEmail: String? = null,
|
val takerEmail: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+2
-16
@@ -8,27 +8,13 @@ import io.ktor.server.routing.Route
|
|||||||
import io.ktor.server.routing.post
|
import io.ktor.server.routing.post
|
||||||
|
|
||||||
fun Route.registerOpenInvoiceTaskRoutes() {
|
fun Route.registerOpenInvoiceTaskRoutes() {
|
||||||
post("/test") {
|
post {
|
||||||
val principal = call.requireOpenApiPrincipal()
|
val principal = call.requireOpenApiPrincipal()
|
||||||
val request = call.receive<OpenBlueInvoiceCreateRequest>()
|
val request = call.receive<OpenBlueInvoiceCreateRequest>()
|
||||||
call.respondOpenApi(principal, "blue-invoice-task.test", null) {
|
call.respondOpenApi(principal, "blue-invoice-task.create", null) {
|
||||||
OpenInvoiceTaskService.createIssueTask(
|
OpenInvoiceTaskService.createIssueTask(
|
||||||
principal = principal,
|
principal = principal,
|
||||||
request = request,
|
request = request,
|
||||||
runMode = OpenInvoiceTaskService.MODE_SIMULATED,
|
|
||||||
sourceType = OpenInvoiceTaskService.SOURCE_TEST,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
post("/production") {
|
|
||||||
val principal = call.requireOpenApiPrincipal()
|
|
||||||
val request = call.receive<OpenBlueInvoiceCreateRequest>()
|
|
||||||
call.respondOpenApi(principal, "blue-invoice-task.production", null) {
|
|
||||||
OpenInvoiceTaskService.createIssueTask(
|
|
||||||
principal = principal,
|
|
||||||
request = request,
|
|
||||||
runMode = OpenInvoiceTaskService.MODE_REAL,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -21,7 +21,6 @@ fun Route.registerOpenInvoiceTaskManageRoutes() {
|
|||||||
digitalAccountId = call.request.queryParameters["digitalAccountId"],
|
digitalAccountId = call.request.queryParameters["digitalAccountId"],
|
||||||
status = call.request.queryParameters["status"],
|
status = call.request.queryParameters["status"],
|
||||||
sourceType = call.request.queryParameters["sourceType"],
|
sourceType = call.request.queryParameters["sourceType"],
|
||||||
runMode = call.request.queryParameters["runMode"],
|
|
||||||
page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1,
|
page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1,
|
||||||
pageSize = call.request.queryParameters["pageSize"]?.toIntOrNull() ?: 20,
|
pageSize = call.request.queryParameters["pageSize"]?.toIntOrNull() ?: 20,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import com.bbit.ticket.entity.request.UpdateDigitalAccountStatusRequest
|
|||||||
import com.bbit.ticket.entity.request.UpdateInvoiceSettingRequest
|
import com.bbit.ticket.entity.request.UpdateInvoiceSettingRequest
|
||||||
import com.bbit.ticket.service.piaotong.PTAuthService
|
import com.bbit.ticket.service.piaotong.PTAuthService
|
||||||
import com.bbit.ticket.service.piaotong.PTConfigService
|
import com.bbit.ticket.service.piaotong.PTConfigService
|
||||||
|
import com.bbit.ticket.utils.queryInt
|
||||||
|
import com.bbit.ticket.utils.queryString
|
||||||
import com.bbit.ticket.utils.requireCurrentUser
|
import com.bbit.ticket.utils.requireCurrentUser
|
||||||
import io.ktor.server.request.receive
|
import io.ktor.server.request.receive
|
||||||
import io.ktor.server.routing.Route
|
import io.ktor.server.routing.Route
|
||||||
@@ -59,7 +61,23 @@ fun Route.registerPTAuthRoutes() {
|
|||||||
|
|
||||||
get("/digital-accounts") {
|
get("/digital-accounts") {
|
||||||
call.respondPt("查询数电账号失败") {
|
call.respondPt("查询数电账号失败") {
|
||||||
PTConfigService.listDigitalAccounts(call.requireCurrentUser())
|
PTConfigService.listDigitalAccounts(
|
||||||
|
user = call.requireCurrentUser(),
|
||||||
|
account = call.queryString("account"),
|
||||||
|
status = call.queryString("status"),
|
||||||
|
page = call.queryInt("page", 1),
|
||||||
|
pageSize = call.queryInt("pageSize", 20),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get("/digital-accounts/options") {
|
||||||
|
call.respondPt("查询数电账号选项失败") {
|
||||||
|
PTConfigService.listDigitalAccountOptions(
|
||||||
|
user = call.requireCurrentUser(),
|
||||||
|
account = call.queryString("account"),
|
||||||
|
limit = call.queryInt("limit", 200),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,9 +56,6 @@ object OpenInvoiceTaskService {
|
|||||||
const val TASK_ISSUE_BLUE = "ISSUE_BLUE"
|
const val TASK_ISSUE_BLUE = "ISSUE_BLUE"
|
||||||
const val TASK_QUERY_BLUE = "QUERY_BLUE"
|
const val TASK_QUERY_BLUE = "QUERY_BLUE"
|
||||||
const val SOURCE_SINGLE = "SINGLE"
|
const val SOURCE_SINGLE = "SINGLE"
|
||||||
const val SOURCE_TEST = "TEST"
|
|
||||||
const val MODE_REAL = "REAL"
|
|
||||||
const val MODE_SIMULATED = "SIMULATED"
|
|
||||||
|
|
||||||
private const val STATUS_PENDING = "PENDING"
|
private const val STATUS_PENDING = "PENDING"
|
||||||
private const val STATUS_PROCESSING = "PROCESSING"
|
private const val STATUS_PROCESSING = "PROCESSING"
|
||||||
@@ -75,7 +72,6 @@ object OpenInvoiceTaskService {
|
|||||||
suspend fun createIssueTask(
|
suspend fun createIssueTask(
|
||||||
principal: OpenApiPrincipal,
|
principal: OpenApiPrincipal,
|
||||||
request: OpenBlueInvoiceCreateRequest,
|
request: OpenBlueInvoiceCreateRequest,
|
||||||
runMode: String,
|
|
||||||
sourceType: String = SOURCE_SINGLE,
|
sourceType: String = SOURCE_SINGLE,
|
||||||
batchNo: String? = null,
|
batchNo: String? = null,
|
||||||
): OpenInvoiceTaskSubmitResponse {
|
): OpenInvoiceTaskSubmitResponse {
|
||||||
@@ -97,12 +93,6 @@ object OpenInvoiceTaskService {
|
|||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
}
|
}
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
if (existing[OpenInvoiceTaskTable.runMode] != runMode) {
|
|
||||||
throw BizException(
|
|
||||||
ErrorCode.BAD_REQUEST.code,
|
|
||||||
"invoiceReqSerialNo 已存在 ${existing[OpenInvoiceTaskTable.runMode]} 任务,不能重复创建 $runMode 任务",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return existing.toSubmitResponse()
|
return existing.toSubmitResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +119,6 @@ object OpenInvoiceTaskService {
|
|||||||
it[taxAccount] = principal.taxAccount
|
it[taxAccount] = principal.taxAccount
|
||||||
it[taskType] = TASK_ISSUE_BLUE
|
it[taskType] = TASK_ISSUE_BLUE
|
||||||
it[OpenInvoiceTaskTable.sourceType] = sourceType
|
it[OpenInvoiceTaskTable.sourceType] = sourceType
|
||||||
it[OpenInvoiceTaskTable.runMode] = runMode
|
|
||||||
it[OpenInvoiceTaskTable.invoiceReqSerialNo] = invoiceReqSerialNo
|
it[OpenInvoiceTaskTable.invoiceReqSerialNo] = invoiceReqSerialNo
|
||||||
it[OpenInvoiceTaskTable.batchNo] = batchNo
|
it[OpenInvoiceTaskTable.batchNo] = batchNo
|
||||||
it[status] = STATUS_PENDING
|
it[status] = STATUS_PENDING
|
||||||
@@ -146,19 +135,12 @@ object OpenInvoiceTaskService {
|
|||||||
}
|
}
|
||||||
.single()
|
.single()
|
||||||
}
|
}
|
||||||
if (task[OpenInvoiceTaskTable.runMode] != runMode) {
|
|
||||||
throw BizException(
|
|
||||||
ErrorCode.BAD_REQUEST.code,
|
|
||||||
"invoiceReqSerialNo 已存在 ${task[OpenInvoiceTaskTable.runMode]} 任务,不能重复创建 $runMode 任务",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return OpenInvoiceTaskSubmitResponse(
|
return OpenInvoiceTaskSubmitResponse(
|
||||||
taskId = task[OpenInvoiceTaskTable.id].toString(),
|
taskId = task[OpenInvoiceTaskTable.id].toString(),
|
||||||
invoiceReqSerialNo = invoiceReqSerialNo,
|
invoiceReqSerialNo = invoiceReqSerialNo,
|
||||||
status = task[OpenInvoiceTaskTable.status],
|
status = task[OpenInvoiceTaskTable.status],
|
||||||
taskType = TASK_ISSUE_BLUE,
|
taskType = TASK_ISSUE_BLUE,
|
||||||
runMode = runMode,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +183,6 @@ object OpenInvoiceTaskService {
|
|||||||
digitalAccountId: String?,
|
digitalAccountId: String?,
|
||||||
status: String?,
|
status: String?,
|
||||||
sourceType: String?,
|
sourceType: String?,
|
||||||
runMode: String?,
|
|
||||||
page: Int,
|
page: Int,
|
||||||
pageSize: Int,
|
pageSize: Int,
|
||||||
): PageResult<OpenInvoiceTaskItem> = dbQuery {
|
): PageResult<OpenInvoiceTaskItem> = dbQuery {
|
||||||
@@ -215,19 +196,32 @@ object OpenInvoiceTaskService {
|
|||||||
sourceType?.takeIf { it.isNotBlank() }?.let {
|
sourceType?.takeIf { it.isNotBlank() }?.let {
|
||||||
where = where and (OpenInvoiceTaskTable.sourceType eq it)
|
where = where and (OpenInvoiceTaskTable.sourceType eq it)
|
||||||
}
|
}
|
||||||
runMode?.takeIf { it.isNotBlank() }?.let {
|
|
||||||
where = where and (OpenInvoiceTaskTable.runMode eq it)
|
|
||||||
}
|
|
||||||
val accountRows = PtDigitalAccountTable.selectAll()
|
val accountRows = PtDigitalAccountTable.selectAll()
|
||||||
.where { accountScope(user) }
|
.where { accountScope(user) }
|
||||||
.associateBy { it[PtDigitalAccountTable.id] }
|
.associateBy { it[PtDigitalAccountTable.id] }
|
||||||
val total = OpenInvoiceTaskTable.selectAll().where { where }.count()
|
val total = OpenInvoiceTaskTable.selectAll().where { where }.count()
|
||||||
val items = OpenInvoiceTaskTable.selectAll()
|
val taskRows = OpenInvoiceTaskTable.selectAll()
|
||||||
.where { where }
|
.where { where }
|
||||||
.orderBy(OpenInvoiceTaskTable.createdAt, SortOrder.DESC)
|
.orderBy(OpenInvoiceTaskTable.createdAt, SortOrder.DESC)
|
||||||
.limit(pageSize)
|
.limit(pageSize)
|
||||||
.offset(((page - 1).coerceAtLeast(0) * pageSize).toLong())
|
.offset(((page - 1).coerceAtLeast(0) * pageSize).toLong())
|
||||||
.map { it.toTaskItem(accountRows[it[OpenInvoiceTaskTable.digitalAccountId]]?.get(PtDigitalAccountTable.account)) }
|
.toList()
|
||||||
|
val historyMessages = taskRows
|
||||||
|
.map { it[OpenInvoiceTaskTable.invoiceReqSerialNo] }
|
||||||
|
.distinct()
|
||||||
|
.takeIf { it.isNotEmpty() }
|
||||||
|
?.let { serialNos ->
|
||||||
|
HistoryInvoiceBasicTable.selectAll()
|
||||||
|
.where { HistoryInvoiceBasicTable.invoiceReqSerialNo inList serialNos }
|
||||||
|
.associate { it[HistoryInvoiceBasicTable.invoiceReqSerialNo] to it[HistoryInvoiceBasicTable.msg] }
|
||||||
|
}
|
||||||
|
?: emptyMap()
|
||||||
|
val items = taskRows.map {
|
||||||
|
it.toTaskItem(
|
||||||
|
accountRows[it[OpenInvoiceTaskTable.digitalAccountId]]?.get(PtDigitalAccountTable.account),
|
||||||
|
historyMessages[it[OpenInvoiceTaskTable.invoiceReqSerialNo]],
|
||||||
|
)
|
||||||
|
}
|
||||||
PageResult(items, page, pageSize, total)
|
PageResult(items, page, pageSize, total)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,18 +268,13 @@ object OpenInvoiceTaskService {
|
|||||||
|
|
||||||
private suspend fun processIssueTask(task: ResultRow) {
|
private suspend fun processIssueTask(task: ResultRow) {
|
||||||
val taskId = task[OpenInvoiceTaskTable.id]
|
val taskId = task[OpenInvoiceTaskTable.id]
|
||||||
val runMode = task[OpenInvoiceTaskTable.runMode]
|
|
||||||
val request = task[OpenInvoiceTaskTable.requestBody]
|
val request = task[OpenInvoiceTaskTable.requestBody]
|
||||||
?.let { myJson.decodeFromString<OpenBlueInvoiceCreateRequest>(it) }
|
?.let { myJson.decodeFromString<OpenBlueInvoiceCreateRequest>(it) }
|
||||||
?: return failTask(taskId, "REQUEST_BODY_NULL", "任务请求体为空")
|
?: return failTask(taskId, "REQUEST_BODY_NULL", "任务请求体为空")
|
||||||
val askRequest = request.toAskInvoiceRequest(task)
|
val askRequest = request.toAskInvoiceRequest(task)
|
||||||
createHistoryPlaceholder(task, askRequest)
|
createHistoryPlaceholder(task, askRequest)
|
||||||
try {
|
try {
|
||||||
if (runMode == MODE_SIMULATED) {
|
PTApi.invoiceBlue(askRequest)
|
||||||
delay(2000)
|
|
||||||
} else {
|
|
||||||
PTApi.invoiceBlue(askRequest)
|
|
||||||
}
|
|
||||||
completeIssueTask(task)
|
completeIssueTask(task)
|
||||||
} catch (e: PTException) {
|
} catch (e: PTException) {
|
||||||
failTask(taskId, e.code, e.message)
|
failTask(taskId, e.code, e.message)
|
||||||
@@ -298,31 +287,23 @@ object OpenInvoiceTaskService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun processQueryTask(task: ResultRow) {
|
private suspend fun processQueryTask(task: ResultRow) {
|
||||||
val taskId = task[OpenInvoiceTaskTable.id]
|
|
||||||
val runMode = task[OpenInvoiceTaskTable.runMode]
|
|
||||||
val invoiceReqSerialNo = task[OpenInvoiceTaskTable.invoiceReqSerialNo]
|
val invoiceReqSerialNo = task[OpenInvoiceTaskTable.invoiceReqSerialNo]
|
||||||
try {
|
try {
|
||||||
val code = if (runMode == MODE_SIMULATED) {
|
val res = PTApi.queryInvoiceInfo(
|
||||||
delay(2000)
|
QueryInvoiceRequest(
|
||||||
simulatedQueryCode(invoiceReqSerialNo, task[OpenInvoiceTaskTable.pollCount])
|
taxpayerNum = task[OpenInvoiceTaskTable.taxpayerNum],
|
||||||
} else {
|
invoiceReqSerialNo = invoiceReqSerialNo,
|
||||||
val res = PTApi.queryInvoiceInfo(
|
)
|
||||||
QueryInvoiceRequest(
|
)
|
||||||
taxpayerNum = task[OpenInvoiceTaskTable.taxpayerNum],
|
dbQuery {
|
||||||
invoiceReqSerialNo = invoiceReqSerialNo,
|
BlueInvoiceDao.upsertInvoiceInfo(
|
||||||
)
|
task[OpenInvoiceTaskTable.userId],
|
||||||
|
res,
|
||||||
|
task[OpenInvoiceTaskTable.enterpriseId],
|
||||||
|
task[OpenInvoiceTaskTable.digitalAccountId],
|
||||||
)
|
)
|
||||||
dbQuery {
|
|
||||||
BlueInvoiceDao.upsertInvoiceInfo(
|
|
||||||
task[OpenInvoiceTaskTable.userId],
|
|
||||||
res,
|
|
||||||
task[OpenInvoiceTaskTable.enterpriseId],
|
|
||||||
task[OpenInvoiceTaskTable.digitalAccountId],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
res.code
|
|
||||||
}
|
}
|
||||||
handleQueryCode(task, code)
|
handleQueryCode(task, res.code, res.msg)
|
||||||
} catch (e: PTException) {
|
} catch (e: PTException) {
|
||||||
retryOrFail(task, e.code, e.message)
|
retryOrFail(task, e.code, e.message)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -352,7 +333,6 @@ object OpenInvoiceTaskService {
|
|||||||
it[taxAccount] = task[OpenInvoiceTaskTable.taxAccount]
|
it[taxAccount] = task[OpenInvoiceTaskTable.taxAccount]
|
||||||
it[taskType] = TASK_QUERY_BLUE
|
it[taskType] = TASK_QUERY_BLUE
|
||||||
it[sourceType] = task[OpenInvoiceTaskTable.sourceType]
|
it[sourceType] = task[OpenInvoiceTaskTable.sourceType]
|
||||||
it[runMode] = task[OpenInvoiceTaskTable.runMode]
|
|
||||||
it[OpenInvoiceTaskTable.invoiceReqSerialNo] = invoiceReqSerialNo
|
it[OpenInvoiceTaskTable.invoiceReqSerialNo] = invoiceReqSerialNo
|
||||||
it[batchNo] = task[OpenInvoiceTaskTable.batchNo]
|
it[batchNo] = task[OpenInvoiceTaskTable.batchNo]
|
||||||
it[status] = STATUS_PENDING
|
it[status] = STATUS_PENDING
|
||||||
@@ -365,23 +345,23 @@ object OpenInvoiceTaskService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleQueryCode(task: ResultRow, code: String) {
|
private suspend fun handleQueryCode(task: ResultRow, code: String, message: String?) {
|
||||||
when (code) {
|
when (code) {
|
||||||
"0000" -> finishQueryTask(task, STATUS_SUCCESS, code, null)
|
"0000" -> finishQueryTask(task, STATUS_SUCCESS, code, null)
|
||||||
"9999" -> finishQueryTask(task, STATUS_FAILED, code, "开票失败")
|
"9999" -> finishQueryTask(task, STATUS_FAILED, code, message?.takeIf { it.isNotBlank() } ?: "开票失败")
|
||||||
AUTH_REQUIRED_CODE -> {
|
AUTH_REQUIRED_CODE -> {
|
||||||
val message = "需要登录/风险认证"
|
val authMessage = message?.takeIf { it.isNotBlank() } ?: "需要登录/风险认证"
|
||||||
dbQuery {
|
dbQuery {
|
||||||
OpenInvoiceTaskTable.update({ OpenInvoiceTaskTable.id eq task[OpenInvoiceTaskTable.id] }) {
|
OpenInvoiceTaskTable.update({ OpenInvoiceTaskTable.id eq task[OpenInvoiceTaskTable.id] }) {
|
||||||
it[status] = STATUS_WAITING_AUTH
|
it[status] = STATUS_WAITING_AUTH
|
||||||
it[ptCode] = code
|
it[ptCode] = code
|
||||||
it[errorMessage] = message
|
it[errorMessage] = authMessage
|
||||||
it[updatedAt] = OffsetDateTime.now()
|
it[updatedAt] = OffsetDateTime.now()
|
||||||
it[lockedBy] = null
|
it[lockedBy] = null
|
||||||
it[lockedAt] = null
|
it[lockedAt] = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pauseApiKey(task[OpenInvoiceTaskTable.apiKey], code, message)
|
pauseApiKey(task[OpenInvoiceTaskTable.apiKey], code, authMessage)
|
||||||
}
|
}
|
||||||
"7777", "6666" -> requeueQueryTask(task, code)
|
"7777", "6666" -> requeueQueryTask(task, code)
|
||||||
else -> requeueQueryTask(task, code)
|
else -> requeueQueryTask(task, code)
|
||||||
@@ -644,15 +624,6 @@ object OpenInvoiceTaskService {
|
|||||||
orderList = orderList,
|
orderList = orderList,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun simulatedQueryCode(invoiceReqSerialNo: String, pollCount: Int): String =
|
|
||||||
when {
|
|
||||||
invoiceReqSerialNo.contains("3999", ignoreCase = true) -> AUTH_REQUIRED_CODE
|
|
||||||
invoiceReqSerialNo.contains("FAIL", ignoreCase = true) -> "9999"
|
|
||||||
pollCount <= 0 -> "7777"
|
|
||||||
pollCount == 1 -> "6666"
|
|
||||||
else -> "0000"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun historyCode(code: String): String =
|
private fun historyCode(code: String): String =
|
||||||
if (code.length <= 8) code else HISTORY_FAILED_CODE
|
if (code.length <= 8) code else HISTORY_FAILED_CODE
|
||||||
|
|
||||||
@@ -690,10 +661,9 @@ object OpenInvoiceTaskService {
|
|||||||
invoiceReqSerialNo = this[OpenInvoiceTaskTable.invoiceReqSerialNo],
|
invoiceReqSerialNo = this[OpenInvoiceTaskTable.invoiceReqSerialNo],
|
||||||
status = this[OpenInvoiceTaskTable.status],
|
status = this[OpenInvoiceTaskTable.status],
|
||||||
taskType = this[OpenInvoiceTaskTable.taskType],
|
taskType = this[OpenInvoiceTaskTable.taskType],
|
||||||
runMode = this[OpenInvoiceTaskTable.runMode],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun ResultRow.toTaskItem(account: String?): OpenInvoiceTaskItem =
|
private fun ResultRow.toTaskItem(account: String?, historyMessage: String?): OpenInvoiceTaskItem =
|
||||||
OpenInvoiceTaskItem(
|
OpenInvoiceTaskItem(
|
||||||
id = this[OpenInvoiceTaskTable.id].toString(),
|
id = this[OpenInvoiceTaskTable.id].toString(),
|
||||||
digitalAccountId = this[OpenInvoiceTaskTable.digitalAccountId].toString(),
|
digitalAccountId = this[OpenInvoiceTaskTable.digitalAccountId].toString(),
|
||||||
@@ -701,12 +671,12 @@ object OpenInvoiceTaskService {
|
|||||||
account = account,
|
account = account,
|
||||||
taskType = this[OpenInvoiceTaskTable.taskType],
|
taskType = this[OpenInvoiceTaskTable.taskType],
|
||||||
sourceType = this[OpenInvoiceTaskTable.sourceType],
|
sourceType = this[OpenInvoiceTaskTable.sourceType],
|
||||||
runMode = this[OpenInvoiceTaskTable.runMode],
|
|
||||||
invoiceReqSerialNo = this[OpenInvoiceTaskTable.invoiceReqSerialNo],
|
invoiceReqSerialNo = this[OpenInvoiceTaskTable.invoiceReqSerialNo],
|
||||||
batchNo = this[OpenInvoiceTaskTable.batchNo],
|
batchNo = this[OpenInvoiceTaskTable.batchNo],
|
||||||
status = this[OpenInvoiceTaskTable.status],
|
status = this[OpenInvoiceTaskTable.status],
|
||||||
ptCode = this[OpenInvoiceTaskTable.ptCode],
|
ptCode = this[OpenInvoiceTaskTable.ptCode],
|
||||||
errorMessage = this[OpenInvoiceTaskTable.errorMessage],
|
errorMessage = this[OpenInvoiceTaskTable.errorMessage]
|
||||||
|
?: historyMessage?.takeIf { this[OpenInvoiceTaskTable.status] == STATUS_FAILED },
|
||||||
attemptCount = this[OpenInvoiceTaskTable.attemptCount],
|
attemptCount = this[OpenInvoiceTaskTable.attemptCount],
|
||||||
maxAttemptCount = this[OpenInvoiceTaskTable.maxAttemptCount],
|
maxAttemptCount = this[OpenInvoiceTaskTable.maxAttemptCount],
|
||||||
pollCount = this[OpenInvoiceTaskTable.pollCount],
|
pollCount = this[OpenInvoiceTaskTable.pollCount],
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.bbit.ticket.dao.piaotong.EnterpriseManageDao
|
|||||||
import com.bbit.ticket.dao.system.UserDao
|
import com.bbit.ticket.dao.system.UserDao
|
||||||
import com.bbit.ticket.database.piaotong.PtDigitalAccountTable
|
import com.bbit.ticket.database.piaotong.PtDigitalAccountTable
|
||||||
import com.bbit.ticket.database.system.SysUserTable
|
import com.bbit.ticket.database.system.SysUserTable
|
||||||
|
import com.bbit.ticket.entity.common.PageResult
|
||||||
import com.bbit.ticket.entity.request.CreateDigitalAccountRequest
|
import com.bbit.ticket.entity.request.CreateDigitalAccountRequest
|
||||||
import com.bbit.ticket.entity.request.QueryDigitalAccountListRequest
|
import com.bbit.ticket.entity.request.QueryDigitalAccountListRequest
|
||||||
import com.bbit.ticket.entity.request.QueryEnterpriseBankAccountRequest
|
import com.bbit.ticket.entity.request.QueryEnterpriseBankAccountRequest
|
||||||
@@ -62,15 +63,42 @@ object PTConfigService {
|
|||||||
return PTAuthService.queryEnterpriseBankInfo(QueryEnterpriseBankAccountRequest(taxpayerNum)).bankList
|
return PTAuthService.queryEnterpriseBankInfo(QueryEnterpriseBankAccountRequest(taxpayerNum)).bankList
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun listDigitalAccounts(user: CurrentUser): List<DigitalAccountManageItem> = dbQuery {
|
suspend fun listDigitalAccounts(
|
||||||
|
user: CurrentUser,
|
||||||
|
account: String?,
|
||||||
|
status: String?,
|
||||||
|
page: Int,
|
||||||
|
pageSize: Int,
|
||||||
|
): PageResult<DigitalAccountManageItem> = dbQuery {
|
||||||
when {
|
when {
|
||||||
user.isSuperAdmin || user.isEnterpriseAdmin -> {
|
user.isSuperAdmin || user.isEnterpriseAdmin -> {
|
||||||
EnterpriseManageDao.digitalAccountsForEnterprise(requireEnterpriseId(user))
|
EnterpriseManageDao.digitalAccountsForEnterprise(requireEnterpriseId(user), account, status, page, pageSize)
|
||||||
}
|
}
|
||||||
user.isDigitalOperator -> {
|
user.isDigitalOperator -> {
|
||||||
val id = user.digitalAccountId
|
val id = user.digitalAccountId
|
||||||
?: throw BizException(ErrorCode.BAD_REQUEST.code, "当前账号未绑定数电账号")
|
?: throw BizException(ErrorCode.BAD_REQUEST.code, "当前账号未绑定数电账号")
|
||||||
EnterpriseManageDao.digitalAccount(id)?.let { listOf(EnterpriseManageDao.run { it.toDigitalAccountItem() }) }
|
val item = EnterpriseManageDao.digitalAccount(id)
|
||||||
|
?.let { EnterpriseManageDao.run { it.toDigitalAccountItem() } }
|
||||||
|
?.takeIf { account.isNullOrBlank() || it.account.contains(account.trim(), ignoreCase = true) }
|
||||||
|
?.takeIf { status.isNullOrBlank() || it.status == status.trim().uppercase() }
|
||||||
|
PageResult(listOfNotNull(item), page, pageSize, if (item == null) 0 else 1)
|
||||||
|
}
|
||||||
|
else -> PageResult(emptyList(), page, pageSize, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun listDigitalAccountOptions(user: CurrentUser, account: String?, limit: Int): List<DigitalAccountManageItem> = dbQuery {
|
||||||
|
when {
|
||||||
|
user.isSuperAdmin || user.isEnterpriseAdmin -> {
|
||||||
|
EnterpriseManageDao.digitalAccountOptionsForEnterprise(requireEnterpriseId(user), account, limit.coerceIn(1, 200))
|
||||||
|
}
|
||||||
|
user.isDigitalOperator -> {
|
||||||
|
val id = user.digitalAccountId
|
||||||
|
?: throw BizException(ErrorCode.BAD_REQUEST.code, "当前账号未绑定数电账号")
|
||||||
|
EnterpriseManageDao.digitalAccount(id)
|
||||||
|
?.let { EnterpriseManageDao.run { it.toDigitalAccountItem() } }
|
||||||
|
?.takeIf { account.isNullOrBlank() || it.account.contains(account.trim(), ignoreCase = true) }
|
||||||
|
?.let { listOf(it) }
|
||||||
?: emptyList()
|
?: emptyList()
|
||||||
}
|
}
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
@@ -97,7 +125,7 @@ object PTConfigService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return listDigitalAccounts(user)
|
return listDigitalAccountOptions(user, null, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun createDigitalAccount(user: CurrentUser, req: CreateDigitalAccountRequest): DigitalAccountManageItem {
|
suspend fun createDigitalAccount(user: CurrentUser, req: CreateDigitalAccountRequest): DigitalAccountManageItem {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ object PTRedService {
|
|||||||
* 红票接口调用 2.10
|
* 红票接口调用 2.10
|
||||||
*/
|
*/
|
||||||
suspend fun invoiceRed(user: CurrentUser, req: RedCreateRequest): String {
|
suspend fun invoiceRed(user: CurrentUser, req: RedCreateRequest): String {
|
||||||
val account = PTConfigService.requireDigitalAccountForAction(user, null)
|
val account = PTConfigService.requireDigitalAccountForAction(user, req.digitalAccountId)
|
||||||
val invoiceReqSerialNo = PTClient.ptDate()
|
val invoiceReqSerialNo = PTClient.ptDate()
|
||||||
val historyId = Uuid.parse(req.historyId)
|
val historyId = Uuid.parse(req.historyId)
|
||||||
val his = dbQuery {
|
val his = dbQuery {
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ object DatabaseInitializer {
|
|||||||
exec(it)
|
exec(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
exec("ALTER TABLE open_invoice_task DROP COLUMN IF EXISTS run_mode")
|
||||||
}
|
}
|
||||||
logger.info("Database schema initialized")
|
logger.info("Database schema initialized")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package com.bbit.ticket.utils.bootstrap
|
|||||||
|
|
||||||
object Global {
|
object Global {
|
||||||
|
|
||||||
val isDev = true
|
val isDev = false
|
||||||
|
|
||||||
// 请求基础地址
|
// 请求基础地址
|
||||||
var baseUrl: String
|
var baseUrl: String
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import http from '@/api/http'
|
import http from '@/api/http'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账号状态
|
* 账号状态
|
||||||
@@ -158,8 +158,20 @@ export interface CreateDigitalAccountRequest {
|
|||||||
platformPassword: string
|
platformPassword: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listDigitalAccountsApi(): Promise<DigitalAccountItem[]> {
|
export function listDigitalAccountsApi(params: {
|
||||||
return http.get('/pt/digital-accounts')
|
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[]> {
|
export function refreshDigitalAccountsApi(): Promise<DigitalAccountItem[]> {
|
||||||
@@ -244,7 +256,6 @@ export interface OpenInvoiceTaskItem {
|
|||||||
account?: string | null
|
account?: string | null
|
||||||
taskType: string
|
taskType: string
|
||||||
sourceType: string
|
sourceType: string
|
||||||
runMode: string
|
|
||||||
invoiceReqSerialNo: string
|
invoiceReqSerialNo: string
|
||||||
batchNo?: string | null
|
batchNo?: string | null
|
||||||
status: string
|
status: string
|
||||||
@@ -271,7 +282,6 @@ export function openInvoiceTaskPageApi(params: {
|
|||||||
digitalAccountId?: string
|
digitalAccountId?: string
|
||||||
status?: string | null
|
status?: string | null
|
||||||
sourceType?: string | null
|
sourceType?: string | null
|
||||||
runMode?: string | null
|
|
||||||
}): Promise<PageResult<OpenInvoiceTaskItem>> {
|
}): Promise<PageResult<OpenInvoiceTaskItem>> {
|
||||||
return http.get('/pt/openapi/tasks', { params })
|
return http.get('/pt/openapi/tasks', { params })
|
||||||
}
|
}
|
||||||
@@ -458,7 +468,9 @@ export function invoiceIssueApi(payload: InvoiceRequest): Promise<string> {
|
|||||||
export interface RedCreateRequest {
|
export interface RedCreateRequest {
|
||||||
/** 蓝票历史记录 ID */
|
/** 蓝票历史记录 ID */
|
||||||
historyId: string
|
historyId: string
|
||||||
/** 冲红原因:01开票有误 02销货退回 03服务中止 04销售折让 */
|
/** 平台数电账号 ID。企业管理员红冲时用于指定开票员 */
|
||||||
|
digitalAccountId?: string | null
|
||||||
|
/** 红冲原因:01开票有误 02销货退回 03服务中止 04销售折让 */
|
||||||
redReason: string
|
redReason: string
|
||||||
/** 收票人名称 */
|
/** 收票人名称 */
|
||||||
takerName?: string
|
takerName?: string
|
||||||
@@ -575,7 +587,7 @@ export interface InvoiceHistoryItem {
|
|||||||
// ===== 发票状态标记 =====
|
// ===== 发票状态标记 =====
|
||||||
/** 作废状态 */
|
/** 作废状态 */
|
||||||
invalidFlag?: string
|
invalidFlag?: string
|
||||||
/** 冲红状态 */
|
/** 红冲状态 */
|
||||||
redFlag?: string
|
redFlag?: string
|
||||||
|
|
||||||
// ===== 人员信息 =====
|
// ===== 人员信息 =====
|
||||||
@@ -847,7 +859,7 @@ export function queryInvoiceApi(
|
|||||||
|
|
||||||
/** 红票申请信息 */
|
/** 红票申请信息 */
|
||||||
export interface RedInvoiceInfo {
|
export interface RedInvoiceInfo {
|
||||||
/** 冲红原因:01开票有误 02销货退回 03服务中止 04销售折让 */
|
/** 红冲原因:01开票有误 02销货退回 03服务中止 04销售折让 */
|
||||||
redReason: string
|
redReason: string
|
||||||
/** 收票人名称 */
|
/** 收票人名称 */
|
||||||
takerName?: string
|
takerName?: string
|
||||||
@@ -974,3 +986,4 @@ export function queryAuthStatusApi(payload: {
|
|||||||
}): Promise<AuthQrcodeStatusResponse> {
|
}): Promise<AuthQrcodeStatusResponse> {
|
||||||
return http.post('/pt/query-auth-status', payload)
|
return http.post('/pt/query-auth-status', payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
<div class="page-toolbar">
|
<div class="page-toolbar">
|
||||||
<h2 class="page-toolbar-title">数电账号管理</h2>
|
<h2 class="page-toolbar-title">数电账号管理</h2>
|
||||||
<div class="page-toolbar-actions">
|
<div class="page-toolbar-actions">
|
||||||
|
<n-input
|
||||||
|
v-model:value="accountKeyword"
|
||||||
|
clearable
|
||||||
|
placeholder="税局账号"
|
||||||
|
class="toolbar-filter-input"
|
||||||
|
/>
|
||||||
<n-button :loading="loading" @click="refreshAccounts">
|
<n-button :loading="loading" @click="refreshAccounts">
|
||||||
<template #icon><n-icon :component="RefreshCw" /></template>
|
<template #icon><n-icon :component="RefreshCw" /></template>
|
||||||
刷新
|
刷新
|
||||||
@@ -22,9 +28,12 @@
|
|||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="accounts"
|
:data="accounts"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:pagination="{ pageSize: 10 }"
|
:pagination="pagination"
|
||||||
:row-key="(row: DigitalAccountItem) => row.id"
|
:row-key="(row: DigitalAccountItem) => row.id"
|
||||||
:scroll-x="1460"
|
:scroll-x="1460"
|
||||||
|
remote
|
||||||
|
@update:page="onPageChange"
|
||||||
|
@update:page-size="onPageSizeChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -133,8 +142,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, h, onMounted, reactive, ref } from 'vue'
|
import { computed, h, onMounted, reactive, ref, watch } from 'vue'
|
||||||
import type { DataTableColumns, FormInst, FormRules } from 'naive-ui'
|
import type { DataTableColumns, FormInst, FormRules, PaginationProps } from 'naive-ui'
|
||||||
import {
|
import {
|
||||||
NAlert,
|
NAlert,
|
||||||
NButton,
|
NButton,
|
||||||
@@ -175,6 +184,8 @@ const authStore = useAuthStore()
|
|||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
const accounts = ref<DigitalAccountItem[]>([])
|
const accounts = ref<DigitalAccountItem[]>([])
|
||||||
|
const accountKeyword = ref('')
|
||||||
|
let accountSearchTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
const showCreate = ref(false)
|
const showCreate = ref(false)
|
||||||
const showSms = ref(false)
|
const showSms = ref(false)
|
||||||
const showQrcode = ref(false)
|
const showQrcode = ref(false)
|
||||||
@@ -195,6 +206,17 @@ const canUpdateStatus = computed(() => authStore.hasPermission('digital-account:
|
|||||||
const qrcodeTypeLabel = computed(() =>
|
const qrcodeTypeLabel = computed(() =>
|
||||||
qrcodeType.value === '2' ? '国家网络身份认证 APP' : '电子税务局 APP'
|
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({
|
const createForm = reactive({
|
||||||
account: '',
|
account: '',
|
||||||
@@ -352,7 +374,17 @@ function renderEllipsisText(value?: string | null) {
|
|||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
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 {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@@ -361,13 +393,26 @@ async function load() {
|
|||||||
async function refreshAccounts() {
|
async function refreshAccounts() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
accounts.value = await refreshDigitalAccountsApi()
|
await refreshDigitalAccountsApi()
|
||||||
message.success('数电账号已刷新')
|
message.success('数电账号已刷新')
|
||||||
|
pager.page = 1
|
||||||
|
await load()
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
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() {
|
async function createAccount() {
|
||||||
await createFormRef.value?.validate()
|
await createFormRef.value?.validate()
|
||||||
saving.value = true
|
saving.value = true
|
||||||
@@ -451,6 +496,14 @@ async function loadQrcode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(load)
|
onMounted(load)
|
||||||
|
|
||||||
|
watch(accountKeyword, () => {
|
||||||
|
if (accountSearchTimer) clearTimeout(accountSearchTimer)
|
||||||
|
accountSearchTimer = setTimeout(() => {
|
||||||
|
pager.page = 1
|
||||||
|
load()
|
||||||
|
}, 300)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -461,6 +514,10 @@ onMounted(load)
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar-filter-input {
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
.row-actions {
|
.row-actions {
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page-shell invoice-history-page">
|
<div class="page-shell invoice-history-page">
|
||||||
<div class="stats-row">
|
<div class="stats-row">
|
||||||
<div v-for="s in stats" :key="s.label" class="stat-card">
|
<div v-for="s in stats" :key="s.label" class="stat-card">
|
||||||
@@ -173,9 +173,9 @@
|
|||||||
}}</strong>
|
}}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
<span>冲红状态</span>
|
<span>红冲状态</span>
|
||||||
<strong>{{
|
<strong>{{
|
||||||
redFlagMap[detailItem.redFlag || ''] || detailItem.redFlag || '未冲红'
|
redFlagMap[detailItem.redFlag || ''] || detailItem.redFlag || '未红冲'
|
||||||
}}</strong>
|
}}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
@@ -227,10 +227,10 @@
|
|||||||
|
|
||||||
<template v-if="detailItem.invoiceType === 'RED' && redInfo">
|
<template v-if="detailItem.invoiceType === 'RED' && redInfo">
|
||||||
<div class="detail-section">
|
<div class="detail-section">
|
||||||
<div class="detail-section-title">冲红申请</div>
|
<div class="detail-section-title">红冲申请</div>
|
||||||
<div class="detail-grid">
|
<div class="detail-grid">
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
<span>冲红原因</span>
|
<span>红冲原因</span>
|
||||||
<strong>{{ redReasonMap[redInfo.redReason] || redInfo.redReason }}</strong>
|
<strong>{{ redReasonMap[redInfo.redReason] || redInfo.redReason }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
@@ -419,7 +419,7 @@
|
|||||||
<n-modal
|
<n-modal
|
||||||
v-model:show="showRedForm"
|
v-model:show="showRedForm"
|
||||||
preset="card"
|
preset="card"
|
||||||
title="发起冲红"
|
title="发起红冲"
|
||||||
:style="{ width: '480px', maxWidth: '92vw' }"
|
:style="{ width: '480px', maxWidth: '92vw' }"
|
||||||
:mask-closable="false"
|
:mask-closable="false"
|
||||||
content-style="padding: 20px"
|
content-style="padding: 20px"
|
||||||
@@ -431,11 +431,21 @@
|
|||||||
label-placement="top"
|
label-placement="top"
|
||||||
require-mark-placement="right-hanging"
|
require-mark-placement="right-hanging"
|
||||||
>
|
>
|
||||||
<n-form-item label="冲红原因" path="redReason">
|
<n-form-item label="开票员" path="digitalAccountId">
|
||||||
|
<n-select
|
||||||
|
v-model:value="redForm.digitalAccountId"
|
||||||
|
:options="digitalAccountOptions"
|
||||||
|
:loading="digitalAccountLoading"
|
||||||
|
placeholder="请选择开票员"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="红冲原因" path="redReason">
|
||||||
<n-select
|
<n-select
|
||||||
v-model:value="redForm.redReason"
|
v-model:value="redForm.redReason"
|
||||||
:options="redReasonOptions"
|
:options="redReasonOptions"
|
||||||
placeholder="请选择冲红原因"
|
placeholder="请选择红冲原因"
|
||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="收票人名称" path="takerName">
|
<n-form-item label="收票人名称" path="takerName">
|
||||||
@@ -451,7 +461,7 @@
|
|||||||
<div class="modal-actions">
|
<div class="modal-actions">
|
||||||
<n-button quaternary @click="showRedForm = false">取消</n-button>
|
<n-button quaternary @click="showRedForm = false">取消</n-button>
|
||||||
<n-button type="error" :loading="redSubmitting" @click="handleRedSubmit"
|
<n-button type="error" :loading="redSubmitting" @click="handleRedSubmit"
|
||||||
>确认冲红</n-button
|
>确认红冲</n-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</n-form>
|
</n-form>
|
||||||
@@ -496,6 +506,7 @@ import {
|
|||||||
invoiceHistoryApi,
|
invoiceHistoryApi,
|
||||||
invoiceKindMap,
|
invoiceKindMap,
|
||||||
invoiceStatusMap,
|
invoiceStatusMap,
|
||||||
|
digitalAccountOptionsApi,
|
||||||
queryInvoiceApi,
|
queryInvoiceApi,
|
||||||
redInvoiceCreateApi,
|
redInvoiceCreateApi,
|
||||||
redInvoiceDownloadUrlApi,
|
redInvoiceDownloadUrlApi,
|
||||||
@@ -507,6 +518,7 @@ import type {
|
|||||||
InvoiceDetailGoods,
|
InvoiceDetailGoods,
|
||||||
InvoiceDetailResponse,
|
InvoiceDetailResponse,
|
||||||
InvoiceDetailVoucher,
|
InvoiceDetailVoucher,
|
||||||
|
DigitalAccountItem,
|
||||||
InvoiceHistoryItem,
|
InvoiceHistoryItem,
|
||||||
RedCreateRequest,
|
RedCreateRequest,
|
||||||
RedInvoiceInfo
|
RedInvoiceInfo
|
||||||
@@ -527,11 +539,11 @@ const invalidFlagMap: Record<string, string> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const redFlagMap: Record<string, string> = {
|
const redFlagMap: Record<string, string> = {
|
||||||
NOT_RED: '未冲红',
|
NOT_RED: '未红冲',
|
||||||
ALREADY_RED: '已冲红',
|
ALREADY_RED: '已红冲',
|
||||||
REDING: '冲红中',
|
REDING: '红冲中',
|
||||||
RED_FAIL: '冲红失败',
|
RED_FAIL: '红冲失败',
|
||||||
PART_RED: '部分冲红'
|
PART_RED: '部分红冲'
|
||||||
}
|
}
|
||||||
|
|
||||||
const redInvoiceKindCodes = new Set(['81', '82', '83', '87'])
|
const redInvoiceKindCodes = new Set(['81', '82', '83', '87'])
|
||||||
@@ -728,7 +740,7 @@ function getRowActions(row: InvoiceHistoryItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (canCreateRedInvoice(row)) {
|
if (canCreateRedInvoice(row)) {
|
||||||
actions.push({ label: '冲红', icon: RotateCcw, onClick: () => startRedTask(row) })
|
actions.push({ label: '红冲', icon: RotateCcw, onClick: () => startRedTask(row) })
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions
|
return actions
|
||||||
@@ -739,7 +751,7 @@ function getActionsColumnWidth() {
|
|||||||
详情: 58,
|
详情: 58,
|
||||||
刷新: 58,
|
刷新: 58,
|
||||||
查看票样: 86,
|
查看票样: 86,
|
||||||
冲红: 58
|
红冲: 58
|
||||||
}
|
}
|
||||||
const rowWidths = dataSource.value.map((row) => {
|
const rowWidths = dataSource.value.map((row) => {
|
||||||
const actions = getRowActions(row)
|
const actions = getRowActions(row)
|
||||||
@@ -835,7 +847,7 @@ const columns = computed<DataTableColumns<InvoiceHistoryItem>>(() => {
|
|||||||
: h('span', { style: 'color:#9ca3af' }, '-')
|
: h('span', { style: 'color:#9ca3af' }, '-')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '冲红状态',
|
title: '红冲状态',
|
||||||
key: 'redFlag',
|
key: 'redFlag',
|
||||||
width: 110,
|
width: 110,
|
||||||
render: (row: InvoiceHistoryItem) => {
|
render: (row: InvoiceHistoryItem) => {
|
||||||
@@ -850,7 +862,7 @@ const columns = computed<DataTableColumns<InvoiceHistoryItem>>(() => {
|
|||||||
}[row.status]
|
}[row.status]
|
||||||
: undefined)
|
: undefined)
|
||||||
if (!redFlag || redFlag === 'NOT_RED') {
|
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'> = {
|
const typeMap: Record<string, 'error' | 'warning' | 'default'> = {
|
||||||
ALREADY_RED: 'error',
|
ALREADY_RED: 'error',
|
||||||
@@ -973,9 +985,12 @@ async function refreshStatus(item: InvoiceHistoryItem) {
|
|||||||
const showRedForm = ref(false)
|
const showRedForm = ref(false)
|
||||||
const redSubmitting = ref(false)
|
const redSubmitting = ref(false)
|
||||||
const redFormRef = ref()
|
const redFormRef = ref()
|
||||||
|
const digitalAccountLoading = ref(false)
|
||||||
|
const digitalAccounts = ref<DigitalAccountItem[]>([])
|
||||||
|
|
||||||
const redForm = reactive({
|
const redForm = reactive({
|
||||||
historyId: '',
|
historyId: '',
|
||||||
|
digitalAccountId: null as string | null,
|
||||||
redReason: '01',
|
redReason: '01',
|
||||||
takerName: '',
|
takerName: '',
|
||||||
takerTel: '',
|
takerTel: '',
|
||||||
@@ -989,17 +1004,40 @@ const redReasonOptions = [
|
|||||||
{ label: '销售折让', value: '04' }
|
{ label: '销售折让', value: '04' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const digitalAccountOptions = computed(() =>
|
||||||
|
digitalAccounts.value.map((item) => ({
|
||||||
|
label: `${item.account}${item.name ? `(${item.name})` : ''}`,
|
||||||
|
value: item.id
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
const redFormRules = {
|
const redFormRules = {
|
||||||
redReason: [{ required: true, message: '请选择冲红原因', trigger: 'change' }]
|
digitalAccountId: [{ required: true, message: '请选择开票员', trigger: 'change' }],
|
||||||
|
redReason: [{ required: true, message: '请选择红冲原因', trigger: 'change' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
function startRedTask(item: InvoiceHistoryItem) {
|
async function ensureDigitalAccountsLoaded() {
|
||||||
|
if (digitalAccounts.value.length > 0) return
|
||||||
|
digitalAccountLoading.value = true
|
||||||
|
try {
|
||||||
|
digitalAccounts.value = await digitalAccountOptionsApi({ limit: 200 })
|
||||||
|
} finally {
|
||||||
|
digitalAccountLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startRedTask(item: InvoiceHistoryItem) {
|
||||||
redForm.historyId = item.id
|
redForm.historyId = item.id
|
||||||
|
redForm.digitalAccountId = null
|
||||||
redForm.redReason = '01'
|
redForm.redReason = '01'
|
||||||
redForm.takerName = ''
|
redForm.takerName = ''
|
||||||
redForm.takerTel = ''
|
redForm.takerTel = ''
|
||||||
redForm.takerEmail = ''
|
redForm.takerEmail = ''
|
||||||
showRedForm.value = true
|
showRedForm.value = true
|
||||||
|
await ensureDigitalAccountsLoaded()
|
||||||
|
if (!redForm.digitalAccountId && digitalAccounts.value.length === 1) {
|
||||||
|
redForm.digitalAccountId = digitalAccounts.value[0].id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleRedSubmit() {
|
async function handleRedSubmit() {
|
||||||
@@ -1012,17 +1050,18 @@ async function handleRedSubmit() {
|
|||||||
try {
|
try {
|
||||||
const payload: RedCreateRequest = {
|
const payload: RedCreateRequest = {
|
||||||
historyId: redForm.historyId,
|
historyId: redForm.historyId,
|
||||||
|
digitalAccountId: redForm.digitalAccountId,
|
||||||
redReason: redForm.redReason,
|
redReason: redForm.redReason,
|
||||||
takerName: redForm.takerName || undefined,
|
takerName: redForm.takerName || undefined,
|
||||||
takerTel: redForm.takerTel || undefined,
|
takerTel: redForm.takerTel || undefined,
|
||||||
takerEmail: redForm.takerEmail || undefined
|
takerEmail: redForm.takerEmail || undefined
|
||||||
}
|
}
|
||||||
await redInvoiceCreateApi(payload)
|
await redInvoiceCreateApi(payload)
|
||||||
message.success('冲红任务创建成功')
|
message.success('红冲任务创建成功')
|
||||||
showRedForm.value = false
|
showRedForm.value = false
|
||||||
fetchData()
|
fetchData()
|
||||||
} catch {
|
} catch {
|
||||||
message.error('创建冲红任务失败')
|
message.error('创建红冲任务失败')
|
||||||
} finally {
|
} finally {
|
||||||
redSubmitting.value = false
|
redSubmitting.value = false
|
||||||
}
|
}
|
||||||
@@ -1471,3 +1510,4 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -931,7 +931,7 @@ import {
|
|||||||
invoiceIssueApi,
|
invoiceIssueApi,
|
||||||
getEnterpriseInfoApi,
|
getEnterpriseInfoApi,
|
||||||
getPresetDataApi,
|
getPresetDataApi,
|
||||||
listDigitalAccountsApi
|
digitalAccountOptionsApi
|
||||||
} from '@/api/piaotong'
|
} from '@/api/piaotong'
|
||||||
import type { DigitalAccountItem, InvoiceRequest, InvoiceItem, VariableLevyProof } from '@/api/piaotong'
|
import type { DigitalAccountItem, InvoiceRequest, InvoiceItem, VariableLevyProof } from '@/api/piaotong'
|
||||||
import type { FormInst, FormRules } from 'naive-ui'
|
import type { FormInst, FormRules } from 'naive-ui'
|
||||||
@@ -1574,7 +1574,7 @@ onMounted(async () => {
|
|||||||
const [enterpriseInfo, presetData, accounts] = await Promise.all([
|
const [enterpriseInfo, presetData, accounts] = await Promise.all([
|
||||||
getEnterpriseInfoApi(),
|
getEnterpriseInfoApi(),
|
||||||
getPresetDataApi(),
|
getPresetDataApi(),
|
||||||
listDigitalAccountsApi()
|
digitalAccountOptionsApi({ limit: 200 })
|
||||||
])
|
])
|
||||||
digitalAccounts.value = accounts
|
digitalAccounts.value = accounts
|
||||||
const defaultAccount =
|
const defaultAccount =
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<n-drawer v-model:show="drawerVisible" :width="760">
|
<n-drawer v-model:show="drawerVisible" :width="980">
|
||||||
<n-drawer-content :title="drawerTitle" closable>
|
<n-drawer-content :title="drawerTitle" closable>
|
||||||
<div class="drawer-toolbar">
|
<div class="drawer-toolbar">
|
||||||
<n-select
|
<n-select
|
||||||
@@ -66,15 +66,6 @@
|
|||||||
class="task-filter"
|
class="task-filter"
|
||||||
@update:value="loadTasks(1)"
|
@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)">
|
<n-button size="small" :loading="taskLoading" @click="loadTasks(taskPage)">
|
||||||
<template #icon><n-icon :component="RefreshCw" /></template>
|
<template #icon><n-icon :component="RefreshCw" /></template>
|
||||||
刷新
|
刷新
|
||||||
@@ -87,7 +78,7 @@
|
|||||||
:data="tasks"
|
:data="tasks"
|
||||||
:loading="taskLoading"
|
:loading="taskLoading"
|
||||||
:pagination="taskPagination"
|
:pagination="taskPagination"
|
||||||
:scroll-x="980"
|
:scroll-x="1280"
|
||||||
remote
|
remote
|
||||||
@update:page="loadTasks"
|
@update:page="loadTasks"
|
||||||
@update:page-size="changeTaskPageSize"
|
@update:page-size="changeTaskPageSize"
|
||||||
@@ -122,7 +113,6 @@ const taskPageSize = ref(20)
|
|||||||
const taskTotal = ref(0)
|
const taskTotal = ref(0)
|
||||||
const taskStatus = ref<string | null>(null)
|
const taskStatus = ref<string | null>(null)
|
||||||
const taskSourceType = ref<string | null>(null)
|
const taskSourceType = ref<string | null>(null)
|
||||||
const taskRunMode = ref<string | null>(null)
|
|
||||||
|
|
||||||
const statusOptions = [
|
const statusOptions = [
|
||||||
{ label: '待处理', value: 'PENDING' },
|
{ label: '待处理', value: 'PENDING' },
|
||||||
@@ -134,14 +124,35 @@ const statusOptions = [
|
|||||||
|
|
||||||
const sourceTypeOptions = [
|
const sourceTypeOptions = [
|
||||||
{ label: '单笔', value: 'SINGLE' },
|
{ label: '单笔', value: 'SINGLE' },
|
||||||
{ label: '批量', value: 'BATCH' },
|
{ label: '批量', value: 'BATCH' }
|
||||||
{ label: '测试', value: 'TEST' }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const runModeOptions = [
|
const queueStatusLabelMap: Record<string, string> = {
|
||||||
{ label: '生产', value: 'REAL' },
|
RUNNING: '运行中',
|
||||||
{ label: '模拟', value: 'SIMULATED' }
|
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(() =>
|
const totals = computed(() =>
|
||||||
rows.value.reduce(
|
rows.value.reduce(
|
||||||
@@ -177,7 +188,11 @@ const columns: DataTableColumns<OpenInvoiceTaskOverviewItem> = [
|
|||||||
key: 'status',
|
key: 'status',
|
||||||
width: 110,
|
width: 110,
|
||||||
render: (row) =>
|
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: 'pending', width: 90 },
|
||||||
{ title: '处理中', key: 'processing', width: 90 },
|
{ title: '处理中', key: 'processing', width: 90 },
|
||||||
@@ -265,21 +280,24 @@ function rowProps(row: OpenInvoiceTaskOverviewItem) {
|
|||||||
|
|
||||||
const taskColumns: DataTableColumns<OpenInvoiceTaskItem> = [
|
const taskColumns: DataTableColumns<OpenInvoiceTaskItem> = [
|
||||||
{ title: '票号', key: 'invoiceReqSerialNo', minWidth: 170 },
|
{ title: '票号', key: 'invoiceReqSerialNo', minWidth: 170 },
|
||||||
{ title: '任务', key: 'taskType', width: 120 },
|
{ title: '任务', key: 'taskType', width: 120, render: (row) => labelOf(taskTypeLabelMap, row.taskType) },
|
||||||
{ title: '来源', key: 'sourceType', width: 90 },
|
{ title: '来源', key: 'sourceType', width: 90, render: (row) => labelOf(sourceTypeLabelMap, row.sourceType) },
|
||||||
{ title: '模式', key: 'runMode', width: 90 },
|
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
key: 'status',
|
key: 'status',
|
||||||
width: 110,
|
width: 110,
|
||||||
render: (row) =>
|
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: 'PT码', key: 'ptCode', width: 90 },
|
||||||
|
{ title: '错误', key: 'errorMessage', minWidth: 260, ellipsis: { tooltip: true } },
|
||||||
{ title: '查询次数', key: 'pollCount', width: 90, render: (row) => `${row.pollCount}/${row.maxPollCount}` },
|
{ title: '查询次数', key: 'pollCount', width: 90, render: (row) => `${row.pollCount}/${row.maxPollCount}` },
|
||||||
{ title: '重试', key: 'attemptCount', width: 90, render: (row) => `${row.attemptCount}/${row.maxAttemptCount}` },
|
{ title: '重试', key: 'attemptCount', width: 90, render: (row) => `${row.attemptCount}/${row.maxAttemptCount}` },
|
||||||
{ title: '下次执行', key: 'nextRunAt', minWidth: 150 },
|
{ title: '下次执行', key: 'nextRunAt', minWidth: 150 }
|
||||||
{ title: '错误', key: 'errorMessage', minWidth: 180 }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const taskPagination = reactive<PaginationProps>({
|
const taskPagination = reactive<PaginationProps>({
|
||||||
@@ -307,7 +325,6 @@ async function loadTasks(page = 1) {
|
|||||||
digitalAccountId: selected.value.digitalAccountId,
|
digitalAccountId: selected.value.digitalAccountId,
|
||||||
status: taskStatus.value,
|
status: taskStatus.value,
|
||||||
sourceType: taskSourceType.value,
|
sourceType: taskSourceType.value,
|
||||||
runMode: taskRunMode.value,
|
|
||||||
page,
|
page,
|
||||||
pageSize: taskPageSize.value
|
pageSize: taskPageSize.value
|
||||||
})
|
})
|
||||||
@@ -326,7 +343,6 @@ function openDrawer(row: OpenInvoiceTaskOverviewItem) {
|
|||||||
drawerVisible.value = true
|
drawerVisible.value = true
|
||||||
taskStatus.value = null
|
taskStatus.value = null
|
||||||
taskSourceType.value = null
|
taskSourceType.value = null
|
||||||
taskRunMode.value = null
|
|
||||||
loadTasks(1)
|
loadTasks(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ function renderLabel(payload: { option: unknown }) {
|
|||||||
? h(NTag, { size: 'small', type: 'primary' }, { default: () => '基础内置' })
|
? h(NTag, { size: 'small', type: 'primary' }, { default: () => '基础内置' })
|
||||||
: null
|
: null
|
||||||
]),
|
]),
|
||||||
h(NSpace, { size: 6, class: 'menu-tree-actions' }, () => [
|
h(NSpace, { size: 6, align: 'center', class: 'menu-tree-actions table-action-buttons' }, () => [
|
||||||
h(
|
h(
|
||||||
NButton,
|
NButton,
|
||||||
{ size: 'small', tertiary: true, class: 'action-btn', onClick: () => openCreate(node.id) },
|
{ size: 'small', tertiary: true, class: 'action-btn', onClick: () => openCreate(node.id) },
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ const columns = computed<DataTableColumns<RoleItem>>(() => [
|
|||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
render: (r) =>
|
render: (r) =>
|
||||||
h(NSpace, { size: 6 }, () => [
|
h(NSpace, { size: 6, align: 'center', class: 'table-action-buttons' }, () => [
|
||||||
h(
|
h(
|
||||||
NButton,
|
NButton,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -660,7 +660,7 @@ const columns = computed<DataTableColumns<UserListItem>>(() => [
|
|||||||
render: (row) =>
|
render: (row) =>
|
||||||
h(
|
h(
|
||||||
NSpace,
|
NSpace,
|
||||||
{ size: 6 },
|
{ size: 6, align: 'center', class: 'table-action-buttons' },
|
||||||
{
|
{
|
||||||
default: () => [
|
default: () => [
|
||||||
h(
|
h(
|
||||||
|
|||||||
@@ -213,6 +213,40 @@ select {
|
|||||||
min-width: 68px;
|
min-width: 68px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-action-buttons,
|
||||||
|
.row-actions,
|
||||||
|
.table-actions,
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-action-buttons {
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-action-buttons .n-button,
|
||||||
|
.row-actions .n-button,
|
||||||
|
.table-actions .n-button,
|
||||||
|
.action-buttons .n-button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-action-buttons .n-button__content,
|
||||||
|
.row-actions .n-button__content,
|
||||||
|
.table-actions .n-button__content,
|
||||||
|
.action-buttons .n-button__content {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.soft-stat {
|
.soft-stat {
|
||||||
border: 1px solid var(--app-border);
|
border: 1px solid var(--app-border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|||||||
Reference in New Issue
Block a user