fix:更新
Some checks failed
Build and Push Docker Image / build (push) Failing after 3h10m10s

This commit is contained in:
Your Name 2026-01-13 15:19:57 +08:00
parent 9a2e1afe56
commit 7b09d9a4b8
77 changed files with 1659 additions and 9624 deletions

View File

@ -17,10 +17,10 @@ export default defineConfig({
}, },
proxy: { proxy: {
'/api/': { '/api/': {
target: 'http://10.39.13.78:8002/', target: 'http://10.39.13.78:8001/',
// target: 'https://gcadmin-test.linyikj.com.cn', // target: 'https://gcadmin-test.linyikj.com.cn',
// target: 'http://guocaiservice.com', // target: 'http://guocaiservice.com',
// changeOrigin: true, changeOrigin: true,
pathRewrite: { '^': '' }, pathRewrite: { '^': '' },
}, },
}, },

View File

@ -1,6 +1,6 @@
{ {
"url": "http://10.39.13.78:8002/api/docs/openapi", "url": "http://10.39.13.78:8001/api/docs/openapi",
"module": "Admin", "module": "Company",
"outPath": "./src/gen/", "outPath": "./src/gen/",
"apis": { "apis": {
"firstLine": "import { MyResponseType } from '@/common';\nimport { request } from '@umijs/max';" "firstLine": "import { MyResponseType } from '@/common';\nimport { request } from '@umijs/max';"

View File

@ -0,0 +1,28 @@
import { MyPaginationMetaType } from '@/common';
import { Pagination } from 'antd';
export function MyModalPagination({
meta,
setParams,
}: {
meta?: MyPaginationMetaType | null;
setParams?: ({ page, perPage }: { page: number; perPage: number }) => void;
}) {
console.log(meta, 'meta2222');
if (!meta) return null;
return (
<div style={{ textAlign: 'right' }}>
<Pagination
style={{ padding: '10px 0' }}
current={meta?.current_page || 1}
total={meta?.total || 0}
pageSize={meta?.per_page || 20}
onChange={(page, perPage) => setParams?.({ page, perPage })}
size="small"
showTotal={(total) => `总共${total}`}
showSizeChanger
showQuickJumper
/>
</div>
);
}

View File

@ -1,25 +1,10 @@
import { MyIcons, MyIconsType, PermissionsType, useMyState } from '@/common'; import { MyIcons, MyIconsType, PermissionsType, useMyState } from '@/common';
import AvatarProps from '@/common/components/layout/AvatarProps'; import AvatarProps from '@/common/components/layout/AvatarProps';
import { import { SettingOutlined } from '@ant-design/icons';
BellOutlined,
SettingOutlined,
TabletOutlined,
} from '@ant-design/icons';
import { Link, RuntimeConfig, history, useNavigate } from '@umijs/max'; import { Link, RuntimeConfig, history, useNavigate } from '@umijs/max';
import { import { AutoComplete, Button, Input, Menu, MenuProps, Space } from 'antd';
AutoComplete,
Button,
Image,
Input,
Menu,
MenuProps,
Popover,
Space,
} from 'antd';
import { useState } from 'react'; import { useState } from 'react';
import './allConfig.scss'; import './allConfig.scss';
import ImgCustomerWxApp from './customer_wx_app.jpg';
import ImgEmployeeWxApp from './employee_wx_app.jpg';
// import Logo from './logo.png'; // import Logo from './logo.png';
interface LevelKeysProps { interface LevelKeysProps {
key?: string; key?: string;
@ -122,7 +107,7 @@ export const LayoutConfig: RuntimeConfig['layout'] = () => {
<div className="headerContentRender"> <div className="headerContentRender">
<div style={{ display: 'flex', alignItems: 'center', gap: 20 }}> <div style={{ display: 'flex', alignItems: 'center', gap: 20 }}>
<HeaderSearch permissionsList={permissionsList} /> <HeaderSearch permissionsList={permissionsList} />
<Space size={20} style={{ color: '#666' }}> {/* <Space size={20} style={{ color: '#666' }}>
: :
{quickLinks.map((q) => ( {quickLinks.map((q) => (
<a <a
@ -133,10 +118,10 @@ export const LayoutConfig: RuntimeConfig['layout'] = () => {
{q.label} {q.label}
</a> </a>
))} ))}
</Space> </Space> */}
</div> </div>
<Space size={10}> <Space size={10}>
<Popover {/* <Popover
placement="bottom" placement="bottom"
title="小程序二维码" title="小程序二维码"
content={ content={
@ -155,7 +140,7 @@ export const LayoutConfig: RuntimeConfig['layout'] = () => {
> >
<Button type="default" shape="circle" icon={<TabletOutlined />} /> <Button type="default" shape="circle" icon={<TabletOutlined />} />
</Popover> </Popover>
<Button type="default" shape="circle" icon={<BellOutlined />} /> <Button type="default" shape="circle" icon={<BellOutlined />} /> */}
<Button <Button
type="default" type="default"
shape="circle" shape="circle"

View File

@ -13,7 +13,7 @@ import { theme } from 'antd';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { stateActions } from '..'; import { stateActions } from '..';
import gcLogo from './gclogo.png'; // import gcLogo from './gclogo.png';
import logingBg from './loginBgImg.jpg'; import logingBg from './loginBgImg.jpg';
export function MyLoginPage() { export function MyLoginPage() {
@ -44,7 +44,7 @@ export function MyLoginPage() {
<LoginFormPage<ApiTypes.Common.Auth.Login> <LoginFormPage<ApiTypes.Common.Auth.Login>
title={ title={
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}> <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<img src={gcLogo} style={{ height: 30, width: 'auto' }} /> {/* <img src={gcLogo} style={{ height: 30, width: 'auto' }} /> */}
<span style={{ color: '#b1b1b1ff', fontSize: 20 }}>|</span> <span style={{ color: '#b1b1b1ff', fontSize: 20 }}>|</span>
<span style={{ color: token.colorTextBase, fontSize: 21 }}> <span style={{ color: token.colorTextBase, fontSize: 21 }}>
@ -71,7 +71,7 @@ export function MyLoginPage() {
> >
<> <>
<ProFormText <ProFormText
name="username" name="phone"
fieldProps={{ fieldProps={{
size: 'large', size: 'large',
prefix: <UserOutlined className={'prefixIcon'} />, prefix: <UserOutlined className={'prefixIcon'} />,

3750
src/gen/ApiTypes.d.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
import { Apis } from '@/gen/Apis';
import { ProFormSelect, QueryFilter } from '@ant-design/pro-components';
import { Form } from 'antd';
type Props = {
onChange?: (value: any) => void;
};
export default function Search(props: Props) {
const [form] = Form.useForm();
return (
<QueryFilter
style={{ backgroundColor: '#fff' }}
defaultCollapsed
split
form={form}
onFinish={props?.onChange}
onReset={() => {
props?.onChange?.(form?.getFieldsValue() || {});
}}
>
<ProFormSelect
name="asset_houses_id"
label="房屋"
valueEnum={{
open: '未解决',
closed: '已解决',
}}
request={async (params) => {
let res = await Apis.Asset.AssetProjects.Select({
keywords: params?.keyWords,
...params,
});
return res?.data;
}}
placeholder="请选择房屋"
/>
</QueryFilter>
);
}

View File

@ -1,17 +1,52 @@
import { import { MyPageContainer } from '@/common';
MyButtons, import { MyModalPagination } from '@/common/components/MyModalPagination';
MyColumns,
MyPageContainer,
MyProTableProps,
} from '@/common';
import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis'; import { Apis } from '@/gen/Apis';
import { ProTable } from '@ant-design/pro-components'; import { HomeFilled } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max'; import { useNavigate } from '@umijs/max';
import { Space } from 'antd'; import { Empty, Space, Tag } from 'antd';
import { useEffect, useState } from 'react';
import SearchInfo from './components/SearchInfo';
export default function Index({ title = '房屋账单' }) { export default function Index({ title = '房屋账单' }) {
const navigate = useNavigate(); const navigate = useNavigate();
// const [selectedBuilding, setSelectedBuilding] =
// useState<SelectedBuilding | null>(null);
const [params, setParams] = useState<any>({ page: 1 });
const [getSummaryBillListData, setGetSummaryBillListData] = useState<any>({});
const getSummaryBillList = (data: any) => {
Apis.Bill.HouseBills.SummaryBillList({ ...params, ...data }).then((res) => {
setParams({ ...params, ...data });
setGetSummaryBillListData(res);
});
};
useEffect(() => {
getSummaryBillList({ page: 1 });
}, []);
// 选择楼栋的回调函数
// const handleBuildingSelect = useCallback((building: SelectedBuilding) => {
// setSelectedBuilding(building);
// // 保存到本地缓存
// localStorage.setItem('selectedBuilding', JSON.stringify(building));
// }, []);
// 从本地缓存恢复选中的楼栋信息
// useEffect(() => {
// const cachedBuilding = localStorage.getItem('selectedBuilding');
// if (cachedBuilding) {
// try {
// const building = JSON.parse(cachedBuilding) as SelectedBuilding;
// setSelectedBuilding(building);
// // 恢复后重新获取账单列表
// getSummaryBillList(building);
// } catch (error) {
// console.error('Failed to parse cached building:', error);
// }
// }
// }, []);
return ( return (
<MyPageContainer <MyPageContainer
@ -20,94 +55,111 @@ export default function Index({ title = '房屋账单' }) {
tabKey="summary" tabKey="summary"
tabLabel={title} tabLabel={title}
> >
<ProTable <div
{...MyProTableProps.props} style={{
headerTitle="房屋账单" display: 'flex',
request={async (params, sort) => alignItems: 'start',
MyProTableProps.request( justifyContent: 'space-between',
params, gap: 15,
sort, }}
Apis.Bill.HouseBills.SummaryBillList, >
) <Space direction="vertical" style={{ flex: 1 }}>
} <SearchInfo
columns={[ onChange={(values) => {
{ setParams({
title: '房屋ID', asset_houses_id: values?.asset_houses_id || '',
dataIndex: 'asset_houses_id', page: 1,
search: false, });
}, getSummaryBillList({
Selects?.AssetProjects({ asset_houses_id: values?.asset_houses_id || '',
title: '选择项目', page: 1,
key: 'asset_projects_id', });
hidden: true,
}),
{
title: '关联项目',
dataIndex: 'project_name',
search: false,
// search: {
// transform: (value) => {
// return { project_name: value };
// },
// },
},
{
title: '房屋名称',
dataIndex: ['asset_house', 'full_name'],
search: {
transform: (value) => {
return { full_name: value };
},
},
},
// {
// title: '账单金额合计',
// dataIndex: 'payable_amount_sum',
// search: false,
// },
// {
// title: '滞纳金合计',
// dataIndex: 'late_fee_sum',
// search: false,
// },
// {
// title: '优惠金额合计',
// dataIndex: 'discount_amount_sum',
// search: false,
// },
{
title: '应收合计',
dataIndex: 'total_payable_sum',
search: false,
},
{
title: '已收合计',
dataIndex: 'total_paid_sum',
search: false,
},
{
title: '未收合计',
render: (_, record) => {
return (record.total_payable_sum - record.total_paid_sum).toFixed(
2,
);
},
search: false,
},
MyColumns.Option({
render: (_, item: any, index) => (
<Space key={index}>
<MyButtons.View
title="查看"
onClick={() => {
navigate(`/bills/summary/show/${item.asset_houses_id}`);
}} }}
/> />
</Space> <ProCard>
), <div style={{ display: 'flex', flexWrap: 'wrap', gap: 15 }}>
}), {getSummaryBillListData?.data?.length ? null : (
]} <div
style={{
display: 'flex',
alignItems: 'center',
flex: 1,
justifyContent: 'center',
padding: '15px 0',
}}
>
<Empty />
</div>
)}
{getSummaryBillListData?.data?.map((res: any) => {
return (
<div
key={`item_${res?.id}`}
style={{
width: '240px',
height: '120px',
backgroundColor: '#f8f8f8',
borderRadius: 5,
overflow: 'hidden',
cursor: 'pointer',
}}
onClick={() => {
navigate(`/bills/summary/show/${res?.asset_houses_id}`);
}}
>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
borderBottom: '1px solid #eee',
padding: '10px 14px 10px 15px',
}}
>
<HomeFilled />
<div>
{res.total_payable_sum - res.total_paid_sum > 0 ? (
<Tag color="red"></Tag>
) : (
<Tag color="green"></Tag>
)}
</div>
</div>
<div style={{ padding: '0 15px' }}>
<div style={{ padding: '10px 0', fontWeight: 'bold' }}>
{res?.asset_house?.full_name}
</div>
{res.total_payable_sum - res.total_paid_sum ? (
<div style={{ color: '#f00' }}>
¥
{(res.total_payable_sum - res.total_paid_sum).toFixed(
2,
)}
</div>
) : (
''
)}
</div>
</div>
);
})}
</div>
<div
style={{
display: 'flex',
padding: '15px 0 0 0',
justifyContent: 'flex-end',
}}
>
<MyModalPagination
{...{ setParams: getSummaryBillList }}
meta={getSummaryBillListData?.meta}
/> />
</div>
</ProCard>
</Space>
</div>
</MyPageContainer> </MyPageContainer>
); );
} }

View File

@ -1,7 +1,6 @@
import { import {
MyButtons, MyButtons,
MyColumns, MyColumns,
MyImportModal,
MyPageContainer, MyPageContainer,
MyProTableProps, MyProTableProps,
renderTextHelper, renderTextHelper,
@ -21,20 +20,7 @@ export default function Index({ title = '员工管理' }) {
const getCurrentPermissions = useCurrentPermissions(); const getCurrentPermissions = useCurrentPermissions();
let toolBarRender = (action: any) => { let toolBarRender = (action: any) => {
return getCurrentPermissions({ return getCurrentPermissions({
create: ( add: <EmployeeCreate key="Create" reload={action?.reload} title="员工" />,
<EmployeeCreate key="Create" reload={action?.reload} title="员工" />
),
export: (
<MyImportModal
key="ImportHouse"
title="导入外部人员"
type="default"
size="middle"
templateApi={Apis.Company.CompanyEmployees.DownloadTemplate}
importApi={Apis.Company.CompanyEmployees.Import}
reload={action?.reload}
/>
),
}); });
}; };
let tableRender = (item: any, action: any) => { let tableRender = (item: any, action: any) => {
@ -42,14 +28,16 @@ export default function Index({ title = '员工管理' }) {
update: ( update: (
<EmployeeUpdate item={item} reload={action?.reload} title={title} /> <EmployeeUpdate item={item} reload={action?.reload} title={title} />
), ),
change: <Change item={item} reload={action?.reload} title={title} />, CompanyEmployees: (
<Change item={item} reload={action?.reload} title={title} />
),
}); });
let permissionsSpace = getCurrentPermissions({ let permissionsSpace = getCurrentPermissions({
Role: { Role: {
key: '1', key: '1',
label: <Role item={item} reload={action?.reload} title={title} />, label: <Role item={item} reload={action?.reload} title={title} />,
}, },
resetPassword: { ResetPassword: {
key: '2', key: '2',
label: ( label: (
<MyButtons.Default <MyButtons.Default
@ -97,7 +85,6 @@ export default function Index({ title = '员工管理' }) {
{...MyProTableProps.props} {...MyProTableProps.props}
// search={false} // search={false}
headerTitle="员工列表" headerTitle="员工列表"
tooltip="通过企微同步的员工信息的修改,需在企微修改后,同步到系统,才能生效。"
request={async (params, sort) => request={async (params, sort) =>
MyProTableProps.request( MyProTableProps.request(
params, params,
@ -106,22 +93,6 @@ export default function Index({ title = '员工管理' }) {
) )
} }
toolBarRender={(action) => [ toolBarRender={(action) => [
<MyButtons.Default
key="sync_wechat_employees"
type="primary"
size="middle"
title="企微同步"
isConfirm={true}
description="确定要执行企微同步操作吗?"
onConfirm={async () => {
try {
await Apis.Company.CompanyEmployees.SyncWechatEmployees();
action?.reload?.();
} catch (error) {
console.error('同步企微信息失败:', error);
}
}}
/>,
<CompletePhone <CompletePhone
key="CompletePhone" key="CompletePhone"
reload={action?.reload} reload={action?.reload}

View File

@ -7,7 +7,6 @@ import {
import { Selects } from '@/components/Select'; import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis'; import { Apis } from '@/gen/Apis';
import { CompanyEmployeesTypeEnum } from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components'; import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd'; import { Form, message } from 'antd';
export default function Update(props: MyBetaModalFormProps) { export default function Update(props: MyBetaModalFormProps) {
@ -16,15 +15,7 @@ export default function Update(props: MyBetaModalFormProps) {
<BetaSchemaForm<ApiTypes.Company.CompanyEmployees.Update> <BetaSchemaForm<ApiTypes.Company.CompanyEmployees.Update>
{...MyModalFormProps.props} {...MyModalFormProps.props}
title={`组织调整`} title={`组织调整`}
trigger={ trigger={<MyButtons.Edit title="组织" type="primary" />}
<MyButtons.Edit
title="组织"
disabled={
props.item?.type !== CompanyEmployeesTypeEnum.External.value
}
type="primary"
/>
}
wrapperCol={{ span: 24 }} wrapperCol={{ span: 24 }}
width="500px" width="500px"
key={new Date().getTime()} key={new Date().getTime()}

View File

@ -17,14 +17,14 @@ export default function Create(props: MyBetaModalFormProps) {
return ( return (
<BetaSchemaForm<ApiTypes.Company.CompanyEmployees.Store> <BetaSchemaForm<ApiTypes.Company.CompanyEmployees.Store>
{...MyModalFormProps.props} {...MyModalFormProps.props}
title={`添加外部人员`} title={`添加${props?.title}`}
layout="horizontal" layout="horizontal"
labelCol={{ span: 5 }} labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }} wrapperCol={{ span: 19 }}
labelAlign="left" labelAlign="left"
width="500px" width="500px"
key={new Date().getTime()} key={new Date().getTime()}
trigger={<MyButtons.Create title={`外部人员`} />} trigger={<MyButtons.Create title={props?.title} />}
form={form} form={form}
onOpenChange={(open: any) => { onOpenChange={(open: any) => {
if (open) { if (open) {

View File

@ -8,7 +8,7 @@ import {
import { Selects } from '@/components/Select'; import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis'; import { Apis } from '@/gen/Apis';
import { CompanyEmployeesTypeEnum, SexEnum } from '@/gen/Enums'; import { SexEnum } from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components'; import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd'; import { Form, message } from 'antd';
export default function Update(props: MyBetaModalFormProps) { export default function Update(props: MyBetaModalFormProps) {
@ -17,17 +17,7 @@ export default function Update(props: MyBetaModalFormProps) {
<BetaSchemaForm<ApiTypes.Company.CompanyEmployees.Update> <BetaSchemaForm<ApiTypes.Company.CompanyEmployees.Update>
{...MyModalFormProps.props} {...MyModalFormProps.props}
title={`编辑员工`} title={`编辑员工`}
trigger={ trigger={<MyButtons.Default title="编辑" type="primary" size="small" />}
<MyButtons.Default
title="编辑"
type="primary"
// variant="solid"
size="small"
disabled={
props.item?.type !== CompanyEmployeesTypeEnum.External.value
}
/>
}
layout="horizontal" layout="horizontal"
labelCol={{ span: 5 }} labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }} wrapperCol={{ span: 19 }}

View File

@ -1,121 +0,0 @@
import { Scene } from '@antv/l7';
import { L7Layer } from '@antv/l7-leaflet';
import { Choropleth } from '@antv/l7plot';
import * as L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { useEffect, useRef } from 'react';
import map_bg_img from './images/map_bg_img.png';
export default function MapInfo() {
const sceneRef = useRef<Scene>();
useEffect(() => {
if (sceneRef.current) return;
// 初始化地图场景
const map = L.map('map', {
center: [29.909571, 119.600006],
zoom: 10,
minZoom: 9,
maxZoom: 10,
zoomControl: false,
attributionControl: false,
}).setView([29.909571, 119.600006], 9);
const l7layer = new L7Layer({
logoVisible: false,
}).addTo(map);
const scene: any = l7layer.getScene();
// const scene = new Scene({
// id: 'map', // 传递 DOM 元素
// map: new Map({
// style: 'blank',
// pitch: 0,
// rotation: 0,
// center: [120.19382669582967, 30.258134],
// zoom: 9,
// minZoom: 8.5,
// maxZoom: 9,
// }),
// });
sceneRef.current = scene;
scene.on('loaded', () => {
// const imageLayer = new ImageLayer();
// imageLayer.source(localMapImage, {
// parser: {
// type: 'image',
// extent: [110, 27, 130, 45],
// },
// });
// scene.addLayer(imageLayer);
const choropleth = new Choropleth({
chinaBorder: false,
source: {
data: [],
joinBy: {
sourceField: 'name',
geoField: 'value',
},
},
viewLevel: {
level: 'city',
adcode: 330100,
},
autoFit: true,
style: {
opacity: 1,
stroke: '#0083FF',
lineWidth: 1,
lineOpacity: 1,
},
label: {
field: 'name',
style: {
fill: '#000',
opacity: 1,
fontSize: 15,
strokeWidth: 1.5,
},
},
state: {
active: { stroke: '#0083FF', lineWidth: 1, fill: '#E4F2FF' },
},
});
choropleth.addToScene(scene);
});
scene.on('resize', () => {
console.log('resize');
});
// 组件卸载时清理
return () => {
if (sceneRef.current) {
sceneRef.current.destroy();
}
};
}, []);
return (
<div
style={{
width: '100%',
height: '582px',
position: 'relative',
zIndex: 1,
backgroundColor: '#fff',
}}
>
<div
id="map"
style={{
width: '100%',
height: '582px',
background: `url(${map_bg_img}) no-repeat bottom`,
backgroundSize: '100%',
}}
></div>
</div>
);
}

View File

@ -1,65 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { Space } from 'antd';
import MyOverviewClient from './charts/OverviewClient';
import AddressIcon from './images/addressIcon.png';
import ImgLeftIcon from './images/LeftIcon.png';
import ImgMapTitleBg from './images/map_title_bg_img.svg';
import MyMapAntL7 from './MapAntL7';
import './styleMap.scss';
export default function Map(props: MyBetaModalFormProps) {
return (
<Space direction="vertical" style={{ width: '100%' }} size="small">
<div className="map_card">
<MyMapAntL7 />
<div className="map_card_contents">
<img src={ImgMapTitleBg} className="map_card_title_bg" />
<div className="map_data_contents">
<div className="map_card_title"></div>
</div>
</div>
<div className="map_card_data_contents">
<div className="map_card_data">
<div>
<div className="map_card_data_title">
<img src={ImgLeftIcon} />
<span></span>
{/* <img src={ImgRightIcon} /> */}
</div>
<div className="map_card_data_number">
{props?.item?.rankingData?.total_users}
</div>
</div>
</div>
<div className="map_card_data">
<div>
<div className="map_card_data_title">
<img src={ImgLeftIcon} />
<span></span>
{/* <img src={ImgRightIcon} /> */}
</div>
<div className="map_card_data_number">
{props?.item?.rankingData?.total_occupants}
</div>
</div>
</div>
</div>
<div className="others_project">
<div className="others_project_cell_list">
<img src={AddressIcon} alt="" />
<div>3</div>
</div>
<div className="others_project_cell_list">
<img src={AddressIcon} alt="" />
<div>3</div>
</div>
<div className="others_project_cell_list">
<img src={AddressIcon} alt="" />
<div>8</div>
</div>
</div>
</div>
<MyOverviewClient item={props?.item?.overviewData} />
</Space>
);
}

View File

@ -1,163 +0,0 @@
import { useMyState } from '@/common';
import { Apis } from '@/gen/Apis';
import { DoubleRightOutlined, RightOutlined } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max';
import { Progress, Space } from 'antd';
import { useEffect, useState } from 'react';
import ContractsToTalNumberBg from './images/ContractsToTalNumberBg.jpg';
import InfoIcon from './images/info.png';
import './styleLeft.scss';
export default function OverviewContractData() {
const { snap } = useMyState();
const navigate = useNavigate();
const [pendingCount, setPendingCount] = useState(0);
const [contractCount, setContractCount] = useState(0);
const [contractCountList, setContractCountList] = useState<any>([]);
const getPendingCount = async () => {
const res = await Apis.Approval.ApprovalInstances.PendingCount();
setPendingCount(res?.data?.count || 0);
const res2 = await Apis.Statistics.IndexCount.ContractStatistics();
setContractCount(res2?.data?.total);
setContractCountList([
{
title: '未审批',
number: res2?.data?.pending_approval,
path: '/contract/contracts',
status: 'TemporaryStorage',
color: '#FF2427',
},
{
title: '未用印',
number: res2?.data?.pending_seal,
path: '/contract/contracts',
color: '#F9B01E',
},
{
title: '未归档',
number: res2?.data?.pending_archive,
path: '/contract/contracts',
color: '#FFD789',
},
{
title: '待关闭',
number: res2?.data?.pending_close,
path: '/contract/contracts',
color: '#2A7EFB',
},
{
title: '审批中',
number: res2?.data?.under_approval,
status: 'UnderApproval',
path: '/contract/contracts',
color: '#2A7EFB',
},
{
title: '30天内到期',
number: res2?.data?.expiring_30_days,
path: '/contract/contracts',
color: '#2A7EFB',
},
{
title: '60天内到期',
number: res2?.data?.expiring_60_days,
path: '/contract/contracts',
color: '#2A7EFB',
},
{
title: '履约中',
number: res2?.data?.in_progress,
path: '/contract/contracts',
color: '#2A7EFB',
},
]);
console.log(res);
};
useEffect(() => {
getPendingCount();
}, []);
return (
<Space direction="vertical" style={{ width: '100%' }} size="small">
<ProCard className="border_radius_15px overview_contract_info_data_card">
<div className="review_information">
<div>
<div className="info_title">
{snap.session.user?.name || ''}
</div>
<div
className="info_content"
onClick={() => {
navigate('/approval/pending');
}}
>
{pendingCount ? (
<a>
{pendingCount || 0}
<DoubleRightOutlined />
</a>
) : (
'暂无可审核信息'
)}
</div>
</div>
<div>
<img src={InfoIcon} alt="" />
</div>
</div>
</ProCard>
<ProCard
style={{ width: '100%' }}
title={<a href="/contract/contracts_bi"></a>}
className="border_radius_15px overview_contract_data_card"
headerBordered
>
<Space direction="vertical" style={{ width: '100%' }}>
{/* <MyPageTitle title="合同数据概览" /> */}
<div className="contracts_total_number">
<img src={ContractsToTalNumberBg} alt="" />
<div className="contracts_total_number_text">
<div className="contracts_total_number_text_title"></div>
<div className="contracts_total_number_text_number">
{contractCount || 0}
</div>
</div>
</div>
<Space direction="vertical" size={10} style={{ width: '100%' }}>
{contractCountList?.map((res: any, index: number) => {
return (
<div key={`items_${index}`}>
<a
className="progress_title progress_title_first"
onClick={() => {
navigate(`${res?.path}?status=${res?.status}`);
}}
>
<div className="progress_title_text">
{res?.title} <RightOutlined />
</div>
<div
className="progress_title_number"
style={{ color: index < 3 ? res?.color : '#666' }}
>
{res?.number}
</div>
</a>
<Progress
percent={res?.number}
status="active"
strokeColor={res?.color}
size={['100%', 14]}
showInfo={false}
/>
</div>
);
})}
</Space>
</Space>
</ProCard>
</Space>
);
}

View File

@ -1,30 +0,0 @@
export default function PageTitle(props: {
title?: string;
subTitle?: string;
}) {
return (
<div
style={{
borderLeft: '5px solid #1890FF',
margin: '10px 0',
fontSize: '15px',
height: '23px',
lineHeight: '23px',
paddingLeft: '10px',
display: 'flex',
}}
>
<h2 style={{ display: 'inline-block' }}>{props.title || '标题'}</h2>
<div
style={{
display: 'inline-block',
padding: '3px 0 0 5px',
color: '#999',
fontSize: '15px',
}}
>
{props?.subTitle}
</div>
</div>
);
}

View File

@ -1,50 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { ProCard } from '@ant-design/pro-components';
import { Space } from 'antd';
import MyFinanceClient from './charts/FinanceClient';
import Ranking1 from './images/Ranking1.png';
import Ranking2 from './images/Ranking2.png';
import Ranking3 from './images/Ranking3.png';
import './styleRight.scss';
export default function Ranking(props: MyBetaModalFormProps) {
return (
<Space direction="vertical" size="small" className="overview_ranking_right">
<ProCard
style={{ width: '100%', height: '582px' }}
title="项目缴费率排名"
className="border_radius_15px"
headerBordered
>
<Space direction="vertical" size="large" style={{ width: '100%' }}>
<div className="ranking_item_content">
{props?.item?.rankingData?.payment_ranking?.map(
(item: any, index: number) => {
return (
<div className="ranking_item" key={index}>
{index < 3 ? (
<img
src={
index === 0
? Ranking1
: index === 1
? Ranking2
: Ranking3
}
alt=""
/>
) : (
<div className="ranking_number">{index + 1}</div>
)}
<div className="name">{item?.project_name}</div>
<div className="number">{item?.payment_rate}%</div>
</div>
);
},
)}
</div>
</Space>
</ProCard>
<MyFinanceClient item={props?.item?.overviewData} />
</Space>
);
}

View File

@ -1,155 +0,0 @@
export const workChartsData = [
{
name: '报修',
: '1月',
数量: 70,
},
{
name: '报事',
: '1月',
数量: 20,
},
{
name: '投诉',
: '2月',
数量: 10,
},
{
name: '报修',
: '2月',
数量: 80,
},
{
name: '报事',
: '2月',
数量: 40,
},
{
name: '投诉',
: '2月',
数量: 6,
},
{
name: '报修',
: '3月',
数量: 67,
},
{
name: '报事',
: '3月',
数量: 27,
},
{
name: '投诉',
: '3月',
数量: 7,
},
{
name: '报修',
: '4月',
数量: 55,
},
{
name: '报事',
: '4月',
数量: 17,
},
{
name: '投诉',
: '4月',
数量: 9,
},
{
name: '报修',
: '5月',
数量: 32,
},
{
name: '报事',
: '5月',
数量: 27,
},
{
name: '投诉',
: '5月',
数量: 11,
},
{
name: '报修',
: '6月',
数量: 42,
},
{
name: '报事',
: '6月',
数量: 7,
},
{
name: '投诉',
: '6月',
数量: 21,
},
];
export const FinanceClientData = [
{
name: '应收',
: '1月',
数量: 200,
},
{
name: '实收',
: '1月',
数量: 210,
},
{
name: '应收',
: '2月',
数量: 170,
},
{
name: '实收',
: '2月',
数量: 200,
},
{
name: '应收',
: '3月',
数量: 270,
},
{
name: '实收',
: '3月',
数量: 310,
},
{
name: '应收',
: '4月',
数量: 230,
},
{
name: '实收',
: '4月',
数量: 190,
},
{
name: '应收',
: '5月',
数量: 170,
},
{
name: '实收',
: '5月',
数量: 160,
},
{
name: '应收',
: '6月',
数量: 250,
},
{
name: '实收',
: '6月',
数量: 280,
},
];

View File

@ -1,39 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { Column } from '@ant-design/plots';
import { ProCard } from '@ant-design/pro-components';
import { useEffect, useState } from 'react';
export default function FinanceClient(props: MyBetaModalFormProps) {
const [configData, setConfigData] = useState({});
const config = {
data: [],
xField: '月份',
yField: '数量',
colorField: 'name',
group: true,
style: {
// 矩形四个方向的内边距
inset: 3,
// 矩形单个方向的内边距
// insetLeft:5,
// insetRight:20,
// insetBottom:10
// insetTop:10
},
};
useEffect(() => {
console.log(props?.item?.financial, 'financial');
setConfigData({ ...config, data: props?.item?.financial || [] });
}, [props?.item?.financial]);
return (
<ProCard
title={<a href="/work_order/work_bi"></a>}
//跳转链接src/pages/work_order/work_bill/index.tsx
headerBordered
className="border_radius_15px"
style={{ height: 468, width: '100%', overflow: 'hidden' }}
>
<Column {...configData} />
</ProCard>
);
}

View File

@ -1,37 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { Column } from '@ant-design/plots';
import { ProCard } from '@ant-design/pro-components';
import { useEffect, useState } from 'react';
export default function OverviewClient(props: MyBetaModalFormProps) {
const [configData, setConfigData] = useState({});
const config = {
data: [],
xField: '月份',
yField: '数量',
colorField: 'name',
group: true,
style: {
// 矩形四个方向的内边距
inset: 5,
// 矩形单个方向的内边距
// insetLeft:5,
// insetRight:20,
// insetBottom:10
// insetTop:10
},
};
useEffect(() => {
console.log(props?.item?.work_order, 'financial');
setConfigData({ ...config, data: props?.item?.work_order || [] });
}, [props?.item?.work_order]);
return (
<ProCard
title={<a href="/charge/charge_bi"></a>}
headerBordered
className="border_radius_15px"
style={{ height: 468, width: '100%', overflow: 'hidden' }}
>
<Column {...configData} />
</ProCard>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="714" height="47" viewBox="0 0 714 47"><g><g><g><path d="M212,17L231.661898,39.996876C235.461674,44.441154,241.016041,47,246.863251,47L467.13675,47C472.98395,47,478.53833,44.441154,482.3381,39.996877999999995L502,17L212,17Z" fill="#2A7EFB" fill-opacity="1"/></g><g><path d="M0,17L714,17L714,12.000001C714,6.4771528,709.52283,2,704,2L10.000001,2C4.4771528,2,0,6.4771528,0,12.000001L0,17Z" fill="#2A7EFB" fill-opacity="1"/></g></g><g><g><path d="M212,15L231.661898,37.996876C235.461674,42.441154,241.016041,45,246.863251,45L467.13675,45C472.98395,45,478.53833,42.441154,482.3381,37.996877999999995L502,15L212,15Z" fill="#E2F1FF" fill-opacity="1"/></g><g><path d="M0,15L714,15L714,10.000001C714,4.4771528,709.52283,0,704,0L10.000001,0C4.4771528,0,0,4.4771528,0,10.000001L0,15Z" fill="#E2F1FF" fill-opacity="1"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 941 B

View File

@ -1,123 +0,0 @@
.progress_title {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 0 8px 0;
font-size: 16px;
font-weight: 500;
color: #3d3d3d;
&_number {
color: #666;
font-size: 20px;
}
}
.review_information {
display: flex;
align-items: center;
justify-content: space-between;
img {
width: 62px;
height: 62px;
}
.info_title {
color: #333;
font-size: 20px;
font-weight: 500;
}
.info_content {
color: #2a7efb;
font-size: 14px;
padding-top: 5px;
}
}
.overview_contract_info_data_card {
height: 100px;
}
.overview_contract_data_card {
height: 950px;
}
/* 平板端 */
@media (min-width: 768px) and (max-width: 1024px) {
.contracts_total_number {
.contracts_total_number_text {
&_title {
font-size: 15px;
padding-top: 8px;
}
&_number {
font-size: 28px;
line-height: 35px;
font-weight: 500;
}
}
}
}
/* 笔记本端 */
@media (min-width: 1025px) and (max-width: 2000px) {
.contracts_total_number {
position: relative;
padding: 15px 0 20px 0;
width: 100%;
img {
width: 100%;
border-radius: 15px;
font-size: 0;
}
.contracts_total_number_text {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
padding: 15px;
&_title {
font-size: 15px;
padding-top: 8px;
}
&_number {
font-size: 28px;
line-height: 35px;
font-weight: 500;
color: #2a7efb;
}
}
}
}
/* 台式机大屏幕 */
@media (min-width: 2001px) {
.contracts_total_number {
position: relative;
padding: 10px 0;
width: 100%;
img {
width: 100%;
border-radius: 15px;
font-size: 0;
}
.contracts_total_number_text {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
padding: 15px;
&_title {
font-size: 20px;
font-weight: 500;
color: #333;
padding-top: 16px;
}
&_number {
font-size: 36px;
line-height: 50px;
font-weight: 500;
color: #2a7efb;
}
}
}
}

View File

@ -1,99 +0,0 @@
.map_card {
width: 100%;
border-radius: 15px;
position: relative;
overflow: hidden;
}
.map_card_contents {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 4;
.map_card_title_bg {
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 70px;
z-index: 1;
}
.map_data_contents {
position: relative;
z-index: 100;
padding-top: 18px;
}
.map_card_title {
color: #2a7efb;
font-size: 1.8rem;
font-weight: 500;
text-align: center;
}
}
.map_card_data_contents {
position: absolute;
top: 70px;
left: 30px;
z-index: 100;
.map_card_data {
// display: inline-block;
// 换为 2
// justify-content: center;
// flex-wrap: wrap;
// justify-content: space-between;
// align-items: center;
// display: inline-flex;
// text-align: center;
padding-bottom: 20px;
}
.map_card_data_title {
color: #3d3d3d;
font-size: 16px;
font-weight: 500;
color: #0083ff;
display: flex;
align-items: center;
// justify-content: space-between;
span {
padding: 0 10px;
}
}
}
.map_card_data_number {
padding: 10px 0 0 25px;
color: #0083ff;
font-size: 28px;
font-weight: 500;
text-align: center;
}
.others_project {
position: absolute;
right: 1px;
bottom: 10px;
z-index: 100;
.others_project_cell_list {
display: flex;
align-items: center;
cursor: pointer;
background: linear-gradient(
270deg,
rgba(124, 191, 255, 0) 0%,
rgba(217, 236, 255, 0.67) 95%
);
padding: 0 10px 0 0;
border-left: 5px solid #0083ff;
margin-bottom: 20px;
width: 200px;
color: #0083ff;
img {
width: 40px;
height: 40px;
margin: 0 3px;
}
&:hover {
opacity: 0.8;
}
}
}

View File

@ -1,112 +0,0 @@
.ranking_item_content {
width: 100%;
padding: 0 0 32px 0;
}
.overview_ranking_right {
width: 100%;
}
.ranking_item {
display: flex;
align-items: center;
background-color: #f3f8fb;
border-left: 5px solid #2a7efb;
padding: 0 15px;
margin-top: 24px;
height: 73px;
width: 100%;
img {
width: 33px;
height: 40px;
}
.name {
flex: 1;
padding: 0 15px;
font-size: 20px;
font-weight: 500;
color: #3d3d3d;
}
.number {
font-size: 20px;
font-weight: 500;
color: #333;
padding-right: 5px;
}
.ranking_number {
width: 36px;
height: 36px;
border-radius: 5px;
font-size: 20px;
color: #333;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
}
&:first-child {
background-color: #fff8eb;
margin-top: 10px;
border-left: 5px solid #faad14;
.number {
color: #faad14;
}
}
&:nth-child(2) {
background-color: #f3f8fb;
border-left: 5px solid #b7c7d6;
.number {
color: #5f8db8;
}
}
&:nth-child(3) {
background-color: #fff9f4;
border-left: 5px solid #dcb08e;
.number {
color: #d08143;
}
}
}
/* 平板端 */
@media (min-width: 768px) and (max-width: 1024px) {
}
/* 笔记本端 */
@media (min-width: 1025px) and (max-width: 2000px) {
.ranking_item {
padding: 15px;
.name {
font-size: 16px;
}
.number {
font-size: 16px;
}
.ranking_number {
width: 26px;
height: 26px;
font-size: 16px;
}
}
}
/* 台式机大屏幕 */
@media (min-width: 2001px) {
}
// @media (min-width: 1400px) and (max-width: 2000px) {
// .overview_ranking {
// width: 100%;
// }
// .overview_ranking_right {
// display: flex;
// width: 100%;
// align-items: self-start;
// justify-content: space-between;
// }
// }
// @media (max-width: 1400px) {
// .overview_ranking {
// width: 100%;
// }
// }

View File

@ -1,45 +0,0 @@
// import MyModalsMapLeaflet from '@/components/ModalsMapLeaflet';
import { Apis } from '@/gen/Apis';
import { useEffect, useState } from 'react';
import MyMap from './components/MapContents';
import MyOverviewContractData from './components/OverviewContractData';
import MyRanking from './components/Ranking';
import './style.scss';
export default function Index() {
const [overviewData, setOverviewData] = useState<any>({});
const [rankingData, setRankingData] = useState<any>({});
const getFinancialWorkOverview = async () => {
const res =
await Apis.Statistics.IndexCount.FinancialAndWorkOrderOverview();
setOverviewData(res?.data);
const res_s =
await Apis.Statistics.IndexCount.ProjectDistributionAndPaymentRanking();
setRankingData(res_s?.data);
console.log(res, 'res');
};
useEffect(() => {
getFinancialWorkOverview();
}, []);
return (
<div className="overview_content">
<div className="overview_contract_data">
{/* <MyModalsMapLeaflet /> */}
<MyOverviewContractData />
</div>
<div className="overview_map">
<div className="overview_map_content">
<MyMap
item={{ overviewData: overviewData, rankingData: rankingData }}
/>
</div>
<div className="overview_ranking">
<MyRanking
item={{ overviewData: overviewData, rankingData: rankingData }}
/>
</div>
</div>
</div>
);
}

View File

@ -1,70 +0,0 @@
.overview_content {
margin: -20px !important;
margin: 0 auto;
display: flex;
flex-wrap: nowrap;
align-items: flex-start;
}
.overview_map {
flex: 1;
display: flex;
flex-wrap: nowrap;
align-items: flex-start;
}
.overview_contract_data {
margin-right: 10px;
min-width: 280px;
}
.overview_map_content {
flex: 1;
}
.overview_ranking {
margin-left: 10px;
min-width: 280px;
}
.border_radius_15px {
border-radius: 15px;
}
/* 平板端 */
@media (min-width: 768px) and (max-width: 1024px) {
}
/* 笔记本端 */
@media (min-width: 1025px) and (max-width: 2000px) {
.overview_contract_data {
width: 28%;
}
.overview_ranking {
width: 32%;
}
}
/* 台式机大屏幕 */
@media (min-width: 2001px) {
.overview_contract_data {
width: 380px;
margin-right: 20px;
}
.overview_ranking {
width: 430px;
margin-left: 20px;
}
}
// @media (min-width: 1400px) and (max-width: 2000px) {
// .overview_content {
// width: 100%;
// margin: 0 auto;
// flex-wrap: wrap;
// }
// }
// @media (max-width: 1400px) {
// .overview_content {
// flex-wrap: wrap;
// width: 100%;
// margin: 0 auto;
// }
// }

View File

@ -1,24 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { Column } from '@ant-design/plots';
import { useEffect, useState } from 'react';
export default function AnalysisClient(props: MyBetaModalFormProps) {
const [configData, setConfigData] = useState({});
const config = {
data: [],
xField: '月份',
yField: '数量',
group: true,
style: {
// 矩形四个方向的内边距
inset: 3,
},
};
useEffect(() => {
setConfigData({ ...config, data: props?.item?.chart || [] });
}, [props?.item?.chart]);
return (
<div style={{ height: 303 }}>
<Column {...configData} />
</div>
);
}

View File

@ -1,155 +0,0 @@
export const workChartsData = [
{
name: '物业费',
: '1月',
数量: 70,
},
{
name: '工单',
: '1月',
数量: 20,
},
{
name: '停车费',
: '2月',
数量: 10,
},
{
name: '物业费',
: '2月',
数量: 80,
},
{
name: '工单',
: '2月',
数量: 40,
},
{
name: '停车费',
: '2月',
数量: 6,
},
{
name: '物业费',
: '3月',
数量: 67,
},
{
name: '工单',
: '3月',
数量: 27,
},
{
name: '停车费',
: '3月',
数量: 7,
},
{
name: '物业费',
: '4月',
数量: 55,
},
{
name: '工单',
: '4月',
数量: 17,
},
{
name: '停车费',
: '4月',
数量: 9,
},
{
name: '物业费',
: '5月',
数量: 32,
},
{
name: '工单',
: '5月',
数量: 27,
},
{
name: '停车费',
: '5月',
数量: 11,
},
{
name: '物业费',
: '6月',
数量: 42,
},
{
name: '工单',
: '6月',
数量: 7,
},
{
name: '停车费',
: '6月',
数量: 21,
},
];
export const FinanceClientData = [
{
name: '应收',
: '1月',
数量: 200,
},
{
name: '实收',
: '1月',
数量: 210,
},
{
name: '应收',
: '2月',
数量: 170,
},
{
name: '实收',
: '2月',
数量: 200,
},
{
name: '应收',
: '3月',
数量: 270,
},
{
name: '实收',
: '3月',
数量: 310,
},
{
name: '应收',
: '4月',
数量: 230,
},
{
name: '实收',
: '4月',
数量: 190,
},
{
name: '应收',
: '5月',
数量: 170,
},
{
name: '实收',
: '5月',
数量: 160,
},
{
name: '应收',
: '6月',
数量: 250,
},
{
name: '实收',
: '6月',
数量: 280,
},
];

View File

@ -1,91 +0,0 @@
import { Apis } from '@/gen/Apis';
import { Pie } from '@ant-design/plots';
import { Space } from 'antd';
import { useEffect, useState } from 'react';
export default function FinancialAnalysisLine() {
const [getPieCount, setPieCount] = useState<any>({});
const config = {
data: [],
angleField: '数量',
colorField: 'name',
innerRadius: 0.8,
radius: 0.5,
style: {
width: '60px',
},
label: {
text: '数量',
style: {
fontWeight: 'bold',
},
},
};
const getPieData = async () => {
const res = await Apis.Statistics.IndexCount.ContractStatistics();
setPieCount({
...config,
data: res?.data?.items,
legend: {
color: {
render: (legendItem: any, item: any) => {
console.log(legendItem, item, 'legendItem');
// 这里可以返回 React 节点或 HTML 字符串
return (
<Space size="small">
{legendItem?.map((row: any, index: number) => {
return (
<Space key={`item_${index}`}>
<div
style={{
width: 8,
height: 8,
backgroundColor: row?.color,
borderRadius: 100,
fontSize: 12,
}}
/>
{row?.label}
{
res?.data?.items?.find(
(i: any) => i.name === row?.label,
)?.
}
</Space>
);
})}
</Space>
);
},
title: false,
position: 'top',
rowPadding: 5,
},
},
annotations: [
{
type: 'text',
style: {
text: `${res?.data?.total}\n合同总数`,
x: '50%',
y: '50%',
textAlign: 'center',
fontSize: 20,
fontStyle: 'bold',
},
},
],
});
console.log(res, 'res');
};
useEffect(() => {
getPieData();
}, []);
return (
<div style={{ height: 430 }}>
<Pie {...getPieCount} />
</div>
);
}

View File

@ -1,50 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { Line } from '@ant-design/plots';
import { useEffect, useState } from 'react';
export default function FinancialAnalysisLine(props: MyBetaModalFormProps) {
const [houseBillsCount, setHouseBillsCount] = useState<any>({});
const config = {
data: [],
xField: '月份',
yField: '金额',
colorField: 'name',
point: {
size: 7,
},
legend: {
position: 'top',
},
tooltip: {},
style: {
// 矩形四个方向的内边距
inset: 5,
},
// 使用双Y轴因为两个指标数值范围差异大
yAxis: [
{
title: {
text: '月收款(万元)',
},
},
{
title: {
text: '收缴率(%)',
},
grid: null,
},
],
};
useEffect(() => {
if (props?.item?.chart?.length) {
setHouseBillsCount({ ...config, data: props?.item?.chart || [] });
}
}, [props?.item?.chart]);
return (
<div style={{ height: 290 }}>
<Line {...houseBillsCount} />
</div>
);
}

View File

@ -1,93 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { Pie } from '@ant-design/plots';
import { Space } from 'antd';
import { useEffect, useState } from 'react';
export default function WorkOrderPie(props: MyBetaModalFormProps) {
const [getPieCount, setPieCount] = useState<any>({});
const config = {
data: [],
angleField: '数量',
colorField: 'name',
innerRadius: 0.8,
radius: 0.5,
style: {
width: '60px',
},
label: {
text: '数量',
style: {
fontWeight: 'bold',
},
},
};
useEffect(() => {
setPieCount({
...config,
data: props?.item?.statistics?.items,
legend: {
color: {
render: (legendItem: any, item: any) => {
console.log(legendItem, item, 'legendItem');
// 这里可以返回 React 节点或 HTML 字符串
return (
<div
style={{
fontSize: 12,
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
gap: '10px',
}}
>
{legendItem?.map((row: any, index: number) => {
return (
<Space key={`item_${index}`}>
<div
style={{
width: 8,
height: 8,
backgroundColor: row?.color,
borderRadius: 100,
fontSize: 12,
}}
/>
{row?.label}
{
props?.item?.statistics?.items?.find(
(i: any) => i.name === row?.label,
)?.
}
</Space>
);
})}
</div>
);
},
title: false,
position: 'top',
rowPadding: 5,
},
},
annotations: [
{
type: 'text',
style: {
text: `${props?.item?.statistics?.total}\n工单总数`,
x: '50%',
y: '50%',
textAlign: 'center',
fontSize: 20,
fontStyle: 'bold',
},
},
],
});
}, [props?.item?.statistics?.items]);
return (
<div style={{ height: 430 }}>
<Pie {...getPieCount} />
</div>
);
}

File diff suppressed because one or more lines are too long

View File

@ -1,132 +0,0 @@
[
{
"name": "上城区",
"level": "district",
"adcode": 330102,
"lng": 120.19732,
"lat": 30.226543,
"childrenNum": 0,
"parent": 330100,
"value": 41.040194955144216
},
{
"name": "拱墅区",
"level": "district",
"adcode": 330105,
"lng": 120.141503,
"lat": 30.319126,
"childrenNum": 0,
"parent": 330100,
"value": 741.6573303294999
},
{
"name": "西湖区",
"level": "district",
"adcode": 330106,
"lng": 120.130396,
"lat": 30.259242,
"childrenNum": 0,
"parent": 330100,
"value": 2948.4079430920074
},
{
"name": "滨江区",
"level": "district",
"adcode": 330108,
"lng": 120.211981,
"lat": 30.208332,
"childrenNum": 0,
"parent": 330100,
"value": 49.89546143372991
},
{
"name": "萧山区",
"level": "district",
"adcode": 330109,
"lng": 120.264263,
"lat": 30.184119,
"childrenNum": 0,
"parent": 330100,
"value": 2384.034354262634
},
{
"name": "余杭区",
"level": "district",
"adcode": 330110,
"lng": 119.978742,
"lat": 30.273705,
"childrenNum": 0,
"parent": 330100,
"value": 1882.4494466789638
},
{
"name": "富阳区",
"level": "district",
"adcode": 330111,
"lng": 119.96022,
"lat": 30.048803,
"childrenNum": 0,
"parent": 330100,
"value": 560.1787727190821
},
{
"name": "临安区",
"level": "district",
"adcode": 330112,
"lng": 119.724457,
"lat": 30.234375,
"childrenNum": 0,
"parent": 330100,
"value": 4051.1361966943305
},
{
"name": "临平区",
"level": "district",
"adcode": 330113,
"lng": 120.299222,
"lat": 30.419154,
"childrenNum": 0,
"parent": 330100,
"value": 4071.9384042194924
},
{
"name": "钱塘区",
"level": "district",
"adcode": 330114,
"lng": 120.493941,
"lat": 30.32304,
"childrenNum": 0,
"parent": 330100,
"value": 1813.6359839537997
},
{
"name": "桐庐县",
"level": "district",
"adcode": 330122,
"lng": 119.691755,
"lat": 29.79418,
"childrenNum": 0,
"parent": 330100,
"value": 2089.953961851202
},
{
"name": "淳安县",
"level": "district",
"adcode": 330127,
"lng": 119.042015,
"lat": 29.609678,
"childrenNum": 0,
"parent": 330100,
"value": 978.0639544756548
},
{
"name": "建德市",
"level": "district",
"adcode": 330182,
"lng": 119.281195,
"lat": 29.474964,
"childrenNum": 0,
"parent": 330100,
"value": 4427.419741967931
}
]

View File

@ -1,60 +0,0 @@
import { Apis } from '@/gen/Apis';
import { RightOutlined } from '@ant-design/icons';
import { useNavigate } from '@umijs/max';
import { Space } from 'antd';
import { useEffect, useState } from 'react';
import AnalysisClient from '../charts/AnalysisClient';
export default function AssetManagementAnalysis() {
const navigate = useNavigate();
const [getAssetAnalysis, setAssetAnalysis] = useState<any>({});
const getAssetAnalysisApi = async () => {
const res = await Apis.Statistics.IndexCount.AssetAnalysis();
setAssetAnalysis(res?.data);
console.log(res, 'res');
};
useEffect(() => {
getAssetAnalysisApi();
}, []);
return (
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
<div className="asset_management_analysis_data">
<div
style={{ cursor: 'pointer' }}
onClick={() => {
navigate('/asset/asset_items');
}}
>
<div className="label">
<RightOutlined />
</div>
<div className="value">{getAssetAnalysis?.total || 0}</div>
</div>
<div
style={{ cursor: 'pointer' }}
onClick={() => {
navigate('/asset/asset_items');
}}
>
<div className="label">
<RightOutlined />
</div>
<div className="value">{getAssetAnalysis?.total_price || 0}</div>
</div>
<div
style={{ cursor: 'pointer' }}
onClick={() => {
navigate('/asset/asset_items');
}}
>
<div className="label">
<RightOutlined />
</div>
<div className="value">{getAssetAnalysis?.idle_count || 0}</div>
</div>
</div>
<AnalysisClient item={getAssetAnalysis} />
</Space>
);
}

View File

@ -1,82 +0,0 @@
import { Apis } from '@/gen/Apis';
import { ProCard } from '@ant-design/pro-components';
import { Space } from 'antd';
import { useEffect, useState } from 'react';
import AssetManagementAnalysis from './AssetManagementAnalysis';
import ImgLeftIcon from './images/LeftIcon.png';
import ImgMapTitleBg from './images/map_title_bg_img.svg';
import MapAntL7 from './MapAntL7';
import './styleCenter.scss';
import './styleMap.scss';
export default function CardCenter() {
const [loginStatus, setLoginStatus] = useState<boolean>(false);
const [dataInfo, setDataInfo] = useState<any>({});
const getProjectDistributionAndPaymentRanking = async () => {
const res =
await Apis.Statistics.IndexCount.ProjectDistributionAndPaymentRanking();
setLoginStatus(true);
setDataInfo(res?.data);
};
useEffect(() => {
getProjectDistributionAndPaymentRanking();
}, []);
return (
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
<div className="map_card">
{loginStatus ? <MapAntL7 item={dataInfo} /> : ''}
<div className="map_card_contents">
<img src={ImgMapTitleBg} className="map_card_title_bg" />
<div className="map_data_contents">
<div className="map_card_title"></div>
</div>
</div>
<div className="map_card_data_contents">
<div className="map_card_data">
<div>
<div className="map_card_data_title">
<img src={ImgLeftIcon} />
<span></span>
{/* <img src={ImgRightIcon} /> */}
</div>
<div className="map_card_data_number">
{dataInfo?.total_users || 0}
</div>
</div>
</div>
<div className="map_card_data">
<div>
<div className="map_card_data_title">
<img src={ImgLeftIcon} />
<span></span>
{/* <img src={ImgRightIcon} /> */}
</div>
<div className="map_card_data_number">
{dataInfo?.total_occupants || 0}
</div>
</div>
</div>
</div>
{/* <div className="others_project">
<div className="others_project_cell_list">
<img src={AddressIcon} alt="" />
<div>3</div>
</div>
<div className="others_project_cell_list">
<img src={AddressIcon} alt="" />
<div>3</div>
</div>
<div className="others_project_cell_list">
<img src={AddressIcon} alt="" />
<div>8</div>
</div>
</div> */}
</div>
<ProCard title="资产管理分析" style={{ borderRadius: '10px' }}>
<AssetManagementAnalysis />
</ProCard>
</Space>
);
}

View File

@ -1,34 +0,0 @@
import { Apis } from '@/gen/Apis';
import { ProCard } from '@ant-design/pro-components';
import { Space } from 'antd';
import { useEffect, useState } from 'react';
import ContractStatisticalAnalysis from '../charts/ContractStatisticalAnalysis';
import FinancialAnalysisLine from '../charts/FinancialAnalysisLine';
import FinancialAnalysis from './FinancialAnalysis';
import './styleLeft.scss';
export default function CardLeft() {
const [getFinancialAnalysis, setFinancialAnalysis] = useState<any>({});
const getFinancialWorkOverview = async () => {
const res = await Apis.Statistics.IndexCount.FinancialAnalysis();
setFinancialAnalysis(res?.data);
console.log(res, 'res');
};
useEffect(() => {
getFinancialWorkOverview();
}, []);
return (
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
<ProCard title="财务分析">
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
<FinancialAnalysis item={getFinancialAnalysis} />
<FinancialAnalysisLine item={getFinancialAnalysis} />
</Space>
</ProCard>
<ProCard title="合同统计分析">
<ContractStatisticalAnalysis />
</ProCard>
</Space>
);
}

View File

@ -1,77 +0,0 @@
import { Apis } from '@/gen/Apis';
import { ProCard } from '@ant-design/pro-components';
import { Progress, Space } from 'antd';
import { useEffect, useState } from 'react';
import WorkOrderPie from '../charts/WorkOrderPie';
import PendingApplicationForm from './PendingApplicationForm';
import './styleRight.scss';
export default function CardRight() {
const [getAssetAnalysis, setAssetAnalysis] = useState<any>({});
const getAssetAnalysisApi = async () => {
const res = await Apis.Statistics.IndexCount.WorkOrderAnalysis();
setAssetAnalysis(res);
console.log(res, 'res');
};
useEffect(() => {
getAssetAnalysisApi();
}, []);
return (
<div className="card_right">
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
<ProCard title="工单分析">
<PendingApplicationForm item={getAssetAnalysis?.data} />
</ProCard>
<ProCard title="工单统计">
<WorkOrderPie item={getAssetAnalysis} />
</ProCard>
<ProCard title="工单数据">
<div className="work_order_data">
<div className="work_order_data_item">
<Progress
type="dashboard"
size={[160, 30]}
percent={getAssetAnalysis?.data?.metrics?.completion_rate || 0}
format={(percent) => {
return (
<div className="dashboard_progress">
<div className="dashboard_value">{`${percent}%`}</div>
<div className="dashboard_label"></div>
</div>
);
}}
/>
<div className="work_order_data_cell">
{getAssetAnalysis?.data?.metrics?.completed_count || 0}
</div>
<div className="work_order_data_cell">
{getAssetAnalysis?.data?.metrics?.closed_count || 0}
</div>
</div>
<div className="work_order_data_item">
<Progress
type="dashboard"
size={[160, 30]}
percent={getAssetAnalysis?.data?.metrics?.approval_rate || 0}
format={(percent) => {
return (
<div className="dashboard_progress">
<div className="dashboard_value">{`${percent}%`}</div>
<div className="dashboard_label"></div>
</div>
);
}}
/>
<div className="work_order_data_cell">
{getAssetAnalysis?.data?.metrics?.evaluated_count || 0}
</div>
<div className="work_order_data_cell">
{getAssetAnalysis?.data?.metrics?.positive_count || 0}
</div>
</div>
</div>
</ProCard>
</Space>
</div>
);
}

View File

@ -1,36 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
export default function FinancialAnalysis(props: MyBetaModalFormProps) {
return (
<div className="financial_analysis">
<div className="financial_analysis_item">
<div className="value">
{props?.item?.month_received || '0'}
<span></span>
</div>
<div className="title"></div>
</div>
<div className="financial_analysis_item">
<div className="value">
{props?.item?.year_received || '0'}
<span></span>
</div>
<div className="title"></div>
</div>
<div className="financial_analysis_item">
<div className="value">
{props?.item?.month_rate || '0'}
<span>%</span>
</div>
<div className="title"></div>
</div>
<div className="financial_analysis_item">
<div className="value">
{props?.item?.year_rate || '0'}
<span>%</span>
</div>
<div className="title"></div>
</div>
</div>
);
}

View File

@ -1,129 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { Scene } from '@antv/l7';
import { L7Layer } from '@antv/l7-leaflet';
import { Choropleth } from '@antv/l7plot';
import * as L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { useEffect, useRef } from 'react';
import ListArea from './AreaInfoList.json';
import map_bg_img from './images/map_bg_img.png';
export default function MapInfo(props: MyBetaModalFormProps) {
const sceneRef = useRef<Scene>();
const getProjectDistributionAndPaymentRanking = async () => {
let dataJson: any = [];
console.log(props?.item?.area_stats, 'props?.item?.area_stats');
props?.item?.area_stats?.map((item: any) => {
ListArea?.map((i: any) => {
if (i?.name === item?.name) {
dataJson?.push({
...i,
name: `${i?.name}(${item?.value}个)`,
: `${item?.value}个项目`,
: i?.name,
});
console.log(i, 'i');
}
});
});
console.log(dataJson, 'skkskck');
return dataJson;
};
useEffect(() => {
if (sceneRef.current) {
return;
}
// 初始化地图场景
const map = L.map('map', {
center: [29.909571, 119.600006],
zoom: 10,
minZoom: 9,
maxZoom: 10,
zoomControl: false,
attributionControl: false,
}).setView([29.909571, 119.600006], 9);
const l7layer = new L7Layer({
logoVisible: false,
}).addTo(map);
const scene: any = l7layer.getScene();
sceneRef.current = scene;
scene.on('loaded', async () => {
let dataAreaJson = await getProjectDistributionAndPaymentRanking();
console.log(dataAreaJson, 'dataAreaJson');
const choropleth = new Choropleth({
chinaBorder: false,
source: {
data: dataAreaJson || [],
joinBy: {
sourceField: 'adcode',
geoField: 'adcode',
},
},
viewLevel: {
level: 'city',
adcode: 330100,
},
autoFit: true,
style: {
opacity: 1,
stroke: '#0083FF',
lineWidth: 1,
lineOpacity: 1,
},
label: {
field: 'name',
style: {
fill: '#000',
opacity: 1,
fontSize: 15,
strokeWidth: 1.5,
},
},
tooltip: {
items: ['区', '数量'],
},
state: {
active: { stroke: '#0083FF', lineWidth: 1, fill: '#E4F2FF' },
},
});
choropleth.addToScene(scene);
});
scene.on('resize', () => {
console.log('resize');
});
// 组件卸载时清理
return () => {
if (sceneRef.current) {
sceneRef.current.destroy();
}
};
}, [props?.item]);
return (
<div
style={{
width: '100%',
height: '594px',
position: 'relative',
zIndex: 1,
backgroundColor: '#fff',
}}
>
<div
id="map"
style={{
width: '100%',
height: '594px',
background: `url(${map_bg_img}) no-repeat bottom`,
backgroundSize: '100%',
}}
></div>
</div>
);
}

View File

@ -1,86 +0,0 @@
import { MyBetaModalFormProps } from '@/common';
import { RightOutlined } from '@ant-design/icons';
import { useNavigate } from '@umijs/max';
export default function PendingApplicationForm(props: MyBetaModalFormProps) {
const navigate = useNavigate();
return (
<div className="pending_application_form">
<div className="pending_application_form_title"></div>
<div className="pending_application_form_container">
<div className="pending_application_form_item">
<div
className="label"
onClick={() => {
navigate('/emergency');
}}
>
<RightOutlined />
</div>
<div className="value">{props?.item?.pending?.emergency || 0}</div>
</div>
<div className="pending_application_form_item">
<div
className="label"
onClick={() => {
navigate('/work_order/list');
}}
>
<RightOutlined />
</div>
<div className="value">{props?.item?.pending?.repair || 0}</div>
</div>
<div className="pending_application_form_item">
<div
className="label"
onClick={() => {
navigate('/work_order/list');
}}
>
<RightOutlined />
</div>
<div className="value">{props?.item?.pending?.incident || 0}</div>
</div>
<div className="pending_application_form_item">
<div
className="label"
onClick={() => {
navigate('/work_order/list');
}}
>
<RightOutlined />
</div>
<div className="value">{props?.item?.pending?.complaint || 0}</div>
</div>
<div className="pending_application_form_item">
<div
className="label"
onClick={() => {
navigate('/attendance/attendance_schedules');
}}
>
<RightOutlined />
</div>
<div className="value">{props?.item?.pending?.inspection || 0}</div>
</div>
<div className="pending_application_form_item">
<div
className="label"
onClick={() => {
navigate('/asset/asset_items_maintenances');
}}
>
<RightOutlined />
</div>
<div className="value">{props?.item?.pending?.maintenance || 0}</div>
</div>
</div>
</div>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="714" height="47" viewBox="0 0 714 47"><g><g><g><path d="M212,17L231.661898,39.996876C235.461674,44.441154,241.016041,47,246.863251,47L467.13675,47C472.98395,47,478.53833,44.441154,482.3381,39.996877999999995L502,17L212,17Z" fill="#2A7EFB" fill-opacity="1"/></g><g><path d="M0,17L714,17L714,12.000001C714,6.4771528,709.52283,2,704,2L10.000001,2C4.4771528,2,0,6.4771528,0,12.000001L0,17Z" fill="#2A7EFB" fill-opacity="1"/></g></g><g><g><path d="M212,15L231.661898,37.996876C235.461674,42.441154,241.016041,45,246.863251,45L467.13675,45C472.98395,45,478.53833,42.441154,482.3381,37.996877999999995L502,15L212,15Z" fill="#E2F1FF" fill-opacity="1"/></g><g><path d="M0,15L714,15L714,10.000001C714,4.4771528,709.52283,0,704,0L10.000001,0C4.4771528,0,0,4.4771528,0,10.000001L0,15Z" fill="#E2F1FF" fill-opacity="1"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 941 B

View File

@ -1,19 +0,0 @@
.asset_management_analysis_data {
background-color: #f3f8fb;
border-radius: 10px;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 15px;
.label {
font-size: 14px;
font-weight: 400;
color: #666666;
}
.value {
color: #333333;
font-size: 30px;
font-weight: 600;
}
}

View File

@ -1,28 +0,0 @@
.financial_analysis {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 15px;
&_item {
color: #fff;
background: linear-gradient(134deg, #6499ff 34%, #95b8ff 100%);
border-radius: 10px;
text-align: center;
width: 48%;
height: 100px;
.value {
font-size: 24px;
font-weight: 500;
padding-top: 17px;
span {
font-size: 12px;
font-weight: 400;
}
}
.title {
font-size: 12px;
font-weight: 400;
}
}
}

View File

@ -1,102 +0,0 @@
.map_card {
width: 100%;
border-radius: 15px;
position: relative;
overflow: hidden;
}
.map_card_contents {
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 4;
.map_card_title_bg {
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 70px;
z-index: 1;
}
.map_data_contents {
position: relative;
z-index: 100;
padding-top: 18px;
}
.map_card_title {
color: #2a7efb;
font-size: 1.8rem;
font-weight: 500;
text-align: center;
}
}
.map_card_data_contents {
position: absolute;
top: 70px;
left: 30px;
z-index: 100;
display: flex;
right: 30px;
justify-content: space-between;
.map_card_data {
// display: inline-block;
// 换为 2
// justify-content: center;
// flex-wrap: wrap;
// justify-content: space-between;
// align-items: center;
// display: inline-flex;
// text-align: center;
padding-bottom: 20px;
}
.map_card_data_title {
color: #3d3d3d;
font-size: 16px;
font-weight: 500;
color: #0083ff;
display: flex;
align-items: center;
// justify-content: space-between;
span {
padding: 0 10px;
}
}
}
.map_card_data_number {
padding: 10px 0 0 25px;
color: #0083ff;
font-size: 28px;
font-weight: 500;
text-align: center;
}
.others_project {
position: absolute;
right: 1px;
bottom: 10px;
z-index: 100;
.others_project_cell_list {
display: flex;
align-items: center;
cursor: pointer;
background: linear-gradient(
270deg,
rgba(124, 191, 255, 0) 0%,
rgba(217, 236, 255, 0.67) 95%
);
padding: 0 10px 0 0;
border-left: 5px solid #0083ff;
margin-bottom: 20px;
width: 200px;
color: #0083ff;
img {
width: 40px;
height: 40px;
margin: 0 3px;
}
&:hover {
opacity: 0.8;
}
}
}

View File

@ -1,67 +0,0 @@
.card_right {
background-color: #fff;
}
.pending_application_form {
background-color: #f3faff;
border-radius: 10px;
&_title {
font-size: 18px;
font-weight: 600;
padding: 15px 20px;
}
&_container {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
padding: 0 30px;
}
&_item {
width: 33.333%;
padding-bottom: 10px;
.label {
color: #666666;
font-size: 14px;
line-height: 12px;
cursor: pointer;
}
.value {
color: #333333;
font-size: 27px;
font-weight: 550;
}
}
}
.work_order_data {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 10px;
&_item {
width: 50%;
text-align: center;
color: #3d3d3d;
font-size: 16rpx;
}
&_cell {
padding-top: 10px;
}
}
.dashboard_progress {
width: 100%;
position: relative;
text-align: center;
// padding-top: 100px;
.dashboard_label {
font-size: 16px;
color: #3d3d3d;
width: 100%;
position: relative;
top: 50px;
}
.dashboard_value {
width: 100%;
}
}

View File

@ -1,20 +1,5 @@
// import MyModalsMapLeaflet from '@/components/ModalsMapLeaflet'; // import MyModalsMapLeaflet from '@/components/ModalsMapLeaflet';
import CardCenter from './components/CardCenter';
import CardLeft from './components/CardLeft';
import CardRight from './components/CardRight';
import './style.scss'; import './style.scss';
export default function Index() { export default function Index() {
return ( return <div className="overview_content">2</div>;
<div className="overview_content">
<div className="overview_left">
<CardLeft />
</div>
<div className="overview_center">
<CardCenter />
</div>
<div className="overview_right">
<CardRight />
</div>
</div>
);
} }

View File

@ -5,14 +5,14 @@ export default function Login() {
<div> <div>
<MyLoginPage /> <MyLoginPage />
<div className="filing_info"> <div className="filing_info">
|{' '} XXXX有限公司 |
<a <a
href="https://beian.miit.gov.cn/#/Integrated/index" href="https://beian.miit.gov.cn/#/Integrated/index"
target="_blank" target="_blank"
key="icp" key="icp"
rel="noreferrer" rel="noreferrer"
> >
ICP备2025210789-3 ICP备2025210-3
</a> </a>
</div> </div>
</div> </div>

View File

@ -1,27 +1,17 @@
import { import { MyPageContainer, MyProTableProps } from '@/common';
MyButtons,
MyColumns,
MyPageContainer,
MyProTableProps,
} from '@/common';
import { Apis } from '@/gen/Apis'; import { Apis } from '@/gen/Apis';
import { SysPermissionsTypeEnum } from '@/gen/Enums';
import { DownOutlined, UpOutlined } from '@ant-design/icons';
import { ActionType, ProTable } from '@ant-design/pro-components'; import { ActionType, ProTable } from '@ant-design/pro-components';
import { Button, Space, Tag } from 'antd';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import Create from './modals/Create';
import Update from './modals/Update';
export default function Index({ title = '功能' }) { export default function Index({ title = '功能' }) {
const [data, setData] = useState<any>([]); const [data, setData] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(false);
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const [guardName] = useState<string>('Admin'); const [guardName] = useState<string>('Admin');
const getData = async () => { const getData = async () => {
let data = await Apis.Permission.SysPermissions.List({ let data = await Apis.Permission.Roles.PermissionTree();
guard_name: guardName, setLoading(true);
});
setData(data.data); setData(data.data);
}; };
@ -38,19 +28,11 @@ export default function Index({ title = '功能' }) {
actionRef={actionRef} actionRef={actionRef}
headerTitle="功能管理" headerTitle="功能管理"
expandable={{ expandable={{
// defaultExpandAllRows: true, defaultExpandAllRows: true,
defaultExpandedRowKeys: [1], // defaultExpandedRowKeys: [1],
}} }}
options={false} options={false}
dataSource={data} dataSource={data}
toolBarRender={() => [
<Create
key="Create"
reload={getData}
title={title}
guardName={guardName}
/>,
]}
columns={[ columns={[
{ {
title: '名称', title: '名称',
@ -58,88 +40,7 @@ export default function Index({ title = '功能' }) {
return `${record.id}_${record?.name}`; return `${record.id}_${record?.name}`;
}, },
}, },
{ title: 'icon', dataIndex: 'icon' },
MyColumns.EnumTag({
title: '类型',
dataIndex: 'type',
valueEnum: SysPermissionsTypeEnum,
}),
{ title: '链接', dataIndex: 'path' },
// { title: '前端表示', dataIndex: 'key' }, // { title: '前端表示', dataIndex: 'key' },
{
title: '后端API',
dataIndex: 'backend_apis',
render: (_, item) => {
return (
<Space direction="vertical">
{item.backend_apis?.map((item: string) => (
<Tag key={item}>{item}</Tag>
))}
</Space>
);
},
},
MyColumns.Option({
render: (_, item: any, index) => (
<Space key={index}>
<Button
size="small"
key={`up_${item.id}`}
icon={<UpOutlined />}
disabled={!item.parent_id}
onClick={() => {
Apis.Permission.SysPermissions.Move({
id: item.id,
type: 'up',
}).then(() => {
getData();
});
}}
/>
<Button
size="small"
icon={<DownOutlined />}
key={`down_${item.id}`}
disabled={!item.parent_id}
onClick={() => {
Apis.Permission.SysPermissions.Move({
id: item.id,
type: 'down',
}).then(() => {
getData();
});
}}
></Button>
<Create
reload={getData}
title={title}
item={item}
key={`create_sub_${item.id}`}
guardName={guardName}
buttonProps={{
size: 'small',
title: '添加下级功能',
type: 'link',
}}
/>
<Update
item={item}
reload={getData}
title={title}
key={`update_${item.id}`}
guardName={guardName}
/>
<MyButtons.Delete
key={`delete_${item.id}`}
onConfirm={() =>
Apis.Permission.SysPermissions.Delete({ id: item.id }).then(
() => getData(),
)
}
/>
</Space>
),
}),
]} ]}
/> />
); );
@ -152,7 +53,7 @@ export default function Index({ title = '功能' }) {
tabKey="system-permissions" tabKey="system-permissions"
tabLabel={title} tabLabel={title}
> >
<ShowTable /> {loading ? <ShowTable /> : null}
</MyPageContainer> </MyPageContainer>
); );
} }

View File

@ -1,4 +1,9 @@
import { MyButtons, MyPageContainer, MyProTableProps } from '@/common'; import {
MyButtons,
MyPageContainer,
MyProTableProps,
useCurrentPermissions,
} from '@/common';
import { flattenToMultiLevelFormatWithRowSpanAdvancedNew } from '@/common/utils/flattenIterative'; import { flattenToMultiLevelFormatWithRowSpanAdvancedNew } from '@/common/utils/flattenIterative';
import { Apis } from '@/gen/Apis'; import { Apis } from '@/gen/Apis';
import { ProCard, ProTable } from '@ant-design/pro-components'; import { ProCard, ProTable } from '@ant-design/pro-components';
@ -10,6 +15,7 @@ interface SelectedBuilding {
name: string; name: string;
} }
export default function Index({ title = '角色' }) { export default function Index({ title = '角色' }) {
const getCurrentPermissions = useCurrentPermissions();
const [selectedBuilding, setSelectedBuilding] = const [selectedBuilding, setSelectedBuilding] =
useState<SelectedBuilding | null>(null); useState<SelectedBuilding | null>(null);
const [selectedPermissionsIds, setSelectedPermissionsIds] = useState<any[]>( const [selectedPermissionsIds, setSelectedPermissionsIds] = useState<any[]>(
@ -19,7 +25,7 @@ export default function Index({ title = '角色' }) {
const [dataTabsSource, setDataTabsSource] = useState<any>([]); const [dataTabsSource, setDataTabsSource] = useState<any>([]);
const [tabsKey, setTabsKey] = useState<any>(''); const [tabsKey, setTabsKey] = useState<any>('');
const getSysPermissions = () => { const getSysPermissions = () => {
Apis.Permission.SysPermissions.List({ guard_name: 'Admin' }).then((res) => { Apis.Permission.Roles.PermissionTree().then((res) => {
setDataSource( setDataSource(
flattenToMultiLevelFormatWithRowSpanAdvancedNew( flattenToMultiLevelFormatWithRowSpanAdvancedNew(
res?.data[0]?.children || [], res?.data[0]?.children || [],
@ -31,7 +37,7 @@ export default function Index({ title = '角色' }) {
const onSave = () => { const onSave = () => {
if (selectedPermissionsIds?.length && selectedBuilding?.id) { if (selectedPermissionsIds?.length && selectedBuilding?.id) {
Apis.Permission.SysRoles.SetPermissions({ Apis.Permission.Roles.SetPermissions({
permissions_ids: selectedPermissionsIds, permissions_ids: selectedPermissionsIds,
id: selectedBuilding?.id || 0, id: selectedBuilding?.id || 0,
}).then(() => { }).then(() => {
@ -52,7 +58,7 @@ export default function Index({ title = '角色' }) {
name: selectedRole.name, name: selectedRole.name,
}); });
} }
Apis.Permission.SysRoles.GetPermissions({ Apis.Permission.Roles.GetPermissions({
id: id ?? 0, id: id ?? 0,
}).then((res) => { }).then((res) => {
setSelectedPermissionsIds(res?.data?.permissions_ids || []); setSelectedPermissionsIds(res?.data?.permissions_ids || []);
@ -60,15 +66,15 @@ export default function Index({ title = '角色' }) {
}; };
const getSysRoles = () => { const getSysRoles = () => {
Apis.Permission.SysRoles.List().then((res) => { Apis.Permission.Roles.List().then((res) => {
setDataTabsSource(res?.data || []); setDataTabsSource(res?.data || []);
if (res?.data?.length) { if (res?.data?.length) {
const firstRole = res.data[0]; const firstRole = res?.data[0];
getPermissions(firstRole?.id || 0); getPermissions(firstRole?.id || 0);
// 初始化选中第一个角色 // 初始化选中第一个角色
setSelectedBuilding({ setSelectedBuilding({
id: firstRole.id, id: firstRole?.id,
name: firstRole.name, name: firstRole?.name,
}); });
} }
console.log(res, 'res'); console.log(res, 'res');
@ -77,7 +83,7 @@ export default function Index({ title = '角色' }) {
const onSelect = () => { const onSelect = () => {
//删除角色 //删除角色
Apis.Permission.SysRoles.Delete({ Apis.Permission.Roles.Delete({
id: tabsKey, id: tabsKey,
}).then(() => { }).then(() => {
getSysRoles(); getSysRoles();
@ -88,21 +94,11 @@ export default function Index({ title = '角色' }) {
getSysRoles(); getSysRoles();
getSysPermissions(); getSysPermissions();
}, []); }, []);
return (
<MyPageContainer let toolBarRender = () => {
title={title} return getCurrentPermissions({
enableTabs={true} add: <Create key="Create" reload={() => getSysRoles()} title={title} />,
tabKey="system-roles" delete: (
tabLabel={title}
>
<ProCard
title="权限配置"
style={{ width: '100%' }}
headerBordered
extra={
<Space size="large">
<Space size="small">
<Create key="Create" reload={() => getSysRoles()} title={title} />
<MyButtons.Default <MyButtons.Default
key="delete" key="delete"
size="middle" size="middle"
@ -115,7 +111,8 @@ export default function Index({ title = '角色' }) {
// 如果当前选中角色是管理员,则禁用删除按钮 // 如果当前选中角色是管理员,则禁用删除按钮
disabled={selectedBuilding?.name === '管理员'} disabled={selectedBuilding?.name === '管理员'}
/> />
</Space> ),
save: (
<MyButtons.Default <MyButtons.Default
key="save" key="save"
type="primary" type="primary"
@ -123,8 +120,22 @@ export default function Index({ title = '角色' }) {
title="保存权限" title="保存权限"
onClick={() => onSave()} onClick={() => onSave()}
/> />
</Space> ),
} });
};
return (
<MyPageContainer
title={title}
enableTabs={true}
tabKey="system-roles"
tabLabel={title}
>
<ProCard
title="权限配置"
style={{ width: '100%' }}
headerBordered
extra={<Space size="small">{toolBarRender()}</Space>}
> >
<div style={{ display: 'flex' }}> <div style={{ display: 'flex' }}>
<div style={{ width: '130px' }}> <div style={{ width: '130px' }}>

View File

@ -26,7 +26,7 @@ export default function Create(props: MyBetaModalFormProps) {
} }
}} }}
onFinish={async (values) => onFinish={async (values) =>
Apis.Permission.SysRoles.Store(values) Apis.Permission.Roles.Store(values)
.then(() => { .then(() => {
props.reload?.(); props.reload?.();
message.success(props.title + '成功'); message.success(props.title + '成功');