diff --git a/web/components.d.ts b/web/components.d.ts
new file mode 100644
index 00000000..a7ad42ea
--- /dev/null
+++ b/web/components.d.ts
@@ -0,0 +1,52 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+export {}
+
+declare module 'vue' {
+ export interface GlobalComponents {
+ ElButton: typeof import('element-plus/es')['ElButton']
+ ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
+ ElDialog: typeof import('element-plus/es')['ElDialog']
+ ElForm: typeof import('element-plus/es')['ElForm']
+ ElFormItem: typeof import('element-plus/es')['ElFormItem']
+ ElInput: typeof import('element-plus/es')['ElInput']
+ ElMenu: typeof import('element-plus/es')['ElMenu']
+ ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
+ ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
+ ElOption: typeof import('element-plus/es')['ElOption']
+ ElPagination: typeof import('element-plus/es')['ElPagination']
+ ElPopover: typeof import('element-plus/es')['ElPopover']
+ ElSelect: typeof import('element-plus/es')['ElSelect']
+ ElSelectV2: typeof import('element-plus/es')['ElSelectV2']
+ ElTable: typeof import('element-plus/es')['ElTable']
+ ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+ ElTag: typeof import('element-plus/es')['ElTag']
+ ElTooltip: typeof import('element-plus/es')['ElTooltip']
+ IEpBottom: typeof import('~icons/ep/bottom')['default']
+ IEpCheck: typeof import('~icons/ep/check')['default']
+ IEpCirclePlus: typeof import('~icons/ep/circle-plus')['default']
+ IEpClose: typeof import('~icons/ep/close')['default']
+ IEpCopyDocument: typeof import('~icons/ep/copy-document')['default']
+ IEpDelete: typeof import('~icons/ep/delete')['default']
+ IEpIphone: typeof import('~icons/ep/iphone')['default']
+ IEpLoading: typeof import('~icons/ep/loading')['default']
+ IEpMinus: typeof import('~icons/ep/minus')['default']
+ IEpMonitor: typeof import('~icons/ep/monitor')['default']
+ IEpMore: typeof import('~icons/ep/more')['default']
+ IEpSearch: typeof import('~icons/ep/search')['default']
+ IEpSort: typeof import('~icons/ep/sort')['default']
+ IEpSortDown: typeof import('~icons/ep/sort-down')['default']
+ IEpSortUp: typeof import('~icons/ep/sort-up')['default']
+ IEpTop: typeof import('~icons/ep/top')['default']
+ IEpView: typeof import('~icons/ep/view')['default']
+ IEpWarningFilled: typeof import('~icons/ep/warning-filled')['default']
+ RouterLink: typeof import('vue-router')['RouterLink']
+ RouterView: typeof import('vue-router')['RouterView']
+ }
+ export interface ComponentCustomProperties {
+ vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+ }
+}
diff --git a/web/src/management/pages/edit/modules/settingModule/SettingPanel.vue b/web/src/management/pages/edit/modules/settingModule/SettingPanel.vue
index 176dbaee..629b713e 100644
--- a/web/src/management/pages/edit/modules/settingModule/SettingPanel.vue
+++ b/web/src/management/pages/edit/modules/settingModule/SettingPanel.vue
@@ -67,13 +67,13 @@ const setterList = computed(() => {
}
} else {
formValue = _get(store.state.edit.schema, formKey, formItem.value)
+ console.log("formVaue:", formValue)
dataConfig[formKey] = formValue
}
formItem.value = formValue
}
form.dataConfig = dataConfig
-
return form
})
})
diff --git a/web/src/management/pages/edit/modules/settingModule/config/baseConfig.js b/web/src/management/pages/edit/modules/settingModule/config/baseConfig.js
index bdeab24a..6af2a296 100644
--- a/web/src/management/pages/edit/modules/settingModule/config/baseConfig.js
+++ b/web/src/management/pages/edit/modules/settingModule/config/baseConfig.js
@@ -7,6 +7,6 @@ export default [
{
title: '提交限制',
key: 'limitConfig',
- formList: ['limit_tLimit']
+ formList: ['limit_tLimit', 'limit_breakAnswer', 'limit_backAnswer']
}
]
diff --git a/web/src/management/pages/edit/modules/settingModule/config/baseFormConfig.js b/web/src/management/pages/edit/modules/settingModule/config/baseFormConfig.js
index 59fed0a1..e1556f87 100644
--- a/web/src/management/pages/edit/modules/settingModule/config/baseFormConfig.js
+++ b/web/src/management/pages/edit/modules/settingModule/config/baseFormConfig.js
@@ -21,5 +21,19 @@ export default {
tip: '问卷仅在指定时间段内可填写',
type: 'QuestionTimeHour',
placement: 'top'
+ },
+ limit_breakAnswer: {
+ key: 'baseConf.breakAnswer',
+ label: '允许断点续答',
+ tip: '回填前一次作答中的内容(注:更换设备/浏览器/清除缓存/更改内容重新发布则此功能失效)',
+ type: 'ELSwitch',
+ value: false
+ },
+ limit_backAnswer: {
+ key: 'baseConf.backAnswer',
+ label: '自动填充上次填写内容',
+ tip: '回填前一次提交的内容(注:更换设备/浏览器/清除缓存/更改内容重新发布则此功能失效)',
+ type: 'ELSwitch',
+ value: false
}
}
diff --git a/web/src/management/store/edit/state.js b/web/src/management/store/edit/state.js
index 7fcab2e6..a14554e4 100644
--- a/web/src/management/store/edit/state.js
+++ b/web/src/management/store/edit/state.js
@@ -42,7 +42,9 @@ export default {
tLimit: 0,
answerBegTime: '',
answerEndTime: '',
- answerLimitTime: 0
+ answerLimitTime: 0,
+ breakAnswer: false,
+ backAnswer: false
},
submitConf: {
submitTitle: '',
diff --git a/web/src/materials/setters/widgets/ELSwitch.vue b/web/src/materials/setters/widgets/ELSwitch.vue
new file mode 100644
index 00000000..10347939
--- /dev/null
+++ b/web/src/materials/setters/widgets/ELSwitch.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/web/src/render/components/BackAnswerDialog.vue b/web/src/render/components/BackAnswerDialog.vue
new file mode 100644
index 00000000..eeafa7ee
--- /dev/null
+++ b/web/src/render/components/BackAnswerDialog.vue
@@ -0,0 +1,79 @@
+
+
+
+
{{ title }}
+
+
{{ cancelBtnText }}
+
{{ confirmBtnText }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/web/src/render/pages/RenderPage.vue b/web/src/render/pages/RenderPage.vue
index a43e0715..04b7bcdb 100644
--- a/web/src/render/pages/RenderPage.vue
+++ b/web/src/render/pages/RenderPage.vue
@@ -81,6 +81,17 @@ const normalizationRequestBody = () => {
clientTime: Date.now()
}
+ //浏览器缓存数据
+ localStorage.removeItem(surveyPath + "_questionData")
+ localStorage.removeItem("isSubmit")
+ //数据加密
+ var formData = Object.assign({}, store.state.formValues)
+ for(const key in formData){
+ formData[key] = encodeURIComponent(formData[key])
+ }
+ localStorage.setItem(surveyPath + "_questionData", JSON.stringify(formData))
+ localStorage.setItem('isSubmit', JSON.stringify(true))
+
if (encryptInfo?.encryptType) {
result.encryptType = encryptInfo?.encryptType
result.data = encrypt[result.encryptType as 'rsa']({
diff --git a/web/src/render/store/actions.js b/web/src/render/store/actions.js
index 05f6c169..6ab52462 100644
--- a/web/src/render/store/actions.js
+++ b/web/src/render/store/actions.js
@@ -6,6 +6,9 @@ moment.locale('zh-cn')
import adapter from '../adapter'
import { queryVote, getEncryptInfo } from '@/render/api/survey'
import { RuleMatch } from '@/common/logicEngine/RulesMatch'
+import state from './state'
+import useCommandComponent from '../hooks/useCommandComponent'
+import BackAnswerDialog from '../components/BackAnswerDialog.vue'
/**
* CODE_MAP不从management引入,在dev阶段,会导致B端 router被加载,进而导致C端路由被添加 baseUrl: /management
*/
@@ -16,6 +19,9 @@ const CODE_MAP = {
}
const VOTE_INFO_KEY = 'voteinfo'
import router from '../router'
+
+const confirm = useCommandComponent(BackAnswerDialog)
+
export default {
// 初始化
init(
@@ -23,7 +29,7 @@ export default {
{ bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf }
) {
commit('setEnterTime')
- const { begTime, endTime, answerBegTime, answerEndTime } = baseConf
+ const { begTime, endTime, answerBegTime, answerEndTime, breakAnswer, backAnswer} = baseConf
const { msgContent } = submitConf
const now = Date.now()
if (now < new Date(begTime).getTime()) {
@@ -57,31 +63,72 @@ export default {
}
}
- // 根据初始的schema生成questionData, questionSeq, rules, formValues, 这四个字段
- const { questionData, questionSeq, rules, formValues } = adapter.generateData({
- bannerConf,
- baseConf,
- bottomConf,
- dataConf,
- skinConf,
- submitConf
- })
+ //回填,断点续填
+ const localData = JSON.parse(localStorage.getItem(state.surveyPath + "_questionData"))
- // 将数据设置到state上
- commit('assignState', {
- questionData,
- questionSeq,
- rules,
- bannerConf,
- baseConf,
- bottomConf,
- dataConf,
- skinConf,
- submitConf,
- formValues
- })
- // 获取已投票数据
- dispatch('initVoteData')
+ //数据解密
+ for(const key in localData){
+ localData[key] = decodeURIComponent(localData[key])
+ }
+
+ const isSubmit = JSON.parse(localStorage.getItem('isSubmit'))
+ if(localData) {
+ if(isSubmit){
+ if(!backAnswer) {
+ clearFormData({ commit, dispatch }, { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf })
+ } else {
+ confirm({
+ title: "您之前已提交过问卷,是否要回填?",
+ onConfirm: async () => {
+ try {
+ loadFormData({ commit, dispatch }, {bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf }, localData)
+ } catch (error) {
+ console.log(error)
+ } finally {
+ confirm.close()
+ }
+ },
+ onCancel: async() => {
+ try {
+ clearFormData({ commit, dispatch }, { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf })
+ } catch (error) {
+ console.log(error)
+ } finally {
+ confirm.close()
+ }
+ }
+ })
+ }
+ } else{
+ if(!breakAnswer) {
+ clearFormData({ commit, dispatch }, { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf })
+ } else {
+ confirm({
+ title: "您之前已填写部分内容, 是否要继续填写?",
+ onConfirm: async () => {
+ try {
+ loadFormData({ commit, dispatch }, {bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf }, localData)
+ } catch (error) {
+ console.log(error)
+ } finally {
+ confirm.close()
+ }
+ },
+ onCancel: async() => {
+ try {
+ clearFormData({ commit, dispatch }, { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf })
+ } catch (error) {
+ console.log(error)
+ } finally {
+ confirm.close()
+ }
+ }
+ })
+ }
+ }
+ } else {
+ clearFormData({ commit, dispatch }, { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf })
+ }
},
// 用户输入或者选择后,更新表单数据
changeData({ commit }, data) {
@@ -177,3 +224,71 @@ export default {
commit('setRuleEgine', ruleEngine)
}
}
+
+ // 加载上次填写过的数据到问卷页
+ function loadFormData({ commit, dispatch }, {bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf }, formData) {
+ commit('setRouter', 'indexPage')
+
+ // 根据初始的schema生成questionData, questionSeq, rules, formValues, 这四个字段
+ const { questionData, questionSeq, rules, formValues } = adapter.generateData({
+ bannerConf,
+ baseConf,
+ bottomConf,
+ dataConf,
+ skinConf,
+ submitConf
+ })
+ console.log("formdata", formData)
+
+ for(const key in formData){
+ formValues[key] = formData[key]
+ console.log("formValues",formValues)
+ }
+
+ // 将数据设置到state上
+ commit('assignState', {
+ questionData,
+ questionSeq,
+ rules,
+ bannerConf,
+ baseConf,
+ bottomConf,
+ dataConf,
+ skinConf,
+ submitConf,
+ formValues
+ })
+ // 获取已投票数据
+ dispatch('initVoteData')
+ }
+
+ // 加载空白页面
+ function clearFormData({ commit, dispatch }, { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf }) {
+ commit('setRouter', 'indexPage')
+
+ // 根据初始的schema生成questionData, questionSeq, rules, formValues, 这四个字段
+ const { questionData, questionSeq, rules, formValues } = adapter.generateData({
+ bannerConf,
+ baseConf,
+ bottomConf,
+ dataConf,
+ skinConf,
+ submitConf
+ })
+
+ // 将数据设置到state上
+ commit('assignState', {
+ questionData,
+ questionSeq,
+ rules,
+ bannerConf,
+ baseConf,
+ bottomConf,
+ dataConf,
+ skinConf,
+ submitConf,
+ formValues
+ })
+ // 获取已投票数据
+ dispatch('initVoteData')
+ }
diff --git a/web/src/render/store/mutations.js b/web/src/render/store/mutations.js
index 4ada3d86..4a5c22ca 100644
--- a/web/src/render/store/mutations.js
+++ b/web/src/render/store/mutations.js
@@ -17,8 +17,19 @@ export default {
},
changeFormData(state, data) {
let { key, value } = data
- // console.log('formValues', key, value)
set(state, `formValues.${key}`, value)
+
+ //数据加密
+ var formData = Object.assign({}, state.formValues);
+ for(const key in formData){
+ formData[key] = encodeURIComponent(formData[key])
+ }
+
+ //浏览器存储
+ localStorage.removeItem(state.surveyPath + "_questionData")
+ localStorage.setItem(state.surveyPath + "_questionData", JSON.stringify(formData))
+ localStorage.setItem('isSubmit', JSON.stringify(false))
+
},
changeSelectMoreData(state, data) {
const { key, value, field } = data