删除多余代码
This commit is contained in:
@@ -1,476 +0,0 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<ElRow>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElInput v-model="searchQuery" placeholder="代理商名称/联系人" clearable></ElInput>
|
||||
</ElCol>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElSelect v-model="levelFilter" placeholder="代理商等级" clearable style="width: 100%">
|
||||
<ElOption label="一级代理" value="1" />
|
||||
<ElOption label="二级代理" value="2" />
|
||||
<ElOption label="三级代理" value="3" />
|
||||
</ElSelect>
|
||||
</ElCol>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton v-ripple @click="handleSearch">搜索</ElButton>
|
||||
<ElButton v-ripple @click="showDialog('add')">新增代理商</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ArtTable :data="filteredData" index row-key="id">
|
||||
<template #default>
|
||||
<ElTableColumn label="代理商名称" prop="agentName" min-width="150" />
|
||||
<ElTableColumn label="代理商编码" prop="agentCode" />
|
||||
<ElTableColumn label="等级" prop="level">
|
||||
<template #default="scope">
|
||||
<ElTag :type="getLevelTagType(scope.row.level)">
|
||||
{{ getLevelText(scope.row.level) }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="上级代理" prop="parentName" show-overflow-tooltip />
|
||||
<ElTableColumn label="联系人" prop="contactPerson" />
|
||||
<ElTableColumn label="联系电话" prop="contactPhone" />
|
||||
<ElTableColumn label="账号数量" prop="accountCount" />
|
||||
<ElTableColumn label="网卡数量" prop="simCardCount" />
|
||||
<ElTableColumn label="佣金总额" prop="totalCommission">
|
||||
<template #default="scope"> ¥{{ scope.row.totalCommission.toFixed(2) }} </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status === 'active' ? 'success' : 'info'">
|
||||
{{ scope.row.status === 'active' ? '启用' : '禁用' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="createTime" width="180" />
|
||||
<ElTableColumn fixed="right" label="操作" width="280">
|
||||
<template #default="scope">
|
||||
<el-button link @click="viewAccountList(scope.row)">账号管理</el-button>
|
||||
<el-button link @click="viewCommission(scope.row)">佣金配置</el-button>
|
||||
<el-button link @click="showDialog('edit', scope.row)">编辑</el-button>
|
||||
<el-button link @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增代理商' : '编辑代理商'"
|
||||
width="700px"
|
||||
align-center
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="代理商名称" prop="agentName">
|
||||
<ElInput v-model="form.agentName" placeholder="请输入代理商名称" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="代理商编码" prop="agentCode">
|
||||
<ElInput v-model="form.agentCode" placeholder="请输入代理商编码" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="代理商等级" prop="level">
|
||||
<ElSelect v-model="form.level" placeholder="请选择代理商等级" style="width: 100%">
|
||||
<ElOption label="一级代理" :value="1" />
|
||||
<ElOption label="二级代理" :value="2" />
|
||||
<ElOption label="三级代理" :value="3" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="上级代理" prop="parentId">
|
||||
<ElSelect
|
||||
v-model="form.parentId"
|
||||
placeholder="请选择上级代理"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="无" :value="undefined" />
|
||||
<ElOption
|
||||
v-for="agent in parentAgentOptions"
|
||||
:key="agent.id"
|
||||
:label="agent.agentName"
|
||||
:value="agent.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="联系人" prop="contactPerson">
|
||||
<ElInput v-model="form.contactPerson" placeholder="请输入联系人" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="联系电话" prop="contactPhone">
|
||||
<ElInput v-model="form.contactPhone" placeholder="请输入联系电话" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElRow :gutter="20">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="邮箱" prop="email">
|
||||
<ElInput v-model="form.email" placeholder="请输入邮箱" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem label="公司地址" prop="address">
|
||||
<ElInput v-model="form.address" placeholder="请输入公司地址" />
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<ElFormItem label="备注" prop="remark">
|
||||
<ElInput v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注信息" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态">
|
||||
<ElSwitch v-model="form.status" active-value="active" inactive-value="inactive" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 账号管理对话框 -->
|
||||
<ElDialog v-model="accountDialogVisible" title="代理商账号管理" width="900px" align-center>
|
||||
<div style="margin-bottom: 16px">
|
||||
<ElButton type="primary" size="small" @click="addSubAccount">创建子账号</ElButton>
|
||||
</div>
|
||||
<ArtTable :data="currentAgentAccounts" index>
|
||||
<template #default>
|
||||
<ElTableColumn label="账号" prop="username" />
|
||||
<ElTableColumn label="真实姓名" prop="realName" />
|
||||
<ElTableColumn label="手机号" prop="phone" />
|
||||
<ElTableColumn label="角色" prop="role" />
|
||||
<ElTableColumn label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status === 'active' ? 'success' : 'info'">
|
||||
{{ scope.row.status === 'active' ? '正常' : '禁用' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="createTime" />
|
||||
<ElTableColumn fixed="right" label="操作" width="150">
|
||||
<template #default>
|
||||
<el-button link>编辑</el-button>
|
||||
<el-button link>禁用</el-button>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 佣金配置对话框 -->
|
||||
<ElDialog v-model="commissionDialogVisible" title="佣金配置" width="600px" align-center>
|
||||
<ElForm label-width="120px">
|
||||
<ElFormItem label="佣金模式">
|
||||
<ElRadioGroup v-model="commissionForm.mode">
|
||||
<ElRadio value="fixed">固定佣金</ElRadio>
|
||||
<ElRadio value="percent">比例佣金</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="commissionForm.mode === 'fixed'" label="固定金额">
|
||||
<ElInputNumber v-model="commissionForm.fixedAmount" :min="0" :precision="2" />
|
||||
<span style="margin-left: 8px">元/笔</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="commissionForm.mode === 'percent'" label="佣金比例">
|
||||
<ElInputNumber v-model="commissionForm.percent" :min="0" :max="100" :precision="2" />
|
||||
<span style="margin-left: 8px">%</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="结算周期">
|
||||
<ElSelect v-model="commissionForm.settlementCycle" style="width: 100%">
|
||||
<ElOption label="实时结算" value="realtime" />
|
||||
<ElOption label="日结" value="daily" />
|
||||
<ElOption label="周结" value="weekly" />
|
||||
<ElOption label="月结" value="monthly" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="commissionDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="saveCommissionConfig">保存</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'AgentManagement' })
|
||||
|
||||
interface Agent {
|
||||
id?: string
|
||||
agentName: string
|
||||
agentCode: string
|
||||
level: number
|
||||
parentId?: string | null
|
||||
parentName?: string
|
||||
contactPerson: string
|
||||
contactPhone: string
|
||||
email?: string
|
||||
address?: string
|
||||
remark?: string
|
||||
accountCount?: number
|
||||
simCardCount?: number
|
||||
totalCommission?: number
|
||||
status: 'active' | 'inactive'
|
||||
createTime?: string
|
||||
}
|
||||
|
||||
// Mock 数据
|
||||
const mockData = ref<Agent[]>([
|
||||
{
|
||||
id: '1',
|
||||
agentName: '华东区总代理',
|
||||
agentCode: 'AGENT_HD_001',
|
||||
level: 1,
|
||||
parentId: null,
|
||||
parentName: '无',
|
||||
contactPerson: '张三',
|
||||
contactPhone: '13800138001',
|
||||
email: 'zhangsan@example.com',
|
||||
address: '上海市浦东新区',
|
||||
accountCount: 5,
|
||||
simCardCount: 1000,
|
||||
totalCommission: 158900.5,
|
||||
status: 'active',
|
||||
createTime: '2026-01-01 10:00:00'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
agentName: '江苏省代理',
|
||||
agentCode: 'AGENT_JS_001',
|
||||
level: 2,
|
||||
parentId: '1',
|
||||
parentName: '华东区总代理',
|
||||
contactPerson: '李四',
|
||||
contactPhone: '13800138002',
|
||||
email: 'lisi@example.com',
|
||||
address: '江苏省南京市',
|
||||
accountCount: 3,
|
||||
simCardCount: 500,
|
||||
totalCommission: 78500.0,
|
||||
status: 'active',
|
||||
createTime: '2026-01-05 11:00:00'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
agentName: '南京市代理',
|
||||
agentCode: 'AGENT_NJ_001',
|
||||
level: 3,
|
||||
parentId: '2',
|
||||
parentName: '江苏省代理',
|
||||
contactPerson: '王五',
|
||||
contactPhone: '13800138003',
|
||||
email: 'wangwu@example.com',
|
||||
address: '江苏省南京市玄武区',
|
||||
accountCount: 2,
|
||||
simCardCount: 200,
|
||||
totalCommission: 32800.0,
|
||||
status: 'active',
|
||||
createTime: '2026-01-10 12:00:00'
|
||||
}
|
||||
])
|
||||
|
||||
const searchQuery = ref('')
|
||||
const levelFilter = ref('')
|
||||
const dialogVisible = ref(false)
|
||||
const accountDialogVisible = ref(false)
|
||||
const commissionDialogVisible = ref(false)
|
||||
const dialogType = ref<'add' | 'edit'>('add')
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const form = reactive<Agent>({
|
||||
agentName: '',
|
||||
agentCode: '',
|
||||
level: 1,
|
||||
parentId: null,
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
email: '',
|
||||
address: '',
|
||||
remark: '',
|
||||
status: 'active'
|
||||
})
|
||||
|
||||
const commissionForm = reactive({
|
||||
mode: 'fixed',
|
||||
fixedAmount: 10,
|
||||
percent: 5,
|
||||
settlementCycle: 'monthly'
|
||||
})
|
||||
|
||||
const currentAgentAccounts = ref([
|
||||
{
|
||||
username: 'agent001',
|
||||
realName: '张三',
|
||||
phone: '13800138001',
|
||||
role: '管理员',
|
||||
status: 'active',
|
||||
createTime: '2026-01-01 10:00:00'
|
||||
}
|
||||
])
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
agentName: [{ required: true, message: '请输入代理商名称', trigger: 'blur' }],
|
||||
agentCode: [{ required: true, message: '请输入代理商编码', trigger: 'blur' }],
|
||||
level: [{ required: true, message: '请选择代理商等级', trigger: 'change' }],
|
||||
contactPerson: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
|
||||
contactPhone: [
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
|
||||
const parentAgentOptions = computed(() => {
|
||||
return mockData.value.filter((item) => item.level < form.level)
|
||||
})
|
||||
|
||||
const filteredData = computed(() => {
|
||||
let data = mockData.value
|
||||
if (searchQuery.value) {
|
||||
data = data.filter(
|
||||
(item) =>
|
||||
item.agentName.includes(searchQuery.value) ||
|
||||
item.contactPerson.includes(searchQuery.value)
|
||||
)
|
||||
}
|
||||
if (levelFilter.value) {
|
||||
data = data.filter((item) => item.level === parseInt(levelFilter.value))
|
||||
}
|
||||
return data
|
||||
})
|
||||
|
||||
const getLevelText = (level: number) => {
|
||||
const levelMap: Record<number, string> = { 1: '一级代理', 2: '二级代理', 3: '三级代理' }
|
||||
return levelMap[level] || '未知'
|
||||
}
|
||||
|
||||
const getLevelTagType = (level: number) => {
|
||||
const typeMap: Record<number, string> = { 1: 'primary', 2: 'success', 3: 'warning' }
|
||||
return typeMap[level] || 'info'
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
// 搜索逻辑已通过 computed 实现
|
||||
}
|
||||
|
||||
const showDialog = (type: 'add' | 'edit', row?: Agent) => {
|
||||
dialogType.value = type
|
||||
dialogVisible.value = true
|
||||
|
||||
if (type === 'edit' && row) {
|
||||
Object.assign(form, row)
|
||||
} else {
|
||||
resetForm()
|
||||
}
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
Object.assign(form, {
|
||||
agentName: '',
|
||||
agentCode: '',
|
||||
level: 1,
|
||||
parentId: null,
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
email: '',
|
||||
address: '',
|
||||
remark: '',
|
||||
status: 'active'
|
||||
})
|
||||
}
|
||||
|
||||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
if (dialogType.value === 'add') {
|
||||
const parentAgent = mockData.value.find((item) => item.id === form.parentId)
|
||||
mockData.value.push({
|
||||
...form,
|
||||
id: Date.now().toString(),
|
||||
parentName: parentAgent ? parentAgent.agentName : '无',
|
||||
accountCount: 0,
|
||||
simCardCount: 0,
|
||||
totalCommission: 0,
|
||||
createTime: new Date().toLocaleString('zh-CN')
|
||||
})
|
||||
ElMessage.success('新增成功')
|
||||
} else {
|
||||
const index = mockData.value.findIndex((item) => item.id === form.id)
|
||||
if (index !== -1) {
|
||||
const parentAgent = mockData.value.find((item) => item.id === form.parentId)
|
||||
mockData.value[index] = {
|
||||
...form,
|
||||
parentName: parentAgent ? parentAgent.agentName : '无'
|
||||
}
|
||||
}
|
||||
ElMessage.success('修改成功')
|
||||
}
|
||||
dialogVisible.value = false
|
||||
formEl.resetFields()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleDelete = (row: Agent) => {
|
||||
ElMessageBox.confirm('确定删除该代理商吗?删除后其下属代理商和账号也将被删除。', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(() => {
|
||||
const index = mockData.value.findIndex((item) => item.id === row.id)
|
||||
if (index !== -1) {
|
||||
mockData.value.splice(index, 1)
|
||||
}
|
||||
ElMessage.success('删除成功')
|
||||
})
|
||||
}
|
||||
|
||||
const viewAccountList = (row: Agent) => {
|
||||
accountDialogVisible.value = true
|
||||
// 实际应用中应该根据代理商ID加载账号列表
|
||||
console.log(row)
|
||||
}
|
||||
|
||||
const viewCommission = (row: Agent) => {
|
||||
commissionDialogVisible.value = true
|
||||
// 实际应用中应该根据代理商ID加载佣金配置
|
||||
console.log(row)
|
||||
}
|
||||
|
||||
const addSubAccount = () => {
|
||||
ElMessage.info('创建子账号功能')
|
||||
}
|
||||
|
||||
const saveCommissionConfig = () => {
|
||||
ElMessage.success('佣金配置保存成功')
|
||||
commissionDialogVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
// 自定义样式
|
||||
}
|
||||
</style>
|
||||
@@ -1,457 +0,0 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<!-- 统计卡片 -->
|
||||
<ElRow :gutter="20" style="margin-bottom: 20px">
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElCard shadow="hover" class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">客户总数</div>
|
||||
<div class="stat-value">{{ statistics.totalCustomers }}</div>
|
||||
</div>
|
||||
<el-icon class="stat-icon" style="color: var(--el-color-primary)"><User /></el-icon>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElCard shadow="hover" class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">累计佣金</div>
|
||||
<div class="stat-value" style="color: var(--el-color-success)">
|
||||
¥{{ statistics.totalCommission.toFixed(2) }}
|
||||
</div>
|
||||
</div>
|
||||
<el-icon class="stat-icon" style="color: var(--el-color-success)"><Money /></el-icon>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElCard shadow="hover" class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">已提现</div>
|
||||
<div class="stat-value" style="color: var(--el-color-warning)">
|
||||
¥{{ statistics.totalWithdrawn.toFixed(2) }}
|
||||
</div>
|
||||
</div>
|
||||
<el-icon class="stat-icon" style="color: var(--el-color-warning)"
|
||||
><WalletFilled
|
||||
/></el-icon>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElCard shadow="hover" class="stat-card">
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">待提现</div>
|
||||
<div class="stat-value" style="color: var(--el-color-danger)">
|
||||
¥{{ statistics.pendingWithdrawal.toFixed(2) }}
|
||||
</div>
|
||||
</div>
|
||||
<el-icon class="stat-icon" style="color: var(--el-color-danger)"><Wallet /></el-icon>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<!-- 搜索和筛选区 -->
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElInput v-model="searchQuery" placeholder="客户名称/手机号" clearable />
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElSelect v-model="customerTypeFilter" placeholder="客户类型" clearable style="width: 100%">
|
||||
<ElOption label="全部" value="" />
|
||||
<ElOption label="代理商" value="agent" />
|
||||
<ElOption label="企业客户" value="enterprise" />
|
||||
</ElSelect>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElSelect
|
||||
v-model="commissionRangeFilter"
|
||||
placeholder="佣金范围"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption label="全部" value="" />
|
||||
<ElOption label="0-1000元" value="0-1000" />
|
||||
<ElOption label="1000-5000元" value="1000-5000" />
|
||||
<ElOption label="5000-10000元" value="5000-10000" />
|
||||
<ElOption label="10000元以上" value="10000+" />
|
||||
</ElSelect>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton v-ripple @click="handleSearch">搜索</ElButton>
|
||||
<ElButton v-ripple @click="exportData">导出</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<!-- 客户佣金列表 -->
|
||||
<ArtTable :data="filteredData" index style="margin-top: 20px">
|
||||
<template #default>
|
||||
<ElTableColumn label="客户名称" prop="customerName" min-width="150" show-overflow-tooltip />
|
||||
<ElTableColumn label="客户类型" prop="customerType" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.customerType === 'agent' ? 'warning' : 'primary'">
|
||||
{{ scope.row.customerType === 'agent' ? '代理商' : '企业客户' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="联系电话" prop="phone" width="130" />
|
||||
<ElTableColumn label="累计佣金" prop="totalCommission" width="130" sortable>
|
||||
<template #default="scope">
|
||||
<span style="font-weight: 600; color: var(--el-color-success)">
|
||||
¥{{ scope.row.totalCommission.toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="已提现" prop="withdrawnAmount" width="130" sortable>
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-warning)">
|
||||
¥{{ scope.row.withdrawnAmount.toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="待提现" prop="pendingAmount" width="130" sortable>
|
||||
<template #default="scope">
|
||||
<span style="font-weight: 600; color: var(--el-color-danger)">
|
||||
¥{{ scope.row.pendingAmount.toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="提现次数" prop="withdrawalCount" width="100" align="center" />
|
||||
<ElTableColumn label="卡片数量" prop="cardCount" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-primary)">{{ scope.row.cardCount }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="最近提现" prop="lastWithdrawalTime" width="180" />
|
||||
<ElTableColumn label="注册时间" prop="registerTime" width="180" />
|
||||
<ElTableColumn fixed="right" label="操作" width="220">
|
||||
<template #default="scope">
|
||||
<el-button link :icon="View" @click="viewCommissionDetail(scope.row)"
|
||||
>佣金详情</el-button
|
||||
>
|
||||
<el-button link :icon="List" @click="viewWithdrawalHistory(scope.row)"
|
||||
>提现记录</el-button
|
||||
>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 佣金详情对话框 -->
|
||||
<ElDialog v-model="commissionDialogVisible" title="佣金详情" width="900px" align-center>
|
||||
<ElDescriptions :column="2" border style="margin-bottom: 20px">
|
||||
<ElDescriptionsItem label="客户名称">{{ currentCustomer.customerName }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="客户类型">
|
||||
<ElTag :type="currentCustomer.customerType === 'agent' ? 'warning' : 'primary'">
|
||||
{{ currentCustomer.customerType === 'agent' ? '代理商' : '企业客户' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="累计佣金">
|
||||
<span style="font-weight: 600; color: var(--el-color-success)">
|
||||
¥{{ currentCustomer.totalCommission.toFixed(2) }}
|
||||
</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="已提现">
|
||||
<span style="color: var(--el-color-warning)">
|
||||
¥{{ currentCustomer.withdrawnAmount.toFixed(2) }}
|
||||
</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="待提现">
|
||||
<span style="font-weight: 600; color: var(--el-color-danger)">
|
||||
¥{{ currentCustomer.pendingAmount.toFixed(2) }}
|
||||
</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="提现次数">{{
|
||||
currentCustomer.withdrawalCount
|
||||
}}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
|
||||
<ElDivider content-position="left">佣金明细</ElDivider>
|
||||
<ArtTable :data="commissionDetails" index>
|
||||
<template #default>
|
||||
<ElTableColumn label="来源" prop="source" width="120" />
|
||||
<ElTableColumn label="订单号" prop="orderNo" width="180" />
|
||||
<ElTableColumn label="佣金金额" prop="amount" width="120">
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-success)"
|
||||
>+¥{{ scope.row.amount.toFixed(2) }}</span
|
||||
>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="佣金比例" prop="rate" width="100" />
|
||||
<ElTableColumn label="订单金额" prop="orderAmount" width="120" />
|
||||
<ElTableColumn label="获得时间" prop="createTime" width="180" />
|
||||
<ElTableColumn label="状态" prop="status" width="100">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.status === 'completed'" type="success">已结算</ElTag>
|
||||
<ElTag v-else-if="scope.row.status === 'pending'" type="warning">待结算</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<template #footer>
|
||||
<ElButton @click="commissionDialogVisible = false">关闭</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 提现记录对话框 -->
|
||||
<ElDialog v-model="withdrawalDialogVisible" title="提现记录" width="900px" align-center>
|
||||
<ArtTable :data="withdrawalHistory" index>
|
||||
<template #default>
|
||||
<ElTableColumn label="提现单号" prop="withdrawalNo" width="180" />
|
||||
<ElTableColumn label="提现金额" prop="amount" width="120">
|
||||
<template #default="scope">
|
||||
<span style="font-weight: 600; color: var(--el-color-danger)">
|
||||
¥{{ scope.row.amount.toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="手续费" prop="fee" width="100">
|
||||
<template #default="scope"> ¥{{ scope.row.fee.toFixed(2) }} </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="实际到账" prop="actualAmount" width="120">
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-success)">
|
||||
¥{{ scope.row.actualAmount.toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="提现方式" prop="method" width="100" />
|
||||
<ElTableColumn label="状态" prop="status" width="100">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.status === 'completed'" type="success">已完成</ElTag>
|
||||
<ElTag v-else-if="scope.row.status === 'processing'" type="warning">处理中</ElTag>
|
||||
<ElTag v-else-if="scope.row.status === 'pending'" type="info">待审核</ElTag>
|
||||
<ElTag v-else type="danger">已拒绝</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="申请时间" prop="applyTime" width="180" />
|
||||
<ElTableColumn label="完成时间" prop="completeTime" width="180">
|
||||
<template #default="scope">
|
||||
{{ scope.row.completeTime || '-' }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<template #footer>
|
||||
<ElButton @click="withdrawalDialogVisible = false">关闭</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { View, List, User, Money, WalletFilled, Wallet } from '@element-plus/icons-vue'
|
||||
|
||||
defineOptions({ name: 'CustomerCommission' })
|
||||
|
||||
interface CustomerCommission {
|
||||
id: string
|
||||
customerName: string
|
||||
customerType: 'agent' | 'enterprise'
|
||||
phone: string
|
||||
totalCommission: number
|
||||
withdrawnAmount: number
|
||||
pendingAmount: number
|
||||
withdrawalCount: number
|
||||
cardCount: number
|
||||
lastWithdrawalTime: string
|
||||
registerTime: string
|
||||
}
|
||||
|
||||
const searchQuery = ref('')
|
||||
const customerTypeFilter = ref('')
|
||||
const commissionRangeFilter = ref('')
|
||||
const commissionDialogVisible = ref(false)
|
||||
const withdrawalDialogVisible = ref(false)
|
||||
|
||||
const statistics = reactive({
|
||||
totalCustomers: 156,
|
||||
totalCommission: 580000.0,
|
||||
totalWithdrawn: 420000.0,
|
||||
pendingWithdrawal: 160000.0
|
||||
})
|
||||
|
||||
const mockData = ref<CustomerCommission[]>([
|
||||
{
|
||||
id: '1',
|
||||
customerName: '华东区总代理',
|
||||
customerType: 'agent',
|
||||
phone: '13800138000',
|
||||
totalCommission: 85000.0,
|
||||
withdrawnAmount: 70000.0,
|
||||
pendingAmount: 15000.0,
|
||||
withdrawalCount: 12,
|
||||
cardCount: 500,
|
||||
lastWithdrawalTime: '2026-01-08 10:00:00',
|
||||
registerTime: '2025-06-01 09:00:00'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
customerName: '深圳市科技有限公司',
|
||||
customerType: 'enterprise',
|
||||
phone: '13900139000',
|
||||
totalCommission: 45000.0,
|
||||
withdrawnAmount: 30000.0,
|
||||
pendingAmount: 15000.0,
|
||||
withdrawalCount: 8,
|
||||
cardCount: 300,
|
||||
lastWithdrawalTime: '2026-01-05 14:30:00',
|
||||
registerTime: '2025-07-15 10:00:00'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
customerName: '北京智能制造',
|
||||
customerType: 'enterprise',
|
||||
phone: '13700137000',
|
||||
totalCommission: 68000.0,
|
||||
withdrawnAmount: 55000.0,
|
||||
pendingAmount: 13000.0,
|
||||
withdrawalCount: 10,
|
||||
cardCount: 450,
|
||||
lastWithdrawalTime: '2026-01-07 16:00:00',
|
||||
registerTime: '2025-08-20 11:00:00'
|
||||
}
|
||||
])
|
||||
|
||||
const currentCustomer = ref<CustomerCommission>({
|
||||
id: '',
|
||||
customerName: '',
|
||||
customerType: 'agent',
|
||||
phone: '',
|
||||
totalCommission: 0,
|
||||
withdrawnAmount: 0,
|
||||
pendingAmount: 0,
|
||||
withdrawalCount: 0,
|
||||
cardCount: 0,
|
||||
lastWithdrawalTime: '',
|
||||
registerTime: ''
|
||||
})
|
||||
|
||||
const commissionDetails = ref([
|
||||
{
|
||||
id: '1',
|
||||
source: '套餐销售',
|
||||
orderNo: 'ORD202601090001',
|
||||
amount: 150.0,
|
||||
rate: '10%',
|
||||
orderAmount: '¥1,500.00',
|
||||
createTime: '2026-01-09 09:30:00',
|
||||
status: 'completed'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
source: '卡片激活',
|
||||
orderNo: 'ORD202601080025',
|
||||
amount: 80.0,
|
||||
rate: '8%',
|
||||
orderAmount: '¥1,000.00',
|
||||
createTime: '2026-01-08 15:20:00',
|
||||
status: 'completed'
|
||||
}
|
||||
])
|
||||
|
||||
const withdrawalHistory = ref([
|
||||
{
|
||||
id: '1',
|
||||
withdrawalNo: 'WD202601080001',
|
||||
amount: 10000.0,
|
||||
fee: 20.0,
|
||||
actualAmount: 9980.0,
|
||||
method: '银行卡',
|
||||
status: 'completed',
|
||||
applyTime: '2026-01-08 10:00:00',
|
||||
completeTime: '2026-01-08 15:30:00'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
withdrawalNo: 'WD202601050002',
|
||||
amount: 5000.0,
|
||||
fee: 10.0,
|
||||
actualAmount: 4990.0,
|
||||
method: '支付宝',
|
||||
status: 'completed',
|
||||
applyTime: '2026-01-05 14:00:00',
|
||||
completeTime: '2026-01-05 18:20:00'
|
||||
}
|
||||
])
|
||||
|
||||
const filteredData = computed(() => {
|
||||
let data = mockData.value
|
||||
|
||||
if (searchQuery.value) {
|
||||
data = data.filter(
|
||||
(item) =>
|
||||
item.customerName.includes(searchQuery.value) || item.phone.includes(searchQuery.value)
|
||||
)
|
||||
}
|
||||
|
||||
if (customerTypeFilter.value) {
|
||||
data = data.filter((item) => item.customerType === customerTypeFilter.value)
|
||||
}
|
||||
|
||||
if (commissionRangeFilter.value) {
|
||||
data = data.filter((item) => {
|
||||
const commission = item.totalCommission
|
||||
if (commissionRangeFilter.value === '0-1000') return commission >= 0 && commission < 1000
|
||||
if (commissionRangeFilter.value === '1000-5000')
|
||||
return commission >= 1000 && commission < 5000
|
||||
if (commissionRangeFilter.value === '5000-10000')
|
||||
return commission >= 5000 && commission < 10000
|
||||
if (commissionRangeFilter.value === '10000+') return commission >= 10000
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
return data
|
||||
})
|
||||
|
||||
const handleSearch = () => {}
|
||||
|
||||
const exportData = () => {
|
||||
ElMessage.success('数据导出中...')
|
||||
}
|
||||
|
||||
const viewCommissionDetail = (row: CustomerCommission) => {
|
||||
currentCustomer.value = { ...row }
|
||||
commissionDialogVisible.value = true
|
||||
}
|
||||
|
||||
const viewWithdrawalHistory = (row: CustomerCommission) => {
|
||||
currentCustomer.value = { ...row }
|
||||
withdrawalDialogVisible.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
.stat-card {
|
||||
:deep(.el-card__body) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
.stat-label {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
font-size: 40px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,253 +0,0 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<ElRow>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElInput v-model="searchQuery" placeholder="角色名称" clearable></ElInput>
|
||||
</ElCol>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton v-ripple @click="handleSearch">搜索</ElButton>
|
||||
<ElButton v-ripple @click="showDialog('add')">新增角色</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ArtTable :data="filteredData" index>
|
||||
<template #default>
|
||||
<ElTableColumn label="角色名称" prop="roleName" />
|
||||
<ElTableColumn label="角色编码" prop="roleCode" />
|
||||
<ElTableColumn label="能力边界" prop="abilities">
|
||||
<template #default="scope">
|
||||
<ElTag
|
||||
v-for="(ability, index) in scope.row.abilities"
|
||||
:key="index"
|
||||
size="small"
|
||||
style="margin-right: 4px"
|
||||
>
|
||||
{{ ability }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="描述" prop="description" show-overflow-tooltip />
|
||||
<ElTableColumn label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status === 'active' ? 'success' : 'info'">
|
||||
{{ scope.row.status === 'active' ? '启用' : '禁用' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="创建时间" prop="createTime" width="180" />
|
||||
<ElTableColumn fixed="right" label="操作" width="180">
|
||||
<template #default="scope">
|
||||
<el-button link @click="showDialog('edit', scope.row)">编辑</el-button>
|
||||
<el-button link @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增客户角色' : '编辑客户角色'"
|
||||
width="600px"
|
||||
align-center
|
||||
>
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||
<ElFormItem label="角色名称" prop="roleName">
|
||||
<ElInput v-model="form.roleName" placeholder="请输入角色名称" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="角色编码" prop="roleCode">
|
||||
<ElInput v-model="form.roleCode" placeholder="请输入角色编码" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="能力边界" prop="abilities">
|
||||
<ElCheckboxGroup v-model="form.abilities">
|
||||
<ElCheckbox label="查看网卡">查看网卡</ElCheckbox>
|
||||
<ElCheckbox label="操作网卡">操作网卡</ElCheckbox>
|
||||
<ElCheckbox label="查看套餐">查看套餐</ElCheckbox>
|
||||
<ElCheckbox label="购买套餐">购买套餐</ElCheckbox>
|
||||
<ElCheckbox label="查看设备">查看设备</ElCheckbox>
|
||||
<ElCheckbox label="管理设备">管理设备</ElCheckbox>
|
||||
<ElCheckbox label="查看佣金">查看佣金</ElCheckbox>
|
||||
<ElCheckbox label="提现佣金">提现佣金</ElCheckbox>
|
||||
</ElCheckboxGroup>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="描述" prop="description">
|
||||
<ElInput
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入角色描述"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="状态">
|
||||
<ElSwitch v-model="form.status" active-value="active" inactive-value="inactive" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'CustomerRole' })
|
||||
|
||||
interface CustomerRole {
|
||||
id?: string
|
||||
roleName: string
|
||||
roleCode: string
|
||||
abilities: string[]
|
||||
description: string
|
||||
status: 'active' | 'inactive'
|
||||
createTime?: string
|
||||
}
|
||||
|
||||
// Mock 数据
|
||||
const mockData = ref<CustomerRole[]>([
|
||||
{
|
||||
id: '1',
|
||||
roleName: '标准客户',
|
||||
roleCode: 'CUSTOMER_STANDARD',
|
||||
abilities: ['查看网卡', '查看套餐', '查看设备'],
|
||||
description: '标准客户角色,拥有基本查看权限',
|
||||
status: 'active',
|
||||
createTime: '2026-01-01 10:00:00'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
roleName: 'VIP客户',
|
||||
roleCode: 'CUSTOMER_VIP',
|
||||
abilities: ['查看网卡', '操作网卡', '查看套餐', '购买套餐', '查看设备', '管理设备'],
|
||||
description: 'VIP客户角色,拥有更多操作权限',
|
||||
status: 'active',
|
||||
createTime: '2026-01-02 11:00:00'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
roleName: '企业客户',
|
||||
roleCode: 'CUSTOMER_ENTERPRISE',
|
||||
abilities: [
|
||||
'查看网卡',
|
||||
'操作网卡',
|
||||
'查看套餐',
|
||||
'购买套餐',
|
||||
'查看设备',
|
||||
'管理设备',
|
||||
'查看佣金'
|
||||
],
|
||||
description: '企业客户角色,拥有完整业务权限',
|
||||
status: 'active',
|
||||
createTime: '2026-01-03 12:00:00'
|
||||
}
|
||||
])
|
||||
|
||||
const searchQuery = ref('')
|
||||
const dialogVisible = ref(false)
|
||||
const dialogType = ref<'add' | 'edit'>('add')
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const form = reactive<CustomerRole>({
|
||||
roleName: '',
|
||||
roleCode: '',
|
||||
abilities: [],
|
||||
description: '',
|
||||
status: 'active'
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
roleName: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
|
||||
roleCode: [{ required: true, message: '请输入角色编码', trigger: 'blur' }],
|
||||
abilities: [{ required: true, message: '请至少选择一项能力', trigger: 'change' }]
|
||||
})
|
||||
|
||||
const filteredData = computed(() => {
|
||||
if (!searchQuery.value) return mockData.value
|
||||
return mockData.value.filter((item) =>
|
||||
item.roleName.toLowerCase().includes(searchQuery.value.toLowerCase())
|
||||
)
|
||||
})
|
||||
|
||||
const handleSearch = () => {
|
||||
// 搜索逻辑已通过 computed 实现
|
||||
}
|
||||
|
||||
const showDialog = (type: 'add' | 'edit', row?: CustomerRole) => {
|
||||
dialogType.value = type
|
||||
dialogVisible.value = true
|
||||
|
||||
if (type === 'edit' && row) {
|
||||
form.id = row.id
|
||||
form.roleName = row.roleName
|
||||
form.roleCode = row.roleCode
|
||||
form.abilities = [...row.abilities]
|
||||
form.description = row.description
|
||||
form.status = row.status
|
||||
} else {
|
||||
resetForm()
|
||||
}
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
form.id = undefined
|
||||
form.roleName = ''
|
||||
form.roleCode = ''
|
||||
form.abilities = []
|
||||
form.description = ''
|
||||
form.status = 'active'
|
||||
}
|
||||
|
||||
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
if (dialogType.value === 'add') {
|
||||
mockData.value.push({
|
||||
...form,
|
||||
id: Date.now().toString(),
|
||||
createTime: new Date().toLocaleString('zh-CN')
|
||||
})
|
||||
ElMessage.success('新增成功')
|
||||
} else {
|
||||
const index = mockData.value.findIndex((item) => item.id === form.id)
|
||||
if (index !== -1) {
|
||||
mockData.value[index] = { ...form }
|
||||
}
|
||||
ElMessage.success('修改成功')
|
||||
}
|
||||
dialogVisible.value = false
|
||||
formEl.resetFields()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleDelete = (row: CustomerRole) => {
|
||||
ElMessageBox.confirm('确定删除该客户角色吗?', '删除确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'error'
|
||||
}).then(() => {
|
||||
const index = mockData.value.findIndex((item) => item.id === row.id)
|
||||
if (index !== -1) {
|
||||
mockData.value.splice(index, 1)
|
||||
}
|
||||
ElMessage.success('删除成功')
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
:deep(.el-checkbox) {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,359 +0,0 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="customer-management-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="formFilters"
|
||||
:items="formItems"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<ElCard shadow="never" class="art-table-card">
|
||||
<!-- 表格头部 -->
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #left>
|
||||
<ElButton type="primary" @click="handleSearch">查询</ElButton>
|
||||
<ElButton @click="exportExcel">导出excel</ElButton>
|
||||
</template>
|
||||
</ArtTableHeader>
|
||||
|
||||
<!-- 表格 -->
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
@selection-change="handleSelectionChange"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import { SearchChangeParams, SearchFormItem } from '@/types'
|
||||
|
||||
defineOptions({ name: 'CustomerManagement' })
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
distributorName: '',
|
||||
distributorAccount: ''
|
||||
}
|
||||
|
||||
// 响应式表单数据
|
||||
const formFilters = reactive({ ...initialSearchState })
|
||||
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref<any[]>([])
|
||||
|
||||
// 表格实例引用
|
||||
const tableRef = ref()
|
||||
|
||||
// 选中的行数据
|
||||
const selectedRows = ref<any[]>([])
|
||||
|
||||
// 模拟数据 - 客户管理(代理商)
|
||||
const mockData = [
|
||||
{
|
||||
id: 1,
|
||||
distributorName: '北京优享科技有限公司',
|
||||
distributorAccount: 'bjyx2024',
|
||||
totalCommission: 12560.8,
|
||||
instantCommission: 8320.5,
|
||||
pendingCommission: 4240.3,
|
||||
prepaidCommission: 2400.0,
|
||||
withdrawnCommission: 6800.2,
|
||||
withdrawingCommission: 1520.3,
|
||||
availableCommission: 2000.0
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
distributorName: '上海智联通信技术公司',
|
||||
distributorAccount: 'shzl2024',
|
||||
totalCommission: 18750.25,
|
||||
instantCommission: 12500.75,
|
||||
pendingCommission: 6249.5,
|
||||
prepaidCommission: 3600.0,
|
||||
withdrawnCommission: 8900.25,
|
||||
withdrawingCommission: 2100.0,
|
||||
availableCommission: 3750.0
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
distributorName: '广州物联网络有限公司',
|
||||
distributorAccount: 'gzwl2024',
|
||||
totalCommission: 9876.4,
|
||||
instantCommission: 6584.3,
|
||||
pendingCommission: 3292.1,
|
||||
prepaidCommission: 1800.0,
|
||||
withdrawnCommission: 4938.2,
|
||||
withdrawingCommission: 980.2,
|
||||
availableCommission: 1958.0
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
distributorName: '深圳云联科技股份公司',
|
||||
distributorAccount: 'szyl2024',
|
||||
totalCommission: 24500.6,
|
||||
instantCommission: 16333.73,
|
||||
pendingCommission: 8166.87,
|
||||
prepaidCommission: 4800.0,
|
||||
withdrawnCommission: 11225.3,
|
||||
withdrawingCommission: 2450.06,
|
||||
availableCommission: 4900.12
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
distributorName: '杭州通达网络服务公司',
|
||||
distributorAccount: 'hztd2024',
|
||||
totalCommission: 15200.35,
|
||||
instantCommission: 10133.57,
|
||||
pendingCommission: 5066.78,
|
||||
prepaidCommission: 2900.0,
|
||||
withdrawnCommission: 7600.18,
|
||||
withdrawingCommission: 1520.04,
|
||||
availableCommission: 3040.07
|
||||
}
|
||||
]
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(formFilters, { ...initialSearchState })
|
||||
pagination.currentPage = 1
|
||||
getCustomerList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', formFilters)
|
||||
pagination.currentPage = 1
|
||||
getCustomerList()
|
||||
}
|
||||
|
||||
// 表单项变更处理
|
||||
const handleFormChange = (params: SearchChangeParams): void => {
|
||||
console.log('表单项变更:', params)
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const formItems: SearchFormItem[] = [
|
||||
{
|
||||
label: '代理商名称',
|
||||
prop: 'distributorName',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入代理商名称'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
},
|
||||
{
|
||||
label: '代理商账号',
|
||||
prop: 'distributorAccount',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入代理商账号'
|
||||
},
|
||||
onChange: handleFormChange
|
||||
}
|
||||
]
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: '勾选', type: 'selection' },
|
||||
{ label: '代理商名称', prop: 'distributorName' },
|
||||
{ label: '代理商账号', prop: 'distributorAccount' },
|
||||
{ label: '总佣金', prop: 'totalCommission' },
|
||||
{ label: '已秒返佣金', prop: 'instantCommission' },
|
||||
{ label: '未秒返佣金', prop: 'pendingCommission' },
|
||||
{ label: '预存佣金', prop: 'prepaidCommission' },
|
||||
{ label: '已提现佣金', prop: 'withdrawnCommission' },
|
||||
{ label: '提现中佣金', prop: 'withdrawingCommission' },
|
||||
{ label: '可提现佣金', prop: 'availableCommission' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 导出Excel
|
||||
const exportExcel = () => {
|
||||
if (selectedRows.value.length === 0) {
|
||||
ElMessage.warning('请先选择要导出的数据')
|
||||
return
|
||||
}
|
||||
ElMessage.success(`导出 ${selectedRows.value.length} 条客户记录`)
|
||||
}
|
||||
|
||||
// 查看提现详情
|
||||
const viewWithdrawDetail = (row: any) => {
|
||||
ElMessage.info(`查看 ${row.distributorName} 的提现详情`)
|
||||
}
|
||||
|
||||
// 查看佣金明细
|
||||
const viewCommissionDetail = (row: any) => {
|
||||
ElMessage.info(`查看 ${row.distributorName} 的佣金明细`)
|
||||
}
|
||||
|
||||
// 查看自动提现详情
|
||||
const viewAutoWithdrawDetail = (row: any) => {
|
||||
ElMessage.info(`查看 ${row.distributorName} 的自动提现详情`)
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
prop: 'distributorName',
|
||||
label: '代理商名称',
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
prop: 'distributorAccount',
|
||||
label: '代理商账号',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
prop: 'totalCommission',
|
||||
label: '总佣金',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.totalCommission.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'instantCommission',
|
||||
label: '已秒返佣金',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.instantCommission.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'pendingCommission',
|
||||
label: '未秒返佣金',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.pendingCommission.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'prepaidCommission',
|
||||
label: '预存佣金',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.prepaidCommission.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'withdrawnCommission',
|
||||
label: '已提现佣金',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.withdrawnCommission.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'withdrawingCommission',
|
||||
label: '提现中佣金',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.withdrawingCommission.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'availableCommission',
|
||||
label: '可提现佣金',
|
||||
width: 120,
|
||||
formatter: (row) => `¥${row.availableCommission.toFixed(2)}`
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 200,
|
||||
formatter: (row: any) => {
|
||||
return h('div', { style: 'display: flex; gap: 5px; flex-wrap: wrap;' }, [
|
||||
h(ArtButtonTable, {
|
||||
type: 'view',
|
||||
text: '提现详情',
|
||||
onClick: () => viewWithdrawDetail(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
type: 'detail',
|
||||
text: '佣金明细',
|
||||
onClick: () => viewCommissionDetail(row)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
type: 'info',
|
||||
text: '自动提现详情',
|
||||
onClick: () => viewAutoWithdrawDetail(row)
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
getCustomerList()
|
||||
})
|
||||
|
||||
// 获取客户列表
|
||||
const getCustomerList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 模拟API调用
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
const startIndex = (pagination.currentPage - 1) * pagination.pageSize
|
||||
const endIndex = startIndex + pagination.pageSize
|
||||
const paginatedData = mockData.slice(startIndex, endIndex)
|
||||
|
||||
tableData.value = paginatedData
|
||||
pagination.total = mockData.length
|
||||
loading.value = false
|
||||
} catch (error) {
|
||||
console.error('获取客户列表失败:', error)
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleRefresh = () => {
|
||||
getCustomerList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getCustomerList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getCustomerList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.customer-management-page {
|
||||
// 可以添加特定样式
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -207,6 +207,7 @@
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
import { EnterpriseService, ShopService } from '@/api/modules'
|
||||
import { ElMessage, ElSwitch, ElCascader, ElTreeSelect } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
@@ -797,7 +798,7 @@
|
||||
// 查看客户账号
|
||||
const viewCustomerAccounts = (row: EnterpriseItem) => {
|
||||
router.push({
|
||||
path: `/account-management/enterprise-customer/customer-accounts/${row.id}`,
|
||||
path: `${RoutesAlias.EnterpriseCustomer}/customer-accounts/${row.id}`,
|
||||
query: { type: 'enterprise' }
|
||||
})
|
||||
}
|
||||
@@ -805,14 +806,14 @@
|
||||
// 卡管理
|
||||
const manageCards = (row: EnterpriseItem) => {
|
||||
router.push({
|
||||
path: '/account-management/enterprise-cards',
|
||||
path: RoutesAlias.EnterpriseCards,
|
||||
query: { id: row.id }
|
||||
})
|
||||
}
|
||||
|
||||
const manageDevices = (row: EnterpriseItem) => {
|
||||
router.push({
|
||||
path: '/asset-management/enterprise-devices',
|
||||
path: RoutesAlias.EnterpriseDevices,
|
||||
query: { id: row.id }
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,599 +0,0 @@
|
||||
<template>
|
||||
<ArtTableFullScreen>
|
||||
<div class="shop-account-page" id="table-full-screen">
|
||||
<!-- 搜索栏 -->
|
||||
<ArtSearchBar
|
||||
v-model:filter="searchForm"
|
||||
:items="searchFormItems"
|
||||
@reset="handleReset"
|
||||
@search="handleSearch"
|
||||
></ArtSearchBar>
|
||||
|
||||
<ElCard shadow="never" class="art-table-card">
|
||||
<!-- 表格头部 -->
|
||||
<ArtTableHeader
|
||||
:columnList="columnOptions"
|
||||
v-model:columns="columnChecks"
|
||||
@refresh="handleRefresh"
|
||||
>
|
||||
<template #left>
|
||||
<ElButton @click="showDialog('add')" v-permission="'shop_account:add'"
|
||||
>新增代理账号</ElButton
|
||||
>
|
||||
</template>
|
||||
</ArtTableHeader>
|
||||
|
||||
<!-- 表格 -->
|
||||
<ArtTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:data="tableData"
|
||||
:currentPage="pagination.currentPage"
|
||||
:pageSize="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:marginTop="10"
|
||||
@selection-change="handleSelectionChange"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
>
|
||||
<template #default>
|
||||
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<ElDialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogType === 'add' ? '新增代理账号' : '编辑代理账号'"
|
||||
width="500px"
|
||||
>
|
||||
<ElForm ref="formRef" :model="formData" :rules="rules" label-width="80px">
|
||||
<ElFormItem label="用户名" prop="username">
|
||||
<ElInput v-model="formData.username" placeholder="请输入用户名" />
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="dialogType === 'add'" label="密码" prop="password">
|
||||
<ElInput
|
||||
v-model="formData.password"
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
show-password
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="手机号" prop="phone">
|
||||
<ElInput v-model="formData.phone" placeholder="请输入手机号" maxlength="11" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="店铺" prop="shop_id">
|
||||
<ElSelect
|
||||
v-model="formData.shop_id"
|
||||
placeholder="请选择店铺"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="searchShops"
|
||||
:loading="shopLoading"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption
|
||||
v-for="shop in shopList"
|
||||
:key="shop.id"
|
||||
:label="shop.shop_name"
|
||||
:value="shop.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleSubmit" :loading="submitLoading"
|
||||
>提交</ElButton
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 修改密码对话框 -->
|
||||
<ElDialog v-model="passwordDialogVisible" title="重置密码" width="400px">
|
||||
<ElForm ref="passwordFormRef" :model="passwordForm" :rules="passwordRules">
|
||||
<ElFormItem label="新密码" prop="new_password">
|
||||
<ElInput
|
||||
v-model="passwordForm.new_password"
|
||||
type="password"
|
||||
placeholder="请输入新密码"
|
||||
show-password
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="passwordDialogVisible = false">取消</ElButton>
|
||||
<ElButton
|
||||
type="primary"
|
||||
@click="handleChangePassword"
|
||||
:loading="passwordSubmitLoading"
|
||||
>提交</ElButton
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { FormInstance, ElMessage, ElMessageBox, ElSwitch, ElSelect, ElOption } from 'element-plus'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { useAuth } from '@/composables/useAuth'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import { AccountService, ShopService } from '@/api/modules'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import type { PlatformAccount, ShopResponse } from '@/types/api'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import { CommonStatus, getStatusText, STATUS_SELECT_OPTIONS } from '@/config/constants'
|
||||
|
||||
defineOptions({ name: 'ShopAccount' }) // 定义组件名称,用于 KeepAlive 缓存控制
|
||||
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
const dialogType = ref('add')
|
||||
const dialogVisible = ref(false)
|
||||
const passwordDialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const passwordSubmitLoading = ref(false)
|
||||
const shopLoading = ref(false)
|
||||
const currentAccountId = ref<number>(0)
|
||||
const shopList = ref<ShopResponse[]>([])
|
||||
const searchShopList = ref<ShopResponse[]>([])
|
||||
|
||||
// 定义表单搜索初始值
|
||||
const initialSearchState = {
|
||||
username: '',
|
||||
phone: '',
|
||||
shop_id: undefined as number | undefined,
|
||||
status: undefined as number | undefined
|
||||
}
|
||||
|
||||
// 响应式表单数据
|
||||
const searchForm = reactive({ ...initialSearchState })
|
||||
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref<PlatformAccount[]>([])
|
||||
|
||||
// 表格实例引用
|
||||
const tableRef = ref()
|
||||
|
||||
// 选中的行数据
|
||||
const selectedRows = ref<any[]>([])
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(searchForm, { ...initialSearchState })
|
||||
pagination.currentPage = 1 // 重置到第一页
|
||||
getAccountList()
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
console.log('搜索参数:', searchForm)
|
||||
pagination.currentPage = 1 // 搜索时重置到第一页
|
||||
getAccountList()
|
||||
}
|
||||
|
||||
// 表单配置项
|
||||
const searchFormItems = computed<SearchFormItem[]>(() => [
|
||||
{
|
||||
label: '用户名',
|
||||
prop: 'username',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入用户名'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
type: 'input',
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请输入手机号'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '店铺',
|
||||
prop: 'shop_id',
|
||||
type: 'select',
|
||||
options: searchShopList.value.map((shop) => ({ label: shop.shop_name, value: shop.id })),
|
||||
config: {
|
||||
clearable: true,
|
||||
filterable: true,
|
||||
remote: true,
|
||||
remoteMethod: handleSearchShop,
|
||||
loading: shopLoading.value,
|
||||
placeholder: '请选择或搜索店铺'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
type: 'select',
|
||||
options: STATUS_SELECT_OPTIONS,
|
||||
config: {
|
||||
clearable: true,
|
||||
placeholder: '请选择状态'
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
// 列配置
|
||||
const columnOptions = [
|
||||
{ label: 'ID', prop: 'id' },
|
||||
{ label: '用户名', prop: 'username' },
|
||||
{ label: '手机号', prop: 'phone' },
|
||||
{ label: '店铺名称', prop: 'shop_name' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
{ label: '创建时间', prop: 'created_at' },
|
||||
{ label: '操作', prop: 'operation' }
|
||||
]
|
||||
|
||||
// 显示对话框
|
||||
const showDialog = (type: string, row?: PlatformAccount) => {
|
||||
dialogType.value = type
|
||||
|
||||
if (type === 'edit' && row) {
|
||||
formData.id = row.id
|
||||
formData.username = row.username
|
||||
formData.phone = row.phone
|
||||
formData.shop_id = row.shop_id || 0
|
||||
formData.password = ''
|
||||
} else {
|
||||
formData.id = 0
|
||||
formData.username = ''
|
||||
formData.phone = ''
|
||||
formData.shop_id = 0
|
||||
formData.password = ''
|
||||
}
|
||||
|
||||
// 重置表单验证状态
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 显示修改密码对话框
|
||||
const showPasswordDialog = (row: PlatformAccount) => {
|
||||
currentAccountId.value = row.id
|
||||
passwordForm.new_password = ''
|
||||
|
||||
// 重置表单验证状态
|
||||
nextTick(() => {
|
||||
passwordFormRef.value?.clearValidate()
|
||||
})
|
||||
|
||||
passwordDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 状态切换处理
|
||||
const handleStatusChange = async (row: PlatformAccount, newStatus: number) => {
|
||||
const oldStatus = row.status
|
||||
// 先更新UI
|
||||
row.status = newStatus
|
||||
try {
|
||||
await AccountService.updateAccountStatus(row.id, newStatus as 0 | 1)
|
||||
ElMessage.success('状态切换成功')
|
||||
} catch (error) {
|
||||
// 切换失败,恢复原状态
|
||||
row.status = oldStatus
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 动态列配置
|
||||
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||
{
|
||||
prop: 'id',
|
||||
label: 'ID'
|
||||
},
|
||||
{
|
||||
prop: 'username',
|
||||
label: '用户名'
|
||||
},
|
||||
{
|
||||
prop: 'phone',
|
||||
label: '手机号'
|
||||
},
|
||||
{
|
||||
prop: 'shop_name',
|
||||
label: '店铺名称',
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
formatter: (row: PlatformAccount) => {
|
||||
return h(ElSwitch, {
|
||||
modelValue: row.status,
|
||||
activeValue: CommonStatus.ENABLED,
|
||||
inactiveValue: CommonStatus.DISABLED,
|
||||
activeText: getStatusText(CommonStatus.ENABLED),
|
||||
inactiveText: getStatusText(CommonStatus.DISABLED),
|
||||
inlinePrompt: true,
|
||||
'onUpdate:modelValue': (val: string | number | boolean) =>
|
||||
handleStatusChange(row, val as number)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'created_at',
|
||||
label: '创建时间',
|
||||
formatter: (row: PlatformAccount) => formatDateTime(row.created_at)
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
formatter: (row: PlatformAccount) => {
|
||||
const buttons = []
|
||||
|
||||
if (hasAuth('shop_account:update_psd')) {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
icon: '',
|
||||
onClick: () => showPasswordDialog(row)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (hasAuth('shop_account:edit')) {
|
||||
buttons.push(
|
||||
h(ArtButtonTable, {
|
||||
type: 'edit',
|
||||
onClick: () => showDialog('edit', row)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return h('div', { style: 'display: flex; gap: 8px;' }, buttons)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
// 表单实例
|
||||
const formRef = ref<FormInstance>()
|
||||
const passwordFormRef = ref<FormInstance>()
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
id: 0,
|
||||
username: '',
|
||||
password: '',
|
||||
phone: '',
|
||||
shop_id: 0
|
||||
})
|
||||
|
||||
// 密码表单数据
|
||||
const passwordForm = reactive({
|
||||
new_password: ''
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getAccountList()
|
||||
loadShopList()
|
||||
loadSearchShopList()
|
||||
})
|
||||
|
||||
// 加载店铺列表(用于新增/编辑对话框,默认加载20条)
|
||||
const loadShopList = async (shopName?: string) => {
|
||||
shopLoading.value = true
|
||||
try {
|
||||
const params: any = {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
if (shopName) {
|
||||
params.shop_name = shopName
|
||||
}
|
||||
const res = await ShopService.getShops(params)
|
||||
if (res.code === 0) {
|
||||
shopList.value = res.data.items || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取店铺列表失败:', error)
|
||||
} finally {
|
||||
shopLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 加载搜索栏店铺列表(默认加载20条)
|
||||
const loadSearchShopList = async (shopName?: string) => {
|
||||
try {
|
||||
const params: any = {
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
}
|
||||
if (shopName) {
|
||||
params.shop_name = shopName
|
||||
}
|
||||
const res = await ShopService.getShops(params)
|
||||
if (res.code === 0) {
|
||||
searchShopList.value = res.data.items || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取店铺列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索店铺(用于新增/编辑对话框)
|
||||
const searchShops = (query: string) => {
|
||||
if (query) {
|
||||
loadShopList(query)
|
||||
} else {
|
||||
loadShopList()
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索店铺(用于搜索栏)
|
||||
const handleSearchShop = (query: string) => {
|
||||
if (query) {
|
||||
loadSearchShopList(query)
|
||||
} else {
|
||||
loadSearchShopList()
|
||||
}
|
||||
}
|
||||
|
||||
// 提交修改密码
|
||||
const handleChangePassword = async () => {
|
||||
if (!passwordFormRef.value) return
|
||||
|
||||
await passwordFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
passwordSubmitLoading.value = true
|
||||
try {
|
||||
await AccountService.updateAccountPassword(
|
||||
currentAccountId.value,
|
||||
passwordForm.new_password
|
||||
)
|
||||
ElMessage.success('重置密码成功')
|
||||
passwordDialogVisible.value = false
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
passwordSubmitLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取账号列表
|
||||
const getAccountList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.currentPage,
|
||||
pageSize: pagination.pageSize,
|
||||
user_type: 3, // 筛选代理账号
|
||||
username: searchForm.username || undefined,
|
||||
phone: searchForm.phone || undefined,
|
||||
shop_id: searchForm.shop_id,
|
||||
status: searchForm.status
|
||||
}
|
||||
const res = await AccountService.getAccounts(params)
|
||||
if (res.code === 0) {
|
||||
tableData.value = res.data.items || []
|
||||
pagination.total = res.data.total || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取代理账号列表失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleRefresh = () => {
|
||||
getAccountList()
|
||||
}
|
||||
|
||||
// 处理表格行选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive<FormRules>({
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{ min: 8, max: 32, message: '密码长度为 8-32 个字符', trigger: 'blur' }
|
||||
],
|
||||
phone: [
|
||||
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
||||
{ len: 11, message: '手机号必须为 11 位', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' }
|
||||
],
|
||||
shop_id: [
|
||||
{ required: true, message: '请选择店铺', trigger: 'change' },
|
||||
{ type: 'number', min: 0, message: '店铺ID必须大于0', trigger: 'change' }
|
||||
]
|
||||
})
|
||||
|
||||
// 密码验证规则
|
||||
const passwordRules = reactive<FormRules>({
|
||||
new_password: [
|
||||
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
||||
{ min: 8, max: 32, message: '密码长度为 8-32 个字符', trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
submitLoading.value = true
|
||||
try {
|
||||
if (dialogType.value === 'add') {
|
||||
const data = {
|
||||
username: formData.username,
|
||||
password: formData.password,
|
||||
phone: formData.phone,
|
||||
user_type: 3, // 代理账号
|
||||
shop_id: formData.shop_id
|
||||
}
|
||||
|
||||
await AccountService.createAccount(data)
|
||||
ElMessage.success('新增成功')
|
||||
} else {
|
||||
const data = {
|
||||
username: formData.username
|
||||
}
|
||||
|
||||
await AccountService.updateAccount(formData.id, data)
|
||||
ElMessage.success('更新成功')
|
||||
}
|
||||
|
||||
dialogVisible.value = false
|
||||
getAccountList()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleSizeChange = (newPageSize: number) => {
|
||||
pagination.pageSize = newPageSize
|
||||
getAccountList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (newCurrentPage: number) => {
|
||||
pagination.currentPage = newCurrentPage
|
||||
getAccountList()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.shop-account-page {
|
||||
// 代理账号管理页面样式
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user