Files
order_site/apps/backend/src/routes/admin/cost-center.ts
T

852 lines
27 KiB
TypeScript

import type { Request } from 'express'
import { Router } from 'express'
import {
getAdminCostCenterOptions,
getAdminCostCenterOverview,
} from '../../services/cost-center/cost-center-overview-service.js'
import {
createAdminCostItem,
createAdminCostSnapshot,
createAdminCostVersion,
deleteAdminCostItem,
deleteAdminCostVersion,
listAdminCostExceptions,
listAdminCostItems,
listAdminCostVersions,
previewAdminCost,
resolveAdminCostException,
retireAdminCostVersion,
updateAdminCostItem,
} from '../../services/cost-center/cost-definition-service.js'
import {
backfillAdminNormalizedQuantities,
backfillAdminProductMappings,
createAdminChannelMapping,
createAdminProduct,
deleteAdminChannelMapping,
deleteAdminProduct,
listAdminChannelMappings,
listAdminProducts,
updateAdminChannelMapping,
updateAdminProduct,
} from '../../services/cost-center/product-catalog-service.js'
import {
adjustPlatformCredit,
grantPlatformCredit,
listPlatformCreditAccounts,
listPlatformCreditEntries,
listPlatformCreditOwners,
} from '../../services/cost-center/platform-credit-service.js'
import {
deleteManualFulfillmentConfig,
getManualFulfillmentConfig,
getManualSkuOverview,
listManualPlatformOptions,
listManualSkus,
rematchManualFulfillments,
saveManualFulfillmentConfig,
scanManualSkus,
} from '../../services/cost-center/manual-fulfillment-config-service.js'
import {
applyAdminTemplateProductBootstrap,
backfillAdminAffiliateDashSkus,
backfillAdminWorkOrderProductSkus,
previewAdminTemplateProductBootstrap,
syncAdminAffiliateDashProducts,
syncAdminWorkOrderTemplateCostVersions,
} from '../../services/cost-center/template-bootstrap-service.js'
import type { AdminSession } from '../../services/admin/admin-auth-service.js'
import {
syncActualWorkOrderCostSnapshots,
syncEstimatedOrderItemCostSnapshots,
} from '../../services/cost-center/cost-snapshot-sync-service.js'
import type { JsonObject } from '../../types/json.js'
import {
createJsonHandler,
requireAdminPermission,
requireAdminRoles,
requireAnyAdminPermission,
} from './session.js'
const router = Router()
function sessionOf(req: Request): AdminSession {
return req.adminSession as AdminSession
}
function idOf(req: Request, key: string): number {
return Number(req.params[key])
}
function bodyOf(req: Request): JsonObject {
return req.body && typeof req.body === 'object' ? (req.body as JsonObject) : {}
}
router.use('/cost-center', requireAdminRoles(['admin', 'operator', 'finance', 'support']))
router.get(
'/cost-center/overview',
requireAdminPermission('finance.view'),
createJsonHandler(() => getAdminCostCenterOverview(), {
successMessage: 'ok',
errorMessage: '读取成本中心总览失败',
scope: '[admin/cost-center/overview]',
}),
)
router.get(
'/cost-center/options',
requireAdminPermission('finance.view'),
createJsonHandler(() => getAdminCostCenterOptions(), {
successMessage: 'ok',
errorMessage: '读取成本中心选项失败',
scope: '[admin/cost-center/options]',
}),
)
router.get(
'/cost-center/template-bootstrap/preview',
requireAdminPermission('finance.view'),
createJsonHandler(() => previewAdminTemplateProductBootstrap(), {
successMessage: 'ok',
errorMessage: '读取接单模板初始化预览失败',
scope: '[admin/cost-center/template-bootstrap/preview]',
}),
)
router.post(
'/cost-center/template-bootstrap/apply',
requireAdminPermission('finance.config'),
createJsonHandler((req) => applyAdminTemplateProductBootstrap(bodyOf(req), sessionOf(req)), {
successMessage: '接单模板初始化完成',
errorMessage: '接单模板初始化失败',
scope: '[admin/cost-center/template-bootstrap/apply]',
audit: (_req, data) => ({
action: 'cost_template_bootstrap_applied',
targetType: 'product_catalog',
targetId: '',
data: data as Record<string, unknown>,
}),
}),
)
router.post(
'/cost-center/affiliate-products/sync',
requireAdminPermission('finance.config'),
createJsonHandler(() => syncAdminAffiliateDashProducts(), {
successMessage: '自动发货商品已同步',
errorMessage: '同步自动发货商品失败',
scope: '[admin/cost-center/affiliate-products/sync]',
audit: (_req, data) => ({
action: 'cost_affiliate_products_synced',
targetType: 'product_catalog',
targetId: '',
data: data as Record<string, unknown>,
}),
}),
)
router.post(
'/cost-center/affiliate-products/backfill',
requireAdminPermission('finance.config'),
createJsonHandler(() => backfillAdminAffiliateDashSkus(), {
successMessage: '自动发货 SKU 已回填',
errorMessage: '回填自动发货 SKU 失败',
scope: '[admin/cost-center/affiliate-products/backfill]',
audit: (_req, data) => ({
action: 'cost_affiliate_skus_backfilled',
targetType: 'order_items',
targetId: '',
data: data as Record<string, unknown>,
}),
}),
)
router.post(
'/cost-center/work-order-products/backfill',
requireAdminPermission('finance.config'),
createJsonHandler(() => backfillAdminWorkOrderProductSkus(), {
successMessage: '接单平台商品已回填',
errorMessage: '回填接单平台商品失败',
scope: '[admin/cost-center/work-order-products/backfill]',
audit: (_req, data) => ({
action: 'cost_work_order_products_backfilled',
targetType: 'order_items',
targetId: '',
data: data as Record<string, unknown>,
}),
}),
)
router.post(
'/cost-center/work-order-template-costs/sync',
requireAdminPermission('finance.config'),
createJsonHandler(() => syncAdminWorkOrderTemplateCostVersions(), {
successMessage: '接单模板发单金额已同步',
errorMessage: '同步接单模板发单金额失败',
scope: '[admin/cost-center/work-order-template-costs/sync]',
audit: (_req, data) => ({
action: 'cost_work_order_template_costs_synced',
targetType: 'cost_versions',
targetId: '',
data: data as Record<string, unknown>,
}),
}),
)
router.get(
'/cost-center/products',
requireAdminPermission('finance.view'),
createJsonHandler((req) => listAdminProducts(req.query as JsonObject), {
successMessage: 'ok',
errorMessage: '读取标准商品失败',
scope: '[admin/cost-center/products]',
}),
)
router.post(
'/cost-center/products',
requireAdminPermission('finance.config'),
createJsonHandler((req) => createAdminProduct(bodyOf(req), sessionOf(req)), {
successMessage: '标准商品已创建',
errorMessage: '创建标准商品失败',
scope: '[admin/cost-center/products]',
audit: (_req, data) => {
const product = (data as { product?: { id?: number; canonicalSku?: string } })?.product
return {
action: 'cost_product_created',
targetType: 'product_catalog',
targetId: String(product?.id || ''),
data: { canonicalSku: product?.canonicalSku || '' },
}
},
}),
)
router.patch(
'/cost-center/products/:productId',
requireAdminPermission('finance.config'),
createJsonHandler((req) => updateAdminProduct(idOf(req, 'productId'), bodyOf(req)), {
successMessage: '标准商品已更新',
errorMessage: '更新标准商品失败',
scope: '[admin/cost-center/products/:productId]',
audit: (req, data) => {
const product = (data as { product?: { id?: number; canonicalSku?: string } })?.product
return {
action: 'cost_product_updated',
targetType: 'product_catalog',
targetId: String(product?.id || req.params.productId || ''),
data: { canonicalSku: product?.canonicalSku || '' },
}
},
}),
)
router.delete(
'/cost-center/products/:productId',
requireAdminPermission('finance.config'),
createJsonHandler((req) => deleteAdminProduct(idOf(req, 'productId')), {
successMessage: '标准商品已删除',
errorMessage: '删除标准商品失败',
scope: '[admin/cost-center/products/:productId]',
audit: (req, data) => {
const product = (data as { product?: { id?: number; canonicalSku?: string } })?.product
return {
action: 'cost_product_deleted',
targetType: 'product_catalog',
targetId: String(product?.id || req.params.productId || ''),
data: { canonicalSku: product?.canonicalSku || '' },
}
},
}),
)
router.get(
'/cost-center/mappings',
requireAdminPermission('finance.view'),
createJsonHandler((req) => listAdminChannelMappings(req.query as JsonObject), {
successMessage: 'ok',
errorMessage: '读取渠道映射失败',
scope: '[admin/cost-center/mappings]',
}),
)
router.post(
'/cost-center/mappings',
requireAdminPermission('finance.config'),
createJsonHandler((req) => createAdminChannelMapping(bodyOf(req), sessionOf(req)), {
successMessage: '渠道映射已创建',
errorMessage: '创建渠道映射失败',
scope: '[admin/cost-center/mappings]',
audit: (_req, data) => {
const mapping = (
data as { mapping?: { id?: number; provider?: string; platformSkuCode?: string } }
)?.mapping
return {
action: 'cost_mapping_created',
targetType: 'channel_product_mapping',
targetId: String(mapping?.id || ''),
data: {
provider: mapping?.provider || '',
platformSkuCode: mapping?.platformSkuCode || '',
},
}
},
}),
)
router.patch(
'/cost-center/mappings/:mappingId',
requireAdminPermission('finance.config'),
createJsonHandler((req) => updateAdminChannelMapping(idOf(req, 'mappingId'), bodyOf(req)), {
successMessage: '渠道映射已更新',
errorMessage: '更新渠道映射失败',
scope: '[admin/cost-center/mappings/:mappingId]',
audit: (req, data) => {
const mapping = (
data as { mapping?: { id?: number; provider?: string; platformSkuCode?: string } }
)?.mapping
return {
action: 'cost_mapping_updated',
targetType: 'channel_product_mapping',
targetId: String(mapping?.id || req.params.mappingId || ''),
data: {
provider: mapping?.provider || '',
platformSkuCode: mapping?.platformSkuCode || '',
},
}
},
}),
)
router.delete(
'/cost-center/mappings/:mappingId',
requireAdminPermission('finance.config'),
createJsonHandler((req) => deleteAdminChannelMapping(idOf(req, 'mappingId')), {
successMessage: '渠道映射已删除',
errorMessage: '删除渠道映射失败',
scope: '[admin/cost-center/mappings/:mappingId]',
audit: (req, data) => {
const mappingId = (data as { mappingId?: number })?.mappingId
return {
action: 'cost_mapping_deleted',
targetType: 'channel_product_mapping',
targetId: String(mappingId || req.params.mappingId || ''),
data: {},
}
},
}),
)
router.post(
'/cost-center/mappings/backfill',
requireAdminPermission('finance.config'),
createJsonHandler((req) => backfillAdminProductMappings(bodyOf(req)), {
successMessage: '商品映射回填完成',
errorMessage: '回填商品映射失败',
scope: '[admin/cost-center/mappings/backfill]',
audit: (_req, data) => ({
action: 'cost_mapping_backfilled',
targetType: 'order_item',
targetId: '',
data: data as Record<string, unknown>,
}),
}),
)
router.post(
'/cost-center/normalized-quantities/backfill',
requireAdminPermission('finance.config'),
createJsonHandler((req) => backfillAdminNormalizedQuantities(bodyOf(req)), {
successMessage: '归一数量回填完成',
errorMessage: '回填归一数量失败',
scope: '[admin/cost-center/normalized-quantities/backfill]',
audit: (_req, data) => ({
action: 'order_item_quantity_backfilled',
targetType: 'order_item',
targetId: '',
data: data as Record<string, unknown>,
}),
}),
)
router.get(
'/cost-center/cost-items',
requireAdminPermission('finance.view'),
createJsonHandler((req) => listAdminCostItems(req.query as JsonObject), {
successMessage: 'ok',
errorMessage: '读取成本项目失败',
scope: '[admin/cost-center/cost-items]',
}),
)
router.post(
'/cost-center/cost-items',
requireAdminPermission('finance.config'),
createJsonHandler((req) => createAdminCostItem(bodyOf(req), sessionOf(req)), {
successMessage: '成本项目已创建',
errorMessage: '创建成本项目失败',
scope: '[admin/cost-center/cost-items]',
audit: (_req, data) => {
const item = (data as { costItem?: { id?: number; code?: string } })?.costItem
return {
action: 'cost_item_created',
targetType: 'cost_item',
targetId: String(item?.id || ''),
data: { code: item?.code || '' },
}
},
}),
)
router.patch(
'/cost-center/cost-items/:costItemId',
requireAdminPermission('finance.config'),
createJsonHandler((req) => updateAdminCostItem(idOf(req, 'costItemId'), bodyOf(req)), {
successMessage: '成本项目已更新',
errorMessage: '更新成本项目失败',
scope: '[admin/cost-center/cost-items/:costItemId]',
audit: (req, data) => {
const item = (data as { costItem?: { id?: number; code?: string } })?.costItem
return {
action: 'cost_item_updated',
targetType: 'cost_item',
targetId: String(item?.id || req.params.costItemId || ''),
data: { code: item?.code || '' },
}
},
}),
)
router.delete(
'/cost-center/cost-items/:costItemId',
requireAdminPermission('finance.config'),
createJsonHandler((req) => deleteAdminCostItem(idOf(req, 'costItemId')), {
successMessage: '成本项目已删除',
errorMessage: '删除成本项目失败',
scope: '[admin/cost-center/cost-items/:costItemId]',
audit: (req, data) => {
const item = (data as { costItem?: { id?: number; code?: string } })?.costItem
return {
action: 'cost_item_deleted',
targetType: 'cost_item',
targetId: String(item?.id || req.params.costItemId || ''),
data: { code: item?.code || '' },
}
},
}),
)
router.get(
'/cost-center/cost-versions',
requireAdminPermission('finance.view'),
createJsonHandler((req) => listAdminCostVersions(req.query as JsonObject), {
successMessage: 'ok',
errorMessage: '读取成本版本失败',
scope: '[admin/cost-center/cost-versions]',
}),
)
router.post(
'/cost-center/cost-versions',
requireAdminPermission('finance.config'),
createJsonHandler((req) => createAdminCostVersion(bodyOf(req), sessionOf(req)), {
successMessage: '成本版本已创建',
errorMessage: '创建成本版本失败',
scope: '[admin/cost-center/cost-versions]',
audit: (_req, data) => {
const version = (data as { version?: { id?: number; costItemId?: number } })?.version
return {
action: 'cost_version_created',
targetType: 'cost_version',
targetId: String(version?.id || ''),
data: { costItemId: version?.costItemId || 0 },
}
},
}),
)
router.patch(
'/cost-center/cost-versions/:versionId/retire',
requireAdminPermission('finance.config'),
createJsonHandler((req) => retireAdminCostVersion(idOf(req, 'versionId'), bodyOf(req)), {
successMessage: '成本版本已停用',
errorMessage: '停用成本版本失败',
scope: '[admin/cost-center/cost-versions/:versionId/retire]',
audit: (req, data) => {
const version = (data as { version?: { id?: number } })?.version
return {
action: 'cost_version_retired',
targetType: 'cost_version',
targetId: String(version?.id || req.params.versionId || ''),
data: {},
}
},
}),
)
router.delete(
'/cost-center/cost-versions/:versionId',
requireAdminPermission('finance.config'),
createJsonHandler((req) => deleteAdminCostVersion(idOf(req, 'versionId')), {
successMessage: '成本版本已删除',
errorMessage: '删除成本版本失败',
scope: '[admin/cost-center/cost-versions/:versionId]',
audit: (req, data) => {
const version = (data as { version?: { id?: number } })?.version
return {
action: 'cost_version_deleted',
targetType: 'cost_version',
targetId: String(version?.id || req.params.versionId || ''),
data: {},
}
},
}),
)
router.get(
'/cost-center/exceptions',
requireAdminPermission('finance.view'),
createJsonHandler((req) => listAdminCostExceptions(req.query as JsonObject), {
successMessage: 'ok',
errorMessage: '读取成本异常失败',
scope: '[admin/cost-center/exceptions]',
}),
)
router.patch(
'/cost-center/exceptions/:exceptionId',
requireAdminPermission('finance.config'),
createJsonHandler(
(req) => resolveAdminCostException(idOf(req, 'exceptionId'), bodyOf(req), sessionOf(req)),
{
successMessage: '成本异常已处理',
errorMessage: '处理成本异常失败',
scope: '[admin/cost-center/exceptions/:exceptionId]',
audit: (req, data) => {
const exception = (data as { exception?: { id?: number; status?: string } })?.exception
return {
action: 'cost_exception_resolved',
targetType: 'cost_exception',
targetId: String(exception?.id || req.params.exceptionId || ''),
data: { status: exception?.status || '' },
}
},
},
),
)
router.post(
'/cost-center/preview',
requireAdminPermission('finance.view'),
createJsonHandler((req) => previewAdminCost(bodyOf(req)), {
successMessage: 'ok',
errorMessage: '成本预览失败',
scope: '[admin/cost-center/preview]',
}),
)
router.post(
'/cost-center/snapshots',
requireAdminPermission('finance.config'),
createJsonHandler((req) => createAdminCostSnapshot(bodyOf(req), sessionOf(req)), {
successMessage: '成本快照已生成',
errorMessage: '生成成本快照失败',
scope: '[admin/cost-center/snapshots]',
audit: (req, data) => {
const result = data as {
createdCount?: number
exceptionCreatedCount?: number
preview?: { context?: { orderItemId?: number } }
}
return {
action: 'cost_snapshot_created',
targetType: 'order_item',
targetId: String(result.preview?.context?.orderItemId || req.body?.orderItemId || ''),
data: {
createdCount: result.createdCount || 0,
exceptionCreatedCount: result.exceptionCreatedCount || 0,
},
}
},
}),
)
router.post(
'/cost-center/snapshots/sync',
requireAdminPermission('finance.config'),
createJsonHandler(
async (req) => {
const body = bodyOf(req)
const mode = String(body.mode || 'both').trim()
const estimated = mode === 'actual' ? null : await syncEstimatedOrderItemCostSnapshots(body)
const actual = mode === 'estimated' ? null : await syncActualWorkOrderCostSnapshots(body)
return { mode, estimated, actual }
},
{
successMessage: '成本快照回填完成',
errorMessage: '回填成本快照失败',
scope: '[admin/cost-center/snapshots/sync]',
audit: (req, data) => {
const result = data as {
mode?: string
estimated?: { createdCount?: number; exceptionCreatedCount?: number } | null
actual?: {
createdCount?: number
directRewardCount?: number
upgradedCount?: number
estimatedRewardCount?: number
} | null
}
return {
action: 'cost_snapshot_synced',
targetType: 'cost_snapshot',
targetId: '',
data: {
mode: result.mode || '',
estimatedCreated: result.estimated?.createdCount || 0,
actualCreated:
(result.actual?.directRewardCount || 0) + (result.actual?.upgradedCount || 0),
estimatedRewardCreated: result.actual?.estimatedRewardCount || 0,
exceptions: result.estimated?.exceptionCreatedCount || 0,
dateFrom: req.body?.dateFrom || '',
dateTo: req.body?.dateTo || '',
},
}
},
},
),
)
// ---------------------------------------------------------------------------
// 人工履约 SKU 配置:扫描 → 配置 → 重新匹配
// ---------------------------------------------------------------------------
router.get(
'/cost-center/manual-skus',
requireAdminPermission('finance.view'),
createJsonHandler((req) => listManualSkus(req.query as Record<string, unknown>), {
successMessage: 'ok',
errorMessage: '读取人工 SKU 清单失败',
scope: '[admin/cost-center/manual-skus]',
}),
)
router.get(
'/cost-center/manual-skus/overview',
requireAdminPermission('finance.view'),
createJsonHandler(() => getManualSkuOverview(), {
successMessage: 'ok',
errorMessage: '读取人工 SKU 概览失败',
scope: '[admin/cost-center/manual-skus/overview]',
}),
)
router.get(
'/cost-center/manual-platforms',
requireAdminPermission('finance.view'),
createJsonHandler(() => listManualPlatformOptions(), {
successMessage: 'ok',
errorMessage: '读取人工履约渠道失败',
scope: '[admin/cost-center/manual-platforms]',
}),
)
router.get(
'/cost-center/manual-configs/:skuKey',
requireAdminPermission('finance.view'),
createJsonHandler((req) => getManualFulfillmentConfig(String(req.params.skuKey || '')), {
successMessage: 'ok',
errorMessage: '读取人工履约配置失败',
scope: '[admin/cost-center/manual-configs/:skuKey]',
}),
)
router.post(
'/cost-center/manual-skus/scan',
requireAdminPermission('finance.config'),
createJsonHandler((req) => scanManualSkus(bodyOf(req) as never), {
successMessage: '扫描完成',
errorMessage: '扫描人工 SKU 失败',
scope: '[admin/cost-center/manual-skus/scan]',
audit: (req, data) => {
const result = data as { scanned?: number; fromDate?: string; toDate?: string }
return {
action: 'manual_skus_scanned',
targetType: 'manual_sku_registry',
targetId: '',
data: {
scanned: result.scanned || 0,
fromDate: result.fromDate || '',
toDate: result.toDate || '',
},
}
},
}),
)
router.post(
'/cost-center/manual-configs',
requireAdminPermission('finance.config'),
createJsonHandler((req) => saveManualFulfillmentConfig(bodyOf(req)), {
successMessage: '人工履约配置已保存',
errorMessage: '保存人工履约配置失败',
scope: '[admin/cost-center/manual-configs]',
audit: (req, data) => {
const config = data as {
id?: number
skuKey?: string
platformKey?: string
creditQuantity?: number
costFen?: number
}
return {
action: 'manual_fulfillment_config_saved',
targetType: 'manual_fulfillment_config',
targetId: String(config.id || ''),
data: {
skuKey: config.skuKey || '',
platformKey: config.platformKey || '',
creditQuantity: config.creditQuantity || 0,
costFen: config.costFen || 0,
},
}
},
}),
)
router.delete(
'/cost-center/manual-configs/:skuKey',
requireAdminPermission('finance.config'),
createJsonHandler((req) => deleteManualFulfillmentConfig(String(req.params.skuKey || '')), {
successMessage: '人工履约配置已删除',
errorMessage: '删除人工履约配置失败',
scope: '[admin/cost-center/manual-configs/:skuKey]',
audit: (req, data) => {
const result = data as { skuKey?: string; deleted?: number }
return {
action: 'manual_fulfillment_config_deleted',
targetType: 'manual_fulfillment_config',
targetId: String(req.params.skuKey || ''),
data: { skuKey: result.skuKey || '', deleted: result.deleted || 0 },
}
},
}),
)
router.post(
'/cost-center/manual-configs/rematch',
requireAdminPermission('finance.config'),
createJsonHandler((req) => rematchManualFulfillments(bodyOf(req)), {
successMessage: '重新匹配完成',
errorMessage: '重新匹配失败',
scope: '[admin/cost-center/manual-configs/rematch]',
audit: (req, data) => {
const result = data as { updatedCount?: number; skuKey?: string }
return {
action: 'manual_fulfillment_rematched',
targetType: 'order_items',
targetId: '',
data: {
updatedCount: result.updatedCount || 0,
skuKey: result.skuKey || '',
},
}
},
}),
)
// ---------------------------------------------------------------------------
// 客服平台积分钱包(南航 / 乐玩 / ROCK)
// ---------------------------------------------------------------------------
router.get(
'/cost-center/platform-credits/accounts',
requireAnyAdminPermission(['fund.view', 'finance.view']),
createJsonHandler((req) => listPlatformCreditAccounts(sessionOf(req)), {
successMessage: 'ok',
errorMessage: '读取积分钱包失败',
scope: '[admin/cost-center/platform-credits/accounts]',
}),
)
router.get(
'/cost-center/platform-credits/entries',
requireAnyAdminPermission(['fund.view', 'finance.view']),
createJsonHandler(
(req) => listPlatformCreditEntries(req.query as Record<string, unknown>, sessionOf(req)),
{
successMessage: 'ok',
errorMessage: '读取积分流水失败',
scope: '[admin/cost-center/platform-credits/entries]',
},
),
)
router.get(
'/cost-center/platform-credits/owners',
requireAdminPermission('finance.config'),
createJsonHandler(() => listPlatformCreditOwners(), {
successMessage: 'ok',
errorMessage: '读取客服列表失败',
scope: '[admin/cost-center/platform-credits/owners]',
}),
)
router.post(
'/cost-center/platform-credits/grant',
requireAdminPermission('finance.config'),
createJsonHandler((req) => grantPlatformCredit(bodyOf(req), sessionOf(req)), {
successMessage: '积分已充值',
errorMessage: '积分充值失败',
scope: '[admin/cost-center/platform-credits/grant]',
audit: (req, data) => {
const result = data as {
platformKey?: string
quantity?: number
amountFen?: number
}
return {
action: 'platform_credit_granted',
targetType: 'platform_credit_account',
targetId: String(req.body?.ownerAdminUserId || ''),
data: {
platformKey: result.platformKey || '',
quantity: result.quantity || 0,
amountFen: result.amountFen || 0,
},
}
},
}),
)
router.post(
'/cost-center/platform-credits/adjust',
requireAdminPermission('finance.config'),
createJsonHandler((req) => adjustPlatformCredit(bodyOf(req), sessionOf(req)), {
successMessage: '积分已调整',
errorMessage: '积分调整失败',
scope: '[admin/cost-center/platform-credits/adjust]',
audit: (req, data) => {
const result = data as {
platformKey?: string
quantity?: number
amountFen?: number
}
return {
action: 'platform_credit_adjusted',
targetType: 'platform_credit_account',
targetId: String(req.body?.ownerAdminUserId || ''),
data: {
platformKey: result.platformKey || '',
quantity: result.quantity || 0,
amountFen: result.amountFen || 0,
},
}
},
}),
)
export default router