Files
projectSystem/ruoyi-ui/src/views/project/module/myModules.vue
2025-09-15 12:42:57 +08:00

519 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="模块名称" prop="moduleName">
<el-input
v-model="queryParams.moduleName"
placeholder="请输入模块名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="项目名称" prop="projectName">
<el-input
v-model="queryParams.projectName"
placeholder="请输入项目名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
<el-option
v-for="dict in dict.type.module_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
<!-- 显示当前用户信息 -->
<div style="margin-top: 10px; color: #666;">
当前用户{{ userName }}ID: {{ userId }} | 用户角色{{ userRoles }}
</div>
<!-- 调试信息开发环境显示 -->
<div v-if="false" style="margin-top: 10px; color: #999; font-size: 12px;">
调试信息: Store状态={{ JSON.stringify($store.state.user) }}
</div>
</el-form>
<el-table v-loading="loading" :data="moduleList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="模块名称" align="center" prop="moduleName">
<template slot-scope="scope">
<el-link type="primary" @click.stop="openSubDrawer(scope.row)">{{ scope.row.moduleName }}</el-link>
</template>
</el-table-column>
<el-table-column label="项目名称" align="center" prop="projectName" />
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<dict-tag :options="dict.type.module_status" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="接取人" align="center" prop="assignee">
<template slot-scope="scope">
{{ scope.row.assignee || '未指派' }}
</template>
</el-table-column>
<el-table-column label="接取时间" align="center" prop="assignTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.assignTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="完成时间" align="center" prop="finishTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.finishTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="250">
<template slot-scope="scope">
<!-- 管理员指派相关按钮在我的模块页面不展示 -->
<!-- 普通用户操作按钮 -->
<template v-if="isNormalUser">
<!-- 待接取状态显示接取按钮 -->
<el-button
v-if="scope.row.status === '0' && scope.row.designatedUser == userId"
size="mini"
type="text"
icon="el-icon-thumb"
@click="handleClaim(scope.row)"
v-hasPermi="['project:module:claim']"
>接取</el-button>
<!-- 进行中状态显示放弃完成上传文档按钮 -->
<template v-if="scope.row.status === '1' && isSelfAssignee(scope.row)">
<el-button
size="mini"
type="text"
icon="el-icon-circle-close"
@click="handleGiveup(scope.row)"
>放弃</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-check"
@click="handleComplete(scope.row)"
>完成</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-upload"
@click="handleUpload(scope.row)"
>上传文档</el-button>
</template>
<!-- 已完成状态显示查看文档按钮 -->
<el-button
v-if="scope.row.status === '2'"
size="mini"
type="text"
icon="el-icon-document"
@click="handleViewDocs(scope.row)"
v-hasPermi="['project:doc:query']"
>查看文档</el-button>
</template>
<!-- 显示模块状态提示 -->
<div style="font-size: 12px; color: #999; margin-top: 5px;">
{{ getModuleStatusText(scope.row) }}
</div>
</template>
</el-table-column>
</el-table>
<div v-if="!loading && moduleList.length === 0" class="empty-state">
<i class="el-icon-document-remove" style="font-size: 100px; color: #dcdfe6;"></i>
<p>暂无被指派的模块</p>
<p>请联系项目管理员指派模块给您</p>
</div>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 子模块抽屉 -->
<el-drawer :title="currentModule ? ('子模块 - ' + currentModule.moduleName) : '子模块'" :visible.sync="subDrawerOpen" size="60%" append-to-body>
<div>
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handleOpenAddSub" v-if="currentModule && currentModule.status==='1' && canOperateSub()" style="margin-bottom: 12px;">新增子模块</el-button>
<el-table v-loading="subLoading" :data="subList">
<el-table-column label="子模块名称" prop="subName" />
<el-table-column label="状态" prop="status">
<template slot-scope="scope">
<el-tag :type="scope.row.status==='0' ? 'info' : scope.row.status==='1' ? 'warning' : 'success'">
{{ {0:'待处理',1:'进行中',2:'已完成'}[scope.row.status] }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="描述" prop="description" />
<el-table-column label="描述" prop="description" />
<el-table-column label="操作" align="center" width="260">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleEditSub(scope.row)" v-if="canOperateSub()">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDeleteSub(scope.row)" v-if="canOperateSub()">删除</el-button>
<el-button size="mini" type="text" icon="el-icon-check" @click="handleCompleteSub(scope.row)" v-if="canOperateSub() && scope.row.status!=='2'">完成</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-drawer>
<!-- 新增子模块对话框 -->
<el-dialog :title="subTitle" :visible.sync="subOpen" width="480px" append-to-body>
<el-form ref="subForm" :model="subForm" :rules="subRules" label-width="88px">
<el-form-item label="子模块名称" prop="subName">
<el-input v-model="subForm.subName" placeholder="请输入子模块名称" />
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input v-model="subForm.description" type="textarea" placeholder="请输入描述" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitSubForm"> </el-button>
<el-button @click="subOpen=false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getMyModules, claimModule, giveupModule, completeModule } from "@/api/project/module"
import { listSubmoduleByModule, addSubmodule, updateSubmodule, delSubmodule, completeSubmodule } from "@/api/project/submodule"
export default {
name: "MyModules",
dicts: ['module_status'],
computed: {
// 判断是否为普通用户
isNormalUser() {
return this.$store.state.user.roles &&
this.$store.state.user.roles.some(role =>
(typeof role === 'string' && role === 'normal_user') ||
(typeof role === 'object' && role.roleKey === 'normal_user')
);
}
},
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 模块表格数据
moduleList: [],
// 当前用户信息
userName: this.$store.state.user.name,
userId: this.$store.state.user.id,
userRoles: '无角色信息',
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
moduleName: null,
projectName: null,
status: null,
},
// 子模块抽屉/表单
subDrawerOpen: false,
subLoading: false,
subList: [],
currentModule: null,
subOpen: false,
subTitle: '新增子模块',
subForm: { subName: null, description: null },
subRules: { subName: [{ required: true, message: '子模块名称不能为空', trigger: 'blur' }] }
};
},
created() {
this.buildUserRolesText();
this.getList();
},
methods: {
/** 统一判断当前用户是否为模块接取人兼容ID/用户名/昵称) */
isSelfAssignee(row) {
if (!row) return false
// 优先使用后端返回的 assigneeId标准用户ID
if (row.assigneeId != null && String(row.assigneeId) === String(this.userId)) return true
const assignee = row.assignee
const uid = String(this.userId)
if (!assignee) return false
// 精确匹配ID 字符串
if (String(assignee) === uid) return true
// 兼容用户名/昵称(后端展示通过 COALESCE 可能为 nick_name 或 user_name
const currentUserName = this.$store.getters && this.$store.getters.name
const currentNickName = this.$store.getters && this.$store.getters.nickName
return assignee === currentUserName || assignee === currentNickName
},
/** 打开子模块抽屉(统一入口) */
openSubDrawer(row) {
this.currentModule = row
this.subDrawerOpen = true
this.loadSubList()
},
/** 行点击触发展开 */
handleRowClick(row, column) {
if (column && column.type === 'selection') return
this.openSubDrawer(row)
},
/** 单元格点击兜底触发 */
handleCellClick(row, column) {
if (column && column.type === 'selection') return
if (!this.subDrawerOpen || !this.currentModule || this.currentModule.moduleId !== row.moduleId) {
this.openSubDrawer(row)
}
},
/** 拉取子模块列表 */
loadSubList() {
if (!this.currentModule) return
this.subLoading = true
listSubmoduleByModule(this.currentModule.moduleId).then(res => {
this.subList = res.rows || []
this.subLoading = false
}).catch(() => { this.subLoading = false })
},
/** 打开新增子模块 */
handleOpenAddSub() {
this.subForm = { subId: null, subName: null, description: null }
this.subOpen = true
},
/** 提交新增子模块 */
submitSubForm() {
this.$refs['subForm'].validate(valid => {
if (!valid) return
// 新增或修改
if (!this.subForm.subId) {
const payload = {
moduleId: this.currentModule.moduleId,
subName: this.subForm.subName,
description: this.subForm.description,
status: '0'
}
addSubmodule(payload).then(() => {
this.$modal.msgSuccess('新增子模块成功')
this.subOpen = false
this.loadSubList()
})
} else {
const payload = {
subId: this.subForm.subId,
moduleId: this.currentModule.moduleId,
subName: this.subForm.subName,
description: this.subForm.description
}
updateSubmodule(payload).then(() => {
this.$modal.msgSuccess('修改子模块成功')
this.subOpen = false
this.loadSubList()
})
}
})
},
/** 可操作判定(仅父模块接取人) */
canOperateSub() {
if (!this.currentModule) return false
// 优先使用后端返回的标准 ID
if (this.currentModule.assigneeId != null && String(this.currentModule.assigneeId) === String(this.userId)) {
return true
}
const assignee = this.currentModule.assignee
if (!assignee) return false
// 兼容旧数据ID字符串/用户名/昵称
if (String(assignee) === String(this.userId)) return true
const currentUserName = this.$store.getters && this.$store.getters.name
const currentNickName = this.$store.getters && this.$store.getters.nickName
return assignee === currentUserName || assignee === currentNickName
},
/** 编辑子模块 */
handleEditSub(row) {
if (!this.canOperateSub()) return
this.subForm = { subId: row.subId, subName: row.subName, description: row.description }
this.subTitle = '修改子模块'
this.subOpen = true
},
/** 删除子模块 */
handleDeleteSub(row) {
if (!this.canOperateSub()) return
this.$modal.confirm('确认删除子模块 "' + row.subName + '" ').then(() => {
return delSubmodule(row.subId)
}).then(() => {
this.$modal.msgSuccess('删除成功')
this.loadSubList()
})
},
/** 完成子模块 */
handleCompleteSub(row) {
if (!this.canOperateSub()) return
if (row.status !== '1') {
this.$modal.msgError('仅进行中的子模块可完成')
return
}
this.$modal.confirm('确认将子模块 "' + row.subName + '" 标记为完成?').then(() => {
return completeSubmodule(row.subId)
}).then(() => {
this.$modal.msgSuccess('已完成')
this.loadSubList()
})
},
/** 将角色英文key转换为中文展示 */
buildUserRolesText() {
const roles = this.$store.state.user.roles || [];
const keyToCn = {
platform_admin: '平台管理员',
project_admin: '项目管理员',
normal_user: '普通用户'
};
const names = roles.map(role => {
if (typeof role === 'object') {
// roleName 若已是中文优先显示
if (role.roleName) return role.roleName;
if (role.roleKey && keyToCn[role.roleKey]) return keyToCn[role.roleKey];
return role.roleKey || '未知角色';
} else if (typeof role === 'string') {
return keyToCn[role] || role;
}
return '未知角色';
});
this.userRoles = names.join('') || '无角色信息';
},
/** 查询我的模块列表 */
getList() {
this.loading = true;
getMyModules(this.queryParams).then(response => {
this.moduleList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.moduleId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 接取按钮操作 */
handleClaim(row) {
this.$modal.confirm('确认接取模块"' + row.moduleName + '"').then(() => {
return claimModule(row.moduleId);
}).then(() => {
this.getList();
this.$modal.msgSuccess("接取成功");
});
},
/** 放弃按钮操作 */
handleGiveup(row) {
this.$modal.confirm('确认放弃模块"' + row.moduleName + '"').then(() => {
return giveupModule(row.moduleId);
}).then(() => {
this.getList();
this.$modal.msgSuccess("放弃成功");
});
},
/** 新增按钮操作 */
handleAdd() {
this.$router.push('/project/module');
},
/** 修改按钮操作 */
handleUpdate(row) {
this.$router.push('/project/module');
},
/** 删除按钮操作 */
handleDelete(row) {
this.$modal.msgInfo("请到模块管理页面进行删除操作");
},
/** 导出按钮操作 */
handleExport() {
this.$modal.msgInfo("请到模块管理页面进行导出操作");
},
/** 完成模块操作 */
handleComplete(row) {
this.$modal.confirm('确认完成模块"' + row.moduleName + '"').then(() => {
return completeModule(row.moduleId);
}).then(() => {
this.getList();
this.$modal.msgSuccess("模块已完成");
});
},
/** 上传文档操作 */
handleUpload(row) {
// 跳转到文档上传页面传递模块ID和类型
this.$router.push({
path: '/project/doc',
query: {
pmodel_id: row.moduleId,
kind_type: 1, // 1表示模块文档
moduleName: row.moduleName,
projectId: row.projectId,
projectName: row.projectName
}
});
},
/** 查看文档操作 */
handleViewDocs(row) {
// 跳转到文档查看页面传递模块ID和类型
this.$router.push({
path: '/project/doc',
query: {
pmodel_id: row.moduleId,
kind_type: 1, // 1表示模块文档
moduleName: row.moduleName,
projectId: row.projectId,
projectName: row.projectName,
view: 'true'
}
});
},
/** 指派模块操作 */
handleAssign(row) {
this.$modal.msgInfo("请到模块管理页面进行指派操作");
},
/** 重新指派模块操作 */
handleReassign(row) {
this.$modal.msgInfo("请到模块管理页面进行重新指派操作");
},
/** 获取模块状态文本 */
getModuleStatusText(row) {
let statusText = '';
if (row.status === '0') {
if (row.designatedUser) {
statusText = `已指派给用户 ${row.designatedUser}`;
} else {
statusText = '待接取';
}
} else if (row.status === '1') {
statusText = `进行中 - 接取人: ${row.assignee || '未知'}`;
} else if (row.status === '2') {
statusText = `已完成 - 完成时间: ${this.parseTime(row.finishTime, '{y}-{m}-{d}')}`;
}
return statusText;
}
}
};
</script>