flat: 暂存

This commit is contained in:
史典卓
2025-03-28 15:30:35 +08:00
parent 2bf8cf55ac
commit b3238e5c2b
50 changed files with 3302 additions and 416 deletions

View File

@@ -1,18 +1,21 @@
import { Footer, Question, SelectLang, AvatarDropdown, AvatarName } from '@/components';
import { LinkOutlined } from '@ant-design/icons';
import { AvatarDropdown, AvatarName, Footer, SelectLang } from '@/components';
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
import { SettingDrawer } from '@ant-design/pro-components';
import type { RunTimeLayoutConfig } from '@umijs/max';
import { history, Link } from '@umijs/max';
import { history } from '@umijs/max';
import defaultSettings from '../config/defaultSettings';
import { errorConfig } from './requestErrorConfig';
import { clearSessionToken, getAccessToken, getRefreshToken, getTokenExpireTime } from './access';
import { getRemoteMenu, getRoutersInfo, getUserInfo, patchRouteWithRemoteMenus, setRemoteMenu } from './services/session';
import {
getRemoteMenu,
getRoutersInfo,
getUserInfo,
patchRouteWithRemoteMenus,
setRemoteMenu,
} from './services/session';
import { PageEnum } from './enums/pagesEnums';
import {logout} from "@/services/system/auth";
import { stringify } from 'querystring';
import { message } from 'antd'
import { createRef } from 'react';
import { message } from 'antd';
const isDev = process.env.NODE_ENV === 'development';
const loginOut = async () => {
@@ -23,7 +26,7 @@ const loginOut = async () => {
/** 此方法会跳转到 redirect 参数所在的位置 */
const redirect = urlParams.get('redirect');
// Note: There may be security issues, please note
console.log('redirect', window.location.pathname, redirect)
console.log('redirect', window.location.pathname, redirect);
if (window.location.pathname !== '/qingdao/user/login' && !redirect) {
history.replace({
pathname: '/user/login',
@@ -34,7 +37,6 @@ const loginOut = async () => {
}
};
/**
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state
* */
@@ -79,12 +81,12 @@ export async function getInitialState(): Promise<{
settings: defaultSettings as Partial<LayoutSettings>,
};
}
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
return {
// actionsRender: () => [<Question key="doc" />, <SelectLang key="SelectLang" />],
actionsRender: () => [ <SelectLang key="SelectLang" />],
actionsRender: () => [<SelectLang key="SelectLang" />],
avatarProps: {
src: initialState?.currentUser?.avatar,
title: <AvatarName />,
@@ -106,7 +108,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
if (!initialState?.currentUser?.userId) {
return [];
}
return getRemoteMenu()
return getRemoteMenu();
},
},
footerRender: () => <Footer />,
@@ -137,6 +139,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
width: '331px',
},
],
pure: false,
// links: isDev
// ? [
// <Link key="openapi" to="/umi/plugin/openapi" target="_blank">
@@ -174,9 +177,9 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
export async function onRouteChange({ clientRoutes, location }) {
const menus = getRemoteMenu();
// console.log('onRouteChange', clientRoutes, location, menus);
if(menus === null && location.pathname !== PageEnum.LOGIN) {
console.log('refresh')
// console.log('onRouteChange', clientRoutes, location, menus);
if (menus === null && location.pathname !== PageEnum.LOGIN) {
console.log('refresh');
// history.go(0);
}
}
@@ -185,24 +188,23 @@ export async function onRouteChange({ clientRoutes, location }) {
// console.log('patchRoutes', routes, routeComponents);
// }
export async function patchClientRoutes({ routes }) {
// console.log('patchClientRoutes', routes);
patchRouteWithRemoteMenus(routes);
}
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) {
if (!token || token?.length === 0) {
oldRender();
return;
}
await getRoutersInfo().then(res => {
console.log('render get routers', 123)
await getRoutersInfo().then((res) => {
console.log('render get routers', 123);
setRemoteMenu(res);
oldRender()
oldRender();
});
}
@@ -241,7 +243,7 @@ export const request = {
clearSessionToken();
}
}
if(process.env.NODE_ENV !== 'development') {
if (process.env.NODE_ENV !== 'development') {
if (url.startsWith('/api')) {
url = url.replace(/^\/api/, '');
}
@@ -255,15 +257,15 @@ export const request = {
const { data = {} as any, config } = response;
switch (data.code) {
case 401:
loginOut()
break
loginOut();
break;
}
if(data.code !== 200 && data.msg) {
message.info(data.msg)
if (data.code !== 200 && data.msg) {
message.info(data.msg);
}
console.log('data: ', data)
// console.log('data: ', data)
// console.log('config: ', config)
return response
return response;
},
],
};

View File

@@ -0,0 +1,24 @@
.mapContent {
height: 400px;
width: 100%;
min-width: 300px;
border: 1px solid #e8e8e8;
}
.AmapContainer {
position: relative;
padding-top: 26px;
.Amap_search {
position: absolute;
left: 0;
top: 0;
z-index: 9;
width: 100%;
}
}
.amap-logo
.amap-copyright {
display: none;
}

View File

@@ -0,0 +1,226 @@
import React, { Fragment, useEffect, useRef, useState } from 'react';
import style from './index.less';
import AMapLoader from '@amap/amap-jsapi-loader';
import { ProFormSelect } from '@ant-design/pro-components';
import img from './point.png';
import { Modal } from 'antd';
import { debounce } from '@/utils/tools';
declare global {
interface Window {
_AMapSecurityConfig?: {
securityJsCode: string;
};
}
}
export type MapProps = {
onSelect: (flag?: boolean, formVals?: unknown) => void;
onCancel: (flag?: boolean, formVals?: unknown) => void;
open: boolean;
};
export const aMapConfig = {
key: '9cfc9370bd8a941951da1cea0308e9e3',
securityJsCode: '7b16386c7f744c3ca05595965f2b037f',
};
const ProFromMap: React.FC<MapProps> = ({ open, onSelect, onCancel }) => {
const mapRef = useRef<any>(null);
const geocoderRef = useRef<any>(null);
const autoCompleteRef = useRef<any>(null);
const addMarkerRef = useRef<any>(null);
const markerRef = useRef<any>(null);
const locationList = useRef<any>([]);
const localData = useRef(null);
const [selectValue, setSelectValue] = useState<any>(null);
const [locationOptions, setLocationOptions] = useState(null);
useEffect(() => {
console.log('open', open);
if (!open) return;
window._AMapSecurityConfig = {
securityJsCode: aMapConfig.securityJsCode,
};
AMapLoader.load({
key: aMapConfig.key, // 申请好的Web端开发者Key首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: ['AMap.Scale'], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['...','...']
})
.then((AMap) => {
mapRef.current = new AMap.Map('container', {
// 设置地图容器id
viewMode: '3D', // 是否为3D地图模式
zoom: 11, // 初始化地图级别
center: [120.384599, 36.062687], // 初始化地图中心点位置
});
// 浏览器定位
AMap.plugin('AMap.Geolocation', function () {
var geolocation = new AMap.Geolocation({
enableHighAccuracy: false, //是否使用高精度定位,默认:true
timeout: 10000, //超过10秒后停止定位默认5s
position: 'RB', //定位按钮的停靠位置
offset: [10, 20], //定位按钮与设置的停靠位置的偏移量,默认:[10, 20]
zoomToAccuracy: true, //定位成功后是否自动调整地图视野到定位点
});
mapRef.current.addControl(geolocation);
geolocation.getCurrentPosition();
});
// 添加插件
AMap.plugin('AMap.AutoComplete', function () {
// 注意输入提示插件2.0版本需引入AMap.AutoComplete而1.4版本应使用AMap.Autocomplete
// 实例化AutoComplete
autoCompleteRef.current = new AMap.AutoComplete({
city: '370200', // 青岛市
citylimit: false,
});
});
// 将经纬度坐标转化为详细地址
AMap.plugin('AMap.Geocoder', () => {
geocoderRef.current = new AMap.Geocoder({
extensions: 'base',
batch: false,
city: '370200', // 青岛市
});
});
// 添加事件
mapRef.current.on('click', (eve) => {
console.log(eve);
const { lat, lng } = eve.lnglat;
if (geocoderRef.current && addMarkerRef.current) {
const lnglat1 = [lng, lat];
geocoderRef.current.getAddress(lnglat1, (status, result) => {
if (status === 'complete' && result.info === 'OK') {
const { formattedAddress } = result.regeocode;
const id = Date.now();
result.id = id;
result.address = formattedAddress;
result.location = {
lat: lat,
lng: lng,
};
setSelectValue(id);
setLocationOptions([result]);
localData.current = result;
console.log(result, '详细地址');
}
});
addMarkerRef.current && addMarkerRef.current(lnglat1);
}
});
addMarkerRef.current = (LngLat: any) => {
if (markerRef.current) {
mapRef.current.remove(markerRef.current);
markerRef.current = null;
addMarkerRef.current && addMarkerRef.current(LngLat);
} else {
markerRef.current = new AMap.Marker({
icon: new AMap.Icon({
size: new AMap.Size(32, 32), // 图标显示大小
image: img, // 自定义图标 URL
imageSize: new AMap.Size(32, 32), // 强制缩放原始图片大小
}),
anchor: 'bottom-center', // 设置锚点方位
position: LngLat, //标注点位置
title: `鼠标移入显示的提示`, //标注点标题
map: mapRef.current, //将标注点添加到地图上
});
}
};
// 获取输入提示信息
})
.catch((e) => {
console.log(e);
});
}, [open]);
useEffect(() => {
return () => {
mapRef.current?.destroy();
};
}, []);
function autoInput(keywords: string) {
return new Promise((resolve, reject) => {
autoCompleteRef.current.search(keywords, function (status: string, result) {
if (status === 'complete' && result.info === 'OK') {
// 搜索成功时result即是对应的匹配数据
resolve(result.tips);
} else {
reject(null);
}
});
});
}
const searchLocation = async (keyWords: string) => {
const keywordsToSearch = keyWords || '青岛';
const resData = await autoInput(keywordsToSearch);
locationList.current = resData;
setLocationOptions(resData);
return resData || [];
};
// 防抖版本(确保组件卸载时清除)
const debounceSearch = useRef(debounce(searchLocation, 500)).current;
function selectItem(id: any) {
const items = locationList.current.filter((item) => item.id === id);
if (items.length) {
const value = items[0];
setSelectValue(value.id);
addMarkerRef.current([value.location.lng, value.location.lat]);
mapRef.current.setZoomAndCenter(16, [value.location.lng, value.location.lat]);
localData.current = value;
}
}
function locationSuccess() {
if (localData.current) {
onSelect && onSelect(localData.current);
}
}
return (
<Fragment>
<Modal
open={open}
title="选择位置"
okText="确定"
cancelText="取消"
width={800}
onCancel={onCancel}
onOk={locationSuccess}
>
<div className={style.AmapContainer}>
<div className={style.Amap_search}>
<ProFormSelect
style={{
width: '100%',
}}
debounceTime={500}
name="select"
// request={searchLocation}
showSearch
placeholder="请输入地点"
fieldProps={{
onSelect: selectItem,
onSearch: debounceSearch,
value: selectValue,
options: locationOptions,
fieldNames: {
label: 'address',
value: 'id',
},
}}
/>
</div>
<div id="container" className={style.mapContent}></div>
</div>
</Modal>
</Fragment>
);
};
export default ProFromMap;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -5,8 +5,8 @@ body,
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
}
.colorWeak {
@@ -14,8 +14,9 @@ body,
}
.ant-layout {
min-height: 100vh;
min-height: 100vh !important;
}
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
left: unset;
}
@@ -39,11 +40,13 @@ ol {
.ant-table {
width: 100%;
overflow-x: auto;
&-thead > tr,
&-tbody > tr {
> th,
> td {
white-space: pre;
> span {
display: block;
}

11
src/models/testModel.ts Normal file
View File

@@ -0,0 +1,11 @@
// src/models/counterModel.ts
import { useCallback, useState } from 'react';
export default function Page() {
const [counter, setCounter] = useState(0);
const increment = useCallback(() => setCounter((c) => c + 1), []);
const decrement = useCallback(() => setCounter((c) => c - 1), []);
return { counter, increment, decrement };
}

View File

@@ -0,0 +1,128 @@
import { useEffect, useState } from 'react';
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormRadio,
ProFormSelect,
ProFormText,
} from '@ant-design/pro-components';
import { Form } from 'antd';
import { DictValueEnumObj } from '@/components/DictTag';
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: API.ApplicationProducts.Product) => Promise<void>;
open: boolean;
values?: Partial<API.ApplicationProducts.Product>;
// jobGroupOptions: DictOptionType[];
companyLabelEnum?: DictValueEnumObj;
companyNatureEnum?: DictValueEnumObj;
enableStatusEnum?: DictValueEnumObj;
};
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
const [colorHex, setColorHex] = useState('#3b82f6');
const { companyNatureEnum, companyLabelEnum, enableStatusEnum } = props;
useEffect(() => {
form.resetFields();
if (props.values) {
form.setFieldsValue({
...props.values,
status: String(props.values.status),
});
setColorHex(props.values.backgroudColor);
}
}, [form, props]);
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
// console.log(colorHex, values.backgroudColor);
if (typeof colorHex === 'string') {
values.backgroudColor = colorHex;
} else {
values.backgroudColor = values.backgroudColor.toHexString();
}
props.onSubmit(values as API.ApplicationProducts.Product);
};
return (
<ModalForm<{
name: string;
company: string;
}>
title={`${props.values ? '编辑' : '新增'}企业`}
form={form}
autoFocusFirstInput
open={props.open}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
initialValues={{
cardOrder: 0,
status: '0',
}}
>
<ProFormDigit label="InputNumber" name="companyCardId" disabled hidden={true} />
<ProForm.Group>
<ProFormText width="md" name="name" label="卡片名称" placeholder="请输入卡片名称" />
<ProFormSelect
width="md"
name="backgroudColor"
label="卡片背景色"
valueType="color"
disabledAlpha
placeholder="请选择单位规模"
fieldProps={{
value: colorHex,
onChange: (e) => setColorHex(e),
}}
/>
{/*<span>HEX: {colorHex.}</span>*/}
</ProForm.Group>
<ProForm.Group>
<ProFormSelect
width="md"
name="companyNature"
label="企业性质"
valueEnum={companyNatureEnum}
placeholder="请选择企业性质"
/>
<ProFormSelect
width="md"
name="targ"
label="企业标签"
valueEnum={companyLabelEnum}
placeholder="请选择企业标签"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormDigit width="md" label="排序" name="cardOrder" min={0} />
<ProFormRadio.Group
valueEnum={enableStatusEnum}
name="status"
label="启用状态"
width="md"
/>
</ProForm.Group>
</ModalForm>
);
};
export default listEdit;

View File

@@ -0,0 +1,221 @@
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { useAccess } from '@umijs/max';
import { Button, FormInstance, message, Modal, Switch } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { DeleteOutlined, FormOutlined, PieChartFilled, PlusOutlined } from '@ant-design/icons';
import EditCompanyListRow from './edit';
import { delCmsCompanyList } from '@/services/company/list';
import { getDictValueEnum } from '@/services/system/dict';
import {
addCmsCardList,
delCmsCardList,
getCmsCardList,
putCmsCardList,
} from '@/services/application/preproducts';
const handleRemoveOne = async (companyCardId: string) => {
const hide = message.loading('正在删除');
if (!companyCardId) return true;
try {
const resp = await delCmsCompanyList(companyCardId);
hide();
if (resp.code === 200) {
message.success('删除成功,即将刷新');
} else {
message.error(resp.msg);
}
return true;
} catch (error) {
hide();
message.error('删除失败,请重试');
return false;
}
};
function ManagementList() {
const access = useAccess();
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<API.ApplicationProducts.Product>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [companyNatureEnum, setCompanyNatureEnum] = useState<any>([]);
const [companyLabelEnum, setCompanyLabelEnum] = useState<any>([]);
const [enableStatusEnum, setEnableStatusEnum] = useState<any>([]);
useEffect(() => {
getDictValueEnum('company_nature', true, true).then((data) => {
setCompanyNatureEnum(data);
});
getDictValueEnum('company_label', true, true).then((data) => {
setCompanyLabelEnum(data);
});
getDictValueEnum('enable_status', true).then((data) => {
setEnableStatusEnum(data);
});
}, []);
const changeStatus = async (record: API.ApplicationProducts.Product) => {
let resData = await putCmsCardList({
companyCardId: record.companyCardId,
status: record.status === 1 ? 0 : 1,
});
if (resData.code === 200) {
message.success('修改成功');
if (actionRef.current) {
actionRef.current.reload();
}
}
};
const columns: ProColumns<API.ApplicationProducts.Product>[] = [
{
title: '卡片名称',
dataIndex: 'name',
valueType: 'text',
align: 'center',
},
{
title: '卡片颜色',
dataIndex: 'backgroudColor',
valueType: 'text',
align: 'center',
render: (text, _) => <PieChartFilled style={{ color: text }} />,
},
{
title: '排序',
dataIndex: 'cardOrder',
valueType: 'text',
align: 'center',
},
{
title: '启用状态',
dataIndex: 'status',
valueType: 'select',
align: 'center',
valueEnum: enableStatusEnum,
render: (text, record) => (
<Switch checked={record.status === 1} onChange={changeStatus.bind(null, record)} />
),
},
{
title: '操作',
hideInSearch: true,
align: 'center',
dataIndex: 'companyCardId',
width: 300,
render: (companyCardId, record) => [
<Button
type="link"
size="small"
key="edit"
icon={<FormOutlined />}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => {
setModalVisible(true);
setCurrentRow(record);
}}
>
</Button>,
<Button
type="link"
size="small"
danger
key="batchRemove"
icon={<DeleteOutlined />}
hidden={!access.hasPerms('area:subway:List')}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确定删除该项吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
const success = await delCmsCardList(companyCardId as string);
if (success) {
if (actionRef.current) {
actionRef.current.reload();
}
}
},
});
}}
>
</Button>,
],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.ApplicationProducts.Product>
// params 是需要自带的参数
// 这个参数优先级更高,会覆盖查询表单的参数
actionRef={actionRef}
formRef={formTableRef}
rowKey="companyCardId"
key="index"
columns={columns}
request={(params) =>
getCmsCardList({ ...params } as API.ApplicationProducts.Params).then((res) => {
return {
data: res.rows,
total: res.total,
success: true,
};
})
}
toolBarRender={() => [
<Button
type="primary"
key="add"
hidden={!access.hasPerms('manage:List:add')}
onClick={async () => {
setCurrentRow(undefined);
setModalVisible(true);
}}
>
<PlusOutlined />
</Button>,
]}
/>
</div>
<EditCompanyListRow
open={modalVisible}
onSubmit={async (values) => {
let resData;
if (values.companyCardId) {
resData = await putCmsCardList(values);
} else {
resData = await addCmsCardList(values);
}
if (resData.code === 200) {
setModalVisible(false);
setCurrentRow(undefined);
if (values.companyCardId) {
message.success('修改成功');
} else {
message.success('新增成功');
}
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
setModalVisible(false);
setCurrentRow(undefined);
}}
values={currentRow}
companyLabelEnum={companyLabelEnum}
companyNatureEnum={companyNatureEnum}
enableStatusEnum={enableStatusEnum}
></EditCompanyListRow>
</Fragment>
);
}
export default ManagementList;

View File

@@ -1,21 +1,14 @@
import { PlusOutlined } from '@ant-design/icons';
import {
ModalForm,
ProForm,
ProFormDateRangePicker,
ProFormSelect,
ProFormText,
ProFormDigit,
} from '@ant-design/pro-components';
import React, {useEffect} from "react";
import { Button, Form, message, InputNumber } from 'antd';
import {DictOptionType, DictValueEnumObj} from "@/components/DictTag";
import { ModalForm, ProForm, ProFormDigit, ProFormText } from '@ant-design/pro-components';
import React, { useEffect, useState } from 'react';
import { Button, Form } from 'antd';
import { DictOptionType, DictValueEnumObj } from '@/components/DictTag';
import ProFromMap from '@/components/ProFromMap';
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: API.AreaBusiness.CircleEditParams) => Promise<void>;
onSubmit: (values: API.AreaBusiness.CircleEditParams) => Promise<void>;
open: boolean;
values?: Partial< API.AreaBusiness.CircleEditParams>;
values?: Partial<API.AreaBusiness.CircleEditParams>;
jobGroupOptions?: DictOptionType[];
statusOptions?: DictValueEnumObj;
};
@@ -30,15 +23,24 @@ const waitTime = (time: number = 100) => {
const SubWayEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
const [open, setOpen] = useState<boolean>(false);
const [viewInfo, setViewInfo] = useState<any>({});
useEffect(() => {
form.resetFields();
if(props.values) {
form.setFieldsValue({
if (props.values) {
const obj = {
commercialAreaId: props.values.commercialAreaId,
commercialAreaName: props.values.commercialAreaName,
latitude: props.values.latitude,
longitude: props.values.longitude,
});
address: props.values.address,
};
form.setFieldsValue(obj);
setViewInfo(obj);
} else {
setViewInfo({});
}
}, [form, props]);
const handleCancel = () => {
@@ -47,10 +49,29 @@ const SubWayEdit: React.FC<ListFormProps> = (props) => {
};
const handleFinish = async (values: Record<string, any>) => {
console.log(values)
props.onSubmit(values as API.AreaBusiness.CircleEditParams);
};
const select = (result) => {
if (result.location) {
const { lat, lng } = result.location;
form.setFieldValue('latitude', lat);
form.setFieldValue('longitude', lng);
form.setFieldValue('address', result.address);
const obj = {
latitude: lat,
longitude: lng,
address: result.address,
};
setViewInfo(obj);
setOpen(false);
}
};
const cancel = () => {
setOpen(false);
};
return (
<ModalForm<API.AreaBusiness.CircleParams>
title={`${props.values ? '编辑' : '新增'}商圈`}
@@ -81,12 +102,36 @@ const SubWayEdit: React.FC<ListFormProps> = (props) => {
rules={[
{
required: true,
message: "请输入商圈名称!" ,
message: '请输入商圈名称!',
},
]}
/>
</ProForm.Group>
<ProForm.Group>
<div>
<Button onClick={() => setOpen(true)}></Button>
<div style={{ margin: '10px 0 0 0' }}>
{viewInfo.address ? (
<span style={{ padding: '0 0 0 16px' }}>{viewInfo.address}</span>
) : null}
{viewInfo.latitude ? (
<span style={{ padding: '0 0 0 16px' }}>
{viewInfo.latitude},{viewInfo.longitude}
</span>
) : (
<span style={{ padding: '0 0 0 16px', color: 'red' }}>!</span>
)}
</div>
</div>
</ProForm.Group>
<ProForm.Group>
<ProFormText
width="md"
name="address"
label="地理位置"
hidden={true}
placeholder="请输入地理位置"
/>
<ProFormDigit
label="纬度"
placeholder="请输入纬度"
@@ -94,11 +139,12 @@ const SubWayEdit: React.FC<ListFormProps> = (props) => {
width="md"
min={-90}
max={90}
hidden={true}
fieldProps={{ controls: false }}
rules={[
{
required: true,
message: "请输入纬度!" ,
message: '请输入纬度!',
},
]}
/>
@@ -108,18 +154,20 @@ const SubWayEdit: React.FC<ListFormProps> = (props) => {
name="longitude"
width="md"
min={-180}
hidden={true}
max={180}
fieldProps={{ controls: false }}
rules={[
{
required: true,
message: "请输入经度!" ,
message: '请输入经度!',
},
]}
/>
</ProForm.Group>
<ProFromMap open={open} onSelect={select} onCancel={cancel}></ProFromMap>
</ModalForm>
);
};
export default SubWayEdit
export default SubWayEdit;

View File

@@ -1,12 +1,9 @@
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormText,
} from '@ant-design/pro-components';
import { Form } from 'antd';
import {DictOptionType, DictValueEnumObj} from "@/components/DictTag";
import {useEffect} from 'react'
import { ModalForm, ProForm, ProFormDigit, ProFormText } from '@ant-design/pro-components';
import { Button, Form } from 'antd';
import { DictOptionType, DictValueEnumObj } from '@/components/DictTag';
import { useEffect, useState } from 'react';
import ProFromMap from '@/components/ProFromMap';
export type ListFormProps = {
onCancel: (flag?: boolean, formVars?: unknown) => void;
onSubmit: (values: API.AreaSubWay.LinePoint) => Promise<void>;
@@ -27,15 +24,14 @@ const waitTime = (time: number = 100) => {
const SubWayEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
const [open, setOpen] = useState<boolean>(false);
const [viewInfo, setViewInfo] = useState<any>({});
useEffect(() => {
form.resetFields();
if(props.values) {
form.setFieldsValue({
stationName: props.values.stationName,
stationId: props.values.stationId,
longitude: props.values.longitude,
latitude: props.values.latitude,
});
if (props.values) {
form.setFieldsValue(props.values);
setViewInfo(props.values);
}
}, [form, props]);
@@ -48,10 +44,31 @@ const SubWayEdit: React.FC<ListFormProps> = (props) => {
props.onSubmit(values as API.AreaSubWay.LinePoint);
};
const select = (result) => {
if (result.location) {
const { lat, lng } = result.location;
form.setFieldValue('latitude', lat);
form.setFieldValue('longitude', lng);
form.setFieldValue('address', result.address);
const obj = {
latitude: lat,
longitude: lng,
address: result.address,
};
setViewInfo(obj);
setOpen(false);
}
};
const cancel = () => {
setOpen(false);
};
return (
<ModalForm<{
name: string;
company: string;
stationOrder: number;
}>
title={`${props.values ? '编辑' : '新增'}站点`}
form={form}
@@ -62,6 +79,9 @@ const SubWayEdit: React.FC<ListFormProps> = (props) => {
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
initialValues={{
sort: 0,
}}
submitTimeout={2000}
onFinish={handleFinish}
>
@@ -76,23 +96,66 @@ const SubWayEdit: React.FC<ListFormProps> = (props) => {
<ProFormText
width="md"
name="stationName"
label="站点名称:"
label="站点名称"
placeholder="请输入名称"
rules={[
{
required: true,
message: '请输入名称!',
},
]}
/>
<ProFormDigit
width="md"
label="排序"
name="stationOrder"
placeholder="请输入排序"
rules={[
{
required: true,
message: '请输入排序!',
},
]}
/>
</ProForm.Group>
<ProForm.Group>
<div>
<Button onClick={() => setOpen(true)}></Button>
<div style={{ margin: '10px 0 0 0' }}>
{viewInfo.address ? (
<span style={{ padding: '0 0 0 16px' }}>{viewInfo.address}</span>
) : null}
{viewInfo.latitude ? (
<span style={{ padding: '0 0 0 16px' }}>
{viewInfo.latitude},{viewInfo.longitude}
</span>
) : (
<span style={{ padding: '0 0 0 16px', color: 'red' }}>!</span>
)}
</div>
</div>
</ProForm.Group>
<ProForm.Group>
<ProFormText
width="md"
name="address"
label="地理位置"
hidden={true}
placeholder="请输入地理位置"
/>
<ProFormDigit
label="纬度"
placeholder="请输入纬度"
name="latitude"
width="md"
hidden={true}
min={-90}
max={90}
fieldProps={{ controls: false }}
rules={[
{
required: true,
message: "请输入纬度!" ,
message: '请输入纬度!',
},
]}
/>
@@ -102,18 +165,20 @@ const SubWayEdit: React.FC<ListFormProps> = (props) => {
name="longitude"
width="md"
min={-180}
hidden={true}
max={180}
fieldProps={{ controls: false }}
rules={[
{
required: true,
message: "请输入经度!" ,
message: '请输入经度!',
},
]}
/>
</ProForm.Group>
<ProFromMap open={open} onSelect={select} onCancel={cancel}></ProFromMap>
</ModalForm>
);
};
export default SubWayEdit
export default SubWayEdit;

View File

@@ -1,16 +1,20 @@
import React, {Fragment, useRef, useState, useCallback} from "react";
import { useIntl, FormattedMessage, useAccess, history } from '@umijs/max';
import { Dropdown, FormInstance, Space, Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, FormOutlined, DownOutlined, EditOutlined } from '@ant-design/icons';
import {getCmsLineListPlatForm, addCmsLinePlatForm, deleteCmsLinePlatForm} from "@/services/area/upline";
import UpStationEdit from "@/pages/Area/Subway/UpLine/edit";
import {getCmsLineSubWay} from "@/services/area/subway";
const handleRemoveOne = async (selectedRow: API.AreaSubWay.Line) => {
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react';
import { useAccess, useParams } from '@umijs/max';
import { Button, FormInstance, message, Modal } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { DeleteOutlined, FormOutlined, PlusOutlined } from '@ant-design/icons';
import {
addCmsLinePlatForm,
deleteCmsLinePlatForm,
getCmsLineListPlatForm,
} from '@/services/area/upline';
import UpStationEdit from '@/pages/Area/Subway/UpLine/edit';
const handleRemoveOne = async (selectedRow: API.AreaSubWay.LinePoint) => {
const hide = message.loading('正在删除');
if (!selectedRow) return true;
try {
const resp = await deleteCmsLinePlatForm(selectedRow.lineId);
const resp = await deleteCmsLinePlatForm(selectedRow.stationId);
hide();
if (resp.code === 200) {
message.success('删除成功,即将刷新');
@@ -30,43 +34,34 @@ function ManagementList() {
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<API.AreaPlatForm.Line>()
const [modalVisible, setModalVisible] = useState<boolean>(false)
const [page, setPage] = useState<API.AreaPlatForm.LineParams>({})
const [lineId, setLineId] = useState<string>();
const [currentRow, setCurrentRow] = useState<API.AreaPlatForm.LinePoint>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [page, setPage] = useState<API.AreaPlatForm.LineParams>({});
const params = useParams();
const id = params.id || '0';
useEffect(() => {
if (lineId !== id) {
setLineId(id);
}
}, [lineId, params]);
const getStationInfo = useCallback(async () => {
// const resData = await getCmsLineSubWay()
}, [])
}, []);
const columns: ProColumns<API.AreaSubWay.Line>[] = [
{
title: '序号',
dataIndex: 'index',
valueType: 'index',
align: 'center',
width: 48,
render: (dom, record, index) => {
if(page.current && page.pageSize) {
return (page.current - 1) * page.pageSize + index + 1
} else {
return ''
}
}
},
// {
// title: '线路名称',
// dataIndex: 'lineName',
// align: 'center',
// search: false,
// valueType: 'text',
// },
const columns: ProColumns<API.AreaSubWay.LinePoint>[] = [
{
title: '站点名称',
dataIndex: 'stationName',
align: 'center',
valueType: 'text',
},
{
title: '排序',
dataIndex: 'stationOrder',
align: 'center',
valueType: 'text',
},
{
title: '操作',
hideInSearch: true,
@@ -77,7 +72,7 @@ function ManagementList() {
type="link"
size="small"
key="edit"
icon={<FormOutlined/>}
icon={<FormOutlined />}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => {
setModalVisible(true);
@@ -91,7 +86,7 @@ function ManagementList() {
size="small"
danger
key="batchRemove"
icon ={<DeleteOutlined/>}
icon={<DeleteOutlined />}
hidden={!access.hasPerms('area:subway:List')}
onClick={async () => {
Modal.confirm({
@@ -111,10 +106,10 @@ function ManagementList() {
}}
>
</Button>
]
}
]
</Button>,
],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
@@ -124,19 +119,22 @@ function ManagementList() {
actionRef={actionRef}
formRef={formTableRef}
columns={columns}
headerTitle='信息'
rowKey="lineId"
key="lineIdList"
headerTitle="信息"
rowKey="stationId"
key="stationId"
request={(params) => {
return getCmsLineListPlatForm(params as API.AreaPlatForm.LineParams).then((res) => {
setPage(params as API.AreaPlatForm.LineParams)
return getCmsLineListPlatForm({
lineId,
...params,
} as API.AreaPlatForm.LineParams).then((res) => {
setPage(params as API.AreaPlatForm.LineParams);
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
});
}}
toolBarRender={() => [
<Button
@@ -157,16 +155,16 @@ function ManagementList() {
open={modalVisible}
onCancel={() => {
setModalVisible(false);
setCurrentRow(undefined)
setCurrentRow(undefined);
}}
onSubmit={async (values) => {
// values.lineId =
// values.lineName =
const resData = await addCmsLinePlatForm(values)
const resData = await addCmsLinePlatForm(values);
if (resData.code === 200) {
setModalVisible(false);
setCurrentRow(undefined);
message.success('添加成功')
message.success('添加成功');
if (actionRef.current) {
actionRef.current.reload();
}
@@ -175,6 +173,7 @@ function ManagementList() {
values={currentRow}
></UpStationEdit>
</Fragment>
)
);
}
export default ManagementList
export default ManagementList;

View File

@@ -1,10 +1,16 @@
import React, {Fragment, useRef, useState} from "react";
import { useIntl, FormattedMessage, useAccess, history } from '@umijs/max';
import { Dropdown, FormInstance, Space, Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, FormOutlined, DownOutlined, EditOutlined } from '@ant-design/icons';
import {getCmsLineList, addCmsLineSubWay, deleteCmsLineSubWay, putCmsLineSubWay} from "@/services/area/subway";
import SubWayEdit from "@/pages/Area/Subway/edit";
import React, { Fragment, useRef, useState } from 'react';
import { history, useAccess } from '@umijs/max';
import { Button, FormInstance, message, Modal } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { DeleteOutlined, FormOutlined, PlusOutlined } from '@ant-design/icons';
import {
addCmsLineSubWay,
deleteCmsLineSubWay,
getCmsLineList,
putCmsLineSubWay,
} from '@/services/area/subway';
import SubWayEdit from '@/pages/Area/Subway/edit';
const handleRemoveOne = async (selectedRow: API.AreaSubWay.Line) => {
const hide = message.loading('正在删除');
if (!selectedRow) return true;
@@ -30,8 +36,8 @@ function ManagementList() {
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<API.AreaSubWay.Line>()
const [modalVisible, setModalVisible] = useState<boolean>(false)
const [currentRow, setCurrentRow] = useState<API.AreaSubWay.Line>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const columns: ProColumns<API.AreaSubWay.Line>[] = [
{
@@ -39,9 +45,15 @@ function ManagementList() {
dataIndex: 'lineName',
align: 'center',
valueType: 'text',
render: (dom, record) => <Button type="link" onClick={() => history.push(`/area/updata-router/index?lineId=${record.lineId}`)} block>
{dom}
</Button>
render: (dom, record) => (
<Button
type="link"
onClick={() => history.push(`/area/updata-router/index/${record.lineId}`)}
block
>
{dom}
</Button>
),
},
{
title: '操作',
@@ -53,7 +65,7 @@ function ManagementList() {
type="link"
size="small"
key="edit"
icon={<FormOutlined/>}
icon={<FormOutlined />}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => {
setModalVisible(true);
@@ -67,7 +79,7 @@ function ManagementList() {
size="small"
danger
key="batchRemove"
icon = <DeleteOutlined/>
icon=<DeleteOutlined />
hidden={!access.hasPerms('area:subway:List')}
onClick={async () => {
Modal.confirm({
@@ -87,10 +99,10 @@ function ManagementList() {
}}
>
</Button>
]
}
]
</Button>,
],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
@@ -100,19 +112,19 @@ function ManagementList() {
actionRef={actionRef}
formRef={formTableRef}
columns={columns}
headerTitle='信息'
headerTitle="信息"
rowKey="lineId"
key="lineIdList"
request={(params) => {
return getCmsLineList(params as API.AreaSubWay.LineParams).then((res) => {
console.log(params)
console.log(params);
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
});
}}
toolBarRender={() => [
<Button
@@ -134,17 +146,17 @@ function ManagementList() {
onSubmit={async (values) => {
let resData;
if (values.lineId) {
resData = await putCmsLineSubWay(values)
resData = await putCmsLineSubWay(values);
} else {
resData = await addCmsLineSubWay(values)
resData = await addCmsLineSubWay(values);
}
if (resData.code === 200) {
setModalVisible(false);
setCurrentRow(undefined);
if(values.lineId) {
message.success('修改成功')
if (values.lineId) {
message.success('修改成功');
} else {
message.success('新增成功')
message.success('新增成功');
}
if (actionRef.current) {
actionRef.current.reload();
@@ -153,11 +165,12 @@ function ManagementList() {
}}
onCancel={() => {
setModalVisible(false);
setCurrentRow(undefined)
setCurrentRow(undefined);
}}
values={currentRow}
></SubWayEdit>
</Fragment>
)
);
}
export default ManagementList
export default ManagementList;

View File

@@ -0,0 +1,144 @@
import React, { useEffect } from 'react';
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormRadio,
ProFormSelect,
ProFormText,
} from '@ant-design/pro-components';
import { Form } from 'antd';
import { DictValueEnumObj } from '@/components/DictTag';
import { FormattedMessage } from '@@/exports';
import { getCmsIndustryTree } from '@/services/classify/industry';
export type ListFormProps = {
onCancel: (flag?: boolean, formVars?: unknown) => void;
onSubmit: (values: API.ClassifyIndustry.IndustryRow) => Promise<void>;
open: boolean;
values?: Partial<API.ClassifyIndustry.IndustryRow>;
// industryStatusEnum: DictOptionType[];
industryStatusEnum: DictValueEnumObj;
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
const { industryStatusEnum } = props;
useEffect(() => {
form.resetFields();
if (props.values) {
form.setFieldsValue(props.values);
}
}, [form, props]);
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
props.onSubmit(values as API.ClassifyIndustry.IndustryRow);
};
return (
<ModalForm<{
name: string;
company: string;
}>
title={`${props.values ? '编辑' : '新增'}行业`}
form={form}
autoFocusFirstInput
open={props.open}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
// readonly
>
<ProFormDigit label="InputNumber" name="industryId" disabled hidden={true} />
<ProForm.Group>
<ProFormText width="md" name="industryName" label="行业名称" placeholder="请输入行业名称" />
<ProFormDigit
label="显示顺序"
name="orderNum"
width="md"
min={0}
placeholder="请输入显示顺序"
/>
</ProForm.Group>
<ProForm.Group>
{/* 多级 */}
{/*<ProFormTreeSelect*/}
{/* name="parentId"*/}
{/* label="父行业"*/}
{/* placeholder="请选择父行业"*/}
{/* allowClear*/}
{/* width="md"*/}
{/* request={async () => {*/}
{/* return getCmsIndustryTree().then((res) => {*/}
{/* return res.data;*/}
{/* });*/}
{/* }}*/}
{/* fieldProps={{*/}
{/* suffixIcon: null,*/}
{/* filterTreeNode: true,*/}
{/* showSearch: true,*/}
{/* popupMatchSelectWidth: false,*/}
{/* labelInValue: false,*/}
{/* autoClearSearchValue: true,*/}
{/* multiple: false,*/}
{/* treeNodeFilterProp: 'title',*/}
{/* fieldNames: {*/}
{/* label: 'label',*/}
{/* value: 'id',*/}
{/* children: 'children',*/}
{/* },*/}
{/* }}*/}
{/*/>*/}
{/* 2级 */}
<ProFormSelect
name="parentId"
label="父行业"
allowClear
width="md"
placeholder="请选择父行业"
request={async () => {
return getCmsIndustryTree().then((res) => {
return res.data;
});
}}
colProps={{ md: 12, xl: 12 }}
rules={[{ required: true, message: '请选择父行业!' }]}
fieldProps={{
suffixIcon: null,
showSearch: true,
popupMatchSelectWidth: false,
labelInValue: false,
autoClearSearchValue: true,
fieldNames: {
label: 'label',
value: 'id',
},
}}
/>
<ProFormRadio.Group
valueEnum={industryStatusEnum}
name="status"
label="行业状态"
width="md"
placeholder="请输入状态"
rules={[
{
required: false,
message: <FormattedMessage id="请输入状态!" defaultMessage="请选择行业状态!" />,
},
]}
/>
</ProForm.Group>
</ModalForm>
);
};
export default listEdit;

View File

@@ -0,0 +1,221 @@
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { FormattedMessage, useAccess } from '@umijs/max';
import { Button, FormInstance, message, Modal } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { DeleteOutlined, FormOutlined, PlusOutlined } from '@ant-design/icons';
import EditCompanyListRow from './edit';
import {
addCmsIndustryIndustryt,
delCmsIndustryList,
exportCmsIndustry,
getCmsIndustryList,
updateCmsIndustryIndustryt,
} from '@/services/classify/industry';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
const handleRemoveOne = async (industryId: string) => {
const hide = message.loading('正在删除');
if (!industryId) return true;
try {
const resp = await delCmsIndustryList(industryId);
hide();
if (resp.code === 200) {
message.success('删除成功,即将刷新');
} else {
message.error(resp.msg);
}
return true;
} catch (error) {
hide();
message.error('删除失败,请重试');
return false;
}
};
const handleExport = async (values: API.ClassifyIndustry.Params) => {
const hide = message.loading('正在导出');
try {
await exportCmsIndustry(values);
hide();
message.success('导出成功');
return true;
} catch (error) {
hide();
message.error('导出失败,请重试');
return false;
}
};
function ManagementList() {
const access = useAccess();
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<API.ClassifyIndustry.IndustryRow>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [industryStatusEnum, setIndustryStatusEnum] = useState<any>([]);
useEffect(() => {
getDictValueEnum('sys_industry_status', true).then((data) => {
setIndustryStatusEnum(data);
});
}, []);
const editSubmit = () => {};
const columns: ProColumns<API.ClassifyIndustry.IndustryRow>[] = [
{
title: '行业名称',
dataIndex: 'industryName',
valueType: 'text',
align: 'center',
},
{
title: '显示顺序',
dataIndex: 'orderNum',
valueType: 'text',
hideInSearch: true,
align: 'center',
},
{
title: '状态',
dataIndex: 'status',
align: 'center',
valueType: 'select',
valueEnum: industryStatusEnum,
render: (_, record) => {
return <DictTag enums={industryStatusEnum} value={record.status} />;
},
},
{
title: '操作',
hideInSearch: true,
align: 'center',
dataIndex: 'industryId',
width: 300,
render: (industryId, record) => [
<Button
type="link"
size="small"
key="edit"
icon={<FormOutlined />}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => {
setModalVisible(true);
setCurrentRow(record);
}}
>
</Button>,
<Button
type="link"
size="small"
danger
key="batchRemove"
icon={<DeleteOutlined />}
hidden={!access.hasPerms('area:subway:List')}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确定删除该项吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
const success = await handleRemoveOne(industryId as string);
if (success) {
if (actionRef.current) {
actionRef.current.reload();
}
}
},
});
}}
>
</Button>,
],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.ClassifyIndustry.IndustryRow>
// params 是需要自带的参数
// 这个参数优先级更高,会覆盖查询表单的参数
actionRef={actionRef}
formRef={formTableRef}
rowKey="industryId"
key="index"
columns={columns}
request={(params) =>
getCmsIndustryList({ ...params } as API.ClassifyIndustry.Params).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
}
toolBarRender={() => [
<Button
type="primary"
key="add"
hidden={!access.hasPerms('manage:List:add')}
onClick={async () => {
setCurrentRow(undefined);
setModalVisible(true);
}}
>
<PlusOutlined />
</Button>,
<Button
key="export"
hidden={!access.hasPerms('system:user:export')}
onClick={async () => {
const searchVal = formTableRef.current && formTableRef.current.getFieldsValue();
handleExport(searchVal as API.ClassifyIndustry.Params);
}}
>
<PlusOutlined />
<FormattedMessage id="pages.searchTable.export" defaultMessage="导出" />
</Button>,
]}
/>
</div>
<EditCompanyListRow
open={modalVisible}
onSubmit={async (values) => {
let resData;
if (values.industryId) {
resData = await updateCmsIndustryIndustryt(values);
} else {
resData = await addCmsIndustryIndustryt(values);
}
if (resData.code === 200) {
setModalVisible(false);
setCurrentRow(undefined);
if (values.industryId) {
message.success('修改成功');
} else {
message.success('新增成功');
}
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
setModalVisible(false);
setCurrentRow(undefined);
}}
industryStatusEnum={industryStatusEnum}
values={currentRow}
></EditCompanyListRow>
</Fragment>
);
}
export default ManagementList;

View File

@@ -0,0 +1,78 @@
import { useEffect } from 'react';
import {
ModalForm,
ProForm,
ProFormDigit,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { Form } from 'antd';
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: API.CompanyList.Company) => Promise<void>;
open: boolean;
values?: Partial<API.CompanyList.Company>;
// jobGroupOptions: DictOptionType[];
// statusOptions: DictValueEnumObj;
};
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
useEffect(() => {
form.resetFields();
if (props.values) {
form.setFieldsValue(props.values);
}
}, [form, props]);
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
props.onSubmit(values as API.CompanyList.Company);
};
return (
<ModalForm<{
name: string;
company: string;
}>
title={`${props.values ? '编辑' : '新增'}企业`}
form={form}
autoFocusFirstInput
open={props.open}
modalProps={{
destroyOnClose: true,
onCancel: () => handleCancel(),
}}
submitTimeout={2000}
onFinish={handleFinish}
>
<ProFormDigit label="InputNumber" name="companyId" disabled hidden={true} />
<ProForm.Group>
<ProFormText width="md" name="name" label="单位名称" placeholder="请输入单位名称" />
</ProForm.Group>
<ProForm.Group>
<ProFormText width="md" name="code" label="信用代码" placeholder="请输入信用代码" />
<ProFormText width="md" name="industry" label="主要行业" placeholder="请输入主要行业" />
</ProForm.Group>
<ProForm.Group>
<ProFormTextArea width="xl" name="location" label="单位地点" placeholder="请输入单位地点" />
</ProForm.Group>
</ModalForm>
);
};
export default listEdit;

View File

@@ -0,0 +1,216 @@
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { FormattedMessage, useAccess } from '@umijs/max';
import { Button, FormInstance, message, Modal } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
import EditCompanyListRow from './edit';
import { addCmsCompanyList, delCmsCompanyList, putCmsCompanyList } from '@/services/company/list';
import { exportCmsJobTitleList, getCmsJobTitleList } from '@/services/classify/jobs';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
const handleRemoveOne = async (jobId: string) => {
const hide = message.loading('正在删除');
if (!jobId) return true;
try {
const resp = await delCmsCompanyList(jobId);
hide();
if (resp.code === 200) {
message.success('删除成功,即将刷新');
} else {
message.error(resp.msg);
}
return true;
} catch (error) {
hide();
message.error('删除失败,请重试');
return false;
}
};
const handleExport = async (values: API.ClassifyJobs.Params) => {
const hide = message.loading('正在导出');
try {
await exportCmsJobTitleList(values);
hide();
message.success('导出成功');
return true;
} catch (error) {
hide();
message.error('导出失败,请重试');
return false;
}
};
function ManagementList() {
const access = useAccess();
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<API.ClassifyJobs.Jobs>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [jobsStatusEnum, setJobsStatusEnum] = useState<any>([]);
useEffect(() => {
getDictValueEnum('sys_jobs_status', true).then((data) => {
setJobsStatusEnum(data);
});
}, []);
const editSubmit = () => {};
const columns: ProColumns<API.ClassifyJobs.Jobs>[] = [
{
title: '岗位名称',
dataIndex: 'jobName',
valueType: 'text',
align: 'center',
},
{
title: '显示顺序',
dataIndex: 'orderNum',
valueType: 'text',
hideInSearch: true,
align: 'center',
},
{
title: '状态',
dataIndex: 'status',
align: 'center',
valueType: 'select',
valueEnum: jobsStatusEnum,
render: (_, record) => {
return <DictTag enums={jobsStatusEnum} value={record.status} />;
},
},
{
title: '操作',
hideInSearch: true,
align: 'center',
dataIndex: 'companyId',
width: 300,
render: (companyId, record) => [
// <Button
// type="link"
// size="small"
// key="edit"
// icon={<FormOutlined />}
// hidden={!access.hasPerms('area:business:List.update')}
// onClick={() => {
// setModalVisible(true);
// setCurrentRow(record);
// }}
// >
// 编辑
// </Button>,
<Button
type="link"
size="small"
danger
key="batchRemove"
icon={<DeleteOutlined />}
hidden={!access.hasPerms('area:subway:List')}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确定删除该项吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
const success = await handleRemoveOne(companyId as string);
if (success) {
if (actionRef.current) {
actionRef.current.reload();
}
}
},
});
}}
>
</Button>,
],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.ClassifyJobs.Jobs>
// params 是需要自带的参数
// 这个参数优先级更高,会覆盖查询表单的参数
actionRef={actionRef}
formRef={formTableRef}
rowKey="jobId"
key="index"
columns={columns}
request={(params) =>
getCmsJobTitleList({ ...params } as API.ClassifyJobs.Params).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
}
toolBarRender={() => [
// <Button
// type="primary"
// key="add"
// hidden={!access.hasPerms('manage:List:add')}
// onClick={async () => {
// setCurrentRow(undefined);
// setModalVisible(true);
// }}
// >
// <PlusOutlined /> 新建
// </Button>,
<Button
type="primary"
key="export"
hidden={!access.hasPerms('system:user:export')}
onClick={async () => {
const searchVal = formTableRef.current && formTableRef.current.getFieldsValue();
handleExport(searchVal as API.ClassifyJobs.Params);
}}
>
<PlusOutlined />
<FormattedMessage id="pages.searchTable.export" defaultMessage="导出" />
</Button>,
]}
/>
</div>
<EditCompanyListRow
open={modalVisible}
onSubmit={async (values) => {
let resData;
if (values.companyId) {
resData = await putCmsCompanyList(values);
} else {
resData = await addCmsCompanyList(values);
}
if (resData.code === 200) {
setModalVisible(false);
setCurrentRow(undefined);
if (values.companyId) {
message.success('修改成功');
} else {
message.success('新增成功');
}
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
setModalVisible(false);
setCurrentRow(undefined);
}}
values={currentRow}
></EditCompanyListRow>
</Fragment>
);
}
export default ManagementList;

View File

@@ -1,13 +1,16 @@
import {useEffect} from 'react'
import { useEffect } from 'react';
import {
ModalForm,
ProForm,
ProFormTextArea,
ProFormDigit,
ProFormSelect,
ProFormText,
ProFormDigit
ProFormTextArea,
ProFormTreeSelect,
} from '@ant-design/pro-components';
import { Button, Form, message } from 'antd';
import {DictOptionType, DictValueEnumObj} from "@/components/DictTag";
import { Form } from 'antd';
import { DictValueEnumObj } from '@/components/DictTag';
import { getCmsIndustryTree } from '@/services/classify/industry';
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
@@ -15,7 +18,7 @@ export type ListFormProps = {
open: boolean;
values?: Partial<API.CompanyList.Company>;
// jobGroupOptions: DictOptionType[];
// statusOptions: DictValueEnumObj;
scaleEnum?: DictValueEnumObj;
};
const waitTime = (time: number = 100) => {
@@ -28,21 +31,24 @@ const waitTime = (time: number = 100) => {
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm();
const { scaleEnum } = props;
useEffect(() => {
form.resetFields();
if(props.values) {
form.setFieldsValue(props.values);
if (props.values) {
form.setFieldsValue({
...props.values,
// industry: props.values.industry.split(','),
});
}
}, [form, props]);
const handleCancel = () => {
props.onCancel();
form.resetFields();
};
const handleFinish = async (values: Record<string, any>) => {
// values.industry = values.industry.join(',');
props.onSubmit(values as API.CompanyList.Company);
};
@@ -62,44 +68,60 @@ const listEdit: React.FC<ListFormProps> = (props) => {
submitTimeout={2000}
onFinish={handleFinish}
>
<ProFormDigit
label="InputNumber"
name="companyId"
disabled
hidden={true}
/>
<ProFormDigit label="InputNumber" name="companyId" disabled hidden={true} />
<ProForm.Group>
<ProFormText
<ProFormText width="md" name="name" label="单位名称" placeholder="请输入单位名称" />
<ProFormSelect
width="md"
name="name"
label="单位名称"
placeholder="请输入单位名称"
name="scale"
label={'单位规模'}
valueEnum={scaleEnum}
placeholder="请选择单位规模"
rules={[{ required: true, message: '请选择单位规模!' }]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText
width="md"
name="code"
label="信用代码"
placeholder="请输入信用代码"
/>
<ProFormText
width="md"
<ProFormText width="md" name="code" label="信用代码" placeholder="请输入信用代码" />
{/*<ProFormText width="md" name="industry" label="主要行业" placeholder="请输入主要行业" />*/}
<ProFormTreeSelect
name="industry"
label="主要行业"
placeholder="请输入主要行业"
allowClear
width="md"
request={async () => {
return getCmsIndustryTree().then((res) => {
return res.data;
});
}}
fieldProps={{
suffixIcon: null,
filterTreeNode: true,
showSearch: true,
popupMatchSelectWidth: false,
labelInValue: false,
autoClearSearchValue: true,
multiple: false,
treeNodeFilterProp: 'title',
fieldNames: {
label: 'label',
value: 'id',
children: 'children',
},
}}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText width="xl" name="location" label="单位地点" placeholder="请输入单位地点" />
<ProFormTextArea
width="xl"
name="location"
label="单位地点"
placeholder="请输入单位地点"
name="description"
label="单位介绍"
placeholder="请输入单位介绍"
/>
</ProForm.Group>
</ModalForm>
);
};
export default listEdit
export default listEdit;

View File

@@ -1,17 +1,18 @@
import React, {Fragment, useRef, useState, useEffect} from "react";
import { useIntl, FormattedMessage, useAccess, history } from '@umijs/max';
import {delCmsJobIds, getCmsJobList} from "@/services/Management/list";
import { Dropdown, FormInstance, Space, Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, FormOutlined, DownOutlined, EditOutlined } from '@ant-design/icons';
import EditCompanyListRow from './edit'
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { FormattedMessage, useAccess } from '@umijs/max';
import { Button, FormInstance, message, Modal } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { DeleteOutlined, FormOutlined, PlusOutlined } from '@ant-design/icons';
import EditCompanyListRow from './edit';
import {
addCmsCompanyList,
delCmsCompanyList,
exportCmsCompanyList,
getCmsCompanyList,
putCmsCompanyList
} from "@/services/company/list";
putCmsCompanyList,
} from '@/services/company/list';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
const handleRemoveOne = async (jobId: string) => {
const hide = message.loading('正在删除');
@@ -52,27 +53,23 @@ function ManagementList() {
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState<API.CompanyList.Company>()
const [modalVisible, setModalVisible] = useState<boolean>(false)
const [salaryEnum, setSalaryEnum] = useState<any>([])
const [currentRow, setCurrentRow] = useState<API.CompanyList.Company>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [scaleEnum, setScaleEnum] = useState<any>([]);
useEffect(() => {
// getDictValueEnum('salary', true).then((data) => {
// setSalaryEnum(data)
// });
getDictValueEnum('scale', true, true).then((data) => {
setScaleEnum(data);
});
}, []);
const editSubmit = () => {
}
const editSubmit = () => {};
const columns: ProColumns<API.CompanyList.Company>[] = [
{
title: '公司名称',
dataIndex: 'name',
valueType: 'text',
hideInSearch: true,
align: 'center',
},
{
@@ -84,9 +81,12 @@ function ManagementList() {
{
title: '公司规模',
dataIndex: 'scale',
valueType: 'text',
// hideInSearch: true,
valueType: 'select',
align: 'center',
valueEnum: scaleEnum,
render: (_, record) => {
return <DictTag enums={scaleEnum} value={record.scale} />;
},
},
{
title: '公司位置',
@@ -106,7 +106,7 @@ function ManagementList() {
type="link"
size="small"
key="edit"
icon={<FormOutlined/>}
icon={<FormOutlined />}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => {
setModalVisible(true);
@@ -120,7 +120,7 @@ function ManagementList() {
size="small"
danger
key="batchRemove"
icon ={<DeleteOutlined/>}
icon={<DeleteOutlined />}
hidden={!access.hasPerms('area:subway:List')}
onClick={async () => {
Modal.confirm({
@@ -140,10 +140,10 @@ function ManagementList() {
}}
>
</Button>
]
}
]
</Button>,
],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
@@ -195,19 +195,20 @@ function ManagementList() {
<EditCompanyListRow
open={modalVisible}
onSubmit={async (values) => {
console.log(values);
let resData;
if (values.companyId) {
resData = await putCmsCompanyList(values)
resData = await putCmsCompanyList(values);
} else {
resData = await addCmsCompanyList(values)
resData = await addCmsCompanyList(values);
}
if (resData.code === 200) {
setModalVisible(false);
setCurrentRow(undefined);
if(values.companyId) {
message.success('修改成功')
if (values.companyId) {
message.success('修改成功');
} else {
message.success('新增成功')
message.success('新增成功');
}
if (actionRef.current) {
actionRef.current.reload();
@@ -219,8 +220,10 @@ function ManagementList() {
setCurrentRow(undefined);
}}
values={currentRow}
scaleEnum={scaleEnum}
></EditCompanyListRow>
</Fragment>
)
);
}
export default ManagementList
export default ManagementList;

View File

@@ -1,4 +1,4 @@
import {useEffect} from 'react'
import {useEffect, useCallback, useState} from 'react'
import {
ModalForm,
ProForm,
@@ -6,11 +6,14 @@ import {
ProFormText,
ProFormDigit,
ProFormRadio,
ProFormDateRangePicker
ProFormDateRangePicker,
ProFormList,
ProFormSelect,
} from '@ant-design/pro-components';
import { Button, Form, message } from 'antd';
import {DictOptionType, DictValueEnumObj} from "@/components/DictTag";
import { useIntl, FormattedMessage } from '@umijs/max';
import {getCmsCompanyList} from "@/services/company/list";
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
@@ -32,9 +35,12 @@ const listEdit: React.FC<ListFormProps> = (props) => {
const intl = useIntl();
const { jobFairType } = props;
const [companyOptions, setCompanyOptions] = useState([])
useEffect(() => {
form.resetFields();
if(props.values) {
console.log(props.values)
form.setFieldsValue({
...props.values,
createTimeRanger: [props.values.startTime, props.values.endTime],
@@ -43,6 +49,21 @@ const listEdit: React.FC<ListFormProps> = (props) => {
}, [form, props]);
const handleChange =(_: string, value: any) => {
const ls = form.getFieldsValue().companyList.map((item: any) => {
if(value.value === item.companyId) {
return {
...item,
companyName: value.title
}
}
return item;
})
form.setFieldValue('companyList', ls)
console.log(ls)
}
const handleCancel = () => {
props.onCancel();
form.resetFields();
@@ -114,6 +135,42 @@ const listEdit: React.FC<ListFormProps> = (props) => {
placeholder="请输入招聘会地点"
/>
</ProForm.Group>
<ProFormList
name="companyList"
creatorButtonProps={{
position: 'bottom',
creatorButtonText: '新建一行',
}}
copyIconProps={{
tooltipText: '复制此行到末尾',
}}
deleteIconProps={{
tooltipText: '移除本行',
}}
>
<ProForm.Group>
<ProFormSelect
key="companyId"
showSearch
width="md"
name="companyId"
onChange={handleChange}
request={async ({keyWords}) => {
let resData = await getCmsCompanyList({ name: keyWords })
return resData.rows.map((item) => ({ label: item.name, value: item.companyId}))
}}
placeholder="请输入公司名称选择公司"
rules={[{ required: true, message: '请输入公司名称选择公司!' }]}
label="招聘会公司列表"
/>
<ProFormText
width="md"
name="companyName"
label=" "
hidden={true}
/>
</ProForm.Group>
</ProFormList>
</ModalForm>
);
};

View File

@@ -10,7 +10,8 @@ import {
delCmsFairList,
exportCmsFairList,
getCmsFairList,
putCmsFairList
putCmsFairList,
getCmsFairId, getCmstitilelist
} from "@/services/jobfair/list";
import {getDictValueEnum} from "@/services/system/dict";
import DictTag from "@/components/DictTag";
@@ -74,7 +75,6 @@ function ManagementList() {
title: '招聘会名称',
dataIndex: 'name',
valueType: 'text',
hideInSearch: true,
align: 'center',
},
{
@@ -107,9 +107,10 @@ function ManagementList() {
key="edit"
icon={<FormOutlined/>}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => {
onClick={async () => {
let resData = await getCmsFairId(jobFairId as string)
setModalVisible(true);
setCurrentRow(record);
setCurrentRow(resData.data);
}}
>

View File

@@ -0,0 +1,74 @@
import { Modal } from 'antd';
import React, { useEffect, useRef } from 'react';
import * as echarts from 'echarts';
export type ListFormProps = {
onClose: (flag?: boolean, formVals?: unknown) => void;
open: boolean;
values?: Partial<API.MobileUser.ListRow>;
matching?: any;
};
const listEdit: React.FC<ListFormProps> = (props) => {
const { open, values, matching } = props;
const mapRef = useRef(null);
useEffect(() => {
console.log(matching);
if (matching && open) {
const myCharts = echarts.init(mapRef.current);
const { educationMatch, maxSimilarity, salaryMatch, areaMatch } = matching;
// educationMatch
// maxSimilarity
// salaryMatch
// areaMatch
myCharts.setOption({
radar: {
shape: 'circle',
indicator: [
{ name: '学历', max: 1 },
{ name: '薪资', max: 1 },
{ name: '区域', max: 1 },
{ name: '内容', max: 1 },
],
},
series: [
{
name: '综合匹配度',
type: 'radar',
data: [
{
value: [educationMatch, salaryMatch, areaMatch, maxSimilarity],
name: 'Allocated Budget',
},
],
},
],
});
}
}, [matching]);
return (
<Modal
title="匹配详情"
width={400}
open={props.open}
footer={''}
onCancel={() => props.onClose()}
maskClosable={true}
>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<div style={{ width: '300px', height: '300px' }} ref={mapRef}></div>
</div>
</Modal>
);
};
export default listEdit;

View File

@@ -0,0 +1,235 @@
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { FormattedMessage, useAccess, useParams } from '@umijs/max';
import { Button, FormInstance, message } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { FormOutlined, PlusOutlined } from '@ant-design/icons';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
import { exportCmsAppUserExport } from '@/services/mobileusers/list';
import { exportCmsJobCandidates, getCmsJobIds } from '@/services/Management/list';
import similarityJobs from '@/utils/similarity_Job';
import Detail from './detail';
const handleExport = async (values: API.MobileUser.ListParams) => {
const hide = message.loading('正在导出');
try {
await exportCmsAppUserExport(values);
hide();
message.success('导出成功');
return true;
} catch (error) {
hide();
message.error('导出失败,请重试');
return false;
}
};
function ManagementList() {
const access = useAccess();
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [jobId, setJobId] = useState<string>();
const [educationEnum, setEducationEnum] = useState<any>([]);
const [experienceEnum, setExperienceEnum] = useState<any>([]);
const [areaEnum, setAreaEnum] = useState<any>([]);
const [sexEnum, setSexEnum] = useState<any>([]);
const [hotEnum, setHotEnum] = useState<any>([]);
const [politicalEnum, setPoliticalEnum] = useState<any>([]);
const [currentRow, setCurrentRow] = useState<API.MobileUser.ListRow>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [jobInfo, setJobInfo] = useState({});
const [matchingDegree, setMatchingDegree] = useState<any>(null);
const params = useParams();
const id = params.id || '0';
useEffect(() => {
if (jobId !== id) {
setJobId(id);
getJobInfo(id);
}
}, [jobId, params]);
const getJobInfo = async (jobId: string) => {
let resData = await getCmsJobIds(jobId);
if (resData.code === 200) {
similarityJobs.setJobInfo(resData.data);
setJobInfo(resData.data);
}
};
useEffect(() => {
getDictValueEnum('education', true, true).then((data) => {
setEducationEnum(data);
});
getDictValueEnum('experience', true, true).then((data) => {
setExperienceEnum(data);
});
getDictValueEnum('area', true, true).then((data) => {
setAreaEnum(data);
});
getDictValueEnum('sys_user_sex', true).then((data) => {
setSexEnum(data);
});
getDictValueEnum('political_affiliation', true, true).then((data) => {
setPoliticalEnum(data);
});
}, []);
const columns: ProColumns<API.MobileUser.ListRow>[] = [
{
title: '用户名',
dataIndex: 'name',
valueType: 'text',
align: 'center',
},
{
title: '期望薪资',
dataIndex: 'minSalary',
valueType: 'text',
hideInSearch: true,
align: 'center',
render: (_, record) => (
<>
{record.salaryMin}-{record.salaryMax}
</>
),
},
{
title: '出生日期',
dataIndex: 'birthDate',
valueType: 'text',
align: 'center',
hideInSearch: true,
},
{
title: '学历要求',
dataIndex: 'education',
valueType: 'select',
align: 'center',
valueEnum: educationEnum,
render: (_, record) => {
return <DictTag enums={educationEnum} value={record.education} />;
},
},
{
title: '区域',
dataIndex: 'area',
valueType: 'select',
align: 'center',
valueEnum: areaEnum,
render: (_, record) => {
return <DictTag enums={areaEnum} value={record.area} />;
},
},
{
title: '性别',
dataIndex: 'sex',
valueType: 'select',
align: 'center',
valueEnum: sexEnum,
render: (_, record) => {
return <DictTag enums={sexEnum} value={record.sex} />;
},
},
{
title: '政治面貌',
dataIndex: 'politicalAffiliation',
valueType: 'select',
align: 'center',
valueEnum: politicalEnum,
render: (_, record) => {
return <DictTag enums={politicalEnum} value={record.politicalAffiliation} />;
},
},
{
title: '匹配度',
dataIndex: 'minSalary',
valueType: 'text',
hideInSearch: true,
align: 'center',
render: (_, record) => (
<>{similarityJobs.calculationMatchingDegreeJob(record).overallMatch}</>
),
},
{
title: '操作',
hideInSearch: true,
align: 'center',
dataIndex: 'jobId',
width: 200,
render: (jobId, record) => [
<Button
type="link"
size="small"
key="edit"
icon={<FormOutlined />}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => {
setModalVisible(true);
setCurrentRow(record);
const val = similarityJobs.calculationMatchingDegreeJob(record);
setMatchingDegree(val);
}}
>
</Button>,
],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.MobileUser.ListRow>
// params 是需要自带的参数
// 这个参数优先级更高,会覆盖查询表单的参数
actionRef={actionRef}
formRef={formTableRef}
rowKey="jobId"
key="index"
columns={columns}
request={(params) =>
exportCmsJobCandidates(jobId).then((res) => {
// const v = similarityJobs.calculationMatchingDegreeJob(res.rows[0]);
// console.log(v);
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
}
toolBarRender={() => [
<Button
type="primary"
key="export"
hidden={!access.hasPerms('system:user:export')}
onClick={async () => {
const searchVal = formTableRef.current && formTableRef.current.getFieldsValue();
handleExport(searchVal as API.MobileUser.ListParams);
}}
>
<PlusOutlined />
<FormattedMessage id="pages.searchTable.export" defaultMessage="导出" />
</Button>,
]}
/>
<Detail
values={currentRow}
open={modalVisible}
matching={matchingDegree}
onClose={() => {
console.log('close');
setModalVisible(false);
setCurrentRow(undefined);
setMatchingDegree(null);
}}
></Detail>
</div>
</Fragment>
);
}
export default ManagementList;

View File

@@ -1,21 +1,24 @@
import { PlusOutlined } from '@ant-design/icons';
import {
ModalForm,
ProForm,
ProFormDateRangePicker,
ProFormDigit,
ProFormSelect,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { Button, Form, message } from 'antd';
import {DictOptionType, DictValueEnumObj} from "@/components/DictTag";
import { Form } from 'antd';
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import { getCmsCompanyList } from '@/services/company/list';
export type ListFormProps = {
onCancel: (flag?: boolean, formVals?: unknown) => void;
onSubmit: (values: API.ManagementList.Manage) => Promise<void>;
open: boolean;
// values: Partial<API.Management.Manage>;
// jobGroupOptions: DictOptionType[];
// statusOptions: DictValueEnumObj;
values?: Partial<API.ManagementList.Manage>;
educationEnum: DictValueEnumObj;
experienceEnum: DictValueEnumObj;
areaEnum: DictValueEnumObj;
};
const waitTime = (time: number = 100) => {
@@ -27,7 +30,17 @@ const waitTime = (time: number = 100) => {
};
const listEdit: React.FC<ListFormProps> = (props) => {
const [form] = Form.useForm<{ name: string; company: string }>();
const [form] = Form.useForm<{ name: string; company: string; companyName: number }>();
const { educationEnum, experienceEnum, areaEnum } = props;
useEffect(() => {
form.resetFields();
if (props.values) {
form.setFieldsValue({
...props.values,
jobLocationAreaCode: String(props.values.jobLocationAreaCode || ''),
});
}
}, [form, props]);
const handleCancel = () => {
props.onCancel();
@@ -38,6 +51,10 @@ const listEdit: React.FC<ListFormProps> = (props) => {
props.onSubmit(values as API.ManagementList.Manage);
};
const handleChange = (_: string, value: any) => {
form.setFieldValue('companyName', value.label);
};
return (
<ModalForm<{
name: string;
@@ -55,71 +72,87 @@ const listEdit: React.FC<ListFormProps> = (props) => {
onFinish={handleFinish}
>
<ProForm.Group>
<ProFormText
<ProFormText width="md" hidden name="jobId" />
<ProFormText width="md" hidden name="companyName" />
<ProFormText width="md" name="jobTitle" label="岗位名称" placeholder="请输入岗位名称" />
<ProFormSelect
showSearch
width="md"
name="jobTitle"
label="岗位名称"
placeholder="请输入名称"
name="companyId"
onChange={handleChange}
request={async ({ keyWords }) => {
let resData = await getCmsCompanyList({ name: keyWords });
return resData.rows.map((item) => ({ label: item.name, value: item.companyId }));
}}
placeholder="请输入公司名称选择公司"
rules={[{ required: true, message: '请输入公司名称选择公司!' }]}
label="招聘会公司"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText
width="md"
<ProFormDigit
name="minSalary"
label="最小薪资"
width="md"
min={0}
label="最小薪资(元/月)"
placeholder="请输入最小薪资(元)"
/>
<ProFormText
width="md"
<ProFormDigit
name="maxSalary"
label="最大薪资"
width="md"
min={0}
label="最大薪资(元/月)"
placeholder="请输入最大薪资(元)"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText
<ProFormSelect
width="md"
name="education"
label="学历要求"
placeholder="请输入学历要求"
label={'学历要求'}
valueEnum={educationEnum}
placeholder="请选择学历要求"
rules={[{ required: true, message: '请选择学历要求!' }]}
/>
<ProFormText
<ProFormSelect
width="md"
name="experience"
label="工作经验"
placeholder="请输入工作经验"
label={'工作经验'}
valueEnum={experienceEnum}
placeholder="请选择岗位"
rules={[{ required: true, message: '请选择工作经验!' }]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText
<ProFormSelect
width="md"
name="companyName"
label="单位名称"
placeholder="请输入单位名称"
name="jobLocationAreaCode"
label={'工作区县'}
valueEnum={areaEnum}
placeholder="请选择区县"
rules={[{ required: true, message: '请选择区县!' }]}
/>
<ProFormText
width="md"
name="jobLocation"
label="工作地点"
placeholder="请输入工作地点"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText
width="md"
name="vacancies"
<ProFormDigit
label="招聘人数"
name="vacancies"
width="md"
min={0}
placeholder="请输入招聘人数"
/>
<ProFormText
width="md"
name="jobLocation"
label="工作地点"
placeholder="请输入工作地点"
</ProForm.Group>
<ProForm.Group>
<ProFormText width="lg" name="jobLocation" label="工作地点" placeholder="请输入工作地点" />
</ProForm.Group>
<ProForm.Group>
<ProFormTextArea
width="lg"
name="description"
label="岗位描述"
placeholder="请输入岗位描述"
/>
</ProForm.Group>
</ModalForm>
);
};
export default listEdit
export default listEdit;

View File

@@ -1,13 +1,33 @@
import React, {Fragment, useRef, useState, useEffect} from "react";
import { useIntl, FormattedMessage, useAccess, history } from '@umijs/max';
import {delCmsJobIds, getCmsJobList} from "@/services/Management/list";
import { Dropdown, FormInstance, Space, Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, FormOutlined, DownOutlined, EditOutlined } from '@ant-design/icons';
import EditManageRow from './edit'
import {getDictValueEnum} from "@/services/system/dict";
import DictTag from "@/components/DictTag";
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { FormattedMessage, history, useAccess } from '@umijs/max';
import {
addCmsJobList,
delCmsJobIds,
exportCmsJob,
getCmsJobList,
updateCmsJobList,
} from '@/services/Management/list';
import { Button, FormInstance, message, Modal, Switch } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { BarChartOutlined, DeleteOutlined, FormOutlined, PlusOutlined } from '@ant-design/icons';
import EditManageRow from './edit';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
const handleExport = async (values: API.ManagementList.ListParams) => {
const hide = message.loading('正在导出');
try {
await exportCmsJob(values);
hide();
message.success('导出成功');
return true;
} catch (error) {
hide();
message.error('导出失败,请重试');
return false;
}
};
const handleRemoveOne = async (jobId: string) => {
const hide = message.loading('正在删除');
if (!jobId) return true;
@@ -33,23 +53,44 @@ function ManagementList() {
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [educationEnum, setEducationEnum] = useState<any>([])
const [experienceEnum, setExperienceEnum] = useState<any>([])
const [hotEnum, setHotEnum] = useState<any>([])
const [currentRow, setCurrentRow] = useState<API.ManagementList.Manage>()
const [modalVisible, setModalVisible] = useState<boolean>(false)
const [educationEnum, setEducationEnum] = useState<any>([]);
const [experienceEnum, setExperienceEnum] = useState<any>([]);
const [areaEnum, setAreaEnum] = useState<any>([]);
const [isPublishEnum, setIsPublishEnum] = useState<any>([]);
const [hotEnum, setHotEnum] = useState<any>([]);
const [currentRow, setCurrentRow] = useState<API.ManagementList.Manage>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
useEffect(() => {
getDictValueEnum('education',true).then((data) => {
setEducationEnum(data)
})
getDictValueEnum('experience',true).then((data) => {
setExperienceEnum(data)
})
getDictValueEnum('education', true, true).then((data) => {
setEducationEnum(data);
});
getDictValueEnum('experience', true, true).then((data) => {
setExperienceEnum(data);
});
getDictValueEnum('area', true, true).then((data) => {
setAreaEnum(data);
});
getDictValueEnum('is_publish', true).then((data) => {
setIsPublishEnum(data);
});
// getDictValueEnum('job_hot',true).then((data) => {
// setHotEnum(data)
// })
}, [])
}, []);
async function changeRelease(record: API.ManagementList.Manage) {
let resData = await updateCmsJobList({
jobId: record.jobId,
isPublish: record.isPublish === 1 ? 0 : 1,
});
if (resData.code === 200) {
message.success('修改成功');
if (actionRef.current) {
actionRef.current.reload();
}
}
}
const columns: ProColumns<API.ManagementList.Manage>[] = [
{
@@ -57,13 +98,18 @@ function ManagementList() {
dataIndex: 'jobTitle',
valueType: 'text',
align: 'center',
},{
},
{
title: '最大最小薪资',
dataIndex: 'maxSalary',
valueType: 'text',
hideInSearch: true,
align: 'center',
render: (_, record) => <>{record.minSalary}-{record.maxSalary}</>
render: (_, record) => (
<>
{record.minSalary}-{record.maxSalary}
</>
),
},
{
title: '单位名称',
@@ -78,18 +124,17 @@ function ManagementList() {
align: 'center',
valueEnum: educationEnum,
render: (_, record) => {
return (<DictTag enums={educationEnum} value={record.education} />);
return <DictTag enums={educationEnum} value={record.education} />;
},
},
{
title: '经验要求',
dataIndex: 'experience',
hideInSearch: true,
valueType: 'select',
align: 'center',
valueEnum: experienceEnum,
render: (_, record) => {
return (<DictTag enums={experienceEnum} value={record.experience} />);
return <DictTag enums={experienceEnum} value={record.experience} />;
},
},
// {
@@ -103,11 +148,14 @@ function ManagementList() {
// },
// },
{
title: '发布时间',
dataIndex: 'postingDate',
valueType: 'text',
hideInSearch: true,
title: '是否发布',
dataIndex: 'isPublish',
valueType: 'select',
align: 'center',
valueEnum: isPublishEnum,
render: (text, record) => (
<Switch checked={record.isPublish === 1} onChange={changeRelease.bind(null, record)} />
),
},
{
title: '招聘人数',
@@ -134,7 +182,17 @@ function ManagementList() {
type="link"
size="small"
key="edit"
icon={<FormOutlined/>}
icon={<BarChartOutlined />}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => history.push(`/management/see-matching/index/${record.jobId}`)}
>
</Button>,
<Button
type="link"
size="small"
key="edit"
icon={<FormOutlined />}
hidden={!access.hasPerms('area:business:List.update')}
onClick={() => {
setModalVisible(true);
@@ -148,7 +206,7 @@ function ManagementList() {
size="small"
danger
key="batchRemove"
icon ={<DeleteOutlined/>}
icon={<DeleteOutlined />}
hidden={!access.hasPerms('area:subway:List')}
onClick={async () => {
Modal.confirm({
@@ -168,10 +226,10 @@ function ManagementList() {
}}
>
</Button>
]
}
]
</Button>,
],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
@@ -185,7 +243,7 @@ function ManagementList() {
columns={columns}
request={(params) =>
getCmsJobList({ ...params } as API.ManagementList.ListParams).then((res) => {
console.log(params)
console.log(params);
const result = {
data: res.rows,
total: res.total,
@@ -206,21 +264,54 @@ function ManagementList() {
>
<PlusOutlined />
</Button>,
<Button
type="primary"
key="export"
hidden={!access.hasPerms('system:user:export')}
onClick={async () => {
const searchVal = formTableRef.current && formTableRef.current.getFieldsValue();
handleExport(searchVal as API.ManagementList.ListParams);
}}
>
<PlusOutlined />
<FormattedMessage id="pages.searchTable.export" defaultMessage="导出" />
</Button>,
]}
/>
</div>
<EditManageRow
open={modalVisible}
onSubmit={(values) => {
console.log(values)
return Promise.resolve()
onSubmit={async (values) => {
let resData;
if (values.jobId) {
resData = await updateCmsJobList(values);
} else {
resData = await addCmsJobList(values);
}
if (resData.code === 200) {
setModalVisible(false);
setCurrentRow(undefined);
if (values.jobId) {
message.success('修改成功');
} else {
message.success('新增成功');
}
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
values={currentRow}
onCancel={() => {
setModalVisible(false);
setCurrentRow(undefined);
}}
educationEnum={educationEnum}
experienceEnum={experienceEnum}
areaEnum={areaEnum}
></EditManageRow>
</Fragment>
)
);
}
export default ManagementList
export default ManagementList;

View File

@@ -0,0 +1,177 @@
import React, { Fragment, useEffect, useRef, useState } from 'react';
import { FormattedMessage, useAccess } from '@umijs/max';
import { Button, FormInstance, message } from 'antd';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined } from '@ant-design/icons';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
import { exportCmsAppUserExport, getCmsAppUserList } from '@/services/mobileusers/list';
const handleExport = async (values: API.MobileUser.ListParams) => {
const hide = message.loading('正在导出');
try {
await exportCmsAppUserExport(values);
hide();
message.success('导出成功');
return true;
} catch (error) {
hide();
message.error('导出失败,请重试');
return false;
}
};
function ManagementList() {
const access = useAccess();
const formTableRef = useRef<FormInstance>();
const actionRef = useRef<ActionType>();
const [educationEnum, setEducationEnum] = useState<any>([]);
const [experienceEnum, setExperienceEnum] = useState<any>([]);
const [areaEnum, setAreaEnum] = useState<any>([]);
const [sexEnum, setSexEnum] = useState<any>([]);
const [hotEnum, setHotEnum] = useState<any>([]);
const [politicalEnum, setPoliticalEnum] = useState<any>([]);
const [currentRow, setCurrentRow] = useState<API.MobileUser.ListRow>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
useEffect(() => {
getDictValueEnum('education', true, true).then((data) => {
setEducationEnum(data);
});
getDictValueEnum('experience', true, true).then((data) => {
setExperienceEnum(data);
});
getDictValueEnum('area', true, true).then((data) => {
setAreaEnum(data);
});
getDictValueEnum('sys_user_sex', true).then((data) => {
setSexEnum(data);
});
getDictValueEnum('political_affiliation', true, true).then((data) => {
setPoliticalEnum(data);
});
// getDictValueEnum('job_hot',true).then((data) => {
// setHotEnum(data)
// })
}, []);
const columns: ProColumns<API.MobileUser.ListRow>[] = [
{
title: '用户名',
dataIndex: 'name',
valueType: 'text',
align: 'center',
},
{
title: '期望薪资',
dataIndex: 'minSalary',
valueType: 'text',
hideInSearch: true,
align: 'center',
render: (_, record) => (
<>
{record.salaryMin}-{record.salaryMax}
</>
),
},
{
title: '出生日期',
dataIndex: 'birthDate',
valueType: 'text',
align: 'center',
},
{
title: '学历要求',
dataIndex: 'education',
valueType: 'select',
align: 'center',
valueEnum: educationEnum,
render: (_, record) => {
return <DictTag enums={educationEnum} value={record.education} />;
},
},
{
title: '区域',
dataIndex: 'area',
valueType: 'select',
align: 'center',
valueEnum: areaEnum,
render: (_, record) => {
return <DictTag enums={areaEnum} value={record.area} />;
},
},
{
title: '性别',
dataIndex: 'sex',
valueType: 'select',
align: 'center',
valueEnum: sexEnum,
render: (_, record) => {
return <DictTag enums={sexEnum} value={record.sex} />;
},
},
{
title: '政治面貌',
dataIndex: 'politicalAffiliation',
valueType: 'select',
align: 'center',
valueEnum: politicalEnum,
render: (_, record) => {
return <DictTag enums={politicalEnum} value={record.politicalAffiliation} />;
},
},
{
title: '操作',
hideInSearch: true,
align: 'center',
dataIndex: 'jobId',
width: 200,
render: (jobId, record) => [],
},
];
return (
<Fragment>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.MobileUser.ListRow>
// params 是需要自带的参数
// 这个参数优先级更高,会覆盖查询表单的参数
actionRef={actionRef}
formRef={formTableRef}
rowKey="jobId"
key="index"
columns={columns}
request={(params) =>
getCmsAppUserList({ ...params } as API.MobileUser.ListParams).then((res) => {
console.log(params);
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
}
toolBarRender={() => [
<Button
type="primary"
key="export"
hidden={!access.hasPerms('system:user:export')}
onClick={async () => {
const searchVal = formTableRef.current && formTableRef.current.getFieldsValue();
handleExport(searchVal as API.MobileUser.ListParams);
}}
>
<PlusOutlined />
<FormattedMessage id="pages.searchTable.export" defaultMessage="导出" />
</Button>,
]}
/>
</div>
</Fragment>
);
}
export default ManagementList;

View File

@@ -1,13 +1,24 @@
import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess, history, useParams } from '@umijs/max';
import React, { useEffect, useRef, useState } from 'react';
import { FormattedMessage, history, useAccess, useIntl, useParams } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getDictDataList, removeDictData, addDictData, updateDictData, exportDictData } from '@/services/system/dictdata';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
addDictData,
exportDictData,
getDictDataList,
removeDictData,
updateDictData,
} from '@/services/system/dictdata';
import UpdateForm from './edit';
import { getDictValueEnum, getDictType, getDictTypeOptionSelect } from '@/services/system/dict';
import { getDictType, getDictTypeOptionSelect, getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
/**
@@ -123,9 +134,7 @@ export type DictTypeArgs = {
id: string;
};
const DictDataTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();
const [dictId, setDictId] = useState<string>('');
@@ -221,7 +230,7 @@ const DictDataTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -235,7 +244,7 @@ const DictDataTableList: React.FC = () => {
dataIndex: 'createTime',
valueType: 'dateRange',
render: (_, record) => {
return (<span>{record.createTime.toString()} </span>);
return <span>{record.createTime.toString()} </span>;
},
search: {
transform: (value) => {
@@ -314,7 +323,11 @@ const DictDataTableList: React.FC = () => {
key="add"
hidden={!access.hasPerms('system:data:add')}
onClick={async () => {
setCurrentRow({ dictType: dictType, isDefault: 'N', status: '0' } as API.System.DictData);
setCurrentRow({
dictType: dictType,
isDefault: 'N',
status: '0',
} as API.System.DictData);
setModalVisible(true);
}}
>
@@ -337,7 +350,7 @@ const DictDataTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>
@@ -357,14 +370,16 @@ const DictDataTableList: React.FC = () => {
</Button>,
]}
request={(params) =>
getDictDataList({ ...params, dictType } as API.System.DictDataListParams).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
getDictDataList({ ...params, dictType } as API.System.DictDataListParams).then(
(res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
},
)
}
columns={columns}
rowSelection={{

View File

@@ -1,10 +1,15 @@
import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import React, { useEffect, useRef, useState } from 'react';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getMenuList, removeMenu, addMenu, updateMenu } from '@/services/system/menu';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { addMenu, getMenuList, removeMenu, updateMenu } from '@/services/system/menu';
import UpdateForm from './edit';
import { getDictValueEnum } from '@/services/system/dict';
import { buildTreeData } from '@/utils/tree';
@@ -85,9 +90,7 @@ const handleRemoveOne = async (selectedRow: API.System.Menu) => {
}
};
const MenuTableList: React.FC = () => {
const [modalVisible, setModalVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
@@ -148,7 +151,7 @@ const MenuTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -259,7 +262,7 @@ const MenuTableList: React.FC = () => {
setMenuTree(treeData);
return {
data: memuData,
total: res.data.length,
total: memuData.length,
success: true,
};
})

View File

@@ -16,14 +16,14 @@ import {
ProFormText,
} from '@ant-design/pro-components';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import { FormattedMessage, history, SelectLang, useIntl, useModel, Helmet } from '@umijs/max';
import { Alert, Col, message, Row, Tabs, Image } from 'antd';
import { FormattedMessage, Helmet, history, SelectLang, useIntl, useModel } from '@umijs/max';
import { Alert, Col, Image, message, Row, Tabs } from 'antd';
import Settings from '../../../../config/defaultSettings';
import React, { useEffect, useState } from 'react';
import { flushSync } from 'react-dom';
// flushSync 允许你强制 React 同步刷新提供的回调中的任何更新。这确保了 DOM 立即更新
import { clearSessionToken, setSessionToken } from '@/access';
import {getRoutersInfo, setRemoteMenu} from "@/services/session";
import logoImg from '@/assets/logo.svg'
import logoImg from '@/assets/logo.svg';
const ActionIcons = () => {
const langClassName = useEmotionCss(({ token }) => {
@@ -87,7 +87,7 @@ const LoginMessage: React.FC<{
};
const Login: React.FC = () => {
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({code: 200});
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({ code: 200 });
const [type, setType] = useState<string>('account');
const { initialState, setInitialState } = useModel('@@initialState');
const [captchaCode, setCaptchaCode] = useState<string>('');
@@ -143,7 +143,7 @@ const Login: React.FC = () => {
console.log('login ok');
const urlParams = new URL(window.location.href).searchParams;
history.push(urlParams.get('redirect') || '/');
setTimeout(() => history.go(0), 0)
setTimeout(() => history.go(0), 0);
return;
} else {
message.error(response.msg);

View File

@@ -1,13 +1,29 @@
import { request } from '@umijs/max';
import { downLoadXlsx } from '@/utils/downloadfile';
export async function getCmsJobList(params?: API.ManagementList.ListParams) {
return request<API.ManagementList.ManagePageResult>(`/api/cms/job/list`, {
method: 'GET',
params: params,
});
}
export async function addCmsJobList(params?: API.ManagementList.AddParams) {
return request<API.ManagementList.ManagePageResult>(`/api/cms/job`, {
method: 'POST',
data: params,
});
}
export async function updateCmsJobList(params?: API.ManagementList.AddParams) {
return request<API.ManagementList.ManagePageResult>(`/api/cms/job`, {
method: 'PUT',
data: params,
});
}
export async function getCmsJobIds(ids: string) {
return request<API.ManagementList.ManagePageResult>(`/api/cms/job/${ids}`, {
return request<API.ManagementList.ManageIdResult>(`/api/cms/job/${ids}`, {
method: 'GET',
});
}
@@ -18,3 +34,15 @@ export async function delCmsJobIds(ids: string) {
});
}
export async function exportCmsJob(params?: API.ManagementList.ListParams) {
return downLoadXlsx(`/api/cms/job/export`, { params }, `job_data_${new Date().getTime()}.xlsx`);
}
export async function exportCmsJobCandidates(ids: string) {
return request<API.ManagementList.ManageIdResult>(`/api/cms/job/candidates`, {
method: 'GET',
params: {
jobId: ids,
},
});
}

View File

@@ -0,0 +1,28 @@
import { request } from '@umijs/max';
export async function getCmsCardList(params?: API.ApplicationProducts.Params) {
return request<API.ApplicationProducts.result>(`/api/cms/card/list`, {
method: 'GET',
params: params,
});
}
export async function addCmsCardList(params?: API.ApplicationProducts.Params) {
return request<API.ApplicationProducts.result>(`/api/cms/card`, {
method: 'POST',
data: params,
});
}
export async function putCmsCardList(params?: API.ApplicationProducts.Params) {
return request<API.ApplicationProducts.result>(`/api/cms/card`, {
method: 'PUT',
data: params,
});
}
export async function delCmsCardList(ids?: string) {
return request<API.ApplicationProducts.result>(`/api/cms/card/${ids}`, {
method: 'DELETE',
});
}

View File

@@ -1,24 +1,24 @@
import { request } from '@umijs/max';
import { downLoadXlsx } from '@/utils/downloadfile';
export async function getCmsAreaList(params?: API.AreaBusiness.CircleParams) {
return request<API.AreaBusiness.CirclePageResult>(`/api/cms/area/list`, {
method: 'GET',
params: params,
});
}
export async function addCmsAreaListRow(params?: API.AreaBusiness.CircleEditParams) {
return request<API.AreaBusiness.CirclePageResult>(`/api/cms/area`, {
method: 'post',
data: params
data: params,
});
}
export async function updateCmsAreaListRow(params?: API.AreaBusiness.CircleEditParams) {
return request<API.AreaBusiness.CirclePageResult>(`/api/cms/area`, {
method: 'put',
data: params
data: params,
});
}
@@ -27,9 +27,7 @@ export async function deleteCmsAreaListRow(ids: number) {
method: 'delete',
});
}
export async function exportCmsAreaListRow(params?: API.AreaBusiness.CircleEditParams) {
return request<API.AreaPlatForm.LinePageResult>(`/api/cms/area/export`, {
method: 'POST',
data: params
});
return downLoadXlsx(`/api/cms/area/export`, { params }, `dict_data_${new Date().getTime()}.xlsx`);
}

View File

@@ -0,0 +1,43 @@
import { request } from '@umijs/max';
import { downLoadXlsx } from '@/utils/downloadfile';
export async function getCmsIndustryList(params?: API.ClassifyIndustry.Params) {
return request<API.ClassifyIndustry.IndustryResult>(`/api/cms/industry/list`, {
method: 'GET',
params: params,
});
}
export async function delCmsIndustryList(industryId?: string) {
return request<API.ClassifyIndustry.IndustryResult>(`/api/cms/industry/${industryId}`, {
method: 'DELETE',
});
}
export async function getCmsIndustryTree() {
return request<API.ClassifyIndustry.IndustryTreeResult>(`/api/cms/industry/treeselect`, {
method: 'GET',
});
}
export async function addCmsIndustryIndustryt(params?: API.ClassifyIndustry.Params) {
return request<API.ClassifyIndustry.IndustryTreeResult>(`/api/cms/industry`, {
method: 'POST',
data: params,
});
}
export async function updateCmsIndustryIndustryt(params?: API.ClassifyIndustry.Params) {
return request<API.ClassifyIndustry.IndustryTreeResult>(`/api/cms/industry`, {
method: 'PUT',
data: params,
});
}
export async function exportCmsIndustry(params?: API.ClassifyIndustry.Params) {
return downLoadXlsx(
`/api/cms/industry/export`,
{ params },
`dict_data_${new Date().getTime()}.xlsx`,
);
}

View File

@@ -0,0 +1,17 @@
import { request } from '@umijs/max';
import { downLoadXlsx } from '@/utils/downloadfile';
export async function getCmsJobTitleList(params?: API.ClassifyJobs.Params) {
return request<API.ClassifyJobs.Result>(`/api/cms/job/titile/list`, {
method: 'GET',
params: params,
});
}
export async function exportCmsJobTitleList(params?: API.ClassifyJobs.Params) {
return downLoadXlsx(
`/api/cms/job/titile/export`,
{ params },
`dict_data_${new Date().getTime()}.xlsx`,
);
}

View File

@@ -1,8 +1,10 @@
import { request } from '@umijs/max';
import { downLoadXlsx } from '@/utils/downloadfile';
export async function getCmsCompanyList(params?: API.CompanyList.Params) {
return request<API.CompanyList.CompanyListResult>(`/api/cms/company/list`, {
method: 'GET',
params: params,
});
}
@@ -15,21 +17,17 @@ export async function delCmsCompanyList(companyIds?: string) {
export async function addCmsCompanyList(params?: API.CompanyList.Params) {
return request<API.CompanyList.CompanyListResult>(`/api/cms/company`, {
method: 'POST',
data: params
data: params,
});
}
export async function putCmsCompanyList(params?: API.CompanyList.Params) {
return request<API.CompanyList.CompanyListResult>(`/api/cms/company`, {
method: 'PUT',
data: params
data: params,
});
}
export async function exportCmsCompanyList(params?: API.CompanyList.Params) {
return request<API.CompanyList.CompanyListResult>(`/cms/company/export`, {
method: 'POST',
data: params
});
return downLoadXlsx(`/cms/company/export`, { params }, `dict_data_${new Date().getTime()}.xlsx`);
}

View File

@@ -1,33 +1,45 @@
import { request } from '@umijs/max';
import { downLoadXlsx } from '@/utils/downloadfile';
export async function getCmsFairList(params?: API.JobFairList.Params) {
return request<API.JobFairList.JobFairListResult>(`/api/app/fair/list`, {
return request<API.JobFairList.JobFairListResult>(`/api/cms/fair/list`, {
method: 'GET',
params: params,
});
}
export async function addCmsFairList(params?: API.JobFairList.JobFairListRows) {
return request<API.JobFairList.JobFairListResult>(`/api/app/fair`, {
return request<API.JobFairList.JobFairListResult>(`/api/cms/fair`, {
method: 'POST',
data: params
data: params,
});
}
export async function putCmsFairList(params?: API.JobFairList.Params) {
return request<API.JobFairList.JobFairListResult>(`/api/app/fair`, {
return request<API.JobFairList.JobFairListResult>(`/api/cms/fair`, {
method: 'PUT',
data: params
data: params,
});
}
export async function delCmsFairList(ids?: string) {
return request<API.JobFairList.JobFairListResult>(`/api/app/fair${ids}`, {
return request<API.JobFairList.JobFairListResult>(`/api/cms/fair/${ids}`, {
method: 'DELETE',
});
}
export async function exportCmsFairList(ids?: API.JobFairList.Params) {
return request<API.JobFairList.JobFairListResult>(`/api/app/fair/export`, {
method: 'POST',
export async function exportCmsFairList(params?: API.JobFairList.Params) {
return downLoadXlsx(`/api/cms/fair/export`, { params }, `dict_data_${new Date().getTime()}.xlsx`);
}
export async function getCmsFairId(jobFairId?: string) {
return request<API.JobFairList.ListInfoResult>(`/api/cms/fair/${jobFairId}`, {
method: 'GET',
});
}
export async function getCmstitilelist(jobFairId?: string) {
return request<API.JobFairList.ListInfoResult>(`/api/cms/industry/list`, {
method: 'GET',
});
}

View File

@@ -0,0 +1,23 @@
import { request } from '@umijs/max';
import { downLoadXlsx } from '@/utils/downloadfile';
export async function getCmsAppUserList(params?: API.MobileUser.ListParams) {
return request<API.MobileUser.ListResult>(`/api/cms/appUser/list`, {
method: 'GET',
params: params,
});
}
export async function getCmsAppUser(userId?: string) {
return request<API.MobileUser.ListResult>(`/api/cms/appUser/${userId}`, {
method: 'GET',
});
}
export async function exportCmsAppUserExport(params?: API.MobileUser.ListParams) {
return downLoadXlsx(
`/api/cms/appUser/export`,
{ params },
`job_data_${new Date().getTime()}.xlsx`,
);
}

View File

@@ -12,7 +12,7 @@ import { downLoadXlsx } from '@/utils/downloadfile';
// 查询字典类型列表
export async function getDictTypeList(params?: API.DictTypeListParams) {
return request(`/api/system/dict/type/list`, {
return request(`/api/cms/dict/type/list`, {
params: {
...params,
},
@@ -25,17 +25,29 @@ export async function getDictTypeList(params?: API.DictTypeListParams) {
// 查询字典类型详细
export function getDictType(dictId: string) {
return request(`/api/system/dict/type/${dictId}`, {
return request(`/api/cms/dict/type/${dictId}`, {
method: 'GET',
});
}
// 查询字典数据详细
export async function getDictValueEnum(dictType: string, isDigital?: boolean): Promise<DictValueEnumObj> {
const resp = await request<API.System.DictTypeResult>(`/api/system/dict/data/type/${dictType}`, {
method: 'GET',
});
if(resp.code === HttpResult.SUCCESS) {
export async function getDictValueEnum(
dictType: string,
isDigital?: boolean,
isCms?: boolean,
): Promise<DictValueEnumObj> {
let resp = null;
if (isCms) {
resp = await request<API.System.DictTypeResult>(`/api/cms/dict/data/type/${dictType}`, {
method: 'GET',
});
} else {
resp = await request<API.System.DictTypeResult>(`/api/system/dict/data/type/${dictType}`, {
method: 'GET',
});
}
if (resp.code === HttpResult.SUCCESS) {
const opts: DictValueEnumObj = {};
resp.data.forEach((item: any) => {
opts[item.dictValue] = {
@@ -44,7 +56,8 @@ export async function getDictValueEnum(dictType: string, isDigital?: boolean): P
value: isDigital ? Number(item.dictValue) : item.dictValue,
key: item.dictCode,
listClass: item.listClass,
status: item.listClass };
status: item.listClass,
};
});
return opts;
} else {
@@ -52,10 +65,17 @@ export async function getDictValueEnum(dictType: string, isDigital?: boolean): P
}
}
export async function getDictSelectOption(dictType: string, isDigital?: boolean) {
const resp = await request<API.System.DictTypeResult>(`/api/system/dict/data/type/${dictType}`, {
method: 'GET',
});
export async function getDictSelectOption(dictType: string, isDigital?: boolean, isCms?: boolean) {
let resp = null;
if (isCms) {
resp = await request<API.System.DictTypeResult>(`/api/cms/dict/data/type/${dictType}`, {
method: 'GET',
});
} else {
resp = await request<API.System.DictTypeResult>(`/api/system/dict/data/type/${dictType}`, {
method: 'GET',
});
}
if (resp.code === 200) {
const options: DictValueEnumObj[] = resp.data.map((item) => {
return {
@@ -64,51 +84,55 @@ export async function getDictSelectOption(dictType: string, isDigital?: boolean)
value: isDigital ? Number(item.dictValue) : item.dictValue,
key: item.dictCode,
listClass: item.listClass,
status: item.listClass
status: item.listClass,
};
});
return options;
}
return [];
};
}
// 新增字典类型
export async function addDictType(params: API.System.DictType) {
return request<API.Result>('/api/system/dict/type', {
return request<API.Result>('/api/cms/dict/type', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
data: params
data: params,
});
}
// 修改字典类型
export async function updateDictType(params: API.System.DictType) {
return request<API.Result>('/api/system/dict/type', {
return request<API.Result>('/api/cms/dict/type', {
method: 'PUT',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
data: params
data: params,
});
}
// 删除字典类型
export async function removeDictType(ids: string) {
return request<API.Result>(`/api/system/dict/type/${ids}`, {
method: 'DELETE'
return request<API.Result>(`/api/cms/dict/type/${ids}`, {
method: 'DELETE',
});
}
// 导出字典类型
export function exportDictType(params?: API.System.DictTypeListParams) {
return downLoadXlsx(`/api/system/dict/type/export`, { params }, `dict_type_${new Date().getTime()}.xlsx`);
return downLoadXlsx(
`/api/cms/dict/type/export`,
{ params },
`dict_type_${new Date().getTime()}.xlsx`,
);
}
// 获取字典选择框列表
export async function getDictTypeOptionSelect(params?: API.DictTypeListParams) {
return request('/api/system/dict/type/optionselect', {
return request('/api/cms/dict/type/optionselect', {
params: {
...params,
},

View File

@@ -6,7 +6,7 @@ export async function getDictDataList(
params?: API.System.DictDataListParams,
options?: { [key: string]: any },
) {
return request<API.System.DictDataPageResult>('/api/system/dict/data/list', {
return request<API.System.DictDataPageResult>('/api/cms/dict/data/list', {
method: 'GET',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
@@ -18,7 +18,7 @@ export async function getDictDataList(
// 查询字典数据详细
export function getDictData(dictCode: number, options?: { [key: string]: any }) {
return request<API.System.DictDataInfoResult>(`/api/system/dict/data/${dictCode}`, {
return request<API.System.DictDataInfoResult>(`/api/cms/dict/data/${dictCode}`, {
method: 'GET',
...(options || {}),
});
@@ -26,7 +26,7 @@ export function getDictData(dictCode: number, options?: { [key: string]: any })
// 新增字典数据
export async function addDictData(params: API.System.DictData, options?: { [key: string]: any }) {
return request<API.Result>('/api/system/dict/data', {
return request<API.Result>('/api/cms/dict/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
@@ -37,8 +37,11 @@ export async function addDictData(params: API.System.DictData, options?: { [key:
}
// 修改字典数据
export async function updateDictData(params: API.System.DictData, options?: { [key: string]: any }) {
return request<API.Result>('/api/system/dict/data', {
export async function updateDictData(
params: API.System.DictData,
options?: { [key: string]: any },
) {
return request<API.Result>('/api/cms/dict/data', {
method: 'PUT',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
@@ -50,7 +53,7 @@ export async function updateDictData(params: API.System.DictData, options?: { [k
// 删除字典数据
export async function removeDictData(ids: string, options?: { [key: string]: any }) {
return request<API.Result>(`/api/system/dict/data/${ids}`, {
return request<API.Result>(`/api/cms/dict/data/${ids}`, {
method: 'DELETE',
...(options || {}),
});
@@ -61,5 +64,9 @@ export function exportDictData(
params?: API.System.DictDataListParams,
options?: { [key: string]: any },
) {
return downLoadXlsx(`/api/system/dict/data/export`, { params }, `dict_data_${new Date().getTime()}.xlsx`);
return downLoadXlsx(
`/api/cms/dict/data/export`,
{ params },
`dict_data_${new Date().getTime()}.xlsx`,
);
}

View File

@@ -19,6 +19,32 @@ declare namespace API.ManagementList {
postingDate: string;
vacancies: number;
view: number;
release: number;
isPublish: number;
}
export interface AddParams {
applyNum?: number;
companyId?: number;
companyName?: string;
education?: string;
experience?: string;
isApply?: number;
isCollection?: number;
isHot?: number;
jobId?: number;
jobLocation?: string;
jobLocationAreaCode?: number;
jobTitle?: string;
latitude?: number;
longitude?: number;
maxSalary?: number;
minSalary?: number;
postingDate?: string;
vacancies?: number;
view?: number;
release?: number;
isPublish?: number;
}
export interface ListParams {
@@ -29,6 +55,14 @@ declare namespace API.ManagementList {
current?: number;
}
export interface ManageIdResult {
code: number;
msg: string;
data: Manage;
rows: Array<any>;
total: number;
}
export interface ManagePageResult {
code: number;
msg: string;

25
src/types/application/preproducts.d.ts vendored Normal file
View File

@@ -0,0 +1,25 @@
declare namespace API.ApplicationProducts {
export interface result {
total: number;
rows: Product[];
code: number;
msg: string;
}
export interface Product {
createTime: string;
companyCardId: number;
name: string;
companyNature: string;
backgroudColor: string;
status: number;
}
export interface Params {
companyCardId?: number;
name?: string;
companyNature?: string;
backgroudColor?: string;
status?: number;
}
}

View File

@@ -7,7 +7,7 @@ declare namespace API.AreaBusiness {
createTime: string;
}
export interface LinePoint {
export interface LinePoint {
latitude: number;
longitude: numberl;
lineName: string;
@@ -27,6 +27,7 @@ declare namespace API.AreaBusiness {
latitude: number;
longitude: number;
commercialAreaId?: number;
address?: string;
}
export interface CirclePageResult {

43
src/types/classify/industry.d.ts vendored Normal file
View File

@@ -0,0 +1,43 @@
declare namespace API.ClassifyIndustry {
export interface IndustryResult {
total: number;
rows: IndustryRow[];
code: number;
msg: string;
}
export interface IndustryRow {
createTime?: any;
industryId: number;
parentId: number;
industryName: string;
orderNum: number;
status: string;
}
export interface Params {
industryId?: number;
parentId?: number;
industryName?: string;
orderNum?: number;
status?: string;
}
export interface IndustryTreeResult {
msg: string;
code: number;
data: IndustryTreeParentData[];
}
export interface IndustryTreeData {
id: number;
label: string;
children?: IndustryTreeParentData[];
}
export interface IndustryTreeParentData {
id: number;
label: string;
children?: IndustryTreeData[];
}
}

25
src/types/classify/jobs.d.ts vendored Normal file
View File

@@ -0,0 +1,25 @@
declare namespace API.ClassifyJobs {
export interface Result {
total: number;
rows: Jobs[];
code: number;
msg: string;
}
export interface Jobs {
createTime?: any;
jobId: number;
parentId: number;
jobName: string;
orderNum: number;
status: string;
}
export interface Params {
jobId?: number;
parentId?: number;
jobName?: string;
orderNum?: number;
status?: string;
}
}

View File

@@ -1,4 +1,3 @@
declare namespace API.CompanyList {
export interface CompanyListResult {
total: number;
@@ -6,6 +5,7 @@ declare namespace API.CompanyList {
code: number;
msg: string;
}
export interface Company {
createTime: string;
companyId: number;
@@ -14,7 +14,9 @@ declare namespace API.CompanyList {
industry: string;
scale: string;
code: string;
description: string;
}
export interface Params {
createTime?: string;
companyId?: number;

View File

@@ -16,7 +16,7 @@ declare namespace API.JobFairList {
longitude?: any;
startTime: string;
endTime: string;
companyList?: any;
companyList?: RootObjectDataCompanyList[];
}
export interface Params {
createTime?: any;
@@ -30,4 +30,10 @@ declare namespace API.JobFairList {
endTime: string;
companyList?: any;
}
export interface ListInfoResult {
msg: string;
code: number;
data: JobFairListRows;
}
}

38
src/types/mobileusers/list.d.ts vendored Normal file
View File

@@ -0,0 +1,38 @@
declare namespace API.MobileUser {
export interface ListResult {
total: number;
rows: ListRow[];
code: number;
msg: string;
}
export interface ListRow {
createTime?: string;
userId: number;
name: string;
age: string;
sex: string;
birthDate: string;
education: string;
politicalAffiliation: string;
phone: string;
avatar: string;
salaryMin: string;
salaryMax: string;
area: string;
status: string;
loginIp: string;
loginDate?: string;
jobTitleId?: string;
jobTitle?: string;
}
export interface ListParams {
name?: string;
age?: string;
sex?: string;
birthDate?: string;
education?: string;
politicalAffiliation?: string;
}
}

401
src/utils/similarity_Job.js Normal file
View File

@@ -0,0 +1,401 @@
// 使用Intl.Segmenter对中文文本进行分词
function segmentText(text) {
const segmenter = new Intl.Segmenter('zh-Hans', {
granularity: 'word',
}); // 使用中文简体语言
const segments = [];
for (let segment of segmenter.segment(text.toLowerCase())) {
// 转为小写后进行分词
segments.push(segment.segment);
}
return segments;
}
// 语气 停用次
const stopWords = [
'的',
'了',
'啊',
'哦',
'/',
'、',
' ',
'',
'-',
'',
'',
'(',
')',
'+',
'=',
'~',
'!',
'<',
'>',
'?',
'[',
']',
'{',
'}',
];
function cleanKeywords(arr) {
return arr.filter((word) => word && !stopWords.includes(word));
}
function calculateMatchScore(source, target) {
const sourceSet = new Set(cleanKeywords(source));
const targetSet = new Set(cleanKeywords(target));
let matchCount = 0;
for (let word of sourceSet) {
if (targetSet.has(word)) {
matchCount++;
}
}
// 匹配度 = source中匹配到的词 / source总词数
return matchCount / sourceSet.size;
}
class CsimilarityJobs {
config = {
thresholdVal: 0.69,
titleSimilarityWeight: 0.4,
salaryMatchWeight: 0.2,
areaMatchWeight: 0.2,
educationMatchWeight: 0.2,
experiencenMatchWeight: 0.1,
};
userTitle = ['Java', 'C', '全栈工程师'];
userSalaryMin = 10000;
userSalaryMax = 15000;
userArea = 0; // 用户指定的区域(例如:市南区)
userEducation = 4; // 用户学历假设4为本科
userExperience = 2; // 用户工作经验
jobTitle = '';
jobMinSalary = 10000;
jobMaxSalary = 15000;
jobLocationAreaCode = 0;
jobEducation = 4;
jobExperience = 2;
jobCategory = '';
// 系统
log = false;
constructor() {}
setUserInfo(resume) {
this.userTitle = resume.jobTitle;
this.userSalaryMax = Number(resume.salaryMax);
this.userSalaryMin = Number(resume.salaryMin);
this.userArea = Number(resume.area);
this.userEducation = resume.education;
this.userExperience = this.getUserExperience(Number(resume.age));
}
setJobInfo(jobInfo) {
this.jobTitle = jobInfo.jobTitle;
this.jobMinSalary = jobInfo.minSalary;
this.jobMaxSalary = jobInfo.maxSalary;
this.jobLocationAreaCode = jobInfo.jobLocationAreaCode;
this.jobEducation = jobInfo.education;
this.jobExperience = jobInfo.experience;
this.jobCategory = jobInfo.jobCategory;
}
calculationMatchingDegreeJob(resume) {
// 计算职位标题相似度
// const titleSimilarity = stringSimilarity.compareTwoStrings(this.userTitle, job.jobTitle);
let jobT = null;
if (this.jobCategory) {
jobT = this.calculateBestJobCategoryMatch(
resume.jobTitle || resume.jobTitleString || [],
this.jobCategory,
);
} else {
jobT = this.calculateBestJobMatch(
resume.jobTitle || resume.jobTitleString || [],
this.jobTitle,
);
}
const { bestMatchJobTitle, maxSimilarity } = jobT;
// 计算薪资匹配度
const salaryMatch = this.calculateSalaryMatch(
Number(resume.salaryMin),
Number(resume.salaryMax),
this.jobMinSalary,
this.jobMaxSalary,
);
// 计算区域匹配度
const areaMatch = this.calculateAreaMatch(Number(resume.area), this.jobLocationAreaCode);
// 计算学历匹配度
const educationMatch = this.calculateEducationMatch(resume.education, this.jobEducation);
// 计算工作经验匹配度
// const experiencenMatch = this.calculateExperienceMatch2(this.userExperience, job.experience);
// 综合匹配度 = 0.4 * 职位相似度 + 0.2 * 薪资匹配度 + 0.1 * 区域匹配度 + 0.2 * 学历匹配度 + 0.1 * 工作经验匹配度
const overallMatch =
this.config.titleSimilarityWeight * maxSimilarity +
this.config.salaryMatchWeight * salaryMatch +
this.config.areaMatchWeight * areaMatch +
this.config.educationMatchWeight * educationMatch;
// console.log(`Job ${job.jobTitle}工作经验匹配度: ${experiencenMatch}`);
if (this.log) {
console.log(
`Job ${job.jobTitle} 标题相似度 ${maxSimilarity} 薪资匹配度: ${salaryMatch}学历匹配度: ${educationMatch} 区域匹配度: ${areaMatch} 综合匹配度: ${overallMatch.toFixed(2)}`,
);
}
// 设置阈值进行岗位匹配判断
const threshold = this.config.thresholdVal;
return {
overallMatch: overallMatch.toFixed(2) * 100 + '%',
data: resume,
maxSimilarity,
salaryMatch,
educationMatch,
areaMatch,
};
}
calculationMatchingDegree(job) {
// 计算职位标题相似度
// console.log(this.userTitle, job.jobTitle)
// const titleSimilarity = stringSimilarity.compareTwoStrings(this.userTitle, job.jobTitle);
let jobT = null;
if (job.jobCategory) {
jobT = this.calculateBestJobCategoryMatch(this.userTitle, job.jobCategory);
} else {
jobT = this.calculateBestJobMatch(this.userTitle, job.jobTitle);
}
const { bestMatchJobTitle, maxSimilarity } = jobT;
// 计算薪资匹配度
const salaryMatch = this.calculateSalaryMatch(
this.userSalaryMin,
this.userSalaryMax,
job.minSalary,
job.maxSalary,
);
// 计算区域匹配度
const areaMatch = this.calculateAreaMatch(this.userArea, job.jobLocationAreaCode);
// 计算学历匹配度
const educationMatch = this.calculateEducationMatch(this.userEducation, job.education);
// 计算工作经验匹配度
// const experiencenMatch = this.calculateExperienceMatch2(this.userExperience, job.experience);
// 综合匹配度 = 0.4 * 职位相似度 + 0.2 * 薪资匹配度 + 0.1 * 区域匹配度 + 0.2 * 学历匹配度 + 0.1 * 工作经验匹配度
const overallMatch =
this.config.titleSimilarityWeight * maxSimilarity +
this.config.salaryMatchWeight * salaryMatch +
this.config.areaMatchWeight * areaMatch +
this.config.educationMatchWeight * educationMatch;
// console.log(`Job ${job.jobTitle}工作经验匹配度: ${experiencenMatch}`);
if (this.log) {
console.log(
`Job ${job.jobTitle} 标题相似度 ${maxSimilarity} 薪资匹配度: ${salaryMatch}学历匹配度: ${educationMatch} 区域匹配度: ${areaMatch} 综合匹配度: ${overallMatch.toFixed(2)}`,
);
}
// 设置阈值进行岗位匹配判断
const threshold = this.config.thresholdVal;
if (overallMatch > threshold) {
return {
overallMatch: overallMatch.toFixed(2) * 100 + '%',
data: job,
maxSimilarity,
salaryMatch,
educationMatch,
areaMatch,
};
}
}
// 根据用户年龄推算工作经验年限区间
getUserExperience(age) {
if ((age = 0)) {
// 30以下
return {
min: 0,
max: 5,
};
} else if (age <= 1) {
// 40以下
return {
min: 5,
max: 10,
};
} else if (age <= 2) {
// 50以下
return {
min: 10,
max: 20,
};
} else {
// 50以上
return {
min: 20,
max: 40,
};
}
}
// 计算经验匹配度
calculateExperienceMatch2(userExperience, jobExperience) {
const jobExperienceRange = this.mapJobExperience(jobExperience);
if (
userExperience.min <= jobExperienceRange.max &&
userExperience.max >= jobExperienceRange.min
) {
return 1;
}
if (
(userExperience.min <= jobExperienceRange.max &&
userExperience.max > jobExperienceRange.min) ||
(userExperience.max >= jobExperienceRange.min && userExperience.min < jobExperienceRange.max)
) {
return 0.5; // 部分匹配
}
return 0; // 不匹配
}
// 映射岗位经验要求到工作经验年限区间
mapJobExperience(jobExperience) {
const experienceMapping = {
1: {
min: 0,
max: 0,
},
2: {
min: 0,
max: 1,
},
3: {
min: 0,
max: 1,
},
4: {
min: 1,
max: 3,
},
5: {
min: 3,
max: 5,
},
6: {
min: 5,
max: 10,
},
7: {
min: 10,
max: 20,
},
8: {
min: 0,
max: 40,
},
};
return experienceMapping[jobExperience];
}
// 计算工作经验匹配度
calculateExperiencenMatch(userExperience, jobExperience) {
if (userExperience === jobExperience) {
return 1;
} else if (userExperience > jobExperience) {
return 0.75;
} else {
return 0;
}
}
calculateSalaryMatch(userMin, userMax, jobMin, jobMax) {
const isMinMatch = userMin >= jobMin && userMin <= jobMax;
const isMaxMatch = userMax >= jobMin && userMax <= jobMax;
if (isMinMatch || isMaxMatch) {
return 1;
}
const minDifference = Math.abs(userMin - jobMin);
const maxDifference = Math.abs(userMax - jobMax);
if (minDifference > 3000 && maxDifference > 3000) {
return 0;
}
return 0.5; // 部分匹配
}
// 计算区域匹配度
calculateAreaMatch(userArea, jobArea) {
return userArea === jobArea ? 1 : 0.5;
}
calculateBestJobCategoryMatch(userJobTitles, jobTitle) {
let maxSimilarity = 0;
let bestMatchJobTitle = '';
for (let i = 0; i < userJobTitles.length; i++) {
let userTitle = userJobTitles[i];
if (userTitle === jobTitle) {
maxSimilarity = 1;
bestMatchJobTitle = userTitle;
break;
}
}
return {
bestMatchJobTitle,
maxSimilarity,
};
}
// 计算职位匹配度
calculateBestJobMatch(userJobTitles, jobTitle) {
let maxSimilarity = 0;
let bestMatchJobTitle = '';
userJobTitles.forEach((userTitle) => {
const userSegments = segmentText(userTitle);
const jobSegments = segmentText(jobTitle);
// 比较分词的交集,计算匹配度
// const intersection = userSegments.filter(segment => jobSegments.includes(segment));
// const similarity = intersection.length / userSegments.length; // 计算匹配度
// 计算匹配度
const similarity = calculateMatchScore(userSegments, jobSegments);
// 记录匹配度最高的职位
if (similarity > maxSimilarity) {
maxSimilarity = similarity;
bestMatchJobTitle = userTitle;
}
});
return {
bestMatchJobTitle,
maxSimilarity,
};
}
// 计算学历匹配度
calculateEducationMatch(userEducation, jobEducation) {
if (userEducation === jobEducation) {
return 1;
} else if (userEducation > jobEducation) {
return 1;
} else {
return 0;
}
}
}
const similarityJobs = new CsimilarityJobs();
export default similarityJobs;

View File

@@ -8,3 +8,13 @@ export function getYear(date = new Date()) {
}
return date.getFullYear();
}
export function debounce<T extends (...args: any[]) => any>(fn: T, delay = 300) {
let timer: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn(...args);
}, delay);
};
}