|
@@ -1,34 +1,26 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div>
|
|
<div>
|
|
|
<el-card>
|
|
<el-card>
|
|
|
- <!--工具条-->
|
|
|
|
|
- <el-col :span="24" class="toolbar">
|
|
|
|
|
- <el-form :inline="true">
|
|
|
|
|
- <el-form-item :label="$t('状态') || '状态'">
|
|
|
|
|
- <el-select
|
|
|
|
|
- v-model="status"
|
|
|
|
|
- placeholder="请选择"
|
|
|
|
|
- clearable
|
|
|
|
|
- size="small"
|
|
|
|
|
- @change="loadData()"
|
|
|
|
|
- >
|
|
|
|
|
- <el-option label="待审批" value="1"></el-option>
|
|
|
|
|
- <el-option label="审批通过" value="2"></el-option>
|
|
|
|
|
- <el-option label="审批驳回" value="3"></el-option>
|
|
|
|
|
- <el-option label="已撤销" value="4"></el-option>
|
|
|
|
|
- <el-option label="全部" value="0"></el-option>
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- <el-form-item>
|
|
|
|
|
- <el-button size="small" type="primary" @click="loadData"
|
|
|
|
|
- >查询</el-button
|
|
|
|
|
- >
|
|
|
|
|
- <el-button size="small" type="warning" @click="openConfig"
|
|
|
|
|
- >配置审批流程</el-button
|
|
|
|
|
- >
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-form>
|
|
|
|
|
- </el-col>
|
|
|
|
|
|
|
+ <closure-filter
|
|
|
|
|
+ :status="status"
|
|
|
|
|
+ :project-keyword="projectKeyword"
|
|
|
|
|
+ @change="statusChange"
|
|
|
|
|
+ @project-change="projectChange"
|
|
|
|
|
+ @search="searchList"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #actions>
|
|
|
|
|
+ <el-button size="small" type="primary" @click="searchList"
|
|
|
|
|
+ >查询</el-button
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ v-if="isSuperAdministrator"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ type="warning"
|
|
|
|
|
+ @click="openConfig"
|
|
|
|
|
+ >配置审批流程</el-button
|
|
|
|
|
+ >
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </closure-filter>
|
|
|
|
|
|
|
|
<!--列表-->
|
|
<!--列表-->
|
|
|
<el-table
|
|
<el-table
|
|
@@ -56,7 +48,7 @@
|
|
|
<el-table-column
|
|
<el-table-column
|
|
|
prop="currentStepDisplay"
|
|
prop="currentStepDisplay"
|
|
|
:label="$t('当前步骤') || '当前步骤'"
|
|
:label="$t('当前步骤') || '当前步骤'"
|
|
|
- width="100"
|
|
|
|
|
|
|
+ width="160"
|
|
|
></el-table-column>
|
|
></el-table-column>
|
|
|
<el-table-column
|
|
<el-table-column
|
|
|
prop="status"
|
|
prop="status"
|
|
@@ -162,13 +154,15 @@
|
|
|
width="60"
|
|
width="60"
|
|
|
align="center"
|
|
align="center"
|
|
|
></el-table-column>
|
|
></el-table-column>
|
|
|
- <el-table-column label="审批角色" min-width="180">
|
|
|
|
|
|
|
+ <el-table-column label="审批角色" min-width="160">
|
|
|
<template slot-scope="scope">
|
|
<template slot-scope="scope">
|
|
|
<el-select
|
|
<el-select
|
|
|
v-model="scope.row.role"
|
|
v-model="scope.row.role"
|
|
|
|
|
+ value-key="id"
|
|
|
placeholder="选择角色"
|
|
placeholder="选择角色"
|
|
|
size="small"
|
|
size="small"
|
|
|
class="role-select"
|
|
class="role-select"
|
|
|
|
|
+ @change="onRoleChange(scope.$index)"
|
|
|
>
|
|
>
|
|
|
<el-option
|
|
<el-option
|
|
|
v-for="role in roleList"
|
|
v-for="role in roleList"
|
|
@@ -179,6 +173,27 @@
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
|
|
+ <el-table-column label="审批人员" min-width="160">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-select
|
|
|
|
|
+ v-model="scope.row.approver"
|
|
|
|
|
+ value-key="id"
|
|
|
|
|
+ placeholder="选择人员"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ class="user-select"
|
|
|
|
|
+ :disabled="!scope.row.role"
|
|
|
|
|
+ :loading="scope.row.userLoading"
|
|
|
|
|
+ @change="onApproverChange(scope.$index)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-option
|
|
|
|
|
+ v-for="user in scope.row.userList"
|
|
|
|
|
+ :key="user.id"
|
|
|
|
|
+ :label="user.name"
|
|
|
|
|
+ :value="user"
|
|
|
|
|
+ ></el-option>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
<el-table-column label="操作" width="280" align="center">
|
|
<el-table-column label="操作" width="280" align="center">
|
|
|
<template slot-scope="scope">
|
|
<template slot-scope="scope">
|
|
|
<div class="action-buttons">
|
|
<div class="action-buttons">
|
|
@@ -219,12 +234,17 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
|
|
+import ClosureFilter from "@/components/ClosureFilter.vue";
|
|
|
export default {
|
|
export default {
|
|
|
|
|
+ components: {
|
|
|
|
|
+ ClosureFilter,
|
|
|
|
|
+ },
|
|
|
data() {
|
|
data() {
|
|
|
return {
|
|
return {
|
|
|
list: [],
|
|
list: [],
|
|
|
listLoading: true,
|
|
listLoading: true,
|
|
|
- status: 0,
|
|
|
|
|
|
|
+ status: "",
|
|
|
|
|
+ projectKeyword: "",
|
|
|
currentPage: 1,
|
|
currentPage: 1,
|
|
|
pageSize: 10,
|
|
pageSize: 10,
|
|
|
total: 0,
|
|
total: 0,
|
|
@@ -236,6 +256,7 @@ export default {
|
|
|
},
|
|
},
|
|
|
configSteps: [],
|
|
configSteps: [],
|
|
|
roleList: [],
|
|
roleList: [],
|
|
|
|
|
+ roleUserCache: {},
|
|
|
};
|
|
};
|
|
|
},
|
|
},
|
|
|
computed: {
|
|
computed: {
|
|
@@ -249,6 +270,10 @@ export default {
|
|
|
user() {
|
|
user() {
|
|
|
return JSON.parse(sessionStorage.getItem("user") || "{}");
|
|
return JSON.parse(sessionStorage.getItem("user") || "{}");
|
|
|
},
|
|
},
|
|
|
|
|
+ isSuperAdministrator() {
|
|
|
|
|
+ const roleName = this.user.roleName || this.user.rolename || "";
|
|
|
|
|
+ return roleName === this.$t("role.superAdministrator") || roleName === "超级管理员";
|
|
|
|
|
+ },
|
|
|
},
|
|
},
|
|
|
created() {
|
|
created() {
|
|
|
this.loadData();
|
|
this.loadData();
|
|
@@ -256,13 +281,19 @@ export default {
|
|
|
methods: {
|
|
methods: {
|
|
|
loadData() {
|
|
loadData() {
|
|
|
this.listLoading = true;
|
|
this.listLoading = true;
|
|
|
- const url = `/project-closure-apply/my-pending?userId=${this.userId}¤t=${this.currentPage}&size=${this.pageSize}&status=${this.status}`;
|
|
|
|
|
|
|
+ const url = `/project-closure-apply/my-pending?userId=${this.userId}¤t=${this.currentPage}&size=${this.pageSize}&status=${this.status}${this.projectKeyword ? `&projectKeyword=${encodeURIComponent(this.projectKeyword)}` : ''}`;
|
|
|
this.http.get(
|
|
this.http.get(
|
|
|
url,
|
|
url,
|
|
|
(res) => {
|
|
(res) => {
|
|
|
if (res.code === 200 || res.code === "ok") {
|
|
if (res.code === 200 || res.code === "ok") {
|
|
|
const data = res.data;
|
|
const data = res.data;
|
|
|
- this.list = data.records || [];
|
|
|
|
|
|
|
+ this.list = (data.records || []).map((item) => ({
|
|
|
|
|
+ ...item,
|
|
|
|
|
+ currentStepDisplay:
|
|
|
|
|
+ item.currentStepDisplay && item.currentStepDisplay !== "1/1"
|
|
|
|
|
+ ? item.currentStepDisplay
|
|
|
|
|
+ : item.currentStepDisplay,
|
|
|
|
|
+ }));
|
|
|
this.total = data.total || 0;
|
|
this.total = data.total || 0;
|
|
|
}
|
|
}
|
|
|
this.listLoading = false;
|
|
this.listLoading = false;
|
|
@@ -277,6 +308,24 @@ export default {
|
|
|
this.currentPage = 1;
|
|
this.currentPage = 1;
|
|
|
this.loadData();
|
|
this.loadData();
|
|
|
},
|
|
},
|
|
|
|
|
+ statusChange(val) {
|
|
|
|
|
+ this.status = val;
|
|
|
|
|
+ this.loadData();
|
|
|
|
|
+ },
|
|
|
|
|
+ projectChange(val) {
|
|
|
|
|
+ this.projectKeyword = val;
|
|
|
|
|
+ },
|
|
|
|
|
+ searchList(payload) {
|
|
|
|
|
+ if (payload && typeof payload === 'object') {
|
|
|
|
|
+ if (payload.status !== undefined) {
|
|
|
|
|
+ this.status = payload.status;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload.projectKeyword !== undefined) {
|
|
|
|
|
+ this.projectKeyword = payload.projectKeyword;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ this.loadData();
|
|
|
|
|
+ },
|
|
|
handleCurrentChange(val) {
|
|
handleCurrentChange(val) {
|
|
|
this.currentPage = val;
|
|
this.currentPage = val;
|
|
|
this.loadData();
|
|
this.loadData();
|
|
@@ -293,7 +342,7 @@ export default {
|
|
|
this.http.post(
|
|
this.http.post(
|
|
|
`/project-closure-apply/approve?applyId=${
|
|
`/project-closure-apply/approve?applyId=${
|
|
|
this.currentApply.id
|
|
this.currentApply.id
|
|
|
- }&applierId=${this.userId}&comment=${encodeURIComponent(
|
|
|
|
|
|
|
+ }&approverUserId=${this.userId}&comment=${encodeURIComponent(
|
|
|
this.approveForm.comment,
|
|
this.approveForm.comment,
|
|
|
)}&action=${action}`,
|
|
)}&action=${action}`,
|
|
|
{},
|
|
{},
|
|
@@ -303,15 +352,32 @@ export default {
|
|
|
this.approveDialog = false;
|
|
this.approveDialog = false;
|
|
|
this.loadData();
|
|
this.loadData();
|
|
|
this.$emit("success");
|
|
this.$emit("success");
|
|
|
|
|
+ const isFirstNodeReject =
|
|
|
|
|
+ action === 3 &&
|
|
|
|
|
+ (this.currentApply.currentStep === 0 ||
|
|
|
|
|
+ this.currentApply.currentStep === "0");
|
|
|
|
|
+ if (isFirstNodeReject) {
|
|
|
|
|
+ this.updateProjectStatus(2);
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
this.$message.error(res.msg || "审批失败");
|
|
this.$message.error(res.msg || "审批失败");
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
);
|
|
);
|
|
|
},
|
|
},
|
|
|
|
|
+ updateProjectStatus(status) {
|
|
|
|
|
+ const projectId = this.currentApply.projectId || this.currentApply.id;
|
|
|
|
|
+ if (!projectId) return;
|
|
|
|
|
+ this.http.post(
|
|
|
|
|
+ `/project/updateStatus?projectId=${projectId}&status=${status}`,
|
|
|
|
|
+ {},
|
|
|
|
|
+ () => {},
|
|
|
|
|
+ );
|
|
|
|
|
+ },
|
|
|
// ========== 审批流程配置相关方法 ==========
|
|
// ========== 审批流程配置相关方法 ==========
|
|
|
openConfig() {
|
|
openConfig() {
|
|
|
this.configDialog = true;
|
|
this.configDialog = true;
|
|
|
|
|
+ this.roleUserCache = {};
|
|
|
// 先加载角色列表,角色列表加载完成后再加载配置
|
|
// 先加载角色列表,角色列表加载完成后再加载配置
|
|
|
const companyId = this.user.companyId;
|
|
const companyId = this.user.companyId;
|
|
|
this.http.post("/permission/getRoleList", { companyId }, (res) => {
|
|
this.http.post("/permission/getRoleList", { companyId }, (res) => {
|
|
@@ -320,15 +386,29 @@ export default {
|
|
|
const roleIdToRole = {};
|
|
const roleIdToRole = {};
|
|
|
this.roleList.forEach((role) => {
|
|
this.roleList.forEach((role) => {
|
|
|
roleIdToRole[role.id] = role;
|
|
roleIdToRole[role.id] = role;
|
|
|
|
|
+ roleIdToRole[String(role.id)] = role;
|
|
|
});
|
|
});
|
|
|
// 角色列表加载完成后,再加载审批配置
|
|
// 角色列表加载完成后,再加载审批配置
|
|
|
- this.http.get("/project-closure-apply/config/list", (res2) => {
|
|
|
|
|
- if (res2.code === 200 || res2.code === "ok") {
|
|
|
|
|
- this.configSteps = (res2.data || []).map((step) => ({
|
|
|
|
|
- role: roleIdToRole[step.roleId] || null,
|
|
|
|
|
- }));
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const companyId = this.user.companyId;
|
|
|
|
|
+ this.http.get(
|
|
|
|
|
+ "/project-closure-apply/config/list?companyId=" + companyId,
|
|
|
|
|
+ (res2) => {
|
|
|
|
|
+ if (res2.code === 200 || res2.code === "ok") {
|
|
|
|
|
+ this.configSteps = (res2.data || []).map((step) => ({
|
|
|
|
|
+ role: roleIdToRole[step.roleId] || null,
|
|
|
|
|
+ approver: step.userList
|
|
|
|
|
+ ? step.userList.find((u) => u.id === step.approverUserId) ||
|
|
|
|
|
+ null
|
|
|
|
|
+ : null,
|
|
|
|
|
+ userList: step.userList || [],
|
|
|
|
|
+ userLoading: false,
|
|
|
|
|
+ roleId: step.roleId || null,
|
|
|
|
|
+ approverUserId: step.approverUserId || null,
|
|
|
|
|
+ approverName: step.approverName || "",
|
|
|
|
|
+ }));
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
} else {
|
|
} else {
|
|
|
this.$message.error(res.msg || "加载角色列表失败");
|
|
this.$message.error(res.msg || "加载角色列表失败");
|
|
|
this.roleList = [];
|
|
this.roleList = [];
|
|
@@ -336,7 +416,15 @@ export default {
|
|
|
});
|
|
});
|
|
|
},
|
|
},
|
|
|
addStep() {
|
|
addStep() {
|
|
|
- this.configSteps.push({ role: null });
|
|
|
|
|
|
|
+ this.configSteps.push({
|
|
|
|
|
+ role: null,
|
|
|
|
|
+ approver: null,
|
|
|
|
|
+ userList: [],
|
|
|
|
|
+ userLoading: false,
|
|
|
|
|
+ roleId: null,
|
|
|
|
|
+ approverUserId: null,
|
|
|
|
|
+ approverName: "",
|
|
|
|
|
+ });
|
|
|
},
|
|
},
|
|
|
removeStep(index) {
|
|
removeStep(index) {
|
|
|
this.configSteps.splice(index, 1);
|
|
this.configSteps.splice(index, 1);
|
|
@@ -348,20 +436,83 @@ export default {
|
|
|
const item = this.configSteps.splice(index, 1)[0];
|
|
const item = this.configSteps.splice(index, 1)[0];
|
|
|
this.configSteps.splice(newIndex, 0, item);
|
|
this.configSteps.splice(newIndex, 0, item);
|
|
|
},
|
|
},
|
|
|
|
|
+ onRoleChange(index) {
|
|
|
|
|
+ const step = this.configSteps[index];
|
|
|
|
|
+ // 重置人员选择
|
|
|
|
|
+ step.approver = null;
|
|
|
|
|
+ step.approverUserId = null;
|
|
|
|
|
+ step.approverName = "";
|
|
|
|
|
+ step.userList = [];
|
|
|
|
|
+ if (!step.role) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ step.roleId = step.role.id;
|
|
|
|
|
+ step.userLoading = true;
|
|
|
|
|
+ // 如果已经缓存了该角色的用户,直接使用
|
|
|
|
|
+ if (this.roleUserCache[step.role.id]) {
|
|
|
|
|
+ step.userList = this.roleUserCache[step.role.id];
|
|
|
|
|
+ step.userLoading = false;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 否则从后端获取该角色的用户列表
|
|
|
|
|
+ const companyId = this.user.companyId;
|
|
|
|
|
+ this.http.post(
|
|
|
|
|
+ "/permission/getRoleUserList",
|
|
|
|
|
+ { roleId: step.role.id, companyId },
|
|
|
|
|
+ (res) => {
|
|
|
|
|
+ if (res.code === 200 || res.code === "ok") {
|
|
|
|
|
+ step.userList = res.data || [];
|
|
|
|
|
+ this.$set(this.roleUserCache, step.role.id, step.userList);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ step.userList = [];
|
|
|
|
|
+ this.$message.error(res.msg || "获取用户列表失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ step.userLoading = false;
|
|
|
|
|
+ },
|
|
|
|
|
+ () => {
|
|
|
|
|
+ step.userLoading = false;
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
|
|
+ },
|
|
|
|
|
+ onApproverChange(index) {
|
|
|
|
|
+ const step = this.configSteps[index];
|
|
|
|
|
+ step.approverUserId = step.approver ? step.approver.id : null;
|
|
|
|
|
+ step.approverName = step.approver ? step.approver.name : "";
|
|
|
|
|
+ },
|
|
|
saveConfig() {
|
|
saveConfig() {
|
|
|
|
|
+ // 校验
|
|
|
|
|
+ for (let i = 0; i < this.configSteps.length; i++) {
|
|
|
|
|
+ const step = this.configSteps[i];
|
|
|
|
|
+ if (!step.role) {
|
|
|
|
|
+ this.$message.warning(`第${i + 1}步请选择审批角色`);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!step.approver) {
|
|
|
|
|
+ this.$message.warning(`第${i + 1}步请选择审批人员`);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
const payload = this.configSteps.map((step, index) => ({
|
|
const payload = this.configSteps.map((step, index) => ({
|
|
|
stepOrder: index + 1,
|
|
stepOrder: index + 1,
|
|
|
- roleId: step.role ? step.role.id : null,
|
|
|
|
|
- roleName: step.role ? step.role.roleName : "",
|
|
|
|
|
|
|
+ roleId: step.roleId || (step.role ? step.role.id : null),
|
|
|
|
|
+ roleName: step.role ? step.role.rolename : "",
|
|
|
|
|
+ approverUserId:
|
|
|
|
|
+ step.approverUserId || (step.approver ? step.approver.id : null),
|
|
|
|
|
+ approverName:
|
|
|
|
|
+ step.approverName || (step.approver ? step.approver.name : ""),
|
|
|
}));
|
|
}));
|
|
|
- this.http.post("/project-closure-apply/config/save", payload, (res) => {
|
|
|
|
|
- if (res.code === 200 || res.code === "ok") {
|
|
|
|
|
- this.$message.success("配置保存成功");
|
|
|
|
|
- this.configDialog = false;
|
|
|
|
|
- } else {
|
|
|
|
|
- this.$message.error(res.msg || "保存失败");
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ this.http.JSONPost(
|
|
|
|
|
+ "/project-closure-apply/config/save?companyId=" + this.user.companyId,
|
|
|
|
|
+ payload,
|
|
|
|
|
+ (res) => {
|
|
|
|
|
+ if (res.code === 200 || res.code === "ok") {
|
|
|
|
|
+ this.$message.success("配置保存成功");
|
|
|
|
|
+ this.configDialog = false;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.$message.error(res.msg || "保存失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
};
|
|
};
|
|
@@ -380,7 +531,8 @@ export default {
|
|
|
overflow-x: visible;
|
|
overflow-x: visible;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.role-select {
|
|
|
|
|
|
|
+.role-select,
|
|
|
|
|
+.user-select {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
}
|
|
}
|
|
|
|
|
|