Compare commits
31 Commits
Author | SHA1 | Date |
---|---|---|
|
5de5b930bf | |
|
e63e98399a | |
|
c66e0e5f06 | |
|
5757b4d23c | |
|
b3bd2eff61 | |
|
b1251e3bc5 | |
|
bc1c74ce55 | |
|
659108a7ac | |
|
cf743c0dd6 | |
|
da50ed138f | |
|
f9a402e991 | |
|
6032c814e2 | |
|
338b1ef8bd | |
|
5327adc0ea | |
|
6160798087 | |
|
e7a69e87f8 | |
|
3a7e373394 | |
|
829acc5857 | |
|
74de4ef76c | |
|
8d02e76518 | |
|
7532d5cf47 | |
|
434a20f0a6 | |
|
43492eb5d2 | |
|
4d62c1baba | |
|
0392aab0e1 | |
|
35a32950a7 | |
|
bfa923b3ac | |
|
c8bb8ef089 | |
|
90867530d3 | |
|
5f860e2fed | |
|
ecacb4dc02 |
|
@ -21,3 +21,4 @@ selenium-debug.log
|
||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
|
/npm
|
||||||
|
|
After Width: | Height: | Size: 606 B |
After Width: | Height: | Size: 775 B |
After Width: | Height: | Size: 804 B |
After Width: | Height: | Size: 241 B |
After Width: | Height: | Size: 338 B |
After Width: | Height: | Size: 1000 B |
After Width: | Height: | Size: 352 B |
|
@ -1,5 +1,4 @@
|
||||||
@use 'sass:math';
|
@use "sass:math";
|
||||||
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -9,7 +8,7 @@
|
||||||
-webkit-user-select: text;
|
-webkit-user-select: text;
|
||||||
-ms-user-select: text;
|
-ms-user-select: text;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
font-family: AliPuHui;
|
font-family: PingFang SC;
|
||||||
}
|
}
|
||||||
$lightThemColor: #3686ff;
|
$lightThemColor: #3686ff;
|
||||||
html {
|
html {
|
||||||
|
@ -105,11 +104,6 @@ body {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//外边距
|
//外边距
|
||||||
.ml10 {
|
.ml10 {
|
||||||
margin-left: 0.1rem;
|
margin-left: 0.1rem;
|
||||||
|
@ -179,7 +173,6 @@ body {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 竖向弹性盒子 */
|
/* 竖向弹性盒子 */
|
||||||
.flex-col {
|
.flex-col {
|
||||||
@include flex-row-vc;
|
@include flex-row-vc;
|
||||||
|
@ -256,7 +249,6 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// dialog弹出给body加了该类名,导致页面右侧偏移
|
// dialog弹出给body加了该类名,导致页面右侧偏移
|
||||||
.el-popup-parent--hidden {
|
.el-popup-parent--hidden {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
|
@ -286,7 +278,6 @@ body {
|
||||||
border-radius: 0.1rem;
|
border-radius: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
:deep(.el-form-item__content) {
|
:deep(.el-form-item__content) {
|
||||||
align-items: flex-start !important;
|
align-items: flex-start !important;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +297,6 @@ body {
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
:deep(.el-button--primary:not(.is-text)) {
|
:deep(.el-button--primary:not(.is-text)) {
|
||||||
background-color: #5584ff !important ;
|
background-color: #5584ff !important ;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
|
@ -322,3 +312,8 @@ body {
|
||||||
:deep(.el-dialog--center .el-dialog__body) {
|
:deep(.el-dialog--center .el-dialog__body) {
|
||||||
padding: 32px !important;
|
padding: 32px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-buttons {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
|
@ -289,3 +289,5 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 223 B |
After Width: | Height: | Size: 1000 B |
After Width: | Height: | Size: 14 KiB |
|
@ -9,10 +9,19 @@
|
||||||
:border="border"
|
:border="border"
|
||||||
:highlight-current-row="highligt"
|
:highlight-current-row="highligt"
|
||||||
@row-click="rowClick"
|
@row-click="rowClick"
|
||||||
|
@sort-change="sortChange"
|
||||||
:row-key="rowKey"
|
:row-key="rowKey"
|
||||||
:height="tableHeight"
|
:height="tableHeight"
|
||||||
|
@select="selected"
|
||||||
|
@select-all="selectAll"
|
||||||
>
|
>
|
||||||
<el-table-column v-if="showSelection" type="selection" width="55" />
|
<el-table-column
|
||||||
|
reserve-selection
|
||||||
|
v-if="showSelection"
|
||||||
|
type="selection"
|
||||||
|
width="55"
|
||||||
|
:selectable="selectable"
|
||||||
|
/>
|
||||||
<el-table-column v-if="showIndex" type="index" width="50" label="序号" />
|
<el-table-column v-if="showIndex" type="index" width="50" label="序号" />
|
||||||
<template>
|
<template>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
|
@ -21,6 +30,7 @@
|
||||||
:label="column.label"
|
:label="column.label"
|
||||||
v-for="(column, index) in columns"
|
v-for="(column, index) in columns"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
:sortable="column.sortable"
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<slot :name="column.prop" :row="scope.row">
|
<slot :name="column.prop" :row="scope.row">
|
||||||
|
@ -146,6 +156,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: "100%",
|
default: "100%",
|
||||||
},
|
},
|
||||||
|
selectable:{
|
||||||
|
type: Function,
|
||||||
|
default: ()=>true,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -170,7 +184,7 @@ export default {
|
||||||
this.$emit("current-change", val);
|
this.$emit("current-change", val);
|
||||||
},
|
},
|
||||||
setCurrentRow(row) {
|
setCurrentRow(row) {
|
||||||
this.$refs.elTableRef.setCurrentRow(row);
|
this.$refs.elTableRef?.setCurrentRow(row);
|
||||||
},
|
},
|
||||||
clearSelection() {
|
clearSelection() {
|
||||||
this.$refs.elTableRef?.clearSelection();
|
this.$refs.elTableRef?.clearSelection();
|
||||||
|
@ -178,12 +192,22 @@ export default {
|
||||||
toggleRowSelection(row, selected) {
|
toggleRowSelection(row, selected) {
|
||||||
this.$refs.elTableRef?.toggleRowSelection(row, selected);
|
this.$refs.elTableRef?.toggleRowSelection(row, selected);
|
||||||
},
|
},
|
||||||
|
sortChange(data) {
|
||||||
|
this.$emit("sortChange", data);
|
||||||
|
},
|
||||||
|
selected(arr, row) {
|
||||||
|
this.$emit("selected", { arr, row });
|
||||||
|
},
|
||||||
|
selectAll(arr) {
|
||||||
|
this.$emit("selectAll", arr);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
if (this.$refs.elTableRef && this.$refs.elTableRef.doLayout) {
|
if (this.$refs.elTableRef && this.$refs.elTableRef.doLayout) {
|
||||||
this.$refs.elTableRef.doLayout();
|
this.$refs.elTableRef.doLayout();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {},
|
mounted() {},
|
||||||
beforeDestroy() {},
|
beforeDestroy() {},
|
||||||
};
|
};
|
||||||
|
@ -208,12 +232,17 @@ export default {
|
||||||
--el-table-text-align: center;
|
--el-table-text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex: none;
|
flex: none;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .el-table th {
|
::v-deep .el-table th {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
::v-deep .operation-column .el-button-text {
|
||||||
|
font-weight: 600 !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
::v-deep .el-table .cell {
|
::v-deep .el-table .cell {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -239,4 +268,7 @@ export default {
|
||||||
::v-deep .el-table {
|
::v-deep .el-table {
|
||||||
max-height: 99%;
|
max-height: 99%;
|
||||||
}
|
}
|
||||||
|
::v-deep .el-table .el-table__body .el-table__cell {
|
||||||
|
padding: 15px 0 !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,29 +1,71 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog title="选择人员" :visible="dialogVisible" width="50%" @close="handleClose">
|
<el-dialog
|
||||||
|
title="选择人员"
|
||||||
|
:visible="dialogVisible"
|
||||||
|
width="50%"
|
||||||
|
@close="handleClose"
|
||||||
|
>
|
||||||
<div class="select-user-container">
|
<div class="select-user-container">
|
||||||
<div class="org-tree">
|
<div class="org-tree">
|
||||||
<el-tree :data="treeData" :props="defaultProps" @node-click="handleNodeClick" default-expand-all />
|
<el-tree
|
||||||
|
:data="treeData"
|
||||||
|
:props="defaultProps"
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
default-expand-all
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-list">
|
<div class="user-list">
|
||||||
|
<div class="flex-row aic jcfe mb10" style="gap: 10px">
|
||||||
|
<el-input
|
||||||
|
v-model="searchForm.nickName"
|
||||||
|
style="width: 300px"
|
||||||
|
placeholder="输入名称"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" size="medium" @click="fetchUserList"
|
||||||
|
>查询</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" size="medium" @click="resetTable"
|
||||||
|
>重置</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<CustomTable
|
<CustomTable
|
||||||
ref="customTableRef"
|
ref="customTableRef"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:tableData="userData"
|
:tableData="userData"
|
||||||
:total="total"
|
:total="total"
|
||||||
:show-selection="true"
|
:show-selection="showSelection"
|
||||||
:show-index="true"
|
:show-index="true"
|
||||||
:table-height="tableHeight"
|
:table-height="tableHeight"
|
||||||
:multiSelect="multiSelect"
|
:multiSelect="multiSelect"
|
||||||
|
:selectable="selectable"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
@selected="selectRow"
|
||||||
|
@selectAll="selectAll"
|
||||||
|
rowKey="userId"
|
||||||
|
:rowClick="
|
||||||
|
(row) => {
|
||||||
|
rowClick(row);
|
||||||
|
}
|
||||||
|
"
|
||||||
maxHeight="380"
|
maxHeight="380"
|
||||||
|
:highligt="highligt"
|
||||||
>
|
>
|
||||||
<template slot="operation" slot-scope="{ row }">
|
<template slot="operation" slot-scope="{ row }">
|
||||||
<div class="operation-buttons">
|
<div class="operation-buttons">
|
||||||
<el-button text type="primary" @click="handleEdit(row)">编辑</el-button>
|
<el-button text type="primary" @click="handleEdit(row)"
|
||||||
<el-button text type="primary" @click="showTimesheet(row)">工作日志</el-button>
|
>编辑</el-button
|
||||||
<el-button text type="danger" @click="handleDelete(row)">删除</el-button>
|
>
|
||||||
|
<el-button text type="primary" @click="showTimesheet(row)"
|
||||||
|
>工作日志</el-button
|
||||||
|
>
|
||||||
|
<el-button text type="danger" @click="handleDelete(row)"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</CustomTable>
|
</CustomTable>
|
||||||
|
@ -39,8 +81,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CustomTable from '@/components/CustomTable.vue'
|
import CustomTable from "@/components/CustomTable.vue";
|
||||||
import { systemApi } from '@/utils/api'
|
import { systemApi } from "@/utils/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -53,12 +95,37 @@ export default {
|
||||||
},
|
},
|
||||||
dialogVisible: {
|
dialogVisible: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true,
|
default: true,
|
||||||
},
|
},
|
||||||
currentSelectedUser: {
|
currentSelectedUser: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
currentSelectedUserName: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
showSelection: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
highligt: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
selectable: {
|
||||||
|
type: Function,
|
||||||
|
default: () => true,
|
||||||
|
},
|
||||||
|
userIdList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
isFilter: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -66,106 +133,229 @@ export default {
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
selectedUsers: [],
|
selectedUsers: [],
|
||||||
currentDepartment: '',
|
currentDepartment: "",
|
||||||
tableHeight: 350, // 设置一个合适的高度
|
tableHeight: "350", // 设置一个合适的高度
|
||||||
treeData: [],
|
treeData: [],
|
||||||
defaultProps: {
|
defaultProps: {
|
||||||
children: 'children',
|
children: "children",
|
||||||
label: 'label',
|
label: "label",
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
{ prop: 'nickName', label: '姓名' },
|
{ prop: "nickName", label: "姓名" },
|
||||||
{ prop: 'dept', label: '部门', type: 'status', callback: (data) => data?.deptName },
|
{
|
||||||
{ prop: 'roles', label: '角色', type: 'status', callback: (data) => data.map(ele => ele.roleName).join(',') },
|
prop: "dept",
|
||||||
|
label: "部门",
|
||||||
|
type: "status",
|
||||||
|
callback: (data) => data?.deptName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "roles",
|
||||||
|
label: "角色",
|
||||||
|
type: "status",
|
||||||
|
callback: (data) => data.map((ele) => ele.roleName).join(","),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
userData: [],
|
userData: [],
|
||||||
customTableRef: null,
|
|
||||||
isInternalChange: false,
|
isInternalChange: false,
|
||||||
}
|
selectAllData: [],
|
||||||
|
searchForm: {
|
||||||
|
nickName: "",
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
emits: [ 'close', 'confirm'],
|
emits: ["close", "confirm"],
|
||||||
methods: {
|
methods: {
|
||||||
handleNodeClick(data) {
|
handleNodeClick(data) {
|
||||||
this.currentDepartment = data.id
|
this.currentDepartment = data.id;
|
||||||
this.currentPage = 1
|
this.currentPage = 1;
|
||||||
this.fetchUserList()
|
this.fetchUserList();
|
||||||
},
|
},
|
||||||
handleCurrentChange(val) {
|
handleCurrentChange(val) {
|
||||||
this.currentPage = val
|
this.currentPage = val;
|
||||||
this.fetchUserList()
|
this.fetchUserList();
|
||||||
},
|
},
|
||||||
handleSizeChange(val) {
|
handleSizeChange(val) {
|
||||||
this.pageSize = val
|
this.pageSize = val;
|
||||||
this.fetchUserList()
|
this.fetchUserList();
|
||||||
},
|
},
|
||||||
handleClose() {
|
handleClose() {
|
||||||
this.$emit('close')
|
this.$emit("close");
|
||||||
},
|
},
|
||||||
handleConfirm() {
|
handleConfirm() {
|
||||||
this.$emit('confirm', this.selectedUsers)
|
if (!this.showSelection) this.$emit("confirm", this.selectedUsers);
|
||||||
this.handleClose()
|
else
|
||||||
|
this.$emit(
|
||||||
|
"confirm",
|
||||||
|
this.selectedUsers.map((ele, index) => ({
|
||||||
|
userId: ele.userId,
|
||||||
|
nickName: ele.nickName,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
this.handleClose();
|
||||||
},
|
},
|
||||||
handleSelectionChange(val) {
|
handleSelectionChange(val) {
|
||||||
if (this.isInternalChange) return
|
if (this.isInternalChange) return;
|
||||||
|
|
||||||
if (!this.multiSelect) {
|
if (!this.multiSelect) {
|
||||||
this.isInternalChange = true
|
this.isInternalChange = true;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (val.length > 0) {
|
if (val.length > 0) {
|
||||||
const lastSelected = val[val.length - 1]
|
const lastSelected = val[val.length - 1];
|
||||||
this.selectedUsers = [lastSelected]
|
this.selectedUsers = [lastSelected];
|
||||||
this.$refs.customTableRef.clearSelection()
|
this.$refs.customTableRef.clearSelection();
|
||||||
this.$refs.customTableRef.toggleRowSelection(lastSelected, true)
|
this.$refs.customTableRef.toggleRowSelection(lastSelected, true);
|
||||||
} else {
|
} else {
|
||||||
this.selectedUsers = []
|
this.selectedUsers = [];
|
||||||
}
|
}
|
||||||
this.isInternalChange = false
|
this.isInternalChange = false;
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
this.selectedUsers = val
|
// this.selectedUsers = val;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
selectRow({ arr, row }) {
|
||||||
|
if (!row) return;
|
||||||
|
if (this.selectedUsers.filter((ele) => ele.userId == row.userId).length) {
|
||||||
|
this.selectedUsers = this.selectedUsers.filter(
|
||||||
|
(ele) => ele.userId != row.userId
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.selectedUsers.push({ userId: row.userId, nickName: row.nickName });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectAll(arr) {
|
||||||
|
let filterArr = this.selectAllData.filter(
|
||||||
|
(ele) => !arr.some((item) => item.userId == ele.userId)
|
||||||
|
);
|
||||||
|
|
||||||
|
arr.forEach((ele) => {
|
||||||
|
if (
|
||||||
|
!this.selectedUsers.filter((item) => item.userId == ele.userId).length
|
||||||
|
)
|
||||||
|
this.selectRow({ row: ele });
|
||||||
|
});
|
||||||
|
filterArr.forEach((ele) => {
|
||||||
|
this.selectRow({ row: ele });
|
||||||
|
});
|
||||||
|
},
|
||||||
fetchUserList: async function () {
|
fetchUserList: async function () {
|
||||||
const response = await systemApi.getUserList({
|
const response = await systemApi.getUserList({
|
||||||
pageNum: this.currentPage,
|
pageNum: this.currentPage,
|
||||||
pageSize: this.pageSize,
|
pageSize: this.pageSize,
|
||||||
deptId: this.currentDepartment,
|
deptId: this.currentDepartment,
|
||||||
})
|
...this.searchForm,
|
||||||
this.userData = response.rows
|
userIdList:this.userIdList,
|
||||||
this.total = response.total
|
});
|
||||||
|
this.userData = response.rows;
|
||||||
|
this.total = response.total;
|
||||||
|
if (!this.multiSelect) {
|
||||||
|
this.userData.forEach((ele) => {
|
||||||
|
if (ele.userId == this.selectedUsers[0]?.userId)
|
||||||
|
this.$refs.customTableRef?.setCurrentRow(ele);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetTable() {
|
||||||
|
this.searchForm.nickName = "";
|
||||||
|
this.fetchUserList();
|
||||||
},
|
},
|
||||||
fetchTreeData: async function () {
|
fetchTreeData: async function () {
|
||||||
const response = await systemApi.getDeptTree()
|
const response = await systemApi.getDeptTree();
|
||||||
this.treeData = response.data
|
this.treeData = response.data;
|
||||||
|
},
|
||||||
|
currentRow(val) {
|
||||||
|
this.selectedUsers = [val];
|
||||||
|
},
|
||||||
|
rowClick(row) {
|
||||||
|
if (!this.showSelection) {
|
||||||
|
if (row.userId == this.selectedUsers[0]?.userId)
|
||||||
|
this.$refs.customTableRef.$refs.elTableRef.setCurrentRow();
|
||||||
|
else this.selectedUsers = [row];
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
currentSelectedUser: {
|
currentSelectedUser: {
|
||||||
handler(newVal) {
|
handler(newVal) {
|
||||||
this.isInternalChange = true
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.selectedUsers = newVal
|
if (!this.showSelection) {
|
||||||
if (this.$refs.customTableRef) {
|
let row = this.userData.find(
|
||||||
this.$refs.customTableRef.clearSelection()
|
(ele) => ele.userId == newVal[0]?.userId
|
||||||
newVal.forEach(user => {
|
);
|
||||||
const row = this.userData.find(item => item.userId === user.userId)
|
if (row) {
|
||||||
if (row) {
|
this.$refs.customTableRef?.setCurrentRow(row);
|
||||||
this.$refs.customTableRef.toggleRowSelection(row, true)
|
this.selectedUsers = [row];
|
||||||
}
|
} else {
|
||||||
})
|
this.selectedUsers = [];
|
||||||
|
this.$refs.customTableRef?.setCurrentRow();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!newVal.length) {
|
||||||
|
this.selectedUsers = [];
|
||||||
|
this.$refs.customTableRef?.clearSelection();
|
||||||
|
} else {
|
||||||
|
// this.$refs.customTableRef?.clearSelection();
|
||||||
|
this.selectedUsers = [];
|
||||||
|
newVal.forEach((item, index) => {
|
||||||
|
this.selectedUsers.push({
|
||||||
|
userId: item,
|
||||||
|
nickName: this.currentSelectedUserName[index],
|
||||||
|
});
|
||||||
|
let row = this.userData.find((ele) => ele.userId == item);
|
||||||
|
if (row) {
|
||||||
|
this.selectAllData.push(row);
|
||||||
|
this.$refs.customTableRef?.toggleRowSelection(row, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.isInternalChange = false
|
});
|
||||||
})
|
},
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
userData: {
|
||||||
|
handler(newVal) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (!this.showSelection) {
|
||||||
|
let row = this.userData.find(
|
||||||
|
(ele) => ele.userId == this.currentSelectedUser[0]?.userId
|
||||||
|
);
|
||||||
|
if (row) {
|
||||||
|
this.selectedUsers = [row];
|
||||||
|
this.$refs.customTableRef?.setCurrentRow(row);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.selectAllData = [];
|
||||||
|
this.currentSelectedUser.forEach((item) => {
|
||||||
|
let row = newVal.find((ele) => ele.userId == item);
|
||||||
|
if (row) {
|
||||||
|
this.selectAllData.push(row);
|
||||||
|
|
||||||
|
this.$refs.customTableRef?.toggleRowSelection(row, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
userIdList: {
|
||||||
|
handler(newVal) {
|
||||||
|
this.fetchUserList();
|
||||||
},
|
},
|
||||||
immediate: true,
|
immediate: true,
|
||||||
deep: true,
|
deep: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchTreeData()
|
this.fetchTreeData();
|
||||||
this.fetchUserList()
|
if(!this.isFilter){
|
||||||
|
this.fetchUserList();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -206,6 +396,10 @@ export default {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
::v-deep .el-table {
|
::v-deep .el-table {
|
||||||
max-height:360px !important;
|
max-height: 360px !important;
|
||||||
}
|
}
|
||||||
</style>
|
::v-deep tr.el-table__row.current-row .el-table__cell {
|
||||||
|
background-color: #409eff !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -63,8 +63,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 15px;
|
width: 10px;
|
||||||
height: 15px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
|
@ -72,7 +72,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background-color: #c0c0c0;
|
background-color: #c8c8c8;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,36 +1,60 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="tags-view-container" class="tags-view-container">
|
<div id="tags-view-container" class="tags-view-container">
|
||||||
<scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
|
<scroll-pane
|
||||||
|
ref="scrollPane"
|
||||||
|
class="tags-view-wrapper"
|
||||||
|
@scroll="handleScroll"
|
||||||
|
>
|
||||||
<router-link
|
<router-link
|
||||||
v-for="tag in visitedViews"
|
v-for="tag in visitedViews"
|
||||||
ref="tag"
|
ref="tag"
|
||||||
:key="tag.path"
|
:key="tag.path"
|
||||||
:class="isActive(tag)?'active':''"
|
:class="isActive(tag) ? 'active' : ''"
|
||||||
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
|
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
|
||||||
tag="span"
|
tag="span"
|
||||||
class="tags-view-item"
|
class="tags-view-item"
|
||||||
:style="activeStyle(tag)"
|
:style="activeStyle(tag)"
|
||||||
@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
|
@click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
||||||
@contextmenu.prevent.native="openMenu(tag,$event)"
|
@contextmenu.prevent.native="openMenu(tag, $event)"
|
||||||
>
|
>
|
||||||
{{ tag.title }}
|
{{ tag.title }}
|
||||||
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
<span
|
||||||
|
v-if="!isAffix(tag)"
|
||||||
|
class="el-icon-close"
|
||||||
|
@click.prevent.stop="closeSelectedTag(tag)"
|
||||||
|
/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</scroll-pane>
|
</scroll-pane>
|
||||||
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
|
<ul
|
||||||
<li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 刷新页面</li>
|
v-show="visible"
|
||||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 关闭当前</li>
|
:style="{ left: left + 'px', top: top + 'px' }"
|
||||||
<li @click="closeOthersTags"><i class="el-icon-circle-close"></i> 关闭其他</li>
|
class="contextmenu"
|
||||||
<li v-if="!isFirstView()" @click="closeLeftTags"><i class="el-icon-back"></i> 关闭左侧</li>
|
>
|
||||||
<li v-if="!isLastView()" @click="closeRightTags"><i class="el-icon-right"></i> 关闭右侧</li>
|
<li @click="refreshSelectedTag(selectedTag)">
|
||||||
<li @click="closeAllTags(selectedTag)"><i class="el-icon-circle-close"></i> 全部关闭</li>
|
<i class="el-icon-refresh-right"></i> 刷新页面
|
||||||
|
</li>
|
||||||
|
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
|
||||||
|
<i class="el-icon-close"></i> 关闭当前
|
||||||
|
</li>
|
||||||
|
<li @click="closeOthersTags">
|
||||||
|
<i class="el-icon-circle-close"></i> 关闭其他
|
||||||
|
</li>
|
||||||
|
<li v-if="!isFirstView()" @click="closeLeftTags">
|
||||||
|
<i class="el-icon-back"></i> 关闭左侧
|
||||||
|
</li>
|
||||||
|
<li v-if="!isLastView()" @click="closeRightTags">
|
||||||
|
<i class="el-icon-right"></i> 关闭右侧
|
||||||
|
</li>
|
||||||
|
<li @click="closeAllTags(selectedTag)">
|
||||||
|
<i class="el-icon-circle-close"></i> 全部关闭
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ScrollPane from './ScrollPane'
|
import ScrollPane from "./ScrollPane";
|
||||||
import path from 'path'
|
import path from "path";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { ScrollPane },
|
components: { ScrollPane },
|
||||||
|
@ -40,201 +64,207 @@ export default {
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
selectedTag: {},
|
selectedTag: {},
|
||||||
affixTags: []
|
affixTags: [],
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
visitedViews() {
|
visitedViews() {
|
||||||
return this.$store.state.tagsView.visitedViews
|
return this.$store.state.tagsView.visitedViews;
|
||||||
},
|
},
|
||||||
routes() {
|
routes() {
|
||||||
return this.$store.state.permission.routes
|
return this.$store.state.permission.routes;
|
||||||
},
|
},
|
||||||
theme() {
|
theme() {
|
||||||
return this.$store.state.settings.theme;
|
return this.$store.state.settings.theme;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route() {
|
$route() {
|
||||||
this.addTags()
|
this.addTags();
|
||||||
this.moveToCurrentTag()
|
this.moveToCurrentTag();
|
||||||
},
|
},
|
||||||
visible(value) {
|
visible(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
document.body.addEventListener('click', this.closeMenu)
|
document.body.addEventListener("click", this.closeMenu);
|
||||||
} else {
|
} else {
|
||||||
document.body.removeEventListener('click', this.closeMenu)
|
document.body.removeEventListener("click", this.closeMenu);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initTags()
|
this.initTags();
|
||||||
this.addTags()
|
this.addTags();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isActive(route) {
|
isActive(route) {
|
||||||
return route.path === this.$route.path
|
return route.path === this.$route.path;
|
||||||
},
|
},
|
||||||
activeStyle(tag) {
|
activeStyle(tag) {
|
||||||
if (!this.isActive(tag)) return {};
|
if (!this.isActive(tag)) return {};
|
||||||
return {
|
return {
|
||||||
"background-color": this.theme,
|
"background-color": this.theme,
|
||||||
"border-color": this.theme
|
"border-color": this.theme,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
isAffix(tag) {
|
isAffix(tag) {
|
||||||
return tag.meta && tag.meta.affix
|
return tag.meta && tag.meta.affix;
|
||||||
},
|
},
|
||||||
isFirstView() {
|
isFirstView() {
|
||||||
try {
|
try {
|
||||||
return this.selectedTag.fullPath === '/index' || this.selectedTag.fullPath === this.visitedViews[1].fullPath
|
return (
|
||||||
|
this.selectedTag.fullPath === "/index" ||
|
||||||
|
this.selectedTag.fullPath === this.visitedViews[1].fullPath
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isLastView() {
|
isLastView() {
|
||||||
try {
|
try {
|
||||||
return this.selectedTag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath
|
return (
|
||||||
|
this.selectedTag.fullPath ===
|
||||||
|
this.visitedViews[this.visitedViews.length - 1].fullPath
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
filterAffixTags(routes, basePath = '/') {
|
filterAffixTags(routes, basePath = "/") {
|
||||||
let tags = []
|
let tags = [];
|
||||||
routes.forEach(route => {
|
routes.forEach((route) => {
|
||||||
if (route.meta && route.meta.affix) {
|
if (route.meta && route.meta.affix) {
|
||||||
const tagPath = path.resolve(basePath, route.path)
|
const tagPath = path.resolve(basePath, route.path);
|
||||||
tags.push({
|
tags.push({
|
||||||
fullPath: tagPath,
|
fullPath: tagPath,
|
||||||
path: tagPath,
|
path: tagPath,
|
||||||
name: route.name,
|
name: route.name,
|
||||||
meta: { ...route.meta }
|
meta: { ...route.meta },
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (route.children) {
|
if (route.children) {
|
||||||
const tempTags = this.filterAffixTags(route.children, route.path)
|
const tempTags = this.filterAffixTags(route.children, route.path);
|
||||||
if (tempTags.length >= 1) {
|
if (tempTags.length >= 1) {
|
||||||
tags = [...tags, ...tempTags]
|
tags = [...tags, ...tempTags];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return tags
|
return tags;
|
||||||
},
|
},
|
||||||
initTags() {
|
initTags() {
|
||||||
const affixTags = this.affixTags = this.filterAffixTags(this.routes)
|
const affixTags = (this.affixTags = this.filterAffixTags(this.routes));
|
||||||
for (const tag of affixTags) {
|
for (const tag of affixTags) {
|
||||||
// Must have tag name
|
// Must have tag name
|
||||||
if (tag.name) {
|
if (tag.name) {
|
||||||
this.$store.dispatch('tagsView/addVisitedView', tag)
|
this.$store.dispatch("tagsView/addVisitedView", tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTags() {
|
addTags() {
|
||||||
const { name } = this.$route
|
const { name } = this.$route;
|
||||||
if (name) {
|
if (name) {
|
||||||
this.$store.dispatch('tagsView/addView', this.$route)
|
this.$store.dispatch("tagsView/addView", this.$route);
|
||||||
if (this.$route.meta.link) {
|
if (this.$route.meta.link) {
|
||||||
this.$store.dispatch('tagsView/addIframeView', this.$route)
|
this.$store.dispatch("tagsView/addIframeView", this.$route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
},
|
},
|
||||||
moveToCurrentTag() {
|
moveToCurrentTag() {
|
||||||
const tags = this.$refs.tag
|
const tags = this.$refs.tag;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
if (tag.to.path === this.$route.path) {
|
if (tag.to.path === this.$route.path) {
|
||||||
this.$refs.scrollPane.moveToTarget(tag)
|
this.$refs.scrollPane.moveToTarget(tag);
|
||||||
// when query is different then update
|
// when query is different then update
|
||||||
if (tag.to.fullPath !== this.$route.fullPath) {
|
if (tag.to.fullPath !== this.$route.fullPath) {
|
||||||
this.$store.dispatch('tagsView/updateVisitedView', this.$route)
|
this.$store.dispatch("tagsView/updateVisitedView", this.$route);
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
refreshSelectedTag(view) {
|
refreshSelectedTag(view) {
|
||||||
this.$tab.refreshPage(view);
|
this.$tab.refreshPage(view);
|
||||||
if (this.$route.meta.link) {
|
if (this.$route.meta.link) {
|
||||||
this.$store.dispatch('tagsView/delIframeView', this.$route)
|
this.$store.dispatch("tagsView/delIframeView", this.$route);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closeSelectedTag(view) {
|
closeSelectedTag(view) {
|
||||||
this.$tab.closePage(view).then(({ visitedViews }) => {
|
this.$tab.closePage(view).then(({ visitedViews }) => {
|
||||||
if (this.isActive(view)) {
|
if (this.isActive(view)) {
|
||||||
this.toLastView(visitedViews, view)
|
this.toLastView(visitedViews, view);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
closeRightTags() {
|
closeRightTags() {
|
||||||
this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {
|
this.$tab.closeRightPage(this.selectedTag).then((visitedViews) => {
|
||||||
if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
|
if (!visitedViews.find((i) => i.fullPath === this.$route.fullPath)) {
|
||||||
this.toLastView(visitedViews)
|
this.toLastView(visitedViews);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
closeLeftTags() {
|
closeLeftTags() {
|
||||||
this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {
|
this.$tab.closeLeftPage(this.selectedTag).then((visitedViews) => {
|
||||||
if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
|
if (!visitedViews.find((i) => i.fullPath === this.$route.fullPath)) {
|
||||||
this.toLastView(visitedViews)
|
this.toLastView(visitedViews);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
closeOthersTags() {
|
closeOthersTags() {
|
||||||
this.$router.push(this.selectedTag.fullPath).catch(()=>{});
|
this.$router.push(this.selectedTag.fullPath).catch(() => {});
|
||||||
this.$tab.closeOtherPage(this.selectedTag).then(() => {
|
this.$tab.closeOtherPage(this.selectedTag).then(() => {
|
||||||
this.moveToCurrentTag()
|
this.moveToCurrentTag();
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
closeAllTags(view) {
|
closeAllTags(view) {
|
||||||
this.$tab.closeAllPage().then(({ visitedViews }) => {
|
this.$tab.closeAllPage().then(({ visitedViews }) => {
|
||||||
if (this.affixTags.some(tag => tag.path === this.$route.path)) {
|
if (this.affixTags.some((tag) => tag.path === this.$route.path)) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
this.toLastView(visitedViews, view)
|
this.toLastView(visitedViews, view);
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
toLastView(visitedViews, view) {
|
toLastView(visitedViews, view) {
|
||||||
const latestView = visitedViews.slice(-1)[0]
|
const latestView = visitedViews.slice(-1)[0];
|
||||||
if (latestView) {
|
if (latestView) {
|
||||||
this.$router.push(latestView.fullPath)
|
this.$router.push(latestView.fullPath);
|
||||||
} else {
|
} else {
|
||||||
// now the default is to redirect to the home page if there is no tags-view,
|
// now the default is to redirect to the home page if there is no tags-view,
|
||||||
// you can adjust it according to your needs.
|
// you can adjust it according to your needs.
|
||||||
if (view.name === 'Dashboard') {
|
if (view.name === "Dashboard") {
|
||||||
// to reload home page
|
// to reload home page
|
||||||
this.$router.replace({ path: '/redirect' + view.fullPath })
|
this.$router.replace({ path: "/redirect" + view.fullPath });
|
||||||
} else {
|
} else {
|
||||||
this.$router.push('/')
|
this.$router.push("/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openMenu(tag, e) {
|
openMenu(tag, e) {
|
||||||
const menuMinWidth = 105
|
const menuMinWidth = 105;
|
||||||
const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
|
const offsetLeft = this.$el.getBoundingClientRect().left; // container margin left
|
||||||
const offsetWidth = this.$el.offsetWidth // container width
|
const offsetWidth = this.$el.offsetWidth; // container width
|
||||||
const maxLeft = offsetWidth - menuMinWidth // left boundary
|
const maxLeft = offsetWidth - menuMinWidth; // left boundary
|
||||||
const left = e.clientX - offsetLeft + 15 // 15: margin right
|
const left = e.clientX - offsetLeft + 15; // 15: margin right
|
||||||
|
|
||||||
if (left > maxLeft) {
|
if (left > maxLeft) {
|
||||||
this.left = maxLeft
|
this.left = maxLeft;
|
||||||
} else {
|
} else {
|
||||||
this.left = left
|
this.left = left;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.top = e.clientY
|
this.top = e.clientY;
|
||||||
this.visible = true
|
this.visible = true;
|
||||||
this.selectedTag = tag
|
this.selectedTag = tag;
|
||||||
},
|
},
|
||||||
closeMenu() {
|
closeMenu() {
|
||||||
this.visible = false
|
this.visible = false;
|
||||||
},
|
},
|
||||||
handleScroll() {
|
handleScroll() {
|
||||||
this.closeMenu()
|
this.closeMenu();
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -243,7 +273,7 @@ export default {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-bottom: 1px solid #d8dce5;
|
border-bottom: 1px solid #d8dce5;
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
|
||||||
.tags-view-wrapper {
|
.tags-view-wrapper {
|
||||||
.tags-view-item {
|
.tags-view-item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -269,7 +299,7 @@ export default {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-color: #42b983;
|
border-color: #42b983;
|
||||||
&::before {
|
&::before {
|
||||||
content: '';
|
content: "";
|
||||||
background: #fff;
|
background: #fff;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
|
@ -292,7 +322,7 @@ export default {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #333;
|
color: #333;
|
||||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
|
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
|
||||||
li {
|
li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 7px 16px;
|
padding: 7px 16px;
|
||||||
|
@ -315,10 +345,10 @@ export default {
|
||||||
vertical-align: 2px;
|
vertical-align: 2px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: all .3s cubic-bezier(.645, .045, .355, 1);
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
transform-origin: 100% 50%;
|
transform-origin: 100% 50%;
|
||||||
&:before {
|
&:before {
|
||||||
transform: scale(.6);
|
transform: scale(0.6);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: -3px;
|
vertical-align: -3px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,48 @@ export const dynamicRoutes = [
|
||||||
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
|
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/project/detail',
|
||||||
|
component: Layout,
|
||||||
|
hidden: true,
|
||||||
|
permissions: ['project:list:detail'],
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/project/detail',
|
||||||
|
component: () => import('@/views/project/detail'),
|
||||||
|
name: 'GenEdit',
|
||||||
|
meta: { title: '项目详情', activeMenu: '/project/detail' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/project/detail',
|
||||||
|
component: Layout,
|
||||||
|
hidden: true,
|
||||||
|
permissions: ['project:list:detail'],
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/project/detail',
|
||||||
|
component: () => import('@/views/project/detail'),
|
||||||
|
name: 'GenEdit',
|
||||||
|
meta: { title: '项目详情', activeMenu: '/project/detail' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/project/detail',
|
||||||
|
component: Layout,
|
||||||
|
hidden: true,
|
||||||
|
permissions: ['project:list:demand'],
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/project/demandManage',
|
||||||
|
component: () => import('@/views/project/demandManage/demandManage'),
|
||||||
|
name: 'GenEdit',
|
||||||
|
meta: { title: '项目详情', activeMenu: '/project/demandManage' }
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
154
src/utils/api.js
|
@ -1,6 +1,6 @@
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
// 登录板块api
|
// 公用板块
|
||||||
|
|
||||||
// 项目板块
|
// 项目板块
|
||||||
export const projectApi = {
|
export const projectApi = {
|
||||||
|
@ -87,6 +87,11 @@ export const workLogApi = {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: data,
|
data: data,
|
||||||
}),
|
}),
|
||||||
|
delLog: (id) => request({
|
||||||
|
url: `/business/work/hour/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,4 +134,151 @@ export const systemApi = {
|
||||||
url: '/system/user/deptTree',
|
url: '/system/user/deptTree',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
}),
|
}),
|
||||||
|
fileUpload: process.env.NODE_ENV == 'development' ? '/common/upload' : '/prod-api/common/upload',
|
||||||
|
downFile: (data) => request({
|
||||||
|
url: '/common/download',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
delFile: (id) => request({
|
||||||
|
url: `/business/project/file/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
|
||||||
|
}),
|
||||||
|
delFileBatch: (id) => request({
|
||||||
|
url: `/business/project/file/batch/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
|
||||||
|
}),
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 任务考核板块
|
||||||
|
export const taskApi = {
|
||||||
|
getTaskUserList: (data) => request({
|
||||||
|
url: '/examine/user',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
getTaskScoreDetail: (data) => request({
|
||||||
|
url: '/examine/detail',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
saveTaskUserScore: (data) => request({
|
||||||
|
url: '/examine/detail/batch',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
}),
|
||||||
|
getTaskListSelf: (data) => request({
|
||||||
|
url: '/task/list',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
getTaskListSelfNormal: (data) => request({
|
||||||
|
url: '/task/listSelf',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
|
||||||
|
getTaskList: (data) => request({
|
||||||
|
url: '/task/get',
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
addTask: (data) => request({
|
||||||
|
url: '/task/add',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
}),
|
||||||
|
upDateTask: (data) => request({
|
||||||
|
url: '/task/update',
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
}),
|
||||||
|
delTask: (id) => request({
|
||||||
|
url: `/task/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
}),
|
||||||
|
delTaskModule: (id) => request({
|
||||||
|
url: `/examine/template/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
}),
|
||||||
|
getTaskSet: (id) => request({
|
||||||
|
url: `/task/target/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
}),
|
||||||
|
setTaskSet: (data) => request({
|
||||||
|
url: `/task/config/update`,
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
|
||||||
|
}),
|
||||||
|
getTaskModel: (data) => request({
|
||||||
|
url: `/examine/template/list`,
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
// 获取模板配置
|
||||||
|
getTaskModelSet: (id) => request({
|
||||||
|
url: `/examine/template/list/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
export const demandApi = {
|
||||||
|
getVersionTree: (data) => request({
|
||||||
|
url: `/projectVersion/tree`,
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
addVersion: (data) => request({
|
||||||
|
url: '/projectVersion/insert',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
}),
|
||||||
|
// 删除版本号
|
||||||
|
delVersion: (data) => request({
|
||||||
|
url: `/projectVersion/${data}`,
|
||||||
|
method: 'delete',
|
||||||
|
}),
|
||||||
|
editVersion: (data) => request({
|
||||||
|
url: '/projectVersion/update',
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
}),
|
||||||
|
getDemandList: (data) => request({
|
||||||
|
url: `/demand/list`,
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
}),
|
||||||
|
addDemand: (data) => request({
|
||||||
|
url: '/demand/insert',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
}),
|
||||||
|
eidtDemand: (data) => request({
|
||||||
|
url: '/demand/update',
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
}),
|
||||||
|
delDemand: (data) => request({
|
||||||
|
url: `/demand/${data}`,
|
||||||
|
method: 'delete',
|
||||||
|
}),
|
||||||
|
getDemandDetail: (id) => request({
|
||||||
|
url: `/demand/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
}),
|
||||||
|
delDemandBatch: (data) => request({
|
||||||
|
url: `/demand/remove/batch/${data}`,
|
||||||
|
method: 'delete',
|
||||||
|
}),
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
</el-form>
|
</el-form>
|
||||||
<!-- 底部 -->
|
<!-- 底部 -->
|
||||||
<div class="el-login-footer">
|
<div class="el-login-footer">
|
||||||
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
|
<span>unissense.tech</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,448 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="sidebarTree"
|
||||||
|
:class="{
|
||||||
|
hidenLeft: !showFlag,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="el-icon-arrow-right"
|
||||||
|
style="font-size: 24px; margin-top: 20px; cursor: pointer"
|
||||||
|
v-show="!showFlag"
|
||||||
|
@click.stop="changeShow()"
|
||||||
|
></i>
|
||||||
|
|
||||||
|
<!-- 树形菜单 -->
|
||||||
|
<div class="treeTitle">版本列表</div>
|
||||||
|
<div class="topBox" v-show="showFlag">
|
||||||
|
<div class="topText" @click.stop="changeOpen">
|
||||||
|
<i v-show="openFlag" class="el-icon-caret-bottom"></i>
|
||||||
|
<i v-show="!openFlag" class="el-icon-caret-right"></i>
|
||||||
|
<img src="@/assets/demand/list.png" />
|
||||||
|
<span>全部版本</span>
|
||||||
|
</div>
|
||||||
|
<div class="topBtn">
|
||||||
|
<i
|
||||||
|
class="el-icon-plus"
|
||||||
|
@click.stop="dialogVisible = true"
|
||||||
|
style="font-size: 20px"
|
||||||
|
></i>
|
||||||
|
<i
|
||||||
|
class="el-icon-arrow-left"
|
||||||
|
style="font-size: 20px"
|
||||||
|
@click.stop="changeShow()"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-tree
|
||||||
|
v-show="showFlag"
|
||||||
|
:data="treeData"
|
||||||
|
:props="defaultProps"
|
||||||
|
:default-expanded-keys="defaultExpend"
|
||||||
|
node-key="nodeId"
|
||||||
|
class="tree"
|
||||||
|
ref="treeRef"
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
>
|
||||||
|
<template #default="{ node, data }">
|
||||||
|
<div
|
||||||
|
class="treeNode"
|
||||||
|
@mousemove="data.hover = true"
|
||||||
|
@mouseout="data.hover = false"
|
||||||
|
>
|
||||||
|
<!-- 展开/收起图标 -->
|
||||||
|
|
||||||
|
<!-- 节点图标 -->
|
||||||
|
<img
|
||||||
|
v-if="data.type == 0 && data.nodeId === selectedId"
|
||||||
|
src="@/assets/demand/treeIcon.png"
|
||||||
|
class="nodeIcon"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
v-if="data.type == 0 && data.nodeId !== selectedId"
|
||||||
|
src="@/assets/demand/treeIcon1.png"
|
||||||
|
class="nodeIcon"
|
||||||
|
/>
|
||||||
|
<!-- 节点文本 -->
|
||||||
|
<el-tooltip
|
||||||
|
class="item"
|
||||||
|
effect="light"
|
||||||
|
:content="data.title"
|
||||||
|
placement="top"
|
||||||
|
:disabled="data.title.length > 8 ? false : true"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'nodeLabel',
|
||||||
|
data.nodeId === selectedId ? 'selected' : '',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
{{ data.title }}
|
||||||
|
</div>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<!-- 右侧数字标记 -->
|
||||||
|
<span
|
||||||
|
v-if="data.type == 0 && !data.hover"
|
||||||
|
:class="[
|
||||||
|
'count',
|
||||||
|
data.nodeId === selectedId ? 'selectedCount' : '',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
{{ data.childrenList.length }}
|
||||||
|
</span>
|
||||||
|
<el-dropdown
|
||||||
|
v-show="data.type == 0 && data.hover"
|
||||||
|
trigger="click"
|
||||||
|
placement="bottom"
|
||||||
|
@command="
|
||||||
|
(val) => {
|
||||||
|
changeRow(val, data);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<i class="el-icon-more" style="font-size: 20px"></i>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="add">新建需求</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="edit">编辑</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="del" style="color: #dd242a"
|
||||||
|
>删除</el-dropdown-item
|
||||||
|
>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
<!-- 右侧操作图标 -->
|
||||||
|
<img
|
||||||
|
v-if="data.actionIcon"
|
||||||
|
:src="data.actionIcon"
|
||||||
|
class="actionIcon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-tree>
|
||||||
|
<el-dialog title="添加版本号" :visible.sync="dialogVisible" width="30%">
|
||||||
|
<el-form>
|
||||||
|
<el-form-item label="版本号">
|
||||||
|
<el-input v-model="demandData.name"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmAddNode">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { demandApi } from "@/utils/api";
|
||||||
|
export default {
|
||||||
|
name: "SidebarTree",
|
||||||
|
props: {
|
||||||
|
projectId: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedId: "",
|
||||||
|
treeData: [],
|
||||||
|
defaultProps: {
|
||||||
|
children: "childrenList",
|
||||||
|
label: "title",
|
||||||
|
},
|
||||||
|
dialogVisible: false,
|
||||||
|
demandData: {
|
||||||
|
name: "",
|
||||||
|
},
|
||||||
|
openFlag: false,
|
||||||
|
showFlag: true,
|
||||||
|
defaultExpend: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleNodeClick(data) {
|
||||||
|
this.selectedId = data.nodeId;
|
||||||
|
this.changeVersion(data);
|
||||||
|
},
|
||||||
|
getVersionTree(defaultId) {
|
||||||
|
demandApi
|
||||||
|
.getVersionTree({
|
||||||
|
projectId: this.projectId,
|
||||||
|
demandStatusList: [],
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (!res.data.length) {
|
||||||
|
this.treeData = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.data = res.data.map((ele) => {
|
||||||
|
ele.nodeId = ele.id + "_" + ele.type;
|
||||||
|
ele.childrenList.map((item) => {
|
||||||
|
item.nodeId = item.id + "_" + item.type;
|
||||||
|
});
|
||||||
|
ele.hover = false;
|
||||||
|
return ele;
|
||||||
|
});
|
||||||
|
this.initTableData(defaultId, res.data);
|
||||||
|
this.treeData = res.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
changeVersion(data) {
|
||||||
|
if (!data) {
|
||||||
|
data = {
|
||||||
|
id: this.projectId,
|
||||||
|
type: 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.$emit("changeVersion", data);
|
||||||
|
},
|
||||||
|
initTableData(defaultId, tableList) {
|
||||||
|
if (defaultId && defaultId != "all") {
|
||||||
|
let searchNode = {};
|
||||||
|
this.defaultExpend = [defaultId];
|
||||||
|
searchNode = tableList.find((ele) => ele.nodeId == defaultId);
|
||||||
|
this.changeVersion(searchNode);
|
||||||
|
this.selectedId = this.defaultExpend[0];
|
||||||
|
} else if (defaultId == "all") {
|
||||||
|
this.selectedId = "";
|
||||||
|
this.changeVersion({
|
||||||
|
id: this.projectId,
|
||||||
|
type: 2,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.defaultExpend = [tableList[0].nodeId];
|
||||||
|
this.selectedId = this.defaultExpend[0];
|
||||||
|
this.setVersionList(tableList.filter((ele) => ele.type == 0));
|
||||||
|
this.changeVersion(
|
||||||
|
tableList.find((ele) => ele.nodeId == this.defaultExpend[0])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setVersionList(data) {
|
||||||
|
this.$emit("setVersionList", data);
|
||||||
|
},
|
||||||
|
confirmAddNode() {
|
||||||
|
if (!this.demandData.name) {
|
||||||
|
this.$message({
|
||||||
|
message: "请填写版本号",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.demandData.name.length > 10) {
|
||||||
|
this.$message({
|
||||||
|
message: "版本号限制10个字符",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let param = {
|
||||||
|
projectId: this.projectId,
|
||||||
|
versionNumber: this.demandData.name,
|
||||||
|
};
|
||||||
|
if (this.demandData.id) {
|
||||||
|
param.id = this.demandData.id;
|
||||||
|
demandApi.editVersion(param).then((res) => {
|
||||||
|
this.resetAdd(0);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
demandApi.addVersion(param).then((res) => {
|
||||||
|
this.resetAdd(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetAdd(add) {
|
||||||
|
this.$message({
|
||||||
|
message: add ? "添加成功" : "修改成功",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.demandData.name = "";
|
||||||
|
this.demandData.id = "";
|
||||||
|
this.getVersionTree();
|
||||||
|
},
|
||||||
|
editDemand(data) {
|
||||||
|
this.demandData = {
|
||||||
|
name: data.title,
|
||||||
|
id: data.id,
|
||||||
|
};
|
||||||
|
this.dialogVisible = true;
|
||||||
|
},
|
||||||
|
delVersion(data) {
|
||||||
|
this.$confirm("此操作将永久删除该版本号, 是否继续?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
demandApi.delVersion(data.id).then((res) => {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "删除成功!",
|
||||||
|
});
|
||||||
|
this.getVersionTree();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
},
|
||||||
|
changeOpen() {
|
||||||
|
this.openFlag = !this.openFlag;
|
||||||
|
if (this.openFlag) {
|
||||||
|
this.defaultExpend = this.treeData.map((ele) => ele.nodeId);
|
||||||
|
} else {
|
||||||
|
this.defaultExpend = [];
|
||||||
|
}
|
||||||
|
this.getVersionTree("all");
|
||||||
|
},
|
||||||
|
changeShow() {
|
||||||
|
this.showFlag = !this.showFlag;
|
||||||
|
},
|
||||||
|
changeRow(type, row) {
|
||||||
|
if (type == "add") {
|
||||||
|
this.$emit("addDemand");
|
||||||
|
} else if (type == "edit") {
|
||||||
|
this.editDemand(row);
|
||||||
|
} else if (type == "del") {
|
||||||
|
this.delVersion(row);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
projectId(newVal) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.getVersionTree();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.sidebarTree {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: inherit;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.hidenLeft {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
.tree {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.treeNode {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 48px;
|
||||||
|
padding: 0 20px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
::v-deep .el-tree-node__children {
|
||||||
|
padding-left: 15px !important;
|
||||||
|
}
|
||||||
|
.expandIcon {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeIcon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeLabel {
|
||||||
|
flex: 1;
|
||||||
|
font-family: "PingFang SC";
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 36px;
|
||||||
|
color: #333;
|
||||||
|
max-width: 160px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeLabel.selected {
|
||||||
|
color: #4096ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count {
|
||||||
|
font-family: "PingFang SC";
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 26px;
|
||||||
|
color: #999;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectedCount {
|
||||||
|
color: #4096ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actionIcon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
.treeTitle {
|
||||||
|
padding: 20px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
/* 选中状态背景色 */
|
||||||
|
// .treeNode:has(.selected) {
|
||||||
|
// background-color: #f6faff;
|
||||||
|
// }
|
||||||
|
|
||||||
|
::v-deep .el-tree-node {
|
||||||
|
min-height: 42px;
|
||||||
|
.el-tree-node__content {
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
:not(.is-leaf.el-tree-node__expand-icon) {
|
||||||
|
font-size: 16px;
|
||||||
|
// color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.topBox {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
.topText {
|
||||||
|
gap: 15px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.topBtn {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
i {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// /* <EFBFBD><EFBFBD>浮效果 */
|
||||||
|
// .treeNode:hover {
|
||||||
|
// background-color: #f5f5f5;
|
||||||
|
// }
|
||||||
|
</style>
|
|
@ -0,0 +1,94 @@
|
||||||
|
<template>
|
||||||
|
<div class="layout">
|
||||||
|
<!-- 左侧树形菜单 -->
|
||||||
|
<SidebarTree
|
||||||
|
:projectId="projectId"
|
||||||
|
class="sidebar"
|
||||||
|
@changeVersion="changeVersion"
|
||||||
|
@setVersionList="setVersionList"
|
||||||
|
@addDemand="addDemand"
|
||||||
|
ref="treeRef"
|
||||||
|
/>
|
||||||
|
<!-- 右侧表格和筛选 -->
|
||||||
|
<MainContentTable
|
||||||
|
:projectId="projectId"
|
||||||
|
class="main-content"
|
||||||
|
:version="version"
|
||||||
|
:projectName="projectName"
|
||||||
|
@refreshTree="refreshTree"
|
||||||
|
:versionList="versionList"
|
||||||
|
:minDate="minDate"
|
||||||
|
:maxDate="maxDate"
|
||||||
|
ref="rightRef"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 导入子组件
|
||||||
|
import SidebarTree from "./components/SidebarTree.vue";
|
||||||
|
import MainContentTable from "./components/MainContentTable.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "demandManage",
|
||||||
|
components: {
|
||||||
|
SidebarTree,
|
||||||
|
MainContentTable,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
projectId: "",
|
||||||
|
projectName: "",
|
||||||
|
versionList: [],
|
||||||
|
version: {},
|
||||||
|
minDate: "",
|
||||||
|
maxDate: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeVersion(data) {
|
||||||
|
this.version = data;
|
||||||
|
},
|
||||||
|
setVersionList(data) {
|
||||||
|
this.versionList = data;
|
||||||
|
},
|
||||||
|
refreshTree(defaultId) {
|
||||||
|
this.$refs.treeRef.getVersionTree(defaultId);
|
||||||
|
},
|
||||||
|
addDemand() {
|
||||||
|
this.$refs.rightRef.handleAdd();
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
this.projectId = this.$route.query.id;
|
||||||
|
this.projectName = this.$route.query.projectName;
|
||||||
|
this.minDate = this.$route.query.startDate;
|
||||||
|
this.maxDate = this.$route.query.endDate;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.layout {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
flex-grow: 1;
|
||||||
|
max-width: 300px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex-grow: 3;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,219 +1,143 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="project-management">
|
<div class="project-management" v-loading="fileLoading">
|
||||||
<el-form
|
<el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" class="custom-form">
|
||||||
ref="formRef"
|
|
||||||
:model="formData"
|
|
||||||
:rules="rules"
|
|
||||||
label-width="120px"
|
|
||||||
class="custom-form"
|
|
||||||
>
|
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="项目名称" prop="projectName">
|
<el-form-item label="项目名称" prop="projectName">
|
||||||
<div>
|
<div>
|
||||||
<el-input
|
<el-input v-model="formData.projectName" placeholder="请输入项目名称" :disabled="isEditing"
|
||||||
v-model="formData.projectName"
|
class="full-width longInput" />
|
||||||
placeholder="请输入项目名称"
|
|
||||||
:disabled="isEditing"
|
|
||||||
class="full-width longInput"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="项目编码" prop="projectCode">
|
<el-form-item label="项目编码" prop="projectCode">
|
||||||
<el-input
|
<el-input v-model="formData.projectCode" class="full-width" :disabled="isEditing" />
|
||||||
v-model="formData.projectCode"
|
|
||||||
class="full-width"
|
|
||||||
:disabled="isEditing"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="项目负责人" prop="projectLeader">
|
<el-form-item label="项目负责人" prop="projectLeader">
|
||||||
<el-input
|
<el-input v-model="formData.projectLeaderName" placeholder="选择项目负责人" readonly :disabled="isEditing"
|
||||||
v-model="formData.projectLeaderName"
|
@click.native="openProjectManagerSelect">
|
||||||
placeholder="选择项目负责人"
|
<el-button size="mini" slot="append" icon="el-icon-s-custom"></el-button></el-input>
|
||||||
readonly
|
|
||||||
:disabled="isEditing"
|
|
||||||
@click.native="openProjectManagerSelect"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="项目状态" prop="projectState">
|
<el-form-item label="数据状态" prop="dataState" style="display: none">
|
||||||
<el-select
|
<el-select v-model="formData.dataState" placeholder="根据时间自动生成" disabled class="full-width">
|
||||||
v-model="formData.projectState"
|
|
||||||
placeholder="根据时间自动生成"
|
|
||||||
disabled
|
|
||||||
class="full-width"
|
|
||||||
>
|
|
||||||
<el-option label="未启动" value="0" />
|
<el-option label="未启动" value="0" />
|
||||||
<el-option label="进行中" value="1" />
|
<el-option label="进行中" value="1" />
|
||||||
<el-option label="已完成" value="2" />
|
<el-option label="已完成" value="2" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="项目状态" prop="projectState">
|
||||||
|
<el-select v-model="formData.projectState" placeholder="请选择项目状态" class="full-width">
|
||||||
|
<el-option v-for="item in statusList" :key="item.dictValue" :label="item.dictLabel"
|
||||||
|
:value="item.dictValue" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="预计人天" prop="budgetDate">
|
<el-form-item label="预计人天" prop="budgetDate">
|
||||||
<el-input
|
<el-input v-model.number="formData.budgetDate" :min="0" :disabled="isEditing" class="full-width" />
|
||||||
v-model.number="formData.budgetDate"
|
|
||||||
:min="0"
|
|
||||||
:disabled="isEditing"
|
|
||||||
class="full-width"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="开始日期" prop="startDate">
|
<el-form-item label="开始日期" prop="startDate">
|
||||||
<el-date-picker
|
<el-date-picker v-model="formData.startDate" type="date" placeholder="选择开始日期" format="yyyy-MM-dd"
|
||||||
v-model="formData.startDate"
|
value-format="yyyy-MM-dd" class="full-width" :disabled="isEditing" />
|
||||||
type="date"
|
|
||||||
placeholder="选择开始日期"
|
|
||||||
format="yyyy-MM-dd"
|
|
||||||
value-format="yyyy-MM-dd"
|
|
||||||
class="full-width"
|
|
||||||
:disabled="isEditing"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="结束日期" prop="endDate">
|
<el-form-item label="结束日期" prop="endDate">
|
||||||
<el-date-picker
|
<el-date-picker v-model="formData.endDate" type="date" placeholder="选择结束日期" format="yyyy-MM-dd"
|
||||||
v-model="formData.endDate"
|
value-format="yyyy-MM-dd" class="full-width" :disabled="isEditing" />
|
||||||
type="date"
|
</el-form-item>
|
||||||
placeholder="选择结束日期"
|
</el-col>
|
||||||
format="yyyy-MM-dd"
|
</el-row>
|
||||||
value-format="yyyy-MM-dd"
|
<el-row :gutter="24">
|
||||||
class="full-width"
|
<el-col :span="24">
|
||||||
:disabled="isEditing"
|
<el-form-item label="附件" prop="fileList">
|
||||||
/>
|
<div>
|
||||||
|
<el-upload class="upload-demo" ref="upload" :action="fileUpload" :show-file-list="false"
|
||||||
|
:auto-upload="true" :multiple="true" :before-upload="beforeUpload" :on-success="successUpload" :headers="{
|
||||||
|
Authorization: 'Bearer ' + token,
|
||||||
|
}" :data="{}">
|
||||||
|
<div class="flex-row aic" style="gap: 10px;margin-bottom: 10px;">
|
||||||
|
<el-button slot="trigger" size="small" type="default"
|
||||||
|
style="width: 200px;color: #333;font-weight: 500;">上传附件</el-button>
|
||||||
|
<div slot="tip" style="color: #999999;font-size: 12px;">单个附件限制100M</div>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
<div class="fileBox">
|
||||||
|
<div v-for="(item, index) in formData.fileList" class="fileRow flex-row jcsb aic" :key="index">
|
||||||
|
<div class="flex-row aic fileItem">
|
||||||
|
<img class="" :src="filePng" v-if="getFileType(item.fileName) == 'file'"> </img>
|
||||||
|
<img class="" :src="imagePng" v-else-if="getFileType(item.fileName) == 'image'"> </img>
|
||||||
|
<img class="" :src="zipPng" v-else-if="getFileType(item.fileName) == 'zip'"> </img>
|
||||||
|
<div @click="downFile(item.fileUrl)">{{ item.fileName }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="del" @click="delFile(item)">×</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="form-actions jcc" v-show="!isEditing">
|
<div class="form-actions jcc" v-show="!isEditing">
|
||||||
<el-button
|
<el-button type="primary" @click="saveProject" v-hasPermi="['project:detail:save']">保存</el-button>
|
||||||
type="primary"
|
|
||||||
@click="saveProject"
|
|
||||||
v-hasPermi="['project:detail:save']"
|
|
||||||
>保存</el-button
|
|
||||||
>
|
|
||||||
<el-button @click="cancelEdit">取消</el-button>
|
<el-button @click="cancelEdit">取消</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="userBox">
|
<div class="userBox">
|
||||||
<div class="table-actions">
|
<div class="table-actions">
|
||||||
<el-button
|
<el-button type="primary" @click="addUser" v-hasPermi="['project:detail:addUser']">新增成员</el-button>
|
||||||
type="primary"
|
|
||||||
@click="addUser"
|
|
||||||
v-hasPermi="['project:detail:addUser']"
|
|
||||||
>新增成员</el-button
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="f1">
|
<div class="f1">
|
||||||
<CustomTable
|
<CustomTable :columns="columns" :tableData="tableData" :show-selection="false" :show-index="true"
|
||||||
:columns="columns"
|
:show-pagination="false" @size-change="handleSizeChange" @current-change="handleCurrentChange"
|
||||||
:tableData="tableData"
|
style="height: 100%">
|
||||||
:show-selection="false"
|
|
||||||
:show-index="true"
|
|
||||||
:show-pagination="false"
|
|
||||||
@size-change="handleSizeChange"
|
|
||||||
@current-change="handleCurrentChange"
|
|
||||||
style="height: 100%;"
|
|
||||||
>
|
|
||||||
<template slot="userName" slot-scope="{ row }">
|
<template slot="userName" slot-scope="{ row }">
|
||||||
<el-input
|
<el-input v-if="row.isNew" v-model="row.userName" placeholder="选择人员" readonly
|
||||||
v-if="row.isNew"
|
@click.native="openSelectUser(row)" />
|
||||||
v-model="row.userName"
|
|
||||||
placeholder="选择人员"
|
|
||||||
readonly
|
|
||||||
@click.native="openSelectUser(row)"
|
|
||||||
/>
|
|
||||||
<span v-else>{{ row.userName }}</span>
|
<span v-else>{{ row.userName }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template slot="post" slot-scope="{ row }">
|
<template slot="post" slot-scope="{ row }">
|
||||||
<el-select
|
<el-select v-if="
|
||||||
v-if="
|
(row.isEditing === true && row.teamId == row.teamId) ||
|
||||||
(row.isEditing === true && row.teamId == row.teamId) ||
|
row.isNew
|
||||||
row.isNew
|
" v-model="row.postId" placeholder="请选择职位">
|
||||||
"
|
<el-option v-for="post in postOptions" :key="post.dictValue" :label="post.dictLabel"
|
||||||
v-model="row.postId"
|
:value="post.dictValue" />
|
||||||
placeholder="请选择职位"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="post in postOptions"
|
|
||||||
:key="post.dictValue"
|
|
||||||
:label="post.dictLabel"
|
|
||||||
:value="post.dictValue"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
<span v-else>{{
|
<span v-else>{{
|
||||||
postOptions.find((post) => post.dictValue === row.postId)
|
postOptions.find((post) => post.dictValue === row.postId)
|
||||||
? postOptions.find((post) => post.dictValue === row.postId)
|
? postOptions.find((post) => post.dictValue === row.postId)
|
||||||
.dictLabel
|
.dictLabel
|
||||||
: ""
|
: ""
|
||||||
}}</span>
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
<template slot="operation" slot-scope="{ row }">
|
<template slot="operation" slot-scope="{ row }">
|
||||||
<div class="operation-buttons">
|
<div class="operation-buttons">
|
||||||
<template v-if="row.isNew">
|
<template v-if="row.isNew">
|
||||||
<el-button
|
<el-button text type="text" size="mini" @click="confirmAddUser(row)">确认</el-button>
|
||||||
text
|
<el-button text type="text" size="mini" @click="cancelAddUser(row)">取消</el-button>
|
||||||
type="text"
|
|
||||||
size="mini"
|
|
||||||
@click="confirmAddUser(row)"
|
|
||||||
>确认</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
text
|
|
||||||
type="text"
|
|
||||||
size="mini"
|
|
||||||
@click="cancelAddUser(row)"
|
|
||||||
>取消</el-button
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="row.isEditing && row.teamId == row.teamId">
|
<template v-else-if="row.isEditing && row.teamId == row.teamId">
|
||||||
<el-button
|
<el-button text type="text" size="mini" @click="saveUserEdit(row)">保存</el-button>
|
||||||
text
|
<el-button text type="text" size="mini" @click="cancelUserEdit(row)">取消</el-button>
|
||||||
type="text"
|
|
||||||
size="mini"
|
|
||||||
@click="saveUserEdit(row)"
|
|
||||||
>保存</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
text
|
|
||||||
type="text"
|
|
||||||
size="mini"
|
|
||||||
@click="cancelUserEdit(row)"
|
|
||||||
>取消</el-button
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-button
|
<el-button type="text" size="mini" v-hasPermi="['project:detail:editUser']"
|
||||||
type="text"
|
@click="editUser(row)">编辑</el-button>
|
||||||
size="mini"
|
<el-button type="text" size="mini" v-hasPermi="['project:detail:workLog']"
|
||||||
v-hasPermi="['project:detail:editUser']"
|
@click="showTimesheet(row)">工作日志</el-button>
|
||||||
@click="editUser(row)"
|
<el-button type="text" size="mini" v-hasPermi="['project:detail:deleteUser']"
|
||||||
>编辑</el-button
|
@click="confirmDelete(row)">删除</el-button>
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="text"
|
|
||||||
size="mini"
|
|
||||||
v-hasPermi="['project:detail:workLog']"
|
|
||||||
@click="showTimesheet(row)"
|
|
||||||
>工作日志</el-button
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
type="text"
|
|
||||||
size="mini"
|
|
||||||
v-hasPermi="['project:detail:deleteUser']"
|
|
||||||
@click="confirmDelete(row)"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -221,22 +145,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SelectUser
|
<SelectUser :dialogVisible="showSelectUser" :multi-select="false" :currentSelectedUser="currentSelectedUser"
|
||||||
:dialogVisible="showSelectUser"
|
@confirm="handleUserConfirm" @close="closeSelectUser" />
|
||||||
:multi-select="false"
|
|
||||||
:currentSelectedUser="currentSelectedUser"
|
|
||||||
@confirm="handleUserConfirm"
|
|
||||||
@close="closeSelectUser"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SelectUser
|
<SelectUser :dialogVisible="showProjectManagerSelect" :multi-select="false"
|
||||||
v-if="showProjectManagerSelect"
|
:currentSelectedUser="projectManagerSelectedUser" @confirm="handleProjectManagerConfirm"
|
||||||
:dialogVisible="showProjectManagerSelect"
|
@close="closeProjectManagerSelect" />
|
||||||
:multi-select="false"
|
|
||||||
:selected-users="projectManagerSelectedUser"
|
|
||||||
@confirm="handleProjectManagerConfirm"
|
|
||||||
@close="closeProjectManagerSelect"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -244,6 +158,10 @@
|
||||||
import CustomTable from "@/components/CustomTable.vue";
|
import CustomTable from "@/components/CustomTable.vue";
|
||||||
import SelectUser from "@/components/SelectUser.vue";
|
import SelectUser from "@/components/SelectUser.vue";
|
||||||
import { projectApi, systemApi } from "@/utils/api";
|
import { projectApi, systemApi } from "@/utils/api";
|
||||||
|
import filePng from "@/assets/images/file.png";
|
||||||
|
import zipPng from "@/assets/images/zip.png";
|
||||||
|
import imagePng from "@/assets/images/image.png";
|
||||||
|
import { getToken } from "@/utils/auth";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -268,8 +186,13 @@ export default {
|
||||||
endDate: "",
|
endDate: "",
|
||||||
budgetDate: 0,
|
budgetDate: 0,
|
||||||
state: 0,
|
state: 0,
|
||||||
|
dataState: 0,
|
||||||
|
fileList: []
|
||||||
},
|
},
|
||||||
postOptions: [],
|
postOptions: [],
|
||||||
|
statusList: [],
|
||||||
|
fileUpload: systemApi.fileUpload,
|
||||||
|
|
||||||
columns: [
|
columns: [
|
||||||
{ prop: "userName", label: "姓名" },
|
{ prop: "userName", label: "姓名" },
|
||||||
{ prop: "post", label: "项目职位" },
|
{ prop: "post", label: "项目职位" },
|
||||||
|
@ -277,6 +200,8 @@ export default {
|
||||||
{ prop: "operation", label: "操作", width: "250px" },
|
{ prop: "operation", label: "操作", width: "250px" },
|
||||||
],
|
],
|
||||||
tableData: [],
|
tableData: [],
|
||||||
|
fileLoading: false,
|
||||||
|
|
||||||
currentEditingRow: {},
|
currentEditingRow: {},
|
||||||
currentSelectedUser: [],
|
currentSelectedUser: [],
|
||||||
projectManagerSelectedUser: [],
|
projectManagerSelectedUser: [],
|
||||||
|
@ -287,8 +212,12 @@ export default {
|
||||||
projectLeader: [
|
projectLeader: [
|
||||||
{ required: true, message: "项目负责人为必填", trigger: "change" },
|
{ required: true, message: "项目负责人为必填", trigger: "change" },
|
||||||
],
|
],
|
||||||
|
projectState: [
|
||||||
|
{ required: true, message: "请选择项目状态", trigger: "change" },
|
||||||
|
],
|
||||||
startDate: [
|
startDate: [
|
||||||
{ required: true, message: "开始日期为必填", trigger: "change" },
|
{ required: true, message: "开始日期为必填", trigger: "change" },
|
||||||
|
{ validator: this.validateDates, trigger: "change" },
|
||||||
],
|
],
|
||||||
endDate: [
|
endDate: [
|
||||||
{ required: true, message: "结束日期为必填", trigger: "change" },
|
{ required: true, message: "结束日期为必填", trigger: "change" },
|
||||||
|
@ -296,9 +225,17 @@ export default {
|
||||||
],
|
],
|
||||||
budgetDate: [
|
budgetDate: [
|
||||||
{ required: true, message: "预算天数为必填", trigger: "blur" },
|
{ required: true, message: "预算天数为必填", trigger: "blur" },
|
||||||
{ validator: this.validateDates, trigger: "change" },
|
|
||||||
],
|
],
|
||||||
|
// fileList: [
|
||||||
|
// { required: true, message: "附件为必填", trigger: "blur" },
|
||||||
|
// ],
|
||||||
},
|
},
|
||||||
|
filePng,
|
||||||
|
zipPng,
|
||||||
|
imagePng,
|
||||||
|
token: getToken(),
|
||||||
|
delFileArr: []
|
||||||
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -319,11 +256,11 @@ export default {
|
||||||
|
|
||||||
if (start && end) {
|
if (start && end) {
|
||||||
if (now < start) {
|
if (now < start) {
|
||||||
this.formData.projectState = "0"; // 未开始
|
this.formData.dataState = "0"; // 未开始
|
||||||
} else if (now >= start && now <= end) {
|
} else if (now >= start && now <= end) {
|
||||||
this.formData.projectState = "1"; // 进行中
|
this.formData.dataState = "1"; // 进行中
|
||||||
} else {
|
} else {
|
||||||
this.formData.projectState = "2"; // 已结束
|
this.formData.dataState = "2"; // 已结束
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -351,10 +288,10 @@ export default {
|
||||||
const projectDataToSave = {
|
const projectDataToSave = {
|
||||||
...this.formData,
|
...this.formData,
|
||||||
startDate: this.formData.startDate
|
startDate: this.formData.startDate
|
||||||
? new Date(this.formData.startDate+' 00:00:00').getTime()
|
? new Date(this.formData.startDate + " 00:00:00").getTime()
|
||||||
: null,
|
: null,
|
||||||
endDate: this.formData.endDate
|
endDate: this.formData.endDate
|
||||||
? new Date(this.formData.endDate+' 23:59:59').getTime()
|
? new Date(this.formData.endDate + " 23:59:59").getTime()
|
||||||
: null,
|
: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -363,6 +300,8 @@ export default {
|
||||||
this.formData.projectId = res.data.projectId;
|
this.formData.projectId = res.data.projectId;
|
||||||
this.formData.projectCode = res.data.projectCode;
|
this.formData.projectCode = res.data.projectCode;
|
||||||
this.$modal.msgSuccess("操作成功");
|
this.$modal.msgSuccess("操作成功");
|
||||||
|
this.fetchProjectData()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const hasLog = await projectApi.projectHasLogData({
|
const hasLog = await projectApi.projectHasLogData({
|
||||||
projectId: this.formData.projectId,
|
projectId: this.formData.projectId,
|
||||||
|
@ -376,15 +315,28 @@ export default {
|
||||||
)
|
)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
await projectApi.updateProject(projectDataToSave);
|
await projectApi.updateProject(projectDataToSave);
|
||||||
|
if (this.delFileArr.length) {
|
||||||
|
await systemApi.delFileBatch(this.delFileArr.join(','))
|
||||||
|
this.delFileArr = []
|
||||||
|
|
||||||
|
}
|
||||||
|
this.fetchProjectData()
|
||||||
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await projectApi.updateProject(projectDataToSave);
|
await projectApi.updateProject(projectDataToSave);
|
||||||
|
if (this.delFileArr.length) {
|
||||||
|
await systemApi.delFileBatch(this.delFileArr.join(','))
|
||||||
|
this.delFileArr = []
|
||||||
|
}
|
||||||
|
this.fetchProjectData()
|
||||||
|
|
||||||
this.$modal.msgSuccess("操作成功");
|
this.$modal.msgSuccess("操作成功");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.$modal.msgError("请检查表单填写是否正确");
|
this.$modal.msgError("请检查表单填写是否正确");
|
||||||
this.$modal.msgSuccess("操作成功");
|
// this.$modal.msgSuccess("操作成功");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -405,10 +357,10 @@ export default {
|
||||||
isNew: true,
|
isNew: true,
|
||||||
userId: "",
|
userId: "",
|
||||||
isEditing: true,
|
isEditing: true,
|
||||||
index: this.tableData.length,
|
index: this.tableData.length - 1,
|
||||||
};
|
};
|
||||||
this.currentEditingRow = newUser;
|
this.currentEditingRow = newUser;
|
||||||
this.tableData.push(newUser);
|
this.tableData.unshift(newUser);
|
||||||
},
|
},
|
||||||
confirmAddUser(row) {
|
confirmAddUser(row) {
|
||||||
if (!this.formData.projectId) {
|
if (!this.formData.projectId) {
|
||||||
|
@ -439,13 +391,15 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
cancelAddUser(row) {
|
cancelAddUser(row) {
|
||||||
const index = this.tableData.findIndex(
|
if (row.index != undefined) {
|
||||||
(item) => item.userId === row.userId
|
let index = this.tableData.findIndex((item) => item.index == row.index);
|
||||||
);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.tableData.splice(index, 1);
|
this.tableData.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
this.tableData.splice(row.index, 1);
|
var index = this.tableData.findIndex(
|
||||||
|
(item) => item.userId === row.userId
|
||||||
|
);
|
||||||
|
this.tableData.splice(index, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
cancelUserEdit(row) {
|
cancelUserEdit(row) {
|
||||||
|
@ -457,6 +411,8 @@ export default {
|
||||||
this.currentSelectedUser = row.userId
|
this.currentSelectedUser = row.userId
|
||||||
? [{ userId: row.userId, userName: row.userName }]
|
? [{ userId: row.userId, userName: row.userName }]
|
||||||
: [];
|
: [];
|
||||||
|
console.log(111, this.currentSelectedUser);
|
||||||
|
|
||||||
this.showSelectUser = true;
|
this.showSelectUser = true;
|
||||||
},
|
},
|
||||||
handleUserConfirm(selectedUsers) {
|
handleUserConfirm(selectedUsers) {
|
||||||
|
@ -477,11 +433,11 @@ export default {
|
||||||
openProjectManagerSelect() {
|
openProjectManagerSelect() {
|
||||||
this.projectManagerSelectedUser = this.formData.projectLeader
|
this.projectManagerSelectedUser = this.formData.projectLeader
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
id: this.formData.projectLeaderId,
|
userId: this.formData.projectLeader,
|
||||||
name: this.formData.projectLeader,
|
nickName: this.formData.projectLeaderName,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
this.showProjectManagerSelect = true;
|
this.showProjectManagerSelect = true;
|
||||||
},
|
},
|
||||||
|
@ -532,7 +488,7 @@ export default {
|
||||||
},
|
},
|
||||||
async fetchProjectData(id) {
|
async fetchProjectData(id) {
|
||||||
try {
|
try {
|
||||||
const response = await projectApi.getProjectDetail(id);
|
const response = await projectApi.getProjectDetail(id||this.formData.projectId);
|
||||||
const projectData = response.data;
|
const projectData = response.data;
|
||||||
let {
|
let {
|
||||||
projectId,
|
projectId,
|
||||||
|
@ -543,6 +499,7 @@ export default {
|
||||||
projectState,
|
projectState,
|
||||||
budgetDate,
|
budgetDate,
|
||||||
state,
|
state,
|
||||||
|
fileList
|
||||||
} = response.data;
|
} = response.data;
|
||||||
let startDate = projectData.startDate.split(" ")[0];
|
let startDate = projectData.startDate.split(" ")[0];
|
||||||
let endDate = projectData.endDate.split(" ")[0];
|
let endDate = projectData.endDate.split(" ")[0];
|
||||||
|
@ -557,6 +514,7 @@ export default {
|
||||||
endDate,
|
endDate,
|
||||||
budgetDate,
|
budgetDate,
|
||||||
state,
|
state,
|
||||||
|
fileList
|
||||||
};
|
};
|
||||||
this.updateProjectState(); // 更新项目状态
|
this.updateProjectState(); // 更新项目状态
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -566,7 +524,9 @@ export default {
|
||||||
},
|
},
|
||||||
async getDictData() {
|
async getDictData() {
|
||||||
const res = await systemApi.getDictData("business_positions");
|
const res = await systemApi.getDictData("business_positions");
|
||||||
|
const res2 = await systemApi.getDictData("business_projectstate");
|
||||||
this.postOptions = res.data;
|
this.postOptions = res.data;
|
||||||
|
this.statusList = res2.data;
|
||||||
},
|
},
|
||||||
async getProjectUser() {
|
async getProjectUser() {
|
||||||
const res = await projectApi.getProjectUser(this.formData.projectId);
|
const res = await projectApi.getProjectUser(this.formData.projectId);
|
||||||
|
@ -597,6 +557,90 @@ export default {
|
||||||
this.$modal.msgError("更新用户信息失败");
|
this.$modal.msgError("更新用户信息失败");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
beforeUpload(file) {
|
||||||
|
|
||||||
|
this.fileLoading = true;
|
||||||
|
if (file.size > 1024 * 1024 * 100) {
|
||||||
|
this.fileLoading = false;
|
||||||
|
|
||||||
|
this.$message({
|
||||||
|
type: "warning",
|
||||||
|
message: "单个文件不能大于100M!",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
successUpload(res, file, fileList) {
|
||||||
|
if (!fileList.filter((ele) => ele.percentage != 100).length) {
|
||||||
|
this.fileLoading = false;
|
||||||
|
}
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.formData.fileList.push({
|
||||||
|
fileName: res.originalFilename, //文件名称
|
||||||
|
filePath: res.filePath, //文件路径
|
||||||
|
fileNewName: res.newFileName, //文件新名称
|
||||||
|
fileUrl: res.url,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.fileLoading = false;
|
||||||
|
this.$message({
|
||||||
|
type: "error",
|
||||||
|
message: res.msg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delFile(row) {
|
||||||
|
if (row.id) {
|
||||||
|
this.$confirm("此操作将永久删除文件, 是否继续?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}).then(() => {
|
||||||
|
this.delFileArr.push(row.id)
|
||||||
|
this.formData.fileList = this.formData.fileList.filter(
|
||||||
|
(ele) => ele.fileNewName != row.fileNewName
|
||||||
|
);
|
||||||
|
this.$message({
|
||||||
|
type: 'success',
|
||||||
|
message: "删除成功!"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.formData.fileList = this.formData.fileList.filter(
|
||||||
|
(ele) => ele.fileNewName != row.fileNewName
|
||||||
|
);
|
||||||
|
this.$message({
|
||||||
|
type: 'success',
|
||||||
|
message: "删除成功!"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getFileType(name) {
|
||||||
|
var data = {
|
||||||
|
jpg: 'image',
|
||||||
|
jpeg: 'image',
|
||||||
|
png: 'image',
|
||||||
|
gif: 'image',
|
||||||
|
bmp: 'image',
|
||||||
|
tiff: 'image',
|
||||||
|
svg: 'image',
|
||||||
|
pdf: 'file',
|
||||||
|
doc: 'file',
|
||||||
|
docx: 'file',
|
||||||
|
xls: 'file',
|
||||||
|
xlsx: 'file',
|
||||||
|
txt: 'file',
|
||||||
|
ppt: 'file',
|
||||||
|
zip: 'zip',
|
||||||
|
rar: 'zip',
|
||||||
|
tar: 'zip',
|
||||||
|
targz: 'zip',
|
||||||
|
}
|
||||||
|
return data[name.split('.')[1]] || 'file'
|
||||||
|
},
|
||||||
|
downFile(url) {
|
||||||
|
window.open(url);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const projectId = this.$route.params.id || this.$route.query.id;
|
const projectId = this.$route.params.id || this.$route.query.id;
|
||||||
|
@ -608,6 +652,7 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.updateProjectState(); // 对于新项目,也要初始化状态
|
this.updateProjectState(); // 对于新项目,也要初始化状态
|
||||||
}
|
}
|
||||||
|
// 获取项目状态数据字典
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -638,7 +683,8 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-form ::v-deep .el-form-item {
|
.custom-form ::v-deep .el-form-item {
|
||||||
margin-bottom: 25px; /* 增加表单行间距 */
|
margin-bottom: 25px;
|
||||||
|
/* 增加表单行间距 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-form ::v-deep .el-form-item__content {
|
.custom-form ::v-deep .el-form-item__content {
|
||||||
|
@ -647,22 +693,29 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-form ::v-deep .el-input {
|
.custom-form ::v-deep .el-input {
|
||||||
height: 42px; /* 调高输入框高度 */
|
height: 42px;
|
||||||
|
/* 调高输入框高度 */
|
||||||
width: 80%;
|
width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .el-form-item__label {
|
::v-deep .el-form-item__label {
|
||||||
height: 42px; /* 调高输入框高度 */
|
height: 42px;
|
||||||
|
/* 调高输入框高度 */
|
||||||
line-height: 42px;
|
line-height: 42px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-form ::v-deep .el-input__wrapper,
|
.custom-form ::v-deep .el-input__wrapper,
|
||||||
.custom-form ::v-deep .el-date-editor.el-input,
|
.custom-form ::v-deep .el-date-editor.el-input,
|
||||||
.custom-form ::v-deep .el-input-number {
|
.custom-form ::v-deep .el-input-number {
|
||||||
height: 42px; /* 调高输入框高度 */
|
height: 42px;
|
||||||
|
/* 调高输入框高度 */
|
||||||
width: 80%;
|
width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-form ::v-deep .el-input__inner {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.custom-form ::v-deep .el-select {
|
.custom-form ::v-deep .el-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -674,12 +727,14 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.userBox {
|
.userBox {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-actions {
|
.table-actions {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -746,4 +801,34 @@ export default {
|
||||||
height: 64px;
|
height: 64px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fileRow {
|
||||||
|
height: 38px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.del {
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fileItem {
|
||||||
|
gap: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fileBox {
|
||||||
|
max-height: 136px;
|
||||||
|
overflow: auto;
|
||||||
|
padding-right: 10px;
|
||||||
|
max-width: 90%;
|
||||||
|
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="project-list">
|
<div class="project-list">
|
||||||
|
<div class="table-actions mb10" style="text-align: right">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="mini"
|
||||||
|
@click="addProject"
|
||||||
|
v-hasPermi="['project:list:add']"
|
||||||
|
style="height: 30px"
|
||||||
|
>+ 新建项目</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div class="search-bar">
|
<div class="search-bar">
|
||||||
<el-form
|
<el-form
|
||||||
:inline="true"
|
:inline="true"
|
||||||
|
@ -16,32 +26,32 @@
|
||||||
placeholder="负责人"
|
placeholder="负责人"
|
||||||
readonly
|
readonly
|
||||||
@click.native="openUserSelectDialog"
|
@click.native="openUserSelectDialog"
|
||||||
/>
|
><el-button slot="append" icon="el-icon-s-custom"></el-button
|
||||||
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="项目状态" class="form-item">
|
<el-form-item label="项目状态" class="form-item">
|
||||||
<el-select v-model="searchForm.projectState" placeholder="项目状态">
|
<el-select
|
||||||
<el-option label="全部" value="" />
|
v-model="searchForm.projectState"
|
||||||
<el-option label="未启动" value="0" />
|
placeholder="项目状态"
|
||||||
<el-option label="进行中" value="1" />
|
clearable
|
||||||
<el-option label="已完成" value="2" />
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in statusList"
|
||||||
|
:key="item.dictValue"
|
||||||
|
:label="item.dictLabel"
|
||||||
|
:value="item.dictValue"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="search-buttons">
|
<el-form-item class="formBtn">
|
||||||
<el-button type="primary" @click="onSearch">查询</el-button>
|
<el-button type="primary" size="medium" @click="onSearch"
|
||||||
<el-button @click="onReset">重置</el-button>
|
>查询</el-button
|
||||||
|
>
|
||||||
|
<el-button @click="onReset" size="medium">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-actions mb10">
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
size="mini"
|
|
||||||
@click="addProject"
|
|
||||||
v-hasPermi="['project:list:add']"
|
|
||||||
>+ 新建项目</el-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="f1 df">
|
<div class="f1 df">
|
||||||
<CustomTable
|
<CustomTable
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
@ -51,24 +61,31 @@
|
||||||
:show-index="true"
|
:show-index="true"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
tableHeight="600"
|
tableHeight="510px"
|
||||||
|
ref="customTableRef"
|
||||||
>
|
>
|
||||||
<template slot="operation" slot-scope="{ row }">
|
<template slot="operation" slot-scope="{ row }">
|
||||||
<div class="operation-buttons">
|
<div class="operation-buttons">
|
||||||
|
<el-button
|
||||||
|
@click="handleDemand(row)"
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
v-hasPermi="['project:list:demand']"
|
||||||
|
>需求管理</el-button
|
||||||
|
>
|
||||||
<el-button
|
<el-button
|
||||||
@click="handleEdit(row)"
|
@click="handleEdit(row)"
|
||||||
type="text"
|
type="text"
|
||||||
size="mini"
|
size="mini"
|
||||||
icon="el-icon-edit"
|
|
||||||
v-hasPermi="['project:list:eidt']"
|
v-hasPermi="['project:list:eidt']"
|
||||||
>编辑</el-button
|
>编辑</el-button
|
||||||
>
|
>
|
||||||
<el-button
|
<el-button
|
||||||
type="text"
|
type="text"
|
||||||
size="mini"
|
size="mini"
|
||||||
icon="el-icon-delete"
|
|
||||||
@click="handleDelete(row)"
|
@click="handleDelete(row)"
|
||||||
v-hasPermi="['project:list:delete']"
|
v-hasPermi="['project:list:delete']"
|
||||||
|
style="color: #666"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,7 +105,7 @@
|
||||||
<script>
|
<script>
|
||||||
import CustomTable from "@/components/CustomTable.vue";
|
import CustomTable from "@/components/CustomTable.vue";
|
||||||
import SelectUser from "@/components/SelectUser.vue";
|
import SelectUser from "@/components/SelectUser.vue";
|
||||||
import { projectApi } from "@/utils/api";
|
import { projectApi, systemApi } from "@/utils/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -104,52 +121,57 @@ export default {
|
||||||
projectState: "",
|
projectState: "",
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
{ prop: "projectName", label: "项目名称" },
|
{ prop: "projectName", label: "项目名称", width: 300 },
|
||||||
{ prop: "projectCode", label: "项目编号" },
|
{ prop: "projectCode", label: "项目编号", width: 200 },
|
||||||
{ prop: "projectLeaderName", label: "负责人" },
|
{ prop: "projectLeaderName", label: "负责人" },
|
||||||
{ prop: "budgetDate", label: "预计工时(天)" },
|
{ prop: "budgetDate", label: "预计工时(天)" },
|
||||||
{
|
{
|
||||||
prop: "startDate",
|
prop: "startDate",
|
||||||
label: "开始时间",
|
label: "开始时间",
|
||||||
type: "status",
|
type: "status",
|
||||||
callback: (data) => data.split(" ")[0],
|
callback: (data) => data?.split(" ")[0],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "endDate",
|
prop: "endDate",
|
||||||
label: "结束时间",
|
label: "结束时间",
|
||||||
type: "status",
|
type: "status",
|
||||||
callback: (data) => data.split(" ")[0],
|
callback: (data) => data?.split(" ")[0],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "projectState",
|
prop: "projectState",
|
||||||
label: "项目状态",
|
label: "项目状态",
|
||||||
type: "status",
|
type: "status",
|
||||||
callback: (value) => {
|
callback: (value) => {
|
||||||
let status = "未知";
|
let status =
|
||||||
let color = "";
|
this.statusList.find((ele) => ele.dictValue == value)
|
||||||
switch (value) {
|
?.dictLabel || "";
|
||||||
case "0":
|
let color = "#333";
|
||||||
status = "未启动";
|
switch (status) {
|
||||||
color = "#909399"; // 灰色
|
case "待启动":
|
||||||
|
color = "#999999"; // 橙色
|
||||||
break;
|
break;
|
||||||
case "1":
|
case "进行中":
|
||||||
status = "进行中";
|
color = "#FF7D00"; // 红色
|
||||||
color = "#409EFF"; // 蓝色
|
|
||||||
break;
|
break;
|
||||||
case "2":
|
case "已完成":
|
||||||
status = "已完成";
|
color = "#50B6AA"; // 绿色
|
||||||
color = "#67C23A"; // 绿色
|
break;
|
||||||
|
case "#50B6AA":
|
||||||
|
color = "#999999"; // 红色
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
color = "#333"; // 默认白色
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return `<span style="color: ${color}">${status}</span>`;
|
return `<span style="color: ${color}">${status}</span>`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ prop: "teamNum", label: "参与项目人数" },
|
{ prop: "teamNum", label: "参与项目人数", width: 100 },
|
||||||
{ prop: "createByName", label: "项目创建人" },
|
{ prop: "createByName", label: "项目创建人" },
|
||||||
{
|
{
|
||||||
prop: "operation",
|
prop: "operation",
|
||||||
label: "操作",
|
label: "操作",
|
||||||
width: "150",
|
width: "250",
|
||||||
fixed: "right",
|
fixed: "right",
|
||||||
className: "operation-column",
|
className: "operation-column",
|
||||||
},
|
},
|
||||||
|
@ -160,17 +182,19 @@ export default {
|
||||||
currentSelectedUser: [],
|
currentSelectedUser: [],
|
||||||
pageNum: 1, // 当前页码
|
pageNum: 1, // 当前页码
|
||||||
pageSize: 10, // 每页条数
|
pageSize: 10, // 每页条数
|
||||||
|
statusList: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onSearch() {
|
onSearch() {
|
||||||
console.log("Search with:", this.searchForm);
|
|
||||||
this.fetchProjectList();
|
this.fetchProjectList();
|
||||||
},
|
},
|
||||||
onReset() {
|
onReset() {
|
||||||
Object.keys(this.searchForm).forEach((key) => {
|
Object.keys(this.searchForm).forEach((key) => {
|
||||||
this.searchForm[key] = "";
|
this.searchForm[key] = "";
|
||||||
});
|
});
|
||||||
|
this.currentSelectedUser = [];
|
||||||
|
this.$refs.customTableRef.handleCurrentChange(1);
|
||||||
this.fetchProjectList();
|
this.fetchProjectList();
|
||||||
},
|
},
|
||||||
addProject() {
|
addProject() {
|
||||||
|
@ -178,6 +202,17 @@ export default {
|
||||||
path: "/project/detail",
|
path: "/project/detail",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleDemand(row) {
|
||||||
|
this.$router.push({
|
||||||
|
path: "/project/demandManage",
|
||||||
|
query: {
|
||||||
|
id: row.projectId,
|
||||||
|
projectName: row.projectName,
|
||||||
|
startDate: new Date(row.startDate).getTime(),
|
||||||
|
endDate: new Date(row.endDate).getTime(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
handleEdit(row) {
|
handleEdit(row) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: "/project/detail",
|
path: "/project/detail",
|
||||||
|
@ -228,8 +263,13 @@ export default {
|
||||||
handleUserClose() {
|
handleUserClose() {
|
||||||
this.userSelectDialogVisible = false;
|
this.userSelectDialogVisible = false;
|
||||||
},
|
},
|
||||||
|
async getDictData() {
|
||||||
|
const res = await systemApi.getDictData("business_projectstate");
|
||||||
|
this.statusList = res.data;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.getDictData();
|
||||||
this.fetchProjectList();
|
this.fetchProjectList();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -259,8 +299,16 @@ export default {
|
||||||
.demo-form-inline .el-form-item {
|
.demo-form-inline .el-form-item {
|
||||||
// margin-right: 50px; /* 将间距设置为 30px */
|
// margin-right: 50px; /* 将间距设置为 30px */
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
::v-deep .el-form-item__label {
|
||||||
|
color: #999 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.formBtn {
|
||||||
|
border: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-form-inline .el-form-item:last-child {
|
.demo-form-inline .el-form-item:last-child {
|
||||||
margin-right: 0; /* 移除最后一个元素的右边距 */
|
margin-right: 0; /* 移除最后一个元素的右边距 */
|
||||||
}
|
}
|
||||||
|
@ -276,6 +324,10 @@ export default {
|
||||||
.form-item ::v-deep .el-input,
|
.form-item ::v-deep .el-input,
|
||||||
.form-item ::v-deep .el-select {
|
.form-item ::v-deep .el-select {
|
||||||
// width: 100%;
|
// width: 100%;
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-buttons {
|
.search-buttons {
|
||||||
|
@ -285,11 +337,13 @@ export default {
|
||||||
::v-deep .operation-buttons .el-button {
|
::v-deep .operation-buttons .el-button {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .operation-column {
|
::v-deep .operation-column {
|
||||||
background-color: #fff;
|
background-color: #ffffff;
|
||||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
|
box-shadow: -2px 0 5px rgba(241, 112, 6, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-button.is-text {
|
.el-button.is-text {
|
||||||
|
@ -327,4 +381,8 @@ export default {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
.search-buttons ::v-deep .el-button {
|
||||||
|
width: 90px !important;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,6 +5,22 @@
|
||||||
<div class="shadowBox"></div>
|
<div class="shadowBox"></div>
|
||||||
<div class="flex-row aic mb20">
|
<div class="flex-row aic mb20">
|
||||||
<h2 class="textC">项目执行表</h2>
|
<h2 class="textC">项目执行表</h2>
|
||||||
|
<div class="ml20">
|
||||||
|
项目状态:
|
||||||
|
<el-select
|
||||||
|
v-model="projectState"
|
||||||
|
placeholder="项目状态"
|
||||||
|
@change="getProjectProgress"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in statusList"
|
||||||
|
:key="item.dictValue"
|
||||||
|
:label="item.dictLabel"
|
||||||
|
:value="item.dictValue"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
<div class="date-range-container">
|
<div class="date-range-container">
|
||||||
<span class="date-range-label">统计时间:</span>
|
<span class="date-range-label">统计时间:</span>
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
|
@ -20,7 +36,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="f1">
|
<div class="f1" style="position: relative">
|
||||||
<CustomTable
|
<CustomTable
|
||||||
:columns="fixedColumns"
|
:columns="fixedColumns"
|
||||||
:tableData="executionData"
|
:tableData="executionData"
|
||||||
|
@ -28,19 +44,22 @@
|
||||||
:showSummary="true"
|
:showSummary="true"
|
||||||
:summaryMethod="getFixedColumnsSummaries"
|
:summaryMethod="getFixedColumnsSummaries"
|
||||||
tableHeight="600"
|
tableHeight="600"
|
||||||
|
:border="true"
|
||||||
></CustomTable>
|
></CustomTable>
|
||||||
|
<div id="scrollBox">
|
||||||
|
<div id="scrollBoxContent"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧滚动列表格 -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { projectBank } from "@/utils/api";
|
import { projectBank, systemApi } from "@/utils/api";
|
||||||
import CustomTable from "@/components/CustomTable.vue";
|
import CustomTable from "@/components/CustomTable.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: "ProjectProgress",
|
||||||
components: {
|
components: {
|
||||||
CustomTable,
|
CustomTable,
|
||||||
},
|
},
|
||||||
|
@ -50,6 +69,8 @@ export default {
|
||||||
dateRange: this.getDefaultDateRange(),
|
dateRange: this.getDefaultDateRange(),
|
||||||
fixedColumns: [],
|
fixedColumns: [],
|
||||||
executionData: [],
|
executionData: [],
|
||||||
|
statusList: [],
|
||||||
|
projectState: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -66,9 +87,25 @@ export default {
|
||||||
const res = await projectBank.porjectProgress({
|
const res = await projectBank.porjectProgress({
|
||||||
startDate: this.dateRange[0] + " 00:00:00",
|
startDate: this.dateRange[0] + " 00:00:00",
|
||||||
endDate: this.dateRange[1] + " 00:00:00",
|
endDate: this.dateRange[1] + " 00:00:00",
|
||||||
|
projectState: this.projectState,
|
||||||
});
|
});
|
||||||
this.timeRange = [this.dateRange[0], this.dateRange[1]];
|
this.timeRange = [this.dateRange[0], this.dateRange[1]];
|
||||||
this.executionData = res.data;
|
this.executionData = res.data;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
let table = document.querySelector(
|
||||||
|
".el-table__body-wrapper .el-table__body"
|
||||||
|
);
|
||||||
|
let width = table.offsetWidth;
|
||||||
|
let tableBox = document.querySelector(".el-table__body-wrapper");
|
||||||
|
let box = document.getElementById("scrollBoxContent");
|
||||||
|
let scroll = document.getElementById("scrollBox");
|
||||||
|
box.style.width = width + "px";
|
||||||
|
scroll.addEventListener("scroll", (event) => {
|
||||||
|
tableBox.scrollLeft = scroll.scrollLeft;
|
||||||
|
});
|
||||||
|
},500);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
getFixedColumnsSummaries(param) {
|
getFixedColumnsSummaries(param) {
|
||||||
const { columns, data } = param;
|
const { columns, data } = param;
|
||||||
|
@ -80,7 +117,7 @@ export default {
|
||||||
}
|
}
|
||||||
let values;
|
let values;
|
||||||
if (column.property == "detailList") {
|
if (column.property == "detailList") {
|
||||||
values = data.map((item) => Number(item[column.property][index - 4]));
|
values = data.map((item) => Number(item[column.property][index - 5]));
|
||||||
} else if (column.property == "projectState") {
|
} else if (column.property == "projectState") {
|
||||||
values = [];
|
values = [];
|
||||||
} else {
|
} else {
|
||||||
|
@ -117,6 +154,10 @@ export default {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
async getDictData() {
|
||||||
|
const res = await systemApi.getDictData("business_projectstate");
|
||||||
|
this.statusList = res.data;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
timeRange: {
|
timeRange: {
|
||||||
|
@ -171,24 +212,38 @@ export default {
|
||||||
label: "项目状态",
|
label: "项目状态",
|
||||||
type: "button",
|
type: "button",
|
||||||
fixed: "left",
|
fixed: "left",
|
||||||
width: 100,
|
width: 150,
|
||||||
callback: (value) => {
|
callback: (value) => {
|
||||||
let status = "未知";
|
let status = this.statusList.find(
|
||||||
let color = "";
|
(ele) => ele.dictValue == value
|
||||||
switch (value) {
|
)?.dictLabel;
|
||||||
case "0":
|
let color = "#333";
|
||||||
status = "未启动";
|
// switch (status) {
|
||||||
color = "#909399"; // 灰色
|
// case "待启动":
|
||||||
break;
|
// color = "#fa721d"; // 橙色
|
||||||
case "1":
|
// break;
|
||||||
status = "进行中";
|
// case "已提需求-待开发":
|
||||||
color = "#409EFF"; // 蓝色
|
// color = "#dd242a"; // 红色
|
||||||
break;
|
// break;
|
||||||
case "2":
|
// case "已提需求-开发中":
|
||||||
status = "已完成";
|
// color = "#1686d8"; // 绿色
|
||||||
color = "#67C23A"; // 绿色
|
// break;
|
||||||
break;
|
// case "已提需求-已完成":
|
||||||
}
|
// color = "#5cb85c"; // 红色
|
||||||
|
// break;
|
||||||
|
// case "开发完成-待验收":
|
||||||
|
// color = "#f7c731"; // 黄色
|
||||||
|
// break;
|
||||||
|
// case "开发完成-已验收":
|
||||||
|
// color = "#8C33FF"; // 蓝色
|
||||||
|
// break;
|
||||||
|
// case "开发完成-已计收":
|
||||||
|
// color = "#08fb9e"; // 绿色
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// color = "#000"; // 默认白色
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
return `<span style="color: ${color}">${status}</span>`;
|
return `<span style="color: ${color}">${status}</span>`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -198,6 +253,12 @@ export default {
|
||||||
width: 100,
|
width: 100,
|
||||||
fixed: "left",
|
fixed: "left",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prop: "allDateWorkTime",
|
||||||
|
label: "总计工时\n(天)",
|
||||||
|
width: 100,
|
||||||
|
fixed: "left",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
prop: "allWorkTime",
|
prop: "allWorkTime",
|
||||||
label: "统计工时\n(天)",
|
label: "统计工时\n(天)",
|
||||||
|
@ -210,6 +271,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.getDictData();
|
||||||
this.getProjectProgress();
|
this.getProjectProgress();
|
||||||
},
|
},
|
||||||
beforeDestroy() {},
|
beforeDestroy() {},
|
||||||
|
@ -245,7 +307,7 @@ export default {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
::v-deep .el-table__footer td {
|
::v-deep .el-table__footer td {
|
||||||
background-color: #c0c4cc !important;
|
background-color: #e0e1e3 !important;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center; /* 确保合计行内容居中 */
|
text-align: center; /* 确保合计行内容居中 */
|
||||||
}
|
}
|
||||||
|
@ -298,7 +360,7 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
margin-left: 350px;
|
margin-left: 180px;
|
||||||
}
|
}
|
||||||
.date-range-label {
|
.date-range-label {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -322,8 +384,6 @@ export default {
|
||||||
}
|
}
|
||||||
::v-deep .el-table__fixed {
|
::v-deep .el-table__fixed {
|
||||||
box-shadow: 5px 20px 20px rgba(7, 7, 7, 0.5) !important;
|
box-shadow: 5px 20px 20px rgba(7, 7, 7, 0.5) !important;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.shadowBox {
|
.shadowBox {
|
||||||
// position: absolute;
|
// position: absolute;
|
||||||
|
@ -333,4 +393,18 @@ export default {
|
||||||
// left: 450px;
|
// left: 450px;
|
||||||
// z-index: 100;
|
// z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table__body-wrapper::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scrollBox {
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 590px;
|
||||||
|
#scrollBoxContent {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -60,6 +60,8 @@
|
||||||
:columns="scrollableColumns"
|
:columns="scrollableColumns"
|
||||||
:tableData="executionData"
|
:tableData="executionData"
|
||||||
:showPagination="false"
|
:showPagination="false"
|
||||||
|
:border="true"
|
||||||
|
tableHeight="600"
|
||||||
></CustomTable>
|
></CustomTable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -70,6 +72,7 @@ import CustomTable from "@/components/CustomTable.vue";
|
||||||
import { projectBank, projectApi } from "@/utils/api";
|
import { projectBank, projectApi } from "@/utils/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: "ProjectUser",
|
||||||
components: {
|
components: {
|
||||||
CustomTable,
|
CustomTable,
|
||||||
},
|
},
|
||||||
|
@ -146,7 +149,6 @@ export default {
|
||||||
newEndDate.setMonth(startDate.getMonth() + 3);
|
newEndDate.setMonth(startDate.getMonth() + 3);
|
||||||
this.dateRange[1] = newEndDate.toISOString().split("T")[0]; // 格式化为 YYYY-MM-DD
|
this.dateRange[1] = newEndDate.toISOString().split("T")[0]; // 格式化为 YYYY-MM-DD
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
async handleProjectChange(projectId, time) {
|
async handleProjectChange(projectId, time) {
|
||||||
const res = await projectApi.getProjectDetail(projectId);
|
const res = await projectApi.getProjectDetail(projectId);
|
||||||
|
@ -165,8 +167,6 @@ export default {
|
||||||
endDate: this.dateRange[1] + " 23:59:59",
|
endDate: this.dateRange[1] + " 23:59:59",
|
||||||
projectId: this.projectInfo.projectId,
|
projectId: this.projectInfo.projectId,
|
||||||
});
|
});
|
||||||
console.log(123,this.dateRange);
|
|
||||||
|
|
||||||
const start = new Date(this.timeRange[0]);
|
const start = new Date(this.timeRange[0]);
|
||||||
const end = new Date(this.timeRange[1]);
|
const end = new Date(this.timeRange[1]);
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
@ -180,7 +180,11 @@ export default {
|
||||||
goToDetail(row) {
|
goToDetail(row) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: "/",
|
path: "/",
|
||||||
query: { userId: row.userId, projectId: this.projectInfo.projectId,nickName:row.userName },
|
query: {
|
||||||
|
userId: row.userId,
|
||||||
|
projectId: this.projectInfo.projectId,
|
||||||
|
nickName: row.userName,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -222,6 +226,15 @@ export default {
|
||||||
this.scrollableColumns = days;
|
this.scrollableColumns = days;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'$route.query': {
|
||||||
|
deep: true,
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal.projectId != this.projectInfo.projectId&&newVal.projectId) {
|
||||||
|
this.selectedProject = Number(newVal.projectId);
|
||||||
|
this.handleProjectChange(this.selectedProject)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getProjectList();
|
this.getProjectList();
|
||||||
|
@ -366,4 +379,15 @@ export default {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
::v-deep .el-table__body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
::v-deep td.el-table__cell {
|
||||||
|
border-bottom: none;
|
||||||
|
border-top: none;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
::v-deep tr.el-table__row.current-row .el-table__cell {
|
||||||
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
placeholder="请选择用户"
|
placeholder="请选择用户"
|
||||||
readonly
|
readonly
|
||||||
@click.native="openUserSelectDialog"
|
@click.native="openUserSelectDialog"
|
||||||
|
suffix-icon="el-icon-s-custom"
|
||||||
></el-input>
|
></el-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="date-range-container">
|
<div class="date-range-container">
|
||||||
|
@ -34,7 +35,8 @@
|
||||||
:showPagination="false"
|
:showPagination="false"
|
||||||
:showSummary="true"
|
:showSummary="true"
|
||||||
:summaryMethod="getFixedColumnsSummaries"
|
:summaryMethod="getFixedColumnsSummaries"
|
||||||
:tableHeight="600"
|
tableHeight="600"
|
||||||
|
:border="true"
|
||||||
></CustomTable>
|
></CustomTable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,6 +57,7 @@ import SelectUser from "@/components/SelectUser.vue";
|
||||||
import { projectBank } from "@/utils/api";
|
import { projectBank } from "@/utils/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: "UserProject",
|
||||||
components: {
|
components: {
|
||||||
CustomTable,
|
CustomTable,
|
||||||
SelectUser,
|
SelectUser,
|
||||||
|
@ -64,11 +67,11 @@ export default {
|
||||||
fixedColumns: [],
|
fixedColumns: [],
|
||||||
executionData: [],
|
executionData: [],
|
||||||
dateRange: [],
|
dateRange: [],
|
||||||
selectedUserName: "超级管理员",
|
selectedUserName: this.$store.state.user.nickName,
|
||||||
selectedUserId: 1,
|
selectedUserId: this.$store.state.user.id,
|
||||||
selectedUser: {
|
selectedUser: {
|
||||||
userId: 1,
|
userId: this.$store.state.user.id,
|
||||||
selectedUserName: "超级管理员",
|
selectedUserName: this.$store.state.user.nickName,
|
||||||
},
|
},
|
||||||
userSelectDialogVisible: false,
|
userSelectDialogVisible: false,
|
||||||
};
|
};
|
||||||
|
@ -229,11 +232,13 @@ export default {
|
||||||
}
|
}
|
||||||
.selectBox {
|
.selectBox {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
margin-left: 35px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
.selectBox span {
|
.selectBox span {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
}
|
}
|
||||||
|
.content{
|
||||||
|
|
||||||
::v-deep .el-table {
|
::v-deep .el-table {
|
||||||
height: 100% !important;
|
height: 100% !important;
|
||||||
}
|
}
|
||||||
|
@ -286,7 +291,7 @@ export default {
|
||||||
}
|
}
|
||||||
/* 调整合计行的样式 */
|
/* 调整合计行的样式 */
|
||||||
::v-deep .el-table__footer td {
|
::v-deep .el-table__footer td {
|
||||||
background-color: #c0c4cc !important;
|
background-color: #e0e1e3 !important;
|
||||||
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
|
@ -312,4 +317,9 @@ export default {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
::v-deep .el-table__footer td {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,392 @@
|
||||||
|
<template>
|
||||||
|
<div class="project-list flex-row jcsb">
|
||||||
|
<div class="left">
|
||||||
|
<div style="margin-bottom: 20px; font-weight: bold">组织架构</div>
|
||||||
|
<el-tree
|
||||||
|
:data="deptOptions"
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
ref="treeRef"
|
||||||
|
node-key="id"
|
||||||
|
default-expand-all
|
||||||
|
highlight-current
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
style="margin-left: 50px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="right f1">
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form
|
||||||
|
:inline="true"
|
||||||
|
:model="searchForm"
|
||||||
|
class="demo-form-inline"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-form-item label="统计任务" class="form-item">
|
||||||
|
<el-select
|
||||||
|
v-model="taskId"
|
||||||
|
placeholder="选择任务"
|
||||||
|
@change="getTaskUserList"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in taskList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.taskName"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="search-buttons">
|
||||||
|
<el-button @click="onReset">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="f1 df">
|
||||||
|
<CustomTable
|
||||||
|
:columns="columns"
|
||||||
|
:tableData="tableData"
|
||||||
|
:total="total"
|
||||||
|
:show-selection="false"
|
||||||
|
:show-index="true"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
tableHeight="495px"
|
||||||
|
@sortChange="sortChange"
|
||||||
|
:default-sort="{
|
||||||
|
prop: 'score',
|
||||||
|
order: 'descending',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template slot="operation" slot-scope="{ row }">
|
||||||
|
<div class="operation-buttons">
|
||||||
|
<el-button type="text" size="mini" @click="handleEdit(row, 0)"
|
||||||
|
>查看详情</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</CustomTable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CustomTable from "@/components/CustomTable.vue";
|
||||||
|
import SelectUser from "@/components/SelectUser.vue";
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
import { deptTreeSelect } from "@/api/system/user";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "UserScore",
|
||||||
|
components: {
|
||||||
|
CustomTable,
|
||||||
|
SelectUser,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
deptOptions: undefined,
|
||||||
|
taskId: "",
|
||||||
|
searchForm: {
|
||||||
|
userIdList: [],
|
||||||
|
userName: "",
|
||||||
|
isAsc: "desc",
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{ prop: "userName", label: "考核人员" },
|
||||||
|
{
|
||||||
|
prop: "score",
|
||||||
|
label: "考核评分",
|
||||||
|
sortable: "custom",
|
||||||
|
type: "status",
|
||||||
|
callback: (value, row) => {
|
||||||
|
if (row.score) {
|
||||||
|
return row.score;
|
||||||
|
} else if (row.examineStatus == 1) {
|
||||||
|
return row.manageScore;
|
||||||
|
} else if (row.examineStatusSelf == 1) {
|
||||||
|
return row.selfScore;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "examineStatus",
|
||||||
|
label: "状态",
|
||||||
|
type: "status",
|
||||||
|
callback: (value, row) => {
|
||||||
|
if (row.examineStatusSelf != 0 && row.examineStatus != 0)
|
||||||
|
var color = "#333";
|
||||||
|
else var color = "#FF7D00";
|
||||||
|
|
||||||
|
if (row.examineStatusSelf == 0 && row.examineStatus == 0) {
|
||||||
|
return `<span style="color: ${color}">待个人自评/组长评分</span>`;
|
||||||
|
} else if (row.examineStatusSelf == 0) {
|
||||||
|
return `<span style="color: ${color}">待个人自评</span>`;
|
||||||
|
} else if (row.examineStatus == 0) {
|
||||||
|
return `<span style="color: ${color}">待组长评分</span>`;
|
||||||
|
} else {
|
||||||
|
return `<span style="color: ${color}">已完成</span>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "operation",
|
||||||
|
label: "操作",
|
||||||
|
width: "250",
|
||||||
|
className: "operation-column",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tableData: [],
|
||||||
|
total: 0,
|
||||||
|
currentSelectedUser: [],
|
||||||
|
pageNum: 1, // 当前页码
|
||||||
|
pageSize: 10, // 每页条数
|
||||||
|
taskList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSearch() {
|
||||||
|
this.getTaskUserList();
|
||||||
|
},
|
||||||
|
onReset() {
|
||||||
|
Object.keys(this.searchForm).forEach((key) => {
|
||||||
|
this.searchForm[key] = "";
|
||||||
|
});
|
||||||
|
this.$refs.treeRef.setCurrentKey(null);
|
||||||
|
this.searchForm.isAsc = "desc"
|
||||||
|
this.initSort()
|
||||||
|
// this.searchForm.taskId = this.taskList[0]?.id;
|
||||||
|
|
||||||
|
this.getTaskUserList();
|
||||||
|
},
|
||||||
|
handleNodeClick(data) {
|
||||||
|
this.searchForm.deptId = data.id;
|
||||||
|
this.getTaskUserList();
|
||||||
|
},
|
||||||
|
handleEdit(row, edit) {
|
||||||
|
let score = "";
|
||||||
|
if (row.score) {
|
||||||
|
score = row.score;
|
||||||
|
} else if (row.manageScore) {
|
||||||
|
score = row.manageScore;
|
||||||
|
} else {
|
||||||
|
score = row.selfScore;
|
||||||
|
}
|
||||||
|
this.$router.push({
|
||||||
|
path: "/projectBank/userScoreDetail",
|
||||||
|
query: { taskId: row.taskId, examineId: row.id, score },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTaskUserList(init) {
|
||||||
|
if (!this.taskId) return;
|
||||||
|
taskApi
|
||||||
|
.getTaskUserList({
|
||||||
|
...this.searchForm,
|
||||||
|
taskId: this.taskId,
|
||||||
|
sortFiled: "all",
|
||||||
|
pageNum: this.pageNum,
|
||||||
|
pageSize: this.pageSize,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.tableData = res.rows;
|
||||||
|
this.total = res.total;
|
||||||
|
if (init === 1) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.initSort();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTaskList(init) {
|
||||||
|
taskApi
|
||||||
|
.getTaskList({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100000,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.taskList = res.rows;
|
||||||
|
this.taskId = res.rows[0]?.id;
|
||||||
|
this.getTaskUserList(init);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleSizeChange(size) {
|
||||||
|
this.pageSize = size;
|
||||||
|
this.pageNum = 1; // 重置为第一页
|
||||||
|
this.getTaskUserList();
|
||||||
|
},
|
||||||
|
handleCurrentChange(page) {
|
||||||
|
this.pageNum = page;
|
||||||
|
this.getTaskUserList();
|
||||||
|
},
|
||||||
|
getDeptTree() {
|
||||||
|
deptTreeSelect().then((response) => {
|
||||||
|
this.deptOptions = response.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
sortChange({ order }) {
|
||||||
|
let ele = document.getElementsByClassName("is-sortable")[0];
|
||||||
|
|
||||||
|
let className = ele.getAttribute("class");
|
||||||
|
if (order == "descending") {
|
||||||
|
ele.setAttribute(
|
||||||
|
"class",
|
||||||
|
className.replace("ascending", "") + " descending"
|
||||||
|
);
|
||||||
|
} else if (order == "ascending") {
|
||||||
|
ele.setAttribute(
|
||||||
|
"class",
|
||||||
|
className.replace("descending", "") + " ascending"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ele.setAttribute(
|
||||||
|
"class",
|
||||||
|
className.replace("ascending", "").replace("descending", "")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.searchForm.isAsc =
|
||||||
|
order == "descending" ? "desc" : order == "ascending" ? "asc" : "";
|
||||||
|
this.getTaskUserList();
|
||||||
|
},
|
||||||
|
initSort() {
|
||||||
|
let ele = document.getElementsByClassName("is-sortable")[0];
|
||||||
|
if(!ele) return
|
||||||
|
let className = ele.getAttribute("class");
|
||||||
|
ele.setAttribute("class", className.replace("ascending", "") + " descending");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getDeptTree();
|
||||||
|
this.getTaskList(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.project-list {
|
||||||
|
padding: 0 20px;
|
||||||
|
background-color: white;
|
||||||
|
height: 88vh;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 20px;
|
||||||
|
.left {
|
||||||
|
padding-top: 20px;
|
||||||
|
width: 300px;
|
||||||
|
height: 100%;
|
||||||
|
// box-shadow: 5px 0 5px rgba(0, 0, 0, 0.5); /* 阴影效果 */
|
||||||
|
border-right: 1px solid #eeeeee;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.right {
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline {
|
||||||
|
// display: flex;
|
||||||
|
// flex-wrap: nowrap;
|
||||||
|
// align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline .el-form-item {
|
||||||
|
// margin-right: 50px; /* 将间距设置为 30px */
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline .el-form-item:last-child {
|
||||||
|
margin-right: 0; /* 移除最后一个元素的右边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item ::v-deep .el-form-item__content {
|
||||||
|
// width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item ::v-deep .el-input,
|
||||||
|
.form-item ::v-deep .el-select {
|
||||||
|
// width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-buttons {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
::v-deep .operation-buttons .el-button {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0 2px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-column {
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: -2px 0 5px rgba(241, 112, 6, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button.is-text {
|
||||||
|
min-width: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer .el-button {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #e6a23c;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加以下样式来使对话框垂直居中 */
|
||||||
|
::v-deep .delete-dialog.el-dialog {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
::v-deep .el-table th {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .cell {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.search-buttons ::v-deep .el-button {
|
||||||
|
width: 90px !important;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table {
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
::v-deep .el-tree-node__content {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
::v-deep .is-current > .el-tree-node__content:first-child .el-tree-node__label {
|
||||||
|
color: #4096ff !important;
|
||||||
|
}
|
||||||
|
::v-deep .el-tree-node__content {
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,510 @@
|
||||||
|
<template>
|
||||||
|
<div class="conetentBox">
|
||||||
|
<div class="titleBox flex-row aic jcsb">
|
||||||
|
<div class="flex-row aic">
|
||||||
|
<div class="block"></div>
|
||||||
|
评分详情
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-row jcsb aic userBox">
|
||||||
|
<div>
|
||||||
|
<el-form :inline="true" class="demo-form-inline" size="small">
|
||||||
|
<el-form-item label="人员姓名" class="form-item">
|
||||||
|
<el-select v-model="examineId" placeholder="请选择" @change="userChange" style="width: 300px">
|
||||||
|
<el-option v-for="item in userList" :key="item.id" :label="item.userName" :value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="任务名称" class="form-item">
|
||||||
|
<el-select v-model="examineTaskId" placeholder="请选择" @change="getUserList" style="width: 300px">
|
||||||
|
<el-option v-for="item in taskList" :key="item.id" :label="item.taskName" :value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-row jcsb aic userBox headerBox">
|
||||||
|
<div class="flex-row aic" style="width: 200px">
|
||||||
|
<i class="el-icon-user-solid" style="color: #4096ff; font-size: 24px; margin-right: 5px"></i>{{
|
||||||
|
(userList.find((ele) => ele.id == examineId) || {}).userName}}
|
||||||
|
</div>
|
||||||
|
<div class="totalBox aic">
|
||||||
|
<div>考核评分:</div>
|
||||||
|
<div class="scoreTotal">{{ score }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-tabs v-model="activeName">
|
||||||
|
<el-tab-pane label="组长评估" name="first">
|
||||||
|
<div class="tableBox">
|
||||||
|
<div class="tableRow" v-for="(table, index) in tableData1" :key="index" style="margin-bottom: 20px">
|
||||||
|
<div class="userBox">{{ table[0].reviewCategory }}</div>
|
||||||
|
<el-table :data="table" style="width: 100%">
|
||||||
|
<el-table-column v-for="(header, hIndex) in headers" :key="hIndex" :label="header.label"
|
||||||
|
:prop="header.prop" :width="header.width" :minWidth="header.minWidth">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column class-name="editCell" label="员工自评" prop="score"
|
||||||
|
v-if="examineTask.templateId && table[0].reviewCategory == '发展与协作' && examineTask.templateType != 0"
|
||||||
|
min-width="220">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/300" v-model="scope.row.remark"
|
||||||
|
readonly maxlength="300" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="评分" prop="score" :minWidth="420" class-name="sorceTableCell">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div style="width: 88%; position: relative">
|
||||||
|
<div>
|
||||||
|
<div class="flex-row jcsb" style="
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 90%;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
">
|
||||||
|
<div>0</div>
|
||||||
|
<div v-show="scope.row.score != 10">10</div>
|
||||||
|
</div>
|
||||||
|
<div class="scoreText aic" v-show="scope.row.score != 0" :style="{
|
||||||
|
left: scope.row.score * 9 - 5 + '%',
|
||||||
|
}">
|
||||||
|
<img src="@/assets/task/score.png" :style="{
|
||||||
|
height: '28px',
|
||||||
|
width: '34px',
|
||||||
|
zIndex: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
top: '0',
|
||||||
|
}" alt="" />
|
||||||
|
<div :style="{
|
||||||
|
zIndex: 10,
|
||||||
|
paddingLeft: scope.row.score != 10 ? '13px' : '9px',
|
||||||
|
}">
|
||||||
|
{{ scope.row.score }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-for="item in scope.row.score == 0
|
||||||
|
? 0
|
||||||
|
: scope.row.score - 1" :key="item" class="stepBox" :style="{
|
||||||
|
left: item * 9 + 1.5 + '%',
|
||||||
|
}"></div>
|
||||||
|
<el-slider v-model="scope.row.score" :min="0" :max="10" :disabled="true" style="width: 90%"
|
||||||
|
show-stops show-tooltip></el-slider>
|
||||||
|
</div>
|
||||||
|
<div class="statusText" v-show="scope.row.score == 0">
|
||||||
|
暂未打分
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div class="userBox">总体评价</div>
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/300" v-model="judgeContent"
|
||||||
|
:readonly="true" maxlength="300" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 20px;font-weight: bold;">组长:{{ manageUserName }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="个人自评" name="second">
|
||||||
|
<div class="tableBox">
|
||||||
|
<div class="tableRow" v-for="(table, index) in tableData2" :key="index" style="margin-bottom: 20px">
|
||||||
|
<div class="userBox">{{ table[0].reviewCategory }}</div>
|
||||||
|
<el-table :data="table" style="width: 100%">
|
||||||
|
<el-table-column v-for="(header, hIndex) in headers" :key="hIndex" :label="header.label"
|
||||||
|
:prop="header.prop" :width="header.width" :minWidth="header.minWidth">
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="评分" prop="score" :minWidth="320" class-name="sorceTableCell"
|
||||||
|
v-if="table[0].reviewCategory != '发展与协作'">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div style="width: 88%; position: relative">
|
||||||
|
<div>
|
||||||
|
<div class="flex-row jcsb" style="
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 90%;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
">
|
||||||
|
<div>0</div>
|
||||||
|
<div v-show="scope.row.score != 10">10</div>
|
||||||
|
</div>
|
||||||
|
<div class="scoreText aic" v-show="scope.row.score != 0" :style="{
|
||||||
|
left: scope.row.score * 9 - 5 + '%',
|
||||||
|
}">
|
||||||
|
<img src="@/assets/task/score.png" :style="{
|
||||||
|
height: '28px',
|
||||||
|
width: '34px',
|
||||||
|
zIndex: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
top: '0',
|
||||||
|
}" alt="" />
|
||||||
|
<div :style="{
|
||||||
|
zIndex: 10,
|
||||||
|
paddingLeft: scope.row.score != 10 ? '13px' : '9px',
|
||||||
|
}">
|
||||||
|
{{ scope.row.score }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-for="item in scope.row.score == 0
|
||||||
|
? 0
|
||||||
|
: scope.row.score - 1" :key="item" class="stepBox" :style="{
|
||||||
|
left: item * 9 + 1.5 + '%',
|
||||||
|
}"></div>
|
||||||
|
<el-slider v-model="scope.row.score" :min="0" :max="10" @change="updateScore(scope.row)"
|
||||||
|
:disabled="true" style="width: 90%" show-stops show-tooltip></el-slider>
|
||||||
|
</div>
|
||||||
|
<div class="statusText" v-show="scope.row.score == 0">
|
||||||
|
暂未打分
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="自评总结" prop="score" width="150"
|
||||||
|
v-if="(examineTask.templateId && table[0].reviewCategory == '发展与协作') || !examineTask.templateId">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div>
|
||||||
|
<el-button @click="handleEdit(scope.row)" type="text" size="mini"
|
||||||
|
:class="{ hasEdit: !scope.row.remark }" style="font-weight: 600">{{ scope.row.remark ? "查看" :
|
||||||
|
"暂未评价" }}</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div v-if="examineTask.templateType != 0 && table[0].reviewCategory != '发展与协作'&&examineTask.templateType" style="margin-top: 10px;">
|
||||||
|
<div class="userBox">评价</div>
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/300" v-model="table[0].remarkCate"
|
||||||
|
readonly maxlength="300" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="(examineTask.templateType && examineTask.templateType == 0)||!examineTask.templateType">
|
||||||
|
<div class="userBox">总体评价</div>
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/300" v-model="selfJudgeContent"
|
||||||
|
:readonly="true" maxlength="300" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<el-dialog title="自评总结" :visible.sync="dialogVisible" width="30%">
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/200" v-model="remark" readonly>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible = false">关闭</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
examineTaskId: "",
|
||||||
|
examineId: "",
|
||||||
|
userList: [],
|
||||||
|
dialogVisible: false,
|
||||||
|
remark: "",
|
||||||
|
headers: [
|
||||||
|
{ label: "考核项", prop: "reviewItem", minWidth: 200 },
|
||||||
|
{
|
||||||
|
label: "评分标准",
|
||||||
|
prop: "remarks",
|
||||||
|
minWidth: 300,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// 二维数组,每个子数组代表一个表格的数据
|
||||||
|
tableData1: [],
|
||||||
|
tableData2: [],
|
||||||
|
taskList: [],
|
||||||
|
judgeContent: "",
|
||||||
|
selfJudgeContent: "",
|
||||||
|
score: "",
|
||||||
|
activeName: "first",
|
||||||
|
manageUserName: "",
|
||||||
|
examineTask: {},
|
||||||
|
examineRemark: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleEdit(row) {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.remark = row.remark;
|
||||||
|
},
|
||||||
|
|
||||||
|
getTaskList(first) {
|
||||||
|
taskApi
|
||||||
|
.getTaskList({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100000,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.taskList = res.rows;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.examineTaskId = Number(this.$route.query.taskId);
|
||||||
|
this.getUserList(first);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getUserList(first) {
|
||||||
|
if (!this.examineTaskId) return;
|
||||||
|
taskApi
|
||||||
|
.getTaskUserList({
|
||||||
|
taskId: this.examineTaskId,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100000,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.userList = res.rows;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (first !== 1) this.examineId = this.userList[0].id;
|
||||||
|
else this.examineId = Number(this.$route.query.examineId);
|
||||||
|
|
||||||
|
this.getSocreDetail(0);
|
||||||
|
this.getSocreDetail(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
userChange() {
|
||||||
|
this.getSocreDetail(0);
|
||||||
|
this.getSocreDetail(1);
|
||||||
|
},
|
||||||
|
// 获取评分详情
|
||||||
|
getSocreDetail(type) {
|
||||||
|
let param = {
|
||||||
|
examineTaskId: this.examineTaskId,
|
||||||
|
reviewType: type,
|
||||||
|
examineId: this.examineId,
|
||||||
|
};
|
||||||
|
taskApi.getTaskScoreDetail(param).then((res) => {
|
||||||
|
this.examineRemark = res.data.remark
|
||||||
|
|
||||||
|
let objData = {};
|
||||||
|
res.data.examineConfigDetailVoList.forEach((ele) => {
|
||||||
|
if (!objData[ele.reviewCategory]) objData[ele.reviewCategory] = [];
|
||||||
|
objData[ele.reviewCategory].push(ele);
|
||||||
|
});
|
||||||
|
if (type == 0) this.tableData1 = Object.values(objData);
|
||||||
|
else this.tableData2 = Object.values(objData).map((ele, index) => {
|
||||||
|
ele[0].remarkCate = this.examineRemark.find((item)=>item.reviewCategory==ele[0].reviewCategory)?.remark||''
|
||||||
|
return ele
|
||||||
|
});;
|
||||||
|
this.judgeContent = res.data.examineUser.judgeContent;
|
||||||
|
this.selfJudgeContent = res.data.examineUser.judgeContent;
|
||||||
|
|
||||||
|
|
||||||
|
this.manageUserName = res.data.examineUser.manageUserName;
|
||||||
|
this.examineTask = res.data.examineTask
|
||||||
|
if (res.data.examineUser.score) {
|
||||||
|
this.score = res.data.examineUser.score;
|
||||||
|
} else if (res.data.examineUser.manageScore) {
|
||||||
|
this.score = res.data.examineUser.manageScore;
|
||||||
|
} else {
|
||||||
|
this.score = res.data.examineUser.selfScore;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getTaskList(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.conetentBox {
|
||||||
|
padding: 40px 30px 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 90vh;
|
||||||
|
/* 设置整体高度 */
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userBox {
|
||||||
|
margin: 0 0 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 10px !important;
|
||||||
|
/* width: 95%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway.disabled .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
background-color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__stop {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: linear-gradient(to right, #ffb144, #ff7d00);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreText {
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table th {
|
||||||
|
text-align: left;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .cell {
|
||||||
|
text-align: left;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusText {
|
||||||
|
color: #ff7d00;
|
||||||
|
position: absolute;
|
||||||
|
right: -50px;
|
||||||
|
top: 26px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hasEdit {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-dialog {
|
||||||
|
margin-top: 15% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableBox {
|
||||||
|
height: 75%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableBox ::v-deep .el-table {
|
||||||
|
border-left: 1px solid #eeeeee;
|
||||||
|
border-right: 1px solid #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableRow {
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 0 20px #0000000f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleBox {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerBox {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 4px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: #4096ff;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepBox {
|
||||||
|
position: absolute;
|
||||||
|
top: 33px;
|
||||||
|
height: 14px;
|
||||||
|
width: 3px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.totalBox {
|
||||||
|
width: 180px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreTotal {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #ff7d00;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .sorceTableCell .cell {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table__body .el-table__cell {
|
||||||
|
padding: 20px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table__header .el-table__cell {
|
||||||
|
padding: 14px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-tabs__item.is-active {
|
||||||
|
color: #4096ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-tabs__item {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-tabs__active-bar {
|
||||||
|
height: 3px;
|
||||||
|
width: 32px !important;
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -61,7 +61,7 @@
|
||||||
</el-form>
|
</el-form>
|
||||||
<!-- 底部 -->
|
<!-- 底部 -->
|
||||||
<div class="el-register-footer">
|
<div class="el-register-footer">
|
||||||
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
|
<span>unissense.tech</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item command="handleDataScope" icon="el-icon-circle-check"
|
<el-dropdown-item command="handleDataScope" icon="el-icon-circle-check"
|
||||||
v-hasPermi="['system:role:edit']">数据权限</el-dropdown-item>
|
v-hasPermi="['system:role:edit']">数据权限</el-dropdown-item>
|
||||||
<el-dropdown-item command="handleAuthUser" icon="el-icon-user"
|
<el-dropdown-item command="handleAuthUser" icon="el-icon-s-custom"
|
||||||
v-hasPermi="['system:role:edit']">分配用户</el-dropdown-item>
|
v-hasPermi="['system:role:edit']">分配用户</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
|
|
|
@ -0,0 +1,570 @@
|
||||||
|
<template>
|
||||||
|
<div class="conetentBox">
|
||||||
|
<div class="titleBox flex-row aic jcsb">
|
||||||
|
<div class="flex-row aic">
|
||||||
|
<div class="block"></div>
|
||||||
|
{{ examineTask.taskName }}
|
||||||
|
</div>
|
||||||
|
<div class="flex-row jcfs f1" style="gap: 20px" v-if="isEdit">
|
||||||
|
<el-button type="default" style="width: 90px" @click="saveScoreCheck(0)">保存</el-button>
|
||||||
|
<el-button type="primary" style="width: 90px" @click="saveScoreCheck(1)">提交</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-row jcsb aic userBox headerBox">
|
||||||
|
<div class="flex-row aic" style="width: 200px;">
|
||||||
|
<i class="el-icon-user-solid" style="color: #4096ff; font-size: 24px; margin-right: 5px"></i>{{
|
||||||
|
examineUser.userName }}
|
||||||
|
</div>
|
||||||
|
<div class="totalBox aic" v-if="!isNormal">
|
||||||
|
<div>考核评分:</div>
|
||||||
|
<div class="scoreTotal">{{ saveData.manageScore }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tableBox">
|
||||||
|
<div class="tableRow" v-for="(table, index) in tableData" :key="index" style="margin-bottom: 20px">
|
||||||
|
<div class="userBox">{{ table[0].reviewCategory }}</div>
|
||||||
|
<el-table :data="table" style="width: 100%">
|
||||||
|
<el-table-column v-for="(header, hIndex) in headers" :key="hIndex" :label="header.label" :prop="header.prop"
|
||||||
|
:width="header.width" :minWidth="header.minWidth">
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column class-name="editCell" label="员工自评" prop="score"
|
||||||
|
v-if="!isNormal && examineTask.templateId && table[0].reviewCategory == '发展与协作' && examineTask.templateType != 0"
|
||||||
|
min-width="320">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/300" v-model="scope.row.remark"
|
||||||
|
readonly maxlength="300" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="评分" prop="score"
|
||||||
|
:minWidth="400" class-name="sorceTableCell"
|
||||||
|
v-if="(isNormal && table[0].reviewCategory != '发展与协作') || !isNormal">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div style="width: 88%; position: relative">
|
||||||
|
<div>
|
||||||
|
<div class="flex-row jcsb" style="
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 90%;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
">
|
||||||
|
<div>0</div>
|
||||||
|
<div v-show="scope.row.score != 10">10</div>
|
||||||
|
</div>
|
||||||
|
<div class="scoreText aic" v-show="scope.row.score != 0" :style="{
|
||||||
|
left: scope.row.score * 9 - 5 + '%',
|
||||||
|
}">
|
||||||
|
<img src="@/assets/task/score.png" :style="{
|
||||||
|
height: '28px',
|
||||||
|
width: '34px',
|
||||||
|
zIndex: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
top: '0',
|
||||||
|
}" alt="" />
|
||||||
|
<div :style="{
|
||||||
|
zIndex: 10,
|
||||||
|
paddingLeft: scope.row.score != 10 ? '13px' : '9px',
|
||||||
|
}">
|
||||||
|
{{ scope.row.score }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-for="item in scope.row.score == 0
|
||||||
|
? 0
|
||||||
|
: scope.row.score - 1" :key="item" class="stepBox" :style="{
|
||||||
|
left: item * 9 + 1.5 + '%',
|
||||||
|
}"></div>
|
||||||
|
<el-slider v-model="scope.row.score" :min="0" :max="10" @change="updateScore(scope.row)"
|
||||||
|
:disabled="!isEdit" style="width: 90%" show-stops show-tooltip></el-slider>
|
||||||
|
</div>
|
||||||
|
<div class="statusText" v-show="scope.row.score == 0">
|
||||||
|
暂未打分
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column class-name="editCell" label="自评总结" prop="score"
|
||||||
|
v-if="(isNormal && examineTask.templateId && table[0].reviewCategory == '发展与协作') || (isNormal && !examineTask.templateId)"
|
||||||
|
minWidth="140">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div>
|
||||||
|
<el-button v-if="isEdit" @click="handleEdit(scope.row)" type="text" size="mini"
|
||||||
|
:class="{ hasEdit: !scope.row.remark }" style="font-weight: 600">{{ scope.row.remark ? "查看" : "暂未评价"
|
||||||
|
}}
|
||||||
|
<i style="color: #4096ff; font-size: 14px" class="el-icon-edit el-icon--right"></i></el-button>
|
||||||
|
<el-button v-if="!isEdit" @click="handleEdit(scope.row)" type="text" size="mini"
|
||||||
|
:class="{ hasEdit: !scope.row.remark }" style="font-weight: 600">{{ scope.row.remark ? "查看" : "暂未评价"
|
||||||
|
}}</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div v-if="examineTask.templateType != 0 && isNormal && table[0].reviewCategory != '发展与协作'"
|
||||||
|
style="margin-top: 10px;">
|
||||||
|
<div class="userBox">评价</div>
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/300" v-model="table[0].remarkCate"
|
||||||
|
:readonly="!isEdit" maxlength="300" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div v-if="(isNormal && examineTask.templateType == 0) || (!isNormal)">
|
||||||
|
<div class="userBox">总体评价</div>
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/300" v-model="saveData.judgeContent"
|
||||||
|
:readonly="!isEdit" maxlength="300" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog title="自评总结" :visible.sync="dialogVisible" width="30%">
|
||||||
|
<div>
|
||||||
|
<el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/200" v-model="remark" :readonly="!isEdit"
|
||||||
|
maxlength="200" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="cancelEdit">{{
|
||||||
|
isEdit ? "取 消" : "关闭"
|
||||||
|
}}</el-button>
|
||||||
|
<el-button type="primary" @click="saveEdit" v-if="isEdit">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userId: "",
|
||||||
|
taskId: "",
|
||||||
|
isNormal: false,
|
||||||
|
dialogVisible: false,
|
||||||
|
selectRow: false,
|
||||||
|
saveStatus: "",
|
||||||
|
remark: "",
|
||||||
|
isEdit: "",
|
||||||
|
headers: [
|
||||||
|
{ label: "考核项", prop: "reviewItem", minWidth: 150 },
|
||||||
|
{
|
||||||
|
label: "评分标准",
|
||||||
|
prop: "remarks",
|
||||||
|
minWidth:300
|
||||||
|
// width: '25%',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// 二维数组,每个子数组代表一个表格的数据
|
||||||
|
tableData: [
|
||||||
|
// 可以根据需要添加更多表格数据
|
||||||
|
],
|
||||||
|
// 获取评分的参数
|
||||||
|
examineTaskId: "",
|
||||||
|
examineId: "",
|
||||||
|
reviewType: "",
|
||||||
|
reviewType: "",
|
||||||
|
// 保存评分的参数
|
||||||
|
saveData: {
|
||||||
|
examineId: "",
|
||||||
|
examineStatus: "",
|
||||||
|
examineStatusSelf: "",
|
||||||
|
manageScore: "",
|
||||||
|
taskId: "",
|
||||||
|
judgeContent: "",
|
||||||
|
examineDetailList: [],
|
||||||
|
},
|
||||||
|
examineUser: {},
|
||||||
|
examineTask: {},
|
||||||
|
examineRemark: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateScore(row) {
|
||||||
|
// 实时计算组长评分数
|
||||||
|
if (!this.isNormal)
|
||||||
|
this.saveData.manageScore =
|
||||||
|
this.tableData
|
||||||
|
.flat()
|
||||||
|
.reduce((total, ele) => (ele.score || 0) * ele.weight + total, 0) /
|
||||||
|
10;
|
||||||
|
},
|
||||||
|
// 获取评分详情
|
||||||
|
getSocreDetail() {
|
||||||
|
let param = {
|
||||||
|
examineTaskId: this.examineTaskId,
|
||||||
|
reviewType: this.reviewType,
|
||||||
|
userId: this.userId,
|
||||||
|
};
|
||||||
|
|
||||||
|
param.examineId = this.examineId;
|
||||||
|
taskApi.getTaskScoreDetail(param).then((res) => {
|
||||||
|
let objData = {};
|
||||||
|
this.examineRemark = res.data.remark;
|
||||||
|
res.data.examineConfigDetailVoList.forEach((ele, index) => {
|
||||||
|
if (!objData[ele.reviewCategory]) objData[ele.reviewCategory] = [];
|
||||||
|
objData[ele.reviewCategory].push(ele);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tableData = Object.values(objData).map((ele, index) => {
|
||||||
|
ele[0].remarkCate = this.examineRemark.find((item)=>item.reviewCategory==ele[0].reviewCategory)?.remark||''
|
||||||
|
return ele
|
||||||
|
});
|
||||||
|
if (!this.examineId) {
|
||||||
|
} else {
|
||||||
|
this.saveData.judgeContent = res.data.examineUser.judgeContent || "";
|
||||||
|
this.saveData.manageScore = res.data.examineUser.manageScore || "";
|
||||||
|
}
|
||||||
|
this.examineId = res.data.examineUser.id;
|
||||||
|
this.examineTask = res.data.examineTask;
|
||||||
|
this.examineUser = res.data.examineUser;
|
||||||
|
if (this.examineTask.templateType == 0) {
|
||||||
|
this.saveData.judgeContent = res.data.examineUser.selfJudgeContent
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
res.data.examineUser.examineStatusSelf == 1 &&
|
||||||
|
res.data.examineUser.examineStatus == 1
|
||||||
|
)
|
||||||
|
this.isEdit = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleEdit(row) {
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.selectRow = row;
|
||||||
|
this.remark = this.selectRow.remark;
|
||||||
|
},
|
||||||
|
saveEdit() {
|
||||||
|
if (this.remark.length > 200) {
|
||||||
|
this.$message({
|
||||||
|
message: "自评总结限制200个字符",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.selectRow.remark = this.remark;
|
||||||
|
},
|
||||||
|
cancelEdit() {
|
||||||
|
this.dialogVisible = false;
|
||||||
|
},
|
||||||
|
saveDataSet(status) {
|
||||||
|
if (!this.isNormal) {
|
||||||
|
this.saveData.examineStatus = status;
|
||||||
|
} else {
|
||||||
|
this.saveData.examineStatusSelf = status;
|
||||||
|
}
|
||||||
|
this.saveData.examineDetailList = this.tableData.flat().map((ele) => ({
|
||||||
|
score: ele.score,
|
||||||
|
configId: ele.id,
|
||||||
|
remark: ele.remark,
|
||||||
|
reviewCategory: ele.reviewCategory,
|
||||||
|
}));
|
||||||
|
if (this.examineTask.templateType != 0 && this.isNormal) {
|
||||||
|
this.saveData.examineRemarkList = this.tableData.filter((ele) => ele[0].reviewCategory != '发展与协作').map((ele) => ({ reviewCategory: ele[0].reviewCategory, remark: ele[0].remarkCate }))
|
||||||
|
} else {
|
||||||
|
this.saveData.examineRemarkList = []
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveData.taskId = this.examineTaskId;
|
||||||
|
this.saveData.examineId = this.examineId;
|
||||||
|
},
|
||||||
|
saveScoreCheck(status) {
|
||||||
|
// 组装保存数据
|
||||||
|
this.saveDataSet(status);
|
||||||
|
|
||||||
|
// 保存
|
||||||
|
if (status == 0) {
|
||||||
|
if (this.isNormal && this.examineTask.templateType == 0) {
|
||||||
|
this.saveData.selfJudgeContent = this.saveData.judgeContent
|
||||||
|
this.saveData.judgeContent = ''
|
||||||
|
}
|
||||||
|
this.saveScore();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 提交
|
||||||
|
if (this.saveData.examineDetailList.filter((ele) => !ele.score && ele.reviewCategory != '发展与协作' || (!ele.score && !this.isNormal)).length) {
|
||||||
|
this.$alert("存在未评分绩效项,请完善后再试", "提交失败", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
this.saveData.examineDetailList.filter((ele) => !ele.remark && ele.reviewCategory == '发展与协作').length &&
|
||||||
|
this.isNormal &&
|
||||||
|
status
|
||||||
|
) {
|
||||||
|
this.$alert("发展与协作下的自评总结为必填,请完善后再试", "提交失败", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
this.saveData.examineDetailList.filter((ele) => ele.remark.length < 100 && ele.reviewCategory == '发展与协作').length &&
|
||||||
|
this.isNormal &&
|
||||||
|
status
|
||||||
|
) {
|
||||||
|
this.$alert("发展与协作下的自评总结最少100个字符,请完善后再试", "提交失败", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
} else if (this.saveData.judgeContent.length > 300 && !this.isNormal && this.examineTask.templateType == '0') {
|
||||||
|
this.$message({
|
||||||
|
message: "总体评价限制300个字符",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
} else if (!this.saveData.judgeContent.length && !this.isNormal) {
|
||||||
|
this.$message({
|
||||||
|
message: "总体评价为必填",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
} else if (!this.saveData.judgeContent.length && this.isNormal && this.examineTask.templateType == 0) {
|
||||||
|
this.$message({
|
||||||
|
message: "个人总体评价为必填",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
} else if (this.saveData.examineRemarkList.filter((ele) => !ele.remark).length && this.isNormal && this.examineTask.templateType != 0 && this.isNormal) {
|
||||||
|
this.$message({
|
||||||
|
message: "存在未填写大类评价,请完善后再试",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
} else if (this.saveData.examineRemarkList.filter((ele) => ele.remark.length < 100).length && this.isNormal && this.examineTask.templateType != 0 && this.isNormal) {
|
||||||
|
this.$message({
|
||||||
|
message: "大类评价最少100个字符,请完善后再试",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (status) {
|
||||||
|
this.$confirm(
|
||||||
|
"提交后将无法修改,该操作不可逆,请确认后再试",
|
||||||
|
"确认提交绩效评分",
|
||||||
|
{
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
if (this.isNormal && this.examineTask.templateType == 0) {
|
||||||
|
this.saveData.selfJudgeContent = this.saveData.judgeContent
|
||||||
|
this.saveData.judgeContent = ''
|
||||||
|
}
|
||||||
|
this.saveScore();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (this.isNormal && this.examineTask.templateType == 0) {
|
||||||
|
this.saveData.selfJudgeContent = this.saveData.judgeContent
|
||||||
|
this.saveData.judgeContent = ''
|
||||||
|
}
|
||||||
|
this.saveScore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
saveScore() {
|
||||||
|
taskApi.saveTaskUserScore(this.saveData).then((res) => {
|
||||||
|
this.$message({
|
||||||
|
message: "操作成功",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
this.$router.go(-1);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getRouteData() {
|
||||||
|
this.isNormal = this.$route.query.isNormal || "";
|
||||||
|
this.examineTaskId = this.$route.query.examineTaskId;
|
||||||
|
this.examineId = this.$route.query.examineId;
|
||||||
|
this.reviewType = this.$route.query.reviewType;
|
||||||
|
this.saveData.reviewType = this.$route.query.reviewType;
|
||||||
|
this.isEdit = this.$route.query.edit == 1 ? true : false;
|
||||||
|
this.userId = this.$store.state.user.id;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getRouteData();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getSocreDetail();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.conetentBox {
|
||||||
|
padding: 40px 30px 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 90vh;
|
||||||
|
/* 设置整体高度 */
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userBox {
|
||||||
|
margin: 0 0 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 10px !important;
|
||||||
|
/* width: 95%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway.disabled .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
background-color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__stop {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: linear-gradient(to right, #ffb144, #ff7d00);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreText {
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table th {
|
||||||
|
text-align: left;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .cell {
|
||||||
|
text-align: left;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusText {
|
||||||
|
color: #ff7d00;
|
||||||
|
position: absolute;
|
||||||
|
right: -50px;
|
||||||
|
top: 26px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hasEdit {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-dialog {
|
||||||
|
margin-top: 15% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableBox {
|
||||||
|
height: 75%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableBox ::v-deep .el-table {
|
||||||
|
border-left: 1px solid #eeeeee;
|
||||||
|
border-right: 1px solid #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableRow {
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 0 20px #0000000f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleBox {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerBox {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 4px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: #4096ff;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepBox {
|
||||||
|
position: absolute;
|
||||||
|
top: 33px;
|
||||||
|
height: 14px;
|
||||||
|
width: 3px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.totalBox {
|
||||||
|
width: 180px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreTotal {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #ff7d00;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table__body .sorceTableCell .cell {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .sorceTableCell.el-table__cell {
|
||||||
|
padding-left: 10% !important;
|
||||||
|
/* padding-right: 10px !important; */
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table__body .el-table__cell {
|
||||||
|
padding: 20px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table__header .el-table__cell {
|
||||||
|
padding: 14px 30px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table__header .el-table__cell .cell {
|
||||||
|
padding-left: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .editCell {
|
||||||
|
padding-right: 20px !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,227 @@
|
||||||
|
<template>
|
||||||
|
<div class="appraisal-manager">
|
||||||
|
<el-tabs v-model="activeName">
|
||||||
|
<el-tab-pane label="进行中" name="进行中">
|
||||||
|
<div class="assessment-container flex-row">
|
||||||
|
<div v-for="item in taskList['0']" :key="item.id" class="taskBox">
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="cardBox flex-col">
|
||||||
|
<img
|
||||||
|
src="@/assets/task/titleIcon.png"
|
||||||
|
alt=""
|
||||||
|
style="width: 32px; height: 34px"
|
||||||
|
/>
|
||||||
|
<div class="flex-row aic nameBox">
|
||||||
|
<div>{{ item.taskName }}</div>
|
||||||
|
<el-tag type="warning" size="mini">进行中</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="timeBox">
|
||||||
|
截止时间:{{ item.endTime.split(" ")[0] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-actions aic">
|
||||||
|
<div class="peopleNumber">
|
||||||
|
考核人数:{{ item.peopleNumber }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="action-buttons aic"
|
||||||
|
@click="viewDetails(item, 1)"
|
||||||
|
:class="{ waitBtn: !item.taskEditFlag }"
|
||||||
|
>
|
||||||
|
考核评分
|
||||||
|
<img
|
||||||
|
src="@/assets/task/right.png"
|
||||||
|
alt=""
|
||||||
|
style="width: 16px; height: 16px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="!taskList['0']" description="暂无数据"></el-empty>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="已过期" name="已过期">
|
||||||
|
<div class="assessment-container flex-row">
|
||||||
|
<div v-for="item in taskList['2']" :key="item.id" class="taskBox">
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="cardBox flex-col">
|
||||||
|
<img
|
||||||
|
src="@/assets/task/titleIcon.png"
|
||||||
|
alt=""
|
||||||
|
style="width: 32px; height: 34px"
|
||||||
|
/>
|
||||||
|
<div class="flex-row aic nameBox">
|
||||||
|
<div>{{ item.taskName }}</div>
|
||||||
|
<el-tag type="info" size="mini">已过期</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="timeBox">
|
||||||
|
截止时间:{{ item.endTime.split(" ")[0] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-actions aic">
|
||||||
|
<div class="peopleNumber">
|
||||||
|
考核人数:{{ item.peopleNumber }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="action-buttons aic"
|
||||||
|
@click="viewDetails(item, 0)"
|
||||||
|
:class="{ waitBtn: !item.taskEditFlag }"
|
||||||
|
>
|
||||||
|
查看详情
|
||||||
|
<img
|
||||||
|
src="@/assets/task/right.png"
|
||||||
|
alt=""
|
||||||
|
style="width: 16px; height: 16px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="!taskList['2']" description="暂无数据"></el-empty>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "AppraisalManager",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeName: "进行中",
|
||||||
|
taskList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getTaks() {
|
||||||
|
taskApi.getTaskListSelf().then((res) => {
|
||||||
|
this.taskList = res.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
viewDetails(row, isEdit) {
|
||||||
|
if (!row.taskEditFlag) {
|
||||||
|
this.$message({
|
||||||
|
message: "分数正在计算中,请等待计算完成",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 查看考核详情
|
||||||
|
this.$router.push({
|
||||||
|
path: "/workAppraisal/managerUser",
|
||||||
|
query: { taskId: row.id, isEdit },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getTaks();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.appraisal-manager {
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
height: calc(100vh - 100px); /* 设置整体高度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.assessment-container {
|
||||||
|
max-height: 650px; /* 减去标题高度 */
|
||||||
|
overflow-y: auto; /* 允许垂直滚动 */
|
||||||
|
gap: 2%;
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.taskBox {
|
||||||
|
width: 23%;
|
||||||
|
height: 200px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
padding: 20px 0 0 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.cardBox {
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between; /* 两端对齐 */
|
||||||
|
align-items: center; /* 垂直居中 */
|
||||||
|
height: 44px;
|
||||||
|
background-color: #f7faff;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.peopleNumber {
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-weight: bold; /* 状态文本加粗 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px; /* 按钮之间的间距 */
|
||||||
|
color: #4096ff;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.statusText {
|
||||||
|
font-size: 26px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.timeBox {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999999;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
::v-deep .el-tabs__item.is-active {
|
||||||
|
color: #4096ff;
|
||||||
|
}
|
||||||
|
::v-deep .el-tabs__item {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
::v-deep .el-tabs__active-bar {
|
||||||
|
height: 3px;
|
||||||
|
width: 32px !important;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
.nameBox {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
::v-deep .el-tag--warning {
|
||||||
|
color: #ea741e;
|
||||||
|
}
|
||||||
|
.waitBtn {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,320 @@
|
||||||
|
<template>
|
||||||
|
<div class="project-list">
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form
|
||||||
|
:inline="true"
|
||||||
|
:model="searchForm"
|
||||||
|
class="demo-form-inline"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-form-item label="考核人员" class="form-item">
|
||||||
|
<el-input
|
||||||
|
v-model="searchForm.userName"
|
||||||
|
placeholder="考核人员"
|
||||||
|
readonly
|
||||||
|
@click.native="openUserSelectDialog"
|
||||||
|
style="width: 300px"
|
||||||
|
><el-button slot="append" icon="el-icon-s-custom"></el-button
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" class="form-item">
|
||||||
|
<el-select
|
||||||
|
v-model="searchForm.examineStatus"
|
||||||
|
placeholder="状态"
|
||||||
|
clearable
|
||||||
|
style="width: 300px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in statusList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="search-buttons">
|
||||||
|
<el-button type="primary" @click="onSearch">查询</el-button>
|
||||||
|
<el-button @click="onReset">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="f1 df">
|
||||||
|
<CustomTable
|
||||||
|
:columns="columns"
|
||||||
|
:tableData="tableData"
|
||||||
|
:total="total"
|
||||||
|
:show-selection="false"
|
||||||
|
:show-index="true"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
@sortChange="sortChange"
|
||||||
|
tableHeight="495px"
|
||||||
|
>
|
||||||
|
<template slot="operation" slot-scope="{ row }">
|
||||||
|
<div class="operation-buttons">
|
||||||
|
<el-button
|
||||||
|
v-if="isEdit == 1 && row.examineStatus == '0'"
|
||||||
|
@click="handleEdit(row, 1)"
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
>去评分</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-if="row.examineStatus == '1' || isEdit == 0"
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
@click="handleEdit(row, 0)"
|
||||||
|
>查看详情</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</CustomTable>
|
||||||
|
</div>
|
||||||
|
<SelectUser
|
||||||
|
:dialogVisible="userSelectDialogVisible"
|
||||||
|
:currentSelectedUser="currentSelectedUser"
|
||||||
|
:showSelection="true"
|
||||||
|
:highligt="false"
|
||||||
|
@confirm="handleUserConfirm"
|
||||||
|
@close="handleUserClose"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CustomTable from "@/components/CustomTable.vue";
|
||||||
|
import SelectUser from "@/components/SelectUser.vue";
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CustomTable,
|
||||||
|
SelectUser,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
searchForm: {
|
||||||
|
userIdList: [],
|
||||||
|
userName: "",
|
||||||
|
examineStatus: "",
|
||||||
|
},
|
||||||
|
taskId: "",
|
||||||
|
isEdit: "",
|
||||||
|
columns: [
|
||||||
|
{ prop: "userName", label: "考核人员" },
|
||||||
|
{ prop: "manageScore", label: "考核评分", sortable: "custom" },
|
||||||
|
{
|
||||||
|
prop: "examineStatus",
|
||||||
|
label: "状态",
|
||||||
|
type: "status",
|
||||||
|
callback: (value) => {
|
||||||
|
if (value == 0) var color = "#EA741D";
|
||||||
|
else var color = "#999";
|
||||||
|
|
||||||
|
return `<span style="color: ${color}">${
|
||||||
|
value == 0 ? "待评分" : "已完成"
|
||||||
|
}</span>`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "operation",
|
||||||
|
label: "操作",
|
||||||
|
width: "250",
|
||||||
|
className: "operation-column",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tableData: [],
|
||||||
|
total: 0,
|
||||||
|
userSelectDialogVisible: false,
|
||||||
|
currentSelectedUser: [],
|
||||||
|
pageNum: 1, // 当前页码
|
||||||
|
pageSize: 10, // 每页条数
|
||||||
|
statusList: [
|
||||||
|
{ label: "全部", value: "" },
|
||||||
|
{ label: "待评分", value: "0" },
|
||||||
|
{ label: "已完成", value: "1" },
|
||||||
|
],
|
||||||
|
isAsc: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSearch() {
|
||||||
|
this.taskUserList();
|
||||||
|
},
|
||||||
|
onReset() {
|
||||||
|
Object.keys(this.searchForm).forEach((key) => {
|
||||||
|
this.searchForm[key] = "";
|
||||||
|
});
|
||||||
|
this.currentSelectedUser = [];
|
||||||
|
this.taskUserList();
|
||||||
|
},
|
||||||
|
handleEdit(row, edit) {
|
||||||
|
this.$router.push({
|
||||||
|
path: "/workAppraisal/detail",
|
||||||
|
query: {
|
||||||
|
edit,
|
||||||
|
examineTaskId: this.taskId,
|
||||||
|
examineId: row.id,
|
||||||
|
reviewType: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
taskUserList() {
|
||||||
|
taskApi
|
||||||
|
.getTaskUserList({
|
||||||
|
...this.searchForm,
|
||||||
|
taskId: this.taskId,
|
||||||
|
pageNum: this.pageNum,
|
||||||
|
pageSize: this.pageSize,
|
||||||
|
isAsc: this.isAsc,
|
||||||
|
sortFiled: "manageScore",
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.tableData = res.rows;
|
||||||
|
this.total = res.total;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleSizeChange(size) {
|
||||||
|
this.pageSize = size;
|
||||||
|
this.pageNum = 1; // 重置为第一页
|
||||||
|
this.taskUserList();
|
||||||
|
},
|
||||||
|
handleCurrentChange(page) {
|
||||||
|
this.pageNum = page;
|
||||||
|
this.taskUserList();
|
||||||
|
},
|
||||||
|
openUserSelectDialog() {
|
||||||
|
this.userSelectDialogVisible = true;
|
||||||
|
},
|
||||||
|
handleUserConfirm(data) {
|
||||||
|
this.searchForm.userName = data.map((ele) => ele.nickName).join(",");
|
||||||
|
this.searchForm.userIdList = data.map((ele) => ele.userId);
|
||||||
|
},
|
||||||
|
handleUserClose() {
|
||||||
|
this.userSelectDialogVisible = false;
|
||||||
|
},
|
||||||
|
sortChange({ order }) {
|
||||||
|
this.isAsc =
|
||||||
|
order == "descending" ? "desc" : order == "ascending" ? "asc" : "";
|
||||||
|
this.taskUserList();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.taskId = this.$route.query.taskId;
|
||||||
|
this.isEdit = this.$route.query.isEdit;
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.taskUserList();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.project-list {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: white;
|
||||||
|
height: 88vh;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline {
|
||||||
|
// display: flex;
|
||||||
|
// flex-wrap: nowrap;
|
||||||
|
// align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline .el-form-item {
|
||||||
|
// margin-right: 50px; /* 将间距设置为 30px */
|
||||||
|
// margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline .el-form-item:last-child {
|
||||||
|
margin-right: 0; /* 移除最后一个元素的右边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item ::v-deep .el-form-item__content {
|
||||||
|
// width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item ::v-deep .el-input,
|
||||||
|
.form-item ::v-deep .el-select {
|
||||||
|
// width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-buttons {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-column {
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: -2px 0 5px rgba(241, 112, 6, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button.is-text {
|
||||||
|
min-width: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer .el-button {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #e6a23c;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加以下样式来使对话框垂直居中 */
|
||||||
|
::v-deep .delete-dialog.el-dialog {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
::v-deep .el-table th {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .cell {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
::v-deep .operation-buttons .el-button {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0 2px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.search-buttons ::v-deep .el-button {
|
||||||
|
width: 90px !important;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
.waitBtn {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,234 @@
|
||||||
|
<template>
|
||||||
|
<div class="appraisal-manager">
|
||||||
|
<el-tabs v-model="activeName">
|
||||||
|
<el-tab-pane label="进行中" name="进行中">
|
||||||
|
<div class="assessment-container flex-row">
|
||||||
|
<div v-for="item in taskList['0']" :key="item.id" class="taskBox">
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="cardBox flex-col">
|
||||||
|
<img
|
||||||
|
src="@/assets/task/titleIcon.png"
|
||||||
|
alt=""
|
||||||
|
style="width: 32px; height: 34px"
|
||||||
|
/>
|
||||||
|
<div class="flex-row aic nameBox">
|
||||||
|
<div>{{ item.taskName }}</div>
|
||||||
|
<el-tag type="warning" size="mini">进行中</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="timeBox">
|
||||||
|
截止时间:{{ item.endTime.split(" ")[0] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-actions aic">
|
||||||
|
<div class="peopleNumber">
|
||||||
|
<!-- 考核人数:{{ item.peopleNumber }} -->
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="action-buttons aic"
|
||||||
|
@click="viewDetails(item, item.examineStatusSelf == 1 ?0: 1)"
|
||||||
|
:class="{ waitBtn: !item.taskEditFlag }"
|
||||||
|
>
|
||||||
|
{{ item.examineStatusSelf == 1 ? "查看详情" : "考核评分" }}
|
||||||
|
<img
|
||||||
|
src="@/assets/task/right.png"
|
||||||
|
alt=""
|
||||||
|
style="width: 16px; height: 16px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="!taskList['0']" description="暂无数据"></el-empty
|
||||||
|
></el-tab-pane>
|
||||||
|
<el-tab-pane label="已过期" name="已过期">
|
||||||
|
<div class="assessment-container flex-row">
|
||||||
|
<div v-for="item in taskList['2']" :key="item.id" class="taskBox">
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="cardBox flex-col">
|
||||||
|
<img
|
||||||
|
src="@/assets/task/titleIcon.png"
|
||||||
|
alt=""
|
||||||
|
style="width: 32px; height: 34px"
|
||||||
|
/>
|
||||||
|
<div class="flex-row aic nameBox">
|
||||||
|
<div>{{ item.taskName }}</div>
|
||||||
|
<el-tag type="info" size="mini">已过期</el-tag>
|
||||||
|
</div>
|
||||||
|
<div class="timeBox">
|
||||||
|
截止时间:{{ item.endTime.split(" ")[0] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-actions aic">
|
||||||
|
<div class="peopleNumber">
|
||||||
|
<!-- 考核人数:{{ item.peopleNumber }} -->
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="action-buttons aic"
|
||||||
|
@click="viewDetails(item, 0)"
|
||||||
|
:class="{ waitBtn: item.taskEditFlag }"
|
||||||
|
>
|
||||||
|
查看详情
|
||||||
|
<img
|
||||||
|
src="@/assets/task/right.png"
|
||||||
|
alt=""
|
||||||
|
style="width: 16px; height: 16px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="!taskList['2']" description="暂无数据"></el-empty>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "NormalWorker",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeName: "进行中",
|
||||||
|
taskList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getTaks() {
|
||||||
|
taskApi.getTaskListSelfNormal().then((res) => {
|
||||||
|
this.taskList = res.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
viewDetails(item, edit) {
|
||||||
|
if (!item.taskEditFlag) {
|
||||||
|
this.$message({
|
||||||
|
message: "分数正在计算中,请等待计算完成",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 查看考核详情
|
||||||
|
this.$router.push({
|
||||||
|
path: "/workAppraisal/detail",
|
||||||
|
query: {
|
||||||
|
edit,
|
||||||
|
isNormal: true,
|
||||||
|
examineTaskId: item.id,
|
||||||
|
reviewType: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
console.log(123);
|
||||||
|
|
||||||
|
this.getTaks();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.appraisal-manager {
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
height: calc(100vh - 100px); /* 设置整体高度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.assessment-container {
|
||||||
|
max-height: 650px; /* 减去标题高度 */
|
||||||
|
overflow-y: auto; /* 允许垂直滚动 */
|
||||||
|
gap: 2%;
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.taskBox {
|
||||||
|
width: 23%;
|
||||||
|
height: 200px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
padding: 20px 0 0 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.cardBox {
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between; /* 两端对齐 */
|
||||||
|
align-items: center; /* 垂直居中 */
|
||||||
|
height: 44px;
|
||||||
|
background-color: #f7faff;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.peopleNumber {
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-weight: bold; /* 状态文本加粗 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px; /* 按钮之间的间距 */
|
||||||
|
color: #4096ff;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.statusText {
|
||||||
|
font-size: 26px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.timeBox {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999999;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
::v-deep .el-tabs__item.is-active {
|
||||||
|
color: #4096ff;
|
||||||
|
}
|
||||||
|
::v-deep .el-tabs__item {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
::v-deep .el-tabs__active-bar {
|
||||||
|
height: 3px;
|
||||||
|
width: 32px !important;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
.nameBox {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
::v-deep .el-tag--warning {
|
||||||
|
color: #ea741e;
|
||||||
|
}
|
||||||
|
.waitBtn {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,493 @@
|
||||||
|
<template>
|
||||||
|
<div class="appraisal-manager ">
|
||||||
|
|
||||||
|
<div class="flex-row aic" style="gap: 20px;margin-bottom: 20px;">
|
||||||
|
<div>看板名称</div>
|
||||||
|
<div>
|
||||||
|
<el-input v-model="moduleName" class="filter-input" readonly>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
<div>看板类型</div>
|
||||||
|
|
||||||
|
<el-select v-model="moduleType" placeholder="看板类型" clearable style="width: 200px" readonly disabled>
|
||||||
|
<el-option label="年度考核" value="0" />
|
||||||
|
<el-option label="季度考核" value="1" />
|
||||||
|
<el-option label="年度考核" value="2" />
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal">
|
||||||
|
<div class="left">
|
||||||
|
<div class="setText" style="font-weight: 600">累计权重</div>
|
||||||
|
<el-collapse v-model="letfValue" :accordion="true" style="height: 300px; overflow: auto"
|
||||||
|
@change="showAllScoure">
|
||||||
|
<el-collapse-item v-for="(item, index) in scoreList" :key="index" :name="item.title">
|
||||||
|
<template #title>
|
||||||
|
<div class="jcsb flex-row contentTitle">
|
||||||
|
<span class="setTitle">{{ item.title }}</span>
|
||||||
|
<span class="statusText">{{ item.weight }}%</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<div v-for="(ele, index) in item.list" :key="index" class="flex-row jcsb leftSub" :class="{
|
||||||
|
selectClass: selectLeftRow == ele.title + ele.type,
|
||||||
|
}" @click="selectLeft(ele)">
|
||||||
|
<div>{{ ele.title }}</div>
|
||||||
|
<div class="statusText">{{ ele.weight }}%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
<div class="flex-row jcsb" style="margin-top: 20px; padding-right: 15px">
|
||||||
|
<div class="setTitle" style="font-weight: 600">总计</div>
|
||||||
|
<div class="statusText">
|
||||||
|
{{
|
||||||
|
scoreList.reduce((total, ele) => total + (ele.weight || 0), 0)
|
||||||
|
}}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div v-show="leftType !== '组长评估绩效指标' && leftType !== '个人自评绩效指标'">
|
||||||
|
<div class="flex-row jcsb setHeader">
|
||||||
|
<div style="width: 15%; font-weight: 600">考核项</div>
|
||||||
|
<div style="width: 50%; font-weight: 600;text-align: center;">评分标准</div>
|
||||||
|
<div class="center" style="width: 25%; font-weight: 600">
|
||||||
|
权重占比
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="(item, index) in (
|
||||||
|
(
|
||||||
|
(scoreList.find((ele) => ele.title == letfValue) || {})
|
||||||
|
.list || []
|
||||||
|
).find((ele) => ele.title + ele.type == selectLeftRow) || {}
|
||||||
|
).rightArr || []" :key="index" class="flex-row jcsb aic contentRow">
|
||||||
|
<div style="width: 15%; font-weight: 500">
|
||||||
|
{{ item.reviewItem }}
|
||||||
|
</div>
|
||||||
|
<div class="center" style="width: 50%;padding: 0 20px;">
|
||||||
|
{{ item.remarks }}
|
||||||
|
</div>
|
||||||
|
<div class="center" style="width: 25%">
|
||||||
|
<div class="flex-row jcsb" style="
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 100%;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
">
|
||||||
|
<div>0</div>
|
||||||
|
<div v-show="item.weight != 20">20</div>
|
||||||
|
</div>
|
||||||
|
<div class="scoreText aic" v-show="item.weight != 0" :style="{
|
||||||
|
left: item.weight * 4.5 - 2.5 + '%',
|
||||||
|
}">
|
||||||
|
<img src="@/assets/task/score.png" :style="{
|
||||||
|
height: '28px',
|
||||||
|
width: '34px',
|
||||||
|
zIndex: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
top: '-2px',
|
||||||
|
}" alt="" />
|
||||||
|
<div :style="{
|
||||||
|
zIndex: 10,
|
||||||
|
textIndent: item.weight < 10 ? '13px' : '10px',
|
||||||
|
fontSize: '12px',
|
||||||
|
}">
|
||||||
|
{{ item.weight }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="flex-row jcsb scoreBox" style="margin-left: 15px">
|
||||||
|
<div>0%</div>
|
||||||
|
<div class="scoreText">{{ item.weight }}%</div>
|
||||||
|
<div>20%</div>
|
||||||
|
</div> -->
|
||||||
|
<div v-for="item in item.weight == 0 ? 0 : item.weight - 1" :key="item" class="stepBox"
|
||||||
|
:style="{
|
||||||
|
left: item * 5 + 4 + '%',
|
||||||
|
}"></div>
|
||||||
|
<el-slider :disabled="isDisabled" v-model="item.weight" :max="20"
|
||||||
|
@change="changeTotal"></el-slider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-show="leftType == '组长评估绩效指标' || leftType == '个人自评绩效指标'">
|
||||||
|
<div v-for="(ele, index) in
|
||||||
|
(scoreList.find((ele) => ele.title == leftType) || {})
|
||||||
|
.list || []
|
||||||
|
|
||||||
|
" :key="index">
|
||||||
|
<div style="margin: 10px;font-weight: 600;font-size: 18px;">{{ ele.title }}</div>
|
||||||
|
<div class="flex-row jcsb setHeader">
|
||||||
|
<div style="width: 15%; font-weight: 600">考核项</div>
|
||||||
|
<div style="width: 50%; font-weight: 600;text-align: center;">评分标准</div>
|
||||||
|
<div class="center" style="width: 25%; font-weight: 600">
|
||||||
|
权重占比
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="margin-bottom: 50px;">
|
||||||
|
<div v-for="(item, index) in (ele.rightArr || [])" class="flex-row jcsb aic contentRow">
|
||||||
|
<div style="width: 15%; font-weight: 600">
|
||||||
|
{{ item.reviewItem }}
|
||||||
|
</div>
|
||||||
|
<div class="center" style="width: 50%;padding: 0 20px;">
|
||||||
|
{{ item.remarks }}
|
||||||
|
</div>
|
||||||
|
<div class="center" style="width: 25%">
|
||||||
|
<div class="flex-row jcsb" style="
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 100%;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
">
|
||||||
|
<div>0</div>
|
||||||
|
<div v-show="item.weight != 20">20</div>
|
||||||
|
</div>
|
||||||
|
<div class="scoreText aic" v-show="item.weight != 0" :style="{
|
||||||
|
left: item.weight * 4.5 - 2.5 + '%',
|
||||||
|
}">
|
||||||
|
<img src="@/assets/task/score.png" :style="{
|
||||||
|
height: '28px',
|
||||||
|
width: '34px',
|
||||||
|
zIndex: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
top: '-2px',
|
||||||
|
}" alt="" />
|
||||||
|
<div :style="{
|
||||||
|
zIndex: 10,
|
||||||
|
textIndent: item.weight < 10 ? '13px' : '10px',
|
||||||
|
fontSize: '12px',
|
||||||
|
}">
|
||||||
|
{{ item.weight }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-for="item in item.weight == 0 ? 0 : item.weight - 1" :key="item"
|
||||||
|
class="stepBox" :style="{
|
||||||
|
left: item * 5 + 4 + '%',
|
||||||
|
}"></div>
|
||||||
|
<el-slider :disabled="isDisabled" v-model="item.weight" :max="20"
|
||||||
|
@change="changeTotal"></el-slider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
moduleId: '',
|
||||||
|
moduleName: '',
|
||||||
|
moduleType: '',
|
||||||
|
scoreList: [],
|
||||||
|
letfValue: "",
|
||||||
|
selectLeftRow: '',
|
||||||
|
leftType: '',
|
||||||
|
isDisabled: true
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getDetail() {
|
||||||
|
taskApi.getTaskModelSet(this.moduleId).then((res) => {
|
||||||
|
let objData = {};
|
||||||
|
res.data.forEach((ele) => {
|
||||||
|
if (!objData[ele.reviewType]) objData[ele.reviewType] = [];
|
||||||
|
objData[ele.reviewType].push(ele);
|
||||||
|
});
|
||||||
|
let arrList = {};
|
||||||
|
Object.keys(objData).forEach((ele) => {
|
||||||
|
let arr = [];
|
||||||
|
objData[ele].forEach((item) => {
|
||||||
|
if (!arr[item.reviewCategory]) arr[item.reviewCategory] = [];
|
||||||
|
arr[item.reviewCategory].push(item);
|
||||||
|
});
|
||||||
|
arrList[ele] = arr;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scoreList = [
|
||||||
|
{
|
||||||
|
title: "组长评估绩效指标",
|
||||||
|
list: Object.keys(arrList["0"]).map((ele) => ({
|
||||||
|
title: ele,
|
||||||
|
weight: arrList["0"][ele].reduce(
|
||||||
|
(total, item) => (item.weight || 0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
rightArr: arrList["0"][ele],
|
||||||
|
type: 0,
|
||||||
|
})),
|
||||||
|
weight: Object.values(arrList["0"]).reduce(
|
||||||
|
(total, item) =>
|
||||||
|
(item.reduce((total, item) => (item.weight || 0) + total, 0) ||
|
||||||
|
0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "个人自评绩效指标",
|
||||||
|
list: Object.keys(arrList["1"]).map((ele) => ({
|
||||||
|
title: ele,
|
||||||
|
weight: arrList["1"][ele].reduce(
|
||||||
|
(total, item) => (item.weight || 0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
rightArr: arrList["1"][ele],
|
||||||
|
type: 1,
|
||||||
|
})),
|
||||||
|
weight: Object.values(arrList["1"]).reduce(
|
||||||
|
(total, item) =>
|
||||||
|
(item.reduce((total, item) => (item.weight || 0) + total, 0) ||
|
||||||
|
0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "系统核算绩效指标",
|
||||||
|
list: Object.keys(arrList["2"] || {}).map((ele) => ({
|
||||||
|
title: ele,
|
||||||
|
weight: arrList["2"][ele].reduce(
|
||||||
|
(total, item) => (item.weight || 0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
rightArr: arrList["2"][ele],
|
||||||
|
type: 2,
|
||||||
|
})),
|
||||||
|
weight: Object.values(arrList["2"] || {}).reduce(
|
||||||
|
(total, item) =>
|
||||||
|
(item.reduce((total, item) => (item.weight || 0) + total, 0) ||
|
||||||
|
0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (!arrList["2"]) {
|
||||||
|
this.scoreList.length = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dialogVisible2 = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selectLeft(row) {
|
||||||
|
this.leftType = ''
|
||||||
|
this.selectLeftRow = row.title + row.type;
|
||||||
|
},
|
||||||
|
changeTotal(data) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scoreList.forEach((ele) => {
|
||||||
|
ele.list.forEach((item) => {
|
||||||
|
item.weight = item.rightArr.reduce(
|
||||||
|
(total, ele) => total + (ele.weight || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ele.weight = ele.list.reduce(
|
||||||
|
(total, ele) => total + (ele.weight || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showAllScoure(val) {
|
||||||
|
if (val)
|
||||||
|
this.leftType = val
|
||||||
|
else {
|
||||||
|
this.leftType = parseInt(this.selectLeftRow)==0?'组长评估绩效指标':'个人自评绩效指标'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.moduleId = this.$route.query.id
|
||||||
|
this.moduleName = this.$route.query.moduleName
|
||||||
|
this.moduleType = this.$route.query.moduleType
|
||||||
|
this.getDetail()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.appraisal-manager {
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
height: calc(100vh - 100px);
|
||||||
|
/* 设置整体高度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
width: 20%;
|
||||||
|
padding: 20px;
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
width: 80%;
|
||||||
|
padding: 20px 40px;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
div.center {
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreBox {
|
||||||
|
position: absolute;
|
||||||
|
top: 45px;
|
||||||
|
right: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 10px !important;
|
||||||
|
/* width: 95%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway.disabled .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
background-color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__stop {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: linear-gradient(to right, #ffb144, #ff7d00);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreText {
|
||||||
|
color: #1686d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setText {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leftSub {
|
||||||
|
padding: 10px 20px 10px 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setTitle {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__content {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__header {}
|
||||||
|
|
||||||
|
.contentTitle {}
|
||||||
|
|
||||||
|
.statusText {
|
||||||
|
color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-buttons ::v-deep .el-button {
|
||||||
|
width: 90px !important;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-buttons .el-button {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0 2px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectClass {
|
||||||
|
background-color: #4096ff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreText {
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 4px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: #4096ff;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepBox {
|
||||||
|
position: absolute;
|
||||||
|
top: 29px;
|
||||||
|
height: 14px;
|
||||||
|
width: 2px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.totalBox {
|
||||||
|
width: 150px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contentRow {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setHeader {
|
||||||
|
background-color: #f8f8f9;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,492 @@
|
||||||
|
<template>
|
||||||
|
<div class="project-list">
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form :inline="true" :model="searchForm" class="demo-form-inline" size="small">
|
||||||
|
<el-form-item label="看板名称" class="form-item">
|
||||||
|
<el-input v-model="searchForm.templateName" placeholder="看板名称" style="width: 300px"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="创建人" class="form-item">
|
||||||
|
<el-input v-model="searchForm.createByName" placeholder="创建人" readonly
|
||||||
|
@click.native="openUserSelectDialog"><el-button slot="append"
|
||||||
|
icon="el-icon-s-custom"></el-button></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="考核类型" class="form-item">
|
||||||
|
<el-select v-model="searchForm.templateType" placeholder="状态" clearable style="width: 300px">
|
||||||
|
<el-option label="年度考核" value="0" />
|
||||||
|
<el-option label="季度考核" value="1" />
|
||||||
|
<el-option label="年度考核" value="2" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item class="search-buttons">
|
||||||
|
<el-button type="primary" @click="onSearch">查询</el-button>
|
||||||
|
<el-button @click="onReset">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="table-actions mb10">
|
||||||
|
<el-button type="primary" size="mini" @click="addTask" style="height: 36px">+ 新增看板</el-button>
|
||||||
|
</div> -->
|
||||||
|
<div class="f1 df">
|
||||||
|
<CustomTable :columns="columns" :tableData="tableData" :total="total" :show-selection="false"
|
||||||
|
:show-index="true" @size-change="handleSizeChange" @current-change="handleCurrentChange"
|
||||||
|
tableHeight="495px">
|
||||||
|
<template slot="operation" slot-scope="{ row }">
|
||||||
|
<div class="operation-buttons">
|
||||||
|
<el-button type="text" size="mini" @click="viewDetail(row)">看板详情</el-button>
|
||||||
|
<!-- <el-button @click="viewDetail(row)" type="text" size="mini">编辑</el-button> -->
|
||||||
|
<el-button type="text" size="mini" @click="delTask(row)">删除</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</CustomTable>
|
||||||
|
</div>
|
||||||
|
<SelectUser :dialogVisible="userSelectDialogVisible" :currentSelectedUser="currentSelectedUser"
|
||||||
|
:currentSelectedUserName="currentSelectedUserName" :highligt="true" ref="selectUserRef"
|
||||||
|
@confirm="handleUserConfirm" @close="handleUserClose" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CustomTable from "@/components/CustomTable.vue";
|
||||||
|
import SelectUser from "@/components/SelectUser.vue";
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CustomTable,
|
||||||
|
SelectUser,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
searchForm: {
|
||||||
|
templateName: "",
|
||||||
|
templateType: "",
|
||||||
|
createBy: "",
|
||||||
|
createByName: ''
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{ prop: "templateName", label: "看板名称" },
|
||||||
|
{
|
||||||
|
prop: "templateType", label: "考核类型", type: "status",
|
||||||
|
callback: (value) => {
|
||||||
|
if (value == 0) var type = "年度考核";
|
||||||
|
else if (value == 1) var type = "季度考核";
|
||||||
|
else if (value == 2) var type = "月度考核";
|
||||||
|
return type
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "createByName",
|
||||||
|
label: "创建人",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "createTime",
|
||||||
|
label: "创建日期",
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "operation",
|
||||||
|
label: "操作",
|
||||||
|
width: "250",
|
||||||
|
className: "operation-column",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tableData: [],
|
||||||
|
total: 0,
|
||||||
|
userSelectDialogVisible: false,
|
||||||
|
currentSelectedUser: [],
|
||||||
|
currentSelectedUserName: [],
|
||||||
|
pageNum: 1, // 当前页码
|
||||||
|
pageSize: 10, // 每页条数
|
||||||
|
statusList: [
|
||||||
|
{ label: "全部", value: "" },
|
||||||
|
{ label: "进行中", value: "0" },
|
||||||
|
{ label: "已过期", value: "2" },
|
||||||
|
],
|
||||||
|
dialogVisible1: false,
|
||||||
|
isEdit: false,
|
||||||
|
taskData: {
|
||||||
|
id: "",
|
||||||
|
taskName: "",
|
||||||
|
peopleNumberDetail: "",
|
||||||
|
userIdList: [],
|
||||||
|
endTime: "",
|
||||||
|
peopleNumber: 0,
|
||||||
|
year: "",
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
taskName: [
|
||||||
|
{ required: true, message: "请输入活动名称", trigger: "blur" },
|
||||||
|
{ min: 1, max: 20, message: "长度限制20个字符", trigger: "blur" },
|
||||||
|
],
|
||||||
|
peopleNumberDetail: [
|
||||||
|
{ required: true, message: "请选择考核人员", trigger: "change" },
|
||||||
|
],
|
||||||
|
endTime: [
|
||||||
|
{ required: true, message: "请选择截止时间", trigger: "blur" },
|
||||||
|
],
|
||||||
|
year: [{ required: true, message: "请选择年份", trigger: "blur" }],
|
||||||
|
},
|
||||||
|
dialogVisible2: false,
|
||||||
|
letfValue: "",
|
||||||
|
scoreList: [],
|
||||||
|
modelList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
dialogVisible1(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.selectUserRef?.$refs.customTableRef?.handleCurrentChange(
|
||||||
|
1
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSearch() {
|
||||||
|
this.getTaskModelList();
|
||||||
|
},
|
||||||
|
onReset() {
|
||||||
|
Object.keys(this.searchForm).forEach((key) => {
|
||||||
|
this.searchForm[key] = "";
|
||||||
|
});
|
||||||
|
this.getTaskModelList();
|
||||||
|
},
|
||||||
|
getTaskModelList() {
|
||||||
|
taskApi
|
||||||
|
.getTaskModel({
|
||||||
|
...this.searchForm,
|
||||||
|
pageNum: this.pageNum,
|
||||||
|
pageSize: this.pageSize,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.tableData = res.rows;
|
||||||
|
this.total = res.total;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleSizeChange(size) {
|
||||||
|
this.pageSize = size;
|
||||||
|
this.pageNum = 1; // 重置为第一页
|
||||||
|
this.getTaskModelList();
|
||||||
|
},
|
||||||
|
handleCurrentChange(page) {
|
||||||
|
this.pageNum = page;
|
||||||
|
this.getTaskModelList();
|
||||||
|
},
|
||||||
|
openUserSelectDialog() {
|
||||||
|
this.userSelectDialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.selectUserRef?.$refs.customTableRef?.clearSelection();
|
||||||
|
this.currentSelectedUser = [this.searchForm.createBy];
|
||||||
|
this.currentSelectedUserName = [this.searchForm.createName];
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleUserConfirm(data) {
|
||||||
|
this.searchForm.createByName = data[0].nickName;
|
||||||
|
this.searchForm.createBy = data[0].userId;
|
||||||
|
},
|
||||||
|
handleUserClose() {
|
||||||
|
this.userSelectDialogVisible = false;
|
||||||
|
},
|
||||||
|
addTask() {
|
||||||
|
this.isEdit = false;
|
||||||
|
this.dialogVisible1 = true;
|
||||||
|
this.taskData = {
|
||||||
|
id: "",
|
||||||
|
taskName: "",
|
||||||
|
peopleNumberDetail: "",
|
||||||
|
userIdList: [],
|
||||||
|
endTime: "",
|
||||||
|
peopleNumber: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
viewDetail(row) {
|
||||||
|
this.$router.push({
|
||||||
|
path: `/workAppraisal/moduleDetail?id=${row.id}&moduleName=${row.templateName}&moduleType=${row.templateType}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
delTask(row) {
|
||||||
|
this.$confirm(
|
||||||
|
"是否确认删除该条看板",
|
||||||
|
"确认删除",
|
||||||
|
{
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
taskApi.delTaskModule(row.id).then((res) => {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "删除成功!",
|
||||||
|
});
|
||||||
|
this.getTaskModelList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getTaskModelList();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.project-list {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: white;
|
||||||
|
height: 88vh;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline {
|
||||||
|
// display: flex;
|
||||||
|
// flex-wrap: nowrap;
|
||||||
|
// align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline .el-form-item {
|
||||||
|
// margin-right: 50px; /* 将间距设置为 30px */
|
||||||
|
// margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline .el-form-item:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
/* 移除最后一个元素的右边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item ::v-deep .el-form-item__content {
|
||||||
|
// width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item ::v-deep .el-input,
|
||||||
|
.form-item ::v-deep .el-select {
|
||||||
|
// width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-buttons {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-buttons .el-button {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-column {
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: -2px 0 5px rgba(241, 112, 6, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button.is-text {
|
||||||
|
min-width: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer .el-button {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #e6a23c;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加以下样式来使对话框垂直居中 */
|
||||||
|
::v-deep .delete-dialog.el-dialog {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table th {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .cell {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-dialog {
|
||||||
|
margin-top: 10% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
width: 40%;
|
||||||
|
padding: 20px;
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
height: 450px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
width: 60%;
|
||||||
|
padding: 20px 40px;
|
||||||
|
height: 450px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
div.center {
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreBox {
|
||||||
|
position: absolute;
|
||||||
|
top: 45px;
|
||||||
|
right: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 10px !important;
|
||||||
|
/* width: 95%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway.disabled .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
background-color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__stop {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: linear-gradient(to right, #ffb144, #ff7d00);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreText {
|
||||||
|
color: #1686d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setText {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leftSub {
|
||||||
|
padding: 10px 20px 10px 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setTitle {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__content {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__header {}
|
||||||
|
|
||||||
|
.contentTitle {}
|
||||||
|
|
||||||
|
.statusText {
|
||||||
|
color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-buttons ::v-deep .el-button {
|
||||||
|
width: 90px !important;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-buttons .el-button {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0 2px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectClass {
|
||||||
|
background-color: #4096ff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreText {
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 4px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: #4096ff;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepBox {
|
||||||
|
position: absolute;
|
||||||
|
top: 29px;
|
||||||
|
height: 14px;
|
||||||
|
width: 2px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.totalBox {
|
||||||
|
width: 150px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,876 @@
|
||||||
|
<template>
|
||||||
|
<div class="project-list">
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form :inline="true" :model="searchForm" class="demo-form-inline" size="small">
|
||||||
|
<el-form-item label="任务名称" class="form-item">
|
||||||
|
<el-input v-model="searchForm.taskName" placeholder="任务名称" style="width: 300px"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="任务状态" class="form-item">
|
||||||
|
<el-select v-model="searchForm.taskStatus" placeholder="状态" clearable style="width: 300px">
|
||||||
|
<el-option v-for="item in statusList" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="任务年份" class="form-item">
|
||||||
|
<el-date-picker v-model="searchForm.year" type="year" style="width: 300px" placeholder="选择年份"
|
||||||
|
value-format="yyyy">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="search-buttons">
|
||||||
|
<el-button type="primary" @click="onSearch">查询</el-button>
|
||||||
|
<el-button @click="onReset">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="table-actions mb10">
|
||||||
|
<el-button type="primary" size="mini" @click="addTask" style="height: 36px">+ 新增任务</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="f1 df">
|
||||||
|
<CustomTable :columns="columns" :tableData="tableData" :total="total" :show-selection="false" :show-index="true"
|
||||||
|
@size-change="handleSizeChange" @current-change="handleCurrentChange" tableHeight="495px">
|
||||||
|
<template slot="operation" slot-scope="{ row }">
|
||||||
|
<div class="operation-buttons">
|
||||||
|
<el-button @click="editTask(row)" type="text" size="mini">编辑</el-button>
|
||||||
|
<el-button v-if="row.taskStatus == 0" type="text" size="mini" @click="setTask(row)">指标配置</el-button>
|
||||||
|
<el-button type="text" size="mini" @click="delTask(row)">删除</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</CustomTable>
|
||||||
|
</div>
|
||||||
|
<SelectUser :dialogVisible="userSelectDialogVisible" :currentSelectedUser="currentSelectedUser"
|
||||||
|
:currentSelectedUserName="currentSelectedUserName" :showSelection="true" :highligt="false"
|
||||||
|
:selectable="selectable" ref="selectUserRef" @confirm="handleUserConfirm" @close="handleUserClose" />
|
||||||
|
<el-dialog :title="isEdit ? '编辑考核任务' : '新增考核任务'" :visible.sync="dialogVisible1" width="25%">
|
||||||
|
<div>
|
||||||
|
<el-form :model="taskData" size="small" ref="taskFormRef" :rules="rules" label-width="100px">
|
||||||
|
<el-form-item label="任务名称" class="form-item" prop="taskName">
|
||||||
|
<el-input v-model="taskData.taskName" placeholder="0/20" style="width: 90%"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="考核人员" class="form-item" prop="peopleNumberDetail">
|
||||||
|
<el-input v-model="taskData.peopleNumberDetail" placeholder="考核人员" readonly style="width: 90%"
|
||||||
|
@click.native="openUserSelectDialog"><el-button slot="append"
|
||||||
|
icon="el-icon-s-custom"></el-button></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="考核模板" class="form-item" prop="templateId">
|
||||||
|
<div>
|
||||||
|
<el-radio-group v-model="taskData.templateType" @change="() => {
|
||||||
|
taskData.templateId = ''
|
||||||
|
}" :disabled="taskData.taskStatus == 2">
|
||||||
|
<el-radio label="0">年度看板</el-radio>
|
||||||
|
<el-radio label="1">季度看板</el-radio>
|
||||||
|
<el-radio label="2">月度看板</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
<el-select v-model="taskData.templateId" placeholder="选择看板" clearable style="width: 300px"
|
||||||
|
:disabled="taskData.taskStatus == 2">
|
||||||
|
<el-option v-for="item in modelList.filter((ele) => ele.templateType == taskData.templateType)"
|
||||||
|
:key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="截止时间" class="form-item" prop="endTime">
|
||||||
|
<el-date-picker v-model="taskData.endTime" type="date" style="width: 90%" placeholder="选择日期"
|
||||||
|
value-format="yyyy-MM-dd 23:59:59" :picker-options="{
|
||||||
|
disabledDate: disabledDate,
|
||||||
|
}">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="年份" class="form-item" prop="year">
|
||||||
|
<el-date-picker v-model="taskData.year" type="year" style="width: 90%" placeholder="选择年份"
|
||||||
|
value-format="yyyy" :picker-options="{
|
||||||
|
disabledDate: disabledDate,
|
||||||
|
}">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible1 = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="saveTask">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog title="配置指标和权重" :visible.sync="dialogVisible2">
|
||||||
|
<div class="modal">
|
||||||
|
<div class="left">
|
||||||
|
<div class="setText flex-row jcsb" style="font-weight: 600">
|
||||||
|
<div>评估维度</div>
|
||||||
|
<div>累计权重</div>
|
||||||
|
</div>
|
||||||
|
<el-collapse v-model="letfValue" :accordion="true" style="height: 300px; overflow: auto">
|
||||||
|
<el-collapse-item v-for="(item, index) in scoreList" :key="index" :name="item.title">
|
||||||
|
<template #title>
|
||||||
|
<div class="jcsb flex-row contentTitle">
|
||||||
|
<span class="setTitle">{{ item.title }}</span>
|
||||||
|
<span class="statusText">{{ item.weight }}%</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<div v-for="(ele, index) in item.list" :key="index" class="flex-row jcsb leftSub" :class="{
|
||||||
|
selectClass: selectLeftRow == ele.title + ele.type,
|
||||||
|
}" @click="selectLeft(ele)">
|
||||||
|
<div>{{ ele.title }}</div>
|
||||||
|
<div class="statusText">{{ ele.weight }}%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
<div class="flex-row jcsb" style="margin-top: 20px; padding-right: 15px">
|
||||||
|
<div class="setTitle" style="font-weight: 600">总计</div>
|
||||||
|
<div class="statusText">
|
||||||
|
{{
|
||||||
|
scoreList.reduce((total, ele) => total + (ele.weight || 0), 0)
|
||||||
|
}}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="flex-row jcsb setText" style="margin-bottom: 20px">
|
||||||
|
<div style="width: 50%; font-weight: 600;text-align: left;">指标</div>
|
||||||
|
<div class="center" style="width: 50%; font-weight: 600;text-align: left;padding-left: 5px;">
|
||||||
|
权重占比
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div v-for="(item, index) in (
|
||||||
|
(
|
||||||
|
(scoreList.find((ele) => ele.title == letfValue) || {})
|
||||||
|
.list || []
|
||||||
|
).find((ele) => ele.title + ele.type == selectLeftRow) || {}
|
||||||
|
).rightArr || []" :key="index" style="margin-bottom: 10px" class="flex-row jcsb aic">
|
||||||
|
<div style="width: 50%; font-weight: 600;color: #333;">
|
||||||
|
{{ item.reviewItem }}
|
||||||
|
</div>
|
||||||
|
<div class="center" style="width: 50%">
|
||||||
|
<div class="flex-row jcsb" style="
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 100%;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
">
|
||||||
|
<div style="font-weight: 500;">0</div>
|
||||||
|
<div v-show="item.weight != 20" style="font-weight: 500;">20</div>
|
||||||
|
</div>
|
||||||
|
<div class="scoreText aic" v-show="item.weight != 0" :style="{
|
||||||
|
left: item.weight * 4.5 - 2.5 + '%',
|
||||||
|
}">
|
||||||
|
<img src="@/assets/task/score.png" :style="{
|
||||||
|
height: '28px',
|
||||||
|
width: '34px',
|
||||||
|
zIndex: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
top: '-2px',
|
||||||
|
}" alt="" />
|
||||||
|
<div :style="{
|
||||||
|
zIndex: 10,
|
||||||
|
textIndent: item.weight < 10 ? '7px' : '5px',
|
||||||
|
fontSize: '12px',
|
||||||
|
}">
|
||||||
|
{{ item.weight }}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="flex-row jcsb scoreBox" style="margin-left: 15px">
|
||||||
|
<div>0%</div>
|
||||||
|
<div class="scoreText">{{ item.weight }}%</div>
|
||||||
|
<div>20%</div>
|
||||||
|
</div> -->
|
||||||
|
<div v-for="item in item.weight == 0 ? 0 : item.weight - 1" :key="item" class="stepBox" :style="{
|
||||||
|
left: item * 5 + 4 + '%',
|
||||||
|
}"></div>
|
||||||
|
<el-slider v-model="item.weight" :max="20" @change="changeTotal"></el-slider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible2 = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="saveSet">保存</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CustomTable from "@/components/CustomTable.vue";
|
||||||
|
import SelectUser from "@/components/SelectUser.vue";
|
||||||
|
import { taskApi } from "@/utils/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CustomTable,
|
||||||
|
SelectUser,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
searchForm: {
|
||||||
|
taskName: "",
|
||||||
|
taskStatus: "",
|
||||||
|
year: "",
|
||||||
|
},
|
||||||
|
selectLeftRow: "",
|
||||||
|
columns: [
|
||||||
|
{ prop: "taskName", label: "任务名称" },
|
||||||
|
{ prop: "peopleNumber", label: "考核人数" },
|
||||||
|
{
|
||||||
|
prop: "taskStatus",
|
||||||
|
label: "任务状态",
|
||||||
|
type: "status",
|
||||||
|
callback: (value) => {
|
||||||
|
if (value == 2) var color = "#999";
|
||||||
|
else var color = "#4096FF";
|
||||||
|
|
||||||
|
return `<span style="color: ${color}">${value ? "已过期" : "进行中"
|
||||||
|
}</span>`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "year",
|
||||||
|
label: "年份",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "createTime",
|
||||||
|
label: "创建时间",
|
||||||
|
type: "status",
|
||||||
|
callback: (value) => {
|
||||||
|
return value.split(" ")[0];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: "endTime",
|
||||||
|
label: "截至时间",
|
||||||
|
type: "status",
|
||||||
|
callback: (value) => {
|
||||||
|
return value.split(" ")[0];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
prop: "operation",
|
||||||
|
label: "操作",
|
||||||
|
width: "250",
|
||||||
|
className: "operation-column",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tableData: [],
|
||||||
|
total: 0,
|
||||||
|
userSelectDialogVisible: false,
|
||||||
|
currentSelectedUser: [],
|
||||||
|
currentSelectedUserName: [],
|
||||||
|
pageNum: 1, // 当前页码
|
||||||
|
pageSize: 10, // 每页条数
|
||||||
|
statusList: [
|
||||||
|
{ label: "全部", value: "" },
|
||||||
|
{ label: "进行中", value: "0" },
|
||||||
|
{ label: "已过期", value: "2" },
|
||||||
|
],
|
||||||
|
dialogVisible1: false,
|
||||||
|
isEdit: false,
|
||||||
|
taskData: {
|
||||||
|
id: "",
|
||||||
|
taskName: "",
|
||||||
|
peopleNumberDetail: "",
|
||||||
|
userIdList: [],
|
||||||
|
endTime: "",
|
||||||
|
peopleNumber: 0,
|
||||||
|
templateType: '0',
|
||||||
|
templateId: '',
|
||||||
|
year: "",
|
||||||
|
taskStatus: 0
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
taskName: [
|
||||||
|
{ required: true, message: "请输入任务名称", trigger: "blur" },
|
||||||
|
{ min: 1, max: 20, message: "长度限制20个字符", trigger: "blur" },
|
||||||
|
],
|
||||||
|
peopleNumberDetail: [
|
||||||
|
{ required: true, message: "请选择考核人员", trigger: "change" },
|
||||||
|
],
|
||||||
|
endTime: [
|
||||||
|
{ required: true, message: "请选择截止时间", trigger: "blur" },
|
||||||
|
],
|
||||||
|
year: [{ required: true, message: "请选择年份", trigger: "blur" }],
|
||||||
|
templateId: [{ required: true, message: "请选择任务看板", trigger: "blur" }],
|
||||||
|
},
|
||||||
|
dialogVisible2: false,
|
||||||
|
letfValue: "",
|
||||||
|
scoreList: [],
|
||||||
|
selectRow: {},
|
||||||
|
modelList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
dialogVisible1(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.selectUserRef?.$refs.customTableRef?.handleCurrentChange(
|
||||||
|
1
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSearch() {
|
||||||
|
this.getTaskList();
|
||||||
|
},
|
||||||
|
onReset() {
|
||||||
|
Object.keys(this.searchForm).forEach((key) => {
|
||||||
|
this.searchForm[key] = "";
|
||||||
|
});
|
||||||
|
this.getTaskList();
|
||||||
|
},
|
||||||
|
disabledDate(date) {
|
||||||
|
const startDate = new Date().getTime(); //
|
||||||
|
|
||||||
|
return new Date(date).getTime() + 60 * 60 * 24 * 1000 < startDate; // 禁用范围外的日期
|
||||||
|
},
|
||||||
|
getTaskList() {
|
||||||
|
taskApi
|
||||||
|
.getTaskList({
|
||||||
|
...this.searchForm,
|
||||||
|
pageNum: this.pageNum,
|
||||||
|
pageSize: this.pageSize,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.tableData = res.rows;
|
||||||
|
this.total = res.total;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleSizeChange(size) {
|
||||||
|
this.pageSize = size;
|
||||||
|
this.pageNum = 1; // 重置为第一页
|
||||||
|
this.getTaskList();
|
||||||
|
},
|
||||||
|
handleCurrentChange(page) {
|
||||||
|
this.pageNum = page;
|
||||||
|
this.getTaskList();
|
||||||
|
},
|
||||||
|
openUserSelectDialog() {
|
||||||
|
this.userSelectDialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.selectUserRef?.$refs.customTableRef?.clearSelection();
|
||||||
|
this.currentSelectedUser = [];
|
||||||
|
this.currentSelectedUserName = [];
|
||||||
|
(this.selectRow.userIdList || []).forEach((ele) => {
|
||||||
|
this.currentSelectedUser.push(ele);
|
||||||
|
});
|
||||||
|
(this.selectRow.peopleNumberDetail || "").split(",").forEach((ele) => {
|
||||||
|
if (ele) this.currentSelectedUserName.push(ele);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleUserConfirm(data) {
|
||||||
|
this.taskData.peopleNumberDetail = data
|
||||||
|
.map((ele) => ele.nickName)
|
||||||
|
.join(",");
|
||||||
|
this.taskData.userIdList = data.map((ele) => ele.userId);
|
||||||
|
this.taskData.peopleNumber = data.length;
|
||||||
|
this.selectRow.userIdList = data.map((ele) => ele.userId);
|
||||||
|
this.selectRow.peopleNumberDetail = data
|
||||||
|
.map((ele) => ele.nickName)
|
||||||
|
.join(",");
|
||||||
|
},
|
||||||
|
handleUserClose() {
|
||||||
|
this.userSelectDialogVisible = false;
|
||||||
|
},
|
||||||
|
addTask() {
|
||||||
|
this.isEdit = false;
|
||||||
|
this.dialogVisible1 = true;
|
||||||
|
this.taskData = {
|
||||||
|
id: "",
|
||||||
|
taskName: "",
|
||||||
|
peopleNumberDetail: "",
|
||||||
|
userIdList: [],
|
||||||
|
endTime: "",
|
||||||
|
peopleNumber: 0,
|
||||||
|
templateType: '0',
|
||||||
|
templateId: '',
|
||||||
|
taskStatus: 0
|
||||||
|
|
||||||
|
};
|
||||||
|
this.selectRow = {};
|
||||||
|
},
|
||||||
|
editTask(row) {
|
||||||
|
this.isEdit = true;
|
||||||
|
this.dialogVisible1 = true;
|
||||||
|
this.taskData.id = row.id;
|
||||||
|
this.taskData.taskName = row.taskName;
|
||||||
|
this.taskData.peopleNumber = row.peopleNumber;
|
||||||
|
this.taskData.peopleNumberDetail = row.peopleNumberDetail;
|
||||||
|
this.taskData.userIdList = row.userIdList;
|
||||||
|
this.taskData.endTime = row.endTime;
|
||||||
|
this.taskData.templateId = row.templateId;
|
||||||
|
this.taskData.templateType = row.templateType;
|
||||||
|
this.taskData.taskStatus = row.taskStatus;
|
||||||
|
this.taskData.year = String(row.year);
|
||||||
|
this.selectRow = row;
|
||||||
|
},
|
||||||
|
setTask(row) {
|
||||||
|
taskApi.getTaskSet(row.id).then((res) => {
|
||||||
|
let objData = {};
|
||||||
|
res.data.forEach((ele) => {
|
||||||
|
if (!objData[ele.reviewType]) objData[ele.reviewType] = [];
|
||||||
|
objData[ele.reviewType].push(ele);
|
||||||
|
});
|
||||||
|
let arrList = {};
|
||||||
|
Object.keys(objData).forEach((ele) => {
|
||||||
|
let arr = [];
|
||||||
|
objData[ele].forEach((item) => {
|
||||||
|
if (!arr[item.reviewCategory]) arr[item.reviewCategory] = [];
|
||||||
|
arr[item.reviewCategory].push(item);
|
||||||
|
});
|
||||||
|
arrList[ele] = arr;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scoreList = [
|
||||||
|
{
|
||||||
|
title: "组长评估绩效指标",
|
||||||
|
list: Object.keys(arrList["0"]).map((ele) => ({
|
||||||
|
title: ele,
|
||||||
|
weight: arrList["0"][ele].reduce(
|
||||||
|
(total, item) => (item.weight || 0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
rightArr: arrList["0"][ele],
|
||||||
|
type: 0,
|
||||||
|
})),
|
||||||
|
weight: Object.values(arrList["0"]).reduce(
|
||||||
|
(total, item) =>
|
||||||
|
(item.reduce((total, item) => (item.weight || 0) + total, 0) ||
|
||||||
|
0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "个人自评绩效指标",
|
||||||
|
list: Object.keys(arrList["1"]).map((ele) => ({
|
||||||
|
title: ele,
|
||||||
|
weight: arrList["1"][ele].reduce(
|
||||||
|
(total, item) => (item.weight || 0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
rightArr: arrList["1"][ele],
|
||||||
|
type: 1,
|
||||||
|
})),
|
||||||
|
weight: Object.values(arrList["1"]).reduce(
|
||||||
|
(total, item) =>
|
||||||
|
(item.reduce((total, item) => (item.weight || 0) + total, 0) ||
|
||||||
|
0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "系统核算绩效指标",
|
||||||
|
list: Object.keys(arrList["2"] || {}).map((ele) => ({
|
||||||
|
title: ele,
|
||||||
|
weight: arrList["2"][ele].reduce(
|
||||||
|
(total, item) => (item.weight || 0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
rightArr: arrList["2"][ele],
|
||||||
|
type: 2,
|
||||||
|
})),
|
||||||
|
weight: Object.values(arrList["2"] || {}).reduce(
|
||||||
|
(total, item) =>
|
||||||
|
(item.reduce((total, item) => (item.weight || 0) + total, 0) ||
|
||||||
|
0) + total,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (!arrList["2"]) {
|
||||||
|
this.scoreList.length = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dialogVisible2 = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
saveSet() {
|
||||||
|
if (
|
||||||
|
this.scoreList.reduce((total, ele) => total + (ele.weight || 0), 0) !==
|
||||||
|
100
|
||||||
|
) {
|
||||||
|
this.$message({
|
||||||
|
type: "warning",
|
||||||
|
message: "累计权重值必须为100%,请调整后再试",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let examineConfigList = [];
|
||||||
|
this.scoreList
|
||||||
|
.map((ele) => ele.list)
|
||||||
|
.flat()
|
||||||
|
.map((ele) => ele.rightArr)
|
||||||
|
.flat()
|
||||||
|
.forEach((ele) => {
|
||||||
|
examineConfigList.push({ id: ele.id, weight: ele.weight });
|
||||||
|
});
|
||||||
|
taskApi
|
||||||
|
.setTaskSet({ examineConfigList, taskId: this.id })
|
||||||
|
.then((res) => {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "操作成功",
|
||||||
|
});
|
||||||
|
this.dialogVisible2 = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delTask(row) {
|
||||||
|
this.$confirm(
|
||||||
|
"删除任务及绩效数据,该操作不可逆,请谨慎操作",
|
||||||
|
"确认删除任务",
|
||||||
|
{
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
taskApi.delTask(row.id).then((res) => {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "删除成功!",
|
||||||
|
});
|
||||||
|
this.getTaskList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selectLeft(row) {
|
||||||
|
this.selectLeftRow = row.title + row.type;
|
||||||
|
},
|
||||||
|
saveTask() {
|
||||||
|
this.$refs.taskFormRef.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
if (this.taskData.id) {
|
||||||
|
taskApi.upDateTask(this.taskData).then((res) => {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "修改成功!",
|
||||||
|
});
|
||||||
|
this.dialogVisible1 = false;
|
||||||
|
this.getTaskList();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
taskApi.addTask(this.taskData).then((res) => {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "新增成功!",
|
||||||
|
});
|
||||||
|
this.dialogVisible1 = false;
|
||||||
|
this.getTaskList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("error submit!!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
changeTotal(data) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scoreList.forEach((ele) => {
|
||||||
|
ele.list.forEach((item) => {
|
||||||
|
item.weight = item.rightArr.reduce(
|
||||||
|
(total, ele) => total + (ele.weight || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ele.weight = ele.list.reduce(
|
||||||
|
(total, ele) => total + (ele.weight || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selectable(row, index) {
|
||||||
|
if (row.roles.find((ele) => ele.roleName == "普通员工")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getTaskModel() {
|
||||||
|
const res = await taskApi.getTaskModel({ pageNum: 1, pageSize: 1000 });
|
||||||
|
this.modelList = res.rows.map((ele) => ({
|
||||||
|
value: ele.id,
|
||||||
|
label: ele.templateName,
|
||||||
|
templateType: ele.templateType
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getTaskList();
|
||||||
|
this.getTaskModel();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.project-list {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: white;
|
||||||
|
height: 88vh;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline {
|
||||||
|
// display: flex;
|
||||||
|
// flex-wrap: nowrap;
|
||||||
|
// align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline .el-form-item {
|
||||||
|
// margin-right: 50px; /* 将间距设置为 30px */
|
||||||
|
// margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-form-inline .el-form-item:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
/* 移除最后一个元素的右边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item ::v-deep .el-form-item__content {
|
||||||
|
// width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item ::v-deep .el-input,
|
||||||
|
.form-item ::v-deep .el-select {
|
||||||
|
// width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-buttons {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-buttons .el-button {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-column {
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: -2px 0 5px rgba(241, 112, 6, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button.is-text {
|
||||||
|
min-width: 32px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer .el-button {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #e6a23c;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加以下样式来使对话框垂直居中 */
|
||||||
|
::v-deep .delete-dialog.el-dialog {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table th {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .cell {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-dialog {
|
||||||
|
margin-top: 10% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #E6E6E6;
|
||||||
|
// border-top: 1px solid #E6E6E6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
width: 40%;
|
||||||
|
padding:0;
|
||||||
|
// border-right: 1px solid #E6E6E6;
|
||||||
|
height: 450px;
|
||||||
|
overflow: auto;
|
||||||
|
box-shadow: 5px 0 20px 5px #eeeeee;
|
||||||
|
z-index: 100;
|
||||||
|
>div{
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
width: 60%;
|
||||||
|
// padding: 0 40px;
|
||||||
|
height: 450px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
div.center {
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
>div{
|
||||||
|
padding-left: 3cap;
|
||||||
|
padding-right: 30px;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreBox {
|
||||||
|
position: absolute;
|
||||||
|
top: 45px;
|
||||||
|
right: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 10px !important;
|
||||||
|
/* width: 95%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__runway.disabled .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
background-color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__stop {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__bar {
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: linear-gradient(to right, #ffb144, #ff7d00);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-slider__button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreText {
|
||||||
|
color: #1686d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setText {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #FAFAFA;
|
||||||
|
text-align: right;
|
||||||
|
padding:15px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leftSub {
|
||||||
|
padding: 10px 20px 10px 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setTitle {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__content {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse-item__header {}
|
||||||
|
|
||||||
|
.contentTitle {}
|
||||||
|
|
||||||
|
.statusText {
|
||||||
|
color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-collapse {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-buttons ::v-deep .el-button {
|
||||||
|
width: 90px !important;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .operation-buttons .el-button {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 0 2px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectClass {
|
||||||
|
background-color: #4096ff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreText {
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 4px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: #4096ff;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepBox {
|
||||||
|
position: absolute;
|
||||||
|
top: 29px;
|
||||||
|
height: 14px;
|
||||||
|
width: 2px;
|
||||||
|
background-color: transparent;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.totalBox {
|
||||||
|
width: 150px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,258 @@
|
||||||
|
<template>
|
||||||
|
<div class="leftBox">
|
||||||
|
<div class="topBox">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="selectMonth"
|
||||||
|
type="month"
|
||||||
|
format="yyyy年MM月"
|
||||||
|
:clearable="false"
|
||||||
|
style="margin-bottom: 10px; width: 150px"
|
||||||
|
@change="changeMonth"
|
||||||
|
prefix-icon="false"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<i
|
||||||
|
class="el-icon-arrow-left"
|
||||||
|
style="font-size: 18px; font-weight: bold"
|
||||||
|
@click="preMonth"
|
||||||
|
></i>
|
||||||
|
<i
|
||||||
|
class="el-icon-arrow-right"
|
||||||
|
style="font-size: 18px; font-weight: bold"
|
||||||
|
@click="nextMonth"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-calendar v-model="selectMonthValue">
|
||||||
|
<template #dateCell="{ data }">
|
||||||
|
<div
|
||||||
|
:key="data.day"
|
||||||
|
:id="data.day"
|
||||||
|
@click="searchLog(data, isOverDay(data.day))"
|
||||||
|
:class="{
|
||||||
|
dayBox: true,
|
||||||
|
disabled: isOverDay(data.day),
|
||||||
|
hasLog: calendarList.filter(
|
||||||
|
(ele) => ele.date == data.day + ' 00:00:00' && ele.state != -1
|
||||||
|
).length,
|
||||||
|
timeout: isTimeOut(
|
||||||
|
data.day,
|
||||||
|
calendarList.find(
|
||||||
|
(ele) => ele.date == data.day + ' 00:00:00' && ele.state == -1
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ data.day.split("-")[2] }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-calendar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { workLogApi, projectApi } from "@/utils/api";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "LeftMonth",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectMonth: this.moment().format("YYYY-MM"),
|
||||||
|
nowDay: this.moment().format("YYYY-MM-DD 23:59:59"),
|
||||||
|
userId: this.$store.state.user.id,
|
||||||
|
calendarList: [],
|
||||||
|
selectDay:
|
||||||
|
this.moment().date() > 10
|
||||||
|
? "0" + this.moment().date()
|
||||||
|
: this.moment().date(),
|
||||||
|
selectMonthValue: this.moment().format("YYYY-MM-DD"),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
preMonth() {
|
||||||
|
this.selectDay = "01";
|
||||||
|
this.selectMonth = this.moment(this.selectMonth)
|
||||||
|
.subtract(1, "months")
|
||||||
|
.format(`YYYY-MM-${this.selectDay}`);
|
||||||
|
this.changeMonth();
|
||||||
|
},
|
||||||
|
nextMonth() {
|
||||||
|
this.selectDay = "01";
|
||||||
|
this.selectMonth = this.moment(this.selectMonth)
|
||||||
|
.add(1, "months")
|
||||||
|
.format(`YYYY-MM-${this.selectDay}`);
|
||||||
|
this.changeMonth();
|
||||||
|
},
|
||||||
|
searchLog(data, overDay) {
|
||||||
|
let checkMonth = this.moment(data.day).format("YYYY-MM");
|
||||||
|
let selectMonth = this.moment(this.selectMonth).format("YYYY-MM");
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (overDay) {
|
||||||
|
this.$message({
|
||||||
|
message: "不能超过当前时间",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
this.$emit("setDisableTable", true);
|
||||||
|
} else {
|
||||||
|
this.selectDay = data.day.split("-")[2];
|
||||||
|
if (selectMonth !== checkMonth) {
|
||||||
|
this.selectMonth = data.day;
|
||||||
|
this.getLogMonth();
|
||||||
|
}
|
||||||
|
this.$emit("searchDay", data.day + " 00:00:00");
|
||||||
|
this.$emit("setDisableTable", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isOverDay(data) {
|
||||||
|
return new Date(data).getTime() > new Date(this.nowDay).getTime();
|
||||||
|
},
|
||||||
|
isTimeOut(data, hasDay) {
|
||||||
|
if (
|
||||||
|
hasDay &&
|
||||||
|
new Date(data).getTime() <
|
||||||
|
new Date(this.moment().format(`YYYY-MM-DD 00:00:00`)).getTime()
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getLogMonth() {
|
||||||
|
if (this.$route.query.userId) {
|
||||||
|
this.userId = this.$route.query.userId;
|
||||||
|
}
|
||||||
|
let start = this.moment(this.selectMonth)
|
||||||
|
.startOf("month")
|
||||||
|
.format(`YYYY-MM-DD 00:00:00`);
|
||||||
|
let end = this.moment(this.selectMonth)
|
||||||
|
.endOf("month")
|
||||||
|
.format("YYYY-MM-DD 23:59:59");
|
||||||
|
|
||||||
|
workLogApi
|
||||||
|
.getLogData({
|
||||||
|
startDate: start,
|
||||||
|
endDate: end,
|
||||||
|
userId: this.userId,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.calendarList = res.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
changeMonth() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.selectMonth == this.selectMonthValue) return;
|
||||||
|
this.selectDay = "01";
|
||||||
|
this.selectMonth = this.moment(this.selectMonth).format(
|
||||||
|
`YYYY-MM-${this.selectDay}`
|
||||||
|
);
|
||||||
|
this.selectMonthValue = this.selectMonth;
|
||||||
|
this.searchLog(
|
||||||
|
{ day: this.selectMonth },
|
||||||
|
this.isOverDay(this.selectMonth)
|
||||||
|
);
|
||||||
|
this.searchLog(
|
||||||
|
{ day: this.selectMonth },
|
||||||
|
this.isOverDay(this.selectMonth)
|
||||||
|
);
|
||||||
|
this.getLogMonth();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
mounted() {
|
||||||
|
this.getLogMonth();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.leftBox ::v-deep .el-calendar__header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.leftBox ::v-deep .el-date-editor {
|
||||||
|
.el-input__inner {
|
||||||
|
border: none;
|
||||||
|
padding-left: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.leftBox ::v-deep .el-calendar__body {
|
||||||
|
padding: 0 !important;
|
||||||
|
thead {
|
||||||
|
th {
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tbody {
|
||||||
|
.hasLog {
|
||||||
|
background: #71afff;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.timeout {
|
||||||
|
background: #f7c940;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
border: none;
|
||||||
|
padding: 10px 0;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
.el-calendar-day {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 !important;
|
||||||
|
font-size: 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-family: cursive !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.next,
|
||||||
|
&.prev {
|
||||||
|
color: #333 !important;
|
||||||
|
}
|
||||||
|
&.is-selected .dayBox:not(.disabled) {
|
||||||
|
border-radius: 50% !important;
|
||||||
|
background-color: #4096ff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.el-calendar-day {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
&:hover {
|
||||||
|
background-color: #88bdfd;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.topBox {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
i {
|
||||||
|
margin-right: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.leftBox ::v-deep .disabled {
|
||||||
|
background-color: #fff !important;
|
||||||
|
color: #c0c4cc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,659 @@
|
||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="topBox" v-show="!disableTable">
|
||||||
|
<div>
|
||||||
|
<div class="topTitle">当日日志</div>
|
||||||
|
<div class="topText">
|
||||||
|
总计填报工时:<span> {{ totalWorkTime }} </span>天
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" @click="handleAdd">
|
||||||
|
<el-icon class="el-icon-plus" />
|
||||||
|
添加日志
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格区域 -->
|
||||||
|
<el-table :data="tableData" style="width: 100%" class="tableBox">
|
||||||
|
<el-table-column label="序号" width="70" type="index" />
|
||||||
|
<el-table-column label="项目名称" prop="projectName">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>
|
||||||
|
<div v-if="scope.row.edit">
|
||||||
|
<el-select v-model="scope.row.projectId" placeholder="时间匹配的项目" class="filter-select" @change="
|
||||||
|
(val) => {
|
||||||
|
getVersionList(val, scope.row);
|
||||||
|
}
|
||||||
|
">
|
||||||
|
<el-option v-for="item in projectListFilter" :key="item.projectId" :label="item.projectName"
|
||||||
|
:value="item.projectId" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div v-show="!scope.row.edit">{{ scope.row.projectName }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="版本" prop="versionNumber">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>
|
||||||
|
<div v-if="scope.row.edit">
|
||||||
|
<el-select v-model="scope.row.versionId" placeholder="含有可选需求的版本" class="filter-select"
|
||||||
|
ref="versionSelectRef" @change="
|
||||||
|
(val) => {
|
||||||
|
getDemandList(val, scope.row);
|
||||||
|
}
|
||||||
|
">
|
||||||
|
<el-option v-for="item in versionList.filter((ele) => ele.type == 0)" :key="item.id" :label="item.title"
|
||||||
|
:value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div v-show="!scope.row.edit">{{ scope.row.versionNumber }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="项目需求">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>
|
||||||
|
<div v-if="scope.row.edit">
|
||||||
|
<el-select v-model="scope.row.demandId" placeholder="时间匹配且非已结束的需求" class="filter-select"
|
||||||
|
@change="openContent(scope.row)" ref="demandSelectRef">
|
||||||
|
<el-option v-for="item in demandList" :key="item.id" :label="item.title" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div v-show="!scope.row.edit">{{ scope.row.title }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="工作内容" prop="workContent">
|
||||||
|
<template #default="scope">
|
||||||
|
<div @click="openContent(scope.row)">
|
||||||
|
<el-popover placement="bottom" width="400" trigger="click" v-model="scope.row.showContent"
|
||||||
|
:key="scope.row.loggerId">
|
||||||
|
<el-input type="textarea" :rows="5" placeholder="请输入内容" v-model="scope.row.workContent"
|
||||||
|
:disabled="!scope.row.edit">
|
||||||
|
</el-input>
|
||||||
|
<div style="margin-top: 10px; text-align: right" v-show="!disableTable && scope.row.edit">
|
||||||
|
<el-button type="primary" @click="saveContent(scope.row, 1)">确认</el-button>
|
||||||
|
<el-button @click="saveContent(scope.row, 0)">取消</el-button>
|
||||||
|
</div>
|
||||||
|
<div slot="reference">
|
||||||
|
<div style="cursor: pointer" :class="{
|
||||||
|
contentText: true,
|
||||||
|
noneText: !scope.row.workContent,
|
||||||
|
}">
|
||||||
|
{{ scope.row.workContent || "请输入" }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="工时分配" prop="estimatedWorkHours">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>
|
||||||
|
<div v-if="scope.row.edit">
|
||||||
|
<el-select v-model="scope.row.workTime" placeholder="请选择工时" class="filter-select" filterable allow-create>
|
||||||
|
<el-option v-for="item in workTimeList" :key="item" :label="item" :value="item" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div v-show="!scope.row.edit">{{ scope.row.workTime }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="200">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>
|
||||||
|
<el-button type="text" @click="handleFile(scope.row)">
|
||||||
|
附件详情
|
||||||
|
</el-button>
|
||||||
|
<el-button type="text" @click="handleEdit(scope.row)" v-show="!disableTable">
|
||||||
|
{{ scope.row.loggerId && !scope.row.edit ? "编辑" : "确认" }}
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button type="text" @click="handleDelete(scope.row, scope.$index)" style="color: #666"
|
||||||
|
v-show="!disableTable">
|
||||||
|
{{ scope.row.loggerId && !scope.row.edit ? "删除" : "取消" }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-dialog title="附件" :visible.sync="dialogVisibleFile" width="780px" :close-on-click-modal="false">
|
||||||
|
<div v-loading="fileLoading">
|
||||||
|
<div v-show="!disableTable">
|
||||||
|
<el-upload class="upload-demo" ref="upload" :action="fileUpload" :show-file-list="false" :auto-upload="true"
|
||||||
|
:multiple="true" :before-upload="beforeUpload" :on-success="successUpload" :headers="{
|
||||||
|
Authorization: 'Bearer ' + token,
|
||||||
|
}" :data="{}">
|
||||||
|
<div class="flex-row aic" style="gap: 10px; margin-bottom: 10px">
|
||||||
|
<el-button slot="trigger" size="small" type="default"
|
||||||
|
style="width: 80px; color: #333; font-weight: 500">上传附件</el-button>
|
||||||
|
<div slot="tip" style="color: #999999; font-size: 12px">
|
||||||
|
单个附件限制100M
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</div>
|
||||||
|
<div style="height: 500px;overflow: auto;">
|
||||||
|
<el-table :data="fileList" style="width: 100%;height: 100%;" class="tableBox">
|
||||||
|
<el-table-column label="名称" prop="fileNewName">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="flex-row aic fileBox" style="gap: 10px;">
|
||||||
|
<img class="" :src="filePng" v-if="getFileType(scope.row.fileNewName) == 'file'"> </img>
|
||||||
|
<img class="" :src="imagePng" v-else-if="getFileType(scope.row.fileNewName) == 'image'"> </img>
|
||||||
|
<img class="" :src="zipPng" v-else-if="getFileType(scope.row.fileNewName) == 'zip'"> </img>
|
||||||
|
<div class="downFileBox" @click="downFile(scope.row.fileUrl)">
|
||||||
|
{{ scope.row.fileNewName }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="类型" prop="fileName">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>
|
||||||
|
{{ scope.row.fileNewName.split(".")[1] }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="上传时间" prop="createTime">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>
|
||||||
|
{{
|
||||||
|
scope.row.createTime || moment().format("YYYY-MM-DD HH:mm:ss")
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<div>
|
||||||
|
<el-button type="text" @click="delFile(scope.row)" v-show="!disableTable">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div slot="footer" class="dialog-footer" v-show="!disableTable">
|
||||||
|
<el-button @click="cancalFile">取消</el-button>
|
||||||
|
<el-button type="primary" @click="saveFile">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { demandApi, workLogApi, projectApi, systemApi } from "@/utils/api";
|
||||||
|
import { getToken } from "@/utils/auth";
|
||||||
|
import filePng from "@/assets/images/file.png";
|
||||||
|
import zipPng from "@/assets/images/zip.png";
|
||||||
|
import imagePng from "@/assets/images/image.png";
|
||||||
|
export default {
|
||||||
|
name: "RightTable",
|
||||||
|
props: {
|
||||||
|
selectDay: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
disableTable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusList: [],
|
||||||
|
userId: this.$store.state.user.id,
|
||||||
|
projectId: "",
|
||||||
|
tableData: [],
|
||||||
|
projectList: [],
|
||||||
|
versionList: [],
|
||||||
|
demandList: [],
|
||||||
|
hasTimeLong: 0,
|
||||||
|
workTimeList: [],
|
||||||
|
oldContent: "",
|
||||||
|
dialogVisibleFile: false,
|
||||||
|
fileList: [],
|
||||||
|
checkRow: {},
|
||||||
|
fileUpload: systemApi.fileUpload,
|
||||||
|
token: getToken(),
|
||||||
|
fileLoading: false,
|
||||||
|
filePng,
|
||||||
|
zipPng,
|
||||||
|
imagePng,
|
||||||
|
delFileArr: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
if (this.$route.query.userId) {
|
||||||
|
this.userId = this.$route.query.userId;
|
||||||
|
this.userName = this.$route.query.nickName;
|
||||||
|
this.projectId = this.$route.query.projectId;
|
||||||
|
}
|
||||||
|
//获取项目列表
|
||||||
|
},
|
||||||
|
getLogList() {
|
||||||
|
workLogApi
|
||||||
|
.getLogDataDetail({
|
||||||
|
createBy: this.userId,
|
||||||
|
loggerDate: this.selectDay,
|
||||||
|
projectId: this.projectId,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.tableData = res.data.map((ele) => {
|
||||||
|
ele.edit = false;
|
||||||
|
ele.showContent = false;
|
||||||
|
return ele;
|
||||||
|
});
|
||||||
|
if (this.tableData.length == 0 && !this.disableTable) {
|
||||||
|
this.handleAdd();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDelete(row, index) {
|
||||||
|
if (row.loggerId && !row.edit) {
|
||||||
|
this.$confirm("此操作将永久删除该版本号, 是否继续?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
workLogApi.delLog(row.loggerId).then((res) => {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "删除成功!",
|
||||||
|
});
|
||||||
|
this.getLogList();
|
||||||
|
this.$emit("changeCaleder");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => { });
|
||||||
|
} else if (!row.loggerId) {
|
||||||
|
this.tableData = this.tableData.filter((ele, ind) => index != ind);
|
||||||
|
} else {
|
||||||
|
row.edit = false;
|
||||||
|
}
|
||||||
|
// 实现删除逻辑
|
||||||
|
},
|
||||||
|
handleAdd() {
|
||||||
|
if (this.tableData.filter((ele) => ele.edit).length) {
|
||||||
|
this.$message({
|
||||||
|
message: "请先保存未完成数据",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.versionList = [];
|
||||||
|
this.demandList = [];
|
||||||
|
this.oldContent = "";
|
||||||
|
this.getDayTime("add");
|
||||||
|
},
|
||||||
|
async handleEdit(row) {
|
||||||
|
if (
|
||||||
|
this.tableData.filter((ele) => ele.edit && ele.loggerId != row.loggerId)
|
||||||
|
.length
|
||||||
|
) {
|
||||||
|
this.$message({
|
||||||
|
message: "请先保存未完成数据",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (row.edit) {
|
||||||
|
if (row.workTime > this.workTimeList[this.workTimeList.length - 1]) {
|
||||||
|
this.$modal.msgWarning("工时超过最大值");
|
||||||
|
return;
|
||||||
|
} else if (!row.workContent) {
|
||||||
|
this.$modal.msgWarning("工作日志不能为空");
|
||||||
|
return;
|
||||||
|
} else if ((String(row.workTime).split(".")[1] || "").length > 1) {
|
||||||
|
this.$modal.msgWarning("工时只允许一位小数");
|
||||||
|
return;
|
||||||
|
} else if (row.workTime <= 0) {
|
||||||
|
this.$modal.msgWarning("工时不能小于等于0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let param = {
|
||||||
|
...row,
|
||||||
|
};
|
||||||
|
if (row.loggerId) {
|
||||||
|
await workLogApi.editLog(param);
|
||||||
|
} else {
|
||||||
|
await workLogApi.addLog(param);
|
||||||
|
this.$emit("changeCaleder");
|
||||||
|
}
|
||||||
|
if (this.delFileArr.length) {
|
||||||
|
systemApi.delFile({ ids: this.delFileArr }).then((res) => {
|
||||||
|
this.fileList = []
|
||||||
|
this.delFileArr = []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.$modal.msgSuccess("操作成功");
|
||||||
|
row.edit = false;
|
||||||
|
this.getLogList();
|
||||||
|
} else {
|
||||||
|
row.edit = true;
|
||||||
|
this.oldContent = row.workContent;
|
||||||
|
this.getDayTime("edit", row);
|
||||||
|
this.getVersionList(row.projectId, row, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleFile(row) {
|
||||||
|
this.dialogVisibleFile = true;
|
||||||
|
this.checkRow = row;
|
||||||
|
this.fileList = [...(row.fileList || []).map((ele) => ({ ...ele }))];
|
||||||
|
},
|
||||||
|
beforeUpload(file) {
|
||||||
|
this.fileLoading = true;
|
||||||
|
if (file.size > 1024 * 1024 * 100) {
|
||||||
|
this.fileLoading = false;
|
||||||
|
|
||||||
|
this.$message({
|
||||||
|
type: "warning",
|
||||||
|
message: "单个文件不能大于100M!",
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
successUpload(res, file, fileList) {
|
||||||
|
if (!fileList.filter((ele) => ele.percentage != 100).length) {
|
||||||
|
this.fileLoading = false;
|
||||||
|
}
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.fileList.push({
|
||||||
|
fileName: res.originalFilename, //文件名称
|
||||||
|
filePath: res.filePath, //文件路径
|
||||||
|
fileNewName: res.newFileName, //文件新名称
|
||||||
|
fileUrl: res.url,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.fileLoading = false;
|
||||||
|
|
||||||
|
this.$message({
|
||||||
|
type: "error",
|
||||||
|
message: res.msg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cancalFile() {
|
||||||
|
this.dialogVisibleFile = false;
|
||||||
|
this.fileList = [];
|
||||||
|
},
|
||||||
|
async saveFile() {
|
||||||
|
this.dialogVisibleFile = false;
|
||||||
|
this.checkRow.fileList = this.fileList;
|
||||||
|
if (this.checkRow.loggerId) {
|
||||||
|
await workLogApi.editLog(this.checkRow);
|
||||||
|
if (this.delFileArr.length) {
|
||||||
|
systemApi.delFileBatch(this.delFileArr.join(',')).then((res) => {
|
||||||
|
this.fileList = []
|
||||||
|
this.delFileArr = []
|
||||||
|
this.getLogList();
|
||||||
|
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.getLogList();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "保存成功!",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async getAllProject() {
|
||||||
|
const response = await projectApi.listProject({
|
||||||
|
pageSize: 10000,
|
||||||
|
pageNum: 1,
|
||||||
|
});
|
||||||
|
this.projectList = response.rows;
|
||||||
|
},
|
||||||
|
// 获取剩余工时
|
||||||
|
async getDayTime(type, row) {
|
||||||
|
const res = await workLogApi.getDayTime({
|
||||||
|
loggerDate: this.selectDay,
|
||||||
|
});
|
||||||
|
this.hasTimeLong = Number(res.data);
|
||||||
|
if (type == "add") {
|
||||||
|
let now = new Date(
|
||||||
|
this.moment().format("YYYY-MM-DD 00:00:00")
|
||||||
|
).getTime();
|
||||||
|
let select = new Date(this.selectDay).getTime();
|
||||||
|
let row = {
|
||||||
|
loggerDate: this.selectDay,
|
||||||
|
projectId: "",
|
||||||
|
workTime: "",
|
||||||
|
workContent: "",
|
||||||
|
state: now == select ? 0 : 1,
|
||||||
|
userId: this.userId,
|
||||||
|
demandId: "",
|
||||||
|
edit: true,
|
||||||
|
fileList: [],
|
||||||
|
};
|
||||||
|
this.computedTime(0);
|
||||||
|
if (this.workTimeList.length) this.tableData.push(row);
|
||||||
|
} else {
|
||||||
|
this.computedTime(row.workTime);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computedTime(time) {
|
||||||
|
let length = (this.hasTimeLong + (Number(time) || 0)).toFixed(1);
|
||||||
|
if (length <= 0) {
|
||||||
|
this.$modal.msgWarning("当日剩余工时为0");
|
||||||
|
this.workTimeList = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.workTimeList = new Array((length * 10) / 1)
|
||||||
|
.fill(0)
|
||||||
|
.map((ele, index) => {
|
||||||
|
return (index + 1) / 10;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getVersionList(val, row, isOpen) {
|
||||||
|
if (!isOpen) {
|
||||||
|
row.versionId = "";
|
||||||
|
row.demandId = "";
|
||||||
|
}
|
||||||
|
this.$nextTick(async () => {
|
||||||
|
const res = await demandApi.getVersionTree({
|
||||||
|
projectId: val,
|
||||||
|
userId: this.userId,
|
||||||
|
demandStatusList: [0, 1, 2, 3],
|
||||||
|
queryDate: this.selectDay,
|
||||||
|
});
|
||||||
|
this.versionList = res.data.filter((ele) => ele.type == 0);
|
||||||
|
this.demandList = res.data.filter((ele) => ele.type == 1);
|
||||||
|
if (!isOpen) this.$refs.versionSelectRef.toggleMenu();
|
||||||
|
if (isOpen) this.getDemandList(row.versionId, row, true);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async getDemandList(val, row, isOpen) {
|
||||||
|
if (!isOpen) row.demandId = "";
|
||||||
|
if (this.versionList.find((ele) => ele.id == val)) {
|
||||||
|
this.demandList = this.versionList.find(
|
||||||
|
(ele) => ele.id == val
|
||||||
|
).childrenList;
|
||||||
|
} else {
|
||||||
|
this.demandList = [];
|
||||||
|
}
|
||||||
|
if (!this.demandList.find((ele) => ele.id == row.demandId)) {
|
||||||
|
row.demandId = "";
|
||||||
|
}
|
||||||
|
if (!isOpen) this.$refs.demandSelectRef.toggleMenu();
|
||||||
|
},
|
||||||
|
openContent(row) {
|
||||||
|
row.showContent = true;
|
||||||
|
},
|
||||||
|
saveContent(row, type) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (type == 0) {
|
||||||
|
row.workContent = this.oldContent;
|
||||||
|
} else {
|
||||||
|
this.oldContent = row.workContent;
|
||||||
|
}
|
||||||
|
row.showContent = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
downFile(url) {
|
||||||
|
window.open(url);
|
||||||
|
},
|
||||||
|
delFile(row) {
|
||||||
|
if (row.id) {
|
||||||
|
this.$confirm("此操作将永久删除文件, 是否继续?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}).then(() => {
|
||||||
|
this.delFileArr.push(row.id)
|
||||||
|
this.fileList = this.fileList.filter(
|
||||||
|
(ele) => ele.fileNewName != row.fileNewName
|
||||||
|
);
|
||||||
|
this.$message({
|
||||||
|
type: 'success',
|
||||||
|
message: "删除成功!"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.fileList = this.fileList.filter(
|
||||||
|
(ele) => ele.fileNewName != row.fileNewName
|
||||||
|
);
|
||||||
|
this.$message({
|
||||||
|
type: 'success',
|
||||||
|
message: "删除成功!"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getFileType(name) {
|
||||||
|
console.log(name);
|
||||||
|
var data = {
|
||||||
|
jpg: "image",
|
||||||
|
jpeg: "image",
|
||||||
|
png: "image",
|
||||||
|
gif: "image",
|
||||||
|
bmp: "image",
|
||||||
|
tiff: "image",
|
||||||
|
svg: "image",
|
||||||
|
pdf: "file",
|
||||||
|
doc: "file",
|
||||||
|
docx: "file",
|
||||||
|
xls: "file",
|
||||||
|
xlsx: "file",
|
||||||
|
txt: "file",
|
||||||
|
ppt: "file",
|
||||||
|
zip: "zip",
|
||||||
|
rar: "zip",
|
||||||
|
tar: "zip",
|
||||||
|
targz: "zip",
|
||||||
|
};
|
||||||
|
return data[name.split(".")[1]] || "file";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route(to, from) {
|
||||||
|
if (this.$route.query.userId) {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectDay(newVal) {
|
||||||
|
this.getLogList();
|
||||||
|
},
|
||||||
|
disableTable(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.tableData = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
versionList(newVal) { },
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
projectListFilter() {
|
||||||
|
let now = new Date(this.selectDay).getTime();
|
||||||
|
return this.projectList.filter(
|
||||||
|
(ele) =>
|
||||||
|
new Date(ele.startDate).getTime() <= now &&
|
||||||
|
new Date(ele.endDate).getTime() >= now
|
||||||
|
);
|
||||||
|
},
|
||||||
|
totalWorkTime() {
|
||||||
|
return (
|
||||||
|
this.tableData
|
||||||
|
.map((ele) => Number(ele.workTime))
|
||||||
|
.reduce((total, now) => {
|
||||||
|
return now * 10 + total;
|
||||||
|
}, 0) / 10
|
||||||
|
).toFixed(1);
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
this.getAllProject();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.container {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topBox {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.topTitle {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topText {
|
||||||
|
color: #999999;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin: 0 5px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contentText {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noneText {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.downFileBox {
|
||||||
|
color: #1686d8;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fileBox {
|
||||||
|
img {
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -34,6 +34,7 @@
|
||||||
:highligt="true"
|
:highligt="true"
|
||||||
ref="projectRef"
|
ref="projectRef"
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
|
rowKey="projectId"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,6 +91,7 @@
|
||||||
type="month"
|
type="month"
|
||||||
format="yyyy年MM月"
|
format="yyyy年MM月"
|
||||||
:clearable="false"
|
:clearable="false"
|
||||||
|
@change="changeMonth"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="calendar-view" v-if="projectInfo">
|
<div class="calendar-view" v-if="projectInfo">
|
||||||
|
@ -106,7 +108,7 @@
|
||||||
disabled: isFutureDate(data.date) && isInProjectRange(data),
|
disabled: isFutureDate(data.date) && isInProjectRange(data),
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ data.day.split("-")[2] }}
|
{{ data.day.split("-")[1] + "/" + data.day.split("-")[2] }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-calendar>
|
</el-calendar>
|
||||||
|
@ -150,6 +152,7 @@
|
||||||
<el-button
|
<el-button
|
||||||
type="text"
|
type="text"
|
||||||
v-if="projectInfo.userId == $store.state.user.id"
|
v-if="projectInfo.userId == $store.state.user.id"
|
||||||
|
@click="logForm.workTime = logForm.max"
|
||||||
>{{ `当天剩余可分配工时:${logForm.max}人天` }}</el-button
|
>{{ `当天剩余可分配工时:${logForm.max}人天` }}</el-button
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -168,6 +171,9 @@
|
||||||
v-if="projectInfo.userId == $store.state.user.id"
|
v-if="projectInfo.userId == $store.state.user.id"
|
||||||
>
|
>
|
||||||
<el-button @click="logDialogVisible = false">取消</el-button>
|
<el-button @click="logDialogVisible = false">取消</el-button>
|
||||||
|
<el-button v-if="logForm.loggerId" type="danger" @click="delWorkLog"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
<el-button type="primary" @click="saveWorkLog">确定</el-button>
|
<el-button type="primary" @click="saveWorkLog">确定</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -220,7 +226,11 @@ export default {
|
||||||
res.data.startDate.split(" ")[0] + " 00:00:00";
|
res.data.startDate.split(" ")[0] + " 00:00:00";
|
||||||
this.projectInfo.endDate = res.data.endDate.split(" ")[0] + " 23:59:59";
|
this.projectInfo.endDate = res.data.endDate.split(" ")[0] + " 23:59:59";
|
||||||
|
|
||||||
this.selectedDate = new Date(this.projectInfo.startDate); // 设置为项目开始时间
|
if (this.projectInfo.userId == this.$store.state.user.id) {
|
||||||
|
this.selectedDate = new Date();
|
||||||
|
} else {
|
||||||
|
this.selectedDate = new Date(this.projectInfo.startDate); // 设置为项目开始时间
|
||||||
|
}
|
||||||
|
|
||||||
const res2 = await workLogApi.getLogData({
|
const res2 = await workLogApi.getLogData({
|
||||||
projectId: this.projectInfo.projectId,
|
projectId: this.projectInfo.projectId,
|
||||||
|
@ -232,13 +242,23 @@ export default {
|
||||||
this.initDateColor(first);
|
this.initDateColor(first);
|
||||||
},
|
},
|
||||||
initDateColor(first) {
|
initDateColor(first) {
|
||||||
|
let boxs = document.getElementsByClassName("date-cell");
|
||||||
|
for (var i = 0; i < boxs.length; i++) {
|
||||||
|
boxs[i].style = "";
|
||||||
|
}
|
||||||
|
|
||||||
this.logData.map((item) => {
|
this.logData.map((item) => {
|
||||||
var ele = document.getElementById(item.date.split(" ")[0]);
|
var ele = document.getElementById(item.date.split(" ")[0]);
|
||||||
|
|
||||||
if (ele) {
|
if (ele) {
|
||||||
if (item.state == -1) {
|
if (item.state == -1) {
|
||||||
ele.style = "background:#ecf5ff";
|
ele.style = "background:#ecf5ff";
|
||||||
} else {
|
} else if (item.state == 0||item.state == 1) {
|
||||||
ele.style = "background:#409eff;color:#fff";
|
ele.style = `background:linear-gradient(to right, #409eff ${
|
||||||
|
(item.workTime || 1) * 100
|
||||||
|
}% , #ecf5ff ${(item.workTime || 1) * 100}%);color:${
|
||||||
|
item.workTime > 0.65 ? "#fff" : "#333"
|
||||||
|
};`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -254,7 +274,6 @@ export default {
|
||||||
this.$modal.msgWarning("请先选择一个项目");
|
this.$modal.msgWarning("请先选择一个项目");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.handleProjectClick(this.projectInfo);
|
|
||||||
|
|
||||||
const clickedDate = new Date(data.day);
|
const clickedDate = new Date(data.day);
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
|
@ -289,9 +308,15 @@ export default {
|
||||||
projectId: this.projectInfo.projectId,
|
projectId: this.projectInfo.projectId,
|
||||||
loggerDate: this.logForm.loggerDate,
|
loggerDate: this.logForm.loggerDate,
|
||||||
});
|
});
|
||||||
this.logForm.workTime = res.data.workTime;
|
if (res.data) {
|
||||||
this.logForm.workContent = res.data.workContent;
|
this.logForm.workTime = res.data.workTime;
|
||||||
this.logForm.loggerId = res.data.loggerId;
|
this.logForm.workContent = res.data.workContent;
|
||||||
|
this.logForm.loggerId = res.data.loggerId;
|
||||||
|
} else {
|
||||||
|
this.logForm.workTime = "";
|
||||||
|
this.logForm.workContent = "";
|
||||||
|
this.logForm.loggerId = "";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.logForm.workTime = "";
|
this.logForm.workTime = "";
|
||||||
this.logForm.workContent = "";
|
this.logForm.workContent = "";
|
||||||
|
@ -300,9 +325,33 @@ export default {
|
||||||
const res = await workLogApi.getDayTime({
|
const res = await workLogApi.getDayTime({
|
||||||
loggerDate: this.logForm.loggerDate,
|
loggerDate: this.logForm.loggerDate,
|
||||||
});
|
});
|
||||||
this.logForm.max =
|
|
||||||
Number(res.data) + (Number(this.logForm.workTime) || 0);
|
this.logForm.max = (
|
||||||
|
Number(res.data) + (Number(this.logForm.workTime) || 0)
|
||||||
|
).toFixed(1);
|
||||||
this.logDialogVisible = true;
|
this.logDialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.changeMonth();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
changeMonth() {
|
||||||
|
let that = this;
|
||||||
|
this.$nextTick(async () => {
|
||||||
|
const res2 = await workLogApi.getLogData({
|
||||||
|
projectId: that.projectInfo.projectId,
|
||||||
|
startDate:
|
||||||
|
that
|
||||||
|
.moment(that.selectedDate)
|
||||||
|
.startOf("month")
|
||||||
|
.format("YYYY-MM-DD") + " 00:00:00",
|
||||||
|
endDate:
|
||||||
|
that.moment(that.selectedDate).endOf("month").format("YYYY-MM-DD") +
|
||||||
|
" 23:59:59",
|
||||||
|
userId: that.projectInfo.userId,
|
||||||
|
});
|
||||||
|
that.logData = res2.data;
|
||||||
|
that.initDateColor(1);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
isInProjectRange(data) {
|
isInProjectRange(data) {
|
||||||
if (!this.projectInfo) return false;
|
if (!this.projectInfo) return false;
|
||||||
|
@ -377,14 +426,13 @@ export default {
|
||||||
}
|
}
|
||||||
this.logDialogVisible = false;
|
this.logDialogVisible = false;
|
||||||
this.$modal.msgSuccess("操作成功");
|
this.$modal.msgSuccess("操作成功");
|
||||||
this.handleProjectClick(this.projectInfo);
|
|
||||||
const response = await workLogApi.userProject(this.projectInfo.userId);
|
const response = await workLogApi.userProject(this.projectInfo.userId);
|
||||||
this.projectList = response.data;
|
this.projectList = response.data;
|
||||||
|
this.handleProjectClick(this.projectInfo);
|
||||||
},
|
},
|
||||||
async fetchUserProjects() {
|
async fetchUserProjects() {
|
||||||
try {
|
try {
|
||||||
const response = await workLogApi.userProject(this.projectInfo.userId);
|
const response = await workLogApi.userProject(this.projectInfo.userId);
|
||||||
console.log(12333, this.projectList);
|
|
||||||
this.projectList = response.data;
|
this.projectList = response.data;
|
||||||
if (this.projectList.length) {
|
if (this.projectList.length) {
|
||||||
let arr = [];
|
let arr = [];
|
||||||
|
@ -415,6 +463,17 @@ export default {
|
||||||
//获取项目列表
|
//获取项目列表
|
||||||
this.fetchUserProjects();
|
this.fetchUserProjects();
|
||||||
},
|
},
|
||||||
|
// 删除日志
|
||||||
|
delWorkLog() {
|
||||||
|
this.$modal.confirm(`是否确认删日志`).then(async () => {
|
||||||
|
await workLogApi.delLog(this.logForm.loggerId);
|
||||||
|
this.$modal.msgSuccess("操作成功");
|
||||||
|
this.logDialogVisible = false;
|
||||||
|
this.changeMonth();
|
||||||
|
const response = await workLogApi.userProject(this.projectInfo.userId);
|
||||||
|
this.projectList = response.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route(to, from) {
|
$route(to, from) {
|
||||||
|
@ -511,22 +570,30 @@ export default {
|
||||||
color: white; /* 白色文字 */
|
color: white; /* 白色文字 */
|
||||||
padding: 5px 0; /* 增加一些内边距 */
|
padding: 5px 0; /* 增加一些内边距 */
|
||||||
}
|
}
|
||||||
|
.project-info-calendar ::v-deep .el-calendar__body th {
|
||||||
|
height: 60px !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
.project-info-calendar .calendar-view ::v-deep .el-calendar-day {
|
.project-info-calendar .calendar-view ::v-deep .el-calendar-day {
|
||||||
height: 65px; /* 增加日期单元格高度(原高度 + 5px) */
|
height: 70px; /* 增加日期单元格高度(原高度 + 5px) */
|
||||||
// padding-top: 5px;
|
// padding-top: 5px;
|
||||||
padding: 3px;
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-info-calendar .calendar-view ::v-deep .el-calendar-day.disabled {
|
.project-info-calendar .calendar-view ::v-deep .el-calendar-day.disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
.project-info-calendar .calendar-view ::v-deep table * {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
.project-info-calendar .calendar-view ::v-deep .date-cell {
|
.project-info-calendar .calendar-view ::v-deep .date-cell {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 55px;
|
line-height: 50px;
|
||||||
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-info-calendar .calendar-view ::v-deep .in-range {
|
.project-info-calendar .calendar-view ::v-deep .in-range {
|
||||||
|
@ -534,7 +601,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-info-calendar .calendar-view ::v-deep .out-range {
|
.project-info-calendar .calendar-view ::v-deep .out-range {
|
||||||
background-color: rgba(0, 0, 0, 0.05) !important;
|
background-color: rgba(0, 0, 0, 0.1) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-info-calendar .calendar-view ::v-deep .disabled {
|
.project-info-calendar .calendar-view ::v-deep .disabled {
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
<template>
|
||||||
|
<div class="layout">
|
||||||
|
<!-- 左侧树形菜单 -->
|
||||||
|
<LeftMonth
|
||||||
|
class="sidebar"
|
||||||
|
ref="leftRef"
|
||||||
|
@searchDay="searchDay"
|
||||||
|
@setDisableTable="setDisableTable"
|
||||||
|
/>
|
||||||
|
<!-- 右侧表格和筛选 -->
|
||||||
|
<RightTable
|
||||||
|
class="main-content"
|
||||||
|
ref="rightRef"
|
||||||
|
:selectDay="selectDay"
|
||||||
|
:disableTable="disableTable"
|
||||||
|
@changeCaleder="changeCaleder"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 导入子组件
|
||||||
|
import LeftMonth from "./components/leftMonth.vue";
|
||||||
|
import RightTable from "./components/rightTable.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "worklog",
|
||||||
|
components: {
|
||||||
|
LeftMonth,
|
||||||
|
RightTable,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectDay: "",
|
||||||
|
disableTable: false,
|
||||||
|
userId: this.$store.state.user.id,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.selectDay = this.moment().format("YYYY-MM-DD 00:00:00");
|
||||||
|
if (this.$route.query.userId && this.userId != this.$route.query.userId) {
|
||||||
|
this.setDisableTable(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
searchDay(data) {
|
||||||
|
this.selectDay = data;
|
||||||
|
},
|
||||||
|
setDisableTable(data) {
|
||||||
|
if (this.$route.query.userId && this.userId != this.$route.query.userId) {
|
||||||
|
data = true;
|
||||||
|
}
|
||||||
|
this.disableTable = data;
|
||||||
|
},
|
||||||
|
changeCaleder() {
|
||||||
|
this.$refs.leftRef.getLogMonth();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.layout {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
flex-grow: 1;
|
||||||
|
max-width: 320px;
|
||||||
|
width: 360px;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|