Compare commits

..

4 Commits

Author SHA1 Message Date
yangxiao
9ae49516b4 flat: 提交石河子案件管理
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-12-28 19:58:28 +08:00
bin
063905292c feat : 新增url中token参数处理登录
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-12-23 15:46:38 +08:00
bin
668f853303 Merge branch 'main' of http://124.243.245.42:3000/sdz/shihezi-admin
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
2025-12-23 14:11:22 +08:00
bin
ab8ee802db 文案 2025-12-23 14:11:21 +08:00
9 changed files with 478 additions and 182 deletions

View File

@@ -76,7 +76,7 @@ export default defineConfig({
* @name layout 插件 * @name layout 插件
* @doc https://umijs.org/docs/max/layout-menu * @doc https://umijs.org/docs/max/layout-menu
*/ */
title: '青岛智慧就业服务系统', title: '石河子智慧就业服务系统',
layout: { layout: {
locale: false, locale: false,
...defaultSettings, ...defaultSettings,

View File

@@ -15,7 +15,7 @@ const Settings: ProLayoutProps & {
fixedHeader: false, fixedHeader: false,
fixSiderbar: true, fixSiderbar: true,
colorWeak: false, colorWeak: false,
title: '青岛智慧就业服务系统', title: '石河子智慧就业服务系统',
pwa: true, pwa: true,
logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg', logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
iconfontUrl: '', iconfontUrl: '',

View File

@@ -6,7 +6,7 @@ import type { RunTimeLayoutConfig } from '@umijs/max';
import { history } from '@umijs/max'; import { history } from '@umijs/max';
import defaultSettings from '../config/defaultSettings'; import defaultSettings from '../config/defaultSettings';
import { errorConfig } from './requestErrorConfig'; import { errorConfig } from './requestErrorConfig';
import { clearSessionToken, getAccessToken, getRefreshToken, getTokenExpireTime } from './access'; import { clearSessionToken, getAccessToken,setSessionToken, getRefreshToken, getTokenExpireTime } from './access';
import { import {
getRemoteMenu, getRemoteMenu,
getRoutersInfo, getRoutersInfo,
@@ -64,12 +64,53 @@ export async function getInitialState(): Promise<{
} as API.CurrentUser; } as API.CurrentUser;
} catch (error) { } catch (error) {
console.log(error); console.log(error);
// 如果获取用户信息失败清除token并跳转到登录页
clearSessionToken();
history.push(PageEnum.LOGIN); history.push(PageEnum.LOGIN);
} }
return undefined; return undefined;
}; };
// 如果不是登录页面,执行
// 检查URL参数中是否包含token参数
const { location } = history; const { location } = history;
const urlParams = new URL(window.location.href).searchParams;
const tokenFromUrl = urlParams.get('token');
if (tokenFromUrl) {
try {
// 处理token去掉Bearer前缀如果存在
let processedToken = tokenFromUrl.trim();
if (processedToken.startsWith('Bearer ')) {
processedToken = processedToken.substring(7);
}
// 设置token
const current = new Date();
const expireTime = current.setTime(current.getTime() + 1000 * 12 * 60 * 60); // 12小时过期
setSessionToken(processedToken, processedToken, expireTime);
// 尝试获取用户信息
const currentUser = await fetchUserInfo();
if (currentUser) {
// 成功获取用户信息清除URL中的token参数并跳转
const newSearch = new URLSearchParams(urlParams);
newSearch.delete('token');
history.push(urlParams.get('redirect') || '/');
setTimeout(() => history.go(0), 0);
return {
fetchUserInfo,
currentUser,
settings: defaultSettings as Partial<LayoutSettings>,
};
}
} catch (error) {
console.error('处理URL token失败:', error);
clearSessionToken();
}
}
// 如果不是登录页面且没有token参数正常执行
if (location.pathname !== PageEnum.LOGIN) { if (location.pathname !== PageEnum.LOGIN) {
const currentUser = await fetchUserInfo(); const currentUser = await fetchUserInfo();
return { return {
@@ -78,6 +119,7 @@ export async function getInitialState(): Promise<{
settings: defaultSettings as Partial<LayoutSettings>, settings: defaultSettings as Partial<LayoutSettings>,
}; };
} }
return { return {
fetchUserInfo, fetchUserInfo,
settings: defaultSettings as Partial<LayoutSettings>, settings: defaultSettings as Partial<LayoutSettings>,
@@ -116,6 +158,17 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
footerRender: () => <Footer />, footerRender: () => <Footer />,
onPageChange: () => { onPageChange: () => {
const { location } = history; const { location } = history;
// 检查URL参数中是否包含token
const urlParams = new URL(window.location.href).searchParams;
const tokenFromUrl = urlParams.get('token');
if (tokenFromUrl) {
// 如果有token参数不执行跳转逻辑由getInitialState处理
return;
}
// 如果没有token参数执行原有的逻辑
// 如果没有登录,重定向到 login // 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== PageEnum.LOGIN) { if (!initialState?.currentUser && location.pathname !== PageEnum.LOGIN) {
history.push(PageEnum.LOGIN); history.push(PageEnum.LOGIN);
@@ -197,14 +250,29 @@ export async function patchClientRoutes({ routes }) {
export async function render(oldRender: () => void) { export async function render(oldRender: () => void) {
console.log('render get routers', oldRender); console.log('render get routers', oldRender);
const token = getAccessToken();
if (!token || token?.length === 0) { // 检查URL参数中是否包含token
oldRender(); const urlParams = new URL(window.location.href).searchParams;
return; const tokenFromUrl = urlParams.get('token');
if (tokenFromUrl) {
// 如果URL中有token参数已经在getInitialState中处理过了
const token = getAccessToken();
if (!token || token?.length === 0) {
oldRender();
return;
}
} else {
// 原有逻辑检查本地存储的token
const token = getAccessToken();
if (!token || token?.length === 0) {
oldRender();
return;
}
} }
await getRoutersInfo().then((res) => { await getRoutersInfo().then((res) => {
console.log('render get routers', 123); console.log('render get routers', 123);
setRemoteMenu(res); setRemoteMenu(res);
oldRender(); oldRender();
}); });

View File

@@ -5,20 +5,20 @@ import { getYear } from '@/utils/tools';
const Footer: React.FC = () => { const Footer: React.FC = () => {
return ( return (
<DefaultFooter <DefaultFooter
copyright={` ${getYear()} 青岛智慧就业服务系统`} copyright={` ${getYear()} 石河子智慧就业服务系统`}
style={{ style={{
background: 'none', background: 'none',
}} }}
links={[ links={[
{ {
key: '青岛政务网', key: '石河子政务网',
title: '青岛政务网', title: '石河子政务网',
href: 'http://www.shihezi.gov.cn/', href: 'http://www.shihezi.gov.cn/',
blankTarget: true, blankTarget: true,
}, },
{ {
key: '青岛市人力资源和社会保障局', key: '石河子市人力资源和社会保障局',
title: '青岛市人力资源和社会保障局', title: '石河子市人力资源和社会保障局',
href: 'https://hrss.shihezi.gov.cn/', href: 'https://hrss.shihezi.gov.cn/',
blankTarget: true, blankTarget: true,
}, },

View File

@@ -69,7 +69,7 @@ const ProFromMap: React.FC<MapProps> = ({ open, onSelect, onCancel }) => {
// 注意输入提示插件2.0版本需引入AMap.AutoComplete而1.4版本应使用AMap.Autocomplete // 注意输入提示插件2.0版本需引入AMap.AutoComplete而1.4版本应使用AMap.Autocomplete
// 实例化AutoComplete // 实例化AutoComplete
autoCompleteRef.current = new AMap.AutoComplete({ autoCompleteRef.current = new AMap.AutoComplete({
city: '370200', // 青岛 city: '370200', // 石河子
citylimit: false, citylimit: false,
}); });
}); });
@@ -79,7 +79,7 @@ const ProFromMap: React.FC<MapProps> = ({ open, onSelect, onCancel }) => {
geocoderRef.current = new AMap.Geocoder({ geocoderRef.current = new AMap.Geocoder({
extensions: 'base', extensions: 'base',
batch: false, batch: false,
city: '370200', // 青岛 city: '370200', // 石河子
}); });
}); });
@@ -155,7 +155,7 @@ const ProFromMap: React.FC<MapProps> = ({ open, onSelect, onCancel }) => {
} }
const searchLocation = async (keyWords: string) => { const searchLocation = async (keyWords: string) => {
const keywordsToSearch = keyWords || '青岛'; const keywordsToSearch = keyWords || '石河子';
const resData = await autoInput(keywordsToSearch); const resData = await autoInput(keywordsToSearch);
locationList.current = resData; locationList.current = resData;
setLocationOptions(resData); setLocationOptions(resData);

View File

@@ -0,0 +1,177 @@
import React, { Fragment, useRef, useState } from 'react';
import { Button, FormInstance, message } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
export default function CaseManagement() {
const actionRef = useRef<ActionType>();
const formTableRef = useRef<FormInstance>()
const columns: ProColumns<API.StorageDetection.StorageItem>[] = [
{
title: '序号',
dataIndex: 'storageDate',
valueType: 'text',
render: (_, record, index) => index + 1,
align: 'center',
hideInSearch: true,
},
{
title: '投诉编号',
dataIndex: 'detectionId',
valueType: 'text',
align: 'center',
},
{
title: '行业类别',
dataIndex: 'industry',
valueType: 'text',
align: 'center',
},
{
title: '用工所在地',
dataIndex: 'address',
valueType: 'text',
align: 'center',
hideInSearch: true,
},
{
title: '投诉单位',
dataIndex: 'unit',
valueType: 'text',
align: 'center',
},
{
title: '投诉人',
dataIndex: 'websiteName',
valueType: 'text',
align: 'center',
},
{
title: '投诉人手机号',
dataIndex: 'number',
valueType: 'text',
align: 'center',
},
{
title: '欠薪人数',
dataIndex: 'wage',
valueType: 'text',
align: 'center',
hideInSearch: true,
},
{
title: '欠薪金额(万元)',
dataIndex: 'amount',
valueType: 'text',
align: 'center',
hideInSearch: true,
},
{
title: '欠薪日期',
dataIndex: 'storageDate',
valueType: 'text',
align: 'center',
hideInSearch: true,
},
{
title: '欠薪区域',
dataIndex: 'wageArrearsArea',
valueType: 'text',
align: 'center',
hideInSearch: true,
ellipsis: true,
},
{
title: '案件状态',
dataIndex: 'failedReason',
valueType: 'text',
align: 'center',
hideInSearch: true,
},
{
title: '操作状态',
dataIndex: 'failedReason',
valueType: 'text',
hideInSearch: true,
align: 'center',
},
// {
// title: '操作',
// hideInSearch: true,
// align: 'center',
// dataIndex: 'detectionId',
// width: 120,
// // render: (detectionId, record) => (
// // <div style={{ display: 'flex', justifyContent: 'center', gap: 8 }}>
// // <Button
// // type="link"
// // size="small"
// // key="view"
// // icon={<EyeOutlined />}
// // loading={loading}
// // hidden={!access.hasPerms('recruitmentDataCollection:jobMonitor:view')}
// // onClick={() => handleViewDetail(detectionId)}
// // >
// // 查看详情
// // </Button>
// // </div>
// // ),
// },
];
return (
<div>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.StorageDetection.StorageItem>
actionRef={actionRef}
formRef={formTableRef}
rowKey="detectionId"
key="storageDetectionIndex"
columns={columns}
search={{ labelWidth: 'auto' }}
request={async (params) => {
// 模拟 API 响应
return {
data: [
{
detectionId: '230',
storageDate: '2023-01-01',
storageDetail: '存储详情1',
failedReason: '正在处理',
industry: '销售',
address: '石河子',
unit: '石河子市水利局‌',
websiteName: '测试1',
number: '1234567890',
wage: '2',
amount: '1111',
wageArrearsArea: '石河子市',
// ... 其他字段
},
{
detectionId: '231',
storageDate: '2023-01-01',
storageDetail: '存储详情1',
failedReason: '正在处理',
industry: '销售',
address: '石河子',
unit: '石河子市水利局‌',
websiteName: '测试1',
number: '1234567890',
wage: '2',
amount: '1111',
wageArrearsArea: '石河子市',
// ... 其他字段
},
],
total: 2,
success: true,
};
}}
/>
</div>
</div>
);
}

View File

@@ -266,7 +266,7 @@ const Login: React.FC = () => {
}} }}
submitter={type === 'scanQode' ? false : true} submitter={type === 'scanQode' ? false : true}
// logo={<img alt="logo" src={logoImg} />} // logo={<img alt="logo" src={logoImg} />}
title="青岛智慧就业服务系统" title="石河子智慧就业服务系统"
// subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })} // subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}
initialValues={{ initialValues={{
autoLogin: true, autoLogin: true,

View File

@@ -1,164 +1,166 @@
import { createIcon } from '@/utils/IconUtil'; import { createIcon } from '@/utils/IconUtil';
import { MenuDataItem } from '@ant-design/pro-components'; import { MenuDataItem } from '@ant-design/pro-components';
import { request } from '@umijs/max'; import { request } from '@umijs/max';
import React, { lazy } from 'react'; import React, { lazy } from 'react';
let remoteMenu: any = null; let remoteMenu: any = null;
export function getRemoteMenu() { export function getRemoteMenu() {
return remoteMenu; return remoteMenu;
} }
export function setRemoteMenu(data: any) { export function setRemoteMenu(data: any) {
remoteMenu = data; remoteMenu = data;
} }
function patchRouteItems(route: any, menu: any, parentPath: string) { function patchRouteItems(route: any, menu: any, parentPath: string) {
for (const menuItem of menu) { for (const menuItem of menu) {
if (menuItem.component === 'Layout' || menuItem.component === 'ParentView') { console.log(menuItem, 'menuItem')
if (menuItem.routes) { if (menuItem.component === 'Layout' || menuItem.component === 'ParentView') {
let hasItem = false; if (menuItem.routes) {
let newItem = null; let hasItem = false;
for (const routeChild of route.routes) { let newItem = null;
if (routeChild.path === menuItem.path) { for (const routeChild of route.routes) {
hasItem = true; if (routeChild.path === menuItem.path) {
newItem = routeChild; hasItem = true;
} newItem = routeChild;
} }
if (!hasItem) { }
newItem = { if (!hasItem) {
path: menuItem.path, newItem = {
routes: [], path: menuItem.path,
children: [] routes: [],
} children: []
route.routes.push(newItem) }
} route.routes.push(newItem)
patchRouteItems(newItem, menuItem.routes, parentPath + menuItem.path + '/'); }
} patchRouteItems(newItem, menuItem.routes, parentPath + menuItem.path + '/');
} else { }
const names: string[] = menuItem.component.split('/'); } else {
let path = ''; const names: string[] = menuItem.component && menuItem.component.split('/');
names.forEach(name => { console.log(names, 'names')
if (path.length > 0) { let path = '';
path += '/'; names && names.forEach(name => {
} if (path.length > 0) {
if (name !== 'index') { path += '/';
path += name.at(0)?.toUpperCase() + name.substr(1); }
} else { if (name !== 'index') {
path += name; path += name.at(0)?.toUpperCase() + name.substr(1);
} } else {
}) path += name;
if (!path.endsWith('.tsx')) { }
path += '.tsx' })
} if (!path.endsWith('.tsx')) {
if (route.routes === undefined) { path += '.tsx'
route.routes = []; }
} if (route.routes === undefined) {
if (route.children === undefined) { route.routes = [];
route.children = []; }
} if (route.children === undefined) {
const newRoute = { route.children = [];
element: React.createElement(lazy(() => import('@/pages/' + path))), }
path: parentPath + menuItem.path, const newRoute = {
} element: React.createElement(lazy(() => import('@/pages/' + path))),
route.children.push(newRoute); path: parentPath + menuItem.path,
route.routes.push(newRoute); }
} route.children.push(newRoute);
} route.routes.push(newRoute);
} }
}
export function patchRouteWithRemoteMenus(routes: any) { }
if (remoteMenu === null) { return; }
let proLayout = null; export function patchRouteWithRemoteMenus(routes: any) {
for (const routeItem of routes) { if (remoteMenu === null) { return; }
if (routeItem.id === 'ant-design-pro-layout') { let proLayout = null;
proLayout = routeItem; for (const routeItem of routes) {
break; if (routeItem.id === 'ant-design-pro-layout') {
} proLayout = routeItem;
} break;
patchRouteItems(proLayout, remoteMenu, ''); }
} }
patchRouteItems(proLayout, remoteMenu, '');
/** 获取当前的用户 GET /api/getUserInfo */ }
export async function getUserInfo(options?: Record<string, any>) {
return request<API.UserInfoResult>('/api/getInfo', { /** 获取当前的用户 GET /api/getUserInfo */
method: 'GET', export async function getUserInfo(options?: Record<string, any>) {
...(options || {}), return request<API.UserInfoResult>('/api/getInfo', {
}); method: 'GET',
} ...(options || {}),
});
// 刷新方法 }
export async function refreshToken() {
return request('/api/auth/refresh', { // 刷新方法
method: 'post' export async function refreshToken() {
}) return request('/api/auth/refresh', {
} method: 'post'
})
export async function getRouters(): Promise<any> { }
return request('/api/getRouters');
} export async function getRouters(): Promise<any> {
return request('/api/getRouters');
export function convertCompatRouters(childrens: API.RoutersMenuItem[]): any[] { }
// childrens = childrens.filter((item) => item.meta !== undefined);
return childrens.map((item: API.RoutersMenuItem) => { export function convertCompatRouters(childrens: API.RoutersMenuItem[]): any[] {
if (!item.meta && item.children?.length) { // childrens = childrens.filter((item) => item.meta !== undefined);
item = item.children[0] return childrens.map((item: API.RoutersMenuItem) => {
} if (!item.meta && item.children?.length) {
return { item = item.children[0]
path: item.path, }
icon: item.meta && createIcon(item.meta.icon), return {
name: item.meta && item.meta.title, path: item.path,
routes: item.children ? convertCompatRouters(item.children) : undefined, icon: item.meta && createIcon(item.meta.icon),
hideChildrenInMenu: item.hidden, name: item.meta && item.meta.title,
hideInMenu: item.hidden, routes: item.children ? convertCompatRouters(item.children) : undefined,
component: item.component, hideChildrenInMenu: item.hidden,
authority: item.perms, hideInMenu: item.hidden,
}; component: item.component,
}); authority: item.perms,
} };
});
export async function getRoutersInfo(): Promise<MenuDataItem[]> { }
return getRouters().then((res) => {
if (res.code === 200) { export async function getRoutersInfo(): Promise<MenuDataItem[]> {
console.log(res.data) return getRouters().then((res) => {
console.log(convertCompatRouters(res.data)) if (res.code === 200) {
return convertCompatRouters(res.data); console.log(res.data)
} else { console.log(convertCompatRouters(res.data))
return []; return convertCompatRouters(res.data);
} } else {
}); return [];
} }
});
export function getMatchMenuItem( }
path: string,
menuData: MenuDataItem[] | undefined, export function getMatchMenuItem(
): MenuDataItem[] { path: string,
if (!menuData) return []; menuData: MenuDataItem[] | undefined,
let items: MenuDataItem[] = []; ): MenuDataItem[] {
menuData.forEach((item) => { if (!menuData) return [];
if (item.path) { let items: MenuDataItem[] = [];
if (item.path === path) { menuData.forEach((item) => {
items.push(item); if (item.path) {
return; if (item.path === path) {
} items.push(item);
if (path.length >= item.path?.length) { return;
const exp = `${item.path}/*`; }
if (path.match(exp)) { if (path.length >= item.path?.length) {
if (item.routes) { const exp = `${item.path}/*`;
const subpath = path.substr(item.path.length + 1); if (path.match(exp)) {
const subItem: MenuDataItem[] = getMatchMenuItem(subpath, item.routes); if (item.routes) {
items = items.concat(subItem); const subpath = path.substr(item.path.length + 1);
} else { const subItem: MenuDataItem[] = getMatchMenuItem(subpath, item.routes);
const paths = path.split('/'); items = items.concat(subItem);
if (paths.length >= 2 && paths[0] === item.path && paths[1] === 'index') { } else {
items.push(item); const paths = path.split('/');
} if (paths.length >= 2 && paths[0] === item.path && paths[1] === 'index') {
} items.push(item);
} }
} }
} }
}); }
return items; }
} });
return items;
}

View File

@@ -0,0 +1,49 @@
declare namespace API.StorageDetection {
export interface StorageDetailItem {
detailId?: string;
websiteId?: string;
websiteName?: string;
successNumber?: string;
failedNumber?: string;
storageDetail?: string;
storageTime?: string;
}
export interface StorageItem {
detectionId?: string;
storageDate?: string;
storageNumber?: string;
storageResult?: string;
storageDetail?: string;
websiteId?: string;
websiteName?: string;
details?: StorageDetailItem[];
}
export interface AddParams {
storageDate?: string;
storageNumber?: string;
storageResult?: string;
storageDetail?: string;
websiteName?: string;
}
export interface ListParams {
storageDate?: string;
pageSize?: number;
current?: number;
}
export interface StorageIdResult {
code: number;
msg: string;
data: StorageItem;
}
export interface StoragePageResult {
code: number;
msg: string;
total: number;
rows: Array<StorageItem>;
}
}