💥 feat(模块): 添加了个很棒的功能

This commit is contained in:
cclu 2025-03-12 19:21:44 +08:00
parent 271a4ad751
commit facf50c0ae
25 changed files with 1668 additions and 101 deletions

View File

@ -1,10 +1,11 @@
const proxy = {
'/auth': {
target: 'http://home.robot-z.cn:7001',
// target: 'http://home.robot-z.cn:7001',
target: 'https://es.robot-z.cn',
changeOrigin: true,
secure: false,
pathRewrite: { '^/auth': '' },
onProxyRes: function(proxyRes) {
onProxyRes: function (proxyRes) {
proxyRes.headers['Access-Control-Allow-Origin'] = '*';
proxyRes.headers['Access-Control-Allow-Methods'] = 'GET,PUT,POST,DELETE,OPTIONS';
proxyRes.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization';

View File

@ -28,17 +28,22 @@ export default [
{
path: '/examine/index',
name: '考评分类管理',
component: "@/pages/examine/index",
component: "@/pages/examine/index/index",
},
{
path: '/examine/question',
name: '考核问题管理',
component: "@/pages/examine/question",
component: "@/pages/examine/question/index",
},
{
path: '/examine/modal',
name: '考核模版管理',
component: "@/pages/examine/modal",
component: "@/pages/examine/modal/index",
},
{
path: '/examine/record',
name: '考核记录管理',
component: "@/pages/examine/record/index",
}
]

View File

@ -16,6 +16,7 @@
"crypto-js": "^4.2.0",
"dva": "^3.0.0-alpha.1",
"moment": "^2.30.1",
"qrcode": "^1.5.4",
"umi": "^4.3.24",
"xlsx": "^0.18.5",
"xlsx-style-fixed": "^0.0.4"

View File

@ -8,6 +8,7 @@ import ProForm, { ProFormText } from "@ant-design/pro-form";
import { Button, Col, FormInstance, Row, Tree } from "antd";
// import { getServerpartTree } from "@/services/options";
import useRequest from "@ahooksjs/use-request";
import { getMerchantShopTree, getServerpartTree } from "./service";
// import './style.less'
// import { getMerchantShopTree } from "@/pages/Setting/Users/service";
@ -26,6 +27,9 @@ type DetailProps = {
noWj?: any // 把万佳商贸隐藏
}
const LeftSelectTree = ({ setSelectedId, reload, actionRef, currentUser, width, otherFun, setCollapsible, collapsible, haveTest, handleGetLeftTreeData, noWj }: DetailProps) => {
console.log('currentUser', currentUser);
const searchTreeRef = useRef<FormInstance>();
// 默认的服务区树
const [allTreeViews, setAllTreeViews] = useState<any>()
@ -37,7 +41,7 @@ const LeftSelectTree = ({ setSelectedId, reload, actionRef, currentUser, width,
if (currentUser?.UserPattern === 2000) {
data = await getMerchantShopTree({ BusinessManId: currentUser?.BusinessManID, ShowShop: false });
} else {
data = await getServerpartTree(currentUser?.ProvinceCode, currentUser?.CityAuthority, true, true, true)
data = await getServerpartTree(currentUser?.provinceCode, currentUser?.CityAuthority, true, true, true, false, 1000)
}
console.log('datatree', data);
@ -233,5 +237,5 @@ const LeftSelectTree = ({ setSelectedId, reload, actionRef, currentUser, width,
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser,
currentUser: user.data
}))(LeftSelectTree);

View File

@ -0,0 +1,61 @@
import request from "@/utils/requestOld"
export async function getServerpartTree(ProvinceCode?: number | string, ServerpartCodes?: string,
ShowWholePower?: boolean, ShowSPRegion?: boolean, ShowRoyalty?: boolean | false, ShowCompactCount?: boolean | false, StatisticsType?: number): Promise<ServerpartTree[]> {
// ShowRoyalty 无论传入什么都是false
const data = await request(`/BaseInfo/GetServerpartTree?
ProvinceCode=${ProvinceCode || ''}&ServerpartCodes=${ServerpartCodes || ''}&
ShowWholePower=${ShowWholePower || false}&ShowWholePower=${ShowSPRegion || true}&
ShowRoyalty=${false}&ShowCompactCount=${ShowCompactCount || false}&StatisticsType=${StatisticsType || ''}`, {
method: 'GET',
});
if (data.Result_Code !== 100) {
return [];
}
return data.Result_Data.List;
}
export async function getMerchantShopTree(params: { BusinessManId?: any, provinceCode?: number }) {
const data = await request(`/FrameWork/GetMerchantShopTree`, {
method: 'GET',
params
})
if (data.Result_Code !== 100) {
return []
}
const treeTable = wrapTreeNode(data.Result_Data.List);
return [...treeTable];
}
export function wrapTreeNode(data: any[]) {
const wrapData: any = data.map((item: any) => {
const node = { ...item.node };
if (item.children && item.children.length > 0) {
node.children = wrapTreeNode(item.children);
}
return node
});
return wrapData;
}
export async function handleGetServerpartDDL(params: any) {
const data = await request(`/BaseInfo/GetServerpartDDL`, {
method: 'GET',
params
})
if (data.Result_Code !== 100) {
return []
}
return data.Result_Data.List
}

View File

@ -193,6 +193,13 @@ const BasicLayout: FC<{ user: UserModelState, global: ProfileModelState, dispatc
hideInMenu: false,
name: "考核模版管理",
path: "/examine/modal",
},
{
SYSTEMMODULE_DESC: "",
guid: "5",
hideInMenu: false,
name: "考核记录管理",
path: "/examine/record",
}
]

View File

@ -235,6 +235,11 @@ const UserModel: UserModelType = {
path: '/examine/modal',
name: '考核模版管理',
component: "@/pages/examine/modal",
},
{
path: '/examine/record',
name: '考核记录管理',
component: "@/pages/examine/record",
}
]
@ -269,6 +274,7 @@ const UserModel: UserModelType = {
'/examine/index',
'/examine/modal',
'/examine/question',
'/examine/record',
],
rootSubmenuKeys: handleGetRootSubmenuKeys(menuRes.data),
indexAllMenuItemById: handleGetEachDatumFromNestedDataByKey(menuRes.data, 'id'),

View File

@ -11,6 +11,9 @@ const authority: PageAuthority = {
'/examine/question': [
'/examine/question',
],
'/examine/record': [
'/examine/record',
],
};

View File

@ -1,20 +1,17 @@
import { connect } from "umi";
import { useRef, useState } from "react";
import { Button, message, Modal, Space, type FormInstance } from "antd";
import { Children, useRef, useState } from "react";
import { Button, message, Modal, Popconfirm, Space, type FormInstance } from "antd";
import type { ActionType } from "@ant-design/pro-table";
import ProTable from "@ant-design/pro-table";
import moment from "moment";
import LeftSelectTree from "@/components/leftSelectTree";
import { handleGetAddExamineType, handleGetExamineTypeList } from "./service";
import { ProForm, ProFormSwitch, ProFormText, ProFormTextArea } from "@ant-design/pro-components";
import LeftSelectTree from "@/components/leftSelectTree/leftSelectTree";
import { handleGetAddExamineType, handleGetDeleteExamineType, handleGetEditExamineType, handleGetExamineTypeList, handleGetExamineTypeTreeList } from "./service";
import { ProForm, ProFormSwitch, ProFormText, ProFormTextArea, ProFormTreeSelect } from "@ant-design/pro-components";
const examineIndex: React.FC<{ currentUser: any }> = (props) => {
console.log('props', props);
const { currentUser } = props
console.log('currentUser', currentUser);
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
// 弹出框的表单实例
@ -23,12 +20,15 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
const [searchParams, setSearchParams] = useState<any>()
// 打开新增的悬浮框
const [openAddModal, setOpenAddModal] = useState<boolean>(false)
// 当前行数据
const [currentRow, setCurrentRow] = useState<any>()
const columns: any = [
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "name",
align: 'left',
ellipsis: true,
width: 200,
hideInSearch: true
},
@ -36,12 +36,14 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "description",
align: 'left',
ellipsis: true,
width: 250,
hideInSearch: true
},
{
title: "有效状态",
dataIndex: "status",
ellipsis: true,
align: 'center',
width: 150,
hideInSearch: true,
@ -52,6 +54,7 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
{
title: "创建时间",
dataIndex: "createdAt",
ellipsis: true,
align: 'center',
width: 200,
hideInSearch: true,
@ -62,6 +65,7 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
{
title: "更新时间",
dataIndex: "updatedAt",
ellipsis: true,
align: 'center',
width: 200,
hideInSearch: true,
@ -77,14 +81,48 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
width: 150,
render: (_: any, record: any) => {
return <Space>
<a></a>
<a></a>
<a onClick={() => {
console.log('record', record);
setCurrentRow(record)
setOpenAddModal(true)
}}></a>
<Popconfirm
title={"确认删除?"}
onConfirm={() => {
console.log('record', record);
handleDeleteType(record.id)
}}
>
<a></a>
</Popconfirm>
</Space>
}
}
]
// 删除分类
const handleDeleteType = async (id: number) => {
const data = await handleGetDeleteExamineType(id)
if (data.code === 200) {
message.success(data.message)
actionRef.current?.reload()
}
}
// 若children没有值 则变为null
const handleGetNoChildren = (list: any) => {
if (list && list.length > 0) {
list.forEach((item) => {
if (item.children && item.children.length > 0) {
item.children = handleGetNoChildren(item.children)
} else {
item.children = null
}
})
}
return list
}
return (
<div>
@ -103,12 +141,18 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
expandable={{
expandRowByClick: true
}}
rowKey={(record) => {
return `${record?.id}`
}}
scroll={{ y: 'calc(100vh - 400px)' }}
headerTitle={<span style={{ color: "#1890ff", fontSize: 14, fontWeight: 600 }}></span>}
search={{ span: 6 }}
request={async (params) => {
const data = await handleGetExamineTypeList()
const req = {}
let data = await handleGetExamineTypeTreeList(req)
console.log('table', data);
if (data && data.length > 0) {
data = handleGetNoChildren(data)
return { data, success: true }
}
return { data: [], success: true }
@ -116,6 +160,7 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
toolbar={{
actions: [
<Button type="primary" onClick={(e) => {
console.log('current', currentRow);
setOpenAddModal(true)
}}>
@ -127,40 +172,85 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
</div>
<Modal
title="分类"
title={`${currentRow?.id ? '编辑' : '创建'}分类`}
open={openAddModal}
destroyOnClose
onOk={() => {
modalRef.current?.validateFields().then(async (res) => {
console.log('res', res);
const req = {
name: res.name,
description: res.description,
sortOrder: "1",
status: res.status,
operator: currentUser?.operator
let req = {}
let data = {}
if (currentRow?.id) {
req = {
...currentRow,
parentId: res.parentId,
name: res.name,
description: res.description,
status: res.status,
operator: currentUser?.operator
}
data = await handleGetEditExamineType(req)
} else {
req = {
parentId: res.parentId,
name: res.name,
description: res.description,
sortOrder: "1",
status: res.status,
operator: currentUser?.operator
}
data = await handleGetAddExamineType(req)
}
const data = await handleGetAddExamineType(req)
console.log('req', req);
console.log('data', data);
if (data.code === 200) {
modalRef.current?.resetFields()
message.success(data.message)
setOpenAddModal(false)
actionRef.current?.reload()
setCurrentRow(undefined)
} else {
message.error(data.message)
}
})
}}
onCancel={() => {
modalRef.current?.setFieldsValue({})
setCurrentRow(undefined)
setOpenAddModal(false)
}}
>
<ProForm
formRef={modalRef}
submitter={false}
onFinish={async (values) => {
console.log('values', values);
}}
>
<ProForm formRef={modalRef} submitter={false} request={() => {
console.log('currentRow', currentRow);
return { ...currentRow }
}}>
<ProFormTreeSelect
label={"类别层级"}
name={"parentId"}
request={async () => {
const req = {}
const data = await handleGetExamineTypeList(req)
console.log('dsadas', data);
let res = [
{
name: '/',
id: 0,
children: data
}
]
return res
}}
fieldProps={{
treeDefaultExpandedKeys: [0],
fieldNames: {
label: "name",
value: "id"
},
}}
rules={[
{ required: true, message: '请选择类别层级!' }
]}
/>
<ProFormText
label={"类别名称"}
name={"name"}
@ -175,11 +265,9 @@ const examineIndex: React.FC<{ currentUser: any }> = (props) => {
<ProFormSwitch
label={"有效状态"}
name={"status"}
initialValue={true}
initialValue={currentRow?.id ? currentRow.status : true}
/>
</ProForm>
</Modal>
</div>
)

View File

@ -0,0 +1,37 @@
import request from "@/utils/request"
// 拿到类别列表接口
export async function handleGetExamineTypeList(params?: any) {
const data = await request.get('/question-categories', params)
if (data.code === 200) {
return data.data
}
return []
}
// 拿树形的
export async function handleGetExamineTypeTreeList(params?: any) {
const data = await request.get('/question-categories/tree', params)
if (data.code === 200) {
return data.data
}
return []
}
// 新增类别列表接口
export async function handleGetAddExamineType(params: any) {
const data = await request.post('/question-categories', params)
return data
}
// 删除类别接口
export async function handleGetDeleteExamineType(params: any) {
const data = await request.get(`/question-categories/delete/${params}`)
return data
}
// 编辑分类接口
export async function handleGetEditExamineType(params: any) {
const data = await request.post(`/question-categories/${params.id}`, params)
return data
}

View File

@ -1,21 +0,0 @@
import { UserConnectedProps } from "@/models/user";
import { connect } from "umi";
type DetailProps = {
}
const modal = ({ }: DetailProps) => {
return (
<div>
modal
</div>
)
}
export default connect(
({ user }: { user: UserConnectedProps['user'] }) => ({
user
}),
)(modal);

View File

@ -0,0 +1,553 @@
import LeftSelectTree from "@/components/leftSelectTree/leftSelectTree";
import { handleGetServerpartDDL } from "@/components/leftSelectTree/service";
import { ActionType, FormInstance, ProCard, ProForm, ProFormList, ProFormSelect, ProFormSwitch, ProFormText, ProFormTextArea, ProTable } from "@ant-design/pro-components";
import { Button, Col, message, Modal, Popconfirm, Row, Space } from "antd";
import moment from "moment";
import { useRef, useState } from "react";
import { connect } from "umi";
import { handleAddTemplates, handleDeleteTemplates, handleGetQuestionList, handleGetTemplatesList, handleUpdateTemplates, handleUploadFile } from "./service";
import { handleGetExamineTypeTreeList } from "../index/service";
import QRCode from 'qrcode';
import { base64ToFile } from "@/utils/publicMethods";
const examineModal: React.FC<{ currentUser: any }> = (props) => {
const { currentUser } = props
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
const modalActionRef = useRef<ActionType>();
const modalFormRef = useRef<FormInstance>();
// 弹出框的表单实例
const modalRef = useRef<FormInstance>()
// 树相关的属性和方法
const [selectedId, setSelectedId] = useState<string>()
const [collapsible, setCollapsible] = useState<boolean>(false)
// 显示新增点位的悬浮框
const [showPlaceModal, setShowPlaceModal] = useState<boolean>(false)
// 当前点击选中的问题行
const [currentRow, setCurrentRow] = useState<any>()
// 服务区的枚举
const [serviceObj, setServiceObj] = useState<any>()
// 生成的二维码的初始
const [qrCodeUrl, setQrCodeUrl] = useState<string>()
// 选择问题的悬浮框
const [selectQuestionModal, setSelectQuestionModal] = useState<boolean>(false)
// 选择的问题列表 详情
const [selectedQuestionDetail, setSelectedQuestionDetail] = useState<any>()
// 选择的问题列表的id
const [selectedQuestionId, setSelectedQuestionId] = useState<any>()
const columns: any = [
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "serverPartName",
hideInSearch: true,
width: 200,
ellipsis: true
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "title",
hideInSearch: true,
width: 200,
ellipsis: true
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "status",
hideInSearch: true,
align: 'center',
width: 100,
ellipsis: true,
render: (_, record) => {
return record?.status ? '有效' : '无效'
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "updatedAt",
hideInSearch: true,
align: 'center',
width: 150,
ellipsis: true,
render: (_, record) => {
return record?.updatedAt ? moment(record?.updatedAt).format('YYYY-MM-DD HH:mm:ss') : ''
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "description",
hideInSearch: true,
width: 200,
ellipsis: true
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "questions",
hideInSearch: true,
width: 200,
ellipsis: true,
render: (_, record) => {
return record?.questions && record?.questions.length > 0 ? JSON.stringify(record?.questions) : ''
}
},
{
title: '操作',
dataIndex: 'option',
align: 'center',
hideInSearch: true,
width: 150,
render: (_: any, record: any) => {
return <Space>
<a onClick={() => {
console.log('record', record);
setCurrentRow(record)
setShowPlaceModal(true)
}}></a>
<Popconfirm
title={"确认删除?"}
onConfirm={async () => {
deleteQuestion(record?.id)
}}
>
<a></a>
</Popconfirm>
</Space>
}
}
]
// 弹出框里面的
const modalColumns: any = [
{
title: "问题分类",
dataIndex: "id",
hideInTable: true,
valueType: 'treeSelect',
request: async () => {
const data = await handleGetExamineTypeTreeList()
console.log('data', data);
return data && data.length > 0 ? data.map(item => ({
title: item.name,
value: item.id,
children: item.children?.map((child: any) => ({
title: child.name,
value: child.id,
children: child.children || []
})) || []
})) : []
},
fieldProps: {
multiple: false,
treeDefaultExpandAll: true,
showSearch: true,
treeNodeFilterProp: 'title',
placeholder: '请选择问题分类'
}
},
{
title: "考核内容",
dataIndex: "title",
width: 200,
ellipsis: true,
hideInSearch: true
},
{
title: "考核选项",
dataIndex: "options",
width: 500,
ellipsis: true,
hideInSearch: true,
render: (_, record) => {
return record?.options && record?.options.length > 0 ? JSON.stringify(record?.options) : ""
}
}
]
// 删除模版
const deleteQuestion = async (id: number) => {
const data = await handleDeleteTemplates({ id: id })
if (data.code === 200) {
message.success(data.message)
actionRef.current?.reload()
}
}
return (
<div style={{ backgroundColor: '#fff', display: 'flex' }}>
{/* <LeftSelectTree setSelectedId={setSelectedId} setCollapsible={setCollapsible} collapsible={collapsible} currentUser={currentUser} /> */}
<div style={{
// width: !collapsible ? 'calc(100% - 300px)' : 'calc(100% - 60px)',
width: "100%",
paddingTop: 0,
paddingBottom: 0,
paddingRight: 0
}}>
<ProTable
actionRef={actionRef}
formRef={formRef}
columns={columns}
bordered
expandable={{
expandRowByClick: true
}}
headerTitle={<span style={{ color: "#1890ff", fontSize: 14, fontWeight: 600 }}></span>}
search={{ span: 6 }}
request={async () => {
const req: any = {
}
const data = await handleGetTemplatesList()
if (data && data.length > 0) {
return { data, success: true }
}
return { data: [], success: true }
}}
toolbar={{
actions: [
<Button type="primary" onClick={(e) => {
setShowPlaceModal(true)
}}>
</Button>
]
}}
>
</ProTable>
<Modal
width={1200}
title={`${currentRow?.id ? '编辑' : '创建'}点位`}
open={showPlaceModal}
destroyOnClose
onOk={() => {
modalRef.current?.validateFields().then(async (res) => {
console.log('res', res);
console.log('currentRow', currentRow);
let req = {}
let data = {}
if (currentRow?.id) {
let questions: any = []
if (selectedQuestionDetail && selectedQuestionDetail.length > 0) {
selectedQuestionDetail.forEach((item) => {
questions.push({
questionId: item.id,
isRequired: item.required,
sortOrder: item.sortOrder
})
})
} else {
// 判断是否有改动 一样 说明没改动 那么把老的拿进去就行
if (currentRow?.questionnaireTemplateQuestions.length === res.questions.length) {
if (currentRow?.questionnaireTemplateQuestions && currentRow?.questionnaireTemplateQuestions.length > 0) {
currentRow?.questionnaireTemplateQuestions.forEach((item) => {
questions.push({
questionId: item.question.id,
isRequired: item.question.required,
sortOrder: item.question.sortOrder
})
})
}
} else {
// 不一样 说明有删除 不然走的是第一个
if (res.questions && res.questions.length > 0) {
res.questions.forEach((item) => {
questions.push({
questionId: item.id,
isRequired: item.required,
sortOrder: item.sortOrder
})
})
}
}
}
req = {
...currentRow,
title: res.title,
serverPartName: serviceObj ? serviceObj[res.serverPartId] : "",
serverPartId: res.serverPartId,
questions: questions && questions.length > 0 ? questions : "",
operator: currentUser?.operator,
status: res.status,
description: res.description
}
data = await handleUpdateTemplates(req)
} else {
let questions: any = []
if (selectedQuestionDetail && selectedQuestionDetail.length > 0) {
selectedQuestionDetail.forEach((item) => {
questions.push({
questionId: item.id,
isRequired: item.required,
sortOrder: item.sortOrder
})
})
}
req = {
title: res.title,
placeName: "",
placeId: 0,
serverPartName: serviceObj ? serviceObj[res.serverPartId] : "",
serverPartId: res.serverPartId,
// qrUrl: "",
questions: questions && questions.length > 0 ? questions : "",
operator: currentUser?.operator,
status: res.status,
description: res.description
}
data = await handleAddTemplates(req)
console.log('datadsadsa1', data.data);
const myQRCodeDataUrl = await QRCode.toDataURL(`pages/walkAroundManager/index?id=${data.data.id}`);
const file = base64ToFile(myQRCodeDataUrl, `wenjuan${data.data.id}.png`);
console.log('file', file);
const formData = new FormData();
formData.append("file", file, `wenjuan${data.data.id}.png`); // 确保文件名也传递
const fileData = await handleUploadFile(formData)
console.log('fileData', fileData);
let imgUrl: string = `https://es.robot-z.cn/${fileData.data.path}`
await handleUpdateTemplates({
...data.data,
qrUrl: imgUrl
})
setQrCodeUrl(imgUrl)
// setQrCodeUrl(myQRCodeDataUrl)
}
console.log('datadsadsa', data);
if (data.code === 200) {
// modalRef.current?.resetFields()
message.success(data.message)
// setShowPlaceModal(false)
actionRef.current?.reload()
// setCurrentRow(undefined)
} else {
message.error(data.message)
}
})
}}
onCancel={() => {
modalRef.current?.resetFields()
setShowPlaceModal(false)
setCurrentRow(undefined)
setQrCodeUrl(undefined)
}}
>
<ProForm formRef={modalRef} submitter={false} request={() => {
console.log('currentRow', currentRow);
let questionsList: any = []
let keyList: any = []
if (currentRow?.questionnaireTemplateQuestions && currentRow?.questionnaireTemplateQuestions.length > 0) {
console.log('1');
currentRow?.questionnaireTemplateQuestions.forEach((item) => {
console.log('2');
if (item.question) {
let obj = JSON.parse(JSON.stringify(item.question))
obj.text = obj.title
obj.mark = JSON.stringify(obj.options)
keyList.push(obj.id)
questionsList.push(obj)
}
})
}
// setSelectedQuestionDetail
setSelectedQuestionId(keyList)
return {
...currentRow,
serverPartId: currentRow.serverPartId.toString(),
questions: questionsList
}
}}>
<Row gutter={8}>
<Col span={8}>
<ProFormSelect
label={"服务区名"}
name={"serverPartId"}
request={async () => {
const req = {
ProvinceCode: currentUser?.provinceCode,
StatisticsType: 1000
}
const data = await handleGetServerpartDDL(req)
let obj: any = {}
if (data && data.length > 0) {
data.forEach((item) => {
obj[item.value] = item.label
})
}
setServiceObj(obj)
return data
}}
fieldProps={{
showSearch: true,
}}
rules={[{
required: true,
message: "请选择服务区!"
}]}
/>
</Col>
<Col span={8}>
<ProFormText
label={"点位名称"}
name={"title"}
rules={[{
required: true,
message: "请输入点位名称!"
}]}
/>
</Col>
<Col span={8}>
<ProFormSwitch
label={"有效状态"}
name={"status"}
initialValue={currentRow?.id ? currentRow.status : true}
/>
</Col>
<Col span={20}>
<ProFormList
name="questions"
label="考核列表"
initialValue={[]}
creatorButtonProps={{
position: 'bottom',
creatorButtonText: '添加选项',
style: { display: 'none' },
onClick: (e) => {
console.log('e', e);
}
}}
copyIconProps={false}
style={{ width: '100%' }}
itemContainerStyle={{ width: '100%' }}
itemRender={({ listDom, action }, { record, index }) => (
<div style={{ width: '100%', display: 'flex', alignItems: 'flex-start', marginBottom: '10px' }}>
<div style={{ flex: 1, width: '100%' }}>{listDom}</div>
<div style={{ marginLeft: '8px', marginTop: '30px' }}>{action}</div>
</div>
)}
>
<Row gutter={6} style={{ width: '100%', margin: 0 }}>
<Col span={8}>
<ProFormTextArea
name="text"
label="考核内容"
fieldProps={{
style: { width: '100%' }
}}
/>
</Col>
<Col span={16}>
<ProFormTextArea
name="mark"
label="考核标准"
/>
</Col>
</Row>
</ProFormList>
</Col>
<Col span={4}>
<Button type={"primary"} onClick={() => {
setSelectQuestionModal(true)
}}></Button>
</Col>
<Col span={24}>
<ProFormTextArea
label={"备注说明"}
name={"description"}
/>
</Col>
<Col span={24}>
<ProFormTextArea
label={"二维码URL"}
name={"qrUrl"}
/>
</Col>
<Col span={24}>
{
qrCodeUrl || currentRow?.qrUrl ?
<img style={{ width: "150px", height: "150px" }} src={qrCodeUrl || currentRow?.qrUrl} /> : ""
}
</Col>
</Row>
</ProForm>
</Modal>
<Modal
width={1400}
title={`点位`}
open={selectQuestionModal}
destroyOnClose
onOk={() => {
console.log('selectedQuestionDetail', selectedQuestionDetail);
// 显示的问题列表
let showQuestion: any = []
if (selectedQuestionDetail && selectedQuestionDetail.length > 0) {
selectedQuestionDetail.forEach((item) => {
showQuestion.push({ text: item.title, mark: item.options ? JSON.stringify(item.options) : "" })
})
}
modalRef.current?.setFieldsValue({
questions: showQuestion
})
setSelectQuestionModal(false)
}}
onCancel={() => {
setSelectQuestionModal(false)
}}
>
<ProTable
actionRef={modalActionRef}
formRef={modalFormRef}
columns={modalColumns}
rowKey={"id"}
scroll={{ y: 'calc(100vh - 500px)' }}
request={async (params) => {
console.log('查询参数:', params);
const req: any = {
categoryId: params.id
}
const data = await handleGetQuestionList(req)
if (data && data.length > 0) {
return { data, success: true }
}
return { data: [], success: true }
}}
rowSelection={{
type: "checkbox",
defaultSelectedRowKeys: selectedQuestionId,
onChange: (selectedRowKeys, selectedRows) => {
setSelectedQuestionDetail(selectedRows)
setSelectedQuestionId(selectedRowKeys)
}
}}
/>
</Modal>
</div>
</div >
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.data
}))(examineModal);

View File

@ -0,0 +1,45 @@
import requestOld from "@/utils/requestOld"
import request from "@/utils/request"
// 拿到模版id列表 去绑定服务区的多个站点信息 的列表接口
export async function handleGetTemplatesList(params?: any) {
const data = await request.get('/questionnaire-templates', params)
if (data.code === 200) {
return data.data
}
return []
}
// 新建模版
export async function handleAddTemplates(params?: any) {
const data = await request.post('/questionnaire-templates', params)
return data
}
// 更新模版
export async function handleUpdateTemplates(params?: any) {
const data = await request.post(`/questionnaire-templates/${params.id}`, params)
return data
}
// 删除模版
export async function handleDeleteTemplates(params?: any) {
const data = await request.get(`/questionnaire-templates/delete/${params.id}`)
return data
}
export async function handleGetQuestionList(params?: any) {
const data = await request.get(`/questions?categoryId=${params.categoryId}`,)
if (data.code === 200) {
return data.data
}
return []
}
// 上传图片的oss接口
export async function handleUploadFile(params?: any) {
const data = await request.post(`/oss/upload`, params)
return data
}

View File

@ -1,21 +0,0 @@
import { UserConnectedProps } from "@/models/user";
import { connect } from "umi";
type DetailProps = {
}
const question = ({ }: DetailProps) => {
return (
<div>
question
</div>
)
}
export default connect(
({ user }: { user: UserConnectedProps['user'] }) => ({
user
}),
)(question);

View File

@ -0,0 +1,358 @@
import { ActionType, FormInstance, ProForm, ProFormDigit, ProFormList, ProFormRadio, ProFormSelect, ProFormSwitch, ProFormText, ProFormTextArea, ProFormTreeSelect, ProTable } from "@ant-design/pro-components";
import { Button, Col, message, Modal, Popconfirm, Row, Space } from "antd";
import { useRef, useState } from "react";
import { connect } from "umi";
import { handleAddQuestion, handleDeleteQuestion, handleEditQuestion, handleGetQuestionList } from "./service";
import { handleGetExamineTypeList, handleGetExamineTypeTreeList } from "../index/service";
import moment from "moment";
const examineQuestion: React.FC<{ currentUser: any }> = (props) => {
const { currentUser } = props
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
// 显示新增问题的悬浮框
const [showQuestionModal, setShowQuestionModal] = useState<boolean>(false)
// 当前点击选中的问题行
const [currentRow, setCurrentRow] = useState<any>()
// 弹出框的表单实例
const modalRef = useRef<FormInstance>()
// 问题分类的枚举
const [categoryIdObj, setCategoryIdObj] = useState<any>()
const columns: any = [
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "description",
width: 200,
hideInSearch: true,
ellipsis: true
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "title",
width: 200,
hideInSearch: true,
ellipsis: true
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "type",
width: 200,
hideInSearch: true,
ellipsis: true,
render: (_, record) => {
let questionType: string = record?.type && record?.type.split('_') && record?.type.split('_').length > 0 ? record?.type.split('_')[0] : ''
return questionType === 'radio' ? '单选' : "多选"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "required",
width: 100,
hideInSearch: true,
ellipsis: true,
render: (_, record) => {
return record?.required ? '是' : "否"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "options",
width: 150,
hideInSearch: true,
ellipsis: true,
render: (_, record) => {
return record?.options && record?.options.length > 0 ? JSON.stringify(record?.options) : ''
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "updatedAt",
width: 150,
hideInSearch: true,
ellipsis: true,
render: (_, record) => {
return record?.updatedAt ? moment(record?.updatedAt).format('YYYY-MM-DD HH:mm:ss') : ''
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "operator",
width: 150,
hideInSearch: true,
ellipsis: true
},
{
title: '操作',
dataIndex: 'option',
align: 'center',
hideInSearch: true,
width: 150,
render: (_: any, record: any) => {
return <Space>
<a onClick={() => {
console.log('record', record);
setCurrentRow(record)
setShowQuestionModal(true)
}}></a>
<Popconfirm
title={"确认删除?"}
onConfirm={async () => {
deleteQuestion(record?.id)
}}
>
<a></a>
</Popconfirm>
</Space>
}
}
]
// 删除分类
const deleteQuestion = async (id: number) => {
const data = await handleDeleteQuestion({ id: id })
if (data.code === 200) {
message.success(data.message)
actionRef.current?.reload()
}
}
return (
<div>
<div style={{
width: '100%',
paddingTop: 0,
paddingBottom: 0,
paddingRight: 0
}}>
<ProTable
actionRef={actionRef}
formRef={formRef}
columns={columns}
bordered
expandable={{
expandRowByClick: true
}}
headerTitle={<span style={{ color: "#1890ff", fontSize: 14, fontWeight: 600 }}></span>}
search={{ span: 6 }}
request={async (params) => {
const data = await handleGetQuestionList()
console.log('data', data);
if (data && data.length > 0) {
return { data, success: true }
}
return { data: [], success: true }
}}
toolbar={{
actions: [
<Button type="primary" onClick={(e) => {
setShowQuestionModal(true)
}}>
</Button>
]
}}
/>
</div>
<Modal
width={800}
title={`${currentRow?.id ? '编辑' : '创建'}问题`}
open={showQuestionModal}
destroyOnClose
onOk={() => {
modalRef.current?.validateFields().then(async (res) => {
let req = {}
let data = {}
if (currentRow?.id) {
req = {
...currentRow,
categoryId: res.categoryId,// 题目id
type: `${res.selectType === 1 ? 'radio' : 'checked'}_choice`,// 题目类型
title: res.title,// 问题内容
required: res.required,// 是否必填
options: res.options,
status: res.status,
operator: currentUser?.operator,
description: `${res.categoryId ? categoryIdObj[res.categoryId] : ''}`
}
data = await handleEditQuestion(req)
} else {
req = {
categoryId: res.categoryId,// 题目id
type: `${res.selectType === 1 ? 'radio' : 'checked'}_choice`,// 题目类型
title: res.title,// 问题内容
required: res.required,// 是否必填
options: res.options,
sortOrder: 1,
status: res.status,
operator: currentUser?.operator,
defaultScore: 0,
images: [],
description: `${res.categoryId ? categoryIdObj[res.categoryId] : ''}`
}
data = await handleAddQuestion(req)
}
console.log('datadsadsa', data);
if (data.code === 200) {
modalRef.current?.resetFields()
message.success(data.message)
setShowQuestionModal(false)
actionRef.current?.reload()
setCurrentRow(undefined)
} else {
message.error(data.message)
}
})
}}
onCancel={() => {
modalRef.current?.resetFields()
setShowQuestionModal(false)
setCurrentRow(undefined)
}}
>
<ProForm formRef={modalRef} submitter={false} request={() => {
console.log('currentRow', currentRow);
return {
...currentRow,
selectType: currentRow.type.split('_')[0] === 'checked' ? 2 : 1
}
}}>
<Row gutter={8}>
<Col span={12}>
<ProFormTreeSelect
label={"问题分类"}
name={"categoryId"}
rules={[
{ required: true, message: '请选择问题分类!' }
]}
request={async () => {
const req = {}
const data = await handleGetExamineTypeTreeList(req)
console.log('dsadas', data);
let res = [
{
name: '/',
id: 0,
children: data
}
]
let obj: any = {}
const labelList = await handleGetExamineTypeList()
if (labelList && labelList.length > 0) {
labelList.forEach((item) => {
obj[item.id] = item.name
})
}
setCategoryIdObj(obj)
return res
}}
fieldProps={{
treeDefaultExpandedKeys: [0],
fieldNames: {
label: "name",
value: "id"
},
showSearch: true,
filterTreeNode: (input, treeNode) => {
return (treeNode?.name ?? '').toLowerCase().indexOf(input.toLowerCase()) >= 0;
},
treeNodeFilterProp: 'name'
}}
/>
</Col>
<Col span={12}>
<ProFormText
label={"问题内容"}
name={"title"}
rules={[
{ required: true, message: '请输入问题!' }
]}
/>
</Col>
<Col span={6}>
<ProFormSwitch
label={"是否必填"}
name={"required"}
initialValue={currentRow?.id ? currentRow.required : true}
/>
</Col>
<Col span={6}>
<ProFormSwitch
label={"有效状态"}
name={"status"}
initialValue={currentRow?.id ? currentRow.status : true}
/>
</Col>
<Col span={6}>
<ProFormRadio.Group
label={"题目类型"}
name={"selectType"}
fieldProps={{
options: [{ label: "单选", value: 1 }, { label: "多选", value: 2 }],
}}
initialValue={1}
/>
</Col>
<Col span={24}>
<ProFormList
name="options"
label="选项内容"
initialValue={[]}
creatorButtonProps={{
position: 'bottom',
creatorButtonText: '添加选项'
}}
copyIconProps={false}
style={{ width: '100%' }}
itemContainerStyle={{ width: '100%' }}
itemRender={({ listDom, action }, { record, index }) => (
<div style={{ width: '100%', display: 'flex', alignItems: 'flex-start', marginBottom: '10px' }}>
<div style={{ flex: 1, width: '100%' }}>{listDom}</div>
<div style={{ marginLeft: '8px', marginTop: '30px' }}>{action}</div>
</div>
)}
>
<Row gutter={6} style={{ width: '100%', margin: 0 }}>
<Col span={16}>
<ProFormTextArea
name="text"
label="选项"
fieldProps={{
style: { width: '100%' }
}}
/>
</Col>
<Col span={8}>
<ProFormDigit
name="mark"
label="分值"
fieldProps={{
style: { width: '100%' },
defaultValue: 0
}}
/>
</Col>
</Row>
</ProFormList>
</Col>
</Row>
</ProForm>
</Modal>
</div >
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.data
}))(examineQuestion);

View File

@ -0,0 +1,30 @@
import request from "@/utils/request"
// 拿到问题列表接口
export async function handleGetQuestionList(params?: any) {
const data = await request.get('/questions', params)
if (data.code === 200) {
return data.data
}
return []
}
// 新增问题接口
export async function handleAddQuestion(params?: any) {
const data = await request.post('/questions', params)
return data
}
// 编辑问题接口
export async function handleEditQuestion(params?: any) {
const data = await request.post(`/questions/${params.id}`, params)
return data
}
// 删除问题
export async function handleDeleteQuestion(params?: any) {
const data = await request.get(`/questions/delete/${params.id}`)
return data
}

View File

@ -0,0 +1,165 @@
import { ConnectState } from "@/models/global";
import { ActionType, FormInstance, ProTable } from "@ant-design/pro-components";
import { useRef, useState } from "react";
import { connect } from "umi";
import { handleGetRecordList } from "./service";
import moment from "moment";
import { Button, Image } from "antd";
const examineRecord: React.FC<{ currentUser: any }> = (props) => {
const { currentUser } = props
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
// 显示的附件数据
const [showImgList, setShowImgList] = useState<string[]>([])
// 预览图片
const [imagePreviewVisible, setImagePreviewVisible] = useState<boolean>(false)
// 预览的索引
const [previewIndex, setPreviewIndex] = useState<number>(0)
const columns: any = [
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "serverPartName",
hideInSearch: true,
width: 150,
ellipsis: true,
render: (_, record) => {
return record?.template.serverPartName ? record?.template.serverPartName : "-"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "placeName",
hideInSearch: true,
width: 150,
ellipsis: true,
render: (_, record) => {
return record?.template.title ? record?.template.title : "-"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "uploadResult",
hideInSearch: true,
width: 200,
ellipsis: true,
render: (_, record) => {
let extendObj = record?.extend ? JSON.parse(record?.extend) : ""
return extendObj?.uploadResult ? extendObj?.uploadResult : "-"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "uploadResult",
hideInSearch: true,
width: 350,
ellipsis: true,
render: (_, record) => {
let obj: any = {}
if (record?.questionResponses && record?.questionResponses.length > 0) {
record?.questionResponses.forEach((item) => {
obj[item.question.title] = JSON.stringify(item.choiceResponse)
})
}
return obj ? JSON.stringify(obj) : "-"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "createdAt",
hideInSearch: true,
width: 150,
ellipsis: true,
align: 'center',
render: (_, record) => {
return record?.createdAt ? moment(record?.createdAt).format('YYYY-MM-DD HH:mm:ss') : '-'
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "placeName",
hideInSearch: true,
width: 150,
ellipsis: true,
align: 'center',
render: (_, record) => {
let extendObj = record?.extend ? JSON.parse(record?.extend) : ""
let imgList = extendObj.imgsList
return imgList && imgList.length > 0 ?
<Button type="primary" onClick={() => {
setShowImgList(imgList)
setImagePreviewVisible(true)
}}></Button> : "-"
}
}
]
return (
<div style={{ backgroundColor: '#fff', display: 'flex' }}>
<div style={{
// width: !collapsible ? 'calc(100% - 300px)' : 'calc(100% - 60px)',
width: "100%",
paddingTop: 0,
paddingBottom: 0,
paddingRight: 0
}}>
<ProTable
actionRef={actionRef}
formRef={formRef}
columns={columns}
bordered
expandable={{
expandRowByClick: true
}}
headerTitle={<span style={{ color: "#1890ff", fontSize: 14, fontWeight: 600 }}></span>}
search={{ span: 6 }}
request={async () => {
const req: any = {
}
const data = await handleGetRecordList()
console.log('data', data);
if (data && data.length > 0) {
return { data, success: true }
}
return { data: [], success: true }
}}
toolbar={{
}}
>
</ProTable>
</div>
{
showImgList && showImgList.length > 0 && <div style={{ display: 'none' }}>
<Image.PreviewGroup
preview={{
visible: imagePreviewVisible,
onVisibleChange: vis => {
setImagePreviewVisible(vis)
},
current: previewIndex
}}>
{
showImgList.map((n) =>
<Image src={n} key={n} />
)
}
</Image.PreviewGroup>
</div>
}
</div>
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.data
}))(examineRecord);

View File

@ -0,0 +1,13 @@
import request from "@/utils/request"
// 拿到问题列表接口
export async function handleGetRecordList(params?: any) {
const data = await request.get('/questionnaire-responses', params)
if (data.code === 200) {
return data.data
}
return []
}

View File

@ -1,16 +0,0 @@
import request from "@/utils/request"
// 拿到类别列表接口
export async function handleGetExamineTypeList(params?: any) {
const data = await request.get('/question-categories', params)
if (data.code === 200) {
return data.data
}
return []
}
// 新增类别列表接口
export async function handleGetAddExamineType(params: any) {
const data = await request.post('/question-categories', params)
return data
}

View File

@ -8,7 +8,7 @@ import * as XLSX from 'xlsx'; // 读写数据的核心工具(无需写样式
import XLSXStyle from 'xlsx-style-fixed';
import moment from "moment";
import { handleFormatNumber } from "@/utils/publicMethods";
import LeftSelectTree from "@/components/leftSelectTree";
import LeftSelectTree from "@/components/leftSelectTree/leftSelectTree";
import { UserConnectedProps } from "@/models/user";

View File

@ -22,3 +22,16 @@ export const handleFormatNumber = (num: any) => {
return `${integer}.${decimal}`;
};
// base64转为文件格式
export const base64ToFile = (base64Data: any, filename = "qrcode.png") => {
const arr = base64Data.split(",");
const mime = arr[0].match(/:(.*?);/)[1]; // 提取 MIME 类型
const bstr = atob(arr[1]); // 解码 Base64
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}

View File

@ -19,10 +19,12 @@ instance.interceptors.request.use(
// config.data = preprocessData(JSON.stringify(config.data)); // 调用预处理函数
// }
const isUpload = config.url?.includes("/oss/upload");
config.headers = {
...config.headers,
Authorization: `Bearer ${localStorage.getItem('Authorization') || ''}`,
"Content-Type": "application/json;charset=utf-8"
"Content-Type": isUpload ? "multipart/form-data" : "application/json;charset=utf-8",
} as AxiosRequestHeaders;
return config;

151
src/utils/requestOld.ts Normal file
View File

@ -0,0 +1,151 @@
import axios from 'axios';
import { getDvaApp } from 'umi';
import { notification } from 'antd';
import type { AxiosRequestHeaders } from 'axios/index';
import CryptoJS from "crypto-js";
const { UMI_APP_BASEURL } = process.env;
// const instance = axios.create({ baseURL: UMI_APP_BASEURL });
const instance = axios.create({ baseURL: 'https://api.eshangtech.com/EShangApiMain' });
// const instance = axios.create({ baseURL: '/auth' });
instance.interceptors.request.use(
(config) => {
// 对data数据进行加密
// if (config.data) {
// config.data = preprocessData(JSON.stringify(config.data)); // 调用预处理函数
// }
config.headers = {
...config.headers,
Authorization: `Bearer ${localStorage.getItem('Authorization') || ''}`,
"Content-Type": "application/json;charset=utf-8"
} as AxiosRequestHeaders;
return config;
},
(error) => Promise.reject(error),
);
instance.interceptors.response.use(
//状态码为2xx的时候执行
(response) => {
const { data } = response;
if (data.code !== 200 && data.Result_Code !== 100) {
notification.error({
message: data.message,
});
}
const timestamp = getFormattedDate()
return data
},
//状态码不是2xx的时候执行
(error) => {
const { response } = error;
if (response && response.status === 401) {
// // 清除本地存储的token
// localStorage.removeItem('Authorization');
// // 重定向到登录页
// window.location.href = '/user/login';
// notification.error({
// message: response?.data?.message || '请求失败',
// description: error.message
// });
} else {
notification.error({
message: response?.data?.message || '请求失败',
description: error.message
});
}
return Promise.reject({
code: response?.status || 500,
message: response?.data?.message || '请求失败'
});
},
);
// 加密
const encryptAESECB = (data: string, key: string) => {
// const cipher = CryptoJS.createCipheriv('aes-128-ecb', key, null); // ECB 模式不需要 IV
const newKey = CryptoJS.enc.Utf8.parse(key); // 密钥必须是 16 字节
const cipher = CryptoJS.AES.encrypt(data, newKey, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
let encrypted = cipher.ciphertext.toString(CryptoJS.enc.Hex);
// let encrypted = cipher.update(data, 'utf8', 'hex');
// encrypted += cipher.final('hex');
return encrypted;
}
// 解密
const decryptAESECB = (data: string, key: string) => {
// const decipher = CryptoJS.createDecipheriv('aes-128-ecb', key, null);
// let decrypted = decipher.update(data, 'hex', 'utf8');
// decrypted += decipher.final('utf8');
const newKey = CryptoJS.enc.Utf8.parse(key);
const encryptedData = CryptoJS.enc.Hex.parse(data);
// 解密操作
const decrypted = CryptoJS.AES.decrypt({ ciphertext: encryptedData }, newKey, {
mode: CryptoJS.mode.ECB, // ECB 模式
padding: CryptoJS.pad.Pkcs7 // PKCS7 填充方式
});
// 将解密后的结果转为 UTF-8 字符串
const decryptedText = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedText;
}
// md5 签名
const md5 = (key: string, data: string, timestamp: string) => {
const text = "s" + key + data + timestamp;
return CryptoJS.MD5(text).toString(CryptoJS.enc.Hex);
}
// 生成签名戳
const getFormattedDate = () => {
const date = new Date();
const year = date.getFullYear(); // 获取年份 (yyyy)
const month = String(date.getMonth() + 1).padStart(2, '0'); // 获取月份 (MM)
const day = String(date.getDate()).padStart(2, '0'); // 获取日期 (dd)
const hours = String(date.getHours()).padStart(2, '0'); // 获取小时 (HH)
return `es0${year}${month}${day}${hours}0es`; // 拼接成 yyyyMMddHH 格式
}
// 加密方法
const preprocessData = (data: string) => {
console.log('data', data);
// YYYYMMDD
let timestamp = getFormattedDate()
console.log('timestamp', timestamp);
// 秒为单位的时间戳
let timeSecond = parseInt((new Date().getTime() / 1000).toString())
console.log('timeSecond', timeSecond);
// 数据的加密
let encryptionData = encryptAESECB(data, timestamp)
console.log('encryptionData', encryptionData);
// md5签名方法
let md5Data = md5(timestamp, encryptionData, timestamp)
console.log('md5Data', md5Data);
let res = {
data: encryptionData,
timestamp: timeSecond,
sign: md5Data
}
console.log('res', res);
return res
}
export default instance;

Binary file not shown.

View File

@ -4260,7 +4260,7 @@ camelcase-keys@^7.0.0:
quick-lru "^5.1.1"
type-fest "^1.2.1"
camelcase@^5.3.1:
camelcase@^5.0.0, camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
@ -4367,6 +4367,15 @@ click-to-react-component@1.1.0:
htm "^3.1.0"
react-merge-refs "^1.1.0"
cliui@^6.0.0:
version "6.0.0"
resolved "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.0"
wrap-ansi "^6.2.0"
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
@ -4880,7 +4889,7 @@ decamelize-keys@^1.1.0:
decamelize "^1.1.0"
map-obj "^1.0.0"
decamelize@^1.1.0:
decamelize@^1.1.0, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==
@ -5013,6 +5022,11 @@ diffie-hellman@^5.0.3:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
dijkstrajs@^1.0.1:
version "1.0.3"
resolved "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz#4c8dbdea1f0f6478bff94d9c49c784d623e4fc23"
integrity sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@ -6249,7 +6263,7 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
get-caller-file@^2.0.5:
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
@ -8542,6 +8556,11 @@ pluralize@^8.0.0:
resolved "https://registry.npmmirror.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
pngjs@^5.0.0:
version "5.0.0"
resolved "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
point-in-polygon@^1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/point-in-polygon/-/point-in-polygon-1.1.0.tgz#b0af2616c01bdee341cbf2894df643387ca03357"
@ -9040,6 +9059,15 @@ qiankun@^2.10.1:
lodash "^4.17.11"
single-spa "^5.9.2"
qrcode@^1.5.4:
version "1.5.4"
resolved "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz#5cb81d86eb57c675febb08cf007fff963405da88"
integrity sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==
dependencies:
dijkstrajs "^1.0.1"
pngjs "^5.0.0"
yargs "^15.3.1"
qs@6.13.0:
version "6.13.0"
resolved "https://registry.npmmirror.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
@ -9870,6 +9898,11 @@ require-from-string@^2.0.2:
resolved "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
require-main-filename@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
@ -10108,6 +10141,11 @@ serve-static@1.16.2:
parseurl "~1.3.3"
send "0.19.0"
set-blocking@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
set-function-length@^1.2.2:
version "1.2.2"
resolved "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
@ -11347,6 +11385,11 @@ which-collection@^1.0.1, which-collection@^1.0.2:
is-weakmap "^2.0.2"
is-weakset "^2.0.3"
which-module@^2.0.0:
version "2.0.1"
resolved "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409"
integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==
which-typed-array@^1.1.16, which-typed-array@^1.1.18:
version "1.1.18"
resolved "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad"
@ -11397,6 +11440,15 @@ word@~0.3.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
@ -11458,6 +11510,11 @@ xtend@^4.0.0:
resolved "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
y18n@^4.0.0:
version "4.0.3"
resolved "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
@ -11478,6 +11535,14 @@ yaml@^1.10.0:
resolved "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yargs-parser@^18.1.2:
version "18.1.3"
resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^20.2.9:
version "20.2.9"
resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
@ -11488,6 +11553,23 @@ yargs-parser@^21.1.1:
resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@^15.3.1:
version "15.4.1"
resolved "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
dependencies:
cliui "^6.0.0"
decamelize "^1.2.0"
find-up "^4.1.0"
get-caller-file "^2.0.1"
require-directory "^2.1.1"
require-main-filename "^2.0.0"
set-blocking "^2.0.0"
string-width "^4.2.0"
which-module "^2.0.0"
y18n "^4.0.0"
yargs-parser "^18.1.2"
yargs@^17.5.1:
version "17.7.2"
resolved "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"