diff --git a/config/routes.ts b/config/routes.ts index 3942e73..ca6c322 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -588,6 +588,11 @@ export default [ name: 'OperationLog', component: './Setting/OperationLog/index', }, + { + path: 'LoginLog', + name: 'LoginLog', + component: './Setting/LoginLog/index', + }, { path: 'menu', name: 'moduleCate', diff --git a/dist.zip b/dist.zip index 76dee89..a90a04a 100644 Binary files a/dist.zip and b/dist.zip differ diff --git a/package.json b/package.json index 498bff1..90e861a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ant-design-pro", - "version": "4.5.74", + "version": "4.5.77", "private": true, "description": "An out-of-box UI solution for enterprise applications", "scripts": { diff --git a/src/models/login.ts b/src/models/login.ts index aa18a10..0857a13 100644 --- a/src/models/login.ts +++ b/src/models/login.ts @@ -10,12 +10,13 @@ import type { Reducer, Effect } from 'umi'; import { history } from 'umi'; -import { accountLogin } from '@/services/login'; +import { accountLogin, handleUpdateLoginLog } from '@/services/login'; import { setAuthority } from '@/utils/authority'; import { message } from 'antd'; import session from '@/utils/session'; import { wrapTreeNode } from '@/utils/format'; +import moment from 'moment' export type StateType = { status?: 'ok' | 'error'; @@ -51,6 +52,7 @@ const Model: LoginModelType = { // 登录方法 * login({ payload }, { call, put }) { const response = yield call(accountLogin, payload); + yield put({ type: 'changeLoginStatus', payload: response, @@ -62,6 +64,20 @@ const Model: LoginModelType = { message.success('🎉 🎉 🎉 登录成功!'); + handleUpdateLoginLog({ + OPERATELOG_TYPE: 1000, + USER_ID: response.currentUser.ID, + USER_NAME: response.currentUser.Name, + USER_PASSPORT: response.currentUser.UserName, + MODULE_NAME: "用户登录", + OPERATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss'), + OPERATELOG_DESC: response.currentUser.Name ? `${response.currentUser.Name}于${moment().format('YYYY-MM-DD HH:mm:ss')}登录了系统` : "登录成功", + USER_LOGINIP: payload?.LoginIP || "", + USER_LOGINPLACE: payload?.LoginPlace || "", + BROWSER_VERSION: payload?.BrowserVersion || "", + OPERATING_SYSTEM: payload?.OperatingSystem || "", + }) + if (!history) return; const { query } = history.location; const { redirect } = query as { @@ -111,7 +127,6 @@ const Model: LoginModelType = { } }, *logout(_, { put }) { // 退出登录 - yield put({ type: 'global/changeTabsRoutes', payload: { data: [], action: 'removeAll' }, @@ -121,6 +136,21 @@ const Model: LoginModelType = { const { query = {} } = history.location; const { redirect } = query; + + const currentUser = session.get('currentUser') + console.log('currentUsercurrentUsercurrentUser', currentUser); + + handleUpdateLoginLog({ + OPERATELOG_TYPE: 1002, + USER_ID: currentUser.ID, + USER_NAME: currentUser.Name, + USER_PASSPORT: currentUser.UserName, + MODULE_NAME: "用户登出", + OPERATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss'), + OPERATELOG_DESC: currentUser.Name ? `${currentUser.Name}于${moment().format('YYYY-MM-DD HH:mm:ss')}登出了系统` : "登出成功", + }) + + // Note: There may be security issues, please note if (window.location.pathname !== '/user/login' && !redirect) { history.replace({ diff --git a/src/pages/Setting/LoginLog/index.tsx b/src/pages/Setting/LoginLog/index.tsx new file mode 100644 index 0000000..8b15e32 --- /dev/null +++ b/src/pages/Setting/LoginLog/index.tsx @@ -0,0 +1,286 @@ +import { connect } from "umi"; +import type { CurrentUser } from "umi"; +import type { ConnectState } from "@/models/connect"; +import React, { useRef, useState } from "react"; +import type { FormInstance } from "antd"; +import { Button, message, Space, Spin, Tree } from "antd"; +import type { ActionType } from "@ant-design/pro-table"; +import ProTable from "@ant-design/pro-table"; +import ReactHTMLTableToExcel from "react-html-table-to-excel"; +import { handleGetOPERATELOGList } from "./service"; +import moment from 'moment' + + +const saleRankReport: React.FC<{ currentUser: CurrentUser }> = (props) => { + const { currentUser } = props + const downloadBtnRef = useRef() + const actionRef = useRef(); + const formRef = useRef(); + const [reqDetailList, setReqDetailList] = useState(); // 合计项数据源 + const [printOut, setPrintOut] = useState(); // 打印数据的内容 + const [collapsible, setCollapsible] = useState(false) + const [treeView, setTreeView] = useState() + const [printIndex, setPrintIndex] = useState(new Date().getTime()) + + + // 树相关的属性和方法 + const [selectedId, setSelectedId] = useState() + // 导出的加载效果 + const [showLoading, setShowLoading] = useState(false) + // 是否显示打印的表格 + const [showExportTable, setShowExportTable] = useState(false) + // 查询的条件 + const [searchParams, setSearchParams] = useState() + + const columns: any = [ + { + title: '查询内容', + width: 120, + ellipsis: true, + dataIndex: 'searchValue', + hideInTable: true, + }, + { + title: '查询日期', + width: 160, + valueType: 'date', + hideInTable: true, + dataIndex: 'searchDate', + initialValue: moment(), + }, + { + title: '访问编码', + width: 120, + ellipsis: true, + hideInSearch: true, + dataIndex: 'OPERATELOG_ID' + }, + { + dataIndex: 'OPERATELOG_TYPE', + title: '登录状态', + width: 120, + align: 'center', + valueType: 'select', + hideInSearch: true, + valueEnum: { + 1000: { text: '登录', status: 'success' }, + 1002: { text: '登出', status: 'error' }, + } + }, + { + dataIndex: 'USER_PASSPORT', + title: '登录账号', + width: 200, + ellipsis: true, + align: 'center', + hideInSearch: true, + }, + { + dataIndex: 'USER_LOGINIP', + title: '登录地址', + ellipsis: true, + width: 160, + align: 'center', + hideInSearch: true, + }, + { + dataIndex: 'USER_LOGINPLACE', + title: '登录地点', + ellipsis: true, + width: 160, + align: 'center', + hideInSearch: true, + }, + { + dataIndex: 'BROWSER_VERSION', + title: '浏览器版本', + width: 140, + ellipsis: true, + align: 'center', + hideInSearch: true, + }, + { + dataIndex: 'OPERATING_SYSTEM', + title: '操作系统', + width: 120, + align: 'center', + hideInSearch: true, + }, + + { + dataIndex: 'OPERATELOG_DESC', + title:
备注说明
, + ellipsis: true, + width: 260, + align: 'left', + hideInSearch: true, + }, + { + dataIndex: 'OPERATE_DATE', + title: '登录时间', + ellipsis: true, + width: 160, + align: 'center', + hideInSearch: true, + }, + ] + + const exportTable = (e) => { + e.stopPropagation(); // 防止Collapse组件收起 + const main = document.getElementsByClassName(`saleReportHideBox${printIndex}`)[0] + const thead = main.querySelector('thead').cloneNode(true); // 深克隆DOM节点 + const tbody = main.querySelector('tbody').cloneNode(true); // 深克隆DOM节点 + const container = document.querySelector('#hiddenBox'); + + const tempTable = document.createElement('table'); + tempTable.appendChild(thead); + tempTable.appendChild(tbody); + + tempTable.setAttribute('id', 'table-to-xls-saleRankReport'); // 给table添加id,值与按钮上的table字段对应 + + container.appendChild(tempTable); // 把创建的节点添加到页面容器中 + + setShowLoading(false) + + downloadBtnRef.current.handleDownload(); + setShowExportTable(false) + tempTable.remove() // 防止重复打印一个内容 + } + + + return ( +
{ + // 打印报表 + if (!reqDetailList || reqDetailList.length === 0) return; + setPrintOut(el); + }} > + + { + showLoading ? +
+
+ + 数据导出中... +
+
: '' + } + +
+ { + showExportTable && reqDetailList && reqDetailList.length > 0 ? + : '' + } +
+
+ +
+
+ { + const req: any = { + SearchParameter: { + OPERATELOG_TYPES: '1000,1002', + OPERATE_DATE_Start: moment(params?.searchDate).format('YYYY-MM-DD'), + OPERATE_DATE_End: moment(params?.searchDate).format('YYYY-MM-DD'), + }, + SortStr: 'OPERATE_DATE desc', + KeyWord: { + Key: 'USER_NAME,USER_LOGINIP,USER_LOGINPLACE,BROWSER_VERSION,OPERATING_SYSTEM', + Value: params?.searchValue || '' + }, + PageIndex: 1, + PageSize: 999999 + } + setSearchParams(params) + const data = await handleGetOPERATELOGList(req) + console.log('login', data); + if (data && data.length > 0) { + setReqDetailList(data) + return { data, success: true } + } + return { data: [], success: true } + }} + toolbar={{ + actions: [ + + + , + + ] + }} + /> +
+
+
+ ) +} + +export default connect(({ user }: ConnectState) => ({ + currentUser: user.currentUser +}))(saleRankReport); diff --git a/src/pages/Setting/LoginLog/service.ts b/src/pages/Setting/LoginLog/service.ts new file mode 100644 index 0000000..405f76d --- /dev/null +++ b/src/pages/Setting/LoginLog/service.ts @@ -0,0 +1,14 @@ +import request from "@/utils/request" + +// 获取操作日志表列表 +export async function handleGetOPERATELOGList(params?: any){ + const data = await request('/Log/GetOPERATELOGList', { + method: 'POST', + data: params, + }) + + if (data.Result_Code !== 100) { + return {} + } + return data.Result_Data.List +} \ No newline at end of file diff --git a/src/pages/Setting/Users/components/edit.tsx b/src/pages/Setting/Users/components/edit.tsx index 6a93f3c..5c95283 100644 --- a/src/pages/Setting/Users/components/edit.tsx +++ b/src/pages/Setting/Users/components/edit.tsx @@ -59,7 +59,7 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, const [checkedRole, setCheckedRole] = useState(); // 当前选中的行 角色 id const [checkedServerpart, setCheckedServerpart] = useState(); // 当前选中的行 服务区id const [checkedShop, setCheckedShop] = useState(); // 当前选中的行 服务区门店id - const [initialDetail, setInitialDetail] = useState(detail || {}); // 当前编辑页面的账户数据 + const [initialDetail, setInitialDetail] = useState(detail || {}); // 当前编辑页面的账户数据 const [copyData, setCopyData] = useState()// 拷贝一份一开始接口返回的表单数据 与 最后提交可以进行对比 const [companyList, setCompanyList] = useState()// 用户下面的公司列表 const [selectDetail, setSelectDetail] = useState()// 选中的业主单位的省份 @@ -185,7 +185,7 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, const getServiceList = async (PROVINCEID: any, id: any) => { const typeId = id || showServiceList const req = { - ProvinceCode: PROVINCEID || selectDetail, + ProvinceCode: PROVINCEID || selectDetail || '530000', ServerpartType: typeId === 1020 ? 1010 : 1000, ShowWholePower: true } @@ -456,15 +456,16 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, if (newData.AnalysisPermission !== copyData.AnalysisPermission) { handleAnalysisPermission({ userId: copyData.USER_ID, - AuthorType: (selectDetail === 340000 && tableTab === '1000' || - selectDetail === 340000 && copyData?.AnalysisPermission === true && tableTab === '1000' || - selectDetail === 340000 && copyData?.AnalysisPermission === false && tableTab === '1000') && newData.AnalysisPermission, + AuthorType: (selectDetail === 530000 && tableTab === '1000' || + selectDetail === 530000 && copyData?.AnalysisPermission === true && tableTab === '1000' || + selectDetail === 530000 && copyData?.AnalysisPermission === false && tableTab === '1000') && newData.AnalysisPermission, OperateUser: currentUser?.Name }) } + console.log('newValuenewValuenewValue', newValue); const success = await handleAddUpdate(newValue, false); console.log('tableTab', tableTab); @@ -650,7 +651,9 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, }, ]} request={async () => { - const options = await getOnwer() + const options = await getOnwer({ DataType: 1, ProvinceCode: "530000" }) + console.log('optionsoptionsoptionsoptions', options); + return options; }} fieldProps={{ @@ -665,8 +668,9 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, setSelectDetail(options.value) getServiceList(options.value, showServiceList || null) detailForm.current?.setFieldsValue({ USERTYPE_ID: '' }) - setInitialDetail({ ...initialDetail, PROVINCE_UNIT: options.label, }) - // if (initialDetail.USER_PATTERN === 4000){ + // setInitialDetail({ ...initialDetail, PROVINCE_UNIT: options.label, }) + setInitialDetail({ ...initialDetail, PROVINCE_UNIT: options.value, OWNERUNIT_NAME: options.label }) + // if (initialDetail.USER_PATTERN === 4000){ // const req = { // ProvinceCode:currentUser?.ProvinceCode, // // OwnerUnitId:e @@ -741,18 +745,18 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, label="账号部门" name="USERTYPE_ID" dependencies={['USER_PROVINCE', 'USER_PATTERN', '']} - rules={[ - { - required: initialDetail.USER_PATTERN === 1000 || initialDetail.USER_PATTERN === 4000, - message: '请选择账号部门', - }, - ]} + // rules={[ + // { + // required: initialDetail.USER_PATTERN === 1000 || initialDetail.USER_PATTERN === 4000, + // message: '请选择账号部门', + // }, + // ]} request={async (params) => { console.log('params', params); if (pageType === 'merchantManagement') { const req: any = { - // ProvinceCode: currentUser?.ProvinceCode || '340000', + // ProvinceCode: currentUser?.ProvinceCode || '530000', UserTypePattern: 2000 } const data = await getUserTypeTree(req) @@ -765,7 +769,7 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, return data } if (params.USER_PROVINCE || params.USER_PATTERN) { const req: any = { - ProvinceCode: params.USER_PATTERN === 2000 ? params.BUSINESSMAN_ID : params.USER_PROVINCE, + ProvinceCode: '530000', UserTypePattern: tableTab === 9000 ? 1000 : tableTab } const data = await getUserTypeTree(req) @@ -926,9 +930,9 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, { - selectDetail === 340000 && tableTab === '1000' || - selectDetail === 340000 && copyData?.AnalysisPermission === true && tableTab === '1000' || - selectDetail === 340000 && copyData?.AnalysisPermission === false && tableTab === '1000' + selectDetail === 530000 && tableTab === '1000' || + selectDetail === 530000 && copyData?.AnalysisPermission === true && tableTab === '1000' || + selectDetail === 530000 && copyData?.AnalysisPermission === false && tableTab === '1000' ? - { + {/* { tableTab === '1000' || tableTab === '4000' || tableTab === '9000' ? {serverpartTree && @@ -1083,9 +1087,13 @@ const Edit = ({ tableTab, openType, detail, reloadTable, currentUser, selectTab, > } - : '' - } + + + : '' + } */} + {/* {(currentUser?.UserPattern === 9000 ? initialDetail.USER_PATTERN === 1000 : currentUser?.UserPattern === 1000) && } */} + { (initialDetail.USER_PATTERN === 2000 && initialDetail.BUSINESSMAN_NAME) || (pageType === 'merchantManagement' && BUSINESSMAN_ID?.label) ? diff --git a/src/pages/Setting/Users/index.tsx b/src/pages/Setting/Users/index.tsx index 61bf4c0..6ddf45b 100644 --- a/src/pages/Setting/Users/index.tsx +++ b/src/pages/Setting/Users/index.tsx @@ -25,6 +25,7 @@ import useRequest from "@ahooksjs/use-request"; import ProDescriptions from "@ant-design/pro-descriptions"; import { getUserSystemRole, getUserList, getUserTypeTree } from './service' +import { getOnwer } from "@/services/options"; const UserList: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => { const { currentUser } = props @@ -73,6 +74,7 @@ const UserList: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => }) // 请求账号部门tree const { run: getUserTypeMenu, loading: typeLoading, data: userTypeTree } = useRequest((type) => getUserTypeTree({ UserTypePattern: type || tableTab, ShowStatus: true })) + // const [userTypeMenu, setUserTypeMenu] = useState<{1000: {}, 2000: {}}>(()=>getUserTypeTree(tableTab)); // 分布更新窗口的弹窗 // 根据角色id查询权限树 const { run: getRoleMenu, data: roleMenuTree } = useRequest(async (SystemRoleId?: number) => { @@ -190,10 +192,17 @@ const UserList: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => return (a.PROVINCE_UNIT || '').localeCompare((b.PROVINCE_UNIT || '')) }, hideInTable: tableTab === '2000', - valueType: "treeSelect", - fieldProps: { - options: userTypeTree, - }, + // valueType: "treeSelect", + valueType: "select", + request: async () => { + let data = await getOnwer({ ProvinceCode: "530000", DataType: 1 }) + if (data && data.length > 0) { + data.forEach((item: any) => { + item.value = item.value.toString() + }) + } + return data + } }, { title: '备注', @@ -289,6 +298,7 @@ const UserList: React.FC<{ currentUser: CurrentUser | undefined }> = (props) => ...params, USER_STATUS: params?.USER_STATUS, USER_PATTERN: tableTab, + PROVINCE_UNIT: '911', UserTypeIds: userTypeId && userTypeId[tableTab] ? userTypeId[tableTab].toString() : '', SortStr: sortstr ? sortstr.toString() : 'USER_INDEX', keyWord: params.searchKey ? { key: "USER_PASSPORT,USER_NAME,USER_MOBILEPHONE,PROVINCE_UNIT,BUSINESSMAN_NAME", value: params.searchKey } : null, // 关键词查询 diff --git a/src/pages/travelMember/EventRegistration/components/EventRegistrationDetail.tsx b/src/pages/travelMember/EventRegistration/components/EventRegistrationDetail.tsx index f5f071d..f720f7f 100644 --- a/src/pages/travelMember/EventRegistration/components/EventRegistrationDetail.tsx +++ b/src/pages/travelMember/EventRegistration/components/EventRegistrationDetail.tsx @@ -5,7 +5,7 @@ import { useRef, useState } from "react"; import React from "react"; import { ExclamationCircleOutlined, setTwoToneColor } from "@ant-design/icons"; import Draggable from "react-draggable"; -import ProForm, { ProFormCheckbox, ProFormDatePicker, ProFormDigit, ProFormText, ProFormTextArea, ProFormUploadButton } from "@ant-design/pro-form"; +import ProForm, { ProFormCheckbox, ProFormDatePicker, ProFormDigit, ProFormSelect, ProFormText, ProFormTextArea, ProFormUploadButton } from "@ant-design/pro-form"; import session from "@/utils/session"; import moment from 'moment' import { handleGetACTIVITYDETAILList, handleGetSynchroACTIVITY } from "../../SharedRestStationManagement/service"; @@ -97,7 +97,7 @@ const EventRegistrationDetail = ({ parentRow, setparentRow, onShow, setOnShow, c { title:
报名状态
, width: 180, - dataIndex: "ACTIVITYDETAIL_STATE", + dataIndex: "ACTIVITYDETAIL_STATE", ellipsis: true, hideInSearch: true, valueType: "select", @@ -193,6 +193,7 @@ const EventRegistrationDetail = ({ parentRow, setparentRow, onShow, setOnShow, c // } : {}} request={async () => { console.log('fileListfileListfileList', fileList); + console.log('parentRowparentRowparentRow', parentRow); if (parentRow) { let idList: any = [] @@ -211,6 +212,8 @@ const EventRegistrationDetail = ({ parentRow, setparentRow, onShow, setOnShow, c ...parentRow, SERVERPART_ID: idList, SERVERPART_SHOWNAME: nameStr, + ACTIVITY_TYPE: Number(parentRow.ACTIVITY_TYPE) + } } return {} @@ -253,7 +256,7 @@ const EventRegistrationDetail = ({ parentRow, setparentRow, onShow, setOnShow, c STAFF_ID: currentUser.ID, STAFF_NAME: currentUser.Name, OPERATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss'), - RelateList: RelateList + RelateList: RelateList, } } else { req = { @@ -265,7 +268,7 @@ const EventRegistrationDetail = ({ parentRow, setparentRow, onShow, setOnShow, c STAFF_NAME: currentUser.Name, OPERATE_DATE: moment().format('YYYY-MM-DD HH:mm:ss'), RelateList: RelateList, - ACTIVITY_STATE: 2 + ACTIVITY_STATE: 2, } } console.log('reqreqreqreq', req); @@ -344,6 +347,17 @@ const EventRegistrationDetail = ({ parentRow, setparentRow, onShow, setOnShow, c readonly={readonly} /> + + + { - parentRow ? + parentRow && Number(parentRow?.ACTIVITY_TYPE) === 1000 ? { - const ownerUnit = session.get(`ownerUnit`); - if (ownerUnit) { - return ownerUnit; - } const data = await request('/BaseInfo/BindingOwnerUnitDDL', { method: 'GET', params diff --git a/src/versionEnv.ts b/src/versionEnv.ts index 0e594d1..d0c27a6 100644 --- a/src/versionEnv.ts +++ b/src/versionEnv.ts @@ -1,4 +1,4 @@ // 由 scripts/writeVersion.js 自动生成 -export const VERSION = "4.5.74"; -export const GIT_HASH = "8244fac"; -export const BUILD_TIME = "2025-11-14T01:20:30.467Z"; +export const VERSION = "4.5.77"; +export const GIT_HASH = "1cd8c40"; +export const BUILD_TIME = "2025-11-18T09:36:29.591Z";