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