Merge branch 'master' into feature-creative-center-v2

#	src/router/index.js
#	src/views/Home/components/Avatar.vue
This commit is contained in:
wanganmao
2022-12-06 11:13:08 +08:00
252 changed files with 20746 additions and 6570 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -3,11 +3,13 @@ VUE_APP_CURRENTMODE = 'dev'
VUE_APP_BASEOSS = 'https://diaoyan-files.automark.cc'
#VUE_APP_BASEURL = 'http://planetg-java.test.automark.cc/'
VUE_APP_BASEURL = 'http://ylst-api-uat.dctest.digitalyili.com/'
VUE_APP_BASEURL = 'http://yls-api-uat.dctest.digitalyili.com/'
VUE_APP_DELiVERY_BASEURL='https://javaxq.test.automark.cc/'
VUE_APP_MESSAGE_CENTER ='http://gtech-gateway.dcin-test.digitalyili.com/apigtech/message-send-center/';
#VUE_APP_SOCKETURL = 'wss://planetg-java.test.automark.cc/survey_sync'
VUE_APP_SOCKETURL = 'wss://ylst-api-uat.dctest.digitalyili.com/survey_sync'
VUE_APP_SOCKETURL = 'wss://yls-api-uat.dctest.digitalyili.com/survey_sync'
VUE_APP_JSONPURL = 'https://iam-uat.dctest.digitalyili.com/idp/restful/getIDPToken'
VUE_APP_YQRURL = 'https://ocp-uat-ain.digitalyili.com'

View File

@@ -1,12 +1,15 @@
NODE_ENV = 'production'
VUE_APP_CURRENTMODE = 'sit'
VUE_APP_CURRENTMODE = 'prod'
VUE_APP_BASEOSS = 'https://test-cxp-pubcos.yili.com/uat-yls'
VUE_APP_BASEURL = 'http://planetg-java.test.automark.cc/'
VUE_APP_BASEOSS = 'https://cxp-pubcos.yili.com/prod-yls'
VUE_APP_BASEURL = 'https://yls.xapi.digitalyili.com/'
VUE_APP_DELiVERY_BASEURL='https://javaxq.test.automark.cc/'
VUE_APP_MESSAGE_CENTER ='http://gtech-gateway.dcin-test.digitalyili.com/apigtech/message-send-center/';
VUE_APP_DELiVERY_BASEURL='https://ylsdist-net.x.digitalyili.com/'
VUE_APP_MESSAGE_CENTER ='http://gtech-gateway.cxpin.digitalyili.com/apigtech/message-send-center/';
VUE_APP_LOGIN = 'https://yip.digitalyili.com//login'
VUE_APP_SOCKETURL = 'wss://yls.xapi.digitalyili.com/survey_sync'
VUE_APP_JSONPURL = 'https://iam.digitalyili.com/idp/restful/getIDPToken'
VUE_APP_YQRURL = 'https://ocp.digitalyili.com'
VUE_APP_LOGIN = 'https://yip-uat.dctest.digitalyili.com/login'
VUE_APP_SOCKETURL = 'wss://planetg-java.test.automark.cc/survey_sync'
VUE_APP_JSONPURL = 'https://iam-uat.dctest.digitalyili.com/idp/restful/getIDPToken'

18
.env.sit Normal file
View File

@@ -0,0 +1,18 @@
NODE_ENV = 'production'
VUE_APP_CURRENTMODE = 'sit'
VUE_APP_BASEOSS = 'https://test-cxp-pubcos.yili.com/uat-yls'
VUE_APP_BASEURL = 'https://yls-api-uat.dctest.digitalyili.com'
VUE_APP_JAVA_DELiVERY_BASEURL='https://ylsdist-net-uat.dctest.digitalyili.com'
VUE_APP_MESSAGE_CENTER ='http://gtech-gateway.dcin-test.digitalyili.com/apigtech/message-send-center/';
VUE_APP_LOGIN = 'https://yip-uat.dctest.digitalyili.com/login'
VUE_APP_SOCKETURL = 'wss://yls-api-uat.dctest.digitalyili.com/survey_sync'
VUE_APP_JSONPURL = 'https://iam-uat.dctest.digitalyili.com/idp/restful/getIDPToken'
VUE_APP_YQRURL = 'https://ocp-uat-ain.digitalyili.com'

View File

@@ -2,7 +2,7 @@ NODE_ENV = 'production'
VUE_APP_CURRENTMODE = 'uat'
VUE_APP_BASEOSS = 'https://test-cxp-pubcos.yili.com/uat-yls'
VUE_APP_BASEURL = 'https://ylst-api-uat.dctest.digitalyili.com'
VUE_APP_BASEURL = 'https://yls-api-uat.dctest.digitalyili.com'
VUE_APP_JAVA_DELiVERY_BASEURL='https://ylsdist-net-uat.dctest.digitalyili.com'
@@ -10,6 +10,8 @@ VUE_APP_MESSAGE_CENTER ='http://gtech-gateway.dcin-test.digitalyili.com/apigtech
VUE_APP_LOGIN = 'https://yip-uat.dctest.digitalyili.com/login'
VUE_APP_SOCKETURL = 'wss://ylst-api-uat.dctest.digitalyili.com/survey_sync'
VUE_APP_SOCKETURL = 'wss://yls-api-uat.dctest.digitalyili.com/survey_sync'
VUE_APP_JSONPURL = 'https://iam-uat.dctest.digitalyili.com/idp/restful/getIDPToken'
VUE_APP_YQRURL = 'https://ocp-uat-ain.digitalyili.com'

18
package-lock.json generated
View File

@@ -12031,7 +12031,7 @@
},
"sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.15.0.tgz",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
"integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w=="
},
"source-list-map": {
@@ -13710,7 +13710,7 @@
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.8.3",
"resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-16.8.3.tgz",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
"dev": true,
"optional": true,
@@ -13722,7 +13722,7 @@
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
@@ -13732,7 +13732,7 @@
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
@@ -13743,7 +13743,7 @@
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
@@ -13753,21 +13753,21 @@
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.2.tgz",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"dev": true,
"optional": true,
@@ -13779,7 +13779,7 @@
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,

View File

@@ -7,6 +7,8 @@
"serve": "vue-cli-service serve --mode dev",
"dev": "vue-cli-service serve --mode dev",
"uat": "vue-cli-service serve --mode uat",
"sit": "vue-cli-service serve --mode sit",
"build_sit": "vue-cli-service build --mode sit",
"build_uat": "vue-cli-service build --mode uat",
"build_prod": "vue-cli-service build --mode prod"
},

View File

@@ -21,7 +21,7 @@
type="text/javascript"
src="https://mapapi.qq.com/web/mapComponents/geoLocation/v/geolocation.min.js"
></script>
<script src="https://pv.sohu.com/cityjson?ie=utf-8"></script>
<!-- <script src="https://pv.sohu.com/cityjson?ie=utf-8"></script> -->
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
</head>
<style>
@@ -54,4 +54,12 @@
}
</script> -->
<!-- 获取ip地址 -->
<script type="text/javascript">
function ipCallback({ ip }) {
localStorage.setItem("plantIp", ip || "");
}
</script>
<script src="https://www.taobao.com/help/getip.php"></script>
</html>

View File

@@ -50,16 +50,17 @@ export default {
</script>
<style lang="scss">
@import "./style/customize/index.scss";
@import "./style/utils.scss";
@font-face {
font-display: optional;
font-family: "SourceHanSana-Normal";
src: url(#{$baseOss}/fonts/SourceHanSans-Normal.ttf);
}
html,
body,
* {
font-family: "SourceHanSana-Normal", sans-serif;
*{
font-family: inherit;
}
* {
margin: 0;
@@ -114,7 +115,7 @@ div {
}
}
strong {
font-family: "Noto Sans CJK SC Medium", "Source Han Sans CN Medium" !important;
// font-family: "Noto Sans CJK SC Medium", "Source Han Sans CN Medium" !important;
font-weight: bolder !important;
}
</style>

View File

@@ -3,18 +3,24 @@
<div class="left">
<i class="iconfont icon-xiangzuo-moren"
@click="backHome"></i>
<a-tooltip placement="right">
<template #title>
{{ project_name }}
</template>
<div class="question-name">{{ project_name }}</div>
</a-tooltip>
</div>
<div class="tab-container">
<div class="tab-item"
style="font-size:18px"
v-for="(tab, index) in tabs"
:key="index"
:class="[tab.link === currentPath ? 'active' : '']"
@click="toPage(tab.link, tab.title)">
<span :class="tab.link === currentPath ? 'click' : 'click2'">{{ index+1 }}</span>
<span>{{ tab.title }}</span>
<span style="font-size:16px">{{ tab.title }}</span>
<span v-if="index!=3"
style="width:54px;margin:0 10px;border-top: 1px dashed #C4C0C0;"></span>
style="width:27px;margin:0 10px;border-top: 1px dashed #C4C0C0;"></span>
</div>
</div>
<div class="right"
@@ -24,41 +30,49 @@
class="preview-btn"
@click="toPreview">
<i class="iconfont icon-yulan"></i>
<span style="margin-left: 6px">预览</span>
<span style="margin-left: 6px;width: 29px;">预览</span>
</div>
<a-button v-show="!showPublish && isRenderBtn"
type="primary"
class="publish-btn"
@click="openPublishModal">
<template #icon>
<i class="iconfont icon-Path"
style="font-size: 15px; margin-right: 6px"></i>
</template>
发布
</a-button>
</template>
<template v-else>
<div style="display: flex; align-items: center">
<a-spin size="small" />
<span style="margin-left: 10px">正在保存中...</span>
</div>
</template>
<a-button type="primary"
<a-button
class="publish-btn share-button"
style="display: flex;align-items: center;"
@click.stop="clickEntrance">
<template #icon>
<i class="iconfont icon-fenxiang"
style="font-size: 15px; margin-right: 6px"></i>
<i class="iconfont icon-fenxiang2 mr-6"></i>
<!-- <img class="download_img"
:src="require('@/assets/img/fenxiang.png')" /> -->
</template>
分享
</a-button>
</template>
<template v-else>
<div style="display: flex; align-items: center;">
<a-spin size="small" style="padding-left: 40px;"/>
<span style="margin-left: 10px;width: 90px;">正在保存中...</span>
</div>
</template>
<a-button v-show="!showPublish && isRenderBtn"
v-if="!showLoading"
type="primary"
class="publish-btn"
style="display: flex;align-items: center;"
@click="openPublishModal">
<template #icon>
<i class="iconfont icon-fabu3 mr-6"></i>
<!-- <img class="download_img"
:src="require('@/assets/img/fabu.png')" /> -->
</template>
发布
</a-button>
<a-button type="primary"
class="download-btn share-button"
style="display: flex;align-items: center;"
@click.stop="toDownload"
v-if="showDownload">
v-if="showDownload&&showxiazai">
<template #icon>
<img class="download_img"
:src="require('@/assets/img/download_center.png')" />
<!-- <img class="download_img"
:src="require('@/assets/img/download_center.png')" /> -->
<i class="iconfont icon-xiazaiqi mr-6"></i>
</template>
下载中心
</a-button>
@@ -66,22 +80,26 @@
</div>
<div class="right"
v-if="!showPreview && !isRenderBtn && !showShare">
<a-button type="primary"
<a-button
class="publish-btn share-button"
style="display: flex;align-items: center;"
@click.stop="clickEntrance">
<template #icon>
<i class="iconfont icon-fenxiang"
style="font-size: 15px; margin-right: 6px"></i>
<i class="iconfont icon-fenxiang2 mr-6"></i>
<!-- <img class="download_img"
:src="require('@/assets/img/fenxiang.png')" /> -->
</template>
分享
</a-button>
<a-button type="primary"
class="download-btn share-button"
style="display: flex;align-items: center;"
@click.stop="toDownload"
v-if="showDownload">
<template #icon>
<img class="download_img"
:src="require('@/assets/img/download_center.png')" />
<!-- <img class="download_img"
:src="require('@/assets/img/download_center.png')" /> -->
<i class="iconfont icon-xiazaiqi mr-6"></i>
</template>
下载中心
</a-button>
@@ -111,7 +129,7 @@
</template>
<script setup>
import { ref, computed, onMounted, createVNode } from "vue";
import { ref, computed, onMounted, createVNode,nextTick } from "vue";
import { useRouter, useRoute } from "vue-router";
import useEmitter from "@/composables/useEmitter";
import { publishSurvey, getSurveyInfo } from "@/api/publish";
@@ -137,7 +155,7 @@ const publish_type = 0;
const sn = route.query.sn;
const tabs = ref([
{
title: "题目设计",
title: "问卷设计",
link: "/survey/planet",
},
{
@@ -215,6 +233,11 @@ const showLoading = computed(() => {
return false;
});
const toPage = (path, title) => {
console.log(path, title)
showxiazai.value=null
if(path!='/survey/planet'&&path!="/survey/schedule/recycle"){
showxiazai.value=true
}
router.push({
path,
query: route.query,
@@ -222,12 +245,15 @@ const toPage = (path, title) => {
document.title = title;
};
const toPreview = () => {
const toPreview = async () => {
var res = await canPlanetPublish(route.query.sn);
if (res) {
router.push({
path: "/preview",
query: route.query,
});
document.title = name;
}
};
const openPublishModal = async () => {
@@ -235,7 +261,8 @@ const openPublishModal = async () => {
var res = await canPlanetPublish(route.query.sn);
if(res){
visible.value = true;
// visible.value = true;
handlePublish()
return;
}
@@ -336,7 +363,11 @@ const toDownload = () => {
// query: { path: route.path, sn },
// });
};
const showxiazai=ref(true)
onMounted(() => {
if(route.path=='/survey/planet/design'){
showxiazai.value=false
}
fetchInfo();
});
</script>
@@ -360,6 +391,11 @@ onMounted(() => {
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
color: #434343;
width: 150px;
overflow:hidden;
text-overflow: ellipsis;
white-space: nowrap;
-webkit-line-clamp: 1;
}
.icon-xiangzuo-moren {
cursor: pointer;
@@ -378,7 +414,7 @@ onMounted(() => {
height: 100%;
display: flex;
align-items: center;
font-size: 16px;
font-size: 18px;
color: #434343;
white-space: nowrap;
font-family: PingFangSC-Regular, PingFang SC;
@@ -392,17 +428,21 @@ onMounted(() => {
display: flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
line-height: 9px;
width: 20px;
height: 20px;
padding-top:5px;
padding-bottom:5px;
line-height: 10px;
border-radius: 60%;
background-color: #70b936;
color: #fff;
}
.click2 {
width: 18px;
height: 18px;
line-height: 9px;
width: 20px;
height: 20px;
padding-top:5px;
padding-bottom:5px;
line-height: 10px;
border-radius: 60%;
background-color: #f5f5f5;
color: black;
@@ -425,20 +465,21 @@ onMounted(() => {
color: #70b936;
}
.publish-btn {
margin-left: 20px;
height: 36px;
margin-left: 10px;
height: 32px;
line-height: 18px;
border-radius: 6px;
border-radius: 4px;
}
.download-btn {
margin-left: 32px;
// width: 88px;
height: 36px;
height: 32px;
line-height: 18px;
border-radius: 6px;
}
.share-button {
margin-left: 20px;
margin-left: 10px;
font-size: 16px;
}
.head-portrait {
width: 32px;
@@ -567,14 +608,16 @@ onMounted(() => {
}
.download_img {
width: 16px;
height: 14px;
height: 16px;
margin-right: 6px;
}
.click {
width: 18px;
height: 18px;
width: 20px;
height: 20px;
padding-top:5px;
padding-bottom:5px;
line-height: 10px;
font-size: 12px;
line-height: 9px;
border-radius: 60%;
background-color: #70b936;
color: #fff;
@@ -585,12 +628,17 @@ onMounted(() => {
display: flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
line-height: 9px;
width: 20px;
height: 20px;
padding-top:5px;
padding-bottom:5px;
line-height: 10px;
font-size: 12px;
border-radius: 60%;
background-color: #f5f5f5;
margin-right: 8px;
}
.mr-6 {
margin-right: 6px;
}
</style>

73
src/api/qc.js Normal file
View File

@@ -0,0 +1,73 @@
import request from '@/utils/request'
/* 标记答卷 */
export function surveys(params) {
return request({
url: `/console/surveys/${params.sn}`,
method: 'GET',
data: params
})
}
/* 标记答卷 */
export function answer_mark(params) {
return request({
url: `/console/surveys/${params.sn}/answer_mark`,
method: 'POST',
data: params
})
}
/**
* 获取题状态
*/
export function getParticularList(sn, params) {
console.log(params)
return request({
url: `/console/surveys/${sn}/answers?${params}`,
method: 'get'
})
}
/* 处理无效答卷 */
export function nullDeal(params) {
return request({
url: `/console/surveys/${params.sn}/nullDeal`,
method: 'POST',
data: params
})
}
/* 批量更新标记数据 */
export function answer_mark_batch(params) {
return request({
url: `/console/surveys/${params.sn}/answer_mark_batch`,
method: 'POST',
data: params
})
}
/* 答卷标记取消 */
export function answer_mark_del(params) {
return request({
url: `/console/surveys/${params.sn}/answer_mark`,
method: 'DELETE',
data: params
})
}
/* 答卷标记取消 */
export function getNullDealConfig(params) {
return request({
url: `/console/surveys/${params.sn}/getNullDealConfig`,
method: 'GET',
params
})
}
/* 答卷标记取消 */
export function heads(params) {
return request({
url: `/console/surveys/${params.sn}/answers/heads`,
method: 'GET',
params
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 623 B

BIN
src/assets/img/fabu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
src/assets/img/fenxiang.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -19,7 +19,7 @@
<i class="iconfont" v-html="item.icon"></i>
</div>
<div class="menu-bar-item-main-text">
<div>{{ item[property] }}</div>
<div style="font-size: 14px;">{{ item[property] }}</div>
<i
v-if="item.children.length > 0"
class="iconfont"
@@ -224,12 +224,12 @@ function menusStatusToFalsefather(menus) {
&-item {
position: relative;
width: 220px;
z-index: 99;
// z-index: 999;
background: rgba(245, 245, 245, 0.6);
&-child {
background-color: #ffffff;
.menu-bar-item-main-text{
width: 68px;
width: 94px;
}
}
&-img {
@@ -246,10 +246,12 @@ function menusStatusToFalsefather(menus) {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
// justify-content: center;
border-radius: 8px 8px 0px 0px;
padding-right: 5px;
padding-left: 52px;
transition: all 0.3s;
color: #434343;
&-active {
color: $yili-default-color;
background: #ffffff;
@@ -262,7 +264,7 @@ function menusStatusToFalsefather(menus) {
&-text {
display: flex;
align-items: center;
margin-top: 8px;
margin-top: 4px;
opacity: 0.8;
div {
font-size: 12px;
@@ -280,23 +282,29 @@ function menusStatusToFalsefather(menus) {
}
&:hover &-icon {
opacity: 1;
color: #70b936;
}
&:hover &-text {
opacity: 1;
color: #70b936;
}
&:hover {
background-color: #efeeee;
// background-color: #efeeee;
}
}
}
&-no-child {
}
&-has-child {
margin-top: 3px;
overflow: hidden;
transition: all 0.3s;
height: 0;
border-radius: 5px 5px 5px 5px;
box-shadow: 0px 2px 8px 0px rgb(0 0 0 / 10%);
position: relative;
z-index: 999;
color: #434343;
}
.menu-bar-item:last-child {
border-radius: 0px 8px 0px 0px;
@@ -306,7 +314,7 @@ function menusStatusToFalsefather(menus) {
}
}
.menu-bar-item-main-text {
font-size: 0.75rem;
font-size: 14px;
z-index: 99;
}
.menu-bar-item-main-icon {
@@ -336,7 +344,7 @@ function menusStatusToFalsefather(menus) {
z-index: 100;
height: 50px;
&:hover {
background-color: #efeeee !important;
background-color: #ffffff !important;
}
}
</style>

View File

@@ -16,7 +16,7 @@
</div>
<div
class="logical-title-line"
:style="{ left: `${activeIndex * posLeft}px`, width: `${lineWidth}px` }"
:style="{ left: `${(activeIndex) * posLeft + 20}px`, width: `${lineWidth}px` }"
></div>
</div>
</template>

View File

@@ -3,7 +3,7 @@
<!-- mob端 -->
<div
v-show="showPrevious && page > min && page < pages"
class="btn previous my-btn"
class="pfe-button btn previous my-btn"
@click="previous"
:style="`color: ${buttonTextColor};background-color: ${buttonColor}`"
>
@@ -12,7 +12,7 @@
</div>
<a-spin v-show="page < pages" :spinning="loading" wrapperClassName="spin">
<div
class="btn next my-btn"
class="pfe-button btn next my-btn"
@click="next"
:style="`color: ${buttonTextColor};background-color: ${buttonColor}`"
>

263
src/components/Slider.vue Normal file
View File

@@ -0,0 +1,263 @@
<template>
<div
class="slider"
:class="{ 'slider-disabled': disabled }"
:style="{
width: sliderWidth === 0 ? '90%' : `${sliderWidth}px`,
marginLeft: `${sliderMrgLeft}px`,
}"
>
<div class="slider-rail"></div>
<div class="slider-track" ref="track"></div>
<div
class="slider-step"
@click="stepClickHandle"
@mousemove="stepMoveHandle"
@mouseup="stepUpHandle"
@mousedown="stepDownHandle"
@touchmove.prevent="touchmoveHandle"
@touchend="touchendHandle"
>
<div
v-if="copyMark.length === 0"
class="slider-dot slider-dot-handler"
style="left: 0"
></div>
<div
v-for="(item, index) in copyMark"
:key="index"
class="slider-dot"
:class="{ 'slider-dot-handler': (activeMark?.left || 0) === item.left }"
:style="{
left: `${item.left}%`,
}"
></div>
<div
v-for="(item, index) in copyMark"
:key="index"
class="slider-step-value"
:style="{
left: `${item.left}%`,
}"
>
{{ item.value }}
</div>
</div>
</div>
</template>
<script>
import { ref } from "@vue/reactivity";
import { nextTick, watch } from "@vue/runtime-core";
export default {
name: "Slider",
props: {
marks: {
type: Array,
default: () => [],
},
value: {
type: Number,
default: 0,
},
stepWidth: {
type: Number,
default: 100,
},
disabled: {
type: Boolean,
default: false,
},
},
emits: ["update:value", "afterChange"],
setup(props, context) {
const track = ref(null);
const sliderWidth = ref("");
const sliderMrgLeft = ref(6);
const activeMark = ref({});
const copyMark = ref([]);
watch(
() => props.marks,
(val) => {
const step = 100 / (val.length - 1);
copyMark.value = val.map((m, index) => {
const temp = {
value: m,
left: Number((index * step).toFixed(2)),
};
if (index === 0) {
temp.left = 0;
}
if (index === val.length - 1) {
temp.left = 100;
}
return temp;
});
sliderWidth.value = props.stepWidth * val.length;
nextTick(() => {
sliderMrgLeft.value = (
(document.querySelector(".slider-step-value")?.clientWidth || 12) /
2
).toFixed(0);
});
},
{ immediate: true }
);
watch(
() => props.value,
(val) => {
const activeMarks = copyMark.value.find((m) => m.value === val);
activeMark.value = activeMarks;
nextTick(() => {
track.value.style.width = (activeMark.value?.left || 0) + "%";
});
},
{ immediate: true }
);
const markHandle = (offsetX = 0) => {
if (props.disabled || copyMark.value.length === 0) return;
const position = Number(((offsetX / sliderWidth.value) * 100).toFixed(0));
const closeIndex = copyMark.value
.map((item) => Math.abs(position - item.left))
.findIndex(
(item) =>
item ===
Math.min(
...copyMark.value.map((item) => Math.abs(position - item.left))
)
);
activeMark.value = copyMark.value[closeIndex];
track.value.style.width = copyMark.value[closeIndex].left + "%";
context.emit("update:value", copyMark.value[closeIndex].value);
};
const stepClickHandle = (event) => {
console.log("click", event);
let offsetX = event.target.offsetLeft;
if (offsetX === 0) {
offsetX = event.offsetX;
}
markHandle(offsetX);
};
const mouseDown = ref(false);
const stepMoveHandle = (event) => {
if (mouseDown.value) {
stepClickHandle(event);
}
};
const stepDownHandle = () => {
mouseDown.value = true;
};
const stepUpHandle = () => {
mouseDown.value = false;
setTimeout(() => {
context.emit("afterChange", activeMark.value?.value || undefined);
}, 100);
};
const touchmoveHandle = (event) => {
const offsetX =
event.changedTouches[0].pageX -
event.target.parentNode.getBoundingClientRect().left;
markHandle(offsetX);
};
const touchendHandle = () => {
context.emit("afterChange", activeMark.value?.value || undefined);
};
return {
copyMark,
track,
activeMark,
sliderWidth,
sliderMrgLeft,
stepClickHandle,
stepMoveHandle,
touchmoveHandle,
touchendHandle,
stepUpHandle,
stepDownHandle,
};
},
};
</script>
<style lang="scss" scoped>
.slider {
color: rgba(0, 0, 0, 0.85);
font-size: 14px;
line-height: 1.5715;
position: relative;
height: 33px;
margin: 14px 6px 10px;
padding: 4px 0;
cursor: pointer;
&-rail {
position: absolute;
top: 4px;
width: 100%;
height: 4px;
background-color: #f5f5f5;
border-radius: 2px;
transition: background-color 0.3s;
}
&-track {
position: absolute;
top: 4px;
height: 4px;
width: 0;
background-color: #a5d39f;
border-radius: 2px;
}
&-step {
position: absolute;
width: 100%;
height: 100%;
&-value {
position: absolute;
top: 10px;
transform: translateX(-50%);
display: inline-block;
color: rgba(0, 0, 0, 0.45);
text-align: center;
word-break: keep-all;
cursor: pointer;
}
}
&-dot {
position: absolute;
top: -2px;
width: 8px;
height: 8px;
margin-left: -4px;
background-color: #fff;
border: 2px solid #f0f0f0;
border-radius: 50%;
cursor: pointer;
&-handler {
width: 14px;
height: 14px;
border-color: #70B936;
outline: none;
box-shadow: 0 0 0 5px rgba(55, 204, 32, 0.2);
margin-top: -3px;
transform: translateX(-20%);
}
}
&-disabled {
cursor: not-allowed;
.slider-dot {
cursor: not-allowed;
}
.slider-step-value {
cursor: not-allowed;
}
}
&:hover {
.slider-rail {
background-color: #e1e1e1;
}
.slider-track {
background-color: #17ae29;
}
}
}
</style>

View File

@@ -24,7 +24,7 @@
>
<a-form :label-col="{ span: 6 }">
<a-form-item label="地址">
<a-input v-model:value="linkAddress" placeholder="请输入地址" />
<a-input v-model:value="linkAddress" placeholder="请输入地址" :disabled="fixation" />
</a-form-item>
<a-form-item label="显示文字">
<a-input v-model:value="linkText" placeholder="请输入显示的文字" />
@@ -266,6 +266,7 @@ import { useStore } from "vuex";
import { useRoute } from "vue-router";
import { nodeHandle } from "../views/planetDesign/Design/js/util.js";
import { baseOss } from "../config.js";
import * as cheerio from 'cheerio';
export default {
name: "Tinymce",
components: { Editor },
@@ -322,13 +323,29 @@ export default {
type: Boolean,
default: false,
},
isLinkContent: {
type: Boolean,
default: false,
},
// 固定插入地址
isFixation: {
type: Boolean,
default: false,
},
// 最大数量
maxNum: {
type: Number,
default: NaN
}
},
setup(props, context) {
const store = useStore();
const route = useRoute();
const sn = computed(() => route.query.sn || "");
const fixation = ref(props.isFixation)
const { linkAddress, linkText, linkDialogVisible, linkDiglogOkHandle } =
linkDialog();
linkDialog(fixation);
const {
d3Address,
d3Width,
@@ -371,14 +388,28 @@ export default {
quesList,
quoteList,
quoteDialogVisible,
isLinkContent: props.isLinkContent,
};
const { content, init, editorId, fileInput } = initTinymce(dataJson);
const { fileChange } = imageHandle(editorId, props.isImageStyle, sn);
const legendFormat = (str)=>{
if(str){
const $ = cheerio.load(str)
const text = $.text().trim()
return text
}
return str
}
onMounted(() => {
tinymce.init(init);
});
watch(content, (val, oldVal) => {
let num = legendFormat(content.value).length
context.emit("update:editorData", content.value);
if(num>=props.maxNum) {
message.warning(`消息内容最大输入字数为${props.maxNum}`)
return
}
});
watch(
() => props.editorData,
@@ -413,6 +444,8 @@ export default {
addQuoListHandle,
fileChange,
delQuoListHandle,
store,
fixation
};
},
};
@@ -447,6 +480,7 @@ function initTinymce(data) {
quoteDialogVisible,
isImageStyle,
sn,
isLinkContent,
} = data;
const content = ref("");
const fileInput = ref(null);
@@ -464,7 +498,7 @@ function initTinymce(data) {
plugins: ["autoresize", "paste"],
toolbar_mode: "wrap",
toolbar_persist: true,
toolbar:
toolbar: isLinkContent ? false :
"bold italic underline fontsizeselect quoteButton imgButton linkButton moreButton",
fontsize_formats: "12px 14px 16px 18px 20px 22px 24px 26px 28px",
images_upload_handler: (blobInfo, success, failure, progress) => {},
@@ -528,6 +562,23 @@ function initTinymce(data) {
context.emit("more", content.value);
},
});
editor.ui.registry.addIcon("linkIcon", link);
editor.ui.registry.addButton("linkButton", {
icon: "linkIcon",
onAction: function (e) {
const wrapperNode = tinymce.editors[editor.id].selection.getNode();
const content = tinymce.editors[editor.id].selection.getContent();
const contentNode = document.createElement("div");
contentNode.innerHTML = content;
linkText.value = contentNode.innerText;
if (wrapperNode.tagName.toLowerCase() === "a") {
tinymce.editors[editor.id].selection.select(wrapperNode, true);
linkText.value = wrapperNode.innerText;
linkAddress.value = wrapperNode.href || "";
}
linkDialogVisible.value = true;
},
});
commonFunc(editor);
editor.on("init", (e) => {
// 等页面渲染完毕,给工具栏绑定拖拽事件并且全选内容
@@ -564,6 +615,7 @@ function initTinymce(data) {
toolbar_mode: "sliding",
object_resizing: true,
fontsize_formats: "10px 12px 14px 16px 18px 20px 22px 24px 26px 28px",
font_formats: "默认='sans-serif';微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';隶书='隶书';幼圆='幼圆';",
content_style: `p { padding:0;margin:0 } body { font-size: ${defaultFontSize}px } img {max-width:100%;}`,
paste_auto_cleanup_on_paste: true,
paste_remove_styles: true,
@@ -670,7 +722,7 @@ function initTinymce(data) {
/**
* 插入链接弹框crud
*/
function linkDialog() {
function linkDialog(fixation) {
const linkAddress = ref("");
const linkText = ref(""); // 用于显示
const linkDialogVisible = ref(false);
@@ -682,11 +734,20 @@ function linkDialog() {
if (!linkAddress.value.startsWith("http")) {
linkAddress.value = `https://${linkAddress.value}`;
}
// 插入链接前后加空格
if(fixation.value) {
tinymce.editors[id].execCommand(
"mceInsertContent",
false,
`&nbsp;<a href="${linkAddress.value}">${linkText.value}</a>&nbsp;`
);
}else{
tinymce.editors[id].execCommand(
"mceInsertContent",
false,
`<a href="${linkAddress.value}">${linkText.value}</a>`
);
}
linkDialogVisible.value = false;
linkAddress.value = "";
linkText.value = "";
@@ -1039,4 +1100,10 @@ function util(store) {
cursor: pointer;
}
}
:deep(.tox-toolbar__group){
flex-wrap: nowrap!important;
}
:deep(.tox-collection__item-label){
white-space: nowrap;
}
</style>

View File

@@ -3,12 +3,12 @@
</template>
<script>
import SignaturePad from 'signature_pad';
import { onMounted, ref } from '@vue/runtime-core';
import common from '@/api/common.js';
import { useRoute } from 'vue-router';
import { message } from 'ant-design-vue';
import { date } from 'is-type-of';
import SignaturePad from 'signature_pad'
import { onMounted, ref } from '@vue/runtime-core'
import common from '@/api/common.js'
import { useRoute } from 'vue-router'
import { message } from 'ant-design-vue'
import { date } from 'is-type-of'
export default {
props: {
url: {
@@ -41,38 +41,40 @@ export default {
// // 取消绑定所有事件处理程序
// signaturePad.off();
// // 重新绑定所有事件处理程序
const canvas = ref();
const signaturePad = ref();
const isErase = ref(false);
const imgList = ref([]);
const isSave = ref(false);
const options = ref();
const route = useRoute();
const canvas = ref()
const signaturePad = ref()
const isErase = ref(false)
const imgList = ref([])
const isSave = ref(false)
const options = ref()
const route = useRoute()
//用于画完图后的显示在抬起时添加来自于allPoints的所有点的数据
// const List<List> allList = new ArrayList<>();
onMounted(() => {
if (props.url) {
let image = new Image();
let image = new Image()
//解决跨域问题
image.crossOrigin = '*';
image.src = props.url + '?v=' + Math.random();
image.crossOrigin = '*'
image.src = props.url + '?v=' + Math.random()
image.onload = () => {
var canvas = document.createElement('canvas');
// window.open(image)
var canvas = document.createElement('canvas')
var context = canvas.getContext('2d')
canvas.width = 302
canvas.height = 152
context.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height)
canvas.width = 316;
canvas.height = 191;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, 316, 191, 0, 0, 316, 191);
var quality = 1;
var quality = 1
//这里的dataurl就是base64类型
var dataURL = canvas.toDataURL('image/jpg', quality); //使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png因为压缩成png后base64的字符串可能比不转换前的长
signaturePad.value.fromDataURL(dataURL);
var dataURL = canvas.toDataURL('image/jpg', quality) //使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png因为压缩成png后base64的字符串可能比不转换前的长
signaturePad.value.fromDataURL(dataURL, {
width: 302,
height: 152
})
if (props.disabled) {
signaturePad.value.off();
signaturePad.value.off()
}
}
};
}
// dotSize default = (minWidth + maxWidth/2)
@@ -105,79 +107,77 @@ export default {
minWidth: 2,
maxWidth: 2,
backgroundColor: '#fafafa'
});
signaturePad.value.width = 318;
signaturePad.value.height = 192;
})
signaturePad.value.width = 318
signaturePad.value.height = 192
signaturePad.value.addEventListener('beginStroke', (e) => {
content.emit('begin', e);
});
content.emit('begin', e)
})
signaturePad.value.addEventListener('endStroke', (e) => {
content.emit('end', e);
console.log('end', e, signaturePad.value.toData());
});
content.emit('end', e)
console.log('end', e, signaturePad.value.toData())
})
if (props.disabled) {
signaturePad.value.off();
signaturePad.value.off()
}
});
})
const base64ToFile = (dataUrl, name) => {
var arr = dataUrl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], name + '.jpg', { type: 'image/jpg' })
}
return new File([u8arr], name + '.jpg', { type: 'image/jpg' });
};
//保存
const save = async () => {
if (signaturePad.value.isEmpty()) {
message.error('签名不能为空');
return;
message.error('签名不能为空')
return
}
let base64 = signaturePad.value.toDataURL()
let file = base64ToFile(base64, new Date().getTime())
const data = await common.cosUpload(file, file.name, '', () => {})
console.log(route.query.sn, file, data)
return data.url
}
let base64 = signaturePad.value.toDataURL();
let file = base64ToFile(base64, new Date().getTime());
const data = await common.cosUpload(file, file.name, '', () => {});
console.log(route.query.sn, file, data);
return data.url;
};
//清除
const clear = () => {
signaturePad.value.clear();
signaturePad.value.clear()
// setTimeout(() => {
// isErase.value = isErase2;
// erase();
// });
setTimeout(() => {
var ctx = canvas.value.getContext('2d');
ctx.globalCompositeOperation = 'source-over';
var ctx = canvas.value.getContext('2d')
ctx.globalCompositeOperation = 'source-over'
if (isErase.value) {
signaturePad.value.minWidth = 18;
signaturePad.value.maxWidth = 212;
signaturePad.value.penColor = '#fafafa';
signaturePad.value.velocityFilterWeight =
signaturePad.value.velocityFilterWeight + 0.1;
signaturePad.value.minWidth = 18
signaturePad.value.maxWidth = 212
signaturePad.value.penColor = '#fafafa'
signaturePad.value.velocityFilterWeight = signaturePad.value.velocityFilterWeight + 0.1
} else {
signaturePad.value.minWidth = 2;
signaturePad.value.maxWidth = 2;
signaturePad.value.penColor = '#000000';
signaturePad.value.velocityFilterWeight =
signaturePad.value.velocityFilterWeight + 0.1;
signaturePad.value.minWidth = 2
signaturePad.value.maxWidth = 2
signaturePad.value.penColor = '#000000'
signaturePad.value.velocityFilterWeight = signaturePad.value.velocityFilterWeight + 0.1
}
}, 100)
}
}, 100);
};
//撤回
const revoke = () => {
signaturePad.value.minWidth = 18;
signaturePad.value.maxWidth = 18;
const data = signaturePad.value.toData();
const newData = data.slice(0, data.length - 1);
signaturePad.value.minWidth = 18
signaturePad.value.maxWidth = 18
const data = signaturePad.value.toData()
const newData = data.slice(0, data.length - 1)
signaturePad.value.fromData(newData, {
clear: true
});
})
// newData.forEach(async (s) => {
// await setTimeout(() => {
// signaturePad.value.fromData([s], {
@@ -185,7 +185,7 @@ export default {
// });
// });
// });
console.log(newData);
console.log(newData)
// console.log(newData);
// data = newData;
// signaturePad.value.fromData(newData, {
@@ -193,61 +193,67 @@ export default {
// });
setTimeout(() => {
var ctx = canvas.value.getContext('2d');
ctx.globalCompositeOperation = 'source-over';
var ctx = canvas.value.getContext('2d')
ctx.globalCompositeOperation = 'source-over'
if (isErase.value) {
signaturePad.value.minWidth = 18;
signaturePad.value.maxWidth = 18;
signaturePad.value.penColor = '#fafafa';
signaturePad.value.minWidth = 18
signaturePad.value.maxWidth = 18
signaturePad.value.penColor = '#fafafa'
// ctx.globalCompositeOperation = 'destination-out';
} else {
signaturePad.value.minWidth = 2;
signaturePad.value.maxWidth = 2;
signaturePad.value.penColor = '#000000';
signaturePad.value.minWidth = 2
signaturePad.value.maxWidth = 2
signaturePad.value.penColor = '#000000'
// ctx.globalCompositeOperation = 'source-over';
}
}, 100);
};
}, 100)
}
//擦除
const erase = () => {
console.log(isErase.value);
var ctx = canvas.value.getContext('2d');
ctx.globalCompositeOperation = 'source-over';
console.log(isErase.value)
var ctx = canvas.value.getContext('2d')
ctx.globalCompositeOperation = 'source-over'
if (!isErase.value) {
signaturePad.value.minWidth = 18;
signaturePad.value.maxWidth = 18;
signaturePad.value.penColor = '#fafafa';
signaturePad.value.minWidth = 18
signaturePad.value.maxWidth = 18
signaturePad.value.penColor = '#fafafa'
//ctx.globalCompositeOperation = 'destination-out';
isErase.value = true;
isErase.value = true
} else {
signaturePad.value.minWidth = 2;
signaturePad.value.maxWidth = 2;
signaturePad.value.penColor = '#000000';
signaturePad.value.minWidth = 2
signaturePad.value.maxWidth = 2
signaturePad.value.penColor = '#000000'
isErase.value = false;
isErase.value = false
}
return isErase
}
return isErase;
};
const onMousedown = (e) => {
console.log(e);
console.log(e)
if (!isSave.value) {
isSave.value = true;
isSave.value = true
}
}
};
const onMouseleave = (e) => {
if (!isSave.value) {
isSave.value = false;
imgList.value.push(save());
isSave.value = false
imgList.value.push(save())
}
}
};
const onMouserup = (e) => {
if (!isSave.value) {
isSave.value = false;
imgList.value.push(save());
isSave.value = false
imgList.value.push(save())
}
};
}
// function resizeCanvas() {
// const ratio = Math.max(window.devicePixelRatio || 1, 1)
// canvas.value.width = canvas.value.offsetWidth * ratio
// canvas.value.height = canvas.value.offsetHeight * ratio
// canvas.value.getContext('2d').scale(ratio, ratio)
// signaturePad.clear() // otherwise isEmpty() might return incorrect value
// }
return {
canvas,
signaturePad,
@@ -259,9 +265,9 @@ export default {
onMouseleave,
onMouserup,
options
};
}
};
}
}
</script>
<style>

View File

@@ -6,4 +6,5 @@ module.exports = {
loginUrl: process.env.VUE_APP_LOGIN,
socketUrl: process.env.VUE_APP_SOCKETURL,
jsonpUrl: process.env.VUE_APP_JSONPURL,
jqrUrl: process.env.VUE_APP_YQRURL,
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 3121635 */
src: url('iconfont.woff2?t=1666232085564') format('woff2'),
url('iconfont.woff?t=1666232085564') format('woff'),
url('iconfont.ttf?t=1666232085564') format('truetype');
src: url('iconfont.woff2?t=1669789588035') format('woff2'),
url('iconfont.woff?t=1669789588035') format('woff'),
url('iconfont.ttf?t=1669789588035') format('truetype');
}
.iconfont {
@@ -13,6 +13,226 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-a-wenjian1:before {
content: "\e60e";
}
.icon-xiangmu:before {
content: "\e809";
}
.icon-PSM2:before {
content: "\e807";
}
.icon-KANO2:before {
content: "\e808";
}
.icon-tihuantupian:before {
content: "\e805";
}
.icon-fangdatupian:before {
content: "\e806";
}
.icon-lianxiren1:before {
content: "\e804";
}
.icon-dakai1:before {
content: "\e803";
}
.icon-a-bianzu34:before {
content: "\e802";
}
.icon-xuanxiangxianshi1:before {
content: "\e801";
}
.icon-a-CombinedShape21:before {
content: "\e800";
}
.icon-xiazaiqi:before {
content: "\e7fe";
}
.icon-piliang1:before {
content: "\e7ff";
}
.icon-fenxiang2:before {
content: "\e7fc";
}
.icon-fabu3:before {
content: "\e7fd";
}
.icon-a-3Dchangjingfenxi:before {
content: "\e7fb";
}
.icon-shoucang2:before {
content: "\e7f9";
}
.icon-shoucangkong:before {
content: "\e7fa";
}
.icon-shoucang:before {
content: "\e7f5";
}
.icon-yulan2:before {
content: "\e7f6";
}
.icon-a-bianzu33:before {
content: "\e7f7";
}
.icon-lianxiwomen:before {
content: "\e7f8";
}
.icon-a-bianzu22:before {
content: "\e7f3";
}
.icon-bianzu6:before {
content: "\e7f4";
}
.icon-a-zu699:before {
content: "\e7f2";
}
.icon-sucaiku:before {
content: "\e7f0";
}
.icon-wodezuopin:before {
content: "\e7f1";
}
.icon-rongqi6:before {
content: "\e7ed";
}
.icon-a-rongqi1:before {
content: "\e60c";
}
.icon-rongqi5:before {
content: "\e60d";
}
.icon-a-rongqi2:before {
content: "\e60b";
}
.icon-Worddaoru:before {
content: "\e7ef";
}
.icon-rongqi4:before {
content: "\e7ec";
}
.icon-a-zu671:before {
content: "\e7ee";
}
.icon-chakanrenqunbao:before {
content: "\e7ea";
}
.icon-lianjie:before {
content: "\e7eb";
}
.icon-a-zu709:before {
content: "\e7e8";
}
.icon-tubiaoshuoming:before {
content: "\e7e9";
}
.icon-chudahuishoushuai1:before {
content: "\e7e3";
}
.icon-chakanwenjuanrenshu:before {
content: "\e7e4";
}
.icon-tiaoyanxiangmuzhuangtai:before {
content: "\e7e5";
}
.icon-wanchengdatirenshu:before {
content: "\e7e6";
}
.icon-dajuanrenshu:before {
content: "\e7e7";
}
.icon-wenjuanku:before {
content: "\e7e2";
}
.icon-tiku1:before {
content: "\e7e1";
}
.icon-a-jingjiadianjijiage:before {
content: "\e7d7";
}
.icon-jingjiajingzhengdu:before {
content: "\e7d8";
}
.icon-liuliangzhishu:before {
content: "\e7d9";
}
.icon-yidongrijiansuoliang:before {
content: "\e7da";
}
.icon-jingjiagongsishuliang:before {
content: "\e7db";
}
.icon-yidongzhishu:before {
content: "\e7dc";
}
.icon-PCrijiansuoliang:before {
content: "\e7dd";
}
.icon-shoululiang:before {
content: "\e7de";
}
.icon-changweicigeshu:before {
content: "\e7df";
}
.icon-a-360zhishu:before {
content: "\e7e0";
}
.icon-guanjiancizhushi:before {
content: "\e7d4";
}

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,391 @@
"css_prefix_text": "icon-",
"description": "调研猩球前台icon",
"glyphs": [
{
"icon_id": "33133939",
"name": "文件 (1)",
"font_class": "a-wenjian1",
"unicode": "e60e",
"unicode_decimal": 58894
},
{
"icon_id": "33069016",
"name": "项目",
"font_class": "xiangmu",
"unicode": "e809",
"unicode_decimal": 59401
},
{
"icon_id": "33002397",
"name": "PSM",
"font_class": "PSM2",
"unicode": "e807",
"unicode_decimal": 59399
},
{
"icon_id": "33002398",
"name": "KANO",
"font_class": "KANO2",
"unicode": "e808",
"unicode_decimal": 59400
},
{
"icon_id": "32968447",
"name": "替换图片",
"font_class": "tihuantupian",
"unicode": "e805",
"unicode_decimal": 59397
},
{
"icon_id": "32967776",
"name": "放大图片",
"font_class": "fangdatupian",
"unicode": "e806",
"unicode_decimal": 59398
},
{
"icon_id": "32932788",
"name": "联系人",
"font_class": "lianxiren1",
"unicode": "e804",
"unicode_decimal": 59396
},
{
"icon_id": "32896944",
"name": "dakai",
"font_class": "dakai1",
"unicode": "e803",
"unicode_decimal": 59395
},
{
"icon_id": "32896940",
"name": "a-bianzu3",
"font_class": "a-bianzu34",
"unicode": "e802",
"unicode_decimal": 59394
},
{
"icon_id": "32896935",
"name": "xuanxiangxianshi",
"font_class": "xuanxiangxianshi1",
"unicode": "e801",
"unicode_decimal": 59393
},
{
"icon_id": "32896934",
"name": "a-CombinedShape2",
"font_class": "a-CombinedShape21",
"unicode": "e800",
"unicode_decimal": 59392
},
{
"icon_id": "32896894",
"name": "xiazaiqi",
"font_class": "xiazaiqi",
"unicode": "e7fe",
"unicode_decimal": 59390
},
{
"icon_id": "32896920",
"name": "piliang",
"font_class": "piliang1",
"unicode": "e7ff",
"unicode_decimal": 59391
},
{
"icon_id": "32880564",
"name": "分享",
"font_class": "fenxiang2",
"unicode": "e7fc",
"unicode_decimal": 59388
},
{
"icon_id": "32880565",
"name": "发布",
"font_class": "fabu3",
"unicode": "e7fd",
"unicode_decimal": 59389
},
{
"icon_id": "32874979",
"name": "3D场景分析",
"font_class": "a-3Dchangjingfenxi",
"unicode": "e7fb",
"unicode_decimal": 59387
},
{
"icon_id": "32850006",
"name": "收藏",
"font_class": "shoucang2",
"unicode": "e7f9",
"unicode_decimal": 59385
},
{
"icon_id": "32850007",
"name": "收藏空",
"font_class": "shoucangkong",
"unicode": "e7fa",
"unicode_decimal": 59386
},
{
"icon_id": "32775900",
"name": "收藏",
"font_class": "shoucang",
"unicode": "e7f5",
"unicode_decimal": 59381
},
{
"icon_id": "32775901",
"name": "预览",
"font_class": "yulan2",
"unicode": "e7f6",
"unicode_decimal": 59382
},
{
"icon_id": "32775957",
"name": "编组 3",
"font_class": "a-bianzu33",
"unicode": "e7f7",
"unicode_decimal": 59383
},
{
"icon_id": "32776009",
"name": "联系我们",
"font_class": "lianxiwomen",
"unicode": "e7f8",
"unicode_decimal": 59384
},
{
"icon_id": "32775859",
"name": "编组 2",
"font_class": "a-bianzu22",
"unicode": "e7f3",
"unicode_decimal": 59379
},
{
"icon_id": "32775860",
"name": "编组",
"font_class": "bianzu6",
"unicode": "e7f4",
"unicode_decimal": 59380
},
{
"icon_id": "32771188",
"name": "组 699",
"font_class": "a-zu699",
"unicode": "e7f2",
"unicode_decimal": 59378
},
{
"icon_id": "32726360",
"name": "素材库",
"font_class": "sucaiku",
"unicode": "e7f0",
"unicode_decimal": 59376
},
{
"icon_id": "32726361",
"name": "我的作品",
"font_class": "wodezuopin",
"unicode": "e7f1",
"unicode_decimal": 59377
},
{
"icon_id": "32599974",
"name": "容器",
"font_class": "rongqi6",
"unicode": "e7ed",
"unicode_decimal": 59373
},
{
"icon_id": "32599653",
"name": "容器 (1)",
"font_class": "a-rongqi1",
"unicode": "e60c",
"unicode_decimal": 58892
},
{
"icon_id": "32599654",
"name": "容器",
"font_class": "rongqi5",
"unicode": "e60d",
"unicode_decimal": 58893
},
{
"icon_id": "32599041",
"name": "容器 2",
"font_class": "a-rongqi2",
"unicode": "e60b",
"unicode_decimal": 58891
},
{
"icon_id": "32565199",
"name": "Word导入",
"font_class": "Worddaoru",
"unicode": "e7ef",
"unicode_decimal": 59375
},
{
"icon_id": "32563282",
"name": "容器",
"font_class": "rongqi4",
"unicode": "e7ec",
"unicode_decimal": 59372
},
{
"icon_id": "32563284",
"name": "组 671",
"font_class": "a-zu671",
"unicode": "e7ee",
"unicode_decimal": 59374
},
{
"icon_id": "32548960",
"name": "查看人群包",
"font_class": "chakanrenqunbao",
"unicode": "e7ea",
"unicode_decimal": 59370
},
{
"icon_id": "32548961",
"name": "链接",
"font_class": "lianjie",
"unicode": "e7eb",
"unicode_decimal": 59371
},
{
"icon_id": "32534923",
"name": "组 709",
"font_class": "a-zu709",
"unicode": "e7e8",
"unicode_decimal": 59368
},
{
"icon_id": "32534924",
"name": "图表说明",
"font_class": "tubiaoshuoming",
"unicode": "e7e9",
"unicode_decimal": 59369
},
{
"icon_id": "32524103",
"name": "触达回收率",
"font_class": "chudahuishoushuai1",
"unicode": "e7e3",
"unicode_decimal": 59363
},
{
"icon_id": "32524104",
"name": "查看问卷人数",
"font_class": "chakanwenjuanrenshu",
"unicode": "e7e4",
"unicode_decimal": 59364
},
{
"icon_id": "32524105",
"name": "调研项目状态",
"font_class": "tiaoyanxiangmuzhuangtai",
"unicode": "e7e5",
"unicode_decimal": 59365
},
{
"icon_id": "32524110",
"name": "完成答题人数",
"font_class": "wanchengdatirenshu",
"unicode": "e7e6",
"unicode_decimal": 59366
},
{
"icon_id": "32524182",
"name": "答卷人数",
"font_class": "dajuanrenshu",
"unicode": "e7e7",
"unicode_decimal": 59367
},
{
"icon_id": "32425797",
"name": "问卷库",
"font_class": "wenjuanku",
"unicode": "e7e2",
"unicode_decimal": 59362
},
{
"icon_id": "32425227",
"name": "题库",
"font_class": "tiku1",
"unicode": "e7e1",
"unicode_decimal": 59361
},
{
"icon_id": "32421503",
"name": "竞价点击价格(¥)",
"font_class": "a-jingjiadianjijiage",
"unicode": "e7d7",
"unicode_decimal": 59351
},
{
"icon_id": "32421505",
"name": "竞价竞争度",
"font_class": "jingjiajingzhengdu",
"unicode": "e7d8",
"unicode_decimal": 59352
},
{
"icon_id": "32421506",
"name": "流量指数",
"font_class": "liuliangzhishu",
"unicode": "e7d9",
"unicode_decimal": 59353
},
{
"icon_id": "32421507",
"name": "移动日检索量",
"font_class": "yidongrijiansuoliang",
"unicode": "e7da",
"unicode_decimal": 59354
},
{
"icon_id": "32421508",
"name": "竞价公司数量",
"font_class": "jingjiagongsishuliang",
"unicode": "e7db",
"unicode_decimal": 59355
},
{
"icon_id": "32421509",
"name": "移动指数",
"font_class": "yidongzhishu",
"unicode": "e7dc",
"unicode_decimal": 59356
},
{
"icon_id": "32421510",
"name": "PC日检索量",
"font_class": "PCrijiansuoliang",
"unicode": "e7dd",
"unicode_decimal": 59357
},
{
"icon_id": "32421511",
"name": "收录量",
"font_class": "shoululiang",
"unicode": "e7de",
"unicode_decimal": 59358
},
{
"icon_id": "32421512",
"name": "长尾词个数",
"font_class": "changweicigeshu",
"unicode": "e7df",
"unicode_decimal": 59359
},
{
"icon_id": "32421566",
"name": "360指数",
"font_class": "a-360zhishu",
"unicode": "e7e0",
"unicode_decimal": 59360
},
{
"icon_id": "32375799",
"name": "关键词注释",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -23,156 +23,165 @@ const constantRoutes = [
// },
{
path: '/:catchAll(.*)',
redirect: "/error/404",
meta: { noRedirectLogin: true },
redirect: '/error/404',
meta: { noRedirectLogin: true }
},
{
path: "/",
redirect: "/home"
path: '/',
redirect: '/home'
},
{
path: "/heartbeat",
component: () => import(/* webpackChunkName: 'heartbeat' */ "@views/Heartbeat/Index.vue"),
path: '/heartbeat',
component: () => import(/* webpackChunkName: 'heartbeat' */ '@views/Heartbeat/Index.vue')
},
{
path: "/home",
name: "home",
redirect: "/home/project",
component: () => import(/* webpackChunkName: 'home' */ "@views/Home/Index.vue"),
children: [...ProjectManage, ...TemplateMarket, ...Contact, ...DocumentLibrary,...DataStatistics, ...Creative]
path: '/home',
name: 'home',
redirect: '/home/project',
component: () => import(/* webpackChunkName: 'home' */ '@views/Home/Index.vue'),
children: [...ProjectManage, ...TemplateMarket, ...Contact, ...DocumentLibrary, ...DataStatistics, ...Creative]
},
{
path: "/luck",
name: "luck",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/luck.vue")
}, {
path: "/addinfor",
name: "addinfor",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/addinfor.vue")
path: '/luck',
name: 'luck',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/luck.vue')
},
{
path: "/prize",
name: "prize",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/prize.vue")
path: '/addinfor',
name: 'addinfor',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/addinfor.vue')
},
{
path: "/succeed",
name: "succeed",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/succeed.vue")
path: '/prize',
name: 'prize',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/prize.vue')
},
{
path: "/login",
name: "login",
component: () => import(/* webpackChunkName: 'login' */ "@views/Login/Login.vue")
path: '/succeed',
name: 'succeed',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/succeed.vue')
},
{
path: "/loginInvite",
name: "loginInvite",
component: () => import(/* webpackChunkName: 'login' */ "@views/TeamManage/TeamCenter/teamAdmin/login.vue")
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: 'login' */ '@views/Login/Login.vue')
},
{
path: "/answer",
name: "Answer",
path: '/loginInvite',
name: 'loginInvite',
component: () => import(/* webpackChunkName: 'login' */ '@views/TeamManage/TeamCenter/teamAdmin/login.vue')
},
{
path: '/answer',
name: 'Answer',
meta: { noRedirectLogin: true },
component: () => import(/* webpackChunkName: "answer" */ "../views/Answer/Index.vue")
component: () => import(/* webpackChunkName: "answer" */ '../views/Answer/Index.vue')
},
{
path: "/preview",
name: "Preview",
component: () => import(/* webpackChunkName: "preview" */ "../views/Answer/Preview.vue")
path: '/preview',
name: 'Preview',
component: () => import(/* webpackChunkName: "preview" */ '../views/Answer/Preview.vue')
},
{
path: "/survey",
name: "Survey",
redirect: "/survey/planet",
component: () => import(/* webpackChunkName: "survey" */ "../views/survey/index.vue"),
path: '/survey',
name: 'Survey',
redirect: '/survey/planet',
component: () => import(/* webpackChunkName: "survey" */ '../views/survey/index.vue'),
children: [
{
path: "planet",
name: "planet",
redirect: "/survey/planet/design",
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/Index.vue"),
path: 'planet',
name: 'planet',
redirect: '/survey/planet/design',
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/Index.vue'),
children: [
{
path: "design",
name: "design",
meta: { showPreview: true, showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/Design/DesignContent.vue")
path: 'design',
name: 'design',
meta: { showPreview: true, showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/Design/DesignContent.vue')
},
{
path: "logical",
name: "logical",
meta: { showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/Logical/Index.vue")
path: 'logical',
name: 'logical',
meta: { showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/Logical/Index.vue')
},
{
path: "test",
meta: { showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/PlanetTest.vue")
path: 'test',
meta: { showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/PlanetTest.vue')
},
{
path: "answer-setting",
meta: { showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/AnswerSetting.vue")
path: 'answer-setting',
meta: { showPublish: true, showDownload: false },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/AnswerSetting.vue')
},
{
path: "theme",
meta: { showPublish: true, showPreview: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/Theme/index.vue")
path: 'theme',
meta: { showPublish: true, showPreview: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/Theme/index.vue')
},
{
path: "redpacket",
meta: { showPublish: true, showPreview: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/index.vue")
path: 'redpacket',
meta: { showPublish: true, showPreview: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/index.vue')
},
{
path: "addset",
meta: { showPublish: true, showPreview: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/planetDesign/redpacket/addset.vue")
path: 'addset',
meta: { showPublish: true, showPreview: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/planetDesign/redpacket/addset.vue')
}
]
},
{
path: "schedule",
name: "schedule",
redirect: "/survey/schedule/index",
component: () => import(/* webpackChunkName: "planet" */ "../views/schedule/index.vue"),
path: 'schedule',
name: 'schedule',
redirect: '/survey/schedule/index',
component: () => import(/* webpackChunkName: "planet" */ '../views/schedule/index.vue'),
children: [
{
path: "recycle",
name: "recycle",
meta: { showPreview: true, showPublish: true, showDownload: true, },
component: () => import(/* webpackChunkName: "planet" */ "../views/schedule/recycle.vue")
},]
path: 'recycle',
name: 'recycle',
meta: { showPreview: true, showPublish: true, showDownload: true },
component: () => import(/* webpackChunkName: "planet" */ '../views/schedule/recycle.vue')
}
]
},
{
path: "analyse",
name: "analyse",
path: 'analyse',
name: 'analyse',
redirect: { name: 'Diagram' },
meta: { keepAlive: false },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/index"),
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/index'),
children: [
{
path: "data-particulars",
name: "DataParticulars",
path: 'data-particulars',
name: 'DataParticulars',
meta: { keepAlive: true },
meta: { showPublish: false, showPreview: false, showShare: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/particulars/list")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/particulars/list')
},
{
path: "diagram",
name: "Diagram",
path: 'test-particulars',
name: 'TestParticulars',
meta: { keepAlive: true },
meta: { showPublish: false, showPreview: false, showShare: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/particulars/test')
},
{
path: 'diagram',
name: 'Diagram',
meta: { keepAlive: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/diagram/test")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/diagram/test')
},
{
path: "test",
name: "test",
path: 'test',
name: 'test',
meta: { keepAlive: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/diagram/test")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/diagram/test')
},
{
path: "kndiagram",
@@ -210,65 +219,70 @@ const constantRoutes = [
// path: "index",
// component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/kndiagram/index"),
// }
},
{
path: "bi",
name: "bi",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/bi")
path: 'bi',
name: 'bi',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/bi')
},
{
// BPTO模拟
path: "bptoAnalog",
name: "bptoAnalog",
path: 'bptoAnalog',
name: 'bptoAnalog',
meta: { keepAlive: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/bptoAnalog/index")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/bptoAnalog/index')
},
{
path: "crosstabs",
name: "crosstabs",
path: 'crosstabs',
name: 'crosstabs',
meta: { keepAlive: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/crosstabs/index.vue")
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/crosstabs/index.vue')
},
{
path: "recycleBin",
name: "recycleBin",
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/recycleBin/index"),
redirect: "detailData",
children: [{
name: "数据明细",
path: "detailData",
path: 'recycleBin',
name: 'recycleBin',
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/recycleBin/index'),
redirect: 'detailData',
children: [
{
name: '数据明细',
path: 'detailData',
// meta: {title:"数据明细" },
component: () => import(/* webpackChunkName: "analyse" */ "@/views/DataAnalyse/recycleBin/binList/detailData"),
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/recycleBin/binList/detailData')
}
]
}
],
},
]
},
{
path: "publish",
name: "publish",
redirect: "/survey/publish/link",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/index"),
path: 'publish',
name: 'publish',
redirect: '/survey/publish/link',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/index'),
children: [
{
path: "link-source",
name: "link-source",
path: 'link-source',
name: 'link-source',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true },
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/link")
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/link')
},
{
path: "link",
name: "link",
path: 'link',
name: 'link',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true },
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/launch-center/launch-task/index")
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/launch-center/launch-task/index')
},
{
path: "create",
name: "create",
path: 'create',
name: 'create',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true },
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/launch-center/launch-task/create")
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/launch-center/launch-task/create')
},
{
path: 'enterprise-weChat',
name: 'enterprise-weChat',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true, permission:'super_admin_flag' },
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/launch-center/launch-task/enterpriseWeChat')
},
// {
// path: "link",
@@ -277,80 +291,86 @@ const constantRoutes = [
// component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/link")
// },
{
path: "analyst",
name: "analyst",
path: 'analyst',
name: 'analyst',
meta: { showPreview: false, showPublish: false, keepAlive: true, showShare: true },
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/analyse")
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/analyse')
},
{
path: "api",
name: "api",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/api")
path: 'api',
name: 'api',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/api')
},
{
path: "email",
name: "email",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/message/record"),
path: 'email',
name: 'email',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/message/record')
},
{
path: "census",
name: "census",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/census/census"),
path: 'census',
name: 'census',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/census/census')
},
{
path: "emailRecord",
name: "emailRecord",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/email/email")
path: 'emailRecord',
name: 'emailRecord',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/email/email')
},
{
path: "message",
name: "message",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/message/record")
path: 'message',
name: 'message',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/message/record')
},
{
path: "messageRecord",
name: "messageRecord",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/message/message")
path: 'messageRecord',
name: 'messageRecord',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/message/message')
},
{
path: "sample",
name: "sample",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/sample/sample")
path: 'sample',
name: 'sample',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/sample/sample')
},
{
path: "activity",
name: "activity",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/activity/activity")
path: 'activity',
name: 'activity',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/activity/activity')
},
{
path: "group",
name: "group",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/temp")
path: 'group',
name: 'group',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/temp')
},
{
path: "flush",
name: "flush",
component: () => import(/* webpackChunkName: "publish" */ "@/views/Publish/flush")
},
path: 'flush',
name: 'flush',
component: () => import(/* webpackChunkName: "publish" */ '@/views/Publish/flush')
}
]
},
}
]
},
{
path: "/InviteLogin",
name: "InviteLogin",
component: () => import(/* webpackChunkName: 'InviteLogin' */ "../views/TeamManage/InviteLogin.vue")
path: '/not-data',
name: 'notData',
// meta: { showPublish: false, showPreview: false, showShare: true, showDownload: true },
component: () => import(/* webpackChunkName: "analyse" */ '@/views/DataAnalyse/particulars/notData/notData')
},
{
path: "/team-manage",
name: "TeamManage",
component: () => import(/* webpackChunkName: 'home' */ "../views/TeamManage/index.vue"),
path: '/InviteLogin',
name: 'InviteLogin',
component: () => import(/* webpackChunkName: 'InviteLogin' */ '../views/TeamManage/InviteLogin.vue')
},
{
path: '/team-manage',
name: 'TeamManage',
component: () => import(/* webpackChunkName: 'home' */ '../views/TeamManage/index.vue'),
children: [
{
path: "user-center",
name: "userCenTer",
component: () => import(/* webpackChunkName: 'home' */ "../views/TeamManage//UserCenter/index.vue"),
path: 'user-center',
name: 'userCenTer',
component: () => import(/* webpackChunkName: 'home' */ '../views/TeamManage//UserCenter/index.vue')
// children: [
// {
// path: "design",
@@ -381,11 +401,11 @@ const constantRoutes = [
// ]
},
{
path: "team-center",
name: "teamCenter",
component: () => import(/* webpackChunkName: 'home' */ "../views/TeamManage//TeamCenter/index.vue")
},
],
path: 'team-center',
name: 'teamCenter',
component: () => import(/* webpackChunkName: 'home' */ '../views/TeamManage//TeamCenter/index.vue')
}
]
},
{
path: "/SceneSurveyViewerPage",
@@ -400,19 +420,29 @@ const constantRoutes = [
// component: () => import(/* webpackChunkName: "preview" */ "../views/DownloadCenter/index.vue")
// },
...routes
];
]
export const asyncRoutes = [];
export const asyncRoutes = []
const router = createRouter({
history: createWebHashHistory(),
routes: constantRoutes
});
})
router.beforeEach((to, from, next) => {
if (!to.meta.noRedirectLogin) {
if (window.self === window.top) {
// window.parent.location.href = 'https://yip-uat.dctest.digitalyili.com/login';
}
}
if(!to.meta.permission) {
next()
return
}
if(!JSON.parse(localStorage.getItem('plantUserInfo'))[to.meta.permission]) {
next({
path:'/error/404',
})
return
}
next()
})
export default router;
export default router

View File

@@ -7,5 +7,9 @@ const router = [
meta: { title: '模板库' },
component: MarketManage,
},
{
path: 'product_test/template',
redirect: '/home/market',
},
];
export default router;

View File

@@ -7,6 +7,9 @@ export const A_COMMON_SET_QUESSAVEPARAM = 'A_COMMON_SET_QUESSAVEPARAM';
export const A_COMMON_GET_ACTIVEQUESTION = 'A_COMMON_GET_ACTIVEQUESTION';
export const A_COMMON_SET_ACTIVEQUESTION = 'A_COMMON_SET_ACTIVEQUESTION';
export const A_COMMON_SET_BANK_LIST = 'A_COMMON_SET_BANK_LIST';
export const A_COMMON_GET_BANK_LIST = 'A_COMMON_GET_BANK_LIST';
export const A_COMMON_GET_WEBSOCKET = 'A_COMMON_GET_WEBSOCKET';
export const A_COMMON_SET_WEBSOCKET = 'A_COMMON_SET_WEBSOCKET';

View File

@@ -18,5 +18,13 @@ export default {
params
});
},
// 问卷发布-发布统计-题组配额
randomProgress (vuex, params = {}) {
return request({
url: `/console/survey_publishes/${params.sn}/random_progress`,
method: 'GET',
params
});
},
}
}

View File

@@ -1,27 +1,6 @@
// import CommonApi from '../../api/api';
import request from "@/utils/request";
import {
A_COMMON_GET_QUESTIONINFO,
A_COMMON_SET_QUESTIONINFO,
A_COMMON_GET_QUESSAVEPARAM,
A_COMMON_SET_QUESSAVEPARAM,
A_COMMON_GET_ACTIVEQUESTION,
A_COMMON_SET_ACTIVEQUESTION,
A_COMMON_GET_WEBSOCKET,
A_COMMON_SET_WEBSOCKET,
A_COMMON_GET_TOKEN,
A_COMMON_CLEAR_TOKEN,
M_COMMON_SET_TOKEN,
M_COMMON_SET_USERINFO,
M_COMMON_GET_USERINFO,
M_COMMON_SET_SURVEY_STATUS,
M_COMMON_SET_SURVEY_NAME,
M_COMMON_SET_TOKEN_UNAUTHORIZED,
GET_FILE_TYPE,
M_COMMON_SET_THEME_INFO,
HEADER_IMG_INFO,
DELETET_HEME_INFO_HEADIMGURL,
} from "../constance/constance.common";
import request from '@/utils/request'
import { A_COMMON_GET_QUESTIONINFO, A_COMMON_SET_QUESTIONINFO, A_COMMON_GET_QUESSAVEPARAM, A_COMMON_SET_QUESSAVEPARAM, A_COMMON_GET_ACTIVEQUESTION, A_COMMON_SET_ACTIVEQUESTION, A_COMMON_GET_WEBSOCKET, A_COMMON_SET_WEBSOCKET, A_COMMON_GET_TOKEN, A_COMMON_CLEAR_TOKEN, M_COMMON_SET_TOKEN, M_COMMON_SET_USERINFO, M_COMMON_GET_USERINFO, M_COMMON_SET_SURVEY_STATUS, M_COMMON_SET_SURVEY_NAME, M_COMMON_SET_TOKEN_UNAUTHORIZED, GET_FILE_TYPE, M_COMMON_SET_THEME_INFO, HEADER_IMG_INFO, DELETET_HEME_INFO_HEADIMGURL, A_COMMON_GET_BANK_LIST, A_COMMON_SET_BANK_LIST } from '../constance/constance.common'
export default {
namespaced: true,
@@ -30,161 +9,175 @@ export default {
quesSaveParam: {}, // 问题保存参数
activeQuestion: {}, // 当前处于编辑态的题目
file_type: [],
token: localStorage.getItem("plantToken") ? localStorage.getItem("plantToken") : "",
userInfo: localStorage.getItem("plantUserInfo")
? JSON.parse(localStorage.getItem("plantUserInfo"))
: {},
token: localStorage.getItem('plantToken') ? localStorage.getItem('plantToken') : '',
userInfo: localStorage.getItem('plantUserInfo') ? JSON.parse(localStorage.getItem('plantUserInfo')) : {},
surveyStatus: undefined,
surveyName: "",
surveyName: '',
tokenUnauthorized: false,
websocket: {}, // 长链接websocket实例
themeInfo: {}, // 主题配置信息
headerImgInfo: {}, //皮肤头图,
initHomeData: false, //首页数据更新
initHomeData: false //首页数据更新
},
getters: {},
mutations: {
/** 获取题型列表 */
[A_COMMON_SET_QUESTIONINFO](state, questionInfo) {
state.questionInfo = JSON.parse(questionInfo);
state.questionInfo = JSON.parse(questionInfo)
},
/** 获取问题保存参数 */
[A_COMMON_SET_QUESSAVEPARAM](state, quesSaveParam) {
state.quesSaveParam = JSON.parse(quesSaveParam);
state.quesSaveParam = JSON.parse(quesSaveParam)
},
/** 获取当前选中题型 */
[A_COMMON_SET_ACTIVEQUESTION](state, activeQuestion) {
state.activeQuestion = JSON.parse(activeQuestion);
state.activeQuestion = JSON.parse(activeQuestion)
},
/**获取题库列表 */
[A_COMMON_SET_BANK_LIST](state, bankList) {
state.bankList = bankList
},
/** 获取websocket实例 */
[A_COMMON_SET_WEBSOCKET](state, ws) {
state.websocket = ws;
state.websocket = ws
},
/** 获取token */
[M_COMMON_SET_TOKEN](state, token) {
state.token = token;
state.token = token
},
/** 获取用户信息 */
[M_COMMON_SET_USERINFO](state, userInfo) {
state.userInfo = JSON.parse(userInfo);
state.userInfo = JSON.parse(userInfo)
},
[M_COMMON_SET_SURVEY_STATUS](state, status) {
state.surveyStatus = status;
state.surveyStatus = status
localStorage.setItem('surveyStatus', status)
},
[M_COMMON_SET_SURVEY_NAME](state, name) {
state.surveyName = name;
state.surveyName = name
},
[M_COMMON_SET_TOKEN_UNAUTHORIZED](state, status) {
state.tokenUnauthorized = !!status;
state.tokenUnauthorized = !!status
},
[GET_FILE_TYPE](state, file_type) {
state.file_type = file_type;
state.file_type = file_type
},
[M_COMMON_SET_THEME_INFO](state, status) {
status.head_img_url = state.themeInfo.head_img_url || status.head_img_url;
// status.head_img_url = state.themeInfo.head_img_url || status.head_img_url;
// 不带头图使用
if (!state.headerImgInfo.checked) {
status.head_img_url = state.themeInfo.head_img_url;
}
state.themeInfo = status;
},
[HEADER_IMG_INFO](state, status) {
if (state.headerImgInfo.checked === false) {
status.checked = false;
}
state.headerImgInfo = status;
},
[DELETET_HEME_INFO_HEADIMGURL](state) {
state.themeInfo.head_img_url = "";
},
state.themeInfo.head_img_url = ''
}
},
actions: {
// 修改用户信息
userInfo({ state }, data) {
state.userInfo = data;
state.userInfo = data
},
initHomeData(vuex, data) {
vuex.state.initHomeData = data;
vuex.state.initHomeData = data
},
/**题型列表 */
[A_COMMON_GET_QUESTIONINFO]({ commit }, questionInfo) {
commit(A_COMMON_SET_QUESTIONINFO, questionInfo);
commit(A_COMMON_SET_QUESTIONINFO, questionInfo)
},
/**问题保存参数 */
[A_COMMON_GET_QUESSAVEPARAM]({ commit }, quesSaveParam) {
commit(A_COMMON_SET_QUESSAVEPARAM, quesSaveParam);
commit(A_COMMON_SET_QUESSAVEPARAM, quesSaveParam)
},
/**选中题型 */
[A_COMMON_GET_ACTIVEQUESTION]({ commit }, activeQuestion) {
commit(A_COMMON_SET_ACTIVEQUESTION, activeQuestion);
commit(A_COMMON_SET_ACTIVEQUESTION, activeQuestion)
},
/**获取题库列表 */
[A_COMMON_GET_BANK_LIST]({ commit }, bankList) {
commit(A_COMMON_SET_BANK_LIST, bankList)
},
/**websocket */
[A_COMMON_GET_WEBSOCKET]({ commit }, ws) {
commit(A_COMMON_SET_WEBSOCKET, ws);
commit(A_COMMON_SET_WEBSOCKET, ws)
},
/* 获取用户token */
[A_COMMON_GET_TOKEN]({ commit, dispatch }, token) {
if (token) {
console.log(dispatch);
commit(M_COMMON_SET_TOKEN, token);
console.log(dispatch)
commit(M_COMMON_SET_TOKEN, token)
}
},
[A_COMMON_CLEAR_TOKEN]: {
root: true,
handler({ commit }) {
commit(M_COMMON_SET_TOKEN, "");
localStorage.removeItem("plantToken");
return true;
},
commit(M_COMMON_SET_TOKEN, '')
localStorage.removeItem('plantToken')
return true
}
},
/* 获取当前登录用户信心 */
[M_COMMON_GET_USERINFO]({ commit, dispatch }, userInfo) {
if (userInfo) {
console.log(dispatch);
commit(M_COMMON_SET_MENUS, userInfo);
console.log(dispatch)
commit(M_COMMON_SET_MENUS, userInfo)
}
},
[GET_FILE_TYPE]({ commit, dispatch }, file_type) {
if (file_type) {
console.log(dispatch);
commit(GET_FILE_TYPE, file_type);
console.log(dispatch)
commit(GET_FILE_TYPE, file_type)
}
},
// 登记联系人
postCommunitiesContacts(vuex, params = {}) {
return request({
url: `/console/communities/${params.community_id}/contacts`,
method: "POST",
params,
});
method: 'POST',
params
})
},
// 前端下载
fileDown(vuex, { fileURL, fileName }) {
const req = new XMLHttpRequest();
req.open("get", fileURL);
req.responseType = "blob";
const req = new XMLHttpRequest()
req.open('get', fileURL)
req.responseType = 'blob'
req.onreadystatechange = (res) => {
if (res.currentTarget.readyState == 4 && res.currentTarget.status == 200) {
const url = window.URL.createObjectURL(res.currentTarget.response);
let link = document.createElement("a");
link.download = fileName || "defaultName";
link.style.display = "none";
link.href = url;
const url = window.URL.createObjectURL(res.currentTarget.response)
let link = document.createElement('a')
link.download = fileName || 'defaultName'
link.style.display = 'none'
link.href = url
// 触发点击
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
};
req.send();
}
req.send()
},
getYlToken() {
try {
return request({
url: `/authorizations`,
method: "POST",
method: 'POST',
headers: {
Authorization: localStorage.getItem("plantToken"),
remoteIp: "127.0.0.1",
},
});
} catch (error) {
console.error(error);
Authorization: localStorage.getItem('plantToken'),
remoteIp: '127.0.0.1'
}
},
},
};
})
} catch (error) {
console.error(error)
}
}
}
}

View File

@@ -4,71 +4,75 @@ import qs from 'qs'
const conUrl = '/console'
export default {
namespaced: true,
state:{
selectKeys:[],
dataFilterInfo:{},
exportInfo:{}
state: {
selectKeys: [],
selectIds: [],
dataFilterInfo: {},
exportInfo: {}
},
actions:{
exportInfo({state},data){
actions: {
exportInfo({ state }, data) {
state.exportInfo = data
},
// 题目答案数据清洗
cleanAnswer({state},{answer,question}){
console.log('开始数据清洗',answer);
cleanAnswer({ state }, { answer, question }) {
console.log('开始数据清洗', answer)
let newChild = []
// 判断是否有修改过的题型
let isFlag = false
for (let i = 0; i < answer.child.length; i++) {
const el = answer.child[i];
const el = answer.child[i]
let flag = true
let questionList = []
question.map(cel=>{
question.map((cel) => {
questionList.push(cel.question_index)
if(cel.question_index ===el.question_index&& cel.question_type !== el.question_type){
if (cel.question_index === el.question_index && cel.question_type !== el.question_type) {
flag = false
isFlag = true
}
})
if(questionList.length>0&&!questionList.includes(el.question_index)){
if (questionList.length > 0 && !questionList.includes(el.question_index)) {
flag = false
isFlag = true
}
if(flag){
if (flag) {
newChild.push(el)
}
}
if(newChild.length>0){
if (newChild.length > 0) {
answer.child = newChild
}else{
} else {
answer.child = [{}]
}
return {answer,isFlag}
return { answer, isFlag }
},
selectKeys({state},data){
selectKeys({ state }, data) {
state.selectKeys = data
},
dataFilterInfo({state},data){
selectIds({ state }, data) {
state.selectIds = data
},
dataFilterInfo({ state }, data) {
state.dataFilterInfo = data
},
// 投放列表
getSurveysAnswers(vuex, data = {}) {
if(data.answer&&typeof data.answer =='object'){
if (data.answer && typeof data.answer == 'object') {
data.answer = JSON.stringify(data.answer)
}
console.log('筛选列表数据',data);
console.log('筛选列表数据', data)
return request({
url: `${conUrl}/surveys/${data.sn}/answers`,
method: 'POST',
data
});
})
},
getSurveysHead(vuex, param = {}) {
return request({
url: `${conUrl}/surveys/${param.sn}/answers/heads`,
method: 'GET',
param
});
})
},
// 数据明细-导出pdf|zip
getSurveysAnswersExport(vuex, data = {}) {
@@ -76,7 +80,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answers_export`,
method: 'POST',
data
});
})
},
// 数据明细-下载
getSurveysAnswersDown(vuex, data = {}) {
@@ -84,7 +88,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answers_download`,
method: 'POST',
data
});
})
},
// 数据明细-回收站
delSurveysAnswers(vuex, data = {}) {
@@ -92,7 +96,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answers`,
method: 'DELETE',
data
});
})
},
// 筛选方案列表
getTemplateExport(vuex, param = {}) {
@@ -100,16 +104,16 @@ export default {
url: `${conUrl}/surveys/${param.sn}/template_export`,
method: 'GET',
param
});
})
},
// 导入作答信息
postAnswersImport(vuex, data = {}) {
let sn = data.get("sn")
let sn = data.get('sn')
return request({
url: `${conUrl}/surveys/${sn}/answers_import`,
method: 'POST',
data
});
})
},
// 筛选方案列表
getSurveysAnswerFilter(vuex, param = {}) {
@@ -117,7 +121,7 @@ export default {
url: `${conUrl}/surveys/${param.sn}/answer_filter`,
method: 'GET',
param
});
})
},
// 筛选方案新增
postSurveysAnswers(vuex, data = {}) {
@@ -125,7 +129,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter`,
method: 'POST',
data
});
})
},
// 筛选方案复制
postSurveysAnswersClone(vuex, data = {}) {
@@ -133,7 +137,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter/${data.id}`,
method: 'POST',
data
});
})
},
// 筛选方案修改
putSurveysAnswers(vuex, data = {}) {
@@ -141,7 +145,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter/${data.id}`,
method: 'PUT',
data
});
})
},
// 筛选方案置顶
putSurveysAnswersTop(vuex, data = {}) {
@@ -149,7 +153,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter/${data.id}/top`,
method: 'PUT',
data
});
})
},
// 筛选方案删除
delSurveysAnswersTop(vuex, data = {}) {
@@ -157,7 +161,7 @@ export default {
url: `${conUrl}/surveys/${data.sn}/answer_filter/${data.id}`,
method: 'DELETE',
data
});
},
})
}
}
}

View File

@@ -48,7 +48,7 @@ export default {
getPsmAnalyzeExport(vuex, params = {}) {
return request({
url: `${console}/surveys/psm/down-data`,
method: 'POST',
method: 'GET',
params
});
},

View File

@@ -0,0 +1,15 @@
export default {
namespaced: true,
state: {
// 企微投放链接地址
hrefUrl: '',
},
getters: {},
mutations: {},
actions: {
changeHrefUrl ({ state }, url) {
state.hrefUrl = url
},
},
};

19
src/style/utils.scss Normal file
View File

@@ -0,0 +1,19 @@
/*
覆盖全局样式
*/
.ant-select-item-option-selected{
font-weight: normal!important;
}
.ant-select-selector{
border-radius:4px;
}
.ant-select-dropdown.ant-select-dropdown-placement-bottomLeft{
border-radius:4px;
}
.ant-table-column-sorter {
position: relative;
top: -2px;
}

View File

@@ -1,5 +1,5 @@
$yili-default-color: #70b936;
$yili-disabled-color: rgba(112, 185, 54, 0.3);
$yili-btn-check-color: #28883D;
$yili-btn-check-color: #8ec75a;
$yili-btn-border-color: #74dd1d;
$yili-bkg-color: rgba(112, 185, 54, 0.11);

View File

@@ -242,18 +242,18 @@ const advancedQuesTypeList = [
// // check: false,
// // type: 104,
// // },
// {
// name: "PSM",
// icon: "&#xe708;",
// check: false,
// type: 101,
// },
// {
// name: "KANO",
// icon: "&#xe710;",
// check: false,
// type: 102,
// },
{
name: "PSM",
icon: "&#xe708;",
check: false,
type: 101,
},
{
name: "KANO",
icon: "&#xe710;",
check: false,
type: 102,
},
]
const d3QuestypeList = [
{

View File

@@ -1,3 +1,4 @@
import * as cheerio from "cheerio";
class Common {
/**
* rgba 转 hex

View File

@@ -20,7 +20,7 @@ service.interceptors.request.use(
(config) => {
// do something before request is sent
config.headers.Accept = 'application/json';
config.headers.ContentType = 'application/json';
//config.headers.ContentType = 'application/json';
config.headers.Authorization = `${localStorage.getItem('plantToken')}`;
config.headers.remoteIp = `${localStorage.getItem('plantIp') || ''}`;
// console.log(storage.getToken());

View File

@@ -33,11 +33,11 @@ export default defineComponent({
language: (navigator.browserLanguage || navigator.language).toLowerCase(),
};
const isMobile = browser.versions.mobile && !browser.versions.iPad;
try {
localStorage.setItem("plantIp", window.returnCitySN?window.returnCitySN["cip"]:"127.0.0.1");
} catch (error) {
localStorage.setItem("plantIp", "");
}
// try {
// localStorage.setItem("plantIp", returnCitySN["cip"]);
// } catch (error) {
// localStorage.setItem("plantIp", "");
// }
return { isMobile };
},

View File

@@ -1,6 +1,6 @@
<template>
<div>
<a-modal v-model:visible="shown" title="导出问卷" :destroyOnClose="true" @ok="handleOk">
<a-modal v-model:visible="shown" title="导出问卷" :destroyOnClose="true" @ok="handleOk" :confirmLoading="loading">
<div class="survey-download-modal-container">
<div class="titie">请选择导出部分</div>
<a-checkbox-group v-model:value="checkedList" :options="options" />
@@ -8,6 +8,7 @@
</a-modal>
<!-- 下载中心 -->
<DownloadCenter
:sn="sn"
:isView="true"
v-model:visible="downloadVisible"
v-if="downloadVisible"
@@ -47,6 +48,7 @@ const props = defineProps({
const route = useRoute();
const store = useStore();
const shown = ref(false);
const loading = ref(false);
const showModal = async () => {
shown.value = true;
@@ -80,6 +82,7 @@ const download = async () => {
// path: "/downloadCenter",
// query: { path:'planet',sn:props.sn },
// });
loading.value = false;
});
// const pendingModal = Modal.info({
// title: () => '导出任务进行中',
@@ -123,7 +126,10 @@ const download = async () => {
// })
};
const handleOk = () => {
if (!loading.value) {
loading.value = true;
download();
}
};
const checkedList = ref(["is_title", "is_in", "is_number", "is_if", "is_logic"]);

View File

@@ -3,14 +3,14 @@
<!-- 头部导航栏 -->
<div class="header">
<div @click="quitPreview" class="left">
<i class="iconfont" v-show="isLogin">&#xe6c0;</i>
<i class="iconfont" v-show="isLogin" style="font-size: 20px;">&#xe6c0;</i>
<span v-show="isLogin">退出预览</span>
</div>
<a-spin :spinning="issueLoading">
<div class="action-container">
<div class="comment" @click="handleComment">
<i class="iconfont icon-pinglun"></i>
<span>评论</span>
评论
</div>
<div class="download" style="margin-left: 20px" @click="handleDownload" v-show="isLogin">
<i class="iconfont icon-daochu1"></i>
@@ -35,7 +35,8 @@
v-show="isLogin && questionsData.survey?.status === 0"
>
<template #icon>
<i class="iconfont icon-Path" style="font-size: 18px; margin-right: 6px"></i>
<!-- <i class="iconfont icon-Path" style="font-size: 18px; margin-right: 6px"></i> -->
<i class="iconfont icon-fabu3" style="margin-right: 6px"></i>
</template>
发布
</a-button>
@@ -70,13 +71,24 @@
</div>
<!-- 预览-pc -->
<a-spin v-show="current === 'pc'" :spinning="loading">
<questions-pc />
<div v-if="questionsData.action?.code === 20013" class="action">
<img src="@/assets/img/answer/actions/suspend.png" />
<div class="msg">感谢您的反馈期待您下次参与</div>
</div>
<questions-pc v-else />
</a-spin>
<!-- 预览-mob -->
<!-- 手机模拟器 -->
<phone v-show="current === 'mobile'" :title="title">
<a-spin :spinning="loading">
<questions-mob />
<div
v-if="questionsData.action?.code === 20013"
class="action"
>
<img src="@/assets/img/answer/actions/suspend.png" />
<div class="msg">感谢您的反馈期待您下次参与</div>
</div>
<questions-mob v-else />
</a-spin>
</phone>
<!-- 展开 -->
@@ -189,6 +201,13 @@ export default defineComponent({
);
question.version = version;
});
// CBC配置
data.answer.cbc_shelves_version?.forEach((version) => {
const question = data.questions.find(
(question) => question.question_index === version.question_index
);
question.version = version;
});
} catch (error) {
console.log(error);
}
@@ -201,9 +220,8 @@ export default defineComponent({
}
// 发布
async function issue() {
var res = await canPlanetPublish(proxy.$route.query.sn);
if(!res) return;
if (!res) return;
issueLoading.value = true;
try {
@@ -336,6 +354,7 @@ export default defineComponent({
cursor: pointer;
.iconfont {
font-size: 16px;
margin-right: 6px;
}
}
.link-address {
@@ -362,9 +381,11 @@ export default defineComponent({
.publish-btn {
margin-left: 32px;
width: 88px;
height: 36px;
height: 32px;
line-height: 18px;
border-radius: 6px;
border-radius: 4px;
display: flex;
align-items: center;
}
}
@@ -518,7 +539,7 @@ export default defineComponent({
}
.open:active {
color: #1c6fff;
color: #70b936;
}
}
@@ -531,6 +552,27 @@ export default defineComponent({
}
}
.action {
padding-top: 99px;
text-align: center;
background-size: 224px 118px;
background-repeat: no-repeat;
background-position: calc(100% - 10px) 24px;
background-image: url("../../../assets/img/answer/pc-bg.png");
img {
width: 200px;
height: 150px;
margin-bottom: 12px;
}
.msg {
font-size: 16px;
color: #70b936;
line-height: 24px;
}
}
.container {
height: 100%;
}

View File

@@ -19,6 +19,9 @@
:title="question.title + '问题评论'"
/>
</div>
<!-- 试销 -->
<div class="attribute" v-html="question.attribute"></div>
<!-- 题型 -->
<div class="question-options">
<!-- 单选题 -->
<div v-if="question.question_type === 1">
@@ -246,6 +249,10 @@ export default defineComponent({
}
}
.attribute {
color: #70b936;
}
.question-options {
.flex {
display: flex;
@@ -265,9 +272,9 @@ export default defineComponent({
flex-direction: column;
img {
width: 120px;
height: 120px;
margin: 10px auto;
width: 50%;
margin: 10px 0;
border-radius: 10px;
}
}
}

View File

@@ -355,6 +355,10 @@
:title="question.stem"
:config="question.config"
v-model:answer="question.answer"
:loading="loading"
@previous="previous"
@next="next"
@toTop="toTop"
isMobile
:isAnswer="isAnswer"
:questionIndex="question.question_index"
@@ -429,7 +433,7 @@ export default defineComponent({ ...questions });
<style lang="scss" scoped>
.container {
height: calc(100% - 50px);
height: 100%;
overflow: auto;
.progress-bar {
@@ -461,7 +465,8 @@ export default defineComponent({ ...questions });
}
.questions {
padding: 20px;
padding: 20px 20px 70px 20px;
background-size: cover;
.question {
margin-bottom: 48px;
@@ -501,3 +506,21 @@ export default defineComponent({ ...questions });
background-color: #f8f8f8;
}
</style>
<style lang="scss">
// /*<=1024的设备*/
// @media (max-width: 1024px){
// html,
// body,
// * {font-size: 14px}
// }
/*<=600的设备*/
@media (max-width: 600px) {
html,
body {
& *:not(p, strong, em, p span) {
font-size: 14px;
}
}
}
</style>

View File

@@ -351,6 +351,10 @@
:title="question.stem"
:config="question.config"
v-model:answer="question.answer"
:loading="loading"
@previous="previous"
@next="next"
@toTop="toTop"
:isAnswer="isAnswer"
:questionIndex="question.question_index"
:label="question.title"

View File

@@ -196,7 +196,7 @@ export default defineComponent({
question.error = isError ? "请输入中文" : "";
break;
case 5: // 邮箱
isError = !/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(
isError = !/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
value
);
question.error = isError ? "请输入正确的email" : "";
@@ -237,7 +237,7 @@ export default defineComponent({
question.error = "请输入中文";
break;
case 5: // 邮箱
if (!/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value))
if (!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(value))
question.error = "请输入正确的email";
break;
case 6: // 手机号

View File

@@ -0,0 +1,393 @@
let answerQues = [];
/**
* 关联选项处理
* @returns
*/
function optionHandle(questionIndex) {
const optAndrelateList = [];
const rowOptAndrelateList = [];
const colOptAndrelateList = [];
const classOptAndrelateList = [];
const curQuesInfo = answerQues.find((ques) => ques.question_index === questionIndex);
curQuesInfo.list.forEach((l) => {
if (l.type === 0) {
optAndrelateList.push(...l.options);
} else if (l.type === 1) {
rowOptAndrelateList.push(...l.options);
} else if (l.type === 2) {
colOptAndrelateList.push(...l.options);
} else if (l.type === 3) {
classOptAndrelateList.push(...l.options);
}
})
const optList = optAndrelateList.map((opt, oIndex) => {
opt.option_index = oIndex + 1;
return opt
})
const rowOptList = rowOptAndrelateList.map((opt, oIndex) => {
opt.option_index = oIndex + 1;
return opt
})
const coloptList = colOptAndrelateList.map((opt, oIndex) => {
opt.option_index = oIndex + 1;
return opt
})
const classoptList = classOptAndrelateList.map((opt, oIndex) => {
opt.option_index = oIndex + 1;
return opt
})
return {
optAndrelateList: optList,
rowOptAndrelateList: rowOptList,
colOptAndrelateList: coloptList,
classOptAndrelateList: classoptList,
}
}
/**
* 运算符转换处理
* @param {*} operator
* @returns
*/
function operatorHandle(operator) {
let operatorStr = '';
if (operator === '=' || operator === '是') {
operatorStr = '==='
} else if (operator === '≠' || operator === '不是') {
operatorStr = '!=='
} else if (operator === '≥') {
operatorStr = '>='
} else if (operator === '≤') {
operatorStr = '<='
} else if (operator === '包含') {
operatorStr = 'includes'
} else if (operator === '不包含') {
operatorStr = '!includes'
} else {
operatorStr = operator;
}
return operatorStr
}
/**
* 处理每种题型的不同逻辑
* @param {*} answer 每个题里面的答题信息answer字段
* @param {*} logChild 逻辑信息
* @returns
*/
function quesHandle(answer, logChild) {
// 单选
const choiceHandle = () => {
// 如果配置的逻辑中option_index为0,则代表没有配置选中项,此时不做校验
if (logChild.option_index === 0) {
return true;
}
let status = false;
Object.keys(answer).forEach((key) => {
const { optAndrelateList } = optionHandle(logChild.question_index);
// 拿到答题时选中的选项位置
const postion = optAndrelateList.find((opt) => opt.option_key === key).option_index;
// 拿到配置的逻辑里选项的位置
const logPostion = optAndrelateList.find((opt) => opt.option_key === logChild.option_index).option_index;
status = eval(`${postion}${operatorHandle(logChild.operator)}${logPostion}`);
})
return status;
}
// 多选
const choiceCheckBoxHandle = () => {
// 如果配置的逻辑中option_index为0,则代表没有配置选中项,此时不做校验
if (logChild.option_index === 0 || logChild.is_select === '') {
return true;
}
let status = false;
if (logChild.is_select) {
// 如果配置的是选中, 则判断answer答案里面是否包含配置的选项
status = Object.keys(answer).includes(logChild.option_index);
} else {
// 如果配置的是未选中, 则判断answer答案里面是否不包含配置的选项
status = !Object.keys(answer).includes(logChild.option_index);
}
return status;
}
// 填空题
const inputHandle = () => {
// 如果配置的逻辑中value为空,则代表没有配置输入值,此时不做校验
if (!logChild.value || !logChild.operator) {
return true;
}
let status = false;
if (['包含', '不包含'].includes(logChild.operator)) {
// eval执行转换成字符串的语句(value.includes('222'))
status = eval(`'${answer.value}'.${operatorHandle(logChild.operator)}('${logChild.value}')`);
} else {
status = eval(`${answer.value}${operatorHandle(logChild.operator)}${logChild.value}`);
}
return status;
}
// 打分题
const rateHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.option_index === 0 || !logChild.operator || !logChild.value) {
return true;
}
return eval(`${answer[logChild.option_index]}${operatorHandle(logChild.operator)}${logChild.value}`);
}
// 矩阵单选题
const matrixRadioHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.cell_index === 0 || logChild.row_index === 0 || !logChild.operator) {
return true;
}
let status = false;
const { colOptAndrelateList } = optionHandle(logChild.question_index);
// 先找到配置的逻辑中,列选项的位置
const cellLogPostion = colOptAndrelateList.find((opt) => opt.option_key === logChild.cell_index).option_index;
// 然后在找到答案里面行和配置的逻辑行一样的key
const selectAnswer = Object.keys(answer).find((key) => key.split('_')[0] === logChild.row_index);
// 再找到逻辑里面配置的行在答案里面选中的位置
const cellPostion = colOptAndrelateList.find((opt) => opt.option_key === selectAnswer.split('_')[1]).option_index;
// 两者进行对比
status = eval(`${cellPostion}${operatorHandle(logChild.operator)}${cellLogPostion}`);
return status
}
// 矩阵多选题
const matrixCheckboxHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.cell_index === 0 || logChild.row_index === 0 || logChild.is_select === '') {
return true;
}
let status = false;
const optionKey = `${logChild.row_index}_${logChild.cell_index}`;
if (logChild.is_select) {
// 如果配置的是选中, 则判断answer答案里面是否包含配置的选项
status = Object.keys(answer).includes(optionKey);
} else {
// 如果配置的是未选中, 则判断answer答案里面是否不包含配置的选项
status = !Object.keys(answer).includes(optionKey);
}
return status
}
// 矩阵打分题
const matrixRateHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.cell_index === 0 || logChild.row_index === 0 || !logChild.operator || !logChild.value) {
return true;
}
const optionKey = `${logChild.row_index}_${logChild.cell_index}`;
return eval(`${answer[optionKey]}${operatorHandle(logChild.operator)}${logChild.value}`);
}
// 矩阵填空题
const matrixInputHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.cell_index === 0 || logChild.row_index === 0 || !logChild.operator || !logChild.value) {
return true;
}
let status = false;
const optionKey = `${logChild.row_index}_${logChild.cell_index}`;
if (['包含', '不包含'].includes(logChild.operator)) {
// eval执行转换成字符串的语句(value.includes('222'))
status = eval(`'${answer[optionKey]}'.${operatorHandle(logChild.operator)}('${logChild.value}')`);
} else {
status = eval(`${answer[optionKey]}${operatorHandle(logChild.operator)}${logChild.value}`);
}
return status
}
// 图片单选
const imgRadioHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.option_index === 0 || !logChild.operator) {
return true;
}
let status = false;
Object.keys(answer).forEach((key) => {
status = eval(`${key}${operatorHandle(logChild.operator)}${logChild.option_index}`);
})
return status;
}
// 图片多选
const imgCheckBoxHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.option_index === 0 || logChild.is_select === '') {
return true;
}
let status = false;
if (logChild.is_select) {
// 如果配置的是选中, 则判断answer答案里面是否包含配置的选项
status = Object.keys(answer).includes(logChild.option_index);
} else {
// 如果配置的是未选中, 则判断answer答案里面是否不包含配置的选项
status = !Object.keys(answer).includes(logChild.option_index);
}
return status;
}
// 分类题
const classifyHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.row_index === 0 || logChild.cell_index === 0 || !logChild.operator) {
return true;
}
const status = eval(`${answer[logChild.row_index]}${operatorHandle(logChild.operator)}${logChild.cell_index}`);
return status
}
// 排序题
const sortHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.option_index === 0 || !logChild.operator || logChild.location === '') {
return true;
}
const status = eval(`${answer[logChild.option_index]}${operatorHandle(logChild.operator)}${logChild.location}`);
return status;
}
// 恒定总和题
const constantSumHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (logChild.option_index === 0 || !logChild.operator || !logChild.value) {
return true;
}
return eval(`${answer[logChild.option_index]}${operatorHandle(logChild.operator)}${logChild.value}`);
}
// 日期时间题
const dateTimeHandle = () => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (!logChild.date || !logChild.operator || !logChild.time) {
return true;
}
let status = false;
if (answer.date && answer.time) {
// 如果同时配置了日期和时间
status = answer.date === logChild.date && answer.time === logChild.time;
} else if (answer.date) {
// 如果只配置了日期
status = answer.date === logChild.date;
} else if (answer.time) {
// 如果只配置了时间
status = answer.time === logChild.time;
}
return status;
}
// psm
const psmHandle = (config) => {
// 如果配置的逻辑中参数为空,则代表没有配置逻辑匹配值,此时不做校验
if (!logChild.value) {
return true;
}
const answerIndex = answer[5];
const status = String(config.price_gradient[answerIndex - 1]) === logChild.value;
return status;
}
return {
choiceHandle,
choiceCheckBoxHandle,
inputHandle,
rateHandle,
matrixRadioHandle,
matrixCheckboxHandle,
matrixRateHandle,
matrixInputHandle,
imgRadioHandle,
imgCheckBoxHandle,
classifyHandle,
sortHandle,
constantSumHandle,
dateTimeHandle,
psmHandle,
}
}
function getConditionStatus(logChild) {
let resultStatus = [];
//拿到当前题的答案
const answer = answerQues.find((ques) => ques.question_index === logChild.question_index).answer;
//拿到当前题的config信息
const config = answerQues.find((ques) => ques.question_index === logChild.question_index).config;
// 如果逻辑是不为空则为作答
if (logChild.is_answer) {
// 每个题型有不同的判断逻辑
const quesHandles = quesHandle(answer, logChild);
let quesStatus = false;
if (answer) {
try {
switch (logChild.question_type) {
case 1:
quesStatus = quesHandles.choiceHandle();
break;
case 2:
quesStatus = quesHandles.choiceCheckBoxHandle();
break;
case 4:
quesStatus = quesHandles.inputHandle();
break;
case 5:
quesStatus = quesHandles.rateHandle();
break;
case 7:
quesStatus = quesHandles.dateTimeHandle();
break;
case 8:
quesStatus = quesHandles.matrixInputHandle();
break;
case 9:
quesStatus = quesHandles.matrixRadioHandle();
break;
case 10:
quesStatus = quesHandles.matrixCheckboxHandle();
break;
case 11:
quesStatus = quesHandles.matrixRateHandle();
break;
case 13:
quesStatus = quesHandles.imgRadioHandle();
break;
case 14:
quesStatus = quesHandles.imgCheckBoxHandle();
break;
case 15:
quesStatus = quesHandles.classifyHandle();
break;
case 16:
quesStatus = quesHandles.sortHandle();
break;
case 17:
quesStatus = quesHandles.constantSumHandle();
break;
case 101:
quesStatus = quesHandles.psmHandle(config);
break;
default:
break;
}
} catch (error) {
console.log(error);
quesStatus = false;
}
}
resultStatus.push(...[answer ? true : false, quesStatus])
} else {
//如果为空则为不作答判断当前题是否包含answer字段如果有则已经作答返回false。
resultStatus.push(answer ? false : true)
}
return eval(resultStatus.join('&&'));
}
function getlogicStatus(questionData) {
answerQues = JSON.parse(JSON.stringify(questionData.questions));
const logics = JSON.parse(JSON.stringify(questionData.logics));
logics.forEach((logs) => {
// 如果选择的是always则直接返回true
if (logs.logic.length === 1 && logs.logic[0].logic === 'always') {
logs.logicStatus = true;
} else {
// 处理每条逻辑(if或者and或者or)的结果
// 将上一步获取到的每条逻辑状态整合起来,统一判断
let statusStr = '';
logs.logic.forEach((logChild, condIndex) => {
const conditionStatus = getConditionStatus(logChild);
if (condIndex !== logs.logic.length - 1) {
statusStr = statusStr + conditionStatus + (logChild.logic === 'or' ? '||' : '&&');
} else {
statusStr = statusStr + conditionStatus;
}
})
logs.logicStatus = eval(statusStr);
}
})
console.log('logics', logics);
return logics;
}
export default getlogicStatus

View File

@@ -0,0 +1,115 @@
import getlogicStatus from "./logical";
// 更新code
function updateCode(action, skipQuestionIndex) {
if (skipQuestionIndex === -1) {
action.code = 20011;
action.msg = "成功结束页";
} else if (skipQuestionIndex === -2) {
action.code = 20004;
action.msg = "甄别结束页";
} else if (skipQuestionIndex === -3) {
action.code = 20016;
action.msg = "配额超限页";
}
}
// 更新分页pages(题后跳转逻辑)
function updatePagesAfter(pages, logic, jumpTo, page) {
const { question_index, skip_question_index } = logic;
const startIndex = pages.findIndex(
(page) => page.findIndex((questionIndex) => questionIndex === question_index) !== -1
);
const endIndex = pages.findIndex(
(page) => page.findIndex((questionIndex) => questionIndex === skip_question_index) !== -1
);
if (endIndex !== -1) {
const endQuestionIndex = pages[endIndex].findIndex(
(questionIndex) => questionIndex === skip_question_index
);
pages[endIndex].splice(0, endQuestionIndex);
// 跳转到某页
if (startIndex > endIndex && startIndex < page) {
jumpTo.question_index = question_index;
return (jumpTo.question_page = endIndex + 1);
}
pages.splice(startIndex + 1, endIndex - startIndex - 1);
}
}
// 更新分页pages(题前设置逻辑)
function updatePagesBefore(pages, hideQuestionIndex) {
const pagesIndex = pages.findIndex(
(page) => page.findIndex((questionIndex) => questionIndex === hideQuestionIndex) !== -1
);
if (pages[pagesIndex].length === 1) {
pages.splice(pagesIndex, 1);
} else {
const pageIndex = pages[pagesIndex].findIndex(
(questionIndex) => questionIndex === hideQuestionIndex
);
pages[pagesIndex].splice(pageIndex, 1);
}
}
// 自动填写
function autoFill(answerAutoFill, logic) {
answerAutoFill.push({
answer: logic.autofill.answer_insert,
question_index: logic.question_index,
question_type: logic.autofill.question_type,
});
}
// 选项隐藏逻辑
function updateOptionHidden(hide_options, logic) {
const { question_index, hide_option_index } = logic;
hide_options.question_index = question_index;
hide_options.option_key.push(...hide_option_index.map((opt) => opt.option_key));
}
// 模拟答题接口
export default function answerMock(questionsData, page) {
const data = {
action: { code: 20010, msg: "答案已记录" },
jump_to: {},
hide_options: {
option_key: [],
},
answer_info_autofill: [],
pages: JSON.parse(JSON.stringify(questionsData.answer.pages_init)),
};
const logics = getlogicStatus(questionsData);
logics.forEach((logic) => {
if (logic.logicStatus && logic.skip_type === 0) {
// 题后跳转逻辑
if (logic.skip_question_index < 0) {
return updateCode(data.action, logic.skip_question_index);
}
updatePagesAfter(data.pages, logic, data.jump_to, page);
} else if (logic.logicStatus && logic.skip_type === 1) {
// 题前设置逻辑
updatePagesBefore(data.pages, logic.question_index);
} else if (logic.logicStatus && logic.skip_type === 3) {
// 自动填写逻辑
autoFill(data.answer_info_autofill, logic);
} else if (logic.logicStatus && logic.skip_type === 4) {
// 选项隐藏逻辑
updateOptionHidden(data.hide_options, logic);
}
});
// 更新问卷状态
if (page === data.pages.length) {
data.action.code = 20011;
data.action.msg = "成功结束页";
}
// 拒绝知情同意书
const refuseIndex = questionsData.questions.findIndex(
(question) => question.question_type === 23 && question.answer?.value === "2"
);
if (refuseIndex !== -1) {
data.action.code = 20013;
data.action.msg = "不同意继续参与,已结束作答";
}
// 返回数据
return data;
}

View File

@@ -35,6 +35,7 @@ import QPSM from "../../questions/high/QPSM.vue";
import QKANO from "../../questions/high/QKANO.vue";
import QBPTO from "../../questions/high/QBPTO.vue";
import QMXD from "../../questions/high/QMXD.vue";
import answerMock from "./mock";
export default defineComponent({
components: {
@@ -79,6 +80,7 @@ export default defineComponent({
type: Boolean,
default: false,
},
// 是否模板预览
isTemplate: {
type: Boolean,
default: false,
@@ -113,11 +115,11 @@ export default defineComponent({
});
// 是否显示分页器
const showPage = computed(() => {
return [104, 105, 201].includes(questions.value[0]?.question_type) ? false : true;
return [102, 104, 105, 201].includes(questions.value[0]?.question_type) ? false : true;
});
// 答题
async function answer(callback, callbackBeforePage) {
if ((questions.value.length || !questionsData.value.questions.length) && props.isAnswer) {
if ((questions.value.length || !questionsData.value.questions.length) && !props.isTemplate) {
// 表单验证(当前页)
const errors = questions.value.filter((question) => {
const { config, answer, question_type: questionType } = question;
@@ -204,7 +206,8 @@ export default defineComponent({
question.error = isError ? "请输入中文" : "";
break;
case 5: // 邮箱
isError = !/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(
isError =
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
value
);
question.error = isError ? "请输入正确的email" : "";
@@ -245,7 +248,11 @@ export default defineComponent({
question.error = "请输入中文";
break;
case 5: // 邮箱
if (!/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value))
if (
!/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
value
)
)
question.error = "请输入正确的email";
break;
case 6: // 手机号
@@ -278,6 +285,27 @@ export default defineComponent({
return isError;
});
if (!errors.length) {
// 判断是作答还是预览
if (!props.isAnswer) {
loading.value = true;
try {
// 模拟接口
const data = answerMock(questionsData.value, page.value);
console.log("模拟作答数据", data);
// 更新答案
updateAnswer(data.answer_info_autofill);
// 更新分页数组
questionsData.value.answer.pages = data.pages;
// 选项隐藏
hideOptions(data.hide_options);
// 更新action
questionsData.value.action = data.action;
callback(data.jump_to);
} catch (error) {
console.log(error);
}
return (loading.value = false);
}
// 表单验证通过,开始答题
const questionsAnswer = questions.value.map((question) => ({
question_index: question.question_index,
@@ -325,9 +353,9 @@ export default defineComponent({
questionsData.value.action = data.action;
callback(data.jump_to);
// 写入关联选项缓存
if (props.isAnswer) {
if (props.isAnswer && questionsData.value.survey.is_breakpoint) {
if (data.action.code === 20010) {
const questionsCache = JSON.parse(localStorage.getItem(questionsCache)) || {};
const questionsCache = JSON.parse(localStorage.getItem("questionsCache")) || {};
questionsCache[proxy.$route.query.sn] = questionsData.value.questions;
localStorage.setItem("questionsCache", JSON.stringify(questionsCache));
} else {
@@ -360,7 +388,7 @@ export default defineComponent({
// 下一页
async function next(callbackBeforePage) {
answer((jumpPage) => {
if (jumpPage) {
if (jumpPage?.question_page) {
page.value = jumpPage.question_page;
} else {
page.value += 1;

View File

@@ -12,7 +12,12 @@
<a-button v-if="!config.is_hide" key="back" :loading="loading" @click="refuse">{{
config.disagree_button_text
}}</a-button>
<a-button key="submit" type="primary" :loading="loading" :disabled="time" @click="agree"
<a-button
key="submit"
type="primary"
:loading="loading"
:disabled="time ? true : false"
@click="agree"
>{{ config.agree_button_text }}<span v-if="time" class="time">({{ time }}s)</span></a-button
>
</template>

View File

@@ -10,7 +10,7 @@
/>
<Remark :title="label + '标题评论'" :type="1" v-if="!isAnswer" />
</div>
<div v-if="showDesc" class="desc-part">
<div v-if="showDesc" class="desc-part" :class="isMobile ? 'm-desc-part' : ''">
<rich-text
isPreview
:nodes="desc"
@@ -100,6 +100,10 @@ export default defineComponent({
flex: 1;
}
}
.m-desc-part {
margin-bottom: 30px;
}
}
.title {
@@ -116,6 +120,7 @@ export default defineComponent({
}
.m-desc {
flex: 1;
margin-top: 30px;
}
</style>

View File

@@ -3,9 +3,10 @@
<div class="checkbox-group">
<div
class="checkbox"
:class="isMobile || config.each_number === 1 ? '' : 'side'"
:style="isMobile ? 'width:100%' : `width: calc(100% / ${config.each_number})`"
v-for="option in options"
:key="option.option_key"
:style="isMobile ? 'width:100%' : `width: calc(100% / ${config.each_number})`"
>
<a-image width="100%" :src="option.option_config.image_url[0]" />
<div class="check-option">
@@ -97,8 +98,6 @@ export default defineComponent({
padding-right: 32px;
:deep(img) {
max-width: 176px;
height: 176px;
border-radius: 10px;
margin-bottom: 24px;
object-fit: cover;
@@ -114,5 +113,12 @@ export default defineComponent({
}
}
}
.side {
:deep(img) {
height: 176px;
max-width: 176px;
}
}
}
</style>

View File

@@ -3,9 +3,10 @@
<div class="radio-group">
<div
class="radio"
:class="isMobile || config.each_number === 1 ? '' : 'side'"
:style="isMobile ? 'width:100%' : `width: calc(100% / ${config.each_number})`"
v-for="option in options"
:key="option.option_key"
:style="isMobile ? 'width:100%' : `width: calc(100% / ${config.each_number})`"
>
<a-image width="100%" :src="option.option_config.image_url[0]" />
<div class="radio-option">
@@ -85,8 +86,6 @@ export default defineComponent({
padding-right: 32px;
:deep(img) {
max-width: 176px;
height: 176px;
border-radius: 10px;
margin-bottom: 24px;
object-fit: cover;
@@ -98,5 +97,12 @@ export default defineComponent({
align-items: center;
}
}
.side {
:deep(img) {
height: 176px;
max-width: 176px;
}
}
}
</style>

View File

@@ -2,20 +2,15 @@
<div class="imgs" :class="isMobile ? 'mob-imgs' : ''">
<div
class="img-show"
:class="isMobile || config.each_number === 1 ? '' : 'side'"
:style="isMobile ? 'width:100%' : `width: calc(100% / ${config.each_number})`"
v-for="option in options"
:key="option.option_key"
:style="
isMobile ? 'width:100%' : `width: calc(100% / ${config.each_number})`
"
>
<!-- 闪照 -->
<div v-if="config.countdown_type && config.countdown_time">
<div v-if="config?.countdown_type && config?.countdown_time">
<!-- 点击查看图片 -->
<div
v-if="option.preview"
class="thumbnail see"
@click="previewImg(option)"
>
<div v-if="option.preview" class="thumbnail see" @click="previewImg(option)">
<img src="@/assets/img/answer/see-img.png" alt="" />
<div class="text">点击查看图片</div>
<div class="desc">查看超时后自动焚毁</div>
@@ -31,9 +26,7 @@
<!-- 图片名 -->
<div v-html="option.option" />
<!-- 倒计时 -->
<div v-if="previewTime" class="preview-time">
{{ previewTime }} 秒后自动关闭
</div>
<div v-if="previewTime" class="preview-time">{{ previewTime }} 秒后自动关闭</div>
<!-- 预览 -->
<a-image
v-if="previewTime"
@@ -127,9 +120,18 @@ export default defineComponent({
:deep(.ant-image-img) {
width: 100%;
margin: 24px 0;
object-fit: cover;
border-radius: 10px;
cursor: pointer;
}
}
.side {
:deep(.ant-image-img) {
height: 176px;
max-width: 176px;
}
}
}
.thumbnail {

View File

@@ -130,13 +130,14 @@ export default defineComponent({
if (!val) {
return message.error(`请输入数字`);
}
if (val && val < props.config.min) {
if (!isNaN(val) && Number(val) < Number(props.config.min)) {
changeValue({ target: { value: "" } });
message.error(`请输入大于等于${props.config.min}的数字`);
}
if (val && val < props.config.min) {
if (!isNaN(val) && Number(val) > Number(props.config.max)) {
changeValue({ target: { value: "" } });
message.error(`请输入大于等于${props.config.min}的数字`);
message.error(`请输入大于等于${props.config.max}的数字`);
}
}

View File

@@ -206,10 +206,11 @@ export default defineComponent({
.td {
min-width: 150px;
max-width: 150px;
padding: 10px 16px;
border-left: 1px dashed #d9d9d9;
text-align: center;
white-space: nowrap;
vertical-align: middle;
}
.td:first-child {
@@ -226,6 +227,7 @@ export default defineComponent({
.mob-matrix {
.table .tr .td {
min-width: 120px;
max-width: 120px;
}
}
</style>

View File

@@ -215,10 +215,12 @@ export default defineComponent({
.tr {
.td {
min-width: 150px;
max-width: 150px;
width: 150px;
padding: 10px 16px;
border-left: 1px dashed #d9d9d9;
text-align: center;
white-space: nowrap;
vertical-align: middle;
}
.td:first-child {
@@ -233,7 +235,7 @@ export default defineComponent({
}
:deep(.ant-input) {
width: 132px;
width: 100%;
height: 28px;
border-radius: 4px;
border: 1px solid #dfe0e3;
@@ -242,6 +244,7 @@ export default defineComponent({
.mob-matrix {
.table .tr .td {
min-width: 120px;
max-width: 120px;
}
}
</style>

View File

@@ -101,7 +101,6 @@ export default {
border-color: #fff !important;
}
:deep(*) {
color: #fff !important;
}
td{
padding: 5px;

View File

@@ -1,5 +1,14 @@
<template>
<AnswerViewerMatrix :isMobile="isMobile" :config="config" :stem="stem" :answerSurveySn="answerSurveySn" :answerSn="answerSn" :question="question" :row="row" :col="col">
<AnswerViewerMatrix
:isMobile="isMobile"
:config="config"
:stem="stem"
:answerSurveySn="answerSurveySn"
:answerSn="answerSn"
:question="question"
:row="row"
:col="col"
>
<div class="matrix scrollbar" :class="isMobile ? 'mob-matrix' : ''">
<table class="table">
<!-- 表头 -->
@@ -47,20 +56,20 @@
</table>
</div>
<template v-slot:page="{ rowIndex }">
<MatrixRadioPage :row="row" :col="col" :rowIndex="rowIndex"/>
<MatrixRadioPage :row="row" :col="col" :rowIndex="rowIndex" />
</template>
</AnswerViewerMatrix>
</AnswerViewerMatrix>
</template>
<script>
import { defineComponent, ref, watch } from "vue";
import AnswerViewerMatrix from "../components/AnswerViewerMatrix";
import MatrixRadioPage from "./MatrixRadioPage"
import MatrixRadioPage from "./MatrixRadioPage";
export default defineComponent({
components: {
AnswerViewerMatrix,
MatrixRadioPage
MatrixRadioPage,
},
props: {
// 题干
@@ -96,15 +105,15 @@ export default defineComponent({
// 样本SN
answerSn: {
type: String,
default: ""
default: "",
},
answerSurveySn: {
type: String,
default: ""
default: "",
},
question: {
type: Object,
default: () => ({})
default: () => ({}),
},
},
setup(props, context) {
@@ -219,10 +228,11 @@ export default defineComponent({
.td {
min-width: 150px;
max-width: 150px;
padding: 10px 16px;
border-left: 1px dashed #d9d9d9;
text-align: center;
white-space: nowrap;
vertical-align: middle;
}
.td:first-child {
@@ -239,6 +249,7 @@ export default defineComponent({
.mob-matrix {
.table .tr .td {
min-width: 120px;
max-width: 120px;
}
}
</style>

View File

@@ -0,0 +1,182 @@
<template>
<div class="matrix scrollbar" :class="isMobile ? 'mob-matrix' : ''">
<table class="table">
<a-radio-group
v-model:value="rowItem.value"
@change="updateAnswer"
:disabled="disabled"
v-for="(rowItem, rowIndex) in row"
:key="rowItem.option_key"
>
<!-- 标题 -->
<div class="title" :class="'answer-background10'">
<div class="answer-color" v-html="rowItem.option" />
</div>
<!-- 表头 -->
<tr class="tr">
<td class="td scrollbar" v-for="colItem in col" :key="colItem.option_key">
<div class="answer-color" v-html="colItem.option" />
</td>
</tr>
<!-- 选择 -->
<tr class="tr">
<td class="td" v-for="(colItem, colIndex) in col" :key="colItem.option_key">
<a-radio
:value="colItem.option_key"
:disabled="isDisabled(rowItem.option_key, colItem.option_key, rowIndex, colIndex)"
/>
</td>
</tr>
</a-radio-group>
</table>
</div>
</template>
<script>
import { defineComponent, ref, watch } from "vue";
export default defineComponent({
props: {
// 列表
list: {
type: Array,
default: () => [],
},
// 配置
config: {
type: Object,
default: () => {},
},
// 答案
answer: {
type: Object,
default: () => {},
},
// 是否禁用
disabled: {
type: Boolean,
default: false,
},
// 是否移动端
isMobile: {
type: Boolean,
default: false,
},
},
setup(props, context) {
// 选项
const row = ref([]); // 行标签
const col = ref([]); // 列标签
// 初始化
function init() {
props.list.forEach((list) => {
if (list.type === 1) {
row.value = [...row.value, ...list.options];
} else if (list.type === 2) {
col.value = [...col.value, ...list.options];
}
});
if (props.answer) {
const obj = {};
Object.keys(props.answer).forEach((key) => {
obj[key.split("_")[0]] = key.split("_")[1];
});
row.value.forEach((rowItem) => {
rowItem.value = obj[rowItem.option_key];
});
updateAnswer();
}
}
init();
// 选择回调
function updateAnswer() {
const answer = {};
const index = row.value.findIndex((rowItem) => {
if (rowItem.value) {
answer[`${rowItem.option_key}_${rowItem.value}`] = 1;
}
return !rowItem.value;
});
// 更新答案
if (index === -1 || !props.config?.is_required) {
context.emit("update:answer", answer);
} else {
context.emit("update:answer", null);
}
}
// 是否禁用选项
function isDisabled(rowKey, colKey, rowIndex, colIndex) {
// 快捷评价
if (props.config.is_quick === 0) {
if ((rowIndex === 0 && colIndex < 2) || (rowIndex === 1 && colIndex > 2)) {
return true;
}
}
const index = (props.config?.disabled || []).findIndex(
(item) => item.row_key === rowKey && item.cell_key === colKey
);
return index === -1 ? false : true;
}
return { row, col, updateAnswer, isDisabled };
},
});
</script>
<style lang="scss" scoped>
.matrix {
overflow-x: auto;
overflow-y: hidden;
padding-bottom: 10px;
.table {
border-radius: 4px 4px 0 0;
.title {
padding: 12px 40px;
border-radius: 4px;
margin-top: 16px;
}
.tr {
display: table-row;
.td {
padding: 10px 48px 0;
text-align: center;
white-space: nowrap;
}
}
}
}
.mob-matrix {
.table {
.title {
padding: 12px 20px;
margin-top: 10px;
font-size: 12px;
}
.tr {
display: flex;
.td {
flex: 1;
padding: 10px 0 0;
font-size: 12px;
}
}
}
.ant-radio-group {
width: 100%;
}
}
:deep(.ant-radio-disabled) {
opacity: 0.5;
}
</style>

View File

@@ -54,6 +54,5 @@ export default {
border-color: #fff !important;
}
:deep(*) {
color: #fff !important;
}
</style>

View File

@@ -202,6 +202,10 @@ export default defineComponent({
border-left: 1px dashed #d9d9d9;
text-align: center;
white-space: nowrap;
.answer-color {
white-space: normal !important;
}
}
.td:first-child {

View File

@@ -1,5 +1,7 @@
<template>
<div @touchstart="handleSign">
<signature :url="url" @save="save" :disabled="disabled" />
</div>
</template>
<script>
@@ -43,7 +45,14 @@ export default defineComponent({
message.success("上传成功");
}
return { url, save };
// 签名题开始触摸事件
function handleSign() {
console.log('签名题开始触摸事件');
const activeElement = document.activeElement;
activeElement.blur();
}
return { url, save, handleSign };
},
});
</script>

View File

@@ -57,11 +57,26 @@ export default defineComponent({
// 选项
const options = ref([]);
// js加法
function addNum(arg1, arg2) {
(arg1 = arg1.toString()), (arg2 = arg2.toString());
var arg1Arr = arg1.split("."),
arg2Arr = arg2.split("."),
d1 = arg1Arr.length == 2 ? arg1Arr[1] : "",
d2 = arg2Arr.length == 2 ? arg2Arr[1] : "";
var maxLen = Math.max(d1.length, d2.length);
var m = Math.pow(10, maxLen);
var result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen));
var d = arguments[2];
return typeof d === "number" ? Number(result.toFixed(d)) : result;
}
// 计算总和
const sum = computed(() => {
let a = 0;
options.value.forEach((option) => {
a += option.value * 1 || 0;
// a += option.value * 1 || 0;
a = addNum(a, option.value * 1 || 0);
});
return a;
});

View File

@@ -13,6 +13,7 @@
:type="3"
:questionIndex="questionIndex"
v-if="!isAnswer"
style="margin-bottom: 22px;"
/>
</div>
<div v-if="error && questionType <= 100" class="error">{{ error }}</div>

View File

@@ -1,8 +1,9 @@
<template>
<div>
<!-- 错误 -->
<div v-if="error" class="error">{{ error }}</div>
<!-- -->
<div class="kano" v-for="item in questions" :key="item">
<div class="kano" v-show="index + 1 === page" v-for="(item, index) in questions" :key="index">
<div class="question-wrapper">
<div class="title answer-color" v-html="item.stem" />
<Remark
@@ -12,23 +13,52 @@
v-if="!isAnswer"
/>
</div>
<matrix-radio
<matrix-radio-kano
:list="item.list"
:config="config"
:disabled="disabled"
v-model:answer="item.answer"
@update:answer="changeValue"
:isMobile="isMobile"
/>
</div>
<!-- 分页-mob -->
<div v-if="isMobile" class="footer">
<pfe-pagination
:min="0"
:page="page"
:pages="questions.length + 1"
submitText="下一页"
:loading="loading"
showPrevious
@previous="previous"
@next="next"
isMobile
/>
</div>
<!-- 分页-pc -->
<pfe-pagination
v-else
:min="0"
:page="page"
:pages="questions.length + 1"
submitText="下一页"
:loading="loading"
showPrevious
@previous="previous"
@next="next"
/>
</div>
</template>
<script>
import { defineComponent, ref } from "vue";
import MatrixRadio from "../QMatrix/MatrixRadio.vue";
import PfePagination from "@/components/PfePagination.vue";
import MatrixRadioKano from "../QMatrix/MatrixRadioKano.vue";
import Remark from "@/views/Answer/components/Remark";
import { message } from "ant-design-vue";
export default defineComponent({
components: { MatrixRadio, Remark },
components: { PfePagination, MatrixRadioKano, Remark },
props: {
// 错误
error: {
@@ -60,6 +90,10 @@ export default defineComponent({
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
// 是否作答模式
isAnswer: {
type: Boolean,
@@ -76,6 +110,7 @@ export default defineComponent({
},
},
setup(props, context) {
const page = ref(1);
const list = ref([]); // 矩阵列表
const questions = ref([]); // 问题列表
@@ -95,7 +130,7 @@ export default defineComponent({
init();
// 选择回调
function changeValue() {
function updateAnswer() {
// 更新答案
const answer = questions.value.map((question, task) =>
question.answer
@@ -109,6 +144,31 @@ export default defineComponent({
if (index === -1) {
context.emit("update:answer", answer);
}
context.emit("next");
}
// 上一页
function previous() {
if (page.value === 1) {
return context.emit("previous");
}
page.value -= 1;
context.emit("toTop");
}
// 下一页
function next() {
// 当前页没有选择
if (props.config.is_required && !questions.value[page.value - 1].answer) {
return message.error("请选择");
}
// 最后一页
if (page.value === questions.value.length) {
return updateAnswer();
}
// 下一页
page.value += 1;
context.emit("toTop");
}
// 设置list
@@ -155,7 +215,7 @@ export default defineComponent({
];
}
return { list, questions, changeValue };
return { page, list, questions, updateAnswer, previous, next };
},
});
</script>
@@ -166,6 +226,7 @@ export default defineComponent({
align-items: center;
justify-content: space-between;
}
.error {
font-size: 12px;
color: #ff374f;
@@ -177,7 +238,19 @@ export default defineComponent({
margin-bottom: 40px;
.title {
margin-bottom: 24px;
margin-bottom: 8px;
}
}
.pagination {
margin-top: 72px;
}
.footer {
// left: 0;
// bottom: 0;
// width: 100%;
// position: absolute;
// padding: 20px 0;
}
</style>

View File

@@ -320,12 +320,12 @@ export default defineComponent({
// 下一页
function next() {
// 作答模式下不进行选择判断
if (!props.isAnswer) {
if (page.value === pages.value) {
return context.emit("next");
}
return (page.value += 1);
}
// if (!props.isAnswer) {
// if (page.value === pages.value) {
// return context.emit("next");
// }
// return (page.value += 1);
// }
// 当前页答案
const currentOptions = allOptions.value[page.value - 1];
if (currentOptions.findIndex((option) => option.value === "b") === -1) {

View File

@@ -9,8 +9,7 @@
<i class="iconfont">&#xe72b;</i>
</a-tooltip>
</div>
<Remark :title="label+'问题评论'" :type="3" :questionIndex="questionIndex" v-if="!isAnswer"/>
<Remark :title="label + '问题评论'" :type="3" :questionIndex="questionIndex" v-if="!isAnswer" />
</div>
<!-- 错误 -->
<div v-if="error" class="error">{{ error }}</div>
@@ -77,11 +76,8 @@
<!-- 问题 -->
<div class="title answer-color">{{ title }}_{{ index + 1 }}{{ item.title }}</div>
<!-- 打分 -->
<div :style="`width: ${(Object.keys(marks).length / 15) * 1000}px;padding-left:14px;`">
<a-slider
:min="config.min"
:max="config.max"
:step="null"
<div>
<slider
:marks="marks"
v-model:value="item.value"
@afterChange="changeValue($event, item, index)"
@@ -97,6 +93,7 @@
import { message } from "ant-design-vue";
import { computed, defineComponent, ref } from "vue";
import Remark from "@/views/Answer/components/Remark";
import Slider from "@/components/Slider";
export default defineComponent({
props: {
@@ -142,17 +139,17 @@ export default defineComponent({
// 题号
questionIndex: {
type: [String, Number],
default: ''
default: "",
},
// 题干
label: {
type: String,
default: ''
}
default: "",
},
components: { Remark },
},
components: { Remark, Slider },
setup(props, context) {
const marks = ref({}); // 刻度标记
const marks = ref([]); // 刻度标记
const questions = ref([]); // 问题列表
const valueArr = computed(() =>
@@ -162,14 +159,15 @@ export default defineComponent({
// 初始化
function init() {
// 设置刻度标记
props.config.price_gradient.forEach((item) => {
marks.value[item] = item;
});
// props.config.price_gradient.forEach((item) => {
// marks.value[item] = item;
// });
marks.value = props.config.price_gradient.map((gradient) => gradient * 1);
// 设置问题列表
questions.value = props.config.text_map.map((question) => ({ title: question }));
if (props.answer) {
questions.value.forEach((question, index) => {
question.value = props.config.price_gradient[props.answer[index + 1] - 1];
question.value = marks.value[props.answer[index + 1] - 1];
});
}
}
@@ -177,6 +175,9 @@ export default defineComponent({
// 滑动回调
function changeValue(value, item, i) {
if (props.disabled) {
return;
}
// 判断
if (i === 4) {
if (value > questions.value[1].value || value < questions.value[2].value) {
@@ -209,9 +210,7 @@ export default defineComponent({
// 更新答案
const answer = {};
const index = questions.value.findIndex((question, index) => {
const priceIndex = props.config.price_gradient.findIndex(
(price) => price === question.value
);
const priceIndex = marks.value.findIndex((price) => price === question.value);
answer[index + 1] = priceIndex + 1;
return question.value === undefined;
});
@@ -241,7 +240,7 @@ export default defineComponent({
justify-content: space-between;
.iconfont {
color: #3461ff;
color: #70b936;
cursor: pointer;
margin-left: 12px;
}
@@ -331,7 +330,7 @@ export default defineComponent({
.slider-group {
.slider-box {
overflow: auto;
overflow-x: auto;
.title {
font-size: 14px;

View File

@@ -7,17 +7,12 @@
* @FilePath: /planet-front-end/src/views/DataAnalyse/bptoAnalog/components/bptoContentMid.vue
-->
<template>
<div class="bptoConInfoTop">
<div class="bptoConInfoTop">
<div class="bptoConInfoLeft">
<a-checkbox
:disabled="props.isFull"
v-model:checked="itemCheck"
:indeterminate="indeterminate"
@change="onCheckAllChange"
>
{{itemData?.title}}
<a-checkbox :disabled="props.isFull" v-model:checked="itemCheck" :indeterminate="indeterminate" @change="onCheckAllChange">
{{ itemData?.title }}
</a-checkbox>
<p>({{itemData?.question_Q}}:需求曲线模拟/单目标)</p>
<p>({{ itemData?.question_Q }}:需求曲线模拟/单目标)</p>
</div>
<div class="bptoConInfoRight">
<a-radio-group v-model:value="cardType" size="small" button-style="solid" @change="changeRadio">
@@ -31,9 +26,9 @@
</div>
<template #overlay>
<a-menu>
<a-menu-item :disabled="itemData.status!=2" @click="getDetil">详情</a-menu-item>
<a-menu-item :disabled="itemData.status!=2" @click="download">下载</a-menu-item>
<a-menu-item v-if="itemData.status!=2" @click="againOper">重新计算</a-menu-item>
<a-menu-item :disabled="itemData.status != 2" @click="getDetil">详情</a-menu-item>
<a-menu-item :disabled="itemData.status != 2" @click="download">下载</a-menu-item>
<a-menu-item v-if="itemData.status != 2" @click="againOper">重新计算</a-menu-item>
<a-menu-item @click="resetName">重命名</a-menu-item>
<a-menu-item class="delClass" @click="delNow">删除</a-menu-item>
</a-menu>
@@ -41,74 +36,74 @@
</a-dropdown>
</div>
</div>
</div>
<div class="bptoConInfoMid">
</div>
<div class="bptoConInfoMid">
<!-- 这是一个echart图表 -->
<component class="bptoMidChart" v-if="itemData.status==2" ref="bptoMidChart" :is="chart" :chartLine="itemData?.linear_chart_data_json" :chartColumn="itemData?.column_chart_data_json" :lineHeader="itemData.target_gradient_json" :cardType="cardType" :avgLine="itemData?.price_avg_price" />
<div class="noChart" v-if="itemData.status!=2">
<component class="bptoMidChart" v-if="itemData.status == 2" ref="bptoMidChart" :is="chart" :chartLine="itemData?.linear_chart_data_json" :chartColumn="itemData?.column_chart_data_json" :lineHeader="itemData.target_gradient_json" :cardType="cardType" :avgLine="itemData?.price_avg_price" />
<div class="noChart" v-if="itemData.status != 2">
<img :src="require('@/assets/img/kano.gif')" />
<p class="countDownBoxDesc">正在进行市场模拟中请您稍后</p>
</div>
<!-- 这是table -->
<div class="bptoConInfoTable">
<a-table :dataSource="itemDataTableData" :columns="itemDataTableColumn" :transformCellText="({ text, column, record, index }) => text||'--.--%'" :pagination="false" :scroll="{ x: (150*itemDataTableColumn.length), y:170 }" >
<a-table :dataSource="itemDataTableData" :columns="itemDataTableColumn" :transformCellText="({ text, column, record, index }) => text || '--.--%'" :pagination="false" :scroll="{ x: 150 * itemDataTableColumn.length, y: 170 }">
<template #count="{ record }">
<div v-if="itemData.status!=2">--.--%</div>
<div v-else>{{record.count}}</div>
<div v-if="itemData.status != 2">--.--%</div>
<div v-else>{{ record.count }}</div>
</template>
<template #head_fir="{ record }">
<div class="headFir" v-html="record.head_fir"></div>
</template>
</a-table>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive,defineProps,defineEmits,watch,onMounted,nextTick } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useStore } from 'vuex';
import { EllipsisOutlined,ExpandOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import chart from './chart.vue';
const router = useRouter();
import { ref, reactive, defineProps, defineEmits, watch, onMounted, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useStore } from 'vuex'
import { EllipsisOutlined, ExpandOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import chart from './chart.vue'
const router = useRouter()
const store = useStore()
// url参数
const query = router.currentRoute.value.query
// 点击全选按钮
const emit = defineEmits(["checkboxClick","delItem"]);
const emit = defineEmits(['checkboxClick', 'delItem'])
const props = defineProps({
// 判断当前是否显示
isFull:{
type:Boolean,
default:false
isFull: {
type: Boolean,
default: false
},
itemData:{
type:Object,
default:()=>{}
itemData: {
type: Object,
default: () => {}
},
index:{
type:Number,
default:-1
index: {
type: Number,
default: -1
},
pagination:{
type:Object,
default:()=>{}
},
allCheckState:{
type:Object,
default:()=>{}
pagination: {
type: Object,
default: () => {}
},
allCheckState: {
type: Object,
default: () => {}
}
})
// 修改格式
const changePerInfo = (data)=>{
const changePerInfo = (data) => {
const newData = JSON.parse(JSON.stringify(data))
let newArr = []
newData.map(el=>{
newData.map((el) => {
const retData = {}
for (const key in el) {
if(typeof el[key]=='number'){
retData[key] = el[key]+'%'
}else{
if (typeof el[key] == 'number') {
retData[key] = el[key] + '%'
} else {
retData[key] = el[key]
}
}
@@ -119,166 +114,181 @@ const changePerInfo = (data)=>{
// 是否选中
const itemCheck = ref(false)
// 图表类型
const cardType= ref(0)
const cardType = ref(0)
const bptoMidChart = ref(null)
// 接受分页参数
watch(()=>cardType.value,nval=>{
watch(
() => cardType.value,
(nval) => {
// 单目标
if(nval===0){
if (nval === 0) {
itemDataTableData.value = changePerInfo(props.itemData.one.dataSource)
itemDataTableColumn.value = [...props.itemData.one.columns]
}
// 下降差
if(nval===1){
if (nval === 1) {
itemDataTableData.value = changePerInfo(props.itemData.decline.dataSource)
itemDataTableColumn.value = [...props.itemData.decline.columns]
}
})
watch(() => store?.state?.bptoData?.fullScreen, nVal => {
if(nVal){
console.log('全屏显示');
}
)
watch(
() => store?.state?.bptoData?.fullScreen,
(nVal) => {
if (nVal) {
console.log('全屏显示')
cardType.value = 0
nextTick(()=>{
nextTick(() => {
bptoMidChart.value.initCharts(0)
bptoMidChart.value.chartResize()
})
}
})
}
)
// table数据
const itemDataTableData = ref([])
// table表头
const itemDataTableColumn = ref([])
// 全屏时候翻页
watch(()=>props.itemData,()=>{
watch(
() => props.itemData,
() => {
itemDataTableData.value = changePerInfo(props.itemData.one.dataSource)
itemDataTableColumn.value = [...props.itemData.one.columns]
cardType.value = 0
nextTick(()=>{
if(bptoMidChart.value){
nextTick(() => {
if (bptoMidChart.value) {
bptoMidChart.value.initCharts(0)
bptoMidChart.value.chartResize()
}
})
}, {
deep:true,
},
{
deep: true,
immediate: true
})
}
)
// 接受分页参数
watch(props.pagination,nval=>{
console.log(nval.value);
watch(props.pagination, (nval) => {
console.log(nval.value)
})
// 接受全选状态
watch(()=>props.allCheckState,nval=>{
console.log(nval.value);
dataList.value.map(el=>el.checked=nval.value.checked)
})
watch(
() => props.allCheckState,
(nval) => {
console.log(nval.value)
dataList.value.map((el) => (el.checked = nval.value.checked))
}
)
// 如果点击一个触发全选的indeterminate
const onCheckAllChange=async e=>{
const onCheckAllChange = async (e) => {
const item = store?.state?.bptoData?.bptoItem
const checkInfo = itemCheck.value
item[props.index].checked =checkInfo
console.log('当前选中',checkInfo,props.index,item);
await store.dispatch('bptoData/saveBptoItem',item)
item[props.index].checked = checkInfo
console.log('当前选中', checkInfo, props.index, item)
await store.dispatch('bptoData/saveBptoItem', item)
}
// 监听全选状态
watch(()=>store?.state?.bptoData?.bptoItem,(nval)=>{
if(props.index>-1&&nval[props.index])itemCheck.value = nval[props.index].checked
}, {
deep:true,
watch(
() => store?.state?.bptoData?.bptoItem,
(nval) => {
if (props.index > -1 && nval[props.index]) itemCheck.value = nval[props.index].checked
},
{
deep: true,
immediate: true
})
}
)
// 查看详情
const getDetil = ()=>{
const getDetil = () => {
const id = props.itemData.id
console.log('查看详情',id);
store.dispatch('bptoData/changeSceneId',id)
store.dispatch('bptoData/changeLookAll',true)
console.log('查看详情', id)
store.dispatch('bptoData/changeSceneId', id)
store.dispatch('bptoData/changeLookAll', true)
}
// 下载
const download = async()=>{
console.log('下载');
const download = async () => {
console.log('下载')
try {
const subData = {
scene_id:props.itemData.id
scene_id: props.itemData.id
}
const {xlsx}= await store.dispatch('bptoData/getSceneDownload',subData)
window.open(xlsx.download_url,"_blank");
const { xlsx } = await store.dispatch('bptoData/getSceneDownload', subData)
window.open(xlsx.download_url, '_blank')
} catch (error) {
console.error(error);
console.error(error)
}
}
// 重新计算
const againOper = async()=>{
const againOper = async () => {
try {
const subData = {
scene_id:props.itemData.id
scene_id: props.itemData.id
}
await store.dispatch('bptoData/putRecalculate',subData)
await store.dispatch('bptoData/putRecalculate', subData)
message.success('计算成功')
emit('delItem')
} catch (error) {
console.error(error);
console.error(error)
}
}
// 重命名
const resetName = ()=>{
console.log('重命名');
const resetName = () => {
console.log('重命名')
const id = props.itemData.id
store.dispatch('bptoData/changeSceneId',id)
store.dispatch('bptoData/changeFullScreenIndex',props.index)
store.dispatch('bptoData/changeResetName',true)
store.dispatch('bptoData/changeSceneId', id)
store.dispatch('bptoData/changeFullScreenIndex', props.index)
store.dispatch('bptoData/changeResetName', true)
}
// 删除
const delNow = ()=>{
console.log('删除');
const delNow = () => {
console.log('删除')
delScene()
}
const delScene =async ()=>{
const delScene = async () => {
try {
const subData = {
scene_id:props.itemData.id,
title:props.itemData.title,
scene_id: props.itemData.id,
title: props.itemData.title
}
await store.dispatch('bptoData/delScene',subData)
await store.dispatch('bptoData/delScene', subData)
emit('delItem')
} catch (error) {
console.error(error);
console.error(error)
}
}
// 翻页监听数据变化
</script>
<style scoped lang='scss'>
.bptoConInfoTop{
<style scoped lang="scss">
.bptoConInfoTop {
display: flex;
justify-content: space-between;
width: 100%;
overflow: hidden;
.bptoConInfoLeft{
.bptoConInfoLeft {
display: flex;
align-items: center;
flex: auto;
overflow: hidden;
&:deep(.ant-checkbox-wrapper){
&:deep(.ant-checkbox-wrapper) {
white-space: nowrap;
// overflow: hidden;
// text-overflow: ellipsis;
}
>p{
> p {
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #8C8C8C;
color: #8c8c8c;
}
}
.bptoConInfoRight{
.bptoConInfoRight {
display: flex;
align-items: center;
flex-shrink: 0;
.icon{
.icon {
cursor: pointer;
margin-left: 16px;
width: 22px;
@@ -291,34 +301,34 @@ const delScene =async ()=>{
}
}
}
.bptoConInfoMid{
flex:1;
.bptoConInfoMid {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
padding-bottom: 16px;
.bptoMidChart{
.bptoMidChart {
flex-shrink: 0;
}
.bptoConInfoTable{
.bptoConInfoTable {
flex: 1;
// overflow: auto;
overflow: hidden;
}
}
.delFont{
.delFont {
color: #ff4d4f;
}
.noChart{
.noChart {
width: 100%;
// height: 220px;
background: #f5f5f5;
margin-bottom: 40px;
margin-top: 20px;
>img{
> img {
width: 100%;
}
.countDownBoxDesc{
.countDownBoxDesc {
font-size: 14px;
font-weight: 600;
color: $yili-default-color;
@@ -328,14 +338,14 @@ const delScene =async ()=>{
margin-top: 20px;
}
}
::v-deep .delClass{
color: #FF3939 !important;
::v-deep .delClass {
color: #ff3939 !important;
}
::v-deep .headFir{
*{
::v-deep .headFir {
* {
margin: 0;
}
img{
img {
width: 100% !important;
height: auto !important;
}

View File

@@ -1,13 +1,13 @@
<template>
<div class="custom-head-cell">
<div class="image-question custom-table-head-img" v-if="[12, 13, 14].includes(question_type)" v-html="content"></div>
<a-popover v-else>
<template #content>
<a-tooltip placement="topLeft" v-else>
<template #title>
<div class="custom-head-preview" v-html="content"></div>
</template>
<div class="custom-head-main">
<!-- 下载题型-->
<div class="file-question" v-if="question_type === 18">
<div class="file-question" v-if="question_type === 18" :style="{width:data.width + 'px'}">
<div class="label">{{ content }}</div>
<a-button size="mini" @click="download">下载全部附件</a-button>
</div>
@@ -15,7 +15,7 @@
<div class="common-text" v-else>{{ content }}</div>
</div>
</a-popover>
</a-tooltip>
<!-- 下载中心 -->
<DownloadCenter v-model:visible="downloadVisible" v-if="downloadVisible"></DownloadCenter>
</div>

View File

@@ -1,22 +1,29 @@
<template>
<a-table
:row-selection="rowSelection"
:rowKey="rowKey"
:type="type"
:columns="customHeaders"
:dataSource="data"
:pagination="pagination"
:scroll="{ x: 1200 }"
@change="handlePageChange"
>
<template
v-for="col in tableHeaders"
:key="col.dataIndex"
#[col.dataIndex]="{ record, text }"
>
<template v-if="col.dataIndex !== 'operation'">
<a-table :row-selection="rowSelection" :rowKey="rowKey" :type="type" :columns="customHeaders" :dataSource="data" :pagination="pagination" :scroll="{ x: 1200 }" @change="handlePageChange">
<template v-for="col in tableHeaders" :key="col.dataIndex" #[col.dataIndex]="{ record, text }">
<!-- 作答类型 -->
<!-- <template v-if="col.dataIndex === 'type'">
<slot name="type" v-bind:record="record">
<span class="show-type show-type-da">作答</span>
</slot>
</template> -->
<template v-if="col.dataIndex === 'is_mark'">
<slot name="is_mark" v-bind:record="record">
<i v-if="record.is_mark == 1" class="icon iconfont show-sign curror" @click="hideSign(record)">&#xe7d6;</i>
<i v-else class="icon iconfont hide-sign curror" @click="showSign(record)">&#xe7d6;</i>
</slot>
</template>
<template v-else-if="col.dataIndex === 'mark_des'">
<slot name="mark_des" v-bind:record="record" v-if="record.is_mark == 1">
<render-table-title :title="text">
<span class="show-mark_des"> {{ record.mark_des }}</span>
</render-table-title>
</slot>
</template>
<template v-else-if="col.dataIndex !== 'operation'">
<render-table-title :title="text"></render-table-title>
</template>
<div v-else>
<slot name="operation" v-bind:record="record"></slot>
</div>
@@ -25,15 +32,17 @@
</template>
<script setup>
import { defineComponent, ref, toRefs, watchEffect, useAttrs,onUnmounted, reactive, useSlots,defineProps } from "vue";
import { useStore } from 'vuex';
import usePagination from "@views/DataAnalyse/composables/usePagination";
import useGeneratorTableColumns from "@views/DataAnalyse/composables/use-generator-table-columns";
import useCustomHeaderTitle from "@views/DataAnalyse/composables/useCustomHeaderTitle";
import RenderTableTitle from "@views/DataAnalyse/components/RenderTableTitle"
import { computed } from "@vue/reactivity";
import { watch } from "fs";
import * as cheerio from 'cheerio';
import { defineComponent, ref, toRefs, watchEffect, useAttrs, onUnmounted, reactive, useSlots, defineProps, createVNode, resolveComponent, h } from 'vue'
import { useStore } from 'vuex'
import usePagination from '@views/DataAnalyse/composables/usePagination'
import useGeneratorTableColumns from '@views/DataAnalyse/composables/use-generator-table-columns'
import useCustomHeaderTitle from '@views/DataAnalyse/composables/useCustomHeaderTitle'
import RenderTableTitle from '@views/DataAnalyse/components/RenderTableTitle'
import { computed } from '@vue/reactivity'
import { watch } from 'fs'
import * as cheerio from 'cheerio'
import { Input, Modal } from 'ant-design-vue'
const props = defineProps({
type: {
type: Number
@@ -87,21 +96,20 @@ const props = defineProps({
type: String,
default: ''
}
}
)
const emit = defineEmits(['change','select'])
})
const emit = defineEmits(['change', 'select'])
const store = useStore()
const data = ref([]);
const columns = ref(null);
const { perPage: per_page, total,page,rowKey } = toRefs(props);
const { pagination } = usePagination(per_page, total,page);
const { tableHeaders } = useGeneratorTableColumns(columns);
const { customHeaders } = useCustomHeaderTitle(tableHeaders, props.sn, props.params);
console.log('tableHeaders',tableHeaders);
const data = ref([])
const columns = ref(null)
const { perPage: per_page, total, page, rowKey } = toRefs(props)
const { pagination } = usePagination(per_page, total, page)
const { tableHeaders } = useGeneratorTableColumns(columns)
const { customHeaders } = useCustomHeaderTitle(tableHeaders, props.sn, props.params)
console.log('tableHeaders', tableHeaders)
// 页码&分页条数,改变时候触发
const handlePageChange =(data)=> {
const handlePageChange = (data) => {
const { pageSize, current } = data
store.dispatch('dataFilter/selectKeys',[])
store.dispatch('dataFilter/selectKeys', [])
emit('select', [])
emit('change', {
pageSize,
@@ -109,35 +117,80 @@ const handlePageChange =(data)=> {
})
}
//
const selectKeys = computed(()=>store.state.dataFilter.selectKeys)
const selectList = computed(()=>store.state.dataFilter.selectKeys)
const selectKeys = computed(() => store.state.dataFilter.selectKeys)
const selectIds = computed(() => store.state.dataFilter.answer_sn)
const selectList = computed(() => store.state.dataFilter.selectKeys)
const rowSelection = {
selectedRowKeys:selectList,
selectedRowKeys: selectList,
onChange: (selectedRowKeys, selectedRows) => {
console.log(selectedRowKeys,selectedRows);
const keys = selectedRows.map(el=>el.newSn)
store.dispatch('dataFilter/selectKeys',keys)
},
};
onUnmounted(()=>{
store.dispatch('dataFilter/selectKeys',[])
console.log(selectedRowKeys, selectedRows)
const keys = selectedRows.map((el) => el.newSn)
const ids = selectedRows.map((el) => el.answer_sn)
store.dispatch('dataFilter/selectKeys', keys)
store.dispatch('dataFilter/selectIds', ids)
}
}
onUnmounted(() => {
store.dispatch('dataFilter/selectIds', [])
store.dispatch('dataFilter/selectKeys', [])
})
watchEffect(() => {
const tableSource =JSON.parse(JSON.stringify(props.tableSource))
const tableSource = JSON.parse(JSON.stringify(props.tableSource))
// 去除标签
tableSource.map(el=>{
tableSource.map((el) => {
for (const key in el) {
const $ = cheerio.load(el[key]+'')
console.log('el[key]',el[key]);
if((el[key]+'').indexOf('<img')>-1){
const $ = cheerio.load(el[key] + '')
if ((el[key] + '').indexOf('<img') > -1) {
el[key] = $.html()
}else{
} else {
el[key] = $.text()
}
}
})
data.value = tableSource
columns.value = props.tableColumns;
columns.value = props.tableColumns
})
});
const showSign = (item) => {
emit('sign', [item], true)
}
const hideSign = (item) => {
emit('sign', [item], false)
}
</script>
<style lang="scss" scoped>
.show-type {
display: block;
width: auto;
padding: 0 5px;
width: 42px;
height: 22px;
line-height: 22px;
border-radius: 4px 4px 4px 4px;
opacity: 1;
font-size: 12px;
font-family: PingFang SC-常规体, PingFang SC;
font-weight: normal;
}
.show-type-da {
background: rgba(50, 176, 246, 0.2);
color: #32b0f6;
}
.show-sign {
color: #70b936;
}
.curror {
cursor: pointer;
}
.hide-sign {
cursor: pointer;
color: #bfbfbf;
}
.show-mark_des {
display: inline-block;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>

View File

@@ -4,12 +4,12 @@
<div class="custom-table-head-img-wrapper" v-html="title"></div>
</div>
<div v-else>
<a-popover>
<template #content>
<a-tooltip placement="topLeft">
<template #title>
<div class="diagram-preview" v-html="title"></div>
</template>
<div class="common-text">{{ title }}</div>
</a-popover>
</a-tooltip>
</div>
</div>
</template>

View File

@@ -38,7 +38,7 @@ export default defineComponent({
position: absolute;
left: 0;
bottom: 0;
top: 42%;
top: 48%;
display: block;
content: '';
width: 4px;

View File

@@ -0,0 +1,9 @@
import request from '@/utils/request'
/* 同步数据 */
export function syncProductTest(sn) {
return request({
url: `/console/surveys/${sn}/sync_product_test`,
method: 'POST',
})
}

View File

@@ -1,5 +1,5 @@
<template>
<div class='content'>
<div class="content">
<!-- <a-select
:getPopupContainer="triggerNode=>triggerNode.parentNode"
class="searchSelect operChd"
@@ -11,35 +11,36 @@
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="">
</template>
</a-select> -->
<a-dropdown class="searchSelect operChd" :getPopupContainer="triggerNode=>triggerNode.parentNode">
<a-dropdown class="searchSelect operChd" :getPopupContainer="(triggerNode) => triggerNode.parentNode">
<template #overlay>
<a-menu @click="opChange">
<a-menu-item v-for="(item) in opList" :key="item.value">
{{item.label}}
<a-menu-item v-for="item in opList" :key="item.value">
{{ item.label }}
</a-menu-item>
</a-menu>
</template>
<a-button class="custom-button">
批量操作
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="">
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="" />
</a-button>
</a-dropdown>
<a-button class="operChd custom-button" @click="emit('cleanAllBtn',true)">清空数据</a-button>
<a-button class="operChd custom-button" @click="emit('cleanAllBtn', true)">清空数据</a-button>
<!-- <a-button class="operChd" @click="handleDownload">下载全部答卷</a-button> -->
<a-dropdown class="searchSelect operChd" :getPopupContainer="triggerNode=>triggerNode.parentNode">
<!-- <a-dropdown class="searchSelect operChd" :getPopupContainer="(triggerNode) => triggerNode.parentNode">
<template #overlay>
<a-menu @click="dataChange">
<a-menu-item v-for="(item) in dataList" :key="item.value">
{{item.label}}
<a-menu-item v-for="item in dataList" :key="item.value">
{{ item.label }}
</a-menu-item>
</a-menu>
</template>
<a-button type="primary">
<a-button type="primary" class="custom-button">
数据管理
<!-- <img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt=""> -->
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="">
<CaretDownOutlined class="suffix-icon" />
</a-button>
</a-dropdown>
</a-dropdown> -->
<a-button type="primary" class="operChd custom-button" @click="dataChange({ key: 2 })">全量数据导出</a-button>
<!-- <a-select
:getPopupContainer="triggerNode=>triggerNode.parentNode"
class="searchSelect operChd"
@@ -50,138 +51,163 @@
<img class="suffix-icon" :src="require('@/assets/img/select-arrow-down.png')" alt="">
</template>
</a-select> -->
<a-button type="primary" class="operChd" @click="configVisible=true">列表配置</a-button>
<a-button type="primary" class="operChd custom-button" @click="noData">无效样本处理</a-button>
<a-button type="primary" class="operChd custom-button" @click="configVisible = true">列表配置</a-button>
<!-- 同步数据 -->
<a-tooltip :overlayStyle="{'max-width': 'none'}">
<template v-slot:title>
产品测试模块会同步该列表数据并作统计展示
</template>
<a-button
v-if="template_type === 100 || template_type === 101"
type="primary"
class="operChd custom-button"
@click="syncData"
:loading="syncDataLoading"
>
{{ other_send_status ? "更新数据" : "同步数据" }}
</a-button>
</a-tooltip>
</div>
<!-- 配置 -->
<ColumnConfig
v-model:visible="configVisible"
:data="answer_columns"
:sn="sn"
@ok="handleConfig"
/>
<ColumnConfig v-model:visible="configVisible" :data="answer_columns" :sn="sn" @ok="handleConfig" />
<!-- 导出 -->
<DownloadData
v-model:visible="downloadVisible"
:params="queryState"
:sn="sn"
:sns="selectedSns"
@ok="handleDownload"
/>
<DownloadData v-model:visible="downloadVisible" :params="queryState" :sn="sn" :sns="selectedSns" @ok="handleDownload" />
<!-- 下载中心 -->
<DownloadCenter v-model:visible="downloadCenterVisible" v-if="downloadCenterVisible"></DownloadCenter>
</template>
<script setup>
import { ref, toRefs, reactive,defineProps,watch,onMounted , computed ,nextTick} from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useStore } from 'vuex';
import { message } from 'ant-design-vue';
import ColumnConfig from "./../../particulars/components/ColumnConfig";
import DownloadData from "./../../particulars/components/DownloadData";
import { addDownloadCenter } from "@/api/download.js";
import DownloadCenter from "@/views/DownloadCenter/index.vue"
import { CaretDownOutlined } from '@ant-design/icons-vue';
import { Modal } from 'ant-design-vue';
const props = defineProps({
answer_columns:{
type:Array,
default:()=>[]
</template>
<script setup>
import { ref, toRefs, reactive, defineProps, watch, onMounted, computed, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useStore } from 'vuex'
import { message } from 'ant-design-vue'
import ColumnConfig from './../../particulars/components/ColumnConfig'
import DownloadData from './../../particulars/components/DownloadData'
import { addDownloadCenter } from '@/api/download.js'
import { syncProductTest } from './api'
import DownloadCenter from '@/views/DownloadCenter/index.vue'
import { CaretDownOutlined } from '@ant-design/icons-vue'
import { Modal } from 'ant-design-vue'
const props = defineProps({
answer_columns: {
type: Array,
default: () => []
},
selectedSns:{}
})
const store = useStore()
const {selectedSns} = toRefs(props)
const answer_columns = computed(()=>props.answer_columns)
console.log('==========answer_columns',answer_columns.value);
const emit = defineEmits()
const route = useRoute()
const router = useRouter()
const sn = computed(() => route.query.sn)
const searchData = ref({
test1:null,
test2:null
})
const opList = ref([
{value:'0',label:'下载答卷'},
{value:'1',label:'导出数据'},
{value:'2',label:'删除'}
])
// 导出选中答卷
const opChange = (e)=>{
const {key} = e
console.log(key);
if(selectKeys.value.length===0){
message.error('请选择需要操作的数据');
selectedSns: {},
template_type: {},
other_send_status: {},
})
const store = useStore()
const { selectedSns } = toRefs(props)
const answer_columns = computed(() => props.answer_columns)
console.log('==========answer_columns', answer_columns.value)
const emit = defineEmits()
const route = useRoute()
const router = useRouter()
const sn = computed(() => route.query.sn)
const searchData = ref({
test1: null,
test2: null
})
const opList = ref([
{ value: '3', label: '标记' },
{ value: '4', label: '取消标记' },
{ value: '0', label: '下载答卷' },
{ value: '1', label: '导出数据' },
{ value: '2', label: '删除' }
])
const syncDataLoading = ref(false);
// 导出选中答卷
const opChange = (e) => {
const { key } = e
console.log(key)
if (selectKeys.value.length === 0) {
message.error('请选择需要操作的数据')
return
}
if(key=='0'){
if (key == '0') {
getSurveysAnswersExport()
}
if(key=='1'){
if (key == '1') {
// getSurveysAnswersDown()
emit('dataExport',1)
emit('dataExport', 1)
}
if(key=='2'){
if (key == '2') {
// delSurveysAnswers()
emit('delFn')
}
if (key == '3') {
// delSurveysAnswers()
emit('sign', undefined, true)
}
const dataList = ref([
if (key == '4') {
// delSurveysAnswers()
emit('sign', undefined, false)
}
}
const dataList = ref([
// {value:'0',label:'添加数据'},
// {value:'1',label:'导入数据'},
{value:'2',label:'导出数据'},
])
// 添加数据 导入数据 导出数据
const dataChange = (e)=>{
const {key} = e
console.log(key);
if(key=='0'){
// { value: '1', label: '导入数据' }
{ value: '2', label: '导出数据' }
])
// 添加数据 导入数据 导出数据
const dataChange = (e) => {
const { key } = e
console.log(key)
if (key == '0') {
getSurveysAnswersDown()
}
if(key=='1'){
if (key == '1') {
emit('dataImport')
}
if(key=='2'){
emit('dataExport',0)
if (key == '2') {
emit('dataExport', 0)
}
}
// 配置列表
const configVisible = ref(false);
const handleConfig =()=> {
}
// 配置列表
const configVisible = ref(false)
const handleConfig = () => {
emit('configOk')
}
}
// 导出
const downloadVisible = ref(false);
const downloadCenterVisible = ref(false)
const queryState = ref({})
const handleDownload = ()=>{
// 导出
const downloadVisible = ref(false)
const downloadCenterVisible = ref(false)
const queryState = ref({})
const handleDownload = () => {
emit('downloadOk')
}
const selectKeys = computed(()=>store.state.dataFilter.selectKeys)
// 导出
const getSurveysAnswersExport = async()=>{
}
const selectKeys = computed(() => store.state.dataFilter.selectKeys)
// 导出
const getSurveysAnswersExport = async () => {
try {
const subData = {
sn:sn.value,
sns:selectKeys.value.join()
sn: sn.value,
sns: selectKeys.value.join()
}
if(selectKeys.value.length==1) {
const res =await store.dispatch('dataFilter/getSurveysAnswersExport',subData)
if (selectKeys.value.length == 1) {
const res = await store.dispatch('dataFilter/getSurveysAnswersExport', subData)
// download(res.data.download_url)
// console.log('getSurveysAnswersExport',res);
const {title,url} = res.data.download_url;
const { title, url } = res.data.download_url
const subdata = {
fileURL:url,
fileName:title
fileURL: url,
fileName: title
}
store.dispatch('common/fileDown',subdata)
}else{
let data ={ download_type: '2', sns:selectKeys.value.join()}
addDownloadCenter(sn.value,data).then(res=>{
store.dispatch('dataFilter/selectIds', [])
store.dispatch('dataFilter/selectKeys', [])
store.dispatch('common/fileDown', subdata)
} else {
let data = { download_type: '2', sns: selectKeys.value.join() }
addDownloadCenter(sn.value, data).then((res) => {
// 下载中心
store.dispatch('downloadCenter/changeCenterUrl',route.path)
store.dispatch('downloadCenter/changeCenterUrl', route.path)
// downloadCenterVisible.value = true
store.dispatch('downloadCenter/changeCenterShow',true)
store.dispatch('downloadCenter/changeCenterShow', true)
store.dispatch('dataFilter/selectIds', [])
store.dispatch('dataFilter/selectKeys', [])
// router.push({
// path: "/downloadCenter",
// query: { path:route.path,sn:sn.value },
@@ -189,68 +215,89 @@
})
}
} catch (error) {
console.error(error);
console.error(error)
}
}
// 下载
const dataFilterInfo = computed(()=>store.state.dataFilter.dataFilterInfo)
const getSurveysAnswersDown = async()=>{
}
// 下载
const dataFilterInfo = computed(() => store.state.dataFilter.dataFilterInfo)
const getSurveysAnswersDown = async () => {
try {
const subData = {
...dataFilterInfo.value,
sn:sn.value,
sns:selectKeys.value.join(),
sn: sn.value,
sns: selectKeys.value.join()
}
const res =await store.dispatch('dataFilter/getSurveysAnswersDown',subData)
const res = await store.dispatch('dataFilter/getSurveysAnswersDown', subData)
download(res.data.download_url)
console.log('getSurveysAnswersDown',res);
console.log('getSurveysAnswersDown', res)
} catch (error) {
console.error(error);
console.error(error)
}
}
// 删除
const delSurveysAnswers = async (flag)=>{
}
// 删除
const delSurveysAnswers = async (flag) => {
try {
const subData = {
sn:sn.value,
sn: sn.value
}
if(!flag)subData.sns = selectKeys.value.join()
if (!flag) subData.sns = selectKeys.value.join()
else subData.full = 1
const res =await store.dispatch('dataFilter/delSurveysAnswers',subData)
store.dispatch('dataFilter/selectKeys',[])
const res = await store.dispatch('dataFilter/delSurveysAnswers', subData)
store.dispatch('dataFilter/selectKeys', [])
emit('delOk')
} catch (error) {
console.error(error);
console.error(error)
}
}
const download = (data)=>{
}
const download = (data) => {
const url = data
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接
a.click(); // 自执行点击事件
const a = document.createElement('a') // 创建a标签
a.setAttribute('download', '') // download属性
a.setAttribute('href', url) // href链接
a.click() // 自执行点击事件
}
const noData = () => {
emit('noData')
}
// 同步数据
async function syncData() {
syncDataLoading.value = true;
try {
await syncProductTest(sn.value);
if (props.other_send_status) {
return message.success("同步成功,您还需在产品测试模块导入该问卷哦~");
}
defineExpose({delSurveysAnswers})
</script>
<style scoped lang='scss'>
.content{
message.success("同步成功!");
emit("update:other_send_status", 1);
} catch (error) {
console.error("同步数据错误", error);
}
syncDataLoading.value = false;
}
defineExpose({ delSurveysAnswers })
</script>
<style scoped lang="scss">
.content {
display: flex;
align-items: center;
height: 80px;
}
.searchSelect{
}
.searchSelect {
width: 110px;
display: flex;
justify-content: space-between;
align-items: center;
}
.operChd:not(:first-child){
}
.operChd:not(:first-child) {
margin-left: 14px;
}
.suffix-icon{
}
.suffix-icon {
position: relative;
z-index: 2;
width: auto;
height: 12px;
}
</style>
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,14 @@
import { ref, watch } from 'vue'
const defaultOptions = {
left_fixed_key: 'id',// 左侧固定列
left_fixed_key: 'id', // 左侧固定列
right_fixed_key: 'operation', //右侧固定列
show_operator: true, // 是否显示操作列
show_check: true,
fixed: 'left'
}
/**
/**
* 是否为特殊题型,特指图文题、上传题
*/
@@ -15,41 +17,81 @@ function includeSpecialType(type) {
}
export default function useGeneratorTableColumns(columns, options = {}) {
options = {...defaultOptions, ...options}
// debugger
options = { ...defaultOptions, ...options }
const tableHeaders = ref([])
function flatData(columns) {
let columnsSing = {}
let columnsType = {}
let columnsMemo = {}
if (options.show_check) {
columnsSing = {
title: '',
key: 'is_mark',
dataIndex: 'is_mark',
align: 'center',
width: 50,
slots: { customRender: 'is_mark' },
fixed: 'left'
}
// columnsType = {
// title: '数据类型',
// key: 'type',
// dataIndex: 'type',
// align: 'center',
// width: 100,
// slots: { customRender: 'type' },
// fixed: 'left'
// }
columnsMemo = {
title: '标记原因',
key: 'mark_des',
dataIndex: 'mark_des',
align: 'center',
width: 150,
slots: { customRender: 'mark_des' },
fixed: 'left'
}
}
let result = columns.reduce((previousValue, currentValue) => {
const arr = Object.entries(currentValue).map(([key, value]) => ({
...value,
key,
dataIndex: key,
width: key === options.left_fixed_key? 100: includeSpecialType(value.question_type) ? 300 : 200,
fixed: key === options.left_fixed_key ? 'left': null,
align: 'center',
slots: {customRender: key },
}));
return previousValue.concat(arr);
}, []);
width: key === options.left_fixed_key ? 100 : includeSpecialType(value.question_type) ? 300 : 200,
fixed: key === options.fixed,
// align: 'center',
slots: { customRender: key }
}))
return previousValue.concat(arr)
}, [])
// 手动修改作答ID数组位置
const snData = result.find(el=>el.key =='id')
result = result.filter(el=>el.key!='id')
if(snData)result.unshift(snData)
if(options.show_operator) {
const snData = result.find((el) => el.key == 'id')
result = result.filter((el) => el.key != 'id')
result.unshift(columnsMemo)
result.unshift(columnsType)
if (snData) {
snData.fixed = 'left'
result.unshift(snData)
}
result.unshift(columnsSing)
if (options.show_operator) {
result.push({
title: '操作',
key: 'operation',
dataIndex: 'operation',
width: 130,
slots: {customRender: "operation" },
fixed: 'right',
width: 120,
slots: { customRender: 'operation' },
fixed: 'right'
})
}
return result
}
watch(columns, (data) => {
if(data) {
tableHeaders.value = flatData(data);
if (data) {
tableHeaders.value = flatData(data)
}
})
return { columns, tableHeaders};
return { columns, tableHeaders }
}

View File

@@ -1,6 +1,7 @@
import { ref, watch } from "vue";
import CustomTableHeaderCell from '@/views/DataAnalyse/components/CustomTableHeaderCell'
export default function renderCustomHeader(columns, sn ,search_params) {
const customHeaders = ref([])
function renderCell(data, sn, search_params) {

Some files were not shown because too many files have changed in this diff Show More