Lan hai 1 semana
pai
achega
8923099127

BIN=BIN
scheduler/__pycache__/processManager.cpython-310.pyc


BIN=BIN
scheduler/__pycache__/utils.cpython-310.pyc


BIN=BIN
viewer/src/assets/1.png


BIN=BIN
viewer/src/assets/2.png


BIN=BIN
viewer/src/assets/3.png


BIN=BIN
viewer/src/assets/4.png


+ 18 - 0
viewer/src/router/index.ts

@@ -54,6 +54,24 @@ const router = createRouter({
         {
           path: 'monitor',
           component: () => import('../views/dashoard/monitor.vue'),
+        },
+        {
+          path:'profile',
+          component: () => import('../views/dashoard/profile.vue'),
+        },
+        {
+          path:'graphicfile',
+          component: () => import('../views/dashoard/graphicfile.vue'),
+        },
+        {
+          path:'taskfile',
+          // 修改为已有的missionsviewer
+          component: () => import('../views/dashoard/view.vue'),
+        },
+        {
+          path:'networkfile',
+          // 修改为已有的missionsviewer
+          component: () => import('../views/dashoard/networkfile.vue'),
         }
       ]
     }

+ 12 - 0
viewer/src/store/userInfo.js

@@ -106,9 +106,21 @@ export function useUserInfo() {
         }
     }
 
+    const logout = () => {
+        // 清空缓存用户信息
+        sessionStorage.set('user-info', '')
+        // 清空当前用户信息
+        userInfo.value = {
+            username: '',
+            displayname: '',
+            identity: '',
+        }
+    }
+
     return {
         userInfo,
         register,
         login,
+        logout,
     }
 }

+ 11 - 0
viewer/src/types.d.ts

@@ -0,0 +1,11 @@
+declare module "@/store/userInfo.js"
+declare module "@/store/analyzeInfo.js"
+
+declare module "@/views/login/login_container.vue"
+declare module "@/views/dashoard/dashboard.vue"
+declare module "@/views/dashoard/select.vue"
+declare module "@/views/dashoard/analyze.vue"
+declare module "@/views/dashoard/plan.vue"
+declare module "@/views/dashoard/calculate.vue"
+declare module "@/views/dashoard/view.vue"
+declare module "@/views/dashoard/monitor.vue"

+ 1 - 113
viewer/src/views/dashoard/analyze.vue

@@ -131,51 +131,6 @@
           <div v-else >
             <router-view></router-view>
           </div>
-
-        </el-card>
-
-        <!-- 历史文件列表 -->
-        <el-card class="history-section">
-          <h3>历史上传记录</h3>
-          <el-table :data="fileHistory" style="width: 100%">
-            <el-table-column label="" width="40">
-              <template #default="scope">
-                <el-button v-if="scope.row.content == 'node'" type="primary"
-                  style="width: 20px; height:20px; padding: 2px;">N</el-button>
-                <el-button v-if="scope.row.content == 'edge'" type="warning"
-                  style="width: 20px; height:20px; padding: 2px;">E</el-button>
-              </template>
-            </el-table-column>
-            <el-table-column prop="fileName" label="文件名" width="180" />
-            <el-table-column prop="uploadTime" label="上传时间" width="180" />
-            <el-table-column prop="fileSize" label="文件大小">
-            </el-table-column>
-
-            <el-table-column label="分析记录">
-              <template #default="{ row }">
-                <el-dropdown>
-                  <span class="analysis-records">
-                    查看记录<el-icon><arrow-down /></el-icon>
-                  </span>
-                  <template #dropdown>
-                    <el-dropdown-menu>
-                      <el-dropdown-item v-for="(record, index) in row.records" :key="index">
-                        {{ record.time }} - {{ record.type }}
-                      </el-dropdown-item>
-                    </el-dropdown-menu>
-                  </template>
-                </el-dropdown>
-              </template>
-            </el-table-column>
-
-            <el-table-column label="操作" width="120">
-              <template #default="{ row }">
-                <el-button type="danger" size="small" @click="handleDeleteFile(row)" plain>
-                  删除
-                </el-button>
-              </template>
-            </el-table-column>
-          </el-table>
         </el-card>
       </el-col>
 
@@ -234,7 +189,7 @@ const edgeFile = ref(null)
 const nodes = ref([{ id: 1, type: '', name: '' }])
 const edges = ref([{ from: '', to: '' }])
 
-const fileHistory = ref([])
+
 const router = useRouter()
 
 
@@ -487,60 +442,6 @@ const preparePlan = (response) => {
   updateUploadHistory()
 }
 
-
-const handleDeleteFile = (file) => {
-  ElMessageBox.confirm(
-    `确定要删除文件 ${file.fileName} 吗?此操作不可恢复。`,
-    '警告',
-    {
-      confirmButtonText: '确定',
-      cancelButtonText: '取消',
-      type: 'warning'
-    }
-  ).then(() => {
-    deleteData('/uploadfile/', { id: file.id }).then(response => {
-      if (response.status == 'success') {
-        ElMessage.success('文件已删除')
-        updateUploadHistory()
-      } else {
-        ElMessage.error('文件删除失败' + response.message)
-      }
-    })
-      .catch(error => {
-        ElMessage.error('文件删除失败');
-        console.log(error)
-      })
-  }).catch(() => { })
-}
-
-const updateUploadHistory = () => {
-  getData('/uploadfile/')
-    .then(response => {
-      fileHistory.value = []
-      response.data.reverse().forEach(item => {
-        fileHistory.value.push({
-          id: item.id,
-          content: item.content,
-          fileName: item.name,
-          uploadTime: item.uploadTime.split('.')[0].replace('T', ' '),
-          fileSize: item.size,
-          records: []
-        })
-      })
-      // history.forEach(element => {
-      //   console.log(element.uploadTime.replace('T', ' ').aplit('.')[0])
-      // });
-      console.log(fileHistory.value)
-    })
-    .catch(error => {
-      ElMessage.error('获取上传历史失败')
-      console.log(error)
-    })
-}
-
-onMounted(() => {
-  updateUploadHistory();
-})
 </script>
 
 <style lang="scss" scoped>
@@ -587,20 +488,7 @@ onMounted(() => {
     }
   }
 
-  .history-section {
-    h3 {
-      margin-bottom: 15px;
-      color: var(--el-text-color-primary);
-    }
 
-    .analysis-records {
-      cursor: pointer;
-      color: var(--el-color-primary);
-      display: flex;
-      align-items: center;
-      gap: 5px;
-    }
-  }
 
   .instruction-section {
     height: 100%;

+ 7 - 7
viewer/src/views/dashoard/dashboard.vue

@@ -13,13 +13,14 @@
         <div class="right-nav">
           <el-dropdown>
             <span class="user-name">
-              {{ userName }}<el-icon><arrow-down /></el-icon>
+              {{ useUserInfo.userInfo.value.username }}<el-icon><arrow-down /></el-icon>
             </span>
             <template #dropdown>
               <el-dropdown-menu>
                 <el-dropdown-item @click="handleMenu('message')">我的消息</el-dropdown-item>
-                <el-dropdown-item @click="handleMenu('graph')">我的图形文件</el-dropdown-item>
-                <el-dropdown-item @click="handleMenu('task')">我的分析任务</el-dropdown-item>
+                <el-dropdown-item @click="handleMenu('graphicfile')">我的图形数据</el-dropdown-item>
+                <el-dropdown-item @click="handleMenu('taskfile')">我的分析任务</el-dropdown-item>
+                <el-dropdown-item @click="handleMenu('networkfile')">我的上传文件</el-dropdown-item>
                 <el-dropdown-item @click="handleMenu('profile')">个人中心</el-dropdown-item>
                 <el-dropdown-item divided @click="logout">退出登录</el-dropdown-item>
               </el-dropdown-menu>
@@ -42,14 +43,12 @@ import { useRouter } from 'vue-router'
 import { ArrowDown } from '@element-plus/icons-vue'
 
 const useUserInfo = inject('userInfo');
-
 const router = useRouter()
 const hoverLeft = ref(false)
 const hoverRight = ref(false)
 const defaultPage = ref(true)
-const userName = useUserInfo.userInfo.value.username; // 从登录信息获取
 
-// 随机生成SVG logo
+// logo
 const randomSVG = computed(() => {
   const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C']
   return `
@@ -66,11 +65,12 @@ const goHome = () => {
 
 const handleMenu = (type) => {
   // 处理菜单点击
-  console.log('Menu clicked:', type)
+  router.push(`/dashboard/${type}`)
 }
 
 const logout = () => {
   // 处理退出登录
+  useUserInfo.logout()
   router.push({name: 'login'})
 }
 

+ 154 - 0
viewer/src/views/dashoard/graphicfile.vue

@@ -0,0 +1,154 @@
+<template>
+  <div class="app-container">
+    <el-table
+      :data="currentPageData"
+      border
+      stripe
+      style="width: 100%; height: 95%"
+      height="calc(100vh - 120px)"
+    >
+      <el-table-column fixed type="index" label="序号" align="center" width="80">
+      <template #default="{ $index }">
+      {{(currentPage - 1) * pageSize + $index + 1 }}
+      </template>
+      </el-table-column>
+      <el-table-column prop="nodes" label="节点组" width="450" align="center">
+        <template #default="{ row }">
+          <span class="download-link" @click="downloadCSV(row)">
+            {{ row.name }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="edges" label="边组" width="450" align="center" />
+      <el-table-column prop="type" label="类型" width="180" align="center" >
+        <template #default="{ row }">
+          <el-tag :type="typeTagMap[row.type] || 'info'">
+            {{ row.type }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="createTime" label="创建时间" width="280" sortable align="center"/>
+      <el-table-column prop="updateTime" label="修改时间" width="280" sortable align="center"/>
+      <el-table-column prop="userId" label="用户ID" width="120" align="center" />
+    </el-table>
+    <div class="pagination-container">
+          <el-pagination background layout="total, sizes, prev, pager, next" :page-sizes="[8, 16, 24]"
+            :current-page="currentPage" :page-size="pageSize" :total="total"
+            @size-change="handleSizeChange" @current-change="handleCurrentChange" class="pagination" />
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, onMounted , inject } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useRouter } from 'vue-router'
+import { getData, postData, deleteData, postFile } from '@/api/axios.js'
+ 
+// 数据列表
+const items = ref([])
+
+// 获取数据逻辑修复
+const fetchFiles = async () => {
+  try {
+    const response = await getData('/selectGraphic/')
+    if (response.status === "success" && response.data?.length) {
+      items.value = response.data //  直接赋值数组
+      total.value = response.data.length //  动态设置总数
+    }
+  } catch (error) { 
+    console.error('获取图形列表失败:', error)
+    ElMessage.error('数据加载失败')
+  }
+}
+
+//请求获取数据
+onMounted(() => {
+  fetchFiles()
+})
+
+const typeTagMap = {
+  Storage: 'success',
+  Compute: 'warning',
+  Network: 'danger',
+  Database: 'primary'
+};
+
+const currentPage = ref(1)
+const pageSize = ref(10)
+const total = ref(0)
+
+const currentPageData = computed(() => {
+  if (!items.value.length) return []
+  const start = (currentPage.value - 1) * pageSize.value
+  const end = start + pageSize.value
+  const itemlist =  items.value.slice(start, end)
+  for(let i = 0; i < itemlist.length; i++)
+  {
+    itemlist[i].createTime = new Date(itemlist[i].createTime).toLocaleString('zh-CN');
+    itemlist[i].updateTime = new Date(itemlist[i].updateTime).toLocaleString('zh-CN');
+  }
+  return itemlist
+})
+
+// CSV 下载功能
+const downloadCSV = async (row) => {
+  debugger
+  const response = await postData('/downloadGraphic/',{
+        id:row.id
+      })
+  try{
+    if(response.status === "success")
+    {
+      const url = window.URL.createObjectURL(new Blob([response.data]));
+      const link = document.createElement('a');
+      link.href = url;
+      link.setAttribute('download', filename);
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+      window.URL.revokeObjectURL(url);
+    }else
+    {
+      ElMessage.error('下载失败');
+    }
+  } catch (error) {
+    ElMessage.error('下载失败')
+  }
+}
+// 分页事件处理
+const handleSizeChange = (size) => {
+  pageSize.value = size
+  currentPage.value = 1
+}
+
+const handleCurrentChange = (page) => {
+  currentPage.value = page
+}
+</script>
+
+<style scoped>
+.app-container {
+  padding: 20px;
+}
+
+.pagination-container {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.download-link {
+  cursor: pointer;
+  color: #409eff;
+  text-decoration: underline;
+}
+
+.download-link:hover {
+  color: #79bbff;
+}
+
+.mr-2 {
+  margin-right: 0.5rem;
+}
+</style>

+ 133 - 0
viewer/src/views/dashoard/networkfile.vue

@@ -0,0 +1,133 @@
+<template>
+    <div>
+        <!-- 历史文件列表 -->
+        <el-card class="history-section">
+            <h3>历史上传记录</h3>
+            <el-table :data="fileHistory" style="width: 100%">
+                <el-table-column prop="mission.name" label="分析任务" width="260"/>
+                <el-table-column prop="mission.id" label="任务ID" width="260"/>
+
+                <el-table-column label="" width="40">
+                    <template #default="scope">
+                        <el-button v-if="scope.row.content == 'node'" type="primary"
+                            style="width: 20px; height:20px; padding: 2px;">N</el-button>
+                        <el-button v-if="scope.row.content == 'edge'" type="warning"
+                            style="width: 20px; height:20px; padding: 2px;">E</el-button>
+                    </template>
+                </el-table-column>
+                <el-table-column prop="fileName" label="文件名" width="280" />
+                <el-table-column prop="uploadTime" label="上传时间" width="280" />
+                <el-table-column prop="fileSize" label="文件大小" width="280">
+                </el-table-column>
+
+                <el-table-column label="文件信息" width="280">
+                    <template #default="{ row }">
+                        <el-dropdown>
+                            <span v-if="row.content === 'node'" class="analysis-records">
+                                {{ '节点总数:' + row.fileInfo.节点总数 }}<el-icon><arrow-down /></el-icon>
+                            </span>
+                            <span v-else class="analysis-records">
+                                {{ '边总数:' + row.fileInfo.边总数 }}<el-icon><arrow-down /></el-icon>
+                            </span>
+                            <template #dropdown>
+                                <el-dropdown-menu>
+                                    <el-dropdown-item v-for="(value, key) in row.fileInfo" :key="key">
+                                        {{ key }} - {{ value }}
+                                    </el-dropdown-item>
+                                </el-dropdown-menu>
+                            </template>
+                        </el-dropdown>
+                    </template>
+                </el-table-column>
+
+                <el-table-column label="操作" width="120">
+                    <template #default="{ row }">
+                        <el-button type="danger" size="small" @click="handleDeleteFile(row)" plain>
+                            删除
+                        </el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </el-card>
+    </div>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, inject } from 'vue'
+import { useRouter } from 'vue-router'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Upload, ArrowDown, Plus } from '@element-plus/icons-vue'
+import { getData, postData, deleteData, postFile } from '@/api/axios.js'
+const fileHistory = ref([])
+const handleDeleteFile = (file) => {
+  ElMessageBox.confirm(
+    `确定要删除文件 ${file.fileName} 吗?此操作不可恢复。`,
+    '警告',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning'
+    }
+  ).then(() => {
+    deleteData('/uploadfile/', { id: file.id }).then(response => {
+      if (response.status == 'success') {
+        ElMessage.success('文件已删除')
+        updateUploadHistory()
+      } else {
+        ElMessage.error('文件删除失败' + response.message)
+      }
+    })
+      .catch(error => {
+        ElMessage.error('文件删除失败');
+        console.log(error)
+      })
+  }).catch(() => { })
+}
+
+const updateUploadHistory = () => {
+  getData('/uploadfile/')
+    .then(response => {
+      fileHistory.value = []
+      response.data.reverse().forEach(item => {
+        fileHistory.value.push({
+          id: item.id,
+          content: item.content,
+          fileName: item.name,
+          uploadTime: item.uploadTime.split('.')[0].replace('T', ' '),
+          fileSize: item.size,
+          // 按照目前逻辑,每个文件的关联mission应该只有一个
+          mission: item.missions[0],
+          fileInfo: item.fileInfo,
+        })
+      })
+      // history.forEach(element => {
+      //   console.log(element.uploadTime.replace('T', ' ').aplit('.')[0])
+      // });
+      console.log(fileHistory.value)
+    })
+    .catch(error => {
+      ElMessage.error('获取上传历史失败')
+      console.log(error)
+    })
+}
+onMounted(() => {
+  updateUploadHistory();
+})
+</script>
+
+<style lang="scss" scoped>
+  .history-section {
+    h3 {
+      margin-bottom: 15px;
+      color: var(--el-text-color-primary);
+    }
+
+    .analysis-records {
+      cursor: pointer;
+      color: var(--el-color-primary);
+      display: flex;
+      align-items: center;
+      gap: 5px;
+    }
+  }
+</style>

+ 288 - 0
viewer/src/views/dashoard/profile.vue

@@ -0,0 +1,288 @@
+<template>
+    <div class="user-center-container">
+      <!-- 用户信息模块 -->
+      <el-card class="user-info-card">
+        <template #header>
+          <div class="card-header">个人信息</div>
+        </template>
+  
+        <!-- 基本信息表单 -->
+        <el-form
+          ref="userFormRef"
+          :model="userForm"
+          label-width="100px"
+          :rules="userRules"
+        >
+          <el-form-item label="用户名" prop="username">
+            <el-input v-model="userForm.username" />
+          </el-form-item>
+          
+          <el-form-item label="创建时间" prop="createtime"> 
+              <el-date-picker
+                v-model="userForm.createtime"
+                type="datetime"
+                disabled
+                format="YYYY/MM/DD HH:mm:ss"
+              />
+          </el-form-item>
+
+          <el-form-item label="昵称" prop="displayname">
+              <el-input v-model="userForm.displayname" />
+          </el-form-item>
+
+          <el-form-item label="身份" prop="identity">
+            <div class="bind-info">
+              <el-input v-model="userForm.identity" disabled/>
+            </div>
+          </el-form-item>
+          
+          <el-form-item label="最后登录时间" prop="lastlogin">
+            <el-date-picker
+                v-model="userForm.lastlogin"
+                type="datetime"
+                disabled
+                format="YYYY/MM/DD HH:mm:ss"
+              />
+          </el-form-item>
+
+          <el-form-item>
+            <el-button type="primary" @click="submitUserForm">保存修改</el-button>
+          </el-form-item>
+        </el-form>
+      </el-card>
+  
+      <!-- 账户安全模块 -->
+      <el-card class="security-card">
+        <template #header>
+          <div class="card-header">账户安全</div>
+        </template>
+        <el-form
+          ref="pwdFormRef"
+          :model="pwdForm"
+          label-width="100px"
+          :rules="pwdRules"
+        >
+          <el-form-item label="原密码" prop="oldPassword">
+            <el-input
+              v-model="pwdForm.oldPassword"
+              type="password"
+              show-password
+            />
+          </el-form-item>
+  
+          <el-form-item label="新密码" prop="newPassword">
+            <el-input
+              v-model="pwdForm.newPassword"
+              type="password"
+              show-password
+            />
+          </el-form-item>
+  
+          <el-form-item label="确认密码" prop="confirmPassword">
+            <el-input
+              v-model="pwdForm.confirmPassword"
+              type="password"
+              show-password
+            />
+          </el-form-item>
+  
+          <el-form-item>
+            <el-button type="primary" @click="submitPwdForm">修改密码</el-button>
+          </el-form-item>
+        </el-form>
+      </el-card>
+    </div>
+  </template>
+  
+  <script setup>
+  import { onMounted, ref, computed, reactive } from 'vue'
+  import { ElMessage } from 'element-plus'
+  import { getData, postData, deleteData, postFile } from '@/api/axios.js'
+  
+  // 用户信息数据 
+  const userInfo = reactive({
+    username: '',
+    createtime: '',
+    displayname: '',
+    identity: '',
+    lastlogin: ''
+  })
+  
+  // 用户信息表单
+  const userFormRef = ref()
+  const userForm = reactive({
+    username: '',
+    createtime: '',
+    displayname: '',
+    identity: '',
+    lastlogin: ''
+  })
+  let pastUserForm = {}
+
+  // 密码修改表单
+  const pwdFormRef = ref()
+  const pwdForm = reactive({
+    oldPassword: '',
+    newPassword: '',
+    confirmPassword: ''
+  })
+  const userRules = {
+    username: [
+      { required: true, message: '请输入用户名', trigger: 'blur' },
+      { min: 2, max: 12, message: '长度在2到12个字符', trigger: 'blur' }
+    ],
+    displayname: [
+      { message: '请输入昵称', trigger: 'blur' },
+      { min: 2, max: 12, message: '长度在2到12个字符', trigger: 'blur' }
+    ],
+    identity: [
+      { required: true, message: '请输入身份', trigger: 'blur' },
+    ]
+  }
+  
+  const pwdRules = {
+    oldPassword: [
+      { required: true, message: '请输入原密码', trigger: 'blur' }
+    ],
+    newPassword: [
+      { required: true, message: '请输入新密码', trigger: 'blur' },
+      { validator: checkPasswordStrength, trigger: 'blur' }
+    ],
+    confirmPassword: [
+      { validator: (rule, value, callback) => {
+        if (value !== pwdForm.newPassword) {
+          callback(new Error('两次输入密码不一致'))
+        } else {
+          callback()
+        }
+      }, trigger: 'blur' }
+    ]
+  }
+  // 获取初始数据
+  onMounted(async () => {
+    try {
+      const response = await getData('/selectUser/')
+      console.log(response)
+      if(response.status == 'success')
+      {
+        userForm.username = response.data.username,
+        userForm.createtime = new Date(response.data.createtime).toLocaleString('zh-CN');
+        userForm.displayname = response.data.displayname,
+        userForm.identity = response.data.identity,
+        userForm.lastlogin = new Date(response.data.lastlogin).toLocaleString('zh-CN');
+        pastUserForm = userForm
+      }else{
+        ElMessage.error('个人信息查询失败')
+      }
+    } catch (e){
+      ElMessage.error('个人信息查询失败')
+    }
+  })
+
+  // 密码强度校验
+  function checkPasswordStrength(rule, value, callback) {
+  if (value.length < 6 || value.length > 20) { // 使用参数 value
+    callback(new Error('密码长度需为6-20位'))
+  } else {
+    callback()
+  }
+  }
+  
+  // 提交表单
+  const submitUserForm = async () => {
+    try {
+      await userFormRef.value.validate()
+      // 调用API保存数据
+      const response = await postData('/updateUser/',{
+        displayname:userForm.displayname,
+        identity:userForm.identity
+      })
+      if(response.status == 'success')
+      {
+        userForm.username = response.data.username,
+        userForm.createtime = new Date(response.data.createtime).toLocaleString('zh-CN');
+        userForm.displayname = response.data.displayname,
+        userForm.identity = response.data.identity,
+        userForm.lastlogin = new Date(response.data.lastlogin).toLocaleString('zh-CN');
+        pastUserForm = userForm
+        ElMessage.success('个人信息更新成功')
+      }else
+      {
+        userForm.username = pastUserForm.username,
+        userForm.createtime = new Date(pastUserForm.createtime).toLocaleString('zh-CN');
+        userForm.displayname = pastUserForm.displayname,
+        userForm.identity = pastUserForm.identity,
+        userForm.lastlogin = new Date(pastUserForm.lastlogin).toLocaleString('zh-CN');
+        ElMessage.error('个人信息更新失败')
+      }
+    } catch (e) {
+      userForm.username = pastUserForm.username,
+      userForm.createtime = new Date(pastUserForm.createtime).toLocaleString('zh-CN');
+      userForm.displayname = pastUserForm.displayname,
+      userForm.identity = pastUserForm.identity,
+      userForm.lastlogin = new Date(pastUserForm.lastlogin).toLocaleString('zh-CN');
+      ElMessage.error('个人信息更新失败')
+    }
+  }
+  
+  const submitPwdForm = async () => {
+    try {
+      await pwdFormRef.value.validate()
+      // 调用API修改密码
+      const response = await postData('/updatePass/',{
+        oldPassword: pwdForm.oldPassword,
+        newPassword: pwdForm.oldPassword,
+      })
+      if(response.status == 'success')
+      {
+        ElMessage.success('密码修改成功')
+        pwdFormRef.value.resetFields();
+      }
+    } catch (error) {
+      console.error('密码修改失败', error)
+      pwdForm.oldPassword = ''
+      pwdForm.newPassword = ''
+      pwdForm.confirmPassword = ''
+      ElMessage.error("密码修改失败:" + error.response.data.message)
+    }
+  }
+  </script>
+  
+  <style scoped>
+  .user-center-container {
+    max-width: 800px;
+    margin: 20px auto;
+  }
+  
+  .avatar-uploader {
+    text-align: center;
+    margin-bottom: 20px;
+  }
+  
+  .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 120px;
+    height: 120px;
+    line-height: 120px;
+    border: 1px dashed #d9d9d9;
+    border-radius: 50%;
+  }
+  
+  .avatar {
+    width: 120px;
+    height: 120px;
+    border-radius: 50%;
+  }
+  
+  .bind-info {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    width: 100%;
+  }
+  
+  .security-card {
+    margin-top: 20px;
+  }
+  </style>

+ 37 - 14
viewer/src/views/dashoard/select.vue

@@ -4,7 +4,7 @@
       <div class="button-column left-column">
         <div class="action-button" @click="navigateTo('analyze')" @mouseenter="hoverLeft = true"
           @mouseleave="hoverLeft = false">
-          <SvgIcon :name="hoverLeft ? 'analyze-hover' : 'analyze'" />
+          <DataLine class="main-icon"></DataLine>
           <div class="button-text">创建计算任务</div>
         </div>
       </div>
@@ -12,20 +12,22 @@
       <div class="button-column right-column">
         <div class="action-button" @click="navigateTo('view')" @mouseenter="hoverRight = true"
           @mouseleave="hoverRight = false">
-          <SvgIcon :name="hoverRight ? 'view-hover' : 'view'" />
+          <View></View>
           <div class="button-text">查看计算任务</div>
         </div>
       </div>
     </div>
 
     <div v-if="isAdmin" class="admin-section">
-      <div class="button-column center-column">
-        <div class="action-button" @click="navigateTo('monitor')" @mouseenter="hoverAdmin = true"
-          @mouseleave="hoverAdmin = false">
+      <div class="button-column center-column" @click="navigateTo('monitor')" @mouseenter="hoverAdmin = true"
+        @mouseleave="hoverAdmin = false">
+        <div class="action-button">
+
           <div class="admin-content">
-            <SvgIcon :name="hoverAdmin ? 'monitor-hover' : 'monitor'" />
+            <Operation class="admin-icon"></Operation>
             <div class="button-text">系统监控面板</div>
           </div>
+
         </div>
       </div>
     </div>
@@ -36,7 +38,7 @@
 <script setup>
 import { ref, computed, inject, onMounted } from 'vue'
 import { useRouter } from 'vue-router'
-import SvgIcon from '@/components/svgIcon.vue'
+import { DataLine, View, Operation } from '@element-plus/icons-vue'
 
 const router = useRouter();
 const hoverLeft = ref(false)
@@ -64,6 +66,13 @@ onMounted(() => {
   display: flex;
   flex-direction: column;
 
+  .main-icon {
+    width: 40% !important; // 从50%减小到40%
+    height: 40% !important;
+    margin-bottom: 12px; // 增加与文字的间距
+  }
+
+
   .main-buttons {
     flex: 1;
     display: flex;
@@ -104,8 +113,8 @@ onMounted(() => {
         }
 
         svg {
-          width: 50%;
-          height: 50%;
+          width: 40%;
+          height: 40%;
         }
       }
     }
@@ -138,11 +147,25 @@ onMounted(() => {
         box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
         transition: all 0.3s;
 
-        .button-text {
-          margin-top: 24px;
-          font-size: 1.5em;
-          color: #606266;
-          font-weight: 500;
+        .admin-content {
+          display: flex;
+          align-items: center;
+          gap: 12px; // 图标与文字间距
+
+          .admin-icon {
+            width: 44px !important; // 固定尺寸
+            height: 44px !important;
+            flex-shrink: 0;
+          }
+
+          .button-text {
+            margin-top: 0; // 移除原顶部间距
+            font-size: 1.3em; // 微调文字大小
+          }
+        }
+        &:hover {
+          transform: translateY(-5px);
+          box-shadow: 0 12px 32px rgba(0, 0, 0, 0.15);
         }
       }
     }

+ 133 - 0
viewer/src/views/dashoard/taskfile.vue

@@ -0,0 +1,133 @@
+<template>
+    <div class="task-container">
+      <el-table
+        :data="currentPageData"
+        style="width: 100%"
+        stripe
+        row-key="id"
+        v-loading="loading"
+      >
+        <el-table-column fixed type="index" label="序号" align="center" width="60">
+        <template #default="{ $index }">
+        {{(currentPage - 1) * pageSize + $index + 1 }}
+        </template>
+        </el-table-column>
+        <el-table-column prop="name" label="任务名称" width="300" />
+        <el-table-column prop="state" label="状态" width="300" sortable />
+        <el-table-column prop="createTime" label="创建时间" width="300" sortable />
+        <el-table-column prop="updateTime" label="修改时间" width="300" sortable />
+      </el-table>
+
+      <div class="pagination-container">
+      <el-pagination
+        current-page="currentPage"
+        page-size="pageSize"
+        :total="total"
+        layout="total, sizes, prev, pager, next, jumper"
+        :page-sizes="[10, 20, 50, 100]"
+      />
+      </div>
+    </div>
+  </template>
+  
+  <script setup>
+  import { ref, onMounted, computed , inject} from 'vue'
+  import { ElMessage } from 'element-plus' 
+  import { getData , postData } from '@/api/axios.js'
+
+  const userName = inject('userName');
+  // 任务状态枚举
+  const TASK_STATUS = {
+    PENDING: 0,
+    RUNNING: 1,
+    SUCCESS: 2,
+    FAILED: 3
+  }
+  
+  // 模拟任务数据
+  const loading = ref(false)
+  
+// 数据列表
+const items = ref([])
+
+  // 获取数据逻辑修复
+  const fetchTasks = async () => {
+    try {
+      const response = await postData('/selectTask/' , {
+        username:userName
+      })
+      if (response.status === "success" && response.data?.length) {
+        items.value = response.data //  直接赋值数组
+        total.value = response.data.length //  动态设置总数
+      }
+    } catch (error) {
+      console.error('获取任务列表失败:', error)
+      ElMessage.error('数据加载失败')
+    }
+  }
+
+  //请求获取数据
+  onMounted(() => {
+    fetchTasks()
+  })
+  
+  // 分页计算属性
+const currentPage = ref(1)
+const pageSize = ref(10)
+const total = ref(0)
+
+const currentPageData = computed(() => {
+  if (!items.value.length) return []
+  const start = (currentPage.value - 1) * pageSize.value
+  const end = start + pageSize.value
+  const itemlist =  items.value.slice(start, end)
+  for(let i = 0; i < itemlist.length; i++)
+  {
+    itemlist[i].createTime = new Date(itemlist[i].createTime).toLocaleString('zh-CN');
+    itemlist[i].updateTime = new Date(itemlist[i].updateTime).toLocaleString('zh-CN');
+  }
+  return itemlist
+})
+
+  </script>
+  
+  <style scoped>
+  .task-container {
+    padding: 20px;
+  }
+  
+  .log-container {
+    max-height: 300px;
+    overflow-y: auto;
+    padding: 10px;
+    background: #1e1e1e;
+    border-radius: 4px;
+  }
+  
+  .log-item {
+    padding: 4px 0;
+    font-family: monospace;
+    font-size: 12px;
+    color: #d4d4d4;
+  }
+  
+  .log-item.info {
+    color: #9cdcfe;
+  }
+  
+  .log-item.warn {
+    color: #dcdcaa;
+  }
+  
+  .log-item.error {
+    color: #f48771;
+  }
+  
+  .error-content {
+    white-space: pre-wrap;
+    word-break: break-all;
+    padding: 10px;
+    background: #f8f8f8;
+    border-radius: 4px;
+  }
+  </style>