feat
parent
e3c66c1f71
commit
69ecb5ffba
|
|
@ -13,8 +13,8 @@ module.exports = {
|
|||
//API_HOST: "http://localhost:80",
|
||||
|
||||
// API_HOST: "http://192.168.0.134",
|
||||
//API_HOST: "http://192.168.0.150", //太浅
|
||||
API_HOST: "https://gbs-gateway.qhdsafety.com",
|
||||
API_HOST: "http://192.168.0.150", //太浅
|
||||
// API_HOST: "https://gbs-gateway.qhdsafety.com",
|
||||
// API_HOST: "http://192.168.0.103", //huwei
|
||||
},
|
||||
production: {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,22 @@ export const coursewareQuestionDelete = declareRequest(
|
|||
"Post > @/safetyEval/question/del/{questionId}",
|
||||
);
|
||||
|
||||
/**
|
||||
* 课件习题-导入试题(multipart,declareRequest 仅支持 json,手动 fetch)
|
||||
* @param {FormData} payload coursewareManagementId/file
|
||||
*/
|
||||
export async function questionImport(payload) {
|
||||
const res = await fetch(
|
||||
`${window.process.env.app.API_HOST}/safetyEval/question/import`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { token: sessionStorage.getItem("token") },
|
||||
body: payload,
|
||||
},
|
||||
);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/** 批量删除习题(请求体:{ questionIds }) */
|
||||
export const coursewareQuestionBatchDelete = declareRequest(
|
||||
"coursewareQuestionLoading",
|
||||
|
|
|
|||
|
|
@ -213,6 +213,7 @@ export const EVALUATOR_OPTIONS = [
|
|||
|
||||
/** 职称等级 */
|
||||
export const TITLE_LEVEL_OPTIONS = [
|
||||
{ value: "NONE", label: "无" },
|
||||
{ value: "SENIOR", label: "高级" },
|
||||
{ value: "MIDDLE", label: "中级" },
|
||||
{ value: "JUNIOR", label: "初级" },
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Checkbox,
|
||||
Form,
|
||||
|
|
@ -9,6 +10,7 @@ import {
|
|||
Select,
|
||||
Space,
|
||||
Table,
|
||||
Upload,
|
||||
message,
|
||||
} from "antd";
|
||||
import {
|
||||
|
|
@ -16,6 +18,7 @@ import {
|
|||
DownloadOutlined,
|
||||
ImportOutlined,
|
||||
PlusOutlined,
|
||||
UploadOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
|
||||
|
|
@ -23,6 +26,7 @@ import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||
import { NS_COURSEWARE } from "~/enumerate/namespace";
|
||||
import { questionImport } from "~/api/courseware";
|
||||
import {
|
||||
QUESTION_TYPE_MAP,
|
||||
QUESTION_TYPE_OPTIONS,
|
||||
|
|
@ -45,6 +49,7 @@ const buildDefaultOptions = (questionType) =>
|
|||
/** 课件习题管理(由课件列表「课件习题」进入) */
|
||||
function CoursewareQuestionPage(props) {
|
||||
const [addOpen, setAddOpen] = useState(false);
|
||||
const [importOpen, setImportOpen] = useState(false);
|
||||
const [editQuestion, setEditQuestion] = useState(null);
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||
const coursewareName = router.query?.coursewareName;
|
||||
|
|
@ -201,7 +206,7 @@ function CoursewareQuestionPage(props) {
|
|||
<Button
|
||||
type="primary"
|
||||
icon={<ImportOutlined />}
|
||||
onClick={() => message.info("习题导入功能暂未开放")}
|
||||
onClick={() => setImportOpen(true)}
|
||||
>
|
||||
导入
|
||||
</Button>
|
||||
|
|
@ -263,6 +268,13 @@ function CoursewareQuestionPage(props) {
|
|||
}}
|
||||
/>
|
||||
|
||||
<ImportQuestionModal
|
||||
open={importOpen}
|
||||
coursewareManagementId={coursewareManagementId}
|
||||
onCancel={() => setImportOpen(false)}
|
||||
onSuccess={handleSearch}
|
||||
/>
|
||||
|
||||
<QuestionFormModal
|
||||
open={!!editQuestion}
|
||||
mode="edit"
|
||||
|
|
@ -294,6 +306,107 @@ function CoursewareQuestionPage(props) {
|
|||
);
|
||||
}
|
||||
|
||||
/** 导入习题弹窗(按课件id导入 Excel),成功后展示导入结果 */
|
||||
function ImportQuestionModal({
|
||||
open,
|
||||
coursewareManagementId,
|
||||
onCancel,
|
||||
onSuccess,
|
||||
}) {
|
||||
const [form] = Form.useForm();
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [result, setResult] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
form.resetFields();
|
||||
setResult(null);
|
||||
setUploading(false);
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
const handleOk = async () => {
|
||||
// 已导入成功时确定按钮即关闭
|
||||
if (result) {
|
||||
onCancel();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
const formData = new FormData();
|
||||
formData.append("coursewareManagementId", coursewareManagementId);
|
||||
formData.append("file", values.file[0].originFileObj);
|
||||
setUploading(true);
|
||||
const res = await questionImport(formData);
|
||||
if (res?.success !== false) {
|
||||
setResult(res?.data || {});
|
||||
onSuccess();
|
||||
}
|
||||
} catch {
|
||||
// validation error
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const errorColumns = [
|
||||
{ title: "行号", dataIndex: "rowIndex", width: 70 },
|
||||
{ title: "sheet页", dataIndex: "sheetName", width: 120 },
|
||||
{ title: "异常原因", dataIndex: "errorMessage", ellipsis: true },
|
||||
];
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
destroyOnHidden
|
||||
title="导入习题"
|
||||
width={560}
|
||||
okText={result ? "关闭" : "开始导入"}
|
||||
confirmLoading={uploading}
|
||||
onOk={handleOk}
|
||||
onCancel={onCancel}
|
||||
>
|
||||
{result ? (
|
||||
<>
|
||||
<Alert
|
||||
type={result.errors?.length ? "warning" : "success"}
|
||||
message={`成功导入 ${result.successCount ?? 0} 条试题${
|
||||
result.errors?.length ? `,失败 ${result.errors.length} 条` : ""
|
||||
}`}
|
||||
showIcon
|
||||
style={{ marginBottom: 12 }}
|
||||
/>
|
||||
{!!result.errors?.length && (
|
||||
<Table
|
||||
size="small"
|
||||
rowKey={(e) => `${e.rowIndex}-${e.sheetName}`}
|
||||
columns={errorColumns}
|
||||
dataSource={result.errors}
|
||||
pagination={false}
|
||||
scroll={{ y: 240 }}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Form form={form} layout="vertical" scrollToFirstError>
|
||||
<Form.Item
|
||||
name="file"
|
||||
label="试题Excel文件"
|
||||
valuePropName="fileList"
|
||||
getValueFromEvent={(e) => (Array.isArray(e) ? e : e?.fileList)}
|
||||
rules={[{ required: true, message: "请上传试题Excel文件" }]}
|
||||
extra="第一个sheet单选题,第二个sheet多选题,第三个sheet判断题"
|
||||
>
|
||||
<Upload accept=".xls,.xlsx" maxCount={1} beforeUpload={() => false}>
|
||||
<Button icon={<UploadOutlined />}>选择文件</Button>
|
||||
</Upload>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增/编辑习题弹窗(仅支持单选/多选/判断;编辑时先调查询接口回填) */
|
||||
function QuestionFormModal({
|
||||
open,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
CHONGQING_DISTRICTS,
|
||||
QUALIFICATION_INDUSTRY_OPTIONS_MAP,
|
||||
} from "~/enumerate/enterpriseOptions";
|
||||
import { NATIONWIDE_DISTRICTS } from "~/enumerate/nationwideTerritory";
|
||||
import {
|
||||
FILING_FORM_MODE,
|
||||
getFilingStatusOptions,
|
||||
|
|
@ -245,19 +246,24 @@ export default function FilingListTable({
|
|||
allowClear
|
||||
/>
|
||||
</Form.Item>,
|
||||
<Form.Item key="filingTerritoryCode" name="filingTerritoryCode">
|
||||
<Form.Item key="filingTerritoryName" name="filingTerritoryName">
|
||||
<ControlWrapper.Select
|
||||
label="备案属地"
|
||||
placeholder="请输入"
|
||||
placeholder={
|
||||
mode === FILING_FORM_MODE.APPLICATION
|
||||
? "请输入"
|
||||
: "请选择(支持搜索全国区县)"
|
||||
}
|
||||
allowClear
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{CHONGQING_DISTRICTS.map((d) => (
|
||||
<Select.Option key={d.value} value={d.value}>
|
||||
{d.label}
|
||||
</Select.Option>
|
||||
))}
|
||||
</ControlWrapper.Select>
|
||||
options={
|
||||
mode === FILING_FORM_MODE.APPLICATION
|
||||
? CHONGQING_DISTRICTS
|
||||
: NATIONWIDE_DISTRICTS
|
||||
}
|
||||
/>
|
||||
</Form.Item>,
|
||||
mode !== 'application' && <Form.Item key="filingNo" name="filingNo">
|
||||
<ControlWrapper.Input
|
||||
|
|
|
|||
Loading…
Reference in New Issue