feat(业务): 我负责的页面

This commit is contained in:
GUjiYN 2024-04-22 17:07:05 +08:00
parent 15f6980876
commit ab4a3d85c0
9 changed files with 2608 additions and 249 deletions

View File

@ -1,213 +0,0 @@
/* eslint-env node */
module.exports = {
'root': true,
'env': {
'browser': true,
'node': true,
'es6': true
},
'parser': 'vue-eslint-parser',
'parserOptions': {
'parser': '@typescript-eslint/parser',
'ecmaVersion': 2020,
'sourceType': 'module',
'jsxPragma': 'React',
'ecmaFeatures': {
'jsx': true,
'tsx': true
}
},
'plugins': ['@typescript-eslint', 'import'],
'extends': [
'plugin:vue/vue3-essential',
'plugin:@typescript-eslint/recommended',
'eslint:recommended'
],
'globals': {
defineEmits: 'readonly',
defineProps: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
WeixinJSBridge: 'readonly',
ElLoading: 'readonly',
ElMessage: 'readonly',
ElMessageBox: 'readonly',
ElNotification: 'readonly'
},
'rules': {
'vue/no-multiple-template-root': 'off',
'vue/multi-word-component-names': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/no-v-html': 'off',
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ['error', 'always', { 'null': 'ignore' }],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'always'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': 'off',
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
};

11
components.d.ts vendored
View File

@ -14,18 +14,18 @@ declare module '@vue/runtime-core' {
Dropzone: typeof import('./src/components/Dropzone/index.vue')['default']
EditorImage: typeof import('./src/components/Tinymce/components/EditorImage.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
ElBadge: typeof import('element-plus/es')['ElBadge']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('element-plus/es')['ElButton']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
ElCard: typeof import('element-plus/es')['ElCard']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
@ -37,7 +37,10 @@ declare module '@vue/runtime-core' {
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
@ -45,8 +48,8 @@ declare module '@vue/runtime-core' {
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTableRow: typeof import('element-plus/es')['ElTableRow']
ElTag: typeof import('element-plus/es')['ElTag']
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElUpload: typeof import('element-plus/es')['ElUpload']
ErrorLog: typeof import('./src/components/ErrorLog/index.vue')['default']

235
src/api/project.js Normal file
View File

@ -0,0 +1,235 @@
import request from '@/utils/request';
function getCurrentTimestamp() {
return new Date().getTime();
}
//我负责的页面获取项目
export function GetProject(page, pageSize, token) {
return request({
url: '/project/my/get',
method: 'get',
params: { page, pageSize },
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//新增项目
export function AddProject(data, token) {
return request({
url: '/project/add',
method: 'post',
data,
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//删除项目
export function DeleteProject(id, token) {
return request({
url: '/project/delete',
method: 'delete',
params:{ id },
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//编辑项目
export function EditProject(id, data, token) {
return request({
url: '/project/edit/',
method: 'put',
params:{ id },
data,
headers: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//根据项目名字模糊查询
export function GetProjectByName(name, token) {
return request({
url: '/project/get/name',
method: 'get',
params: { name },
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//根据项目id查询子系统
export function GetChildSysById(projectId, token) {
return request({
url: "/module/get?projectId=" + projectId ,
method: 'get',
params: { projectId },
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//根据项目名和子系统名查询子模块
export function GetChildSysByName(projectName, childName, token) {
return request({
url: '/project/module/get/name',
method: 'get',
params: { projectName, childName },
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//新增子系统
export function AddChildSystem(data, token) {
return request({
url: '/project/child/add',
method: 'post',
data,
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//删除子系统
export function DeleteChildSystem(id, token) {
return request({
url: '/project/child/delete',
method: 'delete',
params:{ id },
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//编辑子系统
export function EditChildSystem(id, data, token) {
return request({
url: "/project/child/edit",
method: 'put',
data,
params:{ id },
headers: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//根据子系统id获取子模块
export function GetChildModById(sysId, token) {
return request({
url: "/module/get/min?sysId=" + sysId ,
method: 'get',
params: { sysId },
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//查询子模块
//新增子模块
export function AddChildModule(data, token) {
return request({
url: '/project/module/add',
method: 'post',
data,
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//删除子模块
export function DeleteChildModule(id, token) {
return request({
url: '/project/module/delete',
method: 'delete',
params:{ id },
headers: {
'Authorization':'Bearer '+ token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//编辑子模块
export function EditChildModule(id, data, token) {
return request({
url: "/project/module/edit",
method: 'put',
data,
params:{ id },
headers: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//子模块详情
export function ModuleDetails(id, token) {
return request({
url: "/project/module/id",
method: 'get',
params:{ id },
headers: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}
//指定项目负责人
export function GetAppointOptions( token) {
return request({
url: "/project/pri",
method: 'get',
headers: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json;charset=utf-8',
'Timestamp': getCurrentTimestamp()
}
});
}

View File

@ -5,8 +5,8 @@ const Layout = () => import('@/layout/index.vue')
const manageRouter = {
path: '/myslef',
component: Layout,
meta: {
alwaysShow: false, // 始终显示根菜单
title: '个人项目',
@ -14,39 +14,59 @@ const manageRouter = {
roles: ['admin', 'teacher_user']
},
children: [
//我负责的以及子页面
{
path: 'charge',
component: () => import('@/views/personal/project/charge.vue'),
name: 'Charge',
meta: { title: '我负责的', icon: 'user', affix: true }
},
{
path: 'childSysCharge',
component: () => import('@/views/personal/project/childSystem/charge.vue'),
name: 'ChildSysCharge',
meta: { title: '我负责的 / 子系统', breadcrumb: true , hidden: true },
},
{
path: 'childModCharge',
component: () => import('@/views/personal/project/childmodel/charge.vue'),
name: 'ChildModCharge',
meta: { title: '我负责的 / 子系统 / 子模块', breadcrumb: true , hidden: true }
},
{
path:'chargeDetail',
component: () => import('@/views/personal/project/detail/charge.vue'),
name: 'ChargeDetail',
meta: { title: '我负责的 / 子系统 / 子模块 / 详情', breadcrumb: true , hidden: true }
},
//我管理的以及子页面
{
path: 'manage',
component: () => import('@/views/personal/project/manage.vue'),
name: 'Manage',
meta: { title: '我管理的', icon: 'user', affix: true, },
},
{
path: 'childSysManage',
component: () => import('@/views/personal/project/childSystem/manage.vue'),
name: 'ChildSysManage',
meta: { title: '我管理的 / 子系统', breadcrumb: true , hidden: true },
meta: { title: '我管理的 / 子系统', breadcrumb: true , hidden: true },
},
{
path: 'childModManage',
component: () => import('@/views/personal/project/childModel/manage.vue'),
component: () => import('@/views/personal/project/childmodel/manage.vue'),
name: 'ChildModManage',
meta: { title: '我管理的 / 子系统 / 子模块', breadcrumb: true , hidden: true }
meta: { title: '我管理的 / 子系统 / 子模块', breadcrumb: true , hidden: true }
},
{
path:'manageDetail',
component:()=>import('@/views/personal/project/detail/manage.vue'),
name: 'ManageDetail',
meta: { title: '我管理的 / 子系统 / 子模块 / 详情', breadcrumb: true , hidden: true }
meta: { title: '我管理的 / 子系统 / 子模块 / 详情', breadcrumb: true , hidden: true }
},
//我参与的以及子界面
{
@ -59,23 +79,23 @@ const manageRouter = {
path: 'childSysParticipate',
component: () => import('@/views/personal/project/childSystem/participate.vue'),
name: 'ChildSysParticipate',
meta: { title: '我参与的 / 子系统', breadcrumb: true , hidden: true ,affix:false},
meta: { title: '我参与的 / 子系统', breadcrumb: true , hidden: true ,affix:false},
},
{
path: 'childModParticipate',
component: () => import('@/views/personal/project/childModel/participate.vue'),
component: () => import('@/views/personal/project/childmodel/participate.vue'),
name: 'ChildModParticipate',
meta: { title: '我参与的 / 子系统 / 子模块', breadcrumb: true , hidden: true }
meta: { title: '我参与的 / 子系统 / 子模块', breadcrumb: true , hidden: true }
},
{
path: 'participateDetail',
component:()=>import('@/views/personal/project/detail/participate.vue'),
name: 'ParticipateDetail',
meta: { title: '我参与的 / 子系统 / 子模块 /详情', breadcrumb: true , hidden: true }
meta: { title: '我参与的 / 子系统 / 子模块 /详情', breadcrumb: true , hidden: true }
}
]
}
export default manageRouter
export default manageRouter

View File

@ -1,3 +1,735 @@
<template>
hi
</template>
<div>
<el-card style="max-width: 100vw;margin: 1.5vw;">
<template #header>
<div class="card-header">
<span>我负责的</span>
</div>
</template>
<div style="display: flex; gap: 100px">
<el-input
style="width: 550px"
placeholder="请输入"
v-model="searchData.name"
>
<template #prepend>名称</template>
</el-input>
<el-input
style="width: 550px"
placeholder="请输入"
>
<template #prepend>状态</template>
</el-input>
<div>
<el-button-group>
<el-button type="primary" @click="SearchProjectByName()">
<el-icon><Search /></el-icon>
查询
</el-button>
<el-button @click="reset()">
<el-icon><RefreshRight /></el-icon>
重置
</el-button>
</el-button-group>
</div>
</div>
<template #footer>Footer content</template>
</el-card>
<el-card style="max-width: 100vw;margin: 1.5vw;">
<template #header>
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
<span>项目列表</span>
<div style="display: flex;">
<el-button type="primary" @click="toggleAddDialog()">
<el-icon><Plus /></el-icon>
新增
</el-button>
<el-button type="danger" @click="toggleMulDeleteDialog()">
<el-icon><DeleteFilled /></el-icon>
删除
</el-button>
</div>
</div>
</template>
<!--表格内容-->
<el-table :data="tableData" ref="multipleTableRef" style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="序号">
<template v-slot="{row}">
<span>{{ row.id }}</span>
</template>
</el-table-column>
<el-table-column prop="name" label="项目名称">
<template v-slot="{row}">
<span>{{ row.name }}</span>
</template>
</el-table-column>
<el-table-column prop="workLoad" label="工作量">
<template v-slot="{row}">
<span>{{ row.workLoad}}</span>
</template>
</el-table-column>
<el-table-column prop="cycle" label="周期">
<template v-slot="{row}">
<span>{{ row.cycle }}</span>
</template>
</el-table-column>
<el-table-column prop="principalUser" label="项目负责人">
<template v-slot="{row}">
<span>{{ row.principalUser }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="180">
<template v-slot="{row}">
<span>{{ row.status }}</span>
</template>
</el-table-column>
<el-table-column property="tags" label="标签">
<template #default="{ row }">
<el-tag v-for="tag in row.tags" :key="tag">{{ tag.toString() }}</el-tag>
</template>
</el-table-column>
<el-table-column property="isFinish" label="文档(点击下载)">
<template #default="{ row }">
<template v-if="row.files && row.files.URI">
<a :href="row.files.URI" target="_blank" style="color: deepskyblue">
下载文档
</a>
</template>
<template v-else>
</template>
</template>
</el-table-column>
<el-table-column prop="description" label="项目简介">
<template v-slot="{row}">
<span>{{ row.description }}</span>
</template>
</el-table-column>
<el-table-column prop="deadLine" label="截止时间">
<template v-slot="{row}">
<span>{{ row.deadLine }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="120">
<template #default="{ row }">
<div style="display: flex; justify-content: flex-start; margin-bottom: 4px;">
<el-button link type="primary" size="small" @click="toggleEditDialog(row)">编辑</el-button>
<el-button link type="primary" size="small" @click="toggleDeleteDialog(row)">删除</el-button>
</div>
<div style="margin-bottom: 4px">
<el-button link type="primary" size="small" @click="toggleAppointDialog(row)">指定项目负责人</el-button>
</div>
<div style="margin-bottom: 4px">
<el-button link type="primary" size="small" @click="toChildSystem(row.id)">查看详情</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div style="display: flex; justify-content: center;margin-top: 2vh">
<el-pagination
background
layout="prev, pager, next"
:total="totalItems"
/>
</div>
</el-card>
<!--新增项目对话框-->
<el-dialog v-model="AddDialogVisible" title="新增项目" width="500">
<el-form label-width="auto" style="max-width: 600px">
<el-form-item
label="项目名称"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.name" />
</el-form-item>
<el-form-item
label="周期"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.cycle"/>
</el-form-item>
<el-form-item
label="工作量"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.workLoad" />
</el-form-item>
<el-form-item
label="截止时间"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<div class="block">
<el-date-picker
v-model="AddFormData.deadLine"
type="date"
placeholder="Pick a day"
/>
</div>
</el-form-item>
<el-form-item
label="项目简介"
:rules="{
trigger: 'blur',
}"
>
<el-input type="textarea" v-model="AddFormData.description" />
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item
label="负责人"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.principalId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="标签"
:rules="{
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.tags" />
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-row>
<el-col :span="20">
<el-form-item
label="状态"
:rules="{
required: true,
message: 'Please select a status',
trigger: 'blur',
}"
>
<el-select v-model="AddFormData.status">
<el-option value="未开始">未开始</el-option>
<el-option value="进行中">进行中</el-option>
<el-option value="已完成">已完成</el-option>
<el-option value="已暂停">已暂停</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item>
<el-upload
v-model="AddFormData.fakeFile"
multiple
style=" margin-right: 13px;"
>
<el-button type="success">
<el-icon><UploadFilled /></el-icon>
上传文档
</el-button>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelAdd()">取消</el-button>
<el-button type="primary" @click="addProject()">
确认
</el-button>
</div>
</template>
</el-dialog>
<!--删除多个项目对话框-->
<el-dialog
title="删除项目"
width="450"
align-center
v-model="DeleteMulDialogVisible"
>
<span>确认删除该项目吗?</span>
<template #footer>
<div class="dialog-footer">
<el-button type="danger" @click="deleteMultipleProjects()">删除</el-button>
<el-button @click="CancelMulDelete()">取消</el-button>
</div>
</template>
</el-dialog>
<!--删除单个项目对话框-->
<el-dialog
title="删除项目"
width="450"
align-center
v-model="DeleteDialogVisible"
>
<span>确认删除该项目吗?</span>
<template #footer>
<div class="dialog-footer">
<el-button type="danger" @click="deleteProject()">删除</el-button>
<el-button @click="CancelDelete()">取消</el-button>
</div>
</template>
</el-dialog>
<!--编辑项目对话框-->
<el-dialog v-model="EditDialogVisible" title="编辑项目" width="500">
<el-form label-width="auto" style="max-width: 600px">
<el-form-item
label="项目名称"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.name"/>
</el-form-item>
<el-form-item
label="项目简介"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.description"/>
</el-form-item>
<el-form-item
label="项目Id"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.projectId"/>
</el-form-item>
<el-form-item
label="标签"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.tags"/>
</el-form-item>
<el-form-item
label="状态"
:rules="{
required: true,
message: 'Please select a status',
trigger: 'blur',
}"
>
<el-select v-model="EditFormData.status">
<el-option value="未开始">未开始</el-option>
<el-option value="进行中">进行中</el-option>
<el-option value="已完成">已完成</el-option>
<el-option value="已暂停">已暂停</el-option>
</el-select>
</el-form-item>
<el-form-item
label="工作量"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.workLoad"/>
</el-form-item>
<el-form-item
label="周期"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.cycle"/>
</el-form-item>
<el-form-item
label="截止时间"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<div class="block">
<el-date-picker
v-model="EditFormData.deadLine"
type="date"
placeholder="Pick a day"
/>
</div>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelEdit()">取消</el-button>
<el-button type="primary" @click="editProject()">
确认
</el-button>
</div>
</template>
</el-dialog>
<!--指定项目负责人对话框-->
<el-dialog v-model="AppointDialogVisible" title="指定项目负责人">
<el-table :data="[currentRowData]" style="width: 100%">
<el-table-column prop="id" label="序号"></el-table-column>
<el-table-column prop="principalUser" label="项目负责人"></el-table-column>
<el-table-column label="选择新负责人">
<el-select v-model="selectedPrincipal" placeholder="请选择项目负责人">
<el-option v-for="option in appointOptions.option" :value="option.username">
{{option.username}}
</el-option>
</el-select>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelAppoint()">取消</el-button>
<el-button type="primary" @click="confirmAppointment()">确认</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted } from 'vue';
import { Plus, UploadFilled, DeleteFilled, RefreshRight, Search } from '@element-plus/icons-vue';
import { AddProject, DeleteProject, EditProject, GetAppointOptions, GetProject, GetProjectByName } from '@/api/project';
import { getToken } from '@/utils/auth';
import { ElButton, ElMessage, ElTableColumn, ElTag } from 'element-plus';
import { useRouter } from 'vue-router';
const router = useRouter();
const AddDialogVisible = ref(false);
const DeleteDialogVisible = ref(false);
const DeleteMulDialogVisible = ref(false);
const EditDialogVisible = ref(false);
const AppointDialogVisible = ref(false);
const tableData = ref([]);
const listLoading = ref(false);
const token = getToken();
const page = ref('');
const pageSize = ref('');
const totalItems = ref(0);
const editId = reactive({ id:'', })
const searchData = reactive({ name:'', });
const deleteDatas = reactive({ ids: '' });
const deleteData = reactive({ id: '' });
const currentRowData = ref([]);
let appointOptions = reactive({option:''});
const selectedPrincipal = ref('');
const AddFormData = reactive({
name: '',
description: '',
tags: '',
deadLine: '',
workLoad: '',
principalId: '',
cycle: '',
status: '',
fakeFile: {
name: "element-plus-logo.svg",
url: 'https://element-plus.org/images/element-plus-logo.svg'
},
});
const EditFormData = reactive({
name:'',
description:'',
tags:'',
principalId:'',
projectId:'',
files:'',
cycle:'',
status:'',
deadLine:'',
workLoad:'',
})
//
const toChildSystem = (projectId) => {
router.push({ name: 'ChildSysCharge', query: { projectId: projectId } });//4
};
//
const parseData = (data) => {
const files = JSON.parse(data.files);
const tags = JSON.parse(data.tags);
return {
id: data.id,
cycle: data.cycle,
name: data.name,
description: data.description,
workLoad: data.workLoad,
status: data.status,
deadLine: data.deadLine,
tags: tags,
files: files,
principalUser: data.principalUser
};
};
//
async function getList() {
console.log("use token:", token);
listLoading.value = true;
try {
const response = await GetProject(page.value, pageSize.value, token);
console.log("完整响应内容:", response);
if (response.data.list) {
const list = response.data.list;
tableData.value = list.map(item => parseData(item));
totalItems.value = response.data.total;
} else {
console.error("未获取到预期数据,响应内容:", response);
}
} catch (error) {
console.error('请求失败:', error);
} finally {
listLoading.value = false;
}
}
//
function toggleAddDialog() {
AddDialogVisible.value = !AddDialogVisible.value;
}
async function addProject() {
console.log("add token:", token);
try {
const res = await AddProject(AddFormData, token);
if (res.data) {
getList();
listLoading.value = true;
ElMessage({
message: '新增成功',
type: 'success',
})
} else {
console.error("未获取到预期数据,响应内容:", res);
}
} finally {
listLoading.value = false;
AddDialogVisible.value = false;
}
}
function CancelAdd() {
AddDialogVisible.value = false;
}
//
function handleSelectionChange(selection) {
deleteDatas.ids = selection.map(item => item.id);
}
async function deleteMultipleProjects() {
try {
const res = await DeleteProject(deleteDatas.ids, token);
console.log("delete tokens:", token);
if (res.code === 200) {
ElMessage({
message: '删除成功',
type: 'success',
});
DeleteMulDialogVisible.value = false;
getList();
} else {
console.error("删除失败:", res);
}
} finally {
listLoading.value = false;
}
}
function toggleMulDeleteDialog() {
if (deleteDatas.ids.length === 0) {
ElMessage({
message: '请选择要删除的项目',
type: 'warning',
duration: 2500
});
} else {
DeleteMulDialogVisible.value = true;
}
}
function CancelMulDelete() {
DeleteDialogVisible.value = false;
}
//
function toggleDeleteDialog(row) {
deleteData.id = row.id;
DeleteDialogVisible.value = true;
}
async function deleteProject() {
try {
const res = await DeleteProject(deleteData.id, token);
if (res.code === 200) {
ElMessage({
message: '删除成功',
type: 'success',
});
console.log("删除成功");
DeleteDialogVisible.value = false;
getList();
} else {
console.error("删除失败:", res);
}
} finally {
listLoading.value = false;
}
}
//
function CancelDelete() {
DeleteDialogVisible.value = false;
}
//
async function editProject() {
console.log("edit token:", token);
try {
const response = await EditProject(editId.id, EditFormData, token);
if (response.code===200) {
getList();
} else {
console.error("未获取到预期数据,响应内容:", response);
}
} finally {
listLoading.value = false;
EditDialogVisible.value = false;
}
}
//
async function SearchProjectByName() {
console.log("search token:", token);
try {
const response = await GetProjectByName(searchData.name, token);
if (response.data) {
tableData.value = response.data;
} else {
console.error("未获取到预期数据,响应内容:", response);
}
} finally {
listLoading.value = false;
}
}
function toggleEditDialog(row) {
console.log("Editing row:", row); //
// EditFormData
EditFormData.name = row.name;
EditFormData.description = row.description;
EditFormData.tags = row.tags.toString();
EditFormData.files = row.files;
EditFormData.cycle = row.cycle;
EditFormData.workLoad = row.workLoad;
EditFormData.status = row.status;
editId.id = row.id
EditFormData.principalId = row.principalId;
EditDialogVisible.value = true; //
}
function CancelEdit() {
EditDialogVisible.value = false;
}
function reset() {
searchData.name = '';
getList();
}
//
async function getAppointOptions() {
try {
const response = await GetAppointOptions(token);
if (response.code === 200) {
appointOptions.option = response.data;
} else {
console.error("无数据");
}
} catch (error) {
console.error('Error fetching status options:', error);
}
};
function toggleAppointDialog(row) {
currentRowData.value = row;
AppointDialogVisible.value = true;
}
function confirmAppointment() {
console.log("指定新负责人:", selectedPrincipal.value);
//
AppointDialogVisible.value = false;
ElMessage({
message: '项目负责人更新成功',
type: 'success',
duration: 3000
});
getList();
}
function CancelAppoint() {
AppointDialogVisible.value = false;
}
onMounted(async () => {
await getList(); //
await getAppointOptions();
});
</script>

View File

@ -0,0 +1,676 @@
<template>
<div>
<!--顶部卡片-->
<el-card style="max-width: 100vw;margin: 1.5vw;">
<template #header>
<div class="card-header">
<span>子系统{{projectId}}</span>
</div>
</template>
<div style="display: flex; gap: 100px">
<el-input
style="width: 550px"
placeholder="请输入"
v-model="searchData.name"
>
<template #prepend>名称</template>
</el-input>
<el-input
style="width: 550px"
placeholder="请输入"
>
<template #prepend>状态</template>
</el-input>
<div>
<el-button-group>
<el-button type="primary" @click="SearchSystemByName()">
<el-icon><Search /></el-icon>
查询
</el-button>
<el-button @click="reset()">
<el-icon><RefreshRight /></el-icon>
重置
</el-button>
</el-button-group>
</div>
</div>
<template #footer>Footer content</template>
</el-card>
<!--表格卡片-->
<el-card style="max-width: 100vw;margin: 1.5vw;">
<template #header>
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
<span>子系统列表</span>
<div style="display: flex;">
<el-button type="primary" @click="toggleAddDialog()">
<el-icon><Plus /></el-icon>
新增
</el-button>
<el-button type="danger" @click="toggleMulDeleteDialog()">
<el-icon><DeleteFilled /></el-icon>
删除
</el-button>
</div>
</div>
</template>
<!--表格内容-->
<el-table :data="tableData" ref="multipleTableRef" style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="序号">
<template v-slot="{row}">
<span>{{ row.id }}</span>
</template>
</el-table-column>
<el-table-column prop="name" label="子系统名称">
<template v-slot="{row}">
<span>{{ row.name }}</span>
</template>
</el-table-column>
<el-table-column prop="workLoad" label="工作量">
<template v-slot="{row}">
<span>{{ row.workLoad}}</span>
</template>
</el-table-column>
<el-table-column prop="cycle" label="周期">
<template v-slot="{row}">
<span>{{ row.cycle }}</span>
</template>
</el-table-column>
<el-table-column prop="principalName" label="负责人">
<template v-slot="{row}">
<span>{{ row.principalName }}</span>
</template>
</el-table-column>
<el-table-column prop="status" label="状态">
<template v-slot="{row}">
<span>{{ row.status }}</span>
</template>
</el-table-column>
<el-table-column prop="description" label="子系统简介">
<template v-slot="{row}">
<span>{{ row.description }}</span>
</template>
</el-table-column>
<el-table-column prop="deadLine" label="截止时间">
<template v-slot="{row}">
<span>{{ row.deadLine }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="120">
<template #default="{ row }">
<div style="display: flex; justify-content: flex-start; margin-bottom: 4px;">
<el-button link type="primary" size="small" @click="toggleEditDialog(row)">编辑</el-button>
<el-button link type="primary" size="small" @click="toggleDeleteDialog(row)">删除</el-button>
</div>
<div style="margin-bottom: 4px">
<el-button link type="primary" size="small" @click="toggleAppointDialog(row)">指定子系统负责人</el-button>
</div>
<div style="margin-bottom: 4px">
<el-button link type="primary" size="small" @click="toChildModule(row.id)">查看详情</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!--分页-->
<div style="display: flex; justify-content: center;margin-top: 2vh">
<el-pagination
background
layout="prev, pager, next"
/>
</div>
</el-card>
<!--新增子系统对话框-->
<el-dialog v-model="AddDialogVisible" title="新增子系统" width="500">
<el-form label-width="auto" style="max-width: 600px">
<el-form-item
label="子系统名称"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.name"/>
</el-form-item>
<el-row>
<el-col :span="15">
<el-form-item
label="截止时间"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<div class="block">
<el-date-picker
type="date"
placeholder="选择"
v-model="AddFormData.deadLine"
/>
</div>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item
label="周期"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.cycle"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item
label="负责人id"
:rules="{
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.principalId"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="项目id"
:rules="{
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.projectId" disabled/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item
label="工作量"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.workLoad"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="状态"
:rules="{
required: true,
trigger: 'blur',
}"
>
<el-select v-model="AddFormData.status">
<el-option value="未开始">未开始</el-option>
<el-option value="进行中">进行中</el-option>
<el-option value="已完成">已完成</el-option>
<el-option value="已暂停">已暂停</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item
label="描述"
:rules="{
trigger: 'blur',
}"
>
<el-input type="textarea" v-model="AddFormData.description"/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelAdd()">取消</el-button>
<el-button type="primary" @click="addChildSystem() ">
确认
</el-button>
</div>
</template>
</el-dialog>
<!--删除多个子系统对话框-->
<el-dialog
title="删除子系统"
width="450"
align-center
v-model="DeleteMulDialogVisible"
>
<span>确认删除该项目吗?</span>
<template #footer>
<div class="dialog-footer">
<el-button type="danger" @click="deleteMulChildSystem()">删除</el-button>
<el-button @click="CancelMulDelete()">取消</el-button>
</div>
</template>
</el-dialog>
<!--删除单个子系统对话框-->
<el-dialog
title="删除子系统"
width="450"
align-center
v-model="DeleteDialogVisible"
>
<span>确认删除该子系统吗?</span>
<template #footer>
<div class="dialog-footer">
<el-button type="danger" @click="deleteChildSystem()">删除</el-button>
<el-button @click="CancelDelete()">取消</el-button>
</div>
</template>
</el-dialog>
<!--编辑子系统对话框-->
<el-dialog v-model="EditDialogVisible" title="编辑子系统" width="500">
<el-form label-width="auto" style="max-width: 600px">
<el-form-item
label="子系统名称"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.name"/>
</el-form-item>
<el-form-item
label="截止时间"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.deadLine"/>
</el-form-item>
<el-form-item
label="描述"
:rules="{
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.description"/>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item
label="周期"
:rules="{
required: true,
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.cycle"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="项目负责人id"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.principalId"/>
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-row>
<el-col :span="12">
<el-form-item
label="工作量"
:rules="{
required: true,
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.workLoad"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="状态"
:rules="{
required: true,
message: 'Please select a status',
trigger: 'blur',
}"
>
<el-select v-model="EditFormData.status">
<el-option value="未开始">未开始</el-option>
<el-option value="进行中">进行中</el-option>
<el-option value="已完成">已完成</el-option>
<el-option value="已暂停">已暂停</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelEdit()">取消</el-button>
<el-button type="primary" @click="editChildSystem()">
确认
</el-button>
</div>
</template>
</el-dialog>
<!--指定子系统负责人对话框-->
<el-dialog v-model="AppointDialogVisible" title="指定子系统负责人">
<el-table :data="[currentRowData]" style="width: 100%">
<el-table-column prop="id" label="序号"></el-table-column>
<el-table-column prop="principalName" label="子系统负责人"></el-table-column>
<el-table-column label="选择新负责人">
<el-select v-model="selectedPrincipal" placeholder="请选择子系统负责人">
<el-option v-for="option in appointOptions.option" :value="option.username">
{{option.username}}
</el-option>
</el-select>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelAppoint()">取消</el-button>
<el-button type="primary" @click="confirmAppointment()">确认</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import {
AddChildSystem,
DeleteChildSystem,
DeleteProject,
EditChildSystem, GetAppointOptions,
GetChildSysById,
GetProjectByName
} from '@/api/project';
import { getToken } from '@/utils/auth';
import { DeleteFilled, Plus, RefreshRight, Search } from '@element-plus/icons-vue';
import router from '@/router';
import { ElButton, ElMessage, ElTableColumn } from 'element-plus'; // API
const listLoading = ref(false);
const AddDialogVisible = ref(false);
const DeleteDialogVisible = ref(false);
const DeleteMulDialogVisible = ref(false);
const EditDialogVisible = ref(false);
const AppointDialogVisible = ref(false);
const tableData = ref([]);
const token = getToken();
const searchData = reactive({ name:'', });
const editId = reactive({ id:'', })
const deleteDatas = reactive({ ids: '' });
const deleteData = reactive({ id: '' });
const currentRowData = ref([]);
let appointOptions = reactive({option:''});
const selectedPrincipal = ref('');
//id
const route = useRoute();
const projectId = route.query.projectId
const AddFormData = reactive({
deadLine:'',
name: '',
status: '',
description: '',
principalId: '',
projectId:projectId,
cycle: '',
workLoad: '',
});
const EditFormData = reactive({
name:'',
description:'',
principalId:'',
workLoad:'',
status:'',
deadLine:'',
cycle:'',
})
//
const toChildModule = (systemId) => {
router.push({ name: 'ChildModCharge', query: { systemId: systemId } });//4
};
//id
async function getChildSysById(){
if (projectId) {
try {
const response = await GetChildSysById(projectId, token);
tableData.value = response.data;
} catch (error) {
console.error('获取子系统数据失败:', error);
}
}
};
//
async function SearchSystemByName() {
try {
const response = await GetProjectByName(searchData.name, token);
if (response.data) {
tableData.value = response.data;
} else {
console.error("未获取到预期数据,响应内容:", response);
}
} finally {
listLoading.value = false;
}
}
//
function toggleAddDialog() {
AddFormData.projectId = projectId;
AddDialogVisible.value = !AddDialogVisible.value;
}
async function addChildSystem() {
console.log("add token:", token);
try {
const res = await AddChildSystem(AddFormData, token);
if (res.code===200) {
listLoading.value = true;
ElMessage({
message: '新增成功',
type: 'success',
})
getChildSysById();
} else {
console.error("未获取到预期数据,响应内容:", res);
}
} finally {
listLoading.value = false;
AddDialogVisible.value = false;
}
}
function CancelAdd() {
AddDialogVisible.value = false;
}
//
function handleSelectionChange(selection) {
deleteDatas.ids = selection.map(item => item.id);
}
function toggleMulDeleteDialog() {
if (deleteDatas.ids.length === 0) {
ElMessage({
message: '请选择要删除的子系统',
type: 'warning',
duration: 2500
});
} else {
DeleteMulDialogVisible.value = true;
}
}
async function deleteMulChildSystem() {
try {
const res = await DeleteChildSystem(deleteDatas.ids, token);
if (res.code === 200) {
ElMessage({
message: '删除成功',
type: 'success',
});
console.log("多个子系统删除成功");
DeleteMulDialogVisible.value = false;
getChildSysById();
} else {
console.error("'多个子系统删除失败:", res);
}
} finally {
listLoading.value = false;
}
}
function CancelMulDelete() {
DeleteMulDialogVisible.value = false;
}
//
function toggleDeleteDialog(row) {
deleteData.id = row.id;
DeleteDialogVisible.value = true;
}
async function deleteChildSystem() {
try {
const res = await DeleteChildSystem(deleteData.id, token);
if (res.code === 200) {
ElMessage({
message: '删除成功',
type: 'success',
});
console.log("单个子系统删除成功");
DeleteDialogVisible.value = false;
getChildSysById();
} else {
console.error("单个子系统删除失败:", res);
}
} finally {
listLoading.value = false;
}
}
function CancelDelete() {
DeleteDialogVisible.value = false;
}
//
async function editChildSystem() {
console.log("edit token:", token);
try {
const response = await EditChildSystem(editId, EditFormData, token);
if (response.data) {
tableData.value = response.data;
} else {
console.error("未获取到预期数据,响应内容:", response);
}
} finally {
listLoading.value = false;
AddDialogVisible.value = false;
}
}
function toggleEditDialog(row) {
console.log("Editing row:", row); //
EditFormData.name = row.name;
EditFormData.description = row.description;
EditFormData.status = row.status;
EditFormData.workLoad = row.workLoad;
EditFormData.deadLine = row.deadLine;
EditFormData.cycle = row.cycle;
editId.id = row.id
EditDialogVisible.value = true; //
}
function CancelEdit() {
EditDialogVisible.value = false;
}
function reset() {
searchData.name = '';
getChildSysById();
}
//
async function getAppointOptions() {
try {
const response = await GetAppointOptions(token);
if (response.code === 200) {
appointOptions.option = response.data;
} else {
console.error("无数据");
}
} catch (error) {
console.error('Error fetching status options:', error);
}
};
function toggleAppointDialog(row) {
currentRowData.value = row;
AppointDialogVisible.value = true;
}
function confirmAppointment() {
console.log("指定新负责人:", selectedPrincipal.value);
AppointDialogVisible.value = false;
ElMessage({
message: '子系统负责人更新成功',
type: 'success',
duration: 3000
});
getChildSysById();
}
function CancelAppoint() {
AppointDialogVisible.value = false;
}
onMounted(async () => {
await getChildSysById();
await getAppointOptions();
});
</script>

View File

@ -0,0 +1,602 @@
<template>
<div>
<!--顶部卡片-->
<el-card style="max-width: 100vw;margin: 1.5vw;">
<template #header>
<div class="card-header">
<span>子模块{{systemId}}</span>
</div>
</template>
<div style="display: flex; gap: 100px">
<el-input
style="width: 550px"
placeholder="请输入"
v-model="searchData.name"
>
<template #prepend>名称</template>
</el-input>
<el-input
style="width: 550px"
placeholder="请输入"
>
<template #prepend>状态</template>
</el-input>
<div>
<el-button-group>
<el-button type="primary" @click="SearchModuleByName()">
<el-icon><Search /></el-icon>
查询
</el-button>
<el-button @click="reset()">
<el-icon><RefreshRight /></el-icon>
重置
</el-button>
</el-button-group>
</div>
</div>
<template #footer>Footer content</template>
</el-card>
<!--表格卡片-->
<el-card style="max-width: 100vw;margin: 1.5vw;">
<template #header>
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
<span>子模块列表</span>
<div style="display: flex;">
<el-button type="primary" @click="toggleAddDialog()">
<el-icon><Plus /></el-icon>
新增
</el-button>
<el-button type="danger">
<el-icon><DeleteFilled /></el-icon>
删除
</el-button>
</div>
</div>
</template>
<!--表格内容-->
<el-table :data="tableData" ref="multipleTableRef" style="width: 100%">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="序号">
<template v-slot="{row}">
<span>{{ row.id }}</span>
</template>
</el-table-column>
<el-table-column prop="name" label="子模块名称">
<template v-slot="{row}">
<span>{{ row.name }}</span>
</template>
</el-table-column>
<el-table-column prop="workLoad" label="工作量">
<template v-slot="{row}">
<span>{{ row.workLoad}}</span>
</template>
</el-table-column>
<el-table-column prop="cycle" label="周期">
<template v-slot="{row}">
<span>{{ row.cycle }}</span>
</template>
</el-table-column>
<el-table-column prop="principalUser" label="负责人">
<template v-slot="{row}">
<span>{{ row.principalUser }}</span>
</template>
</el-table-column>
<el-table-column prop="status" label="状态">
<template v-slot="{row}">
<span>{{ row.status }}</span>
</template>
</el-table-column>
<el-table-column prop="description" label="子模块简介">
<template v-slot="{row}">
<span>{{ row.description }}</span>
</template>
</el-table-column>
<el-table-column prop="deadLine" label="截止时间">
<template v-slot="{row}">
<span>{{ row.deadLine }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="120">
<template #default="{ row }">
<div style="display: flex; justify-content: flex-start; margin-bottom: 4px;">
<el-button link type="primary" size="small" @click="toggleEditDialog(row)">编辑</el-button>
<el-button link type="primary" size="small" @click="toggleDeleteDialog(row)">删除</el-button>
</div>
<div style="margin-bottom: 4px">
<el-button link type="primary" size="small" @click="toggleAppointDialog(row)">指定子模块负责人</el-button>
</div>
<div style="margin-bottom: 4px">
<el-button link type="primary" size="small" @click="toModuleDetail(row.id)">查看详情</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!--表格分页-->
<div style="display: flex; justify-content: center;margin-top: 2vh">
<el-pagination
background
layout="prev, pager, next"
/>
<el-pagination larger background layout="prev, pager, next" @current-change="handleCurrentChange"
:current-page="currentPage" :page-size="pageSize" :total="total"
style="display: flex;flex-direction: row;justify-content: center;margin-top:5vh" />
</div>
</el-card>
<!--新增子模块对话框-->
<el-dialog v-model="AddDialogVisible" title="新增子模块" width="500">
<el-form label-width="auto" style="max-width: 600px">
<el-form-item
label="子模块名称"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.name"/>
</el-form-item>
<el-row>
<el-col :span="15">
<el-form-item
label="截止时间"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<div class="block">
<el-date-picker
type="date"
placeholder="选择"
v-model="AddFormData.deadLine"
/>
</div>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item
label="周期"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.cycle"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item
label="负责人id"
:rules="{
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.principalId"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="子系统id"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.projectChildId" disabled/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item
label="工作量"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="AddFormData.workLoad"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="状态"
:rules="{
required: true,
trigger: 'blur',
}"
>
<el-select v-model="AddFormData.status">
<el-option value="未开始">未开始</el-option>
<el-option value="进行中">进行中</el-option>
<el-option value="已完成">已完成</el-option>
<el-option value="已暂停">已暂停</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item
label="描述"
:rules="{
trigger: 'blur',
}"
>
<el-input type="textarea" v-model="AddFormData.description"/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelAdd()">取消</el-button>
<el-button type="primary" @click="addChildModule()">
确认
</el-button>
</div>
</template>
</el-dialog>
<!--删除子模块对话框-->
<el-dialog
title="删除子模块"
width="450"
align-center
v-model="DeleteDialogVisible"
>
<span>确认删除该子模块吗?</span>
<template #footer>
<div class="dialog-footer">
<el-button type="danger" >删除</el-button>
<el-button @click="CancelDelete()">取消</el-button>
</div>
</template>
</el-dialog>
<!--编辑子模块对话框-->
<el-dialog v-model="EditDialogVisible" title="编辑子模块" width="500">
<el-form label-width="auto" style="max-width: 600px">
<el-form-item
label="子模块名称"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.name"/>
</el-form-item>
<el-form-item
label="截止时间"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.deadLine"/>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item
label="项目负责人id"
:rules="{
required: true,
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.principalId"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="系统id"
:rules="{
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input />
</el-form-item>
</el-col>
</el-row>
<el-form-item
label="周期"
:rules="{
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.cycle"/>
</el-form-item>
<el-form-item
label="工作量"
:rules="{
trigger: 'blur',
}"
>
<el-input v-model="EditFormData.workLoad"/>
</el-form-item>
<el-form-item>
<el-row>
<el-col :span="20">
<el-form-item
label="状态"
:rules="{
required: true,
message: 'Please select a status',
trigger: 'blur',
}"
>
<el-select v-model="EditFormData.status">
<el-option value="未开始">未开始</el-option>
<el-option value="进行中">进行中</el-option>
<el-option value="已完成">已完成</el-option>
<el-option value="已暂停">已暂停</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item
label="描述"
:rules="{
message: 'domain can not be null',
trigger: 'blur',
}"
>
<el-input type="textarea" v-model="EditFormData.description"/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelEdit()">取消</el-button>
<el-button type="primary" @click="editChildModule()">
确认
</el-button>
</div>
</template>
</el-dialog>
<!--指定子模块负责人对话框-->
<el-dialog v-model="AppointDialogVisible" title="指定子模块负责人">
<el-table :data="[currentRowData]" style="width: 100%">
<el-table-column prop="id" label="序号"></el-table-column>
<el-table-column prop="principalUser" label="子模块负责人"></el-table-column>
<el-table-column label="选择新负责人">
<el-select v-model="selectedPrincipal" placeholder="请选择子模块负责人">
<el-option v-for="option in appointOptions.option" :value="option.username">
{{option.username}}
</el-option>
</el-select>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button @click="CancelAppoint()">取消</el-button>
<el-button type="primary" @click="confirmAppointment()">确认</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import {
AddChildModule,
EditChildModule, GetAppointOptions,
GetChildModById, GetProjectByName
} from '@/api/project';
import { getToken } from '@/utils/auth';
import { DeleteFilled, Plus, RefreshRight, Search } from '@element-plus/icons-vue';
import { ElButton, ElTableColumn } from 'element-plus'; // API
const listLoading = ref(false);
const AddDialogVisible = ref(false);
const DeleteDialogVisible = ref(false);
const EditDialogVisible = ref(false);
const AppointDialogVisible = ref(false);
const tableData = ref([]);
const token = getToken();
const editId = reactive({ id:'', })
const searchData = reactive({ name:'', });
const currentRowData = ref([]);
let appointOptions = reactive({option:''});
const selectedPrincipal = ref('');
//id
const route = useRoute();
const systemId = route.query.systemId
const AddFormData = reactive({
deadLine:'',
name: '',
status: '',
description: '',
principalId: '',
projectChildId:systemId,
workLoad: '',
cycle:'',
});
const EditFormData = reactive({
name:'',
description:'',
principalId:'',
workLoad:'',
status:'',
deadLine:'',
cycle:'',
})
//
const router = useRouter()
const toModuleDetail = (moduleId) => {
router.push({ name: 'ChargeDetail', query: { moduleId:moduleId } });
};
//id
async function getChildModuleById(){
if (systemId) {
try {
const response = await GetChildModById(systemId, token);
tableData.value = response.data;
} catch (error) {
console.error('获取子系统数据失败:', error);
}
}
};
//
async function SearchModuleByName() {
try {
const response = await GetProjectByName(searchData.name, token);
if (response.data) {
tableData.value = response.data;
} else {
console.error("未获取到预期数据,响应内容:", response);
}
} finally {
listLoading.value = false;
}
}
//
async function addChildModule() {
console.log("add token:", token);
try {
const res = await AddChildModule(AddFormData, token);
if (res.code === 200) {
listLoading.value = true;
ElMessage({
message: '新增成功',
type: 'success',
})
getChildModuleById();
} else {
console.error("未获取到预期数据,响应内容:", res);
}
} finally {
listLoading.value = false;
AddDialogVisible.value = false;
}
}
//
async function editChildModule() {
console.log("edit token:", token);
try {
const response = await EditChildModule(editId, EditFormData, token);
if (response.code === 200) {
listLoading.value = true;
ElMessage({
message: '修改成功',
type: 'success',
})
getChildModuleById();
} else {
console.error("未获取到预期数据,响应内容:", response);
}
} finally {
listLoading.value = false;
AddDialogVisible.value = false;
}
}
function toggleAddDialog() {
AddFormData.projectChildId = systemId;
AddDialogVisible.value = !AddDialogVisible.value;
}
function CancelAdd() {
AddDialogVisible.value = false;
}
function toggleDeleteDialog(row) {
console.log("Delete row:", row); //
DeleteDialogVisible.value = !DeleteDialogVisible.value;
}
function CancelDelete() {
DeleteDialogVisible.value = false;
}
function toggleEditDialog(row) {
console.log("Editing row:", row); //
EditFormData.name = row.name;
EditFormData.description = row.description;
EditFormData.status = row.status;
EditFormData.workLoad = row.workLoad;
EditFormData.deadLine = row.deadLine;
EditFormData.cycle = row.cycle;
editId.id = row.id
EditDialogVisible.value = true; //
}
function CancelEdit() {
EditDialogVisible.value = false;
}
function reset() {
searchData.name = '';
getChildModuleById();
}
//
async function getAppointOptions() {
try {
const response = await GetAppointOptions(token);
if (response.code === 200) {
appointOptions.option = response.data;
} else {
console.error("无数据");
}
} catch (error) {
console.error('Error fetching status options:', error);
}
};
function toggleAppointDialog(row) {
currentRowData.value = row;
AppointDialogVisible.value = true;
}
function confirmAppointment() {
console.log("指定新负责人:", selectedPrincipal.value);
AppointDialogVisible.value = false;
ElMessage({
message: '子模块负责人更新成功',
type: 'success',
duration: 3000
});
getChildModuleById();
}
function CancelAppoint() {
AppointDialogVisible.value = false;
}
onMounted(async () => {
await getChildModuleById ();
await getAppointOptions();
});
</script>

View File

@ -0,0 +1,309 @@
<template>
<div>
<el-card>
<template #header>
<div class="card-header">
<span>子模块{{moduleId}}详情</span>
</div>
</template>
<!--子模块详情-->
<div style="display: flex; justify-content: center">
<el-form :model="formData" label-width="auto" style="max-width: 600px">
<el-form-item label="01.模块名称">
<el-input v-model="formData.name"/>
</el-form-item>
<el-form-item label="02.模块周期">
<el-input v-model="formData.cycle"/>
</el-form-item>
<el-form-item label="03.工作量">
<el-input v-model="formData.workLoad"/>
</el-form-item>
<el-form-item label="03.负责人">
<el-input v-model="formData.principalUser"/>
</el-form-item>
<el-form-item label="05.状态">
<el-select v-model="formData.status">
<el-option value="未开始">未开始</el-option>
<el-option value="进行中">进行中</el-option>
<el-option value="已完成">已完成</el-option>
<el-option value="已暂停">已暂停</el-option>
</el-select>
</el-form-item>
<el-form-item
label="06.截止时间"
>
<div class="block">
<el-date-picker
type="date"
v-model="formData.deadLine"
/>
</div>
</el-form-item>
<el-form-item label="07.简介">
<el-input type="textarea" v-model="formData.description"/>
</el-form-item>
<el-form-item>
<el-button type="primary" >编辑</el-button>
<el-button @click="toggleDeleteDialog()">删除</el-button>
</el-form-item>
</el-form>
</div>
<!--删除子模块对话框-->
<el-dialog
title="删除子模块"
width="450"
align-center
v-model="DeleteDialogVisible"
>
<span>确认删除该子模块吗?</span>
<template #footer>
<div class="dialog-footer">
<el-button type="danger" @click="deleteChildModule()">删除</el-button>
<el-button @click="CancelDelete()">取消</el-button>
</div>
</template>
</el-dialog>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, reactive } from 'vue';
import { useRoute } from 'vue-router';
import { getToken } from '@/utils/auth';
import { DeleteChildModule, GetProject, ModuleDetails } from '@/api/project';
const listLoading = ref(false);
const token = getToken();
const DeleteDialogVisible = ref(false);
const EditDialogVisible = ref(false);
//Id
const route = useRoute();
const moduleId = route.query.moduleId;
const formData = reactive({
name: '',
cycle: '',
workLoad: '',
principalUser: '',
status: '',
deadLine: '',
description: ''
});
async function moduleDetails() {
listLoading.value = true;
try {
const response = await ModuleDetails(moduleId, token);
console.log("API Response:", response);
if (response.data) {
//
formData.name = response.data.name !== undefined ? response.data.name : formData.name;
formData.cycle = response.data.cycle !== undefined ? response.data.cycle : formData.cycle;
formData.workLoad = response.data.workLoad !== undefined ? response.data.workLoad : formData.workLoad;
formData.principalUser = response.data.principalUser !== undefined ? response.data.principalUser : formData.principalUser;
formData.status = response.data.status !== undefined ? response.data.status : formData.status;
formData.deadLine = response.data.deadLine !== undefined ? response.data.deadLine : formData.deadLine;
formData.description = response.data.description !== undefined ? response.data.description : formData.description;
} else {
console.error("未获取到预期数据,响应内容:", response);
}
} catch (error) {
console.error('请求失败:', error);
} finally {
listLoading.value = false;
}
}
//
async function deleteChildModule() {
console.log("delete token:", token);
try {
const res = await DeleteChildModule(moduleId, token);
if (res.code === 200) {
ElMessage({
message: '删除成功',
type: 'success',
})
DeleteDialogVisible.value = false;
moduleDetails();
} else {
console.error("删除失败:", res);
}
} finally {
listLoading.value = false;
}
}
function toggleDeleteDialog() {
DeleteDialogVisible.value = !DeleteDialogVisible.value;
}
function CancelDelete() {
DeleteDialogVisible.value = false;
}
onMounted(async () => {
await moduleDetails(); //
});
</script>
<!--
<template>
<div style=" width:100%;">
<el-card style="max-width: 100vw;">
<template #header><strong>子模块{{ moduleId }}详情</strong></template>
</el-card>
<el-card class="card">
<el-row :gutter="20">
<el-col :span="12">
<el-row v-for="item in projectItems" :key="item.label">
<el-col :span="24">
<div style="margin-top: 10%;"><strong>{{ item.label }}</strong> </div>
</el-col>
</el-row>
</el-col>
<el-col :span="12">
<el-row v-for="item in projectItems" :key="item.label">
<el-col :span="24">
<div v-if="item.label !== '05.状态' && item.label !== '07.简介'" style="margin-top: 10%;">{{
item.value
}}</div>
<el-select v-if="item.label === '05.状态'" v-model="selectedStatus" placeholder="请选择状态"
style="width: 150px ;margin-top: 10%">
<el-option label="未开始" value="未开始"></el-option>
<el-option label="进行中" value="进行中"></el-option>
<el-option label="已完成" value="已完成"></el-option>
<el-option label="已暂停" value="已暂停"></el-option>
</el-select>
<textarea style="resize: none;margin-top: 10%;width: 150px;" v-if="item.label === '07.简介'"
v-model="item.value" rows="4" cols="50"></textarea>
</el-col>
</el-row>
</el-col>
</el-row>
</el-card>
<div style="display: flex; justify-content: center;">
<el-button type="primary" style="width:80px">编辑</el-button>
<el-button style="width:80px ;background-color: #bd3124;color: azure;">删除</el-button>
</div>
<el-alert >
<router-view />
</el-alert>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { getToken } from '@/utils/auth';
import { ModuleDetails } from '@/api/project';
const token = getToken();
const projectItems = ref([
{ label: '01.模块名称', value: '项目名称1' },
{ label: '02.模块周期', value: '3个月' },
{ label: '03.工作量', value: '100小时' },
{ label: '04.负责人', value: '张三' },
{ label: '05.状态', value: '进行中' },
{ label: '06.时间', value: '2024-01-01 12:00:00' },
{ label: '07.简介', value: '大王iu大概iudg拍高端屁股的怕耽搁u对爬过文档爬过无' },
]);
const selectedStatus = ref('进行中');
//Id
const route = useRoute();
const moduleId = route.query.moduleId;
//
//
const parseData = (data) => {
projectItems.value.forEach(item => {
if (item.label === '01.模块名称') {
item.value = data.name;
} else if (item.label === '02.模块周期') {
item.value = data.cycle ? data.cycle : '未知';
} else if (item.label === '03.工作量') {
item.value = data.workLoad + "人/天";
} else if (item.label === '04.负责人') {
item.value = data.principalUser;
} else if (item.label === '05.状态') {
item.value = data.status ? data.status : '未知';
} else if (item.label === '06.时间') {
item.value = new Date(data.deadLine).toLocaleDateString();
} else if (item.label === '07.简介') {
item.value = data.description;
}
})
}
//
const fetchData = () => {
const project = ModuleDetails(moduleIdId, token);
project.then(res => {
const data = res.data.data;
console.log(data);
if (data) {
parseData(data);
}
})
}
onMounted(async () => {
await fetchData(); //
});
</script>
<style>
.my-autocomplete li {
line-height: normal;
padding: 7px;
}
.my-autocomplete li .name {
text-overflow: ellipsis;
overflow: hidden;
}
.my-autocomplete li .addr {
font-size: 12px;
color: #b4b4b4;
}
.my-autocomplete li .highlighted .addr {
color: #ddd;
}
.card {
width: 28%;
margin-left: 50%;
transform: translateX(-50%);
}
</style>
-->

View File

@ -189,20 +189,20 @@ const fetchData = () => {
project.then(res => {
const data = res.data.data.list;
const dataTotal = res.data.data.total;
total.value = dataTotal;
if (data) {
const newData = data.map(item => parseData(item));
console.log(newData);
tableData.value = newData;
console.log(tableData.value);
initialTableData.value = tableData.value.slice();
} else {
console.log("没有可用数据");
@ -337,13 +337,13 @@ const showEditDialog = () => {
const idToEdit = selectedIds.value[0]; //
const projectToEdit = tableData.value.find(project => project.id === idToEdit);
if (projectToEdit) {
editFormData.value = { ...projectToEdit };
editFormData.value.tags = projectToEdit.tags.tags;
editFormData.value.files = projectToEdit.files.URI;
isDialogVisible.value = true;
} else {
ElMessage.error('选中的项目未找到');
@ -369,7 +369,7 @@ const submitEditForm = async () => {
status: editFormData.value.status
}
console.log(body);
editProject(body, editFormData.value.id, getToken()).then(res => {
console.log(res);
if (res.data.code === 200) {
@ -384,13 +384,8 @@ const submitEditForm = async () => {
console.log(err);
ElMessage.error('更新失败');
});
};
</script>
<style>
@ -468,4 +463,4 @@ const submitEditForm = async () => {
/* 隐藏默认关闭按钮 */
}
</style>
</style>