feat: pinia迁移--问卷相关遗漏补充 (#355)

Co-authored-by: Ysansan <ysansan98@outlook.com>
This commit is contained in:
ysansan 2024-07-19 18:55:22 +08:00 committed by GitHub
parent bd603eccfb
commit 6b7b3a12d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 155 additions and 350 deletions

View File

@ -4,12 +4,12 @@
</div>
</template>
<script setup lang="ts">
import { computed, watch } from 'vue'
import { useStore } from 'vuex'
import { get as _get } from 'lodash-es'
import { watch } from 'vue'
import { storeToRefs } from 'pinia'
const store = useStore()
const skinConf = computed(() => _get(store, 'state.skinConf', {}))
import { useSurveyStore } from './stores/survey'
const { skinConf } = storeToRefs(useSurveyStore())
const updateSkinConfig = (value: any) => {
const root = document.documentElement

View File

@ -13,19 +13,20 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useStore } from 'vuex'
import { storeToRefs } from 'pinia'
import MaterialGroup from './MaterialGroup.vue'
import { useQuestionStore } from '../stores/question'
import { useSurveyStore } from '../stores/survey'
const store = useStore()
const surveyStore = useSurveyStore()
const questionStore = useQuestionStore()
const renderData = computed(() => questionStore.renderData)
const rules = computed(() => store.state.rules)
const formValues = computed(() => store.state.formValues)
const { rules, formValues } = storeToRefs(surveyStore)
const handleChangeData = (data: any) => {
store.dispatch('changeData', data)
surveyStore.changeData(data)
}
</script>

View File

@ -13,10 +13,10 @@ import QuestionRuleContainer from '../../materials/questions/QuestionRuleContain
import { useVoteMap } from '@/render/hooks/useVoteMap'
import { useShowOthers } from '@/render/hooks/useShowOthers'
import { useShowInput } from '@/render/hooks/useShowInput'
import store from '@/render/store'
import { cloneDeep } from 'lodash-es'
import { ruleEngine } from '@/render/hooks/useRuleEngine.js'
import { useQuestionStore } from '../stores/question'
import { useSurveyStore } from '../stores/survey'
import { NORMAL_CHOICES, RATES, QUESTION_TYPE } from '@/common/typeEnum.ts'
@ -34,9 +34,10 @@ const props = defineProps({
})
const emit = defineEmits(['change'])
const questionStore = useQuestionStore()
const surveyStore = useSurveyStore()
const formValues = computed(() => {
return store.state.formValues
return surveyStore.formValues
})
const questionConfig = computed(() => {
let moduleConfig = props.moduleConfig
@ -98,7 +99,8 @@ watch(
key: field,
value: value
}
store.commit('changeFormData', data)
// store.commit('changeFormData', data)
surveyStore.changeData(data)
}
}
)

View File

@ -1,6 +1,7 @@
import store from '../store/index'
import { useSurveyStore } from '../stores/survey'
import { computed } from 'vue'
export const useProgressBar = () => {
const surveyStore = useSurveyStore()
const isVariableEmpty = (variable) => {
if (variable === undefined || variable === null) {
return true
@ -22,7 +23,7 @@ export const useProgressBar = () => {
fillCount: 0,
topicCount: 0
}
const formValues = store.state.formValues
const formValues = surveyStore.formValues
for (let key in formValues) {
if (key.split('_').length > 1) continue

View File

@ -1,9 +1,10 @@
import store from '../store/index'
import { useQuestionStore } from '../stores/question'
import { useSurveyStore } from '../stores/survey'
export const useShowInput = (questionKey) => {
const questionStore = useQuestionStore()
const formValues = store.state.formValues
const surveyStore = useSurveyStore()
const formValues = surveyStore.formValues
const questionVal = formValues[questionKey]
let rangeConfig = questionStore.questionData[questionKey].rangeConfig
let othersValue = {}
@ -21,7 +22,8 @@ export const useShowInput = (questionKey) => {
key: rangeKey,
value: ''
}
store.commit('changeFormData', data)
surveyStore.changeData(data)
}
}
}

View File

@ -1,9 +1,10 @@
import store from '../store/index'
import { useQuestionStore } from '../stores/question'
import { useSurveyStore } from '../stores/survey'
export const useShowOthers = (questionKey) => {
const questionStore = useQuestionStore()
const formValues = store.state.formValues
const surveyStore = useSurveyStore()
const formValues = surveyStore.formValues
const questionVal = formValues[questionKey]
let othersValue = {}
let options = questionStore.questionData[questionKey].options.map((optionItem) => {
@ -16,7 +17,7 @@ export const useShowOthers = (questionKey) => {
key: opKey,
value: ''
}
store.commit('changeFormData', data)
surveyStore.changeData(data)
}
return {
...optionItem,

View File

@ -2,7 +2,6 @@ import { createApp } from 'vue'
import App from './App.vue'
import EventBus from './utils/eventbus'
import router from './router'
import store from './store'
import { createPinia } from 'pinia'
const app = createApp(App)
@ -12,7 +11,6 @@ const $bus = new EventBus()
app.provide('$bus', $bus)
// 挂载到this上
app.config.globalProperties.$bus = $bus
app.use(store)
app.use(pinia)
app.use(router)

View File

@ -11,20 +11,18 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useStore } from 'vuex'
// @ts-ignore
import communalLoader from '@materials/communals/communalLoader.js'
import { useErrorInfo } from '../stores/errorInfo'
import { useSurveyStore } from '../stores/survey'
const LogoIcon = communalLoader.loadComponent('LogoIcon')
const store = useStore()
const {errorInfo} = useErrorInfo();
const surveyStore = useSurveyStore()
const { errorInfo } = useErrorInfo()
const errorImageUrl = computed(() => {
// const errorType = store.state?.errorInfo?.errorType
const errorType = errorInfo?.errorType
const imageMap = {
overTime: '/imgs/icons/overtime.webp',
default: '/imgs/icons/error.webp'
@ -33,11 +31,10 @@ const errorImageUrl = computed(() => {
return imageMap[errorType as 'overTime'] || imageMap.default
})
// const errorMsg = computed(() => store.state?.errorInfo?.errorMsg || '')
const errorMsg = computed(() => {
return errorInfo?.errorMsg || '提交失败'
})
const logoConf = computed(() => store.state?.bottomConf || {})
const logoConf = computed(() => surveyStore.bottomConf || {})
</script>
<style lang="scss" scoped>
.result-page-wrap {

View File

@ -3,7 +3,6 @@
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import { useStore } from 'vuex'
import { useRoute } from 'vue-router'
import { getPublishedSurveyInfo, getPreviewSchema } from '../api/survey'
@ -12,7 +11,6 @@ import { useSurveyStore } from '../stores/survey'
import AlertDialog from '../components/AlertDialog.vue'
import { initRuleEngine } from '@/render/hooks/useRuleEngine.js'
const store = useStore()
const route = useRoute()
const surveyStore = useSurveyStore()
const loadData = (res: any, surveyPath: string) => {
@ -32,7 +30,7 @@ const loadData = (res: any, surveyPath: string) => {
document.title = data.title
surveyStore.setSurveyPath(surveyPath)
store.dispatch('init', questionData)
surveyStore.initSurvey(questionData)
initRuleEngine(logicConf?.showLogicConf)
} else {
throw new Error(res.errmsg)

View File

@ -20,7 +20,7 @@
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useStore } from 'vuex'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
// @ts-ignore
import communalLoader from '@materials/communals/communalLoader.js'
@ -57,15 +57,12 @@ const boxRef = ref<HTMLElement>()
const alert = useCommandComponent(AlertDialog)
const confirm = useCommandComponent(ConfirmDialog)
const store = useStore()
const router = useRouter()
const surveyStore = useSurveyStore()
const questionStore = useQuestionStore()
const bannerConf = computed(() => store.state?.bannerConf || {})
const renderData = computed(() => questionStore.renderData)
const submitConf = computed(() => store.state?.submitConf || {})
const logoConf = computed(() => store.state?.bottomConf || {})
const { bannerConf, submitConf, bottomConf: logoConf } = storeToRefs(surveyStore)
const surveyPath = computed(() => surveyStore.surveyPath || '')
const validate = (cbk: (v: boolean) => void) => {
@ -76,7 +73,7 @@ const validate = (cbk: (v: boolean) => void) => {
const normalizationRequestBody = () => {
const enterTime = surveyStore.enterTime
const encryptInfo = surveyStore.encryptInfo as any
const formValues = store.state.formValues
const formValues = surveyStore.formValues
const result: any = {
surveyPath: surveyPath.value,
@ -123,7 +120,7 @@ const submitSurver = async () => {
}
const handleSubmit = () => {
const confirmAgain = store.state.submitConf.confirmAgain
const confirmAgain = (surveyStore.submitConf as any).confirmAgain
const { again_text, is_again } = confirmAgain
if (is_again) {

View File

@ -11,16 +11,16 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useStore } from 'vuex'
import { useSurveyStore } from '../stores/survey'
// @ts-ignore
import communalLoader from '@materials/communals/communalLoader.js'
const LogoIcon = communalLoader.loadComponent('LogoIcon')
const store = useStore()
const surveyStore = useSurveyStore()
const logoConf = computed(() => store.state?.bottomConf || {})
const logoConf = computed(() => surveyStore?.bottomConf || {})
const successMsg = computed(() => {
const msgContent = store.state?.submitConf?.msgContent || {}
const msgContent = (surveyStore?.submitConf as any)?.msgContent || {}
return msgContent?.msg_200 || '提交成功'
})
</script>

View File

@ -1,202 +0,0 @@
import moment from 'moment'
// 引入中文
import 'moment/locale/zh-cn'
// 设置中文
moment.locale('zh-cn')
import adapter from '../adapter'
// import { queryVote } from '@/render/api/survey'
import { RuleMatch } from '@/common/logicEngine/RulesMatch'
import { useSurveyStore } from '@/render/stores/survey'
import { useQuestionStore } from '@/render/stores/question'
import { useErrorInfo } from '@/render/stores/errorInfo'
/**
* CODE_MAP不从management引入在dev阶段会导致B端 router被加载进而导致C端路由被添加 baseUrl: /management
*/
// const CODE_MAP = {
// SUCCESS: 200,
// ERROR: 500,
// NO_AUTH: 403
// }
// const VOTE_INFO_KEY = 'voteinfo'
import router from '../router'
export default {
// 初始化
init({ commit }, { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf }) {
const surveyStore = useSurveyStore()
const questionStore = useQuestionStore()
const { setErrorInfo } = useErrorInfo()
surveyStore.setEnterTime()
const { begTime, endTime, answerBegTime, answerEndTime } = baseConf
const { msgContent } = submitConf
const now = Date.now()
if (now < new Date(begTime).getTime()) {
router.push({ name: 'errorPage' })
// commit('setErrorInfo', {
// errorType: 'overTime',
// errorMsg: `<p>问卷未到开始填写时间,暂时无法进行填写<p/>
// <p>开始时间为: ${begTime}</p>`
// })
setErrorInfo({
errorType: 'overTime',
errorMsg: `<p>问卷未到开始填写时间,暂时无法进行填写<p/>
<p>开始时间为: ${begTime}</p>`
})
return
} else if (now > new Date(endTime).getTime()) {
router.push({ name: 'errorPage' })
// commit('setErrorInfo', {
// errorType: 'overTime',
// errorMsg: msgContent.msg_9001 || '您来晚了,感谢支持问卷~'
// })
setErrorInfo({
errorType: 'overTime',
errorMsg: msgContent.msg_9001 || '您来晚了,感谢支持问卷~'
})
return
} else if (answerBegTime && answerEndTime) {
const momentNow = moment()
const todayStr = momentNow.format('yyyy-MM-DD')
const momentStartTime = moment(`${todayStr} ${answerBegTime}`)
const momentEndTime = moment(`${todayStr} ${answerEndTime}`)
if (momentNow.isBefore(momentStartTime) || momentNow.isAfter(momentEndTime)) {
router.push({ name: 'errorPage' })
// commit('setErrorInfo', {
// errorType: 'overTime',
// errorMsg: `<p>不在答题时间范围内,暂时无法进行填写<p/>
// <p>答题时间为: ${answerBegTime} ~ ${answerEndTime}</p>`
// })
setErrorInfo({
errorType: 'overTime',
errorMsg: `<p>不在答题时间范围内,暂时无法进行填写<p/>
<p>答题时间为: ${answerBegTime} ~ ${answerEndTime}</p>`
})
return
}
}
router.push({ name: 'renderPage' })
// 根据初始的schema生成questionData, questionSeq, rules, formValues, 这四个字段
const { questionData, questionSeq, rules, formValues } = adapter.generateData({
bannerConf,
baseConf,
bottomConf,
dataConf,
skinConf,
submitConf
})
questionStore.questionData = questionData
questionStore.questionSeq = questionSeq
// 将数据设置到state上
commit('assignState', {
rules,
bannerConf,
baseConf,
bottomConf,
dataConf,
skinConf,
submitConf,
formValues
})
// 获取已投票数据
questionStore.initVoteData()
},
// 用户输入或者选择后,更新表单数据
changeData({ commit }, data) {
commit('changeFormData', data)
},
// 初始化投票题的数据
// async initVoteData({ state, commit }) {
// const surveyStore = useSurveyStore()
// const questionStore = useQuestionStore()
// const questionData = questionStore.questionData
// const surveyPath = surveyStore.surveyPath
// const fieldList = []
// for (const field in questionData) {
// const { type } = questionData[field]
// if (/vote/.test(type)) {
// fieldList.push(field)
// }
// }
// if (fieldList.length <= 0) {
// return
// }
// try {
// localStorage.removeItem(VOTE_INFO_KEY)
// const voteRes = await queryVote({
// surveyPath,
// fieldList: fieldList.join(',')
// })
// if (voteRes.code === 200) {
// localStorage.setItem(
// VOTE_INFO_KEY,
// JSON.stringify({
// ...voteRes.data
// })
// )
// questionStore.setVoteMap(voteRes.data)
// }
// } catch (error) {
// console.log(error)
// }
// },
// updateVoteData({ state, commit }, data) {
// const questionStore = useQuestionStore()
// const { key: questionKey, value: questionVal } = data
// // 更新前获取接口缓存在localStorage中的数据
// const localData = localStorage.getItem(VOTE_INFO_KEY)
// const voteinfo = JSON.parse(localData)
// const currentQuestion = questionStore.questionData[questionKey]
// const options = currentQuestion.options
// const voteTotal = voteinfo?.[questionKey]?.total || 0
// let totalPayload = {
// questionKey,
// voteKey: 'total',
// voteValue: voteTotal
// }
// options.forEach((option) => {
// const optionhash = option.hash
// const voteCount = voteinfo?.[questionKey]?.[optionhash] || 0
// // 如果选中值包含该选项对应voteCount 和 voteTotal + 1
// if (
// Array.isArray(questionVal) ? questionVal.includes(optionhash) : questionVal === optionhash
// ) {
// const countPayload = {
// questionKey,
// voteKey: optionhash,
// voteValue: voteCount + 1
// }
// totalPayload.voteValue += 1
// questionStore.updateVoteMapByKey(countPayload)
// } else {
// const countPayload = {
// questionKey,
// voteKey: optionhash,
// voteValue: voteCount
// }
// questionStore.updateVoteMapByKey(countPayload)
// }
// questionStore.updateVoteMapByKey(totalPayload)
// })
// },
// async getEncryptInfo({ commit }) {
// try {
// const res = await getEncryptInfo()
// if (res.code === CODE_MAP.SUCCESS) {
// commit('setEncryptInfo', res.data)
// }
// } catch (error) {
// console.log(error)
// }
// },
async initRuleEngine({ commit }, ruleConf) {
const ruleEngine = new RuleMatch(ruleConf)
commit('setRuleEgine', ruleEngine)
}
}

View File

@ -1,25 +0,0 @@
export default {
// 题目列表
// renderData: (state) => {
// const { questionSeq, questionData } = state
// let index = 1
// return (
// questionSeq &&
// questionSeq.reduce((pre, item) => {
// const questionArr = []
// item.forEach((questionKey) => {
// const question = { ...questionData[questionKey] }
// // 开启显示序号
// if (question.showIndex) {
// question.indexNumber = index++
// }
// questionArr.push(question)
// })
// if (questionArr && questionArr.length) {
// pre.push(questionArr)
// }
// return pre
// }, [])
// )
// }
}

View File

@ -1,13 +0,0 @@
import { createStore } from 'vuex'
import state from './state'
import getters from './getters'
import mutations from './mutations'
import actions from './actions'
export default createStore({
state,
getters,
mutations,
actions
})

View File

@ -1,50 +0,0 @@
import { forEach, set } from 'lodash-es'
export default {
// 将数据设置到state上
assignState(state, data) {
forEach(data, (value, key) => {
state[key] = value
})
},
setErrorInfo(state, { errorType, errorMsg }) {
state.errorInfo = {
errorType,
errorMsg
}
},
changeFormData(state, data) {
let { key, value } = data
// console.log('formValues', key, value)
set(state, `formValues.${key}`, value)
},
// changeSelectMoreData(state, data) {
// const { key, value, field } = data
// set(state, `questionData.${field}.othersValue.${key}`, value)
// },
// setEnterTime(state) {
// state.enterTime = Date.now()
// },
// setSurveyPath(state, data) {
// state.surveyPath = data
// },
// setVoteMap(state, data) {
// state.voteMap = data
// },
// updateVoteMapByKey(state, data) {
// const { questionKey, voteKey, voteValue } = data
// // 兼容为空的情况
// if (!state.voteMap[questionKey]) {
// state.voteMap[questionKey] = {}
// }
// state.voteMap[questionKey][voteKey] = voteValue
// },
// setQuestionSeq(state, data) {
// state.questionSeq = data
// },
// setEncryptInfo(state, data) {
// state.encryptInfo = data
// },
setRuleEgine(state, ruleEngine) {
state.ruleEngine = ruleEngine
}
}

View File

@ -1,16 +0,0 @@
// import { isMobile } from '../utils/index'
export default {
// surveyPath: '',
// questionData: null,
// isMobile: isMobile(),
errorInfo: {
errorType: '',
errorMsg: ''
},
// enterTime: null,
// questionSeq: [], // 题目的顺序,因为可能会有分页的情况,所以是一个二维数组[[qid1, qid2], [qid3,qid4]]
// voteMap: {},
// encryptInfo: null,
ruleEngine: null
}

View File

@ -1,8 +1,20 @@
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { defineStore } from 'pinia'
import { pick } from 'lodash-es'
import { isMobile as isInMobile } from '@/render/utils/index'
import { getEncryptInfo as getEncryptInfoApi } from '@/render/api/survey'
import { useQuestionStore } from '@/render/stores/question'
import { useErrorInfo } from '@/render/stores/errorInfo'
import moment from 'moment'
// 引入中文
import 'moment/locale/zh-cn'
// 设置中文
moment.locale('zh-cn')
import adapter from '../adapter'
/**
* CODE_MAP不从management引入在dev阶段会导致B端 router被加载进而导致C端路由被添加 baseUrl: /management
@ -17,6 +29,18 @@ export const useSurveyStore = defineStore('survey', () => {
const isMobile = ref(isInMobile())
const enterTime = ref(0)
const encryptInfo = ref(null)
const rules = ref({})
const bannerConf = ref({})
const baseConf = ref({})
const bottomConf = ref({})
const dataConf = ref({})
const skinConf = ref({})
const submitConf = ref({})
const formValues = ref({})
const router = useRouter()
const questionStore = useQuestionStore()
const { setErrorInfo } = useErrorInfo()
const setSurveyPath = (data) => {
surveyPath.value = data
@ -37,12 +61,102 @@ export const useSurveyStore = defineStore('survey', () => {
}
}
const canFillQuestionnaire = (baseConf) => {
const { begTime, endTime, answerBegTime, answerEndTime } = baseConf
const { msgContent } = submitConf
const now = Date.now()
let isSuccess = true
if (now < new Date(begTime).getTime()) {
isSuccess = false
setErrorInfo({
errorType: 'overTime',
errorMsg: `<p>问卷未到开始填写时间,暂时无法进行填写<p/>
<p>开始时间为: ${begTime}</p>`
})
} else if (now > new Date(endTime).getTime()) {
isSuccess = false
setErrorInfo({
errorType: 'overTime',
errorMsg: msgContent.msg_9001 || '您来晚了,感谢支持问卷~'
})
} else if (answerBegTime && answerEndTime) {
const momentNow = moment()
const todayStr = momentNow.format('yyyy-MM-DD')
const momentStartTime = moment(`${todayStr} ${answerBegTime}`)
const momentEndTime = moment(`${todayStr} ${answerEndTime}`)
if (momentNow.isBefore(momentStartTime) || momentNow.isAfter(momentEndTime)) {
isSuccess = false
setErrorInfo({
errorType: 'overTime',
errorMsg: `<p>不在答题时间范围内,暂时无法进行填写<p/>
<p>答题时间为: ${answerBegTime} ~ ${answerEndTime}</p>`
})
}
}
if (!isSuccess) {
router.push({ name: 'errorPage' })
}
return isSuccess
}
const initSurvey = (option) => {
setEnterTime()
if (!canFillQuestionnaire(option.baseConf)) {
return
}
// 根据初始的schema生成questionData, questionSeq, rules, formValues, 这四个字段
const {
questionData,
questionSeq,
rules: _rules,
formValues: _formValues
} = adapter.generateData(
pick(option, ['bannerConf', 'baseConf', 'bottomConf', 'dataConf', 'skinConf', 'submitConf'])
)
questionStore.questionData = questionData
questionStore.questionSeq = questionSeq
rules.value = _rules
bannerConf.value = option.bannerConf
baseConf.value = option.baseConf
bottomConf.value = option.bottomConf
dataConf.value = option.dataConf
skinConf.value = option.skinConf
submitConf.value = option.submitConf
formValues.value = _formValues
// 获取已投票数据
questionStore.initVoteData()
}
const changeData = (data) => {
let { key, value } = data
if (key in formValues.value) {
formValues.value[key] = value
}
}
return {
surveyPath,
isMobile,
enterTime,
encryptInfo,
rules,
bannerConf,
baseConf,
bottomConf,
dataConf,
skinConf,
submitConf,
formValues,
initSurvey,
changeData,
setSurveyPath,
setEnterTime,
getEncryptInfo