feat: 实现任务管理功能并优化界面显示
- 添加任务列表获取和状态更新API调用 - 修改任务列表组件显示格式和状态标签 - 优化日期格式化处理逻辑 - 调整任务列表样式和交互效果 - 注释掉部分不需要的API调用
This commit is contained in:
@@ -4,18 +4,54 @@
|
||||
<h2>待处理事项</h2>
|
||||
<div class="header-controls">
|
||||
<select v-model="filterPriority" class="priority-filter">
|
||||
<option value="all">全部优先级</option>
|
||||
<option value="urgent">待处理</option>
|
||||
<option value="high">正在处理</option>
|
||||
<option value="medium">已完成</option>
|
||||
<option value="all">全部状态</option>
|
||||
<option value="待处理">待处理</option>
|
||||
<option value="正在处理">正在处理</option>
|
||||
<option value="已完成">已完成</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions-list">
|
||||
<div v-if="filteredActions.length === 0" class="no-tasks">
|
||||
<p>暂无任务</p>
|
||||
</div>
|
||||
<div v-else class="task-list">
|
||||
<div
|
||||
v-for="task in filteredActions"
|
||||
:key="task.task_id"
|
||||
class="task-row"
|
||||
>
|
||||
<div class="task-info">
|
||||
<div class="task-row-1">
|
||||
<span class="task-title">{{ task.task_title }}</span>
|
||||
<span class="task-content">{{ task.task_content }}</span>
|
||||
</div>
|
||||
<div class="task-row-2">
|
||||
<span class="task-date">到期时间: {{ formatDueDate(task.expiration_date) }}</span>
|
||||
<span class="task-created">创建时间: {{ task.created_at }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="task-actions">
|
||||
<span class="status-tag" :class="getTaskStatusClass(task.state)">
|
||||
{{ task.state }}
|
||||
</span>
|
||||
<button
|
||||
class="status-btn"
|
||||
@click="changeTaskStatus(task)"
|
||||
>
|
||||
处理任务
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import axios from 'axios'
|
||||
|
||||
const props = defineProps({
|
||||
selectedGroup: {
|
||||
@@ -40,131 +76,94 @@ const newAction = ref({
|
||||
})
|
||||
|
||||
// 待处理事项数据
|
||||
const actions = ref([
|
||||
{
|
||||
id: 1,
|
||||
title: '突破组转化率改进计划',
|
||||
description: '针对突破组转化率连续下降问题,制定具体改进措施并跟踪执行',
|
||||
priority: 'urgent',
|
||||
dueDate: '2024-01-15',
|
||||
relatedGroup: '突破组',
|
||||
assignee: '王主管',
|
||||
progress: 30,
|
||||
tags: ['业绩改进', '紧急'],
|
||||
completed: false,
|
||||
createdAt: '2024-01-10'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '新星组人员补充',
|
||||
description: '新星组当前人员不足,需要招聘2名新销售并安排培训',
|
||||
priority: 'high',
|
||||
dueDate: '2024-01-20',
|
||||
relatedGroup: '新星组',
|
||||
assignee: '赵主管',
|
||||
progress: 60,
|
||||
tags: ['人员管理', '招聘'],
|
||||
completed: false,
|
||||
createdAt: '2024-01-08'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '月度业绩分析报告',
|
||||
description: '整理各组月度业绩数据,分析趋势并提出下月目标建议',
|
||||
priority: 'medium',
|
||||
dueDate: '2024-01-25',
|
||||
relatedGroup: '',
|
||||
assignee: '中心组长',
|
||||
progress: 80,
|
||||
tags: ['数据分析', '报告'],
|
||||
completed: false,
|
||||
createdAt: '2024-01-05'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '销售技能培训安排',
|
||||
description: '组织各组销售人员参加客户沟通技巧培训',
|
||||
priority: 'medium',
|
||||
dueDate: '2024-01-30',
|
||||
relatedGroup: '',
|
||||
assignee: '培训部',
|
||||
progress: 20,
|
||||
tags: ['培训', '技能提升'],
|
||||
completed: false,
|
||||
createdAt: '2024-01-12'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '客户满意度调研',
|
||||
description: '对已成交客户进行满意度调研,收集改进建议',
|
||||
priority: 'low',
|
||||
dueDate: '2024-02-05',
|
||||
relatedGroup: '',
|
||||
assignee: '客服部',
|
||||
progress: 0,
|
||||
tags: ['客户服务', '调研'],
|
||||
completed: false,
|
||||
createdAt: '2024-01-14'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: '精英组激励方案制定',
|
||||
description: '为表现优秀的精英组制定专项激励方案',
|
||||
priority: 'medium',
|
||||
dueDate: '2024-01-18',
|
||||
relatedGroup: '精英组',
|
||||
assignee: '人事部',
|
||||
progress: 100,
|
||||
tags: ['激励', '团队管理'],
|
||||
completed: true,
|
||||
createdAt: '2024-01-01'
|
||||
}
|
||||
])
|
||||
const actions = ref([])
|
||||
|
||||
// 筛选后的事项
|
||||
const filteredActions = computed(() => {
|
||||
console.log('计算filteredActions - actions.value:', actions.value)
|
||||
console.log('计算filteredActions - filterPriority.value:', filterPriority.value)
|
||||
|
||||
let filtered = actions.value
|
||||
|
||||
if (filterPriority.value !== 'all') {
|
||||
filtered = filtered.filter(action => action.priority === filterPriority.value)
|
||||
filtered = filtered.filter(task => task.state === filterPriority.value)
|
||||
}
|
||||
|
||||
// 如果选中了特定组别,优先显示相关事项
|
||||
if (props.selectedGroup) {
|
||||
filtered = filtered.sort((a, b) => {
|
||||
const aRelated = a.relatedGroup === props.selectedGroup.name
|
||||
const bRelated = b.relatedGroup === props.selectedGroup.name
|
||||
if (aRelated && !bRelated) return -1
|
||||
if (!aRelated && bRelated) return 1
|
||||
return 0
|
||||
console.log('计算filteredActions - filtered结果:', filtered)
|
||||
return filtered
|
||||
})
|
||||
|
||||
// 获取任务状态样式类
|
||||
const getTaskStatusClass = (state) => {
|
||||
switch (state) {
|
||||
case '待处理':
|
||||
return 'status-pending'
|
||||
case '正在处理':
|
||||
return 'status-processing'
|
||||
case '已完成':
|
||||
return 'status-completed'
|
||||
default:
|
||||
return 'status-default'
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化到期日期
|
||||
const formatDueDate = (dateStr) => {
|
||||
if (!dateStr) return '无'
|
||||
// 如果是YYYYMMDD格式,转换为YYYY-MM-DD
|
||||
if (dateStr.length === 8) {
|
||||
const year = dateStr.substring(0, 4)
|
||||
const month = dateStr.substring(4, 6)
|
||||
const day = dateStr.substring(6, 8)
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
return dateStr
|
||||
}
|
||||
// 获取任务列表
|
||||
const getTaskList = async () => {
|
||||
try {
|
||||
const res = await axios.post('http://192.168.15.56:8890/api/v1/level_five/overview/view_tasks', {}, {
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + localStorage.getItem('token')
|
||||
}
|
||||
})
|
||||
console.log(888888,res)
|
||||
if (res.data.code === 200) {
|
||||
actions.value = res.data.data.tasks || res.data.data
|
||||
console.log(777777,actions.value)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取任务列表失败:', error)
|
||||
}
|
||||
}
|
||||
// 修改任务状态按钮点击事件
|
||||
const changeTaskStatus = (task) => {
|
||||
const statusOptions = ['待处理', '正在处理', '已完成']
|
||||
const currentIndex = statusOptions.indexOf(task.state)
|
||||
const nextIndex = (currentIndex + 1) % statusOptions.length
|
||||
const newState = statusOptions[nextIndex]
|
||||
|
||||
return filtered.filter(action => !action.completed)
|
||||
})
|
||||
updateTaskState(task.task_id, newState)
|
||||
}
|
||||
|
||||
// 已完成数量
|
||||
const completedCount = computed(() => {
|
||||
return actions.value.filter(action => action.completed).length
|
||||
})
|
||||
|
||||
|
||||
|
||||
// 格式化截止日期
|
||||
const formatDueDate = (dueDate) => {
|
||||
const date = new Date(dueDate)
|
||||
const today = new Date()
|
||||
const diffTime = date - today
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (diffDays < 0) {
|
||||
return `逾期${Math.abs(diffDays)}天`
|
||||
} else if (diffDays === 0) {
|
||||
return '今天到期'
|
||||
} else if (diffDays === 1) {
|
||||
return '明天到期'
|
||||
} else {
|
||||
return `${diffDays}天后到期`
|
||||
// 修改任务状态 http://192.168.15.56:8890/api/v1/level_four/overview/update_task_state
|
||||
const updateTaskState = async (taskId, state) => {
|
||||
try {
|
||||
const res = await axios.put('http://192.168.15.56:8890/api/v1/level_four/overview/update_task_state', {
|
||||
task_ids: [taskId],
|
||||
new_state: state
|
||||
}, {
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + localStorage.getItem('token')
|
||||
}
|
||||
})
|
||||
if (res.data.code === 200) {
|
||||
console.log('任务状态更新成功')
|
||||
// 刷新任务列表
|
||||
await getTaskList()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新任务状态失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +206,9 @@ const addAction = () => {
|
||||
|
||||
showAddForm.value = false
|
||||
}
|
||||
onMounted(async () => {
|
||||
await getTaskList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -269,57 +271,22 @@ const addAction = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 统计概览
|
||||
.actions-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
.summary-item {
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
|
||||
&.urgent {
|
||||
background: #fef2f2;
|
||||
border: 1px solid #fecaca;
|
||||
}
|
||||
|
||||
&.high {
|
||||
background: #fef3c7;
|
||||
border: 1px solid #fed7aa;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
background: #eff6ff;
|
||||
border: 1px solid #bfdbfe;
|
||||
}
|
||||
|
||||
&.completed {
|
||||
background: #f0fdf4;
|
||||
border: 1px solid #bbf7d0;
|
||||
}
|
||||
|
||||
.summary-count {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #1f2937;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
font-size: 0.8rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 事项列表
|
||||
.actions-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
.no-tasks {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: #999;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.action-item {
|
||||
display: flex;
|
||||
padding: 1rem;
|
||||
@@ -334,43 +301,23 @@ const addAction = () => {
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
border-color: #d0d0d0;
|
||||
}
|
||||
|
||||
&.urgent {
|
||||
border-left: 4px solid #ef4444;
|
||||
}
|
||||
|
||||
&.high {
|
||||
&.status-pending {
|
||||
border-left: 4px solid #f59e0b;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
&.status-processing {
|
||||
border-left: 4px solid #3b82f6;
|
||||
}
|
||||
|
||||
&.low {
|
||||
&.status-completed {
|
||||
border-left: 4px solid #10b981;
|
||||
}
|
||||
|
||||
&.completed {
|
||||
opacity: 0.6;
|
||||
opacity: 0.8;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
&.overdue {
|
||||
background: #fef2f2;
|
||||
}
|
||||
|
||||
.action-checkbox {
|
||||
margin-right: 1rem;
|
||||
|
||||
.checkbox {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.action-content {
|
||||
flex: 1;
|
||||
|
||||
@@ -385,53 +332,54 @@ const addAction = () => {
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
margin: 0;
|
||||
|
||||
&.completed {
|
||||
text-decoration: line-through;
|
||||
color: #9ca3af;
|
||||
}
|
||||
flex: 1;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.action-meta {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
.priority-badge {
|
||||
.status-badge {
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
|
||||
&.urgent {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
&.status-pending {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
border: 1px solid #ffeaa7;
|
||||
}
|
||||
|
||||
&.high {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
&.status-processing {
|
||||
background: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border: 1px solid #bee5eb;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
background: #dbeafe;
|
||||
color: #1e40af;
|
||||
&.status-completed {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
&.low {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
&.status-default {
|
||||
background: #f8f9fa;
|
||||
color: #6c757d;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
}
|
||||
|
||||
.due-date {
|
||||
font-size: 0.8rem;
|
||||
color: #6b7280;
|
||||
|
||||
&.overdue {
|
||||
color: #ef4444;
|
||||
font-weight: 600;
|
||||
}
|
||||
font-size: 0.75rem;
|
||||
color: #666;
|
||||
background: #f8f9fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,102 +392,23 @@ const addAction = () => {
|
||||
}
|
||||
|
||||
.action-details {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
gap: 8px;
|
||||
font-size: 0.8rem;
|
||||
color: #888;
|
||||
|
||||
.detail-label {
|
||||
font-size: 0.8rem;
|
||||
color: #9ca3af;
|
||||
font-weight: 500;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 0.8rem;
|
||||
color: #374151;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.progress-mini {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
.progress-bar-mini {
|
||||
width: 60px;
|
||||
height: 4px;
|
||||
background: #f3f4f6;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
|
||||
.progress-fill-mini {
|
||||
height: 100%;
|
||||
background: #3b82f6;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-text-mini {
|
||||
font-size: 0.75rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.action-tags {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
.tag {
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: #f3f4f6;
|
||||
color: #6b7280;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
.btn-edit, .btn-delete {
|
||||
padding: 0.25rem 0.75rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
|
||||
&:hover {
|
||||
background: #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
|
||||
&:hover {
|
||||
background: #fecaca;
|
||||
}
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -547,6 +416,8 @@ const addAction = () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 空状态
|
||||
.empty-state {
|
||||
display: flex;
|
||||
@@ -698,42 +569,116 @@ const addAction = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端适配
|
||||
@media (max-width: 768px) {
|
||||
.action-items {
|
||||
padding: 1rem;
|
||||
// 任务列表样式
|
||||
.task-list {
|
||||
.task-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
|
||||
.actions-header {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
align-items: flex-start;
|
||||
&:hover {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
.actions-summary {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
.task-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
margin-right: 16px;
|
||||
|
||||
.task-row-1, .task-row-2 {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.task-row-1 {
|
||||
.task-title {
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
font-size: 14px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.task-content {
|
||||
color: #6b7280;
|
||||
font-size: 13px;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.task-row-2 {
|
||||
.task-date, .task-created {
|
||||
color: #9ca3af;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-item {
|
||||
.action-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
.task-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.status-tag {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.pending {
|
||||
background-color: #fef3c7;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
&.in-progress {
|
||||
background-color: #dbeafe;
|
||||
color: #2563eb;
|
||||
}
|
||||
|
||||
&.completed {
|
||||
background-color: #d1fae5;
|
||||
color: #059669;
|
||||
}
|
||||
}
|
||||
|
||||
.action-details {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.action-footer {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
.status-btn {
|
||||
padding: 6px 12px;
|
||||
background-color: #3b82f6;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #2563eb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
.form-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.no-tasks {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
// 移动端适配
|
||||
@media (max-width: 768px) {
|
||||
.task-list {
|
||||
.task-row {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
|
||||
.task-actions {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,16 +716,16 @@ const conversionRateVsAverage = ref({})
|
||||
await CenterCampPeriodAdmin()
|
||||
}
|
||||
// CenterCampPeriodAdmin中已经调用了recalculateStageDates,这里不需要重复调用
|
||||
await CenterOverallCenterPerformance()
|
||||
await CenterTotalGroupCount()
|
||||
await CenterConversionRate()
|
||||
await CenterTotalCallCount()
|
||||
await CenterNewCustomer()
|
||||
await CenterDepositConversionRate()
|
||||
await CenterCustomerType()
|
||||
await CenterUrgentNeedToAddress()
|
||||
await CenterConversionRateVsAverage()
|
||||
await CenterSeniorManagerList()
|
||||
// await CenterOverallCenterPerformance()
|
||||
// await CenterTotalGroupCount()
|
||||
// await CenterConversionRate()
|
||||
// await CenterTotalCallCount()
|
||||
// await CenterNewCustomer()
|
||||
// await CenterDepositConversionRate()
|
||||
// await CenterCustomerType()
|
||||
// await CenterUrgentNeedToAddress()
|
||||
// await CenterConversionRateVsAverage()
|
||||
// await CenterSeniorManagerList()
|
||||
|
||||
|
||||
// await CenterGroupList('all') // 初始化加载全部高级经理数据
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="task-list compact">
|
||||
<div v-for="task in tasks.slice(0, 3)" :key="task.id" class="task-item">
|
||||
<div v-for="task in tasks.slice(0, 10)" :key="task.id" class="task-item">
|
||||
<div class="task-content">
|
||||
<div class="task-title">{{ task.title }}</div>
|
||||
<div class="task-meta" style="display: flex; gap: 15px;">
|
||||
<span class="assignee">分配给: {{ task.assignee }}</span>
|
||||
<span class="deadline">截止: {{ formatDate(task.deadline) }}</span>
|
||||
<span class="deadline">创建时间: {{ formatDate(task.created_at) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="task-status" :class="task.status">
|
||||
|
||||
@@ -158,8 +158,7 @@ import DataDetail from "./components/DataDetail.vue";
|
||||
import CampManagement from "./components/CampManagement.vue";
|
||||
import DetailedDataTable from "./components/DetailedDataTable.vue";
|
||||
import { getOverallCompanyPerformance,getCompanyDepositConversionRate,getCompanyTotalCallCount,getCompanyNewCustomer,getCompanyConversionRate,getCompanyRealTimeProgress
|
||||
,getCompanyConversionRateVsLast,getSalesMonthlyPerformance,getCustomerTypeDistribution,getUrgentNeedToAddress,getLevelTree,getDetailedDataTable,assignTasks
|
||||
} from "@/api/top";
|
||||
,getCompanyConversionRateVsLast,getSalesMonthlyPerformance,getCustomerTypeDistribution,getUrgentNeedToAddress,getLevelTree,getDetailedDataTable,assignTasks } from "@/api/top";
|
||||
|
||||
const rankingPeriod = ref("month");
|
||||
const rankingData = ref([
|
||||
@@ -187,6 +186,101 @@ const newTask = reactive({
|
||||
deadline: "",
|
||||
description: "",
|
||||
});
|
||||
// 获取任务列表
|
||||
const getTaskList = async () => {
|
||||
try {
|
||||
const res = await axios.post('http://192.168.15.56:8890/api/v1/level_five/overview/view_tasks', {}, {
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + localStorage.getItem('token')
|
||||
}
|
||||
})
|
||||
console.log(888888,res)
|
||||
if (res.data.code === 200) {
|
||||
const apiTasks = res.data.data.tasks || res.data.data
|
||||
// 将API数据格式转换为TaskList组件期望的格式
|
||||
tasks.value = apiTasks.map(task => ({
|
||||
id: task.task_id,
|
||||
title: task.task_title,
|
||||
assignee: task.assignee || '未分配',
|
||||
deadline: task.expiration_date,
|
||||
status: task.state === '待处理' ? 'pending' : task.state === '正在处理' ? 'in-progress' : 'completed',
|
||||
description: task.task_content,
|
||||
created_at: task.created_at
|
||||
}))
|
||||
console.log(777777,tasks.value)
|
||||
/**
|
||||
* tasks
|
||||
:
|
||||
[,…]
|
||||
0
|
||||
:
|
||||
{task_id: "1755748690560728_22d55cc618784537973481228a15956a", task_title: "55", task_content: "222",…}
|
||||
created_at
|
||||
:
|
||||
"2025-08-21 11:58:10"
|
||||
expiration_date
|
||||
:
|
||||
"20250808"
|
||||
state
|
||||
:
|
||||
"待处理"
|
||||
task_content
|
||||
:
|
||||
"222"
|
||||
task_id
|
||||
:
|
||||
"1755748690560728_22d55cc618784537973481228a15956a"
|
||||
task_title
|
||||
:
|
||||
"55"
|
||||
1
|
||||
:
|
||||
{task_id: "1755745331126891_650206e5b6d345699de3e3e406a2600e", task_title: "测试任务",…}
|
||||
created_at
|
||||
:
|
||||
"2025-08-21 11:02:11"
|
||||
expiration_date
|
||||
:
|
||||
"121221"
|
||||
state
|
||||
:
|
||||
"待处理"
|
||||
task_content
|
||||
:
|
||||
"测试任务"
|
||||
task_id
|
||||
:
|
||||
"1755745331126891_650206e5b6d345699de3e3e406a2600e"
|
||||
task_title
|
||||
:
|
||||
"测试任务"
|
||||
2
|
||||
:
|
||||
{task_id: "1755745330094989_528dd87dc13a4a5bb33c9c272fb1a482", task_title: "测试任务",…}
|
||||
created_at
|
||||
:
|
||||
"2025-08-21 11:02:10"
|
||||
expiration_date
|
||||
:
|
||||
"121221"
|
||||
state
|
||||
:
|
||||
"已完成"
|
||||
task_content
|
||||
:
|
||||
"测试任务"
|
||||
task_id
|
||||
:
|
||||
"1755745330094989_528dd87dc13a4a5bb33c9c272fb1a482"
|
||||
task_title
|
||||
:
|
||||
"测试任务"
|
||||
*/
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取任务列表失败:', error)
|
||||
}
|
||||
}
|
||||
// 下拉框人员
|
||||
const assigneeOptions = ref([]);
|
||||
async function name() {
|
||||
@@ -203,34 +297,6 @@ async function name() {
|
||||
} catch (error) {
|
||||
console.error('获取下属人员列表失败:', error);
|
||||
}
|
||||
/**
|
||||
* "data": [
|
||||
{
|
||||
"name": "程琦",
|
||||
"wechat_id": "1688856301330784"
|
||||
},
|
||||
{
|
||||
"name": "潘加俊",
|
||||
"wechat_id": "1688855836721980"
|
||||
},
|
||||
{
|
||||
"name": "伍晶晶",
|
||||
"wechat_id": "1688854476805987"
|
||||
},
|
||||
{
|
||||
"name": "张三丰",
|
||||
"wechat_id": "1212345648513"
|
||||
},
|
||||
{
|
||||
"name": "朱一航",
|
||||
"wechat_id": "1212345648513"
|
||||
},
|
||||
{
|
||||
"name": "王卓琳",
|
||||
"wechat_id": "1212345648513"
|
||||
}
|
||||
]
|
||||
*/
|
||||
}
|
||||
// 计算属性
|
||||
const filteredTableData = computed(() => {
|
||||
@@ -329,7 +395,17 @@ const formatTime = (timestamp) => {
|
||||
};
|
||||
|
||||
const formatDate = (dateString) => {
|
||||
return new Date(dateString).toLocaleDateString("zh-CN");
|
||||
if (!dateString) return '';
|
||||
// 处理 "2025-08-21 11:58:10" 格式的时间字符串
|
||||
try {
|
||||
const date = new Date(dateString.replace(' ', 'T'));
|
||||
if (isNaN(date.getTime())) {
|
||||
return dateString; // 如果解析失败,返回原字符串
|
||||
}
|
||||
return date.toLocaleDateString("zh-CN");
|
||||
} catch (error) {
|
||||
return dateString;
|
||||
}
|
||||
};
|
||||
|
||||
const formatDuration = (minutes) => {
|
||||
@@ -643,6 +719,7 @@ onMounted(async() => {
|
||||
// 页面初始化逻辑
|
||||
await getRealTimeProgress()
|
||||
await getTotalDeals()
|
||||
await getTaskList()
|
||||
await getConversionComparison('month')
|
||||
await getCompanySalesRank('red')
|
||||
await getCustomerTypeRatio('child_education')
|
||||
|
||||
Reference in New Issue
Block a user