1100 lines
30 KiB
Vue
1100 lines
30 KiB
Vue
<template>
|
||
<div class="container">
|
||
<div class="topTitle">需求列表</div>
|
||
<!-- 搜索筛选区域 -->
|
||
<div class="search-filters">
|
||
<el-input v-model="filters.title" placeholder="请输入" class="filter-input">
|
||
<template #prefix>
|
||
<div>标题名称</div>
|
||
</template>
|
||
</el-input>
|
||
|
||
<el-input v-model="filters.responsiblePersonName" placeholder="请选择负责人" class="filter-input" readonly
|
||
@focus="openUser('search')">
|
||
<template #prefix>负责人</template>
|
||
</el-input>
|
||
|
||
<el-select v-model="filters.demandStatus" placeholder="不限" class="filter-select" clearable>
|
||
<template #prefix>需求状态</template>
|
||
<el-option v-for="item in statusList" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
|
||
</el-select>
|
||
|
||
<el-select v-model="filters.priority" placeholder="不限" class="filter-select" clearable>
|
||
<template #prefix>优先级</template>
|
||
<el-option v-for="item in priorityList" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
|
||
</el-select>
|
||
|
||
<div class="filter-buttons">
|
||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||
<el-button @click="handleReset">重置</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 操作按钮区域 -->
|
||
<div class="table-operations">
|
||
<el-button type="primary" @click="handleAdd">
|
||
<el-icon class="el-icon-plus" />
|
||
新建需求
|
||
</el-button>
|
||
<el-button @click="handleBatchDelete">删除</el-button>
|
||
</div>
|
||
|
||
<!-- 表格区域 -->
|
||
<el-table :data="tableData" style="width: 100%" @selection-change="handleSelectionChange" class="tableBox"
|
||
:cell-class-name="setRowClass">
|
||
<el-table-column type="selection" width="55" />
|
||
<el-table-column label="序号" width="70" type="index" />
|
||
<el-table-column label="版本号" prop="versionNumber" />
|
||
<el-table-column label="标题" prop="title" />
|
||
<el-table-column label="需求状态">
|
||
<template #default="scope">
|
||
<div>
|
||
<el-dropdown trigger="click" placement="bottom" :key="scope.row.id" @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)]">
|
||
{{
|
||
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>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="负责人" prop="responsiblePersonName">
|
||
<template #default="scope">
|
||
<div @click="openUser('change', scope.row)" style="cursor: pointer">
|
||
{{ scope.row.responsiblePersonName }}
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="预计工时(天)" prop="estimatedWorkHours" />
|
||
<el-table-column label="开始时间" prop="createTime">
|
||
<template #default="scope">
|
||
{{ scope.row.createTime.split(" ")[0] }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="结束时间" prop="endTime">
|
||
<template #default="scope">
|
||
{{ scope.row.endTime.split(" ")[0] }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="优先级" prop="priority">
|
||
<template #default="scope">
|
||
<div>
|
||
<el-dropdown trigger="click" placement="bottom" :key="scope.row.id" @command="
|
||
(data) => {
|
||
changeRow(data, 'priority', scope.row);
|
||
}
|
||
">
|
||
<span class="el-dropdown-link">
|
||
{{
|
||
priorityList.find(
|
||
(ele) => ele.dictValue == scope.row.priority
|
||
)
|
||
? priorityList.find(
|
||
(ele) => ele.dictValue == scope.row.priority
|
||
).dictLabel
|
||
: ""
|
||
}}
|
||
<i class="el-icon-arrow-down"></i>
|
||
</span>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item v-for="item in priorityList" :key="item.dictValue" :command="item.dictValue" :class="{
|
||
tableSelect2: true,
|
||
selectedItem2: item.dictValue == scope.row.priority,
|
||
}">{{ item.dictLabel }}</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="120">
|
||
<template #default="scope">
|
||
<div>
|
||
<el-button type="text" @click="handleEdit(scope.row)">
|
||
编辑
|
||
</el-button>
|
||
<el-button type="text" @click="handleDelete(scope.row)" style="color: #666">
|
||
删除
|
||
</el-button>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<div class="pagination">
|
||
<span class="total">共 {{ total }} 条</span>
|
||
<el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :total="total"
|
||
@current-change="handlePageChange" />
|
||
</div>
|
||
<SelectUser :dialogVisible="userSelectDialogVisible" :multiSelect="false" :currentSelectedUser="currentSelectedUser"
|
||
@confirm="handleUserConfirm" @close="handleUserClose" :userIdList="projectUserList" :isFilter="true"
|
||
ref="selectUserRef" />
|
||
<el-dialog :title="!editData.id ? '新建需求' : '修改需求'" :visible.sync="dialogVisibleAdd" width="660px"
|
||
:close-on-click-modal="false">
|
||
<el-form :inline="true" :rules="rules" :model="editData" label-width="80px" class="addForm" ref="ruleForm"
|
||
v-loading="fileLoading">
|
||
<el-form-item label="标题" class="longItem" prop="title">
|
||
<el-input v-model="editData.title"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="所属项目" prop="projectId">
|
||
<el-input v-model="editData.projectName" disabled></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="所属版本" prop="versionId">
|
||
<el-select v-model="editData.versionId" placeholder="请选择所属版本" clearable>
|
||
<el-option v-for="item in versionList" :key="item.nodeId" :label="item.title" :value="item.id" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="负责人" prop="responsiblePerson">
|
||
<el-input v-model="editData.responsiblePersonName" placeholder="请选择负责人" class="filter-input" readonly
|
||
@focus="openUser('add')">
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="需求状态" prop="demandStatus">
|
||
<el-select v-model="editData.demandStatus" placeholder="请选择需求状态" clearable>
|
||
<el-option v-for="item in statusList" :key="item.dictValue" :label="item.dictLabel"
|
||
:value="item.dictValue" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="优先级" prop="priority">
|
||
<el-select v-model="editData.priority" placeholder="请选择优先级" clearable>
|
||
<el-option v-for="item in priorityList" :key="item.dictValue" :label="item.dictLabel"
|
||
:value="item.dictValue" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="预计工时" prop="estimatedWorkHours">
|
||
<el-select v-model="editData.estimatedWorkHours" filterable allow-create default-first-option
|
||
placeholder="请输入预计工时" @change="changeTime" clearable>
|
||
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="开始时间" prop="createTime">
|
||
<el-date-picker @change="changeTime" v-model="editData.createTime" type="date" placeholder="选择日期"
|
||
style="width: 200px" value-format="yyyy-MM-dd 00:00:00" :picker-options="{
|
||
disabledDate: setDateRange,
|
||
}">
|
||
</el-date-picker>
|
||
</el-form-item>
|
||
<el-form-item label="结束时间" prop="endTime">
|
||
<el-date-picker v-model="editData.endTime" type="date" placeholder="选择日期" value-format="yyyy-MM-dd 23:59:59"
|
||
style="width: 200px" :picker-options="{
|
||
disabledDate: setDateRange,
|
||
}">
|
||
</el-date-picker>
|
||
</el-form-item>
|
||
<el-form-item label="附件" class="longItem" 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 editData.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>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button @click="dialogVisibleAdd = false">取消</el-button>
|
||
<el-button type="primary" @click="confirmAddDemand">确定</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { demandApi, systemApi, projectApi } from "@/utils/api";
|
||
import SelectUser from "@/components/SelectUser.vue";
|
||
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: "MainContentTable",
|
||
components: {
|
||
SelectUser,
|
||
},
|
||
props: {
|
||
projectId: "",
|
||
version: {
|
||
type: Object,
|
||
default: {},
|
||
},
|
||
projectName: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
versionList: {
|
||
type: Array,
|
||
default: [],
|
||
},
|
||
minDate: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
maxDate: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
filters: {
|
||
title: "",
|
||
responsiblePersonName: "",
|
||
demandStatus: "",
|
||
priority: "",
|
||
responsiblePersonId: "",
|
||
},
|
||
tableData: [],
|
||
selectedRows: [],
|
||
checkedRow: {},
|
||
currentPage: 1,
|
||
pageSize: 10,
|
||
total: 0,
|
||
priorityList: [],
|
||
statusList: [],
|
||
userSelectDialogVisible: false,
|
||
dialogVisibleAdd: false,
|
||
currentSelectedUser: [],
|
||
editData: {
|
||
id: "",
|
||
title: "",
|
||
versionId: "",
|
||
demandStatus: "",
|
||
responsiblePerson: "",
|
||
estimatedWorkHours: "",
|
||
createTime: "",
|
||
endTime: "",
|
||
priority: "",
|
||
projectId: "",
|
||
fileList: [],
|
||
},
|
||
token: getToken(),
|
||
fileUpload: systemApi.fileUpload,
|
||
rules: {
|
||
title: [
|
||
{ required: true, message: "请输入标题", trigger: "change" },
|
||
{
|
||
min: 3,
|
||
max: 50,
|
||
message: "长度在 3 到 50 个字符",
|
||
trigger: "blur",
|
||
},
|
||
],
|
||
demandStatus: [
|
||
{
|
||
required: true,
|
||
message: "请选择需求状态",
|
||
trigger: "change",
|
||
},
|
||
],
|
||
responsiblePerson: [
|
||
{
|
||
required: true,
|
||
message: "请选择责任人",
|
||
trigger: "change",
|
||
},
|
||
],
|
||
estimatedWorkHours: [
|
||
{
|
||
required: true,
|
||
message: "请填写预计工时",
|
||
trigger: "change",
|
||
},
|
||
],
|
||
createTime: [
|
||
{ required: true, message: "请选择开始时间", trigger: "change" },
|
||
],
|
||
endTime: [
|
||
{ required: true, message: "请选择结束时间", trigger: "change" },
|
||
],
|
||
priority: [
|
||
{ required: true, message: "请选择优先级", trigger: "change" },
|
||
],
|
||
projectId: [
|
||
{ required: true, message: "请选择所属项目", trigger: "blur" },
|
||
],
|
||
},
|
||
options: new Array(10).fill(0).map((ele, index) => ({
|
||
value: index + 1,
|
||
label: index + 1 + "天",
|
||
})),
|
||
projectUserList: [],
|
||
fileLoading: false,
|
||
filePng,
|
||
zipPng,
|
||
imagePng,
|
||
delFileArr: []
|
||
};
|
||
},
|
||
watch: {
|
||
version(newVal, oldVal) {
|
||
this.$nextTick(() => {
|
||
if (newVal?.id != oldVal?.id) {
|
||
this.filters = {
|
||
title: "",
|
||
responsiblePersonName: "",
|
||
responsiblePersonId: "",
|
||
demandStatus: "",
|
||
priority: "",
|
||
};
|
||
}
|
||
this.currentPage = 1;
|
||
this.pageSize = 10;
|
||
this.getDemandList();
|
||
});
|
||
},
|
||
projectId(newVal) {
|
||
this.editData.projectId = newVal;
|
||
this.getProjectUser();
|
||
},
|
||
projectName(newVal) {
|
||
this.editData.projectName = newVal;
|
||
},
|
||
},
|
||
methods: {
|
||
handleSearch() {
|
||
// 实现搜索逻辑
|
||
this.getDemandList();
|
||
},
|
||
handleReset() {
|
||
this.filters = {
|
||
title: "",
|
||
responsiblePersonName: "",
|
||
responsiblePersonId: "",
|
||
demandStatus: "",
|
||
priority: "",
|
||
};
|
||
this.currentPage = 1;
|
||
this.pageSize = 10;
|
||
this.getDemandList();
|
||
},
|
||
handleAdd() {
|
||
// 实现新增逻辑
|
||
|
||
this.dialogVisibleAdd = true;
|
||
this.editData = {
|
||
id: "",
|
||
title: "",
|
||
versionId: "",
|
||
demandStatus: "",
|
||
responsiblePerson: "",
|
||
estimatedWorkHours: "",
|
||
createTime: "",
|
||
endTime: "",
|
||
priority: "",
|
||
projectId: "",
|
||
fileList: [],
|
||
};
|
||
this.$nextTick(() => {
|
||
if (this.$refs.ruleForm) {
|
||
this.$refs.ruleForm.clearValidate();
|
||
}
|
||
});
|
||
this.editData.projectId = this.projectId;
|
||
if (this.version.type == 0) {
|
||
this.editData.versionId = this.version.id;
|
||
}
|
||
this.editData.projectName = this.projectName;
|
||
},
|
||
handleEdit(row) {
|
||
this.editData = Object.assign({}, row);
|
||
this.editData.projectId = this.projectId;
|
||
this.editData.projectName = this.projectName;
|
||
this.dialogVisibleAdd = true;
|
||
this.getDemandDetail(row);
|
||
// 实现编辑逻辑
|
||
},
|
||
async getDemandDetail(row) {
|
||
const res = await demandApi.getDemandDetail(row.id);
|
||
this.editData.fileList = res.data.fileList;
|
||
},
|
||
downFile(url) {
|
||
window.open(url);
|
||
},
|
||
handleDelete(row) {
|
||
// 实现删除逻辑
|
||
this.$confirm("此操作将永久删除该需求, 是否继续?", "提示", {
|
||
confirmButtonText: "确定",
|
||
cancelButtonText: "取消",
|
||
type: "warning",
|
||
})
|
||
.then(() => {
|
||
demandApi.delDemand(row.id).then((res) => {
|
||
this.$message({
|
||
type: "success",
|
||
message: "删除成功!",
|
||
});
|
||
this.resetList("del");
|
||
});
|
||
})
|
||
.catch(() => { });
|
||
},
|
||
handleBatchDelete() {
|
||
if (!this.selectedRows.length) {
|
||
this.$message({
|
||
type: "warning",
|
||
message: "请选择数据!",
|
||
});
|
||
return;
|
||
}
|
||
// 实现批量删除逻辑
|
||
this.$confirm("此操作将永久删除该需求, 是否继续?", "提示", {
|
||
confirmButtonText: "确定",
|
||
cancelButtonText: "取消",
|
||
type: "warning",
|
||
}).then(() => {
|
||
demandApi
|
||
.delDemandBatch(this.selectedRows.map((ele) => ele.id).join(","))
|
||
.then((res) => {
|
||
this.$message({
|
||
type: "success",
|
||
message: "删除成功!",
|
||
});
|
||
this.resetList("del");
|
||
});
|
||
});
|
||
},
|
||
handleSelectionChange(selection) {
|
||
this.selectedRows = selection;
|
||
},
|
||
handlePageChange(page) {
|
||
this.currentPage = page;
|
||
this.getDemandList();
|
||
// 实现页码改变逻辑
|
||
},
|
||
getStatusClass(status) {
|
||
const classMap = {
|
||
0: "wait",
|
||
1: "pending",
|
||
2: "in-progress",
|
||
3: "completed",
|
||
4: "closed",
|
||
};
|
||
return classMap[status];
|
||
},
|
||
getDemandList() {
|
||
let param = {
|
||
...this.filters,
|
||
pageSize: this.pageSize,
|
||
pageNum: this.currentPage,
|
||
};
|
||
if (this.version.type == 0) {
|
||
param.versionId = this.version.id;
|
||
} else if (this.version.type == 1) {
|
||
param.id = this.version.id;
|
||
} else if (this.version.type == 2) {
|
||
param.projectId = this.version.id;
|
||
}
|
||
demandApi.getDemandList(param).then((res) => {
|
||
this.tableData = res.rows;
|
||
this.total = res.total;
|
||
});
|
||
},
|
||
openUser(type, data) {
|
||
this.selectType = type;
|
||
if (type == "search") {
|
||
this.currentSelectedUser = [
|
||
{ 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") {
|
||
this.currentSelectedUser = [
|
||
{ userId: this.editData.responsiblePerson },
|
||
];
|
||
}
|
||
this.userSelectDialogVisible = true;
|
||
},
|
||
handleUserConfirm(data) {
|
||
if (this.selectType == "search") {
|
||
this.filters.responsiblePersonName = data[0].nickName;
|
||
this.filters.responsiblePersonId = data[0].userId;
|
||
} else if (this.selectType == "change") {
|
||
this.checkedRow.responsiblePerson = data[0].userId;
|
||
this.checkedRow.responsiblePersonName = data[0].nickName;
|
||
this.eidtDemandRow();
|
||
} else if (this.selectType == "add") {
|
||
this.editData.responsiblePersonName = data[0].nickName;
|
||
this.editData.responsiblePerson = data[0].userId;
|
||
}
|
||
},
|
||
handleUserClose() {
|
||
this.userSelectDialogVisible = false;
|
||
},
|
||
eidtDemandRow(row, label, old) {
|
||
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");
|
||
const res2 = await systemApi.getDictData("demand_priority");
|
||
this.statusList = res1.data;
|
||
this.priorityList = res2.data;
|
||
},
|
||
confirmAddDemand() {
|
||
this.$refs.ruleForm.validate((valid) => {
|
||
if (valid) {
|
||
if (
|
||
(this.editData.estimatedWorkHours + "").replace("天", "") !=
|
||
parseFloat(this.editData.estimatedWorkHours)
|
||
) {
|
||
this.$message({
|
||
message: "预计工时为数字",
|
||
type: "warning",
|
||
});
|
||
return;
|
||
}
|
||
if (
|
||
(this.editData.estimatedWorkHours * 10) % 5 != 0 ||
|
||
this.editData.estimatedWorkHours < 0.5
|
||
) {
|
||
this.$message({
|
||
message: "预计工时最小间隔为0.5天",
|
||
type: "warning",
|
||
});
|
||
return;
|
||
}
|
||
if (this.editData.id) {
|
||
demandApi.eidtDemand(this.editData).then((res) => {
|
||
this.$message({
|
||
message: "操作成功",
|
||
type: "success",
|
||
});
|
||
this.resetList("edit");
|
||
});
|
||
} else {
|
||
demandApi.addDemand(this.editData).then((res) => {
|
||
this.$message({
|
||
message: "操作成功",
|
||
type: "success",
|
||
});
|
||
this.resetList("add", res.data);
|
||
});
|
||
}
|
||
|
||
|
||
}
|
||
// }
|
||
});
|
||
},
|
||
async resetList(type, data) {
|
||
if (this.delFileArr.length) {
|
||
await systemApi.delFileBatch(this.delFileArr.join(','))
|
||
this.delFileArr = []
|
||
}
|
||
let refreshId = "";
|
||
if (type == "edit") {
|
||
if (this.editData.versionId) {
|
||
refreshId = this.versionList.find(
|
||
(ele) => this.editData.versionId == ele.id
|
||
).nodeId;
|
||
} else {
|
||
refreshId = this.editData.id + "_1";
|
||
}
|
||
} else if (type == "add") {
|
||
if (this.editData.versionId) {
|
||
refreshId = this.versionList.find(
|
||
(ele) => this.editData.versionId == ele.id
|
||
).nodeId;
|
||
} else {
|
||
refreshId = data.id + "_1";
|
||
}
|
||
} else if (type == "del") {
|
||
if (this.version.type == 0) {
|
||
refreshId = this.version.nodeId;
|
||
} else if (this.version.type == 1) {
|
||
refreshId = "";
|
||
} else if (this.version.type == 2) {
|
||
refreshId = "all";
|
||
}
|
||
}
|
||
this.$emit("refreshTree", refreshId);
|
||
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, label, old);
|
||
});
|
||
},
|
||
changeTime(val) {
|
||
this.$nextTick(() => {
|
||
let day = (this.editData.estimatedWorkHours + "").replace("天", "");
|
||
if (day != parseFloat(day) && day) {
|
||
this.$message({
|
||
message: "预计工时为数字",
|
||
type: "warning",
|
||
});
|
||
return;
|
||
}
|
||
if (this.editData.estimatedWorkHours && this.editData.createTime) {
|
||
if (day > 1) {
|
||
this.editData.endTime = this.moment(
|
||
new Date(this.editData.createTime).getTime()
|
||
)
|
||
.add(Math.ceil(day - 1), "days")
|
||
.format("YYYY-MM-DD 23:59:59");
|
||
} else {
|
||
this.editData.endTime = this.moment(
|
||
new Date(this.editData.createTime).getTime()
|
||
).format("YYYY-MM-DD 23:59:59");
|
||
}
|
||
}
|
||
});
|
||
},
|
||
setDateRange(day) {
|
||
let date = new Date(day).getTime();
|
||
if (date < Number(this.minDate) || date > Number(this.maxDate)) {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
},
|
||
// 获取项目成员
|
||
async getProjectUser() {
|
||
const res1 = await projectApi.getProjectDetail(this.projectId);
|
||
const res2 = await projectApi.getProjectUser(this.projectId);
|
||
this.projectUserList = [
|
||
res1.data.projectLeader,
|
||
...res2.data?.map((ele) => ele.userId),
|
||
];
|
||
|
||
},
|
||
setRowClass({ row }) {
|
||
if (row.demandStatus == 4) {
|
||
return "disabled";
|
||
}
|
||
},
|
||
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.editData.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.editData.fileList = this.editData.fileList.filter(
|
||
(ele) => ele.fileNewName != row.fileNewName
|
||
);
|
||
this.delFileArr.push(row.id)
|
||
this.$message({
|
||
type: 'success',
|
||
message: "删除成功!"
|
||
})
|
||
|
||
});
|
||
} else {
|
||
this.editData.fileList = this.editData.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'
|
||
}
|
||
},
|
||
created() {
|
||
this.getDictData();
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.container {
|
||
padding: 0 20px 20px;
|
||
background-color: #ffffff;
|
||
min-width: 1200px;
|
||
}
|
||
|
||
.search-filters {
|
||
display: flex;
|
||
gap: 20px;
|
||
margin-bottom: 20px;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.filter-input,
|
||
.filter-select {
|
||
width: 18%;
|
||
}
|
||
|
||
.filter-buttons {
|
||
display: flex;
|
||
// gap: 10px;
|
||
}
|
||
|
||
.table-operations {
|
||
margin-bottom: 20px;
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
::v-deep .status-tag {
|
||
.el-radio__label {
|
||
padding-left: 5px !important;
|
||
}
|
||
}
|
||
|
||
::v-deep .status-tag .el-radio__inner {
|
||
height: 18px !important;
|
||
width: 18px !important;
|
||
line-height: 18px;
|
||
text-align: center;
|
||
margin-bottom: 1px;
|
||
background: #fff !important;
|
||
|
||
&::after {
|
||
height: 10px;
|
||
width: 10px;
|
||
}
|
||
}
|
||
|
||
::v-deep .status-tag.pending .el-radio__inner {
|
||
border-color: #ff7d00;
|
||
|
||
&::after {
|
||
background-color: #ff7d00 !important;
|
||
}
|
||
}
|
||
|
||
::v-deep .status-tag.in-progress .el-radio__inner {
|
||
border-color: #4096ff !important;
|
||
|
||
&::after {
|
||
background-color: #4096ff !important;
|
||
}
|
||
}
|
||
|
||
::v-deep .status-tag.completed .el-radio__inner {
|
||
border-color: #50b6aa !important;
|
||
|
||
&::after {
|
||
background-color: #50b6aa !important;
|
||
}
|
||
}
|
||
|
||
::v-deep .status-tag.closed .el-radio__inner {
|
||
border-color: #ccc !important;
|
||
|
||
&::after {
|
||
background-color: #ccc !important;
|
||
}
|
||
}
|
||
|
||
::v-deep .status-tag.wait .el-radio__inner {
|
||
border-color: #999 !important;
|
||
|
||
&::after {
|
||
background-color: #999 !important;
|
||
}
|
||
}
|
||
|
||
::v-deep .status-tag.pending .el-radio__label {
|
||
color: #ff7d00 !important;
|
||
// background-color: #fff7e6;
|
||
}
|
||
|
||
::v-deep .status-tag.in-progress .el-radio__label {
|
||
color: #4096ff !important;
|
||
// background-color: #e6f4ff;
|
||
}
|
||
|
||
::v-deep .status-tag.completed .el-radio__label {
|
||
color: #50b6aa !important;
|
||
// background-color: #e6f7f5;
|
||
}
|
||
|
||
::v-deep .status-tag.wait .el-radio__label {
|
||
color: #999 !important;
|
||
// background-color: #f5f5f5;
|
||
}
|
||
|
||
::v-deep .status-tag.closed .el-radio__label {
|
||
color: #ccc !important;
|
||
}
|
||
|
||
.pagination {
|
||
margin-top: 20px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.total {
|
||
color: #666666;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
::v-deep .disabled.el-table__cell {
|
||
color: #ccc;
|
||
|
||
.el-dropdown-link {
|
||
color: #ccc;
|
||
}
|
||
}
|
||
|
||
::v-deep .el-button {
|
||
border-radius: 4px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
::v-deep .el-table {
|
||
border: 1px solid #eeeeee;
|
||
}
|
||
|
||
::v-deep .el-table th {
|
||
background-color: #fafafa !important;
|
||
color: #666666;
|
||
font-weight: 600;
|
||
}
|
||
|
||
::v-deep .el-table td {
|
||
color: #333333;
|
||
}
|
||
|
||
::v-deep .el-input__prefix {
|
||
color: #999999;
|
||
line-height: 35px;
|
||
padding-left: 10px !important;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.search-filters ::v-deep .el-input__inner {
|
||
padding-left: 80px !important;
|
||
|
||
::placeholder {
|
||
color: #bbb;
|
||
}
|
||
}
|
||
|
||
::v-deep .el-button--primary {
|
||
background-color: #4096ff;
|
||
}
|
||
|
||
::v-deep .el-pagination .el-pager li.is-active {
|
||
border-color: #4096ff;
|
||
background-color: #4096ff;
|
||
}
|
||
|
||
::v-deep .addForm {
|
||
.el-input__inner {
|
||
// width: 100%;
|
||
width: 200px;
|
||
}
|
||
|
||
.el-form-item {
|
||
width: 48%;
|
||
}
|
||
|
||
.el-input--prefix .el-input__inner {
|
||
padding-left: 40px;
|
||
}
|
||
}
|
||
|
||
::v-deep .longItem {
|
||
width: 100% !important;
|
||
|
||
.el-form-item__content {
|
||
width: 82.2%;
|
||
|
||
.el-input__inner {
|
||
width: 100%;
|
||
}
|
||
}
|
||
}
|
||
|
||
.tableSelect1 {
|
||
width: 150px;
|
||
text-align: left !important;
|
||
}
|
||
|
||
.tableSelect2 {
|
||
width: 100px;
|
||
text-align: left !important;
|
||
}
|
||
|
||
.selectedItem1 {
|
||
&::after {
|
||
content: "✔";
|
||
width: 10px;
|
||
height: 10px;
|
||
position: absolute;
|
||
right: 10px;
|
||
color: #4096ff;
|
||
}
|
||
}
|
||
|
||
.selectedItem2 {
|
||
color: #4096ff;
|
||
position: relative;
|
||
|
||
&::after {
|
||
content: "✔";
|
||
width: 10px;
|
||
height: 10px;
|
||
position: absolute;
|
||
right: 10px;
|
||
color: #4096ff;
|
||
}
|
||
}
|
||
|
||
.tableBox {
|
||
.el-radio {
|
||
margin-left: 0;
|
||
}
|
||
}
|
||
|
||
.topTitle {
|
||
padding: 0 20px 20px;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.fileRow {
|
||
height: 38px;
|
||
padding: 0 10px;
|
||
border: 1px solid #ccc;
|
||
border-radius: 5px;
|
||
margin-bottom: 10px;
|
||
|
||
.del {
|
||
font-size: 16px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
img {
|
||
height: 18px;
|
||
}
|
||
}
|
||
|
||
.fileItem {
|
||
gap: 10px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.fileBox {
|
||
max-height: 200px;
|
||
overflow: auto;
|
||
padding-right: 10px;
|
||
}
|
||
</style>
|