perl:代码优化 (#139)

This commit is contained in:
dayou 2024-05-20 17:40:30 +08:00 committed by GitHub
parent 990126f976
commit c714f13905
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 195 additions and 242 deletions

7
web/components.d.ts vendored
View File

@ -12,12 +12,10 @@ declare module 'vue' {
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElIconCheck: typeof import('@element-plus/icons-vue')['Check']
ElIconLoading: typeof import('@element-plus/icons-vue')['Loading']
ElInput: typeof import('element-plus/es')['ElInput']
@ -28,6 +26,7 @@ declare module 'vue' {
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSlider: typeof import('element-plus/es')['ElSlider']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
@ -38,9 +37,6 @@ declare module 'vue' {
ElTag: typeof import('element-plus/es')['ElTag']
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
'IEp-[]': typeof import('~icons/ep/[]')['default']
'IEp-[test]': typeof import('~icons/ep/[test]')['default']
'IEp-]': typeof import('~icons/ep/]')['default']
IEpBottom: typeof import('~icons/ep/bottom')['default']
IEpCheck: typeof import('~icons/ep/check')['default']
IEpCirclePlus: typeof import('~icons/ep/circle-plus')['default']
@ -64,6 +60,5 @@ declare module 'vue' {
}
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
vPopover: typeof import('element-plus/es')['ElPopoverDirective']
}
}

View File

@ -1,8 +1,28 @@
export type BasicOperator = 'in' | 'eq' | 'neq' | 'nin' | 'gt';
// in包含, 选择了,任一
// eq: 等于,选择了,全部
// nin: 不包含,不选择,任一
// neq不等于不选择全部可以实现“填写了”
/**
* in,
* eq: 等于
* nin: 不包含
* neq
*/
export enum Operator {
Include = 'in',
Equal = 'eq',
NotEqual = 'neq',
NotInclude = 'nin',
}
export enum PrefixID {
Rule = 'r',
Condition = 'c'
}
export enum Scope {
Question = 'question',
Option = 'option'
}
export type FieldTypes = string | string[];
// 定义事实对象类型

View File

@ -1,26 +1,26 @@
import { nanoid } from 'nanoid';
import * as yup from 'yup'
import { type BasicOperator, type FieldTypes } from './BasicType'
import { type FieldTypes, PrefixID, Operator, Scope } from './BasicType'
export function generateID(prefix = 'r') {
export function generateID(prefix = PrefixID.Rule) {
return `${prefix}-${nanoid(5)}`
}
// 定义条件规则类
export class ConditionNode {
id: string = '';
public field: string = '';
public operator: BasicOperator = 'in';
public operator: Operator = Operator.Include;
public value: FieldTypes = []
constructor(field: string = '', operator: BasicOperator = 'in', value: FieldTypes = []) {
constructor(field: string = '', operator: Operator = Operator.Include, value: FieldTypes = []) {
this.field = field;
this.operator = operator;
this.value = value;
this.id = generateID('c')
this.id = generateID(PrefixID.Condition)
}
setField(field: string) {
this.field = field;
}
setOperator(operator: BasicOperator) {
setOperator(operator: Operator) {
this.operator = operator;
}
setValue(value: FieldTypes) {
@ -31,10 +31,10 @@ export class ConditionNode {
export class RuleNode {
id: string = '';
conditions: ConditionNode[] = []
scope: string = 'question'
scope: string = Scope.Question
target: string = ''
constructor(scope:string = 'question', target: string = '') {
this.id = generateID('r')
constructor(scope:string = Scope.Question, target: string = '') {
this.id = generateID(PrefixID.Rule)
this.scope = scope
this.target = target
}
@ -54,8 +54,14 @@ export class RuleNode {
export class RuleBuild {
rules: RuleNode[] = [];
static instance: RuleBuild;
constructor() {
this.rules = [];
if (!RuleBuild.instance) {
RuleBuild.instance = this;
}
return RuleBuild.instance;
}
// 添加条件规则到规则引擎中

View File

@ -1,8 +1,8 @@
import { type BasicOperator, type FieldTypes, type Fact } from "./BasicType";
import { Operator, type FieldTypes, type Fact } from "./BasicType";
// 定义条件规则类
export class ConditionNode<F extends string, O extends BasicOperator> {
export class ConditionNode<F extends string, O extends Operator> {
// 默认显示
public result: boolean = false;
constructor(public field: F, public operator: O, public value: FieldTypes) {
@ -22,7 +22,7 @@ export class ConditionNode<F extends string, O extends BasicOperator> {
return this.result
}
switch (this.operator) {
case 'eq':
case Operator.Equal:
if(this.value instanceof Array) {
this.result = this.value.every(v => facts[this.field].includes(v))
return this.result
@ -30,7 +30,7 @@ export class ConditionNode<F extends string, O extends BasicOperator> {
this.result = facts[this.field].includes(this.value);
return this.result
}
case 'in':
case Operator.Include:
if(this.value instanceof Array) {
this.result = this.value.some(v => facts[this.field].includes(v))
return this.result
@ -38,7 +38,7 @@ export class ConditionNode<F extends string, O extends BasicOperator> {
this.result = facts[this.field].includes(this.value);
return this.result
}
case 'nin':
case Operator.NotInclude:
if(this.value instanceof Array) {
this.result = this.value.some(v => !facts[this.field].includes(v))
return this.result
@ -46,7 +46,7 @@ export class ConditionNode<F extends string, O extends BasicOperator> {
this.result = facts[this.field].includes(this.value);
return this.result
}
case 'neq':
case Operator.NotEqual:
if(this.value instanceof Array) {
this.result = this.value.every(v => !facts[this.field].includes(v))
return this.result
@ -67,13 +67,13 @@ export class ConditionNode<F extends string, O extends BasicOperator> {
}
export class RuleNode {
conditions: Map<string, ConditionNode<string, BasicOperator>>; // 使用哈希表存储条件规则对象
conditions: Map<string, ConditionNode<string, Operator>>; // 使用哈希表存储条件规则对象
public result: boolean = false;
constructor(public target: string, public scope: string) {
this.conditions = new Map();
}
// 添加条件规则到规则引擎中
addCondition(condition: ConditionNode<string, BasicOperator>) {
addCondition(condition: ConditionNode<string, Operator>) {
const hash = condition.calculateHash();
this.conditions.set(hash, condition);
}
@ -118,8 +118,16 @@ export class RuleNode {
export class RuleMatch {
rules: Map<string, RuleNode>;
constructor(ruleConf: any) {
static instance: any;
constructor() {
this.rules = new Map();
if (!RuleMatch.instance) {
RuleMatch.instance = this;
}
return RuleMatch.instance;
}
fromJson(ruleConf:any) {
if(ruleConf instanceof Array) {
ruleConf.forEach((rule: any) => {
const ruleNode = new RuleNode(rule.target, rule.scope);
@ -130,7 +138,6 @@ export class RuleMatch {
this.addRule(ruleNode)
})
}
}
// 添加条件规则到规则引擎中
@ -138,7 +145,7 @@ export class RuleMatch {
const hash = rule.calculateHash();
if (this.rules.has(hash)) {
const existRule: any = this.rules.get(hash);
existRule.conditions.forEach((item: ConditionNode<string, BasicOperator>) => {
existRule.conditions.forEach((item: ConditionNode<string, Operator>) => {
rule.addCondition(item)
})
}

View File

@ -0,0 +1,23 @@
import { computed } from 'vue';
import store from '@/management/store'
import { cleanRichText } from '@/common/xss'
export const useQuestionInfo = (field) => {
const getQuestionTitle = computed(() => {
const questionDataList = store.state.edit.schema.questionDataList
return () => {
return questionDataList.find((item) => item.field === field)?.title
}
})
const getOptionTitle = computed(() => {
const questionDataList = store.state.edit.schema.questionDataList
return (value) => {
const options = questionDataList.find((item) => item.field === field)?.options || []
if(value instanceof Array) {
return options.filter((item) => value.includes(item.hash)).map((item) => cleanRichText(item.text))
} else {
return options.filter((item) => item.hash === value).map((item) => cleanRichText(item.text))
}
}
})
return { getQuestionTitle, getOptionTitle }
}

View File

@ -1,23 +0,0 @@
import { computed } from 'vue';
import store from '@/management/store'
import { cleanRichText } from '@/common/xss'
export const useQuestionInfo = (field: string) => {
const getQuestionTitle = computed(() => {
const questionDataList = store.state.edit.schema.questionDataList
return () => {
return questionDataList.find((item: any) => item.field === field)?.title
}
})
const getOptionTitle = computed(() => {
const questionDataList = store.state.edit.schema.questionDataList
return (value: string | Array<string>) => {
const options = questionDataList.find((item: any) => item.field === field)?.options || []
if(value instanceof Array) {
return options.filter((item: any) => value.includes(item.hash)).map((item: any) => cleanRichText(item.text))
} else {
return options.filter((item: any) => item.hash === value).map((item: any) => cleanRichText(item.text))
}
}
})
return { getQuestionTitle, getOptionTitle }
}

View File

@ -0,0 +1,7 @@
import { ref } from 'vue'
import { RuleBuild } from '@/common/logicEngine/RuleBuild'
export const showLogicEngine = ref()
export const initShowLogicEngine = (ruleConf) => {
showLogicEngine.value = new RuleBuild().fromJson(ruleConf)
}

View File

@ -1,13 +1,13 @@
import { computed, unref } from 'vue';
import { useQuestionInfo } from './useQuestionInfo'
import { flatten } from 'lodash-es'
import store from '@/management/store'
import { cleanRichText } from '@/common/xss'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
// 目标题的显示逻辑提示文案
export const useShowLogicInfo = (field: string) => {
export const useShowLogicInfo = (field) => {
const hasShowLogic = computed(() => {
const logicEngine = store.state.logic.showLogicEngine
const logicEngine = showLogicEngine.value
// 判断该题是否作为了显示逻辑前置题
const isField = logicEngine?.findTargetsByFields(field)?.length > 0
// 判断该题是否作为了显示逻辑目标题
@ -15,11 +15,11 @@ export const useShowLogicInfo = (field: string) => {
return isField || isTarget
})
const getShowLogicText = computed(() => {
const logicEngine = store.state.logic.showLogicEngine
const logicEngine = showLogicEngine.value
// 获取目标题的规则
const rules = logicEngine?.findConditionByTarget(field) || []
const conditions = flatten(rules).map((item:any) => {
const conditions = flatten(rules).map((item) => {
const { getQuestionTitle, getOptionTitle } = useQuestionInfo(item.field)
return `<span>【 ${cleanRichText(getQuestionTitle.value())}】 选择了 【${getOptionTitle.value(unref(item.value)).join('、')}】</span> <br/>`
})

View File

@ -115,7 +115,6 @@ const onMoveDown = () => {
isHover.value = false
}
const onDelete = async () => {
// const target = store.state.logic.showLogicEngine.findTargetsByFields(props.moduleConfig.field)
if(unref(hasShowLogic)) {
ElMessageBox.alert('该问题被逻辑依赖,请先删除逻辑依赖', '提示', {
confirmButtonText: '确定',

View File

@ -22,7 +22,7 @@ import LeftMenu from '@/management/components/LeftMenu.vue'
import CommonTemplate from './components/CommonTemplate.vue'
import Navbar from './components/ModuleNavbar.vue'
import { initShowLogicEngine } from '@/management/hooks/useShowLogicEngine'
export default {
name: 'questionEditPage',
components: {
@ -34,7 +34,8 @@ export default {
this.$store.commit('edit/setSurveyId', this.$route.params.id)
try {
await this.$store.dispatch('edit/init')
await this.$store.dispatch('logic/initShowLogic', this.$store.state.edit.schema.logicConf.showLogicConf || {})
// await this.$store.dispatch('logic/initShowLogic', this.$store.state.edit.schema.logicConf.showLogicConf || {})
await initShowLogicEngine(this.$store.state.edit.schema.logicConf.showLogicConf || {})
} catch (error) {
ElMessage.error(error.message)
//

View File

@ -5,14 +5,12 @@
</template>
<script>
import { get as _get } from 'lodash-es'
import { mapState } from 'vuex'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import { get as _get } from 'lodash-es'
import { publishSurvey, saveSurvey } from '@/management/api/survey'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
import buildData from './buildData'
export default {
@ -68,15 +66,15 @@ export default {
}
},
updateLogicConf() {
if(this.$store.state.logic.showLogicEngine) {
if(showLogicEngine.value) {
try {
this.$store.state.logic.showLogicEngine.validateSchema()
showLogicEngine.value.validateSchema()
} catch (error) {
throw error
return
}
const showLogicConf = this.$store.state.logic.showLogicEngine.toJson()
const showLogicConf = showLogicEngine.value.toJson()
//
this.$store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } })
}

View File

@ -23,6 +23,7 @@ import 'element-plus/theme-chalk/src/message.scss'
import { saveSurvey } from '@/management/api/survey'
import buildData from './buildData'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
export default {
components: {},
@ -89,14 +90,14 @@ export default {
}
},
updateLogicConf() {
if(this.$store.state.logic.showLogicEngine) {
if(showLogicEngine.value) {
try {
this.$store.state.logic.showLogicEngine.validateSchema()
showLogicEngine.value.validateSchema()
} catch (error) {
throw error
return
}
const showLogicConf = this.$store.state.logic.showLogicEngine.toJson()
const showLogicConf = showLogicEngine.value.toJson()
//
this.$store.dispatch('edit/changeSchema', { key: 'logicConf', value: { showLogicConf } })
}

View File

@ -20,25 +20,22 @@
</template>
<script setup lang="ts">
import { shallowRef, computed } from 'vue'
import { useStore } from 'vuex'
import { RuleNode, ConditionNode } from '@/common/logicEngine/RuleBuild'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
import RuleNodeView from './components/RuleNodeView.vue'
import { RuleNode, ConditionNode } from '@/common/logicEngine/RuleBuild'
const store = useStore()
const list = computed(() => {
return store.state.logic.showLogicEngine?.rules || []
return showLogicEngine.value?.rules || []
})
const handleAdd = () => {
const condition = new ConditionNode()
const ruleNode = new RuleNode()
ruleNode.addCondition(condition)
store.state.logic.showLogicEngine.addRule(ruleNode)
showLogicEngine.value.addRule(ruleNode)
}
const handleDetele = (id: string) => {
store.state.logic.showLogicEngine.removeRule(id)
showLogicEngine.value.removeRule(id)
}
const ruleWrappers = shallowRef([])

View File

@ -184,4 +184,4 @@ const handleDelete = (id: any) => {
.select {
width: 200px;
}
</style>
</style>

View File

@ -7,14 +7,14 @@
:inline="true"
:model="ruleNode"
>
<conditionView
<ConditionView
v-for="(conditionNode, index) in ruleNode.conditions"
:key="conditionNode.id"
:index="index"
:ruleNode="ruleNode"
:conditionNode="conditionNode"
@delete="handleDeleteCondition"
></conditionView>
></ConditionView>
<div class="target-wrapper">
<div class="line">
<span class="desc">则显示</span>
@ -46,18 +46,14 @@
</template>
<script setup lang="ts">
import { ref, computed, shallowRef, inject, type ComputedRef } from 'vue'
import { useStore } from 'vuex'
import { cloneDeep } from 'lodash-es'
import { ElMessageBox } from 'element-plus'
import 'element-plus/theme-chalk/src/message-box.scss'
import { RuleNode } from '@/common/logicEngine/RuleBuild'
import { cleanRichText } from '@/common/xss'
import { showLogicEngine } from '@/management/hooks/useShowLogicEngine'
import ConditionView from './ConditionView.vue'
import conditionView from './ConditionView.vue'
const store = useStore()
const renderData = inject<ComputedRef<Array<any>>>('renderData') || ref([])
const props = defineProps({
@ -107,7 +103,7 @@ const targetQuestionList = computed(() => {
return {
label: `${item.showIndex ? item.indexNumber + '.' : ''} ${cleanRichText(item.title)}`,
value: item.field,
disabled: store.state.logic.showLogicEngine
disabled: showLogicEngine.value
.findTargetsByScope('question')
.includes(item.field)
}
@ -146,4 +142,4 @@ defineExpose({
.select {
width: 200px;
}
</style>
</style>

View File

@ -1,36 +0,0 @@
<template>
<commonTemplate>
<template #left>
<CatalogPanel></CatalogPanel>
</template>
<template #center>
<PreviewPanel></PreviewPanel>
</template>
<template #right>
<SetterPanel></SetterPanel>
</template>
</commonTemplate>
</template>
<script>
import commonTemplate from '../components/CommonTemplate.vue'
import CatalogPanel from '../modules/questionModule/CatalogPanel.vue'
import PreviewPanel from '../modules/questionModule/PreviewPanel.vue'
import SetterPanel from '../modules/questionModule/SetterPanel.vue'
export default {
name: 'EditPage',
components: {
commonTemplate,
CatalogPanel,
PreviewPanel,
SetterPanel
}
}
</script>
<style lang="scss" scoped>
.navbar {
border-bottom: 1px solid #e7e9eb;
}
</style>

View File

@ -1,11 +1,11 @@
<template>
<div class="logic-wrapper">
<RuleListView></RuleListView>
<RulePanel></RulePanel>
</div>
</template>
<script setup lang="ts">
import { computed, provide } from 'vue'
import RuleListView from '../../modules/logicModule/RulePanel.vue'
import RulePanel from '../../modules/logicModule/RulePanel.vue'
import { filterQuestionPreviewData } from '@/management/utils/index'
import { useStore } from 'vuex'
import { cloneDeep } from 'lodash-es'

View File

@ -1,28 +1,28 @@
<template>
<commonTemplate>
<CommonTemplate>
<template #left>
<catalogPanel />
<CatalogPanel />
</template>
<template #center>
<previewPanel />
<PreviewPanel />
</template>
<template #right>
<setterPanel />
<SetterPanel />
</template>
</commonTemplate>
</CommonTemplate>
</template>
<script>
import commonTemplate from '../../components/CommonTemplate.vue';
import catalogPanel from '../../modules/questionModule/CatalogPanel.vue';
import previewPanel from '../../modules/questionModule/PreviewPanel.vue';
import setterPanel from '../../modules/questionModule/SetterPanel.vue';
import CommonTemplate from '../../components/CommonTemplate.vue';
import CatalogPanel from '../../modules/questionModule/CatalogPanel.vue';
import PreviewPanel from '../../modules/questionModule/PreviewPanel.vue';
import SetterPanel from '../../modules/questionModule/SetterPanel.vue';
export default {
name: 'editInde1111x',
name: 'editIndex',
components: {
commonTemplate,
catalogPanel,
previewPanel,
setterPanel,
CommonTemplate,
CatalogPanel,
PreviewPanel,
SetterPanel,
},
};
</script>

View File

@ -5,7 +5,7 @@
</template>
<script>
import SettingPanel from '../modules/settingModule/SettingPanel.vue'
import SettingPanel from '../../modules/settingModule/SettingPanel'
export default {
name: 'SettingPage',
components: {

View File

@ -1,5 +1,5 @@
<template>
<commonTemplate>
<CommonTemplate>
<template #left>
<CatalogPanel />
</template>
@ -9,10 +9,10 @@
<template #right>
<SetterPanel />
</template>
</commonTemplate>
</CommonTemplate>
</template>
<script>
import commonTemplate from '../../components/CommonTemplate.vue'
import CommonTemplate from '../../components/CommonTemplate.vue'
import CatalogPanel from '../../modules/settingModule/skin/CatalogPanel.vue'
import PreviewPanel from '../../modules/settingModule/skin/PreviewPanel.vue'
import SetterPanel from '../../modules/settingModule/skin/SetterPanel.vue'
@ -20,7 +20,7 @@ import SetterPanel from '../../modules/settingModule/skin/SetterPanel.vue'
export default {
name: 'ContentPage',
components: {
commonTemplate,
CommonTemplate,
CatalogPanel,
PreviewPanel,
SetterPanel

View File

@ -1,5 +1,5 @@
<template>
<commonTemplate>
<CommonTemplate>
<template #left>
<ResultCatalog />
</template>
@ -9,11 +9,11 @@
<template #right>
<ResultSetter />
</template>
</commonTemplate>
</CommonTemplate>
</template>
<script>
import commonTemplate from '../../components/CommonTemplate.vue'
import CommonTemplate from '../../components/CommonTemplate.vue'
import ResultCatalog from '../../modules/settingModule/result/CatalogPanel.vue'
import ResultPreview from '../../modules/settingModule/result/PreviewPanel.vue'
import ResultSetter from '../../modules/settingModule/result/SetterPanel.vue'
@ -21,7 +21,7 @@ import ResultSetter from '../../modules/settingModule/result/SetterPanel.vue'
export default {
name: 'ResultPage',
components: {
commonTemplate,
CommonTemplate,
ResultCatalog,
ResultPreview,
ResultSetter

View File

@ -1,5 +1,5 @@
export const type = {
normal: '调查问卷',
normal: '基础调查',
vote: '投票评选',
nps: 'NPS评分',
register: '在线报名'

View File

@ -59,7 +59,7 @@ const routes: RouteRecordRaw[] = [
meta: {
needLogin: true
},
component: () => import('../pages/edit/pages/SettingPage.vue')
component: () => import('../pages/edit/pages/setting/index.vue')
},
{
path: 'skin',
@ -118,7 +118,7 @@ const routes: RouteRecordRaw[] = [
name: 'login',
component: () => import('../pages/login/LoginPage.vue'),
meta: {
title: '登'
title: '登'
}
}
]

View File

@ -1,5 +1,4 @@
import { getBannerData } from '@/management/api/skin.js'
import { RuleBuild } from '@/common/logicEngine/RuleBuild'
export default {
async getBannerData({ state, commit }) {
@ -10,9 +9,5 @@ export default {
if (res.code === 200) {
commit('setBannerList', res.data)
}
},
initShowLogic({ commit }, ruleConf) {
const showLogicEngine = new RuleBuild(ruleConf)
commit('setShowLogicEngine', showLogicEngine)
}
}

View File

@ -1,7 +1,6 @@
import { createStore } from 'vuex'
import edit from './edit'
import user from './user'
import logic from './logic'
import actions from './actions'
import mutations from './mutations'
@ -14,7 +13,6 @@ export default createStore({
actions,
modules: {
edit,
user,
logic
user
}
})

View File

@ -1,19 +0,0 @@
import { RuleBuild } from '@/common/logicEngine/RuleBuild'
export default {
namespaced: true,
state: {
showLogicEngine: null
},
mutations: {
setShowLogicEngine(state, logicEngine) {
state.showLogicEngine = logicEngine
}
},
actions: {
initShowLogic({ commit }, ruleConf) {
const showLogicEngine = new RuleBuild().fromJson(ruleConf)
commit('setShowLogicEngine', showLogicEngine)
}
}
}

View File

@ -2,7 +2,4 @@ export default {
setBannerList(state, data) {
state.bannerList = data
},
setShowLogicEngine(state, logicEngine) {
state.logicEngine = logicEngine
},
}

View File

@ -1,4 +1,3 @@
export default {
bannerList: [],
logicEngine: null
bannerList: []
}

View File

@ -49,7 +49,7 @@
</div>
</template>
<script setup lang="ts">
<script setup>
import { ref, computed, inject } from 'vue'
import OptionConfig from '../AdvancedConfig/OptionConfig.vue'
import RateConfig from '../AdvancedConfig/RateConfig.vue'
@ -75,7 +75,7 @@ defineProps({
})
const emit = defineEmits(['addOther', 'optionChange', 'change'])
const moduleConfig = inject('moduleConfig') as any
const moduleConfig = inject('moduleConfig')
const optionConfigVisible = ref(false)
const openOptionConfig = () => {
console.log('open')
@ -85,10 +85,10 @@ const openOptionConfig = () => {
const addOther = () => {
emit('addOther')
}
const handleOptionChange = (value: any[]) => {
const handleOptionChange = (value) => {
emit('optionChange', value)
}
const handleChange = (data: any) => {
const handleChange = (data) => {
emit('change', data)
}
@ -96,7 +96,7 @@ const rateConfigVisible = ref(false)
const openRateConfig = () => {
rateConfigVisible.value = true
}
const onVisibleChange = (val: boolean) => {
const onVisibleChange = (val) => {
rateConfigVisible.value = val
}

View File

@ -17,7 +17,7 @@ import AlertDialog from './components/AlertDialog.vue'
import LogoIcon from './components/LogoIcon.vue'
import { get as _get } from 'lodash-es'
import { ruleConf } from '@/common/logicEngine/ruleConf'
import { initRuleEngine } from '@/render/hooks/useRuleEngine.js'
export default {
name: 'App',
@ -69,7 +69,7 @@ export default {
this.setSkin(skinConf)
this.$store.commit('setSurveyPath', surveyPath)
this.$store.dispatch('init', questionData)
this.$store.dispatch('initRuleEngine', logicConf?.showLogicConf);
initRuleEngine(logicConf?.showLogicConf)
this.$store.dispatch('getEncryptInfo')
} else {
throw new Error(res.errmsg)

View File

@ -6,7 +6,7 @@
:indexNumber="indexNumber"
:showTitle="true"
@change="handleChange"
></QuestionRuleContainer>
></QuestionRuleContainer>
</template>
<script setup>
import { unref, computed, watch } from 'vue'
@ -16,6 +16,9 @@ import { useShowOthers } from '@/render/hooks/useShowOthers'
import { useShowInput } from '@/render/hooks/useShowInput'
import store from '@/render/store'
import { cloneDeep } from 'lodash-es'
import { ruleEngine } from '@/render/hooks/useRuleEngine.js'
import { QUESTION_TYPE } from '@/render/constant/index'
const props = defineProps({
indexNumber: {
type: [Number, String],
@ -38,21 +41,20 @@ const questionConfig = computed(() =>{
const { type, field, options, ...rest } = cloneDeep(moduleConfig)
// console.log(field,'formValuechange')
let alloptions = options
if(type === 'vote') {
if(type === QUESTION_TYPE.VOTE) {
const { options, voteTotal } = useVoteMap(field)
const voteOptions = unref(options)
alloptions = alloptions.map((obj, index) => Object.assign(obj, voteOptions[index]))
moduleConfig.voteTotal = unref(voteTotal)
}
if(['radio','checkbox'].includes(type) && options.filter(optionItem => optionItem.others).length > 0) {
if(QUESTION_TYPE.CHOICES.includes(type) && options.filter(optionItem => optionItem.others).length > 0) {
let { options, othersValue } = useShowOthers(field)
const othersOptions = unref(options)
alloptions = alloptions.map((obj, index) => Object.assign(obj, othersOptions[index]))
moduleConfig.othersValue = unref(othersValue)
}
if(['radio-star','radio-nps'].includes(type) && Object.keys(rest.rangeConfig).filter(index => rest.rangeConfig[index].isShowInput).length > 0) {
if(QUESTION_TYPE.RATES.includes(type) && Object.keys(rest.rangeConfig).filter(index => rest.rangeConfig[index].isShowInput).length > 0) {
let { rangeConfig, othersValue } = useShowInput(field)
// console.log({rangeConfig, othersValue})
moduleConfig.rangeConfig = unref(rangeConfig)
moduleConfig.othersValue = unref(othersValue)
}
@ -63,22 +65,21 @@ const questionConfig = computed(() =>{
value: formValues.value[props.moduleConfig.field]
}
})
const { field } = props.moduleConfig
const visible = computed(() => {
const { field } = props.moduleConfig
const matchRule = store.state.ruleEngine.rules.get(field+'question')
if(matchRule) {
return matchRule.result
} else {
return true
}
// computedmatch
return ruleEngine.match(field, 'question', formValues.value)
})
watch(() => visible.value, (newVal, oldVal) => {
//
const { field, type, innerType } = props.moduleConfig
if(!newVal && oldVal) {
let value = ''
// innerType
if (/checkbox/.test(type) || innerType === 'checkbox') {
if (type === QUESTION_TYPE.CHECKBOX || innerType === QUESTION_TYPE.CHECKBOX) {
value = value ? [value] : []
}
const data = {
@ -86,29 +87,14 @@ watch(() => visible.value, (newVal, oldVal) => {
value: value
}
store.commit('changeFormData', data)
notifyMatch(field)
}
})
const handleChange = (data) => {
const { key } = data
// console.log(key, 'change')
emit('change', data)
//
if(props.moduleConfig.type === 'vote') {
if(props.moduleConfig.type === QUESTION_TYPE.VOTE) {
store.dispatch('updateVoteData', data)
}
//
notifyMatch(key)
}
const notifyMatch = (key) => {
let fact = unref(formValues)
const targets = store.state.ruleEngine.findTargetsByField(key) || []
//
targets.forEach((target) => {
store.state.ruleEngine.match(target, 'question', fact)
})
}
</script>

View File

@ -0,0 +1,12 @@
export const QUESTION_TYPE = {
VOTE: 'vote',
CHECKBOX: 'checkbox',
CHOICES: [ // 选择类题型分类
'radio',
'checkbox',
],
RATES: [ // 评分题题型分类
'radio-star',
'radio-nps'
]
}

View File

@ -0,0 +1,6 @@
import { RuleMatch } from '@/common/logicEngine/RulesMatch'
export const ruleEngine = new RuleMatch()
export const initRuleEngine = (ruleConf) => {
ruleEngine.fromJson(ruleConf)
}

View File

@ -1,12 +1,12 @@
<template>
<div class="index">
<progressBar />
<ProgressBar />
<div class="wrapper" ref="box">
<HeaderSetter></HeaderSetter>
<div class="content">
<MainTitle></MainTitle>
<MainRenderer ref="main"></MainRenderer>
<submit :validate="validate" :renderData="renderData" @submit="onSubmit"></submit>
<Submit :validate="validate" :renderData="renderData" @submit="onSubmit"></Submit>
<LogoIcon />
</div>
</div>
@ -16,11 +16,11 @@
<script>
import HeaderSetter from '../components/HeaderSetter.vue'
import MainTitle from '../components/MainTitle.vue'
import submit from '../components/SubmitSetter.vue'
import Submit from '../components/SubmitSetter.vue'
import MainRenderer from '../components/MainRenderer.vue'
import AlertDialog from '../components/AlertDialog.vue'
import ConfirmDialog from '../components/ConfirmDialog.vue'
import progressBar from '../components/ProgressBar.vue'
import ProgressBar from '../components/ProgressBar.vue'
import LogoIcon from '../components/LogoIcon.vue'
import { submitForm } from '../api/survey'
@ -44,9 +44,9 @@ export default {
components: {
HeaderSetter,
MainTitle,
submit,
Submit,
MainRenderer,
progressBar,
ProgressBar,
LogoIcon
},
computed: {
@ -93,22 +93,10 @@ export default {
},
getSubmitData() {
const formValues = cloneDeep(this.$store.state.formValues)
// -
// -
const formModel = Object.keys(formValues)
.filter(key => this.$store.state.ruleEngine.getResult(key, 'question'))
.reduce((obj, key) => {
obj[key] = formValues[key];
return obj;
}, {});
const result = {
surveyPath: this.surveyPath,
data: JSON.stringify(formModel),
data: JSON.stringify(formValues),
difTime: Date.now() - this.$store.state.enterTime,
clientTime: Date.now()
}