Files
fe-manage/src/views/projectcenter/ProjectAdd.vue
2023-03-08 16:21:14 +08:00

997 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!---- 创建项目页面 --->
<template xmlns:display="http://www.w3.org/1999/xhtml">
<div class="projectAdd">
<div class="header">
<span class="title">{{
projectInfo.id ? "编辑" : "创建"
}}{{ ptojectType == "3" ? "班级" : "项目" }}</span>
<div @click="backPage" style="cursor: pointer" to="/projectmanage" class="goback">
<span class="return"></span><span class="returntext">返回</span>
</div>
</div>
<div class="content">
<div class="main">
<div class="name" v-if="projectInfo.parentName">
<div class="namebox">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">项目归属</div>
</div>
<div class="in">
<div style="color: #c7cbd2; font-size: 14px; margin-left: 15px">
{{ projectInfo.parentName }}
</div>
</div>
</div>
<div class="name">
<div class="namebox">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">
{{ ptojectType == 3 ? "班级名称" : "项目名称" }}
</div>
</div>
<div class="in">
<NameInput placeholder="请输入项目名称" v-model:value="projectInfo.name"
v-model:validated="projectInfo.validated" :type="1"
:maxlength="30" show-count :id="projectInfo.id"></NameInput>
</div>
</div>
<div class="name flex-top">
<div class="namebox" style="margin-top: 10px">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">封面图</div>
</div>
<div class="in select" style="flex: 1; display: flex">
<div :class="`box ${projectInfo.picUrl === src.value ? 'active' : ''}`" style="
width: 100px;
height: 100px;
border-radius: 5px;
cursor: pointer;
position: relative;
overflow: hidden;
" v-for="(src, index) in projectPic" :style="{
display: index >= 3 ? 'none' : 'flex',
}" :key="index" @click="() => (projectInfo.picUrl = src.value)">
<img style="
width: 100px;
height: 100px;
margin-bottom: 4px;
margin-right: 4px;
" :src="src.value" alt="avatar"/>
</div>
<div @click="showLearnBgMore" v-if="projectPic.length > 3" style="
width: 100px;
height: 100px;
padding-left: 15px;
border-radius: 5px;
cursor: pointer;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #c7cbd2;
font-size: 14px;
font-weight: 400;
color: #4ea6ff;
line-height: 36px;
">
查看更多
<img src="../../assets/images/projectadd/go.png" alt=""/>
</div>
</div>
</div>
<div class="name">
<div class="namebox">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">项目时间</div>
</div>
<div class="in">
<a-range-picker separator="至" :show-time="{ format: 'HH:mm' }"
:placeholder="[' 开始时间', ' 结束时间']"
:disabledDate="disabledDate" v-model:value="timeRange" @calendarChange="calendarChange"
style="width: 100%; height: 40px; border-radius: 5px" :allowClear="false"
format="YYYY-MM-DD HH:mm"
valueFormat="YYYY-MM-DD HH:mm" @change="timeChange" :disabled="!!viewDetail"/>
</div>
</div>
<div class="name">
<div class="namebox">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">项目经理</div>
</div>
<div class="in">
<ProjectManager v-model:value="projectInfo.managerId" v-model:name="projectInfo.manager"
@onChange="managerChange" mode="multiple"></ProjectManager>
</div>
</div>
<div class="name">
<div class="namebox">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">资源归属</div>
</div>
<div class="in select">
<OrgClass v-model:value="projectInfo.sourceBelongId" v-model:name="projectInfo.sourceBelongName"
v-model:fullName="projectInfo.sourceBelongFullName"></OrgClass>
</div>
</div>
<div class="name">
<div class="namebox">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">项目级别</div>
</div>
<div class="in select">
<ProjectLevel v-model:value="projectInfo.level"></ProjectLevel>
</div>
</div>
<div class="name">
<div class="namebox">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">培训分类</div>
</div>
<div class="in select">
<TrainClass v-model:value="projectInfo.systemId"></TrainClass>
</div>
</div>
<div class="name">
<div class="namebox">
<img class="nameimg" src="../../assets/images/basicinfo/asterisk.png"/>
<div class="inname">是否BOEU实施</div>
</div>
<div class="in">
<a-radio-group v-model:value="projectInfo.boeFlag" :disabled="viewDetail ? true : false">
<a-radio :style="radioStyle" :value="1"></a-radio>
<a-radio :style="radioStyle" :value="0"></a-radio>
</a-radio-group>
</div>
</div>
<div class="name name2">
<div class="namebox">
<div class="inname">同步学习记录</div>
</div>
<div class="in ggysxz">
<a-checkbox v-model:checked="courseSyncFlag">
<span style="
width: 100%;
color: rgba(109, 117, 132, 1);
font-size: 14px;
">
同步课程学习记录如学员在课程库中拥有课程的学习记录自动免修该课程
</span>
</a-checkbox>
</div>
</div>
<div class="name name2">
<div class="namebox">
<div class="inname" style="margin-top: 13px">项目说明</div>
</div>
<div class="in">
<a-textarea v-model:value="projectInfo.remark" style="height: 80px" placeholder="请输入说明" show-count
:maxlength="200" :disabled="viewDetail ? true : false"/>
</div>
</div>
<div v-if="projectInfo.status == -5" class="name name2">
<div class="namebox">
<div class="inname" style="margin-top: 13px">审核意见</div>
</div>
<div class="description">
{{ auditDescription }}
</div>
</div>
</div>
<div class="template">
<div class="name">
<div class="inname" style="width: 50px">模版</div>
<div class="in select" style="margin-left: 2px">
<a-select :getPopupContainer="
(triggerNode) => triggerNode.parentNode || document.body
" placeholder="请选择模版" style="width: 100%" :options="classifyList5" @change="classificationChange5"
@popupScroll="templateScroll" :fieldNames="{
label: 'name',
value: 'id',
}">
</a-select>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="btn">
<a-button @click="backPage" class="btn1">取消</a-button>
<a-button :loading="loading" v-on:click="createProject" type="primary" class="btn1" style="margin-left: 20px">确定
</a-button>
</div>
</div>
<!-- 更多背景图 v-model:visible="learnBgMore" -->
<a-modal :closable="sh" centered="true" v-model:visible="learnBgMore" :footer="null" :width="650"
wrapClassName="learnBgMoreModal" :z-index="9999">
<div class="main">
<div class="top">
<div class="topc">封面图</div>
</div>
<div class="imagesBox">
<!-- <div
@click="() => (projectInfo.picUrl = src.value)"
v-for="item in projectPic"
:key="item.code"
class="learnBgItem"
> -->
<div @click="chooseImg2(item)" v-for="item in projectPic" :key="item.code" class="learnBgItem" :style="{
border:
projectInfo.picUrl === item.value
? '3px solid rgba(78, 166, 255, 1)'
: '1px solid #ccc',
'background-image': 'url(' + item.value.split(',')[0] + ')',
}">
<!-- <img class="im" :src="item.source" /> -->
</div>
</div>
<div class="btn">
<button class="samtn btn2" @click="closeLearnBgMore">取消</button>
<a-button class="samtn btn2" @click="closeLearnBgMore" :loading="projectInfo.validated===1">确定</a-button>
</div>
</div>
</a-modal>
</div>
</template>
<script>
import {onMounted, reactive, toRefs, watch} from "vue";
import {message} from "ant-design-vue";
import {useRoute, useRouter} from "vue-router";
import * as api from "../../api/index";
import {useStore} from "vuex";
import TrainClass from "@/components/project/TrainClass";
import OrgClass from "@/components/project/OrgClass";
import ProjectManager from "@/components/project/ProjectManagerNew";
import NameInput from "@/components/project/NameInput";
import ProjectLevel from "@/components/project/ProjectLevel";
import * as api2 from "../../api/indexAudit";
import {validateName} from "@/api/index1";
import dayjs from "dayjs";
import {scrollLoad} from "@/api/method";
export default {
name: "projectAdd",
components: {
ProjectManager,
ProjectLevel,
// ProjectClass,
TrainClass,
NameInput,
OrgClass,
},
setup() {
const store = useStore();
const routers = useRoute();
const router = useRouter();
const state = reactive({
datePartial: "start",
loading: false,
currentPage: 1, //当前页
tableDataTotal: -1, //模版列表总数
pageSize: 10, //每页10条数据
totalPages: 0, //总页数
viewDetail: null,
projectInfo: { id: "", validated: 0 },
projectPic: [],
memberParam: {
pageNo: 1,
pageSize: 10,
keyWord: "",
},
classifyList5: [],
courseSyncFlag: true,
auditDescription: "",
ptojectType: "",
changeCondition: false,
clickNum: 0,
timeRange: [],
learnBgMore: false,
pathBgId: null,
});
// 封面图选择
const handleChangeSelect = (value) => {
console.log(value);
state.projectInfo.picUrl = value;
};
onMounted(() => {
state.projectPic = store.state.project_pic.map((e) => ({
code: e.id,
value: e.value,
label: e.name,
}));
state.viewDetail = routers.query.viewDetail;
getProjectInfo();
getTemplate();
state.ptojectType = routers.query.ptojectType;
console.log("获取封面图", state.projectPic);
});
watch(routers.query, () => {
state.projectInfo.id = routers.query.id;
state.projectInfo.parentName = routers.query.parentName;
state.projectInfo.parentId = routers.query.parentId;
});
function getProjectInfo() {
state.projectInfo.parentName = routers.query.parentName;
state.projectInfo.parentId = routers.query.parentId;
state.projectInfo.id = routers.query.projectId;
(state.projectInfo.id || state.projectInfo.parentId) &&
api
.getProjectDetail({
projectId: state.projectInfo.id || state.projectInfo.parentId,
})
.then((res) => {
state.projectInfo = {
...res.data.data.projectInfo,
...state.projectInfo,
};
!routers.query.projectId &&
!!routers.query.parentId &&
(state.projectInfo.name = "");
state.timeRange = [
state.projectInfo.beginTime,
state.projectInfo.endTime,
];
state.courseSyncFlag = !!state.projectInfo.courseSyncFlag;
if (Number(state.projectInfo.status) === -5) {
let obj = {
project_id: state.projectInfo.id,
type: 1,
pageNo: 1,
pageSize: 1,
};
api2.auditList(obj).then((d) => {
if (d.data.code === 200) {
let res = d.data.data;
if (res.rows && res.rows.length > 0) {
let i = res.rows.length;
state.auditDescription = res.rows[i - 1].description
? res.rows[i - 1].description
: "-";
}
}
});
}
});
}
const backPage = () => {
router.back();
};
//选择分类
const classificationChange = (value) => {
state.projectType = value; //分类选择的id
};
const classificationChange5 = (key, option) => {
state.projectInfo = option;
state.projectInfo.projectTemplateId = option.id;
state.projectInfo.id = "";
state.projectInfo.type = 3;
state.timeRange = [option.beginTime, option.endTime];
state.projectInfo.parentName = routers.query.parentName;
state.projectInfo.parentId = routers.query.parentId;
};
//获取模版列表
const getTemplate = () => {
let obj = {
pageNo: state.currentPage,
pageSize: state.pageSize,
status: 1,
};
api.getTemplate(obj).then((res) => {
state.totalPages = Number(res.data.data.pages);
state.classifyList5 = res.data.data.rows;
});
};
//模版滚动加载模板信息
const templateScroll = (e) => {
let num = scrollLoad(e);
if (num === 1) {
state.currentPage = 1;
} else if (num === 2) {
// 如果滑到底部,则加载下一页
state.currentPage++;
getTemplate();
}
};
const errorMsgs = {
name: "请输入项目名称",
picUrl: "请选择项目封面图",
beginTime: "请选择项目开始时间",
endTime: "请选择项目结束时间",
manager: "请选择项目经理",
managerId: "请选择项目经理",
sourceBelongId: "请选择资源归属",
level: "请填写项目级别",
systemId: "请填写项目培训体系",
boeFlag: "请选择是否BOEU实施",
};
function timeChange(e) {
if (e && e.length === 2) {
state.projectInfo.beginTime = e[0];
state.projectInfo.endTime = e[1];
}
}
function validate(obj, errorMsgs) {
for (let i in errorMsgs) {
if (!obj[i] && obj[i] !== 0) {
message.destroy();
message.warning(errorMsgs[i]);
return false;
}
}
return true;
}
const createProject = async () => {
state.loading = true;
console.log("保存", state.projectInfo);
if (!validate(state.projectInfo, errorMsgs)) {
state.loading = false;
return;
}
/**
if (!state.projectInfo.validate) {
message.destroy();
message.warning("项目名称重复,请修改名称!");
return;
}*/
const offName = await validateName({
name: state.projectInfo.name,
type: 1,
id: state.projectInfo.id,
}).then((res) => {
return res.data.data == 1;
});
if (offName) {
message.destroy();
state.loading = false;
return message.warning("项目名称重复,请重新填写");
}
state.projectInfo.type = 3;
state.projectInfo.courseSyncFlag = state.courseSyncFlag ? 1 : 0;
api.createProject(state.projectInfo).then((res) => {
state.loading = false;
message.destroy();
message.success(state.projectInfo.id ? "编辑成功" : "创建成功");
router.push({
path: "/taskpage",
query: { projectId: res.data.data },
});
});
};
function managerChange(e, l, d, t, orgName) {
console.log(e, l);
state.projectInfo.sourceBelongId = d;
state.projectInfo.sourceBelongName = t;
state.projectInfo.sourceBelongFullName = orgName;
}
const disabledDate = (current) => {
//编辑的时候 开始实际只能选当前时间之前的时间
if (state.projectInfo.id && state.datePartial === "start") {
return (
current &&
current > dayjs(state.timeRange[0]).endOf("YYYY-MM-DD HH:mm")
);
}
// 去除创建项目时间限制 可以选择创建时间之前的时间
// return current && current < dayjs().subtract(1, 'days').endOf('day')
};
//显示更多路径背景弹窗
const showLearnBgMore = () => {
state.learnBgMore = true;
};
//关闭更多路径背景弹窗
const closeLearnBgMore = () => {
state.learnBgMore = false;
};
function calendarChange(date, dateStr, partial) {
state.datePartial = partial;
}
const chooseImg2 = (item) => {
// console.log(item);
state.projectInfo.picUrl = item.value;
state.pathBgId = item.code;
state.pathBg = item.value.split(",")[0];
state.mobilePicUrl = item.value.split(",")[1];
};
return {
...toRefs(state),
disabledDate,
managerChange,
calendarChange,
timeChange,
classificationChange,
classificationChange5,
createProject,
backPage,
templateScroll,
handleChangeSelect,
showLearnBgMore,
closeLearnBgMore,
chooseImg2,
};
},
};
</script>
<style lang="scss">
.ggysxz {
.ant-checkbox-disabled.ant-checkbox-checked .ant-checkbox-inner::after {
border-color: #fff !important;
}
.ant-checkbox-disabled .ant-checkbox-inner {
background-color: #1890ff !important;
}
}
.flex-top {
align-items: flex-start !important;
}
.projectAdd {
width: 100%;
// height: inherit;
// flex: 1;
// flex-shrink: 0;
// overflow-y: auto;
.header {
width: 100%;
display: flex;
justify-content: space-between;
.title {
color: #000000;
font-size: 18px;
//line-height: 36px;
padding-top: 30px;
padding-left: 37px;
//font-weight: 500;
}
.goback {
padding-right: 70px;
//padding-top: 37px;
position: relative;
.return {
display: inline-block;
width: 42px;
height: 42px;
margin-top: 17px;
margin-right: 10px;
background-image: url("../../assets/images/projectadd/return.png");
}
.returntext {
display: inline-block;
position: absolute;
top: 27px;
color: #4ea6ff;
font-size: 14px;
}
}
}
// 修改 antd upload 样式
.ant-upload {
border-width: 0px;
}
.active {
border: 3px solid rgba(78, 166, 255, 1);
}
.content {
display: flex;
.main {
width: 50%;
display: flex;
flex-direction: column;
align-items: center;
//justify-content: center;
float: left;
border-right: 1px solid rgba(153, 155, 163, 0.3);
.name {
width: 78%;
// background-color: lightcoral;
display: flex;
margin-top: 20px;
align-items: center;
//height: 40px;
// border: 1px solid black;
.namebox {
width: 120px;
display: flex;
align-items: center;
justify-content: flex-end;
flex-shrink: 0;
.nameimg {
width: 10px;
height: 10px;
}
}
.d {
margin-top: 8px;
font-size: 25px;
color: #ff4e4e;
}
.box {
position: relative;
margin-left: 14px;
.box1 {
position: absolute;
left: 50%;
top: 50%;
width: 50px;
margin-left: -25px;
margin-top: -5px;
border-top: 2px solid rgba(78, 166, 255, 1);
}
.box2 {
position: absolute;
left: 50%;
top: 50%;
height: 50px;
//margin-left: -5px;
margin-top: -25px;
border-left: 2px solid rgba(78, 166, 255, 1);
}
}
.inname {
color: #6f6f6f;
font-size: 14px;
margin-left: 7px;
}
.in {
margin-left: 14px;
flex: 1;
// .ant-radio-wrapper {
// }
.ant-input-textarea-show-count {
position: relative;
height: 88px;
}
.ant-input-textarea-show-count::after {
position: absolute;
right: 10px;
bottom: 0px;
}
.ant-input {
border-radius: 8px;
// height: 120%;
width: 100%;
height: 40px;
}
.ant-input-affix-wrapper {
padding: 0 11px;
border-radius: 8px;
}
.ant-select-selector {
border-radius: 5px;
// height: 120%;
width: 100%;
// height: 40px;
}
.btn {
width: 33%;
margin-top: 30px;
display: flex;
justify-content: space-between;
margin-bottom: 30px;
.samtn {
width: 100px;
height: 40px;
font-size: 14px;
border: 1px solid #4ea6ff;
border-radius: 8px;
cursor: pointer;
}
.btn1 {
background-color: #fff;
color: #4ea6ff;
}
.btn2 {
background-color: #4ea6ff;
color: #fff;
}
}
}
.filebox {
margin-left: 14px;
flex: 1;
.fileimg {
width: 15px;
height: 15px;
margin-right: 6px;
}
.filetext {
font-size: 14px;
font-weight: 400;
color: #4ea6ff;
line-height: 36px;
}
.support {
font-size: 14px;
font-weight: 400;
color: #999ba3;
line-height: 36px;
margin-top: 8px;
word-break: break-all;
}
}
}
.name2 {
display: flex;
align-items: flex-start;
.description {
margin-top: 14px;
margin-left: 11px;
}
.ant-input-textarea {
.ant-input {
height: 88px;
}
}
}
}
.template {
width: 50%;
display: flex;
flex-direction: column;
align-items: center;
//justify-content: center;
float: right;
.name {
width: 78%;
// background-color: lightcoral;
display: flex;
margin-top: 20px;
align-items: center;
height: 40px;
// border: 1px solid black;
.d {
margin-top: 8px;
font-size: 25px;
color: #ff4e4e;
}
.inname {
color: #6f6f6f;
font-size: 14px;
margin-left: 7px;
width: 65px;
}
.in {
margin-left: 14px;
width: 81%;
.ant-input {
border-radius: 5px;
// height: 120%;
width: 100%;
height: 40px;
}
.ant-select-selector {
border-radius: 5px;
// height: 120%;
width: 100%;
height: 40px;
}
}
}
}
}
.footer {
width: 100%;
margin-top: 31px;
margin-bottom: 14px;
padding-bottom: 20px;
.btn {
display: flex;
justify-content: center;
.btn1 {
display: flex;
justify-content: center;
align-items: center;
width: 100px;
height: 40px;
border-radius: 8px;
background: #4ea6ff;
color: #ffffff;
margin-right: 14px;
}
.btn2 {
display: flex;
justify-content: center;
align-items: center;
width: 100px;
height: 40px;
border-radius: 8px;
border: 1px solid #4ea6ff;
background: #ffffff;
color: #4ea6ff;
}
}
.text {
color: rgba(153, 155, 163, 1);
font-size: 14px;
margin-left: 223px;
}
}
}
.learnBgMoreModal {
.ant-modal {
width: 680px !important;
height: 528px !important;
.ant-modal-content {
width: 680px !important;
height: 528px !important;
.ant-modal-body {
width: 680px !important;
height: 528px !important;
padding: 0 !important;
.main {
display: flex;
flex-direction: column;
.top {
padding-left: 51px;
padding-right: 51px;
padding-top: 28px;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
.topc {
font-size: 16px;
font-weight: bold;
color: #000000;
line-height: 36px;
}
}
.imagesBox {
display: flex;
// justify-content: space-between;
flex-wrap: wrap;
padding-left: 51px;
padding-right: 39px;
margin-top: 20px;
height: 350px;
overflow-y: auto;
.learnBgItem {
border-radius: 8px;
width: 136px;
height: 106px;
background-size: 100%;
background-repeat: no-repeat;
margin-bottom: 20px;
margin-right: 10px;
}
}
.btn {
width: 100%;
position: absolute;
bottom: 30px;
margin-top: 30px;
display: flex;
justify-content: center;
.samtn {
width: 100px;
height: 40px;
font-size: 14px;
border: 1px solid #4ea6ff;
border-radius: 8px;
cursor: pointer;
}
.btn1 {
background-color: #fff;
color: #4ea6ff;
}
.btn2 {
background-color: #4ea6ff;
color: #fff;
margin-left: 16px;
}
}
}
}
}
}
}
.btn1 {
background-color: #fff;
color: #4ea6ff;
}
.btn2 {
background-color: #4ea6ff;
color: #fff;
margin-left: 16px;
}
.treeDropdown {
// width: 240px !important;
// border-radius: 5px;
// min-height: 600px !important;
.ant-select-tree-list-scrollbar {
width: 5px !important;
.ant-select-tree-list-scrollbar-thumb {
background-color: #4ea6ff !important;
}
}
.ant-select-tree-indent-unit {
width: 7px !important;
}
}
</style>