日志完成80%

v1.2.0
rdpnr_hemingxia 2025-03-26 17:58:58 +08:00
parent f9a402e991
commit da50ed138f
7 changed files with 539 additions and 185 deletions

View File

@ -234,11 +234,11 @@ export const demandApi = {
data: data,
}),
delDemand: (data) => request({
url: `/demand//${data}`,
url: `/demand/${data}`,
method: 'delete',
}),
delDemandBatch: (data) => request({
url: `/demand/remove/batch?ids=${data}`,
url: `/demand/remove/batch/${data}`,
method: 'delete',
}),

View File

@ -74,7 +74,7 @@
class="tableBox"
>
<el-table-column type="selection" width="55" />
<el-table-column label="序号" width="70" prop="id" />
<el-table-column label="序号" width="70" type="index" />
<el-table-column label="版本号" prop="versionNumber" />
<el-table-column label="标题" prop="title" />
<el-table-column label="需求状态">
@ -83,6 +83,7 @@
<el-dropdown
trigger="click"
placement="bottom"
:disabled="scope.row.demandStatus == 4"
@command="
(data) => {
changeRow(data, 'demandStatus', scope.row);
@ -151,6 +152,7 @@
<el-dropdown
trigger="click"
placement="bottom"
:disabled="scope.row.demandStatus == 4"
@command="
(data) => {
changeRow(data, 'priority', scope.row);
@ -491,6 +493,13 @@ export default {
this.editData.projectName = this.projectName;
},
handleEdit(row) {
if (row.demandStatus == 4) {
this.$message({
type: "warning",
message: "需求已关闭,无法编辑!",
});
return;
}
this.editData = row;
this.editData.projectId = this.projectId;
this.editData.projectName = this.projectName;
@ -580,6 +589,13 @@ export default {
{ userId: this.filters.responsiblePersonId },
];
} else if (type == "change") {
if (data.demandStatus == 4) {
this.$message({
type: "warning",
message: "需求关闭后无法编辑!",
});
return;
}
this.checkedRow = data;
this.currentSelectedUser = [{ userId: data.responsiblePerson }];
} else if (type == "add") {
@ -605,14 +621,44 @@ export default {
handleUserClose() {
this.userSelectDialogVisible = false;
},
eidtDemandRow() {
demandApi.eidtDemand(this.checkedRow).then((res) => {
this.$message({
message: "修改成功",
type: "success",
});
this.getDemandList();
});
eidtDemandRow(row, label, old) {
if (this.checkedRow.demandStatus == 4) {
this.$confirm("需求关闭后将无法操作和使用, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
demandApi
.eidtDemand(this.checkedRow)
.then((res) => {
this.$message({
message: "修改成功",
type: "success",
});
this.getDemandList();
})
.catch((res) => {
row[label] = old;
});
})
.catch(() => {
row[label] = old;
});
} else {
demandApi
.eidtDemand(this.checkedRow)
.then((res) => {
this.$message({
message: "修改成功",
type: "success",
});
this.getDemandList();
})
.catch((res) => {
row[label] = old;
});
}
},
async getDictData() {
const res1 = await systemApi.getDictData("demand_status");
@ -624,7 +670,7 @@ export default {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
if (
this.editData.estimatedWorkHours.replace("天", "") !=
(this.editData.estimatedWorkHours + "").replace("天", "") !=
parseFloat(this.editData.estimatedWorkHours)
) {
this.$message({
@ -643,23 +689,48 @@ export default {
});
return;
}
if (this.editData.id) {
demandApi.eidtDemand(this.editData).then((res) => {
this.$message({
message: "操作成功",
type: "success",
});
this.resetList();
if (this.editData.demandStatus == 4) {
this.$confirm("需求关闭后将无法操作和使用, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
if (this.editData.id) {
demandApi.eidtDemand(this.editData).then((res) => {
this.$message({
message: "操作成功",
type: "success",
});
this.resetList();
});
} else {
demandApi.addDemand(this.editData).then((res) => {
this.$message({
message: "操作成功",
type: "success",
});
this.resetList();
});
}
});
} else {
demandApi.addDemand(this.editData).then((res) => {
this.$message({
message: "操作成功",
type: "success",
if (this.editData.id) {
demandApi.eidtDemand(this.editData).then((res) => {
this.$message({
message: "操作成功",
type: "success",
});
this.resetList();
});
this.resetList();
});
} else {
demandApi.addDemand(this.editData).then((res) => {
this.$message({
message: "操作成功",
type: "success",
});
this.resetList();
});
}
}
}
});
@ -677,16 +748,20 @@ export default {
this.dialogVisibleAdd = false;
},
changeRow(value, label, row) {
if (value == row[label]) {
return;
}
let old = row[label];
row[label] = value;
this.checkedRow = row;
this.$nextTick(() => {
this.eidtDemandRow(row);
this.eidtDemandRow(row, label, old);
});
},
changeTime(val) {
this.$nextTick(() => {
let day = (this.editData.estimatedWorkHours + "").replace("天", "");
if (day != parseFloat(day)&&day) {
if (day != parseFloat(day) && day) {
this.$message({
message: "预计工时为数字",
type: "warning",
@ -705,8 +780,6 @@ export default {
new Date(this.editData.createTime).getTime()
).format("YYYY-MM-DD 23:59:59");
}
console.log(this.editData.endTime);
}
});
},

View File

@ -97,7 +97,7 @@
}
"
>
<i class="el-icon-more" style="font-size: 20px;"></i>
<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>
@ -179,7 +179,7 @@ export default {
});
if (defaultId && defaultId != "all") {
if (defaultId == -1) {
this.defaultExpend = res.data[res.data.length - 1].nodeId;
this.defaultExpend = [res.data[res.data.length - 1].nodeId];
} else {
this.defaultExpend = [defaultId];
}
@ -377,7 +377,7 @@ export default {
.el-tree-node__content {
height: 42px;
}
.el-tree-node__expand-icon{
:not(.is-leaf.el-tree-node__expand-icon ) {
font-size: 16px;
color: #333;
}

View File

@ -52,8 +52,6 @@ export default {
this.$refs.treeRef.getVersionTree(defaultId);
},
addDemand() {
console.log(566);
this.$refs.rightRef.handleAdd();
},
},

View File

@ -24,7 +24,21 @@
</div>
</div>
<el-calendar v-model="selectedDate" />
<el-calendar v-model="selectedDate">
<template #dateCell="{ data }">
<div
:key="data.day"
:id="data.day"
@click="searchLog(data, isOverDay(data.day))"
:class="{
dayBox: true,
disabled: isOverDay(data.day),
}"
>
{{ data.day.split("-")[2] }}
</div>
</template>
</el-calendar>
</div>
</template>
@ -36,6 +50,7 @@ export default {
data() {
return {
selectedDate: this.moment(new Date()).format("YYYY-MM-DD"),
nowDay: this.moment(new Date()).format("YYYY-MM-DD"),
};
},
methods: {
@ -50,7 +65,24 @@ export default {
.add(1, "months")
.format("YYYY-MM-DD");
},
},
searchLog(data, overDay) {
this.$nextTick(() => {
if (overDay) {
this.$message({
message: "不能超过当前时间",
type: "warning",
});
this.$emit("setDisableTable", true);
} else {
this.$emit("setDisableTable", false);
this.$emit("searchDay", data.day + " 00:00:00");
}
});
},
isOverDay(data) {
return new Date(data).getTime() > new Date(this.nowDay).getTime();
},
}
};
</script>
@ -81,11 +113,14 @@ export default {
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;
}
@ -103,7 +138,6 @@ export default {
height: 40px;
width: 40px;
line-height: 40px;
border-radius: 50% !important;
&:hover {
background-color: #88bdfd;
@ -123,4 +157,11 @@ export default {
cursor: pointer;
}
}
.leftBox ::v-deep .disabled {
background-color: #fff !important;
color: #c0c4cc;
cursor: not-allowed;
border-radius: 50% !important;
background-color: #fff;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div class="container">
<div class="topBox">
<div class="topBox" v-show="!disableTable">
<div>
<div class="topTitle">当日日志</div>
<div class="topText">总计填报工时:<span>1</span></div>
@ -14,180 +14,165 @@
</div>
<!-- 表格区域 -->
<el-table
:data="tableData"
style="width: 100%"
class="tableBox"
>
<el-table-column label="序号" width="70" prop="id" />
<el-table-column label="项目名称" prop="versionNumber">
<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>
<el-dropdown
trigger="click"
placement="bottom"
@command="
(data) => {
changeRow(data, 'demandStatus', scope.row);
}
"
>
<el-radio
v-model="scope.row.demandStatus"
:label="scope.row.demandStatus"
:class="['status-tag', getStatusClass(scope.row.demandStatus)]"
<div v-if="scope.row.edit">
<el-select
v-model="scope.row.projectId"
placeholder="时间匹配的项目"
class="filter-select"
@change="
(val) => {
getVersionList(val, scope.row);
}
"
>
{{
statusList[scope.row.demandStatus]
? statusList[scope.row.demandStatus].dictLabel
: ""
}}</el-radio
>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item in statusList"
:key="item.dictValue"
:command="item.dictValue"
:class="{
tableSelect1: true,
selectedItem1: item.dictValue == scope.row.demandStatus,
}"
><el-radio
v-model="scope.row.demandStatus"
:label="scope.row.demandStatus"
:class="['status-tag', getStatusClass(item.dictValue)]"
>
{{
statusList[item.dictValue]
? statusList[item.dictValue].dictLabel
: ""
}}</el-radio
></el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
<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="title">
<el-table-column label="版本" prop="versionNumber">
<template #default="scope">
<div>
<el-dropdown
trigger="click"
placement="bottom"
@command="
(data) => {
changeRow(data, 'demandStatus', scope.row);
}
"
>
<el-radio
v-model="scope.row.demandStatus"
:label="scope.row.demandStatus"
:class="['status-tag', getStatusClass(scope.row.demandStatus)]"
<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);
}
"
>
{{
statusList[scope.row.demandStatus]
? statusList[scope.row.demandStatus].dictLabel
: ""
}}</el-radio
>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item in statusList"
:key="item.dictValue"
:command="item.dictValue"
:class="{
tableSelect1: true,
selectedItem1: item.dictValue == scope.row.demandStatus,
}"
><el-radio
v-model="scope.row.demandStatus"
:label="scope.row.demandStatus"
:class="['status-tag', getStatusClass(item.dictValue)]"
>
{{
statusList[item.dictValue]
? statusList[item.dictValue].dictLabel
: ""
}}</el-radio
></el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
<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>
<el-dropdown
trigger="click"
placement="bottom"
@command="
(data) => {
changeRow(data, 'demandStatus', scope.row);
}
"
>
<el-radio
v-model="scope.row.demandStatus"
:label="scope.row.demandStatus"
:class="['status-tag', getStatusClass(scope.row.demandStatus)]"
<div v-if="scope.row.edit">
<el-select
v-model="scope.row.demandId"
placeholder="进行中且时间匹配的需求"
class="filter-select"
@change="openContent"
ref="demandSelectRef"
>
{{
statusList[scope.row.demandStatus]
? statusList[scope.row.demandStatus].dictLabel
: ""
}}</el-radio
>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item in statusList"
:key="item.dictValue"
:command="item.dictValue"
:class="{
tableSelect1: true,
selectedItem1: item.dictValue == scope.row.demandStatus,
}"
><el-radio
v-model="scope.row.demandStatus"
:label="scope.row.demandStatus"
:class="['status-tag', getStatusClass(item.dictValue)]"
>
{{
statusList[item.dictValue]
? statusList[item.dictValue].dictLabel
: ""
}}</el-radio
></el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
<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="responsiblePersonName">
<el-table-column label="工作内容" prop="workContent">
<template #default="scope">
<div @click="openUser('change', scope.row)" style="cursor: pointer">
{{ scope.row.responsiblePersonName }}
<div @click="openContent">
<el-popover
v-if="scope.row.edit"
placement="bottom"
width="400"
trigger="click"
v-model="showContent"
:key="scope.row.loggerId"
>
<el-input
type="textarea"
:rows="5"
placeholder="请输入内容"
v-model="scope.row.workContent"
:disabled="!scope.row.edit"
>
</el-input>
<div slot="reference">
<div
style="cursor: pointer"
:class="{
contentText: true,
noneText: !scope.row.workContent,
}"
>
{{ scope.row.workContent || "请输入" }}
</div>
</div>
</el-popover>
<div
v-show="!scope.row.edit"
style="cursor: pointer"
:class="{
contentText: true,
noneText: !scope.row.workContent,
}"
>
{{ scope.row.workContent || "请输入" }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="工时分配" prop="estimatedWorkHours" />
<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="120">
<template #default="scope">
<div>
<el-button type="text" @click="handleEdit(scope.row)">
编辑
{{ scope.row.loggerId && !scope.row.edit ? "编辑" : "确认" }}
</el-button>
<el-button
type="text"
@click="handleDelete(scope.row)"
@click="handleDelete(scope.row, scope.$index)"
style="color: #666"
>
删除
{{ scope.row.loggerId && !scope.row.edit ? "删除" : "取消" }}
</el-button>
</div>
</template>
@ -197,13 +182,240 @@
</template>
<script>
import { demandApi, workLogApi, projectApi } from "@/utils/api";
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: [],
showContent: false,
};
},
methods: {
init() {
if (this.$route.query.userId) {
this.userId = this.$route.query.userId;
this.userName = this.$route.query.nickName;
this.projectId = this.$route.porjectId;
}
//
},
getLogList() {
workLogApi
.getLogDataDetail({
createBy: this.userId,
loggerDate: this.selectDay,
projectId: this.projectId,
})
.then((res) => {
this.tableData = res.data.map((ele) => {
ele.edit = false;
return ele;
});
});
},
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();
});
})
.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.getDayTime("add");
},
async handleEdit(row) {
if (this.tableData.filter((ele) => ele.edit).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.$modal.msgSuccess("操作成功");
row.edit = false;
this.getLogList();
} else {
row.edit = true;
this.getDayTime("edit", row);
this.getVersionList(row.projectId, row, true);
}
},
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,
};
this.computedTime(0);
this.tableData.push(row);
} else {
this.computedTime(row.workTime);
}
},
computedTime(time) {
let length = (this.hasTimeLong + (Number(time) || 0)).toFixed(1);
this.workTimeList = new Array((length * 10) / 1)
.fill(0)
.map((ele, index) => {
return (index + 1) / 10;
});
},
getVersionList(val, row, isOpen) {
if (!isOpen) row.versionId = "";
this.$nextTick(async () => {
const res = await demandApi.getVersionTree({
projectId: val,
userId: this.userId,
demandStatusList: [2],
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 = "";
console.log(222, this.versionList);
if (this.versionList.find((ele) => ele.id == val)) {
this.demandList = this.versionList.find(
(ele) => ele.id == val
).childrenList;
} else {
this.demandList = [];
}
if (!isOpen) this.$refs.demandSelectRef.toggleMenu();
},
openContent() {
console.log(123);
this.showContent = true;
},
},
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 &&
ele.projectState == 1
);
},
},
mounted() {
this.init();
this.getAllProject();
},
};
</script>
@ -234,4 +446,12 @@ export default {
}
}
}
.contentText {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.noneText {
color: #999;
}
</style>

View File

@ -1,9 +1,19 @@
<template>
<div class="layout">
<!-- 左侧树形菜单 -->
<LeftMonth class="sidebar" ref="leftRef" />
<LeftMonth
class="sidebar"
ref="leftRef"
@searchDay="searchDay"
@setDisableTable="setDisableTable"
/>
<!-- 右侧表格和筛选 -->
<RightTable class="main-content" ref="rightRef" />
<RightTable
class="main-content"
ref="rightRef"
:selectDay="selectDay"
:disableTable="disableTable"
/>
</div>
</template>
@ -19,10 +29,22 @@ export default {
RightTable,
},
data() {
return {};
return {
selectDay: "",
disableTable: false,
};
},
methods: {
searchDay(data) {
this.selectDay = data;
},
setDisableTable(data) {
this.disableTable = data;
},
},
mounted() {
this.selectDay = this.moment().format("YYYY-MM-DD 00:00:00");
},
methods: {},
mounted() {},
};
</script>