563 lines
15 KiB
Vue
563 lines
15 KiB
Vue
<template>
|
||
<div class="logical">
|
||
<div class="logical-bar">
|
||
<div class="catalog">
|
||
<div style="padding: 0 12px 12px 12px">
|
||
<a-input
|
||
class="custom-input"
|
||
style="height: 32px"
|
||
allowClear
|
||
v-model:value="searchName"
|
||
placeholder="请输入题目名"
|
||
@change="searchInputHandle"
|
||
>
|
||
<template #prefix>
|
||
<i class="iconfont" style="color: #bfbfbf"></i>
|
||
</template>
|
||
</a-input>
|
||
</div>
|
||
<div class="catalog-main scrollbar" outside="true">
|
||
<template v-if="contentLoading">
|
||
<div class="catalog-loading" v-show="contentLoading">
|
||
<a-spin />
|
||
</div>
|
||
</template>
|
||
<template v-else>
|
||
<div v-for="(item, itemIndex) in quesList" :key="itemIndex">
|
||
<div class="catalog-page">
|
||
第{{ itemIndex + 1 }}页({{ item.name }})
|
||
</div>
|
||
<template v-for="child in item.child" :key="child.id">
|
||
<a-tooltip>
|
||
<template #title>
|
||
<div v-html="child.stem"></div>
|
||
</template>
|
||
<div class="catalog-text" @click="skipToHandle(child)">
|
||
<i
|
||
class="iconfont catalog-text-icon"
|
||
:class="{
|
||
'iconfont-active': child.logics_has,
|
||
}"
|
||
style="margin-right: 8px"
|
||
v-html="getIcon(child)"
|
||
></i>
|
||
<span class="catalog-text-span">{{ child.title }}</span>
|
||
<p
|
||
v-show="![-1, -2, -3].includes(child.id)"
|
||
v-html="nodeHandle(child.stem)"
|
||
></p>
|
||
</div>
|
||
</a-tooltip>
|
||
</template>
|
||
<div class="catalog-line"></div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="logical-content" id="logicalContent">
|
||
<div class="logical-scroll" v-show="!contentLoading">
|
||
<div class="logical-content-main">
|
||
<div class="logical-content-main-title">
|
||
<div v-show="iframeShow" class="flex-align">
|
||
<span class="logical-iframe-main-title-line"></span>
|
||
<span style="font-size: 16px">逻辑预览</span>
|
||
</div>
|
||
<ModelMenuTitle
|
||
v-show="!iframeShow"
|
||
:titles="logicTitles"
|
||
:posLeft="100"
|
||
:lineWidth="60"
|
||
@check="
|
||
(e) => {
|
||
title = e.flag;
|
||
}
|
||
"
|
||
/>
|
||
<div style="flex: 1">
|
||
<div class="logical-content-main-show" @click="toLogicShow">
|
||
<i class="iconfont"></i>
|
||
<span>切换到{{ iframeShow ? "列表" : "预览" }}视图</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-show="!iframeShow">
|
||
<LogicList
|
||
v-if="title === 'logic'"
|
||
:data="logicList"
|
||
:check="checQues"
|
||
/>
|
||
<RandomList v-if="title === 'random'" :data="processData" />
|
||
<!-- <RandomListV2 v-show="title === 'random'" :data="processData" /> -->
|
||
</div>
|
||
<div v-show="iframeShow">
|
||
<div class="logical-iframe" v-show="iframeShow">
|
||
<iframe
|
||
ref="iframe"
|
||
class="iframe"
|
||
name="logicalIframe"
|
||
src="static/reactFlow/index.html"
|
||
allowfullscreen="true"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="logical-empty" v-show="contentLoading">
|
||
<a-spin />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { computed, ref } from "@vue/reactivity";
|
||
import ModelMenuTitle from "../../../components/ModelMenuTitle.vue";
|
||
import LogicList from "./fragment/LogicList.vue";
|
||
import RandomList from "./fragment/RandomListV2.vue";
|
||
import { useStore } from "vuex";
|
||
import {
|
||
basicQuesTypeList,
|
||
quickQuesTypeList,
|
||
advancedQuesTypeList,
|
||
} from "../../../utils/common";
|
||
import { getQuesByPages, nodeHandle } from "../Design/js/util";
|
||
import { useRoute } from "vue-router";
|
||
import { processControlQuesList } from "../api/api.js";
|
||
import { sendMessage } from "./util/util";
|
||
import { watch } from "@vue/runtime-core";
|
||
import Scroll from "../Design/js/scroll.js";
|
||
export default {
|
||
name: "logicalIndex",
|
||
components: { ModelMenuTitle, LogicList, RandomList },
|
||
setup(props, context) {
|
||
const processData = ref();
|
||
const store = useStore();
|
||
const title = ref("logic");
|
||
const contentLoading = ref(false);
|
||
const logicSrc = ref(
|
||
process.env.NODE_ENV === "production"
|
||
? `https://${window.location.host}/logic-view`
|
||
: "http://localhost:3000"
|
||
);
|
||
const logicRandomSrc = ref(
|
||
process.env.NODE_ENV === "production"
|
||
? `https://${window.location.host}/logic-view`
|
||
: "http://localhost:3000/question-groups"
|
||
);
|
||
const logicTitles = [
|
||
{
|
||
title: "逻辑列表",
|
||
flag: "logic",
|
||
},
|
||
{
|
||
title: "随机列表",
|
||
flag: "random",
|
||
},
|
||
];
|
||
const quesList = ref([]);
|
||
const oldQuesList = ref([]);
|
||
const {
|
||
logicList,
|
||
checQues,
|
||
searchName,
|
||
skipToHandle,
|
||
getIcon,
|
||
searchInputHandle,
|
||
} = domEventHandle(store, quesList, oldQuesList);
|
||
const sn = computed(() => useRoute().query.sn);
|
||
const surVeytitle = computed(
|
||
() => store.state.common.questionInfo.survey?.title || ""
|
||
);
|
||
watch(
|
||
() => store.state.common.questionInfo,
|
||
(val) => {
|
||
sendInfoToIframe(val);
|
||
// 记得要过滤掉选项隐藏的逻辑
|
||
logicList.value = JSON.parse(JSON.stringify(val?.logics || [])).filter(
|
||
(log) => log.skip_type !== 4
|
||
);
|
||
}
|
||
);
|
||
/**
|
||
* 将问题列表处理为{title: 分页开始-分页结束, child: []当前分页包含的所有题}
|
||
*/
|
||
const pageHandle = (dealQuestion) => {
|
||
const introduce = [
|
||
{
|
||
id: -1,
|
||
stem: "问卷标题",
|
||
title: "问卷标题",
|
||
flag: "title",
|
||
},
|
||
{
|
||
id: -2,
|
||
stem: "介绍语",
|
||
title: "介绍语",
|
||
flag: "introduce",
|
||
},
|
||
];
|
||
dealQuestion[0].unshift(...introduce);
|
||
const result = [];
|
||
dealQuestion.forEach((ques) => {
|
||
result.push({
|
||
name: `${ques[0]?.title || ""} ~ ${
|
||
ques[ques.length - 1]?.title || ""
|
||
}`,
|
||
child: ques,
|
||
});
|
||
});
|
||
result.push({
|
||
name: "结束语",
|
||
child: [{ id: -3, stem: "结束语", title: "结束语", flag: "end" }],
|
||
});
|
||
quesList.value = result;
|
||
oldQuesList.value = result;
|
||
};
|
||
const getQuestions = async () => {
|
||
contentLoading.value = true;
|
||
try {
|
||
const { data } = await processControlQuesList(sn.value);
|
||
data.survey.pages = data.survey.pages || [[]];
|
||
const combineList = getQuesByPages(data.questions, data.survey.pages);
|
||
data.questions = combineList;
|
||
store.commit(
|
||
"common/A_COMMON_SET_QUESTIONINFO",
|
||
JSON.stringify({
|
||
logics: data.logics,
|
||
questions: data.questions,
|
||
survey: data.survey,
|
||
})
|
||
);
|
||
store.commit("common/M_COMMON_SET_SURVEY_STATUS", data.survey.status);
|
||
store.commit(
|
||
"common/A_COMMON_SET_QUESSAVEPARAM",
|
||
JSON.stringify({
|
||
newLogics: [],
|
||
newQuestion: [],
|
||
newSurvey: {
|
||
pages: [],
|
||
version: "",
|
||
},
|
||
})
|
||
);
|
||
pageHandle(data.deal_questions);
|
||
processData.value = data;
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
contentLoading.value = false;
|
||
};
|
||
|
||
getQuestions();
|
||
|
||
const iframeShow = ref(false);
|
||
const toLogicShow = () => {
|
||
iframeShow.value = !iframeShow.value;
|
||
};
|
||
// const onSendMessage = () => {
|
||
// sendInfoToIframe(store.state.common.questionInfo);
|
||
// logicList.value = JSON.parse(
|
||
// JSON.stringify(store.state.common.questionInfo?.logics || [])
|
||
// );
|
||
// };
|
||
|
||
return {
|
||
logicSrc,
|
||
logicRandomSrc,
|
||
contentLoading,
|
||
title,
|
||
logicTitles,
|
||
logicList,
|
||
checQues,
|
||
searchName,
|
||
surVeytitle,
|
||
quesList,
|
||
getIcon,
|
||
skipToHandle,
|
||
searchInputHandle,
|
||
processData,
|
||
nodeHandle,
|
||
|
||
iframeShow,
|
||
toLogicShow,
|
||
// onSendMessage
|
||
};
|
||
},
|
||
};
|
||
/**
|
||
* 页面事件统一处理
|
||
*/
|
||
function domEventHandle(store, quesList, oldQuesList) {
|
||
const searchName = ref("");
|
||
const logicList = ref([]);
|
||
const checQues = ref({});
|
||
const skipToHandle = (element) => {
|
||
if (element.question_index) {
|
||
checQues.value = {
|
||
...element
|
||
}
|
||
new Scroll(
|
||
document.getElementById(`${element.id}`),
|
||
20,
|
||
document.querySelector(".logical-content")
|
||
).animate();
|
||
}
|
||
};
|
||
const getIcon = (item) => {
|
||
let icon = "";
|
||
if (item.flag) {
|
||
switch (item.flag) {
|
||
case "title":
|
||
icon = "";
|
||
break;
|
||
case "introduce":
|
||
icon = "";
|
||
break;
|
||
case "end":
|
||
icon = "";
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return icon;
|
||
}
|
||
if (item.config.quick_type === 0) {
|
||
icon =
|
||
basicQuesTypeList?.find((x) =>
|
||
x?.childTypes.includes(item?.question_type)
|
||
)?.icon || "";
|
||
if (!icon) {
|
||
icon =
|
||
quickQuesTypeList?.find((x) => x?.type === item?.question_type)
|
||
?.icon || "";
|
||
}
|
||
} else {
|
||
icon =
|
||
quickQuesTypeList?.find(
|
||
(x) => x?.quickType === item?.config?.quick_type
|
||
)?.icon || "";
|
||
}
|
||
if (!icon) {
|
||
icon =
|
||
advancedQuesTypeList?.find((x) => x?.type === item?.question_type)
|
||
?.icon || "";
|
||
}
|
||
return icon;
|
||
};
|
||
const searchInputHandle = () => {
|
||
if (searchName.value.length > 0) {
|
||
quesList.value = JSON.parse(JSON.stringify(oldQuesList.value))
|
||
.map((x) => {
|
||
x.child = x.child.filter((x) =>
|
||
`${x.title || ""}${x.stem || ""}`.includes(searchName.value)
|
||
);
|
||
return x;
|
||
})
|
||
.filter((x) => x.child.length > 0);
|
||
} else {
|
||
quesList.value = JSON.parse(JSON.stringify(oldQuesList.value));
|
||
}
|
||
};
|
||
return {
|
||
logicList,
|
||
checQues,
|
||
searchName,
|
||
skipToHandle,
|
||
getIcon,
|
||
searchInputHandle,
|
||
};
|
||
}
|
||
/**
|
||
* 将数据发送给iframe窗口
|
||
*/
|
||
function sendInfoToIframe(questionInfo) {
|
||
if (!questionInfo.logics) return;
|
||
const newQuesList = questionInfo.questions.filter((ques) => ques.id);
|
||
newQuesList.forEach((ques) => {
|
||
ques.logics = questionInfo.logics.filter(
|
||
(log) => log.question_id === ques.id
|
||
);
|
||
});
|
||
sendMessage(newQuesList);
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.logical {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
&-bar {
|
||
width: 240px;
|
||
height: 100%;
|
||
background: #ffffff;
|
||
padding: 32px 20px;
|
||
border-right: 1px solid #f5f5f5;
|
||
.catalog {
|
||
padding: 24px 0;
|
||
padding-top: 0;
|
||
&-main {
|
||
max-height: calc(100vh - 200px);
|
||
overflow-y: auto;
|
||
}
|
||
&-page {
|
||
padding-left: 12px;
|
||
margin-top: 31px;
|
||
font-weight: bold;
|
||
color: #434343;
|
||
font-size: 14px;
|
||
}
|
||
&-text {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 24px;
|
||
min-height: 37px;
|
||
font-size: 13px;
|
||
font-family: PingFangSC-Regular, PingFang SC;
|
||
font-weight: 400;
|
||
color: #434343;
|
||
cursor: pointer;
|
||
padding-left: 12px;
|
||
&-span {
|
||
word-break: keep-all;
|
||
}
|
||
&-icon {
|
||
margin-right: 10px;
|
||
}
|
||
&:hover {
|
||
background: #f5f5f5;
|
||
}
|
||
&::v-deep p {
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-align: center;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
}
|
||
&-line {
|
||
margin-top: 24px;
|
||
height: 1px;
|
||
background: #f5f5f5;
|
||
}
|
||
&-loading {
|
||
display: flex;
|
||
justify-content: center;
|
||
height: 100%;
|
||
font-size: 13px;
|
||
font-family: PingFangSC-Regular, PingFang SC;
|
||
font-weight: 400;
|
||
}
|
||
.iconfont {
|
||
color: #000000;
|
||
}
|
||
.iconfont-active {
|
||
color: $yili-default-color;
|
||
}
|
||
}
|
||
}
|
||
&-scroll {
|
||
min-width: 815px;
|
||
background: #ffffff;
|
||
border-radius: 6px;
|
||
// padding: 20px;
|
||
min-height: 100%;
|
||
// box-shadow: 0px 0px 6px 1px rgb(0 0 0 / 10%);
|
||
.logical-content-main-title {
|
||
:deep(.logical-title .logical-title-span) {
|
||
margin-right: 0px;
|
||
}
|
||
}
|
||
}
|
||
&-empty {
|
||
min-width: 500px;
|
||
height: 100%;
|
||
background: #ffffff;
|
||
border-radius: 6px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
&-content {
|
||
padding: 18px 20px 10px 16px;
|
||
overflow-y: auto;
|
||
flex: 1;
|
||
&-main {
|
||
padding-bottom: 30px;
|
||
&-title {
|
||
display: flex;
|
||
align-items: center;
|
||
min-height: 42px;
|
||
}
|
||
&-show {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 139px;
|
||
height: 32px;
|
||
background: #ffffff;
|
||
border-radius: 4px 4px 4px 4px;
|
||
border: 1px solid #dfe0e3;
|
||
float: right;
|
||
cursor: pointer;
|
||
&:hover {
|
||
color: $yili-default-color;
|
||
background-color: $yili-bkg-color;
|
||
}
|
||
.iconfont {
|
||
font-size: 11px;
|
||
margin-right: 5px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
&-iframe {
|
||
height: calc(100vh - 242px);
|
||
iframe {
|
||
height: 100%;
|
||
width: 100%;
|
||
border: none;
|
||
}
|
||
&-main {
|
||
height: 100%;
|
||
&-title {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #434343;
|
||
&-line {
|
||
width: 4px;
|
||
height: 20px;
|
||
background: $yili-default-color;
|
||
margin-right: 12px;
|
||
}
|
||
}
|
||
}
|
||
&-full {
|
||
position: absolute;
|
||
right: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
top: 9px;
|
||
background: #fefefe;
|
||
border-bottom: 1px solid #eee;
|
||
width: 26px;
|
||
height: 26px;
|
||
box-shadow: 0 0 2px 1px rgb(0 0 0 / 8%);
|
||
&:hover {
|
||
background: #f4f4f4;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.flex-align {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
</style>
|