Browse Source

feat: "分配子课题、项目详情分组件"

master
xuesinan 4 years ago
parent
commit
981ca45008
  1. 31
      src/App.vue
  2. 5
      src/apis/index.js
  3. 68
      src/components/tall/center/Global.vue
  4. 57
      src/components/tall/center/Index.vue
  5. 343
      src/components/tall/center/ProjectDetail.vue
  6. 186
      src/components/tall/center/RegularTask.vue
  7. 93
      src/components/tall/center/Roles.vue
  8. 17
      src/components/tall/left/Projects.vue
  9. 22
      src/components/tall/task/AssignmentExperiment.vue
  10. 178
      src/components/tall/task/AssignmentSubject.vue
  11. 1
      src/store/tall/role/mutations.js
  12. 48
      src/store/tall/task/index.js
  13. 4
      src/views/home/Index.vue

31
src/App.vue

@ -132,4 +132,35 @@ body,
display: block;
margin-bottom: 5px;
}
/* 全局提示 */
.ant-message {
position: fixed;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
color: rgba(0, 0, 0, 0.85);
}
.ant-message .ant-message-notice {
margin: 10px 0;
padding: 8px 16px;
background: #fff;
-moz-box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
-webkit-box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
border-radius: 3px;
}
.ant-message .ant-message-custom-content {
display: flex;
align-items: center;
}
.ant-message .ant-message-custom-content .anticon {
margin-right: 8px;
color: #1890ff;
font-size: 16px;
}
</style>

5
src/apis/index.js

@ -73,9 +73,12 @@ export const savePlanTask = params => http.post(`${experiment}/experiment/savePl
// 查看任务计划书
export const getPlanTask = params => http.post(`${experiment}/experiment/getPlanTask`, params);
// 分配子课题
// 添加/编辑子课题
export const saveSubExperiment = params => http.post(`${experiment}/experiment/saveSubExperiment`, params);
// 查看子课题
export const getSubExperiment = params => http.post(`${experiment}/experiment/getSubExperiment`, params);
// 查询成员
export const memberQuery = params => http.post(`${experiment}/organization/query`, params);

68
src/components/tall/center/Global.vue

@ -0,0 +1,68 @@
<template>
<div class="global">
<div class="global-box" v-if="permanents && permanents.length > 0">
<div class="global-task cursor-pointer" v-for="(item, index) in permanents" :key="index" @click="toDetail(item)">
<template v-for="v in item.plugins">
<template v-if="v[0].pluginId == 1">{{ item.name }}</template>
</template>
</div>
</div>
</div>
</template>
<script setup>
import { computed, watch } from 'vue';
import { useStore } from 'vuex';
import { getPermanent } from 'apis';
const store = useStore();
const project = computed(() => store.state.projects.project); //
const roleId = computed(() => store.state.role.roleId); //
const permanents = computed(() => store.state.task.permanents); //
const sessionPermanents = sessionStorage.getItem('permanents'); //
if (sessionPermanents) {
const arr = JSON.parse(sessionPermanents);
store.commit('task/setPermanents', arr);
}
watch([project, roleId], async () => {
if (roleId.value) {
await getPermanentData(roleId.value); //
}
});
//
async function getPermanentData(id) {
const params = { param: { roleId: id } };
try {
const data = await getPermanent(params);
store.commit('task/setPermanents', data);
const globalHeight = data.length * 38 + 26;
store.commit('task/setGlobalHeight', globalHeight);
} catch (error) {
throw new Error(error);
}
}
function toDetail(item) {
store.commit('task/setTaskDetail', item);
}
</script>
<style scoped>
.global {
padding: 16px;
}
.global-box {
border: 1px solid #cccccc;
border-radius: 10px;
padding: 12px 16px;
}
.global-task {
padding: 8px 0;
line-height: 22px;
}
</style>

57
src/components/tall/center/Index.vue

@ -0,0 +1,57 @@
<template>
<div>
<!-- 项目标题 -->
<div class="navbar flex items-center justify-between">
<div class="project-name">{{ project.name }}</div>
<div class="project-action">
<ReloadOutlined :style="{ fontSize: 20 + 'px' }" />
<MoreOutlined :style="{ fontSize: 20 + 'px' }" />
</div>
</div>
<!-- 角色 -->
<Roles />
<!-- 日常任务 -->
<Global />
<!-- 定期任务 -->
<RegularTask />
</div>
</template>
<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';
import { ReloadOutlined, MoreOutlined } from '@ant-design/icons-vue';
import Roles from './Roles.vue'; //
import Global from './Global.vue'; //
import RegularTask from './RegularTask.vue'; //
const store = useStore();
const project = computed(() => store.state.projects.project); //
const sessionProject = sessionStorage.getItem('project'); //
if (sessionProject) {
const projectInfo = JSON.parse(sessionProject);
store.commit('projects/setProject', projectInfo);
}
</script>
<style scoped>
.navbar {
padding: 0 16px;
height: 44px;
}
.project-name {
font-size: 16px;
font-weight: 600;
color: #333;
}
.project-action .anticon {
margin-left: 16px;
cursor: pointer;
}
</style>

343
src/components/tall/center/ProjectDetail.vue

@ -1,343 +0,0 @@
<template>
<!-- 项目标题 -->
<div class="navbar flex items-center justify-between">
<div class="project-name">{{ project.name }}</div>
<div class="project-action">
<ReloadOutlined :style="{ fontSize: 20 + 'px' }" />
<MoreOutlined :style="{ fontSize: 20 + 'px' }" />
</div>
</div>
<!-- 角色 -->
<div class="role-list flex items-center">
<div class="role-box relative" v-for="(item, index) in roles" :key="index">
<div class="role-name" :class="{ mine: item.mine === 1 && currRoleId === item.id }">{{ item.name }}</div>
<div class="line-box absolute flex justify-center" v-if="item.mine === 1 && currRoleId === item.id"><div class="line"></div></div>
</div>
</div>
<!-- 日常任务 -->
<div class="global">
<div class="global-box" v-if="permanentObj.permanentList && permanentObj.permanentList.length > 0">
<div class="global-task cursor-pointer" v-for="(item, index) in permanentObj.permanentList" :key="index" @click="toDetail(item)">
<template v-for="v in item.plugins">
<template v-if="v[0].pluginId == 1">{{ item.name }}</template>
</template>
</div>
</div>
</div>
<!-- 定期任务 -->
<div class="task-list" :style="{ height: 'calc(100vh - 160px - (' + globalHeight + 'px))' }">
<div class="task-box" v-for="(item, index) in taskObj.tasks" :key="index">
<div class="task-time flex items-center justify-between">
<div class="flex items-center">
<PlayCircleOutlined style="font-size: 23px; color: #999999" />
<span>{{ dayjs(item.planStart).format('D日 HH:mm') }}</span>
</div>
<div class="task-action"></div>
</div>
<div class="task-info">
<div>
<div class="task-card">
<div class="task-name cursor-pointer" @click="toDetail(item)">
<template v-for="v in item.plugins">
<template v-if="v[0].pluginId == 1">{{ item.name }}</template>
</template>
</div>
<div class="task-con" v-if="item.sonList && item.sonList.length > 0">
<div v-for="(val, key) in item.sonList" :key="key">
<a-checkbox>{{ val.name }}</a-checkbox>
</div>
</div>
<div class="open-icon" v-if="item.sonList" @click="openCard">
<img />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed, watch, reactive, ref } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import { findShowRole, getRegularTask, findSonTask, findProjectById } from 'apis';
import { ReloadOutlined, MoreOutlined, PlayCircleOutlined } from '@ant-design/icons-vue';
const store = useStore();
const projectId = sessionStorage.getItem('projectId');
const project = computed(() => store.state.projects.project); //
const currRoleId = computed(() => store.state.role.roleId); //
const roles = ref([
{ id: 1, name: '项目经理', mine: 1, pm: 1, sequence: 1 },
{ id: 2, name: '运维', mine: 0, pm: 0, sequence: 2 },
]);
const permanents = computed(() => store.state.role.permanents); //
const permanentObj = reactive({ permanentList: [] }); //
const tasks = computed(() => store.state.role.tasks); //
const taskObj = reactive({ tasks: [] }); //
const globalHeight = ref(0); //
init();
//
watch(project, async () => {
permanentObj.permanentList = permanents.value;
taskObj.tasks = tasks.value;
await getRoles(project.value.id); // id
await getPermanentData(currRoleId.value); //
await getTasks({ roleId: currRoleId.value });
});
// ID
async function init() {
try {
if (projectId) {
permanentObj.permanentList = permanents.value;
taskObj.tasks = tasks.value;
await getFindProjectById(projectId);
await getRoles(projectId); // id
await getPermanentData(currRoleId.value); //
await getTasks({ roleId: currRoleId.value });
}
} catch (error) {
console.log('error: ', error);
}
}
//
function setInitialRoleId(visibleList) {
if (!visibleList || !visibleList.length) return;
roles.value = [...visibleList];
const index = visibleList.findIndex(item => +item.mine === 1);
const currentRole = index > 0 ? visibleList[index] : visibleList[0];
// const storageRoleId = this.$t.storage.getStorageSync('roleId');
// const currentRoleId = storageRoleId ? storageRoleId : currentRole ? currentRole.id : '';
const currentRoleId = currentRole ? currentRole.id : '';
currRoleId.value = currentRoleId;
store.commit('role/setRoleId', currentRoleId);
// storage
// this.$t.storage.setStorageSync('roleId', '');
}
/**
* 通过项目id获取项目信息
* @param {string} projectId
* @param {object} params 提交的参数
*/
async function getFindProjectById(params) {
try {
const data = await findProjectById(params);
store.commit('projects/setProject', data);
} catch (error) {
throw new Error(error);
}
}
/**
* 通过项目id获取角色信息
* @param {string} projectId
* @param {object} params 提交的参数
*/
async function getRoles(params) {
try {
const data = await findShowRole(params);
store.commit('role/setInvisibleRoles', data ? data.invisibleList : []);
store.commit('role/setVisibleRoles', data ? data.visibleList : []);
setInitialRoleId(data ? data.visibleList : []);
} catch (error) {
throw new Error(error);
}
}
//
async function getPermanentData(roleId) {
const params = { param: { roleId } };
try {
const data = await store.dispatch('task/getPermanent', params);
permanentObj.permanentList = data;
globalHeight.value = data.length * 38 + 26;
} catch (error) {
throw new Error(error);
}
}
// id
async function getSonTask(detailId) {
const params = { param: { detailId } };
try {
const data = await findSonTask(params);
taskObj.tasks.forEach(item => {
if (item.detailId === detailId) {
item.sonList = data;
}
});
} catch (error) {
throw new Error(error);
}
}
/**
* 根据时间基准点和角色查找定期任务
* @param {object} query
* @param {string} query.roleId 角色id
* @param {string} query.timeNode 时间基准点 默认当前
* @param {string} query.timeUnit 时间颗粒度 默认天
* @param {string} query.queryNum 查找颗粒度数量 默认3个
* @param {number} query.queryType 0向上查找 1向下查找(默认) 下查包含自己上查不包含
*/
async function getTasks(query) {
const params = { param: query };
try {
const data = await getRegularTask(params);
taskObj.tasks = data;
data.forEach(item => {
item.plugins.forEach(val => {
if (Number(val[0].pluginId) === 6) {
getSonTask(item.detailId);
}
});
});
store.commit('task/setUpTasks', data);
} catch (error) {
throw new Error(error);
}
}
function toDetail(item) {
store.commit('task/setTaskDetail', item);
}
</script>
<style scoped>
.navbar {
padding: 0 16px;
height: 44px;
}
.project-name {
font-size: 16px;
font-weight: 600;
color: #333;
}
.project-action .anticon {
margin-left: 16px;
cursor: pointer;
}
.role-list {
padding: 0 16px;
height: 36px;
border-bottom: 1px solid #cccccc;
}
.role-box {
margin-right: 16px;
height: 36px;
}
.role-name {
font-size: 14px;
line-height: 36px;
color: #333333;
}
.role-name.mine {
font-weight: 600;
color: #1890ff;
}
.role-box .line-box {
width: 100%;
bottom: 0;
}
.line-box .line {
width: 16px;
height: 2px;
background-color: #1890ff;
}
.global {
padding: 16px;
}
.global-box {
border: 1px solid #cccccc;
border-radius: 10px;
padding: 12px 16px;
}
.global-task {
padding: 8px 0;
line-height: 22px;
}
.task-list {
padding: 0 16px 50px;
overflow-y: auto;
}
.task-box {
}
.task-time {
height: 32px;
}
.task-time .anticon {
margin-right: 16px;
}
.task-time span {
font-size: 14px;
color: #595959;
}
.task-info {
margin: 8px 0;
padding-left: 11px;
}
.task-info > div {
padding-left: 27px;
border-left: 1px solid #d2d2d2;
}
.task-info .task-card {
padding: 16px;
border-radius: 8px;
-moz-box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
-webkit-box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
}
.task-con {
margin-top: 16px;
}
.task-con > div {
height: 30px;
}
:deep(.ant-checkbox + span) {
color: #607d8b;
}
.task-list::-webkit-scrollbar {
width: 0 !important;
}
</style>

186
src/components/tall/center/RegularTask.vue

@ -0,0 +1,186 @@
<template>
<div class="task-list" :style="{ height: 'calc(100vh - 160px - (' + globalHeight + 'px))' }">
<div class="task-box" v-for="(item, index) in tasks" :key="index">
<div class="task-time flex items-center justify-between">
<div class="flex items-center">
<PlayCircleOutlined style="font-size: 23px; color: #999999" />
<span>{{ dayjs(item.planStart).format('D日 HH:mm') }}</span>
</div>
<div class="task-action"></div>
</div>
<div class="task-info">
<div>
<div class="task-card">
<div class="task-name cursor-pointer" @click="toDetail(item)">
<template v-for="v in item.plugins">
<template v-if="v[0].pluginId == 1">{{ item.name }}</template>
</template>
</div>
<div class="task-con" v-if="item.sonList && item.sonList.length > 0">
<div v-for="(val, key) in item.sonList" :key="key">
<!-- <a-checkbox>{{ val.name }}</a-checkbox> -->
<span class="son-task-name cursor-pointer" @click.stop="toSonDetail(item, val.detailId)">{{ val.name }}</span>
</div>
</div>
<div class="open-icon" v-if="item.sonList" @click="openCard">
<img />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed, watch, reactive } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import { PlayCircleOutlined } from '@ant-design/icons-vue';
import { getRegularTask, findSonTask } from 'apis';
const store = useStore();
const project = computed(() => store.state.projects.project); //
const roleId = computed(() => store.state.role.roleId); //
const globalHeight = computed(() => store.state.task.globalHeight); //
const sessionGlobalHeight = sessionStorage.getItem('globalHeight'); //
const tasks = computed(() => store.state.task.tasks); //
const taskObj = reactive({ tasks: [] }); //
const sessionTasks = sessionStorage.getItem('tasks'); //
const subProjectInfo = computed(() => store.state.task.subProjectInfo); //
if (sessionGlobalHeight) {
store.commit('task/setGlobalHeight', sessionGlobalHeight);
}
if (sessionTasks) {
const arr = JSON.parse(sessionTasks);
store.commit('task/setUpTasks', arr);
}
watch([project, roleId, subProjectInfo], async () => {
if (roleId.value) {
await getTasks({ roleId: roleId.value }); //
}
});
/**
* 根据时间基准点和角色查找定期任务
* @param {object} query
* @param {string} query.roleId 角色id
* @param {string} query.timeNode 时间基准点 默认当前
* @param {string} query.timeUnit 时间颗粒度 默认天
* @param {string} query.queryNum 查找颗粒度数量 默认3个
* @param {number} query.queryType 0向上查找 1向下查找(默认) 下查包含自己上查不包含
*/
async function getTasks(query) {
const params = { param: query };
try {
const data = await getRegularTask(params);
taskObj.tasks = data;
data.forEach(item => {
item.plugins.forEach(val => {
if (Number(val[0].pluginId) === 6) {
getSonTask(item.detailId);
}
});
});
store.commit('task/setUpTasks', data);
} catch (error) {
throw new Error(error);
}
}
// id
async function getSonTask(id) {
const params = { param: { detailId: id } };
try {
const data = await findSonTask(params);
taskObj.tasks.forEach(item => {
if (item.detailId === id) {
item.sonList = data;
}
});
store.commit('task/setUpTasks', taskObj.tasks);
} catch (error) {
throw new Error(error);
}
}
function toDetail(item) {
store.commit('task/setTaskDetail', item);
store.commit('task/sonDetailId', '');
}
function toSonDetail(item, id) {
store.commit('task/setTaskDetail', item);
store.commit('task/sonDetailId', id);
}
</script>
<style scoped>
.task-list {
padding: 0 16px 50px;
overflow-y: auto;
}
.task-box {
}
.task-time {
height: 32px;
}
.task-time .anticon {
margin-right: 16px;
}
.task-time span {
font-size: 14px;
color: #595959;
}
.task-info {
margin: 8px 0;
padding-left: 11px;
}
.task-info > div {
padding-left: 27px;
border-left: 1px solid #d2d2d2;
}
.task-info .task-card {
padding: 16px;
border-radius: 8px;
-moz-box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
-webkit-box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.12);
}
.task-con {
margin-top: 16px;
padding-left: 16px;
}
.task-con > div {
height: 30px;
}
:deep(.ant-checkbox + span) {
color: #607d8b;
}
.son-task-name {
color: #607d8b;
}
.task-list::-webkit-scrollbar {
width: 0 !important;
}
</style>

93
src/components/tall/center/Roles.vue

@ -0,0 +1,93 @@
<template>
<div class="role-list flex items-center">
<div class="role-box relative" v-for="(item, index) in roles" :key="index">
<div class="role-name" :class="{ mine: item.mine === 1 && roleId === item.id }">{{ item.name }}</div>
<div class="line-box absolute flex justify-center" v-if="item.mine === 1 && roleId === item.id"><div class="line"></div></div>
</div>
</div>
</template>
<script setup>
import { computed, watch } from 'vue';
import { useStore } from 'vuex';
import { findShowRole } from 'apis';
const store = useStore();
const roleId = computed(() => store.state.role.roleId); //
const sessionRoles = sessionStorage.getItem('roles'); //
const roles = computed(() => store.state.role.visibleRoles); //
const project = computed(() => store.state.projects.project); //
if (sessionRoles) {
const roleArr = JSON.parse(sessionRoles);
store.commit('role/setVisibleRoles', roleArr);
setInitialRoleId(roleArr);
}
watch(project, async () => {
if (project.value.id) {
await getRoles(project.value.id); // id
}
});
/**
* 通过项目id获取角色信息
* @param {string} projectId
* @param {object} params 提交的参数
*/
async function getRoles(params) {
try {
const data = await findShowRole(params);
store.commit('role/setInvisibleRoles', data ? data.invisibleList : []);
store.commit('role/setVisibleRoles', data ? data.visibleList : []);
setInitialRoleId(data ? data.visibleList : []);
} catch (error) {
throw new Error(error);
}
}
//
function setInitialRoleId(visibleList) {
if (!visibleList || !visibleList.length) return;
const index = visibleList.findIndex(item => +item.mine === 1);
const currentRole = index > 0 ? visibleList[index] : visibleList[0];
const currentRoleId = currentRole ? currentRole.id : '';
store.commit('role/setRoleId', currentRoleId);
}
</script>
<style scoped>
.role-list {
padding: 0 16px;
height: 36px;
border-bottom: 1px solid #cccccc;
}
.role-box {
margin-right: 16px;
height: 36px;
}
.role-name {
font-size: 14px;
line-height: 36px;
color: #333333;
}
.role-name.mine {
font-weight: 600;
color: #1890ff;
}
.role-box .line-box {
width: 100%;
bottom: 0;
}
.line-box .line {
width: 16px;
height: 2px;
background-color: #1890ff;
}
</style>

17
src/components/tall/left/Projects.vue

@ -1,7 +1,7 @@
<template>
<a-divider />
<div class="list-flex">
<div class="item-box" v-for="(item, index) in projectList" :key="index">
<div class="item-box" v-for="(item, index) in projects" :key="index">
<div class="one-level h-70 cursor-pointer flex items-center" @click="toDetail(item)">
<div class="icon" @click.stop="showActionCard(item)"><img src="https://www.tall.wiki/staticrec/drag.svg" /></div>
<div class="detail">
@ -76,23 +76,22 @@ import { getProjects, delProject } from 'apis';
import { RightOutlined, DownOutlined } from '@ant-design/icons-vue';
const store = useStore();
// const projects = reactive({ projects: [] });
const visible = ref(false);
const deleteId = ref(null);
const projectId = sessionStorage.getItem('projectId');
const projectInfo = computed(() => store.state.projects.project); //
const newProject = computed(() => store.state.projects.newProject); //
const projects = computed(() => store.state.projects.projects); //
const subProjectInfo = computed(() => store.state.task.subProjectInfo); //
const startTime = computed(() => store.state.layout.startTime); //
const endTime = computed(() => store.state.layout.endTime); //
let start = startTime.value ? startTime.value : dayjs().startOf('day').format('x');
let end = endTime.value ? endTime.value : dayjs().startOf('day').format('x');
const projectList = ref([]);
projectList.value = [...projects.value];
let end = endTime.value ? endTime.value : dayjs().endOf('day').format('x');
watch([newProject, startTime, endTime, projectInfo], () => {
watch([newProject, startTime, endTime, projectInfo, subProjectInfo], () => {
start = startTime.value ? startTime.value : dayjs().startOf('day').format('x');
end = endTime.value ? endTime.value : dayjs().startOf('day').format('x');
end = endTime.value ? endTime.value : dayjs().endOf('day').format('x');
getProjectsList(start, end);
});
@ -126,10 +125,8 @@ async function getProjectsList(startData, endData) {
}
});
}
// projectList.value.push(item);
});
projectList.value = [...data];
// projectList.value = [...data];
store.commit('projects/setProjects', data);
} catch (error) {

22
src/components/tall/task/AssignmentExperiment.vue

@ -1,21 +1,21 @@
<template>
<div class="task-form bg-white border-radius-10">
<a-form ref="formRef" :model="experimentFormData">
<a-form ref="formRef" :model="assignExperFormData">
<a-form-item>
<label class="color-3">实验名称</label>
<a-input v-model:value="experimentFormData.name" placeholder="实验名称" />
<a-input v-model:value="assignExperFormData.name" placeholder="实验名称" />
</a-form-item>
<a-form-item>
<label class="color-3">完成期限</label>
<a-space direction="vertical" :size="12">
<a-range-picker v-model:value="experimentFormData.date" />
<a-range-picker v-model:value="assignExperFormData.date" />
</a-space>
</a-form-item>
<a-form-item>
<label class="color-3">负责人</label>
<a-select v-model:value="experimentFormData.memberId">
<a-select v-model:value="assignExperFormData.memberId">
<a-select-option value="jack">Jack</a-select-option>
<a-select-option value="lucy">Lucy</a-select-option>
<a-select-option value="Yiminghe">yiminghe</a-select-option>
@ -24,7 +24,7 @@
<a-form-item>
<label class="color-3">实验目标</label>
<a-textarea v-model:value="experimentFormData.target" placeholder="实验目标" />
<a-textarea v-model:value="assignExperFormData.target" placeholder="实验目标" />
</a-form-item>
<a-form-item class="text-right">
@ -50,7 +50,7 @@ if (sessionProject) {
store.commit('projects/setProject', project);
}
const experimentFormData = ref({
const assignExperFormData = ref({
projectId: projectId.value,
id: '',
name: '',
@ -62,18 +62,18 @@ const experimentFormData = ref({
});
const onSubmit = () => {
experimentFormData.value.date.forEach((item, index) => {
assignExperFormData.value.date.forEach((item, index) => {
if (index === 0) {
experimentFormData.value.startTime = dayjs(item).format('x');
assignExperFormData.value.startTime = dayjs(item).format('x');
} else {
experimentFormData.value.endTime = dayjs(item).format('x');
assignExperFormData.value.endTime = dayjs(item).format('x');
}
});
// const params = { param: experimentFormData.value };
// const params = { param: assignExperFormData.value };
// createExperiment(params);
console.log('submit!', toRaw(experimentFormData.value));
console.log('submit!', toRaw(assignExperFormData.value));
};
</script>

178
src/components/tall/task/AssignmentSubject.vue

@ -8,11 +8,20 @@
<a-form-item>
<label class="color-3">子课题负责人</label>
<a-select v-model:value="topicSubFormData.memberId">
<a-select-option value="jack">Jack</a-select-option>
<a-select-option value="lucy">Lucy</a-select-option>
<a-select-option value="Yiminghe">yiminghe</a-select-option>
</a-select>
<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>
@ -79,39 +88,38 @@
</template>
<script setup>
import { ref, computed, toRaw } from 'vue';
import { ref, computed, watch } from 'vue';
import { useStore } from 'vuex';
import { PlusCircleOutlined } from '@ant-design/icons-vue';
// import { saveSubExperiment } from 'apis';
import { message } from 'ant-design-vue';
import { saveSubExperiment, memberQuery, getSubExperiment } from 'apis';
import dayjs from 'dayjs';
const store = useStore();
const formRef = ref(null);
const sessionProject = sessionStorage.getItem('project');
const projectId = computed(() => store.getters['projects/projectId']);
const sessionTaskDetail = sessionStorage.getItem('taskDetail');
const taskDetail = computed(() => store.state.task.taskDetail); //
const sessionProject = sessionStorage.getItem('project'); //
const projectId = computed(() => store.getters['projects/projectId']); // ID
const options = ref([]);
const detailId = computed(() => store.state.task.detailId); // ID
if (sessionProject) {
const project = JSON.parse(sessionProject);
store.commit('projects/setProject', project);
}
if (sessionTaskDetail) {
const detail = JSON.parse(sessionTaskDetail);
store.commit('task/setTaskDetail', detail);
}
watch(detailId, async () => {
await getSubProject(detailId.value);
});
const topicSubFormData = ref({
projectId: projectId.value,
taskId: taskDetail.value.id,
experimentId: '',
id: detailId.value,
name: '',
memberId: '',
date: [],
startTime: '',
endTime: '',
stageList: [],
stageDtoList: [],
});
const stageList = ref([
@ -147,33 +155,94 @@ function addMilestones() {
});
}
const onSubmit = () => {
topicSubFormData.value.stageList = [];
getList(); //
stageList.value.forEach(item => {
const obj = {
startTime: '',
endTime: '',
thesis: item.thesis,
sciThesis: item.sciThesis,
patent: item.patent,
inventPatent: item.inventPatent,
practicalPatent: item.practicalPatent,
facadePatent: item.facadePatent,
theSoft: item.theSoft,
};
const handleSearch = async value => {
console.log('handleSearch', options.value, 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) {
console.log('error', error);
}
}
const onSubmit = () => {
stageList.value.forEach(item => {
item.date.forEach((val, key) => {
if (key === 0) {
obj.startTime = dayjs(val).format('x');
item.startTime = dayjs(val).format('x');
} else {
obj.endTime = dayjs(val).format('x');
item.endTime = dayjs(val).format('x');
}
});
});
let msgText = '';
stageList.value.forEach(item => {
console.log(item);
if (item.checkContent.indexOf('1') > -1) {
if (!item.thesis) msgText = '请填写论文数量';
}
if (item.checkContent.indexOf('2') > -1) {
if (!item.patent) msgText = '请填写专利数量';
}
topicSubFormData.value.stageList.push(obj);
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];
topicSubFormData.value.date.forEach((item, index) => {
if (index === 0) {
topicSubFormData.value.startTime = dayjs(item).format('x');
@ -182,11 +251,42 @@ const onSubmit = () => {
}
});
// const params = { param: topicSubFormData.value };
// saveSubExperiment(params);
console.log('submit!', toRaw(topicSubFormData.value), stageList.value);
const params = { param: topicSubFormData.value };
saveSubExperiment(params);
getSubProject(detailId.value);
};
async function getSubProject(id) {
try {
const params = { param: { taskDetailId: id } };
const data = await getSubExperiment(params);
store.commit('task/setSubProjectInfo', 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;
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;
} catch (error) {
throw new Error(error);
}
}
</script>
<style scoped>

1
src/store/tall/role/mutations.js

@ -15,6 +15,7 @@ const mutations = {
*/
setVisibleRoles(state, data) {
state.visibleRoles = data || [];
sessionStorage.setItem('roles', JSON.stringify(data));
},
/**

48
src/store/tall/task/index.js

@ -1,4 +1,4 @@
import { getGlobal, getPermanent } from 'apis';
// import { getGlobal, getPermanent } from 'apis';
export default {
namespaced: true,
@ -28,6 +28,9 @@ export default {
taskDetail: {}, // 当前点击任务信息
label: '', // 任务code
members: [], // 成员列表
globalHeight: 0, // 日常任务面板高度
detailId: '', // 子课题Id
subProjectInfo: null, // 当前子课题信息
},
getters: {
@ -154,6 +157,8 @@ export default {
state.tasks = [...arr];
// state.tasks = [...data.concat(state.tasks)];
}
const arr = state.tasks;
sessionStorage.setItem('tasks', JSON.stringify(arr));
},
/**
@ -220,6 +225,7 @@ export default {
*/
setPermanents(state, tasks) {
state.permanents = tasks || [];
sessionStorage.setItem('permanents', JSON.stringify(tasks));
},
/**
@ -320,37 +326,29 @@ export default {
setMembers(state, data) {
state.members = data || [];
},
},
actions: {
/**
* 根据角色查找永久的日常任务
* @param {*} commit
* @param {string} roleId 角色id
* 设置日常任务面板高度
*/
async getPermanent({ commit }, param) {
try {
const data = await getPermanent(param);
commit('setPermanents', data);
return data;
} catch (error) {
throw new Error(error);
}
setGlobalHeight(state, data) {
state.globalHeight = data;
sessionStorage.setItem('globalHeight', data);
},
/**
* 根据时间和角色查找日常任务
* @param {*} commit
* @param {object} param 请求参数 roleId, timeNode, timeUnit
* 子课题Id
*/
async getGlobal({ commit }, param) {
try {
const data = await getGlobal(param);
commit('setDailyTasks', data);
return data;
} catch (error) {
throw new Error(error);
}
sonDetailId(state, data) {
state.detailId = data;
},
/**
* 设置当前子课题信息
*/
setSubProjectInfo(state, data) {
state.subProjectInfo = data;
},
},
actions: {},
};

4
src/views/home/Index.vue

@ -16,7 +16,7 @@
<a-layout>
<Intro v-if="!projectId" />
<a-layout-sider v-if="projectId" class="project-detail"><ProjectDetail /></a-layout-sider>
<a-layout-sider v-if="projectId" class="project-detail"><Center /></a-layout-sider>
<a-layout v-if="taskId">
<!-- 导航栏-->
@ -42,7 +42,7 @@ import zhCN from 'ant-design-vue/es/locale/zh_CN';
import Left from 'components/tall/left/Index.vue';
import Navbar from 'components/tall/top/Navbar.vue';
import TopNavbar from 'components/tall/top/TopNavbar.vue';
import ProjectDetail from 'components/tall/center/ProjectDetail.vue';
import Center from 'components/tall/center/Index.vue';
import Intro from 'components/tall/right/Intro.vue';
const locale = zhCN;

Loading…
Cancel
Save