xialiang 3 years ago
commit b9e71699b8

@ -149,6 +149,7 @@ const CourseList: React.FC = () => {
hideInTable: false,
hideInForm: false,
hideInSearch: true,
width: 100,
renderText: (val: string) => `${val}`,
formItemProps: {
// 参照 https://ant.design/components/form-cn/#Rule
@ -284,6 +285,7 @@ const CourseList: React.FC = () => {
sorter: false,
hideInForm: true,
hideInSearch: true,
width: 100,
renderText: (val: string) => `${val}M`,
formItemProps: {
// 参照 https://ant.design/components/form-cn/#Rule
@ -309,6 +311,7 @@ const CourseList: React.FC = () => {
title: '操作',
dataIndex: 'option',
valueType: 'option',
width: 150,
render: (_dom: any, record: React.SetStateAction<TableListItem | undefined>) => [
<a
key="detail"

@ -28,6 +28,29 @@ export async function queryCourseList(
});
}
/** 获取课程列表(不分页) GET /dsideal_yy/ypt/careerTraining/course/list */
export async function queryCourseListByTag(
params: {
tag_ids?: string; // 过滤标签
},
options?: Record<string, any>,
) {
return request<{
data: TableListItem[];
/** 列表的内容总数 */
total_row?: number;
/** 页面的容量 */
page_size?: number;
success?: boolean;
}>('/dsideal_yy/ypt/careerTraining/component/listCourseByTag', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/**
*
@ -69,19 +92,17 @@ export async function removeCourse(data: { key: number[] }, options?: Record<str
}
/** 查看课程仅仅获取课程详情不标记浏览量GET /dsideal_yy/ypt/careerTraining/course/view */
export async function queryCourseView(data: Record<string, any>, options?: Record<string, any>) {
return request<TableListItem>('/dsideal_yy/ypt/careerTraining/course/view', {
data,
method: 'POST',
requestType: 'form',
...(options || {}),
export async function queryCourseView(params: {
course_id: number;
//count: number;
}): Promise<{ data: { list: any } }> {
return request('/dsideal_yy/ypt/careerTraining/course/view', {
params,
});
}
/** 新建/修改主题 POST /dsideal_yy/ypt/careerTraining/subject/saveSubject */
export async function saveSubject(data: Record<string, any>, options?: Record<string, any>) {
return request<TableListItem>('/dsideal_yy/ypt/careerTraining/subject/saveSubject', {

@ -6,6 +6,7 @@
}
.edit-tag {
user-select: none;
margin: 2px;
}
.tag-input {
width: 78px;

@ -3,7 +3,7 @@ import React from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css'
const ProFormRichEdit = (props) => {
const ProFormRichEdit = (props: any) => {
return (
<ProForm.Item {...props}>
<ReactQuill placeholder={props.placeholder} {...props.fieldProps} />

@ -1,5 +1,5 @@
import { PlusOutlined } from '@ant-design/icons';
import { Button, message, Input, Drawer } from 'antd';
import { Button, message, Image, Modal, } from 'antd';
import React, { useState, useRef } from 'react';
import { history } from 'umi';
import { PageContainer, FooterToolbar } from '@ant-design/pro-layout';
@ -10,14 +10,79 @@ import type { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import ProDescriptions from '@ant-design/pro-descriptions';
import type { FormValueType } from './components/UpdateForm';
import UpdateForm from './components/UpdateForm';
import { copySubject, addSubject, updateSubject, removeSubject, querySubjectList } from './service';
import { copySubject, addSubject, updateSubject, removeSubject, querySubjectList, queryListChapterBySubject } from './service';
import type { TableListItem, TableListPagination } from './data';
import { queryCourseListByTag } from '../option/service';
/** 章节列表项定义 */
const chapterColumns: ProColumns<TableListItem>[] = [
{
title: '序号',
key: 'index',
valueType: 'indexBorder',
width: 48,
},
{
title: '章节名称',
dataIndex: 'chapter_name',
valueType: 'text',
hideInTable: false,
hideInDescriptions: false,
hideInForm: false,
hideInSearch: true,
},
{
title: '简介',
dataIndex: 'chapter_describe',
valueType: 'textarea',
sorter: false,
hideInTable: false,
hideInForm: false,
hideInSearch: true,
renderText: (val: string) => (<div dangerouslySetInnerHTML={{__html: val}} />),
},
{
title: '课程',
valueType: 'select',
dataIndex: 'course_ids',
sorter: false,
hideInTable: false,
hideInForm: false,
hideInSearch: true,
fieldProps: {
mode: "multiple"
},
renderText: (val: string) => `${val}`,
request: async (params) => {
const {tags} = params;
const { data: Items } = await queryCourseListByTag({tag_ids: tags?.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: 'course_minutes',
valueType: 'text',
sorter: false,
hideInTable: false,
hideInForm: true,
hideInSearch: true,
renderText: (val: string) => `${val}`,
},
];
/**
*
*
* @param fields
*/
const handleAdd = async (fields: TableListItem) => {
const hide = message.loading('正在添加');
@ -81,14 +146,14 @@ const handleRemove = async (selectedRows: TableListItem[]) => {
const TableList: React.FC = () => {
/** 新建窗口的弹窗 */
const [createModalVisible, handleModalVisible] = useState<boolean>(false);
/** 分布更新窗口的弹窗 */
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const [showDetail, setShowDetail] = useState<boolean>(false);
const [detailModalVisible, handleDetailModalVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const actionChapterRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<TableListItem>();
const [selectedRowsState, setSelectedRows] = useState<TableListItem[]>([]);
/** 国际化配置 */
const columns: ProColumns<TableListItem>[] = [
{
@ -103,13 +168,17 @@ const TableList: React.FC = () => {
},
{
title: '图片',
dataIndex: 'name',
tip: '主题名称是唯一的 key',
tip: '主题封面',
hideInSearch: true,
render: (dom, entity) => {
// console.log(entity, 'entity')
return (
<img src={entity.attachment_json.url} style={{ width: '150px', height: '75px' }} />
<Image
src={`/dsideal_yy/html/${entity.attachment_json.url}`}
width={300}
height={200}
fallback="data:image/png;base64,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"
style={{ border: '1px solid #f0f0f0', overflowY: 'hidden' }} />
);
},
},
@ -127,7 +196,7 @@ const TableList: React.FC = () => {
dataIndex: 'subject_describe',
valueType: 'textarea',
hideInSearch: true,
width: "60%",
width: "*",
render: (dom, entity) => {
return (
@ -142,17 +211,21 @@ const TableList: React.FC = () => {
},
{
title: '信息',
dataIndex: 'total_course_minutes',
sorter: true,
dataIndex: 'total_course_minutes',
sorter: false,
hideInSearch: true,
width: 200,
render: (dom, entity) => {
if(entity.b_use === 0){
return '待发布'
}
return (
<div>
{entity.total_chapter_number}<br />
{entity.total_course_number}<br />
{entity.total_course_minutes}
{entity.total_chapter_number} <br />
{entity.total_course_number} <br />
{entity.total_course_minutes}
</div>
);
@ -169,9 +242,22 @@ const TableList: React.FC = () => {
title: '操作',
dataIndex: 'option',
valueType: 'option',
width: 200,
render: (_, record) => [
<a
key="config"
key="detail"
onClick={() => {
setCurrentRow(record);
if (actionChapterRef.current) {
actionChapterRef.current.reload();
}
handleDetailModalVisible(true);
}}
>
</a>,
<a
key="edit"
onClick={() => {
history.push(`/course/subject/step/update/${record.subject_id}`)
}}
@ -181,9 +267,11 @@ const TableList: React.FC = () => {
<a
key="copyAlert"
onClick={async () => {
const hide = message.loading('正在复制');
// console.log(e, record, 'copy')
const success = await copySubject({ subject_id: record.subject_id });
if (success) {
hide();
// handleModalVisible(false);
if (actionRef.current) {
actionRef.current.reload();
@ -297,7 +385,7 @@ const TableList: React.FC = () => {
}}
>
<ProFormText
Subjects={[
rules={[
{
required: true,
message: '主题名称为必填项',
@ -308,6 +396,69 @@ const TableList: React.FC = () => {
/>
<ProFormTextArea width="md" name="desc" />
</ModalForm>
<Modal
title={'主题信息'}
width="50%"
visible={detailModalVisible}
onCancel={() => {
setCurrentRow(undefined); // 设置当前行
handleDetailModalVisible(false);
}}
footer={null}
centered
>
{currentRow?.subject_id && (
<>
<ProDescriptions
layout='horizontal'
column={1}
//actionRef={actionRef}
title={false}
/*
request={async () => {
console.log('step2 主题信息')
return Promise.resolve({
success: true,
data: { id: '这是一段文本', object: '', date: '2020-07-30 08:00', duration: '', grade: 100, through: '>60', learn: '>20 min', times: 2 },
});
}}*/
extra={false}
>
<ProDescriptions.Item dataIndex="id" hideInDescriptions />
<ProDescriptions.Item dataIndex="subject_name" label="主题名称" valueType="text">{currentRow?.subject_name}</ProDescriptions.Item>
<ProDescriptions.Item dataIndex="subject_describe" label="主题介绍" valueType="text">
<div dangerouslySetInnerHTML={{__html: currentRow?.subject_describe}} />
</ProDescriptions.Item>
</ProDescriptions>
<ProTable<TableListItem, TableListPagination>
headerTitle={false}
actionRef={actionChapterRef}
rowKey="chapter_id"
options={false}
search={false}
toolBarRender={false}
request={async (value) => {
const { data } = await queryListChapterBySubject({
subject_id: currentRow?.subject_id,
page_number: value?.current || 1,
page_size: value?.pageSize,
});
return {
current: data?.page_number,
data: data?.list,
pageSize: data?.page_size,
success: true,
total: data?.total_row || 0,
};
}}
// dataSource={list}
columns={chapterColumns}
rowSelection={false}
/>
</>
)}
</Modal>
<UpdateForm
onSubmit={async (value) => {
const success = await handleUpdate(value, currentRow);

@ -1,6 +1,7 @@
// @ts-ignore
/* eslint-disable */
import { request } from 'umi';
import { TableListItem } from '../option/data';
import type { CardListItemDataType } from './data.d';
/** 获取规则列表 GET /api/rule */
@ -102,4 +103,47 @@ export async function querySubjectList(params: {
return request('/dsideal_yy/ypt/careerTraining/subject/listSubject', {
params,
});
}
}
/**
*
* http://10.10.14.252:8080/workspace/myWorkspace.do?projectId=382#6428
* @param params
* @returns
*/
export async function queryListChapterBySubject(params: {
page_number: number; //页码 number 非必填默认为1
page_size: number; // 每页条数 number 非必填默认为10
subject_id: number; //主题id
//count: number;
}): Promise<{ data: { list: CardListItemDataType[] } }> {
return request('/dsideal_yy/ypt/careerTraining/subject/listChapterBySubject', {
params,
});
}
/**
* / POST /dsideal_yy/ypt/careerTraining/course/save
*
*/
export async function saveChapter(data: Record<string, any>, options?: Record<string, any>) {
return request<TableListItem>('/dsideal_yy/ypt/careerTraining/subject/saveChapter', {
data,
method: 'POST',
requestType: 'form',
...(options || {}),
});
}
/**
*
*
*/
export async function commitSubject(data: Record<string, any>, options?: Record<string, any>) {
return request<TableListItem>('/dsideal_yy/ypt/careerTraining/subject/commitSubject', {
data,
method: 'POST',
requestType: 'form',
...(options || {}),
});
}

@ -1,5 +1,5 @@
import React, { useEffect, useRef, useState } from 'react';
import { history } from 'umi';
import { history, useParams, useRequest } from 'umi';
import type { ProFormInstance } from '@ant-design/pro-form';
import { BetaSchemaForm, ProFormRadio, ProFormUploadButton } from '@ant-design/pro-form';
import ProForm, {
@ -12,7 +12,7 @@ import ProForm, {
ProFormDateRangePicker,
} from '@ant-design/pro-form';
import ProCard from '@ant-design/pro-card';
import { Button, Checkbox, Col, Divider, List, Menu, message, Modal, Radio, Row, Space, Typography } from 'antd';
import { Button, Checkbox, Col, Divider, List, Menu, message, Modal, Radio, Result, Row, Space, Typography } from 'antd';
import { PageContainer } from '@ant-design/pro-layout';
import ProDescriptions from '@ant-design/pro-descriptions';
import styles from './index.less'
@ -23,7 +23,11 @@ import ProFormRichEdit from '../components/ProFormRichEdit';
import type { ActionType, ProColumns } from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import type { TableListItem, TableListPagination } from '../../option/data';
import { getSubjectInfo, saveSubject } from '../../option/service';
import { queryCourseList, queryCourseListByTag, queryTagList, saveSubject } from '../../option/service';
import { commitSubject, getSubjectInfo, queryListChapterBySubject, saveChapter } from '../service';
import { v4 as uuidv4 } from 'uuid';
/** 列表项定义 */
const columns: ProColumns<TableListItem>[] = [
@ -35,32 +39,108 @@ const columns: ProColumns<TableListItem>[] = [
},
{
title: '章节名称',
dataIndex: 'course_name',
dataIndex: 'chapter_name',
valueType: 'text',
hideInTable: false,
hideInDescriptions: false,
hideInForm: false,
hideInSearch: true,
formItemProps: {
rules: [
{
required: true,
message: '请填写章节名称',
},
]
},
},
{
title: '简介',
dataIndex: 'lecture_teacher',
valueType: 'text',
dataIndex: 'chapter_describe',
valueType: 'textarea',
sorter: false,
hideInTable: false,
hideInForm: false,
hideInSearch: true,
formItemProps: {
rules: [
{
required: true,
message: '请填写章节简介',
},
]
},
renderText: (val: string) => (<div dangerouslySetInnerHTML={{__html: val}} />),
renderFormItem: (item, { defaultRender, ...rest }, form) => (
<ProFormRichEdit
name="chapter_describe"
label=""
width="xl"
// tooltip="最长为 6 位汉字,需要与考生身份证一致"
placeholder="请输入介绍"
// rules={[{ required: true }]}
value="锦书"
// disabled
/>
),
},
{
title: '标签',
valueType: 'select',
dataIndex: 'tags',
sorter: false,
hideInTable: true,
hideInForm: false,
hideInSearch: true,
fieldProps: {
mode: "multiple"
},
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: 'textarea',
dataIndex: 'course_describe',
valueType: 'select',
dataIndex: 'course_ids',
sorter: false,
hideInTable: false,
hideInForm: false,
hideInSearch: true,
fieldProps: {
mode: "multiple"
},
formItemProps: {
rules: [
{
required: true,
message: '请填选择课程',
},
]
},
renderText: (val: string) => `${val}`,
dependencies: ['tags'],
request: async (params) => {
const {tags} = params;
const { data: Items } = await queryCourseListByTag({tag_ids: tags?.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: '学时',
@ -68,14 +148,16 @@ const columns: ProColumns<TableListItem>[] = [
valueType: 'text',
sorter: false,
hideInTable: false,
hideInForm: false,
hideInForm: true,
hideInSearch: true,
renderText: (val: string) => `${val}`,
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
width: 200,
render: (_dom: any, record: React.SetStateAction<TableListItem | undefined>) => [
<a
key="detail"
@ -103,18 +185,35 @@ const columns: ProColumns<TableListItem>[] = [
},
];
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
/**
*
*
* @param fields
*/
const handleAddChapter = async (fields: TableListItem) => {
const hide = message.loading('正在添加');
try {
const {course_ids} = fields
const {code, msg} = await saveChapter({ ...fields, course_ids: course_ids.toString()});
if(code === 2000){
hide();
message.success('添加成功');
return true;
}else{
hide();
message.warn(msg);
return false;
}
} catch (error) {
hide();
message.error('添加失败请重试!');
return false;
}
};
const numbers = [];
for (let i = 0; i < 50; i++) {
numbers.push({ id: `${i}` })
}
export default () => {
const uuid = uuidv4();
const formRef = useRef<ProFormInstance>();
const actionRef = useRef<ActionType>();
@ -123,15 +222,49 @@ export default () => {
const [detailModalVisible, handleDetailModalVisible] = useState<boolean>(false);
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const [uploadFileName, SetUploadFileName] = useState<string>();
const [uploadFileExt, SetUploadFileExt] = useState<string>();
const [subjectIntro, setSubjectIntro] = useState({});
const formMapRef = useRef<React.MutableRefObject<ProFormInstance<any> | undefined>[]>([]);
const params = useParams();
//console.log('params', params);
const {data:subjectInfo} = useRequest(() => {
return getSubjectInfo({subject_id: params?.id});
});
useEffect(() => {
waitTime(1000).then(() => {
// 编辑场景下需要使用formMapRef循环设置formData
formMapRef.current.forEach((formInstanceRef) => {
formInstanceRef.current?.setFieldsValue({subject_name:'123'});
});
console.log('getSubjectInfo', subjectInfo);
console.log('url', subjectInfo?.attachment_json?.url);
// 编辑场景下需要使用formMapRef循环设置formData
formMapRef.current.forEach((formInstanceRef) => {
let fieldsValue;
const subjectValue = {
subject_name:subjectInfo?.subject_name,
subject_describe:subjectInfo?.subject_describe,
}
if(params?.id && subjectInfo?.attachment_json?.url){
fieldsValue = {
...subjectValue,
upload:[
{
name: subjectInfo?.attachment_json?.name,
status: 'done',
url: `/dsideal_yy/html/${subjectInfo?.attachment_json?.url}`
}
]
}
}else{
// 无附件
fieldsValue = subjectValue;
}
formInstanceRef.current?.setFieldsValue(fieldsValue);
});
}, []);
}, [subjectInfo]);
return (
<PageContainer content={''} extraContent={''}>
@ -141,8 +274,8 @@ export default () => {
}>
formMapRef={formMapRef}
formRef={formRef}
onFinish={async () => {
await waitTime(1000);
onFinish={async (values) => {
console.log('values::', values)
message.success('提交成功');
}}
formProps={{
@ -162,53 +295,48 @@ export default () => {
stepProps={{
description: false,
}}
/*
request={async () => {
const data = await getSubjectInfo(5);
console.log(data);
console.log('getSubjectInfo', data);
// return { data: bean }
}}
onFinish={async (value) => {
}}*/
onFinish={async (value: any) => {
console.log(value, "vvvvv");
const _data = await saveSubject({
const url = value?.upload[0]?.url?.replace('/dsideal_yy/html/','') || value?.upload[0]?.response?.url;
const { data } = await saveSubject({
...value,
attachment_json: `{ "url": "${value.upload[0].response.url}"}`
subject_id: params?.id,
attachment_json: `{ "url": "${url}"}`
});
return {
current: _data?.page_number,
data: _data?.data?.list,
pageSize: _data?.page_size,
total: _data?.total_row || 0,
};
setSubjectIntro({subject_id:data?.subject_id, subject_name: value?.subject_name, subject_describe:value?.subject_describe});
return true;
}}
>
<Row gutter={24}>
<Col lg={24} md={24} sm={24}>
<ProFormText
name="subject_name"
label="主题名称"
width="md"
width="xl"
// tooltip="最长为 6 位汉字,需要与考生身份证一致"
placeholder="请输入名称"
// rules={[{ required: true }]}
rules={[{ required: true }]}
// value="锦书"
// disabled
/>
<ProFormRichEdit
name="subject_describe"
label="主题介绍"
width="md"
width="xl"
// tooltip="最长为 6 位汉字,需要与考生身份证一致"
placeholder="请输入介绍"
// rules={[{ required: true }]}
rules={[{ required: true }]}
// value="锦书"
// disabled
@ -220,13 +348,24 @@ export default () => {
fieldProps={{
name: 'file',
listType: 'picture-card',
maxCount: 1,
beforeUpload: (file) => {
console.log('file', file)
// 获取文件名
SetUploadFileName(file?.name);
// 获取最后一个.的位置
const index = file?.name.lastIndexOf(".");
// 获取后缀
SetUploadFileExt(file?.name.substr(index + 1));
},
data: {
name: '5.jpg',
name: uploadFileName,
chunk: 0,
chunks: 1,
key: 'down/Material/BC/BCFFEA09-9660-9D40-8D11-EF7D7110F7A5.jpg'
key: `down/Syzx/${uuid?.substr(0, 2)}/${uuid}.${uploadFileExt}`
}
}}
rules={[{ required: true }]}
action="/dsideal_yy/res/plupload/"
extra=""
/>
@ -244,6 +383,7 @@ export default () => {
description: false,
}}
onFinish={async (fileds) => {
/*
if (params.id) {
fileds = { ...fileds, id: params.id }
}
@ -258,6 +398,7 @@ export default () => {
});
// await waitTime(2000);
*/
return true;
}}
@ -268,23 +409,27 @@ export default () => {
column={1}
//actionRef={actionRef}
title="主题信息"
/*
request={async () => {
console.log('step2 主题信息')
return Promise.resolve({
success: true,
data: { id: '这是一段文本', object: '', date: '2020-07-30 08:00', duration: '', grade: 100, through: '>60', learn: '>20 min', times: 2 },
});
}}
}}*/
extra={false}
>
<ProDescriptions.Item dataIndex="id" hideInDescriptions />
<ProDescriptions.Item dataIndex="object" label="主题名称" valueType="text" />
<ProDescriptions.Item dataIndex="date" label="主题介绍" valueType="text" />
<ProDescriptions.Item dataIndex="subject_id" hideInDescriptions />
<ProDescriptions.Item dataIndex="subject_name" label="主题名称" valueType="text">{subjectIntro?.subject_name}</ProDescriptions.Item>
<ProDescriptions.Item dataIndex="subject_describe" label="主题介绍" valueType="text">
<div dangerouslySetInnerHTML={{__html: subjectIntro?.subject_describe}} />
</ProDescriptions.Item>
</ProDescriptions>
<ProTable<TableListItem, TableListPagination>
headerTitle={false}
actionRef={actionRef}
rowKey="course_id"
rowKey="chapter_id"
options={false}
search={false}
toolBarRender={() => [
@ -299,17 +444,18 @@ export default () => {
</Button>,
]}
request={async (value) => {
// const _data = await saveSubject({
// ...value,
// attachment_json: `{ "url": "${value.upload[0].response.url}"}`
// });
// return {
// current: _data?.page_number,
// data: _data?.data?.list,
// pageSize: _data?.page_size,
// total: _data?.total_row || 0,
// };
const { data } = await queryListChapterBySubject({
subject_id: params?.id || 0,
page_number: value?.current || 1,
page_size: value?.pageSize,
});
return {
current: data?.page_number,
data: data?.list,
pageSize: data?.page_size,
success: true,
total: data?.total_row || 0,
};
}}
// dataSource={list}
columns={columns}
@ -335,7 +481,14 @@ export default () => {
// 表单处理
console.log('columns:', columns);
console.log('values:', values);
const success = await handleAddChapter({
...values,
subject_id: params?.id || 0,
});
if(success){
handleCreateModalVisible(false);
actionRef.current?.reloadAndRest?.();
}
}}
submitter={{
render: (props, doms) => (
@ -360,7 +513,9 @@ export default () => {
stepProps={{
description: false,
}}
onFinish={async () => {
onFinish={async (values) => {
console.log('subject_id:', subjectIntro?.subject_id);
await commitSubject({subject_id: subjectIntro?.subject_id});
console.log(formRef.current?.getFieldsValue());
// 跳转到指定路由
history.push('/course/subject');
@ -369,30 +524,18 @@ export default () => {
>
<Row gutter={24}>
<Col lg={12} md={12} sm={12} offset={8}>
<ProDescriptions
layout='horizontal'
column={1}
//actionRef={actionRef}
title="模拟考试"
request={async () => {
return Promise.resolve({
success: true,
data: { id: '这是一段文本', object: '', date: '2020-07-30 08:00', duration: '', grade: 100, through: '>60', learn: '>20 min', times: 2 },
});
}}
extra={false}
>
<ProDescriptions.Item dataIndex="id" hideInDescriptions />
<ProDescriptions.Item dataIndex="object" label="考试名称" valueType="text" />
<ProDescriptions.Item dataIndex="date" label="关联培训主题" valueType="text" />
<ProDescriptions.Item dataIndex="duration" label="考试时长" valueType="text" />
<ProDescriptions.Item dataIndex="grade" label="考试信息" valueType="text" />
<ProDescriptions.Item dataIndex="through" label="通过标准" valueType="text" />
<ProDescriptions.Item dataIndex="times" label="考试次数" valueType="text" />
</ProDescriptions>
<Col lg={12} md={12} sm={12} offset={6}>
<Result
className={styles.registerResult}
status="success"
title={
<div className={styles.title}>
<span style={{color: '#1890ff'}}>{subjectIntro?.subject_name} </span>/
</div>
}
subTitle="点击提交将设置为发布状态。"
//extra={actions}
/>
</Col>
</Row>
</StepsForm.StepForm>

@ -1,5 +1,5 @@
import { DingdingOutlined, UploadOutlined } from '@ant-design/icons';
import { Button, Card, Steps, Result, Descriptions, Modal, Input, Upload } from 'antd';
import { Button, Card, Steps, Result, Descriptions, Modal, Input, Upload, Popconfirm } from 'antd';
import { Fragment, useRef, useState } from 'react';
import { GridContent } from '@ant-design/pro-layout';
@ -100,6 +100,9 @@ export default () => {
/>
</Modal>
<Popconfirm title="Are you sure" okText="Yes" cancelText="No">
<a href="#">Delete</a>
</Popconfirm>
</>
)
};

@ -213,7 +213,7 @@ const CourseList: React.FC = () => {
render: (_dom: any, record: React.SetStateAction<TableListItem | undefined>) => [
<a
key="update"
key="detail"
onClick={() => {
handleUpdateModalVisible(true);
setCurrentRow(record);

@ -41,7 +41,7 @@ const handleAdd = async (fields: TableListItem) => {
*
* @param fields
*/
/*
const handleUpdate = async (fields: FormValueType, currentRow?: TableListItem) => {
const hide = message.loading('正在配置');
@ -59,6 +59,7 @@ const handleUpdate = async (fields: FormValueType, currentRow?: TableListItem) =
return false;
}
};
*/
/**
*

@ -1,6 +1,6 @@
/** 资质考试 */
//import { AlignLeftOutlined, PlusOutlined } from '@ant-design/icons';
import { Switch, Button, Card, Col, List, Menu, Progress, Row, Typography, Space, Divider, Radio, Checkbox, Tag, Dropdown } from 'antd';
import { Switch, Button, Card, Col, List, Menu, Progress, Row, Typography, Space, Divider, Radio, Checkbox, Tag, Dropdown, Upload } from 'antd';
import { PageContainer } from '@ant-design/pro-layout';
//import { useRequest } from 'umi';
//import { queryFakeList } from './service';
@ -9,62 +9,49 @@ 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 { ReactText, useState } from 'react';
import { ReactText, useEffect, useState } from 'react';
import { PlusOutlined, DeleteOutlined, DownloadOutlined, UploadOutlined, EditOutlined, EyeOutlined, EyeInvisibleOutlined, DownOutlined } from '@ant-design/icons';
import { exportQuestionTemplate, queryQuestionById, queryQuestionList, queryQuestionType } from './service';
import { useRequest } from 'umi';
import { queryCourseView } from '@/pages/course/option/service';
//const { Paragraph } = Typography;
const parsingMap = new Map()
console.log('first');
const QuestionBank = () => {
console.log('second');
const [questionType, setQuestionType] = useState([]);
const [parsing, setParsing] = useState();
const [selectedRowsState, setSelectedRows] = useState<API.RuleListItem[]>([]);
const [expandedDescRowKeys, setExpandedDescRowKeys] = useState<readonly ReactText[]>([]); // 展开解析设置
const [addType, setAddType] = useState(0);
const numbers = [];
for(let i=0;i<50;i++){
numbers.push({id: `${i}`})
}
const dataSource = [
{
id: 1,
name: '下面哪个词语能体现未来思维?',
type: '单选',
options: [
{label: '井底之蛙', value: 'A'},
{label: '鼠目寸光', value: 'B'},
{label: '未雨绸缪', value: 'C'},
{label: '即时行乐', value: 'D'},
],
time: '2022/12/12',
tag: '生涯理论',
course: '特质因素理论',
const labels = ['A','B','C','D','E']
answer:'C',
desc: '该成语意思是天还没有下雨,先把门窗绑牢。比喻事先做好准备工作。该成语意思是天还没有下雨,先把门窗绑牢。比喻事先做好准备工作。该成语意思是天还没有下雨,先把门窗绑牢。比喻事先做好准备工作。该成语意思是天还没有下雨,先把门窗绑牢。比喻事先做好准备工作。',
},
{
id: 2,
name: 'Ant Design',
type: '多选',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
{
id: 3,
name: '蚂蚁金服体验科技',
type: '判断',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
{
id: 4,
name: 'TechUI',
type: '单选',
image:
'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
desc: '我是一条测试的描述',
},
];
/** 获取题型 */
const { data } = useRequest(() => {
return queryQuestionType();
},{
formatResult: (result) => {
return result.list;
}
});
/*
const { data: template } = useRequest(() => {
return exportQuestionTemplate();
});
*/
useEffect(() => {
setQuestionType(data || []);
return ()=>{
/** 退出当前页面清空Map */
parsingMap.clear();
}
}, [data]);
return (
<PageContainer content={false} extraContent={false} className={styles.questionbank}>
@ -76,12 +63,18 @@ const QuestionBank = () => {
showSizeChanger: false,
}}
toolBarRender={() => {
const menu = (
const menuItems = [];
console.log('toolBarRender', questionType);
if(questionType?.length > 0){
console.log('push');
questionType.forEach((item: {code: number, name: string})=>{
menuItems.push(<Menu.Item key={item?.code}>{item?.name}</Menu.Item>)
})
}
const menu = (
<Menu onClick={(value)=>setAddType(value)}>
<Menu.Item key="1"></Menu.Item>
<Menu.Item key="2"></Menu.Item>
<Menu.Item key="3"></Menu.Item>
</Menu>
{menuItems}
</Menu>
);
return [
<Dropdown overlay={menu}>
@ -92,15 +85,27 @@ const QuestionBank = () => {
<Button key="remove" type="default" danger>
<DeleteOutlined />
</Button>,
<Button key="download" >
<Button key="download" onClick={()=>{window.location.href='/dsideal_yy/zygh/training/exportQuestionTemplate'}} >
<DownloadOutlined />
</Button>,
<Button key="upload" >
<UploadOutlined />
</Button>,
<Upload
accept='.xlsx'
showUploadList={false}
action="/dsideal_yy/res/plupload/"
data={
{
type: 0,
}
}
>
<Button key="upload" >
<UploadOutlined />
</Button>
</Upload>,
];
}}
onRow={(record: any) => {
/*
return {
onMouseEnter: () => {
console.log(record);
@ -108,12 +113,45 @@ const QuestionBank = () => {
onClick: () => {
console.log(record);
},
};
};*/
}}
rowKey="id"
headerTitle={false}
tooltip={false}
dataSource={dataSource}
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: 0,
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, };
}
return {
current: questions?.pageNumber,
data: data,
pageSize: questions?.pageSize,
success: true,
total: questions?.totalRow || 0,
};
}}
//dataSource={dataSource}
rowSelection={{
onChange: (_, selectedRows) => {
setSelectedRows(selectedRows);
@ -124,29 +162,42 @@ const QuestionBank = () => {
showExtra="always"
metas={{
title: {
dataIndex: 'name',
dataIndex: 'question_stem',
render: (text: React.ReactNode, record: T, index: number) => `1. ${text}`,
},
avatar: {
dataIndex: 'type',
dataIndex: 'question_type',
valueType: 'text',
render: (text: React.ReactNode, record: T, index: number) => `[${record.type}]`,
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 `[${type[0]?.name}]`
},
},
description: {
dataIndex: 'options',
dataIndex: 'answers',
valueType: 'checkbox',
render: (text: React.ReactNode, record: T, index: number) => {
console.log('description answers', record)
return (
<List
header={false}
footer={false}
bordered={false}
dataSource={record.options || []}
renderItem={item => (
<List.Item>
<Typography.Text mark={false}>{`${item?.value}. ${item?.label}`}</Typography.Text>
</List.Item>
)}
dataSource={record.answers || []}
rowKey='id'
renderItem={ (item, key) => {
console.log('item', item);
return (
<List.Item>
<Typography.Text mark={false}>{`${(record?.question_type === 2) ? ['T','F'][key] : labels[key]}. ${item?.answer}`}</Typography.Text>
</List.Item>)
}}
/>
);
},
@ -154,24 +205,57 @@ const QuestionBank = () => {
subTitle: { },
content: {
render: (text: React.ReactNode, record: T, index: number) => {
return (
<Space direction="vertical" style={{border:'solid 1px #f0f0f0;',padding:10}}>
<Typography>{record.answer}</Typography>
<Typography>{record.desc}</Typography>
</Space>
);
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] === `${idx}`).toString()
break;
case 2: // 判断
answer = ['T', 'F']?.filter((x, idx, self)=>answertrue[idx] === `${idx}`).toString()
break;
}
console.log('expandedDescRowKeys', expandedDescRowKeys)
if(expandedDescRowKeys?.indexOf(record.id) > -1){
return (
<Space direction="vertical" style={{borderTop:'solid 1px #f0f0f0', padding:10, margin: '5px -18px 0 -24px', background: '#fdfdfd'}}>
<Typography>
{answer}
</Typography>
<Typography>{parsing.get(record.id)}</Typography>
</Space>
);
}else{
return (
<Space direction="vertical" style={{borderTop:'solid 1px #f0f0f0', padding:10, margin: '5px -18px 0 -24px', background: '#fdfdfd'}}>
<Typography>
{answer}
</Typography>
</Space>
)
}
},
},
actions: {
cardActionProps: 'extra',
render: (text: React.ReactNode, record: T, _index: number) => {
let eye
if(expandedDescRowKeys?.indexOf(record.id) > -1){
eye = <><EyeInvisibleOutlined /> </>
}else{
eye = <><EyeOutlined /> </>
}
return(
<Row style={{padding:'10px 24px'}}>
<Col flex={1} style={{textAlign:'left'}}>
<Space direction="horizontal" size="large">
<Typography>{record.time}</Typography>
<Typography>{record.tag}</Typography>
<Typography>{record.course}</Typography>
<Typography>{record?.create_time}</Typography>
<Typography>{record?.tag_name}</Typography>
<Typography>{record?.course_name}</Typography>
</Space>
</Col>
<Col flex={1} style={{textAlign:'right'}}>
@ -179,18 +263,31 @@ const QuestionBank = () => {
<a href={record.html_url} target="_blank" rel="noopener noreferrer" key="link">
<EditOutlined />
</a>
<a href={record.html_url} target="_blank" rel="noopener noreferrer" key="warning">
<a href={record.html_url} target="_blank" rel="noopener noreferrer" key="warning" >
<DeleteOutlined />
</a>
<a
key="view"
onClick={()=>{
setExpandedDescRowKeys([...expandedDescRowKeys, record.id]);
onClick={async ()=>{
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)
console.log('expandedDescRowKeys......', expandedDescRowKeys)
}}
>
<EyeOutlined /> <EyeInvisibleOutlined />
{eye}
</a>
</Space>
</Col>

@ -8,3 +8,68 @@ export async function queryFakeList(params: {
params,
});
}
/**
*
* @param params
* @returns
*/
export async function queryQuestionType(): Promise<{ list: any } > {
return request('/dsideal_yy/newUniversityExamination/base/getDicItem', {
method: 'GET',
params: {
kind: 'ZYGH_TRAINING_QUESTION_TYPE'
},
});
}
/**
*
* @param params
* @returns
*/
export async function exportQuestionTemplate(): Promise<{ list: any } > {
return request('/dsideal_yy/zygh/training/exportQuestionTemplate', {
method: 'GET',
params: {
},
});
}
/** 新建/修改试题 */
export async function saveQuestion(data: Record<string, any>, options?: Record<string, any>) {
return request<TableListItem>('/dsideal_yy/zygh/training/updateQuestion', {
data,
method: 'POST',
requestType: 'form',
...(options || {}),
});
}
/**
*
* @param params
* @returns
*/
export async function queryQuestionList(params: {
count: number;
}): Promise<{ data: { list: CardListItemDataType[] } }> {
return request('/dsideal_yy/zygh/training/getQuestionList', {
params,
});
}
/**
*
* @param params
* @returns
*/
export async function queryQuestionById(params: {
id: number;
}): Promise<{ bean: any }> {
return request('/dsideal_yy/zygh/training/getQuestionById', {
params,
});
}

@ -12,6 +12,7 @@ import UpdateForm from './components/UpdateForm';
import { queryTrainList, saveTrain, removeTrain, queryOrgTree, queryValueByKey } from './service';
import type { TableListItem, TableListPagination } from './data';
import { useRequest } from 'umi';
/**
*
*
@ -210,7 +211,7 @@ const TableList: React.FC = () => {
valueType: 'option',
render: (_, record) => [
<a
key="config"
key="detail"
onClick={() => {
handleUpdateModalVisible(true);
setCurrentRow(record);
@ -240,6 +241,7 @@ const TableList: React.FC = () => {
headerTitle={false}
actionRef={actionRef}
rowKey="train_id"
options={false}
search={{
labelWidth: 120,
}}

Loading…
Cancel
Save