<template>
<a-card :bordered="false">
<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
<a-row :gutter="24">
<a-col :span="6">
<a-form-item label="名称" name="username">
<a-input v-model:value="searchFormState.username" placeholder="请输入名称" />
</a-form-item>
</a-col>
<a-col :span="6">
<a-button type="primary" @click="tableRef.refresh()">查询</a-button>
<a-button style="margin: 0 8px" @click="reset">重置</a-button>
</a-col>
</a-row>
</a-form>
<s-table
ref="tableRef"
:columns="columns"
:data="loadData"
:alert="options.alert.show"
bordered
:row-key="(record) => record.agentId"
:tool-config="toolConfig"
:row-selection="options.rowSelection"
:onChange="handleTableChange"
>
<template #operator class="table-operator">
<a-space>
<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('opsAgentAdd')">
<template #icon><plus-outlined /></template>
新增
</a-button>
<xn-batch-button
v-if="hasPerm('opsAgentBatchDelete')"
buttonName="批量删除"
icon="DeleteOutlined"
buttonDanger
:selectedRowKeys="selectedRowKeys"
@batchCallBack="deleteBatchOpsAgent"
/>
</a-space>
</template>
<template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'index'">
{{ index + 1 }}
</template>
<template v-if="column.dataIndex === 'action'">
<a-space>
<a @click="formRef.onOpen(record)" v-if="hasPerm('opsAgentEdit')">编辑</a>
<a-divider type="vertical" v-if="hasPerm(['opsAgentEdit', 'opsAgentDelete'], 'and')" />
<a-popconfirm title="确定要删除吗?" @confirm="deleteOpsAgent(record)">
<a-button type="link" danger size="small" v-if="hasPerm('opsAgentDelete')">删除</a-button>
</a-popconfirm>
</a-space>
</template>
<template v-if="column.dataIndex === 'username'">
<div style="display: flex; flex-direction: column; align-items: center">
<a-avatar :src="record.avatar">
<template #icon><UserOutlined /></template>
</a-avatar>
<div>{{ record.username }}</div>
</div>
</template>
<template v-if="column.dataIndex === 'inviterName'">
<div style="display: flex; flex-direction: column; align-items: center">
<a-avatar v-if="record.inviterId !== 0" :src="record.inviterAvatar">
<template #icon><UserOutlined /></template>
</a-avatar>
<div>{{ record.inviterName }}</div>
</div>
</template>
<template v-if="column.dataIndex === 'nearSixMonthsRevenue'">
¥{{ record.nearSixMonthsRevenue > 0 ? record.nearSixMonthsRevenue : 0.0 }}
</template>
<template v-if="column.dataIndex === 'nearMonthRevenue'">
¥{{ record.nearMonthRevenue > 0 ? record.nearMonthRevenue : 0.0 }}
</template>
<template v-if="column.dataIndex === 'nearWeekRevenue'"> ¥{{ record.nearWeekRevenue > 0 ? record.nearWeekRevenue : 0.0 }} </template>
<template v-if="column.dataIndex === 'nearThreeDaysRevenue'">
¥{{ record.nearThreeDaysRevenue > 0 ? record.nearThreeDaysRevenue : 0.0 }}
</template>
<template v-if="column.dataIndex === 'mobile'">
<div style="display: flex; align-items: center; padding: 0 2px">
<span
style="flex: 1; cursor: pointer; user-select: none"
@click="copyMobile(record.showFullMobile ? record.mobile : encryptMobile(record.mobile))"
:title="record.showFullMobile ? '点击复制完整号码' : '点击复制加密号码'"
>
{{ record.showFullMobile ? record.mobile : encryptMobile(record.mobile) }}
</span>
<a-button type="text" size="small" @click="toggleMobileDisplay(record)" style="padding: 0">
<template #icon>
<EyeInvisibleOutlined v-if="record.showFullMobile" />
<EyeOutlined v-else />
</template>
</a-button>
</div>
</template>
<template v-if="column.dataIndex === 'contract'">
<span v-if="typeof record.contract === 'string'">
<!-- 如果contract是字符串,尝试解析为JSON对象 -->
<span v-if="isValidJSON(record.contract)">
<!-- 解析成功,检查是否包含url -->
<span v-if="getContractUrl(record.contract)">
<a :href="getContractUrl(record.contract)" target="_blank" rel="noopener noreferrer">查看合同</a>
</span>
<span v-else>
<!-- 解析成功,但不包含url -->
<span>合同已上传,但无法直接查看</span>
</span>
</span>
<span v-else>
<!-- 解析失败,可能是无效的JSON字符串 -->
<span>无效的合同数据</span>
</span>
</span>
<span v-else-if="typeof record.contract === 'object' && record.contract !== null">
<!-- 如果contract是对象,直接检查是否包含url -->
<span v-if="record.contract.url">
<a :href="record.contract.url" target="_blank" rel="noopener noreferrer">查看合同</a>
</span>
<span v-else>
<!-- 对象不包含url -->
<span>合同已上传,但无法直接查看</span>
</span>
</span>
<span v-else>
<!-- contract数据为空 -->
<a-button type="link" @click="openUpload(record.agentId)">上传合同</a-button>
</span>
</template>
</template>
</s-table>
<template #empty>
<a-empty
image="https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg"
:image-style="{ height: '60px' }"
description="暂无数据"
>
<a-button type="primary" @click="tableRef.refresh()">重新加载</a-button>
</a-empty>
</template>
</a-card>
<Form ref="formRef" @successful="tableRef.refresh()" />
</template>
<script setup name="agent">
import { EyeInvisibleOutlined, EyeOutlined, UserOutlined } from '@ant-design/icons-vue'
import { cloneDeep } from 'lodash-es'
import Form from './form.vue'
import opsAgentApi from '@/api/ops/opsAgentApi'
import { message } from 'ant-design-vue'
import router from '@/router'
const tableRef = ref()
const formRef = ref()
const searchFormState = ref({})
const toolConfig = {
refresh: true,
height: true,
columnSetting: true,
striped: false,
size: 'default',
setting: {
pageSizeOptions: ['10', '20', '50', '100']
},
virtualScroll: true
}
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
width: 60,
align: 'center',
fixed: 'left'
},
{
title: '名称',
dataIndex: 'username',
width: 120,
ellipsis: true,
align: 'center'
},
{
title: '上级代理',
dataIndex: 'inviterName',
width: 120,
ellipsis: true,
align: 'center'
},
{
title: '联系方式',
dataIndex: 'mobile',
width: 150,
align: 'center'
},
{
title: '累计创收',
children: [
{ title: '近3天', dataIndex: 'nearThreeDaysRevenue', width: 100, align: 'center', sorter: true },
{ title: '近7天', dataIndex: 'nearWeekRevenue', width: 100, align: 'center', sorter: true },
{ title: '近30天', dataIndex: 'nearMonthRevenue', width: 100, align: 'center', sorter: true },
{ title: '近6个月', dataIndex: 'nearSixMonthsRevenue', width: 100, align: 'center', sorter: true }
]
},
{
title: '发展代理',
dataIndex: 'developmentAgentCount',
width: 100,
align: 'center'
},
{
title: '直接乘客',
dataIndex: 'directPassenger',
width: 100,
align: 'center'
},
{
title: '间接乘客',
dataIndex: 'indirectPassenger',
width: 100,
align: 'center'
},
{
title: '合同',
dataIndex: 'contract',
width: 100,
align: 'center'
},
{
title: '签约人',
dataIndex: 'signatory',
width: 100,
align: 'center'
}
]
// 操作栏通过权限判断是否显示
if (hasPerm(['opsAgentEdit', 'opsAgentDelete'])) {
columns.push({
title: '操作',
dataIndex: 'action',
align: 'center',
width: 150
})
}
const selectedRowKeys = ref([])
// 列表选择配置
const options = {
// columns数字类型字段加入 needTotal: true 可以勾选自动算账
alert: {
show: true,
clear: () => {
selectedRowKeys.value = ref([])
}
},
rowSelection: {
onChange: (selectedRowKey, selectedRows) => {
selectedRowKeys.value = selectedRowKey
}
}
}
const loadData = (parameter) => {
const searchFormParam = cloneDeep(searchFormState.value)
return opsAgentApi.opsFirstAgentPage(Object.assign(parameter, searchFormParam)).then((data) => {
return data
})
}
// 重置
const reset = () => {
searchFormRef.value.resetFields()
tableRef.value.refresh(true)
}
// 删除
const deleteOpsAgent = (record) => {
let params = [
{
agentId: record.agentId
}
]
opsAgentApi.opsAgentDelete(params).then(() => {
tableRef.value.refresh(true)
})
}
// 批量删除
const deleteBatchOpsAgent = (params) => {
opsAgentApi.opsAgentDelete(params).then(() => {
tableRef.value.clearRefreshSelected()
})
}
// 辅助函数:检查字符串是否为有效的JSON
function isValidJSON(str) {
try {
JSON.parse(str)
} catch (e) {
return false
}
return true
}
// 辅助函数:从JSON字符串中提取url
function getContractUrl(jsonStr) {
const contract = JSON.parse(jsonStr)
return contract.url
}
// 查看完整手机号
const toggleMobileDisplay = (record) => {
record.showFullMobile = !record.showFullMobile
}
// 复制手机号(兼容性更好的实现)
const copyMobile = (mobile) => {
if (!mobile) return
// 创建临时textarea元素
const textarea = document.createElement('textarea')
textarea.value = mobile
textarea.style.position = 'fixed'
document.body.appendChild(textarea)
textarea.select()
try {
const successful = document.execCommand('copy')
if (successful) {
message.success('手机号已复制')
} else {
message.error('复制失败,请手动复制')
}
} catch (err) {
message.error('复制失败: ' + err)
} finally {
document.body.removeChild(textarea)
}
}
// 简单的手机号加密方法
const encryptMobile = (mobile) => {
if (!mobile) return ''
// 将手机号中间四位替换为星号
return mobile.slice(0, 3) + '****' + mobile.slice(-4)
}
const openUpload = (agentId) => {
router.push({
path: '/ops/firstagent/upload',
query: {
agentId: agentId
}
})
}
// 处理表格变化事件(排序、分页、过滤)
const handleTableChange = (pagination, filters, sorter, extra) => {
// 处理排序信息
if (sorter.field) {
searchFormState.sortField = sorter.field
searchFormState.sortOrder = sorter.order === 'ascend' ? 'asc' : 'desc'
}
// 重新加载数据
loadData()
}
</script>
使用了错误的类型或对象 TypeError: onChange is not a function
(匿名) @ errorHandler.js? [sm]:27
Promise.then(异步)
nextTick @ runtime-core.esm-bundler.js:289
default @ errorHandler.js? [sm]:26
callWithErrorHandling @ runtime-core.esm-bundler.js:199
handleError @ runtime-core.esm-bundler.js:246
callWithErrorHandling @ runtime-core.esm-bundler.js:201
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:206
invoker @ runtime-dom.esm-bundler.js:729
显示另外 6 个框架
最新发布