feat: 皮肤设置 (#78)

This commit is contained in:
dayou 2024-03-22 17:51:32 +08:00 committed by sudoooooo
parent 90243b9875
commit 968576b665
59 changed files with 1218 additions and 405 deletions

View File

@ -1,12 +1,64 @@
{ {
"temp": { "temp": {
"key": "default", "key": "default",
"name": "默认分类", "name": "全部",
"list": [{ "list": [{
"src": "/imgs/skin/17e06b7604a007e1d3e1453b9ddadc3c.webp", "src": "/imgs/skin/17e06b7604a007e1d3e1453b9ddadc3c.webp",
"title": "1" "title": "1"
}] }]
}, },
"scenery": {
"key": "scenery",
"name": "风景",
"list": [{
"src": "/imgs/skin/SyiLRcukyE1558430525760.webp",
"title": "1"
}, {
"src": "/imgs/skin/sqYig4AcWr1558430525663.webp",
"title": "2"
}, {
"src": "/imgs/skin/ElNeqJT2I21558430526165.webp",
"title": "3"
}, {
"src": "/imgs/skin/CxQkSU6AY21558430526163.webp",
"title": "4"
}, {
"src": "/imgs/skin/VTUwbp6vY61558430527320.webp",
"title": "5"
}, {
"src": "/imgs/skin/SHs0K703Yn1558430527218.webp",
"title": "6"
}, {
"src": "/imgs/skin/oVTedX9V4s1558430527671.webp",
"title": "7"
}]
},
"business": {
"key": "business",
"name": "商务",
"list": [{
"src": "/imgs/skin/3ABKqvDaVn1558514860472.webp",
"title": "1"
}, {
"src": "/imgs/skin/OewuaQmWoq1558514860285.webp",
"title": "2"
}, {
"src": "/imgs/skin/HuVqqtbFjs1558514860570.webp",
"title": "3"
}, {
"src": "/imgs/skin/icSlqsr0uZ1558514860875.webp",
"title": "4"
}, {
"src": "/imgs/skin/Qu9rg33wmq1558514861015.webp",
"title": "5"
}, {
"src": "/imgs/skin/145gBCRtNP1558514861211.webp",
"title": "6"
}, {
"src": "/imgs/skin/ykWLFV0QWj1558514861444.webp",
"title": "7"
}]
},
"activity": { "activity": {
"key": "activity", "key": "activity",
"name": "节日", "name": "节日",
@ -41,32 +93,6 @@
"title": "7" "title": "7"
}] }]
}, },
"scenery": {
"key": "scenery",
"name": "风景",
"list": [{
"src": "/imgs/skin/SyiLRcukyE1558430525760.webp",
"title": "1"
}, {
"src": "/imgs/skin/sqYig4AcWr1558430525663.webp",
"title": "2"
}, {
"src": "/imgs/skin/ElNeqJT2I21558430526165.webp",
"title": "3"
}, {
"src": "/imgs/skin/CxQkSU6AY21558430526163.webp",
"title": "4"
}, {
"src": "/imgs/skin/VTUwbp6vY61558430527320.webp",
"title": "5"
}, {
"src": "/imgs/skin/SHs0K703Yn1558430527218.webp",
"title": "6"
}, {
"src": "/imgs/skin/oVTedX9V4s1558430527671.webp",
"title": "7"
}]
},
"transportation": { "transportation": {
"key": "transportation", "key": "transportation",
"name": "交通", "name": "交通",
@ -119,32 +145,7 @@
"title": "7" "title": "7"
}] }]
}, },
"business": {
"key": "business",
"name": "商务",
"list": [{
"src": "/imgs/skin/3ABKqvDaVn1558514860472.webp",
"title": "1"
}, {
"src": "/imgs/skin/OewuaQmWoq1558514860285.webp",
"title": "2"
}, {
"src": "/imgs/skin/HuVqqtbFjs1558514860570.webp",
"title": "3"
}, {
"src": "/imgs/skin/icSlqsr0uZ1558514860875.webp",
"title": "4"
}, {
"src": "/imgs/skin/Qu9rg33wmq1558514861015.webp",
"title": "5"
}, {
"src": "/imgs/skin/145gBCRtNP1558514861211.webp",
"title": "6"
}, {
"src": "/imgs/skin/ykWLFV0QWj1558514861444.webp",
"title": "7"
}]
},
"campus": { "campus": {
"key": "campus", "key": "campus",
"name": "校园", "name": "校园",

View File

@ -124,9 +124,5 @@
"endTime": "2028-05-22 17:17:48", "endTime": "2028-05-22 17:17:48",
"tLimit": "0", "tLimit": "0",
"language": "chinese" "language": "chinese"
},
"skinConf": {
"skinColor": "#4a4c5b",
"inputBgColor": "#ffffff"
} }
} }

View File

@ -13,10 +13,6 @@
"msg_9004": "提交失败!" "msg_9004": "提交失败!"
} }
}, },
"skinConf": {
"skinColor": "#4a4c5b",
"inputBgColor": "#ffffff"
},
"bannerConf": { "bannerConf": {
"titleConfig": { "titleConfig": {
"mainTitle": "<h3 style=\"text-align: center\">满意度调研</h3> <p>&nbsp;</p> <p>为了给您提供更好的服务,希望您能抽出几分钟时间,将您的感受和建议告诉我们,<span style=\"color: rgb(204, 0, 0)\">期待您的参与</span></p>", "mainTitle": "<h3 style=\"text-align: center\">满意度调研</h3> <p>&nbsp;</p> <p>为了给您提供更好的服务,希望您能抽出几分钟时间,将您的感受和建议告诉我们,<span style=\"color: rgb(204, 0, 0)\">期待您的参与</span></p>",

View File

@ -156,9 +156,5 @@
"endTime": "2028-05-22 17:17:48", "endTime": "2028-05-22 17:17:48",
"tLimit": "0", "tLimit": "0",
"language": "chinese" "language": "chinese"
},
"skinConf": {
"skinColor": "#4a4c5b",
"inputBgColor": "#ffffff"
} }
} }

View File

@ -143,9 +143,5 @@
"endTime": "2028-05-25 10:22:23", "endTime": "2028-05-25 10:22:23",
"tLimit": "0", "tLimit": "0",
"language": "chinese" "language": "chinese"
},
"skinConf": {
"skinColor": "#4a4c5b",
"inputBgColor": "#ffffff"
} }
} }

View File

@ -37,6 +37,15 @@
}, },
"skinConf": { "skinConf": {
"skinColor": "#4a4c5b", "skinColor": "#4a4c5b",
"inputBgColor": "#ffffff" "inputBgColor": "#ffffff",
"backgroundConf": {
"color": "#fff"
},
"themeConf": {
"color": "#ffa600"
},
"contentConf": {
"opacity": 100
}
} }
} }

View File

@ -1,55 +1,41 @@
export default [ export default [
{ {
label: '头图配置默认尺寸750*260', label: '顶部图片地址',
type: 'Customed', type: 'Input',
key: 'bannerConfig', key: 'bgImage',
labelStyle: { inline: true,
fontWeight: 'bold', direction: 'horizon',
}, labelStyle: { width: '120px' }
content: [
{
label: '顶部图片地址',
type: 'Input',
key: 'bannerConfig.bgImage',
direction: 'horizon',
},
{
label: '顶部视频地址',
type: 'Input',
key: 'bannerConfig.videoLink',
direction: 'horizon',
},
{
label: '视频海报地址',
type: 'Input',
key: 'bannerConfig.postImg',
direction: 'horizon',
},
],
}, },
{ {
label: '头图跳转', label: '顶部视频地址',
type: 'Customed', type: 'Input',
key: 'bannerConfig-Jump', key: 'videoLink',
labelStyle: { direction: 'horizon',
fontWeight: 'bold', labelStyle: { width: '120px' }
},
{
label: '视频海报地址',
type: 'Input',
key: 'postImg',
direction: 'horizon',
labelStyle: { width: '120px' }
},
{
label: '图片支持点击',
type: 'CustomedSwitch',
direction: 'horizon',
labelStyle: { width: '120px' },
key: 'bgImageAllowJump',
},
{
label: '跳转链接',
type: 'Input',
direction: 'horizon',
labelStyle: { width: '120px' },
key: 'bgImageJumpLink',
relyFunc: (data) => {
return !!data?.bgImageAllowJump;
}, },
content: [
{
label: '图片支持点击',
type: 'CustomedSwitch',
direction: 'space_between',
key: 'bannerConfig.bgImageAllowJump',
},
{
label: '跳转链接',
type: 'Input',
direction: 'horizon',
key: 'bannerConfig.bgImageJumpLink',
relyFunc: (data) => {
return !!data?.bannerConfig?.bgImageAllowJump;
},
},
],
}, },
]; ];

View File

@ -4,17 +4,15 @@ export default [
type: 'Input', type: 'Input',
key: 'logoImage', key: 'logoImage',
tip: '默认尺寸200px*50px', tip: '默认尺寸200px*50px',
labelStyle: { direction: 'horizon',
fontWeight: 'bold', labelStyle: { width: '120px' }
},
}, },
{ {
label: 'Logo大小', label: 'Logo大小',
type: 'InputPercent', type: 'InputPercent',
key: 'logoImageWidth', key: 'logoImageWidth',
tip: '填写宽度百分比例如30%', tip: '填写宽度百分比例如30%',
labelStyle: { direction: 'horizon',
fontWeight: 'bold', labelStyle: { width: '120px' }
},
}, },
]; ];

View File

@ -0,0 +1,46 @@
import bannerConfig from "./bannerConfig"
import logoConfig from "./logoConfig"
export default [
{
name: '头图',
key: 'bannerConf.bannerConfig',
formConfigList: bannerConfig
},
{
name: '背景',
key: 'skinConf.backgroundConf',
formConfigList: [{
direction: 'space_between',
label: '背景颜色',
type: 'ColorPicker',
key: 'color',
}],
},
{
name: '主题色',
key: 'skinConf.themeConf',
formConfigList: [{
direction: 'space_between',
direction: 'space_between',
label: '全局应用',
type: 'ColorPicker',
key: 'color',
}],
},
{
key: 'skinConf.contentConf',
name: '内容区域',
formConfigList: [{
direction: 'space_between',
label: '内容透明度',
type: 'SliderSetter',
key: 'opacity',
}],
},
{
name: '品牌logo',
key: 'bottomConf',
formConfigList: logoConfig
}
]

View File

@ -0,0 +1,7 @@
export default {
'default-1': {
'skinConf.backgroundConf.color': '#90b4fa',
'skinConf.themeConf.color': '#FAA600',
}
}

View File

@ -3,7 +3,7 @@
<div class="question-logo" @click="onSelect"> <div class="question-logo" @click="onSelect">
<img <img
v-if="logoImg !== ''" v-if="logoImg !== ''"
:style="{ width: bottomConf.logoImageWidth }" :style="{ width: logoConf.logoImageWidth }"
class="bottom-logo" class="bottom-logo"
:src="logoImg" :src="logoImg"
/> />
@ -18,7 +18,10 @@
export default { export default {
name: 'LogoPreview', name: 'LogoPreview',
props: { props: {
bottomConf: Object, logoConf: {
type: Object,
default: () => {}
},
isSelected: Boolean, isSelected: Boolean,
}, },
data() { data() {
@ -31,7 +34,7 @@ export default {
}, },
computed: { computed: {
logoImg() { logoImg() {
const { logoImage } = this.bottomConf; const { logoImage = {} } = this.logoConf;
return logoImage; return logoImage;
}, },
}, },

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="title-wrapper" @click="handleClick()"> <div class="title-wrapper" @click="handleClick()">
<div class="main-title" :class="{ active: isSelected }"> <div class="main-title" :class="{ active: isSelected }" >
<richEditor <richEditor
:value="bannerConf?.titleConfig?.mainTitle" :value="bannerConf?.titleConfig?.mainTitle"
@input="onTitleInput" @input="onTitleInput"
@ -17,6 +17,10 @@ export default {
return {}; return {};
}, },
props: { props: {
preview: {
type: Boolean,
default: false,
},
bannerConf: { bannerConf: {
type: Object, type: Object,
}, },
@ -27,7 +31,11 @@ export default {
computed: {}, computed: {},
methods: { methods: {
handleClick() { handleClick() {
this.$emit('select'); if(this.preview) {
return false
} else {
this.$emit('select');
}
}, },
onTitleInput(val) { onTitleInput(val) {
if (!this.isSelected) { if (!this.isSelected) {

View File

@ -193,9 +193,9 @@ export default defineComponent({
&.spliter { &.spliter {
border-bottom: 0.12rem solid $spliter-color; border-bottom: 0.12rem solid $spliter-color;
} }
// &:last-child{ &:last-child{
// border: none; border: none;
// } }
.editor { .editor {
display: flex; display: flex;
font-size: 0.32rem; font-size: 0.32rem;

View File

@ -6,7 +6,6 @@
> >
<el-button <el-button
class="submit-btn" class="submit-btn"
:style="{ 'background-color': skinConf.skinColor }"
type="primary" type="primary"
>{{ submitConf.submitTitle }}</el-button >{{ submitConf.submitTitle }}</el-button
> >
@ -41,8 +40,9 @@ export default {
.submit-btn { .submit-btn {
color: white; color: white;
border: none; border: none;
width: 250px; width: 100%;
height: 44px; height: 44px;
background-color: var(--primary-color);
} }
} }
</style> </style>

View File

@ -23,7 +23,6 @@ export default {
}, },
async created() { async created() {
this.$store.commit('edit/setSurveyId', this.$route.params.id); this.$store.commit('edit/setSurveyId', this.$route.params.id);
this.$store.dispatch('getBannerData');
try { try {
await this.$store.dispatch('edit/init'); await this.$store.dispatch('edit/init');
} catch (error) { } catch (error) {

View File

@ -7,21 +7,25 @@
:to="{ name: btnItem.router }" :to="{ name: btnItem.router }"
tag="div" tag="div"
replace replace
v-slot="{ href, route, navigate, isActive, isExactActive }"
custom
>
<div
:class="[
(isActive && btnItem.key === 'skinsettings' ) || isExactActive ? 'router-link-exact-active' : '']"
> >
<i class="iconfont" :class="[btnItem.icon]"></i> <i class="iconfont" :class="[btnItem.icon]"></i>
<span>{{ btnItem.text }}</span> <a :href="href" @click="navigate"><span>{{ btnItem.text }}</span></a>
<!-- <span>{{ btnItem.text }}</span> -->
</div>
</router-link> </router-link>
<i
v-if="btnItem.next"
:key="btnItem.key + '-next'"
class="iconfont icon-jiantou next"
></i>
</template> </template>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'pageTitle', name: 'pageNav',
props: {}, props: {},
data() { data() {
return { return {
@ -41,10 +45,11 @@ export default {
next: true, next: true,
}, },
{ {
icon: 'icon-jieguoyeshezhi', icon: 'icon-yangshishezhi',
text: '结果页设置', text: '皮肤设置',
router: 'QuestionEditResultConfig', router: 'QuestionSkinSetting',
key: 'status', key: 'skinsettings',
next: true,
}, },
], ],
}; };
@ -62,7 +67,9 @@ export default {
color: #92949d; color: #92949d;
padding: 0 20px; padding: 0 20px;
cursor: pointer; cursor: pointer;
a{
color: inherit;
}
&.router-link-exact-active { &.router-link-exact-active {
color: $font-color-title; color: $font-color-title;

View File

@ -1,77 +0,0 @@
<template>
<div class="banner-list-wrapper">
<el-collapse v-model="curSkinGroupKey">
<el-collapse-item
v-for="(bannerGroup, index) in bannerList"
:key="index"
:title="bannerGroup.name"
:name="bannerGroup.key"
>
<div
class="single-banner-wrapper"
v-for="(banner, bannerIndex) in bannerGroup.list"
:key="bannerIndex"
>
<img
class="banner-img"
:src="banner.src"
loading="lazy"
@click="changeBanner(banner.src)"
/>
</div>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script>
export default {
name: 'bannerList',
data() {
return {
curSkinGroupKey: ['temp'],
};
},
computed: {
bannerList() {
return this.$store?.state?.bannerList || [];
},
},
methods: {
changeBanner(imgSrc) {
this.$emit('change', imgSrc);
},
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
.banner-list-wrapper {
padding: 5px 18px 100px 19px;
overflow-x: hidden;
.banner-img {
position: relative;
margin-bottom: 10px;
width: 100%;
min-height: 111px;
cursor: pointer;
transition: all 0.2s;
&:hover {
-webkit-filter: brightness(90%);
filter: brightness(90%);
}
}
::v-deep .el-collapse-item__header {
font-size: 16px;
color: $font-color-title;
border-bottom: none;
}
::v-deep .el-collapse-item__arrow.is-active {
right: 0;
}
::v-deep .el-collapse-item__arrow {
right: 0;
}
}
</style>

View File

@ -1,13 +1,7 @@
<template> <template>
<div class="main-operation" @click="onMainClick" ref="mainOperation"> <div class="main-operation" @click="onMainClick" ref="mainOperation">
<!-- <div class="toolbar"></div> -->
<div class="operation-wrapper" ref="operationWrapper"> <div class="operation-wrapper" ref="operationWrapper">
<div class="box content" ref="box"> <div class="box content" ref="box">
<banner
:bannerConf="bannerConf"
:is-selected="currentEditOne === 'banner'"
@select="onSelectEditOne('banner')"
/>
<mainTitle <mainTitle
:bannerConf="bannerConf" :bannerConf="bannerConf"
:is-selected="currentEditOne === 'mainTitle'" :is-selected="currentEditOne === 'mainTitle'"
@ -28,29 +22,22 @@
:is-selected="currentEditOne === 'submit'" :is-selected="currentEditOne === 'submit'"
@select="onSelectEditOne('submit')" @select="onSelectEditOne('submit')"
/> />
<logo
:bottom-conf="bottomConf"
:is-selected="currentEditOne === 'logo'"
@select="onSelectEditOne('logo')"
/>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import materialGroup from './components/materialGroup.vue'; import materialGroup from '@/management/pages/edit/components/materialGroup.vue';
import banner from './components/banner.vue'; import mainTitle from '@/management/pages/edit/components/mainTitle.vue';
import mainTitle from './components/mainTitle.vue'; import submit from '@/management/pages/edit/components/submit.vue';
import submit from './components/submit.vue'; import logo from '@/management/pages/edit/components/logo.vue';
import logo from './components/logo.vue';
import { mapState, mapGetters } from 'vuex'; import { mapState, mapGetters } from 'vuex';
import { get as _get } from 'lodash-es'; import { get as _get } from 'lodash-es';
export default { export default {
name: 'mainOperation', name: 'mainOperation',
components: { components: {
banner,
mainTitle, mainTitle,
submit, submit,
logo, logo,
@ -81,6 +68,23 @@ export default {
}, },
}, },
watch: { watch: {
skinConf: {
handler (skinConf) {
const { themeConf, backgroundConf, contentConf} = skinConf
const root = document.documentElement;
if(themeConf?.color) {
root.style.setProperty('--primary-color', themeConf?.color); //
}
if(backgroundConf?.color) {
root.style.setProperty('--primary-background-color', backgroundConf?.color); //
}
if(contentConf?.opacity) {
root.style.setProperty('--opacity', contentConf?.opacity/100); //
}
},
immediate: true, //
deep: true
},
autoScrollData(newVal) { autoScrollData(newVal) {
const { currentEditOne } = newVal; const { currentEditOne } = newVal;
if (typeof currentEditOne === 'number') { if (typeof currentEditOne === 'number') {
@ -188,7 +192,7 @@ export default {
} }
.operation-wrapper { .operation-wrapper {
margin-top: 38px; margin-top: 50px;
margin-bottom: 45px; margin-bottom: 45px;
// min-height: 812px; // min-height: 812px;
overflow-x: hidden; overflow-x: hidden;

View File

@ -13,14 +13,12 @@
:module-config="moduleConfig" :module-config="moduleConfig"
@form-change="onFormChange" @form-change="onFormChange"
/> />
<bannerList v-if="currentEditOne === 'banner'" @change="onClickSkin" />
</template> </template>
</div> </div>
</template> </template>
<script> <script>
import bannerList from './components/bannerList.vue'; import setterField from '@/management/pages/edit/components/setterField.vue';
import setterField from './components/setterField.vue';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
export default { export default {
@ -42,16 +40,9 @@ export default {
}), }),
}, },
components: { components: {
bannerList,
setterField, setterField,
}, },
methods: { methods: {
onClickSkin(src) {
this.onFormChange({
key: 'bannerConfig.bgImage',
value: src,
});
},
onFormChange(data) { onFormChange(data) {
const { key, value } = data; const { key, value } = data;
const resultKey = `${this.currentEditKey}.${key}`; const resultKey = `${this.currentEditKey}.${key}`;
@ -75,7 +66,6 @@ export default {
font-size: 14px; font-size: 14px;
color: $primary-color; color: $primary-color;
padding-left: 20px; padding-left: 20px;
background: #f9fafc;
border-bottom: 1px solid #edeffc; border-bottom: 1px solid #edeffc;
} }
@ -98,6 +88,6 @@ export default {
} }
.question-config-form { .question-config-form {
padding: 30px 20px 50px 20px; padding: 30px 20px 50px 20px!important;
} }
</style> </style>

View File

@ -11,7 +11,7 @@
<div class="video"> <div class="video">
<video <video
class="custom-video" class="custom-video"
:poster="bannerConf.bannerConfig.postImg" :poster="bannerConf.bannerConfigpostImg"
preload="auto" preload="auto"
controls controls
:src="bannerConf.bannerConfig.videoLink" :src="bannerConf.bannerConfig.videoLink"
@ -31,6 +31,7 @@ export default {
props: { props: {
bannerConf: { bannerConf: {
type: Object, type: Object,
default: () => {}
}, },
isSelected: { isSelected: {
type: Boolean, type: Boolean,
@ -59,6 +60,7 @@ export default {
.banner { .banner {
width: 100%; width: 100%;
display: flex;
img { img {
width: 100%; width: 100%;

View File

@ -26,11 +26,12 @@ export default {
.over-time { .over-time {
text-align: center; text-align: center;
margin-bottom: 5.5rem; margin-bottom: 5.5rem;
height: 100%;
.title-msg { .title-msg {
width: 100%; width: 100%;
font-size: 16px; font-size: 16px;
color: #999; color: #666;
} }
} }

View File

@ -32,7 +32,7 @@ export default {
text-align: center; text-align: center;
width: 100%; width: 100%;
display: inline-block; display: inline-block;
height: 100%;
.success-img { .success-img {
margin-top: -0.2rem; margin-top: -0.2rem;
width: 100px; width: 100px;
@ -46,7 +46,6 @@ export default {
width: 100%; width: 100%;
position: relative; position: relative;
padding-top: 1.8rem; padding-top: 1.8rem;
background: #fff;
} }
.title-msg { .title-msg {

View File

@ -5,7 +5,7 @@ export default {
label: '答题有效期', label: '答题有效期',
type: 'QuestionTime', type: 'QuestionTime',
placeholder: 'yyyy-MM-dd hh:mm:ss', placeholder: 'yyyy-MM-dd hh:mm:ss',
direction: 'horizon', // direction: 'horizon',
}, },
// base_showVote: { // base_showVote: {
// key: 'baseConf.showVoteProcess', // key: 'baseConf.showVoteProcess',
@ -42,7 +42,7 @@ export default {
key: 'baseConf.tLimit', key: 'baseConf.tLimit',
label: '问卷回收总数', label: '问卷回收总数',
type: 'InputNumber', type: 'InputNumber',
direction: 'horizon', // direction: 'horizon',
tip: '0为无限制此功能用于限制该问卷总提交的数据量。当数据量达到限额时该问卷将不能继续提交', tip: '0为无限制此功能用于限制该问卷总提交的数据量。当数据量达到限额时该问卷将不能继续提交',
tipShow: true, tipShow: true,
placement: 'top', placement: 'top',
@ -53,7 +53,7 @@ export default {
label: '答题时段', label: '答题时段',
tip: '问卷仅在指定时间段内可填写', tip: '问卷仅在指定时间段内可填写',
type: 'QuestionTimeHour', type: 'QuestionTimeHour',
direction: 'horizon', // direction: 'horizon',
placement: 'top', placement: 'top',
}, },
// skin_skinColor: { // skin_skinColor: {

View File

@ -1,21 +1,24 @@
<template> <template>
<div class="status-list-wrapper"> <div class="tab-box">
<div <div class="title">结果页状态选择</div>
v-for="(status, index) in statusList" <div class="status-list-wrapper">
:key="index" <div
class="status-item" v-for="(status, index) in statusList"
@click="filterDisabledStatus({ type: status.type })" :key="index"
> class="status-item"
<span>{{ status.title }}</span> @click="filterDisabledStatus({ type: status.type })"
<div class="preview-item"> >
<img :src="status.previewImg" :alt="status.title" /> <span>{{ status.title }}</span>
<div class="preview-item">
<img :src="status.previewImg" :alt="status.title" />
</div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { mapMutations } from 'vuex'; import { mapMutations } from 'vuex';
import { EDIT_STATUS_MAP } from './enum'; import { EDIT_STATUS_MAP } from '../enum';
export default { export default {
name: 'resultConfigList', name: 'resultConfigList',
@ -47,13 +50,27 @@ export default {
}; };
</script> </script>
<style lang="scss" rel="stylesheet/scss" scoped> <style lang="scss" rel="stylesheet/scss" scoped>
.status-list-wrapper { .tab-box {
width: 300px; width: 300px;
height: 100%; height: 100%;
box-shadow: none;
border: none;
overflow-y: auto;
background-color: #fff;
.title {
height: 40px;
line-height: 40px;
font-size: 14px;
color: $primary-color;
padding-left: 20px;
// background: #f9fafc;
border-bottom: 1px solid #edeffc;
}
}
.status-list-wrapper {
padding: 19px 18px 100px 19px; padding: 19px 18px 100px 19px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
background-color: #fff;
label.title { label.title {
font-size: 16px; font-size: 16px;

View File

@ -1,19 +1,21 @@
<template> <template>
<div class="result-config-preview"> <div class="result-config-preview">
<div class="status-preview"> <div class="result-page-wrap">
<component <div class="result-page">
:is="currentEditStatus" <component
:key="currentEditStatus" :is="currentEditStatus"
:module-config="moduleConfig" :key="currentEditStatus"
/> :module-config="moduleConfig"
</div> />
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import success from './components/success'; import success from '../components/success';
import overTime from './components/overTime'; import overTime from '../components/overTime';
import { EDIT_STATUS_MAP } from './enum'; import { EDIT_STATUS_MAP } from '../enum';
import { get as _get } from 'lodash-es'; import { get as _get } from 'lodash-es';
export default { export default {
@ -51,13 +53,20 @@ export default {
background-color: #f6f7f9; background-color: #f6f7f9;
} }
.status-preview { .result-page-wrap {
width: 90%; width: 90%;
margin-top: 38px; margin-top: 50px;
min-height: 812px; min-height: 812px;
max-height: 812px; max-height: 812px;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
background-color: #fff; background-color: var(--primary-background-color);
padding: 0 0.3rem;
.result-page{
background: rgba(255, 255, 255, var(--opacity));
display: flex;
flex-direction: column;
height: 100%;
}
} }
</style> </style>

View File

@ -31,13 +31,13 @@
<script> <script>
import FormItem from '@/materials/setters/widgets/FormItem.vue'; import FormItem from '@/materials/setters/widgets/FormItem.vue';
import setterLoader from '@/materials/setters/setterLoader'; import setterLoader from '@/materials/setters/setterLoader';
import statusConfig from './config/statusConfig'; import statusConfig from '../config/statusConfig';
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import { get as _get, pick as _pick } from 'lodash-es'; import { get as _get, pick as _pick } from 'lodash-es';
const textMap = { const textMap = {
Success: '提交成功页面配置', Success: '提交成功页面配置',
OvertTme: '问卷过期页面配置', OverTime: '问卷过期页面配置',
}; };
export default { export default {
@ -150,7 +150,7 @@ export default {
font-size: 14px; font-size: 14px;
color: $primary-color; color: $primary-color;
padding-left: 20px; padding-left: 20px;
background: #f9fafc; // background: #f9fafc;
border-bottom: 1px solid #edeffc; border-bottom: 1px solid #edeffc;
} }

View File

@ -0,0 +1,170 @@
<template>
<div class="tab-box">
<div class="title">主题设置</div>
<div class="content">
<div class="tag-list">
<el-tag
v-for="item in groupList"
:class="[groupName === item.value ? 'current' : '', 'tag']"
type = 'info'
:key="item.value"
@click="() => changeGroup(item.value)">
{{item.label}}
</el-tag>
</div>
<div class="banner-list-wrapper">
<div
class="single-banner-wrapper"
v-for="(banner, bannerIndex) in currentBannerList"
:key="bannerIndex"
>
<img
class="banner-img"
:src="banner.src"
loading="lazy"
@click="changePreset(banner)"
/>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import skinPresets from '@/management/config/skinPresets.js'
export default {
name: 'catalogPanel',
data() {
return {
skinPresets: [],
groupName: 'temp',
};
},
computed: {
bannerList() {
return this.$store?.state?.bannerList || [];
},
groupList() {
return Object.keys(this.bannerList).map((key) => {
return {
label: this.bannerList[key].name,
value: key
}
})
},
currentBannerList () {
const arr = Object.keys(this.bannerList).map((key) => {
return this.bannerList[key]
}).map(data => {
return data.list.map(item => {
item.group = data.key;
return item;
})
})
const allbanner = arr.reduce((acc, curr) => {
return acc.concat(curr);
}, []);
return allbanner.filter(item => {
if(this.groupName === "temp") {
return true
} else {
return item.group === this.groupName
}
})
}
},
mounted() {
},
methods: {
...mapActions({
changeThemePreset: 'edit/changeThemePreset',
}),
changeGroup(value) {
this.groupName = value
},
changePreset(banner) {
const name = banner.group + '-' + banner.title
let presets = {
'bannerConf.bannerConfig.bgImage': banner.src,
'skinConf.themeConf.color': '#FAA600',
'skinConf.backgroundConf.color': '#fff',
}
if(skinPresets[name]){
presets = Object.assign(presets, skinPresets[name])
}
this.changeThemePreset(presets)
}
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
.tab-box {
width: 300px;
height: 100%;
box-shadow: none;
border: none;
overflow-y: auto;
background-color: #fff;
.title {
height: 40px;
line-height: 40px;
font-size: 14px;
color: $primary-color;
padding-left: 20px;
// background: #f9fafc;
border-bottom: 1px solid #edeffc;
}
.content{
padding: 12px;
}
.tag-list{
display: flex;
flex-wrap: wrap;
.tag{
margin: 5px 8px;
cursor: pointer;
&.current{
color: $primary-color;
background-color: $primary-bg-color;
}
}
}
.banner-list-wrapper {
padding: 15px 3px 100px 3px;
overflow-x: hidden;
.banner-img {
position: relative;
margin-bottom: 10px;
width: 100%;
// min-height: 111px;
cursor: pointer;
transition: all 0.2s;
border-radius: 4px;
&:hover {
-webkit-filter: brightness(90%);
filter: brightness(90%);
}
}
::v-deep .el-collapse-item__header {
font-size: 16px;
color: $font-color-title;
border-bottom: none;
}
::v-deep .el-collapse-item__arrow.is-active {
right: 0;
}
::v-deep .el-collapse-item__arrow {
right: 0;
}
}
}
</style>

View File

@ -0,0 +1,169 @@
<template>
<div class="main-operation">
<div class="operation-wrapper">
<div class="box" ref="box">
<div class="mask"></div>
<banner
:bannerConf="bannerConf"
/>
<div class="content">
<mainTitle
:isSelected="false"
:bannerConf="bannerConf"
/>
<materialGroup
:questionDataList="questionDataList"
ref="materialGroup"
/>
<submit
:submit-conf="submitConf"
:skin-conf="skinConf"
:is-selected="currentEditOne === 'submit'"
/>
<logo
:logo-conf="bottomConf"
:is-selected="currentEditOne === 'logo'"
/>
</div>
</div>
</div>
</div>
</template>
<script>
import materialGroup from '@/management/pages/edit/components/materialGroup.vue';
import banner from '../components/banner.vue';
import mainTitle from '@/management/pages/edit/components/mainTitle.vue';
import submit from '@/management/pages/edit/components/submit.vue';
import logo from '@/management/pages/edit/components/logo.vue';
import { mapState, mapGetters } from 'vuex';
import { get as _get } from 'lodash-es';
export default {
name: 'previewPanel',
components: {
banner,
mainTitle,
submit,
logo,
materialGroup,
},
data() {
return {
isAnimating: false,
};
},
computed: {
...mapState({
bannerConf: (state) => _get(state, 'edit.schema.bannerConf'),
submitConf: (state) => _get(state, 'edit.schema.submitConf'),
bottomConf: (state) => _get(state, 'edit.schema.bottomConf'),
skinConf: (state) => _get(state, 'edit.schema.skinConf'),
questionDataList: (state) => _get(state, 'edit.schema.questionDataList'),
currentEditOne: (state) => _get(state, 'edit.currentEditOne'),
}),
...mapGetters({
currentEditKey: 'edit/currentEditKey',
}),
},
watch: {
skinConf: {
handler (skinConf) {
const { themeConf, backgroundConf, contentConf} = skinConf
const root = document.documentElement;
if(themeConf?.color) {
root.style.setProperty('--primary-color', themeConf?.color); //
}
if(backgroundConf?.color) {
root.style.setProperty('--primary-background-color', backgroundConf?.color); //
}
if(contentConf?.opacity.toString()) {
root.style.setProperty('--opacity', contentConf?.opacity/100); //
}
},
immediate: true, //
deep: true
}
},
methods: {
animate(dom, property, targetValue) {
const origin = dom[property];
const subVal = targetValue - origin;
const flag = subVal < 0 ? -1 : 1;
const step = flag * 50;
const totalCount = Math.floor(subVal / step) + 1;
let runCount = 0;
const run = () => {
dom[property] += step;
runCount++;
if (runCount < totalCount) {
requestAnimationFrame(run);
} else {
this.isAnimating = false;
}
};
requestAnimationFrame(run);
},
},
};
</script>
<style lang="scss" scoped>
.main-operation {
width: 100%;
height: 100%;
min-width: 500px;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f6f7f9;
}
.toolbar {
width: 100%;
height: 38px;
background-color: #fff;
flex-grow: 0;
flex-shrink: 0;
}
.operation-wrapper {
margin-top: 50px;
margin-bottom: 45px;
// min-height: 812px;
overflow-x: hidden;
overflow-y: auto;
// padding-right: 30px;
margin-right: 0px;
scrollbar-width: none;
width: 90%;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
.box {
background-color: var(--primary-background-color);
position: relative;
.mask{
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 999;
}
.content {
margin: 0 0.3rem;
background: rgba(255, 255, 255, var(--opacity));
border-radius: 8px 8px 0 0;
}
}
}
</style>

View File

@ -0,0 +1,119 @@
<template>
<div class="setter-wrapper">
<div class="setter-title">
样式设置
</div>
<div class="setter-content">
<el-collapse v-model="collapse">
<el-collapse-item
v-for="(collapse, index) in skinConfig"
:key="index"
:title="collapse.name"
:name="collapse.key"
>
<setterField
:form-config-list="collapse.formConfigList"
:module-config="_get(schema, collapse.key, {})"
@form-change="(key) => { onFormChange(key, collapse.key) }"
/>
</el-collapse-item>
</el-collapse>
</div>
<!-- -->
</div>
</template>
<script>
import skinConfig from '@/management/config/setterConfig/skinConfig';
import setterField from '@/management/pages/edit/components/setterField.vue';
import { mapState, mapGetters } from 'vuex';
import { get as _get } from 'lodash-es'
export default {
name: 'setterPanel',
components: {
setterField,
},
data() {
return {
collapse: '',
skinConfig,
};
},
computed: {
...mapState({
skinConf: (state) => _get(state, 'edit.schema.skinConf'),
schema: (state) => _get(state, 'edit.schema'),
}),
},
methods: {
_get,
onFormChange(data,collapse) {
const { key, value } = data;
const currentEditKey = `${collapse}`
const resultKey = `${currentEditKey}.${key}`;
this.$store.dispatch('edit/changeSchema', { key: resultKey, value });
},
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
.setter-wrapper {
width: 360px;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
background-color: #fff;
}
.setter-title {
height: 40px;
line-height: 40px;
font-size: 14px;
color: $primary-color;
padding-left: 20px;
// background: #f9fafc;
border-bottom: 1px solid #edeffc;
}
.setter-content{
padding: 10px 20px;
.el-collapse {
border: none;
::v-deep .el-collapse-item__header{
font-size: 14px;
color: #606266;
font-weight: bold;
border: none;
}
::v-deep .el-collapse-item__wrap{
border: none;
.el-collapse-item__content{
padding-bottom: 0px!important;
}
}
}
.config-form{
padding: 0!important;
}
}
.no-select-question {
padding-top: 125px;
display: flex;
flex-direction: column;
align-items: center;
img {
width: 160px;
padding: 25px;
}
.tip {
font-size: 14px;
color: $normal-color;
letter-spacing: 0;
}
}
.question-config-form {
padding: 30px 20px 50px 20px;
}
</style>

View File

@ -0,0 +1,32 @@
<template>
<commonTemplate>
<catalogPanel slot="left"></catalogPanel>
<previewPanel slot="center"></previewPanel>
<setterPanel slot="right"></setterPanel>
</commonTemplate>
</template>
<script>
import commonTemplate from '../../components/commonTemplate.vue';
import catalogPanel from '../../modules/settingModule/skin/catalogPanel.vue';
import previewPanel from '../../modules/settingModule/skin/previewPanel.vue';
import setterPanel from '../../modules/settingModule/skin/setterPanel.vue';
export default {
name: 'editIndex',
components: {
commonTemplate,
catalogPanel,
previewPanel,
setterPanel,
},
created() {
this.$store.dispatch('getBannerData');
}
};
</script>
<style lang="scss" scoped>
.navbar {
border-bottom: 1px solid #e7e9eb;
}
</style>

View File

@ -0,0 +1,68 @@
<template>
<div class="skin-content">
<div class="navbar-tab">
<el-radio-group size="mini" style="margin-bottom: 30px;" v-model="activeRouter">
<el-radio-button :label="btnItem.router" :key="btnItem.router" v-for="btnItem in btnList" >
<span>{{ btnItem.text }}</span>
</el-radio-button>
</el-radio-group>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'skinPage',
props: {},
data() {
return {
activeRouter: this.$route.name,
btnList: [
{
text: '内容页',
router: 'QuestionSkinSetting',
key: 'skinsettings',
next: true,
},
{
text: '结果页',
router: 'QuestionEditResultConfig',
key: 'status',
},
],
};
},
watch: {
activeRouter: {
handler (val) {
this.$router.push({ name: val})
}
}
},
};
</script>
<style lang="scss" scoped>
.skin-content {
display: flex;
align-items: center;
justify-content: center;
position: relative;
width: 100%;
height: 100%;
.navbar-tab {
position: absolute;
top: 10px;
cursor: pointer;
z-index: 9999;
::v-deep .el-radio-button__orig-radio:checked + .el-radio-button__inner{
color: $primary-color;
background-color: #fff!important;
// &:active{
// color: $primary-color;
// }
}
}
}
</style>

View File

@ -6,10 +6,10 @@
</commonTemplate> </commonTemplate>
</template> </template>
<script> <script>
import commonTemplate from '../components/commonTemplate.vue'; import commonTemplate from '../../components/commonTemplate.vue';
import resultCatalog from '../modules/settingModule/resultCatalog.vue'; import resultCatalog from '../../modules/settingModule/result/catalogPanel.vue';
import resultPreview from '../modules/settingModule/resultPreview.vue'; import resultPreview from '../../modules/settingModule/result/previewPanel.vue';
import resultSetter from '../modules/settingModule/resultSetter.vue'; import resultSetter from '../../modules/settingModule/result/setterPanel.vue';
export default { export default {
name: 'editIndex', name: 'editIndex',

View File

@ -24,12 +24,14 @@ const routes = [
meta: { meta: {
needLogin: true, needLogin: true,
}, },
// redirect: '/question',
component: () => component: () =>
import(/* webpackChunkName: "editPage" */ '../pages/edit/index.vue'), import(/* webpackChunkName: "editPage" */ '../pages/edit/index.vue'),
children: [ children: [
{ {
path: '', path: '',
name: 'QuestionEditIndex', name: 'QuestionEditIndex',
meta: { meta: {
needLogin: true, needLogin: true,
}, },
@ -50,15 +52,32 @@ const routes = [
), ),
}, },
{ {
path: 'resultConfig', path: 'skin',
name: 'QuestionEditResultConfig', name: 'SkinSetting',
meta: { meta: {
needLogin: true, needLogin: true,
}, },
component: () => component: () => import(/* webpackChunkName: "skin" */ '../pages/edit/pages/skin/index.vue'),
import( children: [
/* webpackChunkName: "QuestionEditResultConfig" */ '../pages/edit/pages/resultConfig.vue' {
), path: '',
name: 'QuestionSkinSetting',
meta: {
needLogin: true,
},
component: () =>
import('../pages/edit/pages/skin/content.vue'),
},
{
path: 'result',
name: 'QuestionEditResultConfig',
meta: {
needLogin: true,
},
component: () =>
import('../pages/edit/pages/skin/result.vue'),
}
],
}, },
], ],
}, },

View File

@ -66,4 +66,7 @@ export default {
commit('changeSchema', { key, value }); commit('changeSchema', { key, value });
commit('updateSchemaUpdateTime', Date.now()); commit('updateSchemaUpdateTime', Date.now());
}, },
changeThemePreset({ commit }, presets) {
commit('changeThemePreset', presets)
},
}; };

View File

@ -1,4 +1,4 @@
import { set as _set, merge as _merge } from 'lodash-es'; import { get as _get, set as _set, merge as _merge } from 'lodash-es';
export default { export default {
setCurrentEditOne(state, data) { setCurrentEditOne(state, data) {
@ -86,4 +86,9 @@ export default {
changeSchema(state, { key, value }) { changeSchema(state, { key, value }) {
_set(state.schema, key, value); _set(state.schema, key, value);
}, },
changeThemePreset(state, presets) {
Object.keys(presets).forEach(key => {
_set(state.schema, key, presets[key]);
})
}
}; };

View File

@ -24,8 +24,15 @@ export default {
logoImageWidth: '28%', logoImageWidth: '28%',
}, },
skinConf: { skinConf: {
skinColor: '#4a4c5b', backgroundConf: {
inputBgColor: '#ffffff', color: "#fff"
},
themeConf: {
color: "#ffa600"
},
contentConf: {
opacity: 100
}
}, },
baseConf: { baseConf: {
begTime: '', begTime: '',

View File

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 4263849 */ font-family: "iconfont"; /* Project id 4263849 */
src: url('//at.alicdn.com/t/c/font_4263849_tcd4y5836dg.woff2?t=1695630919866') format('woff2'), src: url('//at.alicdn.com/t/c/font_4263849_t1b52yiuhie.woff2?t=1695630919866') format('woff2'),
url('//at.alicdn.com/t/c/font_4263849_tcd4y5836dg.woff?t=1695630919866') format('woff'), url('//at.alicdn.com/t/c/font_4263849_t1b52yiuhie.woff?t=1695630919866') format('woff'),
url('//at.alicdn.com/t/c/font_4263849_tcd4y5836dg.ttf?t=1695630919866') format('truetype'); url('//at.alicdn.com/t/c/font_4263849_t1b52yiuhie.ttf?t=1695630919866') format('truetype');
} }
.iconfont { .iconfont {
@ -50,7 +50,7 @@
} }
.icon-wenjuanshezhi:before { .icon-wenjuanshezhi:before {
content: "\e6cc"; content: "\eacc";
} }
.icon-jiantou:before { .icon-jiantou:before {
@ -124,3 +124,6 @@
.icon-erweima:before { .icon-erweima:before {
content: "\e6c0"; content: "\e6c0";
} }
.icon-yangshishezhi:before {
content: "\e6e6";
}

View File

@ -0,0 +1,12 @@
// 定义颜色变量
$primary-color: #ffa600;
$primary-background-color: #fff;
$opacity: 1;
// 使用CSS自定义属性
:root {
--primary-color: #{$primary-color};
--primary-background-color: #{$primary-background-color};
--opacity: #{$opacity};
}

View File

@ -1,8 +1,10 @@
@import './skin.scss';
$primary-color: #ffa600; $primary-color: #ffa600;
$primary-color-hover: #fbb733; $primary-color-hover: #fbb733;
$primary-color-deep: #D48D00; $primary-color-deep: #D48D00;
$primary-color-light: #fffcf0; $primary-color-light: #fffcf0;
$normal-color: #4a4c5b; $normal-color: #4a4c5b;
$normal-color-hover: #626369; $normal-color-hover: #626369;
$normal-color-deep: #292a36; $normal-color-deep: #292a36;
@ -22,6 +24,7 @@ $background-color: #f6f7f9;
$background-color-light: #ffffff; $background-color-light: #ffffff;
$background-color-gray: #F7F9Fb; $background-color-gray: #F7F9Fb;
$background-color-dark: #E7E9EB; $background-color-dark: #E7E9EB;
$primary-bg-color: #fef6e6;
$title-color-deep: #292a36; $title-color-deep: #292a36;
$title-color: #4a4c5b; $title-color: #4a4c5b;
@ -32,3 +35,35 @@ $light-focus-color: #666666;
$spliter-color: #f7f7f7; $spliter-color: #f7f7f7;
$error-color: #ec4e29; $error-color: #ec4e29;
$primary-color-light: hsl(48, 100%, 97%);
$title-size: 0.32rem;
$font-size: 0.28rem;
$tip-size: 0.22rem;
.el-radio__input.is-checked+.el-radio__label {
color: $font-color !important;
}
.el-switch.is-checked .el-switch__core {
border-color: $primary-color !important;
background-color: $primary-color !important;
}
.el-checkbox__input.is-checked .el-checkbox__inner,
.question-edit-wrapper .el-checkbox__input.is-indeterminate .el-checkbox__inner {
background-color: $primary-color !important;
border-color: $primary-color !important;
}
.el-checkbox__input.is-focus .el-checkbox__inner {
border-color: $primary-color !important;
}
.el-checkbox__input.is-checked+.el-checkbox__label {
color: $font-color !important;
}

View File

@ -1,4 +1,4 @@
$primary-color: #FAA600; $primary-color: var(--primary-color);
$primary-color-light: hsl(48, 100%, 97%); $primary-color-light: hsl(48, 100%, 97%);
$title-color-deep: #292a36; $title-color-deep: #292a36;
@ -19,26 +19,3 @@ $error-color: #ec4e29;
$title-size: 0.32rem; $title-size: 0.32rem;
$font-size: 0.28rem; $font-size: 0.28rem;
$tip-size: 0.22rem; $tip-size: 0.22rem;
.el-radio__input.is-checked+.el-radio__label {
color: $font-color !important;
}
.el-switch.is-checked .el-switch__core {
border-color: $primary-color !important;
background-color: $primary-color !important;
}
.el-checkbox__input.is-checked .el-checkbox__inner,
.question-edit-wrapper .el-checkbox__input.is-indeterminate .el-checkbox__inner {
background-color: $primary-color !important;
border-color: $primary-color !important;
}
.el-checkbox__input.is-focus .el-checkbox__inner {
border-color: $primary-color !important;
}
.el-checkbox__input.is-checked+.el-checkbox__label {
color: $font-color !important;
}

View File

@ -1,3 +1,4 @@
@import './default.scss';
.star-wrapper-main { .star-wrapper-main {
// .isShowInput{ // .isShowInput{
// padding-bottom: 0 !important ; // padding-bottom: 0 !important ;

View File

@ -252,7 +252,7 @@ export default {
</script> </script>
<style lang="scss" rel="stylesheet/scss" scoped> <style lang="scss" rel="stylesheet/scss" scoped>
@import '../../common/css/default.scss'; // @import '../../common/css/default.scss';
.ceilingPopper { .ceilingPopper {
max-width: 1000px !important ; max-width: 1000px !important ;
} }

View File

@ -115,7 +115,7 @@ export default {
</script> </script>
<style lang="scss" rel="stylesheet/scss" scoped> <style lang="scss" rel="stylesheet/scss" scoped>
@import '../../common/css/default.scss'; // @import '../../common/css/default.scss';
.option-edit-wrap { .option-edit-wrap {
.focus { .focus {
margin-top: 31px; margin-top: 31px;

View File

@ -118,7 +118,7 @@ export default defineComponent({
}); });
</script> </script>
<style lang="scss" rel="stylesheet/scss" scoped> <style lang="scss" rel="stylesheet/scss" scoped>
@import '../../common/css/default.scss'; // @import '../../common/css/default.scss';
.option-edit-bar-wrap { .option-edit-bar-wrap {
margin-top: 20px; margin-top: 20px;

View File

@ -40,6 +40,7 @@ export default {
}; };
</script> </script>
<style lang="scss" rel="stylesheet/scss" scoped> <style lang="scss" rel="stylesheet/scss" scoped>
@import '../common/css/default.scss';
.process-outer { .process-outer {
position: relative; position: relative;
border-radius: 0.16rem; border-radius: 0.16rem;

View File

@ -0,0 +1,31 @@
<template>
<el-form-item class="pick-wrap">
<el-color-picker :value="formConfig.value" @change="changeData"></el-color-picker>
</el-form-item>
</template>
<script>
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant';
export default {
name: 'ColorPicker',
props: {
formConfig: {
type: Object,
required: true,
},
},
methods: {
changeData(value) {
const key = this.formConfig.key;
this.$emit(FORM_CHANGE_EVENT_KEY, {
key,
value,
});
},
},
};
</script>
<style lang="scss" scoped>
.pick-wrap{
text-align: end;
}
</style>

View File

@ -1,7 +1,7 @@
<template> <template>
<el-form-item <el-form-item
:class="{ :class="{
horizion: formConfig.direction === 'horizon', horizon: formConfig.direction === 'horizon',
space_between: formConfig.direction === 'space_between', space_between: formConfig.direction === 'space_between',
}" }"
> >
@ -46,4 +46,15 @@ export default {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
.space_between{
display: flex;
justify-content: space-between;
::v-deep> label{
flex: 1;
}
::v-deep> div{
flex: 1;
}
}
</style> </style>

View File

@ -1,5 +1,6 @@
<template> <template>
<el-input <el-input
class="custom-input"
:placeholder="formConfig.placeholder" :placeholder="formConfig.placeholder"
v-model="value" v-model="value"
@input="changeData" @input="changeData"
@ -67,4 +68,12 @@ export default {
}, },
}; };
</script> </script>
<style lang="scss" rel="stylesheet/scss" scoped></style> <style lang="scss" rel="stylesheet/scss" scoped>
.custom-input{
::v-deep .el-input__inner{
width: 100px;
padding-right: 0px;
}
}
</style>

View File

@ -0,0 +1,37 @@
<template>
<el-form-item class="slider-wrap">
<el-slider :value="formConfig.value" @input="changeData" :format-tooltip="formatTooltip"></el-slider>
<!-- <span>{{ formConfig.value + '%' }}</span> -->
</el-form-item>
</template>
<script>
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant';
export default {
name: 'SliderSetter',
props: {
formConfig: {
type: Object,
required: true,
},
},
methods: {
formatTooltip (val) {
return val + '%';
},
changeData(value) {
const key = this.formConfig.key;
this.$emit(FORM_CHANGE_EVENT_KEY, {
key,
value,
});
},
},
};
</script>
<style>
.slider-wrap{
flex: 1;
/* display: flex; */
padding: 0 20px;
}
</style>

View File

@ -1,7 +1,7 @@
<template> <template>
<div id="app"> <div id="app">
<Component v-if="$store.state.router" :is="$store.state.router"></Component> <Component v-if="$store.state.router" :is="$store.state.router"></Component>
<logo></logo> <logo v-if="!['successPage', 'indexPage'].includes($store.state.router)"></logo>
</div> </div>
</template> </template>
@ -14,6 +14,7 @@ import errorPage from './pages/errorPage.vue';
import successPage from './pages/successPage.vue'; import successPage from './pages/successPage.vue';
import logo from './components/logo.vue'; import logo from './components/logo.vue';
import { get as _get, value } from 'lodash-es'
export default { export default {
name: 'App', name: 'App',
@ -27,7 +28,16 @@ export default {
data() { data() {
return {}; return {};
}, },
computed: {}, computed: {
skinConf () {
return _get(this.$store, 'state.skinConf', {});
},
},
watch: {
skinConf(value) {
this.setSkin(value)
}
},
async created() { async created() {
this.init(); this.init();
}, },
@ -59,6 +69,7 @@ export default {
skinConf, skinConf,
submitConf, submitConf,
}; };
this.setSkin(skinConf)
this.$store.commit('setSurveyPath', surveyPath); this.$store.commit('setSurveyPath', surveyPath);
this.$store.dispatch('init', questionData); this.$store.dispatch('init', questionData);
this.$store.dispatch('getEncryptInfo'); this.$store.dispatch('getEncryptInfo');
@ -73,6 +84,20 @@ export default {
} }
} }
}, },
setSkin(skinConf) {
const { themeConf, backgroundConf, contentConf} = skinConf
const root = document.documentElement;
if(themeConf?.color) {
root.style.setProperty('--primary-color', themeConf?.color); //
}
if(backgroundConf?.color) {
root.style.setProperty('--primary-background-color', backgroundConf?.color); //
}
if(contentConf?.opacity.toString()) {
console.log({opacity: (contentConf?.opacity)/100})
root.style.setProperty('--opacity', (contentConf?.opacity)/100); //
}
}
}, },
}; };
</script> </script>
@ -86,10 +111,7 @@ html {
background: rgb(238, 238, 238); background: rgb(238, 238, 238);
} }
body,
.container {
height: 100%;
}
#app { #app {
position: relative; position: relative;
@ -97,7 +119,7 @@ body,
width: 100%; width: 100%;
max-width: 750px; max-width: 750px;
margin: auto; margin: auto;
min-height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;

View File

@ -32,7 +32,7 @@
<div class="iconfont icon-kaishi play-icon" @click="play()"></div> <div class="iconfont icon-kaishi play-icon" @click="play()"></div>
</div> </div>
</div> </div>
<div <!-- <div
class="titlePanel" class="titlePanel"
v-if="bannerConf.titleConfig && bannerConf.titleConfig.mainTitle" v-if="bannerConf.titleConfig && bannerConf.titleConfig.mainTitle"
> >
@ -41,7 +41,7 @@
v-if="bannerConf.titleConfig.mainTitle" v-if="bannerConf.titleConfig.mainTitle"
v-safe-html="bannerConf.titleConfig.mainTitle" v-safe-html="bannerConf.titleConfig.mainTitle"
></div> ></div>
</div> </div> -->
</div> </div>
</template> </template>
<script> <script>
@ -53,7 +53,7 @@ export default {
computed: { computed: {
bannerConf() { bannerConf() {
return _get(this.$store, 'state.bannerConf', {}); return _get(this.$store, 'state.bannerConf', {});
}, }
}, },
methods: { methods: {
onBannerClick() { onBannerClick() {
@ -90,6 +90,7 @@ export default {
} }
.banner { .banner {
display: flex;
.banner-img { .banner-img {
width: 100%; width: 100%;
@ -133,39 +134,3 @@ export default {
} }
} }
</style> </style>
<style lang="scss">
@import '@/render/styles/variable.scss';
.mainTitle {
font-size: 0.28rem;
line-height: 0.4rem;
color: $title-color;
ol {
list-style: decimal;
}
ul {
list-style: disc;
}
img {
width: 100%;
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
line-height: 0.6rem;
color: $title-color-deep;
margin-bottom: 0.35rem;
}
p {
margin-bottom: 0;
}
}
</style>

View File

@ -31,7 +31,6 @@ export default {
} }
.logo-wrapper { .logo-wrapper {
max-width: 300px;
text-align: center; text-align: center;
font-size: 0; font-size: 0;
padding: 0.1rem 0 0.5rem; padding: 0.1rem 0 0.5rem;

View File

@ -0,0 +1,68 @@
<template>
<div class="question-header">
<div
class="titlePanel"
v-if="bannerConf.titleConfig && bannerConf.titleConfig.mainTitle"
>
<div
class="mainTitle"
v-if="bannerConf.titleConfig.mainTitle"
v-safe-html="bannerConf.titleConfig.mainTitle"
></div>
</div>
</div>
</template>
<script>
import { get as _get } from 'lodash-es';
export default {
name: 'mainTitle',
computed: {
bannerConf() {
return _get(this.$store, 'state.bannerConf', {});
}
},
}
</script>
<style lang="scss" scoped>
@import '@/render/styles/variable.scss';
.question-header {
.titlePanel {
position: relative;
width: 100%;
padding: 0.4rem 0.4rem;
box-sizing: border-box;
}
}
.mainTitle {
font-size: 0.28rem;
line-height: 0.4rem;
color: $title-color;
ol {
list-style: decimal;
}
ul {
list-style: disc;
}
img {
width: 100%;
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
line-height: 0.6rem;
color: $title-color-deep;
margin-bottom: 0.35rem;
}
p {
margin-bottom: 0;
}
}
</style>

View File

@ -2,7 +2,6 @@
<div class="question-submit_wrapper"> <div class="question-submit_wrapper">
<button <button
class="question-submit-btn" class="question-submit-btn"
:style="{ backgroundColor: skinConf.skinColor }"
@click="submit" @click="submit"
> >
{{ submitConf.submitTitle }} {{ submitConf.submitTitle }}
@ -60,9 +59,9 @@ export default {
font-weight: 500; font-weight: 500;
text-align: center; text-align: center;
color: #fff; color: #fff;
background: $primary-color; background: var(--primary-color);
border-radius: 0.08rem; border-radius: 0.08rem;
margin-top: 0.4rem; margin: 0.4rem 0;
cursor: pointer; cursor: pointer;
} }
} }

View File

@ -1,8 +1,12 @@
<template> <template>
<div class="error-wrapper"> <div class="result-page-wrap">
<img class="error-img" :src="errorImageUrl" /> <div class="result-page">
<div class="bottom-word" v-html="errorMsg"></div> <div class="error-wrapper">
</div> <img class="error-img" :src="errorImageUrl" />
<div class="bottom-word" v-html="errorMsg"></div>
</div>
</div>
</div>
</template> </template>
<script> <script>
export default { export default {
@ -29,6 +33,22 @@ export default {
}; };
</script> </script>
<style lang="scss" rel="stylesheet/scss" scoped> <style lang="scss" rel="stylesheet/scss" scoped>
.result-page-wrap {
width: 100%;
flex: 1;
text-align: center;
overflow: hidden;
background: var(--primary-background-color);
padding: 0 0.3rem;
.result-page{
background: rgba(255, 255, 255, var(--opacity));
display: flex;
flex-direction: column;
height: 100%;
}
}
.error-wrapper { .error-wrapper {
text-align: center; text-align: center;
font-size: 14px; font-size: 14px;

View File

@ -1,23 +1,31 @@
<template> <template>
<div class="index"> <div class="index">
<progressBar /> <progressBar />
<Header></Header> <div class="wrapper" ref="box">
<mainRenderer ref="main"></mainRenderer> <Header></Header>
<submit <div class="content">
:validate="validate" <mainTitle></mainTitle>
:renderData="renderData" <mainRenderer ref="main"></mainRenderer>
@submit="onSubmit" <submit
></submit> :validate="validate"
:renderData="renderData"
@submit="onSubmit"
></submit>
<logo></logo>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import Header from '../components/header.vue'; import Header from '../components/header.vue';
import mainTitle from '../components/mainTitle.vue'
import submit from '../components/submit.vue'; import submit from '../components/submit.vue';
import mainRenderer from '../components/mainRenderer'; import mainRenderer from '../components/mainRenderer';
import progressBar from '../components/progressBar'; import progressBar from '../components/progressBar';
import { submitForm } from '@/render/api/survey'; import { submitForm } from '@/render/api/survey';
import encrypt from '../utils/encrypt'; import encrypt from '../utils/encrypt';
import logo from '../components/logo.vue';
export default { export default {
name: 'indexPage', name: 'indexPage',
@ -33,9 +41,11 @@ export default {
}, },
components: { components: {
Header, Header,
mainTitle,
submit, submit,
mainRenderer, mainRenderer,
progressBar, progressBar,
logo,
}, },
computed: { computed: {
formModel() { formModel() {
@ -121,6 +131,20 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.index { .index {
padding-bottom: 0.8rem; // padding-bottom: 0.8rem;
min-height: 100%;
.wrapper{
min-height: 100%;
background-color: var(--primary-background-color);
display: flex;
flex-direction: column;
.content{
flex: 1;
margin: 0 0.3rem;
background: rgba(255, 255, 255, var(--opacity));
border-radius: 8px 8px 0 0;
height: 100%;
}
}
} }
</style> </style>

View File

@ -1,14 +1,19 @@
<template> <template>
<div class="result-page"> <div class="result-page-wrap">
<div class="result-content"> <div class="result-page">
<img src="/imgs/icons/success.webp" /> <div class="result-content">
<div class="msg" v-safe-html="successMsg"></div> <img src="/imgs/icons/success.webp" />
<div class="msg" v-safe-html="successMsg"></div>
</div>
<logo></logo>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import logo from '../components/logo.vue';
export default { export default {
name: 'resultPage', name: 'resultPage',
components: {logo},
computed: { computed: {
submitConf() { submitConf() {
return this.$store?.state?.submitConf || {}; return this.$store?.state?.submitConf || {};
@ -22,11 +27,20 @@ export default {
<style lang="scss" rel="stylesheet/scss" scoped> <style lang="scss" rel="stylesheet/scss" scoped>
@import '@/render/styles/variable.scss'; @import '@/render/styles/variable.scss';
.result-page { .result-page-wrap {
width: 100%; width: 100%;
flex: 1; flex: 1;
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
background: var(--primary-background-color);
padding: 0 0.3rem;
.result-page{
background: rgba(255, 255, 255, var(--opacity));
display: flex;
flex-direction: column;
height: 100%;
}
} }
.result-content { .result-content {
@ -37,7 +51,7 @@ export default {
width: 100%; width: 100%;
position: relative; position: relative;
padding-top: 2rem; padding-top: 2rem;
background: #fff; flex: 1;
img { img {
width: 2rem; width: 2rem;