<script setup lang="ts">
|
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
import { useRoute, useRouter } from 'vue-router'
|
import { Plus, Refresh, Search } from '@element-plus/icons-vue'
|
import { ElMessage } from 'element-plus'
|
import {
|
adoptManagedOnboarding,
|
getAdminMerchants,
|
getMerchantSettlement,
|
getMerchantSettlementMerchantTypes,
|
getMerchantSettlements,
|
previewManagedOnboarding,
|
} from '../api/admin'
|
import { hasAdminPermission } from '../utils/permissions'
|
|
type Kind = 'onboardings' | 'bank-cards' | 'settlements'
|
|
const kind = ref<Kind>('settlements')
|
const router = useRouter()
|
const route = useRoute()
|
const loading = ref(false)
|
const rows = ref<Record<string, any>[]>([])
|
const total = ref(0)
|
/** 结算记录逐商户查询,个别商户查不到时在这里提示,不影响整页。 */
|
const failures = ref<string[]>([])
|
const page = ref(1)
|
const pageSize = ref(20)
|
|
const filters = reactive({
|
merchantName: '',
|
contactMobile: '',
|
merchantType: '',
|
status: '',
|
dateRange: [] as string[],
|
})
|
|
const tabOptions: Array<{ value: Kind; label: string }> = [
|
{ value: 'settlements', label: '结算记录' },
|
{ value: 'onboardings', label: '商户进件' },
|
{ value: 'bank-cards', label: '银行卡申请' },
|
]
|
|
// 商家类型选项来自后端目录。原先这里手写了一份 8 项清单,标签是目录里根本不用的别名
|
// (住宿服务/购房服务/体检服务),后来又新增的类型也没跟上,才会出现下拉里有的筛不出数据、
|
// 数据里有的选不到。现在只从接口取,取不到就留空。
|
const merchantTypes = ref<string[]>([])
|
// 结算记录没有本地审核状态:它的「状态」是通道流水的结算状态(S/F/P),与表格那一列同一套取值。
|
const statusOptions = computed(() => kind.value === 'settlements'
|
? [
|
{ value: 'S', label: '已结算' },
|
{ value: 'F', label: '结算失败' },
|
{ value: 'P', label: '处理中' },
|
]
|
: [
|
{ value: 'pending', label: '待审核' },
|
{ value: 'approved', label: '已通过' },
|
{ value: 'rejected', label: '已驳回' },
|
])
|
|
function statusLabel(value: string) {
|
return ({ pending: '待审核', approved: '已通过', rejected: '已驳回', processing: '处理中', paid: '已到账', failed: '提现失败' } as Record<string, string>)[value] || value || '-'
|
}
|
|
function statusType(value: string) {
|
return ({ pending: 'warning', approved: 'success', paid: 'success', rejected: 'danger', failed: 'danger', processing: 'primary' } as Record<string, 'warning' | 'success' | 'danger' | 'primary'>)[value] || 'primary'
|
}
|
|
/** 斗拱结算流水的交易状态:S 成功、F 失败、P 处理中。 */
|
function settleStatusLabel(value: unknown) {
|
return ({ S: '已结算', F: '结算失败', P: '处理中' } as Record<string, string>)[String(value || '')] || String(value || '-')
|
}
|
|
function settleStatusType(value: unknown) {
|
const normalized = String(value || '')
|
return normalized === 'S' ? 'success' : normalized === 'F' ? 'danger' : 'warning'
|
}
|
|
/** 结算日期是 yyyyMMdd 字符串,展示成 2026-09-14。 */
|
function formatSettleDate(value: unknown) {
|
const text = String(value || '')
|
return /^\d{8}$/.test(text) ? `${text.slice(0, 4)}-${text.slice(4, 6)}-${text.slice(6, 8)}` : text || '-'
|
}
|
|
function subjectTypeLabel(value: unknown) {
|
const normalized = String(value || '').toLowerCase()
|
if (normalized === 'enterprise' || normalized === 'company' || normalized === '企业') return '企业'
|
return normalized === 'individual' || normalized === 'person' || normalized === '个人' ? '个人' : String(value || '-')
|
}
|
|
function formatAmount(value: unknown) {
|
if (value === null || value === undefined || value === '') return '-'
|
return `¥${(Number(value) / 100).toFixed(2)}`
|
}
|
|
function formatDate(value: unknown) {
|
if (!value) return '-'
|
return String(value).replace('T', ' ').replace(/\.\d+$/, '')
|
}
|
|
/**
|
* 每次查询的序号。切 tab、改条件、翻页都会自增,只有最新那一次的结果允许写回表格。
|
*
|
* 结算记录要逐商户去问斗拱,是最慢的一次请求;先切到别的 tab 的话,它的响应会最后落地。
|
* 少了这道闸,它就会把已经切过去的那个 tab 的表格覆盖成结算流水——表头是进件/银行卡的列,
|
* 内容却是结算记录(连带分页总数也变成结算的条数)。
|
*/
|
let latestRequest = 0
|
|
async function load() {
|
const request = ++latestRequest
|
loading.value = true
|
try {
|
if (kind.value === 'settlements') {
|
// 结算记录来自斗拱,逐商户查询后合并;条数上限 50 是通道的硬限制,传更大的值通道会判
|
// 基础参数校验失败、整页查不出流水。商家、联系电话、商家类型送后端去筛商户(顺带少查几家),
|
// 状态是通道流水的结算状态,只能由后端在拿到流水后筛。
|
const result = await getMerchantSettlements({
|
beginDate: normalizeDate(filters.dateRange?.[0]),
|
endDate: normalizeDate(filters.dateRange?.[1]),
|
size: 50,
|
merchantName: filters.merchantName.trim() || undefined,
|
contactMobile: filters.contactMobile.trim() || undefined,
|
merchantType: filters.merchantType || undefined,
|
status: filters.status || undefined,
|
})
|
if (request !== latestRequest) return
|
rows.value = result.records || []
|
total.value = Number(result.total || 0)
|
failures.value = result.failures || []
|
return
|
}
|
const result = await getMerchantSettlement(kind.value, {
|
page: page.value,
|
size: pageSize.value,
|
merchantName: filters.merchantName.trim() || undefined,
|
contactMobile: filters.contactMobile.trim() || undefined,
|
merchantType: filters.merchantType || undefined,
|
status: filters.status || undefined,
|
// 日期选择器点「清空」时给的是 null(不是 []),这里必须用可选链,否则查询会因为
|
// 读 null[0] 抛异常而静默失败,页面停在旧数据上,看起来像查询没生效。
|
startDate: filters.dateRange?.[0],
|
endDate: filters.dateRange?.[1],
|
})
|
if (request !== latestRequest) return
|
rows.value = result.records || []
|
total.value = Number(result.total || 0)
|
failures.value = []
|
} finally {
|
// 转圈只归最新那次请求管:过期的响应早早关掉它,会让仍在加载的那一页看起来已经加载完了。
|
if (request === latestRequest) loading.value = false
|
}
|
}
|
|
/** 日期选择器给的是 yyyy-MM-dd,斗拱要 yyyyMMdd。 */
|
function normalizeDate(value: string | undefined) {
|
return value ? value.replace(/-/g, '') : undefined
|
}
|
|
/** 商家类型筛选项取自后端目录;取不到就留空,不用一份可能过期的本地清单兜底。 */
|
async function loadMerchantTypes() {
|
try {
|
merchantTypes.value = (await getMerchantSettlementMerchantTypes()) || []
|
} catch {
|
merchantTypes.value = []
|
}
|
}
|
|
function search() {
|
page.value = 1
|
load()
|
}
|
|
function reset() {
|
filters.merchantName = ''
|
filters.contactMobile = ''
|
filters.merchantType = ''
|
filters.status = ''
|
filters.dateRange = []
|
page.value = 1
|
load()
|
}
|
|
function changeKind(value: string | number | boolean | undefined) {
|
kind.value = value as Kind
|
page.value = 1
|
filters.status = ''
|
// 页签要写回地址栏。不写的话,刷新、浏览器返回、把链接发给别人,落地的都是地址栏里那个
|
// 旧页签——从进件详情按返回会掉回银行卡申请就是这么来的。用 replace 而不是 push,
|
// 切页签不该在历史里留一串记录。
|
router.replace({ query: { ...route.query, kind: kind.value } })
|
load()
|
}
|
|
/** 地址栏里的页签;识别不了时返回 null,保留当前选择。 */
|
function routeKind(): Kind | null {
|
const value = String(route.query.kind || '')
|
if (value === 'onboardings' || value === 'bank-cards' || value === 'settlements') return value
|
// 旧链接(提现管理)现在指向结算记录。
|
if (value === 'withdrawals') return 'settlements'
|
return null
|
}
|
|
function applyRouteKind() {
|
const next = routeKind()
|
if (next) kind.value = next
|
}
|
|
function openReview(row: Record<string, any>) {
|
if (kind.value === 'onboardings') {
|
router.push({ name: 'merchant-onboarding-detail', params: { id: row.id } })
|
}
|
}
|
|
/**
|
* 纳管外部进件商户。
|
*
|
* 流程刻意分两步:先「核验通道商户」做一次只读查询,把通道侧的商户注册名称、商户简称与主体类型
|
* 展示出来,运营与所选商家核对后**显式勾选确认**才能提交。不做「名称是否对得上」的程序判定——
|
* 我们这边只有一个商家名(常是简称或服务点名),通道那边是工商全称,形态不对应,规则化匹配必然误判。
|
*/
|
const adoptVisible = ref(false)
|
const adoptPreviewing = ref(false)
|
const adoptSubmitting = ref(false)
|
const adoptConfirmed = ref(false)
|
const adoptPreview = ref<Record<string, any>>()
|
const adoptForm = reactive({ merchantId: undefined as number | string | undefined, providerHuifuId: '', providerApplyNo: '' })
|
const merchantOptions = ref<Array<{ id: number | string; merchantName: string }>>([])
|
const merchantLoading = ref(false)
|
|
async function searchMerchants(keyword: string) {
|
merchantLoading.value = true
|
try {
|
const result = await getAdminMerchants({ page: 1, size: 20, keyword: keyword?.trim() || undefined })
|
merchantOptions.value = result.records || []
|
} catch {
|
merchantOptions.value = []
|
} finally {
|
merchantLoading.value = false
|
}
|
}
|
|
function openAdopt() {
|
adoptForm.merchantId = undefined
|
adoptForm.providerHuifuId = ''
|
adoptForm.providerApplyNo = ''
|
adoptPreview.value = undefined
|
adoptConfirmed.value = false
|
adoptVisible.value = true
|
if (merchantOptions.value.length === 0) searchMerchants('')
|
}
|
|
/** 换了商家或商户号,之前那次核验的对象就不是现在填的了,确认必须重新勾。 */
|
function invalidateAdoptPreview() {
|
adoptPreview.value = undefined
|
adoptConfirmed.value = false
|
}
|
|
async function runAdoptPreview() {
|
if (!adoptForm.merchantId) {
|
ElMessage.warning('请先选择我方商家')
|
return
|
}
|
if (!adoptForm.providerHuifuId.trim()) {
|
ElMessage.warning('请先填写汇付商户号')
|
return
|
}
|
adoptPreviewing.value = true
|
try {
|
// 申请单号一起送去核验:错号(含"真实存在但属于别的商户号")在通道侧会回「申请单不存在」,
|
// 后端会当成硬拦截项列出来,运营当场就知道填错了,不用等提交。
|
adoptPreview.value = await previewManagedOnboarding({
|
merchantId: adoptForm.merchantId,
|
providerHuifuId: adoptForm.providerHuifuId.trim(),
|
providerApplyNo: adoptForm.providerApplyNo.trim(),
|
})
|
adoptConfirmed.value = false
|
} catch (error: any) {
|
adoptPreview.value = undefined
|
adoptConfirmed.value = false
|
ElMessage.error(error?.message || '核验通道商户失败,请确认商户号后重试')
|
} finally {
|
adoptPreviewing.value = false
|
}
|
}
|
|
async function submitAdopt() {
|
if (!adoptPreview.value) {
|
ElMessage.warning('请先核验通道商户')
|
return
|
}
|
if (!adoptForm.providerApplyNo.trim()) {
|
ElMessage.warning('请填写汇付侧的入驻申请单号')
|
return
|
}
|
if (!adoptConfirmed.value) {
|
ElMessage.warning('请先核对通道商户名称并勾选确认')
|
return
|
}
|
adoptSubmitting.value = true
|
try {
|
const result = await adoptManagedOnboarding({
|
merchantId: adoptForm.merchantId as number | string,
|
providerHuifuId: adoptForm.providerHuifuId.trim(),
|
providerApplyNo: adoptForm.providerApplyNo.trim(),
|
confirmed: true,
|
})
|
adoptVisible.value = false
|
ElMessage.success('纳管成功,已触发一次进度刷新')
|
await load()
|
// 纳管产出的就是一条进件记录,直接进详情看分阶段进度与待办理项。
|
if (result?.id) router.push({ name: 'merchant-onboarding-detail', params: { id: String(result.id) } })
|
} catch (error: any) {
|
ElMessage.error(error?.message || '纳管失败,请稍后重试')
|
} finally {
|
adoptSubmitting.value = false
|
}
|
}
|
|
watch(() => route.query.kind, () => {
|
const next = routeKind()
|
// changeKind 自己写回地址栏也会走到这里,那一次已经查过了,别重复请求。
|
if (!next || next === kind.value) return
|
kind.value = next
|
page.value = 1
|
filters.status = ''
|
load()
|
})
|
|
onMounted(() => {
|
applyRouteKind()
|
load()
|
loadMerchantTypes()
|
})
|
</script>
|
|
<template>
|
<div class="withdrawal-page">
|
<div class="settlement-tabs">
|
<el-radio-group v-model="kind" @change="changeKind">
|
<el-radio-button v-for="tab in tabOptions" :key="tab.value" :label="tab.value">
|
{{ tab.label }}
|
</el-radio-button>
|
</el-radio-group>
|
</div>
|
|
<section class="query-panel">
|
<div class="panel-title">查询表格</div>
|
<el-form class="query-form" label-width="70px" @submit.prevent="search">
|
<el-form-item label="商家">
|
<el-input v-model="filters.merchantName" clearable placeholder="请输入商家名称" />
|
</el-form-item>
|
<el-form-item label="联系电话">
|
<el-input v-model="filters.contactMobile" clearable placeholder="请输入商家联系电话" />
|
</el-form-item>
|
<!-- 同一个日期区间在两个 tab 里筛的是不同东西:进件/银行卡按申请时间,结算记录按结算日期。 -->
|
<el-form-item :label="kind === 'settlements' ? '结算日期' : '申请时间'">
|
<el-date-picker
|
v-model="filters.dateRange"
|
type="daterange"
|
value-format="YYYY-MM-DD"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
unlink-panels
|
/>
|
</el-form-item>
|
<el-form-item label="商家类型">
|
<el-select v-model="filters.merchantType" clearable placeholder="全部">
|
<el-option v-for="item in merchantTypes" :key="item" :label="item" :value="item" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="状态">
|
<el-select v-model="filters.status" clearable placeholder="全部">
|
<el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
|
</el-select>
|
</el-form-item>
|
<el-form-item class="query-actions">
|
<el-button type="primary" :icon="Search" @click="search">查询</el-button>
|
<el-button :icon="Refresh" @click="reset">重置</el-button>
|
</el-form-item>
|
</el-form>
|
<!-- 纳管入口只放在「商户进件」页签:纳管产出的就是一条进件记录,这个页签正是进件记录的列表,
|
纳管结果当场可见。位置沿用「商家查询」页「新建」按钮的既有习惯。 -->
|
<div v-if="kind === 'onboardings'" class="settlement-table-tools">
|
<el-button
|
v-if="hasAdminPermission('admin.merchant-settlement.edit')"
|
type="primary"
|
:icon="Plus"
|
@click="openAdopt"
|
>
|
纳管外部进件商户
|
</el-button>
|
</div>
|
</section>
|
|
<section class="table-panel">
|
<el-table v-loading="loading" :data="rows" border class="settlement-table" empty-text="暂无数据">
|
<template v-if="kind === 'settlements'">
|
<el-table-column prop="providerTransactionNo" label="结算流水号" min-width="190" show-overflow-tooltip />
|
<el-table-column prop="merchantName" label="商家名称" min-width="180" show-overflow-tooltip />
|
<el-table-column label="结算日期" min-width="118"><template #default="{ row }">{{ formatSettleDate(row.settleDate) }}</template></el-table-column>
|
<el-table-column label="结算金额" min-width="110" align="right"><template #default="{ row }">{{ formatAmount(row.settleAmountCents) }}</template></el-table-column>
|
<el-table-column label="手续费" min-width="96" align="right"><template #default="{ row }">{{ formatAmount(row.feeAmountCents) }}</template></el-table-column>
|
<el-table-column prop="settleCycle" label="结算周期" min-width="96" />
|
<el-table-column label="状态" min-width="96">
|
<template #default="{ row }"><el-tag :type="settleStatusType(row.status)">{{ settleStatusLabel(row.status) }}</el-tag></template>
|
</el-table-column>
|
<el-table-column prop="cardMasked" label="到账卡号" min-width="160" />
|
<el-table-column prop="cardHolder" label="持卡人" min-width="180" show-overflow-tooltip />
|
</template>
|
<template v-else-if="kind === 'onboardings'">
|
<el-table-column prop="applicationNo" label="进件id" min-width="156" />
|
<el-table-column prop="merchantName" label="商家名称" min-width="150" show-overflow-tooltip />
|
<el-table-column prop="contactMobile" label="联系方式" min-width="118" />
|
<el-table-column prop="merchantType" label="商家类型" min-width="110" />
|
<el-table-column prop="subjectName" label="进件主体" min-width="150" show-overflow-tooltip />
|
<el-table-column label="主体类型" min-width="105"><template #default="{ row }">{{ subjectTypeLabel(row.subjectType) }}</template></el-table-column>
|
<!-- 来源标记:区分两条进件路径,纳管进来的要一眼看出来。 -->
|
<el-table-column label="来源" min-width="100" align="center">
|
<template #default="{ row }">
|
<el-tag :type="row.source === 'managed' ? 'success' : 'info'" effect="plain">{{ row.source === 'managed' ? '纳管' : '自助进件' }}</el-tag>
|
</template>
|
</el-table-column>
|
</template>
|
<template v-else>
|
<el-table-column prop="id" label="申请id" min-width="100" />
|
<el-table-column prop="merchantName" label="商家名称" min-width="150" show-overflow-tooltip />
|
<el-table-column prop="contactMobile" label="联系方式" min-width="118" />
|
<el-table-column prop="merchantType" label="商家类型" min-width="110" />
|
<el-table-column prop="bankName" label="开户银行" min-width="145" show-overflow-tooltip />
|
<el-table-column prop="branchName" label="开户支行" min-width="180" show-overflow-tooltip />
|
<el-table-column prop="cityName" label="开户城市" min-width="120" show-overflow-tooltip />
|
<!-- 卡号只展示后端生成的脱敏值:明文 PAN 不再从接口下发。 -->
|
<el-table-column prop="cardMasked" label="银行卡号" min-width="180" />
|
</template>
|
<template v-if="kind !== 'settlements'">
|
<el-table-column label="申请时间" min-width="165">
|
<template #default="{ row }">{{ formatDate(row.createdAt) }}</template>
|
</el-table-column>
|
<el-table-column label="状态" min-width="100" align="center">
|
<template #default="{ row }">
|
<el-tag :type="statusType(row.status)" effect="light">{{ statusLabel(row.status) }}</el-tag>
|
</template>
|
</el-table-column>
|
</template>
|
<el-table-column v-if="kind === 'onboardings'" label="操作" width="110" fixed="right" align="center">
|
<template #default="{ row }">
|
<el-button link type="primary" @click="openReview(row)">查看</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<el-alert
|
v-if="kind === 'settlements' && failures.length > 0"
|
class="settlement-failures"
|
type="warning"
|
:closable="false"
|
:title="`部分商户结算记录查询失败:${failures.join(';')}`"
|
/>
|
<div v-if="kind !== 'settlements'" class="pagination-bar">
|
<el-pagination
|
v-model:current-page="page"
|
v-model:page-size="pageSize"
|
background
|
layout="total, sizes, prev, pager, next"
|
:page-sizes="[10, 20, 50]"
|
:total="total"
|
@change="load"
|
/>
|
</div>
|
</section>
|
|
<el-dialog
|
v-model="adoptVisible"
|
title="纳管外部进件商户"
|
width="640px"
|
:close-on-click-modal="false"
|
destroy-on-close
|
>
|
<el-form label-width="120px" class="adopt-form">
|
<el-form-item label="我方商家" required>
|
<el-select
|
v-model="adoptForm.merchantId"
|
filterable
|
remote
|
reserve-keyword
|
clearable
|
placeholder="输入商家名称搜索"
|
:remote-method="searchMerchants"
|
:loading="merchantLoading"
|
@change="invalidateAdoptPreview"
|
>
|
<el-option
|
v-for="item in merchantOptions"
|
:key="item.id"
|
:label="item.merchantName"
|
:value="item.id"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="汇付商户号" required>
|
<el-input v-model="adoptForm.providerHuifuId" clearable placeholder="斗拱侧该商户的 huifu_id" @input="invalidateAdoptPreview" />
|
</el-form-item>
|
<el-form-item label="入驻申请单号" required>
|
<!-- 改号同样作废上一次核验:否则会出现「核验的是这个号、提交的却是另一个号」。 -->
|
<el-input v-model="adoptForm.providerApplyNo" clearable placeholder="汇付控台入驻申请列表里的申请单号" @input="invalidateAdoptPreview" />
|
</el-form-item>
|
<el-form-item label=" ">
|
<el-button type="primary" plain :loading="adoptPreviewing" @click="runAdoptPreview">核验通道商户</el-button>
|
</el-form-item>
|
</el-form>
|
|
<template v-if="adoptPreview">
|
<el-descriptions :column="1" border size="small" class="adopt-preview">
|
<el-descriptions-item label="我方商家">
|
{{ adoptPreview.merchantName
|
}}<span v-if="adoptPreview.storeName && adoptPreview.storeName !== adoptPreview.merchantName" class="muted">(门店:{{ adoptPreview.storeName }})</span>
|
</el-descriptions-item>
|
<el-descriptions-item label="通道商户注册名称">{{ adoptPreview.channelMerchantName }}</el-descriptions-item>
|
<el-descriptions-item label="通道商户简称">{{ adoptPreview.channelShortName }}</el-descriptions-item>
|
<el-descriptions-item label="通道主体类型">
|
{{ adoptPreview.channelSubjectType === 'enterprise' ? '企业' : '个人' }}
|
<span v-if="adoptPreview.channelCompanyType" class="muted">({{ adoptPreview.channelCompanyType }})</span>
|
</el-descriptions-item>
|
<el-descriptions-item label="结算银行卡">
|
{{ adoptPreview.settlementCardMasked || '-' }}
|
<span v-if="adoptPreview.settlementBankName" class="muted">({{ adoptPreview.settlementBankName }})</span>
|
</el-descriptions-item>
|
</el-descriptions>
|
<!-- 只提示不拦截:连锁各门店共用一个收款主体是允许的,列出已绑的商家让运营自己确认。 -->
|
<el-alert
|
v-if="adoptPreview.alreadyManaged"
|
class="adopt-alert"
|
type="success"
|
:closable="false"
|
title="该商家已纳管过这个汇付商户号,提交会返回原进件记录,不会新建"
|
/>
|
<el-alert
|
v-if="adoptPreview.boundMerchants?.length"
|
class="adopt-alert"
|
type="info"
|
:closable="false"
|
:title="`该汇付商户号已绑给:${adoptPreview.boundMerchants.join('、')},可继续纳管`"
|
/>
|
<el-alert
|
v-if="adoptPreview.nameWarning"
|
class="adopt-alert"
|
type="warning"
|
:closable="false"
|
title="通道名称与所选商家名完全没有重合字符"
|
:description="adoptPreview.nameWarning"
|
/>
|
<el-alert
|
v-if="adoptPreview.loginNotice"
|
class="adopt-alert"
|
type="warning"
|
:closable="false"
|
:title="adoptPreview.loginNotice"
|
/>
|
<el-alert
|
v-for="blocker in adoptPreview.blockers || []"
|
:key="blocker"
|
class="adopt-alert"
|
type="error"
|
:closable="false"
|
:title="blocker"
|
/>
|
<el-checkbox v-model="adoptConfirmed" :disabled="(adoptPreview.blockers || []).length > 0">
|
我已核对通道商户名称与所选商家一致(该商家的收款将进入这个收款主体)
|
</el-checkbox>
|
</template>
|
|
<template #footer>
|
<el-button @click="adoptVisible = false">取消</el-button>
|
<el-button
|
type="primary"
|
:loading="adoptSubmitting"
|
:disabled="!adoptPreview || !adoptConfirmed || (adoptPreview.blockers || []).length > 0"
|
@click="submitAdopt"
|
>
|
提交纳管
|
</el-button>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<style scoped>
|
.withdrawal-page { min-width: 1040px; }
|
.settlement-failures { margin-top: 12px; }.settlement-tabs { margin: 0 0 16px; }
|
.settlement-tabs :deep(.el-radio-button__inner) { min-width: 96px; }
|
.query-panel, .table-panel { background: #fff; border: 1px solid #edf0f5; }
|
.query-panel { padding: 18px 20px 6px; }
|
.panel-title { margin-bottom: 16px; color: #1d2129; font-size: 15px; font-weight: 600; }
|
.query-form { display: grid; grid-template-columns: repeat(3, minmax(250px, 1fr)); column-gap: 24px; }
|
.query-form :deep(.el-form-item) { margin-bottom: 16px; }
|
.query-form :deep(.el-form-item__content) { min-width: 0; }
|
.query-form :deep(.el-input), .query-form :deep(.el-select), .query-form :deep(.el-date-editor) { width: 100%; }
|
.query-actions { justify-content: flex-end; }
|
.query-actions :deep(.el-form-item__content) { justify-content: flex-end; }
|
.settlement-table-tools { margin: 0 0 12px; }
|
.adopt-form :deep(.el-select) { width: 100%; }
|
.adopt-preview { margin-bottom: 14px; }
|
.adopt-alert { margin-bottom: 12px; }
|
.table-panel { margin-top: 16px; padding: 0 20px 12px; }
|
.settlement-table { width: 100%; }
|
.settlement-table :deep(th.el-table__cell) { color: #303133; font-weight: 600; background: #f7f8fa; }
|
.settlement-table :deep(.el-table__cell) { padding: 10px 0; }
|
.pagination-bar { display: flex; align-items: center; justify-content: flex-end; gap: 18px; padding-top: 14px; color: #606266; font-size: 13px; }
|
.muted { color: #909399; }
|
.review-summary { display: grid; gap: 14px; }
|
.review-summary div { display: flex; justify-content: space-between; gap: 16px; }
|
.review-summary span { color: #909399; }
|
.review-summary strong { color: #303133; font-weight: 500; text-align: right; }
|
@media (max-width: 1280px) { .query-form { grid-template-columns: repeat(2, minmax(280px, 1fr)); } }
|
</style>
|