You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
453 lines
14 KiB
453 lines
14 KiB
<template>
|
|
<div class="task-form bg-white border-radius-10">
|
|
<a-form ref="formRef" :model="topicSubFormData">
|
|
<a-form-item>
|
|
<label class="color-3">子课题名称</label>
|
|
<a-input v-model:value="topicSubFormData.name" placeholder="子课题名称" />
|
|
</a-form-item>
|
|
|
|
<a-form-item>
|
|
<label class="color-3">子课题负责人</label>
|
|
<a-select
|
|
v-model:value="topicSubFormData.memberId"
|
|
show-search
|
|
optionFilterProp="label"
|
|
placeholder="负责人"
|
|
:options="options"
|
|
:filter-option="filterOption"
|
|
@search="handleSearch"
|
|
:getPopupContainer="
|
|
triggerNode => {
|
|
return triggerNode.parentNode || document.body;
|
|
}
|
|
"
|
|
></a-select>
|
|
</a-form-item>
|
|
|
|
<a-form-item>
|
|
<label class="color-3">完成期限</label>
|
|
<a-space direction="vertical" :size="12">
|
|
<a-range-picker v-model:value="topicSubFormData.date" />
|
|
</a-space>
|
|
</a-form-item>
|
|
|
|
<a-form-item class="form-item-dad">
|
|
<div class="flex items-center" style="margin-bottom: 5px">
|
|
<label class="color-3" style="margin-bottom: 0; margin-right: 8px">进度安排</label>
|
|
<PlusCircleOutlined style="color: #1890ff; font-size: 16px" @click="addMilestones" />
|
|
</div>
|
|
|
|
<div class="form-item-son" style="padding-left: 16px">
|
|
<div v-for="(item, index) in stageList" :key="index">
|
|
<a-form-item>
|
|
<label class="color-3">时间</label>
|
|
<a-space direction="vertical" :size="12">
|
|
<a-range-picker v-model:value="item.date" />
|
|
</a-space>
|
|
</a-form-item>
|
|
|
|
<a-form-item>
|
|
<label class="color-3">指标</label>
|
|
|
|
<a-checkbox-group v-model:value="item.checkContent">
|
|
<a-row>
|
|
<a-col :span="5" class="deliverables">
|
|
<a-checkbox value="1" @change="handleChange($event, item)">
|
|
<span class="color-6">论文</span>
|
|
<a-input v-model:value="item.thesis" @change="handleInput($event, item, '1')" />
|
|
</a-checkbox>
|
|
</a-col>
|
|
<a-col :span="15" class="deliverables">
|
|
<a-checkbox value="2" @change="handleChange($event, item)">
|
|
<span class="color-6">专利</span>
|
|
<a-input v-model:value="item.patent" @change="handleInput($event, item, '2')" />
|
|
</a-checkbox>
|
|
</a-col>
|
|
<a-col :span="4" class="deliverables">
|
|
<a-checkbox value="3" @change="handleChange($event, item)">
|
|
<span class="color-6">软著</span>
|
|
<a-input v-model:value="item.theSoft" @change="handleInput($event, item, '3')" />
|
|
</a-checkbox>
|
|
</a-col>
|
|
<a-col :span="5" class="deliverables-son" style="padding-left: 14px">
|
|
<a-checkbox value="4" @change="handleChange($event, item)">
|
|
<span class="color-6">SCI论文</span>
|
|
<a-input v-model:value="item.sciThesis" @change="handleInput($event, item, '4')" />
|
|
</a-checkbox>
|
|
</a-col>
|
|
<a-col :span="5" class="deliverables-son" style="padding-left: 14px">
|
|
<a-checkbox value="5" @change="handleChange($event, item)">
|
|
<span class="color-6">发明专利</span>
|
|
<a-input v-model:value="item.inventPatent" @change="handleInput($event, item, '5')" />
|
|
</a-checkbox>
|
|
</a-col>
|
|
<a-col :span="5" class="deliverables-son">
|
|
<a-checkbox value="6" @change="handleChange($event, item)">
|
|
<span class="color-6">实用新型</span>
|
|
<a-input v-model:value="item.practicalPatent" @change="handleInput($event, item, '6')" />
|
|
</a-checkbox>
|
|
</a-col>
|
|
<a-col :span="5" class="deliverables-son">
|
|
<a-checkbox value="7" @change="handleChange($event, item)">
|
|
<span class="color-6">外观专利</span>
|
|
<a-input v-model:value="item.facadePatent" @change="handleInput($event, item, '7')" />
|
|
</a-checkbox>
|
|
</a-col>
|
|
<a-col :span="4" class="deliverables-son"></a-col>
|
|
</a-row>
|
|
</a-checkbox-group>
|
|
</a-form-item>
|
|
</div>
|
|
</div>
|
|
</a-form-item>
|
|
|
|
<a-form-item class="text-right">
|
|
<a-button type="primary" html-type="submit" @click="onSubmit">确定</a-button>
|
|
</a-form-item>
|
|
</a-form>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, watch } from 'vue';
|
|
import { useStore } from 'vuex';
|
|
import { PlusCircleOutlined } from '@ant-design/icons-vue';
|
|
import { message } from 'ant-design-vue';
|
|
import { saveSubExperiment, memberQuery, getSubExperiment } from 'apis';
|
|
import dayjs from 'dayjs';
|
|
|
|
const store = useStore();
|
|
const formRef = ref(null);
|
|
|
|
const projectId = computed(() => store.getters['projects/projectId']); // 项目ID
|
|
const options = ref([]);
|
|
const detailId = computed(() => store.state.task.detailId); // 子课题ID
|
|
|
|
// 项目起止时间
|
|
const planStartTime = computed(() => store.state.layout.planStartTime);
|
|
const planEndTime = computed(() => store.state.layout.planEndTime);
|
|
|
|
const topicSubFormData = ref({
|
|
projectId: projectId.value,
|
|
id: detailId.value,
|
|
name: '',
|
|
memberId: '',
|
|
date: [],
|
|
startTime: '',
|
|
endTime: '',
|
|
stageDtoList: [],
|
|
});
|
|
|
|
const stageList = ref([
|
|
{
|
|
date: [],
|
|
startTime: '',
|
|
endTime: '',
|
|
checkContent: [],
|
|
thesis: '',
|
|
sciThesis: '',
|
|
patent: '',
|
|
inventPatent: '',
|
|
practicalPatent: '',
|
|
facadePatent: '',
|
|
theSoft: '',
|
|
},
|
|
]);
|
|
|
|
if (detailId.value) {
|
|
getSubProject(detailId.value);
|
|
} else {
|
|
renderData();
|
|
}
|
|
|
|
watch(detailId, async () => {
|
|
if (detailId.value) {
|
|
await getSubProject(detailId.value);
|
|
} else {
|
|
renderData();
|
|
}
|
|
});
|
|
|
|
getList(); // 获取成员列表
|
|
|
|
// 添加实施内容与目标
|
|
function addMilestones() {
|
|
stageList.value.push({
|
|
date: [],
|
|
startTime: '',
|
|
endTime: '',
|
|
checkContent: [],
|
|
thesis: '',
|
|
sciThesis: '',
|
|
patent: '',
|
|
inventPatent: '',
|
|
practicalPatent: '',
|
|
facadePatent: '',
|
|
theSoft: '',
|
|
});
|
|
}
|
|
|
|
const handleChange = (e, data) => {
|
|
if (e.target.checked) {
|
|
if (e.target.value === '4') {
|
|
if (data.checkContent.indexOf('1') === -1) {
|
|
data.checkContent.push('1');
|
|
}
|
|
} else if (e.target.value === '5' || e.target.value === '6' || e.target.value === '7') {
|
|
if (data.checkContent.indexOf('2') === -1) {
|
|
data.checkContent.push('2');
|
|
}
|
|
}
|
|
} else if (e.target.value === '1') {
|
|
data.thesis = 0;
|
|
} else if (e.target.value === '2') {
|
|
data.patent = 0;
|
|
} else if (e.target.value === '3') {
|
|
data.theSoft = 0;
|
|
} else if (e.target.value === '4') {
|
|
data.sciThesis = 0;
|
|
} else if (e.target.value === '5') {
|
|
data.inventPatent = 0;
|
|
} else if (e.target.value === '6') {
|
|
data.practicalPatent = 0;
|
|
} else if (e.target.value === '7') {
|
|
data.facadePatent = 0;
|
|
}
|
|
};
|
|
|
|
const handleInput = (e, data, label) => {
|
|
if (e.data > 0) {
|
|
if (data.checkContent.indexOf(label) === -1) {
|
|
data.checkContent.push(label);
|
|
}
|
|
|
|
if (label === '4') {
|
|
if (data.checkContent.indexOf('1') === -1) data.checkContent.push('1');
|
|
}
|
|
|
|
if (label === '5' || label === '6' || label === '7') {
|
|
if (data.checkContent.indexOf('2') === -1) data.checkContent.push('2');
|
|
}
|
|
} else {
|
|
if (data.checkContent.indexOf(label) > -1) {
|
|
data.checkContent.splice(data.checkContent.indexOf(label), 1);
|
|
}
|
|
|
|
if (label === '4') {
|
|
if (data.checkContent.indexOf('1') > -1) data.checkContent.splice(data.checkContent.indexOf('1'), 1);
|
|
}
|
|
|
|
if (label === '5' || label === '6' || label === '7') {
|
|
if (data.checkContent.indexOf('2') > -1) data.checkContent.splice(data.checkContent.indexOf('2'), 1);
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleSearch = async value => {
|
|
await getList(value); // 获取成员列表
|
|
};
|
|
|
|
const filterOption = (input, option) => {
|
|
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
|
};
|
|
|
|
// 获取成员列表
|
|
async function getList(name) {
|
|
try {
|
|
const params = { param: { projectId: projectId.value, name } };
|
|
const data = await memberQuery(params);
|
|
store.commit('task/setMembers', data);
|
|
options.value = [];
|
|
|
|
data.forEach(item => {
|
|
const obj = {
|
|
label: item.memberName,
|
|
value: item.memberId,
|
|
};
|
|
|
|
options.value.push(obj);
|
|
});
|
|
} catch (error) {
|
|
message.info(error);
|
|
throw new Error(error);
|
|
}
|
|
}
|
|
|
|
const onSubmit = async () => {
|
|
let msgText = '';
|
|
|
|
if (topicSubFormData.value.date) {
|
|
topicSubFormData.value.date.forEach((item, index) => {
|
|
if (index === 0) {
|
|
topicSubFormData.value.startTime = dayjs(item).format('x');
|
|
} else {
|
|
topicSubFormData.value.endTime = dayjs(item).format('x');
|
|
}
|
|
});
|
|
|
|
if (topicSubFormData.value.startTime < planStartTime.value) {
|
|
msgText = '子课题开始时间不能小于项目起始时间';
|
|
}
|
|
if (topicSubFormData.value.endTime > planEndTime.value) {
|
|
msgText = '子课题结束时间不能大于项目终止时间';
|
|
}
|
|
}
|
|
|
|
stageList.value.forEach(item => {
|
|
if (item.date.length > 0) {
|
|
item.date.forEach((val, key) => {
|
|
if (key === 0) {
|
|
item.startTime = dayjs(val).format('x');
|
|
} else {
|
|
item.endTime = dayjs(val).format('x');
|
|
}
|
|
});
|
|
|
|
if (item.startTime < topicSubFormData.value.startTime || item.endTime > topicSubFormData.value.endTime) {
|
|
msgText = '子课题进度安排起止必须在子课题起止时间';
|
|
}
|
|
}
|
|
|
|
if (item.checkContent.indexOf('1') > -1) {
|
|
if (!item.thesis) msgText = '请填写论文数量';
|
|
}
|
|
if (item.checkContent.indexOf('2') > -1) {
|
|
if (!item.patent) msgText = '请填写专利数量';
|
|
}
|
|
if (item.checkContent.indexOf('3') > -1) {
|
|
if (!item.theSoft) msgText = '请填写软著数量';
|
|
}
|
|
if (item.checkContent.indexOf('4') > -1) {
|
|
if (!item.sciThesis) msgText = '请填写SCI论文数量';
|
|
}
|
|
if (item.checkContent.indexOf('5') > -1) {
|
|
if (!item.inventPatent) msgText = '请填写发明专利数量';
|
|
}
|
|
if (item.checkContent.indexOf('6') > -1) {
|
|
if (!item.practicalPatent) msgText = '请填写实用新型专利数量';
|
|
}
|
|
if (item.checkContent.indexOf('7') > -1) {
|
|
if (!item.facadePatent) msgText = '请填写外观专利数量';
|
|
}
|
|
if (item.thesis < item.sciThesis) msgText = 'SCI论文数量不能比总论文数量大';
|
|
const totalPatent = Number(item.inventPatent) + Number(item.practicalPatent) + Number(item.facadePatent);
|
|
if (item.patent < totalPatent) msgText = '发明专利数量、实用新型专利数量、外观专利数量总和不能比总专利数量大';
|
|
});
|
|
|
|
if (msgText) {
|
|
message.info(msgText);
|
|
return false;
|
|
}
|
|
|
|
topicSubFormData.value.stageDtoList = [...stageList.value];
|
|
|
|
const params = { param: topicSubFormData.value };
|
|
await saveSubExperiment(params);
|
|
store.commit('layout/setRefreshProjects');
|
|
store.commit('layout/setSecPlanTime', { startTime: topicSubFormData.value.startTime, endTime: topicSubFormData.value.endTime });
|
|
|
|
if (detailId.value) {
|
|
getSubProject(detailId.value);
|
|
} else {
|
|
renderData();
|
|
}
|
|
};
|
|
|
|
async function getSubProject(id) {
|
|
try {
|
|
const params = { param: { taskDetailId: id } };
|
|
const data = await getSubExperiment(params);
|
|
|
|
if (data) {
|
|
const start = dayjs(Number(data.startTime));
|
|
const end = dayjs(Number(data.endTime));
|
|
data.date = [start, end];
|
|
data.projectId = projectId.value;
|
|
topicSubFormData.value = data;
|
|
data.subExperimentStageDtoList.forEach(item => {
|
|
item.startTime = item.stageStartTime;
|
|
item.endTime = item.stageEndTime;
|
|
console.log(item.startTime !== '0');
|
|
if (item.startTime !== '0') {
|
|
item.date = [dayjs(Number(item.startTime)), dayjs(Number(item.endTime))];
|
|
}
|
|
|
|
item.checkContent = [];
|
|
if (item.thesis) item.checkContent.push('1');
|
|
if (item.patent) item.checkContent.push('2');
|
|
if (item.theSoft) item.checkContent.push('3');
|
|
if (item.sciThesis) item.checkContent.push('4');
|
|
if (item.inventPatent) item.checkContent.push('5');
|
|
if (item.practicalPatent) item.checkContent.push('6');
|
|
if (item.facadePatent) item.checkContent.push('7');
|
|
});
|
|
stageList.value = data.subExperimentStageDtoList;
|
|
} else {
|
|
// 如果返回值为空渲染空数据
|
|
renderData();
|
|
}
|
|
} catch (error) {
|
|
message.info(error);
|
|
throw new Error(error);
|
|
}
|
|
}
|
|
|
|
// 如果是添加渲染数据
|
|
function renderData() {
|
|
topicSubFormData.value = {
|
|
projectId: projectId.value,
|
|
id: detailId.value,
|
|
name: '',
|
|
memberId: '',
|
|
date: [],
|
|
startTime: '',
|
|
endTime: '',
|
|
stageDtoList: [],
|
|
};
|
|
stageList.value = [
|
|
{
|
|
date: [],
|
|
startTime: '',
|
|
endTime: '',
|
|
checkContent: [],
|
|
thesis: '',
|
|
sciThesis: '',
|
|
patent: '',
|
|
inventPatent: '',
|
|
practicalPatent: '',
|
|
facadePatent: '',
|
|
theSoft: '',
|
|
},
|
|
];
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.task-detail {
|
|
background-color: #fff;
|
|
}
|
|
|
|
.ant-col {
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.ant-col:nth-child(-n + 4) {
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.deliverables .ant-input,
|
|
.deliverables-son .ant-input {
|
|
width: 23px;
|
|
height: 14px;
|
|
border-radius: 0;
|
|
padding: 0;
|
|
font-size: 12px;
|
|
color: #1890ff;
|
|
text-align: center;
|
|
margin-left: 5px;
|
|
}
|
|
|
|
.deliverables-son {
|
|
margin-top: 10px !important;
|
|
}
|
|
</style>
|
|
|