123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- <template>
- <div v-if="showMissions" class="mission-container">
- <el-row :gutter="20" class="grid-container">
- <el-col v-for="mission in currentPageData" :key="mission.id" :xs="24" :sm="12" :md="8" :lg="6">
- <el-tooltip :content="mission.description" placement="bottom" popper-class="mission-tooltip">
- <el-card class="mission-card" @click="handleCardClick(mission.id)">
- <!-- 状态指示灯 -->
- <div class="status-indicator">
- <el-tooltip effect="dark" :content="statusText[mission.status]" placement="top">
- <div class="status-light" :style="{ backgroundColor: statusColor[mission.status] }" />
- </el-tooltip>
- </div>
- <div class="card-content">
- <h3 class="title">{{ mission.name }}</h3>
- <div class="meta">
- <el-icon>
- <Calendar />
- </el-icon>
- <span>{{ formatTime(mission.createTime) }}</span>
- </div>
- <div class="stats">
- <!-- 节点行 -->
- <div class="stat-item node-row">
- <div class="label-box">
- <span class="label">节点</span>
- </div>
- <div class="node-stats">
- <span class="node-count">S:{{ mission.nodesInfo.S }}</span>
- <span class="node-count">D:{{ mission.nodesInfo.D }}</span>
- <span class="node-count">I:{{ mission.nodesInfo.I }}</span>
- </div>
- </div>
- <!-- 边行 -->
- <div class="stat-item edge-row">
- <div class="label-box">
- <span class="label">边</span>
- </div>
- <span class="edge-count">{{ mission.edgesInfo.num }}</span>
- </div>
- </div>
- </div>
- </el-card>
- </el-tooltip>
- </el-col>
- </el-row>
- <!-- 分页控件 -->
- <el-pagination background layout="total, sizes, prev, pager, next" :page-sizes="[8, 16, 24]"
- :current-page="pagination.currentPage" :page-size="pagination.pageSize" :total="pagination.total"
- @size-change="handleSizeChange" @current-change="handleCurrentChange" class="pagination" />
- </div>
- <div v-else>
- <router-view></router-view>
- </div>
- </template>
- <script setup>
- import { ref, reactive, computed, onMounted, inject, onActivated, watch } from 'vue'
- import { useRouter, useRoute } from 'vue-router'
- import { Calendar, User, Connection } from '@element-plus/icons-vue'
- import { postData, getData } from '@/api/axios'
- import { ElMessage } from 'element-plus'
- // 保存选中的mission
- const useAnalyzeInfo = inject('analyzeInfo')
- // 任务数据
- const missions = ref([])
- // 任务状态对应颜色
- const statusColor = {
- 'init': '#ff4d4f', // 未开始或暂停、停止
- 'pause': '#ff4d4f', // 未开始或暂停、停止
- 'calculating': '#faad14', // 计算中
- 'done': '#52c41a' // 已完成
- }
- // 任务状态提示语句
- const statusText = {
- 'init': '尚未执行计算',
- 'pause': '计算暂停中',
- 'calculating': '计算进行中',
- 'done': '计算已完成',
- }
- // 用于控制点击后跳转到plan页面
- const showMissions = ref(false)
- // 分页配置
- const pagination = ref({
- currentPage: 1,
- pageSize: 8,
- total: missions.value.length
- })
- // 当前页数据计算
- const currentPageData = computed(() => {
- const start = (pagination.value.currentPage - 1) * pagination.value.pageSize
- return missions.value.slice(start, start + pagination.value.pageSize)
- })
- // 分页事件处理
- const handleSizeChange = (size) => {
- pagination.pageSize = size
- pagination.value.currentPage = 1
- }
- const handleCurrentChange = (page) => {
- pagination.value.currentPage = page
- }
- // 时间格式化
- const formatTime = (isoString) => {
- return new Date(isoString).toLocaleDateString('zh-CN', {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit'
- })
- }
- // 路由跳转
- const router = useRouter()
- const handleCardClick = (id) => {
- // 检查mission的状态,如果还未计算,则应进入plan界面
- // 如果已经计算,应进入calculate界面
- let mission = missions.value.find(mission => mission.id == id)
- preparePlan(mission)
- if(mission.status === "init"){
- // 初始状态,应进入流程规划
- // 切换显示plan的routeview
- showMissions.value = false
- router.push(`/dashboard/analyze/plan`)
- }else{
- showMissions.value = false
- // 否则进入calculate界面,可查看计算过程或结果
- router.push(`/dashboard/analyze/plan/calculate`)
- }
- }
- const preparePlan = (mission) => {
- useAnalyzeInfo.analyzeInfo.value.nodeFile.amount = mission.nodesInfo.S + mission.nodesInfo.D + mission.nodesInfo.I
- useAnalyzeInfo.analyzeInfo.value.nodeFile.sNodes = mission.nodesInfo.S
- useAnalyzeInfo.analyzeInfo.value.nodeFile.dNodes = mission.nodesInfo.D
- useAnalyzeInfo.analyzeInfo.value.nodeFile.iNodes = mission.nodesInfo.I
- useAnalyzeInfo.analyzeInfo.value.edgeFile.amount = mission.edgesInfo.num
- useAnalyzeInfo.analyzeInfo.value.mission = {
- id: mission.id,
- name: mission.name,
- createTime: mission.createTime,
- status: mission.status,
- }
- console.log(useAnalyzeInfo.analyzeInfo.value)
- // 将获取到的数据写入页面缓存,防止刷新丢失
- sessionStorage.setItem('analyze-info', JSON.stringify(useAnalyzeInfo.analyzeInfo.value))
- }
- //加载数据
- const loadMissions = async () => {
- missions.value = [];
- showMissions.value = true;
- try {
- const response = await getData('/missions/');
- missions.value = response.data.map(mission => ({
- id: mission.id,
- name: mission.name,
- createTime: mission.createTime,
- nodesInfo: mission.nodesInfo,
- edgesInfo: mission.edgesInfo,
- status: mission.status,
- // 需要后续完善描述输入
- description: "This is description",
- })).sort((a, b) => b.id - a.id);
- pagination.value.total = missions.value.length;
- } catch (error) {
- console.error(error);
- ElMessage.error("获取任务列表错误");
- }
- }
- const route = useRoute();
- // 监听路由变化
- watch(
- () => route.path,
- (newPath) => {
- if (newPath === '/dashboard/view' || newPath === '/dashboard/taskfile') {
- showMissions.value = true;
- }
- },
- { immediate: true }
- );
- // 首次加载
- onMounted(loadMissions);
- // 通过后退按钮返回页面时重新加载
- onActivated(loadMissions);
- </script>
- <style scoped lang="scss">
- .mission-container {
- padding: 20px;
- max-width: 1400px;
- margin: 0 auto;
- background: #f8fafc;
- .grid-container {
- min-height: 60vh;
- }
- .mission-card {
- position: relative;
- border: 1px solid #e2e8f0;
- border-radius: 12px;
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
- background: white;
- cursor: pointer;
- overflow: hidden;
- &:hover {
- transform: translateY(-3px);
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.08);
- .title {
- color: var(--el-color-primary);
- }
- }
- .label-box {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 48px;
- height: 24px;
- background: #f1f5f9;
- border: 1px solid #e2e8f0;
- border-radius: 4px;
- margin-right: 8px;
- .label {
- color: #475569;
- font-size: 0.85rem;
- font-weight: 500;
- transform: scale(0.9);
- }
- }
- .status-indicator {
- position: absolute;
- right: 16px;
- top: 16px;
- z-index: 2;
- .status-light {
- width: 12px;
- height: 12px;
- border-radius: 50%;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- position: relative;
- &::after {
- content: '';
- position: absolute;
- inset: 0;
- border-radius: 50%;
- background: inherit;
- filter: brightness(1.2);
- opacity: 0.3;
- }
- }
- }
- .card-content {
- .title {
- font-family: "Microsoft YaHei", system-ui;
- font-weight: 600;
- color: #1e293b;
- margin: 0 0 8px; // 减少上下间距
- font-size: 1.15rem;
- line-height: 1.3;
- position: relative;
- padding-left: 24px;
- &::before {
- content: '📌';
- position: absolute;
- left: -4px;
- top: -2px;
- font-size: 0.9em;
- opacity: 0.8;
- }
- }
- .meta {
- display: flex;
- align-items: center;
- margin-bottom: 12px;
- color: #64748b;
- font-size: 0.9rem;
- .el-icon {
- margin-right: 8px;
- font-size: 1.1em;
- color: #94a3b8;
- }
- }
- .stats {
- .stat-item {
- display: flex;
- align-items: center;
- margin-bottom: 8px;
- &.node-row {
- .node-stats {
- display: flex;
- gap: 12px;
- align-items: center;
- }
- }
- &.edge-row {
- .edge-count {
- color: #334155;
- font-weight: 500;
- }
- }
- }
- }
- }
- .pagination {
- margin-top: 30px;
- justify-content: center;
- ::v-deep(.el-pagination__total) {
- color: #64748b;
- }
- }
- }
- @media (max-width: 768px) {
- .mission-card {
- margin: 8px 0;
- .card-content {
- padding: 12px;
- .title {
- font-size: 1.1rem;
- padding-left: 20px;
- }
- .node-stats {
- flex-wrap: wrap;
- gap: 4px !important;
- span::after {
- display: none !important;
- }
- }
- }
- }
- }
- }
- </style>
|