```vue
<template>

<cl-crud ref="Crud">

<cl-row>

<!-- 刷新按钮 -->

<cl-refresh-btn />

<!-- 新增按钮 -->

<cl-add-btn />

<!-- 删除按钮 -->

<!-- <cl-multi-delete-btn /> -->

<!-- 订单类型 -->

<cl-filter label="订单类型">

<cl-select :options="options.order_type" prop="order_type" :width="120" />

</cl-filter>

<!-- 订单状态 -->

<cl-filter label="订单状态">

<cl-select :options="options.status" prop="status" :width="120" />

</cl-filter>

<cl-flex1 />

<!-- 关键字搜索 -->

<cl-search-key />

</cl-row>

  

<cl-row>

<!-- 数据表格 -->

<cl-table ref="Table">

<!-- 审批 -->

<template #slot-btn="{ scope }">

<el-button

v-permission="service.base.sys.user.permission.move"

type="primary"

size="small"

:disabled="scope.row.status !== 'PENDING'"

@click="approve(scope.row)"

>

审批

</el-button>

</template>

<template #slot-info-btn="{ scope }">

<el-button

v-permission="service.base.sys.user.permission.move"

type="text"

size="small"

:disabled="scope.row.status === 'PENDING'"

@click="viewDetail(scope.row)"

>

详情

</el-button>

</template>

</cl-table>

</cl-row>

  

<cl-row>

<cl-flex1 />

<!-- 分页控件 -->

<cl-pagination />

</cl-row>

  

<!-- 新增、编辑 -->

<cl-upsert ref="Upsert" />

  

<!-- 审批弹窗 -->

<el-dialog

v-model="dialogVisible"

title="审批详情"

width="800px"

:close-on-click-modal="false"

>

<el-form :model="form" label-width="100px">

<el-form-item label="申请编号">

<el-input v-model="form.id" disabled />

</el-form-item>

<el-form-item label="申请人">

<el-input v-model="form.mch_id" disabled />

</el-form-item>

<el-form-item label="申请时间">

<el-input v-model="form.createTime" disabled />

</el-form-item>

<el-form-item label="订单类型">

<el-tag

:type="getOrderTypeTag(form.order_type).type"

effect="light"

class="order-type-tag"

>

{{ getOrderTypeTag(form.order_type).label }}

</el-tag>

</el-form-item>

<el-form-item label="订单状态" v-if="form.order_status !== 'PENDING'">

<el-tag

:type="getStatusTag(form.order_status).type"

effect="light"

class="status-tag"

>

{{ getStatusTag(form.order_status).label }}

</el-tag>

</el-form-item>

<el-form-item label="审批意见" v-if="form.order_status !== 'PENDING'">

<el-input type="textarea" :rows="3" :value="form.remark || '无'" disabled />

</el-form-item>

<el-form-item label="订单详情">

<div class="order-info">

<template v-if="form.order_type === 'APPROVE_TRANSFER'">

<div class="payment-info">

<div class="info-section">

<div class="section-title">转账信息</div>

<div class="info-item">

<span class="label">请求ID：</span>

<span class="value">{{ orderInfo.request_id }}</span>

</div>

<div class="info-item">

<span class="label">付款账户：</span>

<span class="value">{{ orderInfo.from_account_id }}</span>

</div>

<div class="info-item">

<span class="label">收款账户：</span>

<span class="value">{{ orderInfo.to_account_id }}</span>

</div>

<div class="info-item">

<span class="label">金额：</span>

<span class="value highlight"

>{{ (orderInfo.amount / 100).toFixed(2) }}

{{ orderInfo.currency }}</span

>

</div>

<div class="info-item">

<span class="label">用途：</span>

<span class="value">{{ orderInfo.purpose }}</span>

</div>

</div>

</div>

</template>

<template v-else-if="form.order_type === 'APPROVE_PAYMENT'">

<div class="payment-info">

<div class="info-section">

<div class="section-title">基本信息</div>

<div class="info-item">

<span class="label">请求ID：</span>

<span class="value">{{ orderInfo.request_id }}</span>

</div>

<div class="info-item">

<span class="label">付款账户：</span>

<span class="value">{{ orderInfo.from_account_id }}</span>

</div>

<div class="info-item">

<span class="label">金额：</span>

<span class="value highlight"

>{{ (orderInfo.amount / 100).toFixed(2) }}

{{ orderInfo.currency }}</span

>

</div>

<div class="info-item">

<span class="label">用途：</span>

<span class="value">{{ orderInfo.purpose }}</span>

</div>

<div class="info-item">

<span class="label">备注：</span>

<span class="value">{{ orderInfo.comment }}</span>

</div>

</div>

<div class="info-section">

<div class="section-title">收款方信息</div>

<div class="info-item">

<span class="label">实体类型：</span>

<span class="value">{{

orderInfo.beneficiary.legal_entity_type

}}</span>

</div>

<div class="info-item">

<span class="label">支付类型：</span>

<span class="value">{{

orderInfo.beneficiary.payment_type

}}</span>

</div>

<div class="info-item">

<span class="label">地区：</span>

<span class="value">{{

orderInfo.beneficiary.region

}}</span>

</div>

<div class="info-item">

<span class="label">银行名称：</span>

<span class="value">{{

orderInfo.beneficiary.bank_name

}}</span>

</div>

<div class="info-item">

<span class="label">账户持有人：</span>

<span class="value">{{

orderInfo.beneficiary.account_holder_name

}}</span>

</div>

<div class="info-item">

<span class="label">账号：</span>

<span class="value">{{

orderInfo.beneficiary.account_number

}}</span>

</div>

<div class="info-item">

<span class="label">BIC号码：</span>

<span class="value">{{

orderInfo.beneficiary.bic_number

}}</span>

</div>

<div class="info-item">

<span class="label">地址：</span>

<span class="value">{{

orderInfo.beneficiary.address

}}</span>

</div>

</div>

</div>

</template>

<template v-else-if="form.order_type === 'APPROVE_DEPOSIT'">

<div class="payment-info">

<div class="info-section">

<div class="section-title">入账信息</div>

<div class="info-item">

<span class="label">请求ID：</span>

<span class="value">{{ orderInfo.request_id }}</span>

</div>

<div class="info-item">

<span class="label">收款账户：</span>

<span class="value">{{ orderInfo.to_account_id }}</span>

</div>

<div class="info-item">

<span class="label">金额：</span>

<span class="value highlight"

>{{ (orderInfo.amount / 100).toFixed(2) }}

{{ orderInfo.currency }}</span

>

</div>

<div class="info-item">

<span class="label">用途：</span>

<span class="value">{{ orderInfo.purpose }}</span>

</div>

</div>

</div>

</template>

<template v-else-if="form.order_type === 'APPROVE_EXCHANGE'">

<div class="payment-info">

<div class="info-section">

<div class="section-title">换汇信息</div>

<div class="info-item">

<span class="label">请求ID：</span>

<span class="value">{{ orderInfo.request_id }}</span>

</div>

<div class="info-item">

<span class="label">账户：</span>

<span class="value">{{ orderInfo.from_account_id }}</span>

</div>

<div class="info-item">

<span class="label">卖出币种：</span>

<span class="value">{{ orderInfo.sell_currency }}</span>

</div>

<div class="info-item">

<span class="label">买入币种：</span>

<span class="value">{{ orderInfo.buy_currency }}</span>

</div>

<div class="info-item">

<span class="label">买入金额：</span>

<span class="value highlight"

>{{ (orderInfo.buy_amount / 100).toFixed(2) }}

{{ orderInfo.buy_currency }}</span

>

</div>

<div class="info-item">

<span class="label">业务类型：</span>

<span class="value">{{ orderInfo.biz_type }}</span>

</div>

<div class="info-item" v-if="orderInfo.reference">

<span class="label">参考号：</span>

<span class="value">{{ orderInfo.reference }}</span>

</div>

</div>

</div>

</template>

<template v-else-if="form.order_type === 'APPROVE_ACCOUNT'">

<div class="payment-info">

<div class="info-section">

<div class="section-title">基础信息</div>

<div class="info-item" v-if="false">

<span class="label">请求ID：</span>

<span class="value">{{ orderInfo.request_id }}</span>

</div>

<div class="info-item">

<span class="label">商户ID：</span>

<span class="value">{{ orderInfo.legal_entity.mchId }}</span>

</div>

<div class="info-item" v-if="false">

<span class="label">实体类型：</span>

<span class="value highlight">{{ orderInfo.legal_entity.type }}</span>

</div>

<div class="info-item">

<span class="label">地区：</span>

<span class="value">{{ orderInfo.legal_entity.region }}</span>

</div>

<div class="info-item">

<span class="label">公司名称：</span>

<span class="value">{{ orderInfo.legal_entity.company_name_en }}</span>

</div>

<div class="info-item">

<span class="label">成立日期：</span>

<span class="value">{{ orderInfo.legal_entity.dob }}</span>

</div>

<div class="info-item">

<span class="label">联系电话：</span>

<span class="value">{{ orderInfo.legal_entity.phone_country }}-{{ orderInfo.legal_entity.phone }}</span>

</div>

<div class="info-item">

<span class="label">电子邮箱：</span>

<span class="value">{{ orderInfo.legal_entity.email }}</span>

</div>

<div class="info-item">

<span class="label">公司地址：</span>

<span class="value">{{ orderInfo.legal_entity.address }}</span>

</div>

<div class="info-item">

<span class="label">公司类型：</span>

<span class="value">{{ orderInfo.legal_entity.company_type }}</span>

</div>

<div class="info-item">

<span class="label">经营范围：</span>

<span class="value">{{ orderInfo.legal_entity.business_scope }}</span>

</div>

<div class="info-item">

<span class="label">所属行业：</span>

<span class="value">{{ orderInfo.legal_entity.industry }}</span>

</div>

<div class="info-item">

<span class="label">企业类型：</span>

<span class="value">{{ orderInfo.legal_entity.enterprise_type }}</span>

</div>

</div>

  

<div class="info-section">

<div class="section-title">企业证件信息</div>

<div class="info-item">

<span class="label">BR号码：</span>

<span class="value">{{ orderInfo.legal_entity.br_number }}</span>

</div>

<div class="info-item">

<span class="label">BR证书：</span>

<span class="value">

<template v-if="isImageFile(orderInfo.legal_entity.br_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(orderInfo.legal_entity.br_image) || orderInfo.legal_entity.br_image"

:preview-src-list="[imageUrlCache.get(orderInfo.legal_entity.br_image) || orderInfo.legal_entity.br_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(orderInfo.legal_entity.br_image)">

下载文件

</el-button>

</template>

</span>

</div>

<div class="info-item">

<span class="label">CR号码：</span>

<span class="value">{{ orderInfo.legal_entity.cr_number }}</span>

</div>

<div class="info-item">

<span class="label">CR证书：</span>

<span class="value">

<template v-if="isImageFile(orderInfo.legal_entity.cr_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(orderInfo.legal_entity.cr_image) || orderInfo.legal_entity.cr_image"

:preview-src-list="[imageUrlCache.get(orderInfo.legal_entity.cr_image) || orderInfo.legal_entity.cr_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(orderInfo.legal_entity.cr_image)">

下载文件

</el-button>

</template>

</span>

</div>

<div class="info-item">

<span class="label">NC1文件：</span>

<span class="value">

<div v-for="(image, index) in orderInfo.legal_entity.nc1_images" :key="index">

<template v-if="isImageFile(image)">

<el-image

style="width: 100px; height: 100px; margin-right: 10px"

:src="imageUrlCache.get(image) || image"

:preview-src-list="orderInfo.legal_entity.nc1_images.map(img => imageUrlCache.get(img) || img)"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(image)">

下载文件

</el-button>

</template>

</div>

</span>

</div>

<div class="info-item">

<span class="label">股权结构：</span>

<span class="value">

<template v-if="isImageFile(orderInfo.legal_entity.ownership_structure_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(orderInfo.legal_entity.ownership_structure_image) || orderInfo.legal_entity.ownership_structure_image"

:preview-src-list="[imageUrlCache.get(orderInfo.legal_entity.ownership_structure_image) || orderInfo.legal_entity.ownership_structure_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(orderInfo.legal_entity.ownership_structure_image)">

下载文件

</el-button>

</template>

</span>

</div>

<div class="info-item">

<span class="label">公司章程：</span>

<span class="value">

<template v-if="isImageFile(orderInfo.legal_entity.aoa)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(orderInfo.legal_entity.aoa) || orderInfo.legal_entity.aoa"

:preview-src-list="[imageUrlCache.get(orderInfo.legal_entity.aoa) || orderInfo.legal_entity.aoa]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(orderInfo.legal_entity.aoa)">

下载文件

</el-button>

</template>

</span>

</div>

</div>

  

<div class="info-section">

<div class="section-title">公司法人或董事</div>

<div class="info-item">

<span class="label">姓名：</span>

<span class="value">{{ orderInfo.legal_entity.owner.name }}</span>

</div>

<div class="info-item">

<span class="label">证件类型：</span>

<span class="value">{{ orderInfo.legal_entity.owner.id_type }}</span>

</div>

<div class="info-item">

<span class="label">证件号码：</span>

<span class="value">{{ orderInfo.legal_entity.owner.id_card_number }}</span>

</div>

<div class="info-item">

<span class="label">出生日期：</span>

<span class="value">{{ orderInfo.legal_entity.owner.dob }}</span>

</div>

<div class="info-item">

<span class="label">地址：</span>

<span class="value">{{ orderInfo.legal_entity.owner.address }}</span>

</div>

<div class="info-item">

<span class="label">证件照片：</span>

<span class="value">

<div style="display: flex; gap: 10px;">

<template v-if="isImageFile(orderInfo.legal_entity.owner.id_card_front_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(orderInfo.legal_entity.owner.id_card_front_image) || orderInfo.legal_entity.owner.id_card_front_image"

:preview-src-list="[imageUrlCache.get(orderInfo.legal_entity.owner.id_card_front_image) || orderInfo.legal_entity.owner.id_card_front_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(orderInfo.legal_entity.owner.id_card_front_image)">

下载正面照片

</el-button>

</template>

  

<template v-if="isImageFile(orderInfo.legal_entity.owner.id_card_back_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(orderInfo.legal_entity.owner.id_card_back_image) || orderInfo.legal_entity.owner.id_card_back_image"

:preview-src-list="[imageUrlCache.get(orderInfo.legal_entity.owner.id_card_back_image) || orderInfo.legal_entity.owner.id_card_back_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(orderInfo.legal_entity.owner.id_card_back_image)">

下载背面照片

</el-button>

</template>

  

<template v-if="isImageFile(orderInfo.legal_entity.owner.id_card_handheld_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(orderInfo.legal_entity.owner.id_card_handheld_image) || orderInfo.legal_entity.owner.id_card_handheld_image"

:preview-src-list="[imageUrlCache.get(orderInfo.legal_entity.owner.id_card_handheld_image) || orderInfo.legal_entity.owner.id_card_handheld_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(orderInfo.legal_entity.owner.id_card_handheld_image)">

下载手持照片

</el-button>

</template>

</div>

</span>

</div>

<div class="info-item">

<span class="label">地址证明：</span>

<span class="value">

<template v-if="isImageFile(orderInfo.legal_entity.owner.address_proof_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(orderInfo.legal_entity.owner.address_proof_image) || orderInfo.legal_entity.owner.address_proof_image"

:preview-src-list="[imageUrlCache.get(orderInfo.legal_entity.owner.address_proof_image) || orderInfo.legal_entity.owner.address_proof_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(orderInfo.legal_entity.owner.address_proof_image)">

下载地址证明

</el-button>

</template>

</span>

</div>

</div>

  

<div class="info-section" v-if="orderInfo.legal_entity.shareholders && orderInfo.legal_entity.shareholders.length > 0">

<div class="section-title">公司股份占比25%及以上的股东</div>

<div v-for="(shareholder, index) in orderInfo.legal_entity.shareholders" :key="index" class="shareholder-info">

<div class="sub-title">股东 {{ index + 1 }}</div>

<div class="info-item">

<span class="label">姓名：</span>

<span class="value">{{ shareholder.name }}</span>

</div>

<div class="info-item">

<span class="label">持股比例：</span>

<span class="value">{{ Number(shareholder.ratio) * 100 }}%</span>

</div>

<div class="info-item">

<span class="label">证件类型：</span>

<span class="value">{{ shareholder.id_type }}</span>

</div>

<div class="info-item">

<span class="label">证件号码：</span>

<span class="value">{{ shareholder.id_card_number }}</span>

</div>

<div class="info-item">

<span class="label">出生日期：</span>

<span class="value">{{ shareholder.dob }}</span>

</div>

<div class="info-item">

<span class="label">地址：</span>

<span class="value">{{ shareholder.address }}</span>

</div>

<div class="info-item">

<span class="label">证件照片：</span>

<span class="value">

<div style="display: flex; gap: 10px;">

<template v-if="isImageFile(shareholder.id_card_front_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(shareholder.id_card_front_image) || shareholder.id_card_front_image"

:preview-src-list="[imageUrlCache.get(shareholder.id_card_front_image) || shareholder.id_card_front_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(shareholder.id_card_front_image)">

下载正面照片

</el-button>

</template>

  

<template v-if="isImageFile(shareholder.id_card_back_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(shareholder.id_card_back_image) || shareholder.id_card_back_image"

:preview-src-list="[imageUrlCache.get(shareholder.id_card_back_image) || shareholder.id_card_back_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(shareholder.id_card_back_image)">

下载背面照片

</el-button>

</template>

  

<template v-if="isImageFile(shareholder.id_card_handheld_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(shareholder.id_card_handheld_image) || shareholder.id_card_handheld_image"

:preview-src-list="[imageUrlCache.get(shareholder.id_card_handheld_image) || shareholder.id_card_handheld_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(shareholder.id_card_handheld_image)">

下载手持照片

</el-button>

</template>

</div>

</span>

</div>

<div class="info-item">

<span class="label">地址证明：</span>

<span class="value">

<template v-if="isImageFile(shareholder.address_proof_image)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(shareholder.address_proof_image) || shareholder.address_proof_image"

:preview-src-list="[imageUrlCache.get(shareholder.address_proof_image) || shareholder.address_proof_image]"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(shareholder.address_proof_image)">

下载地址证明

</el-button>

</template>

</span>

</div>

</div>

</div>

</div>

</template>

<template v-else-if="form.order_type === 'APPROVE_KYC'">

<div class="payment-info">

<div class="info-section">

<div class="section-title">KYC认证信息</div>

<div class="info-item">

<span class="label">请求ID：</span>

<span class="value">{{ orderInfo.request_id }}</span>

</div>

<div class="info-item">

<span class="label">商户ID：</span>

<span class="value">{{ orderInfo.mch_id }}</span>

</div>

<div class="info-item">

<span class="label">认证类型：</span>

<span class="value highlight">{{

orderInfo.kyc_type

}}</span>

</div>

</div>

</div>

</template>

<template v-else-if="form.order_type === 'APPROVE_APPLICATIONS'">

<div class="payment-info">

<div class="info-section">

<div class="section-title">基本信息</div>

<div class="info-item">

<span class="label">请求ID：</span>

<span class="value">{{ orderInfo.request_id }}</span>

</div>

<div class="info-item">

<span class="label">商户ID：</span>

<span class="value">{{ orderInfo.mch_id }}</span>

</div>

<div class="info-item">

<span class="label">用途：</span>

<span class="value">{{ orderInfo.purpose }}</span>

</div>

<div class="info-item">

<span class="label">币种：</span>

<span class="value">{{ orderInfo.currency }}</span>

</div>

<div class="info-item">

<span class="label">支付类型：</span>

<span class="value">{{ orderInfo.payment_type }}</span>

</div>

</div>

  

<div class="info-section">

<div class="section-title">店铺信息</div>

<div class="info-item">

<span class="label">店铺名称：</span>

<span class="value">{{ orderInfo.additional_info?.store_name }}</span>

</div>

<div class="info-item">

<span class="label">店铺地址：</span>

<span class="value">

{{ orderInfo.additional_info?.store_address?.region }}

{{ orderInfo.additional_info?.store_address?.state_or_province }}

{{ orderInfo.additional_info?.store_address?.city }}

{{ orderInfo.additional_info?.store_address?.street }}

{{ orderInfo.additional_info?.store_address?.zip_code }}

</span>

</div>

<div class="info-item">

<span class="label">业务类别：</span>

<span class="value">{{ orderInfo.additional_info?.business_category }}</span>

</div>

<div class="info-item">

<span class="label">业务地区：</span>

<span class="value">{{ orderInfo.additional_info?.business_regions?.join(', ') }}</span>

</div>

</div>

  

<div class="info-section">

<div class="section-title">销售信息</div>

<div class="info-item">

<span class="label">线上销售方式：</span>

<span class="value">{{ orderInfo.additional_info?.online_sales_method }}</span>

</div>

<div class="info-item">

<span class="label">付款方：</span>

<span class="value">{{ orderInfo.additional_info?.payer_party }}</span>

</div>

<div class="info-item">

<span class="label">付款方账户：</span>

<span class="value">{{ orderInfo.additional_info?.payer_party_account }}</span>

</div>

</div>

  

<div class="info-section">

<div class="section-title">店铺照片</div>

<div class="info-item">

<span class="value">

<div style="display: flex; gap: 10px; flex-wrap: wrap;">

<template v-for="(photo, index) in orderInfo.additional_info?.store_photos" :key="index">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(photo) || photo"

:preview-src-list="orderInfo.additional_info?.store_photos?.map(p => imageUrlCache.get(p) || p)"

/>

</template>

</div>

</span>

</div>

</div>

  

<div class="info-section">

<div class="section-title">主营业务证明材料</div>

<div class="info-item">

<span class="value">

<div style="display: flex; gap: 10px; flex-wrap: wrap;">

<template v-for="(doc, index) in orderInfo.additional_info?.documents" :key="index">

<template v-if="isImageFile(doc)">

<el-image

style="width: 100px; height: 100px"

:src="imageUrlCache.get(doc) || doc"

:preview-src-list="orderInfo.additional_info?.documents?.map(d => imageUrlCache.get(d) || d)"

/>

</template>

<template v-else>

<el-button type="primary" link @click="downloadFile(doc)">

下载文件

</el-button>

</template>

</template>

</div>

</span>

</div>

</div>

</div>

</template>

</div>

</el-form-item>

<el-form-item label="审批结果" v-if="form.order_status === 'PENDING'" required>

<el-radio-group v-model="form.status">

<el-radio label="APPROVED">通过</el-radio>

<el-radio label="REJECTED">拒绝</el-radio>

</el-radio-group>

</el-form-item>

<el-form-item label="审批意见" v-if="form.order_status === 'PENDING'" required>

<el-input

type="textarea"

v-model="form.remark"

:rows="3"

placeholder="请输入审批意见"

:rules="[

{ required: true, message: '请输入审批意见', trigger: 'blur' },

{ min: 2, max: 200, message: '长度在 2 到 200 个字符', trigger: 'blur' }

]"

/>

</el-form-item>

</el-form>

<template #footer>

<div class="dialog-footer">

<el-button @click="dialogVisible = false">取 消</el-button>

<el-button

type="primary"

@click="handleSubmit"

:loading="loading"

:disabled="form.order_status !== 'PENDING'"

>确 定</el-button

>

</div>

</template>

</el-dialog>

</cl-crud>

</template>

  

<script setup lang="ts">

import { useCrud, useTable, useUpsert } from '@cool-vue/crud';

import { useCool } from '/@/cool';

import { ref, reactive, onMounted, computed } from 'vue';

import { ElMessage } from 'element-plus';

  

const { service } = useCool();

  

// 弹窗相关

const dialogVisible = ref(false);

const loading = ref(false);

const form = reactive({

id: '',

mch_id: '',

createTime: '',

order_type: '',

order_info: '',

order_status: '',

status: '',

remark: ''

});

  

const orderInfo = reactive({

request_id: '',

from_account_id: '',

to_account_id: '',

account_id: '',

currency: '',

amount: 0,

purpose: '',

comment: '',

sell_currency: '',

buy_currency: '',

buy_amount: 0,

biz_type: '',

reference: '',

mch_id: '',

account_type: '',

kyc_type: '',

payment_type: '',

additional_info: {

store_address: {

region: '',

state_or_province: '',

city: '',

street: '',

zip_code: ''

},

online_sales_method: '',

offline_sales_method: '',

website_url: '',

store_name: '',

store_photos: [] as string[],

business_category: '',

business_regions: [] as string[],

payer_party: '',

payer_party_account: '',

funds_type: '',

monthly_transaction_count: '',

monthly_transaction_amount: '',

abbreviated_company_name: '',

documents: [] as string[]

},

legal_entity: {

mchId: '',

type: '',

region: '',

name: '',

company_name_en: '',

dob: '',

gender: '',

email: '',

phone_country: '',

phone: '',

address: '',

address_en: '',

company_type: '',

business_scope: '',

industry: '',

website: '',

br_number: '',

br_image: '',

cr_number: '',

cr_image: '',

nc1_images: [] as string[],

ownership_structure_image: '',

aoa: '',

issue_date: '',

expiry_date: '',

enterprise_type: '',

owner: {

type: '',

id_type: '',

region: '',

name: '',

dob: '',

address: '',

id_card_number: '',

id_card_back_image: '',

id_card_front_image: '',

id_card_handheld_image: '',

issue_date: '',

expiry_date: '',

issue_agency: '',

address_proof_image: ''

},

shareholders: [] as Array<{

name: string;

address: string;

dob: string;

region: string;

id_type: string;

id_card_number: string;

id_card_back_image: string;

issue_date: string;

id_card_front_image: string;

expiry_date: string;

issue_agency: string;

ratio: string;

address_proof_image: string;

id_card_handheld_image: string;

type: string;

}>

},

beneficiary: {

legal_entity_type: '',

payment_type: '',

region: '',

bank_name: '',

account_holder_name: '',

account_number: '',

bic_number: '',

address: ''

}

});

  

// cl-upsert

const Upsert = useUpsert({

items: []

});

  

// 筛选选项

const options = reactive({

order_type: [

{ label: '全部', value: '' },

{ label: '支付审批', value: 'APPROVE_PAYMENT', type: 'primary' },

{ label: '转账审批', value: 'APPROVE_TRANSFER', type: 'success' },

{ label: '入账审批', value: 'APPROVE_DEPOSIT', type: 'warning' },

{ label: '换汇审批', value: 'APPROVE_EXCHANGE', type: 'info' },

{ label: '开户审批', value: 'APPROVE_ACCOUNT', type: 'danger' },

{ label: '收款账户审批', value: 'APPROVE_APPLICATIONS', type: 'danger' },

{ label: 'KYC认证审批', value: 'APPROVE_KYC', type: 'success' }

],

status: [

{ label: '全部', value: '' },

{ label: '待审批', value: 'PENDING', type: 'warning' },

{ label: '审批中', value: 'PROCESSING', type: 'primary' },

{ label: '已通过', value: 'APPROVED', type: 'success' },

{ label: '已拒绝', value: 'REJECTED', type: 'danger' },

{ label: '已取消', value: 'CANCELED', type: 'info' }

]

});

  

// cl-table

const Table = useTable({

columns: [

{

type: 'selection',

width: 60

},

{

label: '申请编号',

prop: 'id'

},

{

label: '申请人',

prop: 'mch_id'

},

{

label: '申请时间',

prop: 'createTime'

},

{

label: '订单类型',

prop: 'order_type',

width: 100,

dict: options.order_type.filter(item => item.value).map(item => ({

label: item.label,

value: item.value,

type: item.type

}))

},

{

label: '状态',

prop: 'status',

width: 100,

dict: options.status.filter(item => item.value).map(item => ({

label: item.label,

value: item.value,

type: item.type

}))

},

{

label: '审批时间',

prop: 'updateTime'

},

{

label: '操作',

type: 'op',

width: 140,

buttons: ['slot-btn', 'slot-info-btn']

}

]

});

  

// cl-crud

const Crud = useCrud(

{

service: service.api.open_order_approve

},

app => {

app.refresh();

}

);

  

// 刷新

function refresh(params?: any) {

Crud.value?.refresh(params);

}

  

// 图片URL缓存

const imageUrlCache = reactive(new Map<string, string>());

  

// 处理文件URL

async function handleFileUrl(url: string) {

if (!url) return '';

// 如果URL已经在缓存中，直接返回

if (imageUrlCache.has(url)) {

return imageUrlCache.get(url);

}

try {

const filePath = await getFilePathByUrl(url);

// 将结果存入缓存

imageUrlCache.set(url, filePath);

return filePath;

} catch (error) {

console.error('获取文件路径失败:', error);

return url;

}

}

  

// 预加载所有图片URL

async function preloadImageUrls(data: any) {

if (!data) return;

const urls: string[] = [];

// 收集所有图片URL

if (data.legal_entity) {

const { legal_entity } = data;

urls.push(

legal_entity.br_image,

legal_entity.cr_image,

legal_entity.ownership_structure_image,

legal_entity.aoa,

legal_entity.owner?.id_card_front_image,

legal_entity.owner?.id_card_back_image,

legal_entity.owner?.id_card_handheld_image,

legal_entity.owner?.address_proof_image,

...(legal_entity.nc1_images || []),

...(legal_entity.shareholders || []).flatMap((s: any) => [

s.id_card_front_image,

s.id_card_back_image,

s.id_card_handheld_image,

s.address_proof_image

])

);

}

  

// 添加店铺照片和文档的URL

if (data.additional_info) {

const { additional_info } = data;

urls.push(

...(additional_info.store_photos || []),

...(additional_info.documents || [])

);

}

// 过滤掉空值并去重

const uniqueUrls = [...new Set(urls.filter(Boolean))];

// 预加载所有URL

await Promise.all(uniqueUrls.map(url => handleFileUrl(url)));

}

  

// 修改 approve 函数

async function approve(row: any) {

// 重置表单

Object.assign(form, {

id: row.id,

mch_id: row.mch_id,

createTime: row.createTime,

order_type: row.order_type,

order_info: JSON.stringify(JSON.parse(row.order_info), null, 2),

status: '',

remark: ''

});

form.order_status = row.status;

form.remark = row.remark;

// 解析订单详情

const orderInfoData = JSON.parse(row.order_info);

Object.assign(orderInfo, orderInfoData);

// 预加载所有图片URL

await preloadImageUrls(orderInfoData);

dialogVisible.value = true;

}

  

function viewDetail(row: any) {

approve(row);

}

  

function handleSubmit() {

if (!form.status) {

ElMessage.warning('请选择审批结果');

return;

}

if (!form.remark) {

ElMessage.warning('请输入审批意见');

return;

}

loading.value = true;

service.api.open_order_approve

.approve({

id: form.id,

status: form.status,

remark: form.remark

})

.then(() => {

dialogVisible.value = false;

refresh();

ElMessage.success('审批成功');

})

.catch((err) => {

ElMessage.error(err.message || '审批失败');

})

.finally(() => {

loading.value = false;

});

}

  

// 获取订单类型标签

function getOrderTypeTag(type: string) {

const dict = {

APPROVE_PAYMENT: { label: '支付审批', type: 'primary' },

APPROVE_TRANSFER: { label: '转账审批', type: 'success' },

APPROVE_DEPOSIT: { label: '入账审批', type: 'warning' },

APPROVE_EXCHANGE: { label: '换汇审批', type: 'info' },

APPROVE_ACCOUNT: { label: '开户审批', type: 'danger' },

APPROVE_APPLICATIONS: { label: '收款账户审批', type: 'danger' },

APPROVE_KYC: { label: 'KYC认证审批', type: 'success' }

};

return dict[type] || { label: type, type: 'info' };

}

  

// 获取状态标签

function getStatusTag(status: string) {

const dict = {

PENDING: { label: '待审批', type: 'warning' },

PROCESSING: { label: '审批中', type: 'primary' },

APPROVED: { label: '已通过', type: 'success' },

REJECTED: { label: '已拒绝', type: 'danger' },

CANCELED: { label: '已取消', type: 'info' }

};

return dict[status] || { label: status, type: 'info' };

}

  

// 判断是否为图片文件

function isImageFile(url: string): boolean {

if (!url) return false;

const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'];

return imageExtensions.some(ext => url.toLowerCase().endsWith(ext));

}

  

// 获取文件名

function getFileName(url: string): string {

if (!url) return '';

return url.split('/').pop() || '';

}

  

// 获取文件路径

async function getFilePathByUrl(url: string) {

if (!url) return '';

try {

const res = await service.api.open_files.getFilePathByUrl({ url });

return res;

} catch (error) {

console.error('获取文件路径失败:', error);

return url;

}

}

  

// 下载文件

async function downloadFile(url: string) {

try {

const filePath = await getFilePathByUrl(url);

if (!filePath) {

ElMessage.error('获取文件路径失败');

return;

}

// 在新窗口打开下载链接

window.open(filePath, '_blank');

} catch (error) {

console.error('下载文件失败:', error);

ElMessage.error('下载文件失败');

}

}

</script>

  

<style scoped>

.dialog-footer {

text-align: right;

}

  

.order-info {

padding: 10px;

background-color: #f5f7fa;

border-radius: 4px;

}

  

.payment-info {

display: flex;

flex-direction: column;

gap: 16px;

}

  

.info-section {

background-color: #fff;

border-radius: 8px;

padding: 16px;

box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);

}

  

.section-title {

font-size: 16px;

font-weight: 600;

color: #303133;

margin-bottom: 16px;

padding-bottom: 8px;

border-bottom: 1px solid #ebeef5;

}

  

.info-item {

margin-bottom: 12px;

line-height: 1.6;

display: flex;

align-items: flex-start;

}

  

.info-item:last-child {

margin-bottom: 0;

}

  

.info-item .label {

color: #909399;

margin-right: 12px;

min-width: 100px;

}

  

.info-item .value {

color: #303133;

flex: 1;

}

  

.info-item .value.highlight {

color: #409eff;

font-weight: 600;

font-size: 16px;

}

  

.sub-info {

margin-top: 8px;

padding: 8px;

background-color: #fff;

border-radius: 4px;

}

  

.sub-item {

margin-bottom: 4px;

line-height: 1.5;

}

  

.sub-item:last-child {

margin-bottom: 0;

}

  

.sub-item .label {

color: #909399;

margin-right: 8px;

}

  

.sub-item .value {

color: #606266;

}

  

.order-type-tag,

.status-tag {

font-size: 14px;

padding: 0 12px;

height: 32px;

line-height: 32px;

}

</style>

```