Files
alab-amis-fix-exam/src/pages/schema/centre/exam/question.schema.ts
2024-11-13 09:05:45 +08:00

1643 lines
73 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const schema = {
type: 'page',
body: [
{
type: 'form',
name: 'cg',
body: [
{
type: 'service',
name: 'service',
api: {
method: 'get',
url: 'rest/exam_question_categories/${tree}',
sendOn: 'this.tree',
},
messages: {},
body: [
{
type: 'formula',
name: 'filter',
formula: "'(category.in.(' + data.tree + '),category.is.null)'",
condition: 'data.tree && data.no_cate',
id: 'u:20719f5b3c61',
},
{
type: 'formula',
name: 'filter',
condition: 'data.tree && !data.no_cate',
formula: "'(category.in.(' + data.tree + '))'",
id: 'u:da3404346ffb',
},
{
type: 'formula',
name: 'filter',
condition: '!data.tree && data.no_cate',
formula: "'(category.is.null)'",
id: 'u:c7c6c0aa04b6',
},
{
type: 'formula',
name: 'filter',
formula: "'(id.neq.0)'",
condition: '!data.tree && !data.no_cate',
id: 'u:d2517bd7c8ee',
},
],
id: 'u:87d7f2fe2416',
dsType: 'api',
},
{
type: 'tree-select',
label: '分类',
name: 'tree',
mode: 'horizontal',
source: {
method: 'get',
url: 'rest/exam_question_categories?path=cd.root&order=name',
adaptor:
'const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n\r\n return nodes.map(item => {\r\n let temp = recursive(item.id)\r\n\r\n if (temp.length > 0) {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: temp\r\n }\r\n } else {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`\r\n }\r\n }\r\n })\r\n}\r\n\r\nlet tops = payload.data.items.filter(x => x.parent === null)\r\n\r\nreturn {\r\n ...payload,\r\n data: tops.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\n',
},
initiallyOpen: false,
searchable: true,
multiple: true,
joinValues: true,
onlyChildren: false,
withChildren: true,
cascade: true,
heightAuto: true,
virtualThreshold: false,
id: 'u:cde3f7416895',
},
{
type: 'checkbox',
label: '',
name: 'no_cate',
mode: 'inline',
option: '显示无分类题目',
id: 'u:50f0cbebc61b',
},
{
type: 'switch',
name: 'is_show',
mode: 'inline',
value: true,
option: '缩略显示',
optionAtLeft: false,
trueValue: true,
falseValue: false,
id: 'u:bfaf3772c9d4',
},
],
title: '表单',
wrapWithPanel: false,
reload:
'stu?parent=${tree}&tree=${tree}&org_name=${name}&filter=${filter}&is_show=${is_show}',
submitOnInit: true,
submitOnChange: true,
target: '',
initApi: '',
data: {
parentId: 1,
},
md: 3,
resetAfterSubmit: false,
id: 'u:48ceddfb7e02',
feat: 'View',
},
{
type: 'divider',
lineStyle: 'solid',
id: 'u:7a199eac8602',
},
{
type: 'crud',
messages: {},
api: {
method: 'get',
url: 'rest/exam_questions?select=id,type,content,analysis,tag,score,organization_id,answer,difficulty,is_objective,category,exam_question_categories(*),dicts(dictkey,dictvalue)&organization_id=eq.$centre_id&order=category,id',
data: {
page: '${page}',
perPage: '${perPage}',
or: '${filter}',
},
adaptor:
"return {\r\n ...payload,\r\n data: {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n let pattern = /<p>|<\\/p>|<strong>|<\\/strong>|<br \\/>/g\r\n let image_pattern = /<img .*?\\/>/g\r\n let raw_options = ''\r\n item.content.options && item.content.options.forEach(option => {\r\n raw_options = raw_options.concat(option.label.replace(/^<p>/, '<p>'.concat(option.key, '. ')).replace(/^<img/, ''.concat(option.key, '. <img')))\r\n })\r\n return {\r\n ...item,\r\n raw_title: item.content.title.replace(pattern, '').replace(image_pattern, '[图片]').replaceAll('&hellip;', '…').replaceAll('&mdash;', '—').replaceAll('&ldquo;', '“').replaceAll('&rdquo;', '”').replaceAll('&lsquo;', '').replaceAll('&rsquo;', ''),\r\n raw_options: raw_options\r\n }\r\n })\r\n }\r\n}",
requestAdaptor: '',
sendOn: 'this.filter',
},
syncLocation: false,
name: 'stu',
columns: [
{
name: '',
type: 'button',
placeholder: '-',
visibleOn: 'this.is_show',
label: '$raw_title',
actionType: 'dialog',
dialog: {
type: 'dialog',
title: '题目详情',
body: [
{
type: 'tpl',
tpl: "<div><span class=\"label label-default text-md\"><%= this.dicts && this.dicts.dictvalue %></span></div>\n<div><%= this.content && this.content.title %></div>\n<% this.content && this.content.options && this.content.options.forEach(item => { %>\n <div><%= item.label.replace(/^<p>/, '<p>'.concat(item.key, '. ')).replace(/^<img/, ''.concat(item.key, '. <img')) %></div>\n<% }) %>\n<div><%= this.answer && '<span class=\"label label-default text-md\">答案</span>'.concat(this.answer) %></div>\n<div><%= this.analysis && this.analysis.replace(/^<p>/, '<p>'.concat('<span class=\"label label-default text-md\">答案解析</span>')).replace(/^<img/, '<span class=\"label label-default text-md\">答案解析</span><img') %></div>",
inline: false,
},
],
size: 'lg',
actions: [],
closeOnEsc: true,
},
width: 500,
innerClassName: '',
className: 'question',
block: false,
level: 'link',
remark: '',
tooltip: '$raw_title',
tooltipPlacement: 'bottom',
id: 'u:84ea04af2db4',
},
{
name: 'content.title',
type: 'tpl',
placeholder: '-',
tpl: '<% if(data.content) { %><%= data.content.title %><% } %>',
label: '题干',
quickEdit: {
mode: 'popOver',
type: 'image-upload',
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
content: '$content',
},
requestAdaptor:
'let pattern = new RegExp("(\\\\.\\\\./){1,6}")\r\n\r\nif (api.data.content.options.length) {\r\n api.data.content = {\r\n title: api.data.content.title.replace(pattern, "/"),\r\n options: api.data.content.options.map(item => {\r\n return {\r\n ...item,\r\n label: item.label.replace(pattern, "/")\r\n }\r\n })\r\n }\r\n} else {\r\n api.data.content = {\r\n title: api.data.content.title.replace(pattern, "/")\r\n }\r\n}\r\n\r\nreturn api',
},
},
name: 'content.title',
},
inline: false,
popOver: false,
copyable: false,
visibleOn: '!this.is_show',
id: 'u:16e82384ee3c',
},
{
type: 'tpl',
name: 'raw_options',
placeholder: '-',
visibleOn: '!this.is_show',
label: '选项',
tpl: '<%= this.raw_options %>',
inline: false,
quickEdit: {
type: 'custom-option',
name: 'content.options',
label: '选项配置',
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
content: '$content',
},
requestAdaptor:
'let options = JSON.parse(JSON.stringify(api.data.content.options))\r\nlet index = options\r\n .findIndex(item => !Object.keys(item).length)\r\nwhile (index != -1) {\r\n options.splice(index, 1)\r\n index = options\r\n .findIndex(item => !Object.keys(item).length)\r\n}\r\n\r\napi.data.content = {\r\n ...api.data.content,\r\n options: options\r\n}\r\n\r\nlet pattern = new RegExp("(\\\\.\\\\./){1,6}")\r\n\r\nif (api.data.content.options.length) {\r\n api.data.content = {\r\n title: api.data.content.title.replace(pattern, "/"),\r\n options: api.data.content.options.map(item => {\r\n return {\r\n ...item,\r\n label: item.label.replace(pattern, "/")\r\n }\r\n })\r\n }\r\n} else {\r\n api.data.content = {\r\n title: api.data.content.title.replace(pattern, "/")\r\n }\r\n}\r\n\r\nreturn api',
},
},
mode: 'popOver',
form: {
title: '修改选项',
controls: [
{
type: 'text',
label: '选项',
name: 'key',
disabledOn: 'true',
},
{
name: 'label',
label: '内容',
type: 'input-rich-text',
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
mode: 'normal',
},
{
type: 'switch',
name: 'is_fixed',
label: '',
option: '是否固定',
optionAtLeft: false,
trueValue: true,
falseValue: false,
},
],
size: 'lg',
},
multiple: true,
btnLabel: '设置选项',
},
popOver: false,
copyable: false,
quickEditEnabledOn:
"this.type === 'question_single_choice' || this.type === 'question_multi_choice'",
id: 'u:aee56529edd2',
},
{
type: 'tpl',
placeholder: '-',
name: 'answer',
label: '答案',
quickEdit: {
type: 'input-text',
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
answer: '$answer',
},
},
saveImmediately: true,
},
},
tpl: '<%= data.answer %>',
inline: false,
visibleOn: '!this.is_show',
id: 'u:01aba281f46f',
},
{
type: 'tpl',
name: 'analysis',
label: '答案解析',
placeholder: '-',
tpl: '<%= data.analysis %>',
inline: false,
quickEdit: {
type: 'input-rich-text',
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
analysis: '$analysis',
},
requestAdaptor:
'let pattern = new RegExp("(\\\\.\\\\./){1,6}")\r\n\r\napi.data.analysis = api.data.analysis.replace(pattern, "/")\r\n\r\nreturn api',
},
},
mode: 'popOver',
name: 'analysis',
vendor: 'tinymce',
options: {
menubar: 'true',
relative_urls: false,
remove_script_host: true,
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
},
visibleOn: '!this.is_show',
id: 'u:c7737bb550ad',
},
{
type: 'text',
label: '题型',
name: 'dicts.dictvalue',
placeholder: '-',
quickEdit: {
type: 'select',
options: [
{
label: '单选题',
value: 'question_single_choice',
},
{
label: '多选题',
value: 'question_multi_choice',
},
{
label: '判断题',
value: 'question_true_or_false',
},
],
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
type: '${dicts.dictkey}',
},
requestAdaptor:
"if(api.data.type === 'question_single_choice' || api.data.type === 'question_multi_choice' || api.data.type === 'question_true_or_false') {\r\n api.data.is_objective = true;\r\n} else {\r\n api.data.is_objective = false;\r\n}\r\nreturn api;",
},
},
name: 'dicts.dictkey',
mode: 'popOver',
},
id: 'u:cb1a31cb64c5',
},
{
type: 'text',
label: '难易程度',
placeholder: '-',
name: 'difficulty',
quickEdit: {
type: 'select',
options: [
{
label: '简单',
value: '简单',
},
{
label: '中等',
value: '中等',
},
{
label: '困难',
value: '困难',
},
],
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
difficulty: '$difficulty',
},
},
},
},
id: 'u:f802eab00c6d',
},
{
type: 'text',
label: '分数',
name: 'score',
placeholder: '-',
quickEdit: {
type: 'input-number',
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
score: '$score',
},
},
},
},
id: 'u:b3daeb51d76d',
},
{
type: 'tpl',
label: '类别',
name: 'exam_question_categories.name',
placeholder: '-',
quickEdit: {
type: 'tree-select',
source: {
method: 'get',
url: 'rest/exam_question_categories?path=cd.root&order=name',
adaptor:
'const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet tops = payload.data.items.filter(x => x.parent === null)\r\nreturn {\r\n ...payload,\r\n data: tops.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}',
},
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
category: '${exam_question_categories.id}',
},
},
},
name: 'exam_question_categories.id',
initiallyOpen: false,
heightAuto: true,
virtualThreshold: false,
mode: 'popOver',
},
id: 'u:9c16b39eb764',
},
{
type: 'operation',
buttons: [
{
type: 'button-group',
buttons: [
{
type: 'button',
actionType: 'dialog',
dialog: {
type: 'dialog',
title: '修改',
body: [
{
type: 'form',
title: '表单',
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
content: '$content',
category: '$category',
answer: '$answer',
analysis: '$analysis',
difficulty: '$difficulty',
is_objective: '$is_objective',
type: '$type',
},
dataType: 'json',
requestAdaptor:
'if (api && api.data && api.data.content && api.data.content.options) {\r\n let options = JSON.parse(JSON.stringify(api.data.content.options))\r\n let index = options.findIndex(item => !Object.keys(item).length)\r\n while (index != -1) {\r\n options.splice(index, 1)\r\n index = options.findIndex(item => !Object.keys(item).length)\r\n }\r\n\r\n api.data.content = {\r\n ...api.data.content,\r\n options: options\r\n }\r\n} else if (api && api.data && api.data.type === \'question_true_or_false\') {\r\n api.data.content = {\r\n ...api.data.content,\r\n options: [\r\n { "key": "正确", "label": "正确", "is_fixed": false },\r\n { "key": "错误", "label": "错误", "is_fixed": false }\r\n ]\r\n }\r\n}\r\n\r\nlet pattern = new RegExp("(\\\\.\\\\./){1,6}")\r\napi.data.content.title = api.data.content.title.replace(pattern, "/")\r\n\r\nif (api.data.content.options.length) {\r\n api.data.content.options = api.data.content.options.map(item => {\r\n return {\r\n ...item,\r\n label: item.label.replace(pattern, "/")\r\n }\r\n })\r\n}\r\n\r\napi.data.analysis = api.data.analysis.replace(pattern, "/")\r\n\r\nreturn api',
},
body: [
{
label: '',
type: 'combo',
name: 'content',
multiple: false,
multiLine: true,
joinValues: true,
messages: {},
typeSwitchable: false,
strictMode: true,
mode: 'normal',
clearValueOnHidden: true,
visibleOn:
"this.type === 'question_single_choice' || this.type === 'question_multi_choice'",
items: [
{
type: 'input-rich-text',
label: '题干',
name: 'title',
mode: 'normal',
reciever: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
},
{
label: '选项配置',
name: 'options',
type: 'custom-option',
form: {
title: '修改选项',
controls: [
{
type: 'text',
label: '选项',
name: 'key',
},
{
name: 'label',
label: '内容',
type: 'input-rich-text',
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
mode: 'normal',
},
{
type: 'switch',
name: 'is_fixed',
label: '',
option: '是否固定',
optionAtLeft: false,
trueValue: true,
falseValue: false,
},
],
size: 'lg',
},
multiple: true,
btnLabel: '设置选项',
},
],
},
{
type: 'combo',
label: '',
name: 'content',
mode: 'normal',
value: '',
multiple: false,
multiLine: true,
joinValues: true,
messages: {},
typeSwitchable: false,
strictMode: true,
visibleOn:
"this.type === 'question_true_or_false' || this.type === 'question_filling' || this.type === 'question_short_answer'",
clearValueOnHidden: true,
items: [
{
type: 'input-rich-text',
label: '题干',
name: 'title',
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
mode: 'normal',
},
],
},
{
type: 'input-text',
label: '答案',
name: 'answer',
mode: 'normal',
},
{
type: 'input-rich-text',
label: '答案解析',
name: 'analysis',
mode: 'normal',
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
vendor: 'tinymce',
options: {
menubar: 'true',
relative_urls: false,
remove_script_host: true,
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
},
{
type: 'input-text',
label: '难易程度',
name: 'difficulty',
mode: 'normal',
},
{
type: 'select',
name: 'type',
label: '题型',
mode: 'normal',
options: [],
checkAll: false,
source: {
method: 'get',
url: 'rest/dicts?typecode=eq.019',
adaptor:
'return {\r\n ...payload.data,\r\n items: payload.data.items.map(item => {\r\n return {\r\n label: item.dictvalue,\r\n value: item.dictkey\r\n }\r\n })\r\n}',
},
},
{
type: 'formula',
name: 'is_objective',
formula:
"data.type === 'question_single_choice' || data.type === 'question_multi_choice' || data.type === 'question_true_or_false'",
},
{
type: 'hidden',
name: 'is_objective',
},
{
type: 'tree-select',
name: 'category',
label: '类别',
options: [],
source: {
method: 'get',
url: 'rest/exam_question_categories?path=cd.root&order=name',
adaptor:
'const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet tops = payload.data.items.filter(x => x.parent === null)\r\nreturn {\r\n ...payload,\r\n data: tops.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}',
},
mode: 'normal',
heightAuto: true,
virtualThreshold: false,
},
],
},
],
closeOnEsc: true,
showCloseButton: true,
size: 'lg',
},
level: 'link',
size: 'md',
icon: 'fa fa-pencil text-info',
tooltip: '修改',
tooltipPlacement: 'top',
className: 'p-r-none p-l-none',
iconClassName: 'pull-left',
id: 'u:467671f595fd',
},
{
type: 'button',
actionType: 'ajax',
confirmText: '确认删除?',
api: {
method: 'delete',
url: 'rest/exam_questions/$id',
},
level: 'link',
icon: 'fa fa-times text-danger',
size: 'md',
tooltip: '删除',
tooltipPlacement: 'top',
iconClassName: 'pull-left',
className: 'p-r-none p-l-none',
id: 'u:9b3cceb15b58',
},
],
label: '操作',
id: 'u:1c467b0d0cdb',
},
],
label: '操作',
placeholder: '-',
width: 100,
id: 'u:2850d5909876',
},
],
visibleOn: '',
perPageAvailable: ['10', '20', 30, 40, 50],
className: '',
headerToolbar: [
{
type: 'bulk-actions',
},
{
type: 'wrapper',
title: '',
body: [
{
type: 'tpl',
tpl: '${org_name}',
inline: true,
name: 'titletpl',
visibleOn: "this.tree && this.tree.split(',').length === 1",
id: 'u:3f915fa4c5c9',
},
{
type: 'button',
label: '',
actionType: 'dialog',
dialog: {
type: 'dialog',
title: '题目信息',
body: [
{
type: 'form',
title: '表单',
api: {
method: 'patch',
url: 'rest/exam_question_categories/$tree',
data: {
name: '$name',
parent: '$parent',
},
},
initApi: 'rest/exam_question_categories/${tree}',
body: [
{
label: '名称',
type: 'input-text',
name: 'name',
mode: 'normal',
id: 'u:d00a7b4108d3',
},
{
type: 'tree-select',
name: 'parent',
label: '上级目录',
mode: 'normal',
onlyChildren: true,
heightAuto: true,
virtualThreshold: false,
source: {
url: 'rest/exam_question_categories?path=cd.root&order=name',
adaptor:
'const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet tops = payload.data.items.filter(x => x.parent === null)\r\nreturn {\r\n ...payload,\r\n data: tops.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}',
method: 'get',
},
id: 'u:28516ae265d1',
},
],
id: 'u:f314267b4b38',
actions: [
{
type: 'submit',
label: 'Submit',
primary: true,
},
],
feat: 'Edit',
dsType: 'api',
},
],
closeOnEsc: true,
showCloseButton: true,
id: 'u:8a446118216b',
actions: [
{
type: 'button',
actionType: 'cancel',
label: 'Cancel',
id: 'u:63e0b9a383ab',
},
{
type: 'button',
actionType: 'confirm',
label: 'confirm',
primary: true,
id: 'u:3df731dbb334',
},
],
closeOnOutside: false,
showErrorMsg: true,
showLoading: true,
draggable: false,
},
level: 'link',
icon: 'fa fa-edit',
iconClassName: '',
visibleOn: "this.tree && this.tree.split(',').length === 1",
reload: 'cg.tree',
id: 'u:0b1f6849e465',
},
{
type: 'button',
label: '',
actionType: 'ajax',
icon: 'fa fa-trash',
level: 'link',
iconClassName: 'text-danger',
confirmText: '确认删除?',
api: {
method: 'delete',
url: 'rest/exam_question_categories/$tree',
},
reload: 'cg.tree',
visibleOn: "this.tree && this.tree.split(',').length === 1",
id: 'u:e972a2b364b2',
},
],
name: 'header',
id: 'u:373ca0cc2ca7',
},
{
type: 'button',
label: '添加分类',
actionType: 'dialog',
align: 'right',
icon: '',
tpl: '内容',
level: 'primary',
dialog: {
type: 'dialog',
title: '添加分类',
body: [
{
type: 'form',
title: '表单',
api: {
method: 'post',
url: 'rest/exam_question_categories',
requestAdaptor:
'return {\r\n ...api,\r\n data: {\r\n ...api.data,\r\n parent: api.data.parent ? api.data.parent : null\r\n }\r\n}',
headers: {
Prefer: 'params=single-object',
},
adaptor: '',
},
body: [
{
label: '名称',
type: 'input-text',
name: 'name',
required: true,
mode: 'normal',
},
{
type: 'tree-select',
label: '上级目录',
name: 'parent',
mode: 'normal',
source: {
method: 'get',
url: 'rest/exam_question_categories?path=cd.root&order=name',
adaptor:
'const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet tops = payload.data.items.filter(x => x.parent === null)\r\nreturn {\r\n ...payload,\r\n data: tops.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}',
},
onlyChildren: true,
heightAuto: true,
virtualThreshold: false,
disabledOn: 'true',
},
],
},
],
closeOnEsc: true,
showCloseButton: true,
},
reload: 'cg.tree',
id: 'u:88fc9975bcf8',
},
{
type: 'button',
label: '题库导入',
level: 'primary',
actionType: 'dialog',
dialog: {
type: 'dialog',
title: '题库导入',
body: [
{
type: 'form',
title: '表单',
controls: [
{
type: 'tree-select',
label: '分类',
name: 'tree',
mode: 'inline',
options: [],
source: {
method: 'get',
url: 'rest/exam_question_categories?path=cd.root&order=name',
adaptor:
'const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet tops = payload.data.items.filter(x => x.parent === null)\r\nreturn {\r\n ...payload,\r\n data: tops.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}',
},
size: 'sm',
initiallyOpen: false,
heightAuto: true,
virtualThreshold: false,
},
{
type: 'examimport',
name: 'import',
mode: 'inline',
label: '请选择要导入的Word',
visibleOn: 'this.tree',
},
{
type: 'table',
name: 'import',
mode: 'normal',
label: '',
columns: [
{
label: '题干',
name: 'title',
quickEdit: {
type: 'input-rich-text',
name: 'title',
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
content: '$content',
},
},
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
mode: 'popOver',
},
type: 'tpl',
width: 400,
placeholder: '-',
},
{
label: '选项',
name: 'options',
type: 'each',
items: {
type: 'tpl',
tpl: '<%= data.key %>. <%= data.label %>',
inline: false,
},
quickEdit: {
type: 'custom-option',
form: {
title: '修改选项',
controls: [
{
type: 'text',
label: '选项',
name: 'key',
disabledOn: 'true',
},
{
name: 'label',
label: '内容',
type: 'input-rich-text',
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
content: '$content',
},
},
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
},
{
type: 'switch',
name: 'is_fixed',
label: '',
option: '是否固定',
optionAtLeft: false,
trueValue: true,
falseValue: false,
},
],
size: 'lg',
},
multiple: true,
btnLabel: '设置选项',
name: 'options',
mode: 'popOver',
},
quickEditEnabledOn:
"this.type === '单选题' || this.type === '多选题'",
placeholder: '-',
},
{
label: '答案',
name: 'answer',
type: 'tpl',
quickEdit: {
type: 'text',
},
},
{
label: '答案解析',
name: 'analysis',
quickEdit: {
type: 'input-rich-text',
name: 'analysis',
saveImmediately: {
api: {
method: 'patch',
url: 'rest/exam_questions/$id',
data: {
content: '$content',
},
},
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
vendor: 'tinymce',
options: {
menubar: 'true',
relative_urls: false,
remove_script_host: true,
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
mode: 'popOver',
},
type: 'tpl',
placeholder: '-',
},
{
label: '难度',
name: 'difficulty',
quickEdit: {
type: 'select',
options: [
{
label: '简单',
value: '简单',
},
{
label: '中等',
value: '中等',
},
{
label: '困难',
value: '困难',
},
],
},
type: 'tpl',
width: 10,
},
{
label: '题型',
name: 'type',
quickEdit: {
type: 'select',
options: [
{
label: '单选题',
value: '单选题',
},
{
label: '多选题',
value: '多选题',
},
{
label: '判断题',
value: '判断题',
},
],
},
type: 'tpl',
width: 50,
},
],
},
],
api: {
method: 'post',
url: 'rest/exam_questions',
data: {
'&': '$import',
},
requestAdaptor:
"return {\r\n ...api,\r\n data: api.data.map(item => {\r\n let content = {}\r\n if (item.options) {\r\n let options = JSON.parse(JSON.stringify(item.options))\r\n let index = options\r\n .findIndex(item => !Object.keys(item).length)\r\n\r\n while (index != -1) {\r\n options.splice(index, 1)\r\n index = options\r\n .findIndex(item => !Object.keys(item).length)\r\n }\r\n\r\n content = {\r\n title: item.title ? item.title : '',\r\n options: options\r\n }\r\n } else {\r\n content = {\r\n title: item.title ? item.title : ''\r\n }\r\n }\r\n if (!item.type) {\r\n return {\r\n content: content,\r\n answer: item.answer ? item.answer : '',\r\n analysis: item.analysis ? item.analysis : '',\r\n difficulty: item.difficulty ? item.difficulty : '',\r\n category: item.category,\r\n type: 'question_unknow',\r\n organization_id: item.organization_id,\r\n is_objective: true\r\n }\r\n } else if(item.type === '单选题') {\r\n return {\r\n content: content,\r\n answer: item.answer ? item.answer : '',\r\n analysis: item.analysis ? item.analysis : '',\r\n difficulty: item.difficulty ? item.difficulty : '',\r\n category: item.category,\r\n type: 'question_single_choice',\r\n organization_id: item.organization_id,\r\n is_objective: true\r\n }\r\n } else if(item.type === '多选题') {\r\n return {\r\n content: content,\r\n answer: item.answer ? item.answer : '',\r\n analysis: item.analysis ? item.analysis : '',\r\n difficulty: item.difficulty ? item.difficulty : '',\r\n category: item.category,\r\n type: 'question_multi_choice',\r\n organization_id: item.organization_id,\r\n is_objective: true\r\n }\r\n } else if(item.type === '判断题') {\r\n return {\r\n content: content,\r\n answer: item.answer ? item.answer : '',\r\n analysis: item.analysis ? item.analysis : '',\r\n difficulty: item.difficulty ? item.difficulty : '',\r\n category: item.category,\r\n type: 'question_true_or_false',\r\n organization_id: item.organization_id,\r\n is_objective: true\r\n }\r\n } else if(item.type === '填空题') {\r\n return {\r\n content: content,\r\n answer: item.answer ? item.answer : '',\r\n analysis: item.analysis ? item.analysis : '',\r\n difficulty: item.difficulty ? item.difficulty : '',\r\n category: item.category,\r\n type: 'question_filling',\r\n organization_id: item.organization_id,\r\n is_objective: false\r\n }\r\n } else if(item.type === '简答题') {\r\n return {\r\n content: content,\r\n answer: item.answer ? item.answer : '',\r\n analysis: item.analysis ? item.analysis : '',\r\n difficulty: item.difficulty ? item.difficulty : '',\r\n category: item.category,\r\n type: 'question_short_answer',\r\n organization_id: item.organization_id,\r\n is_objective: false\r\n }\r\n } else {\r\n return {\r\n content: content,\r\n answer: item.answer ? item.answer : '',\r\n analysis: item.analysis ? item.analysis : '',\r\n difficulty: item.difficulty ? item.difficulty : '',\r\n category: item.category,\r\n type: 'question_unknow',\r\n organization_id: item.organization_id,\r\n is_objective: false\r\n }\r\n }\r\n })\r\n}",
},
target: '',
name: 'form',
actions: [
{
actionType: 'reload',
target: 'recognize',
},
],
},
],
closeOnEsc: true,
showCloseButton: true,
size: 'xl',
},
className: '',
align: 'right',
visibleOn: 'this.tree',
id: 'u:9208bc84a232',
},
{
type: 'button',
label: '添加试题',
level: 'primary',
actionType: 'dialog',
dialog: {
type: 'dialog',
title: '添加试题',
body: [
{
type: 'form',
title: '表单',
api: {
method: 'post',
url: 'rest/exam_questions',
data: {
organization_id: '${centre_id}',
type: '$type',
content: '$content',
answer: '$answer',
analysis: '$analysis',
score: '$score',
difficulty: '$difficulty',
category: '$tree',
is_objective: '$is_objective',
},
requestAdaptor:
'if (api && api.data && api.data.content && api.data.content.options) {\r\n let options = JSON.parse(JSON.stringify(api.data.content.options))\r\n let index = options.findIndex(item => !Object.keys(item).length)\r\n while (index != -1) {\r\n options.splice(index, 1)\r\n index = options.findIndex(item => !Object.keys(item).length)\r\n }\r\n\r\n api.data.content = {\r\n ...api.data.content,\r\n options: options\r\n }\r\n} else if (api && api.data && api.data.type === \'question_true_or_false\') {\r\n api.data.content = {\r\n ...api.data.content,\r\n options: [\r\n { "key": "正确", "label": "正确", "is_fixed": false },\r\n { "key": "错误", "label": "错误", "is_fixed": false }\r\n ]\r\n }\r\n}\r\n\r\nlet pattern = new RegExp("(\\\\.\\\\./){1,6}")\r\napi.data.content.title = api.data.content.title.replace(pattern, "/")\r\n\r\nif (api.data.content.options.length) {\r\n api.data.content.options = api.data.content.options.map(item => {\r\n return {\r\n ...item,\r\n label: item.label.replace(pattern, "/")\r\n }\r\n })\r\n}\r\n\r\napi.data.analysis = api.data.analysis.replace(pattern, "/")\r\n\r\nreturn api',
},
body: [
{
label: '题型',
type: 'select',
name: 'type',
mode: 'normal',
options: [],
checkAll: false,
source: {
method: 'get',
url: 'rest/dicts?select=value:dictkey,label:dictvalue&typecode=eq.019&dictkey=neq.question_unknow',
},
},
{
type: 'formula',
name: 'is_objective',
formula:
"data.type === 'question_single_choice' || data.type === 'question_multi_choice' || data.type === 'question_true_or_false'",
},
{
type: 'hidden',
name: 'is_objective',
},
{
type: 'combo',
label: '',
name: 'content',
mode: 'normal',
multiple: false,
multiLine: true,
joinValues: true,
messages: {},
typeSwitchable: false,
strictMode: true,
value: {
options: [
{
key: 'A',
label: '',
is_fixed: false,
},
{
key: 'B',
label: '',
is_fixed: false,
},
{
key: 'C',
label: '',
is_fixed: false,
},
{
key: 'D',
label: '',
is_fixed: false,
},
],
},
visibleOn:
"this.type === 'question_single_choice' || this.type === 'question_multi_choice'",
clearValueOnHidden: true,
items: [
{
type: 'input-rich-text',
label: '题干',
name: 'title',
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
mode: 'normal',
},
{
label: '选项配置',
name: 'options',
type: 'custom-option',
form: {
title: '修改选项',
controls: [
{
type: 'text',
label: '选项',
name: 'key',
disabledOn: 'true',
},
{
name: 'label',
label: '内容',
type: 'input-rich-text',
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
mode: 'normal',
},
{
type: 'switch',
name: 'is_fixed',
label: '',
option: '是否固定',
optionAtLeft: false,
trueValue: true,
falseValue: false,
},
],
size: 'lg',
},
multiple: true,
btnLabel: '设置选项',
},
],
},
{
type: 'combo',
name: 'content',
label: '',
mode: 'normal',
value: '',
multiple: false,
multiLine: true,
joinValues: true,
messages: {},
typeSwitchable: false,
strictMode: true,
visibleOn:
"this.type === 'question_true_or_false' || this.type === 'question_filling' || this.type === 'question_short_answer'",
clearValueOnHidden: true,
items: [
{
type: 'input-rich-text',
label: '题干',
name: 'title',
vendor: 'tinymce',
options: {
menubar: 'true',
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
mode: 'normal',
},
],
},
{
type: 'input-text',
label: '答案',
name: 'answer',
mode: 'normal',
},
{
type: 'input-rich-text',
label: '答案解析',
name: 'analysis',
mode: 'normal',
receiver: {
method: 'post',
url: 'storage/v1/object/exam',
adaptor: '',
data: null,
requestAdaptor: '',
},
vendor: 'tinymce',
options: {
menubar: 'true',
relative_urls: false,
remove_script_host: true,
height: 400,
plugins:
'advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking table emoticons template paste help',
toolbar:
'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | help',
},
},
{
type: 'input-number',
label: '分数',
name: 'score',
mode: 'normal',
value: 1,
},
{
type: 'select',
label: '难易程度',
name: 'difficulty',
mode: 'normal',
options: [
{
label: '简单',
value: '简单',
},
{
label: '中等',
value: '中等',
},
{
label: '困难',
value: '困难',
},
],
checkAll: false,
},
{
type: 'tree-select',
label: '类别',
name: 'tree',
options: [],
mode: 'normal',
source: {
method: 'get',
url: 'rest/exam_question_categories?path=cd.root&order=name',
adaptor:
'const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet tops = payload.data.items.filter(x => x.parent === null)\r\nreturn {\r\n ...payload,\r\n data: tops.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}',
},
initiallyOpen: false,
heightAuto: true,
virtualThreshold: false,
},
],
},
],
closeOnEsc: true,
showCloseButton: true,
size: 'lg',
},
visibleOn: 'this.tree',
align: 'right',
id: 'u:79a6cf04b4d0',
},
{
type: 'button',
label: '题库模板示例',
onEvent: {
click: {
actions: [
{
args: {
url: '/download/题库模板参考.docx',
},
actionType: 'url',
},
],
weight: 0,
},
},
level: 'success',
icon: 'fa fa-download',
align: 'right',
id: 'u:06075e8d295a',
},
{
type: 'button',
label: '题库模板说明',
onEvent: {
click: {
actions: [
{
args: {
url: '/download/题库模板说明.docx',
},
actionType: 'url',
},
],
weight: 0,
},
},
level: 'success',
icon: 'fa fa-download',
align: 'right',
id: 'u:2f4c3be56c4f',
},
],
footerToolbar: [
{
type: 'pagination',
},
{
type: 'switch-per-page',
},
{
type: 'statistics',
},
],
bulkActions: [
{
label: '批量移动',
type: 'button',
actionType: 'dialog',
dialog: {
type: 'dialog',
title: '移动到分类',
body: [
{
type: 'form',
title: '表单',
api: {
method: 'patch',
url: 'rest/exam_questions?id=in.(${ids})',
data: {
category: '$category',
},
requestAdaptor:
'return {\r\n ...api,\r\n data: {\r\n category: api.data.category ? api.data.category : null\r\n }\r\n}',
},
body: [
{
type: 'tree-select',
label: '分类',
name: 'category',
options: [],
source: {
method: 'get',
url: 'rest/exam_question_categories?path=cd.root&order=name',
adaptor:
'const recursive = id => {\r\n let nodes = payload.data.items.filter(x => {\r\n return x.parent === id\r\n })\r\n return nodes.map(item => {\r\n return {\r\n ...item,\r\n label: item.name,\r\n value: `${item.id}`,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}\r\nlet tops = payload.data.items.filter(x => x.parent === null)\r\nreturn {\r\n ...payload,\r\n data: tops.map(item => {\r\n return {\r\n label: item.name,\r\n value: item.id,\r\n children: recursive(item.id)\r\n }\r\n })\r\n}',
},
mode: 'normal',
heightAuto: true,
virtualThreshold: false,
},
],
},
],
closeOnEsc: true,
showCloseButton: true,
},
id: 'u:1900a8775c6a',
},
{
label: '批量删除',
actionType: 'ajax',
api: {
method: 'delete',
url: 'rest/exam_questions?id=in.(${ids})',
data: null,
},
confirmText: '确认删除?',
type: 'button',
id: 'u:b24dc3837adb',
},
],
md: 9,
columnsTogglable: false,
filter: null,
quickSaveItemApi: '',
hideQuickSaveBtn: true,
id: 'u:d5ccedbd35f2',
},
],
title: '',
messages: {},
bodyClassName: '',
definitions: {
options: {
type: 'combo',
multiple: true,
multiLine: true,
controls: [
{
type: 'group',
controls: [
{
label: '选项',
name: 'key',
type: 'text',
},
{
label: '内容',
name: 'label',
type: 'text',
},
{
type: 'switch',
option: '开关',
name: 'is_fixed',
label: '是否固定',
},
],
label: false,
},
],
},
},
id: 'u:757690c834b6',
asideResizor: false,
pullRefresh: {
disabled: true,
},
};
export { schema };