feat: 完成预览界面

- 调整 preview 组件
- 增加问卷提交成功的 success 组件
- 为 design 组件设置预览时取消调整选题设置
- 建立 axios 工具库
- 配置相关的代理内容
- 增加 lodash-es 和 axios 库
- design 页面添加获取远程题目
This commit is contained in:
Huangzhe
2025-03-10 14:54:50 +08:00
parent 54c06913d6
commit 97b7d646e4
11 changed files with 290 additions and 18 deletions

View File

@@ -14,8 +14,10 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"axios": "^1.8.2",
"element-plus": "^2.7.8",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"pinia": "^2.1.7",
"sortablejs": "^1.15.6",
"uuid": "^11.1.0",

11
src/config.ts Normal file
View File

@@ -0,0 +1,11 @@
export default {
proxyUrl: process.env.VUE_APP_BASEURL,
proxyUrlDelivery: process.env.VUE_APP_DELiVERY_BASEURL,
proxyUrlMessageCenter: process.env.VUE_APP_MESSAGE_CENTER,
baseOss: process.env.VUE_APP_BASEOSS,
loginUrl: process.env.VUE_APP_LOGIN,
socketUrl: process.env.VUE_APP_SOCKETURL,
jsonpUrl: process.env.VUE_APP_JSONPURL,
jqrUrl: process.env.VUE_APP_YQRURL,
currentMode: process.env.VUE_APP_CURRENTMODE
};

View File

@@ -0,0 +1 @@
export const surveyQuestion = '/api/api/console/surveys/RWNK9BYp/questions';

View File

@@ -0,0 +1,81 @@
import axios from 'axios';
// import router from '@/router/index';
// import { A_COMMON_CLEAR_TOKEN } from '@/stores/constance/constance.common.js';
// const baseURL = process.env.NODE_ENV === 'production' ? proxyUrl : '/api';
// axios.defaults.withCredentials = true;
// create an axios instance
const service = axios.create({
// baseURL: `${baseURL}`, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 30000 // request timeout
});
// request interceptor
service.interceptors.request.use(
(config) => {
if (!config.headers) {
config.headers.Accept = 'application/json';
}
config.headers.Authorization = `${localStorage.getItem('plantToken')}`;
// if (!config.headers.remoteIp) {
// config.baseURL += '/api';
// }
// config.headers.remoteIp = localStorage.getItem('plantIp') || '127.0.0.1';
// if (store.state.common.token) {
// config.headers['Login-Type'] = 'pc';
// config.headers.Authorization = `Bearer ${store.state.common.token}`;
// }
return config;
},
(error) => Promise.reject(error)
);
// response interceptor
service.interceptors.response.use(
(response) => {
if (response.status === 200 || response.status === 201 || response.status === 202 || response.status === 204) {
if (response.config.method === 'put') {
// message.success('保存中...');
}
return Promise.resolve(response);
}
// return Promise.reject(/* new Error(response.message || 'Error') */);
}
// (error) => {
// // for debug
// if (error.response.status === 401) {
// const query = router.currentRoute.value.query;
// //关闭已弹出的所有弹框,防止弹框重叠
// // Modal.destroyAll();
// store.dispatch(A_COMMON_CLEAR_TOKEN);
// window.parent.postMessage(
// {
// code: '301',
// params: {}
// },
// '*'
// );
// store.commit('common/M_COMMON_SET_TOKEN_UNAUTHORIZED', false);
// } else if (error.response.status === 403) {
// router.push({
// path: '/error/403'
// });
// } else if (error.response.status === 404) {
// router.push({
// path: '/error/404'
// });
// } else if (error.response.status === 500) {
// router.push({
// path: '/error/500'
// });
// } else {
// // message.error(error.response.data?.message || '服务器错误');
// }
// return Promise.reject(error.response);
// }
);
export { service as http };

View File

@@ -4,6 +4,8 @@ import { defineStore } from 'pinia';
// 如果没有现成的 uid 函数,可以引入一个 UUID 库
// 或者使用其他 UUID 库
import { v4 as uuidv4 } from 'uuid';
import { http } from '@/request/axios';
import { surveyQuestion } from '@/request/api/modules/survey';
export const useCommonStore = defineStore('common', {
state: () => ({
@@ -257,19 +259,18 @@ export const useCommonStore = defineStore('common', {
question_id: '17852294'
}
],
questions: [],
cycle_pages: null
}
} as QuestionsInfo
}),
actions: {
async fetchQuestionInfo(questionInfo) {
async fetchQuestionInfo(questionInfo: string) {
try {
if (!questionInfo) return;
const info = JSON.parse(questionInfo);
if (info?.questions?.length) {
info.questions.forEach((page) => {
info.questions.forEach((page:any) => {
// 使用 UUID 生成唯一 ID
if (page?.page) {
page.pageId = page.pageId || uuidv4();
@@ -281,8 +282,21 @@ export const useCommonStore = defineStore('common', {
// 未来扩展
}
},
setQuestionInfo(questionInfo) {
setQuestionInfo(questionInfo: QuestionsInfo) {
this.questionsInfo = questionInfo;
},
/**
* web 端测试问卷地址 `/api/api/console/surveys/RWNK9BYp/questions`
* 做了个测试,后面再改
*/
fetchSurveyQuestion() {
http.get(surveyQuestion).then(res => {
// console.log('http get request:',res.data.data);
this.setQuestionInfo(res.data.data);
});/* .catch(res=>{
// console.log('catch',res);
this.setQuestionInfo(res);
}) */
}
},
getters: {

82
src/stores/modules/types/survey.d.ts vendored Normal file
View File

@@ -0,0 +1,82 @@
interface QuestionLogic {
value?: string;
location?: number;
date?: string;
time?: string;
type?: number;
row_type?: number;
cell_type?: number;
logic?: string;
operator?: string;
is_answer?: number;
is_select?: number;
row_index?: number;
cell_index?: number;
question_type?: number;
question_index?: number;
relation_question_index?: number;
relation_question_row_index?: number;
relation_question_cell_index?: number;
is_option_group?: number;
option_index?: number;
skip_type?: null | number;
question_id?: null | string;
}
interface Logic {
logic?: QuestionLogic[];
skip_question_index?: number;
skip_type?: number;
id?: number | string;
question_index?: number;
question_id?: string;
}
interface LocalPage {
pages?: number[];
is_short_time?: number;
short_time?: string;
is_show?: number;
use_type?: number;
}
interface Survey {
id?: number;
introduction?: string;
pages?: number[][];
sn?: string;
status?: number;
title?: string;
detail_pages?: number[][];
group_pages?: number[][];
is_one_page_one_question?: number;
last_question_index?: number;
is_three_d_permissions?: number;
is_dept?: number;
last_title?: string;
project_name?: string;
quota_end_content?: string;
quota_end_url?: string;
quota_end_url_select?: number;
quota_standing_time?: number;
screening_end_content?: string;
screening_end_url?: string;
screening_end_url_select?: number;
screening_standing_time?: number;
end_jump_url?: string;
end_jump_status?: number;
end_jump_standing_time?: number;
success_end_content?: string;
success_end_url?: string;
success_end_url_select?: number;
success_standing_time?: number;
template_type?: number;
local_pages?: LocalPage[];
}
interface QuestionsInfo {
survey?: Survey;
logics?: Logic[];
questions?: any[];
cycle_pages?: null | any;
}

View File

@@ -14,6 +14,8 @@
:questions="questionInfo.questions"
:index="index"
:chooseQuestionId="chooseQuestionId"
:show-actions="!preview"
style="margin: 10px 0"
@get-choose-question-id="getChooseQuestionId"
>
<!-- 选择题 -->
@@ -102,7 +104,7 @@
<!-- {{ element.question_type }}-->
<!-- {{questionInfo.survey.pages.length}}-->
<div v-if="!filterGap">
<div v-if="!preview">
<paging
v-if="!element.question_type && questionInfo.survey.pages.length > 1" :info="element" :index="index"
:active="pageIsActive(activeIndex, questionInfo.questions, element.page)" @click.stop=""
@@ -128,8 +130,10 @@ import TextWithImages from '@/views/Design/components/Questions/TextWithImages.v
import SignQuestion from './components/Questions/SignQuestion.vue';
import FileUpload from './components/Questions/FileUpload.vue';
import NPS from '@/views/Design/components/Questions/NPS.vue';
import { useCommonStore } from '@/stores/modules/common';
const activeIndex = ref(-1);
/**
* 工具函数
*/
@@ -176,9 +180,13 @@ function util() {
};
}
// 获取所有的 question 列表内容
const { filterGap } = defineProps({
filterGap: {
/**
* 该组件用于展示和操作问卷中的问题。
* @description 过滤Gap栏
* @type {boolean} 默认为 false
*/
const { preview } = defineProps({
preview: {
type: Boolean,
required: false,
default: false
@@ -188,18 +196,23 @@ const { filterGap } = defineProps({
const { pageIsActive } = util();
// 获取 Store 实例
const counterStore = useCounterStore();
const store = storeToRefs(counterStore);
const { questionsInfo: questionInfo } = storeToRefs(counterStore);
const chooseQuestionId = ref('');
const questionInfo = ref(store.questionsInfo.value);
// const questionInfo = ref(store.questionsInfo.value);
// 开始获取 http 请求,添加数据
useCommonStore().fetchSurveyQuestion();
const emit = defineEmits(['getActiveQuestion']);
// 获取选中的题目的ID
const getChooseQuestionId = (questionItem) => {
chooseQuestionId.value = questionItem.id;
// 向外传出选中的题目
emit('getActiveQuestion', questionItem);
};
// 组件对应的操作
const actionOptions = [
{
@@ -233,6 +246,7 @@ const actionOptions = [
const actionEvent = (item, el) => {
actionFun[item.fun](el);
};
// 总事件注册
const actionFun = {
// 单选事件 添加选项
@@ -277,7 +291,8 @@ const actionFun = {
};
onMounted(() => {
questionInfo.value = store.questionsInfo.value;
// questionInfo.value = store.questionsInfo.value;
});
</script>
<style scoped lang="scss">
@@ -287,7 +302,7 @@ onMounted(() => {
.design-create {
//min-height: calc(100vh);
background-color: #e9eef3;
//background-color: #e9eef3;
color: #333;
.slot-actions {

View File

@@ -1,16 +1,40 @@
<script setup lang="ts">
import PreviewIndex from './Index.vue';
import { useCommonStore } from '@/stores/modules/common';
import { storeToRefs } from 'pinia';
import { ref } from 'vue';
import Success from '@/views/Survey/views/Success/Index.vue';
const { getQuestionsInfo: questionsInfo } = storeToRefs(useCommonStore());
// 是否提交?如果提交则把组件展示出来
const isSubmit = ref(true);
</script>
<template>
<van-nav-bar title="预览" left-arrow>
<template #right>
<van-icon name="search" />
</template>
<!-- <template #right>-->
<!-- <van-icon name="search" />-->
<!-- </template>-->
</van-nav-bar>
<preview-index :filterGap="true"></preview-index>
<div class="survey-preview">
<div v-if="isSubmit" style="display: flex; flex-flow: column nowrap;align-items: center;">
<div style=" width: 97%;background: white; ">
<div v-html="questionsInfo?.survey?.title"></div>
<p>为优化活动服务品质烦请完成问卷感谢配合您的反馈至关重要</p>
</div>
<preview-index :preview="true"></preview-index>
<van-button color="#70b936" style=" width: 100px;height: 30px" @click="isSubmit = !isSubmit">提交</van-button>
</div>
<!-- 提交成功展示页面 -->
<Component :is="Success" v-else />
</div>
</template>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.survey-preview{
padding: 15px 0;
background: linear-gradient(0deg, rgba(245,245,245,1) 80%, rgba(112,185,54,0.5) 100%) white;
}
</style>

View File

@@ -1,6 +1,7 @@
<template>
<div class="choose-question-container">
<div
v-if="showActions"
class="choose-question-context"
:class="chooseQuestionId === element.id ? 'choose-question-active' : ''"
@click="chooseItem"
@@ -33,11 +34,15 @@
<!-- </div>-->
</van-cell>
</div>
<div v-else>
<slot></slot>
</div>
</div>
</template>
<script setup>
import QuestionAction from '@/views/Design/components/ActionCompoents/QuestionAction.vue';
import { ref } from 'vue';
const props = defineProps({
element: {
type: Object,
@@ -56,6 +61,10 @@ const props = defineProps({
chooseQuestionId: {
type: String,
default: '0'
},
showActions: {
type: Boolean,
default: true
}
});
const element = ref(props.element);

View File

@@ -0,0 +1,18 @@
<template>
<div class="survey-submit">
<van-image :src="successImg" width="200" />
<div>您已完成本次调研感谢您的参与</div>
</div>
</template>
<script setup>
const successImg = 'https://files.axshare.com/gsc/DR6075/c7/5a/53/c75a534148d349f1bb8e185629f784ac/images/%E9%A2%84%E8%A7%88/u123.png?pageId=18fb9d8a-b9b7-465f-9bd7-625b1b78f72e';
</script>
<style lang="scss" scoped>
.survey-submit{
display: flex;
flex-flow: column nowrap;
align-items: center;
}
</style>

View File

@@ -13,6 +13,21 @@ export default defineConfig({
server: {
host: '0.0.0.0', // 监听所有网络接口
port: 3000, // 你也可以指定端口
proxy: {
'/api': {
target: 'http://yls-api-uat.dctest.digitalyili.com/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
// '/api': {
// target: 'http://yls-api-uat.dctest.digitalyili.com/',
// changeOrigin: true,
// pathRewrite: {
// '^/api': 'http://yls-api-uat.dctest.digitalyili.com/', // 路径重写
// },
// cookieDomainRewrite: 'localhost',
// }
}
},
css: {
postcss:{