front/src/views/agent-admin/commission/index.vue
zzh c66071ed5e
All checks were successful
Build and Deploy Front / deploy (push) Successful in 6m43s
feat: 渠道代理门户与运营列表,并修复分区明细工具栏误删分区
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-29 18:38:18 +08:00

247 lines
7.6 KiB
Vue

<template>
<div class="agent-admin-commission-container">
<div class="table-toolbar">
<div class="toolbar-left">
<div class="toolbar-filters">
<a-input-number
v-model="agentId"
placeholder="代理Id"
:min="1"
allow-clear
style="width: 140px"
/>
<a-select v-model="status" allow-clear placeholder="状态" style="width: 140px">
<a-option value="pending">待结算</a-option>
<a-option value="paid">已打款</a-option>
</a-select>
<a-button class="app-btn-search" @click="handleSearch">查询</a-button>
</div>
<a-button :disabled="!selectedIds.length" @click="markPaid">标记已打款</a-button>
</div>
<div class="toolbar-right">
<a-space :size="8">
<a-button @click="loadList">刷新</a-button>
<PaginationPro
:total-count="totalCount"
v-model:current-page="currentPage"
v-model:page-size="pageSize"
@page-change="loadList"
@page-size-change="loadList"
/>
</a-space>
</div>
</div>
<a-spin :loading="listLoading" class="list-spin">
<div ref="tableContainerRef" class="list-wrap">
<HandsontablePro
:columns="hotColumns"
:data="tableRows"
:total="totalCount"
:current-page="currentPage"
:page-size="pageSize"
:stretch-columns="true"
:height="handsontableHeight"
:read-only="true"
:show-action-column="true"
:action-renderer="actionRenderer"
:show-checkbox-column="true"
@selection-change="onSelectionChange"
:custom-cell-renderer="customCellRenderer"
@action-click="handleActionClick"
/>
</div>
</a-spin>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue'
import { Message } from '@arco-design/web-vue'
import HandsontablePro from '@/components/HandsontablePro/index.vue'
import PaginationPro from '@/components/PaginationPro/index.vue'
import { useTableContainerHeight } from '@/composables/useTableContainerHeight'
import { buildStatusTagHtml } from '@/utils/statusTag'
import { renderWarehouseActionBtn, wrapWarehouseActions } from '@/utils/warehouseActionRenderer'
import { AgentAdminApi, type AgentCommissionDto } from '@/api/agent'
defineOptions({ name: 'AgentAdminCommission' })
const { tableContainerRef, tableHeight } = useTableContainerHeight()
const handsontableHeight = computed(() => Math.max(tableHeight.value || 0, 400))
interface CommissionRow {
id: number
agentCode: string
agentName: string
serviceNo: string
customerCode: string
customerName: string
baseType: string
baseAmount: number
commissionRate: number
commissionAmount: number
status: string
statusName: string
triggerOrderStatus: string
createTime: string
}
const tableRows = ref<CommissionRow[]>([])
const totalCount = ref(0)
const listLoading = ref(false)
const agentId = ref<number | undefined>()
const status = ref<string | undefined>()
const currentPage = ref(1)
const pageSize = ref(50)
const selectedRows = ref<CommissionRow[]>([])
const selectedIds = computed(() => selectedRows.value.map((x) => x.id).filter((x) => x > 0))
const hotColumns = computed(() => [
{ key: 'agentCode', label: '代理编号', width: 110 },
{ key: 'serviceNo', label: '运单号', width: 140 },
{ key: 'customerCode', label: '客户编号', width: 110 },
{ key: 'baseType', label: '基数类型', width: 100 },
{ key: 'baseAmount', label: '基数', width: 100 },
{ key: 'commissionRate', label: '比例', width: 80 },
{ key: 'commissionAmount', label: '返佣金额', width: 100 },
{ key: 'statusName', label: '状态', width: 90 },
{ key: 'triggerOrderStatus', label: '触发状态', width: 120 },
{ key: 'createTime', label: '计提时间', width: 160 },
])
function pick(row: Record<string, unknown>, camel: string, pascal: string) {
return row[camel] ?? row[pascal]
}
function mapRow(raw: AgentCommissionDto): CommissionRow {
const r = raw as unknown as Record<string, unknown>
const st = String(pick(r, 'status', 'Status') ?? '')
return {
id: Number(pick(r, 'id', 'Id') ?? 0),
agentCode: String(pick(r, 'agentCode', 'AgentCode') ?? ''),
agentName: String(pick(r, 'agentName', 'AgentName') ?? ''),
serviceNo: String(pick(r, 'serviceNo', 'ServiceNo') ?? ''),
customerCode: String(pick(r, 'customerCode', 'CustomerCode') ?? ''),
customerName: String(pick(r, 'customerName', 'CustomerName') ?? ''),
baseType: String(pick(r, 'baseType', 'BaseType') ?? ''),
baseAmount: Number(pick(r, 'baseAmount', 'BaseAmount') ?? 0),
commissionRate: Number(pick(r, 'commissionRate', 'CommissionRate') ?? 0),
commissionAmount: Number(pick(r, 'commissionAmount', 'CommissionAmount') ?? 0),
status: st,
statusName: st === 'paid' ? '已打款' : '待结算',
triggerOrderStatus: String(pick(r, 'triggerOrderStatus', 'TriggerOrderStatus') ?? ''),
createTime: String(pick(r, 'createTime', 'CreateTime') ?? ''),
}
}
function actionRenderer(row: CommissionRow, rowIndex: number): string {
if (row.status === 'paid') {
return '<span style="color:var(--color-text-3);font-size:12px;">--</span>'
}
return wrapWarehouseActions(
[renderWarehouseActionBtn('markPaid', '标记已打款', 'pay')],
rowIndex,
)
}
function handleActionClick(row: CommissionRow, _rowIndex: number, action?: string) {
if (action === 'markPaid') void markPaidIds([row.id])
}
function customCellRenderer(_row: number, col: number, _value: unknown, rowData: CommissionRow): string | null {
// 操作列 + 序号列 + 复选框列
const dataColIndex = col - 3
if (dataColIndex < 0 || dataColIndex >= hotColumns.value.length) return null
const colKey = hotColumns.value[dataColIndex].key
if (colKey === 'statusName') {
return buildStatusTagHtml(rowData.statusName, rowData.status === 'paid' ? 'ok' : 'wait')
}
return null
}
function onSelectionChange(rows: CommissionRow[]) {
selectedRows.value = rows || []
}
async function loadList() {
listLoading.value = true
try {
const res = await AgentAdminApi.commissionList({
page: currentPage.value,
pageSize: pageSize.value,
agentId: agentId.value,
status: status.value,
})
tableRows.value = (res.items || []).map(mapRow)
totalCount.value = res.total
selectedRows.value = []
} catch (e: any) {
Message.error(e?.message || '加载失败')
} finally {
listLoading.value = false
}
}
function handleSearch() {
currentPage.value = 1
void loadList()
}
async function markPaidIds(ids: number[]) {
const valid = ids.map(Number).filter((x) => x > 0)
if (!valid.length) return
try {
await AgentAdminApi.markPaid(valid)
Message.success('已标记')
await loadList()
} catch (e: any) {
Message.error(e?.message || '操作失败')
}
}
async function markPaid() {
await markPaidIds(selectedIds.value)
}
onMounted(() => void loadList())
</script>
<style scoped lang="less">
.agent-admin-commission-container {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
padding: 16px;
background: #fff;
}
.table-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
gap: 12px;
}
.toolbar-left {
display: flex;
gap: 8px;
align-items: center;
}
.toolbar-filters {
display: flex;
gap: 8px;
align-items: center;
}
.list-spin {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.list-wrap {
flex: 1;
min-height: 0;
}
</style>