文件调试完成

考核看板初步完成
dev
rdpnr_hemingxia 2025-04-25 18:04:28 +08:00
parent b1251e3bc5
commit b3bd2eff61
11 changed files with 1664 additions and 950 deletions

View File

@ -121,6 +121,11 @@ export default {
type: Array, type: Array,
default: () => [], default: () => [],
}, },
isFilter: {
type: Boolean,
default: false,
},
}, },
data() { data() {
return { return {
@ -346,7 +351,9 @@ export default {
}, },
mounted() { mounted() {
this.fetchTreeData(); this.fetchTreeData();
this.fetchUserList(); if(!this.isFilter){
this.fetchUserList();
}
}, },
}; };
</script> </script>

View File

@ -134,7 +134,7 @@ export const systemApi = {
url: '/system/user/deptTree', url: '/system/user/deptTree',
method: 'get', method: 'get',
}), }),
fileUpload: '/common/upload', fileUpload: process.env.NODE_ENV == 'development' ? '/common/upload' : '/prod-api/common/upload',
downFile: (data) => request({ downFile: (data) => request({
url: '/common/download', url: '/common/download',
method: 'get', method: 'get',
@ -145,6 +145,11 @@ export const systemApi = {
method: 'delete', method: 'delete',
}), }),
delFileBatch: (id) => request({
url: `/business/project/file/batch/${id}`,
method: 'delete',
}),
} }
@ -195,16 +200,26 @@ export const taskApi = {
url: `/task/${id}`, url: `/task/${id}`,
method: 'delete', method: 'delete',
}), }),
delTaskModule: (id) => request({
url: `/examine/template/${id}`,
method: 'delete',
}),
getTaskSet: (id) => request({ getTaskSet: (id) => request({
url: `/task/target/${id}`, url: `/task/target/${id}`,
method: 'get', method: 'get',
}), }),
setTaskSet: (data) => request({ getTaskModel: (data) => request({
url: `/task/config/update`, url: `/examine/template/list`,
method: 'put', method: 'get',
data: data, params: data,
}), }),
// 获取模板配置
getTaskModelSet: (id) => request({
url: `/examine/template/list/${id}`,
method: 'get',
}),
@ -250,7 +265,7 @@ export const demandApi = {
url: `/demand/${data}`, url: `/demand/${data}`,
method: 'delete', method: 'delete',
}), }),
getDemandDetail:(id) => request({ getDemandDetail: (id) => request({
url: `/demand/${id}`, url: `/demand/${id}`,
method: 'get', method: 'get',
}), }),

View File

@ -3,54 +3,25 @@
<div class="topTitle">需求列表</div> <div class="topTitle">需求列表</div>
<!-- 搜索筛选区域 --> <!-- 搜索筛选区域 -->
<div class="search-filters"> <div class="search-filters">
<el-input <el-input v-model="filters.title" placeholder="请输入" class="filter-input">
v-model="filters.title"
placeholder="请输入"
class="filter-input"
>
<template #prefix> <template #prefix>
<div>标题名称</div> <div>标题名称</div>
</template> </template>
</el-input> </el-input>
<el-input <el-input v-model="filters.responsiblePersonName" placeholder="请选择负责人" class="filter-input" readonly
v-model="filters.responsiblePersonName" @focus="openUser('search')">
placeholder="请选择负责人"
class="filter-input"
readonly
@focus="openUser('search')"
>
<template #prefix>负责人</template> <template #prefix>负责人</template>
</el-input> </el-input>
<el-select <el-select v-model="filters.demandStatus" placeholder="不限" class="filter-select" clearable>
v-model="filters.demandStatus"
placeholder="不限"
class="filter-select"
clearable
>
<template #prefix>需求状态</template> <template #prefix>需求状态</template>
<el-option <el-option v-for="item in statusList" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
v-for="item in statusList"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select> </el-select>
<el-select <el-select v-model="filters.priority" placeholder="不限" class="filter-select" clearable>
v-model="filters.priority"
placeholder="不限"
class="filter-select"
clearable
>
<template #prefix>优先级</template> <template #prefix>优先级</template>
<el-option <el-option v-for="item in priorityList" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
v-for="item in priorityList"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select> </el-select>
<div class="filter-buttons"> <div class="filter-buttons">
@ -69,13 +40,8 @@
</div> </div>
<!-- 表格区域 --> <!-- 表格区域 -->
<el-table <el-table :data="tableData" style="width: 100%" @selection-change="handleSelectionChange" class="tableBox"
:data="tableData" :cell-class-name="setRowClass">
style="width: 100%"
@selection-change="handleSelectionChange"
class="tableBox"
:cell-class-name="setRowClass"
>
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column label="序号" width="70" type="index" /> <el-table-column label="序号" width="70" type="index" />
<el-table-column label="版本号" prop="versionNumber" /> <el-table-column label="版本号" prop="versionNumber" />
@ -83,48 +49,29 @@
<el-table-column label="需求状态"> <el-table-column label="需求状态">
<template #default="scope"> <template #default="scope">
<div> <div>
<el-dropdown <el-dropdown trigger="click" placement="bottom" :key="scope.row.id" @command="
trigger="click" (data) => {
placement="bottom" changeRow(data, 'demandStatus', scope.row);
:key="scope.row.id" }
@command=" ">
(data) => { <el-radio v-model="scope.row.demandStatus" :label="scope.row.demandStatus"
changeRow(data, 'demandStatus', scope.row); :class="['status-tag', getStatusClass(scope.row.demandStatus)]">
}
"
>
<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]
? statusList[scope.row.demandStatus].dictLabel ? statusList[scope.row.demandStatus].dictLabel
: "" : ""
}}</el-radio }}</el-radio>
>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item <el-dropdown-item v-for="item in statusList" :key="item.dictValue" :command="item.dictValue" :class="{
v-for="item in statusList" tableSelect1: true,
:key="item.dictValue" selectedItem1: item.dictValue == scope.row.demandStatus,
:command="item.dictValue" }"><el-radio v-model="scope.row.demandStatus" :label="scope.row.demandStatus"
:class="{ :class="['status-tag', getStatusClass(item.dictValue)]">
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]
? statusList[item.dictValue].dictLabel ? statusList[item.dictValue].dictLabel
: "" : ""
}}</el-radio }}</el-radio></el-dropdown-item>
></el-dropdown-item
>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>
@ -152,39 +99,28 @@
<el-table-column label="优先级" prop="priority"> <el-table-column label="优先级" prop="priority">
<template #default="scope"> <template #default="scope">
<div> <div>
<el-dropdown <el-dropdown trigger="click" placement="bottom" :key="scope.row.id" @command="
trigger="click" (data) => {
placement="bottom" changeRow(data, 'priority', scope.row);
:key="scope.row.id" }
@command=" ">
(data) => {
changeRow(data, 'priority', scope.row);
}
"
>
<span class="el-dropdown-link"> <span class="el-dropdown-link">
{{ {{
priorityList.find( priorityList.find(
(ele) => ele.dictValue == scope.row.priority (ele) => ele.dictValue == scope.row.priority
) )
? priorityList.find( ? priorityList.find(
(ele) => ele.dictValue == scope.row.priority (ele) => ele.dictValue == scope.row.priority
).dictLabel ).dictLabel
: "" : ""
}} }}
<i class="el-icon-arrow-down"></i> <i class="el-icon-arrow-down"></i>
</span> </span>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item <el-dropdown-item v-for="item in priorityList" :key="item.dictValue" :command="item.dictValue" :class="{
v-for="item in priorityList" tableSelect2: true,
:key="item.dictValue" selectedItem2: item.dictValue == scope.row.priority,
:command="item.dictValue" }">{{ item.dictLabel }}</el-dropdown-item>
:class="{
tableSelect2: true,
selectedItem2: item.dictValue == scope.row.priority,
}"
>{{ item.dictLabel }}</el-dropdown-item
>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>
@ -196,11 +132,7 @@
<el-button type="text" @click="handleEdit(scope.row)"> <el-button type="text" @click="handleEdit(scope.row)">
编辑 编辑
</el-button> </el-button>
<el-button <el-button type="text" @click="handleDelete(scope.row)" style="color: #666">
type="text"
@click="handleDelete(scope.row)"
style="color: #666"
>
删除 删除
</el-button> </el-button>
</div> </div>
@ -211,36 +143,16 @@
<!-- 分页 --> <!-- 分页 -->
<div class="pagination"> <div class="pagination">
<span class="total"> {{ total }} </span> <span class="total"> {{ total }} </span>
<el-pagination <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :total="total"
v-model:current-page="currentPage" @current-change="handlePageChange" />
v-model:page-size="pageSize"
:total="total"
@current-change="handlePageChange"
/>
</div> </div>
<SelectUser <SelectUser :dialogVisible="userSelectDialogVisible" :multiSelect="false" :currentSelectedUser="currentSelectedUser"
:dialogVisible="userSelectDialogVisible" @confirm="handleUserConfirm" @close="handleUserClose" :userIdList="projectUserList" :isFilter="true"
:multiSelect="false" ref="selectUserRef" />
:currentSelectedUser="currentSelectedUser" <el-dialog :title="!editData.id ? '新建需求' : '修改需求'" :visible.sync="dialogVisibleAdd" width="660px"
@confirm="handleUserConfirm" :close-on-click-modal="false">
@close="handleUserClose" <el-form :inline="true" :rules="rules" :model="editData" label-width="80px" class="addForm" ref="ruleForm"
:userIdList="projectUserList" v-loading="fileLoading">
/>
<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-form-item label="标题" class="longItem" prop="title">
<el-input v-model="editData.title"></el-input> <el-input v-model="editData.title"></el-input>
</el-form-item> </el-form-item>
@ -248,136 +160,66 @@
<el-input v-model="editData.projectName" disabled></el-input> <el-input v-model="editData.projectName" disabled></el-input>
</el-form-item> </el-form-item>
<el-form-item label="所属版本" prop="versionId"> <el-form-item label="所属版本" prop="versionId">
<el-select <el-select v-model="editData.versionId" placeholder="请选择所属版本" clearable>
v-model="editData.versionId" <el-option v-for="item in versionList" :key="item.nodeId" :label="item.title" :value="item.id" />
placeholder="请选择所属版本"
clearable
>
<el-option
v-for="item in versionList"
:key="item.nodeId"
:label="item.title"
:value="item.id"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="负责人" prop="responsiblePerson"> <el-form-item label="负责人" prop="responsiblePerson">
<el-input <el-input v-model="editData.responsiblePersonName" placeholder="请选择负责人" class="filter-input" readonly
v-model="editData.responsiblePersonName" @focus="openUser('add')">
placeholder="请选择负责人"
class="filter-input"
readonly
@focus="openUser('add')"
>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label="需求状态" prop="demandStatus"> <el-form-item label="需求状态" prop="demandStatus">
<el-select <el-select v-model="editData.demandStatus" placeholder="请选择需求状态" clearable>
v-model="editData.demandStatus" <el-option v-for="item in statusList" :key="item.dictValue" :label="item.dictLabel"
placeholder="请选择需求状态" :value="item.dictValue" />
clearable
>
<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 label="优先级" prop="priority"> <el-form-item label="优先级" prop="priority">
<el-select <el-select v-model="editData.priority" placeholder="请选择优先级" clearable>
v-model="editData.priority" <el-option v-for="item in priorityList" :key="item.dictValue" :label="item.dictLabel"
placeholder="请选择优先级" :value="item.dictValue" />
clearable
>
<el-option
v-for="item in priorityList"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="预计工时" prop="estimatedWorkHours"> <el-form-item label="预计工时" prop="estimatedWorkHours">
<el-select <el-select v-model="editData.estimatedWorkHours" filterable allow-create default-first-option
v-model="editData.estimatedWorkHours" placeholder="请输入预计工时" @change="changeTime" clearable>
filterable <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
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-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="开始时间" prop="createTime"> <el-form-item label="开始时间" prop="createTime">
<el-date-picker <el-date-picker @change="changeTime" v-model="editData.createTime" type="date" placeholder="选择日期"
@change="changeTime" style="width: 200px" value-format="yyyy-MM-dd 00:00:00" :picker-options="{
v-model="editData.createTime"
type="date"
placeholder="选择日期"
style="width: 200px"
value-format="yyyy-MM-dd 00:00:00"
:picker-options="{
disabledDate: setDateRange, disabledDate: setDateRange,
}" }">
>
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="结束时间" prop="endTime"> <el-form-item label="结束时间" prop="endTime">
<el-date-picker <el-date-picker v-model="editData.endTime" type="date" placeholder="选择日期" value-format="yyyy-MM-dd 23:59:59"
v-model="editData.endTime" style="width: 200px" :picker-options="{
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd 23:59:59"
style="width: 200px"
:picker-options="{
disabledDate: setDateRange, disabledDate: setDateRange,
}" }">
>
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="附件" class="longItem" prop="endTime"> <el-form-item label="附件" class="longItem" prop="fileList">
<div> <div>
<el-upload <el-upload class="upload-demo" ref="upload" :action="fileUpload" :show-file-list="false" :auto-upload="true"
class="upload-demo" :multiple="true" :before-upload="beforeUpload" :on-success="successUpload" :headers="{
ref="upload"
:action="fileUpload"
:show-file-list="false"
:auto-upload="true"
:multiple="true"
:before-upload="beforeUpload"
:on-success="successUpload"
:headers="{
Authorization: 'Bearer ' + token, Authorization: 'Bearer ' + token,
}" }" :data="{}">
:data="{}" <div class="flex-row aic" style="gap: 10px;margin-bottom: 10px;">
> <el-button slot="trigger" size="small" type="default"
<div class="flex-row aic" style="gap: 10px;margin-bottom: 10px;"> style="width: 200px;color: #333;font-weight: 500;">上传附件</el-button>
<el-button slot="trigger" size="small" type="default" style="width: 200px;color: #333;font-weight: 500;" <div slot="tip" style="color: #999999;font-size: 12px;">单个附件限制100M</div>
>上传附件</el-button </div>
>
<div slot="tip" style="color: #999999;font-size: 12px;">单个附件限制100M</div>
</div>
</el-upload> </el-upload>
<div class="fileBox"> <div class="fileBox">
<div <div v-for="(item, index) in editData.fileList" class="fileRow flex-row jcsb aic" :key="index">
v-for="(item, index) in editData.fileList"
class="fileRow flex-row jcsb aic"
:key="index"
>
<div class="flex-row aic fileItem"> <div class="flex-row aic fileItem">
<img class="" :src="filePng" v-if="getFileType(item.fileName)=='file'"> </img> <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="imagePng" v-else-if="getFileType(item.fileName) == 'image'"> </img>
<img class="" :src="zipPng" v-else-if="getFileType(item.fileName)=='zip'"> </img> <img class="" :src="zipPng" v-else-if="getFileType(item.fileName) == 'zip'"> </img>
<div @click="downFile(item.fileUrl)">{{ item.fileName }}</div> <div @click="downFile(item.fileUrl)">{{ item.fileName }}</div>
</div> </div>
<div class="del" @click="delFile(item)">×</div> <div class="del" @click="delFile(item)">×</div>
@ -518,6 +360,7 @@ export default {
filePng, filePng,
zipPng, zipPng,
imagePng, imagePng,
delFileArr: []
}; };
}, },
watch: { watch: {
@ -591,7 +434,7 @@ export default {
this.editData.projectName = this.projectName; this.editData.projectName = this.projectName;
}, },
handleEdit(row) { handleEdit(row) {
this.editData = row; this.editData = Object.assign({}, row);
this.editData.projectId = this.projectId; this.editData.projectId = this.projectId;
this.editData.projectName = this.projectName; this.editData.projectName = this.projectName;
this.dialogVisibleAdd = true; this.dialogVisibleAdd = true;
@ -621,7 +464,7 @@ export default {
this.resetList("del"); this.resetList("del");
}); });
}) })
.catch(() => {}); .catch(() => { });
}, },
handleBatchDelete() { handleBatchDelete() {
if (!this.selectedRows.length) { if (!this.selectedRows.length) {
@ -724,30 +567,6 @@ export default {
this.userSelectDialogVisible = false; this.userSelectDialogVisible = false;
}, },
eidtDemandRow(row, label, old) { 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 demandApi
.eidtDemand(this.checkedRow) .eidtDemand(this.checkedRow)
.then((res) => { .then((res) => {
@ -808,11 +627,17 @@ export default {
this.resetList("add", res.data); this.resetList("add", res.data);
}); });
} }
} }
// } // }
}); });
}, },
resetList(type, data) { async resetList(type, data) {
if (this.delFileArr.length) {
await systemApi.delFileBatch(this.delFileArr.join(','))
this.delFileArr = []
}
let refreshId = ""; let refreshId = "";
if (type == "edit") { if (type == "edit") {
if (this.editData.versionId) { if (this.editData.versionId) {
@ -894,6 +719,7 @@ export default {
res1.data.projectLeader, res1.data.projectLeader,
...res2.data?.map((ele) => ele.userId), ...res2.data?.map((ele) => ele.userId),
]; ];
}, },
setRowClass({ row }) { setRowClass({ row }) {
if (row.demandStatus == 4) { if (row.demandStatus == 4) {
@ -903,7 +729,7 @@ export default {
beforeUpload(file) { beforeUpload(file) {
this.fileLoading = true; this.fileLoading = true;
if (file.size > 1024 * 1024 * 100) { if (file.size > 1024 * 1024 * 100) {
this.fileLoading = false; this.fileLoading = false;
this.$message({ this.$message({
type: "warning", type: "warning",
@ -912,8 +738,8 @@ export default {
return false; return false;
} }
}, },
successUpload(res,file,fileList) { successUpload(res, file, fileList) {
if(!fileList.filter((ele)=>ele.percentage!=100).length){ if (!fileList.filter((ele) => ele.percentage != 100).length) {
this.fileLoading = false; this.fileLoading = false;
} }
if (res.code == 200) { if (res.code == 200) {
@ -924,6 +750,8 @@ export default {
fileUrl: res.url, fileUrl: res.url,
}); });
} else { } else {
this.fileLoading = false;
this.$message({ this.$message({
type: "error", type: "error",
message: res.msg, message: res.msg,
@ -937,48 +765,48 @@ export default {
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning", type: "warning",
}).then(() => { }).then(() => {
systemApi.delFile(row.id).then((res) => { this.editData.fileList = this.editData.fileList.filter(
this.editData.fileList = this.editData.fileList.filter( (ele) => ele.fileNewName != row.fileNewName
(ele) => ele.fileNewName != row.fileNewName );
); this.delFileArr.push(row.id)
this.$message({ this.$message({
type:'success', type: 'success',
message: "删除成功!" message: "删除成功!"
}) })
});
}); });
} else { } else {
this.editData.fileList = this.editData.fileList.filter( this.editData.fileList = this.editData.fileList.filter(
(ele) => ele.fileNewName != row.fileNewName (ele) => ele.fileNewName != row.fileNewName
); );
this.$message({ this.$message({
type:'success', type: 'success',
message: "删除成功!" message: "删除成功!"
}) })
} }
}, },
getFileType(name){ getFileType(name) {
var data={ var data = {
jpg: 'image', jpg: 'image',
jpeg: 'image', jpeg: 'image',
png: 'image', png: 'image',
gif: 'image', gif: 'image',
bmp: 'image', bmp: 'image',
tiff: 'image', tiff: 'image',
svg: 'image', svg: 'image',
pdf: 'file', pdf: 'file',
doc: 'file', doc: 'file',
docx: 'file', docx: 'file',
xls: 'file', xls: 'file',
xlsx: 'file', xlsx: 'file',
txt: 'file', txt: 'file',
ppt: 'file', ppt: 'file',
zip: 'zip', zip: 'zip',
rar: 'zip', rar: 'zip',
tar: 'zip', tar: 'zip',
targz: 'zip', targz: 'zip',
} }
return data[name.split('.')[1]]||'file' return data[name.split('.')[1]] || 'file'
} }
}, },
created() { created() {
@ -1023,6 +851,7 @@ export default {
padding-left: 5px !important; padding-left: 5px !important;
} }
} }
::v-deep .status-tag .el-radio__inner { ::v-deep .status-tag .el-radio__inner {
height: 18px !important; height: 18px !important;
width: 18px !important; width: 18px !important;
@ -1030,41 +859,53 @@ export default {
text-align: center; text-align: center;
margin-bottom: 1px; margin-bottom: 1px;
background: #fff !important; background: #fff !important;
&::after { &::after {
height: 10px; height: 10px;
width: 10px; width: 10px;
} }
} }
::v-deep .status-tag.pending .el-radio__inner { ::v-deep .status-tag.pending .el-radio__inner {
border-color: #ff7d00; border-color: #ff7d00;
&::after { &::after {
background-color: #ff7d00 !important; background-color: #ff7d00 !important;
} }
} }
::v-deep .status-tag.in-progress .el-radio__inner { ::v-deep .status-tag.in-progress .el-radio__inner {
border-color: #4096ff !important; border-color: #4096ff !important;
&::after { &::after {
background-color: #4096ff !important; background-color: #4096ff !important;
} }
} }
::v-deep .status-tag.completed .el-radio__inner { ::v-deep .status-tag.completed .el-radio__inner {
border-color: #50b6aa !important; border-color: #50b6aa !important;
&::after { &::after {
background-color: #50b6aa !important; background-color: #50b6aa !important;
} }
} }
::v-deep .status-tag.closed .el-radio__inner { ::v-deep .status-tag.closed .el-radio__inner {
border-color: #ccc !important; border-color: #ccc !important;
&::after { &::after {
background-color: #ccc !important; background-color: #ccc !important;
} }
} }
::v-deep .status-tag.wait .el-radio__inner { ::v-deep .status-tag.wait .el-radio__inner {
border-color: #999 !important; border-color: #999 !important;
&::after { &::after {
background-color: #999 !important; background-color: #999 !important;
} }
} }
::v-deep .status-tag.pending .el-radio__label { ::v-deep .status-tag.pending .el-radio__label {
color: #ff7d00 !important; color: #ff7d00 !important;
// background-color: #fff7e6; // background-color: #fff7e6;
@ -1084,9 +925,11 @@ export default {
color: #999 !important; color: #999 !important;
// background-color: #f5f5f5; // background-color: #f5f5f5;
} }
::v-deep .status-tag.closed .el-radio__label { ::v-deep .status-tag.closed .el-radio__label {
color: #ccc !important; color: #ccc !important;
} }
.pagination { .pagination {
margin-top: 20px; margin-top: 20px;
display: flex; display: flex;
@ -1099,8 +942,10 @@ export default {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
} }
::v-deep .disabled.el-table__cell { ::v-deep .disabled.el-table__cell {
color: #ccc; color: #ccc;
.el-dropdown-link { .el-dropdown-link {
color: #ccc; color: #ccc;
} }
@ -1131,12 +976,15 @@ export default {
padding-left: 10px !important; padding-left: 10px !important;
font-weight: 600; font-weight: 600;
} }
.search-filters ::v-deep .el-input__inner { .search-filters ::v-deep .el-input__inner {
padding-left: 80px !important; padding-left: 80px !important;
::placeholder { ::placeholder {
color: #bbb; color: #bbb;
} }
} }
::v-deep .el-button--primary { ::v-deep .el-button--primary {
background-color: #4096ff; background-color: #4096ff;
} }
@ -1145,35 +993,44 @@ export default {
border-color: #4096ff; border-color: #4096ff;
background-color: #4096ff; background-color: #4096ff;
} }
::v-deep .addForm { ::v-deep .addForm {
.el-input__inner { .el-input__inner {
// width: 100%; // width: 100%;
width: 200px; width: 200px;
} }
.el-form-item { .el-form-item {
width: 48%; width: 48%;
} }
.el-input--prefix .el-input__inner { .el-input--prefix .el-input__inner {
padding-left: 40px; padding-left: 40px;
} }
} }
::v-deep .longItem { ::v-deep .longItem {
width: 100% !important; width: 100% !important;
.el-form-item__content { .el-form-item__content {
width: 82.2%; width: 82.2%;
.el-input__inner { .el-input__inner {
width: 100%; width: 100%;
} }
} }
} }
.tableSelect1 { .tableSelect1 {
width: 150px; width: 150px;
text-align: left !important; text-align: left !important;
} }
.tableSelect2 { .tableSelect2 {
width: 100px; width: 100px;
text-align: left !important; text-align: left !important;
} }
.selectedItem1 { .selectedItem1 {
&::after { &::after {
content: "✔"; content: "✔";
@ -1184,9 +1041,11 @@ export default {
color: #4096ff; color: #4096ff;
} }
} }
.selectedItem2 { .selectedItem2 {
color: #4096ff; color: #4096ff;
position: relative; position: relative;
&::after { &::after {
content: "✔"; content: "✔";
width: 10px; width: 10px;
@ -1196,17 +1055,20 @@ export default {
color: #4096ff; color: #4096ff;
} }
} }
.tableBox { .tableBox {
.el-radio { .el-radio {
margin-left: 0; margin-left: 0;
} }
} }
.topTitle { .topTitle {
padding: 0 20px 20px; padding: 0 20px 20px;
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
color: #333; color: #333;
} }
.fileRow { .fileRow {
height: 38px; height: 38px;
padding: 0 10px; padding: 0 10px;
@ -1218,15 +1080,18 @@ export default {
font-size: 16px; font-size: 16px;
cursor: pointer; cursor: pointer;
} }
img{
img {
height: 18px; height: 18px;
} }
} }
.fileItem{
.fileItem {
gap: 10px; gap: 10px;
cursor: pointer; cursor: pointer;
} }
.fileBox{
.fileBox {
max-height: 200px; max-height: 200px;
overflow: auto; overflow: auto;
padding-right: 10px; padding-right: 10px;

View File

@ -65,11 +65,22 @@
class="nodeIcon" class="nodeIcon"
/> />
<!-- 节点文本 --> <!-- 节点文本 -->
<span <el-tooltip
:class="['nodeLabel', data.nodeId === selectedId ? 'selected' : '']" class="item"
effect="light"
:content="data.title"
placement="top"
:disabled="data.title.length > 8 ? false : true"
> >
{{ data.title }} <div
</span> :class="[
'nodeLabel',
data.nodeId === selectedId ? 'selected' : '',
]"
>
{{ data.title }}
</div>
</el-tooltip>
<!-- 右侧数字标记 --> <!-- 右侧数字标记 -->
<span <span
@ -164,7 +175,7 @@ export default {
}) })
.then((res) => { .then((res) => {
if (!res.data.length) { if (!res.data.length) {
this.treeData=[] this.treeData = [];
return; return;
} }
res.data = res.data.map((ele) => { res.data = res.data.map((ele) => {
@ -221,6 +232,13 @@ export default {
}); });
return; return;
} }
if (this.demandData.name.length > 10) {
this.$message({
message: "版本号限制10个字符",
type: "warning",
});
return;
}
let param = { let param = {
projectId: this.projectId, projectId: this.projectId,
versionNumber: this.demandData.name, versionNumber: this.demandData.name,
@ -348,6 +366,11 @@ export default {
font-weight: 600; font-weight: 600;
line-height: 36px; line-height: 36px;
color: #333; color: #333;
max-width: 160px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 20px;
} }
.nodeLabel.selected { .nodeLabel.selected {

View File

@ -1,119 +1,61 @@
<template> <template>
<div class="project-management" <div class="project-management" v-loading="fileLoading">
v-loading="fileLoading" <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px" class="custom-form">
>
<el-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-button
size="mini"
slot="append"
icon="el-icon-s-custom"
></el-button
></el-input>
</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="dataState" style="display: none"> <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.dataState"
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-form-item label="项目状态" prop="projectState">
<el-select <el-select v-model="formData.projectState" placeholder="请选择项目状态" class="full-width">
v-model="formData.projectState" <el-option v-for="item in statusList" :key="item.dictValue" :label="item.dictLabel"
placeholder="请选择项目状态" :value="item.dictValue" />
class="full-width"
>
<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-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"
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-row> </el-row>
@ -121,165 +63,81 @@
<el-col :span="24"> <el-col :span="24">
<el-form-item label="附件" prop="fileList"> <el-form-item label="附件" prop="fileList">
<div> <div>
<el-upload <el-upload class="upload-demo" ref="upload" :action="fileUpload" :show-file-list="false"
class="upload-demo" :auto-upload="true" :multiple="true" :before-upload="beforeUpload" :on-success="successUpload" :headers="{
ref="upload" Authorization: 'Bearer ' + token,
:action="fileUpload" }" :data="{}">
:show-file-list="false" <div class="flex-row aic" style="gap: 10px;margin-bottom: 10px;">
:auto-upload="true" <el-button slot="trigger" size="small" type="default"
:multiple="true" style="width: 200px;color: #333;font-weight: 500;">上传附件</el-button>
:before-upload="beforeUpload" <div slot="tip" style="color: #999999;font-size: 12px;">单个附件限制100M</div>
:on-success="successUpload" </div>
:headers="{ </el-upload>
Authorization: 'Bearer ' + token, <div class="fileBox">
}" <div v-for="(item, index) in formData.fileList" class="fileRow flex-row jcsb aic" :key="index">
:data="{}" <div class="flex-row aic fileItem">
> <img class="" :src="filePng" v-if="getFileType(item.fileName) == 'file'"> </img>
<div class="flex-row aic" style="gap: 10px;margin-bottom: 10px;"> <img class="" :src="imagePng" v-else-if="getFileType(item.fileName) == 'image'"> </img>
<el-button slot="trigger" size="small" type="default" style="width: 200px;color: #333;font-weight: 500;" <img class="" :src="zipPng" v-else-if="getFileType(item.fileName) == 'zip'"> </img>
>上传附件</el-button <div @click="downFile(item.fileUrl)">{{ item.fileName }}</div>
> </div>
<div slot="tip" style="color: #999999;font-size: 12px;">单个附件限制100M</div> <div class="del" @click="delFile(item)">×</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>
<div class="del" @click="delFile(item)">×</div>
</div> </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>
@ -287,21 +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"
:dialogVisible="showProjectManagerSelect" :currentSelectedUser="projectManagerSelectedUser" @confirm="handleProjectManagerConfirm"
:multi-select="false" @close="closeProjectManagerSelect" />
:currentSelectedUser="projectManagerSelectedUser"
@confirm="handleProjectManagerConfirm"
@close="closeProjectManagerSelect"
/>
</div> </div>
</template> </template>
@ -338,7 +187,7 @@ export default {
budgetDate: 0, budgetDate: 0,
state: 0, state: 0,
dataState: 0, dataState: 0,
fileList:[] fileList: []
}, },
postOptions: [], postOptions: [],
statusList: [], statusList: [],
@ -378,13 +227,14 @@ export default {
{ required: true, message: "预算天数为必填", trigger: "blur" }, { required: true, message: "预算天数为必填", trigger: "blur" },
], ],
fileList: [ fileList: [
{ required: true, message: "预算天数为必填", trigger: "blur" }, { required: true, message: "附件为必填", trigger: "blur" },
], ],
}, },
filePng, filePng,
zipPng, zipPng,
imagePng, imagePng,
token: getToken(), token: getToken(),
delFileArr: []
}; };
}, },
@ -450,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,
@ -463,9 +315,22 @@ 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("操作成功");
} }
} }
@ -568,11 +433,11 @@ export default {
openProjectManagerSelect() { openProjectManagerSelect() {
this.projectManagerSelectedUser = this.formData.projectLeader this.projectManagerSelectedUser = this.formData.projectLeader
? [ ? [
{ {
userId: this.formData.projectLeader, userId: this.formData.projectLeader,
nickName: this.formData.projectLeaderName, nickName: this.formData.projectLeaderName,
}, },
] ]
: []; : [];
this.showProjectManagerSelect = true; this.showProjectManagerSelect = true;
}, },
@ -623,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,
@ -693,9 +558,10 @@ export default {
} }
}, },
beforeUpload(file) { beforeUpload(file) {
this.fileLoading = true; this.fileLoading = true;
if (file.size > 1024 * 1024 * 100) { if (file.size > 1024 * 1024 * 100) {
this.fileLoading = false; this.fileLoading = false;
this.$message({ this.$message({
type: "warning", type: "warning",
@ -704,8 +570,8 @@ export default {
return false; return false;
} }
}, },
successUpload(res,file,fileList) { successUpload(res, file, fileList) {
if(!fileList.filter((ele)=>ele.percentage!=100).length){ if (!fileList.filter((ele) => ele.percentage != 100).length) {
this.fileLoading = false; this.fileLoading = false;
} }
if (res.code == 200) { if (res.code == 200) {
@ -716,6 +582,7 @@ export default {
fileUrl: res.url, fileUrl: res.url,
}); });
} else { } else {
this.fileLoading = false;
this.$message({ this.$message({
type: "error", type: "error",
message: res.msg, message: res.msg,
@ -729,48 +596,47 @@ export default {
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning", type: "warning",
}).then(() => { }).then(() => {
systemApi.delFile(row.id).then((res) => { this.delFileArr.push(row.id)
this.formData.fileList = this.formData.fileList.filter( this.formData.fileList = this.formData.fileList.filter(
(ele) => ele.fileNewName != row.fileNewName (ele) => ele.fileNewName != row.fileNewName
); );
this.$message({ this.$message({
type:'success', type: 'success',
message: "删除成功!" message: "删除成功!"
}) })
});
}); });
} else { } else {
this.formData.fileList = this.formData.fileList.filter( this.formData.fileList = this.formData.fileList.filter(
(ele) => ele.fileNewName != row.fileNewName (ele) => ele.fileNewName != row.fileNewName
); );
this.$message({ this.$message({
type:'success', type: 'success',
message: "删除成功!" message: "删除成功!"
}) })
} }
}, },
getFileType(name){ getFileType(name) {
var data={ var data = {
jpg: 'image', jpg: 'image',
jpeg: 'image', jpeg: 'image',
png: 'image', png: 'image',
gif: 'image', gif: 'image',
bmp: 'image', bmp: 'image',
tiff: 'image', tiff: 'image',
svg: 'image', svg: 'image',
pdf: 'file', pdf: 'file',
doc: 'file', doc: 'file',
docx: 'file', docx: 'file',
xls: 'file', xls: 'file',
xlsx: 'file', xlsx: 'file',
txt: 'file', txt: 'file',
ppt: 'file', ppt: 'file',
zip: 'zip', zip: 'zip',
rar: 'zip', rar: 'zip',
tar: 'zip', tar: 'zip',
targz: 'zip', targz: 'zip',
} }
return data[name.split('.')[1]]||'file' return data[name.split('.')[1]] || 'file'
}, },
downFile(url) { downFile(url) {
window.open(url); window.open(url);
@ -817,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 {
@ -826,24 +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 { .custom-form ::v-deep .el-input__inner {
height: 100%; height: 100%;
} }
.custom-form ::v-deep .el-select { .custom-form ::v-deep .el-select {
width: 100%; width: 100%;
} }
@ -855,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;
@ -927,13 +801,15 @@ export default {
height: 64px; height: 64px;
margin-bottom: 16px; margin-bottom: 16px;
} }
.fileRow { .fileRow {
height: 38px; height: 38px;
padding: 0 10px; padding: 0 10px;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 5px; border-radius: 5px;
margin-bottom: 10px; margin-bottom: 10px;
img{
img {
height: 18px; height: 18px;
} }
@ -942,12 +818,14 @@ export default {
cursor: pointer; cursor: pointer;
} }
} }
.fileItem{
.fileItem {
gap: 10px; gap: 10px;
cursor: pointer; cursor: pointer;
} }
.fileBox{
max-height: 200px; .fileBox {
max-height: 136px;
overflow: auto; overflow: auto;
padding-right: 10px; padding-right: 10px;
max-width: 90%; max-width: 90%;

View File

@ -237,6 +237,8 @@ export default {
.selectBox span { .selectBox span {
width: 120px; width: 120px;
} }
.content{
::v-deep .el-table { ::v-deep .el-table {
height: 100% !important; height: 100% !important;
} }
@ -318,4 +320,6 @@ export default {
::v-deep .el-table__footer td { ::v-deep .el-table__footer td {
border: none !important; border: none !important;
} }
}
</style> </style>

View File

@ -6,21 +6,14 @@
{{ examineTask.taskName }} {{ examineTask.taskName }}
</div> </div>
<div class="flex-row jcfs f1" style="gap: 20px" v-if="isEdit"> <div class="flex-row jcfs f1" style="gap: 20px" v-if="isEdit">
<el-button type="default" style="width: 90px" @click="saveScoreCheck(0)" <el-button type="default" style="width: 90px" @click="saveScoreCheck(0)"></el-button>
>保存</el-button <el-button type="primary" style="width: 90px" @click="saveScoreCheck(1)"></el-button>
>
<el-button type="primary" style="width: 90px" @click="saveScoreCheck(1)"
>提交</el-button
>
</div> </div>
</div> </div>
<div class="flex-row jcsb aic userBox headerBox"> <div class="flex-row jcsb aic userBox headerBox">
<div class="flex-row aic" style="width: 200px;"> <div class="flex-row aic" style="width: 200px;">
<i <i class="el-icon-user-solid" style="color: #4096ff; font-size: 24px; margin-right: 5px"></i>{{
class="el-icon-user-solid" examineUser.userName }}
style="color: #4096ff; font-size: 24px; margin-right: 5px"
></i
>{{ examineUser.userName }}
</div> </div>
<div class="totalBox aic" v-if="!isNormal"> <div class="totalBox aic" v-if="!isNormal">
<div>考核评分</div> <div>考核评分</div>
@ -28,93 +21,64 @@
</div> </div>
</div> </div>
<div class="tableBox"> <div class="tableBox">
<div <div class="tableRow" v-for="(table, index) in tableData" :key="index" style="margin-bottom: 20px">
class="tableRow"
v-for="(table, index) in tableData"
:key="index"
style="margin-bottom: 20px"
>
<div class="userBox">{{ table[0].reviewCategory }}</div> <div class="userBox">{{ table[0].reviewCategory }}</div>
<el-table :data="table" style="width: 100%"> <el-table :data="table" style="width: 100%">
<el-table-column <el-table-column v-for="(header, hIndex) in headers" :key="hIndex" :label="header.label" :prop="header.prop"
v-for="(header, hIndex) in headers" :width="header.width" :minWidth="header.minWidth">
:key="hIndex"
:label="header.label"
:prop="header.prop"
:width="header.width"
:minWidth="header.minWidth"
>
</el-table-column> </el-table-column>
<el-table-column <el-table-column class-name="editCell" label="员工自评" prop="score"
label="评分" v-if="!isNormal && examineTask.templateId && table[0].reviewCategory == '发展与协作' && examineTask.templateType != 0"
prop="score" min-width="220">
:minWidth="isNormal ? 320 : 420" <template slot-scope="scope">
class-name="sorceTableCell" <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="isNormal ? 320 : table[0].reviewCategory == '发展与协作' ? 220 : 420" class-name="sorceTableCell"
v-if="(isNormal && table[0].reviewCategory != '发展与协作') || !isNormal">
<template slot-scope="scope"> <template slot-scope="scope">
<div style="width: 88%; position: relative"> <div style="width: 88%; position: relative">
<div> <div>
<div <div class="flex-row jcsb" style="
class="flex-row jcsb"
style="
margin-left: 10px; margin-left: 10px;
width: 90%; width: 90%;
color: #999; color: #999;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
" ">
>
<div>0</div> <div>0</div>
<div v-show="scope.row.score != 10">10</div> <div v-show="scope.row.score != 10">10</div>
</div> </div>
<div <div class="scoreText aic" v-show="scope.row.score != 0" :style="{
class="scoreText aic" left: scope.row.score * 9 - 5 + '%',
v-show="scope.row.score != 0" }">
:style="{ <img src="@/assets/task/score.png" :style="{
left: scope.row.score * 9 - 5 + '%', height: '28px',
}" width: '34px',
> zIndex: 0,
<img position: 'absolute',
src="@/assets/task/score.png" top: '0',
:style="{ }" alt="" />
height: '28px', <div :style="{
width: '34px', zIndex: 10,
zIndex: 0, paddingLeft: scope.row.score != 10 ? '13px' : '9px',
position: 'absolute', }">
top: '0',
}"
alt=""
/>
<div
:style="{
zIndex: 10,
paddingLeft: scope.row.score != 10 ? '13px' : '9px',
}"
>
{{ scope.row.score }} {{ scope.row.score }}
</div> </div>
</div> </div>
<div <div v-for="item in scope.row.score == 0
v-for="item in scope.row.score == 0 ? 0
? 0 : scope.row.score - 1" :key="item" class="stepBox" :style="{
: scope.row.score - 1"
:key="item"
class="stepBox"
:style="{
left: item * 9 + 1.5 + '%', left: item * 9 + 1.5 + '%',
}" }"></div>
></div> <el-slider v-model="scope.row.score" :min="0" :max="10" @change="updateScore(scope.row)"
<el-slider :disabled="!isEdit" style="width: 90%" show-stops show-tooltip></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>
<div class="statusText" v-show="scope.row.score == 0"> <div class="statusText" v-show="scope.row.score == 0">
暂未打分 暂未打分
@ -122,49 +86,38 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column class-name="editCell" label="自评总结" prop="score" v-if="isNormal" minWidth="140"> <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"> <template slot-scope="scope">
<div> <div>
<el-button <el-button v-if="isEdit" @click="handleEdit(scope.row)" type="text" size="mini"
v-if="isEdit" :class="{ hasEdit: !scope.row.remark }" style="font-weight: 600">{{ scope.row.remark ? "查看" : "暂未评价"
@click="handleEdit(scope.row)" }}
type="text" <i style="color: #4096ff; font-size: 14px" class="el-icon-edit el-icon--right"></i></el-button>
size="mini" <el-button v-if="!isEdit" @click="handleEdit(scope.row)" type="text" size="mini"
:class="{ hasEdit: !scope.row.remark }" :class="{ hasEdit: !scope.row.remark }" style="font-weight: 600">{{ scope.row.remark ? "查看" : "暂未评价"
style="font-weight: 600" }}</el-button>
>{{ 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> </div>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </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> <div>
<div v-if="!isNormal"> <div v-if="(isNormal && examineTask.templateType == 0) || (!isNormal)">
<div class="userBox">总体评价</div> <div class="userBox">总体评价</div>
<div> <div>
<el-input <el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/300" v-model="saveData.judgeContent"
type="textarea" :readonly="!isEdit" maxlength="300" show-word-limit>
:autosize="{ minRows: 4 }"
placeholder="0/300"
v-model="saveData.judgeContent"
:readonly="!isEdit"
maxlength="300"
show-word-limit
>
</el-input> </el-input>
</div> </div>
</div> </div>
@ -173,25 +126,16 @@
<el-dialog title="自评总结" :visible.sync="dialogVisible" width="30%"> <el-dialog title="自评总结" :visible.sync="dialogVisible" width="30%">
<div> <div>
<el-input <el-input type="textarea" :autosize="{ minRows: 4 }" placeholder="0/200" v-model="remark" :readonly="!isEdit"
type="textarea" maxlength="200" show-word-limit>
:autosize="{ minRows: 4 }"
placeholder="0/200"
v-model="remark"
:readonly="!isEdit"
maxlength="200"
show-word-limit
>
</el-input> </el-input>
</div> </div>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="cancelEdit">{{ <el-button @click="cancelEdit">{{
isEdit ? "取 消" : "关闭" isEdit ? "取 消" : "关闭"
}}</el-button> }}</el-button>
<el-button type="primary" @click="saveEdit" v-if="isEdit" <el-button type="primary" @click="saveEdit" v-if="isEdit"> </el-button>
> </el-button
>
</span> </span>
</el-dialog> </el-dialog>
</div> </div>
@ -215,7 +159,7 @@ export default {
{ {
label: "评分标准", label: "评分标准",
prop: "remarks", prop: "remarks",
minWidth:this.$route.query.isNormal? 240:360, minWidth: this.$route.query.isNormal ? 240 : 360,
}, },
], ],
// //
@ -312,7 +256,10 @@ export default {
score: ele.score, score: ele.score,
configId: ele.id, configId: ele.id,
remark: ele.remark, remark: ele.remark,
reviewCategory: ele.reviewCategory,
})); }));
this.saveData.examineRemarkList = this.tableData.filter((ele)=>ele[0].reviewCategory!='发展与协作').map((ele) => ({ reviewCategory: ele[0].reviewCategory, remark: ele[0].remarkCate }))
this.saveData.taskId = this.examineTaskId; this.saveData.taskId = this.examineTaskId;
this.saveData.examineId = this.examineId; this.saveData.examineId = this.examineId;
}, },
@ -326,21 +273,21 @@ export default {
return; return;
} }
// //
if (this.saveData.examineDetailList.filter((ele) => !ele.score).length) { if (this.saveData.examineDetailList.filter((ele) => !ele.score && ele.reviewCategory != '发展与协作' || (!ele.score && !this.isNormal)).length) {
this.$alert("存在未评分绩效项,请完善后再试", "提交失败", { this.$alert("存在未评分绩效项,请完善后再试", "提交失败", {
confirmButtonText: "确定", confirmButtonText: "确定",
type: "warning", type: "warning",
}); });
} else if ( } else if (
this.saveData.examineDetailList.filter((ele) => !ele.remark).length && this.saveData.examineDetailList.filter((ele) => !ele.remark && ele.reviewCategory == '发展与协作').length &&
this.isNormal && this.isNormal &&
status status
) { ) {
this.$alert("自评总结为必填,请完善后再试", "提交失败", { this.$alert("发展与协作下的自评总结为必填,请完善后再试", "提交失败", {
confirmButtonText: "确定", confirmButtonText: "确定",
type: "warning", type: "warning",
}); });
} else if (this.saveData.judgeContent.length > 300 && !this.isNormal) { } else if (this.saveData.judgeContent.length > 300 && !this.isNormal && this.examineTask.templateType == '0') {
this.$message({ this.$message({
message: "总体评价限制300个字符", message: "总体评价限制300个字符",
type: "warning", type: "warning",
@ -350,6 +297,11 @@ export default {
message: "总体评价为必填", message: "总体评价为必填",
type: "warning", type: "warning",
}); });
} else if (this.saveData.examineRemarkList.filter((ele) => !ele.remark).length && this.isNormal) {
this.$message({
message: "存在未填写大类评价,请完善后再试",
type: "warning",
});
} else { } else {
if (status) { if (status) {
this.$confirm( this.$confirm(
@ -400,9 +352,11 @@ export default {
.conetentBox { .conetentBox {
padding: 40px 30px 30px; padding: 40px 30px 30px;
background-color: #fff; background-color: #fff;
height: 90vh; /* 设置整体高度 */ height: 90vh;
/* 设置整体高度 */
overflow: auto; overflow: auto;
} }
.el-table { .el-table {
margin-top: 20px; margin-top: 20px;
} }
@ -412,31 +366,37 @@ export default {
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
} }
::v-deep .el-slider__runway { ::v-deep .el-slider__runway {
height: 14px; height: 14px;
border-radius: 10px; border-radius: 10px;
margin: 10px !important; margin: 10px !important;
/* width: 95%; */ /* width: 95%; */
} }
::v-deep .el-slider__runway.disabled .el-slider__bar { ::v-deep .el-slider__runway.disabled .el-slider__bar {
height: 14px; height: 14px;
border-radius: 10px; border-radius: 10px;
background-color: #ff5722; background-color: #ff5722;
} }
::v-deep .el-slider__stop { ::v-deep .el-slider__stop {
height: 14px; height: 14px;
border-radius: 0; border-radius: 0;
z-index: 1000; z-index: 1000;
} }
::v-deep .el-slider__bar { ::v-deep .el-slider__bar {
height: 14px; height: 14px;
border-radius: 10px; border-radius: 10px;
background: linear-gradient(to right, #ffb144, #ff7d00); background: linear-gradient(to right, #ffb144, #ff7d00);
} }
::v-deep .el-slider__button { ::v-deep .el-slider__button {
display: none; display: none;
} }
.scoreText { .scoreText {
color: #fff; color: #fff;
position: absolute; position: absolute;
@ -445,6 +405,7 @@ export default {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
::v-deep .el-table th { ::v-deep .el-table th {
text-align: left; text-align: left;
font-size: 14px; font-size: 14px;
@ -456,6 +417,7 @@ export default {
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
} }
.statusText { .statusText {
color: #ff7d00; color: #ff7d00;
position: absolute; position: absolute;
@ -464,43 +426,52 @@ export default {
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
} }
.hasEdit { .hasEdit {
color: #999999; color: #999999;
} }
::v-deep .el-dialog { ::v-deep .el-dialog {
margin-top: 15% !important; margin-top: 15% !important;
} }
.tableBox { .tableBox {
height: 75%; height: 75%;
overflow: auto; overflow: auto;
padding: 20px; padding: 20px;
background-color: #fff; background-color: #fff;
} }
.tableBox ::v-deep .el-table { .tableBox ::v-deep .el-table {
border-left: 1px solid #eeeeee; border-left: 1px solid #eeeeee;
border-right: 1px solid #eeeeee; border-right: 1px solid #eeeeee;
} }
.tableRow { .tableRow {
padding: 20px; padding: 20px;
box-shadow: 0 0 20px #0000000f; box-shadow: 0 0 20px #0000000f;
} }
.titleBox { .titleBox {
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;
margin-bottom: 40px; margin-bottom: 40px;
} }
.headerBox { .headerBox {
padding: 20px; padding: 20px;
background-color: #f9f9f9; background-color: #f9f9f9;
border-radius: 2px; border-radius: 2px;
font-size: 16px; font-size: 16px;
} }
.block { .block {
width: 4px; width: 4px;
height: 24px; height: 24px;
background-color: #4096ff; background-color: #4096ff;
margin-right: 10px; margin-right: 10px;
} }
.stepBox { .stepBox {
position: absolute; position: absolute;
top: 33px; top: 33px;
@ -509,6 +480,7 @@ export default {
background-color: #fff; background-color: #fff;
z-index: 100; z-index: 100;
} }
.totalBox { .totalBox {
width: 180px; width: 180px;
display: flex; display: flex;
@ -516,28 +488,35 @@ export default {
font-size: 16px; font-size: 16px;
color: #333333; color: #333333;
} }
.scoreTotal { .scoreTotal {
font-size: 28px; font-size: 28px;
font-weight: 700; font-weight: 700;
color: #ff7d00; color: #ff7d00;
} }
::v-deep .el-table__body .sorceTableCell .cell { ::v-deep .el-table__body .sorceTableCell .cell {
margin-bottom: 20px; margin-bottom: 20px;
} }
::v-deep .sorceTableCell.el-table__cell{
padding-right: 10px !important; ::v-deep .sorceTableCell.el-table__cell {
padding-right: 10px !important;
} }
::v-deep .el-table__body .el-table__cell { ::v-deep .el-table__body .el-table__cell {
padding: 20px 40px; padding: 20px 40px;
} }
::v-deep .el-table__header .el-table__cell { ::v-deep .el-table__header .el-table__cell {
padding: 14px 30px; padding: 14px 30px;
} }
::v-deep .el-table__header .el-table__cell .cell{
::v-deep .el-table__header .el-table__cell .cell {
padding-left: 20px !important; padding-left: 20px !important;
} }
::v-deep .editCell{
::v-deep .editCell {
padding-right: 20px !important; padding-right: 20px !important;
} }

View File

@ -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>
<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>

View File

@ -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>

View File

@ -1,44 +1,18 @@
<template> <template>
<div class="project-list"> <div class="project-list">
<div class="search-bar"> <div class="search-bar">
<el-form <el-form :inline="true" :model="searchForm" class="demo-form-inline" size="small">
:inline="true"
:model="searchForm"
class="demo-form-inline"
size="small"
>
<el-form-item label="任务名称" class="form-item"> <el-form-item label="任务名称" class="form-item">
<el-input <el-input v-model="searchForm.taskName" placeholder="任务名称" style="width: 300px"></el-input>
v-model="searchForm.taskName"
placeholder="任务名称"
style="width: 300px;"
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="任务状态" class="form-item"> <el-form-item label="任务状态" class="form-item">
<el-select <el-select v-model="searchForm.taskStatus" placeholder="状态" clearable style="width: 300px">
v-model="searchForm.taskStatus" <el-option v-for="item in statusList" :key="item.value" :label="item.label" :value="item.value" />
placeholder="状态"
clearable
style="width: 300px;"
>
<el-option
v-for="item in statusList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="任务年份" class="form-item"> <el-form-item label="任务年份" class="form-item">
<el-date-picker <el-date-picker v-model="searchForm.year" type="year" style="width: 300px" placeholder="选择年份"
v-model="searchForm.year" value-format="yyyy">
type="year"
style="width: 300px"
placeholder="选择年份"
value-format="yyyy"
>
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@ -48,115 +22,65 @@
</el-form> </el-form>
</div> </div>
<div class="table-actions mb10"> <div class="table-actions mb10">
<el-button <el-button type="primary" size="mini" @click="addTask" style="height: 36px">+ 新增任务</el-button>
type="primary"
size="mini"
@click="addTask"
style="height: 36px"
>+ 新增任务</el-button
>
</div> </div>
<div class="f1 df"> <div class="f1 df">
<CustomTable <CustomTable :columns="columns" :tableData="tableData" :total="total" :show-selection="false" :show-index="true"
:columns="columns" @size-change="handleSizeChange" @current-change="handleCurrentChange" tableHeight="495px">
:tableData="tableData"
:total="total"
:show-selection="false"
:show-index="true"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
tableHeight="495px"
>
<template slot="operation" slot-scope="{ row }"> <template slot="operation" slot-scope="{ row }">
<div class="operation-buttons"> <div class="operation-buttons">
<el-button @click="editTask(row)" type="text" size="mini" <el-button @click="editTask(row)" type="text" size="mini">编辑</el-button>
>编辑</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>
<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> </div>
</template> </template>
</CustomTable> </CustomTable>
</div> </div>
<SelectUser <SelectUser :dialogVisible="userSelectDialogVisible" :currentSelectedUser="currentSelectedUser"
:dialogVisible="userSelectDialogVisible" :currentSelectedUserName="currentSelectedUserName" :showSelection="true" :highligt="false"
:currentSelectedUser="currentSelectedUser" :selectable="selectable" ref="selectUserRef" @confirm="handleUserConfirm" @close="handleUserClose" />
:currentSelectedUserName="currentSelectedUserName" <el-dialog :title="isEdit ? '编辑考核任务' : '新增考核任务'" :visible.sync="dialogVisible1" width="25%">
:showSelection="true"
:highligt="false"
:selectable="selectable"
ref="selectUserRef"
@confirm="handleUserConfirm"
@close="handleUserClose"
/>
<el-dialog
:title="isEdit ? '编辑考核任务' : '新增考核任务'"
:visible.sync="dialogVisible1"
width="25%"
>
<div> <div>
<el-form <el-form :model="taskData" size="small" ref="taskFormRef" :rules="rules" label-width="100px">
:model="taskData"
size="small"
ref="taskFormRef"
:rules="rules"
label-width="100px"
>
<el-form-item label="任务名称" class="form-item" prop="taskName"> <el-form-item label="任务名称" class="form-item" prop="taskName">
<el-input <el-input v-model="taskData.taskName" placeholder="0/20" style="width: 90%"></el-input>
v-model="taskData.taskName"
placeholder="0/20"
style="width: 90%"
></el-input>
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="考核人员" class="form-item" prop="peopleNumberDetail">
label="考核人员" <el-input v-model="taskData.peopleNumberDetail" placeholder="考核人员" readonly style="width: 90%"
class="form-item" @click.native="openUserSelectDialog"><el-button slot="append"
prop="peopleNumberDetail" icon="el-icon-s-custom"></el-button></el-input>
>
<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>
<el-form-item label="截止时间" class="form-item" prop="endTime"> <el-form-item label="截止时间" class="form-item" prop="endTime">
<el-date-picker <el-date-picker v-model="taskData.endTime" type="date" style="width: 90%" placeholder="选择日期"
v-model="taskData.endTime" value-format="yyyy-MM-dd 23:59:59" :picker-options="{
type="date"
style="width: 90%"
placeholder="选择日期"
value-format="yyyy-MM-dd 23:59:59"
:picker-options="{
disabledDate: disabledDate, disabledDate: disabledDate,
}" }">
>
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="年份" class="form-item" prop="year"> <el-form-item label="年份" class="form-item" prop="year">
<el-date-picker <el-date-picker v-model="taskData.year" type="year" style="width: 90%" placeholder="选择年份"
v-model="taskData.year" value-format="yyyy" :picker-options="{
type="year"
style="width: 90%"
placeholder="选择年份"
value-format="yyyy"
:picker-options="{
disabledDate: disabledDate, disabledDate: disabledDate,
}" }">
>
</el-date-picker> </el-date-picker>
</el-form-item> </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> </el-form>
</div> </div>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
@ -168,16 +92,8 @@
<div class="modal"> <div class="modal">
<div class="left"> <div class="left">
<div class="setText" style="font-weight: 600">累计权重</div> <div class="setText" style="font-weight: 600">累计权重</div>
<el-collapse <el-collapse v-model="letfValue" :accordion="true" style="height: 300px; overflow: auto">
v-model="letfValue" <el-collapse-item v-for="(item, index) in scoreList" :key="index" :name="item.title">
:accordion="true"
style="height: 300px; overflow: auto"
>
<el-collapse-item
v-for="(item, index) in scoreList"
:key="index"
:name="item.title"
>
<template #title> <template #title>
<div class="jcsb flex-row contentTitle"> <div class="jcsb flex-row contentTitle">
<span class="setTitle">{{ item.title }}</span> <span class="setTitle">{{ item.title }}</span>
@ -185,25 +101,16 @@
</div> </div>
</template> </template>
<div> <div>
<div <div v-for="(ele, index) in item.list" :key="index" class="flex-row jcsb leftSub" :class="{
v-for="(ele, index) in item.list" selectClass: selectLeftRow == ele.title + ele.type,
:key="index" }" @click="selectLeft(ele)">
class="flex-row jcsb leftSub"
:class="{
selectClass: selectLeftRow == ele.title + ele.type,
}"
@click="selectLeft(ele)"
>
<div>{{ ele.title }}</div> <div>{{ ele.title }}</div>
<div class="statusText">{{ ele.weight }}%</div> <div class="statusText">{{ ele.weight }}%</div>
</div> </div>
</div> </div>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<div <div class="flex-row jcsb" style="margin-top: 20px; padding-right: 15px">
class="flex-row jcsb"
style="margin-top: 20px; padding-right: 15px"
>
<div class="setTitle" style="font-weight: 600">总计</div> <div class="setTitle" style="font-weight: 600">总计</div>
<div class="statusText"> <div class="statusText">
{{ {{
@ -214,64 +121,48 @@
</div> </div>
<div class="right"> <div class="right">
<div class="flex-row jcsb" style="margin-bottom: 10px"> <div class="flex-row jcsb" style="margin-bottom: 10px">
<div style="width: 50%;font-weight: 600">指标</div> <div style="width: 50%; font-weight: 600">指标</div>
<div class="center" style="width: 50%;font-weight: 600">权重占比</div> <div class="center" style="width: 50%; font-weight: 600">
权重占比
</div>
</div> </div>
<div> <div>
<div <div v-for="(item, index) in (
v-for="(item, index) in ( (
( (scoreList.find((ele) => ele.title == letfValue) || {})
(scoreList.find((ele) => ele.title == letfValue) || {}) .list || []
.list || [] ).find((ele) => ele.title + ele.type == selectLeftRow) || {}
).find((ele) => ele.title + ele.type == selectLeftRow) || {} ).rightArr || []" :key="index" style="margin-bottom: 10px" class="flex-row jcsb aic">
).rightArr || []"
:key="index"
style="margin-bottom: 10px"
class="flex-row jcsb aic"
>
<div style="width: 50%; font-weight: 600"> <div style="width: 50%; font-weight: 600">
{{ item.reviewItem }} {{ item.reviewItem }}
</div> </div>
<div class="center" style="width: 50%"> <div class="center" style="width: 50%">
<div <div class="flex-row jcsb" style="
class="flex-row jcsb"
style="
margin-left: 10px; margin-left: 10px;
width: 100%; width: 100%;
color: #999; color: #999;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
" ">
>
<div>0</div> <div>0</div>
<div v-show="item.weight != 20">20</div> <div v-show="item.weight != 20">20</div>
</div> </div>
<div <div class="scoreText aic" v-show="item.weight != 0" :style="{
class="scoreText aic" left: item.weight * 4.5 - 2.5 + '%',
v-show="item.weight != 0" }">
:style="{ <img src="@/assets/task/score.png" :style="{
left: item.weight * 4.5 - 2.5 + '%', height: '28px',
}" width: '34px',
> zIndex: 0,
<img position: 'absolute',
src="@/assets/task/score.png" top: '-2px',
:style="{ }" alt="" />
height: '28px', <div :style="{
width: '34px', zIndex: 10,
zIndex: 0, textIndent: item.weight < 10 ? '13px' : '10px',
position: 'absolute', fontSize: '12px',
top: '-2px', }">
}"
alt=""
/>
<div
:style="{
zIndex: 10,
textIndent: item.weight < 10 ? '13px' : '10px',
fontSize: '12px',
}"
>
{{ item.weight }} {{ item.weight }}
</div> </div>
</div> </div>
@ -280,19 +171,10 @@
<div class="scoreText">{{ item.weight }}%</div> <div class="scoreText">{{ item.weight }}%</div>
<div>20%</div> <div>20%</div>
</div> --> </div> -->
<div <div v-for="item in item.weight == 0 ? 0 : item.weight - 1" :key="item" class="stepBox" :style="{
v-for="item in item.weight == 0 ? 0 : item.weight - 1" left: item * 5 + 4 + '%',
:key="item" }"></div>
class="stepBox" <el-slider v-model="item.weight" :max="20" @change="changeTotal"></el-slider>
:style="{
left: item * 5 + 4 + '%',
}"
></div>
<el-slider
v-model="item.weight"
:max="20"
@change="changeTotal"
></el-slider>
</div> </div>
</div> </div>
</div> </div>
@ -335,9 +217,8 @@ export default {
if (value == 2) var color = "#999"; if (value == 2) var color = "#999";
else var color = "#4096FF"; else var color = "#4096FF";
return `<span style="color: ${color}">${ return `<span style="color: ${color}">${value ? "已过期" : "进行中"
value ? "已过期" : "进行中" }</span>`;
}</span>`;
}, },
}, },
{ {
@ -389,11 +270,14 @@ export default {
userIdList: [], userIdList: [],
endTime: "", endTime: "",
peopleNumber: 0, peopleNumber: 0,
templateType:'0',
templateId:'',
year: "", year: "",
taskStatus: 0
}, },
rules: { rules: {
taskName: [ taskName: [
{ required: true, message: "请输入活动名称", trigger: "blur" }, { required: true, message: "请输入任务名称", trigger: "blur" },
{ min: 1, max: 20, message: "长度限制20个字符", trigger: "blur" }, { min: 1, max: 20, message: "长度限制20个字符", trigger: "blur" },
], ],
peopleNumberDetail: [ peopleNumberDetail: [
@ -403,11 +287,13 @@ export default {
{ required: true, message: "请选择截止时间", trigger: "blur" }, { required: true, message: "请选择截止时间", trigger: "blur" },
], ],
year: [{ required: true, message: "请选择年份", trigger: "blur" }], year: [{ required: true, message: "请选择年份", trigger: "blur" }],
templateId: [{ required: true, message: "请选择任务看板", trigger: "blur" }],
}, },
dialogVisible2: false, dialogVisible2: false,
letfValue: "", letfValue: "",
scoreList: [], scoreList: [],
selectRow: {}, selectRow: {},
modelList: [],
}; };
}, },
watch: { watch: {
@ -495,6 +381,10 @@ export default {
userIdList: [], userIdList: [],
endTime: "", endTime: "",
peopleNumber: 0, peopleNumber: 0,
templateType: '0',
templateId: '',
taskStatus: 0
}; };
this.selectRow = {}; this.selectRow = {};
}, },
@ -507,6 +397,9 @@ export default {
this.taskData.peopleNumberDetail = row.peopleNumberDetail; this.taskData.peopleNumberDetail = row.peopleNumberDetail;
this.taskData.userIdList = row.userIdList; this.taskData.userIdList = row.userIdList;
this.taskData.endTime = row.endTime; 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.taskData.year = String(row.year);
this.selectRow = row; this.selectRow = row;
}, },
@ -566,7 +459,7 @@ export default {
}, },
{ {
title: "系统核算绩效指标", title: "系统核算绩效指标",
list: Object.keys(arrList["2"]).map((ele) => ({ list: Object.keys(arrList["2"] || {}).map((ele) => ({
title: ele, title: ele,
weight: arrList["2"][ele].reduce( weight: arrList["2"][ele].reduce(
(total, item) => (item.weight || 0) + total, (total, item) => (item.weight || 0) + total,
@ -575,7 +468,7 @@ export default {
rightArr: arrList["2"][ele], rightArr: arrList["2"][ele],
type: 2, type: 2,
})), })),
weight: Object.values(arrList["2"]).reduce( weight: Object.values(arrList["2"] || {}).reduce(
(total, item) => (total, item) =>
(item.reduce((total, item) => (item.weight || 0) + total, 0) || (item.reduce((total, item) => (item.weight || 0) + total, 0) ||
0) + total, 0) + total,
@ -583,6 +476,9 @@ export default {
), ),
}, },
]; ];
if (!arrList["2"]) {
this.scoreList.length = 2
}
this.dialogVisible2 = true; this.dialogVisible2 = true;
}); });
@ -683,16 +579,25 @@ export default {
}); });
}); });
}, },
selectable(row,index){ selectable(row, index) {
if(row.roles.find((ele)=>ele.roleName=='普通员工')){ if (row.roles.find((ele) => ele.roleName == "普通员工")) {
return true return true;
}else{ } else {
return false 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() { mounted() {
this.getTaskList(); this.getTaskList();
this.getTaskModel();
}, },
}; };
</script> </script>
@ -724,7 +629,8 @@ export default {
} }
.demo-form-inline .el-form-item:last-child { .demo-form-inline .el-form-item:last-child {
margin-right: 0; /* 移除最后一个元素的右边距 */ margin-right: 0;
/* 移除最后一个元素的右边距 */
} }
.form-item { .form-item {
@ -789,6 +695,7 @@ export default {
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
::v-deep .el-table th { ::v-deep .el-table th {
text-align: center; text-align: center;
} }
@ -796,14 +703,17 @@ export default {
::v-deep .el-table .cell { ::v-deep .el-table .cell {
text-align: center; text-align: center;
} }
::v-deep .el-dialog { ::v-deep .el-dialog {
margin-top: 10% !important; margin-top: 10% !important;
} }
.modal { .modal {
display: flex; display: flex;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
} }
.left { .left {
width: 40%; width: 40%;
padding: 20px; padding: 20px;
@ -811,89 +721,108 @@ export default {
height: 450px; height: 450px;
overflow: auto; overflow: auto;
} }
.right { .right {
width: 60%; width: 60%;
padding: 20px 40px; padding: 20px 40px;
height: 450px; height: 450px;
overflow: auto; overflow: auto;
div.center { div.center {
text-align: center; text-align: center;
position: relative; position: relative;
} }
} }
.scoreBox { .scoreBox {
position: absolute; position: absolute;
top: 45px; top: 45px;
right: -20px; right: -20px;
} }
::v-deep .el-slider__runway { ::v-deep .el-slider__runway {
height: 14px; height: 14px;
border-radius: 10px; border-radius: 10px;
margin: 10px !important; margin: 10px !important;
/* width: 95%; */ /* width: 95%; */
} }
::v-deep .el-slider__runway.disabled .el-slider__bar { ::v-deep .el-slider__runway.disabled .el-slider__bar {
height: 14px; height: 14px;
border-radius: 10px; border-radius: 10px;
background-color: #ff5722; background-color: #ff5722;
} }
::v-deep .el-slider__stop { ::v-deep .el-slider__stop {
height: 14px; height: 14px;
border-radius: 0; border-radius: 0;
z-index: 1000; z-index: 1000;
} }
::v-deep .el-slider__bar { ::v-deep .el-slider__bar {
height: 14px; height: 14px;
border-radius: 10px; border-radius: 10px;
background: linear-gradient(to right, #ffb144, #ff7d00); background: linear-gradient(to right, #ffb144, #ff7d00);
} }
::v-deep .el-slider__button { ::v-deep .el-slider__button {
display: none; display: none;
} }
.scoreText { .scoreText {
color: #1686d8; color: #1686d8;
} }
.setText { .setText {
margin-bottom: 20px; margin-bottom: 20px;
text-align: right; text-align: right;
} }
.leftSub { .leftSub {
padding: 10px 20px 10px 10px; padding: 10px 20px 10px 10px;
margin-bottom: 5px; margin-bottom: 5px;
cursor: pointer; cursor: pointer;
} }
.setTitle { .setTitle {
font-weight: bold; font-weight: bold;
} }
::v-deep .el-collapse-item__content { ::v-deep .el-collapse-item__content {
padding-bottom: 10px; padding-bottom: 10px;
} }
::v-deep .el-collapse-item__header {
} ::v-deep .el-collapse-item__header {}
.contentTitle {
} .contentTitle {}
.statusText { .statusText {
color: #ff5722; color: #ff5722;
} }
::v-deep .el-collapse { ::v-deep .el-collapse {
border: none !important; border: none !important;
} }
.search-buttons ::v-deep .el-button { .search-buttons ::v-deep .el-button {
width: 90px !important; width: 90px !important;
height: 36px; height: 36px;
} }
::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-weight: 600;
font-size: 14px; font-size: 14px;
} }
.selectClass { .selectClass {
background-color: #4096ff; background-color: #4096ff;
color: #fff; color: #fff;
} }
.scoreText { .scoreText {
color: #fff; color: #fff;
position: absolute; position: absolute;
@ -903,12 +832,14 @@ export default {
flex-direction: row; flex-direction: row;
width: 40px; width: 40px;
} }
.block { .block {
width: 4px; width: 4px;
height: 24px; height: 24px;
background-color: #4096ff; background-color: #4096ff;
margin-right: 10px; margin-right: 10px;
} }
.stepBox { .stepBox {
position: absolute; position: absolute;
top: 29px; top: 29px;
@ -917,6 +848,7 @@ export default {
background-color: #fff; background-color: #fff;
z-index: 100; z-index: 100;
} }
.totalBox { .totalBox {
width: 150px; width: 150px;
display: flex; display: flex;

View File

@ -162,11 +162,11 @@
</el-table-column> </el-table-column>
<el-table-column label="操作" width="200"> <el-table-column label="操作" width="200">
<template #default="scope"> <template #default="scope">
<div v-show="!disableTable"> <div>
<el-button type="text" @click="handleFile(scope.row)"> <el-button type="text" @click="handleFile(scope.row)">
附件详情 附件详情
</el-button> </el-button>
<el-button type="text" @click="handleEdit(scope.row)"> <el-button type="text" @click="handleEdit(scope.row)" v-show="!disableTable">
{{ scope.row.loggerId && !scope.row.edit ? "编辑" : "确认" }} {{ scope.row.loggerId && !scope.row.edit ? "编辑" : "确认" }}
</el-button> </el-button>
@ -174,6 +174,7 @@
type="text" type="text"
@click="handleDelete(scope.row, scope.$index)" @click="handleDelete(scope.row, scope.$index)"
style="color: #666" style="color: #666"
v-show="!disableTable"
> >
{{ scope.row.loggerId && !scope.row.edit ? "删除" : "取消" }} {{ scope.row.loggerId && !scope.row.edit ? "删除" : "取消" }}
</el-button> </el-button>
@ -188,7 +189,7 @@
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<div v-loading="fileLoading"> <div v-loading="fileLoading">
<div> <div v-show="!disableTable">
<el-upload <el-upload
class="upload-demo" class="upload-demo"
ref="upload" ref="upload"
@ -249,7 +250,7 @@
<el-table-column label="操作" width="120"> <el-table-column label="操作" width="120">
<template #default="scope"> <template #default="scope">
<div> <div>
<el-button type="text" @click="delFile(scope.row)"> <el-button type="text" @click="delFile(scope.row)" v-show="!disableTable">
删除 删除
</el-button> </el-button>
</div> </div>
@ -304,6 +305,7 @@ export default {
filePng, filePng,
zipPng, zipPng,
imagePng, imagePng,
delFileArr:[]
}; };
}, },
methods: { methods: {
@ -328,7 +330,7 @@ export default {
ele.showContent = false; ele.showContent = false;
return ele; return ele;
}); });
if (this.tableData.length == 0) { if (this.tableData.length == 0&&!this.disableTable) {
this.handleAdd(); this.handleAdd();
} }
}); });
@ -406,6 +408,12 @@ export default {
await workLogApi.addLog(param); await workLogApi.addLog(param);
this.$emit("changeCaleder"); this.$emit("changeCaleder");
} }
if(this.delFileArr.length){
systemApi.delFile({ids:this.delFileArr}).then((res) => {
this.fileList = []
this.delFileArr=[]
});
}
this.$modal.msgSuccess("操作成功"); this.$modal.msgSuccess("操作成功");
row.edit = false; row.edit = false;
this.getLogList(); this.getLogList();
@ -445,6 +453,8 @@ export default {
fileUrl: res.url, fileUrl: res.url,
}); });
} else { } else {
this.fileLoading = false;
this.$message({ this.$message({
type: "error", type: "error",
message: res.msg, message: res.msg,
@ -455,10 +465,27 @@ export default {
this.dialogVisibleFile = false; this.dialogVisibleFile = false;
this.fileList = []; this.fileList = [];
}, },
saveFile() { async saveFile() {
this.dialogVisibleFile = false; this.dialogVisibleFile = false;
this.checkRow.fileList = this.fileList; 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() { async getAllProject() {
const response = await projectApi.listProject({ const response = await projectApi.listProject({
@ -563,15 +590,14 @@ export default {
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning", type: "warning",
}).then(() => { }).then(() => {
systemApi.delFile(row.id).then((res) => { this.delFileArr.push(row.id)
this.fileList = this.fileList.filter( this.fileList = this.fileList.filter(
(ele) => ele.fileNewName != row.fileNewName (ele) => ele.fileNewName != row.fileNewName
); );
this.$message({ this.$message({
type:'success', type:'success',
message: "删除成功!" message: "删除成功!"
}) })
});
}); });
} else { } else {
this.fileList = this.fileList.filter( this.fileList = this.fileList.filter(