finyx_data_frontend/src/pages/ProjectListView.vue

147 lines
6.2 KiB
Vue

<template>
<div class="p-8 bg-slate-50 min-h-screen animate-fade-in">
<!-- Header -->
<div class="flex justify-between items-center mb-8">
<div>
<h1 class="text-2xl font-bold text-slate-900">项目列表 (Projects)</h1>
<p class="text-slate-500 text-sm mt-1">管理所有正在进行和已交付的咨询项目</p>
</div>
<div class="flex space-x-4">
<div class="relative">
<Search :size="18" class="absolute left-3 top-2.5 text-slate-400" />
<input
type="text"
placeholder="搜索项目、客户..."
class="pl-10 pr-4 py-2 bg-white border border-slate-200 rounded-md text-sm w-64 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
/>
</div>
<!-- New Project Button -> Goes to Engagement Setup -->
<button
@click="handleNewProject"
class="flex items-center px-4 py-2 bg-blue-600 text-white rounded-md shadow-sm text-sm font-bold hover:bg-blue-700 transition-colors"
>
<Plus :size="18" class="mr-2" /> 新建项目
</button>
</div>
</div>
<!-- Projects Table -->
<div class="bg-white rounded-lg border border-slate-200 shadow-sm overflow-hidden">
<div class="px-6 py-4 border-b border-slate-100 flex justify-between items-center bg-slate-50/50">
<div class="flex space-x-4">
<span class="text-sm font-bold text-slate-800 border-b-2 border-blue-500 pb-1 cursor-pointer">全部项目 (12)</span>
<span class="text-sm font-medium text-slate-500 hover:text-slate-700 cursor-pointer">进行中</span>
<span class="text-sm font-medium text-slate-500 hover:text-slate-700 cursor-pointer">已完成</span>
</div>
<button class="text-slate-400 hover:text-slate-600"><Settings :size="16" /></button>
</div>
<table class="min-w-full text-left text-sm">
<thead class="bg-slate-50 text-slate-500 font-medium">
<tr>
<th class="px-6 py-3">项目名称</th>
<th class="px-6 py-3">客户名称</th>
<th class="px-6 py-3">项目类型</th>
<th class="px-6 py-3">项目进度</th>
<th class="px-6 py-3">负责人</th>
<th class="px-6 py-3">最近更新</th>
<th class="px-6 py-3 text-right">操作</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
<tr
v-for="project in projectsList"
:key="project.id"
class="hover:bg-slate-50 transition-colors group cursor-pointer"
@click="handleProjectClick(project, $event)"
>
<td class="px-6 py-4">
<div class="flex items-center">
<div class="w-8 h-8 rounded bg-blue-50 flex items-center justify-center text-blue-600 mr-3">
<Layers :size="16"/>
</div>
<div class="font-bold text-slate-800">{{ project.name }}</div>
</div>
</td>
<td class="px-6 py-4 text-slate-600">
{{ project.client }}
</td>
<td class="px-6 py-4">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-slate-100 text-slate-600">
{{ project.type }}
</span>
</td>
<td class="px-6 py-4 w-48">
<div class="flex items-center justify-between mb-1 text-xs text-slate-500">
<span>{{ project.progress }}%</span>
</div>
<ProgressBar :percent="project.progress" :status="project.status" />
</td>
<td class="px-6 py-4 text-slate-600">
<div class="flex items-center">
<div class="w-5 h-5 rounded-full bg-slate-200 text-xs flex items-center justify-center mr-2">{{ project.owner[0] }}</div>
{{ project.owner }}
</div>
</td>
<td class="px-6 py-4 text-slate-400 text-xs">
{{ project.lastUpdate }}
</td>
<td class="px-6 py-4 text-right" @click.stop>
<button
@click="() => handleProjectClick(project)"
class="text-blue-600 hover:text-blue-800 font-medium text-xs mr-3"
>
进入作业
</button>
<button class="text-slate-400 hover:text-slate-600"><MoreHorizontal :size="16" /></button>
</td>
</tr>
</tbody>
</table>
<!-- Pagination Mockup -->
<div class="px-6 py-4 border-t border-slate-100 flex items-center justify-between bg-slate-50/30">
<span class="text-xs text-slate-500">显示 1-5 12 条记录</span>
<div class="flex space-x-1">
<button class="px-3 py-1 border border-slate-200 rounded text-xs text-slate-600 hover:bg-slate-100 disabled:opacity-50">上一页</button>
<button class="px-3 py-1 border border-slate-200 rounded text-xs text-slate-600 hover:bg-slate-100">下一页</button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { Search, Plus, Settings, MoreHorizontal, Layers } from 'lucide-vue-next';
import ProgressBar from '@/components/ProgressBar.vue';
import { projectsList } from '@/data/mockData';
import type { ViewMode, Step, Project } from '@/types';
interface Props {
setCurrentView: (view: ViewMode) => void;
setCurrentStep: (step: Step) => void;
}
const props = defineProps<Props>();
const handleNewProject = () => {
props.setCurrentStep('setup');
props.setCurrentView('engagement');
};
const handleProjectClick = (project: Project, event?: Event) => {
// Don't trigger if clicking on action buttons (except the "进入作业" button)
if (event) {
const target = event.target as HTMLElement;
// Prevent double-trigger if clicking on other buttons
if (target.closest('button') && !target.closest('button')?.textContent?.includes('进入作业')) {
return;
}
}
// Always go to engagement view with setup step (project configuration)
props.setCurrentView('engagement');
props.setCurrentStep('setup');
};
</script>