From 73809d33add5b6d649af45e01d14c128b95514f6 Mon Sep 17 00:00:00 2001 From: liuyiliang Date: Thu, 27 Mar 2025 09:46:13 +0800 Subject: [PATCH] =?UTF-8?q?=E8=80=83=E8=AF=95=E5=8A=9F=E8=83=BD=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E4=BF=AE=E6=94=B9=E3=80=81=E8=80=83=E8=AF=95=E7=A0=81?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E3=80=81=E5=85=B6=E4=BB=96=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 62 --------- packages/examination/.env.development | 1 + packages/examination/.env.production | 1 + packages/examination/package.json | 13 +- packages/examination/src/api/axios.js | 7 - .../examination/src/api/exam-online/index.tsx | 16 ++- packages/examination/src/style/common.css | 63 ++++++++- .../exam-online/compoents/ExamEditPage.tsx | 120 +++++++++-------- .../exam-online/compoents/ExamListPage.tsx | 121 ++++++++++++++---- .../compoents/ExamPaperAnalysisPage.tsx | 46 ++++--- .../compoents/ExamStatisticsPage.tsx | 115 ++++++++++------- .../src/views/exam-online/exam-edit.tsx | 22 ++-- .../views/statistical/customerRetention.tsx | 28 +--- .../src/views/statistical/enterpriseFile.tsx | 3 +- .../views/statistical/serviceStatistics.tsx | 24 +++- 15 files changed, 385 insertions(+), 257 deletions(-) delete mode 100644 package.json create mode 100644 packages/examination/.env.development create mode 100644 packages/examination/.env.production diff --git a/package.json b/package.json deleted file mode 100644 index 47738cc..0000000 --- a/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "ccic-web", - "private": true, - "version": "1.0.0", - "description": "大地项目", - "repository": { - "type": "git", - "url": "git@120.78.213.5:/home/git/ccic-code/ccic-web.git" - }, - "scripts": { - "start:insurance": "lerna run start --scope=insure", - "start:expert": "lerna run start --scope=expert", - "start:enterprise": "lerna run start --scope=enterprise", - "build": "lerna run build --scope=*", - "build:pro": "cross-env --REACT_APP_ENVIRONMENT=official lerna run build --scope=*" - }, - "dependencies": { - "@ahooksjs/use-url-state": "^3.5.0", - "@amap/amap-jsapi-loader": "^1.0.1", - "@ant-design/pro-components": "2.3.20", - "ahooks": "3.7.1", - "antd": "^4.24.2", - "axios": "^0.27.2", - "downloadjs": "^1.4.7", - "echarts": "^5.3.3", - "js-base64": "^3.7.5", - "js-cookie": "^3.0.1", - "lodash": "^4.17.21", - "lru-cache": "^6.0.0", - "mime-match": "^1.0.2", - "moment": "^2.29.4", - "nprogress": "^0.2.0", - "query-string": "^7.1.1", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "react-router-dom": "6.3.0", - "react-scripts": "5.0.1", - "store2": "^2.14.2", - "whatwg-fetch": "^3.6.2", - "xlsx": "^0.18.5" - }, - "devDependencies": { - "@craco/craco": "^7.1.0", - "@types/lodash": "^4.14.182", - "@types/node": "^14.14.10", - "@types/react": "^17.0.0", - "@types/react-dom": "^17.0.0", - "@types/react-router-dom": "^5.3.3", - "babel-plugin-transform-remove-console": "^6.9.4", - "craco-less": "^2.1.0-alpha.0", - "cross-env": "^7.0.3", - "http-proxy-middleware": "^2.0.6", - "lerna": "^5.6.2", - "typescript": "^4.7.4", - "webpack-cli": "^5.0.1" - }, - "author": "guowei", - "license": "ISC", - "workspaces": [ - "packages/*" - ] -} diff --git a/packages/examination/.env.development b/packages/examination/.env.development new file mode 100644 index 0000000..fb2af47 --- /dev/null +++ b/packages/examination/.env.development @@ -0,0 +1 @@ +REACT_APP_SERVER_URL=http://localhost:8187/ \ No newline at end of file diff --git a/packages/examination/.env.production b/packages/examination/.env.production new file mode 100644 index 0000000..b90e7d3 --- /dev/null +++ b/packages/examination/.env.production @@ -0,0 +1 @@ +REACT_APP_SERVER_URL=http://172.16.10.66:8187/ \ No newline at end of file diff --git a/packages/examination/package.json b/packages/examination/package.json index b3d946a..74698e2 100644 --- a/packages/examination/package.json +++ b/packages/examination/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@ant-design/icons": "^5.6.1", "@craco/craco": "5.9.0", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", @@ -12,18 +13,24 @@ "antd": "^4.7.0", "axios": "^0.21.0", "craco-less": "^1.17.1", - "echarts": "4.9.0", - "echarts-for-react": "^2.0.16", + "echarts": "5.2.0", + "echarts-for-react": "^3.0.2", + "file-saver": "^2.0.5", + "html2canvas": "^1.4.1", "js-cookie": "^2.2.1", + "jspdf": "^3.0.0", + "process": "^0.11.10", "quill-emoji": "^0.2.0", "react": "^17.0.0", "react-dom": "^17.0.0", + "react-qrcode-logo": "^3.0.0", "react-quill": "^1.3.5", "react-redux": "^7.2.2", "react-router-dom": "^5.2.0", "react-scripts": "3.4.3", "redux": "^4.0.5", - "typescript": "^4.1.3" + "typescript": "^4.1.3", + "xlsx": "^0.18.5" }, "scripts": { "start": "craco start", diff --git a/packages/examination/src/api/axios.js b/packages/examination/src/api/axios.js index 5723905..216e64a 100644 --- a/packages/examination/src/api/axios.js +++ b/packages/examination/src/api/axios.js @@ -22,16 +22,9 @@ const instance = axios.create({ withCredentials: true, timeout: 100000 }) -export const serverUrl = 'http://localhost:8187/'; localStorage.setItem('si', JSON.stringify({ eName: 'admin' })); -// const token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJjY2ljLXVzZXIiLCJpYXQiOjE3NDI1NDI4MTIsImV4cCI6MTc0MjYyOTIxMiwiaWQiOiI0MjY1NjA4NTc2MDI4MjYyNCIsInVzZXJOYW1lIjoi5rWL6K-VNjI2ODg1Iiwib3JnYW5JZCI6MzEwMTAwMDAsIm9yZ2FuTmFtZSI6IuS4iua1t-WIhuWFrOWPuCIsIm9yZ2FuQ29kZSI6IjMxMDEwMDAwIiwidXNlck5vIjoiODAwMDYyNjg4NSIsIm9yZ2FuVHlwZSI6IjMiLCJncmlkQ29kZSI6IjMxMDAwMCJ9.C8a04P9zSCaN388EMmCqlhcTen2H6GV4TmNQaA1qDac' -// if (token) { -// setToken(token); -// localStorage.setItem('si', JSON.stringify({ eName: 'admin' })); -// } - instance.interceptors.request.use( config => { let token = getToken(); diff --git a/packages/examination/src/api/exam-online/index.tsx b/packages/examination/src/api/exam-online/index.tsx index 60fcad8..deb389c 100644 --- a/packages/examination/src/api/exam-online/index.tsx +++ b/packages/examination/src/api/exam-online/index.tsx @@ -7,15 +7,24 @@ export function getList(obj: any) { params: obj }) } -//新增考试 -export function add(obj: any) { - return axios.post( '/ex/exam-schedule/insert', +// 新增或编辑考试 +export function save(obj: any) { + return axios.post( '/ex/exam-schedule/save', obj,{ headers: { 'Content-Type': 'application/json' } }) } +// 保存考试码 +export function saveQrCode(obj: any) { + return axios.post( '/ex/exam-schedule/saveQrCode', + obj,{ + headers: { + 'Content-Type': 'application/json' + } + }) +} // 编辑的画面初期值检索 export function getExamDataById(id:any){ return axios({ @@ -26,7 +35,6 @@ export function getExamDataById(id:any){ } // 发布与批量发布 export function doPublish(ids: string[]) { - debugger return axios.post('/ex/exam-schedule/publish', ids, { headers: { 'Content-Type': 'application/json' diff --git a/packages/examination/src/style/common.css b/packages/examination/src/style/common.css index 80acc8f..59f9159 100644 --- a/packages/examination/src/style/common.css +++ b/packages/examination/src/style/common.css @@ -320,4 +320,65 @@ table.ikd-input-table { } .ant-breadcrumb li:last-child a { color: #6789E2; - } \ No newline at end of file + } +.qrCodeRef { + position: relative; + display: inline-block; +} + +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgb(200 205 219 / 85%); + display: none; + justify-content: center; + align-items: center; + border-radius: 4px; +} + +.refresh-link { + color: black; + text-decoration: none; + font-size: revert; + font-weight: bold; +} +.refresh-link:hover, +.refresh-link:active { + color: #48609f; +} + +.qrCodeRef:hover .overlay { + display: flex; +} +.exam-card-left { + height: 100%; +} +.exam-card-left .ant-card-body { + height: 90%; +} +.exam-card .ant-card-head { + background: #D8E6F5; +} +.exam-card .ant-card-head-title { + font-size: x-large; +} +.exam-card .ant-select-selector { + background-color: rgb(0 0 0 / 0%) !important; + border-color: #bfced6 !important; +} +.exam-statistic-box { + text-align: center; + background: rgb(220, 228, 248); + height: 110px; + border-radius: 4px; +} +.exam-statistic { + justify-content: center; + align-items: center; + display: flex; + height: 100%; + font-size: x-large; +} \ No newline at end of file diff --git a/packages/examination/src/views/exam-online/compoents/ExamEditPage.tsx b/packages/examination/src/views/exam-online/compoents/ExamEditPage.tsx index cfa29b0..016e431 100644 --- a/packages/examination/src/views/exam-online/compoents/ExamEditPage.tsx +++ b/packages/examination/src/views/exam-online/compoents/ExamEditPage.tsx @@ -4,10 +4,9 @@ import { Form, Input, Select, DatePicker, Space, ColProps, Button, Cascader, Def import type { FormProps, FormInstance } from 'antd'; import ESBreadcrumbComponent from './ESBreadcrumbComponent'; // 引入面包屑组件 import { withRouter, RouteComponentProps } from 'react-router-dom'; // 引入 withRouter 和 RouteComponentProps -import { add, getIndustryList, getPaperListWithDetails } from "api/exam-online/index"; // 修改接口为获取带详情的试卷列表 +import { save, getIndustryList, getPaperListWithDetails } from "api/exam-online/index"; // 修改接口为获取带详情的试卷列表 import { provice } from './city.js'; // 引入省市县数据 import moment, { Moment } from 'moment'; -import TextArea from "antd/es/input/TextArea"; // 引入 moment const { Option } = Select; @@ -15,6 +14,7 @@ const { Option } = Select; export interface ExamBasicInfo { examId: string; examName: string; + industryId: string | number; regulatedIndustry: string | number; paperId: string; examScore: string; @@ -78,10 +78,16 @@ const convertArrToRegion = (regionArr: string[]) => { return regionArr.join('/'); }; +interface industryObj { + value: any; + label: any; +} + const ExamBasicInfoForm: React.FC = (props) => { const { isEdit, initialFormData = {} as ExamBasicInfo, history } = props; const formRef = useRef>(null); - const [industryOptions, setIndustryOptions] = useState<{ value: string | number; label: string }[]>([]); + // const [industryOptions, setIndustryOptions] = useState<{ value: string | number; label: string }[]>([]); + const [industryOptions, setIndustryOptions] = useState([]); const [allPaperOptions, setAllPaperOptions] = useState<{ value: string; label: string; examScore: string; examDuration: string; regulatedIndustry: string | number }[]>([]); const [paperOptions, setPaperOptions] = useState<{ value: string; label: string; examScore: string; examDuration: string }[]>([]); const [isDataLoaded, setIsDataLoaded] = useState(false); @@ -95,13 +101,14 @@ const ExamBasicInfoForm: React.FC = (props) => { const formattedValidTo = formatDate(validTo); const formattedValues = { ...otherValues, + id:values.examId, examRegion: formattedRegion, validFrom: formattedValidFrom, validTo: formattedValidTo }; try { - // 调用 add 方法将数据发送到后台 - const response = await add(formattedValues); + // 调用 save 方法将数据发送到后台 + const response = await save(formattedValues); console.log('数据登录成功:', response); // 登录成功后迁移到 /exam-schedule 页面 history.push("/exam-schedule"); @@ -139,77 +146,82 @@ const ExamBasicInfoForm: React.FC = (props) => { const fetchData = async () => { try { // 获取监管行业列表 - const industryResponse = await getIndustryList(); - setIndustryOptions(industryResponse.map((item: any) => ({ value: item.industry_id, label: item.industry_name }))); + let industryResponse = await getIndustryList(); + let industryOptionsArray = industryResponse.map((item: any) => ({ value: item.industry_id, label: item.industry_name })); + setIndustryOptions(industryOptionsArray); // 获取带详情的试卷列表 const paperResponse = await getPaperListWithDetails(); - setAllPaperOptions(paperResponse.map((item: any) => ({ + let allPaperOptionsArray = paperResponse.map((item: any) => ({ value: item.paper_id, label: item.paper_name, examScore: item.total_score, examDuration: item.exam_duration, - regulatedIndustry: item.regulatory_industry // 假设接口返回的试卷数据包含监管行业信息 - }))); + regulatedIndustry: item.regulatory_industry + })) + setAllPaperOptions(allPaperOptionsArray); setIsDataLoaded(true); + const initialIndustry = initialFormData.industryId; + if (String(initialIndustry) === '') { + setPaperOptions(allPaperOptionsArray); + } else if (initialIndustry) { + const filteredPapers = allPaperOptionsArray.filter((paper: { regulatedIndustry: any; }) => String(paper.regulatedIndustry) === String(initialIndustry)); + setPaperOptions(filteredPapers); + } else { + setPaperOptions(allPaperOptionsArray); + } + + if (formRef.current) { + formRef.current.setFieldsValue({ + examId: initialFormData.examId || '', + examName: initialFormData.examName || '', + examRegion: typeof initialFormData.examRegion === "string" ? convertRegionToArr(initialFormData.examRegion) : initialFormData.examRegion, + validFrom: initialFormData.validFrom || null, + validTo: initialFormData.validTo || null, + remark: initialFormData.remark || '', + }); + // 设置监管行业的值 + const selectedIndustry = industryOptionsArray.find((option: { value: any; }) => String(option.value) === String(initialFormData.industryId)); + if (selectedIndustry) { + formRef.current.setFieldsValue({ regulatedIndustry: selectedIndustry.value }); + } else { + formRef.current.setFieldsValue({ regulatedIndustry: '' }); + } + + // 设置试卷名称 + formRef.current.setFieldsValue({ paperId: initialFormData.paperId || '' }); + + // 触发 handlePaperChange 函数更新考试分值和考试时长 + const selectedPaper = allPaperOptionsArray.find((paper: { value: any; }) => String(paper.value) === String(initialFormData.paperId)); + if (selectedPaper && formRef.current) { + // 更新表单中的考试分值和考试时长 + formRef.current.setFieldsValue({ + examScore: selectedPaper.examScore, + examDuration: selectedPaper.examDuration + }); + } + } } catch (error) { console.error('数据加载失败:', error); } }; + fetchData() - fetchData(); }, []); - useEffect(() => { - if (isDataLoaded) { - const initialIndustry = initialFormData.regulatedIndustry; - if (String(initialIndustry) === '') { - setPaperOptions(allPaperOptions); - } else if (initialIndustry) { - const filteredPapers = allPaperOptions.filter(paper => String(paper.regulatedIndustry) === String(initialIndustry)); - setPaperOptions(filteredPapers); - } else { - setPaperOptions(allPaperOptions); - } - - if (formRef.current) { - formRef.current.setFieldsValue({ - examId: initialFormData.examId || '', - examName: initialFormData.examName || '', - examRegion: typeof initialFormData.examRegion === "string" ? convertRegionToArr(initialFormData.examRegion) : initialFormData.examRegion, - validFrom: initialFormData.validFrom || null, - validTo: initialFormData.validTo || null, - remark: initialFormData.remark || '', - }); - - // 设置监管行业的值 - const selectedIndustry = industryOptions.find(option => String(option.value) === String(initialFormData.regulatedIndustry)); - if (selectedIndustry) { - formRef.current.setFieldsValue({ regulatedIndustry: selectedIndustry.value }); - } else { - formRef.current.setFieldsValue({ regulatedIndustry: '' }); - } - - // 设置试卷名称 - formRef.current.setFieldsValue({ paperId: initialFormData.paperId || '' }); - - // 触发 handlePaperChange 函数更新考试分值和考试时长 - handlePaperChange(initialFormData.paperId); - } - } - }, [isDataLoaded, allPaperOptions, initialFormData, industryOptions]); - const handleIndustryChange = (value: string | number) => { if (String(value) === '') { setPaperOptions(allPaperOptions); } else { const filteredPapers = allPaperOptions.filter(paper => String(paper.regulatedIndustry) === String(value)); - setPaperOptions(filteredPapers); - } - if (formRef.current) { - formRef.current.setFieldsValue({ paperId: '' }); // 清空试卷选择 + if (filteredPapers.length > 0) { + setPaperOptions(filteredPapers); + } } + + // @ts-ignore + formRef.current.setFieldsValue({ paperId: '' }); // 清空试卷选择 }; const handlePaperChange = (value: string) => { diff --git a/packages/examination/src/views/exam-online/compoents/ExamListPage.tsx b/packages/examination/src/views/exam-online/compoents/ExamListPage.tsx index 0d563ea..3370545 100644 --- a/packages/examination/src/views/exam-online/compoents/ExamListPage.tsx +++ b/packages/examination/src/views/exam-online/compoents/ExamListPage.tsx @@ -1,8 +1,12 @@ -import React, { useEffect, useState } from 'react'; -import { Table, Input, Button, Select, DatePicker, Modal, Checkbox, message, Form } from 'antd'; +import React, { useEffect, useState, useRef } from 'react'; +import {Table, Input, Button, Select, DatePicker, Modal, Checkbox, message, Form, Space } from 'antd'; +import { + UndoOutlined +} from '@ant-design/icons'; import { Link, withRouter } from 'react-router-dom'; import moment, { Moment } from 'moment'; // 引入 moment -import { getList, doDelete, doCancel, doPublish, getIndustryList } from "api/exam-online/index"; +import { saveQrCode, getList, doDelete, doCancel, doPublish, getIndustryList } from "api/exam-online/index"; +import { QRCode } from 'react-qrcode-logo'; const { Option } = Select; @@ -17,9 +21,11 @@ type Exam = { validTo: string; examDuration: string; publishStatus: 0 | 1 | 2; // 0: 待发布, 1: 已发布, 2: 已撤回 + captcha: string; }; const ExamListPage = ({ history }: { history: any }) => { + const qrCodeRef = useRef(null); const [searchForm, setSearchForm] = useState({ examName: '', paperName: '', @@ -35,6 +41,7 @@ const ExamListPage = ({ history }: { history: any }) => { pageSize: 10, total: 0, }); + const [loading, setLoading] = useState(false); useEffect(() => { const fetchData = async () => { @@ -64,6 +71,7 @@ const ExamListPage = ({ history }: { history: any }) => { // 查询 const handleSearch = async (page = 1) => { + setLoading(true) try { // 构建请求参数 const params = { @@ -82,6 +90,7 @@ const ExamListPage = ({ history }: { history: any }) => { const endIndex = startIndex + pagination.pageSize; setCurrentPageExamList(data.data.slice(startIndex, endIndex)); setPagination({ ...pagination, current: page, total: data.total }); + setLoading(false) } catch (error) { console.error('查询出错:', error); } @@ -190,10 +199,10 @@ const ExamListPage = ({ history }: { history: any }) => { // 编辑 const handleEdit = (examId: number) => { - sessionStorage.setItem('examId', String(examId)); - history.push('/exam-edit'); - // 实现编辑跳转逻辑 - console.log('跳转到编辑页面,examId:', examId); + history.push({ + pathname: '/exam-edit', + state: { examId }, + }); }; const handleDetail = (examId: number) => { @@ -203,11 +212,22 @@ const ExamListPage = ({ history }: { history: any }) => { } const [qrCodeVisible, setQrCodeVisible] = useState(false); + const [examId, setExamId] = useState(''); const [qrCodeData, setQrCodeData] = useState(''); + const [captcha, setCaptcha] = useState(''); + const [examName, setExamName] = useState(''); - const handleGenerateQrCode = (examId: number) => { + const handleGenerateQrCode = (exam: any) => { // 实现生成考试码逻辑 - setQrCodeData(`examId: ${examId}`); + setExamId(exam.examId); + setQrCodeData(exam.examId); + setExamName(exam.examName); + if (exam.captcha) { + setCaptcha(exam.captcha); + } else { + setCaptcha(generateCaptcha()); + } + setQrCodeVisible(true); }; @@ -338,12 +358,12 @@ const ExamListPage = ({ history }: { history: any }) => { key: 'examRegion', }, { - title: '考试有效时间', + title: '考试有效日期', dataIndex: 'validFrom', key: 'validFrom', }, { - title: '考试无效时间', + title: '考试无效日期', dataIndex: 'validTo', key: 'validTo', }, @@ -373,23 +393,27 @@ const ExamListPage = ({ history }: { history: any }) => { title: '操作', key: 'action', render: (cellValue: number, record: Exam) => ( - + ), }, ]; @@ -411,6 +434,43 @@ const ExamListPage = ({ history }: { history: any }) => { handleSearch(pagination.current); }; + const handleDownloadQRCode = () => { + let formData = { + id: examId, + captcha: captcha, + path: qrCodeData + } + saveQrCode(formData).then(res => { + // @ts-ignore + const canvas = qrCodeRef.current.querySelector('canvas'); + if (canvas) { + const dataUrl = canvas.toDataURL('image/png'); + const link = document.createElement('a'); + link.href = dataUrl; + link.download = examName + '-考试码.png'; + link.click(); + setQrCodeVisible(false) + handleSearch(pagination.current); + } + }) + }; + + const handleRefreshQRCode = (examId: any) => { + const str = '/' + Math.floor(Math.random() * 900000); + setQrCodeData(examId + str); + setCaptcha(generateCaptcha()); + } + + const generateCaptcha = () => { + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + let captcha = ''; + for (let i = 0; i < 6; i++) { + const randomIndex = Math.floor(Math.random() * characters.length); + captcha += characters[randomIndex]; + } + return captcha; + } + return (
{ {
{ onChange={handleTableChange} /> 生成考试码} visible={qrCodeVisible} onCancel={() => setQrCodeVisible(false)} - footer={null} + onOk={handleDownloadQRCode} + centered + okText="确认" > - {/**/} + +
+ 验证码:{captcha} +
); diff --git a/packages/examination/src/views/exam-online/compoents/ExamPaperAnalysisPage.tsx b/packages/examination/src/views/exam-online/compoents/ExamPaperAnalysisPage.tsx index 4f2ad28..77f38e4 100644 --- a/packages/examination/src/views/exam-online/compoents/ExamPaperAnalysisPage.tsx +++ b/packages/examination/src/views/exam-online/compoents/ExamPaperAnalysisPage.tsx @@ -98,10 +98,12 @@ const ExamPaperAnalysisPage: React.FC = ({history}) => { setPagination(newPagination); }; - const columns = [ + const columns: any = [ { title: '序号', dataIndex: 'key', + width: 70, + align: 'center', render: (text: any, record: PaperAnalysisDataItem, index: number) => (pagination.current - 1) * pagination.pageSize + index + 1, }, { @@ -175,32 +177,38 @@ const ExamPaperAnalysisPage: React.FC = ({history}) => { {/* 试卷数量行 */} - - -
- 总计 - {totalCount} - + +
+
+
+ 总计 + {totalCount} + +
- -
- 已使用 - {usedCount} - +
+
+
+ 已使用 + {usedCount} + +
- -
- 停用 - {disabledCount} - +
+
+
+ 停用 + {disabledCount} + +
{/* 表格 */} -
-

已使用试卷分析

+
+
已使用试卷分析
{ const handleSelectChange = (value: string) => { console.log('Selected value:', value); + value = !value ? '' : value; if (value === '') { // 选择“全部” setShowIndustryDimension(true); @@ -137,27 +138,50 @@ const Dashboard: React.FC = () => { }; // 环状图配置项生成函数 - const getRingChartOption = (data: { value: number; name: string }[]) => ({ - tooltip: { - trigger: 'item', - formatter: '{a}
{b}: {c} ({d}%)', - }, - legend: { - orient: 'vertical', - right: 10, - top: 'center', - data: data.map(item => item.name), - }, - series: [ - { - name: '占比', - type: 'pie', - radius: ['30%', '50%'], // 设置为环状图 - center: ['40%', '50%'], - data, + const getRingChartOption = (data: { value: number; name: string }[], marginVal: any) => ( + { + tooltip: { + trigger: 'item', + formatter: function (params: { name: string; value: string; percent: string; }) { + return params.name + '
' + params.value + ' (' + params.percent + '%)'; + } }, - ], - }); + legend: { + orient: 'vertical', + right: 10, + top: 'center', + data: data.map(item => item.name), + }, + series: [ + { + name: '占比', + type: 'pie', + radius: ['50%', '75%'], + center: [ `${marginVal}%`, '50%'], + avoidLabelOverlap: false, + itemStyle: { + borderRadius: 3, + borderColor: '#fff', + }, + label: { + show: false, + position: 'center' + }, + emphasis: { + label: { + show: false, + fontSize: 10, + fontWeight: 'bold' + } + }, + labelLine: { + show: false + }, + data: data + } + ] + } + ); const getPieChartOption = (data: { value: number; name: string }[]) => ({ tooltip: { trigger: 'item', @@ -173,8 +197,12 @@ const Dashboard: React.FC = () => { { name: '占比', type: 'pie', - radius: '50%', + radius: '75%', center: ['40%', '50%'], + label: { + show: false, + position: 'center' + }, data, }, ], @@ -185,18 +213,18 @@ const Dashboard: React.FC = () => { {/* 第一行:试题数、试卷数、考试次数 */} -
-

试题{questionCount}

+
+
试题{questionCount}
-
-

试卷{paperCount}

+
+
试卷{paperCount}
-
-

考试{examCount}

+
+
考试{examCount}
@@ -205,14 +233,13 @@ const Dashboard: React.FC = () => { {/* 左半区:题库情况 */}
- 题库情况 - + 监管行业: - {industryOptions.map(option => ( {/* 考试情况 */} - 考试情况 @@ -268,7 +295,7 @@ const Dashboard: React.FC = () => { {/* 试卷情况环状图 */} - 试卷情况 @@ -277,7 +304,7 @@ const Dashboard: React.FC = () => { )} style={{ marginTop: 20 }} > - + diff --git a/packages/examination/src/views/exam-online/exam-edit.tsx b/packages/examination/src/views/exam-online/exam-edit.tsx index a99a0a9..fc9cc51 100644 --- a/packages/examination/src/views/exam-online/exam-edit.tsx +++ b/packages/examination/src/views/exam-online/exam-edit.tsx @@ -4,6 +4,7 @@ import { withRouter, RouteComponentProps } from 'react-router-dom'; import { getExamDataById } from "api/exam-online/index"; import { ExamBasicInfo } from './compoents/ExamEditPage'; import moment, { Moment } from 'moment'; +import { useLocation } from 'react-router-dom'; // 定义 Params 类型 interface Params { @@ -12,6 +13,7 @@ interface Params { // 定义 location.state 的类型 interface LocationState { + examId: any; data?: number; } @@ -30,14 +32,14 @@ interface CustomRouteComponentProps extends RouteComponentProps { hash: string; }; } - class ExamEdit extends Component { constructor(props: CustomRouteComponentProps) { super(props); this.state = { initialFormData: { - examId: '', + examId: props.location.state.examId, examName: '', + industryId: '', regulatedIndustry: '', paperId: '', examScore: '', @@ -52,20 +54,14 @@ class ExamEdit extends Component { } async componentDidMount() { - - // 尝试从 sessionStorage 中获取 examId - const storedExamId = sessionStorage.getItem('examId'); - const examId = storedExamId; - if(storedExamId){ - sessionStorage.removeItem('examId'); - } - + const examId = this.state.initialFormData.examId; try { const response = await getExamDataById(examId); const newInitFormData: ExamBasicInfo = { - examId: response.data.examId, + examId: response.data.id, examName: response.data.examName, - regulatedIndustry: response.data.regulatedIndustry, + industryId: response.data.industryId, + regulatedIndustry: response.data.industryId, paperId: response.data.paperId, examScore: response.data.examScore, examDuration: response.data.examDuration, @@ -75,8 +71,6 @@ class ExamEdit extends Component { remark: response.data.remark }; - console.log('Received examId:', examId); - this.setState({ initialFormData: newInitFormData, isLoading: false diff --git a/packages/examination/src/views/statistical/customerRetention.tsx b/packages/examination/src/views/statistical/customerRetention.tsx index eae7ef7..0114f15 100644 --- a/packages/examination/src/views/statistical/customerRetention.tsx +++ b/packages/examination/src/views/statistical/customerRetention.tsx @@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react'; import {Table, Button, Spin, Space, Modal, Form, Upload, Image, notification} from 'antd'; import TextArea from "antd/es/input/TextArea"; import {getCustomerRetPage, saveCustomerRet} from "../../api/statistical"; -import {serverUrl} from "../../api/axios"; import { getToken, } from '../../api/token' @@ -34,22 +33,6 @@ interface FileRes { const CustomerRetention: React.FC = ({ customer }) => { - // if (!customer) { - // // @ts-ignore - // const { history } = this.props; - // history.push({ - // pathname: '/customer' - // }); - // return (
); - // } - - if (!customer) { - customer = { - customerId: 0, - customerName: 'asda' - } - } - const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [query, setQuery] = useState(null); @@ -141,14 +124,17 @@ const CustomerRetention: React.FC = ({ customer }) => { const showModal2 = (fileUid: string) => { console.log(fileUid) - setFileUrl('./ex/file/download?fileName=' + fileUid + '&token=' + getToken()); + setFileUrl('./api/ex/file/download?fileName=' + fileUid + '&token=' + getToken()); setIsModalOpen2(true); }; const handleOk2 = () => { - const url = serverUrl + fileUrl; + // @ts-ignore + const url = fileUrl; const link = document.createElement('a'); - link.href = url; + if (typeof url === "string") { + link.href = url; + } link.click(); setFileUrl(null); setIsModalOpen2(false); @@ -226,7 +212,7 @@ const CustomerRetention: React.FC = ({ customer }) => { formData.append('file', file); formData.append('fileType', 'CUSTOMER_RETENTION'); try { - const response = await fetch('/ex/file/upload', { + const response = await fetch('/api/ex/file/upload', { method: 'POST', body: formData, headers: { diff --git a/packages/examination/src/views/statistical/enterpriseFile.tsx b/packages/examination/src/views/statistical/enterpriseFile.tsx index e7130b1..deb1f3b 100644 --- a/packages/examination/src/views/statistical/enterpriseFile.tsx +++ b/packages/examination/src/views/statistical/enterpriseFile.tsx @@ -106,7 +106,6 @@ const EnterpriseFile: React.FC = ({ customer }) => { children: res.data.orgRegistrationAddress }]; setItems(baseData); - debugger let policyArr = []; for (var index = 0; index < res.data.policyList.length; index ++) { let policyCoverageList = []; @@ -318,7 +317,7 @@ const EnterpriseFile: React.FC = ({ customer }) => { hazardInvestigationList.push(res.data.serviceStatisticsList[index3].hazardInvestigationList[sIndex]) } policyServiceArr.push({ - policyNumber: res.data.hiveClaimStatisticsList[index3].policyNumber, + policyNumber: res.data.serviceStatisticsList[index3].policyNumber, accidentPreventionList: accidentPreventionList, riskList: riskList, hazardInvestigationList: hazardInvestigationList diff --git a/packages/examination/src/views/statistical/serviceStatistics.tsx b/packages/examination/src/views/statistical/serviceStatistics.tsx index 7cd945f..67f57d0 100644 --- a/packages/examination/src/views/statistical/serviceStatistics.tsx +++ b/packages/examination/src/views/statistical/serviceStatistics.tsx @@ -3,7 +3,6 @@ import {Table, Button, Spin, Radio, DatePicker, Select, Form, Modal} from 'antd' import {getServiceStatPage} from "../../api/statistical"; import type { RadioChangeEvent } from 'antd'; import {dictionary} from "../../api/dict"; -import {serverUrl} from "../../api/axios"; interface Enterprise { key: string; @@ -50,6 +49,13 @@ const App: React.FC = () => { align: 'center', render: (text: string, record: any, index: number) => index + 1 }, + { + title: '数据日期', + dataIndex: 'createdAt', + align: 'center', + width: 150, + key: 'createdAt', + }, { title: '保单号', dataIndex: 'policyNumber', @@ -68,6 +74,20 @@ const App: React.FC = () => { align: 'center', key: 'serviceStatusName', }, + { + title: '启保时间', + dataIndex: 'startDate', + align: 'center', + width: 150, + key: 'startDate', + }, + { + title: '终保时间', + dataIndex: 'doneDate', + align: 'center', + width: 150, + key: 'doneDate', + }, { title: '备注', dataIndex: 'remarks', @@ -169,7 +189,7 @@ const App: React.FC = () => { params['serviceStatus'] = serviceStatus; } const urlParams = new URLSearchParams(params).toString(); - window.open(serverUrl + `./ex/statistics/exportServiceStatList?` + urlParams); + window.open(process.env.REACT_APP_SERVER_URL + `./ex/statistics/exportServiceStatList?` + urlParams); setIsModalOpen(false); };