<template>
|
<div class="container">
|
<div class="title" v-if="!editId">
|
新建任务{{ editId }}
|
<span class="back" @click="back"> <i class="iconfont icon-fanhui"></i> 返回 </span>
|
</div>
|
<div class="title" v-else>
|
<span>修改任务</span> <span class="back" @click="back"> <i class="iconfont icon-fanhui"></i> 返回 </span>
|
</div>
|
|
<div class="wrap">
|
<el-row>
|
<el-col :lg="16" :md="20" :sm="24" :xs="24">
|
<el-form :model="project" status-icon ref="form" label-width="auto" @submit.prevent :rules="rules">
|
<el-form-item label="所属项目" prop="project_id">
|
<el-select
|
v-model="project.project_id"
|
placeholder="所属项目"
|
clearable
|
filterable
|
@change="handleProjectChange"
|
>
|
<el-option v-for="item in projectInfoArr" :key="item.id" :label="item.project_name" :value="item.id" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="项目模块" prop="module_id">
|
<el-cascader
|
v-model="project.module_id"
|
:options="projectModuleTreeArr"
|
width="100%"
|
clearable
|
filterable
|
:props="moduleCascaderProps"
|
:show-all-levels="false"
|
@change="handleModuleChange"
|
/>
|
</el-form-item>
|
|
<el-form-item label="任务名称" prop="name">
|
<el-input v-model="project.name" placeholder="请输入任务名称" clearable />
|
</el-form-item>
|
|
<el-form-item label="任务描述" prop="description">
|
<el-input
|
type="textarea"
|
:autosize="{ minRows: 4, maxRows: 8 }"
|
placeholder="请输入备注"
|
v-model="project.description"
|
>
|
</el-input>
|
</el-form-item>
|
|
<el-form-item label="任务类型" prop="type">
|
<el-select v-model="project.type" placeholder="任务类型" clearable filterable>
|
<el-option
|
v-for="item in projectTaskTypeArr"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="优先级" prop="priority">
|
<el-select v-model="project.priority" placeholder="优先级" clearable filterable>
|
<el-option
|
v-for="item in projectTaskPriorityArr"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="任务状态" prop="status">
|
<el-select v-model="project.status" placeholder="任务状态" clearable filterable>
|
<el-option
|
v-for="item in projectTaskStatusArr"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="排配状态" prop="assign_status">
|
<el-select v-model="project.assign_status" placeholder="排配状态" clearable filterable>
|
<el-option
|
v-for="item in projectTaskAssignStatus"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="评估人" prop="evaluator_users" class="selectClass">
|
<el-select
|
v-model="project.evaluator_users"
|
placeholder="请选择评估人"
|
clearable
|
filterable
|
:multiple="true"
|
>
|
<el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="计划工时" prop="plan_hour">
|
<el-input-number
|
v-model="project.plan_hour"
|
min="0"
|
max="999"
|
label="计划工时"
|
:precision="1"
|
:step="0.5"
|
></el-input-number>
|
</el-form-item>
|
|
<el-form-item label="计划时间" prop="plan_date">
|
<el-date-picker
|
v-model="project.plan_date"
|
type="daterange"
|
range-separator="-"
|
start-placeholder="计划开始时间"
|
end-placeholder="计划结束时间"
|
size="large"
|
format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
/>
|
</el-form-item>
|
<!--
|
<el-form-item label="计划开始时间" prop="plan_begin_date">
|
<el-date-picker
|
v-model="project.plan_begin_date"
|
type="date"
|
placeholder="计划开始时间"
|
size="small"
|
format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
/>
|
</el-form-item>
|
|
<el-form-item label="计划开始时间" prop="plan_end_date">
|
<el-date-picker
|
v-model="project.plan_end_date"
|
type="date"
|
placeholder="计划结束时间"
|
size="small"
|
format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
/>
|
</el-form-item> -->
|
|
<!-- :disabled="editId && project.status !== 'FN'"
|
:disabled="editId && project.status === 'FY'" -->
|
|
<!-- <el-form-item label="开发者" prop="developer_users" class="selectClass">
|
<el-select v-model="project.developer_users" placeholder="请选择开发者" clearable filterable :multiple="true">
|
<el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" />
|
</el-select>
|
</el-form-item> -->
|
<!-- <el-form-item label="实际工时" prop="actual_hour">
|
<el-input-number v-model="project.actual_hour" :min="1" :max="10" label="计划工时" ></el-input-number >
|
</el-form-item>
|
<el-form-item label="实际时间" prop="actual_date">
|
<el-date-picker v-model="project.actual_date" type="daterange" range-separator="-" start-placeholder="实际开始时间"
|
end-placeholder="实际结束时间" size="large"
|
format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
/>
|
</el-form-item> -->
|
|
<el-form-item label="备注" prop="remark">
|
<el-input
|
type="textarea"
|
:autosize="{ minRows: 4, maxRows: 8 }"
|
placeholder="请输入备注"
|
v-model="project.remark"
|
>
|
</el-input>
|
</el-form-item>
|
|
<el-form-item label="文件">
|
<el-upload
|
v-model:file-list="project.file_list"
|
class="upload-demo"
|
:action="uploader.action"
|
multiple
|
:headers="uploader.headers"
|
:on-preview="handleUploadPreview"
|
:on-remove="handleUploadRemove"
|
:before-remove="handleUploadBeforeRemove"
|
:limit="uploader.limit"
|
:on-exceed="handleExceed"
|
:on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList)"
|
:before-upload="beforeAvatarUpload"
|
>
|
<el-button type="primary">文件上传</el-button>
|
<template #tip>
|
<div class="el-upload__tip"></div>
|
</template>
|
</el-upload>
|
</el-form-item>
|
|
<el-form-item class="submit">
|
<el-button type="primary" @click="submitForm">保 存</el-button>
|
<el-button @click="resetForm">重 置</el-button>
|
</el-form-item>
|
</el-form>
|
</el-col>
|
</el-row>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import Config from '@/config'
|
import { getToken } from '@/lin/util/token'
|
|
import { reactive, ref, onMounted, computed } from 'vue'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
import ProjectInfo from '@/model/projectInfo'
|
import sysDictItemModel from '@/model/sysDictItem'
|
import ProjectModuleInfo from '@/model/projectModuleInfo'
|
import AdminInfo from '@/lin/model/admin'
|
import ProjectTaskInfo from '@/model/projectTaskInfo'
|
|
export default {
|
props: {
|
editId: {
|
type: String,
|
default: null,
|
},
|
},
|
setup(props, context) {
|
const uploader = ref({
|
action: `${Config.baseURL}cms/file`,
|
headers: {
|
Authorization: `${getToken('access_token')}`,
|
},
|
limit: 3,
|
fileList: [],
|
})
|
|
const handleUploadRemove = (file, uploadFiles) => {
|
let tmpRemoveFileId = ''
|
if (file && file.id) {
|
tmpRemoveFileId = file.id
|
project.file_list = project.file_list.filter(item => item.id !== tmpRemoveFileId)
|
}
|
}
|
|
const handleUploadPreview = uploadFile => {
|
console.log(uploadFile)
|
// 创建一个临时的 <a> 标签来触发下载
|
const downloadLink = document.createElement('a')
|
|
// 设置下载链接的 href 属性为文件的路径
|
downloadLink.href = uploadFile.path // 假设 uploadFile 包含路径
|
downloadLink.download = uploadFile.name // 使用文件名作为下载的文件名
|
|
// 触发点击事件,模拟下载
|
downloadLink.click()
|
}
|
|
const handleExceed = (files, uploadFiles) => {
|
ElMessage.warning('文件最上传个数超过限制')
|
}
|
|
const handleUploadBeforeRemove = (uploadFile, uploadFiles) => ElMessageBox.confirm(`确定删除文件${uploadFile.name} 嘛 ?`).then(
|
() => true,
|
() => false,
|
)
|
|
const handleUploadSuccess = (response, file, fileList) => {
|
|
if (response && response.length > 0) {
|
const isDuplicate = project.file_list.some(existingItem => existingItem.id === response[0].id)
|
if (isDuplicate) {
|
ElMessage.error('请不要上传重复文档!名字不同内容相同也不可以')
|
|
const tmp = []
|
project.file_list.forEach(item => {
|
if (item.id) {
|
const exist = (project.file_list = project.file_list.filter(exitem => exitem.id !== item.id))
|
if (!exist) {
|
tmp.push(item)
|
}
|
} else if (item.status && item.status === 'success' && item.response && item.response.length > 0) {
|
const exist = (project.file_list = project.file_list.filter(exitem => exitem.id !== item.response[0].id))
|
if (exist) {
|
tmp.push(item.response[0])
|
}
|
}
|
})
|
project.file_list = tmp
|
} else {
|
const tmp = []
|
project.file_list.forEach(item => {
|
if (item.id) {
|
tmp.push(item)
|
} else if (item.status && item.status === 'success' && item.response && item.response.length > 0) {
|
tmp.push(item.response[0])
|
}
|
})
|
project.file_list = tmp
|
}
|
}
|
}
|
|
const beforeAvatarUpload = rawFile => {
|
if (rawFile.size / 1024 / 1024 > 20) {
|
ElMessage.error('文件大小超过 20MB!')
|
return false
|
}
|
return true
|
}
|
|
const form = ref(null)
|
const loading = ref(false)
|
console.log(props.editId)
|
|
const project = reactive({
|
id: '',
|
project_id: '',
|
module_id: '',
|
name: '',
|
description: '',
|
type: '',
|
priority: '',
|
status: '',
|
assign_status: '',
|
evaluator_users: [],
|
developer_users: [],
|
plan_hour: '',
|
plan_date: [],
|
plan_begin_date: '',
|
plan_end_date: '',
|
actual_date: [],
|
actual_begin_date: '',
|
actual_end_date: '',
|
remark: '',
|
fileList: [],
|
})
|
|
const projectTaskStatusArr = ref([])
|
const projectTaskAssignStatus = ref([])
|
const projectTaskTypeArr = ref([])
|
const projectTaskPriorityArr = ref([])
|
const userList = ref([])
|
|
const projectInfoArr = ref([])
|
const projectModuleArr = ref([])
|
const projectModuleTreeArr = ref([])
|
const moduleCascaderProps = {
|
value: 'id', // 设置 value 字段
|
label: 'name', // 设置 label 字段
|
children: 'children', // 设置子项的字段
|
checkStrictly: true, // 设置任意节点的子节点是否可以勾选
|
}
|
|
const listAssign = (a, b) => Object.keys(a).forEach(key => {
|
a[key] = b[key] || a[key]
|
})
|
|
const handleProjectChange = async e => {
|
// 编辑操作
|
projectModuleTreeArr.value = await ProjectModuleInfo.getProjectModuleTree({ projectId: e })
|
}
|
|
// 格式化日期为 "YYYY-MM-DD" 格式
|
const formatDate = date => {
|
const d = new Date(date)
|
const year = d.getFullYear()
|
const month = (d.getMonth() + 1).toString().padStart(2, '0') // 获取月份,补充零
|
const day = d.getDate().toString().padStart(2, '0') // 获取日期,补充零
|
return `${year}-${month}-${day}` // 返回格式化后的日期
|
}
|
|
/**
|
* 表单规则验证
|
*/
|
const rules = {
|
project_id: [{ message: '请选择项目', trigger: ['blur', 'change'], required: true }],
|
module_id: [
|
{
|
validator: (rule, value, callback) => {
|
if (!value) {
|
callback(new Error('请选择项目'))
|
}
|
const project = projectInfoArr.value.filter(item => item.id === value)
|
if (project && project.length > 0) {
|
callback(new Error('根节点为项目节点,不可选择'))
|
}
|
|
callback()
|
},
|
trigger: 'blur,change',
|
required: true,
|
},
|
],
|
name: [{ message: '请输入任务名称', trigger: ['blur', 'change'], required: true }],
|
description: [{ message: '请输入任务描述', trigger: ['blur', 'change'], required: true }],
|
type: [{ message: '请选择任务类型', trigger: ['blur', 'change'], required: true }],
|
priority: [{ message: '请选择优先级', trigger: ['blur', 'change'], required: true }],
|
status: [{ message: '请选择任务状态', trigger: ['blur', 'change'], required: true }],
|
assign_status: [{ message: '请选择排配状态', trigger: ['blur', 'change'], required: true }],
|
evaluator_users: [{ message: '请选择评估人', trigger: ['blur', 'change'], required: true }],
|
// developer_users: [{ message: '请选择开发人员', trigger: ['blur', 'change'], required: true }],
|
plan_hour: [
|
{ message: '请输入计划工时', trigger: ['blur', 'change'], required: true },
|
{
|
validator: (rule, value, callback) => {
|
if (value <= 0) {
|
callback(new Error('计划工时必须大于 0'))
|
} else {
|
callback() // 验证通过
|
}
|
},
|
trigger: ['blur', 'change'],
|
},
|
],
|
plan_date: [
|
{ message: '请输入计划时间', trigger: ['blur', 'change'], required: true },
|
{
|
validator: (rule, value, callback) => {
|
if (!value || value.length !== 2) {
|
return callback(new Error('请选择完整的日期范围'))
|
}
|
|
// 获取当前日期,格式为 "YYYY-MM-DD"
|
const today = formatDate(new Date())
|
|
// 获取选择的开始时间和结束时间
|
const startDate = formatDate(value[0])
|
const endDate = formatDate(value[1])
|
// 比较开始日期和结束日期
|
if (startDate < today) {
|
callback(new Error('计划开始时间不能小于今天'))
|
} else {
|
callback() // 验证通过
|
}
|
},
|
trigger: ['blur', 'change'],
|
},
|
],
|
}
|
|
onMounted(() => {
|
loadDictDitems()
|
})
|
|
const loadDictDitems = async () => {
|
if (props.editId) {
|
await getProjectInfo()
|
projectModuleTreeArr.value = await ProjectModuleInfo.getProjectModuleTree({ projectId: project.project_id })
|
} else {
|
projectModuleTreeArr.value = await ProjectModuleInfo.getProjectModuleTree({})
|
}
|
projectTaskStatusArr.value = await sysDictItemModel.getSysDictItemListByType('project_task_status')
|
projectTaskAssignStatus.value = await sysDictItemModel.getSysDictItemListByType('project_task_assign_status')
|
projectTaskTypeArr.value = await sysDictItemModel.getSysDictItemListByType('project_task_type')
|
projectTaskPriorityArr.value = await sysDictItemModel.getSysDictItemListByType('project_task_priority')
|
|
projectInfoArr.value = await ProjectInfo.getProjectInfoList('')
|
projectModuleArr.value = await ProjectModuleInfo.getProjectModuleInfoList({})
|
|
// const res = await AdminInfo.getAdminUsers({ groupId: 7, count: 30 })
|
const res = await AdminInfo.getAdminUsers({ count: 30 })
|
if (res && res.items) {
|
userList.value = res.items
|
}
|
}
|
|
const getProjectInfo = async () => {
|
loading.value = true
|
const res = await ProjectTaskInfo.get(props.editId)
|
listAssign(project, res)
|
project.plan_date = []
|
project.plan_date.push(`${project.plan_begin_date}`)
|
project.plan_date.push(`${project.plan_end_date}`)
|
if (project.evaluator_users) {
|
const evaluator_users = project.evaluator_users.map(item => Number(item.evaluator_id))
|
project.evaluator_users = evaluator_users
|
}
|
project.value = res
|
if (res.file_list) {
|
project.file_list = res.file_list
|
}
|
|
loading.value = false
|
}
|
|
const handleModuleChange = value => {
|
if (value && value.length > 0) {
|
// 仅保存最后一级的 id
|
project.module_id = value[value.length - 1] // 取最后一个值
|
} else {
|
project.module_id = null // 如果没有选择,则清空
|
}
|
}
|
|
// 重置表单
|
const resetForm = () => {
|
form.value.resetFields()
|
}
|
|
const submitForm = async formName => {
|
console.log('submitForm')
|
console.log(project.file_list)
|
// 遍历文件列表,将文件对象转换为文件信息对象
|
const tmpFile = []
|
if (project.file_list && project.file_list.length > 0) {
|
project.file_list.forEach(file => {
|
tmpFile.push(file.id)
|
})
|
project.upload_file_list = tmpFile
|
}
|
|
form.value.validate(async valid => {
|
if (valid) {
|
project.plan_begin_date = project.plan_date[0]
|
project.plan_end_date = project.plan_date[1]
|
let res = {}
|
if (props.editId) {
|
res = await ProjectTaskInfo.edit(props.editId, project)
|
context.emit('editClose')
|
} else {
|
res = await ProjectTaskInfo.create(project)
|
resetForm(formName)
|
}
|
if (res.code < window.MAX_SUCCESS_CODE) {
|
ElMessage.success(`${res.message}`)
|
}
|
} else {
|
console.error('error submit!!')
|
ElMessage.error('请将信息填写完整')
|
}
|
})
|
}
|
|
const back = () => {
|
context.emit('editClose')
|
}
|
|
return {
|
back,
|
project,
|
form,
|
rules,
|
resetForm,
|
submitForm,
|
|
projectTaskStatusArr,
|
projectTaskAssignStatus,
|
projectTaskTypeArr,
|
projectTaskPriorityArr,
|
userList,
|
|
projectInfoArr,
|
projectModuleArr,
|
projectModuleTreeArr,
|
moduleCascaderProps,
|
|
handleProjectChange,
|
handleModuleChange,
|
|
uploader,
|
handleUploadRemove,
|
handleUploadPreview,
|
handleExceed,
|
handleUploadBeforeRemove,
|
handleUploadSuccess,
|
beforeAvatarUpload,
|
}
|
},
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.container {
|
.title {
|
height: 59px;
|
line-height: 59px;
|
color: $parent-title-color;
|
font-size: 16px;
|
font-weight: 500;
|
text-indent: 40px;
|
border-bottom: 1px solid #dae1ec;
|
|
.back {
|
float: right;
|
margin-right: 40px;
|
cursor: pointer;
|
}
|
}
|
|
.wrap {
|
padding: 20px;
|
}
|
|
.submit {
|
float: left;
|
}
|
}
|
</style>
|