format: 代码格式化 (#160)
This commit is contained in:
parent
38566f1f60
commit
4c85fcc47e
10
web/components.d.ts
vendored
10
web/components.d.ts
vendored
@ -11,26 +11,30 @@ declare module 'vue' {
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
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']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
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']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
IEpBottom: typeof import('~icons/ep/bottom')['default']
|
||||
IEpCheck: typeof import('~icons/ep/check')['default']
|
||||
|
@ -8,10 +8,9 @@ export enum Operator {
|
||||
Include = 'in',
|
||||
Equal = 'eq',
|
||||
NotEqual = 'neq',
|
||||
NotInclude = 'nin',
|
||||
NotInclude = 'nin'
|
||||
}
|
||||
|
||||
|
||||
export enum PrefixID {
|
||||
Rule = 'r',
|
||||
Condition = 'c'
|
||||
@ -22,11 +21,9 @@ export enum Scope {
|
||||
Option = 'option'
|
||||
}
|
||||
|
||||
|
||||
export type FieldTypes = string | string[];
|
||||
export type FieldTypes = string | string[]
|
||||
|
||||
// 定义事实对象类型
|
||||
export type Fact = {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
[key: string]: any
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { nanoid } from 'nanoid';
|
||||
import { nanoid } from 'nanoid'
|
||||
import * as yup from 'yup'
|
||||
import { type FieldTypes, PrefixID, Operator, Scope } from './BasicType'
|
||||
|
||||
@ -7,33 +7,33 @@ export function generateID(prefix = PrefixID.Rule) {
|
||||
}
|
||||
// 定义条件规则类
|
||||
export class ConditionNode {
|
||||
id: string = '';
|
||||
public field: string = '';
|
||||
public operator: Operator = Operator.Include;
|
||||
id: string = ''
|
||||
public field: string = ''
|
||||
public operator: Operator = Operator.Include
|
||||
public value: FieldTypes = []
|
||||
constructor(field: string = '', operator: Operator = Operator.Include, value: FieldTypes = []) {
|
||||
this.field = field;
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
this.field = field
|
||||
this.operator = operator
|
||||
this.value = value
|
||||
this.id = generateID(PrefixID.Condition)
|
||||
}
|
||||
setField(field: string) {
|
||||
this.field = field;
|
||||
this.field = field
|
||||
}
|
||||
setOperator(operator: Operator) {
|
||||
this.operator = operator;
|
||||
this.operator = operator
|
||||
}
|
||||
setValue(value: FieldTypes) {
|
||||
this.value = value;
|
||||
this.value = value
|
||||
}
|
||||
}
|
||||
|
||||
export class RuleNode {
|
||||
id: string = '';
|
||||
id: string = ''
|
||||
conditions: ConditionNode[] = []
|
||||
scope: string = Scope.Question
|
||||
target: string = ''
|
||||
constructor(scope:string = Scope.Question, target: string = '') {
|
||||
constructor(scope: string = Scope.Question, target: string = '') {
|
||||
this.id = generateID(PrefixID.Rule)
|
||||
this.scope = scope
|
||||
this.target = target
|
||||
@ -42,44 +42,44 @@ export class RuleNode {
|
||||
this.target = value
|
||||
}
|
||||
addCondition(condition: ConditionNode) {
|
||||
this.conditions.push(condition);
|
||||
this.conditions.push(condition)
|
||||
}
|
||||
removeCondition(id: string) {
|
||||
this.conditions = this.conditions.filter(v => v.id !== id);
|
||||
this.conditions = this.conditions.filter((v) => v.id !== id)
|
||||
}
|
||||
findCondition(conditionId: string) {
|
||||
return this.conditions.find(condition => condition.id === conditionId);
|
||||
return this.conditions.find((condition) => condition.id === conditionId)
|
||||
}
|
||||
}
|
||||
|
||||
export class RuleBuild {
|
||||
rules: RuleNode[] = [];
|
||||
static instance: RuleBuild;
|
||||
rules: RuleNode[] = []
|
||||
static instance: RuleBuild
|
||||
constructor() {
|
||||
this.rules = [];
|
||||
this.rules = []
|
||||
if (!RuleBuild.instance) {
|
||||
RuleBuild.instance = this;
|
||||
RuleBuild.instance = this
|
||||
}
|
||||
|
||||
return RuleBuild.instance;
|
||||
return RuleBuild.instance
|
||||
}
|
||||
|
||||
// 添加条件规则到规则引擎中
|
||||
addRule(rule: RuleNode) {
|
||||
this.rules.push(rule);
|
||||
this.rules.push(rule)
|
||||
}
|
||||
removeRule(ruleId: string) {
|
||||
this.rules = this.rules.filter(rule => rule.id !== ruleId);
|
||||
this.rules = this.rules.filter((rule) => rule.id !== ruleId)
|
||||
}
|
||||
findRule(ruleId: string) {
|
||||
return this.rules.find(rule => rule.id === ruleId);
|
||||
return this.rules.find((rule) => rule.id === ruleId)
|
||||
}
|
||||
toJson() {
|
||||
return this.rules.map(rule => {
|
||||
return this.rules.map((rule) => {
|
||||
return {
|
||||
target: rule.target,
|
||||
scope: rule.scope,
|
||||
conditions: rule.conditions.map(condition => {
|
||||
conditions: rule.conditions.map((condition) => {
|
||||
return {
|
||||
field: condition.field,
|
||||
operator: condition.operator,
|
||||
@ -91,13 +91,13 @@ export class RuleBuild {
|
||||
}
|
||||
fromJson(ruleConf: any) {
|
||||
this.rules = []
|
||||
if(ruleConf instanceof Array) {
|
||||
if (ruleConf instanceof Array) {
|
||||
ruleConf.forEach((rule: any) => {
|
||||
const { scope, target } = rule
|
||||
const ruleNode = new RuleNode(scope, target);
|
||||
const ruleNode = new RuleNode(scope, target)
|
||||
rule.conditions.forEach((condition: any) => {
|
||||
const { field, operator, value } = condition
|
||||
const conditionNode = new ConditionNode(field, operator, value);
|
||||
const conditionNode = new ConditionNode(field, operator, value)
|
||||
ruleNode.addCondition(conditionNode)
|
||||
})
|
||||
this.addRule(ruleNode)
|
||||
@ -109,13 +109,13 @@ export class RuleBuild {
|
||||
return ruleSchema.validateSync(this.toJson())
|
||||
}
|
||||
// 实现目标选择了下拉框置灰效果
|
||||
findTargetsByScope(scope: string){
|
||||
return this.rules.filter(rule => rule.scope === scope).map(rule => rule.target)
|
||||
findTargetsByScope(scope: string) {
|
||||
return this.rules.filter((rule) => rule.scope === scope).map((rule) => rule.target)
|
||||
}
|
||||
// 实现前置题删除校验
|
||||
findTargetsByFields(field: string) {
|
||||
const nodes = this.rules.filter((rule: RuleNode) => {
|
||||
const conditions = rule.conditions.filter((item: any) => {
|
||||
const conditions = rule.conditions.filter((item: any) => {
|
||||
return item.field === field
|
||||
})
|
||||
return conditions.length > 0
|
||||
@ -126,11 +126,10 @@ export class RuleBuild {
|
||||
}
|
||||
// 根据目标题获取显示逻辑
|
||||
findConditionByTarget(target: string) {
|
||||
return this.rules.filter(rule=> rule.target === target).map(item => item.conditions)
|
||||
return this.rules.filter((rule) => rule.target === target).map((item) => item.conditions)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const ruleSchema = yup.array().of(
|
||||
yup.object({
|
||||
target: yup.string().required(),
|
||||
|
@ -1,64 +1,65 @@
|
||||
|
||||
import { Operator, type FieldTypes, type Fact } from "./BasicType";
|
||||
import { Operator, type FieldTypes, type Fact } from './BasicType'
|
||||
|
||||
// 定义条件规则类
|
||||
export class ConditionNode<F extends string, O extends Operator> {
|
||||
// 默认显示
|
||||
public result: boolean = false;
|
||||
constructor(public field: F, public operator: O, public value: FieldTypes) {
|
||||
}
|
||||
public result: boolean = false
|
||||
constructor(
|
||||
public field: F,
|
||||
public operator: O,
|
||||
public value: FieldTypes
|
||||
) {}
|
||||
|
||||
// 计算条件规则的哈希值
|
||||
calculateHash(): string {
|
||||
// 假设哈希值计算方法为简单的字符串拼接或其他哈希算法
|
||||
return this.field + this.operator + this.value;
|
||||
return this.field + this.operator + this.value
|
||||
}
|
||||
|
||||
match(facts: Fact): boolean {
|
||||
// console.log(this.calculateHash())
|
||||
// 如果该特征在事实对象中不存在,则直接返回false
|
||||
if(!facts[this.field]) {
|
||||
if (!facts[this.field]) {
|
||||
this.result = false
|
||||
return this.result
|
||||
}
|
||||
switch (this.operator) {
|
||||
case Operator.Equal:
|
||||
if(this.value instanceof Array) {
|
||||
this.result = this.value.every(v => facts[this.field].includes(v))
|
||||
if (this.value instanceof Array) {
|
||||
this.result = this.value.every((v) => facts[this.field].includes(v))
|
||||
return this.result
|
||||
} else {
|
||||
this.result = facts[this.field].includes(this.value);
|
||||
this.result = facts[this.field].includes(this.value)
|
||||
return this.result
|
||||
}
|
||||
case Operator.Include:
|
||||
if(this.value instanceof Array) {
|
||||
this.result = this.value.some(v => facts[this.field].includes(v))
|
||||
if (this.value instanceof Array) {
|
||||
this.result = this.value.some((v) => facts[this.field].includes(v))
|
||||
return this.result
|
||||
} else {
|
||||
this.result = facts[this.field].includes(this.value);
|
||||
this.result = facts[this.field].includes(this.value)
|
||||
return this.result
|
||||
}
|
||||
case Operator.NotInclude:
|
||||
if(this.value instanceof Array) {
|
||||
this.result = this.value.some(v => !facts[this.field].includes(v))
|
||||
if (this.value instanceof Array) {
|
||||
this.result = this.value.some((v) => !facts[this.field].includes(v))
|
||||
return this.result
|
||||
} else {
|
||||
this.result = facts[this.field].includes(this.value);
|
||||
this.result = facts[this.field].includes(this.value)
|
||||
return this.result
|
||||
}
|
||||
case Operator.NotEqual:
|
||||
if(this.value instanceof Array) {
|
||||
this.result = this.value.every(v => !facts[this.field].includes(v))
|
||||
if (this.value instanceof Array) {
|
||||
this.result = this.value.every((v) => !facts[this.field].includes(v))
|
||||
return this.result
|
||||
} else {
|
||||
this.result = facts[this.field].includes(this.value);
|
||||
this.result = facts[this.field].includes(this.value)
|
||||
return this.result
|
||||
}
|
||||
// 其他比较操作符的判断逻辑
|
||||
default:
|
||||
return this.result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getResult() {
|
||||
@ -67,27 +68,30 @@ export class ConditionNode<F extends string, O extends Operator> {
|
||||
}
|
||||
|
||||
export class RuleNode {
|
||||
conditions: Map<string, ConditionNode<string, Operator>>; // 使用哈希表存储条件规则对象
|
||||
public result: boolean = false;
|
||||
constructor(public target: string, public scope: string) {
|
||||
this.conditions = new Map();
|
||||
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, Operator>) {
|
||||
const hash = condition.calculateHash();
|
||||
this.conditions.set(hash, condition);
|
||||
const hash = condition.calculateHash()
|
||||
this.conditions.set(hash, condition)
|
||||
}
|
||||
|
||||
// 匹配条件规则
|
||||
match(fact: Fact) {
|
||||
const res = Array.from(this.conditions.entries()).every(([, value]) => {
|
||||
const res = Array.from(this.conditions.entries()).every(([, value]) => {
|
||||
const res = value.match(fact)
|
||||
if (res) {
|
||||
return true;
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
});
|
||||
})
|
||||
this.result = res
|
||||
return res
|
||||
}
|
||||
@ -102,7 +106,7 @@ export class RuleNode {
|
||||
// 计算条件规则的哈希值
|
||||
calculateHash(): string {
|
||||
// 假设哈希值计算方法为简单的字符串拼接或其他哈希算法
|
||||
return this.target + this.scope;
|
||||
return this.target + this.scope
|
||||
}
|
||||
toJson() {
|
||||
return {
|
||||
@ -111,30 +115,33 @@ export class RuleNode {
|
||||
conditions: Object.fromEntries(
|
||||
Array.from(this.conditions, ([key, value]) => [key, value.getResult()])
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class RuleMatch {
|
||||
rules: Map<string, RuleNode>;
|
||||
static instance: any;
|
||||
rules: Map<string, RuleNode>
|
||||
static instance: any
|
||||
constructor() {
|
||||
this.rules = new Map();
|
||||
this.rules = new Map()
|
||||
if (!RuleMatch.instance) {
|
||||
RuleMatch.instance = this;
|
||||
RuleMatch.instance = this
|
||||
}
|
||||
|
||||
return RuleMatch.instance;
|
||||
return RuleMatch.instance
|
||||
}
|
||||
fromJson(ruleConf:any) {
|
||||
if(ruleConf instanceof Array) {
|
||||
fromJson(ruleConf: any) {
|
||||
if (ruleConf instanceof Array) {
|
||||
ruleConf.forEach((rule: any) => {
|
||||
const ruleNode = new RuleNode(rule.target, rule.scope);
|
||||
const ruleNode = new RuleNode(rule.target, rule.scope)
|
||||
rule.conditions.forEach((condition: any) => {
|
||||
const conditionNode = new ConditionNode(condition.field, condition.operator, condition.value);
|
||||
ruleNode.addCondition(conditionNode)
|
||||
});
|
||||
const conditionNode = new ConditionNode(
|
||||
condition.field,
|
||||
condition.operator,
|
||||
condition.value
|
||||
)
|
||||
ruleNode.addCondition(conditionNode)
|
||||
})
|
||||
this.addRule(ruleNode)
|
||||
})
|
||||
}
|
||||
@ -142,23 +149,22 @@ export class RuleMatch {
|
||||
|
||||
// 添加条件规则到规则引擎中
|
||||
addRule(rule: RuleNode) {
|
||||
const hash = rule.calculateHash();
|
||||
const hash = rule.calculateHash()
|
||||
if (this.rules.has(hash)) {
|
||||
const existRule: any = this.rules.get(hash);
|
||||
const existRule: any = this.rules.get(hash)
|
||||
existRule.conditions.forEach((item: ConditionNode<string, Operator>) => {
|
||||
rule.addCondition(item)
|
||||
})
|
||||
}
|
||||
|
||||
this.rules.set(hash, rule);
|
||||
this.rules.set(hash, rule)
|
||||
}
|
||||
|
||||
|
||||
// 匹配条件规则
|
||||
match(target: string, scope: string, fact: Fact) {
|
||||
const hash = this.calculateHash(target, scope);
|
||||
const hash = this.calculateHash(target, scope)
|
||||
|
||||
const rule = this.rules.get(hash);
|
||||
const rule = this.rules.get(hash)
|
||||
if (rule) {
|
||||
const result = rule.match(fact)
|
||||
// this.matchCache.set(hash, result);
|
||||
@ -170,8 +176,8 @@ export class RuleMatch {
|
||||
}
|
||||
|
||||
getResult(target: string, scope: string) {
|
||||
const hash = this.calculateHash(target, scope);
|
||||
const rule = this.rules.get(hash);
|
||||
const hash = this.calculateHash(target, scope)
|
||||
const rule = this.rules.get(hash)
|
||||
if (rule) {
|
||||
const result = rule.getResult()
|
||||
return result
|
||||
@ -183,15 +189,17 @@ export class RuleMatch {
|
||||
// 计算哈希值的方法
|
||||
calculateHash(target: string, scope: string): string {
|
||||
// 假设哈希值计算方法为简单的字符串拼接或其他哈希算法
|
||||
return target + scope;
|
||||
return target + scope
|
||||
}
|
||||
findTargetsByField(field: string) {
|
||||
const rules = new Map([...this.rules.entries()].filter(([, value]) => {
|
||||
return [...value.conditions.entries()].filter(([, value]) => {
|
||||
return value.field === field
|
||||
const rules = new Map(
|
||||
[...this.rules.entries()].filter(([, value]) => {
|
||||
return [...value.conditions.entries()].filter(([, value]) => {
|
||||
return value.field === field
|
||||
})
|
||||
})
|
||||
}))
|
||||
return [...rules.values()].map(obj => obj.target);
|
||||
)
|
||||
return [...rules.values()].map((obj) => obj.target)
|
||||
}
|
||||
toJson() {
|
||||
return Array.from(this.rules.entries()).map(([, value]) => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { computed } from 'vue';
|
||||
import { computed } from 'vue'
|
||||
import store from '@/management/store'
|
||||
import { cleanRichText } from '@/common/xss'
|
||||
export const useQuestionInfo = (field) => {
|
||||
@ -12,9 +12,11 @@ export const useQuestionInfo = (field) => {
|
||||
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 {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { computed, unref } from 'vue';
|
||||
import { computed, unref } from 'vue'
|
||||
import { useQuestionInfo } from './useQuestionInfo'
|
||||
import { flatten } from 'lodash-es'
|
||||
import { cleanRichText } from '@/common/xss'
|
||||
@ -16,14 +16,16 @@ export const useShowLogicInfo = (field) => {
|
||||
})
|
||||
const getShowLogicText = computed(() => {
|
||||
const logicEngine = showLogicEngine.value
|
||||
// 获取目标题的规则
|
||||
const rules = logicEngine?.findConditionByTarget(field) || []
|
||||
// 获取目标题的规则
|
||||
const rules = logicEngine?.findConditionByTarget(field) || []
|
||||
|
||||
const conditions = flatten(rules).map((item) => {
|
||||
const { getQuestionTitle, getOptionTitle } = useQuestionInfo(item.field)
|
||||
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/>`
|
||||
})
|
||||
return conditions.length ? conditions.join('') + '<span> 满足以上全部,则显示本题</span>' :''
|
||||
return conditions.length
|
||||
? conditions.join('') + '<span> 满足以上全部,则显示本题</span>'
|
||||
: ''
|
||||
})
|
||||
return { hasShowLogic, getShowLogicText }
|
||||
}
|
@ -66,7 +66,7 @@ export default {
|
||||
}
|
||||
},
|
||||
updateLogicConf() {
|
||||
if(showLogicEngine.value) {
|
||||
if (showLogicEngine.value) {
|
||||
showLogicEngine.value.validateSchema()
|
||||
const showLogicConf = showLogicEngine.value.toJson()
|
||||
// 更新逻辑配置
|
||||
|
@ -90,7 +90,7 @@ export default {
|
||||
}
|
||||
},
|
||||
updateLogicConf() {
|
||||
if(showLogicEngine.value) {
|
||||
if (showLogicEngine.value) {
|
||||
showLogicEngine.value.validateSchema()
|
||||
const showLogicConf = showLogicEngine.value.toJson()
|
||||
// 更新逻辑配置
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="rule-list">
|
||||
<RuleNodeView
|
||||
v-for="(item) in list"
|
||||
v-for="item in list"
|
||||
ref="ruleWrappers"
|
||||
:key="item.id"
|
||||
:ruleNode="item"
|
||||
|
@ -78,7 +78,8 @@ const props = defineProps({
|
||||
})
|
||||
const fieldList = computed(() => {
|
||||
const currentIndex = renderData.value.findIndex((item) => item.field === props.ruleNode.target)
|
||||
return renderData.value.slice(0, currentIndex)
|
||||
return renderData.value
|
||||
.slice(0, currentIndex)
|
||||
.filter((question: any) => qAbleList.includes(question.type))
|
||||
.map((item: any) => {
|
||||
return {
|
||||
@ -140,14 +141,14 @@ const handleDelete = (id: any) => {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 24px 0;
|
||||
&:not(:last-child)::before{
|
||||
&:not(:last-child)::before {
|
||||
content: attr(data-content-before);
|
||||
bottom: 0px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #FEF6E6;
|
||||
background: #fef6e6;
|
||||
border-radius: 2px;
|
||||
color: #FAA600;
|
||||
color: #faa600;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -155,14 +156,14 @@ const handleDelete = (id: any) => {
|
||||
position: absolute;
|
||||
bottom: -8px;
|
||||
}
|
||||
&:not(:last-child)::after{
|
||||
content: "";
|
||||
display: block;
|
||||
width: calc(100% - 32px);
|
||||
border-top: 1px dashed #e3e4e8;
|
||||
position: absolute;
|
||||
left: 32px;
|
||||
bottom: 0;
|
||||
&:not(:last-child)::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: calc(100% - 32px);
|
||||
border-top: 1px dashed #e3e4e8;
|
||||
position: absolute;
|
||||
left: 32px;
|
||||
bottom: 0;
|
||||
}
|
||||
.desc {
|
||||
display: inline-block;
|
||||
|
@ -32,7 +32,7 @@
|
||||
v-for="{ label, value, disabled } in targetQuestionList"
|
||||
:key="value"
|
||||
:label="label"
|
||||
:disabled="disabled && ruleNode.target !== value "
|
||||
:disabled="disabled && ruleNode.target !== value"
|
||||
:value="value"
|
||||
>
|
||||
</el-option>
|
||||
@ -97,7 +97,9 @@ const submitForm = () => {
|
||||
const targetQuestionList = computed(() => {
|
||||
const currntIndexs: number[] = []
|
||||
props.ruleNode.conditions.forEach((el) => {
|
||||
currntIndexs.push(renderData.value.findIndex((item: { field: string }) => item.field === el.field))
|
||||
currntIndexs.push(
|
||||
renderData.value.findIndex((item: { field: string }) => item.field === el.field)
|
||||
)
|
||||
})
|
||||
const currntIndex = Math.max(...currntIndexs)
|
||||
let questionList = cloneDeep(renderData.value.slice(currntIndex + 1))
|
||||
@ -105,9 +107,7 @@ const targetQuestionList = computed(() => {
|
||||
return {
|
||||
label: `${item.showIndex ? item.indexNumber + '.' : ''} ${cleanRichText(item.title)}`,
|
||||
value: item.field,
|
||||
disabled: showLogicEngine.value
|
||||
.findTargetsByScope('question')
|
||||
.includes(item.field)
|
||||
disabled: showLogicEngine.value.findTargetsByScope('question').includes(item.field)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -6,34 +6,33 @@
|
||||
:name="index"
|
||||
:key="index"
|
||||
>
|
||||
<draggable
|
||||
class="questiontype-list"
|
||||
:list="item.questionList"
|
||||
:group="{ name: DND_GROUP, pull: 'clone', put: false }"
|
||||
:clone="getNewQuestion"
|
||||
item-key="path"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<div
|
||||
:key="element.type"
|
||||
class="qtopic-item"
|
||||
:id="'qtopic' + element.type"
|
||||
@click="onQuestionType({ type: element.type })"
|
||||
@mouseenter="showPreview(element, 'qtopic' + element.type)"
|
||||
@mouseleave="isShowPreviewImage = false"
|
||||
@mousedown="isShowPreviewImage = false"
|
||||
>
|
||||
<i class="iconfont" :class="['icon-' + element.icon]"></i>
|
||||
<p class="text">{{ element.title }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</draggable>
|
||||
<draggable
|
||||
class="questiontype-list"
|
||||
:list="item.questionList"
|
||||
:group="{ name: DND_GROUP, pull: 'clone', put: false }"
|
||||
:clone="getNewQuestion"
|
||||
item-key="path"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<div
|
||||
:key="element.type"
|
||||
class="qtopic-item"
|
||||
:id="'qtopic' + element.type"
|
||||
@click="onQuestionType({ type: element.type })"
|
||||
@mouseenter="showPreview(element, 'qtopic' + element.type)"
|
||||
@mouseleave="isShowPreviewImage = false"
|
||||
@mousedown="isShowPreviewImage = false"
|
||||
>
|
||||
<i class="iconfont" :class="['icon-' + element.icon]"></i>
|
||||
<p class="text">{{ element.title }}</p>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
</el-collapse-item>
|
||||
<Teleport to="body">
|
||||
<div class="preview-popover" v-show="isShowPreviewImage" :style="{ top: previewTop + 'px'}">
|
||||
<img :src="previewImg" class="preview-image"/>
|
||||
<span class="preview-arrow"></span>
|
||||
<div class="preview-popover" v-show="isShowPreviewImage" :style="{ top: previewTop + 'px' }">
|
||||
<img :src="previewImg" class="preview-image" />
|
||||
<span class="preview-arrow"></span>
|
||||
</div>
|
||||
</Teleport>
|
||||
</el-collapse>
|
||||
@ -211,7 +210,7 @@ const showPreview = ({ snapshot }, id) => {
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
content: '';
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
@ -219,7 +218,6 @@ const showPreview = ({ snapshot }, id) => {
|
||||
border-bottom-color: transparent;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<CommonTemplate>
|
||||
<template #left>
|
||||
<CatalogPanel />
|
||||
<CatalogPanel />
|
||||
</template>
|
||||
<template #center>
|
||||
<PreviewPanel />
|
||||
@ -12,19 +12,19 @@
|
||||
</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: 'editIndex',
|
||||
components: {
|
||||
CommonTemplate,
|
||||
CatalogPanel,
|
||||
PreviewPanel,
|
||||
SetterPanel,
|
||||
},
|
||||
};
|
||||
SetterPanel
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.navbar {
|
||||
|
@ -30,8 +30,7 @@ const routes: RouteRecordRaw[] = [
|
||||
needLogin: true
|
||||
},
|
||||
name: 'QuestionEditPage',
|
||||
component: () =>
|
||||
import('../pages/edit/pages/edit/index.vue'),
|
||||
component: () => import('../pages/edit/pages/edit/index.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
@ -39,8 +38,7 @@ const routes: RouteRecordRaw[] = [
|
||||
meta: {
|
||||
needLogin: true
|
||||
},
|
||||
component: () =>
|
||||
import('../pages/edit/pages/edit/QuestionEditPage.vue')
|
||||
component: () => import('../pages/edit/pages/edit/QuestionEditPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'logic',
|
||||
@ -48,8 +46,7 @@ const routes: RouteRecordRaw[] = [
|
||||
meta: {
|
||||
needLogin: true
|
||||
},
|
||||
component: () =>
|
||||
import('../pages/edit/pages/edit/LogicEditPage.vue')
|
||||
component: () => import('../pages/edit/pages/edit/LogicEditPage.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -15,8 +15,15 @@ export default {
|
||||
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
|
||||
const {
|
||||
bannerConf,
|
||||
bottomConf,
|
||||
skinConf,
|
||||
baseConf,
|
||||
submitConf,
|
||||
dataConf,
|
||||
logicConf = {}
|
||||
} = res.data.surveyConfRes.code
|
||||
commit('initSchema', {
|
||||
metaData,
|
||||
codeData: {
|
||||
@ -29,7 +36,6 @@ export default {
|
||||
logicConf
|
||||
}
|
||||
})
|
||||
|
||||
} else {
|
||||
throw new Error(res.errmsg || '问卷不存在')
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export default {
|
||||
setBannerList(state, data) {
|
||||
state.bannerList = data
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -3,19 +3,14 @@ export const QOP_MAP = {
|
||||
COPY: 'copy',
|
||||
EDIT: 'edit'
|
||||
}
|
||||
export const qAbleList = [
|
||||
'radio',
|
||||
'checkbox',
|
||||
'binary-choice',
|
||||
'vote',
|
||||
]
|
||||
export const qAbleList = ['radio', 'checkbox', 'binary-choice', 'vote']
|
||||
export const operatorOptions = [
|
||||
{
|
||||
label: '选择了',
|
||||
value: 'in',
|
||||
label: '选择了',
|
||||
value: 'in'
|
||||
},
|
||||
{
|
||||
label: '不选择',
|
||||
value: 'nin',
|
||||
},
|
||||
label: '不选择',
|
||||
value: 'nin'
|
||||
}
|
||||
]
|
@ -32,7 +32,7 @@ interface Props {
|
||||
}
|
||||
|
||||
interface Emit {
|
||||
(ev: typeof FORM_CHANGE_EVENT_KEY, arg: { key: string; value: string }): void
|
||||
(ev: typeof FORM_CHANGE_EVENT_KEY, arg: { key: string; value: string | null }): void
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
@ -58,8 +58,8 @@ const handleSelectChange = (value: string) => {
|
||||
emit(FORM_CHANGE_EVENT_KEY, { key: formdataBackfillKey, value })
|
||||
}
|
||||
|
||||
const handleSwitchChange = (value: string) => {
|
||||
emit(FORM_CHANGE_EVENT_KEY, { key: formdataBackfillHourKey, value: value ? 24 : null })
|
||||
const handleSwitchChange = (value: string | null) => {
|
||||
emit(FORM_CHANGE_EVENT_KEY, { key: formdataBackfillHourKey, value: value ? '24' : null })
|
||||
}
|
||||
|
||||
const watchValue = computed(() => props.formConfig.value)
|
||||
|
@ -77,15 +77,15 @@ onMounted(async () => {
|
||||
|
||||
if (res.code === 200) {
|
||||
const data = res.data
|
||||
const { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf, logicConf } = data.code
|
||||
const { bannerConf, baseConf, bottomConf, dataConf, skinConf, submitConf, logicConf } =
|
||||
data.code
|
||||
const questionData = {
|
||||
bannerConf,
|
||||
baseConf,
|
||||
bottomConf,
|
||||
dataConf,
|
||||
skinConf,
|
||||
submitConf,
|
||||
|
||||
submitConf
|
||||
}
|
||||
|
||||
document.title = data.title
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<form ref="ruleForm" :model="formValues" :rules="rules">
|
||||
<div v-for="(item) in renderData" :key="item.field">
|
||||
<div v-for="item in renderData" :key="item.field">
|
||||
<QuestionWrapper
|
||||
class="gap"
|
||||
v-bind="$attrs"
|
||||
|
@ -29,31 +29,37 @@ const props = defineProps({
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
const formValues = computed(() => {
|
||||
return store.state.formValues
|
||||
})
|
||||
const questionConfig = computed(() =>{
|
||||
const questionConfig = computed(() => {
|
||||
let moduleConfig = props.moduleConfig
|
||||
const { type, field, options, ...rest } = cloneDeep(moduleConfig)
|
||||
// console.log(field,'这里依赖的formValue,所以change时会触发重新计算')
|
||||
let alloptions = options
|
||||
if(type === QUESTION_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(QUESTION_TYPE.CHOICES.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(QUESTION_TYPE.RATES.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)
|
||||
moduleConfig.rangeConfig = unref(rangeConfig)
|
||||
moduleConfig.othersValue = unref(othersValue)
|
||||
@ -73,27 +79,30 @@ const visible = computed(() => {
|
||||
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 (type === QUESTION_TYPE.CHECKBOX || innerType === QUESTION_TYPE.CHECKBOX) {
|
||||
value = value ? [value] : []
|
||||
watch(
|
||||
() => visible.value,
|
||||
(newVal, oldVal) => {
|
||||
// 题目从显示到隐藏,需要清空值
|
||||
const { field, type, innerType } = props.moduleConfig
|
||||
if (!newVal && oldVal) {
|
||||
let value = ''
|
||||
// 题型是多选,或者子题型是多选(innerType是用于投票)
|
||||
if (type === QUESTION_TYPE.CHECKBOX || innerType === QUESTION_TYPE.CHECKBOX) {
|
||||
value = value ? [value] : []
|
||||
}
|
||||
const data = {
|
||||
key: field,
|
||||
value: value
|
||||
}
|
||||
store.commit('changeFormData', data)
|
||||
}
|
||||
const data = {
|
||||
key: field,
|
||||
value: value
|
||||
}
|
||||
store.commit('changeFormData', data)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const handleChange = (data) => {
|
||||
emit('change', data)
|
||||
// 处理投票题
|
||||
if(props.moduleConfig.type === QUESTION_TYPE.VOTE) {
|
||||
if (props.moduleConfig.type === QUESTION_TYPE.VOTE) {
|
||||
store.dispatch('updateVoteData', data)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
export const QUESTION_TYPE = {
|
||||
VOTE: 'vote',
|
||||
CHECKBOX: 'checkbox',
|
||||
CHOICES: [ // 选择类题型分类
|
||||
CHOICES: [
|
||||
// 选择类题型分类
|
||||
'radio',
|
||||
'checkbox',
|
||||
'checkbox'
|
||||
],
|
||||
RATES: [ // 评分题题型分类
|
||||
RATES: [
|
||||
// 评分题题型分类
|
||||
'radio-star',
|
||||
'radio-nps'
|
||||
]
|
||||
|
@ -5,15 +5,14 @@ export const useShowInput = (questionKey) => {
|
||||
let rangeConfig = store.state.questionData[questionKey].rangeConfig
|
||||
let othersValue = {}
|
||||
if (rangeConfig && Object.keys(rangeConfig).length > 0) {
|
||||
for(let key in rangeConfig) {
|
||||
for (let key in rangeConfig) {
|
||||
const curRange = rangeConfig[key]
|
||||
if (curRange.isShowInput) {
|
||||
const rangeKey = `${questionKey}_${key}`
|
||||
othersValue[rangeKey] = formValues[rangeKey]
|
||||
|
||||
curRange.othersKey = rangeKey,
|
||||
curRange.othersValue = formValues[rangeKey]
|
||||
if(!questionVal.toString().includes(key) && formValues[rangeKey]) {
|
||||
;(curRange.othersKey = rangeKey), (curRange.othersValue = formValues[rangeKey])
|
||||
if (!questionVal.toString().includes(key) && formValues[rangeKey]) {
|
||||
// 如果分值被未被选中且对应的填写更多有值,则清空填写更多
|
||||
const data = {
|
||||
key: rangeKey,
|
||||
@ -25,6 +24,5 @@ export const useShowInput = (questionKey) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return { rangeConfig, othersValue }
|
||||
return { rangeConfig, othersValue }
|
||||
}
|
@ -3,11 +3,11 @@ export const useShowOthers = (questionKey) => {
|
||||
const formValues = store.state.formValues
|
||||
const questionVal = formValues[questionKey]
|
||||
let othersValue = {}
|
||||
let options = store.state.questionData[questionKey].options.map(optionItem => {
|
||||
let options = store.state.questionData[questionKey].options.map((optionItem) => {
|
||||
if (optionItem.others) {
|
||||
const opKey = `${questionKey}_${optionItem.hash}`
|
||||
othersValue[opKey] = formValues[opKey]
|
||||
if(!questionVal.includes(optionItem.hash) && formValues[opKey]) {
|
||||
if (!questionVal.includes(optionItem.hash) && formValues[opKey]) {
|
||||
// 如果选项被未被选中且对应的填写更多有值,则清空填写更多
|
||||
const data = {
|
||||
key: opKey,
|
||||
|
@ -1,17 +1,16 @@
|
||||
import store from '../store/index'
|
||||
export const useVoteMap = (questionKey) => {
|
||||
let voteTotal = store.state.voteMap?.[questionKey]?.total || 0
|
||||
|
||||
let voteTotal = store.state.voteMap?.[questionKey]?.total || 0
|
||||
const options = store.state.questionData[questionKey].options.map((option) => {
|
||||
const optionHash = option.hash
|
||||
const voteCount = store.state.voteMap?.[questionKey]?.[optionHash] || 0
|
||||
|
||||
const options = store.state.questionData[questionKey].options.map(option => {
|
||||
const optionHash = option.hash
|
||||
const voteCount = store.state.voteMap?.[questionKey]?.[optionHash] || 0
|
||||
|
||||
return {
|
||||
...option,
|
||||
voteCount
|
||||
}
|
||||
})
|
||||
return {
|
||||
...option,
|
||||
voteCount
|
||||
}
|
||||
})
|
||||
|
||||
return { options, voteTotal }
|
||||
}
|
@ -9,7 +9,7 @@ export default {
|
||||
questionSeq.reduce((pre, item) => {
|
||||
const questionArr = []
|
||||
|
||||
item.forEach(questionKey => {
|
||||
item.forEach((questionKey) => {
|
||||
console.log('题目重新计算')
|
||||
const question = { ...questionData[questionKey] }
|
||||
// 开启显示序号
|
||||
|
@ -39,7 +39,7 @@ export default {
|
||||
updateVoteMapByKey(state, data) {
|
||||
const { questionKey, voteKey, voteValue } = data
|
||||
// 兼容为空的情况
|
||||
if(!state.voteMap[questionKey]){
|
||||
if (!state.voteMap[questionKey]) {
|
||||
state.voteMap[questionKey] = {}
|
||||
}
|
||||
state.voteMap[questionKey][voteKey] = voteValue
|
||||
@ -52,5 +52,5 @@ export default {
|
||||
},
|
||||
setRuleEgine(state, ruleEngine) {
|
||||
state.ruleEngine = ruleEngine
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user