fix(channels): sanitize card data and format suffixes
This commit is contained in:
@@ -71,14 +71,12 @@ const TXN_SCENES = [
|
|||||||
|
|
||||||
function getChannelIdentifier(channel: ChannelWithAccountNames): string {
|
function getChannelIdentifier(channel: ChannelWithAccountNames): string {
|
||||||
if (channel.channelType === "PAYMENT_CARD") {
|
if (channel.channelType === "PAYMENT_CARD") {
|
||||||
let suffix = channel.cardNumberSuffix?.trim()
|
const digits = (
|
||||||
if (
|
channel.cardNumberSuffix ||
|
||||||
!suffix &&
|
channel.cardNumberFull ||
|
||||||
channel.cardNumberFull &&
|
""
|
||||||
channel.cardNumberFull.length >= 4
|
).replace(/\D/g, "")
|
||||||
) {
|
const suffix = digits.length >= 4 ? digits.slice(-4) : digits
|
||||||
suffix = channel.cardNumberFull.slice(-4)
|
|
||||||
}
|
|
||||||
return suffix ? `•••• ${suffix}` : ""
|
return suffix ? `•••• ${suffix}` : ""
|
||||||
}
|
}
|
||||||
if (channel.channelType === "E_WALLET") {
|
if (channel.channelType === "E_WALLET") {
|
||||||
|
|||||||
@@ -275,11 +275,20 @@ export function ChannelDialog({
|
|||||||
cardBrandRequest.current += 1
|
cardBrandRequest.current += 1
|
||||||
setCardBrand((value as CardBrand | null) || "")
|
setCardBrand((value as CardBrand | null) || "")
|
||||||
}}
|
}}
|
||||||
|
itemToStringLabel={(brand: CardBrand) =>
|
||||||
|
brand ? CARD_BRAND_LABELS[brand] || brand : ""
|
||||||
|
}
|
||||||
|
itemToStringValue={(brand: CardBrand) =>
|
||||||
|
brand
|
||||||
|
? `${brand} ${CARD_BRAND_LABELS[brand] || ""}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
autoHighlight
|
autoHighlight
|
||||||
>
|
>
|
||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
id="cardBrand"
|
id="cardBrand"
|
||||||
placeholder="选择卡组织"
|
placeholder="选择卡组织"
|
||||||
|
className="w-full"
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
/>
|
/>
|
||||||
<ComboboxContent>
|
<ComboboxContent>
|
||||||
|
|||||||
@@ -118,6 +118,15 @@ function formatCardNumber(cardNumber: string) {
|
|||||||
.trim()
|
.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCardSuffix(channel: ChannelWithAccountNames) {
|
||||||
|
const digits = (
|
||||||
|
channel.cardNumberSuffix ||
|
||||||
|
channel.cardNumberFull ||
|
||||||
|
""
|
||||||
|
).replace(/\D/g, "")
|
||||||
|
return digits.length >= 4 ? digits.slice(-4) : digits
|
||||||
|
}
|
||||||
|
|
||||||
export function ChannelsView({
|
export function ChannelsView({
|
||||||
initialChannels,
|
initialChannels,
|
||||||
initialAccounts,
|
initialAccounts,
|
||||||
@@ -402,12 +411,7 @@ export function ChannelsView({
|
|||||||
{visibleCardIds.has(channel.id) &&
|
{visibleCardIds.has(channel.id) &&
|
||||||
channel.cardNumberFull
|
channel.cardNumberFull
|
||||||
? formatCardNumber(channel.cardNumberFull)
|
? formatCardNumber(channel.cardNumberFull)
|
||||||
: `•••• ${
|
: `•••• ${getCardSuffix(channel)}`}
|
||||||
channel.cardNumberSuffix ||
|
|
||||||
formatCardNumber(
|
|
||||||
channel.cardNumberFull || ""
|
|
||||||
).slice(-4)
|
|
||||||
}`}
|
|
||||||
</span>
|
</span>
|
||||||
{channel.cardNumberFull && (
|
{channel.cardNumberFull && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
+26
-11
@@ -133,10 +133,16 @@ export async function createChannelAction(
|
|||||||
return { success: false, error: "关联的部分账户不存在或已被删除" }
|
return { success: false, error: "关联的部分账户不存在或已被删除" }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自动提取或补全卡号后4位
|
// 自动提取并清洗纯数字卡号及后4位
|
||||||
let suffix = val.cardNumberSuffix?.trim() || null
|
const cleanFull = val.cardNumberFull
|
||||||
if (!suffix && val.cardNumberFull && val.cardNumberFull.length >= 4) {
|
? val.cardNumberFull.replace(/\D/g, "")
|
||||||
suffix = val.cardNumberFull.slice(-4)
|
: ""
|
||||||
|
const cleanSuffix = val.cardNumberSuffix
|
||||||
|
? val.cardNumberSuffix.replace(/\D/g, "")
|
||||||
|
: ""
|
||||||
|
let suffix = cleanSuffix.slice(-4) || null
|
||||||
|
if (!suffix && cleanFull.length >= 4) {
|
||||||
|
suffix = cleanFull.slice(-4)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [newChannel] = await db
|
const [newChannel] = await db
|
||||||
@@ -151,8 +157,9 @@ export async function createChannelAction(
|
|||||||
region: val.region ? val.region.toUpperCase().trim() : null,
|
region: val.region ? val.region.toUpperCase().trim() : null,
|
||||||
issuerName: val.issuerName?.trim() || null,
|
issuerName: val.issuerName?.trim() || null,
|
||||||
cardType: val.cardType || null,
|
cardType: val.cardType || null,
|
||||||
cardNumberFull: val.cardNumberFull?.trim() || null,
|
cardNumberFull:
|
||||||
cardNumberSuffix: suffix,
|
val.channelType === "PAYMENT_CARD" ? cleanFull || null : null,
|
||||||
|
cardNumberSuffix: val.channelType === "PAYMENT_CARD" ? suffix : null,
|
||||||
cardBrand: val.cardBrand?.trim() || null,
|
cardBrand: val.cardBrand?.trim() || null,
|
||||||
platform: val.platform?.trim() || null,
|
platform: val.platform?.trim() || null,
|
||||||
platformAccountId: val.platformAccountId?.trim() || null,
|
platformAccountId: val.platformAccountId?.trim() || null,
|
||||||
@@ -205,9 +212,16 @@ export async function updateChannelAction(
|
|||||||
return { success: false, error: "关联的部分账户不存在或已被删除" }
|
return { success: false, error: "关联的部分账户不存在或已被删除" }
|
||||||
}
|
}
|
||||||
|
|
||||||
let suffix = val.cardNumberSuffix?.trim() || null
|
// 自动提取并清洗纯数字卡号及后4位
|
||||||
if (!suffix && val.cardNumberFull && val.cardNumberFull.length >= 4) {
|
const cleanFull = val.cardNumberFull
|
||||||
suffix = val.cardNumberFull.slice(-4)
|
? val.cardNumberFull.replace(/\D/g, "")
|
||||||
|
: ""
|
||||||
|
const cleanSuffix = val.cardNumberSuffix
|
||||||
|
? val.cardNumberSuffix.replace(/\D/g, "")
|
||||||
|
: ""
|
||||||
|
let suffix = cleanSuffix.slice(-4) || null
|
||||||
|
if (!suffix && cleanFull.length >= 4) {
|
||||||
|
suffix = cleanFull.slice(-4)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [updated] = await db
|
const [updated] = await db
|
||||||
@@ -220,8 +234,9 @@ export async function updateChannelAction(
|
|||||||
region: val.region ? val.region.toUpperCase().trim() : null,
|
region: val.region ? val.region.toUpperCase().trim() : null,
|
||||||
issuerName: val.issuerName?.trim() || null,
|
issuerName: val.issuerName?.trim() || null,
|
||||||
cardType: val.cardType || null,
|
cardType: val.cardType || null,
|
||||||
cardNumberFull: val.cardNumberFull?.trim() || null,
|
cardNumberFull:
|
||||||
cardNumberSuffix: suffix,
|
val.channelType === "PAYMENT_CARD" ? cleanFull || null : null,
|
||||||
|
cardNumberSuffix: val.channelType === "PAYMENT_CARD" ? suffix : null,
|
||||||
cardBrand: val.cardBrand?.trim() || null,
|
cardBrand: val.cardBrand?.trim() || null,
|
||||||
platform: val.platform?.trim() || null,
|
platform: val.platform?.trim() || null,
|
||||||
platformAccountId: val.platformAccountId?.trim() || null,
|
platformAccountId: val.platformAccountId?.trim() || null,
|
||||||
|
|||||||
Reference in New Issue
Block a user