feat(数据表格): 实现详细数据表格的筛选和排序功能
- 添加筛选器变化事件处理,支持按中心领导、团队领导和组长筛选数据 - 修改表格排序逻辑以适配新数据结构 - 更新表格显示字段以匹配后端返回的数据格式 - 移除不再需要的格式化函数
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<label>经理:</label>
|
||||
<select v-model="filters.manager" :disabled="!filters.advancedManager">
|
||||
<select v-model="filters.manager" @change="onManagerChange" :disabled="!filters.advancedManager">
|
||||
<option value="">全部经理</option>
|
||||
<option v-for="manager in availableManagers" :key="manager.name" :value="manager.name">
|
||||
{{ manager.name }}
|
||||
@@ -41,34 +41,36 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>人员</th>
|
||||
<th @click="sortBy('dealRate')" class="sortable">成交率 <span class="sort-icon" :class="{ active: sortField === 'dealRate' }">{{ sortOrder === 'desc' ? '↓' : '↑' }}</span></th>
|
||||
<th @click="sortBy('callDuration')" class="sortable">成交单数 <span class="sort-icon" :class="{ active: sortField === 'callDuration' }">{{ sortOrder === 'desc' ? '↓' : '↑' }}</span></th>
|
||||
<th @click="sortBy('conversion_rate')" class="sortable">成交率 <span class="sort-icon" :class="{ active: sortField === 'conversion_rate' }">{{ sortOrder === 'desc' ? '↓' : '↑' }}</span></th>
|
||||
<th @click="sortBy('total_deals')" class="sortable">成交单数 <span class="sort-icon" :class="{ active: sortField === 'total_deals' }">{{ sortOrder === 'desc' ? '↓' : '↑' }}</span></th>
|
||||
<th>加微率</th>
|
||||
<th>入群率</th>
|
||||
<th>表单填写率</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="person in filteredTableData" :key="person.id" @click="$emit('update:selectedPerson', person)" :class="{ selected: selectedPerson && selectedPerson.id === person.id }">
|
||||
<tr v-for="(person, index) in displayTableData" :key="index" @click="$emit('update:selectedPerson', person)" :class="{ selected: selectedPerson && selectedPerson.leader_name === person.leader_name }">
|
||||
|
||||
|
||||
|
||||
<td>
|
||||
<div class="person-info">
|
||||
<div class="person-avatar">{{ person.name.charAt(0) }}</div>
|
||||
<div class="person-avatar">{{ person.leader_name?.charAt(0) }}</div>
|
||||
<div>
|
||||
<div class="person-name">{{ person.name }}</div>
|
||||
<div class="person-position">{{ person.position }}</div>
|
||||
<div class="person-name">{{ person.leader_name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="deal-rate">
|
||||
<span class="rate-value" :class="getRateClass(person.dealRate)">{{ person.dealRate }}%</span>
|
||||
<div class="rate-bar"><div class="rate-fill" :style="{ width: person.dealRate + '%', backgroundColor: getRateColor(person.dealRate) }"></div></div>
|
||||
<span class="rate-value" :class="getRateClass(parseFloat(person.conversion_rate))">{{ person.conversion_rate }}</span>
|
||||
<div class="rate-bar"><div class="rate-fill" :style="{ width: parseFloat(person.conversion_rate) + '%', backgroundColor: getRateColor(parseFloat(person.conversion_rate)) }"></div></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ formatDuration(person.callDuration) }}</td>
|
||||
<td>{{ person.callCount }}次</td>
|
||||
<td>¥{{ person.dealAmount.toLocaleString() }}</td>
|
||||
<td>{{ person.department }}</td>
|
||||
<td>{{ person.total_deals }}</td>
|
||||
<td>{{ person.plus_v_rate }}</td>
|
||||
<td>{{ person.group_rate }}</td>
|
||||
<td>{{ person.form_filling_rate }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -85,10 +87,10 @@ const props = defineProps({
|
||||
selectedPerson: { type: Object, default: null },
|
||||
levelTree: { type: Object, default: () => ({}) }
|
||||
});
|
||||
defineEmits(['update:selectedPerson']);
|
||||
const emit = defineEmits(['update:selectedPerson', 'filter-change']);
|
||||
|
||||
const filters = ref({ centerLeader: '', advancedManager: '', manager: '', dealStatus: '' });
|
||||
const sortField = ref('dealRate');
|
||||
const sortField = ref('conversion_rate');
|
||||
const sortOrder = ref('desc');
|
||||
|
||||
const centerLeaders = computed(() => {
|
||||
@@ -107,13 +109,22 @@ const centerLeaders = computed(() => {
|
||||
return manager ? manager.managers || [] : [];
|
||||
});
|
||||
|
||||
const filteredTableData = computed(() => {
|
||||
let filtered = props.tableData;
|
||||
if (filters.value.centerLeader) filtered = filtered.filter(item => item.centerLeader === filters.value.centerLeader);
|
||||
if (filters.value.advancedManager) filtered = filtered.filter(item => item.advancedManager === filters.value.advancedManager);
|
||||
if (filters.value.manager) filtered = filtered.filter(item => item.manager === filters.value.manager);
|
||||
return filtered.sort((a, b) => {
|
||||
const aValue = a[sortField.value], bValue = b[sortField.value];
|
||||
// 显示表格数据(直接使用API返回的数据)
|
||||
const displayTableData = computed(() => {
|
||||
if (!props.tableData || !Array.isArray(props.tableData)) return [];
|
||||
|
||||
return props.tableData.sort((a, b) => {
|
||||
let aValue = a[sortField.value];
|
||||
let bValue = b[sortField.value];
|
||||
|
||||
// 处理百分比字符串
|
||||
if (typeof aValue === 'string' && aValue.includes('%')) {
|
||||
aValue = parseFloat(aValue.replace('%', ''));
|
||||
}
|
||||
if (typeof bValue === 'string' && bValue.includes('%')) {
|
||||
bValue = parseFloat(bValue.replace('%', ''));
|
||||
}
|
||||
|
||||
return sortOrder.value === 'desc' ? bValue - aValue : aValue - bValue;
|
||||
});
|
||||
});
|
||||
@@ -121,11 +132,31 @@ const filteredTableData = computed(() => {
|
||||
const onCenterLeaderChange = () => {
|
||||
filters.value.advancedManager = '';
|
||||
filters.value.manager = '';
|
||||
};
|
||||
emitFilterChange();
|
||||
};
|
||||
|
||||
const onAdvancedManagerChange = () => {
|
||||
const onAdvancedManagerChange = () => {
|
||||
filters.value.manager = '';
|
||||
};
|
||||
emitFilterChange();
|
||||
};
|
||||
|
||||
const onManagerChange = () => {
|
||||
emitFilterChange();
|
||||
};
|
||||
|
||||
const emitFilterChange = () => {
|
||||
const filterParams = {};
|
||||
if (filters.value.centerLeader) {
|
||||
filterParams.center_leader = filters.value.centerLeader;
|
||||
}
|
||||
if (filters.value.advancedManager) {
|
||||
filterParams.team_leader = filters.value.advancedManager;
|
||||
}
|
||||
if (filters.value.manager) {
|
||||
filterParams.group_leader = filters.value.manager;
|
||||
}
|
||||
emit('filter-change', filterParams);
|
||||
};
|
||||
|
||||
const sortBy = (field) => {
|
||||
if (sortField.value === field) sortOrder.value = sortOrder.value === 'desc' ? 'asc' : 'desc';
|
||||
@@ -137,10 +168,7 @@ const getRateClass = (rate) => {
|
||||
const getRateColor = (rate) => {
|
||||
if (rate >= 80) return '#4CAF50'; if (rate >= 60) return '#FF9800'; return '#f44336';
|
||||
};
|
||||
const formatDuration = (minutes) => {
|
||||
const h = Math.floor(minutes / 60), m = minutes % 60;
|
||||
return h > 0 ? `${h}h${m}m` : `${m}m`;
|
||||
};
|
||||
// 移除formatDuration函数,不再需要
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -69,9 +69,10 @@
|
||||
<!-- 第五行 -->
|
||||
<div class="dashboard-row row-4">
|
||||
<DetailedDataTable
|
||||
:table-data="tableData"
|
||||
:table-data="detailData"
|
||||
:level-tree="levelTree"
|
||||
v-model:selected-person="selectedPerson"
|
||||
@filter-change="handleFilterChange"
|
||||
/>
|
||||
<DataDetailCard :selected-person="selectedPerson" />
|
||||
</div>
|
||||
@@ -1006,17 +1007,83 @@ async function CusotomGetLevelTree() {
|
||||
}
|
||||
// 获取详细数据表格
|
||||
const detailData = ref({});
|
||||
async function getDetailData(level) {
|
||||
const params={
|
||||
level,
|
||||
}
|
||||
async function getDetailData(params) {
|
||||
if(params?.center_leader){
|
||||
// alert(11111)
|
||||
try {
|
||||
const res = await getDetailedDataTable(params)
|
||||
console.log(1222222,res)
|
||||
console.log('详细数据表格:', res)
|
||||
detailData.value = res.data
|
||||
} catch (error) {
|
||||
console.error("获取详细数据表格失败:", error);
|
||||
}
|
||||
}else{
|
||||
// alert(22222)
|
||||
try {
|
||||
const res = await getDetailedDataTable()
|
||||
console.log('详细数据表格:', res)
|
||||
/**
|
||||
* data
|
||||
:
|
||||
[{leader_name: "郭可英", conversion_rate: "0.00%", total_deals: 0, plus_v_rate: "59.75%",…},…]
|
||||
0
|
||||
:
|
||||
{leader_name: "郭可英", conversion_rate: "0.00%", total_deals: 0, plus_v_rate: "59.75%",…}
|
||||
conversion_rate
|
||||
:
|
||||
"0.00%"
|
||||
form_filling_rate
|
||||
:
|
||||
"59.75%"
|
||||
group_rate
|
||||
:
|
||||
"54.09%"
|
||||
leader_name
|
||||
:
|
||||
"郭可英"
|
||||
plus_v_rate
|
||||
:
|
||||
"59.75%"
|
||||
total_deals
|
||||
:
|
||||
0
|
||||
1
|
||||
:
|
||||
{leader_name: "刘瑞", conversion_rate: "1.32%", total_deals: 7, plus_v_rate: "47.17%",…}
|
||||
conversion_rate
|
||||
:
|
||||
"1.32%"
|
||||
form_filling_rate
|
||||
:
|
||||
"47.17%"
|
||||
group_rate
|
||||
:
|
||||
"39.25%"
|
||||
leader_name
|
||||
:
|
||||
"刘瑞"
|
||||
plus_v_rate
|
||||
:
|
||||
"47.17%"
|
||||
total_deals
|
||||
:
|
||||
7
|
||||
message
|
||||
:
|
||||
"获取详细数据表格成功"
|
||||
*/
|
||||
detailData.value = res.data
|
||||
} catch (error) {
|
||||
console.error("获取详细数据表格失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 处理筛选器变化
|
||||
const handleFilterChange = (filterParams) => {
|
||||
console.log('筛选器变化:', filterParams)
|
||||
getDetailData(filterParams)
|
||||
}
|
||||
|
||||
onMounted(async() => {
|
||||
@@ -1029,6 +1096,8 @@ onMounted(async() => {
|
||||
// await getCustomerTypeRatio('child_education')
|
||||
// await getCustomerUrgency()
|
||||
await CusotomGetLevelTree()
|
||||
await getDetailData()
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user