Compare commits

...

2 Commits

Author SHA1 Message Date
28d9bd28a4 Merge pull request 'fix:仪表部分' (#10) from develop into main
All checks were successful
Build and Push Docker Image / build (push) Successful in 3m28s
Reviewed-on: https://code.juyouwu.cn/pay/pay-admin/pulls/10
2025-09-25 20:21:19 +08:00
uiuJun
6ffc7bb71f fix:仪表部分
All checks were successful
Build and Push Docker Image / build (push) Successful in 3m27s
2025-09-25 20:20:46 +08:00
54 changed files with 2418 additions and 942 deletions

View File

@ -18,6 +18,7 @@ export default defineConfig({
target: 'http://10.39.13.78:8001/',
// target: 'https://test-admin.linyikj.com.cn/',
// target: 'https://admin.linyikj.com.cn/',
// target: 'http://cd69cef8.natappfree.cc/',
changeOrigin: true,
pathRewrite: { '^': '' },

132
src/gen/ApiTypes.d.ts vendored
View File

@ -15,6 +15,7 @@ declare namespace ApiTypes {
"is_enroll"?: boolean; // 是否报名:1 是、0 否
"project_ids"?: string[]; // 项目ID
"content": string; // 内容
"cover_image"?: string[]; // 封面图片
};
type Update = {
"id": number; // id
@ -26,6 +27,7 @@ declare namespace ApiTypes {
"is_enroll"?: boolean; // 是否报名:1 是、0 否
"project_ids"?: string[]; // 项目ID
"content": string; // 内容
"cover_image"?: string[]; // 封面图片
};
type ChangePublishStatus = {
"id": number; // id
@ -470,9 +472,14 @@ declare namespace ApiTypes {
namespace Bill {
namespace HouseBills {
type List = {
"asset_houses_id"?: number; // 资产房屋id,[ref:asset_houses]
"full_name"?: string; // 模糊搜索:房屋名称
"company_name"?: string; // 模糊搜索:公司名称
};
type SummaryBillList = {
"full_name"?: string; // 模糊搜索:房屋名称
"asset_houses_id"?: number; // 资产房屋id,[ref:asset_houses]
};
type Store = {
"asset_houses_id": number; // 资产房屋id,[ref:asset_houses]
"company_receipt_accounts_id": number; // 公司收款账户id,[ref:company_receipt_accounts]
@ -1278,6 +1285,131 @@ declare namespace ApiTypes {
};
}
}
namespace Meter {
namespace HouseMeterHasHouses {
type List = {
"house_meters_id"?: number; // 房屋仪表id,[ref:house_meters]
"name"?: string; // 模糊搜索:名称
"full_name"?: string; // 模糊搜索:房屋全称
};
type StoreOrUpdate = {
"house_meters_id": number; // 房屋仪表id,[ref:house_meters]
"asset_houses_ids": string[]; // 房屋id,[ref:asset_houses]
};
type Show = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
namespace HouseMeterReadings {
type List = {
"name"?: string; // 模糊搜索:名称
};
type Store = {
"house_meters_id": number; // 仪表id,[ref:house_meters]
"operation_type": string; // 操作类型,[enum:HouseMeterReadingsOperationTypeEnum]
"current_reading": number; // 本次读数
"reading_time": Date; // 抄表时间
"company_employees_id": number; // 抄表人id,[ref:company_employees]
"remark": string; // 备注
};
type Update = {
"id": number; // id
"house_meters_id": number; // 仪表id,[ref:house_meters]
"operation_type": string; // 操作类型,[enum:HouseMeterReadingsOperationTypeEnum]
"previous_reading": number; // 上次读数
"current_reading": number; // 本次读数
"usage_amount": number; // 用量
"loss_amount"?: number; // 损耗
"reading_time": Date; // 抄表时间
"company_employees_id": number; // 抄表人id,[ref:company_employees]
"remark": string; // 备注
};
type Show = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
namespace HouseMeterTasks {
type List = {
"name"?: string; // 模糊搜索:名称
};
type Store = {
"asset_projects_id": number; // 资产项目id,[ref:asset_projects]
"generation_method": string; // 生成方式,[enum:HouseMeterTasksGenerationMethodEnum]
"month": string; // 月份
"start_date": Date; // 收费开始日期
"end_date": Date; // 收费截止日期
"data": string[]; // 任务数据(如果是楼栋则是楼栋ID,如果是单元则是单元ID,如果是仪表则是仪表ID)
};
type Show = {
"id": number; // id
};
type SoftDelete = {
"id": number; // id
};
type Restore = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
namespace HouseMeters {
type List = {
"name"?: string; // 模糊搜索:名称
"asset_projects_id"?: number; // 项目id,[ref:asset_projects]
"project_name"?: string; // 模糊搜索:项目名称
};
type Store = {
"asset_projects_id": number; // 项目id,[ref:asset_projects]
"charge_standards_id"?: number; // 房屋收费标准id,[ref:house_charge_standards]
"companies_id": number; // 机构id,[ref:companies]
"name": string; // 名称
"meter_type": string; // 仪表类型,[enum:HouseMetersMeterTypeEnum]
"usage_type": string; // 使用类型,[enum:HouseMetersUsageTypeEnum]
"multiple"?: number; // 倍率
"status"?: number; // 是否启用:0:禁用,1:启用
"initial_value"?: number; // 初始抄表读数
"initial_time"?: Date; // 初始抄表时间
"latest_value"?: number; // 最新抄表读数
"latest_time"?: Date; // 最新抄表时间
"remark"?: string; // 备注
};
type Update = {
"id": number; // id
"asset_projects_id": number; // 项目id,[ref:asset_projects]
"charge_standards_id"?: number; // 房屋收费标准id,[ref:house_charge_standards]
"companies_id": number; // 机构id,[ref:companies]
"name": string; // 名称
"meter_type": string; // 仪表类型,[enum:HouseMetersMeterTypeEnum]
"usage_type": string; // 使用类型,[enum:HouseMetersUsageTypeEnum]
"multiple"?: number; // 倍率
"status"?: number; // 是否启用:0:禁用,1:启用
"initial_value"?: number; // 初始抄表读数
"initial_time"?: Date; // 初始抄表时间
"latest_value"?: number; // 最新抄表读数
"latest_time"?: Date; // 最新抄表时间
"remark"?: string; // 备注
};
type Show = {
"id": number; // id
};
type SoftDelete = {
"id": number; // id
};
type Restore = {
"id": number; // id
};
type Delete = {
"id": number; // id
};
}
}
namespace Msg {
namespace MsgPropertyAnnouncements {
type List = {

View File

@ -254,6 +254,9 @@ export const Apis = {
List(data?: ApiTypes.Bill.HouseBills.List): Promise<MyResponseType> {
return request('admin/bill/house_bills/list', { data });
},
SummaryBillList(data?: ApiTypes.Bill.HouseBills.SummaryBillList): Promise<MyResponseType> {
return request('admin/bill/house_bills/summary_bill_list', { data });
},
Store(data: ApiTypes.Bill.HouseBills.Store): Promise<MyResponseType> {
return request('admin/bill/house_bills/store', { data });
},
@ -754,6 +757,82 @@ export const Apis = {
},
},
},
Meter: {
HouseMeterHasHouses: {
List(data?: ApiTypes.Meter.HouseMeterHasHouses.List): Promise<MyResponseType> {
return request('admin/meter/house_meter_has_houses/list', { data });
},
StoreOrUpdate(data: ApiTypes.Meter.HouseMeterHasHouses.StoreOrUpdate): Promise<MyResponseType> {
return request('admin/meter/house_meter_has_houses/store_or_update', { data });
},
Show(data: ApiTypes.Meter.HouseMeterHasHouses.Show): Promise<MyResponseType> {
return request('admin/meter/house_meter_has_houses/show', { data });
},
Delete(data: ApiTypes.Meter.HouseMeterHasHouses.Delete): Promise<MyResponseType> {
return request('admin/meter/house_meter_has_houses/delete', { data });
},
},
HouseMeterReadings: {
List(data?: ApiTypes.Meter.HouseMeterReadings.List): Promise<MyResponseType> {
return request('admin/meter/house_meter_readings/list', { data });
},
Store(data: ApiTypes.Meter.HouseMeterReadings.Store): Promise<MyResponseType> {
return request('admin/meter/house_meter_readings/store', { data });
},
Update(data: ApiTypes.Meter.HouseMeterReadings.Update): Promise<MyResponseType> {
return request('admin/meter/house_meter_readings/update', { data });
},
Show(data: ApiTypes.Meter.HouseMeterReadings.Show): Promise<MyResponseType> {
return request('admin/meter/house_meter_readings/show', { data });
},
Delete(data: ApiTypes.Meter.HouseMeterReadings.Delete): Promise<MyResponseType> {
return request('admin/meter/house_meter_readings/delete', { data });
},
},
HouseMeterTasks: {
List(data?: ApiTypes.Meter.HouseMeterTasks.List): Promise<MyResponseType> {
return request('admin/meter/house_meter_tasks/list', { data });
},
Store(data: ApiTypes.Meter.HouseMeterTasks.Store): Promise<MyResponseType> {
return request('admin/meter/house_meter_tasks/store', { data });
},
Show(data: ApiTypes.Meter.HouseMeterTasks.Show): Promise<MyResponseType> {
return request('admin/meter/house_meter_tasks/show', { data });
},
SoftDelete(data: ApiTypes.Meter.HouseMeterTasks.SoftDelete): Promise<MyResponseType> {
return request('admin/meter/house_meter_tasks/soft_delete', { data });
},
Restore(data: ApiTypes.Meter.HouseMeterTasks.Restore): Promise<MyResponseType> {
return request('admin/meter/house_meter_tasks/restore', { data });
},
Delete(data: ApiTypes.Meter.HouseMeterTasks.Delete): Promise<MyResponseType> {
return request('admin/meter/house_meter_tasks/delete', { data });
},
},
HouseMeters: {
List(data?: ApiTypes.Meter.HouseMeters.List): Promise<MyResponseType> {
return request('admin/meter/house_meters/list', { data });
},
Store(data: ApiTypes.Meter.HouseMeters.Store): Promise<MyResponseType> {
return request('admin/meter/house_meters/store', { data });
},
Update(data: ApiTypes.Meter.HouseMeters.Update): Promise<MyResponseType> {
return request('admin/meter/house_meters/update', { data });
},
Show(data: ApiTypes.Meter.HouseMeters.Show): Promise<MyResponseType> {
return request('admin/meter/house_meters/show', { data });
},
SoftDelete(data: ApiTypes.Meter.HouseMeters.SoftDelete): Promise<MyResponseType> {
return request('admin/meter/house_meters/soft_delete', { data });
},
Restore(data: ApiTypes.Meter.HouseMeters.Restore): Promise<MyResponseType> {
return request('admin/meter/house_meters/restore', { data });
},
Delete(data: ApiTypes.Meter.HouseMeters.Delete): Promise<MyResponseType> {
return request('admin/meter/house_meters/delete', { data });
},
},
},
Msg: {
MsgPropertyAnnouncements: {
List(data?: ApiTypes.Msg.MsgPropertyAnnouncements.List): Promise<MyResponseType> {

View File

@ -154,7 +154,7 @@ export const BannersTypeEnum= {
// 缓存类型
export const CacheTypeEnum= {
'MobilePhoneVerificationCode': {"text":"手机验证码","color":"#5acfb3","value":"MobilePhoneVerificationCode"},
'MobilePhoneVerificationCode': {"text":"手机验证码","color":"#0a9319","value":"MobilePhoneVerificationCode"},
};
// CompaniesMerchantTypeEnum
@ -226,7 +226,6 @@ export const CustomerMomentTasksStatusEnum= {
// CustomerMomentsChannelEnum
export const CustomerMomentsChannelEnum= {
'MomentCorp': {"text":"朋友圈(企业)","color":"#1E90FF","value":"MomentCorp"},
'MomentPersonal': {"text":"朋友圈(个人)","color":"#32CD32","value":"MomentPersonal"},
'CustomerDirectCorp': {"text":"客户1对1消息群发(企业)","color":"#FFA500","value":"CustomerDirectCorp"},
'CustomerGroupCorp': {"text":"客户群群发(企业)","color":"#FF69B4","value":"CustomerGroupCorp"},
};
@ -396,6 +395,34 @@ export const HouseCollectionTasksStatusEnum= {
'Failed': {"text":"失败","color":"#ff0000","value":"Failed"},
};
// HouseMeterReadingsOperationTypeEnum
export const HouseMeterReadingsOperationTypeEnum= {
'NormalReading': {"text":"正常抄表","color":"#4caf50","value":"NormalReading"},
'ResetReading': {"text":"重置读数","color":"#f44336","value":"ResetReading"},
'CorrectReading': {"text":"修正读数","color":"#ff9800","value":"CorrectReading"},
};
// HouseMeterTasksGenerationMethodEnum
export const HouseMeterTasksGenerationMethodEnum= {
'Building': {"text":"按楼栋","color":"#4caf50","value":"Building"},
'Unit': {"text":"按单元","color":"#2196f3","value":"Unit"},
'Meter': {"text":"按仪表","color":"#ff9800","value":"Meter"},
};
// HouseMetersMeterTypeEnum
export const HouseMetersMeterTypeEnum= {
'HouseMeter': {"text":"房屋表","color":"#4caf50","value":"HouseMeter"},
'CommonMeter': {"text":"公摊表","color":"#2196f3","value":"CommonMeter"},
};
// HouseMetersUsageTypeEnum
export const HouseMetersUsageTypeEnum= {
'WaterMeter': {"text":"水表","color":"#2196f3","value":"WaterMeter"},
'ElectricMeter': {"text":"电表","color":"#ff9800","value":"ElectricMeter"},
'GasMeter': {"text":"燃气表","color":"#f44336","value":"GasMeter"},
'HeatingMeter': {"text":"暖气表","color":"#9c27b0","value":"HeatingMeter"},
};
// HouseOccupantsCardTypeEnum
export const HouseOccupantsCardTypeEnum= {
'MainlandID': {"text":"中国大陆居民身份证","color":"#2db7f5","value":"MainlandID"},

View File

@ -7,7 +7,7 @@ import {
} from '@/gen/Enums';
import { ProCard, ProDescriptions } from '@ant-design/pro-components';
import { Space } from 'antd';
import ChangeStatus from './modals/ChangeStatus';
import ChangeStatus from '../table/modals/ChangeStatus';
export default function info(props: MyBetaModalFormProps) {
const { item } = props;

View File

@ -0,0 +1,49 @@
import { MyBetaModalFormProps, MyProTableProps } from '@/common';
import { Apis } from '@/gen/Apis';
import { ProCard, ProTable } from '@ant-design/pro-components';
export default function info(props: MyBetaModalFormProps) {
const { item } = props;
return (
<ProCard>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
asset_houses_id: item?.asset_houses_id,
},
sort,
Apis.Bill.HouseBills.SummaryBillList,
)
}
search={false}
options={false}
pagination={false}
columns={[
{
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,
},
]}
/>
</ProCard>
);
}

View File

@ -5,9 +5,11 @@ import { useParams } from '@umijs/max';
import { Badge, Tabs } from 'antd';
import { useEffect, useState } from 'react';
import HouseInfo from '../components/HouseInfo';
import OccupantsHistory from '../components/OccupantsHistory';
import OccupantsNow from '../components/OccupantsNow';
import RegistersList from '../components/RegistersList';
import SummaryInfo from '../components/SummaryInfo';
import OccupantsHistory from '../table/OccupantsHistory';
import OccupantsNow from '../table/OccupantsNow';
import RegistersList from '../table/RegistersList';
import UnpaidBill from '../table/UnpaidBill';
export default function Show({ title = '房屋档案' }) {
const { id } = useParams<{ id: string }>();
@ -88,11 +90,18 @@ export default function Show({ title = '房屋档案' }) {
/>
),
},
{
label: '欠费账单',
key: '4',
closable: false,
children: <UnpaidBill item={{ ...data, asset_houses_id: id }} />,
},
];
return (
<MyPageContainer title={title}>
<HouseInfo item={data} reload={loadShow} />
<SummaryInfo item={{ ...data, asset_houses_id: id }} reload={loadShow} />
<ProCard style={{ marginTop: 16 }}>
<Tabs type="card" items={items} defaultActiveKey="1" size="small" />
</ProCard>

View File

@ -0,0 +1,71 @@
import { MyColumns, MyProTableProps } from '@/common';
import { Apis } from '@/gen/Apis';
import { HouseBillsTypeEnum } from '@/gen/Enums';
import BillUpdate from '@/pages/bills/list/modals/BillUpdate';
import { ProTable } from '@ant-design/pro-components';
import { Space } from 'antd';
import { useEffect, useRef } from 'react';
export default function Index({ ...rest }) {
const actionLooks = useRef<any>();
useEffect(() => {
actionLooks?.current.reloadAndRest();
}, [rest.loadmore]);
return (
<>
<ProTable<Record<any, any>>
{...MyProTableProps.props}
actionRef={actionLooks}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
asset_houses_id: rest.item?.asset_houses_id,
status: 'Normal',
},
sort,
Apis.Bill.HouseBills.List,
)
}
search={false}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '类型',
dataIndex: 'type',
valueEnum: HouseBillsTypeEnum,
}),
{
title: '账单月份',
render: (_, record) => {
return `${record.year}-${String(record.month).padStart(2, '0')}`;
},
},
{
title: '应付金额',
dataIndex: 'total_payable_amount',
search: false,
},
{
title: '计费开始日期',
dataIndex: 'start_date',
search: false,
},
{
title: '计费结束日期',
dataIndex: 'end_date',
search: false,
},
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<BillUpdate item={item} reload={action?.reload} title="编辑" />
</Space>
),
}),
]}
/>
</>
);
}

View File

@ -153,6 +153,18 @@ export default function Create(props: MyBetaModalFormProps) {
},
renderFormItem: () => <MyEditor />,
},
MyFormItems.UploadImages({
key: 'cover_image',
title: '活动封面',
tooltip: '建议图片比例 16:9',
fieldProps: {
style: {
width: 160,
height: 90,
},
},
max: 1,
}),
]}
/>
);

View File

@ -80,7 +80,21 @@ export default function Show(props: MyBetaModalFormProps) {
{show?.publish_time || '-'}
</Space>
</ProDescriptions.Item>
<ProDescriptions.Item label="活动封面">
{show?.cover_image?.[0]?.url ? (
<img
src={show?.cover_image?.[0]?.url}
alt={show?.title || '-'}
style={{
width: 160,
height: 90,
objectFit: 'cover',
}}
/>
) : (
'-'
)}
</ProDescriptions.Item>
<ProDescriptions.Item label="活动内容">
<div
style={{

View File

@ -153,6 +153,18 @@ export default function Update(props: MyBetaModalFormProps) {
renderFormItem: () => <MyEditor />,
initialValue: props.item?.content,
},
MyFormItems.UploadImages({
key: 'cover_image',
title: '活动封面',
tooltip: '建议图片比例 16:9',
fieldProps: {
style: {
width: 160,
height: 90,
},
},
max: 1,
}),
]}
/>
);

View File

@ -0,0 +1,539 @@
import {
MyButtons,
MyColumns,
MyPageContainer,
MyProTableProps,
usePageTabs,
} from '@/common';
import { Apis } from '@/gen/Apis';
import {
AssetHousesOwnershipTypeEnum,
AssetHousesUsageEnum,
} from '@/gen/Enums';
import { ProCard, ProTable } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max';
import { Alert, message, Space, Typography } from 'antd';
import { useCallback, useMemo, useRef, useState } from 'react';
import BuildingsCreate from './modals/BuildingsCreate';
import AssetBuildingsUpdate from './modals/BuildingsUpdate';
import HousesCreate from './modals/HousesCreate';
import HousesUpdate from './modals/HousesUpdate';
import UnitsCreate from './modals/UnitsCreate';
import AssetUnitsUpdate from './modals/UnitsUpdate';
const { Title } = Typography;
interface SelectedAsset {
id: number;
name: string;
}
interface SelectedBuilding {
id: number;
name: string;
}
interface SelectedUnit {
id: number;
name: string;
}
export default function Index({ title = '项目列表' }) {
usePageTabs({
tabKey: 'asset-buildings',
tabLabel: title,
});
const actionAssetRef: any = useRef();
const actionBuildingsRef: any = useRef();
const actionUnitsRef: any = useRef();
const actionHousesRef: any = useRef();
const navigate = useNavigate();
const [selectedAsset, setSelectedAsset] = useState<SelectedAsset | null>(
null,
);
const [selectedBuilding, setSelectedBuilding] =
useState<SelectedBuilding | null>(null);
const [selectedUnit, setSelectedUnit] = useState<SelectedUnit | null>(null);
const [loading, setLoading] = useState({
buildings: false,
units: false,
houses: false,
});
// 选择项目的回调函数
const handleAssetSelect = useCallback(
(asset: SelectedAsset) => {
if (selectedAsset?.id === asset.id) return; // 避免重复选择
setSelectedAsset(asset);
setSelectedBuilding(null); // 重置楼栋选择
setSelectedUnit(null); // 重置单元选择
// 刷新楼栋和单元列表
actionBuildingsRef?.current?.reload();
actionUnitsRef?.current?.reload();
actionHousesRef?.current?.reload();
},
[selectedAsset?.id],
);
// 选择楼栋的回调函数
const handleBuildingSelect = useCallback(
(building: SelectedBuilding) => {
if (selectedBuilding?.id === building.id) return; // 避免重复选择
setSelectedBuilding(building);
setSelectedUnit(null); // 重置单元选择
// 刷新单元和房屋列表
actionUnitsRef?.current?.reload();
actionHousesRef?.current?.reload();
},
[selectedBuilding?.id],
);
// 选择单元的回调函数
const handleUnitSelect = useCallback(
(unit: SelectedUnit) => {
if (selectedUnit?.id === unit.id) return; // 避免重复选择
setSelectedUnit(unit);
// 刷新房屋列表
actionHousesRef?.current?.reload();
},
[selectedUnit?.id],
);
// 删除操作的通用处理
const handleDelete = useCallback(
async (deleteApi: any, id: number, reloadAction: any, itemName: string) => {
try {
await deleteApi({ id });
message.success(`${itemName}删除成功`);
reloadAction();
// 如果删除的是当前选中项,清空选择
if (itemName === '项目' && selectedAsset?.id === id) {
setSelectedAsset(null);
setSelectedBuilding(null);
setSelectedUnit(null);
} else if (itemName === '楼栋' && selectedBuilding?.id === id) {
setSelectedBuilding(null);
setSelectedUnit(null);
} else if (itemName === '单元' && selectedUnit?.id === id) {
setSelectedUnit(null);
}
} catch (error) {
message.error(`${itemName}删除失败`);
console.error(`删除${itemName}失败:`, error);
}
},
[selectedAsset?.id, selectedBuilding?.id, selectedUnit?.id],
);
// 通用表格配置
const getTableConfig = useMemo(
() => ({
...MyProTableProps.props,
search: false as const,
size: 'middle' as const,
options: false as const,
pagination: {
pageSize: 10,
showSizeChanger: false,
},
}),
[],
);
// 项目表格列配置
const projectColumns = useMemo(
() => [
{
title: '项目',
dataIndex: 'name',
ellipsis: true,
search: {
transform: (value: string) => ({ name: value }),
},
},
MyColumns.Option({
width: 120,
render: (_, item: any, index, action) => (
<Space key={index} size="small">
<MyButtons.View
title="配置"
onClick={() => {
navigate(`/asset/list/show/${item.id}`);
}}
/>
</Space>
),
}),
],
[handleDelete],
);
// 楼栋表格列配置
const buildingColumns = useMemo(
() => [
{
title: '楼栋',
dataIndex: 'name',
ellipsis: true,
},
MyColumns.Option({
width: 120,
render: (_, item: any, index, action) => (
<Space key={index} size="small">
<AssetBuildingsUpdate item={item} reload={action?.reload} />
{/* <MyButtons.Delete
size="small"
onConfirm={() =>
handleDelete(
Apis.Asset.AssetBuildings.Delete,
item.id,
action?.reload,
'楼栋',
)
}
/> */}
</Space>
),
}),
],
[handleDelete],
);
// 单元表格列配置
const unitColumns = useMemo(
() => [
{
title: '单元',
dataIndex: 'name',
ellipsis: true,
},
MyColumns.Option({
width: 120,
render: (_, item: any, index, action) => (
<Space key={index} size="small">
<AssetUnitsUpdate item={item} reload={action?.reload} />
{/* <MyButtons.Delete
size="small"
onConfirm={() =>
handleDelete(
Apis.Asset.AssetUnits.Delete,
item.id,
action?.reload,
'单元',
)
}
/> */}
</Space>
),
}),
],
[handleDelete],
);
// 房屋表格列配置
const houseColumns = useMemo(
() => [
MyColumns.EnumTag({
title: '用途',
dataIndex: 'usage',
valueEnum: AssetHousesUsageEnum,
}),
{
title: '房屋名称',
dataIndex: 'full_name',
},
{
title: '楼层',
dataIndex: 'floor',
render(_, record) {
return `${record?.floor}`;
},
},
{
title: '房号',
dataIndex: 'name',
},
{
title: '计费面积',
dataIndex: 'chargeable_area',
render(_, record) {
return `${
record?.chargeable_area ? record?.chargeable_area + ' m²' : '-'
} `;
},
},
MyColumns.EnumTag({
title: '房屋属性',
dataIndex: 'ownership_type',
valueEnum: AssetHousesOwnershipTypeEnum,
}),
MyColumns.Option({
width: 120,
render: (_, item: any, index, action) => (
<Space key={index} size="small">
<HousesUpdate item={item} reload={action?.reload} title="编辑" />
{/* <MyButtons.Delete
size="small"
onConfirm={() =>
handleDelete(
Apis.Asset.AssetHouses.Delete,
item.id,
action?.reload,
'房屋',
)
}
/> */}
</Space>
),
}),
],
[handleDelete],
);
return (
<MyPageContainer title={title}>
<ProCard
title={
<Alert
message="操作提示:可在项目中添加楼栋,在楼栋中添加单元,在单元中添加房屋!"
type="info"
showIcon
style={{ margin: 0 }}
/>
}
>
<Space align="start" size="large" style={{ width: '100%' }}>
<div style={{ flex: 1 }}>
<Title level={5} style={{ marginBottom: 16 }}>
<Space
style={{ display: 'flex', justifyContent: 'space-between' }}
>
</Space>
</Title>
<ProTable
{...getTableConfig}
// search={{
// labelWidth: 'auto',
// collapsed: false,
// collapseRender: false,
// }}
actionRef={actionAssetRef}
rowClassName={(record: any) => {
return selectedAsset?.id === record?.id
? 'ant-table-row-selected'
: '';
}}
onRow={(record: any) => {
return {
onClick: () => {
handleAssetSelect(record);
},
style: {
cursor: 'pointer',
},
};
}}
request={async (params, sort) =>
MyProTableProps.request(
{ ...params },
sort,
Apis.Asset.AssetProjects.List,
)
}
columns={projectColumns}
/>
</div>
{/* 楼栋列表 */}
{selectedAsset ? (
<div style={{ flex: 1 }}>
<Title level={5} style={{ marginBottom: 16 }}>
<Space
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<span>{selectedAsset?.name}</span>
<BuildingsCreate
key="BuildingsCreate"
item={{ ...selectedAsset, size: 'small' }}
reload={() => actionBuildingsRef?.current?.reload()}
title="楼栋"
/>
</Space>
</Title>
<ProTable
{...getTableConfig}
actionRef={actionBuildingsRef}
rowClassName={(record: any) => {
return selectedBuilding?.id === record?.id
? 'ant-table-row-selected'
: '';
}}
onRow={(record: any) => {
return {
onClick: () => {
handleBuildingSelect(record);
},
style: {
cursor: 'pointer',
},
};
}}
request={async (params, sort) =>
MyProTableProps.request(
{ ...params, asset_projects_id: selectedAsset?.id },
sort,
Apis.Asset.AssetBuildings.List,
)
}
columns={buildingColumns}
/>
</div>
) : (
<div
style={{
flex: 1,
// minWidth: 300,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#999',
}}
>
</div>
)}
{/* 单元列表 */}
{selectedBuilding ? (
<div style={{ flex: 1 }}>
<Title level={5} style={{ marginBottom: 16 }}>
<Space
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<span>{selectedBuilding.name}</span>
<UnitsCreate
key="UnitsCreate"
item={{
...selectedBuilding,
asset_buildings_id: selectedBuilding?.id,
size: 'small',
}}
reload={() => actionUnitsRef?.current?.reload()}
title="单元"
/>
</Space>
</Title>
<ProTable
{...getTableConfig}
actionRef={actionUnitsRef}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
asset_projects_id: selectedAsset?.id,
asset_buildings_id: selectedBuilding?.id,
},
sort,
Apis.Asset.AssetUnits.List,
)
}
rowClassName={(record: any) => {
return selectedUnit?.id === record?.id
? 'ant-table-row-selected'
: '';
}}
onRow={(record: any) => {
return {
onClick: () => {
handleUnitSelect(record);
},
style: {
cursor: 'pointer',
},
};
}}
columns={unitColumns}
/>
</div>
) : (
<div
style={{
flex: 1,
// minWidth: 300,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#999',
}}
>
</div>
)}
{/* 房屋列表 */}
{selectedUnit ? (
<div style={{ flex: 1 }}>
<Title level={5} style={{ marginBottom: 16 }}>
<Space
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<span>{selectedUnit.name}</span>
<HousesCreate
key="HousesCreate"
item={{
...selectedUnit,
asset_projects_id: selectedAsset?.id,
asset_buildings_id: selectedBuilding?.id,
asset_units_id: selectedUnit?.id,
size: 'small',
}}
reload={() => actionHousesRef?.current?.reload()}
title="房屋"
/>
</Space>
</Title>
<ProTable
{...getTableConfig}
actionRef={actionHousesRef}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
asset_projects_id: selectedAsset?.id,
asset_buildings_id: selectedBuilding?.id,
asset_units_id: selectedUnit?.id,
},
sort,
Apis.Asset.AssetHouses.List,
)
}
columns={houseColumns}
/>
</div>
) : (
<div
style={{
flex: 1,
// minWidth: 400,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#999',
}}
>
{selectedBuilding ? '请先选择单元' : '请先选择楼栋'}
</div>
)}
</Space>
</ProCard>
</MyPageContainer>
);
}

View File

@ -5,535 +5,164 @@ import {
MyProTableProps,
usePageTabs,
} from '@/common';
import { MyExport } from '@/components/MyExport';
import { Apis } from '@/gen/Apis';
import {
AssetHousesOwnershipTypeEnum,
AssetHousesUsageEnum,
} from '@/gen/Enums';
import { ProCard, ProTable } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max';
import { Alert, message, Space, Typography } from 'antd';
import { useCallback, useMemo, useRef, useState } from 'react';
import BuildingsCreate from './modals/BuildingsCreate';
import AssetBuildingsUpdate from './modals/BuildingsUpdate';
import HousesCreate from './modals/HousesCreate';
import HousesUpdate from './modals/HousesUpdate';
import UnitsCreate from './modals/UnitsCreate';
import AssetUnitsUpdate from './modals/UnitsUpdate';
import { Space } from 'antd';
import { useState } from 'react';
import HousesShow from '../dictionary/modals/HousesShow';
import HousesUpdate from '../dictionary/modals/HousesUpdate';
const { Title } = Typography;
interface SelectedAsset {
id: number;
name: string;
}
export default function Index({ title = '房屋列表' }) {
const [getParams, setParams] = useState({});
interface SelectedBuilding {
id: number;
name: string;
}
interface SelectedUnit {
id: number;
name: string;
}
export default function Index({ title = '项目列表' }) {
const navigate = useNavigate();
// 注册当前页面为标签页
usePageTabs({
tabKey: 'asset-buildings',
tabKey: 'asset-houses',
tabLabel: title,
});
const actionAssetRef: any = useRef();
const actionBuildingsRef: any = useRef();
const actionUnitsRef: any = useRef();
const actionHousesRef: any = useRef();
const navigate = useNavigate();
const [selectedAsset, setSelectedAsset] = useState<SelectedAsset | null>(
null,
);
const [selectedBuilding, setSelectedBuilding] =
useState<SelectedBuilding | null>(null);
const [selectedUnit, setSelectedUnit] = useState<SelectedUnit | null>(null);
const [loading, setLoading] = useState({
buildings: false,
units: false,
houses: false,
});
// 选择项目的回调函数
const handleAssetSelect = useCallback(
(asset: SelectedAsset) => {
if (selectedAsset?.id === asset.id) return; // 避免重复选择
setSelectedAsset(asset);
setSelectedBuilding(null); // 重置楼栋选择
setSelectedUnit(null); // 重置单元选择
// 刷新楼栋和单元列表
actionBuildingsRef?.current?.reload();
actionUnitsRef?.current?.reload();
actionHousesRef?.current?.reload();
},
[selectedAsset?.id],
);
// 选择楼栋的回调函数
const handleBuildingSelect = useCallback(
(building: SelectedBuilding) => {
if (selectedBuilding?.id === building.id) return; // 避免重复选择
setSelectedBuilding(building);
setSelectedUnit(null); // 重置单元选择
// 刷新单元和房屋列表
actionUnitsRef?.current?.reload();
actionHousesRef?.current?.reload();
},
[selectedBuilding?.id],
);
// 选择单元的回调函数
const handleUnitSelect = useCallback(
(unit: SelectedUnit) => {
if (selectedUnit?.id === unit.id) return; // 避免重复选择
setSelectedUnit(unit);
// 刷新房屋列表
actionHousesRef?.current?.reload();
},
[selectedUnit?.id],
);
// 删除操作的通用处理
const handleDelete = useCallback(
async (deleteApi: any, id: number, reloadAction: any, itemName: string) => {
try {
await deleteApi({ id });
message.success(`${itemName}删除成功`);
reloadAction();
// 如果删除的是当前选中项,清空选择
if (itemName === '项目' && selectedAsset?.id === id) {
setSelectedAsset(null);
setSelectedBuilding(null);
setSelectedUnit(null);
} else if (itemName === '楼栋' && selectedBuilding?.id === id) {
setSelectedBuilding(null);
setSelectedUnit(null);
} else if (itemName === '单元' && selectedUnit?.id === id) {
setSelectedUnit(null);
}
} catch (error) {
message.error(`${itemName}删除失败`);
console.error(`删除${itemName}失败:`, error);
}
},
[selectedAsset?.id, selectedBuilding?.id, selectedUnit?.id],
);
// 通用表格配置
const getTableConfig = useMemo(
() => ({
...MyProTableProps.props,
search: false as const,
size: 'middle' as const,
options: false as const,
pagination: {
pageSize: 10,
showSizeChanger: false,
},
}),
[],
);
// 项目表格列配置
const projectColumns = useMemo(
() => [
{
title: '项目',
dataIndex: 'name',
ellipsis: true,
search: {
transform: (value: string) => ({ name: value }),
},
},
MyColumns.Option({
width: 120,
render: (_, item: any, index, action) => (
<Space key={index} size="small">
<MyButtons.View
title="配置"
onClick={() => {
navigate(`/asset/list/show/${item.id}`);
}}
/>
</Space>
),
}),
],
[handleDelete],
);
// 楼栋表格列配置
const buildingColumns = useMemo(
() => [
{
title: '楼栋',
dataIndex: 'name',
ellipsis: true,
},
MyColumns.Option({
width: 120,
render: (_, item: any, index, action) => (
<Space key={index} size="small">
<AssetBuildingsUpdate item={item} reload={action?.reload} />
{/* <MyButtons.Delete
size="small"
onConfirm={() =>
handleDelete(
Apis.Asset.AssetBuildings.Delete,
item.id,
action?.reload,
'楼栋',
)
}
/> */}
</Space>
),
}),
],
[handleDelete],
);
// 单元表格列配置
const unitColumns = useMemo(
() => [
{
title: '单元',
dataIndex: 'name',
ellipsis: true,
},
MyColumns.Option({
width: 120,
render: (_, item: any, index, action) => (
<Space key={index} size="small">
<AssetUnitsUpdate item={item} reload={action?.reload} />
{/* <MyButtons.Delete
size="small"
onConfirm={() =>
handleDelete(
Apis.Asset.AssetUnits.Delete,
item.id,
action?.reload,
'单元',
)
}
/> */}
</Space>
),
}),
],
[handleDelete],
);
// 房屋表格列配置
const houseColumns = useMemo(
() => [
MyColumns.EnumTag({
title: '用途',
dataIndex: 'usage',
valueEnum: AssetHousesUsageEnum,
}),
{
title: '房屋名称',
dataIndex: 'full_name',
},
{
title: '楼层',
dataIndex: 'floor',
render(_, record) {
return `${record?.floor}`;
},
},
{
title: '房号',
dataIndex: 'name',
},
{
title: '计费面积',
dataIndex: 'chargeable_area',
render(_, record) {
return `${
record?.chargeable_area ? record?.chargeable_area + ' m²' : '-'
} `;
},
},
MyColumns.EnumTag({
title: '房屋属性',
dataIndex: 'ownership_type',
valueEnum: AssetHousesOwnershipTypeEnum,
}),
MyColumns.Option({
width: 120,
render: (_, item: any, index, action) => (
<Space key={index} size="small">
<HousesUpdate item={item} reload={action?.reload} title="编辑" />
{/* <MyButtons.Delete
size="small"
onConfirm={() =>
handleDelete(
Apis.Asset.AssetHouses.Delete,
item.id,
action?.reload,
'房屋',
)
}
/> */}
</Space>
),
}),
],
[handleDelete],
);
return (
<MyPageContainer title={title}>
<ProCard
title={
<Alert
message="操作提示:可在项目中添加楼栋,在楼栋中添加单元,在单元中添加房屋!"
type="info"
showIcon
style={{ margin: 0 }}
/>
}
>
<Space align="start" size="large" style={{ width: '100%' }}>
<div style={{ flex: 1 }}>
<Title level={5} style={{ marginBottom: 16 }}>
<Space
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) => {
setParams(params);
return MyProTableProps.request(
params,
sort,
Apis.Asset.AssetHouses.List,
);
}}
toolBarRender={() => [
<MyExport
key="export"
item={getParams}
download={Apis.Asset.AssetHouses}
/>,
]}
columns={[
MyColumns.ID(),
{
title: '项目名称',
dataIndex: ['asset_project', 'name'],
search: {
transform: (value) => {
return { project_name: value };
},
},
},
{
title: '房屋名称',
dataIndex: 'full_name',
},
MyColumns.EnumTag({
title: '用途',
dataIndex: 'usage',
valueEnum: AssetHousesUsageEnum,
}),
{
title: '楼层',
dataIndex: 'floor',
render(_, record) {
return `${record?.floor}`;
},
search: false,
},
{
title: '建筑面积',
dataIndex: 'built_area',
render(_, record) {
return `${
record?.built_area ? record?.built_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '套内面积',
dataIndex: 'inside_area',
render(_, record) {
return `${
record?.inside_area ? record?.inside_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '计费面积',
dataIndex: 'chargeable_area',
render(_, record) {
return `${
record?.chargeable_area ? record?.chargeable_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '户型',
render(_, record) {
return `${record?.room || 'x'}${record?.hall || 'x'}${
record?.bathroom || 'x'
}${record?.kitchen || 'x'}${record?.balcony || 'x'}`;
},
search: false,
},
// MyColumns.EnumTag({
// title: '朝向',
// dataIndex: 'orientation',
// valueEnum: AssetHousesOrientationEnum,
// search: false,
// }),
// MyColumns.EnumTag({
// title: '房屋状态',
// dataIndex: 'status',
// valueEnum: AssetHousesStatusEnum,
// search: false,
// }),
MyColumns.EnumTag({
title: '房屋属性',
dataIndex: 'ownership_type',
valueEnum: AssetHousesOwnershipTypeEnum,
search: false,
}),
// {
// title: '产权年限',
// dataIndex: 'ownership_term',
// render(_, record) {
// return `${record?.ownership_term || '-'} 年`;
// },
// search: false,
// },
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<HousesShow item={item} reload={action?.reload} />
<HousesUpdate
item={item}
reload={action?.reload}
title="编辑"
/>
<MyButtons.Delete
onConfirm={() =>
Apis.Asset.AssetHouses.Delete({
id: item.id,
}).then(() => action?.reload())
}
/>
</Space>
</Title>
<ProTable
{...getTableConfig}
// search={{
// labelWidth: 'auto',
// collapsed: false,
// collapseRender: false,
// }}
actionRef={actionAssetRef}
rowClassName={(record: any) => {
return selectedAsset?.id === record?.id
? 'ant-table-row-selected'
: '';
}}
onRow={(record: any) => {
return {
onClick: () => {
handleAssetSelect(record);
},
style: {
cursor: 'pointer',
},
};
}}
request={async (params, sort) =>
MyProTableProps.request(
{ ...params },
sort,
Apis.Asset.AssetProjects.List,
)
}
columns={projectColumns}
/>
</div>
{/* 楼栋列表 */}
{selectedAsset ? (
<div style={{ flex: 1 }}>
<Title level={5} style={{ marginBottom: 16 }}>
<Space
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<span>{selectedAsset?.name}</span>
<BuildingsCreate
key="BuildingsCreate"
item={{ ...selectedAsset, size: 'small' }}
reload={() => actionBuildingsRef?.current?.reload()}
title="楼栋"
/>
</Space>
</Title>
<ProTable
{...getTableConfig}
actionRef={actionBuildingsRef}
rowClassName={(record: any) => {
return selectedBuilding?.id === record?.id
? 'ant-table-row-selected'
: '';
}}
onRow={(record: any) => {
return {
onClick: () => {
handleBuildingSelect(record);
},
style: {
cursor: 'pointer',
},
};
}}
request={async (params, sort) =>
MyProTableProps.request(
{ ...params, asset_projects_id: selectedAsset?.id },
sort,
Apis.Asset.AssetBuildings.List,
)
}
columns={buildingColumns}
/>
</div>
) : (
<div
style={{
flex: 1,
// minWidth: 300,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#999',
}}
>
</div>
)}
{/* 单元列表 */}
{selectedBuilding ? (
<div style={{ flex: 1 }}>
<Title level={5} style={{ marginBottom: 16 }}>
<Space
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<span>{selectedBuilding.name}</span>
<UnitsCreate
key="UnitsCreate"
item={{
...selectedBuilding,
asset_buildings_id: selectedBuilding?.id,
size: 'small',
}}
reload={() => actionUnitsRef?.current?.reload()}
title="单元"
/>
</Space>
</Title>
<ProTable
{...getTableConfig}
actionRef={actionUnitsRef}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
asset_projects_id: selectedAsset?.id,
asset_buildings_id: selectedBuilding?.id,
},
sort,
Apis.Asset.AssetUnits.List,
)
}
rowClassName={(record: any) => {
return selectedUnit?.id === record?.id
? 'ant-table-row-selected'
: '';
}}
onRow={(record: any) => {
return {
onClick: () => {
handleUnitSelect(record);
},
style: {
cursor: 'pointer',
},
};
}}
columns={unitColumns}
/>
</div>
) : (
<div
style={{
flex: 1,
// minWidth: 300,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#999',
}}
>
</div>
)}
{/* 房屋列表 */}
{selectedUnit ? (
<div style={{ flex: 1 }}>
<Title level={5} style={{ marginBottom: 16 }}>
<Space
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<span>{selectedUnit.name}</span>
<HousesCreate
key="HousesCreate"
item={{
...selectedUnit,
asset_projects_id: selectedAsset?.id,
asset_buildings_id: selectedBuilding?.id,
asset_units_id: selectedUnit?.id,
size: 'small',
}}
reload={() => actionHousesRef?.current?.reload()}
title="房屋"
/>
</Space>
</Title>
<ProTable
{...getTableConfig}
actionRef={actionHousesRef}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
asset_projects_id: selectedAsset?.id,
asset_buildings_id: selectedBuilding?.id,
asset_units_id: selectedUnit?.id,
},
sort,
Apis.Asset.AssetHouses.List,
)
}
columns={houseColumns}
/>
</div>
) : (
<div
style={{
flex: 1,
// minWidth: 400,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: '#999',
}}
>
{selectedBuilding ? '请先选择单元' : '请先选择楼栋'}
</div>
)}
</Space>
</ProCard>
),
}),
]}
/>
</MyPageContainer>
);
}

View File

@ -13,12 +13,12 @@ import {
import { ProCard, ProTable } from '@ant-design/pro-components';
import { Alert, message, Space, Typography } from 'antd';
import { useCallback, useRef, useState } from 'react';
import BuildingsCreate from '../../houses/modals/BuildingsCreate';
import AssetBuildingsUpdate from '../../houses/modals/BuildingsUpdate';
import HousesCreate from '../../houses/modals/HousesCreate';
import HousesUpdate from '../../houses/modals/HousesUpdate';
import AssetUnitsCreate from '../../houses/modals/UnitsCreate';
import AssetUnitsUpdate from '../../houses/modals/UnitsUpdate';
import BuildingsCreate from '../../dictionary/modals/BuildingsCreate';
import AssetBuildingsUpdate from '../../dictionary/modals/BuildingsUpdate';
import HousesCreate from '../../dictionary/modals/HousesCreate';
import HousesUpdate from '../../dictionary/modals/HousesUpdate';
import AssetUnitsCreate from '../../dictionary/modals/UnitsCreate';
import AssetUnitsUpdate from '../../dictionary/modals/UnitsUpdate';
const { Title } = Typography;

View File

@ -1,168 +0,0 @@
import {
MyButtons,
MyColumns,
MyPageContainer,
MyProTableProps,
usePageTabs,
} from '@/common';
import { MyExport } from '@/components/MyExport';
import { Apis } from '@/gen/Apis';
import {
AssetHousesOwnershipTypeEnum,
AssetHousesUsageEnum,
} from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max';
import { Space } from 'antd';
import { useState } from 'react';
import HousesShow from '../asset/houses/modals/HousesShow';
import HousesUpdate from '../asset/houses/modals/HousesUpdate';
export default function Index({ title = '房屋列表' }) {
const [getParams, setParams] = useState({});
const navigate = useNavigate();
// 注册当前页面为标签页
usePageTabs({
tabKey: 'asset-houses',
tabLabel: title,
});
return (
<MyPageContainer title={title}>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) => {
setParams(params);
return MyProTableProps.request(
params,
sort,
Apis.Asset.AssetHouses.List,
);
}}
toolBarRender={() => [
<MyExport
key="export"
item={getParams}
download={Apis.Asset.AssetHouses}
/>,
]}
columns={[
MyColumns.ID(),
{
title: '项目名称',
dataIndex: ['asset_project', 'name'],
search: {
transform: (value) => {
return { project_name: value };
},
},
},
{
title: '房屋名称',
dataIndex: 'full_name',
},
MyColumns.EnumTag({
title: '用途',
dataIndex: 'usage',
valueEnum: AssetHousesUsageEnum,
}),
{
title: '楼层',
dataIndex: 'floor',
render(_, record) {
return `${record?.floor}`;
},
search: false,
},
{
title: '建筑面积',
dataIndex: 'built_area',
render(_, record) {
return `${
record?.built_area ? record?.built_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '套内面积',
dataIndex: 'inside_area',
render(_, record) {
return `${
record?.inside_area ? record?.inside_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '计费面积',
dataIndex: 'chargeable_area',
render(_, record) {
return `${
record?.chargeable_area ? record?.chargeable_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '户型',
render(_, record) {
return `${record?.room || 'x'}${record?.hall || 'x'}${
record?.bathroom || 'x'
}${record?.kitchen || 'x'}${record?.balcony || 'x'}`;
},
search: false,
},
// MyColumns.EnumTag({
// title: '朝向',
// dataIndex: 'orientation',
// valueEnum: AssetHousesOrientationEnum,
// search: false,
// }),
// MyColumns.EnumTag({
// title: '房屋状态',
// dataIndex: 'status',
// valueEnum: AssetHousesStatusEnum,
// search: false,
// }),
MyColumns.EnumTag({
title: '房屋属性',
dataIndex: 'ownership_type',
valueEnum: AssetHousesOwnershipTypeEnum,
search: false,
}),
// {
// title: '产权年限',
// dataIndex: 'ownership_term',
// render(_, record) {
// return `${record?.ownership_term || '-'} 年`;
// },
// search: false,
// },
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<HousesShow item={item} reload={action?.reload} />
<HousesUpdate
item={item}
reload={action?.reload}
title="编辑"
/>
<MyButtons.Delete
onConfirm={() =>
Apis.Asset.AssetHouses.Delete({
id: item.id,
}).then(() => action?.reload())
}
/>
</Space>
),
}),
]}
/>
</MyPageContainer>
);
}

View File

@ -12,8 +12,8 @@ import { ProTable } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max';
import { Space } from 'antd';
import { useState } from 'react';
import HousesShow from '../asset/houses/modals/HousesShow';
import HousesUpdate from '../asset/houses/modals/HousesUpdate';
import HousesShow from '../asset/dictionary/modals/HousesShow';
import HousesUpdate from '../asset/dictionary/modals/HousesUpdate';
export default function Index({ title = '房屋列表' }) {
const [getParams, setParams] = useState({});

View File

@ -13,10 +13,10 @@ import { Space } from 'antd';
import BillCreate from './modals/BillCreate';
import BillUpdate from './modals/BillUpdate';
export default function Index({ title = '房屋账单' }) {
export default function Index({ title = '账单明细' }) {
// 注册当前页面为标签页
usePageTabs({
tabKey: 'bills',
tabKey: 'housebills',
tabLabel: title,
});
@ -24,7 +24,7 @@ export default function Index({ title = '房屋账单' }) {
<MyPageContainer
title={title}
enableTabs={true}
tabKey="bills"
tabKey="housebills"
tabLabel={title}
>
<ProTable

View File

@ -0,0 +1,92 @@
import {
MyColumns,
MyPageContainer,
MyProTableProps,
usePageTabs,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { ProTable } from '@ant-design/pro-components';
import { Space } from 'antd';
import SummaryShow from './modals/SummaryShow';
export default function Index({ title = '房屋账单' }) {
// 注册当前页面为标签页
usePageTabs({
tabKey: 'summary',
tabLabel: title,
});
return (
<MyPageContainer
title={title}
enableTabs={true}
tabKey="summary"
tabLabel={title}
>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(
params,
sort,
Apis.Bill.HouseBills.SummaryBillList,
)
}
// toolBarRender={(action) => [
// <MyImportModal
// key="ImportHouse"
// title="批量导入"
// type="danger"
// size="middle"
// templateApi={Apis.Bill.HouseBills.DownloadTemplate}
// importApi={Apis.Bill.HouseBills.Import}
// reload={action?.reload}
// />,
// <BillCreate key="Create" reload={action?.reload} title={title} />,
// ]}
columns={[
{
title: '房屋ID',
dataIndex: 'asset_houses_id',
},
{
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,
},
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<SummaryShow item={item} title="查看" reload={action?.reload} />
</Space>
),
}),
]}
/>
</MyPageContainer>
);
}

View File

@ -0,0 +1,100 @@
import { MyBetaModalFormProps, MyColumns, MyProTableProps } from '@/common';
import { MyModal } from '@/components/MyModal';
import { Apis } from '@/gen/Apis';
import { HouseBillsTypeEnum } from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components';
import { Space } from 'antd';
import BillUpdate from '../../list/modals/BillUpdate';
export default function SummaryShow(props: MyBetaModalFormProps) {
return (
<MyModal
title={props.title || '查看'}
type={props.item?.type || 'primary'}
width="1000px"
node={
<ProTable
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(
{ ...params, asset_houses_id: props?.item?.asset_houses_id },
sort,
Apis.Bill.HouseBills.List,
)
}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '类型',
dataIndex: 'type',
valueEnum: HouseBillsTypeEnum,
}),
{
title: '房屋',
dataIndex: ['asset_house', 'full_name'],
search: {
transform: (value) => {
return { full_name: value };
},
},
},
{
title: '账单月份',
render: (_, record) => {
return `${record.year}-${String(record.month).padStart(
2,
'0',
)}`;
},
},
{
title: '账单金额',
dataIndex: 'amount',
search: false,
},
{
title: '优惠金额',
dataIndex: 'discount_amount',
search: false,
},
{
title: '滞纳金',
dataIndex: 'late_fee',
search: false,
},
{
title: '计费开始日期',
dataIndex: 'start_date',
search: false,
},
{
title: '计费结束日期',
dataIndex: 'end_date',
search: false,
},
MyColumns.CreatedAt(),
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<BillUpdate
item={item}
reload={action?.reload}
title="编辑"
/>
{/* <MyButtons.Delete
onConfirm={() =>
Apis.Bill.HouseBills.Delete({ id: item.id }).then(() =>
action?.reload(),
)
}
/> */}
</Space>
),
}),
]}
/>
}
/>
);
}

View File

@ -5,7 +5,6 @@ import {
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { CompanyReceiptAccountsPayChannelEnum } from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components';

View File

@ -1,100 +0,0 @@
import {
MyButtons,
MyColumns,
MyPageContainer,
MyProTableProps,
usePageTabs,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { HouseChargeTaskDetailsStatusEnum } from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components';
import { Space } from 'antd';
import ChargeTasksCreate from './modals/ChargeTasksCreate';
export default function Index({ title = '账单任务' }) {
// 注册当前页面为标签页
usePageTabs({
tabKey: 'house_charge_tasks',
tabLabel: title,
});
return (
<MyPageContainer
title={title}
enableTabs={true}
tabKey="bills"
tabLabel={title}
>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(
params,
sort,
Apis.HouseCharage.HouseChargeTasks.List,
)
}
toolBarRender={(action) => [
<ChargeTasksCreate
key="Create"
reload={action?.reload}
title="账单任务"
/>,
]}
columns={[
{
title: '任务ID',
dataIndex: 'house_charge_tasks_id',
search: false,
},
MyColumns.EnumTag({
title: '任务状态',
dataIndex: 'status',
valueEnum: HouseChargeTaskDetailsStatusEnum,
}),
{
title: '账单ID',
dataIndex: 'id',
search: false,
},
{
title: '关联对象',
dataIndex: 'full_name',
search: false,
},
{
title: '账单月份',
render: (_, record) => {
return `${record.year}-${String(record.month).padStart(2, '0')}`;
},
},
{
title: '计费开始日期',
dataIndex: ['house_charge_task', 'start_date'],
search: false,
},
{
title: '计费结束日期',
dataIndex: ['house_charge_task', 'end_date'],
search: false,
},
// MyColumns.UpdatedAt(),
MyColumns.CreatedAt(),
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<MyButtons.Delete
onConfirm={() =>
Apis.HouseCharage.HouseChargeTaskDetails.Delete({
id: item.id,
}).then(() => action?.reload())
}
/>
</Space>
),
}),
]}
/>
</MyPageContainer>
);
}

View File

@ -1,116 +0,0 @@
import {
MyBetaModalFormProps,
MyButtons,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd';
export default function Create(props: MyBetaModalFormProps) {
const [form] = Form.useForm();
return (
<BetaSchemaForm<ApiTypes.HouseCharage.HouseChargeTasks.Store>
{...MyModalFormProps.props}
title={`创建${props.title}`}
width="480px"
layout="horizontal"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
labelAlign="left"
trigger={<MyButtons.Create title={`创建${props.title}`} />}
key={new Date().getTime()}
form={form}
onOpenChange={(open: any) => {
if (open) {
form.resetFields(); // 清空表单数据
}
}}
onFinish={async (values) =>
Apis.HouseCharage.HouseChargeTasks.Store(values)
.then(() => {
props.reload?.();
message.success(props.title + '账单任务创建成功');
return true;
})
.catch(() => false)
}
columns={[
Selects?.AssetProjects({
title: '选择项目',
key: 'asset_projects_id',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
fieldProps: {
onChange: (val: any) => {
form.setFieldsValue({
house_charge_standards_id: undefined,
});
},
},
}),
{
valueType: 'dependency',
name: ['asset_projects_id'],
columns: ({ asset_projects_id }) => {
return [
Selects?.ChargeStandard({
title: '选择收费标准',
key: 'house_charge_standards_id',
params: {
asset_projects_id: asset_projects_id,
},
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
fieldProps: {
showSearch: true,
},
}),
];
},
},
{
key: 'month',
title: '选择生成月份',
valueType: 'date',
colProps: { span: 24 },
fieldProps: {
picker: 'month',
format: 'YYYY-MM',
valueFormat: 'YYYY-MM',
style: {
width: '100%',
},
},
formItemProps: { ...rulesHelper.text },
},
{
key: 'start_date',
title: '计费开始日期',
valueType: 'date',
colProps: { span: 24 },
fieldProps: {
style: {
width: '100%',
},
},
formItemProps: { ...rulesHelper.text },
},
{
key: 'end_date',
title: '计费结束日期',
valueType: 'date',
colProps: { span: 24 },
fieldProps: {
style: {
width: '100%',
},
},
formItemProps: { ...rulesHelper.text },
},
]}
/>
);
}

View File

@ -0,0 +1,140 @@
import {
MyButtons,
MyColumns,
MyPageContainer,
MyProTableProps,
usePageTabs,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { ProTable } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max';
import { Space } from 'antd';
import {
HouseMetersMeterTypeEnum,
HouseMetersUsageTypeEnum,
} from '@/gen/Enums';
import CompanyCreate from './modals/MeterCreate';
import MeterHasHouse from './modals/MeterHasHouse';
import MeterHasOne from './modals/MeterHasOne';
import CompanyUpdate from './modals/MeterUpdate';
export default function Index({ title = '仪表管理' }) {
const navigate = useNavigate();
// 注册当前页面为标签页
usePageTabs({
tabKey: 'house_meters',
tabLabel: title,
});
return (
<MyPageContainer
title={title}
enableTabs={true}
tabKey="house_meters"
tabLabel={title}
>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(params, sort, Apis.Meter.HouseMeters.List)
}
toolBarRender={(action) => [
<CompanyCreate key="Create" reload={action?.reload} title={title} />,
]}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '类型',
dataIndex: 'meter_type',
valueEnum: HouseMetersMeterTypeEnum,
search: false,
}),
MyColumns.EnumTag({
title: '使用类型',
dataIndex: 'usage_type',
valueEnum: HouseMetersUsageTypeEnum,
search: false,
}),
{
title: '仪表名称',
dataIndex: 'name',
},
{
title: '收费标准',
dataIndex: ['charge_standard', 'name'],
search: false,
},
{
title: '初始抄表读数',
dataIndex: 'initial_value',
search: false,
},
{
title: '最新抄表读数',
dataIndex: 'latest_value',
search: false,
},
{
title: '初始抄表时间',
dataIndex: 'initial_time',
search: false,
},
{
title: '最新抄表时间',
dataIndex: 'latest_time',
search: false,
},
{
title: '备注',
dataIndex: 'remark',
search: false,
},
MyColumns.SoftDelete({
onRestore: Apis.Company.Companies.Restore,
onSoftDelete: Apis.Company.Companies.SoftDelete,
search: false,
}),
MyColumns.CreatedAt(),
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
{/* <CompanyShow item={item} title="查看" reload={action?.reload} /> */}
<CompanyUpdate
item={{ ...item, type: 'link' }}
title="机构"
reload={action?.reload}
/>
{item.meter_type ===
HouseMetersMeterTypeEnum.HouseMeter.value && (
<MeterHasOne
item={item}
reload={action?.reload}
title={'绑房'}
/>
)}
{item.meter_type ===
HouseMetersMeterTypeEnum.CommonMeter.value && (
<MeterHasHouse
item={item}
reload={action?.reload}
title={'绑房'}
/>
)}
<MyButtons.Delete
onConfirm={() =>
Apis.Company.Companies.Delete({ id: item.id }).then(() =>
action?.reload(),
)
}
/>
</Space>
),
}),
]}
/>
</MyPageContainer>
);
}

View File

@ -0,0 +1,127 @@
import {
MyBetaModalFormProps,
MyButtons,
MyFormItems,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis';
import {
HouseMetersMeterTypeEnum,
HouseMetersUsageTypeEnum,
} from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd';
export default function Create(props: MyBetaModalFormProps) {
const [form] = Form.useForm();
return (
<BetaSchemaForm<ApiTypes.Meter.HouseMeters.Store>
{...MyModalFormProps.props}
title={`添加仪表`}
layout="horizontal"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
labelAlign="left"
width="600px"
key={new Date().getTime()}
trigger={<MyButtons.Create title={`添加仪表`} />}
form={form}
onOpenChange={(open: any) => {
if (open) {
form.resetFields(); // 清空表单数据
}
}}
onFinish={async (values) =>
Apis.Meter.HouseMeters.Store({
...values,
})
.then(() => {
props.reload?.();
message.success(props.title + '成功');
return true;
})
.catch(() => false)
}
columns={[
...(props?.item?.id
? []
: [
Selects?.AssetProjects({
key: 'asset_projects_id',
title: '选择项目',
colProps: { span: 24 },
required: true,
}),
]),
MyFormItems.EnumRadio({
key: 'meter_type',
title: '仪表类型',
colProps: { span: 24 },
valueEnum: HouseMetersMeterTypeEnum,
required: true,
}),
MyFormItems.EnumRadio({
key: 'usage_type',
title: '使用类型',
colProps: { span: 24 },
valueEnum: HouseMetersUsageTypeEnum,
required: true,
}),
{
key: 'name',
title: '仪表名称',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
{
key: 'multiple',
title: '倍率',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
{
key: 'initial_value',
title: '初始抄表读数',
valueType: 'number',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.number },
},
{
key: 'initial_time',
title: '初始抄表时间',
valueType: 'date',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
{
valueType: 'dependency',
name: ['asset_projects_id'],
columns: ({ asset_projects_id }) => {
return [
Selects?.ChargeStandard({
title: '选择收费标准',
key: 'charge_standards_id',
params: {
asset_projects_id: asset_projects_id || props?.item?.id || 0,
},
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
}),
];
},
},
{
key: 'remark',
title: '备注',
valueType: 'textarea',
colProps: { span: 24 },
},
]}
/>
);
}

View File

@ -0,0 +1,215 @@
import {
MyBetaModalFormProps,
MyButtons,
MyColumns,
MyProTableProps,
} from '@/common';
import { MyModal } from '@/components/MyModal';
import { Apis } from '@/gen/Apis';
import {
AssetHousesOwnershipTypeEnum,
AssetHousesUsageEnum,
} from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components';
import { message, Space } from 'antd';
import { useRef, useState } from 'react';
export default function ChargeStandardHasHouse(props: MyBetaModalFormProps) {
// 使用 useState 保存选中的房屋 ID 和行数据,确保跨页选中状态保持
const [selectedHousesIds, setSelectedHousesIds] = useState<number[]>([]);
const [selectedRows, setSelectedRows] = useState<any[]>([]);
// 添加 tableRef 用于操作表格
const tableRef = useRef<any>();
const onShowContactPhone = () => {
if (selectedHousesIds.length === 0) {
message.warning('请至少选择一个房屋');
return;
}
// 确保 houses_ids 是字符串数组
const housesIds = selectedHousesIds.map((id) => String(id));
Apis.Meter.HouseMeterHasHouses.StoreOrUpdate({
house_meters_id: props?.item?.id ?? 0,
asset_houses_ids: housesIds,
})
.then(() => {
// 成功后重置选中状态
setSelectedHousesIds([]);
setSelectedRows([]);
props.reload?.();
message.success('添加成功!');
})
.catch((error) => {
console.error('添加失败:', error);
message.error('添加失败: ' + (error.message || '未知错误'));
return false;
});
};
return (
<MyModal
title={props.title || '查看'}
type="primary"
width="920px"
node={
<ProTable
actionRef={tableRef}
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
asset_projects_id: props?.item?.asset_projects_id,
},
sort,
Apis.Asset.AssetHouses.List,
undefined,
(res) => {
// 确保响应数据正确处理
console.log('加载房屋数据:', res);
return res;
},
)
}
style={{ height: '800px', overflowY: 'auto', overflowX: 'hidden' }}
pagination={{
showQuickJumper: true,
pageSizeOptions: [10, 20, 50, 100, 200, 500, 1000, 2000],
}}
rowSelection={{
type: 'checkbox',
preserveSelectedRowKeys: true, // 启用跨页选择
selectedRowKeys: selectedHousesIds,
onChange: (selectedRowKeys, selectedRows) => {
// 确保 selectedRowKeys 是数字类型
const numericKeys = selectedRowKeys.map((key) =>
typeof key === 'string' ? parseInt(key, 10) : key,
) as number[];
// 更新选中状态
setSelectedHousesIds(numericKeys);
// 合并当前页面选中的行和之前选中的行
const newSelectedRows = [...selectedRows];
// 设置选中行数据
setSelectedRows(newSelectedRows);
},
}}
tableAlertOptionRender={({ selectedRowKeys, onCleanSelected }) => {
return (
<Space>
<span> {selectedRowKeys.length} </span>
<a onClick={onCleanSelected}></a>
<MyButtons.Create
title="批量添加"
type="primary"
key="create2"
onClick={() => onShowContactPhone()}
/>
</Space>
);
}}
options={false}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '用途',
dataIndex: 'usage',
valueEnum: AssetHousesUsageEnum,
search: false,
}),
{
title: '项目名称',
dataIndex: ['asset_project', 'name'],
search: false,
},
{
title: '楼栋名称',
dataIndex: ['asset_building', 'name'],
search: {
transform: (value) => {
return { building_name: value };
},
},
},
{
title: '单元名称',
dataIndex: ['asset_unit', 'name'],
search: {
transform: (value) => {
return { unit_name: value };
},
},
},
{
title: '房号',
dataIndex: 'name',
},
{
title: '楼层',
dataIndex: 'floor',
render(_, record) {
return `${record?.floor}`;
},
search: false,
},
{
title: '建筑面积',
dataIndex: 'built_area',
render(_, record) {
return `${
record?.built_area ? record?.built_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '套内面积',
dataIndex: 'inside_area',
render(_, record) {
return `${
record?.inside_area ? record?.inside_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '计费面积',
dataIndex: 'chargeable_area',
render(_, record) {
return `${
record?.chargeable_area
? record?.chargeable_area + ' m²'
: '-'
} `;
},
search: false,
},
// {
// title: '户型',
// render(_, record) {
// return `${record?.room || 'x'}室${record?.hall || 'x'}厅${
// record?.bathroom || 'x'
// }卫${record?.kitchen || 'x'}厨${record?.balcony || 'x'}阳台`;
// },
// search: false,
// },
MyColumns.EnumTag({
title: '产权性质',
dataIndex: 'ownership_type',
valueEnum: AssetHousesOwnershipTypeEnum,
search: false,
}),
]}
/>
}
/>
);
}

View File

@ -0,0 +1,213 @@
import {
MyBetaModalFormProps,
MyButtons,
MyColumns,
MyProTableProps,
} from '@/common';
import { MyModal } from '@/components/MyModal';
import { Apis } from '@/gen/Apis';
import {
AssetHousesOwnershipTypeEnum,
AssetHousesUsageEnum,
} from '@/gen/Enums';
import { ProTable } from '@ant-design/pro-components';
import { message, Space } from 'antd';
import { useRef, useState } from 'react';
export default function ChargeStandardHasHouse(props: MyBetaModalFormProps) {
// 使用 useState 保存选中的房屋 ID 和行数据,只选择一行
const [selectedHouseId, setSelectedHouseId] = useState<number | null>(null);
const [selectedRow, setSelectedRow] = useState<any>(null);
// 添加 tableRef 用于操作表格
const tableRef = useRef<any>();
const onShowContactPhone = () => {
if (!selectedHouseId) {
message.warning('请选择一个房屋');
return;
}
// 确保 houses_ids 是字符串数组
const housesIds = [String(selectedHouseId)];
Apis.Meter.HouseMeterHasHouses.StoreOrUpdate({
house_meters_id: props?.item?.id ?? 0,
asset_houses_ids: housesIds,
})
.then(() => {
// 成功后重置选中状态
setSelectedHouseId(null);
setSelectedRow(null);
props.reload?.();
message.success('添加成功!');
})
.catch((error) => {
console.error('添加失败:', error);
message.error('添加失败: ' + (error.message || '未知错误'));
return false;
});
};
return (
<MyModal
title={props.title || '查看'}
type="primary"
width="920px"
node={
<ProTable
actionRef={tableRef}
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(
{
...params,
asset_projects_id: props?.item?.asset_projects_id,
},
sort,
Apis.Asset.AssetHouses.List,
undefined,
(res) => {
// 确保响应数据正确处理
console.log('加载房屋数据:', res);
return res;
},
)
}
style={{ height: '800px', overflowY: 'auto', overflowX: 'hidden' }}
pagination={{
showQuickJumper: true,
pageSizeOptions: [10, 20, 50, 100, 200, 500, 1000, 2000],
}}
rowSelection={{
type: 'radio', // 改为单选
selectedRowKeys: selectedHouseId ? [selectedHouseId] : [],
onChange: (selectedRowKeys, selectedRows) => {
// 单选模式下,只取第一个选中的项
if (selectedRowKeys.length > 0) {
const selectedKey =
typeof selectedRowKeys[0] === 'string'
? parseInt(selectedRowKeys[0], 10)
: (selectedRowKeys[0] as number);
setSelectedHouseId(selectedKey);
setSelectedRow(selectedRows[0]);
} else {
setSelectedHouseId(null);
setSelectedRow(null);
}
},
}}
tableAlertOptionRender={({ selectedRowKeys, onCleanSelected }) => {
return (
<Space>
<span> {selectedRowKeys.length} </span>
<a
onClick={() => {
onCleanSelected();
setSelectedHouseId(null);
setSelectedRow(null);
}}
>
</a>
<MyButtons.Create
title="添加"
type="primary"
key="create2"
onClick={() => onShowContactPhone()}
/>
</Space>
);
}}
options={false}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '用途',
dataIndex: 'usage',
valueEnum: AssetHousesUsageEnum,
search: false,
}),
{
title: '项目名称',
dataIndex: ['asset_project', 'name'],
search: false,
},
{
title: '楼栋名称',
dataIndex: ['asset_building', 'name'],
search: {
transform: (value) => {
return { building_name: value };
},
},
},
{
title: '单元名称',
dataIndex: ['asset_unit', 'name'],
search: {
transform: (value) => {
return { unit_name: value };
},
},
},
{
title: '房号',
dataIndex: 'name',
},
{
title: '楼层',
dataIndex: 'floor',
render(_, record) {
return `${record?.floor}`;
},
search: false,
},
{
title: '建筑面积',
dataIndex: 'built_area',
render(_, record) {
return `${
record?.built_area ? record?.built_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '套内面积',
dataIndex: 'inside_area',
render(_, record) {
return `${
record?.inside_area ? record?.inside_area + ' m²' : '-'
} `;
},
search: false,
},
{
title: '计费面积',
dataIndex: 'chargeable_area',
render(_, record) {
return `${
record?.chargeable_area
? record?.chargeable_area + ' m²'
: '-'
} `;
},
search: false,
},
MyColumns.EnumTag({
title: '产权性质',
dataIndex: 'ownership_type',
valueEnum: AssetHousesOwnershipTypeEnum,
search: false,
}),
]}
/>
}
/>
);
}

View File

@ -0,0 +1,111 @@
import {
MyBetaModalFormProps,
MyButtons,
MyFormItems,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis';
import {
HouseMetersMeterTypeEnum,
HouseMetersUsageTypeEnum,
} from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd';
export default function Update(props: MyBetaModalFormProps) {
const [form] = Form.useForm();
return (
<BetaSchemaForm<ApiTypes.Meter.HouseMeters.Update>
{...MyModalFormProps.props}
title={`编辑${props.title}`}
trigger={<MyButtons.Default title="编辑" type="primary" size="small" />}
layout="horizontal"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
labelAlign="left"
width="600px"
key={new Date().getTime()}
form={form}
onOpenChange={(open: any) => {
if (open && props.item) {
form.setFieldsValue({
...props.item,
asset_projects_id: props.item?.asset_projects_id,
house_charge_standards_id: props.item?.house_charge_standards_id,
});
}
}}
onFinish={async (values) =>
Apis.Meter.HouseMeters.Update({
...values,
id: props.item?.id ?? 0,
asset_projects_id: props.item?.asset_projects_id,
})
.then(() => {
props.reload?.();
message.success(props.title + '成功');
return true;
})
.catch(() => false)
}
columns={[
MyFormItems.EnumRadio({
key: 'meter_type',
title: '仪表类型',
colProps: { span: 24 },
valueEnum: HouseMetersMeterTypeEnum,
required: true,
}),
MyFormItems.EnumRadio({
key: 'usage_type',
title: '使用类型',
colProps: { span: 24 },
valueEnum: HouseMetersUsageTypeEnum,
required: true,
}),
{
key: 'name',
title: '仪表名称',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
{
key: 'multiple',
title: '倍率',
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
},
// {
// key: 'initial_value',
// title: '初始抄表读数',
// colProps: { span: 24 },
// formItemProps: { ...rulesHelper.text },
// },
// {
// key: 'initial_time',
// title: '初始抄表时间',
// valueType: 'date',
// colProps: { span: 24 },
// formItemProps: { ...rulesHelper.text },
// },
Selects?.ChargeStandard({
title: '选择收费标准',
key: 'charge_standards_id',
params: {
asset_projects_id: props?.item?.asset_projects_id,
},
colProps: { span: 24 },
formItemProps: { ...rulesHelper.text },
}),
{
key: 'remark',
title: '备注',
valueType: 'textarea',
colProps: { span: 24 },
},
]}
/>
);
}

View File

@ -0,0 +1,122 @@
import {
MyButtons,
MyColumns,
MyPageContainer,
MyProTableProps,
usePageTabs,
} from '@/common';
import { Apis } from '@/gen/Apis';
import { ProTable } from '@ant-design/pro-components';
import { useNavigate } from '@umijs/max';
import { Space } from 'antd';
import {
HouseMetersMeterTypeEnum,
HouseMetersUsageTypeEnum,
} from '@/gen/Enums';
import NormalReading from './modals/NormalReading';
export default function Index({ title = '抄表数据' }) {
const navigate = useNavigate();
// 注册当前页面为标签页
usePageTabs({
tabKey: 'house_meter_readings',
tabLabel: title,
});
return (
<MyPageContainer
title={title}
enableTabs={true}
tabKey="house_meter_readings"
tabLabel={title}
>
<ProTable
{...MyProTableProps.props}
request={async (params, sort) =>
MyProTableProps.request(params, sort, Apis.Meter.HouseMeters.List)
}
toolBarRender={(action) => [
// <ReadingCreate key="Create" reload={action?.reload} title={title} />,
]}
columns={[
MyColumns.ID(),
MyColumns.EnumTag({
title: '类型',
dataIndex: 'meter_type',
valueEnum: HouseMetersMeterTypeEnum,
search: false,
}),
MyColumns.EnumTag({
title: '使用类型',
dataIndex: 'usage_type',
valueEnum: HouseMetersUsageTypeEnum,
search: false,
}),
{
title: '仪表名称',
dataIndex: 'name',
},
{
title: '收费标准',
dataIndex: ['charge_standard', 'name'],
search: false,
},
{
title: '初始抄表读数',
dataIndex: 'initial_value',
search: false,
},
{
title: '最新抄表读数',
dataIndex: 'latest_value',
search: false,
},
{
title: '初始抄表时间',
dataIndex: 'initial_time',
search: false,
},
{
title: '最新抄表时间',
dataIndex: 'latest_time',
search: false,
},
{
title: '备注',
dataIndex: 'remark',
search: false,
},
MyColumns.SoftDelete({
onRestore: Apis.Company.Companies.Restore,
onSoftDelete: Apis.Company.Companies.SoftDelete,
search: false,
}),
MyColumns.CreatedAt(),
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
{/* <CompanyShow item={item} title="查看" reload={action?.reload} /> */}
<NormalReading
item={{ ...item, type: 'link' }}
title="抄表"
reload={action?.reload}
/>
<MyButtons.Delete
onConfirm={() =>
Apis.Company.Companies.Delete({ id: item.id }).then(() =>
action?.reload(),
)
}
/>
</Space>
),
}),
]}
/>
</MyPageContainer>
);
}

View File

@ -0,0 +1,149 @@
import {
MyBetaModalFormProps,
MyButtons,
MyModalFormProps,
rulesHelper,
} from '@/common';
import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis';
import { HouseMeterReadingsOperationTypeEnum } from '@/gen/Enums';
import { BetaSchemaForm } from '@ant-design/pro-components';
import { Form, message } from 'antd';
export default function Create(props: MyBetaModalFormProps) {
const [form] = Form.useForm();
return (
<BetaSchemaForm<ApiTypes.Meter.HouseMeterReadings.Store>
{...MyModalFormProps.props}
title={`添加抄表数据`}
layout="horizontal"
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
labelAlign="left"
width="600px"
key={new Date().getTime()}
trigger={<MyButtons.Default title={`抄表`} type="primary" />}
form={form}
onOpenChange={(open: any) => {
if (open && props.item) {
form.resetFields(); // 清空表单数据
form.setFieldsValue({
...props.item,
latest_value:
props.item?.latest_value === '0.00'
? props.item?.initial_value
: props.item?.latest_value,
latest_time: props.item?.latest_time || props.item?.initial_time,
});
}
}}
onFinish={async (values) =>
Apis.Meter.HouseMeterReadings.Store({
...values,
operation_type:
HouseMeterReadingsOperationTypeEnum.NormalReading.value,
})
.then(() => {
props.reload?.();
message.success(props.title + '成功');
return true;
})
.catch(() => false)
}
columns={[
{
key: 'latest_value',
title: '上次抄表读数',
colProps: { span: 24 },
fieldProps: { disabled: true },
},
{
key: 'latest_time',
title: '上次抄表时间',
valueType: 'date',
colProps: { span: 24 },
fieldProps: { disabled: true },
},
{
key: 'current_reading',
title: '本次抄表读数',
valueType: 'number',
colProps: { span: 24 },
formItemProps: {
...rulesHelper.number,
rules: [
...rulesHelper.number.rules,
{
validator: (_, value) => {
const latestValue = form.getFieldValue('latest_value');
if (
value &&
latestValue &&
Number(value) <= Number(latestValue)
) {
return Promise.reject(
new Error('本次读数必须大于上次抄表读数'),
);
}
return Promise.resolve();
},
},
],
},
},
{
key: 'reading_time',
title: '本次抄表时间',
valueType: 'date',
colProps: { span: 24 },
formItemProps: {
...rulesHelper.text,
rules: [
...rulesHelper.text.rules,
{
validator: (_, value) => {
const latestTime = form.getFieldValue('latest_time');
if (value && latestTime) {
const currentTime = new Date(value);
const lastTime = new Date(latestTime);
if (currentTime <= lastTime) {
return Promise.reject(
new Error('本次抄表时间必须大于上次抄表时间'),
);
}
}
return Promise.resolve();
},
},
],
},
},
Selects?.Employees({
key: 'company_employees_id',
title: '抄表人',
params: {
companies_id: props.item?.companies_id,
},
colProps: { span: 24 },
required: true,
fieldProps: {
showSearch: true,
fieldNames: {
label: 'label',
value: 'value',
},
},
}),
{
key: 'remark',
title: '备注',
valueType: 'textarea',
colProps: { span: 24 },
},
]}
/>
);
}

View File

@ -47,32 +47,31 @@ export default function Index({ title = '支付明细' }) {
// <BillCreate key="Create" reload={action?.reload} title={title} />,
// ]}
columns={[
MyColumns.ID(),
// MyColumns.ID(),
{
title: '订单号',
dataIndex: 'order_code',
search: false,
},
MyColumns.EnumTag({
title: '支付方式',
dataIndex: 'payment_method',
valueEnum: HouseOrdersPaymentMethodEnum,
}),
MyColumns.EnumTag({
title: '支付状态',
dataIndex: 'order_status',
valueEnum: HouseOrdersOrderStatusEnum,
}),
MyColumns.EnumTag({
title: '支付渠道',
dataIndex: 'payment_method',
valueEnum: HouseOrdersPaymentMethodEnum,
}),
// {
// title: '支付单号',
// dataIndex: 'payment_no',
// search: false,
// },
{
title: '收款单号',
dataIndex: 'order_code',
search: false,
},
{
title: '账单金额',
dataIndex: 'amount',
search: false,
},
{
title: '优惠金额',
dataIndex: 'discount_amount',
title: '应收金额',
dataIndex: 'actual_paid_amount',
search: false,
},
{
@ -81,13 +80,26 @@ export default function Index({ title = '支付明细' }) {
search: false,
},
{
title: '应付金额',
dataIndex: 'total_payable_amount',
title: '退款总金额',
dataIndex: 'refund_amount',
search: false,
},
{
title: '关联项目',
dataIndex: ['asset_project', 'name'],
title: '实缴金额',
dataIndex: 'actual_paid_amount',
search: false,
},
{
title: '收款账号',
dataIndex: ['house_order_items', 'receipt_account'],
render: (text, item) =>
`${
item?.receipt_account?.company_bank
} ${item?.receipt_account?.company_account?.slice(-4)}`,
},
{
title: '支付时间',
dataIndex: 'paid_time',
search: false,
},
{
@ -95,7 +107,13 @@ export default function Index({ title = '支付明细' }) {
dataIndex: ['company', 'name'],
search: false,
},
MyColumns.CreatedAt(),
{
title: '关联项目',
dataIndex: ['asset_project', 'name'],
search: false,
},
// MyColumns.CreatedAt(),
// MyColumns.Option({
// render: (_, item: any, index, action) => (
// <Space key={index}>