/** 资质考试 */ //import { AlignLeftOutlined, PlusOutlined } from '@ant-design/icons'; import { Switch, Button, Card, Col, List, Menu, Progress, Row, Typography, Space, Divider, Radio, Checkbox, Tag, Dropdown, Upload, Modal, Form, Input, message, Popconfirm } from 'antd'; import { PageContainer } from '@ant-design/pro-layout'; //import { useRequest } from 'umi'; //import { queryFakeList } from './service'; //import type { CardListItemDataType } from './data'; import styles from './style.less'; //import SubMenu from 'antd/lib/menu/SubMenu'; //import ProCard from '@ant-design/pro-card'; import ProList from '@ant-design/pro-list'; import type { ReactText } from 'react'; import { useEffect, useRef, useState } from 'react'; import { PlusOutlined, DeleteOutlined, DownloadOutlined, UploadOutlined, EditOutlined, EyeOutlined, EyeInvisibleOutlined, DownOutlined, UserOutlined } from '@ant-design/icons'; import { exportQuestionTemplate, queryQuestionById, queryQuestionList, queryQuestionType, removeQuestion, saveQuestion } from './service'; import { useParams, useRequest, history, useRouteMatch } from 'umi'; import { queryCourseListByTag, queryCourseView, queryTagList } from '@/pages/course/option/service'; import ProForm, { BetaSchemaForm, ProFormCheckbox, ProFormList, ProFormRadio, ProFormSelect, ProFormText } from '@ant-design/pro-form'; import type { DataItem } from '../dashboard/analysis/data'; import type { ActionType, ProColumns } from '@ant-design/pro-table'; import ProFormRichEdit from '../course/subject/components/ProFormRichEdit'; import type { TableListItem } from '../course/option/data'; import AnswersSelector from './components/AnswersEditor'; //const { Paragraph } = Typography; const { Text, Link } = Typography; const labels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']; const parsingMap = new Map() console.log('first'); /** * 添加试题 * * @param fields */ const handleAdd = async (fields: TableListItem) => { const hide = message.loading('正在添加'); try { await saveQuestion({ ...fields }); hide(); message.success('添加成功'); return true; } catch (error) { hide(); message.error('添加失败请重试!'); return false; } }; /** * 编辑试题 * * @param fields */ const handleUpdate = async (fields: TableListItem) => { const hide = message.loading('正在保存'); try { await saveQuestion({ ...fields }); hide(); message.success('保存成功'); return true; } catch (error) { hide(); message.error('保存失败请重试!'); return false; } }; /** * 删除试题 * * @param selectedRows */ const handleRemove = async (selectedRows: TableListItem[]) => { console.log('selectedRows--', selectedRows) const hide = message.loading('正在删除'); if (!selectedRows) return true; try { const { code, msg } = await removeQuestion({ key: selectedRows.map((row) => row.key), }); hide(); if (code === 2000) { message.success('删除成功,即将刷新'); } else { message.warning(msg); } return true; } catch (error) { hide(); message.error('删除失败,请重试'); return false; } }; const QuestionBank = () => { const match = useRouteMatch(); console.log('match', match); const type = history.location.pathname === '/questionbank/attestation' ? 1 : 0; // 题库类型 const actionRef = useRef(); const formRef = useRef(); const [questionType, setQuestionType] = useState([]); const [parsing, setParsing] = useState(); const [createModalVisible, handleCreateModalVisible] = useState(false); const [updateModalVisible, handleUpdateModalVisible] = useState(false); const [selectedRowsState, setSelectedRows] = useState([]); const [currentRow, setCurrentRow] = useState(); const [expandedDescRowKeys, setExpandedDescRowKeys] = useState([]); // 展开解析设置 const [addType, setAddType] = useState({ name: '', value: '' }); const [pageNumber, setPageNumber] = useState(1) //const [answertrueValues, setAnswertrueValues] = useState(); // 编辑试题答案项值 //const [options, setOptions] = useState([]); // 设置当前选项, 用于删除选项时判断 /** 表单项定义 */ const columns: ProColumns[] = [ { title: '标签', valueType: 'select', dataIndex: 'tag_ids', sorter: false, hideInTable: true, hideInForm: false, hideInSearch: true, fieldProps: { mode: "multiple" }, formItemProps: { rules: [ { required: true, message: '请填标签', }, ] }, /* renderFormItem:(item,{ type, defaultRender, formItemProps, fieldProps, ...rest },form)=>{ return defaultRender },*/ //renderText: (val: string) => `${val}`, request: async () => { const { data: Items } = await queryTagList({}); console.log('queryTagList...') const tags = [] for (let i = 0; i < Items.length; i++) { tags.push({ label: Items[i]?.tag_name, value: Items[i]?.tag_id }) } console.log(tags, 'tags:::'); return tags; }, }, { title: '课程', valueType: 'select', dataIndex: 'course_id', sorter: false, hideInTable: false, hideInForm: false, hideInSearch: true, fieldProps: { //mode: "multiple" }, formItemProps: { rules: [ { required: true, message: '请选择课程', }, ] }, renderText: (val: string) => `${val}`, dependencies: ['tag_ids'], request: async (params) => { const { tag_ids } = params; const { data: Items } = await queryCourseListByTag({ tag_ids: tag_ids?.toString() }); console.log('queryCourseListByTag...') const courses = [] for (let i = 0; i < Items?.length; i++) { courses.push({ label: Items[i]?.course_name, value: Items[i]?.course_id }) } console.log(courses, 'courses:::'); return courses; }, }, { title: '题干', dataIndex: 'question_stem', valueType: 'text', hideInTable: false, hideInDescriptions: false, hideInForm: false, hideInSearch: true, fieldProps: { maxLength: 50 }, formItemProps: { rules: [ { required: true, message: '请填写题干内容', }, ] }, }, { title: '选项', dataIndex: 'answers', valueType: 'text', sorter: false, hideInTable: false, hideInForm: false, hideInSearch: true, renderFormItem: (item, { defaultRender, ...rest }, form) => ( ), formItemProps: { rules: [ { required: true, message: '请填写选项', }, ] }, }, { title: '正确答案', dataIndex: 'answertrue', valueType: 'text', sorter: false, hideInTable: false, hideInForm: false, hideInSearch: true, dependencies: ['answers'], renderFormItem: (item, { defaultRender, ...rest }, form) => { console.log('正确答案...', form.getFieldValue('answers')) // 关联长度变化及编辑回显 console.log('edit answertrue11', item) console.log('form::::::', form.getFieldValue('answertrue')) console.log('rest', rest) console.log('question_type:::', form.getFieldValue('question_type')) // 获取选项长度 const len = form.getFieldValue('answers')?.length || 2; const opts = [] for (let i = 0; i < len; i++) { opts.push(labels[i]) } if (Number(form.getFieldValue('question_type')) === 0) { console.log('my type', Number(form.getFieldValue('question_type'))) } else { console.log('====0') } console.log('answers??', form.getFieldValue('answers')?.length) console.log('addType?.value', addType?.value) // 0 单选 1 多选 2 判断 return ((addType?.value === 0 || addType?.value === 2) || (Number(form.getFieldValue('question_type')) === 0) || Number(form.getFieldValue('question_type')) === 2) ? : }, formItemProps: { rules: [ { required: true, message: '请填写答案', }, ] }, }, { title: '解析', dataIndex: 'parsing', valueType: 'textarea', sorter: false, hideInTable: false, hideInForm: false, hideInSearch: true, formItemProps: { rules: [ { required: true, message: '请填写试题解析', }, { validator: (rule, value) => { console.log("表单:", value, value.replace(/(^\s*)|(\s*$)/g, ""), "|") if (value.replace(/(^\s*)|(\s*$)/g, "") === "") { return Promise.reject('请填写试题解析') } else { return Promise.resolve() } } } ] }, renderText: (val: string) => (
), // renderFormItem: (item, { defaultRender, ...rest }, form) => ( // // ), }, ] /** 获取题型 */ const { data } = useRequest(() => { return queryQuestionType(); }, { formatResult: (result) => { return result.list; } }); /* const { data: template } = useRequest(() => { return exportQuestionTemplate(); }); */ useEffect(() => { setQuestionType(data || []); return () => { /** 退出当前页面清空Map */ parsingMap.clear(); } }, [data]); //saveQuestion return ( style={{ minWidth: 1180 }} rowKey='id' itemLayout="vertical" actionRef={actionRef} rowClassName='questionbank-list-item' pagination={{ defaultPageSize: 10, showSizeChanger: false, showQuickJumper: true }} search={{ labelWidth: 120, }} toolBarRender={() => { const menuItems = []; console.log('toolBarRender', questionType); if (questionType?.length > 0) { console.log('push'); questionType.forEach((item: { code: number, name: string }) => { menuItems.push({item?.name}) }) } const menu = ( { console.log('menu11', value); console.log('menu11', value.key); console.log('menuquestionType',); setAddType({ name: questionType[Number(value?.key)]?.name, value: Number(value?.key) }); handleCreateModalVisible(true); }}> {menuItems} ); return [ , , , { console.log('file status', file?.status) console.log('file event', event) if (file?.status === 'done' && file?.response?.success === true) { message.success(file?.response?.info); actionRef.current?.reload(); // 上传完成刷新 } if (file?.status === 'done' && file?.response?.success === false) { message.error(file?.response?.error_list?.toString()); //actionRef.current?.reload(); // 上传完成刷新 } if (file?.status === 'error') { message.error('批量上传失败'); } }} > , ]; }} onRow={(record: any) => { /* return { onMouseEnter: () => { console.log(record); }, onClick: () => { console.log(record); }, };*/ }} rowKey="id" headerTitle={false} tooltip={false} request={async (value) => { console.log('value', value) /* const { create_time } = value; if (create_time) { value.begin_time = create_time[0] value.end_time = create_time[1] }*/ const questions = await queryQuestionList({ ...value, type: type, page_number: value?.current || 1, page_size: value?.pageSize, }); // 课程名称及课程标签 console.log('data', questions); const data = [] for (let i = 0; i < questions?.table_List.length; i++) { const { data: course } = await queryCourseView({ course_id: questions?.table_List[i]?.course_id }); data[i] = { ...questions?.table_List[i], course_name: course?.course_name, tag_name: course?.tag_name, }; } console.log('questions?.pageNumber', actionRef.current) console.log('questions?.totalRow', questions?.totalRow) setPageNumber(questions?.pageNumber) return { current: Number(questions?.pageNumber), data: data, pageSize: Number(questions?.pageSize), success: true, total: Number(questions?.totalRow) || 10, }; }} //dataSource={dataSource} rowSelection={{ onChange: (_, selectedRows) => { setSelectedRows(selectedRows); }, }} // grid={{ gutter: 16, column: 1 }} showActions="always" showExtra="always" metas={{ title: { title: '题干', search: false, dataIndex: 'question_stem', render: (text: React.ReactNode, record: T, index: number) => ({record?.id} {text}), }, avatar: { title: '题型', search: false, dataIndex: 'question_type', valueType: 'text', render: (text: React.ReactNode, record: T, index: number) => { const type = questionType?.filter((item, idx, self) => { console.log('FFFF', item, idx, self); return item?.code === record.question_type }); console.log('type', type?.name); console.log('type', type?.name); console.log('questionType::::', questionType); return `${(pageNumber - 1) * actionRef.current?.pageInfo?.pageSize + index + 1}. [${type[0]?.name}]` }, }, description: { search: false, dataIndex: 'answers', valueType: 'checkbox', render: (text: React.ReactNode, record: T, index: number) => { console.log('description answers', record) return ( { console.log('item', item); return ( {`${(record?.question_type === 2) ? ['A', 'B'][key] : labels[key]}. ${item?.answer}`} ) }} /> ); }, }, subTitle: { search: false }, content: { search: false, render: (text: React.ReactNode, record: T, index: number) => { let answer = ''; const answertrue = record?.answertrue?.split(','); console.log('answertrue', answertrue) /** 题型 */ switch (record?.question_type) { case 0: // 单选 case 1: // 多选 answer = labels?.filter((x, idx, self) => `${answertrue[idx]}` === `1`).toString() break; case 2: // 判断 answer = ['A', 'B']?.filter((x, idx, self) => `${answertrue[idx]}` === `1`).toString() break; } console.log('expandedDescRowKeys', expandedDescRowKeys) if (expandedDescRowKeys?.indexOf(record.id) > -1) { return ( 正确答案: {answer} 【解析】:
); } else { return ( 正确答案: {answer} ) } }, }, actions: { search: false, cardActionProps: 'extra', render: (text: React.ReactNode, record: T, _index: number) => { let eye if (expandedDescRowKeys?.indexOf(record.id) > -1) { eye = <> 隐藏解析 } else { eye = <> 查看解析 } return ( 创建时间:{record?.create_time} 标签:{record?.tag_name} 课程:{record?.course_name} { console.log('record', record) setCurrentRow(record); handleUpdateModalVisible(true) return false; }} target="_blank" rel="noopener noreferrer" key="link"> 编辑 { const success = await handleRemove([{ key: record?.id }]); // 调用批量删除函数(如果接口不支持批量需要在service中处理) if (success) { // handleModalVisible(false); if (actionRef.current) { setSelectedRows([]); actionRef.current?.reloadAndRest(); } } }} > 删除 { if (expandedDescRowKeys?.indexOf(record.id) > -1) { const descRowKeys = expandedDescRowKeys?.filter((item, idx, self) => { console.log('FFFF', item, idx, self); return item !== record.id }); setExpandedDescRowKeys([...descRowKeys]); } else { const { bean } = await queryQuestionById({ id: record.id }) parsingMap.set(bean.id, bean.parsing) setParsing(parsingMap); console.log('parsing', parsing); setExpandedDescRowKeys([...expandedDescRowKeys, record.id]); } console.log('record id:', record.id); console.log('expandedDescRowKeys......', expandedDescRowKeys) }} > {eye} ) } }, /** 搜索定义 */ question_type: { title: '题型', valueType: 'select', search: true, dataIndex: 'question_type', request: async () => { const { list: Items } = await queryQuestionType(); console.log('queryQuestionType...', Items) const types = [] for (let i = 0; i < Items.length; i++) { types.push({ label: Items[i]?.name, value: Items[i]?.code }) } console.log(types, 'types:::'); return types; }, }, tags: { title: '标签', search: true, valueType: 'select', dataIndex: 'tag_ids', fieldProps: { //mode: "multiple" }, request: async () => { const { data: Items } = await queryTagList({}); console.log('queryTagList...') const tags = [] for (let i = 0; i < Items.length; i++) { tags.push({ label: Items[i]?.tag_name, value: Items[i]?.tag_id }) } console.log(tags, 'tags:::'); return tags; }, }, course_id: { title: '课程', search: true, valueType: 'select', dataIndex: 'course_id', fieldProps: { //mode: "multiple" }, dependencies: ['tag_ids'], request: async (params) => { const { tag_ids } = params; const { data: Items } = await queryCourseListByTag({ tag_ids: tag_ids?.toString() }); console.log('queryCourseListByTag...') const courses = [] for (let i = 0; i < Items?.length; i++) { courses.push({ label: Items[i]?.course_name, value: Items[i]?.course_id }) } console.log(courses, 'courses:::'); return courses; } }, question_stem: { title: '搜索', // 题干 search: true, dataIndex: 'question_stem', valueType: 'text', fieldProps: { placeholder: '请输入关键字' }, }, create_time: { title: '创建时间', search: true, dataIndex: 'create_time', valueType: 'dateRange', fieldProps: { placeholder: ['开始时间', '结束时间'] }, }, }} /> { setAddType({ name: '', value: '' }); // 还原题型选择 handleCreateModalVisible(false); }} footer={null} > formRef={formRef} layout="horizontal" layoutType="Form" labelCol={{ span: 8 }} wrapperCol={{ span: 12 }} onValuesChange={() => { //console.log('formRef', formRef.current.getFieldInstance('answertrue')) //console.log('formRef.current', formRef.current.getFieldsValue(['answertrue'])) //console.log('v', value) //console.log('answers', formRef?.current?.getFieldValue('answers')) const answerTrue = formRef?.current?.getFieldValue('answertrue'); let fixed_answertrue; // 如果正确答案为字符串(单选 / 判断) if (typeof answerTrue === 'string') { console.log('string.....') fixed_answertrue = labels.indexOf(answerTrue) < (formRef?.current?.getFieldValue('answers')?.length || 0) ? answerTrue : undefined; } else if (answerTrue?.length > 0) { fixed_answertrue = answerTrue?.filter((item, key) => { return labels.indexOf(item) < (formRef?.current?.getFieldValue('answers')?.length || 0) }) } console.log('answerTrue', answerTrue) /* const */ //console.log('fixed', fixed_answertrue) formRef?.current?.setFieldsValue({ answertrue: fixed_answertrue }) }} onFinish={async (values: any) => { //console.log('formRef.current', formRef.current.getFieldsValue(['answertrue'])) console.log(values); return // 表单处理 console.log('columns:', columns); console.log('values:', values); const opts = []; values?.answers?.forEach((item, key) => { // const isTrue = (values?.answertrue.toString().indexOf(labels[key]) !== -1) ? 1 : 0; // 判断是否为正确答案 opts.push({ answer: item, is_true: isTrue }) }) const success = await handleAdd({ ...values, type: type, // 必填,0-常规题,1-资质考试题 answers: JSON.stringify(opts), question_type: addType.value, // subject_id: params?.id || 0, }); console.log('123') if (success) { handleCreateModalVisible(false); actionRef.current?.reload(); } }} submitter={{ render: (props, doms) => ( {doms} ), }} // action = '' title="新建" columns={columns} /> { setAddType({ name: '', value: '' }); // 还原题型选择 handleUpdateModalVisible(false); }} footer={null} > layout="horizontal" layoutType="Form" labelCol={{ span: 8 }} wrapperCol={{ span: 12 }} request={() => { // 编辑数据初始化 console.log('currentRow##', currentRow) //answers:currentRow?.answers.map((item)=>(item.answer)) const answertrue = currentRow?.answertrue?.split(','); console.log('answertrue,,,', answertrue) const answerTrueData = labels?.filter((x, idx, self) => (`${answertrue[idx]}` === '1')) console.log('$$$', answerTrueData) const trueData = Number(currentRow?.question_type) === 1 ? answerTrueData : answerTrueData[0] // 处理单选和判断 const tag_ids = currentRow?.tag_ids.split(',') return { ...currentRow, answers: currentRow?.answers.map((item) => (item.answer)), answertrue: trueData, tag_ids: tag_ids.map(item => Number(item)) } }} onFinish={async (values: any) => { // 表单处理 console.log('columns:', columns); console.log('values:', values); const opts = []; values?.answers?.forEach((item, key) => { const is_true = values?.answertrue.indexOf(labels[key]) > -1 ? 1 : 0; opts.push({ answer: item, is_true: is_true || 0 }) // 循环选项 }) const success = await handleUpdate({ ...currentRow, ...values, type: type, // 必填,0-常规题,1-资质考试题 answers: JSON.stringify(opts), tag_ids: values?.tag_ids?.toString(), // 标签ids //question_type: currentRow?.question_type, // 题型 // subject_id: params?.id || 0, }); if (success) { handleUpdateModalVisible(false); actionRef.current?.reloadAndRest?.(); } }} submitter={{ render: (props, doms) => ( {doms} ), }} // action = '' title="编辑" columns={columns} /> ); }; export default QuestionBank;