Merge branch 'feature/pinia'

This commit is contained in:
sudoooooo 2024-07-23 21:27:04 +08:00
commit 0b53b78cda
58 changed files with 1577 additions and 442 deletions

View File

@ -172,7 +172,6 @@ export class WorkspaceController {
pre[id] = cur; pre[id] = cur;
return pre; return pre;
}, {}); }, {});
const surveyTotalList = await Promise.all( const surveyTotalList = await Promise.all(
workspaceIdList.map((item) => { workspaceIdList.map((item) => {
return this.surveyMetaService.countSurveyMetaByWorkspaceId({ return this.surveyMetaService.countSurveyMetaByWorkspaceId({

120
web/components.d.ts vendored
View File

@ -7,67 +7,67 @@ export {}
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: (typeof import('element-plus/es'))['ElButton']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckbox: (typeof import('element-plus/es'))['ElCheckbox']
ElCollapse: typeof import('element-plus/es')['ElCollapse'] ElCollapse: (typeof import('element-plus/es'))['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem'] ElCollapseItem: (typeof import('element-plus/es'))['ElCollapseItem']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] ElColorPicker: (typeof import('element-plus/es'))['ElColorPicker']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElConfigProvider: (typeof import('element-plus/es'))['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDatePicker: (typeof import('element-plus/es'))['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: (typeof import('element-plus/es'))['ElDialog']
ElForm: typeof import('element-plus/es')['ElForm'] ElForm: (typeof import('element-plus/es'))['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: (typeof import('element-plus/es'))['ElFormItem']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: (typeof import('element-plus/es'))['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] ElInputNumber: (typeof import('element-plus/es'))['ElInputNumber']
ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenu: (typeof import('element-plus/es'))['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItem: (typeof import('element-plus/es'))['ElMenuItem']
ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] ElMenuItemGroup: (typeof import('element-plus/es'))['ElMenuItemGroup']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: (typeof import('element-plus/es'))['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: (typeof import('element-plus/es'))['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: (typeof import('element-plus/es'))['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadio: (typeof import('element-plus/es'))['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] ElRadioButton: (typeof import('element-plus/es'))['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRadioGroup: (typeof import('element-plus/es'))['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow'] ElRow: (typeof import('element-plus/es'))['ElRow']
ElSegmented: typeof import('element-plus/es')['ElSegmented'] ElSegmented: (typeof import('element-plus/es'))['ElSegmented']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: (typeof import('element-plus/es'))['ElSelect']
ElSelectV2: typeof import('element-plus/es')['ElSelectV2'] ElSelectV2: (typeof import('element-plus/es'))['ElSelectV2']
ElSlider: typeof import('element-plus/es')['ElSlider'] ElSlider: (typeof import('element-plus/es'))['ElSlider']
ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElSwitch: (typeof import('element-plus/es'))['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable'] ElTable: (typeof import('element-plus/es'))['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] ElTableColumn: (typeof import('element-plus/es'))['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: (typeof import('element-plus/es'))['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: (typeof import('element-plus/es'))['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: (typeof import('element-plus/es'))['ElTag']
ElTimePicker: typeof import('element-plus/es')['ElTimePicker'] ElTimePicker: (typeof import('element-plus/es'))['ElTimePicker']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: (typeof import('element-plus/es'))['ElTooltip']
IEpBottom: typeof import('~icons/ep/bottom')['default'] IEpBottom: (typeof import('~icons/ep/bottom'))['default']
IEpCheck: typeof import('~icons/ep/check')['default'] IEpCheck: (typeof import('~icons/ep/check'))['default']
IEpCirclePlus: typeof import('~icons/ep/circle-plus')['default'] IEpCirclePlus: (typeof import('~icons/ep/circle-plus'))['default']
IEpClose: typeof import('~icons/ep/close')['default'] IEpClose: (typeof import('~icons/ep/close'))['default']
IEpConnection: typeof import('~icons/ep/connection')['default'] IEpConnection: (typeof import('~icons/ep/connection'))['default']
IEpCopyDocument: typeof import('~icons/ep/copy-document')['default'] IEpCopyDocument: (typeof import('~icons/ep/copy-document'))['default']
IEpDelete: typeof import('~icons/ep/delete')['default'] IEpDelete: (typeof import('~icons/ep/delete'))['default']
IEpIphone: typeof import('~icons/ep/iphone')['default'] IEpIphone: (typeof import('~icons/ep/iphone'))['default']
IEpLoading: typeof import('~icons/ep/loading')['default'] IEpLoading: (typeof import('~icons/ep/loading'))['default']
IEpMinus: typeof import('~icons/ep/minus')['default'] IEpMinus: (typeof import('~icons/ep/minus'))['default']
IEpMonitor: typeof import('~icons/ep/monitor')['default'] IEpMonitor: (typeof import('~icons/ep/monitor'))['default']
IEpMore: typeof import('~icons/ep/more')['default'] IEpMore: (typeof import('~icons/ep/more'))['default']
IEpPlus: typeof import('~icons/ep/plus')['default'] IEpPlus: (typeof import('~icons/ep/plus'))['default']
IEpQuestionFilled: typeof import('~icons/ep/question-filled')['default'] IEpQuestionFilled: (typeof import('~icons/ep/question-filled'))['default']
IEpRank: typeof import('~icons/ep/rank')['default'] IEpRank: (typeof import('~icons/ep/rank'))['default']
IEpRemove: typeof import('~icons/ep/remove')['default'] IEpRemove: (typeof import('~icons/ep/remove'))['default']
IEpSearch: typeof import('~icons/ep/search')['default'] IEpSearch: (typeof import('~icons/ep/search'))['default']
IEpSort: typeof import('~icons/ep/sort')['default'] IEpSort: (typeof import('~icons/ep/sort'))['default']
IEpSortDown: typeof import('~icons/ep/sort-down')['default'] IEpSortDown: (typeof import('~icons/ep/sort-down'))['default']
IEpSortUp: typeof import('~icons/ep/sort-up')['default'] IEpSortUp: (typeof import('~icons/ep/sort-up'))['default']
IEpTop: typeof import('~icons/ep/top')['default'] IEpTop: (typeof import('~icons/ep/top'))['default']
IEpView: typeof import('~icons/ep/view')['default'] IEpView: (typeof import('~icons/ep/view'))['default']
IEpWarningFilled: typeof import('~icons/ep/warning-filled')['default'] IEpWarningFilled: (typeof import('~icons/ep/warning-filled'))['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: (typeof import('vue-router'))['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: (typeof import('vue-router'))['RouterView']
} }
export interface ComponentCustomProperties { export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective'] vLoading: (typeof import('element-plus/es'))['ElLoadingDirective']
} }
} }

View File

@ -26,6 +26,7 @@
"moment": "^2.29.4", "moment": "^2.29.4",
"nanoid": "^5.0.7", "nanoid": "^5.0.7",
"node-forge": "^1.3.1", "node-forge": "^1.3.1",
"pinia": "^2.1.7",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"vue": "^3.4.15", "vue": "^3.4.15",
"vue-router": "^4.2.5", "vue-router": "^4.2.5",

View File

@ -24,13 +24,13 @@
<script setup> <script setup>
import { ref, shallowRef, onBeforeMount, watch, computed } from 'vue' import { ref, shallowRef, onBeforeMount, watch, computed } from 'vue'
import { useStore } from 'vuex'
import { get as _get } from 'lodash-es' import { get as _get } from 'lodash-es'
import '@wangeditor/editor/dist/css/style.css' import '@wangeditor/editor/dist/css/style.css'
import './styles/reset-wangeditor.scss' import './styles/reset-wangeditor.scss'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue' import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { useUserStore } from '@/management/stores/user'
import { replacePxWithRem } from './utils' import { replacePxWithRem } from './utils'
const emit = defineEmits(['input', 'onFocus', 'change', 'blur', 'created']) const emit = defineEmits(['input', 'onFocus', 'change', 'blur', 'created'])
@ -66,8 +66,8 @@ const editorConfig = {
MENU_CONF: {} MENU_CONF: {}
} }
const store = useStore() const userStore = useUserStore()
const token = _get(store, 'state.user.userInfo.token') const token = _get(userStore, 'userInfo.token')
// //
editorConfig.MENU_CONF['uploadImage'] = { editorConfig.MENU_CONF['uploadImage'] = {

View File

@ -1,4 +1,4 @@
// 静态数据 // test静态数据,实际业务里无用
export const ruleConf = [ export const ruleConf = [
{ {
conditions: [ conditions: [

View File

@ -1,7 +1,7 @@
import axios from 'axios' import axios from 'axios'
import store from '@/management/store/index'
import router from '@/management/router/index' import router from '@/management/router/index'
import { get as _get } from 'lodash-es' import { get as _get } from 'lodash-es'
import { useUserStore } from '../stores/user'
export const CODE_MAP = { export const CODE_MAP = {
SUCCESS: 200, SUCCESS: 200,
@ -36,8 +36,9 @@ instance.interceptors.response.use(
) )
instance.interceptors.request.use((config) => { instance.interceptors.request.use((config) => {
const hasLogined = _get(store, 'state.user.hasLogined') const userStore = useUserStore()
const token = _get(store, 'state.user.userInfo.token') const hasLogined = _get(userStore, 'hasLogined')
const token = _get(userStore, 'userInfo.token')
if (hasLogined && token) { if (hasLogined && token) {
if (!config.headers) { if (!config.headers) {
config.headers = {} config.headers = {}

View File

@ -30,12 +30,12 @@
<script setup> <script setup>
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
import LogoIcon from './LogoIcon.vue' import LogoIcon from './LogoIcon.vue'
import { SurveyPermissions } from '@/management/utils/types/workSpace.ts' import { SurveyPermissions } from '@/management/utils/types/workSpace.ts'
const store = useStore() const editStore = useEditStore()
const tabArr = [ const tabArr = [
{ {
@ -62,7 +62,7 @@ const tabArr = [
] ]
const tabs = ref([]) const tabs = ref([])
watch( watch(
() => store.state.cooperPermissions, () => editStore.cooperPermissions,
(newVal) => { (newVal) => {
tabs.value = [] tabs.value = []
// //

View File

@ -1,17 +1,19 @@
import { computed } from 'vue' import { computed } from 'vue'
import store from '@/management/store' import { storeToRefs } from 'pinia'
import { useEditStore } from '@/management/stores/edit'
import { cleanRichText } from '@/common/xss' import { cleanRichText } from '@/common/xss'
export const useQuestionInfo = (field) => { export const useQuestionInfo = (field) => {
const editStore = useEditStore()
const { questionDataList } = storeToRefs(editStore)
const getQuestionTitle = computed(() => { const getQuestionTitle = computed(() => {
const questionDataList = store.state.edit.schema.questionDataList
return () => { return () => {
return questionDataList.find((item) => item.field === field)?.title return questionDataList.value.find((item) => item.field === field)?.title
} }
}) })
const getOptionTitle = computed(() => { const getOptionTitle = computed(() => {
const questionDataList = store.state.edit.schema.questionDataList
return (value) => { return (value) => {
const options = questionDataList.find((item) => item.field === field)?.options || [] const options = questionDataList.value.find((item) => item.field === field)?.options || []
if (value instanceof Array) { if (value instanceof Array) {
return options return options
.filter((item) => value.includes(item.hash)) .filter((item) => value.includes(item.hash))

View File

@ -1,14 +1,15 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import store from './store' import { createPinia } from 'pinia'
import plainText from './directive/plainText' import plainText from './directive/plainText'
import safeHtml from './directive/safeHtml' import safeHtml from './directive/safeHtml'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
const pinia = createPinia()
const app = createApp(App) const app = createApp(App)
app.use(store) app.use(pinia)
app.use(router) app.use(router)
app.use(plainText) app.use(plainText)

View File

@ -38,13 +38,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, toRefs } from 'vue' import { ref, reactive, computed, toRefs } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss' import 'element-plus/theme-chalk/src/message.scss'
import { createSurvey } from '@/management/api/survey' import { createSurvey } from '@/management/api/survey'
import { SURVEY_TYPE_LIST } from '../types' import { SURVEY_TYPE_LIST } from '../types'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
interface Props { interface Props {
selectType?: string selectType?: string
@ -54,6 +52,7 @@ const props = withDefaults(defineProps<Props>(), {
selectType: 'normal' selectType: 'normal'
}) })
const workSpaceStore = useWorkSpaceStore()
const ruleForm = ref<any>(null) const ruleForm = ref<any>(null)
const state = reactive({ const state = reactive({
@ -79,7 +78,6 @@ const checkForm = (fn: Function) => {
} }
const router = useRouter() const router = useRouter()
const store = useStore()
const submit = () => { const submit = () => {
if (!state.canSubmit) { if (!state.canSubmit) {
return return
@ -94,8 +92,8 @@ const submit = () => {
surveyType: selectType, surveyType: selectType,
...state.form ...state.form
} }
if (store.state.list.workSpaceId) { if (workSpaceStore.workSpaceId) {
payload.workspaceId = store.state.list.workSpaceId payload.workspaceId = workSpaceStore.workSpaceId
} }
const res: any = await createSurvey(payload) const res: any = await createSurvey(payload)
if (res?.code === 200 && res?.data?.id) { if (res?.code === 200 && res?.data?.id) {

View File

@ -35,7 +35,7 @@
<script> <script>
import { computed, defineComponent, ref, getCurrentInstance } from 'vue' import { computed, defineComponent, ref, getCurrentInstance } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import QuestionContainerB from '@/materials/questions/QuestionContainerB' import QuestionContainerB from '@/materials/questions/QuestionContainerB'
import QuestionWrapper from '@/management/pages/edit/components/QuestionWrapper.vue' import QuestionWrapper from '@/management/pages/edit/components/QuestionWrapper.vue'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
@ -62,13 +62,13 @@ export default defineComponent({
}, },
emits: ['change', 'select', 'changeSeq'], emits: ['change', 'select', 'changeSeq'],
setup(props, { emit }) { setup(props, { emit }) {
const store = useStore() const editStore = useEditStore()
const renderData = computed({ const renderData = computed({
get() { get() {
return filterQuestionPreviewData(props.questionDataList) return filterQuestionPreviewData(props.questionDataList)
}, },
set(questionDataList) { set(value) {
store.commit('edit/setQuestionDataList', questionDataList) editStore.setQuestionDataList(value)
} }
}) })
const handleSelect = (index) => { const handleSelect = (index) => {

View File

@ -25,8 +25,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import { get as _get } from 'lodash-es'
import BackPanel from '../modules/generalModule/BackPanel.vue' import BackPanel from '../modules/generalModule/BackPanel.vue'
import TitlePanel from '../modules/generalModule/TitlePanel.vue' import TitlePanel from '../modules/generalModule/TitlePanel.vue'
@ -37,16 +36,11 @@ import SavePanel from '../modules/contentModule/SavePanel.vue'
import PublishPanel from '../modules/contentModule/PublishPanel.vue' import PublishPanel from '../modules/contentModule/PublishPanel.vue'
import CooperationPanel from '../modules/contentModule/CooperationPanel.vue' import CooperationPanel from '../modules/contentModule/CooperationPanel.vue'
const store = useStore() const editStore = useEditStore()
const title = computed(() => _get(store.state, 'edit.schema.metaData.title')) const title = computed(() => (editStore.schema?.metaData as any)?.title || '')
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import url('@/management/styles/edit-btn.scss'); @import url('@/management/styles/edit-btn.scss');
.view-icon {
font-size: 20px;
height: 29px;
line-height: 29px;
}
.nav { .nav {
width: 100%; width: 100%;
height: 56px; height: 56px;

View File

@ -15,7 +15,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue' import { onMounted } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss' import 'element-plus/theme-chalk/src/message.scss'
@ -26,16 +26,17 @@ import Navbar from './components/ModuleNavbar.vue'
import { initShowLogicEngine } from '@/management/hooks/useShowLogicEngine' import { initShowLogicEngine } from '@/management/hooks/useShowLogicEngine'
const store = useStore() const editStore = useEditStore()
const { schema, init, setSurveyId } = editStore
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
onMounted(async () => { onMounted(async () => {
store.commit('edit/setSurveyId', route.params.id) setSurveyId(route.params.id as string)
try { try {
await store.dispatch('edit/init') await init()
await initShowLogicEngine(store.state.edit.schema.logicConf.showLogicConf || {}) await initShowLogicEngine(schema.logicConf.showLogicConf || {})
} catch (err: any) { } catch (err: any) {
ElMessage.error(err.message) ElMessage.error(err.message)

View File

@ -26,8 +26,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { useStore } from 'vuex'
import { get as _get } from 'lodash-es' import { get as _get } from 'lodash-es'
import { storeToRefs } from 'pinia'
import { useEditStore } from '@/management/stores/edit'
import moment from 'moment' import moment from 'moment'
import 'moment/locale/zh-cn' import 'moment/locale/zh-cn'
moment.locale('zh-cn') moment.locale('zh-cn')
@ -44,21 +45,21 @@ const publishList = ref<Array<any>>([])
const currentTab = ref<'daily' | 'publish'>('daily') const currentTab = ref<'daily' | 'publish'>('daily')
const visible = ref<boolean>(false) const visible = ref<boolean>(false)
const store = useStore() const editStore = useEditStore()
const { surveyId, schemaUpdateTime } = storeToRefs(editStore)
const queryHistories = async () => { const queryHistories = async () => {
if (dirtyMonitor.value) { if (dirtyMonitor.value) {
loading.value = true loading.value = true
dirtyMonitor.value = false dirtyMonitor.value = false
const surveyId = _get(store.state, 'edit.surveyId')
const [dHis, pHis] = await Promise.all([ const [dHis, pHis] = await Promise.all([
getSurveyHistory({ getSurveyHistory({
surveyId, surveyId: surveyId.value,
historyType: 'dailyHis' historyType: 'dailyHis'
}), }),
getSurveyHistory({ getSurveyHistory({
surveyId, surveyId: surveyId.value,
historyType: 'publishHis' historyType: 'publishHis'
}) })
]).finally(() => { ]).finally(() => {
@ -81,7 +82,6 @@ const handlePopoverShow = async () => {
} }
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
const dirtyMonitor = ref<boolean>(true) const dirtyMonitor = ref<boolean>(true)
const schemaUpdateTime = computed(() => _get(store.state, 'edit.schemaUpdateTime'))
watch( watch(
schemaUpdateTime, schemaUpdateTime,

View File

@ -5,7 +5,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss' import 'element-plus/theme-chalk/src/message.scss'
@ -15,7 +15,8 @@ import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
import buildData from './buildData' import buildData from './buildData'
const isPublishing = ref<boolean>(false) const isPublishing = ref<boolean>(false)
const store = useStore() const editStore = useEditStore()
const { schema, changeSchema, getSchemaFromRemote } = editStore
const router = useRouter() const router = useRouter()
const updateLogicConf = () => { const updateLogicConf = () => {
@ -27,7 +28,7 @@ const updateLogicConf = () => {
showLogicEngine.value.validateSchema() showLogicEngine.value.validateSchema()
const showLogicConf = showLogicEngine.value.toJson() const showLogicConf = showLogicEngine.value.toJson()
// //
store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } }) changeSchema({ key: 'logicConf', value: { showLogicConf } })
} }
} }
@ -46,7 +47,7 @@ const handlePublish = async () => {
return return
} }
const saveData = buildData(store.state.edit.schema) const saveData = buildData(schema)
if (!saveData.surveyId) { if (!saveData.surveyId) {
isPublishing.value = false isPublishing.value = false
ElMessage.error('未获取到问卷id') ElMessage.error('未获取到问卷id')
@ -64,7 +65,7 @@ const handlePublish = async () => {
const publishRes: any = await publishSurvey({ surveyId: saveData.surveyId }) const publishRes: any = await publishSurvey({ surveyId: saveData.surveyId })
if (publishRes.code === 200) { if (publishRes.code === 200) {
ElMessage.success('发布成功') ElMessage.success('发布成功')
store.dispatch('edit/getSchemaFromRemote') getSchemaFromRemote()
router.push({ name: 'publish' }) router.push({ name: 'publish' })
} else { } else {
ElMessage.error(`发布失败 ${publishRes.errmsg}`) ElMessage.error(`发布失败 ${publishRes.errmsg}`)

View File

@ -15,8 +15,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, nextTick, watch } from 'vue' import { ref, computed, nextTick, watch } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { get as _get } from 'lodash-es' import { useEditStore } from '@/management/stores/edit'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss' import 'element-plus/theme-chalk/src/message.scss'
@ -36,10 +36,12 @@ const saveText = computed(
})[autoSaveStatus.value] })[autoSaveStatus.value]
) )
const store = useStore() const editStore = useEditStore()
const { schemaUpdateTime } = storeToRefs(editStore)
const { schema, changeSchema } = editStore
const saveData = async () => { const saveData = async () => {
const saveData = buildData(store.state.edit.schema) const saveData = buildData(schema)
if (!saveData.surveyId) { if (!saveData.surveyId) {
ElMessage.error('未获取到问卷id') ElMessage.error('未获取到问卷id')
@ -59,7 +61,7 @@ const updateLogicConf = () => {
showLogicEngine.value.validateSchema() showLogicEngine.value.validateSchema()
const showLogicConf = showLogicEngine.value.toJson() const showLogicConf = showLogicEngine.value.toJson()
// //
store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } }) changeSchema({ key: 'logicConf', value: { showLogicConf } })
} }
} }
@ -128,7 +130,6 @@ const handleSave = async () => {
} }
} }
const schemaUpdateTime = computed(() => _get(store.state, 'edit.schemaUpdateTime'))
watch(schemaUpdateTime, () => { watch(schemaUpdateTime, () => {
triggerAutoSave() triggerAutoSave()
}) })

View File

@ -6,13 +6,13 @@
:bannerConf="bannerConf" :bannerConf="bannerConf"
:readonly="false" :readonly="false"
:is-selected="currentEditOne === 'mainTitle'" :is-selected="currentEditOne === 'mainTitle'"
@select="onSelectEditOne('mainTitle')" @select="setCurrentEditOne('mainTitle')"
@change="handleChange" @change="handleChange"
/> />
<MaterialGroup <MaterialGroup
:current-edit-one="parseInt(currentEditOne)" :current-edit-one="parseInt(currentEditOne)"
:questionDataList="questionDataList" :questionDataList="questionDataList"
@select="onSelectEditOne" @select="setCurrentEditOne"
@change="handleChange" @change="handleChange"
@changeSeq="onQuestionOperation" @changeSeq="onQuestionOperation"
ref="materialGroup" ref="materialGroup"
@ -22,7 +22,7 @@
:readonly="false" :readonly="false"
:skin-conf="skinConf" :skin-conf="skinConf"
:is-selected="currentEditOne === 'submit'" :is-selected="currentEditOne === 'submit'"
@select="onSelectEditOne('submit')" @select="setCurrentEditOne('submit')"
/> />
</div> </div>
</div> </div>
@ -30,34 +30,29 @@
</template> </template>
<script setup> <script setup>
import { computed, ref, watch } from 'vue' import { ref, watch, toRefs } from 'vue'
import communalLoader from '@materials/communals/communalLoader.js' import communalLoader from '@materials/communals/communalLoader.js'
import MaterialGroup from '@/management/pages/edit/components/MaterialGroup.vue' import MaterialGroup from '@/management/pages/edit/components/MaterialGroup.vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { useEditStore } from '@/management/stores/edit'
const MainTitle = communalLoader.loadComponent('MainTitle') const MainTitle = communalLoader.loadComponent('MainTitle')
const SubmitButton = communalLoader.loadComponent('SubmitButton') const SubmitButton = communalLoader.loadComponent('SubmitButton')
const store = useStore() const editStore = useEditStore()
const { questionDataList, currentEditOne, currentEditKey } = storeToRefs(editStore)
const { schema, changeSchema, moveQuestion, copyQuestion, deleteQuestion, setCurrentEditOne } =
editStore
const mainOperation = ref(null) const mainOperation = ref(null)
const materialGroup = ref(null) const materialGroup = ref(null)
const bannerConf = computed(() => store.state.edit.schema.bannerConf) const { bannerConf, submitConf, skinConf } = toRefs(schema)
const submitConf = computed(() => store.state.edit.schema.submitConf) // const autoScrollData = computed(() => {
const skinConf = computed(() => store.state.edit.schema.skinConf) // return {
const questionDataList = computed(() => store.state.edit.schema.questionDataList) // currentEditOne: currentEditOne.value,
const currentEditOne = computed(() => store.state.edit.currentEditOne) // len: questionDataList.value.length
const currentEditKey = computed(() => store.getters['edit/currentEditKey']) // }
const autoScrollData = computed(() => { // })
return {
currentEditOne: currentEditOne.value,
len: questionDataList.value.length
}
})
const onSelectEditOne = async (currentEditOne) => {
store.commit('edit/setCurrentEditOne', currentEditOne)
}
const handleChange = (data) => { const handleChange = (data) => {
if (currentEditOne.value === null) { if (currentEditOne.value === null) {
@ -65,34 +60,33 @@ const handleChange = (data) => {
} }
const { key, value } = data const { key, value } = data
const resultKey = `${currentEditKey.value}.${key}` const resultKey = `${currentEditKey.value}.${key}`
store.dispatch('edit/changeSchema', { key: resultKey, value }) changeSchema({ key: resultKey, value })
} }
const onMainClick = (e) => { const onMainClick = (e) => {
if (e.target === mainOperation.value) { if (e.target === mainOperation.value) {
store.commit('edit/setCurrentEditOne', null) setCurrentEditOne(null)
} }
} }
const onQuestionOperation = (data) => { const onQuestionOperation = (data) => {
switch (data.type) { switch (data.type) {
case 'move': case 'move':
store.dispatch('edit/moveQuestion', { moveQuestion({
index: data.index, index: data.index,
range: data.range range: data.range
}) })
break break
case 'delete': case 'delete':
store.dispatch('edit/deleteQuestion', { index: data.index }) deleteQuestion({ index: data.index })
break break
case 'copy': case 'copy':
store.dispatch('edit/copyQuestion', { index: data.index }) copyQuestion({ index: data.index })
break break
default: default:
break break
} }
} }
watch( watch(
skinConf, skinConf,
(newVal) => { (newVal) => {
@ -114,22 +108,24 @@ watch(
} }
) )
watch(autoScrollData, (newVal) => { //
const { currentEditOne } = newVal //
if (typeof currentEditOne === 'number') { // watch(autoScrollData, (newVal) => {
setTimeout(() => { // const { currentEditOne } = newVal
const field = questionDataList.value?.[currentEditOne]?.field // if (typeof currentEditOne === 'number') {
if (field) { // setTimeout(() => {
const questionModule = materialGroup.value?.getQuestionRefByField(field) // const field = questionDataList.value?.[currentEditOne]?.field
if (questionModule && questionModule.$el) { // if (field) {
questionModule.$el.scrollIntoView({ // const questionModule = materialGroup.value?.getQuestionRefByField(field)
behavior: 'smooth' // if (questionModule && questionModule.$el) {
}) // questionModule.$el.scrollIntoView({
} // behavior: 'smooth'
} // })
}, 0) // }
} // }
}) // }, 0)
// }
// })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -17,23 +17,19 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { storeToRefs } from 'pinia'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import SetterField from '@/management/pages/edit/components/SetterField.vue' import SetterField from '@/management/pages/edit/components/SetterField.vue'
const store = useStore() const editStore = useEditStore()
const { currentEditOne, currentEditKey, currentEditMeta, formConfigList, moduleConfig } =
const currentEditOne = computed(() => store.state?.edit?.currentEditOne) storeToRefs(editStore)
const formConfigList = computed(() => store.getters['edit/formConfigList']) const { changeSchema } = editStore
const moduleConfig = computed(() => store.getters['edit/moduleConfig'])
const currentEditKey = computed(() => store.getters['edit/currentEditKey'])
const currentEditMeta = computed(() => store.getters['edit/currentEditMeta'])
const handleFormChange = (data: any) => { const handleFormChange = (data: any) => {
const { key, value } = data const { key, value } = data
const resultKey = `${currentEditKey.value}.${key}` const resultKey = `${currentEditKey.value}.${key}`
store.dispatch('edit/changeSchema', { key: resultKey, value }) changeSchema({ key: resultKey, value })
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -12,7 +12,7 @@
:title="element.title" :title="element.title"
:indexNumber="element.indexNumber" :indexNumber="element.indexNumber"
:showIndex="element.showIndex" :showIndex="element.showIndex"
@select="handleSelect(index)" @select="setCurrentEditOne(index)"
/> />
</template> </template>
</draggable> </draggable>
@ -20,34 +20,30 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { useEditStore } from '@/management/stores/edit'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import CatalogItem from './CatalogItem.vue' import CatalogItem from './CatalogItem.vue'
import { filterQuestionPreviewData } from '@/management/utils/index' import { filterQuestionPreviewData } from '@/management/utils/index'
const store = useStore() const editStore = useEditStore()
const { questionDataList, currentEditOne } = storeToRefs(editStore)
const { moveQuestion, setCurrentEditOne } = editStore
const renderData = computed(() => { const renderData = computed(() => {
const questions = store.state.edit.schema.questionDataList return filterQuestionPreviewData(questionDataList.value) || []
return filterQuestionPreviewData(questions) || []
}) })
const handleDragEnd = ({ newIndex, oldIndex }: any) => { const handleDragEnd = ({ newIndex, oldIndex }: any) => {
const currentActivityKey = store.state.edit.currentEditOne if (currentEditOne.value === oldIndex) {
setCurrentEditOne(newIndex)
if (currentActivityKey === oldIndex) {
handleSelect(newIndex)
} }
store.dispatch('edit/moveQuestion', { moveQuestion({
index: oldIndex, index: oldIndex,
range: newIndex - oldIndex range: newIndex - oldIndex
}) })
} }
const handleSelect = (idx: number) => {
store.commit('edit/setCurrentEditOne', idx)
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.question-catalog-wrapper { .question-catalog-wrapper {

View File

@ -45,20 +45,24 @@ import { DND_GROUP } from '@/management/config/dnd'
import questionMenuConfig, { questionTypeList } from '@/management/config/questionMenuConfig' import questionMenuConfig, { questionTypeList } from '@/management/config/questionMenuConfig'
import { getQuestionByType } from '@/management/utils/index' import { getQuestionByType } from '@/management/utils/index'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { get as _get, isNumber as _isNumber } from 'lodash-es' import { useEditStore } from '@/management/stores/edit'
import { isNumber as _isNumber } from 'lodash-es'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { QUESTION_TYPE } from '@/common/typeEnum.ts' import { QUESTION_TYPE } from '@/common/typeEnum.ts'
const store = useStore()
const editStore = useEditStore()
const { questionDataList, currentEditOne } = storeToRefs(editStore)
const { addQuestion, setCurrentEditOne } = editStore
const activeNames = ref([0, 1]) const activeNames = ref([0, 1])
const previewImg = ref('') const previewImg = ref('')
const isShowPreviewImage = ref(false) const isShowPreviewImage = ref(false)
const previewTop = ref(0) const previewTop = ref(0)
const questionDataList = computed(() => _get(store, 'state.edit.schema.questionDataList'))
const newQuestionIndex = computed(() => { const newQuestionIndex = computed(() => {
const currentEditOne = _get(store, 'state.edit.currentEditOne') const index = _isNumber(currentEditOne.value)
const index = _isNumber(currentEditOne) ? currentEditOne + 1 : questionDataList.value.length ? currentEditOne.value + 1
: questionDataList.value.length
return index return index
}) })
@ -78,8 +82,8 @@ const getNewQuestion = ({ type }) => {
const onQuestionType = ({ type }) => { const onQuestionType = ({ type }) => {
const newQuestion = getNewQuestion({ type }) const newQuestion = getNewQuestion({ type })
store.dispatch('edit/addQuestion', { question: newQuestion, index: newQuestionIndex.value }) addQuestion({ question: newQuestion, index: newQuestionIndex.value })
store.commit('edit/setCurrentEditOne', newQuestionIndex.value) setCurrentEditOne(newQuestionIndex.value)
} }
const showPreview = ({ snapshot }, id) => { const showPreview = ({ snapshot }, id) => {

View File

@ -38,7 +38,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, onMounted, shallowRef } from 'vue' import { computed, ref, onMounted, shallowRef } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import { cloneDeep as _cloneDeep, isArray as _isArray, get as _get } from 'lodash-es' import { cloneDeep as _cloneDeep, isArray as _isArray, get as _get } from 'lodash-es'
import baseConfig from './config/baseConfig' import baseConfig from './config/baseConfig'
@ -49,6 +49,9 @@ import setterLoader from '@/materials/setters/setterLoader'
const formConfigList = ref<Array<any>>([]) const formConfigList = ref<Array<any>>([])
const components = shallowRef<any>({}) const components = shallowRef<any>({})
const registerTypes = ref<any>({}) const registerTypes = ref<any>({})
const editStore = useEditStore()
const { schema, changeSchema } = editStore
const setterList = computed(() => { const setterList = computed(() => {
const list = _cloneDeep(formConfigList.value) const list = _cloneDeep(formConfigList.value)
@ -61,12 +64,12 @@ const setterList = computed(() => {
if (_isArray(formKey)) { if (_isArray(formKey)) {
formValue = [] formValue = []
for (const key of formKey) { for (const key of formKey) {
const val = _get(store.state.edit.schema, key, formItem.value) const val = _get(schema, key, formItem.value)
formValue.push(val) formValue.push(val)
dataConfig[key] = val dataConfig[key] = val
} }
} else { } else {
formValue = _get(store.state.edit.schema, formKey, formItem.value) formValue = _get(schema, formKey, formItem.value)
dataConfig[formKey] = formValue dataConfig[formKey] = formValue
} }
formItem.value = formValue formItem.value = formValue
@ -78,9 +81,8 @@ const setterList = computed(() => {
}) })
}) })
const store = useStore()
const handleFormChange = (data: any) => { const handleFormChange = (data: any) => {
store.dispatch('edit/changeSchema', { changeSchema({
key: data.key, key: data.key,
value: data.value value: data.value
}) })

View File

@ -17,10 +17,12 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import { EDIT_STATUS_MAP } from '../enum' import { EDIT_STATUS_MAP } from '../enum'
import { storeToRefs } from 'pinia'
const store = useStore() const editStore = useEditStore()
const { currentEditStatus } = storeToRefs(editStore)
const statusList = [ const statusList = [
{ {
type: EDIT_STATUS_MAP.SUCCESS, type: EDIT_STATUS_MAP.SUCCESS,
@ -35,10 +37,8 @@ const statusList = [
] ]
const handleChangePreview = (data: any) => { const handleChangePreview = (data: any) => {
const currentStatus = store.state?.edit?.currentEditStatus if (currentEditStatus.value !== data.type) {
editStore.changeCurrentEditStatus(data.type)
if (currentStatus && currentStatus !== data.type) {
store.commit('edit/changeStatusPreview', data)
} }
} }
</script> </script>

View File

@ -12,9 +12,9 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { toRef } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { get as _get } from 'lodash-es' import { useEditStore } from '@/management/stores/edit'
import SuccessContent from '../components/SuccessContent.vue' import SuccessContent from '../components/SuccessContent.vue'
import OverTime from '../components/OverTime.vue' import OverTime from '../components/OverTime.vue'
@ -25,11 +25,10 @@ const components = {
[EDIT_STATUS_MAP.OVERTIME]: OverTime [EDIT_STATUS_MAP.OVERTIME]: OverTime
} }
const store = useStore() const editStore = useEditStore()
const currentEditStatus = computed(() => store.state?.edit?.currentEditStatus) const { currentEditStatus } = storeToRefs(editStore)
const moduleConfig = computed(() => { const { schema } = editStore
return _get(store.state, 'edit.schema.submitConf') const moduleConfig = toRef(schema, 'submitConf')
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.result-config-preview { .result-config-preview {

View File

@ -23,8 +23,9 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, shallowRef } from 'vue' import { computed, ref, shallowRef, toRef } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { useEditStore } from '@/management/stores/edit'
import { get as _get } from 'lodash-es' import { get as _get } from 'lodash-es'
import FormItem from '@/materials/setters/widgets/FormItem.vue' import FormItem from '@/materials/setters/widgets/FormItem.vue'
@ -36,15 +37,16 @@ const textMap = {
OverTime: '问卷过期页面配置' OverTime: '问卷过期页面配置'
} }
const store = useStore() const editStore = useEditStore()
const { currentEditStatus } = storeToRefs(editStore)
const { schema, changeSchema } = editStore
const components = shallowRef<any>({}) const components = shallowRef<any>({})
const registerTypes = ref<any>({}) const registerTypes = ref<any>({})
const moduleConfig = computed(() => _get(store.state, 'edit.schema.submitConf')) const moduleConfig = toRef(schema, 'submitConf')
const currentEditText = computed(() => (textMap as any)[store.state.edit.currentEditStatus]) const currentEditText = computed(() => (textMap as any)[currentEditStatus.value])
const formFields = computed(() => { const formFields = computed(() => {
const currentStatus = store.state.edit.currentEditStatus const formList = (statusConfig as any)[currentEditStatus.value] || []
const formList = (statusConfig as any)[currentStatus] || []
const list = formList.map((item: any) => { const list = formList.map((item: any) => {
const value = _get(moduleConfig.value, item.key, item.value) const value = _get(moduleConfig.value, item.key, item.value)
@ -57,7 +59,7 @@ const formFields = computed(() => {
}) })
const handleFormChange = ({ key, value }: any) => { const handleFormChange = ({ key, value }: any) => {
store.dispatch('edit/changeSchema', { changeSchema({
key: `submitConf.${key}`, key: `submitConf.${key}`,
value value
}) })

View File

@ -27,13 +27,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import skinPresets from '@/management/config/skinPresets.js' import skinPresets from '@/management/config/skinPresets.js'
const store = useStore() const editStore = useEditStore()
const { changeThemePreset } = editStore
const groupName = ref<string>('temp') const groupName = ref<string>('temp')
const bannerList = computed(() => store?.state?.bannerList || []) const bannerList = computed(() => editStore.bannerList || [])
const groupList = computed(() => const groupList = computed(() =>
Object.keys(bannerList.value).map((key) => ({ Object.keys(bannerList.value).map((key) => ({
label: bannerList.value[key].name, label: bannerList.value[key].name,
@ -81,7 +82,7 @@ const changePreset = (banner: any) => {
presets = Object.assign(presets, (skinPresets as any)[name]) presets = Object.assign(presets, (skinPresets as any)[name])
} }
store.dispatch('edit/changeThemePreset', presets) changeThemePreset(presets)
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -13,7 +13,6 @@
:readonly="false" :readonly="false"
:is-selected="currentEditOne === 'submit'" :is-selected="currentEditOne === 'submit'"
/> />
</div>
<LogoIcon <LogoIcon
:logo-conf="bottomConf" :logo-conf="bottomConf"
:readonly="false" :readonly="false"
@ -22,11 +21,13 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<script> <script>
import { computed, defineComponent } from 'vue' import { defineComponent, toRefs } from 'vue'
import MaterialGroup from '@/management/pages/edit/components/MaterialGroup.vue' import MaterialGroup from '@/management/pages/edit/components/MaterialGroup.vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { useEditStore } from '@/management/stores/edit'
import communalLoader from '@materials/communals/communalLoader.js' import communalLoader from '@materials/communals/communalLoader.js'
const HeaderContent = () => communalLoader.loadComponent('HeaderContent') const HeaderContent = () => communalLoader.loadComponent('HeaderContent')
@ -43,15 +44,10 @@ export default defineComponent({
LogoIcon: LogoIcon() LogoIcon: LogoIcon()
}, },
setup() { setup() {
const store = useStore() const editStore = useEditStore()
const { questionDataList, currentEditOne, currentEditKey } = storeToRefs(editStore)
const bannerConf = computed(() => store.state.edit.schema.bannerConf) const { schema } = editStore
const submitConf = computed(() => store.state.edit.schema.submitConf) const { bannerConf, submitConf, skinConf, bottomConf } = toRefs(schema)
const bottomConf = computed(() => store.state.edit.schema.bottomConf)
const skinConf = computed(() => store.state.edit.schema.skinConf)
const questionDataList = computed(() => store.state.edit.schema.questionDataList)
const currentEditOne = computed(() => store.state.edit.currentEditOne)
const currentEditKey = computed(() => store.getters['edit/currentEditKey'])
return { return {
bannerConf, bannerConf,

View File

@ -24,23 +24,23 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue' import { ref } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import { get as _get } from 'lodash-es' import { get as _get } from 'lodash-es'
import skinConfig from '@/management/config/setterConfig/skinConfig' import skinConfig from '@/management/config/setterConfig/skinConfig'
import SetterField from '@/management/pages/edit/components/SetterField.vue' import SetterField from '@/management/pages/edit/components/SetterField.vue'
const store = useStore() const editStore = useEditStore()
const { schema, changeSchema } = editStore
const collapse = ref<string>('') const collapse = ref<string>('')
const schema = computed(() => _get(store.state, 'edit.schema'))
const handleFormChange = (data: any, collapse: string) => { const handleFormChange = (data: any, collapse: string) => {
const { key, value } = data const { key, value } = data
const currentEditKey = `${collapse}` const currentEditKey = `${collapse}`
const resultKey = `${currentEditKey}.${key}` const resultKey = `${currentEditKey}.${key}`
store.dispatch('edit/changeSchema', { key: resultKey, value }) changeSchema({ key: resultKey, value })
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -5,17 +5,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, provide } from 'vue' import { computed, provide } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { useEditStore } from '@/management/stores/edit'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import RulePanel from '../../modules/logicModule/RulePanel.vue' import RulePanel from '../../modules/logicModule/RulePanel.vue'
import { filterQuestionPreviewData } from '@/management/utils/index' import { filterQuestionPreviewData } from '@/management/utils/index'
const store = useStore() const editStore = useEditStore()
const { questionDataList } = storeToRefs(editStore)
const questionDataList = computed(() => {
return store.state.edit.schema.questionDataList
})
const renderData = computed(() => { const renderData = computed(() => {
return filterQuestionPreviewData(cloneDeep(questionDataList.value)) return filterQuestionPreviewData(cloneDeep(questionDataList.value))

View File

@ -13,17 +13,17 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue' import { onMounted } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import CommonTemplate from '../../components/CommonTemplate.vue' import CommonTemplate from '../../components/CommonTemplate.vue'
import CatalogPanel from '../../modules/settingModule/skin/CatalogPanel.vue' import CatalogPanel from '../../modules/settingModule/skin/CatalogPanel.vue'
import PreviewPanel from '../../modules/settingModule/skin/PreviewPanel.vue' import PreviewPanel from '../../modules/settingModule/skin/PreviewPanel.vue'
import SetterPanel from '../../modules/settingModule/skin/SetterPanel.vue' import SetterPanel from '../../modules/settingModule/skin/SetterPanel.vue'
const store = useStore() const editStore = useEditStore()
onMounted(() => { onMounted(() => {
store.dispatch('getBannerData') editStore.fetchBannerData()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -105,9 +105,9 @@
<script setup> <script setup>
import { ref, computed, unref } from 'vue' import { ref, computed, unref } from 'vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { get, map } from 'lodash-es' import { get, map } from 'lodash-es'
import { storeToRefs } from 'pinia'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss' import 'element-plus/theme-chalk/src/message.scss'
@ -124,6 +124,8 @@ import CooperModify from '@/management/components/CooperModify/ModifyDialog.vue'
import { CODE_MAP } from '@/management/api/base' import { CODE_MAP } from '@/management/api/base'
import { QOP_MAP } from '@/management/utils/constant.ts' import { QOP_MAP } from '@/management/utils/constant.ts'
import { deleteSurvey } from '@/management/api/survey' import { deleteSurvey } from '@/management/api/survey'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
import { useSurveyListStore } from '@/management/stores/surveyList'
import ModifyDialog from './ModifyDialog.vue' import ModifyDialog from './ModifyDialog.vue'
import TagModule from './TagModule.vue' import TagModule from './TagModule.vue'
import StateModule from './StateModule.vue' import StateModule from './StateModule.vue'
@ -141,7 +143,9 @@ import {
buttonOptionsDict buttonOptionsDict
} from '@/management/config/listConfig' } from '@/management/config/listConfig'
const store = useStore() const surveyListStore = useSurveyListStore()
const workSpaceStore = useWorkSpaceStore()
const { workSpaceId } = storeToRefs(workSpaceStore)
const router = useRouter() const router = useRouter()
const props = defineProps({ const props = defineProps({
loading: { loading: {
@ -162,17 +166,9 @@ const fields = ['type', 'title', 'remark', 'owner', 'state', 'createDate', 'upda
const showModify = ref(false) const showModify = ref(false)
const modifyType = ref('') const modifyType = ref('')
const questionInfo = ref({}) const questionInfo = ref({})
const currentPage = ref(1) const currentPage = ref(1)
const searchVal = computed(() => { const { searchVal, selectValueMap, buttonValueMap } = storeToRefs(surveyListStore)
return store.state.list.searchVal
})
const selectValueMap = computed(() => {
return store.state.list.selectValueMap
})
const buttonValueMap = computed(() => {
return store.state.list.buttonValueMap
})
const currentComponent = computed(() => { const currentComponent = computed(() => {
return (componentName) => { return (componentName) => {
switch (componentName) { switch (componentName) {
@ -247,11 +243,8 @@ const order = computed(() => {
}, []) }, [])
return JSON.stringify(formatOrder) return JSON.stringify(formatOrder)
}) })
const workSpaceId = computed(() => {
return store.state.list.workSpaceId
})
const onRefresh = async () => { const onReflush = async () => {
const filterString = JSON.stringify( const filterString = JSON.stringify(
filter.value.filter((item) => { filter.value.filter((item) => {
return item.condition[0].value return item.condition[0].value
@ -298,7 +291,7 @@ const getToolConfig = (row) => {
label: '协作' label: '协作'
} }
] ]
if (!store.state.list.workSpaceId) { if (!workSpaceId.value) {
if (!row.isCollaborated) { if (!row.isCollaborated) {
// //
funcList = funcList.concat(permissionsBtn) funcList = funcList.concat(permissionsBtn)
@ -430,19 +423,18 @@ const onRowClick = (row) => {
}) })
} }
const onSearchText = (e) => { const onSearchText = (e) => {
store.commit('list/setSearchVal', e) searchVal.value = e
currentPage.value = 1 currentPage.value = 1
onRefresh() onRefresh()
} }
const onSelectChange = (selectKey, selectValue) => { const onSelectChange = (selectKey, selectValue) => {
store.commit('list/changeSelectValueMap', { key: selectKey, value: selectValue }) surveyListStore.changeSelectValueMap(selectKey, selectValue)
// selectValueMap.value[selectKey] = selectValue
currentPage.value = 1 currentPage.value = 1
onRefresh() onRefresh()
} }
const onButtonChange = (effectKey, effectValue) => { const onButtonChange = (effectKey, effectValue) => {
store.commit('list/resetButtonValueMap') surveyListStore.resetButtonValueMap()
store.commit('list/changeButtonValueMap', { key: effectKey, value: effectValue }) surveyListStore.changeButtonValueMap(effectKey, effectValue)
onRefresh() onRefresh()
} }

View File

@ -76,7 +76,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { useStore } from 'vuex'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import 'element-plus/theme-chalk/src/message-box.scss' import 'element-plus/theme-chalk/src/message-box.scss'
import { get, map } from 'lodash-es' import { get, map } from 'lodash-es'
@ -90,10 +89,10 @@ import TextSearch from '@/management/pages/list/components/TextSearch.vue'
import EmptyIndex from '@/management/components/EmptyIndex.vue' import EmptyIndex from '@/management/components/EmptyIndex.vue'
import ToolBar from './ToolBar.vue' import ToolBar from './ToolBar.vue'
import { UserRole } from '@/management/utils/types/workSpace' import { UserRole } from '@/management/utils/types/workSpace'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
const showSpaceModify = ref(false) const showSpaceModify = ref(false)
const modifyType = ref('edit') const modifyType = ref('edit')
const store = useStore()
const props = defineProps({ const props = defineProps({
loading: { loading: {
type: Boolean, type: Boolean,
@ -109,15 +108,17 @@ const props = defineProps({
} }
}) })
const emit = defineEmits(['refresh']) const emit = defineEmits(['refresh'])
const workSpaceStore = useWorkSpaceStore()
const fields = ['name', 'surveyTotal', 'memberTotal', 'owner', 'createDate'] const fields = ['name', 'surveyTotal', 'memberTotal', 'owner', 'createDate']
const fieldList = computed(() => { const fieldList = computed(() => {
return map(fields, (f) => { return map(fields, (f) => {
return get(spaceListConfig, f, null) return get(spaceListConfig, f, null)
}) })
}) })
const isAdmin = (id: string) => { const isAdmin = (id: string) => {
return ( return (
store.state.list.teamSpaceList.find((item: any) => item._id === id)?.currentUserRole === workSpaceStore.workSpaceList.find((item: any) => item._id === id)?.currentUserRole ===
UserRole.Admin UserRole.Admin
) )
} }
@ -152,7 +153,7 @@ const getTools = (data: any) => {
} }
const handleModify = async (id: string) => { const handleModify = async (id: string) => {
await store.dispatch('list/getSpaceDetail', id) await workSpaceStore.getSpaceDetail(id)
modifyType.value = 'edit' modifyType.value = 'edit'
showSpaceModify.value = true showSpaceModify.value = true
} }
@ -167,8 +168,8 @@ const handleDelete = (id: string) => {
} }
) )
.then(async () => { .then(async () => {
await store.dispatch('list/deleteSpace', id) await workSpaceStore.deleteSpace(id)
await store.dispatch('list/getSpaceList') await workSpaceStore.getSpaceList()
curPage.value = 1 curPage.value = 1
}) })
.catch(() => {}) .catch(() => {})
@ -184,9 +185,10 @@ const handleClick = (key: string, data: any) => {
const onCloseModify = () => { const onCloseModify = () => {
showSpaceModify.value = false showSpaceModify.value = false
store.dispatch('list/getSpaceList') workSpaceStore.getSpaceList()
curPage.value = 1 curPage.value = 1
} }
defineExpose({ onCloseModify }) defineExpose({ onCloseModify })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -44,17 +44,15 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref, shallowRef, onMounted } from 'vue' import { computed, ref, shallowRef, onMounted } from 'vue'
import { useStore } from 'vuex'
import { pick as _pick } from 'lodash-es' import { pick as _pick } from 'lodash-es'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss' import 'element-plus/theme-chalk/src/message.scss'
import { QOP_MAP } from '@/management/utils/constant' import { QOP_MAP } from '@/management/utils/constant'
import { type IMember, type IWorkspace, UserRole } from '@/management/utils/types/workSpace'
import MemberSelect from '@/management/components/CooperModify/MemberSelect.vue' import MemberSelect from '@/management/components/CooperModify/MemberSelect.vue'
import { type IMember, type IWorkspace, UserRole } from '@/management/utils/types/workSpace'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
const store = useStore() const workSpaceStore = useWorkSpaceStore()
const emit = defineEmits(['on-close-codify', 'onFocus', 'change', 'blur']) const emit = defineEmits(['on-close-codify', 'onFocus', 'change', 'blur'])
const props = defineProps({ const props = defineProps({
type: String, type: String,
@ -66,7 +64,8 @@ const ruleForm = shallowRef<any>(null)
const formTitle = computed(() => { const formTitle = computed(() => {
return props.type === QOP_MAP.ADD ? '创建团队空间' : '管理团队空间' return props.type === QOP_MAP.ADD ? '创建团队空间' : '管理团队空间'
}) })
const formModel = ref<IWorkspace>({ const formModel = ref<Required<IWorkspace>>({
_id: '',
name: '', name: '',
description: '', description: '',
members: [] as IMember[] members: [] as IMember[]
@ -88,28 +87,29 @@ const rules = {
] ]
} }
const spaceDetail = computed(() => { const spaceDetail = computed(() => {
return store.state.list.spaceDetail return workSpaceStore.spaceDetail
}) })
const formDisabled = computed(() => { const formDisabled = computed(() => {
return spaceDetail.value?._id return spaceDetail.value?._id
? store.state.list.teamSpaceList.find((item: any) => item._id === spaceDetail.value._id) ? workSpaceStore.workSpaceList.find((item: any) => item._id === spaceDetail.value?._id)
.currentUserRole !== UserRole.Admin ?.currentUserRole !== UserRole.Admin
: false : false
}) })
onMounted(() => { onMounted(() => {
if (props.type === QOP_MAP.EDIT) { if (props.type === QOP_MAP.EDIT) {
formModel.value = _pick(spaceDetail.value, ['_id', 'name', 'description', 'members']) formModel.value = _pick(spaceDetail.value as any, ['_id', 'name', 'description', 'members'])
} }
}) })
const onClose = () => { const onClose = () => {
formModel.value = { formModel.value = {
_id: '',
name: '', name: '',
description: '', description: '',
members: [] as IMember[] members: [] as IMember[]
} }
// //
store.commit('list/setSpaceDetail', null) workSpaceStore.setSpaceDetail(null)
emit('on-close-codify') emit('on-close-codify')
} }
@ -144,10 +144,10 @@ const handleMembersChange = (val: IMember[]) => {
formModel.value.members = val formModel.value.members = val
} }
const handleUpdate = async () => { const handleUpdate = async () => {
await store.dispatch('list/updateSpace', formModel.value) await workSpaceStore.updateSpace(formModel.value)
} }
const handleAdd = async () => { const handleAdd = async () => {
await store.dispatch('list/addSpace', formModel.value) await workSpaceStore.addSpace(formModel.value)
} }
</script> </script>

View File

@ -56,8 +56,8 @@
ref="spaceListRef" ref="spaceListRef"
@refresh="fetchSpaceList" @refresh="fetchSpaceList"
:loading="spaceLoading" :loading="spaceLoading"
:data="spaceList" :data="workSpaceList"
:total="spaceTotal" :total="workSpaceListTotal"
v-if="spaceType === SpaceType.Group" v-if="spaceType === SpaceType.Group"
></SpaceList> ></SpaceList>
</div> </div>
@ -73,83 +73,66 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import BaseList from './components/BaseList.vue' import BaseList from './components/BaseList.vue'
import SpaceList from './components/SpaceList.vue' import SpaceList from './components/SpaceList.vue'
import SliderBar from './components/SliderBar.vue' import SliderBar from './components/SliderBar.vue'
import SpaceModify from './components/SpaceModify.vue' import SpaceModify from './components/SpaceModify.vue'
import { SpaceType } from '@/management/utils/types/workSpace' import { SpaceType } from '@/management/utils/types/workSpace'
import { useUserStore } from '@/management/stores/user'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
import { useSurveyListStore } from '@/management/stores/surveyList'
const store = useStore() const userStore = useUserStore()
const workSpaceStore = useWorkSpaceStore()
const surveyListStore = useSurveyListStore()
const { surveyList, surveyTotal } = storeToRefs(surveyListStore)
const { spaceMenus, workSpaceId, spaceType, workSpaceList, workSpaceListTotal } =
storeToRefs(workSpaceStore)
const router = useRouter() const router = useRouter()
const userInfo = computed(() => { const userInfo = computed(() => {
return store.state.user.userInfo return userStore.userInfo
}) })
const loading = ref(false) const loading = ref(false)
const surveyList = computed(() => {
return store.state.list.surveyList
})
const surveyTotal = computed(() => {
return store.state.list.surveyTotal
})
const spaceListRef = ref<any>(null) const spaceListRef = ref<any>(null)
const spaceLoading = ref(false) const spaceLoading = ref(false)
const spaceList = computed(() => {
return store.state.list.teamSpaceList
})
const spaceTotal = computed(() => {
return store.state.list.teamSpaceListTotal
})
const fetchSpaceList = async (params?: any) => {
spaceLoading.value = true
store.commit('list/changeWorkSpace', '')
await store.dispatch('list/getSpaceList', params)
spaceLoading.value = false
}
const activeIndex = ref('1') const activeIndex = ref('1')
const spaceMenus = computed(() => { const fetchSpaceList = async (params?: any) => {
return store.state.list.spaceMenus spaceLoading.value = true
}) workSpaceStore.changeWorkSpace('')
const workSpaceId = computed(() => { workSpaceStore.getSpaceList(params)
return store.state.list.workSpaceId spaceLoading.value = false
}) }
const spaceType = computed(() => {
return store.state.list.spaceType
})
const handleSpaceSelect = (id: SpaceType | string) => { const handleSpaceSelect = (id: SpaceType | string) => {
if (id === store.state.list.spaceType || id === store.state.list.workSpaceId) { if (id === spaceType.value || id === workSpaceId.value) {
return void 0 return void 0
} }
const changeSpaceType = (type: SpaceType) => {
store.commit('list/changeSpaceType', type)
}
const changeWorkSpace = (id: string) => {
store.commit('list/changeWorkSpace', id)
}
switch (id) { switch (id) {
case SpaceType.Personal: case SpaceType.Personal:
changeSpaceType(SpaceType.Personal) workSpaceStore.changeSpaceType(SpaceType.Personal)
changeWorkSpace('') workSpaceStore.changeWorkSpace('')
break break
case SpaceType.Group: case SpaceType.Group:
changeSpaceType(SpaceType.Group) workSpaceStore.changeSpaceType(SpaceType.Group)
changeWorkSpace('') workSpaceStore.changeWorkSpace('')
fetchSpaceList() fetchSpaceList()
break break
default: default:
changeSpaceType(SpaceType.Teamwork) workSpaceStore.changeSpaceType(SpaceType.Teamwork)
changeWorkSpace(id) workSpaceStore.changeWorkSpace(id)
break break
} }
fetchSurveyList() fetchSurveyList()
} }
onMounted(() => {
fetchSpaceList()
fetchSurveyList()
})
const fetchSurveyList = async (params?: any) => { const fetchSurveyList = async (params?: any) => {
if (!params) { if (!params) {
params = { params = {
@ -161,19 +144,25 @@ const fetchSurveyList = async (params?: any) => {
params.workspaceId = workSpaceId.value params.workspaceId = workSpaceId.value
} }
loading.value = true loading.value = true
await store.dispatch('list/getSurveyList', params) await surveyListStore.getSurveyList(params)
loading.value = false loading.value = false
} }
onMounted(() => {
fetchSpaceList()
fetchSurveyList()
})
const modifyType = ref('add') const modifyType = ref('add')
const showSpaceModify = ref(false) const showSpaceModify = ref(false)
// //
const currentTeamSpace = computed(() => { const currentTeamSpace = computed(() => {
return store.state.list.teamSpaceList.find((item: any) => item._id === workSpaceId.value) return workSpaceList.value.find((item: any) => item._id === workSpaceId.value)
}) })
const onSetGroup = async () => { const onSetGroup = async () => {
await store.dispatch('list/getSpaceDetail', workSpaceId.value) await workSpaceStore.getSpaceDetail(workSpaceId.value)
modifyType.value = 'edit' modifyType.value = 'edit'
showSpaceModify.value = true showSpaceModify.value = true
} }
@ -192,7 +181,7 @@ const onCreate = () => {
router.push('/create') router.push('/create')
} }
const handleLogout = () => { const handleLogout = () => {
store.dispatch('user/logout') userStore.logout()
router.replace({ name: 'login' }) router.replace({ name: 'login' })
} }
</script> </script>

View File

@ -57,7 +57,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, reactive } from 'vue' import { onMounted, ref, reactive } from 'vue'
import { useStore } from 'vuex'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
@ -66,8 +65,8 @@ import 'element-plus/theme-chalk/src/message.scss'
import { login, register } from '@/management/api/auth' import { login, register } from '@/management/api/auth'
import { refreshCaptcha as refreshCaptchaApi } from '@/management/api/captcha' import { refreshCaptcha as refreshCaptchaApi } from '@/management/api/captcha'
import { CODE_MAP } from '@/management/api/base' import { CODE_MAP } from '@/management/api/base'
import { useUserStore } from '@/management/stores/user'
const store = useStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@ -150,7 +149,8 @@ const submitForm = (type: 'login' | 'register') => {
ElMessage.error(res.errmsg) ElMessage.error(res.errmsg)
throw new Error('登录/注册失败' + res.errmsg) throw new Error('登录/注册失败' + res.errmsg)
} }
store.dispatch('user/login', { const userStore = useUserStore()
userStore.login({
username: res.data.username, username: res.data.username,
token: res.data.token token: res.data.token
}) })

View File

@ -25,8 +25,8 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted } from 'vue' import { computed, onMounted, toRef } from 'vue'
import { useStore } from 'vuex' import { useEditStore } from '@/management/stores/edit'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { get as _get } from 'lodash-es' import { get as _get } from 'lodash-es'
@ -44,14 +44,15 @@ const defaultConfig = {
img: '/imgs/icons/unpublished.webp' img: '/imgs/icons/unpublished.webp'
} }
const store = useStore() const editStore = useEditStore()
const metaData = computed(() => _get(store.state, 'edit.schema.metaData')) const { schema, init, setSurveyId } = editStore
const metaData = toRef(schema, 'metaData')
const curStatus = computed(() => _get(metaData.value, 'curStatus.status', 'new')) const curStatus = computed(() => _get(metaData.value, 'curStatus.status', 'new'))
const mainChannel = computed(() => { const mainChannel = computed(() => {
let fullUrl = '' let fullUrl = ''
if (metaData.value) { if (metaData.value) {
fullUrl = `${location.origin}/render/${metaData.value.surveyPath}?t=${Date.now()}` fullUrl = `${location.origin}/render/${(metaData.value as any).surveyPath}?t=${Date.now()}`
} }
return { fullUrl } return { fullUrl }
@ -60,10 +61,10 @@ const mainChannel = computed(() => {
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
onMounted(async () => { onMounted(async () => {
store.commit('edit/setSurveyId', route.params.id) setSurveyId(route.params.id as string)
try { try {
await store.dispatch('edit/init') await init()
} catch (err: any) { } catch (err: any) {
ElMessage.error(err.message) ElMessage.error(err.message)
setTimeout(() => { setTimeout(() => {

View File

@ -5,11 +5,12 @@ import {
type NavigationGuardNext type NavigationGuardNext
} from 'vue-router' } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router' import type { RouteRecordRaw } from 'vue-router'
import { useStore, type Store } from 'vuex'
import { SurveyPermissions } from '@/management/utils/types/workSpace' import { SurveyPermissions } from '@/management/utils/types/workSpace'
import { analysisTypeMap } from '@/management/config/analysisConfig' import { analysisTypeMap } from '@/management/config/analysisConfig'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss' import 'element-plus/theme-chalk/src/message.scss'
import { useUserStore } from '@/management/stores/user'
import { useEditStore } from '@/management/stores/edit'
const routes: RouteRecordRaw[] = [ const routes: RouteRecordRaw[] = [
{ {
@ -161,10 +162,10 @@ const router = createRouter({
}) })
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const store = useStore() const userStore = useUserStore()
// 初始化用户信息 // 初始化用户信息
if (!store.state.user?.initialized) { if (!userStore?.initialized) {
await store.dispatch('user/init') await userStore.init()
} }
// 更新页面标题 // 更新页面标题
if (to.meta.title) { if (to.meta.title) {
@ -172,7 +173,7 @@ router.beforeEach(async (to, from, next) => {
} }
if (to.meta.needLogin) { if (to.meta.needLogin) {
await handleLoginGuard(to, from, next, store) await handleLoginGuard(to, from, next)
} else { } else {
next() next()
} }
@ -181,11 +182,11 @@ router.beforeEach(async (to, from, next) => {
async function handleLoginGuard( async function handleLoginGuard(
to: RouteLocationNormalized, to: RouteLocationNormalized,
from: RouteLocationNormalized, from: RouteLocationNormalized,
next: NavigationGuardNext, next: NavigationGuardNext
store: Store<any>
) { ) {
if (store.state.user?.hasLogined) { const userStore = useUserStore()
await handlePermissionsGuard(to, from, next, store) if (userStore?.hasLogined) {
await handlePermissionsGuard(to, from, next)
} else { } else {
next({ next({
name: 'login', name: 'login',
@ -197,9 +198,9 @@ async function handleLoginGuard(
async function handlePermissionsGuard( async function handlePermissionsGuard(
to: RouteLocationNormalized, to: RouteLocationNormalized,
from: RouteLocationNormalized, from: RouteLocationNormalized,
next: NavigationGuardNext, next: NavigationGuardNext
store: Store<any>
) { ) {
const editStore = useEditStore()
const currSurveyId = to?.params?.id || '' const currSurveyId = to?.params?.id || ''
const prevSurveyId = from?.params?.id || '' const prevSurveyId = from?.params?.id || ''
// 如果跳转页面不存在surveyId 或者不需要页面权限,则直接跳转 // 如果跳转页面不存在surveyId 或者不需要页面权限,则直接跳转
@ -208,8 +209,8 @@ async function handlePermissionsGuard(
} else { } else {
// 如果跳转编辑页面且跳转页面和上一页的surveyId不同判断是否有对应页面权限 // 如果跳转编辑页面且跳转页面和上一页的surveyId不同判断是否有对应页面权限
if (currSurveyId !== prevSurveyId) { if (currSurveyId !== prevSurveyId) {
await store.dispatch('fetchCooperPermissions', currSurveyId) await editStore.fetchCooperPermissions(currSurveyId as string)
if (hasRequiredPermissions(to.meta.permissions as string[], store.state.cooperPermissions)) { if (hasRequiredPermissions(to.meta.permissions as string[], editStore.cooperPermissions)) {
next() next()
} else { } else {
ElMessage.warning('您没有该问卷的相关协作权限') ElMessage.warning('您没有该问卷的相关协作权限')

View File

@ -0,0 +1,372 @@
import { type Ref, ref, reactive, toRef, computed } from 'vue'
import { defineStore } from 'pinia'
import { merge as _merge, cloneDeep as _cloneDeep, set as _set } from 'lodash-es'
import { getSurveyById } from '@/management/api/survey'
import { getNewField } from '@/management/utils'
import submitFormConfig from '@/management/config/setterConfig/submitConfig'
import questionLoader from '@/materials/questions/questionLoader'
import { SurveyPermissions } from '@/management/utils/types/workSpace'
import { getBannerData } from '@/management/api/skin.js'
import { getCollaboratorPermissions } from '@/management/api/space'
import { CODE_MAP } from '../api/base'
const innerMetaConfig = {
submit: {
title: '提交配置',
formConfig: submitFormConfig
}
}
function useInitializeSchema(surveyId: Ref<string>) {
const schema = reactive({
metaData: null,
bannerConf: {
titleConfig: {
mainTitle: '<h3 style="text-align: center">欢迎填写问卷</h3>',
subTitle: `<p>为了给您提供更好的服务,希望您能抽出几分钟时间,将您的感受和建议告诉我们,<span style="color: rgb(204, 0, 0)">期待您的参与!</span></p>`,
applyTitle: ''
},
bannerConfig: {
bgImage: '',
bgImageAllowJump: false,
bgImageJumpLink: '',
videoLink: '',
postImg: ''
}
},
bottomConf: {
logoImage: '',
logoImageWidth: '28%'
},
skinConf: {
backgroundConf: {
color: '#fff'
},
themeConf: {
color: '#ffa600'
},
contentConf: {
opacity: 100
}
},
baseConf: {
begTime: '',
endTime: '',
language: 'chinese',
showVoteProcess: 'allow',
tLimit: 0,
answerBegTime: '',
answerEndTime: '',
answerLimitTime: 0
},
submitConf: {
submitTitle: '',
msgContent: {},
confirmAgain: {
is_again: true
},
link: ''
},
questionDataList: [],
logicConf: {
showLogicConf: []
}
})
function initSchema({ metaData, codeData }: { metaData: any; codeData: any }) {
schema.metaData = metaData
schema.bannerConf = _merge({}, schema.bannerConf, codeData.bannerConf)
schema.bottomConf = _merge({}, schema.bottomConf, codeData.bottomConf)
schema.skinConf = _merge({}, schema.skinConf, codeData.skinConf)
schema.baseConf = _merge({}, schema.baseConf, codeData.baseConf)
schema.submitConf = _merge({}, schema.submitConf, codeData.submitConf)
schema.questionDataList = codeData.questionDataList || []
schema.logicConf = codeData.logicConf
}
async function getSchemaFromRemote() {
const res: any = await getSurveyById(surveyId.value)
if (res.code === 200) {
const metaData = res.data.surveyMetaRes
document.title = metaData.title
const {
bannerConf,
bottomConf,
skinConf,
baseConf,
submitConf,
dataConf,
logicConf = {}
} = res.data.surveyConfRes.code
initSchema({
metaData,
codeData: {
bannerConf,
bottomConf,
skinConf,
baseConf,
submitConf,
questionDataList: dataConf.dataList,
logicConf
}
})
} else {
throw new Error(res.errmsg || '问卷不存在')
}
}
return {
schema,
initSchema,
getSchemaFromRemote
}
}
function useQuestionDataListOperations(questionDataList: Ref<any[]>, updateTime: () => void) {
function copyQuestion({ index }: { index: number }) {
const newQuestion = _cloneDeep(questionDataList.value[index])
newQuestion.field = getNewField(questionDataList.value.map((item) => item.field))
addQuestion({ question: newQuestion, index })
}
function addQuestion({ question, index }: { question: any; index: number }) {
questionDataList.value.splice(index, 0, question)
updateTime()
}
function deleteQuestion({ index }: { index: number }) {
questionDataList.value.splice(index, 1)
updateTime()
}
function moveQuestion({ index, range }: { index: number; range: number }) {
console.log('move')
let start, end
if (range < 0) {
// 向上移动
start = index + range
end = index
} else if (range > 0) {
// 向下移动
start = index + 1
end = index + range + 1
} else {
// 无变化
return
}
const currentData = questionDataList.value[index]
// 新位置和老位置之间所有的题目
const comparedList = questionDataList.value.slice(start, end)
if (range < 0) {
// 向上移动
questionDataList.value.splice(index + range, 1 - range, currentData, ...comparedList)
} else if (range > 0) {
// 向下移动
questionDataList.value.splice(index, range + 1, ...comparedList, currentData)
}
updateTime()
}
return {
copyQuestion,
addQuestion,
deleteQuestion,
moveQuestion
}
}
function useCurrentEdit({
schema,
questionDataList
}: {
schema: any
questionDataList: Ref<any[]>
}) {
const currentEditOne = ref()
const currentEditStatus = ref('Success')
const currentEditKey = computed(() => {
if (currentEditOne.value === null) {
return null
}
let key = ''
switch (currentEditOne.value) {
case 'banner':
case 'mainTitle':
key = 'bannerConf'
break
case 'submit':
key = 'submitConf'
break
case 'logo':
key = 'bottomConf'
break
default:
key = `questionDataList.${currentEditOne.value}`
}
return key
})
const currentEditMeta = computed(() => {
if (currentEditOne.value === null) {
return null
} else if (innerMetaConfig[currentEditOne.value as keyof typeof innerMetaConfig]) {
return innerMetaConfig[currentEditOne.value as keyof typeof innerMetaConfig]
} else {
const questionType = questionDataList.value?.[currentEditOne.value]?.type
return questionLoader.getMeta(questionType)
}
})
const moduleConfig = computed(() => {
if (currentEditOne.value === null) {
return null
}
if (currentEditOne.value === 'banner' || currentEditOne.value === 'mainTitle') {
return schema?.bannerConf
} else if (currentEditOne.value === 'submit') {
return schema?.submitConf
} else if (currentEditOne.value === 'logo') {
return schema?.bottomConf
} else if (!Number.isNaN(currentEditOne.value)) {
return questionDataList.value?.[currentEditOne.value]
} else {
return null
}
})
const formConfigList = computed(() => {
if (currentEditOne.value === null) {
return null
}
return currentEditMeta.value?.formConfig || []
})
function setCurrentEditOne(data: any) {
currentEditOne.value = data
}
function changeCurrentEditStatus(status: string) {
currentEditStatus.value = status
}
return {
currentEditOne,
currentEditKey,
currentEditStatus,
moduleConfig,
formConfigList,
currentEditMeta,
setCurrentEditOne,
changeCurrentEditStatus
}
}
type IBannerItem = {
name: string
key: string
list: Array<Object>
}
type IBannerList = Record<string, IBannerItem>
export const useEditStore = defineStore('edit', () => {
const surveyId = ref('')
const bannerList: Ref<IBannerList> = ref({})
const cooperPermissions = ref(Object.values(SurveyPermissions))
const schemaUpdateTime = ref(Date.now())
const { schema, initSchema, getSchemaFromRemote } = useInitializeSchema(surveyId)
const questionDataList = toRef(schema, 'questionDataList')
function setQuestionDataList(data: any) {
schema.questionDataList = data
}
function setSurveyId(id: string) {
surveyId.value = id
}
const fetchBannerData = async () => {
const res: any = await getBannerData()
if (res.code === CODE_MAP.SUCCESS) {
bannerList.value = res.data
}
}
const fetchCooperPermissions = async (id: string) => {
const res: any = await getCollaboratorPermissions(id)
if (res.code === CODE_MAP.SUCCESS) {
cooperPermissions.value = res.data.permissions
}
}
const {
currentEditOne,
currentEditKey,
currentEditStatus,
moduleConfig,
formConfigList,
currentEditMeta,
setCurrentEditOne,
changeCurrentEditStatus
} = useCurrentEdit({ schema, questionDataList })
async function init() {
const { metaData } = schema
if (!metaData || (metaData as any)?._id !== surveyId.value) {
getSchemaFromRemote()
}
currentEditOne.value = null
currentEditStatus.value = 'Success'
}
function updateTime() {
schemaUpdateTime.value = Date.now()
}
const { copyQuestion, addQuestion, deleteQuestion, moveQuestion } = useQuestionDataListOperations(
questionDataList,
updateTime
)
function changeSchema({ key, value }: { key: string; value: any }) {
_set(schema, key, value)
updateTime()
}
function changeThemePreset(presets: any) {
Object.keys(presets).forEach((key) => {
_set(schema, key, presets[key])
})
}
return {
surveyId,
setSurveyId,
bannerList,
fetchBannerData,
cooperPermissions,
fetchCooperPermissions,
currentEditOne,
moduleConfig,
formConfigList,
currentEditKey,
currentEditStatus,
currentEditMeta,
setCurrentEditOne,
changeCurrentEditStatus,
schemaUpdateTime,
schema,
questionDataList,
setQuestionDataList,
init,
initSchema,
getSchemaFromRemote,
copyQuestion,
addQuestion,
deleteQuestion,
moveQuestion,
changeSchema,
changeThemePreset
}
})

View File

@ -0,0 +1,170 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import { CODE_MAP } from '@/management/api/base'
import { getSurveyList as getSurveyListReq } from '@/management/api/survey'
import { useWorkSpaceStore } from './workSpace'
function useSearchSurvey() {
const searchVal = ref('')
const selectValueMap = ref<Record<string, any>>({
surveyType: '',
'curStatus.status': ''
})
const buttonValueMap = ref<Record<string, any>>({
'curStatus.date': '',
createDate: -1
})
const listFilter = computed(() => {
return [
{
comparator: '',
condition: [
{
field: 'title',
value: searchVal.value,
comparator: '$regex'
}
]
},
{
comparator: '',
condition: [
{
field: 'curStatus.status',
value: selectValueMap.value['curStatus.status']
}
]
},
{
comparator: '',
condition: [
{
field: 'surveyType',
value: selectValueMap.value.surveyType
}
]
}
]
})
const listOrder = computed(() => {
return Object.entries(buttonValueMap.value)
.filter(([, effectValue]) => effectValue)
.reduce((prev: { field: string; value: string | number }[], item) => {
const [effectKey, effectValue] = item
prev.push({ field: effectKey, value: effectValue })
return prev
}, [])
})
function resetSelectValueMap() {
selectValueMap.value = {
surveyType: '',
'curStatus.status': ''
}
}
function resetButtonValueMap() {
buttonValueMap.value = {
'curStatus.date': '',
createDate: -1
}
}
function changeSelectValueMap(key: string, value: string | number) {
selectValueMap.value[key] = value
}
function changeButtonValueMap(key: string, value: string | number) {
buttonValueMap.value[key] = value
}
function resetSearch() {
searchVal.value = ''
resetSelectValueMap()
resetButtonValueMap()
}
return {
searchVal,
selectValueMap,
buttonValueMap,
listFilter,
listOrder,
resetSearch,
resetSelectValueMap,
resetButtonValueMap,
changeSelectValueMap,
changeButtonValueMap
}
}
export const useSurveyListStore = defineStore('surveyList', () => {
const surveyList = ref([])
const surveyTotal = ref(0)
const {
searchVal,
selectValueMap,
buttonValueMap,
listFilter,
listOrder,
resetSearch,
resetSelectValueMap,
resetButtonValueMap,
changeSelectValueMap,
changeButtonValueMap
} = useSearchSurvey()
const workSpaceStore = useWorkSpaceStore()
async function getSurveyList(payload: { curPage?: number; pageSize?: number }) {
const filterString = JSON.stringify(
listFilter.value.filter((item) => {
return item.condition[0].value
})
)
const orderString = JSON.stringify(listOrder.value)
try {
const params = {
curPage: payload?.curPage || 1,
pageSize: payload?.pageSize || 10, // 默认一页10条
filter: filterString,
order: orderString,
workspaceId: workSpaceStore.workSpaceId
}
const res: any = await getSurveyListReq(params)
if (res.code === CODE_MAP.SUCCESS) {
surveyList.value = res.data.data
surveyTotal.value = res.data.count
} else {
ElMessage.error(res.errmsg)
}
} catch (error) {
ElMessage.error('getSurveyList status' + error)
}
}
return {
surveyList,
surveyTotal,
searchVal,
selectValueMap,
buttonValueMap,
listFilter: listFilter,
listOrder,
resetSearch,
getSurveyList,
resetSelectValueMap,
resetButtonValueMap,
changeSelectValueMap,
changeButtonValueMap
}
})

View File

@ -0,0 +1,55 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
type IUserInfo = {
username: string
token: string
}
const USER_INFO_KEY = 'surveyUserInfo'
export const useUserStore = defineStore('user', () => {
const userInfo = ref<IUserInfo | null>({
username: '',
token: ''
})
const hasLogined = ref(false)
const loginTime = ref<number | null>(null)
const initialized = ref(false)
const init = () => {
const localData = localStorage.getItem(USER_INFO_KEY)
if (localData) {
try {
const { userInfo: info, loginTime: time } = JSON.parse(localData)
if (Date.now() - time > 7 * 3600000) {
localStorage.removeItem(USER_INFO_KEY)
} else {
login(info)
}
} catch (error) {
console.log(error)
}
}
initialized.value = true
}
const login = (data: IUserInfo) => {
userInfo.value = data
hasLogined.value = true
loginTime.value = Date.now()
localStorage.setItem(
USER_INFO_KEY,
JSON.stringify({
userInfo: data,
loginTime: loginTime
})
)
}
const logout = () => {
userInfo.value = null
hasLogined.value = false
localStorage.removeItem(USER_INFO_KEY)
}
return { userInfo, hasLogined, loginTime, initialized, init, login, logout }
})

View File

@ -0,0 +1,147 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import { CODE_MAP } from '@/management/api/base'
import {
createSpace,
updateSpace as updateSpaceReq,
deleteSpace as deleteSpaceReq,
getSpaceList as getSpaceListReq,
getSpaceDetail as getSpaceDetailReq
} from '@/management/api/space'
import { SpaceType } from '@/management/utils/types/workSpace'
import {
type SpaceDetail,
type SpaceItem,
type IWorkspace
} from '@/management/utils/types/workSpace'
import { useSurveyListStore } from './surveyList'
export const useWorkSpaceStore = defineStore('workSpace', () => {
// list空间
const spaceMenus = ref([
{
icon: 'icon-wodekongjian',
name: '我的空间',
id: SpaceType.Personal
},
{
icon: 'icon-tuanduikongjian',
name: '团队空间',
id: SpaceType.Group,
children: []
}
])
const spaceType = ref(SpaceType.Personal)
const workSpaceId = ref('')
const spaceDetail = ref<SpaceDetail | null>(null)
const workSpaceList = ref<SpaceItem[]>([])
const surveyListStore = useSurveyListStore()
async function getSpaceList() {
try {
const res: any = await getSpaceListReq()
if (res.code === CODE_MAP.SUCCESS) {
const { list } = res.data
const workSpace = list.map((item: SpaceDetail) => {
return {
id: item._id,
name: item.name
}
})
workSpaceList.value = list
spaceMenus.value[1].children = workSpace
} else {
ElMessage.error('getSpaceList' + res.errmsg)
}
} catch (err) {
ElMessage.error('getSpaceList' + err)
}
}
async function getSpaceDetail(id: string) {
try {
const _id = id || workSpaceId.value
const res: any = await getSpaceDetailReq(_id)
if (res.code === CODE_MAP.SUCCESS) {
spaceDetail.value = res.data
} else {
ElMessage.error('getSpaceList' + res.errmsg)
}
} catch (err) {
ElMessage.error('getSpaceList' + err)
}
}
function changeSpaceType(id: SpaceType) {
spaceType.value = id
}
function changeWorkSpace(id: string) {
workSpaceId.value = id
surveyListStore.resetSearch()
}
async function deleteSpace(id: string) {
try {
const res: any = await deleteSpaceReq(id)
if (res.code === CODE_MAP.SUCCESS) {
ElMessage.success('删除成功')
} else {
ElMessage.error(res.errmsg)
}
} catch (err: any) {
ElMessage.error(err)
}
}
async function updateSpace(params: Required<IWorkspace>) {
const { _id: workspaceId, name, description, members } = params
const res: any = await updateSpaceReq({ workspaceId, name, description, members })
if (res?.code === CODE_MAP.SUCCESS) {
ElMessage.success('更新成功')
} else {
ElMessage.error(res?.errmsg)
}
}
async function addSpace(params: IWorkspace) {
const { name, description, members } = params
const res: any = await createSpace({ name, description, members })
if (res.code === CODE_MAP.SUCCESS) {
ElMessage.success('添加成功')
} else {
ElMessage.error('createSpace code err' + res.errmsg)
}
}
function setSpaceDetail(data: null | SpaceDetail) {
spaceDetail.value = data
}
return {
spaceMenus,
spaceType,
workSpaceId,
spaceDetail,
workSpaceList,
getSpaceList,
getSpaceDetail,
changeSpaceType,
changeWorkSpace,
addSpace,
deleteSpace,
updateSpace,
setSpaceDetail
}
})

View File

@ -11,7 +11,7 @@ export interface MenuItem {
} }
export type IWorkspace = { export type IWorkspace = {
id?: string _id?: string
name: string name: string
description: string description: string
members: IMember[] members: IMember[]
@ -23,6 +23,24 @@ export type IMember = {
_id?: string _id?: string
} }
export interface SpaceDetail {
_id?: string
name: string
currentUserId?: string
description: string
members: IMember[]
}
export type SpaceItem = Required<Omit<SpaceDetail, 'members'>> & {
createDate: string
curStatus: { date: number; status: string }
memberTotal: number
currentUserRole: string
owner: string
ownerId: string
surveyTotal: number
}
export enum SpaceType { export enum SpaceType {
Personal = 'personal', Personal = 'personal',
Group = 'group', Group = 'group',

View File

@ -13,17 +13,20 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import MaterialGroup from './MaterialGroup.vue' 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(() => store.getters?.renderData) 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) => { const handleChangeData = (data: any) => {
store.dispatch('changeData', data) surveyStore.changeData(data)
} }
</script> </script>

View File

@ -13,9 +13,10 @@ import QuestionRuleContainer from '../../materials/questions/QuestionRuleContain
import { useVoteMap } from '@/render/hooks/useVoteMap' import { useVoteMap } from '@/render/hooks/useVoteMap'
import { useShowOthers } from '@/render/hooks/useShowOthers' import { useShowOthers } from '@/render/hooks/useShowOthers'
import { useShowInput } from '@/render/hooks/useShowInput' import { useShowInput } from '@/render/hooks/useShowInput'
import store from '@/render/store'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { ruleEngine } from '@/render/hooks/useRuleEngine.js' 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' import { NORMAL_CHOICES, RATES, QUESTION_TYPE } from '@/common/typeEnum.ts'
@ -32,9 +33,11 @@ const props = defineProps({
} }
}) })
const emit = defineEmits(['change']) const emit = defineEmits(['change'])
const questionStore = useQuestionStore()
const surveyStore = useSurveyStore()
const formValues = computed(() => { const formValues = computed(() => {
return store.state.formValues return surveyStore.formValues
}) })
const questionConfig = computed(() => { const questionConfig = computed(() => {
let moduleConfig = props.moduleConfig let moduleConfig = props.moduleConfig
@ -96,7 +99,8 @@ watch(
key: field, key: field,
value: value value: value
} }
store.commit('changeFormData', data) // store.commit('changeFormData', data)
surveyStore.changeData(data)
} }
} }
) )
@ -105,7 +109,7 @@ const handleChange = (data) => {
emit('change', data) emit('change', data)
// //
if (props.moduleConfig.type === QUESTION_TYPE.VOTE) { if (props.moduleConfig.type === QUESTION_TYPE.VOTE) {
store.dispatch('updateVoteData', data) questionStore.updateVoteData(data)
} }
} }
</script> </script>

View File

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

View File

@ -1,8 +1,12 @@
import store from '../store/index' import { useQuestionStore } from '../stores/question'
import { useSurveyStore } from '../stores/survey'
export const useShowInput = (questionKey) => { export const useShowInput = (questionKey) => {
const formValues = store.state.formValues const questionStore = useQuestionStore()
const surveyStore = useSurveyStore()
const formValues = surveyStore.formValues
const questionVal = formValues[questionKey] const questionVal = formValues[questionKey]
let rangeConfig = store.state.questionData[questionKey].rangeConfig let rangeConfig = questionStore.questionData[questionKey].rangeConfig
let othersValue = {} let othersValue = {}
if (rangeConfig && Object.keys(rangeConfig).length > 0) { if (rangeConfig && Object.keys(rangeConfig).length > 0) {
for (let key in rangeConfig) { for (let key in rangeConfig) {
@ -18,7 +22,8 @@ export const useShowInput = (questionKey) => {
key: rangeKey, key: rangeKey,
value: '' value: ''
} }
store.commit('changeFormData', data)
surveyStore.changeData(data)
} }
} }
} }

View File

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

View File

@ -1,10 +1,12 @@
import store from '../store/index' import { useQuestionStore } from '../stores/question'
export const useVoteMap = (questionKey) => {
let voteTotal = store.state.voteMap?.[questionKey]?.total || 0
const options = store.state.questionData[questionKey].options.map((option) => { export const useVoteMap = (questionKey) => {
const questionStore = useQuestionStore()
let voteTotal = questionStore.voteMap?.[questionKey]?.total || 0
const options = questionStore.questionData[questionKey].options.map((option) => {
const optionHash = option.hash const optionHash = option.hash
const voteCount = store.state.voteMap?.[questionKey]?.[optionHash] || 0 const voteCount = questionStore.voteMap?.[questionKey]?.[optionHash] || 0
return { return {
...option, ...option,

View File

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

View File

@ -2,35 +2,41 @@
<div class="result-page-wrap"> <div class="result-page-wrap">
<div class="result-page"> <div class="result-page">
<div class="page-content"> <div class="page-content">
<img class="img" :src="errorImageUrl" /> <img class="img" :src="errorImage" />
<div class="msg" v-html="errorMsg"></div> <div class="msg" v-html="errorMsg"></div>
</div> </div>
<LogoIcon :logo-conf="logoConf" :readonly="true" /> <LogoIcon :logo-conf="logoConf" :readonly="true" />
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup>
import { computed } from 'vue' import { computed } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
// @ts-ignore
import communalLoader from '@materials/communals/communalLoader.js' import communalLoader from '@materials/communals/communalLoader.js'
import { useErrorInfo } from '../stores/errorInfo'
import { useSurveyStore } from '../stores/survey'
const LogoIcon = communalLoader.loadComponent('LogoIcon') const LogoIcon = communalLoader.loadComponent('LogoIcon')
const store = useStore() const surveyStore = useSurveyStore()
const errorStore = useErrorInfo()
const errorImageUrl = computed(() => { const { errorInfo } = storeToRefs(errorStore)
const errorType = store.state?.errorInfo?.errorType
const imageMap = { const imageMap = {
overTime: '/imgs/icons/overtime.webp', overTime: '/imgs/icons/overtime.webp',
default: '/imgs/icons/error.webp' default: '/imgs/icons/error.webp'
} }
return imageMap[errorType as 'overTime'] || imageMap.default const errorImage = computed(() => {
const errorType = errorInfo.value.errorType
return imageMap[errorType] || imageMap.default
}) })
const errorMsg = computed(() => store.state?.errorInfo?.errorMsg || '提交失败') const errorMsg = computed(() => {
const logoConf = computed(() => store.state?.bottomConf || {}) return errorInfo.value.errorMsg || '提交失败'
})
const logoConf = computed(() => surveyStore.bottomConf || {})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.result-page-wrap { .result-page-wrap {

View File

@ -3,17 +3,16 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue' import { onMounted } from 'vue'
import { useStore } from 'vuex'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { getPublishedSurveyInfo, getPreviewSchema } from '../api/survey' import { getPublishedSurveyInfo, getPreviewSchema } from '../api/survey'
import useCommandComponent from '../hooks/useCommandComponent' import useCommandComponent from '../hooks/useCommandComponent'
import { useSurveyStore } from '../stores/survey'
import AlertDialog from '../components/AlertDialog.vue' import AlertDialog from '../components/AlertDialog.vue'
import { initRuleEngine } from '@/render/hooks/useRuleEngine.js' import { initRuleEngine } from '@/render/hooks/useRuleEngine.js'
const store = useStore()
const route = useRoute() const route = useRoute()
const surveyStore = useSurveyStore()
const loadData = (res: any, surveyPath: string) => { const loadData = (res: any, surveyPath: string) => {
if (res.code === 200) { if (res.code === 200) {
const data = res.data const data = res.data
@ -30,8 +29,8 @@ const loadData = (res: any, surveyPath: string) => {
document.title = data.title document.title = data.title
store.commit('setSurveyPath', surveyPath) surveyStore.setSurveyPath(surveyPath)
store.dispatch('init', questionData) surveyStore.initSurvey(questionData)
initRuleEngine(logicConf?.showLogicConf) initRuleEngine(logicConf?.showLogicConf)
} else { } else {
throw new Error(res.errmsg) throw new Error(res.errmsg)
@ -40,7 +39,7 @@ const loadData = (res: any, surveyPath: string) => {
onMounted(() => { onMounted(() => {
const surveyId = route.params.surveyId const surveyId = route.params.surveyId
console.log({ surveyId }) console.log({ surveyId })
store.commit('setSurveyPath', surveyId) surveyStore.setSurveyPath(surveyId)
getDetail(surveyId as string) getDetail(surveyId as string)
}) })
@ -54,7 +53,7 @@ const getDetail = async (surveyPath: string) => {
} else { } else {
const res: any = await getPublishedSurveyInfo({ surveyPath }) const res: any = await getPublishedSurveyInfo({ surveyPath })
loadData(res, surveyPath) loadData(res, surveyPath)
store.dispatch('getEncryptInfo') surveyStore.getEncryptInfo()
} }
} catch (error: any) { } catch (error: any) {
console.log(error) console.log(error)

View File

@ -20,7 +20,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useStore } from 'vuex' import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
// @ts-ignore // @ts-ignore
import communalLoader from '@materials/communals/communalLoader.js' import communalLoader from '@materials/communals/communalLoader.js'
@ -29,6 +29,8 @@ import AlertDialog from '../components/AlertDialog.vue'
import ConfirmDialog from '../components/ConfirmDialog.vue' import ConfirmDialog from '../components/ConfirmDialog.vue'
import ProgressBar from '../components/ProgressBar.vue' import ProgressBar from '../components/ProgressBar.vue'
import { useSurveyStore } from '../stores/survey'
import { useQuestionStore } from '../stores/question'
import { submitForm } from '../api/survey' import { submitForm } from '../api/survey'
import encrypt from '../utils/encrypt' import encrypt from '../utils/encrypt'
@ -55,14 +57,13 @@ const boxRef = ref<HTMLElement>()
const alert = useCommandComponent(AlertDialog) const alert = useCommandComponent(AlertDialog)
const confirm = useCommandComponent(ConfirmDialog) const confirm = useCommandComponent(ConfirmDialog)
const store = useStore()
const router = useRouter() const router = useRouter()
const surveyStore = useSurveyStore()
const questionStore = useQuestionStore()
const bannerConf = computed(() => store.state?.bannerConf || {}) const renderData = computed(() => questionStore.renderData)
const renderData = computed(() => store.getters.renderData) const { bannerConf, submitConf, bottomConf: logoConf } = storeToRefs(surveyStore)
const submitConf = computed(() => store.state?.submitConf || {}) const surveyPath = computed(() => surveyStore.surveyPath || '')
const logoConf = computed(() => store.state?.bottomConf || {})
const surveyPath = computed(() => store.state?.surveyPath || '')
const validate = (cbk: (v: boolean) => void) => { const validate = (cbk: (v: boolean) => void) => {
const index = 0 const index = 0
@ -70,9 +71,9 @@ const validate = (cbk: (v: boolean) => void) => {
} }
const normalizationRequestBody = () => { const normalizationRequestBody = () => {
const enterTime = store.state.enterTime const enterTime = surveyStore.enterTime
const encryptInfo = store.state.encryptInfo const encryptInfo = surveyStore.encryptInfo as any
const formValues = store.state.formValues const formValues = surveyStore.formValues
const result: any = { const result: any = {
surveyPath: surveyPath.value, surveyPath: surveyPath.value,
@ -82,7 +83,7 @@ const normalizationRequestBody = () => {
} }
if (encryptInfo?.encryptType) { if (encryptInfo?.encryptType) {
result.encryptType = encryptInfo?.encryptType result.encryptType = encryptInfo.encryptType
result.data = encrypt[result.encryptType as 'rsa']({ result.data = encrypt[result.encryptType as 'rsa']({
data: result.data, data: result.data,
secretKey: encryptInfo?.data?.secretKey secretKey: encryptInfo?.data?.secretKey
@ -119,7 +120,7 @@ const submitSurver = async () => {
} }
const handleSubmit = () => { const handleSubmit = () => {
const confirmAgain = store.state.submitConf.confirmAgain const confirmAgain = (surveyStore.submitConf as any).confirmAgain
const { again_text, is_again } = confirmAgain const { again_text, is_again } = confirmAgain
if (is_again) { if (is_again) {

View File

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

View File

@ -0,0 +1,22 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const useErrorInfo = defineStore('errorInfo', () => {
const errorInfo = ref({
errorType: '',
errorMsg: ''
})
const setErrorInfo = ({ errorType, errorMsg }) => {
errorInfo.value = {
errorType,
errorMsg
}
}
return {
errorInfo,
setErrorInfo
}
})

View File

@ -0,0 +1,157 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { set } from 'lodash-es'
import { useSurveyStore } from '@/render/stores/survey'
import { queryVote } from '@/render/api/survey'
const VOTE_INFO_KEY = 'voteinfo'
export const useQuestionStore = defineStore('question', () => {
const voteMap = ref({})
const questionData = ref(null)
const questionSeq = ref([]) // 题目的顺序,因为可能会有分页的情况,所以是一个二维数组[[qid1, qid2], [qid3,qid4]]
// 题目列表
const renderData = computed(() => {
let index = 1
return (
questionSeq.value &&
questionSeq.value.reduce((pre, item) => {
const questionArr = []
item.forEach((questionKey) => {
const question = { ...questionData.value[questionKey] }
// 开启显示序号
if (question.showIndex) {
question.indexNumber = index++
}
questionArr.push(question)
})
if (questionArr && questionArr.length) {
pre.push(questionArr)
}
return pre
}, [])
)
})
const setQuestionData = (data) => {
questionData.value = data
}
const changeSelectMoreData = (data) => {
const { key, value, field } = data
set(questionData.value, `${field}.othersValue.${key}`, value)
}
const setQuestionSeq = (data) => {
questionSeq.value = data
}
const setVoteMap = (data) => {
voteMap.value = data
}
const updateVoteMapByKey = (data) => {
const { questionKey, voteKey, voteValue } = data
// 兼容为空的情况
if (!voteMap.value[questionKey]) {
voteMap.value[questionKey] = {}
}
voteMap.value[questionKey][voteKey] = voteValue
}
//初始化投票题的数据
const initVoteData = async () => {
const surveyStore = useSurveyStore()
const surveyPath = surveyStore.surveyPath
const fieldList = []
for (const field in questionData.value) {
const { type } = questionData.value[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
})
)
setVoteMap(voteRes.data)
}
} catch (error) {
console.log(error)
}
}
const updateVoteData = (data) => {
const { key: questionKey, value: questionVal } = data
// 更新前获取接口缓存在localStorage中的数据
const localData = localStorage.getItem(VOTE_INFO_KEY)
const voteinfo = JSON.parse(localData)
const currentQuestion = questionData.value[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
updateVoteMapByKey(countPayload)
} else {
const countPayload = {
questionKey,
voteKey: optionhash,
voteValue: voteCount
}
updateVoteMapByKey(countPayload)
}
updateVoteMapByKey(totalPayload)
})
}
return {
voteMap,
questionData,
questionSeq,
renderData,
setQuestionData,
changeSelectMoreData,
setQuestionSeq,
setVoteMap,
updateVoteMapByKey,
initVoteData,
updateVoteData
}
})

View File

@ -0,0 +1,166 @@
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
*/
const CODE_MAP = {
SUCCESS: 200,
ERROR: 500,
NO_AUTH: 403
}
export const useSurveyStore = defineStore('survey', () => {
const surveyPath = ref('')
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
}
const setEnterTime = () => {
enterTime.value = Date.now()
}
const getEncryptInfo = async () => {
try {
const res = await getEncryptInfoApi()
if (res.code === CODE_MAP.SUCCESS) {
encryptInfo.value = res.data
}
} catch (error) {
console.log(error)
}
}
const canFillQuestionnaire = (baseConf, submitConf) => {
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, option.submitConf)) {
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
// 将数据设置到state上
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
}
})

View File

@ -0,0 +1,22 @@
$primary-color: #faa600;
$primary-color-light: hsl(48, 100%, 97%);
$title-color-deep: #292a36;
$title-color: #4a4c5b;
$font-color: #6e707c;
$remark-color: #4a4c5b;
$placeholder-color: #c8c9cd;
$light-focus-color: #666666;
$disable-color: #f2f4f7;
$border-color: #dee2e6;
$spliter-color: #f7f7f7;
$error-color: #ec4e29;
@import './variable';
$title-size: 0.32rem;
$font-size: 0.28rem;
$tip-size: 0.22rem;

View File

@ -61,7 +61,13 @@ export default defineConfig({
'clipboard', 'clipboard',
'qrcode', 'qrcode',
'moment', 'moment',
'moment/locale/zh-cn' 'moment/locale/zh-cn',
'echarts',
'nanoid',
'yup',
'crypto-js/sha256',
'element-plus/es/locale/lang/zh-cn',
'node-forge'
] ]
}, },
plugins: [ plugins: [