用户反馈: 操作列只显示一个文字按钮+⋯ 不方便, 期望按按钮数量智能显示 - 过滤 when 后 ≤3 个: 全部显示文字按钮, 不显示 ⋯ - 过滤 when 后 ≥4 个: 前 2 个常驻文字按钮 + ⋯ (收纳剩余) - 默认 visibleCount=2 (可配置) TableActions API 调整 (W17.6 → W17.6.1): - 原来: :primary=[A] + :more=[B,C,D] (人为主次划分) - 现在: :actions=[A,B,C,D] (按数组顺序自动前 2 显 + ⋯) 16 文件改动 (1 组件 + 15 view 调用方式): - 15 view 合并 :primary/:more → :actions - 3 按钮页 (10 个): 现在全部显示文字按钮无 ⋯, 体验更直接 - 4/5 按钮页 (5 个): 前 2 显 + ⋯, 比之前详情+⋯更直观
123 lines
8.4 KiB
Vue
123 lines
8.4 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* F006 推广员管理 - W16
|
|
*
|
|
* 沿用老 vue supplier/promoter.vue 字段
|
|
*
|
|
* 端点: 4 URL 探测 (promoter/page, /list, /search, /queryPage); 404 → FALLBACK seed
|
|
*/
|
|
import { ref, reactive, onMounted, computed } from 'vue'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { httpGet } from '@/utils/request'
|
|
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
|
import SearchBar from '@/components/SearchBar/SearchBar.vue'
|
|
import DataTable from '@/components/DataTable/DataTable.vue'
|
|
import TableActions from '@/components/TableActions/TableActions.vue'
|
|
|
|
interface PromoterRow { id:string; enterpriseId:string; enterpriseName:string; promoterName:string; promoterRadio:number; promoterGood:string; beginTime:string; endTime:string; createTime:string }
|
|
const ENDPOINTS = [
|
|
'/supplier/promoter/page',
|
|
'/supplier/promoter/list',
|
|
'/supplier/promoter/search',
|
|
'/supplier/promoter/queryPage'
|
|
]
|
|
const FALLBACK: PromoterRow[] = [
|
|
{ id:'P001', enterpriseId:'s20015', enterpriseName:'坚美建筑材料有限公司', promoterName:'张推广', promoterRadio:0.05, promoterGood:'国标槽钢/角钢系列', beginTime:'2026-04-01', endTime:'2026-12-31', createTime:'2026-04-01 09:30:00' },
|
|
{ id:'P002', enterpriseId:'s20016', enterpriseName:'华建门窗厂', promoterName:'李经纪人', promoterRadio:0.08, promoterGood:'断桥铝门窗', beginTime:'2026-04-15', endTime:'2026-10-30', createTime:'2026-04-15 14:22:00' },
|
|
{ id:'P003', enterpriseId:'s20017', enterpriseName:'融鑫管业', promoterName:'王工长', promoterRadio:0.06, promoterGood:'PPR给水管', beginTime:'2026-05-01', endTime:'2026-12-31', createTime:'2026-05-01 11:08:30' },
|
|
{ id:'P004', enterpriseId:'s20018', enterpriseName:'东方五金机械', promoterName:'赵渠道', promoterRadio:0.10, promoterGood:'电动工具', beginTime:'2026-05-10', endTime:'2026-09-30', createTime:'2026-05-10 16:48:00' },
|
|
{ id:'P005', enterpriseId:'s20019', enterpriseName:'美洁涂料', promoterName:'陈渠道', promoterRadio:0.07, promoterGood:'环保涂料', beginTime:'2026-05-20', endTime:'2026-12-31', createTime:'2026-05-20 09:15:00' },
|
|
{ id:'P006', enterpriseId:'s20020', enterpriseName:'万家灯具', promoterName:'周照明师', promoterRadio:0.12, promoterGood:'LED灯具', beginTime:'2026-06-01', endTime:'2026-12-31', createTime:'2026-06-01 10:42:00' },
|
|
{ id:'P007', enterpriseId:'s20021', enterpriseName:'顺达物流', promoterName:'吴同城', promoterRadio:0.05, promoterGood:'同城配送服务', beginTime:'2026-06-10', endTime:'2026-12-31', createTime:'2026-06-10 13:18:00' },
|
|
{ id:'P008', enterpriseId:'s20022', enterpriseName:'华建门窗厂', promoterName:'林工长', promoterRadio:0.08, promoterGood:'铝合金门窗', beginTime:'2026-06-20', endTime:'2026-12-31', createTime:'2026-06-20 11:35:00' },
|
|
{ id:'P009', enterpriseId:'s20023', enterpriseName:'众成厨具', promoterName:'黄销售', promoterRadio:0.06, promoterGood:'厨房用品', beginTime:'2026-07-01', endTime:'2026-12-31', createTime:'2026-07-01 09:50:00' },
|
|
{ id:'P010', enterpriseId:'s20024', enterpriseName:'东方五金机械', promoterName:'何专业', promoterRadio:0.09, promoterGood:'角磨机', beginTime:'2026-07-05', endTime:'2026-12-31', createTime:'2026-07-05 14:25:00' },
|
|
{ id:'P011', enterpriseId:'s20025', enterpriseName:'坚美建筑材料', promoterName:'钱工长', promoterRadio:0.07, promoterGood:'国标钢材', beginTime:'2026-07-08', endTime:'2026-12-31', createTime:'2026-07-08 11:42:00' },
|
|
{ id:'P012', enterpriseId:'s20026', enterpriseName:'美洁涂料', promoterName:'孙工长', promoterRadio:0.06, promoterGood:'外墙腻子粉', beginTime:'2026-07-12', endTime:'2026-12-31', createTime:'2026-07-12 16:08:00' }
|
|
]
|
|
type Col = { type?: 'status'|'text'|'selection'; prop?: string; label: string; width?: number; slot?: string; fixed?: 'right'|true }
|
|
const columns: Col[] = [
|
|
{ type:'selection', label:'', width:50 },
|
|
{ prop:'id', label:'推广员ID', width:100, fixed:true },
|
|
{ prop:'enterpriseName', label:'所属供应商', width:200 },
|
|
{ prop:'promoterName', label:'推广员姓名', width:120 },
|
|
{ prop:'promoterRadio', label:'返佣比例', width:110, slot:'radio' },
|
|
{ prop:'promoterGood', label:'推广商品', width:200 },
|
|
{ prop:'beginTime', label:'开始时间', width:120, slot:'date1' },
|
|
{ prop:'endTime', label:'结束时间', width:120, slot:'date2' },
|
|
{ prop:'createTime', label:'创建时间', width:160, slot:'time' },
|
|
{ prop:'actions', label:'操作', width:140, slot:'actions', fixed:'right' }
|
|
]
|
|
const STATUS_DEFAULTS = [
|
|
{ value:'', label:'全部' },
|
|
{ value:'1', label:'推广中' },
|
|
{ value:'0', label:'已结束' }
|
|
]
|
|
const list = ref<PromoterRow[]>([]); const total = ref(0); const loading = ref(false); const page = ref(1); const limit = ref(10); const filterKw = ref(''); const statusTab = ref('')
|
|
const dataSource = ref<'api'|'mock'|'loading'>('loading'); const apiError = ref<string>('')
|
|
async function load() {
|
|
loading.value = true; dataSource.value = 'loading'
|
|
for (const ep of ENDPOINTS) {
|
|
try {
|
|
const data: any = await httpGet<any>(ep, { page: page.value, limit: limit.value })
|
|
const rows = (data?.list || []).map((it: any) => ({ ...it, raw: it }))
|
|
list.value = rows; total.value = Number(data?.total || rows.length); dataSource.value = 'api'; apiError.value = ''; loading.value = false; return
|
|
} catch {}
|
|
}
|
|
list.value = [...FALLBACK]; total.value = FALLBACK.length; dataSource.value = 'mock'; apiError.value = '后端 API 暂未实装, 已加载前端示例数据'; loading.value = false
|
|
}
|
|
const filtered = computed(() => {
|
|
const kw = filterKw.value.trim().toLowerCase(); let rs = list.value
|
|
if (statusTab.value === '1') rs = rs.filter(r => new Date(r.endTime) >= new Date('2026-07-07'))
|
|
if (kw) rs = rs.filter(r => String(r.promoterName).includes(kw) || String(r.enterpriseName).includes(kw) || String(r.promoterGood).includes(kw))
|
|
return rs
|
|
})
|
|
const searchFields: Array<{ key: string; label: string; type: 'text' }> = [{ key:'promoterName', label:'推广员姓名', type:'text' },{ key:'enterpriseName', label:'供应商', type:'text' },{ key:'promoterGood', label:'推广商品', type:'text' }]
|
|
|
|
const filters = reactive<Record<string, any>>({})
|
|
function onSearch() { filterKw.value = String(filters.promoterName || filters.enterpriseName || filters.promoterGood || ''); page.value = 1 }
|
|
function onStatusTab(v: string) { statusTab.value = v; page.value = 1 }
|
|
async function onDelete(row: PromoterRow) {
|
|
try { await ElMessageBox.confirm(`确认删除推广员「${row.promoterName}」?`, '提示', { type: 'warning' }) } catch { return }
|
|
ElMessage.success('已删除 (前端示例)')
|
|
}
|
|
function onEdit(row: PromoterRow) { ElMessage.info(`编辑 ${row.id}`) }
|
|
function onView(row: PromoterRow) { ElMessage.info(`详情 ${row.id}`) }
|
|
function onExport() { ElMessage.success('已发起导出 (前端示例, 共 ' + filtered.value.length + ' 条)') }
|
|
onMounted(load)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="rr-page">
|
|
<PageHeader title="推广员管理" sub="商品推广返佣管理" :data-source="dataSource" :api-error="apiError">
|
|
<el-button type="primary" @click="onExport">导出明细</el-button>
|
|
</PageHeader>
|
|
<el-tabs v-model="statusTab" @tab-change="onStatusTab" class="rr-tabs">
|
|
<el-tab-pane v-for="t in STATUS_DEFAULTS" :key="t.value" :name="t.value" :label="t.label" />
|
|
</el-tabs>
|
|
<SearchBar v-model:filters="filters" :fields="searchFields" @search="onSearch" />
|
|
<DataTable :columns="columns" :data="filtered"
|
|
:borderless="true" :loading="loading" :page="page" :limit="limit" :total="total" row-key="id"
|
|
@page-change="(p: number) => { page = p; load() }" @limit-change="(l: number) => { limit = l; page = 1; load() }">
|
|
<template #radio="{ row }">{{ (row.promoterRadio * 100).toFixed(1) }}%</template>
|
|
<template #date1="{ row }">{{ row.beginTime }}</template>
|
|
<template #date2="{ row }">{{ row.endTime }}</template>
|
|
<template #time="{ row }">{{ row.createTime }}</template>
|
|
<template #actions="{ row }">
|
|
<TableActions
|
|
:row="row"
|
|
:actions="[
|
|
{ label: '详情', type: 'primary', onClick: onView },
|
|
{ label: '编辑', type: 'primary', onClick: onEdit },
|
|
{ label: '删除', type: 'danger', onClick: onDelete }
|
|
]"
|
|
/>
|
|
</template>
|
|
</DataTable>
|
|
</div>
|
|
</template>
|
|
<style scoped>
|
|
.rr-page { padding: 16px; }
|
|
.rr-tabs { margin-bottom: 12px; }
|
|
</style>
|