refactor(css): 重构样式文件并优化主题样式

- 新增 theme.scss 文件,定义主题颜色- 新增 public.scss 文件,统一公共样式
- 修改 main.scss 文件,引入新的样式文件
-优化容器背景色渐变效果- 调整导航栏样式,增加面包屑导航
-统一问题类型样式,优化选择题样式
This commit is contained in:
陈昱达
2025-03-14 13:42:32 +08:00
parent b46104fa10
commit 10981d439f
15 changed files with 240 additions and 468 deletions

4
components.d.ts vendored
View File

@@ -17,14 +17,18 @@ declare module 'vue' {
VanCellGroup: typeof import('vant/es')['CellGroup']
VanCheckbox: typeof import('vant/es')['Checkbox']
VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
VanCol: typeof import('vant/es')['Col']
VanDivider: typeof import('vant/es')['Divider']
VanField: typeof import('vant/es')['Field']
VanGrid: typeof import('vant/es')['Grid']
VanGridItem: typeof import('vant/es')['GridItem']
VanIcon: typeof import('vant/es')['Icon']
VanNavBar: typeof import('vant/es')['NavBar']
VanPicker: typeof import('vant/es')['Picker']
VanPopup: typeof import('vant/es')['Popup']
VanRadio: typeof import('vant/es')['Radio']
VanRadioGroup: typeof import('vant/es')['RadioGroup']
VanRow: typeof import('vant/es')['Row']
VanSearch: typeof import('vant/es')['Search']
VanStepper: typeof import('vant/es')['Stepper']
VanSwitch: typeof import('vant/es')['Switch']

View File

@@ -1,7 +1,8 @@
@import 'theme';
@import 'base';
@import '../../fonts/iconfont.css';
@import 'vant';
@import '../../fonts/moblie/iconfont.css';
@import 'public';
a,
.green {
@@ -15,6 +16,12 @@ a,
margin-left: 10px;
}
.container {
//width: 100%;
// 绿色 #70B937 白色过渡渐变 竖向 上一半部分 渐变到白色就可以
background: linear-gradient(to bottom, $theme-color 200px, #f2f2f2 300px);
}
@media (hover: hover) {
a:hover {
background-color: hsla(160deg, 100%, 37%, 0.2);

View File

@@ -0,0 +1,33 @@
.van-cell {
padding: 8px !important;
}
.van-divider {
margin: 5px 0 !important;
}
.van-popup--bottom.van-popup--round {
border-radius: 10px 10px 0 0 !important;
}
.van-radio-group {
& .van-radio {
.van-radio__icon--checked {
.van-icon {
border-color: $theme-color;
background-color: $theme-color;
}
}
}
}
.van-checkbox-group {
& .van-checkbox {
.van-checkbox__icon--checked {
.van-icon {
border-color: $theme-color;
background-color: $theme-color;
}
}
}
}

View File

@@ -0,0 +1 @@
$theme-color: #71b73c;

View File

@@ -1,11 +0,0 @@
.van-cell {
padding: 8px !important;
}
.van-divider {
margin: 5px 0 !important;
}
.van-popup--bottom.van-popup--round {
border-radius: 10px 10px 0 0 !important;
}

View File

@@ -30,9 +30,9 @@
<script setup>
import { RouterView, useRouter } from 'vue-router';
import { ref } from 'vue';
// import utils from '@/assets/js/common';
// import { getUserInfo } from '@/api/common/index.js';
// import { showFailToast } from 'vant';
import utils from '@/assets/js/common';
import { getUserInfo } from '@/api/common/index.js';
import { showFailToast } from 'vant';
const router = useRouter();
const active = ref();
@@ -59,28 +59,29 @@ const table = [
}
];
function tabPath(path) {
router.push({
path
});
// if (utils.getParameter('digitalYiliToken')) {
// const appToken = utils.getParameter('digitalYiliToken');
// getUserInfo(appToken).then((res) => {
// if (res.data) {
// utils.setSessionStorage('userInfo', res.data.data);
// router.push({
// path
// });
// } else {
// showFailToast(error.response.data?.message || error.data?.message || error.message || '服务器错误');
// }
// }).catch((error) => {
// showFailToast(error?.response?.data?.message || error?.message || '服务器错误');
// });
// } else {
// router.push({
// path
// });
// }
if (utils.getParameter('digitalYiliToken')) {
const appToken = utils.getParameter('digitalYiliToken');
getUserInfo(appToken)
.then((res) => {
if (res.data) {
utils.setSessionStorage('userInfo', res.data.data);
router.push({
path
});
} else {
showFailToast(
error.response.data?.message || error.data?.message || error.message || '服务器错误'
);
}
})
.catch((error) => {
showFailToast(error?.response?.data?.message || error?.message || '服务器错误');
});
} else {
router.push({
path
});
}
}
</script>

View File

@@ -46,13 +46,13 @@ function showModal(options) {
* @param {*} data
* @returns
*/
const canPlanetPublishPSM = function(data) {
const canPlanetPublishPSM = function (data) {
let isFb = true;
let content = '';
let title = '题目设置未完成';
const incompleteQuestionList = [];
data.questions
&& data.questions.forEach((s) => {
data.questions &&
data.questions.forEach((s) => {
if (s.question_type === 101 && s.config.price_gradient.length <= 0) {
isFb = false;
content = 'psm题目未完成设置请设置价格区间后投放';
@@ -77,15 +77,15 @@ const canPlanetPublishPSM = function(data) {
* @param {*} data
* @returns
*/
const canPlanetPublishMxdAndHotArea = function(data) {
const canPlanetPublishMxdAndHotArea = function (data) {
let isFb = true;
let content = '';
const qSteams = [];
const incompleteQuestionList = [];
let type = 0;
let title = '题目设置未完成';
data.questions
&& data.questions.forEach((s) => {
data.questions &&
data.questions.forEach((s) => {
if (s.question_type === 105 && s.config.design_version <= 0) {
isFb = false;
content = 'maxdiff题目未完成设置请生成设计后投放';
@@ -124,14 +124,14 @@ const canPlanetPublishMxdAndHotArea = function(data) {
* @param {*} data
* @returns
*/
const canPlanetPublish3D = function(data) {
const canPlanetPublish3D = function (data) {
{
let canFB = true;
let content = '';
const qSteams = [];
let title = '';
data.questions
&& data.questions.forEach((s) => {
data.questions &&
data.questions.forEach((s) => {
if (QUESTION_TYPE.contains(s.question_type)) {
try {
if (s.config.is_three_dimensions && !s.config.scene) {
@@ -161,15 +161,15 @@ const canPlanetPublish3D = function(data) {
let content = '';
const qSteams = [];
let title = '';
data.questions
&& data.questions.forEach((s) => {
data.questions &&
data.questions.forEach((s) => {
if (QUESTION_TYPE.contains(s.question_type)) {
try {
if (s.config.is_three_dimensions && s.config.is_binding_goods) {
const wares = [];
const _sceneInformation = s.config.scene_information;
const sceneInformation
= typeof _sceneInformation === 'string'
const sceneInformation =
typeof _sceneInformation === 'string'
? JSON.parse(_sceneInformation)
: _sceneInformation;
sceneInformation.shelves.forEach((shelf) => {
@@ -221,14 +221,14 @@ const canPlanetPublish3D = function(data) {
* @param {*} data
* @returns
*/
const canPlanetPublishImage = function(data) {
const canPlanetPublishImage = function (data) {
{
let canFB = true;
let content = '';
const qSteams = [];
let title = '';
data.questions
&& data.questions.forEach((s) => {
data.questions &&
data.questions.forEach((s) => {
if (s.question_type === 13) {
try {
if (s.options.length <= 0 || s.options.some((y) => y.length <= 0)) {
@@ -236,7 +236,7 @@ const canPlanetPublishImage = function(data) {
qSteams.push(`(${s.title})`);
}
} catch (error) {
console.warn(error);
// 错误返回
}
}
});
@@ -323,8 +323,8 @@ function canPublishRandom(data, publishType) {
if (!isValidated) {
errors.push({
message:
field.message
|| `请填写“${random.title}”中第${index + 1}组“随机题组”的“${field.name}`
field.message ||
`请填写“${random.title}”中第${index + 1}组“随机题组”的“${field.name}`
});
}
});
@@ -378,7 +378,7 @@ function canPublishRandom(data, publishType) {
// return false;
// }
export const canPlanetPublish = async function(sn, publishType) {
export const canPlanetPublish = async function (sn, publishType) {
const parsedPublishType = !publishType ? 2 : publishType;
const num = window.location.href.indexOf('code=');

View File

@@ -3,9 +3,10 @@ import 'amfe-flexible';
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import 'vant/lib/index.css';
import router from './router';
// 2. 引入组件样式
import 'vant/lib/index.css';
import appBridge from '@/assets/js/appBridge';
router.beforeEach((to, from, next) => {
appBridge.setTitle(to.meta.title as string);

View File

@@ -1,331 +1,87 @@
import {
radio,
checkbox,
completion,
rate,
martrixQuestion,
fileUpload,
textWithImages,
signQuestion,
nps
} from '@/utils/importJsons';
const basicQuesTypeList = [
{
name: '选择题',
icon: '&#xe6d3;',
check: false,
type: 1,
childTypes: [1, 2]
icon: '&#xe75b;',
name: '单选题',
question_type: 1,
json: radio
},
{
name: '级联题',
icon: '&#xe6b6;',
check: false,
type: 3,
childTypes: [3]
icon: '&#xe6c3;',
name: '多选题',
question_type: 2,
json: checkbox
},
{
name: '填空题',
icon: '&#xe6c2;',
check: false,
type: 4,
childTypes: [4]
},
{
name: '多项填空题',
icon: '&#xe850;',
check: false,
type: 27,
childTypes: [27]
},
{
name: '打分题',
icon: '&#xe6c1;',
check: false,
type: 5,
childTypes: [5]
},
{
name: '矩阵题',
icon: '&#xe71c;',
check: false,
type: 9,
childTypes: [8, 9, 10, 11]
},
{
name: '图片题',
icon: '&#xe71e;',
check: false,
type: 13,
childTypes: [12, 13, 14]
},
{
name: '分类题',
icon: '&#xe700;',
check: false,
type: 15,
childTypes: [15]
},
{
name: '排序题',
icon: '&#xe71d;',
check: false,
type: 16,
childTypes: [16]
},
{
name: '图文说明题',
icon: '&#xe6d0;',
check: false,
type: 6,
childTypes: [6]
},
{
name: '日期/时间',
icon: '&#xe6ac;',
check: false,
type: 7,
childTypes: [7]
},
{
name: '恒定总和题',
icon: '&#xe6ff;',
check: false,
type: 17,
childTypes: [17]
},
{
name: '文件上传题',
icon: '&#xe6f9;',
check: false,
type: 18,
childTypes: [18]
},
{
name: '热区题',
icon: '&#xe834;',
check: false,
type: 25,
childTypes: [25, 56]
},
{
name: 'NPS',
icon: '&#xe833;',
check: false,
type: 106,
childTypes: [106]
}
];
const quickQuesTypeList = [
{
name: '姓名',
icon: '&#xe713;',
check: false,
type: 4,
quickType: 6
},
{
name: '性别',
icon: '&#xe716;',
check: false,
type: 1,
quickType: 7
},
{
name: '手机号',
icon: '&#xe638;',
check: false,
type: 20
},
{
name: '身份证号',
icon: '&#xe6ba;',
check: false,
type: 4,
quickType: 2
},
{
name: '邮箱',
icon: '&#xe70b;',
check: false,
type: 4,
quickType: 8
},
{
name: '年龄',
icon: '&#xe701;',
check: false,
type: 4,
quickType: 9
},
{
name: '年龄段',
icon: '&#xe6fb;',
check: false,
type: 1,
quickType: 10
},
{
name: '生日',
icon: '&#xe729;',
check: false,
type: 7,
quickType: 11
},
{
name: '学历',
icon: '&#xe712;',
check: false,
type: 1,
quickType: 12
},
{
name: '院校',
icon: '&#xe718;',
check: false,
type: 3,
quickType: 13
},
{
name: '专业',
icon: '&#xe705;',
check: false,
type: 3,
quickType: 14
},
{
name: '行业',
icon: '&#xe715;',
check: false,
type: 1,
quickType: 15
},
{
name: '地理位置',
icon: '&#xe6fd;',
check: false,
type: 19,
quickType: 16
},
{
name: '省份',
icon: '&#xe6b8;',
check: false,
type: 3,
quickType: 3
},
{
name: '省市',
icon: '&#xe6bd;',
check: false,
type: 3,
quickType: 4
},
{
name: '省市区/县',
icon: '&#xe6cb;',
check: false,
type: 3,
quickType: 5
name: '填空题',
question_type: 4,
json: completion
},
// {
// type: 21,
// quickType: 21,
// name: "密码",
// icon: "&#xe639;",
// check: false,
// icon: 'phone-o',
// name: '图形打分',
// question_type: '4',
// json: rate
// },
{
type: 22,
name: '签名题',
icon: '&#xe637;',
check: false
icon: '&#xe641;',
name: '数值打分',
question_type: 5,
json: rate
},
{
type: 23,
name: '知情同意书',
icon: '&#xe63a;',
check: false
}
];
const advancedQuesTypeList = [
{
name: 'Maxdiff',
icon: '&#xe70c;',
check: false,
type: 105
},
// {
// name: "CBC",
// icon: "&#xe70d;",
// check: false,
// type: 103,
// },
// // {
// // name: "BPTO",
// // icon: "&#xe70d;",
// // check: false,
// // type: 104,
// // },
{
name: 'PSM',
icon: '&#xe708;',
check: false,
type: 101
icon: '&#x13c7f;',
name: '矩阵单选',
question_type: 9,
json: martrixQuestion
},
{
name: 'KANO',
icon: '&#xe710;',
check: false,
type: 102
}
];
const d3QuestypeList = [
{
name: 'ID test',
icon: '&#xe762;',
check: false,
type: 200
icon: '&#xe818;',
name: '矩阵多选',
question_type: 10,
json: martrixQuestion
},
{
name: 'Experiment',
icon: '&#xe765;',
check: false,
type: 201
}
];
const uxSimuatorQuestypeList = [
{
name: 'UI',
icon: '&#xe764;',
check: false,
type: 202
icon: '&#xe62e;',
name: '矩阵填空',
question_type: 8,
json: martrixQuestion
},
{
name: 'Prototype',
icon: '&#xe763;',
check: false,
type: 203
icon: '&#xe631;',
name: '文件上传',
question_type: 18,
json: fileUpload
},
{
name: 'UE',
icon: '&#xe761;',
check: false,
type: 204
icon: '&#xe62c;',
name: '图文说明',
question_type: 6,
json: textWithImages
},
{
icon: '&#xe661;',
name: '签名',
question_type: 22,
json: signQuestion
},
{
icon: '&#xe6b0;',
name: 'NPS',
question_type: 106,
json: nps
}
];
function getIcon(item) {
let icon = '';
if (item.config.quick_type === 0) {
icon = basicQuesTypeList?.find((x) => x?.childTypes.includes(item?.question_type))?.icon || '';
if (!icon) {
icon = quickQuesTypeList?.find((x) => x?.type === item?.question_type)?.icon || '';
}
} else {
icon = quickQuesTypeList?.find((x) => x?.quickType === item?.config?.quick_type)?.icon || '';
}
if (!icon) {
icon = advancedQuesTypeList?.find((x) => x?.type === item?.question_type)?.icon || '';
}
return icon;
}
module.exports = {
basicQuesTypeList,
quickQuesTypeList,
advancedQuesTypeList,
d3QuestypeList,
uxSimuatorQuestypeList,
getIcon
};
export { basicQuesTypeList };

View File

@@ -439,7 +439,7 @@ onMounted(() => {
.design-create {
//min-height: calc(100vh);
background-color: #e9eef3;
//background-color: #e9eef3;
color: #333;
.slot-actions {

View File

@@ -1,5 +1,5 @@
<template>
<div class="container question-action-container flex">
<div class="question-action-container flex">
<van-icon name="clear" @click="deleteQuestion"></van-icon>
<van-icon name="setting" @click="openQuestionSettingModel"></van-icon>
<van-icon name="more" @click="openQuestionActionModel"></van-icon>

View File

@@ -6,6 +6,11 @@
:class="chooseQuestionId === element.id ? 'choose-question-active' : ''"
@click="chooseItem"
>
<van-cell>
<template #title>
<span class="title"> {{ getQuestionType(element.question_type) }}</span>
</template>
</van-cell>
<slot></slot>
<!-- 题目操作-->
<van-cell v-if="chooseQuestionId === element.id" class="choose-question-active-container">
@@ -36,6 +41,8 @@
import QuestionAction from '@/views/Design/components/ActionCompoents/QuestionAction.vue';
import { ref } from 'vue';
import { basicQuesTypeList } from '@/utils/common.js';
const props = defineProps({
element: {
type: Object,
@@ -60,6 +67,18 @@ const props = defineProps({
default: true
}
});
// 获取题目选项
const getQuestionType = (type) => {
let typeName = null;
basicQuesTypeList.map((item) => {
if (Number(item.question_type) === Number(type)) {
typeName = item.name;
}
});
return typeName;
};
const element = ref(props.element);
// 选中题目后出现的操作
@@ -72,12 +91,35 @@ const chooseItem = () => {
};
</script>
<style scoped lang="scss">
@import '@/assets/css/theme';
.choose-question-container {
padding: 5px;
padding: 12px;
& .choose-question-context {
overflow: hidden;
border-radius: 5px;
padding: 10px;
border-radius: 8px;
background: #fff;
& .title {
position: relative;
font-weight: 700;
font-size: 14px;
&::after {
content: ' ';
position: absolute;
//padding: 0 5px;
bottom: -4px;
left: -1px;
width: 100%;
height: 7px;
border-radius: 5px;
background: linear-gradient(to right, $theme-color 10%, #f2f2f2 100%);
}
}
}
& .choose-question-active {

View File

@@ -41,7 +41,7 @@
</template>
</option-action>
</van-radio-group>
<van-checkbox-group v-if="element.question_type === 2" shape="square">
<van-checkbox-group v-if="element.question_type === 2" v-model="value" shape="square">
<option-action
v-model:data="element.options[optionIndex]"
:active="active"
@@ -96,6 +96,7 @@ const props = defineProps({
}
});
const { element } = toRefs(props);
const value = ref([]);
const emit = defineEmits(['update:element']);
const emitValue = () => {
emit('update:element', element.value);

View File

@@ -12,7 +12,8 @@ interface OptionConfigType {
}
interface OptionType {
option?: string; // 包含 HTML 标签的字符串,例如 "<p>选项1</p>"
// 包含 HTML 标签的字符串,例如 "<p>选项1</p>"
option?: string;
is_other?: number;
is_fixed?: number;
is_remove_other?: number;

View File

@@ -1,8 +1,8 @@
<template>
<div class="container">
<van-nav-bar :title="surveyTitle" left-text="" left-arrow @click-left="$router.go(-1)">
<template #right>
<van-icon name="ellipsis" size="18" />
<template #left>
<van-icon name="arrow-left" size="18" style="color: #fff" />
</template>
</van-nav-bar>
@@ -298,17 +298,7 @@ import Design from '@/views/Design/Index.vue';
import { useCounterStore } from '@/stores/counter';
import { storeToRefs } from 'pinia';
import { v4 as uuidv4 } from 'uuid';
import {
radio,
checkbox,
completion,
rate,
martrixQuestion,
fileUpload,
textWithImages,
signQuestion,
nps
} from '@/utils/importJsons';
import { basicQuesTypeList } from '@/utils/common';
import { useRoute, useRouter } from 'vue-router';
import YLPicker from '@/components/YLPicker.vue';
import { getPages } from '@/utils/public';
@@ -370,80 +360,7 @@ const saveTitle = () => {
});
};
const quesList = ref([
{
icon: '&#xe75b;',
name: '单选题',
question_type: '1',
json: radio
},
{
icon: '&#xe6c3;',
name: '多选题',
question_type: 2,
json: checkbox
},
{
icon: '&#xe6fd;',
name: '填空题',
question_type: 4,
json: completion
},
// {
// icon: 'phone-o',
// name: '图形打分',
// question_type: '4',
// json: rate
// },
{
icon: '&#xe641;',
name: '数值打分',
question_type: 5,
json: rate
},
{
icon: '&#x13c7f;',
name: '矩阵单选',
question_type: 9,
json: martrixQuestion
},
{
icon: '&#xe818;',
name: '矩阵多选',
question_type: 10,
json: martrixQuestion
},
{
icon: '&#xe62e;',
name: '矩阵填空',
question_type: 8,
json: martrixQuestion
},
{
icon: '&#xe631;',
name: '文件上传',
question_type: 18,
json: fileUpload
},
{
icon: '&#xe62c;',
name: '图文说明',
question_type: 6,
json: textWithImages
},
{
icon: '&#xe661;',
name: '签名',
question_type: 22,
json: signQuestion
},
{
icon: '&#xe6b0;',
name: 'NPS',
question_type: 106,
json: nps
}
]);
const quesList = ref(basicQuesTypeList);
const questionEvent = (item) => {
let questionJson = {};
@@ -457,14 +374,14 @@ const questionEvent = (item) => {
options:
item.json.options.length > 0
? item.json.options.map((item) => {
return item.map((it) => {
return {
...it,
// 主键生成
id: uuidv4()
};
});
})
return item.map((it) => {
return {
...it,
// 主键生成
id: uuidv4()
};
});
})
: []
})
);
@@ -597,14 +514,31 @@ const previewQuestion = () => {
router.push({ name: 'preview', query: { ...route.query } });
};
onMounted(async() => {
onMounted(async () => {
await getQuestionDetail();
});
</script>
<style scoped lang="scss">
::v-deep .van-nav-bar {
background-color: #70b937;
color: #fff;
& .van-nav-bar__content {
color: #fff;
& .van-nav-bar__title {
color: #fff;
}
}
}
::v-deep .van-hairline--bottom::after {
display: none;
}
.container {
height: 100vh;
//height: 100vh;
background-color: #f5f5f5;
button {
@@ -652,6 +586,8 @@ onMounted(async() => {
}
.ques {
min-height: 70vh;
.ques_title {
margin: 20px 0 10px 20px;
font-weight: bold;